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

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

Issue 2476073003: Update PpdProvider threading model. (Closed)
Patch Set: Add more logging, add bypass for manufacturer issue 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/threading/sequenced_task_runner_handle.h" 16 #include "base/threading/sequenced_task_runner_handle.h"
17 #include "base/threading/thread_restrictions.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
(...skipping 25 matching lines...) Expand all
52 private: 53 private:
53 // owner of this delegate. 54 // owner of this delegate.
54 PpdProviderImpl* const owner_; 55 PpdProviderImpl* const owner_;
55 }; 56 };
56 57
57 class PpdProviderImpl : public PpdProvider { 58 class PpdProviderImpl : public PpdProvider {
58 public: 59 public:
59 PpdProviderImpl( 60 PpdProviderImpl(
60 const std::string& api_key, 61 const std::string& api_key,
61 scoped_refptr<net::URLRequestContextGetter> url_context_getter, 62 scoped_refptr<net::URLRequestContextGetter> url_context_getter,
63 scoped_refptr<base::SequencedTaskRunner> disk_task_runner,
62 std::unique_ptr<PpdCache> cache, 64 std::unique_ptr<PpdCache> cache,
63 const PpdProvider::Options& options) 65 const PpdProvider::Options& options)
64 : api_key_(api_key), 66 : api_key_(api_key),
65 forwarding_delegate_(this), 67 forwarding_delegate_(this),
66 url_context_getter_(url_context_getter), 68 url_context_getter_(url_context_getter),
69 disk_task_runner_(disk_task_runner),
67 cache_(std::move(cache)), 70 cache_(std::move(cache)),
68 options_(options) { 71 options_(options),
72 weak_factory_(this) {
69 CHECK_GT(options_.max_ppd_contents_size_, 0U); 73 CHECK_GT(options_.max_ppd_contents_size_, 0U);
70 } 74 }
71 ~PpdProviderImpl() override {} 75 ~PpdProviderImpl() override {}
72 76
73 void Resolve(const Printer::PpdReference& ppd_reference, 77 void Resolve(const Printer::PpdReference& ppd_reference,
74 const PpdProvider::ResolveCallback& cb) override { 78 const PpdProvider::ResolveCallback& cb) override {
75 CHECK(!cb.is_null()); 79 CHECK(!cb.is_null());
80 CHECK(base::SequencedTaskRunnerHandle::IsSet())
81 << "Resolve must be called from a SequencedTaskRunner context";
82 CHECK(resolve_fetcher_ == nullptr)
83 << "Can't have concurrent PpdProvider Resolve calls";
84 resolve_done_task_runner_ = base::SequencedTaskRunnerHandle::Get();
stevenjb 2016/11/11 19:26:43 There is a lot of complexity here. I am wondering
Carlson 2016/11/11 23:06:50 I appreciate you taking the time to look carefully
85 disk_task_runner_->PostTask(
86 FROM_HERE, base::Bind(&PpdProviderImpl::ResolveImpl,
87 weak_factory_.GetWeakPtr(), ppd_reference, cb));
stevenjb 2016/11/11 19:26:43 Here we would normally use TaskRunner::PostTaskAnd
Carlson 2016/11/11 23:06:50 I'm not sure that works for what we want here. Or
stevenjb 2016/11/11 23:25:37 See the documentaiton for TaskRunner::PostTaskAndR
88 }
89
90 // Do the work of Resolve on disk_task_runner
91 void ResolveImpl(const Printer::PpdReference& ppd_reference,
92 const PpdProvider::ResolveCallback& cb) {
93 base::ThreadRestrictions::AssertIOAllowed();
94 CHECK(!cb.is_null());
76 CHECK(resolve_sequence_checker_.CalledOnValidSequence()); 95 CHECK(resolve_sequence_checker_.CalledOnValidSequence());
77 CHECK(base::SequencedTaskRunnerHandle::IsSet()) 96 CHECK(base::SequencedTaskRunnerHandle::IsSet())
78 << "Resolve must be called from a SequencedTaskRunner context"; 97 << "Resolve must be called from a SequencedTaskRunner context";
79 CHECK(resolve_fetcher_ == nullptr) 98 CHECK(resolve_fetcher_ == nullptr)
80 << "Can't have concurrent PpdProvider Resolve calls"; 99 << "Can't have concurrent PpdProvider Resolve calls";
81 100
82 base::Optional<base::FilePath> tmp = cache_->Find(ppd_reference); 101 base::Optional<base::FilePath> tmp = cache_->Find(ppd_reference);
83 if (tmp) { 102 if (tmp) {
84 // Cache hit. Schedule the callback now and return. 103 // Cache hit. Schedule the callback now and return.
85 base::SequencedTaskRunnerHandle::Get()->PostTask( 104 resolve_done_task_runner_->PostTask(
86 FROM_HERE, base::Bind(cb, PpdProvider::SUCCESS, tmp.value())); 105 FROM_HERE, base::Bind(cb, PpdProvider::SUCCESS, tmp.value()));
stevenjb 2016/11/11 19:26:43 We would need to pass a unique_ptr<FilePath> to th
87 return; 106 return;
88 } 107 }
89 108
90 // We don't have a way to automatically resolve user-supplied PPDs yet. So 109 // 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 110 // 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 111 // 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 112 // 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 113 // probably means the quirks server one doesn't work for some reason, so we
95 // shouldn't silently use it. 114 // shouldn't silently use it.
96 if (!ppd_reference.user_supplied_ppd_url.empty()) { 115 if (!ppd_reference.user_supplied_ppd_url.empty()) {
97 base::SequencedTaskRunnerHandle::Get()->PostTask( 116 resolve_done_task_runner_->PostTask(
98 FROM_HERE, base::Bind(cb, PpdProvider::NOT_FOUND, base::FilePath())); 117 FROM_HERE, base::Bind(cb, PpdProvider::NOT_FOUND, base::FilePath()));
stevenjb 2016/11/11 19:26:44 This would return PpdProvider::NOT_FOUND.
99 return; 118 return;
100 } 119 }
101 120
stevenjb 2016/11/11 19:26:43 It looks like the rest of this can be safely calle
102 resolve_reference_ = ppd_reference; 121 resolve_reference_ = ppd_reference;
103 resolve_done_callback_ = cb; 122 resolve_done_callback_ = cb;
104 123
105 resolve_fetcher_ = 124 resolve_fetcher_ =
106 net::URLFetcher::Create(GetQuirksServerPpdLookupURL(ppd_reference), 125 net::URLFetcher::Create(GetQuirksServerPpdLookupURL(ppd_reference),
107 net::URLFetcher::GET, &forwarding_delegate_); 126 net::URLFetcher::GET, &forwarding_delegate_);
stevenjb 2016/11/11 19:26:43 Here, instead of using a forwarding_delegate_ memb
Carlson 2016/11/11 23:06:50 I spent a while going down this path (because it d
stevenjb 2016/11/11 23:25:37 So, for now at least, we can continue to have a si
108 resolve_fetcher_->SetRequestContext(url_context_getter_.get()); 127 resolve_fetcher_->SetRequestContext(url_context_getter_.get());
109 resolve_fetcher_->SetLoadFlags( 128 resolve_fetcher_->SetLoadFlags(
110 net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE | 129 net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE |
111 net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES | 130 net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES |
112 net::LOAD_DO_NOT_SEND_AUTH_DATA); 131 net::LOAD_DO_NOT_SEND_AUTH_DATA);
113 resolve_fetcher_->Start(); 132 resolve_fetcher_->Start();
114 }; 133 }
115 134
116 void AbortResolve() override { 135 void AbortResolve() override {
117 // UrlFetcher guarantees that when the object has been destroyed, no further 136 // UrlFetcher guarantees that when the object has been destroyed, no further
118 // callbacks will occur. 137 // callbacks will occur.
119 resolve_fetcher_.reset(); 138 resolve_fetcher_.reset();
139 resolve_done_task_runner_ = nullptr;
120 } 140 }
121 141
122 void QueryAvailable(const QueryAvailableCallback& cb) override { 142 void QueryAvailable(const QueryAvailableCallback& cb) override {
123 CHECK(!cb.is_null()); 143 CHECK(!cb.is_null());
124 CHECK(query_sequence_checker_.CalledOnValidSequence()); 144 CHECK(query_fetcher_ == nullptr)
145 << "Can't have concurrent PpdProvider QueryAvailable() calls";
125 CHECK(base::SequencedTaskRunnerHandle::IsSet()) 146 CHECK(base::SequencedTaskRunnerHandle::IsSet())
126 << "QueryAvailable() must be called from a SequencedTaskRunner context"; 147 << "QueryAvailable() must be called from a SequencedTaskRunner context";
127 CHECK(query_fetcher_ == nullptr) 148 query_done_task_runner_ = base::SequencedTaskRunnerHandle::Get();
128 << "Can't have concurrent PpdProvider QueryAvailable() calls"; 149 disk_task_runner_->PostTask(FROM_HERE,
150 base::Bind(&PpdProviderImpl::QueryAvailableImpl,
151 weak_factory_.GetWeakPtr(), cb));
152 }
153
154 void QueryAvailableImpl(const QueryAvailableCallback& cb) {
155 base::ThreadRestrictions::AssertIOAllowed();
156 CHECK(query_sequence_checker_.CalledOnValidSequence());
129 157
130 base::Optional<PpdProvider::AvailablePrintersMap> result = 158 base::Optional<PpdProvider::AvailablePrintersMap> result =
131 cache_->FindAvailablePrinters(); 159 cache_->FindAvailablePrinters();
132 if (result) { 160 if (result) {
133 // Satisfy from cache. 161 // Satisfy from cache.
134 base::SequencedTaskRunnerHandle::Get()->PostTask( 162 query_done_task_runner_->PostTask(
135 FROM_HERE, base::Bind(cb, PpdProvider::SUCCESS, result.value())); 163 FROM_HERE, base::Bind(cb, PpdProvider::SUCCESS, result.value()));
136 return; 164 return;
137 } 165 }
138 // Not in the cache, ask QuirksServer. 166 // Not in the cache, ask QuirksServer.
139 query_done_callback_ = cb; 167 query_done_callback_ = cb;
140 168
141 query_fetcher_ = 169 query_fetcher_ =
142 net::URLFetcher::Create(GetQuirksServerPpdListURL(), 170 net::URLFetcher::Create(GetQuirksServerPpdListURL(),
143 net::URLFetcher::GET, &forwarding_delegate_); 171 net::URLFetcher::GET, &forwarding_delegate_);
144 query_fetcher_->SetRequestContext(url_context_getter_.get()); 172 query_fetcher_->SetRequestContext(url_context_getter_.get());
145 query_fetcher_->SetLoadFlags( 173 query_fetcher_->SetLoadFlags(
146 net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE | 174 net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE |
147 net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES | 175 net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES |
148 net::LOAD_DO_NOT_SEND_AUTH_DATA); 176 net::LOAD_DO_NOT_SEND_AUTH_DATA);
149 query_fetcher_->Start(); 177 query_fetcher_->Start();
150 } 178 }
151 179
152 void AbortQueryAvailable() override { 180 void AbortQueryAvailable() override {
153 // UrlFetcher guarantees that when the object has been destroyed, no further 181 // UrlFetcher guarantees that when the object has been destroyed, no further
154 // callbacks will occur. 182 // callbacks will occur.
155 query_fetcher_.reset(); 183 query_fetcher_.reset();
184 query_done_task_runner_ = nullptr;
156 } 185 }
157 186
158 bool CachePpd(const Printer::PpdReference& ppd_reference, 187 bool CachePpd(const Printer::PpdReference& ppd_reference,
159 const base::FilePath& ppd_path) override { 188 const base::FilePath& ppd_path) override {
160 std::string buf; 189 std::string buf;
161 if (!base::ReadFileToStringWithMaxSize(ppd_path, &buf, 190 if (!base::ReadFileToStringWithMaxSize(ppd_path, &buf,
162 options_.max_ppd_contents_size_)) { 191 options_.max_ppd_contents_size_)) {
163 return false; 192 return false;
164 } 193 }
165 return static_cast<bool>(cache_->Store(ppd_reference, buf)); 194 return static_cast<bool>(cache_->Store(ppd_reference, buf));
166 } 195 }
167 196
168 // Route to the proper fetch complete handler based on which fetcher caused 197 // Route to the proper fetch complete handler based on which fetcher caused
169 // it. 198 // it.
170 void OnURLFetchComplete(const net::URLFetcher* fetcher) { 199 void OnURLFetchComplete(const net::URLFetcher* fetcher) {
171 if (fetcher == resolve_fetcher_.get()) { 200 if (fetcher == resolve_fetcher_.get()) {
172 OnResolveFetchComplete(); 201 OnResolveFetchComplete();
173 } else if (fetcher == query_fetcher_.get()) { 202 } else if (fetcher == query_fetcher_.get()) {
174 OnQueryAvailableFetchComplete(); 203 OnQueryAvailableFetchComplete();
175 } else { 204 } else {
176 NOTREACHED() << "Unknown fetcher completed."; 205 NOTREACHED() << "Unknown fetcher completed.";
177 } 206 }
178 } 207 }
179 208
180 private: 209 private:
181 // Called on the same thread as Resolve() when the fetcher completes its 210 // Called on the same thread as Resolve() when the fetcher completes its
182 // fetch. 211 // fetch.
183 void OnResolveFetchComplete() { 212 void OnResolveFetchComplete() {
184 CHECK(resolve_sequence_checker_.CalledOnValidSequence()); 213 CHECK(resolve_sequence_checker_.CalledOnValidSequence());
185 // Scope the allocated |resolve_fetcher_| into this function so we clean it 214 // Scope the allocated |resolve_fetcher_| and |resolve_done_task_runner_|
186 // up when we're done here instead of leaving it around until the next 215 // into this function so we clean it up when we're done here instead of
187 // Resolve() call. 216 // leaving it around until the next Resolve() call.
188 auto fetcher = std::move(resolve_fetcher_); 217 auto task_runner(std::move(resolve_done_task_runner_));
218 auto fetcher(std::move(resolve_fetcher_));
189 std::string contents; 219 std::string contents;
190 if (!ValidateAndGetResponseAsString(*fetcher, &contents)) { 220 if (!ValidateAndGetResponseAsString(*fetcher, &contents)) {
191 // Something went wrong with the fetch. 221 // Something went wrong with the fetch.
192 resolve_done_callback_.Run(PpdProvider::SERVER_ERROR, base::FilePath()); 222 task_runner->PostTask(
223 FROM_HERE, base::Bind(resolve_done_callback_,
224 PpdProvider::SERVER_ERROR, base::FilePath()));
193 return; 225 return;
194 } 226 }
195 227
196 auto dict = base::DictionaryValue::From(base::JSONReader::Read(contents)); 228 auto dict = base::DictionaryValue::From(base::JSONReader::Read(contents));
197 if (dict == nullptr) { 229 if (dict == nullptr) {
198 resolve_done_callback_.Run(PpdProvider::SERVER_ERROR, base::FilePath()); 230 task_runner->PostTask(
231 FROM_HERE, base::Bind(resolve_done_callback_,
232 PpdProvider::SERVER_ERROR, base::FilePath()));
199 return; 233 return;
200 } 234 }
201 std::string ppd_contents; 235 std::string ppd_contents;
202 std::string last_updated_time_string; 236 std::string last_updated_time_string;
203 uint64_t last_updated_time; 237 uint64_t last_updated_time;
204 if (!(dict->GetString(kJSONPPDKey, &ppd_contents) && 238 if (!(dict->GetString(kJSONPPDKey, &ppd_contents) &&
205 dict->GetString(kJSONLastUpdatedKey, &last_updated_time_string) && 239 dict->GetString(kJSONLastUpdatedKey, &last_updated_time_string) &&
206 base::StringToUint64(last_updated_time_string, &last_updated_time))) { 240 base::StringToUint64(last_updated_time_string, &last_updated_time))) {
207 // Malformed response. TODO(justincarlson) - LOG something here? 241 // Malformed response. TODO(justincarlson) - LOG something here?
208 resolve_done_callback_.Run(PpdProvider::SERVER_ERROR, base::FilePath()); 242 task_runner->PostTask(
243 FROM_HERE, base::Bind(resolve_done_callback_,
244 PpdProvider::SERVER_ERROR, base::FilePath()));
209 return; 245 return;
210 } 246 }
211 247
212 if (ppd_contents.size() > options_.max_ppd_contents_size_) { 248 if (ppd_contents.size() > options_.max_ppd_contents_size_) {
213 // PPD is too big. 249 // PPD is too big.
214 // 250 //
215 // Note -- if we ever add shared-ppd-sourcing, e.g. we may serve a ppd to 251 // 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 252 // 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 253 // 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 254 // compress 1GBs of zeros into a 900kb file and see what cups does when it
219 // tries to expand that...) 255 // tries to expand that...)
220 resolve_done_callback_.Run(PpdProvider::SERVER_ERROR, base::FilePath()); 256 resolve_done_callback_.Run(PpdProvider::SERVER_ERROR, base::FilePath());
221 return; 257 return;
222 } 258 }
223 259
224 auto ppd_file = cache_->Store(resolve_reference_, ppd_contents); 260 auto ppd_file = cache_->Store(resolve_reference_, ppd_contents);
225 if (!ppd_file) { 261 if (!ppd_file) {
226 // Failed to store. 262 // Failed to store.
227 resolve_done_callback_.Run(PpdProvider::INTERNAL_ERROR, base::FilePath()); 263 task_runner->PostTask(
264 FROM_HERE, base::Bind(resolve_done_callback_,
265 PpdProvider::INTERNAL_ERROR, base::FilePath()));
228 return; 266 return;
229 } 267 }
230 resolve_done_callback_.Run(PpdProvider::SUCCESS, ppd_file.value()); 268 task_runner->PostTask(
269 FROM_HERE, base::Bind(resolve_done_callback_, PpdProvider::SUCCESS,
270 ppd_file.value()));
231 } 271 }
232 272
233 // Called on the same thread as QueryAvailable() when the fetcher completes 273 // Called on the same thread as QueryAvailable() when the fetcher completes
234 // its fetch. 274 // its fetch.
235 void OnQueryAvailableFetchComplete() { 275 void OnQueryAvailableFetchComplete() {
236 CHECK(query_sequence_checker_.CalledOnValidSequence()); 276 CHECK(query_sequence_checker_.CalledOnValidSequence());
237 // Scope the object fetcher into this function so we clean it up when we're 277 // Scope the object fetcher and task_runner into this function so we clean
238 // done here instead of leaving it around until the next QueryAvailable() 278 // it up when we're done here instead of leaving it around until the next
239 // call. 279 // QueryAvailable() call.
240 auto fetcher = std::move(query_fetcher_); 280 auto task_runner(std::move(query_done_task_runner_));
281 auto fetcher(std::move(query_fetcher_));
241 std::string contents; 282 std::string contents;
242 if (!ValidateAndGetResponseAsString(*fetcher, &contents)) { 283 if (!ValidateAndGetResponseAsString(*fetcher, &contents)) {
243 // Something went wrong with the fetch. 284 // Something went wrong with the fetch.
244 query_done_callback_.Run(PpdProvider::SERVER_ERROR, 285 task_runner->PostTask(
245 AvailablePrintersMap()); 286 FROM_HERE, base::Bind(query_done_callback_, PpdProvider::SERVER_ERROR,
287 AvailablePrintersMap()));
246 return; 288 return;
247 } 289 }
248 290
249 // The server gives us JSON in the form of a list of (manufacturer, list of 291 // The server gives us JSON in the form of a list of (manufacturer, list of
250 // models) tuples. 292 // models) tuples.
251 auto top_dict = 293 auto top_dict =
252 base::DictionaryValue::From(base::JSONReader::Read(contents)); 294 base::DictionaryValue::From(base::JSONReader::Read(contents));
253 const base::ListValue* top_list; 295 const base::ListValue* top_list;
254 if (top_dict == nullptr || !top_dict->GetList(kJSONTopListKey, &top_list)) { 296 if (top_dict == nullptr || !top_dict->GetList(kJSONTopListKey, &top_list)) {
255 LOG(ERROR) << "Malformed response from quirks server"; 297 LOG(ERROR) << "Malformed response from quirks server";
256 query_done_callback_.Run(PpdProvider::SERVER_ERROR, 298 task_runner->PostTask(
257 PpdProvider::AvailablePrintersMap()); 299 FROM_HERE, base::Bind(query_done_callback_, PpdProvider::SERVER_ERROR,
300 AvailablePrintersMap()));
258 return; 301 return;
259 } 302 }
260 303
261 PpdProvider::AvailablePrintersMap result; 304 PpdProvider::AvailablePrintersMap result;
262 for (const std::unique_ptr<base::Value>& entry : *top_list) { 305 for (const std::unique_ptr<base::Value>& entry : *top_list) {
263 base::DictionaryValue* dict; 306 base::DictionaryValue* dict;
264 std::string manufacturer; 307 std::string manufacturer;
265 std::string model; 308 std::string model;
266 base::ListValue* model_list; 309 base::ListValue* model_list;
267 if (!entry->GetAsDictionary(&dict) || 310 if (!entry->GetAsDictionary(&dict) ||
268 !dict->GetString(kJSONManufacturer, &manufacturer) || 311 !dict->GetString(kJSONManufacturer, &manufacturer) ||
269 !dict->GetList(kJSONModelList, &model_list)) { 312 !dict->GetList(kJSONModelList, &model_list)) {
270 LOG(ERROR) << "Unexpected contents in quirks server printer list."; 313 LOG(ERROR) << "Unexpected contents in quirks server printer list.";
271 // Just skip this entry instead of aborting the whole thing. 314 // Just skip this entry instead of aborting the whole thing.
272 continue; 315 continue;
273 } 316 }
274 317
275 std::vector<std::string>& dest = result[manufacturer]; 318 std::vector<std::string>& dest = result[manufacturer];
276 for (const std::unique_ptr<base::Value>& model_value : *model_list) { 319 for (const std::unique_ptr<base::Value>& model_value : *model_list) {
277 if (model_value->GetAsString(&model)) { 320 if (model_value->GetAsString(&model)) {
278 dest.push_back(model); 321 dest.push_back(model);
279 } else { 322 } else {
280 LOG(ERROR) << "Skipping unknown model for manufacturer " 323 LOG(ERROR) << "Skipping unknown model for manufacturer "
281 << manufacturer; 324 << manufacturer;
282 } 325 }
283 } 326 }
284 } 327 }
328
285 if (!result.empty()) { 329 if (!result.empty()) {
286 cache_->StoreAvailablePrinters(result); 330 cache_->StoreAvailablePrinters(result);
287 } else { 331 } else {
288 // An empty map means something is probably wrong; if we cache this map, 332 // An empty map means something is probably wrong; if we cache this map,
289 // we'll have an empty map until the cache expires. So complain and 333 // we'll have an empty map until the cache expires. So complain and
290 // refuse to cache. 334 // refuse to cache.
291 LOG(ERROR) << "Available printers map is unexpectedly empty. Refusing " 335 LOG(ERROR) << "Available printers map is unexpectedly empty. Refusing "
292 "to cache this."; 336 "to cache this.";
293 } 337 }
294 query_done_callback_.Run(PpdProvider::SUCCESS, result); 338 task_runner->PostTask(FROM_HERE, base::Bind(query_done_callback_,
339 PpdProvider::SUCCESS, result));
295 } 340 }
296 341
297 // Generate a url to look up a manufacturer/model from the quirks server 342 // Generate a url to look up a manufacturer/model from the quirks server
298 GURL GetQuirksServerPpdLookupURL( 343 GURL GetQuirksServerPpdLookupURL(
299 const Printer::PpdReference& ppd_reference) const { 344 const Printer::PpdReference& ppd_reference) const {
300 return GURL(base::StringPrintf( 345 return GURL(base::StringPrintf(
301 "https://%s/v2/printer/manufacturers/%s/models/%s?key=%s", 346 "https://%s/v2/printer/manufacturers/%s/models/%s?key=%s",
302 options_.quirks_server.c_str(), 347 options_.quirks_server.c_str(),
303 ppd_reference.effective_manufacturer.c_str(), 348 ppd_reference.effective_manufacturer.c_str(),
304 ppd_reference.effective_model.c_str(), api_key_.c_str())); 349 ppd_reference.effective_model.c_str(), api_key_.c_str()));
(...skipping 14 matching lines...) Expand all
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. 371 // Reference we're currently trying to resolve.
327 Printer::PpdReference resolve_reference_; 372 Printer::PpdReference resolve_reference_;
328 373
374 // TaskRunner on which to invoke the Resolve callback;
375 scoped_refptr<base::SequencedTaskRunner> resolve_done_task_runner_;
376
329 // Callback to invoke on completion. 377 // Callback to invoke on completion.
330 PpdProvider::ResolveCallback resolve_done_callback_; 378 PpdProvider::ResolveCallback resolve_done_callback_;
331 379
332 // Check that Resolve() and its callback are sequenced appropriately. 380 // Check that Resolve() and its callback are sequenced appropriately.
333 base::SequenceChecker resolve_sequence_checker_; 381 base::SequenceChecker resolve_sequence_checker_;
334 382
335 // Fetcher for the current call, if any. 383 // Fetcher for the current call, if any. resolve_fetcher_ is null if there
384 // is no running Resolve().
336 std::unique_ptr<net::URLFetcher> resolve_fetcher_; 385 std::unique_ptr<net::URLFetcher> resolve_fetcher_;
337 386
338 // State held across a QueryAvailable() call. 387 // State held across a QueryAvailable() call.
339 388
340 // Callback to invoke on completion. 389 // Callback to invoke on completion.
341 PpdProvider::QueryAvailableCallback query_done_callback_; 390 PpdProvider::QueryAvailableCallback query_done_callback_;
342 391
392 // TaskRunner on which to invoke the Query Available callback;
393 scoped_refptr<base::SequencedTaskRunner> query_done_task_runner_;
394
343 // Check that QueryAvailable() and its callback are sequenced appropriately. 395 // Check that QueryAvailable() and its callback are sequenced appropriately.
344 base::SequenceChecker query_sequence_checker_; 396 base::SequenceChecker query_sequence_checker_;
345 397
346 // Fetcher for the current call, if any. 398 // Fetcher for the current call, if any.
347 std::unique_ptr<net::URLFetcher> query_fetcher_; 399 std::unique_ptr<net::URLFetcher> query_fetcher_;
348 400
349 // Common state. 401 // Common state.
350 402
351 // API key for accessing quirks server. 403 // API key for accessing quirks server.
352 const std::string api_key_; 404 const std::string api_key_;
353 405
354 ForwardingURLFetcherDelegate forwarding_delegate_; 406 ForwardingURLFetcherDelegate forwarding_delegate_;
355 scoped_refptr<net::URLRequestContextGetter> url_context_getter_; 407 scoped_refptr<net::URLRequestContextGetter> url_context_getter_;
408 scoped_refptr<base::SequencedTaskRunner> disk_task_runner_;
356 std::unique_ptr<PpdCache> cache_; 409 std::unique_ptr<PpdCache> cache_;
357 410
358 // Construction-time options, immutable. 411 // Construction-time options, immutable.
359 const PpdProvider::Options options_; 412 const PpdProvider::Options options_;
413
414 base::WeakPtrFactory<PpdProviderImpl> weak_factory_;
360 }; 415 };
361 416
362 void ForwardingURLFetcherDelegate::OnURLFetchComplete( 417 void ForwardingURLFetcherDelegate::OnURLFetchComplete(
363 const net::URLFetcher* source) { 418 const net::URLFetcher* source) {
364 owner_->OnURLFetchComplete(source); 419 owner_->OnURLFetchComplete(source);
365 } 420 }
366 421
367 } // namespace 422 } // namespace
368 423
369 // static 424 // static
370 std::unique_ptr<PpdProvider> PpdProvider::Create( 425 std::unique_ptr<PpdProvider> PpdProvider::Create(
371 const std::string& api_key, 426 const std::string& api_key,
372 scoped_refptr<net::URLRequestContextGetter> url_context_getter, 427 scoped_refptr<net::URLRequestContextGetter> url_context_getter,
428 scoped_refptr<base::SequencedTaskRunner> disk_task_runner,
373 std::unique_ptr<PpdCache> cache, 429 std::unique_ptr<PpdCache> cache,
374 const PpdProvider::Options& options) { 430 const PpdProvider::Options& options) {
375 return base::MakeUnique<PpdProviderImpl>(api_key, url_context_getter, 431 return base::MakeUnique<PpdProviderImpl>(
376 std::move(cache), options); 432 api_key, url_context_getter, disk_task_runner, std::move(cache), options);
377 } 433 }
378 434
379 } // namespace printing 435 } // namespace printing
380 } // namespace chromeos 436 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698