View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
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 }