GitHub user nobodyiam opened a pull request:
https://github.com/apache/httpasyncclient/pull/8
Fix the issue when redirecting a post request, original 'Host' header is
carried
## Issue description
We have a situation that allows 307 redirects for POST methods, which works
well when using HttpClient.
However, when using HttpAsyncClient, we found the redirected request
carried the wrong 'Host' header, which caused the requests failed with error
responses like '421 Misdirected Request'.
## Demo to duplicate the issue
Attached is a simple demo to dupliate the issue:
[issue-duplication-demo.zip](https://github.com/apache/httpasyncclient/files/1851502/issue-duplication-demo.zip)
In this demo, we have a web controller that returns 307 redirect to
`https://hc.apache.org`:
```java
@RestController
public class Test307Controller {
@PostMapping("/test307")
@RequestMapping(value = "/test307", method = {RequestMethod.GET,
RequestMethod.POST})
public ModelAndView redirectPostToPost(HttpServletRequest request) {
request.setAttribute(View.RESPONSE_STATUS_ATTRIBUTE,
HttpStatus.TEMPORARY_REDIRECT);
return new ModelAndView("redirect:https://hc.apache.org");
}
}
```
And we have 2 tests that send a http post to this controller using
HttpClient and HttpAsyncClient respectively, which both expect a 200 response.
```Java
@Test
public void testSyncPost() throws Exception {
CloseableHttpClient httpclient = createSyncClient();
try {
HttpPost request = new HttpPost("http://localhost:8080/test307");
CloseableHttpResponse response = httpclient.execute(request);
System.out.println("Response status line: " +
response.getStatusLine());
assertEquals(200, response.getStatusLine().getStatusCode());
} finally {
httpclient.close();
}
}
@Test
public void testAsyncPost() throws Exception {
CloseableHttpAsyncClient httpclient = createAsyncClient();
try {
httpclient.start();
HttpPost request = new HttpPost("http://localhost:8080/test307");
Future<HttpResponse> future = httpclient.execute(request, null);
HttpResponse response = future.get();
System.out.println("Response status line: " +
response.getStatusLine());
assertEquals(200, response.getStatusLine().getStatusCode());
} finally {
httpclient.close();
}
}
```
However, only the HttpClient case will succeed and the HttpAsyncClient will
always fail with a http 421 response.
After downloading the demo to your computer, you may run `mvn clean test`
directly and shall see the `testSyncPost` case succeeds and the `testAsyncPost`
case fails.
## Locating the issue
After debugging both the HttpClient and HttpAsyncClient codes, we found the
difference is
[HttpClient](https://github.com/apache/httpcomponents-client/blob/4.5.x/httpclient/src/main/java/org/apache/http/impl/execchain/RedirectExec.java#L122)
passed `currentRequest.getOriginal()` to `redirectStrategy.getRedirect`
method, while
[HttpAsyncClient](https://github.com/apache/httpasyncclient/blob/4.1.x/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/MainClientExec.java#L591)
passed `currentRequest` directly to `redirectStrategy.getRedirect` method.
[HttpClient
logic](https://github.com/apache/httpcomponents-client/blob/4.5.x/httpclient/src/main/java/org/apache/http/impl/execchain/RedirectExec.java#L122):
```java
final HttpRequest redirect =
this.redirectStrategy.getRedirect(currentRequest.getOriginal(), response,
context);
```
[HttpAsyncClient
logic](https://github.com/apache/httpasyncclient/blob/4.1.x/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/MainClientExec.java#L591):
```java
final HttpUriRequest redirect =
this.redirectStrategy.getRedirect(currentRequest, currentResponse,
localContext);
```
Since the current request contains the 'Host' header, the redirected
request will fail.
For the demo case, the redirected request to `hc.apache.org` looks like the
following, which is obviously wrong since the `Host` header is still
`localhost:8080`:
```
POST / HTTP/1.1
Host: localhost:8080
...
User-Agent: Apache-HttpAsyncClient/4.1.3 (Java/1.8.0_74)
```
## Fixing the issue
The fix to this issue is simple: passing `currentRequest.getOriginal()` to
`redirectStrategy.getRedirect` method, just the same logic as what
[HttpClient](https://github.com/apache/httpcomponents-client/blob/4.5.x/httpclient/src/main/java/org/apache/http/impl/execchain/RedirectExec.java#L122)
does.
So please help to review this change, we do need this change available ASAP.
Thanks!
You can merge this pull request into a Git repository by running:
$ git pull https://github.com/nobodyiam/httpasyncclient 4.1.x
Alternatively you can review and apply these changes as the patch at:
https://github.com/apache/httpasyncclient/pull/8.patch
To close this pull request, make a commit to your master/trunk branch
with (at least) the following in the commit message:
This closes #8
----
commit e47ed00e488a6b2d84ad8043fdb197f8a7b2716c
Author: Jason Song <nobodyiam@...>
Date: 2018-03-27T10:07:17Z
fix the issue when redirecting a post request, the original 'Host' header
is carried, which will cause errors like '421 Misdirected Request'
----
---
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]