Skip to content

Commit abc51b1

Browse files
authored
fix: setting custom etag header breaks certification (#3429)
1 parent 94f4964 commit abc51b1

File tree

6 files changed

+87
-72
lines changed

6 files changed

+87
-72
lines changed

Diff for: CHANGELOG.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,12 @@ Updated Motoko to [0.10.1](https://github.com/dfinity/motoko/releases/tag/0.10.1
2828

2929
### Frontend canister
3030

31+
Defining a custom `etag` header no longer breaks certification.
32+
3133
Fixed a certification issue where under certain conditions the fallback file (`/index.html`) was served with an incomplete certificate tree, not proving sufficiently that the fallback file may be used as a replacement.
3234

33-
- Module hash: 32f0024c3310b312b15118a8229998e326171c847955ecf223e166ba6b96b158
35+
- Module hash: 965c8899f0a033593dc9b1634b2ab4e0f3fd28c1cfa06993069be2040a2f700e
36+
- https://github.com/dfinity/sdk/pull/3429
3437
- https://github.com/dfinity/sdk/pull/3428
3538
- https://github.com/dfinity/sdk/pull/3421
3639

Diff for: Cargo.lock

+28-28
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: e2e/tests-dfx/assetscanister.bash

+3-39
Original file line numberDiff line numberDiff line change
@@ -1228,57 +1228,22 @@ CHERRIES" "$stdout"
12281228
assert_match "404 Not Found"
12291229
}
12301230

1231-
@test "asset configuration via .ic-assets.json5 - overwriting etag breaks certification" {
1232-
# this is observed behavior, not expected behavior
1233-
# https://dfinity.atlassian.net/browse/SDK-1245
1234-
install_asset assetscanister
1235-
1236-
dfx_start
1237-
1238-
touch src/e2e_project_frontend/assets/thing.json
1239-
1240-
dfx deploy
1241-
1242-
ID=$(dfx canister id e2e_project_frontend)
1243-
PORT=$(get_webserver_port)
1244-
1245-
dfx canister call --query e2e_project_frontend http_request '(record{url="/thing.json";headers=vec{};method="GET";body=vec{}})'
1246-
assert_command curl --fail --head "http://localhost:$PORT/thing.json?canisterId=$ID"
1247-
1248-
echo '[
1249-
{
1250-
"match": "thing.json",
1251-
"headers": {
1252-
"etag": "my-etag"
1253-
}
1254-
}
1255-
]' > src/e2e_project_frontend/assets/.ic-assets.json5
1256-
1257-
dfx deploy
1258-
1259-
dfx canister call --query e2e_project_frontend http_request '(record{url="/thing.json";headers=vec{};method="GET";body=vec{}})'
1260-
1261-
assert_command_fail curl --fail --head "http://localhost:$PORT/thing.json?canisterId=$ID"
1262-
assert_contains "500 Internal Server Error"
1263-
}
1264-
12651231
@test "asset configuration via .ic-assets.json5 - overwriting default headers" {
12661232
install_asset assetscanister
12671233

12681234
dfx_start
12691235

12701236
touch src/e2e_project_frontend/assets/thing.json
12711237

1272-
# this test used to also set etag, but that breaks certification
1273-
# see https://dfinity.atlassian.net/browse/SDK-1245
12741238
echo '[
12751239
{
12761240
"match": "thing.json",
12771241
"cache": { "max_age": 2000 },
12781242
"headers": {
12791243
"Content-Encoding": "my-encoding",
12801244
"Content-Type": "x-type",
1281-
"Cache-Control": "custom"
1245+
"Cache-Control": "custom",
1246+
"etag": "my-custom-etag"
12821247
}
12831248
}
12841249
]' > src/e2e_project_frontend/assets/.ic-assets.json5
@@ -1294,8 +1259,7 @@ CHERRIES" "$stdout"
12941259
assert_match "cache-control: custom"
12951260
assert_match "content-encoding: my-encoding"
12961261
assert_match "content-type: x-type"
1297-
# https://dfinity.atlassian.net/browse/SDK-1245 assert_not_match "etag: my-etag"
1298-
assert_match "etag: \"[a-z0-9]{64}\""
1262+
assert_match "etag: my-custom-etag"
12991263
}
13001264

13011265
@test "aliasing rules: <filename> to <filename>.html or <filename>/index.html" {

Diff for: src/canisters/frontend/ic-certified-assets/src/asset_certification/types/http.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -182,10 +182,15 @@ impl HttpResponse {
182182
let (status_code, body) = if etags.contains(&enc.sha256) {
183183
(304, RcBytes::default())
184184
} else {
185-
headers.insert(
186-
"etag".to_string(),
187-
format!("\"{}\"", hex::encode(enc.sha256)),
188-
);
185+
if !headers
186+
.iter()
187+
.any(|(header_name, _)| header_name.eq_ignore_ascii_case("etag"))
188+
{
189+
headers.insert(
190+
"etag".to_string(),
191+
format!("\"{}\"", hex::encode(enc.sha256)),
192+
);
193+
}
189194
(200, enc.content_chunks[chunk_index].clone())
190195
};
191196

Diff for: src/canisters/frontend/ic-certified-assets/src/tests.rs

+43
Original file line numberDiff line numberDiff line change
@@ -1887,6 +1887,49 @@ mod certification_v2 {
18871887

18881888
assert!(lookup_header(&response, "ic-certificate").is_some());
18891889
}
1890+
1891+
#[test]
1892+
fn etag() {
1893+
// For now only checks that defining a custom etag doesn't break certification.
1894+
// Serving HTTP 304 responses if the etag matches is part of https://dfinity.atlassian.net/browse/SDK-191
1895+
1896+
let mut state = State::default();
1897+
let time_now = 100_000_000_000;
1898+
1899+
const BODY: &[u8] = b"<!DOCTYPE html><html></html>";
1900+
1901+
create_assets(
1902+
&mut state,
1903+
time_now,
1904+
vec![AssetBuilder::new("/contents.html", "text/html")
1905+
.with_encoding("identity", vec![BODY])
1906+
.with_header("etag", "my-etag")],
1907+
);
1908+
1909+
let response = certified_http_request(
1910+
&state,
1911+
RequestBuilder::get("/contents.html")
1912+
.with_header("Accept-Encoding", "gzip,identity")
1913+
.with_certificate_version(1)
1914+
.build(),
1915+
);
1916+
assert_eq!(
1917+
lookup_header(&response, "etag").expect("ic-certificate header missing"),
1918+
"my-etag"
1919+
);
1920+
1921+
let response = certified_http_request(
1922+
&state,
1923+
RequestBuilder::get("/contents.html")
1924+
.with_header("Accept-Encoding", "gzip,identity")
1925+
.with_certificate_version(2)
1926+
.build(),
1927+
);
1928+
assert_eq!(
1929+
lookup_header(&response, "etag").expect("ic-certificate header missing"),
1930+
"my-etag"
1931+
);
1932+
}
18901933
}
18911934

18921935
#[cfg(test)]

Diff for: src/distributed/assetstorage.wasm.gz

85 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)