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.impl.nio.bootstrap;
28
29 import java.util.ArrayList;
30 import java.util.List;
31
32 import org.apache.hc.core5.function.Callback;
33 import org.apache.hc.core5.function.Decorator;
34 import org.apache.hc.core5.function.Supplier;
35 import org.apache.hc.core5.http.HttpRequestMapper;
36 import org.apache.hc.core5.http.config.CharCodingConfig;
37 import org.apache.hc.core5.http.config.Http1Config;
38 import org.apache.hc.core5.http.config.NamedElementChain;
39 import org.apache.hc.core5.http.impl.DefaultConnectionReuseStrategy;
40 import org.apache.hc.core5.http.impl.DefaultContentLengthStrategy;
41 import org.apache.hc.core5.http.impl.Http1StreamListener;
42 import org.apache.hc.core5.http.impl.HttpProcessors;
43 import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncServer;
44 import org.apache.hc.core5.http.impl.bootstrap.StandardFilter;
45 import org.apache.hc.core5.http.impl.nio.DefaultHttpRequestParserFactory;
46 import org.apache.hc.core5.http.impl.nio.DefaultHttpResponseWriterFactory;
47 import org.apache.hc.core5.http.impl.nio.ServerHttp1StreamDuplexerFactory;
48 import org.apache.hc.core5.http.impl.routing.RequestRouter;
49 import org.apache.hc.core5.http.nio.AsyncFilterHandler;
50 import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
51 import org.apache.hc.core5.http.nio.AsyncServerRequestHandler;
52 import org.apache.hc.core5.http.nio.HandlerFactory;
53 import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
54 import org.apache.hc.core5.http.nio.support.AsyncServerExpectationFilter;
55 import org.apache.hc.core5.http.nio.support.AsyncServerFilterChainElement;
56 import org.apache.hc.core5.http.nio.support.AsyncServerFilterChainExchangeHandlerFactory;
57 import org.apache.hc.core5.http.nio.support.BasicAsyncServerExpectationDecorator;
58 import org.apache.hc.core5.http.nio.support.BasicServerExchangeHandler;
59 import org.apache.hc.core5.http.nio.support.DefaultAsyncResponseExchangeHandlerFactory;
60 import org.apache.hc.core5.http.nio.support.TerminalAsyncServerFilter;
61 import org.apache.hc.core5.http.protocol.HttpProcessor;
62 import org.apache.hc.core5.http.protocol.UriPatternType;
63 import org.apache.hc.core5.http2.HttpVersionPolicy;
64 import org.apache.hc.core5.http2.config.H2Config;
65 import org.apache.hc.core5.http2.impl.H2Processors;
66 import org.apache.hc.core5.http2.impl.nio.H2StreamListener;
67 import org.apache.hc.core5.http2.impl.nio.ServerH2StreamMultiplexerFactory;
68 import org.apache.hc.core5.http2.impl.nio.ServerHttpProtocolNegotiationStarter;
69 import org.apache.hc.core5.http2.ssl.H2ServerTlsStrategy;
70 import org.apache.hc.core5.net.InetAddressUtils;
71 import org.apache.hc.core5.net.URIAuthority;
72 import org.apache.hc.core5.reactor.IOEventHandlerFactory;
73 import org.apache.hc.core5.reactor.IOReactorConfig;
74 import org.apache.hc.core5.reactor.IOSession;
75 import org.apache.hc.core5.reactor.IOSessionListener;
76 import org.apache.hc.core5.util.Args;
77 import org.apache.hc.core5.util.Timeout;
78
79
80
81
82
83
84 @SuppressWarnings("deprecation")
85 public class H2ServerBootstrap {
86
87 private final List<RequestRouter.Entry<Supplier<AsyncServerExchangeHandler>>> routeEntries;
88 private final List<FilterEntry<AsyncFilterHandler>> filters;
89 private String canonicalHostName;
90 private org.apache.hc.core5.http.protocol.LookupRegistry<Supplier<AsyncServerExchangeHandler>> lookupRegistry;
91 private HttpRequestMapper<Supplier<AsyncServerExchangeHandler>> requestRouter;
92 private IOReactorConfig ioReactorConfig;
93 private HttpProcessor httpProcessor;
94 private CharCodingConfig charCodingConfig;
95 private HttpVersionPolicy versionPolicy;
96 private H2Config h2Config;
97 private Http1Config http1Config;
98 private TlsStrategy tlsStrategy;
99 private Timeout handshakeTimeout;
100 private Decorator<IOSession> ioSessionDecorator;
101 private Callback<Exception> exceptionCallback;
102 private IOSessionListener sessionListener;
103 private H2StreamListener h2StreamListener;
104 private Http1StreamListener http1StreamListener;
105
106 private H2ServerBootstrap() {
107 this.routeEntries = new ArrayList<>();
108 this.filters = new ArrayList<>();
109 }
110
111 public static H2ServerBootstrap bootstrap() {
112 return new H2ServerBootstrap();
113 }
114
115
116
117
118
119
120 public final H2ServerBootstrap setCanonicalHostName(final String canonicalHostName) {
121 this.canonicalHostName = canonicalHostName;
122 return this;
123 }
124
125
126
127
128 public final H2ServerBootstrap setIOReactorConfig(final IOReactorConfig ioReactorConfig) {
129 this.ioReactorConfig = ioReactorConfig;
130 return this;
131 }
132
133
134
135
136 public final H2ServerBootstrap setHttpProcessor(final HttpProcessor httpProcessor) {
137 this.httpProcessor = httpProcessor;
138 return this;
139 }
140
141
142
143
144 public final H2ServerBootstrap setVersionPolicy(final HttpVersionPolicy versionPolicy) {
145 this.versionPolicy = versionPolicy;
146 return this;
147 }
148
149
150
151
152 public final H2ServerBootstrap setH2Config(final H2Config h2Config) {
153 this.h2Config = h2Config;
154 return this;
155 }
156
157
158
159
160 public final H2ServerBootstrap setHttp1Config(final Http1Config http1Config) {
161 this.http1Config = http1Config;
162 return this;
163 }
164
165
166
167
168 public final H2ServerBootstrap setCharset(final CharCodingConfig charCodingConfig) {
169 this.charCodingConfig = charCodingConfig;
170 return this;
171 }
172
173
174
175
176 public final H2ServerBootstrap setTlsStrategy(final TlsStrategy tlsStrategy) {
177 this.tlsStrategy = tlsStrategy;
178 return this;
179 }
180
181 public final H2ServerBootstrap setHandshakeTimeout(final Timeout handshakeTimeout) {
182 this.handshakeTimeout = handshakeTimeout;
183 return this;
184 }
185
186
187
188
189 public final H2ServerBootstrap setIOSessionDecorator(final Decorator<IOSession> ioSessionDecorator) {
190 this.ioSessionDecorator = ioSessionDecorator;
191 return this;
192 }
193
194
195
196
197 public final H2ServerBootstrap setExceptionCallback(final Callback<Exception> exceptionCallback) {
198 this.exceptionCallback = exceptionCallback;
199 return this;
200 }
201
202
203
204
205 public final H2ServerBootstrap setIOSessionListener(final IOSessionListener sessionListener) {
206 this.sessionListener = sessionListener;
207 return this;
208 }
209
210
211
212
213 public final H2ServerBootstrap setStreamListener(final H2StreamListener h2StreamListener) {
214 this.h2StreamListener = h2StreamListener;
215 return this;
216 }
217
218
219
220
221 public final H2ServerBootstrap setStreamListener(final Http1StreamListener http1StreamListener) {
222 this.http1StreamListener = http1StreamListener;
223 return this;
224 }
225
226
227
228
229 @Deprecated
230 public final H2ServerBootstrap setLookupRegistry(final org.apache.hc.core5.http.protocol.LookupRegistry<Supplier<AsyncServerExchangeHandler>> lookupRegistry) {
231 this.lookupRegistry = lookupRegistry;
232 return this;
233 }
234
235
236
237
238
239
240
241 public final H2ServerBootstrap setRequestRouter(final HttpRequestMapper<Supplier<AsyncServerExchangeHandler>> requestRouter) {
242 this.requestRouter = requestRouter;
243 return this;
244 }
245
246
247
248
249
250
251
252
253 public final H2ServerBootstrap register(final String uriPattern, final Supplier<AsyncServerExchangeHandler> supplier) {
254 Args.notBlank(uriPattern, "URI pattern");
255 Args.notNull(supplier, "Exchange handler supplier");
256 routeEntries.add(new RequestRouter.Entry<>(uriPattern, supplier));
257 return this;
258 }
259
260
261
262
263
264
265
266
267
268
269
270 public final H2ServerBootstrap register(final String hostname, final String uriPattern, final Supplier<AsyncServerExchangeHandler> supplier) {
271 Args.notBlank(hostname, "Hostname");
272 Args.notBlank(uriPattern, "URI pattern");
273 Args.notNull(supplier, "Exchange handler supplier");
274 routeEntries.add(new RequestRouter.Entry<>(hostname, uriPattern, supplier));
275 return this;
276 }
277
278
279
280
281 @Deprecated
282 public final H2ServerBootstrap registerVirtual(final String hostname, final String uriPattern, final Supplier<AsyncServerExchangeHandler> supplier) {
283 return register(hostname, uriPattern, supplier);
284 }
285
286
287
288
289
290
291
292
293 public final <T> H2ServerBootstrap register(
294 final String uriPattern,
295 final AsyncServerRequestHandler<T> requestHandler) {
296 register(uriPattern, () -> new BasicServerExchangeHandler<>(requestHandler));
297 return this;
298 }
299
300
301
302
303
304
305
306
307
308
309
310 public final <T> H2ServerBootstrap register(
311 final String hostname,
312 final String uriPattern,
313 final AsyncServerRequestHandler<T> requestHandler) {
314 registerVirtual(hostname, uriPattern, () -> new BasicServerExchangeHandler<>(requestHandler));
315 return this;
316 }
317
318
319
320
321 @Deprecated
322 public final <T> H2ServerBootstrap registerVirtual(
323 final String hostname,
324 final String uriPattern,
325 final AsyncServerRequestHandler<T> requestHandler) {
326 return register(hostname, uriPattern, requestHandler);
327 }
328
329
330
331
332 public final H2ServerBootstrap addFilterBefore(final String existing, final String name, final AsyncFilterHandler filterHandler) {
333 Args.notBlank(existing, "Existing");
334 Args.notBlank(name, "Name");
335 Args.notNull(filterHandler, "Filter handler");
336 filters.add(new FilterEntry<>(FilterEntry.Position.BEFORE, name, filterHandler, existing));
337 return this;
338 }
339
340
341
342
343 public final H2ServerBootstrap addFilterAfter(final String existing, final String name, final AsyncFilterHandler filterHandler) {
344 Args.notBlank(existing, "Existing");
345 Args.notBlank(name, "Name");
346 Args.notNull(filterHandler, "Filter handler");
347 filters.add(new FilterEntry<>(FilterEntry.Position.AFTER, name, filterHandler, existing));
348 return this;
349 }
350
351
352
353
354 public final H2ServerBootstrap replaceFilter(final String existing, final AsyncFilterHandler filterHandler) {
355 Args.notBlank(existing, "Existing");
356 Args.notNull(filterHandler, "Filter handler");
357 filters.add(new FilterEntry<>(FilterEntry.Position.REPLACE, existing, filterHandler, existing));
358 return this;
359 }
360
361
362
363
364 public final H2ServerBootstrap addFilterFirst(final String name, final AsyncFilterHandler filterHandler) {
365 Args.notNull(name, "Name");
366 Args.notNull(filterHandler, "Filter handler");
367 filters.add(new FilterEntry<>(FilterEntry.Position.FIRST, name, filterHandler, null));
368 return this;
369 }
370
371
372
373
374 public final H2ServerBootstrap addFilterLast(final String name, final AsyncFilterHandler filterHandler) {
375 Args.notNull(name, "Name");
376 Args.notNull(filterHandler, "Filter handler");
377 filters.add(new FilterEntry<>(FilterEntry.Position.LAST, name, filterHandler, null));
378 return this;
379 }
380
381 public HttpAsyncServer create() {
382 final String actualCanonicalHostName = canonicalHostName != null ? canonicalHostName : InetAddressUtils.getCanonicalLocalHostName();
383 final HttpRequestMapper<Supplier<AsyncServerExchangeHandler>> requestRouterCopy;
384 if (lookupRegistry != null && requestRouter == null) {
385 final org.apache.hc.core5.http.protocol.RequestHandlerRegistry<Supplier<AsyncServerExchangeHandler>> handlerRegistry = new org.apache.hc.core5.http.protocol.RequestHandlerRegistry<>(
386 actualCanonicalHostName,
387 () -> lookupRegistry != null ? lookupRegistry : new org.apache.hc.core5.http.protocol.UriPatternMatcher<>());
388 for (final RequestRouter.Entry<Supplier<AsyncServerExchangeHandler>> entry: routeEntries) {
389 handlerRegistry.register(entry.uriAuthority != null ? entry.uriAuthority.getHostName() : null, entry.route.pattern, entry.route.handler);
390 }
391 requestRouterCopy = handlerRegistry;
392 } else {
393 if (routeEntries.isEmpty()) {
394 requestRouterCopy = requestRouter;
395 } else {
396 requestRouterCopy = RequestRouter.create(
397 new URIAuthority(actualCanonicalHostName),
398 UriPatternType.URI_PATTERN,
399 routeEntries,
400 RequestRouter.IGNORE_PORT_AUTHORITY_RESOLVER,
401 requestRouter);
402 }
403 }
404
405 final HandlerFactory<AsyncServerExchangeHandler> handlerFactory;
406 if (!filters.isEmpty()) {
407 final NamedElementChain<AsyncFilterHandler> filterChainDefinition = new NamedElementChain<>();
408 filterChainDefinition.addLast(
409 new TerminalAsyncServerFilter(new DefaultAsyncResponseExchangeHandlerFactory(requestRouterCopy)),
410 StandardFilter.MAIN_HANDLER.name());
411 filterChainDefinition.addFirst(
412 new AsyncServerExpectationFilter(),
413 StandardFilter.EXPECT_CONTINUE.name());
414
415 for (final FilterEntry<AsyncFilterHandler> entry: filters) {
416 switch (entry.position) {
417 case AFTER:
418 filterChainDefinition.addAfter(entry.existing, entry.filterHandler, entry.name);
419 break;
420 case BEFORE:
421 filterChainDefinition.addBefore(entry.existing, entry.filterHandler, entry.name);
422 break;
423 case REPLACE:
424 filterChainDefinition.replace(entry.existing, entry.filterHandler);
425 break;
426 case FIRST:
427 filterChainDefinition.addFirst(entry.filterHandler, entry.name);
428 break;
429 case LAST:
430
431
432 filterChainDefinition.addBefore(StandardFilter.MAIN_HANDLER.name(), entry.filterHandler, entry.name);
433 break;
434 }
435 }
436
437 NamedElementChain<AsyncFilterHandler>.Node current = filterChainDefinition.getLast();
438 AsyncServerFilterChainElement execChain = null;
439 while (current != null) {
440 execChain = new AsyncServerFilterChainElement(current.getValue(), execChain);
441 current = current.getPrevious();
442 }
443
444 handlerFactory = new AsyncServerFilterChainExchangeHandlerFactory(execChain, exceptionCallback);
445 } else {
446 handlerFactory = new DefaultAsyncResponseExchangeHandlerFactory(requestRouterCopy,
447 handler -> new BasicAsyncServerExpectationDecorator(handler, exceptionCallback));
448 }
449
450 final ServerH2StreamMultiplexerFactory http2StreamHandlerFactory = new ServerH2StreamMultiplexerFactory(
451 httpProcessor != null ? httpProcessor : H2Processors.server(),
452 handlerFactory,
453 h2Config != null ? h2Config : H2Config.DEFAULT,
454 charCodingConfig != null ? charCodingConfig : CharCodingConfig.DEFAULT,
455 h2StreamListener);
456
457 final TlsStrategy actualTlsStrategy = tlsStrategy != null ? tlsStrategy : new H2ServerTlsStrategy();
458
459 final ServerHttp1StreamDuplexerFactory http1StreamHandlerFactory = new ServerHttp1StreamDuplexerFactory(
460 httpProcessor != null ? httpProcessor : HttpProcessors.server(),
461 handlerFactory,
462 http1Config != null ? http1Config : Http1Config.DEFAULT,
463 charCodingConfig != null ? charCodingConfig : CharCodingConfig.DEFAULT,
464 DefaultConnectionReuseStrategy.INSTANCE,
465 new DefaultHttpRequestParserFactory(http1Config),
466 new DefaultHttpResponseWriterFactory(http1Config),
467 DefaultContentLengthStrategy.INSTANCE,
468 DefaultContentLengthStrategy.INSTANCE,
469 http1StreamListener);
470
471 final IOEventHandlerFactory ioEventHandlerFactory = new ServerHttpProtocolNegotiationStarter(
472 http1StreamHandlerFactory,
473 http2StreamHandlerFactory,
474 versionPolicy != null ? versionPolicy : HttpVersionPolicy.NEGOTIATE,
475 actualTlsStrategy,
476 handshakeTimeout);
477
478 return new HttpAsyncServer(ioEventHandlerFactory, ioReactorConfig, ioSessionDecorator, exceptionCallback,
479 sessionListener, actualCanonicalHostName);
480 }
481
482 }