Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |