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