mirror of https://github.com/rwf2/Rocket.git
332 lines
14 KiB
Markdown
332 lines
14 KiB
Markdown
# Rocket v0.3: Fairings, TLS, Private Cookies
|
|
|
|
<p class="metadata"><strong>
|
|
Posted by <a href="https://sergio.bz">Sergio Benitez</a> on July 14, 2017
|
|
</strong></p>
|
|
|
|
I'm excited to announce that the next major release of Rocket is available
|
|
today! Rocket 0.3 is packed with new features and improvements that increase
|
|
developer productivity, improve application security, and provide new
|
|
opportunities for extensibility. Rocket 0.3 is the culmination of almost 6
|
|
months of work. During this time, more than 225 changes were committed, over 100
|
|
issues (primarily questions and feature requests) were closed, and over 40 pull
|
|
requests were submitted. The Rocket community has proven steadfast in their
|
|
support: a sincere thank you to everyone involved!
|
|
|
|
## About Rocket
|
|
|
|
Rocket is a web framework for Rust with a focus on ease of use, expressibility,
|
|
and speed. Rocket makes it simple to write fast web applications without
|
|
sacrificing flexibility or type safety. All with minimal code.
|
|
|
|
Not already using Rocket? Join the thousands of users and dozens of companies
|
|
happily using Rocket today! Rocket's extensive documentation makes it easy. Get
|
|
started now by [reading through the guide](/guide) or learning more from [the
|
|
overview](/overview).
|
|
|
|
## What's New?
|
|
|
|
Rocket 0.3 is a _big_ release, packed with over 100 changes. We highlight the
|
|
biggest new features here. For a complete description of everything new and
|
|
different in 0.3, please see the [CHANGELOG].
|
|
|
|
[CHANGELOG]: https://github.com/SergioBenitez/Rocket/blob/v0.3.0/CHANGELOG.md#version-030-jul-14-2017
|
|
|
|
### Fairings
|
|
|
|
Fairings bring structured middleware to Rocket. With fairings, Rocket
|
|
applications can hook into the application lifecycle to record or rewrite
|
|
information about incoming requests, outgoing responses, and the Rocket
|
|
application itself.
|
|
|
|
Rocket's fairings are a lot like middleware from other frameworks, but they bear
|
|
a few key distinctions:
|
|
|
|
* Fairings cannot directly terminate or respond to an incoming request.
|
|
* Fairings cannot inject arbitrary, non-request data into a request.
|
|
* Fairings _can_ prevent an application from launching.
|
|
* Fairings _can_ inspect and modify the application's configuration.
|
|
|
|
Fairings are implemented through Rocket's [`Fairing`] trait. The trait consists
|
|
of callback methods that Rocket invokes as needed. A fairing can subscribe to
|
|
receive callbacks for the following four events:
|
|
|
|
* **Attach**: called when a fairing is first registered.
|
|
* **Launch**: called immediately before the Rocket application launches.
|
|
* **Request**: called just after a request is received.
|
|
* **Response**: called when a response is ready to be returned.
|
|
|
|
The new [fairings guide] describes fairings in detail, expands on their
|
|
limitations and abilities, and includes implementation examples. I encourage you
|
|
to experiment with fairings and report your experiences. As always, feedback is
|
|
instrumental in solidifying a robust design.
|
|
|
|
[`Fairing`]: https://api.rocket.rs/rocket/fairing/trait.Fairing.html
|
|
[fairings guide]: /guide/fairings
|
|
|
|
### Native TLS Support
|
|
|
|
Rocket 0.3 includes built-in, experimental support for TLS, powered by
|
|
[`rustls`]. To enable TLS support, compile Rocket with the `tls` feature
|
|
enabled. Then, configure file paths to an RSA certificate chain and
|
|
corresponding private key in the `Rocket.toml` file or via environment
|
|
variables:
|
|
|
|
```toml
|
|
[global.tls]
|
|
certs = "/path/to/certs.pem"
|
|
key = "/path/to/key.pem"
|
|
```
|
|
|
|
TLS support in Rocket is experimental and not yet recommended for general use
|
|
over the internet. Instead, prefer to place Rocket behind a mature reverse-proxy
|
|
such as NGINX. That being said, use of Rocket's TLS support is encouraged for
|
|
local networking (such as local-only IoT devices) or as required during
|
|
development.
|
|
|
|
For more details on Rocket's TLS support, see the [configuring TLS] section of
|
|
the guide.
|
|
|
|
[`rustls`]: https://github.com/ctz/rustls
|
|
[configuring TLS]: /guide/configuration/#configuring-tls
|
|
|
|
### Private Cookies
|
|
|
|
In Rocket 0.3, cookies can be _private_. Private cookies are encrypted using
|
|
authenticated encryption, a form of encryption which simultaneously provides
|
|
confidentiality, integrity, and authenticity. This means that private cookies
|
|
cannot be inspected, tampered with, or manufactured by clients.
|
|
|
|
Retrieving, adding, and removing private cookies is done via the new
|
|
[`get_private`], [`add_private`], and [`remove_private`] methods on the
|
|
[`Cookies`] type. As an example, consider the code below which sets and
|
|
retrieves a `user_id` private cookie in two routes:
|
|
|
|
```rust
|
|
/// Retrieve the user's ID, if any.
|
|
#[get("/user_id")]
|
|
fn user_id(cookies: Cookies) -> Option<String> {
|
|
request.cookies()
|
|
.get_private("user_id")
|
|
.map(|cookie| format!("User ID: {}", cookie.value()))
|
|
}
|
|
|
|
/// Remove the `user_id` cookie.
|
|
#[post("/logout")]
|
|
fn logout(mut cookies: Cookies) -> Flash<Redirect> {
|
|
cookies.remove_private(Cookie::named("user_id"));
|
|
Flash::success(Redirect::to("/"), "Successfully logged out.")
|
|
}
|
|
```
|
|
|
|
To encrypt private cookies, Rocket uses the 256-bit key specified in the
|
|
`secret_key` configuration parameter. If one is not specified, Rocket
|
|
automatically generates a fresh key at launch.
|
|
|
|
For more details on private cookies, see the [private cookies] section of the
|
|
guide.
|
|
|
|
[`Cookies`]: https://api.rocket.rs/rocket/http/enum.Cookies.html
|
|
[`get_private`]: https://api.rocket.rs/rocket/http/enum.Cookies.html#method.get_private
|
|
[`add_private`]: https://api.rocket.rs/rocket/http/enum.Cookies.html#method.add_private
|
|
[`remove_private`]: https://api.rocket.rs/rocket/http/enum.Cookies.html#method.remove_private
|
|
[private cookies]: /guide/requests/#private-cookies
|
|
|
|
### Form Field Naming
|
|
|
|
In 0.2 and below, Rocket always matches form field names to structure field
|
|
names exactly when deriving [`FromForm`]. This presented an issue when an
|
|
invalid Rust identifier was used as a form field's name. For example, it was not
|
|
possible to represent a form with a field name of "type" since `type` is a
|
|
keyword and thus an illegal identifier. The following resulted in a compile-time
|
|
error:
|
|
|
|
```rust
|
|
#[derive(FromForm)]
|
|
struct External {
|
|
type: String
|
|
}
|
|
```
|
|
|
|
In Rocket 0.3, you can ask Rocket to match against a different form field for a
|
|
given structure field by using the `#[form(field = "name")]` field annotation.
|
|
As a result, the "type" form field can now be captured using something like the
|
|
following:
|
|
|
|
```rust
|
|
#[derive(FromForm)]
|
|
struct External {
|
|
#[form(field = "type")]
|
|
api_type: String
|
|
}
|
|
```
|
|
|
|
Rocket will automatically match the form field named "type" to the structure
|
|
field named `api_type`. For more details on form field naming, see the [field
|
|
renaming](/guide/requests/#field-renaming) section of the guide.
|
|
|
|
[`FromForm`]: https://api.rocket.rs/rocket/request/trait.FromForm.html
|
|
|
|
### And Plenty More!
|
|
|
|
In addition to the four highlighted above, Rocket 0.3 also ships with the
|
|
following new features:
|
|
|
|
* A [`MsgPack`] type has been added for simple consumption and returning of
|
|
MessagePack data.
|
|
* [`Rocket::launch()`] returns launch failures ([`LaunchError`]) for
|
|
inspection without panicking.
|
|
* Routes without query parameters now match requests with or without query
|
|
parameters.
|
|
* [Default rankings] prefer static paths and routes with query string matches.
|
|
* A native [`Accept`] header structure was added.
|
|
* The [`Accept`] request header can be retrieved via [`Request::accept()`].
|
|
* All active routes can be retrieved via [`Rocket::routes()`].
|
|
* [`Response::body_string()`] was added to retrieve the response body as a
|
|
`String`.
|
|
* [`Response::body_bytes()`] was added to retrieve the response body as a
|
|
`Vec<u8>`.
|
|
* [`Response::content_type()`] was added to retrieve the Content-Type header
|
|
of a response.
|
|
* Data limits on incoming data are [now
|
|
configurable](/guide/configuration/#data-limits).
|
|
* [`Request::limits()`] was added to retrieve incoming data limits.
|
|
* Responders may dynamically adjust their response based on the incoming
|
|
request.
|
|
* [`Request::guard()`] was added for simple retrieval of request guards.
|
|
* [`Request::route()`] was added to retrieve the active route, if any.
|
|
* [`&Route`] is now a request guard.
|
|
* The base mount path of a [`Route`] can be retrieved via `Route::base` or
|
|
`Route::base()`.
|
|
* `Config::{development, staging, production}` constructors were added for
|
|
[`Config`].
|
|
* [`Config::get_datetime()`] was added to retrieve an extra as a `Datetime`.
|
|
* Forms can be now parsed _leniently_ via the new [`LenientForm`] data guard.
|
|
* The `?` operator can now be used with `Outcome`.
|
|
* Quoted string, array, and table [configuration parameters] can be set via
|
|
environment variables.
|
|
* Log coloring is disabled when `stdout` is not a TTY.
|
|
* [`FromForm`] is implemented for `Option<T: FromForm>`, `Result<T: FromForm,
|
|
T::Error>`.
|
|
* The [`NotFound`] responder was added for simple **404** response
|
|
construction.
|
|
|
|
[`MsgPack`]: https://api.rocket.rs/rocket_contrib/struct.MsgPack.html
|
|
[`Rocket::launch()`]: https://api.rocket.rs/rocket/struct.Rocket.html#method.launch
|
|
[`LaunchError`]: https://api.rocket.rs/rocket/error/struct.LaunchError.html
|
|
[Default rankings]: https://api.rocket.rs/rocket/struct.Route.html
|
|
[`&Route`]: https://api.rocket.rs/rocket/struct.Route.html
|
|
[`Route`]: https://api.rocket.rs/rocket/struct.Route.html
|
|
[`Accept`]: https://api.rocket.rs/rocket/http/struct.Accept.html
|
|
[`Request::accept()`]: https://api.rocket.rs/rocket/struct.Request.html#method.accept
|
|
[`contrib`]: https://api.rocket.rs/rocket_contrib/
|
|
[`Rocket::routes()`]: https://api.rocket.rs/rocket/struct.Rocket.html#method.routes
|
|
[`Response::body_string()`]: https://api.rocket.rs/rocket/struct.Response.html#method.body_string
|
|
[`Response::body_bytes()`]: https://api.rocket.rs/rocket/struct.Response.html#method.body_bytes
|
|
[`Response::content_type()`]: https://api.rocket.rs/rocket/struct.Response.html#method.content_type
|
|
[`Request::guard()`]: https://api.rocket.rs/rocket/struct.Request.html#method.guard
|
|
[`Request::limits()`]: https://api.rocket.rs/rocket/struct.Request.html#method.limits
|
|
[`Request::route()`]: https://api.rocket.rs/rocket/struct.Request.html#method.route
|
|
[`Config`]: https://api.rocket.rs/rocket/struct.Config.html
|
|
[`Cookies`]: https://api.rocket.rs/rocket/http/enum.Cookies.html
|
|
[`Config::get_datetime()`]: https://api.rocket.rs/rocket/struct.Config.html#method.get_datetime
|
|
[`LenientForm`]: https://api.rocket.rs/rocket/request/struct.LenientForm.html
|
|
[configuration parameters]: https://api.rocket.rs/rocket/config/index.html#environment-variables
|
|
[`NotFound`]: https://api.rocket.rs/rocket/response/status/struct.NotFound.html
|
|
|
|
## Breaking Changes
|
|
|
|
This release includes many breaking changes such as support for `serde` 1.0. To
|
|
keep this release note short, please see the
|
|
[CHANGELOG](https://github.com/SergioBenitez/Rocket/blob/v0.3.0/CHANGELOG.md#breaking-changes)
|
|
for the full list of breaking changes along with a short note about how to
|
|
handle the breaking change in existing applications.
|
|
|
|
## General Improvements
|
|
|
|
In addition to new features, Rocket saw the following improvements:
|
|
|
|
* "Rocket" is now capitalized in the `Server` HTTP header.
|
|
* The generic parameter of `rocket_contrib::Json` defaults to `json::Value`.
|
|
* The trailing '...' in the launch message was removed.
|
|
* The launch message prints regardless of the config environment.
|
|
* For debugging, `FromData` is implemented for `Vec<u8>` and `String`.
|
|
* The port displayed on launch is the port resolved, not the one configured.
|
|
* The `uuid` dependency was updated to `0.5`.
|
|
* The `base64` dependency was updated to `0.6`.
|
|
* The `toml` dependency was updated to `0.4`.
|
|
* The `handlebars` dependency was updated to `0.27`.
|
|
* The `tera` dependency was updated to `0.10`.
|
|
* [`yansi`] is now used for all terminal coloring.
|
|
* The `dev` `rustc` release channel is supported during builds.
|
|
* [`Config`] is now exported from the root.
|
|
* [`Request`] implements `Clone` and `Debug`.
|
|
* The `workers` config parameter now defaults to `num_cpus * 2`.
|
|
* Console logging for table-based config values is improved.
|
|
* `PartialOrd`, `Ord`, and `Hash` are now implemented for [`State`].
|
|
* The format of a request is always logged when available.
|
|
|
|
[`yansi`]: https://crates.io/crates/yansi
|
|
[`Request`]: https://api.rocket.rs/rocket/struct.Request.html
|
|
[`State`]: https://api.rocket.rs/rocket/struct.State.html
|
|
[`Config`]: https://api.rocket.rs/rocket/struct.Config.html
|
|
|
|
## What's Next?
|
|
|
|
Rocket 0.4, of course! The focus of the next major release is two-fold: security
|
|
and usability. The following major features are planned:
|
|
|
|
1. **Automatic CSRF protection across all payload-based requests
|
|
([#14](https://github.com/SergioBenitez/Rocket/issues/14)).**
|
|
|
|
This is a carry-over from the 0.3 wishlist. Rocket will automatically check
|
|
the origin of requests made for HTTP `PUT`, `POST`, `DELETE`, and `PATCH`
|
|
requests, allowing only valid requests to be dispatched. This includes
|
|
checking form submissions and requests made via JavaScript.
|
|
|
|
2. **First-class database support
|
|
([#167](https://github.com/SergioBenitez/Rocket/issues/167)).**
|
|
|
|
Connecting a database to Rocket is presently [much wordier than necessary].
|
|
The plan for 0.4 is to minimize the amount of effort. At most, a couple of
|
|
lines of configuration and a single line of initialization code should be
|
|
required.
|
|
|
|
3. **Typed URL generation from routes
|
|
([#263](https://github.com/SergioBenitez/Rocket/issues/263)).**
|
|
|
|
Explicitly writing URLs is error-prone. Because routes are fully-typed in
|
|
Rocket, it's possible to check that a URL corresponding to a route
|
|
type-checks. In the next release, a `url!` macro will be available to
|
|
automatically generate URLs for routes in a type-safe manner.
|
|
|
|
[much wordier than necessary]: /guide/state/#databases
|
|
|
|
## Contributors to v0.3
|
|
|
|
The following wonderful people helped make Rocket v0.3 happen:
|
|
|
|
<ul class="columns">
|
|
<li>Alan Stoate</li>
|
|
<li>Alexey Zabelin</li>
|
|
<li>Anton Pirker</li>
|
|
<li>Fabrice Desré</li>
|
|
<li>Ivar Abrahamsen</li>
|
|
<li>Josh Holmer</li>
|
|
<li>Joshua Rombauer</li>
|
|
<li>Lance Carlson</li>
|
|
<li>Lori Holden</li>
|
|
<li>Roman Frołow</li>
|
|
<li>Ryan Leckey</li>
|
|
<li>Stephan Buys</li>
|
|
<li>Tomek Wałkuski</li>
|
|
<li>Vesa Kaihlavirta</li>
|
|
<li>Yong Wen Chua</li>
|
|
</ul>
|
|
|
|
Thank you all! Your contributions are greatly appreciated!
|
|
|
|
Looking to help with Rocket's development? Head over to [Rocket's
|
|
GitHub](https://github.com/SergioBenitez/Rocket#contributing) and start
|
|
contributing!
|