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.List;
39  import java.util.Random;
40  
41  import org.apache.hc.core5.http.ClassicHttpRequest;
42  import org.apache.hc.core5.http.ClassicHttpResponse;
43  import org.apache.hc.core5.http.ContentType;
44  import org.apache.hc.core5.http.Header;
45  import org.apache.hc.core5.http.HttpEntity;
46  import org.apache.hc.core5.http.HttpException;
47  import org.apache.hc.core5.http.HttpHeaders;
48  import org.apache.hc.core5.http.HttpHost;
49  import org.apache.hc.core5.http.HttpStatus;
50  import org.apache.hc.core5.http.HttpVersion;
51  import org.apache.hc.core5.http.Method;
52  import org.apache.hc.core5.http.ProtocolException;
53  import org.apache.hc.core5.http.URIScheme;
54  import org.apache.hc.core5.http.config.Http1Config;
55  import org.apache.hc.core5.http.io.entity.AbstractHttpEntity;
56  import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
57  import org.apache.hc.core5.http.io.entity.EntityUtils;
58  import org.apache.hc.core5.http.io.entity.StringEntity;
59  import org.apache.hc.core5.http.io.support.BasicHttpServerExpectationDecorator;
60  import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
61  import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
62  import org.apache.hc.core5.http.protocol.DefaultHttpProcessor;
63  import org.apache.hc.core5.http.protocol.HttpContext;
64  import org.apache.hc.core5.http.protocol.HttpCoreContext;
65  import org.apache.hc.core5.http.protocol.RequestConnControl;
66  import org.apache.hc.core5.http.protocol.RequestContent;
67  import org.apache.hc.core5.http.protocol.RequestExpectContinue;
68  import org.apache.hc.core5.http.protocol.RequestTargetHost;
69  import org.apache.hc.core5.http.protocol.RequestUserAgent;
70  import org.apache.hc.core5.testing.classic.extension.ClassicTestResources;
71  import org.apache.hc.core5.util.Timeout;
72  import org.junit.jupiter.api.Assertions;
73  import org.junit.jupiter.api.Test;
74  import org.junit.jupiter.api.extension.RegisterExtension;
75  
76  public abstract class ClassicIntegrationTest {
77  
78      private static final Timeout TIMEOUT = Timeout.ofMinutes(1);
79  
80      private final URIScheme scheme;
81      @RegisterExtension
82      private final ClassicTestResources testResources;
83  
84      public ClassicIntegrationTest(final URIScheme scheme) {
85          this.scheme = scheme;
86          this.testResources = new ClassicTestResources(scheme, TIMEOUT);
87      }
88  
89      /**
90       * This test case executes a series of simple GET requests
91       */
92      @Test
93      public void testSimpleBasicHttpRequests() throws Exception {
94          final ClassicTestServer server = testResources.server();
95          final ClassicTestClient client = testResources.client();
96  
97          final int reqNo = 20;
98  
99          final Random rnd = new Random();
100 
101         // Prepare some random data
102         final List<byte[]> testData = new ArrayList<>(reqNo);
103         for (int i = 0; i < reqNo; i++) {
104             final int size = rnd.nextInt(5000);
105             final byte[] data = new byte[size];
106             rnd.nextBytes(data);
107             testData.add(data);
108         }
109 
110 
111         // Initialize the server-side request handler
112         server.registerHandler("*", (request, response, context) -> {
113 
114             String s = request.getPath();
115             if (s.startsWith("/?")) {
116                 s = s.substring(2);
117             }
118             final int index = Integer.parseInt(s);
119             final byte[] data = testData.get(index);
120             final ByteArrayEntity entity = new ByteArrayEntity(data, null);
121             response.setEntity(entity);
122         });
123 
124         server.start();
125         client.start();
126 
127         final HttpCoreContext context = HttpCoreContext.create();
128         final HttpHost host = new HttpHost(scheme.id, "localhost", server.getPort());
129 
130         for (int r = 0; r < reqNo; r++) {
131             final BasicClassicHttpRequest get = new BasicClassicHttpRequest(Method.GET, "/?" + r);
132             try (final ClassicHttpResponse response = client.execute(host, get, context)) {
133                 final byte[] received = EntityUtils.toByteArray(response.getEntity());
134                 final byte[] expected = testData.get(r);
135 
136                 Assertions.assertEquals(expected.length, received.length);
137                 for (int i = 0; i < expected.length; i++) {
138                     Assertions.assertEquals(expected[i], received[i]);
139                 }
140             }
141         }
142     }
143 
144     /**
145      * This test case executes a series of simple POST requests with content length
146      * delimited content.
147      */
148     @Test
149     public void testSimpleHttpPostsWithContentLength() throws Exception {
150         final ClassicTestServer server = testResources.server();
151         final ClassicTestClient client = testResources.client();
152 
153         final int reqNo = 20;
154 
155         final Random rnd = new Random();
156 
157         // Prepare some random data
158         final List<byte[]> testData = new ArrayList<>(reqNo);
159         for (int i = 0; i < reqNo; i++) {
160             final int size = rnd.nextInt(5000);
161             final byte[] data = new byte[size];
162             rnd.nextBytes(data);
163             testData.add(data);
164         }
165 
166         // Initialize the server-side request handler
167         server.registerHandler("*", (request, response, context) -> {
168 
169             final HttpEntity entity = request.getEntity();
170             if (entity != null) {
171                 final byte[] data = EntityUtils.toByteArray(entity);
172                 response.setEntity(new ByteArrayEntity(data, null));
173             }
174         });
175 
176         server.start();
177         client.start();
178 
179         final HttpCoreContext context = HttpCoreContext.create();
180         final HttpHost host = new HttpHost(scheme.id, "localhost", server.getPort());
181 
182         for (int r = 0; r < reqNo; r++) {
183             final BasicClassicHttpRequest post = new BasicClassicHttpRequest(Method.POST, "/");
184             final byte[] data = testData.get(r);
185             post.setEntity(new ByteArrayEntity(data, null));
186 
187             try (final ClassicHttpResponse response = client.execute(host, post, context)) {
188                 final byte[] received = EntityUtils.toByteArray(response.getEntity());
189                 final byte[] expected = testData.get(r);
190 
191                 Assertions.assertEquals(expected.length, received.length);
192                 for (int i = 0; i < expected.length; i++) {
193                     Assertions.assertEquals(expected[i], received[i]);
194                 }
195             }
196         }
197     }
198 
199     /**
200      * This test case executes a series of simple POST requests with chunk
201      * coded content content.
202      */
203     @Test
204     public void testSimpleHttpPostsChunked() throws Exception {
205         final ClassicTestServer server = testResources.server();
206         final ClassicTestClient client = testResources.client();
207 
208         final int reqNo = 20;
209 
210         final Random rnd = new Random();
211 
212         // Prepare some random data
213         final List<byte[]> testData = new ArrayList<>(reqNo);
214         for (int i = 0; i < reqNo; i++) {
215             final int size = rnd.nextInt(20000);
216             final byte[] data = new byte[size];
217             rnd.nextBytes(data);
218             testData.add(data);
219         }
220 
221         // Initialize the server-side request handler
222         server.registerHandler("*", (request, response, context) -> {
223 
224             final HttpEntity entity = request.getEntity();
225             if (entity != null) {
226                 final byte[] data = EntityUtils.toByteArray(entity);
227                 response.setEntity(new ByteArrayEntity(data, null, true));
228             }
229         });
230 
231         server.start();
232         client.start();
233 
234         final HttpCoreContext context = HttpCoreContext.create();
235         final HttpHost host = new HttpHost(scheme.id, "localhost", server.getPort());
236 
237         for (int r = 0; r < reqNo; r++) {
238             final BasicClassicHttpRequest post = new BasicClassicHttpRequest(Method.POST, "/");
239             final byte[] data = testData.get(r);
240             post.setEntity(new ByteArrayEntity(data, null, true));
241 
242             try (final ClassicHttpResponse response = client.execute(host, post, context)) {
243                 final byte[] received = EntityUtils.toByteArray(response.getEntity());
244                 final byte[] expected = testData.get(r);
245 
246                 Assertions.assertEquals(expected.length, received.length);
247                 for (int i = 0; i < expected.length; i++) {
248                     Assertions.assertEquals(expected[i], received[i]);
249                 }
250             }
251         }
252     }
253 
254     /**
255      * This test case executes a series of simple HTTP/1.0 POST requests.
256      */
257     @Test
258     public void testSimpleHttpPostsHTTP10() throws Exception {
259         final ClassicTestServer server = testResources.server();
260         final ClassicTestClient client = testResources.client();
261 
262         final int reqNo = 20;
263 
264         final Random rnd = new Random();
265 
266         // Prepare some random data
267         final List<byte[]> testData = new ArrayList<>(reqNo);
268         for (int i = 0; i < reqNo; i++) {
269             final int size = rnd.nextInt(5000);
270             final byte[] data = new byte[size];
271             rnd.nextBytes(data);
272             testData.add(data);
273         }
274 
275         // Initialize the server-side request handler
276         server.registerHandler("*", (request, response, context) -> {
277 
278             final HttpEntity entity = request.getEntity();
279             if (entity != null) {
280                 final byte[] data = EntityUtils.toByteArray(entity);
281                 response.setEntity(new ByteArrayEntity(data, null));
282             }
283         });
284 
285         server.start();
286         client.start();
287 
288         final HttpCoreContext context = HttpCoreContext.create();
289         final HttpHost host = new HttpHost(scheme.id, "localhost", server.getPort());
290 
291         for (int r = 0; r < reqNo; r++) {
292             // Set protocol level to HTTP/1.0
293             final BasicClassicHttpRequest post = new BasicClassicHttpRequest(Method.POST, "/");
294             post.setVersion(HttpVersion.HTTP_1_0);
295             final byte[] data = testData.get(r);
296             post.setEntity(new ByteArrayEntity(data, null));
297 
298             try (final ClassicHttpResponse response = client.execute(host, post, context)) {
299                 final byte[] received = EntityUtils.toByteArray(response.getEntity());
300                 final byte[] expected = testData.get(r);
301 
302                 Assertions.assertEquals(expected.length, received.length);
303                 for (int i = 0; i < expected.length; i++) {
304                     Assertions.assertEquals(expected[i], received[i]);
305                 }
306             }
307         }
308     }
309 
310     /**
311      * This test case ensures that HTTP/1.1 features are disabled when executing
312      * HTTP/1.0 compatible requests.
313      */
314     @Test
315     public void testHTTP11FeaturesDisabledWithHTTP10Requests() throws Exception {
316         final ClassicTestServer server = testResources.server();
317         final ClassicTestClient client = testResources.client();
318 
319         server.start();
320         client.start();
321 
322         final HttpCoreContext context = HttpCoreContext.create();
323         final HttpHost host = new HttpHost(scheme.id, "localhost", server.getPort());
324 
325         final BasicClassicHttpRequest post = new BasicClassicHttpRequest(Method.POST, "/");
326         post.setVersion(HttpVersion.HTTP_1_0);
327         post.setEntity(new ByteArrayEntity(new byte[] {'a', 'b', 'c'}, null, true));
328 
329         Assertions.assertThrows(ProtocolException.class, () -> {
330             try (final ClassicHttpResponse response = client.execute(host, post, context)) {
331                 EntityUtils.consume(response.getEntity());
332             }
333         });
334     }
335 
336     /**
337      * This test case executes a series of simple POST requests using
338      * the 'expect: continue' handshake.
339      */
340     @Test
341     public void testHttpPostsWithExpectContinue() throws Exception {
342         final ClassicTestServer server = testResources.server();
343         final ClassicTestClient client = testResources.client();
344 
345         final int reqNo = 20;
346 
347         final Random rnd = new Random();
348 
349         // Prepare some random data
350         final List<byte[]> testData = new ArrayList<>(reqNo);
351         for (int i = 0; i < reqNo; i++) {
352             final int size = rnd.nextInt(5000);
353             final byte[] data = new byte[size];
354             rnd.nextBytes(data);
355             testData.add(data);
356         }
357 
358         // Initialize the server-side request handler
359         server.registerHandler("*", (request, response, context) -> {
360 
361             final HttpEntity entity = request.getEntity();
362             if (entity != null) {
363                 final byte[] data = EntityUtils.toByteArray(entity);
364                 response.setEntity(new ByteArrayEntity(data, null, true));
365             }
366         });
367 
368         server.start();
369         client.start();
370 
371         final HttpCoreContext context = HttpCoreContext.create();
372         final HttpHost host = new HttpHost(scheme.id, "localhost", server.getPort());
373 
374         for (int r = 0; r < reqNo; r++) {
375             final BasicClassicHttpRequest post = new BasicClassicHttpRequest(Method.POST, "/");
376             final byte[] data = testData.get(r);
377             post.setEntity(new ByteArrayEntity(data, null, true));
378 
379             try (final ClassicHttpResponse response = client.execute(host, post, context)) {
380                 final byte[] received = EntityUtils.toByteArray(response.getEntity());
381                 final byte[] expected = testData.get(r);
382 
383                 Assertions.assertEquals(expected.length, received.length);
384                 for (int i = 0; i < expected.length; i++) {
385                     Assertions.assertEquals(expected[i], received[i]);
386                 }
387             }
388         }
389     }
390 
391     /**
392      * This test case executes a series of simple POST requests that do not
393      * meet the target server expectations.
394      */
395     @Test
396     public void testHttpPostsWithExpectationVerification() throws Exception {
397         final ClassicTestServer server = testResources.server();
398         final ClassicTestClient client = testResources.client();
399 
400         final int reqNo = 20;
401 
402         // Initialize the server-side request handler
403         server.registerHandler("*", (request, response, context) -> response.setEntity(new StringEntity("No content")));
404 
405         server.start(null, null, handler -> new BasicHttpServerExpectationDecorator(handler) {
406 
407             @Override
408             protected ClassicHttpResponse verify(final ClassicHttpRequest request, final HttpContext context) {
409                 final Header someheader = request.getFirstHeader("Secret");
410                 if (someheader != null) {
411                     final int secretNumber;
412                     try {
413                         secretNumber = Integer.parseInt(someheader.getValue());
414                     } catch (final NumberFormatException ex) {
415                         final ClassicHttpResponse response = new BasicClassicHttpResponse(HttpStatus.SC_BAD_REQUEST);
416                         response.setEntity(new StringEntity(ex.toString()));
417                         return response;
418                     }
419                     if (secretNumber >= 2) {
420                         final ClassicHttpResponse response = new BasicClassicHttpResponse(HttpStatus.SC_EXPECTATION_FAILED);
421                         response.setEntity(new StringEntity("Wrong secret number", ContentType.TEXT_PLAIN));
422                         return response;
423                     }
424                 }
425                 return null;
426             }
427 
428         });
429         client.start();
430 
431         final HttpCoreContext context = HttpCoreContext.create();
432         final HttpHost host = new HttpHost(scheme.id, "localhost", server.getPort());
433 
434         for (int r = 0; r < reqNo; r++) {
435             final BasicClassicHttpRequest post = new BasicClassicHttpRequest(Method.POST, "/");
436             post.addHeader("Secret", Integer.toString(r));
437 
438             final byte[] b = new byte[2048];
439             for (int i = 0; i < b.length; i++) {
440                 b[i] = (byte) ('a' + r);
441             }
442             post.setEntity(new ByteArrayEntity(b, ContentType.TEXT_PLAIN));
443 
444             try (final ClassicHttpResponse response = client.execute(host, post, context)) {
445                 final HttpEntity responseEntity = response.getEntity();
446                 Assertions.assertNotNull(responseEntity);
447                 EntityUtils.consume(responseEntity);
448 
449                 if (r >= 2) {
450                     Assertions.assertEquals(HttpStatus.SC_EXPECTATION_FAILED, response.getCode());
451                 } else {
452                     Assertions.assertEquals(HttpStatus.SC_OK, response.getCode());
453                 }
454             }
455         }
456     }
457 
458     static class RepeatingEntity extends AbstractHttpEntity {
459 
460         private final byte[] raw;
461         private final int n;
462 
463         public RepeatingEntity(final String content, final Charset charset, final int n, final boolean chunked) {
464             super(ContentType.TEXT_PLAIN.withCharset(charset), null, chunked);
465             final Charset cs = charset != null ? charset : StandardCharsets.UTF_8;
466             this.raw = content.getBytes(cs);
467             this.n = n;
468         }
469 
470         @Override
471         public InputStream getContent() throws IOException, IllegalStateException {
472             throw new IllegalStateException("This method is not implemented");
473         }
474 
475         @Override
476         public long getContentLength() {
477             return (this.raw.length + 2) * this.n;
478         }
479 
480         @Override
481         public boolean isRepeatable() {
482             return true;
483         }
484 
485         @Override
486         public boolean isStreaming() {
487             return false;
488         }
489 
490         @Override
491         public void writeTo(final OutputStream outStream) throws IOException {
492             for (int i = 0; i < this.n; i++) {
493                 outStream.write(this.raw);
494                 outStream.write('\r');
495                 outStream.write('\n');
496             }
497             outStream.flush();
498         }
499 
500         @Override
501         public void close() throws IOException {
502         }
503 
504     }
505 
506     @Test
507     public void testHttpContent() throws Exception {
508         final ClassicTestServer server = testResources.server();
509         final ClassicTestClient client = testResources.client();
510 
511         final String[] patterns = {
512 
513             "0123456789ABCDEF",
514             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
515             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
516             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
517             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
518             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
519             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
520             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
521             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
522             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
523             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
524             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
525             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
526             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
527             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-" +
528             "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that"
529         };
530 
531         // Initialize the server-side request handler
532         server.registerHandler("*", (request, response, context) -> {
533 
534             int n = 1;
535             String s = request.getPath();
536             if (s.startsWith("/?n=")) {
537                 s = s.substring(4);
538                 try {
539                     n = Integer.parseInt(s);
540                     if (n <= 0) {
541                         throw new HttpException("Invalid request: " +
542                                 "number of repetitions cannot be negative or zero");
543                     }
544                 } catch (final NumberFormatException ex) {
545                     throw new HttpException("Invalid request: " +
546                             "number of repetitions is invalid");
547                 }
548             }
549 
550             final HttpEntity entity = request.getEntity();
551             if (entity != null) {
552                 final String line = EntityUtils.toString(entity);
553                 final ContentType contentType = ContentType.parse(entity.getContentType());
554                 final Charset charset = ContentType.getCharset(contentType, StandardCharsets.UTF_8);
555                 response.setEntity(new RepeatingEntity(line, charset, n, n % 2 == 0));
556             }
557         });
558 
559         server.start();
560         client.start();
561 
562         final HttpCoreContext context = HttpCoreContext.create();
563         final HttpHost host = new HttpHost(scheme.id, "localhost", server.getPort());
564 
565         for (final String pattern : patterns) {
566             for (int n = 1000; n < 1020; n++) {
567                 final BasicClassicHttpRequest post = new BasicClassicHttpRequest(
568                         Method.POST.name(), "/?n=" + n);
569                 post.setEntity(new StringEntity(pattern, ContentType.TEXT_PLAIN, n % 2 == 0));
570 
571                 try (final ClassicHttpResponse response = client.execute(host, post, context)) {
572                     final HttpEntity entity = response.getEntity();
573                     Assertions.assertNotNull(entity);
574                     final InputStream inStream = entity.getContent();
575                     final ContentType contentType = ContentType.parse(entity.getContentType());
576                     final Charset charset = ContentType.getCharset(contentType, StandardCharsets.UTF_8);
577                     Assertions.assertNotNull(inStream);
578                     final BufferedReader reader = new BufferedReader(new InputStreamReader(inStream, charset));
579 
580                     String line;
581                     int count = 0;
582                     while ((line = reader.readLine()) != null) {
583                         Assertions.assertEquals(pattern, line);
584                         count++;
585                     }
586                     Assertions.assertEquals(n, count);
587                 }
588             }
589         }
590     }
591 
592     @Test
593     public void testHttpPostNoEntity() throws Exception {
594         final ClassicTestServer server = testResources.server();
595         final ClassicTestClient client = testResources.client();
596 
597         server.registerHandler("*", (request, response, context) -> {
598 
599             final HttpEntity entity = request.getEntity();
600             if (entity != null) {
601                 final byte[] data = EntityUtils.toByteArray(entity);
602                 response.setEntity(new ByteArrayEntity(data, null));
603             }
604         });
605 
606         server.start();
607         client.start();
608 
609         final HttpCoreContext context = HttpCoreContext.create();
610         final HttpHost host = new HttpHost(scheme.id, "localhost", server.getPort());
611 
612         final BasicClassicHttpRequest post = new BasicClassicHttpRequest(Method.POST, "/");
613         post.setEntity(null);
614 
615         try (final ClassicHttpResponse response = client.execute(host, post, context)) {
616             Assertions.assertEquals(HttpStatus.SC_OK, response.getCode());
617             final byte[] received = EntityUtils.toByteArray(response.getEntity());
618             Assertions.assertEquals(0, received.length);
619         }
620     }
621 
622     @Test
623     public void testHttpPostNoContentLength() throws Exception {
624         final ClassicTestServer server = testResources.server();
625         final ClassicTestClient client = testResources.client();
626 
627         server.registerHandler("*", (request, response, context) -> {
628 
629             final HttpEntity entity = request.getEntity();
630             if (entity != null) {
631                 final byte[] data = EntityUtils.toByteArray(entity);
632                 response.setEntity(new ByteArrayEntity(data, null));
633             }
634         });
635 
636         server.start();
637         client.start(new DefaultHttpProcessor(
638                 RequestTargetHost.INSTANCE,
639                 RequestConnControl.INSTANCE,
640                 RequestUserAgent.INSTANCE,
641                 RequestExpectContinue.INSTANCE));
642 
643         final HttpCoreContext context = HttpCoreContext.create();
644         final HttpHost host = new HttpHost(scheme.id, "localhost", server.getPort());
645 
646         final BasicClassicHttpRequest post = new BasicClassicHttpRequest(Method.POST, "/");
647         post.setEntity(null);
648 
649         try (final ClassicHttpResponse response = client.execute(host, post, context)) {
650             Assertions.assertEquals(HttpStatus.SC_OK, response.getCode());
651             final byte[] received = EntityUtils.toByteArray(response.getEntity());
652             Assertions.assertEquals(0, received.length);
653         }
654     }
655 
656     @Test
657     public void testHttpPostIdentity() throws Exception {
658         final ClassicTestServer server = testResources.server();
659         final ClassicTestClient client = testResources.client();
660 
661         server.registerHandler("*", (request, response, context) -> {
662 
663             final HttpEntity entity = request.getEntity();
664             if (entity != null) {
665                 final byte[] data = EntityUtils.toByteArray(entity);
666                 response.setEntity(new ByteArrayEntity(data, null));
667             }
668         });
669 
670         server.start();
671         client.start(new DefaultHttpProcessor(
672                 (request, entity, context) -> request.addHeader(HttpHeaders.TRANSFER_ENCODING, "identity"),
673                 RequestTargetHost.INSTANCE,
674                 RequestConnControl.INSTANCE,
675                 RequestUserAgent.INSTANCE,
676                 RequestExpectContinue.INSTANCE));
677 
678         final HttpCoreContext context = HttpCoreContext.create();
679         final HttpHost host = new HttpHost(scheme.id, "localhost", server.getPort());
680 
681         final BasicClassicHttpRequest post = new BasicClassicHttpRequest(Method.POST, "/");
682         post.setEntity(null);
683 
684         try (final ClassicHttpResponse response = client.execute(host, post, context)) {
685             Assertions.assertEquals(HttpStatus.SC_NOT_IMPLEMENTED, response.getCode());
686         }
687     }
688 
689     @Test
690     public void testNoContentResponse() throws Exception {
691         final ClassicTestServer server = testResources.server();
692         final ClassicTestClient client = testResources.client();
693 
694         final int reqNo = 20;
695 
696         // Initialize the server-side request handler
697         server.registerHandler("*", (request, response, context) -> response.setCode(HttpStatus.SC_NO_CONTENT));
698 
699         server.start();
700         client.start();
701 
702         final HttpCoreContext context = HttpCoreContext.create();
703         final HttpHost host = new HttpHost(scheme.id, "localhost", server.getPort());
704 
705         for (int r = 0; r < reqNo; r++) {
706             final BasicClassicHttpRequest get = new BasicClassicHttpRequest(Method.GET, "/?" + r);
707             try (final ClassicHttpResponse response = client.execute(host, get, context)) {
708                 Assertions.assertNull(response.getEntity());
709             }
710         }
711     }
712 
713     @Test
714     public void testHeaderTooLarge() throws Exception {
715         final ClassicTestServer server = testResources.server();
716         final ClassicTestClient client = testResources.client();
717 
718         server.registerHandler("*", (request, response, context) ->
719                 response.setEntity(new StringEntity("All is well", StandardCharsets.US_ASCII)));
720 
721         server.start(
722                 Http1Config.custom()
723                         .setMaxLineLength(100)
724                         .build(),
725                 null,
726                 null);
727         client.start();
728 
729         final HttpCoreContext context = HttpCoreContext.create();
730         final HttpHost host = new HttpHost(scheme.id, "localhost", server.getPort());
731 
732         final BasicClassicHttpRequest get1 = new BasicClassicHttpRequest(Method.GET, "/");
733         get1.setHeader("big-f-header", "1234567890123456789012345678901234567890123456789012345678901234567890" +
734                 "1234567890123456789012345678901234567890");
735         try (final ClassicHttpResponse response1 = client.execute(host, get1, context)) {
736             Assertions.assertEquals(431, response1.getCode());
737             EntityUtils.consume(response1.getEntity());
738         }
739     }
740 
741     @Test
742     public void testHeaderTooLargePost() throws Exception {
743         final ClassicTestServer server = testResources.server();
744         final ClassicTestClient client = testResources.client();
745 
746         server.registerHandler("*", (request, response, context) ->
747                 response.setEntity(new StringEntity("All is well", StandardCharsets.US_ASCII)));
748 
749         server.start(
750                 Http1Config.custom()
751                         .setMaxLineLength(100)
752                         .build(),
753                 null,
754                 null);
755         client.start(
756                 new DefaultHttpProcessor(RequestContent.INSTANCE, RequestTargetHost.INSTANCE, RequestConnControl.INSTANCE));
757 
758         final HttpCoreContext context = HttpCoreContext.create();
759         final HttpHost host = new HttpHost(scheme.id, "localhost", server.getPort());
760 
761         final ClassicHttpRequest post1 = new BasicClassicHttpRequest(Method.POST, "/");
762         post1.setHeader("big-f-header", "1234567890123456789012345678901234567890123456789012345678901234567890" +
763                 "1234567890123456789012345678901234567890");
764         final byte[] b = new byte[2048];
765         for (int i = 0; i < b.length; i++) {
766             b[i] = (byte) ('a' + i % 10);
767         }
768         post1.setEntity(new ByteArrayEntity(b, ContentType.TEXT_PLAIN));
769 
770         try (final ClassicHttpResponse response1 = client.execute(host, post1, context)) {
771             Assertions.assertEquals(431, response1.getCode());
772             EntityUtils.consume(response1.getEntity());
773         }
774     }
775 
776 }