Skip to content

Commit 6c56bb3

Browse files
authored
Merge branch 'ESP32Async:main' into feature/asyncfileresponse-gzip-etag
2 parents e9a5bda + 4b14b0a commit 6c56bb3

File tree

10 files changed

+109
-44
lines changed

10 files changed

+109
-44
lines changed

.github/workflows/build-esp32.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
run: arduino-cli lib install ArduinoJson
3333

3434
- name: Install AsyncTCP (ESP32)
35-
run: ARDUINO_LIBRARY_ENABLE_UNSAFE_INSTALL=true arduino-cli lib install --git-url https://github.com/ESP32Async/AsyncTCP#v3.4.4
35+
run: ARDUINO_LIBRARY_ENABLE_UNSAFE_INSTALL=true arduino-cli lib install --git-url https://github.com/ESP32Async/AsyncTCP#v3.4.5
3636

3737
- name: Checkout
3838
uses: actions/checkout@v4
@@ -63,7 +63,7 @@ jobs:
6363
run: arduino-cli lib install ArduinoJson
6464

6565
- name: Install AsyncTCP (ESP32)
66-
run: ARDUINO_LIBRARY_ENABLE_UNSAFE_INSTALL=true arduino-cli lib install --git-url https://github.com/ESP32Async/AsyncTCP#v3.4.4
66+
run: ARDUINO_LIBRARY_ENABLE_UNSAFE_INSTALL=true arduino-cli lib install --git-url https://github.com/ESP32Async/AsyncTCP#v3.4.5
6767

6868
- name: Checkout
6969
uses: actions/checkout@v4

examples/HeaderManipulation/HeaderManipulation.ino

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,29 @@ void setup() {
7979
)
8080
.addMiddleware(&headerFree);
8181

82+
// curl -v http://192.168.4.1/
83+
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
84+
AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", "Hello, world!");
85+
response->addHeader(AsyncWebHeader::parse("X-Test-1: value1"));
86+
response->addHeader(AsyncWebHeader::parse("X-Test-2:value2"));
87+
response->addHeader(AsyncWebHeader::parse("X-Test-3:"));
88+
response->addHeader(AsyncWebHeader::parse("X-Test-4: "));
89+
response->addHeader(AsyncWebHeader::parse(""));
90+
response->addHeader(AsyncWebHeader::parse(":"));
91+
request->send(response);
92+
/**
93+
< HTTP/1.1 200 OK
94+
< connection: close
95+
< X-Test-1: value1
96+
< X-Test-2: value2
97+
< X-Test-3:
98+
< X-Test-4:
99+
< accept-ranges: none
100+
< content-length: 13
101+
< content-type: text/plain
102+
*/
103+
});
104+
82105
server.begin();
83106
}
84107

idf_component.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ dependencies:
2929
version: "^3.1.1"
3030
require: public
3131
esp32async/asynctcp:
32-
version: "^3.4.4"
32+
version: "^3.4.5"
3333
require: public
3434
bblanchon/arduinojson:
3535
version: "^7.4.2"

library.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
{
2626
"owner": "ESP32Async",
2727
"name": "AsyncTCP",
28-
"version": "^3.4.4",
28+
"version": "^3.4.5",
2929
"platforms": [
3030
"espressif32",
3131
"libretiny"

pioarduino_examples/IncreaseMaxSockets/platformio.ini

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[env]
22
framework = arduino
3-
platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.20/platform-espressif32.zip
3+
platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.21/platform-espressif32.zip
44
build_flags =
55
-Og
66
-Wall -Wextra
@@ -17,7 +17,7 @@ monitor_filters = esp32_exception_decoder, log2file
1717
lib_compat_mode = strict
1818
lib_ldf_mode = chain
1919
lib_deps =
20-
ESP32Async/AsyncTCP @ 3.4.4
20+
ESP32Async/AsyncTCP @ 3.4.5
2121
ESP32Async/ESpAsyncWebServer @ 3.7.0
2222

2323
custom_sdkconfig = CONFIG_LWIP_MAX_ACTIVE_TCP=32

platformio.ini

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ src_dir = examples/PerfTests
3838

3939
[env]
4040
framework = arduino
41-
platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.20/platform-espressif32.zip
41+
platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.21/platform-espressif32.zip
4242
board = esp32dev
4343
build_flags =
4444
-Og
@@ -60,7 +60,7 @@ lib_compat_mode = strict
6060
lib_ldf_mode = chain
6161
lib_deps =
6262
bblanchon/ArduinoJson @ 7.4.2
63-
ESP32Async/AsyncTCP @ 3.4.4
63+
ESP32Async/AsyncTCP @ 3.4.5
6464
board_build.partitions = partitions-4MB.csv
6565
board_build.filesystem = littlefs
6666

@@ -76,7 +76,7 @@ platform = https://github.com/pioarduino/platform-espressif32/releases/download/
7676

7777
[env:arduino-3-no-json]
7878
lib_deps =
79-
ESP32Async/AsyncTCP @ 3.4.4
79+
ESP32Async/AsyncTCP @ 3.4.5
8080

8181
[env:arduino-3-latest-asynctcp]
8282
lib_deps =
@@ -138,7 +138,7 @@ board = ${sysenv.PIO_BOARD}
138138
[env:ci-arduino-3-no-json]
139139
board = ${sysenv.PIO_BOARD}
140140
lib_deps =
141-
ESP32Async/AsyncTCP @ 3.4.4
141+
ESP32Async/AsyncTCP @ 3.4.5
142142

143143
[env:ci-arduino-3-latest-asynctcp]
144144
lib_deps =

src/AsyncWebHeader.cpp

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,32 @@
33

44
#include <ESPAsyncWebServer.h>
55

6-
AsyncWebHeader::AsyncWebHeader(const String &data) {
6+
const AsyncWebHeader AsyncWebHeader::parse(const char *data) {
7+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers
8+
// In HTTP/1.X, a header is a case-insensitive name followed by a colon, then optional whitespace which will be ignored, and finally by its value
79
if (!data) {
8-
return;
10+
return AsyncWebHeader(); // nullptr
911
}
10-
int index = data.indexOf(':');
11-
if (index < 0) {
12-
return;
12+
if (data[0] == '\0') {
13+
return AsyncWebHeader(); // empty string
1314
}
14-
if (data.indexOf('\r') >= 0 || data.indexOf('\n') >= 0) {
15-
// Note: do not log as info, warn or error because this could flood the logs without being able to filter this out
16-
#ifdef ESP32
17-
log_v("Invalid character in HTTP header");
18-
#endif
19-
return; // Invalid header format
15+
if (strchr(data, '\n') || strchr(data, '\r')) {
16+
return AsyncWebHeader(); // Invalid header format
2017
}
21-
_name = data.substring(0, index);
22-
_value = data.substring(index + 2);
23-
}
24-
25-
String AsyncWebHeader::toString() const {
26-
String str;
27-
if (str.reserve(_name.length() + _value.length() + 2)) {
28-
str.concat(_name);
29-
str.concat((char)0x3a);
30-
str.concat((char)0x20);
31-
str.concat(_value);
32-
str.concat(asyncsrv::T_rn);
33-
} else {
34-
#ifdef ESP32
35-
log_e("Failed to allocate");
36-
#endif
18+
char *colon = strchr(data, ':');
19+
if (!colon) {
20+
return AsyncWebHeader(); // separator not found
21+
}
22+
if (colon == data) {
23+
return AsyncWebHeader(); // Header name cannot be empty
24+
}
25+
char *startOfValue = colon + 1; // Skip the colon
26+
// skip one optional whitespace after the colon
27+
if (*startOfValue == ' ') {
28+
startOfValue++;
3729
}
38-
return str;
30+
String name;
31+
name.reserve(colon - data);
32+
name.concat(data, colon - data);
33+
return AsyncWebHeader(name, String(startOfValue));
3934
}

src/ESPAsyncWebServer.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,20 +135,39 @@ class AsyncWebHeader {
135135
String _value;
136136

137137
public:
138+
AsyncWebHeader() {}
138139
AsyncWebHeader(const AsyncWebHeader &) = default;
140+
AsyncWebHeader(AsyncWebHeader &&) = default;
139141
AsyncWebHeader(const char *name, const char *value) : _name(name), _value(value) {}
140142
AsyncWebHeader(const String &name, const String &value) : _name(name), _value(value) {}
141-
AsyncWebHeader(const String &data);
143+
144+
#ifndef ESP8266
145+
[[deprecated("Use AsyncWebHeader::parse(data) instead")]]
146+
#endif
147+
AsyncWebHeader(const String &data)
148+
: AsyncWebHeader(parse(data)){};
142149

143150
AsyncWebHeader &operator=(const AsyncWebHeader &) = default;
151+
AsyncWebHeader &operator=(AsyncWebHeader &&other) = default;
144152

145153
const String &name() const {
146154
return _name;
147155
}
148156
const String &value() const {
149157
return _value;
150158
}
159+
151160
String toString() const;
161+
162+
// returns true if the header is valid
163+
operator bool() const {
164+
return _name.length();
165+
}
166+
167+
static const AsyncWebHeader parse(const String &data) {
168+
return parse(data.c_str());
169+
}
170+
static const AsyncWebHeader parse(const char *data);
152171
};
153172

154173
/*
@@ -1034,6 +1053,10 @@ class AsyncWebServerResponse {
10341053
setContentType(type.c_str());
10351054
}
10361055
void setContentType(const char *type);
1056+
bool addHeader(AsyncWebHeader &&header, bool replaceExisting = true);
1057+
bool addHeader(const AsyncWebHeader &header, bool replaceExisting = true) {
1058+
return header && addHeader(header.name(), header.value(), replaceExisting);
1059+
}
10371060
bool addHeader(const char *name, const char *value, bool replaceExisting = true);
10381061
bool addHeader(const String &name, const String &value, bool replaceExisting = true) {
10391062
return addHeader(name.c_str(), value.c_str(), replaceExisting);

src/WebRequest.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -341,10 +341,10 @@ bool AsyncWebServerRequest::_parseReqHead() {
341341
}
342342

343343
bool AsyncWebServerRequest::_parseReqHeader() {
344-
int index = _temp.indexOf(':');
345-
if (index) {
346-
String name(_temp.substring(0, index));
347-
String value(_temp.substring(index + 2));
344+
AsyncWebHeader header = AsyncWebHeader::parse(_temp);
345+
if (header) {
346+
const String &name = header.name();
347+
const String &value = header.value();
348348
if (name.equalsIgnoreCase(T_Host)) {
349349
_host = value;
350350
} else if (name.equalsIgnoreCase(T_Content_Type)) {
@@ -392,7 +392,7 @@ bool AsyncWebServerRequest::_parseReqHeader() {
392392
_reqconntype = RCT_EVENT;
393393
}
394394
}
395-
_headers.emplace_back(name, value);
395+
_headers.emplace_back(std::move(header));
396396
}
397397
#if defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350) || defined(LIBRETINY)
398398
// Ancient PRI core does not have String::clear() method 8-()

src/WebResponses.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,30 @@ bool AsyncWebServerResponse::headerMustBePresentOnce(const String &name) {
134134
return false;
135135
}
136136

137+
bool AsyncWebServerResponse::addHeader(AsyncWebHeader &&header, bool replaceExisting) {
138+
if (!header) {
139+
return false; // invalid header
140+
}
141+
for (auto i = _headers.begin(); i != _headers.end(); ++i) {
142+
if (i->name().equalsIgnoreCase(header.name())) {
143+
// header already set
144+
if (replaceExisting) {
145+
// remove, break and add the new one
146+
_headers.erase(i);
147+
break;
148+
} else if (headerMustBePresentOnce(i->name())) { // we can have only one header with that name
149+
// do not update
150+
return false;
151+
} else {
152+
break; // accept multiple headers with the same name
153+
}
154+
}
155+
}
156+
// header was not found found, or existing one was removed
157+
_headers.emplace_back(std::move(header));
158+
return true;
159+
}
160+
137161
bool AsyncWebServerResponse::addHeader(const char *name, const char *value, bool replaceExisting) {
138162
for (auto i = _headers.begin(); i != _headers.end(); ++i) {
139163
if (i->name().equalsIgnoreCase(name)) {

0 commit comments

Comments
 (0)