KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ajp > RequestHandler


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.ajp;
18
19 import java.io.ByteArrayInputStream JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.security.cert.CertificateFactory JavaDoc;
22 import java.security.cert.X509Certificate JavaDoc;
23
24 import org.apache.tomcat.util.buf.ByteChunk;
25 import org.apache.tomcat.util.buf.MessageBytes;
26 import org.apache.tomcat.util.http.BaseRequest;
27 import org.apache.tomcat.util.http.HttpMessages;
28 import org.apache.tomcat.util.http.MimeHeaders;
29
30
31 /**
32  * Handle messages related with basic request information.
33  *
34  * This object can handle the following incoming messages:
35  * - "FORWARD_REQUEST" input message ( sent when a request is passed from the web server )
36  * - "PING REQUEST" input message (sent by the web server to determine if tomcat is not frozen,
37  * a PONG REPLY will be sent back)
38  * - "RECEIVE_BODY_CHUNK" input ( sent by container to pass more body, in response to GET_BODY_CHUNK )
39  *
40  * It can handle the following outgoing messages:
41  * - SEND_HEADERS. Pass the status code and headers.
42  * - SEND_BODY_CHUNK. Send a chunk of body
43  * - GET_BODY_CHUNK. Request a chunk of body data
44  * - END_RESPONSE. Notify the end of a request processing.
45  *
46  * @author Henri Gomez [hgomez@apache.org]
47  * @author Dan Milstein [danmil@shore.net]
48  * @author Keith Wannamaker [Keith@Wannamaker.org]
49  * @author Costin Manolache
50  */

51 public class RequestHandler extends AjpHandler
52 {
53     // XXX Will move to a registry system.
54

55     // Prefix codes for message types from server to container
56
public static final byte JK_AJP13_FORWARD_REQUEST = 2;
57     public static final byte JK_AJP13_SHUTDOWN = 7;
58     public static final byte JK_AJP13_PING_REQUEST = 8;
59     public static final byte JK_AJP13_CPING_REQUEST = 10;
60
61     // Prefix codes for message types from container to server
62
public static final byte JK_AJP13_SEND_BODY_CHUNK = 3;
63     public static final byte JK_AJP13_SEND_HEADERS = 4;
64     public static final byte JK_AJP13_END_RESPONSE = 5;
65     public static final byte JK_AJP13_GET_BODY_CHUNK = 6;
66     public static final byte JK_AJP13_CPONG_REPLY = 9;
67     
68     // Integer codes for common response header strings
69
public static final int SC_RESP_CONTENT_TYPE = 0xA001;
70     public static final int SC_RESP_CONTENT_LANGUAGE = 0xA002;
71     public static final int SC_RESP_CONTENT_LENGTH = 0xA003;
72     public static final int SC_RESP_DATE = 0xA004;
73     public static final int SC_RESP_LAST_MODIFIED = 0xA005;
74     public static final int SC_RESP_LOCATION = 0xA006;
75     public static final int SC_RESP_SET_COOKIE = 0xA007;
76     public static final int SC_RESP_SET_COOKIE2 = 0xA008;
77     public static final int SC_RESP_SERVLET_ENGINE = 0xA009;
78     public static final int SC_RESP_STATUS = 0xA00A;
79     public static final int SC_RESP_WWW_AUTHENTICATE = 0xA00B;
80     
81     // Integer codes for common (optional) request attribute names
82
public static final byte SC_A_CONTEXT = 1; // XXX Unused
83
public static final byte SC_A_SERVLET_PATH = 2; // XXX Unused
84
public static final byte SC_A_REMOTE_USER = 3;
85     public static final byte SC_A_AUTH_TYPE = 4;
86     public static final byte SC_A_QUERY_STRING = 5;
87     public static final byte SC_A_JVM_ROUTE = 6;
88     public static final byte SC_A_SSL_CERT = 7;
89     public static final byte SC_A_SSL_CIPHER = 8;
90     public static final byte SC_A_SSL_SESSION = 9;
91     public static final byte SC_A_SSL_KEY_SIZE = 11; // ajp14 originally, now in ajp13 with jk 1.2/2.0
92
public static final byte SC_A_SECRET = 12;
93     public static final byte SC_A_STORED_METHOD = 13;
94
95     // Used for attributes which are not in the list above
96
public static final byte SC_A_REQ_ATTRIBUTE = 10;
97
98     // Terminates list of attributes
99
public static final byte SC_A_ARE_DONE = (byte)0xFF;
100     
101     // Translates integer codes to names of HTTP methods
102
public static final String JavaDoc []methodTransArray = {
103         "OPTIONS",
104         "GET",
105         "HEAD",
106         "POST",
107         "PUT",
108         "DELETE",
109         "TRACE",
110         "PROPFIND",
111         "PROPPATCH",
112         "MKCOL",
113         "COPY",
114         "MOVE",
115         "LOCK",
116         "UNLOCK",
117         "ACL",
118         "REPORT",
119         "VERSION-CONTROL",
120         "CHECKIN",
121         "CHECKOUT",
122         "UNCHECKOUT",
123         "SEARCH",
124         "MKWORKSPACE",
125         "UPDATE",
126         "LABEL",
127         "MERGE",
128         "BASELINE-CONTROL",
129         "MKACTIVITY"
130     };
131     public static final int SC_M_JK_STORED = (byte) 0xFF;
132
133     
134     // id's for common request headers
135
public static final int SC_REQ_ACCEPT = 1;
136     public static final int SC_REQ_ACCEPT_CHARSET = 2;
137     public static final int SC_REQ_ACCEPT_ENCODING = 3;
138     public static final int SC_REQ_ACCEPT_LANGUAGE = 4;
139     public static final int SC_REQ_AUTHORIZATION = 5;
140     public static final int SC_REQ_CONNECTION = 6;
141     public static final int SC_REQ_CONTENT_TYPE = 7;
142     public static final int SC_REQ_CONTENT_LENGTH = 8;
143     public static final int SC_REQ_COOKIE = 9;
144     public static final int SC_REQ_COOKIE2 = 10;
145     public static final int SC_REQ_HOST = 11;
146     public static final int SC_REQ_PRAGMA = 12;
147     public static final int SC_REQ_REFERER = 13;
148     public static final int SC_REQ_USER_AGENT = 14;
149
150     // Translates integer codes to request header names
151
public static final String JavaDoc []headerTransArray = {
152         "accept",
153         "accept-charset",
154         "accept-encoding",
155         "accept-language",
156         "authorization",
157         "connection",
158         "content-type",
159         "content-length",
160         "cookie",
161         "cookie2",
162         "host",
163         "pragma",
164         "referer",
165         "user-agent"
166     };
167
168     public RequestHandler()
169     {
170     }
171
172     public void init( Ajp13 ajp14 ) {
173     // register incoming message handlers
174
ajp14.registerMessageType( JK_AJP13_FORWARD_REQUEST,
175                    "JK_AJP13_FORWARD_REQUEST",
176                    this, null); // 2
177
// register outgoing messages handler
178
ajp14.registerMessageType( JK_AJP13_SEND_BODY_CHUNK, // 3
179
"JK_AJP13_SEND_BODY_CHUNK",
180                    this,null );
181     ajp14.registerMessageType( JK_AJP13_SEND_HEADERS, // 4
182
"JK_AJP13_SEND_HEADERS",
183                    this,null );
184     ajp14.registerMessageType( JK_AJP13_END_RESPONSE, // 5
185
"JK_AJP13_END_RESPONSE",
186                    this,null );
187     ajp14.registerMessageType( JK_AJP13_GET_BODY_CHUNK, // 6
188
"JK_AJP13_GET_BODY_CHUNK",
189                    this, null );
190     ajp14.registerMessageType( JK_AJP13_CPING_REQUEST,
191                    "JK_AJP13_PING_REQUEST",
192                    this, null); // 10
193
ajp14.registerMessageType( JK_AJP13_CPONG_REPLY,
194                    "JK_AJP13_PONG_REPLY",
195                    this, null); // 9
196
}
197     
198     /**
199      * Send a CPONG REPLY to web server to its CPING request
200      *
201      * @param ch the Ajp13 channel
202      * @param outBuf the Ajp13Packet output packet to use
203      */

204     public int sendCPong(Ajp13 ch, Ajp13Packet outBuf)
205     {
206         outBuf.reset();
207         outBuf.appendByte(JK_AJP13_CPONG_REPLY);
208         
209         try
210         {
211             ch.send(outBuf);
212         }
213         catch (IOException JavaDoc ioe)
214         {
215             log("can't send pong reply");
216         }
217         
218         return (999); // success but no need to process farther
219
}
220     
221     // -------------------- Incoming message --------------------
222
public int handleAjpMessage( int type, Ajp13 channel,
223                  Ajp13Packet ajp, BaseRequest req )
224     throws IOException JavaDoc
225     {
226     switch( type ) {
227     case RequestHandler.JK_AJP13_FORWARD_REQUEST:
228         return decodeRequest(channel, channel.hBuf, req );
229         
230     default:
231         return UNKNOWN;
232     }
233     }
234     
235     /**
236      * Parse a FORWARD_REQUEST packet from the web server and store its
237      * properties in the passed-in request object.
238      *
239      * @param req An empty (newly-recycled) request object.
240      * @param msg Holds the packet which has just been sent by the web
241      * server, with its read position just past the packet header (which in
242      * this case includes the prefix code for FORWARD_REQUEST).
243      *
244      * @return 200 in case of a successful decoduing, 500 in case of error.
245      */

246     protected int decodeRequest(Ajp13 ch, Ajp13Packet msg, BaseRequest req)
247         throws IOException JavaDoc
248     {
249         
250         if (debug > 0) {
251             log("decodeRequest()");
252         }
253
254     // XXX Awful return values
255

256         boolean isSSL = false;
257
258         // Translate the HTTP method code to a String.
259
byte methodCode = msg.getByte();
260         if (methodCode != SC_M_JK_STORED)
261           req.method().setString(methodTransArray[(int)methodCode - 1]);
262
263         msg.getMessageBytes(req.protocol());
264         msg.getMessageBytes(req.requestURI());
265
266         msg.getMessageBytes(req.remoteAddr());
267         msg.getMessageBytes(req.remoteHost());
268         msg.getMessageBytes(req.serverName());
269         req.setServerPort(msg.getInt());
270
271     isSSL = msg.getBool();
272
273     // Decode headers
274
MimeHeaders headers = req.headers();
275     int hCount = msg.getInt();
276         for(int i = 0 ; i < hCount ; i++) {
277             String JavaDoc hName = null;
278
279         // Header names are encoded as either an integer code starting
280
// with 0xA0, or as a normal string (in which case the first
281
// two bytes are the length).
282
int isc = msg.peekInt();
283             int hId = isc & 0xFF;
284
285         MessageBytes vMB=null;
286             isc &= 0xFF00;
287             if(0xA000 == isc) {
288                 //
289
// header name is encoded as an int
290
//
291
msg.getInt(); // To advance the read position
292
hName = headerTransArray[hId - 1];
293         vMB= headers.addValue(hName);
294                 msg.getMessageBytes(vMB);
295
296                 if (hId == SC_REQ_CONTENT_LENGTH) {
297                     // just read content-length header
298
int contentLength = (vMB == null) ? -1 : vMB.getInt();
299                     req.setContentLength(contentLength);
300                 } else if (hId == SC_REQ_CONTENT_TYPE) {
301                     // just read content-type header
302
ByteChunk bchunk = vMB.getByteChunk();
303                     req.contentType().setBytes(bchunk.getBytes(),
304                                                bchunk.getOffset(),
305                                                bchunk.getLength());
306                 } else if (hId == SC_REQ_AUTHORIZATION) {
307                     ByteChunk bchunk = vMB.getByteChunk();
308                     req.authorization().setBytes(bchunk.getBytes(),
309                                                bchunk.getOffset(),
310                                                bchunk.getLength());
311                 }
312             } else {
313                 //
314
// header name is a string
315
//
316
// XXX Not very elegant
317
vMB = msg.addHeader(headers);
318         if (vMB == null) {
319                     return 500; // wrong packet
320
}
321                 msg.getMessageBytes(vMB);
322             }
323         }
324
325     byte attributeCode;
326         for(attributeCode = msg.getByte() ;
327             attributeCode != SC_A_ARE_DONE ;
328             attributeCode = msg.getByte()) {
329             switch(attributeCode) {
330         case SC_A_CONTEXT :
331                 break;
332         
333         case SC_A_SERVLET_PATH :
334                 break;
335         
336         case SC_A_REMOTE_USER :
337                 msg.getMessageBytes(req.remoteUser());
338                 break;
339         
340         case SC_A_AUTH_TYPE :
341                 msg.getMessageBytes(req.authType());
342                 break;
343         
344         case SC_A_QUERY_STRING :
345         msg.getMessageBytes(req.queryString());
346                 break;
347         
348         case SC_A_JVM_ROUTE :
349                 msg.getMessageBytes(req.jvmRoute());
350                 break;
351         
352         case SC_A_SSL_CERT :
353         isSSL = true;
354                 // Transform the string into certificate.
355
String JavaDoc certString = msg.getString();
356                 byte[] certData = certString.getBytes();
357                 ByteArrayInputStream JavaDoc bais = new ByteArrayInputStream JavaDoc(certData);
358  
359                 // Fill the first element.
360
X509Certificate JavaDoc jsseCerts[] = null;
361                 try {
362                     CertificateFactory JavaDoc cf =
363                         CertificateFactory.getInstance("X.509");
364                     X509Certificate JavaDoc cert = (X509Certificate JavaDoc)
365                         cf.generateCertificate(bais);
366                     jsseCerts = new X509Certificate JavaDoc[1];
367                     jsseCerts[0] = cert;
368                 } catch(java.security.cert.CertificateException JavaDoc e) {
369                     log("Certificate convertion failed" + e );
370                 }
371  
372                 req.setAttribute("javax.servlet.request.X509Certificate",
373                                  jsseCerts);
374                 break;
375         
376         case SC_A_SSL_CIPHER :
377         isSSL = true;
378         req.setAttribute("javax.servlet.request.cipher_suite",
379                  msg.getString());
380                 break;
381         
382         case SC_A_SECRET :
383                 // If a request has a secret attribute, set it on
384
// channel - it'll be visible to the caller ( Interceptor,
385
// Connector ) and it can check it against its settings before
386
// trusting us.
387
String JavaDoc secret=msg.getString();
388                 if(secret!=null) {
389                     ch.setSecret( secret );
390                 }
391                 break;
392         
393         case SC_A_SSL_SESSION :
394         isSSL = true;
395         req.setAttribute("javax.servlet.request.ssl_session",
396                   msg.getString());
397                 break;
398         
399         case SC_A_REQ_ATTRIBUTE :
400         req.setAttribute(msg.getString(),
401                  msg.getString());
402                 break;
403
404         case SC_A_SSL_KEY_SIZE: // Ajp13 !
405
isSSL = true;
406         req.setAttribute("javax.servlet.request.key_size",
407                  Integer.toString(msg.getInt()));
408         break;
409     
410         case SC_A_STORED_METHOD:
411                 req.method().setString(msg.getString());
412                 break;
413     
414         default:
415                 // Ignore. Assume a single-string value - we shouldn't
416
// allow anything else.
417
msg.getString();
418                 break;
419         }
420         }
421
422         if(isSSL) {
423             req.setScheme(req.SCHEME_HTTPS);
424             req.setSecure(true);
425         }
426
427         // set cookies on request now that we have all headers
428
req.cookies().setHeaders(req.headers());
429
430     // Check to see if there should be a body packet coming along
431
// immediately after
432
if(req.getContentLength() > 0) {
433
434         /* Read present data */
435         int err = ch.receive(ch.inBuf);
436             if(err < 0) {
437                 return 500;
438         }
439         
440         ch.blen = ch.inBuf.peekInt();
441         ch.pos = 0;
442         ch.inBuf.getBytes(ch.bodyBuff);
443         }
444     
445         if (debug > 5) {
446             log(req.toString());
447         }
448
449         return 200; // Success
450
}
451     
452
453     // -------------------- Messages from container to server ------------------
454

455     /**
456      * Send the HTTP headers back to the web server and on to the browser.
457      *
458      * @param status The HTTP status code to send.
459      * @param statusMessage the HTTP status message to send.
460      * @param headers The set of all headers.
461      */

462     public void sendHeaders(Ajp13 ch, Ajp13Packet outBuf,
463                 int status, String JavaDoc statusMessage,
464                             MimeHeaders headers)
465         throws IOException JavaDoc
466     {
467     // XXX if more headers that MAX_SIZE, send 2 packets!
468
if( statusMessage==null ) statusMessage=HttpMessages.getMessage(status);
469     outBuf.reset();
470         outBuf.appendByte(JK_AJP13_SEND_HEADERS);
471         outBuf.appendInt(status);
472     
473     outBuf.appendString(statusMessage);
474         
475     int numHeaders = headers.size();
476         outBuf.appendInt(numHeaders);
477         
478     for( int i=0 ; i < numHeaders ; i++ ) {
479         String JavaDoc headerName = headers.getName(i).toString();
480         int sc = headerNameToSc(headerName);
481             if(-1 != sc) {
482                 outBuf.appendInt(sc);
483             } else {
484                 outBuf.appendString(headerName);
485             }
486             outBuf.appendString(headers.getValue(i).toString() );
487         }
488
489         outBuf.end();
490         ch.send(outBuf);
491     }
492
493
494     /**
495      * Signal the web server that the servlet has finished handling this
496      * request, and that the connection can be reused.
497      */

498     public void finish(Ajp13 ch, Ajp13Packet outBuf) throws IOException JavaDoc {
499         if (debug > 0) log("finish()");
500
501     outBuf.reset();
502         outBuf.appendByte(JK_AJP13_END_RESPONSE);
503         outBuf.appendBool(true); // Reuse this connection
504
outBuf.end();
505         ch.send(outBuf);
506     }
507
508     /**
509      * Send a chunk of response body data to the web server and on to the
510      * browser.
511      *
512      * @param b A huffer of bytes to send.
513      * @param off The offset into the buffer from which to start sending.
514      * @param len The number of bytes to send.
515      */

516     public void doWrite(Ajp13 ch, Ajp13Packet outBuf,
517             byte b[], int off, int len)
518     throws IOException JavaDoc
519     {
520         if (debug > 0) log("doWrite(byte[], " + off + ", " + len + ")");
521
522     int sent = 0;
523     while(sent < len) {
524         int to_send = len - sent;
525         to_send = to_send > Ajp13.MAX_SEND_SIZE ? Ajp13.MAX_SEND_SIZE : to_send;
526
527         outBuf.reset();
528         outBuf.appendByte(JK_AJP13_SEND_BODY_CHUNK);
529         outBuf.appendBytes(b, off + sent, to_send);
530         ch.send(outBuf);
531         sent += to_send;
532     }
533     }
534
535     // -------------------- Utils --------------------
536

537     /**
538      * Translate an HTTP response header name to an integer code if
539      * possible. Case is ignored.
540      *
541      * @param name The name of the response header to translate.
542      *
543      * @return The code for that header name, or -1 if no code exists.
544      */

545     protected int headerNameToSc(String JavaDoc name)
546     {
547         switch(name.charAt(0)) {
548     case 'c':
549     case 'C':
550         if(name.equalsIgnoreCase("Content-Type")) {
551         return SC_RESP_CONTENT_TYPE;
552         } else if(name.equalsIgnoreCase("Content-Language")) {
553         return SC_RESP_CONTENT_LANGUAGE;
554         } else if(name.equalsIgnoreCase("Content-Length")) {
555         return SC_RESP_CONTENT_LENGTH;
556         }
557             break;
558             
559     case 'd':
560     case 'D':
561         if(name.equalsIgnoreCase("Date")) {
562                 return SC_RESP_DATE;
563         }
564             break;
565             
566     case 'l':
567     case 'L':
568         if(name.equalsIgnoreCase("Last-Modified")) {
569         return SC_RESP_LAST_MODIFIED;
570         } else if(name.equalsIgnoreCase("Location")) {
571         return SC_RESP_LOCATION;
572         }
573             break;
574
575     case 's':
576     case 'S':
577         if(name.equalsIgnoreCase("Set-Cookie")) {
578         return SC_RESP_SET_COOKIE;
579         } else if(name.equalsIgnoreCase("Set-Cookie2")) {
580         return SC_RESP_SET_COOKIE2;
581         }
582             break;
583             
584     case 'w':
585     case 'W':
586         if(name.equalsIgnoreCase("WWW-Authenticate")) {
587         return SC_RESP_WWW_AUTHENTICATE;
588         }
589             break;
590         }
591         
592         return -1;
593     }
594    
595     private int debug=0;
596     private Logger logger = new Logger();
597     
598     public void setDebug(int debug) {
599         this.debug = debug;
600     }
601
602     public void setLogger(Logger l) {
603         this.logger = l;
604     }
605     
606     void log(String JavaDoc s) {
607         logger.log("[RequestHandler] " + s );
608     }
609
610     // ==================== Servlet Input Support =================
611
// XXX DEPRECATED
612

613     public int available(Ajp13 ch) throws IOException JavaDoc {
614         if (debug > 0) {
615             log("available()");
616         }
617
618         if (ch.pos >= ch.blen) {
619             if( ! refillReadBuffer(ch)) {
620         return 0;
621         }
622         }
623         return ch.blen - ch.pos;
624     }
625
626     /**
627      * Return the next byte of request body data (to a servlet).
628      */

629     public int doRead(Ajp13 ch) throws IOException JavaDoc
630     {
631         if (debug > 0) {
632             log("doRead()");
633         }
634
635         if(ch.pos >= ch.blen) {
636             if( ! refillReadBuffer(ch)) {
637         return -1;
638         }
639         }
640         return ch.bodyBuff[ch.pos++] & 0xFF;
641     }
642     
643     /**
644      * Store a chunk of request data into the passed-in byte buffer.
645      *
646      * @param b A buffer to fill with data from the request.
647      * @param off The offset in the buffer at which to start filling.
648      * @param len The number of bytes to copy into the buffer.
649      *
650      * @return The number of bytes actually copied into the buffer, or -1
651      * if the end of the stream has been reached.
652      */

653     public int doRead(Ajp13 ch, byte[] b, int off, int len) throws IOException JavaDoc
654     {
655         if (debug > 0) {
656             log("doRead(byte[], int, int)");
657         }
658
659     if(ch.pos >= ch.blen) {
660         if( ! refillReadBuffer(ch)) {
661         return -1;
662         }
663     }
664
665     if(ch.pos + len <= ch.blen) { // Fear the off by one error
666
// Sanity check b.length > off + len?
667
System.arraycopy(ch.bodyBuff, ch.pos, b, off, len);
668         ch.pos += len;
669         return len;
670     }
671
672     // Not enough data (blen < pos + len)
673
int toCopy = len;
674     while(toCopy > 0) {
675         int bytesRemaining = ch.blen - ch.pos;
676         if(bytesRemaining < 0)
677         bytesRemaining = 0;
678         int c = bytesRemaining < toCopy ? bytesRemaining : toCopy;
679             
680         System.arraycopy(ch.bodyBuff, ch.pos, b, off, c);
681
682         toCopy -= c;
683
684         off += c;
685         ch.pos += c; // In case we exactly consume the buffer
686

687         if(toCopy > 0)
688         if( ! refillReadBuffer(ch)) { // Resets blen and pos
689
break;
690         }
691     }
692
693     return len - toCopy;
694     }
695     
696     /**
697      * Get more request body data from the web server and store it in the
698      * internal buffer.
699      *
700      * @return true if there is more data, false if not.
701      */

702     public boolean refillReadBuffer(Ajp13 ch) throws IOException JavaDoc
703     {
704         if (debug > 0) {
705             log("refillReadBuffer()");
706         }
707
708     // If the server returns an empty packet, assume that that end of
709
// the stream has been reached (yuck -- fix protocol??).
710

711     // Why not use outBuf??
712
ch.inBuf.reset();
713     ch.inBuf.appendByte(JK_AJP13_GET_BODY_CHUNK);
714     ch.inBuf.appendInt(Ajp13.MAX_READ_SIZE);
715     ch.send(ch.inBuf);
716     
717     int err = ch.receive(ch.inBuf);
718         if(err < 0) {
719         throw new IOException JavaDoc();
720     }
721     
722         // check for empty packet, which means end of stream
723
if (ch.inBuf.getLen() == 0) {
724             if (debug > 0) {
725                 log("refillReadBuffer(): "
726                     + "received empty packet -> end of stream");
727             }
728             ch.blen = 0;
729             ch.pos = 0;
730             return false;
731         }
732
733         ch.blen = ch.inBuf.peekInt();
734         ch.pos = 0;
735         ch.inBuf.getBytes(ch.bodyBuff);
736
737     return (ch.blen > 0);
738     }
739
740     // ==================== Servlet Output Support =================
741

742     /**
743      */

744     public void beginSendHeaders(Ajp13 ch, Ajp13Packet outBuf,
745                  int status,
746                                  String JavaDoc statusMessage,
747                                  int numHeaders) throws IOException JavaDoc {
748
749         if (debug > 0) {
750             log("sendHeaders()");
751         }
752
753     // XXX if more headers that MAX_SIZE, send 2 packets!
754

755     outBuf.reset();
756         outBuf.appendByte(JK_AJP13_SEND_HEADERS);
757
758         if (debug > 0) {
759             log("status is: " + status +
760                        "(" + statusMessage + ")");
761         }
762
763         // set status code and message
764
outBuf.appendInt(status);
765         outBuf.appendString(statusMessage);
766
767         // write the number of headers...
768
outBuf.appendInt(numHeaders);
769     }
770
771     public void sendHeader(Ajp13Packet outBuf,
772                String JavaDoc name, String JavaDoc value)
773     throws IOException JavaDoc
774     {
775         int sc = headerNameToSc(name);
776         if(-1 != sc) {
777             outBuf.appendInt(sc);
778         } else {
779             outBuf.appendString(name);
780         }
781         outBuf.appendString(value);
782     }
783
784     public void endSendHeaders(Ajp13 ch, Ajp13Packet outBuf)
785     throws IOException JavaDoc
786     {
787         outBuf.end();
788         ch.send(outBuf);
789     }
790
791     /**
792      * Send the HTTP headers back to the web server and on to the browser.
793      *
794      * @param status The HTTP status code to send.
795      * @param headers The set of all headers.
796      */

797     public void sendHeaders(Ajp13 ch, Ajp13Packet outBuf,
798                 int status, MimeHeaders headers)
799         throws IOException JavaDoc
800     {
801         sendHeaders(ch, outBuf, status, HttpMessages.getMessage(status),
802                     headers);
803     }
804     
805
806  }
807
Popular Tags