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

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

Issue 2476073003: Update PpdProvider threading model. (Closed)
Patch Set: Change CHECK to DCHECK 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
« no previous file with comments | « chromeos/printing/ppd_provider.h ('k') | chromeos/printing/ppd_provider_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 bool post_result = io_task_runner_->PostTaskAndReply(
89 FROM_HERE, base::Bind(&PpdProviderImpl::ResolveDoCacheLookup,
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 DCHECK(post_result);
96 }
81 97
82 base::Optional<base::FilePath> tmp = cache_->Find(ppd_reference); 98 void QueryAvailable(const QueryAvailableCallback& cb) override {
83 if (tmp) { 99 CHECK(!cb.is_null());
100 CHECK(base::SequencedTaskRunnerHandle::IsSet())
101 << "QueryAvailable() must be called from a SequencedTaskRunner context";
102 auto cache_result = base::MakeUnique<
103 base::Optional<const PpdProvider::AvailablePrintersMap*>>();
104 CHECK(!query_inflight_)
105 << "Can't have concurrent PpdProvider QueryAvailable calls";
106 query_inflight_ = true;
107 CHECK(io_task_runner_->PostTaskAndReply(
108 FROM_HERE, base::Bind(&PpdProviderImpl::QueryAvailableDoCacheLookup,
109 weak_factory_.GetWeakPtr(), cache_result.get()),
110 base::Bind(&PpdProviderImpl::QueryAvailableCacheLookupDone,
111 weak_factory_.GetWeakPtr(), cb, std::move(cache_result))));
112 }
113
114 bool CachePpd(const Printer::PpdReference& ppd_reference,
115 const base::FilePath& ppd_path) override {
116 std::string buf;
117 if (!base::ReadFileToStringWithMaxSize(ppd_path, &buf,
118 options_.max_ppd_contents_size_)) {
119 return false;
120 }
121 return static_cast<bool>(cache_->Store(ppd_reference, buf));
122 }
123
124 private:
125 // Trivial wrappers around PpdCache::Find() and
126 // PpdCache::FindAvailablePrinters(). We need these wrappers both because we
127 // use weak_ptrs to manage lifetime, and so we need to bind callbacks to
128 // *this*, and because weak_ptr's preclude return values in posted tasks, so
129 // we have to use a parameter to return state.
130 void ResolveDoCacheLookup(
131 const Printer::PpdReference& reference,
132 base::Optional<base::FilePath>* cache_result) const {
133 *cache_result = cache_->Find(reference);
134 }
135
136 void QueryAvailableDoCacheLookup(
137 base::Optional<const PpdProvider::AvailablePrintersMap*>* cache_result)
138 const {
139 auto tmp = cache_->FindAvailablePrinters();
140 if (tmp != nullptr) {
141 *cache_result = tmp;
142 } else {
143 *cache_result = base::nullopt;
144 }
145 }
146
147 // Callback that happens when the Resolve() cache lookup completes. If the
148 // cache satisfied the request, finish the Resolve, otherwise start a URL
149 // request to satisfy the request. This runs on the same thread as Resolve()
150 // was invoked on.
151 void ResolveCacheLookupDone(
152 const Printer::PpdReference& ppd_reference,
153 const PpdProvider::ResolveCallback& done_callback,
154 const std::unique_ptr<base::Optional<base::FilePath>>& cache_result) {
155 CHECK(resolve_sequence_checker_.CalledOnValidSequence());
156 if (*cache_result) {
84 // Cache hit. Schedule the callback now and return. 157 // Cache hit. Schedule the callback now and return.
85 base::SequencedTaskRunnerHandle::Get()->PostTask( 158 resolve_inflight_ = false;
86 FROM_HERE, base::Bind(cb, PpdProvider::SUCCESS, tmp.value())); 159 done_callback.Run(PpdProvider::SUCCESS, cache_result->value());
87 return; 160 return;
88 } 161 }
89 162
90 // We don't have a way to automatically resolve user-supplied PPDs yet. So 163 // 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 164 // 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 165 // 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 166 // 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 167 // probably means the quirks server one doesn't work for some reason, so we
95 // shouldn't silently use it. 168 // shouldn't silently use it.
96 if (!ppd_reference.user_supplied_ppd_url.empty()) { 169 if (!ppd_reference.user_supplied_ppd_url.empty()) {
97 base::SequencedTaskRunnerHandle::Get()->PostTask( 170 resolve_inflight_ = false;
98 FROM_HERE, base::Bind(cb, PpdProvider::NOT_FOUND, base::FilePath())); 171 done_callback.Run(PpdProvider::NOT_FOUND, base::FilePath());
99 return; 172 return;
100 } 173 }
101 174
102 resolve_reference_ = ppd_reference; 175 // Missed in the cache, so start a URLRequest to resolve the request.
103 resolve_done_callback_ = cb; 176 resolve_fetcher_delegate_ = base::MakeUnique<ForwardingURLFetcherDelegate>(
177 base::Bind(&PpdProviderImpl::OnResolveFetchComplete,
178 weak_factory_.GetWeakPtr(), ppd_reference, done_callback));
104 179
105 resolve_fetcher_ = 180 resolve_fetcher_ = net::URLFetcher::Create(
106 net::URLFetcher::Create(GetQuirksServerPpdLookupURL(ppd_reference), 181 GetQuirksServerPpdLookupURL(ppd_reference), net::URLFetcher::GET,
107 net::URLFetcher::GET, &forwarding_delegate_); 182 resolve_fetcher_delegate_.get());
183
108 resolve_fetcher_->SetRequestContext(url_context_getter_.get()); 184 resolve_fetcher_->SetRequestContext(url_context_getter_.get());
109 resolve_fetcher_->SetLoadFlags( 185 resolve_fetcher_->SetLoadFlags(
110 net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE | 186 net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE |
111 net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES | 187 net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES |
112 net::LOAD_DO_NOT_SEND_AUTH_DATA); 188 net::LOAD_DO_NOT_SEND_AUTH_DATA);
113 resolve_fetcher_->Start(); 189 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 } 190 }
121 191
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 192 // Called on the same thread as Resolve() when the fetcher completes its
182 // fetch. 193 // fetch.
183 void OnResolveFetchComplete() { 194 void OnResolveFetchComplete(
195 const Printer::PpdReference& ppd_reference,
196 const PpdProvider::ResolveCallback& done_callback) {
184 CHECK(resolve_sequence_checker_.CalledOnValidSequence()); 197 CHECK(resolve_sequence_checker_.CalledOnValidSequence());
185 // Scope the allocated |resolve_fetcher_| into this function so we clean it 198 // Scope the allocated |resolve_fetcher_| and |resolve_fetcher_delegate_|
186 // up when we're done here instead of leaving it around until the next 199 // into this function so we clean it up when we're done here instead of
187 // Resolve() call. 200 // leaving it around until the next Resolve() call.
188 auto fetcher = std::move(resolve_fetcher_); 201 auto fetcher_delegate(std::move(resolve_fetcher_delegate_));
202 auto fetcher(std::move(resolve_fetcher_));
203 resolve_inflight_ = false;
189 std::string contents; 204 std::string contents;
190 if (!ValidateAndGetResponseAsString(*fetcher, &contents)) { 205 if (!ValidateAndGetResponseAsString(*fetcher, &contents)) {
191 // Something went wrong with the fetch. 206 // Something went wrong with the fetch.
192 resolve_done_callback_.Run(PpdProvider::SERVER_ERROR, base::FilePath()); 207 done_callback.Run(PpdProvider::SERVER_ERROR, base::FilePath());
193 return; 208 return;
194 } 209 }
195 210
196 auto dict = base::DictionaryValue::From(base::JSONReader::Read(contents)); 211 auto dict = base::DictionaryValue::From(base::JSONReader::Read(contents));
197 if (dict == nullptr) { 212 if (dict == nullptr) {
198 resolve_done_callback_.Run(PpdProvider::SERVER_ERROR, base::FilePath()); 213 done_callback.Run(PpdProvider::SERVER_ERROR, base::FilePath());
199 return; 214 return;
200 } 215 }
201 std::string ppd_contents; 216 std::string ppd_contents;
202 std::string last_updated_time_string; 217 std::string last_updated_time_string;
203 uint64_t last_updated_time; 218 uint64_t last_updated_time;
204 if (!(dict->GetString(kJSONPPDKey, &ppd_contents) && 219 if (!(dict->GetString(kJSONPPDKey, &ppd_contents) &&
205 dict->GetString(kJSONLastUpdatedKey, &last_updated_time_string) && 220 dict->GetString(kJSONLastUpdatedKey, &last_updated_time_string) &&
206 base::StringToUint64(last_updated_time_string, &last_updated_time))) { 221 base::StringToUint64(last_updated_time_string, &last_updated_time))) {
207 // Malformed response. TODO(justincarlson) - LOG something here? 222 // Malformed response. TODO(justincarlson) - LOG something here?
208 resolve_done_callback_.Run(PpdProvider::SERVER_ERROR, base::FilePath()); 223 done_callback.Run(PpdProvider::SERVER_ERROR, base::FilePath());
209 return; 224 return;
210 } 225 }
211 226
212 if (ppd_contents.size() > options_.max_ppd_contents_size_) { 227 if (ppd_contents.size() > options_.max_ppd_contents_size_) {
213 // PPD is too big. 228 // PPD is too big.
214 // 229 //
215 // Note -- if we ever add shared-ppd-sourcing, e.g. we may serve a ppd to 230 // 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 231 // 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 232 // 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 233 // compress 1GBs of zeros into a 900kb file and see what cups does when it
219 // tries to expand that...) 234 // tries to expand that...)
220 resolve_done_callback_.Run(PpdProvider::SERVER_ERROR, base::FilePath()); 235 done_callback.Run(PpdProvider::SERVER_ERROR, base::FilePath());
221 return; 236 return;
222 } 237 }
223 238
224 auto ppd_file = cache_->Store(resolve_reference_, ppd_contents); 239 auto ppd_file = cache_->Store(ppd_reference, ppd_contents);
225 if (!ppd_file) { 240 if (!ppd_file) {
226 // Failed to store. 241 // Failed to store.
227 resolve_done_callback_.Run(PpdProvider::INTERNAL_ERROR, base::FilePath()); 242 done_callback.Run(PpdProvider::INTERNAL_ERROR, base::FilePath());
228 return; 243 return;
229 } 244 }
230 resolve_done_callback_.Run(PpdProvider::SUCCESS, ppd_file.value()); 245 done_callback.Run(PpdProvider::SUCCESS, ppd_file.value());
231 } 246 }
232 247
233 // Called on the same thread as QueryAvailable() when the fetcher completes 248 // Called on the same thread as QueryAvailable() when the cache lookup is
234 // its fetch. 249 // done. If the cache satisfied the request, finish the Query, otherwise
235 void OnQueryAvailableFetchComplete() { 250 // start a URL request to satisfy the Query. This runs on the same thread as
251 // QueryAvailable() was invoked on.
252 void QueryAvailableCacheLookupDone(
253 const PpdProvider::QueryAvailableCallback& done_callback,
254 const std::unique_ptr<
255 base::Optional<const PpdProvider::AvailablePrintersMap*>>&
256 cache_result) {
236 CHECK(query_sequence_checker_.CalledOnValidSequence()); 257 CHECK(query_sequence_checker_.CalledOnValidSequence());
237 // Scope the object fetcher into this function so we clean it up when we're 258 if (*cache_result) {
238 // done here instead of leaving it around until the next QueryAvailable() 259 query_inflight_ = false;
239 // call. 260 done_callback.Run(PpdProvider::SUCCESS, *cache_result->value());
240 auto fetcher = std::move(query_fetcher_); 261 return;
262 }
263 // Missed in the cache, start a query.
264 query_fetcher_delegate_ = base::MakeUnique<ForwardingURLFetcherDelegate>(
265 base::Bind(&PpdProviderImpl::OnQueryAvailableFetchComplete,
266 weak_factory_.GetWeakPtr(), done_callback));
267
268 query_fetcher_ = net::URLFetcher::Create(GetQuirksServerPpdListURL(),
269 net::URLFetcher::GET,
270 query_fetcher_delegate_.get());
271 query_fetcher_->SetRequestContext(url_context_getter_.get());
272 query_fetcher_->SetLoadFlags(
273 net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE |
274 net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES |
275 net::LOAD_DO_NOT_SEND_AUTH_DATA);
276 query_fetcher_->Start();
277 }
278
279 void OnQueryAvailableFetchComplete(
280 const PpdProvider::QueryAvailableCallback& done_callback) {
281 CHECK(query_sequence_checker_.CalledOnValidSequence());
282 // Scope the object fetcher and task_runner into this function so we clean
283 // it up when we're done here instead of leaving it around until the next
284 // QueryAvailable() call.
285 auto fetcher_delegate(std::move(query_fetcher_delegate_));
286 auto fetcher(std::move(query_fetcher_));
287 query_inflight_ = false;
241 std::string contents; 288 std::string contents;
242 if (!ValidateAndGetResponseAsString(*fetcher, &contents)) { 289 if (!ValidateAndGetResponseAsString(*fetcher, &contents)) {
243 // Something went wrong with the fetch. 290 // Something went wrong with the fetch.
244 query_done_callback_.Run(PpdProvider::SERVER_ERROR, 291 done_callback.Run(PpdProvider::SERVER_ERROR, AvailablePrintersMap());
245 AvailablePrintersMap());
246 return; 292 return;
247 } 293 }
248 294
249 // The server gives us JSON in the form of a list of (manufacturer, list of 295 // The server gives us JSON in the form of a list of (manufacturer, list of
250 // models) tuples. 296 // models) tuples.
251 auto top_dict = 297 auto top_dict =
252 base::DictionaryValue::From(base::JSONReader::Read(contents)); 298 base::DictionaryValue::From(base::JSONReader::Read(contents));
253 const base::ListValue* top_list; 299 const base::ListValue* top_list;
254 if (top_dict == nullptr || !top_dict->GetList(kJSONTopListKey, &top_list)) { 300 if (top_dict == nullptr || !top_dict->GetList(kJSONTopListKey, &top_list)) {
255 LOG(ERROR) << "Malformed response from quirks server"; 301 LOG(ERROR) << "Malformed response from quirks server";
256 query_done_callback_.Run(PpdProvider::SERVER_ERROR, 302 done_callback.Run(PpdProvider::SERVER_ERROR, AvailablePrintersMap());
257 PpdProvider::AvailablePrintersMap());
258 return; 303 return;
259 } 304 }
260 305
261 auto result = base::MakeUnique<PpdProvider::AvailablePrintersMap>(); 306 auto result = base::MakeUnique<PpdProvider::AvailablePrintersMap>();
262 for (const std::unique_ptr<base::Value>& entry : *top_list) { 307 for (const std::unique_ptr<base::Value>& entry : *top_list) {
263 base::DictionaryValue* dict; 308 base::DictionaryValue* dict;
264 std::string manufacturer; 309 std::string manufacturer;
265 std::string model; 310 std::string model;
266 base::ListValue* model_list; 311 base::ListValue* model_list;
267 if (!entry->GetAsDictionary(&dict) || 312 if (!entry->GetAsDictionary(&dict) ||
268 !dict->GetString(kJSONManufacturer, &manufacturer) || 313 !dict->GetString(kJSONManufacturer, &manufacturer) ||
269 !dict->GetList(kJSONModelList, &model_list)) { 314 !dict->GetList(kJSONModelList, &model_list)) {
270 LOG(ERROR) << "Unexpected contents in quirks server printer list."; 315 LOG(ERROR) << "Unexpected contents in quirks server printer list.";
271 // Just skip this entry instead of aborting the whole thing. 316 // Just skip this entry instead of aborting the whole thing.
272 continue; 317 continue;
273 } 318 }
274 319
275 std::vector<std::string>& dest = (*result)[manufacturer]; 320 std::vector<std::string>& dest = (*result)[manufacturer];
276 for (const std::unique_ptr<base::Value>& model_value : *model_list) { 321 for (const std::unique_ptr<base::Value>& model_value : *model_list) {
277 if (model_value->GetAsString(&model)) { 322 if (model_value->GetAsString(&model)) {
278 dest.push_back(model); 323 dest.push_back(model);
279 } else { 324 } else {
280 LOG(ERROR) << "Skipping unknown model for manufacturer " 325 LOG(ERROR) << "Skipping unknown model for manufacturer "
281 << manufacturer; 326 << manufacturer;
282 } 327 }
283 } 328 }
284 } 329 }
285 query_done_callback_.Run(PpdProvider::SUCCESS, *result); 330 done_callback.Run(PpdProvider::SUCCESS, *result);
286 if (!result->empty()) { 331 if (!result->empty()) {
287 cache_->StoreAvailablePrinters(std::move(result)); 332 cache_->StoreAvailablePrinters(std::move(result));
288 } else { 333 } else {
289 // An empty map means something is probably wrong; if we cache this map, 334 // 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 335 // we'll have an empty map until the cache expires. So complain and
291 // refuse to cache. 336 // refuse to cache.
292 LOG(ERROR) << "Available printers map is unexpectedly empty. Refusing " 337 LOG(ERROR) << "Available printers map is unexpectedly empty. Refusing "
293 "to cache this."; 338 "to cache this.";
294 } 339 }
295 } 340 }
(...skipping 20 matching lines...) Expand all
316 // return true, otherwise return false. 361 // return true, otherwise return false.
317 bool ValidateAndGetResponseAsString(const net::URLFetcher& fetcher, 362 bool ValidateAndGetResponseAsString(const net::URLFetcher& fetcher,
318 std::string* contents) { 363 std::string* contents) {
319 return ((fetcher.GetStatus().status() == net::URLRequestStatus::SUCCESS) && 364 return ((fetcher.GetStatus().status() == net::URLRequestStatus::SUCCESS) &&
320 (fetcher.GetResponseCode() == net::HTTP_OK) && 365 (fetcher.GetResponseCode() == net::HTTP_OK) &&
321 fetcher.GetResponseAsString(contents)); 366 fetcher.GetResponseAsString(contents));
322 } 367 }
323 368
324 // State held across a Resolve() call. 369 // State held across a Resolve() call.
325 370
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. 371 // Check that Resolve() and its callback are sequenced appropriately.
333 base::SequenceChecker resolve_sequence_checker_; 372 base::SequenceChecker resolve_sequence_checker_;
334 373
335 // Fetcher for the current call, if any. 374 // Fetcher and associated delegate for the current Resolve() call, if a fetch
375 // is in progress. These are both null if no Resolve() is in flight.
336 std::unique_ptr<net::URLFetcher> resolve_fetcher_; 376 std::unique_ptr<net::URLFetcher> resolve_fetcher_;
377 std::unique_ptr<ForwardingURLFetcherDelegate> resolve_fetcher_delegate_;
378 // Is there a current Resolve() inflight? Used to help fail-fast in the case
379 // of inappropriate concurrent usage.
380 bool resolve_inflight_ = false;
337 381
338 // State held across a QueryAvailable() call. 382 // State held across a QueryAvailable() call.
339 383
340 // Callback to invoke on completion.
341 PpdProvider::QueryAvailableCallback query_done_callback_;
342
343 // Check that QueryAvailable() and its callback are sequenced appropriately. 384 // Check that QueryAvailable() and its callback are sequenced appropriately.
344 base::SequenceChecker query_sequence_checker_; 385 base::SequenceChecker query_sequence_checker_;
345 386
346 // Fetcher for the current call, if any. 387 // Fetcher and associated delegate for the current QueryAvailable() call, if a
388 // fetch is in progress. These are both null if no QueryAvailable() is in
389 // flight.
347 std::unique_ptr<net::URLFetcher> query_fetcher_; 390 std::unique_ptr<net::URLFetcher> query_fetcher_;
391 std::unique_ptr<ForwardingURLFetcherDelegate> query_fetcher_delegate_;
392 // Is there a current QueryAvailable() inflight? Used to help fail-fast in
393 // the case of inappropriate concurrent usage.
394 bool query_inflight_ = false;
348 395
349 // Common state. 396 // Common state.
350 397
351 // API key for accessing quirks server. 398 // API key for accessing quirks server.
352 const std::string api_key_; 399 const std::string api_key_;
353 400
354 ForwardingURLFetcherDelegate forwarding_delegate_;
355 scoped_refptr<net::URLRequestContextGetter> url_context_getter_; 401 scoped_refptr<net::URLRequestContextGetter> url_context_getter_;
402 scoped_refptr<base::SequencedTaskRunner> io_task_runner_;
356 std::unique_ptr<PpdCache> cache_; 403 std::unique_ptr<PpdCache> cache_;
357 404
358 // Construction-time options, immutable. 405 // Construction-time options, immutable.
359 const PpdProvider::Options options_; 406 const PpdProvider::Options options_;
407
408 base::WeakPtrFactory<PpdProviderImpl> weak_factory_;
360 }; 409 };
361 410
362 void ForwardingURLFetcherDelegate::OnURLFetchComplete(
363 const net::URLFetcher* source) {
364 owner_->OnURLFetchComplete(source);
365 }
366
367 } // namespace 411 } // namespace
368 412
369 // static 413 // static
370 std::unique_ptr<PpdProvider> PpdProvider::Create( 414 std::unique_ptr<PpdProvider> PpdProvider::Create(
371 const std::string& api_key, 415 const std::string& api_key,
372 scoped_refptr<net::URLRequestContextGetter> url_context_getter, 416 scoped_refptr<net::URLRequestContextGetter> url_context_getter,
417 scoped_refptr<base::SequencedTaskRunner> io_task_runner,
373 std::unique_ptr<PpdCache> cache, 418 std::unique_ptr<PpdCache> cache,
374 const PpdProvider::Options& options) { 419 const PpdProvider::Options& options) {
375 return base::MakeUnique<PpdProviderImpl>(api_key, url_context_getter, 420 return base::MakeUnique<PpdProviderImpl>(
376 std::move(cache), options); 421 api_key, url_context_getter, io_task_runner, std::move(cache), options);
377 } 422 }
378 423
379 } // namespace printing 424 } // namespace printing
380 } // namespace chromeos 425 } // namespace chromeos
OLDNEW
« no previous file with comments | « chromeos/printing/ppd_provider.h ('k') | chromeos/printing/ppd_provider_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698