Skip to content

Commit

Permalink
replace Strings with with StreamStrings to avoid String Reallocations.
Browse files Browse the repository at this point in the history
  • Loading branch information
Lan-Hekary committed Mar 21, 2024
1 parent b0c04b4 commit 474dcd3
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 18 deletions.
54 changes: 54 additions & 0 deletions cores/esp8266/Stream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include <Arduino.h>
#include <Stream.h>
#include <StreamString.h>

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

String Stream::readStreamString(const ssize_t maxLen ,const oneShotMs::timeType timeoutMs) {
String ret;
S2Stream stream(ret);
sendGeneric(&stream, maxLen, -1, timeoutMs);
return ret;
}

String Stream::readStreamStringUntil(const int readUntilChar, const oneShotMs::timeType timeoutMs) {
String ret;
S2Stream stream(ret);
sendGeneric(&stream, -1, readUntilChar, timeoutMs);
return ret;
}

String Stream::readStreamStringUntil (const char* terminatorString, uint32_t untilTotalNumberOfOccurrences, const oneShotMs::timeType timeoutMs) {
String ret;
S2Stream stream(ret);
uint32_t occurrences = 0;
size_t termLen = strlen(terminatorString);
size_t termIndex = 0;
// Serial.printf("S %s\n",terminatorString);
while(1){
size_t read = sendGeneric(&stream, -1, terminatorString[termIndex], timeoutMs);
// Serial.printf("r %d, l %d, ti %d\n", read, termLen, termIndex);
if(getLastSendReport() != Report::Success) {
Serial.printf("Error %d\n", (int) getLastSendReport());
break;
}
if(termIndex == termLen - 1){
// Serial.printf("m %d\n", occurrences);
if(++occurrences == untilTotalNumberOfOccurrences){
break;
}else{
ret += terminatorString;
termIndex = 0;
continue;
}
}
int c = timedPeek();
// Serial.printf("c %c %02X\n", c, c);
if( c >= 0 && c != terminatorString[++termIndex]){
ret += String(terminatorString).substring(0, termIndex);
termIndex = 0;
continue;
};
if(c < 0 || (read == 0 && termIndex == 0)) break;
}

return ret;
}



// read what can be read, immediate exit on unavailable data
// prototype similar to Arduino's `int Client::read(buf, len)`
int Stream::read (uint8_t* buffer, size_t maxLen)
Expand Down
4 changes: 4 additions & 0 deletions cores/esp8266/Stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,10 @@ class Stream: public Print {
size_t sendSize (Stream* to, const ssize_t maxLen, const oneShotMs::timeType timeoutMs = oneShotMs::neverExpires) { return sendGeneric(to, maxLen, -1, timeoutMs); }
size_t sendSize (Stream& to, const ssize_t maxLen, const oneShotMs::timeType timeoutMs = oneShotMs::neverExpires) { return sendSize(&to, maxLen, timeoutMs); }

String readStreamString (const ssize_t maxLen = -1 ,const oneShotMs::timeType timeoutMs = oneShotMs::neverExpires);
String readStreamStringUntil (const int readUntilChar, const oneShotMs::timeType timeoutMs = oneShotMs::neverExpires);
String readStreamStringUntil (const char* terminatorString, uint32_t untilTotalNumberOfOccurrences = 1, const oneShotMs::timeType timeoutMs = oneShotMs::neverExpires);

// remaining size (-1 by default = unknown)
virtual ssize_t streamRemaining () { return -1; }

Expand Down
27 changes: 9 additions & 18 deletions libraries/ESP8266WebServer/src/Parsing-impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,8 @@ static bool readBytesWithTimeout(typename ServerType::ClientType& client, size_t
template <typename ServerType>
typename ESP8266WebServerTemplate<ServerType>::ClientFuture ESP8266WebServerTemplate<ServerType>::_parseRequest(ClientType& client) {
// Read the first line of HTTP request
String req = client.readStringUntil('\r');
String req = client.readStreamStringUntil("\r\n");
DBGWS("request: %s\n", req.c_str());
client.readStringUntil('\n');
//reset header value
for (int i = 0; i < _headerKeysCount; ++i) {
_currentHeaders[i].value.clear();
Expand Down Expand Up @@ -122,8 +121,7 @@ typename ESP8266WebServerTemplate<ServerType>::ClientFuture ESP8266WebServerTemp
uint32_t contentLength = 0;
//parse headers
while(1){
req = client.readStringUntil('\r');
client.readStringUntil('\n');
req = client.readStreamStringUntil("\r\n");
if (req.isEmpty()) break; //no more headers
int headerDiv = req.indexOf(':');
if (headerDiv == -1){
Expand Down Expand Up @@ -198,8 +196,7 @@ typename ESP8266WebServerTemplate<ServerType>::ClientFuture ESP8266WebServerTemp
String headerValue;
//parse headers
while(1){
req = client.readStringUntil('\r');
client.readStringUntil('\n');
req = client.readStreamStringUntil("\r\n");
if (req.isEmpty()) break;//no moar headers
int headerDiv = req.indexOf(':');
if (headerDiv == -1){
Expand Down Expand Up @@ -351,11 +348,10 @@ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const
String line;
int retry = 0;
do {
line = client.readStringUntil('\r');
line = client.readStreamStringUntil("\r\n");
++retry;
} while (line.length() == 0 && retry < 3);

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

line = client.readStringUntil('\r');
client.readStringUntil('\n');
line = client.readStreamStringUntil("\r\n");
if (line.length() > 19 && line.substring(0, 19).equalsIgnoreCase(F("Content-Disposition"))){
int nameStart = line.indexOf('=');
if (nameStart != -1){
Expand All @@ -388,19 +383,16 @@ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const
DBGWS("PostArg Name: %s\n", argName.c_str());
using namespace mime;
argType = FPSTR(mimeTable[txt].mimeType);
line = client.readStringUntil('\r');
client.readStringUntil('\n');
line = client.readStreamStringUntil("\r\n");
if (line.length() > 12 && line.substring(0, 12).equalsIgnoreCase(FPSTR(Content_Type))){
argType = line.substring(line.indexOf(':')+2);
//skip next line
client.readStringUntil('\r');
client.readStringUntil('\n');
client.readStringUntil("\r\n");
}
DBGWS("PostArg Type: %s\n", argType.c_str());
if (!argIsFile){
while(1){
line = client.readStringUntil('\r');
client.readStringUntil('\n');
line = client.readStreamStringUntil("\r\n");
if (line.startsWith("--"+boundary)) break;
if (argValue.length() > 0) argValue += '\n';
argValue += line;
Expand Down Expand Up @@ -474,8 +466,7 @@ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const
_currentUpload->type.c_str(),
(int)_currentUpload->totalSize);
if (!client.connected()) return _parseFormUploadAborted();
line = client.readStringUntil('\r');
client.readStringUntil('\n');
line = client.readStreamStringUntil("\r\n");
if (line == "--") { // extra two dashes mean we reached the end of all form fields
DBGWS("Done Parsing POST\n");
break;
Expand Down

0 comments on commit 474dcd3

Please sign in to comment.