Print this page
Split |
Close |
Expand all |
Collapse all |
--- old/test/sun/net/www/http/KeepAliveCache/B5045306.java
+++ new/test/sun/net/www/http/KeepAliveCache/B5045306.java
1 1 /*
2 2 * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 4 *
5 5 * This code is free software; you can redistribute it and/or modify it
6 6 * under the terms of the GNU General Public License version 2 only, as
7 7 * published by the Free Software Foundation.
8 8 *
9 9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 12 * version 2 for more details (a copy is included in the LICENSE file that
13 13 * accompanied this code).
14 14 *
15 15 * You should have received a copy of the GNU General Public License version
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
16 16 * 2 along with this work; if not, write to the Free Software Foundation,
17 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 18 *
19 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 20 * or visit www.oracle.com if you need additional information or have any
21 21 * questions.
22 22 */
23 23
24 24 /*
25 25 * @test
26 - * @bug 5045306 6356004
26 + * @bug 5045306 6356004 6993490
27 27 * @library ../../httptest/
28 28 * @build HttpCallback HttpServer HttpTransaction
29 29 * @run main/othervm B5045306
30 30 * @summary Http keep-alive implementation is not efficient
31 31 */
32 32
33 33 import java.net.*;
34 34 import java.io.*;
35 -import java.nio.channels.*;
36 35 import java.lang.management.*;
37 36
38 37 /* Part 1:
39 38 * The http client makes a connection to a URL whos content contains a lot of
40 39 * data, more than can fit in the socket buffer. The client only reads
41 40 * 1 byte of the data from the InputStream leaving behind more data than can
42 41 * fit in the socket buffer. The client then makes a second call to the http
43 42 * server. If the connection port used by the client is the same as for the
44 43 * first call then that means that the connection is being reused.
45 44 *
46 45 * Part 2:
47 46 * Test buggy webserver that sends less data than it specifies in its
48 47 * Content-length header.
49 48 */
50 49
51 50 public class B5045306
52 51 {
53 52 static SimpleHttpTransaction httpTrans;
54 53 static HttpServer server;
55 54
56 55 public static void main(String[] args) throws Exception {
57 56 startHttpServer();
58 57 clientHttpCalls();
59 58 }
60 59
61 60 public static void startHttpServer() {
62 61 try {
63 62 httpTrans = new SimpleHttpTransaction();
64 63 server = new HttpServer(httpTrans, 1, 10, 0);
65 64 } catch (IOException e) {
66 65 e.printStackTrace();
67 66 }
68 67 }
69 68
70 69 public static void clientHttpCalls() {
71 70 try {
72 71 System.out.println("http server listen on: " + server.getLocalPort());
73 72 String baseURLStr = "http://" + InetAddress.getLocalHost().getHostAddress() + ":" +
74 73 server.getLocalPort() + "/";
75 74
76 75 URL bigDataURL = new URL (baseURLStr + "firstCall");
77 76 URL smallDataURL = new URL (baseURLStr + "secondCall");
78 77
79 78 HttpURLConnection uc = (HttpURLConnection)bigDataURL.openConnection();
80 79
81 80 //Only read 1 byte of response data and close the stream
82 81 InputStream is = uc.getInputStream();
83 82 byte[] ba = new byte[1];
84 83 is.read(ba);
85 84 is.close();
86 85
87 86 // Allow the KeepAliveStreamCleaner thread to read the data left behind and cache the connection.
88 87 try { Thread.sleep(2000); } catch (Exception e) {}
89 88
90 89 uc = (HttpURLConnection)smallDataURL.openConnection();
91 90 uc.getResponseCode();
92 91
93 92 if (SimpleHttpTransaction.failed)
94 93 throw new RuntimeException("Failed: Initial Keep Alive Connection is not being reused");
95 94
96 95 // Part 2
97 96 URL part2Url = new URL (baseURLStr + "part2");
98 97 uc = (HttpURLConnection)part2Url.openConnection();
99 98 is = uc.getInputStream();
100 99 is.close();
101 100
102 101 // Allow the KeepAliveStreamCleaner thread to try and read the data left behind and cache the connection.
103 102 try { Thread.sleep(2000); } catch (Exception e) {}
104 103
105 104 ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
106 105 if (threadMXBean.isThreadCpuTimeSupported()) {
107 106 long[] threads = threadMXBean.getAllThreadIds();
108 107 ThreadInfo[] threadInfo = threadMXBean.getThreadInfo(threads);
109 108 for (int i=0; i<threadInfo.length; i++) {
110 109 if (threadInfo[i].getThreadName().equals("Keep-Alive-SocketCleaner")) {
111 110 System.out.println("Found Keep-Alive-SocketCleaner thread");
112 111 long threadID = threadInfo[i].getThreadId();
113 112 long before = threadMXBean.getThreadCpuTime(threadID);
114 113 try { Thread.sleep(2000); } catch (Exception e) {}
115 114 long after = threadMXBean.getThreadCpuTime(threadID);
116 115
117 116 if (before ==-1 || after == -1)
118 117 break; // thread has died, OK
119 118
120 119 // if Keep-Alive-SocketCleaner consumes more than 50% of cpu then we
121 120 // can assume a recursive loop.
122 121 long total = after - before;
123 122 if (total >= 1000000000) // 1 second, or 1 billion nanoseconds
124 123 throw new RuntimeException("Failed: possible recursive loop in Keep-Alive-SocketCleaner");
125 124 }
126 125 }
127 126 }
128 127
129 128 } catch (IOException e) {
130 129 e.printStackTrace();
131 130 } finally {
132 131 server.terminate();
133 132 }
134 133 }
135 134 }
136 135
137 136 class SimpleHttpTransaction implements HttpCallback
138 137 {
139 138 static boolean failed = false;
140 139
141 140 // Need to have enough data here that is too large for the socket buffer to hold.
142 141 // Also http.KeepAlive.remainingData must be greater than this value, default is 256K.
143 142 static final int RESPONSE_DATA_LENGTH = 128 * 1024;
144 143
145 144 int port1;
146 145
147 146 public void request(HttpTransaction trans) {
148 147 try {
149 148 String path = trans.getRequestURI().getPath();
150 149 if (path.equals("/firstCall")) {
151 150 port1 = trans.channel().socket().getPort();
152 151 System.out.println("First connection on client port = " + port1);
153 152
154 153 byte[] responseBody = new byte[RESPONSE_DATA_LENGTH];
155 154 for (int i=0; i<responseBody.length; i++)
156 155 responseBody[i] = 0x41;
↓ open down ↓ |
111 lines elided |
↑ open up ↑ |
157 156 trans.setResponseEntityBody (responseBody, responseBody.length);
158 157 trans.sendResponse(200, "OK");
159 158 } else if (path.equals("/secondCall")) {
160 159 int port2 = trans.channel().socket().getPort();
161 160 System.out.println("Second connection on client port = " + port2);
162 161
163 162 if (port1 != port2)
164 163 failed = true;
165 164
166 165 trans.setResponseHeader ("Content-length", Integer.toString(0));
166 +
167 + /* Force the server to not respond for more that the timeout
168 + * set by the keepalive cleaner (5000 millis). This ensures the
169 + * timeout is correctly resets the default read timeout,
170 + * infinity. See 6993490. */
171 + System.out.println("server sleeping...");
172 + try {Thread.sleep(6000); } catch (InterruptedException e) {}
173 +
167 174 trans.sendResponse(200, "OK");
168 175 } else if(path.equals("/part2")) {
169 176 System.out.println("Call to /part2");
170 177 byte[] responseBody = new byte[RESPONSE_DATA_LENGTH];
171 178 for (int i=0; i<responseBody.length; i++)
172 179 responseBody[i] = 0x41;
173 180 trans.setResponseEntityBody (responseBody, responseBody.length);
174 181
175 182 // override the Content-length header to be greater than the actual response body
176 183 trans.setResponseHeader("Content-length", Integer.toString(responseBody.length+1));
177 184 trans.sendResponse(200, "OK");
178 185
179 186 // now close the socket
180 187 trans.channel().socket().close();
181 188 }
182 189 } catch (Exception e) {
183 190 e.printStackTrace();
184 191 }
185 192 }
186 193 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX