Bug 769117 - Rewrite youtube flash embed tags to possibly use HTML5; r=bz r=hsivonen

This commit is contained in:
Kyle Machulis 2016-01-06 00:01:59 -08:00
parent bfe65fa356
commit bcad161069
4 changed files with 80 additions and 18 deletions

View File

@ -103,6 +103,7 @@
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
static const char *kPrefJavaMIME = "plugin.java.mime"; static const char *kPrefJavaMIME = "plugin.java.mime";
static const char *kPrefYoutubeRewrite = "plugins.rewrite_youtube_embeds";
using namespace mozilla; using namespace mozilla;
using namespace mozilla::dom; using namespace mozilla::dom;
@ -714,7 +715,8 @@ nsObjectLoadingContent::nsObjectLoadingContent()
, mActivated(false) , mActivated(false)
, mIsStopping(false) , mIsStopping(false)
, mIsLoading(false) , mIsLoading(false)
, mScriptRequested(false) {} , mScriptRequested(false)
, mRewrittenYoutubeEmbed(false) {}
nsObjectLoadingContent::~nsObjectLoadingContent() nsObjectLoadingContent::~nsObjectLoadingContent()
{ {
@ -1482,7 +1484,7 @@ nsObjectLoadingContent::CheckJavaCodebase()
} }
bool bool
nsObjectLoadingContent::IsYoutubeEmbed() nsObjectLoadingContent::ShouldRewriteYoutubeEmbed(nsIURI* aURI)
{ {
nsCOMPtr<nsIContent> thisContent = nsCOMPtr<nsIContent> thisContent =
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this)); do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
@ -1500,25 +1502,41 @@ nsObjectLoadingContent::IsYoutubeEmbed()
NS_WARNING("Could not get TLD service!"); NS_WARNING("Could not get TLD service!");
return false; return false;
} }
nsAutoCString currentBaseDomain; nsAutoCString currentBaseDomain;
bool ok = NS_SUCCEEDED(tldService->GetBaseDomain(mURI, 0, currentBaseDomain)); bool ok = NS_SUCCEEDED(tldService->GetBaseDomain(aURI, 0, currentBaseDomain));
if (!ok) { if (!ok) {
// Data URIs won't parse correctly, so just fail silently here. // Data URIs (commonly used for things like svg embeds) won't parse
// correctly, so just fail silently here.
return false; return false;
} }
// See if URL is referencing youtube // See if URL is referencing youtube
nsAutoCString domain("youtube.com"); if (!currentBaseDomain.EqualsLiteral("youtube.com")) {
if (!StringEndsWith(domain, currentBaseDomain)) {
return false; return false;
} }
// We should only rewrite URLs with paths starting with "/v/", as we shouldn't
// touch object nodes with "/embed/" urls that already do that right thing.
nsAutoCString path;
aURI->GetPath(path);
if (!StringBeginsWith(path, NS_LITERAL_CSTRING("/v/"))) {
return false;
}
// See if requester is planning on using the JS API. // See if requester is planning on using the JS API.
nsAutoCString uri; nsAutoCString uri;
mURI->GetSpec(uri); aURI->GetSpec(uri);
// Only log urls that are rewritable, e.g. not using enablejsapi=1
if (uri.Find("enablejsapi=1", true, 0, -1) != kNotFound) { if (uri.Find("enablejsapi=1", true, 0, -1) != kNotFound) {
return false; return false;
} }
return true;
// If we've made it this far, we've got a rewritable embed. Log it in
// telemetry.
Telemetry::Accumulate(Telemetry::YOUTUBE_REWRITABLE_EMBED_SEEN, 1);
// Even if node is rewritable, only rewrite if the pref tells us we should.
return Preferences::GetBool(kPrefYoutubeRewrite);
} }
bool bool
@ -1769,6 +1787,7 @@ nsObjectLoadingContent::UpdateObjectParameters(bool aJavaURI)
NS_NOTREACHED("Unrecognized plugin-loading tag"); NS_NOTREACHED("Unrecognized plugin-loading tag");
} }
mRewrittenYoutubeEmbed = false;
// Note that the baseURI changing could affect the newURI, even if uriStr did // Note that the baseURI changing could affect the newURI, even if uriStr did
// not change. // not change.
if (!uriStr.IsEmpty()) { if (!uriStr.IsEmpty()) {
@ -1776,6 +1795,19 @@ nsObjectLoadingContent::UpdateObjectParameters(bool aJavaURI)
uriStr, uriStr,
thisContent->OwnerDoc(), thisContent->OwnerDoc(),
newBaseURI); newBaseURI);
if (ShouldRewriteYoutubeEmbed(newURI)) {
// Switch out video access url formats, which should possibly allow HTML5
// video loading.
uriStr.ReplaceSubstring(NS_LITERAL_STRING("/v/"),
NS_LITERAL_STRING("/embed/"));
rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(newURI),
uriStr,
thisContent->OwnerDoc(),
newBaseURI);
mRewrittenYoutubeEmbed = true;
newMime = NS_LITERAL_CSTRING("text/html");
}
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
NS_TryToSetImmutable(newURI); NS_TryToSetImmutable(newURI);
} else { } else {
@ -1939,9 +1971,9 @@ nsObjectLoadingContent::UpdateObjectParameters(bool aJavaURI)
newType = eType_Null; newType = eType_Null;
newMime.Truncate(); newMime.Truncate();
} else if (newChannel) { } else if (newChannel) {
// If newChannel is set above, we considered it in setting newMime // If newChannel is set above, we considered it in setting newMime
newType = GetTypeOfContent(newMime); newType = GetTypeOfContent(newMime);
LOG(("OBJLC [%p]: Using channel type", this)); LOG(("OBJLC [%p]: Using channel type", this));
} else if (((caps & eAllowPluginSkipChannel) || !newURI) && } else if (((caps & eAllowPluginSkipChannel) || !newURI) &&
GetTypeOfContent(newMime) == eType_Plugin) { GetTypeOfContent(newMime) == eType_Plugin) {
newType = eType_Plugin; newType = eType_Plugin;
@ -2170,11 +2202,6 @@ nsObjectLoadingContent::LoadObject(bool aNotify,
return NS_OK; return NS_OK;
} }
// Check whether this is a youtube embed.
if (IsYoutubeEmbed()) {
Telemetry::Accumulate(Telemetry::YOUTUBE_REWRITABLE_EMBED_SEEN, 1);
}
// //
// Security checks // Security checks
// //

View File

@ -331,6 +331,12 @@ class nsObjectLoadingContent : public nsImageLoadingContent
*/ */
virtual nsContentPolicyType GetContentPolicyType() const = 0; virtual nsContentPolicyType GetContentPolicyType() const = 0;
// True if object represents an object/embed tag pointing to a flash embed
// for a youtube video. When possible (see IsRewritableYoutubeEmbed function
// comments for details), we change these to try to load HTML5 versions of
// videos.
bool mRewrittenYoutubeEmbed : 1;
private: private:
// Object parameter changes returned by UpdateObjectParameters // Object parameter changes returned by UpdateObjectParameters
@ -519,7 +525,27 @@ class nsObjectLoadingContent : public nsImageLoadingContent
*/ */
nsPluginFrame* GetExistingFrame(); nsPluginFrame* GetExistingFrame();
bool IsYoutubeEmbed(); /**
* Used for identifying whether we can rewrite a youtube flash embed to
* possibly use HTML5 instead.
*
* Returns true if plugin.rewrite_youtube_embeds pref is true and the
* element this nsObjectLoadingContent instance represents:
*
* - is an embed or object node
* - has a URL pointing at the youtube.com domain, using "/v/" style video
* path reference, and without enablejsapi=1 in the path
*
* Having the enablejsapi flag means the document that contains the element
* could possibly be manipulating the youtube video elsewhere on the page
* via javascript. We can't rewrite these kinds of elements without possibly
* breaking content, which we want to avoid.
*
* If we can rewrite the URL, we change the "/v/" to "/embed/", and change
* our type to eType_Document so that we render similarly to an iframe
* embed.
*/
bool ShouldRewriteYoutubeEmbed(nsIURI* uri);
// Helper class for SetupProtoChain // Helper class for SetupProtoChain
class SetupProtoChainRunner final : public nsIRunnable class SetupProtoChainRunner final : public nsIRunnable

View File

@ -345,6 +345,11 @@ HTMLSharedObjectElement::GetCapabilities() const
if (mNodeInfo->Equals(nsGkAtoms::embed)) { if (mNodeInfo->Equals(nsGkAtoms::embed)) {
capabilities |= eSupportSVG | eSupportImages; capabilities |= eSupportSVG | eSupportImages;
} }
// If this is a rewritten youtube flash embed, add documents to capabilities
// so that we can render HTML5 if possible.
if (mRewrittenYoutubeEmbed) {
capabilities |= eSupportDocuments;
}
return capabilities; return capabilities;
} }

View File

@ -5140,3 +5140,7 @@ pref("webextensions.tests", false);
// Allow customization of the fallback directory for file uploads // Allow customization of the fallback directory for file uploads
pref("dom.input.fallbackUploadDir", ""); pref("dom.input.fallbackUploadDir", "");
// Turn rewriting of youtube embeds on/off
pref("plugins.rewrite_youtube_embeds", true);