Of course. This is prototype code. The part for CONNECT is in
"getGoodRequest()"
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package fr.bycode.tools.jntlmproxy;
import fr.bycode.tools.jntlmproxy.ntlm.NTLMSchemeFactory;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.URI;
import java.net.UnknownHostException;
import java.util.HashSet;
import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpException;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolException;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.NTCredentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.RedirectStrategy;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpOptions;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpTrace;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.ProxyClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import org.glassfish.grizzly.http.server.AfterServiceListener;
import org.glassfish.grizzly.http.server.HttpHandler;
import org.glassfish.grizzly.http.server.Request;
import org.glassfish.grizzly.http.server.Response;
/**
*
* @author yblazart
*/
public class ProxyHttpHandler extends HttpHandler {
private DefaultHttpClient httpClient;
private Credentials credentials;
private HttpHost proxyHost;
private static String via = "Via: 1.1 JNTLMProxy\r\n";
/**
* Constant for the headers for an OK response to an HTTP connect
request.
*/
public static final String CONNECT_OK_HEADERS =
"Connection: Keep-Alive\r\n"
+ "Proxy-Connection: Keep-Alive\r\n"
+ via
+ "\r\n";
/**
* Constant for the headers for a proxy error response.
*/
public static final String PROXY_ERROR_HEADERS =
"Connection: close\r\n"
+ "Proxy-Connection: close\r\n"
+ "Pragma: no-cache\r\n"
+ "Cache-Control: no-cache\r\n"
+ via
+ "\r\n";
protected HashSet _DontProxyHeaders = new HashSet();
{
_DontProxyHeaders.add("proxy-connection");
_DontProxyHeaders.add("connection");
_DontProxyHeaders.add("keep-ali(\"ntlm\", new
NTLMSchemeFactory());ve");
_DontProxyHeaders.add("transfer-encoding");
_DontProxyHeaders.add("te");
_DontProxyHeaders.add("trailer");
_DontProxyHeaders.add("proxy-authorization");
_DontProxyHeaders.add("proxy-authenticate");
_DontProxyHeaders.add("upgrade");
}
public ProxyHttpHandler(String externalProxyHost, int
externalProxyPort, String userName, String password) {
super("SimpleProxyHttpHandler");
credentials = new UsernamePasswordCredentials(userName, password);
init(externalProxyHost, externalProxyPort, credentials);
}
public ProxyHttpHandler(String externalProxyHost, int
externalProxyPort, String userName, String password, boolean ntlm, String
workstation, String domain) {
super("NTLMProxyHttpHandler");
credentials = new NTCredentials(userName, password, workstation,
domain);
init(externalProxyHost, externalProxyPort, credentials);
httpClient.getAuthSchemes().register("ntlm", new
NTLMSchemeFactory());
}
public ProxyHttpHandler() {
super("DirectHttpHandler");
init();
}
@Override
public void service(Request request, Response response) throws
Exception {
System.out.println("request = " + request.getMethod() + "," +
request.getRequestURI());
HttpRequestBase requestBase = getGoodRequest(request, response);
if (requestBase == null) {
return;
}
String requestURL = request.getRequestURL().toString();
System.out.println("requestURL = " +
requestBase.getClass().getSimpleName() + " : " + requestURL);
// copy the URL
requestBase.setURI(new URI(requestURL));
//copy the headers
boolean hasContent = false;
for (String headerName : request.getHeaderNames()) {
// Exclude content length
if (!headerName.equals(HttpHeaders.CONTENT_LENGTH) &&
!_DontProxyHeaders.contains(headerName.toLowerCase())) {
requestBase.setHeader(headerName,
request.getHeader(headerName));
System.out.println(" - copy header " + headerName + " =
" + request.getHeader(headerName));
}
if (headerName.equals(HttpHeaders.CONTENT_TYPE)) {
hasContent = true;
}
}
// copy the headers
if (hasContent && requestBase instanceof
HttpEntityEnclosingRequest) {
((HttpEntityEnclosingRequest) requestBase).setEntity(new
InputStreamEntity(request.getInputStream(),
request.getContentLengthLong()));
}
// response
HttpResponse executed = httpClient.execute(requestBase);
Header[] allHeaders = executed.getAllHeaders();
response.setStatus(executed.getStatusLine().getStatusCode());
System.out.println(" --> ret status " +
executed.getStatusLine());
for (Header header : allHeaders) {
if
(!_DontProxyHeaders.contains(header.getName().toLowerCase())) {
response.setHeader(header.getName(), header.getValue());
System.out.println(" --> set header " + header.getName()
+ " = " + header.getValue());
}
}
// force to close the connection at the end
response.setHeader(HttpHeaders.CONNECTION, "close");
//
HttpEntity entity = executed.getEntity();
if (entity != null) {
response.setContentLengthLong(entity.getContentLength());
Header contentType = entity.getContentType();
if (contentType != null && contentType.getValue() != null) {
response.setContentType(contentType.getValue());
}
Header contentEncoding = entity.getContentEncoding();
if (contentEncoding != null && contentEncoding.getValue() !=
null) {
response.setCharacterEncoding(contentEncoding.getValue());
}
BufferedInputStream bufferedInputStream = new
BufferedInputStream(entity.getContent());
BufferedOutputStream bufferedOutputStream = new
BufferedOutputStream(response.getOutputStream());
byte[] buffer = new byte[4096];
int readed;
while ((readed = bufferedInputStream.read(buffer)) > -1) {
bufferedOutputStream.write(buffer, 0, readed);
bufferedOutputStream.flush();
}
bufferedOutputStream.close();
bufferedInputStream.close();
entity.getContent().close();
}
}
private void init() {
PoolingClientConnectionManager cm = new
PoolingClientConnectionManager();
cm.setMaxTotal(100);
httpClient = new DefaultHttpClient(cm);
httpClient.setRedirectStrategy(new RedirectStrategy() {
@Override
public boolean isRedirected(HttpRequest request, HttpResponse
response, HttpContext context) throws ProtocolException {
return false;
}
@Override
public HttpUriRequest getRedirect(HttpRequest request,
HttpResponse response, HttpContext context) throws ProtocolException {
return null;
}
});
//
http://www.google.fr/webhp
//
httpClient.getParams().setParameter("http.protocol.single-cookie-header",
true);
}
private void init(String externalProxyHost, int externalProxyPort,
Credentials credentials) {
init();
proxyHost = new HttpHost(externalProxyHost, externalProxyPort);
httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,
proxyHost);
httpClient.getCredentialsProvider().setCredentials(
new AuthScope(null, -1),
credentials);
}
private HttpRequestBase getGoodRequest(Request request, Response
response) throws UnknownHostException, IOException, HttpException,
InterruptedException {
String methodString = request.getMethod().getMethodString();
if ("GET".equals(methodString)) {
return new HttpGet();
}
if ("POST".equals(methodString)) {
return new HttpPost();
}
if ("PUT".equals(methodString)) {
return new HttpPut();
}
if ("DELETE".equals(methodString)) {
return new HttpDelete();
}
if ("OPTIONS".equals(methodString)) {
return new HttpOptions();
}
if ("TRACE".equals(methodString)) {
return new HttpTrace();
}
if ("HEAD".equals(methodString)) {
return new HttpHead();
}
if ("CONNECT".equals(methodString)) {
for (String headerName : request.getHeaderNames()) {
// Exclude content length
System.out.println(" - header " + headerName + " = " +
request.getHeader(headerName));
}
String host = request.getRequestURI();
String port = host.substring(host.indexOf(":") + 1);
host = host.substring(0, host.indexOf(":"));
HttpHost target = new HttpHost(host, Integer.parseInt(port));
Socket socket;
if (proxyHost != null) {
ProxyClient proxyClient = new ProxyClient();
if (credentials instanceof NTCredentials) {
proxyClient.getAuthSchemeRegistry().register("ntlm",
new NTLMSchemeFactory());
}
System.out.println("Proxy tunnel");
socket = proxyClient.tunnel(proxyHost, target, credentials);
} else {
socket = new Socket(target.getHostName(), target.getPort());
}
// HttpParams params = new BasicHttpParams();
// params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS,
30);
//
params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new
ConnPerRouteBean(30));
// params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE,
false);
// HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
// SSLSocketFactory socketFactory =
SSLSocketFactory.getSocketFactory();
// final Socket secSocket =
socketFactory.createLayeredSocket(socket, host, Integer.parseInt(port),
params);
final Socket secSocket = socket;
final InputStream in = request.createInputStream();
final OutputStream out = response.getOutputStream();
// response.setStatus(200);
//response.setHeader("Connection", "close");
out.write(("HTTP/1.1 200 Connection
etablished\r\n"+CONNECT_OK_HEADERS).getBytes());
out.flush();
System.out.println("200 sended ");
// response.flush();
Thread tread = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("read from socket");
byte[] buffer = new byte[400];
int readed = 0;
while ((readed =
secSocket.getInputStream().read(buffer)) > -1) {
System.out.println("readed = " + readed);
out.write(buffer, 0, readed);
}
// int l = IOUtils.copy(secSocket.getInputStream(),
out);
System.out.println(" --> stop copy from socket
to out : " + readed);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
});
Thread twrite = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("Write to socket");
byte[] buffer = new byte[400];
int retry = 5;
int readed = 0;
while ((readed = in.read(buffer)) > -1 || retry >
0) {
System.out.println("readed = " + readed);
if (readed >= 0) {
secSocket.getOutputStream().write(buffer,
0, readed);
} else {
System.out.println("Wait from in 1s");
Thread.sleep(1000);
}
}
// int l = IOUtils.copy(in,
secSocket.getOutputStream());
System.out.println(" --> stop copy from in to
socket : " + readed);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
});
tread.start();
twrite.start();
tread.join();
twrite.join();
IOUtils.closeQuietly(secSocket);
return null;
}
throw new IllegalArgumentException("Unknown method : " +
methodString);
}
}
The test is
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package fr.bycode.tools.jntlmproxy;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.Socket;
import java.security.KeyStore;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.junit.Test;
/**
*
* @author yblazart
*/
public class ProxyServerTest2 {
@Test
public void test() throws Exception {
System.setProperty("javax.net.debug", "ssl");
ProxyHttpHandler proxyHttpHandler = new ProxyHttpHandler("proxy",
8080, "qjqx4250", "Gajdb5411&", true, "10.197.64.86", "AD");
// ProxyHttpHandler proxyHttpHandler = new ProxyHttpHandler();
MiniServer proxyServer = new MiniServer("0.0.0.0", 58080, "PROXY",
proxyHttpHandler);
proxyServer.start();
// HttpClient hc = WebClientDevWrapper.wrapClient(new
DefaultHttpClient());
HttpClient hc = new DefaultHttpClient();
HttpHost proxy = new HttpHost("10.158.80.132", 58080);
hc.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
//
//
HttpResponse execute = hc.execute(new HttpGet("
http://www.google.fr/
"));
String toString = EntityUtils.toString(execute.getEntity());
// System.out.println("toString = " + toString);
execute = hc.execute(new HttpGet("
https://mail.google.com/"));
System.out.println("xxxxx");
toString = EntityUtils.toString(execute.getEntity());
System.out.println("toString = " + toString);
while (System.in.read() < 1) {
Thread.sleep(1000);
}
proxyServer.stop();
}
}
2012/8/17 Oleksiy Stashok <oleksiy.stashok_at_oracle.com>
> Hi,
>
> can you pls. share the sources (or at least the part responsible for
> CONNECT) so we can reproduce that?
>
> Thanks.
>
> WBR,
> Alexey.
>
>
> On 08/17/2012 11:49 AM, yann Blazart wrote:
>
>> Hi ! I'm trying to implements my own proxy with grizzly, to pass my f...
>> NTML entreprise proxy.
>> I'm using httpclient 4.2 to get out.
>>
>> Well, everything is ok for Normal Http Method (get, put, delete ...).
>>
>> But I've some problem with connect method.
>>
>> In fact, I've writed my own HttpHandler, with the public void
>> service(Request request, Response response) method.
>>
>> In this, in case of connect method, I made the connection thought the
>> ProxyClient of HttpClient and make a tunnel by getting the socket.
>> I write in the response.getOutputStream the "HTTP/1.1 200 Connection
>> established".
>>
>> This is ok because in my unit test, the client receive it and after it
>> try to make the SSL handshake.
>>
>> After this I made two Threads that make copy form request.getInputStream
>> to socket output stream and from socket.getInputStream to
>> request.getOutputStream.
>>
>> The problem is that the client write to grizzly his SSL things, but the
>> request.getInputStream().read(**...) return -1...
>>
>> Any idea ?
>>
>
>