///|
pub struct Request {
verb : String
uri : String
headers : Headers
body : Bytes
}
///|
pub struct Response {
status : Int32
reason : String
headers : Headers
body : Bytes
}
///|
pub fn Request::new(
verb : String,
uri : String,
cseq : Int32,
body~ : Bytes = b"",
) -> Request raise RtspError {
require(verb.length() > 0 && verb.length() <= 32, "verb length")
for c in verb {
require((c >= 'A' && c <= 'Z') || c == '_', "verb token")
}
ignore(Endpoint::parse(uri))
require(cseq > 0, "positive CSeq")
require(body.length() <= 1048576, "body limit")
let headers = Headers::new()
headers.add("CSeq", cseq.to_string())
headers.add("User-Agent", "MoonRTSP/0.1.0")
{ verb, uri, headers, body, }
}
///|
pub fn Request::encode(self : Request) -> Bytes raise RtspError {
// Revalidate public fields and headers at serialization boundary.
ignore(Request::new(self.verb, self.uri, self.cseq(), body=self.body))
let headers = self.headers.copy()
if self.body.length() > 0 {
headers.set("Content-Length", self.body.length().to_string())
} else {
headers.set("Content-Length", "0")
}
octets(self.verb + " " + self.uri + " RTSP/1.0\r\n" + headers.wire() + "\r\n") +
self.body
}
///|
pub fn Request::cseq(self : Request) -> Int32 raise RtspError {
match self.headers.unique("CSeq") {
Some(v) => number(v, 2147483647)
None => raise Invalid("missing CSeq")
}
}
///|
pub fn Response::cseq(self : Response) -> Int32 raise RtspError {
match self.headers.unique("CSeq") {
Some(v) => number(v, 2147483647)
None => raise Invalid("missing CSeq")
}
}
///|
pub fn Response::encode(self : Response) -> Bytes raise RtspError {
require(
self.status >= 100 && self.status <= 599 && clean(self.reason),
"response status",
)
require(self.body.length() <= 1048576, "body limit")
let h = self.headers.copy()
h.set("Content-Length", self.body.length().to_string())
octets(
"RTSP/1.0 " +
self.status.to_string() +
" " +
self.reason +
"\r\n" +
h.wire() +
"\r\n",
) +
self.body
}
///|
fn parse_head(data : Bytes) -> (String, Headers, Int32) raise RtspError {
let text = bytes_text(data)
let lines = text.split("\r\n").to_array()
require(lines.length() >= 3, "incomplete header")
let headers = Headers::new()
for i = 1; i < lines.length() - 2; i = i + 1 {
let line = lines[i].to_owned()
let parts = line.split(":").to_array()
require(parts.length() >= 2, "header separator")
headers.add(parts[0].to_owned(), parts[1:].map(x => x.to_owned()).join(":"))
}
ignore(headers.unique("CSeq"))
ignore(headers.unique("Session"))
require(
headers.get("Transfer-Encoding") is None,
"transfer encoding unsupported",
)
let length = match headers.unique("Content-Length") {
Some(s) => number(s, 1048576)
None => 0
}
(lines[0].to_owned(), headers, length)
}
///|
fn response_from_head(
start : String,
headers : Headers,
body : Bytes,
) -> Response raise RtspError {
let parts = start.split(" ").to_array()
require(parts.length() >= 3 && parts[0] == "RTSP/1.0", "response start line")
let status = number(parts[1].to_owned(), 599)
require(status >= 100, "response status")
{ status, reason: parts[2:].map(x => x.to_owned()).join(" "), headers, body, }
}
///|
fn request_from_head(
start : String,
headers : Headers,
body : Bytes,
) -> Request raise RtspError {
let parts = start.split(" ").to_array()
require(parts.length() == 3 && parts[2] == "RTSP/1.0", "request start line")
let r = Request::{
verb: parts[0].to_owned(),
uri: parts[1].to_owned(),
headers,
body,
}
ignore(Request::new(r.verb, r.uri, r.cseq(), body~))
r
}
///|
pub fn Response::new(
status : Int32,
reason : String,
headers : Headers,
body~ : Bytes = b"",
) -> Response raise RtspError {
let response = { status, reason, headers: headers.copy(), body, }
ignore(response.encode())
response
}