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