reqwless icon indicating copy to clipboard operation
reqwless copied to clipboard

Host Header Added Twice

Open StefanB7 opened this issue 10 months ago • 1 comments

I was following the example in the project's readme (under esp-mbedtls heading):

... existing
let mut request = client
    .request(reqwless::request::Method::GET, "https://www.google.com")
    .await
    .unwrap()
    .content_type(reqwless::headers::ContentType::TextPlain)
    .headers(&[("Host", "google.com")])
    .send(&mut buffer)
    .await
    .unwrap();

However, I got a bunch of bad requests responses when trying to visit https://www.google.com as well as http://www.mobile-j.de.

Note I was setting the Host in the headers each time.

After debugging the request (by sending it to my localhost) I saw the host header was being added twice.

GET / HTTP/1.1
Host: 192.168.1.2
Content-Type: text/plain
Content-Length: 0
Host: api.telegram.org
user-agent: Mozilla/5.0 (X11; Linux x86_64; rv:135.0) Gecko/20100101 Firefox/135.0
accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
accept-language: en-US,en;q=0.5

It looks like 192.168.1.2 was being added by reqwless by itself and the telegram host by explicit set of headers.

Thanks for the library!

StefanB7 avatar Feb 11 '25 21:02 StefanB7

Hi,

I can't make a PR, but the easiest way to solve it is by updating RequestBuilder: Old:

pub trait RequestBuilder<'req, B>
where
    B: RequestBody,
{
    type WithBody<T: RequestBody>: RequestBuilder<'req, T>;

    /// Set optional headers on the request.
    fn headers(self, headers: &'req [(&'req str, &'req str)]) -> Self;
    /// Set the path of the HTTP request.
    fn path(self, path: &'req str) -> Self;
    /// Set the data to send in the HTTP request body.
    fn body<T: RequestBody>(self, body: T) -> Self::WithBody<T>;
    /// Set the host header.
    fn host(self, host: &'req str) -> Self;
    /// Set the content type header for the request.
    fn content_type(self, content_type: ContentType) -> Self;
    /// Set the accept header for the request.
    fn accept(self, content_type: ContentType) -> Self;
    /// Set the basic authentication header for the request.
    fn basic_auth(self, username: &'req str, password: &'req str) -> Self;
    /// Return an immutable request.
    fn build(self) -> Request<'req, B>;
}

Update:

pub trait RequestBuilder<'req, B>
where
    B: RequestBody,
{
    type WithBody<T: RequestBody>: RequestBuilder<'req, T>;

    /// Set optional headers on the request.
    /// All headers which are NOT: Host, Content-Type, Content-Length
    fn extra_headers(self, headers: &'req [(&'req str, &'req str)]) -> Self;
    /// Set the path of the HTTP request.
    fn path(self, path: &'req str) -> Self;
    /// Set the data to send in the HTTP request body.
    fn body<T: RequestBody>(self, body: T) -> Self::WithBody<T>;
    /// Set the host header.
    fn host(self, host: &'req str) -> Self;
    /// Set the content type header for the request.
    fn content_type(self, content_type: ContentType) -> Self;
    /// Set the accept header for the request.
    fn accept(self, content_type: ContentType) -> Self;
    /// Set the basic authentication header for the request.
    fn basic_auth(self, username: &'req str, password: &'req str) -> Self;
    /// Return an immutable request.
    fn build(self) -> Request<'req, B>;
}

Also update where the function is used.

To make it more clear the README should also be updated for the esp-mbedtls part to contain this as the example:

/// ... [initialization code. See esp-wifi]
let state = TcpClientState::<1, 4096, 4096>::new();
let mut tcp_client = TcpClient::new(stack, &state);
let dns_socket = DnsSocket::new(&stack);
let mut tls = Tls::new(peripherals.SHA)
    .unwrap()
    .with_hardware_rsa(peripherals.RSA);
let config = TlsConfig::new(
    reqwless::TlsVersion::Tls1_3,
    reqwless::Certificates {
        ca_chain: reqwless::X509::pem(CERT.as_bytes()).ok(),
        ..Default::default()
    },
    tls.reference(),
);
let mut client = HttpClient::new_with_tls(&tcp_client, &dns_socket, config);

let mut request = client
    .request(reqwless::request::Method::GET, "https://www.google.com")
    .await
    .unwrap()
    .content_type(reqwless::headers::ContentType::TextPlain)
    .send(&mut buffer)
    .await
    .unwrap();

I hope this helps :)

Lu-Aar avatar Jul 24 '25 20:07 Lu-Aar