Zephはクロスプラットフォームな高性能HTTPサーバーで、Java NIOをI/Oバックエンドとして使用します。 HTTP/1.1とHTTP/2の両方に対応し、TLS/SSLもサポートしています。
Note: io_uringバックエンドは
io_uringブランチで利用可能です。
| Protocol | NIO |
|---|---|
| HTTP/1.1 | OK |
| HTTP/1.1 + TLS | OK |
| HTTP/2 (h2c) | OK |
| HTTP/2 (h2 over TLS) | OK |
| Protocol | Class |
|---|---|
| HTTP/1.1 | HttpServerNio |
| HTTP/1.1 + TLS | HttpsServerNio |
| HTTP/2 (h2c) | HttpServerNio |
| HTTP/2 (h2 over TLS) | HttpsServerNio |
+------------------------------------------------------------------------------+
| Clojure Application |
| |
| (run-server handler {:port 8080 :ssl? true}) |
+------------------------------------------------------------------------------+
|
v
+------------------------------------------------------------------------------+
| server.clj |
| +-------------------------------------------------------------------------+ |
| | run-server: SSL設定、サーバー起動 | |
| +-------------------------------------------------------------------------+ |
+------------------------------------------------------------------------------+
|
v
+------------------------------------------------------------------------------+
| NIO Backend |
| (Windows/macOS/Linux) |
+------------------------------------------------------------------------------+
| +---------------+ +-------------------+ |
| |HttpServerNio | | HttpsServerNio | |
| +---------------+ +-------------------+ |
+------------------------------------------------------------------------------+
Zephは3層のレイヤーアーキテクチャを採用しています:
+------------------------------------------------------------------------------+
| |
| +========================================================================+ |
| || Protocol Layer (プロトコル層) || |
| || || |
| || HTTP/1.1解析、HTTP/2フレーム処理、ストリーミング、チャンク転送 || |
| || || |
| || +-------------------------+ +-------------------------------+ || |
| || | Http1Handler | | Http2ServerHandler | || |
| || | +------------------+ | | +-------------------------+ | || |
| || | | HttpParser | | | | Http2Connection | | || |
| || | +------------------+ | | +-------------------------+ | || |
| || | - Request parsing | | | HpackEncoder/Decoder | | || |
| || | - Response building | | +-------------------------+ | || |
| || | - Keep-alive mgmt | | | Stream management | | || |
| || | - Chunked encoding | | | Flow control | | || |
| || +-------------------------+ +-------------------------------+ || |
| || || |
| +|======================================================================|+ |
| || Transport Layer (トランスポート層) || |
| || || |
| || TLS暗号化/復号化、ALPN交渉、SSL ハンドシェイク || |
| || || |
| || +------------------------------------------------------------------+|| |
| || | SslHandler ||| |
| || | +-------------+ +-------------+ +---------------------+ ||| |
| || | | SSLEngine | | Handshake | | ALPN Negotiation | ||| |
| || | +-------------+ +-------------+ +---------------------+ ||| |
| || +------------------------------------------------------------------+|| |
| || || |
| +|======================================================================|+ |
| || I/O Backend Layer (I/Oバックエンド層) || |
| || || |
| || 接続管理、非同期I/O、イベントループ、マルチワーカー || |
| || || |
| || +------------------------------------------------------------------+|| |
| || | NIO Backend ||| |
| || | +----------------------------+ ||| |
| || | | Selector | ||| |
| || | | SelectionKey | ||| |
| || | +----------------------------+ ||| |
| || | - Multi-selector workers ||| |
| || | - SocketChannel ||| |
| || | - Platform portable ||| |
| || +------------------------------------------------------------------+|| |
| || || |
| +========================================================================+ |
| |
+------------------------------------------------------------------------------+
+-----------------------------+
| <<interface>> |
| ProtocolHandler |
+-----------------------------+
| + processData(byte[]): byte[]|
| + hasPendingStreaming(): bool|
| + continueStreaming(): byte[]|
| + isKeepAlive(): boolean |
| + isOpen(): boolean |
| + close(): void |
+-----------------------------+
^
|
+----------------------+----------------------+
| |
+-----------+-----------+ +-------------+-------------+
| Http1Handler | | Http2ServerHandler |
+-----------------------+ +---------------------------+
| - parser: HttpParser | | - conn: Http2Connection |
| - handler: Function | | - handler: Function |
| - serverPort: int | | - serverPort: int |
| - keepAlive: boolean | | - streams: Map |
+-----------------------+ +---------------------------+
| + parse(): ParseResult| | + processData(): byte[] |
| + getRequest(): Req | | + handleFrame(): void |
| + handleRequest(): Res| | + sendResponse(): void |
| + reset(): void | | + handleGoAway(): void |
+-----------------------+ +---------------------------+
+-----------------------------+
| <<interface>> |
| HttpServer |
+-----------------------------+
| + run(): void |
| + stop(): void |
| + isRunning(): boolean |
| + getPort(): int |
| + close(): void |
+-----------------------------+
^
|
+--------------------------------+--------------------------------+
| |
+---------+---------+ +---------+---------+
| HttpServerNio | | HttpsServerNio |
+-------------------+ +-------------------+
| - workers[] | | - sslConfig |
| - selector | | - sslHandler |
| - connections | +-------------------+
+-------------------+ | Inner classes: |
| Inner classes: | | - NioConnection |
| - NioWorker | | (Http1Handler |
| - NioConnection | | + SslHandler) |
| (Http1Handler) | +-------------------+
+-------------------+
+-----------------------------+
| Client |
+-------------+---------------+
|
| TCP Connection
v
+------------------------------------------------------------------------------+
| HttpServerNio |
| |
| +------------------------------------------------------------------------+ |
| | NioWorker | |
| | | |
| | +------------+ +--------------------------------------------+ | |
| | | Selector |---->| Selection Events | | |
| | | | | (ACCEPT, READ, WRITE) | | |
| | +------------+ +--------------------------------------------+ | |
| | | | | |
| | | select | process events | |
| | v v | |
| | +------------------------------------------------------------------+ | |
| | | handleRead() | | |
| | | | | | |
| | | +---------------------+---------------------+ | | |
| | | | ProtocolDetector | | | |
| | | | isHttp2Preface() ? -> HTTP/2 path | | | |
| | | +---------------------+---------------------+ | | |
| | | | | | |
| | | v (HTTP/1.1 path) | | |
| | | +-------------------------------------------+ | | |
| | | | NioConnection | | | |
| | | | +-------------------------------------+ | | | |
| | | | | Http1Handler | | | | |
| | | | | | | | | |
| | | | | parse() --> ParseResult | | | | |
| | | | | | | | | | |
| | | | | +-- NEED_MORE_DATA | | | | |
| | | | | +-- HEADERS_COMPLETE | | | | |
| | | | | +-- REQUEST_COMPLETE ---------|--|--> handler() | | |
| | | | | +-- ERROR | | | | | |
| | | | | | | | | | |
| | | | | handleRequest() <-----------------|--|-----+ | | |
| | | | | | | | | | |
| | | | | v | | | | |
| | | | | HttpResponse | | | | |
| | | | +-------------------------------------+ | | | |
| | | +-------------------------------------------+ | | |
| | +------------------------------------------------------------------+ | |
| | | | |
| | v | |
| | +------------------------------------------------------------------+ | |
| | | write() | | |
| | | response.encode() -> SocketChannel.write() | | |
| | +------------------------------------------------------------------+ | |
| +------------------------------------------------------------------------+ |
+------------------------------------------------------------------------------+
+-----------------------------+
| Client |
| (ALPN: h2) |
+-------------+---------------+
|
| TLS Connection
v
+------------------------------------------------------------------------------+
| HttpsServerNio |
| |
| +----------------------------------------------------------------------+ |
| | NioConnection | |
| | | |
| | +------------------------------------------------------------------+ |
| | | SslHandler | |
| | | | |
| | | 1. TLS Handshake | |
| | | +-- processHandshake() --> ClientHello | |
| | | <-- ServerHello + Certificate | |
| | | --> ClientKeyExchange | |
| | | <-- Finished | |
| | | | |
| | | 2. ALPN Negotiation | |
| | | +-- getApplicationProtocol() --> "h2" | |
| | | | |
| | | 3. Decrypt Application Data | |
| | | +-- decrypt(encrypted) --> plaintext | |
| | | | |
| | +------------------------------------------------------------------+ |
| | | | |
| | | isHttp2 = true (ALPN) | |
| | v | |
| | +------------------------------------------------------------------+ |
| | | Http2ServerHandler | |
| | | | |
| | | +----------------------------------------------------------+ | |
| | | | Http2Connection | | |
| | | | | | |
| | | | Connection Preface (server): | | |
| | | | SETTINGS frame | | |
| | | | | | |
| | | | Frame Processing: | | |
| | | | HEADERS (stream 1) --> HPACK decode --> HttpRequest | | |
| | | | | | | |
| | | | v | | |
| | | | handler.apply() | | |
| | | | | | | |
| | | | v | | |
| | | | HEADERS (stream 1) <-- HPACK encode <-- HttpResponse | | |
| | | | DATA (stream 1) | | |
| | | | | | |
| | | | Multiplexing: | | |
| | | | Stream 1 --> request/response | | |
| | | | Stream 3 --> request/response (concurrent) | | |
| | | | Stream 5 --> request/response (concurrent) | | |
| | | | | | |
| | | +----------------------------------------------------------+ | |
| | +------------------------------------------------------------------+ |
| +----------------------------------------------------------------------+ |
| | |
| | encrypt() |
| v |
| Write to socket |
+------------------------------------------------------------------------------+
+-------------------------------------------------------------+
| |
v |
+--------------+ |
| ACCEPT | |
| (new conn) | |
+------+-------+ |
| |
v |
+--------------+ +--------------+ +--------------+ |
| READ |---->| PARSE |---->| HANDLER | |
| (request) | | (Http1Handler)| | (user func) | |
+--------------+ +--------------+ +------+-------+ |
| |
v |
+--------------+ |
| WRITE | |
| (response) | |
+------+-------+ |
| |
+-------------------+-------------------+ |
| | |
v | |
+------------+ +------------+ | |
| keep-alive | | close | | |
| = true | | connection | | |
+-----+------+ +------------+ | |
| | |
+----------------------------------------+ |
|
(next request) ---------------------+
TLS Handshake時にALPNでプロトコルを交渉:
Client: ALPN extension [h2, http/1.1]
Server: ALPN extension [h2] <- h2を選択
-> SSLEngine.getApplicationProtocol() = "h2"
-> Http2ServerHandler を使用
HTTP/1.1 Request
+---------------------------------------------------------------------+
| GET / HTTP/1.1 |
| Host: example.com |
| Connection: Upgrade, HTTP2-Settings |
| Upgrade: h2c |
| HTTP2-Settings: AAMAAABkAAQAoAAAAAIAAAAA |
+---------------------------------------------------------------------+
|
v
+---------------------+
| Http1Handler.parse()|
| |
| isH2cUpgradeRequest?|
+----------+----------+
| yes
v
+---------------------+
| H2cUpgradeHelper |
| |
| 101 Switching Proto |
| + Server SETTINGS |
+----------+----------+
|
v
+---------------------+
| ProtocolDetector |
| |
| 以降のデータは |
| HTTP/2 preface |
| で始まる |
+----------+----------+
|
v
+---------------------+
| Http2ServerHandler |
| |
| HTTP/2 frames |
+---------------------+
;; Built-in localhost certificate (development)
{:ssl? true}
;; PEM files
{:ssl? true :cert "cert.pem" :key "key.pem"}
;; PKCS12 keystore
{:ssl? true :keystore "keystore.p12" :keystore-password "secret"}
src/java/zeph/
├── http/
│ ├── HttpServer.java # Interface
│ ├── HttpServerNio.java # NIO HTTP server
│ ├── HttpsServerNio.java # NIO HTTPS server
│ ├── Http1Handler.java # HTTP/1.1 protocol handler
│ ├── HttpParser.java # HTTP/1.1 parser
│ ├── HttpRequest.java # Request model
│ ├── HttpResponse.java # Response model
│ ├── ProtocolDetector.java # HTTP/2 preface detection
│ └── H2cUpgradeHelper.java # h2c upgrade helper
├── http2/
│ ├── Http2ServerHandler.java # HTTP/2 protocol handler
│ ├── Http2Connection.java # HTTP/2 connection state
│ ├── Http2FrameReader.java # Frame parsing
│ ├── Http2FrameType.java # Frame type constants
│ └── hpack/
│ ├── HpackEncoder.java # Header compression
│ └── HpackDecoder.java # Header decompression
├── ssl/
│ ├── SslConfig.java # SSL configuration
│ └── SslHandler.java # TLS handshake/encrypt/decrypt
└── client/
├── HttpClientNio.java # NIO HTTP client
├── HttpClientRequest.java # Client request
└── HttpClientResponse.java # Client response
src/clojure/zeph/
├── server.clj # Server API
├── client.clj # Client API
└── ring.clj # Ring adapter
Can you improve this documentation?Edit on GitLab
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |