use of org.apache.tomcat.util.http.MimeHeaders in project tomcat by apache.
the class AjpProcessor method prepareRequest.
/**
* After reading the request headers, we have to setup the request filters.
*/
private void prepareRequest() {
// Translate the HTTP method code to a String.
byte methodCode = requestHeaderMessage.getByte();
if (methodCode != Constants.SC_M_JK_STORED) {
String methodName = Constants.getMethodForCode(methodCode - 1);
request.method().setString(methodName);
}
requestHeaderMessage.getBytes(request.protocol());
requestHeaderMessage.getBytes(request.requestURI());
requestHeaderMessage.getBytes(request.remoteAddr());
requestHeaderMessage.getBytes(request.remoteHost());
requestHeaderMessage.getBytes(request.localName());
request.setLocalPort(requestHeaderMessage.getInt());
boolean isSSL = requestHeaderMessage.getByte() != 0;
if (isSSL) {
request.scheme().setString("https");
}
// Decode headers
MimeHeaders headers = request.getMimeHeaders();
// Set this every time in case limit has been changed via JMX
headers.setLimit(protocol.getMaxHeaderCount());
boolean contentLengthSet = false;
int hCount = requestHeaderMessage.getInt();
for (int i = 0; i < hCount; i++) {
String hName = null;
// Header names are encoded as either an integer code starting
// with 0xA0, or as a normal string (in which case the first
// two bytes are the length).
int isc = requestHeaderMessage.peekInt();
int hId = isc & 0xFF;
MessageBytes vMB = null;
isc &= 0xFF00;
if (0xA000 == isc) {
// To advance the read position
requestHeaderMessage.getInt();
hName = Constants.getHeaderForCode(hId - 1);
vMB = headers.addValue(hName);
} else {
// reset hId -- if the header currently being read
// happens to be 7 or 8 bytes long, the code below
// will think it's the content-type header or the
// content-length header - SC_REQ_CONTENT_TYPE=7,
// SC_REQ_CONTENT_LENGTH=8 - leading to unexpected
// behaviour. see bug 5861 for more information.
hId = -1;
requestHeaderMessage.getBytes(tmpMB);
ByteChunk bc = tmpMB.getByteChunk();
vMB = headers.addValue(bc.getBuffer(), bc.getStart(), bc.getLength());
}
requestHeaderMessage.getBytes(vMB);
if (hId == Constants.SC_REQ_CONTENT_LENGTH || (hId == -1 && tmpMB.equalsIgnoreCase("Content-Length"))) {
long cl = vMB.getLong();
if (contentLengthSet) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
setErrorState(ErrorState.CLOSE_CLEAN, null);
} else {
contentLengthSet = true;
// Set the content-length header for the request
request.setContentLength(cl);
}
} else if (hId == Constants.SC_REQ_CONTENT_TYPE || (hId == -1 && tmpMB.equalsIgnoreCase("Content-Type"))) {
// just read the content-type header, so set it
ByteChunk bchunk = vMB.getByteChunk();
request.contentType().setBytes(bchunk.getBytes(), bchunk.getOffset(), bchunk.getLength());
}
}
// Decode extra attributes
String requiredSecret = protocol.getRequiredSecret();
boolean secret = false;
byte attributeCode;
while ((attributeCode = requestHeaderMessage.getByte()) != Constants.SC_A_ARE_DONE) {
switch(attributeCode) {
case Constants.SC_A_REQ_ATTRIBUTE:
requestHeaderMessage.getBytes(tmpMB);
String n = tmpMB.toString();
requestHeaderMessage.getBytes(tmpMB);
String v = tmpMB.toString();
/*
* AJP13 misses to forward the local IP address and the
* remote port. Allow the AJP connector to add this info via
* private request attributes.
* We will accept the forwarded data and remove it from the
* public list of request attributes.
*/
if (n.equals(Constants.SC_A_REQ_LOCAL_ADDR)) {
request.localAddr().setString(v);
} else if (n.equals(Constants.SC_A_REQ_REMOTE_PORT)) {
try {
request.setRemotePort(Integer.parseInt(v));
} catch (NumberFormatException nfe) {
// Ignore invalid value
}
} else if (n.equals(Constants.SC_A_SSL_PROTOCOL)) {
request.setAttribute(SSLSupport.PROTOCOL_VERSION_KEY, v);
} else {
request.setAttribute(n, v);
}
break;
case Constants.SC_A_CONTEXT:
requestHeaderMessage.getBytes(tmpMB);
// nothing
break;
case Constants.SC_A_SERVLET_PATH:
requestHeaderMessage.getBytes(tmpMB);
// nothing
break;
case Constants.SC_A_REMOTE_USER:
boolean tomcatAuthorization = protocol.getTomcatAuthorization();
if (tomcatAuthorization || !protocol.getTomcatAuthentication()) {
// Implies tomcatAuthentication == false
requestHeaderMessage.getBytes(request.getRemoteUser());
request.setRemoteUserNeedsAuthorization(tomcatAuthorization);
} else {
// Ignore user information from reverse proxy
requestHeaderMessage.getBytes(tmpMB);
}
break;
case Constants.SC_A_AUTH_TYPE:
if (protocol.getTomcatAuthentication()) {
// ignore server
requestHeaderMessage.getBytes(tmpMB);
} else {
requestHeaderMessage.getBytes(request.getAuthType());
}
break;
case Constants.SC_A_QUERY_STRING:
requestHeaderMessage.getBytes(request.queryString());
break;
case Constants.SC_A_JVM_ROUTE:
requestHeaderMessage.getBytes(tmpMB);
// nothing
break;
case Constants.SC_A_SSL_CERT:
// SSL certificate extraction is lazy, moved to JkCoyoteHandler
requestHeaderMessage.getBytes(certificates);
break;
case Constants.SC_A_SSL_CIPHER:
requestHeaderMessage.getBytes(tmpMB);
request.setAttribute(SSLSupport.CIPHER_SUITE_KEY, tmpMB.toString());
break;
case Constants.SC_A_SSL_SESSION:
requestHeaderMessage.getBytes(tmpMB);
request.setAttribute(SSLSupport.SESSION_ID_KEY, tmpMB.toString());
break;
case Constants.SC_A_SSL_KEY_SIZE:
request.setAttribute(SSLSupport.KEY_SIZE_KEY, Integer.valueOf(requestHeaderMessage.getInt()));
break;
case Constants.SC_A_STORED_METHOD:
requestHeaderMessage.getBytes(request.method());
break;
case Constants.SC_A_SECRET:
requestHeaderMessage.getBytes(tmpMB);
if (requiredSecret != null) {
secret = true;
if (!tmpMB.equals(requiredSecret)) {
response.setStatus(403);
setErrorState(ErrorState.CLOSE_CLEAN, null);
}
}
break;
default:
// Ignore unknown attribute for backward compatibility
break;
}
}
// Check if secret was submitted if required
if ((requiredSecret != null) && !secret) {
response.setStatus(403);
setErrorState(ErrorState.CLOSE_CLEAN, null);
}
// Check for a full URI (including protocol://host:port/)
ByteChunk uriBC = request.requestURI().getByteChunk();
if (uriBC.startsWithIgnoreCase("http", 0)) {
int pos = uriBC.indexOf("://", 0, 3, 4);
int uriBCStart = uriBC.getStart();
int slashPos = -1;
if (pos != -1) {
byte[] uriB = uriBC.getBytes();
slashPos = uriBC.indexOf('/', pos + 3);
if (slashPos == -1) {
slashPos = uriBC.getLength();
// Set URI as "/"
request.requestURI().setBytes(uriB, uriBCStart + pos + 1, 1);
} else {
request.requestURI().setBytes(uriB, uriBCStart + slashPos, uriBC.getLength() - slashPos);
}
MessageBytes hostMB = headers.setValue("host");
hostMB.setBytes(uriB, uriBCStart + pos + 3, slashPos - pos - 3);
}
}
MessageBytes valueMB = request.getMimeHeaders().getValue("host");
parseHost(valueMB);
if (getErrorState().isError()) {
getAdapter().log(request, response, 0);
}
}
use of org.apache.tomcat.util.http.MimeHeaders in project tomcat by apache.
the class Http11Processor method prepareRequest.
/**
* After reading the request headers, we have to setup the request filters.
*/
private void prepareRequest() {
http11 = true;
http09 = false;
contentDelimitation = false;
sendfileData = null;
if (protocol.isSSLEnabled()) {
request.scheme().setString("https");
}
MessageBytes protocolMB = request.protocol();
if (protocolMB.equals(Constants.HTTP_11)) {
http11 = true;
protocolMB.setString(Constants.HTTP_11);
} else if (protocolMB.equals(Constants.HTTP_10)) {
http11 = false;
keepAlive = false;
protocolMB.setString(Constants.HTTP_10);
} else if (protocolMB.equals("")) {
// HTTP/0.9
http09 = true;
http11 = false;
keepAlive = false;
} else {
// Unsupported protocol
http11 = false;
// Send 505; Unsupported HTTP version
response.setStatus(505);
setErrorState(ErrorState.CLOSE_CLEAN, null);
if (log.isDebugEnabled()) {
log.debug(sm.getString("http11processor.request.prepare") + " Unsupported HTTP version \"" + protocolMB + "\"");
}
}
MimeHeaders headers = request.getMimeHeaders();
// Check connection header
MessageBytes connectionValueMB = headers.getValue(Constants.CONNECTION);
if (connectionValueMB != null) {
ByteChunk connectionValueBC = connectionValueMB.getByteChunk();
if (findBytes(connectionValueBC, Constants.CLOSE_BYTES) != -1) {
keepAlive = false;
} else if (findBytes(connectionValueBC, Constants.KEEPALIVE_BYTES) != -1) {
keepAlive = true;
}
}
if (http11) {
MessageBytes expectMB = headers.getValue("expect");
if (expectMB != null) {
if (expectMB.indexOfIgnoreCase("100-continue", 0) != -1) {
inputBuffer.setSwallowInput(false);
request.setExpectation(true);
} else {
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
setErrorState(ErrorState.CLOSE_CLEAN, null);
}
}
}
// Check user-agent header
Pattern restrictedUserAgents = protocol.getRestrictedUserAgentsPattern();
if (restrictedUserAgents != null && (http11 || keepAlive)) {
MessageBytes userAgentValueMB = headers.getValue("user-agent");
// and keepAlive flags accordingly
if (userAgentValueMB != null) {
String userAgentValue = userAgentValueMB.toString();
if (restrictedUserAgents.matcher(userAgentValue).matches()) {
http11 = false;
keepAlive = false;
}
}
}
// Check for a full URI (including protocol://host:port/)
ByteChunk uriBC = request.requestURI().getByteChunk();
if (uriBC.startsWithIgnoreCase("http", 0)) {
int pos = uriBC.indexOf("://", 0, 3, 4);
int uriBCStart = uriBC.getStart();
int slashPos = -1;
if (pos != -1) {
byte[] uriB = uriBC.getBytes();
slashPos = uriBC.indexOf('/', pos + 3);
if (slashPos == -1) {
slashPos = uriBC.getLength();
// Set URI as "/"
request.requestURI().setBytes(uriB, uriBCStart + pos + 1, 1);
} else {
request.requestURI().setBytes(uriB, uriBCStart + slashPos, uriBC.getLength() - slashPos);
}
MessageBytes hostMB = headers.setValue("host");
hostMB.setBytes(uriB, uriBCStart + pos + 3, slashPos - pos - 3);
}
}
// Input filter setup
InputFilter[] inputFilters = inputBuffer.getFilters();
// Parse transfer-encoding header
if (http11) {
MessageBytes transferEncodingValueMB = headers.getValue("transfer-encoding");
if (transferEncodingValueMB != null) {
String transferEncodingValue = transferEncodingValueMB.toString();
// Parse the comma separated list. "identity" codings are ignored
int startPos = 0;
int commaPos = transferEncodingValue.indexOf(',');
String encodingName = null;
while (commaPos != -1) {
encodingName = transferEncodingValue.substring(startPos, commaPos);
addInputFilter(inputFilters, encodingName);
startPos = commaPos + 1;
commaPos = transferEncodingValue.indexOf(',', startPos);
}
encodingName = transferEncodingValue.substring(startPos);
addInputFilter(inputFilters, encodingName);
}
}
// Parse content-length header
long contentLength = request.getContentLengthLong();
if (contentLength >= 0) {
if (contentDelimitation) {
// contentDelimitation being true at this point indicates that
// chunked encoding is being used but chunked encoding should
// not be used with a content length. RFC 2616, section 4.4,
// bullet 3 states Content-Length must be ignored in this case -
// so remove it.
headers.removeHeader("content-length");
request.setContentLength(-1);
} else {
inputBuffer.addActiveFilter(inputFilters[Constants.IDENTITY_FILTER]);
contentDelimitation = true;
}
}
MessageBytes valueMB = headers.getValue("host");
// Check host header
if (http11 && (valueMB == null)) {
// 400 - Bad request
response.setStatus(400);
setErrorState(ErrorState.CLOSE_CLEAN, null);
if (log.isDebugEnabled()) {
log.debug(sm.getString("http11processor.request.prepare") + " host header missing");
}
}
parseHost(valueMB);
if (!contentDelimitation) {
// If there's no content length
// (broken HTTP/1.0 or HTTP/1.1), assume
// the client is not broken and didn't send a body
inputBuffer.addActiveFilter(inputFilters[Constants.VOID_FILTER]);
contentDelimitation = true;
}
if (getErrorState().isError()) {
getAdapter().log(request, response, 0);
}
}
use of org.apache.tomcat.util.http.MimeHeaders in project tomcat by apache.
the class Http11Processor method prepareResponse.
/**
* When committing the response, we have to validate the set of headers, as
* well as setup the response filters.
*/
@Override
protected final void prepareResponse() throws IOException {
boolean entityBody = true;
contentDelimitation = false;
OutputFilter[] outputFilters = outputBuffer.getFilters();
if (http09 == true) {
// HTTP/0.9
outputBuffer.addActiveFilter(outputFilters[Constants.IDENTITY_FILTER]);
outputBuffer.commit();
return;
}
int statusCode = response.getStatus();
if (statusCode < 200 || statusCode == 204 || statusCode == 205 || statusCode == 304) {
// No entity body
outputBuffer.addActiveFilter(outputFilters[Constants.VOID_FILTER]);
entityBody = false;
contentDelimitation = true;
}
MessageBytes methodMB = request.method();
if (methodMB.equals("HEAD")) {
// No entity body
outputBuffer.addActiveFilter(outputFilters[Constants.VOID_FILTER]);
contentDelimitation = true;
}
// Sendfile support
boolean sendingWithSendfile = false;
if (protocol.getUseSendfile()) {
sendingWithSendfile = prepareSendfile(outputFilters);
}
// Check for compression
boolean isCompressable = false;
boolean useCompression = false;
if (entityBody && (protocol.getCompressionLevel() > 0) && !sendingWithSendfile) {
isCompressable = isCompressable();
if (isCompressable) {
useCompression = useCompression();
}
// Change content-length to -1 to force chunking
if (useCompression) {
response.setContentLength(-1);
}
}
MimeHeaders headers = response.getMimeHeaders();
if (!entityBody) {
response.setContentLength(-1);
}
// A SC_NO_CONTENT response may include entity headers
if (entityBody || statusCode == HttpServletResponse.SC_NO_CONTENT) {
String contentType = response.getContentType();
if (contentType != null) {
headers.setValue("Content-Type").setString(contentType);
}
String contentLanguage = response.getContentLanguage();
if (contentLanguage != null) {
headers.setValue("Content-Language").setString(contentLanguage);
}
}
long contentLength = response.getContentLengthLong();
boolean connectionClosePresent = false;
if (contentLength != -1) {
headers.setValue("Content-Length").setLong(contentLength);
outputBuffer.addActiveFilter(outputFilters[Constants.IDENTITY_FILTER]);
contentDelimitation = true;
} else {
// If the response code supports an entity body and we're on
// HTTP 1.1 then we chunk unless we have a Connection: close header
connectionClosePresent = isConnectionClose(headers);
if (entityBody && http11 && !connectionClosePresent) {
outputBuffer.addActiveFilter(outputFilters[Constants.CHUNKED_FILTER]);
contentDelimitation = true;
headers.addValue(Constants.TRANSFERENCODING).setString(Constants.CHUNKED);
} else {
outputBuffer.addActiveFilter(outputFilters[Constants.IDENTITY_FILTER]);
}
}
if (useCompression) {
outputBuffer.addActiveFilter(outputFilters[Constants.GZIP_FILTER]);
headers.setValue("Content-Encoding").setString("gzip");
}
// If it might be compressed, set the Vary header
if (isCompressable) {
// Make Proxies happy via Vary (from mod_deflate)
MessageBytes vary = headers.getValue("Vary");
if (vary == null) {
// Add a new Vary header
headers.setValue("Vary").setString("Accept-Encoding");
} else if (vary.equals("*")) {
// No action required
} else {
// Merge into current header
headers.setValue("Vary").setString(vary.getString() + ",Accept-Encoding");
}
}
// Caching Filter)
if (headers.getValue("Date") == null) {
headers.addValue("Date").setString(FastHttpDateFormat.getCurrentDate());
}
if ((entityBody) && (!contentDelimitation)) {
// Mark as close the connection after the request, and add the
// connection: close header
keepAlive = false;
}
// This may disabled keep-alive to check before working out the
// Connection header.
checkExpectationAndResponseStatus();
// Connection: close header.
if (keepAlive && statusDropsConnection(statusCode)) {
keepAlive = false;
}
if (!keepAlive) {
// Avoid adding the close header twice
if (!connectionClosePresent) {
headers.addValue(Constants.CONNECTION).setString(Constants.CLOSE);
}
} else if (!http11 && !getErrorState().isError()) {
headers.addValue(Constants.CONNECTION).setString(Constants.KEEPALIVE);
}
// Add server header
String server = protocol.getServer();
if (server == null) {
if (protocol.getServerRemoveAppProvidedValues()) {
headers.removeHeader("server");
}
} else {
// server always overrides anything the app might set
headers.setValue("Server").setString(server);
}
// Build the response header
try {
outputBuffer.sendStatus();
int size = headers.size();
for (int i = 0; i < size; i++) {
outputBuffer.sendHeader(headers.getName(i), headers.getValue(i));
}
outputBuffer.endHeaders();
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
// If something goes wrong, reset the header buffer so the error
// response can be written instead.
outputBuffer.resetHeaderBuffer();
throw t;
}
outputBuffer.commit();
}
use of org.apache.tomcat.util.http.MimeHeaders in project tomcat by apache.
the class Http2UpgradeHandler method prepareHeaders.
protected void prepareHeaders(Response coyoteResponse) {
MimeHeaders headers = coyoteResponse.getMimeHeaders();
int statusCode = coyoteResponse.getStatus();
// Add the pseudo header for status
headers.addValue(":status").setString(Integer.toString(statusCode));
// Check to see if a response body is present
if (!(statusCode < 200 || statusCode == 205 || statusCode == 304)) {
String contentType = coyoteResponse.getContentType();
if (contentType != null) {
headers.setValue("content-type").setString(contentType);
}
String contentLanguage = coyoteResponse.getContentLanguage();
if (contentLanguage != null) {
headers.setValue("content-language").setString(contentLanguage);
}
}
// Add date header unless the application has already set one
if (headers.getValue("date") == null) {
headers.addValue("date").setString(FastHttpDateFormat.getCurrentDate());
}
}
use of org.apache.tomcat.util.http.MimeHeaders in project tomcat by apache.
the class ChunkedInputFilter method parseHeader.
private boolean parseHeader() throws IOException {
MimeHeaders headers = request.getMimeHeaders();
byte chr = 0;
// Read new bytes if needed
if (readChunk == null || readChunk.position() >= readChunk.limit()) {
if (readBytes() < 0) {
throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
}
}
// readBytes() above will set readChunk unless it returns a value < 0
chr = readChunk.get(readChunk.position());
// CRLF terminates the request
if (chr == Constants.CR || chr == Constants.LF) {
parseCRLF(false);
return false;
}
// Mark the current buffer position
int startPos = trailingHeaders.getEnd();
//
// Reading the header name
// Header name is always US-ASCII
//
boolean colon = false;
while (!colon) {
// Read new bytes if needed
if (readChunk == null || readChunk.position() >= readChunk.limit()) {
if (readBytes() < 0) {
throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
}
}
// readBytes() above will set readChunk unless it returns a value < 0
chr = readChunk.get(readChunk.position());
if ((chr >= Constants.A) && (chr <= Constants.Z)) {
chr = (byte) (chr - Constants.LC_OFFSET);
}
if (chr == Constants.COLON) {
colon = true;
} else {
trailingHeaders.append(chr);
}
readChunk.position(readChunk.position() + 1);
}
int colonPos = trailingHeaders.getEnd();
//
// Reading the header value (which can be spanned over multiple lines)
//
boolean eol = false;
boolean validLine = true;
int lastSignificantChar = 0;
while (validLine) {
boolean space = true;
// Skipping spaces
while (space) {
// Read new bytes if needed
if (readChunk == null || readChunk.position() >= readChunk.limit()) {
if (readBytes() < 0) {
throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
}
}
chr = readChunk.get(readChunk.position());
if ((chr == Constants.SP) || (chr == Constants.HT)) {
readChunk.position(readChunk.position() + 1);
// If we swallow whitespace, make sure it counts towards the
// limit placed on trailing header size
int newlimit = trailingHeaders.getLimit() - 1;
if (trailingHeaders.getEnd() > newlimit) {
throwIOException(sm.getString("chunkedInputFilter.maxTrailer"));
}
trailingHeaders.setLimit(newlimit);
} else {
space = false;
}
}
// Reading bytes until the end of the line
while (!eol) {
// Read new bytes if needed
if (readChunk == null || readChunk.position() >= readChunk.limit()) {
if (readBytes() < 0) {
throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
}
}
chr = readChunk.get(readChunk.position());
if (chr == Constants.CR || chr == Constants.LF) {
parseCRLF(true);
eol = true;
} else if (chr == Constants.SP) {
trailingHeaders.append(chr);
} else {
trailingHeaders.append(chr);
lastSignificantChar = trailingHeaders.getEnd();
}
if (!eol) {
readChunk.position(readChunk.position() + 1);
}
}
// Read new bytes if needed
if (readChunk == null || readChunk.position() >= readChunk.limit()) {
if (readBytes() < 0) {
throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
}
}
chr = readChunk.get(readChunk.position());
if ((chr != Constants.SP) && (chr != Constants.HT)) {
validLine = false;
} else {
eol = false;
// Copying one extra space in the buffer (since there must
// be at least one space inserted between the lines)
trailingHeaders.append(chr);
}
}
String headerName = new String(trailingHeaders.getBytes(), startPos, colonPos - startPos, StandardCharsets.ISO_8859_1);
if (allowedTrailerHeaders.contains(headerName.toLowerCase(Locale.ENGLISH))) {
MessageBytes headerValue = headers.addValue(headerName);
// Set the header value
headerValue.setBytes(trailingHeaders.getBytes(), colonPos, lastSignificantChar - colonPos);
}
return true;
}
Aggregations