summaryrefslogtreecommitdiff
path: root/spider_server/src/http_server.rs
diff options
context:
space:
mode:
Diffstat (limited to 'spider_server/src/http_server.rs')
-rw-r--r--spider_server/src/http_server.rs135
1 files changed, 135 insertions, 0 deletions
diff --git a/spider_server/src/http_server.rs b/spider_server/src/http_server.rs
new file mode 100644
index 0000000..479ef3f
--- /dev/null
+++ b/spider_server/src/http_server.rs
@@ -0,0 +1,135 @@
+use std::net::{TcpListener, TcpStream, Shutdown};
+use std::io::Write;
+use std::str;
+use std::fmt;
+
+use crate::request::Request;
+use crate::response::Response;
+use crate::http_method::HttpMethod;
+
+pub trait HttpHandler {
+ fn do_get(&self, _request: Request) -> Response {
+ return self.default_action(_request);
+ }
+
+ fn do_head(&self, _request: Request) -> Response {
+ return self.default_action(_request);
+ }
+
+ fn do_post(&self, _request: Request) -> Response {
+ return self.default_action(_request);
+ }
+
+ fn do_put(&self, _request: Request) -> Response {
+ return self.default_action(_request);
+ }
+
+ fn do_delete(&self, _request: Request) -> Response {
+ return self.default_action(_request);
+ }
+
+ fn do_connect(&self, _request: Request) -> Response {
+ return self.default_action(_request);
+ }
+
+ fn do_options(&self, _request: Request) -> Response {
+ return self.default_action(_request);
+ }
+
+ fn do_trace(&self, _request: Request) -> Response {
+ return self.default_action(_request);
+ }
+
+ fn do_patch(&self, _request: Request) -> Response {
+ return self.default_action(_request);
+ }
+
+ fn default_action(&self, _request: Request) -> Response {
+ let msg = String::from("<h1>Method not allowed</h1>");
+ return Response::html(msg, 405);
+ }
+}
+
+pub struct HttpServer<T: HttpHandler> {
+ host: String,
+ port: u16,
+ socket: TcpListener,
+ handler: T
+}
+
+impl<T> HttpServer<T> where T: HttpHandler {
+ // TODO(andrew): add explanations for errors?
+ pub fn new(host: &str, port: u16, handler: T) -> Result<HttpServer<T>, &str> {
+ let addr = format!("{}:{}", host, port);
+ let sock = TcpListener::bind(addr);
+ match sock {
+ Ok(s) => {
+ let server = HttpServer {
+ host: String::from(host),
+ port: port,
+ socket: s,
+ handler: handler,
+ };
+ return Ok(server);
+ },
+ Err(_) => return Err("Couldn't start server")
+ };
+ }
+
+ pub fn serve_forever(&self) -> Result<(), &str> {
+ for stream in self.socket.incoming() {
+ match stream {
+ Ok(s) => {
+ // TODO(andrew): replace println with logging.
+ println!("Got connection!");
+ match self.handle_client(&s) {
+ Ok(_) => (),
+ Err(msg) => return Err(msg)
+ };
+ match s.shutdown(Shutdown::Both) {
+ Ok(_) => println!("Closed connection"),
+ Err(_) => return Err("Couldn't close client socket")
+ };
+ },
+ Err(_) => break
+ };
+ }
+ return Ok(());
+ }
+
+ fn handle_client(&self, mut stream: &TcpStream) -> Result<(), &str> {
+ let mut buf: [u8; 1024] = [0; 1024];
+ // TODO(andrew): read all body, not first 1024 bytes.
+ stream.peek(&mut buf).expect("Couldn't read from socket");
+
+ let request = Request::from(&buf);
+ let request = match request {
+ Some(r) => r,
+ None => return Err("Request parsed with errors")
+ };
+
+ let response = match request.method {
+ HttpMethod::GET => self.handler.do_get(request),
+ HttpMethod::HEAD => self.handler.do_head(request),
+ HttpMethod::POST => self.handler.do_post(request),
+ HttpMethod::PUT => self.handler.do_put(request),
+ HttpMethod::DELETE => self.handler.do_delete(request),
+ HttpMethod::CONNECT => self.handler.do_connect(request),
+ HttpMethod::OPTIONS => self.handler.do_options(request),
+ HttpMethod::TRACE => self.handler.do_trace(request),
+ HttpMethod::PATCH => self.handler.do_patch(request),
+ };
+ let response = response.format();
+ match stream.write(&response) {
+ Ok(_) => return Ok(()),
+ Err(_) => return Err("Couldn't write to client socket")
+ };
+ }
+}
+
+impl<T> fmt::Display for HttpServer<T> where T: HttpHandler {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ return write!(f, "HttpServer({}:{})", self.host, self.port);
+ }
+}
+