19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
20 * or visit www.oracle.com if you need additional information or have any |
20 * or visit www.oracle.com if you need additional information or have any |
21 * questions. |
21 * questions. |
22 */ |
22 */ |
23 |
23 |
24 |
|
25 import java.io.IOException; |
24 import java.io.IOException; |
|
25 import java.net.URI; |
|
26 import java.util.concurrent.CompletableFuture; |
|
27 import javax.net.ssl.SSLContext; |
|
28 import javax.net.ServerSocketFactory; |
|
29 import javax.net.ssl.SSLServerSocketFactory; |
26 import jdk.incubator.http.HttpClient; |
30 import jdk.incubator.http.HttpClient; |
|
31 import jdk.incubator.http.HttpClient.Version; |
27 import jdk.incubator.http.HttpRequest; |
32 import jdk.incubator.http.HttpRequest; |
28 import jdk.incubator.http.HttpResponse; |
33 import jdk.incubator.http.HttpResponse; |
29 import java.net.URI; |
34 import jdk.testlibrary.SimpleSSLContext; |
30 import java.util.concurrent.CompletableFuture; |
35 import static java.lang.System.out; |
31 import java.util.concurrent.Executor; |
36 import static java.lang.String.format; |
32 import java.util.concurrent.ExecutorService; |
|
33 import static jdk.incubator.http.HttpResponse.BodyHandler.asString; |
37 import static jdk.incubator.http.HttpResponse.BodyHandler.asString; |
34 |
38 |
35 /** |
39 /** |
36 * @test |
40 * @test |
37 * @bug 8087112 |
41 * @bug 8087112 |
38 * @key intermittent |
42 * @library /lib/testlibrary |
39 * @build Server |
43 * @build jdk.testlibrary.SimpleSSLContext |
40 * @run main/othervm -Djava.net.HttpClient.log=all SplitResponse |
44 * @build MockServer |
|
45 * @run main/othervm -Djdk.internal.httpclient.debug=true -Djdk.httpclient.HttpClient.log=all SplitResponse |
41 */ |
46 */ |
42 |
47 |
43 /** |
48 /** |
44 * Similar test to QuickResponses except that each byte of the response |
49 * Similar test to QuickResponses except that each byte of the response |
45 * is sent in a separate packet, which tests the stability of the implementation |
50 * is sent in a separate packet, which tests the stability of the implementation |
46 * for receiving unusual packet sizes. |
51 * for receiving unusual packet sizes. Additionally, tests scenarios there |
|
52 * connections that are retrieved from the connection pool may reach EOF before |
|
53 * being reused. |
47 */ |
54 */ |
48 public class SplitResponse { |
55 public class SplitResponse { |
49 |
56 |
50 static Server server; |
57 static String response(String body, boolean serverKeepalive) { |
51 |
58 StringBuilder sb = new StringBuilder(); |
52 static String response(String body) { |
59 sb.append("HTTP/1.1 200 OK\r\n"); |
53 return "HTTP/1.1 200 OK\r\nConnection: Close\r\nContent-length: " |
60 if (!serverKeepalive) |
54 + Integer.toString(body.length()) |
61 sb.append("Connection: Close\r\n"); |
55 + "\r\n\r\n" + body; |
62 |
|
63 sb.append("Content-length: ").append(body.length()).append("\r\n"); |
|
64 sb.append("\r\n"); |
|
65 sb.append(body); |
|
66 return sb.toString(); |
56 } |
67 } |
57 |
68 |
58 static final String responses[] = { |
69 static final String responses[] = { |
59 "Lorem ipsum", |
70 "Lorem ipsum", |
60 "dolor sit amet", |
71 "dolor sit amet", |
66 "Duis aute irure dolor in reprehenderit in voluptate velit esse" + |
77 "Duis aute irure dolor in reprehenderit in voluptate velit esse" + |
67 "cillum dolore eu fugiat nulla pariatur.", |
78 "cillum dolore eu fugiat nulla pariatur.", |
68 "Excepteur sint occaecat cupidatat non proident." |
79 "Excepteur sint occaecat cupidatat non proident." |
69 }; |
80 }; |
70 |
81 |
|
82 final ServerSocketFactory factory; |
|
83 final SSLContext context; |
|
84 final boolean useSSL; |
|
85 SplitResponse(boolean useSSL) throws IOException { |
|
86 this.useSSL = useSSL; |
|
87 context = new SimpleSSLContext().get(); |
|
88 SSLContext.setDefault(context); |
|
89 factory = useSSL ? SSLServerSocketFactory.getDefault() |
|
90 : ServerSocketFactory.getDefault(); |
|
91 } |
|
92 |
|
93 public HttpClient newHttpClient() { |
|
94 HttpClient client; |
|
95 if (useSSL) { |
|
96 client = HttpClient.newBuilder() |
|
97 .sslContext(context) |
|
98 .build(); |
|
99 } else { |
|
100 client = HttpClient.newHttpClient(); |
|
101 } |
|
102 return client; |
|
103 } |
|
104 |
71 public static void main(String[] args) throws Exception { |
105 public static void main(String[] args) throws Exception { |
72 server = new Server(0); |
106 boolean useSSL = false; |
|
107 if (args != null && args.length == 1) { |
|
108 useSSL = "SSL".equals(args[0]); |
|
109 } |
|
110 SplitResponse sp = new SplitResponse(useSSL); |
|
111 |
|
112 for (Version version : Version.values()) { |
|
113 for (boolean serverKeepalive : new boolean[]{ true, false }) { |
|
114 // Note: the mock server doesn't support Keep-Alive, but |
|
115 // pretending that it might exercises code paths in and out of |
|
116 // the connection pool, and retry logic |
|
117 for (boolean async : new boolean[]{ true, false }) { |
|
118 sp.test(version, serverKeepalive, async); |
|
119 } |
|
120 } |
|
121 } |
|
122 } |
|
123 |
|
124 // @Test |
|
125 void test(Version version, boolean serverKeepalive, boolean async) |
|
126 throws Exception |
|
127 { |
|
128 out.println(format("*** version %s, serverKeepAlive: %s, async: %s ***", |
|
129 version, serverKeepalive, async)); |
|
130 MockServer server = new MockServer(0, factory); |
73 URI uri = new URI(server.getURL()); |
131 URI uri = new URI(server.getURL()); |
|
132 out.println("server is: " + uri); |
74 server.start(); |
133 server.start(); |
75 |
134 |
76 HttpClient client = HttpClient.newHttpClient(); |
135 |
77 HttpRequest request = HttpRequest.newBuilder(uri).build(); |
136 // The following code can be uncommented to verify that the |
|
137 // MockServer will reject rogue requests whose URI does not |
|
138 // contain "/foo/". |
|
139 // |
|
140 // Thread rogue = new Thread() { |
|
141 // public void run() { |
|
142 // try { |
|
143 // HttpClient client = newHttpClient(); |
|
144 // URI uri2 = URI.create(uri.toString().replace("/foo/","/")); |
|
145 // HttpRequest request = HttpRequest |
|
146 // .newBuilder(uri2).version(version).build(); |
|
147 // while (true) { |
|
148 // try { |
|
149 // client.send(request, HttpResponse.BodyHandler.asString()); |
|
150 // } catch (IOException ex) { |
|
151 // System.out.println("Client rejected " + request); |
|
152 // } |
|
153 // sleep(250); |
|
154 // } |
|
155 // } catch ( Throwable x) { |
|
156 // } |
|
157 // } |
|
158 // }; |
|
159 // rogue.setDaemon(true); |
|
160 // rogue.start(); |
|
161 |
|
162 |
|
163 HttpClient client = newHttpClient(); |
|
164 HttpRequest request = HttpRequest.newBuilder(uri).version(version).build(); |
78 HttpResponse<String> r; |
165 HttpResponse<String> r; |
79 CompletableFuture<HttpResponse<String>> cf1; |
166 CompletableFuture<HttpResponse<String>> cf1; |
80 |
167 |
81 try { |
168 try { |
82 for (int i=0; i<responses.length; i++) { |
169 for (int i=0; i<responses.length; i++) { |
83 cf1 = client.sendAsync(request, asString()); |
170 out.println("----- iteration " + i + " -----"); |
84 String body = responses[i]; |
171 String body = responses[i]; |
85 |
172 Thread t = sendSplitResponse(response(body, serverKeepalive), server); |
86 Server.Connection c = server.activity(); |
173 |
87 sendSplitResponse(response(body), c); |
174 if (async) { |
88 r = cf1.get(); |
175 out.println("send async: " + request); |
89 if (r.statusCode()!= 200) |
176 cf1 = client.sendAsync(request, asString()); |
|
177 r = cf1.get(); |
|
178 } else { // sync |
|
179 out.println("send sync: " + request); |
|
180 r = client.send(request, asString()); |
|
181 } |
|
182 |
|
183 if (r.statusCode() != 200) |
90 throw new RuntimeException("Failed"); |
184 throw new RuntimeException("Failed"); |
91 |
185 |
92 String rxbody = r.body(); |
186 String rxbody = r.body(); |
93 System.out.println("received " + rxbody); |
187 out.println("received " + rxbody); |
94 if (!rxbody.equals(body)) |
188 if (!rxbody.equals(body)) |
95 throw new RuntimeException("Failed"); |
189 throw new RuntimeException(format("Expected:%s, got:%s", body, rxbody)); |
96 c.close(); |
190 |
|
191 t.join(); |
|
192 conn.close(); |
97 } |
193 } |
98 } finally { |
194 } finally { |
99 Executor def = client.executor(); |
195 server.close(); |
100 if (def instanceof ExecutorService) { |
|
101 ((ExecutorService)def).shutdownNow(); |
|
102 } |
|
103 } |
196 } |
104 System.out.println("OK"); |
197 System.out.println("OK"); |
105 } |
198 } |
106 |
199 |
107 // send the response one byte at a time with a small delay between bytes |
200 // required for cleanup |
108 // to ensure that each byte is read in a separate read |
201 volatile MockServer.Connection conn; |
109 static void sendSplitResponse(String s, Server.Connection conn) { |
202 |
|
203 // Sends the response, mostly, one byte at a time with a small delay |
|
204 // between bytes, to encourage that each byte is read in a separate read |
|
205 Thread sendSplitResponse(String s, MockServer server) { |
110 System.out.println("Sending: "); |
206 System.out.println("Sending: "); |
111 Thread t = new Thread(() -> { |
207 Thread t = new Thread(() -> { |
|
208 System.out.println("Waiting for server to receive headers"); |
|
209 conn = server.activity(); |
|
210 System.out.println("Start sending response"); |
|
211 |
112 try { |
212 try { |
113 int len = s.length(); |
213 int len = s.length(); |
|
214 out.println("sending " + s); |
114 for (int i = 0; i < len; i++) { |
215 for (int i = 0; i < len; i++) { |
115 String onechar = s.substring(i, i + 1); |
216 String onechar = s.substring(i, i + 1); |
116 conn.send(onechar); |
217 conn.send(onechar); |
117 Thread.sleep(30); |
218 Thread.sleep(10); |
118 } |
219 } |
119 System.out.println("sent"); |
220 out.println("sent " + s); |
120 } catch (IOException | InterruptedException e) { |
221 } catch (IOException | InterruptedException e) { |
|
222 throw new RuntimeException(e); |
121 } |
223 } |
122 }); |
224 }); |
123 t.setDaemon(true); |
225 t.setDaemon(true); |
124 t.start(); |
226 t.start(); |
|
227 return t; |
125 } |
228 } |
126 } |
229 } |