summaryrefslogtreecommitdiff
path: root/spider/src
diff options
context:
space:
mode:
Diffstat (limited to 'spider/src')
-rw-r--r--spider/src/http_method.rs28
-rw-r--r--spider/src/http_server.rs75
-rw-r--r--spider/src/lib.rs142
-rw-r--r--spider/src/request.rs56
-rw-r--r--spider/src/response.rs35
5 files changed, 198 insertions, 138 deletions
diff --git a/spider/src/http_method.rs b/spider/src/http_method.rs
new file mode 100644
index 0000000..b1cc884
--- /dev/null
+++ b/spider/src/http_method.rs
@@ -0,0 +1,28 @@
+use std::fmt;
+
+pub enum HttpMethod {
+ GET, POST
+}
+
+impl fmt::Display for HttpMethod {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ HttpMethod::GET => write!(f, "GET"),
+ HttpMethod::POST => write!(f, "POST")
+ }
+ }
+}
+
+impl HttpMethod {
+ pub fn parse(s: String) -> Option<HttpMethod> {
+ if s == "GET" {
+ return Some(HttpMethod::GET);
+ }
+ else if s == "POST" {
+ return Some(HttpMethod::POST);
+ }
+ else {
+ return None;
+ }
+ }
+}
diff --git a/spider/src/http_server.rs b/spider/src/http_server.rs
new file mode 100644
index 0000000..d3fc140
--- /dev/null
+++ b/spider/src/http_server.rs
@@ -0,0 +1,75 @@
+use std::net::{TcpListener, TcpStream};
+use std::io::Write;
+use std::str;
+
+use crate::request::Request;
+use crate::response::Response;
+use crate::http_method::HttpMethod;
+
+pub trait HttpHandler {
+ fn do_get(&self, request: Request) -> Response;
+ fn do_post(&self, request: Request) -> Response;
+}
+
+pub struct HttpServer<T: HttpHandler> {
+ host: String,
+ port: u16,
+ socket: TcpListener,
+ handler: T
+}
+
+impl<T> HttpServer<T> where T: HttpHandler {
+ // TODO(andrew): Add more verbose error handling.
+ pub fn new(host: &str, port: u16, handler: T) -> Option<HttpServer<T>> {
+ 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 Some(server);
+ },
+ Err(_) => return None
+ }
+ }
+
+ pub fn serve_forever(&self) {
+ for stream in self.socket.incoming() {
+ match stream {
+ Ok(s) => {
+ self.handle_client(s);
+ },
+ Err(_) => break
+ };
+ }
+ }
+
+ fn handle_client(&self, mut stream: TcpStream) {
+ let mut buf: [u8; 1024] = [0; 1024];
+ stream.peek(&mut buf).expect("Couldn't read from socket");
+
+ // TODO(andrew): remove panic.
+ let s = match str::from_utf8(&buf) {
+ Ok(v) => v,
+ Err(_) => panic!("Couldn't convert u8 to character")
+ };
+
+ let request = Request::from(&s);
+ // TODO(andrew): remove panic.
+ let request = match request {
+ Some(r) => r,
+ None => panic!("Request parsed with errors")
+ };
+
+ let response = match request.method {
+ HttpMethod::GET => self.handler.do_get(request),
+ HttpMethod::POST => self.handler.do_post(request)
+ };
+ let response = response.format();
+ stream.write(response);
+ }
+}
diff --git a/spider/src/lib.rs b/spider/src/lib.rs
index 66947cf..baa0220 100644
--- a/spider/src/lib.rs
+++ b/spider/src/lib.rs
@@ -1,138 +1,4 @@
-use std::net::{TcpListener, TcpStream};
-use std::str;
-use std::collections::HashMap;
-use std::fmt;
-
-enum HttpMethod {
- GET, POST
-}
-
-impl fmt::Display for HttpMethod {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- HttpMethod::GET => write!(f, "GET"),
- HttpMethod::POST => write!(f, "POST")
- }
- }
-}
-
-impl HttpMethod {
- pub fn parse(s: String) -> Option<HttpMethod> {
- if s == "GET" {
- return Some(HttpMethod::GET);
- }
- else if s == "POST" {
- return Some(HttpMethod::POST);
- }
- else {
- return None;
- }
- }
-}
-
-struct Request {
- method: HttpMethod,
- path: String,
- http_version: String,
- headers: HashMap<String, String>,
- // body: &'a [u8]
-}
-
-impl Request {
- pub fn new( method: HttpMethod
- , path: String
- , http_version: String
- , headers: HashMap<String, String>) -> Request {
- return Request {
- method,
- path,
- http_version,
- headers
- };
- }
-
- pub fn print(&self) {
- println!("Request({}, {})", self.method, self.path);
- }
-}
-
-struct Response {
- status: i32,
- headers: HashMap<String, String>,
- body: String
-}
-
-impl Response {
- pub fn new(body: &str) -> Response {
- let headers: HashMap<String, String> = HashMap::new();
- return Response {
- status: 200,
- headers: headers,
- body: String::from(body)
- };
- }
-}
-
-fn do_get(request: Request) -> Response {
- return Response::new("hey");
-}
-
-fn do_post(request: Request) -> Response {
- return Response::new("hey");
-}
-
-// TODO(andrew): Add some error handling.
-fn parse_request(data: &str) -> Option<Request> {
- let lines = data.split("\r\n").collect::<Vec<&str>>();
-
- let mut headers: HashMap<String, String> = HashMap::new();
- for line in &lines[1..] {
- let line = line.split(": ").collect::<Vec<&str>>();
- headers.insert(String::from(line[0]), line[1..].join(" "));
- }
-
- let first_line = lines[0].split(" ").collect::<Vec<&str>>();
-
- let method = String::from(first_line[0]);
- match HttpMethod::parse(method) {
- Some(method) =>
- return Some(Request::new(
- method,
- String::from(first_line[1]),
- String::from(first_line[2]),
- headers )),
- None => return None
- };
-}
-
-fn format_response<'a>(response: Response) -> &'a [u8] {
- let buf: &[u8];
- buf = &[0; 1024];
-
-
- return buf;
-}
-
-pub fn handle_client(stream: TcpStream) {
- let mut buf: [u8; 1024] = [0; 1024];
- stream.peek(&mut buf).expect("Couldn't read from socket");
-
- let s = match str::from_utf8(&buf) {
- Ok(v) => v,
- Err(_e) => panic!("Couldn't convert u8 to character")
- };
-
- let request = parse_request(&s);
- // TODO(andrew): remove panic!.
- let request = match request {
- Some(r) => r,
- None => panic!("Request parsed with errors")
- };
-
- let response = match request.method {
- HttpMethod::GET => do_get(request),
- HttpMethod::POST => do_post(request)
- };
- let response = format_response(response);
-}
-
+pub mod request;
+pub mod response;
+pub mod http_method;
+pub mod http_server;
diff --git a/spider/src/request.rs b/spider/src/request.rs
new file mode 100644
index 0000000..4fae0c5
--- /dev/null
+++ b/spider/src/request.rs
@@ -0,0 +1,56 @@
+use std::collections::HashMap;
+use std::fmt;
+
+use crate::http_method::HttpMethod;
+
+pub struct Request {
+ pub method: HttpMethod,
+ path: String,
+ http_version: String,
+ headers: HashMap<String, String>,
+ // body: &'a [u8]
+}
+
+impl Request {
+ pub fn new( method: HttpMethod
+ , path: String
+ , http_version: String
+ , headers: HashMap<String, String>) -> Request {
+ return Request {
+ method,
+ path,
+ http_version,
+ headers
+ };
+ }
+
+ // TODO(andrew): Add some error handling.
+ pub fn from(data: &str) -> Option<Request> {
+ let lines = data.split("\r\n").collect::<Vec<&str>>();
+
+ let mut headers: HashMap<String, String> = HashMap::new();
+ for line in &lines[1..] {
+ let line = line.split(": ").collect::<Vec<&str>>();
+ headers.insert(String::from(line[0]), line[1..].join(" "));
+ }
+
+ let first_line = lines[0].split(" ").collect::<Vec<&str>>();
+
+ let method = String::from(first_line[0]);
+ match HttpMethod::parse(method) {
+ Some(method) =>
+ return Some(Request::new(
+ method,
+ String::from(first_line[1]),
+ String::from(first_line[2]),
+ headers )),
+ None => return None
+ };
+ }
+}
+
+impl fmt::Display for Request {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ return write!(f, "Request({}, {})", self.method, self.path);
+ }
+}
diff --git a/spider/src/response.rs b/spider/src/response.rs
new file mode 100644
index 0000000..e192b22
--- /dev/null
+++ b/spider/src/response.rs
@@ -0,0 +1,35 @@
+use std::collections::HashMap;
+use std::fmt;
+
+pub struct Response {
+ status: i32,
+ headers: HashMap<String, String>,
+ body: String
+}
+
+impl Response {
+ pub fn new(body: &str) -> Response {
+ let headers: HashMap<String, String> = HashMap::new();
+ return Response {
+ status: 200,
+ headers: headers,
+ body: String::from(body)
+ };
+ }
+
+ pub fn format<'a>(&self) -> &'a [u8] {
+ 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();
+
+ // let buf: &[u8];
+ // buf = &[0; 1024];
+//
+ // return buf;
+ }
+}
+
+impl fmt::Display for Response {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ return write!(f, "Response({})", self.status);
+ }
+}