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.http.impl.bootstrap;
28
29 import java.net.InetAddress;
30 import java.util.ArrayList;
31 import java.util.List;
32
33 import javax.net.ServerSocketFactory;
34 import javax.net.ssl.SSLContext;
35 import javax.net.ssl.SSLParameters;
36 import javax.net.ssl.SSLServerSocketFactory;
37
38 import org.apache.hc.core5.function.Callback;
39 import org.apache.hc.core5.http.ClassicHttpResponse;
40 import org.apache.hc.core5.http.ConnectionReuseStrategy;
41 import org.apache.hc.core5.http.ExceptionListener;
42 import org.apache.hc.core5.http.HttpRequestMapper;
43 import org.apache.hc.core5.http.HttpResponseFactory;
44 import org.apache.hc.core5.http.URIScheme;
45 import org.apache.hc.core5.http.config.CharCodingConfig;
46 import org.apache.hc.core5.http.config.Http1Config;
47 import org.apache.hc.core5.http.config.NamedElementChain;
48 import org.apache.hc.core5.http.impl.DefaultConnectionReuseStrategy;
49 import org.apache.hc.core5.http.impl.Http1StreamListener;
50 import org.apache.hc.core5.http.impl.HttpProcessors;
51 import org.apache.hc.core5.http.impl.io.DefaultBHttpServerConnection;
52 import org.apache.hc.core5.http.impl.io.DefaultBHttpServerConnectionFactory;
53 import org.apache.hc.core5.http.impl.io.DefaultClassicHttpResponseFactory;
54 import org.apache.hc.core5.http.impl.io.HttpService;
55 import org.apache.hc.core5.http.impl.routing.RequestRouter;
56 import org.apache.hc.core5.http.io.HttpConnectionFactory;
57 import org.apache.hc.core5.http.io.HttpFilterHandler;
58 import org.apache.hc.core5.http.io.HttpRequestHandler;
59 import org.apache.hc.core5.http.io.HttpServerRequestHandler;
60 import org.apache.hc.core5.http.io.SocketConfig;
61 import org.apache.hc.core5.http.io.ssl.DefaultTlsSetupHandler;
62 import org.apache.hc.core5.http.io.support.BasicHttpServerExpectationDecorator;
63 import org.apache.hc.core5.http.io.support.BasicHttpServerRequestHandler;
64 import org.apache.hc.core5.http.io.support.HttpServerExpectationFilter;
65 import org.apache.hc.core5.http.io.support.HttpServerFilterChainElement;
66 import org.apache.hc.core5.http.io.support.HttpServerFilterChainRequestHandler;
67 import org.apache.hc.core5.http.io.support.TerminalServerFilter;
68 import org.apache.hc.core5.http.protocol.HttpProcessor;
69 import org.apache.hc.core5.http.protocol.UriPatternType;
70 import org.apache.hc.core5.net.InetAddressUtils;
71 import org.apache.hc.core5.net.URIAuthority;
72 import org.apache.hc.core5.util.Args;
73
74
75
76
77
78
79 @SuppressWarnings("deprecation")
80 public class ServerBootstrap {
81
82 private final List<RequestRouter.Entry<HttpRequestHandler>> routeEntries;
83 private final List<FilterEntry<HttpFilterHandler>> filters;
84 private String canonicalHostName;
85 private HttpRequestMapper<HttpRequestHandler> requestRouter;
86 private org.apache.hc.core5.http.protocol.LookupRegistry<HttpRequestHandler> lookupRegistry;
87 private int listenerPort;
88 private InetAddress localAddress;
89 private SocketConfig socketConfig;
90 private Http1Config http1Config;
91 private CharCodingConfig charCodingConfig;
92 private HttpProcessor httpProcessor;
93 private ConnectionReuseStrategy connStrategy;
94 private HttpResponseFactory<ClassicHttpResponse> responseFactory;
95 private ServerSocketFactory serverSocketFactory;
96 private SSLContext sslContext;
97 private Callback<SSLParameters> sslSetupHandler;
98 private HttpConnectionFactory<? extends DefaultBHttpServerConnection> connectionFactory;
99 private ExceptionListener exceptionListener;
100 private Http1StreamListener streamListener;
101
102 private ServerBootstrap() {
103 this.routeEntries = new ArrayList<>();
104 this.filters = new ArrayList<>();
105 }
106
107 public static ServerBootstrap bootstrap() {
108 return new ServerBootstrap();
109 }
110
111
112
113
114
115
116 public final ServerBootstrap setCanonicalHostName(final String canonicalHostName) {
117 this.canonicalHostName = canonicalHostName;
118 return this;
119 }
120
121
122
123
124 public final ServerBootstrap setListenerPort(final int listenerPort) {
125 this.listenerPort = listenerPort;
126 return this;
127 }
128
129
130
131
132 public final ServerBootstrap setLocalAddress(final InetAddress localAddress) {
133 this.localAddress = localAddress;
134 return this;
135 }
136
137
138
139
140 public final ServerBootstrap setSocketConfig(final SocketConfig socketConfig) {
141 this.socketConfig = socketConfig;
142 return this;
143 }
144
145
146
147
148 public final ServerBootstrap setHttp1Config(final Http1Config http1Config) {
149 this.http1Config = http1Config;
150 return this;
151 }
152
153
154
155
156 public final ServerBootstrap setCharCodingConfig(final CharCodingConfig charCodingConfig) {
157 this.charCodingConfig = charCodingConfig;
158 return this;
159 }
160
161
162
163
164 public final ServerBootstrap setHttpProcessor(final HttpProcessor httpProcessor) {
165 this.httpProcessor = httpProcessor;
166 return this;
167 }
168
169
170
171
172 public final ServerBootstrap setConnectionReuseStrategy(final ConnectionReuseStrategy connStrategy) {
173 this.connStrategy = connStrategy;
174 return this;
175 }
176
177
178
179
180 public final ServerBootstrap setResponseFactory(final HttpResponseFactory<ClassicHttpResponse> responseFactory) {
181 this.responseFactory = responseFactory;
182 return this;
183 }
184
185
186
187
188 @Deprecated
189 public final ServerBootstrap setLookupRegistry(final org.apache.hc.core5.http.protocol.LookupRegistry<HttpRequestHandler> lookupRegistry) {
190 this.lookupRegistry = lookupRegistry;
191 return this;
192 }
193
194
195
196
197
198
199
200
201 public final ServerBootstrap register(final String uriPattern, final HttpRequestHandler requestHandler) {
202 Args.notBlank(uriPattern, "URI pattern");
203 Args.notNull(requestHandler, "Supplier");
204 routeEntries.add(new RequestRouter.Entry<>(uriPattern, requestHandler));
205 return this;
206 }
207
208
209
210
211
212
213
214
215
216
217
218 public final ServerBootstrap register(final String hostname, final String uriPattern, final HttpRequestHandler requestHandler) {
219 Args.notBlank(hostname, "Hostname");
220 Args.notBlank(uriPattern, "URI pattern");
221 Args.notNull(requestHandler, "Request handler");
222 routeEntries.add(new RequestRouter.Entry<>(hostname, uriPattern, requestHandler));
223 return this;
224 }
225
226
227
228
229 @Deprecated
230 public final ServerBootstrap registerVirtual(final String hostname, final String uriPattern, final HttpRequestHandler requestHandler) {
231 return register(hostname, uriPattern, requestHandler);
232 }
233
234
235
236
237
238
239
240 public final ServerBootstrap setRequestRouter(final HttpRequestMapper<HttpRequestHandler> requestRouter) {
241 this.requestRouter = requestRouter;
242 return this;
243 }
244
245
246
247
248 public final ServerBootstrap setConnectionFactory(
249 final HttpConnectionFactory<? extends DefaultBHttpServerConnection> connectionFactory) {
250 this.connectionFactory = connectionFactory;
251 return this;
252 }
253
254
255
256
257 public final ServerBootstrap setServerSocketFactory(final ServerSocketFactory serverSocketFactory) {
258 this.serverSocketFactory = serverSocketFactory;
259 return this;
260 }
261
262
263
264
265
266
267
268 public final ServerBootstrap setSslContext(final SSLContext sslContext) {
269 this.sslContext = sslContext;
270 return this;
271 }
272
273
274
275
276 public final ServerBootstrap setSslSetupHandler(final Callback<SSLParameters> sslSetupHandler) {
277 this.sslSetupHandler = sslSetupHandler;
278 return this;
279 }
280
281
282
283
284 public final ServerBootstrap setExceptionListener(final ExceptionListener exceptionListener) {
285 this.exceptionListener = exceptionListener;
286 return this;
287 }
288
289
290
291
292 public final ServerBootstrap setStreamListener(final Http1StreamListener streamListener) {
293 this.streamListener = streamListener;
294 return this;
295 }
296
297
298
299
300 public final ServerBootstrap addFilterBefore(final String existing, final String name, final HttpFilterHandler filterHandler) {
301 Args.notBlank(existing, "Existing");
302 Args.notBlank(name, "Name");
303 Args.notNull(filterHandler, "Filter handler");
304 filters.add(new FilterEntry<>(FilterEntry.Position.BEFORE, name, filterHandler, existing));
305 return this;
306 }
307
308
309
310
311 public final ServerBootstrap addFilterAfter(final String existing, final String name, final HttpFilterHandler filterHandler) {
312 Args.notBlank(existing, "Existing");
313 Args.notBlank(name, "Name");
314 Args.notNull(filterHandler, "Filter handler");
315 filters.add(new FilterEntry<>(FilterEntry.Position.AFTER, name, filterHandler, existing));
316 return this;
317 }
318
319
320
321
322 public final ServerBootstrap replaceFilter(final String existing, final HttpFilterHandler filterHandler) {
323 Args.notBlank(existing, "Existing");
324 Args.notNull(filterHandler, "Filter handler");
325 filters.add(new FilterEntry<>(FilterEntry.Position.REPLACE, existing, filterHandler, existing));
326 return this;
327 }
328
329
330
331
332 public final ServerBootstrap addFilterFirst(final String name, final HttpFilterHandler filterHandler) {
333 Args.notNull(name, "Name");
334 Args.notNull(filterHandler, "Filter handler");
335 filters.add(new FilterEntry<>(FilterEntry.Position.FIRST, name, filterHandler, null));
336 return this;
337 }
338
339
340
341
342 public final ServerBootstrap addFilterLast(final String name, final HttpFilterHandler filterHandler) {
343 Args.notNull(name, "Name");
344 Args.notNull(filterHandler, "Filter handler");
345 filters.add(new FilterEntry<>(FilterEntry.Position.LAST, name, filterHandler, null));
346 return this;
347 }
348
349 public HttpServer create() {
350 final String actualCanonicalHostName = canonicalHostName != null ? canonicalHostName : InetAddressUtils.getCanonicalLocalHostName();
351 final HttpRequestMapper<HttpRequestHandler> requestRouterCopy;
352 if (lookupRegistry != null && requestRouter == null) {
353 final org.apache.hc.core5.http.protocol.RequestHandlerRegistry<HttpRequestHandler> handlerRegistry = new org.apache.hc.core5.http.protocol.RequestHandlerRegistry<>(
354 actualCanonicalHostName,
355 () -> lookupRegistry != null ? lookupRegistry : new org.apache.hc.core5.http.protocol.UriPatternMatcher<>());
356 for (final RequestRouter.Entry<HttpRequestHandler> entry: routeEntries) {
357 handlerRegistry.register(entry.uriAuthority != null ? entry.uriAuthority.getHostName() : null, entry.route.pattern, entry.route.handler);
358 }
359 requestRouterCopy = handlerRegistry;
360 } else {
361 if (routeEntries.isEmpty()) {
362 requestRouterCopy = requestRouter;
363 } else {
364 requestRouterCopy = RequestRouter.create(
365 new URIAuthority(actualCanonicalHostName),
366 UriPatternType.URI_PATTERN,
367 routeEntries,
368 RequestRouter.IGNORE_PORT_AUTHORITY_RESOLVER,
369 requestRouter);
370 }
371 }
372
373 final HttpServerRequestHandler requestHandler;
374 if (!filters.isEmpty()) {
375 final NamedElementChain<HttpFilterHandler> filterChainDefinition = new NamedElementChain<>();
376 filterChainDefinition.addLast(
377 new TerminalServerFilter(
378 requestRouterCopy,
379 this.responseFactory != null ? this.responseFactory : DefaultClassicHttpResponseFactory.INSTANCE),
380 StandardFilter.MAIN_HANDLER.name());
381 filterChainDefinition.addFirst(
382 new HttpServerExpectationFilter(),
383 StandardFilter.EXPECT_CONTINUE.name());
384
385 for (final FilterEntry<HttpFilterHandler> entry: filters) {
386 switch (entry.position) {
387 case AFTER:
388 filterChainDefinition.addAfter(entry.existing, entry.filterHandler, entry.name);
389 break;
390 case BEFORE:
391 filterChainDefinition.addBefore(entry.existing, entry.filterHandler, entry.name);
392 break;
393 case REPLACE:
394 filterChainDefinition.replace(entry.existing, entry.filterHandler);
395 break;
396 case FIRST:
397 filterChainDefinition.addFirst(entry.filterHandler, entry.name);
398 break;
399 case LAST:
400
401
402 filterChainDefinition.addBefore(StandardFilter.MAIN_HANDLER.name(), entry.filterHandler, entry.name);
403 break;
404 }
405 }
406
407 NamedElementChain<HttpFilterHandler>.Node current = filterChainDefinition.getLast();
408 HttpServerFilterChainElement filterChain = null;
409 while (current != null) {
410 filterChain = new HttpServerFilterChainElement(current.getValue(), filterChain);
411 current = current.getPrevious();
412 }
413 requestHandler = new HttpServerFilterChainRequestHandler(filterChain);
414 } else {
415 requestHandler = new BasicHttpServerExpectationDecorator(new BasicHttpServerRequestHandler(
416 requestRouterCopy,
417 this.responseFactory != null ? this.responseFactory : DefaultClassicHttpResponseFactory.INSTANCE));
418 }
419
420 final HttpService httpService = new HttpService(
421 this.httpProcessor != null ? this.httpProcessor : HttpProcessors.server(),
422 requestHandler,
423 this.http1Config,
424 this.connStrategy != null ? this.connStrategy : DefaultConnectionReuseStrategy.INSTANCE,
425 this.streamListener);
426
427 HttpConnectionFactory<? extends DefaultBHttpServerConnection> connectionFactoryCopy = this.connectionFactory;
428 if (connectionFactoryCopy == null) {
429 final String scheme = serverSocketFactory instanceof SSLServerSocketFactory || sslContext != null ?
430 URIScheme.HTTPS.id : URIScheme.HTTP.id;
431 connectionFactoryCopy = new DefaultBHttpServerConnectionFactory(scheme, this.http1Config, this.charCodingConfig);
432 }
433
434 return new HttpServer(
435 Math.max(this.listenerPort, 0),
436 httpService,
437 this.localAddress,
438 this.socketConfig != null ? this.socketConfig : SocketConfig.DEFAULT,
439 serverSocketFactory,
440 connectionFactoryCopy,
441 sslContext,
442 sslSetupHandler != null ? sslSetupHandler : DefaultTlsSetupHandler.SERVER,
443 this.exceptionListener != null ? this.exceptionListener : ExceptionListener.NO_OP);
444 }
445
446 }