2020-10-28 00:43:23 +00:00
|
|
|
use std::{
|
|
|
|
collections::*,
|
2020-10-28 01:39:02 +00:00
|
|
|
convert::{TryFrom},
|
2020-10-28 00:43:23 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
use serde::{Deserialize, Serialize};
|
2020-10-31 01:35:39 +00:00
|
|
|
use tokio::sync::mpsc::Receiver;
|
2020-10-28 00:43:23 +00:00
|
|
|
|
2020-10-30 22:01:37 +00:00
|
|
|
// Hyper doesn't seem to make it easy to de/ser requests
|
|
|
|
// and responses and stuff like that, so I do it by hand here.
|
|
|
|
|
2020-10-28 00:43:23 +00:00
|
|
|
pub enum Error {
|
2020-10-31 01:35:39 +00:00
|
|
|
UnsupportedMethod,
|
2020-10-28 00:43:23 +00:00
|
|
|
InvalidHeaderName,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From <hyper::header::InvalidHeaderName> for Error {
|
2020-10-28 01:31:38 +00:00
|
|
|
fn from (_x: hyper::header::InvalidHeaderName) -> Self {
|
2020-10-28 00:43:23 +00:00
|
|
|
Self::InvalidHeaderName
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive (Deserialize, Serialize)]
|
|
|
|
pub enum Method {
|
|
|
|
Get,
|
2020-10-28 02:43:12 +00:00
|
|
|
Head,
|
2020-10-28 00:43:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl TryFrom <hyper::Method> for Method {
|
|
|
|
type Error = Error;
|
|
|
|
|
|
|
|
fn try_from (x: hyper::Method) -> Result <Self, Error> {
|
|
|
|
match x {
|
|
|
|
hyper::Method::GET => Ok (Self::Get),
|
2020-10-28 02:43:12 +00:00
|
|
|
hyper::Method::HEAD => Ok (Self::Head),
|
2020-10-31 01:35:39 +00:00
|
|
|
_ => Err (Error::UnsupportedMethod),
|
2020-10-28 00:43:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive (Deserialize, Serialize)]
|
|
|
|
pub struct RequestParts {
|
|
|
|
pub method: Method,
|
|
|
|
|
|
|
|
// Technically URIs are subtle and complex but I don't care
|
|
|
|
pub uri: String,
|
|
|
|
|
|
|
|
// Technically Hyper has headers in a multi-map
|
|
|
|
// but I don't feel like doing that right now.
|
|
|
|
|
|
|
|
// Headers are _kinda_ ASCII but they can also be binary.
|
|
|
|
// HTTP is nutty.
|
|
|
|
pub headers: HashMap <String, Vec <u8>>,
|
|
|
|
}
|
|
|
|
|
2020-10-31 01:35:39 +00:00
|
|
|
impl RequestParts {
|
|
|
|
pub fn from_hyper (
|
|
|
|
method: hyper::Method,
|
|
|
|
uri: String,
|
|
|
|
headers: hyper::HeaderMap <hyper::header::HeaderValue>
|
|
|
|
) -> Result <Self, Error>
|
|
|
|
{
|
|
|
|
use std::iter::FromIterator;
|
|
|
|
|
|
|
|
let method = Method::try_from (method)?;
|
|
|
|
let headers = HashMap::from_iter (
|
|
|
|
headers.into_iter ()
|
|
|
|
.filter_map (|(k, v)| k.map (|k| (k, v)))
|
|
|
|
.map (|(k, v)| (String::from (k.as_str ()), v.as_bytes ().to_vec ()))
|
|
|
|
);
|
|
|
|
|
|
|
|
Ok (Self {
|
|
|
|
method,
|
|
|
|
uri,
|
|
|
|
headers,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-30 22:25:22 +00:00
|
|
|
#[derive (Deserialize, Serialize)]
|
|
|
|
pub struct WrappedRequest {
|
|
|
|
pub id: String,
|
|
|
|
pub req: RequestParts,
|
|
|
|
}
|
|
|
|
|
2020-10-28 00:43:23 +00:00
|
|
|
#[derive (Deserialize, Serialize)]
|
|
|
|
pub enum StatusCode {
|
|
|
|
Ok,
|
|
|
|
NotFound,
|
2020-10-28 02:43:12 +00:00
|
|
|
PartialContent,
|
2020-10-28 00:43:23 +00:00
|
|
|
}
|
2020-10-28 02:43:12 +00:00
|
|
|
|
2020-10-30 22:01:37 +00:00
|
|
|
impl Default for StatusCode {
|
|
|
|
fn default () -> Self {
|
|
|
|
Self::Ok
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-28 00:43:23 +00:00
|
|
|
impl From <StatusCode> for hyper::StatusCode {
|
|
|
|
fn from (x: StatusCode) -> Self {
|
|
|
|
match x {
|
|
|
|
StatusCode::Ok => Self::OK,
|
|
|
|
StatusCode::NotFound => Self::NOT_FOUND,
|
2020-10-28 02:43:12 +00:00
|
|
|
StatusCode::PartialContent => Self::PARTIAL_CONTENT,
|
2020-10-28 00:43:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-30 22:01:37 +00:00
|
|
|
#[derive (Default, Deserialize, Serialize)]
|
2020-10-28 02:29:15 +00:00
|
|
|
pub struct ResponseParts {
|
|
|
|
pub status_code: StatusCode,
|
2020-10-28 00:43:23 +00:00
|
|
|
|
|
|
|
// Technically Hyper has headers in a multi-map
|
|
|
|
// but I don't feel like doing that right now.
|
2020-10-28 02:29:15 +00:00
|
|
|
// We promise not to need this feature.
|
|
|
|
|
|
|
|
pub headers: HashMap <String, Vec <u8>>,
|
2020-10-28 00:43:23 +00:00
|
|
|
}
|
2020-10-30 22:01:37 +00:00
|
|
|
|
2020-10-31 01:35:39 +00:00
|
|
|
// reqwest and hyper have different Body types for _some reason_
|
|
|
|
// so I have to do everything myself
|
|
|
|
|
|
|
|
type Body = Receiver <Result <Vec <u8>, std::convert::Infallible>>;
|
|
|
|
|
2020-10-30 22:01:37 +00:00
|
|
|
#[derive (Default)]
|
|
|
|
pub struct Response {
|
|
|
|
pub parts: ResponseParts,
|
2020-10-31 01:35:39 +00:00
|
|
|
pub body: Option <Body>,
|
2020-11-06 18:47:04 +00:00
|
|
|
|
|
|
|
// Needed to make Nginx happy
|
|
|
|
pub content_length: Option <u64>,
|
2020-10-30 22:01:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Response {
|
|
|
|
pub fn status_code (&mut self, c: StatusCode) -> &mut Self {
|
|
|
|
self.parts.status_code = c;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn header (&mut self, k: String, v: Vec <u8>) -> &mut Self {
|
|
|
|
self.parts.headers.insert (k, v);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2020-10-31 01:35:39 +00:00
|
|
|
pub fn body (&mut self, b: Body) -> &mut Self {
|
2020-10-30 22:01:37 +00:00
|
|
|
self.body = Some (b);
|
|
|
|
self
|
|
|
|
}
|
2020-10-31 01:35:39 +00:00
|
|
|
|
|
|
|
pub fn body_bytes (&mut self, b: Vec <u8>) -> &mut Self {
|
|
|
|
let (mut tx, rx) = tokio::sync::mpsc::channel (1);
|
|
|
|
tokio::spawn (async move {
|
|
|
|
tx.send (Ok (b)).await.unwrap ();
|
|
|
|
});
|
|
|
|
self.body = Some (rx);
|
|
|
|
self
|
|
|
|
}
|
2020-10-30 22:01:37 +00:00
|
|
|
}
|