///|
/// Split a raw HTTP request-target into its path and query string.
///
/// Routes match against the path; the query is retained separately on the
/// `HttpRequest`. A `#fragment` is never used for routing, so it is stripped
/// from the query rather than exposed.
fn split_request_target(target : String) -> (String, String) {
let (path, rest) = match target.find("?") {
Some(q) => (target[:q].to_owned(), target[q + 1:].to_owned())
None => (target, "")
}
let query = match rest.find("#") {
Some(f) => rest[:f].to_owned()
None => rest
}
(path, query)
}
///|
/// Whether a request carries a body: POST/PUT/PATCH always may, and any
/// method with an explicit (non-empty) `content-length` or a
/// `transfer-encoding` (i.e. chunked) frame is treated as having a body.
/// The same rule is used by every backend so bodies are read consistently.
fn request_has_body(
http_method : String,
headers : Map[@http.CaseInsensitiveString, StringView],
) -> Bool {
match http_method {
"POST" | "PUT" | "PATCH" => true
_ =>
headers.get("transfer-encoding") is Some(_) ||
headers
.get("content-length")
.map(value => value.to_owned().trim() != "0")
.unwrap_or(false)
}
}
///|
pub async fn dispatch_http(
mocket : Mocket,
http_method : String,
url : String,
headers : Map[@http.CaseInsensitiveString, StringView],
raw_body : Bytes,
) -> HttpResponse {
let (path, query) = split_request_target(url)
let (params, handler) = match mocket.find_route(http_method, path) {
Some((h, p)) => (p, h)
_ => ({}, handle_not_found())
}
let event = {
req: { http_method, url: path, query, raw_body, headers },
res: HttpResponse::new(OK),
params,
}
let responder = mocket.execute_middlewares(event, handler) catch {
err => {
if @async.is_cancellation_error(err) {
raise err
}
mocket.handle_request_error(event, err)
}
}
responder.options(event.res)
let buf = Buffer()
responder.output(buf)
event.res.raw_body = buf.to_bytes()
event.res
}