1 /*
2  * Copyright (c) 2002, 2010, 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 4636331
27  * @summary Check that URLClassLoader doesn't create excessive http
28  *          connections
29  */
30 import java.net.*;
31 import java.io.*;
32 import java.util.*;
33 
34 public class HttpTest {
35 
36     /*
37      * Simple http server to service http requests. Auto shutdown
38      * if "idle" (no requests) for 10 seconds. Forks worker thread
39      * to service persistent connections. Work threads shutdown if
40      * "idle" for 5 seconds.
41      */
42     static class HttpServer implements Runnable {
43 
44         private static HttpServer svr = null;
45         private static Counters cnts = null;
46         private static ServerSocket ss;
47 
48         private static Object counterLock = new Object();
49         private static int getCount = 0;
50         private static int headCount = 0;
51 
52         class Worker extends Thread {
53             Socket s;
Worker(Socket s)54             Worker(Socket s) {
55                 this.s = s;
56             }
57 
run()58             public void run() {
59                 InputStream in = null;
60                 try {
61                     in = s.getInputStream();
62                     for (;;) {
63 
64                         // read entire request from client
65                         byte b[] = new byte[1024];
66                         int n, total=0;
67 
68                         // max 5 seconds to wait for new request
69                         s.setSoTimeout(5000);
70                         try {
71                             do {
72                                 n = in.read(b, total, b.length-total);
73                                 // max 0.5 seconds between each segment
74                                 // of request.
75                                 s.setSoTimeout(500);
76                                 if (n > 0) total += n;
77                             } while (n > 0);
78                         } catch (SocketTimeoutException e) { }
79 
80                         if (total == 0) {
81                             s.close();
82                             return;
83                         }
84 
85                         boolean getRequest = false;
86                         if (b[0] == 'G' && b[1] == 'E' && b[2] == 'T')
87                             getRequest = true;
88 
89                         synchronized (counterLock) {
90                             if (getRequest)
91                                 getCount++;
92                             else
93                                 headCount++;
94                         }
95 
96                         // response to client
97                         PrintStream out = new PrintStream(
98                                 new BufferedOutputStream(
99                                         s.getOutputStream() ));
100                         out.print("HTTP/1.1 200 OK\r\n");
101 
102                         out.print("Content-Length: 75000\r\n");
103                         out.print("\r\n");
104                         if (getRequest) {
105                             for (int i=0; i<75*1000; i++) {
106                                 out.write( (byte)'.' );
107                             }
108                         }
109                         out.flush();
110 
111                     } // for
112 
113                 } catch (Exception e) {
114                     unexpected(e);
115                 } finally {
116                     if (in != null) { try {in.close(); } catch(IOException e) {unexpected(e);} }
117                 }
118             }
119         }
120 
HttpServer()121         HttpServer() throws Exception {
122             ss = new ServerSocket(0);
123         }
124 
run()125         public void run() {
126             try {
127                 // shutdown if no request in 10 seconds.
128                 ss.setSoTimeout(10000);
129                 for (;;) {
130                     Socket s = ss.accept();
131                     (new Worker(s)).start();
132                 }
133             } catch (Exception e) {
134             }
135         }
136 
unexpected(Exception e)137         void unexpected(Exception e) {
138             System.out.println(e);
139             e.printStackTrace();
140         }
141 
create()142         public static HttpServer create() throws Exception {
143             if (svr != null)
144                 return svr;
145             cnts = new Counters();
146             svr = new HttpServer();
147             (new Thread(svr)).start();
148             return svr;
149         }
150 
shutdown()151         public static void shutdown() throws Exception {
152             if (svr != null) {
153                 ss.close();
154                 svr = null;
155             }
156         }
157 
port()158         public int port() {
159             return ss.getLocalPort();
160         }
161 
162         public static class Counters {
reset()163             public void reset() {
164                 synchronized (counterLock) {
165                     getCount = 0;
166                     headCount = 0;
167                 }
168             }
169 
getCount()170             public int getCount() {
171                 synchronized (counterLock) {
172                     return getCount;
173                 }
174             }
175 
headCount()176             public int headCount() {
177                 synchronized (counterLock) {
178                     return headCount;
179                 }
180             }
181 
toString()182             public String toString() {
183                 synchronized (counterLock) {
184                     return "GET count: " + getCount + "; " +
185                        "HEAD count: " + headCount;
186                 }
187             }
188         }
189 
counters()190         public Counters counters() {
191             return cnts;
192         }
193 
194     }
195 
main(String args[])196     public static void main(String args[]) throws Exception {
197         boolean failed = false;
198 
199         // create http server
200         HttpServer svr = HttpServer.create();
201 
202         // create class loader
203         URL urls[] =
204             { new URL("http://localhost:" + svr.port() + "/dir1/"),
205               new URL("http://localhost:" + svr.port() + "/dir2/") };
206         URLClassLoader cl = new URLClassLoader(urls);
207 
208         // Test 1 - check that getResource does single HEAD request
209         svr.counters().reset();
210         URL url = cl.getResource("foo.gif");
211         System.out.println(svr.counters());
212 
213         if (svr.counters().getCount() > 0 ||
214             svr.counters().headCount() > 1) {
215             failed = true;
216         }
217 
218         // Test 2 - check that getResourceAsStream does at most
219         //          one GET request
220         svr.counters().reset();
221         InputStream in = cl.getResourceAsStream("foo2.gif");
222         in.close();
223         System.out.println(svr.counters());
224         if (svr.counters().getCount() > 1) {
225             failed = true;
226         }
227 
228         // Test 3 - check that getResources only does HEAD requests
229         svr.counters().reset();
230         Enumeration e = cl.getResources("foos.gif");
231         try {
232             for (;;) {
233                 e.nextElement();
234             }
235         } catch (NoSuchElementException exc) { }
236         System.out.println(svr.counters());
237         if (svr.counters().getCount() > 1) {
238             failed = true;
239         }
240 
241         // shutdown http server
242         svr.shutdown();
243 
244         if (failed) {
245             throw new Exception("Excessive http connections established - Test failed");
246         }
247     }
248 
249 }
250