1 7 package winstone.ajp13; 8 9 import java.io.ByteArrayInputStream ; 10 import java.io.IOException ; 11 import java.io.InputStream ; 12 import java.io.InterruptedIOException ; 13 import java.io.OutputStream ; 14 import java.io.UnsupportedEncodingException ; 15 import java.net.InetAddress ; 16 import java.net.ServerSocket ; 17 import java.net.Socket ; 18 import java.net.SocketException ; 19 import java.security.cert.CertificateException ; 20 import java.security.cert.CertificateFactory ; 21 import java.security.cert.X509Certificate ; 22 import java.util.Arrays ; 23 import java.util.Iterator ; 24 import java.util.Map ; 25 26 import winstone.HostGroup; 27 import winstone.Launcher; 28 import winstone.Listener; 29 import winstone.Logger; 30 import winstone.ObjectPool; 31 import winstone.RequestHandlerThread; 32 import winstone.WebAppConfiguration; 33 import winstone.WinstoneException; 34 import winstone.WinstoneInputStream; 35 import winstone.WinstoneOutputStream; 36 import winstone.WinstoneRequest; 37 import winstone.WinstoneResourceBundle; 38 import winstone.WinstoneResponse; 39 40 47 public class Ajp13Listener implements Listener, Runnable { 48 public final static WinstoneResourceBundle AJP_RESOURCES = new WinstoneResourceBundle("winstone.ajp13.LocalStrings"); 49 50 private final static int LISTENER_TIMEOUT = 5000; private final static int DEFAULT_PORT = 8009; 52 private final static int CONNECTION_TIMEOUT = 60000; 53 private final static int BACKLOG_COUNT = 1000; 54 private final static int KEEP_ALIVE_TIMEOUT = -1; 55 private final static String TEMPORARY_URL_STASH = "winstone.ajp13.TemporaryURLAttribute"; 58 59 private HostGroup hostGroup; 60 private ObjectPool objectPool; 61 private int listenPort; 62 private boolean interrupted; 63 private String listenAddress; 64 65 68 public Ajp13Listener(Map args, ObjectPool objectPool, HostGroup hostGroup) { 69 this.hostGroup = hostGroup; 71 this.objectPool = objectPool; 72 73 this.listenPort = Integer.parseInt(WebAppConfiguration.stringArg(args, 74 "ajp13Port", "" + DEFAULT_PORT)); 75 this.listenAddress = WebAppConfiguration.stringArg(args, 76 "ajp13ListenAddress", null); 77 } 78 79 public boolean start() { 80 if (this.listenPort < 0) { 81 return false; 82 } else { 83 this.interrupted = false; 84 Thread thread = new Thread (this, Launcher.RESOURCES.getString( 85 "Listener.ThreadName", new String [] { "ajp13", 86 "" + this.listenPort })); 87 thread.setDaemon(true); 88 thread.start(); 89 return true; 90 } 91 } 92 93 96 public void run() { 97 try { 98 ServerSocket ss = this.listenAddress == null ? new ServerSocket ( 99 this.listenPort, BACKLOG_COUNT) : new ServerSocket ( 100 this.listenPort, BACKLOG_COUNT, InetAddress 101 .getByName(this.listenAddress)); 102 ss.setSoTimeout(LISTENER_TIMEOUT); 103 Logger.log(Logger.INFO, AJP_RESOURCES, "Ajp13Listener.StartupOK", 104 this.listenPort + ""); 105 106 while (!interrupted) { 108 Socket s = null; 110 try { 111 s = ss.accept(); 112 } catch (java.io.InterruptedIOException err) { 113 s = null; 114 } 115 116 if (s != null) 119 this.objectPool.handleRequest(s, this); 120 } 121 122 ss.close(); 124 } catch (Throwable err) { 125 Logger.log(Logger.ERROR, AJP_RESOURCES, 126 "Ajp13Listener.ShutdownError", err); 127 } 128 129 Logger.log(Logger.INFO, AJP_RESOURCES, "Ajp13Listener.ShutdownOK"); 130 } 131 132 136 public void destroy() { 137 this.interrupted = true; 138 } 139 140 149 public void allocateRequestResponse(Socket socket, InputStream inSocket, 150 OutputStream outSocket, RequestHandlerThread handler, 151 boolean iAmFirst) throws SocketException , IOException { 152 WinstoneRequest req = this.objectPool.getRequestFromPool(); 153 WinstoneResponse rsp = this.objectPool.getResponseFromPool(); 154 rsp.setRequest(req); 155 req.setHostGroup(this.hostGroup); 156 158 if (iAmFirst || (KEEP_ALIVE_TIMEOUT == -1)) 159 socket.setSoTimeout(CONNECTION_TIMEOUT); 160 else 161 socket.setSoTimeout(KEEP_ALIVE_TIMEOUT); 162 Ajp13IncomingPacket headers = null; 163 try { 164 headers = new Ajp13IncomingPacket(inSocket, handler); 165 } catch (InterruptedIOException err) { 166 if (iAmFirst) { 168 throw err; 169 } else { 170 deallocateRequestResponse(handler, req, rsp, null, null); 171 return; 172 } 173 } finally { 174 try {socket.setSoTimeout(CONNECTION_TIMEOUT);} catch (Throwable err) {} 175 } 176 177 if (headers.getPacketLength() > 0) { 178 headers.parsePacket("8859_1"); 179 parseSocketInfo(headers, req); 180 req.parseHeaders(Arrays.asList(headers.getHeaders())); 181 String servletURI = parseURILine(headers, req, rsp); 182 req.setAttribute(TEMPORARY_URL_STASH, servletURI); 183 184 WinstoneInputStream inData = null; 187 int contentLength = req.getContentLength(); 188 if (contentLength > 0) { 189 byte bodyContent[] = new byte[contentLength]; 190 int position = 0; 191 while (position < contentLength) { 192 outSocket.write(getBodyRequestPacket(Math.min(contentLength 193 - position, 8184))); 194 position = getBodyResponsePacket(inSocket, bodyContent, 195 position); 196 Logger.log(Logger.FULL_DEBUG, AJP_RESOURCES, 197 "Ajp13Listener.ReadBodyProgress", new String [] { 198 "" + position, "" + contentLength }); 199 200 } 201 inData = new WinstoneInputStream(bodyContent); 202 inData.setContentLength(contentLength); 203 } else 204 inData = new WinstoneInputStream(new byte[0]); 205 req.setInputStream(inData); 206 207 WinstoneOutputStream outData = new Ajp13OutputStream(socket 209 .getOutputStream(), "8859_1"); 210 outData.setResponse(rsp); 211 rsp.setOutputStream(outData); 212 213 handler.setRequest(req); 215 handler.setResponse(rsp); 216 handler.setInStream(inData); 217 handler.setOutStream(outData); 218 } 219 } 220 221 226 public void deallocateRequestResponse(RequestHandlerThread handler, 227 WinstoneRequest req, WinstoneResponse rsp, 228 WinstoneInputStream inData, WinstoneOutputStream outData) 229 throws IOException { 230 handler.setInStream(null); 231 handler.setOutStream(null); 232 handler.setRequest(null); 233 handler.setResponse(null); 234 if (req != null) 235 this.objectPool.releaseRequestToPool(req); 236 if (rsp != null) 237 this.objectPool.releaseResponseToPool(rsp); 238 } 239 240 244 public String parseURI(RequestHandlerThread handler, WinstoneRequest req, 245 WinstoneResponse rsp, WinstoneInputStream inData, Socket socket, 246 boolean iAmFirst) throws IOException { 247 String uri = (String ) req.getAttribute(TEMPORARY_URL_STASH); 248 req.removeAttribute(TEMPORARY_URL_STASH); 249 return uri; 250 } 251 252 259 public void releaseSocket(Socket socket, InputStream inSocket, 260 OutputStream outSocket) throws IOException { 261 inSocket.close(); 264 outSocket.close(); 265 socket.close(); 266 } 267 268 272 private void parseSocketInfo(Ajp13IncomingPacket headers, 273 WinstoneRequest req) { 274 req.setServerPort(headers.getServerPort()); 275 req.setRemoteIP(headers.getRemoteAddress()); 276 req.setServerName(headers.getServerName()); 277 req.setLocalPort(headers.getServerPort()); 278 req.setLocalAddr(headers.getServerName()); 279 req.setRemoteIP(headers.getRemoteAddress()); 280 if ((headers.getRemoteHost() != null) 281 && !headers.getRemoteHost().equals("")) 282 req.setRemoteName(headers.getRemoteHost()); 283 else 284 req.setRemoteName(headers.getRemoteAddress()); 285 req.setScheme(headers.isSSL() ? "https" : "http"); 286 req.setIsSecure(headers.isSSL()); 287 } 288 289 293 private String parseURILine(Ajp13IncomingPacket headers, 294 WinstoneRequest req, WinstoneResponse rsp) 295 throws UnsupportedEncodingException { 296 req.setMethod(headers.getMethod()); 297 req.setProtocol(headers.getProtocol()); 298 rsp.setProtocol(headers.getProtocol()); 299 rsp.extractRequestKeepAliveHeader(req); 300 303 for (Iterator i = headers.getAttributes().keySet().iterator(); i 305 .hasNext();) { 306 String attName = (String ) i.next(); 307 if (attName.equals("query_string")) { 308 String qs = (String ) headers.getAttributes().get("query_string"); 309 req.setQueryString(qs); 310 } else if (attName.equals("ssl_cert")) { 314 String certValue = (String ) headers.getAttributes().get( 315 "ssl_cert"); 316 InputStream certStream = new ByteArrayInputStream (certValue 317 .getBytes("8859_1")); 318 X509Certificate certificateArray[] = new X509Certificate [1]; 319 try { 320 certificateArray[0] = (X509Certificate ) CertificateFactory 321 .getInstance("X.509").generateCertificate( 322 certStream); 323 } catch (CertificateException err) { 324 Logger.log(Logger.DEBUG, AJP_RESOURCES, 325 "Ajp13Listener.SkippingCert", certValue); 326 } 327 req.setAttribute("javax.servlet.request.X509Certificate", 328 certificateArray); 329 req.setIsSecure(true); 330 } else if (attName.equals("ssl_cipher")) { 331 String cipher = (String ) headers.getAttributes().get( 332 "ssl_cipher"); 333 req.setAttribute("javax.servlet.request.cipher_suite", cipher); 334 req.setAttribute("javax.servlet.request.key_size", 335 getKeySize(cipher)); 336 req.setIsSecure(true); 337 } else if (attName.equals("ssl_session")) { 338 req.setAttribute("javax.servlet.request.ssl_session", headers 339 .getAttributes().get("ssl_session")); 340 req.setIsSecure(true); 341 } else 342 Logger.log(Logger.DEBUG, AJP_RESOURCES, 343 "Ajp13Listener.UnknownAttribute", new String [] { 344 attName, 345 "" + headers.getAttributes().get(attName) }); 346 } 347 return headers.getURI(); 348 349 } 350 351 private Integer getKeySize(String cipherSuite) { 352 if (cipherSuite.indexOf("_WITH_NULL_") != -1) 353 return new Integer (0); 354 else if (cipherSuite.indexOf("_WITH_IDEA_CBC_") != -1) 355 return new Integer (128); 356 else if (cipherSuite.indexOf("_WITH_RC2_CBC_40_") != -1) 357 return new Integer (40); 358 else if (cipherSuite.indexOf("_WITH_RC4_40_") != -1) 359 return new Integer (40); 360 else if (cipherSuite.indexOf("_WITH_RC4_128_") != -1) 361 return new Integer (128); 362 else if (cipherSuite.indexOf("_WITH_DES40_CBC_") != -1) 363 return new Integer (40); 364 else if (cipherSuite.indexOf("_WITH_DES_CBC_") != -1) 365 return new Integer (56); 366 else if (cipherSuite.indexOf("_WITH_3DES_EDE_CBC_") != -1) 367 return new Integer (168); 368 else 369 return null; 370 } 371 372 378 public boolean processKeepAlive(WinstoneRequest request, 379 WinstoneResponse response, InputStream inSocket) 380 throws IOException , InterruptedException { 381 return true; 382 } 383 384 387 private byte[] getBodyRequestPacket(int desiredPacketLength) { 388 byte getBodyRequestPacket[] = new byte[] { 0x41, 0x42, 0x00, 0x03, 389 0x06, 0x00, 0x00 }; 390 Ajp13OutputStream.setIntBlock(desiredPacketLength, 391 getBodyRequestPacket, 5); 392 return getBodyRequestPacket; 393 } 394 395 400 private int getBodyResponsePacket(InputStream in, byte buffer[], int offset) 401 throws IOException { 402 byte headerBuffer[] = new byte[4]; 404 int headerBytesRead = in.read(headerBuffer); 405 if (headerBytesRead != 4) 406 throw new WinstoneException(AJP_RESOURCES 407 .getString("Ajp13Listener.InvalidHeader")); 408 else if ((headerBuffer[0] != 0x12) || (headerBuffer[1] != 0x34)) 409 throw new WinstoneException(AJP_RESOURCES 410 .getString("Ajp13Listener.InvalidHeader")); 411 412 int packetLength = ((headerBuffer[2] & 0xFF) << 8) 414 + (headerBuffer[3] & 0xFF); 415 if (packetLength == 0) 416 return offset; 417 418 byte bodyLengthBuffer[] = new byte[2]; 420 in.read(bodyLengthBuffer); 421 int bodyLength = ((bodyLengthBuffer[0] & 0xFF) << 8) 422 + (bodyLengthBuffer[1] & 0xFF); 423 int packetBytesRead = in.read(buffer, offset, bodyLength); 424 425 if (packetBytesRead < bodyLength) 426 throw new WinstoneException(AJP_RESOURCES 427 .getString("Ajp13Listener.ShortPacket")); 428 else 429 return packetBytesRead + offset; 430 } 431 } 453 | Popular Tags |