componentized/directory

componentized:http

interface dev

This development build was superseded by the release of 0.1.0.

A collection of utility components that remix wasi:http types and interfaces.

interface latch componentized:http/latch@0.1.0-dev since 0.1.0-dev

Access control for wasi:http.

A gate consults a latch before each request it sends or handles. The latch either defers, raising no objection, or denies the request. A latch never grants a request, a request proceeds when the latch defers. Several latches can be aggregated into one, the request is denied when any of them denies it.

Deciding and acting on a decision are separate steps. authorize decides without side effects, then the gate reports the final decision to observe-decision, where a latch updates any state it keeps. A latch aggregated with others may not be asked to authorize a request another latch already denied, but it always observes the final decision.

Types

use variant http-error-code

from wasi:http/types@0.3.0

  • DNS-timeout
  • DNS-error: DNS-error-payload
  • destination-not-found
  • destination-unavailable
  • destination-IP-prohibited
  • destination-IP-unroutable
  • connection-refused
  • connection-terminated
  • connection-timeout
  • connection-read-timeout
  • connection-write-timeout
  • connection-limit-reached
  • TLS-protocol-error
  • TLS-certificate-error
  • TLS-alert-received: TLS-alert-received-payload
  • HTTP-request-denied
  • HTTP-request-length-required
  • HTTP-request-body-size: option<u64>
  • HTTP-request-method-invalid
  • HTTP-request-URI-invalid
  • HTTP-request-URI-too-long
  • HTTP-request-header-section-size: option<u32>
  • HTTP-request-header-size: option<field-size-payload>
  • HTTP-request-trailer-section-size: option<u32>
  • HTTP-request-trailer-size: field-size-payload
  • HTTP-response-incomplete
  • HTTP-response-header-section-size: option<u32>
  • HTTP-response-header-size: field-size-payload
  • HTTP-response-body-size: option<u64>
  • HTTP-response-trailer-section-size: option<u32>
  • HTTP-response-trailer-size: field-size-payload
  • HTTP-response-transfer-coding: option<string>
  • HTTP-response-content-coding: option<string>
  • HTTP-response-timeout
  • HTTP-upgrade-failed
  • HTTP-protocol-error
  • loop-detected
  • configuration-error
  • internal-error: option<string>

    This is a catch-all error for anything that doesn't fit cleanly into a more specific case. It also includes an optional string for an unstructured description of the error. Users should not depend on the string for diagnosing errors, as it's not required to be consistent between implementations.

use resource request

from wasi:http/types@0.3.0

Represents an HTTP Request.

  • static functionnew: static func( headers: headers, contents: option<stream<u8>>, trailers: future<result<option<trailers>, error-code>>, options: option<request-options>, ) -> tuple<request, future<result<_, error-code>>>

    Construct a new request with a default method of GET, and none values for path-with-query, scheme, and authority.

    headers is the HTTP Headers for the Request.

    contents is the optional body content stream with none representing a zero-length content stream. Once it is closed, trailers future must resolve to a result. If trailers resolves to an error, underlying connection will be closed immediately.

    options is optional request-options resource to be used if the request is sent over a network connection.

    It is possible to construct, or manipulate with the accessor functions below, a request with an invalid combination of scheme and authority, or headers which are not permitted to be sent. It is the obligation of the handler.handle implementation to reject invalid constructions of request.

    The returned future resolves to result of transmission of this request.

  • functionget-method: func() -> method

    Get the Method for the Request.

  • functionset-method: func(method: method) -> result

    Set the Method for the Request. Fails if the string present in a method.other argument is not a syntactically valid method.

  • functionget-path-with-query: func() -> option<string>

    Get the combination of the HTTP Path and Query for the Request. When none, this represents an empty Path and empty Query.

  • functionset-path-with-query: func(path-with-query: option<string>) -> result

    Set the combination of the HTTP Path and Query for the Request. When none, this represents an empty Path and empty Query. Fails is the string given is not a syntactically valid path and query uri component.

  • functionget-scheme: func() -> option<scheme>

    Get the HTTP Related Scheme for the Request. When none, the implementation may choose an appropriate default scheme.

  • functionset-scheme: func(scheme: option<scheme>) -> result

    Set the HTTP Related Scheme for the Request. When none, the implementation may choose an appropriate default scheme. Fails if the string given is not a syntactically valid uri scheme.

  • functionget-authority: func() -> option<string>

    Get the authority of the Request's target URI. A value of none may be used with Related Schemes which do not require an authority. The HTTP and HTTPS schemes always require an authority.

  • functionset-authority: func(authority: option<string>) -> result

    Set the authority of the Request's target URI. A value of none may be used with Related Schemes which do not require an authority. The HTTP and HTTPS schemes always require an authority. Fails if the string given is not a syntactically valid URI authority.

  • functionget-options: func() -> option<request-options>

    Get the request-options to be associated with this request

    The returned request-options resource is immutable: set-* operations will fail if invoked.

    This request-options resource is a child: it must be dropped before the parent request is dropped, or its ownership is transferred to another component by e.g. handler.handle.

  • functionget-headers: func() -> headers

    Get the headers associated with the Request.

    The returned headers resource is immutable: set, append, and delete operations will fail with header-error.immutable.

  • static functionconsume-body: static func( this: request, res: future<result<_, error-code>>, ) -> tuple<stream<u8>, future<result<option<trailers>, error-code>>>

    Get body of the Request.

    Stream returned by this method represents the contents of the body. Once the stream is reported as closed, callers should await the returned future to determine whether the body was received successfully. The future will only resolve after the stream is reported as closed.

    This function takes a res future as a parameter, which can be used to communicate an error in handling of the request.

    Note that function will move the request, but references to headers or request options acquired from it previously will remain valid.

record send-argssince 0.1.0-dev

Arguments to wasi:http/client#send.

  • request: borrow<request>

    The request to send. A latch may read it, e.g. its method, scheme, authority, path or headers, but the request is still sent by the gate, after the latch defers.

record handle-argssince 0.1.0-dev

Arguments to wasi:http/handler#handle.

  • request: borrow<request>

    The request to handle. A latch may read it, e.g. its method, scheme, authority, path or headers, but the request is still handled by the gate, after the latch defers.

variant client-operationsince 0.1.0-dev

Operations of the wasi:http/client interface.

  • send: send-args

    Send a request, wasi:http/client#send.

variant handler-operationsince 0.1.0-dev

Operations of the wasi:http/handler interface.

  • handle: handle-args

    Handle a request, wasi:http/handler#handle.

variant operationsince 0.1.0-dev

Operations of the wasi:http package a gate asks a latch to authorize.

variant decisionsince 0.1.0-dev

Whether the request is allowed to proceed.

  • deferred

    The latch raises no objection, the request proceeds unless another latch denies it.

  • denied: http-error-code

    The request must not proceed. The gate fails it with the error code, without sending or handling it.

type latch-namesince 0.1.0-dev

The name of a latch component, identifying which latch reported an error.

  • string

variant error-codesince 0.1.0-dev

A latch was unable to decide or observe. The gate fails the request.

  • invalid-config: latch-name

    The latch's configuration is invalid, the cause is logged by the latch.

  • observation-failed: latch-name

    The latch was unable to act on the final decision.

  • other: option<string>

    Any other error.

Functions

functionauthorize: func(operation: operation) -> result<decision, error-code>since 0.1.0-dev

Decide whether the request may proceed.

Must not have side effects. When latches are aggregated, a latch is not asked about a request another latch already denied, so state changed here could disagree with what actually happened. Act on decisions in observe-decision instead.

functionobserve-decision: func( final-decision: decision, operation: operation, ) -> result<_, error-code>since 0.1.0-dev

Observe the final decision for a request, after authorize returned a decision.

Called for both deferred and denied requests, including requests this latch was not asked to authorize because an aggregated latch denied them first. The final decision is what the gate enforces, so this is where a latch updates any state it keeps. Not called when authorize returned an error.

An error fails the request, since the latch could not act on the decision.

WIT

/// Access control for wasi:http.
///
/// A gate consults a latch before each request it sends or handles. The latch either defers,
/// raising no objection, or denies the request. A latch never grants a request, a request
/// proceeds when the latch defers. Several latches can be aggregated into one, the request is
/// denied when any of them denies it.
///
/// Deciding and acting on a decision are separate steps. `authorize` decides without side
/// effects, then the gate reports the final decision to `observe-decision`, where a latch updates
/// any state it keeps. A latch aggregated with others may not be asked to authorize a request
/// another latch already denied, but it always observes the final decision.
@since(version = 0.1.0-dev)
interface latch {
  use wasi:http/types@0.3.0.{error-code as http-error-code, request};

  /// Arguments to wasi:http/client#send.
  @since(version = 0.1.0-dev)
  record send-args {
    /// The request to send. A latch may read it, e.g. its method, scheme, authority, path or
    /// headers, but the request is still sent by the gate, after the latch defers.
    request: borrow<request>,
  }

  /// Arguments to wasi:http/handler#handle.
  @since(version = 0.1.0-dev)
  record handle-args {
    /// The request to handle. A latch may read it, e.g. its method, scheme, authority, path or
    /// headers, but the request is still handled by the gate, after the latch defers.
    request: borrow<request>,
  }

  /// Operations of the wasi:http/client interface.
  @since(version = 0.1.0-dev)
  variant client-operation {
    /// Send a request, wasi:http/client#send.
    send(send-args),
  }

  /// Operations of the wasi:http/handler interface.
  @since(version = 0.1.0-dev)
  variant handler-operation {
    /// Handle a request, wasi:http/handler#handle.
    handle(handle-args),
  }

  /// Operations of the wasi:http package a gate asks a latch to authorize.
  @since(version = 0.1.0-dev)
  variant operation {
    /// A request sent with wasi:http/client.
    client(client-operation),
    /// A request handled with wasi:http/handler.
    handler(handler-operation),
  }

  /// Whether the request is allowed to proceed.
  @since(version = 0.1.0-dev)
  variant decision {
    /// The latch raises no objection, the request proceeds unless another latch denies it.
    deferred,
    /// The request must not proceed. The gate fails it with the error code, without sending
    /// or handling it.
    denied(http-error-code),
  }

  /// The name of a latch component, identifying which latch reported an error.
  @since(version = 0.1.0-dev)
  type latch-name = string;

  /// A latch was unable to decide or observe. The gate fails the request.
  @since(version = 0.1.0-dev)
  variant error-code {
    /// The latch's configuration is invalid, the cause is logged by the latch.
    invalid-config(latch-name),
    /// The latch was unable to act on the final decision.
    observation-failed(latch-name),
    /// Any other error.
    other(option<string>),
  }

  /// Decide whether the request may proceed.
  ///
  /// Must not have side effects. When latches are aggregated, a latch is not asked about a
  /// request another latch already denied, so state changed here could disagree with what
  /// actually happened. Act on decisions in `observe-decision` instead.
  @since(version = 0.1.0-dev)
  authorize: func(operation: operation) -> result<decision, error-code>;

  /// Observe the final decision for a request, after `authorize` returned a decision.
  ///
  /// Called for both deferred and denied requests, including requests this latch was not asked
  /// to authorize because an aggregated latch denied them first. The final decision is what the
  /// gate enforces, so this is where a latch updates any state it keeps. Not called when
  /// `authorize` returned an error.
  ///
  /// An error fails the request, since the latch could not act on the decision.
  @since(version = 0.1.0-dev)
  observe-decision: func(final-decision: decision, operation: operation) -> result<_, error-code>;
}