Browse the docs

silk.http.head.

Parse and write the head of an HTTP/1.0 or HTTP/1.1 message: the start line and the header fields.

When to use#

Use RequestParser or ResponseParser to parse a head as its bytes arrive from a transport. Use parseRequest or parseResponse when you have all the bytes. Use writeRequestInto and writeResponseInto to write a head from silk.http.message.

Details#

A parser allocates all its memory in make. After that, feed, head, reset, and the write functions do not allocate. feed returns how many bytes of the input it used, and stops after the empty line that ends the head. The bytes after the head, such as the body, stay with you. The head and its fields borrow the parser. Call copy to keep them after a reset.

maxOwnedBytes must hold maxHeadBytes plus 32 bytes for each field in maxFields. Check a Limits value with validateLimits.

Errors#

  • ParseError tells which rule failed, the part, the byte offset in the head, and how many bytes of the current call were used.

  • After an error, the parser stays failed until RequestParser.reset.

  • OutOfMemoryError from make if the Allocator fails.

Gotchas#

The parser is strict. Lines must end with CRLF, and the start line uses one space between its parts. These fail: a bare LF, a space before : in a field, a folded request line, empty lines before the start line, and HTTP/0.9. A folded response field is joined with spaces. A status line with no reason phrase may leave out the space after the code: HTTP/1.1 200.

Examples#

Parse a response head#

silk
import silk.mem.allocator { Allocator, OutOfMemoryError }
import silk.core.effect { Effect }
import silk.http.message { Status }
import silk.http.head {
  Limits,
  ParseError,
  ParsedResponse,
  ProgressState,
  ResponseHead,
  ResponseParser,
  parseResponse
}
import silk.http.headers { Limits as ValueLimits }
import silk.core.result { Result }

fn limits() -> Limits {
  return Limits {
    maxHeadBytes: 4096,
    maxStartLineBytes: 1024,
    maxFieldLineBytes: 1024,
    maxOwnedBytes: 8192,
    values: ValueLimits {
      maxMethodBytes: 16,
      maxTargetBytes: 1024,
      maxNameBytes: 64,
      maxValueBytes: 1024,
      maxFields: 32,
      maxFieldBytes: 4096,
      maxOwnedBytes: 8192,
    },
  }
}

effect fn program() -> i32
  ! OutOfMemoryError {
  let mut allocator = Allocator.systemAllocatorProvider()
  let wire = b"HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nhello"
  let parsed = run parseResponse(&wire, limits()) |> Effect.provideMut<Allocator>(&mut allocator)
  let result = match move parsed {
    Result<ParsedResponse, ParseError>.Success { value } => move value
    Result<ParsedResponse, ParseError>.Failure { error: _ } => {
      return 1
    }
  }

  // The parser stops after the head. The body "hello" starts at byte 38.
  if result.progress.consumed != 38 || result.progress.state != ProgressState.Complete {
    return 1
  }
  let head = match ResponseParser.head(&result.parser) {
    Result<ResponseHead, ParseError>.Success { value } => value
    Result<ResponseHead, ParseError>.Failure { error: _ } => {
      return 1
    }
  }
  if Status.code(&ResponseHead.status(&head)) != 200 || ResponseHead.fieldCount(&head) != 1 {
    return 1
  }
  return 0
}

effect fn failed<E>(error: E) -> i32 {
  drop error
  return 1
}

pub fn main() -> i32 {
  return run Effect.catchAll(program(), failed)
}

Import as RequestParser with import silk.http.head { RequestParser }.

Public declarations: 22.

Limits#

silk
pub struct Limits

The maximum sizes for a parser. The values limits also apply to each part of the head.

Gotchas#

maxOwnedBytes must hold maxHeadBytes plus 32 bytes for each field in maxFields. Check a value with validateLimits.

Field maxHeadBytes#

silk
pub maxHeadBytes: usize

The maximum size of the head, including every CRLF and the empty line at the end.

Field maxStartLineBytes#

silk
pub maxStartLineBytes: usize

The maximum size of the request line or status line, including its CRLF.

Field maxFieldLineBytes#

silk
pub maxFieldLineBytes: usize

The maximum size of one field line, including its CRLF.

Field maxOwnedBytes#

silk
pub maxOwnedBytes: usize

The maximum memory of the parser: maxHeadBytes plus 32 bytes for each field in values.maxFields.

Field values#

silk
pub values: ValueLimits

The limits for the method, target, names, values, and field count.

Implementation Copy for Limits#

silk
impl Copy for Limits

ProgressState#

silk
pub enum ProgressState

Whether a head is complete after a feed.

NeedInput#

silk
NeedInput

The head is not complete. Feed more bytes.

Complete#

silk
Complete

The empty line at the end was read. Get the head with head.

Progress#

silk
pub struct Progress

The result of a successful feed.

Field consumed#

silk
pub consumed: usize

The number of bytes from the start of this input that the parser used. Give the rest again in the next call, or keep it if the head is complete.

Field state#

silk
pub state: ProgressState

Whether the head is complete.

Implementation Copy for Progress#

silk
impl Copy for Progress

ParserState#

silk
pub enum ParserState

The state of a parser.

Active#

silk
Active

The parser takes more input.

Complete#

silk
Complete

A head is complete. Call reset before you parse the next head.

Failed#

silk
Failed

A parse failed. Get the error with failure, and call reset to use the parser again.

ParseComponent#

silk
pub enum ParseComponent

The part of a head where a parse failed.

Parser#

silk
Parser

The parser itself, for example its limits or its state.

StartLine#

silk
StartLine

Request or response start line as a whole.

Version#

silk
Version

HTTP version token.

Method#

silk
Method

Request method token.

Target#

silk
Target

Request target.

Status#

silk
Status

Response status digits or range.

ReasonPhrase#

silk
ReasonPhrase

Response reason phrase.

HeaderName#

silk
HeaderName

Field name.

HeaderValue#

silk
HeaderValue

A field value, without the spaces around it.

Host#

silk
Host

The Host field.

LineEnding#

silk
LineEnding

A line ending.

Implementation Debug for ParseComponent#

silk
impl Debug for ParseComponent

Operation debug#

silk
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut Writer

Writes the name of the variant, such as Parser.

ParseLimitKind#

silk
pub enum ParseLimitKind

The limit that a head exceeded. See ParseReason.LimitExceeded.

HeadBytes#

silk
HeadBytes

maxHeadBytes.

StartLineBytes#

silk
StartLineBytes

maxStartLineBytes.

FieldLineBytes#

silk
FieldLineBytes

maxFieldLineBytes.

Fields#

silk
Fields

maxFields: the number of fields, including repeated fields.

MethodBytes#

silk
MethodBytes

maxMethodBytes.

TargetBytes#

silk
TargetBytes

maxTargetBytes.

NameBytes#

silk
NameBytes

maxNameBytes.

ValueBytes#

silk
ValueBytes

maxValueBytes, for a field value or the reason phrase.

FieldBytes#

silk
FieldBytes

maxFieldBytes: the total length of all names and values.

OwnedBytes#

silk
OwnedBytes

maxOwnedBytes: the memory of the parser.

Implementation Debug for ParseLimitKind#

silk
impl Debug for ParseLimitKind

Operation debug#

silk
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut Writer

Writes the name of the variant, such as HeadBytes.

ParseReason#

silk
pub union ParseReason

The rule that a parse or a write failed.

InvalidStartLine#

silk
InvalidStartLine

The start line does not have the form METHOD SP target SP version or version SP status SP reason, or version SP status with no reason.

UnsupportedVersion#

silk
UnsupportedVersion

A version is not exactly HTTP/1.0 or HTTP/1.1.

InvalidMethod#

silk
InvalidMethod

A request method is not a nonempty HTTP token.

InvalidTarget#

silk
InvalidTarget

The request target is not valid, or its form does not fit the method.

InvalidStatus#

silk
InvalidStatus

The status is not three digits from 100 to 599.

InvalidReasonPhrase#

silk
InvalidReasonPhrase

The reason phrase has a control byte or DEL.

InvalidFieldName#

silk
InvalidFieldName

A field name is empty, or has a byte that is not allowed in a token.

InvalidFieldValue#

silk
InvalidFieldValue

A field value has a byte that is not allowed.

BareLf#

silk
BareLf

A line ends with LF without CR.

InvalidLineEnding#

silk
InvalidLineEnding

A CR is not followed by LF.

WhitespaceBeforeColon#

silk
WhitespaceBeforeColon

A field has a space or a tab between its name and the :.

ObsFold#

silk
ObsFold

A field line starts with a space or a tab. Requests do not accept folded lines; a response accepts one only after its first field, and joins it to that field with spaces.

MissingHost#

silk
MissingHost

An HTTP/1.1 request has no Host field.

DuplicateHost#

silk
DuplicateHost

A request has more than one Host field.

InvalidHost#

silk
InvalidHost

The Host field is not a valid authority.

LimitExceeded#

silk
LimitExceeded

The head exceeded a limit.

Field limit#

silk
pub limit: ParseLimitKind

The limit that was exceeded.

Field allowed#

silk
pub allowed: usize

The value of the limit.

Field attempted#

silk
pub attempted: usize

The size that was found.

SizeOverflow#

silk
SizeOverflow

A size calculation overflowed usize.

Truncated#

silk
Truncated

The input ended, with final set to true, before the head was complete.

InvalidState#

silk
InvalidState

The call is not valid in the current ParserState, for example feed after a complete head.

Implementation Copy for ParseReason#

silk
impl Copy for ParseReason

Implementation Debug for ParseReason#

silk
impl Debug for ParseReason

Operation debug#

silk
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut Writer

Writes the name of the variant and its fields, such as InvalidStartLine.

ParseError#

silk
pub struct ParseError

The error from a parse. It tells which rule failed, the part, the byte offset in the head, and how many bytes of the current call were used.

Field reason#

silk
pub reason: ParseReason

The rule that failed.

Field component#

silk
pub component: ParseComponent

The part of the head that failed.

Field consumed#

silk
pub consumed: usize

The number of bytes of this call that were valid before the error.

Field offset#

silk
pub offset: usize

The byte offset in the head where the error is, from the start of the head.

Field fieldIndex#

silk
pub fieldIndex: Option<usize>

The position of the field, from 0, when the error is in a field.

Implementation Debug for ParseError#

silk
impl Debug for ParseError

Operation debug#

silk
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut Writer

Writes the fields, as ParseError { reason: ..., component: ..., ... }.

validateLimits#

silk
pub fn validateLimits(limits: &Limits) -> Result<(), ParseError>

Checks that limits are consistent, without allocation.

Errors#

  • LimitExceeded with OwnedBytes if maxOwnedBytes is less than maxHeadBytes plus 32 bytes for each field.

  • SizeOverflow if that sum does not fit in usize.

RequestParser#

silk
pub struct RequestParser

A parser for request heads that you feed in parts. Make it with RequestParser.make.

Details#

make allocates all its memory. After that, feed, head, and reset do not allocate. feed returns how many bytes of the input it used, and stops after the empty line that ends the head. The bytes after the head, such as the body, stay with you. The head and its fields borrow the parser. Call copy to keep them after a reset. After an error, the parser stays failed until reset.

Gotchas#

The parser is strict. Lines must end with CRLF, and the start line uses one space between its parts. These fail: a bare LF, a space before : in a field, a folded request line, empty lines before the start line, and HTTP/0.9. A folded response field is joined with spaces. A status line with no reason phrase may leave out the space after the code: HTTP/1.1 200.

ResponseParser#

silk
pub struct ResponseParser

A parser for response heads that you feed in parts. Make it with ResponseParser.make.

Details#

make allocates all its memory. After that, feed, head, and reset do not allocate. feed returns how many bytes of the input it used, and stops after the empty line that ends the head. The bytes after the head, such as the body, stay with you. The head and its fields borrow the parser. Call copy to keep them after a reset. After an error, the parser stays failed until reset.

Gotchas#

The parser is strict. Lines must end with CRLF, and the start line uses one space between its parts. These fail: a bare LF, a space before : in a field, a folded request line, empty lines before the start line, and HTTP/0.9. A folded response field is joined with spaces. A status line with no reason phrase may leave out the space after the code: HTTP/1.1 200.

RequestHead#

silk
pub struct RequestHead<'owner>

A parsed request head. It borrows its parser.

Implementation Copy for RequestHead<'owner>#

silk
impl<'owner> Copy for RequestHead<'owner>

ResponseHead#

silk
pub struct ResponseHead<'owner>

A parsed response head. It borrows its parser.

Implementation Copy for ResponseHead<'owner>#

silk
impl<'owner> Copy for ResponseHead<'owner>

HeaderIterator#

silk
pub struct HeaderIterator<'owner>

An iterator over the fields of a parsed head, in order.

ParsedRequest#

silk
pub struct ParsedRequest

The result of parseRequest.

Field parser#

silk
pub parser: RequestParser

The parser that holds the head. Get the head with RequestParser.head.

Field progress#

silk
pub progress: Progress

How many bytes the head used. The bytes after it, such as the body, start at progress.consumed.

ParsedResponse#

silk
pub struct ParsedResponse

The result of parseResponse.

Field parser#

silk
pub parser: ResponseParser

The parser that holds the head. Get the head with ResponseParser.head.

Field progress#

silk
pub progress: Progress

How many bytes the head used. The bytes after it, such as the body, start at progress.consumed.

Implementation RequestParser#

silk
impl RequestParser

Associated function make#

silk
pub effect fn make(limits: Limits) -> Result<RequestParser, ParseError>
  ! OutOfMemoryError
  ? &mut Allocator

Returns a parser, and allocates all its memory.

Errors#

  • ParseError if validateLimits fails.

  • OutOfMemoryError if the Allocator fails.

Method feed#

silk
pub fn feed(self: &mut Self, input: &[u8], final: bool) -> Result<Progress, ParseError>

Parses the start of input, and returns how many bytes it used.

Details#

The parser keeps the bytes that it used. It stops after the empty line that ends the head. Set final to true when no more input comes, so that an incomplete head fails with Truncated.

Method state#

silk
pub fn state(self: &Self) -> ParserState

Returns the state of the parser.

Method failure#

silk
pub fn failure(self: &Self) -> Option<ParseError>

Returns the error that made the parser fail, or None.

Method head#

silk
pub fn head<'owner>(self: &'owner Self) -> Result<RequestHead<'owner>, ParseError>

Returns the parsed head. Returns InvalidState if the head is not complete.

Method reset#

silk
pub fn reset(self: &mut Self) -> Result<(), ParseError>

Makes the parser ready for a new head, and keeps its memory. You cannot call it while you borrow a head from the parser.

Implementation ResponseParser#

silk
impl ResponseParser

Associated function make#

silk
pub effect fn make(limits: Limits) -> Result<ResponseParser, ParseError>
  ! OutOfMemoryError
  ? &mut Allocator

Returns a parser, and allocates all its memory.

Errors#

  • ParseError if validateLimits fails.

  • OutOfMemoryError if the Allocator fails.

Method feed#

silk
pub fn feed(self: &mut Self, input: &[u8], final: bool) -> Result<Progress, ParseError>

Parses the start of input, and returns how many bytes it used.

Details#

The parser keeps the bytes that it used. It stops after the empty line that ends the head. Set final to true when no more input comes, so that an incomplete head fails with Truncated.

Method state#

silk
pub fn state(self: &Self) -> ParserState

Returns the state of the parser.

Method failure#

silk
pub fn failure(self: &Self) -> Option<ParseError>

Returns the error that made the parser fail, or None.

Method head#

silk
pub fn head<'owner>(self: &'owner Self) -> Result<ResponseHead<'owner>, ParseError>

Returns the parsed head. Returns InvalidState if the head is not complete.

Method reset#

silk
pub fn reset(self: &mut Self) -> Result<(), ParseError>

Makes the parser ready for a new head, and keeps its memory. You cannot call it while you borrow a head from the parser.

Implementation RequestHead<'owner>#

silk
impl<'owner> RequestHead<'owner>

Method version#

silk
pub fn version(self: &Self) -> Version

Returns the parsed protocol version.

Method method#

silk
pub fn method(self: &Self) -> Method<'owner>

Returns the method, spelled as received.

Method target#

silk
pub fn target(self: &Self) -> RequestTarget<'owner>

Returns the request target.

Method fieldCount#

silk
pub fn fieldCount(self: &Self) -> usize

Returns the number of fields, including duplicates.

Method fields#

silk
pub fn fields(self: &Self) -> HeaderIterator<'owner>

Returns an iterator over the fields, in order. Repeated fields stay separate.

Method copy#

silk
pub effect fn copy(
    self: &Self,
    limits: ValueLimits,
  ) -> Result<OwnedRequestHead, ValueError> ! OutOfMemoryError ? &mut Allocator

Copies the head into new memory, as an owned head from silk.http.message.

Errors#

  • ValueError if the head exceeds limits.

  • OutOfMemoryError if the Allocator fails.

Implementation ResponseHead<'owner>#

silk
impl<'owner> ResponseHead<'owner>

Method version#

silk
pub fn version(self: &Self) -> Version

Returns the parsed protocol version.

Method status#

silk
pub fn status(self: &Self) -> Status

Returns the status.

Method reason#

silk
pub fn reason(self: &Self) -> &'owner [u8]

Returns the reason phrase bytes. They can be empty, and are not always UTF-8.

Method fieldCount#

silk
pub fn fieldCount(self: &Self) -> usize

Returns the number of fields, including duplicates.

Method fields#

silk
pub fn fields(self: &Self) -> HeaderIterator<'owner>

Returns an iterator over the fields, in order. Repeated fields stay separate.

Method copy#

silk
pub effect fn copy(
    self: &Self,
    limits: ValueLimits,
  ) -> Result<OwnedResponseHead, ValueError> ! OutOfMemoryError ? &mut Allocator

Copies the head into new memory, as an owned head from silk.http.message.

Errors#

  • ValueError if the head exceeds limits.

  • OutOfMemoryError if the Allocator fails.

Method copyMatchingHeaders#

silk
pub effect fn copyMatchingHeaders<'name>(
    self: &Self,
    name: string<'name>,
    limits: ValueLimits,
  ) -> Result<OwnedResponseHead, ValueError> ! OutOfMemoryError ? &mut Allocator

Copies the status, the reason, and only the fields named name, into new memory.

Details#

Names are compared without case. Repeated fields stay separate, in their order. limits applies to the copied parts only.

Implementation HeaderIterator<'owner>#

silk
impl<'owner> HeaderIterator<'owner>

Method next#

silk
pub fn next(self: &mut Self) -> Option<Header<'owner>>

Returns the next validated field, or None after the final field.

Method fieldIndex#

silk
pub fn fieldIndex(self: &Self) -> usize

Returns the position of the last field from HeaderIterator.next, from 0.

parseRequest#

silk
pub effect fn parseRequest(
  input: &[u8],
  limits: Limits,
) -> Result<ParsedRequest, ParseError> ! OutOfMemoryError ? &mut Allocator

Parses a request head from the start of input. The bytes after the head start at progress.consumed in the result.

Gotchas#

The parser is strict. Lines must end with CRLF, and the start line uses one space between its parts. These fail: a bare LF, a space before : in a field, a folded request line, empty lines before the start line, and HTTP/0.9. A folded response field is joined with spaces. A status line with no reason phrase may leave out the space after the code: HTTP/1.1 200.

parseResponse#

silk
pub effect fn parseResponse(
  input: &[u8],
  limits: Limits,
) -> Result<ParsedResponse, ParseError> ! OutOfMemoryError ? &mut Allocator

Parses a response head from the start of input. The bytes after the head start at progress.consumed in the result.

Gotchas#

The parser is strict. Lines must end with CRLF, and the start line uses one space between its parts. These fail: a bare LF, a space before : in a field, a folded request line, empty lines before the start line, and HTTP/0.9. A folded response field is joined with spaces. A status line with no reason phrase may leave out the space after the code: HTTP/1.1 200.

requestSerializedSize#

silk
pub fn requestSerializedSize<'value>(
  head: &ValueRequestHead<'value>,
  limits: ValueLimits,
) -> Result<usize, ValueError>

Returns the number of bytes that writeRequestInto writes for head.

responseSerializedSize#

silk
pub fn responseSerializedSize<'value>(
  head: &ValueResponseHead<'value>,
  limits: ValueLimits,
) -> Result<usize, ValueError>

Returns the number of bytes that writeResponseInto writes for head.

writeRequestInto#

silk
pub fn writeRequestInto<'value>(
  head: &ValueRequestHead<'value>,
  output: &mut [u8],
  limits: ValueLimits,
) -> Result<usize, ValueError>

Writes head with single spaces and CRLF line endings, and the empty line at the end, to the start of output. Returns the length. If output is too small, it writes nothing.

writeResponseInto#

silk
pub fn writeResponseInto<'value>(
  head: &ValueResponseHead<'value>,
  output: &mut [u8],
  limits: ValueLimits,
) -> Result<usize, ValueError>

Writes head with single spaces and CRLF line endings, and the empty line at the end, to the start of output. Returns the length. If output is too small, it writes nothing.

Category: HTTP.

Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2.

View the source of this page