Skip to content

Commit f6516b0

Browse files
committed
ESP8266WebServer: fix handling of empty POST
Fix handling of case when Content-Length is 0. Change do {} while() loop into while(){} so that we don't wait 1000ms for data in case Content-Length is 0. Also fix handling of cases when malloc or realloc return null.
1 parent 43d0989 commit f6516b0

File tree

2 files changed

+52
-33
lines changed

2 files changed

+52
-33
lines changed

libraries/ESP8266WebServer/src/ESP8266WebServer.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ enum HTTPClientStatus { HC_NONE, HC_WAIT_READ, HC_WAIT_CLOSE };
3434
#define HTTP_DOWNLOAD_UNIT_SIZE 1460
3535
#define HTTP_UPLOAD_BUFLEN 2048
3636
#define HTTP_MAX_DATA_WAIT 1000 //ms to wait for the client to send the request
37+
#define HTTP_MAX_POST_WAIT 1000 //ms to wait for POST data to arrive
3738
#define HTTP_MAX_CLOSE_WAIT 2000 //ms to wait for the client to close the connection
3839

3940
#define CONTENT_LENGTH_UNKNOWN ((size_t) -1)
@@ -66,13 +67,13 @@ class ESP8266WebServer
6667

6768
void begin();
6869
void handleClient();
69-
70+
7071
void close();
7172
void stop();
7273

7374
bool authenticate(const char * username, const char * password);
7475
void requestAuthentication();
75-
76+
7677
typedef std::function<void(void)> THandlerFunction;
7778
void on(const char* uri, THandlerFunction handler);
7879
void on(const char* uri, HTTPMethod method, THandlerFunction fn);

libraries/ESP8266WebServer/src/Parsing.cpp

+49-31
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,38 @@
3131
#define DEBUG_OUTPUT Serial
3232
#endif
3333

34+
static char* readBytesWithTimeout(WiFiClient& client, size_t maxLength, size_t& dataLength, int timeout_ms)
35+
{
36+
char *buf = nullptr;
37+
dataLength = 0;
38+
while (dataLength < maxLength) {
39+
int tries = timeout_ms;
40+
size_t newLength;
41+
while (!(newLength = client.available()) && tries--) delay(1);
42+
if (!newLength) {
43+
break;
44+
}
45+
if (!buf) {
46+
buf = (char *) malloc(newLength + 1);
47+
if (!buf) {
48+
return nullptr;
49+
}
50+
}
51+
else {
52+
char* newBuf = (char *) realloc(buf, dataLength + newLength + 1);
53+
if (!newBuf) {
54+
free(buf);
55+
return nullptr;
56+
}
57+
buf = newBuf;
58+
}
59+
client.readBytes(buf + dataLength, newLength);
60+
dataLength += newLength;
61+
buf[dataLength] = '\0';
62+
}
63+
return buf;
64+
}
65+
3466
bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
3567
// Read the first line of HTTP request
3668
String req = client.readStringUntil('\r');
@@ -114,14 +146,14 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
114146
headerValue = req.substring(headerDiv + 1);
115147
headerValue.trim();
116148
_collectHeader(headerName.c_str(),headerValue.c_str());
117-
149+
118150
#ifdef DEBUG_ESP_HTTP_SERVER
119151
DEBUG_OUTPUT.print("headerName: ");
120152
DEBUG_OUTPUT.println(headerName);
121153
DEBUG_OUTPUT.print("headerValue: ");
122154
DEBUG_OUTPUT.println(headerValue);
123155
#endif
124-
156+
125157
if (headerName == "Content-Type"){
126158
if (headerValue.startsWith("text/plain")){
127159
isForm = false;
@@ -137,41 +169,27 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
137169
}
138170

139171
if (!isForm){
140-
if (searchStr != "") searchStr += '&';
141-
char *plainBuf = nullptr;
142-
size_t plainLen = 0;
143-
do
144-
{
145-
//some clients send headers first and data after (like we do)
146-
//give them a chance
147-
int tries = 1000;//1000ms max wait
148-
size_t newLen;
149-
while( !(newLen = client.available()) && tries--) delay(1);
150-
if (!newLen) break;
151-
plainBuf = (plainBuf == nullptr) ? (char *) malloc(newLen + 1) : (char *) realloc(plainBuf, plainLen + newLen + 1);
152-
client.readBytes(&plainBuf[plainLen], newLen);
153-
plainLen += newLen;
154-
plainBuf[plainLen] = '\0';
155-
} while (plainLen < contentLength);
156-
/* if data loss, exit */
157-
if (plainBuf == nullptr) return false;
158-
if (plainLen < contentLength)
159-
{
172+
size_t plainLength;
173+
char* plainBuf = readBytesWithTimeout(client, contentLength, plainLength, HTTP_MAX_POST_WAIT);
174+
if (plainLength < contentLength) {
160175
free(plainBuf);
161176
return false;
162177
}
163178
#ifdef DEBUG_ESP_HTTP_SERVER
164179
DEBUG_OUTPUT.print("Plain: ");
165180
DEBUG_OUTPUT.println(plainBuf);
166181
#endif
167-
if(plainBuf[0] == '{' || plainBuf[0] == '[' || strstr(plainBuf, "=") == NULL){
168-
//plain post json or other data
169-
searchStr += "plain=";
170-
searchStr += plainBuf;
171-
} else {
172-
searchStr += plainBuf;
182+
if (contentLength > 0) {
183+
if (searchStr != "") searchStr += '&';
184+
if(plainBuf[0] == '{' || plainBuf[0] == '[' || strstr(plainBuf, "=") == NULL){
185+
//plain post json or other data
186+
searchStr += "plain=";
187+
searchStr += plainBuf;
188+
} else {
189+
searchStr += plainBuf;
190+
}
191+
free(plainBuf);
173192
}
174-
free(plainBuf);
175193
}
176194
_parseArguments(searchStr);
177195
if (isForm){
@@ -194,14 +212,14 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
194212
headerName = req.substring(0, headerDiv);
195213
headerValue = req.substring(headerDiv + 2);
196214
_collectHeader(headerName.c_str(),headerValue.c_str());
197-
215+
198216
#ifdef DEBUG_ESP_HTTP_SERVER
199217
DEBUG_OUTPUT.print("headerName: ");
200218
DEBUG_OUTPUT.println(headerName);
201219
DEBUG_OUTPUT.print("headerValue: ");
202220
DEBUG_OUTPUT.println(headerValue);
203221
#endif
204-
222+
205223
if (headerName == "Host"){
206224
_hostHeader = headerValue;
207225
}

0 commit comments

Comments
 (0)