remm 01/01/22 19:55:55 Added: catalina/src/share/org/apache/catalina/connector/http10 Constants.java HttpConnector.java HttpProcessor.java HttpRequestImpl.java HttpResponseImpl.java LocalStrings.properties Log: - Rename "test" connector to "http10" connector. - Added a socket timeout, and a connection timeout parameter (which default to 30s). Revision Changes Path 1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http10/Constants.java Index: Constants.java =================================================================== /* * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http10/Constants.java,v 1.1 2001/01/23 03:55:54 remm Exp $ * $Revision: 1.1 $ * $Date: 2001/01/23 03:55:54 $ * * ==================================================================== * * 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 [EMAIL PROTECTED] * * 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.catalina.connector.http10; import org.apache.catalina.Globals; /** * Static constants for this package. */ public final class Constants { public static final String Package = "org.apache.catalina.connector.http10"; public static final String ServerInfo = Globals.SERVER_INFO + " (HTTP/1.0 Connector)"; public static final int DEFAULT_CONNECTION_TIMEOUT = 30000; } 1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http10/HttpConnector.java Index: HttpConnector.java =================================================================== /* * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http10/HttpConnector.java,v 1.1 2001/01/23 03:55:54 remm Exp $ * $Revision: 1.1 $ * $Date: 2001/01/23 03:55:54 $ * * ==================================================================== * * 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 [EMAIL PROTECTED] * * 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.catalina.connector.http10; import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.Stack; import java.util.Vector; import org.apache.catalina.Connector; import org.apache.catalina.Container; import org.apache.catalina.HttpRequest; import org.apache.catalina.HttpResponse; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleListener; import org.apache.catalina.Logger; import org.apache.catalina.Request; import org.apache.catalina.Response; import org.apache.catalina.net.DefaultServerSocketFactory; import org.apache.catalina.net.ServerSocketFactory; import org.apache.catalina.util.LifecycleSupport; import org.apache.catalina.util.StringManager; /** * Simple implementation of an HTTP/1.0 Connector, for testing and debugging * purposes. Not intended to be the final solution. * * @author Craig R. McClanahan * @version $Revision: 1.1 $ $Date: 2001/01/23 03:55:54 $ */ public final class HttpConnector implements Connector, Lifecycle, Runnable { // ----------------------------------------------------- Instance Variables /** * The accept count for this Connector. */ private int acceptCount = 10; /** * The IP address on which to bind, if any. If <code>null</code>, all * addresses on the server will be bound. */ private String address = null; /** * The input buffer size we should create on input streams. */ private int bufferSize = 2048; /** * The Container used for processing requests received by this Connector. */ protected Container container = null; /** * The set of processors that have ever been created. */ private Vector created = new Vector(); /** * The current number of processors that have been created. */ private int curProcessors = 0; /** * The debugging detail level for this component. */ private int debug = 0; /** * The server socket factory for this component. */ private ServerSocketFactory factory = null; /** * Descriptive information about this Connector implementation. */ private static final String info = "org.apache.catalina.connector.http10.HttpConnector/1.0"; /** * The lifecycle event support for this component. */ protected LifecycleSupport lifecycle = new LifecycleSupport(this); /** * Timeout value on the incoming connection. * Note : a negative value of 0 means no timeout. */ private int connectionTimeout = Constants.DEFAULT_CONNECTION_TIMEOUT; /** * The minimum number of processors to start at initialization time. */ protected int minProcessors = 5; /** * The maximum number of processors allowed, or <0 for unlimited. */ private int maxProcessors = 20; /** * The port number on which we listen for HTTP requests. */ private int port = 8080; /** * The set of processors that have been created but are not currently * being used to process a request. */ private Stack processors = new Stack(); /** * The request scheme that will be set on all requests received * through this connector. */ private String scheme = "http"; /** * The secure connection flag that will be set on all requests received * through this connector. */ private boolean secure = false; /** * The server socket through which we listen for incoming TCP connections. */ private ServerSocket serverSocket = null; /** * The string manager for this package. */ private StringManager sm = StringManager.getManager(Constants.Package); /** * Has this component been started yet? */ private boolean started = false; /** * The shutdown signal to our background thread */ private boolean stopped = false; /** * The background thread. */ private Thread thread = null; /** * The name to register for the background thread. */ private String threadName = null; /** * The thread synchronization object. */ private Object threadSync = new Object(); // ------------------------------------------------------------- Properties /** * Return the connection timeout for this Connector. */ public int getConnectionTimeout() { return (connectionTimeout); } /** * Set the connection timeout for this Connector. * * @param count The new connection timeout */ public void setConnectionTimeout(int connectionTimeout) { this.connectionTimeout = connectionTimeout; } /** * Return the accept count for this Connector. */ public int getAcceptCount() { return (acceptCount); } /** * Set the accept count for this Connector. * * @param count The new accept count */ public void setAcceptCount(int count) { this.acceptCount = count; } /** * Return the bind IP address for this Connector. */ public String getAddress() { return (this.address); } /** * Set the bind IP address for this Connector. * * @param address The bind IP address */ public void setAddress(String address) { this.address = address; } /** * Is this connector available for processing requests? */ public boolean isAvailable() { return (started); } /** * Return the input buffer size for this Connector. */ public int getBufferSize() { return (this.bufferSize); } /** * Set the input buffer size for this Connector. * * @param bufferSize The new input buffer size. */ public void setBufferSize(int bufferSize) { this.bufferSize = bufferSize; } /** * Return the Container used for processing requests received by this * Connector. */ public Container getContainer() { return (container); } /** * Set the Container used for processing requests received by this * Connector. * * @param container The new Container to use */ public void setContainer(Container container) { this.container = container; } /** * Return the current number of processors that have been created. */ public int getCurProcessors() { return (curProcessors); } /** * Return the debugging detail level for this component. */ public int getDebug() { return (debug); } /** * Set the debugging detail level for this component. * * @param debug The new debugging detail level */ public void setDebug(int debug) { this.debug = debug; } /** * Return the server socket factory used by this Container. */ public ServerSocketFactory getFactory() { if (this.factory == null) { synchronized (this) { this.factory = new DefaultServerSocketFactory(); } } return (this.factory); } /** * Set the server socket factory used by this Container. * * @param factory The new server socket factory */ public void setFactory(ServerSocketFactory factory) { this.factory = factory; } /** * Return descriptive information about this Connector implementation. */ public String getInfo() { return (info); } /** * Return the minimum number of processors to start at initialization. */ public int getMinProcessors() { return (minProcessors); } /** * Set the minimum number of processors to start at initialization. * * @param minProcessors The new minimum processors */ public void setMinProcessors(int minProcessors) { this.minProcessors = minProcessors; } /** * Return the maximum number of processors allowed, or <0 for unlimited. */ public int getMaxProcessors() { return (maxProcessors); } /** * Set the maximum number of processors allowed, or <0 for unlimited. * * @param maxProcessors The new maximum processors */ public void setMaxProcessors(int maxProcessors) { this.maxProcessors = maxProcessors; } /** * Return the port number on which we listen for HTTP requests. */ public int getPort() { return (this.port); } /** * Set the port number on which we listen for HTTP requests. * * @param port The new port number */ public void setPort(int port) { this.port = port; } /** * Return the scheme that will be assigned to requests received * through this connector. Default value is "http". */ public String getScheme() { return (this.scheme); } /** * Set the scheme that will be assigned to requests received through * this connector. * * @param scheme The new scheme */ public void setScheme(String scheme) { this.scheme = scheme; } /** * Return the secure connection flag that will be assigned to requests * received through this connector. Default value is "false". */ public boolean getSecure() { return (this.secure); } /** * Set the secure connection flag that will be assigned to requests * received through this connector. * * @param secure The new secure connection flag */ public void setSecure(boolean secure) { this.secure = secure; } // --------------------------------------------------------- Public Methods /** * Create (or allocate) and return a Request object suitable for * specifying the contents of a Request to the responsible Container. */ public Request createRequest() { HttpRequestImpl request = new HttpRequestImpl(); request.setConnector(this); return (request); } /** * Create (or allocate) and return a Response object suitable for * receiving the contents of a Response from the responsible Container. */ public Response createResponse() { HttpResponseImpl response = new HttpResponseImpl(); response.setConnector(this); return (response); } // -------------------------------------------------------- Package Methods /** * Recycle the specified Processor so that it can be used again. * * @param processor The processor to be recycled */ void recycle(HttpProcessor processor) { processors.push(processor); } // -------------------------------------------------------- Private Methods /** * Create (or allocate) and return an available processor for use in * processing a specific HTTP request, if possible. If the maximum * allowed processors have already been created and are in use, return * <code>null</code> instead. */ private HttpProcessor createProcessor() { synchronized (processors) { if (processors.size() > 0) return ((HttpProcessor) processors.pop()); if ((maxProcessors > 0) && (curProcessors < maxProcessors)) return (newProcessor()); else return (null); } } /** * Log a message on the Logger associated with our Container (if any). * * @param message Message to be logged */ private void log(String message) { Logger logger = container.getLogger(); if (logger != null) logger.log(threadName + " " + message); else System.out.println(threadName + " " + message); } /** * Log a message on the Logger associated with our Container (if any). * * @param message Message to be logged * @param throwable Associated exception */ private void log(String message, Throwable throwable) { Logger logger = container.getLogger(); if (logger != null) logger.log(threadName + " " + message, throwable); else { System.out.println(threadName + " " + message); throwable.printStackTrace(System.out); } } /** * Create and return a new processor suitable for processing HTTP * requests and returning the corresponding responses. */ private HttpProcessor newProcessor() { HttpProcessor processor = new HttpProcessor(this, curProcessors++); if (processor instanceof Lifecycle) { try { ((Lifecycle) processor).start(); } catch (LifecycleException e) { log("newProcessor", e); return (null); } } created.addElement(processor); return (processor); } /** * Open and return the server socket for this Connector. If an IP * address has been specified, the socket will be opened only on that * address; otherwise it will be opened on all addresses. * * @exception IOException if an input/output error occurs */ private ServerSocket open() throws IOException { // Acquire the server socket factory for this Connector ServerSocketFactory factory = getFactory(); // If no address is specified, open a connection on all addresses if (address == null) { log(sm.getString("httpConnector.allAddresses")); return (factory.createSocket(port, acceptCount)); } // Open a server socket on the specified address InetAddress[] addresses = InetAddress.getAllByName(InetAddress.getLocalHost().getHostName()); int i; for (i = 0; i < addresses.length; i++) { if (addresses[i].getHostAddress().equals(address)) break; } if (i < addresses.length) { log(sm.getString("httpConnector.anAddress", address)); return (factory.createSocket(port, acceptCount, addresses[i])); } else { log(sm.getString("httpConnector.noAddress", address)); return (factory.createSocket(port, acceptCount)); } } // ---------------------------------------------- Background Thread Methods /** * The background thread that listens for incoming TCP/IP connections and * hands them off to an appropriate processor. */ public void run() { // Loop until we receive a shutdown command while (!stopped) { // Accept the next incoming connection from the server socket Socket socket = null; try { socket = serverSocket.accept(); if (connectionTimeout > 0) socket.setSoTimeout(connectionTimeout); } catch (IOException e) { if (started && !stopped) log("accept: ", e); break; } // Hand this socket off to an appropriate processor HttpProcessor processor = createProcessor(); if (processor == null) { try { log(sm.getString("httpConnector.noProcessor")); socket.close(); } catch (IOException e) { ; } continue; } processor.assign(socket); // The processor will recycle itself when it finishes } // Notify the threadStop() method that we have shut ourselves down synchronized (threadSync) { threadSync.notifyAll(); } } /** * Start the background processing thread. */ private void threadStart() { log(sm.getString("httpConnector.starting")); thread = new Thread(this, threadName); thread.setDaemon(true); thread.start(); } /** * Stop the background processing thread. */ private void threadStop() { log(sm.getString("httpConnector.stopping")); stopped = true; synchronized (threadSync) { try { threadSync.wait(5000); } catch (InterruptedException e) { ; } } thread = null; } // ------------------------------------------------------ Lifecycle Methods /** * Add a lifecycle event listener to this component. * * @param listener The listener to add */ public void addLifecycleListener(LifecycleListener listener) { lifecycle.addLifecycleListener(listener); } /** * Remove a lifecycle event listener from this component. * * @param listener The listener to add */ public void removeLifecycleListener(LifecycleListener listener) { lifecycle.removeLifecycleListener(listener); } /** * Begin processing requests via this Connector. * * @exception LifecycleException if a fatal startup error occurs */ public void start() throws LifecycleException { // Validate and update our current state if (started) throw new LifecycleException (sm.getString("httpConnector.alreadyStarted")); threadName = "HttpConnector[" + port + "]"; lifecycle.fireLifecycleEvent(START_EVENT, null); started = true; // Establish a server socket on the specified port try { serverSocket = open(); } catch (IOException e) { throw new LifecycleException(threadName + ".open", e); } // Start our background thread threadStart(); // Create the specified minimum number of processors while (curProcessors < minProcessors) { if ((maxProcessors > 0) && (curProcessors >= maxProcessors)) break; HttpProcessor processor = newProcessor(); recycle(processor); } } /** * Terminate processing requests via this Connector. * * @exception LifecycleException if a fatal shutdown error occurs */ public void stop() throws LifecycleException { // Validate and update our current state if (!started) throw new LifecycleException (sm.getString("httpConnector.notStarted")); lifecycle.fireLifecycleEvent(STOP_EVENT, null); started = false; // Gracefully shut down all processors we have created for (int i = created.size() - 1; i >= 0; i--) { HttpProcessor processor = (HttpProcessor) created.elementAt(i); if (processor instanceof Lifecycle) { try { ((Lifecycle) processor).stop(); } catch (LifecycleException e) { log("HttpConnector.stop", e); } } } // Close the server socket we were using if (serverSocket != null) { try { serverSocket.close(); } catch (IOException e) { ; } serverSocket = null; } // Stop our background thread threadStop(); } } 1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http10/HttpProcessor.java Index: HttpProcessor.java =================================================================== /* * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http10/HttpProcessor.java,v 1.1 2001/01/23 03:55:54 remm Exp $ * $Revision: 1.1 $ * $Date: 2001/01/23 03:55:54 $ * * ==================================================================== * * 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 [EMAIL PROTECTED] * * 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.catalina.connector.http10; import java.io.BufferedInputStream; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.util.NoSuchElementException; import java.util.StringTokenizer; import java.util.Locale; import java.util.Hashtable; import java.util.Vector; import java.util.Enumeration; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Connector; import org.apache.catalina.Container; import org.apache.catalina.Globals; import org.apache.catalina.HttpRequest; import org.apache.catalina.HttpResponse; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleListener; import org.apache.catalina.Logger; import org.apache.catalina.util.RequestUtil; import org.apache.catalina.util.LifecycleSupport; import org.apache.catalina.util.StringManager; /** * Implementation of a request processor (and its associated thread) that may * be used by an HttpConnector to process individual requests. The connector * will allocate a processor from its pool, assign a particular socket to it, * and the processor will then execute the processing required to complete * the request. When the processor is completed, it will recycle itself. * * @author Craig R. McClanahan * @version $Revision: 1.1 $ $Date: 2001/01/23 03:55:54 $ */ final class HttpProcessor implements Lifecycle, Runnable { // ----------------------------------------------------------- Constructors /** * Construct a new HttpProcessor associated with the specified connector. * * @param connector HttpConnector that owns this processor * @param id Identifier of this HttpProcessor (unique per connector) */ public HttpProcessor(HttpConnector connector, int id) { super(); this.connector = connector; this.debug = connector.getDebug(); this.id = id; this.request = (HttpRequest) connector.createRequest(); this.response = (HttpResponse) connector.createResponse(); this.threadName = "HttpProcessor[" + connector.getPort() + "][" + id + "]"; } // ----------------------------------------------------- Instance Variables /** * Is there a new socket available? */ private boolean available = false; /** * The HttpConnector with which this processor is associated. */ private HttpConnector connector = null; /** * The debugging detail level for this component. */ private int debug = 0; /** * The identifier of this processor, unique per connector. */ private int id = 0; /** * The lifecycle event support for this component. */ private LifecycleSupport lifecycle = new LifecycleSupport(this); /** * The match string for identifying a session ID parameter. */ private static final String match = ";" + Globals.SESSION_PARAMETER_NAME + "="; /** * The HTTP request object we will pass to our associated container. */ private HttpRequest request = null; /** * The HTTP response object we will pass to our associated container. */ private HttpResponse response = null; /** * The string manager for this package. */ protected StringManager sm = StringManager.getManager(Constants.Package); /** * The socket we are currently processing a request for. This object * is used for inter-thread communication only. */ private Socket socket = null; /** * Has this component been started yet? */ private boolean started = false; /** * The shutdown signal to our background thread */ private boolean stopped = false; /** * The background thread. */ private Thread thread = null; /** * The name to register for the background thread. */ private String threadName = null; /** * The thread synchronization object. */ private Object threadSync = new Object(); // -------------------------------------------------------- Package Methods /** * Process an incoming TCP/IP connection on the specified socket. Any * exception that occurs during processing must be logged and swallowed. * <b>NOTE</b>: This method is called from our Connector's thread. We * must assign it to our own thread so that multiple simultaneous * requests can be handled. * * @param socket TCP socket to process */ synchronized void assign(Socket socket) { // Wait for the Processor to get the previous Socket while (available) { try { wait(); } catch (InterruptedException e) { } } // Store the newly available Socket and notify our thread this.socket = socket; available = true; notifyAll(); if ((debug >= 1) && (socket != null)) log(" An incoming request is being assigned"); } // -------------------------------------------------------- Private Methods /** * Await a newly assigned Socket from our Connector, or <code>null</code> * if we are supposed to shut down. */ private synchronized Socket await() { // Wait for the Connector to provide a new Socket while (!available) { try { wait(); } catch (InterruptedException e) { } } // Notify the Connector that we have received this Socket Socket socket = this.socket; available = false; notifyAll(); if ((debug >= 1) && (socket != null)) log(" The incoming request has been awaited"); return (socket); } /** * Log a message on the Logger associated with our Container (if any) * * @param message Message to be logged */ private void log(String message) { Logger logger = connector.getContainer().getLogger(); if (logger != null) logger.log(threadName + " " + message); } /** * Log a message on the Logger associated with our Container (if any) * * @param message Message to be logged * @param throwable Associated exception */ private void log(String message, Throwable throwable) { Logger logger = connector.getContainer().getLogger(); if (logger != null) logger.log(threadName + " " + message, throwable); } /** * Parse and record the connection parameters related to this request. * * @param socket The socket on which we are connected * * @exception IOException if an input/output error occurs * @exception ServletException if a parsing error occurs */ private void parseConnection(Socket socket) throws IOException, ServletException { if (debug >= 2) log(" parseConnection: address=" + socket.getInetAddress() + ", port=" + connector.getPort()); ((HttpRequestImpl) request).setInet(socket.getInetAddress()); request.setServerPort(connector.getPort()); request.setSocket(socket); } /** * Parse the incoming HTTP request headers, and set the appropriate * request headers. * * @param input The input stream connected to our socket * * @exception IOException if an input/output error occurs * @exception ServletException if a parsing error occurs */ private void parseHeaders(InputStream input) throws IOException, ServletException { while (true) { // Read the next header line String line = read(input); if ((line == null) || (line.length() < 1)) break; // Parse the header name and value int colon = line.indexOf(":"); if (colon < 0) throw new ServletException (sm.getString("httpProcessor.parseHeaders.colon")); String name = line.substring(0, colon).trim(); String match = name.toLowerCase(); String value = line.substring(colon + 1).trim(); if (debug >= 1) log(" Header " + name + " = " + value); // Set the corresponding request headers if (match.equals("authorization")) { request.setAuthorization(value); request.addHeader(name, value); } else if (match.equals("accept-language")) { request.addHeader(name, value); // // Adapted from old code perhaps maybe optimized // // Hashtable languages = new Hashtable(); StringTokenizer languageTokenizer = new StringTokenizer(value, ","); while (languageTokenizer.hasMoreTokens()) { String language = languageTokenizer.nextToken().trim(); int qValueIndex = language.indexOf(';'); int qIndex = language.indexOf('q'); int equalIndex = language.indexOf('='); Double qValue = new Double(1); if (qValueIndex > -1 && qValueIndex < qIndex && qIndex < equalIndex) { String qValueStr = language.substring(qValueIndex + 1); language = language.substring(0, qValueIndex); qValueStr = qValueStr.trim().toLowerCase(); qValueIndex = qValueStr.indexOf('='); qValue = new Double(0); if (qValueStr.startsWith("q") && qValueIndex > -1) { qValueStr = qValueStr.substring(qValueIndex + 1); try { qValue = new Double(qValueStr.trim()); } catch (NumberFormatException nfe) { } } } // XXX // may need to handle "*" at some point in time if (! language.equals("*")) { String key = qValue.toString(); Vector v = (Vector)((languages.containsKey(key)) ? languages.get(key) : new Vector()); v.addElement(language); languages.put(key, v); } } Vector l = new Vector(); Enumeration e = languages.keys(); while (e.hasMoreElements()) { String key = (String)e.nextElement(); Vector v = (Vector)languages.get(key); Enumeration le = v.elements(); while (le.hasMoreElements()) { String language = (String)le.nextElement(); String country = ""; int countryIndex = language.indexOf("-"); if (countryIndex > -1) { country = language.substring(countryIndex + 1).trim(); language = language.substring(0, countryIndex).trim(); } request.addLocale(new Locale(language, country)); } } } else if (match.equals("cookie")) { Cookie cookies[] = RequestUtil.parseCookieHeader(value); for (int i = 0; i < cookies.length; i++) { if (cookies[i].getName().equals (Globals.SESSION_COOKIE_NAME)) { // Override anything requested in the URL request.setRequestedSessionId(cookies[i].getValue()); request.setRequestedSessionCookie(true); request.setRequestedSessionURL(false); if (debug >= 1) log(" Requested cookie session id is " + ((HttpServletRequest) request.getRequest()).getRequestedSessionId()); break; // Accept only the first session id value } request.addCookie(cookies[i]); } // Keep Watchdog from whining by adding the header as well // (GetHeaderTest, GetIntHeader_1Test) request.addHeader(name, value); } else if (match.equals("content-length")) { int n = -1; try { n = Integer.parseInt(value); } catch (Exception e) { throw new ServletException (sm.getString("httpProcessor.parseHeaders.contentLength")); } request.setContentLength(n); request.addHeader(name, value); } else if (match.equals("content-type")) { request.setContentType(value); request.addHeader(name, value); } else if (match.equals("host")) { int n = value.indexOf(":"); if (n < 0) request.setServerName(value); else { request.setServerName(value.substring(0, n).trim()); int port = 80; try { port = Integer.parseInt(value.substring(n+1).trim()); } catch (Exception e) { throw new ServletException (sm.getString("httpProcessor.parseHeaders.portNumber")); } request.setServerPort(port); } request.addHeader(name, value); } else { request.addHeader(name, value); } } } /** * Parse the incoming HTTP request and set the corresponding HTTP request * properties. * * @param input The input stream attached to our socket * * @exception IOException if an input/output error occurs * @exception ServletException if a parsing error occurs */ private void parseRequest(InputStream input) throws IOException, ServletException { // Parse the incoming request line String line = read(input); if (line == null) throw new ServletException (sm.getString("httpProcessor.parseRequest.read")); StringTokenizer st = new StringTokenizer(line); String method = null; try { method = st.nextToken(); } catch (NoSuchElementException e) { method = null; } String uri = null; try { uri = st.nextToken(); ; // FIXME - URL decode the URI? } catch (NoSuchElementException e) { uri = null; } String protocol = null; try { protocol = st.nextToken(); } catch (NoSuchElementException e) { protocol = "HTTP/0.9"; } // Validate the incoming request line if (method == null) { throw new ServletException (sm.getString("httpProcessor.parseRequest.method")); } else if (uri == null) { throw new ServletException (sm.getString("httpProcessor.parseRequest.uri")); } // Parse any query parameters out of the request URI int question = uri.indexOf("?"); if (question >= 0) { request.setQueryString(uri.substring(question + 1)); if (debug >= 1) log(" Query string is " + ((HttpServletRequest) request.getRequest()).getQueryString()); uri = uri.substring(0, question); } else request.setQueryString(null); // Parse any requested session ID out of the request URI int semicolon = uri.indexOf(match); if (semicolon >= 0) { String rest = uri.substring(semicolon + match.length()); int semicolon2 = rest.indexOf(";"); if (semicolon2 >= 0) { request.setRequestedSessionId(rest.substring(0, semicolon2)); rest = rest.substring(semicolon2); } else { request.setRequestedSessionId(rest); rest = ""; } request.setRequestedSessionURL(true); uri = uri.substring(0, semicolon) + rest; if (debug >= 1) log(" Requested URL session id is " + ((HttpServletRequest) request.getRequest()).getRequestedSessionId()); } else { request.setRequestedSessionId(null); request.setRequestedSessionURL(false); } // Set the corresponding request properties ((HttpRequest) request).setMethod(method); request.setProtocol(protocol); ((HttpRequest) request).setRequestURI(uri); request.setSecure(false); // No SSL support request.setScheme("http"); // No SSL support if (debug >= 1) log(" Request is " + method + " for " + uri); } /** * Process an incoming HTTP request on the Socket that has been assigned * to this Processor. Any exceptions that occur during processing must be * swallowed and dealt with. * * @param socket The socket on which we are connected to the client */ private void process(Socket socket) { boolean ok = true; InputStream input = null; OutputStream output = null; // Construct and initialize the objects we will need try { input = new BufferedInputStream(socket.getInputStream(), connector.getBufferSize()); request.setStream(input); request.setResponse(response); output = socket.getOutputStream(); response.setStream(output); response.setRequest(request); ((HttpServletResponse) response.getResponse()).setHeader ("Server", Constants.ServerInfo); } catch (Exception e) { log("process.create", e); ok = false; } // Parse the incoming request try { if (ok) { parseConnection(socket); parseRequest(input); if (!request.getRequest().getProtocol().startsWith("HTTP/0")) parseHeaders(input); } } catch (Exception e) { try { log("process.parse", e); ((HttpServletResponse) response.getResponse()).sendError (HttpServletResponse.SC_BAD_REQUEST); } catch (Exception f) { ; } } // Ask our Container to process this request try { if (ok) { connector.getContainer().invoke(request, response); } } catch (ServletException e) { log("process.invoke", e); try { ((HttpServletResponse) response.getResponse()).sendError (HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } catch (Exception f) { ; } ok = false; } catch (Throwable e) { log("process.invoke", e); try { ((HttpServletResponse) response.getResponse()).sendError (HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } catch (Exception f) { ; } ok = false; } // Finish up the handling of the response try { if (ok) response.finishResponse(); } catch (IOException e) { log("FIXME-Exception from finishResponse", e); } try { if (output != null) output.flush(); } catch (IOException e) { log("FIXME-Exception flushing output", e); } try { if (output != null) output.close(); } catch (IOException e) { log("FIXME-Exception closing output", e); } // Finish up the handling of the request try { if (ok) request.finishRequest(); } catch (IOException e) { log("FIXME-Exception from finishRequest", e); } try { if (input != null) input.close(); } catch (IOException e) { log("FIXME-Exception closing input", e); } // Finish up the handling of the socket connection itself try { socket.close(); } catch (IOException e) { log("FIXME-Exception closing socket", e); } socket = null; } /** * Read a line from the specified input stream, and strip off the * trailing carriage return and newline (if any). Return the remaining * characters that were read as a String. * * @param input The input stream connected to our socket * * @returns The line that was read, or <code>null</code> if end-of-file * was encountered * * @exception IOException if an input/output error occurs */ private String read(InputStream input) throws IOException { StringBuffer sb = new StringBuffer(); while (true) { int ch = input.read(); if (ch < 0) { if (sb.length() == 0) { return (null); } else { break; } } else if (ch == '\r') { continue; } else if (ch == '\n') { break; } sb.append((char) ch); } if (debug >= 2) log(" Read: " + sb.toString()); return (sb.toString()); } // ---------------------------------------------- Background Thread Methods /** * The background thread that listens for incoming TCP/IP connections and * hands them off to an appropriate processor. */ public void run() { // Process requests until we receive a shutdown signal while (!stopped) { // Wait for the next socket to be assigned Socket socket = await(); if (socket == null) continue; // Process the request from this socket process(socket); // Finish up this request request.recycle(); response.recycle(); connector.recycle(this); } // Tell threadStop() we have shut ourselves down successfully synchronized (threadSync) { threadSync.notifyAll(); } } /** * Start the background processing thread. */ private void threadStart() { log(sm.getString("httpProcessor.starting")); thread = new Thread(this, threadName); thread.setDaemon(true); thread.start(); if (debug >= 1) log(" Background thread has been started"); } /** * Stop the background processing thread. */ private void threadStop() { log(sm.getString("httpProcessor.stopping")); stopped = true; assign(null); synchronized (threadSync) { try { threadSync.wait(5000); } catch (InterruptedException e) { ; } } thread = null; } // ------------------------------------------------------ Lifecycle Methods /** * Add a lifecycle event listener to this component. * * @param listener The listener to add */ public void addLifecycleListener(LifecycleListener listener) { lifecycle.addLifecycleListener(listener); } /** * Remove a lifecycle event listener from this component. * * @param listener The listener to add */ public void removeLifecycleListener(LifecycleListener listener) { lifecycle.removeLifecycleListener(listener); } /** * Start the background thread we will use for request processing. * * @exception LifecycleException if a fatal startup error occurs */ public void start() throws LifecycleException { if (started) throw new LifecycleException (sm.getString("httpProcessor.alreadyStarted")); lifecycle.fireLifecycleEvent(START_EVENT, null); started = true; threadStart(); } /** * Stop the background thread we will use for request processing. * * @exception LifecycleException if a fatal shutdown error occurs */ public void stop() throws LifecycleException { if (!started) throw new LifecycleException (sm.getString("httpProcessor.notStarted")); lifecycle.fireLifecycleEvent(STOP_EVENT, null); started = false; threadStop(); } } 1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http10/HttpRequestImpl.java Index: HttpRequestImpl.java =================================================================== /* * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http10/HttpRequestImpl.java,v 1.1 2001/01/23 03:55:54 remm Exp $ * $Revision: 1.1 $ * $Date: 2001/01/23 03:55:54 $ * * ==================================================================== * * 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 [EMAIL PROTECTED] * * 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.catalina.connector.http10; import java.net.InetAddress; import org.apache.catalina.connector.HttpRequestBase; /** * Implementation of <b>HttpRequest</b> specific to the HTTP connector. * * @author Craig R. McClanahan * @version $Revision: 1.1 $ $Date: 2001/01/23 03:55:54 $ */ final class HttpRequestImpl extends HttpRequestBase { // ----------------------------------------------------- Instance Variables /** * The InetAddress of the remote client of ths request. */ protected InetAddress inet = null; /** * Descriptive information about this Request implementation. */ protected static final String info = "org.apache.catalina.connector.http10.HttpRequestImpl/1.0"; // ------------------------------------------------------------- Properties /** * [Package Private] Return the InetAddress of the remote client of * this request. */ InetAddress getInet() { return (inet); } /** * [Package Private] Set the InetAddress of the remote client of * this request. * * @param inet The new InetAddress */ void setInet(InetAddress inet) { this.inet = inet; } /** * Return descriptive information about this Request implementation and * the corresponding version number, in the format * <code><description>/<version></code>. */ public String getInfo() { return (info); } // --------------------------------------------------------- Public Methods /** * Release all object references, and initialize instance variables, in * preparation for reuse of this object. */ public void recycle() { super.recycle(); inet = null; } // ------------------------------------------------- ServletRequest Methods /** * Return the Internet Protocol (IP) address of the client that sent * this request. */ public String getRemoteAddr() { return (inet.getHostAddress()); } /** * Return the fully qualified name of the client that sent this request, * or the IP address of the client if the name cannot be determined. */ public String getRemoteHost() { return (inet.getHostName()); } // --------------------------------------------- HttpServletRequest Methods } 1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http10/HttpResponseImpl.java Index: HttpResponseImpl.java =================================================================== /* * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http10/HttpResponseImpl.java,v 1.1 2001/01/23 03:55:54 remm Exp $ * $Revision: 1.1 $ * $Date: 2001/01/23 03:55:54 $ * * ==================================================================== * * 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 [EMAIL PROTECTED] * * 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.catalina.connector.http10; import org.apache.catalina.connector.HttpResponseBase; /** * Implementation of <b>HttpResponse</b> specific to the HTTP connector. * * @author Craig R. McClanahan * @version $Revision: 1.1 $ $Date: 2001/01/23 03:55:54 $ */ final class HttpResponseImpl extends HttpResponseBase { // ----------------------------------------------------- Instance Variables /** * Descriptive information about this Response implementation. */ protected static final String info = "org.apache.catalina.connector.http10.HttpResponseImpl/1.0"; // ------------------------------------------------------------- Properties /** * Return descriptive information about this Response implementation and * the corresponding version number, in the format * <code><description>/<version></code>. */ public String getInfo() { return (info); } // --------------------------------------------------------- Public Methods /** * Release all object references, and initialize instance variables, in * preparation for reuse of this object. */ public void recycle() { super.recycle(); } } 1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http10/LocalStrings.properties Index: LocalStrings.properties =================================================================== httpConnector.alreadyStarted=HTTP connector has already been started httpConnector.allAddresses=Opening server socket on all host IP addresses httpConnector.anAddress=Opening server socket on host IP address {0} httpConnector.noAddress=No host IP address matching {0}, opening on all addresses httpConnector.noProcessor=No processor available, rejecting this connection httpConnector.notStarted=HTTP connector has not yet been started httpConnector.starting=Starting background thread httpConnector.stopping=Stopping background thread httpProcessor.alreadyStarted=HTTP processor has already been started httpProcessor.notStarted=HTTP processor has not yet been started httpProcessor.parseHeaders.contentLength=Invalid 'Content-Length' header httpProcessor.parseHeaders.colon=Invalid HTTP header format httpProcessor.parseHeaders.portNumber=Invalid TCP/IP port number in 'Host' header httpProcessor.parseRequest.method=Missing HTTP request method httpProcessor.parseRequest.read=Missing HTTP request line httpProcessor.parseRequest.uri=Missing HTTP request URI httpProcessor.start=HTTP processor has already been started httpProcessor.starting=Starting background thread httpProcessor.stopping=Stopping background thread --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, email: [EMAIL PROTECTED]