http compressions stage 3
This commit is contained in:
parent
16b90fe61c
commit
be3740f6ed
20
Cargo.lock
generated
20
Cargo.lock
generated
@ -68,6 +68,15 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc32fast"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "diff"
|
name = "diff"
|
||||||
version = "0.1.13"
|
version = "0.1.13"
|
||||||
@ -80,6 +89,16 @@ version = "1.9.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flate2"
|
||||||
|
version = "1.0.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae"
|
||||||
|
dependencies = [
|
||||||
|
"crc32fast",
|
||||||
|
"miniz_oxide",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gimli"
|
name = "gimli"
|
||||||
version = "0.27.3"
|
version = "0.27.3"
|
||||||
@ -98,6 +117,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"flate2",
|
||||||
"itertools",
|
"itertools",
|
||||||
"nom",
|
"nom",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
|
|||||||
@ -25,7 +25,7 @@ thiserror = "1.0.38" # error handling
|
|||||||
tokio = { version = "1.23.0", features = ["full"] } # async networking
|
tokio = { version = "1.23.0", features = ["full"] } # async networking
|
||||||
nom = "7.1.3" # parser combinators
|
nom = "7.1.3" # parser combinators
|
||||||
itertools = "0.11.0" # General iterator helpers
|
itertools = "0.11.0" # General iterator helpers
|
||||||
|
flate2 = "1.0.30"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pretty_assertions = "1.3.0" # nicer looking assertions
|
pretty_assertions = "1.3.0" # nicer looking assertions
|
||||||
|
|
||||||
|
|||||||
36
src/main.rs
36
src/main.rs
@ -1,6 +1,6 @@
|
|||||||
// #![feature(if_let_guard)]
|
// #![feature(if_let_guard)]
|
||||||
|
|
||||||
use std::{ collections::HashMap, path::PathBuf, sync::Arc };
|
use std::{ collections::HashMap, io::Write, path::PathBuf, sync::Arc };
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
@ -10,6 +10,8 @@ use tokio::{
|
|||||||
net::{ TcpListener, TcpStream },
|
net::{ TcpListener, TcpStream },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use flate2::{ write::GzEncoder, Compression };
|
||||||
|
|
||||||
mod utils;
|
mod utils;
|
||||||
use utils::*;
|
use utils::*;
|
||||||
|
|
||||||
@ -72,9 +74,6 @@ async fn process (mut stream: TcpStream, args: A) -> Result<()> {
|
|||||||
let headers = Headers::parse(&mut data).await;
|
let headers = Headers::parse(&mut data).await;
|
||||||
let encoding = Encoding::parse(headers.get("Accept-Encoding"));
|
let encoding = Encoding::parse(headers.get("Accept-Encoding"));
|
||||||
|
|
||||||
println!("{:?}", headers);
|
|
||||||
println!("{:?}", encoding);
|
|
||||||
|
|
||||||
use Method as M;
|
use Method as M;
|
||||||
let response = match (method, target.as_str()) {
|
let response = match (method, target.as_str()) {
|
||||||
(M::GET, "/") => Response::Empty,
|
(M::GET, "/") => Response::Empty,
|
||||||
@ -104,8 +103,6 @@ async fn process (mut stream: TcpStream, args: A) -> Result<()> {
|
|||||||
_ => Response::_404,
|
_ => Response::_404,
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("{:?}", String::from_utf8_lossy(&response.clone().build()));
|
|
||||||
|
|
||||||
let _ = stream.write_all(&response.build()).await;
|
let _ = stream.write_all(&response.build()).await;
|
||||||
let _ = stream.flush().await;
|
let _ = stream.flush().await;
|
||||||
|
|
||||||
@ -143,7 +140,7 @@ impl Headers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
enum Encoding {
|
enum Encoding {
|
||||||
Gzip,
|
Gzip,
|
||||||
Invalid,
|
Invalid,
|
||||||
@ -215,17 +212,31 @@ enum Response {
|
|||||||
impl Response {
|
impl Response {
|
||||||
fn build (self) -> Vec<u8> {
|
fn build (self) -> Vec<u8> {
|
||||||
|
|
||||||
let headers = self.headers().join("\r\n");
|
let mut headers = self.headers();
|
||||||
let code = self.code();
|
let code = self.code();
|
||||||
|
|
||||||
let mut v: Vec<u8> = f!("HTTP/1.1 {code}\r\n{headers}\r\n\r\n").into();
|
let mut v: Vec<u8> = vec![];
|
||||||
|
let mut write_response_header = |headers: Vec<String>| v.extend_from_slice(format!("HTTP/1.1 {code}\r\n{}\r\n\r\n", headers.join("\r\n")).as_bytes());
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Self::OctetStream(bytes) => {
|
Self::OctetStream(bytes) => {
|
||||||
|
write_response_header(headers);
|
||||||
v.extend_from_slice(&bytes);
|
v.extend_from_slice(&bytes);
|
||||||
},
|
},
|
||||||
Self::TextPlain(text, _) => {
|
Self::TextPlain(text, encodings) => {
|
||||||
v.extend_from_slice(text.as_bytes());
|
if encodings.contains(&Encoding::Gzip) {
|
||||||
|
let mut enc = GzEncoder::new(vec![], Compression::default());
|
||||||
|
enc.write_all(text.as_bytes()).unwrap();
|
||||||
|
let b = enc.finish().unwrap();
|
||||||
|
headers.push(format!("Content-Length: {}", b.len()));
|
||||||
|
write_response_header(headers);
|
||||||
|
v.extend_from_slice(&b);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
write_response_header(headers);
|
||||||
|
v.extend_from_slice(text.as_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
@ -248,10 +259,11 @@ impl Response {
|
|||||||
Self::TextPlain(text, enc) => {
|
Self::TextPlain(text, enc) => {
|
||||||
let mut v = vec![
|
let mut v = vec![
|
||||||
f!("Content-Type: text/plain"),
|
f!("Content-Type: text/plain"),
|
||||||
format!("Content-Length: {}", text.len()),
|
|
||||||
];
|
];
|
||||||
|
if !enc.contains(&Encoding::Gzip) { v.push(format!("Content-Length: {}", text.len())) }
|
||||||
let enc = enc.into_iter().map(Encoding::header).filter(|e| !e.is_empty()).join(", ");
|
let enc = enc.into_iter().map(Encoding::header).filter(|e| !e.is_empty()).join(", ");
|
||||||
if !enc.is_empty() { v.push(f!("Content-Encoding: {enc}")) }
|
if !enc.is_empty() { v.push(f!("Content-Encoding: {enc}")) }
|
||||||
|
|
||||||
v
|
v
|
||||||
},
|
},
|
||||||
Self::OctetStream(bytes) => vec![
|
Self::OctetStream(bytes) => vec![
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user