std.http

HTTP requests, streaming responses, and downloads.

Importuse std.http

Types

struct Response#

HTTP response from std.http requests.

use std.http.Response

fn show(response: Response) {
  println(response.status)
  println(response.body)
  println(std.http.get_header(response, "content-type"))
  println(std.http.is_ok(response))
}

fn main() {
  match std.http.try_get("https://example.com/") {
    ok(response) => show(response),
    err(failure) => println(failure.message),
  }
}
status: int

HTTP status code.

body: string

The whole response body, already read.

headers: string

The response header block, one Name: value per line.

struct HttpResponse#

Streaming response returned by std.http.fetch.

status: int

HTTP status code.

headers: string

The response header block, one Name: value per line.

_handle: HttpBody

Transport handle the body reads pull from; not meant to be touched directly.

struct FetchOptions#

Streaming HTTP request options; omitted fields use transport defaults.

method: string

HTTP method; empty means GET.

url: string

Absolute URL to request.

headers: [string]

Request headers, each spelled "Name: value".

body: string

Request body sent verbatim; empty sends none.

timeout_ms: int

Whole-request deadline in milliseconds; 0 takes the transport default.

struct DownloadOptions#

Streaming download options including safe Range resume.

headers: [string]

Request headers, each spelled "Name: value".

resume: bool

Whether to continue an existing partial file with a Range request.

timeout_ms: int

Whole-request deadline in milliseconds; 0 takes the transport default.

struct ByteRange#

One satisfiable Range: bytes= window, inclusive at both ends — which is how HTTP counts, and the off-by-one every hand-rolled range parser makes.

start: int

First byte of the window, counting from zero.

end: int

Last byte of the window, inclusive and clamped to the resource size.

struct HttpBody#

A streaming HTTP client response body.

An opaque handle: only std.http can produce one, and its contents are not reachable from moon source.

_handle: NativeHandle

The native resource.

Functions

extern fn fetch(options: FetchOptions) -> HttpResponse#

Starts a streaming HTTP request; read the returned body incrementally with body_read.

  • options: Method, URL, headers, body, and deadline for the request.
use std.http.FetchOptions

fn main() {
  let response = std.http.try_fetch(
    FetchOptions {
      method: "GET",
      url: "https://example.com/large.bin",
      headers: ["Accept: application/octet-stream"],
      body: "",
      timeout_ms: 10_000,
    },
  ).unwrap()
  println(response.status)
  println(std.http.response_header(response, "content-type"))
  while true {
    let chunk = std.http.try_body_read(response, 64 * 1024).unwrap()
    if chunk == "" { break }
    println(chunk.len())
  }
  std.http.close_response(response)
}
extern fn try_fetch(options: FetchOptions) -> Result<HttpResponse, Error>#

Starts a streaming HTTP request, reporting a connect failure as an error.

  • options: Method, URL, headers, body, and deadline for the request.
extern fn body_read(response: HttpResponse, count: int) -> string#

Reads at most count response bytes; an empty string is EOF.

  • response: Streaming response to read from.
  • count: Upper bound on the bytes returned.
extern fn try_body_read(response: HttpResponse, count: int) -> Result<string, Error>#

Reads at most count response bytes, reporting a broken transfer as an error.

  • response: Streaming response to read from.
  • count: Upper bound on the bytes returned.
fn response_header(response: HttpResponse, name: string) -> string#

Returns one streaming-response header case-insensitively.

  • response: Streaming response to read the header block of.
  • name: Header name, matched case-insensitively.
extern fn close_response(response: HttpResponse)#

Closes a streaming response before or after EOF.

  • response: Streaming response to release.
extern fn download(url: string, path: string, options: DownloadOptions) -> bool#

Streams a URL to a file, resuming with Range when requested.

  • url: Absolute URL to fetch.
  • path: File the body is written to.
  • options: Headers, resume behaviour, and deadline.
use std.http.DownloadOptions

fn main() {
  let saved = std.http.download(
    "https://example.com/archive.tar",
    "archive.tar",
    DownloadOptions { headers: [], resume: true, timeout_ms: 60_000 },
  )
  println(saved)
}
extern fn try_download(url: string, path: string, options: DownloadOptions) -> Result<int, Error>#

Result-returning download twin. A successful response returns its HTTP status; transport, timeout, filesystem, and non-2xx responses are errors. The safe-resume exception is a verified 416 whose complete size already equals the local file; that status is returned as a successful no-op. Request headers and safe Range resume have the same semantics as download.

fn get(url: string) -> Response#

Performs a synchronous HTTP GET request.

  • url: Absolute URL to request.
fn post(url: string, body: string) -> Response#

Performs a synchronous HTTP POST request.

  • url: Absolute URL to request.
  • body: Request body sent verbatim.
fn put(url: string, body: string) -> Response#

Performs a synchronous HTTP PUT request.

  • url: Absolute URL to request.
  • body: Request body sent verbatim.
fn delete(url: string) -> Response#

Performs a synchronous HTTP DELETE request.

  • url: Absolute URL to request.
fn patch(url: string, body: string) -> Response#

Performs a synchronous HTTP PATCH request.

  • url: Absolute URL to request.
  • body: Request body sent verbatim.
extern fn request(method: string, url: string, body: string, headers: string) -> Response#

Performs an HTTP request with explicit method, body, and headers.

  • method: HTTP method, uppercase.
  • url: Absolute URL to request.
  • body: Request body sent verbatim.
  • headers: Serialized header block, one Name: value per line.
fn get_with_headers(url: string, lines: string) -> Response#

Performs a GET request with serialized headers.

  • url: Absolute URL to request.
  • lines: Serialized header block, one Name: value per line.
fn post_with_headers(url: string, body: string, lines: string) -> Response#

Performs a POST request with serialized headers.

  • url: Absolute URL to request.
  • body: Request body sent verbatim.
  • lines: Serialized header block, one Name: value per line.
fn try_get(url: string) -> Result<Response, Error>#

Performs a GET request and returns transport failures as values.

  • url: Absolute URL to request.
fn try_delete(url: string) -> Result<Response, Error>#

Performs a DELETE request and returns transport failures as values.

  • url: Absolute URL to request.
fn try_post(url: string, body: string) -> Result<Response, Error>#

Performs a POST request and returns transport failures as values.

  • url: Absolute URL to request.
  • body: Request body sent verbatim.
fn try_put(url: string, body: string) -> Result<Response, Error>#

Performs a PUT request and returns transport failures as values.

  • url: Absolute URL to request.
  • body: Request body sent verbatim.
fn try_patch(url: string, body: string) -> Result<Response, Error>#

Performs a PATCH request and returns transport failures as values.

  • url: Absolute URL to request.
  • body: Request body sent verbatim.
fn try_get_with_headers(url: string, lines: string) -> Result<Response, Error>#

Performs a header-bearing GET and returns transport failures as values.

  • url: Absolute URL to request.
  • lines: Serialized header block, one Name: value per line.
fn try_post_with_headers(url: string, body: string, lines: string) -> Result<Response, Error>#

Performs a header-bearing POST and returns transport failures as values.

  • url: Absolute URL to request.
  • body: Request body sent verbatim.
  • lines: Serialized header block, one Name: value per line.
extern fn try_request(method: string, url: string, body: string, headers: string) -> Result<Response, Error>#

Performs an HTTP request and returns transport failures as values.

  • method: HTTP method, uppercase.
  • url: Absolute URL to request.
  • body: Request body sent verbatim.
  • headers: Serialized header block, one Name: value per line.
fn url_encode(text: string) -> string#

Percent-encodes text for a URL component.

  • text: Text to percent-encode for one URL component.
println(std.http.url_encode("moon tour"))
println(std.http.query_string(["q", "moon tour", "page", "2"]))
println(std.http.build_url("https://example.com/search", ["q", "moon tour"]))
let block = std.http.headers([
  std.http.header("Accept", "application/json"),
  std.http.header("X-Trace", "abc"),
])
println(block)
fn query_string(pairs: [string]) -> string#

Builds a query string from alternating key/value entries.

  • pairs: Alternating key and value entries.
fn build_url(base: string, pairs: [string]) -> string#

Appends encoded query pairs to a base URL.

  • base: URL the query is appended to.
  • pairs: Alternating key and value entries.
fn parse_byte_range(header: Optional<string>, size: int) -> Optional<ByteRange>#

Parses a Range header against a known resource size.

A single bytes= range only. The suffix (bytes=-500, the last 500 bytes) and open-ended (bytes=100-) forms are what media players actually send; multiple ranges, a different unit, and an unsatisfiable start all answer none, which is the caller's cue to serve the whole resource untouched rather than to fail. A malformed header is not a client error worth a 400 — it is a header worth ignoring.

end is clamped to the last byte, so a player asking for more than exists gets what exists. A start at or past the end answers none, because that is the one case a caller must answer 416 to rather than serve.

  • header: The Range header as sent, or absence when the client sent none.
  • size: Size of the resource in bytes, which bounds the window.
let range = std.http.parse_byte_range(some("bytes=100-199"), 1000).unwrap()
println(range.start) // 100
println(range.end)   // 199
println(std.http.parse_byte_range(some("bytes=-50"), 1000).unwrap().start)
println(std.http.parse_byte_range(none, 1000).is_none())
fn header(name: string, value: string) -> string#

Formats one HTTP header line.

  • name: Header name.
  • value: Header value.
fn headers(lines: [string]) -> string#

Joins HTTP header lines.

  • lines: Header lines to join into one block.
fn get_header(response: Response, name: string) -> string#

Returns a response header value case-insensitively, or an empty string.

  • response: Response to read the header block of.
  • name: Header name, matched case-insensitively.
fn is_ok(response: Response) -> bool#

Reports whether the response status is in the 2xx range.

  • response: Response whose status is tested.