Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Ribbit Server

cascette-ribbit implements a Ribbit protocol server that serves BPSV-formatted game version and CDN configuration data over HTTP and TCP.

For protocol specification details, see Ribbit Protocol.

Architecture

graph TD
    A[cascette-ribbit binary] --> B[Server]
    B --> C[HTTP Server - axum]
    B --> D[TCP Server - tokio]
    C --> E[AppState]
    D --> E
    E --> F[BuildDatabase]
    E --> G[CdnConfig]

    C --> H[HTTP Handlers]
    H --> I[BpsvResponse]

    D --> J{Protocol Version}
    J -->|v1| K[MIME Wrapper + SHA-256]
    J -->|v2| L[Raw BPSV]
    K --> I
    L --> I

Components

ComponentFilePurpose
ServerConfigconfig.rsCLI arguments, env vars, TLS paths
CdnConfigconfig.rsCDN host/path resolution per region
BuildDatabasedatabase.rsJSON build record storage with product indexing
BuildRecorddatabase.rsSingle build entry with MD5 hash validation
AppStateserver.rsShared state (database, CDN config, timestamps)
Serverserver.rsOrchestrates HTTP + TCP listeners
BpsvResponseresponses/bpsv.rsBPSV response builder (versions, cdns, summary)
HTTP handlershttp/handlers.rsaxum route handlers for /{product}/{endpoint}
TCP handlerstcp/handlers.rsCommand routing for v1/ and v2/ prefixes
V1 wrappertcp/v1.rsRFC 2046 MIME wrapping with SHA-256 checksums
V2 handlertcp/v2.rsRaw BPSV TCP responses

Configuration

CLI Arguments and Environment Variables

FlagEnv VarDefaultDescription
--http-bindCASCETTE_RIBBIT_HTTP_BIND0.0.0.0:8080HTTP listen address
--tcp-bindCASCETTE_RIBBIT_TCP_BIND0.0.0.0:1119TCP listen address
--buildsCASCETTE_RIBBIT_BUILDS./builds.jsonPath to build database JSON
--cdn-hostsCASCETTE_RIBBIT_CDN_HOSTScdn.arctium.toolsCDN host(s)
--cdn-pathCASCETTE_RIBBIT_CDN_PATHtpr/wowCDN base path
--tls-certCASCETTE_RIBBIT_TLS_CERTnoneTLS certificate path (enables HTTPS)
--tls-keyCASCETTE_RIBBIT_TLS_KEYnoneTLS private key path

Build Database Format

The server reads build records from a JSON file. Each record represents a product build:

FieldTypeRequiredDescription
idu64yesUnique build identifier
productstringyesProduct code (e.g., wow, wowt)
versionstringyesVersion string (e.g., 1.14.2.42597)
buildstringyesBuild number
build_configstringyes32-char hex MD5 hash
cdn_configstringyes32-char hex MD5 hash
keyringstringno32-char hex MD5 hash
product_configstringno32-char hex MD5 hash
build_timestringyesISO 8601 timestamp
encoding_ekeystringyes32-char hex encoding key
root_ekeystringyes32-char hex root key
install_ekeystringyes32-char hex install key
download_ekeystringyes32-char hex download key

MD5 hash fields are validated to be exactly 32 lowercase hexadecimal characters.

HTTP Endpoints

The HTTP server uses axum with gzip compression and CORS support.

Routes

RouteHandlerResponse
GET /{product}/versionshandle_versionsBPSV versions table
GET /{product}/cdnshandle_cdnsBPSV CDN configuration
GET /{product}/bgdlhandle_bgdlBPSV background download (same as versions)

All responses use Content-Type: text/plain; charset=utf-8.

Returns HTTP 404 if the product is not found in the database.

TCP Protocol

The TCP server accepts one command per connection. After sending the response, the server closes the connection. A 10-second read timeout applies.

V2 Commands (Raw BPSV)

  • v2/products/{product}/versions
  • v2/products/{product}/cdns
  • v2/products/{product}/bgdl

V1 Commands (MIME-wrapped)

  • v1/products/{product}/versions
  • v1/products/{product}/cdns
  • v1/products/{product}/bgdl
  • v1/summary

V1 responses wrap BPSV data in RFC 2046 MIME multipart format with a SHA-256 checksum epilogue. The server does not include PKCS#7 signatures (unlike Blizzard’s production servers).

BPSV Response Format

Versions Response

7 rows, one per region (us, eu, cn, kr, tw, sg, xx):

Region!STRING:0|BuildConfig!HEX:16|CDNConfig!HEX:16|KeyRing!HEX:16|BuildId!DEC:4|VersionsName!STRING:0|ProductConfig!HEX:16
us|0123456789abcdef...|fedcba9876543210...|<keyring>|42597|1.14.2.42597|<product_config>
eu|...|...|...|...|...|...
...
## seqn = 1730534400

CDNs Response

5 rows, one per CDN region (us, eu, kr, tw, cn):

Name!STRING:0|Path!STRING:0|Hosts!STRING:0|Servers!STRING:0|ConfigPath!STRING:0
us|tpr/wow|cdn.arctium.tools|https://cdn.arctium.tools/?maxhosts=4|tpr/wow/config
...
## seqn = 1730534400

Summary Response (TCP v1 only)

One row per product:

Product!STRING:0|Seqn!DEC:4
wow|1730534400
wowt|1730534400
## seqn = 1730534400

Running

Binary

cargo run --bin cascette-ribbit -- --builds ./builds.json

Library

#![allow(unused)]
fn main() {
use cascette_ribbit::{Server, ServerConfig};

let config = ServerConfig {
    http_bind: "127.0.0.1:8080".parse()?,
    tcp_bind: "127.0.0.1:1119".parse()?,
    builds: "./builds.json".into(),
    cdn_hosts: "cdn.arctium.tools".to_string(),
    cdn_path: "tpr/wow".to_string(),
    tls_cert: None,
    tls_key: None,
};

config.validate()?;
let server = Server::new(config)?;
server.run().await?;
}

Example

cargo run --example simple_server

Then test with:

# HTTP
curl http://localhost:8080/wow/versions
curl http://localhost:8080/wow/cdns

# TCP v2
echo "v2/products/wow/versions" | nc localhost 1119

# TCP v1
echo "v1/products/wow/versions" | nc localhost 1119

Testing

The crate has four test suites:

SuiteFileCoverage
HTTP integrationtests/http_test.rsHTTP endpoints, status codes, BPSV format
TCP v1 integrationtests/tcp_v1_test.rsMIME wrapping, checksums, summary
TCP v2 integrationtests/tcp_v2_test.rsRaw BPSV over TCP, connection lifecycle
Contract teststests/contract_test.rscascette-protocol client against server

Contract tests verify that cascette-protocol’s RibbitTactClient can query the server and parse responses correctly. This ensures wire-level compatibility between client and server implementations.

cargo test -p cascette-ribbit
cargo bench -p cascette-ribbit

TLS Support

Enable TLS with the tls feature flag:

cargo run --bin cascette-ribbit --features tls -- \
  --tls-cert /path/to/cert.pem \
  --tls-key /path/to/key.pem

When TLS is enabled, the HTTP server serves HTTPS. The TCP server is not affected (Ribbit TCP does not use TLS).