1 /*
2  * Copyright (c) 2015, 2018, 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  * library /lib/testlibrary/ /
26  * build jdk.testlibrary.SimpleSSLContext ProxyServer
27  * compile ../../../com/sun/net/httpserver/LogFilter.java
28  * compile ../../../com/sun/net/httpserver/EchoHandler.java
29  * compile ../../../com/sun/net/httpserver/FileServerHandler.java
30  */
31 import com.sun.net.httpserver.Headers;
32 import com.sun.net.httpserver.HttpContext;
33 import com.sun.net.httpserver.HttpExchange;
34 import com.sun.net.httpserver.HttpHandler;
35 import com.sun.net.httpserver.HttpServer;
36 import com.sun.net.httpserver.HttpsConfigurator;
37 import com.sun.net.httpserver.HttpsServer;
38 import java.io.IOException;
39 import java.io.InputStream;
40 import java.io.OutputStream;
41 import java.net.InetAddress;
42 import java.net.InetSocketAddress;
43 import java.nio.file.Path;
44 import java.util.HashSet;
45 import java.util.concurrent.BrokenBarrierException;
46 import java.util.concurrent.CyclicBarrier;
47 import java.util.concurrent.ExecutorService;
48 import java.util.concurrent.Executors;
49 import java.util.logging.ConsoleHandler;
50 import java.util.logging.Level;
51 import java.util.logging.Logger;
52 import javax.net.ssl.SSLContext;
53 import jdk.testlibrary.SimpleSSLContext;
54 
55 public class LightWeightHttpServer {
56 
57     static SSLContext ctx;
58     static HttpServer httpServer;
59     static HttpsServer httpsServer;
60     static ExecutorService executor;
61     static int port;
62     static int httpsport;
63     static String httproot;
64     static String httpsroot;
65     static ProxyServer proxy;
66     static int proxyPort;
67     static RedirectErrorHandler redirectErrorHandler, redirectErrorHandlerSecure;
68     static RedirectHandler redirectHandler, redirectHandlerSecure;
69     static DelayHandler delayHandler;
70     static final String midSizedFilename = "/files/notsobigfile.txt";
71     static final String smallFilename = "/files/smallfile.txt";
72     static Path midSizedFile;
73     static Path smallFile;
74     static String fileroot;
75 
initServer()76     public static void initServer() throws IOException {
77 
78         Logger logger = Logger.getLogger("com.sun.net.httpserver");
79         ConsoleHandler ch = new ConsoleHandler();
80         logger.setLevel(Level.ALL);
81         ch.setLevel(Level.ALL);
82         logger.addHandler(ch);
83 
84         String root = System.getProperty("test.src", ".") + "/docs";
85         InetSocketAddress addr = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
86         httpServer = HttpServer.create(addr, 0);
87         if (httpServer instanceof HttpsServer) {
88             throw new RuntimeException("should not be httpsserver");
89         }
90         httpsServer = HttpsServer.create(addr, 0);
91         HttpHandler h = new FileServerHandler(root);
92 
93         HttpContext c1 = httpServer.createContext("/files", h);
94         HttpContext c2 = httpsServer.createContext("/files", h);
95         HttpContext c3 = httpServer.createContext("/echo", new EchoHandler());
96         redirectHandler = new RedirectHandler("/redirect");
97         redirectHandlerSecure = new RedirectHandler("/redirect");
98         HttpContext c4 = httpServer.createContext("/redirect", redirectHandler);
99         HttpContext c41 = httpsServer.createContext("/redirect", redirectHandlerSecure);
100         HttpContext c5 = httpsServer.createContext("/echo", new EchoHandler());
101         HttpContext c6 = httpServer.createContext("/keepalive", new KeepAliveHandler());
102         redirectErrorHandler = new RedirectErrorHandler("/redirecterror");
103         redirectErrorHandlerSecure = new RedirectErrorHandler("/redirecterror");
104         HttpContext c7 = httpServer.createContext("/redirecterror", redirectErrorHandler);
105         HttpContext c71 = httpsServer.createContext("/redirecterror", redirectErrorHandlerSecure);
106         delayHandler = new DelayHandler();
107         HttpContext c8 = httpServer.createContext("/delay", delayHandler);
108         HttpContext c81 = httpsServer.createContext("/delay", delayHandler);
109 
110         executor = Executors.newCachedThreadPool();
111         httpServer.setExecutor(executor);
112         httpsServer.setExecutor(executor);
113         ctx = new SimpleSSLContext().get();
114         httpsServer.setHttpsConfigurator(new HttpsConfigurator(ctx));
115         httpServer.start();
116         httpsServer.start();
117 
118         port = httpServer.getAddress().getPort();
119         System.out.println("HTTP server port = " + port);
120         httpsport = httpsServer.getAddress().getPort();
121         System.out.println("HTTPS server port = " + httpsport);
122         httproot = "http://localhost:" + port + "/";
123         httpsroot = "https://localhost:" + httpsport + "/";
124 
125         proxy = new ProxyServer(0, false);
126         proxyPort = proxy.getPort();
127         System.out.println("Proxy port = " + proxyPort);
128     }
129 
stop()130     public static void stop() throws IOException {
131         if (httpServer != null) {
132             httpServer.stop(0);
133         }
134         if (httpsServer != null) {
135             httpsServer.stop(0);
136         }
137         if (proxy != null) {
138             proxy.close();
139         }
140         if (executor != null) {
141             executor.shutdownNow();
142         }
143     }
144 
145     static class RedirectErrorHandler implements HttpHandler {
146 
147         String root;
148         volatile int count = 1;
149 
RedirectErrorHandler(String root)150         RedirectErrorHandler(String root) {
151             this.root = root;
152         }
153 
count()154         synchronized int count() {
155             return count;
156         }
157 
increment()158         synchronized void increment() {
159             count++;
160         }
161 
162         @Override
handle(HttpExchange t)163         public synchronized void handle(HttpExchange t)
164                 throws IOException {
165             byte[] buf = new byte[2048];
166             try (InputStream is = t.getRequestBody()) {
167                 while (is.read(buf) != -1) ;
168             }
169 
170             Headers map = t.getResponseHeaders();
171             String redirect = root + "/foo/" + Integer.toString(count);
172             increment();
173             map.add("Location", redirect);
174             t.sendResponseHeaders(301, -1);
175             t.close();
176         }
177     }
178 
179     static class RedirectHandler implements HttpHandler {
180 
181         String root;
182         volatile int count = 0;
183 
RedirectHandler(String root)184         RedirectHandler(String root) {
185             this.root = root;
186         }
187 
188         @Override
handle(HttpExchange t)189         public synchronized void handle(HttpExchange t)
190                 throws IOException {
191             byte[] buf = new byte[2048];
192             try (InputStream is = t.getRequestBody()) {
193                 while (is.read(buf) != -1) ;
194             }
195 
196             Headers map = t.getResponseHeaders();
197 
198             if (count++ < 1) {
199                 map.add("Location", root + "/foo/" + count);
200             } else {
201                 map.add("Location", SmokeTest.midSizedFilename);
202             }
203             t.sendResponseHeaders(301, -1);
204             t.close();
205         }
206 
count()207         int count() {
208             return count;
209         }
210 
reset()211         void reset() {
212             count = 0;
213         }
214     }
215 
216     static class KeepAliveHandler implements HttpHandler {
217 
218         volatile int counter = 0;
219         HashSet<Integer> portSet = new HashSet<>();
220         volatile int[] ports = new int[4];
221 
sleep(int n)222         void sleep(int n) {
223             try {
224                 Thread.sleep(n);
225             } catch (InterruptedException e) {
226             }
227         }
228 
229         @Override
handle(HttpExchange t)230         public synchronized void handle(HttpExchange t)
231                 throws IOException {
232             int remotePort = t.getRemoteAddress().getPort();
233             String result = "OK";
234 
235             int n = counter++;
236             /// First test
237             if (n < 4) {
238                 ports[n] = remotePort;
239             }
240             if (n == 3) {
241                 // check all values in ports[] are the same
242                 if (ports[0] != ports[1] || ports[2] != ports[3]
243                         || ports[0] != ports[2]) {
244                     result = "Error " + Integer.toString(n);
245                     System.out.println(result);
246                 }
247             }
248             // Second test
249             if (n >= 4 && n < 8) {
250                 // delay to ensure ports are different
251                 sleep(500);
252                 ports[n - 4] = remotePort;
253             }
254             if (n == 7) {
255                 // should be all different
256                 if (ports[0] == ports[1] || ports[2] == ports[3]
257                         || ports[0] == ports[2]) {
258                     result = "Error " + Integer.toString(n);
259                     System.out.println(result);
260                     System.out.printf("Ports: %d, %d, %d, %d\n",
261                                       ports[0], ports[1], ports[2], ports[3]);
262                 }
263                 // setup for third test
264                 for (int i = 0; i < 4; i++) {
265                     portSet.add(ports[i]);
266                 }
267             }
268             // Third test
269             if (n > 7) {
270                 // just check that port is one of the ones in portSet
271                 if (!portSet.contains(remotePort)) {
272                     System.out.println("UNEXPECTED REMOTE PORT " + remotePort);
273                     result = "Error " + Integer.toString(n);
274                     System.out.println(result);
275                 }
276             }
277             byte[] buf = new byte[2048];
278 
279             try (InputStream is = t.getRequestBody()) {
280                 while (is.read(buf) != -1) ;
281             }
282             t.sendResponseHeaders(200, result.length());
283             OutputStream o = t.getResponseBody();
284             o.write(result.getBytes("US-ASCII"));
285             t.close();
286         }
287     }
288 
289     static class DelayHandler implements HttpHandler {
290 
291         CyclicBarrier bar1 = new CyclicBarrier(2);
292         CyclicBarrier bar2 = new CyclicBarrier(2);
293         CyclicBarrier bar3 = new CyclicBarrier(2);
294 
barrier1()295         CyclicBarrier barrier1() {
296             return bar1;
297         }
298 
barrier2()299         CyclicBarrier barrier2() {
300             return bar2;
301         }
302 
303         @Override
handle(HttpExchange he)304         public synchronized void handle(HttpExchange he) throws IOException {
305             try(InputStream is = he.getRequestBody()) {
306                 is.readAllBytes();
307                 bar1.await();
308                 bar2.await();
309             } catch (InterruptedException | BrokenBarrierException e) {
310                 throw new IOException(e);
311             }
312             he.sendResponseHeaders(200, -1); // will probably fail
313             he.close();
314         }
315     }
316 }
317