Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 69549c8

Browse files
feat(http-client): add support for collecting all HTTP headers, close #10802
1 parent 20c0dde commit 69549c8

File tree

4 files changed

+125
-30
lines changed

4 files changed

+125
-30
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#include <Arduino.h>
2+
3+
#include <WiFi.h>
4+
#include <assert.h>
5+
#include <HTTPClient.h>
6+
7+
#define USE_SERIAL Serial
8+
9+
// Enable or disable collecting all headers
10+
#define COLLECT_ALL_HEADERS true
11+
12+
void setup() {
13+
14+
USE_SERIAL.begin(115200);
15+
16+
USE_SERIAL.println();
17+
USE_SERIAL.println();
18+
USE_SERIAL.println();
19+
20+
for (uint8_t t = 4; t > 0; t--) {
21+
USE_SERIAL.printf("[SETUP] WAIT %d...\n", t);
22+
USE_SERIAL.flush();
23+
delay(1000);
24+
}
25+
26+
WiFi.begin("SSID", "PASSWORD");
27+
28+
while (WiFi.status() != WL_CONNECTED) {
29+
delay(500);
30+
USE_SERIAL.print(".");
31+
}
32+
USE_SERIAL.println();
33+
USE_SERIAL.println("Connected to WiFi: " + WiFi.SSID());
34+
}
35+
36+
void loop() {
37+
38+
HTTPClient http;
39+
40+
USE_SERIAL.print("[HTTP] Preparing HTTP request...\n");
41+
// This page will return the headers we want to test + some others
42+
http.begin("https://httpbingo.org/response-headers?x-custom-header=value:42");
43+
44+
#if COLLECT_ALL_HEADERS
45+
// Collect all headers
46+
http.collectAllHeaders();
47+
#else
48+
// Collect specific headers, only that one will be stored
49+
const char *headerKeys[] = {"x-custom-header"};
50+
const size_t headerKeysCount = sizeof(headerKeys) / sizeof(headerKeys[0]);
51+
http.collectHeaders(headerKeys, headerKeysCount);
52+
#endif
53+
54+
USE_SERIAL.print("[HTTP] Sending HTTP GET request...\n");
55+
// start connection and send HTTP header
56+
int httpCode = http.GET();
57+
58+
// httpCode will be negative on error
59+
if (httpCode > 0) {
60+
// HTTP header has been send and Server response header has been handled
61+
USE_SERIAL.printf("[HTTP] GET response code: %d\n", httpCode);
62+
63+
USE_SERIAL.println("[HTTP] Headers collected:");
64+
for (size_t i = 0; i < http.headers(); i++) {
65+
USE_SERIAL.printf("[HTTP] - '%s': '%s'\n", http.headerName(i).c_str(), http.header(i).c_str());
66+
}
67+
68+
USE_SERIAL.println("[HTTP] Has header 'x-custom-header'? " + String(http.hasHeader("x-custom-header")) + " (expected true)");
69+
USE_SERIAL.printf("[HTTP] x-custom-header: '%s' (expected 'value:42')\n", http.header("x-custom-header").c_str());
70+
USE_SERIAL.printf("[HTTP] non-existing-header: '%s' (expected empty string)\n", http.header("non-existing-header").c_str());
71+
72+
#if COLLECT_ALL_HEADERS
73+
// Server response with multiple headers, one of them is 'server'
74+
USE_SERIAL.println("[HTTP] Has header 'server'? " + String(http.hasHeader("server")) + " (expected true)");
75+
USE_SERIAL.printf("[HTTP] server: '%s'\n", http.header("server").c_str());
76+
#endif
77+
78+
} else {
79+
USE_SERIAL.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
80+
}
81+
82+
http.end();
83+
84+
Serial.println("[HTTP] end connection\n\n");
85+
delay(5000);
86+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"requires_any": [
3+
"CONFIG_SOC_WIFI_SUPPORTED=y",
4+
"CONFIG_ESP_WIFI_REMOTE_ENABLED=y"
5+
]
6+
}

‎libraries/HTTPClient/src/HTTPClient.cpp‎

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,6 @@ HTTPClient::~HTTPClient() {
9090
if (_client) {
9191
_client->stop();
9292
}
93-
if (_currentHeaders) {
94-
delete[] _currentHeaders;
95-
}
9693
if (_tcpDeprecated) {
9794
_tcpDeprecated.reset(nullptr);
9895
}
@@ -564,9 +561,12 @@ int HTTPClient::sendRequest(const char *type, uint8_t *payload, size_t size) {
564561
bool redirect = false;
565562
uint16_t redirectCount = 0;
566563
do {
567-
// wipe out any existing headers from previous request
568-
for (size_t i = 0; i < _headerKeysCount; i++) {
569-
if (_currentHeaders[i].value.length() > 0) {
564+
// wipe out any existing headers from previous request, but preserve the keys if collecting specific headers
565+
if (_collectAllHeaders) {
566+
_currentHeaders.clear();
567+
} else {
568+
// Only clear values, keep the keys for specific header collection
569+
for (size_t i = 0; i < _currentHeaders.size(); ++i) {
570570
_currentHeaders[i].value.clear();
571571
}
572572
}
@@ -1015,19 +1015,24 @@ void HTTPClient::addHeader(const String &name, const String &value, bool first,
10151015
}
10161016
}
10171017

1018+
void HTTPClient::collectAllHeaders(bool collectAll) {
1019+
_collectAllHeaders = collectAll;
1020+
}
1021+
10181022
void HTTPClient::collectHeaders(const char *headerKeys[], const size_t headerKeysCount) {
1019-
_headerKeysCount = headerKeysCount;
1020-
if (_currentHeaders) {
1021-
delete[] _currentHeaders;
1023+
if (_collectAllHeaders) {
1024+
log_w("collectHeaders is ignored when collectAllHeaders is set");
1025+
return;
10221026
}
1023-
_currentHeaders = new RequestArgument[_headerKeysCount];
1024-
for (size_t i = 0; i < _headerKeysCount; i++) {
1027+
_currentHeaders.clear();
1028+
_currentHeaders.resize(headerKeysCount);
1029+
for (size_t i = 0; i < headerKeysCount; i++) {
10251030
_currentHeaders[i].key = headerKeys[i];
10261031
}
10271032
}
10281033

10291034
String HTTPClient::header(const char *name) {
1030-
for (size_t i = 0; i < _headerKeysCount; ++i) {
1035+
for (size_t i = 0; i < _currentHeaders.size(); ++i) {
10311036
if (_currentHeaders[i].key.equalsIgnoreCase(name)) {
10321037
return _currentHeaders[i].value;
10331038
}
@@ -1036,25 +1041,25 @@ String HTTPClient::header(const char *name) {
10361041
}
10371042

10381043
String HTTPClient::header(size_t i) {
1039-
if (i < _headerKeysCount) {
1044+
if (i < _currentHeaders.size()) {
10401045
return _currentHeaders[i].value;
10411046
}
10421047
return String();
10431048
}
10441049

10451050
String HTTPClient::headerName(size_t i) {
1046-
if (i < _headerKeysCount) {
1051+
if (i < _currentHeaders.size()) {
10471052
return _currentHeaders[i].key;
10481053
}
10491054
return String();
10501055
}
10511056

10521057
int HTTPClient::headers() {
1053-
return _headerKeysCount;
1058+
return _currentHeaders.size();
10541059
}
10551060

10561061
bool HTTPClient::hasHeader(const char *name) {
1057-
for (size_t i = 0; i < _headerKeysCount; ++i) {
1062+
for (size_t i = 0; i < _currentHeaders.size(); ++i) {
10581063
if ((_currentHeaders[i].key.equalsIgnoreCase(name)) && (_currentHeaders[i].value.length() > 0)) {
10591064
return true;
10601065
}
@@ -1238,17 +1243,14 @@ int HTTPClient::handleHeaderResponse() {
12381243
setCookie(date, headerValue);
12391244
}
12401245

1241-
for (size_t i = 0; i < _headerKeysCount; i++) {
1242-
if (_currentHeaders[i].key.equalsIgnoreCase(headerName)) {
1243-
// Uncomment the following lines if you need to add support for multiple headers with the same key:
1244-
// if (!_currentHeaders[i].value.isEmpty()) {
1245-
// // Existing value, append this one with a comma
1246-
// _currentHeaders[i].value += ',';
1247-
// _currentHeaders[i].value += headerValue;
1248-
// } else {
1249-
_currentHeaders[i].value = headerValue;
1250-
// }
1251-
break; // We found a match, stop looking
1246+
if (_collectAllHeaders && headerName.length() > 0) {
1247+
_currentHeaders.emplace_back(headerName, headerValue);
1248+
} else {
1249+
for (size_t i = 0; i < _currentHeaders.size(); ++i) {
1250+
if (_currentHeaders[i].key.equalsIgnoreCase(headerName)) {
1251+
_currentHeaders[i].value = headerValue;
1252+
break; // We found a match, stop looking
1253+
}
12521254
}
12531255
}
12541256
}

‎libraries/HTTPClient/src/HTTPClient.h‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
#include <NetworkClientSecure.h>
3939
#endif // HTTPCLIENT_NOSECURE
4040

41-
/// Cookie jar support
41+
/// Cookie jar and header support
4242
#include <vector>
4343

4444
#define HTTPCLIENT_DEFAULT_TCP_TIMEOUT (5000)
@@ -238,6 +238,7 @@ class HTTPClient {
238238
void addHeader(const String &name, const String &value, bool first = false, bool replace = true);
239239

240240
/// Response handling
241+
void collectAllHeaders(bool collectAll = true);
241242
void collectHeaders(const char *headerKeys[], const size_t headerKeysCount);
242243
String header(const char *name); // get request header value by name
243244
String header(size_t i); // get request header value by number
@@ -294,6 +295,7 @@ class HTTPClient {
294295
uint16_t _tcpTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT;
295296
bool _useHTTP10 = false;
296297
bool _secure = false;
298+
bool _collectAllHeaders = false;
297299

298300
String _uri;
299301
String _protocol;
@@ -304,8 +306,7 @@ class HTTPClient {
304306
String _acceptEncoding = "identity;q=1,chunked;q=0.1,*;q=0";
305307

306308
/// Response handling
307-
RequestArgument *_currentHeaders = nullptr;
308-
size_t _headerKeysCount = 0;
309+
std::vector<RequestArgument> _currentHeaders;
309310

310311
int _returnCode = 0;
311312
int _size = -1;

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /