Chromium Code Reviews| 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..01c544ff34be83e50ca37eccb62b70cabcf306d5 |
| --- /dev/null |
| +++ b/chrome/renderer/extensions/chrome_webstore_bindings.cc |
| @@ -0,0 +1,171 @@ |
| +// 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/string16.h" |
|
Aaron Boodman
2011/08/17 04:53:03
I don't see any instance of 'string16' in this fil
Mihai Parparita -not on Chrome
2011/08/17 23:00:16
Removed this and a couple of other unneeded #inclu
|
| +#include "base/string_util.h" |
| +#include "base/utf_string_conversions.h" |
| +#include "base/values.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); |
|
Aaron Boodman
2011/08/17 04:53:03
I don't see this method defined on ExtensionHelper
Mihai Parparita -not on Chrome
2011/08/17 23:00:16
chrome_app_bindings.cc and extension_process_bindi
Aaron Boodman
2011/08/17 23:15:41
Um, ok. I think this changed since I last saw it.
|
| + 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::ChromeStoreItemDetailURLPrefix()); |
| + 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::ChromeStoreItemDetailURLPrefix() + |
| + 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 |