Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(309)

Side by Side Diff: components/ntp_snippets/breaking_news/subscription_json_request.cc

Issue 2918513002: [NTP::Push] Add the classes for sending a breaking news subscription request (Closed)
Patch Set: Adding the tests Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/ntp_snippets/breaking_news/subscription_json_request.h"
6
7 #include <algorithm>
8 #include <utility>
9 #include <vector>
10
11 #include "base/command_line.h"
12 #include "base/json/json_writer.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/metrics/histogram_macros.h"
15 #include "base/metrics/sparse_histogram.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/time/clock.h"
18 #include "base/values.h"
19 #include "components/data_use_measurement/core/data_use_user_data.h"
20 #include "components/ntp_snippets/breaking_news/subscription_request_params.h"
21 #include "components/ntp_snippets/category_info.h"
22 #include "components/ntp_snippets/features.h"
23 #include "components/ntp_snippets/user_classifier.h"
24 #include "components/signin/core/browser/profile_oauth2_token_service.h"
25 #include "components/signin/core/browser/signin_manager.h"
26 #include "components/signin/core/browser/signin_manager_base.h"
27 #include "components/strings/grit/components_strings.h"
28 #include "components/variations/net/variations_http_headers.h"
29 #include "components/variations/variations_associated_data.h"
30 #include "net/base/load_flags.h"
31 #include "net/http/http_response_headers.h"
32 #include "net/http/http_status_code.h"
33 #include "net/traffic_annotation/network_traffic_annotation.h"
34 #include "net/url_request/url_fetcher.h"
35 #include "net/url_request/url_request_context_getter.h"
36 #include "third_party/icu/source/common/unicode/uloc.h"
37 #include "third_party/icu/source/common/unicode/utypes.h"
38 #include "ui/base/l10n/l10n_util.h"
39
40 using net::URLFetcher;
41 using net::URLRequestContextGetter;
42 using net::HttpRequestHeaders;
43 using net::URLRequestStatus;
44
45 namespace ntp_snippets {
46
47 namespace internal {
48
49 SubscriptionJsonRequest::SubscriptionJsonRequest(
50 const ParseJSONCallback& callback)
51 : parse_json_callback_(callback), weak_ptr_factory_(this) {}
52
53 SubscriptionJsonRequest::~SubscriptionJsonRequest() {
54 LOG_IF(DFATAL, !request_completed_callback_.is_null())
fhorschig 2017/05/31 14:51:12 As bernhard said, this is weird (sorry). Could you
mamir 2017/05/31 18:46:02 Is it OK as of now?
fhorschig 2017/06/01 09:23:55 Yes, sgtm.
mamir 2017/06/01 14:52:30 Acknowledged.
55 << "The CompletionCallback was never called!";
56 }
57
58 void SubscriptionJsonRequest::Start(CompletedCallback callback) {
59 request_completed_callback_ = std::move(callback);
60 url_fetcher_->Start();
61 }
62
63 std::string SubscriptionJsonRequest::GetResponseString() const {
64 std::string response;
65 url_fetcher_->GetResponseAsString(&response);
66 return response;
67 }
68
69 ////////////////////////////////////////////////////////////////////////////////
70 // URLFetcherDelegate overrides
71 void SubscriptionJsonRequest::OnURLFetchComplete(
72 const net::URLFetcher* source) {
73 DCHECK_EQ(url_fetcher_.get(), source);
74 const URLRequestStatus& status = url_fetcher_->GetStatus();
75 int response = url_fetcher_->GetResponseCode();
76
77 if (!status.is_success()) {
78 std::move(request_completed_callback_)
79 .Run(/*result=*/nullptr,
fhorschig 2017/05/31 14:51:12 As discussed, a status code is sufficient if resul
mamir 2017/05/31 18:46:02 Done.
80 /*error_details=*/base::StringPrintf(" %d", status.error()));
81 } else if (response != net::HTTP_OK) {
82 std::move(request_completed_callback_)
83 .Run(/*result=*/nullptr,
fhorschig 2017/05/31 14:51:12 same here. status should suffice.
mamir 2017/05/31 18:46:02 Done.
84 /*error_details=*/base::StringPrintf(" %d", response));
85 } else {
86 // request succeeded.
fhorschig 2017/05/31 14:51:12 here you could use a success status.
mamir 2017/05/31 18:46:02 Done.
87 }
88 }
89
90 SubscriptionJsonRequest::Builder::Builder() {}
91 SubscriptionJsonRequest::Builder::Builder(SubscriptionJsonRequest::Builder&&) =
92 default;
fhorschig 2017/05/31 14:51:12 I really want to know whether we need that.
mamir 2017/05/31 18:46:01 Required the test IIUC
93 SubscriptionJsonRequest::Builder::~Builder() = default;
94
95 std::unique_ptr<SubscriptionJsonRequest>
96 SubscriptionJsonRequest::Builder::Build() const {
97 DCHECK(!url_.is_empty());
98 DCHECK(url_request_context_getter_);
99 auto request =
100 base::MakeUnique<SubscriptionJsonRequest>(parse_json_callback_);
101 std::string body = BuildBody();
102 std::string headers = BuildHeaders();
103 request->url_fetcher_ = BuildURLFetcher(request.get(), headers, body);
104
105 // Log the request for debugging network issues.
106 VLOG(1) << "Sending a subscription request to " << url_ << ":\n"
107 << headers << "\n"
108 << body;
109
110 return request;
111 }
112
113 SubscriptionJsonRequest::Builder& SubscriptionJsonRequest::Builder::SetParams(
114 const SubscriptionRequestParams& params) {
115 params_ = params;
116 return *this;
117 }
118
119 SubscriptionJsonRequest::Builder& SubscriptionJsonRequest::Builder::SetUrl(
120 const GURL& url) {
121 url_ = url;
122 return *this;
123 }
124
125 SubscriptionJsonRequest::Builder&
126 SubscriptionJsonRequest::Builder::SetUrlRequestContextGetter(
127 const scoped_refptr<net::URLRequestContextGetter>& context_getter) {
128 url_request_context_getter_ = context_getter;
129 return *this;
130 }
131
132 SubscriptionJsonRequest::Builder&
133 SubscriptionJsonRequest::Builder::SetParseJsonCallback(
134 ParseJSONCallback callback) {
135 parse_json_callback_ = callback;
136 return *this;
137 }
138
139 std::string SubscriptionJsonRequest::Builder::BuildHeaders() const {
140 net::HttpRequestHeaders headers;
141 headers.SetHeader("Content-Type", "application/json; charset=UTF-8");
142 if (!auth_header_.empty()) {
143 headers.SetHeader("Authorization", auth_header_);
fhorschig 2017/05/31 14:51:13 The auth_header_ is always empty for the forseeabl
mamir 2017/05/31 18:46:01 Yes it makes sense. Removed.
144 }
145 // Add X-Client-Data header with experiment IDs from field trials.
146 // Note: It's OK to pass |is_signed_in| false if it's unknown, as it does
147 // not affect transmission of experiments coming from the variations server.
148 bool is_signed_in = false;
fhorschig 2017/05/31 14:51:12 why don't you inline that?
mamir 2017/05/31 18:46:01 Done.
149 variations::AppendVariationHeaders(url_,
150 false, // incognito
151 false, // uma_enabled
152 is_signed_in, &headers);
153 return headers.ToString();
154 }
155
156 std::string SubscriptionJsonRequest::Builder::BuildBody() const {
157 auto request = base::MakeUnique<base::DictionaryValue>();
fhorschig 2017/05/31 14:51:12 Can we use a base::DictionaryValue instead of a po
mamir 2017/05/31 18:46:02 Done.
158 request->SetString("token", params_.token);
159
160 std::string request_json;
161 bool success = base::JSONWriter::WriteWithOptions(
162 *request, base::JSONWriter::OPTIONS_PRETTY_PRINT, &request_json);
163 DCHECK(success);
164 return request_json;
165 }
166
167 std::unique_ptr<net::URLFetcher>
168 SubscriptionJsonRequest::Builder::BuildURLFetcher(
169 net::URLFetcherDelegate* delegate,
170 const std::string& headers,
171 const std::string& body) const {
172 net::NetworkTrafficAnnotationTag traffic_annotation =
173 net::DefineNetworkTrafficAnnotation("gcm_subscription", R"(
174 semantics {
175 sender: "Subscribe for breaking news delivered via GCM push messages"
176 description:
177 "Chromium can received breaking news via GCM push messages. "
178 "This request suscribes the client to receiving them."
179 trigger:
180 "Suscrpion takes place only once per profile lifetime. "
181 data:
182 "The sunscrption token that identifies this Chromium profile."
183 destination: GOOGLE_OWNED_SERVICE
184 }
185 policy {
186 cookies_allowed: false
187 setting:
188 "This feature cannot be disabled by settings now"
189 chrome_policy {
190 NTPContentSuggestionsEnabled {
191 policy_options {mode: MANDATORY}
192 NTPContentSuggestionsEnabled: false
193 }
194 }
195 })");
196 std::unique_ptr<net::URLFetcher> url_fetcher = net::URLFetcher::Create(
197 url_, net::URLFetcher::POST, delegate, traffic_annotation);
198 url_fetcher->SetRequestContext(url_request_context_getter_.get());
199 url_fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
200 net::LOAD_DO_NOT_SAVE_COOKIES);
201 data_use_measurement::DataUseUserData::AttachToFetcher(
202 url_fetcher.get(),
203 data_use_measurement::DataUseUserData::NTP_SNIPPETS_SUGGESTIONS);
204
205 url_fetcher->SetExtraRequestHeaders(headers);
206 url_fetcher->SetUploadData("application/json", body);
207
208 // Fetchers are sometimes cancelled because a network change was detected.
209 url_fetcher->SetAutomaticallyRetryOnNetworkChanges(3);
fhorschig 2017/05/31 14:51:12 Do we want to retry three times?
mamir 2017/05/31 18:46:02 What do you think? :-)
fhorschig 2017/06/01 09:23:55 I doubt it. Once should suffice.
mamir 2017/06/01 14:52:30 Done.
210 return url_fetcher;
211 }
212
213 } // namespace internal
214
215 } // namespace ntp_snippets
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698