-
Notifications
You must be signed in to change notification settings - Fork 125
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 examples using sessions #168
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
78a9bb6
Add examples using cookies
illicitonion 4d9d9c3
Rename to sessions
illicitonion 6a4e768
fmt
illicitonion 3732a9e
Minor readme tweak for session example
bradleybeddoes 385ece2
Minor description tweak session example Cargo.toml
bradleybeddoes 05fb3f9
Minor tweak to session example module comment
bradleybeddoes File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# Sessions Examples | ||
|
||
A collection of crates showing how to store and retrieve session data with the Gotham web framework. | ||
|
||
## Ordering | ||
|
||
We recommend reviewing our sessions examples in the order shown below: | ||
|
||
1. [Introduction](introduction) - Shows how to store and retrieve session data. | ||
2. [Custom data type](custom_data_type) - Shows how to store and retrieve session data with a custom data type. | ||
|
||
## Help | ||
|
||
You can get help for the Gotham web framework at: | ||
|
||
* [The Gotham web framework website](https://gotham.rs) | ||
* [Gotham web framework API documentation](https://docs.rs/gotham/) | ||
* [Gitter chatroom](https://gitter.im/gotham-rs/gotham) | ||
* [Twitter](https://twitter.com/gotham_rs) | ||
|
||
## License | ||
|
||
Licensed under your option of: | ||
|
||
* [MIT License](../LICENSE-MIT) | ||
* [Apache License, Version 2.0](../LICENSE-APACHE) | ||
|
||
## Community | ||
|
||
The following policies guide participation in our project and our community: | ||
|
||
* [Code of conduct](../../CODE_OF_CONDUCT.md) | ||
* [Contributing](../../CONTRIBUTING.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
[package] | ||
name = "gotham_examples_session_custom_data_type" | ||
description = "Storing and retrieving session data with a custom data type, in a type safe way, with the Gotham web framework." | ||
version = "0.0.0" | ||
authors = ["Daniel Wagner-Hall <dawagner@gmail.com>"] | ||
publish = false | ||
|
||
[dependencies] | ||
gotham = { path = "../../../gotham" } | ||
gotham_derive = { path = "../../../gotham_derive" } | ||
|
||
hyper = "0.11" | ||
mime = "0.3" | ||
serde = "1" | ||
serde_derive = "1" | ||
time = "0.1.39" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
# Custom session data types | ||
|
||
Storing and retrieving session data with a custom data type, in a type safe way, with the Gotham web framework. | ||
|
||
## Running | ||
|
||
From the `examples/session/custom_data_type` directory: | ||
|
||
``` | ||
Terminal 1: | ||
$ cargo run 130 ↵ | ||
Compiling gotham_examples_session_custom_data_type v0.0.0 (file://.../gotham/examples/session/custom_data_type) | ||
Finished dev [unoptimized + debuginfo] target(s) in 2.49 secs | ||
Running `.../gotham/target/debug/gotham_examples_cookies_custom_data_type` | ||
Listening for requests at http://127.0.0.1:7878 | ||
|
||
Terminal 2: | ||
$ curl -v -c /tmp/cookiejar http://localhost:7878 | ||
* Rebuilt URL to: http://localhost:7878/ | ||
* Trying ::1... | ||
* TCP_NODELAY set | ||
* Connection failed | ||
* connect to ::1 port 7878 failed: Connection refused | ||
* Trying 127.0.0.1... | ||
* TCP_NODELAY set | ||
* Connected to localhost (127.0.0.1) port 7878 (#0) | ||
> GET / HTTP/1.1 | ||
> Host: localhost:7878 | ||
> User-Agent: curl/7.54.0 | ||
> Accept: */* | ||
> | ||
< HTTP/1.1 200 OK | ||
< Content-Length: 41 | ||
< Content-Type: text/plain | ||
< X-Request-ID: 5fdd0a88-4b23-4c68-8f6b-91d3c6a69fd4 | ||
< X-Frame-Options: DENY | ||
< X-XSS-Protection: 1; mode=block | ||
< X-Content-Type-Options: nosniff | ||
* Added cookie _gotham_session="op-CELe5R-mEJ3zxhcak4eElI5EUtslBLbZ6chyUvAWzEwkvAkPUBzsHj014xHW1tWq0RG4vyXSnXDZneqfxyA" for domain localhost, path /, expire 0 | ||
< Set-Cookie: _gotham_session=op-CELe5R-mEJ3zxhcak4eElI5EUtslBLbZ6chyUvAWzEwkvAkPUBzsHj014xHW1tWq0RG4vyXSnXDZneqfxyA; HttpOnly; SameSite=Lax; Path=/ | ||
< X-Runtime-Microseconds: 1143 | ||
< Date: Thu, 01 Mar 2018 00:29:10 GMT | ||
< | ||
You have never visited this page before. | ||
* Connection #0 to host localhost left intact | ||
|
||
$ curl -v -b /tmp/cookiejar http://localhost:7878 | ||
* Rebuilt URL to: http://localhost:7878/ | ||
* Trying ::1... | ||
* TCP_NODELAY set | ||
* Connection failed | ||
* connect to ::1 port 7878 failed: Connection refused | ||
* Trying 127.0.0.1... | ||
* TCP_NODELAY set | ||
* Connected to localhost (127.0.0.1) port 7878 (#0) | ||
> GET / HTTP/1.1 | ||
> Host: localhost:7878 | ||
> User-Agent: curl/7.54.0 | ||
> Accept: */* | ||
> Cookie: _gotham_session=op-CELe5R-mEJ3zxhcak4eElI5EUtslBLbZ6chyUvAWzEwkvAkPUBzsHj014xHW1tWq0RG4vyXSnXDZneqfxyA | ||
> | ||
< HTTP/1.1 200 OK | ||
< Content-Length: 87 | ||
< Content-Type: text/plain | ||
< X-Request-ID: 0a202d40-2c89-418e-82b0-5854c0041665 | ||
< X-Frame-Options: DENY | ||
< X-XSS-Protection: 1; mode=block | ||
< X-Content-Type-Options: nosniff | ||
< X-Runtime-Microseconds: 400 | ||
< Date: Thu, 01 Mar 2018 00:29:13 GMT | ||
< | ||
You have visited this page 1 time(s) before. Your last visit was 2018-03-01T00:29:10Z. | ||
* Connection #0 to host localhost left intact | ||
|
||
``` | ||
|
||
## License | ||
|
||
Licensed under your option of: | ||
|
||
* [MIT License](../../LICENSE-MIT) | ||
* [Apache License, Version 2.0](../../LICENSE-APACHE) | ||
|
||
## Community | ||
|
||
The following policies guide participation in our project and our community: | ||
|
||
* [Code of conduct](../../CODE_OF_CONDUCT.md) | ||
* [Contributing](../../CONTRIBUTING.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
//! Storing and retrieving session data with a custom data type, in a type safe | ||
//! way, with the Gotham web framework. | ||
|
||
extern crate gotham; | ||
#[macro_use] | ||
extern crate gotham_derive; | ||
extern crate hyper; | ||
extern crate mime; | ||
extern crate serde; | ||
#[macro_use] | ||
extern crate serde_derive; | ||
extern crate time; | ||
|
||
use hyper::{Response, StatusCode}; | ||
|
||
use gotham::http::response::create_response; | ||
use gotham::pipeline::new_pipeline; | ||
use gotham::pipeline::single::single_pipeline; | ||
use gotham::router::Router; | ||
use gotham::router::builder::*; | ||
use gotham::state::{FromState, State}; | ||
use gotham::middleware::session::{NewSessionMiddleware, SessionData}; | ||
|
||
// A custom type for storing data associated with the user's session. | ||
#[derive(Clone, Deserialize, Serialize, StateData)] | ||
struct VisitData { | ||
count: usize, | ||
last_visit: String, | ||
} | ||
|
||
/// Handler function for `GET` requests directed to `/` | ||
/// | ||
/// Each request made will update state about your recent visits, and report it back. | ||
fn get_handler(mut state: State) -> (State, Response) { | ||
let maybe_visit_data = { | ||
let visit_data: &Option<VisitData> = SessionData::<Option<VisitData>>::borrow_from(&state); | ||
visit_data.clone() | ||
}; | ||
|
||
let body = match &maybe_visit_data { | ||
&Some(ref visit_data) => format!( | ||
"You have visited this page {} time(s) before. Your last visit was {}.\n", | ||
visit_data.count, visit_data.last_visit, | ||
), | ||
&None => "You have never visited this page before.\n".to_owned(), | ||
}; | ||
let res = { | ||
create_response( | ||
&state, | ||
StatusCode::Ok, | ||
Some((body.as_bytes().to_vec(), mime::TEXT_PLAIN)), | ||
) | ||
}; | ||
{ | ||
let visit_data: &mut Option<VisitData> = | ||
SessionData::<Option<VisitData>>::borrow_mut_from(&mut state); | ||
let old_count = maybe_visit_data.map(|v| v.count).unwrap_or(0); | ||
*visit_data = Some(VisitData { | ||
count: old_count + 1, | ||
last_visit: format!("{}", time::now().rfc3339()), | ||
}); | ||
} | ||
(state, res) | ||
} | ||
|
||
/// Create a `Router` | ||
fn router() -> Router { | ||
let middleware = NewSessionMiddleware::default() | ||
.with_session_type::<Option<VisitData>>() | ||
// By default, the cookies used are only sent over secure connections. For our test server, | ||
// we don't set up an HTTPS certificate, so we allow the cookies to be sent over insecure | ||
// connections. This should not be done in real applications. | ||
.insecure(); | ||
let (chain, pipelines) = single_pipeline(new_pipeline().add(middleware).build()); | ||
build_router(chain, pipelines, |route| { | ||
route.get("/").to(get_handler); | ||
}) | ||
} | ||
|
||
/// Start a server and use a `Router` to dispatch requests | ||
pub fn main() { | ||
let addr = "127.0.0.1:7878"; | ||
println!("Listening for requests at http://{}", addr); | ||
gotham::start(addr, router()) | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use gotham::test::TestServer; | ||
use hyper::header::{Cookie, SetCookie}; | ||
use std::borrow::Cow; | ||
|
||
#[test] | ||
fn cookie_is_set_and_updates_response() { | ||
let test_server = TestServer::new(router()).unwrap(); | ||
let response = test_server | ||
.client() | ||
.get("http://localhost/") | ||
.perform() | ||
.unwrap(); | ||
|
||
assert_eq!(response.status(), StatusCode::Ok); | ||
|
||
let set_cookie: Vec<String> = { | ||
let cookie_header = response.headers().get::<SetCookie>(); | ||
assert!(cookie_header.is_some()); | ||
cookie_header.unwrap().0.clone() | ||
}; | ||
assert!(set_cookie.len() == 1); | ||
|
||
let body = response.read_body().unwrap(); | ||
assert_eq!( | ||
&body[..], | ||
"You have never visited this page before.\n".as_bytes() | ||
); | ||
|
||
let cookie = { | ||
let mut cookie = Cookie::new(); | ||
|
||
let only_cookie: String = set_cookie.get(0).unwrap().clone(); | ||
let cookie_components: Vec<_> = only_cookie.split(";").collect(); | ||
let cookie_str_parts: Vec<_> = cookie_components.get(0).unwrap().split("=").collect(); | ||
cookie.append( | ||
Cow::Owned(cookie_str_parts.get(0).unwrap().to_string()), | ||
Cow::Owned(cookie_str_parts.get(1).unwrap().to_string()), | ||
); | ||
cookie | ||
}; | ||
|
||
let response = test_server | ||
.client() | ||
.get("http://localhost/") | ||
.with_header(cookie) | ||
.perform() | ||
.unwrap(); | ||
|
||
assert_eq!(response.status(), StatusCode::Ok); | ||
let body = response.read_body().unwrap(); | ||
let body_string = String::from_utf8(body).unwrap(); | ||
assert!( | ||
body_string | ||
.starts_with("You have visited this page 1 time(s) before. Your last visit was ",), | ||
"Wrong body: {}", | ||
body_string | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
[package] | ||
name = "gotham_examples_session_introduction" | ||
description = "An introduction to storing and retrieving session data, in a type safe way, with the Gotham web framework." | ||
version = "0.0.0" | ||
authors = ["Daniel Wagner-Hall <dawagner@gmail.com>"] | ||
publish = false | ||
|
||
[dependencies] | ||
gotham = { path = "../../../gotham" } | ||
|
||
hyper = "0.11" | ||
mime = "0.3" |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was trying to work out whether this could be done without the clone() and without the type-coercing noise. I think that deref() and deref_mut() help a lot here. This is what I came up with:
I'm not sure if I like my match that returns a tuple of (visit_count, body) or not: I think my mind is still in python mode. I suspect that it would get increasingly awkward as the view gets more complicated. Might be better to stick with .clone().
(Thanks for writing this by the way: I was wondering how to use the session middleware)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy to stick with the
clone
for now to try and keep examples simple. Longer term I am hopeful that NLL will help here.When I get a moment I might even grab a nightly compiler and give that a go on a few of our examples now that there is a feature flag for it.