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