diff options
Diffstat (limited to 'backends')
-rw-r--r-- | backends/cloud/googledrive/googledriveuploadrequest.cpp | 46 | ||||
-rw-r--r-- | backends/networking/curl/curlrequest.cpp | 17 | ||||
-rw-r--r-- | backends/networking/curl/networkreadstream.cpp | 72 | ||||
-rw-r--r-- | backends/networking/curl/networkreadstream.h | 8 |
4 files changed, 98 insertions, 45 deletions
diff --git a/backends/cloud/googledrive/googledriveuploadrequest.cpp b/backends/cloud/googledrive/googledriveuploadrequest.cpp index f921f5c96d..c4728c5ac1 100644 --- a/backends/cloud/googledrive/googledriveuploadrequest.cpp +++ b/backends/cloud/googledrive/googledriveuploadrequest.cpp @@ -152,20 +152,10 @@ void GoogleDriveUploadRequest::startUploadCallback(Networking::JsonResponse resp const Networking::NetworkReadStream *stream = rq->getNetworkReadStream(); if (stream) { long code = stream->httpResponseCode(); - Common::String headers = stream->responseHeaders(); if (code == 200) { - const char *cstr = headers.c_str(); - const char *position = strstr(cstr, "Location: "); - - if (position) { - Common::String result = ""; - char c; - for (const char *i = position + 10; c = *i, c != 0; ++i) { - if (c == '\n' || c == '\r') - break; - result += c; - } - _uploadUrl = result; + Common::HashMap<Common::String, Common::String> headers = stream->responseHeadersMap(); + if (headers.contains("location")) { + _uploadUrl = headers["location"]; uploadNextPart(); return; } @@ -230,25 +220,19 @@ bool GoogleDriveUploadRequest::handleHttp308(const Networking::NetworkReadStream if (stream->httpResponseCode() != 308) return false; //seriously - Common::String headers = stream->responseHeaders(); - const char *cstr = headers.c_str(); - for (int rangeTry = 0; rangeTry < 2; ++rangeTry) { - const char *needle = (rangeTry == 0 ? "Range: 0-" : "Range: bytes=0-"); - uint32 needleLength = (rangeTry == 0 ? 9 : 15); - - const char *position = strstr(cstr, needle); //if it lost the first part, I refuse to talk with it - - if (position) { - Common::String result = ""; - char c; - for (const char *i = position + needleLength; c = *i, c != 0; ++i) { - if (c == '\n' || c == '\r') - break; - result += c; + Common::HashMap<Common::String, Common::String> headers = stream->responseHeadersMap(); + if (headers.contains("range")) { + Common::String range = headers["range"]; + for (int rangeTry = 0; rangeTry < 2; ++rangeTry) { + const char *needle = (rangeTry == 0 ? "0-" : "bytes=0-"); //if it lost the first part, I refuse to talk with it + uint32 needleLength = (rangeTry == 0 ? 2 : 8); + + if (range.hasPrefix(needle)) { + range.erase(0, needleLength); + _serverReceivedBytes = range.asUint64() + 1; + uploadNextPart(); + return true; } - _serverReceivedBytes = result.asUint64() + 1; - uploadNextPart(); - return true; } } diff --git a/backends/networking/curl/curlrequest.cpp b/backends/networking/curl/curlrequest.cpp index a9de30cfe9..cb117b7b7b 100644 --- a/backends/networking/curl/curlrequest.cpp +++ b/backends/networking/curl/curlrequest.cpp @@ -71,20 +71,9 @@ void CurlRequest::restart() { Common::String CurlRequest::date() const { if (_stream) { - Common::String headers = _stream->responseHeaders(); - const char *cstr = headers.c_str(); - const char *position = strstr(cstr, "Date: "); - - if (position) { - Common::String result = ""; - char c; - for (const char *i = position + 6; c = *i, c != 0; ++i) { - if (c == '\n' || c == '\r') - break; - result += c; - } - return result; - } + Common::HashMap<Common::String, Common::String> headers = _stream->responseHeadersMap(); + if (headers.contains("date")) + return headers["date"]; } return ""; } diff --git a/backends/networking/curl/networkreadstream.cpp b/backends/networking/curl/networkreadstream.cpp index ac8800b22a..dee48856bf 100644 --- a/backends/networking/curl/networkreadstream.cpp +++ b/backends/networking/curl/networkreadstream.cpp @@ -240,6 +240,78 @@ Common::String NetworkReadStream::responseHeaders() const { return _responseHeaders; } +Common::HashMap<Common::String, Common::String> NetworkReadStream::responseHeadersMap() const { + // HTTP headers are described at RFC 2616: https://tools.ietf.org/html/rfc2616#section-4.2 + // this implementation tries to follow it, but for simplicity it does not support multi-line header values + + Common::HashMap<Common::String, Common::String> headers; + Common::String headerName, headerValue, trailingWhitespace; + char c; + bool readingName = true; + + for (uint i = 0; i < _responseHeaders.size(); ++i) { + c = _responseHeaders[i]; + + if (readingName) { + if (c == ' ' || c == '\r' || c == '\n' || c == '\t') { + // header names should not contain any whitespace, this is invalid + // ignore what's been before + headerName = ""; + continue; + } + if (c == ':') { + if (!headerName.empty()) { + readingName = false; + } + continue; + } + headerName += c; + continue; + } + + // reading value: + if (c == ' ' || c == '\t') { + if (headerValue.empty()) { + // skip leading whitespace + continue; + } else { + // accumulate trailing whitespace + trailingWhitespace += c; + continue; + } + } + + if (c == '\r' || c == '\n') { + // not sure if RFC allows empty values, we'll ignore such + if (!headerName.empty() && !headerValue.empty()) { + // add header value + // RFC allows header with the same name to be sent multiple times + // and requires it to be equivalent of just listing all header values separated with comma + // so if header already was met, we'll add new value to the old one + headerName.toLowercase(); + if (headers.contains(headerName)) { + headers[headerName] += "," + headerValue; + } else { + headers[headerName] = headerValue; + } + } + + headerName = ""; + headerValue = ""; + trailingWhitespace = ""; + readingName = true; + continue; + } + + // if we meet non-whitespace character, turns out those "trailing" whitespace characters were not so trailing + headerValue += trailingWhitespace; + trailingWhitespace = ""; + headerValue += c; + } + + return headers; +} + uint32 NetworkReadStream::fillWithSendingContents(char *bufferToFill, uint32 maxSize) { uint32 sendSize = _sendingContentsSize - _sendingContentsPos; if (sendSize > maxSize) diff --git a/backends/networking/curl/networkreadstream.h b/backends/networking/curl/networkreadstream.h index b83ab27400..7d19286f85 100644 --- a/backends/networking/curl/networkreadstream.h +++ b/backends/networking/curl/networkreadstream.h @@ -136,6 +136,14 @@ public: */ Common::String responseHeaders() const; + /** + * Return response headers as HashMap. All header names in + * it are lowercase. + * + * @note This method should be called when eos() == true. + */ + Common::HashMap<Common::String, Common::String> responseHeadersMap() const; + /** Returns a number in range [0, 1], where 1 is "complete". */ double getProgress() const; |