connection.java
来自「一款Java实现的HTTP代理服务器」· Java 代码 · 共 1,060 行 · 第 1/2 页
JAVA
1,060 行
handleRequest (); return true; } // send the cached entry. return false; } private class TDL implements TunnelDoneListener { private RequestHandler rh; public TDL (RequestHandler rh) { this.rh = rh; } public void tunnelClosed () { logAndClose (rh); } } private void tryStaleEntry (RequestHandler rh, Exception e) { // do we have a stale entry? if (rh.entry != null && rh.conditional && !mustRevalidate) { handleStaleEntry (rh); } else { doError (504, e); return; } } private void handleStaleEntry (RequestHandler rh) { setMayCache (false); try { setupCachedEntry (rh); rh.webHeader.addHeader ("Warning", "110 RabbIT \"Response is stale\""); resourceEstablished (rh); } catch (IOException ex) { doError (504, ex); return; } } HttpHeader setupCachedEntry (RequestHandler rh) throws IOException { SCC swc = new SCC (this, request, requestBuffer, rh); HttpHeader ret = swc.establish (); return ret; } private void setupChunkedContent () throws IOException { setMayUseCache (false); setMayCache (false); clientResourceHandler = new ChunkedContentTransferHandler (this, requestBuffer, tlh); } private void setupClientResourceHandler (long dataSize) { setMayUseCache (false); setMayCache (false); clientResourceHandler = new ContentTransferHandler (this, requestBuffer, dataSize, tlh); } private void readMultiPart (String ct) { // Content-Type: multipart/byteranges; boundary=B-qpuvxclkeavxeywbqupw if (ct.startsWith ("multipart/byteranges")) { setMayUseCache (false); setMayCache (false); clientResourceHandler = new MultiPartTransferHandler (this, requestBuffer, tlh, ct); } } /** Handles the case where the request does not have a valid body. * @param header the request made. */ private void handleBadContent (HttpHeader header, String desc) { getLogger ().logDebug ("bad content for:\n" + header); doError (400, "Bad content: " + desc); } private boolean partialContent (RequestHandler rh) { if (rh.entry == null) return false; String method = request.getMethod (); if (!method.equals ("GET")) return false; HttpHeader resp = rh.dataHook; String realLength = resp.getHeader ("RabbIT-Partial"); return (realLength != null); } private void fillupContent (RequestHandler rh) { setMayUseCache (false); setMayCache (true); // TODO: if the need arise, think about implementing smart partial updates. } private void checkIfRange (RequestHandler rh) { CacheEntry entry = rh.entry; if (entry == null) return; String ifRange = request.getHeader ("If-Range"); if (ifRange == null) return; String range = request.getHeader ("Range"); if (range == null) return; Date d = HttpDateParser.getDate (ifRange); HttpHeader oldresp = rh.dataHook; if (d == null) { // we have an etag... String etag = oldresp.getHeader ("Etag"); if (etag == null || !checkWeakEtag (etag, ifRange)) setMayUseCache (false); } } /** Send an error (400 Bad Request) to the client. * @param status the status code of the error. * @param message the error message to tell the client. */ public void doError (int status, String message) { this.statusCode = Integer.toString (status); HttpHeader header = responseHandler.getHeader ("HTTP/1.0 400 Bad Request"); StringBuilder error = new StringBuilder (HtmlPage.getPageHeader (this, "400 Bad Request") + "Unable to handle request:<br><b>" + message + "</b></body></html>\n"); header.setContent (error.toString ()); sendAndClose (header); } /** Send an error (400 Bad Request or 504) to the client. * @param statuscode the status code of the error. * @param e the exception to tell the client. */ public void doError (int statuscode, Exception e) { StringWriter sw = new StringWriter (); PrintWriter ps = new PrintWriter (sw); e.printStackTrace (ps); String message = sw.toString (); this.statusCode = Integer.toString (statuscode); extraInfo = (extraInfo != null ? extraInfo + e.toString () : e.toString ()); HttpHeader header = null; if (statuscode == 504) header = getHttpGenerator ().get504 (e, requestLine); else header = getHttpGenerator ().getHeader ("HTTP/1.0 400 Bad Request"); StringBuilder sb = new StringBuilder (); sb.append (HtmlPage.getPageHeader (this, statuscode + " " + header.getReasonPhrase ()) + "Unable to handle request:<br><b>" + e.getMessage () + (header.getContent () != null ? "<br>" + header.getContent () : "") + "</b><br><xmp>" + message + "</xmp></body></html>\n"); header.setContent (sb.toString ()); sendAndClose (header); } private void checkAndHandleSSL (ByteBuffer buffer) { SSLHandler sslh = new SSLHandler (proxy, this, request, tlh); if (sslh.isAllowed ()) { sslh.handle (channel, selector, buffer); } else { HttpHeader badresponse = responseHandler.get403 (); sendAndClose (badresponse); } } public SocketChannel getChannel () { return channel; } public Selector getSelector () { return selector; } public HttpProxy getProxy () { return proxy; } private void closeDown () { try { channel.close (); } catch (IOException e) { getLogger ().logWarn ("Failed to close down connection: " + e); } proxy.removeCurrentConnection (this); } public Logger getLogger () { return proxy.getLogger (); } private ConnectionLogger getConnectionLogger () { return proxy.getConnectionLogger (); } public Counter getCounter () { return proxy.getCounter (); } /** Resets the statuses for this connection. */ private void clearStatuses () { status = "Reading request"; started = System.currentTimeMillis (); request = null; keepalive = true; meta = false; chunk = true; mayUseCache = true; mayCache = true; mayFilter = true; mustRevalidate = false; addedINM = false; addedIMS = false; userName = null; password = null; requestLine = "?"; statusCode = "200"; extraInfo = null; contentLength = "-"; clientResourceHandler = null; } /** Set keepalive to a new value. Note that keepalive can only be * promoted down. * @param keepalive the new keepalive value. */ public void setKeepalive (boolean keepalive) { this.keepalive = (this.keepalive && keepalive); } /** Get the keepalive value. * @return true if keepalive should be done, false otherwise. */ public boolean getKeepalive () { return keepalive; } public String getUserName () { return userName; } public void setUserName (String userName) { this.userName = userName; } public String getPassword () { return password; } public void setPassword (String password) { this.password = password; } public String getRequestLine () { return requestLine; } /** Get the http version that the client used. * We modify the request header to hold HTTP/1.1 since that is * what rabbit uses, but the real client may have sent a 1.0 header. */ public String getRequestVersion () { return requestVersion; } public String getStatus () { return status; } public String getStatusCode () { return statusCode; } public String getContentLength () { return contentLength; } public String getExtraInfo () { return extraInfo; } /** Set the extra info. * @param info the new info. */ public void setExtraInfo (String info) { this.extraInfo = info; } /** Get the time this connection was started. */ public long getStarted () { return started; } /** Set the chunking option. * @param b if true this connection should use chunking. */ public void setChunking (boolean b) { chunk = b; } /** Get the chunking option. * @return if this connection is using chunking. */ public boolean getChunking () { return chunk; } /** Get the state of this request. * @return true if this is a metapage request, false otherwise. */ public boolean getMeta () { return meta; } /** Set the state of this request. * @param meta true if this request is a metapage request, false otherwise. */ public void setMeta (boolean meta) { this.meta = meta; } /** Set the state of this request. This can only be promoted down.. * @param useCache true if we may use the cache for this request, * false otherwise. */ public void setMayUseCache (boolean useCache) { mayUseCache = mayUseCache && useCache; } /** Get the state of this request. * @return true if we may use the cache for this request, false otherwise. */ public boolean getMayUseCache () { return mayUseCache; } /** Set the state of this request. This can only be promoted down. * @param cacheAllowed true if we may cache the response, false otherwise. */ public void setMayCache (boolean cacheAllowed) { mayCache = cacheAllowed && mayCache; } /** Get the state of this request. * @return true if we may cache the response, false otherwise. */ public boolean getMayCache () { return mayCache; } /** Get the state of this request. This can only be promoted down. * @param filterAllowed true if we may filter the response, false otherwise. */ public void setMayFilter (boolean filterAllowed) { mayFilter = filterAllowed && mayFilter; } /** Get the state of the request. * @return true if we may filter the response, false otherwise. */ public boolean getMayFilter () { return mayFilter; } void setAddedINM (boolean b) { addedINM = b; } void setAddedIMS (boolean b) { addedIMS = b; } void setMustRevalidate (boolean b) { mustRevalidate = b; } /** Set the content length of the response. * @param contentLength the new content length. */ public void setContentLength (String contentLength) { this.contentLength = contentLength; } void setStatusCode (String statusCode) { this.statusCode = statusCode; } private void setStatusesFromHeader (HttpHeader header) { statusCode = header.getStatusCode (); String cl = header.getHeader ("Content-Length"); if (cl != null) contentLength = cl; } void sendAndRestart (HttpHeader header) { status = "Sending response."; setStatusesFromHeader (header); if (!keepalive) { sendAndClose (header); } else { HttpHeaderSentListener sar = new SendAndRestartListener (); try { HttpHeaderSender sender = new HttpHeaderSender (channel, selector, getLogger (), tlh.getClient (), header, false, sar); } catch (IOException e) { getLogger ().logWarn ("IOException when sending header: " + e); closeDown (); } } } public boolean useFullURI () { return proxy.isProxyConnected (); } private class SendAndRestartListener implements HttpHeaderSentListener { public void httpHeaderSent () { logConnection (); readRequest (); } public void timeout () { getLogger ().logInfo ("Timeout when sending http header"); logAndClose (null); } public void failed (Exception e) { getLogger ().logInfo ("Exception when sending http header: " + e); logAndClose (null); } } void sendAndClose (HttpHeader header) { status = "Sending response and closing."; setStatusesFromHeader (header); keepalive = false; HttpHeaderSentListener scl = new SendAndCloseListener (); try { HttpHeaderSender sender = new HttpHeaderSender (channel, selector, getLogger (), tlh.getClient (), header, false, scl); } catch (IOException e) { getLogger ().logWarn ("IOException when sending header: " + e); closeDown (); } } public void logAndClose (RequestHandler rh) { if (rh != null && rh.wc != null) { proxy.releaseWebConnection (rh.wc); } logConnection (); closeDown (); } public void logAndRestart () { logConnection (); if (getKeepalive ()) readRequest (); else closeDown (); } private class SendAndCloseListener implements HttpHeaderSentListener { public void httpHeaderSent () { logAndClose (null); } public void timeout () { getLogger ().logInfo ("Timeout when sending http header"); logAndClose (null); } public void failed (Exception e) { getLogger ().logInfo ("Exception when sending http header: " + e); logAndClose (null); } } boolean isWeak (String t) { return t.startsWith ("W/"); } boolean checkStrongEtag (String et, String im) { return !isWeak (im) && im.equals (et); } boolean checkWeakEtag (HttpHeader h1, HttpHeader h2) { String et1 = h1.getHeader ("Etag"); String et2 = h2.getHeader ("Etag"); if (et1 == null || et2 == null) return true; return checkWeakEtag (et1, et2); } boolean checkWeakEtag (String et, String im) { if (et == null || im == null) return false; if (isWeak (et)) et = et.substring (2); if (isWeak (im)) im = im.substring (2); return im.equals (et); } public HttpGenerator getHttpGenerator () { return responseHandler; } private void logConnection () { getConnectionLogger ().logConnection (Connection.this); proxy.updateTrafficLog (tlh); tlh.clear (); }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?