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

Side by Side Diff: chromeos/printing/ppd_provider.cc

Issue 2476073003: Update PpdProvider threading model. (Closed)
Patch Set: Fix some comment typos. Created 4 years, 1 month 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
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chromeos/printing/ppd_provider.h" 5 #include "chromeos/printing/ppd_provider.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/files/file_util.h" 9 #include "base/files/file_util.h"
10 #include "base/json/json_parser.h" 10 #include "base/json/json_parser.h"
11 #include "base/memory/ptr_util.h" 11 #include "base/memory/ptr_util.h"
12 #include "base/sequence_checker.h" 12 #include "base/sequence_checker.h"
13 #include "base/strings/string_number_conversions.h" 13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_util.h" 14 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h" 15 #include "base/strings/stringprintf.h"
16 #include "base/task_runner_util.h"
16 #include "base/threading/sequenced_task_runner_handle.h" 17 #include "base/threading/sequenced_task_runner_handle.h"
17 #include "base/time/time.h" 18 #include "base/time/time.h"
18 #include "base/values.h" 19 #include "base/values.h"
19 #include "chromeos/printing/ppd_cache.h" 20 #include "chromeos/printing/ppd_cache.h"
20 #include "net/base/load_flags.h" 21 #include "net/base/load_flags.h"
21 #include "net/http/http_status_code.h" 22 #include "net/http/http_status_code.h"
22 #include "net/url_request/url_fetcher.h" 23 #include "net/url_request/url_fetcher.h"
23 #include "net/url_request/url_fetcher_delegate.h" 24 #include "net/url_request/url_fetcher_delegate.h"
24 #include "net/url_request/url_request_context_getter.h" 25 #include "net/url_request/url_request_context_getter.h"
25 #include "url/gurl.h" 26 #include "url/gurl.h"
26 27
27 namespace chromeos { 28 namespace chromeos {
28 namespace printing { 29 namespace printing {
29 namespace { 30 namespace {
30 31
31 // Expected fields from the quirks server. 32 // Expected fields from the quirks server.
32 const char kJSONPPDKey[] = "compressedPpd"; 33 const char kJSONPPDKey[] = "compressedPpd";
33 const char kJSONLastUpdatedKey[] = "lastUpdatedTime"; 34 const char kJSONLastUpdatedKey[] = "lastUpdatedTime";
34 const char kJSONTopListKey[] = "manufacturers"; 35 const char kJSONTopListKey[] = "manufacturers";
35 const char kJSONManufacturer[] = "manufacturer"; 36 const char kJSONManufacturer[] = "manufacturer";
36 const char kJSONModelList[] = "models"; 37 const char kJSONModelList[] = "models";
37 38
38 class PpdProviderImpl; 39 class PpdProviderImpl;
39 40
40 // URLFetcherDelegate that just forwards the complete callback back to 41 // URLFetcherDelegate that just invokes a callback when the fetch is complete.
41 // the PpdProvider that owns the delegate.
42 class ForwardingURLFetcherDelegate : public net::URLFetcherDelegate { 42 class ForwardingURLFetcherDelegate : public net::URLFetcherDelegate {
43 public: 43 public:
44 explicit ForwardingURLFetcherDelegate(PpdProviderImpl* owner) 44 explicit ForwardingURLFetcherDelegate(
45 : owner_(owner) {} 45 const base::Callback<void()>& done_callback)
46 : done_callback_(done_callback) {}
46 ~ForwardingURLFetcherDelegate() override {} 47 ~ForwardingURLFetcherDelegate() override {}
47 48
48 // URLFetcherDelegate API method. Defined below since we need the 49 // URLFetcherDelegate API method. Defined below since we need the
49 // PpdProviderImpl definition first. 50 // PpdProviderImpl definition first.
50 void OnURLFetchComplete(const net::URLFetcher* source) override; 51 void OnURLFetchComplete(const net::URLFetcher* source) override {
52 done_callback_.Run();
53 }
51 54
52 private: 55 private:
53 // owner of this delegate. 56 // Callback to be run on fetch complete.
54 PpdProviderImpl* const owner_; 57 base::Callback<void()> done_callback_;
55 }; 58 };
56 59
57 class PpdProviderImpl : public PpdProvider { 60 class PpdProviderImpl : public PpdProvider {
58 public: 61 public:
59 PpdProviderImpl( 62 PpdProviderImpl(
60 const std::string& api_key, 63 const std::string& api_key,
61 scoped_refptr<net::URLRequestContextGetter> url_context_getter, 64 scoped_refptr<net::URLRequestContextGetter> url_context_getter,
65 scoped_refptr<base::SequencedTaskRunner> io_task_runner,
62 std::unique_ptr<PpdCache> cache, 66 std::unique_ptr<PpdCache> cache,
63 const PpdProvider::Options& options) 67 const PpdProvider::Options& options)
64 : api_key_(api_key), 68 : api_key_(api_key),
65 forwarding_delegate_(this),
66 url_context_getter_(url_context_getter), 69 url_context_getter_(url_context_getter),
70 io_task_runner_(io_task_runner),
67 cache_(std::move(cache)), 71 cache_(std::move(cache)),
68 options_(options) { 72 options_(options),
73 weak_factory_(this) {
69 CHECK_GT(options_.max_ppd_contents_size_, 0U); 74 CHECK_GT(options_.max_ppd_contents_size_, 0U);
70 } 75 }
71 ~PpdProviderImpl() override {} 76 ~PpdProviderImpl() override {}
72 77
73 void Resolve(const Printer::PpdReference& ppd_reference, 78 void Resolve(const Printer::PpdReference& ppd_reference,
74 const PpdProvider::ResolveCallback& cb) override { 79 const PpdProvider::ResolveCallback& cb) override {
75 CHECK(!cb.is_null()); 80 CHECK(!cb.is_null());
76 CHECK(resolve_sequence_checker_.CalledOnValidSequence()); 81 CHECK(resolve_sequence_checker_.CalledOnValidSequence());
77 CHECK(base::SequencedTaskRunnerHandle::IsSet()) 82 CHECK(base::SequencedTaskRunnerHandle::IsSet())
78 << "Resolve must be called from a SequencedTaskRunner context"; 83 << "Resolve must be called from a SequencedTaskRunner context";
79 CHECK(resolve_fetcher_ == nullptr) 84 CHECK(!resolve_inflight_)
80 << "Can't have concurrent PpdProvider Resolve calls"; 85 << "Can't have concurrent PpdProvider Resolve calls";
86 resolve_inflight_ = true;
87 auto cache_result = base::MakeUnique<base::Optional<base::FilePath>>();
88 CHECK(io_task_runner_->PostTaskAndReply(
stevenjb 2016/11/14 23:08:39 Don't wrap non test function calls with CHECK, ins
Carlson 2016/11/14 23:27:41 Done, but for my own edification, is this just you
stevenjb 2016/11/14 23:55:25 It's not explicitly in the guidelines, however thi
89 FROM_HERE, base::Bind(&PpdProviderImpl::CacheFindWrapper,
stevenjb 2016/11/14 23:08:39 nit: This will be easier to follow if the method i
Carlson 2016/11/14 23:27:41 Done.
90 weak_factory_.GetWeakPtr(), ppd_reference,
91 cache_result.get()),
92 base::Bind(&PpdProviderImpl::ResolveCacheLookupDone,
93 weak_factory_.GetWeakPtr(), ppd_reference, cb,
94 std::move(cache_result))));
95 }
81 96
82 base::Optional<base::FilePath> tmp = cache_->Find(ppd_reference); 97 void QueryAvailable(const QueryAvailableCallback& cb) override {
83 if (tmp) { 98 CHECK(!cb.is_null());
99 CHECK(base::SequencedTaskRunnerHandle::IsSet())
100 << "QueryAvailable() must be called from a SequencedTaskRunner context";
101 auto cache_result = base::MakeUnique<
102 base::Optional<const PpdProvider::AvailablePrintersMap*>>();
103 CHECK(!query_inflight_)
104 << "Can't have concurrent PpdProvider QueryAvailable calls";
105 query_inflight_ = true;
106 CHECK(io_task_runner_->PostTaskAndReply(
107 FROM_HERE, base::Bind(&PpdProviderImpl::CacheFindAvailableWrapper,
stevenjb 2016/11/14 23:08:39 QueryAvailableDoCacheLookup
Carlson 2016/11/14 23:27:41 Done.
108 weak_factory_.GetWeakPtr(), cache_result.get()),
109 base::Bind(&PpdProviderImpl::QueryCacheLookupDone,
stevenjb 2016/11/14 23:08:39 QueryAvailableCacheLookupDone
Carlson 2016/11/14 23:27:41 Done.
110 weak_factory_.GetWeakPtr(), cb, std::move(cache_result))));
111 }
112
113 bool CachePpd(const Printer::PpdReference& ppd_reference,
114 const base::FilePath& ppd_path) override {
115 std::string buf;
116 if (!base::ReadFileToStringWithMaxSize(ppd_path, &buf,
117 options_.max_ppd_contents_size_)) {
118 return false;
119 }
120 return static_cast<bool>(cache_->Store(ppd_reference, buf));
121 }
122
123 private:
124 // Trivial wrappers around PpdCache::Find() and
125 // PpdCache::FindAvailablePrinters(). We need these wrappers both because we
126 // use weak_ptrs to manage lifetime, and so so we need to bind callbacks to
stevenjb 2016/11/14 23:08:39 s/so so/because/
Carlson 2016/11/14 23:27:41 Done.
127 // *this*, and because weak_ptr's preclude return values in posted tasks, so
128 // we have to use a parameter to return state.
stevenjb 2016/11/14 23:08:39 FWIW, this isn't that uncommon a pattern, you coul
Carlson 2016/11/14 23:27:41 From the perspective of someone new to this code b
stevenjb 2016/11/14 23:55:25 Acknowledged, but over-documentation is it's own p
129 void CacheFindWrapper(const Printer::PpdReference& reference,
130 base::Optional<base::FilePath>* cache_result) const {
131 *cache_result = cache_->Find(reference);
132 }
stevenjb 2016/11/14 23:08:39 blank line
Carlson 2016/11/14 23:27:41 Done.
133 void CacheFindAvailableWrapper(
134 base::Optional<const PpdProvider::AvailablePrintersMap*>* cache_result)
135 const {
136 auto tmp = cache_->FindAvailablePrinters();
137 if (tmp != nullptr) {
138 *cache_result = tmp;
139 } else {
140 *cache_result = base::nullopt;
141 }
142 }
143
144 // Callback that happens when the Resolve() cache lookup completes. If the
145 // cache satisfied the request, finish the Resolve, otherwise start a URL
146 // request to satisfy the request. This runs on the same thread as Resolve()
147 // was invoked on.
stevenjb 2016/11/14 23:08:39 Last sentence is unnecessary, we have a CHECK on l
Carlson 2016/11/14 23:27:41 Sort of, the CHECK below just guarantees sequence,
stevenjb 2016/11/14 23:55:25 Sure, but in practice this will only get called fr
148 void ResolveCacheLookupDone(
149 const Printer::PpdReference& ppd_reference,
150 const PpdProvider::ResolveCallback& done_callback,
151 const std::unique_ptr<base::Optional<base::FilePath>>& cache_result) {
152 CHECK(resolve_sequence_checker_.CalledOnValidSequence());
153 if (*cache_result) {
84 // Cache hit. Schedule the callback now and return. 154 // Cache hit. Schedule the callback now and return.
85 base::SequencedTaskRunnerHandle::Get()->PostTask( 155 resolve_inflight_ = false;
86 FROM_HERE, base::Bind(cb, PpdProvider::SUCCESS, tmp.value())); 156 done_callback.Run(PpdProvider::SUCCESS, cache_result->value());
87 return; 157 return;
88 } 158 }
89 159
90 // We don't have a way to automatically resolve user-supplied PPDs yet. So 160 // We don't have a way to automatically resolve user-supplied PPDs yet. So
91 // if we have one specified, and it's not cached, we fail out rather than 161 // if we have one specified, and it's not cached, we fail out rather than
92 // fall back to quirks-server based resolution. The reasoning here is that 162 // fall back to quirks-server based resolution. The reasoning here is that
93 // if the user has specified a PPD when a quirks-server one exists, it 163 // if the user has specified a PPD when a quirks-server one exists, it
94 // probably means the quirks server one doesn't work for some reason, so we 164 // probably means the quirks server one doesn't work for some reason, so we
95 // shouldn't silently use it. 165 // shouldn't silently use it.
96 if (!ppd_reference.user_supplied_ppd_url.empty()) { 166 if (!ppd_reference.user_supplied_ppd_url.empty()) {
97 base::SequencedTaskRunnerHandle::Get()->PostTask( 167 resolve_inflight_ = false;
98 FROM_HERE, base::Bind(cb, PpdProvider::NOT_FOUND, base::FilePath())); 168 done_callback.Run(PpdProvider::NOT_FOUND, base::FilePath());
99 return; 169 return;
100 } 170 }
101 171
102 resolve_reference_ = ppd_reference; 172 // Missed in the cache, so start a URLRequest to resolve the request.
103 resolve_done_callback_ = cb; 173 resolve_fetcher_delegate_ = base::MakeUnique<ForwardingURLFetcherDelegate>(
174 base::Bind(&PpdProviderImpl::OnResolveFetchComplete,
175 weak_factory_.GetWeakPtr(), ppd_reference, done_callback));
104 176
105 resolve_fetcher_ = 177 resolve_fetcher_ = net::URLFetcher::Create(
106 net::URLFetcher::Create(GetQuirksServerPpdLookupURL(ppd_reference), 178 GetQuirksServerPpdLookupURL(ppd_reference), net::URLFetcher::GET,
107 net::URLFetcher::GET, &forwarding_delegate_); 179 resolve_fetcher_delegate_.get());
180
108 resolve_fetcher_->SetRequestContext(url_context_getter_.get()); 181 resolve_fetcher_->SetRequestContext(url_context_getter_.get());
109 resolve_fetcher_->SetLoadFlags( 182 resolve_fetcher_->SetLoadFlags(
110 net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE | 183 net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE |
111 net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES | 184 net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES |
112 net::LOAD_DO_NOT_SEND_AUTH_DATA); 185 net::LOAD_DO_NOT_SEND_AUTH_DATA);
113 resolve_fetcher_->Start(); 186 resolve_fetcher_->Start();
114 };
115
116 void AbortResolve() override {
117 // UrlFetcher guarantees that when the object has been destroyed, no further
118 // callbacks will occur.
119 resolve_fetcher_.reset();
120 } 187 }
121 188
122 void QueryAvailable(const QueryAvailableCallback& cb) override {
123 CHECK(!cb.is_null());
124 CHECK(query_sequence_checker_.CalledOnValidSequence());
125 CHECK(base::SequencedTaskRunnerHandle::IsSet())
126 << "QueryAvailable() must be called from a SequencedTaskRunner context";
127 CHECK(query_fetcher_ == nullptr)
128 << "Can't have concurrent PpdProvider QueryAvailable() calls";
129
130 const PpdProvider::AvailablePrintersMap* result =
131 cache_->FindAvailablePrinters();
132 if (result != nullptr) {
133 // Satisfy from cache.
134 base::SequencedTaskRunnerHandle::Get()->PostTask(
135 FROM_HERE, base::Bind(cb, PpdProvider::SUCCESS, *result));
136 return;
137 }
138 // Not in the cache, ask QuirksServer.
139 query_done_callback_ = cb;
140
141 query_fetcher_ =
142 net::URLFetcher::Create(GetQuirksServerPpdListURL(),
143 net::URLFetcher::GET, &forwarding_delegate_);
144 query_fetcher_->SetRequestContext(url_context_getter_.get());
145 query_fetcher_->SetLoadFlags(
146 net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE |
147 net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES |
148 net::LOAD_DO_NOT_SEND_AUTH_DATA);
149 query_fetcher_->Start();
150 }
151
152 void AbortQueryAvailable() override {
153 // UrlFetcher guarantees that when the object has been destroyed, no further
154 // callbacks will occur.
155 query_fetcher_.reset();
156 }
157
158 bool CachePpd(const Printer::PpdReference& ppd_reference,
159 const base::FilePath& ppd_path) override {
160 std::string buf;
161 if (!base::ReadFileToStringWithMaxSize(ppd_path, &buf,
162 options_.max_ppd_contents_size_)) {
163 return false;
164 }
165 return static_cast<bool>(cache_->Store(ppd_reference, buf));
166 }
167
168 // Route to the proper fetch complete handler based on which fetcher caused
169 // it.
170 void OnURLFetchComplete(const net::URLFetcher* fetcher) {
171 if (fetcher == resolve_fetcher_.get()) {
172 OnResolveFetchComplete();
173 } else if (fetcher == query_fetcher_.get()) {
174 OnQueryAvailableFetchComplete();
175 } else {
176 NOTREACHED() << "Unknown fetcher completed.";
177 }
178 }
179
180 private:
181 // Called on the same thread as Resolve() when the fetcher completes its 189 // Called on the same thread as Resolve() when the fetcher completes its
182 // fetch. 190 // fetch.
183 void OnResolveFetchComplete() { 191 void OnResolveFetchComplete(
192 const Printer::PpdReference& ppd_reference,
193 const PpdProvider::ResolveCallback& done_callback) {
184 CHECK(resolve_sequence_checker_.CalledOnValidSequence()); 194 CHECK(resolve_sequence_checker_.CalledOnValidSequence());
185 // Scope the allocated |resolve_fetcher_| into this function so we clean it 195 // Scope the allocated |resolve_fetcher_| and |resolve_fetcher_delegate_|
186 // up when we're done here instead of leaving it around until the next 196 // into this function so we clean it up when we're done here instead of
187 // Resolve() call. 197 // leaving it around until the next Resolve() call.
188 auto fetcher = std::move(resolve_fetcher_); 198 auto fetcher_delegate(std::move(resolve_fetcher_delegate_));
stevenjb 2016/11/14 23:08:39 nit: we don't appear to need fetcher_delegate belo
Carlson 2016/11/14 23:27:41 The delegate holds the callback *currently being i
stevenjb 2016/11/14 23:55:25 Once the function object is invoked, any bound par
199 auto fetcher(std::move(resolve_fetcher_));
200 resolve_inflight_ = false;
189 std::string contents; 201 std::string contents;
190 if (!ValidateAndGetResponseAsString(*fetcher, &contents)) { 202 if (!ValidateAndGetResponseAsString(*fetcher, &contents)) {
191 // Something went wrong with the fetch. 203 // Something went wrong with the fetch.
192 resolve_done_callback_.Run(PpdProvider::SERVER_ERROR, base::FilePath()); 204 done_callback.Run(PpdProvider::SERVER_ERROR, base::FilePath());
193 return; 205 return;
194 } 206 }
195 207
196 auto dict = base::DictionaryValue::From(base::JSONReader::Read(contents)); 208 auto dict = base::DictionaryValue::From(base::JSONReader::Read(contents));
197 if (dict == nullptr) { 209 if (dict == nullptr) {
198 resolve_done_callback_.Run(PpdProvider::SERVER_ERROR, base::FilePath()); 210 done_callback.Run(PpdProvider::SERVER_ERROR, base::FilePath());
199 return; 211 return;
200 } 212 }
201 std::string ppd_contents; 213 std::string ppd_contents;
202 std::string last_updated_time_string; 214 std::string last_updated_time_string;
203 uint64_t last_updated_time; 215 uint64_t last_updated_time;
204 if (!(dict->GetString(kJSONPPDKey, &ppd_contents) && 216 if (!(dict->GetString(kJSONPPDKey, &ppd_contents) &&
205 dict->GetString(kJSONLastUpdatedKey, &last_updated_time_string) && 217 dict->GetString(kJSONLastUpdatedKey, &last_updated_time_string) &&
206 base::StringToUint64(last_updated_time_string, &last_updated_time))) { 218 base::StringToUint64(last_updated_time_string, &last_updated_time))) {
207 // Malformed response. TODO(justincarlson) - LOG something here? 219 // Malformed response. TODO(justincarlson) - LOG something here?
208 resolve_done_callback_.Run(PpdProvider::SERVER_ERROR, base::FilePath()); 220 done_callback.Run(PpdProvider::SERVER_ERROR, base::FilePath());
209 return; 221 return;
210 } 222 }
211 223
212 if (ppd_contents.size() > options_.max_ppd_contents_size_) { 224 if (ppd_contents.size() > options_.max_ppd_contents_size_) {
213 // PPD is too big. 225 // PPD is too big.
214 // 226 //
215 // Note -- if we ever add shared-ppd-sourcing, e.g. we may serve a ppd to 227 // Note -- if we ever add shared-ppd-sourcing, e.g. we may serve a ppd to
216 // a user that's not from an explicitly trusted source, we should also 228 // a user that's not from an explicitly trusted source, we should also
217 // check *uncompressed* size here to head off zip-bombs (e.g. let's 229 // check *uncompressed* size here to head off zip-bombs (e.g. let's
218 // compress 1GBs of zeros into a 900kb file and see what cups does when it 230 // compress 1GBs of zeros into a 900kb file and see what cups does when it
219 // tries to expand that...) 231 // tries to expand that...)
220 resolve_done_callback_.Run(PpdProvider::SERVER_ERROR, base::FilePath()); 232 done_callback.Run(PpdProvider::SERVER_ERROR, base::FilePath());
221 return; 233 return;
222 } 234 }
223 235
224 auto ppd_file = cache_->Store(resolve_reference_, ppd_contents); 236 auto ppd_file = cache_->Store(ppd_reference, ppd_contents);
225 if (!ppd_file) { 237 if (!ppd_file) {
226 // Failed to store. 238 // Failed to store.
227 resolve_done_callback_.Run(PpdProvider::INTERNAL_ERROR, base::FilePath()); 239 done_callback.Run(PpdProvider::INTERNAL_ERROR, base::FilePath());
228 return; 240 return;
229 } 241 }
230 resolve_done_callback_.Run(PpdProvider::SUCCESS, ppd_file.value()); 242 done_callback.Run(PpdProvider::SUCCESS, ppd_file.value());
231 } 243 }
232 244
233 // Called on the same thread as QueryAvailable() when the fetcher completes 245 // Called on the same thread as QueryAvailable() when the cache lookup is
234 // its fetch. 246 // done. If the cache satisfied the request, finish the Query, otherwise
235 void OnQueryAvailableFetchComplete() { 247 // start a URL request to satisfy the Query. This runs on the same thread as
248 // QueryAvailable() was invoked on.
249 void QueryCacheLookupDone(
250 const PpdProvider::QueryAvailableCallback& done_callback,
251 const std::unique_ptr<
252 base::Optional<const PpdProvider::AvailablePrintersMap*>>&
253 cache_result) {
236 CHECK(query_sequence_checker_.CalledOnValidSequence()); 254 CHECK(query_sequence_checker_.CalledOnValidSequence());
237 // Scope the object fetcher into this function so we clean it up when we're 255 if (*cache_result) {
238 // done here instead of leaving it around until the next QueryAvailable() 256 query_inflight_ = false;
239 // call. 257 done_callback.Run(PpdProvider::SUCCESS, *cache_result->value());
240 auto fetcher = std::move(query_fetcher_); 258 return;
259 }
260 // Missed in the cache, start a query.
261 query_fetcher_delegate_ = base::MakeUnique<ForwardingURLFetcherDelegate>(
262 base::Bind(&PpdProviderImpl::OnQueryAvailableFetchComplete,
263 weak_factory_.GetWeakPtr(), done_callback));
264
265 query_fetcher_ = net::URLFetcher::Create(GetQuirksServerPpdListURL(),
266 net::URLFetcher::GET,
267 query_fetcher_delegate_.get());
268 query_fetcher_->SetRequestContext(url_context_getter_.get());
269 query_fetcher_->SetLoadFlags(
270 net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE |
271 net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES |
272 net::LOAD_DO_NOT_SEND_AUTH_DATA);
273 query_fetcher_->Start();
274 }
275
276 void OnQueryAvailableFetchComplete(
277 const PpdProvider::QueryAvailableCallback& done_callback) {
278 CHECK(query_sequence_checker_.CalledOnValidSequence());
279 // Scope the object fetcher and task_runner into this function so we clean
280 // it up when we're done here instead of leaving it around until the next
281 // QueryAvailable() call.
282 auto fetcher_delegate(std::move(query_fetcher_delegate_));
stevenjb 2016/11/14 23:08:39 Also unused, can use reset().
Carlson 2016/11/14 23:27:41 See above
283 auto fetcher(std::move(query_fetcher_));
284 query_inflight_ = false;
241 std::string contents; 285 std::string contents;
242 if (!ValidateAndGetResponseAsString(*fetcher, &contents)) { 286 if (!ValidateAndGetResponseAsString(*fetcher, &contents)) {
243 // Something went wrong with the fetch. 287 // Something went wrong with the fetch.
244 query_done_callback_.Run(PpdProvider::SERVER_ERROR, 288 done_callback.Run(PpdProvider::SERVER_ERROR, AvailablePrintersMap());
245 AvailablePrintersMap());
246 return; 289 return;
247 } 290 }
248 291
249 // The server gives us JSON in the form of a list of (manufacturer, list of 292 // The server gives us JSON in the form of a list of (manufacturer, list of
250 // models) tuples. 293 // models) tuples.
251 auto top_dict = 294 auto top_dict =
252 base::DictionaryValue::From(base::JSONReader::Read(contents)); 295 base::DictionaryValue::From(base::JSONReader::Read(contents));
253 const base::ListValue* top_list; 296 const base::ListValue* top_list;
254 if (top_dict == nullptr || !top_dict->GetList(kJSONTopListKey, &top_list)) { 297 if (top_dict == nullptr || !top_dict->GetList(kJSONTopListKey, &top_list)) {
255 LOG(ERROR) << "Malformed response from quirks server"; 298 LOG(ERROR) << "Malformed response from quirks server";
256 query_done_callback_.Run(PpdProvider::SERVER_ERROR, 299 done_callback.Run(PpdProvider::SERVER_ERROR, AvailablePrintersMap());
257 PpdProvider::AvailablePrintersMap());
258 return; 300 return;
259 } 301 }
260 302
261 auto result = base::MakeUnique<PpdProvider::AvailablePrintersMap>(); 303 auto result = base::MakeUnique<PpdProvider::AvailablePrintersMap>();
262 for (const std::unique_ptr<base::Value>& entry : *top_list) { 304 for (const std::unique_ptr<base::Value>& entry : *top_list) {
263 base::DictionaryValue* dict; 305 base::DictionaryValue* dict;
264 std::string manufacturer; 306 std::string manufacturer;
265 std::string model; 307 std::string model;
266 base::ListValue* model_list; 308 base::ListValue* model_list;
267 if (!entry->GetAsDictionary(&dict) || 309 if (!entry->GetAsDictionary(&dict) ||
268 !dict->GetString(kJSONManufacturer, &manufacturer) || 310 !dict->GetString(kJSONManufacturer, &manufacturer) ||
269 !dict->GetList(kJSONModelList, &model_list)) { 311 !dict->GetList(kJSONModelList, &model_list)) {
270 LOG(ERROR) << "Unexpected contents in quirks server printer list."; 312 LOG(ERROR) << "Unexpected contents in quirks server printer list.";
271 // Just skip this entry instead of aborting the whole thing. 313 // Just skip this entry instead of aborting the whole thing.
272 continue; 314 continue;
273 } 315 }
274 316
275 std::vector<std::string>& dest = (*result)[manufacturer]; 317 std::vector<std::string>& dest = (*result)[manufacturer];
276 for (const std::unique_ptr<base::Value>& model_value : *model_list) { 318 for (const std::unique_ptr<base::Value>& model_value : *model_list) {
277 if (model_value->GetAsString(&model)) { 319 if (model_value->GetAsString(&model)) {
278 dest.push_back(model); 320 dest.push_back(model);
279 } else { 321 } else {
280 LOG(ERROR) << "Skipping unknown model for manufacturer " 322 LOG(ERROR) << "Skipping unknown model for manufacturer "
281 << manufacturer; 323 << manufacturer;
282 } 324 }
283 } 325 }
284 } 326 }
285 query_done_callback_.Run(PpdProvider::SUCCESS, *result); 327 done_callback.Run(PpdProvider::SUCCESS, *result);
286 if (!result->empty()) { 328 if (!result->empty()) {
287 cache_->StoreAvailablePrinters(std::move(result)); 329 cache_->StoreAvailablePrinters(std::move(result));
288 } else { 330 } else {
289 // An empty map means something is probably wrong; if we cache this map, 331 // An empty map means something is probably wrong; if we cache this map,
290 // we'll have an empty map until the cache expires. So complain and 332 // we'll have an empty map until the cache expires. So complain and
291 // refuse to cache. 333 // refuse to cache.
292 LOG(ERROR) << "Available printers map is unexpectedly empty. Refusing " 334 LOG(ERROR) << "Available printers map is unexpectedly empty. Refusing "
293 "to cache this."; 335 "to cache this.";
294 } 336 }
295 } 337 }
(...skipping 20 matching lines...) Expand all
316 // return true, otherwise return false. 358 // return true, otherwise return false.
317 bool ValidateAndGetResponseAsString(const net::URLFetcher& fetcher, 359 bool ValidateAndGetResponseAsString(const net::URLFetcher& fetcher,
318 std::string* contents) { 360 std::string* contents) {
319 return ((fetcher.GetStatus().status() == net::URLRequestStatus::SUCCESS) && 361 return ((fetcher.GetStatus().status() == net::URLRequestStatus::SUCCESS) &&
320 (fetcher.GetResponseCode() == net::HTTP_OK) && 362 (fetcher.GetResponseCode() == net::HTTP_OK) &&
321 fetcher.GetResponseAsString(contents)); 363 fetcher.GetResponseAsString(contents));
322 } 364 }
323 365
324 // State held across a Resolve() call. 366 // State held across a Resolve() call.
325 367
326 // Reference we're currently trying to resolve.
327 Printer::PpdReference resolve_reference_;
328
329 // Callback to invoke on completion.
330 PpdProvider::ResolveCallback resolve_done_callback_;
331
332 // Check that Resolve() and its callback are sequenced appropriately. 368 // Check that Resolve() and its callback are sequenced appropriately.
333 base::SequenceChecker resolve_sequence_checker_; 369 base::SequenceChecker resolve_sequence_checker_;
334 370
335 // Fetcher for the current call, if any. 371 // Fetcher and associated delegate for the current Resolve() call, if a fetch
372 // is in progress. These are both null if no Resolve() is in flight.
336 std::unique_ptr<net::URLFetcher> resolve_fetcher_; 373 std::unique_ptr<net::URLFetcher> resolve_fetcher_;
374 std::unique_ptr<ForwardingURLFetcherDelegate> resolve_fetcher_delegate_;
375 // Is there a current Resolve() inflight? Used to help fail-fast in the case
376 // of inappropriate concurrent usage.
377 bool resolve_inflight_ = false;
337 378
338 // State held across a QueryAvailable() call. 379 // State held across a QueryAvailable() call.
339 380
340 // Callback to invoke on completion.
341 PpdProvider::QueryAvailableCallback query_done_callback_;
342
343 // Check that QueryAvailable() and its callback are sequenced appropriately. 381 // Check that QueryAvailable() and its callback are sequenced appropriately.
344 base::SequenceChecker query_sequence_checker_; 382 base::SequenceChecker query_sequence_checker_;
345 383
346 // Fetcher for the current call, if any. 384 // Fetcher and associated delegate for the current QueryAvailable() call, if a
385 // fetch is in progress. These are both null if no QueryAvailable() is in
386 // flight.
347 std::unique_ptr<net::URLFetcher> query_fetcher_; 387 std::unique_ptr<net::URLFetcher> query_fetcher_;
388 std::unique_ptr<ForwardingURLFetcherDelegate> query_fetcher_delegate_;
389 // Is there a current QueryAvailable() inflight? Used to help fail-fast in
390 // the case of inappropriate concurrent usage.
391 bool query_inflight_ = false;
348 392
349 // Common state. 393 // Common state.
350 394
351 // API key for accessing quirks server. 395 // API key for accessing quirks server.
352 const std::string api_key_; 396 const std::string api_key_;
353 397
354 ForwardingURLFetcherDelegate forwarding_delegate_;
355 scoped_refptr<net::URLRequestContextGetter> url_context_getter_; 398 scoped_refptr<net::URLRequestContextGetter> url_context_getter_;
399 scoped_refptr<base::SequencedTaskRunner> io_task_runner_;
356 std::unique_ptr<PpdCache> cache_; 400 std::unique_ptr<PpdCache> cache_;
357 401
358 // Construction-time options, immutable. 402 // Construction-time options, immutable.
359 const PpdProvider::Options options_; 403 const PpdProvider::Options options_;
404
405 base::WeakPtrFactory<PpdProviderImpl> weak_factory_;
360 }; 406 };
361 407
362 void ForwardingURLFetcherDelegate::OnURLFetchComplete(
363 const net::URLFetcher* source) {
364 owner_->OnURLFetchComplete(source);
365 }
366
367 } // namespace 408 } // namespace
368 409
369 // static 410 // static
370 std::unique_ptr<PpdProvider> PpdProvider::Create( 411 std::unique_ptr<PpdProvider> PpdProvider::Create(
371 const std::string& api_key, 412 const std::string& api_key,
372 scoped_refptr<net::URLRequestContextGetter> url_context_getter, 413 scoped_refptr<net::URLRequestContextGetter> url_context_getter,
414 scoped_refptr<base::SequencedTaskRunner> io_task_runner,
373 std::unique_ptr<PpdCache> cache, 415 std::unique_ptr<PpdCache> cache,
374 const PpdProvider::Options& options) { 416 const PpdProvider::Options& options) {
375 return base::MakeUnique<PpdProviderImpl>(api_key, url_context_getter, 417 return base::MakeUnique<PpdProviderImpl>(
376 std::move(cache), options); 418 api_key, url_context_getter, io_task_runner, std::move(cache), options);
377 } 419 }
378 420
379 } // namespace printing 421 } // namespace printing
380 } // namespace chromeos 422 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698