Package rabbit.proxy

Source Code of rabbit.proxy.SCC

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;
    }
}
TOP

Related Classes of rabbit.proxy.SCC

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.