Skip to content

Commit 11b0cda

Browse files
committed
feat: add copy on write support to CEL definition types
1 parent 95d52ee commit 11b0cda

File tree

5 files changed

+151
-122
lines changed

5 files changed

+151
-122
lines changed

packages/ic-http-certification/README.md

+29-25
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ let cel_expr = create_cel_expr(&certification);
2929

3030
### Using the CEL builder
3131

32-
The CEL builder interface is provided to ease the creation of CEL expressions through an ergonmic interface. If this interface does not meet your needs, you can also [create CEL expressions directly](#directly-creating-a-cel-expression). To define a CEL expression, start with [DefaultCelBuilder]. This struct provides a set of methods that can be used to define how your request and response pair should be certified.
32+
The CEL builder interface is provided to ease the creation of CEL expressions through an ergonmic interface. If this interface does not meet your needs, you can also [create CEL expressions directly](#directly-creating-a-cel-expression). To define a CEL expression, start with `DefaultCelBuilder`. This struct provides a set of methods that can be used to define how your request and response pair should be certified.
3333

34-
When certifying requests, the request body and method are always certified. To additionally certify request headers and query parameters, use `with_request_headers` and `with_request_query_parameters` respectively. Both methods take a [str] slice as an argument.
34+
When certifying requests, the request body and method are always certified. To additionally certify request headers and query parameters, use `with_request_headers` and `with_request_query_parameters` respectively. Both methods take a `str` slice as an argument.
3535

36-
When certifying a response, the response body and status code are always certified. To additionally certify response headers, use `with_response_certification`. This method takes the `DefaultResponseCertification` enum as an argument. To specify header inclusions, use the `CertifiedResponseHeaders` variant of the `DefaultResponseCertification` enum. Or to certify all response headers, with some exclusions, use the `ResponseHeaderExclusions` variant of the `DefaultResponseCertification` enum. Both variants take a [str] slice as an argument.
36+
When certifying a response, the response body and status code are always certified. To additionally certify response headers, use `with_response_certification`. This method takes the `DefaultResponseCertification` enum as an argument. To specify header inclusions, use the `certified_response_headers` function of the `DefaultResponseCertification` enum. Or to certify all response headers, with some exclusions, use the `response_header_exclusions` function of the `DefaultResponseCertification` enum. Both functions take a `str` slice as an argument.
3737

3838
#### Fully certified request / response pair
3939

@@ -45,7 +45,7 @@ use ic_http_certification::{DefaultCelBuilder, DefaultResponseCertification};
4545
let cel_expr = DefaultCelBuilder::full_certification()
4646
.with_request_headers(&["Accept", "Accept-Encoding", "If-Match"])
4747
.with_request_query_parameters(&["foo", "bar", "baz"])
48-
.with_response_certification(DefaultResponseCertification::CertifiedResponseHeaders(&[
48+
.with_response_certification(DefaultResponseCertification::certified_response_headers(&[
4949
"Cache-Control",
5050
"ETag",
5151
]))
@@ -62,7 +62,7 @@ For example, to certify only the request body and method:
6262
use ic_http_certification::{DefaultCelBuilder, DefaultResponseCertification};
6363

6464
let cel_expr = DefaultCelBuilder::full_certification()
65-
.with_response_certification(DefaultResponseCertification::CertifiedResponseHeaders(&[
65+
.with_response_certification(DefaultResponseCertification::certified_response_headers(&[
6666
"Cache-Control",
6767
"ETag",
6868
]))
@@ -77,7 +77,7 @@ use ic_http_certification::{DefaultCelBuilder, DefaultResponseCertification};
7777
let cel_expr = DefaultCelBuilder::full_certification()
7878
.with_request_headers(&[])
7979
.with_request_query_parameters(&[])
80-
.with_response_certification(DefaultResponseCertification::CertifiedResponseHeaders(&[
80+
.with_response_certification(DefaultResponseCertification::certified_response_headers(&[
8181
"Cache-Control",
8282
"ETag",
8383
]))
@@ -92,7 +92,7 @@ Request certification can be skipped entirely by using `DefaultCelBuilder::respo
9292
use ic_http_certification::{DefaultCelBuilder, DefaultResponseCertification};
9393

9494
let cel_expr = DefaultCelBuilder::response_certification()
95-
.with_response_certification(DefaultResponseCertification::ResponseHeaderExclusions(&[
95+
.with_response_certification(DefaultResponseCertification::response_header_exclusions(&[
9696
"Date",
9797
"Cookie",
9898
"Set-Cookie",
@@ -102,7 +102,7 @@ let cel_expr = DefaultCelBuilder::response_certification()
102102

103103
#### Partially certified response
104104

105-
Similiarly to request certification, any number of response headers can be provided via the `CertifiedResponseHeaders` variant of the `DefaultResponseCertification` enum when calling `with_response_certification`. The provided array can also be an empty. If the array is empty, or the method is not called, then no response headers will be certified.
105+
Similiarly to request certification, any number of response headers can be provided via the `certified_response_headers` function of the `DefaultResponseCertification` enum when calling `with_response_certification`. The provided array can also be an empty. If the array is empty, or the method is not called, then no response headers will be certified.
106106

107107
For example, to certify only the response body and status code:
108108

@@ -118,7 +118,7 @@ This can also be done more explicitly:
118118
use ic_http_certification::{DefaultCelBuilder, DefaultResponseCertification};
119119

120120
let cel_expr = DefaultCelBuilder::response_certification()
121-
.with_response_certification(DefaultResponseCertification::CertifiedResponseHeaders(&[]))
121+
.with_response_certification(DefaultResponseCertification::certified_response_headers(&[]))
122122
.build();
123123
```
124124

@@ -155,7 +155,7 @@ To define a CEL expression, start with the `CelExpression` enum. This enum provi
155155

156156
When certifying requests, the request body and method are always certified. To additionally certify request headers and query parameters, use the `headers` and `query_paramters` of `DefaultRequestCertification` struct. Both properties take a `str` slice as an argument.
157157

158-
When certifying a response, the response body and status code are always certified. To additionally certify response headers, use the `CertifiedResponseHeaders` variant of the `DefaultResponseCertification` enum. Or to certify all response headers, with some exclusions, use the `ResponseHeaderExclusions` variant of the `DefaultResponseCertification` enum. Both variants take a `str` slice as an argument.
158+
When certifying a response, the response body and status code are always certified. To additionally certify response headers, use the `certified_response_headers` function of the `DefaultResponseCertification` enum. Or to certify all response headers, with some exclusions, use the `response_header_exclusions` function of the `DefaultResponseCertification` enum. Both functions take a `str` slice as an argument.
159159

160160
Note that the example CEL expressions provided below are formatted for readability. The actual CEL expressions produced by `CelExpression::to_string` and `create_cel_expr` are minified. The minified CEL expression is preferred because it is more compact, resulting in a smaller payload and a faster evaluation time for the HTTP Gateway that is verifying the certification, but the formatted versions are also accepted.
161161

@@ -164,14 +164,15 @@ Note that the example CEL expressions provided below are formatted for readabili
164164
To define a fully certified request and response pair, including request headers, query parameters, and response headers:
165165

166166
```rust
167+
use std::borrow::Cow;
167168
use ic_http_certification::cel::{CelExpression, DefaultCertification, DefaultRequestCertification, DefaultResponseCertification};
168169

169170
let cel_expr = CelExpression::DefaultCertification(Some(DefaultCertification {
170171
request_certification: Some(DefaultRequestCertification {
171-
headers: &["Accept", "Accept-Encoding", "If-Match"],
172-
query_parameters: &["foo", "bar", "baz"],
172+
headers: Cow::Borrowed(&["Accept", "Accept-Encoding", "If-Match"]),
173+
query_parameters: Cow::Borrowed(&["foo", "bar", "baz"]),
173174
}),
174-
response_certification: DefaultResponseCertification::CertifiedResponseHeaders(&[
175+
response_certification: DefaultResponseCertification::certified_response_headers(&[
175176
"ETag",
176177
"Cache-Control",
177178
]),
@@ -206,14 +207,15 @@ Any number of request headers or query parameters can be provided via the `heade
206207
For example, to certify only the request body and method:
207208

208209
```rust
210+
use std::borrow::Cow;
209211
use ic_http_certification::cel::{CelExpression, DefaultCertification, DefaultRequestCertification, DefaultResponseCertification};
210212

211213
let cel_expr = CelExpression::DefaultCertification(Some(DefaultCertification {
212214
request_certification: Some(DefaultRequestCertification {
213-
headers: &[],
214-
query_parameters: &[],
215+
headers: Cow::Borrowed(&["Accept", "Accept-Encoding", "If-Match"]),
216+
query_parameters: Cow::Borrowed(&["foo", "bar", "baz"]),
215217
}),
216-
response_certification: DefaultResponseCertification::CertifiedResponseHeaders(&[
218+
response_certification: DefaultResponseCertification::certified_response_headers(&[
217219
"ETag",
218220
"Cache-Control",
219221
]),
@@ -250,7 +252,7 @@ use ic_http_certification::cel::{CelExpression, DefaultCertification, DefaultRes
250252

251253
let cel_expr = CelExpression::DefaultCertification(Some(DefaultCertification {
252254
request_certification: None,
253-
response_certification: DefaultResponseCertification::CertifiedResponseHeaders(&[
255+
response_certification: DefaultResponseCertification::certified_response_headers(&[
254256
"ETag",
255257
"Cache-Control",
256258
]),
@@ -277,17 +279,18 @@ default_certification (
277279

278280
#### Partially certified response
279281

280-
Similiarly to request certification, any number of response headers can be provided via the `CertifiedResponseHeaders` variant of the `DefaultResponseCertification` enum, and it can also be an empty array. If the array is empty, no response headers will be certified. For example:
282+
Similiarly to request certification, any number of response headers can be provided via the `certified_response_headers` variant of the `DefaultResponseCertification` enum, and it can also be an empty array. If the array is empty, no response headers will be certified. For example:
281283

282284
```rust
285+
use std::borrow::Cow;
283286
use ic_http_certification::cel::{CelExpression, DefaultCertification, DefaultRequestCertification, DefaultResponseCertification};
284287

285288
let cel_expr = CelExpression::DefaultCertification(Some(DefaultCertification {
286289
request_certification: Some(DefaultRequestCertification {
287-
headers: &["Accept", "Accept-Encoding", "If-Match"],
288-
query_parameters: &["foo", "bar", "baz"],
290+
headers: Cow::Borrowed(&["Accept", "Accept-Encoding", "If-Match"]),
291+
query_parameters: Cow::Borrowed(&["foo", "bar", "baz"]),
289292
}),
290-
response_certification: DefaultResponseCertification::CertifiedResponseHeaders(&[]),
293+
response_certification: DefaultResponseCertification::certified_response_headers(&[]),
291294
}));
292295
```
293296

@@ -309,17 +312,18 @@ default_certification (
309312
)
310313
```
311314

312-
If the `ResponseHeaderExclusions` variant is used, an empty array will certify _all_ response headers. For example:
315+
If the `response_header_exclusions` function is used, an empty array will certify _all_ response headers. For example:
313316

314317
```rust
318+
use std::borrow::Cow;
315319
use ic_http_certification::cel::{CelExpression, DefaultCertification, DefaultRequestCertification, DefaultResponseCertification};
316320

317321
let cel_expr = CelExpression::DefaultCertification(Some(DefaultCertification {
318322
request_certification: Some(DefaultRequestCertification {
319-
headers: &["Accept", "Accept-Encoding", "If-Match"],
320-
query_parameters: &["foo", "bar", "baz"],
323+
headers: Cow::Borrowed(&["Accept", "Accept-Encoding", "If-Match"]),
324+
query_parameters: Cow::Borrowed(&["foo", "bar", "baz"]),
321325
}),
322-
response_certification: DefaultResponseCertification::ResponseHeaderExclusions(&[]),
326+
response_certification: DefaultResponseCertification::response_header_exclusions(&[]),
323327
}));
324328
```
325329

packages/ic-http-certification/src/cel/cel_builder.rs

+48-47
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use super::{
22
CelExpression, DefaultCertification, DefaultRequestCertification, DefaultResponseCertification,
33
};
4+
use std::borrow::Cow;
45

56
/// A CEL expression builder for creating a default certification expression.
67
#[derive(Debug, Clone)]
@@ -104,8 +105,8 @@ impl<'a> DefaultFullCelExpressionBuilder<'a> {
104105
/// Build the CEL expression, consuming the builder.
105106
pub fn build(self) -> CelExpression<'a> {
106107
let request_certification = Some(DefaultRequestCertification {
107-
headers: self.request_headers,
108-
query_parameters: self.request_query_parameters,
108+
headers: Cow::Borrowed(self.request_headers),
109+
query_parameters: Cow::Borrowed(self.request_query_parameters),
109110
});
110111

111112
CelExpression::DefaultCertification(Some(DefaultCertification {
@@ -131,13 +132,15 @@ mod tests {
131132
#[rstest]
132133
fn no_request_response_inclusions(no_request_response_inclusions_cel: String) {
133134
let cel_expr = DefaultCelBuilder::response_certification()
134-
.with_response_certification(DefaultResponseCertification::CertifiedResponseHeaders(&[
135-
"Cache-Control",
136-
"ETag",
137-
"Content-Length",
138-
"Content-Type",
139-
"Content-Encoding",
140-
]))
135+
.with_response_certification(DefaultResponseCertification::certified_response_headers(
136+
&[
137+
"Cache-Control",
138+
"ETag",
139+
"Content-Length",
140+
"Content-Type",
141+
"Content-Encoding",
142+
],
143+
))
141144
.build()
142145
.to_string();
143146

@@ -147,11 +150,9 @@ mod tests {
147150
#[rstest]
148151
fn no_request_response_exclusions(no_request_response_exclusions_cel: String) {
149152
let cel_expr = DefaultCelBuilder::response_certification()
150-
.with_response_certification(DefaultResponseCertification::ResponseHeaderExclusions(&[
151-
"Date",
152-
"Cookie",
153-
"Set-Cookie",
154-
]))
153+
.with_response_certification(DefaultResponseCertification::response_header_exclusions(
154+
&["Date", "Cookie", "Set-Cookie"],
155+
))
155156
.build()
156157
.to_string();
157158

@@ -164,9 +165,9 @@ mod tests {
164165
.build()
165166
.to_string();
166167
let explicit_cel_expr = DefaultCelBuilder::response_certification()
167-
.with_response_certification(
168-
DefaultResponseCertification::CertifiedResponseHeaders(&[]),
169-
)
168+
.with_response_certification(DefaultResponseCertification::certified_response_headers(
169+
&[],
170+
))
170171
.build()
171172
.to_string();
172173
let default_cel_expr = DefaultCelBuilder::response_certification()
@@ -182,9 +183,9 @@ mod tests {
182183
#[rstest]
183184
fn no_request_empty_response_exclusions(no_request_empty_response_exclusions_cel: String) {
184185
let cel_expr = DefaultCelBuilder::response_certification()
185-
.with_response_certification(
186-
DefaultResponseCertification::ResponseHeaderExclusions(&[]),
187-
)
186+
.with_response_certification(DefaultResponseCertification::response_header_exclusions(
187+
&[],
188+
))
188189
.build()
189190
.to_string();
190191

@@ -198,13 +199,15 @@ mod tests {
198199
let cel_expr = DefaultCelBuilder::full_certification()
199200
.with_request_headers(&["Accept", "Accept-Encoding", "If-Match"])
200201
.with_request_query_parameters(&["foo", "bar", "baz"])
201-
.with_response_certification(DefaultResponseCertification::CertifiedResponseHeaders(&[
202-
"Cache-Control",
203-
"ETag",
204-
"Content-Length",
205-
"Content-Type",
206-
"Content-Encoding",
207-
]))
202+
.with_response_certification(DefaultResponseCertification::certified_response_headers(
203+
&[
204+
"Cache-Control",
205+
"ETag",
206+
"Content-Length",
207+
"Content-Type",
208+
"Content-Encoding",
209+
],
210+
))
208211
.build()
209212
.to_string();
210213

@@ -218,11 +221,9 @@ mod tests {
218221
let cel_expr = DefaultCelBuilder::full_certification()
219222
.with_request_headers(&["Accept", "Accept-Encoding", "If-Match"])
220223
.with_request_query_parameters(&["foo", "bar", "baz"])
221-
.with_response_certification(DefaultResponseCertification::ResponseHeaderExclusions(&[
222-
"Date",
223-
"Cookie",
224-
"Set-Cookie",
225-
]))
224+
.with_response_certification(DefaultResponseCertification::response_header_exclusions(
225+
&["Date", "Cookie", "Set-Cookie"],
226+
))
226227
.build()
227228
.to_string();
228229

@@ -241,9 +242,9 @@ mod tests {
241242
let explicit_cel_expr = DefaultCelBuilder::full_certification()
242243
.with_request_headers(&["Accept", "Accept-Encoding", "If-Match"])
243244
.with_request_query_parameters(&["foo", "bar", "baz"])
244-
.with_response_certification(
245-
DefaultResponseCertification::CertifiedResponseHeaders(&[]),
246-
)
245+
.with_response_certification(DefaultResponseCertification::certified_response_headers(
246+
&[],
247+
))
247248
.build()
248249
.to_string();
249250
let default_cel_expr = DefaultCelBuilder::full_certification()
@@ -274,9 +275,9 @@ mod tests {
274275
let cel_expr = DefaultCelBuilder::full_certification()
275276
.with_request_headers(&["Accept", "Accept-Encoding", "If-Match"])
276277
.with_request_query_parameters(&["foo", "bar", "baz"])
277-
.with_response_certification(
278-
DefaultResponseCertification::ResponseHeaderExclusions(&[]),
279-
)
278+
.with_response_certification(DefaultResponseCertification::response_header_exclusions(
279+
&[],
280+
))
280281
.build()
281282
.to_string();
282283

@@ -289,9 +290,9 @@ mod tests {
289290
let explicit_cel_expr = DefaultCelBuilder::full_certification()
290291
.with_request_headers(&[])
291292
.with_request_query_parameters(&[])
292-
.with_response_certification(
293-
DefaultResponseCertification::CertifiedResponseHeaders(&[]),
294-
)
293+
.with_response_certification(DefaultResponseCertification::certified_response_headers(
294+
&[],
295+
))
295296
.build()
296297
.to_string();
297298
let default_cel_expr = DefaultCelBuilder::full_certification()
@@ -309,17 +310,17 @@ mod tests {
309310
#[rstest]
310311
fn empty_request_response_exclusions(empty_request_response_exclusions_cel: String) {
311312
let implicit_cel_expr = DefaultCelBuilder::full_certification()
312-
.with_response_certification(
313-
DefaultResponseCertification::ResponseHeaderExclusions(&[]),
314-
)
313+
.with_response_certification(DefaultResponseCertification::response_header_exclusions(
314+
&[],
315+
))
315316
.build()
316317
.to_string();
317318
let explicit_cel_expr = DefaultCelBuilder::full_certification()
318319
.with_request_headers(&[])
319320
.with_request_query_parameters(&[])
320-
.with_response_certification(
321-
DefaultResponseCertification::ResponseHeaderExclusions(&[]),
322-
)
321+
.with_response_certification(DefaultResponseCertification::response_header_exclusions(
322+
&[],
323+
))
323324
.build()
324325
.to_string();
325326

0 commit comments

Comments
 (0)