Why does nothing happen after matching on a request's path in hyper?

1.2k views Asked by At

I am trying to read POSTed JSON using hyper 0.11.2. I don't see anything happening after "Reached" is printed.

fn call(&self, req: hyper::server::Request) -> Self::Future {
    let mut response: Response = Response::new();

    match (req.method(), req.path()) {
        (&Method::Post, "/assests") => {
             println!("Reached ... "); //POST: 200 OK
            //let (method, uri, _version, head 
            let mut res: Response = Response::new();
            if let Some(len) = req.headers().get::<ContentLength>() {
                res.headers_mut().set(len.clone());
            }

            println!("Reached xxx {:?}", req.body());
            res.with_body("req.body()");
        }
        _ => {
            response.set_status(StatusCode::NotFound);
        }
    };

    futures::future::ok(response)
}

Output:

Reached ...
Reached xxx Body(Body { [stream of values] })
3

There are 3 answers

3
Shepmaster On BEST ANSWER

You created a new Response called response, then created a second Response called res. You then modify res and then throw it away, returning response from your function. If you return the thing you modify, your server returns the string "req.body()", just as you have specified.

fn call(&self, req: hyper::server::Request) -> Self::Future {
    let mut response: Response = Response::new();

    match (req.method(), req.path()) {
        (&Method::Post, "/assets") => {
            if let Some(len) = req.headers().get::<ContentLength>() {
                response.headers_mut().set(len.clone());
            }

            response = response.with_body("req.body()");
        }
        _ => {
            response.set_status(StatusCode::NotFound);
        }
    };

    futures::future::ok(response)
}

I would not set the content-length to an invalid value — your returned string does not match the length of the uploaded data.

2
BalaB On
Below code works, able to parse JSON on POST


#[deny(warnings)]

use hyper::{Post, StatusCode};
use hyper::header::ContentLength;
use hyper::server::{Http, Service, Request, Response};
use futures::{future, Future, Stream}; 
use futures;
use hyper;
use serde_json;
use std::io;
use std::error::Error;


pub struct Persistence;

const SERVICE: &'static str = "Persistence Service";
const SUCCESS: &'static str = r#"{"status": "success"}"#;

impl Service for Persistence {
      type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = futures::BoxFuture<Response, hyper::Error>;

    fn call(&self, req: Request) -> Self::Future {
        let (method, uri, _version, headers, body) = req.deconstruct();
        match (method, uri.path()) {
            (Post, "/assests") => {
                let mut res = Response::new();
                let vec;
                if let Some(len) = headers.get::<ContentLength>() {
                    vec = Vec::with_capacity(**len as usize);
                    res.headers_mut().set(len.clone());
                } else {
                    vec = vec![];
                }
                body.fold(vec, |mut acc, chunk| {
                    acc.extend_from_slice(chunk.as_ref());
                    Ok::<_, hyper::Error>(acc)
                }).and_then(move |value| {
                     use serde_json;

                        let v: serde_json::Value = serde_json::from_slice(&value).map_err(|e| {
                            io::Error::new(
                                io::ErrorKind::Other,
                                e
                            )
                        })?;  
                    println!("value..... {:?}", &v);
                    Ok(res.with_body(SUCCESS))

                }).boxed()
            },
            _ => future::ok(Response::new().with_status(StatusCode::NotFound)).boxed()
        }
    }

}

THanks a lot @Shepmaster :) hip hip hurray!!

0
user2404131 On

according to https://hyper.rs/guides/server/handle_post/#handling-json-and-other-data-types

and here is the code:

extern crate futures;
extern crate hyper;
extern crate serde_json;

use futures::Future;
use futures::{Stream};

use hyper::{Get, Post, StatusCode};
use hyper::header::{ContentLength};
use hyper::server::{Http, Service, Request, Response};

static INDEX: &'static [u8] = b"Try POST /echo";

struct Echo;

impl Service for Echo {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;

    fn call(&self, req: Request) -> Self::Future {
        match (req.method(), req.path()) {
            (&Get, "/") | (&Get, "/echo") => {
                Box::new(futures::future::ok(
                    Response::new()
                        .with_header(ContentLength(INDEX.len() as u64))
                        .with_body(INDEX)))
            },
            (&Post, "/echo") => {
        Box::new(req.body().concat2().map(|b| {
                    let bad_request: &[u8] = b"Missing field";
                    let json: serde_json::Value =
                        if let Ok(j) = serde_json::from_slice(b.as_ref()) {
                        j
                        } else {
                            return Response::new()
                                .with_status(StatusCode::BadRequest)
                                .with_header(ContentLength(bad_request.len() as u64))
                                .with_body(bad_request);
                    };

                    // use json as you like

                    let body = serde_json::to_string(&json).unwrap();
                    Response::new()
                        .with_header(ContentLength(body.len() as u64))
                        .with_body(body)
                }))
            },
            _ => {
                Box::new(futures::future::ok(
                    Response::new().with_status(StatusCode::NotFound)))
            }
        }
    }
}


fn main() {
    let addr = "127.0.0.1:1337".parse().unwrap();

    let server = Http::new().bind(&addr, || Ok(Echo)).unwrap();
    println!("Listening on http://{} with 1 thread.", server.local_addr().unwrap());
    server.run().unwrap();
}