cocoon-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From reinh...@apache.org
Subject svn commit: r894488 - in /cocoon/cocoon3/trunk: cocoon-rest/src/main/java/org/apache/cocoon/rest/controller/ cocoon-sample-webapp/src/test/java/org/apache/cocoon/it/ cocoon-servlet/src/main/java/org/apache/cocoon/servlet/ cocoon-servlet/src/main/java/o...
Date Tue, 29 Dec 2009 21:45:03 GMT
Author: reinhard
Date: Tue Dec 29 21:45:01 2009
New Revision: 894488

URL: http://svn.apache.org/viewvc?rev=894488&view=rev
Log:
first steps towards supporting HEAD requests properly

Modified:
    cocoon/cocoon3/trunk/cocoon-rest/src/main/java/org/apache/cocoon/rest/controller/MethodDelegator.java
    cocoon/cocoon3/trunk/cocoon-sample-webapp/src/test/java/org/apache/cocoon/it/CocoonHtmlUnitTestCase.java
    cocoon/cocoon3/trunk/cocoon-sample-webapp/src/test/java/org/apache/cocoon/it/ControllerTest.java
    cocoon/cocoon3/trunk/cocoon-sample-webapp/src/test/java/org/apache/cocoon/it/SaxPipelineTest.java
    cocoon/cocoon3/trunk/cocoon-servlet/src/main/java/org/apache/cocoon/servlet/RequestProcessor.java
    cocoon/cocoon3/trunk/cocoon-servlet/src/main/java/org/apache/cocoon/servlet/collector/ResponseHeaderCollector.java

Modified: cocoon/cocoon3/trunk/cocoon-rest/src/main/java/org/apache/cocoon/rest/controller/MethodDelegator.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-rest/src/main/java/org/apache/cocoon/rest/controller/MethodDelegator.java?rev=894488&r1=894487&r2=894488&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-rest/src/main/java/org/apache/cocoon/rest/controller/MethodDelegator.java
(original)
+++ cocoon/cocoon3/trunk/cocoon-rest/src/main/java/org/apache/cocoon/rest/controller/MethodDelegator.java
Tue Dec 29 21:45:01 2009
@@ -128,7 +128,11 @@
                 Head head = (Head) controller;
                 return head.doHead();
             }
-            return super.execute(controller);
+
+            // According to http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html a
+            // HEAD response behaves exactly the same as a GET request except that
+            // no content is sent.
+            return new GetDelegate().execute(controller);
         }
     }
 
@@ -155,6 +159,7 @@
                 Options options = (Options) controller;
                 return options.doOptions();
             }
+
             return super.execute(controller);
         }
     }
@@ -188,6 +193,7 @@
                 Put put = (Put) controller;
                 return put.doPut();
             }
+
             return super.execute(controller);
         }
     }

Modified: cocoon/cocoon3/trunk/cocoon-sample-webapp/src/test/java/org/apache/cocoon/it/CocoonHtmlUnitTestCase.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sample-webapp/src/test/java/org/apache/cocoon/it/CocoonHtmlUnitTestCase.java?rev=894488&r1=894487&r2=894488&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sample-webapp/src/test/java/org/apache/cocoon/it/CocoonHtmlUnitTestCase.java
(original)
+++ cocoon/cocoon3/trunk/cocoon-sample-webapp/src/test/java/org/apache/cocoon/it/CocoonHtmlUnitTestCase.java
Tue Dec 29 21:45:01 2009
@@ -19,6 +19,8 @@
 import java.net.URL;
 
 import org.apache.cocoon.tools.it.HtmlUnitTestCase;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.methods.HeadMethod;
 
 public abstract class CocoonHtmlUnitTestCase extends HtmlUnitTestCase {
 
@@ -32,4 +34,13 @@
         }
         return new URL(baseUrl);
     }
+
+    protected HeadMethod loadHeadResponse(String pageURL, int expectedStatusCode) throws
Exception {
+        URL url = new URL(this.setupBaseUrl(), pageURL);
+        HeadMethod method = new HeadMethod(url.toExternalForm());
+        HttpClient client = new HttpClient();
+        int statusCode = client.executeMethod(method);
+        assertEquals(expectedStatusCode, statusCode);
+        return method;
+    }
 }

Modified: cocoon/cocoon3/trunk/cocoon-sample-webapp/src/test/java/org/apache/cocoon/it/ControllerTest.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sample-webapp/src/test/java/org/apache/cocoon/it/ControllerTest.java?rev=894488&r1=894487&r2=894488&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sample-webapp/src/test/java/org/apache/cocoon/it/ControllerTest.java
(original)
+++ cocoon/cocoon3/trunk/cocoon-sample-webapp/src/test/java/org/apache/cocoon/it/ControllerTest.java
Tue Dec 29 21:45:01 2009
@@ -16,6 +16,8 @@
  */
 package org.apache.cocoon.it;
 
+import org.apache.commons.httpclient.methods.HeadMethod;
+
 /**
  * Test a SpringRESTController and StringTemplate.
  */
@@ -25,7 +27,7 @@
      * Test a pipeline that calls a SpringRESTController which delegates to a pipeline that
uses a controller
      * context-aware StringTemplate generator.
      */
-    public void testControllerInvocation() throws Exception {
+     public void testControllerInvocation() throws Exception {
         this.loadXmlPage("/controller/abc/foo?reqparam=1");
         int statusCode = this.response.getStatusCode();
         assertTrue(statusCode == 202);
@@ -35,4 +37,14 @@
         this.assertXPath("/html/body/p[3]", "reqparam=1");
         this.assertXPath("/html/body/p[4]", "testProperty=test");
     }
+
+    /**
+     * Use the HEAD method to access a pipeline that calls a SpringRESTController.
+     */
+    public void testControllerInvocationHead() throws Exception {
+        HeadMethod headMethod = this.loadHeadResponse("/controller/abc/foo?reqparam=1", 202);
+        assertEquals("text/xml", headMethod.getResponseHeader("Content-type").getValue());
+        String content = headMethod.getResponseBodyAsString();
+        assertNull(content);
+    }
 }

Modified: cocoon/cocoon3/trunk/cocoon-sample-webapp/src/test/java/org/apache/cocoon/it/SaxPipelineTest.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sample-webapp/src/test/java/org/apache/cocoon/it/SaxPipelineTest.java?rev=894488&r1=894487&r2=894488&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sample-webapp/src/test/java/org/apache/cocoon/it/SaxPipelineTest.java
(original)
+++ cocoon/cocoon3/trunk/cocoon-sample-webapp/src/test/java/org/apache/cocoon/it/SaxPipelineTest.java
Tue Dec 29 21:45:01 2009
@@ -16,6 +16,8 @@
  */
 package org.apache.cocoon.it;
 
+import org.apache.commons.httpclient.methods.HeadMethod;
+
 /**
  * Test SAX Pipelines
  */
@@ -31,6 +33,13 @@
         assertTrue(this.response.getContentAsString().indexOf("-//W3C//DTD XHTML 1.0 Strict//EN")
== -1);
     }
 
+    public void testHead() throws Exception {
+        HeadMethod headMethod = this.loadHeadResponse("/sax-pipeline/simple", 200);
+        assertEquals("text/xml", headMethod.getResponseHeader("Content-type").getValue());
+        String content = headMethod.getResponseBodyAsString();
+        assertNull(content);
+    }
+
     /**
      * A simple pipeline that produces an XHTML 1.0 document. This implicitly tests if the
      * configuration of serializers works properly.
@@ -62,4 +71,8 @@
         String lastModified = this.response.getResponseHeaderValue("Last-Modified");
         assertNull(lastModified);
     }
+
+    public void testSettingStatusCodeHead() throws Exception {
+        this.loadHeadResponse("/sax-pipeline/unauthorized", 401);
+    }
 }

Modified: cocoon/cocoon3/trunk/cocoon-servlet/src/main/java/org/apache/cocoon/servlet/RequestProcessor.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-servlet/src/main/java/org/apache/cocoon/servlet/RequestProcessor.java?rev=894488&r1=894487&r2=894488&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-servlet/src/main/java/org/apache/cocoon/servlet/RequestProcessor.java
(original)
+++ cocoon/cocoon3/trunk/cocoon-servlet/src/main/java/org/apache/cocoon/servlet/RequestProcessor.java
Tue Dec 29 21:45:01 2009
@@ -271,7 +271,7 @@
     private void sendSitemapResponse(HttpServletRequest request, HttpServletResponse response)
throws IOException {
         Settings settings = (Settings) this.beanFactory.getBean(Settings.class.getName());
 
-        // read conditational GET relevant data
+        // provide conditional GET relevant data and request method
         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         // read the 'If-Modified-Since' request header
         long ifModifiedSince = request.getDateHeader("If-Modified-Since");
@@ -281,6 +281,9 @@
         String ifNoneMatch = request.getHeader("If-None-Match");
         ResponseHeaderCollector.setIfNoneMatch(ifNoneMatch);
 
+        // request method
+        ResponseHeaderCollector.setRequestMethod(request.getMethod());
+
         // invoke the sitemap engine
         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         ByteArrayOutputStream baos = new ByteArrayOutputStream(8192);
@@ -314,6 +317,15 @@
             response.setHeader("X-Cocoon-Version", this.version);
         }
 
+        // Content-Type handling
+        String mimeType = ResponseHeaderCollector.getMimeType();
+        if (mimeType == null || "".equals(mimeType) || "content/unknown".equals(mimeType))
{
+            mimeType = this.servletContext.getMimeType(request.getRequestURI());
+        }
+        if (mimeType != null) {
+            response.setContentType(mimeType);
+        }
+
         // conditional request support (no need to send an unmodified response)
         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         if (!ResponseHeaderCollector.isModifiedResponse()) {
@@ -327,27 +339,30 @@
             return;
         }
 
-        // Content-Type handling
-        String mimeType = ResponseHeaderCollector.getMimeType();
-        if (mimeType == null || "".equals(mimeType) || "content/unknown".equals(mimeType))
{
-            mimeType = this.servletContext.getMimeType(request.getRequestURI());
-        }
-        if (mimeType != null) {
-            response.setContentType(mimeType);
-        }
+        // write the sitemap result to the output stream if at least one byte is available
and
+        // it is not a HEAD request. The Content-Length has to be sent also in the case of
+        // a HEAD request (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html).
+        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+        int contentLengh = baos.size();
+        response.setContentLength(contentLengh);
 
         // Status code handling
         response.setStatus(statusCode);
 
-        // write the sitemap result to the output stream
-        int contentLengh = baos.size();
-        if (contentLengh > 0) {
-            response.setContentLength(contentLengh);
-            if (this.logger.isInfoEnabled()) {
-                this.logger.info("Going to send response: mimeType=" + mimeType + ", contentLength="
+ contentLengh
-                        + ", statusCode=" + statusCode + ", lastModified=" + lastModified);
-            }
+        // logging
+        if (this.logger.isInfoEnabled()) {
+            this.logger.info("Going to send " + request.getMethod().toUpperCase() + " response:
mimeType=" + mimeType
+                    + ", contentLength=" + contentLengh + ", statusCode=" + statusCode +
", lastModified="
+                    + lastModified);
+        }
 
+        // in the case of a HEAD request stop processing here (i.e. don't send any content)
+        if ("HEAD".equalsIgnoreCase(request.getMethod())) {
+            return;
+        }
+
+        // send content
+        if (contentLengh > 0) {
             response.getOutputStream().write(baos.toByteArray());
         }
     }

Modified: cocoon/cocoon3/trunk/cocoon-servlet/src/main/java/org/apache/cocoon/servlet/collector/ResponseHeaderCollector.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-servlet/src/main/java/org/apache/cocoon/servlet/collector/ResponseHeaderCollector.java?rev=894488&r1=894487&r2=894488&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-servlet/src/main/java/org/apache/cocoon/servlet/collector/ResponseHeaderCollector.java
(original)
+++ cocoon/cocoon3/trunk/cocoon-servlet/src/main/java/org/apache/cocoon/servlet/collector/ResponseHeaderCollector.java
Tue Dec 29 21:45:01 2009
@@ -32,29 +32,29 @@
 @Aspect
 public class ResponseHeaderCollector {
 
+    private static CollectorDataStore collectorDataStore = new ThreadLocalCollectorDataStore();
     private static final String KEY_ETAG = ResponseHeaderCollector.class.getName() + "/etag";
     private static final String KEY_IF_MODIFIED_SINCE = ResponseHeaderCollector.class.getName()
+ "/if-modified-since";
     private static final String KEY_IF_NONE_MATCH = ResponseHeaderCollector.class.getName()
+ "/if-none-match";
     private static final String KEY_LAST_MODIFIED = ResponseHeaderCollector.class.getName()
+ "/last-modified";
     private static final String KEY_MIME_TYPE = ResponseHeaderCollector.class.getName() +
"/mime-type";
     private static final String KEY_PIPELINE_EXECUTED = ResponseHeaderCollector.class.getName()
+ "/pipeline-executed";
+    private static final String KEY_REQUEST_METHOD = ResponseHeaderCollector.class.getName()
+ "/method";
     private static final String KEY_STATUS_CODE = ResponseHeaderCollector.class.getName()
+ "/status-code";
 
-    private static CollectorDataStore collectorDataStore = new ThreadLocalCollectorDataStore();
-
     @SuppressWarnings("unchecked")
     @Around("execution(* org.apache.cocoon.pipeline.Pipeline.execute(..))")
     public Object interceptInvoke(ProceedingJoinPoint proceedingJoinPoint) throws Throwable
{
         // prepare data
         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        setPipelineExecuted(false);
+        setModifiedResponse(false);
         Pipeline<PipelineComponent> pipeline = (Pipeline<PipelineComponent>)
proceedingJoinPoint.getTarget();
 
         // collect last-modified data
         final long ifModifiedSince = getIfLastModifiedSince();
         final long lastModified = pipeline.getLastModified();
 
-        // collect eTag
+        // collect ETag
         final String noneMatch = getIfNoneMatch();
         if (pipeline instanceof CachingPipeline) {
             CachingPipeline<PipelineComponent> cachingPipeline = (CachingPipeline<PipelineComponent>)
pipeline;
@@ -90,11 +90,11 @@
 
         // repeat the pipeline
         if (repeatPipeline) {
+            setModifiedResponse(true);
             result = proceedingJoinPoint.proceed();
-            setPipelineExecuted(true);
         }
 
-        // mime type
+        // collect the mime-type
         String newValue = pipeline.getContentType();
         if (newValue != null) {
             setMimeType(newValue);
@@ -156,6 +156,10 @@
         return (String) collectorDataStore.get(KEY_MIME_TYPE);
     }
 
+    public static String getRequestMethod() {
+        return (String) collectorDataStore.get(KEY_REQUEST_METHOD);
+    }
+
     public static int getStatusCode() {
         Integer statusCode = (Integer) collectorDataStore.get(KEY_STATUS_CODE);
 
@@ -190,10 +194,14 @@
         collectorDataStore.set(KEY_MIME_TYPE, mimeType);
     }
 
-    public static void setPipelineExecuted(boolean executed) {
+    public static void setModifiedResponse(boolean executed) {
         collectorDataStore.set(KEY_PIPELINE_EXECUTED, executed);
     }
 
+    public static void setRequestMethod(String method) {
+        collectorDataStore.set(KEY_REQUEST_METHOD, method);
+    }
+
     public static void setStatusCode(int statusCode) {
         collectorDataStore.set(KEY_STATUS_CODE, statusCode);
     }



Mime
View raw message