Skip to content

Commit 287bd81

Browse files
authored
Merge branch 'master' into base64-update
2 parents 280212b + f01cc90 commit 287bd81

File tree

12 files changed

+125
-82
lines changed

12 files changed

+125
-82
lines changed

.github/workflows/ci.yml

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,45 +15,29 @@ jobs:
1515
rust: [stable, beta, nightly]
1616

1717
steps:
18-
- uses: actions/checkout@v2
19-
- uses: actions-rs/toolchain@v1
18+
- uses: actions/checkout@v3
19+
- uses: dtolnay/rust-toolchain@master
2020
with:
2121
toolchain: ${{ matrix.rust }}
22-
profile: minimal
23-
override: true
24-
25-
- name: cargo test --all
26-
uses: actions-rs/cargo@v1
27-
with:
28-
command: test
29-
args: --all
30-
- name: cargo test --benches
31-
if: matrix.rust == 'nightly'
32-
uses: actions-rs/cargo@v1
33-
with:
34-
command: test
35-
args: --benches
36-
22+
components: rustfmt
23+
- run: cargo test --workspace
24+
- if: matrix.rust == 'nightly'
25+
run: cargo test --benches
3726
- name: Check minimal versions
3827
if: matrix.rust == 'nightly'
3928
run: |
4029
cargo clean
4130
cargo update -Z minimal-versions
4231
cargo check
32+
- run: cargo fmt --all --check
4333

4434
MSRV:
4535
runs-on: ubuntu-latest
4636

4737
steps:
48-
- uses: actions/checkout@v2
38+
- uses: actions/checkout@v3
4939
- name: Install rust ${{ env.minrust }}
50-
uses: actions-rs/toolchain@v1
40+
uses: dtolnay/rust-toolchain@master
5141
with:
5242
toolchain: ${{ env.minrust }}
53-
profile: minimal
54-
override: true
55-
56-
- name: cargo build
57-
uses: actions-rs/cargo@v1
58-
with:
59-
command: build
43+
- run: cargo build

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ members = [
1919
[dependencies]
2020
http = "0.2.0"
2121
headers-core = { version = "0.2", path = "./headers-core" }
22-
base64 = "0.21"
22+
base64 = "0.21.3"
2323
bitflags = "1.0"
2424
bytes = "1"
2525
mime = "0.3.14"

src/common/cache_control.rs

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use util::{self, csv, Seconds};
77
use HeaderValue;
88

99
/// `Cache-Control` header, defined in [RFC7234](https://tools.ietf.org/html/rfc7234#section-5.2)
10+
/// with extensions in [RFC8246](https://www.rfc-editor.org/rfc/rfc8246)
1011
///
1112
/// The `Cache-Control` header field is used to specify directives for
1213
/// caches along the request/response chain. Such cache directives are
@@ -43,16 +44,32 @@ pub struct CacheControl {
4344
s_max_age: Option<Seconds>,
4445
}
4546

46-
bitflags! {
47-
struct Flags: u32 {
48-
const NO_CACHE = 0b00000001;
49-
const NO_STORE = 0b00000010;
50-
const NO_TRANSFORM = 0b00000100;
51-
const ONLY_IF_CACHED = 0b00001000;
52-
const MUST_REVALIDATE = 0b00010000;
53-
const PUBLIC = 0b00100000;
54-
const PRIVATE = 0b01000000;
55-
const PROXY_REVALIDATE = 0b10000000;
47+
#[derive(Debug, Clone, PartialEq)]
48+
struct Flags {
49+
bits: u64,
50+
}
51+
52+
impl Flags {
53+
const NO_CACHE: Self = Self { bits: 0b000000001 };
54+
const NO_STORE: Self = Self { bits: 0b000000010 };
55+
const NO_TRANSFORM: Self = Self { bits: 0b000000100 };
56+
const ONLY_IF_CACHED: Self = Self { bits: 0b000001000 };
57+
const MUST_REVALIDATE: Self = Self { bits: 0b000010000 };
58+
const PUBLIC: Self = Self { bits: 0b000100000 };
59+
const PRIVATE: Self = Self { bits: 0b001000000 };
60+
const PROXY_REVALIDATE: Self = Self { bits: 0b010000000 };
61+
const IMMUTABLE: Self = Self { bits: 0b100000000 };
62+
63+
fn empty() -> Self {
64+
Self { bits: 0 }
65+
}
66+
67+
fn contains(&self, flag: Self) -> bool {
68+
(self.bits & flag.bits) != 0
69+
}
70+
71+
fn insert(&mut self, flag: Self) {
72+
self.bits |= flag.bits;
5673
}
5774
}
5875

@@ -100,6 +117,11 @@ impl CacheControl {
100117
self.flags.contains(Flags::PRIVATE)
101118
}
102119

120+
/// Check if the `immutable` directive is set.
121+
pub fn immutable(&self) -> bool {
122+
self.flags.contains(Flags::IMMUTABLE)
123+
}
124+
103125
/// Get the value of the `max-age` directive if set.
104126
pub fn max_age(&self) -> Option<Duration> {
105127
self.max_age.map(Into::into)
@@ -158,27 +180,33 @@ impl CacheControl {
158180
self
159181
}
160182

183+
/// Set the `immutable` directive.
184+
pub fn with_immutable(mut self) -> Self {
185+
self.flags.insert(Flags::IMMUTABLE);
186+
self
187+
}
188+
161189
/// Set the `max-age` directive.
162-
pub fn with_max_age(mut self, seconds: Duration) -> Self {
163-
self.max_age = Some(seconds.into());
190+
pub fn with_max_age(mut self, duration: Duration) -> Self {
191+
self.max_age = Some(duration.into());
164192
self
165193
}
166194

167195
/// Set the `max-stale` directive.
168-
pub fn with_max_stale(mut self, seconds: Duration) -> Self {
169-
self.max_stale = Some(seconds.into());
196+
pub fn with_max_stale(mut self, duration: Duration) -> Self {
197+
self.max_stale = Some(duration.into());
170198
self
171199
}
172200

173201
/// Set the `min-fresh` directive.
174-
pub fn with_min_fresh(mut self, seconds: Duration) -> Self {
175-
self.min_fresh = Some(seconds.into());
202+
pub fn with_min_fresh(mut self, duration: Duration) -> Self {
203+
self.min_fresh = Some(duration.into());
176204
self
177205
}
178206

179207
/// Set the `s-maxage` directive.
180-
pub fn with_s_max_age(mut self, seconds: Duration) -> Self {
181-
self.s_max_age = Some(seconds.into());
208+
pub fn with_s_max_age(mut self, duration: Duration) -> Self {
209+
self.s_max_age = Some(duration.into());
182210
self
183211
}
184212
}
@@ -236,6 +264,9 @@ impl FromIterator<KnownDirective> for FromIter {
236264
Directive::Private => {
237265
cc.flags.insert(Flags::PRIVATE);
238266
}
267+
Directive::Immutable => {
268+
cc.flags.insert(Flags::IMMUTABLE);
269+
}
239270
Directive::ProxyRevalidate => {
240271
cc.flags.insert(Flags::PROXY_REVALIDATE);
241272
}
@@ -278,6 +309,7 @@ impl<'a> fmt::Display for Fmt<'a> {
278309
if_flag(Flags::MUST_REVALIDATE, Directive::MustRevalidate),
279310
if_flag(Flags::PUBLIC, Directive::Public),
280311
if_flag(Flags::PRIVATE, Directive::Private),
312+
if_flag(Flags::IMMUTABLE, Directive::Immutable),
281313
if_flag(Flags::PROXY_REVALIDATE, Directive::ProxyRevalidate),
282314
self.0
283315
.max_age
@@ -325,6 +357,7 @@ enum Directive {
325357
MustRevalidate,
326358
Public,
327359
Private,
360+
Immutable,
328361
ProxyRevalidate,
329362
SMaxAge(u64),
330363
}
@@ -345,6 +378,7 @@ impl fmt::Display for Directive {
345378
Directive::MustRevalidate => "must-revalidate",
346379
Directive::Public => "public",
347380
Directive::Private => "private",
381+
Directive::Immutable => "immutable",
348382
Directive::ProxyRevalidate => "proxy-revalidate",
349383
Directive::SMaxAge(secs) => return write!(f, "s-maxage={}", secs),
350384
},
@@ -364,6 +398,7 @@ impl FromStr for KnownDirective {
364398
"must-revalidate" => Directive::MustRevalidate,
365399
"public" => Directive::Public,
366400
"private" => Directive::Private,
401+
"immutable" => Directive::Immutable,
367402
"proxy-revalidate" => Directive::ProxyRevalidate,
368403
"" => return Err(()),
369404
_ => match s.find('=') {
@@ -428,9 +463,18 @@ mod tests {
428463
);
429464
}
430465

466+
#[test]
467+
fn test_immutable() {
468+
let cc = CacheControl::new().with_immutable();
469+
let headers = test_encode(cc.clone());
470+
assert_eq!(headers["cache-control"], "immutable");
471+
assert_eq!(test_decode::<CacheControl>(&["immutable"]).unwrap(), cc);
472+
assert!(cc.immutable());
473+
}
474+
431475
#[test]
432476
fn test_parse_bad_syntax() {
433-
assert_eq!(test_decode::<CacheControl>(&["max-age=lolz"]), None,);
477+
assert_eq!(test_decode::<CacheControl>(&["max-age=lolz"]), None);
434478
}
435479

436480
#[test]

src/common/content_range.rs

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -178,22 +178,23 @@ fn split_in_two(s: &str, separator: char) -> Option<(&str, &str)> {
178178
}
179179

180180
/*
181-
test_header!(test_bytes,
182-
vec![b"bytes 0-499/500"],
183-
Some(ContentRange(ContentRangeSpec::Bytes {
184-
range: Some((0, 499)),
185-
complete_length: Some(500)
186-
})));
187-
188-
test_header!(test_bytes_unknown_len,
189-
vec![b"bytes 0-499/*"],
190-
Some(ContentRange(ContentRangeSpec::Bytes {
191-
range: Some((0, 499)),
192-
complete_length: None
193-
})));
194-
195-
test_header!(test_bytes_unknown_range,
196-
vec![b"bytes */500"],
181+
test_header!(test_bytes,
182+
vec![b"bytes 0-499/500"],
183+
Some(ContentRange(ContentRangeSpec::Bytes {
184+
range: Some((0, 499)),
185+
complete_length: Some(500)
186+
})));
187+
188+
test_header!(test_bytes_unknown_len,
189+
vec![b"bytes 0-499/*"],
190+
Some(ContentRange(ContentRangeSpec::Bytes {
191+
range: Some((0, 499)),
192+
complete_length: None
193+
})));
194+
195+
test_header!(test_bytes_unknown_range,
196+
vec![b"bytes */
197+
500"],
197198
Some(ContentRange(ContentRangeSpec::Bytes {
198199
range: None,
199200
complete_length: Some(500)

src/common/content_type.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,16 @@ impl fmt::Display for ContentType {
135135
}
136136
}
137137

138+
impl std::str::FromStr for ContentType {
139+
type Err = ::Error;
140+
141+
fn from_str(s: &str) -> Result<ContentType, Self::Err> {
142+
s.parse::<Mime>()
143+
.map(|m| m.into())
144+
.map_err(|_| ::Error::invalid())
145+
}
146+
}
147+
138148
#[cfg(test)]
139149
mod tests {
140150
use super::super::test_decode;
@@ -148,6 +158,15 @@ mod tests {
148158
);
149159
}
150160

161+
#[test]
162+
fn from_str() {
163+
assert_eq!(
164+
"application/json".parse::<ContentType>().unwrap(),
165+
ContentType::json(),
166+
);
167+
assert!("invalid-mimetype".parse::<ContentType>().is_err());
168+
}
169+
151170
bench_header!(bench_plain, ContentType, "text/plain");
152171
bench_header!(bench_json, ContentType, "application/json");
153172
bench_header!(

src/common/etag.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,7 @@ error_type!(InvalidETag);
5050
impl FromStr for ETag {
5151
type Err = InvalidETag;
5252
fn from_str(src: &str) -> Result<Self, Self::Err> {
53-
let val = src
54-
.parse()
55-
.map_err(|_| InvalidETag { _inner: () })?;
53+
let val = src.parse().map_err(|_| InvalidETag { _inner: () })?;
5654

5755
EntityTag::from_owned(val)
5856
.map(ETag)

src/common/host.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use std::fmt;
21
use std::convert::TryFrom;
2+
use std::fmt;
33

44
use http::uri::Authority;
55

src/common/if_range.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ impl IfRange {
6464
pub fn is_modified(&self, etag: Option<&ETag>, last_modified: Option<&LastModified>) -> bool {
6565
match self.0 {
6666
IfRange_::Date(since) => last_modified.map(|time| since < time.0).unwrap_or(true),
67-
IfRange_::EntityTag(ref entity) => etag.map(|etag| !etag.0.strong_eq(entity)).unwrap_or(true),
67+
IfRange_::EntityTag(ref entity) => {
68+
etag.map(|etag| !etag.0.strong_eq(entity)).unwrap_or(true)
69+
}
6870
}
6971
}
7072
}

src/common/origin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use std::fmt;
21
use std::convert::TryFrom;
2+
use std::fmt;
33

44
use bytes::Bytes;
55
use http::uri::{self, Authority, Scheme, Uri};

src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,6 @@
7373
//! ```
7474
7575
extern crate base64;
76-
#[macro_use]
77-
extern crate bitflags;
7876
extern crate bytes;
7977
extern crate headers_core;
8078
extern crate http;

src/util/entity.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,7 @@ impl EntityTag {
167167
}
168168

169169
pub(crate) fn from_val(val: &HeaderValue) -> Option<EntityTag> {
170-
EntityTag::parse(val.as_bytes()).map(|_entity| {
171-
EntityTag(val.clone())
172-
})
170+
EntityTag::parse(val.as_bytes()).map(|_entity| EntityTag(val.clone()))
173171
}
174172
}
175173

@@ -239,11 +237,10 @@ impl EntityTagRange {
239237
{
240238
match *self {
241239
EntityTagRange::Any => true,
242-
EntityTagRange::Tags(ref tags) => {
243-
tags.iter()
244-
.flat_map(EntityTag::<&str>::parse)
245-
.any(|tag| func(&tag, entity))
246-
},
240+
EntityTagRange::Tags(ref tags) => tags
241+
.iter()
242+
.flat_map(EntityTag::<&str>::parse)
243+
.any(|tag| func(&tag, entity)),
247244
}
248245
}
249246
}

src/util/flat_csv.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ impl<'a, Sep: Separator> FromIterator<&'a HeaderValue> for FlatCsv<Sep> {
120120
buf.extend_from_slice(val.as_bytes());
121121
}
122122

123-
let val =
124-
HeaderValue::from_maybe_shared(buf.freeze()).expect("comma separated HeaderValues are valid");
123+
let val = HeaderValue::from_maybe_shared(buf.freeze())
124+
.expect("comma separated HeaderValues are valid");
125125

126126
val.into()
127127
}
@@ -151,8 +151,8 @@ impl<Sep: Separator> FromIterator<HeaderValue> for FlatCsv<Sep> {
151151
buf.extend_from_slice(val.as_bytes());
152152
}
153153

154-
let val =
155-
HeaderValue::from_maybe_shared(buf.freeze()).expect("comma separated HeaderValues are valid");
154+
let val = HeaderValue::from_maybe_shared(buf.freeze())
155+
.expect("comma separated HeaderValues are valid");
156156

157157
val.into()
158158
}

0 commit comments

Comments
 (0)