Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

try to fix http parsing #5262

Merged
merged 3 commits into from
Oct 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cores/esp8266/WString.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -796,3 +796,7 @@ float String::toFloat(void) const {
return atof(buffer);
return 0;
}

// global empty string to allow returning const String& with nothing

const String emptyString;
2 changes: 2 additions & 0 deletions cores/esp8266/WString.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,5 +294,7 @@ class StringSumHelper: public String {
}
};

extern const String emptyString;

#endif // __cplusplus
#endif // String_class_h
46 changes: 23 additions & 23 deletions libraries/ESP8266WebServer/src/ESP8266WebServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,10 @@ void ESP8266WebServer::begin(uint16_t port) {
_server.begin(port);
}

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

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


String ESP8266WebServer::arg(String name) {
const String& ESP8266WebServer::arg(String name) const {
for (int i = 0; i < _currentArgCount; ++i) {
if ( _currentArgs[i].key == name )
return _currentArgs[i].value;
}
return "";
return emptyString;
}

String ESP8266WebServer::arg(int i) {
const String& ESP8266WebServer::arg(int i) const {
if (i >= 0 && i < _currentArgCount)
return _currentArgs[i].value;
return "";
return emptyString;
}

String ESP8266WebServer::argName(int i) {
const String& ESP8266WebServer::argName(int i) const {
if (i >= 0 && i < _currentArgCount)
return _currentArgs[i].key;
return "";
return emptyString;
}

int ESP8266WebServer::args() {
int ESP8266WebServer::args() const {
return _currentArgCount;
}

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


String ESP8266WebServer::header(String name) {
const String& ESP8266WebServer::header(String name) const {
for (int i = 0; i < _headerKeysCount; ++i) {
if (_currentHeaders[i].key.equalsIgnoreCase(name))
return _currentHeaders[i].value;
}
return "";
return emptyString;
}

void ESP8266WebServer::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) {
Expand All @@ -543,31 +543,31 @@ void ESP8266WebServer::collectHeaders(const char* headerKeys[], const size_t hea
}
}

String ESP8266WebServer::header(int i) {
const String& ESP8266WebServer::header(int i) const {
if (i < _headerKeysCount)
return _currentHeaders[i].value;
return "";
return emptyString;
}

String ESP8266WebServer::headerName(int i) {
const String& ESP8266WebServer::headerName(int i) const {
if (i < _headerKeysCount)
return _currentHeaders[i].key;
return "";
return emptyString;
}

int ESP8266WebServer::headers() {
int ESP8266WebServer::headers() const {
return _headerKeysCount;
}

bool ESP8266WebServer::hasHeader(String name) {
bool ESP8266WebServer::hasHeader(String name) const {
for (int i = 0; i < _headerKeysCount; ++i) {
if ((_currentHeaders[i].key.equalsIgnoreCase(name)) && (_currentHeaders[i].value.length() > 0))
return true;
}
return false;
}

String ESP8266WebServer::hostHeader() {
const String& ESP8266WebServer::hostHeader() const {
return _hostHeader;
}

Expand Down Expand Up @@ -612,11 +612,11 @@ void ESP8266WebServer::_handleRequest() {

void ESP8266WebServer::_finalizeResponse() {
if (_chunked) {
sendContent("");
sendContent(emptyString);
}
}

String ESP8266WebServer::_responseCodeToString(int code) {
const String ESP8266WebServer::_responseCodeToString(int code) {
switch (code) {
case 100: return F("Continue");
case 101: return F("Switching Protocols");
Expand Down
41 changes: 20 additions & 21 deletions libraries/ESP8266WebServer/src/ESP8266WebServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,24 +92,23 @@ class ESP8266WebServer
void onNotFound(THandlerFunction fn); //called when handler is not assigned
void onFileUpload(THandlerFunction fn); //handle file uploads

String uri() { return _currentUri; }
HTTPMethod method() { return _currentMethod; }
const String& uri() const { return _currentUri; }
HTTPMethod method() const { return _currentMethod; }
virtual WiFiClient client() { return _currentClient; }
HTTPUpload& upload() { return *_currentUpload; }

String arg(String name); // get request argument value by name
String arg(int i); // get request argument value by number
String argName(int i); // get request argument name by number
int args(); // get arguments count
bool hasArg(String name); // check if argument exists
const String& arg(String name) const; // get request argument value by name
const String& arg(int i) const; // get request argument value by number
const String& argName(int i) const; // get request argument name by number
int args() const; // get arguments count
bool hasArg(const String& name) const; // check if argument exists
void collectHeaders(const char* headerKeys[], const size_t headerKeysCount); // set the request headers to collect
String header(String name); // get request header value by name
String header(int i); // get request header value by number
String headerName(int i); // get request header name by number
int headers(); // get header count
bool hasHeader(String name); // check if header exists

String hostHeader(); // get request host header if available or empty String if not
const String& header(String name) const; // get request header value by name
const String& header(int i) const; // get request header value by number
const String& headerName(int i) const; // get request header name by number
int headers() const; // get header count
bool hasHeader(String name) const; // check if header exists
const String& hostHeader() const; // get request host header if available or empty String if not

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

static String urlDecode(const String& text);

template<typename T>
template<typename T>
size_t streamFile(T &file, const String& contentType) {
_streamFileCore(file.size(), file.name(), contentType);
return _currentClient.write(file);
}

protected:
virtual size_t _currentClientWrite(const char* b, size_t l) { return _currentClient.write( b, l ); }
virtual size_t _currentClientWrite_P(PGM_P b, size_t l) { return _currentClient.write_P( b, l ); }
Expand All @@ -144,19 +143,19 @@ class ESP8266WebServer
bool _parseRequest(WiFiClient& client);
void _parseArguments(const String& data);
int _parseArgumentsPrivate(const String& data, std::function<void(String&,String&,const String&,int,int,int,int)> handler);
static String _responseCodeToString(int code);
bool _parseForm(WiFiClient& client, String boundary, uint32_t len);
static const String _responseCodeToString(int code);
bool _parseForm(WiFiClient& client, const String& boundary, uint32_t len);
bool _parseFormUploadAborted();
void _uploadWriteByte(uint8_t b);
uint8_t _uploadReadByte(WiFiClient& client);
void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength);
bool _collectHeader(const char* headerName, const char* headerValue);

void _streamFileCore(const size_t fileSize, const String & fileName, const String & contentType);

String _getRandomHexString();
static String _getRandomHexString();
// for extracting Auth parameters
String _extractParam(String& authReq,const String& param,const char delimit = '"');
String _extractParam(String& authReq,const String& param,const char delimit = '"') const;

struct RequestArgument {
String key;
Expand Down
91 changes: 44 additions & 47 deletions libraries/ESP8266WebServer/src/Parsing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,41 +35,33 @@
static const char Content_Type[] PROGMEM = "Content-Type";
static const char filename[] PROGMEM = "filename";

static char* readBytesWithTimeout(WiFiClient& client, size_t maxLength, size_t& dataLength, int timeout_ms)
static bool readBytesWithTimeout(WiFiClient& client, size_t maxLength, String& data, int timeout_ms)
{
char *buf = nullptr;
dataLength = 0;
while (dataLength < maxLength) {
if (!data.reserve(maxLength + 1))
return false;
data[0] = 0; // data.clear()??
while (data.length() < maxLength) {
int tries = timeout_ms;
size_t newLength;
while (!(newLength = client.available()) && tries--) delay(1);
if (!newLength) {
size_t avail;
while (!(avail = client.available()) && tries--)
delay(1);
if (!avail)
break;
}
if (!buf) {
buf = (char *) malloc(newLength + 1);
if (!buf) {
return nullptr;
}
}
else {
char* newBuf = (char *) realloc(buf, dataLength + newLength + 1);
if (!newBuf) {
free(buf);
return nullptr;
}
buf = newBuf;
}
client.readBytes(buf + dataLength, newLength);
dataLength += newLength;
buf[dataLength] = '\0';
if (data.length() + avail > maxLength)
avail = maxLength - data.length();
while (avail--)
data += (char)client.read();
}
return buf;
return data.length() == maxLength;
}

bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
// Read the first line of HTTP request
String req = client.readStringUntil('\r');
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("request: ");
DEBUG_OUTPUT.println(req);
#endif
client.readStringUntil('\n');
//reset header value
for (int i = 0; i < _headerKeysCount; ++i) {
Expand All @@ -82,8 +74,7 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
int addr_end = req.indexOf(' ', addr_start + 1);
if (addr_start == -1 || addr_end == -1) {
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("Invalid request: ");
DEBUG_OUTPUT.println(req);
DEBUG_OUTPUT.println("Invalid request");
#endif
return false;
}
Expand Down Expand Up @@ -139,7 +130,7 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
String headerName;
String headerValue;
bool isForm = false;
//bool isEncoded = false;
bool isEncoded = false;
uint32_t contentLength = 0;
//parse headers
while(1){
Expand Down Expand Up @@ -168,7 +159,7 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
isForm = false;
} else if (headerValue.startsWith(F("application/x-www-form-urlencoded"))){
isForm = false;
//isEncoded = true;
isEncoded = true;
} else if (headerValue.startsWith(F("multipart/"))){
boundaryStr = headerValue.substring(headerValue.indexOf('=') + 1);
boundaryStr.replace("\"","");
Expand All @@ -181,34 +172,40 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
}
}

// always parse url for key/value pairs
String plainBuf;
if ( !isForm
&& // read content into plainBuf
( !readBytesWithTimeout(client, contentLength, plainBuf, HTTP_MAX_POST_WAIT)
|| (plainBuf.length() < contentLength)
)
)
{
return false;
}

if (isEncoded) {
// isEncoded => !isForm => plainBuf is not empty
// add plainBuf in search str
if (searchStr.length())
searchStr += '&';
searchStr += plainBuf;
}

// parse searchStr for key/value pairs
_parseArguments(searchStr);

if (!isForm) {
if (contentLength) {

// add key=value: plain={body} (post json or other data)

size_t plainLength;
char* plainBuf = readBytesWithTimeout(client, contentLength, plainLength, HTTP_MAX_POST_WAIT);
if (plainLength < contentLength) {
free(plainBuf);
return false;
}

RequestArgument& arg = _currentArgs[_currentArgCount++];
arg.key = F("plain");
arg.value = String(plainBuf);

free(plainBuf);

arg.value = plainBuf;
}
} else { // isForm is true

// here: content is not yet read (plainBuf is still empty)
if (!_parseForm(client, boundaryStr, contentLength)) {
return false;
}

}
} else {
String headerName;
Expand Down Expand Up @@ -368,7 +365,7 @@ uint8_t ESP8266WebServer::_uploadReadByte(WiFiClient& client){
return (uint8_t)res;
}

bool ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){
bool ESP8266WebServer::_parseForm(WiFiClient& client, const String& boundary, uint32_t len){
(void) len;
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("Parse Form: Boundary: ");
Expand Down