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#
ParseErrortells 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.OutOfMemoryErrorfrommakeif theAllocatorfails.
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#
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#
pub struct LimitsThe 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#
pub maxHeadBytes: usizeThe maximum size of the head, including every CRLF and the empty line at the end.
Field maxStartLineBytes#
pub maxStartLineBytes: usizeThe maximum size of the request line or status line, including its CRLF.
Field maxFieldLineBytes#
pub maxFieldLineBytes: usizeThe maximum size of one field line, including its CRLF.
Field maxOwnedBytes#
pub maxOwnedBytes: usizeThe maximum memory of the parser: maxHeadBytes plus 32 bytes for each field in
values.maxFields.
Field values#
pub values: ValueLimitsThe limits for the method, target, names, values, and field count.
Implementation Copy for Limits#
impl Copy for LimitsProgressState#
pub enum ProgressStateWhether a head is complete after a feed.
NeedInput#
NeedInputThe head is not complete. Feed more bytes.
Complete#
CompleteThe empty line at the end was read. Get the head with head.
Progress#
pub struct ProgressThe result of a successful feed.
Field consumed#
pub consumed: usizeThe 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#
pub state: ProgressStateWhether the head is complete.
Implementation Copy for Progress#
impl Copy for ProgressParserState#
pub enum ParserStateThe state of a parser.
Active#
ActiveThe parser takes more input.
Complete#
CompleteA head is complete. Call reset before you parse the next head.
Failed#
FailedA parse failed. Get the error with failure, and call reset to use the parser again.
ParseComponent#
pub enum ParseComponentThe part of a head where a parse failed.
Parser#
ParserThe parser itself, for example its limits or its state.
StartLine#
StartLineRequest or response start line as a whole.
Version#
VersionHTTP version token.
Method#
MethodRequest method token.
Target#
TargetRequest target.
Status#
StatusResponse status digits or range.
ReasonPhrase#
ReasonPhraseResponse reason phrase.
HeaderName#
HeaderNameField name.
HeaderValue#
HeaderValueA field value, without the spaces around it.
Host#
HostThe Host field.
LineEnding#
LineEndingA line ending.
Implementation Debug for ParseComponent#
impl Debug for ParseComponentOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as Parser.
ParseLimitKind#
pub enum ParseLimitKindThe limit that a head exceeded. See ParseReason.LimitExceeded.
HeadBytes#
HeadBytesmaxHeadBytes.
StartLineBytes#
StartLineBytesmaxStartLineBytes.
FieldLineBytes#
FieldLineBytesmaxFieldLineBytes.
Fields#
FieldsmaxFields: the number of fields, including repeated fields.
MethodBytes#
MethodBytesmaxMethodBytes.
TargetBytes#
TargetBytesmaxTargetBytes.
NameBytes#
NameBytesmaxNameBytes.
ValueBytes#
ValueBytesmaxValueBytes, for a field value or the reason phrase.
FieldBytes#
FieldBytesmaxFieldBytes: the total length of all names and values.
OwnedBytes#
OwnedBytesmaxOwnedBytes: the memory of the parser.
Implementation Debug for ParseLimitKind#
impl Debug for ParseLimitKindOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as HeadBytes.
ParseReason#
pub union ParseReasonThe rule that a parse or a write failed.
InvalidStartLine#
InvalidStartLineThe 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#
UnsupportedVersionA version is not exactly HTTP/1.0 or HTTP/1.1.
InvalidMethod#
InvalidMethodA request method is not a nonempty HTTP token.
InvalidTarget#
InvalidTargetThe request target is not valid, or its form does not fit the method.
InvalidStatus#
InvalidStatusThe status is not three digits from 100 to 599.
InvalidReasonPhrase#
InvalidReasonPhraseThe reason phrase has a control byte or DEL.
InvalidFieldName#
InvalidFieldNameA field name is empty, or has a byte that is not allowed in a token.
InvalidFieldValue#
InvalidFieldValueA field value has a byte that is not allowed.
BareLf#
BareLfA line ends with LF without CR.
InvalidLineEnding#
InvalidLineEndingA CR is not followed by LF.
WhitespaceBeforeColon#
WhitespaceBeforeColonA field has a space or a tab between its name and the :.
ObsFold#
ObsFoldA 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#
MissingHostAn HTTP/1.1 request has no Host field.
DuplicateHost#
DuplicateHostA request has more than one Host field.
InvalidHost#
InvalidHostThe Host field is not a valid authority.
LimitExceeded#
LimitExceededThe head exceeded a limit.
Field limit#
pub limit: ParseLimitKindThe limit that was exceeded.
Field allowed#
pub allowed: usizeThe value of the limit.
Field attempted#
pub attempted: usizeThe size that was found.
SizeOverflow#
SizeOverflowA size calculation overflowed usize.
Truncated#
TruncatedThe input ended, with final set to true, before the head was complete.
InvalidState#
InvalidStateThe call is not valid in the current ParserState, for example feed after a complete
head.
Implementation Copy for ParseReason#
impl Copy for ParseReasonImplementation Debug for ParseReason#
impl Debug for ParseReasonOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant and its fields, such as InvalidStartLine.
ParseError#
pub struct ParseErrorThe 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#
pub reason: ParseReasonThe rule that failed.
Field component#
pub component: ParseComponentThe part of the head that failed.
Field consumed#
pub consumed: usizeThe number of bytes of this call that were valid before the error.
Field offset#
pub offset: usizeThe byte offset in the head where the error is, from the start of the head.
Field fieldIndex#
pub fieldIndex: Option<usize>The position of the field, from 0, when the error is in a field.
Implementation Debug for ParseError#
impl Debug for ParseErrorOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the fields, as ParseError { reason: ..., component: ..., ... }.
validateLimits#
pub fn validateLimits(limits: &Limits) -> Result<(), ParseError>Checks that limits are consistent, without allocation.
Errors#
LimitExceededwithOwnedBytesifmaxOwnedBytesis less thanmaxHeadBytesplus 32 bytes for each field.SizeOverflowif that sum does not fit inusize.
RequestParser#
pub struct RequestParserA 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#
pub struct ResponseParserA 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#
pub struct RequestHead<'owner>A parsed request head. It borrows its parser.
Implementation Copy for RequestHead<'owner>#
impl<'owner> Copy for RequestHead<'owner>ResponseHead#
pub struct ResponseHead<'owner>A parsed response head. It borrows its parser.
Implementation Copy for ResponseHead<'owner>#
impl<'owner> Copy for ResponseHead<'owner>HeaderIterator#
pub struct HeaderIterator<'owner>An iterator over the fields of a parsed head, in order.
ParsedRequest#
pub struct ParsedRequestThe result of parseRequest.
Field parser#
pub parser: RequestParserThe parser that holds the head. Get the head with RequestParser.head.
Field progress#
pub progress: ProgressHow many bytes the head used. The bytes after it, such as the body, start at
progress.consumed.
ParsedResponse#
pub struct ParsedResponseThe result of parseResponse.
Field parser#
pub parser: ResponseParserThe parser that holds the head. Get the head with ResponseParser.head.
Field progress#
pub progress: ProgressHow many bytes the head used. The bytes after it, such as the body, start at
progress.consumed.
Implementation RequestParser#
impl RequestParserAssociated function make#
pub effect fn make(limits: Limits) -> Result<RequestParser, ParseError>
! OutOfMemoryError
? &mut AllocatorReturns a parser, and allocates all its memory.
Errors#
ParseErrorifvalidateLimitsfails.OutOfMemoryErrorif theAllocatorfails.
Method feed#
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#
pub fn state(self: &Self) -> ParserStateReturns the state of the parser.
Method failure#
pub fn failure(self: &Self) -> Option<ParseError>Returns the error that made the parser fail, or None.
Method head#
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#
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#
impl ResponseParserAssociated function make#
pub effect fn make(limits: Limits) -> Result<ResponseParser, ParseError>
! OutOfMemoryError
? &mut AllocatorReturns a parser, and allocates all its memory.
Errors#
ParseErrorifvalidateLimitsfails.OutOfMemoryErrorif theAllocatorfails.
Method feed#
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#
pub fn state(self: &Self) -> ParserStateReturns the state of the parser.
Method failure#
pub fn failure(self: &Self) -> Option<ParseError>Returns the error that made the parser fail, or None.
Method head#
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#
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>#
impl<'owner> RequestHead<'owner>Method version#
pub fn version(self: &Self) -> VersionReturns the parsed protocol version.
Method method#
pub fn method(self: &Self) -> Method<'owner>Returns the method, spelled as received.
Method target#
pub fn target(self: &Self) -> RequestTarget<'owner>Returns the request target.
Method fieldCount#
pub fn fieldCount(self: &Self) -> usizeReturns the number of fields, including duplicates.
Method fields#
pub fn fields(self: &Self) -> HeaderIterator<'owner>Returns an iterator over the fields, in order. Repeated fields stay separate.
Method copy#
pub effect fn copy(
self: &Self,
limits: ValueLimits,
) -> Result<OwnedRequestHead, ValueError> ! OutOfMemoryError ? &mut AllocatorCopies the head into new memory, as an owned head from silk.http.message.
Errors#
ValueErrorif the head exceedslimits.OutOfMemoryErrorif theAllocatorfails.
Implementation ResponseHead<'owner>#
impl<'owner> ResponseHead<'owner>Method version#
pub fn version(self: &Self) -> VersionReturns the parsed protocol version.
Method status#
pub fn status(self: &Self) -> StatusReturns the status.
Method reason#
pub fn reason(self: &Self) -> &'owner [u8]Returns the reason phrase bytes. They can be empty, and are not always UTF-8.
Method fieldCount#
pub fn fieldCount(self: &Self) -> usizeReturns the number of fields, including duplicates.
Method fields#
pub fn fields(self: &Self) -> HeaderIterator<'owner>Returns an iterator over the fields, in order. Repeated fields stay separate.
Method copy#
pub effect fn copy(
self: &Self,
limits: ValueLimits,
) -> Result<OwnedResponseHead, ValueError> ! OutOfMemoryError ? &mut AllocatorCopies the head into new memory, as an owned head from silk.http.message.
Errors#
ValueErrorif the head exceedslimits.OutOfMemoryErrorif theAllocatorfails.
Method copyMatchingHeaders#
pub effect fn copyMatchingHeaders<'name>(
self: &Self,
name: string<'name>,
limits: ValueLimits,
) -> Result<OwnedResponseHead, ValueError> ! OutOfMemoryError ? &mut AllocatorCopies 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>#
impl<'owner> HeaderIterator<'owner>Method next#
pub fn next(self: &mut Self) -> Option<Header<'owner>>Returns the next validated field, or None after the final field.
Method fieldIndex#
pub fn fieldIndex(self: &Self) -> usizeReturns the position of the last field from HeaderIterator.next, from 0.
parseRequest#
pub effect fn parseRequest(
input: &[u8],
limits: Limits,
) -> Result<ParsedRequest, ParseError> ! OutOfMemoryError ? &mut AllocatorParses 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#
pub effect fn parseResponse(
input: &[u8],
limits: Limits,
) -> Result<ParsedResponse, ParseError> ! OutOfMemoryError ? &mut AllocatorParses 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#
pub fn requestSerializedSize<'value>(
head: &ValueRequestHead<'value>,
limits: ValueLimits,
) -> Result<usize, ValueError>Returns the number of bytes that writeRequestInto writes for head.
responseSerializedSize#
pub fn responseSerializedSize<'value>(
head: &ValueResponseHead<'value>,
limits: ValueLimits,
) -> Result<usize, ValueError>Returns the number of bytes that writeResponseInto writes for head.
writeRequestInto#
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#
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.