1 7 package winstone; 8 9 import java.io.IOException ; 10 import java.io.InputStream ; 11 import java.io.InterruptedIOException ; 12 import java.io.OutputStream ; 13 import java.net.InetAddress ; 14 import java.net.ServerSocket ; 15 import java.net.Socket ; 16 import java.net.SocketException ; 17 import java.util.ArrayList ; 18 import java.util.List ; 19 import java.util.Map ; 20 21 29 public class HttpListener implements Listener, Runnable { 30 protected static int LISTENER_TIMEOUT = 5000; protected static int CONNECTION_TIMEOUT = 60000; 33 protected static int BACKLOG_COUNT = 5000; 34 protected static boolean DEFAULT_HNL = false; 35 protected static int KEEP_ALIVE_TIMEOUT = 10000; 36 protected static int KEEP_ALIVE_SLEEP = 20; 37 protected static int KEEP_ALIVE_SLEEP_MAX = 500; 38 protected HostGroup hostGroup; 39 protected ObjectPool objectPool; 40 protected boolean doHostnameLookups; 41 protected int listenPort; 42 protected String listenAddress; 43 protected boolean interrupted; 44 45 protected HttpListener() { 46 } 47 48 51 public HttpListener(Map args, ObjectPool objectPool, HostGroup hostGroup) throws IOException { 52 this.hostGroup = hostGroup; 54 this.objectPool = objectPool; 55 this.listenPort = Integer.parseInt(WebAppConfiguration.stringArg(args, 56 getConnectorName() + "Port", "" + getDefaultPort())); 57 this.listenAddress = WebAppConfiguration.stringArg(args, 58 getConnectorName() + "ListenAddress", null); 59 this.doHostnameLookups = WebAppConfiguration.booleanArg(args, 60 getConnectorName() + "DoHostnameLookups", DEFAULT_HNL); 61 } 62 63 public boolean start() { 64 if (this.listenPort < 0) { 65 return false; 66 } else { 67 this.interrupted = false; 68 Thread thread = new Thread (this, Launcher.RESOURCES.getString( 69 "Listener.ThreadName", new String [] { getConnectorName(), 70 "" + this.listenPort })); 71 thread.setDaemon(true); 72 thread.start(); 73 return true; 74 } 75 } 76 77 81 protected int getDefaultPort() { 82 return 8080; 83 } 84 85 89 protected String getConnectorName() { 90 return getConnectorScheme(); 91 } 92 93 protected String getConnectorScheme() { 94 return "http"; 95 } 96 97 101 protected ServerSocket getServerSocket() throws IOException { 102 ServerSocket ss = this.listenAddress == null ? new ServerSocket ( 103 this.listenPort, BACKLOG_COUNT) : new ServerSocket ( 104 this.listenPort, BACKLOG_COUNT, InetAddress 105 .getByName(this.listenAddress)); 106 return ss; 107 } 108 109 114 public void run() { 115 try { 116 ServerSocket ss = getServerSocket(); 117 ss.setSoTimeout(LISTENER_TIMEOUT); 118 Logger.log(Logger.INFO, Launcher.RESOURCES, "HttpListener.StartupOK", 119 new String [] { getConnectorName().toUpperCase(), 120 this.listenPort + "" }); 121 122 while (!interrupted) { 124 Socket s = null; 126 try { 127 s = ss.accept(); 128 } catch (java.io.InterruptedIOException err) { 129 s = null; 130 } 131 132 if (s != null) 135 this.objectPool.handleRequest(s, this); 136 } 137 138 ss.close(); 140 } catch (Throwable err) { 141 Logger.log(Logger.ERROR, Launcher.RESOURCES, "HttpListener.ShutdownError", 142 getConnectorName().toUpperCase(), err); 143 } 144 145 Logger.log(Logger.INFO, Launcher.RESOURCES, "HttpListener.ShutdownOK", 146 getConnectorName().toUpperCase()); 147 } 148 149 153 public void destroy() { 154 this.interrupted = true; 155 } 156 157 166 public void allocateRequestResponse(Socket socket, InputStream inSocket, 167 OutputStream outSocket, RequestHandlerThread handler, 168 boolean iAmFirst) throws SocketException , IOException { 169 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, 170 "HttpListener.AllocatingRequest", Thread.currentThread() 171 .getName()); 172 socket.setSoTimeout(CONNECTION_TIMEOUT); 173 174 WinstoneInputStream inData = new WinstoneInputStream(inSocket); 176 WinstoneOutputStream outData = new WinstoneOutputStream(outSocket, false); 177 WinstoneRequest req = this.objectPool.getRequestFromPool(); 178 WinstoneResponse rsp = this.objectPool.getResponseFromPool(); 179 outData.setResponse(rsp); 180 req.setInputStream(inData); 181 rsp.setOutputStream(outData); 182 rsp.setRequest(req); 183 req.setHostGroup(this.hostGroup); 185 186 handler.setRequest(req); 188 handler.setResponse(rsp); 189 handler.setInStream(inData); 190 handler.setOutStream(outData); 191 192 rsp.setHeader(WinstoneResponse.SERVER_HEADER, 196 Launcher.RESOURCES.getString("ServerVersion")); 197 } 198 199 204 public void deallocateRequestResponse(RequestHandlerThread handler, 205 WinstoneRequest req, WinstoneResponse rsp, 206 WinstoneInputStream inData, WinstoneOutputStream outData) 207 throws IOException { 208 handler.setInStream(null); 209 handler.setOutStream(null); 210 handler.setRequest(null); 211 handler.setResponse(null); 212 if (req != null) 213 this.objectPool.releaseRequestToPool(req); 214 if (rsp != null) 215 this.objectPool.releaseResponseToPool(rsp); 216 } 217 218 public String parseURI(RequestHandlerThread handler, WinstoneRequest req, 219 WinstoneResponse rsp, WinstoneInputStream inData, Socket socket, 220 boolean iAmFirst) throws IOException { 221 parseSocketInfo(socket, req); 222 223 if (!iAmFirst) { 226 socket.setSoTimeout(KEEP_ALIVE_TIMEOUT); 227 } 228 229 byte uriBuffer[] = null; 230 try { 231 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "HttpListener.WaitingForURILine"); 232 uriBuffer = inData.readLine(); 233 } catch (InterruptedIOException err) { 234 if (iAmFirst) { 236 throw err; 237 } else { 238 return null; 239 } 240 } finally { 241 try {socket.setSoTimeout(CONNECTION_TIMEOUT);} catch (Throwable err) {} 242 } 243 handler.setRequestStartTime(); 244 245 String uriLine = new String (uriBuffer); 247 if (uriLine.trim().equals("")) 248 throw new SocketException ("Empty URI Line"); 249 String servletURI = parseURILine(uriLine, req, rsp); 250 parseHeaders(req, inData); 251 rsp.extractRequestKeepAliveHeader(req); 252 int contentLength = req.getContentLength(); 253 if (contentLength != -1) 254 inData.setContentLength(contentLength); 255 return servletURI; 256 } 257 258 265 public void releaseSocket(Socket socket, InputStream inSocket, 266 OutputStream outSocket) throws IOException { 267 inSocket.close(); 270 outSocket.close(); 271 socket.close(); 272 } 273 274 protected void parseSocketInfo(Socket socket, WinstoneRequest req) 275 throws IOException { 276 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "HttpListener.ParsingSocketInfo"); 277 req.setScheme(getConnectorScheme()); 278 req.setServerPort(socket.getLocalPort()); 279 req.setLocalPort(socket.getLocalPort()); 280 req.setLocalAddr(socket.getLocalAddress().getHostAddress()); 281 req.setRemoteIP(socket.getInetAddress().getHostAddress()); 282 req.setRemotePort(socket.getPort()); 283 if (this.doHostnameLookups) { 284 req.setServerName(socket.getLocalAddress().getHostName()); 285 req.setRemoteName(socket.getInetAddress().getHostName()); 286 req.setLocalName(socket.getLocalAddress().getHostName()); 287 } else { 288 req.setServerName(socket.getLocalAddress().getHostAddress()); 289 req.setRemoteName(socket.getInetAddress().getHostAddress()); 290 req.setLocalName(socket.getLocalAddress().getHostAddress()); 291 } 292 } 293 294 302 public boolean processKeepAlive(WinstoneRequest request, 303 WinstoneResponse response, InputStream inSocket) 304 throws IOException , InterruptedException { 305 boolean continueFlag = !response.closeAfterRequest(); 307 return continueFlag; 308 } 309 310 314 private String parseURILine(String uriLine, WinstoneRequest req, 315 WinstoneResponse rsp) { 316 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "HttpListener.UriLine", uriLine.trim()); 317 318 int spacePos = uriLine.indexOf(' '); 320 if (spacePos == -1) 321 throw new WinstoneException(Launcher.RESOURCES.getString( 322 "HttpListener.ErrorUriLine", uriLine)); 323 String method = uriLine.substring(0, spacePos).toUpperCase(); 324 String fullURI = null; 325 326 String remainder = uriLine.substring(spacePos + 1); 328 spacePos = remainder.indexOf(' '); 329 if (spacePos == -1) { 330 fullURI = trimHostName(remainder.trim()); 331 req.setProtocol("HTTP/0.9"); 332 rsp.setProtocol("HTTP/0.9"); 333 } else { 334 fullURI = trimHostName(remainder.substring(0, spacePos).trim()); 335 String protocol = remainder.substring(spacePos + 1).trim().toUpperCase(); 336 req.setProtocol(protocol); 337 rsp.setProtocol(protocol); 338 } 339 340 req.setMethod(method); 341 return fullURI; 343 } 344 345 private String trimHostName(String input) { 346 if (input == null) 347 return null; 348 else if (input.startsWith("/")) 349 return input; 350 351 int hostStart = input.indexOf("://"); 352 if (hostStart == -1) 353 return input; 354 String hostName = input.substring(hostStart + 3); 355 int pathStart = hostName.indexOf('/'); 356 if (pathStart == -1) 357 return "/"; 358 else 359 return hostName.substring(pathStart); 360 } 361 362 366 public void parseHeaders(WinstoneRequest req, WinstoneInputStream inData) 367 throws IOException { 368 List headerList = new ArrayList (); 369 370 if (!req.getProtocol().startsWith("HTTP/0")) { 371 byte headerBuffer[] = inData.readLine(); 373 String headerLine = new String (headerBuffer); 374 375 while (headerLine.trim().length() > 0) { 376 if (headerLine.indexOf(':') != -1) { 377 headerList.add(headerLine.trim()); 378 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, 379 "HttpListener.Header", headerLine.trim()); 380 } 381 headerBuffer = inData.readLine(); 382 headerLine = new String (headerBuffer); 383 } 384 } 385 386 req.parseHeaders(headerList); 388 } 389 } 390 | Popular Tags |