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