Unverified Commit de1774b7 authored by Jason2866's avatar Jason2866 Committed by GitHub

simplifying webserver file uploads via form POST (#9211)

Backport of #9167
parent 7c344cc8
...@@ -309,42 +309,14 @@ void WebServer::_uploadWriteByte(uint8_t b){ ...@@ -309,42 +309,14 @@ void WebServer::_uploadWriteByte(uint8_t b){
_currentUpload->buf[_currentUpload->currentSize++] = b; _currentUpload->buf[_currentUpload->currentSize++] = b;
} }
int WebServer::_uploadReadByte(WiFiClient& client){ int WebServer::_uploadReadByte(WiFiClient& client) {
int res = client.read(); int res = client.read();
if(res < 0) {
// keep trying until you either read a valid byte or timeout if (res < 0) {
unsigned long startMillis = millis(); while(!client.available() && client.connected())
long timeoutIntervalMillis = client.getTimeout();
boolean timedOut = false;
for(;;) {
if (!client.connected()) return -1;
// loosely modeled after blinkWithoutDelay pattern
while(!timedOut && !client.available() && client.connected()){
delay(2); delay(2);
timedOut = millis() - startMillis >= timeoutIntervalMillis;
}
res = client.read(); res = client.read();
if(res >= 0) {
return res; // exit on a valid read
}
// NOTE: it is possible to get here and have all of the following
// assertions hold true
//
// -- client.available() > 0
// -- client.connected == true
// -- res == -1
//
// a simple retry strategy overcomes this which is to say the
// assertion is not permanent, but the reason that this works
// is elusive, and possibly indicative of a more subtle underlying
// issue
timedOut = millis() - startMillis >= timeoutIntervalMillis;
if(timedOut) {
return res; // exit on a timeout
}
}
} }
return res; return res;
...@@ -436,88 +408,59 @@ bool WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){ ...@@ -436,88 +408,59 @@ bool WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){
if(_currentHandler && _currentHandler->canUpload(_currentUri)) if(_currentHandler && _currentHandler->canUpload(_currentUri))
_currentHandler->upload(*this, _currentUri, *_currentUpload); _currentHandler->upload(*this, _currentUri, *_currentUpload);
_currentUpload->status = UPLOAD_FILE_WRITE; _currentUpload->status = UPLOAD_FILE_WRITE;
int argByte = _uploadReadByte(client);
readfile: int fastBoundaryLen = 4 /* \r\n-- */ + boundary.length() + 1 /* \0 */;
char fastBoundary[ fastBoundaryLen ];
while(argByte != 0x0D){ snprintf(fastBoundary, fastBoundaryLen, "\r\n--%s", boundary.c_str());
if(argByte < 0) return _parseFormUploadAborted(); int boundaryPtr = 0;
_uploadWriteByte(argByte); while ( true ) {
argByte = _uploadReadByte(client); int ret = _uploadReadByte(client);
} if (ret < 0) {
// Unexpected, we should have had data available per above
argByte = _uploadReadByte(client); return _parseFormUploadAborted();
if(argByte < 0) return _parseFormUploadAborted(); }
if (argByte == 0x0A){ char in = (char) ret;
argByte = _uploadReadByte(client); if (in == fastBoundary[ boundaryPtr ]) {
if(argByte < 0) return _parseFormUploadAborted(); // The input matched the current expected character, advance and possibly exit this file
if ((char)argByte != '-'){ boundaryPtr++;
//continue reading the file if (boundaryPtr == fastBoundaryLen - 1) {
_uploadWriteByte(0x0D); // We read the whole boundary line, we're done here!
_uploadWriteByte(0x0A); break;
goto readfile;
} else {
argByte = _uploadReadByte(client);
if(argByte < 0) return _parseFormUploadAborted();
if ((char)argByte != '-'){
//continue reading the file
_uploadWriteByte(0x0D);
_uploadWriteByte(0x0A);
_uploadWriteByte((uint8_t)('-'));
goto readfile;
} }
} 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 ] );
} }
if (in == fastBoundary[ 0 ]) {
uint8_t endBuf[boundary.length()]; // This could be the start of the real end, mark it so and don't emit/skip it
uint32_t i = 0; boundaryPtr = 1;
while(i < boundary.length()){ } else {
argByte = _uploadReadByte(client); // Not the 1st char of our pattern, so emit and ignore
if(argByte < 0) return _parseFormUploadAborted(); _uploadWriteByte( in );
if ((char)argByte == 0x0D){ boundaryPtr = 0;
_uploadWriteByte(0x0D);
_uploadWriteByte(0x0A);
_uploadWriteByte((uint8_t)('-'));
_uploadWriteByte((uint8_t)('-'));
uint32_t j = 0;
while(j < i){
_uploadWriteByte(endBuf[j++]);
} }
goto readfile;
} }
endBuf[i++] = (uint8_t)argByte;
} }
// Found the boundary string, finish processing this file upload
if (strstr((const char*)endBuf, boundary.c_str()) != NULL){ if (_currentHandler && _currentHandler->canUpload(_currentUri))
if(_currentHandler && _currentHandler->canUpload(_currentUri))
_currentHandler->upload(*this, _currentUri, *_currentUpload); _currentHandler->upload(*this, _currentUri, *_currentUpload);
_currentUpload->totalSize += _currentUpload->currentSize; _currentUpload->totalSize += _currentUpload->currentSize;
_currentUpload->status = UPLOAD_FILE_END; _currentUpload->status = UPLOAD_FILE_END;
if(_currentHandler && _currentHandler->canUpload(_currentUri)) if (_currentHandler && _currentHandler->canUpload(_currentUri))
_currentHandler->upload(*this, _currentUri, *_currentUpload); _currentHandler->upload(*this, _currentUri, *_currentUpload);
log_v("End File: %s Type: %s Size: %d", _currentUpload->filename.c_str(), _currentUpload->type.c_str(), _currentUpload->totalSize); log_v("End File: %s Type: %s Size: %d",
line = client.readStringUntil(0x0D); _currentUpload->filename.c_str(),
client.readStringUntil(0x0A); _currentUpload->type.c_str(),
if (line == "--"){ (int)_currentUpload->totalSize);
if (!client.connected()) return _parseFormUploadAborted();
line = client.readStringUntil('\r');
client.readStringUntil('\n');
if (line == "--") { // extra two dashes mean we reached the end of all form fields
log_v("Done Parsing POST"); log_v("Done Parsing POST");
break; break;
} }
continue; continue;
} else {
_uploadWriteByte(0x0D);
_uploadWriteByte(0x0A);
_uploadWriteByte((uint8_t)('-'));
_uploadWriteByte((uint8_t)('-'));
uint32_t i = 0;
while(i < boundary.length()){
_uploadWriteByte(endBuf[i++]);
}
argByte = _uploadReadByte(client);
goto readfile;
}
} else {
_uploadWriteByte(0x0D);
goto readfile;
}
break;
} }
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment