GithubHelp home page GithubHelp logo

Comments (4)

SergioBenitez avatar SergioBenitez commented on May 28, 2024

Note that this RFC is the current active draft. I agree it would be nice to support this. I don't think a new constructor is quite what we want, however. Maybe we want a Prefix enum that works a bit like SameSite. I'd be open to reviewing such a design.

I would suggest starting purely with the design (i.e, a set of interface changes and desired semantics) and then we can talk about implementation.

from cookie-rs.

jakajancar avatar jakajancar commented on May 28, 2024

Iā€™m not actually sure what a good API is. You probably also want name() to still equal the actual name of the cookie, incl. the prefix, so having prefix as completely separate (vs. just a convenience constructor/setter) is not a good idea.

from cookie-rs.

SergioBenitez avatar SergioBenitez commented on May 28, 2024

Thinking about it more, I think the API we want is that of a prefixed child jar. This means we get the following API:

let mut jar: CookieJar; // some cookie jar
jar.prefixed(Host).add(Cookie::new("foo", "bar")); // prefix the name, set the required values, add to jar
jar.prefixed(Host).get("foo") // => cookie with ("foo", "bar")
jar.get("foo") // => cookie with ("__HOST-foo", "bar")

Here's an implementation (that I haven't tested or checked through thoroughly, at all):

use std::marker::PhantomData;
use std::borrow::{Borrow, BorrowMut, Cow};

use crate::{CookieJar, Cookie};

mod private {
    pub trait Sealed {}

    impl Sealed for super::Host {}
    impl Sealed for super::Secure {}
}

pub struct Host;

impl Prefix for Host {
    const PREFIX: &'static str = "__HOST-";

    fn polish(mut cookie: Cookie<'_>) -> Cookie<'_> {
        cookie.set_secure(true);
        cookie.set_path("/");
        cookie.unset_domain();
        cookie
    }
}

pub struct Secure;

impl Prefix for Secure {
    const PREFIX: &'static str = "__SECURE-";

    fn polish(mut cookie: Cookie<'_>) -> Cookie<'_> {
        cookie.set_secure(true);
        cookie
    }
}

pub trait Prefix: private::Sealed {
    #[doc(hidden)]
    const PREFIX: &'static str;

    fn polish(cookie: Cookie<'_>) -> Cookie<'_>;

    #[doc(hidden)]
    fn prefixed_name(name: &str) -> String {
        format!("{}{name}", Self::PREFIX)
    }

    #[doc(hidden)]
    fn prefix(mut cookie: Cookie<'_>) -> Cookie<'_> {
        use crate::CookieStr;

        cookie.name = CookieStr::Concrete(match cookie.name {
            CookieStr::Concrete(Cow::Owned(mut string)) => {
                string.insert_str(0, Self::PREFIX);
                string.into()
            }
            _ => Self::prefixed_name(cookie.name()).into(),
        });

        cookie
    }

    #[doc(hidden)]
    fn clip(mut cookie: Cookie<'_>) -> Cookie<'_> {
        use std::borrow::Cow::*;
        use crate::CookieStr::*;

        debug_assert!(cookie.name().starts_with(Self::PREFIX));
        if !cookie.name().starts_with(Self::PREFIX) {
            return cookie;
        }

        let len = Self::PREFIX.len();
        cookie.name = match cookie.name {
            Indexed(i, j) => Indexed(i + len, j),
            Concrete(Borrowed(v)) => Concrete(Borrowed(&v[len..])),
            Concrete(Owned(v)) => Concrete(Owned(v[len..].to_string())),
        };

        cookie
    }

    #[doc(hidden)]
    fn refine(cookie: Cookie<'_>) -> Cookie<'_> {
        Self::polish(Self::prefix(cookie))
    }
}

pub struct PrefixJar<P: Prefix, J> {
    parent: J,
    _prefix: PhantomData<P>,
}

impl<P: Prefix, J> PrefixJar<P, J> {
    pub(crate) fn new(parent: J) -> Self {
        Self { parent, _prefix: PhantomData }
    }
}

impl<P: Prefix, J: Borrow<CookieJar>> PrefixJar<P, J> {
    pub fn get(&self, name: &str) -> Option<Cookie<'static>> {
        self.parent.borrow()
            .get(&P::prefixed_name(name))
            .map(|c| P::clip(c.clone()))
    }
}

impl<P: Prefix, J: BorrowMut<CookieJar>> PrefixJar<P, J> {
    pub fn add<C: Into<Cookie<'static>>>(&mut self, cookie: C) {
        self.parent.borrow_mut().add(P::refine(cookie.into()));
    }

    pub fn add_original<C: Into<Cookie<'static>>>(&mut self, cookie: C) {
        self.parent.borrow_mut().add_original(P::refine(cookie.into()));
    }

    pub fn remove<C: Into<Cookie<'static>>>(&mut self, cookie: C) {
        self.parent.borrow_mut().remove(P::refine(cookie.into()));
    }
}

from cookie-rs.

jakajancar avatar jakajancar commented on May 28, 2024

That is very clever, I agree. Like a virtual, transparently mapped namespace.

from cookie-rs.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    šŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. šŸ“ŠšŸ“ˆšŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ā¤ļø Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.