Repository: servo/servo
File: components/script/dom/trustedtypepolicyfactory.rs (Rust)

Code before:

impl TrustedTypePolicyFactory {
    fn new_inherited() -> Self {
        Self {
            reflector_: Reflector::new(),
            default_policy: Default::default(),
            policy_names: RefCell::new(vec![]),
        }
    }

    #[cfg_attr(crown, allow(crown::unrooted_must_root))]
    pub(crate) fn new(global: &GlobalScope, can_gc: CanGc) -> DomRoot<Self> {
        reflect_dom_object(Box::new(Self::new_inherited()), global, can_gc)
    }

    /// <https://www.w3.org/TR/trusted-types/#create-trusted-type-policy-algorithm>
    fn create_trusted_type_policy(
        &self,
        policy_name: String,
        options: &TrustedTypePolicyOptions,
        global: &GlobalScope,
        can_gc: CanGc,
    ) -> Fallible<DomRoot<TrustedTypePolicy>> {
        // Step 1: Let allowedByCSP be the result of executing Should Trusted Type policy creation be blocked by
        // Content Security Policy? algorithm with global, policyName and factory’s created policy names value.
        let policy_names = self.policy_names.borrow();
        let policy_names: Vec<&str> = policy_names.iter().map(String::as_ref).collect();
        let allowed_by_csp = global
            .get_csp_list()
            .is_trusted_type_policy_creation_allowed(global, &policy_name, &policy_names);

        // Step 2: If allowedByCSP is "Blocked", throw a TypeError and abort further steps.
        if !allowed_by_csp {
            return Err(Error::Type("Not allowed by CSP".to_string()));
        }

        // Step 3: If policyName is default and the factory’s default policy value is not null, throw a TypeError
        // and abort further steps.
        if policy_name == "default" && self.default_policy.get().is_some() {
            return Err(Error::Type(
                "Already set default policy for factory".to_string(),
            ));
        }

        // Step 4: Let policy be a new TrustedTypePolicy object.
        // Step 5: Set policy’s name property value to policyName.
        // Step 6: Set policy’s options value to «[ "createHTML" ->
        // options["createHTML", "createScript" -> options["createScript",
        // "createScriptURL" -> options["createScriptURL" ]».
        let policy = TrustedTypePolicy::new(policy_name.clone(), options, global, can_gc);
        // Step 7: If the policyName is default, set the factory’s default policy value to policy.

Review comment (suggestion):
Whoops, this borrow is still active when we do `self.policy_names.borrow_mut().push(policy_name);` later.

Code after:

impl TrustedTypePolicyFactory {
    fn new_inherited() -> Self {
        Self {
            reflector_: Reflector::new(),
            default_policy: Default::default(),
            policy_names: RefCell::new(vec![]),
        }
    }

    #[cfg_attr(crown, allow(crown::unrooted_must_root))]
    pub(crate) fn new(global: &GlobalScope, can_gc: CanGc) -> DomRoot<Self> {
        reflect_dom_object(Box::new(Self::new_inherited()), global, can_gc)
    }

    /// <https://www.w3.org/TR/trusted-types/#create-trusted-type-policy-algorithm>
    fn create_trusted_type_policy(
        &self,
        policy_name: String,
        options: &TrustedTypePolicyOptions,
        global: &GlobalScope,
        can_gc: CanGc,
    ) -> Fallible<DomRoot<TrustedTypePolicy>> {
        // Avoid double borrow on policy_names
        {
            // Step 1: Let allowedByCSP be the result of executing Should Trusted Type policy creation be blocked by
            // Content Security Policy? algorithm with global, policyName and factory’s created policy names value.
            let policy_names = self.policy_names.borrow();
            let policy_names: Vec<&str> = policy_names.iter().map(String::as_ref).collect();
            let allowed_by_csp = global
                .get_csp_list()
                .is_trusted_type_policy_creation_allowed(global, &policy_name, &policy_names);

            // Step 2: If allowedByCSP is "Blocked", throw a TypeError and abort further steps.
            if !allowed_by_csp {
                return Err(Error::Type("Not allowed by CSP".to_string()));
            }
        }

        // Step 3: If policyName is default and the factory’s default policy value is not null, throw a TypeError
        // and abort further steps.
        if policy_name == "default" && self.default_policy.get().is_some() {
            return Err(Error::Type(
                "Already set default policy for factory".to_string(),
            ));
        }

        // Step 4: Let policy be a new TrustedTypePolicy object.
        // Step 5: Set policy’s name property value to policyName.
        // Step 6: Set policy’s options value to «[ "createHTML" ->
        // options["createHTML", "createScript" -> options["createScript",