// 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) {
requestHeaderMessage.getInt(); // To advance the read position
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);
error = true;
} else {
contentLengthSet = true;
// Set the content-length header for the request
request.setContentLength(cl);
}
if (cl != 0) {
bodyPresent = true;
}
} 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
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 remotePort.
* Allow the AJP connector to add this info via
* a private request attribute.
* We will accept the forwarded data as the remote port,
* and remove it from the public list of request attributes.
*/
if(n.equals(Constants.SC_A_REQ_REMOTE_PORT)) {
try {
request.setRemotePort(Integer.parseInt(v));
} catch (NumberFormatException nfe) {
// Ignore invalid value
}
} 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 :
if (tomcatAuthentication) {
// ignore server
requestHeaderMessage.getBytes(tmpMB);
} else {
requestHeaderMessage.getBytes(request.getRemoteUser());
}
break;
case Constants.SC_A_AUTH_TYPE :
if (tomcatAuthentication) {
// 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(request.instanceId());
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);
error = true;
}
}
break;
default:
// Ignore unknown attribute for backward compatibility
break;
}
}
// Check if secret was submitted if required
if ((requiredSecret != null) && !secret) {
response.setStatus(403);
error = true;
}
// 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 (error) {
getAdapter().log(request, response, 0);
}