1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "components/plugins/renderer/mobile_youtube_plugin.h" 6 7 #include "base/bind.h" 8 #include "base/bind_helpers.h" 9 #include "base/strings/string_piece.h" 10 #include "base/strings/string_util.h" 11 #include "base/values.h" 12 #include "content/public/common/content_constants.h" 13 #include "content/public/renderer/render_frame.h" 14 #include "gin/handle.h" 15 #include "gin/object_template_builder.h" 16 #include "third_party/WebKit/public/web/WebFrame.h" 17 #include "third_party/WebKit/public/web/WebKit.h" 18 #include "ui/base/webui/jstemplate_builder.h" 19 20 using blink::WebFrame; 21 using blink::WebPlugin; 22 using blink::WebURLRequest; 23 24 const char* const kSlashVSlash = "/v/"; 25 const char* const kSlashESlash = "/e/"; 26 27 namespace { 28 29 std::string GetYoutubeVideoId(const blink::WebPluginParams& params) { 30 GURL url(params.url); 31 std::string video_id = url.path().substr(strlen(kSlashVSlash)); 32 33 // Extract just the video id 34 size_t video_id_end = video_id.find('&'); 35 if (video_id_end != std::string::npos) 36 video_id = video_id.substr(0, video_id_end); 37 return video_id; 38 } 39 40 std::string HtmlData(const blink::WebPluginParams& params, 41 base::StringPiece template_html) { 42 base::DictionaryValue values; 43 values.SetString("video_id", GetYoutubeVideoId(params)); 44 return webui::GetI18nTemplateHtml(template_html, &values); 45 } 46 47 bool IsValidYouTubeVideo(const std::string& path) { 48 unsigned len = strlen(kSlashVSlash); 49 50 // check for more than just /v/ or /e/. 51 if (path.length() <= len) 52 return false; 53 54 std::string str = base::StringToLowerASCII(path); 55 // Youtube flash url can start with /v/ or /e/. 56 if (strncmp(str.data(), kSlashVSlash, len) != 0 && 57 strncmp(str.data(), kSlashESlash, len) != 0) 58 return false; 59 60 // Start after /v/ 61 for (unsigned i = len; i < path.length(); i++) { 62 char c = str[i]; 63 if (isalpha(c) || isdigit(c) || c == '_' || c == '-') 64 continue; 65 // The url can have more parameters such as &hl=en after the video id. 66 // Once we start seeing extra parameters we can return true. 67 return c == '&' && i > len; 68 } 69 return true; 70 } 71 72 } // namespace 73 74 namespace plugins { 75 76 MobileYouTubePlugin::MobileYouTubePlugin(content::RenderFrame* render_frame, 77 blink::WebLocalFrame* frame, 78 const blink::WebPluginParams& params, 79 base::StringPiece& template_html, 80 GURL placeholderDataUrl) 81 : PluginPlaceholder(render_frame, 82 frame, 83 params, 84 HtmlData(params, template_html), 85 placeholderDataUrl) {} 86 87 MobileYouTubePlugin::~MobileYouTubePlugin() {} 88 89 // static 90 bool MobileYouTubePlugin::IsYouTubeURL(const GURL& url, 91 const std::string& mime_type) { 92 std::string host = url.host(); 93 bool is_youtube = EndsWith(host, "youtube.com", true) || 94 EndsWith(host, "youtube-nocookie.com", true); 95 96 return is_youtube && IsValidYouTubeVideo(url.path()) && 97 LowerCaseEqualsASCII(mime_type, content::kFlashPluginSwfMimeType); 98 } 99 100 void MobileYouTubePlugin::OpenYoutubeUrlCallback() { 101 std::string youtube("vnd.youtube:"); 102 GURL url(youtube.append(GetYoutubeVideoId(GetPluginParams()))); 103 WebURLRequest request; 104 request.initialize(); 105 request.setURL(url); 106 render_frame()->LoadURLExternally( 107 GetFrame(), request, blink::WebNavigationPolicyNewForegroundTab); 108 } 109 110 void MobileYouTubePlugin::BindWebFrame(WebFrame* frame) { 111 v8::Isolate* isolate = blink::mainThreadIsolate(); 112 v8::HandleScope handle_scope(isolate); 113 v8::Handle<v8::Context> context = frame->mainWorldScriptContext(); 114 DCHECK(!context.IsEmpty()); 115 116 v8::Context::Scope context_scope(context); 117 v8::Handle<v8::Object> global = context->Global(); 118 global->Set(gin::StringToV8(isolate, "plugin"), 119 gin::CreateHandle(isolate, this).ToV8()); 120 } 121 122 gin::ObjectTemplateBuilder MobileYouTubePlugin::GetObjectTemplateBuilder( 123 v8::Isolate* isolate) { 124 return PluginPlaceholder::GetObjectTemplateBuilder(isolate) 125 .SetMethod("openYoutubeURL", &MobileYouTubePlugin::OpenYoutubeUrlCallback); 126 } 127 128 } // namespace plugins 129