Return-Path: X-Original-To: apmail-hc-commits-archive@www.apache.org Delivered-To: apmail-hc-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 60AFD7A19 for ; Thu, 6 Oct 2011 20:17:22 +0000 (UTC) Received: (qmail 13531 invoked by uid 500); 6 Oct 2011 20:17:22 -0000 Delivered-To: apmail-hc-commits-archive@hc.apache.org Received: (qmail 13495 invoked by uid 500); 6 Oct 2011 20:17:22 -0000 Mailing-List: contact commits-help@hc.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "HttpComponents Project" Delivered-To: mailing list commits@hc.apache.org Received: (qmail 13487 invoked by uid 99); 6 Oct 2011 20:17:22 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 06 Oct 2011 20:17:22 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 06 Oct 2011 20:17:20 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 1813D23889DA for ; Thu, 6 Oct 2011 20:17:00 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: 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 Date: Thu, 06 Oct 2011 20:16:59 -0000 To: commits@hc.apache.org From: olegk@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20111006201700.1813D23889DA@eris.apache.org> 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 + * . + * + */ + +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 + * . + * + */ + +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