ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

reader.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "backends/networking/sdl_net/reader.h"
00024 #include "backends/fs/fs-factory.h"
00025 #include "backends/networking/sdl_net/localwebserver.h"
00026 #include "common/memstream.h"
00027 #include "common/stream.h"
00028 
00029 namespace Networking {
00030 
00031 Reader::Reader() {
00032     _state = RS_NONE;
00033     _content = nullptr;
00034     _bytesLeft = 0;
00035 
00036     _window = nullptr;
00037     _windowUsed = 0;
00038     _windowSize = 0;
00039 
00040     _headersStream = nullptr;
00041     _firstBlock = true;
00042 
00043     _contentLength = 0;
00044     _availableBytes = 0;
00045     _isBadRequest = false;
00046     _allContentRead = false;
00047 }
00048 
00049 Reader::~Reader() {
00050     cleanup();
00051 }
00052 
00053 Reader &Reader::operator=(Reader &r) {
00054     if (this == &r)
00055         return *this;
00056     cleanup();
00057 
00058     _state = r._state;
00059     _content = r._content;
00060     _bytesLeft = r._bytesLeft;
00061     r._state = RS_NONE;
00062 
00063     _window = r._window;
00064     _windowUsed = r._windowUsed;
00065     _windowSize = r._windowSize;
00066     r._window = nullptr;
00067 
00068     _headersStream = r._headersStream;
00069     r._headersStream = nullptr;
00070 
00071     _headers = r._headers;
00072     _method = r._method;
00073     _path = r._path;
00074     _query = r._query;
00075     _anchor = r._anchor;
00076     _queryParameters = r._queryParameters;
00077     _contentLength = r._contentLength;
00078     _boundary = r._boundary;
00079     _availableBytes = r._availableBytes;
00080     _firstBlock = r._firstBlock;
00081     _isBadRequest = r._isBadRequest;
00082     _allContentRead = r._allContentRead;
00083 
00084     return *this;
00085 }
00086 
00087 void Reader::cleanup() {
00088     //_content is not to be freed, it's not owned by Reader
00089 
00090     if (_headersStream != nullptr)
00091         delete _headersStream;
00092 
00093     if (_window != nullptr)
00094         freeWindow();
00095 }
00096 
00097 bool Reader::readAndHandleFirstHeaders() {
00098     Common::String boundary = "\r\n\r\n";
00099     if (_window == nullptr) {
00100         makeWindow(boundary.size());
00101     }
00102     if (_headersStream == nullptr) {
00103         _headersStream = new Common::MemoryReadWriteStream(DisposeAfterUse::YES);
00104     }
00105 
00106     while (readOneByteInStream(_headersStream, boundary)) {
00107         if (_headersStream->size() > SUSPICIOUS_HEADERS_SIZE) {
00108             _isBadRequest = true;
00109             return true;
00110         }
00111         if (!bytesLeft())
00112             return false;
00113     }
00114     handleFirstHeaders(_headersStream);
00115 
00116     freeWindow();
00117     _state = RS_READING_CONTENT;
00118     return true;
00119 }
00120 
00121 bool Reader::readBlockHeadersIntoStream(Common::WriteStream *stream) {
00122     Common::String boundary = "\r\n\r\n";
00123     if (_window == nullptr) makeWindow(boundary.size());
00124 
00125     while (readOneByteInStream(stream, boundary)) {
00126         if (!bytesLeft())
00127             return false;
00128     }
00129     if (stream) stream->flush();
00130 
00131     freeWindow();
00132     _state = RS_READING_CONTENT;
00133     return true;
00134 }
00135 
00136 namespace {
00137 void readFromThatUntilLineEnd(const char *cstr, Common::String needle, Common::String &result) {
00138     const char *position = strstr(cstr, needle.c_str());
00139 
00140     if (position) {
00141         char c;
00142         for (const char *i = position + needle.size(); c = *i, c != 0; ++i) {
00143             if (c == '\n' || c == '\r')
00144                 break;
00145             result += c;
00146         }
00147     }
00148 }
00149 }
00150 
00151 void Reader::handleFirstHeaders(Common::MemoryReadWriteStream *headersStream) {
00152     if (!_boundary.empty()) {
00153         warning("Reader: handleFirstHeaders() called when first headers were already handled");
00154         return;
00155     }
00156 
00157     //parse method, path, query, fragment
00158     _headers = readEverythingFromMemoryStream(headersStream);
00159     parseFirstLine(_headers);
00160 
00161     //find boundary
00162     _boundary = "";
00163     readFromThatUntilLineEnd(_headers.c_str(), "boundary=", _boundary);
00164 
00165     //find content length
00166     Common::String contentLength = "";
00167     readFromThatUntilLineEnd(_headers.c_str(), "Content-Length: ", contentLength);
00168     _contentLength = contentLength.asUint64();
00169     _availableBytes = _contentLength;
00170 }
00171 
00172 void Reader::parseFirstLine(const Common::String &headersToParse) {
00173     uint32 headersSize = headersToParse.size();
00174     bool bad = false;
00175 
00176     if (headersSize > 0) {
00177         const char *cstr = headersToParse.c_str();
00178         const char *position = strstr(cstr, "\r\n");
00179         if (position) { //we have at least one line - and we want the first one
00180             //"<METHOD> <path> HTTP/<VERSION>\r\n"
00181             Common::String methodParsed, pathParsed, http, buf;
00182             uint32 length = position - cstr;
00183             if (headersSize > length)
00184                 headersSize = length;
00185             for (uint32 i = 0; i < headersSize; ++i) {
00186                 if (headersToParse[i] != ' ')
00187                     buf += headersToParse[i];
00188                 if (headersToParse[i] == ' ' || i == headersSize - 1) {
00189                     if (methodParsed == "") {
00190                         methodParsed = buf;
00191                     } else if (pathParsed == "") {
00192                         pathParsed = buf;
00193                     } else if (http == "") {
00194                         http = buf;
00195                     } else {
00196                         bad = true;
00197                         break;
00198                     }
00199                     buf = "";
00200                 }
00201             }
00202 
00203             //check that method is supported
00204             if (methodParsed != "GET" && methodParsed != "PUT" && methodParsed != "POST")
00205                 bad = true;
00206 
00207             //check that HTTP/<VERSION> is OK
00208             if (!http.hasPrefix("HTTP/"))
00209                 bad = true;
00210 
00211             _method = methodParsed;
00212             parsePathQueryAndAnchor(pathParsed);
00213         }
00214     }
00215 
00216     if (bad) _isBadRequest = true;
00217 }
00218 
00219 void Reader::parsePathQueryAndAnchor(Common::String pathToParse) {
00220     //<path>[?query][#anchor]
00221     bool readingPath = true;
00222     bool readingQuery = false;
00223     _path = "";
00224     _query = "";
00225     _anchor = "";
00226     for (uint32 i = 0; i < pathToParse.size(); ++i) {
00227         if (readingPath) {
00228             if (pathToParse[i] == '?') {
00229                 readingPath = false;
00230                 readingQuery = true;
00231             } else {
00232                 _path += pathToParse[i];
00233             }
00234         } else if (readingQuery) {
00235             if (pathToParse[i] == '#') {
00236                 readingQuery = false;
00237             } else {
00238                 _query += pathToParse[i];
00239             }
00240         } else {
00241             _anchor += pathToParse[i];
00242         }
00243     }
00244 
00245     parseQueryParameters();
00246 }
00247 
00248 void Reader::parseQueryParameters() {
00249     Common::String key = "";
00250     Common::String value = "";
00251     bool readingKey = true;
00252     for (uint32 i = 0; i < _query.size(); ++i) {
00253         if (readingKey) {
00254             if (_query[i] == '=') {
00255                 readingKey = false;
00256                 value = "";
00257             } else {
00258                 key += _query[i];
00259             }
00260         } else {
00261             if (_query[i] == '&') {
00262                 if (_queryParameters.contains(key))
00263                     warning("Reader: query parameter \"%s\" is already set!", key.c_str());
00264                 else
00265                     _queryParameters[key] = LocalWebserver::urlDecode(value);
00266                 readingKey = true;
00267                 key = "";
00268             } else {
00269                 value += _query[i];
00270             }
00271         }
00272     }
00273 
00274     if (!key.empty()) {
00275         if (_queryParameters.contains(key))
00276             warning("Reader: query parameter \"%s\" is already set!", key.c_str());
00277         else
00278             _queryParameters[key] = LocalWebserver::urlDecode(value);
00279     }
00280 }
00281 
00282 bool Reader::readContentIntoStream(Common::WriteStream *stream) {
00283     Common::String boundary = "--" + _boundary;
00284     if (!_firstBlock)
00285         boundary = "\r\n" + boundary;
00286     if (_boundary.empty())
00287         boundary = "\r\n";
00288     if (_window == nullptr)
00289         makeWindow(boundary.size());
00290 
00291     while (readOneByteInStream(stream, boundary)) {
00292         if (!bytesLeft())
00293             return false;
00294     }
00295 
00296     _firstBlock = false;
00297     if (stream)
00298         stream->flush();
00299 
00300     freeWindow();
00301     _state = RS_READING_HEADERS;
00302     return true;
00303 }
00304 
00305 void Reader::makeWindow(uint32 size) {
00306     freeWindow();
00307 
00308     _window = new byte[size];
00309     _windowUsed = 0;
00310     _windowSize = size;
00311 }
00312 
00313 void Reader::freeWindow() {
00314     delete[] _window;
00315     _window = nullptr;
00316     _windowUsed = _windowSize = 0;
00317 }
00318 
00319 namespace {
00320 bool windowEqualsString(const byte *window, uint32 windowSize, const Common::String &boundary) {
00321     if (boundary.size() != windowSize)
00322         return false;
00323 
00324     for (uint32 i = 0; i < windowSize; ++i) {
00325         if (window[i] != boundary[i])
00326             return false;
00327     }
00328 
00329     return true;
00330 }
00331 }
00332 
00333 bool Reader::readOneByteInStream(Common::WriteStream *stream, const Common::String &boundary) {
00334     byte b = readOne();
00335     _window[_windowUsed++] = b;
00336     if (_windowUsed < _windowSize)
00337         return true;
00338 
00339     //when window is filled, check whether that's the boundary
00340     if (windowEqualsString(_window, _windowSize, boundary))
00341         return false;
00342 
00343     //if not, add the first byte of the window to the string
00344     if (stream)
00345         stream->writeByte(_window[0]);
00346     for (uint32 i = 1; i < _windowSize; ++i)
00347         _window[i - 1] = _window[i];
00348     --_windowUsed;
00349     return true;
00350 }
00351 
00352 byte Reader::readOne() {
00353     byte b = 0;
00354     _content->read(&b, 1);
00355     --_availableBytes;
00356     --_bytesLeft;
00357     return b;
00358 }
00359 
00361 
00362 bool Reader::readFirstHeaders() {
00363     if (_state == RS_NONE)
00364         _state = RS_READING_HEADERS;
00365 
00366     if (!bytesLeft())
00367         return false;
00368 
00369     if (_state == RS_READING_HEADERS)
00370         return readAndHandleFirstHeaders();
00371 
00372     warning("Reader::readFirstHeaders(): bad state");
00373     return false;
00374 }
00375 
00376 bool Reader::readFirstContent(Common::WriteStream *stream) {
00377     if (_state != RS_READING_CONTENT) {
00378         warning("Reader::readFirstContent(): bad state");
00379         return false;
00380     }
00381 
00382     // no difference, actually
00383     return readBlockContent(stream);
00384 }
00385 
00386 bool Reader::readBlockHeaders(Common::WriteStream *stream) {
00387     if (_state != RS_READING_HEADERS) {
00388         warning("Reader::readBlockHeaders(): bad state");
00389         return false;
00390     }
00391 
00392     if (!bytesLeft())
00393         return false;
00394 
00395     return readBlockHeadersIntoStream(stream);
00396 }
00397 
00398 bool Reader::readBlockContent(Common::WriteStream *stream) {
00399     if (_state != RS_READING_CONTENT) {
00400         warning("Reader::readBlockContent(): bad state");
00401         return false;
00402     }
00403 
00404     if (!bytesLeft())
00405         return false;
00406 
00407     if (!readContentIntoStream(stream))
00408         return false;
00409 
00410     if (_availableBytes >= 2) {
00411         Common::String bts;
00412         bts += readOne();
00413         bts += readOne();
00414         if (bts == "--")
00415             _allContentRead = true;
00416         else if (bts != "\r\n")
00417             warning("Reader: strange bytes: \"%s\"", bts.c_str());
00418     } else {
00419         warning("Reader: strange ending");
00420         _allContentRead = true;
00421     }
00422 
00423     return true;
00424 }
00425 
00426 uint32 Reader::bytesLeft() const { return _bytesLeft; }
00427 
00428 void Reader::setContent(Common::MemoryReadWriteStream *stream) {
00429     _content = stream;
00430     _bytesLeft = stream->size() - stream->pos();
00431 }
00432 
00433 bool Reader::badRequest() const { return _isBadRequest; }
00434 
00435 bool Reader::noMoreContent() const { return _allContentRead; }
00436 
00437 Common::String Reader::headers() const { return _headers; }
00438 
00439 Common::String Reader::method() const { return _method; }
00440 
00441 Common::String Reader::path() const { return _path; }
00442 
00443 Common::String Reader::query() const { return _query; }
00444 
00445 Common::String Reader::queryParameter(Common::String name) const { return _queryParameters[name]; }
00446 
00447 Common::String Reader::anchor() const { return _anchor; }
00448 
00449 Common::String Reader::readEverythingFromMemoryStream(Common::MemoryReadWriteStream *stream) {
00450     Common::String result;
00451     char buf[1024];
00452     uint32 readBytes;
00453     while (true) {
00454         readBytes = stream->read(buf, 1024);
00455         if (readBytes == 0)
00456             break;
00457         result += Common::String(buf, readBytes);
00458     }
00459     return result;
00460 }
00461 
00462 } // End of namespace Networking


Generated on Sat May 25 2019 05:00:51 for ResidualVM by doxygen 1.7.1
curved edge   curved edge