Rocket v0.3: Fairings, TLS, Private Cookies#

Posted by Sergio Benitez on July 14, 2017

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 or learning more from the overview.

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.

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.

: called when a fairing is first registered. Launch : called immediately before the Rocket application launches.

: called immediately before the Rocket application launches. Request : called just after a request is received.

: 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.

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:

1 2 3 [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.

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:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 /// 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.

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:

1 2 3 4 #[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:

1 2 3 4 5 #[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 section of the guide.

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.

type has been added for simple consumption and returning of MessagePack data. Rocket::launch() returns launch failures ( LaunchError ) for inspection without panicking.

returns launch failures ( ) 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.

header structure was added. The Accept request header can be retrieved via Request::accept() .

request header can be retrieved via . All active routes can be retrieved via Rocket::routes() .

. Response::body_string() was added to retrieve the response body as a String .

was added to retrieve the response body as a . Response::body_bytes() was added to retrieve the response body as a Vec<u8> .

was added to retrieve the response body as a . Response::content_type() was added to retrieve the Content-Type header of a response.

was added to retrieve the Content-Type header of a response. Data limits on incoming data are now configurable.

Request::limits() was added to retrieve incoming data 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.

was added for simple retrieval of request guards. Request::route() was added to retrieve the active route, if any.

was added to retrieve the active route, if any. &Route is now a request guard.

is now a request guard. The base mount path of a Route can be retrieved via Route::base or Route::base() .

can be retrieved via or . Config::{development, staging, production} constructors were added for Config .

constructors were added for . Config::get_datetime() was added to retrieve an extra as a Datetime .

was added to retrieve an extra as a . Forms can be now parsed leniently via the new LenientForm data guard.

data guard. The ? operator can now be used with Outcome .

operator can now be used with . Quoted string, array, and table configuration parameters can be set via environment variables.

Log coloring is disabled when stdout is not a TTY.

is not a TTY. FromForm is implemented for Option<T: FromForm> , Result<T: FromForm, T::Error> .

is implemented for , . The NotFound responder was added for simple 404 response construction.

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 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.

HTTP header. The generic parameter of rocket_contrib::Json defaults to json::Value .

defaults to . 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 .

is implemented for and . The port displayed on launch is the port resolved, not the one configured.

The uuid dependency was updated to 0.5 .

dependency was updated to . The base64 dependency was updated to 0.6 .

dependency was updated to . The toml dependency was updated to 0.4 .

dependency was updated to . The handlebars dependency was updated to 0.27 .

dependency was updated to . The tera dependency was updated to 0.10 .

dependency was updated to . yansi is now used for all terminal coloring.

is now used for all terminal coloring. The dev rustc release channel is supported during builds.

release channel is supported during builds. Config is now exported from the root.

is now exported from the root. Request implements Clone and Debug .

implements and . The workers config parameter now defaults to num_cpus * 2 .

config parameter now defaults to . Console logging for table-based config values is improved.

PartialOrd , Ord , and Hash are now implemented for State .

, , and are now implemented for . The format of a request is always logged when available.

Rocket 0.4, of course! The focus of the next major release is two-fold: security and usability. The following major features are planned:

Automatic CSRF protection across all payload-based requests (#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. First-class database support (#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. Typed URL generation from routes (#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.

Contributors to v0.3#

The following wonderful people helped make Rocket v0.3 happen:

Alan Stoate

Alexey Zabelin

Anton Pirker

Fabrice Desré

Ivar Abrahamsen

Josh Holmer

Joshua Rombauer

Lance Carlson

Lori Holden

Roman Frołow

Ryan Leckey

Stephan Buys

Tomek Wałkuski

Vesa Kaihlavirta

Yong Wen Chua

Thank you all! Your contributions are greatly appreciated!

Looking to help with Rocket's development? Head over to Rocket's GitHub and start contributing!