mirror of
https://github.com/rwf2/Rocket.git
synced 2025-01-22 17:32:06 +00:00
parent
3970783d06
commit
86bd7c1008
@ -16,6 +16,12 @@ pub struct ConfigBuilder {
|
||||
pub workers: u16,
|
||||
/// Keep-alive timeout in seconds or disabled if 0.
|
||||
pub keep_alive: u32,
|
||||
/// Number of seconds to wait without _receiving_ data before closing a
|
||||
/// connection; disabled when `None`.
|
||||
pub read_timeout: u32,
|
||||
/// Number of seconds to wait without _sending_ data before closing a
|
||||
/// connection; disabled when `None`.
|
||||
pub write_timeout: u32,
|
||||
/// How much information to log.
|
||||
pub log_level: LoggingLevel,
|
||||
/// The secret key.
|
||||
@ -57,6 +63,8 @@ impl ConfigBuilder {
|
||||
port: config.port,
|
||||
workers: config.workers,
|
||||
keep_alive: config.keep_alive.unwrap_or(0),
|
||||
read_timeout: config.read_timeout.unwrap_or(0),
|
||||
write_timeout: config.write_timeout.unwrap_or(0),
|
||||
log_level: config.log_level,
|
||||
secret_key: None,
|
||||
tls: None,
|
||||
@ -148,6 +156,58 @@ impl ConfigBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the read timeout to `timeout` seconds. If `timeout` is `0`,
|
||||
/// read timeouts are disabled.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::config::{Config, Environment};
|
||||
///
|
||||
/// let config = Config::build(Environment::Staging)
|
||||
/// .read_timeout(10)
|
||||
/// .unwrap();
|
||||
///
|
||||
/// assert_eq!(config.read_timeout, Some(10));
|
||||
///
|
||||
/// let config = Config::build(Environment::Staging)
|
||||
/// .read_timeout(0)
|
||||
/// .unwrap();
|
||||
///
|
||||
/// assert_eq!(config.read_timeout, None);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn read_timeout(mut self, timeout: u32) -> Self {
|
||||
self.read_timeout = timeout;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the write timeout to `timeout` seconds. If `timeout` is `0`,
|
||||
/// write timeouts are disabled.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::config::{Config, Environment};
|
||||
///
|
||||
/// let config = Config::build(Environment::Staging)
|
||||
/// .write_timeout(10)
|
||||
/// .unwrap();
|
||||
///
|
||||
/// assert_eq!(config.write_timeout, Some(10));
|
||||
///
|
||||
/// let config = Config::build(Environment::Staging)
|
||||
/// .write_timeout(0)
|
||||
/// .unwrap();
|
||||
///
|
||||
/// assert_eq!(config.write_timeout, None);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn write_timeout(mut self, timeout: u32) -> Self {
|
||||
self.write_timeout = timeout;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the `log_level` in the configuration being built.
|
||||
///
|
||||
/// # Example
|
||||
@ -318,6 +378,8 @@ impl ConfigBuilder {
|
||||
config.set_port(self.port);
|
||||
config.set_workers(self.workers);
|
||||
config.set_keep_alive(self.keep_alive);
|
||||
config.set_read_timeout(self.read_timeout);
|
||||
config.set_write_timeout(self.write_timeout);
|
||||
config.set_log_level(self.log_level);
|
||||
config.set_extras(self.extras);
|
||||
config.set_limits(self.limits);
|
||||
|
@ -46,6 +46,12 @@ pub struct Config {
|
||||
pub workers: u16,
|
||||
/// Keep-alive timeout in seconds or None if disabled.
|
||||
pub keep_alive: Option<u32>,
|
||||
/// Number of seconds to wait without _receiving_ data before closing a
|
||||
/// connection; disabled when `None`.
|
||||
pub read_timeout: Option<u32>,
|
||||
/// Number of seconds to wait without _sending_ data before closing a
|
||||
/// connection; disabled when `None`.
|
||||
pub write_timeout: Option<u32>,
|
||||
/// How much information to log.
|
||||
pub log_level: LoggingLevel,
|
||||
/// The secret key.
|
||||
@ -229,6 +235,8 @@ impl Config {
|
||||
port: 8000,
|
||||
workers: default_workers,
|
||||
keep_alive: Some(5),
|
||||
read_timeout: Some(5),
|
||||
write_timeout: Some(5),
|
||||
log_level: LoggingLevel::Normal,
|
||||
secret_key: key,
|
||||
tls: None,
|
||||
@ -245,6 +253,8 @@ impl Config {
|
||||
port: 8000,
|
||||
workers: default_workers,
|
||||
keep_alive: Some(5),
|
||||
read_timeout: Some(5),
|
||||
write_timeout: Some(5),
|
||||
log_level: LoggingLevel::Normal,
|
||||
secret_key: key,
|
||||
tls: None,
|
||||
@ -261,6 +271,8 @@ impl Config {
|
||||
port: 8000,
|
||||
workers: default_workers,
|
||||
keep_alive: Some(5),
|
||||
read_timeout: Some(5),
|
||||
write_timeout: Some(5),
|
||||
log_level: LoggingLevel::Critical,
|
||||
secret_key: key,
|
||||
tls: None,
|
||||
@ -307,6 +319,8 @@ impl Config {
|
||||
port => (u16, set_port, ok),
|
||||
workers => (u16, set_workers, ok),
|
||||
keep_alive => (u32, set_keep_alive, ok),
|
||||
read_timeout => (u32, set_read_timeout, ok),
|
||||
write_timeout => (u32, set_write_timeout, ok),
|
||||
log => (log_level, set_log_level, ok),
|
||||
secret_key => (str, set_secret_key, id),
|
||||
tls => (tls_config, set_raw_tls, id),
|
||||
@ -422,6 +436,60 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the read timeout to `timeout` seconds. If `timeout` is `0`, read
|
||||
/// timeouts are disabled.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::config::Config;
|
||||
///
|
||||
/// let mut config = Config::development();
|
||||
///
|
||||
/// // Set read timeout to 10 seconds.
|
||||
/// config.set_read_timeout(10);
|
||||
/// assert_eq!(config.read_timeout, Some(10));
|
||||
///
|
||||
/// // Disable read timeouts.
|
||||
/// config.set_read_timeout(0);
|
||||
/// assert_eq!(config.read_timeout, None);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn set_read_timeout(&mut self, timeout: u32) {
|
||||
if timeout == 0 {
|
||||
self.read_timeout = None;
|
||||
} else {
|
||||
self.read_timeout = Some(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the write timeout to `timeout` seconds. If `timeout` is `0`, write
|
||||
/// timeouts are disabled.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::config::Config;
|
||||
///
|
||||
/// let mut config = Config::development();
|
||||
///
|
||||
/// // Set write timeout to 10 seconds.
|
||||
/// config.set_write_timeout(10);
|
||||
/// assert_eq!(config.write_timeout, Some(10));
|
||||
///
|
||||
/// // Disable write timeouts.
|
||||
/// config.set_write_timeout(0);
|
||||
/// assert_eq!(config.write_timeout, None);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn set_write_timeout(&mut self, timeout: u32) {
|
||||
if timeout == 0 {
|
||||
self.write_timeout = None;
|
||||
} else {
|
||||
self.write_timeout = Some(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the `secret_key` in `self` to `key` which must be a 256-bit base64
|
||||
/// encoded string.
|
||||
///
|
||||
|
@ -32,10 +32,12 @@
|
||||
//! standard configuration parameters are:
|
||||
//!
|
||||
//! | name | type | description | examples |
|
||||
//! |------------|----------------|-------------------------------------------------------------|----------------------------|
|
||||
//! |------------ |----------------|-------------------------------------------------------------|----------------------------|
|
||||
//! | address | string | ip address or host to listen on | `"localhost"`, `"1.2.3.4"` |
|
||||
//! | port | integer | port number to listen on | `8000`, `80` |
|
||||
//! | keep_alive | integer | keep-alive timeout in seconds | `0` (disable), `10` |
|
||||
//! | read_timeout | integer | data read timeout in seconds | `0` (disable), `5` |
|
||||
//! | write_timeout | integer | data write timeout in seconds | `0` (disable), `5` |
|
||||
//! | workers | integer | number of concurrent thread workers | `36`, `512` |
|
||||
//! | log | string | max log level: `"off"`, `"normal"`, `"debug"`, `"critical"` | `"off"`, `"normal"` |
|
||||
//! | secret_key | 256-bit base64 | secret key for private cookies | `"8Xui8SI..."` (44 chars) |
|
||||
@ -64,6 +66,8 @@
|
||||
//! port = 8000
|
||||
//! workers = [number_of_cpus * 2]
|
||||
//! keep_alive = 5
|
||||
//! read_timeout = 5
|
||||
//! write_timeout = 5
|
||||
//! log = "normal"
|
||||
//! secret_key = [randomly generated at launch]
|
||||
//! limits = { forms = 32768 }
|
||||
@ -73,6 +77,8 @@
|
||||
//! port = 8000
|
||||
//! workers = [number_of_cpus * 2]
|
||||
//! keep_alive = 5
|
||||
//! read_timeout = 5
|
||||
//! write_timeout = 5
|
||||
//! log = "normal"
|
||||
//! secret_key = [randomly generated at launch]
|
||||
//! limits = { forms = 32768 }
|
||||
@ -82,6 +88,8 @@
|
||||
//! port = 8000
|
||||
//! workers = [number_of_cpus * 2]
|
||||
//! keep_alive = 5
|
||||
//! read_timeout = 5
|
||||
//! write_timeout = 5
|
||||
//! log = "critical"
|
||||
//! secret_key = [randomly generated at launch]
|
||||
//! limits = { forms = 32768 }
|
||||
@ -579,6 +587,8 @@ mod test {
|
||||
workers = 21
|
||||
log = "critical"
|
||||
keep_alive = 0
|
||||
read_timeout = 1
|
||||
write_timeout = 0
|
||||
secret_key = "8Xui8SN4mI+7egV/9dlfYYLGQJeEx4+DwmSQLwDVXJg="
|
||||
template_dir = "mine"
|
||||
json = true
|
||||
@ -591,6 +601,8 @@ mod test {
|
||||
.workers(21)
|
||||
.log_level(LoggingLevel::Critical)
|
||||
.keep_alive(0)
|
||||
.read_timeout(1)
|
||||
.write_timeout(0)
|
||||
.secret_key("8Xui8SN4mI+7egV/9dlfYYLGQJeEx4+DwmSQLwDVXJg=")
|
||||
.extra("template_dir", "mine")
|
||||
.extra("json", true)
|
||||
@ -866,7 +878,7 @@ mod test {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_good_keep_alives() {
|
||||
fn test_good_keep_alives_and_timeouts() {
|
||||
// Take the lock so changing the environment doesn't cause races.
|
||||
let _env_lock = ENV_LOCK.lock().unwrap();
|
||||
env::set_var(CONFIG_ENV, "stage");
|
||||
@ -898,10 +910,24 @@ mod test {
|
||||
"#.to_string(), TEST_CONFIG_FILENAME), {
|
||||
default_config(Staging).keep_alive(0)
|
||||
});
|
||||
|
||||
check_config!(RocketConfig::parse(r#"
|
||||
[stage]
|
||||
read_timeout = 10
|
||||
"#.to_string(), TEST_CONFIG_FILENAME), {
|
||||
default_config(Staging).read_timeout(10)
|
||||
});
|
||||
|
||||
check_config!(RocketConfig::parse(r#"
|
||||
[stage]
|
||||
write_timeout = 4
|
||||
"#.to_string(), TEST_CONFIG_FILENAME), {
|
||||
default_config(Staging).write_timeout(4)
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bad_keep_alives() {
|
||||
fn test_bad_keep_alives_and_timeouts() {
|
||||
// Take the lock so changing the environment doesn't cause races.
|
||||
let _env_lock = ENV_LOCK.lock().unwrap();
|
||||
env::remove_var(CONFIG_ENV);
|
||||
@ -925,6 +951,16 @@ mod test {
|
||||
[dev]
|
||||
keep_alive = 4294967296
|
||||
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
|
||||
|
||||
assert!(RocketConfig::parse(r#"
|
||||
[dev]
|
||||
read_timeout = true
|
||||
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
|
||||
|
||||
assert!(RocketConfig::parse(r#"
|
||||
[dev]
|
||||
write_timeout = None
|
||||
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -91,7 +91,10 @@ impl Data {
|
||||
}
|
||||
|
||||
// FIXME: This is absolutely terrible (downcasting!), thanks to Hyper.
|
||||
crate fn from_hyp(mut body: HyperBodyReader) -> Result<Data, &'static str> {
|
||||
crate fn from_hyp(
|
||||
req: &crate::Request<'_>,
|
||||
mut body: HyperBodyReader
|
||||
) -> Result<Data, &'static str> {
|
||||
#[inline(always)]
|
||||
#[cfg(feature = "tls")]
|
||||
fn concrete_stream(stream: &mut dyn NetworkStream) -> Option<NetStream> {
|
||||
@ -117,7 +120,8 @@ impl Data {
|
||||
};
|
||||
|
||||
// Set the read timeout to 5 seconds.
|
||||
let _ = net_stream.set_read_timeout(Some(Duration::from_secs(5)));
|
||||
let timeout = req.state.config.read_timeout.map(|s| Duration::from_secs(s as u64));
|
||||
let _ = net_stream.set_read_timeout(timeout);
|
||||
|
||||
// Steal the internal, undecoded data buffer from Hyper.
|
||||
let (mut hyper_buf, pos, cap) = body.get_mut().take_buf();
|
||||
|
@ -271,7 +271,6 @@ impl<'r, R: Responder<'r>> Responder<'r> for Option<R> {
|
||||
/// If `self` is `Ok`, responds with the wrapped `Responder`. Otherwise prints
|
||||
/// an error message with the `Err` value returns an `Err` of
|
||||
/// `Status::InternalServerError`.
|
||||
#[deprecated(since = "0.4.3")]
|
||||
impl<'r, R: Responder<'r>, E: fmt::Debug> Responder<'r> for Result<R, E> {
|
||||
default fn respond_to(self, req: &Request) -> response::Result<'r> {
|
||||
self.map(|r| r.respond_to(req)).unwrap_or_else(|e| {
|
||||
|
@ -69,7 +69,7 @@ impl hyper::Handler for Rocket {
|
||||
};
|
||||
|
||||
// Retrieve the data from the hyper body.
|
||||
let data = match Data::from_hyp(h_body) {
|
||||
let data = match Data::from_hyp(&req, h_body) {
|
||||
Ok(data) => data,
|
||||
Err(reason) => {
|
||||
error_!("Bad data in request: {}", reason);
|
||||
@ -414,11 +414,19 @@ impl Rocket {
|
||||
launch_info_!("secret key: {}", Paint::default(&config.secret_key).bold());
|
||||
launch_info_!("limits: {}", Paint::default(&config.limits).bold());
|
||||
|
||||
match config.keep_alive {
|
||||
Some(v) => launch_info_!("keep-alive: {}", Paint::default(format!("{}s", v)).bold()),
|
||||
None => launch_info_!("keep-alive: {}", Paint::default("disabled").bold()),
|
||||
fn log_timeout(name: &str, value: Option<u32>) {
|
||||
let painted = match value {
|
||||
Some(v) => Paint::default(format!("{}s", v)).bold(),
|
||||
None => Paint::default("disabled".into()).bold()
|
||||
};
|
||||
|
||||
launch_info_!("{}: {}", name, painted);
|
||||
}
|
||||
|
||||
log_timeout("keep-alive", config.keep_alive);
|
||||
log_timeout("read timeout", config.read_timeout);
|
||||
log_timeout("write timeout", config.write_timeout);
|
||||
|
||||
let tls_configured = config.tls.is_some();
|
||||
if tls_configured && cfg!(feature = "tls") {
|
||||
launch_info_!("tls: {}", Paint::default("enabled").bold());
|
||||
@ -717,8 +725,11 @@ impl Rocket {
|
||||
server.keep_alive(timeout);
|
||||
|
||||
// Set sane timeouts.
|
||||
server.set_read_timeout(Some(Duration::from_secs(10)));
|
||||
server.set_write_timeout(Some(Duration::from_secs(10)));
|
||||
let read_timeout = self.config.read_timeout.map(|s| Duration::from_secs(s as u64));
|
||||
server.set_read_timeout(read_timeout);
|
||||
|
||||
let write_timeout = self.config.write_timeout.map(|s| Duration::from_secs(s as u64));
|
||||
server.set_write_timeout(write_timeout);
|
||||
|
||||
// Freeze managed state for synchronization-free accesses later.
|
||||
self.state.freeze();
|
||||
|
@ -87,6 +87,8 @@ run`. You should see the following:
|
||||
=> secret key: generated
|
||||
=> limits: forms = 32KiB
|
||||
=> keep-alive: 5s
|
||||
=> read timeout: 5s
|
||||
=> write timeout: 5s
|
||||
=> tls: disabled
|
||||
🛰 Mounting '/':
|
||||
=> GET / (index)
|
||||
|
@ -194,6 +194,8 @@ Running the application, the console shows:
|
||||
=> secret key: generated
|
||||
=> limits: forms = 32KiB
|
||||
=> keep-alive: 5s
|
||||
=> read timeout: 5s
|
||||
=> write timeout: 5s
|
||||
=> tls: disabled
|
||||
🛰 Mounting '/hello':
|
||||
=> GET /hello/world (world)
|
||||
|
@ -39,6 +39,8 @@ $ sudo ROCKET_ENV=staging cargo run
|
||||
=> secret key: generated
|
||||
=> limits: forms = 32KiB
|
||||
=> keep-alive: 5s
|
||||
=> read timeout: 5s
|
||||
=> write timeout: 5s
|
||||
=> tls: disabled
|
||||
🛰 Mounting '/':
|
||||
=> GET / (hello)
|
||||
@ -66,6 +68,8 @@ address = "localhost"
|
||||
port = 8000
|
||||
workers = [number of cpus * 2]
|
||||
keep_alive = 5
|
||||
read_timeout = 5
|
||||
write_timeout = 5
|
||||
log = "normal"
|
||||
secret_key = [randomly generated at launch]
|
||||
limits = { forms = 32768 }
|
||||
@ -75,6 +79,8 @@ address = "0.0.0.0"
|
||||
port = 8000
|
||||
workers = [number of cpus * 2]
|
||||
keep_alive = 5
|
||||
read_timeout = 5
|
||||
write_timeout = 5
|
||||
log = "normal"
|
||||
secret_key = [randomly generated at launch]
|
||||
limits = { forms = 32768 }
|
||||
@ -84,6 +90,8 @@ address = "0.0.0.0"
|
||||
port = 8000
|
||||
workers = [number of cpus * 2]
|
||||
keep_alive = 5
|
||||
read_timeout = 5
|
||||
write_timeout = 5
|
||||
log = "critical"
|
||||
secret_key = [randomly generated at launch]
|
||||
limits = { forms = 32768 }
|
||||
|
Loading…
Reference in New Issue
Block a user