-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
cb68a45
commit 4d1baa2
Showing
104 changed files
with
374 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
[package] | ||
name = "http" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
## Request | ||
|
||
GET /page1.htm HTTP/1.1 | ||
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 | ||
Accept-Language: en-US | ||
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 | ||
Accept-Encoding: gzip, deflate | ||
Host: example.com | ||
Connection: Keep-Alive | ||
|
||
##Response | ||
|
||
HTTP/1.1 200 OK | ||
Cache-Control: max-age=604800 | ||
Content-Type: text/html; charset=UTF-8 | ||
Date: Fri, 14 Dec 2018 16:46:09 GMT | ||
Etag: "1541025663+gzip" | ||
Expires: Fri, 21 Dec 2018 16:46:09 GMT | ||
Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT | ||
Server: ECS (ord/5730) | ||
Vary: Accept-Encoding | ||
X-Cache: HIT | ||
Content-Length: 1270 | ||
|
||
<!doctype html> | ||
<html> | ||
<head> | ||
<title>Example Domain</title> | ||
... | ||
|
||
|
||
"HTTP/1.1 200 OK | ||
Accept-Ranges: bytes | ||
Age: 43577 | ||
Cache-Control: max-age=604800 | ||
Content-Type: text/html; charset=UTF-8 | ||
Date: Mon, 25 Mar 2024 22:06:50 GMT | ||
Etag: \"3147526947\" | ||
Expires: Mon, 01 Apr 2024 22:06:50 GMT | ||
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT | ||
Server: ECS (laa/7B49 | ||
Vary: Accept-Encoding | ||
X-Cache: HIT | ||
Content-Length: 1256 | ||
Connection: close | ||
|
||
<!doctype html> | ||
<html> | ||
<head> | ||
<title>Example Domain</title> | ||
<meta charset=\"utf-8\" /> | ||
<meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" /> | ||
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" /> | ||
<style type=\"text/css\"> | ||
body { | ||
background-color: #f0f0f2; | ||
margin: 0; | ||
padding: 0; | ||
font-family: -apple-system, system-ui, BlinkMacSystemFont, \"Segoe UI\", \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif; | ||
} | ||
div { | ||
width: 600px; | ||
margin: 5em auto; | ||
padding: 2em; | ||
background-color: #fdfdff; | ||
border-radius: 0.5em; | ||
box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02); | ||
} | ||
a:link, a:visited { | ||
color: #38488f; | ||
text-decoration: none; | ||
} | ||
@media (max-width: 700px) { | ||
div { | ||
margin: 0 auto; | ||
width: auto; | ||
} | ||
} | ||
|
||
</style> | ||
</head> | ||
<body> | ||
<div> | ||
<h1>Example Domain</h1> | ||
<p>This domain is for use in illustrative examples in documents. You may use this | ||
domain in literature without prior coordination or asking for permission.</p> | ||
<p><a href=\"https://www.iana.org/domains/example\">More information...</a></p> | ||
</div> | ||
</body> | ||
</html> | ||
|
||
" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,216 @@ | ||
use std::net::TcpStream; | ||
use std::str::from_utf8; | ||
use std::{ | ||
collections::HashMap, | ||
io::{Read, Write}, | ||
ops::Range, | ||
}; | ||
use std::{fmt, io}; | ||
|
||
#[derive(Debug)] | ||
pub enum Error { | ||
ParseUrlError, | ||
} | ||
|
||
impl fmt::Display for Error { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
write!(f, "URL parsing error",) | ||
} | ||
} | ||
|
||
#[derive(Debug, PartialEq)] | ||
pub struct ParsedUrl { | ||
pub scheme: String, | ||
pub host: String, | ||
pub path: String, | ||
} | ||
|
||
impl ParsedUrl { | ||
pub fn from(url: &str) -> Result<ParsedUrl, Error> { | ||
let addr = if url.starts_with("http") || url.starts_with("https") { | ||
url.to_owned() | ||
} else { | ||
format!("http://{}", url) | ||
}; | ||
|
||
let mut split = addr.split("://"); | ||
|
||
let scheme = match split.next() { | ||
Some(v) => v.to_string(), | ||
None => return Err(Error::ParseUrlError), | ||
}; | ||
|
||
split = match split.next() { | ||
Some(v) => v.split("/"), | ||
None => return Err(Error::ParseUrlError), | ||
}; | ||
|
||
let host = match split.next() { | ||
Some(v) => v.to_string(), | ||
None => return Err(Error::ParseUrlError), | ||
}; | ||
|
||
let mut path = String::new(); | ||
loop { | ||
match split.next() { | ||
Some(v) => path.push_str(format!("/{}", v).as_str()), | ||
None => { | ||
if path.is_empty() { | ||
path.push('/'); | ||
} | ||
break; | ||
} | ||
} | ||
} | ||
|
||
Ok(ParsedUrl { scheme, host, path }) | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
pub struct Connection { | ||
url: ParsedUrl, | ||
stream: TcpStream, | ||
} | ||
|
||
pub enum Method { | ||
GET, | ||
POST, | ||
PUT, | ||
DELETE, | ||
} | ||
impl fmt::Display for Method { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
match self { | ||
Method::GET => write!(f, "GET"), | ||
Method::POST => write!(f, "POST"), | ||
Method::PUT => write!(f, "PUT"), | ||
Method::DELETE => write!(f, "DELETE"), | ||
} | ||
} | ||
} | ||
|
||
pub struct Request { | ||
method: Method, | ||
headers: HashMap<String, String>, | ||
query_strings: String, | ||
range: Option<Range<usize>>, | ||
body: Option<Vec<u8>>, | ||
} | ||
|
||
impl Request { | ||
pub fn new() -> Request { | ||
Request { | ||
method: Method::GET, | ||
headers: HashMap::new(), | ||
query_strings: String::new(), | ||
range: None, | ||
body: None, | ||
} | ||
} | ||
|
||
pub fn set_method(mut self, method: Method) -> Request { | ||
self.method = method; | ||
self | ||
} | ||
|
||
pub fn get_method(&self) -> &Method { | ||
&self.method | ||
} | ||
|
||
pub fn set_headers(mut self, headers: HashMap<String, String>) -> Request { | ||
self.headers = headers; | ||
self | ||
} | ||
|
||
pub fn get_headers(&self) -> &HashMap<String, String> { | ||
&self.headers | ||
} | ||
|
||
pub fn set_range(mut self, range: Range<usize>) -> Request { | ||
self.range = Some(range); | ||
self | ||
} | ||
|
||
pub fn get_range(&self) -> &Option<Range<usize>> { | ||
&self.range | ||
} | ||
|
||
pub fn get_query_strings(&self) -> &String { | ||
&self.query_strings | ||
} | ||
|
||
pub fn get_body(&self) -> &Option<Vec<u8>> { | ||
&self.body | ||
} | ||
|
||
pub fn get_content_length(&self) -> usize { | ||
if let Some(body) = &self.body { | ||
body.len() | ||
} else { | ||
0 | ||
} | ||
} | ||
} | ||
impl Connection { | ||
pub fn new(parse_url: &str) -> Result<Connection, Error> { | ||
let url = ParsedUrl::from(&parse_url).unwrap(); | ||
let stream = TcpStream::connect(format!("{}:80", url.host)).unwrap(); | ||
Ok(Connection { url, stream }) | ||
} | ||
|
||
pub fn send_request(&mut self) -> Result<(), Error> { | ||
let mut request = Request::new(); | ||
self.stream | ||
.write_all(format!("GET {} HTTP/1.1\r\n", self.url.path).as_bytes()) | ||
.unwrap(); | ||
self.stream | ||
.write_all(format!("HOST: {}\r\n", self.url.host).as_bytes()) | ||
.unwrap(); | ||
for header in request.get_headers() { | ||
self.stream | ||
.write_all(format!("{}: {}\r\n", header.0, header.1).as_bytes()) | ||
.unwrap(); | ||
} | ||
self.stream | ||
.write_all(format!("Content-Length: {}\r\n", request.get_content_length()).as_bytes()) | ||
.unwrap(); | ||
if let Some(range) = request.get_range() { | ||
self.stream | ||
.write_all(format!("Range: bytes={}-{}\r\n", range.start, range.end).as_bytes()) | ||
.unwrap(); | ||
} | ||
|
||
self.stream.write_all(b"Connection: Close\r\n").unwrap(); | ||
self.stream.write_all(b"\r\n").unwrap(); | ||
|
||
if let Some(body) = request.get_body() { | ||
self.stream.write_all(body.as_slice()).unwrap(); | ||
} | ||
|
||
self.stream.write_all(b"\r\n\r\n").unwrap(); | ||
let mut buf = String::new(); | ||
match self.stream.read_to_string(&mut buf) { | ||
Ok(_) => { | ||
let mut response = buf.split("/"); | ||
let scheme = response.next(); | ||
let protocol = response.next(); | ||
let status_code = response.next(); | ||
println!("Response:\n{:?}", buf); | ||
} | ||
Err(e) => { | ||
println!("Failed to receive data: {}", e); | ||
} | ||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
fn main() -> Result<(), Error> { | ||
let url = "https://example.com"; | ||
|
||
let mut connection = Connection::new(&url).unwrap(); | ||
//println!("Connection: {:?}", connection); | ||
connection.send_request().unwrap(); | ||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"rustc_fingerprint":6537163298064755573,"outputs":{"15729799797837862367":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/kibet/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""},"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.76.0 (07dca489a 2024-02-04)\nbinary: rustc\ncommit-hash: 07dca489ac2d933c78d3c5158e3f43beefeb02ce\ncommit-date: 2024-02-04\nhost: x86_64-unknown-linux-gnu\nrelease: 1.76.0\nLLVM version: 17.0.6\n","stderr":""}},"successes":{}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Signature: 8a477f597d28d172789f06886806bc55 | ||
# This file is a cache directory tag created by cargo. | ||
# For information about cache directory tags see https://bford.info/cachedir/ |
Empty file.
Binary file added
BIN
+24 Bytes
http/target/debug/.fingerprint/http-014b6fedbe8b6002/dep-test-bin-http
Binary file not shown.
1 change: 1 addition & 0 deletions
1
http/target/debug/.fingerprint/http-014b6fedbe8b6002/invoked.timestamp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
This file has an mtime of when this was started. |
Oops, something went wrong.