14 KiB
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.
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.
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.
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:
[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:
/// 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:
#[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:
#[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. 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 viaRequest::accept()
. - All active routes can be retrieved via
Rocket::routes()
. Response::body_string()
was added to retrieve the response body as aString
.Response::body_bytes()
was added to retrieve the response body as aVec<u8>
.Response::content_type()
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.- 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 viaRoute::base
orRoute::base()
. Config::{development, staging, production}
constructors were added forConfig
.Config::get_datetime()
was added to retrieve an extra as aDatetime
.- Forms can be now parsed leniently via the new
LenientForm
data guard. - The
?
operator can now be used withOutcome
. - 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 forOption<T: FromForm>
,Result<T: FromForm, T::Error>
.- 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. - The generic parameter of
rocket_contrib::Json
defaults tojson::Value
. - The trailing '...' in the launch message was removed.
- The launch message prints regardless of the config environment.
- For debugging,
FromData
is implemented forVec<u8>
andString
. - The port displayed on launch is the port resolved, not the one configured.
- The
uuid
dependency was updated to0.5
. - The
base64
dependency was updated to0.6
. - The
toml
dependency was updated to0.4
. - The
handlebars
dependency was updated to0.27
. - The
tera
dependency was updated to0.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
implementsClone
andDebug
.- The
workers
config parameter now defaults tonum_cpus * 2
. - Console logging for table-based config values is improved.
PartialOrd
,Ord
, andHash
are now implemented forState
.- The format of a request is always logged when available.
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:
- 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!