@@ -20,7 +20,7 @@ use talon_core::{
2020 BackendStore , Error , ListPage , ListedObject , ObjectId , ObjectStat , Result , Version ,
2121} ;
2222
23- use crate :: http:: { HttpClient , HttpRequest , Method } ;
23+ use crate :: http:: { HttpClient , HttpRequest , HttpResponse , HttpStreamResponse , Method } ;
2424
2525/// Percent-encode a query value. `/` is escaped: a listing prefix contains
2626/// slashes and an unescaped one would change the request path.
@@ -163,6 +163,18 @@ impl AzureBackend {
163163 prefix : & str ,
164164 cursor : Option < & str > ,
165165 max : u32 ,
166+ ) -> String {
167+ self . list_url_with_delimiter ( container, prefix, None , cursor, max)
168+ }
169+
170+ /// Build a container listing URL with the full gateway read surface.
171+ pub fn list_url_with_delimiter (
172+ & self ,
173+ container : & str ,
174+ prefix : & str ,
175+ delimiter : Option < & str > ,
176+ cursor : Option < & str > ,
177+ max : u32 ,
166178 ) -> String {
167179 let scheme = if self . config . tls { "https" } else { "http" } ;
168180 let host =
@@ -178,6 +190,9 @@ impl AzureBackend {
178190 if !prefix. is_empty ( ) {
179191 query. push_str ( & format ! ( "&prefix={}" , encode_query_value( prefix) ) ) ;
180192 }
193+ if let Some ( delimiter) = delimiter. filter ( |value| !value. is_empty ( ) ) {
194+ query. push_str ( & format ! ( "&delimiter={}" , encode_query_value( delimiter) ) ) ;
195+ }
181196 if let Some ( marker) = cursor {
182197 query. push_str ( & format ! ( "&marker={}" , encode_query_value( marker) ) ) ;
183198 }
@@ -298,6 +313,57 @@ impl AzureBackend {
298313 }
299314 }
300315
316+ /// Execute a raw metadata request while forwarding only validated
317+ /// conditional headers supplied by a protocol adapter.
318+ pub async fn execute_head_raw (
319+ & self ,
320+ obj : & ObjectId ,
321+ conditions : & [ ( String , String ) ] ,
322+ ) -> std:: result:: Result < HttpResponse , String > {
323+ let mut request = self . build_head ( obj) ;
324+ request. headers . extend_from_slice ( conditions) ;
325+ self . http . execute ( self . authorized ( request) ) . await
326+ }
327+
328+ /// Execute a whole or ranged GET without buffering its response body.
329+ pub async fn execute_get_stream_raw (
330+ & self ,
331+ obj : & ObjectId ,
332+ range : Option < ( u64 , u64 ) > ,
333+ conditions : & [ ( String , String ) ] ,
334+ ) -> std:: result:: Result < HttpStreamResponse , String > {
335+ let mut headers = self . common_headers ( ) ;
336+ if let Some ( ( start, end) ) = range {
337+ headers. push ( ( "x-ms-range" . into ( ) , format ! ( "bytes={start}-{end}" ) ) ) ;
338+ }
339+ headers. extend_from_slice ( conditions) ;
340+ let request = HttpRequest :: new ( Method :: Get , self . blob_url ( obj) , headers) ;
341+ self . http . execute_stream ( self . authorized ( request) ) . await
342+ }
343+
344+ /// Execute one raw Azure List Blobs page.
345+ pub async fn execute_list_raw (
346+ & self ,
347+ container : & str ,
348+ prefix : & str ,
349+ delimiter : Option < & str > ,
350+ marker : Option < & str > ,
351+ max_results : u32 ,
352+ conditions : & [ ( String , String ) ] ,
353+ ) -> std:: result:: Result < HttpResponse , String > {
354+ let url = self . list_url_with_delimiter (
355+ container,
356+ prefix,
357+ delimiter,
358+ marker,
359+ max_results. clamp ( 1 , 5000 ) ,
360+ ) ;
361+ let mut headers = self . common_headers ( ) ;
362+ headers. extend_from_slice ( conditions) ;
363+ let request = HttpRequest :: new ( Method :: Get , url, headers) ;
364+ self . http . execute ( self . authorized ( request) ) . await
365+ }
366+
301367 /// Build the whole-blob PUT request (exposed for testing).
302368 ///
303369 /// Azure block-blob upload requires `x-ms-blob-type: BlockBlob`. When
@@ -407,7 +473,11 @@ impl BackendStore for AzureBackend {
407473 let max_keys = max_keys. clamp ( 1 , 5000 ) ;
408474 let url = self . list_url ( bucket, prefix, cursor, max_keys) ;
409475 let req = HttpRequest :: new ( Method :: Get , url, self . common_headers ( ) ) ;
410- let resp = self . http . execute ( req) . await . map_err ( Error :: Backend ) ?;
476+ let resp = self
477+ . http
478+ . execute ( self . authorized ( req) )
479+ . await
480+ . map_err ( Error :: Backend ) ?;
411481 if resp. status == 404 {
412482 return Err ( Error :: NotFound ( bucket. to_string ( ) ) ) ;
413483 }
0 commit comments