-
Notifications
You must be signed in to change notification settings - Fork 95
[3/n] rename request_body_max_bytes to default_request_body_max_bytes #1173
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,7 +32,7 @@ pub type RawTlsConfig = rustls::ServerConfig; | |
| /// r##" | ||
| /// [http_api_server] | ||
| /// bind_address = "127.0.0.1:12345" | ||
| /// request_body_max_bytes = 1024 | ||
| /// default_request_body_max_bytes = 1024 | ||
| /// ## ... (other app-specific config) | ||
| /// "## | ||
| /// ).map_err(|error| format!("parsing config: {}", error))?; | ||
|
|
@@ -43,12 +43,15 @@ pub type RawTlsConfig = rustls::ServerConfig; | |
| /// } | ||
| /// ``` | ||
| #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] | ||
| #[serde(default)] | ||
| #[serde( | ||
| from = "DeserializedConfigDropshot", | ||
| into = "DeserializedConfigDropshot" | ||
| )] | ||
| pub struct ConfigDropshot { | ||
| /// IP address and TCP port to which to bind for accepting connections | ||
| pub bind_address: SocketAddr, | ||
| /// maximum allowed size of a request body, defaults to 1024 | ||
| pub request_body_max_bytes: usize, | ||
| pub default_request_body_max_bytes: usize, | ||
| /// Default behavior for HTTP handler functions with respect to clients | ||
| /// disconnecting early. | ||
| pub default_handler_task_mode: HandlerTaskMode, | ||
|
|
@@ -113,9 +116,113 @@ impl Default for ConfigDropshot { | |
| fn default() -> Self { | ||
| ConfigDropshot { | ||
| bind_address: "127.0.0.1:0".parse().unwrap(), | ||
| request_body_max_bytes: 1024, | ||
| default_request_body_max_bytes: 1024, | ||
| default_handler_task_mode: HandlerTaskMode::Detached, | ||
| log_headers: Default::default(), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does this need to be Serialize?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is coupled with the |
||
| #[serde(default)] | ||
| struct DeserializedConfigDropshot { | ||
| bind_address: SocketAddr, | ||
| default_request_body_max_bytes: usize, | ||
| // Previous name for default_request_body_max_bytes, in Dropshot < 0.14. | ||
| // Present only to guide users to the new name. | ||
| #[serde( | ||
| deserialize_with = "deserialize_invalid_request_body_max_bytes", | ||
| skip_serializing | ||
| )] | ||
| request_body_max_bytes: Option<InvalidConfig>, | ||
| default_handler_task_mode: HandlerTaskMode, | ||
| log_headers: Vec<String>, | ||
| } | ||
|
|
||
| impl From<DeserializedConfigDropshot> for ConfigDropshot { | ||
| fn from(v: DeserializedConfigDropshot) -> Self { | ||
| ConfigDropshot { | ||
| bind_address: v.bind_address, | ||
| default_request_body_max_bytes: v.default_request_body_max_bytes, | ||
| default_handler_task_mode: v.default_handler_task_mode, | ||
| log_headers: v.log_headers, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl From<ConfigDropshot> for DeserializedConfigDropshot { | ||
| fn from(v: ConfigDropshot) -> Self { | ||
| DeserializedConfigDropshot { | ||
| bind_address: v.bind_address, | ||
| default_request_body_max_bytes: v.default_request_body_max_bytes, | ||
| request_body_max_bytes: None, | ||
| default_handler_task_mode: v.default_handler_task_mode, | ||
| log_headers: v.log_headers, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl Default for DeserializedConfigDropshot { | ||
| fn default() -> Self { | ||
| ConfigDropshot::default().into() | ||
| } | ||
| } | ||
|
|
||
| /// A marker type to indicate that the configuration is invalid. | ||
| /// | ||
| /// This type can never be constructed, which means that for any valid config, | ||
| /// `Option<InvalidConfig>` is always none. | ||
| #[derive(Clone, Debug, PartialEq)] | ||
| pub enum InvalidConfig {} | ||
|
|
||
| // We prefer having a deserialize function over `impl Deserialize for | ||
| // InvalidConfig` for two reasons: | ||
| // | ||
| // 1. This returns an `Option<InvalidConfig>`, not an `InvalidConfig`. | ||
| // 2. This way, the deserializer has a custom message associated with it. | ||
| fn deserialize_invalid_request_body_max_bytes<'de, D>( | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we prefer this to
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This pattern allows a custom error message to be passed in -- I'll add a comment to this note.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh also this returns an
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
that's true... but I think
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, |
||
| deserializer: D, | ||
| ) -> Result<Option<InvalidConfig>, D::Error> | ||
| where | ||
| D: serde::Deserializer<'de>, | ||
| { | ||
| deserialize_invalid( | ||
| deserializer, | ||
| "request_body_max_bytes has been renamed to \ | ||
| default_request_body_max_bytes", | ||
| ) | ||
| } | ||
|
|
||
| fn deserialize_invalid<'de, D>( | ||
| deserializer: D, | ||
| msg: &'static str, | ||
| ) -> Result<Option<InvalidConfig>, D::Error> | ||
| where | ||
| D: serde::Deserializer<'de>, | ||
| { | ||
| use serde::de::Error; | ||
|
|
||
| struct V { | ||
| msg: &'static str, | ||
| } | ||
|
|
||
| impl<'de> serde::de::Visitor<'de> for V { | ||
| type Value = Option<InvalidConfig>; | ||
|
|
||
| fn expecting( | ||
| &self, | ||
| formatter: &mut std::fmt::Formatter, | ||
| ) -> std::fmt::Result { | ||
| write!(formatter, "the field to be absent ({})", self.msg) | ||
| } | ||
|
|
||
| fn visit_some<D>(self, _: D) -> Result<Self::Value, D::Error> | ||
| where | ||
| D: serde::Deserializer<'de>, | ||
| { | ||
| Err(D::Error::custom(self.msg)) | ||
| } | ||
| } | ||
|
|
||
| deserializer.deserialize_any(V { msg }) | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's the point of the into?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is possible to derive
SerializeonConfigDropshotdirectly, and it would work today, but in case there's more divergence between the in-memory implementation and the serializable implementation over time, that may no longer hold true. I've seen this be a recurring source of bugs in other places, and making the types that directly interact with serde be the same for serialization and deserialization has always been helpful.