Search code examples
rustiron

Cannot set headers of an Iron framework Response


I am looking to set the headers of a Iron Response with the following code:

extern crate iron;  // 0.3.0
extern crate hyper; // 0.8.1

use iron::prelude::*;
use iron::status;

use hyper::header::{Headers, ContentType};
use hyper::mime::{Mime, TopLevel, SubLevel};

use std::error::Error;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;

fn main() {
    fn hello_world(_: &mut Request) -> IronResult<Response> {
        let mut headers = Headers::new();
        let string = getFileAsString("./public/index.html");

        headers.set(
            ContentType(Mime(TopLevel::Text, SubLevel::Html, vec![]))
        );

        Ok(Response::with((status::Ok, string, headers)))
    }

    Iron::new(hello_world).http("localhost:3000").unwrap();
    println!("On 3000");
}

fn getFileAsString(fileStr: &str) -> String {
    let path = Path::new(fileStr);
    let display = path.display();
    let mut fileContents = String::new();

    let mut file = match File::open(&path) {
        Err(why) => panic!("couldn't open {}: {}", display, Error::description(&why)),
        Ok(file) => file,
    };

    match file.read_to_string(&mut fileContents) {
        Err(why) => panic!("couldn't read {}: {}", display, Error::description(&why)),
        Ok(_) => fileContents
    }    
}

However I get the error:

error[E0277]: the trait bound `iron::Headers: iron::modifier::Modifier<iron::Response>` is not satisfied
  --> src/main.rs:24:12
   |
24 |         Ok(Response::with((status::Ok, string, headers)))
   |            ^^^^^^^^^^^^^^ the trait `iron::modifier::Modifier<iron::Response>` is not implemented for `iron::Headers`
   |
   = note: required because of the requirements on the impl of `iron::modifier::Modifier<iron::Response>` for `(hyper::status::StatusCode, std::string::String, iron::Headers)`
   = note: required by `iron::Response::with`

Why am I not able to pass headers into this tuple to be modified by the Request builder?


Solution

  • You can modify the headers on the Response object:

    fn hello_world(_: &mut Request) -> IronResult<Response> {
        let string = get_file_as_string("./public/index.html");
        let mut resp = Response::with((status::Ok, string));
        resp.headers.set(ContentType(Mime(TopLevel::Text, SubLevel::Html, vec![])));
        Ok(resp)
    }
    

    To figure out the original error, let's check the error message:

    error[E0277]: the trait bound `iron::Headers: iron::modifier::Modifier<iron::Response>` is not satisfied
      --> src/main.rs:24:12
       |
    24 |         Ok(Response::with((status::Ok, string, headers)))
       |            ^^^^^^^^^^^^^^ the trait `iron::modifier::Modifier<iron::Response>` is not implemented for `iron::Headers`
       |
       = note: required because of the requirements on the impl of `iron::modifier::Modifier<iron::Response>` for `(hyper::status::StatusCode, std::string::String, iron::Headers)`
       = note: required by `iron::Response::with`
    

    The first line tells us the immediate issue: iron::Headers does not implement the trait iron::modifier::Modifier<iron::Response>. If we check the documentation for Headers, we can see under the Trait Implementations section that it indeed does not implement Modifier.

    We can then look at the problem from the other end: what does implement Modifier? The docs for Modifier, when built in conjunction with Iron, answer that question. One thing we can see is:

    impl<H> Modifier<Response> for Header<H>
    where
        H: Header + HeaderFormat,
    

    This leads to an alternate possibility:

    use iron::modifiers::Header;
    
    fn hello_world(_: &mut Request) -> IronResult<Response> {
        let string = get_file_as_string("./public/index.html");
        let content_type = Header(ContentType(Mime(TopLevel::Text, SubLevel::Html, vec![])));
        Ok(Response::with((status::Ok, string, content_type)))
    }
    

    And if we look at the implementation of Modifier for Header:

    fn modify(self, res: &mut Response) {
        res.headers.set(self.0);
    }
    

    It just sets the headers as we did above.


    FYI, Rust style is snake_case for variables and methods and Error::description(&why) is normally written why.description().