From 76f0536eaaf4d1186fe9c34a310baa7ccdf7eaff Mon Sep 17 00:00:00 2001 From: jayjamesjay Date: Tue, 25 Jun 2024 09:57:10 +0200 Subject: [PATCH] improve docs and refactor stream --- LICENSE | 2 +- README.md | 9 +- examples/request_builder_get.rs | 26 +- src/chunked.rs | 13 +- src/error.rs | 2 +- src/lib.rs | 35 ++- src/request.rs | 537 ++++++++++++++++---------------- src/response.rs | 430 ++++++++++++------------- src/stream.rs | 123 +++++--- src/tls.rs | 34 +- src/uri.rs | 314 +++++++++---------- 11 files changed, 787 insertions(+), 738 deletions(-) diff --git a/LICENSE b/LICENSE index c972bbd..78d3280 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018-2023 jayjamesjay +Copyright (c) 2018-2024 jayjamesjay Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index ea6611c..e2cf333 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,10 @@ # http_req +> [!CAUTION] +> V0.11.0 introduces major changes to design of `RequestBuilder` and `Request`. Please review [documentation](https://docs.rs/http_req/0.11.0/http_req/) before migrating from previous versions. + [![Rust](https://github.com/jayjamesjay/http_req/actions/workflows/rust.yml/badge.svg)](https://github.com/jayjamesjay/http_req/actions/workflows/rust.yml) -[![Crates.io](https://img.shields.io/badge/crates.io-v0.10.3-orange.svg?longCache=true)](https://crates.io/crates/http_req) -[![Docs.rs](https://docs.rs/http_req/badge.svg)](https://docs.rs/http_req/0.10.3/http_req/) +[![Crates.io](https://img.shields.io/badge/crates.io-v0.11.0-orange.svg?longCache=true)](https://crates.io/crates/http_req) +[![Docs.rs](https://docs.rs/http_req/badge.svg)](https://docs.rs/http_req/0.11.0/http_req/) Simple and lightweight HTTP client with built-in HTTPS support. @@ -29,7 +32,7 @@ Take a look at [more examples](https://github.com/jayjamesjay/http_req/tree/mast In order to use `http_req` with `rustls` in your project, add the following lines to `Cargo.toml`: ```toml [dependencies] -http_req = {version="^0.10", default-features = false, features = ["rust-tls"]} +http_req = {version="^0.11", default-features = false, features = ["rust-tls"]} ``` ## License diff --git a/examples/request_builder_get.rs b/examples/request_builder_get.rs index ac72597..da13231 100644 --- a/examples/request_builder_get.rs +++ b/examples/request_builder_get.rs @@ -1,7 +1,12 @@ -use http_req::{request::RequestBuilder, response::Response, stream::Stream, uri::Uri}; +use http_req::{ + request::RequestBuilder, + response::Response, + stream::{self, Stream}, + uri::Uri, +}; use std::{ convert::TryFrom, - io::{BufRead, BufReader, Read, Write}, + io::{BufReader, Read, Write}, time::Duration, }; @@ -10,7 +15,7 @@ fn main() { let addr: Uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); //Containers for a server's response. - let mut raw_head = Vec::new(); + let raw_head; let mut body = Vec::new(); //Prepares a request message. @@ -18,8 +23,6 @@ fn main() { .header("Connection", "Close") .parse(); - println!("{:?}", String::from_utf8(request_msg.clone())); - //Connects to a server. Uses information from `addr`. let mut stream = Stream::new(&addr, Some(Duration::from_secs(60))).unwrap(); stream = Stream::try_to_https(stream, &addr, None).unwrap(); @@ -30,18 +33,7 @@ fn main() { //Wraps the stream in BufReader to make it easier to read from it. //Reads a response from the server and saves the head to `raw_head`, and the body to `body`. let mut stream = BufReader::new(stream); - loop { - match stream.read_until(0xA, &mut raw_head) { - Ok(0) | Err(_) => break, - Ok(len) => { - let full_len = raw_head.len(); - - if len == 2 && &raw_head[full_len - 2..] == b"\r\n" { - break; - } - } - } - } + raw_head = stream::read_head(&mut stream); stream.read_to_end(&mut body).unwrap(); //Parses and processes the response. diff --git a/src/chunked.rs b/src/chunked.rs index c17d6f1..44121fb 100644 --- a/src/chunked.rs +++ b/src/chunked.rs @@ -1,14 +1,13 @@ -//!implements the wire protocol for HTTP's "chunked" Transfer-Encoding. -/// -///It's a Rust version of the reference implementation in [Go][1]. +//! implements the wire protocol for HTTP's "chunked" Transfer-Encoding. +use crate::CR_LF; /// -///[1]: https://golang.google.cn/src/net/http/internal/chunked.go +/// It's a Rust version of the reference implementation in [Go][1]. +/// +/// [1]: https://golang.google.cn/src/net/http/internal/chunked.go /// - use std::io::{self, BufRead, BufReader, Error, ErrorKind, Read}; const MAX_LINE_LENGTH: usize = 4096; -const CR_LF: [u8; 2] = [b'\r', b'\n']; pub struct ChunkReader { check_end: bool, @@ -37,7 +36,7 @@ where } if let Ok(_) = self.reader.read_exact(&mut footer) { - if footer != CR_LF { + if &footer != CR_LF { self.err = Some(error_malformed_chunked_encoding()); break; } diff --git a/src/error.rs b/src/error.rs index 454a579..f653c81 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,4 @@ -//!error system +//! error system used around the library. use std::{error, fmt, io, num, str, sync::mpsc}; #[derive(Debug, PartialEq)] diff --git a/src/lib.rs b/src/lib.rs index 780c359..3f806de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,23 +1,26 @@ -//!Simple HTTP client with built-in HTTPS support. -//!Currently it's in heavy development and may frequently change. +//! Simple HTTP client with built-in HTTPS support. +//! Currently it's in heavy development and may frequently change. //! -//!## Example -//!Basic GET request -//!``` -//!use http_req::request; +//! ## Example +//! Basic GET request +//! ``` +//! use http_req::request; //! -//!fn main() { -//! //Container for body of a response -//! let mut body = Vec::new(); -//! let res = request::get("https://doc.rust-lang.org/", &mut body).unwrap(); +//! fn main() { +//! //Container for body of a response +//! let mut body = Vec::new(); +//! let res = request::get("https://doc.rust-lang.org/", &mut body).unwrap(); //! -//! println!("Status: {} {}", res.status_code(), res.reason()); -//!} -//!``` -pub mod uri; +//! println!("Status: {} {}", res.status_code(), res.reason()); +//! } +//! ``` +pub mod chunked; +pub mod error; pub mod request; pub mod response; pub mod stream; -pub mod chunked; pub mod tls; -pub mod error; +pub mod uri; + +pub(crate) const CR_LF: &[u8; 2] = b"\r\n"; +pub(crate) const LF: u8 = 0xA; diff --git a/src/request.rs b/src/request.rs index 2368b3b..246048f 100644 --- a/src/request.rs +++ b/src/request.rs @@ -18,7 +18,7 @@ use std::{ const CR_LF: &str = "\r\n"; const DEFAULT_REQ_TIMEOUT: u64 = 12 * 60 * 60; -///HTTP request methods +/// HTTP request methods #[derive(Debug, PartialEq, Clone, Copy)] pub enum Method { GET, @@ -48,7 +48,7 @@ impl fmt::Display for Method { } } -///HTTP versions +/// HTTP versions #[derive(Debug, PartialEq, Clone, Copy)] pub enum HttpVersion { Http10, @@ -74,19 +74,19 @@ impl fmt::Display for HttpVersion { } } -///Raw HTTP request that can be sent to any stream +/// Raw HTTP request that can be sent to any stream /// -///# Examples -///``` -///use std::convert::TryFrom; -///use http_req::{request::RequestBuilder, uri::Uri}; +/// # Examples +/// ``` +/// use std::convert::TryFrom; +/// use http_req::{request::RequestBuilder, uri::Uri}; /// -///let addr: Uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); +/// let addr: Uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); /// -///let mut request_msg = RequestBuilder::new(&addr) -/// .header("Connection", "Close") -/// .parse(); -///``` +/// let mut request_msg = RequestBuilder::new(&addr) +/// .header("Connection", "Close") +/// .parse(); +/// ``` #[derive(Clone, Debug, PartialEq)] pub struct RequestBuilder<'a> { uri: &'a Uri<'a>, @@ -97,18 +97,18 @@ pub struct RequestBuilder<'a> { } impl<'a> RequestBuilder<'a> { - ///Creates new `RequestBuilder` with default parameters + /// Creates a new `RequestBuilder` with default parameters /// - ///# Examples - ///``` - ///use std::convert::TryFrom; - ///use http_req::{request::RequestBuilder, uri::Uri}; + /// # Examples + /// ``` + /// use std::convert::TryFrom; + /// use http_req::{request::RequestBuilder, uri::Uri}; /// - ///let addr = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); + /// let addr = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); /// - ///let request_builder = RequestBuilder::new(&addr) - /// .header("Connection", "Close"); - ///``` + /// let request_builder = RequestBuilder::new(&addr) + /// .header("Connection", "Close"); + /// ``` pub fn new(uri: &'a Uri<'a>) -> RequestBuilder<'a> { RequestBuilder { headers: Headers::default_http(uri), @@ -119,18 +119,18 @@ impl<'a> RequestBuilder<'a> { } } - ///Sets request method + /// Sets the request method /// - ///# Examples - ///``` - ///use std::convert::TryFrom; - ///use http_req::{request::{RequestBuilder, Method}, uri::Uri}; + /// # Examples + /// ``` + /// use std::convert::TryFrom; + /// use http_req::{request::{RequestBuilder, Method}, uri::Uri}; /// - ///let addr = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); + /// let addr = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); /// - ///let request_builder = RequestBuilder::new(&addr) - /// .method(Method::HEAD); - ///``` + /// let request_builder = RequestBuilder::new(&addr) + /// .method(Method::HEAD); + /// ``` pub fn method(&mut self, method: T) -> &mut Self where Method: From, @@ -139,18 +139,18 @@ impl<'a> RequestBuilder<'a> { self } - ///Sets HTTP version + /// Sets the HTTP version /// - ///# Examples - ///``` - ///use std::convert::TryFrom; - ///use http_req::{request::{RequestBuilder, HttpVersion}, uri::Uri}; + /// # Examples + /// ``` + /// use std::convert::TryFrom; + /// use http_req::{request::{RequestBuilder, HttpVersion}, uri::Uri}; /// - ///let addr = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); + /// let addr = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); /// - ///let request_builder = RequestBuilder::new(&addr) - /// .version(HttpVersion::Http10); - ///``` + /// let request_builder = RequestBuilder::new(&addr) + /// .version(HttpVersion::Http10); + /// ``` pub fn version(&mut self, version: T) -> &mut Self where HttpVersion: From, @@ -159,24 +159,24 @@ impl<'a> RequestBuilder<'a> { self } - ///Replaces all it's headers with headers passed to the function + /// Replaces all it's headers with headers passed to the function /// - ///# Examples - ///``` - ///use std::convert::TryFrom; - ///use http_req::{request::RequestBuilder, response::Headers, uri::Uri}; + /// # Examples + /// ``` + /// use std::convert::TryFrom; + /// use http_req::{request::RequestBuilder, response::Headers, uri::Uri}; /// - ///let addr = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); + /// let addr = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); /// - ///let mut headers = Headers::new(); - ///headers.insert("Accept-Charset", "utf-8"); - ///headers.insert("Accept-Language", "en-US"); - ///headers.insert("Host", "rust-lang.org"); - ///headers.insert("Connection", "Close"); + /// let mut headers = Headers::new(); + /// headers.insert("Accept-Charset", "utf-8"); + /// headers.insert("Accept-Language", "en-US"); + /// headers.insert("Host", "rust-lang.org"); + /// headers.insert("Connection", "Close"); /// - ///let request_builder = RequestBuilder::new(&addr) - /// .headers(headers); - ///``` + /// let request_builder = RequestBuilder::new(&addr) + /// .headers(headers); + /// ``` pub fn headers(&mut self, headers: T) -> &mut Self where Headers: From, @@ -185,18 +185,18 @@ impl<'a> RequestBuilder<'a> { self } - ///Adds new header to existing/default headers + /// Adds a new header to existing/default headers /// - ///# Examples - ///``` - ///use std::convert::TryFrom; - ///use http_req::{request::RequestBuilder, response::Headers, uri::Uri}; + /// # Examples + /// ``` + /// use std::convert::TryFrom; + /// use http_req::{request::RequestBuilder, response::Headers, uri::Uri}; /// - ///let addr = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); + /// let addr = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); /// - ///let request_builder = RequestBuilder::new(&addr) - /// .header("Connection", "Close"); - ///``` + /// let request_builder = RequestBuilder::new(&addr) + /// .header("Connection", "Close"); + /// ``` pub fn header(&mut self, key: &T, val: &U) -> &mut Self where T: ToString + ?Sized, @@ -206,43 +206,40 @@ impl<'a> RequestBuilder<'a> { self } - ///Sets body for request + /// Sets the body for request /// - ///# Examples - ///``` - ///use std::convert::TryFrom; - ///use http_req::{request::{RequestBuilder, Method}, response::Headers, uri::Uri}; + /// # Examples + /// ``` + /// use std::convert::TryFrom; + /// use http_req::{request::{RequestBuilder, Method}, response::Headers, uri::Uri}; /// - ///let addr = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); - ///const BODY: &[u8; 27] = b"field1=value1&field2=value2"; + /// let addr = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); + /// const BODY: &[u8; 27] = b"field1=value1&field2=value2"; /// - ///let request_builder = RequestBuilder::new(&addr) - /// .method(Method::POST) - /// .body(BODY) - /// .header("Content-Length", &BODY.len()) - /// .header("Connection", "Close"); - ///``` + /// let request_builder = RequestBuilder::new(&addr) + /// .method(Method::POST) + /// .body(BODY) + /// .header("Content-Length", &BODY.len()) + /// .header("Connection", "Close"); + /// ``` pub fn body(&mut self, body: &'a [u8]) -> &mut Self { self.body = Some(body); self } - ///Parses request message for this `RequestBuilder` + /// Parses the request message for this `RequestBuilder` /// - ///# Examples - ///``` - ///use std::convert::TryFrom; - ///use http_req::{request::RequestBuilder, uri::Uri}; + /// # Examples + /// ``` + /// use std::convert::TryFrom; + /// use http_req::{request::RequestBuilder, uri::Uri}; /// - ///let addr: Uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); + /// let addr: Uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); /// - ///let mut request_msg = RequestBuilder::new(&addr) - /// .header("Connection", "Close") - /// .parse(); - /// - ///let expected_msg = "GET /learn HTTP/1.1\r\nHost: www.rust-lang.org\r\nConnection: Close\r\n\r\n"; - ///assert_eq!(String::from_utf8(request_msg).unwrap(), expected_msg); - ///``` + /// let mut request_msg = RequestBuilder::new(&addr) + /// .header("Connection", "Close") + /// .parse(); + /// ``` pub fn parse(&self) -> Vec { let request_line = format!( "{} {} {}{}", @@ -268,22 +265,22 @@ impl<'a> RequestBuilder<'a> { } } -///Allows for making HTTP requests based on specified parameters. +/// Allows for making HTTP requests based on specified parameters. /// -///It creates stream (`TcpStream` or `TlsStream`) appropriate for the type of uri (`http`/`https`). -///By default it closes connection after completion of the response. +/// It creates a stream (`TcpStream` or `TlsStream`) appropriate for the type of uri (`http`/`https`). +/// By default it closes connection after completion of the response. /// -///# Examples -///``` -///use http_req::{request::Request, uri::Uri, response::StatusCode}; -///use std::convert::TryFrom; +/// # Examples +/// ``` +/// use http_req::{request::Request, uri::Uri, response::StatusCode}; +/// use std::convert::TryFrom; /// -///let mut writer = Vec::new(); -///let uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); +/// let mut writer = Vec::new(); +/// 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)); -///``` +/// let response = Request::new(&uri).send(&mut writer).unwrap();; +/// assert_eq!(response.status_code(), StatusCode::new(200)); +/// ``` /// #[derive(Clone, Debug, PartialEq)] pub struct Request<'a> { @@ -296,18 +293,18 @@ pub struct Request<'a> { } impl<'a> Request<'a> { - ///Creates new `Request` with default parameters. + /// Creates a new `Request` with default parameters. /// - ///# Examples - ///``` - ///use http_req::{request::Request, uri::Uri}; - ///use std::convert::TryFrom; + /// # Examples + /// ``` + /// use http_req::{request::Request, uri::Uri}; + /// use std::convert::TryFrom; /// - ///let mut writer = Vec::new(); - ///let uri: Uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); + /// let mut writer = Vec::new(); + /// let uri: Uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); /// - ///let response = Request::new(&uri).send(&mut writer).unwrap();; - ///``` + /// let response = Request::new(&uri).send(&mut writer).unwrap();; + /// ``` pub fn new(uri: &'a Uri) -> Request<'a> { let mut builder = RequestBuilder::new(&uri); builder.header("Connection", "Close"); @@ -322,18 +319,18 @@ impl<'a> Request<'a> { } } - ///Sets request method. + /// Sets the request method. /// - ///# Examples - ///``` - ///use http_req::{request::{Request, Method}, uri::Uri}; - ///use std::convert::TryFrom; + /// # Examples + /// ``` + /// use http_req::{request::{Request, Method}, uri::Uri}; + /// use std::convert::TryFrom; /// - ///let uri: Uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); + /// let uri: Uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); /// - ///let response = Request::new(&uri) - /// .method(Method::HEAD); - ///``` + /// let response = Request::new(&uri) + /// .method(Method::HEAD); + /// ``` pub fn method(&mut self, method: T) -> &mut Self where Method: From, @@ -342,18 +339,18 @@ impl<'a> Request<'a> { self } - ///Sets HTTP version. + /// Sets the HTTP version. /// - ///# Examples - ///``` - ///use http_req::{request::{Request, HttpVersion}, uri::Uri}; - ///use std::convert::TryFrom; + /// # Examples + /// ``` + /// use http_req::{request::{Request, HttpVersion}, uri::Uri}; + /// use std::convert::TryFrom; /// - ///let uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); + /// let uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); /// - ///let response = Request::new(&uri) - /// .version(HttpVersion::Http10); - ///``` + /// let response = Request::new(&uri) + /// .version(HttpVersion::Http10); + /// ``` pub fn version(&mut self, version: T) -> &mut Self where @@ -363,24 +360,24 @@ impl<'a> Request<'a> { self } - ///Replaces all it's headers with headers passed to the function. + /// Replaces all it's headers with headers passed to the function. /// - ///# Examples - ///``` - ///use http_req::{request::Request, uri::Uri, response::Headers}; - ///use std::convert::TryFrom; + /// # Examples + /// ``` + /// use http_req::{request::Request, uri::Uri, response::Headers}; + /// use std::convert::TryFrom; /// - ///let uri: Uri = Uri::try_from("https://www.rust-lang.org/learn").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"); - ///headers.insert("Accept-Language", "en-US"); - ///headers.insert("Host", "rust-lang.org"); - ///headers.insert("Connection", "Close"); + /// let mut headers = Headers::new(); + /// headers.insert("Accept-Charset", "utf-8"); + /// headers.insert("Accept-Language", "en-US"); + /// headers.insert("Host", "rust-lang.org"); + /// headers.insert("Connection", "Close"); /// - ///let response = Request::new(&uri) - /// .headers(headers); - ///``` + /// let response = Request::new(&uri) + /// .headers(headers); + /// ``` pub fn headers(&mut self, headers: T) -> &mut Self where Headers: From, @@ -389,18 +386,18 @@ impl<'a> Request<'a> { self } - ///Adds header to existing/default headers. + /// Adds the header to existing/default headers. /// - ///# Examples - ///``` - ///use http_req::{request::Request, uri::Uri}; - ///use std::convert::TryFrom; + /// # Examples + /// ``` + /// use http_req::{request::Request, uri::Uri}; + /// use std::convert::TryFrom; /// - ///let uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); + /// let uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); /// - ///let response = Request::new(&uri) - /// .header("Accept-Language", "en-US"); - ///``` + /// let response = Request::new(&uri) + /// .header("Accept-Language", "en-US"); + /// ``` pub fn header(&mut self, key: &T, val: &U) -> &mut Self where T: ToString + ?Sized, @@ -410,48 +407,48 @@ impl<'a> Request<'a> { self } - ///Sets body for request. + /// Sets the body for request. /// - ///# Examples - ///``` - ///use http_req::{request::{Request, Method}, uri::Uri}; - ///use std::convert::TryFrom; + /// # Examples + /// ``` + /// use http_req::{request::{Request, Method}, uri::Uri}; + /// use std::convert::TryFrom; /// - ///let uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); - ///const body: &[u8; 27] = b"field1=value1&field2=value2"; + /// 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) - /// .method(Method::POST) - /// .header("Content-Length", &body.len()) - /// .body(body); - ///``` + /// let response = Request::new(&uri) + /// .method(Method::POST) + /// .header("Content-Length", &body.len()) + /// .body(body); + /// ``` pub fn body(&mut self, body: &'a [u8]) -> &mut Self { self.inner.body(body); self } - ///Sets connect timeout while using internal `TcpStream` instance. + /// Sets the connect timeout while using internal `TcpStream` instance. /// - ///- If there is a timeout, it will be passed to - /// [`TcpStream::connect_timeout`][TcpStream::connect_timeout]. - ///- If `None` is provided, [`TcpStream::connect`][TcpStream::connect] will - /// be used. A timeout will still be enforced by the operating system, but - /// the exact value depends on the platform. + /// - If there is a timeout, it will be passed to + /// [`TcpStream::connect_timeout`][TcpStream::connect_timeout]. + /// - If `None` is provided, [`TcpStream::connect`][TcpStream::connect] will + /// be used. A timeout will still be enforced by the operating system, but + /// the exact value depends on the platform. /// - ///[TcpStream::connect]: https://doc.rust-lang.org/std/net/struct.TcpStream.html#method.connect - ///[TcpStream::connect_timeout]: https://doc.rust-lang.org/std/net/struct.TcpStream.html#method.connect_timeout + /// [TcpStream::connect]: https://doc.rust-lang.org/std/net/struct.TcpStream.html#method.connect + /// [TcpStream::connect_timeout]: https://doc.rust-lang.org/std/net/struct.TcpStream.html#method.connect_timeout /// - ///# Examples - ///``` - ///use http_req::{request::Request, uri::Uri}; - ///use std::{time::Duration, convert::TryFrom}; + /// # Examples + /// ``` + /// use http_req::{request::Request, uri::Uri}; + /// use std::{time::Duration, convert::TryFrom}; /// - ///let uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); - ///const time: Option = Some(Duration::from_secs(10)); + /// 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) - /// .connect_timeout(time); - ///``` + /// let response = Request::new(&uri) + /// .connect_timeout(time); + /// ``` pub fn connect_timeout(&mut self, timeout: Option) -> &mut Self where Duration: From, @@ -460,24 +457,24 @@ impl<'a> Request<'a> { self } - ///Sets read timeout on internal `TcpStream` instance. + /// Sets the read timeout on internal `TcpStream` instance. /// - ///`timeout` will be passed to - ///[`TcpStream::set_read_timeout`][TcpStream::set_read_timeout]. + /// `timeout` will be passed to + /// [`TcpStream::set_read_timeout`][TcpStream::set_read_timeout]. /// - ///[TcpStream::set_read_timeout]: https://doc.rust-lang.org/std/net/struct.TcpStream.html#method.set_read_timeout + /// [TcpStream::set_read_timeout]: https://doc.rust-lang.org/std/net/struct.TcpStream.html#method.set_read_timeout /// - ///# Examples - ///``` - ///use http_req::{request::Request, uri::Uri}; - ///use std::{time::Duration, convert::TryFrom}; + /// # Examples + /// ``` + /// use http_req::{request::Request, uri::Uri}; + /// use std::{time::Duration, convert::TryFrom}; /// - ///let uri: Uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); - ///const time: Option = Some(Duration::from_secs(15)); + /// 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) - /// .read_timeout(time); - ///``` + /// let response = Request::new(&uri) + /// .read_timeout(time); + /// ``` pub fn read_timeout(&mut self, timeout: Option) -> &mut Self where Duration: From, @@ -486,24 +483,24 @@ impl<'a> Request<'a> { self } - ///Sets write timeout on internal `TcpStream` instance. + /// Sets the write timeout on internal `TcpStream` instance. /// - ///`timeout` will be passed to - ///[`TcpStream::set_write_timeout`][TcpStream::set_write_timeout]. + /// `timeout` will be passed to + /// [`TcpStream::set_write_timeout`][TcpStream::set_write_timeout]. /// - ///[TcpStream::set_write_timeout]: https://doc.rust-lang.org/std/net/struct.TcpStream.html#method.set_write_timeout + /// [TcpStream::set_write_timeout]: https://doc.rust-lang.org/std/net/struct.TcpStream.html#method.set_write_timeout /// - ///# Examples - ///``` - ///use http_req::{request::Request, uri::Uri}; - ///use std::{time::Duration, convert::TryFrom}; + /// # Examples + /// ``` + /// use http_req::{request::Request, uri::Uri}; + /// use std::{time::Duration, convert::TryFrom}; /// - ///let uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); - ///const time: Option = Some(Duration::from_secs(5)); + /// 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) - /// .write_timeout(time); - ///``` + /// let response = Request::new(&uri) + /// .write_timeout(time); + /// ``` pub fn write_timeout(&mut self, timeout: Option) -> &mut Self where Duration: From, @@ -512,20 +509,20 @@ impl<'a> Request<'a> { self } - ///Sets timeout on entire request. - ///Data is read from a stream until the timeout is reached or there is no more data to read. + /// Sets the timeout on entire request. + /// Data is read from a stream until there is no more data to read or the timeout is exceeded. /// - ///# Examples - ///``` - ///use http_req::{request::Request, uri::Uri}; - ///use std::{time::Duration, convert::TryFrom}; + /// # Examples + /// ``` + /// use http_req::{request::Request, uri::Uri}; + /// use std::{time::Duration, convert::TryFrom}; /// - ///let uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); - ///const time: Duration = Duration::from_secs(5); + /// let uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); + /// const time: Duration = Duration::from_secs(5); /// - ///let response = Request::new(&uri) - /// .timeout(time); - ///``` + /// let response = Request::new(&uri) + /// .timeout(time); + /// ``` pub fn timeout(&mut self, timeout: T) -> &mut Self where Duration: From, @@ -534,50 +531,50 @@ impl<'a> Request<'a> { self } - ///Add a file containing the PEM-encoded certificates that should be added in the trusted root store. + /// Adds the file containing the PEM-encoded certificates that should be added in the trusted root store. /// - ///# Examples - ///``` - ///use http_req::{request::Request, uri::Uri}; - ///use std::{time::Duration, convert::TryFrom, path::Path}; + /// # Examples + /// ``` + /// use http_req::{request::Request, uri::Uri}; + /// use std::{time::Duration, convert::TryFrom, path::Path}; /// - ///let uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); - ///let path = Path::new("./foo/bar.txt"); + /// let uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); + /// let path = Path::new("./foo/bar.txt"); /// - ///let response = Request::new(&uri) - /// .root_cert_file_pem(&path); - ///``` + /// let response = Request::new(&uri) + /// .root_cert_file_pem(&path); + /// ``` pub fn root_cert_file_pem(&mut self, file_path: &'a Path) -> &mut Self { self.root_cert_file_pem = Some(file_path); self } - ///Sends HTTP request and returns `Response`. + /// Sends the HTTP request and returns `Response`. /// - ///Creates `TcpStream` (and wraps it with `TlsStream` if needed). Writes request message - ///to created stream. Returns response for this request. Writes response's body to `writer`. + /// Creates `TcpStream` (and wraps it with `TlsStream` if needed). Writes request message + /// to created stream. Returns response for this request. Writes response's body to `writer`. /// - ///# Examples - ///``` - ///use http_req::{request::Request, uri::Uri}; - ///use std::convert::TryFrom; + /// # Examples + /// ``` + /// use http_req::{request::Request, uri::Uri}; + /// use std::convert::TryFrom; /// - ///let mut writer = Vec::new(); - ///let uri: Uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); + /// let mut writer = Vec::new(); + /// let uri: Uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); /// - ///let response = Request::new(&uri).send(&mut writer).unwrap(); - ///``` + /// let response = Request::new(&uri).send(&mut writer).unwrap(); + /// ``` pub fn send(&self, writer: &mut T) -> Result where T: Write, { - //Set up stream. + //Set up a stream. let mut stream = Stream::new(self.inner.uri, self.connect_timeout)?; stream.set_read_timeout(self.read_timeout)?; stream.set_write_timeout(self.write_timeout)?; stream = Stream::try_to_https(stream, self.inner.uri, self.root_cert_file_pem)?; - //Send request message to stream. + //Send the request message to stream. let request_msg = self.inner.parse(); stream.write_all(&request_msg)?; @@ -588,23 +585,23 @@ impl<'a> Request<'a> { let mut raw_response_head: Vec = Vec::new(); let mut buf_reader = BufReader::new(stream); - //Read from stream and send over data via `sender`. + //Read from the stream and send over data via `sender`. thread::spawn(move || { - buf_reader.read_head(&sender); + buf_reader.send_head(&sender); let params: Vec<&str> = receiver_supp.recv().unwrap(); if params.contains(&"non-empty") { if params.contains(&"chunked") { let mut buf_reader = ChunkReader::from(buf_reader); - buf_reader.read_body(&sender); + buf_reader.send_all(&sender); } else { - buf_reader.read_body(&sender); + buf_reader.send_all(&sender); } } }); //Receive and process `head` of the response. - raw_response_head.write_head(&receiver, deadline); + raw_response_head.receive(&receiver, deadline); let response = Response::from_head(&raw_response_head)?; let content_len = response.content_len().unwrap_or(1); @@ -625,24 +622,24 @@ impl<'a> Request<'a> { //Receive and process `body`` of the response. if content_len > 0 { - writer.write_body(&receiver, deadline); + writer.receive_all(&receiver, deadline); } Ok(response) } } -///Creates and sends GET request. Returns response for this request. +/// Creates and sends GET request. Returns response for this request. /// -///# Examples -///``` -///use http_req::request; +/// # Examples +/// ``` +/// use http_req::request; /// -///let mut writer = Vec::new(); -///const uri: &str = "https://www.rust-lang.org/learn"; +/// let mut writer = Vec::new(); +/// const uri: &str = "https://www.rust-lang.org/learn"; /// -///let response = request::get(uri, &mut writer).unwrap(); -///``` +/// let response = request::get(uri, &mut writer).unwrap(); +/// ``` pub fn get(uri: T, writer: &mut U) -> Result where T: AsRef, @@ -652,15 +649,15 @@ where Request::new(&uri).send(writer) } -///Creates and sends HEAD request. Returns response for this request. +/// Creates and sends HEAD request. Returns response for this request. /// -///# Examples -///``` -///use http_req::request; +/// # Examples +/// ``` +/// use http_req::request; /// -///const uri: &str = "https://www.rust-lang.org/learn"; -///let response = request::head(uri).unwrap(); -///``` +/// const uri: &str = "https://www.rust-lang.org/learn"; +/// let response = request::head(uri).unwrap(); +/// ``` pub fn head(uri: T) -> Result where T: AsRef, @@ -671,18 +668,18 @@ where Request::new(&uri).method(Method::HEAD).send(&mut writer) } -///Creates and sends POST request. Returns response for this request. +/// Creates and sends POST request. Returns response for this request. /// -///# Examples -///``` -///use http_req::request; +/// # Examples +/// ``` +/// use http_req::request; /// -///let mut writer = Vec::new(); -///const uri: &str = "https://www.rust-lang.org/learn"; -///const body: &[u8; 27] = b"field1=value1&field2=value2"; +/// let mut writer = Vec::new(); +/// const uri: &str = "https://www.rust-lang.org/learn"; +/// const body: &[u8; 27] = b"field1=value1&field2=value2"; /// -///let response = request::post(uri, body, &mut writer).unwrap(); -///``` +/// let response = request::post(uri, body, &mut writer).unwrap(); +/// ``` pub fn post(uri: T, body: &[u8], writer: &mut U) -> Result where T: AsRef, @@ -770,7 +767,7 @@ mod tests { } #[test] - fn request_b_parse_msg() { + fn request_b_parse() { let uri = Uri::try_from(URI).unwrap(); let req = RequestBuilder::new(&uri); diff --git a/src/response.rs b/src/response.rs index 857f7d5..895e6d6 100644 --- a/src/response.rs +++ b/src/response.rs @@ -13,9 +13,9 @@ use unicase::Ascii; pub(crate) const CR_LF_2: [u8; 4] = [13, 10, 13, 10]; -///Represents an HTTP response. +/// Represents an HTTP response. /// -///It contains `Headers` and `Status` parsed from response. +/// It contains `Headers` and `Status` parsed from response. #[derive(Debug, PartialEq, Clone)] pub struct Response { status: Status, @@ -23,19 +23,19 @@ pub struct Response { } impl Response { - ///Creates new `Response` with head - status and headers - parsed from a slice of bytes + /// Creates new `Response` with head - status and headers - parsed from a slice of bytes /// - ///# Examples - ///``` - ///use http_req::response::Response; + /// # Examples + /// ``` + /// use http_req::response::Response; /// - ///const HEAD: &[u8; 102] = b"HTTP/1.1 200 OK\r\n\ - /// Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\ - /// Content-Type: text/html\r\n\ - /// Content-Length: 100\r\n\r\n"; + /// const HEAD: &[u8; 102] = b"HTTP/1.1 200 OK\r\n\ + /// Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\ + /// Content-Type: text/html\r\n\ + /// Content-Length: 100\r\n\r\n"; /// - ///let response = Response::from_head(HEAD).unwrap(); - ///``` + /// let response = Response::from_head(HEAD).unwrap(); + /// ``` pub fn from_head(head: &[u8]) -> Result { let mut head = str::from_utf8(head)?.splitn(2, '\n'); @@ -45,21 +45,21 @@ impl Response { Ok(Response { status, headers }) } - ///Parses `Response` from slice of bytes. Writes it's body to `writer`. + /// Parses `Response` from slice of bytes. Writes it's body to `writer`. /// - ///# Examples - ///``` - ///use http_req::response::Response; + /// # Examples + /// ``` + /// use http_req::response::Response; /// - ///const RESPONSE: &[u8; 129] = b"HTTP/1.1 200 OK\r\n\ - /// Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\ - /// Content-Type: text/html\r\n\ - /// Content-Length: 100\r\n\r\n\ - /// hello\r\n\r\nhello"; - ///let mut body = Vec::new(); + /// const RESPONSE: &[u8; 129] = b"HTTP/1.1 200 OK\r\n\ + /// Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\ + /// Content-Type: text/html\r\n\ + /// Content-Length: 100\r\n\r\n\ + /// hello\r\n\r\nhello"; + /// let mut body = Vec::new(); /// - ///let response = Response::try_from(RESPONSE, &mut body).unwrap(); - ///``` + /// let response = Response::try_from(RESPONSE, &mut body).unwrap(); + /// ``` pub fn try_from(res: &[u8], writer: &mut T) -> Result { if res.is_empty() { Err(Error::Parse(ParseErr::Empty)) @@ -76,103 +76,103 @@ impl Response { } } - ///Returns status code of this `Response`. + /// Returns status code of this `Response`. /// - ///# Examples - ///``` - ///use http_req::response::{Response, StatusCode}; + /// # Examples + /// ``` + /// use http_req::response::{Response, StatusCode}; /// - ///const RESPONSE: &[u8; 129] = b"HTTP/1.1 200 OK\r\n\ - /// Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\ - /// Content-Type: text/html\r\n\ - /// Content-Length: 100\r\n\r\n\ - /// hello\r\n\r\nhello"; - ///let mut body = Vec::new(); + /// const RESPONSE: &[u8; 129] = b"HTTP/1.1 200 OK\r\n\ + /// Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\ + /// Content-Type: text/html\r\n\ + /// Content-Length: 100\r\n\r\n\ + /// hello\r\n\r\nhello"; + /// let mut body = Vec::new(); /// - ///let response = Response::try_from(RESPONSE, &mut body).unwrap(); - ///assert_eq!(response.status_code(), StatusCode::new(200)); - ///``` + /// let response = Response::try_from(RESPONSE, &mut body).unwrap(); + /// assert_eq!(response.status_code(), StatusCode::new(200)); + /// ``` pub const fn status_code(&self) -> StatusCode { self.status.code } - ///Returns HTTP version of this `Response`. + /// Returns HTTP version of this `Response`. /// - ///# Examples - ///``` - ///use http_req::response::Response; + /// # Examples + /// ``` + /// use http_req::response::Response; /// - ///const RESPONSE: &[u8; 129] = b"HTTP/1.1 200 OK\r\n\ - /// Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\ - /// Content-Type: text/html\r\n\ - /// Content-Length: 100\r\n\r\n\ - /// hello\r\n\r\nhello"; - ///let mut body = Vec::new(); + /// const RESPONSE: &[u8; 129] = b"HTTP/1.1 200 OK\r\n\ + /// Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\ + /// Content-Type: text/html\r\n\ + /// Content-Length: 100\r\n\r\n\ + /// hello\r\n\r\nhello"; + /// let mut body = Vec::new(); /// - ///let response = Response::try_from(RESPONSE, &mut body).unwrap(); - ///assert_eq!(response.version(), "HTTP/1.1"); - ///``` + /// let response = Response::try_from(RESPONSE, &mut body).unwrap(); + /// assert_eq!(response.version(), "HTTP/1.1"); + /// ``` pub fn version(&self) -> &str { &self.status.version } - ///Returns reason of this `Response`. + /// Returns reason of this `Response`. /// - ///# Examples - ///``` - ///use http_req::response::Response; + /// # Examples + /// ``` + /// use http_req::response::Response; /// - ///const RESPONSE: &[u8; 129] = b"HTTP/1.1 200 OK\r\n\ - /// Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\ - /// Content-Type: text/html\r\n\ - /// Content-Length: 100\r\n\r\n\ - /// hello\r\n\r\nhello"; - ///let mut body = Vec::new(); + /// const RESPONSE: &[u8; 129] = b"HTTP/1.1 200 OK\r\n\ + /// Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\ + /// Content-Type: text/html\r\n\ + /// Content-Length: 100\r\n\r\n\ + /// hello\r\n\r\nhello"; + /// let mut body = Vec::new(); /// - ///let response = Response::try_from(RESPONSE, &mut body).unwrap(); - ///assert_eq!(response.reason(), "OK"); - ///``` + /// let response = Response::try_from(RESPONSE, &mut body).unwrap(); + /// assert_eq!(response.reason(), "OK"); + /// ``` pub fn reason(&self) -> &str { &self.status.reason } - ///Returns headers of this `Response`. + /// Returns headers of this `Response`. /// - ///# Examples - ///``` - ///use http_req::response::Response; + /// # Examples + /// ``` + /// use http_req::response::Response; /// - ///const RESPONSE: &[u8; 129] = b"HTTP/1.1 200 OK\r\n\ - /// Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\ - /// Content-Type: text/html\r\n\ - /// Content-Length: 100\r\n\r\n\ - /// hello\r\n\r\nhello"; - ///let mut body = Vec::new(); + /// const RESPONSE: &[u8; 129] = b"HTTP/1.1 200 OK\r\n\ + /// Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\ + /// Content-Type: text/html\r\n\ + /// Content-Length: 100\r\n\r\n\ + /// hello\r\n\r\nhello"; + /// let mut body = Vec::new(); /// - ///let response = Response::try_from(RESPONSE, &mut body).unwrap(); - ///let headers = response.headers(); - ///``` + /// let response = Response::try_from(RESPONSE, &mut body).unwrap(); + /// let headers = response.headers(); + /// ``` pub fn headers(&self) -> &Headers { &self.headers } - ///Returns length of the content of this `Response` as a `Option`, according to information - ///included in headers. If there is no such an information, returns `None`. + /// Returns length of the content of this `Response` as a `Option`, according to information + /// included in headers. If there is no such an information, returns `None`. /// - ///# Examples - ///``` - ///use http_req::response::Response; + /// # Examples + /// ``` + /// use http_req::response::Response; /// - ///const RESPONSE: &[u8; 129] = b"HTTP/1.1 200 OK\r\n\ - /// Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\ - /// Content-Type: text/html\r\n\ - /// Content-Length: 100\r\n\r\n\ - /// hello\r\n\r\nhello"; - ///let mut body = Vec::new(); + /// const RESPONSE: &[u8; 129] = b"HTTP/1.1 200 OK\r\n\ + /// Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\ + /// Content-Type: text/html\r\n\ + /// Content-Length: 100\r\n\r\n\ + /// hello\r\n\r\nhello"; + /// let mut body = Vec::new(); /// - ///let response = Response::try_from(RESPONSE, &mut body).unwrap(); - ///assert_eq!(response.content_len().unwrap(), 100); - ///``` + /// let response = Response::try_from(RESPONSE, &mut body).unwrap(); + /// assert_eq!(response.content_len().unwrap(), 100); + /// ``` pub fn content_len(&self) -> Option { self.headers() .get("Content-Length") @@ -180,7 +180,7 @@ impl Response { } } -///Status of HTTP response +/// Status of HTTP response #[derive(PartialEq, Debug, Clone)] pub struct Status { version: String, @@ -226,98 +226,98 @@ impl str::FromStr for Status { } } -///Wrapper around `HashMap, String>` with additional functionality for parsing HTTP headers +/// Wrapper around `HashMap, String>` with additional functionality for parsing HTTP headers /// -///# Example -///``` -///use http_req::response::Headers; +/// # Example +/// ``` +/// use http_req::response::Headers; /// -///let mut headers = Headers::new(); -///headers.insert("Connection", "Close"); +/// let mut headers = Headers::new(); +/// headers.insert("Connection", "Close"); /// -///assert_eq!(headers.get("Connection"), Some(&"Close".to_string())) -///``` +/// assert_eq!(headers.get("Connection"), Some(&"Close".to_string())) +/// ``` #[derive(Debug, PartialEq, Clone, Default)] pub struct Headers(HashMap, String>); impl Headers { - ///Creates an empty `Headers`. + /// Creates an empty `Headers`. /// - ///The headers are initially created with a capacity of 0, so they will not allocate until - ///it is first inserted into. + /// The headers are initially created with a capacity of 0, so they will not allocate until + /// it is first inserted into. /// - ///# Examples - ///``` - ///use http_req::response::Headers; + /// # Examples + /// ``` + /// use http_req::response::Headers; /// - ///let mut headers = Headers::new(); - ///``` + /// let mut headers = Headers::new(); + /// ``` pub fn new() -> Headers { Headers(HashMap::new()) } - ///Creates empty `Headers` with the specified capacity. + /// Creates empty `Headers` with the specified capacity. /// - ///The headers will be able to hold at least capacity elements without reallocating. - ///If capacity is 0, the headers will not allocate. + /// The headers will be able to hold at least capacity elements without reallocating. + /// If capacity is 0, the headers will not allocate. /// - ///# Examples - ///``` - ///use http_req::response::Headers; + /// # Examples + /// ``` + /// use http_req::response::Headers; /// - ///let mut headers = Headers::with_capacity(200); - ///``` + /// let mut headers = Headers::with_capacity(200); + /// ``` pub fn with_capacity(capacity: usize) -> Headers { Headers(HashMap::with_capacity(capacity)) } - ///An iterator visiting all key-value pairs in arbitrary order. - ///The iterator's element type is `(&Ascii, &String)`. + /// An iterator visiting all key-value pairs in arbitrary order. + /// The iterator's element type is `(&Ascii, &String)`. /// - ///# Examples - ///``` - ///use http_req::response::Headers; + /// # Examples + /// ``` + /// use http_req::response::Headers; /// - ///let mut headers = Headers::new(); - ///headers.insert("Accept-Charset", "utf-8"); - ///headers.insert("Accept-Language", "en-US"); - ///headers.insert("Connection", "Close"); + /// let mut headers = Headers::new(); + /// headers.insert("Accept-Charset", "utf-8"); + /// headers.insert("Accept-Language", "en-US"); + /// headers.insert("Connection", "Close"); /// - ///let mut iterator = headers.iter(); - ///``` + /// let mut iterator = headers.iter(); + /// ``` pub fn iter(&self) -> hash_map::Iter, String> { self.0.iter() } - ///Returns a reference to the value corresponding to the key. + /// Returns a reference to the value corresponding to the key. /// - ///# Examples - ///``` - ///use http_req::response::Headers; + /// # Examples + /// ``` + /// use http_req::response::Headers; /// - ///let mut headers = Headers::new(); - ///headers.insert("Accept-Charset", "utf-8"); + /// let mut headers = Headers::new(); + /// headers.insert("Accept-Charset", "utf-8"); /// - ///assert_eq!(headers.get("Accept-Charset"), Some(&"utf-8".to_string())) - ///``` + /// assert_eq!(headers.get("Accept-Charset"), Some(&"utf-8".to_string())) + /// ``` pub fn get(&self, k: &T) -> Option<&std::string::String> { self.0.get(&Ascii::new(k.to_string())) } - ///Inserts a key-value pair into the headers. + /// Inserts a key-value pair into the headers. /// - ///If the headers did not have this key present, None is returned. + /// If the headers did not have this key present, None is returned. /// - ///If the headers did have this key present, the value is updated, and the old value is returned. - ///The key is not updated, though; this matters for types that can be == without being identical. + /// If the headers did have this key present, the value is updated, and the old value is returned. + /// The key is not updated, though; this matters for types that can be == without being identical. /// - ///# Examples - ///``` - ///use http_req::response::Headers; + /// # Examples + /// ``` + /// use http_req::response::Headers; /// - ///let mut headers = Headers::new(); - ///headers.insert("Accept-Language", "en-US"); - ///``` + /// let mut headers = Headers::new(); + /// headers.insert("Accept-Language", "en-US"); + /// ``` pub fn insert(&mut self, key: &T, val: &U) -> Option where T: ToString + ?Sized, @@ -326,16 +326,16 @@ impl Headers { self.0.insert(Ascii::new(key.to_string()), val.to_string()) } - ///Creates default headers for a HTTP request + /// Creates default headers for a HTTP request /// - ///# Examples - ///``` - ///use http_req::{response::Headers, uri::Uri}; - ///use std::convert::TryFrom; + /// # Examples + /// ``` + /// use http_req::{response::Headers, uri::Uri}; + /// use std::convert::TryFrom; /// - ///let uri: Uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap(); - ///let headers = Headers::default_http(&uri); - ///``` + /// 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 { let mut headers = Headers::with_capacity(4); headers.insert("Host", &uri.host_header().unwrap_or_default()); @@ -390,118 +390,118 @@ impl fmt::Display for Headers { } } -///Code sent by a server in response to a client's request. +/// Code sent by a server in response to a client's request. /// -///# Example -///``` -///use http_req::response::StatusCode; +/// # Example +/// ``` +/// use http_req::response::StatusCode; /// -///const code: StatusCode = StatusCode::new(200); -///assert!(code.is_success()) -///``` +/// const code: StatusCode = StatusCode::new(200); +/// assert!(code.is_success()) +/// ``` #[derive(Debug, PartialEq, Clone, Copy)] pub struct StatusCode(u16); impl StatusCode { - ///Creates new StatusCode from `u16` value. + /// Creates new StatusCode from `u16` value. /// - ///# Examples - ///``` - ///use http_req::response::StatusCode; + /// # Examples + /// ``` + /// use http_req::response::StatusCode; /// - ///const code: StatusCode = StatusCode::new(200); - ///``` + /// const code: StatusCode = StatusCode::new(200); + /// ``` pub const fn new(code: u16) -> StatusCode { StatusCode(code) } - ///Checks if this `StatusCode` is within 100-199, which indicates that it's Informational. + /// Checks if this `StatusCode` is within 100-199, which indicates that it's Informational. /// - ///# Examples - ///``` - ///use http_req::response::StatusCode; + /// # Examples + /// ``` + /// use http_req::response::StatusCode; /// - ///const code: StatusCode = StatusCode::new(101); - ///assert!(code.is_info()) - ///``` + /// const code: StatusCode = StatusCode::new(101); + /// assert!(code.is_info()) + /// ``` pub const fn is_info(self) -> bool { self.0 >= 100 && self.0 < 200 } - ///Checks if this `StatusCode` is within 200-299, which indicates that it's Successful. + /// Checks if this `StatusCode` is within 200-299, which indicates that it's Successful. /// - ///# Examples - ///``` - ///use http_req::response::StatusCode; + /// # Examples + /// ``` + /// use http_req::response::StatusCode; /// - ///const code: StatusCode = StatusCode::new(204); - ///assert!(code.is_success()) - ///``` + /// const code: StatusCode = StatusCode::new(204); + /// assert!(code.is_success()) + /// ``` pub const fn is_success(self) -> bool { self.0 >= 200 && self.0 < 300 } - ///Checks if this `StatusCode` is within 300-399, which indicates that it's Redirection. + /// Checks if this `StatusCode` is within 300-399, which indicates that it's Redirection. /// - ///# Examples - ///``` - ///use http_req::response::StatusCode; + /// # Examples + /// ``` + /// use http_req::response::StatusCode; /// - ///const code: StatusCode = StatusCode::new(301); - ///assert!(code.is_redirect()) - ///``` + /// const code: StatusCode = StatusCode::new(301); + /// assert!(code.is_redirect()) + /// ``` pub const fn is_redirect(self) -> bool { self.0 >= 300 && self.0 < 400 } - ///Checks if this `StatusCode` is within 400-499, which indicates that it's Client Error. + /// Checks if this `StatusCode` is within 400-499, which indicates that it's Client Error. /// - ///# Examples - ///``` - ///use http_req::response::StatusCode; + /// # Examples + /// ``` + /// use http_req::response::StatusCode; /// - ///const code: StatusCode = StatusCode::new(400); - ///assert!(code.is_client_err()) - ///``` + /// const code: StatusCode = StatusCode::new(400); + /// assert!(code.is_client_err()) + /// ``` pub const fn is_client_err(self) -> bool { self.0 >= 400 && self.0 < 500 } - ///Checks if this `StatusCode` is within 500-599, which indicates that it's Server Error. + /// Checks if this `StatusCode` is within 500-599, which indicates that it's Server Error. /// - ///# Examples - ///``` - ///use http_req::response::StatusCode; + /// # Examples + /// ``` + /// use http_req::response::StatusCode; /// - ///const code: StatusCode = StatusCode::new(503); - ///assert!(code.is_server_err()) - ///``` + /// const code: StatusCode = StatusCode::new(503); + /// assert!(code.is_server_err()) + /// ``` pub const fn is_server_err(self) -> bool { self.0 >= 500 && self.0 < 600 } - ///Checks this `StatusCode` using closure `f` + /// Checks this `StatusCode` using closure `f` /// - ///# Examples - ///``` - ///use http_req::response::StatusCode; + /// # Examples + /// ``` + /// use http_req::response::StatusCode; /// - ///const code: StatusCode = StatusCode::new(203); - ///assert!(code.is(|i| i > 199 && i < 250)) - ///``` + /// const code: StatusCode = StatusCode::new(203); + /// assert!(code.is(|i| i > 199 && i < 250)) + /// ``` pub fn is bool>(self, f: F) -> bool { f(self.0) } - ///Returns `Reason-Phrase` corresponding to this `StatusCode` + /// Returns `Reason-Phrase` corresponding to this `StatusCode` /// - ///# Examples - ///``` - ///use http_req::response::StatusCode; + /// # Examples + /// ``` + /// use http_req::response::StatusCode; /// - ///const code: StatusCode = StatusCode::new(200); - ///assert_eq!(code.reason(), Some("OK")) - ///``` + /// const code: StatusCode = StatusCode::new(200); + /// assert_eq!(code.reason(), Some("OK")) + /// ``` pub const fn reason(self) -> Option<&'static str> { let reason = match self.0 { 100 => "Continue", @@ -601,7 +601,7 @@ impl str::FromStr for StatusCode { } } -///Finds elements slice `e` inside slice `data`. Returns position of the end of first match. +/// Finds elements slice `e` inside slice `data`. Returns position of the end of first match. pub fn find_slice(data: &[T], e: &[T]) -> Option where [T]: PartialEq, diff --git a/src/stream.rs b/src/stream.rs index de19204..aa37301 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -1,4 +1,6 @@ -use crate::{error::Error, tls, tls::Conn, uri::Uri}; +//! TCP stream + +use crate::{error::Error, tls, tls::Conn, uri::Uri, CR_LF, LF}; use std::{ io::{self, BufRead, Read, Write}, net::{TcpStream, ToSocketAddrs}, @@ -7,16 +9,17 @@ use std::{ time::{Duration, Instant}, }; -const CR_LF: &str = "\r\n"; const BUF_SIZE: usize = 1024 * 1024; -const RECEIVING_TIMEOUT: Duration = Duration::from_secs(60); +/// Wrapper around TCP stream for HTTP and HTTPS protocols. +/// Allows to perform common operations on underlying stream. pub enum Stream { Http(TcpStream), Https(Conn), } impl Stream { + /// Opens a TCP connection to a remote host with a connection timeout (if specified). pub fn new(uri: &Uri, connect_timeout: Option) -> Result { let host = uri.host().unwrap_or(""); let port = uri.corr_port(); @@ -29,6 +32,11 @@ impl Stream { Ok(Stream::Http(stream)) } + /// Tries to establish a secure connection over TLS. + /// + /// Checks if `uri` scheme denotes a HTTPS protocol: + /// - If yes, attemps to establish a secure connection + /// - Otherwise, returns the `stream` without any modification pub fn try_to_https( stream: Stream, uri: &Uri, @@ -55,17 +63,19 @@ impl Stream { } } + /// Sets the read timeout on the underlying TCP stream. pub fn set_read_timeout(&mut self, dur: Option) -> Result<(), Error> { match self { Stream::Http(stream) => Ok(stream.set_read_timeout(dur)?), - Stream::Https(_) => Err(Error::Tls), + Stream::Https(conn) => Ok(conn.get_mut().set_read_timeout(dur)?), } } + /// Sets the write timeout on the underlying TCP stream. pub fn set_write_timeout(&mut self, dur: Option) -> Result<(), Error> { match self { Stream::Http(stream) => Ok(stream.set_write_timeout(dur)?), - Stream::Https(_) => Err(Error::Tls), + Stream::Https(conn) => Ok(conn.get_mut().set_write_timeout(dur)?), } } } @@ -95,33 +105,23 @@ impl Write for Stream { } pub trait ThreadSend { - fn read_head(&mut self, sender: &Sender>); - fn read_body(&mut self, sender: &Sender>); + /// Reads `head` of the response and sends it via `sender` + fn send_head(&mut self, sender: &Sender>); + + /// Reads all bytes until EOF and sends them via `sender` + fn send_all(&mut self, sender: &Sender>); } impl ThreadSend for T where T: BufRead, { - fn read_head(&mut self, sender: &Sender>) { - loop { - let mut buf = Vec::new(); - - match self.read_until(0xA, &mut buf) { - Ok(0) | Err(_) => break, - Ok(len) => { - let filled_buf = buf[..len].to_owned(); - sender.send(filled_buf).unwrap(); - - if len == 2 && buf == CR_LF.as_bytes() { - break; - } - } - } - } + fn send_head(&mut self, sender: &Sender>) { + let buf = read_head(self); + sender.send(buf).unwrap(); } - fn read_body(&mut self, sender: &Sender>) { + fn send_all(&mut self, sender: &Sender>) { loop { let mut buf = vec![0; BUF_SIZE]; @@ -137,50 +137,48 @@ where } pub trait ThreadReceive { - fn write_head(&mut self, receiver: &Receiver>, deadline: Instant); - fn write_body(&mut self, receiver: &Receiver>, deadline: Instant); + /// Receives data from `receiver` and writes them into this writer. + /// Fails if `deadline` is exceeded. + fn receive(&mut self, receiver: &Receiver>, deadline: Instant); + + /// Continuosly receives data from `receiver` until there is no more data + /// or `deadline` is exceeded. Writes received data into this writer. + fn receive_all(&mut self, receiver: &Receiver>, deadline: Instant); } impl ThreadReceive for T where T: Write, { - fn write_head(&mut self, receiver: &Receiver>, deadline: Instant) { - execute_with_deadline(deadline, || { - let mut continue_reading = true; - - let data_read = match receiver.recv_timeout(RECEIVING_TIMEOUT) { + fn receive(&mut self, receiver: &Receiver>, deadline: Instant) { + execute_with_deadline(deadline, |remaining_time| { + let data_read = match receiver.recv_timeout(remaining_time) { Ok(data) => data, - Err(_) => return false, + Err(_) => return true, }; - if data_read == CR_LF.as_bytes() { - continue_reading = false; - } - self.write_all(&data_read).unwrap(); - - continue_reading + true }); } - fn write_body(&mut self, receiver: &Receiver>, deadline: Instant) { - execute_with_deadline(deadline, || { - let continue_reading = true; + fn receive_all(&mut self, receiver: &Receiver>, deadline: Instant) { + execute_with_deadline(deadline, |remaining_time| { + let is_complete = false; - let data_read = match receiver.recv_timeout(RECEIVING_TIMEOUT) { + let data_read = match receiver.recv_timeout(remaining_time) { Ok(data) => data, - Err(_) => return false, + Err(_) => return true, }; self.write_all(&data_read).unwrap(); - continue_reading + is_complete }); } } -///Connects to target host with a timeout +/// Connects to the target host with a specified timeout. pub fn connect_with_timeout(host: T, port: u16, timeout: U) -> io::Result where Duration: From, @@ -211,15 +209,46 @@ where )) } +/// Exexcutes a function in a loop until operation is completed +/// or deadline is reached. +/// +/// Function `func` needs to return `true` when the operation is complete. pub fn execute_with_deadline(deadline: Instant, mut func: F) where - F: FnMut() -> bool, + F: FnMut(Duration) -> bool, { loop { let now = Instant::now(); + let remaining_time = deadline - now; - if deadline < now || func() == false { + if deadline < now || func(remaining_time) == true { break; } } } + +/// Reads the head of HTTP response from `reader`. +/// +/// Reads from `reader` (line by line) until a blank line is found +/// indicating that all meta-information for the request has been sent. +pub fn read_head(reader: &mut B) -> Vec +where + B: BufRead, +{ + let mut buf = Vec::with_capacity(BUF_SIZE); + + loop { + match reader.read_until(LF, &mut buf) { + Ok(0) | Err(_) => break, + Ok(len) => { + let full_len = buf.len(); + + if len == 2 && &buf[full_len - 2..] == CR_LF { + break; + } + } + } + } + + buf +} diff --git a/src/tls.rs b/src/tls.rs index 5d6a713..343191d 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -1,4 +1,4 @@ -//!secure connection over TLS +//! secure connection over TLS use crate::error::Error as HttpError; use std::{ @@ -16,8 +16,9 @@ use crate::error::ParseErr; #[cfg(not(any(feature = "native-tls", feature = "rust-tls")))] compile_error!("one of the `native-tls` or `rust-tls` features must be enabled"); -///wrapper around TLS Stream, -///depends on selected TLS library +/// Wrapper around TLS Stream, depends on selected TLS library (`S: io::Read + io::Write`): +/// - native_tls: `TlsStream` +/// - rustls: `StreamOwned` pub struct Conn { #[cfg(feature = "native-tls")] stream: native_tls::TlsStream, @@ -26,6 +27,21 @@ pub struct Conn { stream: rustls::StreamOwned, } +impl Conn +where + S: io::Read + io::Write, +{ + /// Returns a reference to the underlying socket + pub fn get_ref(&self) -> &S { + self.stream.get_ref() + } + + /// Returns a mutable reference to the underlying socket + pub fn get_mut(&mut self) -> &mut S { + self.stream.get_mut() + } +} + impl io::Read for Conn { fn read(&mut self, buf: &mut [u8]) -> Result { let len = self.stream.read(buf); @@ -58,7 +74,7 @@ impl io::Write for Conn { } } -///client configuration +/// Client configuration for TLS connection. pub struct Config { #[cfg(feature = "native-tls")] extra_root_certs: Vec, @@ -84,6 +100,7 @@ impl Default for Config { ta.name_constraints, ) })); + Config { root_certs: std::sync::Arc::new(root_store), } @@ -96,17 +113,20 @@ impl Config { let f = File::open(file_path)?; let f = BufReader::new(f); let mut pem_crt = vec![]; + for line in f.lines() { let line = line?; let is_end_cert = line.contains("-----END"); pem_crt.append(&mut line.into_bytes()); pem_crt.push(b'\n'); + if is_end_cert { let crt = native_tls::Certificate::from_pem(&pem_crt)?; self.extra_root_certs.push(crt); pem_crt.clear(); } } + Ok(self) } @@ -117,9 +137,11 @@ impl Config { S: io::Read + io::Write, { let mut connector_builder = native_tls::TlsConnector::builder(); + for crt in self.extra_root_certs.iter() { connector_builder.add_root_certificate((*crt).clone()); } + let connector = connector_builder.build()?; let stream = connector.connect(hostname.as_ref(), stream)?; @@ -130,8 +152,10 @@ impl Config { pub fn add_root_cert_file_pem(&mut self, file_path: &Path) -> Result<&mut Self, HttpError> { let f = File::open(file_path)?; let mut f = BufReader::new(f); + let root_certs = std::sync::Arc::make_mut(&mut self.root_certs); root_certs.add_parsable_certificates(&rustls_pemfile::certs(&mut f)?); + Ok(self) } @@ -147,11 +171,13 @@ impl Config { .with_safe_defaults() .with_root_certificates(self.root_certs.clone()) .with_no_client_auth(); + let session = ClientConnection::new( std::sync::Arc::new(client_config), hostname.as_ref().try_into().map_err(|_| HttpError::Tls)?, ) .map_err(|e| ParseErr::Rustls(e))?; + let stream = StreamOwned::new(session, stream); Ok(Conn { stream }) diff --git a/src/uri.rs b/src/uri.rs index a3e9301..ca76801 100644 --- a/src/uri.rs +++ b/src/uri.rs @@ -11,7 +11,7 @@ use std::{ const HTTP_PORT: u16 = 80; const HTTPS_PORT: u16 = 443; -///A (half-open) range bounded inclusively below and exclusively above (start..end) with `Copy`. +/// A (half-open) range bounded inclusively below and exclusively above (start..end) with `Copy`. #[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] pub struct RangeC { pub start: usize, @@ -19,14 +19,14 @@ pub struct RangeC { } impl RangeC { - ///Creates new `RangeC` with `start` and `end`. + /// Creates new `RangeC` with `start` and `end`. /// - ///# Exmaples - ///``` - ///use http_req::uri::RangeC; + /// # Exmaples + /// ``` + /// use http_req::uri::RangeC; /// - ///const range: RangeC = RangeC::new(0, 20); - ///``` + /// const range: RangeC = RangeC::new(0, 20); + /// ``` pub const fn new(start: usize, end: usize) -> RangeC { RangeC { start, end } } @@ -59,16 +59,16 @@ impl Index for String { } } -///Representation of Uniform Resource Identifier +/// Representation of Uniform Resource Identifier /// -///# Example -///``` -///use http_req::uri::Uri; -///use std::convert::TryFrom; +/// # Example +/// ``` +/// use http_req::uri::Uri; +/// use std::convert::TryFrom; /// -///let uri: Uri = Uri::try_from("https://user:info@foo.com:12/bar/baz?query#fragment").unwrap();; -///assert_eq!(uri.host(), Some("foo.com")); -///``` +/// 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<'a> { inner: &'a str, @@ -80,58 +80,58 @@ pub struct Uri<'a> { } impl<'a> Uri<'a> { - ///Returns scheme of this `Uri`. + /// Returns scheme of this `Uri`. /// - ///# Example - ///``` - ///use http_req::uri::Uri; - ///use std::convert::TryFrom; + /// # Example + /// ``` + /// use http_req::uri::Uri; + /// use std::convert::TryFrom; /// - ///let uri: Uri = Uri::try_from("https://user:info@foo.com:12/bar/baz?query#fragment").unwrap();; - ///assert_eq!(uri.scheme(), "https"); - ///``` + /// 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 { &self.inner[self.scheme] } - ///Returns information about the user included in this `Uri`. - /// - ///# Example - ///``` - ///use http_req::uri::Uri; - ///use std::convert::TryFrom; + /// Returns information about the user included in this `Uri`. + /// + /// # Example + /// ``` + /// use http_req::uri::Uri; + /// use std::convert::TryFrom; /// - ///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")); - ///``` + /// 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> { self.authority.as_ref().and_then(|a| a.user_info()) } - ///Returns host of this `Uri`. - /// - ///# Example - ///``` - ///use http_req::uri::Uri; - ///use std::convert::TryFrom; + /// Returns host of this `Uri`. + /// + /// # Example + /// ``` + /// use http_req::uri::Uri; + /// use std::convert::TryFrom; /// - ///let uri: Uri = Uri::try_from("https://user:info@foo.com:12/bar/baz?query#fragment").unwrap();; - ///assert_eq!(uri.host(), Some("foo.com")); - ///``` + /// 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> { self.authority.as_ref().map(|a| a.host()) } - ///Returns host of this `Uri` to use in a header. - /// - ///# Example - ///``` - ///use http_req::uri::Uri; - ///use std::convert::TryFrom; + /// Returns host of this `Uri` to use in a header. + /// + /// # Example + /// ``` + /// use http_req::uri::Uri; + /// use std::convert::TryFrom; /// - ///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())); - ///``` + /// 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 { self.host().map(|h| match self.corr_port() { HTTP_PORT | HTTPS_PORT => h.to_string(), @@ -139,31 +139,31 @@ impl<'a> Uri<'a> { }) } - ///Returns port of this `Uri` - /// - ///# Example - ///``` - ///use http_req::uri::Uri; - ///use std::convert::TryFrom; + /// Returns port of this `Uri` + /// + /// # Example + /// ``` + /// use http_req::uri::Uri; + /// use std::convert::TryFrom; /// - ///let uri: Uri = Uri::try_from("https://user:info@foo.com:12/bar/baz?query#fragment").unwrap();; - ///assert_eq!(uri.port(), Some(12)); - ///``` + /// 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 { self.authority.as_ref().and_then(|a| a.port()) } - ///Returns port corresponding to this `Uri`. - ///Returns default port if it hasn't been set in the uri. - /// - ///# Example - ///``` - ///use http_req::uri::Uri; - ///use std::convert::TryFrom; + /// Returns port corresponding to this `Uri`. + /// Returns default port if it hasn't been set in the uri. + /// + /// # Example + /// ``` + /// use http_req::uri::Uri; + /// use std::convert::TryFrom; /// - ///let uri: Uri = Uri::try_from("https://user:info@foo.com:12/bar/baz?query#fragment").unwrap();; - ///assert_eq!(uri.corr_port(), 12); - ///``` + /// 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 { let default_port = match self.scheme() { "https" => HTTPS_PORT, @@ -176,58 +176,58 @@ impl<'a> Uri<'a> { } } - ///Returns path of this `Uri`. - /// - ///# Example - ///``` - ///use http_req::uri::Uri; - ///use std::convert::TryFrom; + /// Returns path of this `Uri`. + /// + /// # Example + /// ``` + /// use http_req::uri::Uri; + /// use std::convert::TryFrom; /// - ///let uri: Uri = Uri::try_from("https://user:info@foo.com:12/bar/baz?query#fragment").unwrap();; - ///assert_eq!(uri.path(), Some("/bar/baz")); - ///``` + /// 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> { self.path.map(|r| &self.inner[r]) } - ///Returns query of this `Uri`. - /// - ///# Example - ///``` - ///use http_req::uri::Uri; - ///use std::convert::TryFrom; + /// Returns query of this `Uri`. + /// + /// # Example + /// ``` + /// use http_req::uri::Uri; + /// use std::convert::TryFrom; /// - ///let uri: Uri = Uri::try_from("https://user:info@foo.com:12/bar/baz?query#fragment").unwrap();; - ///assert_eq!(uri.query(), Some("query")); - ///``` + /// 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> { self.query.map(|r| &self.inner[r]) } - ///Returns fragment of this `Uri`. - /// - ///# Example - ///``` - ///use http_req::uri::Uri; - ///use std::convert::TryFrom; + /// Returns fragment of this `Uri`. + /// + /// # Example + /// ``` + /// use http_req::uri::Uri; + /// use std::convert::TryFrom; /// - ///let uri: Uri = Uri::try_from("https://user:info@foo.com:12/bar/baz?query#fragment").unwrap();; - ///assert_eq!(uri.fragment(), Some("fragment")); - ///``` + /// 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> { self.fragment.map(|r| &self.inner[r]) } - ///Returns resource `Uri` points to. - /// - ///# Example - ///``` - ///use http_req::uri::Uri; - ///use std::convert::TryFrom; + /// Returns resource `Uri` points to. + /// + /// # Example + /// ``` + /// use http_req::uri::Uri; + /// use std::convert::TryFrom; /// - ///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"); - ///``` + /// 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 { match self.path { Some(p) => &self.inner[p.start..], @@ -301,16 +301,16 @@ impl<'a> TryFrom<&'a str> for Uri<'a> { } } -///Authority of Uri +/// Authority of Uri /// -///# Example -///``` -///use http_req::uri::Authority; -///use std::convert::TryFrom; +/// # Example +/// ``` +/// use http_req::uri::Authority; +/// use std::convert::TryFrom; /// -///let auth: Authority = Authority::try_from("user:info@foo.com:443").unwrap(); -///assert_eq!(auth.host(), "foo.com"); -///``` +/// 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<'a> { inner: &'a str, @@ -321,44 +321,44 @@ pub struct Authority<'a> { } impl<'a> Authority<'a> { - ///Returns username of this `Authority` + /// Returns username of this `Authority` /// - ///# Example - ///``` - ///use http_req::uri::Authority; - ///use std::convert::TryFrom; + /// # Example + /// ``` + /// use http_req::uri::Authority; + /// use std::convert::TryFrom; /// - ///let auth: Authority = Authority::try_from("user:info@foo.com:443").unwrap(); - ///assert_eq!(auth.username(), Some("user")); - ///``` + /// let auth: Authority = Authority::try_from("user:info@foo.com:443").unwrap(); + /// assert_eq!(auth.username(), Some("user")); + /// ``` pub fn username(&self) -> Option<&'a str> { self.username.map(|r| &self.inner[r]) } - ///Returns password of this `Authority` + /// Returns password of this `Authority` /// - ///# Example - ///``` - ///use http_req::uri::Authority; - ///use std::convert::TryFrom; + /// # Example + /// ``` + /// use http_req::uri::Authority; + /// use std::convert::TryFrom; /// - ///let auth: Authority = Authority::try_from("user:info@foo.com:443").unwrap(); - ///assert_eq!(auth.password(), Some("info")); - ///``` + /// let auth: Authority = Authority::try_from("user:info@foo.com:443").unwrap(); + /// assert_eq!(auth.password(), Some("info")); + /// ``` pub fn password(&self) -> Option<&str> { self.password.map(|r| &self.inner[r]) } - ///Returns information about the user + /// Returns information about the user /// - ///# Example - ///``` - ///use http_req::uri::Authority; - ///use std::convert::TryFrom; + /// # Example + /// ``` + /// use http_req::uri::Authority; + /// use std::convert::TryFrom; /// - ///let auth: Authority = Authority::try_from("user:info@foo.com:443").unwrap(); - ///assert_eq!(auth.user_info(), Some("user:info")); - ///``` + /// 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> { match (&self.username, &self.password) { (Some(u), Some(p)) => Some(&self.inner[u.start..p.end]), @@ -367,30 +367,30 @@ impl<'a> Authority<'a> { } } - ///Returns host of this `Authority` + /// Returns host of this `Authority` /// - ///# Example - ///``` - ///use http_req::uri::Authority; - ///use std::convert::TryFrom; + /// # Example + /// ``` + /// use http_req::uri::Authority; + /// use std::convert::TryFrom; /// - ///let auth: Authority = Authority::try_from("user:info@foo.com:443").unwrap(); - ///assert_eq!(auth.host(), "foo.com"); - ///``` + /// let auth: Authority = Authority::try_from("user:info@foo.com:443").unwrap(); + /// assert_eq!(auth.host(), "foo.com"); + /// ``` pub fn host(&self) -> &str { &self.inner[self.host] } - ///Returns port of this `Authority` + /// Returns port of this `Authority` /// - ///# Example - ///``` - ///use http_req::uri::Authority; - ///use std::convert::TryFrom; + /// # Example + /// ``` + /// use http_req::uri::Authority; + /// use std::convert::TryFrom; /// - ///let auth: Authority = Authority::try_from("user:info@foo.com:443").unwrap(); - ///assert_eq!(auth.port(), Some(443)); - ///``` + /// let auth: Authority = Authority::try_from("user:info@foo.com:443").unwrap(); + /// assert_eq!(auth.port(), Some(443)); + /// ``` pub fn port(&self) -> Option { self.port.as_ref().map(|p| self.inner[*p].parse().unwrap()) } @@ -450,14 +450,14 @@ impl<'a> fmt::Display for Authority<'a> { } } -//Removes whitespace from `text` +/// Removes whitespace from `text` pub fn remove_spaces(text: &mut String) { text.retain(|c| !c.is_whitespace()); } -//Splits `s` by `separator`. If `separator` is found inside `s`, it will return two `Some` values -//consisting `RangeC` of each `&str`. If `separator` is at the end of `s` or it's not found, -//it will return tuple consisting `Some` with `RangeC` of entire `s` inside and None. +/// Splits `s` by `separator`. If `separator` is found inside `s`, it will return two `Some` values +/// consisting `RangeC` of each `&str`. If `separator` is at the end of `s` or it's not found, +/// it will return tuple consisting `Some` with `RangeC` of entire `s` inside and None. fn get_chunks<'a>( s: &'a str, range: Option,