Files
Jellyswarrm/docs/request-response-processing.md
2026-06-07 12:01:06 +02:00

5.5 KiB

Request and Response Processing

Jellyswarrm is a Jellyfin-aware reverse proxy. Clients see Jellyswarrm user IDs, media IDs, server IDs, and API keys. Upstream Jellyfin servers receive their original IDs and credentials.

The code keeps three concerns separate:

  • Request preprocessing chooses the upstream server/session and rewrites the outgoing URL/auth.
  • Request and response JSON processing rewrites IDs inside bodies.
  • URL processing rewrites IDs and credentials in request URLs and embedded media delivery URLs.

Handlers should use the extractors module, ProxyProcessors, and AppState::process_response_json instead of calling low-level processors directly.

Request Flow

flowchart TD
    A[Incoming Axum request] --> B{Route handler type}

    B -->|Routed handler| C[Preprocessed / RequireUser / RequireSession / RequireUserSession]
    B -->|Catch-all proxy_handler| D[Static asset check]
    D -->|Asset found| E[Return asset]
    D -->|No asset| F[preprocess_request]
    C --> F

    F --> G[axum_to_reqwest]
    G --> H[extract_request_infos]
    H --> I[Parse auth headers/query]
    H --> J[Resolve user and device]
    H --> K{JSON request body?}

    K -->|yes| L[RequestAnalyzer]
    L --> M[Find media/user/session hints]
    K -->|no| N[No body hints]
    M --> O[Load user sessions]
    N --> O
    J --> O

    O --> P[resolve_server]
    P --> Q[UrlProcessor.server_from_client_url]
    Q --> R[Pick upstream server/session]
    R --> S[remap_authorization]
    S --> T[apply_to_request]
    T --> U[Remove hop-by-hop headers]
    T --> V[Set Host/Auth headers]
    T --> W[UrlProcessor.client_to_server_url]
    W --> X[Virtual IDs/API key -> upstream IDs/token in path/query]

    X --> Y{Forwarded body is JSON?}
    Y -->|yes| Z[ProxyProcessors.process_request_body]
    Z --> AA[RequestProcessor rewrites JSON virtual IDs -> upstream IDs]
    AA --> AB[set_json_body if modified]
    Y -->|no| AC[Forward request]
    AB --> AC

Response Flow

flowchart TD
    A[Upstream response] --> B{Handler path}

    B -->|Item/media JSON handlers| C[Deserialize as serde_json::Value]
    B -->|Fallback JSON response| D[Deserialize as serde_json::Value]
    B -->|Typed special handlers| E[Deserialize typed model]
    B -->|Non-JSON response| F[Pass through]

    E --> G[Run typed behavior]
    G --> H[Example: playback session tracking]
    G --> I[Serialize typed response to JSON if rewriting is needed]

    C --> J[process_response_json profile: Media]
    D --> K[process_response_json profile: BestEffortMedia]
    I --> J

    J --> L[ResponseProcessor]
    K --> L
    L --> M[Rewrite upstream media IDs -> virtual IDs]
    L --> N[Rewrite ServerId -> proxy server id]
    L --> O[Disable CanDelete/CanDownload]
    L --> P[Optionally suffix names with server name]
    L --> Q[DeliveryUrl/StreamUrl/TranscodingUrl]
    Q --> R[UrlProcessor.server_to_client_delivery_url]
    R --> S[Rewrite embedded path/query IDs and api_key]

    S --> T[Processed JSON]
    M --> T
    N --> T
    O --> T
    P --> T
    T --> U{Typed handler?}
    U -->|yes| V[Deserialize JSON back to typed model]
    U -->|no| W[Serialize JSON body]
    V --> X[Return response]
    W --> Y[Update Content-Length]
    Y --> X
    F --> X

Response Profiles

  • Media: full media response rewriting for explicitly routed media/item/playback/federated handlers.
  • BestEffortMedia: full media-like rewriting for catch-all JSON responses. This keeps less common Jellyfin endpoints working even when they are not explicitly routed.
  • Disabled: no response rewriting.

Media and BestEffortMedia currently rewrite the same fields. The main difference is how they are selected: explicit handlers use Media; the generic fallback uses BestEffortMedia. Name suffixing is still controlled separately by should_change_name and config.

Component Boundaries

  • extractors.rs: Axum extractors that run preprocessing and optionally require a resolved user, session, or both.
  • request_preprocessing.rs: request identity extraction, session lookup, server selection, auth remapping, and outgoing URL/header rewriting.
  • processors/url_processor.rs: all path/query URL rewriting for client-to-server request URLs, server-to-client delivery URLs, and request server detection.
  • processors/request_analyzer.rs: scans incoming JSON bodies for media IDs, user IDs, and session IDs that help pick the upstream server/session.
  • processors/request_processor.rs: rewrites JSON request body IDs from Jellyswarrm virtual IDs to upstream Jellyfin IDs.
  • processors/response_processor.rs: rewrites JSON response fields from upstream Jellyfin IDs to Jellyswarrm virtual IDs and delegates embedded URL rewriting to UrlProcessor.
  • processors/json_processor.rs: generic recursive JSON walker used by analyzers and processors.
  • processors/field_matcher.rs: centralized field-name groups for JSON rewrite rules.
  • ProxyProcessors: facade that constructs and coordinates request, response, analyzer, and URL processors.

Design Rules

  • Prefer serde_json::Value for pass-through media/item responses so unknown Jellyfin schema changes are preserved.
  • Keep typed models where the proxy performs behavior beyond simple transformation, such as playback session tracking and federated item interleaving.
  • Keep URL rewriting centralized in UrlProcessor; request URL rules and embedded delivery URL rules should not drift.
  • Keep handler signatures expressive: use Preprocessed, RequireUser, RequireSession, or RequireUserSession instead of manually calling preprocess_request in routed handlers.