|
| 1 | +# Multiplexing for maintainers |
| 2 | + |
| 3 | +The term "multiplexer" appears in many types across ``NIOHTTP2``. This article |
| 4 | +explains the different ways stream multiplexing is achieved and how the pieces |
| 5 | +fit together. |
| 6 | + |
| 7 | +The intended audience is _library maintainers_ although users may find it |
| 8 | +helpful too. It is not meant to be a comprehensive guide and assumes you have at |
| 9 | +least a high-level understanding of how the library is structured. |
| 10 | + |
| 11 | +There are two high-level approaches to multiplexing in ``NIOHTTP2``: |
| 12 | + |
| 13 | +1. _Legacy_ multiplexing is implemented as a separate `ChannelHandler`. |
| 14 | +2. _Inline_ multiplexing is implemented within the ``NIOHTTP2Handler``. |
| 15 | + |
| 16 | +## Legacy |
| 17 | + |
| 18 | +The _legacy_ multiplexer is a separate `ChannelHandler` which maintains the set |
| 19 | +of open child channels keyed by their stream ID. It is implemented as the |
| 20 | +``HTTP2StreamMultiplexer``. The handler receives frames and various channel |
| 21 | +events from the ``NIOHTTP2Handler`` which are acted upon or propagated to the |
| 22 | +appropriate child channel or forwarded down the connection channel. This |
| 23 | +approach makes heavy use of user-inbound events to pass additional information |
| 24 | +between the ``NIOHTTP2Handler`` and the ``HTTP2StreamMultiplexer``. |
| 25 | + |
| 26 | +The child channels are wrapped up as `MultiplexerAbstractChannel`s: this is a |
| 27 | +wrapper around an `HTTP2StreamChannel` operating in one of two possible modes. |
| 28 | +The modes correspond to the type of data passed between the connection channel |
| 29 | +and the stream channels: |
| 30 | + |
| 31 | +1. ``HTTP2Frame/FramePayload`` |
| 32 | +2. ``HTTP2Frame``. All paths leading to this mode of operation are deprecated, |
| 33 | + see [Issue 214](https://github.com/apple/swift-nio-http2/issues/214) for more |
| 34 | + context. |
| 35 | + |
| 36 | +## Inline |
| 37 | + |
| 38 | +`_Inline_` multiplexing is the newer way of multiplexing streams and is |
| 39 | +implemented inline in the ``NIOHTTP2Handler``. It was created to reduce the cost |
| 40 | +of multiplexing incurred by the legacy multiplexer by removing the out-of-band |
| 41 | +passing of information as user-inbound events. Like the legacy multiplexer, it |
| 42 | +maintains a set of open stream channels and propagates events to them directly. |
| 43 | +This is implemented as the `NIOHTTP2Handler.InlineStreamMultiplexer`. |
| 44 | + |
| 45 | +## How they fit together |
| 46 | + |
| 47 | +Both methods are supported which goes some of the way to explaining why there |
| 48 | +are so many types with the word "multiplexer" in their name. |
| 49 | + |
| 50 | +The ``NIOHTTP2Handler`` makes it possible to use either approach by abstracting |
| 51 | +them away behind the `HTTP2StreamMultiplexer` protocol. The two implementations |
| 52 | +(`LegacyInboundStreamMultiplexer` and `InlineStreamMultiplexer`) are wrapped up |
| 53 | +in an `enum` called `HTTP2InboundStreamMultiplexer` held by the |
| 54 | +``NIOHTTP2Handler``. |
| 55 | + |
| 56 | +The `LegacyInboundStreamMultiplexer` just forwards events down the channel |
| 57 | +pipeline to the ``HTTP2StreamMultiplexer`` `ChannelHandler` which in turn calls |
| 58 | +into the `HTTP2CommonInboundStreamMultiplexer`. |
| 59 | + |
| 60 | +The `NIOHTTP2Handler.InboundStreamMultiplexer` calls the |
| 61 | +`HTTP2CommonInboundStreamMultiplexer` directly. |
| 62 | + |
| 63 | +The ``NIOHTTP2Handler`` propagates events to `HTTP2InboundStreamMultiplexer` but |
| 64 | +_also_ forwards events down the channel pipeline. Because of this, and to avoid |
| 65 | +events being delivered twice, some events on the |
| 66 | +`LegacyInboundStreamMultiplexer` are no-ops. |
| 67 | + |
| 68 | +## The relevant pieces, briefly(-ish) |
| 69 | + |
| 70 | +- **``NIOHTTP2Handler``**: a `public` `ChannelHandler` which decodes bytes to |
| 71 | + ``HTTP2Frame``s (and vice versa). When operating in the 'inline' mode outbound |
| 72 | + streams can be _created_ (via ``NIOHTTP2Handler/StreamMultiplexer``). Inbound |
| 73 | + streams are demultiplexed via the `NIOHTTP2Handler.InboundStreamMultiplexer`. |
| 74 | +- **`HTTP2InboundStreamMultiplexer`**: an `internal` `protocol` which |
| 75 | + demuiltiplexes various inbound events (receiving frames, errors, etc.) into |
| 76 | + streams. |
| 77 | +- **`NIOHTTP2Handler.InboundStreamMultiplexer`**: an `internal` `enum` with two |
| 78 | + cases conforming to `HTTP2InboundStreamMultiplexer`. The `NIOHTTP2Handler` |
| 79 | + holds an instance of this internally. |
| 80 | +- **``NIOHTTP2Handler/StreamMultiplexer``**: a `public` `struct` which wraps |
| 81 | + `HTTP2InboundStreamMultiplexer` to provide API for creating outbound streams. |
| 82 | +- **``HTTP2StreamMultiplexer``**: a `public` `ChannelHandler` used for _legacy_ |
| 83 | + multiplexing. which also allows you to _create_ outbound streams. Most of its |
| 84 | + internals call through to the `HTTP2CommonInboundStreamMultiplexer`. |
| 85 | +- **`LegacyInboundStreamMultiplexer`**: an `internal` `struct` which conforms to |
| 86 | + `HTTP2InboundStreamMultiplexer` and forwards various events down the channel |
| 87 | + pipeline (to the `HTTP2StreamMultiplexer` handler). One of the two cases of |
| 88 | + the `NIOHTTP2Handler.InboundStreamMultiplexer`. |
| 89 | +- **`HTTP2CommonInboundStreamMultiplexer`**: an `internal` `struct` which |
| 90 | + actually holds the set of open streams keyed by their ID and is responsible |
| 91 | + for propagating events to them. |
| 92 | +- **`InlineStreamMultiplexer`**: an `internal` `struct` which conforms to |
| 93 | + `HTTP2InboundStreamMultiplexer` and forwards events directly to the |
| 94 | + `HTTP2CommonInboundStreamMultiplexer`. The second case of the |
| 95 | + `NIOHTTP2Handler.InboundStreamMultiplexer`. |
| 96 | +- **`MultiplexerAbstractChannel`**: an `internal` `enum` with two cases which |
| 97 | + wraps an `HTTP2StreamChannel`. The two cases correspond to the type of data |
| 98 | + passed into the stream (``HTTP2Frame`` vs. ``HTTP2Frame/FramePayload``). |
0 commit comments