Skip to content

Commit 4255594

Browse files
committed
ESP8266WebServer - StreamString parsing experiment
impl based on esp8266#9005, but for existing Arduino methods
1 parent c2f1365 commit 4255594

File tree

7 files changed

+161
-123
lines changed

7 files changed

+161
-123
lines changed

cores/esp8266/Stream.cpp

+33-21
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@
2020
parsing functions based on TextFinder library by Michael Margolis
2121
*/
2222

23-
#include <Arduino.h>
24-
#include <Stream.h>
23+
#include "Arduino.h"
24+
#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
@@ -254,34 +255,45 @@ String Stream::readString() {
254255

255256
String Stream::readStringUntil(char terminator) {
256257
String ret;
257-
int c = timedRead();
258-
while(c >= 0 && c != terminator) {
259-
ret += (char) c;
260-
c = timedRead();
261-
}
258+
259+
S2Stream s2s(ret);
260+
sendUntil(s2s, terminator, _timeout);
261+
262262
return ret;
263263
}
264264

265265
String Stream::readStringUntil(const char* terminator, uint32_t untilTotalNumberOfOccurrences) {
266266
String ret;
267-
int c;
267+
if (!untilTotalNumberOfOccurrences) {
268+
return ret;
269+
}
270+
271+
const size_t termLen = strlen_P(terminator);
272+
if (!termLen) {
273+
return ret;
274+
}
275+
276+
S2Stream s2s(ret);
268277
uint32_t occurrences = 0;
269-
size_t termLen = strlen(terminator);
270-
size_t termIndex = 0;
271-
size_t index = 0;
278+
const size_t tailLen = termLen - 1;
272279

273-
while ((c = timedRead()) > 0) {
274-
ret += (char) c;
275-
index++;
280+
for (;;) {
281+
sendUntil(s2s, terminator[tailLen], _timeout);
282+
if (s2s.getLastSendReport() != Stream::Report::Success) {
283+
break;
284+
}
285+
286+
if ((ret.length() >= tailLen)
287+
&& ((0 == tailLen) || (0 == memcmp_P(terminator, ret.end() - tailLen, tailLen))))
288+
{
289+
++occurrences;
290+
}
276291

277-
if (terminator[termIndex] == c) {
278-
if (++termIndex == termLen && ++occurrences == untilTotalNumberOfOccurrences) {
279-
// don't include terminator in returned string
280-
ret.remove(index - termIndex, termLen);
281-
break;
292+
if (untilTotalNumberOfOccurrences == occurrences) {
293+
if (tailLen) {
294+
ret.remove(ret.length() - tailLen);
282295
}
283-
} else {
284-
termIndex = 0;
296+
break;
285297
}
286298
}
287299

libraries/ESP8266WebServer/src/Parsing-impl.h

+9-17
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.readStringUntil("\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.readStringUntil("\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.readStringUntil("\r\n");
203200
if (req.isEmpty()) break;//no moar headers
204201
int headerDiv = req.indexOf(':');
205202
if (headerDiv == -1){
@@ -351,7 +348,7 @@ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const
351348
String line;
352349
int retry = 0;
353350
do {
354-
line = client.readStringUntil('\r');
351+
line = client.readStringUntil("\r\n");
355352
++retry;
356353
} while (line.length() == 0 && retry < 3);
357354

@@ -367,8 +364,7 @@ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const
367364
String argFilename;
368365
bool argIsFile = false;
369366

370-
line = client.readStringUntil('\r');
371-
client.readStringUntil('\n');
367+
line = client.readStringUntil("\r\n");
372368
if (line.length() > 19 && line.substring(0, 19).equalsIgnoreCase(F("Content-Disposition"))){
373369
int nameStart = line.indexOf('=');
374370
if (nameStart != -1){
@@ -388,19 +384,16 @@ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const
388384
DBGWS("PostArg Name: %s\n", argName.c_str());
389385
using namespace mime;
390386
argType = FPSTR(mimeTable[txt].mimeType);
391-
line = client.readStringUntil('\r');
392-
client.readStringUntil('\n');
387+
line = client.readStringUntil("\r\n");
393388
if (line.length() > 12 && line.substring(0, 12).equalsIgnoreCase(FPSTR(Content_Type))){
394389
argType = line.substring(line.indexOf(':')+2);
395390
//skip next line
396-
client.readStringUntil('\r');
397-
client.readStringUntil('\n');
391+
client.readStringUntil("\r\n");
398392
}
399393
DBGWS("PostArg Type: %s\n", argType.c_str());
400394
if (!argIsFile){
401395
while(1){
402-
line = client.readStringUntil('\r');
403-
client.readStringUntil('\n');
396+
line = client.readStringUntil("\r\n");
404397
if (line.startsWith("--"+boundary)) break;
405398
if (argValue.length() > 0) argValue += '\n';
406399
argValue += line;
@@ -474,8 +467,7 @@ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const
474467
_currentUpload->type.c_str(),
475468
(int)_currentUpload->totalSize);
476469
if (!client.connected()) return _parseFormUploadAborted();
477-
line = client.readStringUntil('\r');
478-
client.readStringUntil('\n');
470+
line = client.readStringUntil("\r\n");
479471
if (line == "--") { // extra two dashes mean we reached the end of all form fields
480472
DBGWS("Done Parsing POST\n");
481473
break;

tests/host/Makefile

+26
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ GENHTML ?= genhtml
3030
CXXFLAGS += -std=gnu++17
3131
CFLAGS += -std=gnu17
3232

33+
# 32-bit mode is prefered, but not required
3334
ifeq ($(FORCE32),1)
3435
SIZEOFLONG = $(shell echo 'int main(){return sizeof(long);}'|$(CXX) -m32 -x c++ - -o sizeoflong 2>/dev/null && ./sizeoflong; echo $$?; rm -f sizeoflong;)
3536
ifneq ($(SIZEOFLONG),4)
@@ -50,6 +51,7 @@ endif
5051
OUTPUT_BINARY := $(BINDIR)/host_tests
5152
LCOV_DIRECTORY := $(BINDIR)/../lcov
5253

54+
# Hide full build commands by default
5355
ifeq ($(V), 0)
5456
VERBC = @echo "C $@";
5557
VERBCXX = @echo "C++ $@";
@@ -66,6 +68,30 @@ endif
6668

6769
$(shell mkdir -p $(BINDIR))
6870

71+
# Core files sometimes override libc functions, check when necessary to hide them
72+
# TODO proper configure script / other build system?
73+
ifeq (,$(wildcard $(BINDIR)/.have_strlcpy))
74+
$(shell echo -e '#include <cstring>\nint main(){char a[4]{}; char b[4]{}; strlcpy(&a[0], &b[0], sizeof(a)); return 0;}' | \
75+
$(CXX) -x c++ - -o $(BINDIR)/.have_strlcpy 2>/dev/null || ( echo -e '#!/bin/sh\nexit 1' > $(BINDIR)/.have_strlcpy ; chmod +x $(BINDIR)/.have_strlcpy; ))
76+
endif
77+
78+
$(shell $(BINDIR)/.have_strlcpy)
79+
ifeq ($(.SHELLSTATUS), 0)
80+
FLAGS += -DHAVE_STRLCPY
81+
endif
82+
83+
ifeq (,$(wildcard $(BINDIR)/.have_strlcat))
84+
$(shell echo -e '#include <cstring>\nint main(){char a[4]{}; strlcat(&a[0], "test", sizeof(a)); return 0;}' | \
85+
$(CXX) -x c++ - -o $(BINDIR)/.have_strlcat 2>/dev/null || ( echo -e '#!/bin/sh\nexit 1' > $(BINDIR)/.have_strlcat ; chmod +x $(BINDIR)/.have_strlcat; ))
86+
endif
87+
88+
$(shell $(BINDIR)/.have_strlcat)
89+
ifeq ($(.SHELLSTATUS), 0)
90+
FLAGS += -DHAVE_STRLCAT
91+
endif
92+
93+
# Actual build recipes
94+
6995
CORE_CPP_FILES := \
7096
$(addprefix $(abspath $(CORE_PATH))/,\
7197
debug.cpp \

tests/host/common/mock.h

+10-5
Original file line numberDiff line numberDiff line change
@@ -56,18 +56,23 @@
5656
#define D8 8
5757

5858
#include <stddef.h>
59+
#include <stdlib.h>
60+
#include <string.h>
61+
62+
#include <stdlib_noniso.h>
5963

6064
#ifdef __cplusplus
6165
extern "C"
6266
{
6367
#endif
64-
// TODO: #include <stdlib_noniso.h> ?
65-
char* itoa(int val, char* s, int radix);
66-
char* ltoa(long val, char* s, int radix);
67-
68+
char* utoa(unsigned value, char* result, int base);
69+
char* itoa(int value, char* result, int base);
70+
#ifndef HAVE_STRLCAT
6871
size_t strlcat(char* dst, const char* src, size_t size);
72+
#endif
73+
#ifndef HAVE_STRLCPY
6974
size_t strlcpy(char* dst, const char* src, size_t size);
70-
75+
#endif
7176
#ifdef __cplusplus
7277
}
7378
#endif

tests/host/common/noniso.c

+3-19
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@
1818
#include <stdbool.h>
1919
#include <stdint.h>
2020
#include <math.h>
21-
#include "stdlib_noniso.h"
2221

23-
void reverse(char* begin, char* end)
22+
#include <stdlib_noniso.h>
23+
24+
static void reverse(char* begin, char* end)
2425
{
2526
char* is = begin;
2627
char* ie = end - 1;
@@ -84,20 +85,3 @@ char* itoa(int value, char* result, int base)
8485
utoa(uvalue, result, base);
8586
return out;
8687
}
87-
88-
int atoi(const char* s)
89-
{
90-
return (int)atol(s);
91-
}
92-
93-
long atol(const char* s)
94-
{
95-
char* tmp;
96-
return strtol(s, &tmp, 10);
97-
}
98-
99-
double atof(const char* s)
100-
{
101-
char* tmp;
102-
return strtod(s, &tmp);
103-
}

0 commit comments

Comments
 (0)