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 + -
显示快捷键?