Skip to content

Commit f4a82cf

Browse files
committed
MCU8MASS-933 Add support for headers in HTTP client
1 parent c149963 commit f4a82cf

File tree

5 files changed

+266
-66
lines changed

5 files changed

+266
-66
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,11 @@ No changes
123123
* Fix a bug where it would take some time before the board was actually in power down mode
124124
* Fix a bug where waking up from power down mode would reset the board
125125
* Fix a bug where it was wrongly reported that the SIM card was not ready
126+
127+
# 1.3.2
128+
129+
## Features
130+
* Add ability to add HTTP headers
131+
132+
## Changes
133+
* Security profile patch is removed as this is now taken care of by NTP synchronization
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* @brief This example demonstrates HTTPS GET request with appended
3+
* headers. Adding header also works for the other methods such as POST, PUT,
4+
* HEAD and DELETE as well as for plain HTTP without TLS.
5+
*/
6+
#include <Arduino.h>
7+
#include <http_client.h>
8+
#include <led_ctrl.h>
9+
#include <log.h>
10+
#include <lte.h>
11+
12+
#define DOMAIN "httpbin.org"
13+
14+
void testHttp();
15+
16+
void setup() {
17+
LedCtrl.begin();
18+
LedCtrl.startupCycle();
19+
20+
Log.begin(115200);
21+
Log.info("Starting HTTPS with header example");
22+
23+
// Start LTE modem and connect to the operator
24+
if (!Lte.begin()) {
25+
Log.error("Failed to connect to the operator");
26+
return;
27+
}
28+
29+
Log.infof("Connected to operator: %s\r\n", Lte.getOperator().c_str());
30+
31+
Log.info("Performing GET with header...");
32+
33+
// For HTTP without TLS, use: HttpClient.configure(DOMAIN, 80, false)
34+
if (!HttpClient.configure(DOMAIN, 443, true)) {
35+
Log.info("Failed to configure https client\r\n");
36+
return;
37+
}
38+
39+
// For other methods such as POST, use:
40+
// HttpClient.post("<endpoint>", "<data>", "Authorization: Bearer");
41+
HttpResponse response = HttpClient.get("/get", "Authorization: Bearer");
42+
43+
Log.infof("GET - status code: %u, data size: %u\r\n",
44+
response.status_code,
45+
response.data_size);
46+
47+
// Add some extra bytes for termination
48+
String response_data = HttpClient.readBody();
49+
50+
if (response_data != "") {
51+
Log.infof("Response: %s\r\n", response_data.c_str());
52+
}
53+
}
54+
55+
void loop() {}

src/http_client.cpp

Lines changed: 115 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@
2525
#define SECURITY_PROFILE_PREFIX_LENGTH 11
2626
#define HTTPS_SECURITY_PROFILE_NUMBER '3'
2727

28-
#define HTTP_SEND "AT+SQNHTTPSND=0,%u,\"%s\",%lu"
28+
#define HTTP_SEND "AT+SQNHTTPSND=0,%u,\"%s\",%lu,\"\",\"%s\""
2929
#define HTTP_RECEIVE "AT+SQNHTTPRCV=0,%lu"
30-
#define HTTP_QUERY "AT+SQNHTTPQRY=0,%u,\"%s\""
30+
#define HTTP_QUERY "AT+SQNHTTPQRY=0,%u,\"%s\",\"%s\""
3131

3232
#define HTTP_RING_URC "SQNHTTPRING"
3333

@@ -63,39 +63,60 @@ HttpClientClass HttpClient = HttpClientClass::instance();
6363
* Issues an AT command to the LTE modem.
6464
*
6565
* @param endpoint Destination of payload, part after host name in URL.
66-
* @param buffer Payload to send.
67-
* @param buffer_size Size of payload.
66+
* @param data Payload to send.
67+
* @param data_length Length of payload.
6868
* @param method POST(0) or PUT(1).
69+
* @param header Optional header.
70+
* @param header_length Length of header.
6971
*/
7072
static HttpResponse sendData(const char* endpoint,
71-
const uint8_t* buffer,
72-
const uint32_t buffer_size,
73-
const uint8_t method) {
73+
const uint8_t* data,
74+
const uint32_t data_length,
75+
const uint8_t method,
76+
const uint8_t* header = NULL,
77+
const uint32_t header_length = 0) {
7478

7579
HttpResponse http_response = {0, 0};
7680

7781
// Setup and transmit SEND command before sending the data
78-
const uint32_t digits_in_data_length = trunc(log10(buffer_size)) + 1;
82+
const uint32_t digits_in_data_length = trunc(log10(data_length)) + 1;
83+
84+
const uint32_t command_length = strlen(HTTP_SEND) + strlen(endpoint) +
85+
digits_in_data_length + header_length;
86+
87+
// Append +1 for NULL termination
88+
char command[command_length + 1];
89+
90+
// Append +1 for NULL termination
91+
snprintf(command,
92+
command_length + 1,
93+
HTTP_SEND,
94+
method,
95+
endpoint,
96+
(unsigned long)data_length,
97+
header == NULL ? "" : (const char*)header);
98+
99+
SequansController.writeBytes((uint8_t*)command, command_length, true);
100+
101+
// Only send the data payload if there is any
102+
if (data_length > 0) {
103+
104+
if (!SequansController.waitForByte(HTTP_SEND_START_CHARACTER,
105+
HTTP_TIMEOUT)) {
106+
Log.error("Timed out whilst waiting on delivering the HTTP "
107+
"payload. Is the "
108+
"server online?");
109+
return http_response;
110+
}
79111

80-
char command[strlen(HTTP_SEND) + strlen(endpoint) + digits_in_data_length];
81-
sprintf(command, HTTP_SEND, method, endpoint, (unsigned long)buffer_size);
82-
SequansController.writeBytes((uint8_t*)command, strlen(command), true);
112+
// Wait some before delivering the payload. The modem might hang if we
113+
// deliver it too quickly
114+
delay(100);
83115

84-
if (!SequansController.waitForByte(HTTP_SEND_START_CHARACTER,
85-
HTTP_TIMEOUT)) {
86-
Log.error(
87-
"Timed out whilst waiting on delivering the HTTP payload. Is the "
88-
"server online?");
89-
return http_response;
116+
// Now we deliver the payload
117+
SequansController.writeBytes(data, data_length);
90118
}
91119

92-
// Wait some before delivering the payload. The modem might hang if we
93-
// deliver it too quickly
94-
delay(100);
95-
96-
// Now we deliver the payload
97-
SequansController.writeBytes(buffer, buffer_size);
98-
99120
char http_response_buffer[HTTP_RESPONSE_MAX_LENGTH] = "";
100121
char http_status_code_buffer[HTTP_RESPONSE_STATUS_CODE_LENGTH + 1] = "";
101122
char data_size_buffer[HTTP_RESPONSE_DATA_SIZE_LENGTH] = "";
@@ -141,18 +162,30 @@ static HttpResponse sendData(const char* endpoint,
141162
*
142163
* @param endpoint Destination of retrieve, part after host name in URL.
143164
* @param method GET(0), HEAD(1) or DELETE(2).
165+
* @param header Optional header.
166+
* @param header_length Length of header.
144167
*/
145-
static HttpResponse queryData(const char* endpoint, const uint8_t method) {
168+
static HttpResponse queryData(const char* endpoint,
169+
const uint8_t method,
170+
const uint8_t* header,
171+
const uint32_t header_length) {
146172

147173
HttpResponse http_response = {0, 0};
148174

149-
// Fix for bringing the modem out of idling and prevent timeout whilst
150-
// waiting for modem response during the next AT command
151-
SequansController.writeCommand("AT");
152-
153175
// Set up and send the query
154-
char command[strlen(HTTP_QUERY) + strlen(endpoint)];
155-
sprintf(command, HTTP_QUERY, method, endpoint);
176+
const uint32_t command_length = strlen(HTTP_QUERY) + strlen(endpoint) +
177+
header_length;
178+
179+
// Append +1 for NULL termination
180+
char command[command_length + 1];
181+
182+
snprintf(command,
183+
command_length + 1,
184+
HTTP_QUERY,
185+
method,
186+
endpoint,
187+
header == NULL ? "" : (const char*)header);
188+
156189
SequansController.writeCommand(command);
157190

158191
char http_response_buffer[HTTP_RESPONSE_MAX_LENGTH] = "";
@@ -243,35 +276,70 @@ bool HttpClientClass::configure(const char* host,
243276
}
244277

245278
HttpResponse HttpClientClass::post(const char* endpoint,
246-
const uint8_t* buffer,
247-
const uint32_t buffer_size) {
248-
return sendData(endpoint, buffer, buffer_size, HTTP_POST_METHOD);
279+
const uint8_t* data_buffer,
280+
const uint32_t data_length,
281+
const uint8_t* header_buffer,
282+
const uint32_t header_length) {
283+
return sendData(endpoint,
284+
data_buffer,
285+
data_length,
286+
HTTP_POST_METHOD,
287+
header_buffer,
288+
header_length);
249289
}
250290

251-
HttpResponse HttpClientClass::post(const char* endpoint, const char* message) {
252-
return post(endpoint, (uint8_t*)message, strlen(message));
291+
HttpResponse HttpClientClass::post(const char* endpoint,
292+
const char* data,
293+
const char* header) {
294+
return post(endpoint,
295+
(uint8_t*)data,
296+
strlen(data),
297+
(uint8_t*)header,
298+
strlen(header));
253299
}
254300

255301
HttpResponse HttpClientClass::put(const char* endpoint,
256-
const uint8_t* buffer,
257-
const uint32_t buffer_size) {
258-
return sendData(endpoint, buffer, buffer_size, HTTP_PUT_METHOD);
302+
const uint8_t* data_buffer,
303+
const uint32_t data_length,
304+
const uint8_t* header_buffer,
305+
const uint32_t header_length) {
306+
return sendData(endpoint,
307+
data_buffer,
308+
data_length,
309+
HTTP_PUT_METHOD,
310+
header_buffer,
311+
header_length);
259312
}
260313

261-
HttpResponse HttpClientClass::put(const char* endpoint, const char* message) {
262-
return put(endpoint, (uint8_t*)message, strlen(message));
314+
HttpResponse HttpClientClass::put(const char* endpoint,
315+
const char* message,
316+
const char* header) {
317+
return put(endpoint,
318+
(uint8_t*)message,
319+
strlen(message),
320+
(uint8_t*)header,
321+
strlen(header));
263322
}
264323

265-
HttpResponse HttpClientClass::get(const char* endpoint) {
266-
return queryData(endpoint, HTTP_GET_METHOD);
324+
HttpResponse HttpClientClass::get(const char* endpoint, const char* header) {
325+
return queryData(endpoint,
326+
HTTP_GET_METHOD,
327+
(uint8_t*)header,
328+
strlen(header));
267329
}
268330

269-
HttpResponse HttpClientClass::head(const char* endpoint) {
270-
return queryData(endpoint, HTTP_HEAD_METHOD);
331+
HttpResponse HttpClientClass::head(const char* endpoint, const char* header) {
332+
return queryData(endpoint,
333+
HTTP_HEAD_METHOD,
334+
(uint8_t*)header,
335+
strlen(header));
271336
}
272337

273-
HttpResponse HttpClientClass::del(const char* endpoint) {
274-
return queryData(endpoint, HTTP_DELETE_METHOD);
338+
HttpResponse HttpClientClass::del(const char* endpoint, const char* header) {
339+
return queryData(endpoint,
340+
HTTP_DELETE_METHOD,
341+
(uint8_t*)header,
342+
strlen(header));
275343
}
276344

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

0 commit comments

Comments
 (0)