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 "third_party/WebKit/public/web/WebFrame.h" 15 #include "ui/base/webui/jstemplate_builder.h" 16 17 using blink::WebFrame; 18 using blink::WebPlugin; 19 using blink::WebURLRequest; 20 21 const char* const kSlashVSlash = "/v/"; 22 const char* const kSlashESlash = "/e/"; 23 24 namespace { 25 26 std::string GetYoutubeVideoId(const blink::WebPluginParams& params) { 27 GURL url(params.url); 28 std::string video_id = url.path().substr(strlen(kSlashVSlash)); 29 30 // Extract just the video id 31 size_t video_id_end = video_id.find('&'); 32 if (video_id_end != std::string::npos) 33 video_id = video_id.substr(0, video_id_end); 34 return video_id; 35 } 36 37 std::string HtmlData(const blink::WebPluginParams& params, 38 base::StringPiece template_html) { 39 base::DictionaryValue values; 40 values.SetString("video_id", GetYoutubeVideoId(params)); 41 return webui::GetI18nTemplateHtml(template_html, &values); 42 } 43 44 bool IsValidYouTubeVideo(const std::string& path) { 45 unsigned len = strlen(kSlashVSlash); 46 47 // check for more than just /v/ or /e/. 48 if (path.length() <= len) 49 return false; 50 51 std::string str = StringToLowerASCII(path); 52 // Youtube flash url can start with /v/ or /e/. 53 if (strncmp(str.data(), kSlashVSlash, len) != 0 && 54 strncmp(str.data(), kSlashESlash, len) != 0) 55 return false; 56 57 // Start after /v/ 58 for (unsigned i = len; i < path.length(); i++) { 59 char c = str[i]; 60 if (isalpha(c) || isdigit(c) || c == '_' || c == '-') 61 continue; 62 // The url can have more parameters such as &hl=en after the video id. 63 // Once we start seeing extra parameters we can return true. 64 return c == '&' && i > len; 65 } 66 return true; 67 } 68 69 } // namespace 70 71 namespace plugins { 72 73 MobileYouTubePlugin::MobileYouTubePlugin(content::RenderFrame* render_frame, 74 blink::WebFrame* frame, 75 const blink::WebPluginParams& params, 76 base::StringPiece& template_html, 77 GURL placeholderDataUrl) 78 : PluginPlaceholder(render_frame, 79 frame, 80 params, 81 HtmlData(params, template_html), 82 placeholderDataUrl) {} 83 84 // static 85 bool MobileYouTubePlugin::IsYouTubeURL(const GURL& url, 86 const std::string& mime_type) { 87 std::string host = url.host(); 88 bool is_youtube = EndsWith(host, "youtube.com", true) || 89 EndsWith(host, "youtube-nocookie.com", true); 90 91 return is_youtube && IsValidYouTubeVideo(url.path()) && 92 LowerCaseEqualsASCII(mime_type, content::kFlashPluginSwfMimeType); 93 } 94 95 void MobileYouTubePlugin::OpenYoutubeUrlCallback( 96 const webkit_glue::CppArgumentList& args, 97 webkit_glue::CppVariant* result) { 98 std::string youtube("vnd.youtube:"); 99 GURL url(youtube.append(GetYoutubeVideoId(GetPluginParams()))); 100 WebURLRequest request; 101 request.initialize(); 102 request.setURL(url); 103 render_frame()->LoadURLExternally( 104 GetFrame(), request, blink::WebNavigationPolicyNewForegroundTab); 105 } 106 void MobileYouTubePlugin::BindWebFrame(WebFrame* frame) { 107 PluginPlaceholder::BindWebFrame(frame); 108 BindCallback("openYoutubeURL", 109 base::Bind(&MobileYouTubePlugin::OpenYoutubeUrlCallback, 110 base::Unretained(this))); 111 } 112 113 } // namespace plugins 114