mcardle     2005/11/18 17:26:11 CET

  Modified files:
    src/net/sf/j2ep/responsehandlers ResponseHandlerBase.java 
  Log:
  * supports HTTP redirection

  * deals properly with static requesthandler

  * rewrites Referer and Location HTTP headers

  * supports HTTP redirection

  * deals with chunked HTTP transfers

  * more debug info
  
  Revision  Changes    Path
  1.11      +120 -41   
esi_server/src/net/sf/j2ep/responsehandlers/ResponseHandlerBase.java
http://jahia.mine.nu:8080/cgi-bin/cvsweb.cgi/esi_server/src/net/sf/j2ep/responsehandlers/ResponseHandlerBase.java.diff?r1=1.10&r2=1.11&f=h
  
  
  
  Index: ResponseHandlerBase.java
  ===================================================================
  RCS file: 
/home/cvs/repository/esi_server/src/net/sf/j2ep/responsehandlers/ResponseHandlerBase.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- ResponseHandlerBase.java  8 Nov 2005 10:58:49 -0000       1.10
  +++ ResponseHandlerBase.java  18 Nov 2005 16:26:10 -0000      1.11
  @@ -22,6 +22,8 @@
   import java.io.ByteArrayOutputStream;
   import java.net.InetAddress;
   import java.net.UnknownHostException;
  +import java.net.URL;
  +import java.net.MalformedURLException;
   import java.util.Vector;
   import java.util.Enumeration;
   import java.util.Date;
  @@ -37,17 +39,19 @@
   import net.sf.j2ep.factories.MethodNotAllowedException;
   import net.sf.j2ep.ProxyFilter;
   
  -import org.apache.commons.httpclient.*;
   import org.apache.commons.httpclient.util.DateUtil;
   import org.apache.commons.httpclient.util.DateParseException;
   import org.apache.commons.httpclient.methods.GetMethod;
  +import org.apache.commons.httpclient.*;
   import org.apache.commons.logging.LogFactory;
   import org.apache.commons.logging.Log;
   import org.jahia.esi.*;
  +import org.jahia.esi.exceptions.RedirectException;
   import org.jahia.esi.cache.CacheAdminstrator;
   import org.jahia.esi.cache.CacheObject;
   import org.jahia.esi.cache.FragmentCache;
   import org.jahia.esi.cache.UrlCacheObject;
  +import org.jahia.urls.URI;
   
   
   /**
  @@ -55,11 +59,33 @@
    * can write the headers and process the output stream.
    *
    * @author Anders Nyman
  + * @author MC
    */
   public abstract class ResponseHandlerBase implements ResponseHandler {
   
       private static Log log = LogFactory.getLog(ResponseHandlerBase.class);
   
  +
  +    protected URL origRequestUrl;
  +    protected HttpServletRequest clientRequest;
  +
  +    public void initOrigRequestUrl(HttpServletRequest request) {
  +        this.clientRequest = request;
  +        try {
  +            this.origRequestUrl = ProxyFilter.getURL(request);
  +        } catch (MalformedURLException e) {
  +            log.error("Bad request URL: " + e);
  +        }
  +    }
  +
  +    public URL getClientRequestURL() {
  +           return origRequestUrl;
  +    }
  +
  +    public HttpServletRequest getClientRequest() {
  +           return clientRequest;
  +    }
  +
       /**
        * Method we are using for this request.
        */
  @@ -70,13 +96,6 @@
        */
       protected boolean cacheMethod;
   
  -
  -    protected RequestHandler requestHandler;
  -
  -    public void setRequestHandler(RequestHandler requestHandler) {
  -        this.requestHandler = requestHandler;
  -    }
  -
       /**
        * Basic constructor only setting the method.
        * 
  @@ -105,7 +124,7 @@
       /**
        * Sets the headers, writes the stream and sets the status code.
        *
  -     * @see 
net.sf.j2ep.model.ResponseHandler#process(javax.servlet.http.HttpServletResponse)
  +     * @see 
net.sf.j2ep.model.ResponseHandler#process(javax.servlet.http.HttpServletResponse,
 javax.servlet.http.HttpServletRequest)
        */
   
   
  @@ -163,7 +182,7 @@
   
           ByteArrayOutputStream cacheStream = new ByteArrayOutputStream(1000);
   
  -       if (streamFromServer != null) {
  +        if (streamFromServer != null) {
               byte[] buffer = new byte[1024];
               int read = streamFromServer.read(buffer);
               while (read > 0) {
  @@ -186,7 +205,7 @@
   
           //fragmentCache.add(cacheKey, this.method, cacheByteContent);
           fragmentCache.add(cacheKey, this.methodToServer, cacheByteContent,
  -                requestHandler.getClientRequestURL().toString(),
  +                this.getClientRequestURL().toString(),
                   null, null, null ,null);  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
   
   
  @@ -216,30 +235,58 @@
        * @param clientResponse The response that will have headers written to 
it
        */
       protected void 
copyHeadersFromServerResponseToClientResponse(HttpServletResponse 
clientResponse) {
  -        copyHeadersFromServerResponseToClientResponse( clientResponse, 
false);
  +        copyHeadersFromServerResponseToClientResponse( clientResponse, 
false, false);
       }
   
       protected void 
copyHeadersFromServerResponseToClientResponse(HttpServletResponse 
clientResponse,
  -                                                                 boolean 
ignoreCookies) {
  +                                                                 boolean 
ignoreCookies,
  +                                                                 boolean 
isRedirect) {
           Header[] headers = methodToServer.getResponseHeaders();
   
           for (int i=0; i < headers.length; i++) {
               Header header = headers[i];
               String name = header.getName();
  -            boolean contentLength = name.equalsIgnoreCase("content-length");
  +            String val = header.getValue(); //TODO: need to consider the 
case when more than one value is possible for one header i.e. using 
HeaderElement[] getValues()
  +            boolean contentLength = 
false;//name.equalsIgnoreCase("content-length"); //Why does it ignore 
contentLength?
               boolean connection = name.equalsIgnoreCase("connection");
               boolean setcookie = name.equalsIgnoreCase("set-cookie");
  +            boolean location = name.equalsIgnoreCase("location");
  +            boolean referer = name.equalsIgnoreCase("referer");
  +            boolean transferEncodingChunked = 
name.equalsIgnoreCase("Transfer-Encoding")
  +                                                && 
val.toLowerCase().indexOf("chunked")!=-1;
  +
  +            log.debug("Detected Server Response header : "+name+":"+val);
  +
  +            //rewrite redirection URL so that it points to the ESI server 
and not
  +            //the remote Jahia server,
  +            //also rewrite the referer header
  +            //TODO: this should probably be precalculated in during 
addFragment stage rather than doing it everytime for each request sent back 
(but it also depends on if we have multiple servers ...)
  +            if ((location && isRedirect) || referer) {
  +                URI uri = new URI(val.trim());
  +                uri.setHostName(this.getClientRequestURL().getHost());
  +                uri.setPort(this.getClientRequestURL().getPort());
  +                if (!referer) {
  +                    log.debug("replacing Host from "+uri.getHostName()+" to 
"+this.getClientRequestURL().getHost() + " due to HTTP redirect");
  +                    log.debug("replacing Port from "+uri.getPort()+" to 
"+this.getClientRequestURL().getPort()  + " due to HTTP redirect");
  +                    log.debug("Redirecting to "+uri.toString(""));
  +                }
  +                else {
  +                    log.debug("Rewrote Referer Header from "+val+"to 
"+uri.toString(""));
  +                }
  +                val = uri.toString(""); //"" makes sure it doesn't reencode 
the URL
  +            }
   
  -            if (!contentLength && !connection ) {
  +            if (!contentLength && !connection && !transferEncodingChunked) {
                   //optionally ignore Set-Cookie header
                   if (setcookie && ignoreCookies) {
  -                    log.debug("Ignored Set-Cookie header because this is a 
response returned from Cache. Header:"+header);
  +                    log.info("Ignored Set-Cookie header because this is a 
response returned from Cache. Header:"+header);
                       continue;
                   }
                   else if (setcookie)  {
  -                    log.debug("Keeping Set-Cookie header because this is a 
response returned directly from Server. Header:"+header);
  +                    log.info("Keeping Set-Cookie header because this is a 
response returned directly from Server. Header:"+header);
                   }
  -                clientResponse.addHeader(name, header.getValue());
  +                clientResponse.addHeader(name, val);
  +                log.debug("Added Client Response header : "+name+":"+val);
               }
           }
   
  @@ -284,8 +331,8 @@
   
               ProxyFilter.getHttpClient().executeMethod(methodToServer);
   
  -            printRequestHeaders(methodToServer);
  -            printResponseHeaders(methodToServer);
  +            printRequestHeaders(methodToServer, " for POST");
  +            printResponseHeaders(methodToServer,  " for POST");
   
               if (methodToServer.getStatusCode() == 405) {
                   Header allow = methodToServer.getResponseHeader("allow");
  @@ -303,16 +350,18 @@
   
       public void process(HttpServletResponse clientResponse, 
HttpServletRequest clientRequest) throws IOException, MethodNotAllowedException 
{
   
  -        String cacheKey = 
CacheAdminstrator.getInstance().generateEntryKey(this.requestHandler);
  +        initOrigRequestUrl(clientRequest);
  +
  +        String cacheKey = 
CacheAdminstrator.getInstance().generateEntryKey(clientRequest, 
this.getClientRequestURL());
   
  -        String clientRequestUrl = 
this.requestHandler.getClientRequestURL().toString();
  +        String clientRequestUrl = this.getClientRequestURL().toString();
   
   
           FragmentCache fragmentCache = FragmentCache.getInstance();
   
           //Case 1: Passthrough (post etc...)
           if (!this.cacheMethod) {
  -            log.debug(" * Case 1: Passthrough (post etc...) * 
url:"+cacheKey);
  +            log.debug(" * BEGIN ---- > Case 1: Passthrough (post etc...) * 
url:"+cacheKey);
               beginServerRequest();
               copyHeadersFromServerResponseToClientResponse(clientResponse);
               //TODO: set cookies here
  @@ -320,16 +369,23 @@
   
               if (!methodToServer.getName().equals("HEAD")) //since there is 
no content for HEAD requests
                   sendStreamToClientPassthrough(clientResponse);
  +            log.debug(" * END ---- > Case 1: Passthrough (post etc...) * 
url:"+cacheKey);
           }
           else {
   
               CacheObject cacheObject = null;
               boolean freshCopy = false;
  +            boolean redirect = false;
   
               //Case 2: Not in cache so fetch any necessary bits
               if (!fragmentCache.contains(cacheKey)) {
                   log.debug(" * Case 2: Not in cache so fetch any necessary 
bits *");
  -                fetch ( clientResponse, clientRequest, cacheKey , 
clientRequestUrl);
  +                try {
  +                    fetch ( clientResponse, clientRequest, cacheKey , 
clientRequestUrl);
  +                }
  +                catch (RedirectException e) {
  +                    redirect = true;
  +                }
                   freshCopy = true;
               }
               else {
  @@ -347,8 +403,8 @@
               //the Set-Cookie header is only forwarded back to the client if
               //this is a fresh copy of the object we are returning.
               //So we can guarantee that the returned Set-Cookie is the one 
targetted for the current client
  -            copyHeadersFromServerResponseToClientResponse(clientResponse, 
!freshCopy); //doesn't copy over saved cookie for responses returned from the 
cache
  -            //TODO: might be inconsistancies
  +            copyHeadersFromServerResponseToClientResponse(clientResponse, 
!freshCopy, redirect); //doesn't copy over saved cookie for responses returned 
from the cache
  +            //TODO: might be inconsistencies
               //TODO: 1/ when simply a fragment of a skeleton is fetched
               //TODO: and we return the Set-Cookie of the cached skeleton and 
not of the newly
               //TODO: fetched fragment. Not sure what behaviour to adopt here.
  @@ -356,16 +412,17 @@
               //TODO: but isn't because the object is already cached. Might 
not be important since
               //TODO: original GET URL contains an ESI identifier which has a 
similar role to cookies. Need to check
   
  -            boolean return304NotModified = 
checkIfConditionalHtppHeaders(clientRequest, cacheObject);
  +            boolean return304NotModified = 
checkIfConditionalHttpHeaders(clientRequest, cacheObject);
   
               if (return304NotModified) {
  -                log.debug("Returning a HTPP 304 for 
"+cacheObject.getUrlCacheObject().getUrl());
  +                log.debug("Returning a HTTP 304 for 
"+cacheObject.getUrlCacheObject().getUrl());
                   
clientResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED); //HTTP 304: the 
document was not modified
                   //no data sent since request object hasn't changed
               }
               else {
                   clientResponse.setStatus(getStatusCode());
  -                if (!methodToServer.getName().equals("HEAD")) //since there 
is no content for HEAD requests
  +                if (!methodToServer.getName().equals("HEAD") //since there 
is no content for HEAD requests
  +                        && !redirect )  //since there is no content for 
redirection requests
                       sendStreamToClientFromCache(clientResponse, cacheKey, 
cachedByteContent);
               }
           }
  @@ -375,20 +432,21 @@
   
   
       public void fetch (HttpServletResponse clientResponse, 
HttpServletRequest clientRequest
  -            , String urlKey, String clientRequestUrl) {
  +            , String urlKey, String clientRequestUrl)
  +            throws RedirectException {
           //can be called because object is not in cache, or some sub-object 
is not in cache
   
           FragmentCache fragmentCache = FragmentCache.getInstance();
  -
           UrlCacheObject urlObj = (UrlCacheObject) 
fragmentCache.getHashCache().get(urlKey);
   
           Vector threads = new Vector();
  +        boolean retrievingSkeleton = false;
   
           if (urlObj==null) {
               //TODO:Need to support all other methods such as POST 
!!!!!!!!!!!!!!!!!!!!!!
   
               GetMethod getMethod = Utils.copyMethod(methodToServer);
  -            getMethod.setFollowRedirects( true );
  +            getMethod.setFollowRedirects( false );
               //TODO: statusCode ??
               //TODO: cookies??
               //TODO: esi headers??
  @@ -403,9 +461,10 @@
                       clientRequestUrl
               );
   
  +            retrievingSkeleton = true;
               threads.add(thread);
  +            
thread.setName("from:RespHdl,["+urlKey.substring(urlKey.length()-15)+"]id:"+thread.getId());
               thread.start();
  -
           }
           else {
               String[] refObjs = urlObj.getReferencedObjs();
  @@ -420,14 +479,15 @@
                       //Need to support all other methods POST 
!!!!!!!!!!!!!!!!!!!!!!
                       GetMethod getMethod = Utils.copyMethod(methodToServer);
                       try {
  -                        URI uri = new 
URI(urlObj.getReferencedObjsUrls()[i]); //TODO: what is this esacpe business?
  +                        org.apache.commons.httpclient.URI uri =
  +                                new 
org.apache.commons.httpclient.URI(urlObj.getReferencedObjsUrls()[i], true);
                           //we don't want to fetch the original URL from 
methodToServer
                           // but the one referenced here
                           getMethod.setURI(uri);
                       } catch (URIException e) {
                           e.printStackTrace();
                       }
  -                    getMethod.setFollowRedirects(true);
  +                    getMethod.setFollowRedirects(false);
                       //TODO: statusCode ??
                       //TODO: cookies??
                       //TODO: esi headers??
  @@ -443,6 +503,7 @@
                       );
   
                       threads.add(thread);
  +                    
thread.setName("from:RespHdl,ref:["+refUrlKey.substring(refUrlKey.length()-15)+"]id:"+thread.getId());
                       thread.start();
                   }
                   else log.debug("Cache HIT on refUrlKey ["+ refUrlKey +"] 
referenced by  ["+urlKey+"]");
  @@ -454,6 +515,14 @@
               GetThread thread = (GetThread) threadEnum.nextElement();
               try {
                   thread.join();
  +                //need to redirect the client browser if we got a redirect 
on the skeleton retrieval
  +                if (retrievingSkeleton) {
  +                    if (thread.isRedirectDetected()) {
  +                        log.debug("throwing RedirectException");
  +                        throw new RedirectException("server redirect 
detected on skeleton request");
  +                    }
  +                }
  +
               } catch (InterruptedException ex) {
                   log.error("THREAD WAS INTERRUPTED !!!!!!!!!!!!!!!!!!!!");
                   //TODO: deal with error
  @@ -461,10 +530,10 @@
           }
       }
   
  -    private boolean checkIfConditionalHtppHeaders(HttpServletRequest 
clientRequest, CacheObject cacheObject) {
  +    private boolean checkIfConditionalHttpHeaders(HttpServletRequest 
clientRequest, CacheObject cacheObject) {
           boolean return304NotModified = false;
   
  -        printRequestHeaders(clientRequest);
  +        //printRequestHeaders(clientRequest);
   
           //check Entity Tag Revalidation
           String IfNoneMatchHeader = clientRequest.getHeader("If-None-Match");
  @@ -529,6 +598,9 @@
       }
   
       public static void printRequestHeaders(HttpServletRequest clientRequest) 
{
  +              printRequestHeaders( clientRequest, null);
  +    }
  +    public static void printRequestHeaders(HttpServletRequest clientRequest, 
String msg) {
           StringBuffer buffer = new StringBuffer();
           Enumeration headerNamesEnum = clientRequest.getHeaderNames();
           while (headerNamesEnum.hasMoreElements()) {
  @@ -539,26 +611,33 @@
                   buffer.append(hName +":"+ hVal+"\n");
               }
           }
  -        log.debug("HTTP client REQUEST Headers : \n" + buffer.toString());
  +        log.debug("HTTP client REQUEST Headers : "+((msg==null)?"":msg)+"\n" 
+ buffer.toString());
       }
   
       public static void printRequestHeaders(HttpMethod method) {
  +        printRequestHeaders(method, null);
  +    }
  +    public static void printRequestHeaders(HttpMethod method, String msg) {
           Header[] headers = method.getRequestHeaders();
           StringBuffer buffer = new StringBuffer();
           for (int i=0; i<headers.length; i++){
               buffer.append(headers[i]);
           }
  -        log.debug("HTTP Server REQUEST Headers : \n" + buffer.toString());
  +        log.debug("HTTP Server REQUEST Headers : "+((msg==null)?"":msg)+"\n" 
+ buffer.toString());
       }
   
  -
       public static void printResponseHeaders(HttpMethod method) {
  +           printResponseHeaders( method, null);
  +    }
  +
  +    public static void printResponseHeaders(HttpMethod method, String msg) {
           Header[] headers = method.getResponseHeaders();
           StringBuffer buffer = new StringBuffer();
           for (int i=0; i<headers.length; i++){
               buffer.append(headers[i]);
           }
  -        log.debug("HTTP Server RESPONSE Headers : \n" + buffer.toString());
  +        log.debug("HTTP Server ["+method.getStatusCode()+"]  RESPONSE 
Headers  "+((msg==null)?"":msg)+" : \n"
  +                + buffer.toString());
       }
   
   
  

Reply via email to