scc.java

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

JAVA
278
字号
package rabbit.proxy;import java.io.IOException;import java.nio.ByteBuffer;import java.util.ArrayList;import java.util.List;import java.util.StringTokenizer;import rabbit.io.Range;import rabbit.io.WebConnection;import rabbit.io.WebConnectionListener;import rabbit.handler.BaseHandler;import rabbit.http.HttpHeader;import rabbit.http.ContentRangeParser;import rabbit.util.Logger;/** A class that tries to setup a resource from the cache * * @author <a href="mailto:robo@khelekore.org">Robert Olofsson</a> */public class SCC {    private Connection con;    private HttpHeader header;     private ByteBuffer buffer;     private Connection.RequestHandler rh;    public SCC (Connection con, HttpHeader header, ByteBuffer buffer, 		Connection.RequestHandler rh) {	this.con = con;	this.header = header;	this.buffer = buffer;	this.rh = rh;    }    private Logger getLogger () {	return con.getLogger ();    }    /**      * @return null if everything looks ok, non-null on an errornous request.     */    public HttpHeader establish () throws IOException {	String ifRange = header.getHeader ("If-Range");	boolean mayRange = true;	rh.webHeader = rh.dataHook;	if (ifRange != null) {	    	    String etag = rh.webHeader.getHeader ("ETag");	    if (etag != null) {  		/* rfc is fuzzy about if it should be weak or strong match here.		mayRange = 		    checkWeakEtag (rh.webheader.getHeader ("ETag"), ifRange);		*/		mayRange = con.checkStrongEtag (etag, ifRange);	    } else {		// we can't use strong validators on dates!		mayRange = false;	    }	    CacheChecker cck = new CacheChecker ();	    boolean cc = cck.checkConditions (con, header, rh.webHeader);	    if (mayRange && !cc) {		// abort...		rh.webHeader = null;		rh.content = null;		return null;	    } else if (!cc) {		rh.content = null;		return null;	    }	}	List<Range> ranges = null;	if (mayRange) {	    try {		ranges = getRanges (header, rh);	    } catch (IllegalArgumentException e) {		return con.getHttpGenerator ().get416 (e);	    }	}	con.setChunking (false);	if (ranges != null) {	    long totalSize = getTotalSize (rh);	    if (!haveAllRanges (ranges, rh, totalSize)) {		// abort and get from web..		rh.webHeader = null;		rh.content = null;		return null;	    }	    setupRangedEntry (ifRange, ranges, totalSize);	} else {	    HttpProxy proxy = con.getProxy ();	    rh.content = 		new CacheResourceSource (proxy.getCache (), rh.entry, proxy);	    rh.size = rh.entry.getSize ();	    rh.webHeader.setStatusCode ("200");	    rh.webHeader.setReasonPhrase ("OK");	}	setAge ();	// do we have a handler for it?	HttpProxy proxy = con.getProxy ();	String ctype = rh.webHeader.getHeader ("Content-Type");  	if (ctype != null) 	    rh.handlerFactory = proxy.getCacheHandlerFactory (ctype); 	if (rh.handlerFactory == null || ranges != null)	    // Simply send, its already filtered.	    rh.handlerFactory = new BaseHandler (); 	WarningsHandler wh = new WarningsHandler ();	wh.removeWarnings (getLogger (), rh.webHeader, false);	return null;    }    private void setupRangedEntry (String ifRange, List<Range> ranges, 				   long totalSize) 	throws IOException {	HttpProxy proxy = con.getProxy ();	rh.content = 	    new RandomCacheResourceSource (proxy.getCache (), 					   rh, proxy,					   ranges, totalSize);	con.setChunking (false);	rh.webHeader = 	    con.getHttpGenerator ().get206 (ifRange, rh.webHeader);	con.setStatusCode ("206");	if (ranges.size () > 1) {	    //prepare multipart...	    rh.webHeader.removeHeader ("Content-Length");	    String CT = 		"multipart/byteranges; boundary=THIS_STRING_SEPARATES";	    rh.webHeader.setHeader ("Content-Type", CT);	} else {	    Range r = ranges.get (0);	    rh.webHeader.setHeader ("Content-Range", 				    "bytes " + r.getStart () + "-" + 				    r.getEnd () + "/" + totalSize);	    rh.size = (r.getEnd () - r.getStart () + 1);	    rh.webHeader.setHeader ("Content-Length", "" + rh.size);	}		    }    private void setAge () {	String age = rh.webHeader.getHeader ("Age");	long now = System.currentTimeMillis ();	long secs = (now - rh.entry.getCacheTime ()) / 1000;	if (age != null) {	    try {		long l = Long.parseLong (age);		secs += l;	    } catch (NumberFormatException e) {		getLogger ().logWarn ("bad Age : '" + age + "'");	    }	}	rh.webHeader.setHeader ("Age", "" + secs);    }    private List<Range> getRanges (HttpHeader header, Connection.RequestHandler rh) {	//Range: bytes=10-,11-10\r\n	List<String> ranges = header.getHeaders ("Range");	int z = ranges.size ();	if (z == 0)	    return null;	List<Range> ret = new ArrayList<Range> ();	try {	    for (int i = 0; i < z; i++) {		String rs = ((String)ranges.get (i)).trim ();		if (!rs.startsWith ("bytes"))		    return null;		rs = rs.substring (5);		int j = rs.indexOf ('=');		if (j == -1)		    return null;		rs = rs.substring (j + 1);		String[] st = rs.split (",");		for (String r : st) {		    Range range = parseRange (r);		    if (range == null)			return null;		    ret.add (range);		}	    }	} catch (NumberFormatException e) {	    return null;	}	return ret;    }    private static final String SBTZ =     "bad range: start bigger than size";    private static final String SAELTZ =     "bad range: start and end both less than zero";    private static final String SLTZ =     "bad range: start less than zero";    private static final String FR =     "bad range: full range";    private Range parseRange (String r) {	int d = r.indexOf ('-');	if (d == -1)	    throw new NumberFormatException ("bad range: no '-'");	String s = r.substring (0, d).trim ();	String e = r.substring (d + 1).trim ();	long start = -1;	long end = -1;	long size = rh.entry.getSize ();	if (s.length () > 0) {	    start = Integer.parseInt (s);	    if (e.length () > 0) {		end = Integer.parseInt (e);	    } else {		// to the end...		end = size;	    }	    if (start > size)				throw new IllegalArgumentException (SBTZ);	    if (start > end)  // ignore this...		return null;	    if (start < 0 || end < 0)		throw new IllegalArgumentException (SAELTZ);	    return new Range (start, end);	} else if (e.length () > 0) {	    // no start so this many bytes from the end...	    start = Integer.parseInt (e);	    if (start < 0)		throw new IllegalArgumentException (SLTZ);	    start = size - start;	    end = size;	    return new Range (start, end);	} else {	    // "-"	    throw new NumberFormatException (FR);	}    }    private long getTotalSize (Connection.RequestHandler rh) {	String cr = rh.webHeader.getHeader ("Content-Range");	if (cr != null) {	    int i = cr.lastIndexOf ('/');	    if (i != -1) {		return Long.parseLong (cr.substring (i + 1));	    }	}	String cl = rh.webHeader.getHeader ("Content-Length");	if (cl != null)	    return Long.parseLong (cl);	// ok fallback...	return rh.entry.getSize ();    }        private boolean haveAllRanges (List<Range> ranges, 				   Connection.RequestHandler rh, 				   long totalSize) {	// do we have all of it?	if (rh.entry.getSize () == totalSize)	    return true;		// check each range...	// TODO add support for many parts...	//Content-Range: bytes 0-4/25\r\n	String cr = rh.webHeader.getHeader ("Content-Range");	if (cr == null)   // TODO check if its ok to return true here.. 	    // if we do not have a content range we ought to have full resource.	    return false; 		for (int i = 0; i < ranges.size (); i++) {	    Range r = ranges.get (i);	    long start = r.getStart ();	    long end = r.getEnd ();	    String t = "bytes " + start + "-" + end + "/" + totalSize;	    if (!t.equals (cr)) {		ContentRangeParser crp = 		    new ContentRangeParser (cr, getLogger ());		if (crp.isValid ()) {		    if (crp.getStart () > start || crp.getEnd () < end)			return false;		}	    }	}	return true;    }}

⌨️ 快捷键说明

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