Skip to content

Cache-Control design #3

Closed
Closed
@seanmonstar

Description

@seanmonstar

The Cache-Control header is just interesting enough that I feel it isn't quite obvious which of the following designs make more sense.

List of Directives

This is how it was in hyper 0.11.x. Essentially, it's just a comma separated list of CacheDirectives, and not any smarter than that.

pub struct CacheControl {
    directives: Vec<CacheDirective>,
}

Example construction:

let cc = CacheControl::new(vec![
    CacheDirective::NO_TRANSFORM,
    CacheDirective::max_age(Duration::from_secs(300)),
]);

This matches the spec more directly, as its ABNF claims to just be a list of directives, and clients may not understand newer directives. However, with the more conservative API (to allow adding new directive support without being a breaking change), the CacheDirective::Ext is no longer exported, so servers/clients couldn't really use "newer" directives anyways, without updating this crate.

The downsides are that this results in an extra allocation of a Vec, and is more complicated for checking if a certain directive is set (one has to iterate looking for a specific directive).

Set of Fields

This would be a plain old Rust object with fields representing known directives.

pub struct CacheControl {
    no_store: bool,
    no_cache: bool,
    max_age: Option<Seconds>,
    // ...
}

This would mean that an allocation of a mostly useless Vec can be removed, and accessors like cc.is_no_cache() can be added cheaply.

The struct could be made even smaller by using bitflags for all the boolean fields.

Lazy (FlatCsv)

Some other fields are currently just lazily parsed when they would otherwise be a list of strings. This saves on allocations/copies (and makes encoding super cheap) at the expense of needing to parse on any lookup. For CacheControl, it seems feasible that you'd need to check for various directives. You could do so once in a single for dir in cc.iter(), but subsequent ones would repeat all the work.


I think I'm leaning towards the Set of Fields option.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions