@@ -19,10 +19,10 @@ use crate::default_client_common::impl_set_path_root;
1919use crate :: oauth2:: { Authorization , TokenCache } ;
2020use crate :: Error ;
2121use futures:: FutureExt ;
22- use std:: borrow:: Cow ;
23- use std:: fmt:: Write ;
2422use std:: str:: FromStr ;
2523use std:: sync:: Arc ;
24+ use ureq:: typestate:: WithBody ;
25+ use ureq:: Agent ;
2626
2727macro_rules! impl_update_token {
2828 ( $self: ident) => {
@@ -237,13 +237,18 @@ impl crate::async_client_trait::NoauthClient for TokenUpdateClient<'_> {}
237237
238238#[ derive( Debug ) ]
239239struct UreqClient {
240- agent : ureq :: Agent ,
240+ agent : Agent ,
241241}
242242
243243impl Default for UreqClient {
244244 fn default ( ) -> Self {
245245 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+ ) ,
247252 }
248253 }
249254}
@@ -253,24 +258,33 @@ impl HttpClient for UreqClient {
253258
254259 fn execute ( & self , request : Self :: Request , body : & [ u8 ] ) -> Result < HttpRequestResultRaw , Error > {
255260 let resp = if body. is_empty ( ) {
256- request. req . call ( )
261+ request. req . send_empty ( )
257262 } else {
258- request. req . send_bytes ( body)
263+ request. req . send ( body)
259264 } ;
260265
261266 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) => {
265272 return Err ( RequestError { inner : e } . into ( ) ) ;
266273 }
267274 } ;
268275
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 ( ) ) ?;
270282
271283 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 ( ) ) ?;
274288 u64:: from_str ( s) . map_err ( |e| {
275289 Error :: UnexpectedResponse ( format ! ( "invalid Content-Length {s:?}: {e}" ) )
276290 } )
@@ -281,7 +295,7 @@ impl HttpClient for UreqClient {
281295 status,
282296 result_header,
283297 content_length,
284- body : resp. into_reader ( ) ,
298+ body : Box :: new ( resp. into_body ( ) . into_reader ( ) ) ,
285299 } )
286300 }
287301
@@ -294,18 +308,12 @@ impl HttpClient for UreqClient {
294308
295309/// This is an implementation detail of the HTTP client.
296310pub struct UreqRequest {
297- req : ureq:: Request ,
311+ req : ureq:: RequestBuilder < WithBody > ,
298312}
299313
300314impl HttpRequest for UreqRequest {
301315 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) ;
309317 self
310318 }
311319}
@@ -316,7 +324,7 @@ impl HttpRequest for UreqRequest {
316324pub enum DefaultClientError {
317325 /// The HTTP client encountered invalid UTF-8 data.
318326 #[ error( "invalid UTF-8 string" ) ]
319- Utf8 ( #[ from] std:: string :: FromUtf8Error ) ,
327+ Utf8 ( #[ from] std:: str :: Utf8Error ) ,
320328
321329 /// The HTTP client encountered some I/O error.
322330 #[ error( "I/O error: {0}" ) ]
@@ -339,7 +347,7 @@ macro_rules! wrap_error {
339347}
340348
341349wrap_error ! ( std:: io:: Error ) ;
342- wrap_error ! ( std:: string :: FromUtf8Error ) ;
350+ wrap_error ! ( std:: str :: Utf8Error ) ;
343351wrap_error ! ( RequestError ) ;
344352
345353/// 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 {
367375 Some ( & self . inner )
368376 }
369377}
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