remm 01/12/09 14:10:47 Modified: http11/src/java/org/apache/coyote/http11 Constants.java Http11Connector.java InternalOutputBuffer.java http11/src/java/org/apache/coyote/http11/filters IdentityInputFilter.java Log: - Request parsing. - The initial code is toString() happy. This can be optimized, but it is unclear at the moment if this would have a very significant impact on performance (as there are only a few String creations). - The connector is almost at the stage where it will be testable. Revision Changes Path 1.3 +24 -0 jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Constants.java Index: Constants.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Constants.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- Constants.java 2001/10/01 01:20:42 1.2 +++ Constants.java 2001/12/09 22:10:47 1.3 @@ -143,4 +143,28 @@ public static final String CRLF = "\r\n"; + /** + * Indetity filters (input and output). + */ + public static final int IDENTITY_FILTER = 0; + + + /** + * Chunked filters (input and output). + */ + public static final int CHUNKED_FILTER = 1; + + + /** + * HTTP/1.0. + */ + public static final String HTTP_10 = "HTTP/1.0"; + + + /** + * HTTP/1.1. + */ + public static final String HTTP_11 = "HTTP/1.1"; + + } 1.4 +259 -10 jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Http11Connector.java Index: Http11Connector.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Http11Connector.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- Http11Connector.java 2001/12/03 06:09:30 1.3 +++ Http11Connector.java 2001/12/09 22:10:47 1.4 @@ -77,7 +77,11 @@ import org.apache.coyote.Request; import org.apache.coyote.Response; +import org.apache.coyote.http11.filters.IdentityInputFilter; +import org.apache.coyote.http11.filters.IdentityOutputFilter; +import org.apache.coyote.http11.filters.VoidOutputFilter; + /** * Processes HTTP requests. * @@ -103,6 +107,8 @@ outputBuffer = new InternalOutputBuffer(response); response.setOutputBuffer(outputBuffer); + initializeFilters(); + } @@ -139,10 +145,93 @@ protected InternalOutputBuffer outputBuffer = null; + /** + * Error flag. + */ + protected boolean error = false; + + + /** + * Keep-alive. + */ + protected boolean keepAlive = true; + + + /** + * Content delimitator for the request (if false, the connection will + * be closed at the end of the request). + */ + protected boolean contentDelimitation = true; + + + /** + * List of restricted user agents. + */ + protected String[] restrictedUserAgents = null; + + // --------------------------------------------------------- Public Methods /** + * Add input or output filter. + * + * @param className class name of the filter + */ + public void addFilter(String className) { + try { + Class clazz = Class.forName(className); + Object obj = clazz.newInstance(); + if (obj instanceof InputFilter) { + inputBuffer.addFilter((InputFilter) obj); + } else if (obj instanceof OutputFilter) { + outputBuffer.addFilter((OutputFilter) obj); + } else { + // Not a valid filter: log and ignore + } + } catch (Exception e) { + // Log and ignore + } + } + + + /** + * Add restricted user-agent (which will downgrade the connector + * to HTTP/1.0 mode). The user agent String given will be exactly matched + * to the user-agent header submitted by the client. + * + * @param userAgent user-agent string + */ + public void addRestrictedUserAgent(String userAgent) { + if (restrictedUserAgents == null) + restrictedUserAgents = new String[0]; + String[] results = new String[restrictedUserAgents.length + 1]; + for (int i = 0; i < restrictedUserAgents.length; i++) + results[i] = restrictedUserAgents[i]; + results[restrictedUserAgents.length] = userAgent; + restrictedUserAgents = results; + } + + + /** + * Set restricted user agent list (this method is best when used with + * a large number of connectors, where it would be better to have all of + * them referenced a single array). + */ + public void setRestrictedUserAgents(String[] restrictedUserAgents) { + this.restrictedUserAgents = restrictedUserAgents; + } + + + /** + * Return the list of restricted user agents. + */ + public String[] findRestrictedUserAgents() { + return (restrictedUserAgents); + } + + + /** * Process pipelined HTTP requests using the specified input and output * streams. * @@ -158,12 +247,13 @@ inputBuffer.setInputStream(input); outputBuffer.setOutputStream(output); - // Ok flag - boolean ok = true; + // Error flag + error = false; + keepAlive = true; // TEMP boolean stopped = false; - while (!stopped && ok) { + while (!stopped && !error && keepAlive) { try { inputBuffer.parseRequestLine(); @@ -171,13 +261,14 @@ inputBuffer.parseHeaders(); } catch (EOFException e) { - ok = false; + error = true; + break; } catch (InterruptedIOException e) { //HttpServletResponse.SC_BAD_REQUEST - ok = false; + error = true; } catch (Exception e) { //SC_BAD_REQUEST - ok = false; + error = true; } // Setting up filters, and parse some request headers @@ -187,20 +278,20 @@ try { adapter.service(request, response); } catch (InterruptedIOException e) { - ok = false; + error = true; } catch (Throwable t) { // ISE - ok = false; + error = true; } // Finish the handling of the request try { outputBuffer.endRequest(); } catch (IOException e) { - ok = false; + error = true; } catch (Throwable t) { // Problem ... - ok = false; + error = true; } // FIXME: Next request @@ -229,6 +320,12 @@ // Validate and write response headers prepareResponse(); + try { + outputBuffer.commit(); + } catch (IOException e) { + // Log the error, and set error flag + error = true; + } } else if (actionCode == ActionCode.ACTION_ACK) { @@ -244,6 +341,13 @@ // End the processing of the current request, and stop any further // transactions with the client + try { + outputBuffer.endRequest(); + } catch (IOException e) { + // Log the error, and set error flag + error = true; + } + } else if (actionCode == ActionCode.ACTION_RESET) { // Reset response @@ -290,8 +394,99 @@ */ protected void prepareRequest() { + boolean http11 = true; + contentDelimitation = false; + + MessageBytes protocol = request.protocol(); + if (protocol.equals(Constants.HTTP_11)) { + http11 = true; + } else if (protocol.equals(Constants.HTTP_10)) { + http11 = false; + keepAlive = false; + } else { + // Unsupported protocol + error = true; + // FIXME: Find right status code + } + + // Check connection header + MessageBytes connectionValueMB = + request.getMimeHeaders().getValue("connection"); + String connectionValue = + connectionValueMB.toString().toLowerCase().trim(); + // FIXME: This can be a comma separated list + if (connectionValue.equals("close")) { + keepAlive = false; + } else if (connectionValue.equals("keep-alive")) { + keepAlive = true; + } + + // Check user-agent header + MessageBytes userAgentValueMB = + request.getMimeHeaders().getValue("user-agent"); + // Check in the restricted list, and adjust the http11 + // and keepAlive flags accordingly + if ((restrictedUserAgents != null) && ((http11) || (keepAlive))) { + String userAgentValue = userAgentValueMB.toString(); + for (int i = 0; i < restrictedUserAgents.length; i++) { + if (restrictedUserAgents[i].equals(userAgentValue)) { + http11 = false; + keepAlive = false; + } + } + } + + InputFilter[] inputFilters = inputBuffer.getFilters(); + + // Parse content-length header + int contentLength = request.getContentLength(); + if (contentLength != -1) { + inputBuffer.addActiveFilter + (inputFilters[Constants.IDENTITY_FILTER]); + contentDelimitation = true; + } + // Parse transfer-encoding header + MessageBytes transferEncodingValueMB = null; + if (http11) + transferEncodingValueMB = + request.getMimeHeaders().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).toLowerCase().trim(); + if (!addInputFilter(inputFilters, encodingName)) { + // Unsupported transfer encoding + error = true; + // FIXME: Find right status code + } + startPos = commaPos + 1; + commaPos = transferEncodingValue.indexOf(',', startPos); + } + encodingName = transferEncodingValue.substring(startPos) + .toLowerCase().trim(); + if (!addInputFilter(inputFilters, encodingName)) { + // Unsupported transfer encoding + error = true; + // FIXME: Find right status code + } + } + + // Check host header + if (http11 && (request.getMimeHeaders().getValue("host") == null)) { + error = true; + // Send 400: Bad request + response.setStatus(400); + } + if (!contentDelimitation) + keepAlive = false; + } @@ -301,8 +496,62 @@ */ protected void prepareResponse() { + contentDelimitation = false; + + + + if (!contentDelimitation) { + // Mark as close the connection after the request, and add the + // connection: close header + keepAlive = false; + } + + } + + + /** + * Initialize standard input and output filters. + */ + protected void initializeFilters() { + // Create and add the identity filters. + inputBuffer.addFilter(new IdentityInputFilter()); + outputBuffer.addFilter(new IdentityOutputFilter()); + // Create and add the chunked filters. + // FIXME + + // Create and add the void filter. + outputBuffer.addFilter(new VoidOutputFilter()); + + } + + + /** + * Add an input filter to the current request. + * + * @return false if the encoding was not found (which would mean it is + * unsupported) + */ + protected boolean addInputFilter(InputFilter[] inputFilters, + String encodingName) { + if (encodingName.equals("identity")) { + // Skip + } else if (encodingName.equals("chunked")) { + inputBuffer.addActiveFilter + (inputFilters[Constants.CHUNKED_FILTER]); + contentDelimitation = true; + } else { + for (int i = 2; i < inputFilters.length; i++) { + if (inputFilters[i].getEncodingName() + .toString().equals(encodingName)) { + inputBuffer.addActiveFilter(inputFilters[i]); + return true; + } + } + return false; + } + return true; } 1.5 +0 -4 jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/InternalOutputBuffer.java Index: InternalOutputBuffer.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/InternalOutputBuffer.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- InternalOutputBuffer.java 2001/12/04 06:33:06 1.4 +++ InternalOutputBuffer.java 2001/12/09 22:10:47 1.5 @@ -341,8 +341,6 @@ // set the filters accordingly. response.action(ActionCode.ACTION_COMMIT, null); - commit(); - } for (int i = lastActiveFilter; i >= 0; i--) { @@ -465,8 +463,6 @@ // then validate the headers, send them (using sendHeaders) and // set the filters accordingly. response.action(ActionCode.ACTION_COMMIT, null); - - commit(); } 1.5 +1 -1 jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/filters/IdentityInputFilter.java Index: IdentityInputFilter.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/filters/IdentityInputFilter.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- IdentityInputFilter.java 2001/12/06 06:46:46 1.4 +++ IdentityInputFilter.java 2001/12/09 22:10:47 1.5 @@ -72,7 +72,7 @@ * * @author Remy Maucherat */ -public class IdentityInputFilter implements InputBuffer { +public class IdentityInputFilter implements InputFilter { // -------------------------------------------------------------- Constants
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>