Skip to content

Commit bb8e42f

Browse files
authored
Add GetOptions::head (#4931)
1 parent 90bc5ec commit bb8e42f

File tree

10 files changed

+29
-102
lines changed

10 files changed

+29
-102
lines changed

object_store/src/aws/client.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -554,15 +554,10 @@ impl GetClient for S3Client {
554554
const STORE: &'static str = STORE;
555555

556556
/// Make an S3 GET request <https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html>
557-
async fn get_request(
558-
&self,
559-
path: &Path,
560-
options: GetOptions,
561-
head: bool,
562-
) -> Result<Response> {
557+
async fn get_request(&self, path: &Path, options: GetOptions) -> Result<Response> {
563558
let credential = self.get_credential().await?;
564559
let url = self.config.path_url(path);
565-
let method = match head {
560+
let method = match options.head {
566561
true => Method::HEAD,
567562
false => Method::GET,
568563
};

object_store/src/aws/mod.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -307,10 +307,6 @@ impl ObjectStore for AmazonS3 {
307307
self.client.get_opts(location, options).await
308308
}
309309

310-
async fn head(&self, location: &Path) -> Result<ObjectMeta> {
311-
self.client.head(location).await
312-
}
313-
314310
async fn delete(&self, location: &Path) -> Result<()> {
315311
self.client.delete_request(location, &()).await
316312
}

object_store/src/azure/client.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -264,15 +264,10 @@ impl GetClient for AzureClient {
264264
/// Make an Azure GET request
265265
/// <https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob>
266266
/// <https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob-properties>
267-
async fn get_request(
268-
&self,
269-
path: &Path,
270-
options: GetOptions,
271-
head: bool,
272-
) -> Result<Response> {
267+
async fn get_request(&self, path: &Path, options: GetOptions) -> Result<Response> {
273268
let credential = self.get_credential().await?;
274269
let url = self.config.path_url(path);
275-
let method = match head {
270+
let method = match options.head {
276271
true => Method::HEAD,
277272
false => Method::GET,
278273
};

object_store/src/azure/mod.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,6 @@ impl ObjectStore for MicrosoftAzure {
202202
self.client.get_opts(location, options).await
203203
}
204204

205-
async fn head(&self, location: &Path) -> Result<ObjectMeta> {
206-
self.client.head(location).await
207-
}
208-
209205
async fn delete(&self, location: &Path) -> Result<()> {
210206
self.client.delete_request(location, &()).await
211207
}

object_store/src/client/get.rs

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
use crate::client::header::{header_meta, HeaderConfig};
1919
use crate::path::Path;
20-
use crate::{Error, GetOptions, GetResult, ObjectMeta};
20+
use crate::{Error, GetOptions, GetResult};
2121
use crate::{GetResultPayload, Result};
2222
use async_trait::async_trait;
2323
use futures::{StreamExt, TryStreamExt};
@@ -34,27 +34,20 @@ pub trait GetClient: Send + Sync + 'static {
3434
last_modified_required: true,
3535
};
3636

37-
async fn get_request(
38-
&self,
39-
path: &Path,
40-
options: GetOptions,
41-
head: bool,
42-
) -> Result<Response>;
37+
async fn get_request(&self, path: &Path, options: GetOptions) -> Result<Response>;
4338
}
4439

4540
/// Extension trait for [`GetClient`] that adds common retrieval functionality
4641
#[async_trait]
4742
pub trait GetClientExt {
4843
async fn get_opts(&self, location: &Path, options: GetOptions) -> Result<GetResult>;
49-
50-
async fn head(&self, location: &Path) -> Result<ObjectMeta>;
5144
}
5245

5346
#[async_trait]
5447
impl<T: GetClient> GetClientExt for T {
5548
async fn get_opts(&self, location: &Path, options: GetOptions) -> Result<GetResult> {
5649
let range = options.range.clone();
57-
let response = self.get_request(location, options, false).await?;
50+
let response = self.get_request(location, options).await?;
5851
let meta =
5952
header_meta(location, response.headers(), T::HEADER_CONFIG).map_err(|e| {
6053
Error::Generic {
@@ -77,15 +70,4 @@ impl<T: GetClient> GetClientExt for T {
7770
meta,
7871
})
7972
}
80-
81-
async fn head(&self, location: &Path) -> Result<ObjectMeta> {
82-
let options = GetOptions::default();
83-
let response = self.get_request(location, options, true).await?;
84-
header_meta(location, response.headers(), T::HEADER_CONFIG).map_err(|e| {
85-
Error::Generic {
86-
store: T::STORE,
87-
source: Box::new(e),
88-
}
89-
})
90-
}
9173
}

object_store/src/gcp/mod.rs

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -389,16 +389,11 @@ impl GetClient for GoogleCloudStorageClient {
389389
const STORE: &'static str = STORE;
390390

391391
/// Perform a get request <https://cloud.google.com/storage/docs/xml-api/get-object-download>
392-
async fn get_request(
393-
&self,
394-
path: &Path,
395-
options: GetOptions,
396-
head: bool,
397-
) -> Result<Response> {
392+
async fn get_request(&self, path: &Path, options: GetOptions) -> Result<Response> {
398393
let credential = self.get_credential().await?;
399394
let url = self.object_url(path);
400395

401-
let method = match head {
396+
let method = match options.head {
402397
true => Method::HEAD,
403398
false => Method::GET,
404399
};
@@ -604,10 +599,6 @@ impl ObjectStore for GoogleCloudStorage {
604599
self.client.get_opts(location, options).await
605600
}
606601

607-
async fn head(&self, location: &Path) -> Result<ObjectMeta> {
608-
self.client.head(location).await
609-
}
610-
611602
async fn delete(&self, location: &Path) -> Result<()> {
612603
self.client.delete_request(location).await
613604
}

object_store/src/http/client.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -288,14 +288,9 @@ impl GetClient for Client {
288288
last_modified_required: false,
289289
};
290290

291-
async fn get_request(
292-
&self,
293-
location: &Path,
294-
options: GetOptions,
295-
head: bool,
296-
) -> Result<Response> {
297-
let url = self.path_url(location);
298-
let method = match head {
291+
async fn get_request(&self, path: &Path, options: GetOptions) -> Result<Response> {
292+
let url = self.path_url(path);
293+
let method = match options.head {
299294
true => Method::HEAD,
300295
false => Method::GET,
301296
};
@@ -311,7 +306,7 @@ impl GetClient for Client {
311306
Some(StatusCode::NOT_FOUND | StatusCode::METHOD_NOT_ALLOWED) => {
312307
crate::Error::NotFound {
313308
source: Box::new(source),
314-
path: location.to_string(),
309+
path: path.to_string(),
315310
}
316311
}
317312
_ => Error::Request { source }.into(),
@@ -322,7 +317,7 @@ impl GetClient for Client {
322317
if has_range && res.status() != StatusCode::PARTIAL_CONTENT {
323318
return Err(crate::Error::NotSupported {
324319
source: Box::new(Error::RangeNotSupported {
325-
href: location.to_string(),
320+
href: path.to_string(),
326321
}),
327322
});
328323
}

object_store/src/http/mod.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,6 @@ impl ObjectStore for HttpStore {
118118
self.client.get_opts(location, options).await
119119
}
120120

121-
async fn head(&self, location: &Path) -> Result<ObjectMeta> {
122-
self.client.head(location).await
123-
}
124-
125121
async fn delete(&self, location: &Path) -> Result<()> {
126122
self.client.delete(location).await
127123
}

object_store/src/lib.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,13 @@ pub trait ObjectStore: std::fmt::Display + Send + Sync + Debug + 'static {
410410
}
411411

412412
/// Return the metadata for the specified location
413-
async fn head(&self, location: &Path) -> Result<ObjectMeta>;
413+
async fn head(&self, location: &Path) -> Result<ObjectMeta> {
414+
let options = GetOptions {
415+
head: true,
416+
..Default::default()
417+
};
418+
Ok(self.get_opts(location, options).await?.meta)
419+
}
414420

415421
/// Delete the object at the specified location.
416422
async fn delete(&self, location: &Path) -> Result<()>;
@@ -716,6 +722,10 @@ pub struct GetOptions {
716722
///
717723
/// <https://datatracker.ietf.org/doc/html/rfc9110#name-range>
718724
pub range: Option<Range<usize>>,
725+
/// Request transfer of no content
726+
///
727+
/// <https://datatracker.ietf.org/doc/html/rfc9110#name-head>
728+
pub head: bool,
719729
}
720730

721731
impl GetOptions {

object_store/src/local.rs

Lines changed: 4 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -419,35 +419,6 @@ impl ObjectStore for LocalFileSystem {
419419
.await
420420
}
421421

422-
async fn head(&self, location: &Path) -> Result<ObjectMeta> {
423-
let path = self.config.path_to_filesystem(location)?;
424-
let location = location.clone();
425-
426-
maybe_spawn_blocking(move || {
427-
let metadata = match metadata(&path) {
428-
Err(e) => Err(match e.kind() {
429-
ErrorKind::NotFound => Error::NotFound {
430-
path: path.clone(),
431-
source: e,
432-
},
433-
_ => Error::Metadata {
434-
source: e.into(),
435-
path: location.to_string(),
436-
},
437-
}),
438-
Ok(m) => match !m.is_dir() {
439-
true => Ok(m),
440-
false => Err(Error::NotFound {
441-
path,
442-
source: io::Error::new(ErrorKind::NotFound, "is directory"),
443-
}),
444-
},
445-
}?;
446-
convert_metadata(metadata, location)
447-
})
448-
.await
449-
}
450-
451422
async fn delete(&self, location: &Path) -> Result<()> {
452423
let path = self.config.path_to_filesystem(location)?;
453424
maybe_spawn_blocking(move || match std::fs::remove_file(&path) {
@@ -1604,15 +1575,15 @@ mod unix_test {
16041575
let path = root.path().join(filename);
16051576
unistd::mkfifo(&path, stat::Mode::S_IRWXU).unwrap();
16061577

1607-
let location = Path::from(filename);
1608-
integration.head(&location).await.unwrap();
1609-
16101578
// Need to open read and write side in parallel
16111579
let spawned = tokio::task::spawn_blocking(|| {
1612-
OpenOptions::new().write(true).open(path).unwrap();
1580+
OpenOptions::new().write(true).open(path).unwrap()
16131581
});
16141582

1583+
let location = Path::from(filename);
1584+
integration.head(&location).await.unwrap();
16151585
integration.get(&location).await.unwrap();
1586+
16161587
spawned.await.unwrap();
16171588
}
16181589
}

0 commit comments

Comments
 (0)