static int decodeHeaders(final Buffer requestContent, int offset, final AjpHttpRequest req) { // Decode headers final MimeHeaders headers = req.getHeaders(); final int hCount = readShort(requestContent, offset); offset += 2; for (int i = 0; i < hCount; i++) { String hName; // 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 = readShort(requestContent, offset); int hId = isc & 0xFF; DataChunk valueDC; isc &= 0xFF00; if (0xA000 == isc) { offset += 2; hName = AjpConstants.headerTransArray[hId - 1]; valueDC = 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; final int headerNameLen = readShort(requestContent, offset); offset += 2; valueDC = headers.addValue(requestContent, offset, headerNameLen); // Don't forget to skip the terminating \0 (that's why "+ 1") offset += headerNameLen + 1; } offset = getBytesToDataChunk(requestContent, offset, valueDC); // Get the last added header name (the one we need) final DataChunk headerNameDC = headers.getName(headers.size() - 1); if (hId == AjpConstants.SC_REQ_CONTENT_LENGTH || (hId == -1 && headerNameDC.equalsIgnoreCase("Content-Length"))) { // just read the content-length header, so set it final long cl = Ascii.parseLong(valueDC); if (cl < Integer.MAX_VALUE) { req.setContentLength((int) cl); } } else if (hId == AjpConstants.SC_REQ_CONTENT_TYPE || (hId == -1 && headerNameDC.equalsIgnoreCase("Content-Type"))) { // just read the content-type header, so set it req.setContentType(valueDC.toString()); } } return offset; }
private static int setStringAttributeValue( final AjpHttpRequest req, final String key, final Buffer buffer, int offset) { final DataChunk tmpDataChunk = req.tmpDataChunk; offset = getBytesToDataChunk(buffer, offset, tmpDataChunk); final String value = tmpDataChunk.toString(); tmpDataChunk.recycle(); req.setAttribute(key, value); return offset; }
static void decodeRequest( final Buffer requestContent, final AjpHttpRequest req, final boolean tomcatAuthentication) throws IOException { // FORWARD_REQUEST handler int offset = requestContent.position(); // Translate the HTTP method code to a String. byte methodCode = requestContent.get(offset++); if (methodCode != AjpConstants.SC_M_JK_STORED) { String mName = AjpConstants.methodTransArray[(int) methodCode - 1]; req.getMethodDC().setString(mName); } offset = getBytesToDataChunk(requestContent, offset, req.getProtocolDC()); final int requestURILen = readShort(requestContent, offset); if (!isNullLength(requestURILen)) { req.getRequestURIRef().init(requestContent, offset + 2, offset + 2 + requestURILen); } // Don't forget to skip the terminating \0 (that's why "+ 1") offset += 2 + requestURILen + 1; offset = getBytesToDataChunk(requestContent, offset, req.remoteAddr()); offset = getBytesToDataChunk(requestContent, offset, req.remoteHostRaw()); offset = getBytesToDataChunk(requestContent, offset, req.localName()); req.setLocalPort(readShort(requestContent, offset)); offset += 2; final boolean isSSL = requestContent.get(offset++) != 0; req.setSecure(isSSL); req.getResponse().setSecure(isSSL); offset = decodeHeaders(requestContent, offset, req); decodeAttributes(requestContent, offset, req, tomcatAuthentication); req.setUnparsedHostHeader(req.getHeaders().getValue("host")); }
private static int decodeAttributes( final Buffer requestContent, int offset, final AjpHttpRequest req, final boolean tomcatAuthentication) { final DataChunk tmpDataChunk = req.tmpDataChunk; boolean moreAttr = true; while (moreAttr) { final byte attributeCode = requestContent.get(offset++); if (attributeCode == AjpConstants.SC_A_ARE_DONE) { return offset; } /* Special case ( XXX in future API make it separate type !) */ if (attributeCode == AjpConstants.SC_A_SSL_KEY_SIZE) { // Bug 1326: it's an Integer. req.setAttribute(SSLSupport.KEY_SIZE_KEY, readShort(requestContent, offset)); offset += 2; } if (attributeCode == AjpConstants.SC_A_REQ_ATTRIBUTE) { // 2 strings ???... offset = setStringAttribute(req, requestContent, offset); } // 1 string attributes switch (attributeCode) { case AjpConstants.SC_A_CONTEXT: // nothing offset = skipBytes(requestContent, offset); break; case AjpConstants.SC_A_REMOTE_USER: if (tomcatAuthentication) { // ignore server offset = skipBytes(requestContent, offset); } else { offset = getBytesToDataChunk(requestContent, offset, req.remoteUser()); } break; case AjpConstants.SC_A_AUTH_TYPE: if (tomcatAuthentication) { // ignore server offset = skipBytes(requestContent, offset); } else { offset = getBytesToDataChunk(requestContent, offset, req.authType()); } break; case AjpConstants.SC_A_QUERY_STRING: offset = getBytesToDataChunk(requestContent, offset, req.getQueryStringDC()); break; case AjpConstants.SC_A_JVM_ROUTE: offset = getBytesToDataChunk(requestContent, offset, req.instanceId()); break; case AjpConstants.SC_A_SSL_CERT: req.setSecure(true); // SSL certificate extraction is costy, initialize on demand offset = getBytesToDataChunk(requestContent, offset, req.sslCert()); break; case AjpConstants.SC_A_SSL_CIPHER: req.setSecure(true); offset = setStringAttributeValue(req, SSLSupport.CIPHER_SUITE_KEY, requestContent, offset); break; case AjpConstants.SC_A_SSL_SESSION: req.setSecure(true); offset = setStringAttributeValue(req, SSLSupport.SESSION_ID_KEY, requestContent, offset); break; case AjpConstants.SC_A_SECRET: offset = getBytesToDataChunk(requestContent, offset, tmpDataChunk); req.setSecret(tmpDataChunk.toString()); tmpDataChunk.recycle(); break; case AjpConstants.SC_A_STORED_METHOD: offset = getBytesToDataChunk(requestContent, offset, req.getMethodDC()); break; default: break; // ignore, we don't know about it - backward compat } } return offset; }