|
8 | 8 |
|
9 | 9 | #include "memfault/http/utils.h"
|
10 | 10 |
|
| 11 | +#include <ctype.h> |
11 | 12 | #include <limits.h>
|
12 | 13 | #include <stdio.h>
|
13 | 14 | #include <string.h>
|
| 15 | +#include <stdint.h> |
14 | 16 |
|
15 | 17 | #include "memfault/core/compiler.h"
|
| 18 | +#include "memfault/core/debug_log.h" |
| 19 | +#include "memfault/core/math.h" |
16 | 20 | #include "memfault/core/platform/device_info.h"
|
17 | 21 | #include "memfault/http/http_client.h"
|
18 | 22 |
|
| 23 | +//! Default buffer size for the URL-encoded device info parameters. This may |
| 24 | +//! need to be set higher by the user if there are particularly long device info |
| 25 | +//! strings |
| 26 | +#ifndef MEMFAULT_DEVICE_INFO_URL_ENCODED_MAX_LEN |
| 27 | +#define MEMFAULT_DEVICE_INFO_URL_ENCODED_MAX_LEN (48) |
| 28 | +#endif |
| 29 | + |
19 | 30 | static bool prv_write_msg(MfltHttpClientSendCb write_callback, void *ctx,
|
20 | 31 | const char *msg, size_t msg_len, size_t max_len) {
|
21 | 32 | if (msg_len >= max_len) {
|
@@ -153,19 +164,49 @@ bool memfault_http_get_latest_ota_payload_url(MfltHttpClientSendCb write_callbac
|
153 | 164 |
|
154 | 165 | #define MEMFAULT_STATIC_STRLEN(s) (sizeof(s) - 1)
|
155 | 166 |
|
156 |
| - if (!prv_write_qparam(write_callback, ctx, |
157 |
| - DEVICE_SERIAL_QPARAM, MEMFAULT_STATIC_STRLEN(DEVICE_SERIAL_QPARAM), |
158 |
| - device_info.device_serial) || |
159 |
| - !prv_write_qparam(write_callback, ctx, |
160 |
| - HARDWARE_VERSION_QPARAM, MEMFAULT_STATIC_STRLEN(HARDWARE_VERSION_QPARAM), |
161 |
| - device_info.hardware_version) || |
162 |
| - !prv_write_qparam(write_callback, ctx, |
163 |
| - SOFTWARE_TYPE_QPARAM, MEMFAULT_STATIC_STRLEN(SOFTWARE_TYPE_QPARAM), |
164 |
| - device_info.software_type) || |
165 |
| - !prv_write_qparam(write_callback, ctx, |
166 |
| - CURRENT_VERSION_QPARAM, MEMFAULT_STATIC_STRLEN(CURRENT_VERSION_QPARAM), |
167 |
| - device_info.software_version)) { |
168 |
| - return false; |
| 167 | + const struct qparam_values_s { |
| 168 | + const char *name; |
| 169 | + size_t name_strlen; |
| 170 | + const char *value; |
| 171 | + } qparam_values[] = { |
| 172 | + { |
| 173 | + DEVICE_SERIAL_QPARAM, |
| 174 | + MEMFAULT_STATIC_STRLEN(DEVICE_SERIAL_QPARAM), |
| 175 | + device_info.device_serial, |
| 176 | + }, |
| 177 | + { |
| 178 | + HARDWARE_VERSION_QPARAM, |
| 179 | + MEMFAULT_STATIC_STRLEN(HARDWARE_VERSION_QPARAM), |
| 180 | + device_info.hardware_version, |
| 181 | + }, |
| 182 | + { |
| 183 | + SOFTWARE_TYPE_QPARAM, |
| 184 | + MEMFAULT_STATIC_STRLEN(SOFTWARE_TYPE_QPARAM), |
| 185 | + device_info.software_type, |
| 186 | + }, |
| 187 | + { |
| 188 | + CURRENT_VERSION_QPARAM, |
| 189 | + MEMFAULT_STATIC_STRLEN(CURRENT_VERSION_QPARAM), |
| 190 | + device_info.software_version, |
| 191 | + }, |
| 192 | + }; |
| 193 | + |
| 194 | + // URL encode the qparam values before writing them |
| 195 | + for (size_t i = 0; i < MEMFAULT_ARRAY_SIZE(qparam_values); i++) { |
| 196 | + const struct qparam_values_s *qparam_value = &qparam_values[i]; |
| 197 | + |
| 198 | + char qparam_encoded_buffer[MEMFAULT_DEVICE_INFO_URL_ENCODED_MAX_LEN]; |
| 199 | + int rv = memfault_http_urlencode(qparam_value->value, strlen(qparam_value->value), |
| 200 | + qparam_encoded_buffer, sizeof(qparam_encoded_buffer)); |
| 201 | + if (rv != 0) { |
| 202 | + MEMFAULT_LOG_ERROR("Failed to URL encode qparam value: %s", qparam_value->value); |
| 203 | + return false; |
| 204 | + } |
| 205 | + |
| 206 | + if (!prv_write_qparam(write_callback, ctx, qparam_value->name, qparam_value->name_strlen, |
| 207 | + qparam_encoded_buffer)) { |
| 208 | + return false; |
| 209 | + } |
169 | 210 | }
|
170 | 211 |
|
171 | 212 | #define LATEST_REQUEST_LINE_END " HTTP/1.1\r\n"
|
@@ -619,3 +660,50 @@ bool memfault_http_get_ota_payload(MfltHttpClientSendCb write_callback, void *ct
|
619 | 660 |
|
620 | 661 | return prv_write_crlf(write_callback, ctx);
|
621 | 662 | }
|
| 663 | + |
| 664 | +static bool prv_is_unreserved(char c) { |
| 665 | + return isalnum((uint8_t)c) || c == '-' || c == '_' || c == '.' || c == '~'; |
| 666 | +} |
| 667 | + |
| 668 | +bool memfault_http_needs_escape(const char *str, size_t len) { |
| 669 | + for (size_t i = 0; i < len; i++) { |
| 670 | + if (!prv_is_unreserved(str[i])) { |
| 671 | + return true; |
| 672 | + } |
| 673 | + } |
| 674 | + return false; |
| 675 | +} |
| 676 | + |
| 677 | +int memfault_http_urlencode(const char *inbuf, size_t inbuf_len, char *outbuf, size_t outbuf_len) { |
| 678 | + // null check |
| 679 | + if (!inbuf || !outbuf || !inbuf_len || !outbuf_len) { |
| 680 | + return -1; |
| 681 | + } |
| 682 | + |
| 683 | + while (inbuf_len--) { |
| 684 | + if (outbuf_len < 2) { |
| 685 | + // ran out of room before encoding the full input, error. there needs to |
| 686 | + // be 1 spare character for null term |
| 687 | + return -1; |
| 688 | + } |
| 689 | + char c = *inbuf++; |
| 690 | + if (prv_is_unreserved(c)) { |
| 691 | + *outbuf++ = c; |
| 692 | + outbuf_len--; |
| 693 | + } else { |
| 694 | + if (outbuf_len < 4) { |
| 695 | + // not enough room for encoded character and null term |
| 696 | + return -1; |
| 697 | + } |
| 698 | + // paste encoding (+ null term) |
| 699 | + snprintf(outbuf, 4, "%%%02X", (uint8_t)c); |
| 700 | + outbuf += 3; |
| 701 | + outbuf_len -= 3; |
| 702 | + } |
| 703 | + } |
| 704 | + |
| 705 | + // null terminate |
| 706 | + *outbuf = '\0'; |
| 707 | + |
| 708 | + return 0; |
| 709 | +} |
0 commit comments