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

Rewrite multipart boundary detection #7728

Merged
merged 3 commits into from
Nov 29, 2020
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
2 changes: 1 addition & 1 deletion libraries/ESP8266WebServer/src/ESP8266WebServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ class ESP8266WebServerTemplate
bool _parseForm(ClientType& client, const String& boundary, uint32_t len);
bool _parseFormUploadAborted();
void _uploadWriteByte(uint8_t b);
uint8_t _uploadReadByte(ClientType& client);
int _uploadReadByte(ClientType& client);
void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength);
bool _collectHeader(const char* headerName, const char* headerValue);

Expand Down
63 changes: 26 additions & 37 deletions libraries/ESP8266WebServer/src/Parsing-impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -347,14 +347,14 @@ void ESP8266WebServerTemplate<ServerType>::_uploadWriteByte(uint8_t b){
}

template <typename ServerType>
uint8_t ESP8266WebServerTemplate<ServerType>::_uploadReadByte(ClientType& client){
int ESP8266WebServerTemplate<ServerType>::_uploadReadByte(ClientType& client){
int res = client.read();
if(res == -1){
while(!client.available() && client.connected())
yield();
res = client.read();
}
return (uint8_t)res;
return res;
}


Expand Down Expand Up @@ -444,45 +444,34 @@ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const
_currentHandler->upload(*this, _currentUri, *_currentUpload);
_currentUpload->status = UPLOAD_FILE_WRITE;

int bLen = boundary.length();
uint8_t boundBuf[2 + bLen + 1]; // "--" + boundary + null terminator
boundBuf[2 + bLen] = '\0';
uint8_t argByte;
bool first = true;
while (1) {
//attempt to fill up boundary buffer with length of boundary string
int i;
for (i = 0; i < 2 + bLen; i++) {
if (!client.connected()) return _parseFormUploadAborted();
argByte = _uploadReadByte(client);
if (argByte == '\r')
break;
boundBuf[i] = argByte;
}
if ((strncmp((const char*)boundBuf, "--", 2) == 0) && (strcmp((const char*)(boundBuf + 2), boundary.c_str()) == 0))
break; //found the boundary, done parsing this file
if (first) first = false; //only add newline characters after the first line
else {
_uploadWriteByte('\r');
_uploadWriteByte('\n');
int fastBoundaryLen = 4 /* \r\n-- */ + boundary.length() + 1 /* \0 */;
char fastBoundary[ fastBoundaryLen ];
snprintf(fastBoundary, fastBoundaryLen, "\r\n--%s", boundary.c_str());
int boundaryPtr = 0;
while ( true ) {
int ret = _uploadReadByte(client);
if (ret < 0) {
// Unexpected, we should have had data available per above
return _parseFormUploadAborted();
}
// current line does not contain boundary, upload all bytes in boundary buffer
for (int j = 0; j < i; j++)
_uploadWriteByte(boundBuf[j]);
// the initial pass (filling up the boundary buffer) did not reach the end of the line. Upload the rest of the line now
if (i >= 2 + bLen) {
if (!client.connected()) return _parseFormUploadAborted();
argByte = _uploadReadByte(client);
while (argByte != '\r') {
if (!client.connected()) return _parseFormUploadAborted();
_uploadWriteByte(argByte);
argByte = _uploadReadByte(client);
char in = (char) ret;
if (in == fastBoundary[ boundaryPtr ]) {
// The input matched the current expected character, advance and possibly exit this file
boundaryPtr++;
if (boundaryPtr == fastBoundaryLen - 1) {
// We read the whole boundary line, we're done here!
break;
}
} else {
// The char doesn't match what we want, so dump whatever matches we had, the read in char, and reset ptr to start
for (int i = 0; i < boundaryPtr; i++) {
_uploadWriteByte( fastBoundary[ i ] );
}
_uploadWriteByte( in );
boundaryPtr = 0;
}
if (!client.connected()) return _parseFormUploadAborted();
_uploadReadByte(client); // '\n'
}
//Found the boundary string, finish processing this file upload
// Found the boundary string, finish processing this file upload
if (_currentHandler && _currentHandler->canUpload(_currentUri))
_currentHandler->upload(*this, _currentUri, *_currentUpload);
_currentUpload->totalSize += _currentUpload->currentSize;
Expand Down