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

Handling Sessions with an 'Environment' #246

Closed
wants to merge 13 commits into from

Conversation

Ryman
Copy link
Member

@Ryman Ryman commented Aug 1, 2015

This builds upon the ideas from #235 to add an 'environment' to each request. See nickel-org/nickel-auth#1 for a related discussion which lead to this proposed change. Session would be really awkward to use correctly without something along the lines of this.

cc @simonpersson

This can be used to add some compile time dependencies for
Middleware and Plugins.

To fix code broken by this, you will need to introduce a type
parameter for Request, Response, MiddlewareResult and NickelError.

```
// e.g. This
fn foo<'a>(&mut Request, Response<'a>) -> MiddlewareResult<'a>

// Should become:
fn foo<'a, D>(&mut Request<D>, Response<'a, D>) -> MiddlewareResult<'a, D>
```

You can add bounds to `D` in the above to place compile-time restrictions on
the server data (can be used for configuration).

BREAKING CHANGE
Also adds `on_send` which can be used to execute code
when the Response headers are being sent.
The 1.2 beta has a regression for this kind of code, so being
explicit should allow us to compile on all targets.
@SimonTeixidor
Copy link
Member

Exciting!

Should we perhaps document the type hinting for the middleware macro somewhere? I think that one example that uses it will be very easy to miss if one runs into this problem.

Other than that, I have no hesitation. Good job! 👍

This is motivated to allow writing Plugins which are able to access
both the current Response and Request without having to rely on odd
syntax such as `(foo, bar).baz()`.

BREAKING CHANGE: This breaks a *lot* of nickel usage, checking the diff
from the examples should help to migrate code relying on the old structure.
This can sometimes be required when using some middleware which are
predicated on the datatype of the Server. An alternative would be to
litter the handler with extra type annotations (which is awkward without
type ascription), or to use explicit type-annotated functions as middleware.

Example usage:
```
middleware! { |res| <ServerData>
   // res is of type Response<ServerData>
}
```
@Ryman
Copy link
Member Author

Ryman commented Aug 1, 2015

Rebased on #247 and updated Ryman@edea3ab with a note about how to use the middleware! macro with a type hint.

I'm thinking we should add an explicit trait requirement for Cookies rather than AsRef<SecretKey> as then we can provide documentation on the trait itself, perhaps providing a better name and explaining what the purpose is.

I'm sure a lot of this needs a bit more annotation, so let me know where else to add!

@SimonTeixidor
Copy link
Member

Nice.

Yes, perhaps an explicit trait could be a good idea. We should probably await comments from someone else. You and I have been working on this for some time, so things that appear to be clear to us might be confusing to others.

This was referenced Aug 7, 2015
@cburgdorf
Copy link
Member

I'm currently building a real world project with nickel that needs Session handling. I figured that this branch may be the most up to date and wanted to give it a try. I'm running into Package "cookie v0.1.20" does not have these features: "secure" though. What do I need to do to get this to compile?

@Ryman
Copy link
Member Author

Ryman commented Aug 8, 2015

It was added in cookie 0.1.21 by the looks of it, have you tried cargo update?

@cburgdorf
Copy link
Member

Ooops, bloody noob mistake. Never mind ;)

format!("You are logged in as: {:?}\n", res.session())
});

server.post("/login", middleware!{|mut res|
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may not see the forest for the tree here. How do I fully test this example? Of course I can send the right json to the running server using something like curl or postman and I get the "successfully logged in" text. But I'd like to test out the entire example (session cookie). So I thought, ok, let's just render a small <form> for the / route that can be used for the login. But that's not gonna work as non ajax submitted forms aren't send as JSON so I would have to change other parts of the example, too.

So I wonder, did you actually test the entire example to see if the session cookie is created by the browser after successful login? If so, how did you test that out?

@Ryman

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See nickel-org/nickel-auth#1, it has a test shell script. (but yes we should have a test written in rust!)

@cburgdorf
Copy link
Member

I played with this a bit more and noticed that in the session_example it directly creates a __SESSION cookie even before /login is called. Is this intended behaviour? Does it automatically create a session because of the Nickel::with_data(ServerData); call where ServerData implements SessionStore?

How would I go if I would like to create the session just after a specific route was called?

@Ryman
Copy link
Member Author

Ryman commented Aug 10, 2015

@cburgdorf The session is quite eager, we could hold off on creating it until there is data written to it (as opposed to only read). In the example, when hitting '/' or '/secret', it would create the session as it gets read, fails to find an active session, and so creates a default one (None in this case).

And yeah, you can't use session at all without implementing the SessionStore for your datatype (and there are a number of dependent traits, the store must be encodable, have a default, etc).

Can you shed light on why you want the Session cookie to only exist after a specific route is called?

@cburgdorf
Copy link
Member

I don't really need it that way but it was unexpected at least. Also some
people may be concerned of unnecessary request bloat. Think of a huge
website where only a minority (e.g admins) will ever make use of the
session. It will create a session cookie for everyone else even if it's not
used/needed.
Am 10.08.2015 03:54 schrieb "Ryman" notifications@github.com:

@cburgdorf https://github.com/cburgdorf The session is quite eager, we
could hold off on creating it until there is data written to it (as opposed
to only read). In the example, when hitting '/' or '/secret', it would
create the session as it gets read, fails to find an active session, and so
creates a default one (None in this case).

And yeah, you can't use session at all without implementing the
SessionStore for your datatype (and there are a number of dependent
traits, the store must be encodable, have a default, etc).

Can you shed light on why you want the Session cookie to only exist after
a specific route is called?


Reply to this email directly or view it on GitHub
#246 (comment).

@Ryman
Copy link
Member Author

Ryman commented Aug 10, 2015

It's a fair point, so perhaps we should only create the session on writes, we'll also need to consider what options are available to tinker with things, e.g. to set the applicable domain for the cookie.

@cburgdorf
Copy link
Member

so perhaps we should only create the session on writes

👍

e.g. to set the applicable domain for the cookie

Yep, that's a good point. Actually I will need to be able to set the domain for the use case that I currently have.

@cburgdorf
Copy link
Member

Hey @Ryman, I have the server that I'm writing as far that it basically does what I want it to do but with a sessionid right in the URL (actually it's even a valid GitHub OAuth token - tell nobody ;)). So, now I wanted to migrate that to use this branch and rely on a session cookie instead. But whoa it's giving me headaches. I wonder if you may be willing to give me a helping hand? It's currently in a private repository but I could give you access to it.

@Ryman
Copy link
Member Author

Ryman commented Aug 27, 2015

Closing in favor of #272

@Ryman Ryman closed this Aug 27, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants