Ndesmic
Ndesmic

Reputation: 57

How to set raw headers in Hyper at runtime?

I'm trying to set headers on a Hyper Response at runtime. In the real code, the headers come from a file so I don't know what they are at compile-time. Unfortunately, I've dug through documentation and all the examples I could find but haven't seen somebody doing this. Here's the code:

extern crate hyper;
use std::collections::HashMap;
use std::io::{Read,Write};
use hyper::server::{Handler,Server,Response,Request};
use hyper::header::*;

fn main() {
    let headers = HashMap::new();
    headers.insert("X-Test-Header".to_string(), "test_value".to_string());
    let responder = Responder::new(headers);

    Server::http("127.0.0.1:1340")
    .unwrap()
    .handle(responder)
    .unwrap();
}

struct Responder {
    headers: HashMap<String, String>
}

impl Responder {
    pub fn new(headers: HashMap<String,String>) -> Self {
        Responder {
            headers: headers.clone()
        }
    }
    fn respond_success(&self, mut res: Response, content: &[u8]) {
        res.headers_mut()
            .set(ContentLength(content.len() as u64));
        for (key, val) in self.headers.iter() {
            res.headers_mut()
                .set_raw(key.as_str(), vec![val.into_bytes()])
        }
        let mut res_body = res.start().unwrap();
        res_body.write_all(content).unwrap();
    }
}

impl Handler for Responder {
    fn handle(&self, req: Request, res: Response) {
        let content = b"Hello World!";
        self.respond_success(res, content);
    }
}

The error:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src\main.rs:31:40
   |
31 |         for (key, val) in self.headers.iter() {
   |                                        ^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 28:65...
  --> src\main.rs:28:66
   |
28 |     fn respond_success(&self, mut res: Response, content: &[u8]) {
   |                                                                  ^
note: ...so that reference does not outlive borrowed content
  --> src\main.rs:31:27
   |
31 |         for (key, val) in self.headers.iter() {
   |                           ^^^^^^^^^^^^
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that types are compatible (expected std::convert::From<&str>, found std::convert::From<&str>)
  --> src\main.rs:33:18
   |
33 |                 .set_raw(key.as_str(), vec![val.into_bytes()])
   |                  ^^^^^^^

It looks like set_raw needs something static but I'm not sure what my best option for refactoring this is. Does responder have to be static? That seems wrong.

Upvotes: 0

Views: 1119

Answers (1)

Shepmaster
Shepmaster

Reputation: 430673

Review the signature for Headers::set_raw:

fn set_raw<K>(&mut self, name: K, value: Vec<Vec<u8>>)
where 
    K: Into<Cow<'static, str>>

This says that name can be any type that can be converted into a Cow<'static, str>. That means that it can be either a &'static str or a String.

Next, review what types you are trying to pass:

.set_raw(key.as_str(), vec![val.into_bytes()])
  1. String::as_str returns a string slice that lives as long as the String it's called on, which is not that 'static lifetime.

    Instead, you need to get an owned string.

  2. You are calling String::into_bytes on a &String, but, as described in Cannot move out of borrowed content, you cannot as it takes the receiver by value.

    Instead, you need to get an owned copy of the bytes.

Together, it looks like:

for (key, val) in self.headers.iter() {
    res.headers_mut()
        .set_raw(key.clone(), vec![val.clone().into_bytes()])
}

Upvotes: 2

Related Questions