*/
package org.apache.coyote.http11;
+import java.io.IOException;
import java.util.StringTokenizer;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
+import org.apache.coyote.ActionCode;
import org.apache.coyote.Adapter;
import org.apache.coyote.Request;
import org.apache.coyote.Response;
import org.apache.coyote.http11.filters.GzipOutputFilter;
import org.apache.coyote.http11.filters.IdentityInputFilter;
import org.apache.coyote.http11.filters.IdentityOutputFilter;
+import org.apache.coyote.http11.filters.SavedRequestInputFilter;
import org.apache.coyote.http11.filters.VoidInputFilter;
import org.apache.coyote.http11.filters.VoidOutputFilter;
import org.apache.juli.logging.Log;
import org.apache.tomcat.util.buf.Ascii;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.FastHttpDateFormat;
+import org.apache.tomcat.util.http.MimeHeaders;
+import org.apache.tomcat.util.net.AbstractEndpoint;
import org.apache.tomcat.util.res.StringManager;
public abstract class AbstractHttp11Processor {
*/
protected String server = null;
+
+ /**
+ * Async used
+ */
+ protected boolean async = false;
+
+
/**
* Set compression level.
*/
}
+ /**
+ * Send an action to the connector.
+ *
+ * @param actionCode Type of the action
+ * @param param Action parameter
+ */
+ public final void action(ActionCode actionCode, Object param) {
+
+ if (actionCode == ActionCode.ACTION_COMMIT) {
+ // Commit current response
+
+ if (response.isCommitted())
+ return;
+
+ // Validate and write response headers
+ try {
+ prepareResponse();
+ getOutputBuffer().commit();
+ } catch (IOException e) {
+ // Set error flag
+ error = true;
+ }
+ } else if (actionCode == ActionCode.ACTION_ACK) {
+ // Acknowledge request
+ // Send a 100 status back if it makes sense (response not committed
+ // yet, and client specified an expectation for 100-continue)
+
+ if ((response.isCommitted()) || !expectation)
+ return;
+
+ getInputBuffer().setSwallowInput(true);
+ try {
+ getOutputBuffer().sendAck();
+ } catch (IOException e) {
+ // Set error flag
+ error = true;
+ }
+ } else if (actionCode == ActionCode.ACTION_CLIENT_FLUSH) {
+
+ try {
+ getOutputBuffer().flush();
+ } catch (IOException e) {
+ // Set error flag
+ error = true;
+ response.setErrorException(e);
+ }
+
+ } else if (actionCode == ActionCode.ACTION_RESET) {
+ // Reset response
+ // Note: This must be called before the response is committed
+
+ getOutputBuffer().reset();
+
+ } else if (actionCode == ActionCode.ACTION_CUSTOM) {
+ // Do nothing
+ // TODO Remove this action
+
+ } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) {
+ ByteChunk body = (ByteChunk) param;
+
+ InputFilter savedBody = new SavedRequestInputFilter(body);
+ savedBody.setRequest(request);
+
+ AbstractInputBuffer internalBuffer = (AbstractInputBuffer)
+ request.getInputBuffer();
+ internalBuffer.addActiveFilter(savedBody);
+ } else if (actionCode == ActionCode.ACTION_ASYNC_START) {
+ async = true;
+ } else {
+ actionInternal(actionCode, param);
+ }
+ }
+
+ abstract void actionInternal(ActionCode actionCode, Object param);
+
+
+ /**
+ * When committing the response, we have to validate the set of headers, as
+ * well as setup the response filters.
+ */
+ private void prepareResponse() {
+
+ boolean entityBody = true;
+ contentDelimitation = false;
+
+ OutputFilter[] outputFilters = getOutputBuffer().getFilters();
+
+ if (http09 == true) {
+ // HTTP/0.9
+ getOutputBuffer().addActiveFilter
+ (outputFilters[Constants.IDENTITY_FILTER]);
+ return;
+ }
+
+ int statusCode = response.getStatus();
+ if ((statusCode == 204) || (statusCode == 205)
+ || (statusCode == 304)) {
+ // No entity body
+ getOutputBuffer().addActiveFilter
+ (outputFilters[Constants.VOID_FILTER]);
+ entityBody = false;
+ contentDelimitation = true;
+ }
+
+ MessageBytes methodMB = request.method();
+ if (methodMB.equals("HEAD")) {
+ // No entity body
+ getOutputBuffer().addActiveFilter
+ (outputFilters[Constants.VOID_FILTER]);
+ contentDelimitation = true;
+ }
+
+ // Sendfile support
+ boolean sendingWithSendfile = false;
+ if (getEndpoint().getUseSendfile()) {
+ sendingWithSendfile = prepareSendfile(outputFilters);
+ }
+
+ // Check for compression
+ boolean useCompression = false;
+ if (entityBody && (compressionLevel > 0) && !sendingWithSendfile) {
+ useCompression = isCompressable();
+ // Change content-length to -1 to force chunking
+ if (useCompression) {
+ response.setContentLength(-1);
+ }
+ }
+
+ MimeHeaders headers = response.getMimeHeaders();
+ if (!entityBody) {
+ response.setContentLength(-1);
+ } else {
+ 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 != -1) {
+ headers.setValue("Content-Length").setLong(contentLength);
+ getOutputBuffer().addActiveFilter
+ (outputFilters[Constants.IDENTITY_FILTER]);
+ contentDelimitation = true;
+ } else {
+ if (entityBody && http11) {
+ getOutputBuffer().addActiveFilter
+ (outputFilters[Constants.CHUNKED_FILTER]);
+ contentDelimitation = true;
+ headers.addValue(Constants.TRANSFERENCODING).setString(Constants.CHUNKED);
+ } else {
+ getOutputBuffer().addActiveFilter
+ (outputFilters[Constants.IDENTITY_FILTER]);
+ }
+ }
+
+ if (useCompression) {
+ getOutputBuffer().addActiveFilter(outputFilters[Constants.GZIP_FILTER]);
+ headers.setValue("Content-Encoding").setString("gzip");
+ // 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");
+ }
+ }
+
+ // Add date header
+ headers.setValue("Date").setString(FastHttpDateFormat.getCurrentDate());
+
+ // FIXME: Add transfer encoding header
+
+ if ((entityBody) && (!contentDelimitation)) {
+ // Mark as close the connection after the request, and add the
+ // connection: close header
+ keepAlive = false;
+ }
+
+ // If we know that the request is bad this early, add the
+ // Connection: close header.
+ keepAlive = keepAlive && !statusDropsConnection(statusCode);
+ if (!keepAlive) {
+ headers.addValue(Constants.CONNECTION).setString(Constants.CLOSE);
+ } else if (!http11 && !error) {
+ headers.addValue(Constants.CONNECTION).setString(Constants.KEEPALIVE);
+ }
+
+ // Build the response header
+ getOutputBuffer().sendStatus();
+
+ // Add server header
+ if (server != null) {
+ // Always overrides anything the app might set
+ headers.setValue("Server").setString(server);
+ } else if (headers.getValue("Server") == null) {
+ // If app didn't set the header, use the default
+ getOutputBuffer().write(Constants.SERVER_BYTES);
+ }
+
+ int size = headers.size();
+ for (int i = 0; i < size; i++) {
+ getOutputBuffer().sendHeader(headers.getName(i), headers.getValue(i));
+ }
+ getOutputBuffer().endHeaders();
+
+ }
+
+ abstract AbstractEndpoint getEndpoint();
+ abstract boolean prepareSendfile(OutputFilter[] outputFilters);
+
+ public void endRequest() {
+
+ // Finish the handling of the request
+ try {
+ getInputBuffer().endRequest();
+ } catch (IOException e) {
+ error = true;
+ } catch (Throwable t) {
+ log.error(sm.getString("http11processor.request.finish"), t);
+ // 500 - Internal Server Error
+ response.setStatus(500);
+ adapter.log(request, response, 0);
+ error = true;
+ }
+ try {
+ getOutputBuffer().endRequest();
+ } catch (IOException e) {
+ error = true;
+ } catch (Throwable t) {
+ log.error(sm.getString("http11processor.response.finish"), t);
+ error = true;
+ }
+
+ }
}
import org.apache.coyote.RequestInfo;
import org.apache.coyote.Response;
import org.apache.coyote.http11.filters.BufferedInputFilter;
-import org.apache.coyote.http11.filters.SavedRequestInputFilter;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.jni.Address;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.HexUtils;
import org.apache.tomcat.util.buf.MessageBytes;
-import org.apache.tomcat.util.http.FastHttpDateFormat;
import org.apache.tomcat.util.http.MimeHeaders;
import org.apache.tomcat.util.net.AbstractEndpoint;
import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
/**
- * Async used
- */
- protected boolean async = false;
-
-
- /**
* SSL enabled ?
*/
protected boolean ssl = false;
* Associated endpoint.
*/
protected AprEndpoint endpoint;
-
+ @Override
+ protected AbstractEndpoint getEndpoint() {
+ return endpoint;
+ }
// --------------------------------------------------------- Public Methods
}
- public void endRequest() {
-
- // Finish the handling of the request
- try {
- inputBuffer.endRequest();
- } catch (IOException e) {
- error = true;
- } catch (Throwable t) {
- log.error(sm.getString("http11processor.request.finish"), t);
- // 500 - Internal Server Error
- response.setStatus(500);
- adapter.log(request, response, 0);
- error = true;
- }
- try {
- outputBuffer.endRequest();
- } catch (IOException e) {
- error = true;
- } catch (Throwable t) {
- log.error(sm.getString("http11processor.response.finish"), t);
- error = true;
- }
-
- }
-
-
public void recycle() {
inputBuffer.recycle();
outputBuffer.recycle();
* @param param Action parameter
*/
@Override
- public void action(ActionCode actionCode, Object param) {
-
- if (actionCode == ActionCode.ACTION_COMMIT) {
- // Commit current response
-
- if (response.isCommitted())
- return;
-
- // Validate and write response headers
- prepareResponse();
- try {
- outputBuffer.commit();
- } catch (IOException e) {
- // Set error flag
- error = true;
- }
-
- } else if (actionCode == ActionCode.ACTION_ACK) {
-
- // Acknowledge request
-
- // Send a 100 status back if it makes sense (response not committed
- // yet, and client specified an expectation for 100-continue)
-
- if ((response.isCommitted()) || !expectation)
- return;
-
- inputBuffer.setSwallowInput(true);
- try {
- outputBuffer.sendAck();
- } catch (IOException e) {
- // Set error flag
- error = true;
- }
-
- } else if (actionCode == ActionCode.ACTION_CLIENT_FLUSH) {
+ public void actionInternal(ActionCode actionCode, Object param) {
- try {
- outputBuffer.flush();
- } catch (IOException e) {
- // Set error flag
- error = true;
- response.setErrorException(e);
- }
-
- } else if (actionCode == ActionCode.ACTION_CLOSE) {
+ if (actionCode == ActionCode.ACTION_CLOSE) {
// Close
// End the processing of the current request, and stop any further
error = true;
}
- } else if (actionCode == ActionCode.ACTION_RESET) {
-
- // Reset response
-
- // Note: This must be called before the response is committed
-
- outputBuffer.reset();
-
- } else if (actionCode == ActionCode.ACTION_CUSTOM) {
-
- // Do nothing
-
} else if (actionCode == ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE) {
// Get remote host address
}
}
- } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) {
- ByteChunk body = (ByteChunk) param;
-
- InputFilter savedBody = new SavedRequestInputFilter(body);
- savedBody.setRequest(request);
-
- InternalAprInputBuffer internalBuffer = (InternalAprInputBuffer)
- request.getInputBuffer();
- internalBuffer.addActiveFilter(savedBody);
-
} else if (actionCode == ActionCode.ACTION_AVAILABLE) {
request.setAvailable(inputBuffer.available());
} else if (actionCode == ActionCode.ACTION_COMET_BEGIN) {
//no op
} else if (actionCode == ActionCode.ACTION_COMET_SETTIMEOUT) {
//no op
- } else if (actionCode == ActionCode.ACTION_ASYNC_START) {
- //TODO SERVLET3 - async
- async = true;
} else if (actionCode == ActionCode.ACTION_ASYNC_COMPLETE) {
//TODO SERVLET3 - async - that is bit hacky -
AtomicBoolean dispatch = (AtomicBoolean)param;
}
- /**
- * When committing the response, we have to validate the set of headers, as
- * well as setup the response filters.
- */
- protected void prepareResponse() {
-
- boolean entityBody = true;
- contentDelimitation = false;
-
- OutputFilter[] outputFilters = outputBuffer.getFilters();
-
- if (http09 == true) {
- // HTTP/0.9
- outputBuffer.addActiveFilter
- (outputFilters[Constants.IDENTITY_FILTER]);
- return;
- }
-
- int statusCode = response.getStatus();
- if ((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
+ @Override
+ protected boolean prepareSendfile(OutputFilter[] outputFilters) {
+ String fileName = (String) request.getAttribute("org.apache.tomcat.sendfile.filename");
+ if (fileName != null) {
+ // No entity body sent here
outputBuffer.addActiveFilter
(outputFilters[Constants.VOID_FILTER]);
contentDelimitation = true;
- }
-
- // Sendfile support
- if (endpoint.getUseSendfile()) {
- String fileName = (String) request.getAttribute("org.apache.tomcat.sendfile.filename");
- if (fileName != null) {
- // No entity body sent here
- outputBuffer.addActiveFilter
- (outputFilters[Constants.VOID_FILTER]);
- contentDelimitation = true;
- sendfileData = new AprEndpoint.SendfileData();
- sendfileData.fileName = fileName;
- sendfileData.start =
- ((Long) request.getAttribute("org.apache.tomcat.sendfile.start")).longValue();
- sendfileData.end =
- ((Long) request.getAttribute("org.apache.tomcat.sendfile.end")).longValue();
- }
- }
-
- // Check for compression
- boolean useCompression = false;
- if (entityBody && (compressionLevel > 0) && (sendfileData == null)) {
- useCompression = isCompressable();
- // Change content-length to -1 to force chunking
- if (useCompression) {
- response.setContentLength(-1);
- }
- }
-
- MimeHeaders headers = response.getMimeHeaders();
- if (!entityBody) {
- response.setContentLength(-1);
- } else {
- 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 != -1) {
- headers.setValue("Content-Length").setLong(contentLength);
- outputBuffer.addActiveFilter
- (outputFilters[Constants.IDENTITY_FILTER]);
- contentDelimitation = true;
- } else {
- if (entityBody && http11) {
- 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");
- // 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");
- }
- }
-
- // Add date header
- headers.setValue("Date").setString(FastHttpDateFormat.getCurrentDate());
-
- // FIXME: Add transfer encoding header
-
- if ((entityBody) && (!contentDelimitation)) {
- // Mark as close the connection after the request, and add the
- // connection: close header
- keepAlive = false;
- }
-
- // If we know that the request is bad this early, add the
- // Connection: close header.
- keepAlive = keepAlive && !statusDropsConnection(statusCode);
- if (!keepAlive) {
- headers.addValue(Constants.CONNECTION).setString(Constants.CLOSE);
- } else if (!http11 && !error) {
- headers.addValue(Constants.CONNECTION).setString(Constants.KEEPALIVE);
- }
-
- // Build the response header
- outputBuffer.sendStatus();
-
- // Add server header
- if (server != null) {
- // Always overrides anything the app might set
- headers.setValue("Server").setString(server);
- } else if (headers.getValue("Server") == null) {
- // If app didn't set the header, use the default
- outputBuffer.write(Constants.SERVER_BYTES);
- }
-
- int size = headers.size();
- for (int i = 0; i < size; i++) {
- outputBuffer.sendHeader(headers.getName(i), headers.getValue(i));
- }
- outputBuffer.endHeaders();
-
+ sendfileData = new AprEndpoint.SendfileData();
+ sendfileData.fileName = fileName;
+ sendfileData.start =
+ ((Long) request.getAttribute("org.apache.tomcat.sendfile.start")).longValue();
+ sendfileData.end =
+ ((Long) request.getAttribute("org.apache.tomcat.sendfile.end")).longValue();
+ return true;
+ }
+ return false;
}
-
@Override
protected AbstractInputBuffer getInputBuffer() {
return inputBuffer;
import org.apache.coyote.RequestInfo;
import org.apache.coyote.Response;
import org.apache.coyote.http11.filters.BufferedInputFilter;
-import org.apache.coyote.http11.filters.SavedRequestInputFilter;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.buf.Ascii;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.HexUtils;
import org.apache.tomcat.util.buf.MessageBytes;
-import org.apache.tomcat.util.http.FastHttpDateFormat;
import org.apache.tomcat.util.http.MimeHeaders;
+import org.apache.tomcat.util.net.AbstractEndpoint;
import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
import org.apache.tomcat.util.net.NioChannel;
import org.apache.tomcat.util.net.NioEndpoint;
protected boolean cometClose = false;
/**
- * Async used
- */
- protected boolean async = false;
-
- /**
* SSL enabled ?
*/
protected boolean ssl = false;
// ------------------------------------------------------------- Properties
+ /**
+ * Expose the endpoint.
+ */
+ @Override
+ protected AbstractEndpoint getEndpoint() {
+ return endpoint;
+ }
// --------------------------------------------------------- Public Methods
}
- public void endRequest() {
-
- // Finish the handling of the request
- try {
- inputBuffer.endRequest();
- } catch (IOException e) {
- error = true;
- } catch (Throwable t) {
- log.error(sm.getString("http11processor.request.finish"), t);
- // 500 - Internal Server Error
- response.setStatus(500);
- adapter.log(request, response, 0);
- error = true;
- }
- try {
- outputBuffer.endRequest();
- } catch (IOException e) {
- error = true;
- } catch (Throwable t) {
- log.error(sm.getString("http11processor.response.finish"), t);
- error = true;
- }
-
- }
-
-
public void recycle() {
inputBuffer.recycle();
outputBuffer.recycle();
* @param param Action parameter
*/
@Override
- public void action(ActionCode actionCode, Object param) {
-
- if (actionCode == ActionCode.ACTION_COMMIT) {
- // Commit current response
-
- if (response.isCommitted())
- return;
-
- // Validate and write response headers
-
- try {
- prepareResponse();
- outputBuffer.commit();
- } catch (IOException e) {
- // Set error flag
- error = true;
- }
-
- } else if (actionCode == ActionCode.ACTION_ACK) {
-
- // Acknowledge request
-
- // Send a 100 status back if it makes sense (response not committed
- // yet, and client specified an expectation for 100-continue)
-
- if ((response.isCommitted()) || !expectation)
- return;
-
- inputBuffer.setSwallowInput(true);
- try {
- outputBuffer.sendAck();
- } catch (IOException e) {
- // Set error flag
- error = true;
- }
-
- } else if (actionCode == ActionCode.ACTION_CLIENT_FLUSH) {
-
- try {
- outputBuffer.flush();
- } catch (IOException e) {
- // Set error flag
- error = true;
- response.setErrorException(e);
- }
+ public void actionInternal(ActionCode actionCode, Object param) {
- } else if (actionCode == ActionCode.ACTION_CLOSE) {
+ if (actionCode == ActionCode.ACTION_CLOSE) {
// Close
// End the processing of the current request, and stop any further
error = true;
}
- } else if (actionCode == ActionCode.ACTION_RESET) {
-
- // Reset response
-
- // Note: This must be called before the response is committed
-
- outputBuffer.reset();
-
- } else if (actionCode == ActionCode.ACTION_CUSTOM) {
-
- // Do nothing
-
} else if (actionCode == ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE) {
// Get remote host address
}
}
- } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) {
- ByteChunk body = (ByteChunk) param;
-
- InputFilter savedBody = new SavedRequestInputFilter(body);
- savedBody.setRequest(request);
-
- InternalNioInputBuffer internalBuffer = (InternalNioInputBuffer)
- request.getInputBuffer();
- internalBuffer.addActiveFilter(savedBody);
-
} else if (actionCode == ActionCode.ACTION_AVAILABLE) {
request.setAvailable(inputBuffer.available());
} else if (actionCode == ActionCode.ACTION_COMET_BEGIN) {
RequestInfo rp = request.getRequestProcessor();
if ( rp.getStage() != org.apache.coyote.Constants.STAGE_SERVICE ) //async handling
attach.setTimeout(timeout);
- } else if (actionCode == ActionCode.ACTION_ASYNC_START) {
- //TODO SERVLET3 - async
- async = true;
} else if (actionCode == ActionCode.ACTION_ASYNC_COMPLETE) {
//TODO SERVLET3 - async
AtomicBoolean dispatch = (AtomicBoolean)param;
}
- /**
- * When committing the response, we have to validate the set of headers, as
- * well as setup the response filters.
- */
- protected void prepareResponse() {
-
- boolean entityBody = true;
- contentDelimitation = false;
-
- OutputFilter[] outputFilters = outputBuffer.getFilters();
-
- if (http09 == true) {
- // HTTP/0.9
- outputBuffer.addActiveFilter
- (outputFilters[Constants.IDENTITY_FILTER]);
- return;
- }
-
- int statusCode = response.getStatus();
- if ((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
- if (this.endpoint.getUseSendfile()) {
- String fileName = (String) request.getAttribute("org.apache.tomcat.sendfile.filename");
- if (fileName != null) {
- // No entity body sent here
- outputBuffer.addActiveFilter(outputFilters[Constants.VOID_FILTER]);
- contentDelimitation = true;
- sendfileData = new NioEndpoint.SendfileData();
- sendfileData.fileName = fileName;
- sendfileData.pos = ((Long) request.getAttribute("org.apache.tomcat.sendfile.start")).longValue();
- sendfileData.length = ((Long) request.getAttribute("org.apache.tomcat.sendfile.end")).longValue() - sendfileData.pos;
- }
- }
-
-
-
- // Check for compression
- boolean useCompression = false;
- if (entityBody && (compressionLevel > 0) && (sendfileData == null)) {
- useCompression = isCompressable();
- // Change content-length to -1 to force chunking
- if (useCompression) {
- response.setContentLength(-1);
- }
- }
-
- MimeHeaders headers = response.getMimeHeaders();
- if (!entityBody) {
- response.setContentLength(-1);
- } else {
- 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 != -1) {
- headers.setValue("Content-Length").setLong(contentLength);
- outputBuffer.addActiveFilter
- (outputFilters[Constants.IDENTITY_FILTER]);
+ @Override
+ protected boolean prepareSendfile(OutputFilter[] outputFilters) {
+ String fileName = (String) request.getAttribute("org.apache.tomcat.sendfile.filename");
+ if (fileName != null) {
+ // No entity body sent here
+ outputBuffer.addActiveFilter(outputFilters[Constants.VOID_FILTER]);
contentDelimitation = true;
- } else {
- if (entityBody && http11) {
- 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");
- // 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");
- }
+ sendfileData = new NioEndpoint.SendfileData();
+ sendfileData.fileName = fileName;
+ sendfileData.pos = ((Long) request.getAttribute("org.apache.tomcat.sendfile.start")).longValue();
+ sendfileData.length = ((Long) request.getAttribute("org.apache.tomcat.sendfile.end")).longValue() - sendfileData.pos;
+ return true;
}
-
- // Add date header
- headers.setValue("Date").setString(FastHttpDateFormat.getCurrentDate());
-
- // FIXME: Add transfer encoding header
-
- if ((entityBody) && (!contentDelimitation)) {
- // Mark as close the connection after the request, and add the
- // connection: close header
- keepAlive = false;
- }
-
- // If we know that the request is bad this early, add the
- // Connection: close header.
- keepAlive = keepAlive && !statusDropsConnection(statusCode);
- if (!keepAlive) {
- headers.addValue(Constants.CONNECTION).setString(Constants.CLOSE);
- } else if (!http11 && !error) {
- headers.addValue(Constants.CONNECTION).setString(Constants.KEEPALIVE);
- }
-
- // Build the response header
- outputBuffer.sendStatus();
-
- // Add server header
- if (server != null) {
- // Always overrides anything the app might set
- headers.setValue("Server").setString(server);
- } else if (headers.getValue("Server") == null) {
- // If app didn't set the header, use the default
- outputBuffer.write(Constants.SERVER_BYTES);
- }
-
- int size = headers.size();
- for (int i = 0; i < size; i++) {
- outputBuffer.sendHeader(headers.getName(i), headers.getValue(i));
- }
- outputBuffer.endHeaders();
-
+ return false;
}
-
/**
* Specialized utility method: find a sequence of lower case bytes inside
* a ByteChunk.
import org.apache.coyote.RequestInfo;
import org.apache.coyote.Response;
import org.apache.coyote.http11.filters.BufferedInputFilter;
-import org.apache.coyote.http11.filters.SavedRequestInputFilter;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.HexUtils;
import org.apache.tomcat.util.buf.MessageBytes;
-import org.apache.tomcat.util.http.FastHttpDateFormat;
import org.apache.tomcat.util.http.MimeHeaders;
+import org.apache.tomcat.util.net.AbstractEndpoint;
import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
import org.apache.tomcat.util.net.JIoEndpoint;
import org.apache.tomcat.util.net.SSLSupport;
/**
- * Async used
- */
- protected boolean async = false;
-
-
- /**
* State flag.
*/
protected boolean started = false;
// --------------------------------------------------------- Public Methods
+
+ /**
+ * Expose the endpoint.
+ */
+ @Override
+ protected AbstractEndpoint getEndpoint() {
+ return this.endpoint;
+ }
+
/**
* Set the SSL information for this HTTP connection.
*/
}
- public void endRequest() {
-
- // Finish the handling of the request
- try {
- inputBuffer.endRequest();
- } catch (IOException e) {
- error = true;
- } catch (Throwable t) {
- log.error(sm.getString("http11processor.request.finish"), t);
- // 500 - Internal Server Error
- response.setStatus(500);
- adapter.log(request, response, 0);
- error = true;
- }
- try {
- outputBuffer.endRequest();
- } catch (IOException e) {
- error = true;
- } catch (Throwable t) {
- log.error(sm.getString("http11processor.response.finish"), t);
- error = true;
- }
-
- }
-
-
public void recycle() {
// Recycle
inputBuffer.recycle();
* @param param Action parameter
*/
@Override
- public void action(ActionCode actionCode, Object param) {
-
- if (actionCode == ActionCode.ACTION_COMMIT) {
- // Commit current response
+ public void actionInternal(ActionCode actionCode, Object param) {
- if (response.isCommitted())
- return;
-
- // Validate and write response headers
- prepareResponse();
- try {
- outputBuffer.commit();
- } catch (IOException e) {
- // Set error flag
- error = true;
- }
-
- } else if (actionCode == ActionCode.ACTION_ACK) {
-
- // Acknowledge request
-
- // Send a 100 status back if it makes sense (response not committed
- // yet, and client specified an expectation for 100-continue)
-
- if ((response.isCommitted()) || !expectation)
- return;
-
- inputBuffer.setSwallowInput(true);
- try {
- outputBuffer.sendAck();
- } catch (IOException e) {
- // Set error flag
- error = true;
- }
-
- } else if (actionCode == ActionCode.ACTION_CLIENT_FLUSH) {
-
- try {
- outputBuffer.flush();
- } catch (IOException e) {
- // Set error flag
- error = true;
- response.setErrorException(e);
- }
-
- } else if (actionCode == ActionCode.ACTION_CLOSE) {
+ if (actionCode == ActionCode.ACTION_CLOSE) {
// Close
async = false;
// End the processing of the current request, and stop any further
error = true;
}
- } else if (actionCode == ActionCode.ACTION_RESET) {
-
- // Reset response
-
- // Note: This must be called before the response is committed
-
- outputBuffer.reset();
-
- } else if (actionCode == ActionCode.ACTION_CUSTOM) {
-
- // Do nothing
-
} else if (actionCode == ActionCode.ACTION_START) {
started = true;
log.warn(sm.getString("http11processor.socket.ssl"), e);
}
}
- } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) {
- ByteChunk body = (ByteChunk) param;
-
- InputFilter savedBody = new SavedRequestInputFilter(body);
- savedBody.setRequest(request);
-
- InternalInputBuffer internalBuffer = (InternalInputBuffer)
- request.getInputBuffer();
- internalBuffer.addActiveFilter(savedBody);
- } else if (actionCode == ActionCode.ACTION_ASYNC_START) {
- //TODO SERVLET3 - async
- async = true;
} else if (actionCode == ActionCode.ACTION_ASYNC_COMPLETE) {
//TODO SERVLET3 - async
AtomicBoolean dispatch = (AtomicBoolean)param;
}
-
- /**
- * When committing the response, we have to validate the set of headers, as
- * well as setup the response filters.
- */
- protected void prepareResponse() {
-
- boolean entityBody = true;
- contentDelimitation = false;
-
- OutputFilter[] outputFilters = outputBuffer.getFilters();
-
- if (http09 == true) {
- // HTTP/0.9
- outputBuffer.addActiveFilter
- (outputFilters[Constants.IDENTITY_FILTER]);
- return;
- }
-
- int statusCode = response.getStatus();
- if ((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;
- }
-
- // Check for compression
- boolean useCompression = false;
- if (entityBody && (compressionLevel > 0)) {
- useCompression = isCompressable();
-
- // Change content-length to -1 to force chunking
- if (useCompression) {
- response.setContentLength(-1);
- }
- }
-
- MimeHeaders headers = response.getMimeHeaders();
- if (!entityBody) {
- response.setContentLength(-1);
- } else {
- 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 != -1) {
- headers.setValue("Content-Length").setLong(contentLength);
- outputBuffer.addActiveFilter
- (outputFilters[Constants.IDENTITY_FILTER]);
- contentDelimitation = true;
- } else {
- if (entityBody && http11) {
- 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");
- // 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");
- }
- }
-
- // Add date header
- headers.setValue("Date").setString(FastHttpDateFormat.getCurrentDate());
-
- // FIXME: Add transfer encoding header
-
- if ((entityBody) && (!contentDelimitation)) {
- // Mark as close the connection after the request, and add the
- // connection: close header
- keepAlive = false;
- }
-
- // If we know that the request is bad this early, add the
- // Connection: close header.
- keepAlive = keepAlive && !statusDropsConnection(statusCode);
- if (!keepAlive) {
- headers.addValue(Constants.CONNECTION).setString(Constants.CLOSE);
- } else if (!http11 && !error) {
- headers.addValue(Constants.CONNECTION).setString(Constants.KEEPALIVE);
- }
-
- // Build the response header
- outputBuffer.sendStatus();
-
- // Add server header
- if (server != null) {
- // Always overrides anything the app might set
- headers.setValue("Server").setString(server);
- } else if (headers.getValue("Server") == null) {
- // If app didn't set the header, use the default
- outputBuffer.write(Constants.SERVER_BYTES);
- }
-
- int size = headers.size();
- for (int i = 0; i < size; i++) {
- outputBuffer.sendHeader(headers.getName(i), headers.getValue(i));
- }
- outputBuffer.endHeaders();
-
+ @Override
+ protected boolean prepareSendfile(OutputFilter[] outputFilters) {
+ // Should never, ever call this code
+ Exception e = new Exception();
+ log.error(sm.getString("http11processor.neverused"), e);
+ return false;
}
-
/**
* Parse host.
*/
http11processor.filter.unknown=Unknown filter {0}
http11processor.filter.error=Error intializing filter {0}
http11processor.header.parse=Error parsing HTTP request header
+http11processor.neverused=This method should never be used
http11processor.request.prepare=Error preparing request
http11processor.request.process=Error processing request
http11processor.request.finish=Error finishing request
}
protected abstract Log getLog();
+ public abstract boolean getUseSendfile();
// -------------------- SSL related properties --------------------
public ServerSocketFactory getServerSocketFactory() { return serverSocketFactory; }
- // ------------------------------------------------ Handler Inner Interface
+ /**
+ * Is sendfile available
+ */
+ @Override
+ public boolean getUseSendfile() {
+ // Not supported
+ return false;
+ }
+
+ // ------------------------------------------------ Handler Inner Interface
/**
* Bare bones interface used for socket processing. Per thread data is to be