2016-04-05 7 views
3

私はRustの小さなAPIに取り組んでおり、Ironから2か所でRequestにアクセスする方法がわかりません。ミドルウェアとハ​​ンドラの両方でIron Requestを読み取るにはどうすればよいですか?

Authenticationミドルウェアは、トークンに対してRequestを一度読み込み、パスが許可されていれば(実際にはチェックは行われません)、実際のルートが再度そのトークンを読み込もうとします。これは、リクエストがすでに読み込まれているため、私にEOFエラーが発生します。

私は簡単に要求をクローンしているようには見えません。私は体を読むためには変更可能でなければならないと信じています。

extern crate iron; 
extern crate router; 
extern crate rustc_serialize; 

use iron::prelude::*; 
use iron::{BeforeMiddleware, status}; 
use router::Router; 
use rustc_serialize::json; 
use rustc_serialize::json::Json; 
use std::io::Read; 

#[derive(RustcEncodable, RustcDecodable)] 
struct Greeting { 
    msg: String 
} 

struct Authentication; 

fn main() { 
    let mut request_body = String::new(); 

    impl BeforeMiddleware for Authentication { 
     fn before(&self, request: &mut Request) -> IronResult<()> { 
      let mut payload = String::new(); 
      request.body.read_to_string(&mut payload).unwrap(); 
      let json = Json::from_str(&payload).unwrap(); 

      println!("json: {}", json); 

      let token = json.as_object() 
       .and_then(|obj| obj.get("token")) 
       .and_then(|token| token.as_string()) 
       .unwrap_or_else(|| { 
        panic!("Unable to get token"); 
       }); 

      println!("token: {}", token); 

      Ok(()) 
     } 
    } 

    fn attr(input: String, attribute: &str) -> String { 
     let json = Json::from_str(&input).unwrap(); 
     let output = json.as_object() 
      .and_then(|obj| obj.get(attribute)) 
      .and_then(|a| a.as_string()) 
      .unwrap_or_else(|| { 
       panic!("Unable to get attribute {}", attribute); 
      }); 

     String::from(output) 
    } 

    fn hello_world(_: &mut Request) -> IronResult<Response> { 
     let greeting = Greeting { msg: "Hello, world!".to_string() }; 
     let payload = json::encode(&greeting).unwrap(); 
     Ok(Response::with((status::Ok, payload))) 
    } 

    // Receive a message by POST and play it back if auth-key is correct. 
    fn set_greeting(request: &mut Request) -> IronResult<Response> { 
     let mut payload = String::new(); 
     request.body.read_to_string(&mut payload).unwrap(); 
     let json = Json::from_str(&payload).unwrap(); 

     println!("json: {}", json); 

     let msg = attr(payload, "msg"); 

     println!("msg: {}", msg); 

     let greeting = Greeting { msg: String::from(msg) }; 
     let payload = json::encode(&greeting).unwrap(); 

     Ok(Response::with((status::Ok, payload))) 
    } 

    let mut router = Router::new(); 

    router.get("/", hello_world); 
    router.post("/set", set_greeting); 

    let mut chain = Chain::new(router); 
    chain.link_before(Authentication); 

    Iron::new(chain).http("localhost:3000").unwrap(); 
} 
+0

ありがとう、それは多くの助けになります – Cottonwoods

答えて

4

身体を再読み込みするために何かできるとは思っていません。(パフォーマンス上の理由から)代わりに、ミドルウェアがデータを解析して、Request.extensionsに格納することができます。その後、あなたの経路はそれを読み返すでしょう:

struct AuthenticatedBody; 

impl iron::typemap::Key for AuthenticatedBody { 
    type Value = Json; 
} 

struct Authentication; 

impl BeforeMiddleware for Authentication { 
    fn before(&self, request: &mut Request) -> IronResult<()> { 
     let mut payload = String::new(); 
     request.body.read_to_string(&mut payload).unwrap(); 
     let json = Json::from_str(&payload).unwrap(); 

     { 
      let token = json.as_object() 
       .and_then(|obj| obj.get("token")) 
       .and_then(|token| token.as_string()) 
       .unwrap_or_else(|| panic!("Unable to get token")); 
     } // Scoped to end the borrow of `json` 

     request.extensions.insert::<AuthenticatedBody>(json); 

     Ok(()) 
    } 
} 

// ... 

fn set_greeting(request: &mut Request) -> IronResult<Response> { 
    let json = request.extensions.get::<AuthenticatedBody>().unwrap(); 
    // ... 
} 
関連する問題