View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
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.ServerHttpProtocolNegotiatorFactory;
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   * HTTP/2 capable {@link HttpAsyncServer} bootstrap.
80   *
81   * @since 5.0
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      * Sets canonical name (fully qualified domain name) of the server.
114      *
115      * @since 5.0
116      */
117     public final H2ServerBootstrap setCanonicalHostName(final String canonicalHostName) {
118         this.canonicalHostName = canonicalHostName;
119         return this;
120     }
121 
122     /**
123      * Sets I/O reactor configuration.
124      */
125     public final H2ServerBootstrap setIOReactorConfig(final IOReactorConfig ioReactorConfig) {
126         this.ioReactorConfig = ioReactorConfig;
127         return this;
128     }
129 
130     /**
131      * Assigns {@link HttpProcessor} instance.
132      */
133     public final H2ServerBootstrap setHttpProcessor(final HttpProcessor httpProcessor) {
134         this.httpProcessor = httpProcessor;
135         return this;
136     }
137 
138     /**
139      * Sets HTTP protocol version policy
140      */
141     public final H2ServerBootstrap setVersionPolicy(final HttpVersionPolicy versionPolicy) {
142         this.versionPolicy = versionPolicy;
143         return this;
144     }
145 
146     /**
147      * Sets HTTP/2 protocol parameters
148      */
149     public final H2ServerBootstrap setH2Config(final H2Config h2Config) {
150         this.h2Config = h2Config;
151         return this;
152     }
153 
154     /**
155      * Sets HTTP/1.1 protocol parameters
156      */
157     public final H2ServerBootstrap setHttp1Config(final Http1Config http1Config) {
158         this.http1Config = http1Config;
159         return this;
160     }
161 
162     /**
163      * Sets message char coding.
164      */
165     public final H2ServerBootstrap setCharset(final CharCodingConfig charCodingConfig) {
166         this.charCodingConfig = charCodingConfig;
167         return this;
168     }
169 
170     /**
171      * Assigns {@link TlsStrategy} instance.
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      * Assigns {@link IOSession} {@link Decorator} instance.
185      */
186     public final H2ServerBootstrap setIOSessionDecorator(final Decorator<IOSession> ioSessionDecorator) {
187         this.ioSessionDecorator = ioSessionDecorator;
188         return this;
189     }
190 
191     /**
192      * Assigns {@link Exception} {@link Callback} instance.
193      */
194     public final H2ServerBootstrap setExceptionCallback(final Callback<Exception> exceptionCallback) {
195         this.exceptionCallback = exceptionCallback;
196         return this;
197     }
198 
199     /**
200      * Assigns {@link IOSessionListener} instance.
201      */
202     public final H2ServerBootstrap setIOSessionListener(final IOSessionListener sessionListener) {
203         this.sessionListener = sessionListener;
204         return this;
205     }
206 
207     /**
208      * Assigns {@link H2StreamListener} instance.
209      */
210     public final H2ServerBootstrap setStreamListener(final H2StreamListener h2StreamListener) {
211         this.h2StreamListener = h2StreamListener;
212         return this;
213     }
214 
215     /**
216      * Assigns {@link Http1StreamListener} instance.
217      */
218     public final H2ServerBootstrap setStreamListener(final Http1StreamListener http1StreamListener) {
219         this.http1StreamListener = http1StreamListener;
220         return this;
221     }
222 
223     /**
224      * Assigns {@link LookupRegistry} instance.
225      */
226     public final H2ServerBootstrap setLookupRegistry(final LookupRegistry<Supplier<AsyncServerExchangeHandler>> lookupRegistry) {
227         this.lookupRegistry = lookupRegistry;
228         return this;
229     }
230 
231     /**
232      * Registers the given {@link AsyncServerExchangeHandler} {@link Supplier} as a default handler for URIs
233      * matching the given pattern.
234      *
235      * @param uriPattern the pattern to register the handler for.
236      * @param supplier the handler supplier.
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      * Registers the given {@link AsyncServerExchangeHandler} {@link Supplier} as a handler for URIs
247      * matching the given host and the pattern.
248      *
249      * @param hostname the host name
250      * @param uriPattern the pattern to register the handler for.
251      * @param supplier the handler supplier.
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      * Registers the given {@link AsyncServerRequestHandler} as a default handler for URIs
263      * matching the given pattern.
264      *
265      * @param uriPattern the pattern to register the handler for.
266      * @param requestHandler the handler.
267      */
268     public final <T> H2ServerBootstrap register(
269             final String uriPattern,
270             final AsyncServerRequestHandler<T> requestHandler) {
271         register(uriPattern, new Supplier<AsyncServerExchangeHandler>() {
272 
273             @Override
274             public AsyncServerExchangeHandler get() {
275                 return new BasicServerExchangeHandler<>(requestHandler);
276             }
277 
278         });
279         return this;
280     }
281 
282     /**
283      * Registers the given {@link AsyncServerRequestHandler} as a handler for URIs
284      * matching the given host and the pattern.
285      *
286      * @param hostname the host name
287      * @param uriPattern the pattern to register the handler for.
288      * @param requestHandler the handler.
289      */
290     public final <T> H2ServerBootstrap registerVirtual(
291             final String hostname,
292             final String uriPattern,
293             final AsyncServerRequestHandler<T> requestHandler) {
294         registerVirtual(hostname, uriPattern, new Supplier<AsyncServerExchangeHandler>() {
295 
296             @Override
297             public AsyncServerExchangeHandler get() {
298                 return new BasicServerExchangeHandler<>(requestHandler);
299             }
300 
301         });
302         return this;
303     }
304 
305     /**
306      * Adds the filter before the filter with the given name.
307      */
308     public final H2ServerBootstrap addFilterBefore(final String existing, final String name, final AsyncFilterHandler filterHandler) {
309         Args.notBlank(existing, "Existing");
310         Args.notBlank(name, "Name");
311         Args.notNull(filterHandler, "Filter handler");
312         filters.add(new FilterEntry<>(FilterEntry.Postion.BEFORE, name, filterHandler, existing));
313         return this;
314     }
315 
316     /**
317      * Adds the filter after the filter with the given name.
318      */
319     public final H2ServerBootstrap addFilterAfter(final String existing, final String name, final AsyncFilterHandler filterHandler) {
320         Args.notBlank(existing, "Existing");
321         Args.notBlank(name, "Name");
322         Args.notNull(filterHandler, "Filter handler");
323         filters.add(new FilterEntry<>(FilterEntry.Postion.AFTER, name, filterHandler, existing));
324         return this;
325     }
326 
327     /**
328      * Replace an existing filter with the given name with new filter.
329      */
330     public final H2ServerBootstrap replaceFilter(final String existing, final AsyncFilterHandler filterHandler) {
331         Args.notBlank(existing, "Existing");
332         Args.notNull(filterHandler, "Filter handler");
333         filters.add(new FilterEntry<>(FilterEntry.Postion.REPLACE, existing, filterHandler, existing));
334         return this;
335     }
336 
337     /**
338      * Add an filter to the head of the processing list.
339      */
340     public final H2ServerBootstrap addFilterFirst(final String name, final AsyncFilterHandler filterHandler) {
341         Args.notNull(name, "Name");
342         Args.notNull(filterHandler, "Filter handler");
343         filters.add(new FilterEntry<>(FilterEntry.Postion.FIRST, name, filterHandler, null));
344         return this;
345     }
346 
347     /**
348      * Add an filter to the tail of the processing list.
349      */
350     public final H2ServerBootstrap addFilterLast(final String name, final AsyncFilterHandler filterHandler) {
351         Args.notNull(name, "Name");
352         Args.notNull(filterHandler, "Filter handler");
353         filters.add(new FilterEntry<>(FilterEntry.Postion.LAST, name, filterHandler, null));
354         return this;
355     }
356 
357     public HttpAsyncServer create() {
358         final String actualCanonicalHostName = canonicalHostName != null ? canonicalHostName : InetAddressUtils.getCanonicalLocalHostName();
359         final RequestHandlerRegistry<Supplier<AsyncServerExchangeHandler>> registry = new RequestHandlerRegistry<>(
360                 actualCanonicalHostName,
361                 new Supplier<LookupRegistry<Supplier<AsyncServerExchangeHandler>>>() {
362 
363                     @Override
364                     public LookupRegistry<Supplier<AsyncServerExchangeHandler>> get() {
365                         return lookupRegistry != null ? lookupRegistry :
366                                 UriPatternType.<Supplier<AsyncServerExchangeHandler>>newMatcher(UriPatternType.URI_PATTERN);
367                     }
368 
369                 });
370         for (final HandlerEntry<Supplier<AsyncServerExchangeHandler>> entry: handlerList) {
371             registry.register(entry.hostname, entry.uriPattern, entry.handler);
372         }
373 
374         final HandlerFactory<AsyncServerExchangeHandler> handlerFactory;
375         if (!filters.isEmpty()) {
376             final NamedElementChain<AsyncFilterHandler> filterChainDefinition = new NamedElementChain<>();
377             filterChainDefinition.addLast(
378                     new TerminalAsyncServerFilter(new DefaultAsyncResponseExchangeHandlerFactory(registry)),
379                     StandardFilter.MAIN_HANDLER.name());
380             filterChainDefinition.addFirst(
381                     new AsyncServerExpectationFilter(),
382                     StandardFilter.EXPECT_CONTINUE.name());
383 
384             for (final FilterEntry<AsyncFilterHandler> entry: filters) {
385                 switch (entry.postion) {
386                     case AFTER:
387                         filterChainDefinition.addAfter(entry.existing, entry.filterHandler, entry.name);
388                         break;
389                     case BEFORE:
390                         filterChainDefinition.addBefore(entry.existing, entry.filterHandler, entry.name);
391                         break;
392                     case REPLACE:
393                         filterChainDefinition.replace(entry.existing, entry.filterHandler);
394                         break;
395                     case FIRST:
396                         filterChainDefinition.addFirst(entry.filterHandler, entry.name);
397                         break;
398                     case LAST:
399                         // Don't add last, after TerminalAsyncServerFilter, as that does not delegate to the chain
400                         // Instead, add the filter just before it, making it effectively the last filter
401                         filterChainDefinition.addBefore(StandardFilter.MAIN_HANDLER.name(), entry.filterHandler, entry.name);
402                         break;
403                 }
404             }
405 
406             NamedElementChain<AsyncFilterHandler>.Node current = filterChainDefinition.getLast();
407             AsyncServerFilterChainElement execChain = null;
408             while (current != null) {
409                 execChain = new AsyncServerFilterChainElement(current.getValue(), execChain);
410                 current = current.getPrevious();
411             }
412 
413             handlerFactory = new AsyncServerFilterChainExchangeHandlerFactory(execChain, exceptionCallback);
414         } else {
415             handlerFactory = new DefaultAsyncResponseExchangeHandlerFactory(registry, new Decorator<AsyncServerExchangeHandler>() {
416 
417                 @Override
418                 public AsyncServerExchangeHandlererExchangeHandler.html#AsyncServerExchangeHandler">AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler handler) {
419                     return new BasicAsyncServerExpectationDecorator(handler, exceptionCallback);
420                 }
421 
422             });
423         }
424 
425         final ServerH2StreamMultiplexerFactoryactory.html#ServerH2StreamMultiplexerFactory">ServerH2StreamMultiplexerFactory http2StreamHandlerFactory = new ServerH2StreamMultiplexerFactory(
426                 httpProcessor != null ? httpProcessor : H2Processors.server(),
427                 handlerFactory,
428                 h2Config != null ? h2Config : H2Config.DEFAULT,
429                 charCodingConfig != null ? charCodingConfig : CharCodingConfig.DEFAULT,
430                 h2StreamListener);
431 
432         final HttpVersionPolicy actualVersionProtocol = versionPolicy != null ? versionPolicy : HttpVersionPolicy.NEGOTIATE;
433         final TlsStrategy actualTlsStrategy = tlsStrategy != null ? tlsStrategy : new H2ServerTlsStrategy();
434 
435         final ServerHttp1StreamDuplexerFactoryctory.html#ServerHttp1StreamDuplexerFactory">ServerHttp1StreamDuplexerFactory http1StreamHandlerFactory = new ServerHttp1StreamDuplexerFactory(
436                 httpProcessor != null ? httpProcessor : HttpProcessors.server(),
437                 handlerFactory,
438                 http1Config != null ? http1Config : Http1Config.DEFAULT,
439                 charCodingConfig != null ? charCodingConfig : CharCodingConfig.DEFAULT,
440                 DefaultConnectionReuseStrategy.INSTANCE,
441                 DefaultHttpRequestParserFactory.INSTANCE,
442                 DefaultHttpResponseWriterFactory.INSTANCE,
443                 DefaultContentLengthStrategy.INSTANCE,
444                 DefaultContentLengthStrategy.INSTANCE,
445                 http1StreamListener);
446 
447         final IOEventHandlerFactory ioEventHandlerFactory = new ServerHttpProtocolNegotiatorFactory(
448                 http1StreamHandlerFactory,
449                 http2StreamHandlerFactory,
450                 actualVersionProtocol,
451                 actualTlsStrategy,
452                 handshakeTimeout);
453 
454         return new HttpAsyncServer(ioEventHandlerFactory, ioReactorConfig, ioSessionDecorator, exceptionCallback,
455                 sessionListener, actualCanonicalHostName);
456     }
457 
458 }