ZIO Quartz H2 Logo

ZIO Quartz H2 Architecture

This document outlines the architecture of the Quartz H2 server, a high-performance HTTP/2 implementation built with Scala and Cats Effect. The architecture focuses on efficient resource management, functional stream processing, and robust connection handling for both HTTP/1.1 and HTTP/2 protocols.

System Overview

Quartz H2 is a modern HTTP/2 server implementation with the following key features:

  • Protocol Support: Full HTTP/2 implementation with fallback to HTTP/1.1
  • TLS Support: ALPN-based protocol negotiation for secure connections
  • IO-Uring Integration: Linux io_uring support for high-performance I/O operations
  • Functional Core: Built with Cats Effect for pure functional programming
  • Stream Processing: Efficient data handling with fs2 streams
  • Resource Safety: Proper resource acquisition and release
  • Flow Control: Comprehensive HTTP/2 flow control implementation

System Architecture

┌───────────────────────────────────────────────────────────────────────────┐
│                           QuartzH2Server                                  │
└─────────────────────────────────────┬─────────────────────────────────────┘
                                      │ creates
                                      ▼
┌───────────────────────────────────────────────────────────────────────────┐
│                     Connection Management Layer                           │
│  ┌─────────────────┐      ┌─────────────────┐      ┌─────────────────┐   │
│  │  TLSChannel     │      │  TCPChannel     │      │  IOURingChannel │   │
│  │  (ALPN, SNI)    │      │  (Plain HTTP)   │      │  (Linux only)   │   │
│  └─────────────────┘      └─────────────────┘      └─────────────────┘   │
└───────────────────────────────┬───────────────────────────────────────────┘
                                │
                                ▼
┌───────────────────────────────────────────────────────────────────────────┐
│                     Protocol Handler Layer                                │
│  ┌─────────────────┐                          ┌─────────────────┐         │
│  │  Http2Connection│                          │ Http11Connection│         │
│  │                 │                          │                 │         │
│  └────────┬────────┘                          └────────┬────────┘         │
│           │                                            │                  │
│           ▼                                            ▼                  │
│  ┌─────────────────┐                          ┌─────────────────┐         │
│  │  Http2Stream(s) │                          │ ChunkedTransfer │         │
│  │                 │                          │                 │         │
│  └─────────────────┘                          └─────────────────┘         │
└───────────────────────────────┬───────────────────────────────────────────┘
                                │
                                ▼
┌───────────────────────────────────────────────────────────────────────────┐
│                     Application Layer                                     │
│  ┌─────────────────┐      ┌─────────────────┐      ┌─────────────────┐    │
│  │  HttpRoute      │      │  WebFilter      │      │  HttpRouteIO    │    │
│  │                 │      │                 │      │                 │    │
│  └─────────────────┘      └─────────────────┘      └─────────────────┘    │
└───────────────────────────────────────────────────────────────────────────┘
                    

The architecture is organized into three main layers:

  1. Connection Management Layer: Handles raw socket connections, TLS negotiation, and I/O operations
  2. Protocol Handler Layer: Implements HTTP/1.1 and HTTP/2 protocol logic, including streams and flow control
  3. Application Layer: Processes HTTP requests and generates responses through routes and filters

HTTP/2 Connection Implementation

The Http2Connection class is the core component that manages HTTP/2 connections. It extends Http2ConnectionCommon which provides shared functionality for both client and server HTTP/2 connections.

┌─────────────────────────────────────────────────────────────────────────┐
│                           Http2Connection                               │
│                                                                         │
│  ┌─────────────────┐      ┌─────────────────┐      ┌─────────────────┐  │
│  │  Outbound Queue │      │  Flow Control   │      │ Stream Table    │  │
│  │  (outq)         │◄────►│  Management     │◄────►│ (streamTbl)     │  │
│  └─────────────────┘      └─────────────────┘      └─────────────────┘  │
│           ▲                        ▲                        ▲           │
│           │                        │                        │           │
│           ▼                        ▼                        ▼           │
│  ┌─────────────────┐      ┌─────────────────┐      ┌─────────────────┐  │
│  │ Outbound Worker │      │ Packet Handler  │      │ Http2Stream(s)  │  │
│  │ Process         │◄────►│                 │◄────►│                 │  │
│  └─────────────────┘      └─────────────────┘      └─────────────────┘  │
│                                    ▲                        ▲           │
└────────────────────────────────────┼────────────────────────┼───────────┘
                                      │                        │
                                      ▼                        ▼
┌──────────────────────────────────┐    ┌──────────────────────────┐
│         IOChannel                 │    │      Http Route          │
└──────────────────────────────────┘    └──────────────────────────┘
                    

Key Components

  • Http2Connection: The main class that manages an HTTP/2 connection, handling frame processing, flow control, and stream management
  • Http2Stream: Represents an individual HTTP/2 stream within a connection, with its own flow control windows and data queues
  • Outbound Queue (outq): A bounded queue (capacity 1024) for managing outgoing data packets
  • Stream Table (streamTbl): A concurrent map that tracks all active streams in the connection
  • Flow Control Management: Implements HTTP/2 flow control at both connection and stream levels

Connection Establishment

The QuartzH2Server handles connection establishment through several methods:

  1. Direct HTTP/2 Connection: When a client sends the HTTP/2 preface string, a new Http2Connection is created
  2. HTTP/1.1 Upgrade: When a client requests an upgrade to HTTP/2 via the HTTP/1.1 Upgrade header, the server performs the protocol switch
  3. TLS with ALPN: For secure connections, ALPN negotiation determines whether to use HTTP/2 or HTTP/1.1

Functional Stream Processing

Quartz H2 leverages functional streams (fs2.Stream) as a core abstraction for processing HTTP/2 data. Unlike traditional imperative streams, these streams represent a description of data transformations that are executed only when the stream is run. This functional approach provides several benefits:

  1. Composability: Stream transformations can be composed together without side effects
  2. Resource Safety: Resources are properly acquired and released
  3. Backpressure: Automatic handling of backpressure throughout the pipeline
  4. Error Handling: Structured error handling within the stream processing pipeline

Key Stream Transformations

  • makePacketStream: Creates a Stream that reads from the IOChannel and transforms raw bytes into HTTP/2 packets
  • packetStreamPipe: Transforms a stream of bytes into a stream of HTTP/2 frames
  • dataEvalEffectProducer: Produces data from queues as a Stream transformation

Stream Processing Implementation

The implementation uses several advanced stream processing techniques:

  • Chunked Processing: Data is processed in chunks for efficiency, with careful handling of partial frames
  • Pull-based Consumption: The Pull API is used to implement custom stream processing logic
  • Lazy Evaluation: Stream transformations are applied lazily when the stream is consumed
  • Resource Management: Proper acquisition and release of resources using bracket patterns
  • 1. Outbound Queue (outq)

    • Purpose: Manages outgoing data packets (ByteBuffers) to be sent to the client
    • Type: Queue[IO, ByteBuffer]
    • Capacity: Bounded queue with capacity of 1024
    • Creation: Created during the initialization of an HTTP/2 connection
    • Usage: All outgoing frames are offered to this queue and processed by the outbound worker

    2. Stream Flow Control Queues

    Each HTTP/2 stream has several queues to manage its data flow:

    a. Data Input Queue (inDataQ)

    • Purpose: Accumulates incoming data packets for a specific stream
    • Type: Queue[IO, ByteBuffer]
    • Capacity: Unbounded queue
    • Creation: Created when a new stream is opened
    • Usage: Stores incoming DATA frames for processing by the application

    b. Flow Control Sync Queue (outXFlowSync)

    • Purpose: Synchronizes flow control for outgoing data frames
    • Type: Queue[IO, Boolean]
    • Capacity: Unbounded queue
    • Creation: Created when a new stream is opened
    • Usage: Signals when the stream can send more data based on flow control window updates

    c. Window Update Sync Queue (syncUpdateWindowQ)

    • Purpose: Manages window update synchronization
    • Type: Queue[IO, Unit]
    • Capacity: Dropping queue with capacity of 1
    • Creation: Created when a new stream is opened
    • Usage: Coordinates window updates for flow control

    Concurrency Control

    The implementation uses several mechanisms to ensure thread-safe concurrent operations:

    • Semaphores: Used to control access to shared resources, particularly for operations that need exclusive access
    • Refs: Thread-safe reference cells that manage state updates atomically
    • Deferred: Used for one-shot communication between fibers, particularly for signaling completion or shutdown
    • Fibers: Lightweight concurrency primitives that allow for parallel execution with proper resource management

Data Flow Process

Incoming Data Flow

  1. Data Reception as Stream:
    • The processIncoming method sets up a Stream pipeline starting with leftover data
    • makePacketStream creates a Stream that reads from the IOChannel and transforms raw bytes into HTTP/2 packets
    • This is a description of the transformation, not the actual execution
  2. Stream Transformation:
    • The byte stream is transformed via the packetStreamPipe pipeline
    • This pipeline chunks the bytes into proper HTTP/2 frames
    • The transformation is applied lazily when the stream is consumed
  3. Stream Consumption:
    • The transformed stream is consumed with foreach, which applies packet_handler to each packet
    • Only at this point is the actual I/O performed and frames processed
  4. Packet Handling:
    • Each packet is processed by the packet_handler method
    • Frames are parsed and handled according to their type (HEADERS, DATA, SETTINGS, etc.)
  5. Stream Data Processing:
    • For DATA frames, the data is placed in the appropriate stream's inDataQ
    • Flow control is managed by updating window sizes and sending WINDOW_UPDATE frames when necessary

Outgoing Data Flow

  1. Frame Generation:
    • Outgoing frames are created using methods like headerFrame and dataFrame
    • These frames are offered to the outq queue
  2. Outbound Processing:
    • The outBoundWorkerProc continuously takes frames from the outq queue
    • It writes the frames to the IOChannel for transmission to the client
  3. Flow Control Management:
    • Before sending DATA frames, the system checks both global and stream-specific flow control windows
    • The txWindow_Transmit method handles the logic for splitting frames if necessary based on available window size
    • The outXFlowSync queue is used to signal when more data can be sent after window updates
  4. Response Streaming:
    • When sending response bodies, data is often provided as a Stream
    • This allows for efficient streaming of large responses without loading everything into memory
    • The Stream is consumed and transformed into HTTP/2 DATA frames as needed

HTTP/1.1 Implementation

Quartz H2 includes a robust HTTP/1.1 implementation that serves as a fallback when HTTP/2 is not supported or negotiated. The HTTP/1.1 implementation has been enhanced with comprehensive documentation, better error handling, and improved code structure.

HTTP/1.1 Connection Handler

The HTTP/1.1 connection handler includes the following improvements:

  • Detailed Documentation: Comprehensive class and method documentation following Scaladoc conventions
  • Improved Error Handling: Better error messages with specific details about what went wrong
  • Enhanced Content Length Handling: Fixed content length error handling with better diagnostics
  • Type Annotations: Added proper type annotations for better code clarity
  • Enhanced Logging: Improved logging with more context and better categorization (debug vs error)
  • Header Translation: Clarified HTTP header translation between HTTP/1.1 and HTTP/2 formats
  • Exception Handling: Improved exception handling for malformed requests

Chunked Transfer Encoding

The HTTP/1.1 chunked transfer encoding implementation has been enhanced with:

  • RFC 7230 Compliance: Proper handling of RFC 7230 compliant chunked transfer encoding
  • Improved Validation: Enhanced validation of chunk terminators and headers
  • Bounds Checking: Added proper bounds checking to prevent IndexOutOfBoundsExceptions
  • Structured Code: Better comments explaining the logic and improved code organization
  • Error Propagation: Improved exception handling to propagate errors properly through the stream

HTTP Range Requests

The HttpRangeRequest class has been improved with:

  • ETag Generation: Proper ETag generation based on file metadata (path, size, and modification time)
  • Range Handling: Better range handling with named variables for readability
  • Byte Range Calculations: Fixed byte range calculations for partial content requests
  • Native Scala Approach: Used a native Scala approach for byte-to-hex conversion without external dependencies

Key Components

QuartzH2Server

The main server class that manages HTTP/2 connections, handles SSL context setup, and manages incoming connections. It provides the following key functionality:

  • Connection Management: Creates and manages HTTP/2 and HTTP/1.1 connections
  • TLS Configuration: Sets up SSL context and handles ALPN negotiation
  • Server Socket Binding: Binds to the specified host and port
  • Connection Lifecycle Hooks: Provides callbacks for connection events (connect, disconnect)

Http2Connection

The main class that manages an HTTP/2 connection. It extends Http2ConnectionCommon and implements the core HTTP/2 protocol logic, including:

  • Frame Processing: Handles different types of HTTP/2 frames
  • Stream Management: Creates and manages HTTP/2 streams
  • Flow Control: Implements HTTP/2 flow control mechanisms
  • Settings Management: Handles HTTP/2 settings frames and parameters

Http2Stream

Represents an individual HTTP/2 stream within a connection. Each stream has its own set of queues for managing data flow and handles:

  • Stream-Level Flow Control: Manages stream-specific flow control windows
  • Header Processing: Handles HTTP headers for requests and responses
  • Data Queueing: Manages incoming and outgoing data
  • Stream State: Tracks the state of the stream (idle, open, closed, etc.)

TLSChannel

Handles secure connections using SSL/TLS protocols. Key features include:

  • ALPN Support: Application-Layer Protocol Negotiation for HTTP/2
  • SNI Support: Server Name Indication for virtual hosting
  • Secure Handshake: Manages the SSL/TLS handshake process
  • Encrypted Communication: Handles encryption and decryption of data

Flow Control

HTTP/2 implements flow control at two levels:

  1. Connection-Level: Managed by globalTransmitWindow and globalInboundWindow
  2. Stream-Level: Each stream has its own transmitWindow and inboundWindow

Cats Effect Queues play a crucial role in coordinating these flow control mechanisms, ensuring efficient data transmission while preventing buffer bloat and resource exhaustion.

Client Implementation

Quartz H2 includes a client implementation for making HTTP/2 requests to servers. The QuartzH2Client provides functionality for establishing connections and sending requests.

Connection Establishment

The client supports several methods for establishing connections:

  • TLS with ALPN: Secure connections with protocol negotiation via connectTLS_alpn_h2
  • Direct HTTP/2: Plain HTTP/2 connections without TLS
  • Connection Pooling: Reusing connections for multiple requests to improve performance

Request Handling

The client provides several features for handling requests:

  • Streaming Requests: Support for streaming request bodies
  • Header Management: Proper handling of HTTP/2 headers
  • Response Processing: Processing and streaming of response data
  • Error Handling: Robust error handling for network issues and protocol errors

Conclusion

Quartz H2 is a high-performance HTTP/2 server and client implementation built with Scala and Cats Effect. Its architecture emphasizes:

  • Functional Programming: Pure functional approach using Cats Effect for composable, referentially transparent operations
  • Stream Processing: Efficient data handling with fs2 streams for backpressure and resource management
  • Protocol Compliance: Full HTTP/2 implementation with fallback to enhanced HTTP/1.1
  • Performance: Optimized for high throughput and low latency with features like connection pooling and io_uring support
  • Robustness: Comprehensive error handling and recovery mechanisms

The architecture provides a solid foundation for building high-performance web applications and services with modern HTTP capabilities while maintaining code clarity and maintainability through functional programming principles.