HelloWebServer.java 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. package hello;
  2. import com.fasterxml.jackson.databind.ObjectMapper;
  3. import org.microhttp.EventLoop;
  4. import org.microhttp.Header;
  5. import org.microhttp.LogEntry;
  6. import org.microhttp.Logger;
  7. import org.microhttp.Options;
  8. import org.microhttp.Request;
  9. import org.microhttp.Response;
  10. import java.io.IOException;
  11. import java.nio.charset.StandardCharsets;
  12. import java.time.Duration;
  13. import java.time.Instant;
  14. import java.time.ZoneOffset;
  15. import java.time.format.DateTimeFormatter;
  16. import java.util.List;
  17. import java.util.function.Consumer;
  18. public class HelloWebServer {
  19. static final String MESSAGE = "Hello, World!";
  20. static final byte[] TEXT_BYTES = MESSAGE.getBytes(StandardCharsets.UTF_8);
  21. static final String SERVER = "microhttp";
  22. static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.RFC_1123_DATE_TIME.withZone(ZoneOffset.UTC);
  23. static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
  24. final int port;
  25. volatile String date = DATE_FORMATTER.format(Instant.now());
  26. record JsonMessage(String message) {
  27. }
  28. HelloWebServer(int port) {
  29. this.port = port;
  30. }
  31. void start() throws IOException {
  32. startUpdater();
  33. Options options = new Options()
  34. .withHost(null) // wildcard any-address binding
  35. .withPort(port)
  36. .withReuseAddr(true)
  37. .withReusePort(true)
  38. .withAcceptLength(8_192)
  39. .withMaxRequestSize(1_024 * 1_024)
  40. .withReadBufferSize(1_024 * 64)
  41. .withResolution(Duration.ofMillis(1_000))
  42. .withRequestTimeout(Duration.ofSeconds(90));
  43. EventLoop eventLoop = new EventLoop(options, new DisabledLogger(), this::handle);
  44. eventLoop.start();
  45. }
  46. void startUpdater() {
  47. Thread thread = new Thread(this::runDateUpdater);
  48. thread.setDaemon(true);
  49. thread.setPriority(Thread.MIN_PRIORITY);
  50. thread.start();
  51. }
  52. void runDateUpdater() {
  53. while (true) {
  54. try {
  55. Thread.sleep(1_000);
  56. } catch (InterruptedException e) {
  57. return;
  58. }
  59. date = DATE_FORMATTER.format(Instant.now());
  60. }
  61. }
  62. void handle(Request request, Consumer<Response> callback) {
  63. if (request.uri().equals("/plaintext")) {
  64. List<Header> headers = List.of(
  65. new Header("Content-Type", "text/plain"),
  66. new Header("Date", date),
  67. new Header("Server", SERVER));
  68. callback.accept(new Response(200, "OK", headers, TEXT_BYTES));
  69. } else if (request.uri().equals("/json")) {
  70. List<Header> headers = List.of(
  71. new Header("Content-Type", "application/json"),
  72. new Header("Date", date),
  73. new Header("Server", SERVER));
  74. callback.accept(new Response(200, "OK", headers, jsonBody()));
  75. } else {
  76. List<Header> headers = List.of(
  77. new Header("Date", date),
  78. new Header("Server", SERVER));
  79. callback.accept(new Response(404, "Not Found", headers, new byte[0]));
  80. }
  81. }
  82. static byte[] jsonBody() {
  83. try {
  84. return OBJECT_MAPPER.writeValueAsBytes(new JsonMessage(MESSAGE));
  85. } catch (IOException e) {
  86. throw new RuntimeException(e);
  87. }
  88. }
  89. public static void main(String[] args) throws IOException {
  90. int port = args.length > 0
  91. ? Integer.parseInt(args[0])
  92. : 8080;
  93. new HelloWebServer(port).start();
  94. }
  95. static class DisabledLogger implements Logger {
  96. @Override
  97. public boolean enabled() {
  98. return false;
  99. }
  100. @Override
  101. public void log(LogEntry... logEntries) {
  102. }
  103. @Override
  104. public void log(Exception e, LogEntry... logEntries) {
  105. }
  106. }
  107. }