You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by et...@apache.org on 2008/06/10 19:17:02 UTC

svn commit: r666216 - in /incubator/shindig/trunk: config/ java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ java/server/src/main/webapp/WEB-INF/

Author: etnu
Date: Tue Jun 10 10:17:01 2008
New Revision: 666216

URL: http://svn.apache.org/viewvc?rev=666216&view=rev
Log:
First phase of proxy cleanup (SHINDIG-370).

This splits the makeRequest and open proxies into two pieces so that their unique security and feature differences can be more cleanly addressed.


Added:
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/MakeRequestServlet.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/HttpServletResponseRecorder.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/MakeRequestServletTest.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ProxyServletTest.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ServletTestFixture.java
Modified:
    incubator/shindig/trunk/config/container.js
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyHandler.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyServlet.java
    incubator/shindig/trunk/java/server/src/main/webapp/WEB-INF/web.full.xml
    incubator/shindig/trunk/java/server/src/main/webapp/WEB-INF/web.xml

Modified: incubator/shindig/trunk/config/container.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/config/container.js?rev=666216&r1=666215&r2=666216&view=diff
==============================================================================
--- incubator/shindig/trunk/config/container.js (original)
+++ incubator/shindig/trunk/config/container.js Tue Jun 10 10:17:01 2008
@@ -59,7 +59,7 @@
   "core.io" : {
     // Note: /proxy is an open proxy. Be careful how you expose this!
     "proxyUrl" : "proxy?refresh=%refresh%&url=%url%",
-    "jsonProxyUrl" : "proxy?output=js"
+    "jsonProxyUrl" : "makeRequest"
   },
   "views" : {
     "profile" : {

Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/MakeRequestServlet.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/MakeRequestServlet.java?rev=666216&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/MakeRequestServlet.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/MakeRequestServlet.java Tue Jun 10 10:17:01 2008
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.servlet;
+
+import org.apache.shindig.common.servlet.InjectedServlet;
+import org.apache.shindig.gadgets.GadgetException;
+
+import com.google.inject.Inject;
+
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Handles calls to gadgets.io.makeRequest.
+ *
+ * GET and POST are supported so as to facilitate improved browser caching.
+ *
+ * Currently this just delegates to ProxyHandler, which deals with both
+ * makeRequest and open proxy calls.
+ */
+public class MakeRequestServlet extends InjectedServlet {
+  private final static Logger LOG = Logger.getLogger(MakeRequestServlet.class.getName());
+
+  private ProxyHandler proxyHandler;
+
+  @Inject
+  public void setProxyHandler(ProxyHandler proxyHandler) {
+    this.proxyHandler = proxyHandler;
+  }
+
+  @Override
+  protected void doGet(HttpServletRequest request, HttpServletResponse response)
+      throws IOException {
+    try {
+      proxyHandler.fetchJson(request, response);
+    } catch (GadgetException e) {
+      // TODO: Move this logic into ProxyHandler / MakeRequestHandler.
+      outputError(e, response);
+    }
+  }
+
+  @Override
+  protected void doPost(HttpServletRequest request,  HttpServletResponse response)
+      throws IOException {
+    doGet(request, response);
+  }
+
+  /**
+   * Outputs an error message for the request if it fails.
+   *
+   * TODO: Eliminate this.
+   */
+  private static void outputError(GadgetException e, HttpServletResponse resp)
+      throws IOException {
+    LOG.log(Level.INFO, "makeRequest failed", e);
+    resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
+  }
+}

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyHandler.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyHandler.java?rev=666216&r1=666215&r2=666216&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyHandler.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyHandler.java Tue Jun 10 10:17:01 2008
@@ -363,6 +363,10 @@
       response.setContentType(rcr.getOptions().rewriteMimeType);
     }
 
+    if (results.getHttpStatusCode() != HttpResponse.SC_OK) {
+      response.sendError(results.getHttpStatusCode());
+    }
+
     response.getOutputStream().write(results.getResponseAsBytes());
   }
 

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyServlet.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyServlet.java?rev=666216&r1=666215&r2=666216&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyServlet.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyServlet.java Tue Jun 10 10:17:01 2008
@@ -20,7 +20,6 @@
 
 import org.apache.shindig.common.servlet.InjectedServlet;
 import org.apache.shindig.gadgets.GadgetException;
-import org.apache.shindig.gadgets.servlet.ProxyServletRequest;
 
 import com.google.inject.Inject;
 
@@ -28,14 +27,15 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+/**
+ * Handles open proxy requests (used in rewriting and for urls returned by
+ * gadgets.io.getProxyUrl).
+ */
 public class ProxyServlet extends InjectedServlet {
-
-  private static final Logger logger
-      = Logger.getLogger("org.apache.shindig.gadgets");
+  private final static Logger LOG = Logger.getLogger(ProxyServlet.class.getName());
 
   private ProxyHandler proxyHandler;
 
@@ -47,37 +47,21 @@
   @Override
   protected void doGet(HttpServletRequest request, HttpServletResponse response)
       throws IOException {
-    ProxyServletRequest proxyRequest = new ProxyServletRequest(request);    
-    String output = proxyRequest.getParameter("output");
     try {
-      if ("js".equals(output)) {
-        proxyHandler.fetchJson(proxyRequest, response);
-      } else {
-        proxyHandler.fetch(proxyRequest, response);
-      }
-    } catch (GadgetException ge) {
-      outputError(ge, response);
+      proxyHandler.fetch(new ProxyServletRequest(request), response);
+    } catch (GadgetException e) {
+      outputError(e, response);
     }
   }
 
-  @SuppressWarnings("unused")
-  @Override
-  protected void doPost(HttpServletRequest request,
-      HttpServletResponse response) throws ServletException, IOException {
-    // Currently they are identical
-    doGet(request, response);
-  }
-
-  private static void outputError(GadgetException excep, HttpServletResponse resp)
+  /**
+   * Outputs an error message for the request if it fails.
+   *
+   * TODO: Eliminate this.
+   */
+  private static void outputError(GadgetException e, HttpServletResponse resp)
       throws IOException {
-    StringBuilder err = new StringBuilder();
-    err.append(excep.getCode().toString());
-    err.append(' ');
-    err.append(excep.getMessage());
-
-    // Log the errors here for now. We might want different severity levels
-    // for different error codes.
-    logger.log(Level.INFO, "Proxy request failed", err);
-    resp.sendError(HttpServletResponse.SC_BAD_REQUEST, err.toString());
+    LOG.log(Level.INFO, "makeRequest failed", e);
+    resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
   }
 }

Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/HttpServletResponseRecorder.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/HttpServletResponseRecorder.java?rev=666216&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/HttpServletResponseRecorder.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/HttpServletResponseRecorder.java Tue Jun 10 10:17:01 2008
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.servlet;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+/**
+ * Captures output from an HttpServletResponse.
+ */
+public class HttpServletResponseRecorder extends HttpServletResponseWrapper {
+  private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+  private final PrintWriter writer = new PrintWriter(baos);
+  private int httpStatusCode = 200;
+
+  public HttpServletResponseRecorder(HttpServletResponse response) {
+    super(response);
+  }
+
+  public String getResponseAsString() {
+    try {
+      writer.close();
+      return new String(baos.toByteArray(), "UTF-8");
+    } catch (IOException e) {
+      return null;
+    }
+  }
+
+  public byte[] getResponseAsBytes() {
+    return baos.toByteArray();
+  }
+
+  public int getHttpStatusCode() {
+    return httpStatusCode;
+  }
+
+  @Override
+  public PrintWriter getWriter() {
+    return writer;
+  }
+
+  @Override
+  public ServletOutputStream getOutputStream() {
+    return new ServletOutputStream() {
+      @Override
+      public void write(int b) {
+        baos.write(b);
+      }
+    };
+  }
+
+  @Override
+  public void setStatus(int httpStatusCode) {
+    this.httpStatusCode = httpStatusCode;
+  }
+
+  @Override
+  public void sendError(int httpStatusCode) {
+    this.httpStatusCode = httpStatusCode;
+  }
+
+  @Override
+  public void setStatus(int httpStatusCode, String msg) {
+    writer.write(msg);
+    this.httpStatusCode = httpStatusCode;
+  }
+
+  @Override
+  public void sendError(int httpStatusCode, String msg) {
+    writer.write(msg);
+    this.httpStatusCode = httpStatusCode;
+  }
+}

Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/MakeRequestServletTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/MakeRequestServletTest.java?rev=666216&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/MakeRequestServletTest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/MakeRequestServletTest.java Tue Jun 10 10:17:01 2008
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.servlet;
+
+import static junitx.framework.StringAssert.assertContains;
+import static junitx.framework.StringAssert.assertStartsWith;
+import static org.easymock.EasyMock.expect;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.http.HttpRequest;
+import org.apache.shindig.gadgets.http.HttpResponse;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.net.URI;
+import java.util.Collections;
+import java.util.Enumeration;
+
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Tests for MakeRequestServlet.
+ *
+ * Tests are trivial; real tests are in ProxyHandlerTest.
+ */
+public class MakeRequestServletTest {
+  private static final String REQUEST_URL = "http://example.org/file";
+  private static final String RESPONSE_BODY = "Hello, world!";
+  private static final String ERROR_MESSAGE = "Broken!";
+  private static final Enumeration<String> EMPTY_ENUM
+      = Collections.enumeration(Collections.<String>emptyList());
+
+  private final ServletTestFixture fixture = new ServletTestFixture();
+  private final MakeRequestServlet servlet = new MakeRequestServlet();
+  private final HttpServletResponseRecorder recorder
+      = new HttpServletResponseRecorder(fixture.response);
+  private final HttpRequest request = HttpRequest.getRequest(URI.create(REQUEST_URL), false);
+  private final HttpResponse response = new HttpResponse(RESPONSE_BODY);
+
+  @Before
+  public void setUp() {
+    servlet.setProxyHandler(fixture.proxyHandler);
+    expect(fixture.request.getHeaderNames()).andReturn(EMPTY_ENUM).anyTimes();
+    expect(fixture.request.getParameter(ProxyHandler.METHOD_PARAM))
+        .andReturn("GET").anyTimes();
+    expect(fixture.request.getParameter(ProxyHandler.URL_PARAM)).andReturn(REQUEST_URL).anyTimes();
+  }
+
+  private void setupGet() {
+    expect(fixture.request.getMethod()).andReturn("GET").anyTimes();
+  }
+
+  private void setupPost() {
+    expect(fixture.request.getMethod()).andReturn("POST").anyTimes();
+  }
+
+  private void assertResponseOk(int expectedStatus, String expectedBody) throws JSONException {
+    if (recorder.getHttpStatusCode() == HttpServletResponse.SC_OK) {
+      String body = recorder.getResponseAsString();
+      assertStartsWith(ProxyHandler.UNPARSEABLE_CRUFT, body);
+      body = body.substring(ProxyHandler.UNPARSEABLE_CRUFT.length());
+      JSONObject object = new JSONObject(body);
+      object = object.getJSONObject(REQUEST_URL);
+      assertEquals(expectedStatus, object.getInt("rc"));
+      assertEquals(expectedBody, object.getString("body"));
+    } else {
+      fail("Invalid response for request.");
+    }
+  }
+
+  @Test
+  public void doGetNormal() throws Exception {
+    setupGet();
+    expect(fixture.httpFetcher.fetch(request)).andReturn(response);
+    fixture.replay();
+
+    servlet.doGet(fixture.request, recorder);
+
+    assertResponseOk(HttpResponse.SC_OK, RESPONSE_BODY);
+  }
+
+  @Test
+  public void doGetHttpError() throws Exception {
+    setupGet();
+    expect(fixture.httpFetcher.fetch(request)).andReturn(HttpResponse.notFound());
+    fixture.replay();
+
+    servlet.doGet(fixture.request, recorder);
+
+    assertResponseOk(HttpResponse.SC_NOT_FOUND, "");
+  }
+
+  @Test
+  public void doGetException() throws Exception {
+    setupGet();
+    expect(fixture.httpFetcher.fetch(request)).andThrow(
+        new GadgetException(GadgetException.Code.FAILED_TO_RETRIEVE_CONTENT, ERROR_MESSAGE));
+    fixture.replay();
+
+    servlet.doGet(fixture.request, recorder);
+
+    assertEquals(HttpServletResponse.SC_BAD_REQUEST, recorder.getHttpStatusCode());
+    assertContains(ERROR_MESSAGE, recorder.getResponseAsString());
+  }
+
+  @Test
+  public void doPostNormal() throws Exception {
+    setupPost();
+    expect(fixture.httpFetcher.fetch(request)).andReturn(response);
+    fixture.replay();
+
+    servlet.doPost(fixture.request, recorder);
+
+    assertResponseOk(HttpResponse.SC_OK, RESPONSE_BODY);
+  }
+
+  @Test
+  public void doPostHttpError() throws Exception {
+    setupPost();
+    expect(fixture.httpFetcher.fetch(request)).andReturn(HttpResponse.notFound());
+    fixture.replay();
+
+    servlet.doGet(fixture.request, recorder);
+
+    assertResponseOk(HttpResponse.SC_NOT_FOUND, "");
+  }
+
+  @Test
+  public void doPostException() throws Exception {
+    setupPost();
+    expect(fixture.httpFetcher.fetch(request)).andThrow(
+        new GadgetException(GadgetException.Code.FAILED_TO_RETRIEVE_CONTENT, ERROR_MESSAGE));
+    fixture.replay();
+
+    servlet.doPost(fixture.request, recorder);
+
+    assertEquals(HttpServletResponse.SC_BAD_REQUEST, recorder.getHttpStatusCode());
+    assertContains(ERROR_MESSAGE, recorder.getResponseAsString());
+  }
+}

Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ProxyServletTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ProxyServletTest.java?rev=666216&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ProxyServletTest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ProxyServletTest.java Tue Jun 10 10:17:01 2008
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.servlet;
+
+import static junitx.framework.StringAssert.assertContains;
+import static org.easymock.EasyMock.expect;
+import static org.junit.Assert.assertEquals;
+
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.http.HttpRequest;
+import org.apache.shindig.gadgets.http.HttpResponse;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.net.URI;
+import java.util.Collections;
+import java.util.Enumeration;
+
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Tests for ProxyServlet.
+ *
+ * Tests are trivial; real tests are in ProxyHandlerTest.
+ */
+public class ProxyServletTest {
+  private static final String REQUEST_DOMAIN = "example.org";
+  private static final String REQUEST_URL = "http://example.org/file";
+  private static final String BASIC_SYNTAX_URL
+      = "http://opensocial.org/proxy?foo=bar&url=" + REQUEST_URL;
+  private static final String ALT_SYNTAX_URL
+      = "http://opensocial.org/proxy/foo=bar/" + REQUEST_URL;
+  private static final String RESPONSE_BODY = "Hello, world!";
+  private static final String ERROR_MESSAGE = "Broken!";
+  private static final Enumeration<String> EMPTY_ENUM
+      = Collections.enumeration(Collections.<String>emptyList());
+
+  private final ServletTestFixture fixture = new ServletTestFixture();
+  private final ProxyServlet servlet = new ProxyServlet();
+  private final HttpServletResponseRecorder recorder
+      = new HttpServletResponseRecorder(fixture.response);
+  private final HttpRequest request = HttpRequest.getRequest(URI.create(REQUEST_URL), false);
+  private final HttpResponse response = new HttpResponse(RESPONSE_BODY);
+
+  @Before
+  public void setUp() {
+    servlet.setProxyHandler(fixture.proxyHandler);
+    expect(fixture.request.getHeaderNames()).andReturn(EMPTY_ENUM).anyTimes();
+    expect(fixture.request.getParameter(ProxyHandler.METHOD_PARAM))
+        .andReturn("GET").anyTimes();
+    expect(fixture.request.getParameter(ProxyHandler.URL_PARAM))
+        .andReturn(REQUEST_URL).anyTimes();
+    expect(fixture.request.getMethod()).andReturn("GET").anyTimes();
+    expect(fixture.request.getHeader("Host")).andReturn(REQUEST_DOMAIN).anyTimes();
+    expect(fixture.lockedDomainService.embedCanRender(REQUEST_DOMAIN))
+        .andReturn(true).anyTimes();
+  }
+
+  private void setupBasic() {
+    expect(fixture.request.getRequestURI()).andReturn(BASIC_SYNTAX_URL);
+  }
+
+  private void setupAltSyntax() {
+    expect(fixture.request.getRequestURI()).andReturn(ALT_SYNTAX_URL);
+  }
+
+  private void assertResponseOk(int expectedStatus, String expectedBody) {
+      assertEquals(expectedStatus, recorder.getHttpStatusCode());
+      assertEquals(expectedBody, recorder.getResponseAsString());
+  }
+
+  @Test
+  public void doGetNormal() throws Exception {
+    setupBasic();
+    expect(fixture.httpFetcher.fetch(request)).andReturn(response);
+    fixture.replay();
+
+    servlet.doGet(fixture.request, recorder);
+
+    assertResponseOk(HttpResponse.SC_OK, RESPONSE_BODY);
+  }
+
+  @Test
+  public void doGetHttpError() throws Exception {
+    setupBasic();
+    expect(fixture.httpFetcher.fetch(request)).andReturn(HttpResponse.notFound());
+    fixture.replay();
+
+    servlet.doGet(fixture.request, recorder);
+
+    assertResponseOk(HttpResponse.SC_NOT_FOUND, "");
+  }
+
+  @Test
+  public void doGetException() throws Exception {
+    setupBasic();
+    expect(fixture.httpFetcher.fetch(request)).andThrow(
+        new GadgetException(GadgetException.Code.FAILED_TO_RETRIEVE_CONTENT, ERROR_MESSAGE));
+    fixture.replay();
+
+    servlet.doGet(fixture.request, recorder);
+
+    assertEquals(HttpServletResponse.SC_BAD_REQUEST, recorder.getHttpStatusCode());
+    assertContains(ERROR_MESSAGE, recorder.getResponseAsString());
+  }
+
+  @Test
+  public void doGetAlternateSyntax() throws Exception {
+    setupAltSyntax();
+    expect(fixture.request.getRequestURI()).andReturn(ALT_SYNTAX_URL);
+    expect(fixture.httpFetcher.fetch(request)).andReturn(response);
+    fixture.replay();
+
+    servlet.doGet(fixture.request, recorder);
+
+    assertResponseOk(HttpResponse.SC_OK, RESPONSE_BODY);
+  }
+}

Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ServletTestFixture.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ServletTestFixture.java?rev=666216&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ServletTestFixture.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ServletTestFixture.java Tue Jun 10 10:17:01 2008
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.servlet;
+
+import static org.easymock.EasyMock.expect;
+
+import org.apache.shindig.common.SecurityTokenDecoder;
+import org.apache.shindig.gadgets.LockedDomainService;
+import org.apache.shindig.gadgets.http.ContentFetcherFactory;
+import org.apache.shindig.gadgets.http.HttpFetcher;
+import org.apache.shindig.gadgets.rewrite.ContentRewriter;
+import org.apache.shindig.gadgets.rewrite.NoOpContentRewriter;
+
+import org.easymock.classextension.EasyMock;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Contains everything needed for making servlet requests.
+ */
+public class ServletTestFixture {
+  private final List<Object> mocks = new ArrayList<Object>();
+
+  public final HttpServletRequest request = mock(HttpServletRequest.class);
+  public final HttpServletResponse response = mock(HttpServletResponse.class);
+  public final SecurityTokenDecoder securityTokenDecoder = mock(SecurityTokenDecoder.class);
+  public final HttpFetcher httpFetcher = mock(HttpFetcher.class);
+  public final LockedDomainService lockedDomainService = mock(LockedDomainService.class);
+  public final ContentRewriter rewriter = new NoOpContentRewriter();
+  public final ProxyHandler proxyHandler;
+
+  public ServletTestFixture() {
+    // TODO: This is horrible. It needs to be fixed.
+    ContentFetcherFactory contentFetcherFactory = mock(ContentFetcherFactory.class);
+    expect(contentFetcherFactory.get()).andReturn(httpFetcher).anyTimes();
+
+    proxyHandler = new ProxyHandler(
+        contentFetcherFactory,
+        securityTokenDecoder,
+        lockedDomainService,
+        rewriter);
+  }
+
+  /**
+   * Creates a strict mock object for the given class, adds it to the internal
+   * list of all mocks, and returns it.
+   *
+   * @param clazz Class to be mocked.
+   * @return A mock instance of the given type.
+   **/
+  protected <T> T mock(Class<T> clazz) {
+    return mock(clazz, false);
+  }
+
+  /**
+   * Creates a strict or nice mock object for the given class, adds it to the internal
+   * list of all mocks, and returns it.
+   *
+   * @param clazz Class to be mocked.
+   * @param strict whether or not to make a strict mock
+   * @return A mock instance of the given type.
+   **/
+  protected <T> T mock(Class<T> clazz, boolean strict) {
+    T m = strict ? EasyMock.createMock(clazz) : EasyMock.createNiceMock(clazz);
+    mocks.add(m);
+    return m;
+  }
+
+  /**
+   * Sets each mock to replay mode in the order they were created. Call this after setting
+   * all of the mock expectations for a test.
+   */
+  protected void replay() {
+    EasyMock.replay(mocks.toArray());
+  }
+
+  /**
+   * Verifies each mock in the order they were created. Call this at the end of each test
+   * to verify the expectations were satisfied.
+   */
+  protected void verify() {
+    EasyMock.verify(mocks.toArray());
+  }
+}

Modified: incubator/shindig/trunk/java/server/src/main/webapp/WEB-INF/web.full.xml
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/server/src/main/webapp/WEB-INF/web.full.xml?rev=666216&r1=666215&r2=666216&view=diff
==============================================================================
--- incubator/shindig/trunk/java/server/src/main/webapp/WEB-INF/web.full.xml (original)
+++ incubator/shindig/trunk/java/server/src/main/webapp/WEB-INF/web.full.xml Tue Jun 10 10:17:01 2008
@@ -49,6 +49,14 @@
     </servlet-class>
   </servlet>
 
+  <!-- makeRequest -->
+  <servlet>
+    <servlet-name>makeRequest</servlet-name>
+    <servlet-class>
+      org.apache.shindig.gadgets.servlet.MakeRequestServlet
+    </servlet-class>
+  </servlet>
+
   <servlet>
     <servlet-name>concat</servlet-name>
     <servlet-class>
@@ -100,6 +108,11 @@
     <servlet-name>proxy</servlet-name>
     <url-pattern>/gadgets/proxy/*</url-pattern>
   </servlet-mapping>
+ 
+  <servlet-mapping>
+    <servlet-name>makeRequest</servlet-name>
+    <url-pattern>/gadgets/makeRequest</url-pattern>
+  </servlet-mapping>
 
   <servlet-mapping>
     <servlet-name>concat</servlet-name>

Modified: incubator/shindig/trunk/java/server/src/main/webapp/WEB-INF/web.xml
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/server/src/main/webapp/WEB-INF/web.xml?rev=666216&r1=666215&r2=666216&view=diff
==============================================================================
--- incubator/shindig/trunk/java/server/src/main/webapp/WEB-INF/web.xml (original)
+++ incubator/shindig/trunk/java/server/src/main/webapp/WEB-INF/web.xml Tue Jun 10 10:17:01 2008
@@ -49,6 +49,14 @@
     </servlet-class>
   </servlet>
 
+  <!-- makeRequest -->
+  <servlet>
+    <servlet-name>makeRequest</servlet-name>
+    <servlet-class>
+      org.apache.shindig.gadgets.MakeRequestServlet
+    </servlet-class>
+  </servlet>
+
   <!-- Concat -->
   <servlet>
     <servlet-name>concat</servlet-name>
@@ -102,6 +110,11 @@
   </servlet-mapping>
 
   <servlet-mapping>
+    <servlet-name>makeRequest</servlet-name>
+    <url-pattern>/gadgets/makeRequest</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
     <servlet-name>concat</servlet-name>
     <url-pattern>/gadgets/concat</url-pattern>
   </servlet-mapping>