Fix for bug 233907 (document.createElementNS() doesn't throw NAMESPACE_ERR when given a namespace-invalid name.). r/sr=jst.

This commit is contained in:
peterv%propagandism.org 2004-03-06 16:00:23 +00:00
parent 545ad9d0ad
commit 68a7e5f818
11 changed files with 253 additions and 142 deletions

View File

@ -77,6 +77,7 @@
#include "nsIForm.h"
#include "nsIFormControl.h"
#include "nsHTMLAtoms.h"
#include "nsLayoutAtoms.h"
static const char kJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
static NS_DEFINE_IID(kParserServiceCID, NS_PARSERSERVICE_CID);
@ -1597,9 +1598,8 @@ nsContentUtils::CheckQName(const nsAString& aQualifiedName,
NS_ENSURE_TRUE(parserService, NS_ERROR_FAILURE);
const PRUnichar *colon;
return parserService->IsValidQName(PromiseFlatString(aQualifiedName),
aNamespaceAware, &colon) ?
NS_OK : NS_ERROR_DOM_INVALID_CHARACTER_ERR;
return parserService->CheckQName(PromiseFlatString(aQualifiedName),
aNamespaceAware, &colon);
}
// static
@ -1614,11 +1614,9 @@ nsContentUtils::GetNodeInfoFromQName(const nsAString& aNamespaceURI,
const nsAFlatString& qName = PromiseFlatString(aQualifiedName);
const PRUnichar* colon;
if (!parserService->IsValidQName(qName, PR_TRUE, &colon)) {
return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
}
nsresult rv = parserService->CheckQName(qName, PR_TRUE, &colon);
NS_ENSURE_SUCCESS(rv, rv);
nsresult rv;
if (colon) {
const PRUnichar* end;
qName.EndReading(end);
@ -1632,8 +1630,29 @@ nsContentUtils::GetNodeInfoFromQName(const nsAString& aNamespaceURI,
rv = aNodeInfoManager->GetNodeInfo(aQualifiedName, nsnull, aNamespaceURI,
aNodeInfo);
}
NS_ENSURE_SUCCESS(rv, rv);
return rv;
nsIAtom* prefix = (*aNodeInfo)->GetPrefixAtom();
PRInt32 nsID = (*aNodeInfo)->NamespaceID();
nsIAtom* nil = nsnull;
// NAMESPACE_ERR: Raised if the qualifiedName is a malformed qualified name,
// if the qualifiedName has a prefix and the namespaceURI is null, if the
// qualifiedName has a prefix that is "xml" and the namespaceURI is different
// from "http://www.w3.org/XML/1998/namespace", if the qualifiedName or its
// prefix is "xmlns" and the namespaceURI is different from
// "http://www.w3.org/2000/xmlns/", or if the namespaceURI is
// "http://www.w3.org/2000/xmlns/" and neither the qualifiedName nor its
// prefix is "xmlns".
PRBool xmlPrefix = prefix == nsLayoutAtoms::xmlNameSpace;
PRBool xmlns = (*aNodeInfo)->Equals(nsLayoutAtoms::xmlnsNameSpace, nil) ||
prefix == nsLayoutAtoms::xmlnsNameSpace;
return (prefix && DOMStringIsNull(aNamespaceURI)) ||
(xmlPrefix && nsID != kNameSpaceID_XML) ||
(xmlns && nsID != kNameSpaceID_XMLNS) ||
(nsID == kNameSpaceID_XMLNS && !xmlns) ?
NS_ERROR_DOM_NAMESPACE_ERR : NS_OK;
}
void

View File

@ -121,6 +121,7 @@ static NS_DEFINE_CID(kDOMEventGroupCID, NS_DOMEVENTGROUP_CID);
#include "nsScriptEventManager.h"
#include "nsIXPathEvaluatorInternal.h"
#include "nsIElementFactory.h"
#include "nsIParserService.h"
#ifdef DEBUG
#include "nsICharsetAlias.h"
@ -362,8 +363,25 @@ nsDOMImplementation::CreateDocument(const nsAString& aNamespaceURI,
nsresult rv;
if (!aQualifiedName.IsEmpty()) {
rv = nsContentUtils::CheckQName(aQualifiedName);
nsIParserService *parserService =
nsContentUtils::GetParserServiceWeakRef();
NS_ENSURE_TRUE(parserService, NS_ERROR_FAILURE);
const nsAFlatString& qName = PromiseFlatString(aQualifiedName);
const PRUnichar *colon;
rv = parserService->CheckQName(qName, PR_TRUE, &colon);
NS_ENSURE_SUCCESS(rv, rv);
if (colon &&
(DOMStringIsNull(aNamespaceURI) ||
(Substring(qName.get(), colon).Equals(NS_LITERAL_STRING("xml")) &&
!aNamespaceURI.Equals(NS_LITERAL_STRING("http://www.w3.org/XML/1998/namespace"))))) {
return NS_ERROR_DOM_NAMESPACE_ERR;
}
}
else if (DOMStringIsNull(aQualifiedName) &&
!DOMStringIsNull(aNamespaceURI)) {
return NS_ERROR_DOM_NAMESPACE_ERR;
}
if (aDoctype) {

View File

@ -64,69 +64,82 @@ int MOZ_byte_type(unsigned char p)
#endif
#define CHECK_NAME_CASES(ptr) \
case BT_NONASCII: \
if (!IS_NAME_CHAR_MINBPC(ptr)) \
return 0; \
case BT_NMSTRT: \
case BT_HEX: \
case BT_DIGIT: \
case BT_NAME: \
case BT_MINUS:
#define MOZ_EXPAT_VALID_QNAME (0)
#define MOZ_EXPAT_EMPTY_QNAME (1 << 0)
#define MOZ_EXPAT_INVALID_CHARACTER (1 << 1)
#define MOZ_EXPAT_MALFORMED (1 << 2)
#define CHECK_NMSTRT_CASES(ptr) \
case BT_NONASCII: \
if (!IS_NMSTRT_CHAR_MINBPC(ptr)) \
return 0; \
case BT_NMSTRT: \
case BT_HEX:
int MOZ_XMLIsValidQName(const char* ptr, const char* end,
int ns_aware, const char** colon)
int MOZ_XMLCheckQName(const char* ptr, const char* end, int ns_aware,
const char** colon)
{
int result = MOZ_EXPAT_VALID_QNAME;
int nmstrt = 1;
*colon = 0;
if (ptr == end)
return 0;
switch (BYTE_TYPE(ptr)) {
CHECK_NMSTRT_CASES(ptr)
ptr += 2;
break;
default:
return 0;
if (ptr == end) {
return MOZ_EXPAT_EMPTY_QNAME;
}
while (ptr != end) {
do {
switch (BYTE_TYPE(ptr)) {
case BT_COLON:
if (ns_aware) {
if (*colon != 0)
return 0;
if (*colon != 0 || nmstrt || ptr + 2 == end) {
// We already encountered a colon or this is the first or the last
// character so the QName is malformed.
result |= MOZ_EXPAT_MALFORMED;
}
*colon = ptr;
ptr += 2;
if (ptr == end)
return 0;
switch (BYTE_TYPE(ptr)) {
CHECK_NMSTRT_CASES(ptr)
break;
default:
return 0;
nmstrt = 1;
}
else if (nmstrt) {
// This is the first character so the QName is malformed.
result |= MOZ_EXPAT_MALFORMED;
nmstrt = 0;
}
break;
case BT_NONASCII:
if (nmstrt) {
if (!IS_NMSTRT_CHAR_MINBPC(ptr)) {
// If this is a valid name character the QName is malformed,
// otherwise it contains an invalid character.
result |= IS_NAME_CHAR_MINBPC(ptr) ? MOZ_EXPAT_MALFORMED :
MOZ_EXPAT_INVALID_CHARACTER;
}
}
ptr += 2;
else if (!IS_NAME_CHAR_MINBPC(ptr)) {
result |= MOZ_EXPAT_INVALID_CHARACTER;
}
nmstrt = 0;
break;
CHECK_NAME_CASES(ptr)
ptr += 2;
case BT_NMSTRT:
case BT_HEX:
nmstrt = 0;
break;
case BT_DIGIT:
case BT_NAME:
case BT_MINUS:
if (nmstrt) {
result |= MOZ_EXPAT_MALFORMED;
nmstrt = 0;
}
break;
default:
return 0;
result |= MOZ_EXPAT_INVALID_CHARACTER;
nmstrt = 0;
}
}
return 1;
ptr += 2;
} while (ptr != end);
return result;
}
int MOZ_XMLIsLetter(const char* ptr)
{
switch (BYTE_TYPE(ptr)) {
CHECK_NMSTRT_CASES(ptr)
case BT_NONASCII:
if (!IS_NMSTRT_CHAR_MINBPC(ptr)) {
return 0;
}
case BT_NMSTRT:
case BT_HEX:
return 1;
default:
return 0;
@ -136,7 +149,15 @@ int MOZ_XMLIsLetter(const char* ptr)
int MOZ_XMLIsNCNameChar(const char* ptr)
{
switch (BYTE_TYPE(ptr)) {
CHECK_NAME_CASES(ptr)
case BT_NONASCII:
if (!IS_NAME_CHAR_MINBPC(ptr)) {
return 0;
}
case BT_NMSTRT:
case BT_HEX:
case BT_DIGIT:
case BT_NAME:
case BT_MINUS:
return 1;
default:
return 0;

View File

@ -102,8 +102,8 @@ public:
};
#ifdef TX_EXE
extern "C" int MOZ_XMLIsValidQName(const char* ptr, const char* end,
int ns_aware, const char** colon);
extern "C" int MOZ_XMLCheckQName(const char* ptr, const char* end,
int ns_aware, const char** colon);
extern "C" int MOZ_XMLIsLetter(const char* ptr);
extern "C" int MOZ_XMLIsNCNameChar(const char* ptr);
#else
@ -148,15 +148,15 @@ public:
aQName.EndReading(end);
const char *colonPtr;
PRBool valid = MOZ_XMLIsValidQName(NS_REINTERPRET_CAST(const char*,
aQName.get()),
NS_REINTERPRET_CAST(const char*,
end),
PR_TRUE, &colonPtr);
int result = MOZ_XMLCheckQName(NS_REINTERPRET_CAST(const char*,
aQName.get()),
NS_REINTERPRET_CAST(const char*,
end),
PR_TRUE, &colonPtr);
*aColon = NS_REINTERPRET_CAST(const PRUnichar*, colonPtr);
return valid;
return result == 0;
#else
return gTxParserService->IsValidQName(aQName, PR_TRUE, aColon);
return NS_SUCCEEDED(gTxParserService->CheckQName(aQName, PR_TRUE, aColon));
#endif
}

View File

@ -103,7 +103,7 @@ class nsIParserService : public nsISupports {
NS_IMETHOD GetTopicObservers(const nsAString& aTopic,
nsIObserverEntry** aEntry) = 0;
virtual PRBool IsValidQName(const nsASingleFragmentString& aQName,
virtual nsresult CheckQName(const nsASingleFragmentString& aQName,
PRBool aNamespaceAware,
const PRUnichar** aColon) = 0;
virtual PRBool IsXMLLetter(PRUnichar aChar) = 0;

View File

@ -19,6 +19,7 @@
*
*/
#include "nsDOMError.h"
#include "nsIAtom.h"
#include "nsParserService.h"
#include "nsHTMLEntities.h"
@ -182,6 +183,32 @@ nsParserService::GetTopicObservers(const nsAString& aTopic,
return result;
}
nsresult
nsParserService::CheckQName(const nsASingleFragmentString& aQName,
PRBool aNamespaceAware,
const PRUnichar** aColon)
{
const char* colon;
const PRUnichar *begin, *end;
aQName.BeginReading(begin);
aQName.EndReading(end);
int result = MOZ_XMLCheckQName(NS_REINTERPRET_CAST(const char*, begin),
NS_REINTERPRET_CAST(const char*, end),
aNamespaceAware, &colon);
*aColon = NS_REINTERPRET_CAST(const PRUnichar*, colon);
if (result == 0) {
return NS_OK;
}
// MOZ_EXPAT_INVALID_CHARACTER
if (result & (1 << 1)) {
return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
}
return NS_ERROR_DOM_NAMESPACE_ERR;
}
class nsMatchesTopic : public nsDequeFunctor{
const nsAString& mString;
public:

View File

@ -25,8 +25,8 @@
#include "nsDTDUtils.h"
#include "nsVoidArray.h"
extern "C" int MOZ_XMLIsValidQName(const char* ptr, const char* end,
int ns_aware, const char** colon);
extern "C" int MOZ_XMLCheckQName(const char* ptr, const char* end,
int ns_aware, const char** colon);
extern "C" int MOZ_XMLIsLetter(const char* ptr);
extern "C" int MOZ_XMLIsNCNameChar(const char* ptr);
@ -63,20 +63,9 @@ public:
NS_IMETHOD GetTopicObservers(const nsAString& aTopic,
nsIObserverEntry** aEntry);
PRBool IsValidQName(const nsASingleFragmentString& aQName,
PRBool aNamespaceAware,
const PRUnichar** aColon)
{
const char* colon;
const PRUnichar *begin, *end;
aQName.BeginReading(begin);
aQName.EndReading(end);
int result = MOZ_XMLIsValidQName(NS_REINTERPRET_CAST(const char*, begin),
NS_REINTERPRET_CAST(const char*, end),
aNamespaceAware, &colon);
*aColon = NS_REINTERPRET_CAST(const PRUnichar*, colon);
return !!result;
}
nsresult CheckQName(const nsASingleFragmentString& aQName,
PRBool aNamespaceAware, const PRUnichar** aColon);
PRBool IsXMLLetter(PRUnichar aChar)
{
return MOZ_XMLIsLetter(NS_REINTERPRET_CAST(const char*, &aChar));

View File

@ -64,69 +64,82 @@ int MOZ_byte_type(unsigned char p)
#endif
#define CHECK_NAME_CASES(ptr) \
case BT_NONASCII: \
if (!IS_NAME_CHAR_MINBPC(ptr)) \
return 0; \
case BT_NMSTRT: \
case BT_HEX: \
case BT_DIGIT: \
case BT_NAME: \
case BT_MINUS:
#define MOZ_EXPAT_VALID_QNAME (0)
#define MOZ_EXPAT_EMPTY_QNAME (1 << 0)
#define MOZ_EXPAT_INVALID_CHARACTER (1 << 1)
#define MOZ_EXPAT_MALFORMED (1 << 2)
#define CHECK_NMSTRT_CASES(ptr) \
case BT_NONASCII: \
if (!IS_NMSTRT_CHAR_MINBPC(ptr)) \
return 0; \
case BT_NMSTRT: \
case BT_HEX:
int MOZ_XMLIsValidQName(const char* ptr, const char* end,
int ns_aware, const char** colon)
int MOZ_XMLCheckQName(const char* ptr, const char* end, int ns_aware,
const char** colon)
{
int result = MOZ_EXPAT_VALID_QNAME;
int nmstrt = 1;
*colon = 0;
if (ptr == end)
return 0;
switch (BYTE_TYPE(ptr)) {
CHECK_NMSTRT_CASES(ptr)
ptr += 2;
break;
default:
return 0;
if (ptr == end) {
return MOZ_EXPAT_EMPTY_QNAME;
}
while (ptr != end) {
do {
switch (BYTE_TYPE(ptr)) {
case BT_COLON:
if (ns_aware) {
if (*colon != 0)
return 0;
if (*colon != 0 || nmstrt || ptr + 2 == end) {
// We already encountered a colon or this is the first or the last
// character so the QName is malformed.
result |= MOZ_EXPAT_MALFORMED;
}
*colon = ptr;
ptr += 2;
if (ptr == end)
return 0;
switch (BYTE_TYPE(ptr)) {
CHECK_NMSTRT_CASES(ptr)
break;
default:
return 0;
nmstrt = 1;
}
else if (nmstrt) {
// This is the first character so the QName is malformed.
result |= MOZ_EXPAT_MALFORMED;
nmstrt = 0;
}
break;
case BT_NONASCII:
if (nmstrt) {
if (!IS_NMSTRT_CHAR_MINBPC(ptr)) {
// If this is a valid name character the QName is malformed,
// otherwise it contains an invalid character.
result |= IS_NAME_CHAR_MINBPC(ptr) ? MOZ_EXPAT_MALFORMED :
MOZ_EXPAT_INVALID_CHARACTER;
}
}
ptr += 2;
else if (!IS_NAME_CHAR_MINBPC(ptr)) {
result |= MOZ_EXPAT_INVALID_CHARACTER;
}
nmstrt = 0;
break;
CHECK_NAME_CASES(ptr)
ptr += 2;
case BT_NMSTRT:
case BT_HEX:
nmstrt = 0;
break;
case BT_DIGIT:
case BT_NAME:
case BT_MINUS:
if (nmstrt) {
result |= MOZ_EXPAT_MALFORMED;
nmstrt = 0;
}
break;
default:
return 0;
result |= MOZ_EXPAT_INVALID_CHARACTER;
nmstrt = 0;
}
}
return 1;
ptr += 2;
} while (ptr != end);
return result;
}
int MOZ_XMLIsLetter(const char* ptr)
{
switch (BYTE_TYPE(ptr)) {
CHECK_NMSTRT_CASES(ptr)
case BT_NONASCII:
if (!IS_NMSTRT_CHAR_MINBPC(ptr)) {
return 0;
}
case BT_NMSTRT:
case BT_HEX:
return 1;
default:
return 0;
@ -136,7 +149,15 @@ int MOZ_XMLIsLetter(const char* ptr)
int MOZ_XMLIsNCNameChar(const char* ptr)
{
switch (BYTE_TYPE(ptr)) {
CHECK_NAME_CASES(ptr)
case BT_NONASCII:
if (!IS_NAME_CHAR_MINBPC(ptr)) {
return 0;
}
case BT_NMSTRT:
case BT_HEX:
case BT_DIGIT:
case BT_NAME:
case BT_MINUS:
return 1;
default:
return 0;

View File

@ -103,7 +103,7 @@ class nsIParserService : public nsISupports {
NS_IMETHOD GetTopicObservers(const nsAString& aTopic,
nsIObserverEntry** aEntry) = 0;
virtual PRBool IsValidQName(const nsASingleFragmentString& aQName,
virtual nsresult CheckQName(const nsASingleFragmentString& aQName,
PRBool aNamespaceAware,
const PRUnichar** aColon) = 0;
virtual PRBool IsXMLLetter(PRUnichar aChar) = 0;

View File

@ -19,6 +19,7 @@
*
*/
#include "nsDOMError.h"
#include "nsIAtom.h"
#include "nsParserService.h"
#include "nsHTMLEntities.h"
@ -182,6 +183,32 @@ nsParserService::GetTopicObservers(const nsAString& aTopic,
return result;
}
nsresult
nsParserService::CheckQName(const nsASingleFragmentString& aQName,
PRBool aNamespaceAware,
const PRUnichar** aColon)
{
const char* colon;
const PRUnichar *begin, *end;
aQName.BeginReading(begin);
aQName.EndReading(end);
int result = MOZ_XMLCheckQName(NS_REINTERPRET_CAST(const char*, begin),
NS_REINTERPRET_CAST(const char*, end),
aNamespaceAware, &colon);
*aColon = NS_REINTERPRET_CAST(const PRUnichar*, colon);
if (result == 0) {
return NS_OK;
}
// MOZ_EXPAT_INVALID_CHARACTER
if (result & (1 << 1)) {
return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
}
return NS_ERROR_DOM_NAMESPACE_ERR;
}
class nsMatchesTopic : public nsDequeFunctor{
const nsAString& mString;
public:

View File

@ -25,8 +25,8 @@
#include "nsDTDUtils.h"
#include "nsVoidArray.h"
extern "C" int MOZ_XMLIsValidQName(const char* ptr, const char* end,
int ns_aware, const char** colon);
extern "C" int MOZ_XMLCheckQName(const char* ptr, const char* end,
int ns_aware, const char** colon);
extern "C" int MOZ_XMLIsLetter(const char* ptr);
extern "C" int MOZ_XMLIsNCNameChar(const char* ptr);
@ -63,20 +63,9 @@ public:
NS_IMETHOD GetTopicObservers(const nsAString& aTopic,
nsIObserverEntry** aEntry);
PRBool IsValidQName(const nsASingleFragmentString& aQName,
PRBool aNamespaceAware,
const PRUnichar** aColon)
{
const char* colon;
const PRUnichar *begin, *end;
aQName.BeginReading(begin);
aQName.EndReading(end);
int result = MOZ_XMLIsValidQName(NS_REINTERPRET_CAST(const char*, begin),
NS_REINTERPRET_CAST(const char*, end),
aNamespaceAware, &colon);
*aColon = NS_REINTERPRET_CAST(const PRUnichar*, colon);
return !!result;
}
nsresult CheckQName(const nsASingleFragmentString& aQName,
PRBool aNamespaceAware, const PRUnichar** aColon);
PRBool IsXMLLetter(PRUnichar aChar)
{
return MOZ_XMLIsLetter(NS_REINTERPRET_CAST(const char*, &aChar));