} else { /* figure out what kind of connection this is */ newconnection = true; if (https) { if (sslContext == null) { logger.warning ("SSL connection received. No https contxt created"); throw new HttpError ("No SSL context established"); } sslStreams = new SSLStreams (ServerImpl.this, sslContext, chan); rawin = sslStreams.getInputStream(); rawout = sslStreams.getOutputStream(); engine = sslStreams.getSSLEngine(); connection.sslStreams = sslStreams; } else { rawin = new BufferedInputStream( new Request.ReadStream ( ServerImpl.this, chan )); rawout = new Request.WriteStream ( ServerImpl.this, chan ); } connection.raw = rawin; connection.rawout = rawout; } Request req = new Request (rawin, rawout); requestLine = req.requestLine(); if (requestLine == null) { /* connection closed */ closeConnection(connection); return; } int space = requestLine.indexOf (' '); if (space == -1) { reject (Code.HTTP_BAD_REQUEST, requestLine, "Bad request line"); return; } String method = requestLine.substring (0, space); int start = space+1; space = requestLine.indexOf(' ', start); if (space == -1) { reject (Code.HTTP_BAD_REQUEST, requestLine, "Bad request line"); return; } String uriStr = requestLine.substring (start, space); URI uri = new URI (uriStr); start = space+1; String version = requestLine.substring (start); Headers headers = req.headers(); String s = headers.getFirst ("Transfer-encoding"); long clen = 0L; if (s !=null && s.equalsIgnoreCase ("chunked")) { clen = -1L; } else { s = headers.getFirst ("Content-Length"); if (s != null) { clen = Long.parseLong(s); } if (clen == 0) { requestCompleted (connection); } } ctx = contexts.findContext (protocol, uri.getPath()); if (ctx == null) { reject (Code.HTTP_NOT_FOUND, requestLine, "No context found for request"); return; } connection.setContext (ctx); if (ctx.getHandler() == null) { reject (Code.HTTP_INTERNAL_ERROR, requestLine, "No handler for context"); return; } tx = new ExchangeImpl ( method, uri, req, clen, connection ); String chdr = headers.getFirst("Connection"); Headers rheaders = tx.getResponseHeaders(); if (chdr != null && chdr.equalsIgnoreCase ("close")) { tx.close = true; } if (version.equalsIgnoreCase ("http/1.0")) { tx.http10 = true; if (chdr == null) { tx.close = true; rheaders.set ("Connection", "close"); } else if (chdr.equalsIgnoreCase ("keep-alive")) { rheaders.set ("Connection", "keep-alive"); int idle=(int)ServerConfig.getIdleInterval()/1000; int max=(int)ServerConfig.getMaxIdleConnections(); String val = "timeout="+idle+", max="+max; rheaders.set ("Keep-Alive", val); } } if (newconnection) { connection.setParameters ( rawin, rawout, chan, engine, sslStreams, sslContext, protocol, ctx, rawin ); } /* check if client sent an Expect 100 Continue. * In that case, need to send an interim response. * In future API may be modified to allow app to * be involved in this process. */ String exp = headers.getFirst("Expect"); if (exp != null && exp.equalsIgnoreCase ("100-continue")) { logReply (100, requestLine, null); sendReply ( Code.HTTP_CONTINUE, false, null ); } /* uf is the list of filters seen/set by the user. * sf is the list of filters established internally * and which are not visible to the user. uc and sc * are the corresponding Filter.Chains. * They are linked together by a LinkHandler * so that they can both be invoked in one call. */ List<Filter> sf = ctx.getSystemFilters(); List<Filter> uf = ctx.getFilters(); Filter.Chain sc = new Filter.Chain(sf, ctx.getHandler()); Filter.Chain uc = new Filter.Chain(uf, new LinkHandler (sc)); /* set up the two stream references */ tx.getRequestBody(); tx.getResponseBody(); if (https) { uc.doFilter (new HttpsExchangeImpl (tx)); } else { uc.doFilter (new HttpExchangeImpl (tx)); } } catch (IOException e1) { logger.log (Level.FINER, "ServerImpl.Exchange (1)", e1); closeConnection(connection); } catch (NumberFormatException e3) { reject (Code.HTTP_BAD_REQUEST, requestLine, "NumberFormatException thrown"); } catch (URISyntaxException e) { reject (Code.HTTP_BAD_REQUEST, requestLine, "URISyntaxException thrown"); } catch (Exception e4) { logger.log (Level.FINER, "ServerImpl.Exchange (2)", e4); closeConnection(connection); } } /* used to link to 2 or more Filter.Chains together */ class LinkHandler implements HttpHandler { Filter.Chain nextChain; LinkHandler (Filter.Chain nextChain) { this.nextChain = nextChain; } public void handle (HttpExchange exchange) throws IOException { nextChain.doFilter (exchange); } } void reject (int code, String requestStr, String message) { rejected = true; logReply (code, requestStr, message); sendReply ( code, false, "<h1>"+code+Code.msg(code)+"</h1>"+message ); closeConnection(connection); } void sendReply ( int code, boolean closeNow, String text) { try { StringBuilder builder = new StringBuilder (512); builder.append ("HTTP/1.1 ") .append (code).append (Code.msg(code)).append ("\r\n"); if (text != null && text.length() != 0) { builder.append ("Content-Length: ") .append (text.length()).append ("\r\n") .append ("Content-Type: text/html\r\n"); } else { builder.append ("Content-Length: 0\r\n"); text = ""; } if (closeNow) { builder.append ("Connection: close\r\n"); } builder.append ("\r\n").append (text); String s = builder.toString(); byte[] b = s.getBytes("ISO8859_1"); rawout.write (b); rawout.flush(); if (closeNow) { closeConnection(connection); } } catch (IOException e) { logger.log (Level.FINER, "ServerImpl.sendReply", e); closeConnection(connection); } } } void logReply (int code, String requestStr, String text) { if (!logger.isLoggable(Level.FINE)) { return; } if (text == null) { text = ""; } String r; if (requestStr.length() > 80) { r = requestStr.substring (0, 80) + "<TRUNCATED>"; } else { r = requestStr; } String message = r + " [" + code + " " + Code.msg(code) + "] ("+text+")"; logger.fine (message); } long getTicks() { return ticks; } public long getTime() { return time; } void delay () { Thread.yield(); try { Thread.sleep (200); } catch (InterruptedException e) {} } private int exchangeCount = 0; synchronized void startExchange () { exchangeCount ++; } synchronized int endExchange () { exchangeCount --; assert exchangeCount >= 0; return exchangeCount; } HttpServer getWrapper () { return wrapper; } void requestStarted (HttpConnection c) { c.creationTime = getTime(); c.setState (State.REQUEST); reqConnections.add (c); } // called after a request has been completely read // by the server. This stops the timer which would // close the connection if the request doesn't arrive // quickly enough. It then starts the timer // that ensures the client reads the response in a timely // fashion. void requestCompleted (HttpConnection c) { assert c.getState() == State.REQUEST; reqConnections.remove (c); c.rspStartedTime = getTime(); rspConnections.add (c); c.setState (State.RESPONSE); } // called after response has been sent void responseCompleted (HttpConnection c) { assert c.getState() == State.RESPONSE; rspConnections.remove (c); c.setState (State.IDLE); } /** * TimerTask run every CLOCK_TICK ms */ class ServerTimerTask extends TimerTask { public void run () { LinkedList<HttpConnection> toClose = new LinkedList<HttpConnection>(); time = System.currentTimeMillis(); ticks ++; synchronized (idleConnections) { for (HttpConnection c : idleConnections) { if (c.time <= time) { toClose.add (c); } } for (HttpConnection c : toClose) { idleConnections.remove (c); allConnections.remove (c); c.close(); } } } } class ServerTimerTask1 extends TimerTask { // runs every TIMER_MILLIS public void run () { LinkedList<HttpConnection> toClose = new LinkedList<HttpConnection>(); time = System.currentTimeMillis(); synchronized (reqConnections) { if (MAX_REQ_TIME != -1) { for (HttpConnection c : reqConnections) { if (c.creationTime + TIMER_MILLIS + MAX_REQ_TIME <= time) { toClose.add (c); } } for (HttpConnection c : toClose) { logger.log (Level.FINE, "closing: no request: " + c); reqConnections.remove (c); allConnections.remove (c); c.close(); } } } toClose = new LinkedList<HttpConnection>(); synchronized (rspConnections) { if (MAX_RSP_TIME != -1) { for (HttpConnection c : rspConnections) { if (c.rspStartedTime + TIMER_MILLIS +MAX_RSP_TIME <= time) { toClose.add (c); } } for (HttpConnection c : toClose) { logger.log (Level.FINE, "closing: no response: " + c); rspConnections.remove (c); allConnections.remove (c); c.close(); } } } } } void logStackTrace (String s) { logger.finest (s); StringBuilder b = new StringBuilder (); StackTraceElement[] e = Thread.currentThread().getStackTrace(); for (int i=0; i<e.length; i++) { b.append (e[i].toString()).append("\n"); } logger.finest (b.toString()); } static long getTimeMillis(long secs) { if (secs == -1) { return -1; } else { return secs * 1000; } }}Lines 501–870 of 870. Previous lines
} else { /* figure out what kind of connection this is */ newconnection = true; if (https) { if (sslContext == null) { logger.warning ("SSL connection received. No https contxt created"); throw new HttpError ("No SSL context established"); } sslStreams = new SSLStreams (ServerImpl.this, sslContext, chan); rawin = sslStreams.getInputStream(); rawout = sslStreams.getOutputStream(); engine = sslStreams.getSSLEngine(); connection.sslStreams = sslStreams; } else { rawin = new BufferedInputStream( new Request.ReadStream ( ServerImpl.this, chan )); rawout = new Request.WriteStream ( ServerImpl.this, chan ); } connection.raw = rawin; connection.rawout = rawout; } Request req = new Request (rawin, rawout); requestLine = req.requestLine(); if (requestLine == null) { /* connection closed */ closeConnection(connection); return; } int space = requestLine.indexOf (' '); if (space == -1) { reject (Code.HTTP_BAD_REQUEST, requestLine, "Bad request line"); return; } String method = requestLine.substring (0, space); int start = space+1; space = requestLine.indexOf(' ', start); if (space == -1) { reject (Code.HTTP_BAD_REQUEST, requestLine, "Bad request line"); return; } String uriStr = requestLine.substring (start, space); URI uri = new URI (uriStr); start = space+1; String version = requestLine.substring (start); Headers headers = req.headers(); String s = headers.getFirst ("Transfer-encoding"); long clen = 0L; if (s !=null && s.equalsIgnoreCase ("chunked")) { clen = -1L; } else { s = headers.getFirst ("Content-Length"); if (s != null) { clen = Long.parseLong(s); } if (clen == 0) { requestCompleted (connection); } } ctx = contexts.findContext (protocol, uri.getPath()); if (ctx == null) { reject (Code.HTTP_NOT_FOUND, requestLine, "No context found for request"); return; } connection.setContext (ctx); if (ctx.getHandler() == null) { reject (Code.HTTP_INTERNAL_ERROR, requestLine, "No handler for context"); return; } tx = new ExchangeImpl ( method, uri, req, clen, connection ); String chdr = headers.getFirst("Connection"); Headers rheaders = tx.getResponseHeaders(); if (chdr != null && chdr.equalsIgnoreCase ("close")) { tx.close = true; } if (version.equalsIgnoreCase ("http/1.0")) { tx.http10 = true; if (chdr == null) { tx.close = true; rheaders.set ("Connection", "close"); } else if (chdr.equalsIgnoreCase ("keep-alive")) { rheaders.set ("Connection", "keep-alive"); int idle=(int)ServerConfig.getIdleInterval()/1000; int max=(int)ServerConfig.getMaxIdleConnections(); String val = "timeout="+idle+", max="+max; rheaders.set ("Keep-Alive", val); } } if (newconnection) { connection.setParameters ( rawin, rawout, chan, engine, sslStreams, sslContext, protocol, ctx, rawin ); } /* check if client sent an Expect 100 Continue. * In that case, need to send an interim response. * In future API may be modified to allow app to * be involved in this process. */ String exp = headers.getFirst("Expect"); if (exp != null && exp.equalsIgnoreCase ("100-continue")) { logReply (100, requestLine, null); sendReply ( Code.HTTP_CONTINUE, false, null ); } /* uf is the list of filters seen/set by the user. * sf is the list of filters established internally * and which are not visible to the user. uc and sc * are the corresponding Filter.Chains. * They are linked together by a LinkHandler * so that they can both be invoked in one call. */ List<Filter> sf = ctx.getSystemFilters(); List<Filter> uf = ctx.getFilters(); Filter.Chain sc = new Filter.Chain(sf, ctx.getHandler()); Filter.Chain uc = new Filter.Chain(uf, new LinkHandler (sc)); /* set up the two stream references */ tx.getRequestBody(); tx.getResponseBody(); if (https) { uc.doFilter (new HttpsExchangeImpl (tx)); } else { uc.doFilter (new HttpExchangeImpl (tx)); } } catch (IOException e1) { logger.log (Level.FINER, "ServerImpl.Exchange (1)", e1); closeConnection(connection); } catch (NumberFormatException e3) { reject (Code.HTTP_BAD_REQUEST, requestLine, "NumberFormatException thrown"); } catch (URISyntaxException e) { reject (Code.HTTP_BAD_REQUEST, requestLine, "URISyntaxException thrown"); } catch (Exception e4) { logger.log (Level.FINER, "ServerImpl.Exchange (2)", e4); closeConnection(connection); } } /* used to link to 2 or more Filter.Chains together */ class LinkHandler implements HttpHandler { Filter.Chain nextChain; LinkHandler (Filter.Chain nextChain) { this.nextChain = nextChain; } public void handle (HttpExchange exchange) throws IOException { nextChain.doFilter (exchange); } } void reject (int code, String requestStr, String message) { rejected = true; logReply (code, requestStr, message); sendReply ( code, false, "<h1>"+code+Code.msg(code)+"</h1>"+message ); closeConnection(connection); } void sendReply ( int code, boolean closeNow, String text) { try { StringBuilder builder = new StringBuilder (512); builder.append ("HTTP/1.1 ") .append (code).append (Code.msg(code)).append ("\r\n"); if (text != null && text.length() != 0) { builder.append ("Content-Length: ") .append (text.length()).append ("\r\n") .append ("Content-Type: text/html\r\n"); } else { builder.append ("Content-Length: 0\r\n"); text = ""; } if (closeNow) { builder.append ("Connection: close\r\n"); } builder.append ("\r\n").append (text); String s = builder.toString(); byte[] b = s.getBytes("ISO8859_1"); rawout.write (b); rawout.flush(); if (closeNow) { closeConnection(connection); } } catch (IOException e) { logger.log (Level.FINER, "ServerImpl.sendReply", e); closeConnection(connection); } } } void logReply (int code, String requestStr, String text) { if (!logger.isLoggable(Level.FINE)) { return; } if (text == null) { text = ""; } String r; if (requestStr.length() > 80) { r = requestStr.substring (0, 80) + "<TRUNCATED>"; } else { r = requestStr; } String message = r + " [" + code + " " + Code.msg(code) + "] ("+text+")"; logger.fine (message); } long getTicks() { return ticks; } public long getTime() { return time; } void delay () { Thread.yield(); try { Thread.sleep (200); } catch (InterruptedException e) {} } private int exchangeCount = 0; synchronized void startExchange () { exchangeCount ++; } synchronized int endExchange () { exchangeCount --; assert exchangeCount >= 0; return exchangeCount; } HttpServer getWrapper () { return wrapper; } void requestStarted (HttpConnection c) { c.creationTime = getTime(); c.setState (State.REQUEST); reqConnections.add (c); } // called after a request has been completely read // by the server. This stops the timer which would // close the connection if the request doesn't arrive // quickly enough. It then starts the timer // that ensures the client reads the response in a timely // fashion. void requestCompleted (HttpConnection c) { assert c.getState() == State.REQUEST; reqConnections.remove (c); c.rspStartedTime = getTime(); rspConnections.add (c); c.setState (State.RESPONSE); } // called after response has been sent void responseCompleted (HttpConnection c) { assert c.getState() == State.RESPONSE; rspConnections.remove (c); c.setState (State.IDLE); } /** * TimerTask run every CLOCK_TICK ms */ class ServerTimerTask extends TimerTask { public void run () { LinkedList<HttpConnection> toClose = new LinkedList<HttpConnection>(); time = System.currentTimeMillis(); ticks ++; synchronized (idleConnections) { for (HttpConnection c : idleConnections) { if (c.time <= time) { toClose.add (c); } } for (HttpConnection c : toClose) { idleConnections.remove (c); allConnections.remove (c); c.close(); } } } } class ServerTimerTask1 extends TimerTask { // runs every TIMER_MILLIS public void run () { LinkedList<HttpConnection> toClose = new LinkedList<HttpConnection>(); time = System.currentTimeMillis(); synchronized (reqConnections) { if (MAX_REQ_TIME != -1) { for (HttpConnection c : reqConnections) { if (c.creationTime + TIMER_MILLIS + MAX_REQ_TIME <= time) { toClose.add (c); } } for (HttpConnection c : toClose) { logger.log (Level.FINE, "closing: no request: " + c); reqConnections.remove (c); allConnections.remove (c); c.close(); } } } toClose = new LinkedList<HttpConnection>(); synchronized (rspConnections) { if (MAX_RSP_TIME != -1) { for (HttpConnection c : rspConnections) { if (c.rspStartedTime + TIMER_MILLIS +MAX_RSP_TIME <= time) { toClose.add (c); } } for (HttpConnection c : toClose) { logger.log (Level.FINE, "closing: no response: " + c); rspConnections.remove (c); allConnections.remove (c); c.close(); } } } } } void logStackTrace (String s) { logger.finest (s); StringBuilder b = new StringBuilder (); StackTraceElement[] e = Thread.currentThread().getStackTrace(); for (int i=0; i<e.length; i++) { b.append (e[i].toString()).append("\n"); } logger.finest (b.toString()); } static long getTimeMillis(long secs) { if (secs == -1) { return -1; } else { return secs * 1000; } } }