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/02/12 05:17:19 UTC
svn commit: r620700 - 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/
java/gadgets/src/main/java/org/apache/shindig/util/ java/gadgets/src/te...
Author: etnu
Date: Mon Feb 11 20:17:18 2008
New Revision: 620700
URL: http://svn.apache.org/viewvc?rev=620700&view=rev
Log:
Implemented SHINDIG-56, and SHINDIG-38. This change required a significant overhaul of RemoteContentFetcher and ProxyHandler, and touched many parts of the code base.
Added:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentRequest.java
Modified:
incubator/shindig/trunk/features/core/feature.xml
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/GadgetServer.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/MessageBundleSubstituter.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContent.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/CajaContentFilter.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/GadgetRenderingServlet.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/RpcServlet.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/InputStreamConsumer.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/RemoteContentTest.java
Modified: incubator/shindig/trunk/features/core/feature.xml
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/core/feature.xml?rev=620700&r1=620699&r2=620700&view=diff
==============================================================================
--- incubator/shindig/trunk/features/core/feature.xml (original)
+++ incubator/shindig/trunk/features/core/feature.xml Mon Feb 11 20:17:18 2008
@@ -27,7 +27,7 @@
<script><![CDATA[
gadgets.io.init({
proxyUrl: "http://www.gmodules.com/ig/proxy?url=%url%",
- jsonProxyUrl: "proxy?url=%url%&output=js"
+ jsonProxyUrl: "proxy?output=js"
});
]]></script>
<script src="legacy.js"/>
Modified: incubator/shindig/trunk/features/core/io.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/core/io.js?rev=620700&r1=620699&r2=620700&view=diff
==============================================================================
--- incubator/shindig/trunk/features/core/io.js (original)
+++ incubator/shindig/trunk/features/core/io.js Mon Feb 11 20:17:18 2008
@@ -106,7 +106,7 @@
} else {
var parser = new DOMParser();
dom = parser.parseFromString(resp.text, "text/xml");
- if ("parsererror" == dom.documentElement.nodeName) {
+ if ("parsererror" === dom.documentElement.nodeName) {
resp.errors.push("failed to parse XML");
} else {
resp.data = dom;
@@ -146,34 +146,36 @@
// gadgets.io.RequestParameters, and validate them.
var xhr = makeXhr();
var params = opt_params || {};
- var newUrl = config.jsonProxyUrl.replace("%url%",
- encodeURIComponent(url));
+
+ xhr.open("POST", config.jsonProxyUrl, true);
+ if (callback) {
+ xhr.onreadystatechange = gadgets.util.makeClosure(
+ null, processResponse, url, callback, params, xhr);
+ }
+ // We always send a POST request; we just hide the details.
+ xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// Check if authorization is requested
+ var auth, st;
if (params.AUTHORIZATION && params.AUTHORIZATION !== "NONE") {
- newUrl += "&authz=" + 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);
+ auth = params.AUTHORIZATION.toLowerCase();
+ st = gadgets.util.getUrlParameters().st;
}
- if (params.METHOD === "POST") {
- xhr.setRequestHeader('Content-Type',
- 'application/x-www-form-urlencoded');
- if (params.POST_DATA) {
- xhr.send("postData=" + encodeURIComponent(params.POST_DATA));
- } else {
- xhr.send("postData=");
- }
- } else {
- xhr.send(null);
+
+ var headers = params.HEADERS || {};
+ if (params.METHOD === "POST" && !headers["Content-Type"]) {
+ headers["Content-Type"] = "application/x-www-form-urlencoded";
}
+
+ var postData = {
+ url: url,
+ httpMethod : params.METHOD || "GET",
+ headers: gadgets.io.encodeValues(headers),
+ postData : params.POST_DATA || "",
+ authz : auth || "",
+ st : st || "",
+ };
+ xhr.send(gadgets.io.encodeValues(postData));
},
/**
@@ -181,18 +183,22 @@
* (key=value&...)
*
* @param {Object} fields The post fields you wish to encode
- * @return {String} The processed post data; this will include a trailing
- * ampersand (&)
+ * @return {String} The processed post data in www-form-urlencoded format.
*
* @member gadgets.io
*/
encodeValues : function (fields) {
var buf = [];
+ var first = false;
for (var i in fields) {
+ if (!first) {
+ first = true;
+ } else {
+ buf.push("&");
+ }
buf.push(encodeURIComponent(i));
buf.push("=");
buf.push(encodeURIComponent(fields[i]));
- buf.push("&");
}
return buf.join("");
},
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=620700&r1=620699&r2=620700&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 Mon Feb 11 20:17:18 2008
@@ -19,6 +19,7 @@
package org.apache.shindig.gadgets;
import java.net.URL;
+import java.util.Collection;
import java.util.Map;
/**
@@ -47,8 +48,8 @@
* {@inheritDoc}
* Signer that does not sign.
*/
- public URL signUrl(URL uri, String httpMethod, Map parameters)
- throws GadgetException {
+ public URL signUrl(URL uri, String httpMethod,
+ Map<String, Collection<String>> parameters) {
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=620700&r1=620699&r2=620700&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 Mon Feb 11 20:17:18 2008
@@ -17,11 +17,10 @@
*/
package org.apache.shindig.gadgets;
-import java.io.ByteArrayOutputStream;
+import org.apache.shindig.util.InputStreamConsumer;
+
import java.io.IOException;
-import java.io.InputStream;
import java.net.HttpURLConnection;
-import java.net.URL;
import java.util.List;
import java.util.Map;
@@ -43,67 +42,82 @@
this.maxObjSize = maxObjSize;
}
- /** {@inheritDoc} */
- public RemoteContent fetch(URL url, ProcessingOptions options) {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
-
- int responseCode;
+ /**
+ * Initializes the connection.
+ *
+ * @param request
+ * @param options
+ * @return The opened connection
+ * @throws IOException
+ */
+ private HttpURLConnection getConnection(RemoteContentRequest request,
+ ProcessingOptions options) throws IOException {
HttpURLConnection fetcher;
- Map<String, List<String>> headers = null;
-
- try {
- 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);
+ fetcher = (HttpURLConnection)request.getUri().toURL().openConnection();
+ fetcher.setInstanceFollowRedirects(true);
+ fetcher.setConnectTimeout(CONNECT_TIMEOUT_MS);
+ Map<String, List<String>> reqHeaders = request.getAllHeaders();
+ for (Map.Entry<String, List<String>> entry : reqHeaders.entrySet()) {
+ List<String> value = entry.getValue();
+ if (value.size() == 1) {
+ fetcher.setRequestProperty(entry.getKey(), value.get(0));
+ } else {
+ StringBuilder headerList = new StringBuilder();
+ boolean first = false;
+ for (String val : value) {
+ if (!first) {
+ first = true;
+ } else {
+ headerList.append(",");
+ }
+ headerList.append(val);
+ }
+ fetcher.setRequestProperty(entry.getKey(), headerList.toString());
}
- } catch (IOException e) {
- responseCode = 500;
}
+ fetcher.setDefaultUseCaches(!options.getIgnoreCache());
+ return fetcher;
+ }
- return new RemoteContent(responseCode, out.toByteArray(), headers);
+ /**
+ * @param fetcher
+ * @return A RemoteContent object made by consuming the response of the
+ * given HttpURLConnection.
+ */
+ private RemoteContent makeResponse(HttpURLConnection fetcher)
+ throws IOException {
+ Map<String, List<String>> headers = fetcher.getHeaderFields();
+ int responseCode = fetcher.getResponseCode();
+ byte[] body = InputStreamConsumer.readToByteArray(
+ fetcher.getInputStream(), maxObjSize);
+ return new RemoteContent(responseCode, body, headers);
}
- public RemoteContent fetchByPost(URL url, byte[] postData,
- ProcessingOptions options) {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
-
- int responseCode;
- HttpURLConnection fetcher;
- Map<String, List<String>> headers = null;
+ /** {@inheritDoc} */
+ public RemoteContent fetch(RemoteContentRequest request,
+ ProcessingOptions options) {
+ try {
+ return makeResponse(getConnection(request, options));
+ } catch (IOException e) {
+ return RemoteContent.ERROR;
+ }
+ }
+ public RemoteContent fetchByPost(RemoteContentRequest request,
+ ProcessingOptions options) {
try {
- fetcher = (HttpURLConnection) url.openConnection();
+ HttpURLConnection fetcher = getConnection(request, options);
fetcher.setRequestMethod("POST");
- fetcher.setInstanceFollowRedirects(true);
- fetcher.setConnectTimeout(CONNECT_TIMEOUT_MS);
- fetcher.setRequestProperty("Content-Length", String.valueOf(postData.length));
+ fetcher.setRequestProperty("Content-Length",
+ String.valueOf(request.getPostBodyLength()));
fetcher.setUseCaches(false);
fetcher.setDoInput(true);
fetcher.setDoOutput(true);
- fetcher.getOutputStream().write(postData);
-
- 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);
- }
+ InputStreamConsumer.pipe(request.getPostBody(),
+ fetcher.getOutputStream());
+ return makeResponse(fetcher);
} catch (IOException e) {
- responseCode = 500;
+ return RemoteContent.ERROR;
}
-
- return new RemoteContent(responseCode, out.toByteArray(), headers);
}
}
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java?rev=620700&r1=620699&r2=620700&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java Mon Feb 11 20:17:18 2008
@@ -19,7 +19,6 @@
import org.apache.shindig.util.Check;
-import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -322,10 +321,9 @@
return;
}
- RemoteContent xml = null;
- try {
- xml = fetcher.fetch(gadgetId.getURI().toURL(), wc.context.getOptions());
- } catch (MalformedURLException e) {
+ RemoteContentRequest req = new RemoteContentRequest(gadgetId.getURI());
+ RemoteContent xml = fetcher.fetch(req, wc.context.getOptions());
+ if (xml.getHttpStatusCode() != RemoteContent.SC_OK) {
throw new GadgetException(
GadgetException.Code.FAILED_TO_RETRIEVE_CONTENT,
"Malformed gadget spec URL: " + gadgetId.getURI().toString());
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=620700&r1=620699&r2=620700&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 Mon Feb 11 20:17:18 2008
@@ -19,6 +19,7 @@
package org.apache.shindig.gadgets;
import java.net.URL;
+import java.util.Collection;
import java.util.Map;
/**
@@ -45,6 +46,6 @@
* @return The signed URL
* @throws GadgetException
*/
- public URL signUrl(URL uri, String httpMethod, Map parameters)
- throws GadgetException;
+ public URL signUrl(URL uri, String httpMethod,
+ Map<String, Collection<String>> parameters) throws GadgetException;
}
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/MessageBundleSubstituter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/MessageBundleSubstituter.java?rev=620700&r1=620699&r2=620700&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/MessageBundleSubstituter.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/MessageBundleSubstituter.java Mon Feb 11 20:17:18 2008
@@ -7,7 +7,7 @@
* "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
+ * 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
@@ -20,7 +20,6 @@
import org.json.JSONException;
import org.json.JSONObject;
-import java.net.MalformedURLException;
import java.net.URI;
import java.util.List;
import java.util.Locale;
@@ -87,10 +86,9 @@
bundle = context.getMessageBundleCache().get(uri.toString());
if (bundle == null) {
RemoteContent data = null;
- try {
- data = context.getHttpFetcher().fetch(uri.toURL(),
- context.getOptions());
- } catch (MalformedURLException e) {
+ data = context.getHttpFetcher().fetch(new RemoteContentRequest(uri),
+ context.getOptions());
+ if (data.getHttpStatusCode() != RemoteContent.SC_OK) {
throw new GadgetException(
GadgetException.Code.FAILED_TO_RETRIEVE_CONTENT,
String.format("Malformed message bundle URL: %s",
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContent.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContent.java?rev=620700&r1=620699&r2=620700&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContent.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContent.java Mon Feb 11 20:17:18 2008
@@ -17,10 +17,12 @@
*/
package org.apache.shindig.gadgets;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -28,18 +30,34 @@
* Represents the results of an HTTP content retrieval operation.
*/
public class RemoteContent {
+ // Replicate HTTP status codes here.
+ public final static int SC_OK = 200;
+ public final static int SC_INTERNAL_SERVER_ERROR = 500;
+
private final int httpStatusCode;
private static final String DEFAULT_ENCODING = "UTF-8";
private final String encoding;
+ public static final RemoteContent ERROR = new RemoteContent();
+
// Used to lazily convert to a string representation of the input.
private String responseString = null;
private final byte[] responseBytes;
private final Map<String, List<String>> headers;
/**
+ * Create a dummy empty map. Access via RemoteContent.ERROR
+ */
+ private RemoteContent() {
+ this.httpStatusCode = SC_INTERNAL_SERVER_ERROR;
+ this.responseBytes = new byte[0];
+ this.encoding = DEFAULT_ENCODING;
+ this.headers = Collections.emptyMap();
+ }
+
+ /**
* @param httpStatusCode
- * @param resultBody
+ * @param responseBytes
* @param headers May be null.
*/
public RemoteContent(int httpStatusCode, byte[] responseBytes,
@@ -48,22 +66,22 @@
if (responseBytes == null) {
this.responseBytes = new byte[0];
} else {
- this.responseBytes = responseBytes;
+ this.responseBytes = new byte[responseBytes.length];
+ System.arraycopy(
+ responseBytes, 0, this.responseBytes, 0, responseBytes.length);
}
- Map<String, List<String>> tempHeaders = new HashMap<String, List<String>>();
-
- if (headers != null) {
- for (Map.Entry<String, List<String>> header : headers.entrySet()) {
- List<String> values = new LinkedList<String>();
- for (String value : header.getValue()) {
- values.add(value);
- }
- tempHeaders.put(header.getKey(), values);
+ if (headers == null) {
+ this.headers = Collections.emptyMap();
+ } else {
+ Map<String, List<String>> tmpHeaders
+ = new HashMap<String, List<String>>();
+ for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
+ List<String> newList = new ArrayList<String>(entry.getValue());
+ tmpHeaders.put(entry.getKey(), Collections.unmodifiableList(newList));
}
+ this.headers = Collections.unmodifiableMap(tmpHeaders);
}
-
- this.headers = Collections.unmodifiableMap(tempHeaders);
this.encoding = detectEncoding();
}
@@ -90,15 +108,21 @@
return httpStatusCode;
}
- public byte[] getByteArray() {
- return responseBytes;
- }
-
+ /**
+ * @return The encoding of the response body, if we're able to determine it.
+ */
public String getEncoding() {
return encoding;
}
/**
+ * @return An input stream suitable for reading the entirety of the response.
+ */
+ public InputStream getResponse() {
+ return new ByteArrayInputStream(responseBytes);
+ }
+
+ /**
* Attempts to convert the response body to a string using the Content-Type
* header. If no Content-Type header is specified (or it doesn't include an
* encoding), we will assume it is UTF-8.
@@ -138,7 +162,7 @@
if (ret == null) {
return Collections.emptyList();
} else {
- return Collections.unmodifiableList(ret);
+ return ret;
}
}
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=620700&r1=620699&r2=620700&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 Mon Feb 11 20:17:18 2008
@@ -17,25 +17,24 @@
*/
package org.apache.shindig.gadgets;
-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
+ * @param request The request to fetch.
+ * @param options Additional options
* @return RemoteContent
*/
- public RemoteContent fetch(URL url, ProcessingOptions options);
+ public RemoteContent fetch(RemoteContentRequest request,
+ 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
+ * @param request The request to fetch.
+ * @param options Additional options
* @return RemoteContent
*/
- public RemoteContent fetchByPost(URL url, byte[] postData,
- ProcessingOptions options);
+ public RemoteContent fetchByPost(RemoteContentRequest request,
+ ProcessingOptions options);
}
Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentRequest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentRequest.java?rev=620700&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentRequest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentRequest.java Mon Feb 11 20:17:18 2008
@@ -0,0 +1,174 @@
+/*
+ * 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;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Holds request data for passing to a RemoteContentFetcher.
+ * Instances of this object are immutable.
+ *
+ * TODO: We should probably just stick the method in here. Having separate
+ * calls for POST vs. get seems unnecessary.
+ *
+ * TODO: This naming seems really ridiculous now. Why don't we just call it
+ * what it is -- an HTTP request?
+ */
+public class RemoteContentRequest {
+ private final byte[] postBody;
+
+ /**
+ * @return An input stream that can be used to read the post body.
+ */
+ public InputStream getPostBody() {
+ return new ByteArrayInputStream(postBody);
+ }
+
+ /**
+ * Retrieves the total length of the post body.
+ *
+ * @return The length of the post body.
+ */
+ public int getPostBodyLength() {
+ return postBody.length;
+ }
+
+ private final String contentType;
+ private final static String DEFAULT_CONTENT_TYPE
+ = "application/x-www-form-urlencoded; charset=utf-8";
+
+ /**
+ * @return The content type of the request (determined from request headers)
+ */
+ public String getContentType() {
+ return contentType;
+ }
+
+ private final Map<String, List<String>> headers;
+
+ /**
+ * @return All headers set in this request.
+ */
+ public Map<String, List<String>> getAllHeaders() {
+ return headers;
+ }
+
+ /**
+ * @param name The header to fetch
+ * @return A list of headers with that name (may be empty).
+ */
+ public List<String> getHeaders(String name) {
+ List<String> match = headers.get(name);
+ if (match == null) {
+ return Collections.emptyList();
+ } else {
+ return match;
+ }
+ }
+
+ /**
+ * @param name
+ * @return The first set header with the given name or null if not set. If
+ * you need multiple values for the header, use getHeaders().
+ */
+ public String getHeader(String name) {
+ List<String> headerList = getHeaders(name);
+ if (headerList.size() == 0) {
+ return null;
+ } else {
+ return headerList.get(0);
+ }
+ }
+
+ private final URI uri;
+ public URI getUri() {
+ return uri;
+ }
+
+ /**
+ *
+ * @param uri
+ * @param headers
+ * @param postBody
+ */
+ public RemoteContentRequest(URI uri,
+ Map<String, List<String>> headers,
+ byte[] postBody) {
+ this.uri = uri;
+ // Copy the headers
+ if (headers == null) {
+ this.headers = Collections.emptyMap();
+ } else {
+ Map<String, List<String>> tmpHeaders
+ = new HashMap<String, List<String>>();
+ for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
+ List<String> newList = new ArrayList<String>(entry.getValue());
+ tmpHeaders.put(entry.getKey(), Collections.unmodifiableList(newList));
+ }
+ this.headers = Collections.unmodifiableMap(tmpHeaders);
+ }
+ if (postBody == null) {
+ this.postBody = new byte[0];
+ } else {
+ this.postBody = new byte[postBody.length];
+ System.arraycopy(postBody, 0, this.postBody, 0, postBody.length);
+ }
+
+ // Calculate content type.
+ String type = getHeader("Content-Type");
+ if (type == null) {
+ contentType = DEFAULT_CONTENT_TYPE;
+ } else {
+ contentType = type;
+ }
+ }
+
+ public RemoteContentRequest(URI uri, Map<String, List<String>> headers) {
+ this(uri, headers, null);
+ }
+
+ public RemoteContentRequest(URI uri, byte[] postBody) {
+ this(uri, null, postBody);
+ }
+
+ public RemoteContentRequest(URI uri) {
+ this(uri, null, null);
+ }
+
+ @Override
+ public boolean equals(Object rhs) {
+ if (rhs == this) {return true;}
+ if (rhs instanceof RemoteContentRequest) {
+ RemoteContentRequest req = (RemoteContentRequest)rhs;
+ return uri.equals(req.uri) &&
+ Arrays.equals(postBody, req.postBody) &&
+ headers.equals(req.headers);
+ }
+ return false;
+ }
+}
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CajaContentFilter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CajaContentFilter.java?rev=620700&r1=620699&r2=620700&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CajaContentFilter.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CajaContentFilter.java Mon Feb 11 20:17:18 2008
@@ -59,8 +59,7 @@
throw new UriCallbackException(externalReference);
}
- public URI rewrite(ExternalReference externalReference, String string)
- throws UriCallbackException {
+ public URI rewrite(ExternalReference externalReference, String string) {
return externalReference.getUri();
}
};
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/GadgetRenderingServlet.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/GadgetRenderingServlet.java?rev=620700&r1=620699&r2=620700&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/GadgetRenderingServlet.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/GadgetRenderingServlet.java Mon Feb 11 20:17:18 2008
@@ -38,6 +38,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -244,7 +245,8 @@
// Preserve existing query string parameters.
URI redirURI = gadget.getContentHref();
- StringBuilder query = new StringBuilder(redirURI.getQuery());
+ String queryStr = redirURI.getQuery();
+ StringBuilder query = new StringBuilder(queryStr == null ? "" : queryStr);
// TODO: userprefs on the fragment rather than query string
query.append(getPrefsQueryString(gadget.getUserPrefValues()));
@@ -252,7 +254,8 @@
String[] libs;
String forcedLibs = options.getForcedJsLibs();
if (forcedLibs == null) {
- libs = (String[])gadget.getRequires().keySet().toArray();
+ Set<String> reqs = gadget.getRequires().keySet();
+ libs = reqs.toArray(new String[reqs.size()]);
} else {
libs = forcedLibs.split(":");
}
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=620700&r1=620699&r2=620700&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 Mon Feb 11 20:17:18 2008
@@ -24,17 +24,22 @@
import org.apache.shindig.gadgets.ProcessingOptions;
import org.apache.shindig.gadgets.RemoteContent;
import org.apache.shindig.gadgets.RemoteContentFetcher;
+import org.apache.shindig.gadgets.RemoteContentRequest;
+import org.apache.shindig.util.InputStreamConsumer;
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.net.URI;
import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -44,9 +49,6 @@
public class ProxyHandler {
private static final String UNPARSEABLE_CRUFT = "throw 1; < don't be evil' >";
- 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 final RemoteContentFetcher fetcher;
@@ -58,15 +60,16 @@
HttpServletResponse response,
GadgetSigner signer)
throws ServletException, IOException {
-
GadgetToken token = extractAndValidateToken(request, signer);
- URL originalUrl = extractAndValidateUrl(request);
+ String url = request.getParameter("url");
+ URL originalUrl = validateUrl(url);
URL signedUrl = signUrl(originalUrl, token, request);
// Fetch the content and convert it into JSON.
// TODO: Fetcher needs to handle variety of HTTP methods.
- RemoteContent results = fetchContent(signedUrl, request,
- new ProcessingOptions());
+ RemoteContent results = fetchContent(signedUrl,
+ request,
+ new HttpProcessingOptions(request));
response.setStatus(results.getHttpStatusCode());
if (results.getHttpStatusCode() == HttpServletResponse.SC_OK) {
@@ -76,8 +79,7 @@
JSONObject resp = new JSONObject()
.put("body", results.getResponseAsString())
.put("rc", results.getHttpStatusCode());
- String json = new JSONObject()
- .put(request.getParameter("url"), resp).toString();
+ String json = new JSONObject().put(url, resp).toString();
output = UNPARSEABLE_CRUFT + json;
} catch (JSONException e) {
output = "";
@@ -86,8 +88,7 @@
setCachingHeaders(response);
response.setContentType("application/json; charset=utf-8");
response.setHeader("Content-Disposition", "attachment;filename=p.txt");
- PrintWriter pw = response.getWriter();
- pw.write(output);
+ response.getWriter().write(output);
}
}
@@ -95,14 +96,14 @@
HttpServletResponse response,
GadgetSigner signer)
throws ServletException, IOException {
-
GadgetToken token = extractAndValidateToken(request, signer);
- URL originalUrl = extractAndValidateUrl(request);
+ URL originalUrl = validateUrl(request.getParameter("url"));
URL signedUrl = signUrl(originalUrl, token, request);
// TODO: Fetcher needs to handle variety of HTTP methods.
- RemoteContent results = fetchContent(signedUrl, request,
- new ProcessingOptions());
+ RemoteContent results = fetchContent(signedUrl,
+ request,
+ new HttpProcessingOptions(request));
int status = results.getHttpStatusCode();
response.setStatus(status);
@@ -123,56 +124,114 @@
}
}
}
- response.getOutputStream().write(results.getByteArray());
+ response.getOutputStream().write(
+ InputStreamConsumer.readToByteArray(results.getResponse()));
}
}
/**
* Fetch the content for a request
*/
- private RemoteContent fetchContent(URL signedUrl, HttpServletRequest request,
- ProcessingOptions procOptions) throws ServletException {
+ @SuppressWarnings("unchecked")
+ private RemoteContent fetchContent(URL signedUrl,
+ HttpServletRequest request,
+ ProcessingOptions procOptions)
+ throws ServletException {
+ String encoding = request.getCharacterEncoding();
+ if (encoding == null) {
+ encoding = "UTF-8";
+ }
try {
if ("POST".equals(request.getMethod())) {
- String data = request.getParameter("postData");
- return fetcher.fetchByPost(signedUrl,
- URLDecoder.decode(data, request.getCharacterEncoding()).getBytes(),
- procOptions);
+ String method = getParameter(request, "httpMethod", "GET");
+ String postData = URLDecoder.decode(
+ getParameter(request, "postData", ""), encoding);
+
+ Map<String, List<String>> headers;
+ String headerData = request.getParameter("headers");
+ if (headerData == null) {
+ headers = Collections.emptyMap();
+ } else {
+ if (headerData.length() == 0) {
+ headers = Collections.emptyMap();
+ } else {
+ // We actually only accept single key value mappings now.
+ headers = new HashMap<String, List<String>>();
+ String[] headerList = headerData.split("&");
+ for (String header : headerList) {
+ String[] parts = header.split("=");
+ if (parts.length != 2) {
+ // Malformed headers
+ return RemoteContent.ERROR;
+ }
+ headers.put(URLDecoder.decode(parts[0], encoding),
+ Arrays.asList(URLDecoder.decode(parts[1], encoding)));
+ }
+ }
+ }
+
+ removeUnsafeHeaders(headers);
+
+ RemoteContentRequest req = new RemoteContentRequest(
+ signedUrl.toURI(), headers, postData.getBytes());
+ if ("POST".equals(method)) {
+ return fetcher.fetchByPost(req, procOptions);
+ } else {
+ return fetcher.fetch(req, procOptions);
+ }
} else {
- return fetcher.fetch(signedUrl, new ProcessingOptions());
+ Map<String, List<String>> headers = new HashMap<String, List<String>>();
+ Enumeration<String> headerNames = request.getHeaderNames();
+ while (headerNames.hasMoreElements()) {
+ String header = headerNames.nextElement();
+ headers.put(header, Collections.list(request.getHeaders(header)));
+ }
+ removeUnsafeHeaders(headers);
+ RemoteContentRequest req
+ = new RemoteContentRequest(signedUrl.toURI(), headers);
+ return fetcher.fetch(req, procOptions);
}
- } catch (UnsupportedEncodingException uee) {
- throw new ServletException(uee);
+ } catch (UnsupportedEncodingException e) {
+ throw new ServletException(e);
+ } catch (URISyntaxException e) {
+ throw new ServletException(e);
}
}
/**
- * Gets the url= parameter from the request and applies some basic sanity
- * checking.
+ * Removes unsafe headers from the header set.
+ * @param headers
+ */
+ private void removeUnsafeHeaders(Map<String, List<String>> headers) {
+ // Host must be removed.
+ final String[] badHeaders = new String[] {
+ // No legitimate reason to over ride these.
+ // TODO: We probably need to test variations as well.
+ "Host", "Accept-Encoding", "Accept"
+ };
+ for (String bad : badHeaders) {
+ headers.remove(bad);
+ }
+ }
+
+ /**
+ * Validates that the given url is valid for this reques.t
*
- * @param request The HTTP request from the browser.
+ * @param url
* @return A URL object of the URL
* @throws ServletException if the URL fails security checks or is malformed.
*/
- private URL extractAndValidateUrl(HttpServletRequest request)
- throws ServletException {
- String url = request.getParameter("url");
+ private URL validateUrl(String url) throws ServletException {
if (url == null) {
- throw new ServletException("Missing url parameter");
+ throw new ServletException("url parameter is missing.");
}
-
try {
- URI origin = new URI(request.getParameter("url"));
+ URI origin = new URI(url);
if (origin.getScheme() == null) {
- // No scheme, assume it was double-encoded.
- origin = new URI(URLDecoder.decode(request.getParameter("url"),
- request.getCharacterEncoding()));
- if (origin.getScheme() == null) {
- throw new ServletException("Invalid URL " + origin.toString());
- }
+ throw new ServletException("Invalid URL " + origin.toString());
}
if (!origin.getScheme().equals("http")) {
- throw new ServletException("Unsupported protocol: " + origin.getScheme());
+ throw new ServletException("Unsupported scheme: " + origin.getScheme());
}
if (origin.getPath() == null || origin.getPath().length() == 0) {
// Forcibly set the path to "/" if it is empty
@@ -187,8 +246,6 @@
throw new ServletException("Malformed URL " + use.getMessage());
} catch (MalformedURLException mfe) {
throw new ServletException("Malformed URL " + mfe.getMessage());
- } catch (UnsupportedEncodingException uee) {
- throw new ServletException("Unsupported encoding " + uee.getMessage());
}
}
@@ -202,10 +259,7 @@
if (signer == null) {
return null;
}
- String token = request.getParameter("st");
- if (token == null) {
- token = "";
- }
+ String token = getParameter(request, "st", "");
return signer.createToken(token);
} catch (GadgetException ge) {
throw new ServletException(ge);
@@ -213,34 +267,43 @@
}
/**
- * Sets HTTP headers that instruct the browser to cache for 2 hours.
+ * Sets HTTP caching headers
*
* @param response The HTTP response
*/
private void setCachingHeaders(HttpServletResponse response) {
- // TODO: figure out why we're not using the same amount of time for these
- // headers.
- response.setHeader("Cache-Control", "public,max-age=" + ONE_HOUR_IN_SECS);
- response.setDateHeader("Expires", System.currentTimeMillis()
- + TWO_HOURS_IN_MS);
+ // TODO: Re-implement caching behavior if appropriate.
+ response.setHeader("Cache-Control", "private; max-age=0");
+ response.setDateHeader("Expires", System.currentTimeMillis() - 30);
}
/**
* Sign a URL with a GadgetToken if needed
- * @return
+ * @return The signed url.
*/
+ @SuppressWarnings("unchecked")
private URL signUrl(URL originalUrl, GadgetToken token,
HttpServletRequest request) throws ServletException {
try {
- if (token == null ||
- !"signed".equals(request.getParameter("authz"))) {
+ if (token == null || !"signed".equals(request.getParameter("authz"))) {
return originalUrl;
}
- return token.signUrl(originalUrl, "GET", // TODO: request.getMethod()
- request.getParameterMap());
+ String method = getParameter(request, "httpMethod", "GET");
+ return token.signUrl(originalUrl, method, request.getParameterMap());
} catch (GadgetException ge) {
throw new ServletException(ge);
}
}
+ /**
+ * Extracts the first parameter from the parameter map with the given name.
+ * @param request
+ * @param name
+ * @return The parameter, if found, or defaultValue
+ */
+ private static String getParameter(HttpServletRequest request,
+ String name, String defaultValue) {
+ String ret = request.getParameter(name);
+ return ret == null ? defaultValue : ret;
+ }
}
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcServlet.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcServlet.java?rev=620700&r1=620699&r2=620700&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcServlet.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcServlet.java Mon Feb 11 20:17:18 2008
@@ -19,9 +19,10 @@
package org.apache.shindig.gadgets.http;
+import org.apache.shindig.util.InputStreamConsumer;
+
import org.json.JSONObject;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.logging.Level;
@@ -58,19 +59,12 @@
return;
}
- ServletInputStream reader = request.getInputStream();
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- byte[] buf = new byte[1024 * 8];
- int read = 0;
-
- while ((read = reader.read(buf, 0, buf.length)) > 0) {
- os.write(buf, 0, read);
- if (os.size() > length) {
- // Bad request, we're leaving now.
- logger.info("Wrong size. Length: " + length + " real: " + os.size());
- response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
- return;
- }
+ ServletInputStream is = request.getInputStream();
+ byte[] body = InputStreamConsumer.readToByteArray(is, length);
+ if (body.length != length) {
+ logger.info("Wrong size. Length: " + length + " real: " + body.length);
+ response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+ return;
}
try {
@@ -78,7 +72,7 @@
if (encoding == null) {
encoding = "UTF-8";
}
- String postBody = new String(os.toByteArray(), encoding);
+ String postBody = new String(body, encoding);
JsonRpcRequest req = new JsonRpcRequest(postBody);
JSONObject out = req.process(state);
response.setStatus(HttpServletResponse.SC_OK);
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/InputStreamConsumer.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/InputStreamConsumer.java?rev=620700&r1=620699&r2=620700&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/InputStreamConsumer.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/InputStreamConsumer.java Mon Feb 11 20:17:18 2008
@@ -21,47 +21,88 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
/**
- * Used to consume an entire input stream. Don't use this for network
- * streams or any other stream that doesn't have a known length. This is
- * intended for reading resources from jars and the local file system only.
+ * Used to consume entire input streams and transform them into data buffers.
+ * These are all blocking routines and should never be called from a thread
+ * that will cause deadlock.
*/
public class InputStreamConsumer {
/**
- * Loads content and returns it as a raw byte array.
+ * Consumes the entire contents of the stream. Only safe to use if you are
+ * sure that you're consuming a fixed-size buffer.
* @param is
* @return The contents of the stream.
* @throws IOException on stream reading error.
*/
public static byte[] readToByteArray(InputStream is) throws IOException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- byte[] buf = new byte[8192];
- int read = 0;
+ return readToByteArray(is, Integer.MAX_VALUE);
+ }
- while ((read = is.read(buf)) > 0) {
- baos.write(buf, 0, read);
+ /**
+ * Reads at most maxBytes bytes from the stream.
+ * @param is
+ * @param maxBytes
+ * @return The bytes that were read
+ * @throws IOException
+ */
+ public static byte[] readToByteArray(InputStream is, int maxBytes)
+ throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ byte[] chunk = new byte[8192];
+ int chunkSize;
+ while (out.size() < maxBytes && (chunkSize = is.read(chunk)) != -1) {
+ out.write(chunk, 0, chunkSize);
}
-
- return baos.toByteArray();
+ return out.toByteArray();
}
/**
* Loads content from the given input stream as a UTF-8-encoded string.
+ * Use only when you're sure of the finite length of the input stream.
+ * If you're not sure, use {@code readToString(InputStream, maxBytes)}.
*
* @param is
* @return The contents of the stream.
* @throws IOException on stream reading error.
*/
public static String readToString(InputStream is) throws IOException {
- byte[] bytes = readToByteArray(is);
+ return readToString(is, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Loads content from the given input stream as a UTF-8-encoded string.
+ *
+ * @param is
+ * @return The contents of the stream.
+ * @throws IOException on stream reading error.
+ */
+ public static String readToString(InputStream is, int maxBytes)
+ throws IOException {
+ byte[] bytes = readToByteArray(is, maxBytes);
try {
return new String(bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
// UTF-8 is required by the Java spec.
throw new RuntimeException("UTF-8 not supported!", e);
}
+ }
+
+ /**
+ * Consumes all of is and sends it to os. This is not the same as
+ * Piped Input / Output streams because it reads the entire input first.
+ * This means that you won't get deadlock, but it also means that this is
+ * not necessarily suitable for normal piping tasks. Use a piped stream for
+ * that sort of work.
+ *
+ * @param is
+ * @param os
+ * @throws IOException
+ */
+ public static void pipe(InputStream is, OutputStream os) throws IOException {
+ os.write(readToByteArray(is));
}
}
Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java?rev=620700&r1=620699&r2=620700&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java Mon Feb 11 20:17:18 2008
@@ -72,8 +72,10 @@
RemoteContent results = new RemoteContent(200, DATETIME_XML.getBytes(), null);
ProcessingOptions options = new ProcessingOptions();
+ RemoteContentRequest req = new RemoteContentRequest(DATETIME_URI);
+
expect(specCache.get(eq(DATETIME_URI_STRING))).andReturn(null);
- expect(fetcher.fetch(eq(DATETIME_URI.toURL()),
+ expect(fetcher.fetch(eq(req),
eq(options))).andReturn(results);
specCache.put(eq(DATETIME_URI_STRING), isA(GadgetSpec.class));
replay();
@@ -99,8 +101,10 @@
RemoteContent results = new RemoteContent(200, DATETIME_XML.getBytes(), null);
ProcessingOptions options = new ProcessingOptions();
+ RemoteContentRequest req = new RemoteContentRequest(DATETIME_URI);
+
expect(specCache.get(eq(DATETIME_URI_STRING))).andReturn(null);
- expect(fetcher.fetch(eq(DATETIME_URI.toURL()),
+ expect(fetcher.fetch(eq(req),
eq(options))).andReturn(results);
specCache.put(eq(DATETIME_URI_STRING), isA(GadgetSpec.class));
replay();
Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/RemoteContentTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/RemoteContentTest.java?rev=620700&r1=620699&r2=620700&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/RemoteContentTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/RemoteContentTest.java Mon Feb 11 20:17:18 2008
@@ -20,6 +20,9 @@
import junit.framework.TestCase;
+import org.apache.shindig.util.InputStreamConsumer;
+
+import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -78,12 +81,13 @@
assertEquals("\u4F60\u597D", content.getResponseAsString());
}
- public void testPreserveBinaryData() {
+ public void testPreserveBinaryData() throws Exception {
byte[] data = new byte[] {
(byte)0x00, (byte)0xDE, (byte)0xEA, (byte)0xDB, (byte)0xEE, (byte)0xF0
};
addHeader("Content-Type", "application/octet-stream");
RemoteContent content = new RemoteContent(200, data, headers);
- assertEquals(data, content.getByteArray());
+ byte[] out = InputStreamConsumer.readToByteArray(content.getResponse());
+ assertTrue(Arrays.equals(data, out));
}
}