You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by lr...@apache.org on 2008/02/01 22:39:47 UTC

svn commit: r617660 - in /incubator/shindig/trunk: features/core/ java/gadgets/src/main/java/org/apache/shindig/gadgets/ java/gadgets/src/main/java/org/apache/shindig/gadgets/http/

Author: lryan
Date: Fri Feb  1 13:39:37 2008
New Revision: 617660

URL: http://svn.apache.org/viewvc?rev=617660&view=rev
Log:
Initial support for request signing including
 - GadgetTokens used to sign requests
 - POST request fetching
 - Setting security token (st) and authorization (authz) params
 - encoding form post into postData param
 - JsFeature loader supports '//' path prefixes to mean host relative URLs

Modified:
    incubator/shindig/trunk/features/core/io.js
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetToken.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicRemoteContentFetcher.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetToken.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentFetcher.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java

Modified: incubator/shindig/trunk/features/core/io.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/core/io.js?rev=617660&r1=617659&r2=617660&view=diff
==============================================================================
--- incubator/shindig/trunk/features/core/io.js (original)
+++ incubator/shindig/trunk/features/core/io.js Fri Feb  1 13:39:37 2008
@@ -126,12 +126,25 @@
       var params = opt_params || {};
       var newUrl = config.jsonProxyUrl.replace("%url%",
           encodeURIComponent(url));
+
+      // Check if authorization is requested
+      if (opt_params.AUTHORIZATION &&
+          gadgets.io.AuthorizationType[opt_params.AUTHORIZATION.toUpperCase()]
+              != gadgets.io.AuthorizationType.NONE) {
+        newUrl += "&authz=" + opt_params.AUTHORIZATION.toLowerCase();
+        // Add the security-token if available
+        if (gadgets.util.getUrlParameters()["st"]) {
+          newUrl += "&st=" + gadgets.util.getUrlParameters()["st"];
+        }
+      }
+      // TODO: Fetcher cannot distinguish between GET & POST yet.
       xhr.open(params.METHOD || "GET", newUrl, true);
       if (callback) {
         xhr.onreadystatechange = gadgets.util.makeClosure(null,
             processResponse, url, callback, params, xhr);
       }
-      xhr.send(params.postData);
+      xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
+      xhr.send("postData=" + encodeURIComponent(params.postData));
     },
 
     /**

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetToken.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetToken.java?rev=617660&r1=617659&r2=617660&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetToken.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetToken.java Fri Feb  1 13:39:37 2008
@@ -18,6 +18,9 @@
  */
 package org.apache.shindig.gadgets;
 
+import java.net.URL;
+import java.util.Map;
+
 /**
  * Primitive token implementation that uses stings as tokens.
  */
@@ -31,11 +34,21 @@
     return token;
   }
 
+
   /**
    * Generates a token from an input string
-   * @param token
+   * @param token String form of token
    */
   public BasicGadgetToken(String token) {
     this.token = token;
+  }
+
+  /**
+   * {@inheritDoc}
+   * Signer that does not sign.
+   */
+  public URL signUrl(URL uri, String httpMethod, Map parameters)
+      throws GadgetException {
+    return uri;
   }
 }

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicRemoteContentFetcher.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicRemoteContentFetcher.java?rev=617660&r1=617659&r2=617660&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicRemoteContentFetcher.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicRemoteContentFetcher.java Fri Feb  1 13:39:37 2008
@@ -13,9 +13,6 @@
  */
 package org.apache.shindig.gadgets;
 
-import org.apache.shindig.gadgets.RemoteContentFetcher;
-import org.apache.shindig.gadgets.RemoteContent;
-
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -54,6 +51,41 @@
       fetcher = (HttpURLConnection) url.openConnection();
       fetcher.setInstanceFollowRedirects(true);
       fetcher.setConnectTimeout(CONNECT_TIMEOUT_MS);
+
+      responseCode = fetcher.getResponseCode();
+      headers = fetcher.getHeaderFields();
+
+      byte chunk[] = new byte[8192];
+      int chunkSize;
+      InputStream in = fetcher.getInputStream();
+      while (out.size() < maxObjSize && (chunkSize = in.read(chunk)) != -1) {
+        out.write(chunk, 0, chunkSize);
+      }
+    } catch (IOException e) {
+      responseCode = 500;
+    }
+
+    return new RemoteContent(responseCode, out.toByteArray(), headers);
+  }
+
+  public RemoteContent fetchByPost(URL url, byte[] postData,
+      ProcessingOptions options) {
+    ByteArrayOutputStream out = new ByteArrayOutputStream();
+    
+    int responseCode;
+    HttpURLConnection fetcher;
+    Map<String, List<String>> headers = null;
+
+    try {
+      fetcher = (HttpURLConnection) url.openConnection();
+      fetcher.setRequestMethod("POST");
+      fetcher.setInstanceFollowRedirects(true);
+      fetcher.setConnectTimeout(CONNECT_TIMEOUT_MS);
+      fetcher.setRequestProperty("Content-Length", "" + postData.length);
+      fetcher.setUseCaches(false);
+      fetcher.setDoInput(true);
+      fetcher.setDoOutput(true);
+      fetcher.getOutputStream().write(postData);
 
       responseCode = fetcher.getResponseCode();
       headers = fetcher.getHeaderFields();

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetToken.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetToken.java?rev=617660&r1=617659&r2=617660&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetToken.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetToken.java Fri Feb  1 13:39:37 2008
@@ -18,6 +18,9 @@
  */
 package org.apache.shindig.gadgets;
 
+import java.net.URL;
+import java.util.Map;
+
 /**
  * An abstract representation of a signing token.
  * Use in conjuction with @code GadgetSigner.
@@ -32,4 +35,16 @@
    * @return A string representation of the token.
    */
   public String toSerialForm();
+
+
+  /**
+   * Sign a URL using this token
+   * @param uri The URL to sign
+   * @param httpMethod The HTTP method used
+   * @param parameters associated with the signing request
+   * @return The signed URL
+   * @throws GadgetException
+   */
+  public URL signUrl(URL uri, String httpMethod, Map parameters)
+      throws GadgetException;
 }

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java?rev=617660&r1=617659&r2=617660&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java Fri Feb  1 13:39:37 2008
@@ -367,6 +367,9 @@
           content = srcNode.getTextContent();
           if (content.startsWith("http://")) {
             type = JsLibrary.Type.URL;
+          } else if (content.startsWith("//")) {
+            type = JsLibrary.Type.URL;
+            content = content.substring(1);
           } else if (content.startsWith("res://")) {
             content = content.substring(6);
             type = JsLibrary.Type.RESOURCE;

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentFetcher.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentFetcher.java?rev=617660&r1=617659&r2=617660&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentFetcher.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentFetcher.java Fri Feb  1 13:39:37 2008
@@ -16,5 +16,22 @@
 import java.net.URL;
 
 public interface RemoteContentFetcher {
+
+  /**
+   * Fetch content using the HTTP GET method
+   * @param url Location of content to fetch
+   * @param options Additioanl options
+   * @return RemoteContent
+   */
   public RemoteContent fetch(URL url, ProcessingOptions options);
+
+  /**
+   * Fetch content using the HTTP POST method
+   * @param url Location of content to fetch
+   * @param postData The data to post
+   * @param options Additioanl options
+   * @return RemoteContent
+   */
+  public RemoteContent fetchByPost(URL url, byte[] postData,
+      ProcessingOptions options);
 }

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java?rev=617660&r1=617659&r2=617660&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java Fri Feb  1 13:39:37 2008
@@ -24,13 +24,16 @@
 import org.apache.shindig.gadgets.GadgetToken;
 import org.apache.shindig.gadgets.ProcessingOptions;
 import org.apache.shindig.gadgets.RemoteContent;
+import org.apache.shindig.gadgets.RemoteContentFetcher;
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.net.URLDecoder;
 import java.util.List;
 import java.util.Map;
 
@@ -43,27 +46,34 @@
   private static final int TWO_HOURS_IN_MS = 7200000;
   private static final int ONE_HOUR_IN_SECS = 3600;
   private static final int MAX_PROXY_SIZE = 1024 * 1024;
-  private static final BasicRemoteContentFetcher fetcher =
-      new BasicRemoteContentFetcher(MAX_PROXY_SIZE);
+  
+  private final RemoteContentFetcher fetcher;
+
+  public ProxyHandler() {
+    this(new BasicRemoteContentFetcher(MAX_PROXY_SIZE));
+  }
+  
+  public ProxyHandler(RemoteContentFetcher fetcher) {
+    this.fetcher = fetcher;
+  }
 
   public void fetchJson(HttpServletRequest request,
                         HttpServletResponse response,
                         GadgetSigner signer)
       throws ServletException, IOException {
 
-    if (signer != null) {
-      // We're just going to toss away the token, but it should exist.
-      extractAndValidateToken(request, signer);
-    }
-
-    // Validate url= parameter
-    URL origin = extractAndValidateUrl(request);
+    GadgetToken token = extractAndValidateToken(request, signer);
+    URL originalUrl = extractAndValidateUrl(request);
+    URL signedUrl = signUrl(originalUrl, token, request);
 
     // Fetch the content and convert it into JSON.
-    RemoteContent results = fetcher.fetch(origin, new ProcessingOptions());
+    // TODO: Fetcher needs to handle variety of HTTP methods.
+    RemoteContent results = fetchContent(signedUrl, request,
+        new ProcessingOptions());
+
     String output;
     try {
-      String json = new JSONObject().put(origin.toString(), new JSONObject()
+      String json = new JSONObject().put(originalUrl.toString(), new JSONObject()
           .put("body", new String(results.getByteArray()))
           .put("rc", results.getHttpStatusCode())
           ).toString();
@@ -84,14 +94,14 @@
                     GadgetSigner signer)
       throws ServletException, IOException {
 
-    if (signer != null) {
-      // We're just going to toss away the token, but it should exist.
-      extractAndValidateToken(request, signer);
-    }
+    GadgetToken token = extractAndValidateToken(request, signer);
+    URL originalUrl = extractAndValidateUrl(request);
+    URL signedUrl = signUrl(originalUrl, token, request);
+
+    // TODO: Fetcher needs to handle variety of HTTP methods.
+    RemoteContent results = fetchContent(signedUrl, request,
+        new ProcessingOptions());
 
-    // Validate url= parameter
-    URL origin = extractAndValidateUrl(request);
-    RemoteContent results = fetcher.fetch(origin, new ProcessingOptions());
     int status = results.getHttpStatusCode();
     response.setStatus(status);
     if (status == HttpServletResponse.SC_OK) {
@@ -116,6 +126,25 @@
   }
 
   /**
+   * Fetch the content for a request
+   */
+  private RemoteContent fetchContent(URL signedUrl, HttpServletRequest request,
+      ProcessingOptions procOptions) throws ServletException {
+    try {
+      if (request.getMethod().equals("POST")) {
+        String data = request.getParameter("postData");
+        return fetcher.fetchByPost(signedUrl,
+            URLDecoder.decode(data, request.getCharacterEncoding()).getBytes(),
+            procOptions);
+      } else {
+        return fetcher.fetch(signedUrl, new ProcessingOptions());
+      }
+    } catch (UnsupportedEncodingException uee) {
+      throw new ServletException(uee);
+    }
+  }
+
+  /**
    * Gets the url= parameter from the request and applies some basic sanity
    * checking.
    *
@@ -147,17 +176,19 @@
 
   /**
    * @return A valid token for the given input.
+   * @throws ServletException
    */
   private GadgetToken extractAndValidateToken(HttpServletRequest request,
       GadgetSigner signer) throws ServletException {
-    String token = request.getParameter("t");
-    if (token == null) {
-      token = "";
-    }
     try {
+      if (signer == null) return null;
+      String token = request.getParameter("st");
+      if (token == null) {
+        token = "";
+      }
       return signer.createToken(token);
-    } catch (GadgetException e) {
-      throw new ServletException(e);
+    } catch (GadgetException ge) {
+      throw new ServletException(ge);
     }
   }
 
@@ -173,4 +204,23 @@
     response.setDateHeader("Expires", System.currentTimeMillis()
                                      + TWO_HOURS_IN_MS);
   }
+
+  /**
+   * Sign a URL with a GadgetToken if needed
+   * @return 
+   */
+  private URL signUrl(URL originalUrl, GadgetToken token,
+      HttpServletRequest request) throws ServletException {
+    try {
+      if (token == null ||
+          !"signed".equals(request.getParameter("authz"))) {
+        return originalUrl;
+      }
+      return token.signUrl(originalUrl, "GET", // TODO: request.getMethod() 
+          request.getParameterMap());
+    } catch (GadgetException ge) {
+      throw new ServletException(ge);
+    }
+  }
+
 }

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java?rev=617660&r1=617659&r2=617660&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java Fri Feb  1 13:39:37 2008
@@ -29,8 +29,8 @@
 import javax.servlet.http.HttpServletResponse;
 
 public class ProxyServlet extends HttpServlet {
-  private final static ProxyHandler handler = new ProxyHandler();
   private final GadgetSigner signer;
+  private final ProxyHandler handler;
 
   @Override
   protected void doGet(HttpServletRequest request, HttpServletResponse response)
@@ -43,19 +43,27 @@
     }
   }
 
+  @Override
+  protected void doPost(HttpServletRequest request, HttpServletResponse response)
+      throws ServletException, IOException {
+    // Currently they are identical
+    doGet(request, response);
+  }
+
   /**
    * Constructs a ProxyServlet with the default (non-secure) GadgetSigner.
    */
   public ProxyServlet() {
-    this(new BasicGadgetSigner());
+    this(new BasicGadgetSigner(), new ProxyHandler());
   }
 
   /**
    * Creates a ProxyServlet using the specified GadgetSigner.
-   *
-   * @param signer
+   * @param signer Used to sign and verify requests
+   * @param handler Used to fetch proxied content
    */
-  public ProxyServlet(GadgetSigner signer) {
+  public ProxyServlet(GadgetSigner signer, ProxyHandler handler) {
     this.signer = signer;
+    this.handler = handler;
   }
 }



Re: svn commit: r617660 - in /incubator/shindig/trunk: features/core/ java/gadgets/src/main/java/org/apache/shindig/gadgets/ java/gadgets/src/main/java/org/apache/shindig/gadgets/http/

Posted by Kevin Brown <et...@google.com>.
On Feb 1, 2008 1:39 PM, <lr...@apache.org> wrote:

> Author: lryan
> Date: Fri Feb  1 13:39:37 2008
> New Revision: 617660
>
> URL: http://svn.apache.org/viewvc?rev=617660&view=rev
> Log:
> Initial support for request signing including
>  - GadgetTokens used to sign requests
>  - POST request fetching
>  - Setting security token (st) and authorization (authz) params
>  - encoding form post into postData param
>  - JsFeature loader supports '//' path prefixes to mean host relative URLs
>
> Modified:
>    incubator/shindig/trunk/features/core/io.js
>
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetToken.java
>
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicRemoteContentFetcher.java
>
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetToken.java
>
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java
>
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentFetcher.java
>
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java
>
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java
>
> Modified: incubator/shindig/trunk/features/core/io.js
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/features/core/io.js?rev=617660&r1=617659&r2=617660&view=diff
>
> ==============================================================================
> --- incubator/shindig/trunk/features/core/io.js (original)
> +++ incubator/shindig/trunk/features/core/io.js Fri Feb  1 13:39:37 2008
> @@ -126,12 +126,25 @@
>       var params = opt_params || {};
>       var newUrl = config.jsonProxyUrl.replace("%url%",
>           encodeURIComponent(url));
> +
> +      // Check if authorization is requested
> +      if (opt_params.AUTHORIZATION &&
> +          gadgets.io.AuthorizationType
> [opt_params.AUTHORIZATION.toUpperCase()]


This is unnecessary. The keys and values are the same in the spec. You can
safely use the short (upper case) string version of the field in all cases
here.


>
> +              != gadgets.io.AuthorizationType.NONE) {
> +        newUrl += "&authz=" + opt_params.AUTHORIZATION.toLowerCase();


And we should just stick with upper case everywhere, even if it looks
slightly ugly. Makes things less error prone.


>
> +        // Add the security-token if available
> +        if (gadgets.util.getUrlParameters()["st"]) {
> +          newUrl += "&st=" + gadgets.util.getUrlParameters()["st"];
> +        }
> +      }


st is passed in the hash, not on the query string, so
gadgets.util.getUrlParameters() won't contain it. This is important for
caching and so that it doesn't leak in referrer headers. Perhaps we should
make getHashParameters() for cases like this.


> +      // TODO: Fetcher cannot distinguish between GET & POST yet.
>       xhr.open(params.METHOD || "GET", newUrl, true);
>       if (callback) {
>         xhr.onreadystatechange = gadgets.util.makeClosure(null,
>             processResponse, url, callback, params, xhr);
>       }
> -      xhr.send(params.postData);
> +      xhr.setRequestHeader('Content-Type',
> 'application/x-www-form-urlencoded');
> +      xhr.send("postData=" + encodeURIComponent(params.postData));
>     },
>
>     /**
>
> Modified:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetToken.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetToken.java?rev=617660&r1=617659&r2=617660&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetToken.java
> (original)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetToken.java
> Fri Feb  1 13:39:37 2008
> @@ -18,6 +18,9 @@
>  */
>  package org.apache.shindig.gadgets;
>
> +import java.net.URL;
> +import java.util.Map;
> +
>  /**
>  * Primitive token implementation that uses stings as tokens.
>  */
> @@ -31,11 +34,21 @@
>     return token;
>   }
>
> +
>   /**
>    * Generates a token from an input string
> -   * @param token
> +   * @param token String form of token
>    */
>   public BasicGadgetToken(String token) {
>     this.token = token;
> +  }
> +
> +  /**
> +   * {@inheritDoc}
> +   * Signer that does not sign.
> +   */
> +  public URL signUrl(URL uri, String httpMethod, Map parameters)
> +      throws GadgetException {
> +    return uri;
>   }
>  }
>
> Modified:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicRemoteContentFetcher.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicRemoteContentFetcher.java?rev=617660&r1=617659&r2=617660&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicRemoteContentFetcher.java
> (original)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicRemoteContentFetcher.java
> Fri Feb  1 13:39:37 2008
> @@ -13,9 +13,6 @@
>  */
>  package org.apache.shindig.gadgets;
>
> -import org.apache.shindig.gadgets.RemoteContentFetcher;
> -import org.apache.shindig.gadgets.RemoteContent;
> -
>  import java.io.ByteArrayOutputStream;
>  import java.io.IOException;
>  import java.io.InputStream;
> @@ -54,6 +51,41 @@
>       fetcher = (HttpURLConnection) url.openConnection();
>       fetcher.setInstanceFollowRedirects(true);
>       fetcher.setConnectTimeout(CONNECT_TIMEOUT_MS);
> +
> +      responseCode = fetcher.getResponseCode();
> +      headers = fetcher.getHeaderFields();
> +
> +      byte chunk[] = new byte[8192];
> +      int chunkSize;
> +      InputStream in = fetcher.getInputStream();
> +      while (out.size() < maxObjSize && (chunkSize = in.read(chunk)) !=
> -1) {
> +        out.write(chunk, 0, chunkSize);
> +      }
> +    } catch (IOException e) {
> +      responseCode = 500;
> +    }
> +
> +    return new RemoteContent(responseCode, out.toByteArray(), headers);
> +  }
> +
> +  public RemoteContent fetchByPost(URL url, byte[] postData,
> +      ProcessingOptions options) {
> +    ByteArrayOutputStream out = new ByteArrayOutputStream();
> +
> +    int responseCode;
> +    HttpURLConnection fetcher;
> +    Map<String, List<String>> headers = null;
> +
> +    try {
> +      fetcher = (HttpURLConnection) url.openConnection();
> +      fetcher.setRequestMethod("POST");
> +      fetcher.setInstanceFollowRedirects(true);
> +      fetcher.setConnectTimeout(CONNECT_TIMEOUT_MS);
> +      fetcher.setRequestProperty("Content-Length", "" + postData.length);
> +      fetcher.setUseCaches(false);
> +      fetcher.setDoInput(true);
> +      fetcher.setDoOutput(true);
> +      fetcher.getOutputStream().write(postData);
>
>       responseCode = fetcher.getResponseCode();
>       headers = fetcher.getHeaderFields();
>
> Modified:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetToken.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetToken.java?rev=617660&r1=617659&r2=617660&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetToken.java
> (original)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetToken.java
> Fri Feb  1 13:39:37 2008
> @@ -18,6 +18,9 @@
>  */
>  package org.apache.shindig.gadgets;
>
> +import java.net.URL;
> +import java.util.Map;
> +
>  /**
>  * An abstract representation of a signing token.
>  * Use in conjuction with @code GadgetSigner.
> @@ -32,4 +35,16 @@
>    * @return A string representation of the token.
>    */
>   public String toSerialForm();
> +
> +
> +  /**
> +   * Sign a URL using this token
> +   * @param uri The URL to sign
> +   * @param httpMethod The HTTP method used
> +   * @param parameters associated with the signing request
> +   * @return The signed URL
> +   * @throws GadgetException
> +   */
> +  public URL signUrl(URL uri, String httpMethod, Map parameters)
> +      throws GadgetException;
>  }
>
> Modified:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java?rev=617660&r1=617659&r2=617660&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java
> (original)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java
> Fri Feb  1 13:39:37 2008
> @@ -367,6 +367,9 @@
>           content = srcNode.getTextContent();
>           if (content.startsWith("http://")) {
>             type = JsLibrary.Type.URL;
> +          } else if (content.startsWith("//")) {
> +            type = JsLibrary.Type.URL;
> +            content = content.substring(1);
>           } else if (content.startsWith("res://")) {
>             content = content.substring(6);
>             type = JsLibrary.Type.RESOURCE;
>
> Modified:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentFetcher.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentFetcher.java?rev=617660&r1=617659&r2=617660&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentFetcher.java
> (original)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentFetcher.java
> Fri Feb  1 13:39:37 2008
> @@ -16,5 +16,22 @@
>  import java.net.URL;
>
>  public interface RemoteContentFetcher {
> +
> +  /**
> +   * Fetch content using the HTTP GET method
> +   * @param url Location of content to fetch
> +   * @param options Additioanl options
> +   * @return RemoteContent
> +   */
>   public RemoteContent fetch(URL url, ProcessingOptions options);
> +
> +  /**
> +   * Fetch content using the HTTP POST method
> +   * @param url Location of content to fetch
> +   * @param postData The data to post
> +   * @param options Additioanl options
> +   * @return RemoteContent
> +   */
> +  public RemoteContent fetchByPost(URL url, byte[] postData,
> +      ProcessingOptions options);
>  }


>
> Modified:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java?rev=617660&r1=617659&r2=617660&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java
> (original)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java
> Fri Feb  1 13:39:37 2008
> @@ -24,13 +24,16 @@
>  import org.apache.shindig.gadgets.GadgetToken;
>  import org.apache.shindig.gadgets.ProcessingOptions;
>  import org.apache.shindig.gadgets.RemoteContent;
> +import org.apache.shindig.gadgets.RemoteContentFetcher;
>  import org.json.JSONException;
>  import org.json.JSONObject;
>
>  import java.io.IOException;
>  import java.io.PrintWriter;
> +import java.io.UnsupportedEncodingException;
>  import java.net.MalformedURLException;
>  import java.net.URL;
> +import java.net.URLDecoder;
>  import java.util.List;
>  import java.util.Map;
>
> @@ -43,27 +46,34 @@
>   private static final int TWO_HOURS_IN_MS = 7200000;
>   private static final int ONE_HOUR_IN_SECS = 3600;
>   private static final int MAX_PROXY_SIZE = 1024 * 1024;
> -  private static final BasicRemoteContentFetcher fetcher =
> -      new BasicRemoteContentFetcher(MAX_PROXY_SIZE);
> +
> +  private final RemoteContentFetcher fetcher;
> +
> +  public ProxyHandler() {
> +    this(new BasicRemoteContentFetcher(MAX_PROXY_SIZE));
> +  }
> +
> +  public ProxyHandler(RemoteContentFetcher fetcher) {
> +    this.fetcher = fetcher;
> +  }
>
>   public void fetchJson(HttpServletRequest request,
>                         HttpServletResponse response,
>                         GadgetSigner signer)
>       throws ServletException, IOException {
>
> -    if (signer != null) {
> -      // We're just going to toss away the token, but it should exist.
> -      extractAndValidateToken(request, signer);
> -    }
> -
> -    // Validate url= parameter
> -    URL origin = extractAndValidateUrl(request);
> +    GadgetToken token = extractAndValidateToken(request, signer);
> +    URL originalUrl = extractAndValidateUrl(request);
> +    URL signedUrl = signUrl(originalUrl, token, request);
>
>     // Fetch the content and convert it into JSON.
> -    RemoteContent results = fetcher.fetch(origin, new
> ProcessingOptions());
> +    // TODO: Fetcher needs to handle variety of HTTP methods.
> +    RemoteContent results = fetchContent(signedUrl, request,
> +        new ProcessingOptions());
> +
>     String output;
>     try {
> -      String json = new JSONObject().put(origin.toString(), new
> JSONObject()
> +      String json = new JSONObject().put(originalUrl.toString(), new
> JSONObject()
>           .put("body", new String(results.getByteArray()))
>           .put("rc", results.getHttpStatusCode())
>           ).toString();
> @@ -84,14 +94,14 @@
>                     GadgetSigner signer)
>       throws ServletException, IOException {
>
> -    if (signer != null) {
> -      // We're just going to toss away the token, but it should exist.
> -      extractAndValidateToken(request, signer);
> -    }
> +    GadgetToken token = extractAndValidateToken(request, signer);
> +    URL originalUrl = extractAndValidateUrl(request);
> +    URL signedUrl = signUrl(originalUrl, token, request);


Shouldn't we only be signing for requests that actually require it?


> +
> +    // TODO: Fetcher needs to handle variety of HTTP methods.
> +    RemoteContent results = fetchContent(signedUrl, request,
> +        new ProcessingOptions());
>
> -    // Validate url= parameter
> -    URL origin = extractAndValidateUrl(request);
> -    RemoteContent results = fetcher.fetch(origin, new
> ProcessingOptions());
>     int status = results.getHttpStatusCode();
>     response.setStatus(status);
>     if (status == HttpServletResponse.SC_OK) {
> @@ -116,6 +126,25 @@
>   }
>
>   /**
> +   * Fetch the content for a request
> +   */
> +  private RemoteContent fetchContent(URL signedUrl, HttpServletRequest
> request,
> +      ProcessingOptions procOptions) throws ServletException {
> +    try {
> +      if (request.getMethod().equals("POST")) {
> +        String data = request.getParameter("postData");
> +        return fetcher.fetchByPost(signedUrl,
> +            URLDecoder.decode(data, request.getCharacterEncoding
> ()).getBytes(),
> +            procOptions);
> +      } else {
> +        return fetcher.fetch(signedUrl, new ProcessingOptions());
> +      }
> +    } catch (UnsupportedEncodingException uee) {
> +      throw new ServletException(uee);
> +    }
> +  }
> +
> +  /**
>    * Gets the url= parameter from the request and applies some basic
> sanity
>    * checking.
>    *
> @@ -147,17 +176,19 @@
>
>   /**
>    * @return A valid token for the given input.
> +   * @throws ServletException
>    */
>   private GadgetToken extractAndValidateToken(HttpServletRequest request,
>       GadgetSigner signer) throws ServletException {
> -    String token = request.getParameter("t");
> -    if (token == null) {
> -      token = "";
> -    }
>     try {
> +      if (signer == null) return null;
> +      String token = request.getParameter("st");
> +      if (token == null) {
> +        token = "";
> +      }
>       return signer.createToken(token);
> -    } catch (GadgetException e) {
> -      throw new ServletException(e);
> +    } catch (GadgetException ge) {
> +      throw new ServletException(ge);
>     }
>   }
>
> @@ -173,4 +204,23 @@
>     response.setDateHeader("Expires", System.currentTimeMillis()
>                                      + TWO_HOURS_IN_MS);
>   }
> +
> +  /**
> +   * Sign a URL with a GadgetToken if needed
> +   * @return
> +   */
> +  private URL signUrl(URL originalUrl, GadgetToken token,
> +      HttpServletRequest request) throws ServletException {
> +    try {
> +      if (token == null ||
> +          !"signed".equals(request.getParameter("authz"))) {
> +        return originalUrl;
> +      }
> +      return token.signUrl(originalUrl, "GET", // TODO: request.getMethod
> ()
> +          request.getParameterMap());
> +    } catch (GadgetException ge) {
> +      throw new ServletException(ge);
> +    }
> +  }
> +
>  }
>
> Modified:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java?rev=617660&r1=617659&r2=617660&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java
> (original)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java
> Fri Feb  1 13:39:37 2008
> @@ -29,8 +29,8 @@
>  import javax.servlet.http.HttpServletResponse;
>
>  public class ProxyServlet extends HttpServlet {
> -  private final static ProxyHandler handler = new ProxyHandler();
>   private final GadgetSigner signer;
> +  private final ProxyHandler handler;
>
>   @Override
>   protected void doGet(HttpServletRequest request, HttpServletResponse
> response)
> @@ -43,19 +43,27 @@
>     }
>   }
>
> +  @Override
> +  protected void doPost(HttpServletRequest request, HttpServletResponse
> response)
> +      throws ServletException, IOException {
> +    // Currently they are identical
> +    doGet(request, response);
> +  }
> +
>   /**
>    * Constructs a ProxyServlet with the default (non-secure) GadgetSigner.
>    */
>   public ProxyServlet() {
> -    this(new BasicGadgetSigner());
> +    this(new BasicGadgetSigner(), new ProxyHandler());
>   }
>
>   /**
>    * Creates a ProxyServlet using the specified GadgetSigner.
> -   *
> -   * @param signer
> +   * @param signer Used to sign and verify requests
> +   * @param handler Used to fetch proxied content
>    */
> -  public ProxyServlet(GadgetSigner signer) {
> +  public ProxyServlet(GadgetSigner signer, ProxyHandler handler) {
>     this.signer = signer;
> +    this.handler = handler;
>   }
>  }
>
>
>