Source code: org/mortbay/http/ajp/AJP13Connection.java
1 // ========================================================================
2 // Copyright (c) 2002-2003 Mort Bay Consulting (Australia) Pty. Ltd.
3 // $Id: AJP13Connection.java,v 1.27 2003/10/05 23:46:23 gregwilkins Exp $
4 // ========================================================================
5
6 package org.mortbay.http.ajp;
7
8
9 import java.io.ByteArrayInputStream;
10 import java.io.IOException;
11 import java.io.InputStream;
12 import java.io.OutputStream;
13 import java.net.InetAddress;
14 import java.net.Socket;
15 import java.net.SocketException;
16 import java.security.cert.CertificateFactory;
17 import java.security.cert.X509Certificate;
18
19 import org.apache.commons.logging.Log;
20 import org.apache.commons.logging.LogFactory;
21 import org.mortbay.http.HttpConnection;
22 import org.mortbay.http.HttpContext;
23 import org.mortbay.http.HttpFields;
24 import org.mortbay.http.HttpMessage;
25 import org.mortbay.http.HttpRequest;
26 import org.mortbay.http.HttpResponse;
27 import org.mortbay.http.Version;
28 import org.mortbay.util.LineInput;
29 import org.mortbay.util.LogSupport;
30
31 /* ------------------------------------------------------------ */
32 /**
33 * @version $Id: AJP13Connection.java,v 1.27 2003/10/05 23:46:23 gregwilkins Exp $
34 * @author Greg Wilkins (gregw)
35 */
36 public class AJP13Connection extends HttpConnection
37 {
38 private static Log log = LogFactory.getLog(AJP13Connection.class);
39
40 private AJP13Listener _listener;
41 private AJP13InputStream _ajpIn;
42 private AJP13OutputStream _ajpOut;
43 private String _remoteHost;
44 private String _remoteAddr;
45 private String _serverName;
46 private int _serverPort;
47 private boolean _isSSL;
48
49 /* ------------------------------------------------------------ */
50 public AJP13Connection(AJP13Listener listener,
51 InputStream in,
52 OutputStream out,
53 Socket socket,
54 int bufferSize)
55 throws IOException
56 {
57 super(listener,
58 null,
59 new AJP13InputStream(in,out,bufferSize),
60 out,
61 socket);
62
63 LineInput lin = (LineInput)getInputStream().getInputStream();
64 _ajpIn=(AJP13InputStream)lin.getInputStream();
65 _ajpOut=new AJP13OutputStream(getOutputStream().getFilterStream(),
66 bufferSize);
67 _ajpOut.setCommitObserver(this);
68 getOutputStream().setBufferedOutputStream(_ajpOut,true);
69 _listener=listener;
70 }
71
72 /* ------------------------------------------------------------ */
73 /** Get the Remote address.
74 * @return the remote address
75 */
76 public InetAddress getRemoteInetAddress()
77 {
78 return null;
79 }
80
81 /* ------------------------------------------------------------ */
82 public void destroy()
83 {
84 if (_ajpIn!=null)_ajpIn.destroy();
85 _ajpIn=null;
86 if (_ajpOut!=null)_ajpOut.destroy();
87 _ajpOut=null;
88 _remoteHost=null;
89 _remoteAddr=null;
90 _serverName=null;
91 }
92
93 /* ------------------------------------------------------------ */
94 /** Get the Remote address.
95 * @return the remote host name
96 */
97 public String getRemoteAddr()
98 {
99 return _remoteAddr;
100 }
101
102 /* ------------------------------------------------------------ */
103 /** Get the Remote address.
104 * @return the remote host name
105 */
106 public String getRemoteHost()
107 {
108 return _remoteHost;
109 }
110
111 /* ------------------------------------------------------------ */
112 /** Get the listeners HttpServer .
113 * Conveniance method equivalent to getListener().getHost().
114 * @return HttpServer.
115 */
116 public String getServerName()
117 {
118 return _serverName;
119 }
120
121 /* ------------------------------------------------------------ */
122 /** Get the listeners Port .
123 * Conveniance method equivalent to getListener().getPort().
124 * @return HttpServer.
125 */
126 public int getServerPort()
127 {
128 return _serverPort;
129 }
130
131 /* ------------------------------------------------------------ */
132 /** Get the listeners Default scheme.
133 * Conveniance method equivalent to getListener().getDefaultProtocol().
134 * @return HttpServer.
135 */
136 public String getDefaultScheme()
137 {
138 return _isSSL?HttpMessage.__SSL_SCHEME:super.getDefaultScheme();
139 }
140
141 /* ------------------------------------------------------------ */
142 public boolean isSSL()
143 {
144 return _isSSL;
145 }
146
147 /* ------------------------------------------------------------ */
148 public boolean handleNext()
149 {
150 AJP13RequestPacket packet=null;
151 HttpRequest request = getRequest();
152 HttpResponse response = getResponse();
153 HttpContext context = null;
154 boolean gotRequest=false;
155 _persistent=true;
156 _keepAlive=true;
157
158 try
159 {
160 try
161 {
162 packet = null;
163 packet = _ajpIn.nextPacket();
164 if (packet==null)
165 return false;
166 if (packet.getDataSize()==0)
167 return true;
168 }
169 catch (IOException e)
170 {
171 LogSupport.ignore(log,e);
172 return false;
173 }
174
175 int type=packet.getByte();
176 if(log.isDebugEnabled())log.debug("AJP13 type="+type+" size="+packet.unconsumedData());
177
178 switch (type)
179 {
180 case AJP13Packet.__FORWARD_REQUEST:
181 request.setTimeStamp(System.currentTimeMillis());
182
183 request.setState(HttpMessage.__MSG_EDITABLE);
184 request.setMethod(packet.getMethod());
185 request.setVersion(packet.getString());
186 request.setPath(packet.getString());
187 _remoteAddr=packet.getString();
188 _remoteHost=packet.getString();
189 _serverName=packet.getString();
190 _serverPort=packet.getInt();
191 _isSSL=packet.getBoolean();
192
193 // Check keep alive
194 _keepAlive=request.getDotVersion()>=1;
195
196 // Headers
197 int h=packet.getInt();
198 for (int i=0;i<h;i++)
199 {
200 String hdr=packet.getHeader();
201 String val=packet.getString();
202 request.setField(hdr,val);
203 if (!_keepAlive && hdr.equalsIgnoreCase(HttpFields.__Connection) &&
204 val.equalsIgnoreCase(HttpFields.__KeepAlive))
205 _keepAlive=true;
206 }
207
208
209 // Handler other attributes
210 byte attr=packet.getByte();
211 while ((0xFF&attr)!=0xFF)
212 {
213 String value=packet.getString();
214 switch (attr)
215 {
216 case 10: // request attribute
217 request.setAttribute(value,packet.getString());
218 break;
219 case 9: // SSL session
220 //log.warn("not implemented: sslsession="+value);
221 break;
222 case 8: // SSL cipher
223 request.setAttribute("javax.servlet.request.cipher_suite",value);
224 break;
225 case 7: // SSL cert
226 //request.setAttribute("javax.servlet.request.X509Certificate",value);
227 CertificateFactory cf =
228 CertificateFactory.getInstance("X.509");
229 InputStream certstream =
230 new ByteArrayInputStream(value.getBytes());
231 X509Certificate cert = (X509Certificate)
232 cf.generateCertificate(certstream);
233 X509Certificate certs[] = {cert};
234 request.setAttribute("javax.servlet.request.X509Certificate",certs);
235 break;
236 case 6: // JVM Route
237 request.setAttribute("org.mortbay.http.ajp.JVMRoute",value);
238 break;
239 case 5: // Query String
240 request.setQuery(value);
241 break;
242 case 4: // AuthType
243 request.setAuthType(value);
244 break;
245 case 3: // Remote User
246 request.setAuthUser(value);
247 break;
248
249 case 2: // servlet path not implemented
250 case 1: // context not implemented
251 default:
252 log.warn("Unknown attr: "+attr+"="+value);
253 }
254
255 attr=packet.getByte();
256 }
257
258 _listener.customizeRequest(this,request);
259
260 gotRequest=true;
261 statsRequestStart();
262 request.setState(HttpMessage.__MSG_RECEIVED);
263
264 // Complete response
265 if (request.getContentLength()==0 &&
266 request.getField(HttpFields.__TransferEncoding)==null)
267 _ajpIn.close();
268
269 // Prepare response
270 response.setState(HttpMessage.__MSG_EDITABLE);
271 response.setVersion(HttpMessage.__HTTP_1_1);
272 response.setDateField(HttpFields.__Date,_request.getTimeStamp());
273 response.setField(HttpFields.__Server,Version.__VersionDetail);
274
275 // Service request
276 if(log.isDebugEnabled())log.debug("REQUEST:\n"+request);
277 context=service(request,response);
278 if(log.isDebugEnabled())log.debug("RESPONSE:\n"+response);
279
280 break;
281
282 default:
283 if(log.isDebugEnabled())log.debug("Ignored: "+packet);
284 _persistent=false;
285 }
286
287 }
288 catch (SocketException e)
289 {
290 LogSupport.ignore(log,e);
291 _persistent=false;
292 }
293 catch (Exception e)
294 {
295 log.warn(LogSupport.EXCEPTION,e);
296 _persistent=false;
297 try{
298 if (gotRequest)
299 _ajpOut.close();
300 }
301 catch (IOException e2){LogSupport.ignore(log,e2);}
302 }
303 finally
304 {
305 // abort if nothing received.
306 if (packet==null || !gotRequest)
307 return false;
308
309 // flush and end the output
310 try{
311 //Consume unread input.
312 // while(_ajpIn.skip(4096)>0 || _ajpIn.read()>=0);
313
314 // end response
315 getOutputStream().close();
316 if (!_persistent)
317 _ajpOut.end();
318
319 // Close the outout
320 _ajpOut.close();
321
322 // reset streams
323 getOutputStream().resetStream();
324 getOutputStream().addObserver(this);
325 getInputStream().resetStream();
326 _ajpIn.resetStream();
327 _ajpOut.resetStream();
328 }
329 catch (Exception e)
330 {
331 log.debug(LogSupport.EXCEPTION,e);
332 _persistent=false;
333 }
334 finally
335 {
336 statsRequestEnd();
337 if (context!=null)
338 context.log(request,response,-1);
339 }
340 }
341 return _persistent;
342 }
343
344
345 /* ------------------------------------------------------------ */
346 protected void firstWrite()
347 throws IOException
348 {
349 log.debug("ajp13 firstWrite()");
350 }
351
352 /* ------------------------------------------------------------ */
353 protected void commit()
354 throws IOException
355 {
356 log.debug("ajp13 commit()");
357 if (_response.isCommitted())
358 return;
359 _request.setHandled(true);
360 getOutputStream().writeHeader(_response);
361 }
362
363
364 /* ------------------------------------------------------------ */
365 protected void setupOutputStream()
366 throws IOException
367 {
368 // Nobble the OutputStream for HEAD requests
369 if (HttpRequest.__HEAD.equals(getRequest().getMethod()))
370 getOutputStream().nullOutput();
371 }
372 }