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