240 {
241 constexpr std::array allowed {
242 std::string_view { "timeouts" },
243 std::string_view { "retry" },
244 std::string_view { "admission" },
245 std::string_view { "cache" },
246 std::string_view { "redirect_policy" },
247 std::string_view { "maximum_artifact_bytes" },
248 };
250
251 if (const auto value = object.find("timeouts"); value != object.end()) {
252 constexpr std::array fields {
253 std::string_view { "total_ms" },
254 std::string_view { "connect_ms" },
255 std::string_view { "read_ms" },
256 std::string_view { "write_ms" },
257 std::string_view { "pool_ms" },
258 };
260 *value, fields, std::string(location) + ".timeouts"
261 );
263 *value, "total_ms",
264 static_cast<std::uint64_t
>(policy.
timeouts.
total.count()), 1U,
266 ));
269 *value, "connect_ms",
272 std::string(location) + ".timeouts"
273 ));
275 *value, "read_ms",
276 static_cast<std::uint64_t
>(policy.
timeouts.
read.count()), 1U,
278 ));
280 *value, "write_ms",
281 static_cast<std::uint64_t
>(policy.
timeouts.
write.count()), 1U,
283 ));
285 *value, "pool_ms",
286 static_cast<std::uint64_t
>(policy.
timeouts.
pool.count()), 1U,
288 ));
289 }
290 if (const auto value = object.find("retry"); value != object.end()) {
291 constexpr std::array fields {
292 std::string_view { "maximum_attempts" },
293 std::string_view { "initial_delay_ms" },
294 std::string_view { "maximum_delay_ms" },
295 std::string_view { "total_delay_budget_ms" },
296 std::string_view { "respect_retry_after" },
297 };
299 *value, fields, std::string(location) + ".retry"
300 );
304 1U, 20U, std::string(location) + ".retry"
305 ));
308 *value, "initial_delay_ms",
311 std::string(location) + ".retry"
312 ));
315 *value, "maximum_delay_ms",
318 std::string(location) + ".retry"
319 ));
322 *value, "total_delay_budget_ms",
323 static_cast<std::uint64_t>(
325 ),
327 std::string(location) + ".retry"
328 ));
331 std::string(location) + ".retry"
332 );
333 }
334 if (const auto value = object.find("admission");
335 value != object.end()) {
336 constexpr std::array fields {
337 std::string_view { "maximum_concurrency" },
338 std::string_view { "minimum_interval_ms" },
339 };
341 *value, fields, std::string(location) + ".admission"
342 );
345 *value, "maximum_concurrency",
347 std::string(location) + ".admission"
348 ));
351 *value, "minimum_interval_ms",
352 static_cast<std::uint64_t>(
354 ),
356 std::string(location) + ".admission"
357 ));
358 }
359 if (const auto value = object.find("cache"); value != object.end()) {
360 constexpr std::array fields { std::string_view { "ttl_seconds" } };
362 *value, fields, std::string(location) + ".cache"
363 );
365 *value, "ttl_seconds",
366 static_cast<std::uint64_t
>(policy.
cache.
ttl.count()), 0U,
368 ));
369 }
370 if (const auto value = object.find("redirect_policy");
371 value != object.end()) {
372 constexpr std::array fields {
373 std::string_view { "follow" },
374 std::string_view { "maximum_redirects" },
375 std::string_view { "allow_https_to_http" },
376 std::string_view { "allowed_hosts" },
377 };
379 *value, fields, std::string(location) + ".redirect_policy"
380 );
383 std::string(location) + ".redirect_policy"
384 );
387 *value, "maximum_redirects",
389 std::string(location) + ".redirect_policy"
390 ));
392 *value, "allow_https_to_http",
394 std::string(location) + ".redirect_policy"
395 );
396 if (const auto hosts = value->find("allowed_hosts");
397 hosts != value->end()) {
398 if (!hosts->is_array() || hosts->empty()) {
399 throw std::invalid_argument(
400 std::string(location)
401 + ".redirect_policy.allowed_hosts must be a non-empty "
402 "array"
403 );
404 }
406 for (const auto& host : *hosts) {
407 if (!host.is_string()
408 || host.get_ref<const std::string&>().empty()) {
409 throw std::invalid_argument(
410 std::string(location)
411 + ".redirect_policy.allowed_hosts contains an "
412 "invalid host"
413 );
414 }
416 host.get<std::string>()
417 );
418 }
419 }
420 }
423 static_cast<std::uint64_t>(
424 std::numeric_limits<std::int64_t>::max()
425 ),
426 location
427 );
428
430 throw std::invalid_argument(
431 std::string(location) + " connect timeout exceeds total timeout"
432 );
433 }
435 throw std::invalid_argument(
436 std::string(location)
437 + " initial retry delay exceeds maximum retry delay"
438 );
439 }
442 throw std::invalid_argument(
443 std::string(location)
444 + " disables redirects but permits redirect attempts"
445 );
446 }
447 }
constexpr std::uint64_t maximum_cache_seconds
constexpr std::uint64_t maximum_policy_milliseconds
void reject_unknown_keys(const json &object, const std::span< const std::string_view > allowed, const std::string_view location)
std::uint64_t bounded_unsigned(const json &object, const std::string_view key, const std::uint64_t fallback, const std::uint64_t minimum, const std::uint64_t maximum, const std::string_view location)
bool optional_boolean(const json &object, const std::string_view key, const bool fallback, const std::string_view location)
std::size_t maximum_concurrency
std::chrono::milliseconds minimum_interval
admission_settings admission
timeout_settings timeouts
configured_redirect_policy redirects
std::uint64_t maximum_artifact_bytes
std::chrono::milliseconds initial_delay
std::chrono::milliseconds maximum_delay
std::size_t maximum_attempts
std::chrono::milliseconds total_delay_budget
std::chrono::milliseconds connect
std::chrono::milliseconds read
std::chrono::milliseconds total
std::chrono::milliseconds pool
std::chrono::milliseconds write