ByteString introduced as AsciiString super class
Motivation: The usage and code within AsciiString has exceeded the original design scope for this class. Its usage as a binary string is confusing and on the verge of violating interface assumptions in some spots. Modifications: - ByteString will be created as a base class to AsciiString. All of the generic byte handling processing will live in ByteString and all the special character encoding will live in AsciiString. Results: The AsciiString interface will be clarified. Users of AsciiString can now be clear of the limitations the class imposes while users of the ByteString class don't have to live with those limitations.
This commit is contained in:
parent
f58fd3f8c7
commit
b823bfa950
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package io.netty.buffer;
|
||||
|
||||
import io.netty.util.ByteProcessor;
|
||||
import io.netty.util.IllegalReferenceCountException;
|
||||
import io.netty.util.ResourceLeakDetector;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
@ -965,7 +966,7 @@ public abstract class AbstractByteBuf extends ByteBuf {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(ByteBufProcessor processor) {
|
||||
public int forEachByte(ByteProcessor processor) {
|
||||
int index = readerIndex;
|
||||
int length = writerIndex - index;
|
||||
ensureAccessible();
|
||||
@ -973,12 +974,12 @@ public abstract class AbstractByteBuf extends ByteBuf {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(int index, int length, ByteBufProcessor processor) {
|
||||
public int forEachByte(int index, int length, ByteProcessor processor) {
|
||||
checkIndex(index, length);
|
||||
return forEachByteAsc0(index, length, processor);
|
||||
}
|
||||
|
||||
private int forEachByteAsc0(int index, int length, ByteBufProcessor processor) {
|
||||
private int forEachByteAsc0(int index, int length, ByteProcessor processor) {
|
||||
if (processor == null) {
|
||||
throw new NullPointerException("processor");
|
||||
}
|
||||
@ -1005,7 +1006,7 @@ public abstract class AbstractByteBuf extends ByteBuf {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(ByteBufProcessor processor) {
|
||||
public int forEachByteDesc(ByteProcessor processor) {
|
||||
int index = readerIndex;
|
||||
int length = writerIndex - index;
|
||||
ensureAccessible();
|
||||
@ -1013,13 +1014,13 @@ public abstract class AbstractByteBuf extends ByteBuf {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(int index, int length, ByteBufProcessor processor) {
|
||||
public int forEachByteDesc(int index, int length, ByteProcessor processor) {
|
||||
checkIndex(index, length);
|
||||
|
||||
return forEachByteDesc0(index, length, processor);
|
||||
}
|
||||
|
||||
private int forEachByteDesc0(int index, int length, ByteBufProcessor processor) {
|
||||
private int forEachByteDesc0(int index, int length, ByteProcessor processor) {
|
||||
|
||||
if (processor == null) {
|
||||
throw new NullPointerException("processor");
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package io.netty.buffer;
|
||||
|
||||
import io.netty.util.ByteProcessor;
|
||||
import io.netty.util.ResourceLeak;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -599,25 +600,25 @@ final class AdvancedLeakAwareByteBuf extends WrappedByteBuf {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(ByteBufProcessor processor) {
|
||||
public int forEachByte(ByteProcessor processor) {
|
||||
leak.record();
|
||||
return super.forEachByte(processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(int index, int length, ByteBufProcessor processor) {
|
||||
public int forEachByte(int index, int length, ByteProcessor processor) {
|
||||
leak.record();
|
||||
return super.forEachByte(index, length, processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(ByteBufProcessor processor) {
|
||||
public int forEachByteDesc(ByteProcessor processor) {
|
||||
leak.record();
|
||||
return super.forEachByteDesc(processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(int index, int length, ByteBufProcessor processor) {
|
||||
public int forEachByteDesc(int index, int length, ByteProcessor processor) {
|
||||
leak.record();
|
||||
return super.forEachByteDesc(index, length, processor);
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package io.netty.buffer;
|
||||
|
||||
import io.netty.util.ByteProcessor;
|
||||
import io.netty.util.ReferenceCounted;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -178,7 +179,7 @@ import java.nio.charset.UnsupportedCharsetException;
|
||||
*
|
||||
* For simple single-byte searches, use {@link #indexOf(int, int, byte)} and {@link #bytesBefore(int, int, byte)}.
|
||||
* {@link #bytesBefore(byte)} is especially useful when you deal with a {@code NUL}-terminated string.
|
||||
* For complicated searches, use {@link #forEachByte(int, int, ByteBufProcessor)} with a {@link ByteBufProcessor}
|
||||
* For complicated searches, use {@link #forEachByte(int, int, ByteProcessor)} with a {@link ByteProcessor}
|
||||
* implementation.
|
||||
*
|
||||
* <h3>Mark and reset</h3>
|
||||
@ -1605,26 +1606,26 @@ public abstract class ByteBuf implements ReferenceCounted, Comparable<ByteBuf> {
|
||||
* Iterates over the readable bytes of this buffer with the specified {@code processor} in ascending order.
|
||||
*
|
||||
* @return {@code -1} if the processor iterated to or beyond the end of the readable bytes.
|
||||
* The last-visited index If the {@link ByteBufProcessor#process(byte)} returned {@code false}.
|
||||
* The last-visited index If the {@link ByteProcessor#process(byte)} returned {@code false}.
|
||||
*/
|
||||
public abstract int forEachByte(ByteBufProcessor processor);
|
||||
public abstract int forEachByte(ByteProcessor processor);
|
||||
|
||||
/**
|
||||
* Iterates over the specified area of this buffer with the specified {@code processor} in ascending order.
|
||||
* (i.e. {@code index}, {@code (index + 1)}, .. {@code (index + length - 1)})
|
||||
*
|
||||
* @return {@code -1} if the processor iterated to or beyond the end of the specified area.
|
||||
* The last-visited index If the {@link ByteBufProcessor#process(byte)} returned {@code false}.
|
||||
* The last-visited index If the {@link ByteProcessor#process(byte)} returned {@code false}.
|
||||
*/
|
||||
public abstract int forEachByte(int index, int length, ByteBufProcessor processor);
|
||||
public abstract int forEachByte(int index, int length, ByteProcessor processor);
|
||||
|
||||
/**
|
||||
* Iterates over the readable bytes of this buffer with the specified {@code processor} in descending order.
|
||||
*
|
||||
* @return {@code -1} if the processor iterated to or beyond the beginning of the readable bytes.
|
||||
* The last-visited index If the {@link ByteBufProcessor#process(byte)} returned {@code false}.
|
||||
* The last-visited index If the {@link ByteProcessor#process(byte)} returned {@code false}.
|
||||
*/
|
||||
public abstract int forEachByteDesc(ByteBufProcessor processor);
|
||||
public abstract int forEachByteDesc(ByteProcessor processor);
|
||||
|
||||
/**
|
||||
* Iterates over the specified area of this buffer with the specified {@code processor} in descending order.
|
||||
@ -1632,9 +1633,9 @@ public abstract class ByteBuf implements ReferenceCounted, Comparable<ByteBuf> {
|
||||
*
|
||||
*
|
||||
* @return {@code -1} if the processor iterated to or beyond the beginning of the specified area.
|
||||
* The last-visited index If the {@link ByteBufProcessor#process(byte)} returned {@code false}.
|
||||
* The last-visited index If the {@link ByteProcessor#process(byte)} returned {@code false}.
|
||||
*/
|
||||
public abstract int forEachByteDesc(int index, int length, ByteBufProcessor processor);
|
||||
public abstract int forEachByteDesc(int index, int length, ByteProcessor processor);
|
||||
|
||||
/**
|
||||
* Returns a copy of this buffer's readable bytes. Modifying the content
|
||||
|
@ -16,10 +16,15 @@
|
||||
|
||||
package io.netty.buffer;
|
||||
|
||||
public interface ByteBufProcessor {
|
||||
import io.netty.util.ByteProcessor;
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link ByteProcessor}.
|
||||
*/
|
||||
public interface ByteBufProcessor extends ByteProcessor {
|
||||
|
||||
/**
|
||||
* Aborts on a {@code NUL (0x00)}.
|
||||
* @deprecated Use {@link ByteProcessor#FIND_NULL}.
|
||||
*/
|
||||
ByteBufProcessor FIND_NUL = new ByteBufProcessor() {
|
||||
@Override
|
||||
@ -29,7 +34,7 @@ public interface ByteBufProcessor {
|
||||
};
|
||||
|
||||
/**
|
||||
* Aborts on a non-{@code NUL (0x00)}.
|
||||
* @deprecated Use {@link ByteProcessor#FIND_NON_NUL}.
|
||||
*/
|
||||
ByteBufProcessor FIND_NON_NUL = new ByteBufProcessor() {
|
||||
@Override
|
||||
@ -39,7 +44,7 @@ public interface ByteBufProcessor {
|
||||
};
|
||||
|
||||
/**
|
||||
* Aborts on a {@code CR ('\r')}.
|
||||
* @deprecated Use {@link ByteProcessor#FIND_CR}.
|
||||
*/
|
||||
ByteBufProcessor FIND_CR = new ByteBufProcessor() {
|
||||
@Override
|
||||
@ -49,7 +54,7 @@ public interface ByteBufProcessor {
|
||||
};
|
||||
|
||||
/**
|
||||
* Aborts on a non-{@code CR ('\r')}.
|
||||
* @deprecated Use {@link ByteProcessor#FIND_NON_CR}.
|
||||
*/
|
||||
ByteBufProcessor FIND_NON_CR = new ByteBufProcessor() {
|
||||
@Override
|
||||
@ -59,7 +64,7 @@ public interface ByteBufProcessor {
|
||||
};
|
||||
|
||||
/**
|
||||
* Aborts on a {@code LF ('\n')}.
|
||||
* @deprecated Use {@link ByteProcessor#FIND_LF}.
|
||||
*/
|
||||
ByteBufProcessor FIND_LF = new ByteBufProcessor() {
|
||||
@Override
|
||||
@ -69,7 +74,7 @@ public interface ByteBufProcessor {
|
||||
};
|
||||
|
||||
/**
|
||||
* Aborts on a non-{@code LF ('\n')}.
|
||||
* @deprecated Use {@link ByteProcessor#FIND_NON_LF}.
|
||||
*/
|
||||
ByteBufProcessor FIND_NON_LF = new ByteBufProcessor() {
|
||||
@Override
|
||||
@ -79,7 +84,7 @@ public interface ByteBufProcessor {
|
||||
};
|
||||
|
||||
/**
|
||||
* Aborts on a {@code CR ('\r')} or a {@code LF ('\n')}.
|
||||
* @deprecated Use {@link ByteProcessor#FIND_CRLF}.
|
||||
*/
|
||||
ByteBufProcessor FIND_CRLF = new ByteBufProcessor() {
|
||||
@Override
|
||||
@ -89,7 +94,7 @@ public interface ByteBufProcessor {
|
||||
};
|
||||
|
||||
/**
|
||||
* Aborts on a byte which is neither a {@code CR ('\r')} nor a {@code LF ('\n')}.
|
||||
* @deprecated Use {@link ByteProcessor#FIND_NON_CRLF}.
|
||||
*/
|
||||
ByteBufProcessor FIND_NON_CRLF = new ByteBufProcessor() {
|
||||
@Override
|
||||
@ -99,7 +104,7 @@ public interface ByteBufProcessor {
|
||||
};
|
||||
|
||||
/**
|
||||
* Aborts on a linear whitespace (a ({@code ' '} or a {@code '\t'}).
|
||||
* @deprecated Use {@link ByteProcessor#FIND_LINEAR_WHITESPACE}.
|
||||
*/
|
||||
ByteBufProcessor FIND_LINEAR_WHITESPACE = new ByteBufProcessor() {
|
||||
@Override
|
||||
@ -109,7 +114,7 @@ public interface ByteBufProcessor {
|
||||
};
|
||||
|
||||
/**
|
||||
* Aborts on a byte which is not a linear whitespace (neither {@code ' '} nor {@code '\t'}).
|
||||
* @deprecated Use {@link ByteProcessor#FIND_NON_LINEAR_WHITESPACE}.
|
||||
*/
|
||||
ByteBufProcessor FIND_NON_LINEAR_WHITESPACE = new ByteBufProcessor() {
|
||||
@Override
|
||||
@ -117,10 +122,4 @@ public interface ByteBufProcessor {
|
||||
return value == ' ' || value == '\t';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {@code true} if the processor wants to continue the loop and handle the next byte in the buffer.
|
||||
* {@code false} if the processor wants to stop handling bytes and abort the loop.
|
||||
*/
|
||||
boolean process(byte value) throws Exception;
|
||||
}
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package io.netty.buffer;
|
||||
|
||||
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
||||
import io.netty.util.ByteString;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.Recycler;
|
||||
import io.netty.util.Recycler.Handle;
|
||||
@ -31,6 +33,7 @@ import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.nio.charset.CoderResult;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
@ -549,6 +552,85 @@ public final class ByteBufUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of the underlying storage from {@link value} into a byte array.
|
||||
* The copy will start at {@link ByteBuf#readerIndex()} and copy {@link ByteBuf#readableBytes()} bytes.
|
||||
*/
|
||||
public static byte[] getBytes(ByteBuf buf) {
|
||||
return getBytes(buf, checkNotNull(buf, "buf").readerIndex(), buf.readableBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of the underlying storage from {@link buf} into a byte array.
|
||||
* The copy will start at {@code start} and copy {@code length} bytes.
|
||||
*/
|
||||
public static byte[] getBytes(ByteBuf buf, int start, int length) {
|
||||
return getBytes(buf, start, length, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of the underlying storage from {@link buf} into a byte array.
|
||||
* The copy will start at {@code start} and copy {@code length} bytes.
|
||||
* If {@code copy} is true a copy will be made of the memory.
|
||||
* If {@code copy} is false the underlying storage will be shared, if possible.
|
||||
*/
|
||||
public static byte[] getBytes(ByteBuf buf, int start, int length, boolean copy) {
|
||||
if (start < 0 || length > checkNotNull(buf, "buf").capacity() - start) {
|
||||
throw new IndexOutOfBoundsException("expected: " + "0 <= start(" + start + ") <= start + length(" + length
|
||||
+ ") <= " + "buf.capacity(" + buf.capacity() + ')');
|
||||
}
|
||||
|
||||
if (buf.hasArray()) {
|
||||
if (copy || start != 0 || length != buf.capacity()) {
|
||||
int baseOffset = buf.arrayOffset() + start;
|
||||
return Arrays.copyOfRange(buf.array(), baseOffset, baseOffset + length);
|
||||
} else {
|
||||
return buf.array();
|
||||
}
|
||||
}
|
||||
|
||||
byte[] v = new byte[length];
|
||||
buf.getBytes(start, v);
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the content of {@code src} to a {@link ByteBuf} using {@link ByteBuf#writeBytes(byte[], int, int)}.
|
||||
* @param src The source of the data to copy.
|
||||
* @param srcIdx the starting offset of characters to copy.
|
||||
* @param dst the destination byte array.
|
||||
* @param dstIdx the starting offset in the destination byte array.
|
||||
* @param length the number of characters to copy.
|
||||
*/
|
||||
public static void copy(ByteString src, int srcIdx, ByteBuf dst, int dstIdx, int length) {
|
||||
final int thisLen = src.length();
|
||||
|
||||
if (srcIdx < 0 || length > thisLen - srcIdx) {
|
||||
throw new IndexOutOfBoundsException("expected: " + "0 <= srcIdx(" + srcIdx + ") <= srcIdx + length("
|
||||
+ length + ") <= srcLen(" + thisLen + ')');
|
||||
}
|
||||
|
||||
checkNotNull(dst, "dst").setBytes(dstIdx, src.array(), srcIdx, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the content of {@code src} to a {@link ByteBuf} using {@link ByteBuf#writeBytes(byte[], int, int)}.
|
||||
* @param src The source of the data to copy.
|
||||
* @param srcIdx the starting offset of characters to copy.
|
||||
* @param dst the destination byte array.
|
||||
* @param length the number of characters to copy.
|
||||
*/
|
||||
public static void copy(ByteString src, int srcIdx, ByteBuf dst, int length) {
|
||||
final int thisLen = src.length();
|
||||
|
||||
if (srcIdx < 0 || length > thisLen - srcIdx) {
|
||||
throw new IndexOutOfBoundsException("expected: " + "0 <= srcIdx(" + srcIdx + ") <= srcIdx + length("
|
||||
+ length + ") <= srcLen(" + thisLen + ')');
|
||||
}
|
||||
|
||||
checkNotNull(dst, "dst").writeBytes(src.array(), srcIdx, length);
|
||||
}
|
||||
|
||||
static final class ThreadLocalUnsafeDirectByteBuf extends UnpooledUnsafeDirectByteBuf {
|
||||
|
||||
private static final Recycler<ThreadLocalUnsafeDirectByteBuf> RECYCLER =
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package io.netty.buffer;
|
||||
|
||||
import io.netty.util.ByteProcessor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@ -293,12 +295,12 @@ public class DuplicatedByteBuf extends AbstractDerivedByteBuf {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(int index, int length, ByteBufProcessor processor) {
|
||||
public int forEachByte(int index, int length, ByteProcessor processor) {
|
||||
return buffer.forEachByte(index, length, processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(int index, int length, ByteBufProcessor processor) {
|
||||
public int forEachByteDesc(int index, int length, ByteProcessor processor) {
|
||||
return buffer.forEachByteDesc(index, length, processor);
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package io.netty.buffer;
|
||||
|
||||
import io.netty.util.ByteProcessor;
|
||||
import io.netty.util.internal.EmptyArrays;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
@ -668,23 +669,23 @@ public final class EmptyByteBuf extends ByteBuf {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(ByteBufProcessor processor) {
|
||||
public int forEachByte(ByteProcessor processor) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(int index, int length, ByteBufProcessor processor) {
|
||||
public int forEachByte(int index, int length, ByteProcessor processor) {
|
||||
checkIndex(index, length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(ByteBufProcessor processor) {
|
||||
public int forEachByteDesc(ByteProcessor processor) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(int index, int length, ByteBufProcessor processor) {
|
||||
public int forEachByteDesc(int index, int length, ByteProcessor processor) {
|
||||
checkIndex(index, length);
|
||||
return -1;
|
||||
}
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package io.netty.buffer;
|
||||
|
||||
import io.netty.util.ByteProcessor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@ -296,12 +298,12 @@ public class ReadOnlyByteBuf extends AbstractDerivedByteBuf {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(int index, int length, ByteBufProcessor processor) {
|
||||
public int forEachByte(int index, int length, ByteProcessor processor) {
|
||||
return buffer.forEachByte(index, length, processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(int index, int length, ByteBufProcessor processor) {
|
||||
public int forEachByteDesc(int index, int length, ByteProcessor processor) {
|
||||
return buffer.forEachByteDesc(index, length, processor);
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package io.netty.buffer;
|
||||
|
||||
import io.netty.util.ByteProcessor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@ -275,7 +277,7 @@ public class SlicedByteBuf extends AbstractDerivedByteBuf {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(int index, int length, ByteBufProcessor processor) {
|
||||
public int forEachByte(int index, int length, ByteProcessor processor) {
|
||||
int ret = buffer.forEachByte(index + adjustment, length, processor);
|
||||
if (ret >= adjustment) {
|
||||
return ret - adjustment;
|
||||
@ -285,7 +287,7 @@ public class SlicedByteBuf extends AbstractDerivedByteBuf {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(int index, int length, ByteBufProcessor processor) {
|
||||
public int forEachByteDesc(int index, int length, ByteProcessor processor) {
|
||||
int ret = buffer.forEachByteDesc(index + adjustment, length, processor);
|
||||
if (ret >= adjustment) {
|
||||
return ret - adjustment;
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package io.netty.buffer;
|
||||
|
||||
import io.netty.util.ByteProcessor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@ -680,22 +682,22 @@ public class SwappedByteBuf extends ByteBuf {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(ByteBufProcessor processor) {
|
||||
public int forEachByte(ByteProcessor processor) {
|
||||
return buf.forEachByte(processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(int index, int length, ByteBufProcessor processor) {
|
||||
public int forEachByte(int index, int length, ByteProcessor processor) {
|
||||
return buf.forEachByte(index, length, processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(ByteBufProcessor processor) {
|
||||
public int forEachByteDesc(ByteProcessor processor) {
|
||||
return buf.forEachByteDesc(processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(int index, int length, ByteBufProcessor processor) {
|
||||
public int forEachByteDesc(int index, int length, ByteProcessor processor) {
|
||||
return buf.forEachByteDesc(index, length, processor);
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package io.netty.buffer;
|
||||
|
||||
import io.netty.util.ByteProcessor;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -668,22 +669,22 @@ public class WrappedByteBuf extends ByteBuf {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(ByteBufProcessor processor) {
|
||||
public int forEachByte(ByteProcessor processor) {
|
||||
return buf.forEachByte(processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(int index, int length, ByteBufProcessor processor) {
|
||||
public int forEachByte(int index, int length, ByteProcessor processor) {
|
||||
return buf.forEachByte(index, length, processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(ByteBufProcessor processor) {
|
||||
public int forEachByteDesc(ByteProcessor processor) {
|
||||
return buf.forEachByteDesc(processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(int index, int length, ByteBufProcessor processor) {
|
||||
public int forEachByteDesc(int index, int length, ByteProcessor processor) {
|
||||
return buf.forEachByteDesc(index, length, processor);
|
||||
}
|
||||
|
||||
|
@ -15,9 +15,11 @@
|
||||
*/
|
||||
package io.netty.buffer;
|
||||
|
||||
import io.netty.util.ByteProcessor;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.IllegalReferenceCountException;
|
||||
import io.netty.util.internal.ThreadLocalRandom;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Before;
|
||||
@ -1666,7 +1668,7 @@ public abstract class AbstractByteBufTest {
|
||||
|
||||
final AtomicInteger lastIndex = new AtomicInteger();
|
||||
buffer.setIndex(CAPACITY / 4, CAPACITY * 3 / 4);
|
||||
assertThat(buffer.forEachByte(new ByteBufProcessor() {
|
||||
assertThat(buffer.forEachByte(new ByteProcessor() {
|
||||
int i = CAPACITY / 4;
|
||||
|
||||
@Override
|
||||
@ -1689,7 +1691,7 @@ public abstract class AbstractByteBufTest {
|
||||
}
|
||||
|
||||
final int stop = CAPACITY / 2;
|
||||
assertThat(buffer.forEachByte(CAPACITY / 3, CAPACITY / 3, new ByteBufProcessor() {
|
||||
assertThat(buffer.forEachByte(CAPACITY / 3, CAPACITY / 3, new ByteProcessor() {
|
||||
int i = CAPACITY / 3;
|
||||
|
||||
@Override
|
||||
@ -1713,7 +1715,7 @@ public abstract class AbstractByteBufTest {
|
||||
}
|
||||
|
||||
final AtomicInteger lastIndex = new AtomicInteger();
|
||||
assertThat(buffer.forEachByteDesc(CAPACITY / 4, CAPACITY * 2 / 4, new ByteBufProcessor() {
|
||||
assertThat(buffer.forEachByteDesc(CAPACITY / 4, CAPACITY * 2 / 4, new ByteProcessor() {
|
||||
int i = CAPACITY * 3 / 4 - 1;
|
||||
|
||||
@Override
|
||||
@ -2377,22 +2379,22 @@ public abstract class AbstractByteBufTest {
|
||||
|
||||
@Test(expected = IllegalReferenceCountException.class)
|
||||
public void testForEachByteAfterRelease() {
|
||||
releasedBuffer().forEachByte(new TestByteBufProcessor());
|
||||
releasedBuffer().forEachByte(new TestByteProcessor());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalReferenceCountException.class)
|
||||
public void testForEachByteAfterRelease1() {
|
||||
releasedBuffer().forEachByte(0, 1, new TestByteBufProcessor());
|
||||
releasedBuffer().forEachByte(0, 1, new TestByteProcessor());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalReferenceCountException.class)
|
||||
public void testForEachByteDescAfterRelease() {
|
||||
releasedBuffer().forEachByteDesc(new TestByteBufProcessor());
|
||||
releasedBuffer().forEachByteDesc(new TestByteProcessor());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalReferenceCountException.class)
|
||||
public void testForEachByteDescAfterRelease1() {
|
||||
releasedBuffer().forEachByteDesc(0, 1, new TestByteBufProcessor());
|
||||
releasedBuffer().forEachByteDesc(0, 1, new TestByteProcessor());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalReferenceCountException.class)
|
||||
@ -2647,7 +2649,7 @@ public abstract class AbstractByteBufTest {
|
||||
}
|
||||
}
|
||||
|
||||
private static final class TestByteBufProcessor implements ByteBufProcessor {
|
||||
private static final class TestByteProcessor implements ByteProcessor {
|
||||
@Override
|
||||
public boolean process(byte value) throws Exception {
|
||||
return true;
|
||||
|
@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package io.netty.buffer;
|
||||
|
||||
import io.netty.util.CharsetUtil;
|
||||
import org.junit.Test;
|
||||
|
||||
import static io.netty.util.ReferenceCountUtil.releaseLater;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class ByteBufProcessorTest {
|
||||
@Test
|
||||
public void testForward() {
|
||||
final ByteBuf buf = releaseLater(
|
||||
Unpooled.copiedBuffer("abc\r\n\ndef\r\rghi\n\njkl\0\0mno \t\tx", CharsetUtil.ISO_8859_1));
|
||||
final int length = buf.readableBytes();
|
||||
|
||||
assertEquals(3, buf.forEachByte(0, length, ByteBufProcessor.FIND_CRLF));
|
||||
assertEquals(6, buf.forEachByte(3, length - 3, ByteBufProcessor.FIND_NON_CRLF));
|
||||
assertEquals(9, buf.forEachByte(6, length - 6, ByteBufProcessor.FIND_CR));
|
||||
assertEquals(11, buf.forEachByte(9, length - 9, ByteBufProcessor.FIND_NON_CR));
|
||||
assertEquals(14, buf.forEachByte(11, length - 11, ByteBufProcessor.FIND_LF));
|
||||
assertEquals(16, buf.forEachByte(14, length - 14, ByteBufProcessor.FIND_NON_LF));
|
||||
assertEquals(19, buf.forEachByte(16, length - 16, ByteBufProcessor.FIND_NUL));
|
||||
assertEquals(21, buf.forEachByte(19, length - 19, ByteBufProcessor.FIND_NON_NUL));
|
||||
assertEquals(24, buf.forEachByte(21, length - 21, ByteBufProcessor.FIND_LINEAR_WHITESPACE));
|
||||
assertEquals(28, buf.forEachByte(24, length - 24, ByteBufProcessor.FIND_NON_LINEAR_WHITESPACE));
|
||||
assertEquals(-1, buf.forEachByte(28, length - 28, ByteBufProcessor.FIND_LINEAR_WHITESPACE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBackward() {
|
||||
final ByteBuf buf = releaseLater(
|
||||
Unpooled.copiedBuffer("abc\r\n\ndef\r\rghi\n\njkl\0\0mno \t\tx", CharsetUtil.ISO_8859_1));
|
||||
final int length = buf.readableBytes();
|
||||
|
||||
assertEquals(27, buf.forEachByteDesc(0, length, ByteBufProcessor.FIND_LINEAR_WHITESPACE));
|
||||
assertEquals(23, buf.forEachByteDesc(0, 28, ByteBufProcessor.FIND_NON_LINEAR_WHITESPACE));
|
||||
assertEquals(20, buf.forEachByteDesc(0, 24, ByteBufProcessor.FIND_NUL));
|
||||
assertEquals(18, buf.forEachByteDesc(0, 21, ByteBufProcessor.FIND_NON_NUL));
|
||||
assertEquals(15, buf.forEachByteDesc(0, 19, ByteBufProcessor.FIND_LF));
|
||||
assertEquals(13, buf.forEachByteDesc(0, 16, ByteBufProcessor.FIND_NON_LF));
|
||||
assertEquals(10, buf.forEachByteDesc(0, 14, ByteBufProcessor.FIND_CR));
|
||||
assertEquals(8, buf.forEachByteDesc(0, 11, ByteBufProcessor.FIND_NON_CR));
|
||||
assertEquals(5, buf.forEachByteDesc(0, 9, ByteBufProcessor.FIND_CRLF));
|
||||
assertEquals(2, buf.forEachByteDesc(0, 6, ByteBufProcessor.FIND_NON_CRLF));
|
||||
assertEquals(-1, buf.forEachByteDesc(0, 3, ByteBufProcessor.FIND_CRLF));
|
||||
}
|
||||
}
|
64
buffer/src/test/java/io/netty/buffer/ByteProcessorTest.java
Normal file
64
buffer/src/test/java/io/netty/buffer/ByteProcessorTest.java
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2013 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package io.netty.buffer;
|
||||
|
||||
import static io.netty.util.ReferenceCountUtil.releaseLater;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import io.netty.util.ByteProcessor;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class ByteProcessorTest {
|
||||
@Test
|
||||
public void testForward() {
|
||||
final ByteBuf buf = releaseLater(
|
||||
Unpooled.copiedBuffer("abc\r\n\ndef\r\rghi\n\njkl\0\0mno \t\tx", CharsetUtil.ISO_8859_1));
|
||||
final int length = buf.readableBytes();
|
||||
|
||||
assertEquals(3, buf.forEachByte(0, length, ByteProcessor.FIND_CRLF));
|
||||
assertEquals(6, buf.forEachByte(3, length - 3, ByteProcessor.FIND_NON_CRLF));
|
||||
assertEquals(9, buf.forEachByte(6, length - 6, ByteProcessor.FIND_CR));
|
||||
assertEquals(11, buf.forEachByte(9, length - 9, ByteProcessor.FIND_NON_CR));
|
||||
assertEquals(14, buf.forEachByte(11, length - 11, ByteProcessor.FIND_LF));
|
||||
assertEquals(16, buf.forEachByte(14, length - 14, ByteProcessor.FIND_NON_LF));
|
||||
assertEquals(19, buf.forEachByte(16, length - 16, ByteProcessor.FIND_NUL));
|
||||
assertEquals(21, buf.forEachByte(19, length - 19, ByteProcessor.FIND_NON_NUL));
|
||||
assertEquals(24, buf.forEachByte(21, length - 21, ByteProcessor.FIND_LINEAR_WHITESPACE));
|
||||
assertEquals(28, buf.forEachByte(24, length - 24, ByteProcessor.FIND_NON_LINEAR_WHITESPACE));
|
||||
assertEquals(-1, buf.forEachByte(28, length - 28, ByteProcessor.FIND_LINEAR_WHITESPACE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBackward() {
|
||||
final ByteBuf buf = releaseLater(
|
||||
Unpooled.copiedBuffer("abc\r\n\ndef\r\rghi\n\njkl\0\0mno \t\tx", CharsetUtil.ISO_8859_1));
|
||||
final int length = buf.readableBytes();
|
||||
|
||||
assertEquals(27, buf.forEachByteDesc(0, length, ByteProcessor.FIND_LINEAR_WHITESPACE));
|
||||
assertEquals(23, buf.forEachByteDesc(0, 28, ByteProcessor.FIND_NON_LINEAR_WHITESPACE));
|
||||
assertEquals(20, buf.forEachByteDesc(0, 24, ByteProcessor.FIND_NUL));
|
||||
assertEquals(18, buf.forEachByteDesc(0, 21, ByteProcessor.FIND_NON_NUL));
|
||||
assertEquals(15, buf.forEachByteDesc(0, 19, ByteProcessor.FIND_LF));
|
||||
assertEquals(13, buf.forEachByteDesc(0, 16, ByteProcessor.FIND_NON_LF));
|
||||
assertEquals(10, buf.forEachByteDesc(0, 14, ByteProcessor.FIND_CR));
|
||||
assertEquals(8, buf.forEachByteDesc(0, 11, ByteProcessor.FIND_NON_CR));
|
||||
assertEquals(5, buf.forEachByteDesc(0, 9, ByteProcessor.FIND_CRLF));
|
||||
assertEquals(2, buf.forEachByteDesc(0, 6, ByteProcessor.FIND_NON_CRLF));
|
||||
assertEquals(-1, buf.forEachByteDesc(0, 3, ByteProcessor.FIND_CRLF));
|
||||
}
|
||||
}
|
@ -16,8 +16,8 @@
|
||||
package io.netty.handler.codec.haproxy;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufProcessor;
|
||||
import io.netty.handler.codec.haproxy.HAProxyProxiedProtocol.AddressFamily;
|
||||
import io.netty.util.ByteProcessor;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.NetUtil;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
@ -166,7 +166,7 @@ public final class HAProxyMessage {
|
||||
Math.min(addressInfoLen, header.readableBytes()) + " bytes (expected: 216+ bytes)");
|
||||
}
|
||||
int startIdx = header.readerIndex();
|
||||
int addressEnd = header.forEachByte(startIdx, 108, ByteBufProcessor.FIND_NUL);
|
||||
int addressEnd = header.forEachByte(startIdx, 108, ByteProcessor.FIND_NUL);
|
||||
if (addressEnd == -1) {
|
||||
addressLen = 108;
|
||||
} else {
|
||||
@ -176,7 +176,7 @@ public final class HAProxyMessage {
|
||||
|
||||
startIdx += 108;
|
||||
|
||||
addressEnd = header.forEachByte(startIdx, 108, ByteBufProcessor.FIND_NUL);
|
||||
addressEnd = header.forEachByte(startIdx, 108, ByteProcessor.FIND_NUL);
|
||||
if (addressEnd == -1) {
|
||||
addressLen = 108;
|
||||
} else {
|
||||
|
@ -15,9 +15,11 @@
|
||||
*/
|
||||
package io.netty.handler.codec.http;
|
||||
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.DefaultTextHeaders;
|
||||
import io.netty.handler.codec.TextHeaders;
|
||||
import io.netty.util.AsciiString;
|
||||
import io.netty.util.ByteProcessor;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
@ -81,17 +83,34 @@ public class DefaultHttpHeaders extends DefaultTextHeaders implements HttpHeader
|
||||
return seq;
|
||||
}
|
||||
|
||||
private static void validateValue(AsciiString seq) {
|
||||
int state = 0;
|
||||
// Start looping through each of the character
|
||||
final int start = seq.arrayOffset();
|
||||
final int end = start + seq.length();
|
||||
final byte[] array = seq.array();
|
||||
for (int index = start; index < end; index++) {
|
||||
state = validateValueChar(seq, state, (char) (array[index] & 0xFF));
|
||||
private static final class ValidateValueProcessor implements ByteProcessor {
|
||||
private final CharSequence seq;
|
||||
private int state;
|
||||
|
||||
public ValidateValueProcessor(CharSequence seq) {
|
||||
this.seq = seq;
|
||||
}
|
||||
|
||||
if (state != 0) {
|
||||
@Override
|
||||
public boolean process(byte value) throws Exception {
|
||||
state = validateValueChar(state, (char) value, seq);
|
||||
return true;
|
||||
}
|
||||
|
||||
public int state() {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateValue(AsciiString seq) {
|
||||
ValidateValueProcessor processor = new ValidateValueProcessor(seq);
|
||||
try {
|
||||
seq.forEachByte(processor);
|
||||
} catch (Throwable t) {
|
||||
PlatformDependent.throwException(t);
|
||||
}
|
||||
|
||||
if (processor.state() != 0) {
|
||||
throw new IllegalArgumentException("a header value must not end with '\\r' or '\\n':" + seq);
|
||||
}
|
||||
}
|
||||
@ -100,7 +119,7 @@ public class DefaultHttpHeaders extends DefaultTextHeaders implements HttpHeader
|
||||
int state = 0;
|
||||
// Start looping through each of the character
|
||||
for (int index = 0; index < seq.length(); index++) {
|
||||
state = validateValueChar(seq, state, seq.charAt(index));
|
||||
state = validateValueChar(state, seq.charAt(index), seq);
|
||||
}
|
||||
|
||||
if (state != 0) {
|
||||
@ -108,16 +127,16 @@ public class DefaultHttpHeaders extends DefaultTextHeaders implements HttpHeader
|
||||
}
|
||||
}
|
||||
|
||||
private static int validateValueChar(CharSequence seq, int state, char character) {
|
||||
private static int validateValueChar(int state, char c, CharSequence seq) {
|
||||
/*
|
||||
* State:
|
||||
* 0: Previous character was neither CR nor LF
|
||||
* 1: The previous character was CR
|
||||
* 2: The previous character was LF
|
||||
*/
|
||||
if ((character & HIGHEST_INVALID_VALUE_CHAR_MASK) == 0) {
|
||||
if ((c & HIGHEST_INVALID_VALUE_CHAR_MASK) == 0) {
|
||||
// Check the absolutely prohibited characters.
|
||||
switch (character) {
|
||||
switch (c) {
|
||||
case 0x0: // NULL
|
||||
throw new IllegalArgumentException("a header value contains a prohibited character '\0': " + seq);
|
||||
case 0x0b: // Vertical tab
|
||||
@ -130,7 +149,7 @@ public class DefaultHttpHeaders extends DefaultTextHeaders implements HttpHeader
|
||||
// Check the CRLF (HT | SP) pattern
|
||||
switch (state) {
|
||||
case 0:
|
||||
switch (character) {
|
||||
switch (c) {
|
||||
case '\r':
|
||||
state = 1;
|
||||
break;
|
||||
@ -140,7 +159,7 @@ public class DefaultHttpHeaders extends DefaultTextHeaders implements HttpHeader
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
switch (character) {
|
||||
switch (c) {
|
||||
case '\n':
|
||||
state = 2;
|
||||
break;
|
||||
@ -149,7 +168,7 @@ public class DefaultHttpHeaders extends DefaultTextHeaders implements HttpHeader
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
switch (character) {
|
||||
switch (c) {
|
||||
case '\t':
|
||||
case ' ':
|
||||
state = 0;
|
||||
@ -165,6 +184,24 @@ public class DefaultHttpHeaders extends DefaultTextHeaders implements HttpHeader
|
||||
static class HttpHeadersNameConverter implements NameConverter<CharSequence> {
|
||||
protected final boolean validate;
|
||||
|
||||
private static final class ValidateNameProcessor implements ByteProcessor {
|
||||
private final CharSequence seq;
|
||||
|
||||
public ValidateNameProcessor(CharSequence seq) {
|
||||
this.seq = seq;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(byte value) throws Exception {
|
||||
// Check to see if the character is not an ASCII character.
|
||||
if (value < 0) {
|
||||
throw new IllegalArgumentException("a header name cannot contain non-ASCII character: " + seq);
|
||||
}
|
||||
validateNameChar(value, seq);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
HttpHeadersNameConverter(boolean validate) {
|
||||
this.validate = validate;
|
||||
}
|
||||
@ -183,43 +220,33 @@ public class DefaultHttpHeaders extends DefaultTextHeaders implements HttpHeader
|
||||
}
|
||||
|
||||
private static void validateName(AsciiString name) {
|
||||
// Go through each characters in the name
|
||||
final int start = name.arrayOffset();
|
||||
final int end = start + name.length();
|
||||
final byte[] array = name.array();
|
||||
for (int index = start; index < end; index ++) {
|
||||
byte b = array[index];
|
||||
|
||||
// Check to see if the character is not an ASCII character
|
||||
if (b < 0) {
|
||||
throw new IllegalArgumentException("a header name cannot contain non-ASCII characters: " + name);
|
||||
}
|
||||
|
||||
// Check for prohibited characters.
|
||||
validateNameChar(name, b);
|
||||
try {
|
||||
name.forEachByte(new ValidateNameProcessor(name));
|
||||
} catch (Throwable t) {
|
||||
PlatformDependent.throwException(t);
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateName(CharSequence name) {
|
||||
// Go through each characters in the name
|
||||
// Go through each characters in the name.
|
||||
for (int index = 0; index < name.length(); index++) {
|
||||
char character = name.charAt(index);
|
||||
char c = name.charAt(index);
|
||||
|
||||
// Check to see if the character is not an ASCII character
|
||||
if (character > 127) {
|
||||
// Check to see if the character is not an ASCII character.
|
||||
if (c > 127) {
|
||||
throw new IllegalArgumentException("a header name cannot contain non-ASCII characters: " + name);
|
||||
}
|
||||
|
||||
// Check for prohibited characters.
|
||||
validateNameChar(name, character);
|
||||
validateNameChar(c, name);
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateNameChar(CharSequence name, int character) {
|
||||
private static void validateNameChar(int character, CharSequence seq) {
|
||||
if ((character & HIGHEST_INVALID_NAME_CHAR_MASK) == 0 && LOOKUP_TABLE[character] != 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"a header name cannot contain the following prohibited characters: =,;: \\t\\r\\n\\v\\f: " +
|
||||
name);
|
||||
seq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ package io.netty.handler.codec.http;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.util.AsciiString;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
package io.netty.handler.codec.http;
|
||||
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.util.AsciiString;
|
||||
|
||||
/**
|
||||
* Standard HTTP header names.
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
package io.netty.handler.codec.http;
|
||||
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.util.AsciiString;
|
||||
|
||||
/**
|
||||
* Standard HTTP header values.
|
||||
|
@ -17,7 +17,6 @@ package io.netty.handler.codec.http;
|
||||
|
||||
import io.netty.handler.codec.TextHeaders;
|
||||
|
||||
|
||||
/**
|
||||
* Provides the constants for the standard HTTP header names and values and
|
||||
* commonly used utility methods that accesses an {@link HttpMessage}.
|
||||
|
@ -17,8 +17,9 @@
|
||||
package io.netty.handler.codec.http;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.handler.codec.TextHeaders.EntryVisitor;
|
||||
import io.netty.util.AsciiString;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
@ -61,7 +62,7 @@ final class HttpHeadersEncoder implements EntryVisitor {
|
||||
}
|
||||
|
||||
private static void writeAsciiString(ByteBuf buf, int offset, AsciiString value, int valueLen) {
|
||||
value.copy(0, buf, offset, valueLen);
|
||||
ByteBufUtil.copy(value, 0, buf, offset, valueLen);
|
||||
}
|
||||
|
||||
private static void writeCharSequence(ByteBuf buf, int offset, CharSequence value, int valueLen) {
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
package io.netty.handler.codec.http;
|
||||
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.util.AsciiString;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -16,13 +16,13 @@
|
||||
package io.netty.handler.codec.http;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufProcessor;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.handler.codec.DecoderResult;
|
||||
import io.netty.handler.codec.TooLongFrameException;
|
||||
import io.netty.util.ByteProcessor;
|
||||
import io.netty.util.internal.AppendableCharSequence;
|
||||
|
||||
import java.util.List;
|
||||
@ -734,7 +734,7 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static class HeaderParser implements ByteBufProcessor {
|
||||
private static class HeaderParser implements ByteProcessor {
|
||||
private final AppendableCharSequence seq;
|
||||
private final int maxLength;
|
||||
private int size;
|
||||
|
@ -15,12 +15,13 @@
|
||||
*/
|
||||
package io.netty.handler.codec.http;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpConstants.CR;
|
||||
import static io.netty.handler.codec.http.HttpConstants.LF;
|
||||
import static io.netty.handler.codec.http.HttpConstants.SP;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.util.AsciiString;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpConstants.*;
|
||||
|
||||
/**
|
||||
* Encodes an {@link HttpRequest} or an {@link HttpContent} into
|
||||
* a {@link ByteBuf}.
|
||||
@ -38,7 +39,7 @@ public class HttpRequestEncoder extends HttpObjectEncoder<HttpRequest> {
|
||||
@Override
|
||||
protected void encodeInitialLine(ByteBuf buf, HttpRequest request) throws Exception {
|
||||
AsciiString method = request.method().name();
|
||||
buf.writeBytes(method.array(), method.arrayOffset(), method.length());
|
||||
buf.writeBytes(method.array());
|
||||
buf.writeByte(SP);
|
||||
|
||||
// Add / as absolute path if no is present.
|
||||
@ -75,7 +76,7 @@ public class HttpRequestEncoder extends HttpObjectEncoder<HttpRequest> {
|
||||
buf.writeByte(SP);
|
||||
|
||||
AsciiString version = request.protocolVersion().text();
|
||||
buf.writeBytes(version.array(), version.arrayOffset(), version.length());
|
||||
buf.writeBytes(version.array());
|
||||
buf.writeBytes(CRLF);
|
||||
}
|
||||
}
|
||||
|
@ -15,10 +15,11 @@
|
||||
*/
|
||||
package io.netty.handler.codec.http;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpConstants.CR;
|
||||
import static io.netty.handler.codec.http.HttpConstants.LF;
|
||||
import static io.netty.handler.codec.http.HttpConstants.SP;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpConstants.*;
|
||||
import io.netty.util.AsciiString;
|
||||
|
||||
/**
|
||||
* Encodes an {@link HttpResponse} or an {@link HttpContent} into
|
||||
@ -35,15 +36,15 @@ public class HttpResponseEncoder extends HttpObjectEncoder<HttpResponse> {
|
||||
@Override
|
||||
protected void encodeInitialLine(ByteBuf buf, HttpResponse response) throws Exception {
|
||||
AsciiString version = response.protocolVersion().text();
|
||||
buf.writeBytes(version.array(), version.arrayOffset(), version.length());
|
||||
buf.writeBytes(version.array());
|
||||
buf.writeByte(SP);
|
||||
|
||||
AsciiString code = response.status().codeAsText();
|
||||
buf.writeBytes(code.array(), code.arrayOffset(), code.length());
|
||||
buf.writeBytes(code.array());
|
||||
buf.writeByte(SP);
|
||||
|
||||
AsciiString reasonPhrase = response.status().reasonPhrase();
|
||||
buf.writeBytes(reasonPhrase.array(), reasonPhrase.arrayOffset(), reasonPhrase.length());
|
||||
buf.writeBytes(reasonPhrase.array());
|
||||
buf.writeBytes(CRLF);
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,9 @@
|
||||
*/
|
||||
package io.netty.handler.codec.http;
|
||||
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.util.AsciiString;
|
||||
import io.netty.util.ByteProcessor;
|
||||
import io.netty.util.ByteString;
|
||||
|
||||
/**
|
||||
* The response code and its description of HTTP or its derived protocols, such as
|
||||
@ -464,6 +466,85 @@ public class HttpResponseStatus implements Comparable<HttpResponseStatus> {
|
||||
}
|
||||
}
|
||||
|
||||
private static final class HttpStatusLineProcessor implements ByteProcessor {
|
||||
private static final byte ASCII_SPACE = (byte) ' ';
|
||||
private final ByteString string;
|
||||
private int i;
|
||||
/**
|
||||
* 0 = New or havn't seen {@link ASCII_SPACE}.
|
||||
* 1 = Last byte was {@link ASCII_SPACE}.
|
||||
* 2 = Terminal State. Processed the byte after {@link ASCII_SPACE}, and parsed the status line.
|
||||
* 3 = Terminal State. There was no byte after {@link ASCII_SPACE} but status has been parsed with what we saw.
|
||||
*/
|
||||
private int state;
|
||||
private HttpResponseStatus status;
|
||||
|
||||
public HttpStatusLineProcessor(ByteString string) {
|
||||
this.string = string;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(byte value) {
|
||||
switch (state) {
|
||||
case 0:
|
||||
if (value == ASCII_SPACE) {
|
||||
state = 1;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
parseStatus(i);
|
||||
state = 2;
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void parseStatus(int codeEnd) {
|
||||
int code = string.parseAsciiInt(0, codeEnd);
|
||||
status = valueOf(code);
|
||||
if (codeEnd < string.length()) {
|
||||
String actualReason = string.toString(codeEnd + 1, string.length());
|
||||
if (!status.reasonPhrase().equals(actualReason)) {
|
||||
status = new HttpResponseStatus(code, actualReason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public HttpResponseStatus status() {
|
||||
if (state <= 1) {
|
||||
parseStatus(string.length());
|
||||
state = 3;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the specified HTTP status line into a {@link HttpResponseStatus}. The expected formats of the line are:
|
||||
* <ul>
|
||||
* <li>{@code statusCode} (e.g. 200)</li>
|
||||
* <li>{@code statusCode} {@code reasonPhrase} (e.g. 404 Not Found)</li>
|
||||
* </ul>
|
||||
*
|
||||
* @throws IllegalArgumentException if the specified status line is malformed
|
||||
*/
|
||||
public static HttpResponseStatus parseLine(ByteString line) {
|
||||
try {
|
||||
HttpStatusLineProcessor processor = new HttpStatusLineProcessor(line);
|
||||
line.forEachByte(processor);
|
||||
HttpResponseStatus status = processor.status();
|
||||
if (status == null) {
|
||||
throw new IllegalArgumentException("unable to get status after parsing input");
|
||||
}
|
||||
return status;
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("malformed status line: " + line, e);
|
||||
}
|
||||
}
|
||||
|
||||
private final int code;
|
||||
private final AsciiString codeAsText;
|
||||
private HttpStatusClass codeClass;
|
||||
|
@ -17,7 +17,7 @@ package io.netty.handler.codec.http;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.util.AsciiString;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
import io.netty.util.ReferenceCounted;
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
package io.netty.handler.codec.http;
|
||||
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.util.AsciiString;
|
||||
|
||||
/**
|
||||
* The class of HTTP status.
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
package io.netty.handler.codec.http;
|
||||
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.util.AsciiString;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
@ -36,13 +36,13 @@
|
||||
package io.netty.handler.codec.http.websocketx;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufProcessor;
|
||||
import io.netty.handler.codec.CorruptedFrameException;
|
||||
import io.netty.util.ByteProcessor;
|
||||
|
||||
/**
|
||||
* Checks UTF8 bytes for validity
|
||||
*/
|
||||
final class Utf8Validator implements ByteBufProcessor {
|
||||
final class Utf8Validator implements ByteProcessor {
|
||||
private static final int UTF8_ACCEPT = 0;
|
||||
private static final int UTF8_REJECT = 12;
|
||||
|
||||
|
@ -17,7 +17,6 @@ package io.netty.handler.codec.http.websocketx;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
@ -27,6 +26,7 @@ import io.netty.handler.codec.http.HttpHeaders;
|
||||
import io.netty.handler.codec.http.HttpMethod;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import io.netty.util.AsciiString;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
|
@ -15,12 +15,12 @@
|
||||
*/
|
||||
package io.netty.handler.codec.http.websocketx;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
@ -28,11 +28,10 @@ import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpHeaderValues;
|
||||
import io.netty.handler.codec.http.HttpHeaders;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.util.AsciiString;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpVersion.*;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Performs server side opening and closing handshakes for web socket specification version <a
|
||||
|
@ -16,8 +16,8 @@
|
||||
|
||||
package io.netty.handler.codec.rtsp;
|
||||
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.util.AsciiString;
|
||||
|
||||
/**
|
||||
* Standard RTSP header names.
|
||||
|
@ -16,8 +16,8 @@
|
||||
|
||||
package io.netty.handler.codec.rtsp;
|
||||
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.http.HttpHeaderValues;
|
||||
import io.netty.util.AsciiString;
|
||||
|
||||
/**
|
||||
* Standard RTSP header names.
|
||||
|
@ -15,14 +15,15 @@
|
||||
*/
|
||||
package io.netty.handler.codec.rtsp;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpConstants.CR;
|
||||
import static io.netty.handler.codec.http.HttpConstants.LF;
|
||||
import static io.netty.handler.codec.http.HttpConstants.SP;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpRequest;
|
||||
import io.netty.util.AsciiString;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpConstants.*;
|
||||
|
||||
/**
|
||||
* Encodes an RTSP request represented in {@link FullHttpRequest} into
|
||||
* a {@link ByteBuf}.
|
||||
@ -39,14 +40,14 @@ public class RtspRequestEncoder extends RtspObjectEncoder<HttpRequest> {
|
||||
@Override
|
||||
protected void encodeInitialLine(ByteBuf buf, HttpRequest request) throws Exception {
|
||||
AsciiString method = request.method().name();
|
||||
buf.writeBytes(method.array(), method.arrayOffset(), method.length());
|
||||
buf.writeBytes(method.array());
|
||||
buf.writeByte(SP);
|
||||
|
||||
buf.writeBytes(request.uri().getBytes(CharsetUtil.UTF_8));
|
||||
buf.writeByte(SP);
|
||||
|
||||
AsciiString version = request.protocolVersion().text();
|
||||
buf.writeBytes(version.array(), version.arrayOffset(), version.length());
|
||||
buf.writeBytes(version.array());
|
||||
buf.writeBytes(CRLF);
|
||||
}
|
||||
}
|
||||
|
@ -15,12 +15,13 @@
|
||||
*/
|
||||
package io.netty.handler.codec.rtsp;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpConstants.CR;
|
||||
import static io.netty.handler.codec.http.HttpConstants.LF;
|
||||
import static io.netty.handler.codec.http.HttpConstants.SP;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpResponse;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpConstants.*;
|
||||
import io.netty.util.AsciiString;
|
||||
|
||||
/**
|
||||
* Encodes an RTSP response represented in {@link FullHttpResponse} into
|
||||
@ -37,15 +38,15 @@ public class RtspResponseEncoder extends RtspObjectEncoder<HttpResponse> {
|
||||
@Override
|
||||
protected void encodeInitialLine(ByteBuf buf, HttpResponse response) throws Exception {
|
||||
AsciiString version = response.protocolVersion().text();
|
||||
buf.writeBytes(version.array(), version.arrayOffset(), version.length());
|
||||
buf.writeBytes(version.array());
|
||||
buf.writeByte(SP);
|
||||
|
||||
AsciiString code = response.status().codeAsText();
|
||||
buf.writeBytes(code.array(), code.arrayOffset(), code.length());
|
||||
buf.writeBytes(code.array());
|
||||
buf.writeByte(SP);
|
||||
|
||||
AsciiString reasonPhrase = response.status().reasonPhrase();
|
||||
buf.writeBytes(reasonPhrase.array(), reasonPhrase.arrayOffset(), reasonPhrase.length());
|
||||
buf.writeBytes(reasonPhrase.array());
|
||||
buf.writeBytes(CRLF);
|
||||
}
|
||||
}
|
||||
|
@ -15,10 +15,10 @@
|
||||
*/
|
||||
package io.netty.handler.codec.spdy;
|
||||
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.DefaultTextHeaders;
|
||||
import io.netty.handler.codec.Headers;
|
||||
import io.netty.handler.codec.TextHeaders;
|
||||
import io.netty.util.AsciiString;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
|
@ -18,8 +18,10 @@ package io.netty.handler.codec.spdy;
|
||||
import static io.netty.handler.codec.spdy.SpdyCodecUtil.SPDY_MAX_NV_LENGTH;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.util.AsciiString;
|
||||
import io.netty.util.ByteString;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import java.util.Set;
|
||||
@ -57,18 +59,20 @@ public class SpdyHeaderBlockRawEncoder extends SpdyHeaderBlockEncoder {
|
||||
ByteBuf headerBlock = alloc.heapBuffer();
|
||||
writeLengthField(headerBlock, numHeaders);
|
||||
for (CharSequence name: names) {
|
||||
byte[] nameBytes = AsciiString.getBytes(name, CharsetUtil.UTF_8);
|
||||
writeLengthField(headerBlock, nameBytes.length);
|
||||
headerBlock.writeBytes(nameBytes);
|
||||
final ByteString nameBytes = new ByteString(name, CharsetUtil.UTF_8);
|
||||
int length = nameBytes.length();
|
||||
writeLengthField(headerBlock, length);
|
||||
ByteBufUtil.copy(nameBytes, 0, headerBlock, length);
|
||||
int savedIndex = headerBlock.writerIndex();
|
||||
int valueLength = 0;
|
||||
writeLengthField(headerBlock, valueLength);
|
||||
for (CharSequence value: frame.headers().getAll(name)) {
|
||||
byte[] valueBytes = AsciiString.getBytes(value, CharsetUtil.UTF_8);
|
||||
if (valueBytes.length > 0) {
|
||||
headerBlock.writeBytes(valueBytes);
|
||||
final ByteString valueBytes = new ByteString(value, CharsetUtil.UTF_8);
|
||||
length = valueBytes.length();
|
||||
if (length > 0) {
|
||||
ByteBufUtil.copy(valueBytes, 0, headerBlock, length);
|
||||
headerBlock.writeByte(0);
|
||||
valueLength += valueBytes.length + 1;
|
||||
valueLength += length + 1;
|
||||
}
|
||||
}
|
||||
if (valueLength != 0) {
|
||||
|
@ -15,8 +15,8 @@
|
||||
*/
|
||||
package io.netty.handler.codec.spdy;
|
||||
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.TextHeaders;
|
||||
import io.netty.util.AsciiString;
|
||||
|
||||
/**
|
||||
* Provides the constants for the standard SPDY HTTP header names and commonly
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
package io.netty.handler.codec.spdy;
|
||||
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.util.AsciiString;
|
||||
|
||||
/**
|
||||
* Provides the constants for the header names used by the {@link SpdyHttpDecoder} and {@link SpdyHttpEncoder}.
|
||||
|
@ -15,7 +15,8 @@
|
||||
*/
|
||||
package io.netty.handler.codec.http;
|
||||
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.util.AsciiString;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -28,10 +28,10 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.channel.ChannelPromiseAggregator;
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.handler.codec.compression.ZlibCodecFactory;
|
||||
import io.netty.handler.codec.compression.ZlibWrapper;
|
||||
import io.netty.util.ByteString;
|
||||
|
||||
/**
|
||||
* A decorating HTTP2 encoder that will compress data frames according to the {@code content-encoding} header for each
|
||||
@ -170,11 +170,11 @@ public class CompressorHttp2ConnectionEncoder extends DecoratingHttp2ConnectionE
|
||||
* (alternatively, you can throw a {@link Http2Exception} to block unknown encoding).
|
||||
* @throws Http2Exception If the specified encoding is not not supported and warrants an exception
|
||||
*/
|
||||
protected EmbeddedChannel newContentCompressor(AsciiString contentEncoding) throws Http2Exception {
|
||||
if (GZIP.equalsIgnoreCase(contentEncoding) || X_GZIP.equalsIgnoreCase(contentEncoding)) {
|
||||
protected EmbeddedChannel newContentCompressor(ByteString contentEncoding) throws Http2Exception {
|
||||
if (GZIP.equals(contentEncoding) || X_GZIP.equals(contentEncoding)) {
|
||||
return newCompressionChannel(ZlibWrapper.GZIP);
|
||||
}
|
||||
if (DEFLATE.equalsIgnoreCase(contentEncoding) || X_DEFLATE.equalsIgnoreCase(contentEncoding)) {
|
||||
if (DEFLATE.equals(contentEncoding) || X_DEFLATE.equals(contentEncoding)) {
|
||||
return newCompressionChannel(ZlibWrapper.ZLIB);
|
||||
}
|
||||
// 'identity' or unsupported
|
||||
@ -189,7 +189,7 @@ public class CompressorHttp2ConnectionEncoder extends DecoratingHttp2ConnectionE
|
||||
* @return the expected content encoding of the new content.
|
||||
* @throws Http2Exception if the {@code contentEncoding} is not supported and warrants an exception
|
||||
*/
|
||||
protected AsciiString getTargetContentEncoding(AsciiString contentEncoding) throws Http2Exception {
|
||||
protected ByteString getTargetContentEncoding(ByteString contentEncoding) throws Http2Exception {
|
||||
return contentEncoding;
|
||||
}
|
||||
|
||||
@ -219,7 +219,7 @@ public class CompressorHttp2ConnectionEncoder extends DecoratingHttp2ConnectionE
|
||||
EmbeddedChannel compressor = stream.getProperty(CompressorHttp2ConnectionEncoder.class);
|
||||
if (compressor == null) {
|
||||
if (!endOfStream) {
|
||||
AsciiString encoding = headers.get(CONTENT_ENCODING);
|
||||
ByteString encoding = headers.get(CONTENT_ENCODING);
|
||||
if (encoding == null) {
|
||||
encoding = IDENTITY;
|
||||
}
|
||||
@ -227,8 +227,8 @@ public class CompressorHttp2ConnectionEncoder extends DecoratingHttp2ConnectionE
|
||||
compressor = newContentCompressor(encoding);
|
||||
if (compressor != null) {
|
||||
stream.setProperty(CompressorHttp2ConnectionEncoder.class, compressor);
|
||||
AsciiString targetContentEncoding = getTargetContentEncoding(encoding);
|
||||
if (IDENTITY.equalsIgnoreCase(targetContentEncoding)) {
|
||||
ByteString targetContentEncoding = getTargetContentEncoding(encoding);
|
||||
if (IDENTITY.equals(targetContentEncoding)) {
|
||||
headers.remove(CONTENT_ENCODING);
|
||||
} else {
|
||||
headers.set(CONTENT_ENCODING, targetContentEncoding);
|
||||
|
@ -14,11 +14,63 @@
|
||||
*/
|
||||
package io.netty.handler.codec.http2;
|
||||
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import static io.netty.util.internal.StringUtil.UPPER_CASE_TO_LOWER_CASE_ASCII_OFFSET;
|
||||
import io.netty.handler.codec.BinaryHeaders;
|
||||
import io.netty.handler.codec.DefaultBinaryHeaders;
|
||||
import io.netty.util.AsciiString;
|
||||
import io.netty.util.ByteProcessor;
|
||||
import io.netty.util.ByteString;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
|
||||
public class DefaultHttp2Headers extends DefaultBinaryHeaders implements Http2Headers {
|
||||
private static final ByteProcessor HTTP2_ASCII_UPPERCASE_PROCESSOR = new ByteProcessor() {
|
||||
@Override
|
||||
public boolean process(byte value) throws Exception {
|
||||
return value < 'A' || value > 'Z';
|
||||
}
|
||||
};
|
||||
|
||||
private static final class Http2AsciiToLowerCaseConverter implements ByteProcessor {
|
||||
private final byte[] result;
|
||||
private int i;
|
||||
|
||||
public Http2AsciiToLowerCaseConverter(int length) {
|
||||
result = new byte[length];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(byte value) throws Exception {
|
||||
result[i++] = (value >= 'A' && value <= 'Z')
|
||||
? (byte) (value + UPPER_CASE_TO_LOWER_CASE_ASCII_OFFSET) : value;
|
||||
return true;
|
||||
}
|
||||
|
||||
public byte[] result() {
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
private static final NameConverter<ByteString> HTTP2_ASCII_TO_LOWER_CONVERTER = new NameConverter<ByteString>() {
|
||||
@Override
|
||||
public ByteString convertName(ByteString name) {
|
||||
if (name instanceof AsciiString) {
|
||||
return ((AsciiString) name).toLowerCase();
|
||||
}
|
||||
|
||||
try {
|
||||
if (name.forEachByte(HTTP2_ASCII_UPPERCASE_PROCESSOR) == -1) {
|
||||
return name;
|
||||
}
|
||||
|
||||
Http2AsciiToLowerCaseConverter converter = new Http2AsciiToLowerCaseConverter(name.length());
|
||||
name.forEachByte(converter);
|
||||
return new ByteString(converter.result(), false);
|
||||
} catch (Exception e) {
|
||||
PlatformDependent.throwException(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an instance that will convert all header names to lowercase.
|
||||
@ -41,95 +93,95 @@ public class DefaultHttp2Headers extends DefaultBinaryHeaders implements Http2He
|
||||
* @param forceKeyToLower if @{code false} no header name conversion will be performed
|
||||
*/
|
||||
public DefaultHttp2Headers(boolean forceKeyToLower) {
|
||||
super(forceKeyToLower);
|
||||
super(forceKeyToLower ? HTTP2_ASCII_TO_LOWER_CONVERTER : IDENTITY_NAME_CONVERTER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers add(AsciiString name, AsciiString value) {
|
||||
public Http2Headers add(ByteString name, ByteString value) {
|
||||
super.add(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers add(AsciiString name, Iterable<? extends AsciiString> values) {
|
||||
public Http2Headers add(ByteString name, Iterable<? extends ByteString> values) {
|
||||
super.add(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers add(AsciiString name, AsciiString... values) {
|
||||
public Http2Headers add(ByteString name, ByteString... values) {
|
||||
super.add(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addObject(AsciiString name, Object value) {
|
||||
public Http2Headers addObject(ByteString name, Object value) {
|
||||
super.addObject(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addObject(AsciiString name, Iterable<?> values) {
|
||||
public Http2Headers addObject(ByteString name, Iterable<?> values) {
|
||||
super.addObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addObject(AsciiString name, Object... values) {
|
||||
public Http2Headers addObject(ByteString name, Object... values) {
|
||||
super.addObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addBoolean(AsciiString name, boolean value) {
|
||||
public Http2Headers addBoolean(ByteString name, boolean value) {
|
||||
super.addBoolean(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addChar(AsciiString name, char value) {
|
||||
public Http2Headers addChar(ByteString name, char value) {
|
||||
super.addChar(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addByte(AsciiString name, byte value) {
|
||||
public Http2Headers addByte(ByteString name, byte value) {
|
||||
super.addByte(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addShort(AsciiString name, short value) {
|
||||
public Http2Headers addShort(ByteString name, short value) {
|
||||
super.addShort(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addInt(AsciiString name, int value) {
|
||||
public Http2Headers addInt(ByteString name, int value) {
|
||||
super.addInt(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addLong(AsciiString name, long value) {
|
||||
public Http2Headers addLong(ByteString name, long value) {
|
||||
super.addLong(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addFloat(AsciiString name, float value) {
|
||||
public Http2Headers addFloat(ByteString name, float value) {
|
||||
super.addFloat(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addDouble(AsciiString name, double value) {
|
||||
public Http2Headers addDouble(ByteString name, double value) {
|
||||
super.addDouble(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addTimeMillis(AsciiString name, long value) {
|
||||
public Http2Headers addTimeMillis(ByteString name, long value) {
|
||||
super.addTimeMillis(name, value);
|
||||
return this;
|
||||
}
|
||||
@ -141,91 +193,91 @@ public class DefaultHttp2Headers extends DefaultBinaryHeaders implements Http2He
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers set(AsciiString name, AsciiString value) {
|
||||
public Http2Headers set(ByteString name, ByteString value) {
|
||||
super.set(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers set(AsciiString name, Iterable<? extends AsciiString> values) {
|
||||
public Http2Headers set(ByteString name, Iterable<? extends ByteString> values) {
|
||||
super.set(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers set(AsciiString name, AsciiString... values) {
|
||||
public Http2Headers set(ByteString name, ByteString... values) {
|
||||
super.set(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setObject(AsciiString name, Object value) {
|
||||
public Http2Headers setObject(ByteString name, Object value) {
|
||||
super.setObject(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setObject(AsciiString name, Iterable<?> values) {
|
||||
public Http2Headers setObject(ByteString name, Iterable<?> values) {
|
||||
super.setObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setObject(AsciiString name, Object... values) {
|
||||
public Http2Headers setObject(ByteString name, Object... values) {
|
||||
super.setObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setBoolean(AsciiString name, boolean value) {
|
||||
public Http2Headers setBoolean(ByteString name, boolean value) {
|
||||
super.setBoolean(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setChar(AsciiString name, char value) {
|
||||
public Http2Headers setChar(ByteString name, char value) {
|
||||
super.setChar(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setByte(AsciiString name, byte value) {
|
||||
public Http2Headers setByte(ByteString name, byte value) {
|
||||
super.setByte(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setShort(AsciiString name, short value) {
|
||||
public Http2Headers setShort(ByteString name, short value) {
|
||||
super.setShort(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setInt(AsciiString name, int value) {
|
||||
public Http2Headers setInt(ByteString name, int value) {
|
||||
super.setInt(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setLong(AsciiString name, long value) {
|
||||
public Http2Headers setLong(ByteString name, long value) {
|
||||
super.setLong(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setFloat(AsciiString name, float value) {
|
||||
public Http2Headers setFloat(ByteString name, float value) {
|
||||
super.setFloat(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setDouble(AsciiString name, double value) {
|
||||
public Http2Headers setDouble(ByteString name, double value) {
|
||||
super.setDouble(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setTimeMillis(AsciiString name, long value) {
|
||||
public Http2Headers setTimeMillis(ByteString name, long value) {
|
||||
super.setTimeMillis(name, value);
|
||||
return this;
|
||||
}
|
||||
@ -249,57 +301,57 @@ public class DefaultHttp2Headers extends DefaultBinaryHeaders implements Http2He
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers method(AsciiString value) {
|
||||
public Http2Headers method(ByteString value) {
|
||||
set(PseudoHeaderName.METHOD.value(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers scheme(AsciiString value) {
|
||||
public Http2Headers scheme(ByteString value) {
|
||||
set(PseudoHeaderName.SCHEME.value(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers authority(AsciiString value) {
|
||||
public Http2Headers authority(ByteString value) {
|
||||
set(PseudoHeaderName.AUTHORITY.value(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers path(AsciiString value) {
|
||||
public Http2Headers path(ByteString value) {
|
||||
set(PseudoHeaderName.PATH.value(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers status(AsciiString value) {
|
||||
public Http2Headers status(ByteString value) {
|
||||
set(PseudoHeaderName.STATUS.value(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString method() {
|
||||
public ByteString method() {
|
||||
return get(PseudoHeaderName.METHOD.value());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString scheme() {
|
||||
public ByteString scheme() {
|
||||
return get(PseudoHeaderName.SCHEME.value());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString authority() {
|
||||
public ByteString authority() {
|
||||
return get(PseudoHeaderName.AUTHORITY.value());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString path() {
|
||||
public ByteString path() {
|
||||
return get(PseudoHeaderName.PATH.value());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString status() {
|
||||
public ByteString status() {
|
||||
return get(PseudoHeaderName.STATUS.value());
|
||||
}
|
||||
}
|
||||
|
@ -17,13 +17,13 @@ package io.netty.handler.codec.http2;
|
||||
|
||||
import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_HEADER_TABLE_SIZE;
|
||||
import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_MAX_HEADER_SIZE;
|
||||
import static io.netty.handler.codec.http2.Http2Error.COMPRESSION_ERROR;
|
||||
import static io.netty.handler.codec.http2.Http2Error.INTERNAL_ERROR;
|
||||
import static io.netty.handler.codec.http2.Http2Error.PROTOCOL_ERROR;
|
||||
import static io.netty.handler.codec.http2.Http2Error.COMPRESSION_ERROR;
|
||||
import static io.netty.handler.codec.http2.Http2Exception.connectionError;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufInputStream;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.util.ByteString;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@ -62,7 +62,7 @@ public class DefaultHttp2HeadersDecoder implements Http2HeadersDecoder, Http2Hea
|
||||
HeaderListener listener = new HeaderListener() {
|
||||
@Override
|
||||
public void addHeader(byte[] key, byte[] value, boolean sensitive) {
|
||||
headers.add(new AsciiString(key, false), new AsciiString(value, false));
|
||||
headers.add(new ByteString(key, false), new ByteString(value, false));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -23,8 +23,8 @@ import static io.netty.handler.codec.http2.Http2Exception.connectionError;
|
||||
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufOutputStream;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.BinaryHeaders.EntryVisitor;
|
||||
import io.netty.util.ByteString;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@ -67,8 +67,8 @@ public class DefaultHttp2HeadersEncoder implements Http2HeadersEncoder, Http2Hea
|
||||
|
||||
// Write pseudo headers first as required by the HTTP/2 spec.
|
||||
for (Http2Headers.PseudoHeaderName pseudoHeader : Http2Headers.PseudoHeaderName.values()) {
|
||||
AsciiString name = pseudoHeader.value();
|
||||
AsciiString value = headers.get(name);
|
||||
ByteString name = pseudoHeader.value();
|
||||
ByteString value = headers.get(name);
|
||||
if (value != null) {
|
||||
encodeHeader(name, value, stream);
|
||||
}
|
||||
@ -76,9 +76,9 @@ public class DefaultHttp2HeadersEncoder implements Http2HeadersEncoder, Http2Hea
|
||||
|
||||
headers.forEachEntry(new EntryVisitor() {
|
||||
@Override
|
||||
public boolean visit(Entry<AsciiString, AsciiString> entry) throws Exception {
|
||||
final AsciiString name = entry.getKey();
|
||||
final AsciiString value = entry.getValue();
|
||||
public boolean visit(Entry<ByteString, ByteString> entry) throws Exception {
|
||||
final ByteString name = entry.getKey();
|
||||
final ByteString value = entry.getValue();
|
||||
if (!Http2Headers.PseudoHeaderName.isPseudoHeader(name)) {
|
||||
encodeHeader(name, value, stream);
|
||||
}
|
||||
@ -108,7 +108,7 @@ public class DefaultHttp2HeadersEncoder implements Http2HeadersEncoder, Http2Hea
|
||||
return this;
|
||||
}
|
||||
|
||||
private void encodeHeader(AsciiString key, AsciiString value, OutputStream stream) throws IOException {
|
||||
private void encodeHeader(ByteString key, ByteString value, OutputStream stream) throws IOException {
|
||||
encoder.encodeHeader(stream, key.array(), value.array(), sensitivityDetector.isSensitive(key, value));
|
||||
}
|
||||
|
||||
|
@ -28,10 +28,10 @@ import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.handler.codec.compression.ZlibCodecFactory;
|
||||
import io.netty.handler.codec.compression.ZlibWrapper;
|
||||
import io.netty.util.ByteString;
|
||||
|
||||
/**
|
||||
* A HTTP2 frame listener that will decompress data frames according to the {@code content-encoding} header for each
|
||||
@ -159,13 +159,11 @@ public class DelegatingDecompressorFrameListener extends Http2FrameListenerDecor
|
||||
* (alternatively, you can throw a {@link Http2Exception} to block unknown encoding).
|
||||
* @throws Http2Exception If the specified encoding is not not supported and warrants an exception
|
||||
*/
|
||||
protected EmbeddedChannel newContentDecompressor(AsciiString contentEncoding) throws Http2Exception {
|
||||
if (GZIP.equalsIgnoreCase(contentEncoding) ||
|
||||
X_GZIP.equalsIgnoreCase(contentEncoding)) {
|
||||
protected EmbeddedChannel newContentDecompressor(ByteString contentEncoding) throws Http2Exception {
|
||||
if (GZIP.equals(contentEncoding) || X_GZIP.equals(contentEncoding)) {
|
||||
return new EmbeddedChannel(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP));
|
||||
}
|
||||
if (DEFLATE.equalsIgnoreCase(contentEncoding) ||
|
||||
X_DEFLATE.equalsIgnoreCase(contentEncoding)) {
|
||||
if (DEFLATE.equals(contentEncoding) || X_DEFLATE.equals(contentEncoding)) {
|
||||
final ZlibWrapper wrapper = strict ? ZlibWrapper.ZLIB : ZlibWrapper.ZLIB_OR_NONE;
|
||||
// To be strict, 'deflate' means ZLIB, but some servers were not implemented correctly.
|
||||
return new EmbeddedChannel(ZlibCodecFactory.newZlibDecoder(wrapper));
|
||||
@ -182,7 +180,7 @@ public class DelegatingDecompressorFrameListener extends Http2FrameListenerDecor
|
||||
* @return the expected content encoding of the new content.
|
||||
* @throws Http2Exception if the {@code contentEncoding} is not supported and warrants an exception
|
||||
*/
|
||||
protected AsciiString getTargetContentEncoding(@SuppressWarnings("UnusedParameters") AsciiString contentEncoding)
|
||||
protected ByteString getTargetContentEncoding(@SuppressWarnings("UnusedParameters") ByteString contentEncoding)
|
||||
throws Http2Exception {
|
||||
return IDENTITY;
|
||||
}
|
||||
@ -205,7 +203,7 @@ public class DelegatingDecompressorFrameListener extends Http2FrameListenerDecor
|
||||
Http2Decompressor decompressor = decompressor(stream);
|
||||
if (decompressor == null && !endOfStream) {
|
||||
// Determine the content encoding.
|
||||
AsciiString contentEncoding = headers.get(CONTENT_ENCODING);
|
||||
ByteString contentEncoding = headers.get(CONTENT_ENCODING);
|
||||
if (contentEncoding == null) {
|
||||
contentEncoding = IDENTITY;
|
||||
}
|
||||
@ -215,8 +213,8 @@ public class DelegatingDecompressorFrameListener extends Http2FrameListenerDecor
|
||||
stream.setProperty(Http2Decompressor.class, decompressor);
|
||||
// Decode the content and remove or replace the existing headers
|
||||
// so that the message looks like a decoded message.
|
||||
AsciiString targetContentEncoding = getTargetContentEncoding(contentEncoding);
|
||||
if (IDENTITY.equalsIgnoreCase(targetContentEncoding)) {
|
||||
ByteString targetContentEncoding = getTargetContentEncoding(contentEncoding);
|
||||
if (IDENTITY.equals(targetContentEncoding)) {
|
||||
headers.remove(CONTENT_ENCODING);
|
||||
} else {
|
||||
headers.set(CONTENT_ENCODING, targetContentEncoding);
|
||||
|
@ -15,9 +15,9 @@
|
||||
|
||||
package io.netty.handler.codec.http2;
|
||||
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.BinaryHeaders;
|
||||
import io.netty.handler.codec.EmptyBinaryHeaders;
|
||||
import io.netty.util.ByteString;
|
||||
|
||||
public final class EmptyHttp2Headers extends EmptyBinaryHeaders implements Http2Headers {
|
||||
public static final EmptyHttp2Headers INSTANCE = new EmptyHttp2Headers();
|
||||
@ -26,91 +26,91 @@ public final class EmptyHttp2Headers extends EmptyBinaryHeaders implements Http2
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers add(AsciiString name, AsciiString value) {
|
||||
public Http2Headers add(ByteString name, ByteString value) {
|
||||
super.add(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers add(AsciiString name, Iterable<? extends AsciiString> values) {
|
||||
public Http2Headers add(ByteString name, Iterable<? extends ByteString> values) {
|
||||
super.add(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers add(AsciiString name, AsciiString... values) {
|
||||
public Http2Headers add(ByteString name, ByteString... values) {
|
||||
super.add(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addObject(AsciiString name, Object value) {
|
||||
public Http2Headers addObject(ByteString name, Object value) {
|
||||
super.addObject(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addObject(AsciiString name, Iterable<?> values) {
|
||||
public Http2Headers addObject(ByteString name, Iterable<?> values) {
|
||||
super.addObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addObject(AsciiString name, Object... values) {
|
||||
public Http2Headers addObject(ByteString name, Object... values) {
|
||||
super.addObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addBoolean(AsciiString name, boolean value) {
|
||||
public Http2Headers addBoolean(ByteString name, boolean value) {
|
||||
super.addBoolean(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addChar(AsciiString name, char value) {
|
||||
public Http2Headers addChar(ByteString name, char value) {
|
||||
super.addChar(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addByte(AsciiString name, byte value) {
|
||||
public Http2Headers addByte(ByteString name, byte value) {
|
||||
super.addByte(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addShort(AsciiString name, short value) {
|
||||
public Http2Headers addShort(ByteString name, short value) {
|
||||
super.addShort(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addInt(AsciiString name, int value) {
|
||||
public Http2Headers addInt(ByteString name, int value) {
|
||||
super.addInt(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addLong(AsciiString name, long value) {
|
||||
public Http2Headers addLong(ByteString name, long value) {
|
||||
super.addLong(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addFloat(AsciiString name, float value) {
|
||||
public Http2Headers addFloat(ByteString name, float value) {
|
||||
super.addFloat(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addDouble(AsciiString name, double value) {
|
||||
public Http2Headers addDouble(ByteString name, double value) {
|
||||
super.addDouble(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers addTimeMillis(AsciiString name, long value) {
|
||||
public Http2Headers addTimeMillis(ByteString name, long value) {
|
||||
super.addTimeMillis(name, value);
|
||||
return this;
|
||||
}
|
||||
@ -122,91 +122,91 @@ public final class EmptyHttp2Headers extends EmptyBinaryHeaders implements Http2
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers set(AsciiString name, AsciiString value) {
|
||||
public Http2Headers set(ByteString name, ByteString value) {
|
||||
super.set(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers set(AsciiString name, Iterable<? extends AsciiString> values) {
|
||||
public Http2Headers set(ByteString name, Iterable<? extends ByteString> values) {
|
||||
super.set(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers set(AsciiString name, AsciiString... values) {
|
||||
public Http2Headers set(ByteString name, ByteString... values) {
|
||||
super.set(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setObject(AsciiString name, Object value) {
|
||||
public Http2Headers setObject(ByteString name, Object value) {
|
||||
super.setObject(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setObject(AsciiString name, Iterable<?> values) {
|
||||
public Http2Headers setObject(ByteString name, Iterable<?> values) {
|
||||
super.setObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setObject(AsciiString name, Object... values) {
|
||||
public Http2Headers setObject(ByteString name, Object... values) {
|
||||
super.setObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setBoolean(AsciiString name, boolean value) {
|
||||
public Http2Headers setBoolean(ByteString name, boolean value) {
|
||||
super.setBoolean(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setChar(AsciiString name, char value) {
|
||||
public Http2Headers setChar(ByteString name, char value) {
|
||||
super.setChar(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setByte(AsciiString name, byte value) {
|
||||
public Http2Headers setByte(ByteString name, byte value) {
|
||||
super.setByte(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setShort(AsciiString name, short value) {
|
||||
public Http2Headers setShort(ByteString name, short value) {
|
||||
super.setShort(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setInt(AsciiString name, int value) {
|
||||
public Http2Headers setInt(ByteString name, int value) {
|
||||
super.setInt(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setLong(AsciiString name, long value) {
|
||||
public Http2Headers setLong(ByteString name, long value) {
|
||||
super.setLong(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setFloat(AsciiString name, float value) {
|
||||
public Http2Headers setFloat(ByteString name, float value) {
|
||||
super.setFloat(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setDouble(AsciiString name, double value) {
|
||||
public Http2Headers setDouble(ByteString name, double value) {
|
||||
super.setDouble(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2Headers setTimeMillis(AsciiString name, long value) {
|
||||
public Http2Headers setTimeMillis(ByteString name, long value) {
|
||||
super.setTimeMillis(name, value);
|
||||
return this;
|
||||
}
|
||||
@ -230,52 +230,52 @@ public final class EmptyHttp2Headers extends EmptyBinaryHeaders implements Http2
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmptyHttp2Headers method(AsciiString method) {
|
||||
public EmptyHttp2Headers method(ByteString method) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmptyHttp2Headers scheme(AsciiString status) {
|
||||
public EmptyHttp2Headers scheme(ByteString status) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmptyHttp2Headers authority(AsciiString authority) {
|
||||
public EmptyHttp2Headers authority(ByteString authority) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmptyHttp2Headers path(AsciiString path) {
|
||||
public EmptyHttp2Headers path(ByteString path) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmptyHttp2Headers status(AsciiString status) {
|
||||
public EmptyHttp2Headers status(ByteString status) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString method() {
|
||||
public ByteString method() {
|
||||
return get(PseudoHeaderName.METHOD.value());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString scheme() {
|
||||
public ByteString scheme() {
|
||||
return get(PseudoHeaderName.SCHEME.value());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString authority() {
|
||||
public ByteString authority() {
|
||||
return get(PseudoHeaderName.AUTHORITY.value());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString path() {
|
||||
public ByteString path() {
|
||||
return get(PseudoHeaderName.PATH.value());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString status() {
|
||||
public ByteString status() {
|
||||
return get(PseudoHeaderName.STATUS.value());
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,9 @@
|
||||
|
||||
package io.netty.handler.codec.http2;
|
||||
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.BinaryHeaders;
|
||||
import io.netty.util.ByteString;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
@ -55,8 +56,8 @@ public interface Http2Headers extends BinaryHeaders {
|
||||
*/
|
||||
STATUS(":status");
|
||||
|
||||
private final AsciiString value;
|
||||
private static final Set<AsciiString> PSEUDO_HEADERS = new HashSet<AsciiString>();
|
||||
private final ByteString value;
|
||||
private static final Set<ByteString> PSEUDO_HEADERS = new HashSet<ByteString>();
|
||||
static {
|
||||
for (PseudoHeaderName pseudoHeader : PseudoHeaderName.values()) {
|
||||
PSEUDO_HEADERS.add(pseudoHeader.value());
|
||||
@ -64,10 +65,10 @@ public interface Http2Headers extends BinaryHeaders {
|
||||
}
|
||||
|
||||
PseudoHeaderName(String value) {
|
||||
this.value = new AsciiString(value);
|
||||
this.value = new ByteString(value, CharsetUtil.UTF_8);
|
||||
}
|
||||
|
||||
public AsciiString value() {
|
||||
public ByteString value() {
|
||||
// Return a slice so that the buffer gets its own reader index.
|
||||
return value;
|
||||
}
|
||||
@ -75,103 +76,103 @@ public interface Http2Headers extends BinaryHeaders {
|
||||
/**
|
||||
* Indicates whether the given header name is a valid HTTP/2 pseudo header.
|
||||
*/
|
||||
public static boolean isPseudoHeader(AsciiString header) {
|
||||
public static boolean isPseudoHeader(ByteString header) {
|
||||
return PSEUDO_HEADERS.contains(header);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Http2Headers add(AsciiString name, AsciiString value);
|
||||
Http2Headers add(ByteString name, ByteString value);
|
||||
|
||||
@Override
|
||||
Http2Headers add(AsciiString name, Iterable<? extends AsciiString> values);
|
||||
Http2Headers add(ByteString name, Iterable<? extends ByteString> values);
|
||||
|
||||
@Override
|
||||
Http2Headers add(AsciiString name, AsciiString... values);
|
||||
Http2Headers add(ByteString name, ByteString... values);
|
||||
|
||||
@Override
|
||||
Http2Headers addObject(AsciiString name, Object value);
|
||||
Http2Headers addObject(ByteString name, Object value);
|
||||
|
||||
@Override
|
||||
Http2Headers addObject(AsciiString name, Iterable<?> values);
|
||||
Http2Headers addObject(ByteString name, Iterable<?> values);
|
||||
|
||||
@Override
|
||||
Http2Headers addObject(AsciiString name, Object... values);
|
||||
Http2Headers addObject(ByteString name, Object... values);
|
||||
|
||||
@Override
|
||||
Http2Headers addBoolean(AsciiString name, boolean value);
|
||||
Http2Headers addBoolean(ByteString name, boolean value);
|
||||
|
||||
@Override
|
||||
Http2Headers addByte(AsciiString name, byte value);
|
||||
Http2Headers addByte(ByteString name, byte value);
|
||||
|
||||
@Override
|
||||
Http2Headers addChar(AsciiString name, char value);
|
||||
Http2Headers addChar(ByteString name, char value);
|
||||
|
||||
@Override
|
||||
Http2Headers addShort(AsciiString name, short value);
|
||||
Http2Headers addShort(ByteString name, short value);
|
||||
|
||||
@Override
|
||||
Http2Headers addInt(AsciiString name, int value);
|
||||
Http2Headers addInt(ByteString name, int value);
|
||||
|
||||
@Override
|
||||
Http2Headers addLong(AsciiString name, long value);
|
||||
Http2Headers addLong(ByteString name, long value);
|
||||
|
||||
@Override
|
||||
Http2Headers addFloat(AsciiString name, float value);
|
||||
Http2Headers addFloat(ByteString name, float value);
|
||||
|
||||
@Override
|
||||
Http2Headers addDouble(AsciiString name, double value);
|
||||
Http2Headers addDouble(ByteString name, double value);
|
||||
|
||||
@Override
|
||||
Http2Headers addTimeMillis(AsciiString name, long value);
|
||||
Http2Headers addTimeMillis(ByteString name, long value);
|
||||
|
||||
@Override
|
||||
Http2Headers add(BinaryHeaders headers);
|
||||
|
||||
@Override
|
||||
Http2Headers set(AsciiString name, AsciiString value);
|
||||
Http2Headers set(ByteString name, ByteString value);
|
||||
|
||||
@Override
|
||||
Http2Headers set(AsciiString name, Iterable<? extends AsciiString> values);
|
||||
Http2Headers set(ByteString name, Iterable<? extends ByteString> values);
|
||||
|
||||
@Override
|
||||
Http2Headers set(AsciiString name, AsciiString... values);
|
||||
Http2Headers set(ByteString name, ByteString... values);
|
||||
|
||||
@Override
|
||||
Http2Headers setObject(AsciiString name, Object value);
|
||||
Http2Headers setObject(ByteString name, Object value);
|
||||
|
||||
@Override
|
||||
Http2Headers setObject(AsciiString name, Iterable<?> values);
|
||||
Http2Headers setObject(ByteString name, Iterable<?> values);
|
||||
|
||||
@Override
|
||||
Http2Headers setObject(AsciiString name, Object... values);
|
||||
Http2Headers setObject(ByteString name, Object... values);
|
||||
|
||||
@Override
|
||||
Http2Headers setBoolean(AsciiString name, boolean value);
|
||||
Http2Headers setBoolean(ByteString name, boolean value);
|
||||
|
||||
@Override
|
||||
Http2Headers setByte(AsciiString name, byte value);
|
||||
Http2Headers setByte(ByteString name, byte value);
|
||||
|
||||
@Override
|
||||
Http2Headers setChar(AsciiString name, char value);
|
||||
Http2Headers setChar(ByteString name, char value);
|
||||
|
||||
@Override
|
||||
Http2Headers setShort(AsciiString name, short value);
|
||||
Http2Headers setShort(ByteString name, short value);
|
||||
|
||||
@Override
|
||||
Http2Headers setInt(AsciiString name, int value);
|
||||
Http2Headers setInt(ByteString name, int value);
|
||||
|
||||
@Override
|
||||
Http2Headers setLong(AsciiString name, long value);
|
||||
Http2Headers setLong(ByteString name, long value);
|
||||
|
||||
@Override
|
||||
Http2Headers setFloat(AsciiString name, float value);
|
||||
Http2Headers setFloat(ByteString name, float value);
|
||||
|
||||
@Override
|
||||
Http2Headers setDouble(AsciiString name, double value);
|
||||
Http2Headers setDouble(ByteString name, double value);
|
||||
|
||||
@Override
|
||||
Http2Headers setTimeMillis(AsciiString name, long value);
|
||||
Http2Headers setTimeMillis(ByteString name, long value);
|
||||
|
||||
@Override
|
||||
Http2Headers set(BinaryHeaders headers);
|
||||
@ -185,50 +186,50 @@ public interface Http2Headers extends BinaryHeaders {
|
||||
/**
|
||||
* Sets the {@link PseudoHeaderName#METHOD} header or {@code null} if there is no such header
|
||||
*/
|
||||
Http2Headers method(AsciiString value);
|
||||
Http2Headers method(ByteString value);
|
||||
|
||||
/**
|
||||
* Sets the {@link PseudoHeaderName#SCHEME} header if there is no such header
|
||||
*/
|
||||
Http2Headers scheme(AsciiString value);
|
||||
Http2Headers scheme(ByteString value);
|
||||
|
||||
/**
|
||||
* Sets the {@link PseudoHeaderName#AUTHORITY} header or {@code null} if there is no such header
|
||||
*/
|
||||
Http2Headers authority(AsciiString value);
|
||||
Http2Headers authority(ByteString value);
|
||||
|
||||
/**
|
||||
* Sets the {@link PseudoHeaderName#PATH} header or {@code null} if there is no such header
|
||||
*/
|
||||
Http2Headers path(AsciiString value);
|
||||
Http2Headers path(ByteString value);
|
||||
|
||||
/**
|
||||
* Sets the {@link PseudoHeaderName#STATUS} header or {@code null} if there is no such header
|
||||
*/
|
||||
Http2Headers status(AsciiString value);
|
||||
Http2Headers status(ByteString value);
|
||||
|
||||
/**
|
||||
* Gets the {@link PseudoHeaderName#METHOD} header or {@code null} if there is no such header
|
||||
*/
|
||||
AsciiString method();
|
||||
ByteString method();
|
||||
|
||||
/**
|
||||
* Gets the {@link PseudoHeaderName#SCHEME} header or {@code null} if there is no such header
|
||||
*/
|
||||
AsciiString scheme();
|
||||
ByteString scheme();
|
||||
|
||||
/**
|
||||
* Gets the {@link PseudoHeaderName#AUTHORITY} header or {@code null} if there is no such header
|
||||
*/
|
||||
AsciiString authority();
|
||||
ByteString authority();
|
||||
|
||||
/**
|
||||
* Gets the {@link PseudoHeaderName#PATH} header or {@code null} if there is no such header
|
||||
*/
|
||||
AsciiString path();
|
||||
ByteString path();
|
||||
|
||||
/**
|
||||
* Gets the {@link PseudoHeaderName#STATUS} header or {@code null} if there is no such header
|
||||
*/
|
||||
AsciiString status();
|
||||
ByteString status();
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
package io.netty.handler.codec.http2;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.util.ByteString;
|
||||
|
||||
/**
|
||||
* Encodes {@link Http2Headers} into HPACK-encoded headers blocks.
|
||||
@ -47,7 +47,7 @@ public interface Http2HeadersEncoder {
|
||||
* <a href="http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#section-7.1.3">sensitive</a>.
|
||||
* {@code false} otherwise.
|
||||
*/
|
||||
boolean isSensitive(AsciiString name, AsciiString value);
|
||||
boolean isSensitive(ByteString name, ByteString value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -64,11 +64,11 @@ public interface Http2HeadersEncoder {
|
||||
Configuration configuration();
|
||||
|
||||
/**
|
||||
* Always return {@code false} for {@link SensitivityDetector#isSensitive(AsciiString, AsciiString)}.
|
||||
* Always return {@code false} for {@link SensitivityDetector#isSensitive(ByteString, ByteString)}.
|
||||
*/
|
||||
SensitivityDetector NEVER_SENSITIVE = new SensitivityDetector() {
|
||||
@Override
|
||||
public boolean isSensitive(AsciiString name, AsciiString value) {
|
||||
public boolean isSensitive(ByteString name, ByteString value) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
@ -23,15 +23,17 @@ import static io.netty.handler.codec.http2.Http2CodecUtil.writeFrameHeader;
|
||||
import static io.netty.handler.codec.http2.Http2FrameTypes.SETTINGS;
|
||||
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.base64.Base64;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpServerUpgradeHandler;
|
||||
import io.netty.util.ByteString;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import java.nio.CharBuffer;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@ -104,8 +106,7 @@ public class Http2ServerUpgradeCodec implements HttpServerUpgradeHandler.Upgrade
|
||||
@Override
|
||||
public void upgradeTo(final ChannelHandlerContext ctx, FullHttpRequest upgradeRequest,
|
||||
FullHttpResponse upgradeResponse) {
|
||||
// Add the HTTP/2 connection handler to the pipeline immediately following the current
|
||||
// handler.
|
||||
// Add the HTTP/2 connection handler to the pipeline immediately following the current handler.
|
||||
ctx.pipeline().addAfter(ctx.name(), handlerName, connectionHandler);
|
||||
}
|
||||
|
||||
@ -114,7 +115,7 @@ public class Http2ServerUpgradeCodec implements HttpServerUpgradeHandler.Upgrade
|
||||
*/
|
||||
private Http2Settings decodeSettingsHeader(ChannelHandlerContext ctx, CharSequence settingsHeader)
|
||||
throws Http2Exception {
|
||||
ByteBuf header = Unpooled.wrappedBuffer(AsciiString.getBytes(settingsHeader, CharsetUtil.UTF_8));
|
||||
ByteBuf header = ByteBufUtil.encodeString(ctx.alloc(), CharBuffer.wrap(settingsHeader), CharsetUtil.UTF_8);
|
||||
try {
|
||||
// Decode the SETTINGS payload.
|
||||
ByteBuf payload = Base64.decode(header, URL_SAFE);
|
||||
|
@ -18,7 +18,6 @@ import static io.netty.handler.codec.http2.Http2Error.PROTOCOL_ERROR;
|
||||
import static io.netty.handler.codec.http2.Http2Exception.connectionError;
|
||||
import static io.netty.handler.codec.http2.Http2Exception.streamError;
|
||||
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.BinaryHeaders;
|
||||
import io.netty.handler.codec.TextHeaders.EntryVisitor;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
||||
@ -35,6 +34,8 @@ import io.netty.handler.codec.http.HttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponse;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import io.netty.util.AsciiString;
|
||||
import io.netty.util.ByteString;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
@ -168,7 +169,7 @@ public final class HttpUtil {
|
||||
* @return The HTTP/1.x status
|
||||
* @throws Http2Exception If there is a problem translating from HTTP/2 to HTTP/1.x
|
||||
*/
|
||||
public static HttpResponseStatus parseStatus(AsciiString status) throws Http2Exception {
|
||||
public static HttpResponseStatus parseStatus(ByteString status) throws Http2Exception {
|
||||
HttpResponseStatus result;
|
||||
try {
|
||||
result = HttpResponseStatus.parseLine(status);
|
||||
@ -220,11 +221,10 @@ public final class HttpUtil {
|
||||
*/
|
||||
public static FullHttpRequest toHttpRequest(int streamId, Http2Headers http2Headers, boolean validateHttpHeaders)
|
||||
throws Http2Exception {
|
||||
// HTTP/2 does not define a way to carry the version identifier that is
|
||||
// included in the HTTP/1.1 request line.
|
||||
final AsciiString method = checkNotNull(http2Headers.method(),
|
||||
// HTTP/2 does not define a way to carry the version identifier that is included in the HTTP/1.1 request line.
|
||||
final ByteString method = checkNotNull(http2Headers.method(),
|
||||
"method header cannot be null in conversion to HTTP/1.x");
|
||||
final AsciiString path = checkNotNull(http2Headers.path(),
|
||||
final ByteString path = checkNotNull(http2Headers.path(),
|
||||
"path header cannot be null in conversion to HTTP/1.x");
|
||||
FullHttpRequest msg = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.valueOf(method
|
||||
.toString()), path.toString(), validateHttpHeaders);
|
||||
@ -330,10 +330,10 @@ public final class HttpUtil {
|
||||
/**
|
||||
* Translations from HTTP/2 header name to the HTTP/1.x equivalent.
|
||||
*/
|
||||
private static final Map<AsciiString, AsciiString>
|
||||
REQUEST_HEADER_TRANSLATIONS = new HashMap<AsciiString, AsciiString>();
|
||||
private static final Map<AsciiString, AsciiString>
|
||||
RESPONSE_HEADER_TRANSLATIONS = new HashMap<AsciiString, AsciiString>();
|
||||
private static final Map<ByteString, ByteString>
|
||||
REQUEST_HEADER_TRANSLATIONS = new HashMap<ByteString, ByteString>();
|
||||
private static final Map<ByteString, ByteString>
|
||||
RESPONSE_HEADER_TRANSLATIONS = new HashMap<ByteString, ByteString>();
|
||||
static {
|
||||
RESPONSE_HEADER_TRANSLATIONS.put(Http2Headers.PseudoHeaderName.AUTHORITY.value(),
|
||||
ExtensionHeaderNames.AUTHORITY.text());
|
||||
@ -346,7 +346,7 @@ public final class HttpUtil {
|
||||
|
||||
private final int streamId;
|
||||
private final HttpHeaders output;
|
||||
private final Map<AsciiString, AsciiString> translations;
|
||||
private final Map<ByteString, ByteString> translations;
|
||||
|
||||
/**
|
||||
* Create a new instance
|
||||
@ -362,10 +362,10 @@ public final class HttpUtil {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(Entry<AsciiString, AsciiString> entry) throws Http2Exception {
|
||||
final AsciiString name = entry.getKey();
|
||||
final AsciiString value = entry.getValue();
|
||||
AsciiString translatedName = translations.get(name);
|
||||
public boolean visit(Entry<ByteString, ByteString> entry) throws Http2Exception {
|
||||
final ByteString name = entry.getKey();
|
||||
final ByteString value = entry.getValue();
|
||||
ByteString translatedName = translations.get(name);
|
||||
if (translatedName != null || !Http2Headers.PseudoHeaderName.isPseudoHeader(name)) {
|
||||
if (translatedName == null) {
|
||||
translatedName = name;
|
||||
@ -373,11 +373,11 @@ public final class HttpUtil {
|
||||
|
||||
// http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-8.1.2.3
|
||||
// All headers that start with ':' are only valid in HTTP/2 context
|
||||
if (translatedName.isEmpty() || translatedName.charAt(0) == ':') {
|
||||
if (translatedName.isEmpty() || translatedName.byteAt(0) == ':') {
|
||||
throw streamError(streamId, PROTOCOL_ERROR,
|
||||
"Invalid HTTP/2 header '%s' encountered in translation to HTTP/1.x", translatedName);
|
||||
} else {
|
||||
output.add(translatedName, value);
|
||||
output.add(new AsciiString(translatedName.array(), false), new AsciiString(value.array(), false));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -16,14 +16,15 @@ package io.netty.handler.codec.http2;
|
||||
|
||||
import static io.netty.handler.codec.http2.Http2Error.PROTOCOL_ERROR;
|
||||
import static io.netty.handler.codec.http2.Http2Exception.connectionError;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.TextHeaders.EntryVisitor;
|
||||
import io.netty.handler.codec.http.DefaultHttpHeaders;
|
||||
import io.netty.handler.codec.http.FullHttpMessage;
|
||||
import io.netty.handler.codec.http.HttpHeaders;
|
||||
import io.netty.util.AsciiString;
|
||||
import io.netty.util.collection.IntObjectHashMap;
|
||||
import io.netty.util.collection.IntObjectMap;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
|
@ -40,12 +40,12 @@ import io.netty.channel.ChannelPromise;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpHeaderValues;
|
||||
import io.netty.handler.codec.http2.Http2TestUtil.FrameAdapter;
|
||||
import io.netty.handler.codec.http2.Http2TestUtil.FrameCountDown;
|
||||
import io.netty.handler.codec.http2.Http2TestUtil.Http2Runnable;
|
||||
import io.netty.util.AsciiString;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.NetUtil;
|
||||
import io.netty.util.concurrent.Future;
|
||||
|
@ -15,30 +15,41 @@
|
||||
*/
|
||||
package io.netty.handler.codec.http2;
|
||||
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import io.netty.util.AsciiString;
|
||||
import io.netty.util.ByteString;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class DefaultHttp2HeadersTest {
|
||||
|
||||
private static final AsciiString NAME = new AsciiString("Test");
|
||||
private static final AsciiString VALUE = new AsciiString("some value");
|
||||
private static final byte[] NAME_BYTES = { 'T', 'E', 's', 'T' };
|
||||
private static final byte[] NAME_BYTES_LOWERCASE = { 't', 'e', 's', 't' };
|
||||
private static final ByteString NAME_BYTESTRING = new ByteString(NAME_BYTES);
|
||||
private static final AsciiString NAME_ASCIISTRING = new AsciiString("Test");
|
||||
private static final ByteString VALUE = new ByteString("some value", CharsetUtil.UTF_8);
|
||||
|
||||
@Test
|
||||
public void defaultLowercase() {
|
||||
Http2Headers headers = new DefaultHttp2Headers().set(NAME, VALUE);
|
||||
assertEquals(first(headers), NAME.toLowerCase());
|
||||
Http2Headers headers = new DefaultHttp2Headers().set(NAME_BYTESTRING, VALUE);
|
||||
assertArrayEquals(NAME_BYTES_LOWERCASE, first(headers).toByteArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultLowercaseAsciiString() {
|
||||
Http2Headers headers = new DefaultHttp2Headers().set(NAME_ASCIISTRING, VALUE);
|
||||
assertEquals(NAME_ASCIISTRING.toLowerCase(), first(headers));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void caseInsensitive() {
|
||||
Http2Headers headers = new DefaultHttp2Headers(false).set(NAME, VALUE);
|
||||
assertEquals(first(headers), NAME);
|
||||
Http2Headers headers = new DefaultHttp2Headers(false).set(NAME_BYTESTRING, VALUE);
|
||||
assertArrayEquals(NAME_BYTES, first(headers).toByteArray());
|
||||
}
|
||||
|
||||
private static AsciiString first(Http2Headers headers) {
|
||||
private static ByteString first(Http2Headers headers) {
|
||||
return headers.names().iterator().next();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,8 +17,9 @@ package io.netty.handler.codec.http2;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.util.AsciiString;
|
||||
import io.netty.util.ByteString;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
@ -61,8 +62,8 @@ final class Http2TestUtil {
|
||||
/**
|
||||
* Converts a byte array into an {@link AsciiString}.
|
||||
*/
|
||||
public static AsciiString as(byte[] value) {
|
||||
return new AsciiString(value);
|
||||
public static ByteString as(byte[] value) {
|
||||
return new ByteString(value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -77,7 +78,7 @@ final class Http2TestUtil {
|
||||
/**
|
||||
* Returns an {@link AsciiString} that wraps a randomly-filled byte array.
|
||||
*/
|
||||
public static AsciiString randomString() {
|
||||
public static ByteString randomString() {
|
||||
return as(randomBytes());
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,6 @@ import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpMessage;
|
||||
@ -54,6 +53,7 @@ import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import io.netty.handler.codec.http2.Http2TestUtil.FrameAdapter;
|
||||
import io.netty.handler.codec.http2.Http2TestUtil.Http2Runnable;
|
||||
import io.netty.util.AsciiString;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.NetUtil;
|
||||
import io.netty.util.concurrent.Future;
|
||||
|
@ -15,8 +15,8 @@
|
||||
*/
|
||||
package io.netty.handler.codec.stomp;
|
||||
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.TextHeaders;
|
||||
import io.netty.util.AsciiString;
|
||||
|
||||
/**
|
||||
* The multimap data structure for the STOMP header names and values. It also provides the constants for the standard
|
||||
|
@ -20,7 +20,9 @@ package io.netty.handler.codec;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.handler.codec.TextHeaders.EntryVisitor;
|
||||
import io.netty.util.AsciiString;
|
||||
|
||||
public final class AsciiHeadersEncoder implements EntryVisitor {
|
||||
|
||||
@ -129,7 +131,7 @@ public final class AsciiHeadersEncoder implements EntryVisitor {
|
||||
}
|
||||
|
||||
private static void writeAsciiString(ByteBuf buf, int offset, AsciiString value, int valueLen) {
|
||||
value.copy(0, buf, offset, valueLen);
|
||||
ByteBufUtil.copy(value, 0, buf, offset, valueLen);
|
||||
}
|
||||
|
||||
private static void writeCharSequence(ByteBuf buf, int offset, CharSequence value, int valueLen) {
|
||||
|
@ -16,68 +16,70 @@
|
||||
|
||||
package io.netty.handler.codec;
|
||||
|
||||
import io.netty.util.ByteString;
|
||||
|
||||
/**
|
||||
* A typical {@code AsciiString} multimap used by protocols that use binary headers (such as HTTP/2) for the
|
||||
* representation of arbitrary key-value data. {@link AsciiString} is just a wrapper around a byte array but provides
|
||||
* A typical {@code ByteString} multimap used by protocols that use binary headers (such as HTTP/2) for the
|
||||
* representation of arbitrary key-value data. {@link ByteString} is just a wrapper around a byte array but provides
|
||||
* some additional utility when handling text data.
|
||||
*/
|
||||
public interface BinaryHeaders extends Headers<AsciiString> {
|
||||
public interface BinaryHeaders extends Headers<ByteString> {
|
||||
/**
|
||||
* A visitor that helps reduce GC pressure while iterating over a collection of {@link Headers}.
|
||||
* Provides an abstraction to iterate over elements maintained in the {@link Headers} collection.
|
||||
*/
|
||||
interface EntryVisitor extends Headers.EntryVisitor<AsciiString> {
|
||||
interface EntryVisitor extends Headers.EntryVisitor<ByteString> {
|
||||
}
|
||||
|
||||
/**
|
||||
* A visitor that helps reduce GC pressure while iterating over a collection of {@link Headers}.
|
||||
* Provides an abstraction to iterate over elements maintained in the {@link Headers} collection.
|
||||
*/
|
||||
interface NameVisitor extends Headers.NameVisitor<AsciiString> {
|
||||
interface NameVisitor extends Headers.NameVisitor<ByteString> {
|
||||
}
|
||||
|
||||
@Override
|
||||
BinaryHeaders add(AsciiString name, AsciiString value);
|
||||
BinaryHeaders add(ByteString name, ByteString value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders add(AsciiString name, Iterable<? extends AsciiString> values);
|
||||
BinaryHeaders add(ByteString name, Iterable<? extends ByteString> values);
|
||||
|
||||
@Override
|
||||
BinaryHeaders add(AsciiString name, AsciiString... values);
|
||||
BinaryHeaders add(ByteString name, ByteString... values);
|
||||
|
||||
@Override
|
||||
BinaryHeaders addObject(AsciiString name, Object value);
|
||||
BinaryHeaders addObject(ByteString name, Object value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders addObject(AsciiString name, Iterable<?> values);
|
||||
BinaryHeaders addObject(ByteString name, Iterable<?> values);
|
||||
|
||||
@Override
|
||||
BinaryHeaders addObject(AsciiString name, Object... values);
|
||||
BinaryHeaders addObject(ByteString name, Object... values);
|
||||
|
||||
@Override
|
||||
BinaryHeaders addBoolean(AsciiString name, boolean value);
|
||||
BinaryHeaders addBoolean(ByteString name, boolean value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders addByte(AsciiString name, byte value);
|
||||
BinaryHeaders addByte(ByteString name, byte value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders addChar(AsciiString name, char value);
|
||||
BinaryHeaders addChar(ByteString name, char value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders addShort(AsciiString name, short value);
|
||||
BinaryHeaders addShort(ByteString name, short value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders addInt(AsciiString name, int value);
|
||||
BinaryHeaders addInt(ByteString name, int value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders addLong(AsciiString name, long value);
|
||||
BinaryHeaders addLong(ByteString name, long value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders addFloat(AsciiString name, float value);
|
||||
BinaryHeaders addFloat(ByteString name, float value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders addDouble(AsciiString name, double value);
|
||||
BinaryHeaders addDouble(ByteString name, double value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders addTimeMillis(AsciiString name, long value);
|
||||
BinaryHeaders addTimeMillis(ByteString name, long value);
|
||||
|
||||
/**
|
||||
* See {@link Headers#add(Headers)}
|
||||
@ -85,49 +87,49 @@ public interface BinaryHeaders extends Headers<AsciiString> {
|
||||
BinaryHeaders add(BinaryHeaders headers);
|
||||
|
||||
@Override
|
||||
BinaryHeaders set(AsciiString name, AsciiString value);
|
||||
BinaryHeaders set(ByteString name, ByteString value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders set(AsciiString name, Iterable<? extends AsciiString> values);
|
||||
BinaryHeaders set(ByteString name, Iterable<? extends ByteString> values);
|
||||
|
||||
@Override
|
||||
BinaryHeaders set(AsciiString name, AsciiString... values);
|
||||
BinaryHeaders set(ByteString name, ByteString... values);
|
||||
|
||||
@Override
|
||||
BinaryHeaders setObject(AsciiString name, Object value);
|
||||
BinaryHeaders setObject(ByteString name, Object value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders setObject(AsciiString name, Iterable<?> values);
|
||||
BinaryHeaders setObject(ByteString name, Iterable<?> values);
|
||||
|
||||
@Override
|
||||
BinaryHeaders setObject(AsciiString name, Object... values);
|
||||
BinaryHeaders setObject(ByteString name, Object... values);
|
||||
|
||||
@Override
|
||||
BinaryHeaders setBoolean(AsciiString name, boolean value);
|
||||
BinaryHeaders setBoolean(ByteString name, boolean value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders setByte(AsciiString name, byte value);
|
||||
BinaryHeaders setByte(ByteString name, byte value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders setChar(AsciiString name, char value);
|
||||
BinaryHeaders setChar(ByteString name, char value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders setShort(AsciiString name, short value);
|
||||
BinaryHeaders setShort(ByteString name, short value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders setInt(AsciiString name, int value);
|
||||
BinaryHeaders setInt(ByteString name, int value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders setLong(AsciiString name, long value);
|
||||
BinaryHeaders setLong(ByteString name, long value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders setFloat(AsciiString name, float value);
|
||||
BinaryHeaders setFloat(ByteString name, float value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders setDouble(AsciiString name, double value);
|
||||
BinaryHeaders setDouble(ByteString name, double value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders setTimeMillis(AsciiString name, long value);
|
||||
BinaryHeaders setTimeMillis(ByteString name, long value);
|
||||
|
||||
/**
|
||||
* See {@link Headers#set(Headers)}
|
||||
|
@ -14,80 +14,74 @@
|
||||
*/
|
||||
package io.netty.handler.codec;
|
||||
|
||||
import io.netty.util.ByteString;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.text.ParseException;
|
||||
|
||||
import static io.netty.handler.codec.AsciiString.*;
|
||||
|
||||
public class DefaultBinaryHeaders extends DefaultHeaders<AsciiString> implements BinaryHeaders {
|
||||
private static final HashCodeGenerator<AsciiString> ASCII_HASH_CODE_GENERATOR =
|
||||
new HashCodeGenerator<AsciiString>() {
|
||||
public class DefaultBinaryHeaders extends DefaultHeaders<ByteString> implements BinaryHeaders {
|
||||
private static final ValueConverter<ByteString> OBJECT_TO_BYTE = new ValueConverter<ByteString>() {
|
||||
private final Charset DEFAULT_CHARSET = CharsetUtil.UTF_8;
|
||||
@Override
|
||||
public int generateHashCode(AsciiString name) {
|
||||
return AsciiString.caseInsensitiveHashCode(name);
|
||||
}
|
||||
};
|
||||
|
||||
private static final ValueConverter<AsciiString> OBJECT_TO_ASCII = new ValueConverter<AsciiString>() {
|
||||
@Override
|
||||
public AsciiString convertObject(Object value) {
|
||||
if (value instanceof AsciiString) {
|
||||
return (AsciiString) value;
|
||||
public ByteString convertObject(Object value) {
|
||||
if (value instanceof ByteString) {
|
||||
return (ByteString) value;
|
||||
}
|
||||
if (value instanceof CharSequence) {
|
||||
return new AsciiString((CharSequence) value);
|
||||
return new ByteString((CharSequence) value, DEFAULT_CHARSET);
|
||||
}
|
||||
return new AsciiString(value.toString());
|
||||
return new ByteString(value.toString(), DEFAULT_CHARSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString convertInt(int value) {
|
||||
return new AsciiString(String.valueOf(value));
|
||||
public ByteString convertInt(int value) {
|
||||
return new ByteString(String.valueOf(value), DEFAULT_CHARSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString convertLong(long value) {
|
||||
return new AsciiString(String.valueOf(value));
|
||||
public ByteString convertLong(long value) {
|
||||
return new ByteString(String.valueOf(value), DEFAULT_CHARSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString convertDouble(double value) {
|
||||
return new AsciiString(String.valueOf(value));
|
||||
public ByteString convertDouble(double value) {
|
||||
return new ByteString(String.valueOf(value), DEFAULT_CHARSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString convertChar(char value) {
|
||||
return new AsciiString(String.valueOf(value));
|
||||
public ByteString convertChar(char value) {
|
||||
return new ByteString(String.valueOf(value), DEFAULT_CHARSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString convertBoolean(boolean value) {
|
||||
return new AsciiString(String.valueOf(value));
|
||||
public ByteString convertBoolean(boolean value) {
|
||||
return new ByteString(String.valueOf(value), DEFAULT_CHARSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString convertFloat(float value) {
|
||||
return new AsciiString(String.valueOf(value));
|
||||
public ByteString convertFloat(float value) {
|
||||
return new ByteString(String.valueOf(value), DEFAULT_CHARSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int convertToInt(AsciiString value) {
|
||||
return value.parseInt();
|
||||
public int convertToInt(ByteString value) {
|
||||
return value.parseAsciiInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long convertToLong(AsciiString value) {
|
||||
return value.parseLong();
|
||||
public long convertToLong(ByteString value) {
|
||||
return value.parseAsciiLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString convertTimeMillis(long value) {
|
||||
return new AsciiString(String.valueOf(value));
|
||||
public ByteString convertTimeMillis(long value) {
|
||||
return new ByteString(String.valueOf(value), DEFAULT_CHARSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long convertToTimeMillis(AsciiString value) {
|
||||
public long convertToTimeMillis(ByteString value) {
|
||||
try {
|
||||
return HeaderDateFormat.get().parse(value.toString());
|
||||
} catch (ParseException e) {
|
||||
@ -97,155 +91,145 @@ public class DefaultBinaryHeaders extends DefaultHeaders<AsciiString> implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public double convertToDouble(AsciiString value) {
|
||||
return value.parseDouble();
|
||||
public double convertToDouble(ByteString value) {
|
||||
return value.parseAsciiDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char convertToChar(AsciiString value) {
|
||||
return value.charAt(0);
|
||||
public char convertToChar(ByteString value) {
|
||||
return value.parseChar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean convertToBoolean(AsciiString value) {
|
||||
public boolean convertToBoolean(ByteString value) {
|
||||
return value.byteAt(0) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float convertToFloat(AsciiString value) {
|
||||
return value.parseFloat();
|
||||
public float convertToFloat(ByteString value) {
|
||||
return value.parseAsciiFloat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString convertShort(short value) {
|
||||
return new AsciiString(String.valueOf(value));
|
||||
public ByteString convertShort(short value) {
|
||||
return new ByteString(String.valueOf(value), DEFAULT_CHARSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short convertToShort(AsciiString value) {
|
||||
return value.parseShort();
|
||||
public short convertToShort(ByteString value) {
|
||||
return value.parseAsciiShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString convertByte(byte value) {
|
||||
return new AsciiString(String.valueOf(value));
|
||||
public ByteString convertByte(byte value) {
|
||||
return new ByteString(String.valueOf(value), DEFAULT_CHARSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte convertToByte(AsciiString value) {
|
||||
public byte convertToByte(ByteString value) {
|
||||
return value.byteAt(0);
|
||||
}
|
||||
};
|
||||
|
||||
private static final NameConverter<AsciiString> ASCII_TO_LOWER_CONVERTER = new NameConverter<AsciiString>() {
|
||||
@Override
|
||||
public AsciiString convertName(AsciiString name) {
|
||||
return name.toLowerCase();
|
||||
}
|
||||
};
|
||||
|
||||
private static final NameConverter<AsciiString> ASCII_IDENTITY_CONVERTER = new NameConverter<AsciiString>() {
|
||||
@Override
|
||||
public AsciiString convertName(AsciiString name) {
|
||||
return name;
|
||||
}
|
||||
};
|
||||
private static final HashCodeGenerator<ByteString> JAVA_HASH_CODE_GENERATOR =
|
||||
new JavaHashCodeGenerator<ByteString>();
|
||||
protected static final NameConverter<ByteString> IDENTITY_NAME_CONVERTER = new IdentityNameConverter<ByteString>();
|
||||
|
||||
public DefaultBinaryHeaders() {
|
||||
this(false);
|
||||
this(IDENTITY_NAME_CONVERTER);
|
||||
}
|
||||
|
||||
public DefaultBinaryHeaders(boolean forceKeyToLower) {
|
||||
super(CASE_INSENSITIVE_ORDER, CASE_INSENSITIVE_ORDER, ASCII_HASH_CODE_GENERATOR, OBJECT_TO_ASCII,
|
||||
forceKeyToLower ? ASCII_TO_LOWER_CONVERTER : ASCII_IDENTITY_CONVERTER);
|
||||
public DefaultBinaryHeaders(NameConverter<ByteString> nameConverter) {
|
||||
super(ByteString.DEFAULT_COMPARATOR, ByteString.DEFAULT_COMPARATOR,
|
||||
JAVA_HASH_CODE_GENERATOR, OBJECT_TO_BYTE, nameConverter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders add(AsciiString name, AsciiString value) {
|
||||
public BinaryHeaders add(ByteString name, ByteString value) {
|
||||
super.add(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders add(AsciiString name, Iterable<? extends AsciiString> values) {
|
||||
public BinaryHeaders add(ByteString name, Iterable<? extends ByteString> values) {
|
||||
super.add(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders add(AsciiString name, AsciiString... values) {
|
||||
public BinaryHeaders add(ByteString name, ByteString... values) {
|
||||
super.add(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addObject(AsciiString name, Object value) {
|
||||
public BinaryHeaders addObject(ByteString name, Object value) {
|
||||
super.addObject(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addObject(AsciiString name, Iterable<?> values) {
|
||||
public BinaryHeaders addObject(ByteString name, Iterable<?> values) {
|
||||
super.addObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addObject(AsciiString name, Object... values) {
|
||||
public BinaryHeaders addObject(ByteString name, Object... values) {
|
||||
super.addObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addBoolean(AsciiString name, boolean value) {
|
||||
public BinaryHeaders addBoolean(ByteString name, boolean value) {
|
||||
super.addBoolean(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addChar(AsciiString name, char value) {
|
||||
public BinaryHeaders addChar(ByteString name, char value) {
|
||||
super.addChar(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addByte(AsciiString name, byte value) {
|
||||
public BinaryHeaders addByte(ByteString name, byte value) {
|
||||
super.addByte(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addShort(AsciiString name, short value) {
|
||||
public BinaryHeaders addShort(ByteString name, short value) {
|
||||
super.addShort(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addInt(AsciiString name, int value) {
|
||||
public BinaryHeaders addInt(ByteString name, int value) {
|
||||
super.addInt(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addLong(AsciiString name, long value) {
|
||||
public BinaryHeaders addLong(ByteString name, long value) {
|
||||
super.addLong(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addFloat(AsciiString name, float value) {
|
||||
public BinaryHeaders addFloat(ByteString name, float value) {
|
||||
super.addFloat(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addDouble(AsciiString name, double value) {
|
||||
public BinaryHeaders addDouble(ByteString name, double value) {
|
||||
super.addDouble(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addTimeMillis(AsciiString name, long value) {
|
||||
public BinaryHeaders addTimeMillis(ByteString name, long value) {
|
||||
super.addTimeMillis(name, value);
|
||||
return this;
|
||||
}
|
||||
@ -257,91 +241,91 @@ public class DefaultBinaryHeaders extends DefaultHeaders<AsciiString> implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders set(AsciiString name, AsciiString value) {
|
||||
public BinaryHeaders set(ByteString name, ByteString value) {
|
||||
super.set(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders set(AsciiString name, Iterable<? extends AsciiString> values) {
|
||||
public BinaryHeaders set(ByteString name, Iterable<? extends ByteString> values) {
|
||||
super.set(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders set(AsciiString name, AsciiString... values) {
|
||||
public BinaryHeaders set(ByteString name, ByteString... values) {
|
||||
super.set(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setObject(AsciiString name, Object value) {
|
||||
public BinaryHeaders setObject(ByteString name, Object value) {
|
||||
super.setObject(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setObject(AsciiString name, Iterable<?> values) {
|
||||
public BinaryHeaders setObject(ByteString name, Iterable<?> values) {
|
||||
super.setObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setObject(AsciiString name, Object... values) {
|
||||
public BinaryHeaders setObject(ByteString name, Object... values) {
|
||||
super.setObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setBoolean(AsciiString name, boolean value) {
|
||||
public BinaryHeaders setBoolean(ByteString name, boolean value) {
|
||||
super.setBoolean(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setChar(AsciiString name, char value) {
|
||||
public BinaryHeaders setChar(ByteString name, char value) {
|
||||
super.setChar(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setByte(AsciiString name, byte value) {
|
||||
public BinaryHeaders setByte(ByteString name, byte value) {
|
||||
super.setByte(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setShort(AsciiString name, short value) {
|
||||
public BinaryHeaders setShort(ByteString name, short value) {
|
||||
super.setShort(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setInt(AsciiString name, int value) {
|
||||
public BinaryHeaders setInt(ByteString name, int value) {
|
||||
super.setInt(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setLong(AsciiString name, long value) {
|
||||
public BinaryHeaders setLong(ByteString name, long value) {
|
||||
super.setLong(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setFloat(AsciiString name, float value) {
|
||||
public BinaryHeaders setFloat(ByteString name, float value) {
|
||||
super.setFloat(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setDouble(AsciiString name, double value) {
|
||||
public BinaryHeaders setDouble(ByteString name, double value) {
|
||||
super.setDouble(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setTimeMillis(AsciiString name, long value) {
|
||||
public BinaryHeaders setTimeMillis(ByteString name, long value) {
|
||||
super.setTimeMillis(name, value);
|
||||
return this;
|
||||
}
|
||||
|
@ -66,6 +66,16 @@ public class DefaultHeaders<T> implements Headers<T> {
|
||||
T convertName(T name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the {@link #hashCode()} method to generate the hash code.
|
||||
*/
|
||||
public static final class JavaHashCodeGenerator<T> implements HashCodeGenerator<T> {
|
||||
@Override
|
||||
public int generateHashCode(T name) {
|
||||
return name.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A name converted which does not covert but instead just returns this {@code name} unchanged
|
||||
*/
|
||||
|
@ -16,6 +16,10 @@
|
||||
|
||||
package io.netty.handler.codec;
|
||||
|
||||
import static io.netty.util.AsciiString.CHARSEQUENCE_CASE_INSENSITIVE_ORDER;
|
||||
import static io.netty.util.AsciiString.CHARSEQUENCE_CASE_SENSITIVE_ORDER;
|
||||
import static io.netty.util.internal.StringUtil.COMMA;
|
||||
import io.netty.util.AsciiString;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
@ -23,9 +27,6 @@ import java.text.ParseException;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
|
||||
import static io.netty.handler.codec.AsciiString.*;
|
||||
import static io.netty.util.internal.StringUtil.COMMA;
|
||||
|
||||
public class DefaultTextHeaders extends DefaultConvertibleHeaders<CharSequence, String> implements TextHeaders {
|
||||
private static final HashCodeGenerator<CharSequence> CHARSEQUECE_CASE_INSENSITIVE_HASH_CODE_GENERATOR =
|
||||
new HashCodeGenerator<CharSequence>() {
|
||||
@ -36,12 +37,7 @@ public class DefaultTextHeaders extends DefaultConvertibleHeaders<CharSequence,
|
||||
};
|
||||
|
||||
private static final HashCodeGenerator<CharSequence> CHARSEQUECE_CASE_SENSITIVE_HASH_CODE_GENERATOR =
|
||||
new HashCodeGenerator<CharSequence>() {
|
||||
@Override
|
||||
public int generateHashCode(CharSequence name) {
|
||||
return name.hashCode();
|
||||
}
|
||||
};
|
||||
new JavaHashCodeGenerator<CharSequence>();
|
||||
|
||||
public static class DefaultTextValueTypeConverter implements ValueConverter<CharSequence> {
|
||||
@Override
|
||||
|
@ -16,96 +16,98 @@
|
||||
|
||||
package io.netty.handler.codec;
|
||||
|
||||
public class EmptyBinaryHeaders extends EmptyHeaders<AsciiString> implements BinaryHeaders {
|
||||
import io.netty.util.ByteString;
|
||||
|
||||
public class EmptyBinaryHeaders extends EmptyHeaders<ByteString> implements BinaryHeaders {
|
||||
protected EmptyBinaryHeaders() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders add(AsciiString name, AsciiString value) {
|
||||
public BinaryHeaders add(ByteString name, ByteString value) {
|
||||
super.add(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders add(AsciiString name, Iterable<? extends AsciiString> values) {
|
||||
public BinaryHeaders add(ByteString name, Iterable<? extends ByteString> values) {
|
||||
super.add(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders add(AsciiString name, AsciiString... values) {
|
||||
public BinaryHeaders add(ByteString name, ByteString... values) {
|
||||
super.add(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addObject(AsciiString name, Object value) {
|
||||
public BinaryHeaders addObject(ByteString name, Object value) {
|
||||
super.addObject(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addObject(AsciiString name, Iterable<?> values) {
|
||||
public BinaryHeaders addObject(ByteString name, Iterable<?> values) {
|
||||
super.addObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addObject(AsciiString name, Object... values) {
|
||||
public BinaryHeaders addObject(ByteString name, Object... values) {
|
||||
super.addObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addBoolean(AsciiString name, boolean value) {
|
||||
public BinaryHeaders addBoolean(ByteString name, boolean value) {
|
||||
super.addBoolean(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addChar(AsciiString name, char value) {
|
||||
public BinaryHeaders addChar(ByteString name, char value) {
|
||||
super.addChar(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addByte(AsciiString name, byte value) {
|
||||
public BinaryHeaders addByte(ByteString name, byte value) {
|
||||
super.addByte(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addShort(AsciiString name, short value) {
|
||||
public BinaryHeaders addShort(ByteString name, short value) {
|
||||
super.addShort(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addInt(AsciiString name, int value) {
|
||||
public BinaryHeaders addInt(ByteString name, int value) {
|
||||
super.addInt(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addLong(AsciiString name, long value) {
|
||||
public BinaryHeaders addLong(ByteString name, long value) {
|
||||
super.addLong(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addFloat(AsciiString name, float value) {
|
||||
public BinaryHeaders addFloat(ByteString name, float value) {
|
||||
super.addFloat(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addDouble(AsciiString name, double value) {
|
||||
public BinaryHeaders addDouble(ByteString name, double value) {
|
||||
super.addDouble(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addTimeMillis(AsciiString name, long value) {
|
||||
public BinaryHeaders addTimeMillis(ByteString name, long value) {
|
||||
super.addTimeMillis(name, value);
|
||||
return this;
|
||||
}
|
||||
@ -117,91 +119,91 @@ public class EmptyBinaryHeaders extends EmptyHeaders<AsciiString> implements Bin
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders set(AsciiString name, AsciiString value) {
|
||||
public BinaryHeaders set(ByteString name, ByteString value) {
|
||||
super.set(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders set(AsciiString name, Iterable<? extends AsciiString> values) {
|
||||
public BinaryHeaders set(ByteString name, Iterable<? extends ByteString> values) {
|
||||
super.set(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders set(AsciiString name, AsciiString... values) {
|
||||
public BinaryHeaders set(ByteString name, ByteString... values) {
|
||||
super.set(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setObject(AsciiString name, Object value) {
|
||||
public BinaryHeaders setObject(ByteString name, Object value) {
|
||||
super.setObject(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setObject(AsciiString name, Iterable<?> values) {
|
||||
public BinaryHeaders setObject(ByteString name, Iterable<?> values) {
|
||||
super.setObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setObject(AsciiString name, Object... values) {
|
||||
public BinaryHeaders setObject(ByteString name, Object... values) {
|
||||
super.setObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setBoolean(AsciiString name, boolean value) {
|
||||
public BinaryHeaders setBoolean(ByteString name, boolean value) {
|
||||
super.setBoolean(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setChar(AsciiString name, char value) {
|
||||
public BinaryHeaders setChar(ByteString name, char value) {
|
||||
super.setChar(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setByte(AsciiString name, byte value) {
|
||||
public BinaryHeaders setByte(ByteString name, byte value) {
|
||||
super.setByte(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setShort(AsciiString name, short value) {
|
||||
public BinaryHeaders setShort(ByteString name, short value) {
|
||||
super.setShort(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setInt(AsciiString name, int value) {
|
||||
public BinaryHeaders setInt(ByteString name, int value) {
|
||||
super.setInt(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setLong(AsciiString name, long value) {
|
||||
public BinaryHeaders setLong(ByteString name, long value) {
|
||||
super.setLong(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setFloat(AsciiString name, float value) {
|
||||
public BinaryHeaders setFloat(ByteString name, float value) {
|
||||
super.setFloat(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setDouble(AsciiString name, double value) {
|
||||
public BinaryHeaders setDouble(ByteString name, double value) {
|
||||
super.setDouble(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setTimeMillis(AsciiString name, long value) {
|
||||
public BinaryHeaders setTimeMillis(ByteString name, long value) {
|
||||
super.setTimeMillis(name, value);
|
||||
return this;
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ import java.util.Set;
|
||||
|
||||
public interface Headers<T> extends Iterable<Map.Entry<T, T>> {
|
||||
/**
|
||||
* A visitor that helps reduce GC pressure while iterating over a collection of {@link Headers}.
|
||||
* Provides an abstraction to iterate over elements maintained in the {@link Headers} collection.
|
||||
*/
|
||||
interface EntryVisitor<T> {
|
||||
/**
|
||||
@ -36,7 +36,7 @@ public interface Headers<T> extends Iterable<Map.Entry<T, T>> {
|
||||
}
|
||||
|
||||
/**
|
||||
* A visitor that helps reduce GC pressure while iterating over a collection of {@link Headers}.
|
||||
* Provides an abstraction to iterate over elements maintained in the {@link Headers} collection.
|
||||
*/
|
||||
interface NameVisitor<T> {
|
||||
/**
|
||||
@ -1095,16 +1095,14 @@ public interface Headers<T> extends Iterable<Map.Entry<T, T>> {
|
||||
Iterator<Entry<T, T>> iterator();
|
||||
|
||||
/**
|
||||
* Provide a means of iterating over elements in this map with low GC
|
||||
*
|
||||
* Provides an abstraction to iterate over elements maintained in the {@link Headers} collection.
|
||||
* @param visitor The visitor which will visit each element in this map
|
||||
* @return The last entry before iteration stopped or {@code null} if iteration went past the end
|
||||
*/
|
||||
Map.Entry<T, T> forEachEntry(EntryVisitor<T> visitor) throws Exception;
|
||||
|
||||
/**
|
||||
* Provide a means of iterating over elements in this map with low GC
|
||||
*
|
||||
* Provides an abstraction to iterate over elements maintained in the {@link Headers} collection.
|
||||
* @param visitor The visitor which will visit each element in this map
|
||||
* @return The last key before iteration stopped or {@code null} if iteration went past the end
|
||||
*/
|
||||
|
@ -17,9 +17,9 @@ package io.netty.handler.codec;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.buffer.ByteBufProcessor;
|
||||
import io.netty.buffer.SwappedByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.util.ByteProcessor;
|
||||
import io.netty.util.Signal;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
@ -352,7 +352,7 @@ final class ReplayingDecoderByteBuf extends ByteBuf {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(ByteBufProcessor processor) {
|
||||
public int forEachByte(ByteProcessor processor) {
|
||||
int ret = buffer.forEachByte(processor);
|
||||
if (ret < 0) {
|
||||
throw REPLAY;
|
||||
@ -362,7 +362,7 @@ final class ReplayingDecoderByteBuf extends ByteBuf {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(int index, int length, ByteBufProcessor processor) {
|
||||
public int forEachByte(int index, int length, ByteProcessor processor) {
|
||||
final int writerIndex = buffer.writerIndex();
|
||||
if (index >= writerIndex) {
|
||||
throw REPLAY;
|
||||
@ -381,7 +381,7 @@ final class ReplayingDecoderByteBuf extends ByteBuf {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(ByteBufProcessor processor) {
|
||||
public int forEachByteDesc(ByteProcessor processor) {
|
||||
if (terminated) {
|
||||
return buffer.forEachByteDesc(processor);
|
||||
} else {
|
||||
@ -391,7 +391,7 @@ final class ReplayingDecoderByteBuf extends ByteBuf {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(int index, int length, ByteBufProcessor processor) {
|
||||
public int forEachByteDesc(int index, int length, ByteProcessor processor) {
|
||||
if (index + length > buffer.writerIndex()) {
|
||||
throw REPLAY;
|
||||
}
|
||||
|
@ -17,6 +17,8 @@ package io.netty.handler.codec;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import io.netty.util.AsciiString;
|
||||
import io.netty.util.ByteString;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@ -40,11 +42,11 @@ public class DefaultBinaryHeadersTest {
|
||||
byte[] key2 = randomBytes();
|
||||
byte[] value2 = randomBytes();
|
||||
|
||||
DefaultBinaryHeaders h1 = new DefaultBinaryHeaders(false);
|
||||
DefaultBinaryHeaders h1 = new DefaultBinaryHeaders();
|
||||
h1.set(as(key1), as(value1));
|
||||
h1.set(as(key2), as(value2));
|
||||
|
||||
DefaultBinaryHeaders h2 = new DefaultBinaryHeaders(false);
|
||||
DefaultBinaryHeaders h2 = new DefaultBinaryHeaders();
|
||||
h2.set(as(key1), as(value1));
|
||||
h2.set(as(key2), as(value2));
|
||||
|
||||
@ -63,13 +65,13 @@ public class DefaultBinaryHeadersTest {
|
||||
byte[] v3 = randomBytes();
|
||||
byte[] v4 = randomBytes();
|
||||
|
||||
DefaultBinaryHeaders h1 = new DefaultBinaryHeaders(false);
|
||||
DefaultBinaryHeaders h1 = new DefaultBinaryHeaders();
|
||||
h1.set(as(k1), as(v1));
|
||||
h1.set(as(k2), as(v2));
|
||||
h1.add(as(k2), as(v3));
|
||||
h1.add(as(k1), as(v4));
|
||||
|
||||
DefaultBinaryHeaders h2 = new DefaultBinaryHeaders(false);
|
||||
DefaultBinaryHeaders h2 = new DefaultBinaryHeaders();
|
||||
h2.set(as(k1), as(v1));
|
||||
h2.set(as(k2), as(v2));
|
||||
h2.add(as(k1), as(v4));
|
||||
@ -90,13 +92,13 @@ public class DefaultBinaryHeadersTest {
|
||||
byte[] v3 = randomBytes();
|
||||
byte[] v4 = randomBytes();
|
||||
|
||||
DefaultBinaryHeaders h1 = new DefaultBinaryHeaders(false);
|
||||
DefaultBinaryHeaders h1 = new DefaultBinaryHeaders();
|
||||
h1.set(as(k1), as(v1));
|
||||
h1.set(as(k2), as(v2));
|
||||
h1.add(as(k2), as(v3));
|
||||
h1.add(as(k1), as(v4));
|
||||
|
||||
DefaultBinaryHeaders h2 = new DefaultBinaryHeaders(false);
|
||||
DefaultBinaryHeaders h2 = new DefaultBinaryHeaders();
|
||||
h2.set(as(k1), as(v1));
|
||||
h2.set(as(k2), as(v2));
|
||||
h2.add(as(k1), as(v4));
|
||||
@ -116,18 +118,18 @@ public class DefaultBinaryHeadersTest {
|
||||
byte[] v3 = randomBytes();
|
||||
byte[] v4 = randomBytes();
|
||||
|
||||
DefaultBinaryHeaders h1 = new DefaultBinaryHeaders(false);
|
||||
DefaultBinaryHeaders h1 = new DefaultBinaryHeaders();
|
||||
h1.set(as(k1), as(v1));
|
||||
h1.set(as(k2), as(v2));
|
||||
h1.add(as(k2), as(v3));
|
||||
h1.add(as(k1), as(v4));
|
||||
|
||||
DefaultBinaryHeaders h2 = new DefaultBinaryHeaders(false);
|
||||
DefaultBinaryHeaders h2 = new DefaultBinaryHeaders();
|
||||
h2.set(as(k1), as(v1));
|
||||
h2.set(as(k2), as(v2));
|
||||
h2.add(as(k1), as(v4));
|
||||
|
||||
DefaultBinaryHeaders expected = new DefaultBinaryHeaders(false);
|
||||
DefaultBinaryHeaders expected = new DefaultBinaryHeaders();
|
||||
expected.set(as(k1), as(v1));
|
||||
expected.set(as(k2), as(v2));
|
||||
expected.add(as(k2), as(v3));
|
||||
@ -148,14 +150,14 @@ public class DefaultBinaryHeadersTest {
|
||||
byte[] v2 = randomBytes();
|
||||
byte[] v3 = randomBytes();
|
||||
|
||||
DefaultBinaryHeaders h1 = new DefaultBinaryHeaders(false);
|
||||
DefaultBinaryHeaders h1 = new DefaultBinaryHeaders();
|
||||
h1.add(as(k1), as(v1));
|
||||
h1.add(as(k1), as(v2));
|
||||
assertEquals(2, h1.size());
|
||||
|
||||
h1.set(as(k1), as(v3));
|
||||
assertEquals(1, h1.size());
|
||||
List<AsciiString> list = h1.getAll(as(k1));
|
||||
List<ByteString> list = h1.getAll(as(k1));
|
||||
assertEquals(1, list.size());
|
||||
assertEquals(as(v3), list.get(0));
|
||||
}
|
||||
@ -251,14 +253,14 @@ public class DefaultBinaryHeadersTest {
|
||||
|
||||
h1.set(as("foo"), as("goo3"));
|
||||
assertEquals(1, h1.size());
|
||||
List<AsciiString> list = h1.getAll(as("foo"));
|
||||
List<ByteString> list = h1.getAll(as("foo"));
|
||||
assertEquals(1, list.size());
|
||||
assertEquals(as("goo3"), list.get(0));
|
||||
}
|
||||
|
||||
@Test(expected = NoSuchElementException.class)
|
||||
public void iterateEmptyHeadersShouldThrow() {
|
||||
Iterator<Map.Entry<AsciiString, AsciiString>> iterator = new DefaultBinaryHeaders().iterator();
|
||||
Iterator<Map.Entry<ByteString, ByteString>> iterator = new DefaultBinaryHeaders().iterator();
|
||||
assertFalse(iterator.hasNext());
|
||||
iterator.next();
|
||||
}
|
||||
@ -281,7 +283,7 @@ public class DefaultBinaryHeadersTest {
|
||||
}
|
||||
|
||||
// Now iterate through the headers, removing them from the original set.
|
||||
for (Map.Entry<AsciiString, AsciiString> entry : h1) {
|
||||
for (Map.Entry<ByteString, ByteString> entry : h1) {
|
||||
assertTrue(headers.remove(entry.getKey().toString() + ':' + entry.getValue().toString()));
|
||||
}
|
||||
|
||||
@ -296,7 +298,7 @@ public class DefaultBinaryHeadersTest {
|
||||
h1.add(as("foo"), as("goo2"));
|
||||
assertEquals(as("goo"), h1.getAndRemove(as("foo")));
|
||||
assertEquals(0, h1.size());
|
||||
List<AsciiString> values = h1.getAll(as("foo"));
|
||||
List<ByteString> values = h1.getAll(as("foo"));
|
||||
assertEquals(0, values.size());
|
||||
}
|
||||
|
||||
|
@ -13,11 +13,13 @@
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.handler.codec;
|
||||
package io.netty.util;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
||||
import static io.netty.util.internal.StringUtil.UPPER_CASE_TO_LOWER_CASE_ASCII_OFFSET;
|
||||
import io.netty.util.ByteProcessor.IndexOfProcessor;
|
||||
import io.netty.util.internal.EmptyArrays;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
@ -32,11 +34,13 @@ import java.util.regex.PatternSyntaxException;
|
||||
* A string which has been encoded into a character encoding whose character always takes a single byte, similarly to
|
||||
* ASCII. It internally keeps its content in a byte array unlike {@link String}, which uses a character array, for
|
||||
* reduced memory footprint and faster data transfer from/to byte-based data structures such as a byte array and
|
||||
* {@link ByteBuf}. It is often used in conjunction with {@link TextHeaders}.
|
||||
* {@link ByteBuffer}. It is often used in conjunction with {@link TextHeaders}.
|
||||
*/
|
||||
public final class AsciiString implements CharSequence, Comparable<CharSequence> {
|
||||
public final class AsciiString extends ByteString implements CharSequence, Comparable<CharSequence> {
|
||||
|
||||
private static final char MAX_CHAR_VALUE = 255;
|
||||
public static final AsciiString EMPTY_STRING = new AsciiString("");
|
||||
|
||||
public static final Comparator<AsciiString> CASE_INSENSITIVE_ORDER = new Comparator<AsciiString>() {
|
||||
@Override
|
||||
public int compare(AsciiString o1, AsciiString o2) {
|
||||
@ -73,8 +77,8 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
if (v1 == v2) {
|
||||
continue;
|
||||
}
|
||||
int c1 = toLowerCase(v1) & 0xFF;
|
||||
int c2 = toLowerCase(v2) & 0xFF;
|
||||
int c1 = toLowerCase(v1);
|
||||
int c2 = toLowerCase(v2);
|
||||
result = c1 - c2;
|
||||
if (result != 0) {
|
||||
return result;
|
||||
@ -83,7 +87,7 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
} else if (a1 != null) {
|
||||
byte[] thisValue = a1.value;
|
||||
for (int i = 0; i < minLength; i++) {
|
||||
int c1 = toLowerCase(thisValue[i]) & 0xFF;
|
||||
int c1 = toLowerCase(thisValue[i]);
|
||||
int c2 = toLowerCase(o2.charAt(i));
|
||||
result = c1 - c2;
|
||||
if (result != 0) {
|
||||
@ -94,7 +98,7 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
byte[] thatValue = a2.value;
|
||||
for (int i = 0; i < minLength; i++) {
|
||||
int c1 = toLowerCase(o1.charAt(i));
|
||||
int c2 = toLowerCase(thatValue[i]) & 0xFF;
|
||||
int c2 = toLowerCase(thatValue[i]);
|
||||
result = c1 - c2;
|
||||
if (result != 0) {
|
||||
return result;
|
||||
@ -188,7 +192,7 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
int hash = 0;
|
||||
final int end = value.length();
|
||||
for (int i = 0; i < end; i++) {
|
||||
hash = hash * 31 ^ value.charAt(i) & 31;
|
||||
hash = hash * HASH_CODE_PRIME ^ value.charAt(i) & HASH_CODE_PRIME;
|
||||
}
|
||||
|
||||
return hash;
|
||||
@ -245,27 +249,7 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
return a.equals(b);
|
||||
}
|
||||
|
||||
public static byte[] getBytes(CharSequence v, Charset charset) {
|
||||
if (v instanceof AsciiString) {
|
||||
return ((AsciiString) v).array();
|
||||
} else if (v instanceof String) {
|
||||
return ((String) v).getBytes(charset);
|
||||
} else if (v != null) {
|
||||
final ByteBuf buf = Unpooled.copiedBuffer(v, charset);
|
||||
try {
|
||||
if (buf.hasArray()) {
|
||||
return buf.array();
|
||||
} else {
|
||||
byte[] result = new byte[buf.readableBytes()];
|
||||
buf.readBytes(result);
|
||||
return result;
|
||||
}
|
||||
} finally {
|
||||
buf.release();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private String string;
|
||||
|
||||
/**
|
||||
* Returns an {@link AsciiString} containing the given character sequence. If the given string is already a
|
||||
@ -275,259 +259,113 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
return string instanceof AsciiString ? (AsciiString) string : new AsciiString(string);
|
||||
}
|
||||
|
||||
private final byte[] value;
|
||||
private String string;
|
||||
private int hash;
|
||||
|
||||
public AsciiString(byte[] value) {
|
||||
this(value, true);
|
||||
super(value);
|
||||
}
|
||||
|
||||
public AsciiString(byte[] value, boolean copy) {
|
||||
checkNull(value);
|
||||
if (copy) {
|
||||
this.value = value.clone();
|
||||
} else {
|
||||
this.value = value;
|
||||
}
|
||||
super(value, copy);
|
||||
}
|
||||
|
||||
public AsciiString(byte[] value, int start, int length) {
|
||||
this(value, start, length, true);
|
||||
super(value, start, length);
|
||||
}
|
||||
|
||||
public AsciiString(byte[] value, int start, int length, boolean copy) {
|
||||
checkNull(value);
|
||||
if (start < 0 || start > value.length - length) {
|
||||
throw new IndexOutOfBoundsException("expected: " + "0 <= start(" + start + ") <= start + length(" + length
|
||||
+ ") <= " + "value.length(" + value.length + ')');
|
||||
super(value, start, length, copy);
|
||||
}
|
||||
|
||||
if (copy || start != 0 || length != value.length) {
|
||||
this.value = Arrays.copyOfRange(value, start, start + length);
|
||||
} else {
|
||||
this.value = value;
|
||||
public AsciiString(ByteBuffer value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
public AsciiString(ByteBuffer value, int start, int length) {
|
||||
super(value, start, length);
|
||||
}
|
||||
|
||||
public AsciiString(ByteBuffer value, int start, int length, boolean copy) {
|
||||
super(value, start, length, copy);
|
||||
}
|
||||
|
||||
public AsciiString(char[] value) {
|
||||
this(checkNull(value), 0, value.length);
|
||||
this(checkNotNull(value, "value"), 0, value.length);
|
||||
}
|
||||
|
||||
public AsciiString(char[] value, int start, int length) {
|
||||
checkNull(value);
|
||||
if (start < 0 || start > value.length - length) {
|
||||
super(length);
|
||||
if (start < 0 || start > checkNotNull(value, "value").length - length) {
|
||||
throw new IndexOutOfBoundsException("expected: " + "0 <= start(" + start + ") <= start + length(" + length
|
||||
+ ") <= " + "value.length(" + value.length + ')');
|
||||
}
|
||||
|
||||
this.value = new byte[length];
|
||||
for (int i = 0, j = start; i < length; i++, j++) {
|
||||
this.value[i] = c2b(value[j]);
|
||||
}
|
||||
}
|
||||
|
||||
public AsciiString(CharSequence value) {
|
||||
this(checkNull(value), 0, value.length());
|
||||
this(checkNotNull(value, "value"), 0, value.length());
|
||||
}
|
||||
|
||||
public AsciiString(CharSequence value, int start, int length) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
|
||||
if (start < 0 || length < 0 || length > value.length() - start) {
|
||||
super(length);
|
||||
if (start < 0 || length < 0 || length > checkNotNull(value, "value").length() - start) {
|
||||
throw new IndexOutOfBoundsException("expected: " + "0 <= start(" + start + ") <= start + length(" + length
|
||||
+ ") <= " + "value.length(" + value.length() + ')');
|
||||
}
|
||||
|
||||
this.value = new byte[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
this.value[i] = c2b(value.charAt(start + i));
|
||||
}
|
||||
}
|
||||
|
||||
public AsciiString(ByteBuffer value) {
|
||||
this(checkNull(value), value.position(), value.remaining());
|
||||
}
|
||||
|
||||
public AsciiString(ByteBuffer value, int start, int length) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
|
||||
if (start < 0 || length > value.capacity() - start) {
|
||||
throw new IndexOutOfBoundsException("expected: " + "0 <= start(" + start + ") <= start + length(" + length
|
||||
+ ") <= " + "value.capacity(" + value.capacity() + ')');
|
||||
}
|
||||
|
||||
if (value.hasArray()) {
|
||||
int baseOffset = value.arrayOffset() + start;
|
||||
this.value = Arrays.copyOfRange(value.array(), baseOffset, baseOffset + length);
|
||||
} else {
|
||||
this.value = new byte[length];
|
||||
int oldPos = value.position();
|
||||
value.get(this.value, 0, this.value.length);
|
||||
value.position(oldPos);
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> T checkNull(T value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return value.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char charAt(int index) {
|
||||
return (char) (byteAt(index) & 0xFF);
|
||||
}
|
||||
|
||||
public byte byteAt(int index) {
|
||||
return value[index];
|
||||
}
|
||||
|
||||
public byte[] array() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public int arrayOffset() {
|
||||
return 0;
|
||||
return b2c(byteAt(index));
|
||||
}
|
||||
|
||||
private static byte c2b(char c) {
|
||||
if (c > 255) {
|
||||
if (c > MAX_CHAR_VALUE) {
|
||||
return '?';
|
||||
}
|
||||
return (byte) c;
|
||||
}
|
||||
|
||||
private static char b2c(byte b) {
|
||||
return (char) (b & 0xFF);
|
||||
}
|
||||
|
||||
private static byte toLowerCase(byte b) {
|
||||
if ('A' <= b && b <= 'Z') {
|
||||
return (byte) (b + 32);
|
||||
return (byte) (b + UPPER_CASE_TO_LOWER_CASE_ASCII_OFFSET);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
private static char toLowerCase(char c) {
|
||||
if ('A' <= c && c <= 'Z') {
|
||||
return (char) (c + 32);
|
||||
return (char) (c + UPPER_CASE_TO_LOWER_CASE_ASCII_OFFSET);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
private static byte toUpperCase(byte b) {
|
||||
if ('a' <= b && b <= 'z') {
|
||||
return (byte) (b - 32);
|
||||
return (byte) (b - UPPER_CASE_TO_LOWER_CASE_ASCII_OFFSET);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies a range of characters into a new string.
|
||||
*
|
||||
* @param start the offset of the first character.
|
||||
* @return a new string containing the characters from start to the end of the string.
|
||||
* @throws IndexOutOfBoundsException if {@code start < 0} or {@code start > length()}.
|
||||
*/
|
||||
public AsciiString subSequence(int start) {
|
||||
return subSequence(start, length());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString subSequence(int start, int end) {
|
||||
if (start < 0 || start > end || end > length()) {
|
||||
throw new IndexOutOfBoundsException("expected: 0 <= start(" + start + ") <= end (" + end + ") <= length("
|
||||
+ length() + ')');
|
||||
public String toString(Charset charset, int start, int end) {
|
||||
if (start == 0 && end == length()) {
|
||||
if (string == null) {
|
||||
string = super.toString(charset, start, end);
|
||||
}
|
||||
|
||||
final byte[] value = this.value;
|
||||
if (start == 0 && end == value.length) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (end == start) {
|
||||
return EMPTY_STRING;
|
||||
}
|
||||
|
||||
return new AsciiString(value, start, end - start, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = this.hash;
|
||||
final byte[] value = this.value;
|
||||
if (hash != 0 || value.length == 0) {
|
||||
return hash;
|
||||
}
|
||||
|
||||
for (int i = 0; i < value.length; ++i) {
|
||||
hash = hash * 31 ^ value[i] & 31;
|
||||
}
|
||||
|
||||
return this.hash = hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof AsciiString)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
AsciiString that = (AsciiString) obj;
|
||||
int thisHash = hashCode();
|
||||
int thatHash = that.hashCode();
|
||||
if (thisHash != thatHash || length() != that.length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
byte[] thisValue = value;
|
||||
byte[] thatValue = that.value;
|
||||
int end = thisValue.length;
|
||||
for (int i = 0, j = 0; i < end; i++, j++) {
|
||||
if (thisValue[i] != thatValue[j]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public String toString() {
|
||||
String string = this.string;
|
||||
if (string != null) {
|
||||
return string;
|
||||
}
|
||||
|
||||
final byte[] value = this.value;
|
||||
return this.string = new String(value, 0, 0, value.length);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public String toString(int start, int end) {
|
||||
final byte[] value = this.value;
|
||||
if (start == 0 && end == value.length) {
|
||||
return toString();
|
||||
}
|
||||
|
||||
int length = end - start;
|
||||
if (length == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return new String(value, 0, start, length);
|
||||
return super.toString(charset, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -543,7 +381,6 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
* positive integer if this string is after the specified string.
|
||||
* @throws NullPointerException if {@code string} is {@code null}.
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(CharSequence string) {
|
||||
if (this == string) {
|
||||
return 0;
|
||||
@ -555,7 +392,7 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
int minLength = Math.min(length1, length2);
|
||||
byte[] value = this.value;
|
||||
for (int i = 0, j = 0; j < minLength; i++, j++) {
|
||||
result = (value[i] & 0xFF) - string.charAt(j);
|
||||
result = b2c(value[i]) - string.charAt(j);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
@ -648,7 +485,6 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
return false;
|
||||
}
|
||||
|
||||
final byte[] value = this.value;
|
||||
final int thisLen = value.length;
|
||||
final int thatLen = string.length();
|
||||
if (thisLen != thatLen) {
|
||||
@ -656,7 +492,7 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
}
|
||||
|
||||
for (int i = 0; i < thisLen; i++) {
|
||||
char c1 = (char) (value[i] & 0xFF);
|
||||
char c1 = b2c(value[i]);
|
||||
char c2 = string.charAt(i);
|
||||
if (c1 != c2 && toLowerCase(c1) != toLowerCase(c2)) {
|
||||
return false;
|
||||
@ -665,24 +501,6 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this string to a byte array using the ASCII encoding.
|
||||
*
|
||||
* @return the byte array encoding of this string.
|
||||
*/
|
||||
public byte[] toByteArray() {
|
||||
return toByteArray(0, length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this string to a byte array using the ASCII encoding.
|
||||
*
|
||||
* @return the byte array encoding of this string.
|
||||
*/
|
||||
public byte[] toByteArray(int start, int end) {
|
||||
return Arrays.copyOfRange(value, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the characters in this string to a character array.
|
||||
*
|
||||
@ -703,85 +521,13 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
return EmptyArrays.EMPTY_CHARS;
|
||||
}
|
||||
|
||||
final byte[] value = this.value;
|
||||
final char[] buffer = new char[length];
|
||||
for (int i = 0, j = start; i < length; i++, j++) {
|
||||
buffer[i] = (char) (value[j] & 0xFF);
|
||||
buffer[i] = b2c(value[j]);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the content of this string to a {@link ByteBuf} using {@link ByteBuf#writeBytes(byte[], int, int)}.
|
||||
*
|
||||
* @param srcIdx the starting offset of characters to copy.
|
||||
* @param dst the destination byte array.
|
||||
* @param dstIdx the starting offset in the destination byte array.
|
||||
* @param length the number of characters to copy.
|
||||
*/
|
||||
public void copy(int srcIdx, ByteBuf dst, int dstIdx, int length) {
|
||||
if (dst == null) {
|
||||
throw new NullPointerException("dst");
|
||||
}
|
||||
|
||||
final byte[] value = this.value;
|
||||
final int thisLen = value.length;
|
||||
|
||||
if (srcIdx < 0 || length > thisLen - srcIdx) {
|
||||
throw new IndexOutOfBoundsException("expected: " + "0 <= srcIdx(" + srcIdx + ") <= srcIdx + length("
|
||||
+ length + ") <= srcLen(" + thisLen + ')');
|
||||
}
|
||||
|
||||
dst.setBytes(dstIdx, value, srcIdx, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the content of this string to a {@link ByteBuf} using {@link ByteBuf#writeBytes(byte[], int, int)}.
|
||||
*
|
||||
* @param srcIdx the starting offset of characters to copy.
|
||||
* @param dst the destination byte array.
|
||||
* @param length the number of characters to copy.
|
||||
*/
|
||||
public void copy(int srcIdx, ByteBuf dst, int length) {
|
||||
if (dst == null) {
|
||||
throw new NullPointerException("dst");
|
||||
}
|
||||
|
||||
final byte[] value = this.value;
|
||||
final int thisLen = value.length;
|
||||
|
||||
if (srcIdx < 0 || length > thisLen - srcIdx) {
|
||||
throw new IndexOutOfBoundsException("expected: " + "0 <= srcIdx(" + srcIdx + ") <= srcIdx + length("
|
||||
+ length + ") <= srcLen(" + thisLen + ')');
|
||||
}
|
||||
|
||||
dst.writeBytes(value, srcIdx, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the content of this string to a byte array.
|
||||
*
|
||||
* @param srcIdx the starting offset of characters to copy.
|
||||
* @param dst the destination byte array.
|
||||
* @param dstIdx the starting offset in the destination byte array.
|
||||
* @param length the number of characters to copy.
|
||||
*/
|
||||
public void copy(int srcIdx, byte[] dst, int dstIdx, int length) {
|
||||
if (dst == null) {
|
||||
throw new NullPointerException("dst");
|
||||
}
|
||||
|
||||
final byte[] value = this.value;
|
||||
final int thisLen = value.length;
|
||||
|
||||
if (srcIdx < 0 || length > thisLen - srcIdx) {
|
||||
throw new IndexOutOfBoundsException("expected: " + "0 <= srcIdx(" + srcIdx + ") <= srcIdx + length("
|
||||
+ length + ") <= srcLen(" + thisLen + ')');
|
||||
}
|
||||
|
||||
System.arraycopy(value, srcIdx, dst, dstIdx, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copied the content of this string to a character array.
|
||||
*
|
||||
@ -795,7 +541,6 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
throw new NullPointerException("dst");
|
||||
}
|
||||
|
||||
final byte[] value = this.value;
|
||||
final int thisLen = value.length;
|
||||
|
||||
if (srcIdx < 0 || length > thisLen - srcIdx) {
|
||||
@ -805,44 +550,13 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
|
||||
final int dstEnd = dstIdx + length;
|
||||
for (int i = srcIdx, j = dstIdx; j < dstEnd; i++, j++) {
|
||||
dst[j] = (char) (value[i] & 0xFF);
|
||||
dst[j] = b2c(value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches in this string for the first index of the specified character. The search for the character starts at
|
||||
* the beginning and moves towards the end of this string.
|
||||
*
|
||||
* @param c the character to find.
|
||||
* @return the index in this string of the specified character, -1 if the character isn't found.
|
||||
*/
|
||||
public int indexOf(int c) {
|
||||
return indexOf(c, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches in this string for the index of the specified character. The search for the character starts at the
|
||||
* specified offset and moves towards the end of this string.
|
||||
*
|
||||
* @param c the character to find.
|
||||
* @param start the starting offset.
|
||||
* @return the index in this string of the specified character, -1 if the character isn't found.
|
||||
*/
|
||||
public int indexOf(int c, int start) {
|
||||
final byte[] value = this.value;
|
||||
final int length = value.length;
|
||||
if (start < length) {
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
}
|
||||
|
||||
for (int i = start; i < length; i++) {
|
||||
if ((value[i] & 0xFF) == c) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
@Override
|
||||
public AsciiString subSequence(int start, int end) {
|
||||
return (AsciiString) super.subSequence(start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -873,7 +587,6 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
start = 0;
|
||||
}
|
||||
|
||||
final byte[] value = this.value;
|
||||
final int thisLen = value.length;
|
||||
|
||||
int subCount = subString.length();
|
||||
@ -884,14 +597,16 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
return -1;
|
||||
}
|
||||
|
||||
char firstChar = subString.charAt(0);
|
||||
final char firstChar = subString.charAt(0);
|
||||
ByteProcessor IndexOfVisitor = new IndexOfProcessor((byte) firstChar);
|
||||
try {
|
||||
for (;;) {
|
||||
int i = indexOf(firstChar, start);
|
||||
int i = forEachByte(start, thisLen - start, IndexOfVisitor);
|
||||
if (i == -1 || subCount + i > thisLen) {
|
||||
return -1; // handles subCount > count || start >= count
|
||||
}
|
||||
int o1 = i, o2 = 0;
|
||||
while (++o2 < subCount && (value[++o1] & 0xFF) == subString.charAt(o2)) {
|
||||
while (++o2 < subCount && b2c(value[++o1]) == subString.charAt(o2)) {
|
||||
// Intentionally empty
|
||||
}
|
||||
if (o2 == subCount) {
|
||||
@ -899,42 +614,11 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
}
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches in this string for the last index of the specified character. The search for the character starts at the
|
||||
* end and moves towards the beginning of this string.
|
||||
*
|
||||
* @param c the character to find.
|
||||
* @return the index in this string of the specified character, -1 if the character isn't found.
|
||||
*/
|
||||
public int lastIndexOf(int c) {
|
||||
return lastIndexOf(c, length() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches in this string for the index of the specified character. The search for the character starts at the
|
||||
* specified offset and moves towards the beginning of this string.
|
||||
*
|
||||
* @param c the character to find.
|
||||
* @param start the starting offset.
|
||||
* @return the index in this string of the specified character, -1 if the character isn't found.
|
||||
*/
|
||||
public int lastIndexOf(int c, int start) {
|
||||
if (start >= 0) {
|
||||
final byte[] value = this.value;
|
||||
final int length = value.length;
|
||||
if (start >= length) {
|
||||
start = length - 1;
|
||||
}
|
||||
for (int i = start; i >= 0; --i) {
|
||||
if ((value[i] & 0xFF) == c) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
PlatformDependent.throwException(e);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches in this string for the last index of the specified string. The search for the string starts at the end
|
||||
@ -961,7 +645,6 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
* @throws NullPointerException if {@code subString} is {@code null}.
|
||||
*/
|
||||
public int lastIndexOf(CharSequence subString, int start) {
|
||||
final byte[] value = this.value;
|
||||
final int thisLen = value.length;
|
||||
final int subCount = subString.length();
|
||||
|
||||
@ -976,14 +659,16 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
start = Math.min(start, thisLen - subCount);
|
||||
|
||||
// count and subCount are both >= 1
|
||||
char firstChar = subString.charAt(0);
|
||||
final char firstChar = subString.charAt(0);
|
||||
ByteProcessor IndexOfVisitor = new IndexOfProcessor((byte) firstChar);
|
||||
try {
|
||||
for (;;) {
|
||||
int i = lastIndexOf(firstChar, start);
|
||||
int i = forEachByteDesc(start, thisLen - start, IndexOfVisitor);
|
||||
if (i == -1) {
|
||||
return -1;
|
||||
}
|
||||
int o1 = i, o2 = 0;
|
||||
while (++o2 < subCount && (value[++o1] & 0xFF) == subString.charAt(o2)) {
|
||||
while (++o2 < subCount && b2c(value[++o1]) == subString.charAt(o2)) {
|
||||
// Intentionally empty
|
||||
}
|
||||
if (o2 == subCount) {
|
||||
@ -991,15 +676,10 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
}
|
||||
start = i - 1;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
PlatformDependent.throwException(e);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Answers if the size of this String is zero.
|
||||
*
|
||||
* @return true if the size of this String is zero, false otherwise
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return value.length == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1022,7 +702,6 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
return false;
|
||||
}
|
||||
|
||||
final byte[] value = this.value;
|
||||
final int thisLen = value.length;
|
||||
if (thisStart < 0 || thisLen - thisStart < length) {
|
||||
return false;
|
||||
@ -1034,7 +713,7 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
|
||||
final int thisEnd = thisStart + length;
|
||||
for (int i = thisStart, j = start; i < thisEnd; i++, j++) {
|
||||
if ((value[i] & 0xFF) != string.charAt(j)) {
|
||||
if (b2c(value[i]) != string.charAt(j)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1062,7 +741,6 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
throw new NullPointerException("string");
|
||||
}
|
||||
|
||||
final byte[] value = this.value;
|
||||
final int thisLen = value.length;
|
||||
if (thisStart < 0 || length > thisLen - thisStart) {
|
||||
return false;
|
||||
@ -1073,7 +751,7 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
|
||||
int thisEnd = thisStart + length;
|
||||
while (thisStart < thisEnd) {
|
||||
char c1 = (char) (value[thisStart++] & 0xFF);
|
||||
char c1 = b2c(value[thisStart++]);
|
||||
char c2 = string.charAt(start++);
|
||||
if (c1 != c2 && toLowerCase(c1) != toLowerCase(c2)) {
|
||||
return false;
|
||||
@ -1090,18 +768,29 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
* @return a new string with occurrences of oldChar replaced by newChar.
|
||||
*/
|
||||
public AsciiString replace(char oldChar, char newChar) {
|
||||
int index = indexOf(oldChar, 0);
|
||||
if (oldChar > MAX_CHAR_VALUE) {
|
||||
return this;
|
||||
}
|
||||
|
||||
final int index;
|
||||
final byte oldCharByte = c2b(oldChar);
|
||||
try {
|
||||
index = forEachByte(new IndexOfProcessor(oldCharByte));
|
||||
} catch (Exception e) {
|
||||
PlatformDependent.throwException(e);
|
||||
return this;
|
||||
}
|
||||
if (index == -1) {
|
||||
return this;
|
||||
}
|
||||
|
||||
final byte[] value = this.value;
|
||||
final int count = value.length;
|
||||
final byte newCharByte = c2b(newChar);
|
||||
byte[] buffer = new byte[count];
|
||||
for (int i = 0, j = 0; i < value.length; i++, j++) {
|
||||
for (int i = 0, j = 0; i < count; i++, j++) {
|
||||
byte b = value[i];
|
||||
if ((char) (b & 0xFF) == oldChar) {
|
||||
b = (byte) newChar;
|
||||
if (b == oldCharByte) {
|
||||
b = newCharByte;
|
||||
}
|
||||
buffer[j] = b;
|
||||
}
|
||||
@ -1141,7 +830,6 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
*/
|
||||
public AsciiString toLowerCase() {
|
||||
boolean lowercased = true;
|
||||
final byte[] value = this.value;
|
||||
int i, j;
|
||||
for (i = 0; i < value.length; ++i) {
|
||||
byte b = value[i];
|
||||
@ -1171,7 +859,6 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
* @return a new string containing the uppercase characters equivalent to the characters in this string.
|
||||
*/
|
||||
public AsciiString toUpperCase() {
|
||||
final byte[] value = this.value;
|
||||
boolean uppercased = true;
|
||||
int i, j;
|
||||
for (i = 0; i < value.length; ++i) {
|
||||
@ -1202,7 +889,6 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
* @return a new string with characters {@code <= \\u0020} removed from the beginning and the end.
|
||||
*/
|
||||
public AsciiString trim() {
|
||||
final byte[] value = this.value;
|
||||
int start = 0, last = value.length;
|
||||
int end = last;
|
||||
while (start <= end && value[start] <= ' ') {
|
||||
@ -1283,7 +969,6 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
final List<AsciiString> res = new ArrayList<AsciiString>();
|
||||
|
||||
int start = 0;
|
||||
final byte[] value = this.value;
|
||||
final int length = value.length;
|
||||
for (int i = start; i < length; i++) {
|
||||
if (charAt(i) == delim) {
|
||||
@ -1331,155 +1016,70 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
}
|
||||
|
||||
public int parseInt() {
|
||||
return parseInt(0, length(), 10);
|
||||
return parseAsciiInt();
|
||||
}
|
||||
|
||||
public int parseInt(int radix) {
|
||||
return parseInt(0, length(), radix);
|
||||
return parseAsciiInt(radix);
|
||||
}
|
||||
|
||||
public int parseInt(int start, int end) {
|
||||
return parseInt(start, end, 10);
|
||||
return parseAsciiInt(start, end);
|
||||
}
|
||||
|
||||
public int parseInt(int start, int end, int radix) {
|
||||
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
|
||||
throw new NumberFormatException();
|
||||
}
|
||||
|
||||
if (start == end) {
|
||||
throw new NumberFormatException();
|
||||
}
|
||||
|
||||
int i = start;
|
||||
boolean negative = charAt(i) == '-';
|
||||
if (negative && ++i == end) {
|
||||
throw new NumberFormatException(subSequence(start, end).toString());
|
||||
}
|
||||
|
||||
return parseInt(i, end, radix, negative);
|
||||
}
|
||||
|
||||
private int parseInt(int start, int end, int radix, boolean negative) {
|
||||
final byte[] value = this.value;
|
||||
int max = Integer.MIN_VALUE / radix;
|
||||
int result = 0;
|
||||
int offset = start;
|
||||
while (offset < end) {
|
||||
int digit = Character.digit((char) (value[offset++] & 0xFF), radix);
|
||||
if (digit == -1) {
|
||||
throw new NumberFormatException(subSequence(start, end).toString());
|
||||
}
|
||||
if (max > result) {
|
||||
throw new NumberFormatException(subSequence(start, end).toString());
|
||||
}
|
||||
int next = result * radix - digit;
|
||||
if (next > result) {
|
||||
throw new NumberFormatException(subSequence(start, end).toString());
|
||||
}
|
||||
result = next;
|
||||
}
|
||||
if (!negative) {
|
||||
result = -result;
|
||||
if (result < 0) {
|
||||
throw new NumberFormatException(subSequence(start, end).toString());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return parseAsciiInt(start, end, radix);
|
||||
}
|
||||
|
||||
public long parseLong() {
|
||||
return parseLong(0, length(), 10);
|
||||
return parseAsciiLong();
|
||||
}
|
||||
|
||||
public long parseLong(int radix) {
|
||||
return parseLong(0, length(), radix);
|
||||
return parseAsciiLong(radix);
|
||||
}
|
||||
|
||||
public long parseLong(int start, int end) {
|
||||
return parseLong(start, end, 10);
|
||||
return parseAsciiLong(start, end);
|
||||
}
|
||||
|
||||
public long parseLong(int start, int end, int radix) {
|
||||
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
|
||||
throw new NumberFormatException();
|
||||
return parseAsciiLong(start, end, radix);
|
||||
}
|
||||
|
||||
if (start == end) {
|
||||
throw new NumberFormatException();
|
||||
}
|
||||
|
||||
int i = start;
|
||||
boolean negative = charAt(i) == '-';
|
||||
if (negative && ++i == end) {
|
||||
throw new NumberFormatException(subSequence(start, end).toString());
|
||||
}
|
||||
|
||||
return parseLong(i, end, radix, negative);
|
||||
}
|
||||
|
||||
private long parseLong(int start, int end, int radix, boolean negative) {
|
||||
final byte[] value = this.value;
|
||||
long max = Long.MIN_VALUE / radix;
|
||||
long result = 0;
|
||||
int offset = start;
|
||||
while (offset < end) {
|
||||
int digit = Character.digit((char) (value[offset++] & 0xFF), radix);
|
||||
if (digit == -1) {
|
||||
throw new NumberFormatException(subSequence(start, end).toString());
|
||||
}
|
||||
if (max > result) {
|
||||
throw new NumberFormatException(subSequence(start, end).toString());
|
||||
}
|
||||
long next = result * radix - digit;
|
||||
if (next > result) {
|
||||
throw new NumberFormatException(subSequence(start, end).toString());
|
||||
}
|
||||
result = next;
|
||||
}
|
||||
if (!negative) {
|
||||
result = -result;
|
||||
if (result < 0) {
|
||||
throw new NumberFormatException(subSequence(start, end).toString());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
public char parseChar(int start) {
|
||||
return charAt(start);
|
||||
}
|
||||
|
||||
public short parseShort() {
|
||||
return parseShort(0, length(), 10);
|
||||
return parseAsciiShort();
|
||||
}
|
||||
|
||||
public short parseShort(int radix) {
|
||||
return parseShort(0, length(), radix);
|
||||
return parseAsciiShort(radix);
|
||||
}
|
||||
|
||||
public short parseShort(int start, int end) {
|
||||
return parseShort(start, end, 10);
|
||||
return parseAsciiShort(start, end);
|
||||
}
|
||||
|
||||
public short parseShort(int start, int end, int radix) {
|
||||
int intValue = parseInt(start, end, radix);
|
||||
short result = (short) intValue;
|
||||
if (result != intValue) {
|
||||
throw new NumberFormatException(subSequence(start, end).toString());
|
||||
}
|
||||
return result;
|
||||
return parseAsciiShort(start, end, radix);
|
||||
}
|
||||
|
||||
public float parseFloat() {
|
||||
return parseFloat(0, length());
|
||||
return parseAsciiFloat();
|
||||
}
|
||||
|
||||
public float parseFloat(int start, int end) {
|
||||
return Float.parseFloat(toString(start, end));
|
||||
return parseAsciiFloat(start, end);
|
||||
}
|
||||
|
||||
public double parseDouble() {
|
||||
return parseDouble(0, length());
|
||||
return parseAsciiDouble();
|
||||
}
|
||||
|
||||
public double parseDouble(int start, int end) {
|
||||
return Double.parseDouble(toString(start, end));
|
||||
return parseAsciiDouble(start, end);
|
||||
}
|
||||
}
|
128
common/src/main/java/io/netty/util/ByteProcessor.java
Normal file
128
common/src/main/java/io/netty/util/ByteProcessor.java
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2015 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License, version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain a
|
||||
* copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package io.netty.util;
|
||||
|
||||
/**
|
||||
* Provides a mechanism to iterate over a collection of bytes.
|
||||
*/
|
||||
public interface ByteProcessor {
|
||||
/**
|
||||
* A {@link ByteProcessor} which finds the first appearance of a specific byte.
|
||||
*/
|
||||
class IndexOfProcessor implements ByteProcessor {
|
||||
private final byte byteToFind;
|
||||
|
||||
public IndexOfProcessor(byte byteToFind) {
|
||||
this.byteToFind = byteToFind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(byte value) {
|
||||
return value != byteToFind;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link ByteProcessor} which finds the first appearance which is not of a specific byte.
|
||||
*/
|
||||
class IndexNotOfProcessor implements ByteProcessor {
|
||||
private final byte byteToNotFind;
|
||||
|
||||
public IndexNotOfProcessor(byte byteToNotFind) {
|
||||
this.byteToNotFind = byteToNotFind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(byte value) {
|
||||
return value == byteToNotFind;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aborts on a {@code NUL (0x00)}.
|
||||
*/
|
||||
ByteProcessor FIND_NUL = new IndexOfProcessor((byte) 0);
|
||||
|
||||
/**
|
||||
* Aborts on a non-{@code NUL (0x00)}.
|
||||
*/
|
||||
ByteProcessor FIND_NON_NUL = new IndexNotOfProcessor((byte) 0);
|
||||
|
||||
/**
|
||||
* Aborts on a {@code CR ('\r')}.
|
||||
*/
|
||||
ByteProcessor FIND_CR = new IndexOfProcessor((byte) '\r');
|
||||
|
||||
/**
|
||||
* Aborts on a non-{@code CR ('\r')}.
|
||||
*/
|
||||
ByteProcessor FIND_NON_CR = new IndexNotOfProcessor((byte) '\r');
|
||||
|
||||
/**
|
||||
* Aborts on a {@code LF ('\n')}.
|
||||
*/
|
||||
ByteProcessor FIND_LF = new IndexOfProcessor((byte) '\n');
|
||||
|
||||
/**
|
||||
* Aborts on a non-{@code LF ('\n')}.
|
||||
*/
|
||||
ByteProcessor FIND_NON_LF = new IndexNotOfProcessor((byte) '\n');
|
||||
|
||||
/**
|
||||
* Aborts on a {@code CR ('\r')} or a {@code LF ('\n')}.
|
||||
*/
|
||||
ByteProcessor FIND_CRLF = new ByteProcessor() {
|
||||
@Override
|
||||
public boolean process(byte value) throws Exception {
|
||||
return value != '\r' && value != '\n';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Aborts on a byte which is neither a {@code CR ('\r')} nor a {@code LF ('\n')}.
|
||||
*/
|
||||
ByteProcessor FIND_NON_CRLF = new ByteProcessor() {
|
||||
@Override
|
||||
public boolean process(byte value) throws Exception {
|
||||
return value == '\r' || value == '\n';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Aborts on a linear whitespace (a ({@code ' '} or a {@code '\t'}).
|
||||
*/
|
||||
ByteProcessor FIND_LINEAR_WHITESPACE = new ByteProcessor() {
|
||||
@Override
|
||||
public boolean process(byte value) throws Exception {
|
||||
return value != ' ' && value != '\t';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Aborts on a byte which is not a linear whitespace (neither {@code ' '} nor {@code '\t'}).
|
||||
*/
|
||||
ByteProcessor FIND_NON_LINEAR_WHITESPACE = new ByteProcessor() {
|
||||
@Override
|
||||
public boolean process(byte value) throws Exception {
|
||||
return value == ' ' || value == '\t';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {@code true} if the processor wants to continue the loop and handle the next byte in the buffer.
|
||||
* {@code false} if the processor wants to stop handling bytes and abort the loop.
|
||||
*/
|
||||
boolean process(byte value) throws Exception;
|
||||
}
|
660
common/src/main/java/io/netty/util/ByteString.java
Normal file
660
common/src/main/java/io/netty/util/ByteString.java
Normal file
@ -0,0 +1,660 @@
|
||||
/*
|
||||
* Copyright 2015 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License, version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain a
|
||||
* copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package io.netty.util;
|
||||
|
||||
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* The primary use case for this class is to function as an immutable array of bytes. For performance reasons this
|
||||
* class supports sharing memory with external arrays, and also direct access to the underlying memory via
|
||||
* {@link #array()}. Care must be taken when directly accessing the memory as that may invalidate assumptions that
|
||||
* this object is immutable.
|
||||
*/
|
||||
public class ByteString {
|
||||
/**
|
||||
* A byte wise comparator between two {@link ByteString} objects.
|
||||
*/
|
||||
public static final Comparator<ByteString> DEFAULT_COMPARATOR = new Comparator<ByteString>() {
|
||||
@Override
|
||||
public int compare(ByteString o1, ByteString o2) {
|
||||
if (o1 == o2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int result;
|
||||
int length1 = o1.length();
|
||||
int length2 = o2.length();
|
||||
int minLength = Math.min(length1, length2);
|
||||
for (int i = 0, j = 0; j < minLength; i++, j++) {
|
||||
result = o1.value[i] - o2.value[j];
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return length1 - length2;
|
||||
}
|
||||
};
|
||||
public static final ByteString EMPTY_STRING = new ByteString(0);
|
||||
protected static final int HASH_CODE_PRIME = 31;
|
||||
|
||||
/**
|
||||
* If this value is modified outside the constructor then call {@link #arrayChanged()}.
|
||||
*/
|
||||
protected final byte[] value;
|
||||
/**
|
||||
* The hash code is cached after it is first computed. It can be reset with {@link #arrayChanged()}.
|
||||
*/
|
||||
private int hash;
|
||||
|
||||
/**
|
||||
* Used for classes which extend this class and want to initialize the {@link #value} array by them selves.
|
||||
*/
|
||||
ByteString(int length) { value = new byte[length]; }
|
||||
|
||||
/**
|
||||
* Initialize this byte string based upon a byte array. A copy will be made.
|
||||
*/
|
||||
public ByteString(byte[] value) {
|
||||
this(value, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this byte string based upon a byte array.
|
||||
* {@code copy} determines if a copy is made or the array is shared.
|
||||
*/
|
||||
public ByteString(byte[] value, boolean copy) {
|
||||
if (copy) {
|
||||
this.value = checkNotNull(value, "value").clone();
|
||||
} else {
|
||||
this.value = checkNotNull(value, "value");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this byte string based upon a range of a byte array. A copy will be made.
|
||||
*/
|
||||
public ByteString(byte[] value, int start, int length) {
|
||||
this(value, start, length, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new {@link BinaryString} object from a {@code byte[]} array.
|
||||
* @param copy {@code true} then a copy of the memory will be made. {@code false} the underlying memory
|
||||
* will be shared. If this shared memory changes then {@link #arrayChanged()} must be called.
|
||||
*/
|
||||
public ByteString(byte[] value, int start, int length, boolean copy) {
|
||||
if (start < 0 || start > checkNotNull(value, "value").length - length) {
|
||||
throw new IndexOutOfBoundsException("expected: " + "0 <= start(" + start + ") <= start + length(" + length
|
||||
+ ") <= " + "value.length(" + value.length + ')');
|
||||
}
|
||||
|
||||
if (copy || start != 0 || length != value.length) {
|
||||
this.value = Arrays.copyOfRange(value, start, start + length);
|
||||
} else {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of the underlying storage from {@link value}.
|
||||
* The copy will start at {@link ByteBuffer#position()} and copy {@link ByteBuffer#remaining()} bytes.
|
||||
*/
|
||||
public ByteString(ByteBuffer value) {
|
||||
this.value = getBytes(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of the underlying storage from {@link value}.
|
||||
* The copy will start at {@code start} and copy {@code length} bytes.
|
||||
*/
|
||||
public ByteString(ByteBuffer value, int start, int length) {
|
||||
this.value = getBytes(value, start, length, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a {@link ByteString} based upon the underlying storage from {@link value}.
|
||||
* The copy will start at {@code start} and copy {@code length} bytes.
|
||||
* if {@code copy} is true a copy will be made of the memory.
|
||||
* if {@code copy} is false the underlying storage will be shared, if possible.
|
||||
*/
|
||||
public ByteString(ByteBuffer value, int start, int length, boolean copy) {
|
||||
this.value = getBytes(value, start, length, copy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of {@link value} into a {@link ByteString} using the encoding type of {@code charset}.
|
||||
*/
|
||||
public ByteString(char[] value, Charset charset) {
|
||||
this.value = getBytes(value, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of {@link value} into a {@link ByteString} using the encoding type of {@code charset}.
|
||||
* The copy will start at index {@code start} and copy {@code length} bytes.
|
||||
*/
|
||||
public ByteString(char[] value, Charset charset, int start, int length) {
|
||||
this.value = getBytes(value, charset, start, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of {@link value} into a {@link ByteString} using the encoding type of {@code charset}.
|
||||
*/
|
||||
public ByteString(CharSequence value, Charset charset) {
|
||||
this.value = getBytes(value, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of {@link value} into a {@link ByteString} using the encoding type of {@code charset}.
|
||||
* The copy will start at index {@code start} and copy {@code length} bytes.
|
||||
*/
|
||||
public ByteString(CharSequence value, Charset charset, int start, int length) {
|
||||
this.value = getBytes(value, charset, start, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of the underlying storage from {@link value} into a byte array.
|
||||
* The copy will start at {@link ByteBuffer#position()} and copy {@link ByteBuffer#remaining()} bytes.
|
||||
*/
|
||||
private static byte[] getBytes(ByteBuffer value) {
|
||||
return getBytes(value, value.position(), checkNotNull(value, "value").remaining());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of the underlying storage from {@link value} into a byte array.
|
||||
* The copy will start at {@code start} and copy {@code length} bytes.
|
||||
*/
|
||||
private static byte[] getBytes(ByteBuffer value, int start, int length) {
|
||||
return getBytes(value, start, length, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of the underlying storage from {@link value} into a byte array.
|
||||
* The copy will start at {@code start} and copy {@code length} bytes.
|
||||
* if {@code copy} is true a copy will be made of the memory.
|
||||
* if {@code copy} is false the underlying storage will be shared, if possible.
|
||||
*/
|
||||
private static byte[] getBytes(ByteBuffer value, int start, int length, boolean copy) {
|
||||
if (start < 0 || length > checkNotNull(value, "value").capacity() - start) {
|
||||
throw new IndexOutOfBoundsException("expected: " + "0 <= start(" + start + ") <= start + length(" + length
|
||||
+ ") <= " + "value.capacity(" + value.capacity() + ')');
|
||||
}
|
||||
|
||||
if (value.hasArray()) {
|
||||
if (copy || start != 0 || length != value.capacity()) {
|
||||
int baseOffset = value.arrayOffset() + start;
|
||||
return Arrays.copyOfRange(value.array(), baseOffset, baseOffset + length);
|
||||
} else {
|
||||
return value.array();
|
||||
}
|
||||
}
|
||||
|
||||
byte[] v = new byte[length];
|
||||
int oldPos = value.position();
|
||||
value.get(v, 0, length);
|
||||
value.position(oldPos);
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of {@link value} into a byte array using the encoding type of {@code charset}.
|
||||
*/
|
||||
private static byte[] getBytes(char[] value, Charset charset) {
|
||||
return getBytes(value, charset, 0, checkNotNull(value, "value").length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of {@link value} into a byte array using the encoding type of {@code charset}.
|
||||
* The copy will start at index {@code start} and copy {@code length} bytes.
|
||||
*/
|
||||
private static byte[] getBytes(char[] value, Charset charset, int start, int length) {
|
||||
if (start < 0 || length > checkNotNull(value, "value").length - start) {
|
||||
throw new IndexOutOfBoundsException("expected: " + "0 <= start(" + start + ") <= start + length(" + length
|
||||
+ ") <= " + "length(" + length + ')');
|
||||
}
|
||||
|
||||
CharBuffer cbuf = CharBuffer.wrap(value, start, start + length);
|
||||
CharsetEncoder encoder = CharsetUtil.getEncoder(charset);
|
||||
ByteBuffer nativeBuffer = ByteBuffer.allocate((int) (encoder.maxBytesPerChar() * length));
|
||||
encoder.encode(cbuf, nativeBuffer, true);
|
||||
final int offset = nativeBuffer.arrayOffset();
|
||||
return Arrays.copyOfRange(nativeBuffer.array(), offset, offset + nativeBuffer.position());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of {@link value} into a byte array using the encoding type of {@code charset}.
|
||||
*/
|
||||
private static byte[] getBytes(CharSequence value, Charset charset) {
|
||||
return getBytes(value, charset, 0, checkNotNull(value, "value").length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of {@link value} into a byte array using the encoding type of {@code charset}.
|
||||
* The copy will start at index {@code start} and copy {@code length} bytes.
|
||||
*/
|
||||
private static byte[] getBytes(CharSequence value, Charset charset, int start, int length) {
|
||||
if (start < 0 || length > checkNotNull(value, "value").length() - start) {
|
||||
throw new IndexOutOfBoundsException("expected: " + "0 <= start(" + start + ") <= start + length(" + length
|
||||
+ ") <= " + "length(" + value.length() + ')');
|
||||
}
|
||||
|
||||
CharBuffer cbuf = CharBuffer.wrap(value, start, start + length);
|
||||
CharsetEncoder encoder = CharsetUtil.getEncoder(charset);
|
||||
ByteBuffer nativeBuffer = ByteBuffer.allocate((int) (encoder.maxBytesPerChar() * length));
|
||||
encoder.encode(cbuf, nativeBuffer, true);
|
||||
final int offset = nativeBuffer.arrayOffset();
|
||||
return Arrays.copyOfRange(nativeBuffer.array(), offset, offset + nativeBuffer.position());
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over the readable bytes of this buffer with the specified {@code processor} in ascending order.
|
||||
*
|
||||
* @return {@code -1} if the processor iterated to or beyond the end of the readable bytes.
|
||||
* The last-visited index If the {@link ByteProcessor#process(byte)} returned {@code false}.
|
||||
*/
|
||||
public final int forEachByte(ByteProcessor visitor) throws Exception {
|
||||
return forEachByte(0, value.length, visitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over the specified area of this buffer with the specified {@code processor} in ascending order.
|
||||
* (i.e. {@code index}, {@code (index + 1)}, .. {@code (index + length - 1)}).
|
||||
*
|
||||
* @return {@code -1} if the processor iterated to or beyond the end of the specified area.
|
||||
* The last-visited index If the {@link ByteProcessor#process(byte)} returned {@code false}.
|
||||
*/
|
||||
public final int forEachByte(int index, int length, ByteProcessor visitor) throws Exception {
|
||||
if (index < 0 || length > value.length - index) {
|
||||
throw new IndexOutOfBoundsException("expected: " + "0 <= index(" + index + ") <= start + length(" + length
|
||||
+ ") <= " + "length(" + value.length + ')');
|
||||
}
|
||||
|
||||
for (int i = index; i < length; ++i) {
|
||||
if (!visitor.process(value[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over the readable bytes of this buffer with the specified {@code processor} in descending order.
|
||||
*
|
||||
* @return {@code -1} if the processor iterated to or beyond the beginning of the readable bytes.
|
||||
* The last-visited index If the {@link ByteProcessor#process(byte)} returned {@code false}.
|
||||
*/
|
||||
public final int forEachByteDesc(ByteProcessor visitor) throws Exception {
|
||||
return forEachByteDesc(0, length(), visitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over the specified area of this buffer with the specified {@code processor} in descending order.
|
||||
* (i.e. {@code (index + length - 1)}, {@code (index + length - 2)}, ... {@code index}).
|
||||
*
|
||||
* @return {@code -1} if the processor iterated to or beyond the beginning of the specified area.
|
||||
* The last-visited index If the {@link ByteProcessor#process(byte)} returned {@code false}.
|
||||
*/
|
||||
public final int forEachByteDesc(int index, int length, ByteProcessor visitor) throws Exception {
|
||||
if (index < 0 || length > value.length - index) {
|
||||
throw new IndexOutOfBoundsException("expected: " + "0 <= index(" + index + ") <= start + length(" + length
|
||||
+ ") <= " + "length(" + value.length + ')');
|
||||
}
|
||||
|
||||
for (int i = index + length - 1; i >= index; --i) {
|
||||
if (!visitor.process(value[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public final byte byteAt(int index) {
|
||||
return value[index];
|
||||
}
|
||||
|
||||
public final boolean isEmpty() {
|
||||
return value.length == 0;
|
||||
}
|
||||
|
||||
public final int length() {
|
||||
return value.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* During normal use cases the {@link ByteString} should be immutable, but if the underlying array is shared,
|
||||
* and changes then this needs to be called.
|
||||
*/
|
||||
public final void arrayChanged() {
|
||||
hash = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This gives direct access to the underlying storage array.
|
||||
* The {@link #toByteArray()} should be preferred over this method.
|
||||
* If the return value is changed then {@link #arrayChanged()} must be called.
|
||||
*/
|
||||
public final byte[] array() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this string to a byte array.
|
||||
*/
|
||||
public final byte[] toByteArray() {
|
||||
return toByteArray(0, length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a subset of this string to a byte array.
|
||||
* The subset is defined by the range [{@code start}, {@code end}).
|
||||
*/
|
||||
public final byte[] toByteArray(int start, int end) {
|
||||
return Arrays.copyOfRange(value, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the content of this string to a byte array.
|
||||
*
|
||||
* @param srcIdx the starting offset of characters to copy.
|
||||
* @param dst the destination byte array.
|
||||
* @param dstIdx the starting offset in the destination byte array.
|
||||
* @param length the number of characters to copy.
|
||||
*/
|
||||
public final void copy(int srcIdx, byte[] dst, int dstIdx, int length) {
|
||||
final int thisLen = value.length;
|
||||
|
||||
if (srcIdx < 0 || length > thisLen - srcIdx) {
|
||||
throw new IndexOutOfBoundsException("expected: " + "0 <= srcIdx(" + srcIdx + ") <= srcIdx + length("
|
||||
+ length + ") <= srcLen(" + thisLen + ')');
|
||||
}
|
||||
|
||||
System.arraycopy(value, srcIdx, checkNotNull(dst, "dst"), dstIdx, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
if (hash != 0) {
|
||||
return hash;
|
||||
}
|
||||
|
||||
for (int i = 0; i < value.length; ++i) {
|
||||
hash = hash * HASH_CODE_PRIME ^ value[i] & HASH_CODE_PRIME;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies a range of characters into a new string.
|
||||
*
|
||||
* @param start the offset of the first character.
|
||||
* @return a new string containing the characters from start to the end of the string.
|
||||
* @throws IndexOutOfBoundsException if {@code start < 0} or {@code start > length()}.
|
||||
*/
|
||||
public final ByteString subSequence(int start) {
|
||||
return subSequence(start, length());
|
||||
}
|
||||
|
||||
public ByteString subSequence(int start, int end) {
|
||||
if (start < 0 || start > end || end > length()) {
|
||||
throw new IndexOutOfBoundsException("expected: 0 <= start(" + start + ") <= end (" + end + ") <= length("
|
||||
+ length() + ')');
|
||||
}
|
||||
|
||||
if (start == 0 && end == value.length) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (end == start) {
|
||||
return EMPTY_STRING;
|
||||
}
|
||||
|
||||
return new ByteString(value, start, end - start, false);
|
||||
}
|
||||
|
||||
public final int parseAsciiInt() {
|
||||
return parseAsciiInt(0, length(), 10);
|
||||
}
|
||||
|
||||
public final int parseAsciiInt(int radix) {
|
||||
return parseAsciiInt(0, length(), radix);
|
||||
}
|
||||
|
||||
public final int parseAsciiInt(int start, int end) {
|
||||
return parseAsciiInt(start, end, 10);
|
||||
}
|
||||
|
||||
public final int parseAsciiInt(int start, int end, int radix) {
|
||||
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
|
||||
throw new NumberFormatException();
|
||||
}
|
||||
|
||||
if (start == end) {
|
||||
throw new NumberFormatException();
|
||||
}
|
||||
|
||||
int i = start;
|
||||
boolean negative = byteAt(i) == '-';
|
||||
if (negative && ++i == end) {
|
||||
throw new NumberFormatException(subSequence(start, end).toString());
|
||||
}
|
||||
|
||||
return parseAsciiInt(i, end, radix, negative);
|
||||
}
|
||||
|
||||
private int parseAsciiInt(int start, int end, int radix, boolean negative) {
|
||||
int max = Integer.MIN_VALUE / radix;
|
||||
int result = 0;
|
||||
int offset = start;
|
||||
while (offset < end) {
|
||||
int digit = Character.digit((char) (value[offset++] & 0xFF), radix);
|
||||
if (digit == -1) {
|
||||
throw new NumberFormatException(subSequence(start, end).toString());
|
||||
}
|
||||
if (max > result) {
|
||||
throw new NumberFormatException(subSequence(start, end).toString());
|
||||
}
|
||||
int next = result * radix - digit;
|
||||
if (next > result) {
|
||||
throw new NumberFormatException(subSequence(start, end).toString());
|
||||
}
|
||||
result = next;
|
||||
}
|
||||
if (!negative) {
|
||||
result = -result;
|
||||
if (result < 0) {
|
||||
throw new NumberFormatException(subSequence(start, end).toString());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public final long parseAsciiLong() {
|
||||
return parseAsciiLong(0, length(), 10);
|
||||
}
|
||||
|
||||
public final long parseAsciiLong(int radix) {
|
||||
return parseAsciiLong(0, length(), radix);
|
||||
}
|
||||
|
||||
public final long parseAsciiLong(int start, int end) {
|
||||
return parseAsciiLong(start, end, 10);
|
||||
}
|
||||
|
||||
public final long parseAsciiLong(int start, int end, int radix) {
|
||||
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
|
||||
throw new NumberFormatException();
|
||||
}
|
||||
|
||||
if (start == end) {
|
||||
throw new NumberFormatException();
|
||||
}
|
||||
|
||||
int i = start;
|
||||
boolean negative = byteAt(i) == '-';
|
||||
if (negative && ++i == end) {
|
||||
throw new NumberFormatException(subSequence(start, end).toString());
|
||||
}
|
||||
|
||||
return parseAsciiLong(i, end, radix, negative);
|
||||
}
|
||||
|
||||
private long parseAsciiLong(int start, int end, int radix, boolean negative) {
|
||||
long max = Long.MIN_VALUE / radix;
|
||||
long result = 0;
|
||||
int offset = start;
|
||||
while (offset < end) {
|
||||
int digit = Character.digit((char) (value[offset++] & 0xFF), radix);
|
||||
if (digit == -1) {
|
||||
throw new NumberFormatException(subSequence(start, end).toString());
|
||||
}
|
||||
if (max > result) {
|
||||
throw new NumberFormatException(subSequence(start, end).toString());
|
||||
}
|
||||
long next = result * radix - digit;
|
||||
if (next > result) {
|
||||
throw new NumberFormatException(subSequence(start, end).toString());
|
||||
}
|
||||
result = next;
|
||||
}
|
||||
if (!negative) {
|
||||
result = -result;
|
||||
if (result < 0) {
|
||||
throw new NumberFormatException(subSequence(start, end).toString());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public final char parseChar() {
|
||||
return parseChar(0);
|
||||
}
|
||||
|
||||
public char parseChar(int start) {
|
||||
if (start + 1 >= value.length) {
|
||||
throw new IndexOutOfBoundsException("2 bytes required to convert to character. index " +
|
||||
start + " would go out of bounds.");
|
||||
}
|
||||
return (char) (((value[start] & 0xFF) << 8) | (value[start + 1] & 0xFF));
|
||||
}
|
||||
|
||||
public final short parseAsciiShort() {
|
||||
return parseAsciiShort(0, length(), 10);
|
||||
}
|
||||
|
||||
public final short parseAsciiShort(int radix) {
|
||||
return parseAsciiShort(0, length(), radix);
|
||||
}
|
||||
|
||||
public final short parseAsciiShort(int start, int end) {
|
||||
return parseAsciiShort(start, end, 10);
|
||||
}
|
||||
|
||||
public final short parseAsciiShort(int start, int end, int radix) {
|
||||
int intValue = parseAsciiInt(start, end, radix);
|
||||
short result = (short) intValue;
|
||||
if (result != intValue) {
|
||||
throw new NumberFormatException(subSequence(start, end).toString());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public final float parseAsciiFloat() {
|
||||
return parseAsciiFloat(0, length());
|
||||
}
|
||||
|
||||
public final float parseAsciiFloat(int start, int end) {
|
||||
return Float.parseFloat(toString(start, end));
|
||||
}
|
||||
|
||||
public final double parseAsciiDouble() {
|
||||
return parseAsciiDouble(0, length());
|
||||
}
|
||||
|
||||
public final double parseAsciiDouble(int start, int end) {
|
||||
return Double.parseDouble(toString(start, end));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof ByteString)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ByteString that = (ByteString) obj;
|
||||
if (length() != that.length() || hashCode() != that.hashCode()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int end = value.length;
|
||||
for (int i = 0, j = 0; i < end; i++, j++) {
|
||||
if (value[i] != that.value[j]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the entire byte string to a {@link String}.
|
||||
* @see {@link #toString(int, int)}
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(0, length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the entire byte string to a {@link String} using the {@code charset} encoding.
|
||||
* @see {@link #toString(Charset, int, int)}
|
||||
*/
|
||||
public final String toString(Charset charset) {
|
||||
return toString(charset, 0, length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the [{@code start}, {@code end}) range of this byte string to a {@link String}.
|
||||
* @see {@link #toString(Charset, int, int)}
|
||||
*/
|
||||
public final String toString(int start, int end) {
|
||||
return toString(CharsetUtil.ISO_8859_1, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the [{@code start}, {@code end}) range of this byte string to a {@link String}
|
||||
* using the {@code charset} encoding.
|
||||
*/
|
||||
public String toString(Charset charset, int start, int end) {
|
||||
int length = end - start;
|
||||
if (length == 0) {
|
||||
return StringUtil.EMPTY_STRING;
|
||||
}
|
||||
|
||||
return new String(value, start, length, charset);
|
||||
}
|
||||
}
|
@ -34,6 +34,7 @@ public final class StringUtil {
|
||||
public static final char LINE_FEED = '\n';
|
||||
public static final char CARRIAGE_RETURN = '\r';
|
||||
public static final String EMPTY_STRING = "";
|
||||
public static final byte UPPER_CASE_TO_LOWER_CASE_ASCII_OFFSET = (int) 'a' - (int) 'A';
|
||||
private static final String[] BYTE2HEX_PAD = new String[256];
|
||||
private static final String[] BYTE2HEX_NOPAD = new String[256];
|
||||
/**
|
||||
|
@ -13,15 +13,11 @@
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.handler.codec;
|
||||
package io.netty.util;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
@ -41,8 +37,8 @@ public class AsciiStringTest {
|
||||
final Charset[] charsets = CharsetUtil.values();
|
||||
for (int i = 0; i < charsets.length; ++i) {
|
||||
final Charset charset = charsets[i];
|
||||
byte[] expected = getBytesWithEncoder(bString, charset);
|
||||
byte[] actual = AsciiString.getBytes(b, charset);
|
||||
byte[] expected = bString.getBytes(charset);
|
||||
byte[] actual = new ByteString(b, charset).toByteArray();
|
||||
assertArrayEquals("failure for " + charset, expected, actual);
|
||||
}
|
||||
}
|
||||
@ -58,7 +54,7 @@ public class AsciiStringTest {
|
||||
for (int i = 0; i < charsets.length; ++i) {
|
||||
final Charset charset = charsets[i];
|
||||
byte[] expected = bString.getBytes(charset);
|
||||
byte[] actual = AsciiString.getBytes(bString, charset);
|
||||
byte[] actual = new ByteString(bString, charset).toByteArray();
|
||||
assertArrayEquals("failure for " + charset, expected, actual);
|
||||
}
|
||||
}
|
||||
@ -72,12 +68,8 @@ public class AsciiStringTest {
|
||||
final String bString = b.toString();
|
||||
// The AsciiString class actually limits the Charset to ISO_8859_1
|
||||
byte[] expected = bString.getBytes(CharsetUtil.ISO_8859_1);
|
||||
final Charset[] charsets = CharsetUtil.values();
|
||||
for (int i = 0; i < charsets.length; ++i) {
|
||||
final Charset charset = charsets[i];
|
||||
byte[] actual = AsciiString.getBytes(new AsciiString(bString), charset);
|
||||
assertArrayEquals("failure for " + charset, expected, actual);
|
||||
}
|
||||
byte[] actual = new AsciiString(bString).toByteArray();
|
||||
assertArrayEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -86,11 +78,4 @@ public class AsciiStringTest {
|
||||
AsciiString ascii = new AsciiString(string.toCharArray());
|
||||
Assert.assertEquals(string, ascii.toString());
|
||||
}
|
||||
|
||||
private static byte[] getBytesWithEncoder(CharSequence value, Charset charset) {
|
||||
final CharsetEncoder encoder = CharsetUtil.getEncoder(charset);
|
||||
final ByteBuffer nativeBuffer = ByteBuffer.allocate((int) (encoder.maxBytesPerChar() * value.length()));
|
||||
encoder.encode(CharBuffer.wrap(value), nativeBuffer, true);
|
||||
return nativeBuffer.array();
|
||||
}
|
||||
}
|
@ -15,6 +15,12 @@
|
||||
*/
|
||||
package io.netty.example.http.helloworld;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.CONNECTION;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
|
||||
import static io.netty.handler.codec.http.HttpResponseStatus.CONTINUE;
|
||||
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
|
||||
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerAdapter;
|
||||
@ -25,10 +31,6 @@ import io.netty.handler.codec.http.HttpHeaderUtil;
|
||||
import io.netty.handler.codec.http.HttpHeaderValues;
|
||||
import io.netty.handler.codec.http.HttpRequest;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.*;
|
||||
import static io.netty.handler.codec.http.HttpResponseStatus.*;
|
||||
import static io.netty.handler.codec.http.HttpVersion.*;
|
||||
|
||||
|
||||
public class HttpHelloWorldServerHandler extends ChannelHandlerAdapter {
|
||||
private static final byte[] CONTENT = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' };
|
||||
|
@ -22,7 +22,6 @@ import static io.netty.handler.codec.http.HttpResponseStatus.OK;
|
||||
import static io.netty.handler.logging.LogLevel.INFO;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.http.HttpServerUpgradeHandler;
|
||||
import io.netty.handler.codec.http2.DefaultHttp2Connection;
|
||||
import io.netty.handler.codec.http2.DefaultHttp2FrameReader;
|
||||
@ -39,6 +38,7 @@ import io.netty.handler.codec.http2.Http2FrameWriter;
|
||||
import io.netty.handler.codec.http2.Http2Headers;
|
||||
import io.netty.handler.codec.http2.Http2InboundFrameLogger;
|
||||
import io.netty.handler.codec.http2.Http2OutboundFrameLogger;
|
||||
import io.netty.util.AsciiString;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
/**
|
||||
|
@ -20,7 +20,6 @@ import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.base64.Base64;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
@ -31,6 +30,7 @@ import io.netty.handler.codec.http.HttpResponse;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import io.netty.handler.codec.http.LastHttpContent;
|
||||
import io.netty.util.AsciiString;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
Loading…
Reference in New Issue
Block a user