Skip to content

Commit

Permalink
Add examples using cookies
Browse files Browse the repository at this point in the history
One is for a basic data type (usize), and the other shows using your own
custom data type.
  • Loading branch information
illicitonion committed Mar 1, 2018
1 parent 3b4a92d commit 24dd5bc
Show file tree
Hide file tree
Showing 10 changed files with 536 additions and 1 deletion.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ members = [
"examples/query_string/introduction",

# cookies
"examples/cookies/introduction",
"examples/cookies/custom_data_type",

# headers
"examples/headers/setting",
Expand Down
2 changes: 1 addition & 1 deletion examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ information on functionality and ordering.
| [Routing](routing) | Dispatching `Requests` to functionality provided by your application. | 4 |
| [Path](path) | Extracting data from the `Request` path ensuring type safety. | 1 |
| [Query String](query_string) | Extracting data from the `Request` query string whilst ensuring type safety. | 1 |
| [Cookies](cookies) | Working with Cookies. | 0 |
| [Cookies](cookies) | Working with Cookies. | 2 |
| [Headers](headers) | Working with HTTP Headers. | 1 |
| [Handlers](handlers) | Developing application logic that responds to web requests. | 0 |
| [Middleware](middleware) | Developing custom middleware for your application. | 1 |
Expand Down
Empty file removed examples/cookies/.gitkeep
Empty file.
33 changes: 33 additions & 0 deletions examples/cookies/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Cookies Examples

A crate showing how to store and retrieve session data with the Gotham web framework.

## Ordering

We recommend reviewing our cookies 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)
16 changes: 16 additions & 0 deletions examples/cookies/custom_data_type/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "gotham_examples_cookies_custom_data_type"
description = "An introduction to 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"
89 changes: 89 additions & 0 deletions examples/cookies/custom_data_type/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Cookies introduction

An introduction to storing and retrieving session data with a custom data type, in a type safe way, with the Gotham web framework.

## Running

From the `examples/cookies/custom_data_type` directory:

```
Terminal 1:
$ cargo run 130 ↵
Compiling gotham_examples_cookies_custom_data_type v0.0.0 (file://.../gotham/examples/cookies/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)
154 changes: 154 additions & 0 deletions examples/cookies/custom_data_type/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
//! An introduction to 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
);
}
}
12 changes: 12 additions & 0 deletions examples/cookies/introduction/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "gotham_examples_cookies_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"
Loading

0 comments on commit 24dd5bc

Please sign in to comment.