KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > web > connector > grizzly > ProcessorTask


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 /*
25  * Copyright 1999-2004 The Apache Software Foundation
26  *
27  * Licensed under the Apache License, Version 2.0 (the "License");
28  * you may not use this file except in compliance with the License.
29  * You may obtain a copy of the License at
30  *
31  * http://www.apache.org/licenses/LICENSE-2.0
32  *
33  * Unless required by applicable law or agreed to in writing, software
34  * distributed under the License is distributed on an "AS IS" BASIS,
35  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
36  * See the License for the specific language governing permissions and
37  * limitations under the License.
38  */

39 package com.sun.enterprise.web.connector.grizzly;
40
41 import com.sun.enterprise.web.connector.grizzly.async.DefaultAsyncHandler;
42 import com.sun.enterprise.web.connector.grizzly.async.DefaultAsyncExecutor;
43 import java.io.EOFException JavaDoc;
44 import java.io.IOException JavaDoc;
45 import java.io.InputStream JavaDoc;
46 import java.io.InterruptedIOException JavaDoc;
47 import java.io.OutputStream JavaDoc;
48
49 import java.net.InetAddress JavaDoc;
50 import java.net.Socket JavaDoc;
51 import java.nio.ByteBuffer JavaDoc;
52 import java.nio.channels.SocketChannel JavaDoc;
53 import java.util.logging.Logger JavaDoc;
54 import java.util.logging.Level JavaDoc;
55
56 import org.apache.catalina.util.ServerInfo;
57
58 import org.apache.coyote.ActionCode;
59 import org.apache.coyote.ActionHook;
60 import org.apache.coyote.Adapter;
61 import org.apache.coyote.Processor;
62 import org.apache.coyote.Request;
63 import org.apache.coyote.RequestInfo;
64 import org.apache.coyote.Response;
65 import org.apache.coyote.http11.InternalInputBuffer;
66 import org.apache.coyote.http11.InternalOutputBuffer;
67 import org.apache.coyote.http11.InputFilter;
68 import org.apache.coyote.http11.OutputFilter;
69 import org.apache.coyote.http11.filters.ChunkedInputFilter;
70 import org.apache.coyote.http11.filters.ChunkedOutputFilter;
71 import org.apache.coyote.http11.filters.GzipOutputFilter;
72 import org.apache.coyote.http11.filters.IdentityInputFilter;
73 import org.apache.coyote.http11.filters.IdentityOutputFilter;
74 import org.apache.coyote.http11.filters.VoidInputFilter;
75 import org.apache.coyote.http11.filters.VoidOutputFilter;
76 import org.apache.coyote.http11.filters.BufferedInputFilter;
77 import org.apache.coyote.tomcat5.CoyoteAdapter;
78 import org.apache.coyote.tomcat5.CoyoteRequest;
79
80 import org.apache.tomcat.util.buf.Ascii;
81 import org.apache.tomcat.util.buf.ByteChunk;
82 import org.apache.tomcat.util.buf.HexUtils;
83 import org.apache.tomcat.util.buf.MessageBytes;
84 import org.apache.tomcat.util.http.FastHttpDateFormat;
85 import org.apache.tomcat.util.http.MimeHeaders;
86 import org.apache.tomcat.util.net.SSLImplementation;
87 import org.apache.tomcat.util.net.SSLSupport;
88 import com.sun.enterprise.web.connector.grizzly.handlers.NoParsingHandler;
89
90 import com.sun.org.apache.commons.modeler.Registry;
91
92 import javax.management.ObjectName JavaDoc;
93
94 import java.nio.channels.Selector JavaDoc;
95
96 /**
97  * Process HTTP request. This class is based on
98  * <code>org.apache.coyote.http11.Http11Processor</code>
99  *
100  * @author Jean-Francois Arcand
101  */

102 public class ProcessorTask extends TaskBase implements Processor, ActionHook {
103
104     /**
105      * Associated adapter.
106      */

107     protected Adapter adapter = null;
108
109
110     /**
111      * Request object.
112      */

113     protected Request request = null;
114
115
116     /**
117      * Response object.
118      */

119     protected Response response = null;
120
121
122     /**
123      * Input.
124      */

125     protected InternalInputBuffer inputBuffer = null;
126
127
128     /**
129      * Output.
130      */

131     protected InternalOutputBuffer outputBuffer = null;
132
133
134     /**
135      * State flag.
136      */

137     protected boolean started = false;
138
139
140     /**
141      * Error flag.
142      */

143     protected boolean error = false;
144
145
146     /**
147      * Keep-alive.
148      */

149     protected boolean keepAlive = true;
150     
151     
152     /**
153      * Connection: value
154      */

155     protected boolean connectionHeaderValue = true;
156
157     /**
158      * HTTP/1.1 flag.
159      */

160     protected boolean http11 = true;
161
162
163     /**
164      * HTTP/0.9 flag.
165      */

166     protected boolean http09 = false;
167
168
169     /**
170      * Content delimitator for the request (if false, the connection will
171      * be closed at the end of the request).
172      */

173     protected boolean contentDelimitation = true;
174
175
176     /**
177      * SSL information.
178      */

179     protected SSLSupport sslSupport;
180
181
182     /**
183      * Socket associated with the current connection.
184      */

185     protected Socket JavaDoc socket;
186
187
188     /**
189      * Remote Address associated with the current connection.
190      */

191     protected String JavaDoc remoteAddr = null;
192
193
194     /**
195      * Remote Host associated with the current connection.
196      */

197     protected String JavaDoc remoteHost = null;
198     
199     
200     /**
201      * Local Host associated with the current connection.
202      */

203     protected String JavaDoc localName = null;
204         
205     
206     /**
207      * Local port to which the socket is connected
208      */

209     protected int localPort = -1;
210     
211     
212     /**
213      * Remote port to which the socket is connected
214      */

215     protected int remotePort = -1;
216     
217     
218     /**
219      * The local Host address.
220      */

221     protected String JavaDoc localAddr = null;
222
223
224     /**
225      * Maximum timeout on uploads. 5 minutes as in Apache HTTPD server.
226      */

227     protected int timeout = 300000;
228
229
230     /**
231      * Max post size.
232      */

233     protected int maxPostSize = 2 * 1024 * 1024;
234
235
236     /**
237      * Host name (used to avoid useless B2C conversion on the host name).
238      */

239     protected char[] hostNameC = new char[0];
240
241
242     /**
243      * The <code>taskContext</code> associated with this object. The
244      * <code>taskContext</code> contains information about the current
245      * connection.
246      */

247     protected TaskContext taskContext;
248     
249     
250     /**
251      * The <code>TaskEvent</code> associated with this task.
252      */

253     protected TaskEvent<TaskContext> taskEvent;
254
255     
256     /**
257      * The underlying SSL implementation used.
258      */

259     protected SSLImplementation sslImplementation = null;
260     
261     
262     /**
263      * Are we using NIO non blocking mode?
264      */

265     protected boolean usingNioNonBlocking = true;
266     
267     
268     /**
269      * Has the request associated with this <code>ProcessorTask</code> been
270      * registered with the <code>RequestGroupInfo</code>
271      */

272     private boolean hasRequestInfoRegistered = false;
273     
274     
275     /**
276      * Default HTTP header buffer size.
277      */

278     protected int maxHttpHeaderSize = Constants.DEFAULT_HEADER_SIZE;
279
280     
281     /**
282      * The number of requests <code>ProcessorTask</code> has proceeded.
283      */

284     protected static int requestCount;
285
286     
287     /**
288      * The input request buffer size.
289      */

290     private int requestBufferSize = Constants.DEFAULT_REQUEST_BUFFER_SIZE;
291
292
293     /**
294      * ObjectName under which this <code>ProcessorTask</code> will be
295      * JMX-registered if monitoring has been turned on
296      */

297     private ObjectName JavaDoc oname;
298
299     
300     /**
301      * Disable all keep-Alive functionality. Usualy used with NIO Mode 3
302      */

303     protected boolean useAlternateKeepAlive = false;
304     
305     
306     /**
307      * Allow client of this class to force connection closing.
308      */

309     protected boolean dropConnection = false;
310     
311     
312     /**
313      * Maximum number of Keep-Alive requests to honor. This value is used
314      * only when NIO blocking mode is enabled.
315      */

316     protected int maxKeepAliveRequests = Constants.DEFAULT_MAX_KEEP_ALIVE;
317     
318     
319     /**
320      * The current keep-alive count left before closing the connection.
321      */

322     protected int keepAliveLeft;
323   
324      
325     /**
326      * The handler used by this <code>Task</code> to manipulate the request.
327      */

328     protected Handler handler;
329     
330     
331     /**
332      * The default response-type
333      */

334     private String JavaDoc defaultResponseType =
335             org.apache.coyote.tomcat5.Constants.DEFAULT_RESPONSE_TYPE;
336      
337     
338     /**
339      * The forced response-type
340      */

341     private String JavaDoc forcedResponseType =
342             org.apache.coyote.tomcat5.Constants.FORCED_RESPONSE_TYPE;
343     
344     
345     /**
346      * Is asynchronous mode enabled?
347      */

348     private boolean asyncExecution = false;
349     
350     
351     /**
352      * The code>RequestInfo</code> used to gather stats.
353      */

354     private RequestInfo requestInfo;
355     
356     
357     /**
358      * The <code>OutputBuffer</code> used when NIO non-blocking is enabled.
359      */

360     private SocketChannelOutputBuffer channelOutputBuffer;
361     
362     
363     /**
364      * When the asynchronous mode is enabled, the execution of this object
365      * will be delegated to the <code>AsyncHandler</code>
366      */

367     private AsyncHandler asyncHandler;
368     
369     
370     /**
371      * Is SSL enabled.
372      */

373     private boolean sslEnabled = sslImplementation == null ? false: true;
374     
375         
376     // ----------------------------------------------------- Constructor ---- //
377

378     public ProcessorTask(){
379         this(true, true);
380     }
381         
382     public ProcessorTask(boolean useNio, boolean init){
383         
384         usingNioNonBlocking = useNio;
385         type = PROCESSOR_TASK;
386         if (init) {
387             initialize();
388         }
389     }
390
391     
392     /**
393      * Initialize the stream and the buffer used to parse the request.
394      */

395     protected void initialize(){
396         started = true;
397         request = new Request();
398
399         response = new Response();
400         response.setHook(this);
401         
402         inputBuffer = new InternalInputBuffer(request,requestBufferSize);
403  
404         if ( usingNioNonBlocking ){
405             outputBuffer = new SocketChannelOutputBuffer(response,
406                                                          maxHttpHeaderSize);
407         } else {
408             outputBuffer = new InternalOutputBuffer(response,
409                                                     maxHttpHeaderSize);
410         }
411         request.setInputBuffer(inputBuffer);
412        
413         response.setOutputBuffer(outputBuffer);
414         request.setResponse(response);
415
416         initializeFilters();
417
418     }
419
420
421     // ----------------------------------------------------- Thread run ---- //
422

423     
424      /**
425      * Execute the HTTP request by parsing the header/body,
426      * and then by delegating the process to the Catalina container.
427      */

428     public void doTask() throws IOException JavaDoc{
429         boolean sslEnabled = sslImplementation == null ? false: true;
430         usingNioNonBlocking = usingNioNonBlocking && !sslEnabled;
431         try {
432             if ( usingNioNonBlocking ) {
433                 process(taskContext.getInputStream(),
434                         taskContext.getOutputStream());
435             } else {
436                 process(socket.getInputStream(),socket.getOutputStream());
437             }
438         } catch(Throwable JavaDoc ex){
439             SelectorThread.logger().log(Level.FINE,
440                     "processorTask.errorProcessingRequest", ex);
441         } finally {
442             terminateProcess();
443         }
444     }
445
446  
447      // --------------------------------------------------------- TaskEvent ---//
448

449      
450     public void taskEvent(TaskEvent event){
451         if ( event.getStatus() == TaskEvent.START) {
452             taskContext = (TaskContext)event.attachement();
453             if ( taskEvent == null ) {
454                 taskEvent = new TaskEvent<TaskContext>();
455             }
456             
457             taskEvent.attach(taskContext);
458
459             if ( !asyncExecution ) {
460                 execute();
461             } else {
462                 asyncHandler.handle(this);
463             }
464         }
465     }
466
467     // -------------------------------------------------------------------- //
468

469     
470     /**
471      * Pre process the request by decoding the request line and the header.
472      */

473     public void preProcess() throws Exception JavaDoc {
474         if ( usingNioNonBlocking && !sslEnabled ) {
475             preProcess(taskContext.getInputStream(),
476                        taskContext.getOutputStream());
477         } else {
478             preProcess(socket.getInputStream(),
479                        socket.getOutputStream());
480         }
481     }
482     
483     
484     /**
485      * Pre process the request by decoding the request line and the header.
486      * @param input the InputStream to read bytes
487      * @param output the OutputStream to write bytes
488      */

489     public void preProcess(InputStream JavaDoc input, OutputStream JavaDoc output)
490                                                             throws Exception JavaDoc {
491         
492         // Make sure this object has been initialized.
493
if ( !started ){
494             initialize();
495         }
496         
497         if (isMonitoringEnabled()){
498             adapter.
499                 fireAdapterEvent(Adapter.CONNECTION_PROCESSING_STARTED,
500                     request.getRequestProcessor());
501         }
502
503       
504         if (sslImplementation != null) {
505             sslSupport = sslImplementation.getSSLSupport(socket);
506         }
507                               
508         if( selectorThread.getDomain() != null
509                 && isMonitoringEnabled()
510                 && !hasRequestInfoRegistered ) {
511             registerMonitoring();
512         } else if (!isMonitoringEnabled() && hasRequestInfoRegistered) {
513             unregisterMonitoring();
514         }
515         
516         if (isMonitoringEnabled()) {
517             requestInfo = request.getRequestProcessor();
518             requestInfo.setWorkerThreadID(Thread.currentThread().getId());
519         }
520
521         // Setting up the I/O
522
inputBuffer.setInputStream(input);
523         if ( usingNioNonBlocking ) {
524             channelOutputBuffer = ((SocketChannelOutputBuffer)outputBuffer);
525             channelOutputBuffer.setChannel((SocketChannel JavaDoc)key.channel());
526         } else {
527             outputBuffer.setOutputStream(output);
528         }
529         
530         // Set the remote address
531
remoteAddr = null;
532         remoteHost = null;
533         localName = null;
534         localAddr = null;
535         remotePort = -1;
536         localPort = -1;
537         connectionHeaderValue = true;
538         
539         // Error flag
540
error = false;
541         keepAlive = true;
542
543         keepAliveLeft = maxKeepAliveRequests;
544         int soTimeout = socket.getSoTimeout();
545         if (request.getServerPort() == 0) {
546             request.setServerPort(selectorThread.getPort());
547         }
548     }
549
550     
551     /**
552      * Process an HTTP request using a non blocking <code>socket</code>
553      */

554     public boolean processNonBlocked() throws Exception JavaDoc {
555         if ( usingNioNonBlocking && !sslEnabled ) {
556             return processNonBlocked(taskContext.getInputStream(),
557                                      taskContext.getOutputStream());
558         } else {
559             return processNonBlocked(socket.getInputStream(),
560                                      socket.getOutputStream());
561         }
562     }
563     
564     
565     /**
566      * Process an HTTP request using a non blocking <code>socket</code>
567      * @param input the InputStream to read bytes
568      * @param output the OutputStream to write bytes
569      */

570     public boolean processNonBlocked(InputStream JavaDoc input, OutputStream JavaDoc output)
571                                                             throws Exception JavaDoc{
572         boolean exitWhile = parseRequest(input,output,false);
573         if ( exitWhile ) return exitWhile;
574         invokeAdapter();
575         postResponse();
576         return error;
577     }
578     
579     
580     /**
581      * Process an HTTP request using a blocking <code>socket</code>
582      */

583     public void processBlocked() throws Exception JavaDoc {
584         if ( usingNioNonBlocking && !sslEnabled ) {
585             processBlocked(taskContext.getInputStream(),
586                               taskContext.getOutputStream());
587         } else {
588             processBlocked(socket.getInputStream(),
589                               socket.getOutputStream());
590         }
591     }
592     
593     
594     /**
595      * Process an HTTP request using a blocking <code>socket</code>
596      * @param input the InputStream to read bytes
597      * @param output the OutputStream to write bytes
598      */

599     public void processBlocked(InputStream JavaDoc input, OutputStream JavaDoc output)
600                                                             throws Exception JavaDoc {
601         boolean keptAlive = false;
602         while (started && !error && keepAlive) {
603
604             boolean exitWhile = parseRequest(input,output,keptAlive);
605             if ( exitWhile ) break;
606                         
607             invokeAdapter();
608             postResponse();
609         }
610     }
611
612     
613     /**
614      * Prepare and post the response.
615      * @param input the InputStream to read bytes
616      * @param output the OutputStream to write bytes
617      */

618     public void postResponse() throws Exception JavaDoc{
619         // Finish the handling of the request
620
try {
621              inputBuffer.endRequest();
622         } catch (IOException JavaDoc e) {
623             error = true;
624         } catch (Throwable JavaDoc t) {
625             SelectorThread.logger().log(Level.SEVERE,
626                     "processorTask.errorFinishingRequest", t);
627             // 500 - Internal Server Error
628
response.setStatus(500);
629             error = true;
630         }
631         try {
632             outputBuffer.endRequest();
633         } catch (IOException JavaDoc e) {
634             error = true;
635         } catch (Throwable JavaDoc t) {
636             SelectorThread.logger().log(Level.SEVERE,
637                     "processorTask.errorFinishingResponse", t);
638             error = true;
639         }
640
641         // If there was an error, make sure the request is counted as
642
// and error, and update the statistics counter
643
if (error) {
644             response.setStatus(500);
645         }
646
647         if (isMonitoringEnabled()) {
648             request.updateCounters();
649             adapter.fireAdapterEvent(Adapter.REQUEST_PROCESSING_COMPLETED,
650                     request.getRequestProcessor());
651         }
652
653         // Next request
654
inputBuffer.nextRequest();
655         outputBuffer.nextRequest();
656     }
657     
658     
659     /**
660      * Invoke the <code>Adapter</code>, which usualy invoke the Servlet
661      * Container.
662      */

663     public void invokeAdapter(){
664         // Process the request in the adapter
665
if (!error) {
666             try {
667                 adapter.service(request, response);
668                 // Handle when the response was committed before a serious
669
// error occurred. Throwing a ServletException should both
670
// set the status to 500 and set the errorException.
671
// If we fail here, then the response is likely already
672
// committed, so we can't try and set headers.
673
if(keepAlive && !error) { // Avoid checking twice.
674
error = response.getErrorException() != null ||
675                             statusDropsConnection(response.getStatus());
676                 }
677
678             } catch (InterruptedIOException JavaDoc e) {
679                 error = true;
680             } catch (Throwable JavaDoc t) {
681                 SelectorThread.logger().log(Level.SEVERE,
682                         "processorTask.serviceError", t);
683                 // 500 - Internal Server Error
684
response.setStatus(500);
685                 error = true;
686             }
687         }
688     }
689     
690     
691     /**
692      * Parse the request line and the http header.
693      */

694     public void parseRequest() throws Exception JavaDoc {
695         if ( usingNioNonBlocking && !sslEnabled ) {
696             parseRequest(taskContext.getInputStream(),
697                          taskContext.getOutputStream(), true);
698         } else {
699             parseRequest(socket.getInputStream(),socket.getOutputStream(),true);
700         }
701     }
702     
703     
704     /**
705      * Parse the request line and the http header.
706      * @param input the InputStream to read bytes
707      * @param output the OutputStream to write bytes
708      */

709     public boolean parseRequest(InputStream JavaDoc input, OutputStream JavaDoc output,
710             boolean keptAlive) throws Exception JavaDoc {
711         
712         // Parsing the request header
713
try {
714             if (isMonitoringEnabled()){
715                 adapter.fireAdapterEvent(Adapter.REQUEST_PROCESSING_STARTED,
716                         request.getRequestProcessor());
717             }
718
719             inputBuffer.parseRequestLine();
720             if (isMonitoringEnabled()) {
721                 request.getRequestProcessor().setRequestCompletionTime(0);
722             }
723
724             request.setStartTime(System.currentTimeMillis());
725             if ( handler.handle(request,Handler.REQUEST_LINE_PARSED)
726                     == Handler.BREAK){
727                 return true;
728             }
729
730             keptAlive = true;
731             inputBuffer.parseHeaders();
732         } catch (IOException JavaDoc e) {
733             SelectorThread.logger().log(Level.FINEST,
734                     "processorTask.nonBlockingError", e);
735             error = true;
736             keepAlive = false;
737             return true;
738         } catch (Throwable JavaDoc t) {
739             SelectorThread.logger().log(Level.SEVERE,
740                     "processorTask.nonBlockingError", t);
741             // 400 - Bad Request
742
response.setStatus(400);
743             error = true;
744         }
745
746         // Setting up filters, and parse some request headers
747
try {
748             prepareRequest();
749         } catch (Throwable JavaDoc t) {
750             SelectorThread.logger().log(Level.FINE,
751                     "processorTask.createRequestError", t);
752             // 400 - Internal Server Error
753
response.setStatus(400);
754             error = true;
755         }
756
757         if (!usingNioNonBlocking){
758             if (maxKeepAliveRequests > 0 && --keepAliveLeft == 0)
759                 keepAlive = false;
760         }
761         return false;
762     }
763     
764     
765     /**
766      * Post process the http request, after the response has been
767      * commited.
768      */

769     public void postProcess() throws Exception JavaDoc {
770         if ( usingNioNonBlocking && !sslEnabled ) {
771             postProcess(taskContext.getInputStream(),
772                         taskContext.getOutputStream());
773         } else {
774             postProcess(socket.getInputStream(),socket.getOutputStream());
775         }
776     }
777     
778     
779     /**
780      * Post process the http request, after the response has been
781      * commited.
782      */

783     public void postProcess(InputStream JavaDoc input, OutputStream JavaDoc output)
784                                                             throws Exception JavaDoc {
785         if (!recycle){
786             started = false;
787             inputBuffer = null;
788             outputBuffer = null;
789             response = null;
790             if (isMonitoringEnabled()) {
791                 request.getRequestProcessor().setWorkerThreadID(0);
792                 adapter.fireAdapterEvent(Adapter.CONNECTION_PROCESSING_COMPLETED,
793                         request.getRequestProcessor());
794             }
795             request = null;
796         } else {
797             inputBuffer.recycle();
798             outputBuffer.recycle();
799         }
800
801         // Recycle ssl info
802
sslSupport = null;
803
804         if (error){
805             keepAlive = false;
806             connectionHeaderValue = false;
807         }
808     }
809     
810
811     /**
812      * Notify the <code>TaskListener</code> that the request has been
813      * fully processed.
814      */

815     public void terminateProcess(){
816         if ( error && usingNioNonBlocking) {
817             taskEvent.setStatus(TaskEvent.ERROR);
818         } else {
819             taskEvent.setStatus(TaskEvent.COMPLETED);
820         }
821         fireTaskEvent(taskEvent);
822     }
823     
824     
825     // -------------------------------------------------------------------- //
826

827     
828     /**
829      * Process pipelined HTTP requests using the specified input and output
830      * streams.
831      *
832      * @param input stream from which the HTTP requests will be read
833      * @param output stream which will be used to output the HTTP
834      * responses
835      * @return true is an error occured.
836      * @throws Exception error during an I/O operation
837      */

838     public boolean process(InputStream JavaDoc input, OutputStream JavaDoc output)
839             throws Exception JavaDoc {
840         preProcess(input,output);
841         if ( !usingNioNonBlocking ) {
842             processBlocked(input,output);
843         } else {
844             processNonBlocked(input,output);
845         }
846         postProcess(input,output);
847         return keepAlive;
848     }
849     
850     
851     /**
852      * Get the request associated with this processor.
853      */

854     public Request getRequest() {
855         return request;
856     }
857     
858
859     // ----------------------------------------------------- ActionHook Methods
860

861
862     /**
863      * Send an action to the connector.
864      *
865      * @param actionCode Type of the action
866      * @param param Action parameter
867      */

868     public void action(ActionCode actionCode, Object JavaDoc param) {
869
870         if (actionCode == ActionCode.ACTION_COMMIT) {
871             // Commit current response
872

873             if (response.isCommitted())
874                 return;
875                         
876             // Validate and write response headers
877
prepareResponse();
878             try {
879                 outputBuffer.commit();
880             } catch (IOException JavaDoc ex) {
881                  SelectorThread.logger().log(Level.FINEST,
882                         "processorTask.nonBlockingError", ex);
883                 // Set error flag
884
error = true;
885             }
886
887         } else if (actionCode == ActionCode.ACTION_ACK) {
888
889             // Acknowlege request
890

891             // Send a 100 status back if it makes sense (response not committed
892
// yet, and client specified an expectation for 100-continue)
893

894             if ((response.isCommitted()) || (!http11))
895                 return;
896
897             MessageBytes expectMB = request.getMimeHeaders().getValue("expect");
898             if ((expectMB != null)
899                 && (expectMB.indexOfIgnoreCase("100-continue", 0) != -1)) {
900                 try {
901                     outputBuffer.sendAck();
902                 } catch (IOException JavaDoc e) {
903                     // Set error flag
904
error = true;
905                 }
906             }
907
908         } else if (actionCode == ActionCode.ACTION_CLOSE) {
909             // Close
910

911             // End the processing of the current request, and stop any further
912
// transactions with the client
913

914             try {
915                 outputBuffer.endRequest();
916             } catch (IOException JavaDoc e) {
917                 SelectorThread.logger().log(Level.FINEST,
918                         "processorTask.nonBlockingError", e);
919                 // Set error flag
920
error = true;
921             }
922
923         } else if (actionCode == ActionCode.ACTION_RESET) {
924
925             // Reset response
926

927             // Note: This must be called before the response is committed
928

929             outputBuffer.reset();
930
931         } else if (actionCode == ActionCode.ACTION_CUSTOM) {
932
933             // Do nothing
934

935         } else if (actionCode == ActionCode.ACTION_START) {
936
937             started = true;
938
939         } else if (actionCode == ActionCode.ACTION_STOP) {
940
941             started = false;
942
943         } else if (actionCode == ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) {
944
945             try {
946                 if (sslSupport != null) {
947                     Object JavaDoc sslO = sslSupport.getCipherSuite();
948                     if (sslO != null)
949                         request.setAttribute
950                             (SSLSupport.CIPHER_SUITE_KEY, sslO);
951                     sslO = sslSupport.getPeerCertificateChain(false);
952                     if (sslO != null)
953                         request.setAttribute
954                             (SSLSupport.CERTIFICATE_KEY, sslO);
955                     sslO = sslSupport.getKeySize();
956                     if (sslO != null)
957                         request.setAttribute
958                             (SSLSupport.KEY_SIZE_KEY, sslO);
959                     sslO = sslSupport.getSessionId();
960                     if (sslO != null)
961                         request.setAttribute
962                             (SSLSupport.SESSION_ID_KEY, sslO);
963                 }
964             } catch (Exception JavaDoc e) {
965                 SelectorThread.logger().log(Level.WARNING,
966                         "processorTask.errorSSL" ,e);
967             }
968
969         } else if (actionCode == ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE) {
970
971             if ((remoteAddr == null) && (socket != null)) {
972                 InetAddress JavaDoc inetAddr = socket.getInetAddress();
973                 if (inetAddr != null) {
974                     remoteAddr = inetAddr.getHostAddress();
975                 }
976             }
977             request.remoteAddr().setString(remoteAddr);
978
979         } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_NAME_ATTRIBUTE) {
980             
981             if ((localName == null) && (socket != null)) {
982                 InetAddress JavaDoc inetAddr = socket.getLocalAddress();
983                 if (inetAddr != null) {
984                     localName = inetAddr.getHostName();
985                 }
986             }
987             request.localName().setString(localName);
988
989         } else if (actionCode == ActionCode.ACTION_REQ_HOST_ATTRIBUTE) {
990             
991             if ((remoteHost == null) && (socket != null)) {
992                 InetAddress JavaDoc inetAddr = socket.getInetAddress();
993                 if (inetAddr != null) {
994                     remoteHost = inetAddr.getHostName();
995                 }
996                 
997                 if(remoteHost == null) {
998                     if(remoteAddr != null) {
999                         remoteHost = remoteAddr;
1000                    } else { // all we can do is punt
1001
request.remoteHost().recycle();
1002                    }
1003                }
1004            }
1005            request.remoteHost().setString(remoteHost);
1006            
1007        } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE) {
1008                       
1009            if (localAddr == null)
1010               localAddr = socket.getLocalAddress().getHostAddress();
1011
1012            request.localAddr().setString(localAddr);
1013            
1014        } else if (actionCode == ActionCode.ACTION_REQ_REMOTEPORT_ATTRIBUTE) {
1015            
1016            if ((remotePort == -1 ) && (socket !=null)) {
1017                remotePort = socket.getPort();
1018            }
1019            request.setRemotePort(remotePort);
1020
1021        } else if (actionCode == ActionCode.ACTION_REQ_LOCALPORT_ATTRIBUTE) {
1022            
1023            if ((localPort == -1 ) && (socket !=null)) {
1024                localPort = socket.getLocalPort();
1025            }
1026            request.setLocalPort(localPort);
1027       
1028        } else if (actionCode == ActionCode.ACTION_REQ_SSL_CERTIFICATE) {
1029            if( sslSupport != null) {
1030                /*
1031                 * Consume and buffer the request body, so that it does not
1032                 * interfere with the client's handshake messages
1033                 */

1034                InputFilter[] inputFilters = inputBuffer.getFilters();
1035                ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER])
1036                    .setLimit(maxPostSize);
1037                inputBuffer.addActiveFilter
1038                    (inputFilters[Constants.BUFFERED_FILTER]);
1039                try {
1040                    Object JavaDoc sslO = sslSupport.getPeerCertificateChain(true);
1041                    if( sslO != null) {
1042                        request.setAttribute
1043                            (SSLSupport.CERTIFICATE_KEY, sslO);
1044                    }
1045                } catch (Exception JavaDoc e) {
1046                    SelectorThread.logger().log(Level.WARNING,
1047                            "processorTask.exceptionSSLcert",e);
1048                }
1049            }
1050        } else if ( actionCode == ActionCode.ACTION_POST_REQUEST ) {
1051            if (response.getStatus() == 200){
1052                try{
1053                    handler.handle(request,Handler.RESPONSE_PROCEEDED);
1054                } catch(IOException JavaDoc ex){
1055                    ; //Ignore
1056
}
1057            }
1058        }
1059    }
1060
1061    // ------------------------------------------------------ Connector Methods
1062

1063
1064    /**
1065     * Set the associated adapter.
1066     *
1067     * @param adapter the new adapter
1068     */

1069    public void setAdapter(Adapter adapter) {
1070        this.adapter = adapter;
1071    }
1072
1073
1074    /**
1075     * Get the associated adapter.
1076     *
1077     * @return the associated adapter
1078     */

1079    public Adapter getAdapter() {
1080        return adapter;
1081    }
1082
1083
1084    // ------------------------------------------------------ Protected Methods
1085

1086
1087    /**
1088     * After reading the request headers, we have to setup the request filters.
1089     */

1090    protected void prepareRequest() {
1091
1092        http11 = true;
1093        http09 = false;
1094        contentDelimitation = false;
1095        if (sslSupport != null) {
1096            request.scheme().setString("https");
1097        }
1098        MessageBytes protocolMB = request.protocol();
1099        if (protocolMB.equals(Constants.HTTP_11)) {
1100            http11 = true;
1101            protocolMB.setString(Constants.HTTP_11);
1102        } else if (protocolMB.equals(Constants.HTTP_10)) {
1103            http11 = false;
1104            keepAlive = false;
1105            protocolMB.setString(Constants.HTTP_10);
1106        } else if (protocolMB.equals("")) {
1107            // HTTP/0.9
1108
http09 = true;
1109            http11 = false;
1110            keepAlive = false;
1111        } else {
1112            // Unsupported protocol
1113
http11 = false;
1114            error = true;
1115            // Send 505; Unsupported HTTP version
1116
response.setStatus(505);
1117        }
1118        
1119        MessageBytes methodMB = request.method();
1120        if (methodMB.equals(Constants.GET)) {
1121            methodMB.setString(Constants.GET);
1122        } else if (methodMB.equals(Constants.POST)) {
1123            methodMB.setString(Constants.POST);
1124        }
1125
1126        MimeHeaders headers = request.getMimeHeaders();
1127
1128        // Check connection header
1129
MessageBytes connectionValueMB = headers.getValue("connection");
1130        if (connectionValueMB != null) {
1131            ByteChunk connectionValueBC = connectionValueMB.getByteChunk();
1132            if (findBytes(connectionValueBC, Constants.CLOSE_BYTES) != -1) {
1133                keepAlive = false;
1134                connectionHeaderValue = false;
1135            } else if (findBytes(connectionValueBC,
1136                                 Constants.KEEPALIVE_BYTES) != -1) {
1137                keepAlive = true;
1138                connectionHeaderValue = true;
1139            }
1140        }
1141
1142
1143        // Check for a full URI (including protocol://host:port/)
1144
ByteChunk uriBC = request.requestURI().getByteChunk();
1145        if (uriBC.startsWithIgnoreCase("http", 0)) {
1146
1147            int pos = uriBC.indexOf("://", 0, 3, 4);
1148            int uriBCStart = uriBC.getStart();
1149            int slashPos = -1;
1150            if (pos != -1) {
1151                byte[] uriB = uriBC.getBytes();
1152                slashPos = uriBC.indexOf('/', pos + 3);
1153                if (slashPos == -1) {
1154                    slashPos = uriBC.getLength();
1155                    // Set URI as "/"
1156
request.requestURI().setBytes
1157                        (uriB, uriBCStart + pos + 1, 1);
1158                } else {
1159                    request.requestURI().setBytes
1160                        (uriB, uriBCStart + slashPos,
1161                         uriBC.getLength() - slashPos);
1162                }
1163                MessageBytes hostMB = headers.setValue("host");
1164                hostMB.setBytes(uriB, uriBCStart + pos + 3,
1165                                slashPos - pos - 3);
1166            }
1167
1168        }
1169
1170        // Input filter setup
1171
InputFilter[] inputFilters = inputBuffer.getFilters();
1172
1173        // Parse content-length header
1174
long contentLength = request.getContentLengthLong();
1175        if (contentLength >= 0) {
1176            
1177            inputBuffer.addActiveFilter
1178                (inputFilters[Constants.IDENTITY_FILTER]);
1179            contentDelimitation = true;
1180        }
1181
1182        // Parse transfer-encoding header
1183
MessageBytes transferEncodingValueMB = null;
1184        if (http11)
1185            transferEncodingValueMB = headers.getValue("transfer-encoding");
1186        if (transferEncodingValueMB != null) {
1187            String JavaDoc transferEncodingValue = transferEncodingValueMB.toString();
1188            // Parse the comma separated list. "identity" codings are ignored
1189
int startPos = 0;
1190            int commaPos = transferEncodingValue.indexOf(',');
1191            String JavaDoc encodingName = null;
1192            while (commaPos != -1) {
1193                encodingName = transferEncodingValue.substring
1194                    (startPos, commaPos).toLowerCase().trim();
1195                if (!addInputFilter(inputFilters, encodingName)) {
1196                    // Unsupported transfer encoding
1197
error = true;
1198                    // 501 - Unimplemented
1199
response.setStatus(501);
1200                }
1201                startPos = commaPos + 1;
1202                commaPos = transferEncodingValue.indexOf(',', startPos);
1203            }
1204            encodingName = transferEncodingValue.substring(startPos)
1205                .toLowerCase().trim();
1206            if (!addInputFilter(inputFilters, encodingName)) {
1207                // Unsupported transfer encoding
1208
error = true;
1209                // 501 - Unimplemented
1210
response.setStatus(501);
1211            }
1212        }
1213
1214        MessageBytes valueMB = headers.getValue("host");
1215
1216        // Check host header
1217
if (http11 && (valueMB == null)) {
1218            error = true;
1219            // 400 - Bad request
1220
response.setStatus(400);
1221        }
1222
1223        parseHost(valueMB);
1224
1225        if (!contentDelimitation) {
1226            // If there's no content length
1227
// (broken HTTP/1.0 or HTTP/1.1), assume
1228
// the client is not broken and didn't send a body
1229
inputBuffer.addActiveFilter
1230                (inputFilters[Constants.VOID_FILTER]);
1231            contentDelimitation = true;
1232        }
1233    }
1234
1235
1236    /**
1237     * Parse host.
1238     */

1239    public void parseHost(MessageBytes valueMB) {
1240
1241        if (valueMB == null || valueMB.isNull()) {
1242            // HTTP/1.0
1243
// Default is what the socket tells us. Overriden if a host is
1244
// found/parsed
1245
request.setServerPort(socket.getLocalPort());
1246            InetAddress JavaDoc localAddress = socket.getLocalAddress();
1247            // Setting the socket-related fields. The adapter doesn't know
1248
// about socket.
1249
request.setLocalHost(localAddress.getHostName());
1250            request.serverName().setString(localAddress.getHostName());
1251            return;
1252        }
1253
1254        ByteChunk valueBC = valueMB.getByteChunk();
1255        byte[] valueB = valueBC.getBytes();
1256        int valueL = valueBC.getLength();
1257        int valueS = valueBC.getStart();
1258        int colonPos = -1;
1259        if (hostNameC.length < valueL) {
1260            hostNameC = new char[valueL];
1261        }
1262
1263        boolean ipv6 = (valueB[valueS] == '[');
1264        boolean bracketClosed = false;
1265        for (int i = 0; i < valueL; i++) {
1266            char b = (char) valueB[i + valueS];
1267            hostNameC[i] = b;
1268            if (b == ']') {
1269                bracketClosed = true;
1270            } else if (b == ':') {
1271                if (!ipv6 || bracketClosed) {
1272                    colonPos = i;
1273                    break;
1274                }
1275            }
1276        }
1277
1278        if (colonPos < 0) {
1279            if (sslSupport == null) {
1280                // 80 - Default HTTTP port
1281
request.setServerPort(80);
1282            } else {
1283                // 443 - Default HTTPS port
1284
request.setServerPort(443);
1285            }
1286            request.serverName().setChars(hostNameC, 0, valueL);
1287        } else {
1288
1289            request.serverName().setChars(hostNameC, 0, colonPos);
1290
1291            int port = 0;
1292            int mult = 1;
1293            for (int i = valueL - 1; i > colonPos; i--) {
1294                int charValue = HexUtils.DEC[(int) valueB[i + valueS]];
1295                if (charValue == -1) {
1296                    // Invalid character
1297
error = true;
1298                    // 400 - Bad request
1299
response.setStatus(400);
1300                    break;
1301                }
1302                port = port + (charValue * mult);
1303                mult = 10 * mult;
1304            }
1305            request.setServerPort(port);
1306
1307        }
1308
1309    }
1310
1311
1312    /**
1313     * When committing the response, we have to validate the set of headers, as
1314     * well as setup the response filters.
1315     */

1316    protected void prepareResponse() {
1317
1318        boolean entityBody = true;
1319        contentDelimitation = false;
1320
1321        OutputFilter[] outputFilters = outputBuffer.getFilters();
1322
1323        if (http09 == true) {
1324            // HTTP/0.9
1325
outputBuffer.addActiveFilter
1326                (outputFilters[Constants.IDENTITY_FILTER]);
1327            return;
1328        }
1329
1330        int statusCode = response.getStatus();
1331        if ((statusCode == 204) || (statusCode == 205)
1332            || (statusCode == 304)) {
1333            // No entity body
1334
outputBuffer.addActiveFilter
1335                (outputFilters[Constants.VOID_FILTER]);
1336            entityBody = false;
1337            contentDelimitation = true;
1338        }
1339
1340        MessageBytes methodMB = request.method();
1341        if (methodMB.equals("HEAD")) {
1342            // No entity body
1343
outputBuffer.addActiveFilter
1344                (outputFilters[Constants.VOID_FILTER]);
1345            contentDelimitation = true;
1346        }
1347
1348        MimeHeaders headers = response.getMimeHeaders();
1349        if (!entityBody) {
1350            response.setContentLength(-1);
1351        } else {
1352            if ( forcedResponseType.equalsIgnoreCase(
1353                    org.apache.coyote.tomcat5.Constants.FORCED_RESPONSE_TYPE) ) {
1354                String JavaDoc contentType = response.getContentType();
1355                if (contentType != null) {
1356                    headers.setValue("Content-Type").setString(contentType);
1357                } else {
1358                    headers.setValue("Content-Type")
1359                        .setString(defaultResponseType);
1360                }
1361            } else {
1362                headers.setValue("Content-Type").setString(forcedResponseType);
1363            }
1364        
1365            String JavaDoc contentLanguage = response.getContentLanguage();
1366            if (contentLanguage != null) {
1367                headers.setValue("Content-Language")
1368                    .setString(contentLanguage);
1369            }
1370        }
1371
1372        int contentLength = response.getContentLength();
1373        if (contentLength != -1) {
1374            headers.setValue("Content-Length").setInt(contentLength);
1375            outputBuffer.addActiveFilter
1376                (outputFilters[Constants.IDENTITY_FILTER]);
1377            contentDelimitation = true;
1378        } else {
1379            if (entityBody && http11 && keepAlive) {
1380                outputBuffer.addActiveFilter
1381                    (outputFilters[Constants.CHUNKED_FILTER]);
1382                contentDelimitation = true;
1383                response.addHeader("Transfer-Encoding", "chunked");
1384            } else {
1385                outputBuffer.addActiveFilter
1386                    (outputFilters[Constants.IDENTITY_FILTER]);
1387            }
1388        }
1389
1390        // Add date header
1391
if (! response.containsHeader("Date")){
1392            String JavaDoc date = FastHttpDateFormat.getCurrentDate();
1393            response.addHeader("Date", date);
1394        }
1395         
1396        // Add server header
1397
headers.setValue("Server").setString(ServerInfo.getServerInfo());
1398
1399        // Add transfer encoding header
1400
// FIXME
1401

1402        if ((entityBody) && (!contentDelimitation)) {
1403            // Mark as close the connection after the request, and add the
1404
// connection: close header
1405
keepAlive = false;
1406        }
1407
1408        // If we know that the request is bad this early, add the
1409
// Connection: close header.
1410
keepAlive = keepAlive && !statusDropsConnection(statusCode)
1411            && !dropConnection;
1412        if (!keepAlive ) {
1413            headers.setValue("Connection").setString("close");
1414            connectionHeaderValue = false;
1415        } else if (!http11 && !error) {
1416            headers.setValue("Connection").setString("Keep-Alive");
1417        }
1418
1419        // Build the response header
1420
outputBuffer.sendStatus();
1421
1422        int size = headers.size();
1423        for (int i = 0; i < size; i++) {
1424            outputBuffer.sendHeader(headers.getName(i), headers.getValue(i));
1425        }
1426        outputBuffer.endHeaders();
1427
1428    }
1429
1430
1431    /**
1432     * Initialize standard input and output filters.
1433     */

1434    protected void initializeFilters() {
1435
1436        // Create and add the identity filters.
1437
inputBuffer.addFilter(new IdentityInputFilter());
1438        outputBuffer.addFilter(new IdentityOutputFilter());
1439
1440        // Create and add the chunked filters.
1441
inputBuffer.addFilter(new ChunkedInputFilter());
1442        outputBuffer.addFilter(new ChunkedOutputFilter());
1443
1444        // Create and add the void filters.
1445
inputBuffer.addFilter(new VoidInputFilter());
1446        outputBuffer.addFilter(new VoidOutputFilter());
1447
1448        // Create and add buffered input filter
1449
inputBuffer.addFilter(new BufferedInputFilter());
1450
1451        // Create and add the chunked filters.
1452
//inputBuffer.addFilter(new GzipInputFilter());
1453
outputBuffer.addFilter(new GzipOutputFilter());
1454
1455    }
1456
1457
1458    /**
1459     * Add an input filter to the current request.
1460     *
1461     * @return false if the encoding was not found (which would mean it is
1462     * unsupported)
1463     */

1464    protected boolean addInputFilter(InputFilter[] inputFilters,
1465                                     String JavaDoc encodingName) {
1466        if (encodingName.equals("identity")) {
1467            // Skip
1468
} else if (encodingName.equals("chunked")) {
1469            inputBuffer.addActiveFilter
1470                (inputFilters[Constants.CHUNKED_FILTER]);
1471            contentDelimitation = true;
1472        } else {
1473            for (int i = 2; i < inputFilters.length; i++) {
1474                if (inputFilters[i].getEncodingName()
1475                    .toString().equals(encodingName)) {
1476                    inputBuffer.addActiveFilter(inputFilters[i]);
1477                    return true;
1478                }
1479            }
1480            return false;
1481        }
1482        return true;
1483    }
1484
1485
1486    /**
1487     * Specialized utility method: find a sequence of lower case bytes inside
1488     * a ByteChunk.
1489     */

1490    protected int findBytes(ByteChunk bc, byte[] b) {
1491
1492        byte first = b[0];
1493        byte[] buff = bc.getBuffer();
1494        int start = bc.getStart();
1495        int end = bc.getEnd();
1496
1497        // Look for first char
1498
int srcEnd = b.length;
1499
1500        for (int i = start; i <= (end - srcEnd); i++) {
1501            if (Ascii.toLower(buff[i]) != first) continue;
1502            // found first char, now look for a match
1503
int myPos = i+1;
1504            for (int srcPos = 1; srcPos < srcEnd; ) {
1505                    if (Ascii.toLower(buff[myPos++]) != b[srcPos++])
1506                break;
1507                    if (srcPos == srcEnd) return i - start; // found it
1508
}
1509        }
1510        return -1;
1511
1512    }
1513
1514    /**
1515     * Determine if we must drop the connection because of the HTTP status
1516     * code. Use the same list of codes as Apache/httpd.
1517     */

1518    protected boolean statusDropsConnection(int status) {
1519        return status == 400 /* SC_BAD_REQUEST */ ||
1520               status == 408 /* SC_REQUEST_TIMEOUT */ ||
1521               status == 411 /* SC_LENGTH_REQUIRED */ ||
1522               status == 413 /* SC_REQUEST_ENTITY_TOO_LARGE */ ||
1523               status == 414 /* SC_REQUEST_URI_TOO_LARGE */ ||
1524               status == 500 /* SC_INTERNAL_SERVER_ERROR */ ||
1525               status == 503 /* SC_SERVICE_UNAVAILABLE */ ||
1526               status == 501 /* SC_NOT_IMPLEMENTED */;
1527    }
1528
1529     /**
1530     * Add input or output filter.
1531     *
1532     * @param className class name of the filter
1533     */

1534    protected void addFilter(String JavaDoc className) {
1535        try {
1536            Class JavaDoc clazz = Class.forName(className);
1537            Object JavaDoc obj = clazz.newInstance();
1538            if (obj instanceof InputFilter) {
1539                inputBuffer.addFilter((InputFilter) obj);
1540            } else if (obj instanceof OutputFilter) {
1541                outputBuffer.addFilter((OutputFilter) obj);
1542            } else {
1543                SelectorThread.logger().log(Level.WARNING,
1544                        "processorTask.unknownFilter" ,className);
1545            }
1546        } catch (Exception JavaDoc e) {
1547            SelectorThread.logger().log(Level.SEVERE,"processorTask.errorFilter",
1548                        new Object JavaDoc[]{className, e});
1549        }
1550    }
1551
1552
1553    /**
1554     * Set the maximum size of a POST which will be buffered in SSL mode.
1555     */

1556    public void setMaxPostSize(int mps) {
1557        maxPostSize = mps;
1558    }
1559
1560
1561    /**
1562     * Return the maximum size of a POST which will be buffered in SSL mode.
1563     */

1564    public int getMaxPostSize() {
1565        return maxPostSize;
1566    }
1567
1568
1569    /**
1570     * Set the socket associated with this HTTP connection.
1571     */

1572    public void setSocket(Socket JavaDoc socket){
1573        this.socket = socket;
1574    }
1575
1576    
1577    /**
1578     * Set the upload timeout.
1579     */

1580    public void setTimeout( int timeouts ) {
1581        timeout = timeouts ;
1582    }
1583
1584    /**
1585     * Get the upload timeout.
1586     */

1587    public int getTimeout() {
1588        return timeout;
1589    }
1590    
1591    /**
1592     * Set the SSL implementation object we are using. This information will
1593     * be required when SSL is used.
1594     */

1595    public void setSSLImplementation( SSLImplementation sslImplementation){
1596        this.sslImplementation = sslImplementation;
1597    }
1598    
1599    
1600    /**
1601     * Register a new <code>RequestProcessor</code> instance.
1602     */

1603    private void registerMonitoring(){
1604
1605        RequestInfo requestInfo = request.getRequestProcessor();
1606        // Add RequestInfo to RequestGroupInfo
1607
requestInfo.setGlobalProcessor(getRequestGroupInfo());
1608
1609        try {
1610            oname = new ObjectName JavaDoc(selectorThread.getDomain()
1611                                   + ":type=RequestProcessor,worker=http"
1612                                   + selectorThread.getPort()
1613                                   + ",name=HttpRequest"
1614                                   + requestCount++ );
1615            Registry.getRegistry().registerComponent(requestInfo, oname,
1616                                                     null);
1617        } catch( Exception JavaDoc ex ) {
1618            SelectorThread.logger().log(Level.WARNING,
1619                       "processorTask.errorRegisteringRequest",
1620                       ex);
1621        }
1622
1623        hasRequestInfoRegistered = true;
1624    }
1625    
1626
1627    /**
1628     * Unregisters the MBean corresponding to this
1629     * <code>ProcessorTask</code>.
1630     */

1631    private void unregisterMonitoring() {
1632
1633        RequestInfo requestInfo = request.getRequestProcessor();
1634        /*
1635         * Remove 'requestInfo' from 'requestGroupInfo'.
1636         * This will also update 'requestGroupInfo' with the current stats
1637         * of 'requestInfo', which is why we need to reset 'requestInfo' so
1638         * its current stats will not be considered when it is added back to
1639         * 'requestGroupInfo' next time registerMonitoring() is called.
1640         */

1641        requestInfo.setGlobalProcessor(null);
1642        requestInfo.reset();
1643
1644        if (oname != null) {
1645            try {
1646                Registry.getRegistry().unregisterComponent(oname);
1647            } catch (Exception JavaDoc ex) {
1648                SelectorThread.logger().log(Level.WARNING,
1649                           "processorTask.errorUnregisteringRequest",
1650                           ex);
1651            }
1652        }
1653
1654        hasRequestInfoRegistered = false;
1655    }
1656
1657
1658    public int getMaxHttpHeaderSize() {
1659        return maxHttpHeaderSize;
1660    }
1661    
1662    public void setMaxHttpHeaderSize(int maxHttpHeaderSize) {
1663        this.maxHttpHeaderSize = maxHttpHeaderSize;
1664    }
1665
1666
1667    /**
1668     * Set the request input buffer size
1669     */

1670    public void setBufferSize(int requestBufferSize){
1671        this.requestBufferSize = requestBufferSize;
1672    }
1673    
1674
1675    /**
1676     * Return the request input buffer size
1677     */

1678    public int getBufferSize(){
1679        return requestBufferSize;
1680    }
1681    
1682    
1683    /**
1684     * Use alternate keep-alive mechanism by using the <code>Selector</code>
1685     * @param useAlternateKeepAlive true if an NIO based keep-alive algorithm
1686     */

1687    public void useAlternateKeepAlive(boolean useAlternateKeepAlive){
1688        this.useAlternateKeepAlive = useAlternateKeepAlive;
1689    }
1690    
1691
1692    /**
1693     * Return the current <code>Socket</code> used by this instance
1694     * @return socket the current <code>Socket</code> used by this instance
1695     */

1696    protected Socket JavaDoc getSocket(){
1697        return socket;
1698    }
1699    
1700    
1701    /**
1702     * Enable or disable the keep-alive mechanism. Setting this value
1703     * to <code>false</code> will automatically add the following header to the
1704     * response ' Connection: close '
1705     */

1706    public void setDropConnection(boolean dropConnection){
1707        this.dropConnection = dropConnection;
1708    }
1709    
1710    
1711    /**
1712     * Is the keep-alive mechanism enabled or disabled.
1713     */

1714    public boolean getDropConnection(){
1715        return dropConnection;
1716    }
1717    
1718    
1719    /**
1720     * Set the maximum number of Keep-Alive requests to honor.
1721     * This is to safeguard from DoS attacks. Setting to a negative
1722     * value disables the check.
1723     */

1724    public void setMaxKeepAliveRequests(int maxKeepAliveRequests) {
1725        this.maxKeepAliveRequests = maxKeepAliveRequests;
1726    }
1727
1728
1729    /**
1730     * Return the number of Keep-Alive requests that we will honor.
1731     */

1732    public int getMaxKeepAliveRequests() {
1733        return maxKeepAliveRequests;
1734    }
1735    
1736    
1737    /**
1738     * Return the number of blocking keep-alive connection
1739     */

1740    public int countBlockingKeepAlive(){
1741        if (maxKeepAliveRequests == -1) return -1;
1742                
1743        return maxKeepAliveRequests - keepAliveLeft;
1744    }
1745 
1746    
1747    /**
1748     * Set the <code>Handler</code> used by this class.
1749     */

1750    public void setHandler(Handler handler){
1751        this.handler = handler;
1752    }
1753    
1754    
1755    /**
1756     * Set the default response type used. Specified as a semi-colon
1757     * delimited string consisting of content-type, encoding,
1758     * language, charset
1759     */

1760    public void setDefaultResponseType(String JavaDoc defaultResponseType){
1761         this.defaultResponseType = defaultResponseType;
1762    }
1763
1764
1765    /**
1766     * Return the default response type used
1767     */

1768    public String JavaDoc getDefaultResponseType(){
1769         return defaultResponseType;
1770    }
1771    
1772    
1773    /**
1774     * Set the forced response type used. The response type to be forced
1775     * if the content served cannot be matched by any of the MIME mappings
1776     * for extensions. Specified as a semi-colon delimited string consisting of
1777     * content-type, encoding, language, charset
1778     */

1779    public void setForcedResponseType(String JavaDoc forcedResponseType){
1780        this.forcedResponseType = forcedResponseType;
1781    }
1782    
1783        
1784    /**
1785     * Return the default response type used
1786     */

1787    public String JavaDoc getForcedResponseType(){
1788        return forcedResponseType;
1789    }
1790    
1791    
1792    // ------------------------------------------------------- Asynch call ---//
1793

1794    /**
1795     * Enable/disable asynchronous execution of this object.
1796     */

1797    public void setEnableAsyncExecution(boolean asyncExecution){
1798        this.asyncExecution = asyncExecution;
1799    }
1800    
1801    
1802    /**
1803     * Is asynchronous execution enabled?
1804     */

1805    public boolean isAsyncExecutionEnabled(){
1806        return asyncExecution;
1807    }
1808    
1809    
1810    /**
1811     * Set the <code>AsyncHandler</code> used when asynchronous execution is
1812     * enabled.
1813     */

1814    public void setAsyncHandler(AsyncHandler asyncHandler){
1815        this.asyncHandler = asyncHandler;
1816    }
1817    
1818       
1819    /**
1820     * Return the <code>AsyncHandler</code> used when asynchronous execution is
1821     * enabled.
1822     */

1823    public AsyncHandler getAsyncHandler(){
1824        return asyncHandler;
1825    }
1826    
1827    
1828    /**
1829     * Recyle this object.
1830     */

1831    public void recycle(){
1832        clearTaskListeners();
1833        socket = null;
1834        dropConnection = false;
1835        key = null;
1836        channelOutputBuffer.setChannel(null);
1837    }
1838}
1839
1840
Popular Tags