1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.apache.hc.core5.http2.examples;
28
29 import java.io.IOException;
30 import java.net.InetSocketAddress;
31 import java.time.Instant;
32 import java.util.List;
33 import java.util.concurrent.ExecutionException;
34 import java.util.concurrent.Future;
35
36 import org.apache.hc.core5.http.ContentType;
37 import org.apache.hc.core5.http.EndpointDetails;
38 import org.apache.hc.core5.http.EntityDetails;
39 import org.apache.hc.core5.http.Header;
40 import org.apache.hc.core5.http.HttpException;
41 import org.apache.hc.core5.http.HttpHeaders;
42 import org.apache.hc.core5.http.HttpRequest;
43 import org.apache.hc.core5.http.HttpResponse;
44 import org.apache.hc.core5.http.Message;
45 import org.apache.hc.core5.http.NameValuePair;
46 import org.apache.hc.core5.http.URIScheme;
47 import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncServer;
48 import org.apache.hc.core5.http.message.BasicHttpResponse;
49 import org.apache.hc.core5.http.nio.AsyncEntityConsumer;
50 import org.apache.hc.core5.http.nio.AsyncRequestConsumer;
51 import org.apache.hc.core5.http.nio.AsyncServerRequestHandler;
52 import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers;
53 import org.apache.hc.core5.http.nio.entity.DiscardingEntityConsumer;
54 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
55 import org.apache.hc.core5.http.nio.support.AbstractServerExchangeHandler;
56 import org.apache.hc.core5.http.nio.support.BasicRequestConsumer;
57 import org.apache.hc.core5.http.nio.support.BasicResponseProducer;
58 import org.apache.hc.core5.http.protocol.HttpContext;
59 import org.apache.hc.core5.http.protocol.HttpCoreContext;
60 import org.apache.hc.core5.http2.HttpVersionPolicy;
61 import org.apache.hc.core5.http2.config.H2Config;
62 import org.apache.hc.core5.http2.impl.nio.bootstrap.H2ServerBootstrap;
63 import org.apache.hc.core5.io.CloseMode;
64 import org.apache.hc.core5.net.WWWFormCodec;
65 import org.apache.hc.core5.reactor.IOReactorConfig;
66 import org.apache.hc.core5.reactor.ListenerEndpoint;
67 import org.apache.hc.core5.util.TimeValue;
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86 public class H2GreetingServer {
87 public static void main(final String[] args) throws ExecutionException, InterruptedException {
88 int port = 8080;
89 if (args.length >= 1) {
90 port = Integer.parseInt(args[0]);
91 }
92
93 final HttpAsyncServer server = H2ServerBootstrap.bootstrap()
94 .setH2Config(H2Config.DEFAULT)
95 .setIOReactorConfig(IOReactorConfig.DEFAULT)
96 .setVersionPolicy(HttpVersionPolicy.NEGOTIATE)
97
98
99 .register("*", CustomServerExchangeHandler::new)
100 .create();
101
102
103 Runtime.getRuntime().addShutdownHook(new Thread(() -> {
104 System.out.println("HTTP server shutting down");
105 server.close(CloseMode.GRACEFUL);
106 }));
107
108 server.start();
109 final Future<ListenerEndpoint> future = server.listen(new InetSocketAddress(port), URIScheme.HTTP);
110 final ListenerEndpoint listenerEndpoint = future.get();
111 System.out.println("Listening on " + listenerEndpoint.getAddress());
112 server.awaitShutdown(TimeValue.ofDays(Long.MAX_VALUE));
113 }
114
115 static class CustomServerExchangeHandler extends AbstractServerExchangeHandler<Message<HttpRequest, String>> {
116
117
118 @Override
119 protected AsyncRequestConsumer<Message<HttpRequest, String>> supplyConsumer(
120 final HttpRequest request,
121 final EntityDetails entityDetails,
122 final HttpContext context) {
123
124 AsyncEntityConsumer<String> entityConsumer = new DiscardingEntityConsumer<>();
125
126 if (entityDetails != null) {
127 entityConsumer = new StringAsyncEntityConsumer();
128 }
129
130 return new BasicRequestConsumer<>(entityConsumer);
131
132 }
133
134 @Override
135 protected void handle(final Message<HttpRequest, String> requestMessage,
136 final AsyncServerRequestHandler.ResponseTrigger responseTrigger,
137 final HttpContext localContext) throws HttpException, IOException {
138
139 final HttpCoreContext context = HttpCoreContext.cast(localContext);
140 final EndpointDetails endpoint = context.getEndpointDetails();
141 final HttpRequest req = requestMessage.getHead();
142 final String httpEntity = requestMessage.getBody();
143
144
145 final HttpResponse resp = new BasicHttpResponse(200);
146
147
148 System.out.printf("[%s] %s %s %s%n", Instant.now(),
149 endpoint != null ? endpoint.getRemoteAddress() : null,
150 req.getMethod(),
151 req.getPath());
152
153
154 if (httpEntity == null) {
155 responseTrigger.submitResponse(
156 new BasicResponseProducer(resp), context);
157 return;
158 }
159
160
161 final Header cth = req.getHeader(HttpHeaders.CONTENT_TYPE);
162 final ContentType contentType = cth != null ? ContentType.parse(cth.getValue()) : null;
163 String name = "stranger";
164 if (contentType != null && contentType.isSameMimeType(ContentType.APPLICATION_FORM_URLENCODED)) {
165
166
167 final List<NameValuePair> args = WWWFormCodec.parse(httpEntity, contentType.getCharset());
168 if (!args.isEmpty()) {
169 name = args.get(0).getValue();
170 }
171 }
172
173
174 final String greeting = String.format("Hello %s\n", name);
175 responseTrigger.submitResponse(
176 new BasicResponseProducer(resp, AsyncEntityProducers.create(greeting)), context);
177 }
178 }
179
180 }
181