Skip to content

Commit

Permalink
fix(http): retain headers order (#1884)
Browse files Browse the repository at this point in the history
* fix(http): retain headers order

closes #1882

* simplify if

* actually set headers

---------

Co-authored-by: Lucas Nogueira <[email protected]>
  • Loading branch information
amrbashir and lucasfernog authored Oct 9, 2024
1 parent 60064fc commit 9b2840d
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 24 deletions.
6 changes: 6 additions & 0 deletions .changes/http-headers-order.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"http": "patch"
"http-js": "patch"
---

Retain headers order.
51 changes: 27 additions & 24 deletions plugins/http/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

use std::{collections::HashMap, future::Future, pin::Pin, sync::Arc, time::Duration};
use std::{future::Future, pin::Pin, str::FromStr, sync::Arc, time::Duration};

use http::{header, HeaderName, Method, StatusCode};
use http::{header, HeaderMap, HeaderName, HeaderValue, Method, StatusCode};
use reqwest::{redirect::Policy, NoProxy};
use serde::{Deserialize, Serialize};
use tauri::{
Expand Down Expand Up @@ -176,7 +176,7 @@ pub async fn fetch<R: Runtime>(
let ClientConfig {
method,
url,
headers,
headers: headers_raw,
data,
connect_timeout,
max_redirections,
Expand All @@ -185,7 +185,17 @@ pub async fn fetch<R: Runtime>(

let scheme = url.scheme();
let method = Method::from_bytes(method.as_bytes())?;
let headers: HashMap<String, String> = HashMap::from_iter(headers);

let mut headers = HeaderMap::new();
for (h, v) in headers_raw {
let name = HeaderName::from_str(&h)?;
#[cfg(not(feature = "unsafe-headers"))]
if is_unsafe_header(&name) {
continue;
}

headers.append(name, HeaderValue::from_str(&v)?);
}

match scheme {
"http" | "https" => {
Expand Down Expand Up @@ -228,45 +238,38 @@ pub async fn fetch<R: Runtime>(

let mut request = builder.build()?.request(method.clone(), url);

for (name, value) in &headers {
let name = HeaderName::from_bytes(name.as_bytes())?;
#[cfg(not(feature = "unsafe-headers"))]
if is_unsafe_header(&name) {
continue;
}

request = request.header(name, value);
}

// POST and PUT requests should always have a 0 length content-length,
// if there is no body. https://fetch.spec.whatwg.org/#http-network-or-cache-fetch
if data.is_none() && matches!(method, Method::POST | Method::PUT) {
request = request.header(header::CONTENT_LENGTH, 0);
headers.append(header::CONTENT_LENGTH, HeaderValue::from_str("0")?);
}

if headers.contains_key(header::RANGE.as_str()) {
if headers.contains_key(header::RANGE) {
// https://fetch.spec.whatwg.org/#http-network-or-cache-fetch step 18
// If httpRequest’s header list contains `Range`, then append (`Accept-Encoding`, `identity`)
request = request.header(header::ACCEPT_ENCODING, "identity");
headers.append(header::ACCEPT_ENCODING, HeaderValue::from_str("identity")?);
}

if !headers.contains_key(header::USER_AGENT.as_str()) {
request = request.header(header::USER_AGENT, HTTP_USER_AGENT);
if !headers.contains_key(header::USER_AGENT) {
headers.append(header::USER_AGENT, HeaderValue::from_str(HTTP_USER_AGENT)?);
}

if cfg!(feature = "unsafe-headers")
&& !headers.contains_key(header::ORIGIN.as_str())
{
// ensure we have an Origin header set
if cfg!(not(feature = "unsafe-headers")) || !headers.contains_key(header::ORIGIN) {
if let Ok(url) = webview.url() {
request =
request.header(header::ORIGIN, url.origin().ascii_serialization());
headers.append(
header::ORIGIN,
HeaderValue::from_str(&url.origin().ascii_serialization())?,
);
}
}

if let Some(data) = data {
request = request.body(data);
}

request = request.headers(headers);

let fut = async move { request.send().await.map_err(Into::into) };
let mut resources_table = webview.resources_table();
let rid = resources_table.add_request(Box::pin(fut));
Expand Down

0 comments on commit 9b2840d

Please sign in to comment.