On Thu, Nov 17, 2011 at 08:48:16PM -0800, steve labar wrote:
> I'm trying to create a http/https proxy server leveraging httpclient and
> httpcore. I can get the http portion of the proxy to work just fine.
> However, when I try to implement the ssl section I have major trouble. It
> looks like its failing within HTTPService.handleRequest(). I expect its due
> to ssl but hard to really tell what i'm doing wrong. Here is what i'm
> currently doing:
>
> Setup socket to listen on 8080
>
> serversocket = new ServerSocket(port);
> this.params = new SyncBasicHttpParams();
> this.params.setBooleanParameter(ClientPNames.HANDLE_REDIRECTS,
> true).setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 50000)
>
> .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE,
> 8 * 1024)
> .setBooleanParameter(
> CoreConnectionPNames.STALE_CONNECTION_CHECK,
> false)
> .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY,
> true)
> .setParameter(CoreProtocolPNames.ORIGIN_SERVER,
> "HttpComponents/1.1");
> // Set up the HTTP protocol processor
> HttpProcessor httpproc = new ImmutableHttpProcessor(
> new HttpResponseInterceptor[] { new ResponseDate(),
> new ResponseServer(), new ResponseContent(),
> new ResponseConnControl() });
>
> // Set up request handlers
> HttpRequestHandlerRegistry reqistry = new
> HttpRequestHandlerRegistry();
> reqistry.register("*", new DefaultHttpRequestHandler());
> // Set up the HTTP service
> this.httpService = new HttpService(httpproc,
> new DefaultConnectionReuseStrategy(),
> new DefaultHttpResponseFactory(), reqistry,
> this.params);
>
> Then on every incoming accept() on that socket i send that data to a worker
> thread that calls httpservice.handlerequest() here is that code snippet:
>
> public void run() {
> System.out.println("New connection thread");
> HttpContext context = new BasicHttpContext(null);
>
> try {
> while (!Thread.interrupted() && this.conn.isOpen()) {
> //HttpRequest req = this.conn.receiveRequestHeader();
> this.httpservice.handleRequest(this.conn, context);
> }
> } catch (ConnectionClosedException ex) {
> System.err.println("Client closed connection");
> } catch (IOException ex) {
> System.err.println("I/O error: " + ex.getMessage());
> ex.printStackTrace();
> } catch (HttpException ex) {
> System.err.println("Unrecoverable HTTP protocol violation: "
> + ex.getMessage());
> } finally {
> try {
> this.conn.shutdown();
> } catch (IOException ignore) {
> }
> }
>
> Then each request gets handled by my DefaultHttpRequestHandler which
> extends HttpRequestHandler here is the method called anytime
> httpService.handleRequest() is called. You will notice I peek at the
> http(s) method if not a CONNECT. Its super simple make request to server
> and set the response object and let the method handle sending back to
> browser on socket listening. The problem comes up if i hit as an example
> https://google.com. When i debug it comes in gets set to handle() by the
> httpservice.handlerequest(). As soon as it reaches the handle method I peek
> and see its a Connect www.google.com:443. So, i make request with
> httpclient right here and get a 200 response so i know my proxy server and
> the server(google) can accept ssl so at this point i set the response to be
> HTTP/1.0 200 Connection established\r\nProxy-agent: proxy client\r\n\r\n"
> just as RFC says you do to tell browser we can start talking in ssl. But as
> soon as i set this as response and it leaves the method it shuts connection
> down and Firefox says:
>
> Secure Connection Failed
>
> An error occurred during a connection to www.google.com.
>
> SSL received a record that exceeded the maximum permissible length.
>
> (Error code: ssl_error_rx_record_too_long)
>
> I have read online and it says that this happens if you try to send ssl to
> port 80 but i'm pretty sure that is not problem. Any ideas?
>
Hi Steve
SSL tunneling via an HTTP proxy simply does not work like that. Upon receipt of
a CONNECT request, the proxy is expected to do the following:
(1) optionally authenticate the user and respond with 407 status if user
credentials are not valid
(2) open a TCP connection to the origin server, but send NO data to the origin
(3) if connection is successful, respond to the client with 200 status
(4) at this point the tunnel can be considered established and operational.
From hence on the proxy is expected to read whatever data comes from the client
and relay it to the origin and the other way around. The content passed between
the client and the origin is completely opaque to the proxy.
For proper specification of the protocol please see
http://www.ietf.org/rfc/rfc2817.txt
The trouble is that connection tunneling is not easy to implement with the
classic (blocking) I/O. One would need to employ two treads to be able to read
and write in both directions simultaneously or use one thread and constantly
switch between read and write mode which may be not very efficient. Usually NIO
tends to be a better model for proxies.
Oleg
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]