Skip to content

Commit 5511c82

Browse files
committed
replace Strings with with StreamStrings to avoid String Reallocations.
1 parent f09b8b1 commit 5511c82

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
@@ -212,6 +212,10 @@ class Stream: public Print {
212212
size_t sendSize (Stream* to, const ssize_t maxLen, const oneShotMs::timeType timeoutMs = oneShotMs::neverExpires) { return sendGeneric(to, maxLen, -1, timeoutMs); }
213213
size_t sendSize (Stream& to, const ssize_t maxLen, const oneShotMs::timeType timeoutMs = oneShotMs::neverExpires) { return sendSize(&to, maxLen, timeoutMs); }
214214

215+
String readStreamString (const ssize_t maxLen = -1 ,const oneShotMs::timeType timeoutMs = oneShotMs::neverExpires);
216+
String readStreamStringUntil (const int readUntilChar, const oneShotMs::timeType timeoutMs = oneShotMs::neverExpires);
217+
String readStreamStringUntil (const char* terminatorString, uint32_t untilTotalNumberOfOccurrences = 1, const oneShotMs::timeType timeoutMs = oneShotMs::neverExpires);
218+
215219
// remaining size (-1 by default = unknown)
216220
virtual ssize_t streamRemaining () { return -1; }
217221

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
if(_postArgs) delete[] _postArgs;
@@ -368,8 +364,7 @@ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const
368364
String argFilename;
369365
bool argIsFile = false;
370366

371-
line = client.readStringUntil('\r');
372-
client.readStringUntil('\n');
367+
line = client.readStreamStringUntil("\r\n");
373368
if (line.length() > 19 && line.substring(0, 19).equalsIgnoreCase(F("Content-Disposition"))){
374369
int nameStart = line.indexOf('=');
375370
if (nameStart != -1){
@@ -389,19 +384,16 @@ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const
389384
DBGWS("PostArg Name: %s\n", argName.c_str());
390385
using namespace mime;
391386
argType = FPSTR(mimeTable[txt].mimeType);
392-
line = client.readStringUntil('\r');
393-
client.readStringUntil('\n');
387+
line = client.readStreamStringUntil("\r\n");
394388
if (line.length() > 12 && line.substring(0, 12).equalsIgnoreCase(FPSTR(Content_Type))){
395389
argType = line.substring(line.indexOf(':')+2);
396390
//skip next line
397-
client.readStringUntil('\r');
398-
client.readStringUntil('\n');
391+
client.readStringUntil("\r\n");
399392
}
400393
DBGWS("PostArg Type: %s\n", argType.c_str());
401394
if (!argIsFile){
402395
while(1){
403-
line = client.readStringUntil('\r');
404-
client.readStringUntil('\n');
396+
line = client.readStreamStringUntil("\r\n");
405397
if (line.startsWith("--"+boundary)) break;
406398
if (argValue.length() > 0) argValue += '\n';
407399
argValue += line;
@@ -475,8 +467,7 @@ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const
475467
_currentUpload->type.c_str(),
476468
(int)_currentUpload->totalSize);
477469
if (!client.connected()) return _parseFormUploadAborted();
478-
line = client.readStringUntil('\r');
479-
client.readStringUntil('\n');
470+
line = client.readStreamStringUntil("\r\n");
480471
if (line == "--") { // extra two dashes mean we reached the end of all form fields
481472
DBGWS("Done Parsing POST\n");
482473
break;

0 commit comments

Comments
 (0)