Skip to content

Commit 0c6e373

Browse files
eserilevdanielrachi1
authored andcommitted
Assume Content-Type is json for endpoints that require json (sigp#4575)
* added default content type filter * Merge branch 'unstable' of https://github.com/sigp/lighthouse into unstable * create custom warp json filter that ignores content type header * cargo fmt and linting * updated test * updated test * merge unstable * merge conflicts * workspace=true * use Bytes instead of Buf * resolve merge conflict * resolve merge conflicts * add extra error message context * merge conflicts * lint
1 parent c5bcb8a commit 0c6e373

File tree

7 files changed

+88
-28
lines changed

7 files changed

+88
-28
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

beacon_node/http_api/src/lib.rs

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -682,7 +682,7 @@ pub fn serve<T: BeaconChainTypes>(
682682
.clone()
683683
.and(warp::path("validator_balances"))
684684
.and(warp::path::end())
685-
.and(warp::body::json())
685+
.and(warp_utils::json::json())
686686
.then(
687687
|state_id: StateId,
688688
task_spawner: TaskSpawner<T::EthSpec>,
@@ -726,7 +726,7 @@ pub fn serve<T: BeaconChainTypes>(
726726
.clone()
727727
.and(warp::path("validators"))
728728
.and(warp::path::end())
729-
.and(warp::body::json())
729+
.and(warp_utils::json::json())
730730
.then(
731731
|state_id: StateId,
732732
task_spawner: TaskSpawner<T::EthSpec>,
@@ -1257,7 +1257,7 @@ pub fn serve<T: BeaconChainTypes>(
12571257
.and(warp::path("beacon"))
12581258
.and(warp::path("blocks"))
12591259
.and(warp::path::end())
1260-
.and(warp::body::json())
1260+
.and(warp_utils::json::json())
12611261
.and(task_spawner_filter.clone())
12621262
.and(chain_filter.clone())
12631263
.and(network_tx_filter.clone())
@@ -1327,7 +1327,7 @@ pub fn serve<T: BeaconChainTypes>(
13271327
.and(warp::path("blocks"))
13281328
.and(warp::query::<api_types::BroadcastValidationQuery>())
13291329
.and(warp::path::end())
1330-
.and(warp::body::json())
1330+
.and(warp_utils::json::json())
13311331
.and(task_spawner_filter.clone())
13321332
.and(chain_filter.clone())
13331333
.and(network_tx_filter.clone())
@@ -1404,7 +1404,7 @@ pub fn serve<T: BeaconChainTypes>(
14041404
.and(warp::path("beacon"))
14051405
.and(warp::path("blinded_blocks"))
14061406
.and(warp::path::end())
1407-
.and(warp::body::json())
1407+
.and(warp_utils::json::json())
14081408
.and(task_spawner_filter.clone())
14091409
.and(chain_filter.clone())
14101410
.and(network_tx_filter.clone())
@@ -1472,7 +1472,7 @@ pub fn serve<T: BeaconChainTypes>(
14721472
.and(warp::path("blinded_blocks"))
14731473
.and(warp::query::<api_types::BroadcastValidationQuery>())
14741474
.and(warp::path::end())
1475-
.and(warp::body::json())
1475+
.and(warp_utils::json::json())
14761476
.and(task_spawner_filter.clone())
14771477
.and(chain_filter.clone())
14781478
.and(network_tx_filter.clone())
@@ -1754,7 +1754,7 @@ pub fn serve<T: BeaconChainTypes>(
17541754
.clone()
17551755
.and(warp::path("attestations"))
17561756
.and(warp::path::end())
1757-
.and(warp::body::json())
1757+
.and(warp_utils::json::json())
17581758
.and(network_tx_filter.clone())
17591759
.and(log_filter.clone())
17601760
.then(
@@ -1930,7 +1930,7 @@ pub fn serve<T: BeaconChainTypes>(
19301930
.clone()
19311931
.and(warp::path("attester_slashings"))
19321932
.and(warp::path::end())
1933-
.and(warp::body::json())
1933+
.and(warp_utils::json::json())
19341934
.and(network_tx_filter.clone())
19351935
.then(
19361936
|task_spawner: TaskSpawner<T::EthSpec>,
@@ -1988,7 +1988,7 @@ pub fn serve<T: BeaconChainTypes>(
19881988
.clone()
19891989
.and(warp::path("proposer_slashings"))
19901990
.and(warp::path::end())
1991-
.and(warp::body::json())
1991+
.and(warp_utils::json::json())
19921992
.and(network_tx_filter.clone())
19931993
.then(
19941994
|task_spawner: TaskSpawner<T::EthSpec>,
@@ -2046,7 +2046,7 @@ pub fn serve<T: BeaconChainTypes>(
20462046
.clone()
20472047
.and(warp::path("voluntary_exits"))
20482048
.and(warp::path::end())
2049-
.and(warp::body::json())
2049+
.and(warp_utils::json::json())
20502050
.and(network_tx_filter.clone())
20512051
.then(
20522052
|task_spawner: TaskSpawner<T::EthSpec>,
@@ -2102,7 +2102,7 @@ pub fn serve<T: BeaconChainTypes>(
21022102
.clone()
21032103
.and(warp::path("sync_committees"))
21042104
.and(warp::path::end())
2105-
.and(warp::body::json())
2105+
.and(warp_utils::json::json())
21062106
.and(network_tx_filter.clone())
21072107
.and(log_filter.clone())
21082108
.then(
@@ -2139,7 +2139,7 @@ pub fn serve<T: BeaconChainTypes>(
21392139
.clone()
21402140
.and(warp::path("bls_to_execution_changes"))
21412141
.and(warp::path::end())
2142-
.and(warp::body::json())
2142+
.and(warp_utils::json::json())
21432143
.and(network_tx_filter.clone())
21442144
.and(log_filter.clone())
21452145
.then(
@@ -2533,7 +2533,7 @@ pub fn serve<T: BeaconChainTypes>(
25332533
.and(warp::path("attestations"))
25342534
.and(warp::path::param::<Epoch>())
25352535
.and(warp::path::end())
2536-
.and(warp::body::json())
2536+
.and(warp_utils::json::json())
25372537
.then(
25382538
|task_spawner: TaskSpawner<T::EthSpec>,
25392539
chain: Arc<BeaconChain<T>>,
@@ -2583,7 +2583,7 @@ pub fn serve<T: BeaconChainTypes>(
25832583
.and(warp::path("sync_committee"))
25842584
.and(block_id_or_err)
25852585
.and(warp::path::end())
2586-
.and(warp::body::json())
2586+
.and(warp_utils::json::json())
25872587
.and(log_filter.clone())
25882588
.then(
25892589
|task_spawner: TaskSpawner<T::EthSpec>,
@@ -3326,7 +3326,7 @@ pub fn serve<T: BeaconChainTypes>(
33263326
}))
33273327
.and(warp::path::end())
33283328
.and(not_while_syncing_filter.clone())
3329-
.and(warp::body::json())
3329+
.and(warp_utils::json::json())
33303330
.and(task_spawner_filter.clone())
33313331
.and(chain_filter.clone())
33323332
.then(
@@ -3352,7 +3352,7 @@ pub fn serve<T: BeaconChainTypes>(
33523352
}))
33533353
.and(warp::path::end())
33543354
.and(not_while_syncing_filter.clone())
3355-
.and(warp::body::json())
3355+
.and(warp_utils::json::json())
33563356
.and(task_spawner_filter.clone())
33573357
.and(chain_filter.clone())
33583358
.then(
@@ -3406,7 +3406,7 @@ pub fn serve<T: BeaconChainTypes>(
34063406
.and(not_while_syncing_filter.clone())
34073407
.and(task_spawner_filter.clone())
34083408
.and(chain_filter.clone())
3409-
.and(warp::body::json())
3409+
.and(warp_utils::json::json())
34103410
.and(network_tx_filter.clone())
34113411
.and(log_filter.clone())
34123412
.then(
@@ -3519,7 +3519,7 @@ pub fn serve<T: BeaconChainTypes>(
35193519
.and(not_while_syncing_filter.clone())
35203520
.and(task_spawner_filter.clone())
35213521
.and(chain_filter.clone())
3522-
.and(warp::body::json())
3522+
.and(warp_utils::json::json())
35233523
.and(network_tx_filter)
35243524
.and(log_filter.clone())
35253525
.then(
@@ -3545,7 +3545,7 @@ pub fn serve<T: BeaconChainTypes>(
35453545
.and(warp::path("validator"))
35463546
.and(warp::path("beacon_committee_subscriptions"))
35473547
.and(warp::path::end())
3548-
.and(warp::body::json())
3548+
.and(warp_utils::json::json())
35493549
.and(validator_subscription_tx_filter.clone())
35503550
.and(task_spawner_filter.clone())
35513551
.and(chain_filter.clone())
@@ -3601,7 +3601,7 @@ pub fn serve<T: BeaconChainTypes>(
36013601
.and(task_spawner_filter.clone())
36023602
.and(chain_filter.clone())
36033603
.and(log_filter.clone())
3604-
.and(warp::body::json())
3604+
.and(warp_utils::json::json())
36053605
.then(
36063606
|task_spawner: TaskSpawner<T::EthSpec>,
36073607
chain: Arc<BeaconChain<T>>,
@@ -3652,7 +3652,7 @@ pub fn serve<T: BeaconChainTypes>(
36523652
.and(task_spawner_filter.clone())
36533653
.and(chain_filter.clone())
36543654
.and(log_filter.clone())
3655-
.and(warp::body::json())
3655+
.and(warp_utils::json::json())
36563656
.then(
36573657
|task_spawner: TaskSpawner<T::EthSpec>,
36583658
chain: Arc<BeaconChain<T>>,
@@ -3826,7 +3826,7 @@ pub fn serve<T: BeaconChainTypes>(
38263826
.and(warp::path("validator"))
38273827
.and(warp::path("sync_committee_subscriptions"))
38283828
.and(warp::path::end())
3829-
.and(warp::body::json())
3829+
.and(warp_utils::json::json())
38303830
.and(validator_subscription_tx_filter)
38313831
.and(task_spawner_filter.clone())
38323832
.and(chain_filter.clone())
@@ -3872,7 +3872,7 @@ pub fn serve<T: BeaconChainTypes>(
38723872
.and(warp::path("liveness"))
38733873
.and(warp::path::param::<Epoch>())
38743874
.and(warp::path::end())
3875-
.and(warp::body::json())
3875+
.and(warp_utils::json::json())
38763876
.and(task_spawner_filter.clone())
38773877
.and(chain_filter.clone())
38783878
.then(
@@ -3913,7 +3913,7 @@ pub fn serve<T: BeaconChainTypes>(
39133913
let post_lighthouse_liveness = warp::path("lighthouse")
39143914
.and(warp::path("liveness"))
39153915
.and(warp::path::end())
3916-
.and(warp::body::json())
3916+
.and(warp_utils::json::json())
39173917
.and(task_spawner_filter.clone())
39183918
.and(chain_filter.clone())
39193919
.then(
@@ -4016,7 +4016,7 @@ pub fn serve<T: BeaconChainTypes>(
40164016
.and(warp::path("ui"))
40174017
.and(warp::path("validator_metrics"))
40184018
.and(warp::path::end())
4019-
.and(warp::body::json())
4019+
.and(warp_utils::json::json())
40204020
.and(task_spawner_filter.clone())
40214021
.and(chain_filter.clone())
40224022
.then(
@@ -4035,7 +4035,7 @@ pub fn serve<T: BeaconChainTypes>(
40354035
.and(warp::path("ui"))
40364036
.and(warp::path("validator_info"))
40374037
.and(warp::path::end())
4038-
.and(warp::body::json())
4038+
.and(warp_utils::json::json())
40394039
.and(task_spawner_filter.clone())
40404040
.and(chain_filter.clone())
40414041
.then(
@@ -4338,7 +4338,7 @@ pub fn serve<T: BeaconChainTypes>(
43384338
let post_lighthouse_block_rewards = warp::path("lighthouse")
43394339
.and(warp::path("analysis"))
43404340
.and(warp::path("block_rewards"))
4341-
.and(warp::body::json())
4341+
.and(warp_utils::json::json())
43424342
.and(warp::path::end())
43434343
.and(task_spawner_filter.clone())
43444344
.and(chain_filter.clone())

common/eth2/src/lib.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,10 +373,30 @@ impl BeaconNodeHttpClient {
373373
if let Some(timeout) = timeout {
374374
builder = builder.timeout(timeout);
375375
}
376+
376377
let response = builder.json(body).send().await?;
377378
ok_or_error(response).await
378379
}
379380

381+
/// Generic POST function supporting arbitrary responses and timeouts.
382+
/// Does not include Content-Type application/json in the request header.
383+
async fn post_generic_json_without_content_type_header<T: Serialize, U: IntoUrl>(
384+
&self,
385+
url: U,
386+
body: &T,
387+
timeout: Option<Duration>,
388+
) -> Result<Response, Error> {
389+
let mut builder = self.client.post(url);
390+
if let Some(timeout) = timeout {
391+
builder = builder.timeout(timeout);
392+
}
393+
394+
let serialized_body = serde_json::to_vec(body).map_err(Error::InvalidJson)?;
395+
396+
let response = builder.body(serialized_body).send().await?;
397+
ok_or_error(response).await
398+
}
399+
380400
/// Generic POST function supporting arbitrary responses and timeouts.
381401
async fn post_generic_with_consensus_version<T: Serialize, U: IntoUrl>(
382402
&self,
@@ -1250,7 +1270,8 @@ impl BeaconNodeHttpClient {
12501270
.push("pool")
12511271
.push("attester_slashings");
12521272

1253-
self.post(path, slashing).await?;
1273+
self.post_generic_json_without_content_type_header(path, slashing, None)
1274+
.await?;
12541275

12551276
Ok(())
12561277
}

common/warp_utils/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ beacon_chain = { workspace = true }
1414
state_processing = { workspace = true }
1515
safe_arith = { workspace = true }
1616
serde = { workspace = true }
17+
serde_json = { workspace = true }
1718
tokio = { workspace = true }
1819
headers = "0.3.2"
1920
lighthouse_metrics = { workspace = true }
2021
lazy_static = { workspace = true }
2122
serde_array_query = "0.1.0"
23+
bytes = { workspace = true }

common/warp_utils/src/json.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use bytes::Bytes;
2+
use serde::de::DeserializeOwned;
3+
use std::error::Error as StdError;
4+
use warp::{Filter, Rejection};
5+
6+
use crate::reject;
7+
8+
struct Json;
9+
10+
type BoxError = Box<dyn StdError + Send + Sync>;
11+
12+
impl Json {
13+
fn decode<T: DeserializeOwned>(bytes: Bytes) -> Result<T, BoxError> {
14+
serde_json::from_slice(&bytes).map_err(Into::into)
15+
}
16+
}
17+
18+
pub fn json<T: DeserializeOwned + Send>() -> impl Filter<Extract = (T,), Error = Rejection> + Copy {
19+
warp::body::bytes().and_then(|bytes: Bytes| async move {
20+
Json::decode(bytes).map_err(|err| reject::custom_deserialize_error(format!("{:?}", err)))
21+
})
22+
}

common/warp_utils/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//! Lighthouse project. E.g., the `http_api` and `http_metrics` crates.
33
44
pub mod cors;
5+
pub mod json;
56
pub mod metrics;
67
pub mod query;
78
pub mod reject;

common/warp_utils/src/reject.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,15 @@ pub fn custom_bad_request(msg: String) -> warp::reject::Rejection {
8282
warp::reject::custom(CustomBadRequest(msg))
8383
}
8484

85+
#[derive(Debug)]
86+
pub struct CustomDeserializeError(pub String);
87+
88+
impl Reject for CustomDeserializeError {}
89+
90+
pub fn custom_deserialize_error(msg: String) -> warp::reject::Rejection {
91+
warp::reject::custom(CustomDeserializeError(msg))
92+
}
93+
8594
#[derive(Debug)]
8695
pub struct CustomServerError(pub String);
8796

@@ -161,6 +170,9 @@ pub async fn handle_rejection(err: warp::Rejection) -> Result<impl warp::Reply,
161170
if err.is_not_found() {
162171
code = StatusCode::NOT_FOUND;
163172
message = "NOT_FOUND".to_string();
173+
} else if let Some(e) = err.find::<crate::reject::CustomDeserializeError>() {
174+
message = format!("BAD_REQUEST: body deserialize error: {}", e.0);
175+
code = StatusCode::BAD_REQUEST;
164176
} else if let Some(e) = err.find::<warp::filters::body::BodyDeserializeError>() {
165177
message = format!("BAD_REQUEST: body deserialize error: {}", e);
166178
code = StatusCode::BAD_REQUEST;

0 commit comments

Comments
 (0)