gziphandler.java

来自「一款Java实现的HTTP代理服务器」· Java 代码 · 共 194 行

JAVA
194
字号
package rabbit.handler;import java.io.IOException;import java.io.OutputStream;import java.nio.ByteBuffer;import java.util.zip.GZIPOutputStream;import rabbit.http.HttpHeader;import rabbit.proxy.BlockSender;import rabbit.proxy.Connection;import rabbit.proxy.TrafficLoggerHandler;import rabbit.util.Logger;import rabbit.util.SProperties;/** This handler compresses the data passing through it.  * * @author <a href="mailto:robo@khelekore.org">Robert Olofsson</a> */public class GZipHandler extends BaseHandler {    protected boolean compress = true;    protected GZIPOutputStream gz = null;    private boolean isCompressing = false;    private boolean addListener = false;    private boolean waitingForBlockSent = false;    /** For creating the factory.     */    public GZipHandler () {    }        /** Create a new GZipHandler 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.     * @param compress if we want this handler to compress or not.     */    public GZipHandler (Connection con, TrafficLoggerHandler tlh, 			HttpHeader request, ByteBuffer clientBuffer,			HttpHeader response, ResourceSource content, 			boolean mayCache, boolean mayFilter, long size, 			boolean compress) {	super (con, tlh, request, clientBuffer, response, content, 	       mayCache, mayFilter, size);	this.compress = compress;	if (compress) {	    String gzip = response.getHeader ("Content-Encoding");	    isCompressing = !(gzip != null 			      && (gzip.equalsIgnoreCase ("gzip") 				  || gzip.equalsIgnoreCase ("compress")				  || gzip.equalsIgnoreCase ("deflate")));	    if (isCompressing) {		response.removeHeader ("Content-Length");		response.setHeader ("Content-Encoding", "gzip");		if (!con.getChunking ())		    con.setKeepalive (false);	    } else {		this.mayFilter = false;	    }	}    }        @Override    public Handler getNewInstance (Connection con, TrafficLoggerHandler tlh,				   HttpHeader header, ByteBuffer buffer, 				   HttpHeader webHeader, 				   ResourceSource content, boolean mayCache, 				   boolean mayFilter, long size) {	return new GZipHandler (con, tlh, header, buffer, webHeader, content,				mayCache, mayFilter, size, 				compress && mayFilter);     }    /**      * ®return true this handler modifies the content.     */    @Override public boolean changesContentSize () {	return true;    }    @Override    protected void prepare () throws IOException {	super.prepare ();	if (isCompressing) {	    Stream2Channel s2c = new GZStream2Channel ();	    gz = new GZIPOutputStream (s2c);	}    }        @Override    protected void finishData () throws IOException {	addListener = false;	if (isCompressing)	    gz.finish ();	super.finishData ();    }    /** Check if this handler supports direct transfers.     * @return this handler always return false.     */    @Override    protected boolean mayTransfer () {	return false;    }    protected class Stream2Channel extends OutputStream {	public void write (byte[] b) throws IOException {	    write (b, 0, b.length);	}	public void write (byte[] b, int off, int len) throws IOException {	    ByteBuffer buf = ByteBuffer.wrap (b, off, len);	    if (cacheChannel != null)		writeCache (buf);	    new BlockSender (con.getChannel (), con.getSelector (), 			     getLogger (), tlh.getClient (), buf, 			     con.getChunking (), GZipHandler.this);	    	}	public void write (int b) throws IOException {	    byte[] buf = new byte[1];	    buf[0] = (byte)b;	    write (buf);	}    }    protected class GZStream2Channel extends Stream2Channel {	public void write (byte[] b, int off, int len) throws IOException {	    waitingForBlockSent = true;	    super.write (b, off, len);	}    }        public void blockSent () {	if (addListener) {	    addListener = false;	    content.addBlockListener (this);	}    }        /** Write the current block of data to the gzipper.     *  If you override this method you probably want to override      *  the modifyBuffer(ByteBuffer) as well.     * @param arr the data to write to the gzip stream.     */    protected void writeDataToGZipper (byte[] arr) throws IOException {	gz.write (arr);	    }    /** This method is used when we are not compressing data.      *  This method will just call "super.bufferRead (buf);"     * @param buf the buffer that was just read.     */    protected void modifyBuffer (ByteBuffer buf) {	super.bufferRead (buf);	    }    @Override    public void bufferRead (ByteBuffer buf) {	if (isCompressing) {	    try {		// we normally have direct buffers and we can not use		// array() on them. Create a new byte[] and copy data into it.		byte[] arr = new byte[buf.remaining ()];		buf.get (arr);		addListener = true;		waitingForBlockSent = false;		writeDataToGZipper (arr);		if (!waitingForBlockSent)		    content.addBlockListener (this);	    } catch (IOException e) {		failed (e);	    }	} else {	    addListener = true;	    modifyBuffer (buf);	}    }        @Override     public void setup (Logger logger, SProperties prop) {	if (prop != null) {	    String comp = prop.getProperty ("compress", "true");	    if (comp.equalsIgnoreCase ("false"))		compress = false;	    else		compress = true;	}    }}

⌨️ 快捷键说明

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