| Index: chrome/renderer/extensions/chrome_webstore_bindings.cc
|
| diff --git a/chrome/renderer/extensions/chrome_webstore_bindings.cc b/chrome/renderer/extensions/chrome_webstore_bindings.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9c58d15c1b8c4519e188af813f63cfcaa5dfef11
|
| --- /dev/null
|
| +++ b/chrome/renderer/extensions/chrome_webstore_bindings.cc
|
| @@ -0,0 +1,168 @@
|
| +// Copyright (c) 2011 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/renderer/extensions/chrome_webstore_bindings.h"
|
| +
|
| +#include "base/string_util.h"
|
| +#include "chrome/common/extensions/extension.h"
|
| +#include "chrome/renderer/extensions/bindings_utils.h"
|
| +#include "chrome/renderer/extensions/extension_helper.h"
|
| +#include "content/renderer/render_view.h"
|
| +#include "googleurl/src/gurl.h"
|
| +#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
|
| +#include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h"
|
| +#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
|
| +#include "third_party/WebKit/Source/WebKit/chromium/public/WebNode.h"
|
| +#include "third_party/WebKit/Source/WebKit/chromium/public/WebNodeList.h"
|
| +#include "v8/include/v8.h"
|
| +
|
| +using WebKit::WebDocument;
|
| +using WebKit::WebElement;
|
| +using WebKit::WebFrame;
|
| +using WebKit::WebNode;
|
| +using WebKit::WebNodeList;
|
| +
|
| +const char kWebstoreLinkRelation[] = "chrome-webstore-item";
|
| +
|
| +const char kNotInTopFrameError[] =
|
| + "Chrome Web Store installations can only be started by the top frame.";
|
| +const char kNotUserGestureError[] =
|
| + "Chrome Web Store installations can only be initated by a user gesture.";
|
| +const char kNoWebstoreItemLinkFoundError[] =
|
| + "No Chrome Web Store item link found.";
|
| +const char kInvalidWebstoreItemUrlError[] =
|
| + "Invalid Chrome Web Store item URL.";
|
| +
|
| +namespace extensions_v8 {
|
| +
|
| +static const char* const kWebstoreExtensionName = "v8/ChromeWebstore";
|
| +
|
| +class ChromeWebstoreExtensionWrapper : public v8::Extension {
|
| + public:
|
| + ChromeWebstoreExtensionWrapper() :
|
| + v8::Extension(
|
| + kWebstoreExtensionName,
|
| + "var chrome;"
|
| + "if (!chrome)"
|
| + " chrome = {};"
|
| + "if (!chrome.webstore) {"
|
| + " chrome.webstore = new function() {"
|
| + " native function Install();"
|
| + " this.install = Install;"
|
| + " };"
|
| + "}") {
|
| + }
|
| +
|
| + virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
|
| + v8::Handle<v8::String> name) {
|
| + if (name->Equals(v8::String::New("Install"))) {
|
| + return v8::FunctionTemplate::New(Install);
|
| + } else {
|
| + return v8::Handle<v8::FunctionTemplate>();
|
| + }
|
| + }
|
| +
|
| + static v8::Handle<v8::Value> Install(const v8::Arguments& args) {
|
| + WebFrame* frame = WebFrame::frameForCurrentContext();
|
| + RenderView* render_view = bindings_utils::GetRenderViewForCurrentContext();
|
| + if (frame && render_view) {
|
| + std::string webstore_item_id;
|
| + std::string error;
|
| + if (GetWebstoreItemIdFromFrame(frame, &webstore_item_id, &error)) {
|
| + ExtensionHelper* helper = ExtensionHelper::Get(render_view);
|
| + helper->InlineWebstoreInstall(webstore_item_id);
|
| + } else {
|
| + v8::ThrowException(v8::String::New(error.c_str()));
|
| + }
|
| + }
|
| +
|
| + return v8::Undefined();
|
| + }
|
| +
|
| + private:
|
| + // Extracts a Web Store item ID from a <link rel="chrome-webstore-item"
|
| + // href="https://chrome.google.com/webstore/detail/id"> node found in the
|
| + // frame. On success, true will be returned and the |webstore_item_id|
|
| + // parameter will be populated with the ID. On failure, false will be returned
|
| + // and |error| will be populated with the error.
|
| + static bool GetWebstoreItemIdFromFrame(
|
| + WebFrame* frame, std::string* webstore_item_id, std::string* error) {
|
| + if (frame != frame->top()) {
|
| + *error = kNotInTopFrameError;
|
| + return false;
|
| + }
|
| +
|
| + if (!frame->isProcessingUserGesture()) {
|
| + *error = kNotUserGestureError;
|
| + return false;
|
| + }
|
| +
|
| + WebDocument document = frame->document();
|
| + if (document.isNull()) {
|
| + *error = kNoWebstoreItemLinkFoundError;
|
| + return false;
|
| + }
|
| +
|
| + WebElement head = document.head();
|
| + if (head.isNull()) {
|
| + *error = kNoWebstoreItemLinkFoundError;
|
| + return false;
|
| + }
|
| +
|
| + GURL webstore_base_url =
|
| + GURL(extension_misc::GetWebstoreItemDetailURLPrefix());
|
| + WebNodeList children = head.childNodes();
|
| + for (unsigned i = 0; i < children.length(); ++i) {
|
| + WebNode child = children.item(i);
|
| + if (!child.isElementNode())
|
| + continue;
|
| + WebElement elem = child.to<WebElement>();
|
| +
|
| + if (!elem.hasTagName("link") || !elem.hasAttribute("rel") ||
|
| + !elem.hasAttribute("href"))
|
| + continue;
|
| +
|
| + std::string rel = elem.getAttribute("rel").utf8();
|
| + if (!LowerCaseEqualsASCII(rel, kWebstoreLinkRelation))
|
| + continue;
|
| +
|
| + std::string webstore_url_string(elem.getAttribute("href").utf8());
|
| + GURL webstore_url = GURL(webstore_url_string);
|
| + if (!webstore_url.is_valid()) {
|
| + *error = kInvalidWebstoreItemUrlError;
|
| + return false;
|
| + }
|
| +
|
| + if (webstore_url.scheme() != webstore_base_url.scheme() ||
|
| + webstore_url.host() != webstore_base_url.host() ||
|
| + !StartsWithASCII(
|
| + webstore_url.path(), webstore_base_url.path(), true)) {
|
| + *error = kInvalidWebstoreItemUrlError;
|
| + return false;
|
| + }
|
| +
|
| + std::string candidate_webstore_item_id = webstore_url.path().substr(
|
| + webstore_base_url.path().length());
|
| + std::string reconstructed_webstore_item_url_string =
|
| + extension_misc::GetWebstoreItemDetailURLPrefix() +
|
| + candidate_webstore_item_id;
|
| + if (reconstructed_webstore_item_url_string != webstore_url_string) {
|
| + *error = kInvalidWebstoreItemUrlError;
|
| + return false;
|
| + }
|
| +
|
| + *webstore_item_id = candidate_webstore_item_id;
|
| + return true;
|
| + }
|
| +
|
| + *error = kNoWebstoreItemLinkFoundError;
|
| + return false;
|
| + }
|
| +};
|
| +
|
| +v8::Extension* ChromeWebstoreExtension::Get() {
|
| + return new ChromeWebstoreExtensionWrapper();
|
| +}
|
| +
|
| +} // namespace extensions_v8
|
|
|