CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-waitress

A production-quality pure-Python WSGI server with robust HTTP protocol support and comprehensive configuration options

Pending
Overview
Eval results
Files

http-processing.mddocs/

HTTP Processing

Low-level HTTP request parsing, connection management, and protocol handling for custom server implementations and advanced use cases.

Capabilities

HTTP Channel Management

Handles individual HTTP client connections with full request/response lifecycle management.

class HTTPChannel(wasyncore.dispatcher):
    """
    Manages individual HTTP client connections with full request/response lifecycle.
    
    Handles request parsing, WSGI application execution, response transmission,
    connection keep-alive, and proper resource cleanup for a single client.
    """
    
    # Class attributes
    task_class = WSGITask             # Task class for WSGI execution
    error_task_class = ErrorTask      # Task class for error responses
    parser_class = HTTPRequestParser  # Parser class for requests
    
    def __init__(self, server, sock, addr, adj, map=None):
        """
        Initialize HTTP channel for client connection.
        
        Parameters:
        - server: Parent server instance
        - sock: Client socket object
        - addr: Client address tuple (host, port)
        - adj: Adjustments configuration object
        - map: asyncore socket map (optional)
        """
    
    def check_client_disconnected(self):
        """
        Check if client has disconnected.
        
        Returns:
        bool: True if client is disconnected
        
        Notes:
        - Inserted into WSGI environ for applications to check
        - Allows long-running operations to detect disconnection
        """
    
    def received(self, data):
        """
        Process received data from client.
        
        Parameters:
        - data (bytes): Raw HTTP data from client
        
        Notes:
        - Handles incremental request parsing
        - Manages request buffering and validation
        - Triggers request processing when complete
        """
    
    def handle_request(self, req):
        """
        Handle complete HTTP request.
        
        Parameters:
        - req: Parsed request object with WSGI environ
        
        Notes:
        - Creates appropriate task (WSGI or Error)
        - Manages connection keep-alive
        - Handles 100 Continue responses
        """
    
    def build_response_header(self, status, headers):
        """
        Build HTTP response header from WSGI components.
        
        Parameters:
        - status (str): HTTP status line (e.g., "200 OK")
        - headers (list): List of (name, value) header tuples
        
        Returns:
        bytes: Complete HTTP response header
        """
    
    def write_soon(self, data):
        """
        Queue data for asynchronous transmission to client.
        
        Parameters:
        - data (bytes): Response data to send
        
        Notes:
        - Thread-safe buffering system
        - Automatic flow control and backpressure
        - Handles large response streaming
        """
    
    def writable(self):
        """
        Check if channel has data ready to send.
        
        Returns:
        bool: True if data waiting to be sent
        """
    
    def handle_write(self):
        """Send buffered data to client socket."""
    
    def handle_read(self):
        """Read and process data from client socket."""
    
    def handle_close(self):
        """Clean up resources when connection closes."""

class ClientDisconnected(Exception):
    """
    Raised when client disconnects unexpectedly during request processing.
    
    This exception is raised when:
    - Client closes connection during request processing
    - Socket errors indicate disconnection
    - Write operations fail due to broken connection
    """

HTTP Request Parsing

Comprehensive HTTP request parser with support for HTTP/1.0 and HTTP/1.1 protocols.

class HTTPRequestParser:
    """
    Parses HTTP requests into WSGI environ dictionaries.
    
    Supports HTTP/1.0 and HTTP/1.1 with proper handling of:
    - Request line parsing
    - Header field parsing and validation
    - Content-Length and Transfer-Encoding
    - Connection management headers
    """
    
    def __init__(self, adj):
        """
        Initialize request parser.
        
        Parameters:
        - adj: Adjustments configuration for limits and behavior
        """
    
    def received(self, data, pos=0):
        """
        Process received request data.
        
        Parameters:
        - data (bytes): Raw HTTP request data
        - pos (int): Starting position in data
        
        Returns:
        int: Number of bytes consumed
        """
    
    def parse_headers(self, header_plus):
        """Parse HTTP headers into environ dict."""
    
    def get_body_stream(self):
        """Get request body as file-like object."""

class ParsingError(Exception):
    """
    Raised when HTTP request parsing fails.
    
    Indicates malformed requests, protocol violations,
    or requests exceeding configured limits.
    """

class TransferEncodingNotImplemented(Exception):
    """
    Raised for unsupported Transfer-Encoding values.
    
    Currently only 'chunked' and 'identity' are supported.
    """

HTTP Parsing Utilities

Low-level functions for parsing HTTP protocol elements.

def unquote_bytes_to_wsgi(bytestring):
    """
    URL decode bytes to WSGI-compatible string.
    
    Parameters:
    - bytestring (bytes): URL-encoded bytes
    
    Returns:
    str: Decoded string safe for WSGI environ
    """

def split_uri(uri):
    """
    Parse URI into components.
    
    Parameters:
    - uri (str): Complete URI string
    
    Returns:
    tuple: (scheme, netloc, path, query, fragment)
    """

def get_header_lines(header):
    """
    Split HTTP header block into individual header lines.
    
    Parameters:
    - header (str): Complete header block
    
    Returns:
    list: Individual header lines
    """

def crack_first_line(line):
    """
    Parse HTTP request line.
    
    Parameters:
    - line (str): HTTP request line (e.g., "GET /path HTTP/1.1")
    
    Returns:
    tuple: (method, uri, version)
    
    Raises:
    ValueError: For malformed request lines
    """

Request Processing Examples

Common patterns for working with HTTP processing components.

Custom Channel Implementation

from waitress.channel import HTTPChannel
from waitress.adjustments import Adjustments

class CustomHTTPChannel(HTTPChannel):
    """Custom HTTP channel with additional logging."""
    
    def received(self, data):
        # Log incoming data
        print(f"Received {len(data)} bytes from {self.addr}")
        return super().received(data)
    
    def handle_request(self, req):
        # Custom request processing
        print(f"Processing {req['REQUEST_METHOD']} {req['PATH_INFO']}")
        return super().handle_request(req)

# Use custom channel in server
adj = Adjustments()
# Server configuration would use CustomHTTPChannel

Manual Request Parsing

from waitress.parser import HTTPRequestParser
from waitress.adjustments import Adjustments

adj = Adjustments(max_request_header_size=65536)
parser = HTTPRequestParser(adj)

# Simulate receiving HTTP request data
request_data = b"""GET /hello HTTP/1.1\r
Host: example.com\r
User-Agent: Test/1.0\r
\r
"""

try:
    bytes_consumed = parser.received(request_data)
    if parser.completed:
        environ = parser.environ
        print(f"Method: {environ['REQUEST_METHOD']}")
        print(f"Path: {environ['PATH_INFO']}")
        print(f"Headers parsed successfully")
except ParsingError as e:
    print(f"Parsing failed: {e}")

URI and Header Processing

from waitress.parser import split_uri, crack_first_line, get_header_lines

# Parse request line
method, uri, version = crack_first_line("GET /api/users?page=1 HTTP/1.1")
print(f"Method: {method}, URI: {uri}, Version: {version}")

# Parse URI components
scheme, netloc, path, query, fragment = split_uri(uri)
print(f"Path: {path}, Query: {query}")

# Process headers
header_block = """Content-Type: application/json\r
Content-Length: 123\r
Authorization: Bearer token123"""

header_lines = get_header_lines(header_block)
for line in header_lines:
    if ':' in line:
        name, value = line.split(':', 1)
        print(f"Header: {name.strip()} = {value.strip()}")

Protocol Support

Waitress HTTP processing supports comprehensive HTTP protocol features.

# Supported HTTP versions
HTTP_VERSIONS = ["HTTP/1.0", "HTTP/1.1"]

# Supported request methods  
HTTP_METHODS = ["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "PATCH", "TRACE"]

# Connection handling
KEEPALIVE_SUPPORT = True  # HTTP/1.1 persistent connections
PIPELINING_SUPPORT = False  # HTTP pipelining not supported

# Transfer encodings
SUPPORTED_ENCODINGS = ["identity", "chunked"]

# Content encodings (handled by application)
CONTENT_ENCODING_PASSTHROUGH = True

Error Conditions

HTTP processing can raise various exceptions for different error conditions.

# Common parsing errors:
# - Request line malformed: ValueError from crack_first_line()
# - Headers too large: ParsingError with size limit exceeded
# - Invalid transfer encoding: TransferEncodingNotImplemented
# - Connection errors: ClientDisconnected during processing
# - Protocol violations: ParsingError with description

# Example error handling
try:
    parser.received(request_data)
except ParsingError as e:
    # Send 400 Bad Request
    response = b"HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n"
except TransferEncodingNotImplemented as e:
    # Send 501 Not Implemented
    response = b"HTTP/1.1 501 Not Implemented\r\nConnection: close\r\n\r\n"
except ClientDisconnected:
    # Clean up connection
    pass

Integration with WSGI

HTTP processing creates proper WSGI environ dictionaries.

# Required WSGI environ keys populated:
REQUEST_METHOD = "GET"          # HTTP method
SCRIPT_NAME = ""                # Application script name
PATH_INFO = "/path"             # Request path
QUERY_STRING = "param=value"    # Query parameters
CONTENT_TYPE = ""               # Content-Type header
CONTENT_LENGTH = ""             # Content-Length header
SERVER_NAME = "localhost"       # Server hostname
SERVER_PORT = "8080"            # Server port
SERVER_PROTOCOL = "HTTP/1.1"    # HTTP version
wsgi.version = (1, 0)           # WSGI version
wsgi.url_scheme = "http"        # URL scheme
wsgi.input = file_object        # Request body stream
wsgi.errors = sys.stderr        # Error stream
wsgi.multithread = True         # Threading model
wsgi.multiprocess = False       # Process model
wsgi.run_once = False           # Execution model

# HTTP headers converted to HTTP_* keys:
HTTP_HOST = "example.com"       # Host header
HTTP_USER_AGENT = "Browser"     # User-Agent header
HTTP_ACCEPT = "text/html"       # Accept header
# etc.

Install with Tessl CLI

npx tessl i tessl/pypi-waitress

docs

buffer-management.md

command-line.md

configuration.md

error-handling.md

http-processing.md

index.md

proxy-headers.md

server-management.md

task-management.md

tile.json