blob: 58102f5974a46f6f41ec618c0951537fb4291a16 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2001 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 */
23
24/**
25 * @test
26 * @bug 4507412
27 * @bug 4506998
28 * @summary Check that a 304 "Not-Modified" response from a server
29 * doesn't cause http client to close a keep-alive
30 * connection.
31 * Check that a content-length of 0 results in an
32 * empty input stream.
33 */
34import java.net.*;
35import java.io.*;
36
37public class ZeroContentLength {
38
39 /*
40 * Is debugging enabled - start with -d to enable.
41 */
42 static boolean debug = false;
43
44 static void debug(String msg) {
45 if (debug)
46 System.out.println(msg);
47 }
48
49 /*
50 * The response string and content-length that
51 * the server should return;
52 */
53 static String response;
54 static int contentLength;
55
56 static synchronized void setResponse(String rsp, int cl) {
57 response = rsp;
58 contentLength = cl;
59 }
60
61 /*
62 * Worker thread to service single connection - can service
63 * multiple http requests on same connection.
64 */
65 class Worker extends Thread {
66 Socket s;
67 int id;
68
69 Worker(Socket s, int id) {
70 this.s = s;
71 this.id = id;
72 }
73
74 public void run() {
75 try {
76
77 s.setSoTimeout(2000);
78 int max = 100;
79
80 for (;;) {
81
82 // read entire request from client
83 byte b[] = new byte[100];
84 InputStream in = s.getInputStream();
85 int n, total=0;
86
87 try {
88 do {
89 n = in.read(b);
90 if (n > 0) total += n;
91 } while (n > 0);
92 } catch (SocketTimeoutException e) { }
93
94 debug("worker " + id +
95 ": Read request from client " +
96 "(" + total + " bytes).");
97
98 if (total == 0) {
99 debug("worker: " + id + ": Shutdown");
100 return;
101 }
102
103 // response to client
104 PrintStream out = new PrintStream(
105 new BufferedOutputStream(
106 s.getOutputStream() ));
107
108 out.print("HTTP/1.1 " + response + "\r\n");
109 if (contentLength >= 0) {
110 out.print("Content-Length: " + contentLength +
111 "\r\n");
112 }
113 out.print("\r\n");
114 for (int i=0; i<contentLength; i++) {
115 out.write( (byte)'.' );
116 }
117 out.flush();
118
119 debug("worked " + id +
120 ": Sent response to client, length: " + contentLength);
121
122 if (--max == 0) {
123 s.close();
124 return;
125 }
126 }
127
128 } catch (Exception e) {
129 e.printStackTrace();
130 } finally {
131 try {
132 s.close();
133 } catch (Exception e) { }
134 }
135 }
136 }
137
138 /*
139 * Server thread to accept connection and create worker threads
140 * to service each connection.
141 */
142 class Server extends Thread {
143 ServerSocket ss;
144 int connectionCount;
145 boolean shutdown = false;
146
147 Server(ServerSocket ss) {
148 this.ss = ss;
149 }
150
151 public synchronized int connectionCount() {
152 return connectionCount;
153 }
154
155 public synchronized void shutdown() {
156 shutdown = true;
157 }
158
159 public void run() {
160 try {
161 ss.setSoTimeout(2000);
162
163 for (;;) {
164 Socket s;
165 try {
166 debug("server: Waiting for connections");
167 s = ss.accept();
168 } catch (SocketTimeoutException te) {
169 synchronized (this) {
170 if (shutdown) {
171 debug("server: Shuting down.");
172 return;
173 }
174 }
175 continue;
176 }
177
178 int id;
179 synchronized (this) {
180 id = connectionCount++;
181 }
182
183 Worker w = new Worker(s, id);
184 w.start();
185 debug("server: Started worker " + id);
186 }
187
188 } catch (Exception e) {
189 e.printStackTrace();
190 } finally {
191 try {
192 ss.close();
193 } catch (Exception e) { }
194 }
195 }
196 }
197
198 /*
199 * Make a single http request and return the content length
200 * received. Also do sanity check to ensure that the
201 * content-length header matches the total received on
202 * the input stream.
203 */
204 int doRequest(String uri) throws Exception {
205 URL url = new URL(uri);
206 HttpURLConnection http = (HttpURLConnection)url.openConnection();
207
208 int cl = http.getContentLength();
209
210 InputStream in = http.getInputStream();
211 byte b[] = new byte[100];
212 int total = 0;
213 int n;
214 do {
215 n = in.read(b);
216 if (n > 0) total += n;
217 } while (n > 0);
218 in.close();
219
220 if (cl >= 0 && total != cl) {
221 System.err.println("content-length header indicated: " + cl);
222 System.err.println("Actual received: " + total);
223 throw new Exception("Content-length didn't match actual received");
224 }
225
226 return total;
227 }
228
229
230 /*
231 * Send http requests to "server" and check that they all
232 * use the same network connection and that the content
233 * length corresponds to the content length expected.
234 * stream.
235 */
236 ZeroContentLength() throws Exception {
237
238 /* start the server */
239 ServerSocket ss = new ServerSocket(0);
240 Server svr = new Server(ss);
241 svr.start();
242
243 String uri = "http://localhost:" +
244 Integer.toString(ss.getLocalPort()) +
245 "/foo.html";
246
247 int expectedTotal = 0;
248 int actualTotal = 0;
249
250 System.out.println("**********************************");
251 System.out.println("200 OK, content-length:1024 ...");
252 setResponse("200 OK", 1024);
253 for (int i=0; i<5; i++) {
254 actualTotal += doRequest(uri);
255 expectedTotal += 1024;
256 }
257
258 System.out.println("**********************************");
259 System.out.println("200 OK, content-length:0 ...");
260 setResponse("200 OK", 0);
261 for (int i=0; i<5; i++) {
262 actualTotal += doRequest(uri);
263 }
264
265 System.out.println("**********************************");
266 System.out.println("304 Not-Modified, (no content-length) ...");
267 setResponse("304 Not-Modifed", -1);
268 for (int i=0; i<5; i++) {
269 actualTotal += doRequest(uri);
270 }
271
272 System.out.println("**********************************");
273 System.out.println("204 No-Content, (no content-length) ...");
274 setResponse("204 No-Content", -1);
275 for (int i=0; i<5; i++) {
276 actualTotal += doRequest(uri);
277 }
278
279 // shutdown server - we're done.
280 svr.shutdown();
281
282 System.out.println("**********************************");
283
284 if (actualTotal == expectedTotal) {
285 System.out.println("Passed: Actual total equal to expected total");
286 } else {
287 throw new Exception("Actual total != Expected total!!!");
288 }
289
290 int cnt = svr.connectionCount();
291 if (cnt == 1) {
292 System.out.println("Passed: Only 1 connection established");
293 } else {
294 throw new Exception("Test failed: Number of connections " +
295 "established: " + cnt + " - see log for details.");
296 }
297 }
298
299 public static void main(String args[]) throws Exception {
300
301 if (args.length > 0 && args[0].equals("-d")) {
302 debug = true;
303 }
304
305 new ZeroContentLength();
306 }
307
308}