///|
pub fn RuntimeResponse::is_cache_reuse(self : RuntimeResponse) -> Bool {
self.source is CacheSource ||
self.source is RevalidatedSource ||
self.source is StaleSource
}
///|
fn response_headers_to_json(headers : HeaderMap) -> Json {
let object : Map[String, Json] = Map([])
let safe = headers.redacted()
for name in safe.names() {
let values = safe.get_all(name)
if values.length() == 1 {
object[name] = Json::string(values[0])
} else {
object[name] = Json::array(values.map(fn(value) { Json::string(value) }))
}
}
Json::object(object)
}
///|
/// Structured runtime report. Response bodies are deliberately excluded;
/// their size is enough for diagnostics and cannot leak cached content.
pub fn RuntimeResponse::to_json(self : RuntimeResponse) -> Json {
Json::object({
"source": self.source.label(),
"status": self.meta.status,
"headers": response_headers_to_json(self.meta.headers),
"body_bytes": self.body.length(),
"body_complete": self.meta.body_complete,
"cache_reuse": self.is_cache_reuse(),
"trace": self.trace.to_json(),
})
}
///|
pub fn RuntimeResponse::json_report(self : RuntimeResponse) -> String {
self.to_json().stringify(indent=2)
}
///|
pub fn RuntimeResponse::text_report(self : RuntimeResponse) -> String {
let lines = [
"Source: \{self.source.label()}",
"Status: \{self.meta.status}",
"Body bytes: \{self.body.length()}",
"Body complete: \{self.meta.body_complete}",
]
for pair in self.meta.headers.redacted().pairs() {
lines.push("Response header: \{pair.0}: \{pair.1}")
}
lines.push(self.trace.text_report())
lines.join("\n")
}