Skip to content

Commit 57aaf27

Browse files
committed
replace Strings with with StreamStrings to avoid String Reallocations.
1 parent 9ae9c5b commit 57aaf27

File tree

3 files changed

+67
-18
lines changed

3 files changed

+67
-18
lines changed

cores/esp8266/Stream.cpp

+54
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#include <Arduino.h>
2424
#include <Stream.h>
25+
#include <StreamString.h>
2526

2627
#define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait
2728
#define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field
@@ -288,6 +289,59 @@ String Stream::readStringUntil(const char* terminator, uint32_t untilTotalNumber
288289
return ret;
289290
}
290291

292+
String Stream::readStreamString(const ssize_t maxLen ,const oneShotMs::timeType timeoutMs) {
293+
String ret;
294+
S2Stream stream(ret);
295+
sendGeneric(&stream, maxLen, -1, timeoutMs);
296+
return ret;
297+
}
298+
299+
String Stream::readStreamStringUntil(const int readUntilChar, const oneShotMs::timeType timeoutMs) {
300+
String ret;
301+
S2Stream stream(ret);
302+
sendGeneric(&stream, -1, readUntilChar, timeoutMs);
303+
return ret;
304+
}
305+
306+
String Stream::readStreamStringUntil (const char* terminatorString, uint32_t untilTotalNumberOfOccurrences, const oneShotMs::timeType timeoutMs) {
307+
String ret;
308+
S2Stream stream(ret);
309+
uint32_t occurrences = 0;
310+
size_t termLen = strlen(terminatorString);
311+
size_t termIndex = 0;
312+
// Serial.printf("S %s\n",terminatorString);
313+
while(1){
314+
size_t read = sendGeneric(&stream, -1, terminatorString[termIndex], timeoutMs);
315+
// Serial.printf("r %d, l %d, ti %d\n", read, termLen, termIndex);
316+
if(getLastSendReport() != Report::Success) {
317+
Serial.printf("Error %d\n", (int) getLastSendReport());
318+
break;
319+
}
320+
if(termIndex == termLen - 1){
321+
// Serial.printf("m %d\n", occurrences);
322+
if(++occurrences == untilTotalNumberOfOccurrences){
323+
break;
324+
}else{
325+
ret += terminatorString;
326+
termIndex = 0;
327+
continue;
328+
}
329+
}
330+
int c = timedPeek();
331+
// Serial.printf("c %c %02X\n", c, c);
332+
if( c >= 0 && c != terminatorString[++termIndex]){
333+
ret += String(terminatorString).substring(0, termIndex);
334+
termIndex = 0;
335+
continue;
336+
};
337+
if(c < 0 || (read == 0 && termIndex == 0)) break;
338+
}
339+
340+
return ret;
341+
}
342+
343+
344+
291345
// read what can be read, immediate exit on unavailable data
292346
// prototype similar to Arduino's `int Client::read(buf, len)`
293347
int Stream::read (uint8_t* buffer, size_t maxLen)

cores/esp8266/Stream.h

+4
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,10 @@ class Stream: public Print {
216216
size_t sendSize (Stream& to, const ssize_t maxLen, const oneShotMs::timeType timeoutMs = oneShotMs::neverExpires) { return sendSize(&to, maxLen, timeoutMs); }
217217
size_t sendSize (Stream&& to, const ssize_t maxLen, const oneShotMs::timeType timeoutMs = oneShotMs::neverExpires) { return sendSize(&to, maxLen, timeoutMs); }
218218

219+
String readStreamString (const ssize_t maxLen = -1 ,const oneShotMs::timeType timeoutMs = oneShotMs::neverExpires);
220+
String readStreamStringUntil (const int readUntilChar, const oneShotMs::timeType timeoutMs = oneShotMs::neverExpires);
221+
String readStreamStringUntil (const char* terminatorString, uint32_t untilTotalNumberOfOccurrences = 1, const oneShotMs::timeType timeoutMs = oneShotMs::neverExpires);
222+
219223
// remaining size (-1 by default = unknown)
220224
virtual ssize_t streamRemaining () { return -1; }
221225

libraries/ESP8266WebServer/src/Parsing-impl.h

+9-18
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,8 @@ static bool readBytesWithTimeout(typename ServerType::ClientType& client, size_t
4444
template <typename ServerType>
4545
typename ESP8266WebServerTemplate<ServerType>::ClientFuture ESP8266WebServerTemplate<ServerType>::_parseRequest(ClientType& client) {
4646
// Read the first line of HTTP request
47-
String req = client.readStringUntil('\r');
47+
String req = client.readStreamStringUntil("\r\n");
4848
DBGWS("request: %s\n", req.c_str());
49-
client.readStringUntil('\n');
5049
//reset header value
5150
for (int i = 0; i < _headerKeysCount; ++i) {
5251
_currentHeaders[i].value.clear();
@@ -122,8 +121,7 @@ typename ESP8266WebServerTemplate<ServerType>::ClientFuture ESP8266WebServerTemp
122121
uint32_t contentLength = 0;
123122
//parse headers
124123
while(1){
125-
req = client.readStringUntil('\r');
126-
client.readStringUntil('\n');
124+
req = client.readStreamStringUntil("\r\n");
127125
if (req.isEmpty()) break; //no more headers
128126
int headerDiv = req.indexOf(':');
129127
if (headerDiv == -1){
@@ -198,8 +196,7 @@ typename ESP8266WebServerTemplate<ServerType>::ClientFuture ESP8266WebServerTemp
198196
String headerValue;
199197
//parse headers
200198
while(1){
201-
req = client.readStringUntil('\r');
202-
client.readStringUntil('\n');
199+
req = client.readStreamStringUntil("\r\n");
203200
if (req.isEmpty()) break;//no moar headers
204201
int headerDiv = req.indexOf(':');
205202
if (headerDiv == -1){
@@ -351,11 +348,10 @@ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const
351348
String line;
352349
int retry = 0;
353350
do {
354-
line = client.readStringUntil('\r');
351+
line = client.readStreamStringUntil("\r\n");
355352
++retry;
356353
} while (line.length() == 0 && retry < 3);
357354

358-
client.readStringUntil('\n');
359355
//start reading the form
360356
if (line == ("--"+boundary)){
361357
std::unique_ptr<RequestArgument[]> postArgs(new RequestArgument[WEBSERVER_MAX_POST_ARGS]);
@@ -367,8 +363,7 @@ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const
367363
String argFilename;
368364
bool argIsFile = false;
369365

370-
line = client.readStringUntil('\r');
371-
client.readStringUntil('\n');
366+
line = client.readStreamStringUntil("\r\n");
372367
if (line.length() > 19 && line.substring(0, 19).equalsIgnoreCase(F("Content-Disposition"))){
373368
int nameStart = line.indexOf('=');
374369
if (nameStart != -1){
@@ -388,19 +383,16 @@ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const
388383
DBGWS("PostArg Name: %s\n", argName.c_str());
389384
using namespace mime;
390385
argType = FPSTR(mimeTable[txt].mimeType);
391-
line = client.readStringUntil('\r');
392-
client.readStringUntil('\n');
386+
line = client.readStreamStringUntil("\r\n");
393387
if (line.length() > 12 && line.substring(0, 12).equalsIgnoreCase(FPSTR(Content_Type))){
394388
argType = line.substring(line.indexOf(':')+2);
395389
//skip next line
396-
client.readStringUntil('\r');
397-
client.readStringUntil('\n');
390+
client.readStringUntil("\r\n");
398391
}
399392
DBGWS("PostArg Type: %s\n", argType.c_str());
400393
if (!argIsFile){
401394
while(1){
402-
line = client.readStringUntil('\r');
403-
client.readStringUntil('\n');
395+
line = client.readStreamStringUntil("\r\n");
404396
if (line.startsWith("--"+boundary)) break;
405397
if (argValue.length() > 0) argValue += '\n';
406398
argValue += line;
@@ -474,8 +466,7 @@ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const
474466
_currentUpload->type.c_str(),
475467
(int)_currentUpload->totalSize);
476468
if (!client.connected()) return _parseFormUploadAborted();
477-
line = client.readStringUntil('\r');
478-
client.readStringUntil('\n');
469+
line = client.readStreamStringUntil("\r\n");
479470
if (line == "--") { // extra two dashes mean we reached the end of all form fields
480471
DBGWS("Done Parsing POST\n");
481472
break;

0 commit comments

Comments
 (0)