Index: chromeos/printing/ppd_provider.cc |
diff --git a/chromeos/printing/ppd_provider.cc b/chromeos/printing/ppd_provider.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..068a4acbd41e90846ac17f0786d90de931c40548 |
--- /dev/null |
+++ b/chromeos/printing/ppd_provider.cc |
@@ -0,0 +1,193 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
skau
2016/09/17 00:59:59
ppd_provider.h should be included first
https://go
Carlson
2016/10/06 15:56:05
Done.
|
+#include "base/json/json_parser.h" |
+#include "base/memory/ptr_util.h" |
+#include "base/strings/string_number_conversions.h" |
+#include "base/strings/string_util.h" |
+#include "base/time/time.h" |
+#include "base/values.h" |
+#include "chromeos/printing/ppd_cache.h" |
+#include "chromeos/printing/ppd_provider.h" |
+#include "net/base/load_flags.h" |
+#include "net/http/http_status_code.h" |
+#include "net/url_request/url_fetcher.h" |
+#include "net/url_request/url_fetcher_delegate.h" |
+#include "net/url_request/url_request_context_getter.h" |
+#include "url/gurl.h" |
+ |
+using ::base::DictionaryValue; |
+using ::base::Value; |
+using ::net::URLFetcher; |
+using ::net::URLFetcherDelegate; |
+using ::std::string; |
+using ::std::unique_ptr; |
+ |
+namespace chromeos { |
+namespace printing { |
+namespace { |
+ |
+const char* kJSONPPDKey = "compressedPpd"; |
+const char* kJSONLastUpdatedKey = "lastUpdatedTime"; |
+ |
+class PPDProviderImpl; |
+ |
+// URLFetcherDelegate that just forwards the complete callback back to |
+// the PPDProvider that owns the delegate. |
+class ForwardingURLFetcherDelegate : public URLFetcherDelegate { |
+ public: |
+ ForwardingURLFetcherDelegate(PPDProviderImpl* owner) : owner_(owner) {} |
+ ~ForwardingURLFetcherDelegate() override {} |
+ |
+ // URLFetcherDelegate API method. Defined below since we need the |
+ // PPDProviderImpl definition first. |
+ void OnURLFetchComplete(const URLFetcher* source) override; |
+ |
+ private: |
+ // owner of this delegate. |
+ PPDProviderImpl* owner_; |
+}; |
+ |
+// TODO(justincarlson) - Determine what concurrency this class |
+// needs to deal with, particularly around the lifetime of files |
+// in the cache, but also for concurrent Lookups. |
+class PPDProviderImpl : public PPDProvider { |
+ public: |
+ PPDProviderImpl( |
+ scoped_refptr<net::URLRequestContextGetter> url_context_getter, |
+ ::std::unique_ptr<PPDCache> cache, |
+ const PPDProvider::Options& options) |
+ : forwarding_delegate_(this), |
+ url_context_getter_(url_context_getter), |
+ cache_(std::move(cache)), |
+ options_(options) {} |
+ ~PPDProviderImpl() override {} |
+ |
+ void Lookup(const string& manufacturer, |
+ const string& model, |
+ PPDProvider::LookupCallback cb) override { |
+ auto tmp = cache_->Lookup(manufacturer, model); |
+ if (tmp != nullptr) { |
+ // Cache hit. Schedule the callback right now. |
+ url_context_getter_->GetNetworkTaskRunner()->PostTask( |
+ FROM_HERE, base::Bind(cb, PPDProvider::SUCCESS, *tmp)); |
+ return; |
+ } |
+ |
+ done_callback_ = cb; |
+ fetcher_ = net::URLFetcher::Create(GetLookupURL(manufacturer, model), |
+ URLFetcher::GET, &forwarding_delegate_); |
+ fetcher_->SetRequestContext(url_context_getter_.get()); |
+ fetcher_->SetLoadFlags(net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE | |
+ net::LOAD_DO_NOT_SAVE_COOKIES | |
+ net::LOAD_DO_NOT_SEND_COOKIES | |
+ net::LOAD_DO_NOT_SEND_AUTH_DATA); |
+ fetcher_->Start(); |
+ }; |
+ |
+ // Called when the fetcher completes its fetch. |
+ void OnURLFetchComplete() { |
+ // TODO(justincarlson) -- What does URLFetcher do with redirects? Does it |
+ // automatically resolve them, or do we need to do something else? |
+ string contents; |
+ if ((fetcher_->GetStatus().status() != net::URLRequestStatus::SUCCESS) || |
+ (fetcher_->GetResponseCode() != net::HTTP_OK) || |
+ !fetcher_->GetResponseAsString(&contents)) { |
+ // Something went wrong with the fetch. |
+ done_callback_.Run(PPDProvider::SERVER_ERROR, Printer::PPDFile()); |
+ } else { |
+ auto parsed_json = ::base::JSONReader::Read(contents); |
+ DictionaryValue* dict; |
+ if (parsed_json == nullptr || // |
+ parsed_json->GetType() != Value::TYPE_DICTIONARY || // |
skau
2016/09/17 00:59:59
GetAsDictionary implies this check and will fail s
Carlson
2016/10/06 15:56:05
Done.
|
+ !parsed_json->GetAsDictionary(&dict)) { |
+ // Malformed response. TODO(justincarlson) - LOG something here? |
+ done_callback_.Run(PPDProvider::SERVER_ERROR, Printer::PPDFile()); |
+ return; |
+ } |
+ std::string compressed_ppd_contents; |
+ std::string last_updated_time_string; |
+ uint64_t last_updated_time; |
+ if (!(dict->GetString(kJSONPPDKey, &compressed_ppd_contents) && |
+ dict->GetString(kJSONLastUpdatedKey, &last_updated_time_string) && |
+ ::base::StringToUint64(last_updated_time_string, |
+ &last_updated_time))) { |
+ // Malformed response. TODO(justincarlson) - LOG something here? |
+ done_callback_.Run(PPDProvider::SERVER_ERROR, Printer::PPDFile()); |
+ return; |
+ } |
+ auto ppd_file = |
+ cache_->Store(manufacturer_, model_, base::Time::Now().ToJavaTime(), |
+ last_updated_time, compressed_ppd_contents); |
+ } |
+ done_callback_.Run(PPDProvider::SUCCESS, Printer::PPDFile()); |
+ } |
+ |
+ private: |
+ // Generate a url to look up a manufacturer/model from the quirks server |
+ GURL GetLookupURL(const string& manufacturer, const string& model) const { |
+ return GURL(::base::JoinString( |
+ { |
+ "https://", // |
+ options_.quirks_server, // |
+ "/v2/printer/manufacturers/", // |
+ manufacturer, // |
+ "/models/", // |
+ model, // |
+ "?key=", // |
+ options_.api_key // |
+ }, |
+ "")); |
+ } |
+ |
+ // Manufacturer/model strings for the current lookup. |
+ std::string manufacturer_; |
+ std::string model_; |
+ |
+ ForwardingURLFetcherDelegate forwarding_delegate_; |
+ scoped_refptr<net::URLRequestContextGetter> url_context_getter_; |
+ unique_ptr<PPDCache> cache_; |
+ |
+ // Construction-time options, immutable. |
+ const PPDProvider::Options options_; |
+ unique_ptr<::net::URLFetcher> fetcher_; |
+ PPDProvider::LookupCallback done_callback_; |
+}; |
+ |
+void ForwardingURLFetcherDelegate::OnURLFetchComplete( |
+ const URLFetcher* source) { |
+ owner_->OnURLFetchComplete(); |
+} |
+ |
+} // namespace |
+ |
+// static |
+PPDProvider::Options PPDProvider::Defaults() { |
+ PPDProvider::Options ret; |
+ ret.quirks_server = "chromeosquirksserver-pa.googleapis.com"; |
+ // TODO(justincarlson) - How do we set a default api key? Can't include |
+ // google_apis/google_api_keys directly. |
+ // ret.api_key = ::google_apis::GetAPIKey(); |
skau
2016/09/17 00:59:59
It'll need to be passed in as it depends on the pl
Carlson
2016/10/06 15:56:05
Done.
|
+ return ret; |
+} |
+ |
+// static |
+unique_ptr<PPDProvider> PPDProvider::Create( |
+ scoped_refptr<net::URLRequestContextGetter> url_context_getter, |
+ unique_ptr<PPDCache> cache, |
+ const PPDProvider::Options& options) { |
+ return ::base::MakeUnique<PPDProviderImpl>(url_context_getter, |
+ std::move(cache), options); |
+} |
+ |
+// static |
+unique_ptr<PPDProvider> PPDProvider::Create( |
+ scoped_refptr<net::URLRequestContextGetter> url_context_getter, |
+ unique_ptr<PPDCache> cache) { |
+ return ::base::MakeUnique<PPDProviderImpl>(url_context_getter, |
+ std::move(cache), Defaults()); |
+} |
+ |
+} // namespace printing |
+} // namespace chromeos |