You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by vs...@apache.org on 2009/04/04 15:44:52 UTC
svn commit: r761942 -
/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/BasicHttpFetcher.java
Author: vsiveton
Date: Sat Apr 4 13:44:51 2009
New Revision: 761942
URL: http://svn.apache.org/viewvc?rev=761942&view=rev
Log:
SHINDIG-765: BasiHttpFetcher does not set a read timeout and connection timeout is hardcoded to 5 seconds(not configurable)
Submitted by: chirag shah
o patch applied
Modified:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/BasicHttpFetcher.java
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/BasicHttpFetcher.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/BasicHttpFetcher.java?rev=761942&r1=761941&r2=761942&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/BasicHttpFetcher.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/BasicHttpFetcher.java Sat Apr 4 13:44:51 2009
@@ -17,27 +17,36 @@
*/
package org.apache.shindig.gadgets.http;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang.ArrayUtils;
-import org.apache.commons.lang.StringUtils;
-
-import com.google.common.collect.Maps;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.google.inject.Singleton;
-
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.net.HttpURLConnection;
import java.net.Proxy;
-import java.net.URL;
+import java.net.Socket;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
+import org.apache.commons.httpclient.Header;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.HttpStatus;
+import org.apache.commons.httpclient.methods.DeleteMethod;
+import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.methods.PutMethod;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.lang.StringUtils;
+
+import com.google.common.collect.Maps;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
/**
* A very primitive HTTP fetcher implementation. Not recommended for production deployments until
* the following issues are addressed:
@@ -45,10 +54,6 @@
* 1. This class potentially allows access to resources behind an organization's firewall.
* 2. This class does not handle most advanced HTTP functionality correctly (SSL, gzip, etc.)
* 3. This class does not enforce any limits on what is fetched from remote hosts.
- *
- * It is highly likely that this will be replaced by an apache commons HttpClient in the future.
- *
- * TODO: Replace with commons HttpClient.
*/
@Singleton
public class BasicHttpFetcher implements HttpFetcher {
@@ -86,94 +91,133 @@
}
/**
- * Initializes the connection.
- *
- * @param request
- * @return The opened connection
- * @throws IOException
+ * @param httpMethod
+ * @param responseCode
+ * @return A HttpResponse object made by consuming the response of the
+ * given HttpMethod.
+ * @throws java.io.IOException
*/
- private HttpURLConnection getConnection(HttpRequest request) throws IOException {
- URL url = new URL(request.getUri().toString());
- HttpURLConnection fetcher = (HttpURLConnection) ( proxyProvider == null ?
- url.openConnection() : url.openConnection(proxyProvider.get()));
- fetcher.setConnectTimeout(CONNECT_TIMEOUT_MS);
- fetcher.setRequestProperty("Accept-Encoding", "gzip, deflate");
- fetcher.setInstanceFollowRedirects(request.getFollowRedirects());
- for (Map.Entry<String, List<String>> entry : request.getHeaders().entrySet()) {
- fetcher.setRequestProperty(entry.getKey(), StringUtils.join(entry.getValue(), ','));
+ private HttpResponse makeResponse(HttpMethod httpMethod, int responseCode) throws IOException {
+ Map<String, String> headers = Maps.newHashMap();
+
+ if (httpMethod.getResponseHeaders() != null) {
+ for (Header h : httpMethod.getResponseHeaders()) {
+ headers.put(h.getName(), h.getValue());
+ }
}
- fetcher.setDefaultUseCaches(!request.getIgnoreCache());
- return fetcher;
- }
- /**
- * @param fetcher
- * @return A HttpResponse object made by consuming the response of the
- * given HttpURLConnection.
- */
- private HttpResponse makeResponse(HttpURLConnection fetcher) throws IOException {
- Map<String, List<String>> headers = Maps.newHashMap(fetcher.getHeaderFields());
// The first header is always null here to provide the response body.
headers.remove(null);
- int responseCode = fetcher.getResponseCode();
+
// Find the response stream - the error stream may be valid in cases
// where the input stream is not.
- InputStream baseIs = null;
+ InputStream responseBodyStream = null;
try {
- baseIs = fetcher.getInputStream();
+ responseBodyStream = httpMethod.getResponseBodyAsStream();
} catch (IOException e) {
// normal for 401, 403 and 404 responses, for example...
}
- if (baseIs == null) {
- // Try for an error input stream
- baseIs = fetcher.getErrorStream();
- }
- if (baseIs == null) {
+
+ if (responseBodyStream == null) {
// Fall back to zero length response.
- baseIs = new ByteArrayInputStream(ArrayUtils.EMPTY_BYTE_ARRAY);
+ responseBodyStream = new ByteArrayInputStream(ArrayUtils.EMPTY_BYTE_ARRAY);
}
- String encoding = fetcher.getContentEncoding();
+ String encoding = headers.get("Content-Type");
+
// Create the appropriate stream wrapper based on the encoding type.
- InputStream is = null;
+ InputStream is = responseBodyStream;
if (encoding == null) {
- is = baseIs;
+ is = responseBodyStream;
} else if (encoding.equalsIgnoreCase("gzip")) {
- is = new GZIPInputStream(baseIs);
+ is = new GZIPInputStream(responseBodyStream);
} else if (encoding.equalsIgnoreCase("deflate")) {
Inflater inflater = new Inflater(true);
- is = new InflaterInputStream(baseIs, inflater);
+ is = new InflaterInputStream(responseBodyStream, inflater);
}
byte[] body = IOUtils.toByteArray(is);
return new HttpResponseBuilder()
.setHttpStatusCode(responseCode)
.setResponse(body)
- .addAllHeaders(headers)
+ .addHeaders(headers)
.create();
}
/** {@inheritDoc} */
public HttpResponse fetch(HttpRequest request) {
- try {
- HttpURLConnection fetcher = getConnection(request);
- fetcher.setRequestMethod(request.getMethod());
- if (!"GET".equals(request.getMethod())) {
- fetcher.setUseCaches(false);
- }
- fetcher.setRequestProperty("Content-Length",
- String.valueOf(request.getPostBodyLength()));
+ HttpClient httpClient = new HttpClient();
+ HttpMethod httpMethod;
+ String methodType = request.getMethod();
+ String requestUri = request.getUri().toString();
+
+ if (proxyProvider != null) {
+ Socket proxySocket = new Socket(proxyProvider.get());
+ httpClient.getHostConfiguration().setLocalAddress(proxySocket.getLocalAddress());
+ }
+
+ if ("POST".equals(methodType) || "PUT".equals(methodType)) {
+ EntityEnclosingMethod enclosingMethod = ("POST".equals(methodType))
+ ? new PostMethod(requestUri)
+ : new PutMethod(requestUri);
+
if (request.getPostBodyLength() > 0) {
- fetcher.setDoOutput(true);
- IOUtils.copy(request.getPostBody(), fetcher.getOutputStream());
+ enclosingMethod.setRequestEntity(new InputStreamRequestEntity(request.getPostBody()));
}
- return makeResponse(fetcher);
+
+ httpMethod = enclosingMethod;
+ } else if ("DELETE".equals(methodType)) {
+ httpMethod = new DeleteMethod(requestUri);
+ } else {
+ httpMethod = new GetMethod(requestUri);
+ }
+
+ httpMethod.setFollowRedirects(false);
+ httpMethod.getParams().setSoTimeout(CONNECT_TIMEOUT_MS);
+ httpMethod.setRequestHeader("Content-Length", String.valueOf(request.getPostBodyLength()));
+ httpMethod.setRequestHeader("Accept-Encoding", "gzip, deflate");
+
+ for (Map.Entry<String, List<String>> entry : request.getHeaders().entrySet()) {
+ httpMethod.setRequestHeader(entry.getKey(), StringUtils.join(entry.getValue(), ','));
+ }
+
+ try {
+
+ int statusCode = httpClient.executeMethod(httpMethod);
+
+ // Handle redirects manually
+ if (request.getFollowRedirects() &&
+ ((statusCode == HttpStatus.SC_MOVED_TEMPORARILY) ||
+ (statusCode == HttpStatus.SC_MOVED_PERMANENTLY) ||
+ (statusCode == HttpStatus.SC_SEE_OTHER) ||
+ (statusCode == HttpStatus.SC_TEMPORARY_REDIRECT))) {
+
+ Header header = httpMethod.getResponseHeader("location");
+ if (header != null) {
+ String redirectUri = header.getValue();
+
+ if ((redirectUri == null) || (redirectUri.equals(""))) {
+ redirectUri = "/";
+ }
+ httpMethod.releaseConnection();
+ httpMethod = new GetMethod(redirectUri);
+
+ statusCode = httpClient.executeMethod(httpMethod);
+ }
+ }
+
+ return makeResponse(httpMethod, statusCode);
+
} catch (IOException e) {
if (e instanceof java.net.SocketTimeoutException ||
e instanceof java.net.SocketException) {
return HttpResponse.timeout();
}
+
return HttpResponse.error();
+
+ } finally {
+ httpMethod.releaseConnection();
}
}
}