mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-03 00:31:50 +00:00
Support duplicate keys in HTTP API query strings (#2908)
## Issues Addressed Closes #2739 Closes #2812 ## Proposed Changes Support the deserialization of query strings containing duplicate keys into their corresponding types. As `warp` does not support this feature natively (as discussed in #2739), it relies on the external library [`serde_array_query`](https://github.com/sigp/serde_array_query) (written by @michaelsproul) This is backwards compatible meaning that both of the following requests will produce the same output: ``` curl "http://localhost:5052/eth/v1/events?topics=head,block" ``` ``` curl "http://localhost:5052/eth/v1/events?topics=head&topics=block" ``` ## Additional Info Certain error messages have changed slightly. This only affects endpoints which accept multiple values. For example: ``` {"code":400,"message":"BAD_REQUEST: invalid query: Invalid query string","stacktraces":[]} ``` is now ``` {"code":400,"message":"BAD_REQUEST: unable to parse query","stacktraces":[]} ``` The serve order of the endpoints `get_beacon_state_validators` and `get_beacon_state_validators_id` have flipped: ```rust .or(get_beacon_state_validators_id.boxed()) .or(get_beacon_state_validators.boxed()) ``` This is to ensure proper error messages when filter fallback occurs due to the use of the `and_then` filter. ## Future Work - Cleanup / remove filter fallback behaviour by substituting `and_then` with `then` where appropriate. - Add regression tests for HTTP API error messages. ## Credits - @mooori for doing the ground work of investigating possible solutions within the existing Rust ecosystem. - @michaelsproul for writing [`serde_array_query`](https://github.com/sigp/serde_array_query) and for helping debug the behaviour of the `warp` filter fallback leading to incorrect error messages.
This commit is contained in:
@@ -18,3 +18,4 @@ tokio = { version = "1.14.0", features = ["sync"] }
|
||||
headers = "0.3.2"
|
||||
lighthouse_metrics = { path = "../lighthouse_metrics" }
|
||||
lazy_static = "1.4.0"
|
||||
serde_array_query = "0.1.0"
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
|
||||
pub mod cors;
|
||||
pub mod metrics;
|
||||
pub mod query;
|
||||
pub mod reject;
|
||||
pub mod task;
|
||||
|
||||
22
common/warp_utils/src/query.rs
Normal file
22
common/warp_utils/src/query.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
use crate::reject::custom_bad_request;
|
||||
use serde::Deserialize;
|
||||
use warp::Filter;
|
||||
|
||||
// Custom query filter using `serde_array_query`.
|
||||
// This allows duplicate keys inside query strings.
|
||||
pub fn multi_key_query<'de, T: Deserialize<'de>>(
|
||||
) -> impl warp::Filter<Extract = (Result<T, warp::Rejection>,), Error = std::convert::Infallible> + Copy
|
||||
{
|
||||
raw_query().then(|query_str: String| async move {
|
||||
serde_array_query::from_str(&query_str).map_err(|e| custom_bad_request(e.to_string()))
|
||||
})
|
||||
}
|
||||
|
||||
// This ensures that empty query strings are still accepted.
|
||||
// This is because warp::filters::query::raw() does not allow empty query strings
|
||||
// but warp::query::<T>() does.
|
||||
fn raw_query() -> impl Filter<Extract = (String,), Error = std::convert::Infallible> + Copy {
|
||||
warp::filters::query::raw()
|
||||
.or(warp::any().map(String::default))
|
||||
.unify()
|
||||
}
|
||||
Reference in New Issue
Block a user