use of org.apache.tomcat.util.buf.MessageBytes 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;
if (statusCode == 205) {
// RFC 7231 requires the server to explicitly signal an empty
// response in this case
response.setContentLength(0);
} else {
response.setContentLength(-1);
}
}
MessageBytes methodMB = request.method();
if (methodMB.equals("HEAD")) {
// No entity body
outputBuffer.addActiveFilter(outputFilters[Constants.VOID_FILTER]);
contentDelimitation = true;
}
// Sendfile support
if (protocol.getUseSendfile()) {
prepareSendfile(outputFilters);
}
// Check for compression
boolean useCompression = false;
if (entityBody && sendfileData == null) {
useCompression = protocol.useCompression(request, response);
}
MimeHeaders headers = response.getMimeHeaders();
// 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 = isConnectionToken(headers, Constants.CLOSE);
if (http11 && response.getTrailerFields() != null) {
// If trailer fields are set, always use chunking
outputBuffer.addActiveFilter(outputFilters[Constants.CHUNKED_FILTER]);
contentDelimitation = true;
headers.addValue(Constants.TRANSFERENCODING).setString(Constants.CHUNKED);
} else if (contentLength != -1) {
headers.setValue("Content-Length").setLong(contentLength);
outputBuffer.addActiveFilter(outputFilters[Constants.IDENTITY_FILTER]);
contentDelimitation = true;
} else {
// HTTP 1.1 then we chunk unless we have a Connection: close header
if (http11 && entityBody && !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]);
}
// Caching Filter)
if (headers.getValue("Date") == null) {
headers.addValue("Date").setString(FastHttpDateFormat.getCurrentDate());
}
if ((entityBody) && (!contentDelimitation) || connectionClosePresent) {
// Disable keep-alive if:
// - there is a response body but way for the client to determine
// the content length information; or
// - there is a "connection: close" header present
// This will cause the "connection: close" header to be added if it
// is not already present.
keepAlive = false;
}
// This may disabled keep-alive to check before working out the
// Connection header.
checkExpectationAndResponseStatus();
// This may disable keep-alive if there is more body to swallow
// than the configuration allows
checkMaxSwallowSize();
// 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 (!getErrorState().isError()) {
if (!http11) {
headers.addValue(Constants.CONNECTION).setString(Constants.KEEP_ALIVE_HEADER_VALUE_TOKEN);
}
if (protocol.getUseKeepAliveResponseHeader()) {
boolean connectionKeepAlivePresent = isConnectionToken(request.getMimeHeaders(), Constants.KEEP_ALIVE_HEADER_VALUE_TOKEN);
if (connectionKeepAlivePresent) {
int keepAliveTimeout = protocol.getKeepAliveTimeout();
if (keepAliveTimeout > 0) {
String value = "timeout=" + keepAliveTimeout / 1000L;
headers.setValue(Constants.KEEP_ALIVE_HEADER_NAME).setString(value);
if (http11) {
// Append if there is already a Connection header,
// else create the header
MessageBytes connectionHeaderValue = headers.getValue(Constants.CONNECTION);
if (connectionHeaderValue == null) {
headers.addValue(Constants.CONNECTION).setString(Constants.KEEP_ALIVE_HEADER_VALUE_TOKEN);
} else {
connectionHeaderValue.setString(connectionHeaderValue.getString() + ", " + Constants.KEEP_ALIVE_HEADER_VALUE_TOKEN);
}
}
}
}
}
}
// 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.buf.MessageBytes in project tomcat by apache.
the class Http11Processor method prepareInputFilters.
private void prepareInputFilters(MimeHeaders headers) throws IOException {
contentDelimitation = false;
InputFilter[] inputFilters = inputBuffer.getFilters();
// HTTP 1.x header from a 1.x client unless the specs says otherwise.
if (!http09) {
MessageBytes transferEncodingValueMB = headers.getValue("transfer-encoding");
if (transferEncodingValueMB != null) {
List<String> encodingNames = new ArrayList<>();
if (TokenList.parseTokenList(headers.values("transfer-encoding"), encodingNames)) {
for (String encodingName : encodingNames) {
addInputFilter(inputFilters, encodingName);
}
} else {
// Invalid transfer encoding
badRequest("http11processor.request.invalidTransferEncoding");
}
}
}
// Parse content-length header
long contentLength = -1;
try {
contentLength = request.getContentLengthLong();
} catch (NumberFormatException e) {
badRequest("http11processor.request.nonNumericContentLength");
} catch (IllegalArgumentException e) {
badRequest("http11processor.request.multipleContentLength");
}
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);
keepAlive = false;
} else {
inputBuffer.addActiveFilter(inputFilters[Constants.IDENTITY_FILTER]);
contentDelimitation = true;
}
}
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;
}
}
use of org.apache.tomcat.util.buf.MessageBytes in project tomcat by apache.
the class AjpProcessor 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 {
response.setCommitted(true);
tmpMB.recycle();
responseMsgPos = -1;
responseMessage.reset();
responseMessage.appendByte(Constants.JK_AJP13_SEND_HEADERS);
// Responses with certain status codes are not permitted to include a
// response body.
int statusCode = response.getStatus();
if (statusCode < 200 || statusCode == 204 || statusCode == 205 || statusCode == 304) {
// No entity body
swallowResponse = true;
}
// Responses to HEAD requests are not permitted to include a response
// body.
MessageBytes methodMB = request.method();
if (methodMB.equals("HEAD")) {
// No entity body
swallowResponse = true;
}
// HTTP header contents
responseMessage.appendInt(statusCode);
// Reason phrase is optional but mod_jk + httpd 2.x fails with a null
// reason phrase - bug 45026
tmpMB.setString(Integer.toString(response.getStatus()));
responseMessage.appendBytes(tmpMB);
// Special headers
MimeHeaders headers = response.getMimeHeaders();
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();
if (contentLength >= 0) {
headers.setValue("Content-Length").setLong(contentLength);
}
// Other headers
int numHeaders = headers.size();
responseMessage.appendInt(numHeaders);
for (int i = 0; i < numHeaders; i++) {
MessageBytes hN = headers.getName(i);
int hC = Constants.getResponseAjpIndex(hN.toString());
if (hC > 0) {
responseMessage.appendInt(hC);
} else {
responseMessage.appendBytes(hN);
}
MessageBytes hV = headers.getValue(i);
responseMessage.appendBytes(hV);
}
// Write to buffer
responseMessage.end();
socketWrapper.write(true, responseMessage.getBuffer(), 0, responseMessage.getLen());
socketWrapper.flush(true);
}
use of org.apache.tomcat.util.buf.MessageBytes 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());
if (socketWrapper != null) {
request.peerAddr().setString(socketWrapper.getRemoteAddr());
}
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 secret = protocol.getSecret();
boolean secretPresentInRequest = 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 if (n.equals("JK_LB_ACTIVATION")) {
request.setAttribute(n, v);
} else if (jakartaAttributeMapping.containsKey(n)) {
// AJP uses the Java Servlet attribute names.
// Need to convert these to Jakarta Servlet.
request.setAttribute(jakartaAttributeMapping.get(n), v);
} else if (iisTlsAttributes.contains(n)) {
// Allow IIS TLS attributes
request.setAttribute(n, v);
} else {
// All 'known' attributes will be processed by the previous
// blocks. Any remaining attribute is an 'arbitrary' one.
Pattern pattern = protocol.getAllowedRequestAttributesPatternInternal();
if (pattern != null && pattern.matcher(n).matches()) {
request.setAttribute(n, v);
} else {
log.warn(sm.getString("ajpprocessor.unknownAttribute", n));
response.setStatus(403);
setErrorState(ErrorState.CLOSE_CLEAN, null);
}
}
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 (secret != null && secret.length() > 0) {
secretPresentInRequest = true;
if (!tmpMB.equals(secret)) {
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 (secret != null && secret.length() > 0 && !secretPresentInRequest) {
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().isIoAllowed()) {
getAdapter().log(request, response, 0);
}
}
use of org.apache.tomcat.util.buf.MessageBytes in project tomcat by apache.
the class CoyoteAdapter method postParseRequest.
// ------------------------------------------------------ Protected Methods
/**
* Perform the necessary processing after the HTTP headers have been parsed
* to enable the request/response pair to be passed to the start of the
* container pipeline for processing.
*
* @param req The coyote request object
* @param request The catalina request object
* @param res The coyote response object
* @param response The catalina response object
*
* @return <code>true</code> if the request should be passed on to the start
* of the container pipeline, otherwise <code>false</code>
*
* @throws IOException If there is insufficient space in a buffer while
* processing headers
* @throws ServletException If the supported methods of the target servlet
* cannot be determined
*/
protected boolean postParseRequest(org.apache.coyote.Request req, Request request, org.apache.coyote.Response res, Response response) throws IOException, ServletException {
// processor hasn't set it, use the settings from the connector
if (req.scheme().isNull()) {
// Use connector scheme and secure configuration, (defaults to
// "http" and false respectively)
req.scheme().setString(connector.getScheme());
request.setSecure(connector.getSecure());
} else {
// Use processor specified scheme to determine secure state
request.setSecure(req.scheme().equals("https"));
}
// At this point the Host header has been processed.
// Override if the proxyPort/proxyHost are set
String proxyName = connector.getProxyName();
int proxyPort = connector.getProxyPort();
if (proxyPort != 0) {
req.setServerPort(proxyPort);
} else if (req.getServerPort() == -1) {
// Not explicitly set. Use default ports based on the scheme
if (req.scheme().equals("https")) {
req.setServerPort(443);
} else {
req.setServerPort(80);
}
}
if (proxyName != null) {
req.serverName().setString(proxyName);
}
MessageBytes undecodedURI = req.requestURI();
// Check for ping OPTIONS * request
if (undecodedURI.equals("*")) {
if (req.method().equalsIgnoreCase("OPTIONS")) {
StringBuilder allow = new StringBuilder();
allow.append("GET, HEAD, POST, PUT, DELETE, OPTIONS");
// Trace if allowed
if (connector.getAllowTrace()) {
allow.append(", TRACE");
}
res.setHeader("Allow", allow.toString());
// Access log entry as processing won't reach AccessLogValve
connector.getService().getContainer().logAccess(request, response, 0, true);
return false;
} else {
response.sendError(400, "Invalid URI");
}
}
MessageBytes decodedURI = req.decodedURI();
if (undecodedURI.getType() == MessageBytes.T_BYTES) {
if (connector.getRejectSuspiciousURIs()) {
if (checkSuspiciousURIs(undecodedURI.getByteChunk())) {
response.sendError(400, "Invalid URI");
}
}
// Copy the raw URI to the decodedURI
decodedURI.duplicate(undecodedURI);
// Parse (and strip out) the path parameters
parsePathParameters(req, request);
// %xx decoding of the URL
try {
req.getURLDecoder().convert(decodedURI.getByteChunk(), connector.getEncodedSolidusHandlingInternal());
} catch (IOException ioe) {
response.sendError(400, "Invalid URI: " + ioe.getMessage());
}
// Normalization
if (normalize(req.decodedURI(), connector.getAllowBackslash())) {
// Character decoding
convertURI(decodedURI, request);
// URIEncoding values are limited to US-ASCII supersets.
// Therefore it is not necessary to check that the URI remains
// normalized after character decoding
} else {
response.sendError(400, "Invalid URI");
}
} else {
/* The URI is chars or String, and has been sent using an in-memory
* protocol handler. The following assumptions are made:
* - req.requestURI() has been set to the 'original' non-decoded,
* non-normalized URI
* - req.decodedURI() has been set to the decoded, normalized form
* of req.requestURI()
* - 'suspicious' URI filtering - if required - has already been
* performed
*/
decodedURI.toChars();
// Remove all path parameters; any needed path parameter should be set
// using the request object rather than passing it in the URL
CharChunk uriCC = decodedURI.getCharChunk();
int semicolon = uriCC.indexOf(';');
if (semicolon > 0) {
decodedURI.setChars(uriCC.getBuffer(), uriCC.getStart(), semicolon);
}
}
// Request mapping.
MessageBytes serverName;
if (connector.getUseIPVHosts()) {
serverName = req.localName();
if (serverName.isNull()) {
// well, they did ask for it
res.action(ActionCode.REQ_LOCAL_NAME_ATTRIBUTE, null);
}
} else {
serverName = req.serverName();
}
// Version for the second mapping loop and
// Context that we expect to get for that version
String version = null;
Context versionContext = null;
boolean mapRequired = true;
if (response.isError()) {
// An error this early means the URI is invalid. Ensure invalid data
// is not passed to the mapper. Note we still want the mapper to
// find the correct host.
decodedURI.recycle();
}
while (mapRequired) {
// This will map the the latest version by default
connector.getService().getMapper().map(serverName, decodedURI, version, request.getMappingData());
// so no context could be mapped.
if (request.getContext() == null) {
// body.
return true;
}
// Now we have the context, we can parse the session ID from the URL
// (if any). Need to do this before we redirect in case we need to
// include the session id in the redirect
String sessionID;
if (request.getServletContext().getEffectiveSessionTrackingModes().contains(SessionTrackingMode.URL)) {
// Get the session ID if there was one
sessionID = request.getPathParameter(SessionConfig.getSessionUriParamName(request.getContext()));
if (sessionID != null) {
request.setRequestedSessionId(sessionID);
request.setRequestedSessionURL(true);
}
}
// Look for session ID in cookies and SSL session
try {
parseSessionCookiesId(request);
} catch (IllegalArgumentException e) {
// Too many cookies
if (!response.isError()) {
response.setError();
response.sendError(400);
}
return true;
}
parseSessionSslId(request);
sessionID = request.getRequestedSessionId();
mapRequired = false;
if (version != null && request.getContext() == versionContext) {
// We got the version that we asked for. That is it.
} else {
version = null;
versionContext = null;
Context[] contexts = request.getMappingData().contexts;
// No session ID means no possibility of remap
if (contexts != null && sessionID != null) {
// Find the context associated with the session
for (int i = contexts.length; i > 0; i--) {
Context ctxt = contexts[i - 1];
if (ctxt.getManager().findSession(sessionID) != null) {
// already been mapped?
if (!ctxt.equals(request.getMappingData().context)) {
// Set version so second time through mapping
// the correct context is found
version = ctxt.getWebappVersion();
versionContext = ctxt;
// Reset mapping
request.getMappingData().recycle();
mapRequired = true;
// Recycle cookies and session info in case the
// correct context is configured with different
// settings
request.recycleSessionInfo();
request.recycleCookieInfo(true);
}
break;
}
}
}
}
if (!mapRequired && request.getContext().getPaused()) {
// point.
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// Should never happen
}
// Reset mapping
request.getMappingData().recycle();
mapRequired = true;
}
}
// Possible redirect
MessageBytes redirectPathMB = request.getMappingData().redirectPath;
if (!redirectPathMB.isNull()) {
String redirectPath = URLEncoder.DEFAULT.encode(redirectPathMB.toString(), StandardCharsets.UTF_8);
String query = request.getQueryString();
if (request.isRequestedSessionIdFromURL()) {
// This is not optimal, but as this is not very common, it
// shouldn't matter
redirectPath = redirectPath + ";" + SessionConfig.getSessionUriParamName(request.getContext()) + "=" + request.getRequestedSessionId();
}
if (query != null) {
// This is not optimal, but as this is not very common, it
// shouldn't matter
redirectPath = redirectPath + "?" + query;
}
response.sendRedirect(redirectPath);
request.getContext().logAccess(request, response, 0, true);
return false;
}
// Filter trace method
if (!connector.getAllowTrace() && req.method().equalsIgnoreCase("TRACE")) {
Wrapper wrapper = request.getWrapper();
String header = null;
if (wrapper != null) {
String[] methods = wrapper.getServletMethods();
if (methods != null) {
for (String method : methods) {
if ("TRACE".equals(method)) {
continue;
}
if (header == null) {
header = method;
} else {
header += ", " + method;
}
}
}
}
if (header != null) {
res.addHeader("Allow", header);
}
response.sendError(405, "TRACE method is not allowed");
// Safe to skip the remainder of this method.
return true;
}
doConnectorAuthenticationAuthorization(req, request);
return true;
}
Aggregations