tower-web icon indicating copy to clipboard operation
tower-web copied to clipboard

Accessing incoming requests

Open lnicola opened this issue 7 years ago • 3 comments

It might be useful to be able to access the incoming request, e.g. for compatibility with some libraries. This could probably be supported with an impl Extract for Request, but is there a way to avoid the clone?

EDIT: well, Request isn't Clone anyway.

lnicola avatar Sep 07 '18 20:09 lnicola

This seems to work, at least:

use tower_web::extract::{Context, Extract, Immediate};
use tower_web::util::BufStream;

impl<B: BufStream> Extract<B> for http::Request<()> {
    type Future = Immediate<Self>;

    fn extract(ctx: &Context) -> Self::Future {
        let mut request = http::Request::builder()
            .method(ctx.request().method())
            .version(ctx.request().version())
            .uri(ctx.request().uri())
            .body(())
            .unwrap();
        request
            .headers_mut()
            .extend(ctx.request().headers().clone());
        Immediate::ok(request)
    }
}

lnicola avatar Sep 07 '18 21:09 lnicola

My thought for this would be to add an ExtractRef trait that is always immediate.

The macro would then check the arguments to extract. If they are by value, nothing changes. If they are by reference, then the ExtractRef trait is used.

Request could implement ExtractRef.

carllerche avatar Sep 08 '18 00:09 carllerche

Also, if you only need access to the headers and the body in your project, you could also create your own custom HeaderMap type, like so:

use std::ops::Deref;

use hyper::{self, header::HeaderValue};
use tower_web::extract::{Context, Extract, Immediate};
use tower_web::util::BufStream;

#[derive(Debug, Eq, PartialEq)]
pub struct HeaderMap(hyper::HeaderMap<HeaderValue>);

impl Deref for HeaderMap {
    type Target = hyper::HeaderMap<HeaderValue>;

    fn deref(&self) -> &Self::Target {
        let HeaderMap(ref inner) = *self;
        inner
    }
}

impl<B: BufStream> Extract<B> for HeaderMap {
    type Future = Immediate<Self>;

    fn extract(ctx: &Context) -> Self::Future {
        let map = ctx.request().headers().clone();
        Immediate::ok(HeaderMap(map))
    }
}

Then, in your Web application you can do:

#[derive(Debug)]
struct HelloWorld;

impl_web! {
    impl HelloWorld {
        fn hello_world(&self, headers: HeaderMap, body: Vec<u8>) -> Result<Response, Error> {
             // Manipulate request data here and return response.
        }
    }
}

ebkalderon avatar Oct 24 '18 05:10 ebkalderon