aboutsummaryrefslogtreecommitdiff
path: root/backends
diff options
context:
space:
mode:
Diffstat (limited to 'backends')
-rw-r--r--backends/cloud/googledrive/googledriveuploadrequest.cpp46
-rw-r--r--backends/networking/curl/curlrequest.cpp17
-rw-r--r--backends/networking/curl/networkreadstream.cpp72
-rw-r--r--backends/networking/curl/networkreadstream.h8
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;