Author: johnh
Date: Mon Jan 10 20:05:56 2011
New Revision: 1057339
URL: http://svn.apache.org/viewvc?rev=1057339&view=rev
Log:
Make ETag filter more extensible.
Modified:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ETagFilter.java
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ETaggingHttpResponse.java
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ETaggingHttpResponseTest.java
Modified:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ETagFilter.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ETagFilter.java?rev=1057339&r1=1057338&r2=1057339&view=diff
==============================================================================
---
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ETagFilter.java
(original)
+++
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ETagFilter.java
Mon Jan 10 20:05:56 2011
@@ -50,8 +50,7 @@ public class ETagFilter implements Filte
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
if (request instanceof HttpServletRequest && response instanceof
HttpServletResponse) {
- ETaggingHttpResponse taggingResponse =
- new ETaggingHttpResponse((HttpServletRequest) request,
(HttpServletResponse) response);
+ ETaggingHttpResponse taggingResponse = createTaggingResponse(request,
response);
try {
chain.doFilter(request, taggingResponse);
} finally {
@@ -64,4 +63,8 @@ public class ETagFilter implements Filte
}
}
+ protected ETaggingHttpResponse createTaggingResponse(
+ ServletRequest request, ServletResponse response) {
+ return new ETaggingHttpResponse((HttpServletRequest) request,
(HttpServletResponse) response);
+ }
}
Modified:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ETaggingHttpResponse.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ETaggingHttpResponse.java?rev=1057339&r1=1057338&r2=1057339&view=diff
==============================================================================
---
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ETaggingHttpResponse.java
(original)
+++
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ETaggingHttpResponse.java
Mon Jan 10 20:05:56 2011
@@ -17,6 +17,8 @@
*/
package org.apache.shindig.gadgets.servlet;
+import com.google.common.annotations.VisibleForTesting;
+
import org.apache.http.util.ByteArrayBuffer;
import org.apache.shindig.common.util.HashUtil;
@@ -46,11 +48,11 @@ public class ETaggingHttpResponse extend
public static final String RESPONSE_HEADER = "ETag";
public static final String REQUEST_HEADER = "If-None-Match";
- private final HttpServletRequest request;
- private final BufferServletOutputStream stream;
- private ServletOutputStream originalStream;
- private PrintWriter writer;
- private boolean batching;
+ protected final HttpServletRequest request;
+ protected final BufferServletOutputStream stream;
+ protected ServletOutputStream originalStream;
+ protected PrintWriter writer;
+ protected boolean batching;
public ETaggingHttpResponse(HttpServletRequest request, HttpServletResponse
response) {
super(response);
@@ -155,8 +157,7 @@ public class ETaggingHttpResponse extend
if (etag.equals(reqEtag)) {
emitETagMatchedResult();
} else {
- getResponse().setContentLength(bytes.length);
- getResponse().getOutputStream().write(bytes);
+ emitFullResponseBody(bytes);
}
} else if (bytes.length != 0) {
originalStream.write(bytes);
@@ -164,18 +165,24 @@ public class ETaggingHttpResponse extend
}
}
- protected void emitETagMatchedResult() throws IOException {
+ protected void emitETagMatchedResult() {
((HttpServletResponse)
getResponse()).setStatus(HttpServletResponse.SC_NOT_MODIFIED);
getResponse().setContentLength(0);
}
+ protected void emitFullResponseBody(byte[] bytes) throws IOException {
+ getResponse().setContentLength(bytes.length);
+ getResponse().getOutputStream().write(bytes);
+ }
+
/**
* A ServletOutputStream that stores the data in a byte array buffer.
*/
- private class BufferServletOutputStream extends ServletOutputStream {
+ @VisibleForTesting
+ class BufferServletOutputStream extends ServletOutputStream {
private static final int BUFFER_INITIAL_CAPACITY = 16384;
- private MessageDigest digest = HashUtil.getMessageDigest();
+ private MessageDigest digest = null;
private ByteArrayBuffer buffer = new
ByteArrayBuffer(BUFFER_INITIAL_CAPACITY);
@Override
@@ -194,20 +201,26 @@ public class ETaggingHttpResponse extend
public void reset() {
buffer.clear();
- digest.reset();
+ digest = null;
}
public String getContentHash() {
+ ensureDigestObjectExists();
String hash = HashUtil.bytesToHex(digest.digest());
digest = null;
return hash;
}
private void updateDigest(int b) {
+ ensureDigestObjectExists();
+ digest.update((byte) b);
+ }
+
+ private void ensureDigestObjectExists() {
if (digest == null) {
digest = HashUtil.getMessageDigest();
+ digest.update(buffer.toByteArray());
}
- digest.update((byte) b);
}
}
}
Modified:
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ETaggingHttpResponseTest.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ETaggingHttpResponseTest.java?rev=1057339&r1=1057338&r2=1057339&view=diff
==============================================================================
---
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ETaggingHttpResponseTest.java
(original)
+++
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ETaggingHttpResponseTest.java
Mon Jan 10 20:05:56 2011
@@ -20,6 +20,7 @@ package org.apache.shindig.gadgets.servl
import static org.junit.Assert.*;
import org.apache.http.util.ByteArrayBuffer;
+import
org.apache.shindig.gadgets.servlet.ETaggingHttpResponse.BufferServletOutputStream;
import org.easymock.EasyMock;
import org.easymock.IMocksControl;
import org.junit.Before;
@@ -41,9 +42,11 @@ public class ETaggingHttpResponseTest {
new byte[] {-62, -95, 72, 111, 108, 97, 44, 32, 110, 105, -61, -79, 111,
33};
private static final String SECOND_RESPONSE_BODY = "ä½ å¥½";
private static final byte[] AFTER_SECOND_RESPONSE_BODY_BYTES =
- new byte[] {-62, -95, 72, 111, 108, 97, 44, 32, 110, 105, -61, -79, 111,
33};
+ new byte[] {-62, -95, 72, 111, 108, 97, 44, 32, 110, 105, -61, -79, 111,
33,
+ -28, -67, -96, -27, -91, -67};
private static final int RESPONSE_BODY_LENGTH = RESPONSE_BODY_BYTES.length;
private static final String GOOD_ETAG = "dae018f624d09423e7c4d7209fbea597";
+ private static final String SECOND_ETAG = "b6e56fb0129c3530f23dbb795daa3200";
private static final String BAD_ETAG = "some bogus etag";
private static final String EMPTY_CONTENT_ETAG =
"d41d8cd98f00b204e9800998ecf8427e";
@@ -84,7 +87,7 @@ public class ETaggingHttpResponseTest {
@Test
public void testNotModifiedWithPrint() throws Exception {
expectRequestETag(GOOD_ETAG);
- expectNotModifiedResponse();
+ expectNotModifiedResponse(GOOD_ETAG);
control.replay();
response.getWriter().print(RESPONSE_BODY);
@@ -123,7 +126,7 @@ public class ETaggingHttpResponseTest {
@Test
public void testNotModifiedWithWrite() throws Exception {
expectRequestETag(GOOD_ETAG);
- expectNotModifiedResponse();
+ expectNotModifiedResponse(GOOD_ETAG);
control.replay();
response.getOutputStream().write(RESPONSE_BODY_BYTES);
@@ -171,9 +174,44 @@ public class ETaggingHttpResponseTest {
response.startStreaming();
assertArrayEquals(RESPONSE_BODY_BYTES, stream.getBuffer());
- response.getWriter().print(SECOND_RESPONSE_BODY);
+ response.getOutputStream().write(SECOND_RESPONSE_BODY.getBytes("UTF-8"));
assertArrayEquals(AFTER_SECOND_RESPONSE_BODY_BYTES, stream.getBuffer());
}
+
+ @Test
+ public void testCanCalculateHashSeveralTimes() throws Exception {
+ expectRequestETag(GOOD_ETAG);
+ expectNotModifiedResponse(GOOD_ETAG);
+ control.replay();
+
+ response.getOutputStream().write(RESPONSE_BODY.getBytes("UTF-8"));
+ String hash = ((BufferServletOutputStream)
response.getOutputStream()).getContentHash();
+ assertEquals(GOOD_ETAG, hash);
+ hash = ((BufferServletOutputStream)
response.getOutputStream()).getContentHash();
+ assertEquals(GOOD_ETAG, hash);
+
+ response.flushBuffer();
+ assertResponseBodyIsEmpty();
+ control.verify();
+ }
+
+ @Test
+ public void testHashVariesAsDataIsAdded() throws Exception {
+ expectRequestETag(SECOND_ETAG);
+ expectNotModifiedResponse(SECOND_ETAG);
+ control.replay();
+
+ response.getOutputStream().write(RESPONSE_BODY.getBytes("UTF-8"));
+ String hash = ((BufferServletOutputStream)
response.getOutputStream()).getContentHash();
+ assertEquals(GOOD_ETAG, hash);
+ response.getOutputStream().write(SECOND_RESPONSE_BODY.getBytes("UTF-8"));
+ hash = ((BufferServletOutputStream)
response.getOutputStream()).getContentHash();
+ assertEquals(SECOND_ETAG, hash);
+
+ response.flushBuffer();
+ assertResponseBodyIsEmpty();
+ control.verify();
+ }
private void expectRequestETag(String eTag) {
EasyMock.expect(request.getHeader(ETaggingHttpResponse.REQUEST_HEADER)).andReturn(eTag);
@@ -184,8 +222,8 @@ public class ETaggingHttpResponseTest {
origResponse.setContentLength(RESPONSE_BODY_LENGTH);
}
- private void expectNotModifiedResponse() {
- origResponse.setHeader(ETaggingHttpResponse.RESPONSE_HEADER, GOOD_ETAG);
+ private void expectNotModifiedResponse(String eTag) {
+ origResponse.setHeader(ETaggingHttpResponse.RESPONSE_HEADER, eTag);
origResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
origResponse.setContentLength(0);
}