Package org.w3c.www.protocol.http.cache

Source Code of org.w3c.www.protocol.http.cache.EntityCachedResource

// EntityCachedResource.java
// $Id: EntityCachedResource.java,v 1.37 2003/02/24 14:13:08 ylafon Exp $
// (c) COPYRIGHT MIT, INRIA and Keio, 1999.
// Please first read the full copyright statement in file COPYRIGHT.html

package org.w3c.www.protocol.http.cache;

import java.net.URL;

import java.util.Enumeration;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;

import org.w3c.util.ArrayDictionary;
import org.w3c.tools.resources.Attribute;
import org.w3c.tools.resources.AttributeRegistry;
import org.w3c.tools.resources.BooleanAttribute;
import org.w3c.tools.resources.IntegerAttribute;
import org.w3c.tools.resources.LongAttribute;
import org.w3c.tools.resources.StringAttribute;
import org.w3c.www.http.HeaderDescription;
import org.w3c.www.http.HTTP;
import org.w3c.www.http.HttpCacheControl;
import org.w3c.www.http.HttpContentRange;
import org.w3c.www.http.HttpRange;
import org.w3c.www.http.HttpEntityTag;
import org.w3c.www.http.HttpFactory;
import org.w3c.www.http.ByteRangeOutputStream;
import org.w3c.www.protocol.http.HttpException;
import org.w3c.www.protocol.http.Reply;
import org.w3c.www.protocol.http.Request;
import org.w3c.www.mime.MimeType;
import org.w3c.jigsaw.frames.MimeTypeAttribute;

/**
* A cached resource with an entity
*/
public class EntityCachedResource extends CachedResource {

    /**
     * Condition check return code - Condition existed but failed.
     */
    public static final int COND_FAILED = 1;
    /**
     * Condition check return code - Condition existed and succeeded.
     */
    public static final int COND_OK = 2
    /**
     * Condition check return code - Condition existed and succeeded
     *                               but is a weak validation.
     */
    public static final int COND_WEAK = 3;   

    /**
     * Attribute index - The Content-Type of the resource
     */
    protected static int ATTR_CONTENT_TYPE = -1;
    /**
     * Attribute index - The resource's max age.
     */
    protected static int ATTR_FRESHNESS_LIFETIME = -1;
    /**
     * Attribute index - The initial age of this resource.
     */
    protected static int ATTR_INITIAL_AGE = -1;
    /**
     * Attribute index - The response time
     */
    protected static int ATTR_RESPONSE_TIME = -1;   
    /**
     * Attribute index - Revalidate flag
     */
    protected static int ATTR_REVALIDATE = -1;   
    /**
     * Attribute index - The download state
     */
    protected static int ATTR_LOAD_STATE = -1;   

    static {
  Attribute a = null;
  Class     c = null;
  try {
      c = Class.forName(
    "org.w3c.www.protocol.http.cache.EntityCachedResource");
  } catch (Exception ex) {
      ex.printStackTrace();
      System.exit(1);
  }
  // Declare the contenht type attribute:
  a = new MimeTypeAttribute("content-type"
          , null
          , Attribute.COMPUTED);
  ATTR_CONTENT_TYPE = AttributeRegistry.registerAttribute(c, a);
  // Declare the max-age (freshness lifetime) value.
  a = new IntegerAttribute("freshness-lifetime"
         , null
         , Attribute.COMPUTED);
  ATTR_FRESHNESS_LIFETIME = AttributeRegistry.registerAttribute(c, a);
  // Declare the initial age value.
  a = new IntegerAttribute("initial-age"
         , null
         , Attribute.COMPUTED);
  ATTR_INITIAL_AGE = AttributeRegistry.registerAttribute(c, a);
  // Declare the response time value.
  a = new LongAttribute("response-time"
            , null
            , Attribute.COMPUTED);
  ATTR_RESPONSE_TIME = AttributeRegistry.registerAttribute(c, a);
  // Declare the response time value.
  a = new BooleanAttribute("revalidate"
            , Boolean.FALSE
            , Attribute.COMPUTED);
  ATTR_REVALIDATE = AttributeRegistry.registerAttribute(c, a)
    }

    // some download specific variables
    protected boolean revalidating = false;
    protected boolean regetting    = false;
    protected boolean hasEntity    = false;
    protected int       oldsize = -1;
    protected int    wantedsize = -1;
    // our cache filter, if we need to notify it
    protected CacheFilter filter;

    /**
     * Get the Content-Type of the cached resource of <code>null</code> if
     * there is no mime type (it should NEVER happen!)
     * @return a MimeType
     */
    public MimeType getContentType() { 
  return (MimeType) getValue(ATTR_CONTENT_TYPE, null);
    }

    /**
     * Set the Content-Type of this cached resource
     * @param a MimeType, the mime type of this resource
     */
    public void setContentType(MimeType type) {
  setValue(ATTR_CONTENT_TYPE, type);
    }

    /**
     * Get this resource's freshness lifetime (RFC2616: 13.2.4).
     * @return A long number of seconds for which that entry will remain
     * valid, or <strong>-1</strong> if undefined.
     */
    public int getFreshnessLifetime() {
  return getInt(ATTR_FRESHNESS_LIFETIME, -1);
    }

    /**
     * Set this cached entry . freshness lifetime (RFC2616: 13.2.4).
     * @param maxage A number of seconds during which the entry will
     * remain valid, or <strong>-1</strong> to undefine previous setting.
     */
    public void setFreshnessLifetime(int freshnessLifetime) {
  setInt(ATTR_FRESHNESS_LIFETIME, freshnessLifetime);
    }

    /**
     * Get this cached entry initial age.
     * @return A long number of seconds giving the initial age
     * or <strong>-1</strong> if undefined.
     */
    public int getInitialAge() {
  return getInt(ATTR_INITIAL_AGE, -1);
    }

    /**
     * Set this resource's initial age.
     * @param initage The initial age as a number of seconds
     * or <strong>-1</strong> to undefine previous setting.
     */
    public void setInitialAge(int initage) {
  setInt(ATTR_INITIAL_AGE, initage);
    }

    /**
     * Get the time of the response used to cached that entry.
     * @return A long number of milliseconds since Java epoch, or <strong>
     * -1</strong> if undefined.
     */
    public long getResponseTime() {
  return getLong(ATTR_RESPONSE_TIME, -1);
    }

    /**
     * Set this cached entry response time.
     * @param responsetime A long number of milliseconds indicating the
     * response time relative to Java epoch, or <strong>-1</strong> to
     * undefined previous setting.
     */
    public void setResponseTime(long responsetime) {
  setLong(ATTR_RESPONSE_TIME, responsetime);
    }

    /**
     * Get the revalidate flag
     * @return a boolean, <code>true</code> if the proxy must revalidate
     * stale entries
     * -1</strong> if undefined.
     */
    public boolean getRevalidate() {
  return getBoolean(ATTR_REVALIDATE, false);
    }

    /**
     * Set this cached entry revalidate flag.
     * @param validate, a boolean, <code>true</code> if this entry needs
     * to be revalidated while stale.
     */
    public void setRevalidate(boolean validate) {
  setBoolean(ATTR_REVALIDATE, validate);
    }

    /**
     * Get the entity tag associated with that cached entry
     * @return the entity tag or <strong>null</strong> if undefined
     */
    public HttpEntityTag getHETag() {
  if (definesAttribute(ATTR_ETAG)) {
      if (etags == null) {
    etags    = new HttpEntityTag[1];
    etags[0] = HttpFactory.parseETag(getETag());
      }
      return etags[0];
  }
  return null;
    }
    // FIXME add entity tag here

    // end of the basic accessors

    /**
     * Get the cached data for that cached entry.
     * @return A <em>non-buffered</em> output stream.
     */
    public synchronized InputStream getInputStream()
  throws IOException
    {
  return new BufferedInputStream(new FileInputStream(getFile()));
    }

    /**
     * Get the current age of this resource
     * @return a long the current age of this resource
     */
    public int getCurrentAge() {
  long now = System.currentTimeMillis();
  // RFC2616: 13.2.3 Age Calculation
   return (int) (getInitialAge() + ((now - getResponseTime()) / 1000));
    }

    /**
     * Try to validate an <code>If-Modified-Since</code> request.
     * @param request The request to validate.
     * @return An integer, <code>COND_FAILED</code>, if the condition  was
     * checked, but failed; <code>COND_OK</code> of condition was checked
     * and succeeded, <strong>0</strong> otherwise.
     */

    public int checkIfModifiedSince(Request request) {
  // Check for an If-Modified-Since conditional:
  long ims = request.getIfModifiedSince();
  long cmt = getLastModified();
  if (ims >= 0) {
      if (cmt > 0) {
    long s_cmt = cmt / 1000;
    long s_ims = ims / 1000;
    if (s_cmt < s_ims) {
        return COND_FAILED;
    } else if (s_cmt == s_ims) {
        return COND_WEAK;
    }
    return COND_OK;
      }
  }
  return 0;
    }

    /**
     * Try to validate an <code>If-Unmodified-Since</code> request.
     * @param request The request to validate.
     * @return An integer, <code>COND_FAILED</code>, if the condition  was
     * checked, but failed; <code>COND_OK</code> of condition was checked
     * and succeeded, <strong>0</strong> otherwise.
     */

    public int checkIfUnmodifiedSince(Request request) {
  // Check for an If-Unmodified-Since conditional:
  long iums = request.getIfUnmodifiedSince();
  long cmt = getLastModified();
  if ( iums >= 0 )
      return ((cmt > 0) && (cmt - 1000) >= iums) ? COND_FAILED : COND_OK;
  return 0;
    }

    /**
     * Try to validate an <code>If-Match</code> request.
     * @param request The request to validate.
     * @return An integer, <code>COND_FAILED</code>, if the condition  was
     * checked, but failed; <code>COND_OK</code> of condition was checked
     * and succeeded, <strong>0</strong> otherwise.
     */

    public int checkIfMatch(Request request) {
  HttpEntityTag tags[] = request.getIfMatch();
  if ( tags != null ) {
      HttpEntityTag etag = getHETag();
      // Good, real validators in use:
      if ( etag != null ) {
    for (int i = 0 ; i < tags.length ; i++) {
        HttpEntityTag t = tags[i];
        if (t.getTag().equals(etag.getTag())) {
      if (t.isWeak() || etag.isWeak()) {
          return COND_WEAK;
      } else {
          return COND_OK;
      }
        }
    }
      }
      return COND_FAILED;
  }
  return 0;
    }

    /**
     * Try to validate an <code>If-None-Match</code> request.
     * @param request The request to validate.
     * @return An integer, <code>COND_FAILED</code>, if the condition  was
     * checked, but failed; <code>COND_OK</code> of condition was checked
     * and succeeded, <strong>0</strong> otherwise.
     */

    public int checkIfNoneMatch(Request request) {
  String setag = getETag();
  HttpEntityTag etag = null;
  // Check for an If-None-Match conditional:
  HttpEntityTag tags[] = request.getIfNoneMatch();
  if (setag != null) {
      etag = HttpFactory.parseETag(getETag());
  }
  if ( tags != null ) {
      if ( etag == null ) {
    return COND_OK;
      }
      int status = COND_OK;
      for (int i = 0 ; i < tags.length ; i++) {
    HttpEntityTag t = tags[i];
    if (t.getTag().equals(etag.getTag())) {
//        if (t.isWeak() && !etag.isWeak()) {
        if (t.isWeak() || etag.isWeak()) {
      status = COND_WEAK;
        } else {
      return COND_FAILED;
        }
    }
    if (t.getTag().equals("*")) {
        return COND_FAILED;
    }
      }
      return status;
  }
  return 0;
    }

    /**
     * Called when the tee succeed, it allows you to notify a listener of the
     * Tee that the download completed succesfully with a specific size
     * @parameter the size received, an integer
     */
    public synchronized void notifyTeeSuccess(int size) {
  int state = getLoadState();
        try {
      if ( wantedsize > 0 ) {
    if (!regetting) {
        // sanity check
        if (state == STATE_NOT_LOADED) {
      if (size == wantedsize) {
          // cool! the right size and it was the first
          // download!
          setCurrentLength(size);
          setLoadState(STATE_LOAD_COMPLETE);
      } else {
          // argh! wrong size and a success hum...
          setCurrentLength(size);
          setLoadState(STATE_LOAD_ERROR);
          System.out.println(getIdentifier()
                 +": tee stream mismatch, "
                 + "bytes(adv/got)="+
                 wantedsize+"/"+size);
      }
        } else {
      // how can we end up here, I frankly don't know
      setCurrentLength(size);
      setLoadState(STATE_LOAD_ERROR);
      System.out.println(getIdentifier()
             +": UNKNOWN STATE for "
             +"tee stream!, bytes(adv/got)="+
             wantedsize+"/"+size);
        }
    } else {
        // we asked for the diff, and we have it!!!
        if (size == wantedsize) {
      setCurrentLength(oldsize+wantedsize);
      setLoadState(STATE_LOAD_COMPLETE);
        } else {
      // argh! wrong size and a success hum...
      setCurrentLength(size);
      setLoadState(STATE_LOAD_ERROR);
      System.out.println(getIdentifier()
             +": tee stream mismatch in reget, "
             + "bytes(adv/got)="+
             wantedsize+"/"+size);
        }
    }
      } else {
    // we didn't knew the size, we should trust what we got
    // (unless it is HTTP/1.0)
    setCurrentLength(size);
    // FIXME (a trust flag to select btw COMPLETE and UNKNOWN
    setLoadState(STATE_LOAD_COMPLETE);
      }
      // Update cache filter space usage:
//      filter.markUsed(this, oldsize, wantedsize);
   
  } finally {
      cleanUpload();
  }
    }

    public void notifyTeeFailure(int size) {
  System.out.println(getIdentifier()+": tee streaming failed !");
  int state = getLoadState();
 
  setCurrentLength(size);
  setLoadState(STATE_LOAD_ERROR);
  System.out.println(getIdentifier()
         +": tee stream mismatch, "
         + "bytes(adv/got)="+
         wantedsize+"/"+size);
  // and finish the thing!
  cleanUpload();
    }

    // FIXME should be called after every upload
    protected synchronized void cleanUpload() {
  // FIXME reset a whole bunch of stuff
  uploading = false;
  filter.cleanUpload(this);
  notifyAll();
    }

    /**
     * FIXME Will be replaced soon, so that multiple people may share
     * the same temporary resource.
     * Wait for the upload to finish, if needed.
     */
    protected final synchronized void waitUpload() {
  while ( uploading ) {
      try {
    wait();
      } catch (InterruptedException ex) {
      }
  }
    }

    /**
     * handle a range request, according to the first range or the
     * request FIXME we should handle all the ranges at some point...
     */
    protected Reply handleRangeRequest(Request request, HttpRange r) {
  // Should we check against a IfRange header ?
  HttpEntityTag t = request.getIfRange();
  if ( t != null ) {
      if (t.isWeak() || ! t.getTag().equals(getHETag().getTag()))
    return null;
  }
  // Check the range:
  int cl = getContentLength();
  int fb = r.getFirstPosition();
  int lb = r.getLastPosition();
  int sz;
  if (fb > cl-1) { // first byte already out of range
      HttpContentRange cr = HttpFactory.makeContentRange("bytes", 0,
                     cl - 1, cl);
      Reply rr;
      rr = request.makeReply(HTTP.REQUESTED_RANGE_NOT_SATISFIABLE);
      rr.setContentLength(-1);
      rr.setHeaderValue(rr.H_CONTENT_RANGE, cr);
      rr.setContentMD5(null);
      return rr;
  }
  if ((fb < 0) && (lb >= 0)) { // ex: bytes=-20 final 20 bytes
      if (lb >= cl)   // cut the end
    lb = cl;
      sz = lb;
      fb = cl - lb;
      lb = cl - 1;
  } else if (lb < 0) {  // ex: bytes=10- the last size - 10
      lb = cl-1;
      sz = lb-fb+1;
  } else {              // ex: bytes=10-20
      if (lb >= cl// cut the end
    lb = cl-1;
      sz = lb-fb+1;
  }
  if ((fb < 0) || (lb < 0) || (fb <= lb)) {
      HttpContentRange cr = null;
      fb = (fb < 0) ? 0 : fb;
      lb = ((lb > cl) || (lb < 0)) ? cl : lb;
      cr = HttpFactory.makeContentRange("bytes", fb, lb, cl);
      // Emit reply:
      Reply rr = request.makeReply(HTTP.PARTIAL_CONTENT);
      try {
    rr.setContentMD5(null); // just in case :)
    rr.setContentLength(sz);
    rr.setHeaderValue(rr.H_CONTENT_RANGE, cr);
    rr.setStream(new ByteRangeOutputStream(getFile(), fb, lb+1));
    return rr;
      } catch (IOException ex) {
      }
  }
  return null;
    }
 
    /**
     * decorate the reply header with some meta information taken
     * from the cached resource
     * @return a reply, the one we just updated
     */
    protected Reply setReplyHeaders(Reply reply) {
  int status = reply.getStatus();
  if (status != HTTP.NOT_MODIFIED) {
      // FIXME check for byte range replies
      reply.setContentLength(getContentLength());
      // dump the headers we know.
      reply.setContentMD5(getContentMD5());
      reply.setContentLanguage(getContentLanguage());
      reply.setContentEncoding(getContentEncoding());
      reply.setContentType(getContentType());
      reply.setLastModified(getLastModified());
      reply.setVary(getVary());
  }
  reply.setETag(getHETag());
  long date = getDate();
  if ( date > 0 )
      reply.setDate(getDate());
  reply.setAge(getCurrentAge());
  ArrayDictionary a = getExtraHeaders();
  if ( a != null ) {
      // This is the slowest operation of the whole cache :-(
      Enumeration e = a.keys();
      while (e.hasMoreElements() ) {
    String hname  = (String) e.nextElement();
    String hvalue = (String) a.get(hname);
    reply.setValue(hname, hvalue);
      }
  }
  if ((filter != null) && filter.isShared()) {
      HttpCacheControl hcc = reply.getCacheControl();
      if (hcc != null) {
    String priv[] = hcc.getPrivate();
    if (priv != null) {
        for (int i=0; i<priv.length; i++) {
      // remove headers that are private if we are
      // a shared cache (rfc2616#14.9, rfc2616#14.9.1)
      reply.setHeaderValue(priv[i], null);
        }
    }
      }
  }
  return reply;
    }

    /**
     * check the validators namely LMT/Etags according to rfc2616 rules
     * @return An integer, either <code>COND_FAILED</cond> if condition
     * was checked, but failed, <code>COND_OK</code> if condition was checked
     * and succeeded, or <strong>0</strong> if the condition was not checked
     * at all (eg because the resource or the request didn't support it).
     */
    public int checkValidators(Request request) {
  int v_inm = checkIfNoneMatch(request);
  int v_ims = checkIfModifiedSince(request);

  if ((v_inm == COND_OK) || (v_ims == COND_OK)) {
      return COND_OK;
  }
  if ((v_inm == COND_FAILED) || (v_ims == COND_FAILED)) {
      return COND_FAILED;
  }
  if ((v_inm == COND_WEAK) || (v_ims == COND_WEAK)) {
      return COND_FAILED;
  }
  return 0;
    }

    /**
     * This cached entry has been checked valid, perform given request.
     * @param request The request to perform.
     * @return An Reply instance.
     * @exception HttpException If something went wrong.
     */
    public Reply perform(Request request)
  throws HttpException
    {
  // If the resource is currently being uploaded, wait:
  waitUpload();
  // Now perform the request:
  try {
      Reply   reply       = null;
      boolean needsEntity = true;
      // Handle range requests:
      HttpRange ranges[] = request.getRange();
      if ((ranges != null) && (ranges.length == 1))
    reply = handleRangeRequest(request, ranges[0]);
      // Handle full retreivals:
      if ( reply == null ) {
    int status = getStatus();
    // Try validating first
    // NOTE: We know we are only dealing with GETs and HEADs here
    // otherwise the cache wouldn't be used...
    int cim = checkIfMatch(request);
    if ( (cim == COND_FAILED) || (cim == COND_WEAK) ) {
        status      = HTTP.PRECONDITION_FAILED;
        needsEntity = false;
        reply = request.makeReply(status);
        reply.setContent("Pre-conditions failed.");
        throw new HttpException(request, reply, "pre-condition");
          } else if ( checkIfUnmodifiedSince(request) == COND_FAILED ) {
        status      = HTTP.PRECONDITION_FAILED;
        reply = request.makeReply(status);
        reply.setContent("Pre-conditions failed.");
         throw new HttpException(request, reply, "pre-condition");
    } else if ( checkValidators(request) == COND_FAILED ) {
        status      = HTTP.NOT_MODIFIED;
        needsEntity = false;
    }
    // Emit reply:
    reply = request.makeReply(status);
    if ( needsEntity ) {
        reply.setStream(getInputStream());
    }
      }
      setReplyHeaders(reply);
      // Check if entity is needed:
      String mth = request.getMethod();
      if ( mth.equals("HEAD") || mth.equals("OPTIONS") )
    reply.setStream(null);
//      filter.markUsed(this);
      return reply;
  } catch (IOException ex) {
//      if (debug)
//    ex.printStackTrace();
      // Some exception occured, delete that resource (no longer usefull)
//      delete();
  }
  return null;
    }

    /**
     * Try using an active stream to cache the content.
     * Byte size usage is taken care of only at the end of the download
     * to make sure we get the right sizes (might different from the
     * advertized ones).
     * @return An InputStream instance if active caching was possible,
     * <strong>null</strong> otherwise.
     */
    public synchronized InputStream tryActiveCacheContent(InputStream in)
  throws IOException
    {
  // If we don't return null, we *are* responsible for cleaning up
  // the upload *whatever* happens ...
  InputStream  tee = null;
  OutputStream out = null;
  uploading = true;
  // Open the output stream:
  try {
      out = new FileOutputStream(getFile());
  } catch (IOException ex) {
//      if (debug)
    ex.printStackTrace();
      // We'll let cacheContent take care of that situation:
      return null;
  }
  // We might be able to use active streams:
//  if (upnewsize > ACTIVE_STREAM_THRESOLD ) {
      tee = ActiveStream.createTee(this, in, out);
      if ( tee != null )
    return tee;
//  }
  // We were not able to active stream:
  try {
      out.close();
  } catch (IOException ex) {
  }
  return null;
    }

    /**
     * The basic initialization
     */
    public void initialize(Object values[]) {
  super.initialize(values);
    }   

    /**
     * sets some useful information about the entity
     * @param the request that requested this entity
     * @param the reply triggered by this request
     */
    protected void updateInfo(Request request, Reply rep) {
  String   mth       = request.getMethod();
  Reply    reply     = (Reply) rep.getClone();
  boolean  hasEntity = !(mth.equals("HEAD") || mth.equals("OPTIONS"));
  // is it a revalidation?
  if (!request.hasState(CacheState.STATE_REVALIDATION)) {
      // no, go for it!
      HttpCacheControl hcc = reply.getCacheControl();
      // first we should NOT cache headers protected by a no-cache
      // per rfc2616@14.9
      if (hcc != null) {
    String nocache[] = hcc.getNoCache();
    if (nocache != null) {
        for (int i=0; i< nocache.length; i++) {
      reply.setHeaderValue(nocache[i], null);
        }
    }
      }
      setStatus(reply.getStatus());
      setContentType(reply.getContentType());
      setContentLength(reply.getContentLength());
      setLastModified(reply.getLastModified());
      setContentMD5(reply.getContentMD5());
      String vary[] = reply.getVary();
      setVary(vary);
      if (vary != null) {
    // update the conneg headers
    ArrayDictionary a = null;
    for (int i=0; i< vary.length; i++) {
        if (vary[i].equals("*")) {
      continue;
        }
        if (a == null) {
      a = new ArrayDictionary(vary.length);
        }
        a.put (vary[i].toLowerCase(), request.getValue(vary[i]));
    }
    // FIXME we should be able to update to save multiple
    // matches, but with a limitation of course
    if (a != null) {
        setConnegHeaders(a);
    }
      }
      if (reply.hasHeader(reply.H_ETAG)) {
    setETag(reply.getETag().toString());
      } else {
    // be safe here!
    setETag(null);
      }
      ArrayDictionary a = new ArrayDictionary(5, 5);
      Enumeration     e = reply.enumerateHeaderDescriptions();
      while ( e.hasMoreElements() ) {
    HeaderDescription d = (HeaderDescription) e.nextElement();
    // Skip all well-known headers:
    if ( d.isHeader(Reply.H_CONTENT_TYPE)
         || d.isHeader(Reply.H_CONTENT_LENGTH)
         || d.isHeader(Reply.H_LAST_MODIFIED)
         || d.isHeader(Reply.H_ETAG)
         || d.isHeader(Reply.H_AGE)
         || d.isHeader(Reply.H_DATE)
         || d.isHeader(Reply.H_VARY)
         || d.isHeader(Reply.H_CONNECTION)
         || d.isHeader(Reply.H_PROXY_CONNECTION)
         || d.isHeader(Reply.H_TRANSFER_ENCODING)
         || d.isHeader(Reply.H_CONTENT_MD5)
         || d.getName().equalsIgnoreCase("keep-alive"))
        continue;
    // This is an extra header:
    a.put(d.getName(), reply.getValue(d));
      }
      setExtraHeaders(a);
      // FIXME add the headers ;)
     
  }
    }

    /**
     * This cached entry needs revalidation, it will modify the
     * request to do that.
     */
    public Request setRequestRevalidation(Request request) {
  Request origreq = (Request) request.getClone();
  request.setState(CacheState.STATE_RESOURCE, this);
  request.setState(CacheState.STATE_ORIGREQ, origreq);
  // At this point, we use the suggested way of using date as etag:
  request.setIfModifiedSince(getLastModified());
  // But if we do have an etag, we also uses it, as recommended:
  if ((etags == null) && (getETag() != null)) {
      etags    = new HttpEntityTag[1];
      etags[0] = HttpFactory.parseETag(getETag());
  }
  request.setIfNoneMatch(etags);
  // We have to remove all other conditionals here:
  request.setIfRange(null);
  request.setRange(null);
  request.setIfUnmodifiedSince(-1);
  request.setIfMatch(null);
  return request;
   

    /**
     * A constructor for new resources that will get some data
     * directly
     * FIXME params
     */
    public EntityCachedResource(CacheFilter filter, Request req, Reply rep) {
  invalidated = false;
  setValue(ATTR_IDENTIFIER, req.getURL().toExternalForm());
  // Keep fast track of the filter:
  this.filter = filter;
  // update the headers
  updateInfo(req, rep);
  // and do some calculation according to the validator
  filter.getValidator().updateExpirationInfo(this, req, rep);
  // Save the content of resource into the content cache:
  setFile(filter.getStore().getNewEntryFile());
  wantedsize = rep.getContentLength();
  InputStream in;
  try {
      in = tryActiveCacheContent(rep.getInputStream());
      if (in == null) {
    // something bad happened
    // in = cacheContent(reply.getInputStream());
      }
      rep.setStream(in);
  } catch (IOException ex) {
      // FIXME
 
    }

    public EntityCachedResource() {
  super();
    }
}

TOP

Related Classes of org.w3c.www.protocol.http.cache.EntityCachedResource

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.