From michael.hixson at gmail.com Tue Aug 8 09:10:18 2017 From: michael.hixson at gmail.com (Michael Hixson) Date: Tue, 8 Aug 2017 06:10:18 -0700 Subject: [undertow-dev] Writing tests for HTTP handlers Message-ID: Hello, I want to write junit tests for my application's HttpHandlers and I'm wondering what the best way to simulate a request/response exchange is. How do other people go about this? My first thought was that I want to somehow: 1) Build up a valid HttpServerExchange object to represent my incoming request (likely the HTTP method, request URI, HTTP headers, and request entity/body would vary from test to test) 2) Instantiate my HttpHandler directly, and invoke its handleRequest method directly 3) Obtain a CompletableFuture that will complete when the exchange completes (possibly by adding an io.undertow.server.ExchangeCompletionListener to my exchange) 4) Verify the contents of the response (possibly by examining the HttpServerExchange object and by using an io.undertow.conduits.StoredResponseStreamSinkConduit to record the response entity) This would all happen without creating an Undertow instance or binding to any ports. I started writing my own mock request/response library classes and they're getting complicated enough that I'd rather reuse someone else's work here if possible. Maybe I'm going down the wrong path... I could create an Undertow server instance and use something like a Jersey client to make actual HTTP requests. Is that what other people do in their tests? -Michael From tomaz.cerar at gmail.com Tue Aug 8 10:41:53 2017 From: tomaz.cerar at gmail.com (=?UTF-8?B?VG9tYcW+IENlcmFy?=) Date: Tue, 8 Aug 2017 16:41:53 +0200 Subject: [undertow-dev] Writing tests for HTTP handlers In-Reply-To: References: Message-ID: You could use DefaultServer junit runner for your tests. Same "framework" that undertow tests are written with. for example see https://github.com/undertow-io/undertow/blob/master/core/src/test/java/io/undertow/server/handlers/file/FileHandlerTestCase.java or pretty much any other test. -- tomaz On Tue, Aug 8, 2017 at 3:10 PM, Michael Hixson wrote: > Hello, > > I want to write junit tests for my application's HttpHandlers and I'm > wondering what the best way to simulate a request/response exchange > is. How do other people go about this? > > My first thought was that I want to somehow: > > 1) Build up a valid HttpServerExchange object to represent my incoming > request (likely the HTTP method, request URI, HTTP headers, and > request entity/body would vary from test to test) > > 2) Instantiate my HttpHandler directly, and invoke its handleRequest > method directly > > 3) Obtain a CompletableFuture that will complete when the exchange > completes (possibly by adding an > io.undertow.server.ExchangeCompletionListener to my exchange) > > 4) Verify the contents of the response (possibly by examining the > HttpServerExchange object and by using an > io.undertow.conduits.StoredResponseStreamSinkConduit to record the > response entity) > > This would all happen without creating an Undertow instance or binding > to any ports. > > I started writing my own mock request/response library classes and > they're getting complicated enough that I'd rather reuse someone > else's work here if possible. > > Maybe I'm going down the wrong path... I could create an Undertow > server instance and use something like a Jersey client to make actual > HTTP requests. Is that what other people do in their tests? > > -Michael > _______________________________________________ > undertow-dev mailing list > undertow-dev at lists.jboss.org > https://lists.jboss.org/mailman/listinfo/undertow-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://lists.jboss.org/pipermail/undertow-dev/attachments/20170808/53255012/attachment.html From sdouglas at redhat.com Tue Aug 8 18:58:32 2017 From: sdouglas at redhat.com (Stuart Douglas) Date: Wed, 9 Aug 2017 08:58:32 +1000 Subject: [undertow-dev] Writing tests for HTTP handlers In-Reply-To: References: Message-ID: Note that DefaultServer is not a supported API as it is part of the Undertow test suite, however it is unlikely to change much (I would actually recommend just copying the class and deleting what you don't need). I would definitely recommend testing by setting up a server and testing using real HTTP requests. The overhead should be minimal, and it makes the test much more realistic. Stuart On Wed, Aug 9, 2017 at 12:41 AM, Toma? Cerar wrote: > You could use DefaultServer junit runner for your tests. > > Same "framework" that undertow tests are written with. > > for example see > https://github.com/undertow-io/undertow/blob/master/core/src/test/java/io/undertow/server/handlers/file/FileHandlerTestCase.java > > or pretty much any other test. > > -- > tomaz > > > > On Tue, Aug 8, 2017 at 3:10 PM, Michael Hixson > wrote: >> >> Hello, >> >> I want to write junit tests for my application's HttpHandlers and I'm >> wondering what the best way to simulate a request/response exchange >> is. How do other people go about this? >> >> My first thought was that I want to somehow: >> >> 1) Build up a valid HttpServerExchange object to represent my incoming >> request (likely the HTTP method, request URI, HTTP headers, and >> request entity/body would vary from test to test) >> >> 2) Instantiate my HttpHandler directly, and invoke its handleRequest >> method directly >> >> 3) Obtain a CompletableFuture that will complete when the exchange >> completes (possibly by adding an >> io.undertow.server.ExchangeCompletionListener to my exchange) >> >> 4) Verify the contents of the response (possibly by examining the >> HttpServerExchange object and by using an >> io.undertow.conduits.StoredResponseStreamSinkConduit to record the >> response entity) >> >> This would all happen without creating an Undertow instance or binding >> to any ports. >> >> I started writing my own mock request/response library classes and >> they're getting complicated enough that I'd rather reuse someone >> else's work here if possible. >> >> Maybe I'm going down the wrong path... I could create an Undertow >> server instance and use something like a Jersey client to make actual >> HTTP requests. Is that what other people do in their tests? >> >> -Michael >> _______________________________________________ >> undertow-dev mailing list >> undertow-dev at lists.jboss.org >> https://lists.jboss.org/mailman/listinfo/undertow-dev > > > > _______________________________________________ > undertow-dev mailing list > undertow-dev at lists.jboss.org > https://lists.jboss.org/mailman/listinfo/undertow-dev From michael.hixson at gmail.com Tue Aug 8 22:45:03 2017 From: michael.hixson at gmail.com (Michael Hixson) Date: Tue, 8 Aug 2017 19:45:03 -0700 Subject: [undertow-dev] Writing tests for HTTP handlers In-Reply-To: References: Message-ID: Thank you both. I'll dig into DefaultServer and copy what I need. It helps to see that the Undertow tests on GitHub rely on a third-party library's request/response API. That makes a lot of sense, and I'm not sure why I thought it would be good idea to do anything else. -Michael On Tue, Aug 8, 2017 at 3:58 PM, Stuart Douglas wrote: > Note that DefaultServer is not a supported API as it is part of the > Undertow test suite, however it is unlikely to change much (I would > actually recommend just copying the class and deleting what you don't > need). > > I would definitely recommend testing by setting up a server and > testing using real HTTP requests. The overhead should be minimal, and > it makes the test much more realistic. > > Stuart > > On Wed, Aug 9, 2017 at 12:41 AM, Toma? Cerar wrote: >> You could use DefaultServer junit runner for your tests. >> >> Same "framework" that undertow tests are written with. >> >> for example see >> https://github.com/undertow-io/undertow/blob/master/core/src/test/java/io/undertow/server/handlers/file/FileHandlerTestCase.java >> >> or pretty much any other test. >> >> -- >> tomaz >> >> >> >> On Tue, Aug 8, 2017 at 3:10 PM, Michael Hixson >> wrote: >>> >>> Hello, >>> >>> I want to write junit tests for my application's HttpHandlers and I'm >>> wondering what the best way to simulate a request/response exchange >>> is. How do other people go about this? >>> >>> My first thought was that I want to somehow: >>> >>> 1) Build up a valid HttpServerExchange object to represent my incoming >>> request (likely the HTTP method, request URI, HTTP headers, and >>> request entity/body would vary from test to test) >>> >>> 2) Instantiate my HttpHandler directly, and invoke its handleRequest >>> method directly >>> >>> 3) Obtain a CompletableFuture that will complete when the exchange >>> completes (possibly by adding an >>> io.undertow.server.ExchangeCompletionListener to my exchange) >>> >>> 4) Verify the contents of the response (possibly by examining the >>> HttpServerExchange object and by using an >>> io.undertow.conduits.StoredResponseStreamSinkConduit to record the >>> response entity) >>> >>> This would all happen without creating an Undertow instance or binding >>> to any ports. >>> >>> I started writing my own mock request/response library classes and >>> they're getting complicated enough that I'd rather reuse someone >>> else's work here if possible. >>> >>> Maybe I'm going down the wrong path... I could create an Undertow >>> server instance and use something like a Jersey client to make actual >>> HTTP requests. Is that what other people do in their tests? >>> >>> -Michael >>> _______________________________________________ >>> undertow-dev mailing list >>> undertow-dev at lists.jboss.org >>> https://lists.jboss.org/mailman/listinfo/undertow-dev >> >> >> >> _______________________________________________ >> undertow-dev mailing list >> undertow-dev at lists.jboss.org >> https://lists.jboss.org/mailman/listinfo/undertow-dev From stevehu at gmail.com Mon Aug 28 21:25:57 2017 From: stevehu at gmail.com (Steve Hu) Date: Mon, 28 Aug 2017 21:25:57 -0400 Subject: [undertow-dev] Using UndertowClient from one server to call another server Message-ID: Hi, I am trying to use UndertowClient to call another service in the current service handleRequest using HTTP 2.0. If I have concurrent requests to the current service, then I will get the following error. java.io.IOException: UT001033: Invalid connection state at io.undertow.client.http.HttpClientConnection.sendRequest(HttpClientConnection.java:336) Since HTTP 2.0 connection is multiplex, so I use instance variables for UndertowClient instance and ClientConnection instance and don't close the connection for each call. My question is how many requests can go through the same connection? Is the Invalid connection state caused by too many requests in the same connection? If yes, I can use a connection pool just like the HTTP 1.1. Also, is it possible that the server will close the connection if it is idle for a period of time? Here is the handler code for reference. public class DataGetHandler implements HttpHandler { UndertowClient client = UndertowClient.getInstance(); ClientConnection connection; @Override public void handleRequest(HttpServerExchange exchange) throws Exception { List list = new ArrayList<>(); final CountDownLatch latch = new CountDownLatch(1); if(connection == null) { try { connection = client.connect(new URI(apidHost), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); } catch (Exception e) { logger.error("Exeption:", e); throw new ClientException(e); } } final AtomicReference reference = new AtomicReference<>(); try { ClientRequest request = new ClientRequest().setMethod(Methods.GET).setPath(apidPath); connection.sendRequest(request, client.createClientCallback(reference, latch)); latch.await(); int statusCode = reference.get().getResponseCode(); if(statusCode >= 300){ throw new Exception("Failed to call API D: " + statusCode); } List apidList = Config.getInstance().getMapper().readValue(reference.get().getAttachment(Http2Client.RESPONSE_BODY), new TypeReference>(){}); list.addAll(apidList); } catch (Exception e) { logger.error("Exception:", e); throw new ClientException(e); } list.add("API C: Message 1"); list.add("API C: Message 2"); exchange.getResponseSender().send(Config.getInstance().getMapper().writeValueAsString(list)); } } -------------- next part -------------- An HTML attachment was scrubbed... URL: http://lists.jboss.org/pipermail/undertow-dev/attachments/20170828/69e6f458/attachment.html From sdouglas at redhat.com Mon Aug 28 21:50:26 2017 From: sdouglas at redhat.com (Stuart Douglas) Date: Tue, 29 Aug 2017 11:50:26 +1000 Subject: [undertow-dev] Using UndertowClient from one server to call another server In-Reply-To: References: Message-ID: This looks like a bug in the client with regards to how it handles HTTP upgrade. If the second request is added before the initial upgrade request is fully processed you can get this error. If you file a JIRA I will look into it. For now a possible workaround would be to use prior knowledge rather than upgrade (by using a URL of the form h2c-prior://target:p8080/whatever). Stuart On Tue, Aug 29, 2017 at 11:25 AM, Steve Hu wrote: > Hi, > > I am trying to use UndertowClient to call another service in the current > service handleRequest using HTTP 2.0. If I have concurrent requests to the > current service, then I will get the following error. > > java.io.IOException: UT001033: Invalid connection state > at > io.undertow.client.http.HttpClientConnection.sendRequest(HttpClientConnection.java:336) > > Since HTTP 2.0 connection is multiplex, so I use instance variables for > UndertowClient instance and ClientConnection instance and don't close the > connection for each call. > > My question is how many requests can go through the same connection? Is the > Invalid connection state caused by too many requests in the same connection? > If yes, I can use a connection pool just like the HTTP 1.1. Also, is it > possible that the server will close the connection if it is idle for a > period of time? > > Here is the handler code for reference. > > public class DataGetHandler implements HttpHandler { > UndertowClient client = UndertowClient.getInstance(); > ClientConnection connection; > > @Override > public void handleRequest(HttpServerExchange exchange) throws Exception > { > List list = new ArrayList<>(); > final CountDownLatch latch = new CountDownLatch(1); > if(connection == null) { > try { > connection = client.connect(new URI(apidHost), > Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? > OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): > OptionMap.EMPTY).get(); > } catch (Exception e) { > logger.error("Exeption:", e); > throw new ClientException(e); > } > } > final AtomicReference reference = new > AtomicReference<>(); > try { > ClientRequest request = new > ClientRequest().setMethod(Methods.GET).setPath(apidPath); > connection.sendRequest(request, > client.createClientCallback(reference, latch)); > latch.await(); > int statusCode = reference.get().getResponseCode(); > if(statusCode >= 300){ > throw new Exception("Failed to call API D: " + statusCode); > } > List apidList = > Config.getInstance().getMapper().readValue(reference.get().getAttachment(Http2Client.RESPONSE_BODY), > new TypeReference>(){}); > list.addAll(apidList); > } catch (Exception e) { > logger.error("Exception:", e); > throw new ClientException(e); > } > list.add("API C: Message 1"); > list.add("API C: Message 2"); > > exchange.getResponseSender().send(Config.getInstance().getMapper().writeValueAsString(list)); > } > } > > > _______________________________________________ > undertow-dev mailing list > undertow-dev at lists.jboss.org > https://lists.jboss.org/mailman/listinfo/undertow-dev From stevehu at gmail.com Mon Aug 28 22:17:13 2017 From: stevehu at gmail.com (Steve Hu) Date: Mon, 28 Aug 2017 22:17:13 -0400 Subject: [undertow-dev] Using UndertowClient from one server to call another server In-Reply-To: References: Message-ID: Hi Stuart, Thanks for the quick reply. I have opened an issue https://issues.jboss.org/browse/UNDERTOW-1170 Also, I have tried your workaround with h2c-prior:// but got the following error in the callback. java.nio.channels.ClosedChannelException at io.undertow.protocols.http2.Http2Channel.createStream(Http2Channel.java:827) at io.undertow.client.http2.Http2ClientConnection.sendRequest(Http2ClientConnection.java:195) at com.networknt.apic.handler.DataGetHandler.handleRequest(DataGetHandler.java:57) On Mon, Aug 28, 2017 at 9:50 PM, Stuart Douglas wrote: > This looks like a bug in the client with regards to how it handles > HTTP upgrade. If the second request is added before the initial > upgrade request is fully processed you can get this error. > > If you file a JIRA I will look into it. For now a possible workaround > would be to use prior knowledge rather than upgrade (by using a URL of > the form h2c-prior://target:p8080/whatever). > > Stuart > > On Tue, Aug 29, 2017 at 11:25 AM, Steve Hu wrote: > > Hi, > > > > I am trying to use UndertowClient to call another service in the current > > service handleRequest using HTTP 2.0. If I have concurrent requests to > the > > current service, then I will get the following error. > > > > java.io.IOException: UT001033: Invalid connection state > > at > > io.undertow.client.http.HttpClientConnection.sendRequest( > HttpClientConnection.java:336) > > > > Since HTTP 2.0 connection is multiplex, so I use instance variables for > > UndertowClient instance and ClientConnection instance and don't close the > > connection for each call. > > > > My question is how many requests can go through the same connection? Is > the > > Invalid connection state caused by too many requests in the same > connection? > > If yes, I can use a connection pool just like the HTTP 1.1. Also, is it > > possible that the server will close the connection if it is idle for a > > period of time? > > > > Here is the handler code for reference. > > > > public class DataGetHandler implements HttpHandler { > > UndertowClient client = UndertowClient.getInstance(); > > ClientConnection connection; > > > > @Override > > public void handleRequest(HttpServerExchange exchange) throws > Exception > > { > > List list = new ArrayList<>(); > > final CountDownLatch latch = new CountDownLatch(1); > > if(connection == null) { > > try { > > connection = client.connect(new URI(apidHost), > > Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? > > OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): > > OptionMap.EMPTY).get(); > > } catch (Exception e) { > > logger.error("Exeption:", e); > > throw new ClientException(e); > > } > > } > > final AtomicReference reference = new > > AtomicReference<>(); > > try { > > ClientRequest request = new > > ClientRequest().setMethod(Methods.GET).setPath(apidPath); > > connection.sendRequest(request, > > client.createClientCallback(reference, latch)); > > latch.await(); > > int statusCode = reference.get().getResponseCode(); > > if(statusCode >= 300){ > > throw new Exception("Failed to call API D: " + > statusCode); > > } > > List apidList = > > Config.getInstance().getMapper().readValue( > reference.get().getAttachment(Http2Client.RESPONSE_BODY), > > new TypeReference>(){}); > > list.addAll(apidList); > > } catch (Exception e) { > > logger.error("Exception:", e); > > throw new ClientException(e); > > } > > list.add("API C: Message 1"); > > list.add("API C: Message 2"); > > > > exchange.getResponseSender().send(Config.getInstance().getMapper(). > writeValueAsString(list)); > > } > > } > > > > > > _______________________________________________ > > undertow-dev mailing list > > undertow-dev at lists.jboss.org > > https://lists.jboss.org/mailman/listinfo/undertow-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://lists.jboss.org/pipermail/undertow-dev/attachments/20170828/0a0b511f/attachment.html From sdouglas at redhat.com Mon Aug 28 22:43:51 2017 From: sdouglas at redhat.com (Stuart Douglas) Date: Tue, 29 Aug 2017 12:43:51 +1000 Subject: [undertow-dev] Using UndertowClient from one server to call another server In-Reply-To: References: Message-ID: What is the endpoint that you are trying to connect to? Is it another Undertow server? Stuart On Tue, Aug 29, 2017 at 12:17 PM, Steve Hu wrote: > Hi Stuart, > > Thanks for the quick reply. I have opened an issue > https://issues.jboss.org/browse/UNDERTOW-1170 > > Also, I have tried your workaround with h2c-prior:// but got the following > error in the callback. > > java.nio.channels.ClosedChannelException > at > io.undertow.protocols.http2.Http2Channel.createStream(Http2Channel.java:827) > at > io.undertow.client.http2.Http2ClientConnection.sendRequest(Http2ClientConnection.java:195) > at > com.networknt.apic.handler.DataGetHandler.handleRequest(DataGetHandler.java:57) > > > On Mon, Aug 28, 2017 at 9:50 PM, Stuart Douglas wrote: >> >> This looks like a bug in the client with regards to how it handles >> HTTP upgrade. If the second request is added before the initial >> upgrade request is fully processed you can get this error. >> >> If you file a JIRA I will look into it. For now a possible workaround >> would be to use prior knowledge rather than upgrade (by using a URL of >> the form h2c-prior://target:p8080/whatever). >> >> Stuart >> >> On Tue, Aug 29, 2017 at 11:25 AM, Steve Hu wrote: >> > Hi, >> > >> > I am trying to use UndertowClient to call another service in the current >> > service handleRequest using HTTP 2.0. If I have concurrent requests to >> > the >> > current service, then I will get the following error. >> > >> > java.io.IOException: UT001033: Invalid connection state >> > at >> > >> > io.undertow.client.http.HttpClientConnection.sendRequest(HttpClientConnection.java:336) >> > >> > Since HTTP 2.0 connection is multiplex, so I use instance variables for >> > UndertowClient instance and ClientConnection instance and don't close >> > the >> > connection for each call. >> > >> > My question is how many requests can go through the same connection? Is >> > the >> > Invalid connection state caused by too many requests in the same >> > connection? >> > If yes, I can use a connection pool just like the HTTP 1.1. Also, is it >> > possible that the server will close the connection if it is idle for a >> > period of time? >> > >> > Here is the handler code for reference. >> > >> > public class DataGetHandler implements HttpHandler { >> > UndertowClient client = UndertowClient.getInstance(); >> > ClientConnection connection; >> > >> > @Override >> > public void handleRequest(HttpServerExchange exchange) throws >> > Exception >> > { >> > List list = new ArrayList<>(); >> > final CountDownLatch latch = new CountDownLatch(1); >> > if(connection == null) { >> > try { >> > connection = client.connect(new URI(apidHost), >> > Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? >> > OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): >> > OptionMap.EMPTY).get(); >> > } catch (Exception e) { >> > logger.error("Exeption:", e); >> > throw new ClientException(e); >> > } >> > } >> > final AtomicReference reference = new >> > AtomicReference<>(); >> > try { >> > ClientRequest request = new >> > ClientRequest().setMethod(Methods.GET).setPath(apidPath); >> > connection.sendRequest(request, >> > client.createClientCallback(reference, latch)); >> > latch.await(); >> > int statusCode = reference.get().getResponseCode(); >> > if(statusCode >= 300){ >> > throw new Exception("Failed to call API D: " + >> > statusCode); >> > } >> > List apidList = >> > >> > Config.getInstance().getMapper().readValue(reference.get().getAttachment(Http2Client.RESPONSE_BODY), >> > new TypeReference>(){}); >> > list.addAll(apidList); >> > } catch (Exception e) { >> > logger.error("Exception:", e); >> > throw new ClientException(e); >> > } >> > list.add("API C: Message 1"); >> > list.add("API C: Message 2"); >> > >> > >> > exchange.getResponseSender().send(Config.getInstance().getMapper().writeValueAsString(list)); >> > } >> > } >> > >> > >> > _______________________________________________ >> > undertow-dev mailing list >> > undertow-dev at lists.jboss.org >> > https://lists.jboss.org/mailman/listinfo/undertow-dev > > From stevehu at gmail.com Mon Aug 28 22:59:41 2017 From: stevehu at gmail.com (Steve Hu) Date: Mon, 28 Aug 2017 22:59:41 -0400 Subject: [undertow-dev] Using UndertowClient from one server to call another server In-Reply-To: References: Message-ID: Yes. It is another Undertow server with HTTP 2.0 enabled. I can build a repo with two servers to reproduce the issue if it is necessary. Thanks, Steve On Mon, Aug 28, 2017 at 10:43 PM, Stuart Douglas wrote: > What is the endpoint that you are trying to connect to? Is it another > Undertow server? > > Stuart > > On Tue, Aug 29, 2017 at 12:17 PM, Steve Hu wrote: > > Hi Stuart, > > > > Thanks for the quick reply. I have opened an issue > > https://issues.jboss.org/browse/UNDERTOW-1170 > > > > Also, I have tried your workaround with h2c-prior:// but got the > following > > error in the callback. > > > > java.nio.channels.ClosedChannelException > > at > > io.undertow.protocols.http2.Http2Channel.createStream( > Http2Channel.java:827) > > at > > io.undertow.client.http2.Http2ClientConnection.sendRequest( > Http2ClientConnection.java:195) > > at > > com.networknt.apic.handler.DataGetHandler.handleRequest( > DataGetHandler.java:57) > > > > > > On Mon, Aug 28, 2017 at 9:50 PM, Stuart Douglas > wrote: > >> > >> This looks like a bug in the client with regards to how it handles > >> HTTP upgrade. If the second request is added before the initial > >> upgrade request is fully processed you can get this error. > >> > >> If you file a JIRA I will look into it. For now a possible workaround > >> would be to use prior knowledge rather than upgrade (by using a URL of > >> the form h2c-prior://target:p8080/whatever). > >> > >> Stuart > >> > >> On Tue, Aug 29, 2017 at 11:25 AM, Steve Hu wrote: > >> > Hi, > >> > > >> > I am trying to use UndertowClient to call another service in the > current > >> > service handleRequest using HTTP 2.0. If I have concurrent requests to > >> > the > >> > current service, then I will get the following error. > >> > > >> > java.io.IOException: UT001033: Invalid connection state > >> > at > >> > > >> > io.undertow.client.http.HttpClientConnection.sendRequest( > HttpClientConnection.java:336) > >> > > >> > Since HTTP 2.0 connection is multiplex, so I use instance variables > for > >> > UndertowClient instance and ClientConnection instance and don't close > >> > the > >> > connection for each call. > >> > > >> > My question is how many requests can go through the same connection? > Is > >> > the > >> > Invalid connection state caused by too many requests in the same > >> > connection? > >> > If yes, I can use a connection pool just like the HTTP 1.1. Also, is > it > >> > possible that the server will close the connection if it is idle for a > >> > period of time? > >> > > >> > Here is the handler code for reference. > >> > > >> > public class DataGetHandler implements HttpHandler { > >> > UndertowClient client = UndertowClient.getInstance(); > >> > ClientConnection connection; > >> > > >> > @Override > >> > public void handleRequest(HttpServerExchange exchange) throws > >> > Exception > >> > { > >> > List list = new ArrayList<>(); > >> > final CountDownLatch latch = new CountDownLatch(1); > >> > if(connection == null) { > >> > try { > >> > connection = client.connect(new URI(apidHost), > >> > Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? > >> > OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): > >> > OptionMap.EMPTY).get(); > >> > } catch (Exception e) { > >> > logger.error("Exeption:", e); > >> > throw new ClientException(e); > >> > } > >> > } > >> > final AtomicReference reference = new > >> > AtomicReference<>(); > >> > try { > >> > ClientRequest request = new > >> > ClientRequest().setMethod(Methods.GET).setPath(apidPath); > >> > connection.sendRequest(request, > >> > client.createClientCallback(reference, latch)); > >> > latch.await(); > >> > int statusCode = reference.get().getResponseCode(); > >> > if(statusCode >= 300){ > >> > throw new Exception("Failed to call API D: " + > >> > statusCode); > >> > } > >> > List apidList = > >> > > >> > Config.getInstance().getMapper().readValue( > reference.get().getAttachment(Http2Client.RESPONSE_BODY), > >> > new TypeReference>(){}); > >> > list.addAll(apidList); > >> > } catch (Exception e) { > >> > logger.error("Exception:", e); > >> > throw new ClientException(e); > >> > } > >> > list.add("API C: Message 1"); > >> > list.add("API C: Message 2"); > >> > > >> > > >> > exchange.getResponseSender().send(Config.getInstance().getMapper(). > writeValueAsString(list)); > >> > } > >> > } > >> > > >> > > >> > _______________________________________________ > >> > undertow-dev mailing list > >> > undertow-dev at lists.jboss.org > >> > https://lists.jboss.org/mailman/listinfo/undertow-dev > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://lists.jboss.org/pipermail/undertow-dev/attachments/20170828/cfca2185/attachment.html From sdouglas at redhat.com Mon Aug 28 23:01:18 2017 From: sdouglas at redhat.com (Stuart Douglas) Date: Tue, 29 Aug 2017 13:01:18 +1000 Subject: [undertow-dev] Using UndertowClient from one server to call another server In-Reply-To: References: Message-ID: That would be great. This is tested in the test suite so I am not sure why it is not working for you. Stuart On 29 Aug. 2017 12:59 pm, "Steve Hu" wrote: Yes. It is another Undertow server with HTTP 2.0 enabled. I can build a repo with two servers to reproduce the issue if it is necessary. Thanks, Steve On Mon, Aug 28, 2017 at 10:43 PM, Stuart Douglas wrote: > What is the endpoint that you are trying to connect to? Is it another > Undertow server? > > Stuart > > On Tue, Aug 29, 2017 at 12:17 PM, Steve Hu wrote: > > Hi Stuart, > > > > Thanks for the quick reply. I have opened an issue > > https://issues.jboss.org/browse/UNDERTOW-1170 > > > > Also, I have tried your workaround with h2c-prior:// but got the > following > > error in the callback. > > > > java.nio.channels.ClosedChannelException > > at > > io.undertow.protocols.http2.Http2Channel.createStream(Http2C > hannel.java:827) > > at > > io.undertow.client.http2.Http2ClientConnection.sendRequest(H > ttp2ClientConnection.java:195) > > at > > com.networknt.apic.handler.DataGetHandler.handleRequest(Data > GetHandler.java:57) > > > > > > On Mon, Aug 28, 2017 at 9:50 PM, Stuart Douglas > wrote: > >> > >> This looks like a bug in the client with regards to how it handles > >> HTTP upgrade. If the second request is added before the initial > >> upgrade request is fully processed you can get this error. > >> > >> If you file a JIRA I will look into it. For now a possible workaround > >> would be to use prior knowledge rather than upgrade (by using a URL of > >> the form h2c-prior://target:p8080/whatever). > >> > >> Stuart > >> > >> On Tue, Aug 29, 2017 at 11:25 AM, Steve Hu wrote: > >> > Hi, > >> > > >> > I am trying to use UndertowClient to call another service in the > current > >> > service handleRequest using HTTP 2.0. If I have concurrent requests to > >> > the > >> > current service, then I will get the following error. > >> > > >> > java.io.IOException: UT001033: Invalid connection state > >> > at > >> > > >> > io.undertow.client.http.HttpClientConnection.sendRequest(Htt > pClientConnection.java:336) > >> > > >> > Since HTTP 2.0 connection is multiplex, so I use instance variables > for > >> > UndertowClient instance and ClientConnection instance and don't close > >> > the > >> > connection for each call. > >> > > >> > My question is how many requests can go through the same connection? > Is > >> > the > >> > Invalid connection state caused by too many requests in the same > >> > connection? > >> > If yes, I can use a connection pool just like the HTTP 1.1. Also, is > it > >> > possible that the server will close the connection if it is idle for a > >> > period of time? > >> > > >> > Here is the handler code for reference. > >> > > >> > public class DataGetHandler implements HttpHandler { > >> > UndertowClient client = UndertowClient.getInstance(); > >> > ClientConnection connection; > >> > > >> > @Override > >> > public void handleRequest(HttpServerExchange exchange) throws > >> > Exception > >> > { > >> > List list = new ArrayList<>(); > >> > final CountDownLatch latch = new CountDownLatch(1); > >> > if(connection == null) { > >> > try { > >> > connection = client.connect(new URI(apidHost), > >> > Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? > >> > OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): > >> > OptionMap.EMPTY).get(); > >> > } catch (Exception e) { > >> > logger.error("Exeption:", e); > >> > throw new ClientException(e); > >> > } > >> > } > >> > final AtomicReference reference = new > >> > AtomicReference<>(); > >> > try { > >> > ClientRequest request = new > >> > ClientRequest().setMethod(Methods.GET).setPath(apidPath); > >> > connection.sendRequest(request, > >> > client.createClientCallback(reference, latch)); > >> > latch.await(); > >> > int statusCode = reference.get().getResponseCode(); > >> > if(statusCode >= 300){ > >> > throw new Exception("Failed to call API D: " + > >> > statusCode); > >> > } > >> > List apidList = > >> > > >> > Config.getInstance().getMapper().readValue(reference.get(). > getAttachment(Http2Client.RESPONSE_BODY), > >> > new TypeReference>(){}); > >> > list.addAll(apidList); > >> > } catch (Exception e) { > >> > logger.error("Exception:", e); > >> > throw new ClientException(e); > >> > } > >> > list.add("API C: Message 1"); > >> > list.add("API C: Message 2"); > >> > > >> > > >> > exchange.getResponseSender().send(Config.getInstance().getMa > pper().writeValueAsString(list)); > >> > } > >> > } > >> > > >> > > >> > _______________________________________________ > >> > undertow-dev mailing list > >> > undertow-dev at lists.jboss.org > >> > https://lists.jboss.org/mailman/listinfo/undertow-dev > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://lists.jboss.org/pipermail/undertow-dev/attachments/20170829/decbfc93/attachment-0001.html From stevehu at gmail.com Tue Aug 29 19:24:51 2017 From: stevehu at gmail.com (Steve Hu) Date: Tue, 29 Aug 2017 19:24:51 -0400 Subject: [undertow-dev] Using UndertowClient from one server to call another server In-Reply-To: References: Message-ID: Hi Stuart, I have created two servers with one calls another with h2c-prior to reproduce the issue. There is a README.md in the root folder with instructions. https://github.com/stevehu/server2server Thanks, Steve On Mon, Aug 28, 2017 at 11:01 PM, Stuart Douglas wrote: > That would be great. This is tested in the test suite so I am not sure why > it is not working for you. > > Stuart > > On 29 Aug. 2017 12:59 pm, "Steve Hu" wrote: > > Yes. It is another Undertow server with HTTP 2.0 enabled. I can build a > repo with two servers to reproduce the issue if it is necessary. > > Thanks, > > Steve > > On Mon, Aug 28, 2017 at 10:43 PM, Stuart Douglas > wrote: > >> What is the endpoint that you are trying to connect to? Is it another >> Undertow server? >> >> Stuart >> >> On Tue, Aug 29, 2017 at 12:17 PM, Steve Hu wrote: >> > Hi Stuart, >> > >> > Thanks for the quick reply. I have opened an issue >> > https://issues.jboss.org/browse/UNDERTOW-1170 >> > >> > Also, I have tried your workaround with h2c-prior:// but got the >> following >> > error in the callback. >> > >> > java.nio.channels.ClosedChannelException >> > at >> > io.undertow.protocols.http2.Http2Channel.createStream(Http2C >> hannel.java:827) >> > at >> > io.undertow.client.http2.Http2ClientConnection.sendRequest(H >> ttp2ClientConnection.java:195) >> > at >> > com.networknt.apic.handler.DataGetHandler.handleRequest(Data >> GetHandler.java:57) >> > >> > >> > On Mon, Aug 28, 2017 at 9:50 PM, Stuart Douglas >> wrote: >> >> >> >> This looks like a bug in the client with regards to how it handles >> >> HTTP upgrade. If the second request is added before the initial >> >> upgrade request is fully processed you can get this error. >> >> >> >> If you file a JIRA I will look into it. For now a possible workaround >> >> would be to use prior knowledge rather than upgrade (by using a URL of >> >> the form h2c-prior://target:p8080/whatever). >> >> >> >> Stuart >> >> >> >> On Tue, Aug 29, 2017 at 11:25 AM, Steve Hu wrote: >> >> > Hi, >> >> > >> >> > I am trying to use UndertowClient to call another service in the >> current >> >> > service handleRequest using HTTP 2.0. If I have concurrent requests >> to >> >> > the >> >> > current service, then I will get the following error. >> >> > >> >> > java.io.IOException: UT001033: Invalid connection state >> >> > at >> >> > >> >> > io.undertow.client.http.HttpClientConnection.sendRequest(Htt >> pClientConnection.java:336) >> >> > >> >> > Since HTTP 2.0 connection is multiplex, so I use instance variables >> for >> >> > UndertowClient instance and ClientConnection instance and don't close >> >> > the >> >> > connection for each call. >> >> > >> >> > My question is how many requests can go through the same connection? >> Is >> >> > the >> >> > Invalid connection state caused by too many requests in the same >> >> > connection? >> >> > If yes, I can use a connection pool just like the HTTP 1.1. Also, is >> it >> >> > possible that the server will close the connection if it is idle for >> a >> >> > period of time? >> >> > >> >> > Here is the handler code for reference. >> >> > >> >> > public class DataGetHandler implements HttpHandler { >> >> > UndertowClient client = UndertowClient.getInstance(); >> >> > ClientConnection connection; >> >> > >> >> > @Override >> >> > public void handleRequest(HttpServerExchange exchange) throws >> >> > Exception >> >> > { >> >> > List list = new ArrayList<>(); >> >> > final CountDownLatch latch = new CountDownLatch(1); >> >> > if(connection == null) { >> >> > try { >> >> > connection = client.connect(new URI(apidHost), >> >> > Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? >> >> > OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): >> >> > OptionMap.EMPTY).get(); >> >> > } catch (Exception e) { >> >> > logger.error("Exeption:", e); >> >> > throw new ClientException(e); >> >> > } >> >> > } >> >> > final AtomicReference reference = new >> >> > AtomicReference<>(); >> >> > try { >> >> > ClientRequest request = new >> >> > ClientRequest().setMethod(Methods.GET).setPath(apidPath); >> >> > connection.sendRequest(request, >> >> > client.createClientCallback(reference, latch)); >> >> > latch.await(); >> >> > int statusCode = reference.get().getResponseCode(); >> >> > if(statusCode >= 300){ >> >> > throw new Exception("Failed to call API D: " + >> >> > statusCode); >> >> > } >> >> > List apidList = >> >> > >> >> > Config.getInstance().getMapper().readValue(reference.get().g >> etAttachment(Http2Client.RESPONSE_BODY), >> >> > new TypeReference>(){}); >> >> > list.addAll(apidList); >> >> > } catch (Exception e) { >> >> > logger.error("Exception:", e); >> >> > throw new ClientException(e); >> >> > } >> >> > list.add("API C: Message 1"); >> >> > list.add("API C: Message 2"); >> >> > >> >> > >> >> > exchange.getResponseSender().send(Config.getInstance().getMa >> pper().writeValueAsString(list)); >> >> > } >> >> > } >> >> > >> >> > >> >> > _______________________________________________ >> >> > undertow-dev mailing list >> >> > undertow-dev at lists.jboss.org >> >> > https://lists.jboss.org/mailman/listinfo/undertow-dev >> > >> > >> > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://lists.jboss.org/pipermail/undertow-dev/attachments/20170829/8b97a975/attachment.html From sdouglas at redhat.com Tue Aug 29 19:37:46 2017 From: sdouglas at redhat.com (Stuart Douglas) Date: Wed, 30 Aug 2017 09:37:46 +1000 Subject: [undertow-dev] Using UndertowClient from one server to call another server In-Reply-To: References: Message-ID: The issue is that you are attempting to use prior knowledge to connect to a https endpoint. HTTPS endpoints must use ALPN instead. I did not notice you were attempting to use HTTPS in the original issue. The code should not attempt an upgrade in this case. Is it possible that ALPN is failing so normal HTTP/1 is used instead, then the server closes the connection so your request fails due to the connection being closed? Stuart On Wed, Aug 30, 2017 at 9:24 AM, Steve Hu wrote: > Hi Stuart, > > I have created two servers with one calls another with h2c-prior to > reproduce the issue. There is a README.md in the root folder with > instructions. > > https://github.com/stevehu/server2server > > Thanks, > > Steve > > On Mon, Aug 28, 2017 at 11:01 PM, Stuart Douglas > wrote: >> >> That would be great. This is tested in the test suite so I am not sure why >> it is not working for you. >> >> Stuart >> >> On 29 Aug. 2017 12:59 pm, "Steve Hu" wrote: >> >> Yes. It is another Undertow server with HTTP 2.0 enabled. I can build a >> repo with two servers to reproduce the issue if it is necessary. >> >> Thanks, >> >> Steve >> >> On Mon, Aug 28, 2017 at 10:43 PM, Stuart Douglas >> wrote: >>> >>> What is the endpoint that you are trying to connect to? Is it another >>> Undertow server? >>> >>> Stuart >>> >>> On Tue, Aug 29, 2017 at 12:17 PM, Steve Hu wrote: >>> > Hi Stuart, >>> > >>> > Thanks for the quick reply. I have opened an issue >>> > https://issues.jboss.org/browse/UNDERTOW-1170 >>> > >>> > Also, I have tried your workaround with h2c-prior:// but got the >>> > following >>> > error in the callback. >>> > >>> > java.nio.channels.ClosedChannelException >>> > at >>> > >>> > io.undertow.protocols.http2.Http2Channel.createStream(Http2Channel.java:827) >>> > at >>> > >>> > io.undertow.client.http2.Http2ClientConnection.sendRequest(Http2ClientConnection.java:195) >>> > at >>> > >>> > com.networknt.apic.handler.DataGetHandler.handleRequest(DataGetHandler.java:57) >>> > >>> > >>> > On Mon, Aug 28, 2017 at 9:50 PM, Stuart Douglas >>> > wrote: >>> >> >>> >> This looks like a bug in the client with regards to how it handles >>> >> HTTP upgrade. If the second request is added before the initial >>> >> upgrade request is fully processed you can get this error. >>> >> >>> >> If you file a JIRA I will look into it. For now a possible workaround >>> >> would be to use prior knowledge rather than upgrade (by using a URL of >>> >> the form h2c-prior://target:p8080/whatever). >>> >> >>> >> Stuart >>> >> >>> >> On Tue, Aug 29, 2017 at 11:25 AM, Steve Hu wrote: >>> >> > Hi, >>> >> > >>> >> > I am trying to use UndertowClient to call another service in the >>> >> > current >>> >> > service handleRequest using HTTP 2.0. If I have concurrent requests >>> >> > to >>> >> > the >>> >> > current service, then I will get the following error. >>> >> > >>> >> > java.io.IOException: UT001033: Invalid connection state >>> >> > at >>> >> > >>> >> > >>> >> > io.undertow.client.http.HttpClientConnection.sendRequest(HttpClientConnection.java:336) >>> >> > >>> >> > Since HTTP 2.0 connection is multiplex, so I use instance variables >>> >> > for >>> >> > UndertowClient instance and ClientConnection instance and don't >>> >> > close >>> >> > the >>> >> > connection for each call. >>> >> > >>> >> > My question is how many requests can go through the same connection? >>> >> > Is >>> >> > the >>> >> > Invalid connection state caused by too many requests in the same >>> >> > connection? >>> >> > If yes, I can use a connection pool just like the HTTP 1.1. Also, is >>> >> > it >>> >> > possible that the server will close the connection if it is idle for >>> >> > a >>> >> > period of time? >>> >> > >>> >> > Here is the handler code for reference. >>> >> > >>> >> > public class DataGetHandler implements HttpHandler { >>> >> > UndertowClient client = UndertowClient.getInstance(); >>> >> > ClientConnection connection; >>> >> > >>> >> > @Override >>> >> > public void handleRequest(HttpServerExchange exchange) throws >>> >> > Exception >>> >> > { >>> >> > List list = new ArrayList<>(); >>> >> > final CountDownLatch latch = new CountDownLatch(1); >>> >> > if(connection == null) { >>> >> > try { >>> >> > connection = client.connect(new URI(apidHost), >>> >> > Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? >>> >> > OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): >>> >> > OptionMap.EMPTY).get(); >>> >> > } catch (Exception e) { >>> >> > logger.error("Exeption:", e); >>> >> > throw new ClientException(e); >>> >> > } >>> >> > } >>> >> > final AtomicReference reference = new >>> >> > AtomicReference<>(); >>> >> > try { >>> >> > ClientRequest request = new >>> >> > ClientRequest().setMethod(Methods.GET).setPath(apidPath); >>> >> > connection.sendRequest(request, >>> >> > client.createClientCallback(reference, latch)); >>> >> > latch.await(); >>> >> > int statusCode = reference.get().getResponseCode(); >>> >> > if(statusCode >= 300){ >>> >> > throw new Exception("Failed to call API D: " + >>> >> > statusCode); >>> >> > } >>> >> > List apidList = >>> >> > >>> >> > >>> >> > Config.getInstance().getMapper().readValue(reference.get().getAttachment(Http2Client.RESPONSE_BODY), >>> >> > new TypeReference>(){}); >>> >> > list.addAll(apidList); >>> >> > } catch (Exception e) { >>> >> > logger.error("Exception:", e); >>> >> > throw new ClientException(e); >>> >> > } >>> >> > list.add("API C: Message 1"); >>> >> > list.add("API C: Message 2"); >>> >> > >>> >> > >>> >> > >>> >> > exchange.getResponseSender().send(Config.getInstance().getMapper().writeValueAsString(list)); >>> >> > } >>> >> > } >>> >> > >>> >> > >>> >> > _______________________________________________ >>> >> > undertow-dev mailing list >>> >> > undertow-dev at lists.jboss.org >>> >> > https://lists.jboss.org/mailman/listinfo/undertow-dev >>> > >>> > >> >> >> > From stevehu at gmail.com Tue Aug 29 19:53:30 2017 From: stevehu at gmail.com (Steve Hu) Date: Tue, 29 Aug 2017 19:53:30 -0400 Subject: [undertow-dev] Using UndertowClient from one server to call another server In-Reply-To: References: Message-ID: I've been using https all the time. Let me add a debug statement to check the response protocol to ensure that http2 is used all the time. Thanks for pointing to the right direction. Although HTTP2.0 supports multiplex, do you think it would be problem if too many concurrent requests go through the same connection? Should I create a connection poll to split the load to multiple connections like HTTP 1.1? On Tue, Aug 29, 2017 at 7:37 PM, Stuart Douglas wrote: > The issue is that you are attempting to use prior knowledge to connect > to a https endpoint. HTTPS endpoints must use ALPN instead. > > I did not notice you were attempting to use HTTPS in the original > issue. The code should not attempt an upgrade in this case. Is it > possible that ALPN is failing so normal HTTP/1 is used instead, then > the server closes the connection so your request fails due to the > connection being closed? > > Stuart > > On Wed, Aug 30, 2017 at 9:24 AM, Steve Hu wrote: > > Hi Stuart, > > > > I have created two servers with one calls another with h2c-prior to > > reproduce the issue. There is a README.md in the root folder with > > instructions. > > > > https://github.com/stevehu/server2server > > > > Thanks, > > > > Steve > > > > On Mon, Aug 28, 2017 at 11:01 PM, Stuart Douglas > > wrote: > >> > >> That would be great. This is tested in the test suite so I am not sure > why > >> it is not working for you. > >> > >> Stuart > >> > >> On 29 Aug. 2017 12:59 pm, "Steve Hu" wrote: > >> > >> Yes. It is another Undertow server with HTTP 2.0 enabled. I can build a > >> repo with two servers to reproduce the issue if it is necessary. > >> > >> Thanks, > >> > >> Steve > >> > >> On Mon, Aug 28, 2017 at 10:43 PM, Stuart Douglas > >> wrote: > >>> > >>> What is the endpoint that you are trying to connect to? Is it another > >>> Undertow server? > >>> > >>> Stuart > >>> > >>> On Tue, Aug 29, 2017 at 12:17 PM, Steve Hu wrote: > >>> > Hi Stuart, > >>> > > >>> > Thanks for the quick reply. I have opened an issue > >>> > https://issues.jboss.org/browse/UNDERTOW-1170 > >>> > > >>> > Also, I have tried your workaround with h2c-prior:// but got the > >>> > following > >>> > error in the callback. > >>> > > >>> > java.nio.channels.ClosedChannelException > >>> > at > >>> > > >>> > io.undertow.protocols.http2.Http2Channel.createStream( > Http2Channel.java:827) > >>> > at > >>> > > >>> > io.undertow.client.http2.Http2ClientConnection.sendRequest( > Http2ClientConnection.java:195) > >>> > at > >>> > > >>> > com.networknt.apic.handler.DataGetHandler.handleRequest( > DataGetHandler.java:57) > >>> > > >>> > > >>> > On Mon, Aug 28, 2017 at 9:50 PM, Stuart Douglas > > >>> > wrote: > >>> >> > >>> >> This looks like a bug in the client with regards to how it handles > >>> >> HTTP upgrade. If the second request is added before the initial > >>> >> upgrade request is fully processed you can get this error. > >>> >> > >>> >> If you file a JIRA I will look into it. For now a possible > workaround > >>> >> would be to use prior knowledge rather than upgrade (by using a URL > of > >>> >> the form h2c-prior://target:p8080/whatever). > >>> >> > >>> >> Stuart > >>> >> > >>> >> On Tue, Aug 29, 2017 at 11:25 AM, Steve Hu > wrote: > >>> >> > Hi, > >>> >> > > >>> >> > I am trying to use UndertowClient to call another service in the > >>> >> > current > >>> >> > service handleRequest using HTTP 2.0. If I have concurrent > requests > >>> >> > to > >>> >> > the > >>> >> > current service, then I will get the following error. > >>> >> > > >>> >> > java.io.IOException: UT001033: Invalid connection state > >>> >> > at > >>> >> > > >>> >> > > >>> >> > io.undertow.client.http.HttpClientConnection.sendRequest( > HttpClientConnection.java:336) > >>> >> > > >>> >> > Since HTTP 2.0 connection is multiplex, so I use instance > variables > >>> >> > for > >>> >> > UndertowClient instance and ClientConnection instance and don't > >>> >> > close > >>> >> > the > >>> >> > connection for each call. > >>> >> > > >>> >> > My question is how many requests can go through the same > connection? > >>> >> > Is > >>> >> > the > >>> >> > Invalid connection state caused by too many requests in the same > >>> >> > connection? > >>> >> > If yes, I can use a connection pool just like the HTTP 1.1. Also, > is > >>> >> > it > >>> >> > possible that the server will close the connection if it is idle > for > >>> >> > a > >>> >> > period of time? > >>> >> > > >>> >> > Here is the handler code for reference. > >>> >> > > >>> >> > public class DataGetHandler implements HttpHandler { > >>> >> > UndertowClient client = UndertowClient.getInstance(); > >>> >> > ClientConnection connection; > >>> >> > > >>> >> > @Override > >>> >> > public void handleRequest(HttpServerExchange exchange) throws > >>> >> > Exception > >>> >> > { > >>> >> > List list = new ArrayList<>(); > >>> >> > final CountDownLatch latch = new CountDownLatch(1); > >>> >> > if(connection == null) { > >>> >> > try { > >>> >> > connection = client.connect(new URI(apidHost), > >>> >> > Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, > enableHttp2 ? > >>> >> > OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): > >>> >> > OptionMap.EMPTY).get(); > >>> >> > } catch (Exception e) { > >>> >> > logger.error("Exeption:", e); > >>> >> > throw new ClientException(e); > >>> >> > } > >>> >> > } > >>> >> > final AtomicReference reference = new > >>> >> > AtomicReference<>(); > >>> >> > try { > >>> >> > ClientRequest request = new > >>> >> > ClientRequest().setMethod(Methods.GET).setPath(apidPath); > >>> >> > connection.sendRequest(request, > >>> >> > client.createClientCallback(reference, latch)); > >>> >> > latch.await(); > >>> >> > int statusCode = reference.get().getResponseCode(); > >>> >> > if(statusCode >= 300){ > >>> >> > throw new Exception("Failed to call API D: " + > >>> >> > statusCode); > >>> >> > } > >>> >> > List apidList = > >>> >> > > >>> >> > > >>> >> > Config.getInstance().getMapper().readValue( > reference.get().getAttachment(Http2Client.RESPONSE_BODY), > >>> >> > new TypeReference>(){}); > >>> >> > list.addAll(apidList); > >>> >> > } catch (Exception e) { > >>> >> > logger.error("Exception:", e); > >>> >> > throw new ClientException(e); > >>> >> > } > >>> >> > list.add("API C: Message 1"); > >>> >> > list.add("API C: Message 2"); > >>> >> > > >>> >> > > >>> >> > > >>> >> > exchange.getResponseSender().send(Config.getInstance(). > getMapper().writeValueAsString(list)); > >>> >> > } > >>> >> > } > >>> >> > > >>> >> > > >>> >> > _______________________________________________ > >>> >> > undertow-dev mailing list > >>> >> > undertow-dev at lists.jboss.org > >>> >> > https://lists.jboss.org/mailman/listinfo/undertow-dev > >>> > > >>> > > >> > >> > >> > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://lists.jboss.org/pipermail/undertow-dev/attachments/20170829/60b604eb/attachment-0001.html From sdouglas at redhat.com Tue Aug 29 20:01:14 2017 From: sdouglas at redhat.com (Stuart Douglas) Date: Wed, 30 Aug 2017 10:01:14 +1000 Subject: [undertow-dev] Using UndertowClient from one server to call another server In-Reply-To: References: Message-ID: It should be ok, just make sure you have set the max concurrent streams high enough, with that said though you will probably get better performance with a connection pool. If you have a single connection that will be serviced by a single IO thread, and will be limited by the speed that it can send over the TCP connection. I am not sure how much difference it will make in your environment, but in some situations it can make a huge difference. Stuart On Wed, Aug 30, 2017 at 9:53 AM, Steve Hu wrote: > I've been using https all the time. Let me add a debug statement to check > the response protocol to ensure that http2 is used all the time. Thanks for > pointing to the right direction. > > Although HTTP2.0 supports multiplex, do you think it would be problem if too > many concurrent requests go through the same connection? Should I create a > connection poll to split the load to multiple connections like HTTP 1.1? > > > On Tue, Aug 29, 2017 at 7:37 PM, Stuart Douglas wrote: >> >> The issue is that you are attempting to use prior knowledge to connect >> to a https endpoint. HTTPS endpoints must use ALPN instead. >> >> I did not notice you were attempting to use HTTPS in the original >> issue. The code should not attempt an upgrade in this case. Is it >> possible that ALPN is failing so normal HTTP/1 is used instead, then >> the server closes the connection so your request fails due to the >> connection being closed? >> >> Stuart >> >> On Wed, Aug 30, 2017 at 9:24 AM, Steve Hu wrote: >> > Hi Stuart, >> > >> > I have created two servers with one calls another with h2c-prior to >> > reproduce the issue. There is a README.md in the root folder with >> > instructions. >> > >> > https://github.com/stevehu/server2server >> > >> > Thanks, >> > >> > Steve >> > >> > On Mon, Aug 28, 2017 at 11:01 PM, Stuart Douglas >> > wrote: >> >> >> >> That would be great. This is tested in the test suite so I am not sure >> >> why >> >> it is not working for you. >> >> >> >> Stuart >> >> >> >> On 29 Aug. 2017 12:59 pm, "Steve Hu" wrote: >> >> >> >> Yes. It is another Undertow server with HTTP 2.0 enabled. I can build a >> >> repo with two servers to reproduce the issue if it is necessary. >> >> >> >> Thanks, >> >> >> >> Steve >> >> >> >> On Mon, Aug 28, 2017 at 10:43 PM, Stuart Douglas >> >> wrote: >> >>> >> >>> What is the endpoint that you are trying to connect to? Is it another >> >>> Undertow server? >> >>> >> >>> Stuart >> >>> >> >>> On Tue, Aug 29, 2017 at 12:17 PM, Steve Hu wrote: >> >>> > Hi Stuart, >> >>> > >> >>> > Thanks for the quick reply. I have opened an issue >> >>> > https://issues.jboss.org/browse/UNDERTOW-1170 >> >>> > >> >>> > Also, I have tried your workaround with h2c-prior:// but got the >> >>> > following >> >>> > error in the callback. >> >>> > >> >>> > java.nio.channels.ClosedChannelException >> >>> > at >> >>> > >> >>> > >> >>> > io.undertow.protocols.http2.Http2Channel.createStream(Http2Channel.java:827) >> >>> > at >> >>> > >> >>> > >> >>> > io.undertow.client.http2.Http2ClientConnection.sendRequest(Http2ClientConnection.java:195) >> >>> > at >> >>> > >> >>> > >> >>> > com.networknt.apic.handler.DataGetHandler.handleRequest(DataGetHandler.java:57) >> >>> > >> >>> > >> >>> > On Mon, Aug 28, 2017 at 9:50 PM, Stuart Douglas >> >>> > >> >>> > wrote: >> >>> >> >> >>> >> This looks like a bug in the client with regards to how it handles >> >>> >> HTTP upgrade. If the second request is added before the initial >> >>> >> upgrade request is fully processed you can get this error. >> >>> >> >> >>> >> If you file a JIRA I will look into it. For now a possible >> >>> >> workaround >> >>> >> would be to use prior knowledge rather than upgrade (by using a URL >> >>> >> of >> >>> >> the form h2c-prior://target:p8080/whatever). >> >>> >> >> >>> >> Stuart >> >>> >> >> >>> >> On Tue, Aug 29, 2017 at 11:25 AM, Steve Hu >> >>> >> wrote: >> >>> >> > Hi, >> >>> >> > >> >>> >> > I am trying to use UndertowClient to call another service in the >> >>> >> > current >> >>> >> > service handleRequest using HTTP 2.0. If I have concurrent >> >>> >> > requests >> >>> >> > to >> >>> >> > the >> >>> >> > current service, then I will get the following error. >> >>> >> > >> >>> >> > java.io.IOException: UT001033: Invalid connection state >> >>> >> > at >> >>> >> > >> >>> >> > >> >>> >> > >> >>> >> > io.undertow.client.http.HttpClientConnection.sendRequest(HttpClientConnection.java:336) >> >>> >> > >> >>> >> > Since HTTP 2.0 connection is multiplex, so I use instance >> >>> >> > variables >> >>> >> > for >> >>> >> > UndertowClient instance and ClientConnection instance and don't >> >>> >> > close >> >>> >> > the >> >>> >> > connection for each call. >> >>> >> > >> >>> >> > My question is how many requests can go through the same >> >>> >> > connection? >> >>> >> > Is >> >>> >> > the >> >>> >> > Invalid connection state caused by too many requests in the same >> >>> >> > connection? >> >>> >> > If yes, I can use a connection pool just like the HTTP 1.1. Also, >> >>> >> > is >> >>> >> > it >> >>> >> > possible that the server will close the connection if it is idle >> >>> >> > for >> >>> >> > a >> >>> >> > period of time? >> >>> >> > >> >>> >> > Here is the handler code for reference. >> >>> >> > >> >>> >> > public class DataGetHandler implements HttpHandler { >> >>> >> > UndertowClient client = UndertowClient.getInstance(); >> >>> >> > ClientConnection connection; >> >>> >> > >> >>> >> > @Override >> >>> >> > public void handleRequest(HttpServerExchange exchange) throws >> >>> >> > Exception >> >>> >> > { >> >>> >> > List list = new ArrayList<>(); >> >>> >> > final CountDownLatch latch = new CountDownLatch(1); >> >>> >> > if(connection == null) { >> >>> >> > try { >> >>> >> > connection = client.connect(new URI(apidHost), >> >>> >> > Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, >> >>> >> > enableHttp2 ? >> >>> >> > OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): >> >>> >> > OptionMap.EMPTY).get(); >> >>> >> > } catch (Exception e) { >> >>> >> > logger.error("Exeption:", e); >> >>> >> > throw new ClientException(e); >> >>> >> > } >> >>> >> > } >> >>> >> > final AtomicReference reference = new >> >>> >> > AtomicReference<>(); >> >>> >> > try { >> >>> >> > ClientRequest request = new >> >>> >> > ClientRequest().setMethod(Methods.GET).setPath(apidPath); >> >>> >> > connection.sendRequest(request, >> >>> >> > client.createClientCallback(reference, latch)); >> >>> >> > latch.await(); >> >>> >> > int statusCode = reference.get().getResponseCode(); >> >>> >> > if(statusCode >= 300){ >> >>> >> > throw new Exception("Failed to call API D: " + >> >>> >> > statusCode); >> >>> >> > } >> >>> >> > List apidList = >> >>> >> > >> >>> >> > >> >>> >> > >> >>> >> > Config.getInstance().getMapper().readValue(reference.get().getAttachment(Http2Client.RESPONSE_BODY), >> >>> >> > new TypeReference>(){}); >> >>> >> > list.addAll(apidList); >> >>> >> > } catch (Exception e) { >> >>> >> > logger.error("Exception:", e); >> >>> >> > throw new ClientException(e); >> >>> >> > } >> >>> >> > list.add("API C: Message 1"); >> >>> >> > list.add("API C: Message 2"); >> >>> >> > >> >>> >> > >> >>> >> > >> >>> >> > >> >>> >> > exchange.getResponseSender().send(Config.getInstance().getMapper().writeValueAsString(list)); >> >>> >> > } >> >>> >> > } >> >>> >> > >> >>> >> > >> >>> >> > _______________________________________________ >> >>> >> > undertow-dev mailing list >> >>> >> > undertow-dev at lists.jboss.org >> >>> >> > https://lists.jboss.org/mailman/listinfo/undertow-dev >> >>> > >> >>> > >> >> >> >> >> >> >> > > > From spamcmon at gmail.com Wed Aug 30 07:05:03 2017 From: spamcmon at gmail.com (Tester) Date: Wed, 30 Aug 2017 13:05:03 +0200 Subject: [undertow-dev] Fwd: Issue with Java 9 (Jigsaw) when using Undertow In-Reply-To: References: Message-ID: Hi, I'm using the Spring Boot starter for Undertow. The dependencies which are pulled in are: org.springframework.boot:spring-boot-starter-undertow:jar:2.0.0.M3:compile | +- io.undertow:undertow-core:jar:1.4.18.Final:compile | | +- org.jboss.xnio:xnio-api:jar:3.3.8.Final:compile | | \- org.jboss.xnio:xnio-nio:jar:3.3.8.Final:runtime | +- io.undertow:undertow-servlet:jar:1.4.18.Final:compile | | \- org.jboss.spec.javax.annotation:jboss-annotations- api_1.2_spec:jar:1.0.0.Final:compile | +- io.undertow:undertow-websockets-jsr:jar:1.4.18.Final:compile | | \- org.jboss.spec.javax.websocket:jboss-websocket-api_ 1.1_spec:jar:1.1.0.Final:compile | +- javax.servlet:javax.servlet-api:jar:3.1.0:compile | \- org.glassfish:javax.el:jar:3.0.0:compile Now, when I run the application through Java 9 (Release candidate) and I have a module-info.java (Jigsaw), then I get the following error: Error occurred during initialization of boot layer java.lang.module.FindException: Unable to derive module descriptor for C:\Users\xxxxx\.m2\repository\org\jboss\spec\javax\ annotation\jboss-annotations-api_1.2_spec\1.0.0.Final\ jboss-annotations-api_1.2_spec-1.0.0.Final.jar Caused by: java.lang.IllegalArgumentException: jboss.annotations.api.1.2.spec: Invalid module name: '1' is not a Java identifier It seems there is an issue with the determination of the naming of the automatic module. I expect to have the same issue for jboss-websocket-api_1.1_spec. The name of the jar file isn't aligned on the algorithm defined under ( http://download.java.net/java/jigsaw/docs/api/java/ lang/module/ModuleFinder.html). Is anyone aware of this issue? Is this something that can be resolved? -------------- next part -------------- An HTML attachment was scrubbed... URL: http://lists.jboss.org/pipermail/undertow-dev/attachments/20170830/c835b7c2/attachment.html From sdouglas at redhat.com Wed Aug 30 21:25:34 2017 From: sdouglas at redhat.com (Stuart Douglas) Date: Thu, 31 Aug 2017 11:25:34 +1000 Subject: [undertow-dev] Fwd: Issue with Java 9 (Jigsaw) when using Undertow In-Reply-To: References: Message-ID: It sounds like we need to add an Automatic-Module-Name entry to these jars manifests to specify the actual module name. Is there any chance you could modify the jar's to test this out? Stuart On Wed, Aug 30, 2017 at 9:05 PM, Tester wrote: > Hi, > > I'm using the Spring Boot starter for Undertow. The dependencies which are > pulled in are: > > org.springframework.boot:spring-boot-starter-undertow:jar:2.0.0.M3:compile > | +- io.undertow:undertow-core:jar:1.4.18.Final:compile > | | +- org.jboss.xnio:xnio-api:jar:3.3.8.Final:compile > | | \- org.jboss.xnio:xnio-nio:jar:3.3.8.Final:runtime > | +- io.undertow:undertow-servlet:jar:1.4.18.Final:compile > | | \- > org.jboss.spec.javax.annotation:jboss-annotations-api_1.2_spec:jar:1.0.0.Final:compile > | +- io.undertow:undertow-websockets-jsr:jar:1.4.18.Final:compile > | | \- > org.jboss.spec.javax.websocket:jboss-websocket-api_1.1_spec:jar:1.1.0.Final:compile > | +- javax.servlet:javax.servlet-api:jar:3.1.0:compile > | \- org.glassfish:javax.el:jar:3.0.0:compile > > Now, when I run the application through Java 9 (Release candidate) and I > have a module-info.java (Jigsaw), then I get the following error: > > Error occurred during initialization of boot layer > java.lang.module.FindException: Unable to derive module descriptor for > C:\Users\xxxxx\.m2\repository\org\jboss\spec\javax\annotation\jboss-annotations-api_1.2_spec\1.0.0.Final\jboss-annotations-api_1.2_spec-1.0.0.Final.jar > Caused by: java.lang.IllegalArgumentException: > jboss.annotations.api.1.2.spec: Invalid module name: '1' is not a Java > identifier > > It seems there is an issue with the determination of the naming of the > automatic module. I expect to have the same issue for > jboss-websocket-api_1.1_spec. > > The name of the jar file isn't aligned on the algorithm defined under > (http://download.java.net/java/jigsaw/docs/api/java/lang/module/ModuleFinder.html). > > Is anyone aware of this issue? Is this something that can be resolved? > > > _______________________________________________ > undertow-dev mailing list > undertow-dev at lists.jboss.org > https://lists.jboss.org/mailman/listinfo/undertow-dev From spamcmon at gmail.com Thu Aug 31 11:47:53 2017 From: spamcmon at gmail.com (Tester) Date: Thu, 31 Aug 2017 17:47:53 +0200 Subject: [undertow-dev] Fwd: Issue with Java 9 (Jigsaw) when using Undertow In-Reply-To: References: Message-ID: Hi Stuart, I've tested it out for both spec jars by adding an Automatic-Module-Name to their respective manifest.mf files and then it's working. No more errors with regards to the bundle names. While tryout out the Jetty Spring Boot starter, I noticed they are using the javax.servlet.* libraries to pull in the api's. That solution isn't giving any issues neither, so that might be a viable option as well? Do I log a defect for this or is this handled internally? With kind regards, Peter 2017-08-31 3:25 GMT+02:00 Stuart Douglas : > It sounds like we need to add an Automatic-Module-Name entry to these > jars manifests to specify the actual module name. Is there any chance > you could modify the jar's to test this out? > > Stuart > > On Wed, Aug 30, 2017 at 9:05 PM, Tester wrote: > > Hi, > > > > I'm using the Spring Boot starter for Undertow. The dependencies which > are > > pulled in are: > > > > org.springframework.boot:spring-boot-starter-undertow: > jar:2.0.0.M3:compile > > | +- io.undertow:undertow-core:jar:1.4.18.Final:compile > > | | +- org.jboss.xnio:xnio-api:jar:3.3.8.Final:compile > > | | \- org.jboss.xnio:xnio-nio:jar:3.3.8.Final:runtime > > | +- io.undertow:undertow-servlet:jar:1.4.18.Final:compile > > | | \- > > org.jboss.spec.javax.annotation:jboss-annotations- > api_1.2_spec:jar:1.0.0.Final:compile > > | +- io.undertow:undertow-websockets-jsr:jar:1.4.18.Final:compile > > | | \- > > org.jboss.spec.javax.websocket:jboss-websocket-api_ > 1.1_spec:jar:1.1.0.Final:compile > > | +- javax.servlet:javax.servlet-api:jar:3.1.0:compile > > | \- org.glassfish:javax.el:jar:3.0.0:compile > > > > Now, when I run the application through Java 9 (Release candidate) and I > > have a module-info.java (Jigsaw), then I get the following error: > > > > Error occurred during initialization of boot layer > > java.lang.module.FindException: Unable to derive module descriptor for > > C:\Users\xxxxx\.m2\repository\org\jboss\spec\javax\ > annotation\jboss-annotations-api_1.2_spec\1.0.0.Final\ > jboss-annotations-api_1.2_spec-1.0.0.Final.jar > > Caused by: java.lang.IllegalArgumentException: > > jboss.annotations.api.1.2.spec: Invalid module name: '1' is not a Java > > identifier > > > > It seems there is an issue with the determination of the naming of the > > automatic module. I expect to have the same issue for > > jboss-websocket-api_1.1_spec. > > > > The name of the jar file isn't aligned on the algorithm defined under > > (http://download.java.net/java/jigsaw/docs/api/java/ > lang/module/ModuleFinder.html). > > > > Is anyone aware of this issue? Is this something that can be resolved? > > > > > > _______________________________________________ > > undertow-dev mailing list > > undertow-dev at lists.jboss.org > > https://lists.jboss.org/mailman/listinfo/undertow-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://lists.jboss.org/pipermail/undertow-dev/attachments/20170831/f5f56959/attachment-0001.html From ecki at zusammenkunft.net Thu Aug 31 13:59:57 2017 From: ecki at zusammenkunft.net (Bernd Eckenfels) Date: Thu, 31 Aug 2017 17:59:57 +0000 Subject: [undertow-dev] Fwd: Issue with Java 9 (Jigsaw) when using Undertow In-Reply-To: References: , Message-ID: I think we should report that to maven as well, if it does put something on the module path it should ensure the filename complies. (however imam unsure why it uses the module path at all?) Gruss Bernd -- http://bernd.eckenfels.net ________________________________ From: undertow-dev-bounces at lists.jboss.org on behalf of Tester Sent: Thursday, August 31, 2017 5:47:53 PM To: Stuart Douglas Cc: Undertow Developers Subject: Re: [undertow-dev] Fwd: Issue with Java 9 (Jigsaw) when using Undertow Hi Stuart, I've tested it out for both spec jars by adding an Automatic-Module-Name to their respective manifest.mf files and then it's working. No more errors with regards to the bundle names. While tryout out the Jetty Spring Boot starter, I noticed they are using the javax.servlet.* libraries to pull in the api's. That solution isn't giving any issues neither, so that might be a viable option as well? Do I log a defect for this or is this handled internally? With kind regards, Peter 2017-08-31 3:25 GMT+02:00 Stuart Douglas >: It sounds like we need to add an Automatic-Module-Name entry to these jars manifests to specify the actual module name. Is there any chance you could modify the jar's to test this out? Stuart On Wed, Aug 30, 2017 at 9:05 PM, Tester > wrote: > Hi, > > I'm using the Spring Boot starter for Undertow. The dependencies which are > pulled in are: > > org.springframework.boot:spring-boot-starter-undertow:jar:2.0.0.M3:compile > | +- io.undertow:undertow-core:jar:1.4.18.Final:compile > | | +- org.jboss.xnio:xnio-api:jar:3.3.8.Final:compile > | | \- org.jboss.xnio:xnio-nio:jar:3.3.8.Final:runtime > | +- io.undertow:undertow-servlet:jar:1.4.18.Final:compile > | | \- > org.jboss.spec.javax.annotation:jboss-annotations-api_1.2_spec:jar:1.0.0.Final:compile > | +- io.undertow:undertow-websockets-jsr:jar:1.4.18.Final:compile > | | \- > org.jboss.spec.javax.websocket:jboss-websocket-api_1.1_spec:jar:1.1.0.Final:compile > | +- javax.servlet:javax.servlet-api:jar:3.1.0:compile > | \- org.glassfish:javax.el:jar:3.0.0:compile > > Now, when I run the application through Java 9 (Release candidate) and I > have a module-info.java (Jigsaw), then I get the following error: > > Error occurred during initialization of boot layer > java.lang.module.FindException: Unable to derive module descriptor for > C:\Users\xxxxx\.m2\repository\org\jboss\spec\javax\annotation\jboss-annotations-api_1.2_spec\1.0.0.Final\jboss-annotations-api_1.2_spec-1.0.0.Final.jar > Caused by: java.lang.IllegalArgumentException: > jboss.annotations.api.1.2.spec: Invalid module name: '1' is not a Java > identifier > > It seems there is an issue with the determination of the naming of the > automatic module. I expect to have the same issue for > jboss-websocket-api_1.1_spec. > > The name of the jar file isn't aligned on the algorithm defined under > (http://download.java.net/java/jigsaw/docs/api/java/lang/module/ModuleFinder.html). > > Is anyone aware of this issue? Is this something that can be resolved? > > > _______________________________________________ > undertow-dev mailing list > undertow-dev at lists.jboss.org > https://lists.jboss.org/mailman/listinfo/undertow-dev -------------- next part -------------- An HTML attachment was scrubbed... URL: http://lists.jboss.org/pipermail/undertow-dev/attachments/20170831/8b3dfbb8/attachment.html From matt at matthicks.com Thu Aug 31 15:57:51 2017 From: matt at matthicks.com (Hicks, Matt) Date: Thu, 31 Aug 2017 19:57:51 +0000 Subject: [undertow-dev] Streaming a ZIP file Message-ID: I'm trying to create ZIP files on-demand from the server and stream them back to the browser, but I'm not sure the proper way to do this. The only way I can think of is to use a `ZipOutputStream`, but that would be a blocking operation. Is there a better way to do this? -------------- next part -------------- An HTML attachment was scrubbed... URL: http://lists.jboss.org/pipermail/undertow-dev/attachments/20170831/0d331912/attachment.html