simple_hyper_client/connector/
http.rs1use crate::connector::{NetworkConnection, NetworkConnector};
8use crate::connector_impl::connect;
9use hyper::Uri;
10use hyper_util::client::legacy::connect::{Connected, Connection};
11use std::error::Error as StdError;
12use std::future::Future;
13use std::pin::Pin;
14use std::task::{Context, Poll};
15use std::time::Duration;
16use std::{fmt, io};
17use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
18use tokio::net::TcpStream;
19
20pub(crate) const DEFAULT_HTTP_PORT: u16 = 80;
21pub(crate) const DEFAULT_HTTPS_PORT: u16 = 443;
22
23#[derive(Clone)]
29pub struct HttpConnector {
30 connect_timeout: Option<Duration>,
31}
32
33impl HttpConnector {
34 pub fn new() -> Self {
35 HttpConnector {
36 connect_timeout: None,
37 }
38 }
39
40 pub fn connect_timeout(mut self, timeout: Option<Duration>) -> Self {
42 self.connect_timeout = timeout;
43 self
44 }
45
46 pub async fn connect_raw(
48 &self,
49 uri: Uri,
50 ) -> Result<TcpStream, Box<dyn StdError + Send + Sync>> {
51 connect(uri, false, self.connect_timeout)
52 .await
53 .map(|conn| conn.into_tcp_stream())
54 .map_err(|err| Box::new(err) as _)
55 }
56}
57
58impl NetworkConnector for HttpConnector {
59 fn connect(
60 &self,
61 uri: Uri,
62 ) -> Pin<
63 Box<dyn Future<Output = Result<NetworkConnection, Box<dyn StdError + Send + Sync>>> + Send>,
64 > {
65 let connect_timeout = self.connect_timeout;
66 Box::pin(async move {
67 match connect(uri, false, connect_timeout).await {
68 Ok(conn) => Ok(NetworkConnection::new(conn)),
69 Err(e) => Err(Box::new(e) as _),
70 }
71 })
72 }
73}
74
75pub struct HttpConnection {
79 pub(crate) stream: TcpStream,
80}
81
82impl Connection for HttpConnection {
83 fn connected(&self) -> Connected {
84 Connected::new()
86 }
87}
88
89impl HttpConnection {
90 pub fn into_tcp_stream(self) -> TcpStream {
91 self.stream
92 }
93}
94
95impl AsyncRead for HttpConnection {
96 fn poll_read(
97 self: Pin<&mut Self>,
98 cx: &mut Context<'_>,
99 buf: &mut ReadBuf<'_>,
100 ) -> Poll<io::Result<()>> {
101 Pin::new(&mut self.get_mut().stream).poll_read(cx, buf)
102 }
103}
104
105impl AsyncWrite for HttpConnection {
106 fn poll_write(
107 self: Pin<&mut Self>,
108 cx: &mut Context<'_>,
109 buf: &[u8],
110 ) -> Poll<io::Result<usize>> {
111 Pin::new(&mut self.get_mut().stream).poll_write(cx, buf)
112 }
113
114 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
115 Pin::new(&mut self.get_mut().stream).poll_flush(cx)
116 }
117
118 fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
119 Pin::new(&mut self.get_mut().stream).poll_shutdown(cx)
120 }
121}
122
123pub struct ConnectError {
124 msg: &'static str,
125 cause: Option<Box<dyn StdError + Send + Sync>>,
126}
127
128impl ConnectError {
129 pub fn new(msg: &'static str) -> Self {
130 ConnectError { msg, cause: None }
131 }
132
133 pub fn cause<E: Into<Box<dyn StdError + Send + Sync>>>(mut self, cause: E) -> Self {
134 self.cause = Some(cause.into());
135 self
136 }
137}
138
139impl fmt::Debug for ConnectError {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 if let Some(ref cause) = self.cause {
142 f.debug_tuple("ConnectError")
143 .field(&self.msg)
144 .field(cause)
145 .finish()
146 } else {
147 self.msg.fmt(f)
148 }
149 }
150}
151
152impl fmt::Display for ConnectError {
153 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154 f.write_str(&self.msg)?;
155 if let Some(ref cause) = self.cause {
156 write!(f, ": {}", cause)?;
157 }
158 Ok(())
159 }
160}
161
162impl StdError for ConnectError {
163 fn source(&self) -> Option<&(dyn StdError + 'static)> {
164 self.cause.as_ref().map(|e| &**e as _)
165 }
166}