Bug 234628 part 2 - Make manual encoding overrides not apply to internal URL schemes or to docs declared as UTF-16 on the HTTP level; make docshells able to report when the encoding menu should be disabled. r=bzbarsky.

This commit is contained in:
Henri Sivonen 2013-01-18 16:27:03 +02:00
Родитель 7f2f8a25e2
Коммит 2583554bc9
9 изменённых файлов: 191 добавлений и 106 удалений

Просмотреть файл

@ -100,8 +100,8 @@ template<typename> class Sequence;
} // namespace mozilla
#define NS_IDOCUMENT_IID \
{ 0xff03d72f, 0x87cd, 0x4d11, \
{ 0x81, 0x8d, 0xa8, 0xb4, 0xf5, 0x98, 0x1a, 0x10 } }
{ 0x2df7f766, 0xf70b, 0x4de4, \
{ 0xb0, 0xba, 0x78, 0x25, 0x07, 0x41, 0xd6, 0xce } }
// Flag for AddStyleSheet().
#define NS_STYLESHEET_FROM_CATALOG (1 << 0)
@ -568,6 +568,12 @@ public:
virtual nsViewportInfo GetViewportInfo(uint32_t aDisplayWidth,
uint32_t aDisplayHeight) = 0;
/**
* True iff this doc will ignore manual character encoding overrides.
*/
virtual bool WillIgnoreCharsetOverride() {
return true;
}
protected:
virtual Element *GetRootElementInternal() const = 0;

Просмотреть файл

@ -3186,16 +3186,12 @@ nsDocument::SetHeaderData(nsIAtom* aHeaderField, const nsAString& aData)
}
}
bool
void
nsDocument::TryChannelCharset(nsIChannel *aChannel,
int32_t& aCharsetSource,
nsACString& aCharset,
nsHtml5TreeOpExecutor* aExecutor)
{
if(kCharsetFromChannel <= aCharsetSource) {
return true;
}
if (aChannel) {
nsAutoCString charsetVal;
nsresult rv = aChannel->GetContentCharset(charsetVal);
@ -3204,13 +3200,12 @@ nsDocument::TryChannelCharset(nsIChannel *aChannel,
if(EncodingUtils::FindEncodingForLabel(charsetVal, preferred)) {
aCharset = preferred;
aCharsetSource = kCharsetFromChannel;
return true;
return;
} else if (aExecutor && !charsetVal.IsEmpty()) {
aExecutor->ComplainAboutBogusProtocolCharset(this);
}
}
}
return false;
}
nsresult

Просмотреть файл

@ -1050,7 +1050,7 @@ protected:
void RetrieveRelevantHeaders(nsIChannel *aChannel);
bool TryChannelCharset(nsIChannel *aChannel,
void TryChannelCharset(nsIChannel *aChannel,
int32_t& aCharsetSource,
nsACString& aCharset,
nsHtml5TreeOpExecutor* aExecutor);

Просмотреть файл

@ -105,6 +105,7 @@
#include "nsIDOMJSWindow.h"
#include "nsSandboxFlags.h"
#include "mozilla/dom/HTMLBodyElement.h"
#include "nsCharsetSource.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -341,7 +342,7 @@ nsHTMLDocument::TryHintCharset(nsIMarkupDocumentViewer* aMarkupDV,
}
bool
void
nsHTMLDocument::TryUserForcedCharset(nsIMarkupDocumentViewer* aMarkupDV,
nsIDocShell* aDocShell,
int32_t& aCharsetSource,
@ -350,34 +351,45 @@ nsHTMLDocument::TryUserForcedCharset(nsIMarkupDocumentViewer* aMarkupDV,
nsresult rv = NS_OK;
if(kCharsetFromUserForced <= aCharsetSource)
return true;
return;
// mCharacterSet not updated yet for channel, so check aCharset, too.
if (WillIgnoreCharsetOverride() || !IsAsciiCompatible(aCharset)) {
return;
}
nsAutoCString forceCharsetFromDocShell;
if (aMarkupDV) {
// XXX mailnews-only
rv = aMarkupDV->GetForceCharacterSet(forceCharsetFromDocShell);
}
// Not making the IsAsciiCompatible() check here to allow the user to
// force UTF-16 from the menu.
if(NS_SUCCEEDED(rv) && !forceCharsetFromDocShell.IsEmpty()) {
if(NS_SUCCEEDED(rv) &&
!forceCharsetFromDocShell.IsEmpty() &&
IsAsciiCompatible(forceCharsetFromDocShell)) {
aCharset = forceCharsetFromDocShell;
//TODO: we should define appropriate constant for force charset
aCharsetSource = kCharsetFromUserForced;
} else if (aDocShell) {
return;
}
if (aDocShell) {
// This is the Character Encoding menu code path in Firefox
nsCOMPtr<nsIAtom> csAtom;
aDocShell->GetForcedCharset(getter_AddRefs(csAtom));
if (csAtom) {
csAtom->ToUTF8String(aCharset);
nsAutoCString charset;
csAtom->ToUTF8String(charset);
if (!IsAsciiCompatible(charset)) {
return;
}
aCharset = charset;
aCharsetSource = kCharsetFromUserForced;
aDocShell->SetForcedCharset(nullptr);
return true;
}
}
return false;
}
bool
void
nsHTMLDocument::TryCacheCharset(nsICachingChannel* aCachingChannel,
int32_t& aCharsetSource,
nsACString& aCharset)
@ -385,7 +397,7 @@ nsHTMLDocument::TryCacheCharset(nsICachingChannel* aCachingChannel,
nsresult rv;
if (kCharsetFromCache <= aCharsetSource) {
return true;
return;
}
nsCString cachedCharset;
@ -399,11 +411,7 @@ nsHTMLDocument::TryCacheCharset(nsICachingChannel* aCachingChannel,
{
aCharset = cachedCharset;
aCharsetSource = kCharsetFromCache;
return true;
}
return false;
}
static bool
@ -438,7 +446,10 @@ nsHTMLDocument::TryParentCharset(nsIDocShell* aDocShell,
if (!aDocShell) {
return;
}
int32_t source;
if (aCharsetSource >= kCharsetFromParentForced) {
return;
}
nsCOMPtr<nsIAtom> csAtom;
int32_t parentSource;
nsAutoCString parentCharset;
@ -448,9 +459,23 @@ nsHTMLDocument::TryParentCharset(nsIDocShell* aDocShell,
}
aDocShell->GetParentCharsetSource(&parentSource);
csAtom->ToUTF8String(parentCharset);
if (kCharsetFromParentForced <= parentSource) {
source = kCharsetFromParentForced;
} else if (kCharsetFromHintPrevDoc == parentSource) {
if (kCharsetFromParentForced == parentSource ||
kCharsetFromUserForced == parentSource) {
if (WillIgnoreCharsetOverride() ||
!IsAsciiCompatible(aCharset) || // if channel said UTF-16
!IsAsciiCompatible(parentCharset)) {
return;
}
aCharset.Assign(parentCharset);
aCharsetSource = kCharsetFromParentForced;
return;
}
if (aCharsetSource >= kCharsetFromHintPrevDoc) {
return;
}
if (kCharsetFromHintPrevDoc == parentSource) {
// Make sure that's OK
if (!aParentDocument ||
!CheckSameOrigin(this, aParentDocument) ||
@ -460,8 +485,16 @@ nsHTMLDocument::TryParentCharset(nsIDocShell* aDocShell,
// if parent is posted doc, set this prevent autodetections
// I'm not sure this makes much sense... but whatever.
source = kCharsetFromHintPrevDoc;
} else if (kCharsetFromCache <= parentSource) {
aCharset.Assign(parentCharset);
aCharsetSource = kCharsetFromHintPrevDoc;
return;
}
if (aCharsetSource >= kCharsetFromParentFrame) {
return;
}
if (kCharsetFromCache <= parentSource) {
// Make sure that's OK
if (!aParentDocument ||
!CheckSameOrigin(this, aParentDocument) ||
@ -469,21 +502,13 @@ nsHTMLDocument::TryParentCharset(nsIDocShell* aDocShell,
return;
}
source = kCharsetFromParentFrame;
} else {
return;
aCharset.Assign(parentCharset);
aCharsetSource = kCharsetFromParentFrame;
}
if (source < aCharsetSource) {
return;
}
aCharset.Assign(parentCharset);
aCharsetSource = source;
}
void
nsHTMLDocument::UseWeakDocTypeDefault(int32_t& aCharsetSource,
nsHTMLDocument::TryWeakDocTypeDefault(int32_t& aCharsetSource,
nsACString& aCharset)
{
if (kCharsetFromWeakDocTypeDefault <= aCharsetSource)
@ -503,28 +528,23 @@ nsHTMLDocument::UseWeakDocTypeDefault(int32_t& aCharsetSource,
return;
}
bool
void
nsHTMLDocument::TryDefaultCharset( nsIMarkupDocumentViewer* aMarkupDV,
int32_t& aCharsetSource,
nsACString& aCharset)
{
if(kCharsetFromUserDefault <= aCharsetSource)
return true;
return;
nsAutoCString defaultCharsetFromDocShell;
if (aMarkupDV) {
nsresult rv =
aMarkupDV->GetDefaultCharacterSet(defaultCharsetFromDocShell);
// Not making the IsAsciiCompatible() check here to allow the user to
// force UTF-16 from the menu.
if(NS_SUCCEEDED(rv)) {
if(NS_SUCCEEDED(rv) && IsAsciiCompatible(defaultCharsetFromDocShell)) {
aCharset = defaultCharsetFromDocShell;
aCharsetSource = kCharsetFromUserDefault;
return true;
}
}
return false;
}
void
@ -736,37 +756,39 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand,
charsetSource = kCharsetUninitialized;
wyciwygChannel = do_QueryInterface(aChannel);
// The following charset resolving calls has implied knowledge
// about charset source priority order. Each try will return true
// if the source is higher or equal to the source as its name
// describes. Some try call might change charset source to
// multiple values, like TryHintCharset and TryParentCharset. It
// should be always safe to try more sources.
if (!TryUserForcedCharset(muCV, docShell, charsetSource, charset)) {
TryHintCharset(muCV, charsetSource, charset);
TryParentCharset(docShell, parentDocument, charsetSource, charset);
// The following will try to get the character encoding from various
// sources. Each Try* function will return early if the source is already
// at least as large as any of the sources it might look at. Some of
// these functions (like TryHintCharset and TryParentCharset) can set
// charsetSource to various values depending on where the charset they
// end up finding originally comes from.
// Don't actually get the charset from the channel if this is a
// wyciwyg channel; it'll always be UTF-16
if (!wyciwygChannel &&
TryChannelCharset(aChannel, charsetSource, charset, executor)) {
// Use the channel's charset (e.g., charset from HTTP
// "Content-Type" header).
}
else if (cachingChan && !urlSpec.IsEmpty() &&
TryCacheCharset(cachingChan, charsetSource, charset)) {
// Use the cache's charset.
}
else if (TryDefaultCharset(muCV, charsetSource, charset)) {
// Use the default charset.
// previous document charset might be inherited as default charset.
}
else {
// Use the weak doc type default charset
UseWeakDocTypeDefault(charsetSource, charset);
}
// Don't actually get the charset from the channel if this is a
// wyciwyg channel; it'll always be UTF-16
if (!wyciwygChannel) {
// Otherwise, try the channel's charset (e.g., charset from HTTP
// "Content-Type" header) first. This way, we get to reject overrides in
// TryParentCharset and TryUserForcedCharset if the channel said UTF-16.
// This is to avoid socially engineered XSS by adding user-supplied
// content to a UTF-16 site such that the byte have a dangerous
// interpretation as ASCII and the user can be lured to using the
// charset menu.
TryChannelCharset(aChannel, charsetSource, charset, executor);
}
TryUserForcedCharset(muCV, docShell, charsetSource, charset);
TryHintCharset(muCV, charsetSource, charset); // XXX mailnews-only
TryParentCharset(docShell, parentDocument, charsetSource, charset);
if (cachingChan && !urlSpec.IsEmpty()) {
TryCacheCharset(cachingChan, charsetSource, charset);
}
TryDefaultCharset(muCV, charsetSource, charset);
TryWeakDocTypeDefault(charsetSource, charset);
bool isPostPage = false;
// check if current doc is from POST command
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
@ -3779,3 +3801,37 @@ nsHTMLDocument::DocSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const
// - mWyciwygChannel
// - mMidasCommandManager
}
bool
nsHTMLDocument::WillIgnoreCharsetOverride()
{
if (!mIsRegularHTML) {
return true;
}
if (mCharacterSetSource == kCharsetFromByteOrderMark) {
return true;
}
if (!IsAsciiCompatible(mCharacterSet)) {
return true;
}
nsCOMPtr<nsIWyciwygChannel> wyciwyg = do_QueryInterface(mChannel);
if (wyciwyg) {
return true;
}
nsIURI* uri = GetOriginalURI();
if (uri) {
bool schemeIs = false;
uri->SchemeIs("about", &schemeIs);
if (schemeIs) {
return true;
}
bool isResource;
nsresult rv = NS_URIChainHasFlags(uri,
nsIProtocolHandler::URI_IS_UI_RESOURCE,
&isResource);
if (NS_FAILED(rv) || isResource) {
return true;
}
}
return false;
}

Просмотреть файл

@ -173,6 +173,8 @@ public:
virtual void DocSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const;
// DocSizeOfIncludingThis is inherited from nsIDocument.
virtual bool WillIgnoreCharsetOverride();
// WebIDL API
void GetDomain(nsAString& aDomain, mozilla::ErrorResult& rv);
void SetDomain(const nsAString& aDomain, mozilla::ErrorResult& rv);
@ -296,24 +298,24 @@ protected:
static bool IsAsciiCompatible(const nsACString& aPreferredName);
static void TryHintCharset(nsIMarkupDocumentViewer* aMarkupDV,
int32_t& aCharsetSource,
nsACString& aCharset);
static bool TryUserForcedCharset(nsIMarkupDocumentViewer* aMarkupDV,
nsIDocShell* aDocShell,
int32_t& aCharsetSource,
nsACString& aCharset);
static bool TryCacheCharset(nsICachingChannel* aCachingChannel,
int32_t& aCharsetSource,
nsACString& aCharset);
void TryUserForcedCharset(nsIMarkupDocumentViewer* aMarkupDV,
nsIDocShell* aDocShell,
int32_t& aCharsetSource,
nsACString& aCharset);
static void TryCacheCharset(nsICachingChannel* aCachingChannel,
int32_t& aCharsetSource,
nsACString& aCharset);
// aParentDocument could be null.
void TryParentCharset(nsIDocShell* aDocShell,
nsIDocument* aParentDocument,
int32_t& charsetSource, nsACString& aCharset);
static void UseWeakDocTypeDefault(int32_t& aCharsetSource,
nsACString& aCharset);
static bool TryDefaultCharset(nsIMarkupDocumentViewer* aMarkupDV,
int32_t& aCharsetSource,
nsACString& aCharset);
nsIDocument* aParentDocument,
int32_t& charsetSource, nsACString& aCharset);
static void TryWeakDocTypeDefault(int32_t& aCharsetSource,
nsACString& aCharset);
static void TryDefaultCharset(nsIMarkupDocumentViewer* aMarkupDV,
int32_t& aCharsetSource,
nsACString& aCharset);
// Override so we can munge the charset on our wyciwyg channel as needed.
virtual void SetDocumentCharacterSet(const nsACString& aCharSetID);

Просмотреть файл

@ -2248,6 +2248,25 @@ nsDocShell::SetFullscreenAllowed(bool aFullscreenAllowed)
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::GetMayEnableCharacterEncodingMenu(bool* aMayEnableCharacterEncodingMenu)
{
*aMayEnableCharacterEncodingMenu = false;
if (!mContentViewer) {
return NS_OK;
}
nsIDocument* doc = mContentViewer->GetDocument();
if (!doc) {
return NS_OK;
}
if (doc->WillIgnoreCharsetOverride()) {
return NS_OK;
}
*aMayEnableCharacterEncodingMenu = true;
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::GetDocShellEnumerator(int32_t aItemType, int32_t aDirection, nsISimpleEnumerator **outEnum)
{

Просмотреть файл

@ -39,7 +39,7 @@ interface nsIWebBrowserPrint;
interface nsIVariant;
interface nsIPrivacyTransitionObserver;
[scriptable, builtinclass, uuid(008f5c86-b915-458c-aaf1-78de3b484e68)]
[scriptable, builtinclass, uuid(ca15d803-1330-4154-b3f9-063fb2b443e7)]
interface nsIDocShell : nsISupports
{
/**
@ -583,7 +583,7 @@ interface nsIDocShell : nsISupports
/*
* In a child docshell, this is the source of parentCharset
* @see nsIParser
* @see nsCharsetSource.h
*/
attribute int32_t parentCharsetSource;
@ -725,4 +725,10 @@ interface nsIDocShell : nsISupports
[infallible] readonly attribute boolean fullscreenAllowed;
void setFullscreenAllowed(in boolean allowed);
/**
* Indicates whether the UI may enable the character encoding menu. The UI
* must disable the menu when this property is false.
*/
[infallible] readonly attribute boolean mayEnableCharacterEncodingMenu;
};

Просмотреть файл

@ -46,19 +46,20 @@ interface nsIMarkupDocumentViewer : nsISupports
*/
attribute ACString defaultCharacterSet;
/*
XXX Comment here!
*/
/**
* XXX comm-central only: bug 829543. Not the Character Encoding menu in
* browser!
*/
attribute ACString forceCharacterSet;
/*
XXX Comment here!
*/
/**
* XXX comm-central only: bug 829543.
*/
attribute ACString hintCharacterSet;
/*
XXX Comment here!
*/
/**
* XXX comm-central only: bug 829543.
*/
attribute int32_t hintCharacterSetSource;
/*

Просмотреть файл

@ -7,7 +7,7 @@ const enteredText2="\u03BE\u03B5\u03C3\u03BA\u03B5\u03C0\u03AC\u03B6\u03C9\u0020
function test() {
waitForExplicitFinish();
var rootDir = getRootDirectory(gTestPath);
var rootDir = "http://mochi.test:8888/browser/docshell/test/browser/";
gBrowser.selectedTab = gBrowser.addTab(rootDir + "test-form_sjis.html");
gBrowser.selectedBrowser.addEventListener("load", afterOpen, true);
}