| /* | |
| * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| /** | |
| * library /test/lib / | |
| * build jdk.test.lib.net.SimpleSSLContext ProxyServer | |
| * compile ../../../com/sun/net/httpserver/LogFilter.java | |
| * compile ../../../com/sun/net/httpserver/EchoHandler.java | |
| * compile ../../../com/sun/net/httpserver/FileServerHandler.java | |
| */ | |
| import com.sun.net.httpserver.Headers; | |
| import com.sun.net.httpserver.HttpContext; | |
| import com.sun.net.httpserver.HttpExchange; | |
| import com.sun.net.httpserver.HttpHandler; | |
| import com.sun.net.httpserver.HttpServer; | |
| import com.sun.net.httpserver.HttpsServer; | |
| import java.io.IOException; | |
| import java.io.InputStream; | |
| import java.io.OutputStream; | |
| import java.net.InetAddress; | |
| import java.net.InetSocketAddress; | |
| import java.nio.file.Path; | |
| import java.util.HashSet; | |
| import java.util.concurrent.BrokenBarrierException; | |
| import java.util.concurrent.CyclicBarrier; | |
| import java.util.concurrent.ExecutorService; | |
| import java.util.concurrent.Executors; | |
| import java.util.logging.ConsoleHandler; | |
| import java.util.logging.Level; | |
| import java.util.logging.Logger; | |
| import javax.net.ssl.SSLContext; | |
| import jdk.httpclient.test.lib.common.TestServerConfigurator; | |
| import jdk.test.lib.net.SimpleSSLContext; | |
| public class LightWeightHttpServer { | |
| static SSLContext ctx; | |
| static HttpServer httpServer; | |
| static HttpsServer httpsServer; | |
| static ExecutorService executor; | |
| static int port; | |
| static int httpsport; | |
| static String httproot; | |
| static String httpsroot; | |
| static ProxyServer proxy; | |
| static int proxyPort; | |
| static RedirectErrorHandler redirectErrorHandler, redirectErrorHandlerSecure; | |
| static RedirectHandler redirectHandler, redirectHandlerSecure; | |
| static DelayHandler delayHandler; | |
| static final String midSizedFilename = "/files/notsobigfile.txt"; | |
| static final String smallFilename = "/files/smallfile.txt"; | |
| static Path midSizedFile; | |
| static Path smallFile; | |
| static String fileroot; | |
| public static void initServer() throws IOException { | |
| Logger logger = Logger.getLogger("com.sun.net.httpserver"); | |
| ConsoleHandler ch = new ConsoleHandler(); | |
| logger.setLevel(Level.ALL); | |
| ch.setLevel(Level.ALL); | |
| logger.addHandler(ch); | |
| String root = System.getProperty("test.src", ".") + "/docs"; | |
| InetSocketAddress addr = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); | |
| httpServer = HttpServer.create(addr, 0); | |
| if (httpServer instanceof HttpsServer) { | |
| throw new RuntimeException("should not be httpsserver"); | |
| } | |
| httpsServer = HttpsServer.create(addr, 0); | |
| HttpHandler h = new FileServerHandler(root); | |
| HttpContext c1 = httpServer.createContext("/files", h); | |
| HttpContext c2 = httpsServer.createContext("/files", h); | |
| HttpContext c3 = httpServer.createContext("/echo", new EchoHandler()); | |
| redirectHandler = new RedirectHandler("/redirect"); | |
| redirectHandlerSecure = new RedirectHandler("/redirect"); | |
| HttpContext c4 = httpServer.createContext("/redirect", redirectHandler); | |
| HttpContext c41 = httpsServer.createContext("/redirect", redirectHandlerSecure); | |
| HttpContext c5 = httpsServer.createContext("/echo", new EchoHandler()); | |
| HttpContext c6 = httpServer.createContext("/keepalive", new KeepAliveHandler()); | |
| redirectErrorHandler = new RedirectErrorHandler("/redirecterror"); | |
| redirectErrorHandlerSecure = new RedirectErrorHandler("/redirecterror"); | |
| HttpContext c7 = httpServer.createContext("/redirecterror", redirectErrorHandler); | |
| HttpContext c71 = httpsServer.createContext("/redirecterror", redirectErrorHandlerSecure); | |
| delayHandler = new DelayHandler(); | |
| HttpContext c8 = httpServer.createContext("/delay", delayHandler); | |
| HttpContext c81 = httpsServer.createContext("/delay", delayHandler); | |
| executor = Executors.newCachedThreadPool(); | |
| httpServer.setExecutor(executor); | |
| httpsServer.setExecutor(executor); | |
| ctx = new SimpleSSLContext().get(); | |
| httpsServer.setHttpsConfigurator(new TestServerConfigurator(addr.getAddress(), ctx)); | |
| httpServer.start(); | |
| httpsServer.start(); | |
| port = httpServer.getAddress().getPort(); | |
| System.out.println("HTTP server port = " + port); | |
| httpsport = httpsServer.getAddress().getPort(); | |
| System.out.println("HTTPS server port = " + httpsport); | |
| httproot = "http://" + makeServerAuthority(httpServer.getAddress()) + "/"; | |
| httpsroot = "https://" + makeServerAuthority(httpsServer.getAddress()) + "/"; | |
| proxy = new ProxyServer(0, false); | |
| proxyPort = proxy.getPort(); | |
| System.out.println("Proxy port = " + proxyPort); | |
| } | |
| private static String makeServerAuthority(final InetSocketAddress addr) { | |
| final String hostIP = addr.getAddress().getHostAddress(); | |
| // escape for ipv6 | |
| final String h = hostIP.contains(":") ? "[" + hostIP + "]" : hostIP; | |
| return h + ":" + addr.getPort(); | |
| } | |
| public static void stop() throws IOException { | |
| if (httpServer != null) { | |
| httpServer.stop(0); | |
| } | |
| if (httpsServer != null) { | |
| httpsServer.stop(0); | |
| } | |
| if (proxy != null) { | |
| proxy.close(); | |
| } | |
| if (executor != null) { | |
| executor.shutdownNow(); | |
| } | |
| } | |
| static class RedirectErrorHandler implements HttpHandler { | |
| String root; | |
| volatile int count = 1; | |
| RedirectErrorHandler(String root) { | |
| this.root = root; | |
| } | |
| synchronized int count() { | |
| return count; | |
| } | |
| synchronized void increment() { | |
| count++; | |
| } | |
| @Override | |
| public synchronized void handle(HttpExchange t) | |
| throws IOException { | |
| byte[] buf = new byte[2048]; | |
| try (InputStream is = t.getRequestBody()) { | |
| while (is.read(buf) != -1) ; | |
| } | |
| Headers map = t.getResponseHeaders(); | |
| String redirect = root + "/foo/" + Integer.toString(count); | |
| increment(); | |
| map.add("Location", redirect); | |
| t.sendResponseHeaders(301, -1); | |
| t.close(); | |
| } | |
| } | |
| static class RedirectHandler implements HttpHandler { | |
| String root; | |
| volatile int count = 0; | |
| RedirectHandler(String root) { | |
| this.root = root; | |
| } | |
| @Override | |
| public synchronized void handle(HttpExchange t) | |
| throws IOException { | |
| byte[] buf = new byte[2048]; | |
| try (InputStream is = t.getRequestBody()) { | |
| while (is.read(buf) != -1) ; | |
| } | |
| Headers map = t.getResponseHeaders(); | |
| if (count++ < 1) { | |
| map.add("Location", root + "/foo/" + count); | |
| } else { | |
| map.add("Location", SmokeTest.midSizedFilename); | |
| } | |
| t.sendResponseHeaders(301, -1); | |
| t.close(); | |
| } | |
| int count() { | |
| return count; | |
| } | |
| void reset() { | |
| count = 0; | |
| } | |
| } | |
| static class KeepAliveHandler implements HttpHandler { | |
| volatile int counter = 0; | |
| HashSet<Integer> portSet = new HashSet<>(); | |
| volatile int[] ports = new int[4]; | |
| void sleep(int n) { | |
| try { | |
| Thread.sleep(n); | |
| } catch (InterruptedException e) { | |
| } | |
| } | |
| @Override | |
| public synchronized void handle(HttpExchange t) | |
| throws IOException { | |
| int remotePort = t.getRemoteAddress().getPort(); | |
| String result = "OK"; | |
| int n = counter++; | |
| /// First test | |
| if (n < 4) { | |
| ports[n] = remotePort; | |
| } | |
| if (n == 3) { | |
| // check all values in ports[] are the same | |
| if (ports[0] != ports[1] || ports[2] != ports[3] | |
| || ports[0] != ports[2]) { | |
| result = "Error " + Integer.toString(n); | |
| System.out.println(result); | |
| } | |
| } | |
| // Second test | |
| if (n >= 4 && n < 8) { | |
| // delay to ensure ports are different | |
| sleep(500); | |
| ports[n - 4] = remotePort; | |
| } | |
| if (n == 7) { | |
| // should be all different | |
| if (ports[0] == ports[1] || ports[2] == ports[3] | |
| || ports[0] == ports[2]) { | |
| result = "Error " + Integer.toString(n); | |
| System.out.println(result); | |
| System.out.printf("Ports: %d, %d, %d, %d\n", | |
| ports[0], ports[1], ports[2], ports[3]); | |
| } | |
| // setup for third test | |
| for (int i = 0; i < 4; i++) { | |
| portSet.add(ports[i]); | |
| } | |
| } | |
| // Third test | |
| if (n > 7) { | |
| // just check that port is one of the ones in portSet | |
| if (!portSet.contains(remotePort)) { | |
| System.out.println("UNEXPECTED REMOTE PORT " + remotePort); | |
| result = "Error " + Integer.toString(n); | |
| System.out.println(result); | |
| } | |
| } | |
| byte[] buf = new byte[2048]; | |
| try (InputStream is = t.getRequestBody()) { | |
| while (is.read(buf) != -1) ; | |
| } | |
| t.sendResponseHeaders(200, result.length()); | |
| OutputStream o = t.getResponseBody(); | |
| o.write(result.getBytes("US-ASCII")); | |
| t.close(); | |
| } | |
| } | |
| static class DelayHandler implements HttpHandler { | |
| CyclicBarrier bar1 = new CyclicBarrier(2); | |
| CyclicBarrier bar2 = new CyclicBarrier(2); | |
| CyclicBarrier bar3 = new CyclicBarrier(2); | |
| CyclicBarrier barrier1() { | |
| return bar1; | |
| } | |
| CyclicBarrier barrier2() { | |
| return bar2; | |
| } | |
| @Override | |
| public synchronized void handle(HttpExchange he) throws IOException { | |
| try(InputStream is = he.getRequestBody()) { | |
| is.readAllBytes(); | |
| bar1.await(); | |
| bar2.await(); | |
| } catch (InterruptedException | BrokenBarrierException e) { | |
| throw new IOException(e); | |
| } | |
| he.sendResponseHeaders(200, -1); // will probably fail | |
| he.close(); | |
| } | |
| } | |
| } |