Skip to content

Commit a063c2b

Browse files
authored
fix http parsing (#5262)
* follows #5252 * use const refs where relevant (aka stop being nasty with ram and cpu)
1 parent e954022 commit a063c2b

File tree

5 files changed

+93
-91
lines changed

5 files changed

+93
-91
lines changed

Diff for: cores/esp8266/WString.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -796,3 +796,7 @@ float String::toFloat(void) const {
796796
return atof(buffer);
797797
return 0;
798798
}
799+
800+
// global empty string to allow returning const String& with nothing
801+
802+
const String emptyString;

Diff for: cores/esp8266/WString.h

+2
Original file line numberDiff line numberDiff line change
@@ -294,5 +294,7 @@ class StringSumHelper: public String {
294294
}
295295
};
296296

297+
extern const String emptyString;
298+
297299
#endif // __cplusplus
298300
#endif // String_class_h

Diff for: libraries/ESP8266WebServer/src/ESP8266WebServer.cpp

+23-23
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,10 @@ void ESP8266WebServer::begin(uint16_t port) {
100100
_server.begin(port);
101101
}
102102

103-
String ESP8266WebServer::_extractParam(String& authReq,const String& param,const char delimit){
103+
String ESP8266WebServer::_extractParam(String& authReq,const String& param,const char delimit) const {
104104
int _begin = authReq.indexOf(param);
105-
if (_begin == -1)
106-
return "";
105+
if (_begin == -1)
106+
return emptyString;
107107
return authReq.substring(_begin+param.length(),authReq.indexOf(delimit,_begin+param.length()));
108108
}
109109

@@ -487,35 +487,35 @@ void ESP8266WebServer::_streamFileCore(const size_t fileSize, const String & fil
487487
contentType != String(FPSTR(mimeTable[none].mimeType))) {
488488
sendHeader(F("Content-Encoding"), F("gzip"));
489489
}
490-
send(200, contentType, "");
490+
send(200, contentType, emptyString);
491491
}
492492

493493

494-
String ESP8266WebServer::arg(String name) {
494+
const String& ESP8266WebServer::arg(String name) const {
495495
for (int i = 0; i < _currentArgCount; ++i) {
496496
if ( _currentArgs[i].key == name )
497497
return _currentArgs[i].value;
498498
}
499-
return "";
499+
return emptyString;
500500
}
501501

502-
String ESP8266WebServer::arg(int i) {
502+
const String& ESP8266WebServer::arg(int i) const {
503503
if (i >= 0 && i < _currentArgCount)
504504
return _currentArgs[i].value;
505-
return "";
505+
return emptyString;
506506
}
507507

508-
String ESP8266WebServer::argName(int i) {
508+
const String& ESP8266WebServer::argName(int i) const {
509509
if (i >= 0 && i < _currentArgCount)
510510
return _currentArgs[i].key;
511-
return "";
511+
return emptyString;
512512
}
513513

514-
int ESP8266WebServer::args() {
514+
int ESP8266WebServer::args() const {
515515
return _currentArgCount;
516516
}
517517

518-
bool ESP8266WebServer::hasArg(String name) {
518+
bool ESP8266WebServer::hasArg(const String& name) const {
519519
for (int i = 0; i < _currentArgCount; ++i) {
520520
if (_currentArgs[i].key == name)
521521
return true;
@@ -524,12 +524,12 @@ bool ESP8266WebServer::hasArg(String name) {
524524
}
525525

526526

527-
String ESP8266WebServer::header(String name) {
527+
const String& ESP8266WebServer::header(String name) const {
528528
for (int i = 0; i < _headerKeysCount; ++i) {
529529
if (_currentHeaders[i].key.equalsIgnoreCase(name))
530530
return _currentHeaders[i].value;
531531
}
532-
return "";
532+
return emptyString;
533533
}
534534

535535
void ESP8266WebServer::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) {
@@ -543,31 +543,31 @@ void ESP8266WebServer::collectHeaders(const char* headerKeys[], const size_t hea
543543
}
544544
}
545545

546-
String ESP8266WebServer::header(int i) {
546+
const String& ESP8266WebServer::header(int i) const {
547547
if (i < _headerKeysCount)
548548
return _currentHeaders[i].value;
549-
return "";
549+
return emptyString;
550550
}
551551

552-
String ESP8266WebServer::headerName(int i) {
552+
const String& ESP8266WebServer::headerName(int i) const {
553553
if (i < _headerKeysCount)
554554
return _currentHeaders[i].key;
555-
return "";
555+
return emptyString;
556556
}
557557

558-
int ESP8266WebServer::headers() {
558+
int ESP8266WebServer::headers() const {
559559
return _headerKeysCount;
560560
}
561561

562-
bool ESP8266WebServer::hasHeader(String name) {
562+
bool ESP8266WebServer::hasHeader(String name) const {
563563
for (int i = 0; i < _headerKeysCount; ++i) {
564564
if ((_currentHeaders[i].key.equalsIgnoreCase(name)) && (_currentHeaders[i].value.length() > 0))
565565
return true;
566566
}
567567
return false;
568568
}
569569

570-
String ESP8266WebServer::hostHeader() {
570+
const String& ESP8266WebServer::hostHeader() const {
571571
return _hostHeader;
572572
}
573573

@@ -612,11 +612,11 @@ void ESP8266WebServer::_handleRequest() {
612612

613613
void ESP8266WebServer::_finalizeResponse() {
614614
if (_chunked) {
615-
sendContent("");
615+
sendContent(emptyString);
616616
}
617617
}
618618

619-
String ESP8266WebServer::_responseCodeToString(int code) {
619+
const String ESP8266WebServer::_responseCodeToString(int code) {
620620
switch (code) {
621621
case 100: return F("Continue");
622622
case 101: return F("Switching Protocols");

Diff for: libraries/ESP8266WebServer/src/ESP8266WebServer.h

+20-21
Original file line numberDiff line numberDiff line change
@@ -92,24 +92,23 @@ class ESP8266WebServer
9292
void onNotFound(THandlerFunction fn); //called when handler is not assigned
9393
void onFileUpload(THandlerFunction fn); //handle file uploads
9494

95-
String uri() { return _currentUri; }
96-
HTTPMethod method() { return _currentMethod; }
95+
const String& uri() const { return _currentUri; }
96+
HTTPMethod method() const { return _currentMethod; }
9797
virtual WiFiClient client() { return _currentClient; }
9898
HTTPUpload& upload() { return *_currentUpload; }
9999

100-
String arg(String name); // get request argument value by name
101-
String arg(int i); // get request argument value by number
102-
String argName(int i); // get request argument name by number
103-
int args(); // get arguments count
104-
bool hasArg(String name); // check if argument exists
100+
const String& arg(String name) const; // get request argument value by name
101+
const String& arg(int i) const; // get request argument value by number
102+
const String& argName(int i) const; // get request argument name by number
103+
int args() const; // get arguments count
104+
bool hasArg(const String& name) const; // check if argument exists
105105
void collectHeaders(const char* headerKeys[], const size_t headerKeysCount); // set the request headers to collect
106-
String header(String name); // get request header value by name
107-
String header(int i); // get request header value by number
108-
String headerName(int i); // get request header name by number
109-
int headers(); // get header count
110-
bool hasHeader(String name); // check if header exists
111-
112-
String hostHeader(); // get request host header if available or empty String if not
106+
const String& header(String name) const; // get request header value by name
107+
const String& header(int i) const; // get request header value by number
108+
const String& headerName(int i) const; // get request header name by number
109+
int headers() const; // get header count
110+
bool hasHeader(String name) const; // check if header exists
111+
const String& hostHeader() const; // get request host header if available or empty String if not
113112

114113
// send response to the client
115114
// code - HTTP response code, can be 200 or 404
@@ -129,12 +128,12 @@ class ESP8266WebServer
129128

130129
static String urlDecode(const String& text);
131130

132-
template<typename T>
131+
template<typename T>
133132
size_t streamFile(T &file, const String& contentType) {
134133
_streamFileCore(file.size(), file.name(), contentType);
135134
return _currentClient.write(file);
136135
}
137-
136+
138137
protected:
139138
virtual size_t _currentClientWrite(const char* b, size_t l) { return _currentClient.write( b, l ); }
140139
virtual size_t _currentClientWrite_P(PGM_P b, size_t l) { return _currentClient.write_P( b, l ); }
@@ -144,19 +143,19 @@ class ESP8266WebServer
144143
bool _parseRequest(WiFiClient& client);
145144
void _parseArguments(const String& data);
146145
int _parseArgumentsPrivate(const String& data, std::function<void(String&,String&,const String&,int,int,int,int)> handler);
147-
static String _responseCodeToString(int code);
148-
bool _parseForm(WiFiClient& client, String boundary, uint32_t len);
146+
static const String _responseCodeToString(int code);
147+
bool _parseForm(WiFiClient& client, const String& boundary, uint32_t len);
149148
bool _parseFormUploadAborted();
150149
void _uploadWriteByte(uint8_t b);
151150
uint8_t _uploadReadByte(WiFiClient& client);
152151
void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength);
153152
bool _collectHeader(const char* headerName, const char* headerValue);
154-
153+
155154
void _streamFileCore(const size_t fileSize, const String & fileName, const String & contentType);
156155

157-
String _getRandomHexString();
156+
static String _getRandomHexString();
158157
// for extracting Auth parameters
159-
String _extractParam(String& authReq,const String& param,const char delimit = '"');
158+
String _extractParam(String& authReq,const String& param,const char delimit = '"') const;
160159

161160
struct RequestArgument {
162161
String key;

Diff for: libraries/ESP8266WebServer/src/Parsing.cpp

+44-47
Original file line numberDiff line numberDiff line change
@@ -35,41 +35,33 @@
3535
static const char Content_Type[] PROGMEM = "Content-Type";
3636
static const char filename[] PROGMEM = "filename";
3737

38-
static char* readBytesWithTimeout(WiFiClient& client, size_t maxLength, size_t& dataLength, int timeout_ms)
38+
static bool readBytesWithTimeout(WiFiClient& client, size_t maxLength, String& data, int timeout_ms)
3939
{
40-
char *buf = nullptr;
41-
dataLength = 0;
42-
while (dataLength < maxLength) {
40+
if (!data.reserve(maxLength + 1))
41+
return false;
42+
data[0] = 0; // data.clear()??
43+
while (data.length() < maxLength) {
4344
int tries = timeout_ms;
44-
size_t newLength;
45-
while (!(newLength = client.available()) && tries--) delay(1);
46-
if (!newLength) {
45+
size_t avail;
46+
while (!(avail = client.available()) && tries--)
47+
delay(1);
48+
if (!avail)
4749
break;
48-
}
49-
if (!buf) {
50-
buf = (char *) malloc(newLength + 1);
51-
if (!buf) {
52-
return nullptr;
53-
}
54-
}
55-
else {
56-
char* newBuf = (char *) realloc(buf, dataLength + newLength + 1);
57-
if (!newBuf) {
58-
free(buf);
59-
return nullptr;
60-
}
61-
buf = newBuf;
62-
}
63-
client.readBytes(buf + dataLength, newLength);
64-
dataLength += newLength;
65-
buf[dataLength] = '\0';
50+
if (data.length() + avail > maxLength)
51+
avail = maxLength - data.length();
52+
while (avail--)
53+
data += (char)client.read();
6654
}
67-
return buf;
55+
return data.length() == maxLength;
6856
}
6957

7058
bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
7159
// Read the first line of HTTP request
7260
String req = client.readStringUntil('\r');
61+
#ifdef DEBUG_ESP_HTTP_SERVER
62+
DEBUG_OUTPUT.print("request: ");
63+
DEBUG_OUTPUT.println(req);
64+
#endif
7365
client.readStringUntil('\n');
7466
//reset header value
7567
for (int i = 0; i < _headerKeysCount; ++i) {
@@ -82,8 +74,7 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
8274
int addr_end = req.indexOf(' ', addr_start + 1);
8375
if (addr_start == -1 || addr_end == -1) {
8476
#ifdef DEBUG_ESP_HTTP_SERVER
85-
DEBUG_OUTPUT.print("Invalid request: ");
86-
DEBUG_OUTPUT.println(req);
77+
DEBUG_OUTPUT.println("Invalid request");
8778
#endif
8879
return false;
8980
}
@@ -139,7 +130,7 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
139130
String headerName;
140131
String headerValue;
141132
bool isForm = false;
142-
//bool isEncoded = false;
133+
bool isEncoded = false;
143134
uint32_t contentLength = 0;
144135
//parse headers
145136
while(1){
@@ -168,7 +159,7 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
168159
isForm = false;
169160
} else if (headerValue.startsWith(F("application/x-www-form-urlencoded"))){
170161
isForm = false;
171-
//isEncoded = true;
162+
isEncoded = true;
172163
} else if (headerValue.startsWith(F("multipart/"))){
173164
boundaryStr = headerValue.substring(headerValue.indexOf('=') + 1);
174165
boundaryStr.replace("\"","");
@@ -181,34 +172,40 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
181172
}
182173
}
183174

184-
// always parse url for key/value pairs
175+
String plainBuf;
176+
if ( !isForm
177+
&& // read content into plainBuf
178+
( !readBytesWithTimeout(client, contentLength, plainBuf, HTTP_MAX_POST_WAIT)
179+
|| (plainBuf.length() < contentLength)
180+
)
181+
)
182+
{
183+
return false;
184+
}
185+
186+
if (isEncoded) {
187+
// isEncoded => !isForm => plainBuf is not empty
188+
// add plainBuf in search str
189+
if (searchStr.length())
190+
searchStr += '&';
191+
searchStr += plainBuf;
192+
}
193+
194+
// parse searchStr for key/value pairs
185195
_parseArguments(searchStr);
186196

187197
if (!isForm) {
188198
if (contentLength) {
189-
190199
// add key=value: plain={body} (post json or other data)
191-
192-
size_t plainLength;
193-
char* plainBuf = readBytesWithTimeout(client, contentLength, plainLength, HTTP_MAX_POST_WAIT);
194-
if (plainLength < contentLength) {
195-
free(plainBuf);
196-
return false;
197-
}
198-
199200
RequestArgument& arg = _currentArgs[_currentArgCount++];
200201
arg.key = F("plain");
201-
arg.value = String(plainBuf);
202-
203-
free(plainBuf);
204-
202+
arg.value = plainBuf;
205203
}
206204
} else { // isForm is true
207-
205+
// here: content is not yet read (plainBuf is still empty)
208206
if (!_parseForm(client, boundaryStr, contentLength)) {
209207
return false;
210208
}
211-
212209
}
213210
} else {
214211
String headerName;
@@ -368,7 +365,7 @@ uint8_t ESP8266WebServer::_uploadReadByte(WiFiClient& client){
368365
return (uint8_t)res;
369366
}
370367

371-
bool ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){
368+
bool ESP8266WebServer::_parseForm(WiFiClient& client, const String& boundary, uint32_t len){
372369
(void) len;
373370
#ifdef DEBUG_ESP_HTTP_SERVER
374371
DEBUG_OUTPUT.print("Parse Form: Boundary: ");

0 commit comments

Comments
 (0)