HTTP: Sessions
● Intermediate2 min
http.open keeps one connection open for many requests, instead of connecting again for each.
use std.http
use std.net
fn api(r: Request) -> Response {
http.text(200, "{r.method} {r.path}")
}
fn main() ! Error {
const listener = try net.listen("127.0.0.1:0")
const _server = spawn http.serve(listener, api)
const session = try http.open("http://{listener.address()}")
for path in ["/users/1", "/users/2"] {
const reply = try session.get(path)
print(reply.body.text() ?? "")
}
const made = try session.post("/users", "Asha".bytes())
print(made.body.text() ?? "")
session.close()
}The program ran and printed:
kavach run session.kav
GET /users/1GET /users/2POST /users
Requests on a session go one after another, each waiting for its answer. A session is for one task at a time: give each task its own, so no task reads another's answer.
One HTTP/2 connection for many tasks
A service that speaks HTTP/2 itself, as gRPC does, connects once with h2.connect from std.http.h2. Several tasks can share the H2Client it gives: each request is on a stream of its own, all open at once, and each answer goes to the task that asked, in whatever order the server sends them.
use std.http
use std.http.h2
use std.net
fn hello(r: Request) -> Response {
http.text(200, "{r.method} {r.path}")
}
fn ask(c: H2Client, path: String) -> String ! H2Error uses Net {
const reply = try c.request([
Header(name: ":method", value: "GET"),
Header(name: ":scheme", value: "http"),
Header(name: ":authority", value: "localhost"),
Header(name: ":path", value: path),
], Bytes([]))
reply.body.text() ?? "?"
}
fn main() ! Error {
const listener = try net.listen("127.0.0.1:0")
const _server = spawn http.serve(listener, hello)
const c = try h2.connect(try net.connect(listener.address()))
print(try ask(c, "/orders"))
const tasks = [spawn ask(c, "/stock"), spawn ask(c, "/prices")]
for t in tasks {
print(try t.wait())
}
print("going away: {c.going_away()}")
c.close()
print(ask(c, "/late") catch e => "{e}")
}The program ran and printed:
kavach run h2-client.kav
GET /ordersGET /stockGET /pricesgoing away: falseProtocol(reason: "the client was closed")
| Function | Gives |
|---|---|
h2.connect(conn) -> H2Client ! H2Error | Starts a connection that takes many requests, so a service connects once instead of once per call |
c.request(headers, body) -> H2Message ! H2Error | Sends one request on c, on a stream of its own, and reads its response. Requests from several tasks are open at once: their sends take turns, in the order they asked, and each answer goes to the task that asked, in whatever order the server sends them. A stream the server resets fails only its own request |
c.going_away() -> Bool | Whether the server said it is going away (GOAWAY) or the connection broke: a pool replaces such a client with a new one |
c.close() | Closes the connection once the request being answered is done; a request after it fails with Protocol. A client is also closed when its last holder lets it go, as its connection is (14.10) |
- A pool replaces a client whose
going_away()is true: the server sent GOAWAY, or the connection broke. - After
close(), a request fails withProtocol. - A stream the server resets fails only its own request.