You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2011/10/06 22:16:59 UTC

svn commit: r1179817 - in /httpcomponents/httpclient/trunk/httpclient/src: examples/org/apache/http/examples/client/ProxyTunnelDemo.java main/java/org/apache/http/impl/client/ProxyClient.java

Author: olegk
Date: Thu Oct  6 20:16:59 2011
New Revision: 1179817

URL: http://svn.apache.org/viewvc?rev=1179817&view=rev
Log:
HTTPCLIENT-1132: ProxyClient implementation

Added:
    httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ProxyTunnelDemo.java   (with props)
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/ProxyClient.java   (with props)

Added: httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ProxyTunnelDemo.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ProxyTunnelDemo.java?rev=1179817&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ProxyTunnelDemo.java (added)
+++ httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ProxyTunnelDemo.java Thu Oct  6 20:16:59 2011
@@ -0,0 +1,74 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.examples.client;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.net.Socket;
+
+import org.apache.http.HttpHost;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.impl.client.ProxyClient;
+import org.apache.http.protocol.HTTP;
+
+/**
+ * Example code for using {@link ProxyClient} in order to establish a tunnel through an HTTP proxy.
+ */
+public class ProxyTunnelDemo {
+
+    public final static void main(String[] args) throws Exception {
+
+        ProxyClient proxyClient = new ProxyClient();
+        HttpHost target = new HttpHost("www.yahoo.com", 80);
+        HttpHost proxy = new HttpHost("localhost", 8888);
+        UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("user", "pwd");
+        Socket socket = proxyClient.tunnel(proxy, target, credentials);
+        try {
+            Writer out = new OutputStreamWriter(socket.getOutputStream(),
+                    HTTP.DEFAULT_CONTENT_CHARSET);
+            out.write("GET / HTTP/1.1\r\n");
+            out.write("Host: " + target.toHostString() + "\r\n");
+            out.write("Agent: whatever\r\n");
+            out.write("Connection: close\r\n");
+            out.write("\r\n");
+            out.flush();
+            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(),
+                    HTTP.DEFAULT_CONTENT_CHARSET));
+            String line = null;
+            while ((line = in.readLine()) != null) {
+                System.out.println(line);
+            }
+        } finally {
+            socket.close();
+        }
+    }
+
+}
+

Propchange: httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ProxyTunnelDemo.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ProxyTunnelDemo.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ProxyTunnelDemo.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/ProxyClient.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/ProxyClient.java?rev=1179817&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/ProxyClient.java (added)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/ProxyClient.java Thu Oct  6 20:16:59 2011
@@ -0,0 +1,245 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.client;
+
+import java.io.IOException;
+import java.net.Socket;
+
+import javax.net.ssl.SSLSession;
+
+import org.apache.http.ConnectionReuseStrategy;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.HttpResponse;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.auth.AuthSchemeRegistry;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.AuthState;
+import org.apache.http.auth.Credentials;
+import org.apache.http.client.params.AuthPolicy;
+import org.apache.http.client.params.HttpClientParams;
+import org.apache.http.client.protocol.ClientContext;
+import org.apache.http.client.protocol.RequestClientConnControl;
+import org.apache.http.client.protocol.RequestProxyAuthentication;
+import org.apache.http.conn.HttpRoutedConnection;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.entity.BufferedHttpEntity;
+import org.apache.http.impl.DefaultConnectionReuseStrategy;
+import org.apache.http.impl.DefaultHttpClientConnection;
+import org.apache.http.impl.auth.BasicSchemeFactory;
+import org.apache.http.impl.auth.DigestSchemeFactory;
+import org.apache.http.impl.auth.NTLMSchemeFactory;
+import org.apache.http.impl.auth.NegotiateSchemeFactory;
+import org.apache.http.message.BasicHttpRequest;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.HttpProtocolParams;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.ExecutionContext;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpProcessor;
+import org.apache.http.protocol.HttpRequestExecutor;
+import org.apache.http.protocol.ImmutableHttpProcessor;
+import org.apache.http.protocol.RequestContent;
+import org.apache.http.protocol.RequestTargetHost;
+import org.apache.http.protocol.RequestUserAgent;
+import org.apache.http.util.EntityUtils;
+
+public class ProxyClient {
+
+    private final HttpProcessor httpProcessor;
+    private final HttpRequestExecutor requestExec;
+    private final ProxyAuthenticationStrategy proxyAuthStrategy;
+    private final HttpAuthenticator authenticator;
+    private final AuthState proxyAuthState;
+    private final AuthSchemeRegistry authSchemeRegistry;
+    private final ConnectionReuseStrategy reuseStrategy;
+    private final HttpParams params;
+
+    public ProxyClient(final HttpParams params) {
+        super();
+        if (params == null) {
+            throw new IllegalArgumentException("HTTP parameters may not be null");
+        }
+        this.httpProcessor = new ImmutableHttpProcessor(new HttpRequestInterceptor[] {
+                new RequestContent(),
+                new RequestTargetHost(),
+                new RequestClientConnControl(),
+                new RequestUserAgent(),
+                new RequestProxyAuthentication()
+        } );
+        this.requestExec = new HttpRequestExecutor();
+        this.proxyAuthStrategy = new ProxyAuthenticationStrategy();
+        this.authenticator = new HttpAuthenticator();
+        this.proxyAuthState = new AuthState();
+        this.authSchemeRegistry = new AuthSchemeRegistry();
+        this.authSchemeRegistry.register(AuthPolicy.BASIC, new BasicSchemeFactory());
+        this.authSchemeRegistry.register(AuthPolicy.DIGEST, new DigestSchemeFactory());
+        this.authSchemeRegistry.register(AuthPolicy.NTLM, new NTLMSchemeFactory());
+        this.authSchemeRegistry.register(AuthPolicy.SPNEGO, new NegotiateSchemeFactory());
+        this.reuseStrategy = new DefaultConnectionReuseStrategy();
+        this.params = params;
+    }
+
+    public ProxyClient() {
+        this(new BasicHttpParams());
+    }
+
+    public HttpParams getParams() {
+        return this.params;
+    }
+
+    public AuthSchemeRegistry getAuthSchemeRegistry() {
+        return this.authSchemeRegistry;
+    }
+
+    public Socket tunnel(
+            final HttpHost proxy,
+            final HttpHost target,
+            final Credentials credentials) throws IOException, HttpException {
+        ProxyConnection conn = new ProxyConnection(new HttpRoute(proxy));
+        HttpContext context = new BasicHttpContext();
+        HttpResponse response = null;
+
+        for (;;) {
+            if (!conn.isOpen()) {
+                Socket socket = new Socket(proxy.getHostName(), proxy.getPort());
+                conn.bind(socket, this.params);
+            }
+            String host = target.getHostName();
+            int port = target.getPort();
+            if (port < 0) {
+                port = 80;
+            }
+
+            StringBuilder buffer = new StringBuilder(host.length() + 6);
+            buffer.append(host);
+            buffer.append(':');
+            buffer.append(Integer.toString(port));
+
+            String authority = buffer.toString();
+            ProtocolVersion ver = HttpProtocolParams.getVersion(this.params);
+            HttpRequest connect = new BasicHttpRequest("CONNECT", authority, ver);
+            connect.setParams(this.params);
+
+            BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
+            credsProvider.setCredentials(new AuthScope(proxy), credentials);
+
+            // Populate the execution context
+            context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, target);
+            context.setAttribute(ExecutionContext.HTTP_PROXY_HOST, proxy);
+            context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
+            context.setAttribute(ExecutionContext.HTTP_REQUEST, connect);
+            context.setAttribute(ClientContext.PROXY_AUTH_STATE, this.proxyAuthState);
+            context.setAttribute(ClientContext.CREDS_PROVIDER, credsProvider);
+            context.setAttribute(ClientContext.AUTHSCHEME_REGISTRY, this.authSchemeRegistry);
+
+            this.requestExec.preProcess(connect, this.httpProcessor, context);
+
+            response = this.requestExec.execute(connect, conn, context);
+
+            response.setParams(this.params);
+            this.requestExec.postProcess(response, this.httpProcessor, context);
+
+            int status = response.getStatusLine().getStatusCode();
+            if (status < 200) {
+                throw new HttpException("Unexpected response to CONNECT request: " +
+                        response.getStatusLine());
+            }
+
+            if (HttpClientParams.isAuthenticating(this.params)) {
+                if (this.authenticator.isAuthenticationRequested(response,
+                        this.proxyAuthStrategy, this.proxyAuthState, context)) {
+                    if (this.authenticator.authenticate(proxy, response,
+                            this.proxyAuthStrategy, this.proxyAuthState, context)) {
+                        // Retry request
+                        if (this.reuseStrategy.keepAlive(response, context)) {
+                            // Consume response content
+                            HttpEntity entity = response.getEntity();
+                            EntityUtils.consume(entity);
+                        } else {
+                            conn.close();
+                        }
+                    } else {
+                        break;
+                    }
+                } else {
+                    break;
+                }
+            }
+        }
+
+        int status = response.getStatusLine().getStatusCode();
+
+        if (status > 299) {
+
+            // Buffer response content
+            HttpEntity entity = response.getEntity();
+            if (entity != null) {
+                response.setEntity(new BufferedHttpEntity(entity));
+            }
+
+            conn.close();
+            throw new TunnelRefusedException("CONNECT refused by proxy: " +
+                    response.getStatusLine(), response);
+        }
+        return conn.getSocket();
+    }
+
+    static class ProxyConnection extends DefaultHttpClientConnection implements HttpRoutedConnection {
+
+        private final HttpRoute route;
+
+        ProxyConnection(final HttpRoute route) {
+            super();
+            this.route = route;
+        }
+
+        public HttpRoute getRoute() {
+            return this.route;
+        }
+
+        public boolean isSecure() {
+            return false;
+        }
+
+        public SSLSession getSSLSession() {
+            return null;
+        }
+
+        @Override
+        public Socket getSocket() {
+            return super.getSocket();
+        }
+
+    }
+
+}

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/ProxyClient.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/ProxyClient.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/ProxyClient.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain