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.BufferedReader;
31  import java.io.IOException;
32  import java.io.InputStream;
33  import java.io.InputStreamReader;
34  import java.io.OutputStream;
35  import java.nio.charset.Charset;
36  import java.nio.charset.StandardCharsets;
37  import java.util.ArrayList;
38  import java.util.Arrays;
39  import java.util.Collection;
40  import java.util.List;
41  import java.util.Random;
42  import java.util.concurrent.TimeUnit;
43  
44  import org.apache.hc.core5.function.Decorator;
45  import org.apache.hc.core5.http.ClassicHttpRequest;
46  import org.apache.hc.core5.http.ClassicHttpResponse;
47  import org.apache.hc.core5.http.ContentType;
48  import org.apache.hc.core5.http.EntityDetails;
49  import org.apache.hc.core5.http.Header;
50  import org.apache.hc.core5.http.HttpEntity;
51  import org.apache.hc.core5.http.HttpException;
52  import org.apache.hc.core5.http.HttpHeaders;
53  import org.apache.hc.core5.http.HttpHost;
54  import org.apache.hc.core5.http.HttpRequest;
55  import org.apache.hc.core5.http.HttpRequestInterceptor;
56  import org.apache.hc.core5.http.HttpStatus;
57  import org.apache.hc.core5.http.HttpVersion;
58  import org.apache.hc.core5.http.Method;
59  import org.apache.hc.core5.http.URIScheme;
60  import org.apache.hc.core5.http.config.Http1Config;
61  import org.apache.hc.core5.http.io.HttpRequestHandler;
62  import org.apache.hc.core5.http.io.HttpServerRequestHandler;
63  import org.apache.hc.core5.http.io.SocketConfig;
64  import org.apache.hc.core5.http.io.entity.AbstractHttpEntity;
65  import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
66  import org.apache.hc.core5.http.io.entity.EntityUtils;
67  import org.apache.hc.core5.http.io.entity.StringEntity;
68  import org.apache.hc.core5.http.io.support.BasicHttpServerExpectationDecorator;
69  import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
70  import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
71  import org.apache.hc.core5.http.protocol.DefaultHttpProcessor;
72  import org.apache.hc.core5.http.protocol.HttpContext;
73  import org.apache.hc.core5.http.protocol.HttpCoreContext;
74  import org.apache.hc.core5.http.protocol.RequestConnControl;
75  import org.apache.hc.core5.http.protocol.RequestContent;
76  import org.apache.hc.core5.http.protocol.RequestExpectContinue;
77  import org.apache.hc.core5.http.protocol.RequestTargetHost;
78  import org.apache.hc.core5.http.protocol.RequestUserAgent;
79  import org.apache.hc.core5.io.CloseMode;
80  import org.apache.hc.core5.testing.SSLTestContexts;
81  import org.junit.Assert;
82  import org.junit.Rule;
83  import org.junit.Test;
84  import org.junit.rules.ExternalResource;
85  import org.junit.runner.RunWith;
86  import org.junit.runners.Parameterized;
87  
88  @RunWith(Parameterized.class)
89  public class ClassicIntegrationTest {
90  
91      @Parameterized.Parameters(name = "{0}")
92      public static Collection<Object[]> protocols() {
93          return Arrays.asList(new Object[][]{
94                  { URIScheme.HTTP },
95                  { URIScheme.HTTPS }
96          });
97      }
98  
99      private final URIScheme scheme;
100     private ClassicTestServer server;
101 
102     public ClassicIntegrationTest(final URIScheme scheme) {
103         this.scheme = scheme;
104     }
105 
106     @Rule
107     public ExternalResource serverResource = new ExternalResource() {
108 
109         @Override
110         protected void before() throws Throwable {
111             server = new ClassicTestServer(
112                     scheme == URIScheme.HTTPS ? SSLTestContexts.createServerSSLContext() : null,
113                     SocketConfig.custom()
114                             .setSoTimeout(5, TimeUnit.SECONDS)
115                             .build());
116         }
117 
118         @Override
119         protected void after() {
120             if (server != null) {
121                 try {
122                     server.shutdown(CloseMode.IMMEDIATE);
123                     server = null;
124                 } catch (final Exception ignore) {
125                 }
126             }
127         }
128 
129     };
130 
131     private ClassicTestClient client;
132 
133     @Rule
134     public ExternalResource clientResource = new ExternalResource() {
135 
136         @Override
137         protected void before() throws Throwable {
138             client = new ClassicTestClient(
139                     scheme == URIScheme.HTTPS  ? SSLTestContexts.createClientSSLContext() : null,
140                     SocketConfig.custom()
141                             .setSoTimeout(5, TimeUnit.SECONDS)
142                             .build());
143         }
144 
145         @Override
146         protected void after() {
147             if (client != null) {
148                 try {
149                     client.shutdown(CloseMode.IMMEDIATE);
150                     client = null;
151                 } catch (final Exception ignore) {
152                 }
153             }
154         }
155 
156     };
157 
158     /**
159      * This test case executes a series of simple GET requests
160      */
161     @Test
162     public void testSimpleBasicHttpRequests() throws Exception {
163 
164         final int reqNo = 20;
165 
166         final Random rnd = new Random();
167 
168         // Prepare some random data
169         final List<byte[]> testData = new ArrayList<>(reqNo);
170         for (int i = 0; i < reqNo; i++) {
171             final int size = rnd.nextInt(5000);
172             final byte[] data = new byte[size];
173             rnd.nextBytes(data);
174             testData.add(data);
175         }
176 
177         // Initialize the server-side request handler
178         this.server.registerHandler("*", new HttpRequestHandler() {
179 
180             @Override
181             public void handle(
182                     final ClassicHttpRequest request,
183                     final ClassicHttpResponse response,
184                     final HttpContext context) throws HttpException, IOException {
185 
186                 String s = request.getPath();
187                 if (s.startsWith("/?")) {
188                     s = s.substring(2);
189                 }
190                 final int index = Integer.parseInt(s);
191                 final byte[] data = testData.get(index);
192                 final ByteArrayEntity entity = new ByteArrayEntity(data, null);
193                 response.setEntity(entity);
194             }
195 
196         });
197 
198         this.server.start();
199         this.client.start();
200 
201         final HttpCoreContext context = HttpCoreContext.create();
202         final HttpHost host = new HttpHost(scheme.id, "localhost", this.server.getPort());
203 
204         for (int r = 0; r < reqNo; r++) {
205             final BasicClassicHttpRequest get = new BasicClassicHttpRequest(Method.GET, "/?" + r);
206             try (final ClassicHttpResponse response = this.client.execute(host, get, context)) {
207                 final byte[] received = EntityUtils.toByteArray(response.getEntity());
208                 final byte[] expected = testData.get(r);
209 
210                 Assert.assertEquals(expected.length, received.length);
211                 for (int i = 0; i < expected.length; i++) {
212                     Assert.assertEquals(expected[i], received[i]);
213                 }
214             }
215         }
216     }
217 
218     /**
219      * This test case executes a series of simple POST requests with content length
220      * delimited content.
221      */
222     @Test
223     public void testSimpleHttpPostsWithContentLength() throws Exception {
224 
225         final int reqNo = 20;
226 
227         final Random rnd = new Random();
228 
229         // Prepare some random data
230         final List<byte[]> testData = new ArrayList<>(reqNo);
231         for (int i = 0; i < reqNo; i++) {
232             final int size = rnd.nextInt(5000);
233             final byte[] data = new byte[size];
234             rnd.nextBytes(data);
235             testData.add(data);
236         }
237 
238         // Initialize the server-side request handler
239         this.server.registerHandler("*", new HttpRequestHandler() {
240 
241             @Override
242             public void handle(
243                     final ClassicHttpRequest request,
244                     final ClassicHttpResponse response,
245                     final HttpContext context) throws HttpException, IOException {
246 
247                 final HttpEntity entity = request.getEntity();
248                 if (entity != null) {
249                     final byte[] data = EntityUtils.toByteArray(entity);
250                     response.setEntity(new ByteArrayEntity(data, null));
251                 }
252             }
253 
254         });
255 
256         this.server.start();
257         this.client.start();
258 
259         final HttpCoreContext context = HttpCoreContext.create();
260         final HttpHost host = new HttpHost(scheme.id, "localhost", this.server.getPort());
261 
262         for (int r = 0; r < reqNo; r++) {
263             final BasicClassicHttpRequest post = new BasicClassicHttpRequest(Method.POST, "/");
264             final byte[] data = testData.get(r);
265             post.setEntity(new ByteArrayEntity(data, null));
266 
267             try (final ClassicHttpResponse response = this.client.execute(host, post, context)) {
268                 final byte[] received = EntityUtils.toByteArray(response.getEntity());
269                 final byte[] expected = testData.get(r);
270 
271                 Assert.assertEquals(expected.length, received.length);
272                 for (int i = 0; i < expected.length; i++) {
273                     Assert.assertEquals(expected[i], received[i]);
274                 }
275             }
276         }
277     }
278 
279     /**
280      * This test case executes a series of simple POST requests with chunk
281      * coded content content.
282      */
283     @Test
284     public void testSimpleHttpPostsChunked() throws Exception {
285 
286         final int reqNo = 20;
287 
288         final Random rnd = new Random();
289 
290         // Prepare some random data
291         final List<byte[]> testData = new ArrayList<>(reqNo);
292         for (int i = 0; i < reqNo; i++) {
293             final int size = rnd.nextInt(20000);
294             final byte[] data = new byte[size];
295             rnd.nextBytes(data);
296             testData.add(data);
297         }
298 
299         // Initialize the server-side request handler
300         this.server.registerHandler("*", new HttpRequestHandler() {
301 
302             @Override
303             public void handle(
304                     final ClassicHttpRequest request,
305                     final ClassicHttpResponse response,
306                     final HttpContext context) throws HttpException, IOException {
307 
308                 final HttpEntity entity = request.getEntity();
309                 if (entity != null) {
310                     final byte[] data = EntityUtils.toByteArray(entity);
311                     response.setEntity(new ByteArrayEntity(data, null, true));
312                 }
313             }
314 
315         });
316 
317         this.server.start();
318         this.client.start();
319 
320         final HttpCoreContext context = HttpCoreContext.create();
321         final HttpHost host = new HttpHost(scheme.id, "localhost", this.server.getPort());
322 
323         for (int r = 0; r < reqNo; r++) {
324             final BasicClassicHttpRequest post = new BasicClassicHttpRequest(Method.POST, "/");
325             final byte[] data = testData.get(r);
326             post.setEntity(new ByteArrayEntity(data, null, true));
327 
328             try (final ClassicHttpResponse response = this.client.execute(host, post, context)) {
329                 final byte[] received = EntityUtils.toByteArray(response.getEntity());
330                 final byte[] expected = testData.get(r);
331 
332                 Assert.assertEquals(expected.length, received.length);
333                 for (int i = 0; i < expected.length; i++) {
334                     Assert.assertEquals(expected[i], received[i]);
335                 }
336             }
337         }
338     }
339 
340     /**
341      * This test case executes a series of simple HTTP/1.0 POST requests.
342      */
343     @Test
344     public void testSimpleHttpPostsHTTP10() throws Exception {
345 
346         final int reqNo = 20;
347 
348         final Random rnd = new Random();
349 
350         // Prepare some random data
351         final List<byte[]> testData = new ArrayList<>(reqNo);
352         for (int i = 0; i < reqNo; i++) {
353             final int size = rnd.nextInt(5000);
354             final byte[] data = new byte[size];
355             rnd.nextBytes(data);
356             testData.add(data);
357         }
358 
359         // Initialize the server-side request handler
360         this.server.registerHandler("*", new HttpRequestHandler() {
361 
362             @Override
363             public void handle(
364                     final ClassicHttpRequest request,
365                     final ClassicHttpResponse response,
366                     final HttpContext context) throws HttpException, IOException {
367 
368                 final HttpEntity entity = request.getEntity();
369                 if (entity != null) {
370                     final byte[] data = EntityUtils.toByteArray(entity);
371                     response.setEntity(new ByteArrayEntity(data, null));
372                 }
373                 if (HttpVersion.HTTP_1_0.equals(request.getVersion())) {
374                     response.addHeader("Version", "1.0");
375                 }
376             }
377 
378         });
379 
380         this.server.start();
381         this.client.start();
382 
383         final HttpCoreContext context = HttpCoreContext.create();
384         final HttpHost host = new HttpHost(scheme.id, "localhost", this.server.getPort());
385 
386         for (int r = 0; r < reqNo; r++) {
387             // Set protocol level to HTTP/1.0
388             final BasicClassicHttpRequest post = new BasicClassicHttpRequest(Method.POST, "/");
389             post.setVersion(HttpVersion.HTTP_1_0);
390             final byte[] data = testData.get(r);
391             post.setEntity(new ByteArrayEntity(data, null));
392 
393             try (final ClassicHttpResponse response = this.client.execute(host, post, context)) {
394                 Assert.assertEquals(HttpVersion.HTTP_1_1, response.getVersion());
395                 final Header h1 = response.getFirstHeader("Version");
396                 Assert.assertNotNull(h1);
397                 Assert.assertEquals("1.0", h1.getValue());
398                 final byte[] received = EntityUtils.toByteArray(response.getEntity());
399                 final byte[] expected = testData.get(r);
400 
401                 Assert.assertEquals(expected.length, received.length);
402                 for (int i = 0; i < expected.length; i++) {
403                     Assert.assertEquals(expected[i], received[i]);
404                 }
405             }
406         }
407     }
408 
409     /**
410      * This test case executes a series of simple POST requests using
411      * the 'expect: continue' handshake.
412      */
413     @Test
414     public void testHttpPostsWithExpectContinue() throws Exception {
415 
416         final int reqNo = 20;
417 
418         final Random rnd = new Random();
419 
420         // Prepare some random data
421         final List<byte[]> testData = new ArrayList<>(reqNo);
422         for (int i = 0; i < reqNo; i++) {
423             final int size = rnd.nextInt(5000);
424             final byte[] data = new byte[size];
425             rnd.nextBytes(data);
426             testData.add(data);
427         }
428 
429         // Initialize the server-side request handler
430         this.server.registerHandler("*", new HttpRequestHandler() {
431 
432             @Override
433             public void handle(
434                     final ClassicHttpRequest request,
435                     final ClassicHttpResponse response,
436                     final HttpContext context) throws HttpException, IOException {
437 
438                 final HttpEntity entity = request.getEntity();
439                 if (entity != null) {
440                     final byte[] data = EntityUtils.toByteArray(entity);
441                     response.setEntity(new ByteArrayEntity(data, null, true));
442                 }
443             }
444 
445         });
446 
447         this.server.start();
448         this.client.start();
449 
450         final HttpCoreContext context = HttpCoreContext.create();
451         final HttpHost host = new HttpHost(scheme.id, "localhost", this.server.getPort());
452 
453         for (int r = 0; r < reqNo; r++) {
454             final BasicClassicHttpRequest post = new BasicClassicHttpRequest(Method.POST, "/");
455             final byte[] data = testData.get(r);
456             post.setEntity(new ByteArrayEntity(data, null, true));
457 
458             try (final ClassicHttpResponse response = this.client.execute(host, post, context)) {
459                 final byte[] received = EntityUtils.toByteArray(response.getEntity());
460                 final byte[] expected = testData.get(r);
461 
462                 Assert.assertEquals(expected.length, received.length);
463                 for (int i = 0; i < expected.length; i++) {
464                     Assert.assertEquals(expected[i], received[i]);
465                 }
466             }
467         }
468     }
469 
470     /**
471      * This test case executes a series of simple POST requests that do not
472      * meet the target server expectations.
473      */
474     @Test
475     public void testHttpPostsWithExpectationVerification() throws Exception {
476 
477         final int reqNo = 20;
478 
479         // Initialize the server-side request handler
480         this.server.registerHandler("*", new HttpRequestHandler() {
481 
482             @Override
483             public void handle(
484                     final ClassicHttpRequest request,
485                     final ClassicHttpResponse response,
486                     final HttpContext context) throws HttpException, IOException {
487 
488                 response.setEntity(new StringEntity("No content"));
489             }
490 
491         });
492 
493         this.server.start(null, null, new Decorator<HttpServerRequestHandler>() {
494 
495             @Override
496             public HttpServerRequestHandler decorate(final HttpServerRequestHandler handler) {
497                 return new BasicHttpServerExpectationDecorator(handler) {
498 
499                     @Override
500                     protected ClassicHttpResponse verify(final ClassicHttpRequest request, final HttpContext context) {
501                         final Header someheader = request.getFirstHeader("Secret");
502                         if (someheader != null) {
503                             final int secretNumber;
504                             try {
505                                 secretNumber = Integer.parseInt(someheader.getValue());
506                             } catch (final NumberFormatException ex) {
507                                 final ClassicHttpResponse response = new BasicClassicHttpResponse(HttpStatus.SC_BAD_REQUEST);
508                                 response.setEntity(new StringEntity(ex.toString()));
509                                 return response;
510                             }
511                             if (secretNumber >= 2) {
512                                 final ClassicHttpResponse response = new BasicClassicHttpResponse(HttpStatus.SC_EXPECTATION_FAILED);
513                                 response.setEntity(new StringEntity("Wrong secret number", ContentType.TEXT_PLAIN));
514                                 return response;
515                             }
516                         }
517                         return null;
518                     }
519 
520                 };
521             }
522 
523         });
524         this.client.start();
525 
526         final HttpCoreContext context = HttpCoreContext.create();
527         final HttpHost host = new HttpHost(scheme.id, "localhost", this.server.getPort());
528 
529         for (int r = 0; r < reqNo; r++) {
530             final BasicClassicHttpRequest post = new BasicClassicHttpRequest(Method.POST, "/");
531             post.addHeader("Secret", Integer.toString(r));
532 
533             final byte[] b = new byte[2048];
534             for (int i = 0; i < b.length; i++) {
535                 b[i] = (byte) ('a' + r);
536             }
537             post.setEntity(new ByteArrayEntity(b, ContentType.TEXT_PLAIN));
538 
539             try (final ClassicHttpResponse response = this.client.execute(host, post, context)) {
540                 final HttpEntity responseEntity = response.getEntity();
541                 Assert.assertNotNull(responseEntity);
542                 EntityUtils.consume(responseEntity);
543 
544                 if (r >= 2) {
545                     Assert.assertEquals(HttpStatus.SC_EXPECTATION_FAILED, response.getCode());
546                 } else {
547                     Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
548                 }
549             }
550         }
551     }
552 
553     static class RepeatingEntity extends AbstractHttpEntity {
554 
555         private final byte[] raw;
556         private final int n;
557 
558         public RepeatingEntity(final String content, final Charset charset, final int n, final boolean chunked) {
559             super(ContentType.TEXT_PLAIN.withCharset(charset), null, chunked);
560             final Charset cs = charset != null ? charset : StandardCharsets.US_ASCII;
561             this.raw = content.getBytes(cs);
562             this.n = n;
563         }
564 
565         @Override
566         public InputStream getContent() throws IOException, IllegalStateException {
567             throw new IllegalStateException("This method is not implemented");
568         }
569 
570         @Override
571         public long getContentLength() {
572             return (this.raw.length + 2) * this.n;
573         }
574 
575         @Override
576         public boolean isRepeatable() {
577             return true;
578         }
579 
580         @Override
581         public boolean isStreaming() {
582             return false;
583         }
584 
585         @Override
586         public void writeTo(final OutputStream outStream) throws IOException {
587             for (int i = 0; i < this.n; i++) {
588                 outStream.write(this.raw);
589                 outStream.write('\r');
590                 outStream.write('\n');
591             }
592             outStream.flush();
593         }
594 
595         @Override
596         public void close() throws IOException {
597         }
598 
599     }
600 
601     @Test
602     public void testHttpContent() throws Exception {
603 
604         final String[] patterns = {
605 
606             "0123456789ABCDEF",
607             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
608             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
609             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
610             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
611             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
612             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
613             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
614             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
615             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
616             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
617             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
618             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
619             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
620             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
621             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that"
622         };
623 
624         // Initialize the server-side request handler
625         this.server.registerHandler("*", new HttpRequestHandler() {
626 
627             @Override
628             public void handle(
629                     final ClassicHttpRequest request,
630                     final ClassicHttpResponse response,
631                     final HttpContext context) throws HttpException, IOException {
632 
633                 int n = 1;
634                 String s = request.getPath();
635                 if (s.startsWith("/?n=")) {
636                     s = s.substring(4);
637                     try {
638                         n = Integer.parseInt(s);
639                         if (n <= 0) {
640                             throw new HttpException("Invalid request: " +
641                                     "number of repetitions cannot be negative or zero");
642                         }
643                     } catch (final NumberFormatException ex) {
644                         throw new HttpException("Invalid request: " +
645                                 "number of repetitions is invalid");
646                     }
647                 }
648 
649                 final HttpEntity entity = request.getEntity();
650                 if (entity != null) {
651                     final String line = EntityUtils.toString(entity);
652                     final ContentType contentType = ContentType.parse(entity.getContentType());
653                     Charset charset = contentType.getCharset();
654                     if (charset == null) {
655                         charset = StandardCharsets.ISO_8859_1;
656                     }
657                     response.setEntity(new RepeatingEntity(line, charset, n, n % 2 == 0));
658                 }
659             }
660 
661         });
662 
663         this.server.start();
664         this.client.start();
665 
666         final HttpCoreContext context = HttpCoreContext.create();
667         final HttpHost host = new HttpHost(scheme.id, "localhost", this.server.getPort());
668 
669         for (final String pattern : patterns) {
670             for (int n = 1000; n < 1020; n++) {
671                 final BasicClassicHttpRequest post = new BasicClassicHttpRequest(
672                         Method.POST.name(), "/?n=" + n);
673                 post.setEntity(new StringEntity(pattern, ContentType.TEXT_PLAIN, n % 2 == 0));
674 
675                 try (final ClassicHttpResponse response = this.client.execute(host, post, context)) {
676                     final HttpEntity entity = response.getEntity();
677                     Assert.assertNotNull(entity);
678                     final InputStream inStream = entity.getContent();
679                     final ContentType contentType = ContentType.parse(entity.getContentType());
680                     Charset charset = contentType.getCharset();
681                     if (charset == null) {
682                         charset = StandardCharsets.ISO_8859_1;
683                     }
684                     Assert.assertNotNull(inStream);
685                     final BufferedReader reader = new BufferedReader(new InputStreamReader(inStream, charset));
686 
687                     String line;
688                     int count = 0;
689                     while ((line = reader.readLine()) != null) {
690                         Assert.assertEquals(pattern, line);
691                         count++;
692                     }
693                     Assert.assertEquals(n, count);
694                 }
695             }
696         }
697     }
698 
699     @Test
700     public void testHttpPostNoEntity() throws Exception {
701         this.server.registerHandler("*", new HttpRequestHandler() {
702 
703             @Override
704             public void handle(
705                     final ClassicHttpRequest request,
706                     final ClassicHttpResponse response,
707                     final HttpContext context) throws HttpException, IOException {
708 
709                 final HttpEntity entity = request.getEntity();
710                 if (entity != null) {
711                     final byte[] data = EntityUtils.toByteArray(entity);
712                     response.setEntity(new ByteArrayEntity(data, null));
713                 }
714             }
715 
716         });
717 
718         this.server.start();
719         this.client.start();
720 
721         final HttpCoreContext context = HttpCoreContext.create();
722         final HttpHost host = new HttpHost(scheme.id, "localhost", this.server.getPort());
723 
724         final BasicClassicHttpRequest post = new BasicClassicHttpRequest(Method.POST, "/");
725         post.setEntity(null);
726 
727         try (final ClassicHttpResponse response = this.client.execute(host, post, context)) {
728             Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
729             final byte[] received = EntityUtils.toByteArray(response.getEntity());
730             Assert.assertEquals(0, received.length);
731         }
732     }
733 
734     @Test
735     public void testHttpPostNoContentLength() throws Exception {
736         this.server.registerHandler("*", new HttpRequestHandler() {
737 
738             @Override
739             public void handle(
740                     final ClassicHttpRequest request,
741                     final ClassicHttpResponse response,
742                     final HttpContext context) throws HttpException, IOException {
743 
744                 final HttpEntity entity = request.getEntity();
745                 if (entity != null) {
746                     final byte[] data = EntityUtils.toByteArray(entity);
747                     response.setEntity(new ByteArrayEntity(data, null));
748                 }
749             }
750 
751         });
752 
753         this.server.start();
754         this.client.start(new DefaultHttpProcessor(
755                 new RequestTargetHost(),
756                 new RequestConnControl(),
757                 new RequestUserAgent(),
758                 new RequestExpectContinue()));
759 
760         final HttpCoreContext context = HttpCoreContext.create();
761         final HttpHost host = new HttpHost(scheme.id, "localhost", this.server.getPort());
762 
763         final BasicClassicHttpRequest post = new BasicClassicHttpRequest(Method.POST, "/");
764         post.setEntity(null);
765 
766         try (final ClassicHttpResponse response = this.client.execute(host, post, context)) {
767             Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
768             final byte[] received = EntityUtils.toByteArray(response.getEntity());
769             Assert.assertEquals(0, received.length);
770         }
771     }
772 
773     @Test
774     public void testHttpPostIdentity() throws Exception {
775         this.server.registerHandler("*", new HttpRequestHandler() {
776 
777             @Override
778             public void handle(
779                     final ClassicHttpRequest request,
780                     final ClassicHttpResponse response,
781                     final HttpContext context) throws HttpException, IOException {
782 
783                 final HttpEntity entity = request.getEntity();
784                 if (entity != null) {
785                     final byte[] data = EntityUtils.toByteArray(entity);
786                     response.setEntity(new ByteArrayEntity(data, null));
787                 }
788             }
789 
790         });
791 
792         this.server.start();
793         this.client.start(new DefaultHttpProcessor(
794                 new HttpRequestInterceptor() {
795 
796                     @Override
797                     public void process(
798                             final HttpRequest request,
799                             final EntityDetails entity,
800                             final HttpContext context) throws HttpException, IOException {
801                         request.addHeader(HttpHeaders.TRANSFER_ENCODING, "identity");
802                     }
803 
804                 },
805                 new RequestTargetHost(),
806                 new RequestConnControl(),
807                 new RequestUserAgent(),
808                 new RequestExpectContinue()));
809 
810         final HttpCoreContext context = HttpCoreContext.create();
811         final HttpHost host = new HttpHost(scheme.id, "localhost", this.server.getPort());
812 
813         final BasicClassicHttpRequest post = new BasicClassicHttpRequest(Method.POST, "/");
814         post.setEntity(null);
815 
816         try (final ClassicHttpResponse response = this.client.execute(host, post, context)) {
817             Assert.assertEquals(HttpStatus.SC_NOT_IMPLEMENTED, response.getCode());
818         }
819     }
820 
821     @Test
822     public void testNoContentResponse() throws Exception {
823 
824         final int reqNo = 20;
825 
826         // Initialize the server-side request handler
827         this.server.registerHandler("*", new HttpRequestHandler() {
828 
829             @Override
830             public void handle(
831                     final ClassicHttpRequest request,
832                     final ClassicHttpResponse response,
833                     final HttpContext context) throws HttpException, IOException {
834                 response.setCode(HttpStatus.SC_NO_CONTENT);
835             }
836 
837         });
838 
839         this.server.start();
840         this.client.start();
841 
842         final HttpCoreContext context = HttpCoreContext.create();
843         final HttpHost host = new HttpHost(scheme.id, "localhost", this.server.getPort());
844 
845         for (int r = 0; r < reqNo; r++) {
846             final BasicClassicHttpRequest get = new BasicClassicHttpRequest(Method.GET, "/?" + r);
847             try (final ClassicHttpResponse response = this.client.execute(host, get, context)) {
848                 Assert.assertNull(response.getEntity());
849             }
850         }
851     }
852 
853     @Test
854     public void testAbsentHostHeader() throws Exception {
855 
856         // Initialize the server-side request handler
857         this.server.registerHandler("*", new HttpRequestHandler() {
858 
859             @Override
860             public void handle(
861                     final ClassicHttpRequest request,
862                     final ClassicHttpResponse response,
863                     final HttpContext context) throws HttpException, IOException {
864                 response.setEntity(new StringEntity("All is well", StandardCharsets.US_ASCII));
865             }
866 
867         });
868 
869         this.server.start();
870         this.client.start(new DefaultHttpProcessor(new RequestContent(), new RequestConnControl()));
871 
872         final HttpCoreContext context = HttpCoreContext.create();
873         final HttpHost host = new HttpHost(scheme.id, "localhost", this.server.getPort());
874 
875         final BasicClassicHttpRequest get1 = new BasicClassicHttpRequest(Method.GET, "/");
876         get1.setVersion(HttpVersion.HTTP_1_0);
877         try (final ClassicHttpResponse response1 = this.client.execute(host, get1, context)) {
878             Assert.assertEquals(200, response1.getCode());
879             EntityUtils.consume(response1.getEntity());
880         }
881 
882         final BasicClassicHttpRequest get2 = new BasicClassicHttpRequest(Method.GET, "/");
883         try (final ClassicHttpResponse response2 = this.client.execute(host, get2, context)) {
884             Assert.assertEquals(400, response2.getCode());
885             EntityUtils.consume(response2.getEntity());
886         }
887     }
888 
889     @Test
890     public void testHeaderTooLarge() throws Exception {
891         this.server.registerHandler("*", new HttpRequestHandler() {
892 
893             @Override
894             public void handle(
895                     final ClassicHttpRequest request,
896                     final ClassicHttpResponse response,
897                     final HttpContext context) throws HttpException, IOException {
898                 response.setEntity(new StringEntity("All is well", StandardCharsets.US_ASCII));
899             }
900 
901         });
902 
903         this.server.start(
904                 Http1Config.custom()
905                         .setMaxLineLength(100)
906                         .build(),
907                 null,
908                 null);
909         this.client.start();
910 
911         final HttpCoreContext context = HttpCoreContext.create();
912         final HttpHost host = new HttpHost(scheme.id, "localhost", this.server.getPort());
913 
914         final BasicClassicHttpRequest get1 = new BasicClassicHttpRequest(Method.GET, "/");
915         get1.setHeader("big-f-header", "1234567890123456789012345678901234567890123456789012345678901234567890" +
916                 "1234567890123456789012345678901234567890");
917         try (final ClassicHttpResponse response1 = this.client.execute(host, get1, context)) {
918             Assert.assertEquals(431, response1.getCode());
919             EntityUtils.consume(response1.getEntity());
920         }
921     }
922 
923     @Test
924     public void testHeaderTooLargePost() throws Exception {
925         this.server.registerHandler("*", new HttpRequestHandler() {
926 
927             @Override
928             public void handle(
929                     final ClassicHttpRequest request,
930                     final ClassicHttpResponse response,
931                     final HttpContext context) throws HttpException, IOException {
932                 response.setEntity(new StringEntity("All is well", StandardCharsets.US_ASCII));
933             }
934 
935         });
936 
937         this.server.start(
938                 Http1Config.custom()
939                         .setMaxLineLength(100)
940                         .build(),
941                 null,
942                 null);
943         this.client.start(
944                 new DefaultHttpProcessor(new RequestContent(), new RequestTargetHost(), new RequestConnControl()));
945 
946         final HttpCoreContext context = HttpCoreContext.create();
947         final HttpHost host = new HttpHost(scheme.id, "localhost", this.server.getPort());
948 
949         final ClassicHttpRequest post1 = new BasicClassicHttpRequest(Method.POST, "/");
950         post1.setHeader("big-f-header", "1234567890123456789012345678901234567890123456789012345678901234567890" +
951                 "1234567890123456789012345678901234567890");
952         final byte[] b = new byte[2048];
953         for (int i = 0; i < b.length; i++) {
954             b[i] = (byte) ('a' + i % 10);
955         }
956         post1.setEntity(new ByteArrayEntity(b, ContentType.TEXT_PLAIN));
957 
958         try (final ClassicHttpResponse response1 = this.client.execute(host, post1, context)) {
959             Assert.assertEquals(431, response1.getCode());
960             EntityUtils.consume(response1.getEntity());
961         }
962     }
963 
964 }