KickJava   Java API By Example, From Geeks To Geeks.

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


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 JavaDoc;
20 import java.io.InputStream JavaDoc;
21 import java.io.OutputStream JavaDoc;
22 import java.net.Socket JavaDoc;
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 JavaDoc out;
66     InputStream JavaDoc 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 JavaDoc 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 JavaDoc socket ) throws IOException JavaDoc {
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 JavaDoc s ) {
156         secret=s;
157     }
158
159     public String JavaDoc 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 JavaDoc handlerName[]=new String JavaDoc[MAX_HANDLERS];
172     int currentId=RESERVED;
173
174     public int registerMessageType( int id, String JavaDoc name, AjpHandler h,
175                     String JavaDoc 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 JavaDoc {
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 JavaDoc 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 JavaDoc
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 JavaDoc {
291         return reqHandler.available(this);
292     }
293
294     public int doRead() throws IOException JavaDoc
295     {
296         return reqHandler.doRead( this );
297     }
298     
299     public int doRead(byte[] b, int off, int len) throws IOException JavaDoc
300     {
301         return reqHandler.doRead( this, b, off, len );
302     }
303     
304     private boolean refillReadBuffer() throws IOException JavaDoc
305     {
306         return reqHandler.refillReadBuffer(this);
307     }
308
309     public void beginSendHeaders(int status,
310                                  String JavaDoc statusMessage,
311                                  int numHeaders) throws IOException JavaDoc {
312         reqHandler.beginSendHeaders( this, outBuf,
313                                          status, statusMessage,
314                                          numHeaders);
315     }
316
317     public void sendHeader(String JavaDoc name, String JavaDoc value) throws IOException JavaDoc {
318         reqHandler.sendHeader( outBuf, name, value );
319     }
320
321
322     public void endSendHeaders() throws IOException JavaDoc {
323         reqHandler.endSendHeaders(this, outBuf);
324     }
325
326     public void sendHeaders(int status, MimeHeaders headers)
327         throws IOException JavaDoc
328     {
329         reqHandler.sendHeaders(this, outBuf, status,
330                                    HttpMessages.getMessage(status),
331                                    headers);
332     }
333
334     public void sendHeaders(int status, String JavaDoc statusMessage,
335                             MimeHeaders headers)
336         throws IOException JavaDoc
337     {
338         reqHandler.sendHeaders( this, outBuf, status,
339                                     statusMessage, headers );
340     }
341
342     public void finish() throws IOException JavaDoc {
343         reqHandler.finish(this, outBuf );
344     }
345
346     public void doWrite(byte b[], int off, int len) throws IOException JavaDoc {
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 JavaDoc in, byte[] b, int offset, int len) throws IOException JavaDoc {
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 JavaDoc {
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 JavaDoc {
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 JavaDoc {
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 }
513
Popular Tags