Rocket/site/news/2017-07-14-version-0.3.md

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, expressiveness,
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-v0.3) 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`]: @api-v0.3/rocket/fairing/trait.Fairing.html
[fairings guide]: @guide-v0.3/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-v0.3/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`]: @api-v0.3/rocket/http/enum.Cookies.html
[`get_private`]: @api-v0.3/rocket/http/enum.Cookies.html#method.get_private
[`add_private`]: @api-v0.3/rocket/http/enum.Cookies.html#method.add_private
[`remove_private`]: @api-v0.3/rocket/http/enum.Cookies.html#method.remove_private
[private cookies]: @guide-v0.3/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-v0.3/requests/#field-renaming) section of the guide.
[`FromForm`]: @api-v0.3/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-v0.3/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`]: @api-v0.3/rocket_contrib/msgpack/struct.MsgPack.html
[`Rocket::launch()`]: @api-v0.3/rocket/struct.Rocket.html#method.launch
[`LaunchError`]: @api-v0.3/rocket/error/struct.LaunchError.html
[Default rankings]: @api-v0.3/rocket/struct.Route.html
[`&Route`]: @api-v0.3/rocket/struct.Route.html
[`Route`]: @api-v0.3/rocket/struct.Route.html
[`Accept`]: @api-v0.3/rocket/http/struct.Accept.html
[`Request::accept()`]: @api-v0.3/rocket/struct.Request.html#method.accept
[`contrib`]: @api-v0.3/rocket_contrib/
[`Rocket::routes()`]: @api-v0.3/rocket/struct.Rocket.html#method.routes
[`Response::body_string()`]: @api-v0.3/rocket/struct.Response.html#method.body_string
[`Response::body_bytes()`]: @api-v0.3/rocket/struct.Response.html#method.body_bytes
[`Response::content_type()`]: @api-v0.3/rocket/struct.Response.html#method.content_type
[`Request::guard()`]: @api-v0.3/rocket/struct.Request.html#method.guard
[`Request::limits()`]: @api-v0.3/rocket/struct.Request.html#method.limits
[`Request::route()`]: @api-v0.3/rocket/struct.Request.html#method.route
[`Config`]: @api-v0.3/rocket/struct.Config.html
[`Cookies`]: @api-v0.3/rocket/http/enum.Cookies.html
[`Config::get_datetime()`]: @api-v0.3/rocket/struct.Config.html#method.get_datetime
[`LenientForm`]: @api-v0.3/rocket/request/struct.LenientForm.html
[configuration parameters]: @api-v0.3/rocket/config/index.html#environment-variables
[`NotFound`]: @api-v0.3/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`]: @api-v0.3/rocket/struct.Request.html
[`State`]: @api-v0.3/rocket/struct.State.html
[`Config`]: @api-v0.3/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-v0.3/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!