blob: 91292d629e0999fdfebcf8e307367b51708c652e [file] [log] [blame]
// 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