http client
This commit is contained in:
parent
24db811c57
commit
d59523b009
84
Cargo.lock
generated
84
Cargo.lock
generated
@ -92,15 +92,32 @@ version = "0.1.6"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"mime_guess",
|
"mime_guess",
|
||||||
|
"openssl",
|
||||||
"rand",
|
"rand",
|
||||||
"rusty_pool",
|
"rusty_pool",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"threadpool",
|
"threadpool",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-io-timeout",
|
"tokio-io-timeout",
|
||||||
|
"tokio-openssl",
|
||||||
"urlencoding",
|
"urlencoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||||
|
dependencies = [
|
||||||
|
"foreign-types-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types-shared"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures"
|
name = "futures"
|
||||||
version = "0.3.30"
|
version = "0.3.30"
|
||||||
@ -303,6 +320,50 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.20.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl"
|
||||||
|
version = "0.10.68"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"cfg-if",
|
||||||
|
"foreign-types",
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"openssl-macros",
|
||||||
|
"openssl-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-macros"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-sys"
|
||||||
|
version = "0.9.104"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.12.3"
|
version = "0.12.3"
|
||||||
@ -338,6 +399,12 @@ version = "0.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkg-config"
|
||||||
|
version = "0.3.31"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.20"
|
version = "0.2.20"
|
||||||
@ -566,6 +633,17 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-openssl"
|
||||||
|
version = "0.6.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59df6849caa43bb7567f9a36f863c447d95a11d5903c9cc334ba32576a27eadd"
|
||||||
|
dependencies = [
|
||||||
|
"openssl",
|
||||||
|
"openssl-sys",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicase"
|
name = "unicase"
|
||||||
version = "2.8.0"
|
version = "2.8.0"
|
||||||
@ -584,6 +662,12 @@ version = "2.1.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
|
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vcpkg"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
@ -19,3 +19,5 @@ threadpool = "1.8.1"
|
|||||||
lazy_static = "1.5.0"
|
lazy_static = "1.5.0"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
mime_guess = "2.0.5"
|
mime_guess = "2.0.5"
|
||||||
|
openssl = "0.10.68"
|
||||||
|
tokio-openssl = "0.6.5"
|
16
examples/request_meex.rs
Normal file
16
examples/request_meex.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use ezhttp::{client::{HttpClient, RequestBuilder}, request::URL};
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
let response = HttpClient::default().send(
|
||||||
|
RequestBuilder::get(
|
||||||
|
URL::from_str("https://meex.lol/dku?key=value#hex_id")
|
||||||
|
.expect("url error")
|
||||||
|
).build()
|
||||||
|
).await.expect("request error");
|
||||||
|
println!("status code: {}", response.status_code);
|
||||||
|
println!("headers: {}", response.headers.entries().iter().map(|o| format!("{}: {}", o.0, o.1)).collect::<Vec<String>>().join("; "));
|
||||||
|
println!("body: {} bytes", response.body.as_text().unwrap().len());
|
||||||
|
}
|
@ -160,6 +160,7 @@ impl Default for Body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone,Debug)]
|
||||||
pub struct Part {
|
pub struct Part {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub body: Body,
|
pub body: Body,
|
||||||
|
71
src/ezhttp/client/client.rs
Normal file
71
src/ezhttp/client/client.rs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
use crate::{error::HttpError, headers::Headers, prelude::HttpResponse, request::HttpRequest};
|
||||||
|
|
||||||
|
use super::{send_request, Proxy};
|
||||||
|
|
||||||
|
pub struct HttpClient {
|
||||||
|
proxy: Proxy,
|
||||||
|
verify: bool,
|
||||||
|
headers: Headers
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ClientBuilder {
|
||||||
|
proxy: Proxy,
|
||||||
|
verify: bool,
|
||||||
|
headers: Headers
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClientBuilder {
|
||||||
|
pub fn new() -> ClientBuilder {
|
||||||
|
ClientBuilder {
|
||||||
|
proxy: Proxy::None,
|
||||||
|
verify: false,
|
||||||
|
headers: Headers::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(self) -> HttpClient {
|
||||||
|
HttpClient {
|
||||||
|
proxy: self.proxy,
|
||||||
|
verify: self.verify,
|
||||||
|
headers: self.headers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn proxy(mut self, proxy: Proxy) -> Self {
|
||||||
|
self.proxy = proxy;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify(mut self, verify: bool) -> Self {
|
||||||
|
self.verify = verify;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn headers(mut self, headers: Headers) -> Self {
|
||||||
|
self.headers = headers;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn header(mut self, name: impl ToString, value: impl ToString) -> Self {
|
||||||
|
self.headers.put(name, value.to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HttpClient {
|
||||||
|
pub fn builder() -> ClientBuilder {
|
||||||
|
ClientBuilder::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send(&self, request: HttpRequest) -> Result<HttpResponse, HttpError> {
|
||||||
|
send_request(request, self.verify, self.proxy.clone(), self.headers.clone()).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for HttpClient {
|
||||||
|
fn default() -> Self {
|
||||||
|
ClientBuilder::new().build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,66 @@
|
|||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
|
||||||
|
use tokio::net::TcpStream;
|
||||||
|
use tokio_openssl::SslStream;
|
||||||
|
|
||||||
|
use super::{error::HttpError, gen_multipart_boundary, headers::Headers, prelude::HttpResponse, request::HttpRequest};
|
||||||
|
|
||||||
|
|
||||||
|
pub mod req_builder;
|
||||||
|
pub mod client;
|
||||||
|
pub mod proxy;
|
||||||
|
|
||||||
|
pub use req_builder::*;
|
||||||
|
pub use client::*;
|
||||||
|
pub use proxy::*;
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: proxy support
|
||||||
|
async fn send_request(request: HttpRequest, ssl_verify: bool, _proxy: Proxy, headers: Headers) -> Result<HttpResponse, HttpError> {
|
||||||
|
let mut request = request;
|
||||||
|
|
||||||
|
let mut stream = TcpStream::connect(
|
||||||
|
format!("{}:{}", request.url.domain, request.url.port)
|
||||||
|
).await.map_err(|_| HttpError::ConnectError)?;
|
||||||
|
|
||||||
|
for (key, value) in headers.entries() {
|
||||||
|
request.headers.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
request.headers.put("Connection", "close".to_string());
|
||||||
|
request.headers.put("Host", request.url.domain.to_string());
|
||||||
|
request.headers.put("Content-Length", request.body.as_bytes().len().to_string());
|
||||||
|
|
||||||
|
if request.url.scheme == "http" {
|
||||||
|
request.send(&mut stream).await?;
|
||||||
|
|
||||||
|
Ok(HttpResponse::recv(&mut stream).await?)
|
||||||
|
} else if request.url.scheme == "https" {
|
||||||
|
let mut ssl_connector = SslConnector::builder(SslMethod::tls())
|
||||||
|
.map_err(|_| HttpError::SslError)?;
|
||||||
|
|
||||||
|
ssl_connector.set_verify(if ssl_verify { SslVerifyMode::PEER } else { SslVerifyMode::NONE });
|
||||||
|
|
||||||
|
let ssl_connector = ssl_connector.build();
|
||||||
|
|
||||||
|
let ssl = ssl_connector
|
||||||
|
.configure()
|
||||||
|
.map_err(|_| HttpError::SslError)?
|
||||||
|
.into_ssl(&request.url.domain)
|
||||||
|
.map_err(|_| HttpError::SslError)?;
|
||||||
|
|
||||||
|
let mut wrapper = SslStream::new(ssl, stream)
|
||||||
|
.map_err(|_| HttpError::SslError)?;
|
||||||
|
|
||||||
|
let mut wrapper = Pin::new(&mut wrapper);
|
||||||
|
|
||||||
|
wrapper.as_mut().connect().await.map_err(|_| HttpError::SslError)?;
|
||||||
|
|
||||||
|
request.send(&mut wrapper).await?;
|
||||||
|
|
||||||
|
Ok(HttpResponse::recv(&mut wrapper).await?)
|
||||||
|
} else {
|
||||||
|
Err(HttpError::UnknownScheme)
|
||||||
|
}
|
||||||
|
}
|
44
src/ezhttp/client/proxy.rs
Normal file
44
src/ezhttp/client/proxy.rs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
use std::net::{ToSocketAddrs, SocketAddr};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum Proxy {
|
||||||
|
None,
|
||||||
|
Socks5 { host: SocketAddr, auth: Option<(String, String)> },
|
||||||
|
Socks4 { host: SocketAddr, user: String },
|
||||||
|
Http { host: SocketAddr, auth: Option<(String, String)> },
|
||||||
|
Https { host: SocketAddr, auth: Option<(String, String)> },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Proxy {
|
||||||
|
pub fn none() -> Self {
|
||||||
|
Self::None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn socks5(host: impl ToSocketAddrs) -> Self {
|
||||||
|
Self::Socks5 { host: host.to_socket_addrs().unwrap().next().unwrap(), auth: None }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn socks5_with_auth(host: impl ToSocketAddrs, user: String, password: String) -> Self {
|
||||||
|
Self::Socks5 { host: host.to_socket_addrs().unwrap().next().unwrap(), auth: Some((user, password)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn socks4(host: impl ToSocketAddrs, user_id: String) -> Self {
|
||||||
|
Self::Socks4 { host: host.to_socket_addrs().unwrap().next().unwrap(), user: user_id }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn http(host: impl ToSocketAddrs) -> Self {
|
||||||
|
Self::Http { host: host.to_socket_addrs().unwrap().next().unwrap(), auth: None }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn http_with_auth(host: impl ToSocketAddrs, user: String, password: String) -> Self {
|
||||||
|
Self::Http { host: host.to_socket_addrs().unwrap().next().unwrap(), auth: Some((user, password)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn https(host: impl ToSocketAddrs) -> Self {
|
||||||
|
Self::Https { host: host.to_socket_addrs().unwrap().next().unwrap(), auth: None }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn https_with_auth(host: impl ToSocketAddrs, user: String, password: String) -> Self {
|
||||||
|
Self::Https { host: host.to_socket_addrs().unwrap().next().unwrap(), auth: Some((user, password)) }
|
||||||
|
}
|
||||||
|
}
|
100
src/ezhttp/client/req_builder.rs
Normal file
100
src/ezhttp/client/req_builder.rs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
use std::{collections::HashMap, net::ToSocketAddrs};
|
||||||
|
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
use super::{super::body::{Body, Part}, gen_multipart_boundary, super::headers::Headers, super::request::{HttpRequest, URL}};
|
||||||
|
|
||||||
|
pub struct RequestBuilder {
|
||||||
|
method: String,
|
||||||
|
url: URL,
|
||||||
|
headers: Headers,
|
||||||
|
body: Option<Body>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RequestBuilder {
|
||||||
|
pub fn new(method: String, url: URL) -> Self {
|
||||||
|
RequestBuilder {
|
||||||
|
method,
|
||||||
|
url,
|
||||||
|
headers: Headers::new(),
|
||||||
|
body: None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(url: URL) -> Self { Self::new("GET".to_string(), url) }
|
||||||
|
pub fn head(url: URL) -> Self { Self::new("HEAD".to_string(), url) }
|
||||||
|
pub fn post(url: URL) -> Self { Self::new("POST".to_string(), url) }
|
||||||
|
pub fn put(url: URL) -> Self { Self::new("PUT".to_string(), url) }
|
||||||
|
pub fn delete(url: URL) -> Self { Self::new("DELETE".to_string(), url) }
|
||||||
|
pub fn connect(url: URL) -> Self { Self::new("CONNECT".to_string(), url) }
|
||||||
|
pub fn options(url: URL) -> Self { Self::new("OPTIONS".to_string(), url) }
|
||||||
|
pub fn trace(url: URL) -> Self { Self::new("TRACE".to_string(), url) }
|
||||||
|
pub fn patch(url: URL) -> Self { Self::new("PATCH".to_string(), url) }
|
||||||
|
|
||||||
|
pub fn url(mut self, url: URL) -> Self {
|
||||||
|
self.url = url;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn method(mut self, method: String) -> Self {
|
||||||
|
self.method = method;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn headers(mut self, headers: Headers) -> Self {
|
||||||
|
self.headers = headers;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn header(mut self, name: impl ToString, value: impl ToString) -> Self {
|
||||||
|
self.headers.put(name, value.to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn body(mut self, body: Body) -> Self {
|
||||||
|
self.body = Some(body);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn text(mut self, text: impl ToString) -> Self {
|
||||||
|
self.body = Some(Body::from_text(text.to_string().as_str()));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn json(mut self, json: Value) -> Self {
|
||||||
|
self.body = Some(Body::from_json(json));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bytes(mut self, bytes: &[u8]) -> Self {
|
||||||
|
self.body = Some(Body::from_bytes(bytes));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn multipart(mut self, parts: &[Part]) -> Self {
|
||||||
|
let boundary = gen_multipart_boundary();
|
||||||
|
self.headers.put("Content-Type", format!("multipart/form-data; boundary={}", boundary.clone()));
|
||||||
|
self.body = Some(Body::from_multipart(parts.to_vec(), boundary));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn url_query(mut self, query: &[(impl ToString, impl ToString)]) -> Self {
|
||||||
|
self.url.query = HashMap::from_iter(query.iter().map(|o| (o.0.to_string(), o.1.to_string())));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn body_query(mut self, query: &[(impl ToString, impl ToString)]) -> Self {
|
||||||
|
self.body = Some(Body::from_query(HashMap::from_iter(query.iter().map(|o| (o.0.to_string(), o.1.to_string())))));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(self) -> HttpRequest {
|
||||||
|
HttpRequest {
|
||||||
|
url: self.url,
|
||||||
|
method: self.method,
|
||||||
|
addr: "localhost:80".to_socket_addrs().unwrap().next().unwrap(),
|
||||||
|
headers: self.headers,
|
||||||
|
body: self.body.unwrap_or(Body::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,11 @@ pub enum HttpError {
|
|||||||
WriteBodyError,
|
WriteBodyError,
|
||||||
InvalidStatus,
|
InvalidStatus,
|
||||||
RequestError,
|
RequestError,
|
||||||
UrlError
|
UrlError,
|
||||||
|
ConnectError,
|
||||||
|
ShutdownError,
|
||||||
|
SslError,
|
||||||
|
UnknownScheme
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for HttpError {
|
impl std::fmt::Display for HttpError {
|
||||||
|
@ -7,7 +7,6 @@ pub mod server;
|
|||||||
pub mod client;
|
pub mod client;
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use super::*;
|
|
||||||
pub use super::error::*;
|
pub use super::error::*;
|
||||||
pub use super::headers::*;
|
pub use super::headers::*;
|
||||||
pub use super::request::*;
|
pub use super::request::*;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::{body::{Body, Part}, gen_multipart_boundary, read_line_crlf, headers::Headers, HttpError};
|
use super::{body::{Body, Part}, client::RequestBuilder, gen_multipart_boundary, headers::Headers, read_line_crlf, HttpError};
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap, fmt::{Debug, Display}, net::SocketAddr, str::FromStr
|
collections::HashMap, fmt::{Debug, Display}, net::SocketAddr, str::FromStr
|
||||||
@ -184,7 +184,7 @@ impl HttpRequest {
|
|||||||
|
|
||||||
self.headers.send(stream).await?;
|
self.headers.send(stream).await?;
|
||||||
|
|
||||||
stream.write_all(b"\r\n").await.map_err(|_| HttpError::WriteHeadError)?;
|
stream.write_all(b"\r\n").await.map_err(|_| HttpError::WriteBodyError)?;
|
||||||
|
|
||||||
self.body.send(stream).await?;
|
self.body.send(stream).await?;
|
||||||
|
|
||||||
@ -206,6 +206,10 @@ impl HttpRequest {
|
|||||||
self.body = Body::from_multipart(parts, boundary);
|
self.body = Body::from_multipart(parts, boundary);
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn builder(method: String, url: URL) -> RequestBuilder {
|
||||||
|
RequestBuilder::new(method, url)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ impl HttpResponse {
|
|||||||
|
|
||||||
self.headers.send(stream).await?;
|
self.headers.send(stream).await?;
|
||||||
|
|
||||||
stream.write_all(b"\r\n").await.map_err(|_| HttpError::WriteHeadError)?;
|
stream.write_all(b"\r\n").await.map_err(|_| HttpError::WriteBodyError)?;
|
||||||
|
|
||||||
self.body.send(stream).await?;
|
self.body.send(stream).await?;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user