@@ -32,7 +32,6 @@ use super::message::BooleanResp;
32
32
use super :: message:: FileStatusType ;
33
33
use super :: message:: FileStatusWrapper ;
34
34
use super :: message:: FileStatusesWrapper ;
35
- use super :: message:: Redirection ;
36
35
use crate :: ops:: * ;
37
36
use crate :: raw:: * ;
38
37
use crate :: * ;
@@ -271,7 +270,7 @@ impl WebhdfsBackend {
271
270
"CREATE"
272
271
} ;
273
272
let mut url = format ! (
274
- "{}/webhdfs/v1/{}?op={}&overwrite=true&noredirect=true " ,
273
+ "{}/webhdfs/v1/{}?op={}&overwrite=true" ,
275
274
self . endpoint,
276
275
percent_encode_path( & p) ,
277
276
op,
@@ -283,21 +282,35 @@ impl WebhdfsBackend {
283
282
let req = Request :: put ( & url)
284
283
. body ( AsyncBody :: Empty )
285
284
. map_err ( new_request_build_error) ?;
285
+
286
286
// mkdir does not redirect
287
287
if path. ends_with ( '/' ) {
288
288
return Ok ( req) ;
289
289
}
290
290
291
291
let resp = self . client . send_async ( req) . await ?;
292
292
293
- self . webhdfs_put_redirect ( resp, size, content_type, body)
294
- . await
293
+ // should be a 307 TEMPORARY_REDIRECT
294
+ if resp. status ( ) != StatusCode :: TEMPORARY_REDIRECT {
295
+ return Err ( parse_error ( resp) . await ?) ;
296
+ }
297
+ let re_url = self . follow_redirect ( resp) ?;
298
+
299
+ let mut re_builder = Request :: put ( re_url) ;
300
+ if let Some ( size) = size {
301
+ re_builder = re_builder. header ( CONTENT_LENGTH , size. to_string ( ) ) ;
302
+ }
303
+ if let Some ( content_type) = content_type {
304
+ re_builder = re_builder. header ( CONTENT_TYPE , content_type) ;
305
+ }
306
+
307
+ re_builder. body ( body) . map_err ( new_request_build_error)
295
308
}
296
309
297
310
async fn webhdfs_open_req ( & self , path : & str , range : & BytesRange ) -> Result < Request < AsyncBody > > {
298
311
let p = build_abs_path ( & self . root , path) ;
299
312
let mut url = format ! (
300
- "{}/webhdfs/v1/{}?op=OPEN&noredirect=true " ,
313
+ "{}/webhdfs/v1/{}?op=OPEN" ,
301
314
self . endpoint,
302
315
percent_encode_path( & p) ,
303
316
) ;
@@ -378,15 +391,16 @@ impl WebhdfsBackend {
378
391
let req = self . webhdfs_open_req ( path, & range) . await ?;
379
392
let resp = self . client . send_async ( req) . await ?;
380
393
381
- // this should be an 200 OK http response
382
- // with JSON redirect message in its body
383
- if resp. status ( ) != StatusCode :: OK {
384
- // let the outside handle this error
385
- return Ok ( resp) ;
394
+ // this should be a 307 redirect
395
+ if resp. status ( ) != StatusCode :: TEMPORARY_REDIRECT {
396
+ return Err ( parse_error ( resp) . await ?) ;
386
397
}
387
398
388
- let redirected = self . webhdfs_get_redirect ( resp) . await ?;
389
- self . client . send_async ( redirected) . await
399
+ let re_url = self . follow_redirect ( resp) ?;
400
+ let re_req = Request :: get ( & re_url)
401
+ . body ( AsyncBody :: Empty )
402
+ . map_err ( new_request_build_error) ?;
403
+ self . client . send_async ( re_req) . await
390
404
}
391
405
392
406
async fn webhdfs_status_object ( & self , path : & str ) -> Result < Response < IncomingAsyncBody > > {
@@ -427,56 +441,32 @@ impl WebhdfsBackend {
427
441
428
442
self . client . send_async ( req) . await
429
443
}
430
-
431
- /// get redirect destination from 307 TEMPORARY_REDIRECT http response
432
- async fn follow_redirect ( & self , resp : Response < IncomingAsyncBody > ) -> Result < String > {
433
- let bs = resp. into_body ( ) . bytes ( ) . await . map_err ( |e| {
434
- Error :: new ( ErrorKind :: Unexpected , "redirection receive fail" )
435
- . with_context ( "service" , Scheme :: Webhdfs )
436
- . set_source ( e)
437
- } ) ?;
438
- let loc = serde_json:: from_reader :: < _ , Redirection > ( bs. reader ( ) )
439
- . map_err ( |e| {
440
- Error :: new ( ErrorKind :: Unexpected , "redirection fail" )
441
- . with_context ( "service" , Scheme :: Webhdfs )
442
- . set_permanent ( )
443
- . set_source ( e)
444
- } ) ?
445
- . location ;
446
-
447
- Ok ( loc)
448
- }
449
444
}
450
445
451
446
impl WebhdfsBackend {
452
- async fn webhdfs_get_redirect (
453
- & self ,
454
- redirection : Response < IncomingAsyncBody > ,
455
- ) -> Result < Request < AsyncBody > > {
456
- let redirect = self . follow_redirect ( redirection) . await ?;
457
-
458
- Request :: get ( redirect)
459
- . body ( AsyncBody :: Empty )
460
- . map_err ( new_request_build_error)
461
- }
462
-
463
- async fn webhdfs_put_redirect (
464
- & self ,
465
- resp : Response < IncomingAsyncBody > ,
466
- size : Option < u64 > ,
467
- content_type : Option < & str > ,
468
- body : AsyncBody ,
469
- ) -> Result < Request < AsyncBody > > {
470
- let redirect = self . follow_redirect ( resp) . await ?;
471
-
472
- let mut req = Request :: put ( redirect) ;
473
- if let Some ( size) = size {
474
- req = req. header ( CONTENT_LENGTH , size. to_string ( ) ) ;
475
- }
476
- if let Some ( content_type) = content_type {
477
- req = req. header ( CONTENT_TYPE , content_type) ;
478
- }
479
- req. body ( body) . map_err ( new_request_build_error)
447
+ /// get redirect destination from 307 TEMPORARY_REDIRECT http response
448
+ fn follow_redirect ( & self , resp : Response < IncomingAsyncBody > ) -> Result < String > {
449
+ let loc = match parse_location ( resp. headers ( ) ) ? {
450
+ Some ( p) => {
451
+ if !p. starts_with ( '/' ) {
452
+ // is not relative path
453
+ p. to_string ( )
454
+ } else {
455
+ // is relative path
456
+ // prefix with endpoint url
457
+ let url = self . endpoint . clone ( ) ;
458
+ format ! ( "{url}/{p}" )
459
+ }
460
+ }
461
+ None => {
462
+ let err = Error :: new (
463
+ ErrorKind :: Unexpected ,
464
+ "redirection fail: no location header" ,
465
+ ) ;
466
+ return Err ( err) ;
467
+ }
468
+ } ;
469
+ Ok ( loc)
480
470
}
481
471
482
472
fn consume_success_mkdir ( & self , path : & str , parts : Parts , body : & str ) -> Result < RpCreate > {
@@ -497,9 +487,7 @@ impl WebhdfsBackend {
497
487
) ) ;
498
488
}
499
489
}
500
- }
501
490
502
- impl WebhdfsBackend {
503
491
async fn check_root ( & self ) -> Result < ( ) > {
504
492
let resp = self . webhdfs_status_object ( "/" ) . await ?;
505
493
match resp. status ( ) {
0 commit comments