Skip to content

Commit e86131b

Browse files
committed
MCU8MASS-1827 Add timeout to HttpClient
1 parent 51c2fa5 commit e86131b

File tree

2 files changed

+131
-53
lines changed

2 files changed

+131
-53
lines changed

src/http_client.cpp

Lines changed: 103 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@
1313

1414
// We only use profile 0 to keep things simple we also stick with spId 3
1515
// which we dedicate to HTTPS
16-
#define HTTP_CONFIGURE "AT+SQNHTTPCFG=0,\"%s\",%u,0,\"\",\"\",%u,120,1,3"
16+
#define HTTP_CONFIGURE "AT+SQNHTTPCFG=0,\"%s\",%u,0,\"\",\"\",%u,120,,3"
1717

18-
// Command without any data in it (with quotation marks): 36 bytes
19-
// Max length of doman name: 127 bytes
18+
// Command without any data in it (with quotation marks): 35 bytes
19+
// Max length of domain name: 127 bytes
2020
// Max length of port number: 5 bytes (0-65535)
2121
// TLS enabled: 1 byte
2222
// Termination: 1 byte
23-
// This results in 36 + 127 + 5 + 1 + 1 = 170
24-
#define HTTP_CONFIGURE_SIZE 170
23+
// This results in 35 + 127 + 5 + 1 + 1 = 169
24+
#define HTTP_CONFIGURE_SIZE 169
2525

2626
#define HTTPS_SECURITY_PROFILE_NUMBER 3
2727

@@ -75,14 +75,17 @@ HttpClientClass HttpClient = HttpClientClass::instance();
7575
* @param method POST(0) or PUT(1).
7676
* @param header Optional header.
7777
* @param header_length Length of header.
78+
* @param timeout_ms Timeout in milliseconds for the transmission.
7879
*/
79-
static HttpResponse sendData(const char* endpoint,
80-
const uint8_t* data,
81-
const uint32_t data_length,
82-
const uint8_t method,
83-
const uint8_t* header = NULL,
84-
const uint32_t header_length = 0,
85-
const char* content_type = "") {
80+
static HttpResponse
81+
sendData(const char* endpoint,
82+
const uint8_t* data,
83+
const uint32_t data_length,
84+
const uint8_t method,
85+
const uint8_t* header = NULL,
86+
const uint32_t header_length = 0,
87+
const char* content_type = "",
88+
const uint32_t timeout_ms = HTTP_DEFAULT_TIMEOUT_MS) {
8689

8790
LedCtrl.on(Led::CON, true);
8891

@@ -102,17 +105,33 @@ static HttpResponse sendData(const char* endpoint,
102105
char command[command_length + 1];
103106

104107
// Append +1 for NULL termination
105-
snprintf(command,
106-
command_length + 1,
107-
HTTP_SEND,
108-
method,
109-
endpoint,
110-
(unsigned long)data_length,
111-
content_type,
112-
header == NULL ? "" : (const char*)header);
108+
int bytes_written = snprintf(command,
109+
command_length,
110+
HTTP_SEND,
111+
method,
112+
endpoint,
113+
(unsigned long)data_length,
114+
content_type,
115+
header == NULL ? "" : (const char*)header);
116+
if (bytes_written < 0) {
117+
Log.errorf(
118+
"Failed to write HTTP send command, snprintf returned %d\r\n",
119+
bytes_written);
120+
return HttpResponse{0, 0};
121+
}
122+
123+
if (bytes_written >= (int)command_length) {
124+
Log.errorf("Failed to write HTTP send command, snprintf returned %d "
125+
"but command length is %d\r\n",
126+
bytes_written,
127+
command_length);
128+
return HttpResponse{0, 0};
129+
}
130+
131+
command[bytes_written + 1] = '\0';
113132

114133
LedCtrl.on(Led::DATA, true);
115-
SequansController.writeBytes((uint8_t*)command, command_length, true);
134+
SequansController.writeBytes((uint8_t*)command, bytes_written, true);
116135

117136
// Only send the data payload if there is any
118137
if (data_length > 0) {
@@ -134,7 +153,7 @@ static HttpResponse sendData(const char* endpoint,
134153
_delay_ms(100);
135154

136155
// Now we deliver the payload
137-
SequansController.writeBytes(data, data_length);
156+
SequansController.writeBytes(data, data_length, true);
138157
}
139158

140159
char http_response_buffer[HTTP_RESPONSE_MAX_LENGTH] = "";
@@ -144,7 +163,8 @@ static HttpResponse sendData(const char* endpoint,
144163
// Now we wait for the URC
145164
if (!SequansController.waitForURC(HTTP_RING_URC,
146165
http_response_buffer,
147-
sizeof(http_response_buffer))) {
166+
sizeof(http_response_buffer),
167+
timeout_ms)) {
148168
LedCtrl.off(Led::CON, true);
149169
LedCtrl.off(Led::DATA, true);
150170
Log.warn("Did not get HTTP response before timeout\r\n");
@@ -190,11 +210,13 @@ static HttpResponse sendData(const char* endpoint,
190210
* @param method GET(0), HEAD(1) or DELETE(2).
191211
* @param header Optional header.
192212
* @param header_length Length of header.
213+
* @param timeout_ms Timeout in milliseconds for the query.
193214
*/
194215
static HttpResponse queryData(const char* endpoint,
195216
const uint8_t method,
196217
const uint8_t* header,
197-
const uint32_t header_length) {
218+
const uint32_t header_length,
219+
const uint32_t timeout_ms) {
198220

199221
LedCtrl.on(Led::CON, true);
200222

@@ -211,12 +233,29 @@ static HttpResponse queryData(const char* endpoint,
211233
// Append +1 for NULL termination
212234
char command[command_length + 1];
213235

214-
snprintf(command,
215-
command_length + 1,
216-
HTTP_QUERY,
217-
method,
218-
endpoint,
219-
header == NULL ? "" : (const char*)header);
236+
int bytes_written = snprintf(command,
237+
command_length,
238+
HTTP_QUERY,
239+
method,
240+
endpoint,
241+
header == NULL ? "" : (const char*)header);
242+
243+
if (bytes_written < 0) {
244+
Log.errorf(
245+
"Failed to write HTTP query command, snprintf returned %d\r\n",
246+
bytes_written);
247+
return HttpResponse{0, 0};
248+
}
249+
250+
if (bytes_written >= (int)command_length) {
251+
Log.errorf("Failed to write HTTP query command, snprintf returned %d "
252+
"but command length is %d\r\n",
253+
bytes_written,
254+
command_length);
255+
return HttpResponse{0, 0};
256+
}
257+
258+
command[bytes_written + 1] = '\0';
220259

221260
LedCtrl.on(Led::DATA, true);
222261
SequansController.writeCommand(command);
@@ -227,7 +266,8 @@ static HttpResponse queryData(const char* endpoint,
227266

228267
if (!SequansController.waitForURC(HTTP_RING_URC,
229268
http_response_buffer,
230-
sizeof(http_response_buffer))) {
269+
sizeof(http_response_buffer),
270+
timeout_ms)) {
231271
Log.warn("Did not get HTTP response before timeout\r\n");
232272

233273
LedCtrl.off(Led::DATA, true);
@@ -288,7 +328,8 @@ HttpResponse HttpClientClass::post(const char* endpoint,
288328
const uint32_t data_length,
289329
const uint8_t* header_buffer,
290330
const uint32_t header_length,
291-
const ContentType content_type) {
331+
const ContentType content_type,
332+
const uint32_t timeout_ms) {
292333

293334
// The content type within the Sequans modem is classified by a single
294335
// character (+1 for NULL termination)
@@ -332,63 +373,80 @@ HttpResponse HttpClientClass::post(const char* endpoint,
332373
HTTP_POST_METHOD,
333374
header_buffer,
334375
header_length,
335-
content_type_buffer);
376+
content_type_buffer,
377+
timeout_ms);
336378
}
337379

338380
HttpResponse HttpClientClass::post(const char* endpoint,
339381
const char* data,
340382
const char* header,
341-
const ContentType content_type) {
383+
const ContentType content_type,
384+
const uint32_t timeout_ms) {
342385
return post(endpoint,
343386
(uint8_t*)data,
344387
strlen(data),
345388
(uint8_t*)header,
346389
header == NULL ? 0 : strlen(header),
347-
content_type);
390+
content_type,
391+
timeout_ms);
348392
}
349393

350394
HttpResponse HttpClientClass::put(const char* endpoint,
351395
const uint8_t* data_buffer,
352396
const uint32_t data_length,
353397
const uint8_t* header_buffer,
354-
const uint32_t header_length) {
398+
const uint32_t header_length,
399+
const uint32_t timeout_ms) {
355400
return sendData(endpoint,
356401
data_buffer,
357402
data_length,
358403
HTTP_PUT_METHOD,
359404
header_buffer,
360-
header_length);
405+
header_length,
406+
"",
407+
timeout_ms);
361408
}
362409

363410
HttpResponse HttpClientClass::put(const char* endpoint,
364411
const char* message,
365-
const char* header) {
412+
const char* header,
413+
const uint32_t timeout_ms) {
366414
return put(endpoint,
367415
(uint8_t*)message,
368416
strlen(message),
369417
(uint8_t*)header,
370-
header == NULL ? 0 : strlen(header));
418+
header == NULL ? 0 : strlen(header),
419+
timeout_ms);
371420
}
372421

373-
HttpResponse HttpClientClass::get(const char* endpoint, const char* header) {
422+
HttpResponse HttpClientClass::get(const char* endpoint,
423+
const char* header,
424+
const uint32_t timeout_ms) {
374425
return queryData(endpoint,
375426
HTTP_GET_METHOD,
376427
(uint8_t*)header,
377-
strlen(header));
428+
strlen(header),
429+
timeout_ms);
378430
}
379431

380-
HttpResponse HttpClientClass::head(const char* endpoint, const char* header) {
432+
HttpResponse HttpClientClass::head(const char* endpoint,
433+
const char* header,
434+
const uint32_t timeout_ms) {
381435
return queryData(endpoint,
382436
HTTP_HEAD_METHOD,
383437
(uint8_t*)header,
384-
strlen(header));
438+
strlen(header),
439+
timeout_ms);
385440
}
386441

387-
HttpResponse HttpClientClass::del(const char* endpoint, const char* header) {
442+
HttpResponse HttpClientClass::del(const char* endpoint,
443+
const char* header,
444+
const uint32_t timeout_ms) {
388445
return queryData(endpoint,
389446
HTTP_DELETE_METHOD,
390447
(uint8_t*)header,
391-
strlen(header));
448+
strlen(header),
449+
timeout_ms);
392450
}
393451

394452
int16_t HttpClientClass::readBody(char* buffer, const uint32_t buffer_size) {

src/http_client.h

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include <Arduino.h>
99
#include <stdint.h>
1010

11+
#define HTTP_DEFAULT_TIMEOUT_MS (30000U)
12+
1113
typedef struct {
1214
uint16_t status_code;
1315
uint32_t data_size;
@@ -63,13 +65,15 @@ class HttpClientClass {
6365
* bearers)
6466
* @param header_length Length of the optinal header line.
6567
* @param content_type HTTP content type of the post request.
68+
* @param timeout_ms Timeout in milliseconds to wait for the POST request.
6669
*/
6770
HttpResponse post(const char* endpoint,
6871
const uint8_t* data_buffer,
6972
const uint32_t data_length,
7073
const uint8_t* header_buffer = NULL,
7174
const uint32_t header_length = 0,
72-
const ContentType content_type = CONTENT_TYPE_TEXT_PLAIN);
75+
const ContentType content_type = CONTENT_TYPE_TEXT_PLAIN,
76+
const uint32_t timeout_ms = HTTP_DEFAULT_TIMEOUT_MS);
7377

7478
/**
7579
* @brief Issues a post to the host configured. Will block until operation
@@ -81,11 +85,13 @@ class HttpClientClass {
8185
* @param header Optional header line (e.g. for authorization
8286
* bearers).
8387
* @param content_type HTTP content type of the post request.
88+
* @param timeout_ms Timeout in milliseconds to wait for the POST request.
8489
*/
8590
HttpResponse post(const char* endpoint,
8691
const char* data,
8792
const char* header = NULL,
88-
const ContentType content_type = CONTENT_TYPE_TEXT_PLAIN);
93+
const ContentType content_type = CONTENT_TYPE_TEXT_PLAIN,
94+
const uint32_t timeout_ms = HTTP_DEFAULT_TIMEOUT_MS);
8995

9096
/**
9197
* @brief Issues a put to the host configured. Will block until operation is
@@ -98,12 +104,14 @@ class HttpClientClass {
98104
* @param header_buffer Optional header line (e.g. for authorization
99105
* bearers)
100106
* @param header_length Length of the optinal header line.
107+
* @param timeout_ms Timeout in milliseconds to wait for the PUT request.
101108
*/
102109
HttpResponse put(const char* endpoint,
103110
const uint8_t* data_buffer,
104111
const uint32_t data_length,
105112
const uint8_t* header_buffer = NULL,
106-
const uint32_t header_length = 0);
113+
const uint32_t header_length = 0,
114+
const uint32_t timeout_ms = HTTP_DEFAULT_TIMEOUT_MS);
107115

108116
/**
109117
* @brief Issues a put to the host configured. Will block until operation is
@@ -114,9 +122,12 @@ class HttpClientClass {
114122
* @param data The data payload.
115123
* @param header Optional header line (e.g. for authorization
116124
* bearers).
125+
* @param timeout_ms Timeout in milliseconds to wait for the PUT request.
117126
*/
118-
HttpResponse
119-
put(const char* endpoint, const char* data, const char* header = NULL);
127+
HttpResponse put(const char* endpoint,
128+
const char* data,
129+
const char* header = NULL,
130+
const uint32_t timeout_ms = HTTP_DEFAULT_TIMEOUT_MS);
120131

121132
/**
122133
* @brief Issues a get from the host configured. Will block until operation
@@ -127,8 +138,11 @@ class HttpClientClass {
127138
* after the domain.
128139
* @param header Optional header line (e.g. for authorization
129140
* bearers).
141+
* @param timeout_ms Timeout in milliseconds to wait for the GET request.
130142
*/
131-
HttpResponse get(const char* endpoint, const char* header = NULL);
143+
HttpResponse get(const char* endpoint,
144+
const char* header = NULL,
145+
const uint32_t timeout_ms = HTTP_DEFAULT_TIMEOUT_MS);
132146

133147
/**
134148
* @brief Issues a head from the host configured. Will block until operation
@@ -138,8 +152,11 @@ class HttpClientClass {
138152
* after the domain.
139153
* @param header Optional header line (e.g. for authorization
140154
* bearers).
155+
* @param timeout_ms Timeout in milliseconds to wait for the HEAD request.
141156
*/
142-
HttpResponse head(const char* endpoint, const char* header = NULL);
157+
HttpResponse head(const char* endpoint,
158+
const char* header = NULL,
159+
const uint32_t timeout_ms = HTTP_DEFAULT_TIMEOUT_MS);
143160

144161
/**
145162
* @brief Issues a delete from the host configured. Will block until
@@ -149,8 +166,11 @@ class HttpClientClass {
149166
* after the domain.
150167
* @param header Optional header line (e.g. for authorization
151168
* bearers).
169+
* @param timeout_ms Timeout in milliseconds to wait for the DELETE request.
152170
*/
153-
HttpResponse del(const char* endpoint, const char* header = NULL);
171+
HttpResponse del(const char* endpoint,
172+
const char* header = NULL,
173+
const uint32_t timeout_ms = HTTP_DEFAULT_TIMEOUT_MS);
154174

155175
/**
156176
* @brief Reads the body of a response after a HTTP call. Note that the

0 commit comments

Comments
 (0)