KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ajp > tomcat33 > Ajp14Interceptor


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.tomcat33;
18
19 import java.io.IOException JavaDoc;
20 import java.net.InetAddress JavaDoc;
21 import java.net.Socket JavaDoc;
22
23 import org.apache.ajp.Ajp13;
24 import org.apache.ajp.NegociationHandler;
25 import org.apache.ajp.RequestHandler;
26 import org.apache.tomcat.core.Context;
27 import org.apache.tomcat.core.ContextManager;
28 import org.apache.tomcat.core.Request;
29 import org.apache.tomcat.core.Response;
30 import org.apache.tomcat.core.TomcatException;
31 import org.apache.tomcat.modules.server.PoolTcpConnector;
32 import org.apache.tomcat.util.buf.UDecoder;
33 import org.apache.tomcat.util.http.BaseRequest;
34 import org.apache.tomcat.util.http.Cookies;
35 import org.apache.tomcat.util.http.HttpMessages;
36 import org.apache.tomcat.util.net.TcpConnection;
37 import org.apache.tomcat.util.net.TcpConnectionHandler;
38
39 /** Note. PoolTcpConnector is a convenience base class used for
40     TCP-based connectors in tomcat33. It allows all those modules
41     to share the thread pool and listener code.
42
43     In future it's likely other optimizations will be implemented in
44     the PoolTcpConnector, so it's better to use it if you don't have
45     a good reason not to ( like a connector for J2ME, where you want
46     minimal footprint and don't care about high load )
47 */

48
49 /** Tomcat 33 module implementing the Ajp14 protocol.
50  *
51  * The actual protocol implementation is in Ajp14.java, this is just an
52  * adapter to plug it into tomcat.
53  */

54 public class Ajp14Interceptor extends PoolTcpConnector
55     implements TcpConnectionHandler
56 {
57     int ajp14_note=-1;
58     String JavaDoc password;
59     RequestHandler reqHandler=new RequestHandler();
60     NegociationHandler negHandler=new NegociationHandler();
61     
62     public Ajp14Interceptor()
63     {
64         super();
65     super.setSoLinger( 100 );
66     super.setTcpNoDelay( true );
67     }
68
69     // initialization
70
public void engineInit(ContextManager cm) throws TomcatException {
71     log("engineInit");
72     }
73
74     public void engineStart(ContextManager cm) throws TomcatException {
75     super.engineInit( cm );
76     ajp14_note=cm.getNoteId( ContextManager.REQUEST_NOTE, "ajp14" );
77     super.engineStart(cm);
78    }
79
80     
81     // -------------------- Ajp14 specific parameters --------------------
82

83     public void setPassword( String JavaDoc s ) {
84     this.password=s;
85     }
86
87     /**
88      * Set the original entropy seed
89      */

90     public void setSeed(String JavaDoc pseed)
91     {
92     negHandler.setSeed( pseed );
93     }
94     
95     // -------------------- PoolTcpConnector --------------------
96

97     /** Called by PoolTcpConnector to allow childs to init.
98      */

99     protected void localInit() throws Exception JavaDoc {
100     ep.setConnectionHandler( this );
101     }
102
103     // -------------------- Handler implementation --------------------
104

105     /* The TcpConnectionHandler interface is used by the PoolTcpConnector to
106      * handle incoming connections.
107      */

108
109     /** Called by the thread pool when a new thread is added to the pool,
110     in order to create the (expensive) objects that will be stored
111     as thread data.
112     XXX we should use a single object, not array ( several reasons ),
113     XXX Ajp14 should be storead as a request note, to be available in
114     all modules
115     */

116     public Object JavaDoc[] init()
117     {
118     if( debug > 0 ) log("Init ");
119         Object JavaDoc thData[]=new Object JavaDoc[1];
120     thData[0]=initRequest( null );
121     return thData;
122     }
123
124     /** Construct the request object, with probably unnecesary
125     sanity tests ( should work without thread pool - but that is
126     not supported in PoolTcpConnector, maybe in future )
127     */

128     private Ajp14Request initRequest(Object JavaDoc thData[] ) {
129     if( ajp14_note < 0 ) throw new RuntimeException JavaDoc( "assert: ajp14_note>0" );
130     Ajp14Request req=null;
131     if( thData != null ) {
132         req=(Ajp14Request)thData[0];
133     }
134     if( req != null ) {
135         Response res=req.getResponse();
136         req.recycle();
137         res.recycle();
138         // make the note available to other modules
139
req.setNote( ajp14_note, req.ajp13);
140         return req;
141     }
142     // either thData==null or broken ( req==null)
143
Ajp13 ajp13=new Ajp13(reqHandler);
144         negHandler.init( ajp13 );
145
146     negHandler.setContainerSignature( ContextManager.TOMCAT_NAME +
147                                           " v" + ContextManager.TOMCAT_VERSION);
148     if( password!= null ) {
149             negHandler.setPassword( password );
150             ajp13.setBackward(false);
151         }
152
153     BaseRequest ajpreq=new BaseRequest();
154
155     req=new Ajp14Request(ajp13, ajpreq);
156     Ajp14Response res=new Ajp14Response(ajp13);
157     cm.initRequest(req, res);
158     return req;
159     }
160     
161     /** Called whenever a new TCP connection is received. The connection
162     is reused.
163      */

164     public void processConnection(TcpConnection connection, Object JavaDoc thData[])
165     {
166         try {
167         if( debug>0)
168         log( "Received ajp14 connection ");
169             Socket JavaDoc socket = connection.getSocket();
170         // assert: socket!=null, connection!=null ( checked by PoolTcpEndpoint )
171

172             socket.setSoLinger( true, 100);
173
174             Ajp14Request req=initRequest( thData );
175             Ajp14Response res= (Ajp14Response)req.getResponse();
176             Ajp13 ajp13=req.ajp13;
177         BaseRequest ajpReq=req.ajpReq;
178
179             ajp13.setSocket(socket);
180
181         // first request should be the loginit.
182
int status=ajp13.receiveNextRequest( ajpReq );
183         if( status != 304 ) { // XXX use better codes
184
log( "Failure in logInit ");
185         return;
186         }
187
188         status=ajp13.receiveNextRequest( ajpReq );
189         if( status != 304 ) { // XXX use better codes
190
log( "Failure in login ");
191         return;
192         }
193         
194             boolean moreRequests = true;
195             while(moreRequests) {
196         status=ajp13.receiveNextRequest( ajpReq );
197
198         if( status==-2) {
199             // special case - shutdown
200
// XXX need better communication, refactor it
201
if( !doShutdown(socket.getLocalAddress(),
202                     socket.getInetAddress())) {
203             moreRequests = false;
204             continue;
205             }
206         }
207         
208         // 999 low level requests are just ignored (ie cping/cpong)
209
if( status == 200)
210             cm.service(req, res);
211         else if (status == 500) {
212             log( "Invalid request received " + req );
213             break;
214         }
215         
216         req.recycle();
217         res.recycle();
218             }
219             if( debug > 0 ) log("Closing ajp14 connection");
220             ajp13.close();
221         socket.close();
222         } catch (Exception JavaDoc e) {
223         log("Processing connection " + connection, e);
224         }
225     }
226
227     // We don't need to check isSameAddress if we authenticate !!!
228
protected boolean doShutdown(InetAddress JavaDoc serverAddr,
229                                  InetAddress JavaDoc clientAddr)
230     {
231         try {
232         // close the socket connection before handling any signal
233
// but get the addresses first so they are not corrupted
234
if(isSameAddress(serverAddr, clientAddr)) {
235         cm.stop();
236         // same behavior as in past, because it seems that
237
// stopping everything doesn't work - need to figure
238
// out what happens with the threads ( XXX )
239

240         // XXX It should work now - but will fail if servlets create
241
// threads
242
System.exit(0);
243         }
244     } catch(Exception JavaDoc ignored) {
245         log("Ignored " + ignored);
246     }
247     log("Shutdown command ignored");
248     return false;
249     }
250
251     // legacy, should be removed
252
public void setServer(Object JavaDoc contextM)
253     {
254         this.cm=(ContextManager)contextM;
255     }
256
257     public Object JavaDoc getInfo( Context ctx, Request request,
258                int id, String JavaDoc key ) {
259     if( ! ( request instanceof Ajp14Request ) ) {
260         return null;
261     }
262     Ajp14Request ajp14req = (Ajp14Request)request;
263     return ajp14req.ajpReq.getAttribute( key );
264     }
265     public int setInfo( Context ctx, Request request,
266             int id, String JavaDoc key, Object JavaDoc obj ) {
267     if( ! ( request instanceof Ajp14Request ) ) {
268         return DECLINED;
269     }
270     Ajp14Request ajp14req = (Ajp14Request)request;
271     ajp14req.ajpReq.setAttribute(key, obj);
272     return OK;
273     }
274         
275
276
277 }
278
279
280 //-------------------- Glue code for request/response.
281
// Probably not needed ( or can be simplified ), but it's
282
// not that bad.
283

284 class Ajp14Request extends Request
285 {
286     Ajp13 ajp13;
287     BaseRequest ajpReq;
288     
289     public Ajp14Request(Ajp13 ajp13, BaseRequest ajpReq)
290     {
291     headers = ajpReq.headers();
292     methodMB=ajpReq.method();
293     protoMB=ajpReq.protocol();
294     uriMB = ajpReq.requestURI();
295     queryMB = ajpReq.queryString();
296     remoteAddrMB = ajpReq.remoteAddr();
297     remoteHostMB = ajpReq.remoteHost();
298     serverNameMB = ajpReq.serverName();
299
300     // XXX sync cookies
301
scookies = new Cookies( headers );
302     urlDecoder=new UDecoder();
303
304     // XXX sync headers
305

306     params.setQuery( queryMB );
307     params.setURLDecoder( urlDecoder );
308     params.setHeaders( headers );
309     initRequest();
310
311         this.ajp13=ajp13;
312     this.ajpReq=ajpReq;
313     }
314
315     // -------------------- Wrappers for changed method names, and to use the buffers
316
// XXX Move BaseRequest into util !!! ( it's just a stuct with some MessageBytes )
317

318     public int getServerPort() {
319         return ajpReq.getServerPort();
320     }
321
322     public void setServerPort(int i ) {
323     ajpReq.setServerPort( i );
324     }
325
326     public void setRemoteUser( String JavaDoc s ) {
327     super.setRemoteUser(s);
328     ajpReq.remoteUser().setString(s);
329     }
330
331     public String JavaDoc getRemoteUser() {
332     String JavaDoc s=ajpReq.remoteUser().toString();
333     if( s == null )
334         s=super.getRemoteUser();
335     return s;
336     }
337
338     public String JavaDoc getAuthType() {
339     return ajpReq.authType().toString();
340     }
341     
342     public void setAuthType(String JavaDoc s ) {
343     ajpReq.authType().setString(s);
344     }
345
346     public String JavaDoc getJvmRoute() {
347     return ajpReq.jvmRoute().toString();
348     }
349     
350     public void setJvmRoute(String JavaDoc s ) {
351     ajpReq.jvmRoute().setString(s);
352     }
353
354     // XXX scheme
355

356     public boolean isSecure() {
357     return ajpReq.getSecure();
358     }
359     
360     public int getContentLength() {
361         int i=ajpReq.getContentLength();
362     if( i >= 0 ) return i;
363     i= super.getContentLength();
364     return i;
365     }
366
367     public void setContentLength( int i ) {
368     super.setContentLength(i); // XXX sync
369
}
370
371     // XXX broken
372
// public Iterator getAttributeNames() {
373
// return attributes.keySet().iterator();
374
// }
375

376
377     // --------------------
378

379     public void recycle() {
380     super.recycle();
381     ajpReq.recycle();
382     if( ajp13!=null) ajp13.recycle();
383     }
384
385     public String JavaDoc dumpRequest() {
386     return ajpReq.toString();
387     }
388     
389     // --------------------
390

391     // XXX This should go away if we introduce an InputBuffer.
392
// We almost have it as result of encoding fixes, but for now
393
// just keep this here, doesn't hurt too much.
394
public int doRead() throws IOException JavaDoc
395     {
396     if( available <= 0 )
397         return -1;
398     available--;
399     return ajp13.reqHandler.doRead(ajp13);
400     }
401     
402     public int doRead(byte[] b, int off, int len) throws IOException JavaDoc
403     {
404     if( available <= 0 )
405         return -1;
406     int rd=ajp13.reqHandler.doRead( ajp13, b,off, len );
407     available -= rd;
408     return rd;
409     }
410     
411 }
412
413 class Ajp14Response extends Response
414 {
415     Ajp13 ajp13;
416     boolean finished=false;
417     
418     public Ajp14Response(Ajp13 ajp13)
419     {
420     super();
421     this.ajp13=ajp13;
422     }
423
424     public void recycle() {
425     super.recycle();
426     finished=false;
427     }
428
429     // XXX if more headers that MAX_SIZE, send 2 packets!
430
// XXX Can be implemented using module notification, no need to extend
431
public void endHeaders() throws IOException JavaDoc
432     {
433         super.endHeaders();
434     
435         if (request.protocol().isNull()) {
436             return;
437         }
438
439     ajp13.reqHandler.sendHeaders(ajp13, ajp13.outBuf, getStatus(),
440                      HttpMessages.getMessage(status),
441                      getMimeHeaders());
442     }
443
444     // XXX Can be implemented using module notification, no need to extend
445
public void finish() throws IOException JavaDoc
446     {
447     if(!finished) {
448         super.finish();
449         finished = true; // Avoid END_OF_RESPONSE sent 2 times
450
ajp13.reqHandler.finish(ajp13, ajp13.outBuf);
451     }
452     }
453
454     // XXX Can be implemented using the buffers, no need to extend
455
public void doWrite( byte b[], int off, int len) throws IOException JavaDoc
456     {
457     ajp13.reqHandler.doWrite(ajp13, ajp13.outBuf, b, off, len );
458     }
459     
460 }
461
Popular Tags