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?
public void handle(HttpRequest request, HttpResponse response,
HttpContext context) throws HttpException, IOException {
System.out.println("Request in handle: " + request);
RequestLine reqLine = request.getRequestLine();
if(reqLine.getMethod().equalsIgnoreCase("CONNECT"))
{
String uri = reqLine.getUri();
String[] uriParts = uri.split(":");
String url ="https://"+ uriParts[0];
request = new BasicHttpRequest("GET",url);
HttpResponse connectRes = getResponse(request);
StatusLine responseLine = connectRes.getStatusLine();
if(responseLine.getStatusCode() == 200)
{
response.setEntity(new BufferedHttpEntity(new
StringEntity("HTTP/1.0 200 Connection established\r\nProxy-agent: proxy
client\r\n\r\n")));
}
response.setEntity(new BufferedHttpEntity(new
StringEntity("HTTP/1.0 200 Connection established\r\nProxy-agent: proxy
client\r\n\r\n")));
}
else
{
try {
HttpResponse clientResponse = null;
HttpEntity entity = null;
clientResponse = httpClient.execute(new
RequestWrapper(request));
entity = clientResponse.getEntity();
if (entity != null) {
response.setEntity(new BufferedHttpEntity(entity));
}
} catch (Exception e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
}
}