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