You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by jo...@apache.org on 2010/07/19 19:57:38 UTC
svn commit: r965572 - in /shindig/trunk/java/gadgets/src:
main/java/org/apache/shindig/gadgets/http/
main/java/org/apache/shindig/gadgets/servlet/
main/java/org/apache/shindig/gadgets/uri/
test/java/org/apache/shindig/gadgets/servlet/
Author: johnh
Date: Mon Jul 19 17:57:38 2010
New Revision: 965572
URL: http://svn.apache.org/viewvc?rev=965572&view=rev
Log:
Handle POST requests in Accel service.
Also includes several enhancements and tests for UriUtils.
Patch provided by Gagan Singh. Thanks!
Modified:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpRequest.java
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/AccelHandler.java
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HtmlAccelServlet.java
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/UriUtils.java
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/HtmlAccelServletTest.java
Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpRequest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpRequest.java?rev=965572&r1=965571&r2=965572&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpRequest.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpRequest.java Mon Jul 19 17:57:38 2010
@@ -51,6 +51,10 @@ public class HttpRequest {
private String method = "GET";
private Uri uri;
private final Map<String, List<String>> headers = Maps.newTreeMap(String.CASE_INSENSITIVE_ORDER);
+
+ // Internal parameters which serve as extra information to pass along the
+ // chain of HttpRequest processing.
+ // NOTE: These are not get/post parameter equivalent of HttpServletRequest.
private final Map<String, String> params = Maps.newHashMap();
private byte[] postBody = ArrayUtils.EMPTY_BYTE_ARRAY;
Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/AccelHandler.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/AccelHandler.java?rev=965572&r1=965571&r2=965572&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/AccelHandler.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/AccelHandler.java Mon Jul 19 17:57:38 2010
@@ -102,9 +102,9 @@ public class AccelHandler extends ProxyB
// Copy the response headers and status code to the final http servlet
// response.
UriUtils.copyResponseHeadersAndStatusCode(
- results, response,
- UriUtils.DisallowedResponseHeaders.OUTPUT_TRANSFER_DIRECTIVES,
- UriUtils.DisallowedResponseHeaders.CLIENT_STATE_DIRECTIVES);
+ results, response, true,
+ UriUtils.DisallowedHeaders.OUTPUT_TRANSFER_DIRECTIVES,
+ UriUtils.DisallowedHeaders.CLIENT_STATE_DIRECTIVES);
// Override the content type of the final http response if the input request
// had the rewrite mime type header.
@@ -160,7 +160,8 @@ public class AccelHandler extends ProxyB
}
/**
- * Generate a remote content request based on the parameters sent from the client.
+ * Build an HttpRequest object encapsulating the request details as requested
+ * by the user.
* @param request The http request.
* @param uriToProxyOrRewrite The parsed uri to proxy or rewrite through
* accel servlet.
@@ -173,12 +174,21 @@ public class AccelHandler extends ProxyB
Uri tgt = uriToProxyOrRewrite.getResource();
validateUrl(tgt);
HttpRequest req = uriToProxyOrRewrite.makeHttpRequest(tgt);
- this.setRequestHeaders(request, req);
-
if (req == null) {
throw new GadgetException(GadgetException.Code.INVALID_PARAMETER,
"No url parameter in request", HttpResponse.SC_BAD_REQUEST);
}
+
+ // Copy the post body if it exists.
+ UriUtils.copyRequestData(request, req);
+
+ // Set and copy headers.
+ this.setRequestHeaders(request, req);
+ UriUtils.copyRequestHeaders(
+ request, req,
+ UriUtils.DisallowedHeaders.POST_INCOMPATIBLE_DIRECTIVES);
+
+ req.setFollowRedirects(false);
return req;
}
Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HtmlAccelServlet.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HtmlAccelServlet.java?rev=965572&r1=965571&r2=965572&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HtmlAccelServlet.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HtmlAccelServlet.java Mon Jul 19 17:57:38 2010
@@ -62,4 +62,10 @@ public class HtmlAccelServlet extends In
}
accelHandler.fetch(request, response);
}
+
+ @Override
+ protected void doPost(HttpServletRequest request, HttpServletResponse response)
+ throws IOException {
+ doGet(request, response);
+ }
}
Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/UriUtils.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/UriUtils.java?rev=965572&r1=965571&r2=965572&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/UriUtils.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/UriUtils.java Mon Jul 19 17:57:38 2010
@@ -19,15 +19,17 @@
package org.apache.shindig.gadgets.uri;
import com.google.common.collect.ImmutableSet;
-
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.http.HttpRequest;
import org.apache.shindig.gadgets.http.HttpResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
+import java.util.Enumeration;
+import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-import java.util.HashSet;
-
-import javax.servlet.http.HttpServletResponse;
/**
* Utility functions related to URI and Http servlet response management.
@@ -38,7 +40,7 @@ public class UriUtils {
* the user. The webserver serving out the response should be responsible
* for filling these.
*/
- public enum DisallowedResponseHeaders {
+ public enum DisallowedHeaders {
// Directives controlled by the serving infrastructure.
OUTPUT_TRANSFER_DIRECTIVES(ImmutableSet.of(
"content-length", "transfer-encoding", "content-encoding", "server",
@@ -47,20 +49,25 @@ public class UriUtils {
CACHING_DIRECTIVES(ImmutableSet.of("vary", "expires", "date", "pragma",
"cache-control")),
- CLIENT_STATE_DIRECTIVES(ImmutableSet.of("set-cookie", "www-authenticate"));
+ CLIENT_STATE_DIRECTIVES(ImmutableSet.of("set-cookie", "www-authenticate")),
+
+ // Headers that the fetcher itself would like to fill. For example,
+ // httpclient library crashes if Content-Length header is set in the
+ // request being fetched.
+ POST_INCOMPATIBLE_DIRECTIVES(ImmutableSet.of("content-length"));
// Miscellaneous headers we should take care of, but are left for now.
// "set-cookie", "content-length", "content-encoding", "etag",
// "last-modified" ,"accept-ranges", "vary", "expires", "date",
// "pragma", "cache-control", "transfer-encoding", "www-authenticate"
- private Set<String> responseHeaders;
- DisallowedResponseHeaders(Set<String> responseHeaders) {
- this.responseHeaders = responseHeaders;
+ private Set<String> disallowedHeaders;
+ DisallowedHeaders(Set<String> disallowedHeaders) {
+ this.disallowedHeaders = disallowedHeaders;
}
- public Set<String> getResponseHeaders() {
- return responseHeaders;
+ public Set<String> getDisallowedHeaders() {
+ return disallowedHeaders;
}
}
@@ -101,26 +108,33 @@ public class UriUtils {
* response.
* @param data The http response when fetching the requested accel uri.
* @param resp The servlet response to return back to client.
- * @param disallowedResponseHeaderses Disallowed response headers to omit from the response
+ * @param setHeaders If true, then setHeader method of HttpServletResponse is
+ * called, otherwise addHeader is called for every header.
+ * @param disallowedResponseHeaders Disallowed response headers to omit from the response
* returned to the user.
* @throws IOException In case the http response was not successful.
*/
public static void copyResponseHeadersAndStatusCode(
HttpResponse data, HttpServletResponse resp,
- DisallowedResponseHeaders... disallowedResponseHeaderses)
+ boolean setHeaders,
+ DisallowedHeaders... disallowedResponseHeaders)
throws IOException {
// Pass original return code:
resp.setStatus(data.getHttpStatusCode());
Set<String> allDisallowedHeaders = new HashSet<String>();
- for (DisallowedResponseHeaders h : disallowedResponseHeaderses) {
- allDisallowedHeaders.addAll(h.getResponseHeaders());
+ for (DisallowedHeaders h : disallowedResponseHeaders) {
+ allDisallowedHeaders.addAll(h.getDisallowedHeaders());
}
for (Map.Entry<String, String> entry : data.getHeaders().entries()) {
if (isValidHeaderName(entry.getKey()) && isValidHeaderValue(entry.getValue()) &&
!allDisallowedHeaders.contains(entry.getKey().toLowerCase())) {
- resp.setHeader(entry.getKey(), entry.getValue());
+ if (setHeaders) {
+ resp.setHeader(entry.getKey(), entry.getValue());
+ } else {
+ resp.addHeader(entry.getKey(), entry.getValue());
+ }
}
}
@@ -129,4 +143,66 @@ public class UriUtils {
resp.sendError(HttpResponse.SC_BAD_GATEWAY);
}
}
+
+ /**
+ * Copies headers from HttpServletRequest object to HttpRequest object.
+ * @param data Servlet request to copy headers from.
+ * @param req The HttpRequest object to copy headers to.
+ * @param disallowedRequestHeaders Disallowed request headers to omit from
+ * the servlet request
+ */
+ public static void copyRequestHeaders(HttpServletRequest data,
+ HttpRequest req,
+ DisallowedHeaders... disallowedRequestHeaders) {
+ Set<String> allDisallowedHeaders = new HashSet<String>();
+ for (DisallowedHeaders h : disallowedRequestHeaders) {
+ allDisallowedHeaders.addAll(h.getDisallowedHeaders());
+ }
+
+ Enumeration headerNames = data.getHeaderNames();
+ if (headerNames != null) {
+ while (headerNames.hasMoreElements()) {
+ Object headerObj = headerNames.nextElement();
+ if (!(headerObj instanceof String)) {
+ continue;
+ }
+
+ String header = (String) headerObj;
+ Enumeration headerValues = data.getHeaders(header);
+ if (headerValues != null && headerValues.hasMoreElements() &&
+ isValidHeaderName(header) &&
+ !allDisallowedHeaders.contains(header.toLowerCase())) {
+ // Remove existing values of this header.
+ req.removeHeader(header);
+
+ while (headerValues.hasMoreElements()) {
+ Object valueObj = headerValues.nextElement();
+ if (valueObj != null && valueObj instanceof String &&
+ isValidHeaderValue((String) valueObj)) {
+ // Add this header to data.
+ req.addHeader(header, (String) valueObj);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Copies the post data from HttpServletRequest object to HttpRequest object.
+ * @param request Servlet request to copy post data from.
+ * @param req The HttpRequest object to copy post data to.
+ * @throws GadgetException In case of errors.
+ */
+ public static void copyRequestData(HttpServletRequest request,
+ HttpRequest req) throws GadgetException {
+ req.setMethod(request.getMethod());
+ try {
+ if (request.getMethod().toLowerCase().equals("post")) {
+ req.setPostBody(request.getInputStream());
+ }
+ } catch (IOException e) {
+ throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
+ }
+ }
}
Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/HtmlAccelServletTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/HtmlAccelServletTest.java?rev=965572&r1=965571&r2=965572&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/HtmlAccelServletTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/HtmlAccelServletTest.java Mon Jul 19 17:57:38 2010
@@ -32,12 +32,18 @@ import org.apache.shindig.gadgets.rewrit
import org.apache.shindig.gadgets.uri.AccelUriManager;
import org.apache.shindig.gadgets.uri.DefaultAccelUriManager;
import org.apache.shindig.gadgets.uri.DefaultProxyUriManager;
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.easymock.IAnswer;
import org.junit.Before;
import org.junit.Test;
+import javax.servlet.ServletInputStream;
+import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
+import static org.easymock.EasyMock.capture;
import static org.easymock.EasyMock.expect;
public class HtmlAccelServletTest extends ServletTestFixture {
@@ -87,6 +93,51 @@ public class HtmlAccelServletTest extend
accelUriManager));
}
+ private void expectRequest(String extraPath, String url) {
+ expect(request.getMethod()).andReturn("GET").anyTimes();
+ expect(request.getServletPath()).andReturn(SERVLET).anyTimes();
+ expect(request.getScheme()).andReturn("http").anyTimes();
+ expect(request.getServerName()).andReturn("apache.org").anyTimes();
+ expect(request.getServerPort()).andReturn(-1).anyTimes();
+ expect(request.getRequestURI()).andReturn(SERVLET + extraPath).anyTimes();
+ expect(request.getRequestURL())
+ .andReturn(new StringBuffer("apache.org" + SERVLET + extraPath))
+ .anyTimes();
+ String queryParams = (url == null ? "" : "url=" + url + "&container=accel"
+ + "&gadget=test");
+ expect(request.getQueryString()).andReturn(queryParams).anyTimes();
+ }
+
+ private void expectPostRequest(String extraPath, String url,
+ final String data)
+ throws IOException {
+ expect(request.getMethod()).andReturn("POST").anyTimes();
+ expect(request.getServletPath()).andReturn(SERVLET).anyTimes();
+ expect(request.getScheme()).andReturn("http").anyTimes();
+ expect(request.getServerName()).andReturn("apache.org").anyTimes();
+ expect(request.getServerPort()).andReturn(-1).anyTimes();
+ expect(request.getRequestURI()).andReturn(SERVLET + extraPath).anyTimes();
+ expect(request.getRequestURL())
+ .andReturn(new StringBuffer("apache.org" + SERVLET + extraPath))
+ .anyTimes();
+ String queryParams = (url == null ? "" : "url=" + url + "&container=accel"
+ + "&gadget=test");
+ expect(request.getQueryString()).andReturn(queryParams).anyTimes();
+
+ ServletInputStream inputStream = mock(ServletInputStream.class);
+ expect(request.getInputStream()).andReturn(inputStream);
+ expect(inputStream.read((byte[]) EasyMock.anyObject()))
+ .andAnswer(new IAnswer<Integer>() {
+ public Integer answer() throws Throwable {
+ byte[] byteArray = (byte[]) EasyMock.getCurrentArguments()[0];
+ System.arraycopy(data.getBytes(), 0, byteArray, 0, data.length());
+ return data.length();
+ }
+ });
+ expect(inputStream.read((byte[]) EasyMock.anyObject()))
+ .andReturn(-1);
+ }
+
@Test
public void testHtmlAccelNoData() throws Exception {
String url = "http://example.org/data.html";
@@ -191,17 +242,27 @@ public class HtmlAccelServletTest extend
assertFalse(rewriter.responseWasRewritten());
}
- private void expectRequest(String extraPath, String url) {
- expect(request.getServletPath()).andReturn(SERVLET).anyTimes();
- expect(request.getScheme()).andReturn("http").anyTimes();
- expect(request.getServerName()).andReturn("apache.org").anyTimes();
- expect(request.getServerPort()).andReturn(-1).anyTimes();
- expect(request.getRequestURI()).andReturn(SERVLET + extraPath).anyTimes();
- expect(request.getRequestURL())
- .andReturn(new StringBuffer("apache.org" + SERVLET + extraPath))
- .anyTimes();
- String queryParams = (url == null ? "" : "url=" + url + "&container=accel"
- + "&gadget=test");
- expect(request.getQueryString()).andReturn(queryParams).anyTimes();
+ @Test
+ public void testHtmlAccelHandlesPost() throws Exception {
+ String url = "http://example.org/data.html";
+ String data = "<html><body>This is error page</body></html>";
+
+ ((FakeCaptureRewriter) rewriter).setContentToRewrite(data);
+ Capture<HttpRequest> req = new Capture<HttpRequest>();
+ HttpResponse resp = new HttpResponseBuilder()
+ .setResponse(data.getBytes())
+ .setHeader("Content-Type", "text/html")
+ .create();
+ expect(pipeline.execute(capture(req))).andReturn(resp).once();
+ expectPostRequest("", url, "hello=world");
+ replay();
+
+ servlet.doPost(request, recorder);
+ verify();
+ assertEquals(data, recorder.getResponseAsString());
+ assertEquals(200, recorder.getHttpStatusCode());
+ assertTrue(rewriter.responseWasRewritten());
+ assertEquals("POST", req.getValue().getMethod());
+ assertEquals("hello=world", req.getValue().getPostBodyAsString());
}
}