hc-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Mohammad Sadeq Dousti (JIRA)" <j...@apache.org>
Subject [jira] [Updated] (HTTPCORE-473) ElementalReverseProxy does not properly handle POST requests
Date Sat, 24 Jun 2017 07:56:01 GMT

     [ https://issues.apache.org/jira/browse/HTTPCORE-473?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]

Mohammad Sadeq Dousti updated HTTPCORE-473:
-------------------------------------------
    Description: 
Dear Oleg et al.,

I understand that {{ElementalReverseProxy}} is provided just as an example, but it will be
great if this example works properly, as it shows how the underlying API must be used.

Here's a simple setup that shows why {{ElementalReverseProxy}} fails to work with POST request
(and in fact, any requests including {{Content-Length}} or {{Transfer-Content}} headers):
# Let {{http://127.0.0.1:80}} denote the back-end server which we want to proxy against, and
assume the server hosts the file {{/index.html}}.
# Run {{ElementalReverseProxy}} with default config against the back-end server.

Test the back-end server using {{wget}}:


{code:bash}
wget http://127.0.0.1:80 --post-data="some data"
--2017-06-24 11:52:30--  http://127.0.0.1/
Connecting to 127.0.0.1:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 343 [text/html]
Saving to: 'index.html'

index.html                      100%[====================================================>]
    343  --.-KB/s    in 0s

2017-06-24 11:52:30 (9.78 MB/s) - 'index.html' saved [343/343]
{code}

As you can see, it works just fine. Now try it with {{ElementalReverseProxy}}:

{code:bash}
wget http://127.0.0.1:8888 --post-data="some data"
--2017-06-24 11:53:31--  http://127.0.0.1:8888/
Connecting to 127.0.0.1:8888... connected.
HTTP request sent, awaiting response... 400 Bad Request
2017-06-24 11:53:31 ERROR 400: Bad Request.
{code}

h3. Resolution

{{ProxyThread}} executes {{httpservice.handleRequest}}, which in turn calls {{processor.process(request,
context)}}. This causes {{RequestContent.process()}} to be executed, which throws an exception
as it finds that the request already contains the {{Content-Length}} header.

One way to rectify this is to initialize {{inhttpproc}} with {{RequestContent(true)}}, which
overwrites the {{Content-Length}} header even if it is present, without throwing an exception.

Running {{wget}} again will now result in no error, but with one catch: Notice the response
misses the {{Content-Length}} header (this is evident from {{Length: unspecified}} below):

{code:bash}
wget http://127.0.0.1:8888 --post-data="some data"
--2017-06-24 12:09:25--  http://127.0.0.1:8888/
Connecting to 127.0.0.1:8888... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: 'index.html'

index.html                          [ <=>                                          
      ]     343  --.-KB/s    in 0s

2017-06-24 12:09:25 (8.82 MB/s) - 'index.html' saved [343]
{code}

This is due to the line {{targetResponse.removeHeaders(HTTP.CONTENT_LEN)}} in {{ProxyHandler#handle()}}
method. Commenting this line will resolve the issue.

In general, I don't get the {{ProxyHandler#handle()}} method: It is called by {{HttpService#doService()}},
which in turn gets called just after the following line:

{code:java}
this.processor.process(request, context);
{code}

So, it means that just after the above line applied mandatory HTTP headers, {{ProxyHandler#handle()}}
removes them all! Next, it tries to re-apply them:

{code:java}
this.httpexecutor.preProcess(request, this.httpproc, context);
{code}

But here, {{this.httpproc}} refers to {{outhttpproc}}, for which the {{requestInterceptors}}
instance is {{null}} effectively doing nothing.

  was:
Dear Oleg et al.,

I understand that {{ElementalReverseProxy}} is provided just as an example, but it will be
great if this example works properly, as it shows how the underlying API must be used.

Here's a simple setup that shows why {{ElementalReverseProxy}} fails to work with POST request
(and in fact, any requests including {{Content-Length}} or {{Transfer-Content}} headers):
# Let {{http://127.0.0.1:80}} denote the back-end server which we want to proxy against, and
assume the server hosts the file {{/index.html}}.
# Run {{ElementalReverseProxy}} with default config against the back-end server.

Test the back-end server using {{wget}}:

{{wget http://127.0.0.1:80 --post-data="some data"
--2017-06-24 11:52:30--  http://127.0.0.1/
Connecting to 127.0.0.1:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 343 [text/html]
Saving to: 'index.html'

index.html                      100%[====================================================>]
    343  --.-KB/s    in 0s

2017-06-24 11:52:30 (9.78 MB/s) - 'index.html' saved [343/343]}}

As you can see, it works just fine. Now try it with {{ElementalReverseProxy}}:

{{wget http://127.0.0.1:8888 --post-data="some data"
--2017-06-24 11:53:31--  http://127.0.0.1:8888/
Connecting to 127.0.0.1:8888... connected.
HTTP request sent, awaiting response... 400 Bad Request
2017-06-24 11:53:31 ERROR 400: Bad Request.}}

h3. Resolution

{{ProxyThread}} executes {{httpservice.handleRequest}}, which in turn calls {{processor.process(request,
context)}}. This causes {{RequestContent.process()}} to be executed, which throws an exception
as it finds that the request already contains the {{Content-Length}} header.

One way to rectify this is to initialize {{inhttpproc}} with {{RequestContent(true)}}, which
overwrites the {{Content-Length}} header even if it is present, without throwing an exception.

Running {{wget}} again will now result in no error, but with one catch: Notice the response
misses the {{Content-Length}} header (this is evident from {{Length: unspecified}} below):

{{wget http://127.0.0.1:8888 --post-data="some data"
--2017-06-24 12:09:25--  http://127.0.0.1:8888/
Connecting to 127.0.0.1:8888... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: 'index.html'

index.html                          [ <=>                                          
      ]     343  --.-KB/s    in 0s

2017-06-24 12:09:25 (8.82 MB/s) - 'index.html' saved [343]}}

This is due to the line {{targetResponse.removeHeaders(HTTP.CONTENT_LEN)}} in {{ProxyHandler#handle()}}
method. Commenting this line will resolve the issue.

In general, I don't get the {{ProxyHandler#handle()}} method: It is called by {{HttpService#doService()}},
which in turn gets called just after the following line:

{{this.processor.process(request, context);}}

So, it means that just after the above line applied mandatory HTTP headers, {{ProxyHandler#handle()}}
removes them all! Next, it tries to re-apply them:

{{this.httpexecutor.preProcess(request, this.httpproc, context);}}

But here, {{this.httpproc}} refers to {{outhttpproc}}, for which the {{requestInterceptors}}
instance is {{null}} effectively doing nothing.


> ElementalReverseProxy does not properly handle POST requests
> ------------------------------------------------------------
>
>                 Key: HTTPCORE-473
>                 URL: https://issues.apache.org/jira/browse/HTTPCORE-473
>             Project: HttpComponents HttpCore
>          Issue Type: Bug
>          Components: Examples
>    Affects Versions: 4.4.6
>         Environment: Windows 7, Java 8
>            Reporter: Mohammad Sadeq Dousti
>            Priority: Minor
>
> Dear Oleg et al.,
> I understand that {{ElementalReverseProxy}} is provided just as an example, but it will
be great if this example works properly, as it shows how the underlying API must be used.
> Here's a simple setup that shows why {{ElementalReverseProxy}} fails to work with POST
request (and in fact, any requests including {{Content-Length}} or {{Transfer-Content}} headers):
> # Let {{http://127.0.0.1:80}} denote the back-end server which we want to proxy against,
and assume the server hosts the file {{/index.html}}.
> # Run {{ElementalReverseProxy}} with default config against the back-end server.
> Test the back-end server using {{wget}}:
> {code:bash}
> wget http://127.0.0.1:80 --post-data="some data"
> --2017-06-24 11:52:30--  http://127.0.0.1/
> Connecting to 127.0.0.1:80... connected.
> HTTP request sent, awaiting response... 200 OK
> Length: 343 [text/html]
> Saving to: 'index.html'
> index.html                      100%[====================================================>]
    343  --.-KB/s    in 0s
> 2017-06-24 11:52:30 (9.78 MB/s) - 'index.html' saved [343/343]
> {code}
> As you can see, it works just fine. Now try it with {{ElementalReverseProxy}}:
> {code:bash}
> wget http://127.0.0.1:8888 --post-data="some data"
> --2017-06-24 11:53:31--  http://127.0.0.1:8888/
> Connecting to 127.0.0.1:8888... connected.
> HTTP request sent, awaiting response... 400 Bad Request
> 2017-06-24 11:53:31 ERROR 400: Bad Request.
> {code}
> h3. Resolution
> {{ProxyThread}} executes {{httpservice.handleRequest}}, which in turn calls {{processor.process(request,
context)}}. This causes {{RequestContent.process()}} to be executed, which throws an exception
as it finds that the request already contains the {{Content-Length}} header.
> One way to rectify this is to initialize {{inhttpproc}} with {{RequestContent(true)}},
which overwrites the {{Content-Length}} header even if it is present, without throwing an
exception.
> Running {{wget}} again will now result in no error, but with one catch: Notice the response
misses the {{Content-Length}} header (this is evident from {{Length: unspecified}} below):
> {code:bash}
> wget http://127.0.0.1:8888 --post-data="some data"
> --2017-06-24 12:09:25--  http://127.0.0.1:8888/
> Connecting to 127.0.0.1:8888... connected.
> HTTP request sent, awaiting response... 200 OK
> Length: unspecified [text/html]
> Saving to: 'index.html'
> index.html                          [ <=>                                     
           ]     343  --.-KB/s    in 0s
> 2017-06-24 12:09:25 (8.82 MB/s) - 'index.html' saved [343]
> {code}
> This is due to the line {{targetResponse.removeHeaders(HTTP.CONTENT_LEN)}} in {{ProxyHandler#handle()}}
method. Commenting this line will resolve the issue.
> In general, I don't get the {{ProxyHandler#handle()}} method: It is called by {{HttpService#doService()}},
which in turn gets called just after the following line:
> {code:java}
> this.processor.process(request, context);
> {code}
> So, it means that just after the above line applied mandatory HTTP headers, {{ProxyHandler#handle()}}
removes them all! Next, it tries to re-apply them:
> {code:java}
> this.httpexecutor.preProcess(request, this.httpproc, context);
> {code}
> But here, {{this.httpproc}} refers to {{outhttpproc}}, for which the {{requestInterceptors}}
instance is {{null}} effectively doing nothing.



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@hc.apache.org
For additional commands, e-mail: dev-help@hc.apache.org


Mime
View raw message