users@grizzly.java.net

Re: Make an http proxy with grizzly

From: Oleksiy Stashok <oleksiy.stashok_at_oracle.com>
Date: Sat, 18 Aug 2012 21:01:38 +0200

Hi,

On 08/18/2012 03:14 PM, yann Blazart wrote:
> Hi ! Thanks for your patch. But it doesn't seem to work....
> The read in the inputstream of the request is blocked again.
Wait didn't it return -1 before?
Now it will block if there is no data to read - that's expected.

If you want to leverage NIO - you have to use NIOInputStream's isReady()
and notifyAvailable(...) methods like in this sample [1].

WBR,
Alexey.

[1]
http://java.net/projects/grizzly/sources/git/content/samples/http-server-samples/src/main/java/org/glassfish/grizzly/samples/httpserver/nonblockinghandler/UploadHttpHandlerSample.java

>
> I made a test with a stupid ServerSocket with old IO and it works. I
> would prefer to use Grizzly....
>
> 2012/8/18 Oleksiy Stashok <oleksiy.stashok_at_oracle.com
> <mailto:oleksiy.stashok_at_oracle.com>>
>
> Thanks.
>
> it was an issue in Grizzly
> http://java.net/jira/browse/GRIZZLY-1317
>
> I've fixed it on trunk and added unit-test.
> You can either checkout the Grizzly trunk or use Grizzly
> 3.0-SNAPSHOT maven dependency (artifacts will be available soon @
> snapshots repository [1]).
>
> Let me know if it works for you.
>
> Thanks.
>
> WBR,
> Alexey.
>
> [1] https://maven.java.net/content/repositories/snapshots/
>
>
> On 08/17/2012 12:04 PM, yann Blazart wrote:
>> 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
>> <mailto: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 ?
>>
>>
>>
>
>
>