68 if ((evt == NULL) || (evt->event_id != HTTP_EVENT_ON_HEADER) ||
69 (evt->user_data == NULL) || (evt->header_key == NULL)) {
74 if (strcasecmp(evt->header_key,
"Date") == 0) {
76 const char *val = (evt->header_value != NULL) ? evt->header_value :
"";
77 (void)strncpy(hdrs->
date, val,
sizeof(hdrs->
date) - 1U);
78 hdrs->
date[
sizeof(hdrs->
date) - 1U] =
'\0';
107 int64_t server_epoch = 0;
111 if (date_hdr[0] ==
'\0') {
112 ESP_LOGW(
TAG,
"no Date header - clock not corroborated");
117 ESP_LOGW(
TAG,
"unparseable Date header - clock not corroborated");
121 local_epoch =
static_cast<int64_t
>(time(NULL));
122 skew = local_epoch - server_epoch;
123 if (skew < 0) { skew = -skew; }
126 ESP_LOGE(
TAG,
"clock off by %" PRId64
" s vs server (local %" PRId64
127 ", server %" PRId64
") - refusing (spoofed NTP?)",
128 skew, local_epoch, server_epoch);
132 ESP_LOGD(
TAG,
"clock corroborated (skew %" PRId64
" s)", skew);
141 char *resp_buf,
size_t resp_buf_size,
142 const char *user,
const char *pass,
const char *ca_pem)
144 bool success =
false;
146 if ((url == NULL) || (body == NULL) || (resp_buf == NULL) ||
147 (resp_buf_size < 2U)) {
154 bool use_auth = ((user != NULL) && (user[0] !=
'\0') &&
155 (pass != NULL) && (pass[0] !=
'\0'));
158 (void)memset(&hdrs, 0,
sizeof(hdrs));
160 esp_http_client_config_t cfg;
161 CW_Utils::secure_wipe(
reinterpret_cast<uint8_t *
>(&cfg),
sizeof(cfg));
163 cfg.method = HTTP_METHOD_POST;
164 cfg.timeout_ms = 15000;
166 cfg.user_data = &hdrs;
169 if (ca_pem != NULL) {
170 cfg.cert_pem = ca_pem;
172 cfg.crt_bundle_attach = esp_crt_bundle_attach;
177 cfg.auth_type = HTTP_AUTH_TYPE_BASIC;
180 esp_http_client_handle_t client = esp_http_client_init(&cfg);
181 if (client == NULL) {
182 ESP_LOGE(
TAG,
"HTTP client init failed");
186 (void)esp_http_client_set_header(client,
"Content-Type",
"application/json");
188 int body_len =
static_cast<int>(strlen(body));
189 esp_err_t err = esp_http_client_open(client, body_len);
191 ESP_LOGE(
TAG,
"HTTP open: %s", esp_err_to_name(err));
195 if (esp_http_client_write(client, body, body_len) != body_len) {
196 ESP_LOGE(
TAG,
"HTTP write incomplete");
201 int64_t content_length = esp_http_client_fetch_headers(client);
202 (void)content_length;
218 int space =
static_cast<int>(resp_buf_size - 1U) - total;
219 if (space <= 0) { full =
true;
break; }
220 read = esp_http_client_read(client, resp_buf + total, space);
221 if (read > 0) { total += read; }
224 resp_buf[total] =
'\0';
230 if (full && !esp_http_client_is_complete_data_received(client)) {
231 ESP_LOGE(
TAG,
"response larger than %u bytes - dropped",
232 static_cast<unsigned>(resp_buf_size - 1U));
238 int status = esp_http_client_get_status_code(client);
242 success = ((total > 0) && (status == 200));
246 esp_http_client_close(client);
247 esp_http_client_cleanup(client);
bool https_post_json(const char *url, const char *body, char *resp_buf, size_t resp_buf_size, const char *user, const char *pass, const char *ca_pem)
POST a JSON body over HTTPS and read the response.
static esp_err_t http_event_cb(esp_http_client_event_t *evt)
HTTP event hook that captures the response Date header.
static bool clock_corroborated(const char *date_hdr)
Cross-check the system clock against the server's HTTP Date header.
One HTTPS JSON POST, shared by every RPC client in the firmware.
static void wdt_feed(void)
Feed the task watchdog if, and only if, the calling task is subscribed.