зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
7f2f8a25e2
Коммит
2583554bc9
|
@ -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);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче