Http Proxy and Pump

1,259 views
Skip to first unread message

Marco Palladino

unread,
Nov 10, 2012, 11:07:31 PM11/10/12
to ve...@googlegroups.com
I was trying to create a simple HTTP proxy using Pump, with the following code:

vertx.createHttpServer().requestHandler(new Handler<HttpServerRequest>() {
@Override
public void handle(final HttpServerRequest request) {
HttpClient httpClient = vertx.createHttpClient().setHost("host.com").setPort(80);
HttpClientRequest clientRequest = httpClient.request(request.method, request.uri, new Handler<HttpClientResponse>() {
@Override
public void handle(HttpClientResponse clientResponse) {
Pump.createPump(clientResponse, request.response);
}
});
Pump.createPump(request, clientRequest);
}
}).listen(9000);

The thing is that the code above doesn't work, so I'm probably making the wrong assumptions on how Pump.createPump works.

Any tips?

Christian Essl

unread,
Nov 11, 2012, 3:37:15 AM11/11/12
to ve...@googlegroups.com
I can't answer you question regarding Pump but there is an example for a http proxy in samples (which does not use Pump): https://github.com/vert-x/vert.x/tree/master/vertx-examples/src/main/java/proxy Maybe that helps

Marco Palladino

unread,
Nov 11, 2012, 4:25:59 AM11/11/12
to ve...@googlegroups.com
I've seen it too but I was wondering if Pump can be used instead, as it seems to be the best use case scenario for it.

ddimensia

unread,
Nov 12, 2012, 1:17:05 PM11/12/12
to ve...@googlegroups.com
I believe you have to copy the headers across first before using the Pump, by the time your handler is called for an HttpServer (same on the response from the HttpClient) the headers are parsed.  The Pump will transfer the body of the request/response.

Guido García

unread,
Dec 19, 2012, 10:59:44 AM12/19/12
to ve...@googlegroups.com
I don't know if that solves your issue but at least you need to call Pump#start() after calling createPump().

Did you finally get it working? If so it would be great to see the final working solution.

Thanks.


On Sunday, November 11, 2012 5:07:31 AM UTC+1, Marco Palladino wrote:

Max Calderoni

unread,
May 2, 2013, 7:29:22 PM5/2/13
to ve...@googlegroups.com
Hi,
have the same question about using Pump in an http proxy as described in this thread.
Was anybody able to do this?
I am attaching some code that does not work as i wished.
To run it (check the code first as there is one hardcoded file path - you need to give it a file to upload), you do:
vertx run UploadServer.java
vertx run ProxyServer.java
vertx run UploadClient.java -instances 2

It will upload the file, but only one, not two, while i have two verticles, so, should be two files.

From other posts i read, sounds like Pump cannot be used this way, but i wish someone confirmed that.

Max
httppump.tar.gz

Tim Fox

unread,
May 3, 2013, 2:05:18 AM5/3/13
to ve...@googlegroups.com
Please open a github issue if the issue can be easily replicated

On 03/05/13 00:29, Max Calderoni wrote:
> Hi,
> have the same question about using Pump in an http proxy as described in
> this thread.
> Was anybody able to do this?
> I am attaching some code that does not work as i wished.
> To run it (check the code first as there is one hardcoded file path - you
> need to give it a file to upload), you do:
> vertx run UploadServer.java
> vertx run ProxyServer.java
> vertx run UploadClient.java -instances 2
>
> It will upload the file, but only one, not two, while i have two verticles,
> so, should be two files.
>
> From other posts i read, sounds like Pump cannot be used this way, but i
> wish someone confirmed that.
>
> Max
>

Max Calderoni

unread,
May 3, 2013, 1:22:19 PM5/3/13
to ve...@googlegroups.com
Ok, thanks, done in vertx github: "Http Proxy and Pump".
(was not able to quickly find a way to attach the gz there, however)


On Thu, May 2, 2013 at 11:05 PM, Tim Fox <timv...@gmail.com> wrote:
Please open a github issue if the issue can be easily replicated


On 03/05/13 00:29, Max Calderoni wrote:
Hi,
have the same question about using Pump in an http proxy as described in
this thread.
Was anybody able to do this?
I am attaching some code that does not work as i wished.
To run it (check the code first as there is one hardcoded file path - you
need to give it a file to upload), you do:
vertx run UploadServer.java
vertx run ProxyServer.java
vertx run UploadClient.java -instances 2

It will upload the file, but only one, not two, while i have two verticles,
so, should be two files.

 From other posts i read, sounds like Pump cannot be used this way, but i
wish someone confirmed that.

Max


--
You received this message because you are subscribed to a topic in the Google Groups "vert.x" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/vertx/9x2p7AGx7kM/unsubscribe?hl=en-GB.
To unsubscribe from this group and all of its topics, send an email to vertx+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.





--
Max Calderoni

ddimensia

unread,
May 13, 2013, 6:59:33 PM5/13/13
to ve...@googlegroups.com
I think you're issue is how the underlying HttpClient class deals with boss threads or max connections (can't remember which one it is).  If I remember the 1.3.1 code correctly it will queue the second request rather than run them simultaneously, somewhere in the code I think there may be an issue with losing that second request as I've seen similar issues in a different app that doesn't use Pump.

-Gil
To unsubscribe from this group and all of its topics, send an email to vertx+un...@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.





--
Max Calderoni

Kevin Cox

unread,
May 13, 2013, 10:52:07 PM5/13/13
to ve...@googlegroups.com
Try adding .start()
Pump.createPump(clientResponse, request.response).start();

Max Calderoni

unread,
May 14, 2013, 2:16:04 AM5/14/13
to ve...@googlegroups.com
the start() call is there.


On Mon, May 13, 2013 at 7:52 PM, Kevin Cox <koxa...@gmail.com> wrote:
Try adding .start()
Pump.createPump(clientResponse, request.response).start();

--
You received this message because you are subscribed to a topic in the Google Groups "vert.x" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/vertx/9x2p7AGx7kM/unsubscribe?hl=en-GB.
To unsubscribe from this group and all of its topics, send an email to vertx+un...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Max Calderoni

Max Calderoni

unread,
May 14, 2013, 3:17:25 AM5/14/13
to ve...@googlegroups.com
Gil,
thanks for your reply, but i think Tim answered that he is expecting that behavior (see issue https://github.com/vert-x/vert.x/issues/585).

So, i rewrote that proxy and i am reattaching code here, where i do get multiple files uploaded/downloaded like i wanted for my test, but i am losing data: sometimes the file downloaded is corrupt.

The (perhaps ignorant) question then still is: how to use the Pump API with http.
Am i getting close? Because i get an NPE on the server's code (also attached).
What am i doing wrong? Is it the endHandler?

The attached zip contains a java file called Config in which you have to first hard-code the configuration of source/sink directory and download/upload file of your choice (the file i tested is 135263593 bytes). Then in 3 terminals you run server, proxy and ten client instances:

$>vertx run Server.java
$>vertx run Proxy.java
$>vertx run DClient.java -instances 10

That should generate an NPE (attached) after a few downloads. .

Uploads seem to work fine:
$>vertx run UClient.java -instances 10

So, in summary questions are:
1) am i using this API correctly?
2) if not, how to use it correctly? In other words, what is the correct Proxy.java code.

What i am trying to write here is a test that simulates many uploads/downloads in rapid succession of many files simultaneously.
Maybe this is an incorrect way to test that, but i would still like to assess what is wrong with this code.

Massimo

http_pump.zip

Max Calderoni

unread,
May 15, 2013, 10:03:15 PM5/15/13
to ve...@googlegroups.com
Adapted code to vertx 2.0.0.beta1 and it works. Attaching code.



--
Max Calderoni
http_pump_2.0.0.beta1.zip

Deven Phillips

unread,
Mar 3, 2015, 10:16:12 PM3/3/15
to ve...@googlegroups.com
I was just working on this same problem using Vert.x 3.0.0-SNAPSHOT and thought I would post an update for any who might be interested.. The code example above helped me, but I think it was incomplete as it does not appear to forward any responses back from the proxied resource..

It looks like this code does:

Client -> Proxy -> Server

But it does not appear to handle any response data like:

Client -> Proxy -> Server -> Proxy -> Client

Here's an example from my proxy server (still untested):

    /**
     * Send a request received by the proxy, forward it to the Nexus server, and send back the results
     * @param ctx The {@link RoutingContext} of the request
     */
    private void sendProxyRequest(RoutingContext ctx) {
        String urlWithQueryParams = ctx.request().uri().split("/", 3)[4];
        String uri = "http://"
                + context.config().getString("targetHost")
                + ":"
                + context.config().getString("targetPort")
                + "/" + urlWithQueryParams;
        HttpClient client = vertx.createHttpClient(new HttpClientOptions());
        final HttpClientRequest req = client.request(ctx.request().method(), uri);
        req.headers().clear().addAll(ctx.request().headers());
        req.endHandler(end -> {
            ctx.response().end();
        });
        req.setChunked(true);
        req.handler(pResponse -> {
            ctx.response().headers().clear().addAll(pResponse.headers());
            ctx.response().setStatusCode(pResponse.statusCode());
            ctx.response().setStatusMessage(pResponse.statusMessage());
            ctx.response().setChunked(true);
            Pump targetToProxy = Pump.pump(pResponse, ctx.response());
        });
        Pump proxyToTarget = Pump.pump(ctx.request(), req);
        proxyToTarget.start();
    }

Deven Phillips

unread,
Mar 3, 2015, 10:18:12 PM3/3/15
to ve...@googlegroups.com
Whoops! I forgot to "start()" the pumps in that snippet!

Deven

Deven Phillips

unread,
Mar 4, 2015, 12:07:19 AM3/4/15
to ve...@googlegroups.com
So, I coded up an simple example and pushed it up to GitHub, and it works . . . . . MOSTLY...

https://github.com/InfoSec812/simple-vertx-proxy-example

The problem that I am having is that even though all of the data is being proxied in both directions, the response connection is never ending so the browser's indicator keeps spinning (or curl requests hang at the end)... Could someone explain what I might be doing wrong?

Thanks in advance!!

Deven

Tim Fox

unread,
Mar 4, 2015, 3:27:02 AM3/4/15
to ve...@googlegroups.com
Hi Deven,

I can see a few issues with you example:

1. https://github.com/InfoSec812/simple-vertx-proxy-example/blob/master/src/main/java/com/zanclus/simple/proxy/example/Main.java#L38

Not sure what you want to achieve here - a request end handle is called after the request has ended, so writing something then doesn't make much sense.

2. https://github.com/InfoSec812/simple-vertx-proxy-example/blob/master/src/main/java/com/zanclus/simple/proxy/example/Main.java#L51

You should use routingContext.addBodyEndHandler() not request.bodyEndHandler() in Apex

but... I'm not sure what you want to achieve here and why you're writing a \r\n...

btw - have you looked at the proxy example in the examples repo?

hth
--
You received this message because you are subscribed to the Google Groups "vert.x" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vertx+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Deven Phillips

unread,
Mar 4, 2015, 7:33:43 AM3/4/15
to ve...@googlegroups.com
The "end("\r\n\")" was just me flailing about wildly last night after too little sleep. I have tried many numbers of combinations. I will try addBodyEndHandler on the RoutingContext and report back..

Deven

Deven Phillips

unread,
Mar 4, 2015, 8:04:50 AM3/4/15
to ve...@googlegroups.com
OK, as to if I had looked at the vert-x3/vertx-examples for the Proxy, I remember now, after looking again, I had looked at it... I was concerned about using that code because the application I am going to proxy will be handling large file uploads/downloads. With that concern, I thought it more reliable to use Pump to ensure that the application could handle lots of data without lots of RAM..

Additionally, in my final target application, I only want to proxy requests for a certain URI space to another application while other requests are handled by the Vert.x application:

For example, requests to "/proxypath/" would get proxied to a backend application while requests to "/rest/**" or "/static/**" would be handled by my Vert.x application.

I updated the code with your suggestions and I am still seeing the same symptoms. The updated code has been pushed to the GitHub repo... I'm not sure what to do next...


Thanks for the help and all the work on Vert.x!!

Deven

Tim Fox

unread,
Mar 4, 2015, 8:22:18 AM3/4/15
to ve...@googlegroups.com
I've simplified your example here https://github.com/InfoSec812/simple-vertx-proxy-example/pull/1

I haven't tested with PUT/POST but it works with the simple GET to reddit as in your example.

Andrey

unread,
Dec 18, 2015, 10:39:14 AM12/18/15
to vert.x
Tim,

I'm trying to implement something similar, and faced with the issue that you can find at https://github.com/eclipse/vert.x/issues/1244.
As Julien Viet stated, the root cause is Pump pauses http client connection and it may leave connection hanging in some situations (and entire proxy server if there is no more room in connection pool).


What i've done to break it:
1. set client max pool size to 1 (for simplicity)     
2. set server socket accept backlog to 1 (to get connection reset from server using less connections)
3. replace www.reddit.com with www.google.com since reddit responds with redirect and empty body, so pump is not involved, but it should.
4. ab -n2 -c2 http://localhost:8080/ (Apache Bench to send 2 connections concurrently)

After that you should see 'Benchmarking localhost (be patient)...apr_socket_recv: Connection reset by peer (54)'. If not, try one more time probably increasing connections amount. 

After that, most likely (not always, but almost every time) you've got hanging proxy that do not respond to requests. And http client connection becomes CLOSE_WAIT some time later.

So, the question is how to write a proxy absolutely correctly with all required exception handlers to prevent any denial of service?

Thanks!

среда, 4 марта 2015 г., 16:22:18 UTC+3 пользователь Tim Fox написал:
Reply all
Reply to author
Forward
0 new messages