http_net/blocking.rs
1//! A small blocking adapter over `std::net`: the Tier-1 path.
2//!
3//! [`Server`] serves a handler on a socket with one thread per connection
4//! (bounded by [`ServerConfig::with_max_connections`]); [`Connection`] is the
5//! per-connection loop for callers who run their own accept loop or need the
6//! socket back after an upgrade; [`get`] fetches a URL. Everything here is a
7//! thin shell around [`ServerConn`] and [`ClientConn`]: all parsing, framing,
8//! and limit enforcement happens in the sans-IO core.
9//!
10//! Only plain `http://` is spoken; there is no TLS in this crate.
11
12use std::{
13 cell::Cell,
14 fmt, io,
15 io::{IoSlice, Read, Write},
16 net::{
17 IpAddr, Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, TcpListener, TcpStream, ToSocketAddrs,
18 },
19 string::{String, ToString},
20 sync::{
21 Arc, Condvar, Mutex,
22 atomic::{AtomicBool, Ordering},
23 },
24 thread,
25 time::{Duration, Instant, SystemTime, UNIX_EPOCH},
26 vec::Vec,
27};
28
29use crate::{
30 BodyPlan, ClientConn, ClientEvent, DateCache, HttpDate, HttpError, Limits, Method, Progress,
31 Request, RequestHead, Response, ServerConn, ServerEvent,
32 message::OutBody,
33 redact::{FieldValue, serialized_fields},
34};
35
36/// Bytes a closing connection reads and discards so the peer's unread data
37/// does not turn the close into a reset that destroys the last response.
38const DRAIN_LIMIT: usize = 256 * 1024;
39/// How long one read of the lingering close may wait.
40const DRAIN_READ_TIMEOUT: Duration = Duration::from_millis(250);
41/// How long the whole lingering close may take, however the peer behaves:
42/// a peer that keeps sending must not keep the connection (and its slot).
43const DRAIN_TOTAL: Duration = Duration::from_secs(1);
44/// Responses larger than this do not keep their output buffer afterwards.
45const OUT_RETAIN: usize = 64 * 1024;
46/// Full bodies larger than this are written after the head with one
47/// vectored write instead of being copied into the output buffer.
48const VECTORED_BODY: usize = 4 * 1024;
49
50/// What can go wrong in the blocking adapter.
51///
52/// # Examples
53///
54/// ```
55/// let err = http_net::blocking::get("https://example.com/").unwrap_err();
56/// assert!(matches!(err, http_net::blocking::Error::InvalidUrl(_)));
57/// ```
58#[non_exhaustive]
59#[derive(Debug)]
60pub enum Error {
61 /// The socket failed (connect, read, write, or timeout).
62 Io(io::Error),
63 /// The peer sent a message this crate refuses, or a call was out of
64 /// order.
65 Http(HttpError),
66 /// The URL is not `http://host[:port][/path][?query]`; the text says
67 /// which part is wrong.
68 InvalidUrl(&'static str),
69}
70
71impl fmt::Display for Error {
72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73 match self {
74 Self::Io(e) => write!(f, "I/O error: {e}"),
75 Self::Http(e) => write!(f, "HTTP error: {e}"),
76 Self::InvalidUrl(why) => write!(f, "invalid URL: {why}"),
77 }
78 }
79}
80
81impl std::error::Error for Error {
82 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
83 match self {
84 Self::Io(e) => Some(e),
85 Self::Http(e) => Some(e),
86 Self::InvalidUrl(_) => None,
87 }
88 }
89}
90
91impl From<io::Error> for Error {
92 fn from(e: io::Error) -> Self {
93 Self::Io(e)
94 }
95}
96
97impl From<HttpError> for Error {
98 fn from(e: HttpError) -> Self {
99 Self::Http(e)
100 }
101}
102
103/// Settings for [`Server`].
104///
105/// | Setting | Default |
106/// |---|---|
107/// | limits | [`Limits::new`] |
108/// | concurrent connections | 64 (the 65th is answered `503` and closed) |
109/// | read timeout (also the idle keep-alive timeout) | 10 s |
110/// | request timeout (first byte of a request to the end of its body) | 30 s |
111/// | write timeout (each write) | 10 s |
112/// | response deadline (writing one whole response) | 60 s |
113/// | requests per connection | no cap |
114///
115/// # Examples
116///
117/// ```
118/// use std::time::Duration;
119/// use http_net::{blocking::ServerConfig, Limits};
120///
121/// let config = ServerConfig::new()
122/// .with_limits(Limits::new().with_max_body(16 * 1024))
123/// .with_max_connections(8)
124/// .with_read_timeout(Some(Duration::from_secs(5)));
125/// assert_eq!(config.max_connections(), 8);
126/// ```
127#[derive(Clone, Copy, Debug, PartialEq, Eq)]
128pub struct ServerConfig {
129 limits: Limits,
130 max_connections: usize,
131 read_timeout: Option<Duration>,
132 request_timeout: Option<Duration>,
133 write_timeout: Option<Duration>,
134 response_deadline: Option<Duration>,
135 max_requests: Option<u64>,
136}
137
138impl Default for ServerConfig {
139 fn default() -> Self {
140 Self::new()
141 }
142}
143
144impl ServerConfig {
145 /// The defaults (see the table on [`ServerConfig`]).
146 ///
147 /// # Examples
148 ///
149 /// ```
150 /// assert_eq!(http_net::blocking::ServerConfig::new().max_connections(), 64);
151 /// ```
152 #[must_use]
153 pub const fn new() -> Self {
154 Self {
155 limits: Limits::new(),
156 max_connections: 64,
157 read_timeout: Some(Duration::from_secs(10)),
158 request_timeout: Some(Duration::from_secs(30)),
159 write_timeout: Some(Duration::from_secs(10)),
160 response_deadline: Some(Duration::from_secs(60)),
161 max_requests: None,
162 }
163 }
164
165 /// Sets the message limits for every connection.
166 ///
167 /// # Examples
168 ///
169 /// ```
170 /// let c = http_net::blocking::ServerConfig::new()
171 /// .with_limits(http_net::Limits::new().with_max_headers(10));
172 /// assert_eq!(c.limits().max_headers(), 10);
173 /// ```
174 #[must_use]
175 pub const fn with_limits(mut self, limits: Limits) -> Self {
176 self.limits = limits;
177 self
178 }
179
180 /// Sets how many connections are served at once (at least 1).
181 ///
182 /// # Examples
183 ///
184 /// ```
185 /// let c = http_net::blocking::ServerConfig::new().with_max_connections(0);
186 /// assert_eq!(c.max_connections(), 1);
187 /// ```
188 #[must_use]
189 pub const fn with_max_connections(mut self, n: usize) -> Self {
190 self.max_connections = if n == 0 { 1 } else { n };
191 self
192 }
193
194 /// Sets the socket read timeout: how long a request may take to arrive,
195 /// and how long an idle keep-alive connection is held. `None` waits
196 /// forever.
197 ///
198 /// # Examples
199 ///
200 /// ```
201 /// let c = http_net::blocking::ServerConfig::new().with_read_timeout(None);
202 /// assert_eq!(c.read_timeout(), None);
203 /// ```
204 #[must_use]
205 pub const fn with_read_timeout(mut self, timeout: Option<Duration>) -> Self {
206 self.read_timeout = timeout;
207 self
208 }
209
210 /// Sets the request timeout: the most time one request may take to
211 /// arrive, from its first byte to the end of its body. The read timeout
212 /// alone cannot stop a client that sends one byte just inside it
213 /// ("slowloris"); this deadline can. A request still incomplete when it
214 /// passes is answered `408 Request Timeout` and the connection closed.
215 /// Time spent idle between keep-alive requests does not count (the read
216 /// timeout governs that). `None` disables the deadline.
217 ///
218 /// # Examples
219 ///
220 /// ```
221 /// use std::time::Duration;
222 /// let c = http_net::blocking::ServerConfig::new().with_request_timeout(Some(Duration::from_secs(10)));
223 /// assert_eq!(c.request_timeout(), Some(Duration::from_secs(10)));
224 /// ```
225 #[must_use]
226 pub const fn with_request_timeout(mut self, timeout: Option<Duration>) -> Self {
227 self.request_timeout = timeout;
228 self
229 }
230
231 /// Sets the socket write timeout. `None` waits forever.
232 ///
233 /// # Examples
234 ///
235 /// ```
236 /// use std::time::Duration;
237 /// let c = http_net::blocking::ServerConfig::new().with_write_timeout(Some(Duration::from_secs(1)));
238 /// assert_eq!(c.write_timeout(), Some(Duration::from_secs(1)));
239 /// ```
240 #[must_use]
241 pub const fn with_write_timeout(mut self, timeout: Option<Duration>) -> Self {
242 self.write_timeout = timeout;
243 self
244 }
245
246 /// Sets the response deadline: the most time writing one response may
247 /// take, from its first byte to its last (a streamed body included).
248 /// The write timeout bounds each write; it cannot stop a client that
249 /// reads one byte just inside it and so holds a thread for as long as a
250 /// large response takes. This deadline can: when it passes, the
251 /// connection is closed. `None` disables it.
252 ///
253 /// # Examples
254 ///
255 /// ```
256 /// use std::time::Duration;
257 /// let c = http_net::blocking::ServerConfig::new().with_response_deadline(Some(Duration::from_secs(5)));
258 /// assert_eq!(c.response_deadline(), Some(Duration::from_secs(5)));
259 /// ```
260 #[must_use]
261 pub const fn with_response_deadline(mut self, deadline: Option<Duration>) -> Self {
262 self.response_deadline = deadline;
263 self
264 }
265
266 /// Sets the most requests served on one connection: the response that
267 /// reaches the cap carries `connection: close` and the connection ends
268 /// after it. `Some(0)` is raised to 1; `None` (the default) sets no cap.
269 ///
270 /// # Examples
271 ///
272 /// ```
273 /// let c = http_net::blocking::ServerConfig::new().with_max_requests_per_connection(Some(100));
274 /// assert_eq!(c.max_requests_per_connection(), Some(100));
275 /// ```
276 #[must_use]
277 pub const fn with_max_requests_per_connection(mut self, max: Option<u64>) -> Self {
278 self.max_requests = match max {
279 Some(0) => Some(1),
280 other => other,
281 };
282 self
283 }
284
285 /// The message limits.
286 ///
287 /// # Examples
288 ///
289 /// ```
290 /// assert_eq!(http_net::blocking::ServerConfig::new().limits(), http_net::Limits::new());
291 /// ```
292 #[must_use]
293 pub const fn limits(&self) -> Limits {
294 self.limits
295 }
296
297 /// The concurrent connection cap.
298 ///
299 /// # Examples
300 ///
301 /// ```
302 /// assert_eq!(http_net::blocking::ServerConfig::new().max_connections(), 64);
303 /// ```
304 #[must_use]
305 pub const fn max_connections(&self) -> usize {
306 self.max_connections
307 }
308
309 /// The read timeout.
310 ///
311 /// # Examples
312 ///
313 /// ```
314 /// use std::time::Duration;
315 /// assert_eq!(http_net::blocking::ServerConfig::new().read_timeout(), Some(Duration::from_secs(10)));
316 /// ```
317 #[must_use]
318 pub const fn read_timeout(&self) -> Option<Duration> {
319 self.read_timeout
320 }
321
322 /// The request timeout.
323 ///
324 /// # Examples
325 ///
326 /// ```
327 /// use std::time::Duration;
328 /// assert_eq!(http_net::blocking::ServerConfig::new().request_timeout(), Some(Duration::from_secs(30)));
329 /// ```
330 #[must_use]
331 pub const fn request_timeout(&self) -> Option<Duration> {
332 self.request_timeout
333 }
334
335 /// The write timeout.
336 ///
337 /// # Examples
338 ///
339 /// ```
340 /// use std::time::Duration;
341 /// assert_eq!(http_net::blocking::ServerConfig::new().write_timeout(), Some(Duration::from_secs(10)));
342 /// ```
343 #[must_use]
344 pub const fn write_timeout(&self) -> Option<Duration> {
345 self.write_timeout
346 }
347
348 /// The response deadline.
349 ///
350 /// # Examples
351 ///
352 /// ```
353 /// use std::time::Duration;
354 /// assert_eq!(http_net::blocking::ServerConfig::new().response_deadline(), Some(Duration::from_secs(60)));
355 /// ```
356 #[must_use]
357 pub const fn response_deadline(&self) -> Option<Duration> {
358 self.response_deadline
359 }
360
361 /// The cap on requests per connection.
362 ///
363 /// # Examples
364 ///
365 /// ```
366 /// assert_eq!(http_net::blocking::ServerConfig::new().max_requests_per_connection(), None);
367 /// ```
368 #[must_use]
369 pub const fn max_requests_per_connection(&self) -> Option<u64> {
370 self.max_requests
371 }
372}
373
374/// A connection handed over by a `101 Switching Protocols` (or a 2xx to
375/// `CONNECT`): the socket, the bytes of the new protocol that already
376/// arrived, and the target of the request that asked for the switch.
377///
378/// # Examples
379///
380/// ```no_run
381/// use http_net::{blocking::Server, Response};
382///
383/// let server = Server::bind("127.0.0.1:0")?.on_upgrade(|up| {
384/// // Hand `up.stream` and `up.leftover` to a protocol engine.
385/// let _ = (up.stream, up.leftover, up.target);
386/// });
387/// server.serve(|req, _body| {
388/// if req.is_upgrade() {
389/// Response::switching_protocols("x")
390/// } else {
391/// Response::new(404)
392/// }
393/// })?;
394/// # Ok::<(), std::io::Error>(())
395/// ```
396#[derive(Debug)]
397pub struct Upgraded {
398 /// The socket, now speaking the new protocol.
399 pub stream: TcpStream,
400 /// Bytes of the new protocol received together with the request.
401 pub leftover: Vec<u8>,
402 /// The target of the request that asked for the switch.
403 pub target: String,
404}
405
406type UpgradeHook = Arc<dyn Fn(Upgraded) + Send + Sync>;
407
408/// A blocking HTTP/1.1 server: one thread per connection, bounded.
409///
410/// # Examples
411///
412/// ```
413/// use http_net::{blocking::{self, Server}, Response};
414///
415/// let server = Server::bind("127.0.0.1:0")?;
416/// let addr = server.local_addr();
417/// let stop = server.shutdown_handle();
418/// let thread = std::thread::spawn(move || {
419/// server.serve(|req, _body| Response::text(200, &format!("you asked for {}", req.path())))
420/// });
421///
422/// let resp = blocking::get(&format!("http://{addr}/hello"))?;
423/// assert_eq!(resp.status(), 200);
424/// assert_eq!(resp.text(), Some("you asked for /hello"));
425///
426/// stop.shutdown();
427/// thread.join().unwrap()?;
428/// # Ok::<(), Box<dyn std::error::Error>>(())
429/// ```
430pub struct Server {
431 listener: TcpListener,
432 local: SocketAddr,
433 config: ServerConfig,
434 stop: Arc<AtomicBool>,
435 upgrade: Option<UpgradeHook>,
436}
437
438impl fmt::Debug for Server {
439 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
440 f.debug_struct("Server")
441 .field("local_addr", &self.local)
442 .field("config", &self.config)
443 .finish()
444 }
445}
446
447/// Stops a running [`Server::serve`] from another thread.
448///
449/// # Examples
450///
451/// ```
452/// let server = http_net::blocking::Server::bind("127.0.0.1:0")?;
453/// let stop = server.shutdown_handle();
454/// let t = std::thread::spawn(move || server.serve(|_, _| http_net::Response::new(204)));
455/// stop.shutdown();
456/// t.join().unwrap()?;
457/// # Ok::<(), std::io::Error>(())
458/// ```
459#[derive(Clone, Debug)]
460pub struct ShutdownHandle {
461 stop: Arc<AtomicBool>,
462 wake: SocketAddr,
463}
464
465impl ShutdownHandle {
466 /// Asks the server to stop: it accepts no new connections, lets each
467 /// open connection finish its current exchange, waits for them, and
468 /// returns from `serve`.
469 ///
470 /// # Examples
471 ///
472 /// See [`ShutdownHandle`].
473 pub fn shutdown(&self) {
474 self.stop.store(true, Ordering::SeqCst);
475 // `accept` blocks; a throwaway connection wakes it so it sees the
476 // flag. If the connect fails the listener is already gone, which is
477 // the outcome being asked for, so the error carries no information.
478 if let Ok(stream) = TcpStream::connect_timeout(&self.wake, Duration::from_secs(1)) {
479 drop(stream);
480 }
481 }
482}
483
484/// Counts live connection threads so shutdown can wait for them.
485#[derive(Default)]
486struct Active {
487 count: Mutex<usize>,
488 idle: Condvar,
489}
490
491impl Active {
492 fn try_enter(&self, max: usize) -> bool {
493 let mut n = self
494 .count
495 .lock()
496 .unwrap_or_else(std::sync::PoisonError::into_inner);
497 if *n >= max {
498 return false;
499 }
500 *n += 1;
501 true
502 }
503
504 fn leave(&self) {
505 let mut n = self
506 .count
507 .lock()
508 .unwrap_or_else(std::sync::PoisonError::into_inner);
509 *n = n.saturating_sub(1);
510 if *n == 0 {
511 self.idle.notify_all();
512 }
513 }
514
515 fn wait_idle(&self) {
516 let mut n = self
517 .count
518 .lock()
519 .unwrap_or_else(std::sync::PoisonError::into_inner);
520 while *n > 0 {
521 n = self
522 .idle
523 .wait(n)
524 .unwrap_or_else(std::sync::PoisonError::into_inner);
525 }
526 }
527}
528
529/// Leaves the active set even if the handler panics.
530struct ActiveGuard(Arc<Active>);
531
532impl Drop for ActiveGuard {
533 fn drop(&mut self) {
534 self.0.leave();
535 }
536}
537
538impl Server {
539 /// Binds a listening socket. Use `127.0.0.1:0` for an ephemeral
540 /// localhost port and read it back with [`local_addr`](Self::local_addr).
541 ///
542 /// # Errors
543 ///
544 /// The bind error from the operating system.
545 ///
546 /// # Examples
547 ///
548 /// ```
549 /// let server = http_net::blocking::Server::bind("127.0.0.1:0")?;
550 /// assert!(server.local_addr().ip().is_loopback());
551 /// # Ok::<(), std::io::Error>(())
552 /// ```
553 pub fn bind(addr: impl ToSocketAddrs) -> io::Result<Self> {
554 let listener = TcpListener::bind(addr)?;
555 let local = listener.local_addr()?;
556 Ok(Self {
557 listener,
558 local,
559 config: ServerConfig::new(),
560 stop: Arc::new(AtomicBool::new(false)),
561 upgrade: None,
562 })
563 }
564
565 /// Replaces the configuration.
566 ///
567 /// # Examples
568 ///
569 /// ```
570 /// use http_net::blocking::{Server, ServerConfig};
571 /// let s = Server::bind("127.0.0.1:0")?.with_config(ServerConfig::new().with_max_connections(4));
572 /// # Ok::<(), std::io::Error>(())
573 /// ```
574 #[must_use]
575 pub fn with_config(mut self, config: ServerConfig) -> Self {
576 self.config = config;
577 self
578 }
579
580 /// Sets what happens to a connection after the handler answers with
581 /// `101 Switching Protocols`: `hook` receives the socket on the
582 /// connection's thread. Without a hook such connections are closed.
583 ///
584 /// # Examples
585 ///
586 /// See [`Upgraded`].
587 #[must_use]
588 pub fn on_upgrade(mut self, hook: impl Fn(Upgraded) + Send + Sync + 'static) -> Self {
589 self.upgrade = Some(Arc::new(hook));
590 self
591 }
592
593 /// The bound address (with the real port when bound to port 0).
594 ///
595 /// # Examples
596 ///
597 /// ```
598 /// let server = http_net::blocking::Server::bind("127.0.0.1:0")?;
599 /// assert_ne!(server.local_addr().port(), 0);
600 /// # Ok::<(), std::io::Error>(())
601 /// ```
602 #[must_use]
603 pub fn local_addr(&self) -> SocketAddr {
604 self.local
605 }
606
607 /// A handle that stops [`serve`](Self::serve) from another thread.
608 ///
609 /// # Examples
610 ///
611 /// See [`ShutdownHandle`].
612 #[must_use]
613 pub fn shutdown_handle(&self) -> ShutdownHandle {
614 let mut wake = self.local;
615 if wake.ip().is_unspecified() {
616 wake.set_ip(match wake.ip() {
617 IpAddr::V4(_) => IpAddr::V4(Ipv4Addr::LOCALHOST),
618 IpAddr::V6(_) => IpAddr::V6(Ipv6Addr::LOCALHOST),
619 });
620 }
621 ShutdownHandle {
622 stop: Arc::clone(&self.stop),
623 wake,
624 }
625 }
626
627 /// Serves `handler` until [`ShutdownHandle::shutdown`] is called.
628 ///
629 /// The handler gets each request's head and its complete body (bounded
630 /// by [`Limits::max_body`]) and returns the response. Requests that fail
631 /// to parse are answered with [`Response::from_error`] and the
632 /// connection is closed; the handler never sees them. A request with
633 /// `Expect: 100-continue` gets `100 Continue` before its body is read;
634 /// one with any other expectation is answered `417 Expectation Failed`
635 /// without reading its body (RFC 9110 section 10.1.1), and the
636 /// connection is closed. Every response gets a `date` field (from
637 /// [`now_date`]) unless the handler set one. The time limits and the
638 /// request cap of [`ServerConfig`] apply to every connection.
639 ///
640 /// # Errors
641 ///
642 /// Only if accepting connections fails persistently; transient accept
643 /// errors are retried.
644 ///
645 /// # Examples
646 ///
647 /// See [`Server`].
648 pub fn serve<H>(self, handler: H) -> io::Result<()>
649 where
650 H: Fn(&RequestHead<'_>, &[u8]) -> Response + Send + Sync + 'static,
651 {
652 let handler = Arc::new(handler);
653 let active = Arc::new(Active::default());
654 let mut consecutive_errors = 0u32;
655 for incoming in self.listener.incoming() {
656 if self.stop.load(Ordering::SeqCst) {
657 break;
658 }
659 let stream = match incoming {
660 Ok(stream) => {
661 consecutive_errors = 0;
662 stream
663 }
664 Err(e) => {
665 // Aborted handshakes and descriptor exhaustion are
666 // transient; back off briefly instead of spinning, and
667 // give up only if accept never recovers.
668 consecutive_errors += 1;
669 if consecutive_errors > 1000 {
670 return Err(e);
671 }
672 thread::sleep(Duration::from_millis(10));
673 continue;
674 }
675 };
676 if !active.try_enter(self.config.max_connections) {
677 refuse_busy(stream, &self.config);
678 continue;
679 }
680 let guard = ActiveGuard(Arc::clone(&active));
681 let handler = Arc::clone(&handler);
682 let upgrade = self.upgrade.clone();
683 let stop = Arc::clone(&self.stop);
684 let config = self.config;
685 let spawned = thread::Builder::new()
686 .name("http-net-conn".into())
687 .spawn(move || {
688 let _guard = guard;
689 serve_stream(stream, &config, &*handler, upgrade.as_deref(), &stop);
690 });
691 // A failed spawn drops the closure, its guard, and the stream:
692 // the connection is closed and the slot released.
693 drop(spawned);
694 }
695 active.wait_idle();
696 Ok(())
697 }
698}
699
700fn refuse_busy(mut stream: TcpStream, config: &ServerConfig) {
701 const BUSY: &[u8] =
702 b"HTTP/1.1 503 Service Unavailable\r\ncontent-length: 0\r\nconnection: close\r\n\r\n";
703 // Best effort on a connection being turned away: a failure here only
704 // means the client already left. This runs on the accept thread, so it
705 // must never wait on the peer: the 503 fits in an empty send buffer,
706 // and only what has already arrived is drained (without blocking) so
707 // that it does not turn the close into a reset.
708 if stream.set_write_timeout(config.write_timeout).is_err()
709 || stream.write_all(BUSY).is_err()
710 || stream.shutdown(Shutdown::Write).is_err()
711 || stream.set_nonblocking(true).is_err()
712 {
713 return;
714 }
715 let mut scratch = [0u8; 4096];
716 let mut drained = 0;
717 while drained < DRAIN_LIMIT {
718 match stream.read(&mut scratch) {
719 Ok(n) if n > 0 => drained += n,
720 _ => break,
721 }
722 }
723}
724
725fn serve_stream(
726 stream: TcpStream,
727 config: &ServerConfig,
728 handler: &(dyn Fn(&RequestHead<'_>, &[u8]) -> Response + Send + Sync),
729 upgrade: Option<&(dyn Fn(Upgraded) + Send + Sync)>,
730 stop: &AtomicBool,
731) {
732 let configured = stream.set_read_timeout(config.read_timeout).is_ok()
733 && stream.set_write_timeout(config.write_timeout).is_ok()
734 && stream.set_nodelay(true).is_ok();
735 if !configured {
736 return;
737 }
738 let mut conn = Connection::new(stream, config.limits)
739 .with_request_timeout(config.request_timeout)
740 .with_response_deadline(config.response_deadline);
741 conn.refuse_unknown_expectations = true;
742 while !stop.load(Ordering::SeqCst) {
743 // The handler runs inside the first match; errors (which borrow
744 // nothing) are handled in the second, where `conn` is free again.
745 let outcome = match conn.next_request() {
746 Ok(Some(incoming)) => {
747 let head = incoming.head();
748 Ok((
749 handler(&head, incoming.body()),
750 head.method() == Method::Head,
751 ))
752 }
753 Ok(None) => break,
754 Err(e) => Err(e),
755 };
756 let (response, is_head) = match outcome {
757 Ok(answer) => answer,
758 Err(Error::Http(e)) => {
759 if conn.respond(&Response::from_error(&e)).is_err() {
760 return;
761 }
762 break;
763 }
764 Err(Error::Io(e)) if is_timeout(&e) && conn.request_in_progress() => {
765 // A request that did not arrive in time: say so, then
766 // close (the rest of it can no longer be framed).
767 if conn.send_request_timeout().is_ok() {
768 conn.close();
769 }
770 return;
771 }
772 Err(_) => return,
773 };
774 // `Server` writes full bodies only: the handler has no way to send
775 // a streamed one, so it would leave the client waiting. A `HEAD`
776 // answer is the exception: it announces a length or chunked
777 // framing but carries no body, so it is complete once written.
778 let streamed = response.body_bytes().is_none();
779 let response = if streamed && !is_head {
780 Response::text(
781 500,
782 "handler error: Server cannot send a streamed response; \
783 use Connection for streaming",
784 )
785 .close()
786 } else {
787 response
788 };
789 if config
790 .max_requests
791 .is_some_and(|max| conn.conn.requests_served().saturating_add(1) >= max)
792 {
793 // This response reaches the cap: it carries `connection: close`.
794 conn.conn.set_keep_alive(false);
795 }
796 match conn.respond(&response) {
797 Ok(()) if streamed && is_head => {
798 if conn.end_body().is_err() {
799 return;
800 }
801 }
802 Ok(()) => {}
803 // Refused before anything was written (a builder error, or a
804 // 101 to a request that did not ask): answer 500 instead.
805 Err(Error::Http(e)) => {
806 let message = format!("handler error: invalid response: {e}");
807 if conn
808 .respond(&Response::text(500, &message).close())
809 .is_err()
810 {
811 return;
812 }
813 }
814 Err(_) => return,
815 }
816 if conn.is_upgraded() {
817 match (conn.into_upgraded(), upgrade) {
818 (Some(up), Some(hook)) => hook(up),
819 (Some(up), None) => drain_and_close(up.stream),
820 (None, _) => {}
821 }
822 return;
823 }
824 }
825 conn.close();
826}
827
828fn drain_and_close(mut stream: TcpStream) {
829 // Lingering close (RFC 9112 section 9.6): stop sending, then read what
830 // the peer is still sending so the close does not become a reset that
831 // discards the response before the peer reads it.
832 // The drain is bounded in bytes and in total time, not only per read:
833 // a peer that keeps trickling data must not hold the thread.
834 if stream.flush().is_err() || stream.shutdown(Shutdown::Write).is_err() {
835 return;
836 }
837 let deadline = Instant::now() + DRAIN_TOTAL;
838 let mut scratch = [0u8; 4096];
839 let mut drained = 0;
840 while drained < DRAIN_LIMIT {
841 let left = deadline.saturating_duration_since(Instant::now());
842 if left.is_zero()
843 || stream
844 .set_read_timeout(Some(left.min(DRAIN_READ_TIMEOUT)))
845 .is_err()
846 {
847 break;
848 }
849 match stream.read(&mut scratch) {
850 Ok(0) | Err(_) => break,
851 Ok(n) => drained += n,
852 }
853 }
854}
855
856fn response_timed_out() -> Error {
857 Error::Io(io::Error::new(
858 io::ErrorKind::TimedOut,
859 "the response was not written within the response deadline",
860 ))
861}
862
863fn is_timeout(e: &io::Error) -> bool {
864 // Unix reports an expired socket timeout as WouldBlock, Windows as
865 // TimedOut.
866 matches!(
867 e.kind(),
868 io::ErrorKind::TimedOut | io::ErrorKind::WouldBlock
869 )
870}
871
872/// One request read by [`Connection::next_request`]: its head and its
873/// complete body.
874///
875/// # Examples
876///
877/// See [`Connection`].
878#[derive(Debug)]
879pub struct Incoming<'a> {
880 head: RequestHead<'a>,
881 body: &'a [u8],
882}
883
884impl<'a> Incoming<'a> {
885 /// The request head.
886 ///
887 /// # Examples
888 ///
889 /// See [`Connection`].
890 #[must_use]
891 pub fn head(&self) -> RequestHead<'a> {
892 self.head
893 }
894
895 /// The complete request body (empty when there is none).
896 ///
897 /// # Examples
898 ///
899 /// See [`Connection`].
900 #[must_use]
901 pub fn body(&self) -> &'a [u8] {
902 self.body
903 }
904}
905
906/// A blocking server connection: [`ServerConn`] driven over a `TcpStream`.
907///
908/// Use it for your own accept loop, or to keep the socket after an
909/// upgrade with [`into_upgraded`](Self::into_upgraded).
910///
911/// # Examples
912///
913/// ```
914/// use std::net::{TcpListener, TcpStream};
915/// use std::io::{Read, Write};
916/// use http_net::{blocking::Connection, Limits, Response};
917///
918/// let listener = TcpListener::bind("127.0.0.1:0")?;
919/// let addr = listener.local_addr()?;
920/// let client = std::thread::spawn(move || -> std::io::Result<Vec<u8>> {
921/// let mut s = TcpStream::connect(addr)?;
922/// s.write_all(b"POST /sum HTTP/1.1\r\nHost: x\r\nContent-Length: 3\r\nConnection: close\r\n\r\n1 2")?;
923/// let mut reply = Vec::new();
924/// s.read_to_end(&mut reply)?;
925/// Ok(reply)
926/// });
927///
928/// let (stream, _) = listener.accept()?;
929/// let mut conn = Connection::new(stream, Limits::new());
930/// while let Some(req) = conn.next_request()? {
931/// let sum: u32 = std::str::from_utf8(req.body())?.split(' ').filter_map(|n| n.parse::<u32>().ok()).sum();
932/// let response = Response::text(200, &sum.to_string());
933/// conn.respond(&response)?;
934/// }
935/// conn.close();
936/// let reply = client.join().unwrap()?;
937/// assert!(reply.ends_with(b"\r\n\r\n3"));
938/// # Ok::<(), Box<dyn std::error::Error>>(())
939/// ```
940#[derive(Debug)]
941pub struct Connection {
942 stream: TcpStream,
943 conn: ServerConn,
944 body: Vec<u8>,
945 out: Vec<u8>,
946 /// The socket's own read timeout, restored once a request deadline no
947 /// longer applies.
948 read_timeout: Option<Duration>,
949 request_timeout: Option<Duration>,
950 /// When the request being read must be complete.
951 deadline: Option<Instant>,
952 /// Whether the socket's read timeout is currently shortened to the
953 /// deadline.
954 shortened: bool,
955 /// The socket's own write timeout, restored after a response deadline
956 /// shortened it.
957 write_timeout: Option<Duration>,
958 response_deadline: Option<Duration>,
959 /// When the response being written must be complete.
960 write_deadline: Option<Instant>,
961 write_shortened: bool,
962 /// `Server` answers expectations other than `100-continue` with 417
963 /// before the body is read; a bare `Connection` leaves them to the
964 /// caller.
965 refuse_unknown_expectations: bool,
966}
967
968impl Connection {
969 /// Wraps an accepted socket. Set its timeouts first if you want them:
970 /// the read timeout set on `stream` is the idle timeout, and
971 /// [`with_request_timeout`](Self::with_request_timeout) adds a deadline
972 /// for each request as a whole.
973 ///
974 /// # Examples
975 ///
976 /// See [`Connection`].
977 #[must_use]
978 pub fn new(stream: TcpStream, limits: Limits) -> Self {
979 let read_timeout = stream.read_timeout().ok().flatten();
980 let write_timeout = stream.write_timeout().ok().flatten();
981 Self {
982 stream,
983 conn: ServerConn::with_limits(limits),
984 body: Vec::new(),
985 out: Vec::new(),
986 read_timeout,
987 request_timeout: None,
988 deadline: None,
989 shortened: false,
990 write_timeout,
991 response_deadline: None,
992 write_deadline: None,
993 write_shortened: false,
994 refuse_unknown_expectations: false,
995 }
996 }
997
998 /// Sets a deadline for writing each response, from its first byte to
999 /// its last, a streamed body included (see
1000 /// [`ServerConfig::with_response_deadline`]). When it passes, the write
1001 /// fails with an [`Error::Io`] of kind `TimedOut`; close the connection
1002 /// then (the response cannot be finished). `None` (the default for a
1003 /// bare `Connection`) leaves only the socket's own write timeout.
1004 ///
1005 /// # Examples
1006 ///
1007 /// ```no_run
1008 /// use std::time::Duration;
1009 /// # fn demo(stream: std::net::TcpStream) {
1010 /// let conn = http_net::blocking::Connection::new(stream, http_net::Limits::new())
1011 /// .with_response_deadline(Some(Duration::from_secs(60)));
1012 /// # let _ = conn;
1013 /// # }
1014 /// ```
1015 #[must_use]
1016 pub fn with_response_deadline(mut self, deadline: Option<Duration>) -> Self {
1017 self.response_deadline = deadline;
1018 self
1019 }
1020
1021 /// Sets a deadline for each request: from the moment its first byte is
1022 /// seen to the end of its body (see
1023 /// [`ServerConfig::with_request_timeout`]). When it passes,
1024 /// [`next_request`](Self::next_request) fails with an [`Error::Io`] of
1025 /// kind `TimedOut`. `None` (the default for a bare `Connection`) leaves
1026 /// only the socket's own read timeout.
1027 ///
1028 /// # Examples
1029 ///
1030 /// ```no_run
1031 /// use std::time::Duration;
1032 /// # fn demo(stream: std::net::TcpStream) {
1033 /// let conn = http_net::blocking::Connection::new(stream, http_net::Limits::new())
1034 /// .with_request_timeout(Some(Duration::from_secs(10)));
1035 /// # let _ = conn;
1036 /// # }
1037 /// ```
1038 #[must_use]
1039 pub fn with_request_timeout(mut self, timeout: Option<Duration>) -> Self {
1040 self.request_timeout = timeout;
1041 self
1042 }
1043
1044 /// Whether part of a request has arrived and the rest is outstanding.
1045 fn request_in_progress(&self) -> bool {
1046 self.conn.request().is_some() || !self.conn.remaining_input().is_empty()
1047 }
1048
1049 /// Answers a request that did not arrive in time with `408`, unless a
1050 /// response is already on its way.
1051 fn send_request_timeout(&mut self) -> Result<(), Error> {
1052 if self.conn.response_started() {
1053 return Err(Error::Http(HttpError::InvalidState(
1054 "a response was already started",
1055 )));
1056 }
1057 const BODY: &[u8] = b"request timed out";
1058 self.out.clear();
1059 self.out.extend_from_slice(
1060 b"HTTP/1.1 408 Request Timeout\r\ncontent-type: text/plain; charset=utf-8\r\n\
1061 content-length: ",
1062 );
1063 self.out
1064 .extend_from_slice(BODY.len().to_string().as_bytes());
1065 self.out
1066 .extend_from_slice(b"\r\nconnection: close\r\ndate: ");
1067 self.out.extend_from_slice(now_date().as_bytes());
1068 self.out.extend_from_slice(b"\r\n\r\n");
1069 self.out.extend_from_slice(BODY);
1070 self.flush_out()
1071 }
1072
1073 /// Reads into the parser's buffer, under the request deadline if one
1074 /// is running.
1075 fn fill(&mut self) -> Result<(), Error> {
1076 if let Some(limit) = self.request_timeout {
1077 if self.deadline.is_none() && self.request_in_progress() {
1078 self.deadline = Some(Instant::now() + limit);
1079 }
1080 }
1081 match self.deadline {
1082 Some(deadline) => {
1083 let left = deadline.saturating_duration_since(Instant::now());
1084 if left.is_zero() {
1085 return Err(Error::Io(io::Error::new(
1086 io::ErrorKind::TimedOut,
1087 "the request did not arrive within the request timeout",
1088 )));
1089 }
1090 let wait = self.read_timeout.map_or(left, |t| t.min(left));
1091 self.stream.set_read_timeout(Some(wait))?;
1092 self.shortened = true;
1093 }
1094 None if self.shortened => {
1095 self.stream.set_read_timeout(self.read_timeout)?;
1096 self.shortened = false;
1097 }
1098 None => {}
1099 }
1100 let spare = self.conn.read_buf();
1101 if spare.is_empty() {
1102 return Err(Error::Http(HttpError::InvalidState(
1103 "input buffer full while the parser needs input",
1104 )));
1105 }
1106 let n = loop {
1107 match self.stream.read(spare) {
1108 Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
1109 other => break other?,
1110 }
1111 };
1112 if n == 0 {
1113 self.conn.feed_eof();
1114 } else {
1115 self.conn.commit(n);
1116 }
1117 Ok(())
1118 }
1119
1120 /// Reads the next complete request. `Ok(None)` means the connection is
1121 /// finished (the client closed between requests, the previous exchange
1122 /// ended with `connection: close`, or the connection was upgraded).
1123 ///
1124 /// A request that carries `Expect: 100-continue` is answered with
1125 /// `100 Continue` before its body is read. Other expectations are left
1126 /// to the caller (see [`RequestHead::has_unknown_expectation`]);
1127 /// [`Server`] answers them with 417.
1128 ///
1129 /// # Errors
1130 ///
1131 /// [`Error::Http`] for a request this crate refuses (answer it with its
1132 /// [`HttpError::status`] and close), [`Error::Io`] for socket failures
1133 /// and timeouts (including the request deadline, as `TimedOut`), and
1134 /// [`Error::Http`] with [`HttpError::InvalidState`] if the previous
1135 /// request has not been answered.
1136 ///
1137 /// # Examples
1138 ///
1139 /// See [`Connection`].
1140 pub fn next_request(&mut self) -> Result<Option<Incoming<'_>>, Error> {
1141 self.body.clear();
1142 self.deadline = None;
1143 loop {
1144 match self.conn.poll()? {
1145 ServerEvent::Request(head) => {
1146 // The whole body is read before the caller sees the
1147 // request, so the expectation is answered here (RFC 9110
1148 // section 10.1.1). A body over the limit was already
1149 // refused from its Content-Length.
1150 let unknown = head.has_unknown_expectation();
1151 let expects_continue = head.expects_continue();
1152 if self.refuse_unknown_expectations && unknown {
1153 // An expectation this server cannot meet: 417, the
1154 // body left unread, so the connection closes after.
1155 let refusal =
1156 Response::text(417, "expectation not supported; send without Expect")
1157 .close();
1158 self.respond(&refusal)?;
1159 return Ok(None);
1160 }
1161 if expects_continue {
1162 self.out.clear();
1163 self.conn.send_continue(&mut self.out)?;
1164 self.flush_out()?;
1165 }
1166 }
1167 ServerEvent::Body(chunk) => self.body.extend_from_slice(chunk),
1168 ServerEvent::RequestEnd => break,
1169 ServerEvent::NeedInput => self.fill()?,
1170 ServerEvent::AwaitingResponse => {
1171 return Err(Error::Http(HttpError::InvalidState(
1172 "respond to the previous request first",
1173 )));
1174 }
1175 _ => return Ok(None),
1176 }
1177 }
1178 match self.conn.request() {
1179 Some(head) => Ok(Some(Incoming {
1180 head,
1181 body: &self.body,
1182 })),
1183 None => Ok(None),
1184 }
1185 }
1186
1187 /// Writes `response` to the socket. A streamed response continues with
1188 /// [`send_body`](Self::send_body) and [`end_body`](Self::end_body).
1189 ///
1190 /// # Errors
1191 ///
1192 /// [`Error::Http`] when the response is invalid or out of order (see
1193 /// [`ServerConn::respond`]); [`Error::Io`] when the write fails.
1194 ///
1195 /// # Examples
1196 ///
1197 /// See [`Connection`].
1198 pub fn respond(&mut self, response: &Response) -> Result<(), Error> {
1199 self.out.clear();
1200 let date = now_date();
1201 // A large full body goes out after the head in one vectored write
1202 // instead of being copied into the output buffer.
1203 let tail = match response.body_bytes() {
1204 Some(body) if body.len() > VECTORED_BODY => {
1205 let plan = self.conn.respond_head_dated(
1206 response,
1207 Some(&date.as_bytes()[..]),
1208 &mut self.out,
1209 )?;
1210 if plan == BodyPlan::Raw { body } else { &[][..] }
1211 }
1212 _ => {
1213 self.conn
1214 .respond_with_date(response, &date, &mut self.out)?;
1215 &[][..]
1216 }
1217 };
1218 self.write_deadline = self.response_deadline.map(|d| Instant::now() + d);
1219 self.flush_with(tail)
1220 }
1221
1222 /// Writes an interim response (for example `103 Early Hints`) before
1223 /// the final one, through [`ServerConn::send_informational`].
1224 ///
1225 /// # Errors
1226 ///
1227 /// As [`ServerConn::send_informational`], plus [`Error::Io`].
1228 ///
1229 /// # Examples
1230 ///
1231 /// ```no_run
1232 /// # fn demo(conn: &mut http_net::blocking::Connection) -> Result<(), http_net::blocking::Error> {
1233 /// use http_net::Response;
1234 ///
1235 /// conn.send_informational(&Response::new(103).header("link", "</app.css>; rel=preload; as=style"))?;
1236 /// conn.respond(&Response::text(200, "page"))?;
1237 /// # Ok(()) }
1238 /// ```
1239 pub fn send_informational(&mut self, response: &Response) -> Result<(), Error> {
1240 self.out.clear();
1241 self.conn.send_informational(response, &mut self.out)?;
1242 self.flush_out()
1243 }
1244
1245 /// Writes body bytes of a streamed response.
1246 ///
1247 /// # Errors
1248 ///
1249 /// As [`ServerConn::send_body`], plus [`Error::Io`].
1250 ///
1251 /// # Examples
1252 ///
1253 /// ```no_run
1254 /// # fn demo(conn: &mut http_net::blocking::Connection) -> Result<(), http_net::blocking::Error> {
1255 /// conn.respond(&http_net::Response::new(200).chunked())?;
1256 /// conn.send_body(b"first")?;
1257 /// conn.end_body()?;
1258 /// # Ok(()) }
1259 /// ```
1260 pub fn send_body(&mut self, data: &[u8]) -> Result<(), Error> {
1261 self.out.clear();
1262 self.conn.send_body(data, &mut self.out)?;
1263 self.flush_out()
1264 }
1265
1266 /// Ends a streamed response.
1267 ///
1268 /// # Errors
1269 ///
1270 /// As [`ServerConn::end_body`], plus [`Error::Io`].
1271 ///
1272 /// # Examples
1273 ///
1274 /// See [`send_body`](Self::send_body).
1275 pub fn end_body(&mut self) -> Result<(), Error> {
1276 self.out.clear();
1277 self.conn.end_body(&mut self.out)?;
1278 self.flush_out()
1279 }
1280
1281 /// Writes `out`. While a response deadline runs, each write waits at
1282 /// most the time left (and never longer than the socket's own write
1283 /// timeout); the deadline ends with the response.
1284 fn flush_out(&mut self) -> Result<(), Error> {
1285 self.flush_with(&[])
1286 }
1287
1288 /// Writes the serialized bytes in `out` and then `tail` (a full body
1289 /// sent as it is, not copied into `out`), with vectored writes while
1290 /// both remain.
1291 fn flush_with(&mut self, tail: &[u8]) -> Result<(), Error> {
1292 let head_len = self.out.len();
1293 let total = head_len + tail.len();
1294 let mut written = 0;
1295 while written < total {
1296 if let Some(deadline) = self.write_deadline {
1297 let left = deadline.saturating_duration_since(Instant::now());
1298 if left.is_zero() {
1299 return Err(response_timed_out());
1300 }
1301 let wait = self.write_timeout.map_or(left, |t| t.min(left));
1302 self.stream.set_write_timeout(Some(wait))?;
1303 self.write_shortened = true;
1304 }
1305 let result = if written >= head_len {
1306 self.stream.write(&tail[written - head_len..])
1307 } else if tail.is_empty() {
1308 self.stream.write(&self.out[written..])
1309 } else {
1310 let parts = [IoSlice::new(&self.out[written..]), IoSlice::new(tail)];
1311 self.stream.write_vectored(&parts)
1312 };
1313 match result {
1314 Ok(0) => return Err(Error::Io(io::ErrorKind::WriteZero.into())),
1315 Ok(n) => written += n,
1316 Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
1317 Err(e)
1318 if is_timeout(&e)
1319 && self.write_deadline.is_some_and(|d| Instant::now() >= d) =>
1320 {
1321 return Err(response_timed_out());
1322 }
1323 Err(e) => return Err(Error::Io(e)),
1324 }
1325 }
1326 if self.conn.progress() != Progress::WritingBody {
1327 self.write_deadline = None;
1328 if self.write_shortened {
1329 self.stream.set_write_timeout(self.write_timeout)?;
1330 self.write_shortened = false;
1331 }
1332 }
1333 if self.out.capacity() > OUT_RETAIN {
1334 self.out = Vec::new();
1335 }
1336 Ok(())
1337 }
1338
1339 /// Whether a `101` (or a 2xx to `CONNECT`) was sent.
1340 ///
1341 /// # Examples
1342 ///
1343 /// See [`into_upgraded`](Self::into_upgraded).
1344 #[must_use]
1345 pub fn is_upgraded(&self) -> bool {
1346 self.conn.is_upgraded()
1347 }
1348
1349 /// The socket and the bytes of the new protocol, after an upgrade;
1350 /// `None` if the connection was not upgraded. The socket's read timeout
1351 /// is the one it had when the `Connection` was created (a request
1352 /// deadline may have shortened it while the request was read).
1353 ///
1354 /// # Examples
1355 ///
1356 /// ```no_run
1357 /// # fn demo(mut conn: http_net::blocking::Connection) {
1358 /// if conn.is_upgraded() {
1359 /// let up = conn.into_upgraded().unwrap();
1360 /// // speak the new protocol on up.stream, starting with up.leftover
1361 /// # let _ = up;
1362 /// }
1363 /// # }
1364 /// ```
1365 #[must_use]
1366 pub fn into_upgraded(self) -> Option<Upgraded> {
1367 if !self.is_upgraded() {
1368 return None;
1369 }
1370 let target = self
1371 .conn
1372 .request()
1373 .map(|r| r.target().to_string())
1374 .unwrap_or_default();
1375 if self.shortened {
1376 // Best effort: the new protocol must not inherit what was left
1377 // of the request deadline. Setting a timeout this socket has
1378 // already accepted does not fail in practice, and the hand-off
1379 // is more useful than refusing it over one.
1380 let _ = self.stream.set_read_timeout(self.read_timeout);
1381 }
1382 Some(Upgraded {
1383 leftover: self.conn.remaining_input().to_vec(),
1384 target,
1385 stream: self.stream,
1386 })
1387 }
1388
1389 /// Closes the connection gracefully: stops sending, briefly drains what
1390 /// the client is still sending, and drops the socket.
1391 ///
1392 /// # Examples
1393 ///
1394 /// See [`Connection`].
1395 pub fn close(self) {
1396 drain_and_close(self.stream);
1397 }
1398}
1399
1400/// A response fetched by [`get`] or [`Client::get`], fully read.
1401///
1402/// # Examples
1403///
1404/// See [`Server`].
1405#[derive(Clone, PartialEq, Eq)]
1406pub struct ClientResponse {
1407 status: u16,
1408 headers: Vec<(String, Vec<u8>)>,
1409 body: Vec<u8>,
1410}
1411
1412/// Shows status, fields, and body size; the values of credential fields
1413/// (`set-cookie` above all) are replaced by `<redacted N bytes>`.
1414impl fmt::Debug for ClientResponse {
1415 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1416 struct Fields<'a>(&'a [(String, Vec<u8>)]);
1417 impl fmt::Debug for Fields<'_> {
1418 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1419 f.debug_list()
1420 .entries(self.0.iter().map(|(name, value)| {
1421 (
1422 name.as_str(),
1423 FieldValue {
1424 name: name.as_bytes(),
1425 value,
1426 },
1427 )
1428 }))
1429 .finish()
1430 }
1431 }
1432 f.debug_struct("ClientResponse")
1433 .field("status", &self.status)
1434 .field("headers", &Fields(&self.headers))
1435 .field("body", &format_args!("{} bytes", self.body.len()))
1436 .finish()
1437 }
1438}
1439
1440impl ClientResponse {
1441 /// The status code.
1442 ///
1443 /// # Examples
1444 ///
1445 /// See [`Server`].
1446 #[must_use]
1447 pub fn status(&self) -> u16 {
1448 self.status
1449 }
1450
1451 /// The fields in arrival order.
1452 ///
1453 /// # Examples
1454 ///
1455 /// ```no_run
1456 /// let resp = http_net::blocking::get("http://127.0.0.1:8080/")?;
1457 /// for (name, value) in resp.headers() {
1458 /// let _ = (name, value);
1459 /// }
1460 /// # Ok::<(), http_net::blocking::Error>(())
1461 /// ```
1462 pub fn headers(&self) -> impl Iterator<Item = (&str, &[u8])> {
1463 self.headers.iter().map(|(n, v)| (n.as_str(), v.as_slice()))
1464 }
1465
1466 /// The first field named `name` (ASCII case-insensitive).
1467 ///
1468 /// # Examples
1469 ///
1470 /// ```no_run
1471 /// let resp = http_net::blocking::get("http://127.0.0.1:8080/")?;
1472 /// let _ = resp.header("content-type");
1473 /// # Ok::<(), http_net::blocking::Error>(())
1474 /// ```
1475 #[must_use]
1476 pub fn header(&self, name: &str) -> Option<&[u8]> {
1477 self.headers
1478 .iter()
1479 .find(|(n, _)| n.eq_ignore_ascii_case(name))
1480 .map(|(_, v)| v.as_slice())
1481 }
1482
1483 /// The body.
1484 ///
1485 /// # Examples
1486 ///
1487 /// See [`Server`].
1488 #[must_use]
1489 pub fn body(&self) -> &[u8] {
1490 &self.body
1491 }
1492
1493 /// The body, if it is UTF-8.
1494 ///
1495 /// # Examples
1496 ///
1497 /// See [`Server`].
1498 #[must_use]
1499 pub fn text(&self) -> Option<&str> {
1500 core::str::from_utf8(&self.body).ok()
1501 }
1502
1503 /// Takes the body.
1504 ///
1505 /// # Examples
1506 ///
1507 /// ```no_run
1508 /// let bytes = http_net::blocking::get("http://127.0.0.1:8080/")?.into_body();
1509 /// # let _ = bytes;
1510 /// # Ok::<(), http_net::blocking::Error>(())
1511 /// ```
1512 #[must_use]
1513 pub fn into_body(self) -> Vec<u8> {
1514 self.body
1515 }
1516}
1517
1518/// Fetches `url` with `GET` using the default [`Client`].
1519///
1520/// # Errors
1521///
1522/// [`Error::InvalidUrl`] for anything but `http://host[:port][/path]`,
1523/// [`Error::Io`] for connection failures and timeouts, [`Error::Http`] for
1524/// a response this crate refuses (including one over the body limit).
1525///
1526/// # Examples
1527///
1528/// See [`Server`].
1529pub fn get(url: &str) -> Result<ClientResponse, Error> {
1530 Client::new().get(url)
1531}
1532
1533/// Sends `body` to `url` with `POST` and `content-type: content_type`,
1534/// using the default [`Client`].
1535///
1536/// # Errors
1537///
1538/// As [`get`], plus [`Error::Http`] for a content type that is not a valid
1539/// field value.
1540///
1541/// # Examples
1542///
1543/// ```
1544/// use http_net::{blocking, Response};
1545///
1546/// let server = blocking::Server::bind("127.0.0.1:0")?;
1547/// let addr = server.local_addr();
1548/// let stop = server.shutdown_handle();
1549/// let t = std::thread::spawn(move || server.serve(|_, body| Response::text(200, &body.len().to_string())));
1550///
1551/// let resp = blocking::post(&format!("http://{addr}/notes"), "text/plain", b"hello")?;
1552/// assert_eq!(resp.text(), Some("5"));
1553///
1554/// stop.shutdown();
1555/// t.join().unwrap()?;
1556/// # Ok::<(), Box<dyn std::error::Error>>(())
1557/// ```
1558pub fn post(url: &str, content_type: &str, body: &[u8]) -> Result<ClientResponse, Error> {
1559 let request = Request::post("/")
1560 .header("content-type", content_type)
1561 .body(body.to_vec());
1562 Client::new().request(url, request)
1563}
1564
1565/// Binds `addr` and serves `handler` with the default [`ServerConfig`]
1566/// until the process ends: the shortest way to run a server. Use
1567/// [`Server`] for a shutdown handle, settings, or an upgrade hook.
1568///
1569/// # Errors
1570///
1571/// The bind error, or a persistent accept failure (see [`Server::serve`]).
1572///
1573/// # Examples
1574///
1575/// ```no_run
1576/// use http_net::{blocking, Response};
1577///
1578/// blocking::serve("127.0.0.1:8080", |req, _body| Response::text(200, req.path()))?;
1579/// # Ok::<(), std::io::Error>(())
1580/// ```
1581pub fn serve<H>(addr: impl ToSocketAddrs, handler: H) -> io::Result<()>
1582where
1583 H: Fn(&RequestHead<'_>, &[u8]) -> Response + Send + Sync + 'static,
1584{
1585 Server::bind(addr)?.serve(handler)
1586}
1587
1588/// A blocking HTTP/1.1 client: one connection per request.
1589///
1590/// | Setting | Default |
1591/// |---|---|
1592/// | limits | [`Limits::new`] with a 16 MiB body |
1593/// | connect, read, and write timeout | 30 s each |
1594/// | total deadline for one exchange (connect, write, read) | none |
1595///
1596/// # Examples
1597///
1598/// ```no_run
1599/// use std::time::Duration;
1600/// use http_net::{blocking::Client, Limits};
1601///
1602/// let client = Client::new()
1603/// .with_limits(Limits::new().with_max_body(64 << 20))
1604/// .with_timeout(Duration::from_secs(5));
1605/// let resp = client.get("http://127.0.0.1:8080/big")?;
1606/// # let _ = resp;
1607/// # Ok::<(), http_net::blocking::Error>(())
1608/// ```
1609#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1610pub struct Client {
1611 limits: Limits,
1612 timeout: Duration,
1613 deadline: Option<Duration>,
1614}
1615
1616impl Default for Client {
1617 fn default() -> Self {
1618 Self::new()
1619 }
1620}
1621
1622impl Client {
1623 /// The defaults (see the table on [`Client`]).
1624 ///
1625 /// # Examples
1626 ///
1627 /// ```
1628 /// let _ = http_net::blocking::Client::new();
1629 /// ```
1630 #[must_use]
1631 pub const fn new() -> Self {
1632 Self {
1633 limits: Limits::new().with_max_body(16 * 1024 * 1024),
1634 timeout: Duration::from_secs(30),
1635 deadline: None,
1636 }
1637 }
1638
1639 /// Sets the response limits.
1640 ///
1641 /// # Examples
1642 ///
1643 /// ```
1644 /// let _ = http_net::blocking::Client::new().with_limits(http_net::Limits::new());
1645 /// ```
1646 #[must_use]
1647 pub const fn with_limits(mut self, limits: Limits) -> Self {
1648 self.limits = limits;
1649 self
1650 }
1651
1652 /// Sets the connect, read, and write timeout (zero is raised to 1 ms).
1653 ///
1654 /// # Examples
1655 ///
1656 /// ```
1657 /// let _ = http_net::blocking::Client::new().with_timeout(std::time::Duration::from_secs(2));
1658 /// ```
1659 #[must_use]
1660 pub const fn with_timeout(mut self, timeout: Duration) -> Self {
1661 self.timeout = if timeout.is_zero() {
1662 Duration::from_millis(1)
1663 } else {
1664 timeout
1665 };
1666 self
1667 }
1668
1669 /// Sets a total deadline for one exchange: connecting, writing the
1670 /// request, and reading the whole response. The per-operation timeout
1671 /// of [`with_timeout`](Self::with_timeout) cannot stop a server that
1672 /// sends one byte just inside it; this deadline can. `None` (the
1673 /// default) disables it.
1674 ///
1675 /// # Examples
1676 ///
1677 /// ```
1678 /// use std::time::Duration;
1679 /// let _ = http_net::blocking::Client::new().with_deadline(Some(Duration::from_secs(10)));
1680 /// ```
1681 #[must_use]
1682 pub const fn with_deadline(mut self, deadline: Option<Duration>) -> Self {
1683 self.deadline = deadline;
1684 self
1685 }
1686
1687 /// Fetches `url` with `GET`.
1688 ///
1689 /// # Errors
1690 ///
1691 /// As [`get`].
1692 ///
1693 /// # Examples
1694 ///
1695 /// See [`Client`].
1696 pub fn get(&self, url: &str) -> Result<ClientResponse, Error> {
1697 self.request(url, Request::get("/"))
1698 }
1699
1700 /// Sends `request` to the `http://` URL `url` and reads the response.
1701 /// The URL gives the authority (written as `host`) and the target, which
1702 /// replaces the target `request` was built with; the method, fields,
1703 /// and body come from `request`. The request is sent with
1704 /// `connection: close` on a connection of its own.
1705 ///
1706 /// # Errors
1707 ///
1708 /// As [`get`]; [`Error::Http`] with the builder's first error;
1709 /// [`HttpError::InvalidHost`] when `request` already has a `host` (the
1710 /// URL supplies it); [`HttpError::InvalidState`] for a streamed body
1711 /// (`chunked` or `content_length`: this client sends full bodies) or an
1712 /// upgrade request (it cannot hand the connection over; use
1713 /// [`ClientConn`]).
1714 ///
1715 /// # Examples
1716 ///
1717 /// ```
1718 /// use http_net::{blocking::{self, Client}, Request, Response};
1719 ///
1720 /// let server = blocking::Server::bind("127.0.0.1:0")?;
1721 /// let addr = server.local_addr();
1722 /// let stop = server.shutdown_handle();
1723 /// let t = std::thread::spawn(move || {
1724 /// server.serve(|req, body| Response::text(200, &format!("{} {} {}", req.method_str(), req.path(), body.len())))
1725 /// });
1726 ///
1727 /// let put = Request::put("/").header("content-type", "application/json").body(&b"{}"[..]);
1728 /// let resp = Client::new().request(&format!("http://{addr}/items/7"), put)?;
1729 /// assert_eq!(resp.text(), Some("PUT /items/7 2"));
1730 ///
1731 /// stop.shutdown();
1732 /// t.join().unwrap()?;
1733 /// # Ok::<(), Box<dyn std::error::Error>>(())
1734 /// ```
1735 pub fn request(&self, url: &str, request: Request) -> Result<ClientResponse, Error> {
1736 let url = Url::parse(url)?;
1737 let request = retarget(&request, url.target, url.authority)?;
1738 let deadline = self.deadline.map(|d| Instant::now() + d);
1739 let addrs = (url.host, url.port).to_socket_addrs()?;
1740 let mut stream = connect_any(addrs, self.timeout, deadline)?;
1741 let mut conn = ClientConn::with_limits(self.limits);
1742 let mut out = Vec::new();
1743 conn.send_request(&request, &mut out)?;
1744 let mut io = Timed {
1745 stream: &mut stream,
1746 timeout: self.timeout,
1747 deadline,
1748 };
1749 io.write_all(&out)?;
1750 read_response(&mut io, &mut conn)
1751 }
1752}
1753
1754/// Rebuilds `request` for a URL: the URL's target, `host` from its
1755/// authority first, then the request's own fields, body, and flags, and
1756/// always `connection: close` (one connection per exchange).
1757fn retarget(request: &Request, target: &str, authority: &str) -> Result<Request, Error> {
1758 if let Some(e) = request.error() {
1759 return Err(Error::Http(e));
1760 }
1761 if request.has_host {
1762 return Err(Error::Http(HttpError::InvalidHost));
1763 }
1764 if request.upgrade {
1765 return Err(Error::Http(HttpError::InvalidState(
1766 "the blocking client cannot hand over an upgraded connection; use ClientConn",
1767 )));
1768 }
1769 let mut rebuilt = Request::new(request.method(), target).header("host", authority);
1770 for (name, value) in serialized_fields(request.fields()) {
1771 let name = core::str::from_utf8(name).unwrap_or("");
1772 if request.expect_continue
1773 && name.eq_ignore_ascii_case("expect")
1774 && value.eq_ignore_ascii_case(b"100-continue")
1775 {
1776 // Added again below by its builder method.
1777 continue;
1778 }
1779 rebuilt = rebuilt.header(name, value);
1780 }
1781 if request.expect_continue {
1782 rebuilt = rebuilt.expect_continue();
1783 }
1784 rebuilt = match &request.body {
1785 OutBody::Full(body) => rebuilt.body(body.clone()),
1786 OutBody::Length(_) | OutBody::Chunked => {
1787 return Err(Error::Http(HttpError::InvalidState(
1788 "the blocking client sends full bodies only; use ClientConn to stream",
1789 )));
1790 }
1791 };
1792 let rebuilt = rebuilt.close();
1793 match rebuilt.error() {
1794 Some(e) => Err(Error::Http(e)),
1795 None => Ok(rebuilt),
1796 }
1797}
1798
1799/// Connects to the first address that accepts, each attempt bounded by
1800/// `timeout` and by what is left before `deadline`.
1801fn connect_any(
1802 addrs: impl IntoIterator<Item = SocketAddr>,
1803 timeout: Duration,
1804 deadline: Option<Instant>,
1805) -> Result<TcpStream, Error> {
1806 let mut last = None;
1807 for addr in addrs {
1808 let wait = match deadline {
1809 Some(d) => {
1810 let left = d.saturating_duration_since(Instant::now());
1811 if left.is_zero() {
1812 return Err(exchange_timed_out());
1813 }
1814 left.min(timeout)
1815 }
1816 None => timeout,
1817 };
1818 match TcpStream::connect_timeout(&addr, wait) {
1819 Ok(stream) => {
1820 stream.set_read_timeout(Some(timeout))?;
1821 stream.set_write_timeout(Some(timeout))?;
1822 stream.set_nodelay(true)?;
1823 return Ok(stream);
1824 }
1825 Err(e) => last = Some(e),
1826 }
1827 }
1828 Err(Error::Io(last.unwrap_or_else(|| {
1829 io::Error::new(io::ErrorKind::NotFound, "the host resolved to no address")
1830 })))
1831}
1832
1833fn exchange_timed_out() -> Error {
1834 Error::Io(io::Error::new(
1835 io::ErrorKind::TimedOut,
1836 "the exchange did not finish within the client deadline",
1837 ))
1838}
1839
1840/// A client socket whose reads and writes stop at a total deadline: each
1841/// operation waits at most the time left, and never longer than the
1842/// per-operation timeout.
1843struct Timed<'a> {
1844 stream: &'a mut TcpStream,
1845 timeout: Duration,
1846 deadline: Option<Instant>,
1847}
1848
1849impl Timed<'_> {
1850 /// Sets the socket timeouts for the next operation.
1851 fn arm(&mut self) -> Result<(), Error> {
1852 if let Some(d) = self.deadline {
1853 let left = d.saturating_duration_since(Instant::now());
1854 if left.is_zero() {
1855 return Err(exchange_timed_out());
1856 }
1857 let wait = left.min(self.timeout);
1858 self.stream.set_read_timeout(Some(wait))?;
1859 self.stream.set_write_timeout(Some(wait))?;
1860 }
1861 Ok(())
1862 }
1863
1864 /// Maps a timeout that ran into the deadline to the deadline's error.
1865 fn check(&self, e: io::Error) -> Error {
1866 if is_timeout(&e) && self.deadline.is_some_and(|d| Instant::now() >= d) {
1867 exchange_timed_out()
1868 } else {
1869 Error::Io(e)
1870 }
1871 }
1872
1873 fn write_all(&mut self, mut data: &[u8]) -> Result<(), Error> {
1874 while !data.is_empty() {
1875 self.arm()?;
1876 match self.stream.write(data) {
1877 Ok(0) => return Err(Error::Io(io::ErrorKind::WriteZero.into())),
1878 Ok(n) => data = &data[n..],
1879 Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
1880 Err(e) => return Err(self.check(e)),
1881 }
1882 }
1883 Ok(())
1884 }
1885
1886 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
1887 loop {
1888 self.arm()?;
1889 match self.stream.read(buf) {
1890 Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
1891 Err(e) => return Err(self.check(e)),
1892 Ok(n) => return Ok(n),
1893 }
1894 }
1895 }
1896}
1897
1898fn read_response(stream: &mut Timed<'_>, conn: &mut ClientConn) -> Result<ClientResponse, Error> {
1899 let mut response = ClientResponse {
1900 status: 0,
1901 headers: Vec::new(),
1902 body: Vec::new(),
1903 };
1904 loop {
1905 match conn.poll()? {
1906 ClientEvent::Response(head) => {
1907 response.status = head.status();
1908 response.headers = head
1909 .headers()
1910 .map(|(n, v)| (n.to_string(), v.to_vec()))
1911 .collect();
1912 }
1913 ClientEvent::Body(chunk) => response.body.extend_from_slice(chunk),
1914 ClientEvent::ResponseEnd => return Ok(response),
1915 ClientEvent::NeedInput => {
1916 let spare = conn.read_buf();
1917 if spare.is_empty() {
1918 return Err(Error::Http(HttpError::InvalidState(
1919 "input buffer full while the parser needs input",
1920 )));
1921 }
1922 let n = stream.read(spare)?;
1923 if n == 0 {
1924 conn.feed_eof();
1925 } else {
1926 conn.commit(n);
1927 }
1928 }
1929 _ => {
1930 return Err(Error::Http(HttpError::InvalidState(
1931 "the connection ended without a complete response",
1932 )));
1933 }
1934 }
1935 }
1936}
1937
1938/// The parts of an `http://` URL needed to send a request.
1939#[derive(Debug, PartialEq, Eq)]
1940struct Url<'a> {
1941 /// `host[:port]` as written, for the Host header.
1942 authority: &'a str,
1943 /// The host for name resolution (brackets removed from IPv6 literals).
1944 host: &'a str,
1945 port: u16,
1946 /// Path and query; `/` when the URL has no path.
1947 target: &'a str,
1948}
1949
1950impl<'a> Url<'a> {
1951 fn parse(url: &'a str) -> Result<Self, Error> {
1952 let scheme_end = url.find("://").ok_or(Error::InvalidUrl("missing scheme"))?;
1953 if !url[..scheme_end].eq_ignore_ascii_case("http") {
1954 return Err(Error::InvalidUrl(
1955 "only http:// is supported (no TLS in this crate)",
1956 ));
1957 }
1958 let rest = &url[scheme_end + 3..];
1959 // The fragment is never sent.
1960 let rest = rest.split_once('#').map_or(rest, |(r, _)| r);
1961 let auth_end = rest.find(['/', '?']).unwrap_or(rest.len());
1962 let authority = &rest[..auth_end];
1963 let target = match &rest[auth_end..] {
1964 "" => "/",
1965 t if t.starts_with('?') => {
1966 return Err(Error::InvalidUrl("a query needs a path, for example /?q"));
1967 }
1968 t => t,
1969 };
1970 if authority.is_empty() {
1971 return Err(Error::InvalidUrl("missing host"));
1972 }
1973 if authority.contains('@') {
1974 return Err(Error::InvalidUrl(
1975 "credentials in the URL are not supported",
1976 ));
1977 }
1978 let (host, port) = if let Some(v6) = authority.strip_prefix('[') {
1979 let (inside, after) = v6.split_once(']').ok_or(Error::InvalidUrl("unclosed ["))?;
1980 let port = match after {
1981 "" => None,
1982 p => Some(
1983 p.strip_prefix(':')
1984 .ok_or(Error::InvalidUrl("junk after ]"))?,
1985 ),
1986 };
1987 (inside, port)
1988 } else {
1989 match authority.rsplit_once(':') {
1990 Some((h, p)) => (h, Some(p)),
1991 None => (authority, None),
1992 }
1993 };
1994 let port = match port {
1995 None => 80,
1996 Some(p) => p.parse().map_err(|_| Error::InvalidUrl("bad port"))?,
1997 };
1998 if host.is_empty() {
1999 return Err(Error::InvalidUrl("missing host"));
2000 }
2001 Ok(Self {
2002 authority,
2003 host,
2004 port,
2005 target,
2006 })
2007 }
2008}
2009
2010thread_local! {
2011 /// One date cache per thread: each connection thread formats `date` at
2012 /// most once per second, and nothing is shared between threads.
2013 static DATE: Cell<DateCache> = const { Cell::new(DateCache::new()) };
2014}
2015
2016/// The current time as a `Date` value, from a per-thread
2017/// [`DateCache`]: the system clock is read on every call, the value is
2018/// reformatted only when the second changes. [`Connection::respond`] and
2019/// [`Server`] write it on every response that did not set its own `date`.
2020///
2021/// # Examples
2022///
2023/// ```
2024/// let date = http_net::blocking::now_date();
2025/// assert_eq!(date.as_bytes().len(), 29);
2026/// assert!(date.as_str().ends_with(" GMT"));
2027/// ```
2028#[must_use]
2029pub fn now_date() -> HttpDate {
2030 let secs = SystemTime::now()
2031 .duration_since(UNIX_EPOCH)
2032 .map_or(0, |d| d.as_secs());
2033 DATE.with(|cell| {
2034 let mut cache = cell.get();
2035 let date = *cache.update(secs);
2036 cell.set(cache);
2037 date
2038 })
2039}
2040
2041#[cfg(test)]
2042mod tests {
2043 use super::*;
2044
2045 #[test]
2046 fn test_now_date_is_the_current_second() {
2047 let before = SystemTime::now()
2048 .duration_since(UNIX_EPOCH)
2049 .map_or(0, |d| d.as_secs());
2050 let shown = now_date();
2051 let after = SystemTime::now()
2052 .duration_since(UNIX_EPOCH)
2053 .map_or(0, |d| d.as_secs());
2054 assert!(
2055 shown == HttpDate::from_unix_seconds(before)
2056 || shown == HttpDate::from_unix_seconds(after),
2057 "{shown}"
2058 );
2059 // The same second twice comes from the cache and is equal.
2060 assert_eq!(now_date().as_bytes().len(), 29);
2061 }
2062
2063 /// E-198: a name that resolves to several addresses is tried in order;
2064 /// an address that refuses the connection does not end the attempt.
2065 #[test]
2066 fn test_connect_any_unreachable_first_address_tries_the_next() {
2067 let closed = TcpListener::bind("127.0.0.1:0").unwrap();
2068 let refused = closed.local_addr().unwrap();
2069 drop(closed);
2070 let open = TcpListener::bind("127.0.0.1:0").unwrap();
2071 let good = open.local_addr().unwrap();
2072 let stream = connect_any([refused, good], Duration::from_secs(5), None).unwrap();
2073 assert_eq!(stream.peer_addr().unwrap(), good);
2074
2075 let err = connect_any([refused], Duration::from_secs(5), None).unwrap_err();
2076 assert!(matches!(err, Error::Io(_)), "{err}");
2077 let err = connect_any(Vec::<SocketAddr>::new(), Duration::from_secs(5), None).unwrap_err();
2078 assert!(
2079 matches!(&err, Error::Io(e) if e.kind() == io::ErrorKind::NotFound),
2080 "{err}"
2081 );
2082 }
2083
2084 #[test]
2085 fn test_connect_any_past_the_deadline_times_out() {
2086 let open = TcpListener::bind("127.0.0.1:0").unwrap();
2087 let good = open.local_addr().unwrap();
2088 let err = connect_any([good], Duration::from_secs(5), Some(Instant::now())).unwrap_err();
2089 assert!(
2090 matches!(&err, Error::Io(e) if e.kind() == io::ErrorKind::TimedOut),
2091 "{err}"
2092 );
2093 }
2094
2095 #[test]
2096 fn test_client_request_with_host_is_refused() {
2097 let req = Request::get("/").header("host", "a");
2098 let err = Client::new()
2099 .request("http://127.0.0.1:1/", req)
2100 .unwrap_err();
2101 assert!(matches!(err, Error::Http(HttpError::InvalidHost)), "{err}");
2102 }
2103
2104 #[test]
2105 fn test_client_request_streamed_body_is_refused() {
2106 for req in [
2107 Request::post("/").chunked(),
2108 Request::put("/").content_length(3),
2109 ] {
2110 let err = Client::new()
2111 .request("http://127.0.0.1:1/", req)
2112 .unwrap_err();
2113 assert!(
2114 matches!(err, Error::Http(HttpError::InvalidState(_))),
2115 "{err}"
2116 );
2117 }
2118 }
2119
2120 #[test]
2121 fn test_retarget_keeps_method_fields_body_and_flags() {
2122 let original = Request::new("PATCH", "/ignored")
2123 .header("x-a", "1")
2124 .header("content-type", "text/plain")
2125 .body(&b"xyz"[..]);
2126 let r = retarget(&original, "/real?q", "example.com:8080").unwrap();
2127 assert_eq!(r.method(), "PATCH");
2128 assert_eq!(r.target(), "/real?q");
2129 assert_eq!(r.header_value("host"), Some(&b"example.com:8080"[..]));
2130 assert_eq!(r.header_value("x-a"), Some(&b"1"[..]));
2131 assert_eq!(r.body_bytes(), Some(&b"xyz"[..]));
2132 let mut out = Vec::new();
2133 ClientConn::new().send_request(&r, &mut out).unwrap();
2134 let text = String::from_utf8(out).unwrap();
2135 assert!(
2136 text.starts_with("PATCH /real?q HTTP/1.1\r\nhost: example.com:8080\r\nx-a: 1\r\n"),
2137 "{text}"
2138 );
2139 assert!(text.contains("connection: close\r\n"), "{text}");
2140 assert!(text.ends_with("\r\n\r\nxyz"), "{text}");
2141
2142 // The blocking client reads one response to its end, so it cannot
2143 // hand over an upgraded connection.
2144 let up = Request::get("/").upgrade("websocket");
2145 assert!(matches!(
2146 retarget(&up, "/", "a"),
2147 Err(Error::Http(HttpError::InvalidState(_)))
2148 ));
2149 // A builder error surfaces first.
2150 let bad = Request::get("/").header("bad name", "x");
2151 assert!(matches!(
2152 retarget(&bad, "/", "a"),
2153 Err(Error::Http(HttpError::InvalidHeaderName))
2154 ));
2155 }
2156
2157 #[test]
2158 fn test_url_parsing() {
2159 let u = Url::parse("http://127.0.0.1:8080/a/b?c=d#frag").unwrap();
2160 assert_eq!(
2161 u,
2162 Url {
2163 authority: "127.0.0.1:8080",
2164 host: "127.0.0.1",
2165 port: 8080,
2166 target: "/a/b?c=d"
2167 }
2168 );
2169 let u = Url::parse("HTTP://[::1]/").unwrap();
2170 assert_eq!((u.host, u.port, u.authority), ("::1", 80, "[::1]"));
2171 assert_eq!(Url::parse("http://example.com").unwrap().target, "/");
2172 for bad in [
2173 "example.com",
2174 "https://x/",
2175 "http:///x",
2176 "http://u:p@x/",
2177 "http://x:99999/",
2178 "http://[::1/",
2179 "http://[::1]x/",
2180 "http://x?q",
2181 "http://:80/",
2182 ] {
2183 assert!(
2184 matches!(Url::parse(bad), Err(Error::InvalidUrl(_))),
2185 "{bad}"
2186 );
2187 }
2188 }
2189
2190 #[test]
2191 fn test_error_display_and_source() {
2192 use std::error::Error as _;
2193 let e = Error::from(HttpError::BareCr);
2194 assert!(e.to_string().starts_with("HTTP error"));
2195 assert!(e.source().is_some());
2196 let e = Error::from(io::Error::other("x"));
2197 assert!(e.source().is_some());
2198 assert!(Error::InvalidUrl("y").source().is_none());
2199 }
2200}