summaryrefslogtreecommitdiff
path: root/spider
diff options
context:
space:
mode:
authorAndrew <saintruler@gmail.com>2021-02-18 19:48:06 +0400
committerAndrew <saintruler@gmail.com>2021-02-18 19:48:06 +0400
commit0a1d8409e49343427d26c4ddf0bf56d5b3e7b7d5 (patch)
tree9654645e0c74af2cf834ac4f1d7d68ca219a57e6 /spider
parent9b69d6460e91244bfd77d8ea77c13d21d9050e4c (diff)
Renamed spider package to spider_server
Diffstat (limited to 'spider')
-rw-r--r--spider/Cargo.toml7
-rw-r--r--spider/src/http_method.rs39
-rw-r--r--spider/src/http_server.rs135
-rw-r--r--spider/src/http_status.rs60
-rw-r--r--spider/src/lib.rs5
-rw-r--r--spider/src/request.rs114
-rw-r--r--spider/src/response.rs59
7 files changed, 0 insertions, 419 deletions
diff --git a/spider/Cargo.toml b/spider/Cargo.toml
deleted file mode 100644
index b35cb43..0000000
--- a/spider/Cargo.toml
+++ /dev/null
@@ -1,7 +0,0 @@
-[package]
-name = "spider"
-version = "0.1.0"
-authors = ["Andrew <saintruler@gmail.com>"]
-edition = "2018"
-
-[dependencies]
diff --git a/spider/src/http_method.rs b/spider/src/http_method.rs
deleted file mode 100644
index 814c93b..0000000
--- a/spider/src/http_method.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-use std::fmt;
-
-#[derive(PartialEq)]
-pub enum HttpMethod {
- GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH
-}
-
-impl fmt::Display for HttpMethod {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- HttpMethod::GET => write!(f, "GET"),
- HttpMethod::HEAD => write!(f, "HEAD"),
- HttpMethod::POST => write!(f, "POST"),
- HttpMethod::PUT => write!(f, "PUT"),
- HttpMethod::DELETE => write!(f, "DELETE"),
- HttpMethod::CONNECT => write!(f, "CONNECT"),
- HttpMethod::OPTIONS => write!(f, "OPTIONS"),
- HttpMethod::TRACE => write!(f, "TRACE"),
- HttpMethod::PATCH => write!(f, "PATCH"),
- }
- }
-}
-
-impl HttpMethod {
- pub fn parse(s: String) -> Option<HttpMethod> {
- match &*s {
- "GET" => Some(HttpMethod::GET),
- "HEAD" => Some(HttpMethod::HEAD),
- "POST" => Some(HttpMethod::POST),
- "PUT" => Some(HttpMethod::PUT),
- "DELETE" => Some(HttpMethod::DELETE),
- "CONNECT" => Some(HttpMethod::CONNECT),
- "OPTIONS" => Some(HttpMethod::OPTIONS),
- "TRACE" => Some(HttpMethod::TRACE),
- "PATCH" => Some(HttpMethod::PATCH),
- _ => None
- }
- }
-}
diff --git a/spider/src/http_server.rs b/spider/src/http_server.rs
deleted file mode 100644
index 479ef3f..0000000
--- a/spider/src/http_server.rs
+++ /dev/null
@@ -1,135 +0,0 @@
-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);
- }
-}
-
diff --git a/spider/src/http_status.rs b/spider/src/http_status.rs
deleted file mode 100644
index 0ea889e..0000000
--- a/spider/src/http_status.rs
+++ /dev/null
@@ -1,60 +0,0 @@
-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
deleted file mode 100644
index 9f4074f..0000000
--- a/spider/src/lib.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-pub mod request;
-pub mod response;
-pub mod http_method;
-pub mod http_server;
-mod http_status;
diff --git a/spider/src/request.rs b/spider/src/request.rs
deleted file mode 100644
index 3bd6a8f..0000000
--- a/spider/src/request.rs
+++ /dev/null
@@ -1,114 +0,0 @@
-use std::collections::HashMap;
-use std::fmt;
-
-use crate::http_method::HttpMethod;
-
-pub struct Request {
- pub method: HttpMethod,
- pub path: String,
- pub http_version: String,
- pub headers: HashMap<String, String>,
- pub body: Vec<u8>,
-}
-
-impl Request {
- pub fn new( method: HttpMethod
- , path: String
- , http_version: String
- , headers: HashMap<String, String>
- , body: Vec<u8> ) -> Request {
- return Request {
- method,
- path,
- http_version,
- headers,
- body,
- };
- }
-
- // TODO(andrew): add some error handling.
- pub fn from(data: &[u8]) -> Option<Request> {
- let mut lines: Vec<String> = Vec::new();
- let mut line = String::new();
- let mut idx = 0;
- let mut char_count = 0;
-
- // Parsing headers until first empty line (char_count == 0).
- for c in data {
- let c = *c as char;
- line.push(c);
- idx += 1;
-
- if c == '\n' {
- lines.push(line);
- if char_count == 0 { break; }
- else { line = String::new(); }
- }
- if c != '\r' && c != '\n' {
- char_count += 1;
- }
- }
-
- let mut body = data[idx..].to_vec();
-
- let mut headers: HashMap<String, String> = HashMap::new();
- if lines.len() > 0 {
- for line in &lines[1..] {
- let line = line
- .trim_end_matches("\r\n")
- .split(": ")
- .collect::<Vec<&str>>();
- headers.insert(String::from(line[0]), line[1..].join(" "));
- }
- }
-
- let request_line = lines[0]
- .trim_end_matches("\r\n")
- .split(" ")
- .collect::<Vec<&str>>();
-
- let (path, params) = split_path(String::from(request_line[1]));
-
- let method = String::from(request_line[0]);
- match HttpMethod::parse(method) {
- Some(method) => {
- if method == HttpMethod::GET {
- if let Some(p) = params {
- body = p.as_bytes().to_vec();
- }
- }
- return Some(Request::new(
- method,
- path,
- String::from(request_line[2]),
- headers,
- body ));
- }
- None => return None
- };
- }
-}
-
-fn split_path(resource: String) -> (String, Option<String>) {
- let mut idx = None;
- for (i, c) in resource.chars().enumerate() {
- if c == '?' {
- idx = Some(i);
- break;
- }
- }
- match idx {
- Some(n) => {
- let path = &resource[..n];
- let params = &resource[n + 1..];
- return (path.to_string(), Some(params.to_string()));
- },
- None => return (resource, 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
deleted file mode 100644
index fe1df78..0000000
--- a/spider/src/response.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-use std::collections::HashMap;
-use std::fmt;
-
-use crate::http_status::get_status_text;
-
-pub struct Response {
- code: u16,
- headers: HashMap<String, String>,
- body: Vec<u8>,
-}
-
-// TODO(andrew): add more constructors for different content types.
-impl Response {
- 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 {
- code: status_code,
- headers: headers,
- body: html.as_bytes().to_vec(),
- };
- }
-
- pub fn format<'a>(&self) -> Vec<u8> {
- // FIXME(andrew): is undefined status code an error that should
- // be handled here?
- 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.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;
-}