1use crate::certification::cert::{build_asset_certificate_header, build_certified_expression};
2use crate::constants::ASSET_ENCODING_NO_COMPRESSION;
3use crate::http::headers::{build_headers, build_redirect_headers};
4use crate::http::types::{CallbackFunc, HeaderField, StreamingCallbackToken, StreamingStrategy};
5use crate::memory::STATE;
6use crate::types::config::{StorageConfig, StorageConfigIFrame};
7use crate::types::runtime_state::StorageRuntimeState;
8use crate::types::store::{Asset, AssetEncoding, AssetKey, EncodingType};
9use junobuild_collections::types::rules::Memory;
10use junobuild_shared::ic::api::id;
11use serde_bytes::ByteBuf;
12
13pub fn streaming_strategy(
14 key: &AssetKey,
15 encoding: &AssetEncoding,
16 encoding_type: &str,
17 headers: &[HeaderField],
18 memory: &Memory,
19) -> Option<StreamingStrategy> {
20 let streaming_token: Option<StreamingCallbackToken> =
21 create_token(key, 0, encoding, encoding_type, headers, memory);
22
23 streaming_token.map(|streaming_token| StreamingStrategy::Callback {
24 callback: CallbackFunc::new(id(), "http_request_streaming_callback".to_string()),
25 token: streaming_token,
26 })
27}
28
29pub fn create_token(
30 key: &AssetKey,
31 chunk_index: usize,
32 encoding: &AssetEncoding,
33 encoding_type: &str,
34 headers: &[HeaderField],
35 memory: &Memory,
36) -> Option<StreamingCallbackToken> {
37 if chunk_index + 1 >= encoding.content_chunks.len() {
38 return None;
39 }
40
41 Some(StreamingCallbackToken {
42 full_path: key.full_path.clone(),
43 token: key.token.clone(),
44 headers: headers.to_owned(),
45 index: chunk_index + 1,
46 sha256: Some(ByteBuf::from(encoding.sha256)),
47 encoding_type: encoding_type.to_owned(),
48 memory: memory.clone(),
49 })
50}
51
52pub fn build_response_headers(
53 url: &str,
54 asset: &Asset,
55 encoding: &AssetEncoding,
56 encoding_type: &EncodingType,
57 certificate_version: &Option<u16>,
58 rewrite_source: &Option<String>,
59 config: &StorageConfig,
60) -> Result<Vec<HeaderField>, &'static str> {
61 let asset_headers = build_headers(asset, encoding, encoding_type, config);
62
63 extend_headers_with_certification(asset_headers, url, certificate_version, rewrite_source)
64}
65
66pub fn build_response_redirect_headers(
67 url: &str,
68 location: &str,
69 iframe: &StorageConfigIFrame,
70 certificate_version: &Option<u16>,
71) -> Result<Vec<HeaderField>, &'static str> {
72 let asset_headers = build_redirect_headers(location, iframe);
73
74 extend_headers_with_certification(asset_headers, url, certificate_version, &None)
75}
76
77fn extend_headers_with_certification(
78 asset_headers: Vec<HeaderField>,
79 url: &str,
80 certificate_version: &Option<u16>,
81 rewrite_source: &Option<String>,
82) -> Result<Vec<HeaderField>, &'static str> {
83 let certified_header = build_certified_headers(url, certificate_version, rewrite_source)?;
84 let certified_expression = build_certified_expression(&asset_headers, certificate_version)?;
85
86 match certified_expression {
87 None => Ok([asset_headers, vec![certified_header]].concat()),
88 Some(certified_expression) => {
89 Ok([asset_headers, vec![certified_header, certified_expression]].concat())
90 }
91 }
92}
93
94fn build_certified_headers(
95 url: &str,
96 certificate_version: &Option<u16>,
97 rewrite_source: &Option<String>,
98) -> Result<HeaderField, &'static str> {
99 STATE.with(|state| {
100 build_certified_headers_impl(
101 url,
102 certificate_version,
103 rewrite_source,
104 &state.borrow().runtime.storage,
105 )
106 })
107}
108
109fn build_certified_headers_impl(
110 url: &str,
111 certificate_version: &Option<u16>,
112 rewrite_source: &Option<String>,
113 state: &StorageRuntimeState,
114) -> Result<HeaderField, &'static str> {
115 build_asset_certificate_header(
116 &state.asset_hashes,
117 url.to_owned(),
118 certificate_version,
119 rewrite_source,
120 )
121}
122
123pub fn build_encodings(headers: Vec<HeaderField>) -> Vec<String> {
124 let mut encodings: Vec<String> = vec![];
125 for HeaderField(name, value) in headers.iter() {
126 if name.eq_ignore_ascii_case("Accept-Encoding") {
127 for v in value.split(',') {
128 encodings.push(v.trim().to_string());
129 }
130 }
131 }
132 encodings.push(ASSET_ENCODING_NO_COMPRESSION.to_string());
133
134 encodings
135}