summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew <saintruler@gmail.com>2021-02-14 16:47:56 +0400
committerAndrew <saintruler@gmail.com>2021-02-14 16:47:56 +0400
commitba53adb8c8e4b1a5f870ee8cdf97489087f2b0bc (patch)
treebd56aec0f295e6ec3c633f670db45d3ca1f1e239
parentad92fb3dc6a3350b7b8952be40c5c3a7aa543892 (diff)
Added actual formatting of responses
-rw-r--r--blog/src/main.rs4
-rw-r--r--spider/src/http_server.rs4
-rw-r--r--spider/src/http_status.rs60
-rw-r--r--spider/src/lib.rs1
-rw-r--r--spider/src/response.rs51
5 files changed, 103 insertions, 17 deletions
diff --git a/blog/src/main.rs b/blog/src/main.rs
index 9693f88..c27bc4e 100644
--- a/blog/src/main.rs
+++ b/blog/src/main.rs
@@ -6,11 +6,11 @@ struct MyHandler {}
impl HttpHandler for MyHandler {
fn do_get(&self, _request: Request) -> Response {
- return Response::new("hey");
+ return Response::html(String::from("hey"), 200);
}
fn do_post(&self, _request: Request) -> Response {
- return Response::new("hey");
+ return Response::html(String::from("hey"), 200);
}
}
diff --git a/spider/src/http_server.rs b/spider/src/http_server.rs
index a3f4bc2..12c410f 100644
--- a/spider/src/http_server.rs
+++ b/spider/src/http_server.rs
@@ -44,6 +44,7 @@ impl<T> HttpServer<T> where T: HttpHandler {
Ok(s) => {
println!("Got connection!");
self.handle_client(&s);
+ // TODO(andrew): handle possible errors.
s.shutdown(Shutdown::Both);
println!("Connection hadled");
},
@@ -78,6 +79,7 @@ impl<T> HttpServer<T> where T: HttpHandler {
HttpMethod::POST => self.handler.do_post(request)
};
let response = response.format();
- stream.write(response);
+ // TODO(andrew): handle possible errors.
+ stream.write(&response);
}
}
diff --git a/spider/src/http_status.rs b/spider/src/http_status.rs
new file mode 100644
index 0000000..0ea889e
--- /dev/null
+++ b/spider/src/http_status.rs
@@ -0,0 +1,60 @@
+pub fn get_status_text(code: u16) -> Option<String> {
+ match code {
+ 100 => Some(String::from("Continue")),
+ 101 => Some(String::from("Switching Protocols")),
+ 102 => Some(String::from("Processing")),
+ 200 => Some(String::from("OK")),
+ 201 => Some(String::from("Created")),
+ 202 => Some(String::from("Accepted")),
+ 203 => Some(String::from("Non Authoritative Information")),
+ 204 => Some(String::from("No Content")),
+ 205 => Some(String::from("Reset Content")),
+ 206 => Some(String::from("Partial Content")),
+ 207 => Some(String::from("Multi Status")),
+ 226 => Some(String::from("IM Used")),
+ 300 => Some(String::from("Multiple Choices")),
+ 301 => Some(String::from("Moved Permanently")),
+ 302 => Some(String::from("Found")),
+ 303 => Some(String::from("See Other")),
+ 304 => Some(String::from("Not Modified")),
+ 305 => Some(String::from("Use Proxy")),
+ 307 => Some(String::from("Temporary Redirect")),
+ 308 => Some(String::from("Permanent Redirect")),
+ 400 => Some(String::from("Bad Request")),
+ 401 => Some(String::from("Unauthorized")),
+ 402 => Some(String::from("Payment Required")),
+ 403 => Some(String::from("Forbidden")),
+ 404 => Some(String::from("Not Found")),
+ 405 => Some(String::from("Method Not Allowed")),
+ 406 => Some(String::from("Not Acceptable")),
+ 407 => Some(String::from("Proxy Authentication Required")),
+ 408 => Some(String::from("Request Timeout")),
+ 409 => Some(String::from("Conflict")),
+ 410 => Some(String::from("Gone")),
+ 411 => Some(String::from("Length Required")),
+ 412 => Some(String::from("Precondition Failed")),
+ 413 => Some(String::from("Request Entity Too Large")),
+ 414 => Some(String::from("Request URI Too Long")),
+ 415 => Some(String::from("Unsupported Media Type")),
+ 416 => Some(String::from("Requested Range Not Satisfiable")),
+ 417 => Some(String::from("Expectation Failed")),
+ 418 => Some(String::from("I'm a teapot")),
+ 421 => Some(String::from("Misdirected Request")),
+ 422 => Some(String::from("Unprocessable Entity")),
+ 423 => Some(String::from("Locked")),
+ 424 => Some(String::from("Failed Dependency")),
+ 426 => Some(String::from("Upgrade Required")),
+ 428 => Some(String::from("Precondition Required")),
+ 429 => Some(String::from("Too Many Requests")),
+ 431 => Some(String::from("Request Header Fields Too Large")),
+ 449 => Some(String::from("Retry With")),
+ 451 => Some(String::from("Unavailable For Legal Reasons")),
+ 500 => Some(String::from("Internal Server Error")),
+ 501 => Some(String::from("Not Implemented")),
+ 502 => Some(String::from("Bad Gateway")),
+ 503 => Some(String::from("Service Unavailable")),
+ 504 => Some(String::from("Gateway Timeout")),
+ 505 => Some(String::from("HTTP Version Not Supported")),
+ _ => None
+ }
+}
diff --git a/spider/src/lib.rs b/spider/src/lib.rs
index baa0220..9f4074f 100644
--- a/spider/src/lib.rs
+++ b/spider/src/lib.rs
@@ -2,3 +2,4 @@ pub mod request;
pub mod response;
pub mod http_method;
pub mod http_server;
+mod http_status;
diff --git a/spider/src/response.rs b/spider/src/response.rs
index 35b2f00..3873315 100644
--- a/spider/src/response.rs
+++ b/spider/src/response.rs
@@ -1,34 +1,57 @@
use std::collections::HashMap;
use std::fmt;
-// TODO(andrew): add more flexible status structure.
-// (Possibly with enum variants?)
+use crate::http_status::get_status_text;
+
pub struct Response {
- status: i32,
+ code: u16,
headers: HashMap<String, String>,
- body: String
+ body: Vec<u8>,
}
+// TODO(andrew): add more constructors for different content types.
impl Response {
- pub fn new(body: &str) -> Response {
- let headers: HashMap<String, String> = HashMap::new();
+ pub fn html(html: String, status_code: u16) -> Response {
+ let mut headers = HashMap::new();
+ headers.insert( String::from("Content-Type")
+ , String::from("text/html") );
+
return Response {
- status: 200,
+ code: status_code,
headers: headers,
- body: String::from(body)
+ body: html.as_bytes().to_vec(),
};
}
- pub fn format<'a>(&self) -> &'a [u8] {
- // TODO(andrew): replace placeholder response with actual
- // formatted response;
- let s = "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Type: text/html\r\n\r\n<i>Hello</i>";
- return s.as_bytes();
+ pub fn format<'a>(&self) -> Vec<u8> {
+ let status_text = match get_status_text(self.code) {
+ Some(text) => text,
+ None => String::from("UNDEFINED")
+ };
+
+ let mut data = Vec::new();
+
+ let first_line = format!("HTTP/1.1 {} {}", self.code, status_text);
+ let headers = format_headers(&self.headers);
+ let head = format!("{}\r\n{}\r\n", first_line, headers);
+
+ data.extend_from_slice(head.as_bytes());
+ data.extend_from_slice(&self.body);
+ return data;
}
}
impl fmt::Display for Response {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- return write!(f, "Response({})", self.status);
+ return write!(f, "Response({})", self.code);
+ }
+}
+
+fn format_headers(headers: &HashMap<String, String>) -> String {
+ let mut result = String::new();
+ for (key, value) in headers.iter() {
+ let line = format!("{}: {}\r\n", key, value);
+ result.push_str(&line);
}
+ return result;
}