pdk_core/host/context/
root.rs

1// Copyright (c) 2025, Salesforce, Inc.,
2// All rights reserved.
3// For full license text, see the LICENSE.txt file
4
5//! Middleware to fix missing metadata propagation in the root context.
6
7use crate::host::context::http::HttpContextAdapter;
8use crate::host::property::PropertyAccessor;
9use crate::policy_context::metadata::{read_api_name_from_plugin_name, PolicyMetadata};
10use crate::policy_context::static_policy_context_cache::StaticPolicyContextCache;
11use classy::proxy_wasm::traits::{Context, HttpContext, RootContext};
12use classy::proxy_wasm::types::ContextType;
13use std::rc::Rc;
14
15/// Adapter to enrich the root context with policy metadata.
16pub struct RootContextAdapter {
17    root_context: Box<dyn RootContext>,
18    policy_metadata: Rc<PolicyMetadata>,
19    plugin_name_api_id: Rc<String>,
20}
21
22impl RootContextAdapter {
23    pub fn new(context: Box<dyn RootContext>) -> Self {
24        let property_accessor = <dyn PropertyAccessor>::default();
25
26        Self {
27            root_context: context,
28            policy_metadata: Rc::new(PolicyMetadata::from(property_accessor)),
29            plugin_name_api_id: Rc::new(read_api_name_from_plugin_name(property_accessor)),
30        }
31    }
32
33    pub fn boxed(self) -> Box<dyn RootContext> {
34        Box::new(self)
35    }
36
37    fn fix_current_context(&self) {
38        StaticPolicyContextCache::fix_metadata(&self.policy_metadata);
39        StaticPolicyContextCache::fix_plugin_name_api_id(&self.plugin_name_api_id);
40    }
41}
42
43impl Context for RootContextAdapter {
44    fn on_http_call_response(
45        &mut self,
46        token_id: u32,
47        num_headers: usize,
48        body_size: usize,
49        num_trailers: usize,
50    ) {
51        self.fix_current_context();
52        self.root_context
53            .on_http_call_response(token_id, num_headers, body_size, num_trailers)
54    }
55
56    fn on_grpc_call_response(&mut self, token_id: u32, status_code: u32, response_size: usize) {
57        self.fix_current_context();
58        self.root_context
59            .on_grpc_call_response(token_id, status_code, response_size)
60    }
61
62    fn on_done(&mut self) -> bool {
63        self.fix_current_context();
64        self.root_context.on_done()
65    }
66}
67
68impl RootContext for RootContextAdapter {
69    fn on_configure(&mut self, plugin_configuration_size: usize) -> bool {
70        self.fix_current_context();
71        self.root_context.on_configure(plugin_configuration_size)
72    }
73
74    fn create_http_context(&self, context_id: u32) -> Option<Box<dyn HttpContext>> {
75        self.fix_current_context();
76        self.root_context
77            .create_http_context(context_id)
78            .map(|ctx| {
79                HttpContextAdapter::new(
80                    ctx,
81                    Rc::clone(&self.policy_metadata),
82                    Rc::clone(&self.plugin_name_api_id),
83                )
84                .boxed()
85            })
86    }
87
88    fn get_type(&self) -> Option<ContextType> {
89        self.root_context.get_type()
90    }
91
92    fn on_tick(&mut self) {
93        self.root_context.on_tick();
94    }
95}