Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/ajp/Ajp13.java


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.IOException;
20  import java.io.InputStream;
21  import java.io.OutputStream;
22  import java.net.Socket;
23  
24  import org.apache.tomcat.util.http.BaseRequest;
25  import org.apache.tomcat.util.http.HttpMessages;
26  import org.apache.tomcat.util.http.MimeHeaders;
27  
28  /**
29   * Represents a single, persistent connection between the web server and
30   * the servlet container.  Uses the Apache JServ Protocol version 1.3 for
31   * communication.  Because this protocal does not multiplex requests, this
32   * connection can only be associated with a single request-handling cycle
33   * at a time.<P>
34   *
35   * This class contains knowledge about how an individual packet is laid out
36   * (via the <CODE>Ajp13Packet</CODE> class), and also about the
37   * stages of communicaton between the server and the servlet container.  It
38   * translates from Tomcat's internal servlet support methods
39   * (e.g. doWrite) to the correct packets to send to the web server.
40   *
41   * @author Dan Milstein [danmil@shore.net]
42   * @author Keith Wannamaker [Keith@Wannamaker.org]
43   * @author Kevin Seguin [seguin@apache.org]
44   * @author Henri Gomez [hgomez@apache.org]
45   * @author Costin Manolache
46   */
47  public class Ajp13 {
48  
49      public static final int MAX_PACKET_SIZE=8192;
50      public static final int H_SIZE=4;  // Size of basic packet header
51  
52      public static final int  MAX_READ_SIZE = MAX_PACKET_SIZE - H_SIZE - 2;
53      public static final int  MAX_SEND_SIZE = MAX_PACKET_SIZE - H_SIZE - 4;
54  
55      // Error code for Ajp13
56      public static final int  JK_AJP13_BAD_HEADER        = -100;
57      public static final int  JK_AJP13_NO_HEADER         = -101;
58      public static final int  JK_AJP13_COMM_CLOSED       = -102;
59      public static final int  JK_AJP13_COMM_BROKEN       = -103;
60      public static final int  JK_AJP13_BAD_BODY          = -104;
61      public static final int  JK_AJP13_INCOMPLETE_BODY   = -105;
62  
63      // ============ Instance Properties ====================
64  
65      OutputStream out;
66      InputStream in;
67  
68      // Buffer used of output body and headers
69      public Ajp13Packet outBuf = new Ajp13Packet( MAX_PACKET_SIZE );
70      // Buffer used for input body
71      Ajp13Packet inBuf  = new Ajp13Packet( MAX_PACKET_SIZE );
72      // Buffer used for request head ( and headers )
73      Ajp13Packet hBuf=new Ajp13Packet( MAX_PACKET_SIZE );
74  
75      // Holds incoming reads of request body data (*not* header data)
76      byte []bodyBuff = new byte[MAX_READ_SIZE];
77      
78      int blen;  // Length of current chunk of body data in buffer
79      int pos;   // Current read position within that buffer
80  
81      boolean end_of_stream;  // true if we've received an empty packet
82      
83      // Required handler - essential request processing
84      public RequestHandler reqHandler;
85      // AJP14 - detect protocol,set communication parameters, login
86      // If no password is set, use only Ajp13 messaging
87      boolean backwardCompat=true;
88      boolean logged=false;
89      String secret=null;
90      
91      public Ajp13() {
92    super();
93    initBuf();
94          reqHandler=new RequestHandler();
95    reqHandler.init( this );
96      }
97  
98      public Ajp13(RequestHandler reqHandler ) {
99    super();
100   initBuf();
101         this.reqHandler=reqHandler;
102   reqHandler.init( this );
103     }
104 
105     /** Will be overriden
106      */
107     public void initBuf() {
108   outBuf = new Ajp13Packet( MAX_PACKET_SIZE );
109   inBuf  = new Ajp13Packet( MAX_PACKET_SIZE );
110   hBuf=new Ajp13Packet( MAX_PACKET_SIZE );
111     }
112     
113     public void recycle() {
114         if (debug > 0) {
115             logger.log("recycle()");
116         }
117 
118         // This is a touch cargo-cultish, but I think wise.
119         blen = 0; 
120         pos = 0;
121         end_of_stream = false;
122         logged=false;
123     }
124     
125     /**
126      * Associate an open socket with this instance.
127      */
128     public void setSocket( Socket socket ) throws IOException {
129         if (debug > 0) {
130             logger.log("setSocket()");
131         }
132         
133   socket.setSoLinger( true, 100);
134   out = socket.getOutputStream();
135   in  = socket.getInputStream();
136   pos = 0;
137     }
138 
139     /**
140      * Backward compat mode, no login  needed
141      */
142     public void setBackward(boolean b) 
143     {
144         backwardCompat=b;
145     }
146 
147     public boolean isLogged() {
148   return logged;
149     }
150 
151     void setLogged( boolean b ) {
152         logged=b;
153     }
154 
155     public void setSecret( String s ) {
156         secret=s;
157     }
158 
159     public String getSecret() {
160         return secret;
161     }
162     
163     // -------------------- Handlers registry --------------------
164 
165     static final int MAX_HANDLERS=32;
166     static final int RESERVED=16;  // reserved names, backward compat
167 
168     // Note that we don't make distinction between in and out
169     // messages ( i.e. one id is used only in one direction )
170     AjpHandler handlers[]=new AjpHandler[MAX_HANDLERS];
171     String handlerName[]=new String[MAX_HANDLERS];
172     int currentId=RESERVED;
173 
174     public int registerMessageType( int id, String name, AjpHandler h,
175             String sig[] )
176     {
177   if( id < 0 ) {
178       // try to find it by name
179       for( int i=0; i< handlerName.length; i++ )
180     if( name.equals( handlerName[i] ) ) return i;
181       handlerName[currentId]=name;
182       handlers[currentId]=h;
183       currentId++;
184       return currentId;
185   }
186   // fixed id
187   handlerName[id]=name;
188   handlers[id]=h;
189   return id;
190     }
191     
192     // -------------------- Main dispatch --------------------
193     
194     /**
195      * Read a new packet from the web server and decode it.  If it's a
196      * forwarded request, store its properties in the passed-in AjpRequest
197      * object.
198      *
199      * @param req An empty (newly-recycled) request object.
200      * 
201      * @return 200 in case of a successful read of a forwarded request, 500
202      * if there were errors in the reading of the request, and -2 if the
203      * server is asking the container to shut itself down.  
204      */
205     public int receiveNextRequest(BaseRequest req) throws IOException {
206         if (debug > 0) {
207             logger.log("receiveNextRequest()");
208         }
209         
210         // XXX The return values are awful.
211 
212         int err = 0;
213 
214         // if we receive an IOException here, it must be because
215         // the remote just closed the ajp13 connection, and it's not
216         // an error, we just need to close the AJP13 connection
217         try {
218             err = receive(hBuf);
219         } catch (IOException ioe) {
220             if(debug >0 ) logger.log( "IOException receiving message ");
221             return -1;  // Indicate it's a disconnection from the remote end
222         }
223         
224   if(err < 0) {
225       if(debug >0 ) logger.log( "Error receiving message ");
226       return 500;
227   }
228   
229   int type = (int)hBuf.getByte();
230         //        System.out.println("XXX " + this );
231         return handleMessage( type, hBuf, req );
232     }
233 
234     /** Override for ajp14, temporary
235      */
236     public int handleMessage( int type, Ajp13Packet hBuf, BaseRequest req )
237         throws IOException
238     {
239         if( type > handlers.length ) {
240       logger.log( "Invalid handler " + type );
241       return 500;
242   }
243 
244         if( debug > 0 )
245             logger.log( "Received " + type + " " + handlerName[type]);
246         
247         // Ajp14, unlogged
248   if( ! backwardCompat && ! isLogged() ) {
249       if( type != NegociationHandler.JK_AJP14_LOGINIT_CMD &&
250     type != NegociationHandler.JK_AJP14_LOGCOMP_CMD ) {
251 
252                 logger.log( "Ajp14 error: not logged " +
253                             type + " " + handlerName[type]);
254 
255     return 300;
256       }
257       // else continue
258   }
259 
260         // Ajp13 messages
261   switch(type) {
262   case RequestHandler.JK_AJP13_FORWARD_REQUEST:
263       return reqHandler.decodeRequest(this, hBuf, req);
264       
265   case RequestHandler.JK_AJP13_CPING_REQUEST:
266     return reqHandler.sendCPong(this, outBuf);
267     
268   case RequestHandler.JK_AJP13_SHUTDOWN:
269       return -2;
270   }
271 
272   // logged || loging message
273   AjpHandler handler=handlers[type];
274   if( handler==null ) {
275       logger.log( "Unknown message " + type + handlerName[type] );
276       return 200;
277   }
278 
279         if( debug > 0 )
280             logger.log( "Ajp14 handler " + handler );
281   return handler.handleAjpMessage( type, this, hBuf, req );
282     }
283 
284     // ==================== Servlet Input Support =================
285 
286     /** @deprecated -- Will use reqHandler, make sure nobody else
287      calls this */
288 
289     
290     public int available() throws IOException {
291         return reqHandler.available(this);
292     }
293 
294     public int doRead() throws IOException 
295     {
296         return reqHandler.doRead( this );
297     }
298     
299     public int doRead(byte[] b, int off, int len) throws IOException 
300     {
301         return reqHandler.doRead( this, b, off, len );
302     }
303     
304     private boolean refillReadBuffer() throws IOException 
305     {
306         return reqHandler.refillReadBuffer(this);
307     }    
308 
309     public void beginSendHeaders(int status,
310                                  String statusMessage,
311                                  int numHeaders) throws IOException {
312         reqHandler.beginSendHeaders( this, outBuf,
313                                          status, statusMessage,
314                                          numHeaders);
315     }        
316 
317   public void sendHeader(String name, String value) throws IOException {
318     reqHandler.sendHeader(  outBuf, name, value );
319   }
320 
321 
322     public void endSendHeaders() throws IOException {
323         reqHandler.endSendHeaders(this, outBuf);
324     }
325 
326     public void sendHeaders(int status, MimeHeaders headers)
327         throws IOException
328     {
329         reqHandler.sendHeaders(this, outBuf, status,
330                                    HttpMessages.getMessage(status),
331                                    headers);
332     }
333 
334     public void sendHeaders(int status, String statusMessage,
335                             MimeHeaders headers)
336         throws IOException
337     {
338         reqHandler.sendHeaders( this, outBuf, status,
339                                     statusMessage, headers );
340     }
341 
342     public void finish() throws IOException {
343         reqHandler.finish(this, outBuf );
344     }
345 
346     public void doWrite(byte b[], int off, int len) throws IOException {
347         reqHandler.doWrite( this, outBuf, b, off, len );
348     }
349     
350 
351     // ========= Internal Packet-Handling Methods =================
352 
353     /**
354      * Read N bytes from the InputStream, and ensure we got them all
355      * Under heavy load we could experience many fragmented packets
356      * just read Unix Network Programming to recall that a call to
357      * read didn't ensure you got all the data you want
358      *
359      * from read() Linux manual
360      *
361      * On success, the number of bytes read is returned (zero indicates end of file),
362      * and the file position is advanced by this number.
363      * It is not an error if this number is smaller than the number of bytes requested;
364      * this may happen for example because fewer bytes
365      * are actually available right now (maybe because we were close to end-of-file,
366      * or because we are reading from a pipe, or  from  a
367      * terminal),  or  because  read()  was interrupted by a signal.
368      * On error, -1 is returned, and errno is set appropriately. In this
369      * case it is left unspecified whether the file position (if any) changes.
370      *
371      **/
372     private int readN(InputStream in, byte[] b, int offset, int len) throws IOException {
373         int pos = 0;
374         int got;
375 
376         while(pos < len) {
377             got = in.read(b, pos + offset, len - pos);
378 
379             if (debug > 10) {
380                 logger.log("read got # " + got);
381             }
382 
383             // connection just closed by remote. 
384             if (got <= 0) {
385                 // This happens periodically, as apache restarts
386                 // periodically.
387                 // It should be more gracefull ! - another feature for Ajp14 
388                 return JK_AJP13_COMM_BROKEN;
389             }
390 
391             pos += got;
392         }
393         return pos;
394      }
395 
396     /**
397      * Read in a packet from the web server and store it in the passed-in
398      * <CODE>Ajp13Packet</CODE> object.
399      *
400      * @param msg The object into which to store the incoming packet -- any
401      * current contents will be overwritten.
402      *
403      * @return The number of bytes read on a successful read or -1 if there 
404      * was an error.
405      **/
406     public int receive(Ajp13Packet msg) throws IOException {
407         if (debug > 0) {
408             logger.log("receive()");
409         }
410 
411   // XXX If the length in the packet header doesn't agree with the
412   // actual number of bytes read, it should probably return an error
413   // value.  Also, callers of this method never use the length
414   // returned -- should probably return true/false instead.
415   byte b[] = msg.getBuff();
416   
417         int rd = readN(in, b, 0, H_SIZE );
418         
419         // XXX - connection closed (JK_AJP13_COMM_CLOSED)
420         //     - connection broken (JK_AJP13_COMM_BROKEN)
421         //
422         if(rd < 0) {
423             // Most likely normal apache restart.
424             return rd;
425         }
426         
427   int len = msg.checkIn();
428   if( debug > 5 )
429             logger.log( "Received " + rd + " " + len + " " + b[0] );
430         
431   // XXX check if enough space - it's assert()-ed !!!
432         
433    int total_read = 0;
434         
435         total_read = readN(in, b, H_SIZE, len);
436 
437         // it's ok to have read 0 bytes when len=0 -- this means
438         // the end of the stream has been reached.
439         if (total_read < 0) {
440             logger.log("can't read body, waited #" + len);
441             return JK_AJP13_BAD_BODY;
442         }
443         
444         if (total_read != len) {
445             logger.log( "incomplete read, waited #" + len +
446                         " got only " + total_read);
447             return JK_AJP13_INCOMPLETE_BODY;
448         }
449         
450         if (debug > 0)
451             logger.log("receive:  total read = " + total_read);
452   return total_read;
453     }
454     
455     /**
456      * Send a packet to the web server.  Works for any type of message.
457      *
458      * @param msg A packet with accumulated data to send to the server --
459      * this method will write out the length in the header.  
460      */
461     public void send( Ajp13Packet msg ) throws IOException {
462         if (debug > 0) {
463             logger.log("send()");
464         }
465 
466   msg.end(); // Write the packet header
467   byte b[] = msg.getBuff();
468   int len  = msg.getLen();
469 
470         if (debug > 5 )
471             logger.log("send() " + len + " " + b[0] );
472 
473   out.write( b, 0, len );
474     }
475   
476     /**
477      * Close the socket connection to the web server.  In general, sockets
478      * are maintained across many requests, so this will not be called
479      * after finish().  
480      */
481     public void close() throws IOException {
482         if (debug > 0) {
483             logger.log("close()");
484         }
485 
486   if(null != out) {        
487       out.close();
488   }
489   if(null !=in) {
490       in.close();
491   }
492         setLogged( false );  // no more logged now 
493     }
494 
495     // -------------------- Debug --------------------
496     protected int debug = 0;
497     
498     public void setDebug(int debug) {
499         this.debug = debug;
500         this.reqHandler.setDebug(debug);
501     }
502 
503     public void setLogger(Logger l) {
504         this.logger = l;
505         this.reqHandler.setLogger(l);
506     }
507 
508     /**
509      * XXX place holder...
510      */
511     Logger logger = new Logger();
512 }