///|
/// A single HTTP request to a Consul agent: the verb, the full URL (scheme,
/// address, path and query already joined), the request headers, and the body
/// for writes. The transport owns the socket and the TLS configuration.
pub(all) struct Request {
verb : String
url : String
headers : Map[String, String]
body : Bytes
}
///|
/// A request with no headers and an empty body.
pub fn Request::new(verb : String, url : String) -> Request {
{ verb, url, headers: Map([]), body: b"", }
}
///|
/// A request with `headers` and `body`.
pub fn Request::new_full(
verb : String,
url : String,
headers : Map[String, String],
body : Bytes,
) -> Request {
{ verb, url, headers, body, }
}
///|
/// A Consul agent's HTTP response: the status code, the response headers (the
/// blocking-query metadata rides on `X-Consul-Index` and its siblings), and the
/// raw body bytes.
pub(all) struct Response {
status : Int32
headers : Map[String, String]
body : Bytes
}
///|
/// A response carrying `status` and `body`, with no headers.
pub fn Response::new(status : Int32, body : Bytes) -> Response {
{ status, headers: Map([]), body, }
}
///|
/// A response carrying `status`, `headers` and `body`.
pub fn Response::new_full(
status : Int32,
headers : Map[String, String],
body : Bytes,
) -> Response {
{ status, headers, body, }
}
///|
/// A response header by name, case-insensitively (HTTP header names are not
/// case-sensitive; Consul spells them `X-Consul-Index` and friends).
pub fn Response::header(self : Response, name : String) -> String? {
match self.headers.get(name) {
Some(v) => Some(v)
None => {
let lower = name.to_lower()
let mut found : String? = None
for k, v in self.headers {
if k.to_lower() == lower {
found = Some(v)
break
}
}
found
}
}
}
///|
/// The HTTP medium a `Client` drives. It performs one request and returns the
/// response, or raises `Refused` on a transport failure. The production client
/// plugs an HTTP-backed transport in here; tests plug an in-memory fake that
/// returns canned responses, so the request shaping and JSON parsing run
/// against a real agent's wire format without a network.
pub(open) trait Transport {
async fn send(self : Self, Request) -> Response raise Refused
}