in java/org/apache/tomcat/util/http/parser/HttpHeaderParser.java [74:267]
public HeaderParseStatus parseHeader() throws IOException {
while (headerParsePos == HeaderParsePosition.HEADER_START) {
// Read new bytes if needed
if (source.getHeaderByteBuffer().position() >= source.getHeaderByteBuffer().limit()) {
if (!source.fillHeaderBuffer()) {
return HeaderParseStatus.NEED_MORE_DATA;
}
}
prevChr = chr;
chr = source.getHeaderByteBuffer().get();
if (chr == CR && prevChr != CR) {
// Possible start of CRLF - process the next byte.
} else if (chr == LF) {
if (!tolerantEol && prevChr != CR) {
throw new IllegalArgumentException(sm.getString("httpHeaderParser.invalidCrlfNoCR"));
}
return HeaderParseStatus.DONE;
} else {
if (prevChr == CR) {
// Must have read two bytes (first was CR, second was not LF)
source.getHeaderByteBuffer().position(source.getHeaderByteBuffer().position() - 2);
} else {
// Must have only read one byte
source.getHeaderByteBuffer().position(source.getHeaderByteBuffer().position() - 1);
}
break;
}
}
if (headerParsePos == HeaderParsePosition.HEADER_START) {
// Mark the current buffer position
headerData.start = source.getHeaderByteBuffer().position();
headerData.lineStart = headerData.start;
headerParsePos = HeaderParsePosition.HEADER_NAME;
}
//
// Reading the header name
// Header name is always US-ASCII
//
while (headerParsePos == HeaderParsePosition.HEADER_NAME) {
// Read new bytes if needed
if (source.getHeaderByteBuffer().position() >= source.getHeaderByteBuffer().limit()) {
if (!source.fillHeaderBuffer()) {
return HeaderParseStatus.NEED_MORE_DATA;
}
}
int pos = source.getHeaderByteBuffer().position();
chr = source.getHeaderByteBuffer().get();
if (chr == COLON) {
if (headerData.start == pos) {
// Zero length header name - not valid.
// skipLine() will handle the error
return skipLine();
}
headerParsePos = HeaderParsePosition.HEADER_VALUE_START;
headerData.headerValue = headers.addValue(source.getHeaderByteBuffer().array(), headerData.start,
pos - headerData.start);
pos = source.getHeaderByteBuffer().position();
// Mark the current buffer position
headerData.start = pos;
headerData.realPos = pos;
headerData.lastSignificantChar = pos;
break;
} else if (!HttpParser.isToken(chr)) {
// Non-token characters are illegal in header names
// Parsing continues so the error can be reported in context
headerData.lastSignificantChar = pos;
source.getHeaderByteBuffer().position(source.getHeaderByteBuffer().position() - 1);
// skipLine() will handle the error
return skipLine();
}
// chr is next byte of header name. Convert to lowercase.
if (chr >= A && chr <= Z) {
source.getHeaderByteBuffer().put(pos, (byte) (chr - LC_OFFSET));
}
}
// Skip the line and ignore the header
if (headerParsePos == HeaderParsePosition.HEADER_SKIPLINE) {
return skipLine();
}
//
// Reading the header value (which can be spanned over multiple lines)
//
while (headerParsePos == HeaderParsePosition.HEADER_VALUE_START ||
headerParsePos == HeaderParsePosition.HEADER_VALUE ||
headerParsePos == HeaderParsePosition.HEADER_MULTI_LINE) {
if (headerParsePos == HeaderParsePosition.HEADER_VALUE_START) {
// Skipping spaces
while (true) {
// Read new bytes if needed
if (source.getHeaderByteBuffer().position() >= source.getHeaderByteBuffer().limit()) {
if (!source.fillHeaderBuffer()) {
return HeaderParseStatus.NEED_MORE_DATA;
}
}
chr = source.getHeaderByteBuffer().get();
if (chr != SP && chr != HT) {
headerParsePos = HeaderParsePosition.HEADER_VALUE;
source.getHeaderByteBuffer().position(source.getHeaderByteBuffer().position() - 1);
// Avoids prevChr = chr at start of header value
// parsing which causes problems when chr is CR
// (in the case of an empty header value)
chr = 0;
break;
}
}
}
if (headerParsePos == HeaderParsePosition.HEADER_VALUE) {
// Reading bytes until the end of the line
boolean eol = false;
while (!eol) {
// Read new bytes if needed
if (source.getHeaderByteBuffer().position() >= source.getHeaderByteBuffer().limit()) {
if (!source.fillHeaderBuffer()) {
return HeaderParseStatus.NEED_MORE_DATA;
}
}
prevChr = chr;
chr = source.getHeaderByteBuffer().get();
if (chr == CR && prevChr != CR) {
// CR is only permitted at the start of a CRLF sequence.
// Possible start of CRLF - process the next byte.
} else if (chr == LF) {
if (!tolerantEol && prevChr != CR) {
throw new IllegalArgumentException(sm.getString("httpHeaderParser.invalidCrlfNoCR"));
}
eol = true;
} else if (prevChr == CR) {
// Invalid value - also need to delete header
return skipLine();
} else if (HttpParser.isControl(chr) && chr != HT) {
// Invalid value - also need to delete header
return skipLine();
} else if (chr == SP || chr == HT) {
source.getHeaderByteBuffer().put(headerData.realPos, chr);
headerData.realPos++;
} else {
source.getHeaderByteBuffer().put(headerData.realPos, chr);
headerData.realPos++;
headerData.lastSignificantChar = headerData.realPos;
}
}
// Ignore whitespaces at the end of the line
headerData.realPos = headerData.lastSignificantChar;
// Checking the first character of the new line. If the character
// is a LWS, then it's a multiline header
headerParsePos = HeaderParsePosition.HEADER_MULTI_LINE;
}
// Read new bytes if needed
if (source.getHeaderByteBuffer().position() >= source.getHeaderByteBuffer().limit()) {
if (!source.fillHeaderBuffer()) {
return HeaderParseStatus.NEED_MORE_DATA;
}
}
byte peek = source.getHeaderByteBuffer().get(source.getHeaderByteBuffer().position());
if (headerParsePos == HeaderParsePosition.HEADER_MULTI_LINE) {
if (peek != SP && peek != HT) {
headerParsePos = HeaderParsePosition.HEADER_START;
break;
} else {
// Copying one extra space in the buffer (since there must
// be at least one space inserted between the lines)
source.getHeaderByteBuffer().put(headerData.realPos, peek);
headerData.realPos++;
headerParsePos = HeaderParsePosition.HEADER_VALUE_START;
}
}
}
// Set the header value
headerData.headerValue.setBytes(source.getHeaderByteBuffer().array(), headerData.start,
headerData.lastSignificantChar - headerData.start);
headerData.recycle();
return HeaderParseStatus.HAVE_MORE_HEADERS;
}