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();
     }
   }
 }