Yuki
Yuki

Reputation: 23

&Option<HeaderName> to &HeaderName

I'm making proxy using axum for accepting request from browser and reqwest for sending request to target host in Rust. So I have to change axum request to reqwest request and remove some headers like host, origin, etc. This is my remove function.

pub fn remove_headers(request: &reqwest::Request, keys_to_remove: Vec<String>) -> HeaderMap {
    let mut cloned_headers = request.headers().clone();

    // Convert keys_to_remove into a set for fast lookups
    let keys_set: HashSet<String> = keys_to_remove.into_iter().collect();

    // Create a new HeaderMap and only insert headers that are not in the keys_to_remove list
    let filtered_headers = cloned_headers
        .into_iter()
        .filter(|(key, _)| {
            // Dereference the key from &Option<HeaderName> to HeaderName and compare with the set
            if let Some(header_name) = key {
                !keys_set.contains(&header_name.as_str().to_string())
            } else {
                key.is_some()
            }
        })
        .collect::<HeaderMap>(); // Collect back into a HeaderMap

    filtered_headers
}

I expect the type of key is &HeaderName, but now &Option. So filtered_headers is not converted to HeaderMap.

Upvotes: 0

Views: 73

Answers (1)

fdan
fdan

Reputation: 1814

In addition to the hint posted in the comments (using filter_map), you can save performace by not copying all collections/strings involved:

  • Do not clone all headers, iterate over references and clone key-values when not filtered out
  • Do not convert the header name to String, you can do the lookup using &str
  • Do not convert the vector to a hashmap everytime (if possible)
fn remove_headers(request: &Request, keys_to_remove: &HashSet<String>) -> HeaderMap {
    request
        .headers()
        .iter()
        .filter_map(|(key, value)| {
            if !keys_to_remove.contains(key.as_str()) {
                Some((key.clone(), value.clone()))
            } else {
                None
            }
        })
        .collect()
}

Note that if you can mutate request, you can simply use HeaderMap::remove:

fn remove_headers(request: &mut Request, keys_to_remove: &Vec<String>) {
    for key in keys_to_remove {
        request.headers_mut().remove(key);
    }
}

Upvotes: 1

Related Questions