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

Quick Search    Search Deep

Source code: org/apache/ajp/tomcat33/Ajp14Interceptor.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.tomcat33;
18  
19  import java.io.IOException;
20  import java.net.InetAddress;
21  import java.net.Socket;
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 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 s ) {
84    this.password=s;
85      }
86  
87      /**
88       * Set the original entropy seed
89       */
90      public void setSeed(String 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 {
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[] init()
117     {
118   if( debug > 0 ) log("Init ");
119         Object thData[]=new Object[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 thData[] ) {
129   if( ajp14_note < 0 ) throw new RuntimeException( "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 thData[])
165     {
166         try {
167       if( debug>0)
168     log( "Received ajp14 connection ");
169             Socket 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 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 serverAddr,
229                                  InetAddress 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 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 contextM)
253     {
254         this.cm=(ContextManager)contextM;
255     }
256 
257     public Object getInfo( Context ctx, Request request,
258          int id, String 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 key, Object 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 s ) {
327   super.setRemoteUser(s);
328   ajpReq.remoteUser().setString(s);
329     }
330 
331     public String getRemoteUser() {
332   String s=ajpReq.remoteUser().toString();
333   if( s == null )
334       s=super.getRemoteUser();
335   return s;
336     }
337 
338     public String getAuthType() {
339   return ajpReq.authType().toString();
340     }
341     
342     public void setAuthType(String s ) {
343   ajpReq.authType().setString(s);
344     }
345 
346     public String getJvmRoute() {
347   return ajpReq.jvmRoute().toString();
348     }
349     
350     public void setJvmRoute(String 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 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 
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 
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 
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 
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 
456     {
457   ajp13.reqHandler.doWrite(ajp13, ajp13.outBuf, b, off, len );
458     }
459     
460 }