Skip to content

Commit

Permalink
feat(ic-asset-certification): allow overriding asset response status …
Browse files Browse the repository at this point in the history
…code
  • Loading branch information
nathanosdev committed Nov 20, 2024
1 parent ac8f90b commit 90cdfc3
Show file tree
Hide file tree
Showing 24 changed files with 560 additions and 176 deletions.
9 changes: 8 additions & 1 deletion examples/http-certification/assets/src/backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ use ic_cdk::{
api::{data_certificate, set_certified_data},
*,
};
use ic_http_certification::{HeaderField, HttpCertificationTree, HttpRequest, HttpResponse};
use ic_http_certification::{
HeaderField, HttpCertificationTree, HttpRequest, HttpResponse, HttpStatusCode,
};
use include_dir::{include_dir, Dir};
use std::{cell::RefCell, rc::Rc};

Expand Down Expand Up @@ -62,6 +64,7 @@ fn certify_all_assets() {
let asset_configs = vec![
AssetConfig::File {
path: "index.html".to_string(),
status_code: Some(HttpStatusCode::Ok),
content_type: Some("text/html".to_string()),
headers: get_asset_headers(vec![(
"cache-control".to_string(),
Expand All @@ -75,6 +78,7 @@ fn certify_all_assets() {
},
AssetConfig::Pattern {
pattern: "**/*.js".to_string(),
status_code: Some(HttpStatusCode::Ok),
content_type: Some("text/javascript".to_string()),
headers: get_asset_headers(vec![(
"cache-control".to_string(),
Expand All @@ -84,6 +88,7 @@ fn certify_all_assets() {
},
AssetConfig::Pattern {
pattern: "**/*.css".to_string(),
status_code: Some(HttpStatusCode::Ok),
content_type: Some("text/css".to_string()),
headers: get_asset_headers(vec![(
"cache-control".to_string(),
Expand All @@ -93,6 +98,7 @@ fn certify_all_assets() {
},
AssetConfig::Pattern {
pattern: "**/*.ico".to_string(),
status_code: Some(HttpStatusCode::Ok),
content_type: Some("image/x-icon".to_string()),
headers: get_asset_headers(vec![(
"cache-control".to_string(),
Expand All @@ -102,6 +108,7 @@ fn certify_all_assets() {
},
AssetConfig::Pattern {
pattern: "**/*.svg".to_string(),
status_code: Some(HttpStatusCode::Ok),
content_type: Some("image/svg+xml".to_string()),
headers: get_asset_headers(vec![(
"cache-control".to_string(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use ic_cdk::{
use ic_http_certification::{
utils::add_v2_certificate_header, DefaultCelBuilder, DefaultResponseCertification,
DefaultResponseOnlyCelExpression, HeaderField, HttpCertification, HttpCertificationPath,
HttpCertificationTree, HttpCertificationTreeEntry, HttpRequest, HttpResponse,
HttpCertificationTree, HttpCertificationTreeEntry, HttpRequest, HttpResponse, HttpStatusCode,
CERTIFICATE_EXPRESSION_HEADER_NAME,
};
use include_dir::{include_dir, Dir};
Expand Down Expand Up @@ -399,7 +399,7 @@ fn create_uncertified_response() -> HttpResponse<'static> {
);

HttpResponse::builder()
.with_status_code(200)
.with_status_code(HttpStatusCode::Ok)
.with_headers(headers)
.with_body(body)
.build()
Expand Down Expand Up @@ -436,7 +436,7 @@ fn create_asset_response(
let headers = get_asset_headers(additional_headers, body.len(), cel_expr);

HttpResponse::builder()
.with_status_code(200)
.with_status_code(HttpStatusCode::Ok)
.with_headers(headers)
.with_body(body)
.build()
Expand Down
18 changes: 9 additions & 9 deletions examples/http-certification/json-api/src/backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use ic_http_certification::{
utils::add_v2_certificate_header, DefaultCelBuilder, DefaultFullCelExpression,
DefaultResponseCertification, DefaultResponseOnlyCelExpression, HttpCertification,
HttpCertificationPath, HttpCertificationTree, HttpCertificationTreeEntry, HttpRequest,
HttpResponse, CERTIFICATE_EXPRESSION_HEADER_NAME,
HttpResponse, HttpStatusCode, CERTIFICATE_EXPRESSION_HEADER_NAME,
};
use lazy_static::lazy_static;
use matchit::{Params, Router};
Expand Down Expand Up @@ -176,7 +176,7 @@ fn certify_list_todos_response() {
)
.encode()
});
let mut response = create_response(200, body);
let mut response = create_response(HttpStatusCode::Ok, body);

certify_response(request, &mut response, &TODOS_TREE_PATH);
}
Expand All @@ -191,15 +191,15 @@ fn certify_not_allowed_todo_responses() {
.build();

let body = ErrorResponse::not_allowed().encode();
let mut response = create_response(405, body);
let mut response = create_response(HttpStatusCode::MethodNotAllowed, body);

certify_response(request, &mut response, &TODOS_TREE_PATH);
});
}

fn certify_not_found_response() {
let body = ErrorResponse::not_found().encode();
let mut response = create_response(404, body);
let mut response = create_response(HttpStatusCode::NotFound, body);

let tree_path = HttpCertificationPath::wildcard(NOT_FOUND_PATH);

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

let body = CreateTodoItemResponse::ok(&todo_item).encode();
create_response(201, body)
create_response(HttpStatusCode::Created, body)
}

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

let body = UpdateTodoItemResponse::ok(&()).encode();
create_response(200, body)
create_response(HttpStatusCode::Ok, body)
}

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

let body = DeleteTodoItemResponse::ok(&()).encode();
create_response(204, body)
create_response(HttpStatusCode::NoContent, body)
}

fn upgrade_to_update_call_handler(
Expand All @@ -451,7 +451,7 @@ fn upgrade_to_update_call_handler(
}

fn no_update_call_handler(_http_request: &HttpRequest, _params: &Params) -> HttpResponse<'static> {
create_response(400, vec![])
create_response(HttpStatusCode::BadRequest, vec![])
}

// Encoding
Expand All @@ -463,7 +463,7 @@ where
serde_json::from_slice(value).expect("Failed to deserialize value")
}

fn create_response(status_code: u16, body: Vec<u8>) -> HttpResponse<'static> {
fn create_response(status_code: HttpStatusCode, body: Vec<u8>) -> HttpResponse<'static> {
HttpResponse::builder()
.with_status_code(status_code)
.with_headers(vec![
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use ic_cdk::{
};
use ic_http_certification::{
utils::{add_skip_certification_header, skip_certification_certified_data},
HttpResponse,
HttpResponse, HttpStatusCode,
};

#[init]
Expand Down Expand Up @@ -55,7 +55,7 @@ fn create_response() -> HttpResponse<'static> {
];

HttpResponse::builder()
.with_status_code(200)
.with_status_code(HttpStatusCode::Ok)
.with_headers(headers)
.with_body(body)
.build()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use ic_cdk::*;
use ic_http_certification::{HttpResponse, HttpUpdateResponse};
use ic_http_certification::{HttpResponse, HttpStatusCode, HttpUpdateResponse};

#[query]
fn http_request() -> HttpResponse<'static> {
Expand All @@ -9,7 +9,7 @@ fn http_request() -> HttpResponse<'static> {
#[update]
fn http_request_update() -> HttpUpdateResponse<'static> {
HttpResponse::builder()
.with_status_code(418)
.with_status_code(HttpStatusCode::ImATeapot)
.with_body(b"I'm a teapot")
.build_update()
}
34 changes: 21 additions & 13 deletions packages/ic-asset-certification/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ This is implemented in the following steps:
2. [Configuring asset certification](#configuring-asset-certification)
3. [Inserting assets into the asset router](#inserting-assets-into-the-asset-router)
4. [Serving assets](#serving-assets)
5. [Deleting assets](#deleting-assets)
6. [Querying assets](#querying-assets)

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

Expand Down Expand Up @@ -167,10 +169,12 @@ on the `/index.html` path, in addition to serving as the fallback for the `/`
scope and setting `/` as an alias for this asset.

```rust
use ic_http_certification::HttpStatusCode;
use ic_asset_certification::{AssetConfig, AssetFallbackConfig};

let config = AssetConfig::File {
path: "index.html".to_string(),
status_code: Some(HttpStatusCode::Ok),
content_type: Some("text/html".to_string()),
headers: vec![
("Cache-Control".to_string(), "public, no-cache, no-store".to_string()),
Expand Down Expand Up @@ -206,10 +210,12 @@ Multiple aliases are also configured for this asset, namely:
Requests to any of those aliases will serve the `/404.html` asset.

```rust
use ic_http_certification::HttpStatusCode;
use ic_asset_certification::{AssetConfig, AssetFallbackConfig};

let config = AssetConfig::File {
path: "404.html".to_string(),
status_code: Some(HttpStatusCode::NotFound),
content_type: Some("text/html".to_string()),
headers: vec![
("Cache-Control".to_string(), "public, no-cache, no-store".to_string()),
Expand Down Expand Up @@ -269,10 +275,12 @@ For example, the following pattern will match all `.js` files in the `js`
directory:

```rust
use ic_http_certification::HttpStatusCode;
use ic_asset_certification::AssetConfig;

let config = AssetConfig::Pattern {
pattern: "js/*.js".to_string(),
status_code: Some(HttpStatusCode::Ok),
content_type: Some("application/javascript".to_string()),
headers: vec![
("Cache-Control".to_string(), "public, max-age=31536000, immutable".to_string()),
Expand Down Expand Up @@ -331,6 +339,7 @@ the appropriate response.
Assets can be inserted using the `certify_assets` method:

```rust
use ic_http_certification::HttpStatusCode;
use ic_asset_certification::{Asset, AssetConfig, AssetFallbackConfig, AssetRouter, AssetRedirectKind};

let mut asset_router = AssetRouter::default();
Expand Down Expand Up @@ -377,6 +386,7 @@ let assets = vec![
let asset_configs = vec![
AssetConfig::File {
path: "index.html".to_string(),
status_code: Some(HttpStatusCode::Ok),
content_type: Some("text/html".to_string()),
headers: vec![(
"cache-control".to_string(),
Expand All @@ -393,6 +403,7 @@ let asset_configs = vec![
},
AssetConfig::Pattern {
pattern: "**/*.js".to_string(),
status_code: Some(HttpStatusCode::Ok),
content_type: Some("text/javascript".to_string()),
headers: vec![(
"cache-control".to_string(),
Expand All @@ -405,6 +416,7 @@ let asset_configs = vec![
},
AssetConfig::Pattern {
pattern: "**/*.css".to_string(),
status_code: Some(HttpStatusCode::Ok),
content_type: Some("text/css".to_string()),
headers: vec![(
"cache-control".to_string(),
Expand Down Expand Up @@ -460,7 +472,7 @@ This method will return a response, a witness and an expression path, which can
alongside the canister's data certificate to add the required certificate header to the response.

```rust
use ic_http_certification::{HttpRequest, utils::add_v2_certificate_header};
use ic_http_certification::{HttpRequest, utils::add_v2_certificate_header, HttpStatusCode};
use ic_asset_certification::{Asset, AssetConfig, AssetFallbackConfig, AssetRouter};

let mut asset_router = AssetRouter::default();
Expand All @@ -472,6 +484,7 @@ let asset = Asset::new(

let asset_config = AssetConfig::File {
path: "index.html".to_string(),
status_code: Some(HttpStatusCode::Ok),
content_type: Some("text/html".to_string()),
headers: vec![
("Cache-Control".to_string(), "public, no-cache, no-store".to_string()),
Expand Down Expand Up @@ -522,6 +535,7 @@ only includes Brotli, then the Gzip file will not be deleted.
Using the same base example used to demonstrate certifying assets:

```rust
use ic_http_certification::HttpStatusCode;
use ic_asset_certification::{Asset, AssetConfig, AssetFallbackConfig, AssetRouter, AssetRedirectKind, AssetEncoding};

let mut asset_router = AssetRouter::default();
Expand Down Expand Up @@ -568,6 +582,7 @@ let assets = vec![
let asset_configs = vec![
AssetConfig::File {
path: "index.html".to_string(),
status_code: Some(HttpStatusCode::Ok),
content_type: Some("text/html".to_string()),
headers: vec![(
"cache-control".to_string(),
Expand All @@ -584,6 +599,7 @@ let asset_configs = vec![
},
AssetConfig::Pattern {
pattern: "**/*.js".to_string(),
status_code: Some(HttpStatusCode::Ok),
content_type: Some("text/javascript".to_string()),
headers: vec![(
"cache-control".to_string(),
Expand All @@ -596,6 +612,7 @@ let asset_configs = vec![
},
AssetConfig::Pattern {
pattern: "**/*.css".to_string(),
status_code: Some(HttpStatusCode::Ok),
content_type: Some("text/css".to_string()),
headers: vec![(
"cache-control".to_string(),
Expand All @@ -619,10 +636,6 @@ asset_router.certify_assets(assets, asset_configs).unwrap();
To delete the `index.html` asset, along with the fallback configuration for the `/` scope, the alias `/` and the alternative encodings:

```rust
# use ic_asset_certification::{Asset, AssetConfig, AssetFallbackConfig, AssetRouter, AssetRedirectKind, AssetEncoding};

# let mut asset_router = AssetRouter::default();

asset_router
.delete_assets(
vec![
Expand All @@ -635,6 +648,7 @@ asset_router
],
vec![AssetConfig::File {
path: "index.html".to_string(),
status_code: Some(HttpStatusCode::Ok),
content_type: Some("text/html".to_string()),
headers: vec![(
"cache-control".to_string(),
Expand All @@ -656,10 +670,6 @@ asset_router
To delete the `app.js` asset, along with the alternative encodings:

```rust
# use ic_asset_certification::{Asset, AssetConfig, AssetFallbackConfig, AssetRouter, AssetRedirectKind, AssetEncoding};

# let mut asset_router = AssetRouter::default();

asset_router
.delete_assets(
vec![
Expand All @@ -669,6 +679,7 @@ asset_router
],
vec![AssetConfig::Pattern {
pattern: "**/*.js".to_string(),
status_code: Some(HttpStatusCode::Ok),
content_type: Some("text/javascript".to_string()),
headers: vec![(
"cache-control".to_string(),
Expand All @@ -686,10 +697,6 @@ asset_router
To delete the `css/app-ba74b708.css` asset, along with the alternative encodings:

```rust
# use ic_asset_certification::{Asset, AssetConfig, AssetFallbackConfig, AssetRouter, AssetRedirectKind, AssetEncoding};

# let mut asset_router = AssetRouter::default();

asset_router.delete_assets(
vec![
Asset::new(
Expand All @@ -708,6 +715,7 @@ asset_router.delete_assets(
vec![
AssetConfig::Pattern {
pattern: "**/*.css".to_string(),
status_code: Some(HttpStatusCode::Ok),
content_type: Some("text/css".to_string()),
headers: vec![(
"cache-control".to_string(),
Expand Down
Loading

0 comments on commit 90cdfc3

Please sign in to comment.