basehandler.java

来自「一款Java实现的HTTP代理服务器」· Java 代码 · 共 551 行 · 第 1/2 页

JAVA
551
字号
package rabbit.handler;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.PrintWriter;import java.io.StringWriter;import java.nio.ByteBuffer;import java.nio.channels.SocketChannel;import java.nio.channels.WritableByteChannel;import java.util.Date;import java.util.StringTokenizer;import rabbit.cache.Cache;import rabbit.cache.CacheEntry;import rabbit.http.HttpDateParser;import rabbit.http.HttpHeader;import rabbit.http.ContentRangeParser;import rabbit.proxy.BlockSender;import rabbit.proxy.BlockSentListener;import rabbit.proxy.ChunkEnder;import rabbit.proxy.Connection;import rabbit.proxy.HttpHeaderSender;import rabbit.proxy.HttpHeaderSentListener;import rabbit.proxy.PartialCacher;import rabbit.proxy.TrafficLoggerHandler;import rabbit.proxy.TransferHandler;import rabbit.proxy.TransferListener;import rabbit.util.Logger;import rabbit.util.SProperties;/** This class is an implementation of the Handler interface. *  This handler does no filtering, it only sends the data as *  effective as it can. * * @author <a href="mailto:robo@khelekore.org">Robert Olofsson</a> */public class BaseHandler     implements Handler, HandlerFactory, HttpHeaderSentListener, BlockListener,                BlockSentListener {    /** The Connection handling the request.*/    protected Connection con;    /** The traffic logger handler. */    protected TrafficLoggerHandler tlh;    /** The actual request made. */    protected HttpHeader request;    /** The client buffer. */    protected ByteBuffer clientBuffer;    /** The actual response. */    protected HttpHeader response;    /** The resource */    protected ResourceSource content;    /** The cache entry if available. */    protected CacheEntry<HttpHeader, HttpHeader> entry = null;    /** The cache channel. */    protected WritableByteChannel cacheChannel;        /** May we cache this request. */    protected boolean mayCache;    /** May we filter this request */    protected boolean mayFilter;    /** The length of the data beeing handled or -1 if unknown.*/    protected long size = -1;    /** The total amount of data that we read. */    protected long totalRead = 0;    /** The flag for the last empty chunk */    private boolean emptyChunkSent = false;    /** For creating the factory.     */    public BaseHandler () {	    }        /** Create a new BaseHandler for the given request.     * @param con the Connection handling the request.     * @param request the actual request made.     * @param clientBuffer the client side buffer.     * @param response the actual response.     * @param content the resource.     * @param mayCache May we cache this request?      * @param mayFilter May we filter this request?     * @param size the size of the data beeing handled.     */    public BaseHandler (Connection con, TrafficLoggerHandler tlh, 			HttpHeader request, ByteBuffer clientBuffer,			HttpHeader response, ResourceSource content, 			boolean mayCache, boolean mayFilter, long size) {	this.con = con;	this.tlh = tlh;	this.request = request;	this.clientBuffer = clientBuffer;	this.response = response;	if (response == null)	    throw new IllegalArgumentException ("response may not be null");	this.content = content;	this.mayCache = mayCache;	this.mayFilter = mayFilter;	this.size = size;    }    public Handler getNewInstance (Connection con, TrafficLoggerHandler tlh, 				   HttpHeader header, ByteBuffer buffer, 				   HttpHeader webHeader, 				   ResourceSource content, boolean mayCache, 				   boolean mayFilter, long size) {	return new BaseHandler (con, tlh, header, buffer, webHeader, content, 				mayCache, mayFilter, size);    }    protected Logger getLogger () {	return con.getLogger ();    }    /** Handle the request.     * A request is made in these steps:      * <xmp>     * sendHeader ();      * addCache ();      * prepare ();     * send ();      * finishData ();     * finish ();     * </xmp>     * Note that finish is always called, no matter what exceptions are thrown.     * The middle steps are most probably only performed if the previous steps     * have all succeded     */    public void handle () {	sendHeader ();    }    /**      * ®return false this handler never modifies the content.     */    public boolean changesContentSize () {	return false;    }    protected void sendHeader () {	try {	    HttpHeaderSender responseSender = 		new HttpHeaderSender (con.getChannel (), con.getSelector (), 				      getLogger (), tlh.getClient (), 				      response, false, this);	} catch (IOException e) {	    failed (e);	}    }        public void httpHeaderSent () {	addCache ();	try {	    prepare ();	    send ();	} catch (IOException e) {	    failed (e);	}    }    /** This method is used to prepare the data for the resource being sent.     *  This method does nothing here.     */    protected void prepare () throws IOException {	// nothing here.    }        /** This method is used to finish the data for the resource being sent.     *  This method does nothing here.     */    protected void finishData () throws IOException {	// nothing here.    }        private void removePrivateParts (HttpHeader header, String type) {	for (String val : header.getHeaders ("Cache-Control")) {	    int j = val.indexOf (type);	    if (j >= 0) {		String p = val.substring (j + type.length ());		StringTokenizer st = new StringTokenizer (p, ",\"");		while (st.hasMoreTokens ()) {		    String t = st.nextToken ();		    header.removeHeader (t);		}	    }	}		    }    private void removePrivateParts (HttpHeader header) {	removePrivateParts (header, "private=");	removePrivateParts (header, "no-cache=");    }    /** Mark the current response as a partial response.      */    protected void setPartialContent (long got, long shouldbe) {	response.setHeader ("RabbIT-Partial", "" + shouldbe);    }        /** Close nesseccary channels and adjust the cached files.     *  If you override this one, remember to call super.finish ()!     * @param good if true then the connection may be restarted,      *             if false then the connection may not be restared     */    protected void finish (boolean good) {	boolean ok = false;	try {	    if (content != null)		content.release (con);	    if (cacheChannel != null) { 		try {		    cacheChannel.close ();		} catch (IOException e) {		    failed (e);		}	    }	    	    if (entry != null && mayCache) {		Cache<HttpHeader, HttpHeader> cache = 		    con.getProxy ().getCache ();		String entryName = 		    cache.getEntryName (entry.getId (), false);		File f = new File (entryName);		long filesize = f.length ();		entry.setSize (filesize);		String cl = response.getHeader ("Content-Length");		if (cl == null) {		    response.removeHeader ("Transfer-Encoding");		    response.setHeader ("Content-Length", "" + filesize);		}				removePrivateParts (response);		cache.addEntry (entry);	    }	    if (response != null 		&& response.getHeader ("Content-Length") != null)		con.setContentLength (response.getHeader ("Content-length"));	    	    ok = true;	} finally {	    // and clean up...	    request = null;	    response = null;	    content = null;	    entry = null;	    cacheChannel = null;	}	if (good && ok)	    con.logAndRestart ();	else 	    con.logAndClose (null);	con = null;	clientBuffer = null;    }    /** Try to use the resource size to decide if we may cache or not.      *  If the size is known and the size is bigger than the maximum cache      *  size, then we dont want to cache the resource.      */    protected boolean mayCacheFromSize () {	Cache<HttpHeader, HttpHeader>  cache = con.getProxy ().getCache ();	if ((size > 0 && size > cache.getMaxSize ()) || 	    (cache.getMaxSize () == 0))	    return false;	return true;    }    /** Check if this handler may force the cached resource to be      *  less than the cache max size.     * @return true     */    protected boolean mayRestrictCacheSize () {	return true;    }    /** Set the expire time on the cache entry.      *  If the expire time is 0 then the cache is not written.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?