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 package org.apache.hc.client5.testing.sync;
28
29 import java.io.IOException;
30 import java.net.Socket;
31
32 import org.apache.hc.client5.http.classic.methods.HttpGet;
33 import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
34 import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
35 import org.apache.hc.core5.http.ClassicHttpResponse;
36 import org.apache.hc.core5.http.HttpException;
37 import org.apache.hc.core5.http.HttpHost;
38 import org.apache.hc.core5.http.HttpStatus;
39 import org.apache.hc.core5.http.config.Http1Config;
40 import org.apache.hc.core5.http.impl.bootstrap.HttpServer;
41 import org.apache.hc.core5.http.impl.bootstrap.ServerBootstrap;
42 import org.apache.hc.core5.http.impl.io.DefaultBHttpServerConnection;
43 import org.apache.hc.core5.http.io.HttpConnectionFactory;
44 import org.apache.hc.core5.http.io.entity.EntityUtils;
45 import org.apache.hc.core5.http.io.entity.StringEntity;
46 import org.apache.hc.core5.io.CloseMode;
47 import org.junit.jupiter.api.AfterEach;
48 import org.junit.jupiter.api.Assertions;
49 import org.junit.jupiter.api.Test;
50
51 class TestMalformedServerResponse {
52
53 private HttpServer server;
54
55 @AfterEach
56 void shutDown() {
57 if (this.server != null) {
58 this.server.close(CloseMode.GRACEFUL);
59 }
60 }
61
62 static class BrokenServerConnection extends DefaultBHttpServerConnection {
63
64 public BrokenServerConnection(final String scheme, final Http1Config h1Config) {
65 super(scheme, h1Config);
66 }
67
68 @Override
69 public void sendResponseHeader(final ClassicHttpResponse response) throws HttpException, IOException {
70 super.sendResponseHeader(response);
71 if (response.getCode() == HttpStatus.SC_NO_CONTENT) {
72 response.setEntity(new StringEntity(
73 "garbage\ngarbage\n" +
74 "garbage\ngarbage\n" +
75 "garbage\ngarbage\n" +
76 "garbage\ngarbage\n" +
77 "garbage\ngarbage\n" +
78 "garbage\ngarbage\n" +
79 "garbage\ngarbage\n" +
80 "garbage\ngarbage\n" +
81 "garbage\ngarbage\n"));
82 sendResponseEntity(response);
83 }
84 }
85 }
86
87 static class BrokenServerConnectionFactory implements HttpConnectionFactory<DefaultBHttpServerConnection> {
88
89 @Override
90 public DefaultBHttpServerConnection createConnection(final Socket socket) throws IOException {
91 final BrokenServerConnection conn = new BrokenServerConnection("http", Http1Config.DEFAULT);
92 conn.bind(socket);
93 return conn;
94 }
95 }
96
97 @Test
98 void testNoContentResponseWithGarbage() throws Exception {
99 server = ServerBootstrap.bootstrap()
100 .setCanonicalHostName("localhost")
101 .setConnectionFactory(new BrokenServerConnectionFactory())
102 .register("/nostuff", (request, response, context) -> response.setCode(HttpStatus.SC_NO_CONTENT))
103 .register("/stuff", (request, response, context) -> {
104 response.setCode(HttpStatus.SC_OK);
105 response.setEntity(new StringEntity("Some important stuff"));
106 })
107 .create();
108 server.start();
109
110 final HttpHost target = new HttpHost("localhost", server.getLocalPort());
111 try (final CloseableHttpClient httpclient = HttpClientBuilder.create().build()) {
112 final HttpGet get1 = new HttpGet("/nostuff");
113 httpclient.execute(target, get1, response -> {
114 Assertions.assertEquals(HttpStatus.SC_NO_CONTENT, response.getCode());
115 EntityUtils.consume(response.getEntity());
116 return null;
117 });
118 final HttpGet get2 = new HttpGet("/stuff");
119 httpclient.execute(target, get2, response -> {
120 Assertions.assertEquals(HttpStatus.SC_OK, response.getCode());
121 EntityUtils.consume(response.getEntity());
122 return null;
123 });
124 }
125 }
126
127 }