Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CORS filter #2

Closed
seanmonstar opened this issue Aug 1, 2018 · 6 comments
Closed

Add CORS filter #2

seanmonstar opened this issue Aug 1, 2018 · 6 comments
Labels
feature New feature or request

Comments

@seanmonstar
Copy link
Owner

No description provided.

@digeratus
Copy link

👍🏾+1

@seanmonstar seanmonstar added the feature New feature or request label Aug 13, 2018
@manifest
Copy link

Is there any concept already how it will look in code?

@manifest
Copy link

To support CORS we need to add specific headers only if Origin header is provided.

For preflight requests it's easy to implement using the filter:

warp::options().and(warp::header("origin")).map(|origin| {
    Ok(Response::builder()
        .status(StatusCode::OK)
        .header("access-control-allow-methods", "HEAD, GET")
        .header("access-control-allow-headers", "authorization")
        .header("access-control-allow-credentials", "true")
        .header("access-control-max-age", "300")
        .header("access-control-allow-origin", origin)
        .header("vary", "origin")
        .body(""))
});

What would be the right way to implement handlers for regular requests? Some kind of response extension to check on Origin header?

// If "Origin" header is presented
warp::get2().map(|| {
    Ok(Response::builder()
        .status(StatusCode::OK)
        .header("access-control-allow-origin", origin)
        .header("vary", "origin")
        .body("foobar"))
})

// If it isn't
warp::get2().map(|| {
    Ok(Response::builder()
        .status(StatusCode::OK)
        .body("foobar"))
})

@manifest
Copy link

manifest commented Aug 24, 2018

Probably a handler for a regular request might also be implemented as a filter that initialize response with

Response::builder()
    .header("access-control-allow-origin", origin)
    .header("vary", "origin")

if Origin header is presented and just Response::builder() if isn't.

let cors = warp::any()
    .and(warp::header("origin").map(|origin: String| {
        Response::builder()
            .header("access-control-allow-origin", origin)
            .header("vary", "origin")
    }))
    .or(warp::any().map(|| Response::builder()))
    .unify();

warp::get2()
    .and(cors)
    .map(|response: &mut Builder| {
        Ok(response
            .status(StatusCode::OK)
            .body("foobar"))
    })

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:68:13
   |
68 |             Response::builder()
   |             ^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
...
71 |         }))
   |         - temporary value dropped here while still borrowed
   |
   = note: values in a scope are dropped in the opposite order they are created

Is there any way I can accomplish that?

@seanmonstar
Copy link
Owner Author

Is there any concept already how it will look in code?

What I've had in mind is to make use the sealed Wrap trait, allowing usage with Filter::with:

let cors = warp::cors()
    .allow_origin("my.foo.local")
    .allow_max_age(60 * 10)
    .allow_methods(&["GET", "POST", "DELETE"]);

// chained on any route:
let route = warp::path("api")
    .map(generate_response)
    .with(&cors);

borrowed value does not live long enough

That's because as of 0.1.x, http::response::Builder is a by-ref builder, so methods like header returns &mut Self. Therefore, in your example, you tried to return &mut Builder, which the compiler is saying won't work, because its a pointer to the builder living on the stack, which will be dropped once the closure ends.

@manifest
Copy link

manifest commented Aug 26, 2018

Hi @seanmonstar, thanks for the example. Filter::with looks perfect for this case.

I'm trying to figure out how to implement the cors filter using sealed Wrap trait. If I understand it right, I should seal a function that consumes route and response objects and returns a modified response. But it looks like I can't move out the modified response from route::with(|_route| {...}) closure.

rror[E0507]: cannot move out of captured outer variable in an `Fn` closure
  --> /Users/manifest/projects/github/warp/src/filters/cors.rs:22:13
   |
18 |     let func = |resp: Response| {
   |                 ---- captured outer variable
...
22 |             resp
   |             ^^^^ cannot move out of captured outer variable in an `Fn` closure

error: aborting due to previous error

For more information about this error, try `rustc --explain E0507`.

We can fix it by changing function type of with<F, R>(func: F) from Fn to FnOnce. Shall we do that?

I've opened a PR with all the changes I described to view them at once.

seanmonstar added a commit that referenced this issue Dec 8, 2018
The CORS wrapping filter is similar to `log`, in that it can "wrap"
other filters, and provides support for the CORS protocol.

Closes #2
seanmonstar added a commit that referenced this issue Dec 8, 2018
The CORS wrapping filter is similar to `log`, in that it can "wrap"
other filters, and provides support for the CORS protocol.

Closes #2
seanmonstar added a commit that referenced this issue Dec 8, 2018
The CORS wrapping filter is similar to `log`, in that it can "wrap"
other filters, and provides support for the CORS protocol.

Closes #2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants