Skip to content

Commit ee07154

Browse files
committed
refactor: share S3 preflight Vary helper
1 parent 32ee3a6 commit ee07154

2 files changed

Lines changed: 40 additions & 36 deletions

File tree

api/src/cors.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ const S3_DEFAULT_ALLOWED_HEADERS: &str = "authorization,content-type,content-md5
1212
const S3_EXPOSED_HEADERS: &str = "etag,content-range,accept-ranges,content-length,last-modified,\
1313
x-amz-request-id,x-amz-version-id,x-amz-delete-marker,aruna-source-content-type,\
1414
aruna-source-etag,aruna-source-last-modified,aruna-last-refresh";
15+
pub(crate) const S3_PREFLIGHT_VARY: &[&str] = &[
16+
"Origin",
17+
"Access-Control-Request-Method",
18+
"Access-Control-Request-Headers",
19+
];
1520

1621
/// Allowed cross-origin request origins, shared by the REST and S3 interfaces.
1722
/// An empty configuration denies all cross-origin access (no CORS headers are
@@ -153,6 +158,36 @@ impl CorsConfig {
153158
}
154159
}
155160

161+
pub(crate) fn append_vary_headers(headers: &mut HeaderMap, values: &[&str]) {
162+
let mut vary_values = headers
163+
.get(header::VARY)
164+
.and_then(|value| value.to_str().ok())
165+
.map(|value| {
166+
value
167+
.split(',')
168+
.map(str::trim)
169+
.filter(|entry| !entry.is_empty())
170+
.map(str::to_owned)
171+
.collect::<Vec<_>>()
172+
})
173+
.unwrap_or_default();
174+
175+
for value in values {
176+
if !vary_values
177+
.iter()
178+
.any(|existing| existing.eq_ignore_ascii_case(value))
179+
{
180+
vary_values.push((*value).to_string());
181+
}
182+
}
183+
184+
if !vary_values.is_empty()
185+
&& let Ok(value) = HeaderValue::from_str(&vary_values.join(", "))
186+
{
187+
headers.insert(header::VARY, value);
188+
}
189+
}
190+
156191
#[cfg(test)]
157192
mod tests {
158193
use super::*;

api/src/s3/cors.rs

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
use crate::cors::{S3_PREFLIGHT_VARY, append_vary_headers};
12
use aruna_core::structs::{BucketCorsConfiguration, BucketCorsRule};
2-
use http::header::{HeaderName, HeaderValue, VARY};
3+
use http::header::{HeaderName, HeaderValue};
34
use http::{Method, StatusCode};
45
use s3s::HttpResponse;
56
use s3s::dto::{CORSConfiguration, CORSRule, GetBucketCorsOutput};
@@ -18,9 +19,6 @@ pub(crate) const MAX_AGE_HEADER: &str = "access-control-max-age";
1819
const WILDCARD: &str = "*";
1920
const VALID_CORS_METHODS: &[&str] = &["GET", "PUT", "HEAD", "POST", "DELETE"];
2021

21-
pub(crate) const PREFLIGHT_VARY: &[&str] =
22-
&[ORIGIN_HEADER, REQUEST_METHOD_HEADER, REQUEST_HEADERS_HEADER];
23-
2422
#[derive(Debug, Clone, PartialEq, Eq)]
2523
pub(crate) struct MatchedCorsRule {
2624
pub allow_origin: String,
@@ -284,14 +282,14 @@ pub(crate) fn build_preflight_response(matched_rule: MatchedCorsRule) -> HttpRes
284282
&max_age_seconds.to_string(),
285283
);
286284
}
287-
append_vary_headers(response.headers_mut(), PREFLIGHT_VARY);
285+
append_vary_headers(response.headers_mut(), S3_PREFLIGHT_VARY);
288286
response
289287
}
290288

291289
pub(crate) fn build_preflight_forbidden_response() -> HttpResponse {
292290
let mut response = HttpResponse::new(s3s::Body::empty());
293291
*response.status_mut() = StatusCode::FORBIDDEN;
294-
append_vary_headers(response.headers_mut(), PREFLIGHT_VARY);
292+
append_vary_headers(response.headers_mut(), S3_PREFLIGHT_VARY);
295293
response
296294
}
297295

@@ -329,39 +327,10 @@ fn append_header<T>(response: &mut http::Response<T>, name: HeaderName, value: &
329327
}
330328
}
331329

332-
fn append_vary_headers(headers: &mut http::HeaderMap, values: &[&str]) {
333-
let mut vary_values = headers
334-
.get(VARY)
335-
.and_then(|value| value.to_str().ok())
336-
.map(|value| {
337-
value
338-
.split(',')
339-
.map(str::trim)
340-
.filter(|entry| !entry.is_empty())
341-
.map(str::to_owned)
342-
.collect::<Vec<_>>()
343-
})
344-
.unwrap_or_default();
345-
346-
for value in values {
347-
if !vary_values
348-
.iter()
349-
.any(|existing| existing.eq_ignore_ascii_case(value))
350-
{
351-
vary_values.push((*value).to_string());
352-
}
353-
}
354-
355-
if !vary_values.is_empty()
356-
&& let Ok(value) = HeaderValue::from_str(&vary_values.join(", "))
357-
{
358-
headers.insert(VARY, value);
359-
}
360-
}
361-
362330
#[cfg(test)]
363331
mod tests {
364332
use super::*;
333+
use http::header::VARY;
365334

366335
#[test]
367336
fn converts_cors_configuration_between_dto_and_core() {

0 commit comments

Comments
 (0)