Programming Language

Nocter

A self-contained systems language built around simplicity, encapsulation, and foolproof design.

index.nct

//! Validated HTTP/1.1 message values and transport-independent framing.

use /hash.{Hash, HashState}
use /iter.{Iterator, LendingIterator}
use /io.{BlockingReader, Reader, TimedReader, TimedWriter, Writer}
use /net.SocketAddress
use /session.SessionId
use /string.String
use /time.Duration
use /tls.TrustAnchor
use /url.Url
use /vec.Vec

see ./async_client.nct
see ./application_response.nct
see ./application_values.nct
see ./body.nct
see ./body_cursor.nct
see ./body_cursor_tests.nct
see ./client.nct
see ./client_storage.nct
see ./client_tests.nct
see ./client_transport.nct
see ./codec.nct
see ./connection_input.nct
see ./connection_policy.nct
see ./cookie.nct
see ./errors.nct
see ./exchange.nct
see ./encoding.nct
see ./field_codec.nct
see ./form.nct
see ./media_type.nct
see ./request.nct
see ./request_head.nct
see ./request_convenience.nct
see ./router.nct
see ./router_storage.nct
see ./response_collection.nct
see ./response_head.nct
see ./response_plan.nct
see ./response_writer.nct
see ./session_cookie.nct
see ./server.nct
see ./server_storage.nct
see ./server_values.nct
see ./storage.nct
see ./target.nct
see ./tests.nct
see ./transport_buffer.nct
see ./values.nct
see ./wire.nct

/// One validated, case-sensitive HTTP method token.
pub struct Method

construct Method {
    /// Validates and copies one HTTP method token.
    pub func parse(text: &str): Self!

    /// Returns the standard GET method.
    pub func get(): Self

    /// Returns the standard HEAD method.
    pub func head(): Self

    /// Returns the standard POST method.
    pub func post(): Self
}

instance Method {
    /// Returns the exact method token.
    pub noalloc method &self.text(): &str from self

    /// Compares the case-sensitive method token.
    pub noalloc operator (&self == other: &Self): bool
}

/// One validated three-digit HTTP status code.
pub copy struct Status

construct Status {
    /// Accepts codes from 100 through 999.
    pub noalloc func new(code: u16): Self!

    /// Returns the standard 200 OK status.
    pub noalloc func ok(): Self

    /// Returns the standard 400 Bad Request status.
    pub noalloc func bad_request(): Self

    /// Returns the standard 404 Not Found status.
    pub noalloc func not_found(): Self

    /// Returns the standard 405 Method Not Allowed status.
    pub noalloc func method_not_allowed(): Self

    /// Returns the standard 500 Internal Server Error status.
    pub noalloc func internal_server_error(): Self
}

instance Status {
    /// Returns the numeric status code.
    pub noalloc method &self.code(): u16

    /// Returns whether this is an informational response.
    pub noalloc method &self.is_informational(): bool

    /// Returns whether this is a successful response.
    pub noalloc method &self.is_success(): bool
}

/// One validated HTTP field name with canonical lowercase storage.
pub struct HeaderName

construct HeaderName {
    /// Validates one non-empty ASCII token and stores its lowercase spelling.
    pub func parse(text: &str): Self!
}

instance HeaderName {
    impl Hash

    /// Returns the canonical lowercase field name.
    pub noalloc method &self.text(): &str from self

    /// Compares canonical field names.
    pub noalloc operator (&self == other: &Self): bool

    /// Adds the canonical field-name identity to `state`.
    pub noalloc method &self.hash_into(state: &+HashState): void
}

/// One validated HTTP field value stored as exact bytes without surrounding wire whitespace.
pub struct HeaderValue

construct HeaderValue {
    /// Validates and copies bytes that contain no forbidden field controls.
    pub func parse(bytes: &[u8]): Self!

    /// Validates and copies a UTF-8 field value.
    pub func from_text(text: &str): Self!
}

instance HeaderValue {
    /// Returns the exact validated field bytes.
    pub noalloc method &self.bytes(): &[u8] from self
}

/// One ordered HTTP field.
pub struct Header

construct Header {
    /// Combines an already validated name and value.
    pub noalloc func new(name: HeaderName, value: HeaderValue): Self
}

instance Header {
    /// Borrows the field name.
    pub noalloc method &self.name(): &HeaderName from self

    /// Borrows the field value.
    pub noalloc method &self.value(): &HeaderValue from self
}

/// An ordered sequence of HTTP fields that preserves duplicates.
pub struct Headers

construct Headers {
    /// Constructs an empty field sequence.
    pub noalloc func empty(): Self
}

instance Headers {
    /// Appends one validated field without combining it with earlier fields.
    pub method &+self.append(header: Header): void

    /// Returns the number of retained fields.
    pub noalloc method &self.len(): usize

    /// Borrows the field at `index`.
    pub noalloc method &self.at(index: usize): &Header? from self

    /// Borrows the first value whose canonical name equals `name`.
    pub noalloc method &self.first(name: &str): &HeaderValue? from self
}

/// Finite limits applied before HTTP syntax can cause unbounded storage growth.
pub copy struct Limits

construct Limits {
    /// Returns conservative defaults for ordinary HTTP messages.
    pub noalloc func standard(): Self

    /// Constructs one nonzero, internally consistent limit set.
    pub noalloc func new(
        max_start_line_bytes: usize,
        max_header_bytes: usize,
        max_header_count: usize,
        max_informational_responses: usize,
        max_field_bytes: usize,
        max_chunk_line_bytes: usize,
        max_body_bytes: usize,
    ): Self!
}

/// One validated origin-form request target with its path/query boundary parsed once.
pub struct RequestTarget

construct RequestTarget {
    /// Validates syntax and decoded query UTF-8, then copies one origin-form request target.
    pub func parse(text: &str): Self!
}

instance RequestTarget {
    /// Borrows the exact validated request-target spelling.
    pub noalloc method &self.text(): &str from self

    /// Borrows the percent-encoded path spelling without the query delimiter.
    pub noalloc method &self.path(): &str from self

    /// Borrows the percent-encoded query spelling when a `?` delimiter was present.
    pub noalloc method &self.query(): &str? from self

    /// Returns the number of already separated path segments after the leading `/`.
    pub noalloc method &self.path_segment_count(): usize

    /// Borrows one percent-encoded path segment without rescanning the target.
    pub noalloc method &self.path_segment(index: usize): &str? from self

    /// Iterates decoded query name/value pairs in source order.
    pub noalloc method &self.query_pairs(): QueryIter from self
}

/// One decoded query name/value pair lent by its active query decoder.
pub struct QueryParameter

instance QueryParameter {
    /// Borrows the decoded parameter name.
    pub noalloc method &self.name(): &str from self

    /// Borrows the decoded parameter value, or empty text when no `=` was present.
    pub noalloc method &self.value(): &str from self

    /// Copies this pair into independently owned text.
    pub method &self.to_owned(): OwnedQueryParameter
}

/// One independently owned decoded query name/value pair.
pub struct OwnedQueryParameter

instance OwnedQueryParameter {
    /// Borrows the decoded owned parameter name.
    pub noalloc method &self.name(): &str from self

    /// Borrows the decoded owned parameter value.
    pub noalloc method &self.value(): &str from self
}

/// One borrowed iterator over a request target's query pairs.
pub struct QueryIter

instance QueryIter {
    impl LendingIterator { .Item = QueryParameter }
}

/// Finite bounds for application-level HTTP value decoding.
pub copy struct ApplicationLimits

construct ApplicationLimits {
    /// Returns conservative limits for ordinary forms, media parameters, and cookies.
    pub noalloc func standard(): Self

    /// Constructs nonzero item, per-value, and aggregate decoded-byte limits.
    pub noalloc func new(
        max_items: usize,
        max_value_bytes: usize,
        max_decoded_bytes: usize,
    ): Self!
}

/// One owned application/x-www-form-urlencoded name/value pair.
pub struct FormParameter

instance FormParameter {
    /// Borrows the decoded parameter name.
    pub noalloc method &self.name(): &str from self

    /// Borrows the decoded parameter value.
    pub noalloc method &self.value(): &str from self
}

/// One bounded, ordered application/x-www-form-urlencoded value.
pub struct Form

construct Form {
    /// Decodes percent escapes and `+` spaces while preserving pair and duplicate order.
    pub func parse(text: &str): Self!

    /// Decodes with explicit item, per-value, and aggregate limits.
    pub func parse_with_limits(text: &str, limits: ApplicationLimits): Self!
}

instance Form {
    /// Returns the retained pair count.
    pub noalloc method &self.len(): usize

    /// Borrows one pair by source order.
    pub noalloc method &self.at(index: usize): &FormParameter? from self

    /// Borrows the first value with the exact decoded name.
    pub noalloc method &self.first(name: &str): &str? from self

    /// Counts values with the exact decoded name.
    pub noalloc method &self.count(name: &str): usize
}

/// One parsed media type with canonical lowercase type, subtype, and parameter names.
pub struct MediaType

construct MediaType {
    /// Parses one bounded media type, including token and quoted parameter values.
    pub func parse(text: &str): Self!

    /// Parses with explicit parameter, per-value, and aggregate limits.
    pub func parse_with_limits(text: &str, limits: ApplicationLimits): Self!
}

instance MediaType {
    /// Borrows the canonical lowercase top-level type.
    pub noalloc method &self.type_name(): &str from self

    /// Borrows the canonical lowercase subtype.
    pub noalloc method &self.subtype(): &str from self

    /// Returns whether the canonical type and subtype match ASCII-insensitively.
    pub noalloc method &self.matches(type_name: &str, subtype: &str): bool

    /// Returns the retained parameter count.
    pub noalloc method &self.parameter_count(): usize

    /// Borrows the first parameter value with the ASCII-insensitive name.
    pub noalloc method &self.parameter(name: &str): &str? from self
}

/// One validated request-cookie name/value pair.
pub struct Cookie

construct Cookie {
    /// Validates and copies one cookie pair.
    pub func new(name: &str, value: &str): Self!
}

instance Cookie {
    /// Borrows the cookie name.
    pub noalloc method &self.name(): &str from self

    /// Borrows the cookie value.
    pub noalloc method &self.value(): &str from self

    /// Renders the canonical `name=value` request-cookie spelling.
    pub method &self.render(): String
}

/// One bounded, ordered request `Cookie` field value.
pub struct Cookies

construct Cookies {
    /// Parses semicolon-separated cookie pairs while preserving duplicates and source order.
    pub func parse(text: &str): Self!

    /// Parses with explicit pair, per-value, and aggregate limits.
    pub func parse_with_limits(text: &str, limits: ApplicationLimits): Self!
}

instance Cookies {
    /// Returns the retained cookie count.
    pub noalloc method &self.len(): usize

    /// Borrows one cookie by source order.
    pub noalloc method &self.at(index: usize): &Cookie? from self

    /// Borrows the first value with the exact cookie name.
    pub noalloc method &self.first(name: &str): &str? from self

    /// Counts cookies with the exact name.
    pub noalloc method &self.count(name: &str): usize
}

/// One fixed, HttpOnly session-cookie transport policy.
pub struct SessionCookie

construct SessionCookie {
    /// Validates one cookie name and absolute cookie path.
    pub func new(name: &str, path: &str, secure: bool): Self!
}

instance SessionCookie {
    /// Reads one unambiguous session identifier from the complete request fields.
    pub method &self.read_headers(headers: &Headers): SessionId?!

    /// Reads one unambiguous canonical session identifier from request cookies.
    pub noalloc method &self.read(cookies: &Cookies): SessionId?!

    /// Creates one `Set-Cookie` header using HttpOnly and SameSite=Lax.
    pub method &self.set_header(identifier: &SessionId): Header!

    /// Creates one matching `Set-Cookie` header that expires the browser value.
    pub method &self.clear_header(): Header!
}

/// A validated outbound HTTP/1.1 request head.
pub struct RequestHead

construct RequestHead {
    /// Constructs a request head from a method and origin-form request target.
    pub func new(request_method: Method, target: &str): Self!
}

instance RequestHead {
    /// Borrows the method.
    pub noalloc method &self.request_method(): &Method from self

    /// Borrows the parsed origin-form request target.
    pub noalloc method &self.target(): &RequestTarget from self

    /// Appends one ordered field.
    pub method &+self.append_header(header: Header): void

    /// Borrows the ordered fields.
    pub noalloc method &self.headers(): &Headers from self
}

/// One validated HTTP/1.1 response status and ordered field set.
pub struct ResponseHead

construct ResponseHead {
    /// Creates an empty final response head.
    pub noalloc func new(status: Status): Self!

    /// Creates an empty successful response head with status 200.
    pub noalloc func ok(): Self
}

instance ResponseHead {
    /// Returns the response status.
    pub noalloc method &self.status(): Status

    /// Borrows the ordered fields.
    pub noalloc method &self.headers(): &Headers from self

    /// Appends one validated ordered field.
    pub method &+self.append_header(header: Header): void

    /// Validates and appends one textual field.
    pub method &+self.append_header_text(name: &str, value: &str): void!
}

/// One owned HTTP request with a parsed URL and bounded byte body.
pub struct Request

construct Request {
    /// Creates an empty-body request for `url`.
    pub func new(request_method: Method, url: Url): Self!

    /// Creates an empty-body GET request for `url`.
    pub func get(url: Url): Self!

    /// Creates an empty-body HEAD request for `url`.
    pub func head(url: Url): Self!

    /// Creates an empty-body POST request for `url`.
    pub func post(url: Url): Self!
}

instance Request {
    /// Borrows the parsed destination URL.
    pub noalloc method &self.url(): &Url from self

    /// Borrows the request method.
    pub noalloc method &self.request_method(): &Method from self

    /// Borrows the ordered user fields.
    pub noalloc method &self.headers(): &Headers from self

    /// Borrows the complete request body.
    pub noalloc method &self.body(): &[u8] from self

    /// Appends one validated user field.
    pub method &+self.append_header(header: Header): void

    /// Validates and appends one textual user field.
    pub method &+self.append_header_text(name: &str, value: &str): void!

    /// Replaces the complete owned request body.
    pub method &+self.set_body(body: Vec<u8>): void

    /// Copies UTF-8 bytes into the complete owned request body.
    pub method &+self.set_text_body(text: &str): void
}

/// Immutable HTTP request policy shared by synchronous and asynchronous operations.
pub struct Client

construct Client {
    /// Uses the standard finite HTTP limits.
    pub noalloc func new(): Self

    /// Uses one caller-selected validated limit set.
    pub noalloc func with_limits(limits: Limits): Self
}

instance Client {
    /// Returns this policy with one additional TLS trust root.
    pub method self.with_trust_anchor(trust_anchor: TrustAnchor): Self

    /// Sends one request over one new connection and returns its final response.
    pub blocking method &self.send_blocking(request: Request): Response!

    /// Lazily validates, resolves, connects, sends, and receives without blocking the executor.
    pub async method &self.send(request: Request): Response!

    /// Performs each asynchronous transport operation with an explicit timeout.
    pub async method &self.send_with_timeout(
        request: Request,
        timeout: Duration,
    ): Response!

    /// Sends with one connection deadline and per-operation stream timeouts.
    pub blocking method &self.send_with_timeout_blocking(
        request: Request,
        timeout: Duration,
    ): Response!
}

/// One uniquely owned response body stream and its parsed response head.
pub struct Response

instance Response {
    impl BlockingReader
    impl Reader
    impl TimedReader

    /// Returns the final response status.
    pub noalloc method &self.status(): Status

    /// Borrows the final ordered response fields.
    pub noalloc method &self.headers(): &Headers from self

    /// Reads at most `output.len()` decoded response-body bytes, possibly waiting for input.
    pub blocking method &+self.read_blocking(output: &+[u8]): usize!

    /// Reads at most `output.len()` decoded response-body bytes without blocking the executor.
    pub async method &+self.read(output: &+[u8]): usize!

    /// Reads at most `output.len()` decoded bytes with an idle timeout for needed input.
    pub async method &+self.read_with_timeout(
        output: &+[u8],
        timeout: Duration,
    ): usize!

    /// Reads the complete decoded body with a fresh idle timeout for each needed input fragment.
    pub async method &+self.read_to_end_with_timeout(timeout: Duration): Vec<u8>!

    /// Reads and validates the complete UTF-8 body with per-fragment idle timeouts.
    pub async method &+self.read_to_string_with_timeout(timeout: Duration): String!

    /// Closes the owned connection; later reads report end of stream.
    pub noalloc method &+self.close(): void
}

/// One HTTP/1.1 request head and uniquely owned streaming request body.
pub struct IncomingRequest

instance IncomingRequest {
    impl Reader
    impl TimedReader

    /// Borrows the request method.
    pub noalloc method &self.request_method(): &Method from self

    /// Borrows the parsed origin-form request target.
    pub noalloc method &self.target(): &RequestTarget from self

    /// Borrows the ordered request fields.
    pub noalloc method &self.headers(): &Headers from self

    /// Reads at most `output.len()` decoded request-body bytes.
    pub async method &+self.read(output: &+[u8]): usize!

    /// Reads at most `output.len()` decoded bytes with an idle input timeout.
    pub async method &+self.read_with_timeout(
        output: &+[u8],
        timeout: Duration,
    ): usize!

    /// Drains any unread body and transfers the unique response authority.
    pub async method self.finish_body(): Responder!

    /// Drains the unread body before one fixed monotonic deadline.
    pub async method self.finish_body_with_timeout(timeout: Duration): Responder!

    /// Drains the request body and sends one complete response through the canonical responder.
    pub async method self.respond(response: OutgoingResponse): ServerConnection?!

    /// Drains and responds while applying one timeout to each existing consuming transition.
    pub async method self.respond_with_timeout(
        response: OutgoingResponse,
        timeout: Duration,
    ): ServerConnection?!

    /// Closes the connection without draining the body or sending a response.
    pub method self.close(): void
}

/// One owned HTTP/1.1 response to be sent by a `Responder`.
pub struct OutgoingResponse

construct OutgoingResponse {
    /// Creates an empty-body final response.
    pub noalloc func new(status: Status): Self!

    /// Creates an empty successful response with status 200.
    pub noalloc func ok(): Self

    /// Creates a UTF-8 plain-text response with one canonical content type.
    pub func text(status: Status, text: &str): Self!

    /// Creates a UTF-8 JSON response without interpreting or rewriting its document bytes.
    pub func json(status: Status, document: &str): Self!
}

instance OutgoingResponse {
    /// Returns the selected final status.
    pub noalloc method &self.status(): Status

    /// Borrows the ordered user fields.
    pub noalloc method &self.headers(): &Headers from self

    /// Borrows the complete response body.
    pub noalloc method &self.body(): &[u8] from self

    /// Appends one validated user field.
    pub method &+self.append_header(header: Header): void

    /// Validates and appends one textual user field.
    pub method &+self.append_header_text(name: &str, value: &str): void!

    /// Replaces the complete response body.
    pub method &+self.set_body(body: Vec<u8>): void

    /// Copies UTF-8 bytes into the complete response body.
    pub method &+self.set_text_body(text: &str): void
}

/// One asynchronous HTTP listener with immutable parsing and buffering limits.
pub struct Server

construct Server {
    /// Binds one numeric address with standard finite HTTP limits.
    pub async func bind(address: SocketAddress): Self!

    /// Binds one numeric address with caller-selected finite HTTP limits.
    pub async func bind_with_limits(address: SocketAddress, limits: Limits): Self!
}

instance Server {
    /// Returns the effective local address, including a kernel-selected port.
    pub noalloc method &self.local_address(): SocketAddress!

    /// Accepts one connection without blocking the executor thread.
    pub async method &+self.accept(): ServerConnection!

    /// Accepts one connection before a fixed monotonic deadline.
    pub async method &+self.accept_with_timeout(timeout: Duration): ServerConnection!

    /// Consumes this listener admission authority without affecting accepted connections.
    pub noalloc method self.close(): void
}

/// One accepted stream that has not yet yielded its next request head.
pub struct ServerConnection

instance ServerConnection {
    /// Returns the accepted peer address.
    pub noalloc method &self.peer_address(): SocketAddress

    /// Decodes one bounded request head and transfers its streaming body owner.
    pub async method self.read_request(): IncomingRequest!

    /// Decodes one request head before a fixed monotonic deadline.
    pub async method self.read_request_with_timeout(
        timeout: Duration,
    ): IncomingRequest!

    /// Closes this connection without reading a request.
    pub method self.close(): void
}

/// One heterogeneous readonly request handler over explicitly borrowed application state.
pub type Handler<State> = any &func(
    state: &State,
    request: IncomingRequest,
    route: RouteMatch,
): future ServerConnection?! from state | request | route

/// One decoded named path parameter.
pub struct RouteParameter

instance RouteParameter {
    /// Borrows the parameter name authored in the route pattern.
    pub noalloc method &self.name(): &str from self

    /// Borrows the percent-decoded UTF-8 value selected from the request path.
    pub noalloc method &self.value(): &str from self
}

/// The owned named parameters selected for one request.
pub struct RouteMatch

instance RouteMatch {
    /// Returns the number of named parameters.
    pub noalloc method &self.len(): usize

    /// Borrows the parameter at `index` in pattern order.
    pub noalloc method &self.at(index: usize): &RouteParameter? from self

    /// Borrows the first value whose parameter name equals `name`.
    pub noalloc method &self.parameter(name: &str): &str? from self
}

/// The result of route selection and optional handler execution.
pub enum RouteDispatch {
    /// A selected handler completed and returned its connection disposition.
    handled(connection: ServerConnection?)

    /// No registered path pattern matched; the request remains available for policy handling.
    not_found(request: IncomingRequest)

    /// A path matched but no handler accepted the request method.
    method_not_allowed(request: IncomingRequest)
}

/// Explicit application state and an ordered set of validated, non-ambiguous handlers.
pub struct Router<State>

construct Router<State> {
    /// Moves application state into a router without registered routes or allocation.
    pub noalloc func new(state: State): Self
}

instance Router<State> {
    /// Borrows the exact application state passed to every selected handler.
    pub noalloc method &self.state(): &State from self

    /// Consumes the router and recovers its application state.
    pub method self.into_state(): State

    /// Adds one method and path pattern, rejecting duplicates and equal-precedence overlap.
    pub method &+self.add(
        request_method: Method,
        pattern: &str,
        handler: Handler<State>,
    ): void!

    /// Adds one GET route.
    pub method &+self.get(pattern: &str, handler: Handler<State>): void!

    /// Adds one POST route.
    pub method &+self.post(pattern: &str, handler: Handler<State>): void!

    /// Selects and awaits one handler, retaining unmatched requests for application policy.
    pub async method &self.dispatch(request: IncomingRequest): RouteDispatch!
}

/// The unique capability to send one response on one decoded request connection.
pub struct Responder

instance Responder {
    /// Forces the completed response to advertise and perform connection closure.
    pub noalloc method &+self.close_after_response(): void

    /// Writes a fixed-length response head and returns its streaming body writer.
    pub async method self.begin_fixed(
        head: ResponseHead,
        content_length: usize,
    ): ResponseWriter!

    /// Begins a fixed-length response before one fixed monotonic deadline.
    pub async method self.begin_fixed_with_timeout(
        head: ResponseHead,
        content_length: usize,
        timeout: Duration,
    ): ResponseWriter!

    /// Writes a chunked response head and returns its streaming body writer.
    pub async method self.begin_chunked(head: ResponseHead): ResponseWriter!

    /// Begins a chunked response before one fixed monotonic deadline.
    pub async method self.begin_chunked_with_timeout(
        head: ResponseHead,
        timeout: Duration,
    ): ResponseWriter!

    /// Sends one complete response and returns a reusable connection when safe.
    pub async method self.respond(response: OutgoingResponse): ServerConnection?!

    /// Sends one complete response before a fixed monotonic deadline.
    pub async method self.respond_with_timeout(
        response: OutgoingResponse,
        timeout: Duration,
    ): ServerConnection?!

    /// Closes this connection without sending a response.
    pub method self.close(): void
}

/// The unique streaming body output for one frozen HTTP/1.1 response plan.
pub struct ResponseWriter

instance ResponseWriter {
    impl TimedWriter
    impl Writer

    /// Writes one complete body fragment with transport backpressure.
    pub async method &+self.write(bytes: &[u8]): void!

    /// Writes one complete fragment before one fixed monotonic deadline.
    pub async method &+self.write_with_timeout(
        bytes: &[u8],
        timeout: Duration,
    ): void!

    /// Completes framing and returns a reusable connection when policy permits it.
    pub async method self.finish(): ServerConnection?!

    /// Completes framing before one fixed monotonic deadline.
    pub async method self.finish_with_timeout(timeout: Duration): ServerConnection?!

    /// Closes the connection without completing response framing.
    pub method self.close(): void
}