@@ -19,10 +19,10 @@ use crate::default_client_common::impl_set_path_root;
19
19
use crate :: oauth2:: { Authorization , TokenCache } ;
20
20
use crate :: Error ;
21
21
use futures:: FutureExt ;
22
- use std:: borrow:: Cow ;
23
- use std:: fmt:: Write ;
24
22
use std:: str:: FromStr ;
25
23
use std:: sync:: Arc ;
24
+ use ureq:: typestate:: WithBody ;
25
+ use ureq:: Agent ;
26
26
27
27
macro_rules! impl_update_token {
28
28
( $self: ident) => {
@@ -237,13 +237,18 @@ impl crate::async_client_trait::NoauthClient for TokenUpdateClient<'_> {}
237
237
238
238
#[ derive( Debug ) ]
239
239
struct UreqClient {
240
- agent : ureq :: Agent ,
240
+ agent : Agent ,
241
241
}
242
242
243
243
impl Default for UreqClient {
244
244
fn default ( ) -> Self {
245
245
Self {
246
- agent : ureq:: Agent :: new ( ) ,
246
+ agent : Agent :: new_with_config (
247
+ Agent :: config_builder ( )
248
+ . https_only ( true )
249
+ . http_status_as_error ( false )
250
+ . build ( ) ,
251
+ ) ,
247
252
}
248
253
}
249
254
}
@@ -253,24 +258,33 @@ impl HttpClient for UreqClient {
253
258
254
259
fn execute ( & self , request : Self :: Request , body : & [ u8 ] ) -> Result < HttpRequestResultRaw , Error > {
255
260
let resp = if body. is_empty ( ) {
256
- request. req . call ( )
261
+ request. req . send_empty ( )
257
262
} else {
258
- request. req . send_bytes ( body)
263
+ request. req . send ( body)
259
264
} ;
260
265
261
266
let ( status, resp) = match resp {
262
- Ok ( resp) => ( resp. status ( ) , resp) ,
263
- Err ( ureq:: Error :: Status ( status, resp) ) => ( status, resp) ,
264
- Err ( e @ ureq:: Error :: Transport ( _) ) => {
267
+ Ok ( resp) => ( resp. status ( ) . as_u16 ( ) , resp) ,
268
+ Err ( ureq:: Error :: Io ( e) ) => {
269
+ return Err ( e. into ( ) ) ;
270
+ }
271
+ Err ( e) => {
265
272
return Err ( RequestError { inner : e } . into ( ) ) ;
266
273
}
267
274
} ;
268
275
269
- let result_header = resp. header ( "Dropbox-API-Result" ) . map ( String :: from) ;
276
+ let result_header = resp
277
+ . headers ( )
278
+ . get ( "Dropbox-API-Result" )
279
+ . map ( |v| String :: from_utf8 ( v. as_bytes ( ) . to_vec ( ) ) )
280
+ . transpose ( )
281
+ . map_err ( |e| e. utf8_error ( ) ) ?;
270
282
271
283
let content_length = resp
272
- . header ( "Content-Length" )
273
- . map ( |s| {
284
+ . headers ( )
285
+ . get ( "Content-Length" )
286
+ . map ( |v| {
287
+ let s = std:: str:: from_utf8 ( v. as_bytes ( ) ) ?;
274
288
u64:: from_str ( s) . map_err ( |e| {
275
289
Error :: UnexpectedResponse ( format ! ( "invalid Content-Length {s:?}: {e}" ) )
276
290
} )
@@ -281,7 +295,7 @@ impl HttpClient for UreqClient {
281
295
status,
282
296
result_header,
283
297
content_length,
284
- body : resp. into_reader ( ) ,
298
+ body : Box :: new ( resp. into_body ( ) . into_reader ( ) ) ,
285
299
} )
286
300
}
287
301
@@ -294,18 +308,12 @@ impl HttpClient for UreqClient {
294
308
295
309
/// This is an implementation detail of the HTTP client.
296
310
pub struct UreqRequest {
297
- req : ureq:: Request ,
311
+ req : ureq:: RequestBuilder < WithBody > ,
298
312
}
299
313
300
314
impl HttpRequest for UreqRequest {
301
315
fn set_header ( mut self , name : & str , value : & str ) -> Self {
302
- if name. eq_ignore_ascii_case ( "dropbox-api-arg" ) {
303
- // Non-ASCII and 0x7F in a header need to be escaped per the HTTP spec, and ureq doesn't
304
- // do this for us. This is only an issue for this particular header.
305
- self . req = self . req . set ( name, json_escape_header ( value) . as_ref ( ) ) ;
306
- } else {
307
- self . req = self . req . set ( name, value) ;
308
- }
316
+ self . req = self . req . header ( name, value) ;
309
317
self
310
318
}
311
319
}
@@ -316,7 +324,7 @@ impl HttpRequest for UreqRequest {
316
324
pub enum DefaultClientError {
317
325
/// The HTTP client encountered invalid UTF-8 data.
318
326
#[ error( "invalid UTF-8 string" ) ]
319
- Utf8 ( #[ from] std:: string :: FromUtf8Error ) ,
327
+ Utf8 ( #[ from] std:: str :: Utf8Error ) ,
320
328
321
329
/// The HTTP client encountered some I/O error.
322
330
#[ error( "I/O error: {0}" ) ]
@@ -339,7 +347,7 @@ macro_rules! wrap_error {
339
347
}
340
348
341
349
wrap_error ! ( std:: io:: Error ) ;
342
- wrap_error ! ( std:: string :: FromUtf8Error ) ;
350
+ wrap_error ! ( std:: str :: Utf8Error ) ;
343
351
wrap_error ! ( RequestError ) ;
344
352
345
353
/// Something went wrong making the request, or the server returned a response we didn't expect.
@@ -367,53 +375,3 @@ impl std::error::Error for RequestError {
367
375
Some ( & self . inner )
368
376
}
369
377
}
370
-
371
- /// Replaces any non-ASCII characters (and 0x7f) with JSON-style '\uXXXX' sequence. Otherwise,
372
- /// returns it unmodified without any additional allocation or copying.
373
- fn json_escape_header ( s : & str ) -> Cow < ' _ , str > {
374
- // Unfortunately, the HTTP spec requires escaping ASCII DEL (0x7F), so we can't use the quicker
375
- // bit pattern check done in str::is_ascii() to skip this for the common case of all ASCII. :(
376
-
377
- let mut out = Cow :: Borrowed ( s) ;
378
- for ( i, c) in s. char_indices ( ) {
379
- if !c. is_ascii ( ) || c == '\x7f' {
380
- let mstr = match out {
381
- Cow :: Borrowed ( _) => {
382
- // If we're still borrowed, we must have had ascii up until this point.
383
- // Clone the string up until here, and from now on we'll be pushing chars to it.
384
- out = Cow :: Owned ( s[ 0 ..i] . to_owned ( ) ) ;
385
- out. to_mut ( )
386
- }
387
- Cow :: Owned ( ref mut m) => m,
388
- } ;
389
- write ! ( mstr, "\\ u{:04x}" , c as u32 ) . unwrap ( ) ;
390
- } else if let Cow :: Owned ( ref mut o) = out {
391
- o. push ( c) ;
392
- }
393
- }
394
- out
395
- }
396
-
397
- #[ cfg( test) ]
398
- mod test {
399
- use super :: * ;
400
-
401
- #[ test]
402
- fn test_json_escape ( ) {
403
- assert_eq ! ( Cow :: Borrowed ( "foobar" ) , json_escape_header( "foobar" ) ) ;
404
- assert_eq ! (
405
- Cow :: <' _, str >:: Owned ( "tro\\ u0161kovi" . to_owned( ) ) ,
406
- json_escape_header( "troškovi" )
407
- ) ;
408
- assert_eq ! (
409
- Cow :: <' _, str >:: Owned (
410
- r#"{"field": "some_\u00fc\u00f1\u00eec\u00f8d\u00e9_and_\u007f"}"# . to_owned( )
411
- ) ,
412
- json_escape_header( "{\" field\" : \" some_üñîcødé_and_\x7f \" }" )
413
- ) ;
414
- assert_eq ! (
415
- Cow :: <' _, str >:: Owned ( "almost,\\ u007f but not quite" . to_owned( ) ) ,
416
- json_escape_header( "almost,\x7f but not quite" )
417
- ) ;
418
- }
419
- }
0 commit comments