Fixed headers parsing in CurlHttpClient

1. substr(pos, pos_end) was used instead of substr(pos, pos_end - pos)
2. CURLOPT_HEADERFUNCTION is called for single header so no need to
   merge and split them later

Change-Id: Iad852212258f870c2fe0683b0021ae99a020d12b
Reviewed-on: https://weave-review.googlesource.com/1562
Reviewed-by: Vitaly Buka <vitalybuka@google.com>
diff --git a/examples/provider/curl_http_client.cc b/examples/provider/curl_http_client.cc
index 32aa4af..774c07b 100644
--- a/examples/provider/curl_http_client.cc
+++ b/examples/provider/curl_http_client.cc
@@ -34,6 +34,27 @@
   return size * nmemb;
 }
 
+size_t HeaderFunction(void* contents, size_t size, size_t nmemb, void* userp) {
+  std::string header(static_cast<const char*>(contents), size * nmemb);
+  auto pos = header.find(':');
+  if (pos != std::string::npos) {
+    std::pair<std::string, std::string> header_pair;
+
+    static const char kSpaces[] = " \t\r\n";
+    header_pair.first = header.substr(0, pos);
+    pos = header.find_first_not_of(kSpaces, pos + 1);
+    if (pos != std::string::npos) {
+      auto last_non_space = header.find_last_not_of(kSpaces);
+      if (last_non_space >= pos)
+        header_pair.second = header.substr(pos, last_non_space - pos + 1);
+    }
+
+    static_cast<provider::HttpClient::Headers*>(userp)
+        ->emplace_back(std::move(header_pair));
+  }
+  return size * nmemb;
+}
+
 std::pair<std::unique_ptr<CurlHttpClient::Response>, ErrorPtr>
 SendRequestBlocking(CurlHttpClient::Method method,
                     const std::string& url,
@@ -76,9 +97,10 @@
   CHECK_EQ(CURLE_OK,
            curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &response->data));
   CHECK_EQ(CURLE_OK, curl_easy_setopt(curl.get(), CURLOPT_HEADERFUNCTION,
-                                      &WriteFunction));
-  CHECK_EQ(CURLE_OK, curl_easy_setopt(curl.get(), CURLOPT_HEADERDATA,
-                                      &response->content_type));
+                                      &HeaderFunction));
+  provider::HttpClient::Headers response_headers;
+  CHECK_EQ(CURLE_OK,
+           curl_easy_setopt(curl.get(), CURLOPT_HEADERDATA, &response_headers));
 
   CURLcode res = curl_easy_perform(curl.get());
   if (chunk)
@@ -91,20 +113,16 @@
     return {nullptr, std::move(error)};
   }
 
-  const std::string kContentType = "\r\nContent-Type:";
-  auto pos = response->content_type.find(kContentType);
-  if (pos == std::string::npos) {
+  for (const auto& header : response_headers) {
+    if (header.first == "Content-Type")
+      response->content_type = header.second;
+  }
+
+  if (response->content_type.empty()) {
     Error::AddTo(&error, FROM_HERE, "curl", "no_content_header",
                  "Content-Type header is missing");
     return {nullptr, std::move(error)};
   }
-  pos += kContentType.size();
-  auto pos_end = response->content_type.find("\r\n", pos);
-  if (pos_end == std::string::npos) {
-    pos_end = response->content_type.size();
-  }
-
-  response->content_type = response->content_type.substr(pos, pos_end);
 
   CHECK_EQ(CURLE_OK, curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE,
                                        &response->status));
diff --git a/src/device_registration_info.cc b/src/device_registration_info.cc
index d2b10a9..8b8e752 100644
--- a/src/device_registration_info.cc
+++ b/src/device_registration_info.cc
@@ -201,9 +201,9 @@
       SplitAtFirst(response.GetContentType(), ";", true).first;
 
   if (content_type != http::kJson && content_type != http::kPlain) {
-    Error::AddTo(error, FROM_HERE, errors::json::kDomain,
-                 "non_json_content_type",
-                 "Unexpected response content type: " + content_type);
+    Error::AddTo(
+        error, FROM_HERE, errors::json::kDomain, "non_json_content_type",
+        "Unexpected content type: \'" + response.GetContentType() + "\'");
     return std::unique_ptr<base::DictionaryValue>();
   }
 
diff --git a/src/device_registration_info_unittest.cc b/src/device_registration_info_unittest.cc
index 9edd396..8174b90 100644
--- a/src/device_registration_info_unittest.cc
+++ b/src/device_registration_info_unittest.cc
@@ -222,10 +222,9 @@
   url += "client_id=";
   url += test_data::kClientId;
   EXPECT_EQ(url, dev_reg_->GetOAuthURL(
-                     "auth",
-                     {{"redirect_uri", "urn:ietf:wg:oauth:2.0:oob"},
-                      {"response_type", "code"},
-                      {"client_id", test_data::kClientId}}));
+                     "auth", {{"redirect_uri", "urn:ietf:wg:oauth:2.0:oob"},
+                              {"response_type", "code"},
+                              {"client_id", test_data::kClientId}}));
 }
 
 TEST_F(DeviceRegistrationInfoTest, HaveRegistrationCredentials) {