Skip to content

Commit b813a80

Browse files
Rewrite multipart boundary detection
Use a simpler, cleaner implementation of multipart form detection as defined in https://tools.ietf.org/html/rfc7578 . Implements a simple state machine that detects the \r\n--<boundary> stream in input a character at a time, instead of buffering and comparing in chunks which can miss things due to alignment issues and which also had a problem with replacing characters in a binary stream. Fixes esp8266#7723
1 parent 8c7fd6a commit b813a80

File tree

1 file changed

+23
-35
lines changed

1 file changed

+23
-35
lines changed

libraries/ESP8266WebServer/src/Parsing-impl.h

+23-35
Original file line numberDiff line numberDiff line change
@@ -444,45 +444,33 @@ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const
444444
_currentHandler->upload(*this, _currentUri, *_currentUpload);
445445
_currentUpload->status = UPLOAD_FILE_WRITE;
446446

447-
int bLen = boundary.length();
448-
uint8_t boundBuf[2 + bLen + 1]; // "--" + boundary + null terminator
449-
boundBuf[2 + bLen] = '\0';
450-
uint8_t argByte;
451-
bool first = true;
452-
while (1) {
453-
//attempt to fill up boundary buffer with length of boundary string
454-
int i;
455-
for (i = 0; i < 2 + bLen; i++) {
456-
if (!client.connected()) return _parseFormUploadAborted();
457-
argByte = _uploadReadByte(client);
458-
if (argByte == '\r')
459-
break;
460-
boundBuf[i] = argByte;
461-
}
462-
if ((strncmp((const char*)boundBuf, "--", 2) == 0) && (strcmp((const char*)(boundBuf + 2), boundary.c_str()) == 0))
463-
break; //found the boundary, done parsing this file
464-
if (first) first = false; //only add newline characters after the first line
465-
else {
466-
_uploadWriteByte('\r');
467-
_uploadWriteByte('\n');
447+
int fastBoundaryLen = 4 /* \r\n-- */ + boundary.length() + 1 /* \0 */;
448+
char fastBoundary[ fastBoundaryLen ];
449+
snprintf(fastBoundary, fastBoundaryLen, "\r\n--%s", boundary.c_str());
450+
int boundaryPtr = 0;
451+
while ( true ) {
452+
if ( !client.connected() ) {
453+
// Unexpected disconnection, abort!
454+
return _parseFormUploadAborted();
468455
}
469-
// current line does not contain boundary, upload all bytes in boundary buffer
470-
for (int j = 0; j < i; j++)
471-
_uploadWriteByte(boundBuf[j]);
472-
// the initial pass (filling up the boundary buffer) did not reach the end of the line. Upload the rest of the line now
473-
if (i >= 2 + bLen) {
474-
if (!client.connected()) return _parseFormUploadAborted();
475-
argByte = _uploadReadByte(client);
476-
while (argByte != '\r') {
477-
if (!client.connected()) return _parseFormUploadAborted();
478-
_uploadWriteByte(argByte);
479-
argByte = _uploadReadByte(client);
456+
char in = _uploadReadByte(client);
457+
if (in == fastBoundary[ boundaryPtr ]) {
458+
// The input matched the current expected character, advance and possibly exit this file
459+
boundaryPtr++;
460+
if (boundaryPtr == fastBoundaryLen - 1) {
461+
// We read the whole boundary line, we're done here!
462+
break;
463+
}
464+
} else {
465+
// The char doesn't match what we want, so dump whatever matches we had, the read in char, and reset ptr to start
466+
for (int i = 0; i < boundaryPtr; i++) {
467+
_uploadWriteByte( fastBoundary[ i ] );
480468
}
469+
_uploadWriteByte( in );
470+
boundaryPtr = 0;
481471
}
482-
if (!client.connected()) return _parseFormUploadAborted();
483-
_uploadReadByte(client); // '\n'
484472
}
485-
//Found the boundary string, finish processing this file upload
473+
// Found the boundary string, finish processing this file upload
486474
if (_currentHandler && _currentHandler->canUpload(_currentUri))
487475
_currentHandler->upload(*this, _currentUri, *_currentUpload);
488476
_currentUpload->totalSize += _currentUpload->currentSize;

0 commit comments

Comments
 (0)