Skip to content

Commit 7e3f70d

Browse files
authored
feat(ic-asset-certification): allow overriding asset response status code (#394)
Needs #393 to be merged first for the CI to pass
1 parent af036cd commit 7e3f70d

File tree

25 files changed

+287
-177
lines changed

25 files changed

+287
-177
lines changed

examples/http-certification/assets/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ fn certify_all_assets() {
180180
)]),
181181
fallback_for: vec![AssetFallbackConfig {
182182
scope: "/".to_string(),
183+
status_code: Some(StatusCode::OK),
183184
}],
184185
aliased_by: vec!["/".to_string()],
185186
encodings: encodings.clone(),

examples/http-certification/assets/src/backend/src/lib.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ use ic_cdk::{
55
api::{data_certificate, set_certified_data},
66
*,
77
};
8-
use ic_http_certification::{HeaderField, HttpCertificationTree, HttpRequest, HttpResponse};
8+
use ic_http_certification::{
9+
HeaderField, HttpCertificationTree, HttpRequest, HttpResponse, StatusCode,
10+
};
911
use include_dir::{include_dir, Dir};
1012
use std::{cell::RefCell, rc::Rc};
1113

@@ -69,6 +71,7 @@ fn certify_all_assets() {
6971
)]),
7072
fallback_for: vec![AssetFallbackConfig {
7173
scope: "/".to_string(),
74+
status_code: Some(StatusCode::OK),
7275
}],
7376
aliased_by: vec!["/".to_string()],
7477
encodings: encodings.clone(),

examples/http-certification/custom-assets/src/backend/src/lib.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use ic_cdk::{
55
use ic_http_certification::{
66
utils::add_v2_certificate_header, DefaultCelBuilder, DefaultResponseCertification,
77
DefaultResponseOnlyCelExpression, HeaderField, HttpCertification, HttpCertificationPath,
8-
HttpCertificationTree, HttpCertificationTreeEntry, HttpRequest, HttpResponse,
8+
HttpCertificationTree, HttpCertificationTreeEntry, HttpRequest, HttpResponse, StatusCode,
99
CERTIFICATE_EXPRESSION_HEADER_NAME,
1010
};
1111
use include_dir::{include_dir, Dir};
@@ -399,7 +399,7 @@ fn create_uncertified_response() -> HttpResponse<'static> {
399399
);
400400

401401
HttpResponse::builder()
402-
.with_status_code(200)
402+
.with_status_code(StatusCode::OK)
403403
.with_headers(headers)
404404
.with_body(body)
405405
.build()
@@ -436,7 +436,7 @@ fn create_asset_response(
436436
let headers = get_asset_headers(additional_headers, body.len(), cel_expr);
437437

438438
HttpResponse::builder()
439-
.with_status_code(200)
439+
.with_status_code(StatusCode::OK)
440440
.with_headers(headers)
441441
.with_body(body)
442442
.build()

examples/http-certification/json-api/src/backend/src/lib.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use ic_http_certification::{
66
utils::add_v2_certificate_header, DefaultCelBuilder, DefaultFullCelExpression,
77
DefaultResponseCertification, DefaultResponseOnlyCelExpression, HttpCertification,
88
HttpCertificationPath, HttpCertificationTree, HttpCertificationTreeEntry, HttpRequest,
9-
HttpResponse, CERTIFICATE_EXPRESSION_HEADER_NAME,
9+
HttpResponse, StatusCode, CERTIFICATE_EXPRESSION_HEADER_NAME,
1010
};
1111
use lazy_static::lazy_static;
1212
use matchit::{Params, Router};
@@ -176,7 +176,7 @@ fn certify_list_todos_response() {
176176
)
177177
.encode()
178178
});
179-
let mut response = create_response(200, body);
179+
let mut response = create_response(StatusCode::OK, body);
180180

181181
certify_response(request, &mut response, &TODOS_TREE_PATH);
182182
}
@@ -191,15 +191,15 @@ fn certify_not_allowed_todo_responses() {
191191
.build();
192192

193193
let body = ErrorResponse::not_allowed().encode();
194-
let mut response = create_response(405, body);
194+
let mut response = create_response(StatusCode::METHOD_NOT_ALLOWED, body);
195195

196196
certify_response(request, &mut response, &TODOS_TREE_PATH);
197197
});
198198
}
199199

200200
fn certify_not_found_response() {
201201
let body = ErrorResponse::not_found().encode();
202-
let mut response = create_response(404, body);
202+
let mut response = create_response(StatusCode::NOT_FOUND, body);
203203

204204
let tree_path = HttpCertificationPath::wildcard(NOT_FOUND_PATH);
205205

@@ -405,7 +405,7 @@ fn create_todo_item_handler(req: &HttpRequest, _params: &Params) -> HttpResponse
405405
certify_list_todos_response();
406406

407407
let body = CreateTodoItemResponse::ok(&todo_item).encode();
408-
create_response(201, body)
408+
create_response(StatusCode::CREATED, body)
409409
}
410410

411411
fn update_todo_item_handler(req: &HttpRequest, params: &Params) -> HttpResponse<'static> {
@@ -427,7 +427,7 @@ fn update_todo_item_handler(req: &HttpRequest, params: &Params) -> HttpResponse<
427427
certify_list_todos_response();
428428

429429
let body = UpdateTodoItemResponse::ok(&()).encode();
430-
create_response(200, body)
430+
create_response(StatusCode::OK, body)
431431
}
432432

433433
fn delete_todo_item_handler(_req: &HttpRequest, params: &Params) -> HttpResponse<'static> {
@@ -440,7 +440,7 @@ fn delete_todo_item_handler(_req: &HttpRequest, params: &Params) -> HttpResponse
440440
certify_list_todos_response();
441441

442442
let body = DeleteTodoItemResponse::ok(&()).encode();
443-
create_response(204, body)
443+
create_response(StatusCode::NO_CONTENT, body)
444444
}
445445

446446
fn upgrade_to_update_call_handler(
@@ -451,7 +451,7 @@ fn upgrade_to_update_call_handler(
451451
}
452452

453453
fn no_update_call_handler(_http_request: &HttpRequest, _params: &Params) -> HttpResponse<'static> {
454-
create_response(400, vec![])
454+
create_response(StatusCode::BAD_REQUEST, vec![])
455455
}
456456

457457
// Encoding
@@ -463,7 +463,7 @@ where
463463
serde_json::from_slice(value).expect("Failed to deserialize value")
464464
}
465465

466-
fn create_response(status_code: u16, body: Vec<u8>) -> HttpResponse<'static> {
466+
fn create_response(status_code: StatusCode, body: Vec<u8>) -> HttpResponse<'static> {
467467
HttpResponse::builder()
468468
.with_status_code(status_code)
469469
.with_headers(vec![

examples/http-certification/skip-certification/src/backend/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use ic_cdk::{
44
};
55
use ic_http_certification::{
66
utils::{add_skip_certification_header, skip_certification_certified_data},
7-
HttpResponse,
7+
HttpResponse, StatusCode,
88
};
99

1010
#[init]
@@ -55,7 +55,7 @@ fn create_response() -> HttpResponse<'static> {
5555
];
5656

5757
HttpResponse::builder()
58-
.with_status_code(200)
58+
.with_status_code(StatusCode::OK)
5959
.with_headers(headers)
6060
.with_body(body)
6161
.build()
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use ic_cdk::*;
2-
use ic_http_certification::{HttpResponse, HttpUpdateResponse};
2+
use ic_http_certification::{HttpResponse, HttpUpdateResponse, StatusCode};
33

44
#[query]
55
fn http_request() -> HttpResponse<'static> {
@@ -9,7 +9,7 @@ fn http_request() -> HttpResponse<'static> {
99
#[update]
1010
fn http_request_update() -> HttpUpdateResponse<'static> {
1111
HttpResponse::builder()
12-
.with_status_code(418)
12+
.with_status_code(StatusCode::IM_A_TEAPOT)
1313
.with_body(b"I'm a teapot")
1414
.build_update()
1515
}

packages/ic-asset-certification/README.md

+15-13
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ This is implemented in the following steps:
1515
2. [Configuring asset certification](#configuring-asset-certification)
1616
3. [Inserting assets into the asset router](#inserting-assets-into-the-asset-router)
1717
4. [Serving assets](#serving-assets)
18+
5. [Deleting assets](#deleting-assets)
19+
6. [Querying assets](#querying-assets)
1820

1921
For canisters that need it, it's also possible to [delete assets](#deleting-assets).
2022

@@ -167,6 +169,7 @@ on the `/index.html` path, in addition to serving as the fallback for the `/`
167169
scope and setting `/` as an alias for this asset.
168170

169171
```rust
172+
use ic_http_certification::StatusCode;
170173
use ic_asset_certification::{AssetConfig, AssetFallbackConfig};
171174

172175
let config = AssetConfig::File {
@@ -177,6 +180,7 @@ let config = AssetConfig::File {
177180
],
178181
fallback_for: vec![AssetFallbackConfig {
179182
scope: "/".to_string(),
183+
status_code: Some(StatusCode::OK),
180184
}],
181185
aliased_by: vec!["/".to_string()],
182186
encodings: vec![
@@ -206,6 +210,7 @@ Multiple aliases are also configured for this asset, namely:
206210
Requests to any of those aliases will serve the `/404.html` asset.
207211

208212
```rust
213+
use ic_http_certification::StatusCode;
209214
use ic_asset_certification::{AssetConfig, AssetFallbackConfig};
210215

211216
let config = AssetConfig::File {
@@ -217,9 +222,11 @@ let config = AssetConfig::File {
217222
fallback_for: vec![
218223
AssetFallbackConfig {
219224
scope: "/css".to_string(),
225+
status_code: Some(StatusCode::NOT_FOUND),
220226
},
221227
AssetFallbackConfig {
222228
scope: "/js".to_string(),
229+
status_code: Some(StatusCode::NOT_FOUND),
223230
},
224231
],
225232
aliased_by: vec![
@@ -269,6 +276,7 @@ For example, the following pattern will match all `.js` files in the `js`
269276
directory:
270277

271278
```rust
279+
use ic_http_certification::StatusCode;
272280
use ic_asset_certification::AssetConfig;
273281

274282
let config = AssetConfig::Pattern {
@@ -331,6 +339,7 @@ the appropriate response.
331339
Assets can be inserted using the `certify_assets` method:
332340

333341
```rust
342+
use ic_http_certification::StatusCode;
334343
use ic_asset_certification::{Asset, AssetConfig, AssetFallbackConfig, AssetRouter, AssetRedirectKind};
335344

336345
let mut asset_router = AssetRouter::default();
@@ -384,6 +393,7 @@ let asset_configs = vec![
384393
)],
385394
fallback_for: vec![AssetFallbackConfig {
386395
scope: "/".to_string(),
396+
status_code: Some(StatusCode::OK),
387397
}],
388398
aliased_by: vec!["/".to_string()],
389399
encodings: vec![
@@ -460,7 +470,7 @@ This method will return a response, a witness and an expression path, which can
460470
alongside the canister's data certificate to add the required certificate header to the response.
461471

462472
```rust
463-
use ic_http_certification::{HttpRequest, utils::add_v2_certificate_header};
473+
use ic_http_certification::{HttpRequest, utils::add_v2_certificate_header, StatusCode};
464474
use ic_asset_certification::{Asset, AssetConfig, AssetFallbackConfig, AssetRouter};
465475

466476
let mut asset_router = AssetRouter::default();
@@ -478,6 +488,7 @@ let asset_config = AssetConfig::File {
478488
],
479489
fallback_for: vec![AssetFallbackConfig {
480490
scope: "/".to_string(),
491+
status_code: Some(StatusCode::OK),
481492
}],
482493
aliased_by: vec!["/".to_string()],
483494
encodings: vec![],
@@ -522,6 +533,7 @@ only includes Brotli, then the Gzip file will not be deleted.
522533
Using the same base example used to demonstrate certifying assets:
523534

524535
```rust
536+
use ic_http_certification::StatusCode;
525537
use ic_asset_certification::{Asset, AssetConfig, AssetFallbackConfig, AssetRouter, AssetRedirectKind, AssetEncoding};
526538

527539
let mut asset_router = AssetRouter::default();
@@ -575,6 +587,7 @@ let asset_configs = vec![
575587
)],
576588
fallback_for: vec![AssetFallbackConfig {
577589
scope: "/".to_string(),
590+
status_code: Some(StatusCode::OK),
578591
}],
579592
aliased_by: vec!["/".to_string()],
580593
encodings: vec![
@@ -619,10 +632,6 @@ asset_router.certify_assets(assets, asset_configs).unwrap();
619632
To delete the `index.html` asset, along with the fallback configuration for the `/` scope, the alias `/` and the alternative encodings:
620633

621634
```rust
622-
# use ic_asset_certification::{Asset, AssetConfig, AssetFallbackConfig, AssetRouter, AssetRedirectKind, AssetEncoding};
623-
624-
# let mut asset_router = AssetRouter::default();
625-
626635
asset_router
627636
.delete_assets(
628637
vec![
@@ -642,6 +651,7 @@ asset_router
642651
)],
643652
fallback_for: vec![AssetFallbackConfig {
644653
scope: "/".to_string(),
654+
status_code: Some(StatusCode::OK),
645655
}],
646656
aliased_by: vec!["/".to_string()],
647657
encodings: vec![
@@ -656,10 +666,6 @@ asset_router
656666
To delete the `app.js` asset, along with the alternative encodings:
657667

658668
```rust
659-
# use ic_asset_certification::{Asset, AssetConfig, AssetFallbackConfig, AssetRouter, AssetRedirectKind, AssetEncoding};
660-
661-
# let mut asset_router = AssetRouter::default();
662-
663669
asset_router
664670
.delete_assets(
665671
vec![
@@ -686,10 +692,6 @@ asset_router
686692
To delete the `css/app-ba74b708.css` asset, along with the alternative encodings:
687693

688694
```rust
689-
# use ic_asset_certification::{Asset, AssetConfig, AssetFallbackConfig, AssetRouter, AssetRedirectKind, AssetEncoding};
690-
691-
# let mut asset_router = AssetRouter::default();
692-
693695
asset_router.delete_assets(
694696
vec![
695697
Asset::new(

packages/ic-asset-certification/src/asset_config.rs

+12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::{Asset, AssetCertificationError};
22
use globset::{Glob, GlobMatcher};
3+
use ic_http_certification::StatusCode;
34
use std::fmt::{Display, Formatter};
45

56
/// Certification configuration for [assets](Asset). This configuration
@@ -22,6 +23,7 @@ use std::fmt::{Display, Formatter};
2223
/// set to `text/javascript` and a `cache-control` header is added.
2324
///
2425
/// ```
26+
/// use ic_http_certification::StatusCode;
2527
/// use ic_asset_certification::{AssetConfig, AssetEncoding};
2628
///
2729
/// let config = AssetConfig::File {
@@ -48,6 +50,7 @@ use std::fmt::{Display, Formatter};
4850
/// The content type is set to `text/html` and a `cache-control` header is added.
4951
///
5052
/// ```
53+
/// use ic_http_certification::StatusCode;
5154
/// use ic_asset_certification::{AssetConfig, AssetFallbackConfig, AssetEncoding};
5255
///
5356
/// let config = AssetConfig::File {
@@ -58,6 +61,7 @@ use std::fmt::{Display, Formatter};
5861
/// ],
5962
/// fallback_for: vec![AssetFallbackConfig {
6063
/// scope: "/".to_string(),
64+
/// status_code: Some(StatusCode::OK),
6165
/// }],
6266
/// aliased_by: vec!["/".to_string()],
6367
/// encodings: vec![
@@ -88,6 +92,7 @@ use std::fmt::{Display, Formatter};
8892
/// - `/not-found/index.html`
8993
///
9094
/// ```
95+
/// use ic_http_certification::StatusCode;
9196
/// use ic_asset_certification::{AssetConfig, AssetFallbackConfig, AssetEncoding};
9297
///
9398
/// let config = AssetConfig::File {
@@ -99,9 +104,11 @@ use std::fmt::{Display, Formatter};
99104
/// fallback_for: vec![
100105
/// AssetFallbackConfig {
101106
/// scope: "/css".to_string(),
107+
/// status_code: Some(StatusCode::NOT_FOUND),
102108
/// },
103109
/// AssetFallbackConfig {
104110
/// scope: "/js".to_string(),
111+
/// status_code: Some(StatusCode::NOT_FOUND),
105112
/// },
106113
/// ],
107114
/// aliased_by: vec![
@@ -126,6 +133,7 @@ use std::fmt::{Display, Formatter};
126133
/// set to `text/css` and a `cache-control` header is added.
127134
///
128135
/// ```
136+
/// use ic_http_certification::StatusCode;
129137
/// use ic_asset_certification::{AssetConfig, AssetEncoding};
130138
///
131139
/// let config = AssetConfig::Pattern {
@@ -371,6 +379,10 @@ pub struct AssetFallbackConfig {
371379
/// See the [fallback_for](AssetConfig::File::fallback_for)
372380
/// configuration of the [AssetConfig] interface for more information.
373381
pub scope: String,
382+
383+
/// The HTTP status code to return when serving the asset.
384+
/// If this value is not provided, the default status code will be 200.
385+
pub status_code: Option<StatusCode>,
374386
}
375387

376388
/// The type of redirect to use. Redirects can be either

0 commit comments

Comments
 (0)