Skip to content

Commit 5d2563e

Browse files
authored
Fixed bug in parsing POST file uploads (#7543)
The boundary parsing in the webserver could end up missing boundaries if the uploaded file had `--` at the start of the line because it read in the entire boundary length worth of bytes. Fix by only reading up to either the boundary length or a newline, avoiding the issue. Fixes #7542
1 parent 1bb0815 commit 5d2563e

File tree

1 file changed

+54
-63
lines changed

1 file changed

+54
-63
lines changed

libraries/ESP8266WebServer/src/Parsing-impl.h

Lines changed: 54 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ uint8_t ESP8266WebServerTemplate<ServerType>::_uploadReadByte(ClientType& client
357357
return (uint8_t)res;
358358
}
359359

360+
360361
template <typename ServerType>
361362
bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const String& boundary, uint32_t len){
362363
(void) len;
@@ -442,74 +443,64 @@ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const
442443
if(_currentHandler && _currentHandler->canUpload(_currentUri))
443444
_currentHandler->upload(*this, _currentUri, *_currentUpload);
444445
_currentUpload->status = UPLOAD_FILE_WRITE;
445-
uint8_t argByte = _uploadReadByte(client);
446-
readfile:
447-
while(argByte != 0x0D){
448-
if (!client.connected()) return _parseFormUploadAborted();
449-
_uploadWriteByte(argByte);
450-
argByte = _uploadReadByte(client);
451-
}
452446

453-
argByte = _uploadReadByte(client);
454-
if (!client.connected()) return _parseFormUploadAborted();
455-
if (argByte == 0x0A){
456-
argByte = _uploadReadByte(client);
457-
if (!client.connected()) return _parseFormUploadAborted();
458-
if ((char)argByte != '-'){
459-
//continue reading the file
460-
_uploadWriteByte(0x0D);
461-
_uploadWriteByte(0x0A);
462-
goto readfile;
463-
} else {
464-
argByte = _uploadReadByte(client);
465-
if (!client.connected()) return _parseFormUploadAborted();
466-
if ((char)argByte != '-'){
467-
//continue reading the file
468-
_uploadWriteByte(0x0D);
469-
_uploadWriteByte(0x0A);
470-
_uploadWriteByte((uint8_t)('-'));
471-
goto readfile;
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;
472461
}
473-
}
474-
475-
uint8_t endBuf[boundary.length()];
476-
client.readBytes(endBuf, boundary.length());
477-
478-
if (strstr((const char*)endBuf, boundary.c_str()) != NULL){
479-
if(_currentHandler && _currentHandler->canUpload(_currentUri))
480-
_currentHandler->upload(*this, _currentUri, *_currentUpload);
481-
_currentUpload->totalSize += _currentUpload->currentSize;
482-
_currentUpload->status = UPLOAD_FILE_END;
483-
if(_currentHandler && _currentHandler->canUpload(_currentUri))
484-
_currentHandler->upload(*this, _currentUri, *_currentUpload);
485-
DBGWS("End File: %s Type: %s Size: %d\n",
486-
_currentUpload->filename.c_str(),
487-
_currentUpload->type.c_str(),
488-
(int)_currentUpload->totalSize);
489-
line = client.readStringUntil(0x0D);
490-
client.readStringUntil(0x0A);
491-
if (line == "--"){
492-
DBGWS("Done Parsing POST\n");
493-
break;
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');
494468
}
495-
continue;
496-
} else {
497-
_uploadWriteByte(0x0D);
498-
_uploadWriteByte(0x0A);
499-
_uploadWriteByte((uint8_t)('-'));
500-
_uploadWriteByte((uint8_t)('-'));
501-
uint32_t i = 0;
502-
while(i < boundary.length()){
503-
_uploadWriteByte(endBuf[i++]);
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);
480+
}
504481
}
505-
argByte = _uploadReadByte(client);
506-
goto readfile;
507-
}
508-
} else {
509-
_uploadWriteByte(0x0D);
510-
goto readfile;
482+
if (!client.connected()) return _parseFormUploadAborted();
483+
_uploadReadByte(client); // '\n'
484+
}
485+
//Found the boundary string, finish processing this file upload
486+
if (_currentHandler && _currentHandler->canUpload(_currentUri))
487+
_currentHandler->upload(*this, _currentUri, *_currentUpload);
488+
_currentUpload->totalSize += _currentUpload->currentSize;
489+
_currentUpload->status = UPLOAD_FILE_END;
490+
if (_currentHandler && _currentHandler->canUpload(_currentUri))
491+
_currentHandler->upload(*this, _currentUri, *_currentUpload);
492+
DBGWS("End File: %s Type: %s Size: %d\n",
493+
_currentUpload->filename.c_str(),
494+
_currentUpload->type.c_str(),
495+
(int)_currentUpload->totalSize);
496+
if (!client.connected()) return _parseFormUploadAborted();
497+
line = client.readStringUntil('\r');
498+
client.readStringUntil('\n');
499+
if (line == "--") { // extra two dashes mean we reached the end of all form fields
500+
DBGWS("Done Parsing POST\n");
501+
break;
511502
}
512-
break;
503+
continue;
513504
}
514505
}
515506
}

0 commit comments

Comments
 (0)