aboutsummaryrefslogtreecommitdiff
path: root/backends/networking/sdl_net/reader.cpp
diff options
context:
space:
mode:
authorAlexander Tkachev2016-08-02 12:32:48 +0600
committerAlexander Tkachev2016-08-24 16:07:55 +0600
commit97cf2be7ef4ee5041ade5cd6f1b150d014653ed3 (patch)
treeb6631b79767cf73b4325497eaa5d996d1a5bc8f5 /backends/networking/sdl_net/reader.cpp
parentdc02a789b6b2fc4e7693b2e7e69ff57b2767b889 (diff)
downloadscummvm-rg350-97cf2be7ef4ee5041ade5cd6f1b150d014653ed3.tar.gz
scummvm-rg350-97cf2be7ef4ee5041ade5cd6f1b150d014653ed3.tar.bz2
scummvm-rg350-97cf2be7ef4ee5041ade5cd6f1b150d014653ed3.zip
CLOUD: Update LocalWebserver
Reader now reads headers into stream, and some checks are added there and in UploadFileClientHandler, so if headers are too long, they are treated as bad request.
Diffstat (limited to 'backends/networking/sdl_net/reader.cpp')
-rw-r--r--backends/networking/sdl_net/reader.cpp143
1 files changed, 80 insertions, 63 deletions
diff --git a/backends/networking/sdl_net/reader.cpp b/backends/networking/sdl_net/reader.cpp
index 0e4cc9a106..8f3199f51c 100644
--- a/backends/networking/sdl_net/reader.cpp
+++ b/backends/networking/sdl_net/reader.cpp
@@ -37,7 +37,7 @@ Reader::Reader() {
_windowUsed = 0;
_windowSize = 0;
- _headers = "";
+ _headersStream = nullptr;
_firstBlock = true;
_contentLength = 0;
@@ -65,6 +65,9 @@ Reader &Reader::operator=(Reader &r) {
_windowSize = r._windowSize;
r._window = nullptr;
+ _headersStream = r._headersStream;
+ r._headersStream = nullptr;
+
_headers = r._headers;
_method = r._method;
_path = r._path;
@@ -84,6 +87,9 @@ Reader &Reader::operator=(Reader &r) {
void Reader::cleanup() {
//_content is not to be freed, it's not owned by Reader
+ if (_headersStream != nullptr)
+ delete _headersStream;
+
if (_window != nullptr)
freeWindow();
}
@@ -92,14 +98,20 @@ bool Reader::readAndHandleFirstHeaders() {
Common::String boundary = "\r\n\r\n";
if (_window == nullptr) {
makeWindow(boundary.size());
- _headers = "";
+ }
+ if (_headersStream == nullptr) {
+ _headersStream = new Common::MemoryReadWriteStream(DisposeAfterUse::YES);
}
- while (readOneByteInString(_headers, boundary)) {
+ while (readOneByteInStream(_headersStream, boundary)) {
+ if (_headersStream->size() > SUSPICIOUS_HEADERS_SIZE) {
+ _isBadRequest = true;
+ return true;
+ }
if (!bytesLeft())
return false;
}
- handleFirstHeaders(_headers);
+ handleFirstHeaders(_headersStream);
freeWindow();
_state = RS_READING_CONTENT;
@@ -136,22 +148,23 @@ void readFromThatUntilLineEnd(const char *cstr, Common::String needle, Common::S
}
}
-void Reader::handleFirstHeaders(Common::String headers) {
+void Reader::handleFirstHeaders(Common::MemoryReadWriteStream *headersStream) {
if (!_boundary.empty()) {
warning("Reader: handleFirstHeaders() called when first headers were already handled");
return;
}
//parse method, path, query, fragment
- parseFirstLine(headers);
+ _headers = readEverythingFromMemoryStream(headersStream);
+ parseFirstLine(_headers);
//find boundary
_boundary = "";
- readFromThatUntilLineEnd(headers.c_str(), "boundary=", _boundary);
+ readFromThatUntilLineEnd(_headers.c_str(), "boundary=", _boundary);
//find content length
Common::String contentLength = "";
- readFromThatUntilLineEnd(headers.c_str(), "Content-Length: ", contentLength);
+ readFromThatUntilLineEnd(_headers.c_str(), "Content-Length: ", contentLength);
_contentLength = contentLength.asUint64();
_availableBytes = _contentLength;
}
@@ -160,48 +173,43 @@ void Reader::parseFirstLine(const Common::String &headers) {
uint32 headersSize = headers.size();
bool bad = false;
- const uint32 SUSPICIOUS_HEADERS_SIZE = 128 * 1024;
- if (headersSize > SUSPICIOUS_HEADERS_SIZE) bad = true;
-
- if (!bad) {
- if (headersSize > 0) {
- const char *cstr = headers.c_str();
- const char *position = strstr(cstr, "\r\n");
- if (position) { //we have at least one line - and we want the first one
- //"<METHOD> <path> HTTP/<VERSION>\r\n"
- Common::String method, path, http, buf;
- uint32 length = position - cstr;
- if (headersSize > length)
- headersSize = length;
- for (uint32 i = 0; i < headersSize; ++i) {
- if (headers[i] != ' ')
- buf += headers[i];
- if (headers[i] == ' ' || i == headersSize - 1) {
- if (method == "") {
- method = buf;
- } else if (path == "") {
- path = buf;
- } else if (http == "") {
- http = buf;
- } else {
- bad = true;
- break;
- }
- buf = "";
+ if (headersSize > 0) {
+ const char *cstr = headers.c_str();
+ const char *position = strstr(cstr, "\r\n");
+ if (position) { //we have at least one line - and we want the first one
+ //"<METHOD> <path> HTTP/<VERSION>\r\n"
+ Common::String method, path, http, buf;
+ uint32 length = position - cstr;
+ if (headersSize > length)
+ headersSize = length;
+ for (uint32 i = 0; i < headersSize; ++i) {
+ if (headers[i] != ' ')
+ buf += headers[i];
+ if (headers[i] == ' ' || i == headersSize - 1) {
+ if (method == "") {
+ method = buf;
+ } else if (path == "") {
+ path = buf;
+ } else if (http == "") {
+ http = buf;
+ } else {
+ bad = true;
+ break;
}
+ buf = "";
}
+ }
- //check that method is supported
- if (method != "GET" && method != "PUT" && method != "POST")
- bad = true;
+ //check that method is supported
+ if (method != "GET" && method != "PUT" && method != "POST")
+ bad = true;
- //check that HTTP/<VERSION> is OK
- if (!http.hasPrefix("HTTP/"))
- bad = true;
+ //check that HTTP/<VERSION> is OK
+ if (!http.hasPrefix("HTTP/"))
+ bad = true;
- _method = method;
- parsePathQueryAndAnchor(path);
- }
+ _method = method;
+ parsePathQueryAndAnchor(path);
}
}
@@ -308,37 +316,33 @@ void Reader::freeWindow() {
_windowUsed = _windowSize = 0;
}
-bool Reader::readOneByteInStream(Common::WriteStream *stream, const Common::String &boundary) {
- byte b = readOne();
- _window[_windowUsed++] = b;
- if (_windowUsed < _windowSize)
- return true;
-
- //when window is filled, check whether that's the boundary
- if (Common::String((char *)_window, _windowSize) == boundary)
+namespace {
+bool windowEqualsString(const byte *window, uint32 windowSize, const Common::String &boundary) {
+ if (boundary.size() != windowSize)
return false;
- //if not, add the first byte of the window to the string
- if (stream)
- stream->writeByte(_window[0]);
- for (uint32 i = 1; i < _windowSize; ++i)
- _window[i - 1] = _window[i];
- --_windowUsed;
+ for (uint32 i = 0; i < windowSize; ++i) {
+ if (window[i] != boundary[i])
+ return false;
+ }
+
return true;
}
+}
-bool Reader::readOneByteInString(Common::String &buffer, const Common::String &boundary) {
+bool Reader::readOneByteInStream(Common::WriteStream *stream, const Common::String &boundary) {
byte b = readOne();
_window[_windowUsed++] = b;
if (_windowUsed < _windowSize)
return true;
//when window is filled, check whether that's the boundary
- if (Common::String((char *)_window, _windowSize) == boundary)
+ if (windowEqualsString(_window, _windowSize, boundary))
return false;
//if not, add the first byte of the window to the string
- buffer += _window[0];
+ if (stream)
+ stream->writeByte(_window[0]);
for (uint32 i = 1; i < _windowSize; ++i)
_window[i - 1] = _window[i];
--_windowUsed;
@@ -419,7 +423,7 @@ bool Reader::readBlockContent(Common::WriteStream *stream) {
return true;
}
-uint32 Reader::bytesLeft() { return _bytesLeft; }
+uint32 Reader::bytesLeft() const { return _bytesLeft; }
void Reader::setContent(Common::MemoryReadWriteStream *stream) {
_content = stream;
@@ -442,4 +446,17 @@ Common::String Reader::queryParameter(Common::String name) const { return _query
Common::String Reader::anchor() const { return _anchor; }
+Common::String Reader::readEverythingFromMemoryStream(Common::MemoryReadWriteStream *stream) {
+ Common::String result;
+ char buf[1024];
+ uint32 readBytes;
+ while (true) {
+ readBytes = stream->read(buf, 1024);
+ if (readBytes == 0)
+ break;
+ result += Common::String(buf, readBytes);
+ }
+ return result;
+}
+
} // End of namespace Networking