Am 2020-05-26 um 20:20 schrieb Oleg Kalnichevski:
On Tue, 2020-05-26 at 17:58 +0000, Bernd Eckenfels wrote:
Michael, this looks a bit like the packets in between have been TLS
handshakes which have not been carried out because the engine was not
kicked off. Maybe a starHandshake() would help? Or can you share the
full traces? Did you try http as well?
Michael,
I can only second what Bernd has said. Try to simplify the setup and
see if you can get things to work with plain HTTP first.
Also feel free to tweak my code as you see fit.
I followed Bernd's advise and disabled TLS. Although I already had a
clue what is going wrong. Attached is a patch on top of Oleg's branch
which makes it work unencrypted and encrypted. I will explain in detail
why the changes are necessary.
- public static final Timeout DEFAULT_WAIT_FOR_EARLY_RESPONSE =
Timeout.ofMilliseconds(5);
+ public static final Timeout DEFAULT_WAIT_FOR_EARLY_RESPONSE =
Timeout.ofMilliseconds(50);
unless client and server are physically next to each other 5 ms are
virtually impossible. I have tried with our server at work. I am
connected with my laptop via VPN to the corporate network, I don't know
where the peering point of our VPN provider is, but the server is
physically 10 km away from me and with TLS 1.3 it takes 28 ms to produce
the 401.
Maybe both timeouts (expect and early) should be configurable via
RequestConfig?
+ conn.flush();
This is why it did not work before is that headers were stuck in the
local buffer and were flushed only when the body was sent. So the server
never saw the headers before the body. The wait was pointless.
Please also note that even the buffer for headers might be large due to
some authnz tokens. E.g., JWT or SPNEGO, cookies, etc.
+ response = conn.receiveResponseHeader();
One needs to read the headers because the client shall be able to see
the status code and if fast enough the response body. In my case the
error page from Tomcat.
RFC 7230, section 6.5 says:
A client sending a message body SHOULD monitor the network connection
for an error response while it is transmitting the request. If the
client sees a response that indicates the server does not wish to
receive the message body and is closing the connection, the client
SHOULD immediately cease transmitting the body and close its side of
the connection.
I have issued another request and HttpClient reuses the connection
because Tomcat forgot to send "Connection: close". At some point the
second request will fail and no additional 401 is responded (of course.
I consider the missing "Connection: close" to be a bug in Tomcat [1].
So HttpClent behaves correctly. I assume that then a close would be
send, response#close() will do the right thing and subsequent requests
will use new connections.
WDYT?
Michael
[1] https://www.mail-archive.com/[email protected]/msg135255.html
diff --git
a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/HttpRequestExecutor.java
b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/HttpRequestExecutor.java
index 8f777243a..402182740 100644
---
a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/HttpRequestExecutor.java
+++
b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/HttpRequestExecutor.java
@@ -74,7 +74,7 @@
public class HttpRequestExecutor {
public static final Timeout DEFAULT_WAIT_FOR_CONTINUE =
Timeout.ofSeconds(3);
- public static final Timeout DEFAULT_WAIT_FOR_EARLY_RESPONSE =
Timeout.ofMilliseconds(5);
+ public static final Timeout DEFAULT_WAIT_FOR_EARLY_RESPONSE =
Timeout.ofMilliseconds(50);
public static final long LARGE_MESSAGE_LEN = 64 * 1024;
private final Timeout waitForContinue;
@@ -156,13 +156,17 @@ public ClassicHttpResponse execute(
if (streamListener != null) {
streamListener.onRequestHead(conn, request);
}
+ conn.flush();
+
boolean expectContinue = false;
final HttpEntity entity = request.getEntity();
+ ClassicHttpResponse response = null;
if (entity != null) {
final Header expect =
request.getFirstHeader(HttpHeaders.EXPECT);
expectContinue = expect != null &&
HeaderElements.CONTINUE.equalsIgnoreCase(expect.getValue());
if (!expectContinue) {
if (entity.getContentLength() > LARGE_MESSAGE_LEN &&
conn.isDataAvailable(waitForEarlyResponse)) {
+ response = conn.receiveResponseHeader();
conn.terminateRequest(request);
} else {
conn.sendRequestEntity(request);
@@ -170,7 +174,7 @@ public ClassicHttpResponse execute(
}
}
conn.flush();
- ClassicHttpResponse response = null;
+
while (response == null) {
if (expectContinue) {
if (conn.isDataAvailable(this.waitForContinue)) {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]