| 1 |   | /* * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/HttpProcessor.java,v 1.36.2.5 2002/04/04 17:46:08 remm Exp $ |   | 1 |   | /* * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/HttpProcessor.java,v 1.46    2002/04/04 17:50:34 remm Exp $ | 
| 2 |   |  * $Revision: 1.36.2.5 $ |   | 2 |   |  * $Revision: 1.46    $ | 
| 3 |   |  * $Date: 2002/04/04 17:46:08 $ |   | 3 |   |  * $Date: 2002/04/04 17:50:34 $ | 
| 4 |   |  * |   | 4 |   |  * | 
| 5 |   |  * ==================================================================== |   | 5 |   |  * ==================================================================== | 
| 6 |   |  * |   | 6 |   |  * | 
| 7 |   |  * The Apache Software License, Version 1.1 |   | 7 |   |  * The Apache Software License, Version 1.1 | 
| 8 |   |  * |   | 8 |   |  * | 
| 9 |   |  * Copyright (c) 1999 The Apache Software Foundation.  All rights |   | 9 |   |  * Copyright (c) 1999 The Apache Software Foundation.  All rights | 
| 10 |   |  * reserved. |   | 10 |   |  * reserved. | 
| 11 |   |  * |   | 11 |   |  * | 
| 12 |   |  * Redistribution and use in source and binary forms, with or without |   | 12 |   |  * Redistribution and use in source and binary forms, with or without | 
| 13 |   |  * modification, are permitted provided that the following conditions |   | 13 |   |  * modification, are permitted provided that the following conditions | 
| 14 |   |  * are met: |   | 14 |   |  * are met: | 
| 15 |   |  * |   | 15 |   |  * | 
| 16 |   |  * 1. Redistributions of source code must retain the above copyright |   | 16 |   |  * 1. Redistributions of source code must retain the above copyright | 
| 17 |   |  *    notice, this list of conditions and the following disclaimer. |   | 17 |   |  *    notice, this list of conditions and the following disclaimer. | 
| 18 |   |  * |   | 18 |   |  * | 
| 19 |   |  * 2. Redistributions in binary form must reproduce the above copyright |   | 19 |   |  * 2. Redistributions in binary form must reproduce the above copyright | 
| 20 |   |  *    notice, this list of conditions and the following disclaimer in |   | 20 |   |  *    notice, this list of conditions and the following disclaimer in | 
| 21 |   |  *    the documentation and/or other materials provided with the |   | 21 |   |  *    the documentation and/or other materials provided with the | 
| 22 |   |  *    distribution. |   | 22 |   |  *    distribution. | 
| 23 |   |  * |   | 23 |   |  * | 
| 24 |   |  * 3. The end-user documentation included with the redistribution, if |   | 24 |   |  * 3. The end-user documentation included with the redistribution, if | 
| 25 |   |  *    any, must include the following acknowlegement: |   | 25 |   |  *    any, must include the following acknowlegement: | 
| 26 |   |  *       "This product includes software developed by the |   | 26 |   |  *       "This product includes software developed by the | 
| 27 |   |  *        Apache Software Foundation (http://www.apache.org/)." |   | 27 |   |  *        Apache Software Foundation (http://www.apache.org/)." | 
| 28 |   |  *    Alternately, this acknowlegement may appear in the software itself, |   | 28 |   |  *    Alternately, this acknowlegement may appear in the software itself, | 
| 29 |   |  *    if and wherever such third-party acknowlegements normally appear. |   | 29 |   |  *    if and wherever such third-party acknowlegements normally appear. | 
| 30 |   |  * |   | 30 |   |  * | 
| 31 |   |  * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software |   | 31 |   |  * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software | 
| 32 |   |  *    Foundation" must not be used to endorse or promote products derived |   | 32 |   |  *    Foundation" must not be used to endorse or promote products derived | 
| 33 |   |  *    from this software without prior written permission. For written |   | 33 |   |  *    from this software without prior written permission. For written | 
| 34 |   |  *    permission, please contact apache@apache.org. |   | 34 |   |  *    permission, please contact apache@apache.org. | 
| 35 |   |  * |   | 35 |   |  * | 
| 36 |   |  * 5. Products derived from this software may not be called "Apache" |   | 36 |   |  * 5. Products derived from this software may not be called "Apache" | 
| 37 |   |  *    nor may "Apache" appear in their names without prior written |   | 37 |   |  *    nor may "Apache" appear in their names without prior written | 
| 38 |   |  *    permission of the Apache Group. |   | 38 |   |  *    permission of the Apache Group. | 
| 39 |   |  * |   | 39 |   |  * | 
| 40 |   |  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |   | 40 |   |  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | 
| 41 |   |  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |   | 41 |   |  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | 
| 42 |   |  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |   | 42 |   |  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 
| 43 |   |  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |   | 43 |   |  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | 
| 44 |   |  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |   | 44 |   |  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
| 45 |   |  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |   | 45 |   |  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
| 46 |   |  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |   | 46 |   |  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | 
| 47 |   |  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |   | 47 |   |  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 
| 48 |   |  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |   | 48 |   |  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 
| 49 |   |  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |   | 49 |   |  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | 
| 50 |   |  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |   | 50 |   |  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 
| 51 |   |  * SUCH DAMAGE. |   | 51 |   |  * SUCH DAMAGE. | 
| 52 |   |  * ==================================================================== |   | 52 |   |  * ==================================================================== | 
| 53 |   |  * |   | 53 |   |  * | 
| 54 |   |  * This software consists of voluntary contributions made by many |   | 54 |   |  * This software consists of voluntary contributions made by many | 
| 55 |   |  * individuals on behalf of the Apache Software Foundation.  For more |   | 55 |   |  * individuals on behalf of the Apache Software Foundation.  For more | 
| 56 |   |  * information on the Apache Software Foundation, please see |   | 56 |   |  * information on the Apache Software Foundation, please see | 
| 57 |   |  * <http://www.apache.org/>. |   | 57 |   |  * <http://www.apache.org/>. | 
| 58 |   |  * |   | 58 |   |  * | 
| 59 |   |  * [Additional notices, if required by prior licensing conditions] |   | 59 |   |  * [Additional notices, if required by prior licensing conditions] | 
| 60 |   |  * |   | 60 |   |  * | 
| 61 |   |  */ |   | 61 |   |  */ | 
| 62 |   |  |   | 62 |   |  | 
| 63 |   |  |   | 63 |   |  | 
| 64 |   | package org.apache.catalina.connector.http; |   | 64 |   | package org.apache.catalina.connector.http; | 
| 65 |   |  |   | 65 |   |  | 
| 66 |   |  |   | 66 |   |  | 
| 67 |   | import java.io.BufferedInputStream; |   | 67 |   | import java.io.BufferedInputStream; | 
| 68 |   | import java.io.EOFException; |   | 68 |   | import java.io.EOFException; | 
| 69 |   | import java.io.InterruptedIOException; |   | 69 |   | import java.io.InterruptedIOException; | 
| 70 |   | import java.io.InputStream; |   | 70 |   | import java.io.InputStream; | 
| 71 |   | import java.io.IOException; |   | 71 |   | import java.io.IOException; | 
| 72 |   | import java.io.OutputStream; |   | 72 |   | import java.io.OutputStream; | 
| 73 |   | import java.net.InetAddress; |   | 73 |   | import java.net.InetAddress; | 
| 74 |   | import java.net.Socket; |   | 74 |   | import java.net.Socket; | 
| 75 |   | import java.util.ArrayList; |   | 75 |   | import java.util.ArrayList; | 
| 76 |   | import java.util.Iterator; |   | 76 |   | import java.util.Iterator; | 
| 77 |   | import java.util.Locale; |   | 77 |   | import java.util.Locale; | 
| 78 |   | import java.util.StringTokenizer; |   | 78 |   | import java.util.StringTokenizer; | 
| 79 |   | import java.util.TreeMap; |   | 79 |   | import java.util.TreeMap; | 
| 80 |   | import javax.servlet.ServletException; |   | 80 |   | import javax.servlet.ServletException; | 
| 81 |   | import javax.servlet.http.Cookie; |   | 81 |   | import javax.servlet.http.Cookie; | 
| 82 |   | import javax.servlet.http.HttpServletRequest; |   | 82 |   | import javax.servlet.http.HttpServletRequest; | 
| 83 |   | import javax.servlet.http.HttpServletResponse; |   | 83 |   | import javax.servlet.http.HttpServletResponse; | 
| 84 |   | import org.apache.catalina.Connector; |   | 84 |   | import org.apache.catalina.Connector; | 
| 85 |   | import org.apache.catalina.Container; |   | 85 |   | import org.apache.catalina.Container; | 
| 86 |   | import org.apache.catalina.Globals; |   | 86 |   | import org.apache.catalina.Globals; | 
| 87 |   | import org.apache.catalina.HttpRequest; |   | 87 |   | import org.apache.catalina.HttpRequest; | 
| 88 |   | import org.apache.catalina.HttpResponse; |   | 88 |   | import org.apache.catalina.HttpResponse; | 
| 89 |   | import org.apache.catalina.Lifecycle; |   | 89 |   | import org.apache.catalina.Lifecycle; | 
| 90 |   | import org.apache.catalina.LifecycleEvent; |   | 90 |   | import org.apache.catalina.LifecycleEvent; | 
| 91 |   | import org.apache.catalina.LifecycleException; |   | 91 |   | import org.apache.catalina.LifecycleException; | 
| 92 |   | import org.apache.catalina.LifecycleListener; |   | 92 |   | import org.apache.catalina.LifecycleListener; | 
| 93 |   | import org.apache.catalina.Logger; |   | 93 |   | import org.apache.catalina.Logger; | 
| 94 |   | import org.apache.catalina.util.RequestUtil; |   | 94 |   | import org.apache.catalina.util.FastHttpDateFormat   ; | 
| 95 |   | import org.apache.catalina.util.LifecycleSupport; |   | 95 |   | import org.apache.catalina.util.LifecycleSupport; | 
|   |   |   |   | 96 |   | import org.apache.catalina.util.RequestUtil; | 
|   |   |   |   | 97 |   | import org.apache.catalina.util.ServerInfo; | 
| 96 |   | import org.apache.catalina.util.StringManager; |   | 98 |   | import org.apache.catalina.util.StringManager; | 
| 97 |   | import org.apache.catalina.util.StringParser; |   | 99 |   | import org.apache.catalina.util.StringParser; | 
| 98 |   |  |   | 100 |   |  | 
| 99 |   |  |   | 101 |   |  | 
| 100 |   | /** |   | 102 |   | /** | 
| 101 |   |  * Implementation of a request processor (and its associated thread) that may |   | 103 |   |  * Implementation of a request processor (and its associated thread) that may | 
| 102 |   |  * be used by an HttpConnector to process individual requests.  The connector |   | 104 |   |  * be used by an HttpConnector to process individual requests.  The connector | 
| 103 |   |  * will allocate a processor from its pool, assign a particular socket to it, |   | 105 |   |  * will allocate a processor from its pool, assign a particular socket to it, | 
| 104 |   |  * and the processor will then execute the processing required to complete |   | 106 |   |  * and the processor will then execute the processing required to complete | 
| 105 |   |  * the request.  When the processor is completed, it will recycle itself. |   | 107 |   |  * the request.  When the processor is completed, it will recycle itself. | 
| 106 |   |  * |   | 108 |   |  * | 
| 107 |   |  * @author Craig R. McClanahan |   | 109 |   |  * @author Craig R. McClanahan | 
| 108 |   |  * @author Remy Maucherat |   | 110 |   |  * @author Remy Maucherat | 
| 109 |   |  * @version $Revision: 1.36.2.5 $ $Date: 2002/04/04 17:46:08 $ |   | 111 |   |  * @version $Revision: 1.46    $ $Date: 2002/04/04 17:50:34 $ | 
|   |   |   |   | 112 |   |  * @deprecated | 
| 110 |   |  */ |   | 113 |   |  */ | 
| 111 |   |  |   | 114 |   |  | 
| 112 |   | final class HttpProcessor |   | 115 |   | final class HttpProcessor | 
| 113 |   |     implements Lifecycle, Runnable { |   | 116 |   |     implements Lifecycle, Runnable { | 
| 114 |   |  |   | 117 |   |  | 
| 115 |   |  |   | 118 |   |  | 
|   |   |   |   | 119 |   |     // ----------------------------------------------------- Manifest Constants | 
|   |   |   |   | 120 |   |  | 
|   |   |   |   | 121 |   |  | 
|   |   |   |   | 122 |   |     /** | 
|   |   |   |   | 123 |   |      * Server information string for this server. | 
|   |   |   |   | 124 |   |      */ | 
|   |   |   |   | 125 |   |     private static final String SERVER_INFO = | 
|   |   |   |   | 126 |   |         ServerInfo.getServerInfo() + " (HTTP/1.1 Connector)"; | 
|   |   |   |   | 127 |   |  | 
|   |   |   |   | 128 |   |  | 
| 116 |   |     // ----------------------------------------------------------- Constructors |   | 129 |   |     // ----------------------------------------------------------- Constructors | 
| 117 |   |  |   | 130 |   |  | 
| 118 |   |  |   | 131 |   |  | 
| 119 |   |     /** |   | 132 |   |     /** | 
| 120 |   |      * Construct a new HttpProcessor associated with the specified connector. |   | 133 |   |      * Construct a new HttpProcessor associated with the specified connector. | 
| 121 |   |      * |   | 134 |   |      * | 
| 122 |   |      * @param connector HttpConnector that owns this processor |   | 135 |   |      * @param connector HttpConnector that owns this processor | 
| 123 |   |      * @param id Identifier of this HttpProcessor (unique per connector) |   | 136 |   |      * @param id Identifier of this HttpProcessor (unique per connector) | 
| 124 |   |      */ |   | 137 |   |      */ | 
| 125 |   |     public HttpProcessor(HttpConnector connector, int id) { |   | 138 |   |     public HttpProcessor(HttpConnector connector, int id) { | 
| 126 |   |  |   | 139 |   |  | 
| 127 |   |         super(); |   | 140 |   |         super(); | 
| 128 |   |         this.connector = connector; |   | 141 |   |         this.connector = connector; | 
| 129 |   |         this.debug = connector.getDebug(); |   | 142 |   |         this.debug = connector.getDebug(); | 
| 130 |   |         this.id = id; |   | 143 |   |         this.id = id; | 
| 131 |   |         this.proxyName = connector.getProxyName(); |   | 144 |   |         this.proxyName = connector.getProxyName(); | 
| 132 |   |         this.proxyPort = connector.getProxyPort(); |   | 145 |   |         this.proxyPort = connector.getProxyPort(); | 
| 133 |   |         this.request = (HttpRequestImpl) connector.createRequest(); |   | 146 |   |         this.request = (HttpRequestImpl) connector.createRequest(); | 
| 134 |   |         this.response = (HttpResponseImpl) connector.createResponse(); |   | 147 |   |         this.response = (HttpResponseImpl) connector.createResponse(); | 
| 135 |   |         this.serverPort = connector.getPort(); |   | 148 |   |         this.serverPort = connector.getPort(); | 
| 136 |   |         this.threadName = |   | 149 |   |         this.threadName = | 
| 137 |   |           "HttpProcessor[" + connector.getPort() + "][" + id + "]"; |   | 150 |   |           "HttpProcessor[" + connector.getPort() + "][" + id + "]"; | 
| 138 |   |  |   | 151 |   |  | 
| 139 |   |     } |   | 152 |   |     } | 
| 140 |   |  |   | 153 |   |  | 
| 141 |   |  |   | 154 |   |  | 
| 142 |   |     // ----------------------------------------------------- Instance Variables |   | 155 |   |     // ----------------------------------------------------- Instance Variables | 
| 143 |   |  |   | 156 |   |  | 
| 144 |   |  |   | 157 |   |  | 
| 145 |   |     /** |   | 158 |   |     /** | 
| 146 |   |      * Is there a new socket available? |   | 159 |   |      * Is there a new socket available? | 
| 147 |   |      */ |   | 160 |   |      */ | 
| 148 |   |     private boolean available = false; |   | 161 |   |     private boolean available = false; | 
| 149 |   |  |   | 162 |   |  | 
| 150 |   |  |   | 163 |   |  | 
| 151 |   |     /** |   | 164 |   |     /** | 
| 152 |   |      * The HttpConnector with which this processor is associated. |   | 165 |   |      * The HttpConnector with which this processor is associated. | 
| 153 |   |      */ |   | 166 |   |      */ | 
| 154 |   |     private HttpConnector connector = null; |   | 167 |   |     private HttpConnector connector = null; | 
| 155 |   |  |   | 168 |   |  | 
| 156 |   |  |   | 169 |   |  | 
| 157 |   |     /** |   | 170 |   |     /** | 
| 158 |   |      * The debugging detail level for this component. |   | 171 |   |      * The debugging detail level for this component. | 
| 159 |   |      */ |   | 172 |   |      */ | 
| 160 |   |     private int debug = 0; |   | 173 |   |     private int debug = 0; | 
| 161 |   |  |   | 174 |   |  | 
| 162 |   |  |   | 175 |   |  | 
| 163 |   |     /** |   | 176 |   |     /** | 
| 164 |   |      * The identifier of this processor, unique per connector. |   | 177 |   |      * The identifier of this processor, unique per connector. | 
| 165 |   |      */ |   | 178 |   |      */ | 
| 166 |   |     private int id = 0; |   | 179 |   |     private int id = 0; | 
| 167 |   |  |   | 180 |   |  | 
| 168 |   |  |   | 181 |   |  | 
| 169 |   |     /** |   | 182 |   |     /** | 
| 170 |   |      * The lifecycle event support for this component. |   | 183 |   |      * The lifecycle event support for this component. | 
| 171 |   |      */ |   | 184 |   |      */ | 
| 172 |   |     private LifecycleSupport lifecycle = new LifecycleSupport(this); |   | 185 |   |     private LifecycleSupport lifecycle = new LifecycleSupport(this); | 
| 173 |   |  |   | 186 |   |  | 
| 174 |   |  |   | 187 |   |  | 
| 175 |   |     /** |   | 188 |   |     /** | 
| 176 |   |      * The match string for identifying a session ID parameter. |   | 189 |   |      * The match string for identifying a session ID parameter. | 
| 177 |   |      */ |   | 190 |   |      */ | 
| 178 |   |     private static final String match = |   | 191 |   |     private static final String match = | 
| 179 |   |         ";" + Globals.SESSION_PARAMETER_NAME + "="; |   | 192 |   |         ";" + Globals.SESSION_PARAMETER_NAME + "="; | 
| 180 |   |  |   | 193 |   |  | 
| 181 |   |  |   | 194 |   |  | 
| 182 |   |     /** |   | 195 |   |     /** | 
| 183 |   |      * The match string for identifying a session ID parameter. |   | 196 |   |      * The match string for identifying a session ID parameter. | 
| 184 |   |      */ |   | 197 |   |      */ | 
| 185 |   |     private static final char[] SESSION_ID = match.toCharArray(); |   | 198 |   |     private static final char[] SESSION_ID = match.toCharArray(); | 
| 186 |   |  |   | 199 |   |  | 
| 187 |   |  |   | 200 |   |  | 
| 188 |   |     /** |   | 201 |   |     /** | 
| 189 |   |      * The string parser we will use for parsing request lines. |   | 202 |   |      * The string parser we will use for parsing request lines. | 
| 190 |   |      */ |   | 203 |   |      */ | 
| 191 |   |     private StringParser parser = new StringParser(); |   | 204 |   |     private StringParser parser = new StringParser(); | 
| 192 |   |  |   | 205 |   |  | 
| 193 |   |  |   | 206 |   |  | 
| 194 |   |     /** |   | 207 |   |     /** | 
| 195 |   |      * The proxy server name for our Connector. |   | 208 |   |      * The proxy server name for our Connector. | 
| 196 |   |      */ |   | 209 |   |      */ | 
| 197 |   |     private String proxyName = null; |   | 210 |   |     private String proxyName = null; | 
| 198 |   |  |   | 211 |   |  | 
| 199 |   |  |   | 212 |   |  | 
| 200 |   |     /** |   | 213 |   |     /** | 
| 201 |   |      * The proxy server port for our Connector. |   | 214 |   |      * The proxy server port for our Connector. | 
| 202 |   |      */ |   | 215 |   |      */ | 
| 203 |   |     private int proxyPort = 0; |   | 216 |   |     private int proxyPort = 0; | 
| 204 |   |  |   | 217 |   |  | 
| 205 |   |  |   | 218 |   |  | 
| 206 |   |     /** |   | 219 |   |     /** | 
| 207 |   |      * The HTTP request object we will pass to our associated container. |   | 220 |   |      * The HTTP request object we will pass to our associated container. | 
| 208 |   |      */ |   | 221 |   |      */ | 
| 209 |   |     private HttpRequestImpl request = null; |   | 222 |   |     private HttpRequestImpl request = null; | 
| 210 |   |  |   | 223 |   |  | 
| 211 |   |  |   | 224 |   |  | 
| 212 |   |     /** |   | 225 |   |     /** | 
| 213 |   |      * The HTTP response object we will pass to our associated container. |   | 226 |   |      * The HTTP response object we will pass to our associated container. | 
| 214 |   |      */ |   | 227 |   |      */ | 
| 215 |   |     private HttpResponseImpl response = null; |   | 228 |   |     private HttpResponseImpl response = null; | 
| 216 |   |  |   | 229 |   |  | 
| 217 |   |  |   | 230 |   |  | 
| 218 |   |     /** |   | 231 |   |     /** | 
| 219 |   |      * The actual server port for our Connector. |   | 232 |   |      * The actual server port for our Connector. | 
| 220 |   |      */ |   | 233 |   |      */ | 
| 221 |   |     private int serverPort = 0; |   | 234 |   |     private int serverPort = 0; | 
| 222 |   |  |   | 235 |   |  | 
| 223 |   |  |   | 236 |   |  | 
| 224 |   |     /** |   | 237 |   |     /** | 
| 225 |   |      * The string manager for this package. |   | 238 |   |      * The string manager for this package. | 
| 226 |   |      */ |   | 239 |   |      */ | 
| 227 |   |     protected StringManager sm = |   | 240 |   |     protected StringManager sm = | 
| 228 |   |         StringManager.getManager(Constants.Package); |   | 241 |   |         StringManager.getManager(Constants.Package); | 
| 229 |   |  |   | 242 |   |  | 
| 230 |   |  |   | 243 |   |  | 
| 231 |   |     /** |   | 244 |   |     /** | 
| 232 |   |      * The socket we are currently processing a request for.  This object |   | 245 |   |      * The socket we are currently processing a request for.  This object | 
| 233 |   |      * is used for inter-thread communication only. |   | 246 |   |      * is used for inter-thread communication only. | 
| 234 |   |      */ |   | 247 |   |      */ | 
| 235 |   |     private Socket socket = null; |   | 248 |   |     private Socket socket = null; | 
| 236 |   |  |   | 249 |   |  | 
| 237 |   |  |   | 250 |   |  | 
| 238 |   |     /** |   | 251 |   |     /** | 
| 239 |   |      * Has this component been started yet? |   | 252 |   |      * Has this component been started yet? | 
| 240 |   |      */ |   | 253 |   |      */ | 
| 241 |   |     private boolean started = false; |   | 254 |   |     private boolean started = false; | 
| 242 |   |  |   | 255 |   |  | 
| 243 |   |  |   | 256 |   |  | 
| 244 |   |     /** |   | 257 |   |     /** | 
| 245 |   |      * The shutdown signal to our background thread |   | 258 |   |      * The shutdown signal to our background thread | 
| 246 |   |      */ |   | 259 |   |      */ | 
| 247 |   |     private boolean stopped = false; |   | 260 |   |     private boolean stopped = false; | 
| 248 |   |  |   | 261 |   |  | 
| 249 |   |  |   | 262 |   |  | 
| 250 |   |     /** |   | 263 |   |     /** | 
| 251 |   |      * The background thread. |   | 264 |   |      * The background thread. | 
| 252 |   |      */ |   | 265 |   |      */ | 
| 253 |   |     private Thread thread = null; |   | 266 |   |     private Thread thread = null; | 
| 254 |   |  |   | 267 |   |  | 
| 255 |   |  |   | 268 |   |  | 
| 256 |   |     /** |   | 269 |   |     /** | 
| 257 |   |      * The name to register for the background thread. |   | 270 |   |      * The name to register for the background thread. | 
| 258 |   |      */ |   | 271 |   |      */ | 
| 259 |   |     private String threadName = null; |   | 272 |   |     private String threadName = null; | 
| 260 |   |  |   | 273 |   |  | 
| 261 |   |  |   | 274 |   |  | 
| 262 |   |     /** |   | 275 |   |     /** | 
| 263 |   |      * The thread synchronization object. |   | 276 |   |      * The thread synchronization object. | 
| 264 |   |      */ |   | 277 |   |      */ | 
| 265 |   |     private Object threadSync = new Object(); |   | 278 |   |     private Object threadSync = new Object(); | 
| 266 |   |  |   | 279 |   |  | 
| 267 |   |  |   | 280 |   |  | 
| 268 |   |     /** |   | 281 |   |     /** | 
| 269 |   |      * Keep alive indicator. |   | 282 |   |      * Keep alive indicator. | 
| 270 |   |      */ |   | 283 |   |      */ | 
| 271 |   |     private boolean keepAlive = false; |   | 284 |   |     private boolean keepAlive = false; | 
| 272 |   |  |   | 285 |   |  | 
| 273 |   |  |   | 286 |   |  | 
| 274 |   |     /** |   | 287 |   |     /** | 
| 275 |   |      * HTTP/1.1 client. |   | 288 |   |      * HTTP/1.1 client. | 
| 276 |   |      */ |   | 289 |   |      */ | 
| 277 |   |     private boolean http11 = true; |   | 290 |   |     private boolean http11 = true; | 
| 278 |   |  |   | 291 |   |  | 
| 279 |   |  |   | 292 |   |  | 
| 280 |   |     /** |   | 293 |   |     /** | 
| 281 |   |      * True if the client has asked to recieve a request acknoledgement. If so |   | 294 |   |      * True if the client has asked to recieve a request acknoledgement. If so | 
| 282 |   |      * the server will send a preliminary 100 Continue response just after it |   | 295 |   |      * the server will send a preliminary 100 Continue response just after it | 
| 283 |   |      * has successfully parsed the request headers, and before starting |   | 296 |   |      * has successfully parsed the request headers, and before starting | 
| 284 |   |      * reading the request entity body. |   | 297 |   |      * reading the request entity body. | 
| 285 |   |      */ |   | 298 |   |      */ | 
| 286 |   |     private boolean sendAck = false; |   | 299 |   |     private boolean sendAck = false; | 
| 287 |   |  |   | 300 |   |  | 
| 288 |   |  |   | 301 |   |  | 
| 289 |   |     /** |   | 302 |   |     /** | 
| 290 |   |      * Ack string when pipelining HTTP requests. |   | 303 |   |      * Ack string when pipelining HTTP requests. | 
| 291 |   |      */ |   | 304 |   |      */ | 
| 292 |   |     private static final byte[] ack = |   | 305 |   |     private static final byte[] ack = | 
| 293 |   |         (new String("HTTP/1.1 100 Continue\r\n\r\n")).getBytes(); |   | 306 |   |         (new String("HTTP/1.1 100 Continue\r\n\r\n")).getBytes(); | 
| 294 |   |  |   | 307 |   |  | 
| 295 |   |  |   | 308 |   |  | 
| 296 |   |     /** |   | 309 |   |     /** | 
| 297 |   |      * CRLF. |   | 310 |   |      * CRLF. | 
| 298 |   |      */ |   | 311 |   |      */ | 
| 299 |   |     private static final byte[] CRLF = (new String("\r\n")).getBytes(); |   | 312 |   |     private static final byte[] CRLF = (new String("\r\n")).getBytes(); | 
| 300 |   |  |   | 313 |   |  | 
| 301 |   |  |   | 314 |   |  | 
| 302 |   |     /** |   | 315 |   |     /** | 
| 303 |   |      * Line buffer. |   | 316 |   |      * Line buffer. | 
| 304 |   |      */ |   | 317 |   |      */ | 
| 305 |   |     //private char[] lineBuffer = new char[4096]; |   | 318 |   |     //private char[] lineBuffer = new char[4096]; | 
| 306 |   |  |   | 319 |   |  | 
| 307 |   |  |   | 320 |   |  | 
| 308 |   |     /** |   | 321 |   |     /** | 
| 309 |   |      * Request line buffer. |   | 322 |   |      * Request line buffer. | 
| 310 |   |      */ |   | 323 |   |      */ | 
| 311 |   |     private HttpRequestLine requestLine = new HttpRequestLine(); |   | 324 |   |     private HttpRequestLine requestLine = new HttpRequestLine(); | 
| 312 |   |  |   | 325 |   |  | 
| 313 |   |  |   | 326 |   |  | 
| 314 |   |     /** |   | 327 |   |     /** | 
| 315 |   |      * Processor state |   | 328 |   |      * Processor state | 
| 316 |   |      */ |   | 329 |   |      */ | 
| 317 |   |     private int status = Constants.PROCESSOR_IDLE; |   | 330 |   |     private int status = Constants.PROCESSOR_IDLE; | 
| 318 |   |  |   | 331 |   |  | 
| 319 |   |  |   | 332 |   |  | 
| 320 |   |     // --------------------------------------------------------- Public Methods |   | 333 |   |     // --------------------------------------------------------- Public Methods | 
| 321 |   |  |   | 334 |   |  | 
| 322 |   |  |   | 335 |   |  | 
| 323 |   |     /** |   | 336 |   |     /** | 
| 324 |   |      * Return a String value representing this object. |   | 337 |   |      * Return a String value representing this object. | 
| 325 |   |      */ |   | 338 |   |      */ | 
| 326 |   |     public String toString() { |   | 339 |   |     public String toString() { | 
| 327 |   |  |   | 340 |   |  | 
| 328 |   |         return (this.threadName); |   | 341 |   |         return (this.threadName); | 
| 329 |   |  |   | 342 |   |  | 
| 330 |   |     } |   | 343 |   |     } | 
| 331 |   |  |   | 344 |   |  | 
| 332 |   |  |   | 345 |   |  | 
| 333 |   |     // -------------------------------------------------------- Package Methods |   | 346 |   |     // -------------------------------------------------------- Package Methods | 
| 334 |   |  |   | 347 |   |  | 
| 335 |   |  |   | 348 |   |  | 
| 336 |   |     /** |   | 349 |   |     /** | 
| 337 |   |      * Process an incoming TCP/IP connection on the specified socket.  Any |   | 350 |   |      * Process an incoming TCP/IP connection on the specified socket.  Any | 
| 338 |   |      * exception that occurs during processing must be logged and swallowed. |   | 351 |   |      * exception that occurs during processing must be logged and swallowed. | 
| 339 |   |      * <b>NOTE</b>:  This method is called from our Connector's thread.  We |   | 352 |   |      * <b>NOTE</b>:  This method is called from our Connector's thread.  We | 
| 340 |   |      * must assign it to our own thread so that multiple simultaneous |   | 353 |   |      * must assign it to our own thread so that multiple simultaneous | 
| 341 |   |      * requests can be handled. |   | 354 |   |      * requests can be handled. | 
| 342 |   |      * |   | 355 |   |      * | 
| 343 |   |      * @param socket TCP socket to process |   | 356 |   |      * @param socket TCP socket to process | 
| 344 |   |      */ |   | 357 |   |      */ | 
| 345 |   |     synchronized void assign(Socket socket) { |   | 358 |   |     synchronized void assign(Socket socket) { | 
| 346 |   |  |   | 359 |   |  | 
| 347 |   |         // Wait for the Processor to get the previous Socket |   | 360 |   |         // Wait for the Processor to get the previous Socket | 
| 348 |   |         while (available) { |   | 361 |   |         while (available) { | 
| 349 |   |             try { |   | 362 |   |             try { | 
| 350 |   |                 wait(); |   | 363 |   |                 wait(); | 
| 351 |   |             } catch (InterruptedException e) { |   | 364 |   |             } catch (InterruptedException e) { | 
| 352 |   |             } |   | 365 |   |             } | 
| 353 |   |         } |   | 366 |   |         } | 
| 354 |   |  |   | 367 |   |  | 
| 355 |   |         // Store the newly available Socket and notify our thread |   | 368 |   |         // Store the newly available Socket and notify our thread | 
| 356 |   |         this.socket = socket; |   | 369 |   |         this.socket = socket; | 
| 357 |   |         available = true; |   | 370 |   |         available = true; | 
| 358 |   |         notifyAll(); |   | 371 |   |         notifyAll(); | 
| 359 |   |  |   | 372 |   |  | 
| 360 |   |         if ((debug >= 1) && (socket != null)) |   | 373 |   |         if ((debug >= 1) && (socket != null)) | 
| 361 |   |             log(" An incoming request is being assigned"); |   | 374 |   |             log(" An incoming request is being assigned"); | 
| 362 |   |  |   | 375 |   |  | 
| 363 |   |     } |   | 376 |   |     } | 
| 364 |   |  |   | 377 |   |  | 
| 365 |   |  |   | 378 |   |  | 
| 366 |   |     // -------------------------------------------------------- Private Methods |   | 379 |   |     // -------------------------------------------------------- Private Methods | 
| 367 |   |  |   | 380 |   |  | 
| 368 |   |  |   | 381 |   |  | 
| 369 |   |     /** |   | 382 |   |     /** | 
| 370 |   |      * Await a newly assigned Socket from our Connector, or <code>null</code> |   | 383 |   |      * Await a newly assigned Socket from our Connector, or <code>null</code> | 
| 371 |   |      * if we are supposed to shut down. |   | 384 |   |      * if we are supposed to shut down. | 
| 372 |   |      */ |   | 385 |   |      */ | 
| 373 |   |     private synchronized Socket await() { |   | 386 |   |     private synchronized Socket await() { | 
| 374 |   |  |   | 387 |   |  | 
| 375 |   |         // Wait for the Connector to provide a new Socket |   | 388 |   |         // Wait for the Connector to provide a new Socket | 
| 376 |   |         while (!available) { |   | 389 |   |         while (!available) { | 
| 377 |   |             try { |   | 390 |   |             try { | 
| 378 |   |                 wait(); |   | 391 |   |                 wait(); | 
| 379 |   |             } catch (InterruptedException e) { |   | 392 |   |             } catch (InterruptedException e) { | 
| 380 |   |             } |   | 393 |   |             } | 
| 381 |   |         } |   | 394 |   |         } | 
| 382 |   |  |   | 395 |   |  | 
| 383 |   |         // Notify the Connector that we have received this Socket |   | 396 |   |         // Notify the Connector that we have received this Socket | 
| 384 |   |         Socket socket = this.socket; |   | 397 |   |         Socket socket = this.socket; | 
| 385 |   |         available = false; |   | 398 |   |         available = false; | 
| 386 |   |         notifyAll(); |   | 399 |   |         notifyAll(); | 
| 387 |   |  |   | 400 |   |  | 
| 388 |   |         if ((debug >= 1) && (socket != null)) |   | 401 |   |         if ((debug >= 1) && (socket != null)) | 
| 389 |   |             log("  The incoming request has been awaited"); |   | 402 |   |             log("  The incoming request has been awaited"); | 
| 390 |   |  |   | 403 |   |  | 
| 391 |   |         return (socket); |   | 404 |   |         return (socket); | 
| 392 |   |  |   | 405 |   |  | 
| 393 |   |     } |   | 406 |   |     } | 
| 394 |   |  |   | 407 |   |  | 
| 395 |   |  |   | 408 |   |  | 
| 396 |   |  |   | 409 |   |  | 
| 397 |   |     /** |   | 410 |   |     /** | 
| 398 |   |      * Log a message on the Logger associated with our Container (if any) |   | 411 |   |      * Log a message on the Logger associated with our Container (if any) | 
| 399 |   |      * |   | 412 |   |      * | 
| 400 |   |      * @param message Message to be logged |   | 413 |   |      * @param message Message to be logged | 
| 401 |   |      */ |   | 414 |   |      */ | 
| 402 |   |     private void log(String message) { |   | 415 |   |     private void log(String message) { | 
| 403 |   |  |   | 416 |   |  | 
| 404 |   |         Logger logger = connector.getContainer().getLogger(); |   | 417 |   |         Logger logger = connector.getContainer().getLogger(); | 
| 405 |   |         if (logger != null) |   | 418 |   |         if (logger != null) | 
| 406 |   |             logger.log(threadName + " " + message); |   | 419 |   |             logger.log(threadName + " " + message); | 
| 407 |   |  |   | 420 |   |  | 
| 408 |   |     } |   | 421 |   |     } | 
| 409 |   |  |   | 422 |   |  | 
| 410 |   |  |   | 423 |   |  | 
| 411 |   |     /** |   | 424 |   |     /** | 
| 412 |   |      * Log a message on the Logger associated with our Container (if any) |   | 425 |   |      * Log a message on the Logger associated with our Container (if any) | 
| 413 |   |      * |   | 426 |   |      * | 
| 414 |   |      * @param message Message to be logged |   | 427 |   |      * @param message Message to be logged | 
| 415 |   |      * @param throwable Associated exception |   | 428 |   |      * @param throwable Associated exception | 
| 416 |   |      */ |   | 429 |   |      */ | 
| 417 |   |     private void log(String message, Throwable throwable) { |   | 430 |   |     private void log(String message, Throwable throwable) { | 
| 418 |   |  |   | 431 |   |  | 
| 419 |   |         Logger logger = connector.getContainer().getLogger(); |   | 432 |   |         Logger logger = connector.getContainer().getLogger(); | 
| 420 |   |         if (logger != null) |   | 433 |   |         if (logger != null) | 
| 421 |   |             logger.log(threadName + " " + message, throwable); |   | 434 |   |             logger.log(threadName + " " + message, throwable); | 
| 422 |   |  |   | 435 |   |  | 
| 423 |   |     } |   | 436 |   |     } | 
| 424 |   |  |   | 437 |   |  | 
| 425 |   |  |   | 438 |   |  | 
| 426 |   |     /** |   | 439 |   |     /** | 
| 427 |   |      * Parse the value of an <code>Accept-Language</code> header, and add |   | 440 |   |      * Parse the value of an <code>Accept-Language</code> header, and add | 
| 428 |   |      * the corresponding Locales to the current request. |   | 441 |   |      * the corresponding Locales to the current request. | 
| 429 |   |      * |   | 442 |   |      * | 
| 430 |   |      * @param value The value of the <code>Accept-Language</code> header. |   | 443 |   |      * @param value The value of the <code>Accept-Language</code> header. | 
| 431 |   |      */ |   | 444 |   |      */ | 
| 432 |   |     private void parseAcceptLanguage(String value) { |   | 445 |   |     private void parseAcceptLanguage(String value) { | 
| 433 |   |  |   | 446 |   |  | 
| 434 |   |         // Store the accumulated languages that have been requested in |   | 447 |   |         // Store the accumulated languages that have been requested in | 
| 435 |   |         // a local collection, sorted by the quality value (so we can |   | 448 |   |         // a local collection, sorted by the quality value (so we can | 
| 436 |   |         // add Locales in descending order).  The values will be ArrayLists |   | 449 |   |         // add Locales in descending order).  The values will be ArrayLists | 
| 437 |   |         // containing the corresponding Locales to be added |   | 450 |   |         // containing the corresponding Locales to be added | 
| 438 |   |         TreeMap locales = new TreeMap(); |   | 451 |   |         TreeMap locales = new TreeMap(); | 
| 439 |   |  |   | 452 |   |  | 
| 440 |   |         // Preprocess the value to remove all whitespace |   | 453 |   |         // Preprocess the value to remove all whitespace | 
| 441 |   |         int white = value.indexOf(' '); |   | 454 |   |         int white = value.indexOf(' '); | 
| 442 |   |         if (white < 0) |   | 455 |   |         if (white < 0) | 
| 443 |   |             white = value.indexOf('\t'); |   | 456 |   |             white = value.indexOf('\t'); | 
| 444 |   |         if (white >= 0) { |   | 457 |   |         if (white >= 0) { | 
| 445 |   |             StringBuffer sb = new StringBuffer(); |   | 458 |   |             StringBuffer sb = new StringBuffer(); | 
| 446 |   |             int len = value.length(); |   | 459 |   |             int len = value.length(); | 
| 447 |   |             for (int i = 0; i < len; i++) { |   | 460 |   |             for (int i = 0; i < len; i++) { | 
| 448 |   |                 char ch = value.charAt(i); |   | 461 |   |                 char ch = value.charAt(i); | 
| 449 |   |                 if ((ch != ' ') && (ch != '\t')) |   | 462 |   |                 if ((ch != ' ') && (ch != '\t')) | 
| 450 |   |                     sb.append(ch); |   | 463 |   |                     sb.append(ch); | 
| 451 |   |             } |   | 464 |   |             } | 
| 452 |   |             value = sb.toString(); |   | 465 |   |             value = sb.toString(); | 
| 453 |   |         } |   | 466 |   |         } | 
| 454 |   |  |   | 467 |   |  | 
| 455 |   |         // Process each comma-delimited language specification |   | 468 |   |         // Process each comma-delimited language specification | 
| 456 |   |         parser.setString(value);        // ASSERT: parser is available to us |   | 469 |   |         parser.setString(value);        // ASSERT: parser is available to us | 
| 457 |   |         int length = parser.getLength(); |   | 470 |   |         int length = parser.getLength(); | 
| 458 |   |         while (true) { |   | 471 |   |         while (true) { | 
| 459 |   |  |   | 472 |   |  | 
| 460 |   |             // Extract the next comma-delimited entry |   | 473 |   |             // Extract the next comma-delimited entry | 
| 461 |   |             int start = parser.getIndex(); |   | 474 |   |             int start = parser.getIndex(); | 
| 462 |   |             if (start >= length) |   | 475 |   |             if (start >= length) | 
| 463 |   |                 break; |   | 476 |   |                 break; | 
| 464 |   |             int end = parser.findChar(','); |   | 477 |   |             int end = parser.findChar(','); | 
| 465 |   |             String entry = parser.extract(start, end).trim(); |   | 478 |   |             String entry = parser.extract(start, end).trim(); | 
| 466 |   |             parser.advance();   // For the following entry |   | 479 |   |             parser.advance();   // For the following entry | 
| 467 |   |  |   | 480 |   |  | 
| 468 |   |             // Extract the quality factor for this entry |   | 481 |   |             // Extract the quality factor for this entry | 
| 469 |   |             double quality = 1.0; |   | 482 |   |             double quality = 1.0; | 
| 470 |   |             int semi = entry.indexOf(";q="); |   | 483 |   |             int semi = entry.indexOf(";q="); | 
| 471 |   |             if (semi >= 0) { |   | 484 |   |             if (semi >= 0) { | 
| 472 |   |                 try { |   | 485 |   |                 try { | 
| 473 |   |                     quality = Double.parseDouble(entry.substring(semi + 3)); |   | 486 |   |                     quality = Double.parseDouble(entry.substring(semi + 3)); | 
| 474 |   |                 } catch (NumberFormatException e) { |   | 487 |   |                 } catch (NumberFormatException e) { | 
| 475 |   |                     quality = 0.0; |   | 488 |   |                     quality = 0.0; | 
| 476 |   |                 } |   | 489 |   |                 } | 
| 477 |   |                 entry = entry.substring(0, semi); |   | 490 |   |                 entry = entry.substring(0, semi); | 
| 478 |   |             } |   | 491 |   |             } | 
| 479 |   |  |   | 492 |   |  | 
| 480 |   |             // Skip entries we are not going to keep track of |   | 493 |   |             // Skip entries we are not going to keep track of | 
| 481 |   |             if (quality < 0.00005) |   | 494 |   |             if (quality < 0.00005) | 
| 482 |   |                 continue;       // Zero (or effectively zero) quality factors |   | 495 |   |                 continue;       // Zero (or effectively zero) quality factors | 
| 483 |   |             if ("*".equals(entry)) |   | 496 |   |             if ("*".equals(entry)) | 
| 484 |   |                 continue;       // FIXME - "*" entries are not handled |   | 497 |   |                 continue;       // FIXME - "*" entries are not handled | 
| 485 |   |  |   | 498 |   |  | 
| 486 |   |             // Extract the language and country for this entry |   | 499 |   |             // Extract the language and country for this entry | 
| 487 |   |             String language = null; |   | 500 |   |             String language = null; | 
| 488 |   |             String country = null; |   | 501 |   |             String country = null; | 
| 489 |   |             String variant = null; |   | 502 |   |             String variant = null; | 
| 490 |   |             int dash = entry.indexOf('-'); |   | 503 |   |             int dash = entry.indexOf('-'); | 
| 491 |   |             if (dash < 0) { |   | 504 |   |             if (dash < 0) { | 
| 492 |   |                 language = entry; |   | 505 |   |                 language = entry; | 
| 493 |   |                 country = ""; |   | 506 |   |                 country = ""; | 
| 494 |   |                 variant = ""; |   | 507 |   |                 variant = ""; | 
| 495 |   |             } else { |   | 508 |   |             } else { | 
| 496 |   |                 language = entry.substring(0, dash); |   | 509 |   |                 language = entry.substring(0, dash); | 
| 497 |   |                 country = entry.substring(dash + 1); |   | 510 |   |                 country = entry.substring(dash + 1); | 
| 498 |   |                 int vDash = country.indexOf('-'); |   | 511 |   |                 int vDash = country.indexOf('-'); | 
| 499 |   |                 if (vDash > 0) { |   | 512 |   |                 if (vDash > 0) { | 
| 500 |   |                     String cTemp = country.substring(0, vDash); |   | 513 |   |                     String cTemp = country.substring(0, vDash); | 
| 501 |   |                     variant = country.substring(vDash + 1); |   | 514 |   |                     variant = country.substring(vDash + 1); | 
| 502 |   |                     country = cTemp; |   | 515 |   |                     country = cTemp; | 
| 503 |   |                 } else { |   | 516 |   |                 } else { | 
| 504 |   |                     variant = ""; |   | 517 |   |                     variant = ""; | 
| 505 |   |                 } |   | 518 |   |                 } | 
| 506 |   |             } |   | 519 |   |             } | 
| 507 |   |  |   | 520 |   |  | 
| 508 |   |             // Add a new Locale to the list of Locales for this quality level |   | 521 |   |             // Add a new Locale to the list of Locales for this quality level | 
| 509 |   |             Locale locale = new Locale(language, country, variant); |   | 522 |   |             Locale locale = new Locale(language, country, variant); | 
| 510 |   |             Double key = new Double(-quality);  // Reverse the order |   | 523 |   |             Double key = new Double(-quality);  // Reverse the order | 
| 511 |   |             ArrayList values = (ArrayList) locales.get(key); |   | 524 |   |             ArrayList values = (ArrayList) locales.get(key); | 
| 512 |   |             if (values == null) { |   | 525 |   |             if (values == null) { | 
| 513 |   |                 values = new ArrayList(); |   | 526 |   |                 values = new ArrayList(); | 
| 514 |   |                 locales.put(key, values); |   | 527 |   |                 locales.put(key, values); | 
| 515 |   |             } |   | 528 |   |             } | 
| 516 |   |             values.add(locale); |   | 529 |   |             values.add(locale); | 
| 517 |   |  |   | 530 |   |  | 
| 518 |   |         } |   | 531 |   |         } | 
| 519 |   |  |   | 532 |   |  | 
| 520 |   |         // Process the quality values in highest->lowest order (due to |   | 533 |   |         // Process the quality values in highest->lowest order (due to | 
| 521 |   |         // negating the Double value when creating the key) |   | 534 |   |         // negating the Double value when creating the key) | 
| 522 |   |         Iterator keys = locales.keySet().iterator(); |   | 535 |   |         Iterator keys = locales.keySet().iterator(); | 
| 523 |   |         while (keys.hasNext()) { |   | 536 |   |         while (keys.hasNext()) { | 
| 524 |   |             Double key = (Double) keys.next(); |   | 537 |   |             Double key = (Double) keys.next(); | 
| 525 |   |             ArrayList list = (ArrayList) locales.get(key); |   | 538 |   |             ArrayList list = (ArrayList) locales.get(key); | 
| 526 |   |             Iterator values = list.iterator(); |   | 539 |   |             Iterator values = list.iterator(); | 
| 527 |   |             while (values.hasNext()) { |   | 540 |   |             while (values.hasNext()) { | 
| 528 |   |                 Locale locale = (Locale) values.next(); |   | 541 |   |                 Locale locale = (Locale) values.next(); | 
| 529 |   |                 if (debug >= 1) |   | 542 |   |                 if (debug >= 1) | 
| 530 |   |                     log(" Adding locale '" + locale + "'"); |   | 543 |   |                     log(" Adding locale '" + locale + "'"); | 
| 531 |   |                 request.addLocale(locale); |   | 544 |   |                 request.addLocale(locale); | 
| 532 |   |             } |   | 545 |   |             } | 
| 533 |   |         } |   | 546 |   |         } | 
| 534 |   |  |   | 547 |   |  | 
| 535 |   |     } |   | 548 |   |     } | 
| 536 |   |  |   | 549 |   |  | 
| 537 |   |  |   | 550 |   |  | 
| 538 |   |     /** |   | 551 |   |     /** | 
| 539 |   |      * Parse and record the connection parameters related to this request. |   | 552 |   |      * Parse and record the connection parameters related to this request. | 
| 540 |   |      * |   | 553 |   |      * | 
| 541 |   |      * @param socket The socket on which we are connected |   | 554 |   |      * @param socket The socket on which we are connected | 
| 542 |   |      * |   | 555 |   |      * | 
| 543 |   |      * @exception IOException if an input/output error occurs |   | 556 |   |      * @exception IOException if an input/output error occurs | 
| 544 |   |      * @exception ServletException if a parsing error occurs |   | 557 |   |      * @exception ServletException if a parsing error occurs | 
| 545 |   |      */ |   | 558 |   |      */ | 
| 546 |   |     private void parseConnection(Socket socket) |   | 559 |   |     private void parseConnection(Socket socket) | 
| 547 |   |         throws IOException, ServletException { |   | 560 |   |         throws IOException, ServletException { | 
| 548 |   |  |   | 561 |   |  | 
| 549 |   |         if (debug >= 2) |   | 562 |   |         if (debug >= 2) | 
| 550 |   |             log("  parseConnection: address=" + socket.getInetAddress() + |   | 563 |   |             log("  parseConnection: address=" + socket.getInetAddress() + | 
| 551 |   |                 ", port=" + connector.getPort()); |   | 564 |   |                 ", port=" + connector.getPort()); | 
| 552 |   |         ((HttpRequestImpl) request).setInet(socket.getInetAddress()); |   | 565 |   |         ((HttpRequestImpl) request).setInet(socket.getInetAddress()); | 
| 553 |   |         if (proxyPort != 0) |   | 566 |   |         if (proxyPort != 0) | 
| 554 |   |             request.setServerPort(proxyPort); |   | 567 |   |             request.setServerPort(proxyPort); | 
| 555 |   |         else |   | 568 |   |         else | 
| 556 |   |             request.setServerPort(serverPort); |   | 569 |   |             request.setServerPort(serverPort); | 
| 557 |   |         request.setSocket(socket); |   | 570 |   |         request.setSocket(socket); | 
| 558 |   |  |   | 571 |   |  | 
| 559 |   |     } |   | 572 |   |     } | 
| 560 |   |  |   | 573 |   |  | 
| 561 |   |  |   | 574 |   |  | 
| 562 |   |     /** |   | 575 |   |     /** | 
| 563 |   |      * Parse the incoming HTTP request headers, and set the appropriate |   | 576 |   |      * Parse the incoming HTTP request headers, and set the appropriate | 
| 564 |   |      * request headers. |   | 577 |   |      * request headers. | 
| 565 |   |      * |   | 578 |   |      * | 
| 566 |   |      * @param input The input stream connected to our socket |   | 579 |   |      * @param input The input stream connected to our socket | 
| 567 |   |      * |   | 580 |   |      * | 
| 568 |   |      * @exception IOException if an input/output error occurs |   | 581 |   |      * @exception IOException if an input/output error occurs | 
| 569 |   |      * @exception ServletException if a parsing error occurs |   | 582 |   |      * @exception ServletException if a parsing error occurs | 
| 570 |   |      */ |   | 583 |   |      */ | 
| 571 |   |     private void parseHeaders(SocketInputStream input) |   | 584 |   |     private void parseHeaders(SocketInputStream input) | 
| 572 |   |         throws IOException, ServletException { |   | 585 |   |         throws IOException, ServletException { | 
| 573 |   |  |   | 586 |   |  | 
| 574 |   |         while (true) { |   | 587 |   |         while (true) { | 
| 575 |   |  |   | 588 |   |  | 
| 576 |   |             HttpHeader header = request.allocateHeader(); |   | 589 |   |             HttpHeader header = request.allocateHeader(); | 
| 577 |   |  |   | 590 |   |  | 
| 578 |   |             // Read the next header |   | 591 |   |             // Read the next header | 
| 579 |   |             input.readHeader(header); |   | 592 |   |             input.readHeader(header); | 
| 580 |   |             if (header.nameEnd == 0) { |   | 593 |   |             if (header.nameEnd == 0) { | 
| 581 |   |                 if (header.valueEnd == 0) { |   | 594 |   |                 if (header.valueEnd == 0) { | 
| 582 |   |                     return; |   | 595 |   |                     return; | 
| 583 |   |                 } else { |   | 596 |   |                 } else { | 
| 584 |   |                     throw new ServletException |   | 597 |   |                     throw new ServletException | 
| 585 |   |                         (sm.getString("httpProcessor.parseHeaders.colon")); |   | 598 |   |                         (sm.getString("httpProcessor.parseHeaders.colon")); | 
| 586 |   |                 } |   | 599 |   |                 } | 
| 587 |   |             } |   | 600 |   |             } | 
| 588 |   |  |   | 601 |   |  | 
| 589 |   |             String value = new String(header.value, 0, header.valueEnd); |   | 602 |   |             String value = new String(header.value, 0, header.valueEnd); | 
| 590 |   |             if (debug >= 1) |   | 603 |   |             if (debug >= 1) | 
| 591 |   |                 log(" Header " + new String(header.name, 0, header.nameEnd) |   | 604 |   |                 log(" Header " + new String(header.name, 0, header.nameEnd) | 
| 592 |   |                     + " = " + value); |   | 605 |   |                     + " = " + value); | 
| 593 |   |  |   | 606 |   |  | 
| 594 |   |             // Set the corresponding request headers |   | 607 |   |             // Set the corresponding request headers | 
| 595 |   |             if (header.equals(DefaultHeaders.AUTHORIZATION_NAME)) { |   | 608 |   |             if (header.equals(DefaultHeaders.AUTHORIZATION_NAME)) { | 
| 596 |   |                 request.setAuthorization(value); |   | 609 |   |                 request.setAuthorization(value); | 
| 597 |   |             } else if (header.equals(DefaultHeaders.ACCEPT_LANGUAGE_NAME)) { |   | 610 |   |             } else if (header.equals(DefaultHeaders.ACCEPT_LANGUAGE_NAME)) { | 
| 598 |   |                 parseAcceptLanguage(value); |   | 611 |   |                 parseAcceptLanguage(value); | 
| 599 |   |             } else if (header.equals(DefaultHeaders.COOKIE_NAME)) { |   | 612 |   |             } else if (header.equals(DefaultHeaders.COOKIE_NAME)) { | 
| 600 |   |                 Cookie cookies[] = RequestUtil.parseCookieHeader(value); |   | 613 |   |                 Cookie cookies[] = RequestUtil.parseCookieHeader(value); | 
| 601 |   |                 for (int i = 0; i < cookies.length; i++) { |   | 614 |   |                 for (int i = 0; i < cookies.length; i++) { | 
| 602 |   |                     if (cookies[i].getName().equals |   | 615 |   |                     if (cookies[i].getName().equals | 
| 603 |   |                         (Globals.SESSION_COOKIE_NAME)) { |   | 616 |   |                         (Globals.SESSION_COOKIE_NAME)) { | 
| 604 |   |                         // Override anything requested in the URL |   | 617 |   |                         // Override anything requested in the URL | 
| 605 |   |                         if (!request.isRequestedSessionIdFromCookie()) { |   | 618 |   |                         if (!request.isRequestedSessionIdFromCookie()) { | 
| 606 |   |                             // Accept only the first session id cookie |   | 619 |   |                             // Accept only the first session id cookie | 
| 607 |   |                             request.setRequestedSessionId |   | 620 |   |                             request.setRequestedSessionId | 
| 608 |   |                                 (cookies[i].getValue()); |   | 621 |   |                                 (cookies[i].getValue()); | 
| 609 |   |                             request.setRequestedSessionCookie(true); |   | 622 |   |                             request.setRequestedSessionCookie(true); | 
| 610 |   |                             request.setRequestedSessionURL(false); |   | 623 |   |                             request.setRequestedSessionURL(false); | 
| 611 |   |                             if (debug >= 1) |   | 624 |   |                             if (debug >= 1) | 
| 612 |   |                                 log(" Requested cookie session id is " + |   | 625 |   |                                 log(" Requested cookie session id is " + | 
| 613 |   |                                     ((HttpServletRequest) request.getRequest()) |   | 626 |   |                                     ((HttpServletRequest) request.getRequest()) | 
| 614 |   |                                     .getRequestedSessionId()); |   | 627 |   |                                     .getRequestedSessionId()); | 
| 615 |   |                         } |   | 628 |   |                         } | 
| 616 |   |                     } |   | 629 |   |                     } | 
| 617 |   |                     if (debug >= 1) |   | 630 |   |                     if (debug >= 1) | 
| 618 |   |                         log(" Adding cookie " + cookies[i].getName() + "=" + |   | 631 |   |                         log(" Adding cookie " + cookies[i].getName() + "=" + | 
| 619 |   |                             cookies[i].getValue()); |   | 632 |   |                             cookies[i].getValue()); | 
| 620 |   |                     request.addCookie(cookies[i]); |   | 633 |   |                     request.addCookie(cookies[i]); | 
| 621 |   |                 } |   | 634 |   |                 } | 
| 622 |   |             } else if (header.equals(DefaultHeaders.CONTENT_LENGTH_NAME)) { |   | 635 |   |             } else if (header.equals(DefaultHeaders.CONTENT_LENGTH_NAME)) { | 
| 623 |   |                 int n = -1; |   | 636 |   |                 int n = -1; | 
| 624 |   |                 try { |   | 637 |   |                 try { | 
| 625 |   |                     n = Integer.parseInt(value); |   | 638 |   |                     n = Integer.parseInt(value); | 
| 626 |   |                 } catch (Exception e) { |   | 639 |   |                 } catch (Exception e) { | 
| 627 |   |                     throw new ServletException |   | 640 |   |                     throw new ServletException | 
| 628 |   |                         (sm.getString |   | 641 |   |                         (sm.getString | 
| 629 |   |                          ("httpProcessor.parseHeaders.contentLength")); |   | 642 |   |                          ("httpProcessor.parseHeaders.contentLength")); | 
| 630 |   |                 } |   | 643 |   |                 } | 
| 631 |   |                 request.setContentLength(n); |   | 644 |   |                 request.setContentLength(n); | 
| 632 |   |             } else if (header.equals(DefaultHeaders.CONTENT_TYPE_NAME)) { |   | 645 |   |             } else if (header.equals(DefaultHeaders.CONTENT_TYPE_NAME)) { | 
| 633 |   |                 request.setContentType(value); |   | 646 |   |                 request.setContentType(value); | 
| 634 |   |             } else if (header.equals(DefaultHeaders.HOST_NAME)) { |   | 647 |   |             } else if (header.equals(DefaultHeaders.HOST_NAME)) { | 
| 635 |   |                 int n = value.indexOf(':'); |   | 648 |   |                 int n = value.indexOf(':'); | 
| 636 |   |                 if (n < 0) { |   | 649 |   |                 if (n < 0) { | 
| 637 |   |                     if (connector.getScheme().equals("http")) { |   | 650 |   |                     if (connector.getScheme().equals("http")) { | 
| 638 |   |                         request.setServerPort(80); |   | 651 |   |                         request.setServerPort(80); | 
| 639 |   |                     } else if (connector.getScheme().equals("https")) { |   | 652 |   |                     } else if (connector.getScheme().equals("https")) { | 
| 640 |   |                         request.setServerPort(443); |   | 653 |   |                         request.setServerPort(443); | 
| 641 |   |                     } |   | 654 |   |                     } | 
| 642 |   |                     if (proxyName != null) |   | 655 |   |                     if (proxyName != null) | 
| 643 |   |                         request.setServerName(proxyName); |   | 656 |   |                         request.setServerName(proxyName); | 
| 644 |   |                     else |   | 657 |   |                     else | 
| 645 |   |                         request.setServerName(value); |   | 658 |   |                         request.setServerName(value); | 
| 646 |   |                 } else { |   | 659 |   |                 } else { | 
| 647 |   |                     if (proxyName != null) |   | 660 |   |                     if (proxyName != null) | 
| 648 |   |                         request.setServerName(proxyName); |   | 661 |   |                         request.setServerName(proxyName); | 
| 649 |   |                     else |   | 662 |   |                     else | 
| 650 |   |                         request.setServerName(value.substring(0, n).trim()); |   | 663 |   |                         request.setServerName(value.substring(0, n).trim()); | 
| 651 |   |                     if (proxyPort != 0) |   | 664 |   |                     if (proxyPort != 0) | 
| 652 |   |                         request.setServerPort(proxyPort); |   | 665 |   |                         request.setServerPort(proxyPort); | 
| 653 |   |                     else { |   | 666 |   |                     else { | 
| 654 |   |                         int port = 80; |   | 667 |   |                         int port = 80; | 
| 655 |   |                         try { |   | 668 |   |                         try { | 
| 656 |   |                             port = |   | 669 |   |                             port = | 
| 657 |   |                                 Integer.parseInt(value.substring(n+1).trim()); |   | 670 |   |                                 Integer.parseInt(value.substring(n+1).trim()); | 
| 658 |   |                         } catch (Exception e) { |   | 671 |   |                         } catch (Exception e) { | 
| 659 |   |                             throw new ServletException |   | 672 |   |                             throw new ServletException | 
| 660 |   |                                 (sm.getString |   | 673 |   |                                 (sm.getString | 
| 661 |   |                                  ("httpProcessor.parseHeaders.portNumber")); |   | 674 |   |                                  ("httpProcessor.parseHeaders.portNumber")); | 
| 662 |   |                         } |   | 675 |   |                         } | 
| 663 |   |                         request.setServerPort(port); |   | 676 |   |                         request.setServerPort(port); | 
| 664 |   |                     } |   | 677 |   |                     } | 
| 665 |   |                 } |   | 678 |   |                 } | 
| 666 |   |             } else if (header.equals(DefaultHeaders.CONNECTION_NAME)) { |   | 679 |   |             } else if (header.equals(DefaultHeaders.CONNECTION_NAME)) { | 
| 667 |   |                 if (header.valueEquals |   | 680 |   |                 if (header.valueEquals | 
| 668 |   |                     (DefaultHeaders.CONNECTION_CLOSE_VALUE)) { |   | 681 |   |                     (DefaultHeaders.CONNECTION_CLOSE_VALUE)) { | 
| 669 |   |                     keepAlive = false; |   | 682 |   |                     keepAlive = false; | 
| 670 |   |                     response.setHeader("Connection", "close"); |   | 683 |   |                     response.setHeader("Connection", "close"); | 
| 671 |   |                 } |   | 684 |   |                 } | 
| 672 |   |                 //request.setConnection(header); |   | 685 |   |                 //request.setConnection(header); | 
| 673 |   |                 /* |   | 686 |   |                 /* | 
| 674 |   |                   if ("keep-alive".equalsIgnoreCase(value)) { |   | 687 |   |                   if ("keep-alive".equalsIgnoreCase(value)) { | 
| 675 |   |                   keepAlive = true; |   | 688 |   |                   keepAlive = true; | 
| 676 |   |                   } |   | 689 |   |                   } | 
| 677 |   |                 */ |   | 690 |   |                 */ | 
| 678 |   |             } else if (header.equals(DefaultHeaders.EXPECT_NAME)) { |   | 691 |   |             } else if (header.equals(DefaultHeaders.EXPECT_NAME)) { | 
| 679 |   |                 if (header.valueEquals(DefaultHeaders.EXPECT_100_VALUE)) |   | 692 |   |                 if (header.valueEquals(DefaultHeaders.EXPECT_100_VALUE)) | 
| 680 |   |                     sendAck = true; |   | 693 |   |                     sendAck = true; | 
| 681 |   |                 else |   | 694 |   |                 else | 
| 682 |   |                     throw new ServletException |   | 695 |   |                     throw new ServletException | 
| 683 |   |                         (sm.getString |   | 696 |   |                         (sm.getString | 
| 684 |   |                          ("httpProcessor.parseHeaders.unknownExpectation")); |   | 697 |   |                          ("httpProcessor.parseHeaders.unknownExpectation")); | 
| 685 |   |             } else if (header.equals(DefaultHeaders.TRANSFER_ENCODING_NAME)) { |   | 698 |   |             } else if (header.equals(DefaultHeaders.TRANSFER_ENCODING_NAME)) { | 
| 686 |   |                 //request.setTransferEncoding(header); |   | 699 |   |                 //request.setTransferEncoding(header); | 
| 687 |   |             } |   | 700 |   |             } | 
| 688 |   |  |   | 701 |   |  | 
| 689 |   |             request.nextHeader(); |   | 702 |   |             request.nextHeader(); | 
| 690 |   |  |   | 703 |   |  | 
| 691 |   |         } |   | 704 |   |         } | 
| 692 |   |  |   | 705 |   |  | 
| 693 |   |     } |   | 706 |   |     } | 
| 694 |   |  |   | 707 |   |  | 
| 695 |   |  |   | 708 |   |  | 
| 696 |   |     /** |   | 709 |   |     /** | 
| 697 |   |      * Parse the incoming HTTP request and set the corresponding HTTP request |   | 710 |   |      * Parse the incoming HTTP request and set the corresponding HTTP request | 
| 698 |   |      * properties. |   | 711 |   |      * properties. | 
| 699 |   |      * |   | 712 |   |      * | 
| 700 |   |      * @param input The input stream attached to our socket |   | 713 |   |      * @param input The input stream attached to our socket | 
| 701 |   |      * @param output The output stream of the socket |   | 714 |   |      * @param output The output stream of the socket | 
| 702 |   |      * |   | 715 |   |      * | 
| 703 |   |      * @exception IOException if an input/output error occurs |   | 716 |   |      * @exception IOException if an input/output error occurs | 
| 704 |   |      * @exception ServletException if a parsing error occurs |   | 717 |   |      * @exception ServletException if a parsing error occurs | 
| 705 |   |      */ |   | 718 |   |      */ | 
| 706 |   |     private void parseRequest(SocketInputStream input, OutputStream output) |   | 719 |   |     private void parseRequest(SocketInputStream input, OutputStream output) | 
| 707 |   |         throws IOException, ServletException { |   | 720 |   |         throws IOException, ServletException { | 
| 708 |   |  |   | 721 |   |  | 
| 709 |   |         // Parse the incoming request line |   | 722 |   |         // Parse the incoming request line | 
| 710 |   |         input.readRequestLine(requestLine); |   | 723 |   |         input.readRequestLine(requestLine); | 
| 711 |   |          |   | 724 |   |          | 
| 712 |   |         // When the previous method returns, we're actually processing a  |   | 725 |   |         // When the previous method returns, we're actually processing a  | 
| 713 |   |         // request |   | 726 |   |         // request | 
| 714 |   |         status = Constants.PROCESSOR_ACTIVE; |   | 727 |   |         status = Constants.PROCESSOR_ACTIVE; | 
| 715 |   |          |   | 728 |   |          | 
| 716 |   |         String method = |   | 729 |   |         String method = | 
| 717 |   |             new String(requestLine.method, 0, requestLine.methodEnd); |   | 730 |   |             new String(requestLine.method, 0, requestLine.methodEnd); | 
| 718 |   |         String uri = null; |   | 731 |   |         String uri = null; | 
| 719 |   |         String protocol = new String(requestLine.protocol, 0, |   | 732 |   |         String protocol = new String(requestLine.protocol, 0, | 
| 720 |   |                                      requestLine.protocolEnd); |   | 733 |   |                                      requestLine.protocolEnd); | 
| 721 |   |  |   | 734 |   |  | 
| 722 |   |         //System.out.println(" Method:" + method + "_ Uri:" + uri |   | 735 |   |         //System.out.println(" Method:" + method + "_ Uri:" + uri | 
| 723 |   |         //                   + "_ Protocol:" + protocol); |   | 736 |   |         //                   + "_ Protocol:" + protocol); | 
| 724 |   |  |   | 737 |   |  | 
| 725 |   |         if (protocol.length() == 0) |   | 738 |   |         if (protocol.length() == 0) | 
| 726 |   |             protocol = "HTTP/0.9"; |   | 739 |   |             protocol = "HTTP/0.9"; | 
| 727 |   |  |   | 740 |   |  | 
| 728 |   |         // Now check if the connection should be kept alive after parsing the |   | 741 |   |         // Now check if the connection should be kept alive after parsing the | 
| 729 |   |         // request. |   | 742 |   |         // request. | 
| 730 |   |         if ( protocol.equals("HTTP/1.1") ) { |   | 743 |   |         if ( protocol.equals("HTTP/1.1") ) { | 
| 731 |   |             http11 = true; |   | 744 |   |             http11 = true; | 
| 732 |   |             sendAck = false; |   | 745 |   |             sendAck = false; | 
| 733 |   |         } else { |   | 746 |   |         } else { | 
| 734 |   |             http11 = false; |   | 747 |   |             http11 = false; | 
| 735 |   |             sendAck = false; |   | 748 |   |             sendAck = false; | 
| 736 |   |             // For HTTP/1.0, connection are not persistent by default, |   | 749 |   |             // For HTTP/1.0, connection are not persistent by default, | 
| 737 |   |             // unless specified with a Connection: Keep-Alive header. |   | 750 |   |             // unless specified with a Connection: Keep-Alive header. | 
| 738 |   |             keepAlive = false; |   | 751 |   |             keepAlive = false; | 
| 739 |   |         } |   | 752 |   |         } | 
| 740 |   |  |   | 753 |   |  | 
| 741 |   |         // Validate the incoming request line |   | 754 |   |         // Validate the incoming request line | 
| 742 |   |         if (method.length() < 1) { |   | 755 |   |         if (method.length() < 1) { | 
| 743 |   |             throw new ServletException |   | 756 |   |             throw new ServletException | 
| 744 |   |                 (sm.getString("httpProcessor.parseRequest.method")); |   | 757 |   |                 (sm.getString("httpProcessor.parseRequest.method")); | 
| 745 |   |         } else if (requestLine.uriEnd < 1) { |   | 758 |   |         } else if (requestLine.uriEnd < 1) { | 
| 746 |   |             throw new ServletException |   | 759 |   |             throw new ServletException | 
| 747 |   |                 (sm.getString("httpProcessor.parseRequest.uri")); |   | 760 |   |                 (sm.getString("httpProcessor.parseRequest.uri")); | 
| 748 |   |         } |   | 761 |   |         } | 
| 749 |   |  |   | 762 |   |  | 
| 750 |   |         // Parse any query parameters out of the request URI |   | 763 |   |         // Parse any query parameters out of the request URI | 
| 751 |   |         int question = requestLine.indexOf("?"); |   | 764 |   |         int question = requestLine.indexOf("?"); | 
| 752 |   |         if (question >= 0) { |   | 765 |   |         if (question >= 0) { | 
| 753 |   |             request.setQueryString |   | 766 |   |             request.setQueryString | 
| 754 |   |                 (new String(requestLine.uri, question + 1, |   | 767 |   |                 (new String(requestLine.uri, question + 1, | 
| 755 |   |                             requestLine.uriEnd - question - 1)); |   | 768 |   |                             requestLine.uriEnd - question - 1)); | 
| 756 |   |             if (debug >= 1) |   | 769 |   |             if (debug >= 1) | 
| 757 |   |                 log(" Query string is " + |   | 770 |   |                 log(" Query string is " + | 
| 758 |   |                     ((HttpServletRequest) request.getRequest()) |   | 771 |   |                     ((HttpServletRequest) request.getRequest()) | 
| 759 |   |                     .getQueryString()); |   | 772 |   |                     .getQueryString()); | 
| 760 |   |             uri = new String(requestLine.uri, 0, question); |   | 773 |   |             uri = new String(requestLine.uri, 0, question); | 
| 761 |   |         } else { |   | 774 |   |         } else { | 
| 762 |   |             request.setQueryString(null); |   | 775 |   |             request.setQueryString(null); | 
| 763 |   |             uri = new String(requestLine.uri, 0, requestLine.uriEnd); |   | 776 |   |             uri = new String(requestLine.uri, 0, requestLine.uriEnd); | 
| 764 |   |         } |   | 777 |   |         } | 
| 765 |   |  |   | 778 |   |  | 
| 766 |   |         // Checking for an absolute URI (with the HTTP protocol) |   | 779 |   |         // Checking for an absolute URI (with the HTTP protocol) | 
| 767 |   |         if (!uri.startsWith("/")) { |   | 780 |   |         if (!uri.startsWith("/")) { | 
| 768 |   |             int pos = uri.indexOf("://"); |   | 781 |   |             int pos = uri.indexOf("://"); | 
| 769 |   |             // Parsing out protocol and host name |   | 782 |   |             // Parsing out protocol and host name | 
| 770 |   |             if (pos != -1) { |   | 783 |   |             if (pos != -1) { | 
| 771 |   |                 pos = uri.indexOf('/', pos + 3); |   | 784 |   |                 pos = uri.indexOf('/', pos + 3); | 
| 772 |   |                 if (pos == -1) { |   | 785 |   |                 if (pos == -1) { | 
| 773 |   |                     uri = ""; |   | 786 |   |                     uri = ""; | 
| 774 |   |                 } else { |   | 787 |   |                 } else { | 
| 775 |   |                     uri = uri.substring(pos); |   | 788 |   |                     uri = uri.substring(pos); | 
| 776 |   |                 } |   | 789 |   |                 } | 
| 777 |   |             } |   | 790 |   |             } | 
| 778 |   |         } |   | 791 |   |         } | 
| 779 |   |  |   | 792 |   |  | 
| 780 |   |         // Parse any requested session ID out of the request URI |   | 793 |   |         // Parse any requested session ID out of the request URI | 
| 781 |   |         int semicolon = uri.indexOf(match); |   | 794 |   |         int semicolon = uri.indexOf(match); | 
| 782 |   |         if (semicolon >= 0) { |   | 795 |   |         if (semicolon >= 0) { | 
| 783 |   |             String rest = uri.substring(semicolon + match.length()); |   | 796 |   |             String rest = uri.substring(semicolon + match.length()); | 
| 784 |   |             int semicolon2 = rest.indexOf(';'); |   | 797 |   |             int semicolon2 = rest.indexOf(';'); | 
| 785 |   |             if (semicolon2 >= 0) { |   | 798 |   |             if (semicolon2 >= 0) { | 
| 786 |   |                 request.setRequestedSessionId(rest.substring(0, semicolon2)); |   | 799 |   |                 request.setRequestedSessionId(rest.substring(0, semicolon2)); | 
| 787 |   |                 rest = rest.substring(semicolon2); |   | 800 |   |                 rest = rest.substring(semicolon2); | 
| 788 |   |             } else { |   | 801 |   |             } else { | 
| 789 |   |                 request.setRequestedSessionId(rest); |   | 802 |   |                 request.setRequestedSessionId(rest); | 
| 790 |   |                 rest = ""; |   | 803 |   |                 rest = ""; | 
| 791 |   |             } |   | 804 |   |             } | 
| 792 |   |             request.setRequestedSessionURL(true); |   | 805 |   |             request.setRequestedSessionURL(true); | 
| 793 |   |             uri = uri.substring(0, semicolon) + rest; |   | 806 |   |             uri = uri.substring(0, semicolon) + rest; | 
| 794 |   |             if (debug >= 1) |   | 807 |   |             if (debug >= 1) | 
| 795 |   |                 log(" Requested URL session id is " + |   | 808 |   |                 log(" Requested URL session id is " + | 
| 796 |   |                     ((HttpServletRequest) request.getRequest()) |   | 809 |   |                     ((HttpServletRequest) request.getRequest()) | 
| 797 |   |                     .getRequestedSessionId()); |   | 810 |   |                     .getRequestedSessionId()); | 
| 798 |   |         } else { |   | 811 |   |         } else { | 
| 799 |   |             request.setRequestedSessionId(null); |   | 812 |   |             request.setRequestedSessionId(null); | 
| 800 |   |             request.setRequestedSessionURL(false); |   | 813 |   |             request.setRequestedSessionURL(false); | 
| 801 |   |         } |   | 814 |   |         } | 
| 802 |   |  |   | 815 |   |  | 
| 803 |   |         // Normalize URI (using String operations at the moment) |   | 816 |   |         // Normalize URI (using String operations at the moment) | 
| 804 |   |         String normalizedUri = normalize(uri); |   | 817 |   |         String normalizedUri = normalize(uri); | 
| 805 |   |         if (debug >= 1) |   | 818 |   |         if (debug >= 1) | 
| 806 |   |             log("Normalized: '" + uri + "' to '" + normalizedUri + "'"); |   | 819 |   |             log("Normalized: '" + uri + "' to '" + normalizedUri + "'"); | 
| 807 |   |  |   | 820 |   |  | 
| 808 |   |         // Set the corresponding request properties |   | 821 |   |         // Set the corresponding request properties | 
| 809 |   |         ((HttpRequest) request).setMethod(method); |   | 822 |   |         ((HttpRequest) request).setMethod(method); | 
| 810 |   |         request.setProtocol(protocol); |   | 823 |   |         request.setProtocol(protocol); | 
| 811 |   |         if (normalizedUri != null) { |   | 824 |   |         if (normalizedUri != null) { | 
| 812 |   |             ((HttpRequest) request).setRequestURI(normalizedUri); |   | 825 |   |             ((HttpRequest) request).setRequestURI(normalizedUri); | 
| 813 |   |         } else { |   | 826 |   |         } else { | 
| 814 |   |             ((HttpRequest) request).setRequestURI(uri); |   | 827 |   |             ((HttpRequest) request).setRequestURI(uri); | 
| 815 |   |         } |   | 828 |   |         } | 
| 816 |   |         request.setSecure(connector.getSecure()); |   | 829 |   |         request.setSecure(connector.getSecure()); | 
| 817 |   |         request.setScheme(connector.getScheme()); |   | 830 |   |         request.setScheme(connector.getScheme()); | 
| 818 |   |  |   | 831 |   |  | 
| 819 |   |         if (normalizedUri == null) { |   | 832 |   |         if (normalizedUri == null) { | 
| 820 |   |             log(" Invalid request URI: '" + uri + "'"); |   | 833 |   |             log(" Invalid request URI: '" + uri + "'"); | 
| 821 |   |             throw new ServletException("Invalid URI: " + uri + "'"); |   | 834 |   |             throw new ServletException("Invalid URI: " + uri + "'"); | 
| 822 |   |         } |   | 835 |   |         } | 
| 823 |   |  |   | 836 |   |  | 
| 824 |   |         if (debug >= 1) |   | 837 |   |         if (debug >= 1) | 
| 825 |   |             log(" Request is '" + method + "' for '" + uri + |   | 838 |   |             log(" Request is '" + method + "' for '" + uri + | 
| 826 |   |                 "' with protocol '" + protocol + "'"); |   | 839 |   |                 "' with protocol '" + protocol + "'"); | 
| 827 |   |  |   | 840 |   |  | 
| 828 |   |     } |   | 841 |   |     } | 
| 829 |   |  |   | 842 |   |  | 
| 830 |   |  |   | 843 |   |  | 
| 831 |   |     /** |   | 844 |   |     /** | 
| 832 |   |      * Return a context-relative path, beginning with a "/", that represents |   | 845 |   |      * Return a context-relative path, beginning with a "/", that represents | 
| 833 |   |      * the canonical version of the specified path after ".." and "." elements |   | 846 |   |      * the canonical version of the specified path after ".." and "." elements | 
| 834 |   |      * are resolved out.  If the specified path attempts to go outside the |   | 847 |   |      * are resolved out.  If the specified path attempts to go outside the | 
| 835 |   |      * boundaries of the current context (i.e. too many ".." path elements |   | 848 |   |      * boundaries of the current context (i.e. too many ".." path elements | 
| 836 |   |      * are present), return <code>null</code> instead. |   | 849 |   |      * are present), return <code>null</code> instead. | 
| 837 |   |      * |   | 850 |   |      * | 
| 838 |   |      * @param path Path to be normalized |   | 851 |   |      * @param path Path to be normalized | 
| 839 |   |      */ |   | 852 |   |      */ | 
| 840 |   |     protected String normalize(String path) { |   | 853 |   |     protected String normalize(String path) { | 
| 841 |   |  |   | 854 |   |  | 
| 842 |   |         if (path == null) |   | 855 |   |         if (path == null) | 
| 843 |   |             return null; |   | 856 |   |             return null; | 
| 844 |   |  |   | 857 |   |  | 
| 845 |   |         // Create a place for the normalized path |   | 858 |   |         // Create a place for the normalized path | 
| 846 |   |         String normalized = path; |   | 859 |   |         String normalized = path; | 
| 847 |   |  |   | 860 |   |  | 
| 848 |   |         // Normalize "/%7E" and "/%7e" at the beginning to "/~" |   | 861 |   |         // Normalize "/%7E" and "/%7e" at the beginning to "/~" | 
| 849 |   |         if (normalized.startsWith("/%7E") || |   | 862 |   |         if (normalized.startsWith("/%7E") || | 
| 850 |   |             normalized.startsWith("/%7e")) |   | 863 |   |             normalized.startsWith("/%7e")) | 
| 851 |   |             normalized = "/~" + normalized.substring(4); |   | 864 |   |             normalized = "/~" + normalized.substring(4); | 
| 852 |   |  |   | 865 |   |  | 
| 853 |   |         // Prevent encoding '%', '/', '.' and '\', which are special reserved |   | 866 |   |         // Prevent encoding '%', '/', '.' and '\', which are special reserved | 
| 854 |   |         // characters |   | 867 |   |         // characters | 
| 855 |   |         if ((normalized.indexOf("%25") >= 0) |   | 868 |   |         if ((normalized.indexOf("%25") >= 0) | 
| 856 |   |             || (normalized.indexOf("%2F") >= 0) |   | 869 |   |             || (normalized.indexOf("%2F") >= 0) | 
| 857 |   |             || (normalized.indexOf("%2E") >= 0) |   | 870 |   |             || (normalized.indexOf("%2E") >= 0) | 
| 858 |   |             || (normalized.indexOf("%5C") >= 0) |   | 871 |   |             || (normalized.indexOf("%5C") >= 0) | 
| 859 |   |             || (normalized.indexOf("%2f") >= 0) |   | 872 |   |             || (normalized.indexOf("%2f") >= 0) | 
| 860 |   |             || (normalized.indexOf("%2e") >= 0) |   | 873 |   |             || (normalized.indexOf("%2e") >= 0) | 
| 861 |   |             || (normalized.indexOf("%5c") >= 0)) { |   | 874 |   |             || (normalized.indexOf("%5c") >= 0)) { | 
| 862 |   |             return null; |   | 875 |   |             return null; | 
| 863 |   |         } |   | 876 |   |         } | 
| 864 |   |  |   | 877 |   |  | 
| 865 |   |         if (normalized.equals("/.")) |   | 878 |   |         if (normalized.equals("/.")) | 
| 866 |   |             return "/"; |   | 879 |   |             return "/"; | 
| 867 |   |  |   | 880 |   |  | 
| 868 |   |         // Normalize the slashes and add leading slash if necessary |   | 881 |   |         // Normalize the slashes and add leading slash if necessary | 
| 869 |   |         if (normalized.indexOf('\\') >= 0) |   | 882 |   |         if (normalized.indexOf('\\') >= 0) | 
| 870 |   |             normalized = normalized.replace('\\', '/'); |   | 883 |   |             normalized = normalized.replace('\\', '/'); | 
| 871 |   |         if (!normalized.startsWith("/")) |   | 884 |   |         if (!normalized.startsWith("/")) | 
| 872 |   |             normalized = "/" + normalized; |   | 885 |   |             normalized = "/" + normalized; | 
| 873 |   |  |   | 886 |   |  | 
| 874 |   |         // Resolve occurrences of "//" in the normalized path |   | 887 |   |         // Resolve occurrences of "//" in the normalized path | 
| 875 |   |         while (true) { |   | 888 |   |         while (true) { | 
| 876 |   |             int index = normalized.indexOf("//"); |   | 889 |   |             int index = normalized.indexOf("//"); | 
| 877 |   |             if (index < 0) |   | 890 |   |             if (index < 0) | 
| 878 |   |                 break; |   | 891 |   |                 break; | 
| 879 |   |             normalized = normalized.substring(0, index) + |   | 892 |   |             normalized = normalized.substring(0, index) + | 
| 880 |   |                 normalized.substring(index + 1); |   | 893 |   |                 normalized.substring(index + 1); | 
| 881 |   |         } |   | 894 |   |         } | 
| 882 |   |  |   | 895 |   |  | 
| 883 |   |         // Resolve occurrences of "/./" in the normalized path |   | 896 |   |         // Resolve occurrences of "/./" in the normalized path | 
| 884 |   |         while (true) { |   | 897 |   |         while (true) { | 
| 885 |   |             int index = normalized.indexOf("/./"); |   | 898 |   |             int index = normalized.indexOf("/./"); | 
| 886 |   |             if (index < 0) |   | 899 |   |             if (index < 0) | 
| 887 |   |                 break; |   | 900 |   |                 break; | 
| 888 |   |             normalized = normalized.substring(0, index) + |   | 901 |   |             normalized = normalized.substring(0, index) + | 
| 889 |   |                 normalized.substring(index + 2); |   | 902 |   |                 normalized.substring(index + 2); | 
| 890 |   |         } |   | 903 |   |         } | 
| 891 |   |  |   | 904 |   |  | 
| 892 |   |         // Resolve occurrences of "/../" in the normalized path |   | 905 |   |         // Resolve occurrences of "/../" in the normalized path | 
| 893 |   |         while (true) { |   | 906 |   |         while (true) { | 
| 894 |   |             int index = normalized.indexOf("/../"); |   | 907 |   |             int index = normalized.indexOf("/../"); | 
| 895 |   |             if (index < 0) |   | 908 |   |             if (index < 0) | 
| 896 |   |                 break; |   | 909 |   |                 break; | 
| 897 |   |             if (index == 0) |   | 910 |   |             if (index == 0) | 
| 898 |   |                 return (null);  // Trying to go outside our context |   | 911 |   |                 return (null);  // Trying to go outside our context | 
| 899 |   |             int index2 = normalized.lastIndexOf('/', index - 1); |   | 912 |   |             int index2 = normalized.lastIndexOf('/', index - 1); | 
| 900 |   |             normalized = normalized.substring(0, index2) + |   | 913 |   |             normalized = normalized.substring(0, index2) + | 
| 901 |   |                 normalized.substring(index + 3); |   | 914 |   |                 normalized.substring(index + 3); | 
| 902 |   |         } |   | 915 |   |         } | 
| 903 |   |  |   | 916 |   |  | 
| 904 |   |         // Declare occurrences of "/..." (three or more dots) to be invalid |   | 917 |   |         // Declare occurrences of "/..." (three or more dots) to be invalid | 
| 905 |   |         // (on some Windows platforms this walks the directory tree!!!) |   | 918 |   |         // (on some Windows platforms this walks the directory tree!!!) | 
| 906 |   |         if (normalized.indexOf("/...") >= 0) |   | 919 |   |         if (normalized.indexOf("/...") >= 0) | 
| 907 |   |             return (null); |   | 920 |   |             return (null); | 
| 908 |   |  |   | 921 |   |  | 
| 909 |   |         // Return the normalized path that we have completed |   | 922 |   |         // Return the normalized path that we have completed | 
| 910 |   |         return (normalized); |   | 923 |   |         return (normalized); | 
| 911 |   |  |   | 924 |   |  | 
| 912 |   |     } |   | 925 |   |     } | 
| 913 |   |  |   | 926 |   |  | 
| 914 |   |  |   | 927 |   |  | 
| 915 |   |     /** |   | 928 |   |     /** | 
| 916 |   |      * Send a confirmation that a request has been processed when pipelining. |   | 929 |   |      * Send a confirmation that a request has been processed when pipelining. | 
| 917 |   |      * HTTP/1.1 100 Continue is sent back to the client. |   | 930 |   |      * HTTP/1.1 100 Continue is sent back to the client. | 
| 918 |   |      * |   | 931 |   |      * | 
| 919 |   |      * @param output Socket output stream |   | 932 |   |      * @param output Socket output stream | 
| 920 |   |      */ |   | 933 |   |      */ | 
| 921 |   |     private void ackRequest(OutputStream output) |   | 934 |   |     private void ackRequest(OutputStream output) | 
| 922 |   |         throws IOException { |   | 935 |   |         throws IOException { | 
| 923 |   |         if (sendAck) |   | 936 |   |         if (sendAck) | 
| 924 |   |             output.write(ack); |   | 937 |   |             output.write(ack); | 
| 925 |   |     } |   | 938 |   |     } | 
| 926 |   |  |   | 939 |   |  | 
| 927 |   |  |   | 940 |   |  | 
| 928 |   |     /** |   | 941 |   |     /** | 
| 929 |   |      * Process an incoming HTTP request on the Socket that has been assigned |   | 942 |   |      * Process an incoming HTTP request on the Socket that has been assigned | 
| 930 |   |      * to this Processor.  Any exceptions that occur during processing must be |   | 943 |   |      * to this Processor.  Any exceptions that occur during processing must be | 
| 931 |   |      * swallowed and dealt with. |   | 944 |   |      * swallowed and dealt with. | 
| 932 |   |      * |   | 945 |   |      * | 
| 933 |   |      * @param socket The socket on which we are connected to the client |   | 946 |   |      * @param socket The socket on which we are connected to the client | 
| 934 |   |      */ |   | 947 |   |      */ | 
| 935 |   |     private void process(Socket socket) { |   | 948 |   |     private void process(Socket socket) { | 
| 936 |   |  |   | 949 |   |  | 
| 937 |   |         boolean ok = true; |   | 950 |   |         boolean ok = true; | 
| 938 |   |         boolean finishResponse = true; |   | 951 |   |         boolean finishResponse = true; | 
| 939 |   |         SocketInputStream input = null; |   | 952 |   |         SocketInputStream input = null; | 
| 940 |   |         OutputStream output = null; |   | 953 |   |         OutputStream output = null; | 
| 941 |   |  |   | 954 |   |  | 
| 942 |   |         // Construct and initialize the objects we will need |   | 955 |   |         // Construct and initialize the objects we will need | 
| 943 |   |         try { |   | 956 |   |         try { | 
| 944 |   |             input = new SocketInputStream(socket.getInputStream(), |   | 957 |   |             input = new SocketInputStream(socket.getInputStream(), | 
| 945 |   |                                           connector.getBufferSize()); |   | 958 |   |                                           connector.getBufferSize()); | 
| 946 |   |         } catch (Exception e) { |   | 959 |   |         } catch (Exception e) { | 
| 947 |   |             log("process.create", e); |   | 960 |   |             log("process.create", e); | 
| 948 |   |             ok = false; |   | 961 |   |             ok = false; | 
| 949 |   |         } |   | 962 |   |         } | 
| 950 |   |  |   | 963 |   |  | 
| 951 |   |         keepAlive = true; |   | 964 |   |         keepAlive = true; | 
| 952 |   |  |   | 965 |   |  | 
| 953 |   |         while (!stopped && ok && keepAlive) { |   | 966 |   |         while (!stopped && ok && keepAlive) { | 
| 954 |   |  |   | 967 |   |  | 
| 955 |   |             finishResponse = true; |   | 968 |   |             finishResponse = true; | 
| 956 |   |  |   | 969 |   |  | 
| 957 |   |             try { |   | 970 |   |             try { | 
| 958 |   |                 request.setStream(input); |   | 971 |   |                 request.setStream(input); | 
| 959 |   |                 request.setResponse(response); |   | 972 |   |                 request.setResponse(response); | 
| 960 |   |                 output = socket.getOutputStream(); |   | 973 |   |                 output = socket.getOutputStream(); | 
| 961 |   |                 response.setStream(output); |   | 974 |   |                 response.setStream(output); | 
| 962 |   |                 response.setRequest(request); |   | 975 |   |                 response.setRequest(request); | 
| 963 |   |                 ((HttpServletResponse) response.getResponse()).setHeader |   | 976 |   |                 ((HttpServletResponse) response.getResponse()).setHeader | 
| 964 |   |                     ("Server", Constants.ServerInfo); |   | 977 |   |                     ("Server",    SERVER_INFO); | 
| 965 |   |             } catch (Exception e) { |   | 978 |   |             } catch (Exception e) { | 
| 966 |   |                 log("process.create", e); |   | 979 |   |                 log("process.create", e); | 
| 967 |   |                 ok = false; |   | 980 |   |                 ok = false; | 
| 968 |   |             } |   | 981 |   |             } | 
| 969 |   |  |   | 982 |   |  | 
| 970 |   |             // Parse the incoming request |   | 983 |   |             // Parse the incoming request | 
| 971 |   |             try { |   | 984 |   |             try { | 
| 972 |   |                 if (ok) { |   | 985 |   |                 if (ok) { | 
| 973 |   |                     parseConnection(socket); |   | 986 |   |                     parseConnection(socket); | 
| 974 |   |                     parseRequest(input, output); |   | 987 |   |                     parseRequest(input, output); | 
| 975 |   |                     if (!request.getRequest().getProtocol() |   | 988 |   |                     if (!request.getRequest().getProtocol() | 
| 976 |   |                         .startsWith("HTTP/0")) |   | 989 |   |                         .startsWith("HTTP/0")) | 
| 977 |   |                         parseHeaders(input); |   | 990 |   |                         parseHeaders(input); | 
| 978 |   |                     if (http11) { |   | 991 |   |                     if (http11) { | 
| 979 |   |                         // Sending a request acknowledge back to the client if |   | 992 |   |                         // Sending a request acknowledge back to the client if | 
| 980 |   |                         // requested. |   | 993 |   |                         // requested. | 
| 981 |   |                         ackRequest(output); |   | 994 |   |                         ackRequest(output); | 
| 982 |   |                         // If the protocol is HTTP/1.1, chunking is allowed. |   | 995 |   |                         // If the protocol is HTTP/1.1, chunking is allowed. | 
| 983 |   |                         if (connector.isChunkingAllowed()) |   | 996 |   |                         if (connector.isChunkingAllowed()) | 
| 984 |   |                             response.setAllowChunking(true); |   | 997 |   |                             response.setAllowChunking(true); | 
| 985 |   |                     } |   | 998 |   |                     } | 
| 986 |   |                 } |   | 999 |   |                 } | 
| 987 |   |             } catch (EOFException e) { |   | 1000 |   |             } catch (EOFException e) { | 
| 988 |   |                 // It's very likely to be a socket disconnect on either the  |   | 1001 |   |                 // It's very likely to be a socket disconnect on either the  | 
| 989 |   |                 // client or the server |   | 1002 |   |                 // client or the server | 
| 990 |   |                 ok = false; |   | 1003 |   |                 ok = false; | 
| 991 |   |                 finishResponse = false; |   | 1004 |   |                 finishResponse = false; | 
| 992 |   |             } catch (ServletException e) { |   | 1005 |   |             } catch (ServletException e) { | 
| 993 |   |                 ok = false; |   | 1006 |   |                 ok = false; | 
| 994 |   |                 try { |   | 1007 |   |                 try { | 
| 995 |   |                     ((HttpServletResponse) response.getResponse()) |   | 1008 |   |                     ((HttpServletResponse) response.getResponse()) | 
| 996 |   |                         .sendError(HttpServletResponse.SC_BAD_REQUEST); |   | 1009 |   |                         .sendError(HttpServletResponse.SC_BAD_REQUEST); | 
| 997 |   |                 } catch (Exception f) { |   | 1010 |   |                 } catch (Exception f) { | 
| 998 |   |                     ; |   | 1011 |   |                     ; | 
| 999 |   |                 } |   | 1012 |   |                 } | 
| 1000 |   |             } catch (InterruptedIOException e) { |   | 1013 |   |             } catch (InterruptedIOException e) { | 
| 1001 |   |                 if (debug > 1) { |   | 1014 |   |                 if (debug > 1) { | 
| 1002 |   |                     try { |   | 1015 |   |                     try { | 
| 1003 |   |                         log("process.parse", e); |   | 1016 |   |                         log("process.parse", e); | 
| 1004 |   |                         ((HttpServletResponse) response.getResponse()) |   | 1017 |   |                         ((HttpServletResponse) response.getResponse()) | 
| 1005 |   |                             .sendError(HttpServletResponse.SC_BAD_REQUEST); |   | 1018 |   |                             .sendError(HttpServletResponse.SC_BAD_REQUEST); | 
| 1006 |   |                     } catch (Exception f) { |   | 1019 |   |                     } catch (Exception f) { | 
| 1007 |   |                         ; |   | 1020 |   |                         ; | 
| 1008 |   |                     } |   | 1021 |   |                     } | 
| 1009 |   |                 } |   | 1022 |   |                 } | 
| 1010 |   |                 ok = false; |   | 1023 |   |                 ok = false; | 
| 1011 |   |             } catch (Exception e) { |   | 1024 |   |             } catch (Exception e) { | 
| 1012 |   |                 try { |   | 1025 |   |                 try { | 
| 1013 |   |                     log("process.parse", e); |   | 1026 |   |                     log("process.parse", e); | 
| 1014 |   |                     ((HttpServletResponse) response.getResponse()).sendError |   | 1027 |   |                     ((HttpServletResponse) response.getResponse()).sendError | 
| 1015 |   |                         (HttpServletResponse.SC_BAD_REQUEST); |   | 1028 |   |                         (HttpServletResponse.SC_BAD_REQUEST); | 
| 1016 |   |                 } catch (Exception f) { |   | 1029 |   |                 } catch (Exception f) { | 
| 1017 |   |                     ; |   | 1030 |   |                     ; | 
| 1018 |   |                 } |   | 1031 |   |                 } | 
| 1019 |   |                 ok = false; |   | 1032 |   |                 ok = false; | 
| 1020 |   |             } |   | 1033 |   |             } | 
| 1021 |   |  |   | 1034 |   |  | 
| 1022 |   |             // Ask our Container to process this request |   | 1035 |   |             // Ask our Container to process this request | 
| 1023 |   |             try { |   | 1036 |   |             try { | 
| 1024 |   |                 ((HttpServletResponse) response).addDate   Header |   | 1037 |   |                 ((HttpServletResponse) response).setHeader | 
| 1025 |   |                     ("Date", Syst   e  m  .currentTimeMillis()); |   | 1038 |   |                     ("Date", FastHttpDateFormat.getCurrentDate   ()); | 
| 1026 |   |                 if (ok) { |   | 1039 |   |                 if (ok) { | 
| 1027 |   |                     connector.getContainer().invoke(request, response); |   | 1040 |   |                     connector.getContainer().invoke(request, response); | 
| 1028 |   |                 } |   | 1041 |   |                 } | 
| 1029 |   |             } catch (ServletException e) { |   | 1042 |   |             } catch (ServletException e) { | 
| 1030 |   |                 log("process.invoke", e); |   | 1043 |   |                 log("process.invoke", e); | 
| 1031 |   |                 try { |   | 1044 |   |                 try { | 
| 1032 |   |                     ((HttpServletResponse) response.getResponse()).sendError |   | 1045 |   |                     ((HttpServletResponse) response.getResponse()).sendError | 
| 1033 |   |                         (HttpServletResponse.SC_INTERNAL_SERVER_ERROR); |   | 1046 |   |                         (HttpServletResponse.SC_INTERNAL_SERVER_ERROR); | 
| 1034 |   |                 } catch (Exception f) { |   | 1047 |   |                 } catch (Exception f) { | 
| 1035 |   |                     ; |   | 1048 |   |                     ; | 
| 1036 |   |                 } |   | 1049 |   |                 } | 
| 1037 |   |                 ok = false; |   | 1050 |   |                 ok = false; | 
| 1038 |   |             } catch (InterruptedIOException e) { |   | 1051 |   |             } catch (InterruptedIOException e) { | 
| 1039 |   |                 ok = false; |   | 1052 |   |                 ok = false; | 
| 1040 |   |             } catch (Throwable e) { |   | 1053 |   |             } catch (Throwable e) { | 
| 1041 |   |                 log("process.invoke", e); |   | 1054 |   |                 log("process.invoke", e); | 
| 1042 |   |                 try { |   | 1055 |   |                 try { | 
| 1043 |   |                     ((HttpServletResponse) response.getResponse()).sendError |   | 1056 |   |                     ((HttpServletResponse) response.getResponse()).sendError | 
| 1044 |   |                         (HttpServletResponse.SC_INTERNAL_SERVER_ERROR); |   | 1057 |   |                         (HttpServletResponse.SC_INTERNAL_SERVER_ERROR); | 
| 1045 |   |                 } catch (Exception f) { |   | 1058 |   |                 } catch (Exception f) { | 
| 1046 |   |                     ; |   | 1059 |   |                     ; | 
| 1047 |   |                 } |   | 1060 |   |                 } | 
| 1048 |   |                 ok = false; |   | 1061 |   |                 ok = false; | 
| 1049 |   |             } |   | 1062 |   |             } | 
| 1050 |   |  |   | 1063 |   |  | 
| 1051 |   |             // Finish up the handling of the request |   | 1064 |   |             // Finish up the handling of the request | 
| 1052 |   |             try { |   | 1065 |   |             if (finishResponse) { | 
| 1053 |   |                 if (finishResponse) { |   | 1066 |   |                 try { | 
| 1054 |   |                     response.finishResponse(); |   | 1067 |   |                     response.finishResponse(); | 
|   |   |   |   | 1068 |   |                 } catch (IOException e) { | 
|   |   |   |   | 1069 |   |                     ok = false; | 
|   |   |   |   | 1070 |   |                 } catch (Throwable e) { | 
|   |   |   |   | 1071 |   |                     log("process.invoke", e); | 
|   |   |   |   | 1072 |   |                     ok = false; | 
|   |   |   |   | 1073 |   |                 } | 
|   |   |   |   | 1074 |   |                 try { | 
| 1055 |   |                     request.finishRequest(); |   | 1075 |   |                     request.finishRequest(); | 
|   |   |   |   | 1076 |   |                 } catch (IOException e) { | 
|   |   |   |   | 1077 |   |                     ok = false; | 
|   |   |   |   | 1078 |   |                 } catch (Throwable e) { | 
|   |   |   |   | 1079 |   |                     log("process.invoke", e); | 
|   |   |   |   | 1080 |   |                     ok = false; | 
|   |   |   |   | 1081 |   |                 } | 
|   |   |   |   | 1082 |   |                 try { | 
| 1056 |   |                     if (output != null) |   | 1083 |   |                     if (output != null) | 
| 1057 |   |                         output.flush(); |   | 1084 |   |                         output.flush(); | 
|   |   |   |   | 1085 |   |                 } catch (IOException e) { | 
|   |   |   |   | 1086 |   |                     ok = false; | 
| 1058 |   |                 } |   | 1087 |   |                 } | 
| 1059 |   |             } catch (IOException e) { |   |   |   |   | 
| 1060 |   |                 ok = false; |   |   |   |   | 
| 1061 |   |             } catch (Exception e) { |   |   |   |   | 
| 1062 |   |                 log("process.finish", e); |   |   |   |   | 
| 1063 |   |             } |   | 1088 |   |             } | 
| 1064 |   |  |   | 1089 |   |  | 
| 1065 |   |             // We have to check if the connection closure has been requested |   | 1090 |   |             // We have to check if the connection closure has been requested | 
| 1066 |   |             // by the application or the response stream (in case of HTTP/1.0 |   | 1091 |   |             // by the application or the response stream (in case of HTTP/1.0 | 
| 1067 |   |             // and keep-alive). |   | 1092 |   |             // and keep-alive). | 
| 1068 |   |             if ( "close".equals(response.getHeader("Connection")) ) { |   | 1093 |   |             if ( "close".equals(response.getHeader("Connection")) ) { | 
| 1069 |   |                 keepAlive = false; |   | 1094 |   |                 keepAlive = false; | 
| 1070 |   |             } |   | 1095 |   |             } | 
| 1071 |   |  |   | 1096 |   |  | 
| 1072 |   |             // End of request processing |   | 1097 |   |             // End of request processing | 
| 1073 |   |             status = Constants.PROCESSOR_IDLE; |   | 1098 |   |             status = Constants.PROCESSOR_IDLE; | 
| 1074 |   |  |   | 1099 |   |  | 
| 1075 |   |             // Recycling the request and the response objects |   | 1100 |   |             // Recycling the request and the response objects | 
| 1076 |   |             request.recycle(); |   | 1101 |   |             request.recycle(); | 
| 1077 |   |             response.recycle(); |   | 1102 |   |             response.recycle(); | 
| 1078 |   |  |   | 1103 |   |  | 
| 1079 |   |         } |   | 1104 |   |         } | 
| 1080 |   |  |   | 1105 |   |  | 
| 1081 |   |         try { |   | 1106 |   |         try { | 
| 1082 |   |             shutdownInput(input); |   | 1107 |   |             shutdownInput(input); | 
| 1083 |   |             socket.close(); |   | 1108 |   |             socket.close(); | 
| 1084 |   |         } catch (IOException e) { |   | 1109 |   |         } catch (IOException e) { | 
| 1085 |   |             ; |   | 1110 |   |             ; | 
|   |   |   |   | 1111 |   |         } catch (Throwable e) { | 
|   |   |   |   | 1112 |   |             log("process.invoke", e); | 
| 1086 |   |         } |   | 1113 |   |         } | 
| 1087 |   |         socket = null; |   | 1114 |   |         socket = null; | 
| 1088 |   |  |   | 1115 |   |  | 
| 1089 |   |     } |   | 1116 |   |     } | 
| 1090 |   |  |   | 1117 |   |  | 
| 1091 |   |  |   | 1118 |   |  | 
| 1092 |   |     protected void shutdownInput(InputStream input)    |   | 1119 |   |     protected void shutdownInput(InputStream input) { | 
| 1093 |   |         throws IOException { |   |   |   |   | 
| 1094 |   |         try { |   | 1120 |   |         try { | 
| 1095 |   |             int available = input.available(); |   | 1121 |   |             int available = input.available(); | 
| 1096 |   |             // skip any unread (bogus) bytes |   | 1122 |   |             // skip any unread (bogus) bytes | 
| 1097 |   |             if (available > 0) { |   | 1123 |   |             if (available > 0) { | 
| 1098 |   |                 input.skip(available); |   | 1124 |   |                 input.skip(available); | 
| 1099 |   |             } |   | 1125 |   |             } | 
| 1100 |   |         } catch (Exception e) { |   | 1126 |   |         } catch (Throwable e) { | 
| 1101 |   |             ; |   | 1127 |   |             ; | 
| 1102 |   |         } |   | 1128 |   |         } | 
| 1103 |   |     } |   | 1129 |   |     } | 
| 1104 |   |  |   | 1130 |   |  | 
| 1105 |   |  |   | 1131 |   |  | 
| 1106 |   |     // ---------------------------------------------- Background Thread Methods |   | 1132 |   |     // ---------------------------------------------- Background Thread Methods | 
| 1107 |   |  |   | 1133 |   |  | 
| 1108 |   |  |   | 1134 |   |  | 
| 1109 |   |     /** |   | 1135 |   |     /** | 
| 1110 |   |      * The background thread that listens for incoming TCP/IP connections and |   | 1136 |   |      * The background thread that listens for incoming TCP/IP connections and | 
| 1111 |   |      * hands them off to an appropriate processor. |   | 1137 |   |      * hands them off to an appropriate processor. | 
| 1112 |   |      */ |   | 1138 |   |      */ | 
| 1113 |   |     public void run() { |   | 1139 |   |     public void run() { | 
| 1114 |   |  |   | 1140 |   |  | 
| 1115 |   |         // Process requests until we receive a shutdown signal |   | 1141 |   |         // Process requests until we receive a shutdown signal | 
| 1116 |   |         while (!stopped) { |   | 1142 |   |         while (!stopped) { | 
| 1117 |   |  |   | 1143 |   |  | 
| 1118 |   |             // Wait for the next socket to be assigned |   | 1144 |   |             // Wait for the next socket to be assigned | 
| 1119 |   |             Socket socket = await(); |   | 1145 |   |             Socket socket = await(); | 
| 1120 |   |             if (socket == null) |   | 1146 |   |             if (socket == null) | 
| 1121 |   |                 continue; |   | 1147 |   |                 continue; | 
| 1122 |   |  |   | 1148 |   |  | 
| 1123 |   |             // Process the request from this socket |   | 1149 |   |             // Process the request from this socket | 
| 1124 |   |             try { |   | 1150 |   |             try { | 
| 1125 |   |                 process(socket); |   | 1151 |   |                 process(socket); | 
| 1126 |   |             } catch (Throwable t) { |   | 1152 |   |             } catch (Throwable t) { | 
| 1127 |   |                 log("process   ", t); |   | 1153 |   |                 log("process.invoke", t); | 
| 1128 |   |             } |   | 1154 |   |             } | 
| 1129 |   |  |   | 1155 |   |  | 
| 1130 |   |             // Finish up this request |   | 1156 |   |             // Finish up this request | 
| 1131 |   |             connector.recycle(this); |   | 1157 |   |             connector.recycle(this); | 
| 1132 |   |  |   | 1158 |   |  | 
| 1133 |   |         } |   | 1159 |   |         } | 
| 1134 |   |  |   | 1160 |   |  | 
| 1135 |   |         // Tell threadStop() we have shut ourselves down successfully |   | 1161 |   |         // Tell threadStop() we have shut ourselves down successfully | 
| 1136 |   |         synchronized (threadSync) { |   | 1162 |   |         synchronized (threadSync) { | 
| 1137 |   |             threadSync.notifyAll(); |   | 1163 |   |             threadSync.notifyAll(); | 
| 1138 |   |         } |   | 1164 |   |         } | 
| 1139 |   |  |   | 1165 |   |  | 
| 1140 |   |     } |   | 1166 |   |     } | 
| 1141 |   |  |   | 1167 |   |  | 
| 1142 |   |  |   | 1168 |   |  | 
| 1143 |   |     /** |   | 1169 |   |     /** | 
| 1144 |   |      * Start the background processing thread. |   | 1170 |   |      * Start the background processing thread. | 
| 1145 |   |      */ |   | 1171 |   |      */ | 
| 1146 |   |     private void threadStart() { |   | 1172 |   |     private void threadStart() { | 
| 1147 |   |  |   | 1173 |   |  | 
| 1148 |   |         log(sm.getString("httpProcessor.starting")); |   | 1174 |   |         log(sm.getString("httpProcessor.starting")); | 
| 1149 |   |  |   | 1175 |   |  | 
| 1150 |   |         thread = new Thread(this, threadName); |   | 1176 |   |         thread = new Thread(this, threadName); | 
| 1151 |   |         thread.setDaemon(true); |   | 1177 |   |         thread.setDaemon(true); | 
| 1152 |   |         thread.start(); |   | 1178 |   |         thread.start(); | 
| 1153 |   |  |   | 1179 |   |  | 
| 1154 |   |         if (debug >= 1) |   | 1180 |   |         if (debug >= 1) | 
| 1155 |   |             log(" Background thread has been started"); |   | 1181 |   |             log(" Background thread has been started"); | 
| 1156 |   |  |   | 1182 |   |  | 
| 1157 |   |     } |   | 1183 |   |     } | 
| 1158 |   |  |   | 1184 |   |  | 
| 1159 |   |  |   | 1185 |   |  | 
| 1160 |   |     /** |   | 1186 |   |     /** | 
| 1161 |   |      * Stop the background processing thread. |   | 1187 |   |      * Stop the background processing thread. | 
| 1162 |   |      */ |   | 1188 |   |      */ | 
| 1163 |   |     private void threadStop() { |   | 1189 |   |     private void threadStop() { | 
| 1164 |   |  |   | 1190 |   |  | 
| 1165 |   |         log(sm.getString("httpProcessor.stopping")); |   | 1191 |   |         log(sm.getString("httpProcessor.stopping")); | 
| 1166 |   |  |   | 1192 |   |  | 
| 1167 |   |         stopped = true; |   | 1193 |   |         stopped = true; | 
| 1168 |   |         assign(null); |   | 1194 |   |         assign(null); | 
| 1169 |   |  |   | 1195 |   |  | 
| 1170 |   |         if (status != Constants.PROCESSOR_IDLE) { |   | 1196 |   |         if (status != Constants.PROCESSOR_IDLE) { | 
| 1171 |   |             // Only wait if the processor is actually processing a command |   | 1197 |   |             // Only wait if the processor is actually processing a command | 
| 1172 |   |             synchronized (threadSync) { |   | 1198 |   |             synchronized (threadSync) { | 
| 1173 |   |                 try { |   | 1199 |   |                 try { | 
| 1174 |   |                     threadSync.wait(5000); |   | 1200 |   |                     threadSync.wait(5000); | 
| 1175 |   |                 } catch (InterruptedException e) { |   | 1201 |   |                 } catch (InterruptedException e) { | 
| 1176 |   |                     ; |   | 1202 |   |                     ; | 
| 1177 |   |                 } |   | 1203 |   |                 } | 
| 1178 |   |             } |   | 1204 |   |             } | 
| 1179 |   |         } |   | 1205 |   |         } | 
| 1180 |   |         thread = null; |   | 1206 |   |         thread = null; | 
| 1181 |   |  |   | 1207 |   |  | 
| 1182 |   |     } |   | 1208 |   |     } | 
| 1183 |   |  |   | 1209 |   |  | 
| 1184 |   |  |   | 1210 |   |  | 
| 1185 |   |     // ------------------------------------------------------ Lifecycle Methods |   | 1211 |   |     // ------------------------------------------------------ Lifecycle Methods | 
| 1186 |   |  |   | 1212 |   |  | 
| 1187 |   |  |   | 1213 |   |  | 
| 1188 |   |     /** |   | 1214 |   |     /** | 
| 1189 |   |      * Add a lifecycle event listener to this component. |   | 1215 |   |      * Add a lifecycle event listener to this component. | 
| 1190 |   |      * |   | 1216 |   |      * | 
| 1191 |   |      * @param listener The listener to add |   | 1217 |   |      * @param listener The listener to add | 
| 1192 |   |      */ |   | 1218 |   |      */ | 
| 1193 |   |     public void addLifecycleListener(LifecycleListener listener) { |   | 1219 |   |     public void addLifecycleListener(LifecycleListener listener) { | 
| 1194 |   |  |   | 1220 |   |  | 
| 1195 |   |         lifecycle.addLifecycleListener(listener); |   | 1221 |   |         lifecycle.addLifecycleListener(listener); | 
| 1196 |   |  |   | 1222 |   |  | 
| 1197 |   |     } |   | 1223 |   |     } | 
| 1198 |   |  |   | 1224 |   |  | 
| 1199 |   |  |   | 1225 |   |  | 
| 1200 |   |     /** |   | 1226 |   |     /** | 
|   |   |   |   | 1227 |   |      * Get the lifecycle listeners associated with this lifecycle. If this  | 
|   |   |   |   | 1228 |   |      * Lifecycle has no listeners registered, a zero-length array is returned. | 
|   |   |   |   | 1229 |   |      */ | 
|   |   |   |   | 1230 |   |     public LifecycleListener[] findLifecycleListeners() { | 
|   |   |   |   | 1231 |   |  | 
|   |   |   |   | 1232 |   |         return lifecycle.findLifecycleListeners(); | 
|   |   |   |   | 1233 |   |  | 
|   |   |   |   | 1234 |   |     } | 
|   |   |   |   | 1235 |   |  | 
|   |   |   |   | 1236 |   |  | 
|   |   |   |   | 1237 |   |     /** | 
| 1201 |   |      * Remove a lifecycle event listener from this component. |   | 1238 |   |      * Remove a lifecycle event listener from this component. | 
| 1202 |   |      * |   | 1239 |   |      * | 
| 1203 |   |      * @param listener The listener to add |   | 1240 |   |      * @param listener The listener to add | 
| 1204 |   |      */ |   | 1241 |   |      */ | 
| 1205 |   |     public void removeLifecycleListener(LifecycleListener listener) { |   | 1242 |   |     public void removeLifecycleListener(LifecycleListener listener) { | 
| 1206 |   |  |   | 1243 |   |  | 
| 1207 |   |         lifecycle.removeLifecycleListener(listener); |   | 1244 |   |         lifecycle.removeLifecycleListener(listener); | 
| 1208 |   |  |   | 1245 |   |  | 
| 1209 |   |     } |   | 1246 |   |     } | 
| 1210 |   |  |   | 1247 |   |  | 
| 1211 |   |  |   | 1248 |   |  | 
| 1212 |   |     /** |   | 1249 |   |     /** | 
| 1213 |   |      * Start the background thread we will use for request processing. |   | 1250 |   |      * Start the background thread we will use for request processing. | 
| 1214 |   |      * |   | 1251 |   |      * | 
| 1215 |   |      * @exception LifecycleException if a fatal startup error occurs |   | 1252 |   |      * @exception LifecycleException if a fatal startup error occurs | 
| 1216 |   |      */ |   | 1253 |   |      */ | 
| 1217 |   |     public void start() throws LifecycleException { |   | 1254 |   |     public void start() throws LifecycleException { | 
| 1218 |   |  |   | 1255 |   |  | 
| 1219 |   |         if (started) |   | 1256 |   |         if (started) | 
| 1220 |   |             throw new LifecycleException |   | 1257 |   |             throw new LifecycleException | 
| 1221 |   |                 (sm.getString("httpProcessor.alreadyStarted")); |   | 1258 |   |                 (sm.getString("httpProcessor.alreadyStarted")); | 
| 1222 |   |         lifecycle.fireLifecycleEvent(START_EVENT, null); |   | 1259 |   |         lifecycle.fireLifecycleEvent(START_EVENT, null); | 
| 1223 |   |         started = true; |   | 1260 |   |         started = true; | 
| 1224 |   |  |   | 1261 |   |  | 
| 1225 |   |         threadStart(); |   | 1262 |   |         threadStart(); | 
| 1226 |   |  |   | 1263 |   |  | 
| 1227 |   |     } |   | 1264 |   |     } | 
| 1228 |   |  |   | 1265 |   |  | 
| 1229 |   |  |   | 1266 |   |  | 
| 1230 |   |     /** |   | 1267 |   |     /** | 
| 1231 |   |      * Stop the background thread we will use for request processing. |   | 1268 |   |      * Stop the background thread we will use for request processing. | 
| 1232 |   |      * |   | 1269 |   |      * | 
| 1233 |   |      * @exception LifecycleException if a fatal shutdown error occurs |   | 1270 |   |      * @exception LifecycleException if a fatal shutdown error occurs | 
| 1234 |   |      */ |   | 1271 |   |      */ | 
| 1235 |   |     public void stop() throws LifecycleException { |   | 1272 |   |     public void stop() throws LifecycleException { | 
| 1236 |   |  |   | 1273 |   |  | 
| 1237 |   |         if (!started) |   | 1274 |   |         if (!started) | 
| 1238 |   |             throw new LifecycleException |   | 1275 |   |             throw new LifecycleException | 
| 1239 |   |                 (sm.getString("httpProcessor.notStarted")); |   | 1276 |   |                 (sm.getString("httpProcessor.notStarted")); | 
| 1240 |   |         lifecycle.fireLifecycleEvent(STOP_EVENT, null); |   | 1277 |   |         lifecycle.fireLifecycleEvent(STOP_EVENT, null); | 
| 1241 |   |         started = false; |   | 1278 |   |         started = false; | 
| 1242 |   |  |   | 1279 |   |  | 
| 1243 |   |         threadStop(); |   | 1280 |   |         threadStop(); | 
| 1244 |   |  |   | 1281 |   |  | 
| 1245 |   |     } |   | 1282 |   |     } | 
| 1246 |   |  |   | 1283 |   |  | 
| 1247 |   |  |   | 1284 |   |  | 
| 1248 |   | } |   | 1285 |   | } |