///|
/// HTTP Request representation
pub(all) struct Request {
http_method : String
uri : String
version : String
headers : Array[(String, String)]
body : Array[Byte]
} derive(Show, Eq)
///|
pub fn Request::new(http_method : String, uri : String) -> Request {
{ http_method, uri, version: "HTTP/1.1", headers: [], body: [] }
}
///|
pub fn Request::with_version(
http_method : String,
uri : String,
version : String,
) -> Request {
{ http_method, uri, version, headers: [], body: [] }
}
///|
pub fn Request::header(
self : Request,
name : String,
value : String,
) -> Request {
let new_headers = []
for h in self.headers {
new_headers.push(h)
}
new_headers.push((name, value))
{ ..self, headers: new_headers }
}
///|
pub fn Request::body(self : Request, body : Array[Byte]) -> Request {
{ ..self, body, }
}
///|
pub fn Request::get_header(self : Request, name : String) -> String? {
let lower_name = request_string_to_lower(name)
let mut idx = 0
while idx < self.headers.length() {
let (key, value) = self.headers[idx]
if request_string_to_lower(key) == lower_name {
return Some(value)
}
idx = idx + 1
}
None
}
///|
pub fn Request::has_header(self : Request, name : String) -> Bool {
let lower_name = request_string_to_lower(name)
let mut idx = 0
while idx < self.headers.length() {
let (key, _) = self.headers[idx]
if request_string_to_lower(key) == lower_name {
return true
}
idx = idx + 1
}
false
}
///|
pub fn Request::is_keep_alive(self : Request) -> Bool {
if self.version == "HTTP/1.1" {
match self.get_header("connection") {
Some(v) => request_string_to_lower(v) != "close"
None => true
}
} else if self.version == "HTTP/1.0" {
match self.get_header("connection") {
Some(v) => request_string_to_lower(v) == "keep-alive"
None => false
}
} else {
false
}
}
///|
pub fn Request::content_length(self : Request) -> Int? {
match self.get_header("content-length") {
Some(v) => request_parse_int(v)
None => None
}
}
///|
pub fn Request::is_chunked(self : Request) -> Bool {
match self.get_header("transfer-encoding") {
Some(v) => request_string_to_lower(v) == "chunked"
None => false
}
}
///|
pub fn Request::http_method(self : Request) -> String {
self.http_method
}
///|
fn request_string_to_lower(s : String) -> String {
let mut result = ""
let mut idx = 0
while idx < s.length() {
let c = s[idx]
let ci = c.to_int()
let new_c = if ci >= 65 && ci <= 90 {
Int::unsafe_to_char(ci + 32).to_string()
} else {
c.to_string()
}
result = result + new_c
idx = idx + 1
}
result
}
///|
fn request_parse_int(s : String) -> Int? {
let mut result = 0
let mut idx = 0
let len = s.length()
if len == 0 {
return None
}
while idx < len {
let c = s[idx]
let ci = c.to_int()
if ci >= 48 && ci <= 57 {
result = result * 10 + (ci - 48)
} else {
return None
}
idx = idx + 1
}
Some(result)
}