2
2
3
3
extern crate witnet_data_structures;
4
4
5
- use std:: str:: FromStr ;
6
-
7
- use futures:: { executor:: block_on, future:: join_all} ;
5
+ use futures:: { AsyncReadExt , executor:: block_on, future:: join_all} ;
8
6
use serde:: Serialize ;
9
7
pub use serde_cbor:: { to_vec as cbor_to_vec, Value as CborValue } ;
10
8
#[ cfg( test) ]
@@ -18,13 +16,7 @@ use witnet_data_structures::{
18
16
witnessing:: WitnessingConfig ,
19
17
} ;
20
18
pub use witnet_net:: Uri ;
21
- use witnet_net:: {
22
- client:: http:: WitnetHttpClient ,
23
- surf:: {
24
- http:: headers:: { HeaderName , HeaderValues , ToHeaderValues } ,
25
- RequestBuilder ,
26
- } ,
27
- } ;
19
+ use witnet_net:: client:: http:: WitnetHttpClient ;
28
20
29
21
use crate :: {
30
22
conditions:: { evaluate_tally_precondition_clause, TallyPreconditionClauseResult } ,
@@ -37,6 +29,9 @@ use crate::{
37
29
user_agents:: UserAgent ,
38
30
} ;
39
31
use core:: convert:: From ;
32
+ use witnet_net:: client:: http:: {
33
+ WitnetHttpBody , WitnetHttpRequest ,
34
+ } ;
40
35
41
36
pub mod conditions;
42
37
pub mod error;
@@ -250,38 +245,61 @@ async fn http_response(
250
245
message : err. to_string ( ) ,
251
246
} ) ?
252
247
}
253
- }
254
- . as_surf_client ( ) ;
248
+ } ;
255
249
256
- let request = match retrieve. kind {
257
- RADType :: HttpGet => client. get ( & retrieve. url ) ,
258
- RADType :: HttpPost => {
259
- // The call to `.body` sets the content type header to `application/octet-stream`
260
- client. post ( & retrieve. url ) . body ( retrieve. body . clone ( ) )
250
+ let request = WitnetHttpRequest :: build ( |builder| {
251
+ // Populate the builder and generate the body for different types of retrievals
252
+ let ( builder, body) = match retrieve. kind {
253
+ RADType :: HttpGet => (
254
+ builder. method ( "GET" ) . uri ( & retrieve. url ) ,
255
+ WitnetHttpBody :: empty ( ) ,
256
+ ) ,
257
+ RADType :: HttpPost => {
258
+ // Using `Vec<u8>` as the body sets the content type header to `application/octet-stream`
259
+ (
260
+ builder. method ( "POST" ) . uri ( & retrieve. url ) ,
261
+ WitnetHttpBody :: from ( retrieve. body . clone ( ) ) ,
262
+ )
263
+ }
264
+ _ => panic ! (
265
+ "Called http_response with invalid retrieval kind {:?}" ,
266
+ retrieve. kind
267
+ ) ,
268
+ } ;
269
+
270
+ // Add random user agent
271
+ let mut builder = builder. header ( "User-Agent" , UserAgent :: random ( ) ) ;
272
+
273
+ // Add extra_headers from retrieve.headers
274
+ for ( name, value) in & retrieve. headers {
275
+ builder = builder. header ( name, value) ;
261
276
}
262
- _ => panic ! (
263
- "Called http_response with invalid retrieval kind {:?}" ,
264
- retrieve. kind
265
- ) ,
266
- } ;
267
- let request = add_http_headers ( request, retrieve, context) ?;
268
- let mut response = request. await . map_err ( |x| RadError :: HttpOther {
269
- message : x. to_string ( ) ,
277
+
278
+ // Finally attach the body to complete building the HTTP request
279
+ builder
280
+ . body ( body)
281
+ . map_err ( |e| RadError :: HttpOther { message : e. to_string ( ) } )
270
282
} ) ?;
271
283
284
+ let response = client
285
+ . send ( request)
286
+ . await
287
+ . map_err ( |x| RadError :: HttpOther {
288
+ message : x. to_string ( ) ,
289
+ } ) ?
290
+ . inner ( ) ;
291
+
272
292
if !response. status ( ) . is_success ( ) {
273
293
return Err ( RadError :: HttpStatus {
274
294
status_code : response. status ( ) . into ( ) ,
275
295
} ) ;
276
296
}
277
297
278
- let response_string = response
279
- // TODO: replace with .body_bytes() and let RADON handle the encoding?
280
- . body_string ( )
281
- . await
282
- . map_err ( |x| RadError :: HttpOther {
283
- message : x. to_string ( ) ,
284
- } ) ?;
298
+ let ( _parts, mut body) = response. into_parts ( ) ;
299
+ let mut response_string= String :: default ( ) ;
300
+ body. read_to_string ( & mut response_string) . await . map_err ( |x| RadError :: HttpOther {
301
+ message : x. to_string ( ) ,
302
+ } ) ?;
285
303
286
304
let result = run_retrieval_with_data_report ( retrieve, & response_string, context, settings) ;
287
305
@@ -320,67 +338,6 @@ async fn rng_response(
320
338
Ok ( RadonReport :: from_result ( Ok ( random_bytes) , context) )
321
339
}
322
340
323
- /// Add HTTP headers from `retrieve.headers` to surf request.
324
- ///
325
- /// Some notes:
326
- ///
327
- /// * Overwriting the User-Agent header is allowed.
328
- /// * Multiple headers with the same key but different value are not supported, the current
329
- /// implementation will only use the last header.
330
- /// * All the non-standard headers will be converted to lowercase. Standard headers will use their
331
- /// standard capitalization, for example: `Content-Type`.
332
- /// * The HTTP client may reorder the headers: the order can change between consecutive invocations
333
- /// of the same request
334
- fn add_http_headers (
335
- mut request : RequestBuilder ,
336
- retrieve : & RADRetrieve ,
337
- _context : & mut ReportContext < RadonTypes > ,
338
- ) -> Result < RequestBuilder > {
339
- // Add random user agent
340
- request = request. header ( "User-Agent" , UserAgent :: random ( ) ) ;
341
-
342
- // Add extra_headers from retrieve.headers
343
- for ( name, value) in & retrieve. headers {
344
- // Additional validation because surf does not validate some cases such as:
345
- // * header name that contains `:`
346
- // * header value that contains `\n`
347
- let _name = http:: header:: HeaderName :: from_str ( name. as_str ( ) ) . map_err ( |e| {
348
- RadError :: InvalidHttpHeader {
349
- name : name. to_string ( ) ,
350
- value : value. to_string ( ) ,
351
- error : e. to_string ( ) ,
352
- }
353
- } ) ?;
354
- let _value = http:: header:: HeaderValue :: from_str ( value. as_str ( ) ) . map_err ( |e| {
355
- RadError :: InvalidHttpHeader {
356
- name : name. to_string ( ) ,
357
- value : value. to_string ( ) ,
358
- error : e. to_string ( ) ,
359
- }
360
- } ) ?;
361
-
362
- // Validate headers using surf to avoid panics
363
- let name: HeaderName =
364
- HeaderName :: from_str ( name) . map_err ( |e| RadError :: InvalidHttpHeader {
365
- name : name. to_string ( ) ,
366
- value : value. to_string ( ) ,
367
- error : e. to_string ( ) ,
368
- } ) ?;
369
- let values: HeaderValues = value
370
- . to_header_values ( )
371
- . map_err ( |e| RadError :: InvalidHttpHeader {
372
- name : name. to_string ( ) ,
373
- value : value. to_string ( ) ,
374
- error : e. to_string ( ) ,
375
- } ) ?
376
- . collect ( ) ;
377
-
378
- request = request. header ( name, & values) ;
379
- }
380
-
381
- Ok ( request)
382
- }
383
-
384
341
/// Run retrieval stage of a data request, return `Result<RadonReport>`.
385
342
pub async fn run_retrieval_report (
386
343
retrieve : & RADRetrieve ,
0 commit comments