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