diff --git a/.gitignore b/.gitignore index b309da6..a008342 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ /target **/*.rs.bk -/.idea \ No newline at end of file +.DS_store \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 20f0585..acfd7c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "autocfg" version = "1.0.1" @@ -91,7 +93,7 @@ dependencies = [ "native-tls", "rustls", "unicase", - "webpki", + "webpki 0.22.0", "webpki-roots", ] @@ -293,7 +295,7 @@ dependencies = [ "log", "ring", "sct", - "webpki", + "webpki 0.21.4", ] [[package]] @@ -483,13 +485,23 @@ dependencies = [ "untrusted", ] +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "webpki-roots" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82015b7e0b8bad8185994674a13a93306bea76cf5a16c5a181382fd3a5ec2376" +checksum = "b533367e7546a31c15093b12a273004b79eb3b57b15359af710460f9aee94cf8" dependencies = [ - "webpki", + "webpki 0.22.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index dfa43e1..c2faf9e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,11 +26,11 @@ version = "^0.19" optional = true [dependencies.webpki] -version = "^0.21" +version = "^0.22" optional = true [dependencies.webpki-roots] -version = "^0.21" +version = "^0.22" optional = true [badges] diff --git a/benches/bench.rs b/benches/bench.rs index 5b6e411..c877159 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -3,7 +3,7 @@ extern crate http_req; extern crate test; use http_req::{request::Request, response::Response, uri::Uri}; -use std::{fs::File, io::Read, time::Duration}; +use std::{convert::TryFrom, fs::File, io::Read, time::Duration}; use test::Bencher; #[bench] @@ -23,7 +23,7 @@ const URI: &str = "https://www.rust-lang.org/"; #[bench] fn request_send(b: &mut Bencher) { b.iter(|| { - let uri = URI.parse::().unwrap(); + let uri = Uri::try_from(URI).unwrap(); let timeout = Some(Duration::from_secs(6)); let mut writer = Vec::new(); @@ -38,5 +38,5 @@ fn request_send(b: &mut Bencher) { #[bench] fn parse_uri(b: &mut Bencher) { - b.iter(|| URI.parse::()); + b.iter(|| Uri::try_from(URI)); } diff --git a/examples/request_builder_get.rs b/examples/request_builder_get.rs index 5745571..52457d7 100644 --- a/examples/request_builder_get.rs +++ b/examples/request_builder_get.rs @@ -1,9 +1,9 @@ use http_req::{request::RequestBuilder, tls, uri::Uri}; -use std::net::TcpStream; +use std::{convert::TryFrom, net::TcpStream}; fn main() { //Parse uri and assign it to variable `addr` - let addr: Uri = "https://doc.rust-lang.org/".parse().unwrap(); + let addr: Uri = Uri::try_from("https://doc.rust-lang.org/").unwrap(); //Connect to remote host let stream = TcpStream::connect((addr.host().unwrap(), addr.corr_port())).unwrap(); diff --git a/src/request.rs b/src/request.rs index c82c872..364823c 100644 --- a/src/request.rs +++ b/src/request.rs @@ -6,6 +6,7 @@ use crate::{ uri::Uri, }; use std::{ + convert::TryFrom, fmt, io::{self, ErrorKind, Read, Write}, net::{TcpStream, ToSocketAddrs}, @@ -27,7 +28,7 @@ pub struct Counter { } impl Counter { - pub fn new(stop: usize) -> Counter { + pub const fn new(stop: usize) -> Counter { Counter { count: 0, stop } } } @@ -98,7 +99,7 @@ where R: Read + ?Sized, { let mut buf = [0; SMALL_BUF_SIZE]; - let mut writer = Vec::new(); + let mut writer = Vec::with_capacity(SMALL_BUF_SIZE); let mut counter = Counter::new(TEST_FREQ); let mut split_idx = 0; @@ -165,7 +166,7 @@ pub enum HttpVersion { } impl HttpVersion { - pub fn as_str(self) -> &'static str { + pub const fn as_str(self) -> &'static str { use self::HttpVersion::*; match self { @@ -189,10 +190,10 @@ impl fmt::Display for HttpVersion { /// ///# Examples ///``` -///use std::net::TcpStream; +///use std::{net::TcpStream, convert::TryFrom}; ///use http_req::{request::RequestBuilder, tls, uri::Uri, response::StatusCode}; /// -///let addr: Uri = "https://www.rust-lang.org/learn".parse().unwrap(); +///let addr: Uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); ///let mut writer = Vec::new(); /// ///let stream = TcpStream::connect((addr.host().unwrap(), addr.corr_port())).unwrap(); @@ -209,7 +210,7 @@ impl fmt::Display for HttpVersion { ///``` #[derive(Clone, Debug, PartialEq)] pub struct RequestBuilder<'a> { - uri: &'a Uri, + uri: &'a Uri<'a>, method: Method, version: HttpVersion, headers: Headers, @@ -222,10 +223,10 @@ impl<'a> RequestBuilder<'a> { /// ///# Examples ///``` - ///use std::net::TcpStream; + ///use std::{net::TcpStream, convert::TryFrom}; ///use http_req::{request::RequestBuilder, tls, uri::Uri}; /// - ///let addr: Uri = "https://www.rust-lang.org/learn".parse().unwrap(); + ///let addr = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); ///let mut writer = Vec::new(); /// ///let stream = TcpStream::connect((addr.host().unwrap(), addr.corr_port())).unwrap(); @@ -238,7 +239,7 @@ impl<'a> RequestBuilder<'a> { /// .send(&mut stream, &mut writer) /// .unwrap(); ///``` - pub fn new(uri: &'a Uri) -> RequestBuilder<'a> { + pub fn new(uri: &'a Uri<'a>) -> RequestBuilder<'a> { RequestBuilder { headers: Headers::default_http(uri), uri, @@ -253,10 +254,10 @@ impl<'a> RequestBuilder<'a> { /// ///# Examples ///``` - ///use std::net::TcpStream; + ///use std::{net::TcpStream, convert::TryFrom}; ///use http_req::{request::{RequestBuilder, Method}, tls, uri::Uri}; /// - ///let addr: Uri = "https://www.rust-lang.org/learn".parse().unwrap(); + ///let addr= Uri::try_from("https://www.rust-lang.org/learn").unwrap(); ///let mut writer = Vec::new(); /// ///let stream = TcpStream::connect((addr.host().unwrap(), addr.corr_port())).unwrap(); @@ -282,10 +283,10 @@ impl<'a> RequestBuilder<'a> { /// ///# Examples ///``` - ///use std::net::TcpStream; + ///use std::{net::TcpStream, convert::TryFrom}; ///use http_req::{request::{RequestBuilder, HttpVersion}, tls, uri::Uri}; /// - ///let addr: Uri = "https://www.rust-lang.org/learn".parse().unwrap(); + ///let addr = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); ///let mut writer = Vec::new(); /// ///let stream = TcpStream::connect((addr.host().unwrap(), addr.corr_port())).unwrap(); @@ -312,10 +313,10 @@ impl<'a> RequestBuilder<'a> { /// ///# Examples ///``` - ///use std::net::TcpStream; + ///use std::{net::TcpStream, convert::TryFrom}; ///use http_req::{request::{RequestBuilder, Method}, response::Headers, tls, uri::Uri}; /// - ///let addr: Uri = "https://www.rust-lang.org/learn".parse().unwrap(); + ///let addr = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); ///let mut writer = Vec::new(); ///let mut headers = Headers::new(); ///headers.insert("Accept-Charset", "utf-8"); @@ -345,10 +346,10 @@ impl<'a> RequestBuilder<'a> { /// ///# Examples ///``` - ///use std::net::TcpStream; + ///use std::{net::TcpStream, convert::TryFrom}; ///use http_req::{request::{RequestBuilder, Method}, tls, uri::Uri}; /// - ///let addr: Uri = "https://www.rust-lang.org/learn".parse().unwrap(); + ///let addr: Uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); ///let mut writer = Vec::new(); /// ///let stream = TcpStream::connect((addr.host().unwrap(), addr.corr_port())).unwrap(); @@ -374,10 +375,10 @@ impl<'a> RequestBuilder<'a> { /// ///# Examples ///``` - ///use std::net::TcpStream; + ///use std::{net::TcpStream, convert::TryFrom}; ///use http_req::{request::{RequestBuilder, Method}, tls, uri::Uri}; /// - ///let addr: Uri = "https://www.rust-lang.org/learn".parse().unwrap(); + ///let addr = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); ///const body: &[u8; 27] = b"field1=value1&field2=value2"; ///let mut writer = Vec::new(); /// @@ -403,10 +404,10 @@ impl<'a> RequestBuilder<'a> { /// ///# Examples ///``` - ///use std::{net::TcpStream, time::{Duration, Instant}}; + ///use std::{net::TcpStream, time::{Duration, Instant}, convert::TryFrom}; ///use http_req::{request::RequestBuilder, tls, uri::Uri}; /// - ///let addr: Uri = "https://www.rust-lang.org/learn".parse().unwrap(); + ///let addr = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); ///let mut writer = Vec::new(); /// ///let stream = TcpStream::connect((addr.host().unwrap(), addr.corr_port())).unwrap(); @@ -439,11 +440,11 @@ impl<'a> RequestBuilder<'a> { /// ///HTTP ///``` - ///use std::net::TcpStream; + ///use std::{net::TcpStream, convert::TryFrom}; ///use http_req::{request::RequestBuilder, uri::Uri}; /// /// //This address is automatically redirected to HTTPS, so response code will not ever be 200 - ///let addr: Uri = "http://www.rust-lang.org/learn".parse().unwrap(); + ///let addr = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); ///let mut writer = Vec::new(); ///let mut stream = TcpStream::connect((addr.host().unwrap(), addr.corr_port())).unwrap(); /// @@ -455,10 +456,10 @@ impl<'a> RequestBuilder<'a> { /// ///HTTPS ///``` - ///use std::net::TcpStream; + ///use std::{net::TcpStream, convert::TryFrom}; ///use http_req::{request::RequestBuilder, tls, uri::Uri}; /// - ///let addr: Uri = "https://www.rust-lang.org/learn".parse().unwrap(); + ///let addr: Uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); ///let mut writer = Vec::new(); /// ///let stream = TcpStream::connect((addr.host().unwrap(), addr.corr_port())).unwrap(); @@ -578,9 +579,10 @@ impl<'a> RequestBuilder<'a> { ///# Examples ///``` ///use http_req::{request::Request, uri::Uri, response::StatusCode}; +///use std::convert::TryFrom; /// ///let mut writer = Vec::new(); -///let uri: Uri = "https://www.rust-lang.org/learn".parse().unwrap(); +///let uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); /// ///let response = Request::new(&uri).send(&mut writer).unwrap();; ///assert_eq!(response.status_code(), StatusCode::new(200)); @@ -601,9 +603,10 @@ impl<'a> Request<'a> { ///# Examples ///``` ///use http_req::{request::Request, uri::Uri}; + ///use std::convert::TryFrom; /// ///let mut writer = Vec::new(); - ///let uri: Uri = "https://www.rust-lang.org/learn".parse().unwrap(); + ///let uri: Uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); /// ///let response = Request::new(&uri).send(&mut writer).unwrap();; ///``` @@ -625,9 +628,10 @@ impl<'a> Request<'a> { ///# Examples ///``` ///use http_req::{request::{Request, Method}, uri::Uri}; + ///use std::convert::TryFrom; /// ///let mut writer = Vec::new(); - ///let uri: Uri = "https://www.rust-lang.org/learn".parse().unwrap(); + ///let uri: Uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); /// ///let response = Request::new(&uri) /// .method(Method::HEAD) @@ -647,9 +651,10 @@ impl<'a> Request<'a> { ///# Examples ///``` ///use http_req::{request::{Request, HttpVersion}, uri::Uri}; + ///use std::convert::TryFrom; /// ///let mut writer = Vec::new(); - ///let uri: Uri = "https://www.rust-lang.org/learn".parse().unwrap(); + ///let uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); /// ///let response = Request::new(&uri) /// .version(HttpVersion::Http10) @@ -670,9 +675,10 @@ impl<'a> Request<'a> { ///# Examples ///``` ///use http_req::{request::Request, uri::Uri, response::Headers}; + ///use std::convert::TryFrom; /// ///let mut writer = Vec::new(); - ///let uri: Uri = "https://www.rust-lang.org/learn".parse().unwrap(); + ///let uri: Uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); /// ///let mut headers = Headers::new(); ///headers.insert("Accept-Charset", "utf-8"); @@ -698,9 +704,10 @@ impl<'a> Request<'a> { ///# Examples ///``` ///use http_req::{request::Request, uri::Uri}; + ///use std::convert::TryFrom; /// ///let mut writer = Vec::new(); - ///let uri: Uri = "https://www.rust-lang.org/learn".parse().unwrap(); + ///let uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); /// ///let response = Request::new(&uri) /// .header("Accept-Language", "en-US") @@ -721,9 +728,10 @@ impl<'a> Request<'a> { ///# Examples ///``` ///use http_req::{request::{Request, Method}, uri::Uri}; + ///use std::convert::TryFrom; /// ///let mut writer = Vec::new(); - ///let uri: Uri = "https://www.rust-lang.org/learn".parse().unwrap(); + ///let uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); ///const body: &[u8; 27] = b"field1=value1&field2=value2"; /// ///let response = Request::new(&uri) @@ -742,11 +750,11 @@ impl<'a> Request<'a> { /// ///# Examples ///``` - ///use std::time::{Duration, Instant}; + ///use std::{time::{Duration, Instant}, convert::TryFrom}; ///use http_req::{request::Request, uri::Uri}; /// ///let mut writer = Vec::new(); - ///let uri: Uri = "https://www.rust-lang.org/learn".parse().unwrap(); + ///let uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); ///const body: &[u8; 27] = b"field1=value1&field2=value2"; ///let timeout = Some(Duration::from_secs(3600)); /// @@ -777,10 +785,10 @@ impl<'a> Request<'a> { ///# Examples ///``` ///use http_req::{request::Request, uri::Uri}; - ///use std::time::Duration; + ///use std::{time::Duration, convert::TryFrom}; /// ///let mut writer = Vec::new(); - ///let uri: Uri = "https://www.rust-lang.org/learn".parse().unwrap(); + ///let uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); ///const time: Option = Some(Duration::from_secs(10)); /// ///let response = Request::new(&uri) @@ -806,10 +814,10 @@ impl<'a> Request<'a> { ///# Examples ///``` ///use http_req::{request::Request, uri::Uri}; - ///use std::time::Duration; + ///use std::{time::Duration, convert::TryFrom}; /// ///let mut writer = Vec::new(); - ///let uri: Uri = "https://www.rust-lang.org/learn".parse().unwrap(); + ///let uri: Uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); ///const time: Option = Some(Duration::from_secs(15)); /// ///let response = Request::new(&uri) @@ -835,10 +843,10 @@ impl<'a> Request<'a> { ///# Examples ///``` ///use http_req::{request::Request, uri::Uri}; - ///use std::time::Duration; + ///use std::{time::Duration, convert::TryFrom}; /// ///let mut writer = Vec::new(); - ///let uri: Uri = "https://www.rust-lang.org/learn".parse().unwrap(); + ///let uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); ///const time: Option = Some(Duration::from_secs(5)); /// ///let response = Request::new(&uri) @@ -868,9 +876,10 @@ impl<'a> Request<'a> { ///# Examples ///``` ///use http_req::{request::Request, uri::Uri}; + ///use std::convert::TryFrom; /// ///let mut writer = Vec::new(); - ///let uri: Uri = "https://www.rust-lang.org/learn".parse().unwrap(); + ///let uri: Uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); /// ///let response = Request::new(&uri).send(&mut writer).unwrap(); ///``` @@ -942,7 +951,7 @@ where ///let response = request::get(uri, &mut writer).unwrap(); ///``` pub fn get, U: Write>(uri: T, writer: &mut U) -> Result { - let uri = uri.as_ref().parse::()?; + let uri = Uri::try_from(uri.as_ref())?; Request::new(&uri).send(writer) } @@ -958,7 +967,7 @@ pub fn get, U: Write>(uri: T, writer: &mut U) -> Result>(uri: T) -> Result { let mut writer = Vec::new(); - let uri = uri.as_ref().parse::()?; + let uri = Uri::try_from(uri.as_ref())?; Request::new(&uri).method(Method::HEAD).send(&mut writer) } @@ -976,11 +985,11 @@ pub fn head>(uri: T) -> Result { ///let response = request::post(uri, body, &mut writer).unwrap(); ///``` pub fn post, U: Write>( - uri: T, + uri: T, body: &[u8], writer: &mut U, ) -> Result { - let uri = uri.as_ref().parse::()?; + let uri = Uri::try_from(uri.as_ref())?; Request::new(&uri) .method(Method::POST) @@ -1056,13 +1065,13 @@ mod tests { #[test] fn request_b_new() { - RequestBuilder::new(&URI.parse().unwrap()); - RequestBuilder::new(&URI_S.parse().unwrap()); + RequestBuilder::new(&Uri::try_from(URI).unwrap()); + RequestBuilder::new(&Uri::try_from(URI_S).unwrap()); } #[test] fn request_b_method() { - let uri: Uri = URI.parse().unwrap(); + let uri = Uri::try_from(URI).unwrap(); let mut req = RequestBuilder::new(&uri); let req = req.method(Method::HEAD); @@ -1077,7 +1086,7 @@ mod tests { headers.insert("Host", "doc.rust-lang.org"); headers.insert("Connection", "Close"); - let uri: Uri = URI.parse().unwrap(); + let uri = Uri::try_from(URI).unwrap(); let mut req = RequestBuilder::new(&uri); let req = req.headers(headers.clone()); @@ -1086,7 +1095,7 @@ mod tests { #[test] fn request_b_header() { - let uri: Uri = URI.parse().unwrap(); + let uri = Uri::try_from(URI).unwrap(); let mut req = RequestBuilder::new(&uri); let k = "Connection"; let v = "Close"; @@ -1103,7 +1112,7 @@ mod tests { #[test] fn request_b_body() { - let uri: Uri = URI.parse().unwrap(); + let uri = Uri::try_from(URI).unwrap(); let mut req = RequestBuilder::new(&uri); let req = req.body(&BODY); @@ -1112,7 +1121,7 @@ mod tests { #[test] fn request_b_timeout() { - let uri = URI.parse().unwrap(); + let uri = Uri::try_from(URI).unwrap(); let mut req = RequestBuilder::new(&uri); let timeout = Some(Duration::from_secs(360)); @@ -1124,10 +1133,10 @@ mod tests { #[test] fn request_b_send() { let mut writer = Vec::new(); - let uri: Uri = URI.parse().unwrap(); + let uri = Uri::try_from(URI).unwrap(); let mut stream = TcpStream::connect((uri.host().unwrap_or(""), uri.corr_port())).unwrap(); - RequestBuilder::new(&URI.parse().unwrap()) + RequestBuilder::new(&Uri::try_from(URI).unwrap()) .header("Connection", "Close") .send(&mut stream, &mut writer) .unwrap(); @@ -1137,14 +1146,14 @@ mod tests { #[test] fn request_b_send_secure() { let mut writer = Vec::new(); - let uri: Uri = URI_S.parse().unwrap(); + let uri = Uri::try_from(URI_S).unwrap(); let stream = TcpStream::connect((uri.host().unwrap_or(""), uri.corr_port())).unwrap(); let mut secure_stream = tls::Config::default() .connect(uri.host().unwrap_or(""), stream) .unwrap(); - RequestBuilder::new(&URI_S.parse().unwrap()) + RequestBuilder::new(&Uri::try_from(URI_S).unwrap()) .header("Connection", "Close") .send(&mut secure_stream, &mut writer) .unwrap(); @@ -1152,7 +1161,7 @@ mod tests { #[test] fn request_b_parse_msg() { - let uri = URI.parse().unwrap(); + let uri = Uri::try_from(URI).unwrap(); let req = RequestBuilder::new(&uri); const DEFAULT_MSG: &str = "GET /std/string/index.html HTTP/1.1\r\n\ @@ -1172,13 +1181,13 @@ mod tests { #[test] fn request_new() { - let uri = URI.parse().unwrap(); + let uri = Uri::try_from(URI).unwrap(); Request::new(&uri); } #[test] fn request_method() { - let uri = URI.parse().unwrap(); + let uri = Uri::try_from(URI).unwrap(); let mut req = Request::new(&uri); req.method(Method::HEAD); @@ -1193,7 +1202,7 @@ mod tests { headers.insert("Host", "doc.rust-lang.org"); headers.insert("Connection", "Close"); - let uri: Uri = URI.parse().unwrap(); + let uri = Uri::try_from(URI).unwrap(); let mut req = Request::new(&uri); let req = req.headers(headers.clone()); @@ -1202,7 +1211,7 @@ mod tests { #[test] fn request_header() { - let uri: Uri = URI.parse().unwrap(); + let uri = Uri::try_from(URI).unwrap(); let mut req = Request::new(&uri); let k = "Accept-Language"; let v = "en-US"; @@ -1220,7 +1229,7 @@ mod tests { #[test] fn request_body() { - let uri = URI.parse().unwrap(); + let uri = Uri::try_from(URI).unwrap(); let mut req = Request::new(&uri); let req = req.body(&BODY); @@ -1229,7 +1238,7 @@ mod tests { #[test] fn request_timeout() { - let uri = URI.parse().unwrap(); + let uri = Uri::try_from(URI).unwrap(); let mut request = Request::new(&uri); let timeout = Some(Duration::from_secs(360)); @@ -1239,7 +1248,7 @@ mod tests { #[test] fn request_connect_timeout() { - let uri = URI.parse().unwrap(); + let uri = Uri::try_from(URI).unwrap(); let mut request = Request::new(&uri); request.connect_timeout(Some(Duration::from_nanos(1))); @@ -1255,7 +1264,7 @@ mod tests { #[ignore] #[test] fn request_read_timeout() { - let uri = URI.parse().unwrap(); + let uri = Uri::try_from(URI).unwrap(); let mut request = Request::new(&uri); request.read_timeout(Some(Duration::from_nanos(1))); @@ -1276,7 +1285,7 @@ mod tests { #[test] fn request_write_timeout() { - let uri = URI.parse().unwrap(); + let uri = Uri::try_from(URI).unwrap(); let mut request = Request::new(&uri); request.write_timeout(Some(Duration::from_nanos(100))); @@ -1286,7 +1295,7 @@ mod tests { #[test] fn request_send() { let mut writer = Vec::new(); - let uri = URI.parse().unwrap(); + let uri = Uri::try_from(URI).unwrap(); let res = Request::new(&uri).send(&mut writer).unwrap(); assert_ne!(res.status_code(), UNSUCCESS_CODE); diff --git a/src/response.rs b/src/response.rs index 2520f86..30bac49 100644 --- a/src/response.rs +++ b/src/response.rs @@ -92,7 +92,7 @@ impl Response { ///let response = Response::try_from(RESPONSE, &mut body).unwrap(); ///assert_eq!(response.status_code(), StatusCode::new(200)); ///``` - pub fn status_code(&self) -> StatusCode { + pub const fn status_code(&self) -> StatusCode { self.status.code } @@ -188,6 +188,12 @@ pub struct Status { reason: String, } +impl Status { + pub fn new(version: &str, code: StatusCode, reason: &str) -> Status { + Status::from((version, code, reason)) + } +} + impl From<(T, U, V)> for Status where T: ToString, @@ -325,8 +331,9 @@ impl Headers { ///# Examples ///``` ///use http_req::{response::Headers, uri::Uri}; + ///use std::convert::TryFrom; /// - ///let uri: Uri = "https://www.rust-lang.org/learn".parse().unwrap(); + ///let uri: Uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); ///let headers = Headers::default_http(&uri); ///``` pub fn default_http(uri: &Uri) -> Headers { @@ -419,7 +426,7 @@ impl StatusCode { ///const code: StatusCode = StatusCode::new(101); ///assert!(code.is_info()) ///``` - pub fn is_info(self) -> bool { + pub const fn is_info(self) -> bool { self.0 >= 100 && self.0 < 200 } @@ -432,7 +439,7 @@ impl StatusCode { ///const code: StatusCode = StatusCode::new(204); ///assert!(code.is_success()) ///``` - pub fn is_success(self) -> bool { + pub const fn is_success(self) -> bool { self.0 >= 200 && self.0 < 300 } @@ -445,7 +452,7 @@ impl StatusCode { ///const code: StatusCode = StatusCode::new(301); ///assert!(code.is_redirect()) ///``` - pub fn is_redirect(self) -> bool { + pub const fn is_redirect(self) -> bool { self.0 >= 300 && self.0 < 400 } @@ -458,7 +465,7 @@ impl StatusCode { ///const code: StatusCode = StatusCode::new(400); ///assert!(code.is_client_err()) ///``` - pub fn is_client_err(self) -> bool { + pub const fn is_client_err(self) -> bool { self.0 >= 400 && self.0 < 500 } @@ -471,7 +478,7 @@ impl StatusCode { ///const code: StatusCode = StatusCode::new(503); ///assert!(code.is_server_err()) ///``` - pub fn is_server_err(self) -> bool { + pub const fn is_server_err(self) -> bool { self.0 >= 500 && self.0 < 600 } @@ -497,7 +504,7 @@ impl StatusCode { ///const code: StatusCode = StatusCode::new(200); ///assert_eq!(code.reason(), Some("OK")) ///``` - pub fn reason(self) -> Option<&'static str> { + pub const fn reason(self) -> Option<&'static str> { let reason = match self.0 { 100 => "Continue", 101 => "Switching Protocols", @@ -615,6 +622,7 @@ where #[cfg(test)] mod tests { use super::*; + use std::convert::TryFrom; const RESPONSE: &[u8; 129] = b"HTTP/1.1 200 OK\r\n\ Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\ @@ -787,9 +795,7 @@ mod tests { #[test] fn headers_default_http() { - let uri = "http://doc.rust-lang.org/std/string/index.html" - .parse() - .unwrap(); + let uri = Uri::try_from("http://doc.rust-lang.org/std/string/index.html").unwrap(); let mut headers = Headers::with_capacity(4); headers.insert("Host", "doc.rust-lang.org"); diff --git a/src/uri.rs b/src/uri.rs index 08220c7..378a602 100644 --- a/src/uri.rs +++ b/src/uri.rs @@ -1,6 +1,7 @@ //! uri operations use crate::error::{Error, ParseErr}; use std::{ + convert::TryFrom, fmt, ops::{Index, Range}, str, @@ -40,6 +41,15 @@ impl From for Range { } } +impl Index for str { + type Output = str; + + #[inline] + fn index(&self, index: RangeC) -> &str { + &self[..][Range::from(index)] + } +} + impl Index for String { type Output = str; @@ -54,28 +64,30 @@ impl Index for String { ///# Example ///``` ///use http_req::uri::Uri; +///use std::convert::TryFrom; /// -///let uri: Uri = "https://user:info@foo.com:12/bar/baz?query#fragment".parse().unwrap(); +///let uri: Uri = Uri::try_from("https://user:info@foo.com:12/bar/baz?query#fragment").unwrap();; ///assert_eq!(uri.host(), Some("foo.com")); ///``` #[derive(Clone, Debug, PartialEq)] -pub struct Uri { - inner: String, +pub struct Uri<'a> { + inner: &'a str, scheme: RangeC, - authority: Option, + authority: Option>, path: Option, query: Option, fragment: Option, } -impl Uri { +impl<'a> Uri<'a> { ///Returns scheme of this `Uri`. /// ///# Example ///``` ///use http_req::uri::Uri; + ///use std::convert::TryFrom; /// - ///let uri: Uri = "https://user:info@foo.com:12/bar/baz?query#fragment".parse().unwrap(); + ///let uri: Uri = Uri::try_from("https://user:info@foo.com:12/bar/baz?query#fragment").unwrap();; ///assert_eq!(uri.scheme(), "https"); ///``` pub fn scheme(&self) -> &str { @@ -87,8 +99,9 @@ impl Uri { ///# Example ///``` ///use http_req::uri::Uri; + ///use std::convert::TryFrom; /// - ///let uri: Uri = "https://user:info@foo.com:12/bar/baz?query#fragment".parse().unwrap(); + ///let uri: Uri = Uri::try_from("https://user:info@foo.com:12/bar/baz?query#fragment").unwrap();; ///assert_eq!(uri.user_info(), Some("user:info")); ///``` pub fn user_info(&self) -> Option<&str> { @@ -100,8 +113,9 @@ impl Uri { ///# Example ///``` ///use http_req::uri::Uri; + ///use std::convert::TryFrom; /// - ///let uri: Uri = "https://user:info@foo.com:12/bar/baz?query#fragment".parse().unwrap(); + ///let uri: Uri = Uri::try_from("https://user:info@foo.com:12/bar/baz?query#fragment").unwrap();; ///assert_eq!(uri.host(), Some("foo.com")); ///``` pub fn host(&self) -> Option<&str> { @@ -113,8 +127,9 @@ impl Uri { ///# Example ///``` ///use http_req::uri::Uri; + ///use std::convert::TryFrom; /// - ///let uri: Uri = "https://user:info@foo.com:12/bar/baz?query#fragment".parse().unwrap(); + ///let uri: Uri = Uri::try_from("https://user:info@foo.com:12/bar/baz?query#fragment").unwrap();; ///assert_eq!(uri.host_header(), Some("foo.com:12".to_string())); ///``` pub fn host_header(&self) -> Option { @@ -129,8 +144,9 @@ impl Uri { ///# Example ///``` ///use http_req::uri::Uri; + ///use std::convert::TryFrom; /// - ///let uri: Uri = "https://user:info@foo.com:12/bar/baz?query#fragment".parse().unwrap(); + ///let uri: Uri = Uri::try_from("https://user:info@foo.com:12/bar/baz?query#fragment").unwrap();; ///assert_eq!(uri.port(), Some(12)); ///``` pub fn port(&self) -> Option { @@ -143,8 +159,9 @@ impl Uri { ///# Example ///``` ///use http_req::uri::Uri; + ///use std::convert::TryFrom; /// - ///let uri: Uri = "https://user:info@foo.com:12/bar/baz?query#fragment".parse().unwrap(); + ///let uri: Uri = Uri::try_from("https://user:info@foo.com:12/bar/baz?query#fragment").unwrap();; ///assert_eq!(uri.corr_port(), 12); ///``` pub fn corr_port(&self) -> u16 { @@ -164,8 +181,9 @@ impl Uri { ///# Example ///``` ///use http_req::uri::Uri; + ///use std::convert::TryFrom; /// - ///let uri: Uri = "https://user:info@foo.com:12/bar/baz?query#fragment".parse().unwrap(); + ///let uri: Uri = Uri::try_from("https://user:info@foo.com:12/bar/baz?query#fragment").unwrap();; ///assert_eq!(uri.path(), Some("/bar/baz")); ///``` pub fn path(&self) -> Option<&str> { @@ -177,8 +195,9 @@ impl Uri { ///# Example ///``` ///use http_req::uri::Uri; + ///use std::convert::TryFrom; /// - ///let uri: Uri = "https://user:info@foo.com:12/bar/baz?query#fragment".parse().unwrap(); + ///let uri: Uri = Uri::try_from("https://user:info@foo.com:12/bar/baz?query#fragment").unwrap();; ///assert_eq!(uri.query(), Some("query")); ///``` pub fn query(&self) -> Option<&str> { @@ -190,8 +209,9 @@ impl Uri { ///# Example ///``` ///use http_req::uri::Uri; + ///use std::convert::TryFrom; /// - ///let uri: Uri = "https://user:info@foo.com:12/bar/baz?query#fragment".parse().unwrap(); + ///let uri: Uri = Uri::try_from("https://user:info@foo.com:12/bar/baz?query#fragment").unwrap();; ///assert_eq!(uri.fragment(), Some("fragment")); ///``` pub fn fragment(&self) -> Option<&str> { @@ -203,8 +223,9 @@ impl Uri { ///# Example ///``` ///use http_req::uri::Uri; + ///use std::convert::TryFrom; /// - ///let uri: Uri = "https://user:info@foo.com:12/bar/baz?query#fragment".parse().unwrap(); + ///let uri: Uri = Uri::try_from("https://user:info@foo.com:12/bar/baz?query#fragment").unwrap();; ///assert_eq!(uri.resource(), "/bar/baz?query#fragment"); ///``` pub fn resource(&self) -> &str { @@ -221,7 +242,7 @@ impl Uri { } } -impl fmt::Display for Uri { +impl<'a> fmt::Display for Uri<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let uri = if let Some(auth) = &self.authority { let mut uri = self.inner.to_string(); @@ -238,13 +259,10 @@ impl fmt::Display for Uri { } } -impl str::FromStr for Uri { - type Err = Error; - - fn from_str(s: &str) -> Result { - let mut s = s.to_string(); - remove_spaces(&mut s); +impl<'a> TryFrom<&'a str> for Uri<'a> { + type Error = Error; + fn try_from(s: &'a str) -> Result { let (scheme, mut uri_part) = get_chunks(&s, Some(RangeC::new(0, s.len())), ":"); let scheme = scheme.ok_or(ParseErr::UriErr)?; @@ -255,7 +273,7 @@ impl str::FromStr for Uri { let (auth, part) = get_chunks(&s, Some(RangeC::new(u.start + 2, u.end)), "/"); authority = if let Some(a) = auth { - Some(s[a].parse()?) + Some(Authority::try_from(&s[a])?) } else { None }; @@ -288,30 +306,32 @@ impl str::FromStr for Uri { ///# Example ///``` ///use http_req::uri::Authority; +///use std::convert::TryFrom; /// -///let auth: Authority = "user:info@foo.com:443".parse().unwrap(); +///let auth: Authority = Authority::try_from("user:info@foo.com:443").unwrap(); ///assert_eq!(auth.host(), "foo.com"); ///``` #[derive(Clone, Debug, PartialEq)] -pub struct Authority { - inner: String, +pub struct Authority<'a> { + inner: &'a str, username: Option, password: Option, host: RangeC, port: Option, } -impl Authority { +impl<'a> Authority<'a> { ///Returns username of this `Authority` /// ///# Example ///``` ///use http_req::uri::Authority; + ///use std::convert::TryFrom; /// - ///let auth: Authority = "user:info@foo.com:443".parse().unwrap(); + ///let auth: Authority = Authority::try_from("user:info@foo.com:443").unwrap(); ///assert_eq!(auth.username(), Some("user")); ///``` - pub fn username(&self) -> Option<&str> { + pub fn username(&self) -> Option<&'a str> { self.username.map(|r| &self.inner[r]) } @@ -320,8 +340,9 @@ impl Authority { ///# Example ///``` ///use http_req::uri::Authority; + ///use std::convert::TryFrom; /// - ///let auth: Authority = "user:info@foo.com:443".parse().unwrap(); + ///let auth: Authority = Authority::try_from("user:info@foo.com:443").unwrap(); ///assert_eq!(auth.password(), Some("info")); ///``` pub fn password(&self) -> Option<&str> { @@ -333,8 +354,9 @@ impl Authority { ///# Example ///``` ///use http_req::uri::Authority; + ///use std::convert::TryFrom; /// - ///let auth: Authority = "user:info@foo.com:443".parse().unwrap(); + ///let auth: Authority = Authority::try_from("user:info@foo.com:443").unwrap(); ///assert_eq!(auth.user_info(), Some("user:info")); ///``` pub fn user_info(&self) -> Option<&str> { @@ -350,8 +372,9 @@ impl Authority { ///# Example ///``` ///use http_req::uri::Authority; + ///use std::convert::TryFrom; /// - ///let auth: Authority = "user:info@foo.com:443".parse().unwrap(); + ///let auth: Authority = Authority::try_from("user:info@foo.com:443").unwrap(); ///assert_eq!(auth.host(), "foo.com"); ///``` pub fn host(&self) -> &str { @@ -363,8 +386,9 @@ impl Authority { ///# Example ///``` ///use http_req::uri::Authority; + ///use std::convert::TryFrom; /// - ///let auth: Authority = "user:info@foo.com:443".parse().unwrap(); + ///let auth: Authority = Authority::try_from("user:info@foo.com:443").unwrap(); ///assert_eq!(auth.port(), Some(443)); ///``` pub fn port(&self) -> Option { @@ -372,12 +396,10 @@ impl Authority { } } -impl str::FromStr for Authority { - type Err = ParseErr; - - fn from_str(s: &str) -> Result { - let inner = s.to_string(); +impl<'a> TryFrom<&'a str> for Authority<'a> { + type Error = ParseErr; + fn try_from(s: &'a str) -> Result { let mut username = None; let mut password = None; @@ -402,13 +424,13 @@ impl str::FromStr for Authority { let host = host.ok_or(ParseErr::UriErr)?; if let Some(p) = port { - if inner[p].parse::().is_err() { + if s[p].parse::().is_err() { return Err(ParseErr::UriErr); } } Ok(Authority { - inner, + inner: s, username, password, host, @@ -417,7 +439,7 @@ impl str::FromStr for Authority { } } -impl fmt::Display for Authority { +impl<'a> fmt::Display for Authority<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let auth = if let Some(pass) = self.password { let range = Range::from(pass); @@ -436,7 +458,7 @@ impl fmt::Display for Authority { } //Removes whitespace from `text` -fn remove_spaces(text: &mut String) { +pub fn remove_spaces(text: &mut String) { text.retain(|c| !c.is_whitespace()); } @@ -502,9 +524,10 @@ mod tests { #[test] fn uri_full_parse() { - let uri = "abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1" - .parse::() - .unwrap(); + let uri = Uri::try_from( + "abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1", + ) + .unwrap(); assert_eq!(uri.scheme(), "abc"); assert_eq!(uri.user_info(), Some("username:password")); @@ -519,7 +542,7 @@ mod tests { #[test] fn uri_parse() { for uri in TEST_URIS.iter() { - uri.parse::().unwrap(); + Uri::try_from(*uri).unwrap(); } } @@ -527,7 +550,7 @@ mod tests { fn uri_scheme() { let uris: Vec<_> = TEST_URIS .iter() - .map(|uri| uri.parse::().unwrap()) + .map(|uri| Uri::try_from(*uri).unwrap()) .collect(); assert_eq!(uris[0].scheme(), "https"); @@ -541,7 +564,7 @@ mod tests { fn uri_uesr_info() { let uris: Vec<_> = TEST_URIS .iter() - .map(|uri| uri.parse::().unwrap()) + .map(|uri| Uri::try_from(*uri).unwrap()) .collect(); assert_eq!(uris[0].user_info(), Some("user:info")); @@ -555,7 +578,7 @@ mod tests { fn uri_host() { let uris: Vec<_> = TEST_URIS .iter() - .map(|uri| uri.parse::().unwrap()) + .map(|uri| Uri::try_from(*uri).unwrap()) .collect(); assert_eq!(uris[0].host(), Some("foo.com")); @@ -567,12 +590,11 @@ mod tests { #[test] fn uri_host_header() { - let uri_def: Uri = "https://en.wikipedia.org:443/wiki/Hypertext_Transfer_Protocol" - .parse() - .unwrap(); + let uri_def: Uri = + Uri::try_from("https://en.wikipedia.org:443/wiki/Hypertext_Transfer_Protocol").unwrap(); let uris: Vec<_> = TEST_URIS .iter() - .map(|uri| uri.parse::().unwrap()) + .map(|uri| Uri::try_from(*uri).unwrap()) .collect(); assert_eq!(uris[0].host_header(), Some("foo.com:12".to_string())); @@ -584,7 +606,7 @@ mod tests { fn uri_port() { let uris: Vec<_> = TEST_URIS .iter() - .map(|uri| uri.parse::().unwrap()) + .map(|uri| Uri::try_from(*uri).unwrap()) .collect(); assert_eq!(uris[0].port(), Some(12)); @@ -599,7 +621,7 @@ mod tests { fn uri_corr_port() { let uris: Vec<_> = TEST_URIS .iter() - .map(|uri| uri.parse::().unwrap()) + .map(|uri| Uri::try_from(*uri).unwrap()) .collect(); assert_eq!(uris[0].corr_port(), 12); @@ -613,7 +635,7 @@ mod tests { fn uri_path() { let uris: Vec<_> = TEST_URIS .iter() - .map(|uri| uri.parse::().unwrap()) + .map(|uri| Uri::try_from(*uri).unwrap()) .collect(); assert_eq!(uris[0].path(), Some("/bar/baz")); @@ -630,7 +652,7 @@ mod tests { fn uri_query() { let uris: Vec<_> = TEST_URIS .iter() - .map(|uri| uri.parse::().unwrap()) + .map(|uri| Uri::try_from(*uri).unwrap()) .collect(); assert_eq!(uris[0].query(), Some("query")); @@ -644,7 +666,7 @@ mod tests { fn uri_fragment() { let uris: Vec<_> = TEST_URIS .iter() - .map(|uri| uri.parse::().unwrap()) + .map(|uri| Uri::try_from(*uri).unwrap()) .collect(); assert_eq!(uris[0].fragment(), Some("fragment")); @@ -658,7 +680,7 @@ mod tests { fn uri_resource() { let uris: Vec<_> = TEST_URIS .iter() - .map(|uri| uri.parse::().unwrap()) + .map(|uri| Uri::try_from(*uri).unwrap()) .collect(); assert_eq!(uris[0].resource(), "/bar/baz?query#fragment"); @@ -672,7 +694,7 @@ mod tests { fn uri_display() { let uris: Vec<_> = TEST_URIS .iter() - .map(|uri| uri.parse::().unwrap()) + .map(|uri| Uri::try_from(*uri).unwrap()) .collect(); assert_eq!( @@ -690,7 +712,7 @@ mod tests { fn authority_username() { let auths: Vec<_> = TEST_AUTH .iter() - .map(|auth| auth.parse::().unwrap()) + .map(|auth| Authority::try_from(*auth).unwrap()) .collect(); assert_eq!(auths[0].username(), Some("user")); @@ -703,7 +725,7 @@ mod tests { fn authority_password() { let auths: Vec<_> = TEST_AUTH .iter() - .map(|auth| auth.parse::().unwrap()) + .map(|auth| Authority::try_from(*auth).unwrap()) .collect(); assert_eq!(auths[0].password(), Some("info")); @@ -716,7 +738,7 @@ mod tests { fn authority_host() { let auths: Vec<_> = TEST_AUTH .iter() - .map(|auth| auth.parse::().unwrap()) + .map(|auth| Authority::try_from(*auth).unwrap()) .collect(); assert_eq!(auths[0].host(), "foo.com"); @@ -729,7 +751,7 @@ mod tests { fn authority_port() { let auths: Vec<_> = TEST_AUTH .iter() - .map(|auth| auth.parse::().unwrap()) + .map(|auth| Authority::try_from(*auth).unwrap()) .collect(); assert_eq!(auths[0].port(), Some(12)); @@ -741,7 +763,7 @@ mod tests { #[test] fn authority_from_str() { for auth in TEST_AUTH.iter() { - auth.parse::().unwrap(); + Authority::try_from(*auth).unwrap(); } } @@ -749,7 +771,7 @@ mod tests { fn authority_display() { let auths: Vec<_> = TEST_AUTH .iter() - .map(|auth| auth.parse::().unwrap()) + .map(|auth| Authority::try_from(*auth).unwrap()) .collect(); assert_eq!("user:****@foo.com:12", auths[0].to_string());