You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2002/01/15 17:00:10 UTC

cvs commit: jakarta-tomcat-connectors/http11/src/test/java/org/apache/coyote/http11 FileTester.java

remm        02/01/15 08:00:10

  Modified:    http11/src/test/java/org/apache/coyote/http11
                        FileTester.java
  Added:       http11/src/java/org/apache/coyote/http11
                        Http11Processor.java
  Removed:     http11/src/java/org/apache/coyote/http11
                        Http11Connector.java
  Log:
  - Rename Connector -> Processor, since it more accurately represents the interface
    function, and will avoid lots of name conflicts.
  
  Revision  Changes    Path
  1.1                  jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Http11Processor.java
  
  Index: Http11Processor.java
  ===================================================================
  /*
   * ====================================================================
   * 
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  
  package org.apache.coyote.http11;
  
  import java.io.EOFException;
  import java.io.InterruptedIOException;
  import java.io.InputStream;
  import java.io.IOException;
  import java.io.OutputStream;
  
  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.coyote.ActionHook;
  import org.apache.coyote.ActionCode;
  import org.apache.coyote.Adapter;
  import org.apache.coyote.InputBuffer;
  import org.apache.coyote.OutputBuffer;
  import org.apache.coyote.Processor;
  import org.apache.coyote.Request;
  import org.apache.coyote.Response;
  
  import org.apache.coyote.http11.filters.ChunkedInputFilter;
  import org.apache.coyote.http11.filters.ChunkedOutputFilter;
  import org.apache.coyote.http11.filters.IdentityInputFilter;
  import org.apache.coyote.http11.filters.IdentityOutputFilter;
  import org.apache.coyote.http11.filters.VoidInputFilter;
  import org.apache.coyote.http11.filters.VoidOutputFilter;
  
  
  /**
   * Processes HTTP requests.
   * 
   * @author Remy Maucherat
   */
  public class Http11Processor implements Processor, ActionHook {
  
  
      // ----------------------------------------------------------- Constructors
  
  
      /**
       * Default constructor.
       */
      public Http11Processor() {
  
          request = new Request();
          inputBuffer = new InternalInputBuffer(request);
          request.setInputBuffer(inputBuffer);
  
          response = new Response();
          response.setHook(this);
          outputBuffer = new InternalOutputBuffer(response);
          response.setOutputBuffer(outputBuffer);
  
          initializeFilters();
  
      }
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * Associated adapter.
       */
      protected Adapter adapter = null;
  
  
      /**
       * Request object.
       */
      protected Request request = null;
  
  
      /**
       * Response object.
       */
      protected Response response = null;
  
  
      /**
       * Input.
       */
      protected InternalInputBuffer inputBuffer = null;
  
  
      /**
       * Output.
       */
      protected InternalOutputBuffer outputBuffer = null;
  
  
      /**
       * Error flag.
       */
      protected boolean error = false;
  
  
      /**
       * Keep-alive.
       */
      protected boolean keepAlive = true;
  
  
      /**
       * HTTP/1.1 flag.
       */
      protected boolean http11 = 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.
       * 
       * @param inputStream stream from which the HTTP requests will be read
       * @param outputStream stream which will be used to output the HTTP 
       * responses
       * @throws IOException error during an I/O operation
       */
      public void process(InputStream input, OutputStream output)
          throws IOException {
  
          // Setting up the I/O
          inputBuffer.setInputStream(input);
          outputBuffer.setOutputStream(output);
  
          // Error flag
          error = false;
          keepAlive = true;
          // TEMP
          boolean stopped = false;
  
          while (!stopped && !error && keepAlive) {
  
              try {
                  inputBuffer.parseRequestLine();
                  // Check for HTTP/0.9
                  
                  inputBuffer.parseHeaders();
              } catch (EOFException e) {
                  error = true;
                  break;
              } catch (InterruptedIOException e) {
                  e.printStackTrace();
                  //HttpServletResponse.SC_BAD_REQUEST
                  error = true;
              } catch (Exception e) {
                  e.printStackTrace();
                  //SC_BAD_REQUEST
                  error = true;
              }
  
              // Setting up filters, and parse some request headers
              prepareRequest();
  
              // Process the request in the adapter
              try {
                  adapter.service(request, response);
              } catch (InterruptedIOException e) {
                  e.printStackTrace();
                  error = true;
              } catch (Throwable t) {
                  // ISE
                  t.printStackTrace();
                  error = true;
              }
  
              // Finish the handling of the request
              try {
                  inputBuffer.endRequest();
              } catch (IOException e) {
                  e.printStackTrace();
                  error = true;
              } catch (Throwable t) {
                  // Problem ...
                  t.printStackTrace();
                  error = true;
              }
              try {
                  outputBuffer.endRequest();
              } catch (IOException e) {
                  e.printStackTrace();
                  error = true;
              } catch (Throwable t) {
                  // Problem ...
                  t.printStackTrace();
                  error = true;
              }
  
              // Next request
              inputBuffer.nextRequest();
              outputBuffer.nextRequest();
  
          }
  
          // Recycle
          inputBuffer.recycle();
          outputBuffer.recycle();
  
      }
  
  
      // ----------------------------------------------------- ActionHook Methods
  
  
      /**
       * Send an action to the connector.
       * 
       * @param actionCode Type of the action
       * @param param Action parameter
       */
      public void action(ActionCode actionCode, Object param) {
  
          if (actionCode == ActionCode.ACTION_COMMIT) {
  
              // Commit current response
  
              // Validate and write response headers
              prepareResponse();
              try {
                  outputBuffer.commit();
              } catch (IOException e) {
                  // Log the error, and set error flag
                  e.printStackTrace();
                  error = true;
              }
  
          } else if (actionCode == ActionCode.ACTION_ACK) {
  
              // Acknowlege request
  
              // Send a 100 status back if it makes sense (response not committed
              // yet, and client specified an expectation for 100-continue)
  
              try {
                  outputBuffer.sendAck();
              } catch (IOException e) {
                  // Log the error, and set error flag
                  e.printStackTrace();
                  error = true;
              }
  
          } else if (actionCode == ActionCode.ACTION_CLOSE) {
  
              // Close
  
              // 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
                  e.printStackTrace();
                  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
  
          }
  
      }
  
  
      // ------------------------------------------------------ Connector Methods
  
  
      /**
       * Set the associated adapter.
       * 
       * @param adapter the new adapter
       */
      public void setAdapter(Adapter adapter) {
          this.adapter = adapter;
      }
  
  
      /**
       * Get the associated adapter.
       * 
       * @return the associated adapter
       */
      public Adapter getAdapter() {
          return adapter;
      }
  
  
      // ------------------------------------------------------ Protected Methods
  
  
      /**
       * After reading the request headers, we have to setup the request filters.
       */
      protected void prepareRequest() {
  
          http11 = true;
          contentDelimitation = false;
  
          MessageBytes protocolMB = request.protocol();
          if (protocolMB.equals(Constants.HTTP_11)) {
              http11 = true;
          } else if (protocolMB.equals(Constants.HTTP_10)) {
              http11 = false;
              keepAlive = false;
          } else if (protocolMB.equals("")) {
              // HTTP/0.9
              http11 = false;
              keepAlive = false;
          } else {
              // Unsupported protocol
              http11 = false;
              error = true;
              // Send 505; Unsupported HTTP version
              response.setStatus(505);
          }
  
          MessageBytes methodMB = request.method();
  
          // Check connection header
          MessageBytes connectionValueMB = 
              request.getMimeHeaders().getValue("connection");
          if (connectionValueMB != null) {
              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;
                      // Send 501; Unimplemented
                      response.setStatus(501);
                  }
                  startPos = commaPos + 1;
                  commaPos = transferEncodingValue.indexOf(',', startPos);
              }
              encodingName = transferEncodingValue.substring(startPos)
                  .toLowerCase().trim();
              if (!addInputFilter(inputFilters, encodingName)) {
                  // Unsupported transfer encoding
                  error = true;
                  // Send 501; Unimplemented
                  response.setStatus(501);
              }
          }
  
          // Check host header
          if (http11 && (request.getMimeHeaders().getValue("host") == null)) {
              error = true;
              // Send 400: Bad request
              response.setStatus(400);
          }
  
          if (!contentDelimitation) {
              // If method is GET or HEAD, prevent from reading any content
              if ((methodMB.equals("GET"))
                  || (methodMB.equals("HEAD"))
                  || (methodMB.equals("TRACE"))) {
                  inputBuffer.addActiveFilter
                      (inputFilters[Constants.VOID_FILTER]);
                  contentDelimitation = true;
              }
          }
  
          if (!contentDelimitation)
              keepAlive = false;
  
      }
  
  
      /**
       * When committing the response, we have to validate the set of headers, as
       * well as setup the response filters.
       */
      protected void prepareResponse() {
  
          boolean http09 = false;
          boolean entityBody = true;
          contentDelimitation = false;
  
          OutputFilter[] outputFilters = outputBuffer.getFilters();
  
          MessageBytes protocolMB = request.protocol();
          if (protocolMB.equals(Constants.HTTP_11)) {
              http11 = true;
          } else if (protocolMB.equals(Constants.HTTP_10)) {
              http11 = false;
          } else if (protocolMB.equals("")) {
              // 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;
          }
  
          MessageBytes methodMB = request.method();
          if (methodMB.equals("HEAD")) {
              // No entity body
              outputBuffer.addActiveFilter
                  (outputFilters[Constants.VOID_FILTER]);
          }
  
          int contentLength = response.getContentLength();
          if (contentLength != -1) {
              outputBuffer.addActiveFilter
                  (outputFilters[Constants.IDENTITY_FILTER]);
              contentDelimitation = true;
          } else {
              if (entityBody && http11) {
                  outputBuffer.addActiveFilter
                      (outputFilters[Constants.CHUNKED_FILTER]);
                  contentDelimitation = true;
                  response.addHeader("Transfer-Encoding", "chunked");
              }
          }
  
          // Add date header
          response.addHeader("Date", FastHttpDateFormat.getCurrentDate());
  
          // Add server header
          response.addHeader("Server", Constants.SERVER);
  
          // Add transfer encoding header
          // FIXME
  
          if ((entityBody) && (!contentDelimitation)) {
              // Mark as close the connection after the request, and add the 
              // connection: close header
              keepAlive = false;
          }
  
          if (!keepAlive) {
              response.addHeader("Connection", "close");
          }
  
          // Build the response header
          outputBuffer.sendStatus();
  
          MimeHeaders headers = response.getMimeHeaders();
          int size = headers.size();
          for (int i = 0; i < size; i++) {
              outputBuffer.sendHeader(headers.getName(i), headers.getValue(i));
          }
          outputBuffer.endHeaders();
  
      }
  
  
      /**
       * 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.
          inputBuffer.addFilter(new ChunkedInputFilter());
          outputBuffer.addFilter(new ChunkedOutputFilter());
  
          // Create and add the void filters.
          inputBuffer.addFilter(new VoidInputFilter());
          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.3       +12 -12    jakarta-tomcat-connectors/http11/src/test/java/org/apache/coyote/http11/FileTester.java
  
  Index: FileTester.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-connectors/http11/src/test/java/org/apache/coyote/http11/FileTester.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- FileTester.java	14 Jan 2002 00:21:27 -0000	1.2
  +++ FileTester.java	15 Jan 2002 16:00:10 -0000	1.3
  @@ -67,13 +67,13 @@
   import java.util.Locale;
   
   import org.apache.coyote.Adapter;
  -import org.apache.coyote.Connector;
  +import org.apache.coyote.Processor;
   
   /**
    * File tester.
    * <p>
    * This tester is initialized with an adapter (it will use the HTTP/1.1 
  - * connector), and will then accept an input file (which will contain the 
  + * processor), and will then accept an input file (which will contain the 
    * input data), and an output file, to which the result of the request(s)
    * will be written.
    *
  @@ -93,17 +93,17 @@
        * of the output file will be overwritten when the test is run.
        * 
        * @param adapter Coyote adapter to use for this test
  -     * @param connector Coyote connector to use for this test
  +     * @param processor Coyote processor to use for this test
        * @param inputFile File containing the HTTP requests in plain text
        * @param outputFile File containing the HTTP responses
        */
  -    public FileTester(Adapter adapter, Connector connector,
  +    public FileTester(Adapter adapter, Processor processor,
                         File inputFile, File outputFile) {
   
  -        connector.setAdapter(adapter);
  +        processor.setAdapter(adapter);
   
           this.adapter = adapter;
  -        this.connector = connector;
  +        this.processor = processor;
           this.inputFile = inputFile;
           this.outputFile = outputFile;
   
  @@ -114,7 +114,7 @@
   
   
       /**
  -     * Utility main method, which will use the HTTP/1.1 connector with the 
  +     * Utility main method, which will use the HTTP/1.1 processor with the 
        * test adapter.
        *
        * @param args Command line arguments to be processed
  @@ -134,9 +134,9 @@
           File outputFile = new File(args[1]);
   
           Adapter testAdapter = new RandomAdapter();
  -        Connector http11Connector = new Http11Connector();
  +        Processor http11Processor = new Http11Processor();
   
  -        FileTester tester = new FileTester(testAdapter, http11Connector,
  +        FileTester tester = new FileTester(testAdapter, http11Processor,
                                              inputFile, outputFile);
           tester.test();
   
  @@ -165,9 +165,9 @@
   
   
       /**
  -     * Coyote connector to use.
  +     * Coyote processor to use.
        */
  -    protected Connector connector;
  +    protected Processor processor;
   
   
       // --------------------------------------------------------- Public Methods
  @@ -182,7 +182,7 @@
           InputStream is = new FileInputStream(inputFile);
           OutputStream os = new FileOutputStream(outputFile);
   
  -        connector.process(is, os);
  +        processor.process(is, os);
   
       }
   
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>