下面列出了怎么用io.netty.util.internal.AppendableCharSequence的API类实例代码及写法,或者点击链接到github查看源代码。
protected HttpObjectDecoder(
int maxInitialLineLength, int maxHeaderSize, int maxChunkSize,
boolean chunkedSupported, boolean validateHeaders, int initialBufferSize) {
if (maxInitialLineLength <= 0) {
throw new IllegalArgumentException(
"maxInitialLineLength must be a positive integer: " +
maxInitialLineLength);
}
if (maxHeaderSize <= 0) {
throw new IllegalArgumentException(
"maxHeaderSize must be a positive integer: " +
maxHeaderSize);
}
if (maxChunkSize <= 0) {
throw new IllegalArgumentException(
"maxChunkSize must be a positive integer: " +
maxChunkSize);
}
AppendableCharSequence seq = new AppendableCharSequence(initialBufferSize);
lineParser = new LineParser(seq, maxInitialLineLength);
headerParser = new HeaderParser(seq, maxHeaderSize);
this.maxChunkSize = maxChunkSize;
this.chunkedSupported = chunkedSupported;
this.validateHeaders = validateHeaders;
}
private static String[] splitInitialLine(AppendableCharSequence sb) {
int aStart;
int aEnd;
int bStart;
int bEnd;
int cStart;
int cEnd;
aStart = findNonWhitespace(sb, 0);
aEnd = findWhitespace(sb, aStart);
bStart = findNonWhitespace(sb, aEnd);
bEnd = findWhitespace(sb, bStart);
cStart = findNonWhitespace(sb, bEnd);
cEnd = findEndOfString(sb);
return new String[] {
sb.subStringUnsafe(aStart, aEnd),
sb.subStringUnsafe(bStart, bEnd),
cStart < cEnd? sb.subStringUnsafe(cStart, cEnd) : "" };
}
private String readLine(ByteBuf buffer, int initialBufferSize) {
AppendableCharSequence buf = new AppendableCharSequence(initialBufferSize);
int lineLength = 0;
for (;;) {
byte nextByte = buffer.readByte();
if (nextByte == StompConstants.CR) {
//do nothing
} else if (nextByte == StompConstants.LF) {
return buf.toString();
} else {
if (lineLength >= maxLineLength) {
invalidLineLength();
}
lineLength ++;
buf.append((char) nextByte);
}
}
}
private static String[] splitInitialLine(AppendableCharSequence sb) {
int aStart;
int aEnd;
int bStart;
int bEnd;
int cStart;
int cEnd;
aStart = findNonWhitespace(sb, 0);
aEnd = findWhitespace(sb, aStart);
bStart = findNonWhitespace(sb, aEnd);
bEnd = findWhitespace(sb, bStart);
cStart = findNonWhitespace(sb, bEnd);
cEnd = findEndOfString(sb);
return new String[] {
sb.subStringUnsafe(aStart, aEnd),
sb.subStringUnsafe(bStart, bEnd),
cStart < cEnd? sb.subStringUnsafe(cStart, cEnd) : "" };
}
@Override
public Integer parse(ByteBuf in) {
AppendableCharSequence seq = sequenceRef.get();
seq.reset();
boolean foundStart = false;
for (;;) {
char c = ((char) in.readUnsignedByte());
if (c == '{') {
foundStart = true;
} else if (c == '}') {
return Integer.parseInt(seq.toString());
} else if (foundStart) {
seq.append(c);
}
}
}
private static String[] splitInitialLine(AppendableCharSequence sb) {
int aStart;
int aEnd;
int bStart;
int bEnd;
int cStart;
int cEnd;
aStart = findNonWhitespace(sb, 0);
aEnd = findWhitespace(sb, aStart);
bStart = findNonWhitespace(sb, aEnd);
bEnd = findWhitespace(sb, bStart);
cStart = findNonWhitespace(sb, bEnd);
cEnd = findEndOfString(sb);
return new String[] {
sb.substring(aStart, aEnd),
sb.substring(bStart, bEnd),
cStart < cEnd? sb.substring(cStart, cEnd) : "" };
}
private void splitHeader(AppendableCharSequence sb) {
final int length = sb.length();
int nameStart;
int nameEnd;
int colonEnd;
int valueStart;
int valueEnd;
nameStart = findNonWhitespace(sb, 0);
for (nameEnd = nameStart; nameEnd < length; nameEnd ++) {
char ch = sb.charAt(nameEnd);
if (ch == ':' || Character.isWhitespace(ch)) {
break;
}
}
for (colonEnd = nameEnd; colonEnd < length; colonEnd ++) {
if (sb.charAt(colonEnd) == ':') {
colonEnd ++;
break;
}
}
name = sb.subStringUnsafe(nameStart, nameEnd);
valueStart = findNonWhitespace(sb, colonEnd);
if (valueStart == length) {
value = EMPTY_VALUE;
} else {
valueEnd = findEndOfString(sb);
value = sb.subStringUnsafe(valueStart, valueEnd);
}
}
private static int findNonWhitespace(AppendableCharSequence sb, int offset) {
for (int result = offset; result < sb.length(); ++result) {
if (!Character.isWhitespace(sb.charAtUnsafe(result))) {
return result;
}
}
return sb.length();
}
private static int findWhitespace(AppendableCharSequence sb, int offset) {
for (int result = offset; result < sb.length(); ++result) {
if (Character.isWhitespace(sb.charAtUnsafe(result))) {
return result;
}
}
return sb.length();
}
private static int findEndOfString(AppendableCharSequence sb) {
for (int result = sb.length() - 1; result > 0; --result) {
if (!Character.isWhitespace(sb.charAtUnsafe(result))) {
return result + 1;
}
}
return 0;
}
public AppendableCharSequence parse(ByteBuf buffer) {
final int oldSize = size;
seq.reset();
int i = buffer.forEachByte(this);
if (i == -1) {
size = oldSize;
return null;
}
buffer.readerIndex(i + 1);
return seq;
}
private State readHeaders(ByteBuf buffer, StompHeaders headers) {
AppendableCharSequence buf = new AppendableCharSequence(128);
for (;;) {
boolean headerRead = readHeader(headers, buf, buffer);
if (!headerRead) {
if (headers.contains(StompHeaders.CONTENT_LENGTH)) {
contentLength = getContentLength(headers, 0);
if (contentLength == 0) {
return State.FINALIZE_FRAME_READ;
}
}
return State.READ_CONTENT;
}
}
}
private boolean readHeader(StompHeaders headers, AppendableCharSequence buf, ByteBuf buffer) {
buf.reset();
int lineLength = 0;
String key = null;
boolean valid = false;
for (;;) {
byte nextByte = buffer.readByte();
if (nextByte == StompConstants.COLON && key == null) {
key = buf.toString();
valid = true;
buf.reset();
} else if (nextByte == StompConstants.CR) {
//do nothing
} else if (nextByte == StompConstants.LF) {
if (key == null && lineLength == 0) {
return false;
} else if (valid) {
headers.add(key, buf.toString());
} else if (validateHeaders) {
invalidHeader(key, buf.toString());
}
return true;
} else {
if (lineLength >= maxLineLength) {
invalidLineLength();
}
if (nextByte == StompConstants.COLON && key != null) {
valid = false;
}
lineLength ++;
buf.append((char) nextByte);
}
}
}
@Override
public boolean isSupport(ByteBuf buffer) {
// from netty protocol implement
if (isNativeMqtt(buffer)) {
return false;
}
if (!skipControlCharacters(buffer)) {
return false;
}
int rIdx = buffer.readerIndex();
LineParser lineParser = new LineParser(new AppendableCharSequence(65536), 4096);
AppendableCharSequence line = lineParser.parse(buffer);
String[] initialLine = splitInitialLine(line);
if (initialLine.length < 3) {
return false;
}
Map<String, String> headers = readHeaders(buffer);
buffer.readerIndex(rIdx);
if (!headers.containsKey("Connection") && !headers.get("Connection").equals("Upgrade")) {
return false;
}
if (!headers.containsKey("Upgrade") && !headers.get("Upgrade").equals("websocket")) {
return false;
}
if (!headers.containsKey("Sec-WebSocket-Protocol") && !headers.get("Sec-WebSocket-Protocol").equals("mqtt")) {
return false;
}
return true;
}
private static int findNonWhitespace(AppendableCharSequence sb, int offset) {
for (int result = offset; result < sb.length(); ++result) {
if (!Character.isWhitespace(sb.charAtUnsafe(result))) {
return result;
}
}
return sb.length();
}
private static int findWhitespace(AppendableCharSequence sb, int offset) {
for (int result = offset; result < sb.length(); ++result) {
if (Character.isWhitespace(sb.charAtUnsafe(result))) {
return result;
}
}
return sb.length();
}
private static int findEndOfString(AppendableCharSequence sb) {
for (int result = sb.length() - 1; result > 0; --result) {
if (!Character.isWhitespace(sb.charAtUnsafe(result))) {
return result + 1;
}
}
return 0;
}
public AppendableCharSequence parse(ByteBuf buffer) {
final int oldSize = size;
seq.reset();
int i = buffer.forEachByte(this);
if (i == -1) {
size = oldSize;
return null;
}
buffer.readerIndex(i + 1);
return seq;
}
public AppendableCharSequence get() {
AppendableCharSequence sequence = reference.get();
if (sequence == null) {
sequence = newCharSeq();
}
reference = new SoftReference<>(sequence);
return sequence;
}
@Override
public String parse(ByteBuf in) {
AppendableCharSequence seq = sequenceRef.get();
seq.reset();
size = 0;
expectedSize = -1;
for (;;) {
char c = ((char) in.readUnsignedByte());
if (c == '{' && expectedSize < 0) {
in.readerIndex(in.readerIndex() - 1);
expectedSize = sizeParser.parse(in);
in.readerIndex(in.readerIndex() + 2); // Skip CRLF
} else if (expectedSize >= 0) {
seq.reset();
seq.append(c);
size++;
while (size < expectedSize) {
c = ((char) in.readUnsignedByte());
seq.append(c);
size++;
}
return seq.toString();
} else if (Character.isWhitespace(c)) {
continue;
} else {
in.readerIndex(in.readerIndex() - 1);
return stringParser.parse(in);
}
}
}
@Override
public String parse(ByteBuf buffer) {
AppendableCharSequence sequence = sequenceReference.get();
int readerIndex = buffer.readerIndex();
try {
super.parse(buffer);
} catch (Signal e) {
e.expect(REPLAYING_SIGNAL);
buffer.readerIndex(readerIndex + size);
return sequence.toString();
}
return sequence.toString();
}
/**
* See https://tools.ietf.org/html/rfc3501.html#section-4.3
*
* String literals have the form
*
* {10}
* abcdefghij
*
* Where {10} represents the length of the string literal. The literal
* begins after any CLRF characters following the '}' character.
*/
private String parseLiteral(ByteBuf buffer, AppendableCharSequence seq) {
int length = 0;
char c = (char) buffer.readUnsignedByte();
while (c != '}') {
if (Character.isDigit(c)) {
int digit = Character.digit(c, 10);
length = (length * 10) + digit;
c = (char) buffer.readUnsignedByte();
} else {
throw new DecoderException(
String.format("Found non-digit character %c where a digit was expected", c)
);
}
}
if (length > 0) {
//ignore crlf characters after '}'
c = (char) buffer.readUnsignedByte();
while (isCRLFCharacter(c)) {
c = (char) buffer.readUnsignedByte();
}
append(seq, c);
append(seq, buffer, length);
return seq.toString();
} else {
return "";
}
}
private void append(AppendableCharSequence seq, char c) {
if (size >= maxStringLength) {
throw new TooLongFrameException("String is larger than " + maxStringLength + " bytes.");
}
size++;
seq.append(c);
}
private void append(AppendableCharSequence seq, ByteBuf buffer, int length) {
if (size + length >= maxStringLength) {
throw new TooLongFrameException("String is larger than " + maxStringLength + " bytes.");
}
size += length;
seq.append(buffer.readCharSequence(length - 1, StandardCharsets.UTF_8));
}
@Override
public String parse(ByteBuf in) {
AppendableCharSequence seq = sequenceRef.get();
seq.reset();
size = 0;
for (;;) {
char nextByte = (char) in.readUnsignedByte();
if (Character.isWhitespace(nextByte)) {
if (size > 0) {
break;
}
} else if (!Character.isLetterOrDigit(nextByte) && nextByte != '.' && nextByte != '-') {
in.readerIndex(in.readerIndex() - 1);
break;
} else {
if (size >= maxWordLength) {
throw new TooLongFrameException(
"Word is larger than " + maxWordLength +
" bytes.");
}
size++;
seq.append(nextByte);
}
}
return seq.toString();
}
/**
* Creates a new instance with the specified parameters.
*/
protected HttpObjectDecoder(
int maxInitialLineLength, int maxHeaderSize, int maxChunkSize,
boolean chunkedSupported, boolean validateHeaders) {
if (maxInitialLineLength <= 0) {
throw new IllegalArgumentException(
"maxInitialLineLength must be a positive integer: " +
maxInitialLineLength);
}
if (maxHeaderSize <= 0) {
throw new IllegalArgumentException(
"maxHeaderSize must be a positive integer: " +
maxHeaderSize);
}
if (maxChunkSize <= 0) {
throw new IllegalArgumentException(
"maxChunkSize must be a positive integer: " +
maxChunkSize);
}
this.maxChunkSize = maxChunkSize;
this.chunkedSupported = chunkedSupported;
this.validateHeaders = validateHeaders;
AppendableCharSequence seq = new AppendableCharSequence(128);
lineParser = new LineParser(seq, maxInitialLineLength);
headerParser = new HeaderParser(seq, maxHeaderSize);
}
private void splitHeader(AppendableCharSequence sb) {
final int length = sb.length();
int nameStart;
int nameEnd;
int colonEnd;
int valueStart;
int valueEnd;
nameStart = findNonWhitespace(sb, 0);
for (nameEnd = nameStart; nameEnd < length; nameEnd ++) {
char ch = sb.charAt(nameEnd);
if (ch == ':' || Character.isWhitespace(ch)) {
break;
}
}
for (colonEnd = nameEnd; colonEnd < length; colonEnd ++) {
if (sb.charAt(colonEnd) == ':') {
colonEnd ++;
break;
}
}
name = sb.substring(nameStart, nameEnd);
valueStart = findNonWhitespace(sb, colonEnd);
if (valueStart == length) {
value = EMPTY_VALUE;
} else {
valueEnd = findEndOfString(sb);
value = sb.substring(valueStart, valueEnd);
}
}
public AppendableCharSequence parse(ByteBuf buffer) {
final int oldSize = size;
seq.reset();
int i = buffer.forEachByte(this);
if (i == -1) {
size = oldSize;
return null;
}
buffer.readerIndex(i + 1);
return seq;
}
private State readHeaders(ByteBuf buffer) {
final HttpMessage message = this.message;
final HttpHeaders headers = message.headers();
AppendableCharSequence line = headerParser.parse(buffer);
if (line == null) {
return null;
}
if (line.length() > 0) {
do {
char firstChar = line.charAt(0);
if (name != null && (firstChar == ' ' || firstChar == '\t')) {
//please do not make one line from below code
//as it breaks +XX:OptimizeStringConcat optimization//请不要从下面的代码中写一行
//当它中断时+XX:OptimizeStringConcat优化
String trimmedLine = line.toString().trim();
String valueStr = String.valueOf(value);
value = valueStr + ' ' + trimmedLine;
} else {
if (name != null) {
headers.add(name, value);
}
splitHeader(line);
}
line = headerParser.parse(buffer);
if (line == null) {
return null;
}
} while (line.length() > 0);
}
// Add the last header.
if (name != null) {
headers.add(name, value);
}
// reset name and value fields
name = null;
value = null;
State nextState;
if (isContentAlwaysEmpty(message)) {
HttpUtil.setTransferEncodingChunked(message, false);
nextState = State.SKIP_CONTROL_CHARS;
} else if (HttpUtil.isTransferEncodingChunked(message)) {
nextState = State.READ_CHUNK_SIZE;
} else if (contentLength() >= 0) {
nextState = State.READ_FIXED_LENGTH_CONTENT;
} else {
nextState = State.READ_VARIABLE_LENGTH_CONTENT;
}
return nextState;
}
private LastHttpContent readTrailingHeaders(ByteBuf buffer) {
AppendableCharSequence line = headerParser.parse(buffer);
if (line == null) {
return null;
}
CharSequence lastHeader = null;
if (line.length() > 0) {
LastHttpContent trailer = this.trailer;
if (trailer == null) {
trailer = this.trailer = new DefaultLastHttpContent(Unpooled.EMPTY_BUFFER, validateHeaders);
}
do {
char firstChar = line.charAt(0);
if (lastHeader != null && (firstChar == ' ' || firstChar == '\t')) {
List<String> current = trailer.trailingHeaders().getAll(lastHeader);
if (!current.isEmpty()) {
int lastPos = current.size() - 1;
//please do not make one line from below code
//as it breaks +XX:OptimizeStringConcat optimization//请不要从下面的代码中写一行
//当它中断时+XX:OptimizeStringConcat优化
String lineTrimmed = line.toString().trim();
String currentLastPos = current.get(lastPos);
current.set(lastPos, currentLastPos + lineTrimmed);
}
} else {
splitHeader(line);
CharSequence headerName = name;
if (!HttpHeaderNames.CONTENT_LENGTH.contentEqualsIgnoreCase(headerName) &&
!HttpHeaderNames.TRANSFER_ENCODING.contentEqualsIgnoreCase(headerName) &&
!HttpHeaderNames.TRAILER.contentEqualsIgnoreCase(headerName)) {
trailer.trailingHeaders().add(headerName, value);
}
lastHeader = name;
// reset name and value fields
name = null;
value = null;
}
line = headerParser.parse(buffer);
if (line == null) {
return null;
}
} while (line.length() > 0);
this.trailer = null;
return trailer;
}
return LastHttpContent.EMPTY_LAST_CONTENT;
}