View Javadoc
1   /*
2    * Copyright 2024 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  
17  package io.netty.testsuite_jpms.main;
18  
19  import io.netty.bootstrap.ServerBootstrap;
20  import io.netty.channel.IoHandlerFactory;
21  import io.netty.channel.EventLoopGroup;
22  import io.netty.channel.Channel;
23  import io.netty.channel.MultiThreadIoEventLoopGroup;
24  import io.netty.channel.ChannelOption;
25  import io.netty.channel.epoll.EpollIoHandler;
26  import io.netty.channel.epoll.EpollServerSocketChannel;
27  import io.netty.channel.kqueue.KQueueIoHandler;
28  import io.netty.channel.kqueue.KQueueServerSocketChannel;
29  import io.netty.channel.nio.NioIoHandler;
30  import io.netty.channel.socket.ServerSocketChannel;
31  import io.netty.channel.socket.nio.NioServerSocketChannel;
32  import io.netty.channel.uring.IoUringIoHandler;
33  import io.netty.channel.uring.IoUringServerSocketChannel;
34  import io.netty.handler.logging.LogLevel;
35  import io.netty.handler.logging.LoggingHandler;
36  import io.netty.handler.ssl.IdentityCipherSuiteFilter;
37  import io.netty.handler.ssl.SslContext;
38  import io.netty.handler.ssl.SslProvider;
39  import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
40  import io.netty.pkitesting.CertificateBuilder;
41  import io.netty.pkitesting.X509Bundle;
42  
43  import static io.netty.handler.ssl.SslContextBuilder.forServer;
44  
45  /**
46   * <p>An HTTP server that sends back the content of the received HTTP request
47   * in a pretty plaintext form.</p>
48   *
49   * <p>Running the server:
50   * <ul>
51   *     <li>./target/maven-jlink/default/bin/java
52   *     -m io.netty.testsuite_jpms.main/io.netty.testsuite_jpms.main.HttpHelloWorldServer</li>
53   *     <li>./target/maven-jlink/default/bin/http (shortcut)</li>
54   * </ul>
55   *
56   * <p>Running with OpenSSL requires to add the
57   * io.netty.internal.tcnative.openssl.${os.detected.name}.${os.detected.arch} module, e.g.
58   * ./target/maven-jlink/default/bin/java --add-modules io.netty.internal.tcnative.openssl.osx.aarch_64
59   * -m io.netty.testsuite_jpms.main/io.netty.testsuite_jpms.main.HttpHelloWorldServer --ssl --ssl-provider OPENSSL
60   *
61   * <p>Running with native requires to add io.netty.transport.kqueue.${os.detected.name}.${os.detected.arch}, e.g.
62   * ./target/maven-jlink/default/bin/java --add-modules io.netty.transport.kqueue.osx.aarch_64
63   * -m io.netty.testsuite_jpms.main/io.netty.testsuite_jpms.main.HttpHelloWorldServer --transport kqueue
64   */
65  public final class HttpHelloWorldServer {
66  
67      private HttpHelloWorldServer() {
68      }
69  
70      public static void main(String[] args) throws Exception {
71  
72          String transport = "nio";
73          boolean ssl = false;
74          SslProvider sslProvider = SslProvider.JDK;
75  
76          Integer port = null;
77          for (int i = 0; i < args.length; i++) {
78              if (args[i].equals("--help")) {
79                  System.out.println("usage: [options]");
80                  System.out.println("--ssl");
81                  System.out.println("--ssl-provider [ JDK | OPENSSL ]");
82                  System.out.println("--port <port>");
83                  System.out.println("--transport [ nio | kqueue | epoll | io_uring ]");
84                  System.exit(0);
85              }
86              if (args[i].equals("--ssl")) {
87                  ssl = true;
88              }
89              if (args[i].equals("--ssl-provider")) {
90                  if (i < args.length - 1) {
91                      sslProvider = SslProvider.valueOf(args[++i]);
92                  } else {
93                      System.exit(1);
94                  }
95              }
96              if (args[i].equals("--port")) {
97                  if (i < args.length - 1) {
98                      port = Integer.parseInt(args[++i]);
99                  } else {
100                     System.exit(1);
101                 }
102             }
103             if (args[i].equals("--transport")) {
104                 if (i < args.length - 1) {
105                     transport = args[++i];
106                 } else {
107                     System.exit(1);
108                 }
109             }
110         }
111 
112         if (port == null) {
113             port = ssl ? 8443 : 8080;
114         }
115 
116         IoHandlerFactory ioHandlerFactory;
117         Class<? extends ServerSocketChannel> serverSocketChannelFactory;
118         switch (transport) {
119             case "nio":
120                 ioHandlerFactory = NioIoHandler.newFactory();
121                 serverSocketChannelFactory = NioServerSocketChannel.class;
122                 break;
123             case "kqueue":
124                 ioHandlerFactory = KQueueIoHandler.newFactory();
125                 serverSocketChannelFactory = KQueueServerSocketChannel.class;
126                 break;
127             case "epoll":
128                 ioHandlerFactory = EpollIoHandler.newFactory();
129                 serverSocketChannelFactory = EpollServerSocketChannel.class;
130                 break;
131             case "io_uring":
132                 ioHandlerFactory = IoUringIoHandler.newFactory();
133                 serverSocketChannelFactory = IoUringServerSocketChannel.class;
134                 break;
135             default:
136                 System.exit(1);
137                 return;
138         }
139 
140         X509Bundle cert = new CertificateBuilder()
141                 .subject("cn=localhost")
142                 .setIsCertificateAuthority(true)
143                 .buildSelfSigned();
144 
145         SslContext sslContext;
146         if (ssl) {
147             sslContext = forServer(cert.toKeyManagerFactory())
148                     .sslProvider(sslProvider)
149                     .protocols("TLSv1.2")
150                     .trustManager(InsecureTrustManagerFactory.INSTANCE)
151                     .ciphers(null, IdentityCipherSuiteFilter.INSTANCE)
152                     .sessionCacheSize(0)
153                     .sessionTimeout(0)
154                     .build();
155         } else {
156             sslContext = null;
157         }
158 
159         // Configure the server.
160         EventLoopGroup bossGroup = new MultiThreadIoEventLoopGroup(1, ioHandlerFactory);
161         EventLoopGroup workerGroup = new MultiThreadIoEventLoopGroup(ioHandlerFactory);
162         try {
163             ServerBootstrap b = new ServerBootstrap();
164             b.option(ChannelOption.SO_BACKLOG, 1024);
165             b.group(bossGroup, workerGroup)
166              .channel(serverSocketChannelFactory)
167              .handler(new LoggingHandler(LogLevel.INFO))
168              .childHandler(new HttpHelloWorldServerInitializer(sslContext));
169 
170             Channel ch = b.bind(port).sync().channel();
171 
172             System.err.println("Open your web browser and navigate to " +
173                     (ssl? "https" : "http") + "://127.0.0.1:" + port + '/');
174 
175             ch.closeFuture().sync();
176         } finally {
177             bossGroup.shutdownGracefully();
178             workerGroup.shutdownGracefully();
179         }
180     }
181 }