1
+ /*
2
+ * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
+ *
5
+ * This code is free software; you can redistribute it and/or modify it
6
+ * under the terms of the GNU General Public License version 2 only, as
7
+ * published by the Free Software Foundation.
8
+ *
9
+ * This code is distributed in the hope that it will be useful, but WITHOUT
10
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
+ * version 2 for more details (a copy is included in the LICENSE file that
13
+ * accompanied this code).
14
+ *
15
+ * You should have received a copy of the GNU General Public License version
16
+ * 2 along with this work; if not, write to the Free Software Foundation,
17
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
+ *
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
21
+ * questions.
22
+ */
23
+
24
+ /*
25
+ * @test
26
+ * @bug 8293786
27
+ * @summary Checks to see if the HttpClient can process a request to cancel a transmission from a remote if the server
28
+ * does not process any data. The client should read all data from the server and close the connection.
29
+ * @library /test/jdk/java/net/httpclient/lib
30
+ * @build jdk.httpclient.test.lib.http2.Http2TestServer
31
+ * @run testng/othervm/timeout=50 -Djdk.httpclient.HttpClient.log=all
32
+ * PostPutTest
33
+ */
34
+
35
+ import jdk .httpclient .test .lib .http2 .Http2Handler ;
36
+ import jdk .httpclient .test .lib .http2 .Http2TestExchange ;
37
+ import jdk .httpclient .test .lib .http2 .Http2TestServer ;
38
+
39
+ import org .testng .annotations .AfterTest ;
40
+ import org .testng .annotations .BeforeTest ;
41
+ import org .testng .annotations .DataProvider ;
42
+ import org .testng .annotations .Test ;
43
+
44
+ import java .io .IOException ;
45
+ import java .io .PrintStream ;
46
+ import java .net .URI ;
47
+ import java .net .http .HttpClient ;
48
+ import java .net .http .HttpRequest ;
49
+ import java .net .http .HttpResponse ;
50
+
51
+ import static java .net .http .HttpClient .Version .HTTP_2 ;
52
+ import static java .net .http .HttpRequest .BodyPublishers .ofByteArray ;
53
+
54
+ public class PostPutTest {
55
+
56
+ Http2TestServer http2TestServer ;
57
+ URI warmupURI , testHandlerBasicURI , testHandlerCloseBosURI , testHandleNegativeContentLengthURI ;
58
+ static PrintStream testLog = System .err ;
59
+
60
+ // As per jdk.internal.net.http.WindowController.DEFAULT_INITIAL_WINDOW_SIZE
61
+ final int DEFAULT_INITIAL_WINDOW_SIZE = (64 * 1024 ) - 1 ;
62
+ // Add on a small amount of arbitrary bytes to see if client hangs when receiving RST_STREAM
63
+ byte [] data = new byte [DEFAULT_INITIAL_WINDOW_SIZE + 10 ];
64
+
65
+ @ BeforeTest
66
+ public void setup () throws Exception {
67
+ http2TestServer = new Http2TestServer (false , 0 );
68
+ http2TestServer .addHandler (new WarmupHandler (), "/Warmup" );
69
+ http2TestServer .addHandler (new TestHandlerBasic (), "/TestHandlerBasic" );
70
+ http2TestServer .addHandler (new TestHandlerCloseBos (), "/TestHandlerCloseBos" );
71
+ http2TestServer .addHandler (new TestHandleNegativeContentLength (), "/TestHandleNegativeContentLength" );
72
+ http2TestServer .start ();
73
+ testLog .println ("PostPutTest.setup(): Starting server" );
74
+ warmupURI = new URI ("http://" + http2TestServer .serverAuthority () + "/Warmup" );
75
+ testHandlerBasicURI = new URI ("http://" + http2TestServer .serverAuthority () + "/TestHandlerBasic" );
76
+ testHandlerCloseBosURI = new URI ("http://" + http2TestServer .serverAuthority () + "/TestHandlerCloseBos" );
77
+ testHandleNegativeContentLengthURI = new URI ("http://" + http2TestServer .serverAuthority () + "/TestHandleNegativeContentLength" );
78
+ testLog .println ("PostPutTest.setup(): warmupURI: " + warmupURI );
79
+ testLog .println ("PostPutTest.setup(): testHandlerBasicURI: " + testHandlerBasicURI );
80
+ testLog .println ("PostPutTest.setup(): testHandlerCloseBosURI: " + testHandlerCloseBosURI );
81
+ testLog .println ("PostPutTest.setup(): testHandleNegativeContentLengthURI: " + testHandleNegativeContentLengthURI );
82
+ }
83
+
84
+ @ AfterTest
85
+ public void teardown () {
86
+ testLog .println ("PostPutTest.teardown(): Stopping server" );
87
+ http2TestServer .stop ();
88
+ data = null ;
89
+ }
90
+
91
+ @ DataProvider (name = "variants" )
92
+ public Object [][] variants () {
93
+ HttpRequest over64kPost , over64kPut , over64kPostCloseBos , over64kPutCloseBos , over64kPostNegativeContentLength , over64kPutNegativeContentLength ;
94
+ over64kPost = HttpRequest .newBuilder ().version (HTTP_2 ).POST (ofByteArray (data )).uri (testHandlerBasicURI ).build ();
95
+ over64kPut = HttpRequest .newBuilder ().version (HTTP_2 ).PUT (ofByteArray (data )).uri (testHandlerBasicURI ).build ();
96
+
97
+ over64kPostCloseBos = HttpRequest .newBuilder ().version (HTTP_2 ).POST (ofByteArray (data )).uri (testHandlerCloseBosURI ).build ();
98
+ over64kPutCloseBos = HttpRequest .newBuilder ().version (HTTP_2 ).PUT (ofByteArray (data )).uri (testHandlerCloseBosURI ).build ();
99
+
100
+ over64kPostNegativeContentLength = HttpRequest .newBuilder ().version (HTTP_2 ).POST (ofByteArray (data )).uri (testHandleNegativeContentLengthURI ).build ();
101
+ over64kPutNegativeContentLength = HttpRequest .newBuilder ().version (HTTP_2 ).PUT (ofByteArray (data )).uri (testHandleNegativeContentLengthURI ).build ();
102
+
103
+ return new Object [][] {
104
+ { over64kPost , "POST data over 64k bytes" },
105
+ { over64kPut , "PUT data over 64k bytes" },
106
+ { over64kPostCloseBos , "POST data over 64k bytes with close bos" },
107
+ { over64kPutCloseBos , "PUT data over 64k bytes with close bos" },
108
+ { over64kPostNegativeContentLength , "POST data over 64k bytes with negative content length" },
109
+ { over64kPutNegativeContentLength , "PUT data over 64k bytes with negative content length" }
110
+ };
111
+ }
112
+
113
+ public HttpRequest getWarmupReq () {
114
+ return HttpRequest .newBuilder ()
115
+ .GET ()
116
+ .uri (warmupURI )
117
+ .build ();
118
+ }
119
+
120
+ @ Test (dataProvider = "variants" )
121
+ public void testOver64kPUT (HttpRequest req , String testMessage ) {
122
+ testLog .println ("PostPutTest: Performing test: " + testMessage );
123
+ HttpClient hc = HttpClient .newBuilder ().version (HTTP_2 ).build ();
124
+ hc .sendAsync (getWarmupReq (), HttpResponse .BodyHandlers .ofString ()).join ();
125
+ hc .sendAsync (req , HttpResponse .BodyHandlers .ofString ()).join ();
126
+ /*
127
+ If this test fails in timeout, it is likely due to one of two reasons:
128
+ - The responseSubscriber is null, so no incoming frames are being processed by the client
129
+ (See Stream::schedule)
130
+ - The test server is for some reason not sending a RST_STREAM with the NO_ERROR flag set after
131
+ sending an empty DATA frame with the END_STREAM flag set.
132
+ */
133
+ }
134
+
135
+ private static class TestHandlerBasic implements Http2Handler {
136
+
137
+ @ Override
138
+ public void handle (Http2TestExchange exchange ) throws IOException {
139
+ // The input stream is not read in this bug as this will trigger window updates for the server. This bug
140
+ // concerns the case where no updates are sent and the server instead tells the client to abort the transmission.
141
+ exchange .sendResponseHeaders (200 , 0 );
142
+ }
143
+ }
144
+
145
+ private static class TestHandlerCloseBos implements Http2Handler {
146
+
147
+ @ Override
148
+ public void handle (Http2TestExchange exchange ) throws IOException {
149
+ // This case does actually cause the test to hang due to the body input stream being closed before it can send
150
+ // the RST_STREAM frame.
151
+ exchange .sendResponseHeaders (200 , 0 );
152
+ exchange .getResponseBody ().close ();
153
+ }
154
+ }
155
+
156
+ private static class TestHandleNegativeContentLength implements Http2Handler {
157
+
158
+ @ Override
159
+ public void handle (Http2TestExchange exchange ) throws IOException {
160
+ exchange .sendResponseHeaders (200 , -1 );
161
+ }
162
+ }
163
+
164
+ private static class WarmupHandler implements Http2Handler {
165
+
166
+ @ Override
167
+ public void handle (Http2TestExchange exchange ) throws IOException {
168
+ exchange .sendResponseHeaders (200 , 0 );
169
+ }
170
+ }
171
+ }
0 commit comments