| // Copyright (c) 2012 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. |
| |
| #include "chrome/browser/extensions/webstore_install_helper.h" |
| |
| #include "base/bind.h" |
| #include "base/values.h" |
| #include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h" |
| #include "components/safe_json_parser/safe_json_parser.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "net/base/load_flags.h" |
| #include "net/url_request/url_request.h" |
| |
| using content::BrowserThread; |
| |
| namespace { |
| |
| const char kImageDecodeError[] = "Image decode failed"; |
| |
| } // namespace |
| |
| namespace extensions { |
| |
| WebstoreInstallHelper::WebstoreInstallHelper( |
| Delegate* delegate, |
| const std::string& id, |
| const std::string& manifest, |
| const GURL& icon_url, |
| net::URLRequestContextGetter* context_getter) |
| : delegate_(delegate), |
| id_(id), |
| manifest_(manifest), |
| icon_url_(icon_url), |
| context_getter_(context_getter), |
| icon_decode_complete_(false), |
| manifest_parse_complete_(false), |
| parse_error_(Delegate::UNKNOWN_ERROR) { |
| } |
| |
| WebstoreInstallHelper::~WebstoreInstallHelper() {} |
| |
| void WebstoreInstallHelper::Start() { |
| CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| // No existing |json_parser_| to avoid unbalanced AddRef(). |
| CHECK(!json_parser_.get()); |
| AddRef(); // Balanced in OnJSONParseSucceeded()/OnJSONParseFailed(). |
| // Use base::Unretained so that base::Bind won't AddRef() on us. Otherwise, |
| // we'll have two callbacks holding references to us, only one of which will |
| // ever be called. |
| json_parser_ = new safe_json_parser::SafeJsonParser( |
| manifest_, |
| base::Bind(&WebstoreInstallHelper::OnJSONParseSucceeded, |
| base::Unretained(this)), |
| base::Bind(&WebstoreInstallHelper::OnJSONParseFailed, |
| base::Unretained(this))); |
| json_parser_->Start(); |
| |
| if (icon_url_.is_empty()) { |
| icon_decode_complete_ = true; |
| } else { |
| // No existing |icon_fetcher_| to avoid unbalanced AddRef(). |
| CHECK(!icon_fetcher_.get()); |
| AddRef(); // Balanced in OnFetchComplete(). |
| icon_fetcher_.reset(new chrome::BitmapFetcher(icon_url_, this)); |
| icon_fetcher_->Init( |
| context_getter_, std::string(), |
| net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE, |
| net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES); |
| icon_fetcher_->Start(); |
| } |
| } |
| |
| void WebstoreInstallHelper::OnFetchComplete(const GURL& url, |
| const SkBitmap* image) { |
| CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| // OnFetchComplete should only be called as icon_fetcher_ delegate to avoid |
| // unbalanced Release(). |
| CHECK(icon_fetcher_.get()); |
| |
| if (image) |
| icon_ = *image; |
| icon_decode_complete_ = true; |
| if (icon_.empty()) { |
| error_ = kImageDecodeError; |
| parse_error_ = Delegate::ICON_ERROR; |
| } |
| icon_fetcher_.reset(); |
| |
| ReportResultsIfComplete(); |
| Release(); // Balanced in Start(). |
| } |
| |
| void WebstoreInstallHelper::OnJSONParseSucceeded( |
| scoped_ptr<base::Value> result) { |
| CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| manifest_parse_complete_ = true; |
| const base::DictionaryValue* value; |
| if (result->GetAsDictionary(&value)) |
| parsed_manifest_.reset(value->DeepCopy()); |
| else |
| parse_error_ = Delegate::MANIFEST_ERROR; |
| |
| ReportResultsIfComplete(); |
| Release(); // Balanced in Start(). |
| } |
| |
| void WebstoreInstallHelper::OnJSONParseFailed( |
| const std::string& error_message) { |
| CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| manifest_parse_complete_ = true; |
| error_ = error_message; |
| parse_error_ = Delegate::MANIFEST_ERROR; |
| ReportResultsIfComplete(); |
| Release(); // Balanced in Start(). |
| } |
| |
| void WebstoreInstallHelper::ReportResultsIfComplete() { |
| CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| if (!icon_decode_complete_ || !manifest_parse_complete_) |
| return; |
| |
| if (error_.empty() && parsed_manifest_) |
| delegate_->OnWebstoreParseSuccess(id_, icon_, parsed_manifest_.release()); |
| else |
| delegate_->OnWebstoreParseFailure(id_, parse_error_, error_); |
| } |
| |
| } // namespace extensions |