HI I m trying to write a client that makes http2 request to multiple servers(which already supports http2). so far I have written this standalone program which works fine that I can see all requests goes via same tcp connection(verified with the help of wireshark). I use Apache Httpclient 5 with conscrypt to support ALPN in jdk8 (jdk8 is my requirement, I cannot upgrade to jdk9 or later)
The Main block goes like,
try {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager(){
public X509Certificate[] getAcceptedIssuers(){ return null; }
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
}
};
Provider provider = Conscrypt.newProvider();
SSLContext sslContext = SSLContext.getInstance("TLSv1.3", provider);
sslContext.init(null, trustAllCerts, new SecureRandom());
client = Http2AsyncClientBuilder.create().setTlsStrategy(new ConscryptClientTlsStrategy(sslContext)).setH2Config(H2Config.DEFAULT).build();
client.start();
ThreadPoolExecutor tpe = (ThreadPoolExecutor)Executors.newFixedThreadPool(50);
for (int i=0; i < 50; i++) {
Runnable worker = new WorkerClass(client, i);
tpe.execute(worker);
}
} catch (Exception e) {
e.printStackTrace();
}
The runnable goes like,
static class WorkerClass implements Runnable {
CloseableHttpAsyncClient client = null;
int i = 0;
WorkerClass(CloseableHttpAsyncClient client, int i) {
this.client = client;
this.i = i;
}
public void run() {
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(Timeout.of(15, TimeUnit.SECONDS))//Determines the timeout until a new connection is fully established.
.setConnectionRequestTimeout(Timeout.of(60, TimeUnit.SECONDS))//Returns the connection lease request timeout used when requesting a connection from the connection manager.
.setResponseTimeout(Timeout.of(60, TimeUnit.SECONDS))//Determines the timeout until arrival of a response from the opposite endpoint.
.build();
String url = "https://localhost:8081/myagent/getOutput?"+System.currentTimeMillis();
String cachedXMLRequest = "<?xml version=\"1.0\" standalone=\"no\"?><My XML REQUEST GOES HERE>";
SimpleHttpRequest request= SimpleHttpRequests.POST.create(url);
request.setBodyText(cachedXMLRequest, ContentType.APPLICATION_JSON);
request.setConfig(requestConfig);
final CountDownLatch latch = new CountDownLatch(1);
client.execute(request, new FutureCallback<SimpleHttpResponse>() {
@Override
public void cancelled() {
System.out.println("Cancelled");
latch.countDown();
}
@Override
public void completed(SimpleHttpResponse arg0) {
System.out.println("Completed "+arg0.getBodyText());
latch.countDown();
}
@Override
public void failed(Exception exception) {
System.out.println("Failed ");
exception.printStackTrace();
latch.countDown();
}
});
try {
latch.await(60, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
So I simulated this standalone in my client which asynchronously calls multiple servers for polling using the above logic. But here I can see one tcp connection per request and the connection is closed at the end of the request(Though the response header returns as HTTP/2.0). I use the main block code to initialize the client at the startup of my application(Except threadpool part, as it is used to simulate multithreaded environment in standalone) and create the url, request and response objects and execute each request simultaneously in a threaded model(Asynchronous multiplexing). My requirement is to use one tcp connection per domain and use it for prolonged time for handling high number of requests. What am I missing here?
Or someone hep me with the proper way fo handling http2 using httpclient 5
Kindy shed some light on it.
Edited:
There are two things I tracked down for abnormal connection closes,
1. The connection is closed after every single request
Reason: caused by this line
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(Timeout.of(15, TimeUnit.SECONDS))...
This setConnectTimeout is supposed to be at request level, but after 15 idle seconds it closes the tcp connection itself, I don't know whether it is a bug or expected behaviour as this configuration is for encapsulating request items as per the documentation.
Removing this line allows the tcp connection to be kept alive for more than a request.
2. Due to Illegal HEADERS frame/Protocol ERROR/INTERNAL ERROR
I can see these exception in wire log exactly where my tcp connection is getting closed(it closes randomly), I could not share the whole logs as there are too many I just post the exception part
0x0][0x1][0x0][0x0][0x4][0xffffffc9]"
2019-02-07 16:05:08,666 DEBUG - i/o-0000001B << stream 0 frame: WINDOW_UPDATE (0x8); flags: (0x0); length: 4
2019-02-07 16:05:08,666 DEBUG - i/o-0000001B << Increment 1225
2019-02-07 16:05:08,666 DEBUG - i/o-0000001B >> stream 0 flow control 1225 -> 65535
2019-02-07 16:05:08,666 DEBUG - i/o-0000001B << stream 1 frame: WINDOW_UPDATE (0x8); flags: (0x0); length: 4
2019-02-07 16:05:08,666 DEBUG - i/o-0000001B << Increment 1225
2019-02-07 16:05:08,666 DEBUG - i/o-0000001B >> stream 1 flow control 1225 -> 65535
2019-02-07 16:05:08,827 DEBUG - i/o-0000001B << "[0x0][0x0][0x1d][0x1][0x4][0x0][0x0][0x0][0x5]?[0xffffffe1]?[0xffffff88][0x1f][0x12][0xffffff96][0xffffffdf]=[0xffffffbf]J[0x1][0xffffffd5]0[0xffffff96]5[0x4][0x0][0xffffffbe][0xffffffa0]Aq[0xffffff91][0x10][0xffffff94][0xffffffc5][0xffffffa3][0x0][0x3]E[0x0][0x1][0x0][0x0][0x0][0x5][\n]"
2019-02-07 16:05:08,827 DEBUG - i/o-0000001B << "[\n]"
2019-02-07 16:05:08,827 DEBUG - i/o-0000001B << ""
2019-02-07 16:05:08,827 DEBUG - i/o-0000001B << stream 5 frame: HEADERS (0x1); flags: END_HEADERS (0x4); length: 29
2019-02-07 16:05:08,828 DEBUG - i/o-0000001B << ?.?. ...=.J..0.5 3f e1 3f 88 1f 12 96 df 3d bf 4a 01 d5 30 96 35
2019-02-07 16:05:08,828 DEBUG - i/o-0000001B << ....Aq..... 04 00 be a0 41 71 91 5c 10 94 c5 a3 7f
2019-02-07 16:05:08,828 DEBUG - i/o-0000001B >> stream 0 frame: GOAWAY (0x7); flags: (0x0); length: 29
2019-02-07 16:05:08,828 DEBUG - i/o-0000001B >> Last stream 0
2019-02-07 16:05:08,829 DEBUG - i/o-0000001B >> Code PROTOCOL_ERROR
2019-02-07 16:05:08,829 DEBUG - i/o-0000001B >> Illegal HEADERS frame
2019-02-07 16:05:08,829 DEBUG - i/o-0000001B >> "[0x0][0x0][0x1d][0x7][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x1]Illegal HEADERS frame"
2019-02-07 16:05:10,401 DEBUG - ex-0000018D: preparing request execution
and,
2019-02-07 16:17:17,519 DEBUG - i/o-0000000C << stream 0 frame: WINDOW_UPDATE (0x8); flags: (0x0); length: 4
2019-02-07 16:17:17,519 DEBUG - i/o-0000000C << Increment 1208
2019-02-07 16:17:17,519 DEBUG - i/o-0000000C >> stream 0 flow control 1208 -> 65535
2019-02-07 16:17:17,519 DEBUG - i/o-0000000C << stream 1 frame: WINDOW_UPDATE (0x8); flags: (0x0); length: 4
2019-02-07 16:17:17,519 DEBUG - i/o-0000000C << Increment 1208
2019-02-07 16:17:17,519 DEBUG - i/o-0000000C >> stream 1 flow control 1208 -> 65535
2019-02-07 16:17:17,569 DEBUG - i/o-0000000C << "[0x0][0x0][0x4][0x3][0x0][0x0][0x0][0x0][0x3][0x0][0x0][0x0][0x2]"
2019-02-07 16:17:17,569 DEBUG - i/o-0000000C << stream 3 frame: RST_STREAM (0x3); flags: (0x0); length: 4
2019-02-07 16:17:17,569 DEBUG - i/o-0000000C << Code INTERNAL_ERROR
2019-02-07 16:17:17,569 DEBUG - i/o-0000000C >> stream 0 frame: GOAWAY (0x7); flags: (0x0); length: 31
2019-02-07 16:17:17,569 DEBUG - i/o-0000000C >> Last stream 0
2019-02-07 16:17:17,569 DEBUG - i/o-0000000C >> Code PROTOCOL_ERROR
2019-02-07 16:17:17,569 DEBUG - i/o-0000000C >> Unexpected stream id: 3
I don't know what causes these exceptions I tried with both static and dynamic post body data and both behaves similarly
Full Session logs:
https://drive.google.com/open?id=12y8HnaMTrPo-NBeLaoCYpK6zklJBL56T
https://drive.google.com/open?id=16KHgqLWrwz3Z3ls3Yvpp58zOI3SUNATM
Client: Tomcat 9.0x, Jdk 1.8.x(with conscrypt for ALPN support, and we connect it via TLSv1.3) on ubuntu 16.x
Server: Tomcat 9.0x (with openssl implementation, NIO connector, http2 support), Openssl 1.1.1 for TLSv1.3 support, JDK 10.0.2 on ubuntu 14.x
Any help will be appreciated
TIA