|
52 | 52 | const std::string& entity_tag, |
53 | 53 | int64_t last_modified_unix_seconds, |
54 | 54 | webscene_native::v8_dom_runtime::resource_response& response) { |
55 | | - if (resource_load_callback_v3_ == nullptr |
| 55 | + if (resource_load_callback_v4_ == nullptr |
| 56 | + && resource_load_callback_v3_ == nullptr |
56 | 57 | && resource_load_callback_v2_ == nullptr |
57 | 58 | && resource_load_callback_ == nullptr) return false; |
58 | 59 | const auto started = std::chrono::steady_clock::now(); |
|
120 | 121 | request_context.body.size(), |
121 | 122 | request_context.content_type.data(), |
122 | 123 | request_context.content_type.size()}; |
| 124 | + const webscene_resource_request_context_v4 native_context_v4{ |
| 125 | + sizeof(webscene_resource_request_context_v4), |
| 126 | + request_context.initiator, |
| 127 | + request_context.origin.data(), |
| 128 | + request_context.origin.size(), |
| 129 | + request_context.referrer.data(), |
| 130 | + request_context.referrer.size(), |
| 131 | + request_context.mode, |
| 132 | + request_context.destination, |
| 133 | + request_context.method.data(), |
| 134 | + request_context.method.size(), |
| 135 | + request_context.body.data(), |
| 136 | + request_context.body.size(), |
| 137 | + request_context.content_type.data(), |
| 138 | + request_context.content_type.size(), |
| 139 | + request_context.credentials, |
| 140 | + request_context.cookie.data(), |
| 141 | + request_context.cookie.size()}; |
| 142 | + webscene_resource_response_v4 native_response{}; |
123 | 143 | const auto invoke = [&](char* destination, size_t capacity) { |
124 | | - return resource_load_callback_v3_ != nullptr |
| 144 | + native_response = {}; |
| 145 | + native_response.struct_size = sizeof(native_response); |
| 146 | + return resource_load_callback_v4_ != nullptr |
| 147 | + ? resource_load_callback_v4_( |
| 148 | + resource_load_v4_user_data_, kind, url.data(), url.size(), |
| 149 | + entity_tag.data(), entity_tag.size(), |
| 150 | + last_modified_unix_seconds, &native_context_v4, |
| 151 | + &native_response, destination, capacity) |
| 152 | + : resource_load_callback_v3_ != nullptr |
125 | 153 | ? resource_load_callback_v3_( |
126 | 154 | resource_load_v3_user_data_, kind, url.data(), url.size(), |
127 | 155 | entity_tag.data(), entity_tag.size(), |
|
185 | 213 | response.content.assign( |
186 | 214 | buffer + envelope_header_size + response_tag_length, |
187 | 215 | required - envelope_header_size - response_tag_length); |
| 216 | + if (resource_load_callback_v4_ != nullptr) { |
| 217 | + response.has_http_metadata = true; |
| 218 | + constexpr size_t maximum_response_headers = 64U; |
| 219 | + constexpr size_t maximum_response_metadata_bytes = 64U * 1024U; |
| 220 | + constexpr size_t maximum_response_url_bytes = 8U * 1024U; |
| 221 | + if (native_response.status < 100U || native_response.status > 599U |
| 222 | + || native_response.status_text_length > 1024U |
| 223 | + || native_response.final_url_length > maximum_response_url_bytes |
| 224 | + || native_response.header_count > maximum_response_headers |
| 225 | + || (native_response.status_text_length != 0U |
| 226 | + && native_response.status_text == nullptr) |
| 227 | + || (native_response.final_url_length != 0U |
| 228 | + && native_response.final_url == nullptr) |
| 229 | + || (native_response.header_count != 0U |
| 230 | + && native_response.headers == nullptr)) { |
| 231 | + return failed("invalid-response-metadata"); |
| 232 | + } |
| 233 | + response.status = native_response.status; |
| 234 | + response.status_text.assign( |
| 235 | + native_response.status_text == nullptr ? "" : native_response.status_text, |
| 236 | + native_response.status_text_length); |
| 237 | + response.final_url.assign( |
| 238 | + native_response.final_url == nullptr ? "" : native_response.final_url, |
| 239 | + native_response.final_url_length); |
| 240 | + auto metadata_bytes = response.status_text.size() + response.final_url.size(); |
| 241 | + response.headers.reserve(native_response.header_count); |
| 242 | + for (size_t index = 0; index < native_response.header_count; ++index) { |
| 243 | + const auto& header = native_response.headers[index]; |
| 244 | + if (header.struct_size < sizeof(webscene_resource_header_v4) |
| 245 | + || header.name == nullptr || header.name_length == 0U |
| 246 | + || (header.value_length != 0U && header.value == nullptr)) { |
| 247 | + return failed("invalid-response-metadata"); |
| 248 | + } |
| 249 | + metadata_bytes += header.name_length + header.value_length; |
| 250 | + if (metadata_bytes > maximum_response_metadata_bytes) { |
| 251 | + return failed("response-metadata-too-large"); |
| 252 | + } |
| 253 | + std::string name(header.name, header.name_length); |
| 254 | + std::string value( |
| 255 | + header.value == nullptr ? "" : header.value, |
| 256 | + header.value_length); |
| 257 | + const auto valid_name = std::all_of( |
| 258 | + name.begin(), name.end(), [](unsigned char character) { |
| 259 | + return std::isalnum(character) || character == '!' || character == '#' |
| 260 | + || character == '$' || character == '%' || character == '&' |
| 261 | + || character == '\'' || character == '*' || character == '+' |
| 262 | + || character == '-' || character == '.' || character == '^' |
| 263 | + || character == '_' || character == '`' || character == '|' |
| 264 | + || character == '~'; |
| 265 | + }); |
| 266 | + if (!valid_name || value.find_first_of("\r\n") != std::string::npos) { |
| 267 | + return failed("invalid-response-header"); |
| 268 | + } |
| 269 | + std::transform(name.begin(), name.end(), name.begin(), [](unsigned char character) { |
| 270 | + return static_cast<char>(std::tolower(character)); |
| 271 | + }); |
| 272 | + response.headers.emplace_back(std::move(name), std::move(value)); |
| 273 | + if (response.headers.back().first == "set-cookie") { |
| 274 | + response.cacheable = false; |
| 275 | + } |
| 276 | + } |
| 277 | + } else { |
| 278 | + response.final_url = url; |
| 279 | + } |
188 | 280 | return true; |
189 | 281 | }, |
190 | 282 | [this] { |
|
0 commit comments