silk.http.transport.
The byte transport under an HTTP connection: plain bytes or TLS.
When to use#
silk.http.exchange reads and writes through the HttpTransport service. Use plain to
use a byte duplex, such as a TCP socket, as the transport. Use secured to use a TLS
connection. Implement HttpTransport yourself for a custom transport, for example in tests.
Details#
plain, secured, and borrow borrow a provider. They do not allocate or do I/O. The
caller keeps ownership of the provider.
HttpTransport.readSome and HttpTransport.writeSome check the counts of the provider. A
count of zero, or more than the buffer, closes the transport and fails. An empty buffer returns
zero at once, and does not call the provider.
Each operation gets an absolute deadline, and passes it to the provider unchanged.
Errors#
TransportError keeps the original error: Plain for a byte duplex error, Secured for a
TLS error.
Gotchas#
closecloses the provider: the socket forplain, the TLS connection forsecured. It does not flush. A second call does nothing.After
close, each read, write, or flush fails with aClosederror.
Examples#
Write and read over a memory duplex#
import silk.mem.allocator { Allocator, OutOfMemoryError }
import silk.io.byte_duplex { ReadTransfer }
import silk.collections.bytes { Bytes }
import silk.core.effect { Effect }
import silk.http.transport { HttpTransport, TransportError, plain }
import silk.collections.list { List }
import silk.io.memory_byte_duplex {
MemoryByteDuplex,
MemoryReadEvent,
MemoryWriteAction,
MemoryWriteEvent
}
import silk.system.monotonic_clock { MonotonicClock }
import silk.core.option { Option }
import silk.system.random { Random }
import silk.core.result { Result }
import silk.system.system_clock { Instant, SystemClock }
import silk.num.u64
struct FixedClock {}
impl MonotonicClock for FixedClock {
effect fn now(self: &mut Self) -> Instant {
return SystemClock.make(0, 0)
}
effect fn getResolution(self: &mut Self) -> u64 {
return u64.toU64(1)
}
effect fn waitUntil(self: &mut Self, when: Instant) -> () {
drop when
return ()
}
effect fn waitFor(self: &mut Self, howLong: u64) -> () {
drop howLong
return ()
}
}
struct ZeroRandom {}
impl Random for ZeroRandom {
effect fn fillBytes(self: &mut Self, output: &mut [u8]) -> () {
drop output
return ()
}
}
// Writes a ping, reads the reply, and closes the transport.
effect fn exchange() -> i32
! TransportError | OutOfMemoryError
? &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut Random {
let written = run HttpTransport.writeSome(b"ping", Option<Instant>.none())
if written != 4 {
return 1
}
run HttpTransport.flush(Option<Instant>.none())
let mut reply: [u8; 8] = [0; 8]
let count = match run HttpTransport.readSome(&mut reply, Option<Instant>.none()) {
ReadTransfer.Data { count } => count
ReadTransfer.End => {
return 1
}
}
if count != 4 || reply[0] != 112 {
return 1
}
run HttpTransport.close()
// A second close does nothing.
run HttpTransport.close()
return 0
}
effect fn program() -> i32
! TransportError | OutOfMemoryError
? &mut MonotonicClock | &mut Allocator | &mut Random {
let reply = run Bytes.copy(b"pong")
let mut reads = List<MemoryReadEvent>.make()
run List.append(
&mut reads,
MemoryReadEvent.Data { readyAt: SystemClock.make(0, 0), bytes: move reply }
)
let mut writes = List<MemoryWriteEvent>.make()
run List.append(
&mut writes,
MemoryWriteEvent {
readyAt: SystemClock.make(0, 0),
action: MemoryWriteAction.Accept { count: 64 }
},
)
let mut memory = run MemoryByteDuplex.make(move reads, move writes, 64, 8, Option<i32>.none())
let mut transport = plain(&mut memory)
let result = run exchange() |> Effect.provideMut<HttpTransport>(&mut transport)
drop transport
if MemoryByteDuplex.closeAttempts(&memory) != 1 {
return 1
}
return result
}
effect fn failed<E>(error: E) -> i32 {
drop error
return 1
}
pub fn main() -> i32 {
let mut allocator = Allocator.systemAllocatorProvider()
let mut clock = FixedClock {}
let mut random = ZeroRandom {}
return run Effect.catchAll(program(), failed) |> Effect.provideMut<Random>(&mut random)
|> Effect.provideMut<MonotonicClock>(&mut clock)
|> Effect.provideMut<Allocator>(&mut allocator)
}Import as HttpTransport with import silk.http.transport { HttpTransport }.
Public declarations: 8.
TransportError#
pub union TransportErrorThe error of a transport operation, with its original cause: Plain for a byte duplex error,
Secured for a TLS error.
Plain#
PlainThe byte duplex failed.
Field error#
pub error: ByteIoErrorThe error of the byte duplex.
Secured#
SecuredThe TLS connection failed.
Field error#
pub error: ConnectionErrorThe error of the TLS connection.
Implementation Debug for TransportError#
impl Debug for TransportErrorOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant and its fields, such as Plain { ... }.
HttpTransport#
pub service HttpTransportReads and writes the bytes of an HTTP connection.
Call HttpTransport.readSome and HttpTransport.writeSome, not the raw operations. They
check the counts of the provider: a count of zero, or more than the buffer, closes the transport
and fails. Each operation gets an absolute deadline, and passes it to the provider unchanged.
Use plain for a byte duplex, such as a TCP socket, or secured for a TLS connection.
Gotchas#
close closes the provider: the socket for plain, the TLS connection for secured. It
does not flush. After close, each read, write, or flush fails with a Closed error.
Operation readSomeRaw#
unsafe effect fn readSomeRaw(output: &mut [u8], deadline: Option<Instant>) -> ReadTransfer ! TransportError | OutOfMemoryError ? &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut RandomReads bytes from the provider into output. It is unsafe because it does not check the count.
Use HttpTransport.readSome.
Operation writeSomeRaw#
unsafe effect fn writeSomeRaw(input: &[u8], deadline: Option<Instant>) -> usize ! TransportError | OutOfMemoryError ? &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut RandomWrites bytes from input to the provider. It is unsafe because it does not check the count.
Use HttpTransport.writeSome.
Operation flush#
effect fn flush(deadline: Option<Instant>) -> () ! TransportError | OutOfMemoryError ? &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut RandomSends all bytes that writes accepted to the provider.
Operation close#
effect fn close() -> () ! TransportError ? &mut HttpTransportCloses the transport without waiting. A second call does nothing. It does not flush. After it,
each read, write, or flush fails with a Closed error.
Implementation HttpTransport#
impl HttpTransportAssociated function readSome#
pub effect fn readSome(output: &mut [u8], deadline: Option<Instant>) -> ReadTransfer
! TransportError | OutOfMemoryError
? &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut RandomReads at least one byte into the start of output, or returns End.
If output is empty, it returns zero bytes at once. If the provider reports zero bytes, or
more than output.length, the transport is closed and the read fails.
Associated function writeSome#
pub effect fn writeSome(input: &[u8], deadline: Option<Instant>) -> usize
! TransportError | OutOfMemoryError
? &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut RandomWrites at least one byte from the start of input, and returns the count.
The count can be less than input.length. If input is empty, it returns zero at once. If
the provider reports zero, or more than input.length, the transport is closed and the write
fails.
Plain#
pub struct Plain<'provider, P>A transport over a byte duplex. Make it with plain.
Secured#
pub struct Secured<'provider, P>A transport over a TLS connection. Make it with secured.
plain#
pub fn plain<'provider, P>(provider: &'provider mut P) -> Plain<'provider, P>Uses the byte duplex provider as a transport. It does not allocate or do I/O. The caller keeps
ownership of provider. Closing the transport closes the byte duplex.
secured#
pub fn secured<'provider, P>(provider: &'provider mut OwnedConnection<P>) -> Secured<'provider, P>Uses the TLS connection provider as a transport. It does not allocate or do I/O. The caller
keeps ownership of provider. Closing the transport closes the TLS connection.
Implementation Plain<'provider, P>#
impl<'provider, P> Plain<'provider, P>Implementation HttpTransport for Plain<'provider, P>#
impl<'provider, P> HttpTransport for Plain<'provider, P>
where
&mut P provides &ByteDuplex from &mut ByteDuplex,
&mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock,
&mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock | &mut Allocator | &mut RandomOperation readSomeRaw#
readSomeRaw: Plain.readOperation writeSomeRaw#
writeSomeRaw: Plain.writeOperation flush#
flush: Plain.flushOutputOperation close#
close: Plain.closeLeaseImplementation Secured<'provider, P>#
impl<'provider, P> Secured<'provider, P>Implementation HttpTransport for Secured<'provider, P>#
impl<'provider, P> HttpTransport for Secured<'provider, P>
where
&mut P provides &ByteDuplex from &mut ByteDuplex,
&mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock,
&mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock | &mut Allocator | &mut RandomOperation readSomeRaw#
readSomeRaw: Secured.readOperation writeSomeRaw#
writeSomeRaw: Secured.writeOperation flush#
flush: Secured.flushOutputOperation close#
close: Secured.closeLeaseLoan#
pub struct Loan<'provider, P>A transport that borrows another transport. Make it with borrow.
Closing the loan closes the transport that it borrows.
borrow#
pub fn borrow<'provider, P>(provider: &'provider mut P) -> Loan<'provider, P>Borrows the transport provider as a Loan. It does not allocate or do I/O.
Implementation Loan<'provider, P>#
impl<'provider, P> Loan<'provider, P>Implementation HttpTransport for Loan<'provider, P>#
impl<'provider, P> HttpTransport for Loan<'provider, P>
where
&mut P provides &HttpTransport from &mut HttpTransport,
&mut P provides &HttpTransport from &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut RandomOperation readSomeRaw#
readSomeRaw: Loan.readOperation writeSomeRaw#
writeSomeRaw: Loan.writeOperation flush#
flush: Loan.flushOutputOperation close#
close: Loan.closeLeaseImplementation ByteDuplex for Loan<'provider, P>#
impl<'provider, P> ByteDuplex for Loan<'provider, P>
where
&mut P provides &ByteDuplex from &mut ByteDuplex,
&mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClockOperation readSomeRaw#
readSomeRaw: Loan.readBytesOperation writeSomeRaw#
writeSomeRaw: Loan.writeBytesOperation writeSomeVectoredRaw#
writeSomeVectoredRaw: Loan.writeBytesVectoredOperation flushRaw#
flushRaw: Loan.flushBytesOperation shutdownWriteRaw#
shutdownWriteRaw: Loan.shutdownBytesOperation closeRaw#
closeRaw: Loan.closeBytesCategory: 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.