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.classic;
29
30 import java.io.IOException;
31 import java.util.Arrays;
32 import java.util.Collection;
33
34 import org.apache.hc.core5.http.ClassicHttpRequest;
35 import org.apache.hc.core5.http.ClassicHttpResponse;
36 import org.apache.hc.core5.http.ContentType;
37 import org.apache.hc.core5.http.HeaderElements;
38 import org.apache.hc.core5.http.HttpException;
39 import org.apache.hc.core5.http.HttpHeaders;
40 import org.apache.hc.core5.http.HttpHost;
41 import org.apache.hc.core5.http.HttpStatus;
42 import org.apache.hc.core5.http.Method;
43 import org.apache.hc.core5.http.URIScheme;
44 import org.apache.hc.core5.http.impl.bootstrap.HttpRequester;
45 import org.apache.hc.core5.http.impl.bootstrap.HttpServer;
46 import org.apache.hc.core5.http.impl.bootstrap.RequesterBootstrap;
47 import org.apache.hc.core5.http.impl.bootstrap.ServerBootstrap;
48 import org.apache.hc.core5.http.impl.bootstrap.StandardFilter;
49 import org.apache.hc.core5.http.io.HttpFilterChain;
50 import org.apache.hc.core5.http.io.HttpFilterHandler;
51 import org.apache.hc.core5.http.io.SocketConfig;
52 import org.apache.hc.core5.http.io.entity.EntityUtils;
53 import org.apache.hc.core5.http.io.entity.StringEntity;
54 import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
55 import org.apache.hc.core5.http.protocol.HttpContext;
56 import org.apache.hc.core5.http.protocol.HttpCoreContext;
57 import org.apache.hc.core5.io.CloseMode;
58 import org.apache.hc.core5.testing.SSLTestContexts;
59 import org.apache.hc.core5.util.Timeout;
60 import org.hamcrest.CoreMatchers;
61 import org.hamcrest.MatcherAssert;
62 import org.junit.Rule;
63 import org.junit.Test;
64 import org.junit.rules.ExternalResource;
65 import org.junit.runner.RunWith;
66 import org.junit.runners.Parameterized;
67 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory;
69
70 @RunWith(Parameterized.class)
71 public class ClassicServerAndRequesterTest {
72
73 @Parameterized.Parameters(name = "{0}")
74 public static Collection<Object[]> protocols() {
75 return Arrays.asList(new Object[][]{
76 { URIScheme.HTTP },
77 { URIScheme.HTTPS }
78 });
79 }
80
81 private static final Timeout TIMEOUT = Timeout.ofSeconds(30);
82
83 private final Logger log = LoggerFactory.getLogger(getClass());
84
85 private final URIScheme scheme;
86 private HttpServer server;
87
88 public ClassicServerAndRequesterTest(final URIScheme scheme) {
89 this.scheme = scheme;
90 }
91
92 @Rule
93 public ExternalResource serverResource = new ExternalResource() {
94
95 @Override
96 protected void before() throws Throwable {
97 log.debug("Starting up test server");
98 server = ServerBootstrap.bootstrap()
99 .setSslContext(scheme == URIScheme.HTTPS ? SSLTestContexts.createServerSSLContext() : null)
100 .setSocketConfig(SocketConfig.custom()
101 .setSoTimeout(TIMEOUT)
102 .build())
103 .register("*", new EchoHandler())
104 .addFilterBefore(StandardFilter.MAIN_HANDLER.name(), "no-keep-alive", new HttpFilterHandler() {
105
106 @Override
107 public void handle(
108 final ClassicHttpRequest request,
109 final HttpFilterChain.ResponseTrigger responseTrigger,
110 final HttpContext context,
111 final HttpFilterChain chain) throws HttpException, IOException {
112 chain.proceed(request, new HttpFilterChain.ResponseTrigger() {
113
114 @Override
115 public void sendInformation(
116 final ClassicHttpResponse response) throws HttpException, IOException {
117 responseTrigger.sendInformation(response);
118 }
119
120 @Override
121 public void submitResponse(
122 final ClassicHttpResponse response) throws HttpException, IOException {
123 if (request.getPath().startsWith("/no-keep-alive")) {
124 response.setHeader(HttpHeaders.CONNECTION, HeaderElements.CLOSE);
125 }
126 responseTrigger.submitResponse(response);
127 }
128
129 }, context);
130 }
131
132 })
133 .setExceptionListener(LoggingExceptionListener.INSTANCE)
134 .setStreamListener(LoggingHttp1StreamListener.INSTANCE)
135 .create();
136 }
137
138 @Override
139 protected void after() {
140 log.debug("Shutting down test server");
141 if (server != null) {
142 try {
143 server.close(CloseMode.IMMEDIATE);
144 } catch (final Exception ignore) {
145 }
146 }
147 }
148
149 };
150
151 private HttpRequester requester;
152
153 @Rule
154 public ExternalResource clientResource = new ExternalResource() {
155
156 @Override
157 protected void before() throws Throwable {
158 log.debug("Starting up test client");
159 requester = RequesterBootstrap.bootstrap()
160 .setSslContext(scheme == URIScheme.HTTPS ? SSLTestContexts.createClientSSLContext() : null)
161 .setSocketConfig(SocketConfig.custom()
162 .setSoTimeout(TIMEOUT)
163 .build())
164 .setMaxTotal(2)
165 .setDefaultMaxPerRoute(2)
166 .setStreamListener(LoggingHttp1StreamListener.INSTANCE)
167 .setConnPoolListener(LoggingConnPoolListener.INSTANCE)
168 .create();
169 }
170
171 @Override
172 protected void after() {
173 log.debug("Shutting down test client");
174 if (requester != null) {
175 try {
176 requester.close(CloseMode.GRACEFUL);
177 } catch (final Exception ignore) {
178 }
179 }
180 }
181
182 };
183
184 @Test
185 public void testSequentialRequests() throws Exception {
186 server.start();
187 final HttpHost target = new HttpHost(scheme.id, "localhost", server.getLocalPort());
188 final HttpCoreContext context = HttpCoreContext.create();
189 final ClassicHttpRequest request1 = new BasicClassicHttpRequest(Method.POST, "/stuff");
190 request1.setEntity(new StringEntity("some stuff", ContentType.TEXT_PLAIN));
191 try (final ClassicHttpResponse response1 = requester.execute(target, request1, TIMEOUT, context)) {
192 MatcherAssert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
193 final String body1 = EntityUtils.toString(response1.getEntity());
194 MatcherAssert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
195 }
196 final ClassicHttpRequest request2 = new BasicClassicHttpRequest(Method.POST, "/other-stuff");
197 request2.setEntity(new StringEntity("some other stuff", ContentType.TEXT_PLAIN));
198 try (final ClassicHttpResponse response2 = requester.execute(target, request2, TIMEOUT, context)) {
199 MatcherAssert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
200 final String body2 = EntityUtils.toString(response2.getEntity());
201 MatcherAssert.assertThat(body2, CoreMatchers.equalTo("some other stuff"));
202 }
203 final ClassicHttpRequest request3 = new BasicClassicHttpRequest(Method.POST, "/more-stuff");
204 request3.setEntity(new StringEntity("some more stuff", ContentType.TEXT_PLAIN));
205 try (final ClassicHttpResponse response3 = requester.execute(target, request3, TIMEOUT, context)) {
206 MatcherAssert.assertThat(response3.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
207 final String body3 = EntityUtils.toString(response3.getEntity());
208 MatcherAssert.assertThat(body3, CoreMatchers.equalTo("some more stuff"));
209 }
210 }
211
212 @Test
213 public void testSequentialRequestsNonPersistentConnection() throws Exception {
214 server.start();
215 final HttpHost target = new HttpHost(scheme.id, "localhost", server.getLocalPort());
216 final HttpCoreContext context = HttpCoreContext.create();
217 final ClassicHttpRequest request1 = new BasicClassicHttpRequest(Method.POST, "/no-keep-alive/stuff");
218 request1.setEntity(new StringEntity("some stuff", ContentType.TEXT_PLAIN));
219 try (final ClassicHttpResponse response1 = requester.execute(target, request1, TIMEOUT, context)) {
220 MatcherAssert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
221 final String body1 = EntityUtils.toString(response1.getEntity());
222 MatcherAssert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
223 }
224 final ClassicHttpRequest request2 = new BasicClassicHttpRequest(Method.POST, "/no-keep-alive/other-stuff");
225 request2.setEntity(new StringEntity("some other stuff", ContentType.TEXT_PLAIN));
226 try (final ClassicHttpResponse response2 = requester.execute(target, request2, TIMEOUT, context)) {
227 MatcherAssert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
228 final String body2 = EntityUtils.toString(response2.getEntity());
229 MatcherAssert.assertThat(body2, CoreMatchers.equalTo("some other stuff"));
230 }
231 final ClassicHttpRequest request3 = new BasicClassicHttpRequest(Method.POST, "/no-keep-alive/more-stuff");
232 request3.setEntity(new StringEntity("some more stuff", ContentType.TEXT_PLAIN));
233 try (final ClassicHttpResponse response3 = requester.execute(target, request3, TIMEOUT, context)) {
234 MatcherAssert.assertThat(response3.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
235 final String body3 = EntityUtils.toString(response3.getEntity());
236 MatcherAssert.assertThat(body3, CoreMatchers.equalTo("some more stuff"));
237 }
238 }
239
240 }