KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > jk > common > HandlerRequest


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

16
17 package org.apache.jk.common;
18
19 import java.io.File JavaDoc;
20 import java.io.FileOutputStream JavaDoc;
21 import java.io.IOException JavaDoc;
22 import java.io.CharConversionException JavaDoc;
23 import java.net.InetAddress JavaDoc;
24 import java.util.Properties JavaDoc;
25
26 import org.apache.coyote.Request;
27 import org.apache.coyote.RequestInfo;
28 import org.apache.coyote.Response;
29 import org.apache.coyote.Constants;
30 import org.apache.jk.core.JkHandler;
31 import org.apache.jk.core.Msg;
32 import org.apache.jk.core.MsgContext;
33 import org.apache.jk.core.WorkerEnv;
34 import org.apache.jk.core.JkChannel;
35 import org.apache.tomcat.util.buf.ByteChunk;
36 import org.apache.tomcat.util.buf.CharChunk;
37 import org.apache.tomcat.util.buf.HexUtils;
38 import org.apache.tomcat.util.buf.MessageBytes;
39 import org.apache.tomcat.util.http.MimeHeaders;
40 import org.apache.tomcat.util.net.SSLSupport;
41 import org.apache.tomcat.util.threads.ThreadWithAttributes;
42
43 /**
44  * Handle messages related with basic request information.
45  *
46  * This object can handle the following incoming messages:
47  * - "FORWARD_REQUEST" input message ( sent when a request is passed from the
48  * web server )
49  * - "RECEIVE_BODY_CHUNK" input ( sent by container to pass more body, in
50  * response to GET_BODY_CHUNK )
51  *
52  * It can handle the following outgoing messages:
53  * - SEND_HEADERS. Pass the status code and headers.
54  * - SEND_BODY_CHUNK. Send a chunk of body
55  * - GET_BODY_CHUNK. Request a chunk of body data
56  * - END_RESPONSE. Notify the end of a request processing.
57  *
58  * @author Henri Gomez [hgomez@apache.org]
59  * @author Dan Milstein [danmil@shore.net]
60  * @author Keith Wannamaker [Keith@Wannamaker.org]
61  * @author Costin Manolache
62  */

63 public class HandlerRequest extends JkHandler
64 {
65     private static org.apache.commons.logging.Log log=
66         org.apache.commons.logging.LogFactory.getLog( HandlerRequest.class );
67
68     // XXX Will move to a registry system.
69

70     // Prefix codes for message types from server to container
71
public static final byte JK_AJP13_FORWARD_REQUEST = 2;
72         public static final byte JK_AJP13_SHUTDOWN = 7;
73         public static final byte JK_AJP13_PING_REQUEST = 8;
74         public static final byte JK_AJP13_CPING_REQUEST = 10;
75
76     // Prefix codes for message types from container to server
77
public static final byte JK_AJP13_SEND_BODY_CHUNK = 3;
78     public static final byte JK_AJP13_SEND_HEADERS = 4;
79     public static final byte JK_AJP13_END_RESPONSE = 5;
80         public static final byte JK_AJP13_GET_BODY_CHUNK = 6;
81         public static final byte JK_AJP13_CPONG_REPLY = 9;
82     
83     // Integer codes for common response header strings
84
public static final int SC_RESP_CONTENT_TYPE = 0xA001;
85     public static final int SC_RESP_CONTENT_LANGUAGE = 0xA002;
86     public static final int SC_RESP_CONTENT_LENGTH = 0xA003;
87     public static final int SC_RESP_DATE = 0xA004;
88     public static final int SC_RESP_LAST_MODIFIED = 0xA005;
89     public static final int SC_RESP_LOCATION = 0xA006;
90     public static final int SC_RESP_SET_COOKIE = 0xA007;
91     public static final int SC_RESP_SET_COOKIE2 = 0xA008;
92     public static final int SC_RESP_SERVLET_ENGINE = 0xA009;
93     public static final int SC_RESP_STATUS = 0xA00A;
94     public static final int SC_RESP_WWW_AUTHENTICATE = 0xA00B;
95         
96     // Integer codes for common (optional) request attribute names
97
public static final byte SC_A_CONTEXT = 1; // XXX Unused
98
public static final byte SC_A_SERVLET_PATH = 2; // XXX Unused
99
public static final byte SC_A_REMOTE_USER = 3;
100     public static final byte SC_A_AUTH_TYPE = 4;
101     public static final byte SC_A_QUERY_STRING = 5;
102     public static final byte SC_A_JVM_ROUTE = 6;
103     public static final byte SC_A_SSL_CERT = 7;
104     public static final byte SC_A_SSL_CIPHER = 8;
105     public static final byte SC_A_SSL_SESSION = 9;
106     public static final byte SC_A_SSL_KEYSIZE = 11;
107     public static final byte SC_A_SECRET = 12;
108     public static final byte SC_A_STORED_METHOD = 13;
109
110     // Used for attributes which are not in the list above
111
public static final byte SC_A_REQ_ATTRIBUTE = 10;
112
113     // Terminates list of attributes
114
public static final byte SC_A_ARE_DONE = (byte)0xFF;
115     
116     // Translates integer codes to names of HTTP methods
117
public static final String JavaDoc []methodTransArray = {
118         "OPTIONS",
119         "GET",
120         "HEAD",
121         "POST",
122         "PUT",
123         "DELETE",
124         "TRACE",
125         "PROPFIND",
126         "PROPPATCH",
127         "MKCOL",
128         "COPY",
129         "MOVE",
130         "LOCK",
131         "UNLOCK",
132         "ACL",
133         "REPORT",
134         "VERSION-CONTROL",
135         "CHECKIN",
136         "CHECKOUT",
137         "UNCHECKOUT",
138         "SEARCH",
139         "MKWORKSPACE",
140         "UPDATE",
141         "LABEL",
142         "MERGE",
143         "BASELINE-CONTROL",
144         "MKACTIVITY"
145     };
146     public static final int SC_M_JK_STORED = (byte) 0xFF;
147     
148     // id's for common request headers
149
public static final int SC_REQ_ACCEPT = 1;
150     public static final int SC_REQ_ACCEPT_CHARSET = 2;
151     public static final int SC_REQ_ACCEPT_ENCODING = 3;
152     public static final int SC_REQ_ACCEPT_LANGUAGE = 4;
153     public static final int SC_REQ_AUTHORIZATION = 5;
154     public static final int SC_REQ_CONNECTION = 6;
155     public static final int SC_REQ_CONTENT_TYPE = 7;
156     public static final int SC_REQ_CONTENT_LENGTH = 8;
157     public static final int SC_REQ_COOKIE = 9;
158     public static final int SC_REQ_COOKIE2 = 10;
159     public static final int SC_REQ_HOST = 11;
160     public static final int SC_REQ_PRAGMA = 12;
161     public static final int SC_REQ_REFERER = 13;
162     public static final int SC_REQ_USER_AGENT = 14;
163     // AJP14 new header
164
public static final byte SC_A_SSL_KEY_SIZE = 11; // XXX ???
165

166     // Translates integer codes to request header names
167
public static final String JavaDoc []headerTransArray = {
168         "accept",
169         "accept-charset",
170         "accept-encoding",
171         "accept-language",
172         "authorization",
173         "connection",
174         "content-type",
175         "content-length",
176         "cookie",
177         "cookie2",
178         "host",
179         "pragma",
180         "referer",
181         "user-agent"
182     };
183
184     /*
185      * Note for Host parsing.
186      */

187     public static final int HOSTBUFFER = 10;
188
189     /**
190      * Thread lock.
191      */

192     private static Object JavaDoc lock = new Object JavaDoc();
193
194     HandlerDispatch dispatch;
195     String JavaDoc ajpidDir="conf";
196     
197
198     public HandlerRequest()
199     {
200     }
201
202     public void init() {
203         dispatch=(HandlerDispatch)wEnv.getHandler( "dispatch" );
204         if( dispatch != null ) {
205             // register incoming message handlers
206
dispatch.registerMessageType( JK_AJP13_FORWARD_REQUEST,
207                                           "JK_AJP13_FORWARD_REQUEST",
208                                           this, null); // 2
209

210             dispatch.registerMessageType( JK_AJP13_SHUTDOWN,
211                                           "JK_AJP13_SHUTDOWN",
212                                           this, null); // 7
213

214             dispatch.registerMessageType( JK_AJP13_CPING_REQUEST,
215                                           "JK_AJP13_CPING_REQUEST",
216                                            this, null); // 10
217
dispatch.registerMessageType( HANDLE_THREAD_END,
218                                          "HANDLE_THREAD_END",
219                                          this, null);
220             // register outgoing messages handler
221
dispatch.registerMessageType( JK_AJP13_SEND_BODY_CHUNK, // 3
222
"JK_AJP13_SEND_BODY_CHUNK",
223                                           this,null );
224         }
225
226         bodyNote=wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "jkInputStream" );
227         tmpBufNote=wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "tmpBuf" );
228         secretNote=wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "secret" );
229
230         if( next==null )
231             next=wEnv.getHandler( "container" );
232         if( log.isDebugEnabled() )
233             log.debug( "Container handler " + next + " " + next.getName() +
234                        " " + next.getClass().getName());
235
236         // should happen on start()
237
generateAjp13Id();
238     }
239
240     public void setSecret( String JavaDoc s ) {
241         requiredSecret=s;
242     }
243
244     public void setUseSecret( boolean b ) {
245         requiredSecret=Double.toString(Math.random());
246     }
247
248     public void setDecodedUri( boolean b ) {
249         decoded=b;
250     }
251
252     public boolean isTomcatAuthentication() {
253         return tomcatAuthentication;
254     }
255
256     public void setShutdownEnabled(boolean se) {
257         shutdownEnabled = se;
258     }
259
260     public boolean getShutdownEnabled() {
261         return shutdownEnabled;
262     }
263
264     public void setTomcatAuthentication(boolean newTomcatAuthentication) {
265         tomcatAuthentication = newTomcatAuthentication;
266     }
267     
268     public void setAjpidDir( String JavaDoc path ) {
269         if( "".equals( path ) ) path=null;
270         ajpidDir=path;
271     }
272
273     /**
274      * Set the flag to tell if we JMX register requests.
275      */

276     public void setRegisterRequests(boolean srr) {
277         registerRequests = srr;
278     }
279
280     /**
281      * Get the flag to tell if we JMX register requests.
282      */

283     public boolean getRegisterRequests() {
284         return registerRequests;
285     }
286
287     // -------------------- Ajp13.id --------------------
288

289     private void generateAjp13Id() {
290         int portInt=8009; // tcpCon.getPort();
291
InetAddress JavaDoc address=null; // tcpCon.getAddress();
292

293         if( requiredSecret == null )
294             return;
295         
296         File JavaDoc f1=new File JavaDoc( wEnv.getJkHome() );
297         File JavaDoc f2=new File JavaDoc( f1, "conf" );
298         
299         if( ! f2.exists() ) {
300             log.error( "No conf dir for ajp13.id " + f2 );
301             return;
302         }
303         
304         File JavaDoc sf=new File JavaDoc( f2, "ajp13.id");
305         
306         if( log.isDebugEnabled())
307             log.debug( "Using stop file: "+sf);
308
309         try {
310             Properties JavaDoc props=new Properties JavaDoc();
311
312             props.put( "port", Integer.toString( portInt ));
313             if( address!=null ) {
314                 props.put( "address", address.getHostAddress() );
315             }
316             if( requiredSecret !=null ) {
317                 props.put( "secret", requiredSecret );
318             }
319
320             FileOutputStream JavaDoc stopF=new FileOutputStream JavaDoc( sf );
321             props.store( stopF, "Automatically generated, don't edit" );
322         } catch( IOException JavaDoc ex ) {
323             if(log.isDebugEnabled())
324                 log.debug( "Can't create stop file: "+sf,ex );
325         }
326     }
327     
328     // -------------------- Incoming message --------------------
329
String JavaDoc requiredSecret=null;
330     int bodyNote;
331     int tmpBufNote;
332     int secretNote;
333
334     boolean decoded=true;
335     boolean tomcatAuthentication=true;
336     boolean registerRequests=true;
337     boolean shutdownEnabled=false;
338     
339     public int invoke(Msg msg, MsgContext ep )
340         throws IOException JavaDoc
341     {
342         int type=msg.getByte();
343         ThreadWithAttributes twa = null;
344         if (Thread.currentThread() instanceof ThreadWithAttributes) {
345             twa = (ThreadWithAttributes) Thread.currentThread();
346         }
347         Object JavaDoc control=ep.getControl();
348
349         MessageBytes tmpMB=(MessageBytes)ep.getNote( tmpBufNote );
350         if( tmpMB==null ) {
351             tmpMB= MessageBytes.newInstance();
352             ep.setNote( tmpBufNote, tmpMB);
353         }
354         if( log.isDebugEnabled() )
355             log.debug( "Handling " + type );
356         
357         switch( type ) {
358         case JK_AJP13_FORWARD_REQUEST:
359             try {
360                 if (twa != null) {
361                     twa.setCurrentStage(control, "JkDecode");
362                 }
363                 decodeRequest( msg, ep, tmpMB );
364                 if (twa != null) {
365                     twa.setCurrentStage(control, "JkService");
366                     twa.setParam(control,
367                                  ((Request)ep.getRequest()).unparsedURI());
368                 }
369             } catch( Exception JavaDoc ex ) {
370                 log.error( "Error decoding request ", ex );
371                 msg.dump( "Incomming message");
372                 return ERROR;
373             }
374
375             if( requiredSecret != null ) {
376                 String JavaDoc epSecret=(String JavaDoc)ep.getNote( secretNote );
377                 if( epSecret==null || ! requiredSecret.equals( epSecret ) )
378                     return ERROR;
379             }
380             /* XXX it should be computed from request, by workerEnv */
381             if(log.isDebugEnabled() )
382                 log.debug("Calling next " + next.getName() + " " +
383                   next.getClass().getName());
384
385             int err= next.invoke( msg, ep );
386             if (twa != null) {
387                 twa.setCurrentStage(control, "JkDone");
388             }
389
390             if( log.isDebugEnabled() )
391                 log.debug( "Invoke returned " + err );
392             return err;
393         case JK_AJP13_SHUTDOWN:
394             String JavaDoc epSecret=null;
395             if( msg.getLen() > 3 ) {
396                 // we have a secret
397
msg.getBytes( tmpMB );
398                 epSecret=tmpMB.toString();
399             }
400             
401             if( requiredSecret != null &&
402                 requiredSecret.equals( epSecret ) ) {
403                 if( log.isDebugEnabled() )
404                     log.debug("Received wrong secret, no shutdown ");
405                 return ERROR;
406             }
407
408             // XXX add isSameAddress check
409
JkChannel ch=ep.getSource();
410         if( !ch.isSameAddress(ep) ) {
411         log.error("Shutdown request not from 'same address' ");
412         return ERROR;
413             }
414
415             if( !shutdownEnabled ) {
416                 log.warn("Ignoring shutdown request: shutdown not enabled");
417                 return ERROR;
418             }
419             // forward to the default handler - it'll do the shutdown
420
checkRequest(ep);
421             next.invoke( msg, ep );
422
423             if(log.isInfoEnabled())
424                 log.info("Exiting");
425             System.exit(0);
426             
427             return OK;
428
429             // We got a PING REQUEST, quickly respond with a PONG
430
case JK_AJP13_CPING_REQUEST:
431             msg.reset();
432             msg.appendByte(JK_AJP13_CPONG_REPLY);
433             ep.setType( JkHandler.HANDLE_SEND_PACKET );
434             ep.getSource().send( msg, ep );
435         return OK;
436
437         case HANDLE_THREAD_END:
438             return OK;
439
440         default:
441             if(log.isInfoEnabled())
442                 log.info("Unknown message " + type);
443         }
444
445         return OK;
446     }
447
448     static int count = 0;
449
450     private Request checkRequest(MsgContext ep) {
451         Request req=(Request)ep.getRequest();
452         if( req==null ) {
453             req=new Request();
454             Response res=new Response();
455             req.setResponse(res);
456             ep.setRequest( req );
457             if( registerRequests ) {
458                 synchronized(lock) {
459                     ep.getSource().registerRequest(req, ep, count++);
460                 }
461             }
462         }
463         return req;
464     }
465
466     private int decodeRequest( Msg msg, MsgContext ep, MessageBytes tmpMB )
467         throws IOException JavaDoc
468     {
469         // FORWARD_REQUEST handler
470
Request req = checkRequest(ep);
471
472     RequestInfo rp = req.getRequestProcessor();
473     rp.setStage(Constants.STAGE_PARSE);
474         MessageBytes tmpMB2 = (MessageBytes)req.getNote(WorkerEnv.SSL_CERT_NOTE);
475         if(tmpMB2 != null) {
476             tmpMB2.recycle();
477         }
478         req.setStartTime(System.currentTimeMillis());
479         JkInputStream jkBody=(JkInputStream)ep.getNote( bodyNote );
480         if( jkBody==null ) {
481             jkBody=new JkInputStream();
482             jkBody.setMsgContext( ep );
483
484             ep.setNote( bodyNote, jkBody );
485         }
486
487         jkBody.recycle();
488         
489         // Translate the HTTP method code to a String.
490
byte methodCode = msg.getByte();
491         if (methodCode != SC_M_JK_STORED) {
492             String JavaDoc mName=methodTransArray[(int)methodCode - 1];
493             req.method().setString(mName);
494         }
495
496         msg.getBytes(req.protocol());
497         msg.getBytes(req.requestURI());
498
499         msg.getBytes(req.remoteAddr());
500         msg.getBytes(req.remoteHost());
501         msg.getBytes(req.localName());
502         req.setLocalPort(msg.getInt());
503
504         boolean isSSL = msg.getByte() != 0;
505         if( isSSL ) {
506             // XXX req.setSecure( true );
507
req.scheme().setString("https");
508         }
509
510         decodeHeaders( ep, msg, req, tmpMB );
511
512         decodeAttributes( ep, msg, req, tmpMB );
513
514     rp.setStage(Constants.STAGE_PREPARE);
515         MessageBytes valueMB = req.getMimeHeaders().getValue("host");
516         parseHost(valueMB, req);
517         // set cookies on request now that we have all headers
518
req.getCookies().setHeaders(req.getMimeHeaders());
519
520         // Check to see if there should be a body packet coming along
521
// immediately after
522
int cl=req.getContentLength();
523         if(cl > 0) {
524             jkBody.setContentLength( cl );
525             jkBody.receive();
526         }
527     
528         if (log.isTraceEnabled()) {
529             log.trace(req.toString());
530          }
531
532         return OK;
533     }
534         
535     private int decodeAttributes( MsgContext ep, Msg msg, Request req,
536                                   MessageBytes tmpMB) {
537         boolean moreAttr=true;
538
539         while( moreAttr ) {
540             byte attributeCode=msg.getByte();
541             if( attributeCode == SC_A_ARE_DONE )
542                 return 200;
543
544             /* Special case ( XXX in future API make it separate type !)
545              */

546             if( attributeCode == SC_A_SSL_KEY_SIZE ) {
547                 // Bug 1326: it's an Integer.
548
req.setAttribute(SSLSupport.KEY_SIZE_KEY,
549                                  new Integer JavaDoc( msg.getInt()));
550                //Integer.toString(msg.getInt()));
551
}
552
553             if( attributeCode == SC_A_REQ_ATTRIBUTE ) {
554                 // 2 strings ???...
555
msg.getBytes( tmpMB );
556                 String JavaDoc n=tmpMB.toString();
557                 msg.getBytes( tmpMB );
558                 String JavaDoc v=tmpMB.toString();
559                 req.setAttribute(n, v );
560             }
561
562
563             // 1 string attributes
564
switch(attributeCode) {
565             case SC_A_CONTEXT :
566                 msg.getBytes( tmpMB );
567                 // nothing
568
break;
569                 
570             case SC_A_SERVLET_PATH :
571                 msg.getBytes( tmpMB );
572                 // nothing
573
break;
574                 
575             case SC_A_REMOTE_USER :
576                 if( tomcatAuthentication ) {
577                     // ignore server
578
msg.getBytes( tmpMB );
579                 } else {
580                     msg.getBytes(req.getRemoteUser());
581                 }
582                 break;
583                 
584             case SC_A_AUTH_TYPE :
585                 if( tomcatAuthentication ) {
586                     // ignore server
587
msg.getBytes( tmpMB );
588                 } else {
589                     msg.getBytes(req.getAuthType());
590                 }
591                 break;
592                 
593             case SC_A_QUERY_STRING :
594                 msg.getBytes(req.queryString());
595                 break;
596                 
597             case SC_A_JVM_ROUTE :
598                 msg.getBytes(req.instanceId());
599                 break;
600                 
601             case SC_A_SSL_CERT :
602                 req.scheme().setString( "https" );
603                 // Transform the string into certificate.
604
MessageBytes tmpMB2 = (MessageBytes)req.getNote(WorkerEnv.SSL_CERT_NOTE);
605                 if(tmpMB2 == null) {
606                     tmpMB2 = MessageBytes.newInstance();
607                     req.setNote(WorkerEnv.SSL_CERT_NOTE, tmpMB2);
608                 }
609                 // SSL certificate extraction is costy, moved to JkCoyoteHandler
610
msg.getBytes(tmpMB2);
611                 break;
612                 
613             case SC_A_SSL_CIPHER :
614                 req.scheme().setString( "https" );
615                 msg.getBytes(tmpMB);
616                 req.setAttribute(SSLSupport.CIPHER_SUITE_KEY,
617                                  tmpMB.toString());
618                 break;
619                 
620             case SC_A_SSL_SESSION :
621                 req.scheme().setString( "https" );
622                 msg.getBytes(tmpMB);
623                 req.setAttribute(SSLSupport.SESSION_ID_KEY,
624                                   tmpMB.toString());
625                 break;
626                 
627             case SC_A_SECRET :
628                 msg.getBytes(tmpMB);
629                 String JavaDoc secret=tmpMB.toString();
630                 log.info("Secret: " + secret );
631                 // endpoint note
632
ep.setNote( secretNote, secret );
633                 break;
634                 
635             case SC_A_STORED_METHOD:
636                 msg.getBytes(req.method());
637                 break;
638                 
639             default:
640                 break; // ignore, we don't know about it - backward compat
641
}
642         }
643         return 200;
644     }
645     
646     private void decodeHeaders( MsgContext ep, Msg msg, Request req,
647                                 MessageBytes tmpMB ) {
648         // Decode headers
649
MimeHeaders headers = req.getMimeHeaders();
650
651         int hCount = msg.getInt();
652         for(int i = 0 ; i < hCount ; i++) {
653             String JavaDoc hName = null;
654
655             // Header names are encoded as either an integer code starting
656
// with 0xA0, or as a normal string (in which case the first
657
// two bytes are the length).
658
int isc = msg.peekInt();
659             int hId = isc & 0xFF;
660
661             MessageBytes vMB=null;
662             isc &= 0xFF00;
663             if(0xA000 == isc) {
664                 msg.getInt(); // To advance the read position
665
hName = headerTransArray[hId - 1];
666                 vMB=headers.addValue( hName );
667             } else {
668                 // reset hId -- if the header currently being read
669
// happens to be 7 or 8 bytes long, the code below
670
// will think it's the content-type header or the
671
// content-length header - SC_REQ_CONTENT_TYPE=7,
672
// SC_REQ_CONTENT_LENGTH=8 - leading to unexpected
673
// behaviour. see bug 5861 for more information.
674
hId = -1;
675                 msg.getBytes( tmpMB );
676                 ByteChunk bc=tmpMB.getByteChunk();
677                 vMB=headers.addValue( bc.getBuffer(),
678                                       bc.getStart(), bc.getLength() );
679             }
680
681             msg.getBytes(vMB);
682
683             if (hId == SC_REQ_CONTENT_LENGTH ||
684                 (hId == -1 && tmpMB.equalsIgnoreCase("Content-Length"))) {
685                 // just read the content-length header, so set it
686
req.setContentLength( vMB.getInt() );
687             } else if (hId == SC_REQ_CONTENT_TYPE ||
688                 (hId == -1 && tmpMB.equalsIgnoreCase("Content-Type"))) {
689                 // just read the content-type header, so set it
690
ByteChunk bchunk = vMB.getByteChunk();
691                 req.contentType().setBytes(bchunk.getBytes(),
692                                            bchunk.getOffset(),
693                                            bchunk.getLength());
694             }
695         }
696     }
697
698     /**
699      * Parse host.
700      */

701     private void parseHost(MessageBytes valueMB, Request request)
702         throws IOException JavaDoc {
703
704         if (valueMB == null || valueMB.isNull()) {
705             // HTTP/1.0
706
// Default is what the socket tells us. Overriden if a host is
707
// found/parsed
708
request.setServerPort(request.getLocalPort());
709             request.serverName().duplicate(request.localName());
710             return;
711         }
712
713         ByteChunk valueBC = valueMB.getByteChunk();
714         byte[] valueB = valueBC.getBytes();
715         int valueL = valueBC.getLength();
716         int valueS = valueBC.getStart();
717         int colonPos = -1;
718         CharChunk hostNameC = (CharChunk)request.getNote(HOSTBUFFER);
719         if(hostNameC == null) {
720             hostNameC = new CharChunk(valueL);
721             request.setNote(HOSTBUFFER, hostNameC);
722         }
723         hostNameC.recycle();
724
725         boolean ipv6 = (valueB[valueS] == '[');
726         boolean bracketClosed = false;
727         for (int i = 0; i < valueL; i++) {
728             char b = (char) valueB[i + valueS];
729             hostNameC.append(b);
730             if (b == ']') {
731                 bracketClosed = true;
732             } else if (b == ':') {
733                 if (!ipv6 || bracketClosed) {
734                     colonPos = i;
735                     break;
736                 }
737             }
738         }
739
740         if (colonPos < 0) {
741             if (request.scheme().equalsIgnoreCase("https")) {
742                 // 80 - Default HTTTP port
743
request.setServerPort(443);
744             } else {
745                 // 443 - Default HTTPS port
746
request.setServerPort(80);
747             }
748             request.serverName().setChars(hostNameC.getChars(),
749                                           hostNameC.getStart(),
750                                           hostNameC.getLength());
751         } else {
752
753             request.serverName().setChars(hostNameC.getChars(),
754                                           hostNameC.getStart(), colonPos);
755
756             int port = 0;
757             int mult = 1;
758             for (int i = valueL - 1; i > colonPos; i--) {
759                 int charValue = HexUtils.DEC[(int) valueB[i + valueS]];
760                 if (charValue == -1) {
761                     // Invalid character
762
throw new CharConversionException JavaDoc("Invalid char in port: " + valueB[i + valueS]);
763                 }
764                 port = port + (charValue * mult);
765                 mult = 10 * mult;
766             }
767             request.setServerPort(port);
768
769         }
770
771     }
772
773 }
774
Popular Tags