5. Araxis Merge File Comparison Report

Produced by Araxis Merge on 2016-08-05 08:06:57 +0000. See www.araxis.com for information about Merge. This report uses XHTML and CSS2, and is best viewed with a modern standards-compliant browser. For optimum results when printing this report, use landscape orientation and enable printing of background images and colours in your browser.

5.1 Files compared

#LocationFileLast Modified
1/Merge Test Files/jakarta-tomcat-4.0.6-src/catalina/src/share/org/apache/catalina/connector/httpHttpProcessor.java2002-10-08 14:15:34 +0000
2/Merge Test Files/jakarta-tomcat-4.1.18-src/catalina/src/share/org/apache/catalina/connector/httpHttpProcessor.java2002-12-19 13:49:42 +0000

5.2 Comparison summary

DescriptionBetween
Files 1 and 2
Text BlocksLines
Unchanged172460
Changed928
Inserted741
Removed14

5.3 Comparison options

WhitespaceDifferences in whitespace are significant
Character caseDifferences in character case are significant
Line endingsDifferences in line endings (CR and LF characters) are significant
CR/LF charactersNot shown in the comparison detail

5.4 Active regular expressions

No regular expressions were active.

5.5 Comparison detail

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 }