WebSeed
A BEP-19 web seed (url-list, "GetRight" style): a plain HTTP(S) server that hosts the torrent's files so a client can download them with ordinary ranged GETs instead of the BitTorrent wire protocol.
Coroutine port of libtorrent's web_peer_connection (src/web_peer_connection.cpp) and its base web_connection_base (src/web_connection_base.cpp). libtorrent runs a web seed as a full pseudo-peer_connection: it fabricates a have-all bitfield, lets the normal piece picker schedule blocks, then in write_request turns each BitTorrent block request into one or more HTTP GET … Range: bytes=a-b requests, one per file the block overlaps, and re-assembles the response bytes back into the piece. This class keeps that request-mapping + fetch core and drops the peer-connection machinery (choke/interest, the receive-buffer state machine, redirect-following, pad-file zero-filling), which belong to the orchestrator above.
URL construction mirrors web_peer_connection's constructor and write_request:
Single-file torrent: the file is the torrent. libtorrent uses the seed URL as-is, except when the URL ends in
/it appends the (already-encoded) torrent name (web_peer_connection.cpp:108-121). So here, baseUrl ending in/→baseUrl + escapedName, otherwise baseUrl verbatim.Multi-file torrent: the seed URL is a directory. libtorrent ensures a trailing slash (web_peer_connection.cpp:101-107) then appends each file's percent-encoded path (
escape_file_path, web_peer_connection.cpp:497). So here, each URL isbaseUrl(/) + escapePath(relativeFilePath).
Block → range mapping (rangesFor) reproduces file_storage::map_block (src/file_storage.cpp:485): the request's absolute torrent offset is piece * pieceLength + offset, and the run of length bytes is sliced at file boundaries, yielding one HttpRange per file touched. A block that straddles a file boundary therefore produces multiple ranges, fetched and concatenated in order. libtorrent does the same: it issues multiple GETs and joins the payloads.
Threading. fetchBlock/downloadPiece suspend on the injected client only; they hold no mutable state, so a single WebSeed may be shared across coroutines.
Parameters
the ktor HttpClient (engine chosen by the caller: CIO on JVM/Android, Darwin on iOS), injected so it can be mocked.
the web-seed URL from the torrent's url-list.
the parsed torrent whose files this seed serves.
Functions
Download an entire piece by fetching it as a single contiguous block (offset 0, the full TorrentInfo.storage piece size). The final piece is shorter than TorrentInfo.pieceLength; io.github.yuroyami.kitetorrent.torrent.FileStorage.pieceSize gives the exact length. Multi-file pieces still fan out to per-file ranges inside fetchBlock.
Fetch one BitTorrent block (length bytes at (piece, offset)) from this web seed, issuing a ranged HTTP GET per file the block overlaps (rangesFor) and concatenating the bodies in order. Mirrors how web_peer_connection re-assembles incoming_payload fragments into a single block.
Map a BitTorrent block request to the list of HTTP byte ranges that satisfy it. This is the pure, network-free core of fetchBlock. It delegates to WebSeedMapper, the testable port of the URL + Range computation in web_peer_connection::write_request together with file_storage::map_block.