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 8bf105ac4f
commit 3601994212
4 changed files with 80 additions and 18 deletions

View File

@ -103,6 +103,7 @@
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
static const char *kPrefJavaMIME = "plugin.java.mime";
static const char *kPrefYoutubeRewrite = "plugins.rewrite_youtube_embeds";
using namespace mozilla;
using namespace mozilla::dom;
@ -704,7 +705,8 @@ nsObjectLoadingContent::UnbindFromTree(bool aDeep, bool aNullParent)
}
nsObjectLoadingContent::nsObjectLoadingContent()
: mType(eType_Loading)
: mRewrittenYoutubeEmbed(false)
, mType(eType_Loading)
, mFallbackType(eFallbackAlternate)
, mRunID(0)
, mHasRunID(false)
@ -1482,7 +1484,7 @@ nsObjectLoadingContent::CheckJavaCodebase()
}
bool
nsObjectLoadingContent::IsYoutubeEmbed()
nsObjectLoadingContent::ShouldRewriteYoutubeEmbed(nsIURI* aURI)
{
nsCOMPtr<nsIContent> thisContent =
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
@ -1500,25 +1502,41 @@ nsObjectLoadingContent::IsYoutubeEmbed()
NS_WARNING("Could not get TLD service!");
return false;
}
nsAutoCString currentBaseDomain;
bool ok = NS_SUCCEEDED(tldService->GetBaseDomain(mURI, 0, currentBaseDomain));
bool ok = NS_SUCCEEDED(tldService->GetBaseDomain(aURI, 0, currentBaseDomain));
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;
}
// See if URL is referencing youtube
nsAutoCString domain("youtube.com");
if (!StringEndsWith(domain, currentBaseDomain)) {
if (!currentBaseDomain.EqualsLiteral("youtube.com")) {
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.
nsAutoCString uri;
mURI->GetSpec(uri);
// Only log urls that are rewritable, e.g. not using enablejsapi=1
aURI->GetSpec(uri);
if (uri.Find("enablejsapi=1", true, 0, -1) != kNotFound) {
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
@ -1769,6 +1787,7 @@ nsObjectLoadingContent::UpdateObjectParameters(bool aJavaURI)
NS_NOTREACHED("Unrecognized plugin-loading tag");
}
mRewrittenYoutubeEmbed = false;
// Note that the baseURI changing could affect the newURI, even if uriStr did
// not change.
if (!uriStr.IsEmpty()) {
@ -1776,6 +1795,19 @@ nsObjectLoadingContent::UpdateObjectParameters(bool aJavaURI)
uriStr,
thisContent->OwnerDoc(),
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)) {
NS_TryToSetImmutable(newURI);
} else {
@ -1939,9 +1971,9 @@ nsObjectLoadingContent::UpdateObjectParameters(bool aJavaURI)
newType = eType_Null;
newMime.Truncate();
} else if (newChannel) {
// If newChannel is set above, we considered it in setting newMime
newType = GetTypeOfContent(newMime);
LOG(("OBJLC [%p]: Using channel type", this));
// If newChannel is set above, we considered it in setting newMime
newType = GetTypeOfContent(newMime);
LOG(("OBJLC [%p]: Using channel type", this));
} else if (((caps & eAllowPluginSkipChannel) || !newURI) &&
GetTypeOfContent(newMime) == eType_Plugin) {
newType = eType_Plugin;
@ -2170,11 +2202,6 @@ nsObjectLoadingContent::LoadObject(bool aNotify,
return NS_OK;
}
// Check whether this is a youtube embed.
if (IsYoutubeEmbed()) {
Telemetry::Accumulate(Telemetry::YOUTUBE_REWRITABLE_EMBED_SEEN, 1);
}
//
// Security checks
//

View File

@ -331,6 +331,12 @@ class nsObjectLoadingContent : public nsImageLoadingContent
*/
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:
// Object parameter changes returned by UpdateObjectParameters
@ -519,7 +525,27 @@ class nsObjectLoadingContent : public nsImageLoadingContent
*/
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
class SetupProtoChainRunner final : public nsIRunnable

View File

@ -345,6 +345,11 @@ HTMLSharedObjectElement::GetCapabilities() const
if (mNodeInfo->Equals(nsGkAtoms::embed)) {
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;
}

View File

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