F3.IO.HTTP (F3 v0.1.0)

Copy Markdown

HTTP byte source.

open/2 sends one HEAD and stores Content-Length. pread/3 sends one GET with Range: bytes=offset-end and returns at most the requested length. Redirects are refused. lib_urls in a footer are not requests.

Unsigned options are headers: and timeout_ms:. sign: is a function (method, url, headers) -> {:ok, headers} | {:error, F3.Error.t()} that the caller uses to attach its own signature. When endpoint:, bucket:, key:, region:, access_key:, and secret_key: are all set, this module signs path-style HEAD and GET with SigV4. The object URL is endpoint/bucket/key. The secret is not stored on the error or printed by Inspect.

Summary

Types

t()

One HTTP source.

Functions

Marks the handle closed and drops headers and the signer.

Opens url with one HEAD request.

One ranged GET. A closed handle is :closed. A negative offset or length is :invalid_argument. A start at or past size is {:ok, ""} and does not send a request.

Size from the HEAD response. A closed handle is :closed.

Types

t()

@type t() :: %F3.IO.HTTP{
  closed: boolean(),
  display_url: String.t(),
  headers: [{String.t(), String.t()}],
  signer:
    (atom(), String.t(), [{String.t(), String.t()}] ->
       {:ok, [{String.t(), String.t()}]} | {:error, F3.Error.t()})
    | nil,
  size: non_neg_integer(),
  timeout: pos_integer(),
  url: String.t()
}

One HTTP source.

url is the request URL. display_url is that URL with userinfo removed. size is the Content-Length from HEAD. headers are the caller headers. timeout is the request timeout in milliseconds. signer is the optional arity-3 function, or nil. closed drops the signer and headers.

Functions

close(state)

Marks the handle closed and drops headers and the signer.

Examples

iex> state = %F3.IO.HTTP{
...>   url: "http://example.test/a",
...>   display_url: "http://example.test/a",
...>   size: 4,
...>   headers: [{"authorization", "redacted"}],
...>   timeout: 10_000,
...>   signer: nil
...> }
iex> {:ok, closed} = F3.IO.HTTP.close(state)
iex> {closed.closed, closed.headers, closed.signer}
{true, [], nil}

open(url, opts \\ [])

@spec open(String.t(), keyword()) :: {:ok, t()} | {:error, F3.Error.t()}

Opens url with one HEAD request.

See the module docs for opts. When the six signing keys are set, url is not requested. The path-style object URL is.

A non-http URL, a partial key set, a bad sign:, and timeout_ms that is not a positive integer are :invalid_argument and do not raise. Combining sign: with the six keys is the same error.

Examples

iex> {:error, error} = F3.IO.HTTP.open("ftp://example.test/a")
iex> error.category
:invalid_argument

iex> {:error, error} = F3.IO.HTTP.open("http://example.test/a", timeout_ms: 0)
iex> error.message
"timeout_ms must be a positive integer"

iex> {:error, error} = F3.IO.HTTP.open("http://example.test/a", bucket: "b")
iex> error.message
"signed request needs endpoint, bucket, key, region, access_key, and secret_key"

pread(state, offset, length)

One ranged GET. A closed handle is :closed. A negative offset or length is :invalid_argument. A start at or past size is {:ok, ""} and does not send a request.

Examples

iex> state = %F3.IO.HTTP{
...>   url: "http://example.test/a",
...>   display_url: "http://example.test/a",
...>   size: 4,
...>   headers: [],
...>   timeout: 10_000,
...>   signer: nil,
...>   closed: true
...> }
iex> {:error, error} = F3.IO.HTTP.pread(state, 0, 1)
iex> error.category
:closed

size(http)

Size from the HEAD response. A closed handle is :closed.

Examples

iex> state = %F3.IO.HTTP{
...>   url: "http://example.test/a",
...>   display_url: "http://example.test/a",
...>   size: 4,
...>   headers: [],
...>   timeout: 10_000,
...>   signer: nil
...> }
iex> F3.IO.HTTP.size(state)
{:ok, 4}