summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Guschin <saintruler@gmail.com>2021-02-18 00:25:11 +0400
committerAndrew Guschin <saintruler@gmail.com>2021-02-18 00:25:11 +0400
commit9b69d6460e91244bfd77d8ea77c13d21d9050e4c (patch)
tree74a891c6c6ec6b565cb92187db2cece11a6ff1d9
parent04a3c64713ae4f0a7f1b5cfdab132f78cc33a862 (diff)
Added parsing of query params in GET requests handler
-rw-r--r--blog/src/main.rs13
-rw-r--r--blog/src/querystring.rs50
-rw-r--r--spider/Cargo.toml2
-rw-r--r--spider/src/http_method.rs1
-rw-r--r--spider/src/request.rs63
5 files changed, 109 insertions, 20 deletions
diff --git a/blog/src/main.rs b/blog/src/main.rs
index b0b8c71..ebae43a 100644
--- a/blog/src/main.rs
+++ b/blog/src/main.rs
@@ -2,10 +2,22 @@ use spider::http_server::{HttpHandler, HttpServer};
use spider::request::Request;
use spider::response::Response;
+mod querystring;
+use crate::querystring::parse_qs;
+use std::str;
+
struct MyHandler {}
impl HttpHandler for MyHandler {
fn do_get(&self, _request: Request) -> Response {
+ let params = str::from_utf8(&_request.body).unwrap().to_string();
+ let params = parse_qs(params);
+
+ println!("{}", _request.path);
+ for (key, val) in &params {
+ println!(" {}={}", key, val);
+ }
+
return Response::html(String::from("hey"), 200);
}
@@ -18,6 +30,7 @@ impl MyHandler {
pub fn new() -> MyHandler {
return MyHandler {};
}
+
}
// TODO(andrew): create logging package.
diff --git a/blog/src/querystring.rs b/blog/src/querystring.rs
new file mode 100644
index 0000000..8bb174a
--- /dev/null
+++ b/blog/src/querystring.rs
@@ -0,0 +1,50 @@
+use std::str;
+use std::collections::HashMap;
+use std::num::ParseIntError;
+
+
+pub fn parse_qs(query: String) -> HashMap<String, String> {
+ let query = percent_decode(query);
+ let mut map = HashMap::new();
+ for pair in query.split('&') {
+ let pair = pair.split('=').collect::<Vec<&str>>();
+ map.insert(pair[0].to_string(), pair[1].to_string());
+ }
+ return map;
+}
+
+fn percent_decode(s: String) -> String {
+ let len = s.len();
+ let mut s = s.chars();
+ let mut result = String::new();
+ let mut decode = String::new();
+
+ let mut i = 0;
+ while i < len {
+ let cur = s.nth(0).unwrap();
+ if cur == '%' {
+ decode.push(s.nth(0).unwrap());
+ decode.push(s.nth(0).unwrap());
+ i += 3;
+ continue;
+ }
+ if decode.len() != 0 {
+ match decode_hex(&decode) {
+ Ok(v) => result.push_str(str::from_utf8(&v).unwrap()),
+ Err(_) => ()
+ };
+ decode = String::new();
+ }
+
+ result.push(cur);
+ i += 1;
+ }
+ return result;
+}
+
+fn decode_hex(s: &str) -> Result<Vec<u8>, ParseIntError> {
+ (0..s.len())
+ .step_by(2)
+ .map(|i| u8::from_str_radix(&s[i..i + 2], 16))
+ .collect()
+}
diff --git a/spider/Cargo.toml b/spider/Cargo.toml
index 84e5702..b35cb43 100644
--- a/spider/Cargo.toml
+++ b/spider/Cargo.toml
@@ -4,6 +4,4 @@ version = "0.1.0"
authors = ["Andrew <saintruler@gmail.com>"]
edition = "2018"
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
[dependencies]
diff --git a/spider/src/http_method.rs b/spider/src/http_method.rs
index a0b2e17..814c93b 100644
--- a/spider/src/http_method.rs
+++ b/spider/src/http_method.rs
@@ -1,5 +1,6 @@
use std::fmt;
+#[derive(PartialEq)]
pub enum HttpMethod {
GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH
}
diff --git a/spider/src/request.rs b/spider/src/request.rs
index db1f2ad..3bd6a8f 100644
--- a/spider/src/request.rs
+++ b/spider/src/request.rs
@@ -5,21 +5,21 @@ use crate::http_method::HttpMethod;
pub struct Request {
pub method: HttpMethod,
- resource: String,
- http_version: String,
- headers: HashMap<String, String>,
- body: Vec<u8>,
+ pub path: String,
+ pub http_version: String,
+ pub headers: HashMap<String, String>,
+ pub body: Vec<u8>,
}
impl Request {
pub fn new( method: HttpMethod
- , resource: String
+ , path: String
, http_version: String
, headers: HashMap<String, String>
, body: Vec<u8> ) -> Request {
return Request {
method,
- resource,
+ path,
http_version,
headers,
body,
@@ -49,15 +49,17 @@ impl Request {
}
}
- let body = data[idx..].to_vec();
+ let mut body = data[idx..].to_vec();
let mut headers: HashMap<String, String> = HashMap::new();
- 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(" "));
+ 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]
@@ -65,23 +67,48 @@ impl Request {
.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) =>
+ Some(method) => {
+ if method == HttpMethod::GET {
+ if let Some(p) = params {
+ body = p.as_bytes().to_vec();
+ }
+ }
return Some(Request::new(
method,
- // TODO(andrew): add parsing of resource line.
- String::from(request_line[1]),
+ path,
String::from(request_line[2]),
headers,
- body )),
+ 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.resource);
+ return write!(f, "Request({}, {})", self.method, self.path);
}
}