@@ -29,6 +29,11 @@ pub const DEFAULT_GET_HEADER_TIMEOUT_MILLIS: u64 = 1000;
2929/// Default user agent for HTTP requests.
3030pub const DEFAULT_USER_AGENT : & str = lighthouse_version:: VERSION ;
3131
32+ /// The value we set on the `ACCEPT` http header to indicate a preference for ssz response.
33+ pub const PREFERENCE_ACCEPT_VALUE : & str = "application/octet-stream;q=1.0,application/json;q=0.9" ;
34+ /// Only accept json responses.
35+ pub const JSON_ACCEPT_VALUE : & str = "application/json" ;
36+
3237#[ derive( Clone ) ]
3338pub struct Timeouts {
3439 get_header : Duration ,
@@ -57,14 +62,20 @@ pub struct BuilderHttpClient {
5762 server : SensitiveUrl ,
5863 timeouts : Timeouts ,
5964 user_agent : String ,
60- ssz_enabled : Arc < AtomicBool > ,
65+ /// Only use json for all requests/responses types.
66+ disable_ssz : bool ,
67+ /// Indicates that the `get_header` response had content-type ssz
68+ /// so we can set content-type header to ssz to make the `submit_blinded_blocks`
69+ /// request.
70+ ssz_available : Arc < AtomicBool > ,
6171}
6272
6373impl BuilderHttpClient {
6474 pub fn new (
6575 server : SensitiveUrl ,
6676 user_agent : Option < String > ,
6777 builder_header_timeout : Option < Duration > ,
78+ disable_ssz : bool ,
6879 ) -> Result < Self , Error > {
6980 let user_agent = user_agent. unwrap_or ( DEFAULT_USER_AGENT . to_string ( ) ) ;
7081 let client = reqwest:: Client :: builder ( ) . user_agent ( & user_agent) . build ( ) ?;
@@ -73,7 +84,8 @@ impl BuilderHttpClient {
7384 server,
7485 timeouts : Timeouts :: new ( builder_header_timeout) ,
7586 user_agent,
76- ssz_enabled : Arc :: new ( false . into ( ) ) ,
87+ disable_ssz,
88+ ssz_available : Arc :: new ( false . into ( ) ) ,
7789 } )
7890 }
7991
@@ -124,15 +136,15 @@ impl BuilderHttpClient {
124136
125137 let Ok ( Some ( fork_name) ) = self . fork_name_from_header ( & headers) else {
126138 // if no fork version specified, attempt to fallback to JSON
127- self . ssz_enabled . store ( false , Ordering :: SeqCst ) ;
139+ self . ssz_available . store ( false , Ordering :: SeqCst ) ;
128140 return serde_json:: from_slice ( & response_bytes) . map_err ( Error :: InvalidJson ) ;
129141 } ;
130142
131143 let content_type = self . content_type_from_header ( & headers) ;
132144
133145 match content_type {
134146 ContentType :: Ssz => {
135- self . ssz_enabled . store ( true , Ordering :: SeqCst ) ;
147+ self . ssz_available . store ( true , Ordering :: SeqCst ) ;
136148 T :: from_ssz_bytes_by_fork ( & response_bytes, fork_name)
137149 . map ( |data| ForkVersionedResponse {
138150 version : Some ( fork_name) ,
@@ -142,15 +154,17 @@ impl BuilderHttpClient {
142154 . map_err ( Error :: InvalidSsz )
143155 }
144156 ContentType :: Json => {
145- self . ssz_enabled . store ( false , Ordering :: SeqCst ) ;
157+ self . ssz_available . store ( false , Ordering :: SeqCst ) ;
146158 serde_json:: from_slice ( & response_bytes) . map_err ( Error :: InvalidJson )
147159 }
148160 }
149161 }
150162
151163 /// Return `true` if the most recently received response from the builder had SSZ Content-Type.
152- pub fn is_ssz_enabled ( & self ) -> bool {
153- self . ssz_enabled . load ( Ordering :: SeqCst )
164+ /// Return `false` otherwise.
165+ /// Also returns `false` if we have explicitly disabled ssz.
166+ pub fn is_ssz_available ( & self ) -> bool {
167+ !self . disable_ssz && self . ssz_available . load ( Ordering :: SeqCst )
154168 }
155169
156170 async fn get_with_timeout < T : DeserializeOwned , U : IntoUrl > (
@@ -213,19 +227,14 @@ impl BuilderHttpClient {
213227 & self ,
214228 url : U ,
215229 ssz_body : Vec < u8 > ,
216- mut headers : HeaderMap ,
230+ headers : HeaderMap ,
217231 timeout : Option < Duration > ,
218232 ) -> Result < Response , Error > {
219233 let mut builder = self . client . post ( url) ;
220234 if let Some ( timeout) = timeout {
221235 builder = builder. timeout ( timeout) ;
222236 }
223237
224- headers. insert (
225- CONTENT_TYPE_HEADER ,
226- HeaderValue :: from_static ( SSZ_CONTENT_TYPE_HEADER ) ,
227- ) ;
228-
229238 let response = builder
230239 . headers ( headers)
231240 . body ( ssz_body)
@@ -292,9 +301,21 @@ impl BuilderHttpClient {
292301 . push ( "blinded_blocks" ) ;
293302
294303 let mut headers = HeaderMap :: new ( ) ;
295- if let Ok ( value) = HeaderValue :: from_str ( & blinded_block. fork_name_unchecked ( ) . to_string ( ) ) {
296- headers. insert ( CONSENSUS_VERSION_HEADER , value) ;
297- }
304+ headers. insert (
305+ CONSENSUS_VERSION_HEADER ,
306+ HeaderValue :: from_str ( & blinded_block. fork_name_unchecked ( ) . to_string ( ) )
307+ . map_err ( |e| Error :: InvalidHeaders ( format ! ( "{}" , e) ) ) ?,
308+ ) ;
309+ headers. insert (
310+ CONTENT_TYPE_HEADER ,
311+ HeaderValue :: from_str ( SSZ_CONTENT_TYPE_HEADER )
312+ . map_err ( |e| Error :: InvalidHeaders ( format ! ( "{}" , e) ) ) ?,
313+ ) ;
314+ headers. insert (
315+ ACCEPT ,
316+ HeaderValue :: from_str ( PREFERENCE_ACCEPT_VALUE )
317+ . map_err ( |e| Error :: InvalidHeaders ( format ! ( "{}" , e) ) ) ?,
318+ ) ;
298319
299320 let result = self
300321 . post_ssz_with_raw_response (
@@ -326,9 +347,21 @@ impl BuilderHttpClient {
326347 . push ( "blinded_blocks" ) ;
327348
328349 let mut headers = HeaderMap :: new ( ) ;
329- if let Ok ( value) = HeaderValue :: from_str ( & blinded_block. fork_name_unchecked ( ) . to_string ( ) ) {
330- headers. insert ( CONSENSUS_VERSION_HEADER , value) ;
331- }
350+ headers. insert (
351+ CONSENSUS_VERSION_HEADER ,
352+ HeaderValue :: from_str ( & blinded_block. fork_name_unchecked ( ) . to_string ( ) )
353+ . map_err ( |e| Error :: InvalidHeaders ( format ! ( "{}" , e) ) ) ?,
354+ ) ;
355+ headers. insert (
356+ CONTENT_TYPE_HEADER ,
357+ HeaderValue :: from_str ( JSON_CONTENT_TYPE_HEADER )
358+ . map_err ( |e| Error :: InvalidHeaders ( format ! ( "{}" , e) ) ) ?,
359+ ) ;
360+ headers. insert (
361+ ACCEPT ,
362+ HeaderValue :: from_str ( JSON_ACCEPT_VALUE )
363+ . map_err ( |e| Error :: InvalidHeaders ( format ! ( "{}" , e) ) ) ?,
364+ ) ;
332365
333366 Ok ( self
334367 . post_with_raw_response (
@@ -362,12 +395,20 @@ impl BuilderHttpClient {
362395 . push ( pubkey. as_hex_string ( ) . as_str ( ) ) ;
363396
364397 let mut headers = HeaderMap :: new ( ) ;
365- if let Ok ( ssz_content_type_header) = HeaderValue :: from_str ( & format ! (
366- "{}; q=1.0,{}; q=0.9" ,
367- SSZ_CONTENT_TYPE_HEADER , JSON_CONTENT_TYPE_HEADER
368- ) ) {
369- headers. insert ( ACCEPT , ssz_content_type_header) ;
370- } ;
398+ if self . disable_ssz {
399+ headers. insert (
400+ ACCEPT ,
401+ HeaderValue :: from_str ( JSON_CONTENT_TYPE_HEADER )
402+ . map_err ( |e| Error :: InvalidHeaders ( format ! ( "{}" , e) ) ) ?,
403+ ) ;
404+ } else {
405+ // Indicate preference for ssz response in the accept header
406+ headers. insert (
407+ ACCEPT ,
408+ HeaderValue :: from_str ( PREFERENCE_ACCEPT_VALUE )
409+ . map_err ( |e| Error :: InvalidHeaders ( format ! ( "{}" , e) ) ) ?,
410+ ) ;
411+ }
371412
372413 let resp = self
373414 . get_with_header ( path, self . timeouts . get_header , headers)
@@ -395,3 +436,18 @@ impl BuilderHttpClient {
395436 . await
396437 }
397438}
439+
440+ #[ cfg( test) ]
441+ mod tests {
442+ use super :: * ;
443+
444+ #[ test]
445+ fn test_headers_no_panic ( ) {
446+ for fork in ForkName :: list_all ( ) {
447+ assert ! ( HeaderValue :: from_str( & fork. to_string( ) ) . is_ok( ) ) ;
448+ }
449+ assert ! ( HeaderValue :: from_str( PREFERENCE_ACCEPT_VALUE ) . is_ok( ) ) ;
450+ assert ! ( HeaderValue :: from_str( JSON_ACCEPT_VALUE ) . is_ok( ) ) ;
451+ assert ! ( HeaderValue :: from_str( JSON_CONTENT_TYPE_HEADER ) . is_ok( ) ) ;
452+ }
453+ }
0 commit comments