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