Repository navigation
colibri 0.9.0: routes, queries, one set of HTTP names, and TLS alerts
colibri 0.9.0 gives the server's router a program's functions and middleware, gives a request its query, names each HTTP concept once in the server and the client, and lets a TLS record session send a fatal alert the program names. The client's connection pool opens TCP connections on demand. It pins chapulin 1f3a99cb and stdx 5fd03aa.
Breaking changes
- One name for each HTTP concept in
serverandclient(decision 126):server.BodyisRequestBody,server.ContentisResponseBody, and the client'sRequest.contentisbody.Fields,FieldandFieldSectionareHeadersandHeader, andfieldsisheaders.Trailersholdsheaders: Headers,WantedisWantedHeader, andNeverIndexed.fieldsisheaders.- The server's
doneandcancelledevents are onefinishedevent with an outcome, on both sides.RequestIdnames a request on both sides. VersionsisProtocols,DeadlinesandDeadlineareTimeoutsandTimeout, and the close reasondeadlineistimeout.client.Channelisclient.ConnectionPool, andChannelOfisConnectionPoolOf.client.HttpsisHttpsRecord,client.ValuesisDestination, andset_valuesisset_destination.client.Optionsfolds intoConfig:memory_bytes(config)andinit(memory, config, destination).- Names say bytes, not octets:
StreamOctetsisStreamBytes.ReceivedisReceiveResult, andaccept(Security)takestls: bool. - Decision 126 holds the whole table.
- The client's connection pool opens TCP connections on demand and holds its connections and requests in memory the program places (decision 125). Each event and call about a connection names a
ConnectionHandle, and asendevent names a TCP connection that owes bytes. The counts say requests:Config.requests,constants.requests_maxandpool_requests_max. - A request's query is apart from its path (decision 127):
Request.pathholds no query, andRequest.queryholds the raw query or null.http.QueryParametersreads itsname=valuepairs, from the WHATWG URL Standard. The router percent-decodes each path segment and takes%. A segment that encodes/,\or NUL getsnot_found. server.router(Context, table)replacesrouter(Value, table)(decision 127). The table is.{ .error_handler, .middleware, .routes }. A route holds a function, which takes typed path and query structs, or a struct withon_request,on_body,on_writable,on_finishedand aState.Router.Of(options)sizes the router's pool, andhandle(context, endpoint, event)drives it. New names:server.ResponseWriter,server.Handledandserver.middleware.Next.matchgives aRoutetag.- A route table's walk backs up past a leaf that does not serve the method (decision 128), so a table such as
/v1/charges/searchbeside/v1/charges/:chargecompiles, androute_hiddenis gone. A 405'sAllowlists the methods of every leaf the path reaches, so its value can grow. A table that names more thanserver.constants.route_methods_max(10) methods does not compile. - chapulin
50d7d17banswers a KeyUpdate with its next record of data.tls_provider.Content.new_session_ticketand.key_updateare.without_data, and h2's and h11'sDecrypted.owes_handshakeis gone. More than 16 KeyUpdates in a run close the connection:OpenError.KeyUpdates,h2.Limit.key_updatesandserver.Limit.key_updatesare new, andtls.constants.key_update_replies_maxis removed. A program with its owntls_providerfollows the new contract. - stdx's
platform.Cpuholdssha256,sha512,sha3,ssse3andsse4_1, with no default. A program that writes aplatform.Cpuliteral states them. One that callsplatform.probe()changes nothing.
What's new
tls.record.Client.failandtls.record.Server.failsend the fatal alert the program names, for an error it found itself, such as a record longer than RFC 9846 §5.2 allows. They take the error alerts of RFC 9846 §6.2 alone, on a connected session, and fail the session. A refused call returns atls.record.FailErrorand leaves the session as it was (#114).- Middleware may wrap a body's reader and writer:
State,wrap_body,wrap_responseandfinish_response. - Each route names its own parameters, so two routes may name one position differently (decision 129).
- On arm64, a session runs the SHA instructions where the probe has them and the timing is stated as data-independent.
Fixes
- chapulin
1f3a99cbsends record_overflow before it decrypts a record longer than RFC 9846 §5.1 or §5.4 allows, or longer than the record_size_limit this side sent (RFC 8449 §4). Each TLS session over TCP grows 8 bytes. - A server sends
record_size_limitonly to a client that offered it (chapulina6703587, RFC 9846 §4.3). Clients on rustls refused it before. - h11's
write_responsereturnsFramingInvalidfor a bad Content-Length, where it panicked.
Speed
No API change. Against the competitors' run of 2026-10-20, per request or connection, kernel and user together, on the arm64 judge:
- A TLS handshake costs about half: h11-tls-one, h2-tls-one and h3-one fall 48%, 47% and 59%.
- h2-many falls 7%, h11-many 11%, and h11-tls-many 20%.
- The router matches a path in one pass: h2-routes-many, which routes each request over the GitHub API's GET routes, falls 4% (ratio 0.960 in two judge runs).
Checked
GitHub's main workflow passed on bf4fe21f (run 40828900211).