ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_c6link_mdl.c
Go to the documentation of this file.
1
9
10#include "ra8_c6link_mdl.h"
11
12#include <stddef.h>
13#include <stdint.h>
14#include <string.h>
15
16#include "ra8_attributes.h"
17#include "ra8_c6link_internal.h"
20
21static_assert((uint32_t)k_mdl_format_loose == RA8__MDL__FORMAT__FORMAT_LOOSE);
22static_assert((uint32_t)k_mdl_format_cbz == RA8__MDL__FORMAT__FORMAT_CBZ);
23static_assert((uint32_t)k_mdl_format_cbt == RA8__MDL__FORMAT__FORMAT_CBT);
24static_assert((uint32_t)k_mdl_format_cbr == RA8__MDL__FORMAT__FORMAT_CBR);
27static_assert((uint32_t)k_mdl_format_epub == RA8__MDL__FORMAT__FORMAT_EPUB);
28static_assert((uint32_t)k_mdl_format_jof == RA8__MDL__FORMAT__FORMAT_JOF);
31
38
50
66RA8_INTERNAL static bool internal_mdl_http_field_valid(const char* text, size_t cap)
67{
68 if (text == nullptr) {
69 return true;
70 }
71 const size_t length = strnlen(text, cap);
72 if (length >= cap) {
73 return false;
74 }
75 for (size_t index = 0U; index < length; index++) {
76 if ((text[index] == '\r') || (text[index] == '\n')) {
77 return false;
78 }
79 }
80 return true;
81}
82
99{
100 const bool empty = (msg->retry_after != nullptr) && (msg->retry_after[0] == '\0') &&
101 (msg->etag != nullptr) && (msg->etag[0] == '\0') &&
102 (msg->last_modified != nullptr) && (msg->last_modified[0] == '\0') &&
103 (msg->content_type != nullptr) && (msg->content_type[0] == '\0');
105 return (msg->http_status == 0) && empty;
106 }
107 return (msg->http_status >= (int32_t)k_ra8_mdl_http_status_min) &&
108 (msg->http_status <= (int32_t)k_ra8_mdl_http_status_max) &&
113}
114
129RA8_INTERNAL static void
130internal_mdl_http_field_copy(char* destination, const char* source, size_t cap)
131{
132 const size_t length = strnlen(source, cap);
133 memcpy(destination, source, length + 1U);
134}
135
153 const Ra8__Mdl__Chunk* msg)
154{
155 *take->chunk = (ra8_mdl_chunk_t){.job_id = msg->job_id,
156 .sequence = msg->sequence,
157 .offset = msg->offset,
158 .total_bytes = msg->total_bytes,
159 .state = (ra8_mdl_state_t)msg->state,
160 .status = (ra8_err_t)msg->status,
161 .data_len = (uint16_t)msg->data.len,
162 .has_sha256 = (msg->sha256.len == k_ra8_mdl_sha256_bytes)};
163 if (msg->data.len != 0U) {
164 memcpy(take->chunk->data, msg->data.data, msg->data.len);
165 }
166 if (take->chunk->has_sha256) {
167 memcpy(take->chunk->sha256, msg->sha256.data, k_ra8_mdl_sha256_bytes);
168 }
170 take->chunk->response.status = msg->http_status;
172 msg->retry_after,
173 sizeof(take->chunk->response.retry_after));
175 msg->etag,
176 sizeof(take->chunk->response.etag));
178 msg->last_modified,
179 sizeof(take->chunk->response.last_modified));
181 msg->content_type,
182 sizeof(take->chunk->response.content_type));
183 }
184 take->session->next_offset += msg->data.len;
185 take->session->next_sequence += 1U;
189 take->session->active = false;
190 }
192}
193
209{
210 if (msg->data.len > (UINT64_MAX - msg->offset)) {
211 return false;
212 }
213 const uint64_t end = msg->offset + msg->data.len;
214 const bool total_covers_data = (msg->total_bytes == 0U) || (end <= msg->total_bytes);
215 if (!total_covers_data) {
216 return false;
217 }
219 return false;
220 }
221 switch (msg->state) {
223 return (msg->status == 0) && (msg->data.len != 0U) && (msg->sha256.len == 0U);
225 return (msg->status == 0) && (msg->data.len == 0U) &&
226 (msg->sha256.len == k_ra8_mdl_sha256_bytes) && (msg->sha256.data != nullptr) &&
227 ((msg->total_bytes == 0U) || (msg->total_bytes == end));
229 return (msg->status == 0) && (msg->data.len == 0U) && (msg->sha256.len == 0U);
231 return (msg->status > 0) && (msg->status <= UINT16_MAX) && (msg->data.len == 0U) &&
232 (msg->sha256.len == 0U);
233 default:
234 return false;
235 }
236}
237
255 const ProtobufCBinaryData* data)
256{
257 ProtobufCAllocator alloc = {};
258 priv_c6link_arena_bind(&alloc, take->link);
259 Ra8__Mdl__Accepted* msg = ra8__mdl__accepted__unpack(&alloc, data->len, data->data);
260 if (msg == nullptr) {
262 }
263 const bool valid = (msg->base.n_unknown_fields == 0U) &&
264 (msg->protocol_version == k_ra8_mdl_protocol_version) && (msg->job_id != 0U) &&
265 (msg->max_chunk_bytes != 0U) &&
267 ((uint32_t)msg->format == (uint32_t)take->requested_format);
268 if (valid) {
269 *take->session = (ra8_mdl_session_t){
270 .job_id = msg->job_id,
271 .next_sequence = 0U,
272 .next_offset = 0U,
273 .max_chunk_bytes = msg->max_chunk_bytes,
274 .format = take->requested_format,
275 .active = true,
276 };
277 }
279 return valid ? k_ra8_ok : k_ra8_err_protocol_error;
280}
281
299 const ProtobufCBinaryData* data)
300{
301 ProtobufCAllocator alloc = {};
302 priv_c6link_arena_bind(&alloc, take->link);
303 Ra8__Mdl__Chunk* msg = ra8__mdl__chunk__unpack(&alloc, data->len, data->data);
304 if (msg == nullptr) {
306 }
307 const bool valid =
308 (msg->base.n_unknown_fields == 0U) && (msg->protocol_version == k_ra8_mdl_protocol_version) &&
309 (msg->job_id == take->session->job_id) && (msg->sequence == take->session->next_sequence) &&
310 (msg->offset == take->session->next_offset) && (msg->data.len <= take->requested_bytes) &&
311 (msg->data.len <= k_ra8_mdl_chunk_data_max) &&
312 ((msg->data.len == 0U) || (msg->data.data != nullptr)) &&
314 const ra8_err_t result = valid ? internal_mdl_accept_chunk(take, msg) : k_ra8_err_protocol_error;
316 return result;
317}
318
336internal_mdl_take_cancelled(mdl_take_ctx_t* take, const uint8_t* data, size_t len)
337{
338 ProtobufCAllocator alloc = {};
339 priv_c6link_arena_bind(&alloc, take->link);
340 Ra8__Mdl__Cancelled* msg = ra8__mdl__cancelled__unpack(&alloc, len, data);
341 if (msg == nullptr) {
343 }
344 const bool valid = (msg->base.n_unknown_fields == 0U) &&
346 (msg->job_id == take->session->job_id) && (msg->status == 0);
347 if (valid) {
348 take->session->active = false;
349 }
351 return valid ? k_ra8_ok : k_ra8_err_protocol_error;
352}
353
370RA8_INTERNAL static ra8_err_t internal_mdl_take_response(void* ctx, const void* msg_v)
371{
372 mdl_take_ctx_t* take = (mdl_take_ctx_t*)ctx;
373 const Rpc* msg = (const Rpc*)msg_v;
374 const RpcRespCustomRpc* body = msg->resp_custom_rpc;
375 if ((body == nullptr) || (body->custom_msg_id != take->operation)) {
377 }
378 const ra8_err_t remote = priv_c6link_resp(take->link, take->operation, body->resp);
379 if (remote != k_ra8_ok) {
380 return remote;
381 }
382 // mcdc-deactivated: internal_mdl_take_response empty-body guard; the length operand is constant-false whenever it is evaluated. protobuf-c's unpack sets a bytes field's `data` pointer to NULL for every zero-length field (`else { bd->data = NULL; }` in parse_required_member), so a decoded body of length zero always arrives with a null pointer and is consumed by the first operand; reaching the second requires a non-null pointer, which the same code only produces when `len > 0`. A modelled co-processor that puts a present but empty body on the wire -- exercised by test_ra8_c6link_mdl_decode.c -- decodes to (null, 0) like an omitted one.
383 if ((body->data.data == nullptr) || (body->data.len == 0U)) {
385 }
386 switch (take->kind) {
388 return internal_mdl_take_accepted(take, &body->data);
389 case k_mdl_take_chunk:
390 return internal_mdl_take_chunk(take, &body->data);
392 return internal_mdl_take_cancelled(take, body->data.data, body->data.len);
393 default:
395 }
396}
397
398/* protobuf-c's pack-only binary-data ABI still declares its byte pointer
399 * mutable. */
400// NOLINTBEGIN(readability-non-const-parameter) -- interface contract fixes this writable pointer type.
421 uint32_t operation,
422 uint8_t* data,
423 size_t data_len,
424 mdl_take_ctx_t* take)
425{
426 RpcReqCustomRpc body = RPC__REQ__CUSTOM_RPC__INIT;
427 body.custom_msg_id = operation;
428 body.data = (ProtobufCBinaryData){.len = data_len, .data = data};
429
430 Rpc req = RPC__INIT;
431 req.msg_type = RPC_TYPE__Req;
432 req.msg_id = RPC_ID__Req_CustomRpc;
433 req.payload_case = RPC__PAYLOAD_REQ_CUSTOM_RPC;
434 req.req_custom_rpc = &body;
435 take->link = link;
436 take->operation = operation;
437 return priv_c6link_rpc_call(link,
438 &req,
439 (uint32_t)RPC_ID__Resp_CustomRpc,
441 take);
442}
443// NOLINTEND(readability-non-const-parameter)
444
446 ra8_mdl_session_t* session,
447 const uint8_t* packed,
448 size_t len)
449{
450 mdl_take_ctx_t take = {.link = link, .session = session, .kind = k_mdl_take_cancelled};
451 return internal_mdl_take_cancelled(&take, packed, len);
452}
453
455{
456 return internal_mdl_http_field_valid(text, cap);
457}
458
463
468
498 size_t* out_url_len)
499{
500 if ((request == nullptr) || (request->url == nullptr)) {
501 return k_ra8_err_null_ptr;
502 }
503 const size_t https_prefix_len = sizeof("https://") - 1U;
504 const size_t url_len = strnlen(request->url, k_ra8_mdl_url_max);
505 if ((url_len == 0U) || (url_len >= k_ra8_mdl_url_max) ||
506 (strncmp(request->url, "https://", https_prefix_len) != 0) ||
507 (request->url[https_prefix_len] == '\0')) {
509 }
510 if (((uint32_t)request->format > (uint32_t)k_mdl_format_rabook) ||
517 }
518 *out_url_len = url_len;
519 return k_ra8_ok;
520}
521
538
560{
561 if (http->user_agent != nullptr) {
562 memcpy(out->user_agent, http->user_agent, strlen(http->user_agent) + 1U);
563 }
564 if (http->referer != nullptr) {
565 memcpy(out->referer, http->referer, strlen(http->referer) + 1U);
566 }
567 if (http->if_none_match != nullptr) {
568 memcpy(out->if_none_match, http->if_none_match, strlen(http->if_none_match) + 1U);
569 }
570 if (http->if_modified_since != nullptr) {
572 }
573}
574
576 const ra8_mdl_request_t* request,
577 ra8_mdl_session_t* session)
578{
579 if ((link == nullptr) || (session == nullptr)) {
580 return k_ra8_err_null_ptr;
581 }
582 size_t url_len = 0U;
583 const ra8_err_t valid = internal_mdl_start_request_valid(request, &url_len);
584 if (valid != k_ra8_ok) {
585 return valid;
586 }
587 *session = (ra8_mdl_session_t){};
588 char url_copy[k_ra8_mdl_url_max];
589 memcpy(url_copy, request->url, url_len + 1U);
590 mdl_http_headers_t headers = {};
591 internal_mdl_stage_headers(&request->http, &headers);
595 inner.url = url_copy;
596 inner.format = (Ra8__Mdl__Format)request->format;
597 inner.user_agent = headers.user_agent;
598 inner.referer = headers.referer;
599 inner.if_none_match = headers.if_none_match;
600 inner.if_modified_since = headers.if_modified_since;
601 inner.timeout_ms = request->http.timeout_ms;
602 uint8_t* const data = link->mdl_request;
603 const size_t packed = ra8__mdl__start_request__get_packed_size(&inner);
604 // mcdc-deactivated: ra8_c6link_mdl_start_request codec self-consistency guard; all three conditions are constant-false on every reachable path, so this is a fail-closed backstop against a codec defect rather than an input class. get_packed_size() counts a message whose protocol_version is the non-zero k_ra8_mdl_protocol_version, so it never reports 0; k_ra8_mdl_request_bytes_max is the exact sum of every bounded field plus 96 bytes of tag and varint headroom, and each field was bounded before this point, so the packed message cannot exceed link->mdl_request; and protobuf-c pack() returns exactly what get_packed_size() computed for the same message.
605 if ((packed == 0U) || (packed > sizeof(link->mdl_request)) ||
606 (ra8__mdl__start_request__pack(&inner, data) != packed)) {
608 }
609 mdl_take_ctx_t take = {.session = session,
610 .requested_format = request->format,
611 .kind = k_mdl_take_accepted};
612 return internal_mdl_call(link, k_ra8_mdl_rpc_start, data, packed, &take);
613}
614
616 const char* url,
617 mdl_format_t format,
618 ra8_mdl_session_t* session)
619{
620 const ra8_mdl_request_t request = {.url = url, .format = format};
621 return ra8_c6link_mdl_start_request(link, &request, session);
622}
623
625 ra8_mdl_session_t* session,
626 uint16_t max_bytes,
627 ra8_mdl_chunk_t* chunk)
628{
629 if ((link == nullptr) || (session == nullptr) || (chunk == nullptr)) {
630 return k_ra8_err_null_ptr;
631 }
632 if (!session->active || (session->job_id == 0U)) {
634 }
635 if ((max_bytes == 0U) || (max_bytes > session->max_chunk_bytes) ||
636 (max_bytes > k_ra8_mdl_chunk_data_max)) {
638 }
639 *chunk = (ra8_mdl_chunk_t){};
642 inner.job_id = session->job_id;
643 inner.acknowledged_offset = session->next_offset;
644 inner.max_bytes = max_bytes;
645 uint8_t* const data = link->mdl_request;
646 const size_t packed = ra8__mdl__next_request__get_packed_size(&inner);
647 // mcdc-deactivated: ra8_c6link_mdl_next codec self-consistency guard; all three conditions are constant-false on every reachable path, so this is a fail-closed backstop against a codec defect rather than an input class. get_packed_size() counts a message whose protocol_version is the non-zero k_ra8_mdl_protocol_version, so it never reports 0; k_ra8_mdl_request_bytes_max is the exact sum of every bounded field plus 96 bytes of tag and varint headroom, and each field was bounded before this point, so the packed message cannot exceed link->mdl_request; and protobuf-c pack() returns exactly what get_packed_size() computed for the same message.
648 if ((packed == 0U) || (packed > sizeof(link->mdl_request)) ||
649 (ra8__mdl__next_request__pack(&inner, data) != packed)) {
651 }
652 mdl_take_ctx_t take = {.session = session,
653 .chunk = chunk,
654 .requested_bytes = max_bytes,
655 .kind = k_mdl_take_chunk};
656 return internal_mdl_call(link, k_ra8_mdl_rpc_next, data, packed, &take);
657}
658
660{
661 if ((link == nullptr) || (session == nullptr)) {
662 return k_ra8_err_null_ptr;
663 }
664 if (!session->active || (session->job_id == 0U)) {
666 }
669 inner.job_id = session->job_id;
670 uint8_t* const data = link->mdl_request;
671 const size_t packed = ra8__mdl__cancel_request__get_packed_size(&inner);
672 // mcdc-deactivated: ra8_c6link_mdl_cancel codec self-consistency guard; all three conditions are constant-false on every reachable path, so this is a fail-closed backstop against a codec defect rather than an input class. get_packed_size() counts a message whose protocol_version is the non-zero k_ra8_mdl_protocol_version, so it never reports 0; k_ra8_mdl_request_bytes_max is the exact sum of every bounded field plus 96 bytes of tag and varint headroom, and each field was bounded before this point, so the packed message cannot exceed link->mdl_request; and protobuf-c pack() returns exactly what get_packed_size() computed for the same message.
673 if ((packed == 0U) || (packed > sizeof(link->mdl_request)) ||
674 (ra8__mdl__cancel_request__pack(&inner, data) != packed)) {
676 }
677 mdl_take_ctx_t take = {.session = session, .kind = k_mdl_take_cancelled};
678 return internal_mdl_call(link, k_ra8_mdl_rpc_cancel, data, packed, &take);
679}
mdl_format_t
Artifact format selected by a media-download composition root.
Definition mdl_format.h:35
@ k_mdl_format_cbz
ZIP of images (.cbz).
Definition mdl_format.h:37
@ k_mdl_format_invalid
Unrecognized or unsupported selection.
Definition mdl_format.h:45
@ k_mdl_format_loose
Leave loose page images.
Definition mdl_format.h:36
@ k_mdl_format_cbr
Reserved RAR output.
Definition mdl_format.h:39
@ k_mdl_format_epub
Fixed-layout EPUB (.epub).
Definition mdl_format.h:42
@ k_mdl_format_cbt_gz
Gzip-compressed tar (.cbt.gz).
Definition mdl_format.h:41
@ k_mdl_format_cbt_xz
Reserved xz-compressed tar output.
Definition mdl_format.h:40
@ k_mdl_format_rabook
Chunked reader-native book (.rabook).
Definition mdl_format.h:44
@ k_mdl_format_jof
Native JOF tile atlas per page (.jof).
Definition mdl_format.h:43
@ k_mdl_format_cbt
Tar of images (.cbt).
Definition mdl_format.h:38
Annotation-attribute framework macros for ra8-firmware.
#define RA8_TEST_HELPER
Mark a symbol as externally-linked but only callable from tests.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_invalid_state
Module in wrong state for requested operation.
Definition ra8_err.h:161
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_null_ptr
Pointer was NULL where a valid pointer was required.
Definition ra8_err.h:478
@ k_ra8_err_protocol_error
Protocol-level error (e.g.
Definition ra8_err.h:429
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
int strncmp(const char *s1, const char *s2, size_t n)
Compare two strings up to a specified length.
size_t strlen(const char *s)
Calculate string length.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
size_t strnlen(const char *s, size_t maxlen)
Calculate bounded string length.
@ k_ra8_mdl_user_agent_max
Maximum User-Agent size, including NUL.
@ k_ra8_mdl_referer_max
Maximum Referer size, including NUL.
@ k_ra8_mdl_chunk_data_max
Maximum raw body bytes in one chunk.
@ k_ra8_mdl_url_max
Maximum URL buffer size, including NUL.
@ k_ra8_mdl_http_date_max
Maximum HTTP-date size, including NUL.
@ k_ra8_mdl_etag_max
Maximum ETag size, including NUL.
@ k_ra8_mdl_content_type_max
Maximum Content-Type size, including NUL.
@ k_ra8_mdl_sha256_bytes
SHA-256 digest size in bytes.
@ k_ra8_mdl_retry_after_max
Maximum Retry-After size, including NUL.
@ k_ra8_mdl_timeout_ms_max
Maximum caller-selected HTTP timeout in ms.
@ k_ra8_mdl_http_status_max
Highest well-formed HTTP status code.
@ k_ra8_mdl_http_status_min
Lowest well-formed HTTP status code.
@ k_ra8_mdl_protocol_version
Typed HTTP-artifact transfer protocol.
ra8_mdl_state_t
Remote job state.
@ k_ra8_mdl_rpc_start
Start one typed-artifact job.
@ k_ra8_mdl_rpc_cancel
Cancel one active job.
@ k_ra8_mdl_rpc_next
Pull one ordered bounded chunk.
Generated protobuf-C declarations for the media-download protocol.
#define RA8__MDL__CANCEL_REQUEST__INIT
size_t ra8__mdl__start_request__pack(const Ra8__Mdl__StartRequest *message, uint8_t *out)
Ra8__Mdl__Chunk * ra8__mdl__chunk__unpack(ProtobufCAllocator *allocator, size_t len, const uint8_t *data)
void ra8__mdl__accepted__free_unpacked(Ra8__Mdl__Accepted *message, ProtobufCAllocator *allocator)
@ RA8__MDL__FORMAT__FORMAT_CBT_GZ
@ RA8__MDL__FORMAT__FORMAT_RABOOK
@ RA8__MDL__FORMAT__FORMAT_CBT_XZ
@ RA8__MDL__FORMAT__FORMAT_JOF
@ RA8__MDL__FORMAT__FORMAT_INVALID
@ RA8__MDL__FORMAT__FORMAT_LOOSE
@ RA8__MDL__FORMAT__FORMAT_CBR
@ RA8__MDL__FORMAT__FORMAT_CBZ
@ RA8__MDL__FORMAT__FORMAT_CBT
@ RA8__MDL__FORMAT__FORMAT_EPUB
Ra8__Mdl__Accepted * ra8__mdl__accepted__unpack(ProtobufCAllocator *allocator, size_t len, const uint8_t *data)
size_t ra8__mdl__cancel_request__get_packed_size(const Ra8__Mdl__CancelRequest *message)
void ra8__mdl__chunk__free_unpacked(Ra8__Mdl__Chunk *message, ProtobufCAllocator *allocator)
size_t ra8__mdl__next_request__pack(const Ra8__Mdl__NextRequest *message, uint8_t *out)
void ra8__mdl__cancelled__free_unpacked(Ra8__Mdl__Cancelled *message, ProtobufCAllocator *allocator)
size_t ra8__mdl__start_request__get_packed_size(const Ra8__Mdl__StartRequest *message)
enum _Ra8__Mdl__Format Ra8__Mdl__Format
@ RA8__MDL__STATE__STATE_DOWNLOADING
@ RA8__MDL__STATE__STATE_COMPLETE
@ RA8__MDL__STATE__STATE_CANCELLED
@ RA8__MDL__STATE__STATE_FAILED
Ra8__Mdl__Cancelled * ra8__mdl__cancelled__unpack(ProtobufCAllocator *allocator, size_t len, const uint8_t *data)
void ra8__mdl__start_request__init(Ra8__Mdl__StartRequest *message)
size_t ra8__mdl__next_request__get_packed_size(const Ra8__Mdl__NextRequest *message)
#define RA8__MDL__NEXT_REQUEST__INIT
size_t ra8__mdl__cancel_request__pack(const Ra8__Mdl__CancelRequest *message, uint8_t *out)
ProtobufCBinaryData sha256
ProtobufCBinaryData data
Fixed-capacity storage for the four optional MDL HTTP request headers.
char if_modified_since[k_ra8_mdl_http_date_max]
If-Modified-Since staging.
char user_agent[k_ra8_mdl_user_agent_max]
User-Agent staging.
char if_none_match[k_ra8_mdl_etag_max]
If-None-Match staging.
char referer[k_ra8_mdl_referer_max]
Referer staging.
Context consumed synchronously by the CustomRpc response extractor.
uint16_t requested_bytes
Maximum accepted response body bytes.
mdl_take_kind_t kind
Expected generated response variant.
ra8_c6link_t * link
Link whose arena decoded the response.
uint32_t operation
Expected CustomRpc operation id.
ra8_mdl_chunk_t * chunk
Optional caller chunk destination.
ra8_mdl_session_t * session
Correlated caller session.
mdl_format_t requested_format
Format the Accepted response must echo.
One correlated bounded raw-byte response.
ra8_mdl_http_response_t response
Terminal HTTP metadata.
uint8_t data[k_ra8_mdl_chunk_data_max]
Bounded raw body bytes.
uint8_t sha256[k_ra8_mdl_sha256_bytes]
Complete-body SHA-256.
bool has_sha256
Whether sha256 is valid.
Bounded request policy forwarded to the C6 HTTP client.
uint32_t timeout_ms
Whole-request timeout, or zero for default.
const char * if_modified_since
If-Modified-Since value, or null/empty.
const char * if_none_match
If-None-Match value, or null/empty to omit.
const char * user_agent
User-Agent value, or null/empty to omit.
const char * referer
Referer value, or null/empty to omit.
char last_modified[k_ra8_mdl_http_date_max]
Last-Modified or empty.
int32_t status
Final HTTP status.
char retry_after[k_ra8_mdl_retry_after_max]
Retry-After or empty.
char content_type[k_ra8_mdl_content_type_max]
Content-Type or empty.
char etag[k_ra8_mdl_etag_max]
ETag or empty.
Complete typed HTTPS request accepted by protocol version 3.
mdl_format_t format
Exact returned artifact identity.
ra8_mdl_http_policy_t http
Forwarded request policy.
const char * url
Absolute HTTPS source URL.
RA8-local state for one accepted remote artifact job.
uint64_t next_offset
Exact byte offset required from the next response.
uint32_t job_id
Remote-generated non-zero identifier.
bool active
Whether next/cancel is currently valid.
uint32_t next_sequence
Exact sequence required from the next response.
uint32_t max_chunk_bytes
Maximum accepted pull size negotiated at start.