|
1 | 1 | # httpserver |
2 | 2 |
|
3 | | -A zero-dependency implementation of the JDK com.sun.net.httpserver.HttpServer specification with a few significant enhancements. |
| 3 | +Zero-dependency implementation of the JDK [`com.sun.net.httpserver.HttpServer` specification](https://docs.oracle.com/en/java/javase/21/docs/api/jdk.httpserver/com/sun/net/httpserver/package-summary.html) with a few significant enhancements. |
4 | 4 |
|
5 | | -It adds websocket support using modified source from nanohttpd. |
6 | | - |
7 | | -It has basic server-side proxy support using [ProxyHandler](https://github.com/robaho/httpserver/blob/main/src/main/java/robaho/net/httpserver/extras/ProxyHandler.java). |
8 | | - |
9 | | -ProxyHandler also supports tunneling proxies using CONNECT for https. |
10 | | - |
11 | | -It supports Http2 [RFC 9113](https://www.rfc-editor.org/rfc/rfc9113.html) |
| 5 | +- WebSocket support using modified source code from nanohttpd. |
| 6 | +- Server-side proxy support using [ProxyHandler](https://github.com/robaho/httpserver/blob/main/src/main/java/robaho/net/httpserver/extras/ProxyHandler.java). (Tunneling proxies are also supported using CONNECT for https.) |
| 7 | +- HTTP/2 [RFC 9113](https://www.rfc-editor.org/rfc/rfc9113.html) support |
| 8 | +- Performance enhancements such as proper HTTP pipelining, optimized String parsing, etc. |
12 | 9 |
|
13 | 10 | All async functionality has been removed. All synchronized blocks were removed in favor of other Java concurrency concepts. |
14 | 11 |
|
15 | 12 | The end result is an implementation that easily integrates with Virtual Threads available in JDK 21 - simply set a virtual thread based ExecutorService. |
16 | 13 |
|
17 | | -Improved performance by more than **10x** over the JDK implementation, using http pipelining, optimized String parsing, etc. |
| 14 | +Improves performance by more than **10x** over the JDK implementation. |
18 | 15 |
|
19 | 16 | Designed for embedding with only a 90kb jar and zero dependencies. |
20 | 17 |
|
21 | 18 | ## background |
22 | 19 |
|
23 | | -The JDK httpserver implementation has no support for connection upgrades, so it is not possible to add websocket support. |
| 20 | +The built-in JDK httpserver implementation has no support for connection upgrades, so it is not possible to add websocket support. |
24 | 21 |
|
25 | 22 | Additionally, the code still has a lot of async - e.g. using SSLEngine to provide SSL support - which makes it more difficult to understand and enhance. |
26 | 23 |
|
27 | | -The streams based processing and thread per connection design simplifies the code substantially. |
| 24 | +The stream-based processing and thread-per-connection design simplifies the code substantially. |
28 | 25 |
|
29 | 26 | ## testing |
30 | 27 |
|
31 | | -Nearly all of the tests were included from the JDK so this version should be highly compliant and reliable. |
| 28 | +Nearly all tests were included from the JDK, so this version should be highly compliant and reliable. |
32 | 29 |
|
33 | 30 | ## using |
34 | 31 |
|
35 | | -Set the default HttpServer provider when starting the jvm: |
| 32 | +The JDK will automatically use `robaho.net.httpserver.DefaultHttpServerProvider` in the place of the default implementation when the jar is placed on the class/module path. If there are multiple `HttpServer` providers on the classpath, we can use the following property when starting the JVM to specify the correct one <code>-Dcom.sun.net.httpserver.HttpServerProvider=robaho.net.httpserver.DefaultHttpServerProvider</code> |
36 | 33 |
|
37 | | -<code>-Dcom.sun.net.httpserver.HttpServerProvider=robaho.net.httpserver.DefaultHttpServerProvider</code> |
| 34 | +Alternatively, you can instantiate the server directly using [this](https://github.com/robaho/httpserver/blob/main/src/main/java/robaho/net/httpserver/DefaultHttpServerProvider.java#L33). |
38 | 35 |
|
39 | | -or instantiate the server directly using [this](https://github.com/robaho/httpserver/blob/main/src/main/java/robaho/net/httpserver/DefaultHttpServerProvider.java#L33). |
40 | | - |
41 | | -or the service loader will automatically find it when the jar is placed on the class path when using the standard HttpServer service provider. |
| 36 | +### Example Usage |
| 37 | +```java |
| 38 | +import java.io.IOException; |
| 39 | +import java.io.OutputStream; |
| 40 | +import java.net.InetSocketAddress; |
| 41 | + |
| 42 | +import com.sun.net.httpserver.HttpExchange; |
| 43 | +import com.sun.net.httpserver.HttpHandler; |
| 44 | +import com.sun.net.httpserver.HttpServer; |
| 45 | + |
| 46 | +public class Test { |
| 47 | + |
| 48 | + public static void main(String[] args) throws Exception { |
| 49 | + HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0); |
| 50 | + server.createContext("/", new MyHandler()); |
| 51 | + server.setExecutor(Executors.newVirtualThreadPerTaskExecutor()); // sets virtual thread executor |
| 52 | + server.start(); |
| 53 | + } |
| 54 | + |
| 55 | + static class MyHandler implements HttpHandler { |
| 56 | + @Override |
| 57 | + public void handle(HttpExchange exchange) throws IOException { |
| 58 | + String response = "This is the response"; |
| 59 | + byte[] bytes = response.getBytes(); |
| 60 | + |
| 61 | + // -1 means no content, 0 means unknown content length |
| 62 | + var contentLength = bytes.length == 0 ? -1 : bytes.length; |
| 63 | + |
| 64 | + try (OutputStream os = exchange.getResponseBody()) { |
| 65 | + exchange.sendResponseHeaders(200, contentLength); |
| 66 | + os.write(bytes); |
| 67 | + } |
| 68 | + } |
| 69 | + } |
| 70 | +} |
| 71 | +``` |
42 | 72 |
|
43 | 73 | ## performance |
44 | 74 |
|
|
0 commit comments