3

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?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Jacob Clark
  • 3,317
  • 5
  • 32
  • 61

1 Answers1

11

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().

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Thanks, could you explain why I cannot pass headers into the tuple as I understand Response::with accepts a tuple of modifiers for the response object? – Jacob Clark May 23 '16 at 22:02
  • @JacobClark ah yes, I forgot the important part of the answer! – Shepmaster May 23 '16 at 22:23
  • excellent, thank you! Possibly out of the scope now, but how is the tuple applied? I would normally expect to see a form each iterating through each modifier, but in the Iron modifier source I do not see this, can you point me to where/how each modifier in a tuple is applied? – Jacob Clark May 24 '16 at 06:36