Skip to content

Commit 7de2acd

Browse files
authored
Allow RootContext to create child contexts for streams. (#34)
Fixes #6. Signed-off-by: Daniel Grimm <dgrimm@redhat.com>
1 parent 9d31236 commit 7de2acd

File tree

7 files changed

+161
-29
lines changed

7 files changed

+161
-29
lines changed

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,8 @@ crate-type = ["cdylib"]
6060
name = "http_body"
6161
path = "examples/http_body.rs"
6262
crate-type = ["cdylib"]
63+
64+
[[example]]
65+
name = "http_config"
66+
path = "examples/http_config.rs"
67+
crate-type = ["cdylib"]

examples/http_body.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,21 @@ use proxy_wasm::types::*;
1818
#[no_mangle]
1919
pub fn _start() {
2020
proxy_wasm::set_log_level(LogLevel::Trace);
21-
proxy_wasm::set_http_context(|_, _| -> Box<dyn HttpContext> { Box::new(HttpBody) });
21+
proxy_wasm::set_root_context(|_| -> Box<dyn RootContext> { Box::new(HttpBodyRoot) });
22+
}
23+
24+
struct HttpBodyRoot;
25+
26+
impl Context for HttpBodyRoot {}
27+
28+
impl RootContext for HttpBodyRoot {
29+
fn get_type(&self) -> Option<ContextType> {
30+
Some(ContextType::HttpContext)
31+
}
32+
33+
fn create_http_context(&self, _context_id: u32) -> Option<Box<dyn HttpContext>> {
34+
Some(Box::new(HttpBody))
35+
}
2236
}
2337

2438
struct HttpBody;

examples/http_config.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright 2020 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
use proxy_wasm::traits::*;
16+
use proxy_wasm::types::*;
17+
18+
#[no_mangle]
19+
pub fn _start() {
20+
proxy_wasm::set_log_level(LogLevel::Trace);
21+
proxy_wasm::set_root_context(|_| -> Box<dyn RootContext> {
22+
Box::new(HttpConfigHeaderRoot {
23+
header_content: String::new(),
24+
})
25+
});
26+
}
27+
28+
struct HttpConfigHeader {
29+
header_content: String,
30+
}
31+
32+
impl Context for HttpConfigHeader {}
33+
34+
impl HttpContext for HttpConfigHeader {
35+
fn on_http_response_headers(&mut self, _num_headers: usize) -> Action {
36+
self.add_http_response_header("custom-header", self.header_content.as_str());
37+
Action::Continue
38+
}
39+
}
40+
41+
struct HttpConfigHeaderRoot {
42+
header_content: String,
43+
}
44+
45+
impl Context for HttpConfigHeaderRoot {}
46+
47+
impl RootContext for HttpConfigHeaderRoot {
48+
fn on_configure(&mut self, _plugin_configuration_size: usize) -> bool {
49+
if let Some(config_bytes) = self.get_configuration() {
50+
self.header_content = String::from_utf8(config_bytes).unwrap()
51+
}
52+
true
53+
}
54+
55+
fn create_http_context(&self, _context_id: u32) -> Option<Box<dyn HttpContext>> {
56+
Some(Box::new(HttpConfigHeader {
57+
header_content: self.header_content.clone(),
58+
}))
59+
}
60+
61+
fn get_type(&self) -> Option<ContextType> {
62+
Some(ContextType::HttpContext)
63+
}
64+
}

examples/http_headers.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,23 @@ use proxy_wasm::types::*;
1919
#[no_mangle]
2020
pub fn _start() {
2121
proxy_wasm::set_log_level(LogLevel::Trace);
22-
proxy_wasm::set_http_context(|context_id, _| -> Box<dyn HttpContext> {
23-
Box::new(HttpHeaders { context_id })
24-
});
22+
proxy_wasm::set_root_context(|_| -> Box<dyn RootContext> { Box::new(HttpHeadersRoot) });
23+
}
24+
25+
struct HttpHeadersRoot;
26+
27+
impl Context for HttpHeadersRoot {}
28+
29+
impl RootContext for HttpHeadersRoot {
30+
fn get_type(&self) -> Option<ContextType> {
31+
Some(ContextType::HttpContext)
32+
}
33+
34+
fn create_http_context(&self, _context_id: u32) -> Option<Box<dyn HttpContext>> {
35+
Some(Box::new(HttpHeaders {
36+
context_id: _context_id,
37+
}))
38+
}
2539
}
2640

2741
struct HttpHeaders {

src/dispatcher.rs

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,17 @@ impl Dispatcher {
8080
self.new_http_stream.set(Some(callback));
8181
}
8282

83+
fn register_callout(&self, token_id: u32) {
84+
if self
85+
.callouts
86+
.borrow_mut()
87+
.insert(token_id, self.active_id.get())
88+
.is_some()
89+
{
90+
panic!("duplicate token_id")
91+
}
92+
}
93+
8394
fn create_root_context(&self, context_id: u32) {
8495
let new_context = match self.new_root.get() {
8596
Some(f) => f(context_id),
@@ -96,12 +107,15 @@ impl Dispatcher {
96107
}
97108

98109
fn create_stream_context(&self, context_id: u32, root_context_id: u32) {
99-
if !self.roots.borrow().contains_key(&root_context_id) {
100-
panic!("invalid root_context_id")
101-
}
102-
let new_context = match self.new_stream.get() {
103-
Some(f) => f(context_id, root_context_id),
104-
None => panic!("missing constructor"),
110+
let new_context = match self.roots.borrow().get(&root_context_id) {
111+
Some(root_context) => match self.new_stream.get() {
112+
Some(f) => f(context_id, root_context_id),
113+
None => match root_context.create_stream_context(context_id) {
114+
Some(stream_context) => stream_context,
115+
None => panic!("create_stream_context returned None"),
116+
},
117+
},
118+
None => panic!("invalid root_context_id"),
105119
};
106120
if self
107121
.streams
@@ -114,12 +128,15 @@ impl Dispatcher {
114128
}
115129

116130
fn create_http_context(&self, context_id: u32, root_context_id: u32) {
117-
if !self.roots.borrow().contains_key(&root_context_id) {
118-
panic!("invalid root_context_id")
119-
}
120-
let new_context = match self.new_http_stream.get() {
121-
Some(f) => f(context_id, root_context_id),
122-
None => panic!("missing constructor"),
131+
let new_context = match self.roots.borrow().get(&root_context_id) {
132+
Some(root_context) => match self.new_http_stream.get() {
133+
Some(f) => f(context_id, root_context_id),
134+
None => match root_context.create_http_context(context_id) {
135+
Some(stream_context) => stream_context,
136+
None => panic!("create_http_context returned None"),
137+
},
138+
},
139+
None => panic!("invalid root_context_id"),
123140
};
124141
if self
125142
.http_streams
@@ -131,26 +148,25 @@ impl Dispatcher {
131148
}
132149
}
133150

134-
fn register_callout(&self, token_id: u32) {
135-
if self
136-
.callouts
137-
.borrow_mut()
138-
.insert(token_id, self.active_id.get())
139-
.is_some()
140-
{
141-
panic!("duplicate token_id")
142-
}
143-
}
144-
145151
fn on_create_context(&self, context_id: u32, root_context_id: u32) {
146152
if root_context_id == 0 {
147-
self.create_root_context(context_id)
153+
self.create_root_context(context_id);
148154
} else if self.new_http_stream.get().is_some() {
149155
self.create_http_context(context_id, root_context_id);
150156
} else if self.new_stream.get().is_some() {
151157
self.create_stream_context(context_id, root_context_id);
158+
} else if let Some(root_context) = self.roots.borrow().get(&root_context_id) {
159+
match root_context.get_type() {
160+
Some(ContextType::HttpContext) => {
161+
self.create_http_context(context_id, root_context_id)
162+
}
163+
Some(ContextType::StreamContext) => {
164+
self.create_stream_context(context_id, root_context_id)
165+
}
166+
None => panic!("missing ContextType on root_context"),
167+
}
152168
} else {
153-
panic!("missing constructors")
169+
panic!("invalid root_context_id and missing constructors");
154170
}
155171
}
156172

src/traits.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,18 @@ pub trait RootContext: Context {
121121
fn on_queue_ready(&mut self, _queue_id: u32) {}
122122

123123
fn on_log(&mut self) {}
124+
125+
fn create_http_context(&self, _context_id: u32) -> Option<Box<dyn HttpContext>> {
126+
None
127+
}
128+
129+
fn create_stream_context(&self, _context_id: u32) -> Option<Box<dyn StreamContext>> {
130+
None
131+
}
132+
133+
fn get_type(&self) -> Option<ContextType> {
134+
None
135+
}
124136
}
125137

126138
pub trait StreamContext: Context {

src/types.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ pub enum Status {
4747
InternalFailure = 10,
4848
}
4949

50+
#[repr(u32)]
51+
#[derive(Debug)]
52+
pub enum ContextType {
53+
HttpContext = 0,
54+
StreamContext = 1,
55+
}
56+
5057
#[repr(u32)]
5158
#[derive(Debug)]
5259
pub enum BufferType {

0 commit comments

Comments
 (0)