From dad61a03c6bf6346dc79443d74960f20d051c65c Mon Sep 17 00:00:00 2001 From: Charles Sibbald Date: Tue, 27 Oct 2026 16:20:27 +0200 Subject: [PATCH] perf(client): borrow a request's headers when there is nothing to merge; no copy into the request target - `prepare_attempt_headers` rebuilt a merged `HeaderMap` for every attempt: defaults, then provider metadata, then the request's headers, each value cloned. With no default headers, no metadata provider and nothing to strip (the common case), the request's own map is used as is (`Cow::Borrowed`). That saves the map's allocations and a clone of every value; the first clone of a value built with `HeaderValue::from_str` allocates, because it promotes the bytes to shared. - `origin_form` built the request target in a `String` and then `parse()` copied it into the `Uri`. `Uri::try_from(String)` takes the buffer. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Y3TSRmEZAYU6RBUXhkn7WF --- src/client/rich.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/client/rich.rs b/src/client/rich.rs index 1e671a5..4a08f57 100644 --- a/src/client/rich.rs +++ b/src/client/rich.rs @@ -1,5 +1,6 @@ //! Replay-aware requests, secure redirects, and bounded connection pooling. +use std::borrow::Cow; use std::collections::{HashMap, HashSet}; use std::fmt; use std::io::{self, Read}; @@ -1107,19 +1108,27 @@ impl Client { snapshot } - fn prepare_attempt_headers( + fn prepare_attempt_headers<'h>( &self, - request_headers: &HeaderMap, + request_headers: &'h HeaderMap, context: RequestMetadataContext<'_>, credentials_stripped: bool, sensitive_headers: &mut HashSet, - ) -> io::Result { + ) -> io::Result> { validate_request_headers( request_headers, self.inner.config.max_request_headers, self.inner.config.max_request_header_bytes, "request", )?; + // Nothing to merge in (no default headers, no metadata provider, nothing stripped): the + // request's own headers are the attempt's, borrowed rather than rebuilt per attempt. + if self.inner.config.default_headers.is_empty() + && self.inner.metadata_provider.is_none() + && !credentials_stripped + { + return Ok(Cow::Borrowed(request_headers)); + } let mut headers = self.inner.config.default_headers.clone(); if let Some(provider) = &self.inner.metadata_provider { @@ -1172,7 +1181,7 @@ impl Client { self.inner.config.max_request_header_bytes, "merged", )?; - Ok(headers) + Ok(Cow::Owned(headers)) } fn send_on_lease( @@ -2104,7 +2113,8 @@ fn origin_form(url: &Url) -> io::Result { target.push('?'); target.push_str(query); } - target.parse().map_err(|error| { + // `try_from(String)` takes the buffer; `parse()` would copy it. + http::Uri::try_from(target).map_err(|error| { io::Error::new( io::ErrorKind::InvalidInput, format!("URL cannot be represented as an HTTP request target: {error}"),