KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > coyote > ajp > AjpAprProcessor


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 package org.apache.coyote.ajp;
19
20 import java.io.ByteArrayInputStream JavaDoc;
21 import java.io.IOException JavaDoc;
22 import java.io.InterruptedIOException JavaDoc;
23 import java.net.InetAddress JavaDoc;
24 import java.nio.ByteBuffer JavaDoc;
25 import java.security.cert.CertificateFactory JavaDoc;
26 import java.security.cert.X509Certificate JavaDoc;
27
28 import org.apache.coyote.ActionCode;
29 import org.apache.coyote.ActionHook;
30 import org.apache.coyote.Adapter;
31 import org.apache.coyote.InputBuffer;
32 import org.apache.coyote.OutputBuffer;
33 import org.apache.coyote.Request;
34 import org.apache.coyote.RequestInfo;
35 import org.apache.coyote.Response;
36 import org.apache.tomcat.jni.Socket;
37 import org.apache.tomcat.jni.Status;
38 import org.apache.tomcat.util.buf.ByteChunk;
39 import org.apache.tomcat.util.buf.HexUtils;
40 import org.apache.tomcat.util.buf.MessageBytes;
41 import org.apache.tomcat.util.http.HttpMessages;
42 import org.apache.tomcat.util.http.MimeHeaders;
43 import org.apache.tomcat.util.net.AprEndpoint;
44 import org.apache.tomcat.util.res.StringManager;
45
46
47 /**
48  * Processes HTTP requests.
49  *
50  * @author Remy Maucherat
51  * @author Henri Gomez
52  * @author Dan Milstein
53  * @author Keith Wannamaker
54  * @author Kevin Seguin
55  * @author Costin Manolache
56  * @author Bill Barker
57  */

58 public class AjpAprProcessor implements ActionHook {
59
60
61     /**
62      * Logger.
63      */

64     protected static org.apache.commons.logging.Log log =
65         org.apache.commons.logging.LogFactory.getLog(AjpAprProcessor.class);
66
67     /**
68      * The string manager for this package.
69      */

70     protected static StringManager sm =
71         StringManager.getManager(Constants.Package);
72
73
74     // ----------------------------------------------------------- Constructors
75

76
77     public AjpAprProcessor(int packetSize, AprEndpoint endpoint) {
78
79         this.endpoint = endpoint;
80
81         request = new Request();
82         request.setInputBuffer(new SocketInputBuffer());
83
84         response = new Response();
85         response.setHook(this);
86         response.setOutputBuffer(new SocketOutputBuffer());
87         request.setResponse(response);
88
89         requestHeaderMessage = new AjpMessage(packetSize);
90         responseHeaderMessage = new AjpMessage(packetSize);
91         bodyMessage = new AjpMessage(packetSize);
92         
93         if (endpoint.getFirstReadTimeout() > 0) {
94             readTimeout = endpoint.getFirstReadTimeout() * 1000;
95         } else {
96             readTimeout = 100 * 1000;
97         }
98
99         // Allocate input and output buffers
100
inputBuffer = ByteBuffer.allocateDirect(packetSize * 2);
101         inputBuffer.limit(0);
102         outputBuffer = ByteBuffer.allocateDirect(packetSize * 2);
103
104         // Cause loading of HexUtils
105
int foo = HexUtils.DEC[0];
106
107         // Cause loading of HttpMessages
108
HttpMessages.getMessage(200);
109
110     }
111
112
113     // ----------------------------------------------------- Instance Variables
114

115
116     /**
117      * Associated adapter.
118      */

119     protected Adapter adapter = null;
120
121
122     /**
123      * Request object.
124      */

125     protected Request request = null;
126
127
128     /**
129      * Response object.
130      */

131     protected Response response = null;
132
133
134     /**
135      * Header message. Note that this header is merely the one used during the
136      * processing of the first message of a "request", so it might not be a request
137      * header. It will stay unchanged during the processing of the whole request.
138      */

139     protected AjpMessage requestHeaderMessage = null;
140
141
142     /**
143      * Message used for response header composition.
144      */

145     protected AjpMessage responseHeaderMessage = null;
146
147
148     /**
149      * Body message.
150      */

151     protected AjpMessage bodyMessage = null;
152
153
154     /**
155      * Body message.
156      */

157     protected MessageBytes bodyBytes = MessageBytes.newInstance();
158
159
160     /**
161      * State flag.
162      */

163     protected boolean started = false;
164
165
166     /**
167      * Error flag.
168      */

169     protected boolean error = false;
170
171
172     /**
173      * Socket associated with the current connection.
174      */

175     protected long socket;
176
177
178     /**
179      * Host name (used to avoid useless B2C conversion on the host name).
180      */

181     protected char[] hostNameC = new char[0];
182
183
184     /**
185      * Associated endpoint.
186      */

187     protected AprEndpoint endpoint;
188
189
190     /**
191      * The socket timeout used when reading the first block of the request
192      * header.
193      */

194     protected long readTimeout;
195
196
197     /**
198      * Temp message bytes used for processing.
199      */

200     protected MessageBytes tmpMB = MessageBytes.newInstance();
201
202
203     /**
204      * Byte chunk for certs.
205      */

206     protected MessageBytes certificates = MessageBytes.newInstance();
207
208
209     /**
210      * End of stream flag.
211      */

212     protected boolean endOfStream = false;
213
214
215     /**
216      * Body empty flag.
217      */

218     protected boolean empty = true;
219
220
221     /**
222      * First read.
223      */

224     protected boolean first = true;
225
226
227     /**
228      * Replay read.
229      */

230     protected boolean replay = false;
231
232
233     /**
234      * Finished response.
235      */

236     protected boolean finished = false;
237
238
239     /**
240      * Direct buffer used for output.
241      */

242     protected ByteBuffer JavaDoc outputBuffer = null;
243
244
245     /**
246      * Direct buffer used for input.
247      */

248     protected ByteBuffer JavaDoc inputBuffer = null;
249
250
251     /**
252      * Direct buffer used for sending right away a get body message.
253      */

254     protected static final ByteBuffer JavaDoc getBodyMessageBuffer;
255
256
257     /**
258      * Direct buffer used for sending right away a pong message.
259      */

260     protected static final ByteBuffer JavaDoc pongMessageBuffer;
261
262
263     /**
264      * End message array.
265      */

266     protected static final byte[] endMessageArray;
267
268     /**
269      * Direct buffer used for sending explicit flush message.
270      */

271     protected static final ByteBuffer JavaDoc flushMessageBuffer;
272
273
274     // ----------------------------------------------------- Static Initializer
275

276
277     static {
278
279         // Set the get body message buffer
280
AjpMessage getBodyMessage = new AjpMessage(16);
281         getBodyMessage.reset();
282         getBodyMessage.appendByte(Constants.JK_AJP13_GET_BODY_CHUNK);
283         getBodyMessage.appendInt(Constants.MAX_READ_SIZE);
284         getBodyMessage.end();
285         getBodyMessageBuffer =
286             ByteBuffer.allocateDirect(getBodyMessage.getLen());
287         getBodyMessageBuffer.put(getBodyMessage.getBuffer(), 0,
288                 getBodyMessage.getLen());
289
290         // Set the read body message buffer
291
AjpMessage pongMessage = new AjpMessage(16);
292         pongMessage.reset();
293         pongMessage.appendByte(Constants.JK_AJP13_CPONG_REPLY);
294         pongMessage.end();
295         pongMessageBuffer = ByteBuffer.allocateDirect(pongMessage.getLen());
296         pongMessageBuffer.put(pongMessage.getBuffer(), 0,
297                 pongMessage.getLen());
298
299         // Allocate the end message array
300
AjpMessage endMessage = new AjpMessage(16);
301         endMessage.reset();
302         endMessage.appendByte(Constants.JK_AJP13_END_RESPONSE);
303         endMessage.appendByte(1);
304         endMessage.end();
305         endMessageArray = new byte[endMessage.getLen()];
306         System.arraycopy(endMessage.getBuffer(), 0, endMessageArray, 0,
307                 endMessage.getLen());
308
309         // Set the flush message buffer
310
AjpMessage flushMessage = new AjpMessage(16);
311         flushMessage.reset();
312         flushMessage.appendByte(Constants.JK_AJP13_SEND_BODY_CHUNK);
313         flushMessage.appendInt(0);
314         flushMessage.appendByte(0);
315         flushMessage.end();
316         flushMessageBuffer =
317             ByteBuffer.allocateDirect(flushMessage.getLen());
318         flushMessageBuffer.put(flushMessage.getBuffer(), 0,
319                 flushMessage.getLen());
320
321     }
322
323
324     // ------------------------------------------------------------- Properties
325

326
327     /**
328      * Use Tomcat authentication ?
329      */

330     protected boolean tomcatAuthentication = true;
331     public boolean getTomcatAuthentication() { return tomcatAuthentication; }
332     public void setTomcatAuthentication(boolean tomcatAuthentication) { this.tomcatAuthentication = tomcatAuthentication; }
333
334
335     /**
336      * Required secret.
337      */

338     protected String JavaDoc requiredSecret = null;
339     public void setRequiredSecret(String JavaDoc requiredSecret) { this.requiredSecret = requiredSecret; }
340
341
342     // --------------------------------------------------------- Public Methods
343

344
345     /** Get the request associated with this processor.
346      *
347      * @return The request
348      */

349     public Request getRequest() {
350         return request;
351     }
352
353
354     /**
355      * Process pipelined HTTP requests using the specified input and output
356      * streams.
357      *
358      * @throws IOException error during an I/O operation
359      */

360     public boolean process(long socket)
361         throws IOException JavaDoc {
362         RequestInfo rp = request.getRequestProcessor();
363         rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
364
365         // Setting up the socket
366
this.socket = socket;
367         Socket.setrbb(this.socket, inputBuffer);
368         Socket.setsbb(this.socket, outputBuffer);
369
370         // Error flag
371
error = false;
372
373         int limit = 0;
374         if (endpoint.getFirstReadTimeout() > 0) {
375             limit = endpoint.getMaxThreads() / 2;
376         }
377
378         boolean openSocket = true;
379         boolean keptAlive = false;
380
381         while (started && !error) {
382
383             // Parsing the request header
384
try {
385                 // Get first message of the request
386
if (!readMessage(requestHeaderMessage, true,
387                         keptAlive && (endpoint.getCurrentThreadsBusy() > limit))) {
388                     // This means that no data is available right now
389
// (long keepalive), so that the processor should be recycled
390
// and the method should return true
391
rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
392                     break;
393                 }
394                 // Check message type, process right away and break if
395
// not regular request processing
396
int type = requestHeaderMessage.getByte();
397                 if (type == Constants.JK_AJP13_CPING_REQUEST) {
398                     if (Socket.sendb(socket, pongMessageBuffer, 0,
399                             pongMessageBuffer.position()) < 0) {
400                         error = true;
401                     }
402                     continue;
403                 } else if(type != Constants.JK_AJP13_FORWARD_REQUEST) {
404                     // Usually the servlet didn't read the previous request body
405
if(log.isDebugEnabled()) {
406                         log.debug("Unexpected message: "+type);
407                     }
408                     continue;
409                 }
410
411                 keptAlive = true;
412                 request.setStartTime(System.currentTimeMillis());
413             } catch (IOException JavaDoc e) {
414                 error = true;
415                 break;
416             } catch (Throwable JavaDoc t) {
417                 log.debug(sm.getString("ajpprocessor.header.error"), t);
418                 // 400 - Bad Request
419
response.setStatus(400);
420                 error = true;
421             }
422
423             // Setting up filters, and parse some request headers
424
rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
425             try {
426                 prepareRequest();
427             } catch (Throwable JavaDoc t) {
428                 log.debug(sm.getString("ajpprocessor.request.prepare"), t);
429                 // 400 - Internal Server Error
430
response.setStatus(400);
431                 error = true;
432             }
433
434             // Process the request in the adapter
435
if (!error) {
436                 try {
437                     rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
438                     adapter.service(request, response);
439                 } catch (InterruptedIOException JavaDoc e) {
440                     error = true;
441                 } catch (Throwable JavaDoc t) {
442                     log.error(sm.getString("ajpprocessor.request.process"), t);
443                     // 500 - Internal Server Error
444
response.setStatus(500);
445                     error = true;
446                 }
447             }
448
449             // Finish the response if not done yet
450
if (!finished) {
451                 try {
452                     finish();
453                 } catch (Throwable JavaDoc t) {
454                     error = true;
455                 }
456             }
457
458             // If there was an error, make sure the request is counted as
459
// and error, and update the statistics counter
460
if (error) {
461                 response.setStatus(500);
462             }
463             request.updateCounters();
464
465             rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
466             recycle();
467
468         }
469
470         // Add the socket to the poller
471
if (!error) {
472             endpoint.getPoller().add(socket);
473         } else {
474             openSocket = false;
475         }
476
477         rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
478         recycle();
479
480         return openSocket;
481
482     }
483
484
485     // ----------------------------------------------------- ActionHook Methods
486

487
488     /**
489      * Send an action to the connector.
490      *
491      * @param actionCode Type of the action
492      * @param param Action parameter
493      */

494     public void action(ActionCode actionCode, Object JavaDoc param) {
495
496         if (actionCode == ActionCode.ACTION_COMMIT) {
497
498             if (response.isCommitted())
499                 return;
500
501             // Validate and write response headers
502
try {
503                 prepareResponse();
504             } catch (IOException JavaDoc e) {
505                 // Set error flag
506
error = true;
507             }
508
509         } else if (actionCode == ActionCode.ACTION_CLIENT_FLUSH) {
510
511             if (!response.isCommitted()) {
512                 // Validate and write response headers
513
try {
514                     prepareResponse();
515                 } catch (IOException JavaDoc e) {
516                     // Set error flag
517
error = true;
518                     return;
519                 }
520             }
521
522             try {
523                 flush();
524                 // Send explicit flush message
525
if (Socket.sendb(socket, flushMessageBuffer, 0,
526                                  flushMessageBuffer.position()) < 0) {
527                     error = true;
528                 }
529             } catch (IOException JavaDoc e) {
530                 // Set error flag
531
error = true;
532             }
533
534         } else if (actionCode == ActionCode.ACTION_CLOSE) {
535             // Close
536

537             // End the processing of the current request, and stop any further
538
// transactions with the client
539

540             try {
541                 finish();
542             } catch (IOException JavaDoc e) {
543                 // Set error flag
544
error = true;
545             }
546
547         } else if (actionCode == ActionCode.ACTION_START) {
548
549             started = true;
550
551         } else if (actionCode == ActionCode.ACTION_STOP) {
552
553             started = false;
554
555         } else if (actionCode == ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) {
556
557             if (!certificates.isNull()) {
558                 ByteChunk certData = certificates.getByteChunk();
559                 X509Certificate JavaDoc jsseCerts[] = null;
560                 ByteArrayInputStream JavaDoc bais =
561                     new ByteArrayInputStream JavaDoc(certData.getBytes(),
562                             certData.getStart(),
563                             certData.getLength());
564                 // Fill the first element.
565
try {
566                     CertificateFactory JavaDoc cf =
567                         CertificateFactory.getInstance("X.509");
568                     X509Certificate JavaDoc cert = (X509Certificate JavaDoc)
569                     cf.generateCertificate(bais);
570                     jsseCerts = new X509Certificate JavaDoc[1];
571                     jsseCerts[0] = cert;
572                     request.setAttribute(AprEndpoint.CERTIFICATE_KEY, jsseCerts);
573                 } catch (java.security.cert.CertificateException JavaDoc e) {
574                     log.error(sm.getString("ajpprocessor.certs.fail"), e);
575                     return;
576                 }
577             }
578
579         } else if (actionCode == ActionCode.ACTION_REQ_HOST_ATTRIBUTE) {
580
581             // Get remote host name using a DNS resolution
582
if (request.remoteHost().isNull()) {
583                 try {
584                     request.remoteHost().setString(InetAddress.getByName
585                             (request.remoteAddr().toString()).getHostName());
586                 } catch (IOException JavaDoc iex) {
587                     // Ignore
588
}
589             }
590
591         } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE) {
592
593             // Copy from local name for now, which should simply be an address
594
request.localAddr().setString(request.localName().toString());
595
596         } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) {
597
598             // Set the given bytes as the content
599
ByteChunk bc = (ByteChunk) param;
600             bodyBytes.setBytes(bc.getBytes(), bc.getStart(), bc.getLength());
601             request.setContentLength(bc.getLength());
602             first = false;
603             empty = false;
604             replay = true;
605
606         }
607
608
609     }
610
611
612     // ------------------------------------------------------ Connector Methods
613

614
615     /**
616      * Set the associated adapter.
617      *
618      * @param adapter the new adapter
619      */

620     public void setAdapter(Adapter adapter) {
621         this.adapter = adapter;
622     }
623
624
625     /**
626      * Get the associated adapter.
627      *
628      * @return the associated adapter
629      */

630     public Adapter getAdapter() {
631         return adapter;
632     }
633
634
635     // ------------------------------------------------------ Protected Methods
636

637
638     /**
639      * After reading the request headers, we have to setup the request filters.
640      */

641     protected void prepareRequest() {
642
643         // Translate the HTTP method code to a String.
644
byte methodCode = requestHeaderMessage.getByte();
645         if (methodCode != Constants.SC_M_JK_STORED) {
646             String JavaDoc methodName = Constants.methodTransArray[(int)methodCode - 1];
647             request.method().setString(methodName);
648         }
649
650         requestHeaderMessage.getBytes(request.protocol());
651         requestHeaderMessage.getBytes(request.requestURI());
652
653         requestHeaderMessage.getBytes(request.remoteAddr());
654         requestHeaderMessage.getBytes(request.remoteHost());
655         requestHeaderMessage.getBytes(request.localName());
656         request.setLocalPort(requestHeaderMessage.getInt());
657
658         boolean isSSL = requestHeaderMessage.getByte() != 0;
659         if (isSSL) {
660             request.scheme().setString("https");
661         }
662
663         // Decode headers
664
MimeHeaders headers = request.getMimeHeaders();
665
666         int hCount = requestHeaderMessage.getInt();
667         for(int i = 0 ; i < hCount ; i++) {
668             String JavaDoc hName = null;
669
670             // Header names are encoded as either an integer code starting
671
// with 0xA0, or as a normal string (in which case the first
672
// two bytes are the length).
673
int isc = requestHeaderMessage.peekInt();
674             int hId = isc & 0xFF;
675
676             MessageBytes vMB = null;
677             isc &= 0xFF00;
678             if(0xA000 == isc) {
679                 requestHeaderMessage.getInt(); // To advance the read position
680
hName = Constants.headerTransArray[hId - 1];
681                 vMB = headers.addValue(hName);
682             } else {
683                 // reset hId -- if the header currently being read
684
// happens to be 7 or 8 bytes long, the code below
685
// will think it's the content-type header or the
686
// content-length header - SC_REQ_CONTENT_TYPE=7,
687
// SC_REQ_CONTENT_LENGTH=8 - leading to unexpected
688
// behaviour. see bug 5861 for more information.
689
hId = -1;
690                 requestHeaderMessage.getBytes(tmpMB);
691                 ByteChunk bc = tmpMB.getByteChunk();
692                 vMB = headers.addValue(bc.getBuffer(),
693                         bc.getStart(), bc.getLength());
694             }
695
696             requestHeaderMessage.getBytes(vMB);
697
698             if (hId == Constants.SC_REQ_CONTENT_LENGTH ||
699                     (hId == -1 && tmpMB.equalsIgnoreCase("Content-Length"))) {
700                 // just read the content-length header, so set it
701
request.setContentLength( vMB.getInt() );
702             } else if (hId == Constants.SC_REQ_CONTENT_TYPE ||
703                     (hId == -1 && tmpMB.equalsIgnoreCase("Content-Type"))) {
704                 // just read the content-type header, so set it
705
ByteChunk bchunk = vMB.getByteChunk();
706                 request.contentType().setBytes(bchunk.getBytes(),
707                         bchunk.getOffset(),
708                         bchunk.getLength());
709             }
710         }
711
712         // Decode extra attributes
713
boolean secret = false;
714         byte attributeCode;
715         while ((attributeCode = requestHeaderMessage.getByte())
716                 != Constants.SC_A_ARE_DONE) {
717
718             switch (attributeCode) {
719
720             case Constants.SC_A_REQ_ATTRIBUTE :
721                 requestHeaderMessage.getBytes(tmpMB);
722                 String JavaDoc n = tmpMB.toString();
723                 requestHeaderMessage.getBytes(tmpMB);
724                 String JavaDoc v = tmpMB.toString();
725                 request.setAttribute(n, v);
726                 break;
727
728             case Constants.SC_A_CONTEXT :
729                 requestHeaderMessage.getBytes(tmpMB);
730                 // nothing
731
break;
732
733             case Constants.SC_A_SERVLET_PATH :
734                 requestHeaderMessage.getBytes(tmpMB);
735                 // nothing
736
break;
737
738             case Constants.SC_A_REMOTE_USER :
739                 if (tomcatAuthentication) {
740                     // ignore server
741
requestHeaderMessage.getBytes(tmpMB);
742                 } else {
743                     requestHeaderMessage.getBytes(request.getRemoteUser());
744                 }
745                 break;
746
747             case Constants.SC_A_AUTH_TYPE :
748                 if (tomcatAuthentication) {
749                     // ignore server
750
requestHeaderMessage.getBytes(tmpMB);
751                 } else {
752                     requestHeaderMessage.getBytes(request.getAuthType());
753                 }
754                 break;
755
756             case Constants.SC_A_QUERY_STRING :
757                 requestHeaderMessage.getBytes(request.queryString());
758                 break;
759
760             case Constants.SC_A_JVM_ROUTE :
761                 requestHeaderMessage.getBytes(request.instanceId());
762                 break;
763
764             case Constants.SC_A_SSL_CERT :
765                 request.scheme().setString("https");
766                 // SSL certificate extraction is lazy, moved to JkCoyoteHandler
767
requestHeaderMessage.getBytes(certificates);
768                 break;
769
770             case Constants.SC_A_SSL_CIPHER :
771                 request.scheme().setString("https");
772                 requestHeaderMessage.getBytes(tmpMB);
773                 request.setAttribute(AprEndpoint.CIPHER_SUITE_KEY,
774                                      tmpMB.toString());
775                 break;
776
777             case Constants.SC_A_SSL_SESSION :
778                 request.scheme().setString("https");
779                 requestHeaderMessage.getBytes(tmpMB);
780                 request.setAttribute(AprEndpoint.SESSION_ID_KEY,
781                                      tmpMB.toString());
782                 break;
783
784             case Constants.SC_A_SSL_KEY_SIZE :
785                 request.setAttribute(AprEndpoint.KEY_SIZE_KEY,
786                                      new Integer JavaDoc(requestHeaderMessage.getInt()));
787                 break;
788
789             case Constants.SC_A_STORED_METHOD:
790                 requestHeaderMessage.getBytes(request.method());
791                 break;
792
793             case Constants.SC_A_SECRET:
794                 requestHeaderMessage.getBytes(tmpMB);
795                 if (requiredSecret != null) {
796                     secret = true;
797                     if (!tmpMB.equals(requiredSecret)) {
798                         response.setStatus(403);
799                         error = true;
800                     }
801                 }
802                 break;
803
804             default:
805                 // Ignore unknown attribute for backward compatibility
806
break;
807
808             }
809
810         }
811
812         // Check if secret was submitted if required
813
if ((requiredSecret != null) && !secret) {
814             response.setStatus(403);
815             error = true;
816         }
817
818         // Check for a full URI (including protocol://host:port/)
819
ByteChunk uriBC = request.requestURI().getByteChunk();
820         if (uriBC.startsWithIgnoreCase("http", 0)) {
821
822             int pos = uriBC.indexOf("://", 0, 3, 4);
823             int uriBCStart = uriBC.getStart();
824             int slashPos = -1;
825             if (pos != -1) {
826                 byte[] uriB = uriBC.getBytes();
827                 slashPos = uriBC.indexOf('/', pos + 3);
828                 if (slashPos == -1) {
829                     slashPos = uriBC.getLength();
830                     // Set URI as "/"
831
request.requestURI().setBytes
832                         (uriB, uriBCStart + pos + 1, 1);
833                 } else {
834                     request.requestURI().setBytes
835                         (uriB, uriBCStart + slashPos,
836                          uriBC.getLength() - slashPos);
837                 }
838                 MessageBytes hostMB = headers.setValue("host");
839                 hostMB.setBytes(uriB, uriBCStart + pos + 3,
840                                 slashPos - pos - 3);
841             }
842
843         }
844
845         MessageBytes valueMB = request.getMimeHeaders().getValue("host");
846         parseHost(valueMB);
847
848     }
849
850
851     /**
852      * Parse host.
853      */

854     public void parseHost(MessageBytes valueMB) {
855
856         if (valueMB == null || (valueMB != null && valueMB.isNull()) ) {
857             // HTTP/1.0
858
// Default is what the socket tells us. Overriden if a host is
859
// found/parsed
860
request.setServerPort(endpoint.getPort());
861             return;
862         }
863
864         ByteChunk valueBC = valueMB.getByteChunk();
865         byte[] valueB = valueBC.getBytes();
866         int valueL = valueBC.getLength();
867         int valueS = valueBC.getStart();
868         int colonPos = -1;
869         if (hostNameC.length < valueL) {
870             hostNameC = new char[valueL];
871         }
872
873         boolean ipv6 = (valueB[valueS] == '[');
874         boolean bracketClosed = false;
875         for (int i = 0; i < valueL; i++) {
876             char b = (char) valueB[i + valueS];
877             hostNameC[i] = b;
878             if (b == ']') {
879                 bracketClosed = true;
880             } else if (b == ':') {
881                 if (!ipv6 || bracketClosed) {
882                     colonPos = i;
883                     break;
884                 }
885             }
886         }
887
888         if (colonPos < 0) {
889             if (request.scheme().equalsIgnoreCase("https")) {
890                 // 443 - Default HTTPS port
891
request.setServerPort(443);
892             } else {
893                 // 80 - Default HTTTP port
894
request.setServerPort(80);
895             }
896             request.serverName().setChars(hostNameC, 0, valueL);
897         } else {
898
899             request.serverName().setChars(hostNameC, 0, colonPos);
900
901             int port = 0;
902             int mult = 1;
903             for (int i = valueL - 1; i > colonPos; i--) {
904                 int charValue = HexUtils.DEC[(int) valueB[i + valueS]];
905                 if (charValue == -1) {
906                     // Invalid character
907
error = true;
908                     // 400 - Bad request
909
response.setStatus(400);
910                     break;
911                 }
912                 port = port + (charValue * mult);
913                 mult = 10 * mult;
914             }
915             request.setServerPort(port);
916
917         }
918
919     }
920
921
922     /**
923      * When committing the response, we have to validate the set of headers, as
924      * well as setup the response filters.
925      */

926     protected void prepareResponse()
927         throws IOException JavaDoc {
928
929         response.setCommitted(true);
930
931         responseHeaderMessage.reset();
932         responseHeaderMessage.appendByte(Constants.JK_AJP13_SEND_HEADERS);
933
934         // HTTP header contents
935
responseHeaderMessage.appendInt(response.getStatus());
936         String JavaDoc message = response.getMessage();
937         if (message == null){
938             message = HttpMessages.getMessage(response.getStatus());
939         } else {
940             message = message.replace('\n', ' ').replace('\r', ' ');
941         }
942         tmpMB.setString(message);
943         responseHeaderMessage.appendBytes(tmpMB);
944
945         // Special headers
946
MimeHeaders headers = response.getMimeHeaders();
947         String JavaDoc contentType = response.getContentType();
948         if (contentType != null) {
949             headers.setValue("Content-Type").setString(contentType);
950         }
951         String JavaDoc contentLanguage = response.getContentLanguage();
952         if (contentLanguage != null) {
953             headers.setValue("Content-Language").setString(contentLanguage);
954         }
955         int contentLength = response.getContentLength();
956         if (contentLength >= 0) {
957             headers.setValue("Content-Length").setInt(contentLength);
958         }
959
960         // Other headers
961
int numHeaders = headers.size();
962         responseHeaderMessage.appendInt(numHeaders);
963         for (int i = 0; i < numHeaders; i++) {
964             MessageBytes hN = headers.getName(i);
965             responseHeaderMessage.appendBytes(hN);
966             MessageBytes hV=headers.getValue(i);
967             responseHeaderMessage.appendBytes(hV);
968         }
969
970         // Write to buffer
971
responseHeaderMessage.end();
972         outputBuffer.put(responseHeaderMessage.getBuffer(), 0, responseHeaderMessage.getLen());
973
974     }
975
976
977     /**
978      * Finish AJP response.
979      */

980     protected void finish()
981         throws IOException JavaDoc {
982
983         if (!response.isCommitted()) {
984             // Validate and write response headers
985
try {
986                 prepareResponse();
987             } catch (IOException JavaDoc e) {
988                 // Set error flag
989
error = true;
990             }
991         }
992
993         if (finished)
994             return;
995
996         finished = true;
997
998         // Add the end message
999
if (outputBuffer.position() + endMessageArray.length > outputBuffer.capacity()) {
1000            flush();
1001        }
1002        outputBuffer.put(endMessageArray);
1003        flush();
1004
1005    }
1006
1007
1008    /**
1009     * Read at least the specified amount of bytes, and place them
1010     * in the input buffer.
1011     */

1012    protected boolean read(int n)
1013        throws IOException JavaDoc {
1014
1015        if (inputBuffer.capacity() - inputBuffer.limit() <=
1016                n - inputBuffer.remaining()) {
1017            inputBuffer.compact();
1018            inputBuffer.limit(inputBuffer.position());
1019            inputBuffer.position(0);
1020        }
1021        while (inputBuffer.remaining() < n) {
1022            int nRead = Socket.recvbb
1023                (socket, inputBuffer.limit(),
1024                        inputBuffer.capacity() - inputBuffer.limit());
1025            if (nRead > 0) {
1026                inputBuffer.limit(inputBuffer.limit() + nRead);
1027            } else {
1028                throw new IOException JavaDoc(sm.getString("ajpprotocol.failedread"));
1029            }
1030        }
1031
1032        return true;
1033
1034    }
1035
1036
1037    /**
1038     * Read at least the specified amount of bytes, and place them
1039     * in the input buffer.
1040     */

1041    protected boolean readt(int n, boolean useAvailableData)
1042        throws IOException JavaDoc {
1043
1044        if (useAvailableData && inputBuffer.remaining() == 0) {
1045            return false;
1046        }
1047        if (inputBuffer.capacity() - inputBuffer.limit() <=
1048                n - inputBuffer.remaining()) {
1049            inputBuffer.compact();
1050            inputBuffer.limit(inputBuffer.position());
1051            inputBuffer.position(0);
1052        }
1053        while (inputBuffer.remaining() < n) {
1054            int nRead = Socket.recvbbt
1055                (socket, inputBuffer.limit(),
1056                        inputBuffer.capacity() - inputBuffer.limit(), readTimeout);
1057            if (nRead > 0) {
1058                inputBuffer.limit(inputBuffer.limit() + nRead);
1059            } else {
1060                if ((-nRead) == Status.ETIMEDOUT || (-nRead) == Status.TIMEUP) {
1061                    return false;
1062                } else {
1063                    throw new IOException JavaDoc(sm.getString("ajpprotocol.failedread"));
1064                }
1065            }
1066        }
1067
1068        return true;
1069
1070    }
1071
1072
1073    /** Receive a chunk of data. Called to implement the
1074     * 'special' packet in ajp13 and to receive the data
1075     * after we send a GET_BODY packet
1076     */

1077    public boolean receive() throws IOException JavaDoc {
1078
1079        first = false;
1080        bodyMessage.reset();
1081        readMessage(bodyMessage, false, false);
1082
1083        // No data received.
1084
if (bodyMessage.getLen() == 0) {
1085            // just the header
1086
// Don't mark 'end of stream' for the first chunk.
1087
return false;
1088        }
1089        int blen = bodyMessage.peekInt();
1090        if (blen == 0) {
1091            return false;
1092        }
1093
1094        bodyMessage.getBytes(bodyBytes);
1095        empty = false;
1096        return true;
1097    }
1098
1099    /**
1100     * Get more request body data from the web server and store it in the
1101     * internal buffer.
1102     *
1103     * @return true if there is more data, false if not.
1104     */

1105    private boolean refillReadBuffer() throws IOException JavaDoc {
1106        // If the server returns an empty packet, assume that that end of
1107
// the stream has been reached (yuck -- fix protocol??).
1108
// FORM support
1109
if (replay) {
1110            endOfStream = true; // we've read everything there is
1111
}
1112        if (endOfStream) {
1113            return false;
1114        }
1115
1116        // Request more data immediately
1117
Socket.sendb(socket, getBodyMessageBuffer, 0,
1118                getBodyMessageBuffer.position());
1119
1120        boolean moreData = receive();
1121        if( !moreData ) {
1122            endOfStream = true;
1123        }
1124        return moreData;
1125    }
1126
1127
1128    /**
1129     * Read an AJP message.
1130     *
1131     * @param first is true if the message is the first in the request, which
1132     * will cause a short duration blocking read
1133     * @return true if the message has been read, false if the short read
1134     * didn't return anything
1135     * @throws IOException any other failure, including incomplete reads
1136     */

1137    protected boolean readMessage(AjpMessage message, boolean first,
1138            boolean useAvailableData)
1139        throws IOException JavaDoc {
1140
1141        byte[] buf = message.getBuffer();
1142        int headerLength = message.getHeaderLength();
1143
1144        if (first) {
1145            if (!readt(headerLength, useAvailableData)) {
1146                return false;
1147            }
1148        } else {
1149            read(headerLength);
1150        }
1151        inputBuffer.get(message.getBuffer(), 0, headerLength);
1152        message.processHeader();
1153        read(message.getLen());
1154        inputBuffer.get(message.getBuffer(), headerLength, message.getLen());
1155
1156        return true;
1157
1158    }
1159
1160
1161    /**
1162     * Recycle the processor.
1163     */

1164    public void recycle() {
1165
1166        // Recycle Request object
1167
first = true;
1168        endOfStream = false;
1169        empty = true;
1170        replay = false;
1171        finished = false;
1172        request.recycle();
1173        response.recycle();
1174        certificates.recycle();
1175
1176        inputBuffer.clear();
1177        inputBuffer.limit(0);
1178        outputBuffer.clear();
1179
1180    }
1181
1182
1183    /**
1184     * Callback to write data from the buffer.
1185     */

1186    protected void flush()
1187        throws IOException JavaDoc {
1188        if (outputBuffer.position() > 0) {
1189            if (Socket.sendbb(socket, 0, outputBuffer.position()) < 0) {
1190                throw new IOException JavaDoc();
1191            }
1192            outputBuffer.clear();
1193        }
1194    }
1195
1196
1197    // ------------------------------------- InputStreamInputBuffer Inner Class
1198

1199
1200    /**
1201     * This class is an input buffer which will read its data from an input
1202     * stream.
1203     */

1204    protected class SocketInputBuffer
1205        implements InputBuffer {
1206
1207
1208        /**
1209         * Read bytes into the specified chunk.
1210         */

1211        public int doRead(ByteChunk chunk, Request req )
1212            throws IOException JavaDoc {
1213
1214            if (endOfStream) {
1215                return -1;
1216            }
1217            if (first && req.getContentLength() > 0) {
1218                // Handle special first-body-chunk
1219
if (!receive()) {
1220                    return 0;
1221                }
1222            } else if (empty) {
1223                if (!refillReadBuffer()) {
1224                    return -1;
1225                }
1226            }
1227            ByteChunk bc = bodyBytes.getByteChunk();
1228            chunk.setBytes(bc.getBuffer(), bc.getStart(), bc.getLength());
1229            empty = true;
1230            return chunk.getLength();
1231
1232        }
1233
1234    }
1235
1236
1237    // ----------------------------------- OutputStreamOutputBuffer Inner Class
1238

1239
1240    /**
1241     * This class is an output buffer which will write data to an output
1242     * stream.
1243     */

1244    protected class SocketOutputBuffer
1245        implements OutputBuffer {
1246
1247
1248        /**
1249         * Write chunk.
1250         */

1251        public int doWrite(ByteChunk chunk, Response res)
1252            throws IOException JavaDoc {
1253
1254            if (!response.isCommitted()) {
1255                // Validate and write response headers
1256
try {
1257                    prepareResponse();
1258                } catch (IOException JavaDoc e) {
1259                    // Set error flag
1260
error = true;
1261                }
1262            }
1263
1264            int len = chunk.getLength();
1265            // 4 - hardcoded, byte[] marshalling overhead
1266
int chunkSize = Constants.MAX_SEND_SIZE;
1267            int off = 0;
1268            while (len > 0) {
1269                int thisTime = len;
1270                if (thisTime > chunkSize) {
1271                    thisTime = chunkSize;
1272                }
1273                len -= thisTime;
1274                if (outputBuffer.position() + thisTime +
1275                    Constants.H_SIZE + 4 > outputBuffer.capacity()) {
1276                    flush();
1277                }
1278                outputBuffer.put((byte) 0x41);
1279                outputBuffer.put((byte) 0x42);
1280                outputBuffer.putShort((short) (thisTime + 4));
1281                outputBuffer.put(Constants.JK_AJP13_SEND_BODY_CHUNK);
1282                outputBuffer.putShort((short) thisTime);
1283                outputBuffer.put(chunk.getBytes(), chunk.getOffset() + off, thisTime);
1284                outputBuffer.put((byte) 0x00);
1285                off += thisTime;
1286            }
1287
1288            return chunk.getLength();
1289
1290        }
1291
1292
1293    }
1294
1295
1296}
1297
Popular Tags