001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- 002 * 003 * Copyright © 2019–2020 microBean™. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 014 * implied. See the License for the specific language governing 015 * permissions and limitations under the License. 016 */ 017package org.microbean.jersey.netty; 018 019import java.net.URI; 020 021import java.util.Objects; 022 023import java.util.function.Supplier; 024 025import javax.ws.rs.core.Application; 026import javax.ws.rs.core.Configuration; 027 028import io.netty.buffer.ByteBufAllocator; 029import io.netty.buffer.Unpooled; 030 031import io.netty.channel.Channel; 032import io.netty.channel.ChannelHandler; // for javadoc only 033import io.netty.channel.ChannelHandlerContext; 034import io.netty.channel.ChannelInitializer; 035import io.netty.channel.ChannelPipeline; 036import io.netty.channel.SimpleChannelInboundHandler; 037 038import io.netty.util.concurrent.DefaultEventExecutorGroup; 039import io.netty.util.concurrent.EventExecutorGroup; 040 041import io.netty.handler.codec.http.HttpMessage; 042import io.netty.handler.codec.http.HttpRequest; 043import io.netty.handler.codec.http.HttpServerCodec; 044import io.netty.handler.codec.http.HttpServerExpectContinueHandler; 045import io.netty.handler.codec.http.HttpServerUpgradeHandler; 046import io.netty.handler.codec.http.HttpServerUpgradeHandler.SourceCodec; // for javadoc only 047import io.netty.handler.codec.http.HttpServerUpgradeHandler.UpgradeCodec; 048import io.netty.handler.codec.http.HttpServerUpgradeHandler.UpgradeCodecFactory; 049 050import io.netty.handler.codec.http2.CleartextHttp2ServerUpgradeHandler; 051import io.netty.handler.codec.http2.Http2CodecUtil; 052import io.netty.handler.codec.http2.Http2FrameCodec; 053import io.netty.handler.codec.http2.Http2FrameCodecBuilder; 054import io.netty.handler.codec.http2.Http2HeadersFrame; 055import io.netty.handler.codec.http2.Http2MultiplexHandler; 056import io.netty.handler.codec.http2.Http2ServerUpgradeCodec; 057 058import io.netty.handler.ssl.ApplicationProtocolNames; 059import io.netty.handler.ssl.ApplicationProtocolNegotiationHandler; 060import io.netty.handler.ssl.SslContext; 061import io.netty.handler.ssl.SslHandler; 062 063import io.netty.util.AsciiString; 064import io.netty.util.ReferenceCountUtil; 065 066import org.glassfish.jersey.internal.inject.Bindings; 067import org.glassfish.jersey.internal.inject.InjectionManager; 068import org.glassfish.jersey.internal.inject.ReferencingFactory; 069 070import org.glassfish.jersey.process.internal.RequestScoped; 071 072import org.glassfish.jersey.server.ApplicationHandler; 073import org.glassfish.jersey.server.ContainerRequest; // for javadoc only 074 075import org.microbean.jersey.netty.AbstractByteBufBackedChannelOutboundInvokingOutputStream.ByteBufCreator; 076 077/** 078 * A {@link ChannelInitializer} that {@linkplain 079 * #initChannel(Channel) initializes 080 * <code>Channel</code>s} by configuring their {@link 081 * ChannelPipeline}s to include {@link ChannelHandler}s that transform 082 * Netty HTTP and HTTP/2 messages into Jersey {@link 083 * ContainerRequest}s that are then {@linkplain 084 * ApplicationHandler#handle(ContainerRequest) handled} by an {@link 085 * ApplicationHandler}. 086 * 087 * @author <a href="https://about.me/lairdnelson" 088 * target="_parent">Laird Nelson</a> 089 * 090 * @see #initChannel(Channel) 091 * 092 * @see ContainerRequest 093 * 094 * @see ApplicationHandler#handle(ContainerRequest) 095 * 096 * @see HttpObjectToContainerRequestDecoder 097 * 098 * @see HttpContainerRequestHandlingResponseWriter 099 * 100 * @see Http2StreamFrameToContainerRequestDecoder 101 * 102 * @see Http2ContainerRequestHandlingResponseWriter 103 */ 104public class JerseyChannelInitializer extends ChannelInitializer<Channel> { 105 106 107 /* 108 * Static fields. 109 */ 110 111 112 /* 113 * Instance fields. 114 */ 115 116 117 /** 118 * The base {@link URI} for the Jersey application. 119 * 120 * <p>This field is never {@code null}.</p> 121 * 122 * @see #JerseyChannelInitializer(URI, SslContext, long, 123 * ApplicationHandler) 124 */ 125 private final URI baseUri; 126 127 /** 128 * An {@link SslContext} that may be used to {@linkplain 129 * #createSslHandler(SslContext, ByteBufAllocator) create an 130 * <code>SslHandler</code>}. 131 * 132 * <p>This field may be {@code null}.</p> 133 * 134 * @see #JerseyChannelInitializer(URI, SslContext, long, 135 * ApplicationHandler) 136 * 137 * @see SslContext 138 * 139 * @see #createSslHandler(SslContext, ByteBufAllocator) 140 */ 141 private final SslContext sslContext; 142 143 private final boolean http2Support; 144 145 /** 146 * In the case of HTTP to HTTP/2 147 * upgrades, this field governs the maximum permitted incoming 148 * entity length in bytes; if less than {@code 0} then {@link 149 * Long#MAX_VALUE} will be used instead; if exactly {@code 0} then 150 * if the HTTP message containing the upgrade header is something 151 * like a {@code POST} it will be rejected with a {@code 413} error 152 * code. 153 * 154 * @see HttpServerUpgradeHandler#maxContentLength() 155 */ 156 private final long maxIncomingContentLength; 157 158 private final EventExecutorGroup jerseyEventExecutorGroup; 159 160 private final Supplier<? extends ApplicationHandler> applicationHandlerSupplier; 161 162 private final int flushThreshold; 163 164 private final ByteBufCreator byteBufCreator; 165 166 167 /* 168 * Constructors. 169 */ 170 171 172 /** 173 * Creates a new {@link JerseyChannelInitializer}. 174 * 175 * @param baseUri a {@link URI} that will serve as the {@linkplain 176 * ContainerRequest#getBaseUri() base <code>URI</code>} in a new 177 * {@link ContainerRequest}; may be {@code null} in which case the 178 * return value of {@link URI#create(String) URI.create("/")} will 179 * be used instead 180 * 181 * @param sslContext an {@link SslContext}; may be {@code null} in 182 * which case network communications will occur in plain text 183 * 184 * @param jaxrsApplication the {@link Application} to run; may be 185 * {@code null} somewhat pathologically 186 * 187 * @see #JerseyChannelInitializer(URI, SslContext, boolean, long, 188 * EventExecutorGroup, boolean, Supplier, int, 189 * AbstractByteBufBackedChannelOutboundInvokingOutputStream.ByteBufCreator) 190 * 191 * @see ContainerRequest 192 * 193 * @see SslContext 194 * 195 * @see 196 * HttpServerUpgradeHandler#HttpServerUpgradeHandler(SourceCodec, 197 * UpgradeCodecFactory, int) 198 * 199 * @see ApplicationHandler#handle(ContainerRequest) 200 * 201 * @see AbstractContainerRequestHandlingResponseWriter 202 * 203 * @see HttpObjectToContainerRequestDecoder 204 * 205 * @see HttpContainerRequestHandlingResponseWriter 206 * 207 * @see Http2StreamFrameToContainerRequestDecoder 208 * 209 * @see Http2ContainerRequestHandlingResponseWriter 210 */ 211 public JerseyChannelInitializer(final URI baseUri, 212 final SslContext sslContext, 213 final Application jaxrsApplication) { 214 this(baseUri, 215 sslContext, 216 true, 217 toApplicationHandlerSupplier(jaxrsApplication)); 218 } 219 220 /** 221 * Creates a new {@link JerseyChannelInitializer}. 222 * 223 * @param baseUri a {@link URI} that will serve as the {@linkplain 224 * ContainerRequest#getBaseUri() base <code>URI</code>} in a new 225 * {@link ContainerRequest}; may be {@code null} in which case the 226 * return value of {@link URI#create(String) URI.create("/")} will 227 * be used instead 228 * 229 * @param sslContext an {@link SslContext}; may be {@code null} in 230 * which case network communications will occur in plain text 231 * 232 * @param applicationHandler an {@link ApplicationHandler} 233 * representing a <a 234 * href="https://jakarta.ee/specifications/restful-ws/" 235 * target="_parent">Jakarta RESTful Web Services application</a> 236 * whose {@link ApplicationHandler#handle(ContainerRequest)} method 237 * will serve as the bridge between Netty and Jersey; may be {@code 238 * null} somewhat pathologically but normally is not 239 * 240 * @see #JerseyChannelInitializer(URI, SslContext, boolean, long, 241 * EventExecutorGroup, boolean, Supplier, int, 242 * AbstractByteBufBackedChannelOutboundInvokingOutputStream.ByteBufCreator) 243 * 244 * @see ContainerRequest 245 * 246 * @see SslContext 247 * 248 * @see 249 * HttpServerUpgradeHandler#HttpServerUpgradeHandler(SourceCodec, 250 * UpgradeCodecFactory, int) 251 * 252 * @see ApplicationHandler#handle(ContainerRequest) 253 * 254 * @see AbstractContainerRequestHandlingResponseWriter 255 * 256 * @see HttpObjectToContainerRequestDecoder 257 * 258 * @see HttpContainerRequestHandlingResponseWriter 259 * 260 * @see Http2StreamFrameToContainerRequestDecoder 261 * 262 * @see Http2ContainerRequestHandlingResponseWriter 263 */ 264 public JerseyChannelInitializer(final URI baseUri, 265 final SslContext sslContext, 266 final ApplicationHandler applicationHandler) { 267 this(baseUri, 268 sslContext, 269 true, 270 toApplicationHandlerSupplier(applicationHandler)); 271 } 272 273 /** 274 * Creates a new {@link JerseyChannelInitializer}. 275 * 276 * @param baseUri a {@link URI} that will serve as the {@linkplain 277 * ContainerRequest#getBaseUri() base <code>URI</code>} in a new 278 * {@link ContainerRequest}; may be {@code null} in which case the 279 * return value of {@link URI#create(String) URI.create("/")} will 280 * be used instead 281 * 282 * @param sslContext an {@link SslContext}; may be {@code null} in 283 * which case network communications will occur in plain text 284 * 285 * @param applicationHandlerSupplier a {@link Supplier} of an {@link 286 * ApplicationHandler} representing a <a 287 * href="https://jakarta.ee/specifications/restful-ws/" 288 * target="_parent">Jakarta RESTful Web Services application</a> 289 * whose {@link ApplicationHandler#handle(ContainerRequest)} method 290 * will serve as the bridge between Netty and Jersey; may be {@code 291 * null} somewhat pathologically but normally is not 292 * 293 * @see #JerseyChannelInitializer(URI, SslContext, boolean, long, 294 * EventExecutorGroup, boolean, Supplier, int, 295 * AbstractByteBufBackedChannelOutboundInvokingOutputStream.ByteBufCreator) 296 * 297 * @see ContainerRequest 298 * 299 * @see SslContext 300 * 301 * @see 302 * HttpServerUpgradeHandler#HttpServerUpgradeHandler(SourceCodec, 303 * UpgradeCodecFactory, int) 304 * 305 * @see ApplicationHandler#handle(ContainerRequest) 306 * 307 * @see AbstractContainerRequestHandlingResponseWriter 308 * 309 * @see HttpObjectToContainerRequestDecoder 310 * 311 * @see HttpContainerRequestHandlingResponseWriter 312 * 313 * @see Http2StreamFrameToContainerRequestDecoder 314 * 315 * @see Http2ContainerRequestHandlingResponseWriter 316 */ 317 public JerseyChannelInitializer(final URI baseUri, 318 final SslContext sslContext, 319 final Supplier<? extends ApplicationHandler> applicationHandlerSupplier) { 320 this(baseUri, 321 sslContext, 322 true, 323 applicationHandlerSupplier); 324 } 325 326 /** 327 * Creates a new {@link JerseyChannelInitializer}. 328 * 329 * @param baseUri a {@link URI} that will serve as the {@linkplain 330 * ContainerRequest#getBaseUri() base <code>URI</code>} in a new 331 * {@link ContainerRequest}; may be {@code null} in which case the 332 * return value of {@link URI#create(String) URI.create("/")} will 333 * be used instead 334 * 335 * @param sslContext an {@link SslContext}; may be {@code null} in 336 * which case network communications will occur in plain text 337 * 338 * @param http2Support if HTTP/2 support (including upgrades, prior 339 * knowledge, h2c, etc.) should be enabled 340 * 341 * @param jaxrsApplication the {@link Application} to run; may be 342 * {@code null} somewhat pathologically 343 * 344 * @see #JerseyChannelInitializer(URI, SslContext, boolean, long, 345 * EventExecutorGroup, boolean, Supplier, int, 346 * AbstractByteBufBackedChannelOutboundInvokingOutputStream.ByteBufCreator) 347 * 348 * @see ContainerRequest 349 * 350 * @see SslContext 351 * 352 * @see 353 * HttpServerUpgradeHandler#HttpServerUpgradeHandler(SourceCodec, 354 * UpgradeCodecFactory, int) 355 * 356 * @see ApplicationHandler#handle(ContainerRequest) 357 * 358 * @see AbstractContainerRequestHandlingResponseWriter 359 * 360 * @see HttpObjectToContainerRequestDecoder 361 * 362 * @see HttpContainerRequestHandlingResponseWriter 363 * 364 * @see Http2StreamFrameToContainerRequestDecoder 365 * 366 * @see Http2ContainerRequestHandlingResponseWriter 367 */ 368 public JerseyChannelInitializer(final URI baseUri, 369 final SslContext sslContext, 370 final boolean http2Support, 371 final Application jaxrsApplication) { 372 this(baseUri, 373 sslContext, 374 http2Support, 375 20971520L, /* 20 MB; arbitrary */ 376 null, /* Jersey EventExecutorGroup will be defaulted */ 377 true, /* use Jersey injection */ 378 toApplicationHandlerSupplier(jaxrsApplication), 379 8192, /* 8K; arbitrary */ 380 Unpooled::wrappedBuffer); 381 } 382 383 /** 384 * Creates a new {@link JerseyChannelInitializer}. 385 * 386 * @param baseUri a {@link URI} that will serve as the {@linkplain 387 * ContainerRequest#getBaseUri() base <code>URI</code>} in a new 388 * {@link ContainerRequest}; may be {@code null} in which case the 389 * return value of {@link URI#create(String) URI.create("/")} will 390 * be used instead 391 * 392 * @param sslContext an {@link SslContext}; may be {@code null} in 393 * which case network communications will occur in plain text 394 * 395 * @param http2Support if HTTP/2 support (including upgrades, prior 396 * knowledge, h2c, etc.) should be enabled 397 * 398 * @param applicationHandler an {@link ApplicationHandler} 399 * representing a <a 400 * href="https://jakarta.ee/specifications/restful-ws/" 401 * target="_parent">Jakarta RESTful Web Services application</a> 402 * whose {@link ApplicationHandler#handle(ContainerRequest)} method 403 * will serve as the bridge between Netty and Jersey; may be {@code 404 * null} somewhat pathologically but normally is not 405 * 406 * @see #JerseyChannelInitializer(URI, SslContext, boolean, long, 407 * EventExecutorGroup, boolean, Supplier, int, 408 * AbstractByteBufBackedChannelOutboundInvokingOutputStream.ByteBufCreator) 409 * 410 * @see ContainerRequest 411 * 412 * @see SslContext 413 * 414 * @see 415 * HttpServerUpgradeHandler#HttpServerUpgradeHandler(SourceCodec, 416 * UpgradeCodecFactory, int) 417 * 418 * @see ApplicationHandler#handle(ContainerRequest) 419 * 420 * @see AbstractContainerRequestHandlingResponseWriter 421 * 422 * @see HttpObjectToContainerRequestDecoder 423 * 424 * @see HttpContainerRequestHandlingResponseWriter 425 * 426 * @see Http2StreamFrameToContainerRequestDecoder 427 * 428 * @see Http2ContainerRequestHandlingResponseWriter 429 */ 430 public JerseyChannelInitializer(final URI baseUri, 431 final SslContext sslContext, 432 final boolean http2Support, 433 final ApplicationHandler applicationHandler) { 434 this(baseUri, 435 sslContext, 436 http2Support, 437 20971520L, /* 20 MB; arbitrary */ 438 null, /* Jersey EventExecutorGroup will be defaulted */ 439 true, /* use Jersey injection */ 440 toApplicationHandlerSupplier(applicationHandler), 441 8192, /* 8K; arbitrary */ 442 Unpooled::wrappedBuffer); 443 } 444 445 /** 446 * Creates a new {@link JerseyChannelInitializer}. 447 * 448 * @param baseUri a {@link URI} that will serve as the {@linkplain 449 * ContainerRequest#getBaseUri() base <code>URI</code>} in a new 450 * {@link ContainerRequest}; may be {@code null} in which case the 451 * return value of {@link URI#create(String) URI.create("/")} will 452 * be used instead 453 * 454 * @param sslContext an {@link SslContext}; may be {@code null} in 455 * which case network communications will occur in plain text 456 * 457 * @param http2Support if HTTP/2 support (including upgrades, prior 458 * knowledge, h2c, etc.) should be enabled 459 * 460 * @param applicationHandlerSupplier a {@link Supplier} of an {@link 461 * ApplicationHandler} representing a <a 462 * href="https://jakarta.ee/specifications/restful-ws/" 463 * target="_parent">Jakarta RESTful Web Services application</a> 464 * whose {@link ApplicationHandler#handle(ContainerRequest)} method 465 * will serve as the bridge between Netty and Jersey; may be {@code 466 * null} somewhat pathologically but normally is not 467 * 468 * @see #JerseyChannelInitializer(URI, SslContext, boolean, long, 469 * EventExecutorGroup, boolean, Supplier, int, 470 * AbstractByteBufBackedChannelOutboundInvokingOutputStream.ByteBufCreator) 471 * 472 * @see ContainerRequest 473 * 474 * @see SslContext 475 * 476 * @see 477 * HttpServerUpgradeHandler#HttpServerUpgradeHandler(SourceCodec, 478 * UpgradeCodecFactory, int) 479 * 480 * @see ApplicationHandler#handle(ContainerRequest) 481 * 482 * @see AbstractContainerRequestHandlingResponseWriter 483 * 484 * @see HttpObjectToContainerRequestDecoder 485 * 486 * @see HttpContainerRequestHandlingResponseWriter 487 * 488 * @see Http2StreamFrameToContainerRequestDecoder 489 * 490 * @see Http2ContainerRequestHandlingResponseWriter 491 */ 492 public JerseyChannelInitializer(final URI baseUri, 493 final SslContext sslContext, 494 final boolean http2Support, 495 final Supplier<? extends ApplicationHandler> applicationHandlerSupplier) { 496 this(baseUri, 497 sslContext, 498 http2Support, 499 20971520L, /* 20 MB; arbitrary */ 500 null, /* Jersey EventExecutorGroup will be defaulted */ 501 true, /* use Jersey injection */ 502 applicationHandlerSupplier, 503 8192, /* 8K; arbitrary */ 504 Unpooled::wrappedBuffer); 505 } 506 507 /** 508 * Creates a new {@link JerseyChannelInitializer}. 509 * 510 * @param baseUri a {@link URI} that will serve as the {@linkplain 511 * ContainerRequest#getBaseUri() base <code>URI</code>} in a new 512 * {@link ContainerRequest}; may be {@code null} in which case the 513 * return value of {@link URI#create(String) URI.create("/")} will 514 * be used instead 515 * 516 * @param sslContext an {@link SslContext}; may be {@code null} in 517 * which case network communications will occur in plain text 518 * 519 * @param http2Support if HTTP/2 support (including upgrades, prior 520 * knowledge, h2c, etc.) should be enabled 521 * 522 * @param maxIncomingContentLength in the case of HTTP to HTTP/2 523 * upgrades, a {@code long} that governs the maximum permitted 524 * incoming entity length in bytes; if less than {@code 0} then 525 * {@link Long#MAX_VALUE} will be used instead; if exactly {@code 0} 526 * then if the HTTP message containing the upgrade header is 527 * something like a {@code POST} it will be rejected with a {@code 528 * 413} error code; ignored entirely if {@code http2Support} is 529 * {@code false} 530 * 531 * @param jerseyEventExecutorGroup an {@link EventExecutorGroup} 532 * that will manage the thread on which an {@link 533 * ApplicationHandler#handle(ContainerRequest)} call will occur; may 534 * be {@code null} in which case a new {@link 535 * DefaultEventExecutorGroup} will be used instead 536 * 537 * @param jaxrsApplication the {@link Application} to run; may be 538 * {@code null} somewhat pathologically 539 * 540 * @param flushThreshold the minimum number of bytes that an {@link 541 * AbstractByteBufBackedChannelOutboundInvokingOutputStream} 542 * returned by an implementation of the {@link 543 * AbstractContainerRequestHandlingResponseWriter#createOutputStream(long, 544 * ContainerResponse)} method must write before an automatic 545 * {@linkplain 546 * AbstractByteBufBackedChannelOutboundInvokingOutputStream#flush() 547 * flush} may take place; if less than {@code 0} {@code 0} will be 548 * used instead; if {@link Integer#MAX_VALUE} then it is suggested 549 * that no automatic flushing will occur 550 * 551 * @param byteBufCreator a {@link ByteBufCreator} that will be 552 * {@linkplain 553 * AbstractContainerRequestHandlingResponseWriter#AbstractContainerRequestHandlingResponseWriter(Supplier, 554 * int, 555 * AbstractByteBufBackedChannelOutboundInvokingOutputStream.ByteBufCreator) 556 * passed to an 557 * <code>AbstractContainerRequestHandlingResponseWriter</code>} 558 * implementation; may be {@code null} 559 * 560 * @see #JerseyChannelInitializer(URI, SslContext, boolean, long, 561 * EventExecutorGroup, boolean, Supplier, int, 562 * AbstractByteBufBackedChannelOutboundInvokingOutputStream.ByteBufCreator) 563 * 564 * @see ContainerRequest 565 * 566 * @see SslContext 567 * 568 * @see 569 * HttpServerUpgradeHandler#HttpServerUpgradeHandler(SourceCodec, 570 * UpgradeCodecFactory, int) 571 * 572 * @see ApplicationHandler#handle(ContainerRequest) 573 * 574 * @see AbstractContainerRequestHandlingResponseWriter 575 * 576 * @see HttpObjectToContainerRequestDecoder 577 * 578 * @see HttpContainerRequestHandlingResponseWriter 579 * 580 * @see Http2StreamFrameToContainerRequestDecoder 581 * 582 * @see Http2ContainerRequestHandlingResponseWriter 583 */ 584 public JerseyChannelInitializer(final URI baseUri, 585 final SslContext sslContext, 586 final boolean http2Support, 587 final long maxIncomingContentLength, 588 final EventExecutorGroup jerseyEventExecutorGroup, 589 final Application jaxrsApplication, 590 final int flushThreshold, 591 final ByteBufCreator byteBufCreator) { 592 this(baseUri, 593 sslContext, 594 http2Support, 595 maxIncomingContentLength, 596 jerseyEventExecutorGroup, 597 true, /* use Jersey injection */ 598 toApplicationHandlerSupplier(jaxrsApplication), 599 flushThreshold, 600 byteBufCreator); 601 } 602 603 /** 604 * Creates a new {@link JerseyChannelInitializer}. 605 * 606 * @param baseUri a {@link URI} that will serve as the {@linkplain 607 * ContainerRequest#getBaseUri() base <code>URI</code>} in a new 608 * {@link ContainerRequest}; may be {@code null} in which case the 609 * return value of {@link URI#create(String) URI.create("/")} will 610 * be used instead 611 * 612 * @param sslContext an {@link SslContext}; may be {@code null} in 613 * which case network communications will occur in plain text 614 * 615 * @param http2Support if HTTP/2 support (including upgrades, prior 616 * knowledge, h2c, etc.) should be enabled 617 * 618 * @param maxIncomingContentLength in the case of HTTP to HTTP/2 619 * upgrades, a {@code long} that governs the maximum permitted 620 * incoming entity length in bytes; if less than {@code 0} then 621 * {@link Long#MAX_VALUE} will be used instead; if exactly {@code 0} 622 * then if the HTTP message containing the upgrade header is 623 * something like a {@code POST} it will be rejected with a {@code 624 * 413} error code; ignored entirely if {@code http2Support} is 625 * {@code false} 626 * 627 * @param jerseyEventExecutorGroup an {@link EventExecutorGroup} 628 * that will manage the thread on which an {@link 629 * ApplicationHandler#handle(ContainerRequest)} call will occur; may 630 * be {@code null} in which case a new {@link 631 * DefaultEventExecutorGroup} will be used instead 632 * 633 * @param applicationHandler an {@link ApplicationHandler} 634 * representing a <a 635 * href="https://jakarta.ee/specifications/restful-ws/" 636 * target="_parent">Jakarta RESTful Web Services application</a> 637 * whose {@link ApplicationHandler#handle(ContainerRequest)} method 638 * will serve as the bridge between Netty and Jersey; may be {@code 639 * null} somewhat pathologically but normally is not 640 * 641 * @param flushThreshold the minimum number of bytes that an {@link 642 * AbstractByteBufBackedChannelOutboundInvokingOutputStream} 643 * returned by an implementation of the {@link 644 * AbstractContainerRequestHandlingResponseWriter#createOutputStream(long, 645 * ContainerResponse)} method must write before an automatic 646 * {@linkplain 647 * AbstractByteBufBackedChannelOutboundInvokingOutputStream#flush() 648 * flush} may take place; if less than {@code 0} {@code 0} will be 649 * used instead; if {@link Integer#MAX_VALUE} then it is suggested 650 * that no automatic flushing will occur 651 * 652 * @param byteBufCreator a {@link ByteBufCreator} that will be 653 * {@linkplain 654 * AbstractContainerRequestHandlingResponseWriter#AbstractContainerRequestHandlingResponseWriter(Supplier, 655 * int, 656 * AbstractByteBufBackedChannelOutboundInvokingOutputStream.ByteBufCreator) 657 * passed to an 658 * <code>AbstractContainerRequestHandlingResponseWriter</code>} 659 * implementation; may be {@code null} 660 * 661 * @see #JerseyChannelInitializer(URI, SslContext, boolean, long, 662 * EventExecutorGroup, boolean, ApplicationHandler, int, 663 * AbstractByteBufBackedChannelOutboundInvokingOutputStream.ByteBufCreator) 664 * @see ContainerRequest 665 * 666 * @see SslContext 667 * 668 * @see 669 * HttpServerUpgradeHandler#HttpServerUpgradeHandler(SourceCodec, 670 * UpgradeCodecFactory, int) 671 * 672 * @see ApplicationHandler#handle(ContainerRequest) 673 * 674 * @see AbstractContainerRequestHandlingResponseWriter 675 * 676 * @see HttpObjectToContainerRequestDecoder 677 * 678 * @see HttpContainerRequestHandlingResponseWriter 679 * 680 * @see Http2StreamFrameToContainerRequestDecoder 681 * 682 * @see Http2ContainerRequestHandlingResponseWriter 683 */ 684 public JerseyChannelInitializer(final URI baseUri, 685 final SslContext sslContext, 686 final boolean http2Support, 687 final long maxIncomingContentLength, 688 final EventExecutorGroup jerseyEventExecutorGroup, 689 final ApplicationHandler applicationHandler, 690 final int flushThreshold, 691 final ByteBufCreator byteBufCreator) { 692 this(baseUri, 693 sslContext, 694 http2Support, 695 maxIncomingContentLength, 696 jerseyEventExecutorGroup, 697 true, /* use Jersey injection */ 698 toApplicationHandlerSupplier(applicationHandler), 699 flushThreshold, 700 byteBufCreator); 701 } 702 703 /** 704 * Creates a new {@link JerseyChannelInitializer}. 705 * 706 * @param baseUri a {@link URI} that will serve as the {@linkplain 707 * ContainerRequest#getBaseUri() base <code>URI</code>} in a new 708 * {@link ContainerRequest}; may be {@code null} in which case the 709 * return value of {@link URI#create(String) URI.create("/")} will 710 * be used instead 711 * 712 * @param sslContext an {@link SslContext}; may be {@code null} in 713 * which case network communications will occur in plain text 714 * 715 * @param http2Support if HTTP/2 support (including upgrades, prior 716 * knowledge, h2c, etc.) should be enabled 717 * 718 * @param maxIncomingContentLength in the case of HTTP to HTTP/2 719 * upgrades, a {@code long} that governs the maximum permitted 720 * incoming entity length in bytes; if less than {@code 0} then 721 * {@link Long#MAX_VALUE} will be used instead; if exactly {@code 0} 722 * then if the HTTP message containing the upgrade header is 723 * something like a {@code POST} it will be rejected with a {@code 724 * 413} error code; ignored entirely if {@code http2Support} is 725 * {@code false} 726 * 727 * @param jerseyEventExecutorGroup an {@link EventExecutorGroup} 728 * that will manage the thread on which an {@link 729 * ApplicationHandler#handle(ContainerRequest)} call will occur; may 730 * be {@code null} in which case a new {@link 731 * DefaultEventExecutorGroup} will be used instead 732 * 733 * @param applicationHandlerSupplier a {@link Supplier} of an {@link 734 * ApplicationHandler} representing a <a 735 * href="https://jakarta.ee/specifications/restful-ws/" 736 * target="_parent">Jakarta RESTful Web Services application</a> 737 * whose {@link ApplicationHandler#handle(ContainerRequest)} method 738 * will serve as the bridge between Netty and Jersey; may be {@code 739 * null} somewhat pathologically but normally is not 740 * 741 * @param flushThreshold the minimum number of bytes that an {@link 742 * AbstractByteBufBackedChannelOutboundInvokingOutputStream} 743 * returned by an implementation of the {@link 744 * AbstractContainerRequestHandlingResponseWriter#createOutputStream(long, 745 * ContainerResponse)} method must write before an automatic 746 * {@linkplain 747 * AbstractByteBufBackedChannelOutboundInvokingOutputStream#flush() 748 * flush} may take place; if less than {@code 0} {@code 0} will be 749 * used instead; if {@link Integer#MAX_VALUE} then it is suggested 750 * that no automatic flushing will occur 751 * 752 * @param byteBufCreator a {@link ByteBufCreator} that will be 753 * {@linkplain 754 * AbstractContainerRequestHandlingResponseWriter#AbstractContainerRequestHandlingResponseWriter(Supplier, 755 * int, 756 * AbstractByteBufBackedChannelOutboundInvokingOutputStream.ByteBufCreator) 757 * passed to an 758 * <code>AbstractContainerRequestHandlingResponseWriter</code>} 759 * implementation; may be {@code null} 760 * 761 * @see #JerseyChannelInitializer(URI, SslContext, boolean, long, 762 * EventExecutorGroup, boolean, Supplier, int, 763 * AbstractByteBufBackedChannelOutboundInvokingOutputStream.ByteBufCreator) 764 * @see ContainerRequest 765 * 766 * @see SslContext 767 * 768 * @see 769 * HttpServerUpgradeHandler#HttpServerUpgradeHandler(SourceCodec, 770 * UpgradeCodecFactory, int) 771 * 772 * @see ApplicationHandler#handle(ContainerRequest) 773 * 774 * @see AbstractContainerRequestHandlingResponseWriter 775 * 776 * @see HttpObjectToContainerRequestDecoder 777 * 778 * @see HttpContainerRequestHandlingResponseWriter 779 * 780 * @see Http2StreamFrameToContainerRequestDecoder 781 * 782 * @see Http2ContainerRequestHandlingResponseWriter 783 */ 784 public JerseyChannelInitializer(final URI baseUri, 785 final SslContext sslContext, 786 final boolean http2Support, 787 final long maxIncomingContentLength, 788 final EventExecutorGroup jerseyEventExecutorGroup, 789 final Supplier<? extends ApplicationHandler> applicationHandlerSupplier, 790 final int flushThreshold, 791 final ByteBufCreator byteBufCreator) { 792 this(baseUri, 793 sslContext, 794 http2Support, 795 maxIncomingContentLength, 796 jerseyEventExecutorGroup, 797 true, /* use Jersey injection */ 798 applicationHandlerSupplier, 799 flushThreshold, 800 byteBufCreator); 801 } 802 803 /** 804 * Creates a new {@link JerseyChannelInitializer}. 805 * 806 * @param baseUri a {@link URI} that will serve as the {@linkplain 807 * ContainerRequest#getBaseUri() base <code>URI</code>} in a new 808 * {@link ContainerRequest}; may be {@code null} in which case the 809 * return value of {@link URI#create(String) URI.create("/")} will 810 * be used instead 811 * 812 * @param sslContext an {@link SslContext}; may be {@code null} in 813 * which case network communications will occur in plain text 814 * 815 * @param http2Support if HTTP/2 support (including upgrades, prior 816 * knowledge, h2c, etc.) should be enabled 817 * 818 * @param maxIncomingContentLength in the case of HTTP to HTTP/2 819 * upgrades, a {@code long} that governs the maximum permitted 820 * incoming entity length in bytes; if less than {@code 0} then 821 * {@link Long#MAX_VALUE} will be used instead; if exactly {@code 0} 822 * then if the HTTP message containing the upgrade header is 823 * something like a {@code POST} it will be rejected with a {@code 824 * 413} error code; ignored entirely if {@code http2Support} is 825 * {@code false} 826 * 827 * @param jerseyEventExecutorGroup an {@link EventExecutorGroup} 828 * that will manage the thread on which an {@link 829 * ApplicationHandler#handle(ContainerRequest)} call will occur; may 830 * be {@code null} in which case a new {@link 831 * DefaultEventExecutorGroup} will be used instead 832 * 833 * @param useJerseyInjection if {@code true} then certain Netty 834 * constructs like {@link ChannelHandlerContext} will be made 835 * available for dependency injection in user applications using 836 * Jersey's native dependency injection facilities; if {@code false} 837 * then these facilities will not be used or referenced 838 * 839 * @param applicationHandler an {@link ApplicationHandler} 840 * representing a <a 841 * href="https://jakarta.ee/specifications/restful-ws/" 842 * target="_parent">Jakarta RESTful Web Services application</a> 843 * whose {@link ApplicationHandler#handle(ContainerRequest)} method 844 * will serve as the bridge between Netty and Jersey; may be {@code 845 * null} somewhat pathologically but normally is not 846 * 847 * @param flushThreshold the minimum number of bytes that an {@link 848 * AbstractByteBufBackedChannelOutboundInvokingOutputStream} 849 * returned by an implementation of the {@link 850 * AbstractContainerRequestHandlingResponseWriter#createOutputStream(long, 851 * ContainerResponse)} method must write before an automatic 852 * {@linkplain 853 * AbstractByteBufBackedChannelOutboundInvokingOutputStream#flush() 854 * flush} may take place; if less than {@code 0} {@code 0} will be 855 * used instead; if {@link Integer#MAX_VALUE} then it is suggested 856 * that no automatic flushing will occur 857 * 858 * @param byteBufCreator a {@link ByteBufCreator} that will be 859 * {@linkplain 860 * AbstractContainerRequestHandlingResponseWriter#AbstractContainerRequestHandlingResponseWriter(Supplier, 861 * int, 862 * AbstractByteBufBackedChannelOutboundInvokingOutputStream.ByteBufCreator) 863 * passed to an 864 * <code>AbstractContainerRequestHandlingResponseWriter</code>} 865 * implementation; may be {@code null} 866 * 867 * @see ContainerRequest 868 * 869 * @see SslContext 870 * 871 * @see 872 * HttpServerUpgradeHandler#HttpServerUpgradeHandler(SourceCodec, 873 * UpgradeCodecFactory, int) 874 * 875 * @see ApplicationHandler#handle(ContainerRequest) 876 * 877 * @see AbstractContainerRequestHandlingResponseWriter 878 * 879 * @see HttpObjectToContainerRequestDecoder 880 * 881 * @see HttpContainerRequestHandlingResponseWriter 882 * 883 * @see Http2StreamFrameToContainerRequestDecoder 884 * 885 * @see Http2ContainerRequestHandlingResponseWriter 886 */ 887 public JerseyChannelInitializer(final URI baseUri, 888 final SslContext sslContext, 889 final boolean http2Support, 890 final long maxIncomingContentLength, 891 final EventExecutorGroup jerseyEventExecutorGroup, 892 final boolean useJerseyInjection, 893 final ApplicationHandler applicationHandler, 894 final int flushThreshold, 895 final ByteBufCreator byteBufCreator) { 896 this(baseUri, 897 sslContext, 898 http2Support, 899 maxIncomingContentLength, 900 jerseyEventExecutorGroup, 901 useJerseyInjection, 902 toApplicationHandlerSupplier(applicationHandler), 903 flushThreshold, 904 byteBufCreator); 905 } 906 907 /** 908 * Creates a new {@link JerseyChannelInitializer}. 909 * 910 * @param baseUri a {@link URI} that will serve as the {@linkplain 911 * ContainerRequest#getBaseUri() base <code>URI</code>} in a new 912 * {@link ContainerRequest}; may be {@code null} in which case the 913 * return value of {@link URI#create(String) URI.create("/")} will 914 * be used instead 915 * 916 * @param sslContext an {@link SslContext}; may be {@code null} in 917 * which case network communications will occur in plain text 918 * 919 * @param http2Support if HTTP/2 support (including upgrades, prior 920 * knowledge, h2c, etc.) should be enabled 921 * 922 * @param maxIncomingContentLength in the case of HTTP to HTTP/2 923 * upgrades, a {@code long} that governs the maximum permitted 924 * incoming entity length in bytes; if less than {@code 0} then 925 * {@link Long#MAX_VALUE} will be used instead; if exactly {@code 0} 926 * then if the HTTP message containing the upgrade header is 927 * something like a {@code POST} it will be rejected with a {@code 928 * 413} error code; ignored entirely if {@code http2Support} is 929 * {@code false} 930 * 931 * @param jerseyEventExecutorGroup an {@link EventExecutorGroup} 932 * that will manage the thread on which an {@link 933 * ApplicationHandler#handle(ContainerRequest)} call will occur; may 934 * be {@code null} in which case a new {@link 935 * DefaultEventExecutorGroup} will be used instead 936 * 937 * @param useJerseyInjection if {@code true} then certain Netty 938 * constructs like {@link ChannelHandlerContext} will be made 939 * available for dependency injection in user applications using 940 * Jersey's native dependency injection facilities; if {@code false} 941 * then these facilities will not be used or referenced 942 * 943 * @param applicationHandlerSupplier a {@link Supplier} of an {@link 944 * ApplicationHandler} representing a <a 945 * href="https://jakarta.ee/specifications/restful-ws/" 946 * target="_parent">Jakarta RESTful Web Services application</a> 947 * whose {@link ApplicationHandler#handle(ContainerRequest)} method 948 * will serve as the bridge between Netty and Jersey; may be {@code 949 * null} somewhat pathologically but normally is not. 950 * 951 * @param flushThreshold the minimum number of bytes that an {@link 952 * AbstractByteBufBackedChannelOutboundInvokingOutputStream} 953 * returned by an implementation of the {@link 954 * AbstractContainerRequestHandlingResponseWriter#createOutputStream(long, 955 * ContainerResponse)} method must write before an automatic 956 * {@linkplain 957 * AbstractByteBufBackedChannelOutboundInvokingOutputStream#flush() 958 * flush} may take place; if less than {@code 0} {@code 0} will be 959 * used instead; if {@link Integer#MAX_VALUE} then it is suggested 960 * that no automatic flushing will occur 961 * 962 * @param byteBufCreator a {@link ByteBufCreator} that will be 963 * {@linkplain 964 * AbstractContainerRequestHandlingResponseWriter#AbstractContainerRequestHandlingResponseWriter(Supplier, 965 * int, 966 * AbstractByteBufBackedChannelOutboundInvokingOutputStream.ByteBufCreator) 967 * passed to an 968 * <code>AbstractContainerRequestHandlingResponseWriter</code>} 969 * implementation; may be {@code null} 970 * 971 * @see ContainerRequest 972 * 973 * @see SslContext 974 * 975 * @see 976 * HttpServerUpgradeHandler#HttpServerUpgradeHandler(SourceCodec, 977 * UpgradeCodecFactory, int) 978 * 979 * @see ApplicationHandler#handle(ContainerRequest) 980 * 981 * @see AbstractContainerRequestHandlingResponseWriter 982 * 983 * @see HttpObjectToContainerRequestDecoder 984 * 985 * @see HttpContainerRequestHandlingResponseWriter 986 * 987 * @see Http2StreamFrameToContainerRequestDecoder 988 * 989 * @see Http2ContainerRequestHandlingResponseWriter 990 */ 991 public JerseyChannelInitializer(final URI baseUri, 992 final SslContext sslContext, 993 final boolean http2Support, 994 final long maxIncomingContentLength, 995 final EventExecutorGroup jerseyEventExecutorGroup, 996 final boolean useJerseyInjection, 997 Supplier<? extends ApplicationHandler> applicationHandlerSupplier, 998 final int flushThreshold, 999 final ByteBufCreator byteBufCreator) { 1000 super(); 1001 this.baseUri = baseUri; 1002 this.sslContext = sslContext; 1003 this.http2Support = http2Support; 1004 // It's somewhat odd that Netty's MessageAggregator class (of 1005 // which HttpServerUpgradeHandler is a subclass) expresses a 1006 // maximum content length as an int, when Jersey and other 1007 // HTTP-centric frameworks express it as a long. We will accept a 1008 // long and truncate it where necessary. 1009 if (maxIncomingContentLength < 0L) { 1010 this.maxIncomingContentLength = Long.MAX_VALUE; 1011 } else { 1012 this.maxIncomingContentLength = maxIncomingContentLength; 1013 } 1014 if (jerseyEventExecutorGroup == null) { 1015 this.jerseyEventExecutorGroup = new DefaultEventExecutorGroup(Runtime.getRuntime().availableProcessors()); // no idea how to size this 1016 } else { 1017 this.jerseyEventExecutorGroup = jerseyEventExecutorGroup; 1018 } 1019 if (applicationHandlerSupplier == null) { 1020 final ApplicationHandler applicationHandler = new ApplicationHandler(); 1021 applicationHandlerSupplier = new ImmutableSupplier<>(applicationHandler); 1022 } 1023 if (useJerseyInjection) { 1024 // The idiom you see before you is apparently the right and only 1025 // way to install non-proxiable objects into request scope: you 1026 // install a factory that makes factories of mutable references 1027 // that produce the object you want, then elsewhere set the 1028 // payload of those references when you're actually in request 1029 // scope. Really. You'll find this pattern throughout the 1030 // Jersey codebase. We follow suit here. 1031 final InjectionManager injectionManager = applicationHandlerSupplier.get().getInjectionManager(); 1032 if (injectionManager != null) { 1033 injectionManager.register(Bindings.supplier(ChannelHandlerContextReferencingFactory.class) 1034 .to(ChannelHandlerContext.class) 1035 .proxy(false) 1036 .in(RequestScoped.class)); 1037 injectionManager.register(Bindings.supplier(ReferencingFactory.<ChannelHandlerContext>referenceFactory()) 1038 .to(ChannelHandlerContextReferencingFactory.genericRefType) 1039 .in(RequestScoped.class)); 1040 injectionManager.register(Bindings.supplier(HttpRequestReferencingFactory.class) 1041 .to(HttpRequest.class) 1042 .proxy(false) 1043 .in(RequestScoped.class)); 1044 injectionManager.register(Bindings.supplier(ReferencingFactory.<HttpRequest>referenceFactory()) 1045 .to(HttpRequestReferencingFactory.genericRefType) 1046 .in(RequestScoped.class)); 1047 if (http2Support) { 1048 injectionManager.register(Bindings.supplier(Http2HeadersFrameReferencingFactory.class) 1049 .to(Http2HeadersFrame.class) 1050 .proxy(false) 1051 .in(RequestScoped.class)); 1052 injectionManager.register(Bindings.supplier(ReferencingFactory.<Http2HeadersFrame>referenceFactory()) 1053 .to(Http2HeadersFrameReferencingFactory.genericRefType) 1054 .in(RequestScoped.class)); 1055 } 1056 } 1057 } 1058 this.applicationHandlerSupplier = applicationHandlerSupplier; 1059 this.flushThreshold = Math.max(0, flushThreshold); 1060 this.byteBufCreator = byteBufCreator; 1061 } 1062 1063 1064 /* 1065 * Instance methods. 1066 */ 1067 1068 1069 /** 1070 * Returns the {@link EventExecutorGroup} that this {@link 1071 * JerseyChannelInitializer} will use to offload blocking work from 1072 * the Netty event loop. 1073 * 1074 * <p>This method never returns {@code null}.</p> 1075 * 1076 * @return a non-{@code null} {@link EventExecutorGroup} 1077 * 1078 * @see #JerseyChannelInitializer(URI, SslContext, boolean, long, 1079 * EventExecutorGroup, boolean, Supplier, int, 1080 * AbstractByteBufBackedChannelOutboundInvokingOutputStream.ByteBufCreator) 1081 */ 1082 public final EventExecutorGroup getJerseyEventExecutorGroup() { 1083 return this.jerseyEventExecutorGroup; 1084 } 1085 1086 /** 1087 * Returns the {@link URI} that was {@linkplain 1088 * #JerseyChannelInitializer(URI, SslContext, boolean, long, 1089 * EventExecutorGroup, boolean, Supplier, int, 1090 * AbstractByteBufBackedChannelOutboundInvokingOutputStream.ByteBufCreator) 1091 * supplied at construction time}. 1092 * 1093 * <p>This method may return {@code null}.</p> 1094 * 1095 * @return the {@link URI} that was {@linkplain 1096 * #JerseyChannelInitializer(URI, SslContext, boolean, long, 1097 * EventExecutorGroup, boolean, Supplier, int, 1098 * AbstractByteBufBackedChannelOutboundInvokingOutputStream.ByteBufCreator) 1099 * supplied at construction time}, or {@code null} 1100 * 1101 * @see #JerseyChannelInitializer(URI, SslContext, boolean, long, 1102 * EventExecutorGroup, boolean, Supplier, int, 1103 * AbstractByteBufBackedChannelOutboundInvokingOutputStream.ByteBufCreator) 1104 */ 1105 public final URI getBaseUri() { 1106 return this.baseUri; 1107 } 1108 1109 /** 1110 * Initializes the supplied {@link Channel} using an appropriate 1111 * sequencing of several {@link ChannelHandler}s and other Netty 1112 * utility classes. 1113 * 1114 * <p>The {@link ChannelHandler}s and other classes involved include:</p> 1115 * 1116 * <ul> 1117 * 1118 * <li>{@link HttpObjectToContainerRequestDecoder}</li> 1119 * 1120 * <li>{@link HttpContainerRequestHandlingResponseWriter}</li> 1121 * 1122 * <li>{@link Http2StreamFrameToContainerRequestDecoder}</li> 1123 * 1124 * <li>{@link Http2ContainerRequestHandlingResponseWriter}</li> 1125 * 1126 * <li>{@link HttpServerCodec}</li> 1127 * 1128 * <li>{@link UpgradeCodecFactory}</li> 1129 * 1130 * <li>{@link UpgradeCodec}</li> 1131 * 1132 * <li>{@link Http2FrameCodecBuilder}</li> 1133 * 1134 * <li>{@link Http2FrameCodec}</li> 1135 * 1136 * <li>{@link Http2ServerUpgradeCodec}</li> 1137 * 1138 * <li>{@link Http2MultiplexHandler}</li> 1139 * 1140 * <li>{@link HttpServerUpgradeHandler}</li> 1141 * 1142 * <li>{@link CleartextHttp2ServerUpgradeHandler}</li> 1143 * 1144 * <li>{@link HttpServerExpectContinueHandler}</li> 1145 * 1146 * <li>{@link HttpNegotiationHandler}</li> 1147 * 1148 * </ul> 1149 * 1150 * <p>All of these classes collaborate to form a {@link 1151 * ChannelPipeline} that can handle HTTP 1.0, HTTP 1.1 and HTTP/2 1152 * scenarios, including upgrades.</p> 1153 * 1154 * @param channel the {@link Channel} to initialize; must not be 1155 * {@code null} 1156 * 1157 * @exception NullPointerException if {@code channel} is {@code 1158 * null}, or if the return value of {@link Channel#pipeline() 1159 * channel.pipeline()} is {@code null} 1160 */ 1161 @Override 1162 protected final void initChannel(final Channel channel) { 1163 Objects.requireNonNull(channel); 1164 final ChannelPipeline channelPipeline = Objects.requireNonNull(channel.pipeline()); 1165 1166 final SslHandler sslHandler; 1167 if (this.sslContext == null) { 1168 sslHandler = null; 1169 } else { 1170 sslHandler = createSslHandler(this.sslContext, channel.alloc()); 1171 } 1172 1173 if (sslHandler == null) { 1174 1175 final HttpServerCodec httpServerCodec = new HttpServerCodec(); 1176 1177 if (this.http2Support) { 1178 1179 // See https://github.com/netty/netty/issues/7079 1180 final int maxIncomingContentLength; 1181 if (this.maxIncomingContentLength >= Integer.MAX_VALUE) { 1182 maxIncomingContentLength = Integer.MAX_VALUE; 1183 } else { 1184 maxIncomingContentLength = (int)this.maxIncomingContentLength; 1185 } 1186 1187 final UpgradeCodecFactory upgradeCodecFactory = new UpgradeCodecFactory() { 1188 @Override 1189 public final UpgradeCodec newUpgradeCodec(final CharSequence protocolName) { 1190 final UpgradeCodec returnValue; 1191 if (protocolName == null || 1192 !AsciiString.contentEquals(Http2CodecUtil.HTTP_UPGRADE_PROTOCOL_NAME, protocolName)) { 1193 returnValue = null; 1194 } else { 1195 returnValue = 1196 new Http2ServerUpgradeCodec(Http2FrameCodecBuilder.forServer().build(), 1197 new Http2MultiplexHandler(new Http2JerseyChannelInitializer(getJerseyEventExecutorGroup(), 1198 baseUri, 1199 applicationHandlerSupplier, 1200 flushThreshold, 1201 byteBufCreator))); 1202 } 1203 return returnValue; 1204 } 1205 }; 1206 1207 // Create a handler that will deal with HTTP 1.1-to-HTTP/2 1208 // upgrade scenarios. It by itself doesn't really do anything 1209 // but it will be supplied to a new instance of 1210 // CleartextHttp2ServerUpgradeHandler. 1211 final HttpServerUpgradeHandler httpServerUpgradeHandler = 1212 new HttpServerUpgradeHandler(httpServerCodec, upgradeCodecFactory, maxIncomingContentLength); 1213 1214 // Build a CleartextHttp2ServerUpgradeHandler. This is really a 1215 // channel pipeline reconfigurator: it arranges things such 1216 // that: 1217 // 1218 // * A private internal handler created inside the 1219 // CleartextHttp2ServerUpgradeHandler class is added first 1220 // (it will see if a prior knowledge situation is 1221 // occurring and then will decide to do with the handlers 1222 // supplied in this constructor; see 1223 // https://github.com/netty/netty/blob/d8b1a2d93f556a08270e6549bf7f91b3b09f24bb/codec-http2/src/main/java/io/netty/handler/codec/http2/CleartextHttp2ServerUpgradeHandler.java#L74-L100 1224 // for details) 1225 // 1226 // * The first handler, an HttpServerCodec, MAY be added to 1227 // the pipeline next (it will, if the prior knowledge 1228 // handler doesn't bypass and remove it, be responsible 1229 // for interpreting an HTTP 1.1 message that might be 1230 // destined for an upgrade to HTTP/2) 1231 // 1232 // * The second handler, an HttpServerUpgradeHandler, 1233 // created by us above, will be added next if indeed the 1234 // HttpServerCodec was actually added by the prior 1235 // knowledge handler (it will read an HttpMessage (an HTTP 1236 // 1.1 message) and will see if it represents an upgrade 1237 // request). If this handler is actually added to the 1238 // pipeline, then "prior knowledge" is not in effect. 1239 // 1240 // * The third handler is held in reserve to be used only in 1241 // those cases where prior knowledge is in effect; see 1242 // https://github.com/netty/netty/blob/d8b1a2d93f556a08270e6549bf7f91b3b09f24bb/codec-http2/src/main/java/io/netty/handler/codec/http2/CleartextHttp2ServerUpgradeHandler.java#L90-L95 1243 // for details and 1244 // https://http2.github.io/http2-spec/#known-http for 1245 // specification references. 1246 // 1247 // This API is tremendously confusing; it's not just you. 1248 final CleartextHttp2ServerUpgradeHandler cleartextHttp2ServerUpgradeHandler = 1249 new CleartextHttp2ServerUpgradeHandler(httpServerCodec, 1250 httpServerUpgradeHandler, 1251 new ChannelInitializer<Channel>() { 1252 @Override 1253 public final void initChannel(final Channel channel) { 1254 // "Prior 1255 // knowledge" is in 1256 // effect. See 1257 // https://http2.github.io/http2-spec/#known-http. 1258 final ChannelPipeline channelPipeline = channel.pipeline(); 1259 channelPipeline.addLast(Http2FrameCodec.class.getSimpleName(), 1260 Http2FrameCodecBuilder.forServer().build()); 1261 channelPipeline.addLast(Http2MultiplexHandler.class.getSimpleName(), 1262 new Http2MultiplexHandler(new Http2JerseyChannelInitializer(getJerseyEventExecutorGroup(), 1263 baseUri, 1264 applicationHandlerSupplier, 1265 flushThreshold, 1266 byteBufCreator))); 1267 } 1268 }); 1269 channelPipeline.addLast(cleartextHttp2ServerUpgradeHandler); 1270 1271 // We add a CONDITIONAL handler for the (probably very common) 1272 // case where no one (a) connected with HTTP/2 or (b) asked 1273 // for an HTTP/2 upgrade. In this case after all the 1274 // shenanigans we just jumped through we're just a regular old 1275 // common HTTP 1.1 connection. Strangely, we have to handle 1276 // this in Netty as a special case even though it is likely to 1277 // be the most common one. 1278 channelPipeline.addLast(new SimpleChannelInboundHandler<HttpMessage>() { 1279 @Override 1280 protected final void channelRead0(final ChannelHandlerContext channelHandlerContext, 1281 final HttpMessage httpMessage) 1282 throws Exception { 1283 final ChannelPipeline channelPipeline = channelHandlerContext.pipeline(); 1284 1285 // If we're actually called then we know that in "front" 1286 // of us is an HttpServerCodec because otherwise we 1287 // wouldn't have been called (note that our event is an 1288 // HttpMessage). Now that we know this is going to be 1289 // HTTP 1.1 with no upgrades, replace *this* handler 1290 // we're "in" now with a handler that deals with HTTP 1291 // 100-class statuses... 1292 channelPipeline.replace(this, 1293 HttpServerExpectContinueHandler.class.getSimpleName(), 1294 new HttpServerExpectContinueHandler()); 1295 1296 // ...and then after that add the "real" initializer (a 1297 // JerseyChannelSubInitializer instance, defined below 1298 // in this source file) that will install a 1299 // ChunkedWriteHandler followed by the main Jersey 1300 // integration. 1301 channelPipeline.addLast("HttpJerseyChannelInitializer", 1302 new HttpJerseyChannelInitializer(getJerseyEventExecutorGroup(), 1303 baseUri, 1304 applicationHandlerSupplier, 1305 flushThreshold, 1306 byteBufCreator)); 1307 1308 // Forward the event on as we never touched it. 1309 channelHandlerContext.fireChannelRead(ReferenceCountUtil.retain(httpMessage)); 1310 } 1311 }); 1312 } else { 1313 channelPipeline.addLast(HttpServerCodec.class.getSimpleName(), 1314 httpServerCodec); 1315 channelPipeline.addLast(HttpServerExpectContinueHandler.class.getSimpleName(), 1316 new HttpServerExpectContinueHandler()); 1317 channelPipeline.addLast("HttpJerseyChannelInitializer", 1318 new HttpJerseyChannelInitializer(this.getJerseyEventExecutorGroup(), 1319 baseUri, 1320 applicationHandlerSupplier, 1321 flushThreshold, 1322 byteBufCreator)); 1323 } 1324 1325 1326 } else { 1327 1328 // The SSL handler decodes TLS stuff... 1329 channelPipeline.addLast(sslHandler.getClass().getSimpleName(), 1330 sslHandler); 1331 1332 // ...then the HttpNegotiationHandler does ALPN 1333 // (Application-Level Protocol Negotiation) to figure out 1334 // whether it's HTTP 1.1 or HTTP/2; see the private inner 1335 // class below for details. 1336 channelPipeline.addLast(HttpNegotiationHandler.class.getSimpleName(), 1337 new HttpNegotiationHandler(this.getJerseyEventExecutorGroup(), 1338 baseUri, 1339 applicationHandlerSupplier, 1340 flushThreshold, 1341 byteBufCreator)); 1342 1343 } 1344 1345 } 1346 1347 /** 1348 * Creates and returns a new {@link SslHandler} when invoked. 1349 * 1350 * <p>This method never returns {@code null}.</p> 1351 * 1352 * <p>Overrides of this method must not return {@code null}.</p> 1353 * 1354 * <p>This implementation calls {@link 1355 * SslContext#newHandler(ByteBufAllocator) 1356 * sslContext.newHandler(byteBufAllocator)} and returns the 1357 * result.</p> 1358 * 1359 * @param sslContext the {@link SslContext} that may assist in the 1360 * creation; must not be {@code null} 1361 * 1362 * @param byteBufAllocator a {@link ByteBufAllocator} that may 1363 * assist in the creation; must not be {@code null} 1364 * 1365 * @return a new {@link SslHandler}; never {@code null} 1366 * 1367 * @exception NullPointerException if {@code sslContext} is {@code null} 1368 * 1369 * @see SslContext#newHandler(ByteBufAllocator) 1370 */ 1371 protected SslHandler createSslHandler(final SslContext sslContext, final ByteBufAllocator byteBufAllocator) { 1372 return sslContext.newHandler(byteBufAllocator); 1373 } 1374 1375 1376 /* 1377 * Static methods. 1378 */ 1379 1380 1381 private static final Supplier<? extends ApplicationHandler> toApplicationHandlerSupplier(final Application application) { 1382 return toApplicationHandlerSupplier(application == null ? new ApplicationHandler() : new ApplicationHandler(application)); 1383 } 1384 1385 private static final Supplier<? extends ApplicationHandler> toApplicationHandlerSupplier(final ApplicationHandler suppliedApplicationHandler) { 1386 return new ImmutableSupplier<>(suppliedApplicationHandler == null ? new ApplicationHandler() : suppliedApplicationHandler); 1387 } 1388 1389 private static final Supplier<? extends Configuration> toConfigurationSupplier(final Supplier<? extends ApplicationHandler> applicationHandlerSupplier) { 1390 return applicationHandlerSupplier == null ? JerseyChannelInitializer::returnNullConfiguration : new ConfigurationSupplier(applicationHandlerSupplier); 1391 } 1392 1393 private static final Configuration returnNullConfiguration() { 1394 return null; 1395 } 1396 1397 private static final ApplicationHandler returnNullApplicationHandler() { 1398 return null; 1399 } 1400 1401 1402 /* 1403 * Inner and nested classes. 1404 */ 1405 1406 1407 private static final class ConfigurationSupplier implements Supplier<Configuration> { 1408 1409 private final Supplier<? extends ApplicationHandler> applicationHandlerSupplier; 1410 1411 private ConfigurationSupplier(final Supplier<? extends ApplicationHandler> applicationHandlerSupplier) { 1412 super(); 1413 this.applicationHandlerSupplier = applicationHandlerSupplier == null ? JerseyChannelInitializer::returnNullApplicationHandler : applicationHandlerSupplier; 1414 } 1415 1416 @Override 1417 public final Configuration get() { 1418 final ApplicationHandler applicationHandler = this.applicationHandlerSupplier.get(); 1419 return applicationHandler == null ? null : applicationHandler.getConfiguration(); 1420 } 1421 1422 } 1423 1424 /** 1425 * A {@link ChannelInitializer} that {@linkplain 1426 * ChannelPipeline#addLast(String, ChannelHandler) adds} an {@link 1427 * HttpObjectToContainerRequestDecoder} followed by an {@link 1428 * HttpContainerRequestHandlingResponseWriter} (which is added with 1429 * its own {@link EventExecutorGroup}). 1430 * 1431 * @author <a href="https://about.me/lairdnelson" 1432 * target="_parent">Laird Nelson</a> 1433 * 1434 * @see ChannelInitializer 1435 */ 1436 private static final class HttpJerseyChannelInitializer extends ChannelInitializer<Channel> { 1437 1438 private final EventExecutorGroup jerseyEventExecutorGroup; 1439 1440 private final URI baseUri; 1441 1442 private final Supplier<? extends ApplicationHandler> applicationHandlerSupplier; 1443 1444 private final Supplier<? extends Configuration> configurationSupplier; 1445 1446 private final int flushThreshold; 1447 1448 private final ByteBufCreator byteBufCreator; 1449 1450 /** 1451 * Creates a new {@link HttpJerseyChannelInitializer}. 1452 */ 1453 private HttpJerseyChannelInitializer(final EventExecutorGroup jerseyEventExecutorGroup, 1454 final URI baseUri, 1455 final Supplier<? extends ApplicationHandler> applicationHandlerSupplier, 1456 final int flushThreshold, 1457 final ByteBufCreator byteBufCreator) { 1458 super(); 1459 this.jerseyEventExecutorGroup = Objects.requireNonNull(jerseyEventExecutorGroup); 1460 this.baseUri = baseUri; 1461 this.applicationHandlerSupplier = applicationHandlerSupplier; 1462 this.configurationSupplier = toConfigurationSupplier(applicationHandlerSupplier); 1463 this.flushThreshold = Math.max(0, flushThreshold); 1464 this.byteBufCreator = byteBufCreator; 1465 } 1466 1467 /** 1468 * {@linkplain ChannelPipeline#addLast(String, ChannelHandler) 1469 * Adds} an {@link 1470 * HttpObjectToContainerRequestDecoder} followed by an {@link 1471 * HttpContainerRequestHandlingResponseWriter} (which is added with 1472 * its own {@link EventExecutorGroup}) 1473 * 1474 * @param channel the {@link Channel} being configured; must 1475 * not be {@code null} 1476 * 1477 */ 1478 @Override 1479 protected final void initChannel(final Channel channel) { 1480 final ChannelPipeline channelPipeline = channel.pipeline(); 1481 channelPipeline.addLast(HttpObjectToContainerRequestDecoder.class.getSimpleName(), 1482 new HttpObjectToContainerRequestDecoder(baseUri, this.configurationSupplier)); 1483 channelPipeline.addLast(jerseyEventExecutorGroup, 1484 HttpContainerRequestHandlingResponseWriter.class.getSimpleName(), 1485 new HttpContainerRequestHandlingResponseWriter(applicationHandlerSupplier, 1486 flushThreshold, 1487 byteBufCreator)); 1488 } 1489 1490 } 1491 1492 1493 /** 1494 * A {@link ChannelInitializer} that {@linkplain 1495 * ChannelPipeline#addLast(String, ChannelHandler) adds} an {@link 1496 * Http2StreamFrameToContainerRequestDecoder} followed by an {@link 1497 * Http2ContainerRequestHandlingResponseWriter} (which is added with 1498 * its own {@link EventExecutorGroup}). 1499 * 1500 * @author <a href="https://about.me/lairdnelson" 1501 * target="_parent">Laird Nelson</a> 1502 * 1503 * @see ChannelInitializer 1504 */ 1505 private static final class Http2JerseyChannelInitializer extends ChannelInitializer<Channel> { 1506 1507 private final EventExecutorGroup jerseyEventExecutorGroup; 1508 1509 private final URI baseUri; 1510 1511 private final Supplier<? extends ApplicationHandler> applicationHandlerSupplier; 1512 1513 private final Supplier<? extends Configuration> configurationSupplier; 1514 1515 private final int flushThreshold; 1516 1517 private final ByteBufCreator byteBufCreator; 1518 1519 /** 1520 * Creates a new {@link Http2JerseyChannelInitializer}. 1521 */ 1522 private Http2JerseyChannelInitializer(final EventExecutorGroup jerseyEventExecutorGroup, 1523 final URI baseUri, 1524 final Supplier<? extends ApplicationHandler> applicationHandlerSupplier, 1525 final int flushThreshold, 1526 final ByteBufCreator byteBufCreator) { 1527 super(); 1528 this.jerseyEventExecutorGroup = Objects.requireNonNull(jerseyEventExecutorGroup); 1529 this.baseUri = baseUri; 1530 this.applicationHandlerSupplier = applicationHandlerSupplier; 1531 this.configurationSupplier = toConfigurationSupplier(applicationHandlerSupplier); 1532 this.flushThreshold = Math.max(0, flushThreshold); 1533 this.byteBufCreator = byteBufCreator; 1534 } 1535 1536 /** 1537 * {@linkplain ChannelPipeline#addLast(String, ChannelHandler) 1538 * Adds} an {@link 1539 * Http2StreamFrameToContainerRequestDecoder} followed by an {@link 1540 * Http2ContainerRequestHandlingResponseWriter} (which is added with 1541 * its own {@link EventExecutorGroup}). 1542 * 1543 * @param channel the {@link Channel} being configured; must 1544 * not be {@code null} 1545 * 1546 * @exception NullPointerException if {@code channel} is {@code 1547 * null} 1548 */ 1549 @Override 1550 protected final void initChannel(final Channel channel) { 1551 final ChannelPipeline channelPipeline = channel.pipeline(); 1552 channelPipeline.addLast(Http2StreamFrameToContainerRequestDecoder.class.getSimpleName(), 1553 new Http2StreamFrameToContainerRequestDecoder(baseUri, this.configurationSupplier)); 1554 channelPipeline.addLast(jerseyEventExecutorGroup, 1555 Http2ContainerRequestHandlingResponseWriter.class.getSimpleName(), 1556 new Http2ContainerRequestHandlingResponseWriter(this.applicationHandlerSupplier)); 1557 } 1558 1559 } 1560 1561 /** 1562 * An {@link ApplicationProtocolNegotiationHandler} that knows how 1563 * to configure a {@link ChannelPipeline} for HTTP 1.1 or HTTP/2 1564 * requests that require Jersey integration. 1565 * 1566 * @author <a href="https://about.me/lairdnelson" 1567 * target="_parent">Laird Nelson</a> 1568 * 1569 * @see ApplicationProtocolNegotiationHandler 1570 */ 1571 private static final class HttpNegotiationHandler extends ApplicationProtocolNegotiationHandler { 1572 1573 private final EventExecutorGroup jerseyEventExecutorGroup; 1574 1575 private final URI baseUri; 1576 1577 private final Supplier<? extends ApplicationHandler> applicationHandlerSupplier; 1578 1579 private final int flushThreshold; 1580 1581 private final ByteBufCreator byteBufCreator; 1582 /** 1583 * Creates a new {@link HttpNegotiationHandler}. 1584 */ 1585 private HttpNegotiationHandler(final EventExecutorGroup jerseyEventExecutorGroup, 1586 final URI baseUri, 1587 final Supplier<? extends ApplicationHandler> applicationHandlerSupplier, 1588 final int flushThreshold, 1589 final ByteBufCreator byteBufCreator) { 1590 super(ApplicationProtocolNames.HTTP_1_1); 1591 this.jerseyEventExecutorGroup = Objects.requireNonNull(jerseyEventExecutorGroup); 1592 this.baseUri = baseUri; 1593 this.applicationHandlerSupplier = applicationHandlerSupplier; 1594 this.flushThreshold = Math.max(0, flushThreshold); 1595 this.byteBufCreator = byteBufCreator; 1596 } 1597 1598 /** 1599 * Sets up the {@linkplain ChannelHandlerContext#pipeline() 1600 * current pipeline} for HTTP 1.1 or HTTP/2 requests that require 1601 * Jersey integration. 1602 * 1603 * @param channelHandlerContext a {@link ChannelHandlerContext} 1604 * representing the current Netty execution; must not be {@code 1605 * null} 1606 * 1607 * @param protocol the protocol that was negotiated; must be equal 1608 * to either {@link ApplicationProtocolNames#HTTP_2} or {@link 1609 * ApplicationProtocolNames#HTTP_1_1} 1610 * 1611 * @exception NullPointerException if {@code 1612 * channelHandlerContext} or {@code protocol} is {@code null} 1613 * 1614 * @exception IllegalArgumentException if {@code protocol} is not 1615 * equal to the value of either the {@link 1616 * ApplicationProtocolNames#HTTP_1_1} or {@link 1617 * ApplicationProtocolNames#HTTP_2} constants 1618 */ 1619 @Override 1620 protected final void configurePipeline(final ChannelHandlerContext channelHandlerContext, final String protocol) { 1621 final ChannelPipeline channelPipeline = channelHandlerContext.pipeline(); 1622 switch (protocol) { 1623 case ApplicationProtocolNames.HTTP_2: 1624 channelPipeline.addLast(Http2FrameCodec.class.getSimpleName(), 1625 Http2FrameCodecBuilder.forServer().build()); 1626 channelPipeline.addLast(Http2MultiplexHandler.class.getSimpleName(), 1627 new Http2MultiplexHandler(new Http2JerseyChannelInitializer(jerseyEventExecutorGroup, 1628 baseUri, 1629 applicationHandlerSupplier, 1630 flushThreshold, 1631 byteBufCreator))); 1632 break; 1633 case ApplicationProtocolNames.HTTP_1_1: 1634 channelPipeline.addLast(HttpServerCodec.class.getSimpleName(), 1635 new HttpServerCodec()); 1636 channelPipeline.addLast(HttpServerExpectContinueHandler.class.getSimpleName(), 1637 new HttpServerExpectContinueHandler()); 1638 channelPipeline.addLast("HttpJerseyChannelInitializer", 1639 new HttpJerseyChannelInitializer(jerseyEventExecutorGroup, 1640 baseUri, 1641 applicationHandlerSupplier, 1642 flushThreshold, 1643 byteBufCreator)); 1644 break; 1645 default: 1646 throw new IllegalArgumentException("protocol: " + protocol); 1647 } 1648 } 1649 1650 } 1651 1652}