1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.hc.core5.testing.nio;
29
30 import static org.hamcrest.MatcherAssert.assertThat;
31
32 import java.io.IOException;
33 import java.net.InetSocketAddress;
34 import java.util.concurrent.Future;
35
36 import org.apache.hc.core5.function.Supplier;
37 import org.apache.hc.core5.http.ContentType;
38 import org.apache.hc.core5.http.HeaderElements;
39 import org.apache.hc.core5.http.HttpException;
40 import org.apache.hc.core5.http.HttpHeaders;
41 import org.apache.hc.core5.http.HttpHost;
42 import org.apache.hc.core5.http.HttpRequest;
43 import org.apache.hc.core5.http.HttpResponse;
44 import org.apache.hc.core5.http.HttpStatus;
45 import org.apache.hc.core5.http.Message;
46 import org.apache.hc.core5.http.Method;
47 import org.apache.hc.core5.http.URIScheme;
48 import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncRequester;
49 import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncServer;
50 import org.apache.hc.core5.http.impl.bootstrap.StandardFilter;
51 import org.apache.hc.core5.http.impl.routing.RequestRouter;
52 import org.apache.hc.core5.http.nio.AsyncEntityProducer;
53 import org.apache.hc.core5.http.nio.AsyncFilterChain;
54 import org.apache.hc.core5.http.nio.AsyncPushProducer;
55 import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
56 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
57 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityProducer;
58 import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
59 import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
60 import org.apache.hc.core5.reactor.IOReactorConfig;
61 import org.apache.hc.core5.reactor.ListenerEndpoint;
62 import org.apache.hc.core5.testing.nio.extension.HttpAsyncRequesterResource;
63 import org.apache.hc.core5.testing.nio.extension.HttpAsyncServerResource;
64 import org.apache.hc.core5.util.Timeout;
65 import org.hamcrest.CoreMatchers;
66 import org.junit.jupiter.api.Test;
67 import org.junit.jupiter.api.extension.RegisterExtension;
68
69 public abstract class Http1CoreTransportTest extends HttpCoreTransportTest {
70
71 private static final Timeout TIMEOUT = Timeout.ofMinutes(1);
72
73 @RegisterExtension
74 private final HttpAsyncServerResource serverResource;
75 @RegisterExtension
76 private final HttpAsyncRequesterResource clientResource;
77
78 public Http1CoreTransportTest(final URIScheme scheme) {
79 super(scheme);
80 this.serverResource = new HttpAsyncServerResource(bootstrap -> bootstrap
81 .setIOReactorConfig(
82 IOReactorConfig.custom()
83 .setSoTimeout(TIMEOUT)
84 .build())
85 .setRequestRouter(RequestRouter.<Supplier<AsyncServerExchangeHandler>>builder()
86 .addRoute(RequestRouter.LOCAL_AUTHORITY, "*", () -> new EchoHandler(2048))
87 .resolveAuthority(RequestRouter.LOCAL_AUTHORITY_RESOLVER)
88 .build())
89 .addFilterBefore(StandardFilter.MAIN_HANDLER.name(), "no-keepalive", (request, entityDetails, context, responseTrigger, chain) ->
90 chain.proceed(request, entityDetails, context, new AsyncFilterChain.ResponseTrigger() {
91
92 @Override
93 public void sendInformation(
94 final HttpResponse response) throws HttpException, IOException {
95 responseTrigger.sendInformation(response);
96 }
97
98 @Override
99 public void submitResponse(
100 final HttpResponse response,
101 final AsyncEntityProducer entityProducer) throws HttpException, IOException {
102 if (request.getPath().startsWith("/no-keep-alive")) {
103 response.setHeader(HttpHeaders.CONNECTION, HeaderElements.CLOSE);
104 }
105 responseTrigger.submitResponse(response, entityProducer);
106 }
107
108 @Override
109 public void pushPromise(
110 final HttpRequest promise,
111 final AsyncPushProducer responseProducer) throws HttpException, IOException {
112 responseTrigger.pushPromise(promise, responseProducer);
113 }
114
115 }))
116 );
117 this.clientResource = new HttpAsyncRequesterResource(bootstrap -> bootstrap
118 .setIOReactorConfig(IOReactorConfig.custom()
119 .setSoTimeout(TIMEOUT)
120 .build())
121 );
122 }
123
124 @Override
125 HttpAsyncServer serverStart() throws IOException {
126 return serverResource.start();
127 }
128
129 @Override
130 HttpAsyncRequester clientStart() {
131 return clientResource.start();
132 }
133
134 @Test
135 public void testSequentialRequestsNonPersistentConnection() throws Exception {
136 final HttpAsyncServer server = serverResource.start();
137 final Future<ListenerEndpoint> future = server.listen(new InetSocketAddress(0), scheme);
138 final ListenerEndpoint listener = future.get();
139 final InetSocketAddress address = (InetSocketAddress) listener.getAddress();
140 final HttpAsyncRequester requester = clientResource.start();
141
142 final HttpHost target = new HttpHost(scheme.id, "localhost", address.getPort());
143 final Future<Message<HttpResponse, String>> resultFuture1 = requester.execute(
144 new BasicRequestProducer(Method.POST, target, "/no-keep-alive/stuff",
145 new StringAsyncEntityProducer("some stuff", ContentType.TEXT_PLAIN)),
146 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
147 final Message<HttpResponse, String> message1 = resultFuture1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
148 assertThat(message1, CoreMatchers.notNullValue());
149 final HttpResponse response1 = message1.getHead();
150 assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
151 final String body1 = message1.getBody();
152 assertThat(body1, CoreMatchers.equalTo("some stuff"));
153
154 final Future<Message<HttpResponse, String>> resultFuture2 = requester.execute(
155 new BasicRequestProducer(Method.POST, target, "/no-keep-alive/other-stuff",
156 new StringAsyncEntityProducer("some other stuff", ContentType.TEXT_PLAIN)),
157 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
158 final Message<HttpResponse, String> message2 = resultFuture2.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
159 assertThat(message2, CoreMatchers.notNullValue());
160 final HttpResponse response2 = message2.getHead();
161 assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
162 final String body2 = message2.getBody();
163 assertThat(body2, CoreMatchers.equalTo("some other stuff"));
164
165 final Future<Message<HttpResponse, String>> resultFuture3 = requester.execute(
166 new BasicRequestProducer(Method.POST, target, "/no-keep-alive/more-stuff",
167 new StringAsyncEntityProducer("some more stuff", ContentType.TEXT_PLAIN)),
168 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
169 final Message<HttpResponse, String> message3 = resultFuture3.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
170 assertThat(message3, CoreMatchers.notNullValue());
171 final HttpResponse response3 = message3.getHead();
172 assertThat(response3.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
173 final String body3 = message3.getBody();
174 assertThat(body3, CoreMatchers.equalTo("some more stuff"));
175 }
176
177 }