mirror of https://github.com/rwf2/Rocket.git
Allow customizing and removing 'Server' header.
This commit is contained in:
parent
6206a46222
commit
128234d9a8
|
@ -54,6 +54,74 @@ impl<'h> Header<'h> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if `val` is a valid header value.
|
||||
///
|
||||
/// If `allow_empty` is `true`, this function returns `true` for empty
|
||||
/// values. Otherwise, this function returns `false` for empty values.
|
||||
///
|
||||
/// This implements a simple (i.e, correct but not particularly performant)
|
||||
/// header "field-content" checker as defined in RFC 7230 without support
|
||||
/// for obsolete (`obs-`) syntax:
|
||||
///
|
||||
/// field-value = *(field-content)
|
||||
/// field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
|
||||
/// field-vchar = VCHAR
|
||||
/// VCHAR = %x21-7E ; visible (printing) characters
|
||||
///
|
||||
/// Note that this is a generic checker. Specific headers may have stricter
|
||||
/// requirements. For example, the `Server` header does not allow delimiters
|
||||
/// in its values.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # extern crate rocket;
|
||||
/// use rocket::http::Header;
|
||||
///
|
||||
/// assert!(!Header::is_valid_value("", false));
|
||||
/// assert!(!Header::is_valid_value(" " , false));
|
||||
/// assert!(!Header::is_valid_value(" hi", false));
|
||||
/// assert!(!Header::is_valid_value("a\nbc", false));
|
||||
/// assert!(!Header::is_valid_value("\nbc", false));
|
||||
/// assert!(!Header::is_valid_value("\n", false));
|
||||
/// assert!(!Header::is_valid_value("\t", false));
|
||||
/// assert!(!Header::is_valid_value("\r", false));
|
||||
/// assert!(!Header::is_valid_value("a\nb\nc", false));
|
||||
/// assert!(!Header::is_valid_value("a\rb\rc", false));
|
||||
///
|
||||
/// assert!(Header::is_valid_value("", true));
|
||||
/// assert!(Header::is_valid_value("a", false));
|
||||
/// assert!(Header::is_valid_value("a", true));
|
||||
/// assert!(Header::is_valid_value("abc", false));
|
||||
/// assert!(Header::is_valid_value("abc", true));
|
||||
/// assert!(Header::is_valid_value("a b c", false));
|
||||
/// assert!(Header::is_valid_value("a b c", true));
|
||||
/// ```
|
||||
#[doc(hidden)]
|
||||
pub const fn is_valid_value(val: &str, allow_empty: bool) -> bool {
|
||||
const fn is_valid_start(b: &u8) -> bool {
|
||||
b.is_ascii_graphic()
|
||||
}
|
||||
|
||||
const fn is_valid_continue(b: &u8) -> bool {
|
||||
is_valid_start(b) || *b == b' ' || *b == b'\t'
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
let bytes = val.as_bytes();
|
||||
while i < bytes.len() {
|
||||
match i {
|
||||
0 if !is_valid_start(&bytes[i]) => return false,
|
||||
_ if i > 0 && !is_valid_continue(&bytes[i]) => return false,
|
||||
_ => { /* ok */ }
|
||||
};
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
allow_empty || i > 0
|
||||
}
|
||||
|
||||
/// Returns the name of this header.
|
||||
///
|
||||
/// # Example
|
||||
|
|
|
@ -7,7 +7,7 @@ use figment::value::{Map, Dict};
|
|||
use serde::{Deserialize, Serialize};
|
||||
use yansi::Paint;
|
||||
|
||||
use crate::config::{TlsConfig, LogLevel, Shutdown};
|
||||
use crate::config::{TlsConfig, LogLevel, Shutdown, Ident};
|
||||
use crate::request::{self, Request, FromRequest};
|
||||
use crate::data::Limits;
|
||||
|
||||
|
@ -74,6 +74,9 @@ pub struct Config {
|
|||
pub limits: Limits,
|
||||
/// The TLS configuration, if any. **(default: `None`)**
|
||||
pub tls: Option<TlsConfig>,
|
||||
/// How, if at all, to identify the server via the `Server` header.
|
||||
/// **(default: `"Rocket"`)**
|
||||
pub ident: Ident,
|
||||
/// The secret key for signing and encrypting. **(default: `0`)**
|
||||
///
|
||||
/// **Note:** This field _always_ serializes as a 256-bit array of `0`s to
|
||||
|
@ -129,7 +132,6 @@ impl Default for Config {
|
|||
}
|
||||
|
||||
impl Config {
|
||||
|
||||
const DEPRECATED_KEYS: &'static [(&'static str, Option<&'static str>)] = &[
|
||||
("env", Some(Self::PROFILE)), ("log", Some(Self::LOG_LEVEL)),
|
||||
];
|
||||
|
@ -162,6 +164,7 @@ impl Config {
|
|||
keep_alive: 5,
|
||||
limits: Limits::default(),
|
||||
tls: None,
|
||||
ident: Ident::default(),
|
||||
#[cfg(feature = "secrets")]
|
||||
secret_key: SecretKey::zero(),
|
||||
temp_dir: std::env::temp_dir(),
|
||||
|
@ -308,6 +311,7 @@ impl Config {
|
|||
launch_info_!("address: {}", Paint::default(&self.address).bold());
|
||||
launch_info_!("port: {}", Paint::default(&self.port).bold());
|
||||
launch_info_!("workers: {}", Paint::default(self.workers).bold());
|
||||
launch_info_!("ident: {}", Paint::default(&self.ident).bold());
|
||||
|
||||
let ka = self.keep_alive;
|
||||
if ka > 0 {
|
||||
|
|
|
@ -0,0 +1,238 @@
|
|||
use std::fmt;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::de::{self, Deserializer};
|
||||
|
||||
use crate::http::Header;
|
||||
|
||||
/// An identifier (or `None`) to send as the `Server` header.
|
||||
///
|
||||
/// # Deserialization
|
||||
///
|
||||
/// An `Ident` deserializes from any of the following:
|
||||
///
|
||||
/// * `string`
|
||||
///
|
||||
/// The string must be a valid `Ident`. See [`Ident::try_new()`] for details.
|
||||
///
|
||||
/// * `boolean`
|
||||
///
|
||||
/// The boolean must be `false`. The value will be [`Ident::none()`].
|
||||
///
|
||||
/// * `Option<string>`
|
||||
///
|
||||
/// If `Some`, this is the same as deserializing from the inner string. If
|
||||
/// `None`, the value is [`Ident::none()`].
|
||||
///
|
||||
/// * `unit`
|
||||
///
|
||||
/// Always deserializes as [`Ident::none()`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// As with all Rocket configuration options, when using the default
|
||||
/// [`Config::figment()`](crate::Config::figment()), `Ident` can be configured
|
||||
/// via a `Rocket.toml` file. When no value for `ident` is provided, the value
|
||||
/// defaults to `"Rocket"`. Because a default is provided, configuration only
|
||||
/// needs to provided to customize or remove the value.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use rocket::figment::{Figment, providers::{Format, Toml}};
|
||||
/// use rocket::config::{Config, Ident};
|
||||
///
|
||||
/// // If these are the contents of `Rocket.toml`...
|
||||
/// # let toml = Toml::string(r#"
|
||||
/// [default]
|
||||
/// ident = false
|
||||
/// # "#).nested();
|
||||
///
|
||||
/// // The config parses as follows:
|
||||
/// # let config = Config::from(Figment::from(Config::debug_default()).merge(toml));
|
||||
/// assert_eq!(config.ident, Ident::none());
|
||||
///
|
||||
/// // If these are the contents of `Rocket.toml`...
|
||||
/// # let toml = Toml::string(r#"
|
||||
/// [default]
|
||||
/// ident = "My Server"
|
||||
/// # "#).nested();
|
||||
///
|
||||
/// // The config parses as follows:
|
||||
/// # let config = Config::from(Figment::from(Config::debug_default()).merge(toml));
|
||||
/// assert_eq!(config.ident, Ident::try_new("My Server").unwrap());
|
||||
/// ```
|
||||
///
|
||||
/// The following example illustrates manual configuration:
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::config::{Config, Ident};
|
||||
///
|
||||
/// let figment = rocket::Config::figment().merge(("ident", false));
|
||||
/// let config = rocket::Config::from(figment);
|
||||
/// assert_eq!(config.ident, Ident::none());
|
||||
///
|
||||
/// let figment = rocket::Config::figment().merge(("ident", "Fancy/1.0"));
|
||||
/// let config = rocket::Config::from(figment);
|
||||
/// assert_eq!(config.ident, Ident::try_new("Fancy/1.0").unwrap());
|
||||
/// ```
|
||||
#[derive(Debug, Clone, PartialEq, Serialize)]
|
||||
pub struct Ident(Option<String>);
|
||||
|
||||
macro_rules! ident {
|
||||
($value:expr) => {
|
||||
{
|
||||
#[allow(unknown_lints, eq_op)]
|
||||
const _: [(); 0 - !{
|
||||
const ASSERT: bool = $crate::http::Header::is_valid_value($value, false);
|
||||
ASSERT
|
||||
} as usize] = [];
|
||||
|
||||
$crate::config::Ident::try_new($value).unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ident {
|
||||
/// Returns a new `Ident` with the string `ident`.
|
||||
///
|
||||
/// When configured as the [`Config::ident`](crate::Config::ident), Rocket
|
||||
/// will set a `Server` header with the `ident` value on all responses.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// The string `ident` must be non-empty and may only contain visible ASCII
|
||||
/// characters. The first character cannot be whitespace. The only
|
||||
/// whitespace characters allowed are ` ` (space) and `\t` (horizontal tab).
|
||||
/// The string is returned wrapped in `Err` if it contains any invalid
|
||||
/// characters.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::config::Ident;
|
||||
///
|
||||
/// let ident = Ident::try_new("Rocket").unwrap();
|
||||
/// assert_eq!(ident.as_str(), Some("Rocket"));
|
||||
///
|
||||
/// let ident = Ident::try_new("Rocket Run").unwrap();
|
||||
/// assert_eq!(ident.as_str(), Some("Rocket Run"));
|
||||
///
|
||||
/// let ident = Ident::try_new(" Rocket");
|
||||
/// assert!(ident.is_err());
|
||||
///
|
||||
/// let ident = Ident::try_new("Rocket\nRun");
|
||||
/// assert!(ident.is_err());
|
||||
///
|
||||
/// let ident = Ident::try_new("\tShip");
|
||||
/// assert!(ident.is_err());
|
||||
/// ```
|
||||
pub fn try_new<S: Into<String>>(ident: S) -> Result<Ident, String> {
|
||||
// This is a little more lenient than reality.
|
||||
let ident = ident.into();
|
||||
if !Header::is_valid_value(&ident, false) {
|
||||
return Err(ident);
|
||||
}
|
||||
|
||||
Ok(Ident(Some(ident)))
|
||||
}
|
||||
|
||||
/// Returns a new `Ident` which is `None`.
|
||||
///
|
||||
/// When configured as the [`Config::ident`](crate::Config::ident), Rocket
|
||||
/// will not set a `Server` header on any response. Any `Server` header
|
||||
/// emitted by the application will still be written out.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::config::Ident;
|
||||
///
|
||||
/// let ident = Ident::none();
|
||||
/// assert_eq!(ident.as_str(), None);
|
||||
/// ```
|
||||
pub const fn none() -> Ident {
|
||||
Ident(None)
|
||||
}
|
||||
|
||||
/// Returns `self` as an `Option<&str>`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::config::Ident;
|
||||
///
|
||||
/// let ident = Ident::try_new("Rocket").unwrap();
|
||||
/// assert_eq!(ident.as_str(), Some("Rocket"));
|
||||
///
|
||||
/// let ident = Ident::try_new("Rocket/1 (Unix)").unwrap();
|
||||
/// assert_eq!(ident.as_str(), Some("Rocket/1 (Unix)"));
|
||||
///
|
||||
/// let ident = Ident::none();
|
||||
/// assert_eq!(ident.as_str(), None);
|
||||
/// ```
|
||||
pub fn as_str(&self) -> Option<&str> {
|
||||
self.0.as_deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Ident {
|
||||
fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
|
||||
struct Visitor;
|
||||
|
||||
impl<'de> de::Visitor<'de> for Visitor {
|
||||
type Value = Ident;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("a server ident string or `false`")
|
||||
}
|
||||
|
||||
fn visit_bool<E: de::Error>(self, v: bool) -> Result<Self::Value, E> {
|
||||
if !v {
|
||||
return Ok(Ident::none());
|
||||
}
|
||||
|
||||
Err(E::invalid_value(de::Unexpected::Bool(v), &self))
|
||||
}
|
||||
|
||||
fn visit_some<D>(self, de: D) -> Result<Self::Value, D::Error>
|
||||
where D: Deserializer<'de>
|
||||
{
|
||||
de.deserialize_string(self)
|
||||
}
|
||||
|
||||
fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
|
||||
Ok(Ident::none())
|
||||
}
|
||||
|
||||
fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
|
||||
Ok(Ident::none())
|
||||
}
|
||||
|
||||
fn visit_string<E: de::Error>(self, v: String) -> Result<Self::Value, E> {
|
||||
Ident::try_new(v)
|
||||
.map_err(|s| E::invalid_value(de::Unexpected::Str(&s), &self))
|
||||
}
|
||||
|
||||
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
|
||||
self.visit_string(v.into())
|
||||
}
|
||||
}
|
||||
|
||||
de.deserialize_string(Visitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Ident {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.as_str() {
|
||||
Some(name) => name.fmt(f),
|
||||
None => "disabled".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The default `Ident` is `"Rocket"`.
|
||||
impl Default for Ident {
|
||||
fn default() -> Self {
|
||||
ident!("Rocket")
|
||||
}
|
||||
}
|
|
@ -111,6 +111,8 @@
|
|||
//! [`Toml`]: figment::providers::Toml
|
||||
//! [`Env`]: figment::providers::Env
|
||||
|
||||
#[macro_use]
|
||||
mod ident;
|
||||
mod config;
|
||||
mod tls;
|
||||
mod shutdown;
|
||||
|
@ -124,6 +126,7 @@ pub use config::Config;
|
|||
pub use crate::log::LogLevel;
|
||||
pub use shutdown::Shutdown;
|
||||
pub use tls::TlsConfig;
|
||||
pub use ident::Ident;
|
||||
|
||||
#[cfg(feature = "secrets")]
|
||||
#[cfg_attr(nightly, doc(cfg(feature = "secrets")))]
|
||||
|
@ -139,10 +142,20 @@ mod tests {
|
|||
use figment::{Figment, Profile};
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use crate::config::{Config, TlsConfig, Shutdown};
|
||||
use crate::config::{Config, TlsConfig, Shutdown, Ident};
|
||||
use crate::log::LogLevel;
|
||||
use crate::data::{Limits, ToByteUnit};
|
||||
|
||||
#[test]
|
||||
fn test_figment_is_default() {
|
||||
figment::Jail::expect_with(|_| {
|
||||
let mut default: Config = Config::figment().extract().unwrap();
|
||||
default.profile = Config::default().profile;
|
||||
assert_eq!(default, Config::default());
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_default_round_trip() {
|
||||
figment::Jail::expect_with(|_| {
|
||||
|
@ -182,6 +195,7 @@ mod tests {
|
|||
jail.create_file("Rocket.toml", r#"
|
||||
[default]
|
||||
address = "1.2.3.4"
|
||||
ident = "Something Cool"
|
||||
port = 1234
|
||||
workers = 20
|
||||
keep_alive = 10
|
||||
|
@ -194,6 +208,7 @@ mod tests {
|
|||
address: Ipv4Addr::new(1, 2, 3, 4).into(),
|
||||
port: 1234,
|
||||
workers: 20,
|
||||
ident: ident!("Something Cool"),
|
||||
keep_alive: 10,
|
||||
log_level: LogLevel::Off,
|
||||
cli_colors: false,
|
||||
|
@ -203,6 +218,7 @@ mod tests {
|
|||
jail.create_file("Rocket.toml", r#"
|
||||
[global]
|
||||
address = "1.2.3.4"
|
||||
ident = "Something Else Cool"
|
||||
port = 1234
|
||||
workers = 20
|
||||
keep_alive = 10
|
||||
|
@ -215,6 +231,7 @@ mod tests {
|
|||
address: Ipv4Addr::new(1, 2, 3, 4).into(),
|
||||
port: 1234,
|
||||
workers: 20,
|
||||
ident: ident!("Something Else Cool"),
|
||||
keep_alive: 10,
|
||||
log_level: LogLevel::Off,
|
||||
cli_colors: false,
|
||||
|
@ -224,6 +241,7 @@ mod tests {
|
|||
jail.create_file("Rocket.toml", r#"
|
||||
[global]
|
||||
shutdown.ctrlc = 0
|
||||
ident = false
|
||||
|
||||
[global.tls]
|
||||
certs = "/ssl/cert.pem"
|
||||
|
@ -238,6 +256,7 @@ mod tests {
|
|||
let config = Config::from(Config::figment());
|
||||
assert_eq!(config, Config {
|
||||
shutdown: Shutdown { ctrlc: false, ..Default::default() },
|
||||
ident: Ident::none(),
|
||||
tls: Some(TlsConfig::from_paths("/ssl/cert.pem", "/ssl/key.pem")),
|
||||
limits: Limits::default()
|
||||
.limit("forms", 1.mebibytes())
|
||||
|
@ -363,6 +382,16 @@ mod tests {
|
|||
..Config::default()
|
||||
});
|
||||
|
||||
jail.set_env("ROCKET_IDENT", false);
|
||||
let config = Config::from(Config::figment().join(&prev_figment));
|
||||
assert_eq!(config, Config {
|
||||
port: 9999,
|
||||
tls: Some(TlsConfig::from_paths("new.pem", "key.pem")),
|
||||
limits: Limits::default().limit("stream", 100.kibibytes()),
|
||||
ident: Ident::none(),
|
||||
..Config::default()
|
||||
});
|
||||
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@ impl fmt::Display for Sig {
|
|||
///
|
||||
/// ```rust
|
||||
/// # use rocket::figment::{Figment, providers::{Format, Toml}};
|
||||
/// use rocket::{Rocket, Config};
|
||||
/// use rocket::Config;
|
||||
///
|
||||
/// // If these are the contents of `Rocket.toml`...
|
||||
/// # let toml = Toml::string(r#"
|
||||
|
@ -169,8 +169,7 @@ impl fmt::Display for Sig {
|
|||
///
|
||||
/// ```rust
|
||||
/// # use rocket::figment::{Figment, providers::{Format, Toml}};
|
||||
/// use rocket::{Rocket, Config};
|
||||
/// use rocket::config::Shutdown;
|
||||
/// use rocket::config::{Config, Shutdown};
|
||||
///
|
||||
/// #[cfg(unix)]
|
||||
/// use rocket::config::Sig;
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::outcome::{self, IntoOutcome, try_outcome, Outcome::*};
|
|||
|
||||
/// Type alias for the `Outcome` of [`FromData`].
|
||||
///
|
||||
/// [`FromData`]: crTte::data::FromData
|
||||
/// [`FromData`]: crate::data::FromData
|
||||
pub type Outcome<'r, T, E = <T as FromData<'r>>::Error>
|
||||
= outcome::Outcome<T, (Status, E), Data<'r>>;
|
||||
|
||||
|
|
|
@ -210,8 +210,10 @@ impl Rocket<Orbit> {
|
|||
|
||||
// Add a default 'Server' header if it isn't already there.
|
||||
// TODO: If removing Hyper, write out `Date` header too.
|
||||
if !response.headers().contains("Server") {
|
||||
response.set_header(Header::new("Server", "Rocket"));
|
||||
if let Some(ident) = request.rocket().config.ident.as_str() {
|
||||
if !response.headers().contains("Server") {
|
||||
response.set_header(Header::new("Server", ident));
|
||||
}
|
||||
}
|
||||
|
||||
// Run the response fairings.
|
||||
|
|
|
@ -28,5 +28,25 @@ mod conditionally_set_server_header {
|
|||
let response = client.get("/use_default").dispatch();
|
||||
let server = response.headers().get_one("Server");
|
||||
assert_eq!(server, Some("Rocket"));
|
||||
|
||||
// Now with a special `Ident`.
|
||||
|
||||
let config = rocket::Config {
|
||||
ident: rocket::config::Ident::try_new("My Special Server").unwrap(),
|
||||
..rocket::Config::debug_default()
|
||||
};
|
||||
|
||||
let rocket = rocket::custom(config)
|
||||
.mount("/", routes![do_not_overwrite, use_default]);
|
||||
|
||||
let client = Client::debug(rocket).unwrap();
|
||||
|
||||
let response = client.get("/do_not_overwrite").dispatch();
|
||||
let server = response.headers().get_one("Server");
|
||||
assert_eq!(server, Some("Test"));
|
||||
|
||||
let response = client.get("/use_default").dispatch();
|
||||
let server = response.headers().get_one("Server");
|
||||
assert_eq!(server, Some("My Special Server"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ msgpack = "2 MiB"
|
|||
[default]
|
||||
key = "a default app-key"
|
||||
extra = false
|
||||
ident = "Rocket"
|
||||
|
||||
[debug]
|
||||
address = "127.0.0.1"
|
||||
|
|
|
@ -17,21 +17,23 @@ is configured with. This means that no matter which configuration provider
|
|||
Rocket is asked to use, it must be able to read the following configuration
|
||||
values:
|
||||
|
||||
| key | kind | description | debug/release default |
|
||||
|----------------|-----------------|-------------------------------------------------|-----------------------|
|
||||
| `address` | `IpAddr` | IP address to serve on | `127.0.0.1` |
|
||||
| `port` | `u16` | Port to serve on. | `8000` |
|
||||
| `workers` | `usize` | Number of threads to use for executing futures. | cpu core count |
|
||||
| `keep_alive` | `u32` | Keep-alive timeout seconds; disabled when `0`. | `5` |
|
||||
| `log_level` | `LogLevel` | Max level to log. (off/normal/debug/critical) | `normal`/`critical` |
|
||||
| `cli_colors` | `bool` | Whether to use colors and emoji when logging. | `true` |
|
||||
| `secret_key` | `SecretKey` | Secret key for signing and encrypting values. | `None` |
|
||||
| `tls` | `TlsConfig` | TLS configuration, if any. | `None` |
|
||||
| `tls.key` | `&[u8]`/`&Path` | Path/bytes to DER-encoded ASN.1 PKCS#1/#8 key. | |
|
||||
| `tls.certs` | `&[u8]`/`&Path` | Path/bytes to DER-encoded X.509 TLS cert chain. | |
|
||||
| `limits` | `Limits` | Streaming read size limits. | [`Limits::default()`] |
|
||||
| `limits.$name` | `&str`/`uint` | Read limit for `$name`. | forms = "32KiB" |
|
||||
| `ctrlc` | `bool` | Whether `ctrl-c` initiates a server shutdown. | `true` |
|
||||
| key | kind | description | debug/release default |
|
||||
|----------------|-------------------|-------------------------------------------------|-------------------------|
|
||||
| `address` | `IpAddr` | IP address to serve on | `127.0.0.1` |
|
||||
| `port` | `u16` | Port to serve on. | `8000` |
|
||||
| `workers` | `usize` | Number of threads to use for executing futures. | cpu core count |
|
||||
| `ident` | `string`, `false` | If and how to identify via the `Server` header. | `"Rocket"` |
|
||||
| `keep_alive` | `u32` | Keep-alive timeout seconds; disabled when `0`. | `5` |
|
||||
| `log_level` | [`LogLevel`] | Max level to log. (off/normal/debug/critical) | `normal`/`critical` |
|
||||
| `cli_colors` | `bool` | Whether to use colors and emoji when logging. | `true` |
|
||||
| `secret_key` | [`SecretKey`] | Secret key for signing and encrypting values. | `None` |
|
||||
| `tls` | [`TlsConfig`] | TLS configuration, if any. | `None` |
|
||||
| `tls.key` | `&[u8]`/`&Path` | Path/bytes to DER-encoded ASN.1 PKCS#1/#8 key. | |
|
||||
| `tls.certs` | `&[u8]`/`&Path` | Path/bytes to DER-encoded X.509 TLS cert chain. | |
|
||||
| `limits` | [`Limits`] | Streaming read size limits. | [`Limits::default()`] |
|
||||
| `limits.$name` | `&str`/`uint` | Read limit for `$name`. | forms = "32KiB" |
|
||||
| `ctrlc` | `bool` | Whether `ctrl-c` initiates a server shutdown. | `true` |
|
||||
| `shutdown` | [`Shutdown`] | Graceful shutdown configuration. | [`Shutdown::default()`] |
|
||||
|
||||
### Profiles
|
||||
|
||||
|
@ -58,7 +60,129 @@ selected profile doesn't contain a requested values, while values in the
|
|||
[`Json`]: @figment/providers/struct.Json.html
|
||||
[`Figment`]: @api/rocket/struct.Figment.html
|
||||
[`Deserialize`]: @api/rocket/serde/trait.Deserialize.html
|
||||
[`LogLevel`]: @api/rocket/config/enum.LogLevel.html
|
||||
[`Limits`]: @api/rocket/data/struct.Limits.html
|
||||
[`Limits::default()`]: @api/rocket/data/struct.Limits.html#impl-Default
|
||||
[`SecretKey`]: @api/rocket/config/struct.SecretKey.html
|
||||
[`TlsConfig`]: @api/rocket/config/struct.TlsConfig.html
|
||||
[`Shutdown`]: @api/rocket/config/struct.Shutdown.html
|
||||
[`Shutdown::default()`]: @api/rocket/config/struct.Shutdown.html#fields
|
||||
|
||||
## Default Provider
|
||||
|
||||
Rocket's default configuration provider is [`Config::figment()`]; this is the
|
||||
provider that's used when calling [`rocket::build()`].
|
||||
|
||||
The default figment merges, at a per-key level, and reads from the following
|
||||
sources, in ascending priority order:
|
||||
|
||||
1. [`Config::default()`] - which provides default values for all parameters.
|
||||
2. `Rocket.toml` _or_ TOML file path in `ROCKET_CONFIG` environment variable.
|
||||
3. `ROCKET_` prefixed environment variables.
|
||||
|
||||
The selected profile is the value of the `ROCKET_PROFILE` environment variable,
|
||||
or if it is not set, "debug" when compiled in debug mode and "release" when
|
||||
compiled in release mode.
|
||||
|
||||
As a result, without any effort, Rocket's server can be configured via a
|
||||
`Rocket.toml` file and/or via environment variables, the latter of which take
|
||||
precedence over the former. Note that neither the file nor any environment
|
||||
variables need to be present as [`Config::default()`] is a complete
|
||||
configuration source.
|
||||
|
||||
[`Config::default()`]: @api/rocket/struct.Config.html#method.default
|
||||
|
||||
### Rocket.toml
|
||||
|
||||
Rocket searches for `Rocket.toml` or the filename in a `ROCKET_CONFIG`
|
||||
environment variable starting at the current working directory. If it is not
|
||||
found, the parent directory, its parent, and so on, are searched until the file
|
||||
is found or the root is reached. If the path set in `ROCKET_CONFIG` is absolute,
|
||||
no such search occurs and the set path is used directly.
|
||||
|
||||
The file is assumed to be _nested_, so each top-level key declares a profile and
|
||||
its values the value for the profile. The following is an example of what such a
|
||||
file might look like:
|
||||
|
||||
```toml
|
||||
## defaults for _all_ profiles
|
||||
[default]
|
||||
address = "0.0.0.0"
|
||||
limits = { forms = "64 kB", json = "1 MiB" }
|
||||
|
||||
## set only when compiled in debug mode, i.e, `cargo build`
|
||||
[debug]
|
||||
port = 8000
|
||||
## only the `json` key from `default` will be overridden; `forms` will remain
|
||||
limits = { json = "10MiB" }
|
||||
|
||||
## set only when the `nyc` profile is selected
|
||||
[nyc]
|
||||
port = 9001
|
||||
|
||||
## set only when compiled in release mode, i.e, `cargo build --release`
|
||||
## don't use this secret_key! generate your own and keep it private!
|
||||
[release]
|
||||
port = 9999
|
||||
secret_key = "hPRYyVRiMyxpw5sBB1XeCMN1kFsDCqKvBi2QJxBVHQk="
|
||||
```
|
||||
|
||||
The following is a `Rocket.toml` file with all configuration options set for
|
||||
demonstratation purposes. You **do not** and _should not_ set a value for
|
||||
configuration options needlessly, preferring to use the default value when
|
||||
sensible.
|
||||
|
||||
```toml
|
||||
[default]
|
||||
address = "127.0.0.1"
|
||||
port = 8000
|
||||
workers = 16
|
||||
keep_alive = 5
|
||||
ident = "Rocket"
|
||||
log_level = "normal"
|
||||
temp_dir = "/tmp"
|
||||
cli_colors = true
|
||||
## NOTE: Don't (!) use this key! Generate your own!
|
||||
secret_key = "hPRYyVRiMyxpw5sBB1XeCMN1kFsDCqKvBi2QJxBVHQk="
|
||||
|
||||
[default.limits]
|
||||
forms = "64 kB"
|
||||
json = "1 MiB"
|
||||
msgpack = "2 MiB"
|
||||
"file/jpg" = "5 MiB"
|
||||
|
||||
[default.tls]
|
||||
certs = "path/to/cert-chain.pem"
|
||||
key = "path/to/key.pem"
|
||||
|
||||
[default.shutdown]
|
||||
ctrlc = true
|
||||
signals = ["term", "hup"]
|
||||
grace = 5
|
||||
mercy = 5
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Rocket reads all environment variable names prefixed with `ROCKET_` using the
|
||||
string after the `_` as the name of a configuration value as the value of the
|
||||
parameter as the value itself. Environment variables take precedence over values
|
||||
in `Rocket.toml`. Values are parsed as loose form of TOML syntax. Consider the
|
||||
following examples:
|
||||
|
||||
```sh
|
||||
ROCKET_FLOAT=3.14
|
||||
ROCKET_ARRAY=[1,"b",3.14]
|
||||
ROCKET_STRING=Hello
|
||||
ROCKET_STRING="Hello There"
|
||||
|
||||
ROCKET_KEEP_ALIVE=1
|
||||
ROCKET_IDENT=Rocket
|
||||
ROCKET_IDENT="Hello Rocket"
|
||||
ROCKET_IDENT=false
|
||||
ROCKET_TLS={certs="abc",key="foo/bar"}
|
||||
ROCKET_LIMITS={forms="64 KiB"}
|
||||
```
|
||||
|
||||
### Secret Key
|
||||
|
||||
|
@ -66,6 +190,10 @@ The `secret_key` parameter configures a cryptographic key to use when encrypting
|
|||
application values. In particular, the key is used to encrypt [private cookies],
|
||||
which are available only when the `secrets` crate feature is enabled.
|
||||
|
||||
Generating a string suitable for use as a `secret_key` configuration value is
|
||||
usually done through tools like `openssl`. Using `openssl`, a 256-bit base64 key
|
||||
can be generated with the command `openssl rand -base64 32`.
|
||||
|
||||
When compiled in debug mode, a fresh key is generated automatically. In release
|
||||
mode, Rocket requires you to set a secret key if the `secrets` feature is
|
||||
enabled. Failure to do so results in a hard error at launch time. The value of
|
||||
|
@ -106,8 +234,8 @@ the expected value. When a path is configured in a file source, such as
|
|||
`Rocket.toml`, relative paths are interpreted as being relative to the source
|
||||
file's directory.
|
||||
|
||||
! warning: Rocket's built-in TLS implements only TLS 1.2 and 1.3. As such, it
|
||||
may not be suitable for production use.
|
||||
! warning: Rocket's built-in TLS implements only TLS 1.2 and 1.3. It may not be
|
||||
suitable for production use.
|
||||
|
||||
### Workers
|
||||
|
||||
|
@ -120,83 +248,6 @@ only the values set by the `ROCKET_WORKERS` environment variable or in the
|
|||
`workers` property of `Rocket.toml` will be considered - all other `workers`
|
||||
values are ignored.
|
||||
|
||||
## Default Provider
|
||||
|
||||
Rocket's default configuration provider is [`Config::figment()`]; this is the
|
||||
provider that's used when calling [`rocket::build()`].
|
||||
|
||||
The default figment merges, at a per-key level, and reads from the following
|
||||
sources, in ascending priority order:
|
||||
|
||||
1. [`Config::default()`] - which provides default values for all parameters.
|
||||
2. `Rocket.toml` _or_ TOML file path in `ROCKET_CONFIG` environment variable.
|
||||
3. `ROCKET_` prefixed environment variables.
|
||||
|
||||
The selected profile is the value of the `ROCKET_PROFILE` environment variable,
|
||||
or if it is not set, "debug" when compiled in debug mode and "release" when
|
||||
compiled in release mode.
|
||||
|
||||
As a result, without any effort, Rocket's server can be configured via a
|
||||
`Rocket.toml` file and/or via environment variables, the latter of which take
|
||||
precedence over the former. Note that neither the file nor any environment
|
||||
variables need to be present as [`Config::default()`] is a complete
|
||||
configuration source.
|
||||
|
||||
[`Config::default()`]: @api/rocket/struct.Config.html#method.default
|
||||
|
||||
### Rocket.toml
|
||||
|
||||
Rocket searches for `Rocket.toml` or the filename in a `ROCKET_CONFIG`
|
||||
environment variable starting at the current working directory. If it is not
|
||||
found, the parent directory, its parent, and so on, are searched until the file
|
||||
is found or the root is reached. If the path set in `ROCKET_CONFIG` is absolute,
|
||||
no such search occurs, and the set path is used directly.
|
||||
|
||||
The file is assumed to be _nested_, so each top-level key declares a profile and
|
||||
its values the value for the profile. The following is an example of what such a
|
||||
file might look like:
|
||||
|
||||
```toml
|
||||
## defaults for _all_ profiles
|
||||
[default]
|
||||
address = "0.0.0.0"
|
||||
limits = { forms = "64 kB", json = "1 MiB" }
|
||||
|
||||
## set only when compiled in debug mode, i.e, `cargo build`
|
||||
[debug]
|
||||
port = 8000
|
||||
## only the `json` key from `default` will be overridden; `forms` will remain
|
||||
limits = { json = "10MiB" }
|
||||
|
||||
## set only when the `nyc` profile is selected
|
||||
[nyc]
|
||||
port = 9001
|
||||
|
||||
## set only when compiled in release mode, i.e, `cargo build --release`
|
||||
## don't use this secret_key! generate your own and keep it private!
|
||||
[release]
|
||||
port = 9999
|
||||
secret_key = "hPRYyVRiMyxpw5sBB1XeCMN1kFsDCqKvBi2QJxBVHQk="
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Rocket reads all environment variable names prefixed with `ROCKET_` using the
|
||||
string after the `_` as the name of a configuration value as the value of the
|
||||
parameter as the value itself. Environment variables take precedence over values
|
||||
in `Rocket.toml`. Values are parsed as loose form of TOML syntax. Consider the
|
||||
following examples:
|
||||
|
||||
```sh
|
||||
ROCKET_INTEGER=1
|
||||
ROCKET_FLOAT=3.14
|
||||
ROCKET_STRING=Hello
|
||||
ROCKET_STRING="Hello"
|
||||
ROCKET_BOOL=true
|
||||
ROCKET_ARRAY=[1,"b",3.14]
|
||||
ROCKET_DICT={key="abc",val=123}
|
||||
```
|
||||
|
||||
## Extracting Values
|
||||
|
||||
Your application can extract any configuration that implements [`Deserialize`]
|
||||
|
|
Loading…
Reference in New Issue