| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/journey/journey_info_json_request.h" |
| |
| #include <algorithm> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/values.h" |
| #include "components/journey/proto/batch_get_switcher_journey_from_pageload_request.pb.h" |
| #include "components/variations/net/variations_http_headers.h" |
| #include "net/base/load_flags.h" |
| #include "net/http/http_request_headers.h" |
| #include "net/traffic_annotation/network_traffic_annotation.h" |
| #include "services/network/public/cpp/resource_request.h" |
| #include "services/network/public/cpp/shared_url_loader_factory.h" |
| #include "services/network/public/cpp/simple_url_loader.h" |
| |
| namespace journey { |
| |
| namespace { |
| |
| const int k5xxRetries = 2; |
| |
| std::string GetSerializedJourneyRequest( |
| const std::vector<int64_t>& timestamps) { |
| BatchGetSwitcherJourneyFromPageloadRequest request; |
| |
| for (const auto timestamp : timestamps) { |
| request.add_page_timestamp_usec(timestamp); |
| } |
| |
| return request.SerializeAsString(); |
| } |
| |
| } // namespace |
| |
| JourneyInfoJsonRequest::JourneyInfoJsonRequest( |
| const ParseJSONCallback& callback) |
| : parse_json_callback_(callback), weak_ptr_factory_(this) {} |
| |
| JourneyInfoJsonRequest::~JourneyInfoJsonRequest() {} |
| |
| void JourneyInfoJsonRequest::Start( |
| CompletedCallback callback, |
| const scoped_refptr<network::SharedURLLoaderFactory>& loader_factory) { |
| completed_callback_ = std::move(callback); |
| last_response_string_.clear(); |
| |
| simple_url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie( |
| loader_factory.get(), |
| base::BindOnce(&JourneyInfoJsonRequest::OnSimpleURLLoaderComplete, |
| base::Unretained(this))); |
| } |
| |
| const std::string& JourneyInfoJsonRequest::GetResponseString() const { |
| return last_response_string_; |
| } |
| |
| void JourneyInfoJsonRequest::OnSimpleURLLoaderComplete( |
| std::unique_ptr<std::string> response_body) { |
| DCHECK(simple_url_loader_); |
| |
| int response_code = -1; |
| if (simple_url_loader_->ResponseInfo() && |
| simple_url_loader_->ResponseInfo()->headers) { |
| response_code = |
| simple_url_loader_->ResponseInfo()->headers->response_code(); |
| } |
| |
| int net_error = simple_url_loader_->NetError(); |
| simple_url_loader_.reset(); |
| |
| if (net_error != net::OK) { |
| std::move(completed_callback_) |
| .Run(nullptr, base::StringPrintf("Network error code: %d", net_error)); |
| } else if (response_code / 100 != 2) { |
| std::move(completed_callback_) |
| .Run(nullptr, |
| base::StringPrintf("Http response error code: %d", response_code)); |
| } else { |
| last_response_string_ = std::move(*response_body); |
| parse_json_callback_.Run( |
| last_response_string_, |
| base::BindRepeating(&JourneyInfoJsonRequest::OnJsonParsed, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindRepeating(&JourneyInfoJsonRequest::OnJsonError, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| } |
| |
| void JourneyInfoJsonRequest::OnJsonParsed(std::unique_ptr<base::Value> result) { |
| std::move(completed_callback_).Run(std::move(result), std::string()); |
| } |
| |
| void JourneyInfoJsonRequest::OnJsonError(const std::string& error) { |
| DLOG(WARNING) << "Received invalid JSON (" << error |
| << "): " << last_response_string_; |
| std::move(completed_callback_).Run(nullptr, error); |
| } |
| |
| JourneyInfoJsonRequest::Builder::Builder() |
| : url_(GURL( |
| "https://chrome-memex-dev.appspot.com/api/journey_from_pageload")) {} |
| |
| JourneyInfoJsonRequest::Builder::~Builder() = default; |
| |
| std::unique_ptr<JourneyInfoJsonRequest> JourneyInfoJsonRequest::Builder::Build() |
| const { |
| auto request = std::make_unique<JourneyInfoJsonRequest>(parse_json_callback_); |
| request->simple_url_loader_ = BuildSimpleURLLoader(); |
| |
| return request; |
| } |
| |
| JourneyInfoJsonRequest::Builder& |
| JourneyInfoJsonRequest::Builder::SetAuthentication( |
| const std::string& auth_header) { |
| DVLOG(0) << "Authorization header " << auth_header; |
| auth_header_ = auth_header; |
| return *this; |
| } |
| |
| JourneyInfoJsonRequest::Builder& JourneyInfoJsonRequest::Builder::SetTimestamps( |
| const std::vector<int64_t>& timestamps) { |
| body_ = GetSerializedJourneyRequest(timestamps); |
| return *this; |
| } |
| |
| JourneyInfoJsonRequest::Builder& |
| JourneyInfoJsonRequest::Builder::SetParseJsonCallback( |
| ParseJSONCallback callback) { |
| parse_json_callback_ = std::move(callback); |
| return *this; |
| } |
| |
| net::HttpRequestHeaders |
| JourneyInfoJsonRequest::Builder::BuildSimpleURLLoaderHeaders() const { |
| net::HttpRequestHeaders headers; |
| headers.SetHeader("Content-Type", "application/json; charset=UTF-8"); |
| if (!auth_header_.empty()) { |
| headers.SetHeader("Authorization", auth_header_); |
| } |
| return headers; |
| } |
| |
| std::unique_ptr<network::SimpleURLLoader> |
| JourneyInfoJsonRequest::Builder::BuildSimpleURLLoader() const { |
| // TODO(meiliang): update the policy section with correct setting and |
| // chrome_policy |
| net::NetworkTrafficAnnotationTag traffic_annotation = NO_TRAFFIC_ANNOTATION_YET; |
| |
| auto resource_request = std::make_unique<network::ResourceRequest>(); |
| resource_request->url = GURL(url_); |
| resource_request->allow_credentials = false; |
| resource_request->headers = BuildSimpleURLLoaderHeaders(); |
| variations::AppendVariationsHeader(url_, variations::InIncognito::kNo, |
| variations::SignedIn::kNo, |
| resource_request.get()); |
| resource_request->method = "POST"; |
| |
| auto simple_loader = network::SimpleURLLoader::Create( |
| std::move(resource_request), traffic_annotation); |
| simple_loader->SetAllowHttpErrorResults(true); |
| simple_loader->AttachStringForUpload(body_, |
| "application/json; charset=UTF-8"); |
| simple_loader->SetRetryOptions( |
| k5xxRetries, network::SimpleURLLoader::RetryMode::RETRY_ON_5XX); |
| |
| return simple_loader; |
| } |
| |
| } // namespace journey |