diff --git a/extensions/webservices/schema/src/nsSchemaLoader.cpp b/extensions/webservices/schema/src/nsSchemaLoader.cpp index 2d3b73f348d6..910898abfc4e 100644 --- a/extensions/webservices/schema/src/nsSchemaLoader.cpp +++ b/extensions/webservices/schema/src/nsSchemaLoader.cpp @@ -42,6 +42,7 @@ // content includes #include "nsIContent.h" +#include "nsIDocument.h" #include "nsIDOMDocument.h" #include "nsIDOM3Node.h" @@ -660,47 +661,17 @@ nsSchemaLoader::GetResolvedURI(const nsAString& aSchemaURI, /* nsISchema load (in AString schemaURI); */ NS_IMETHODIMP -nsSchemaLoader::Load(const nsAString& schemaURI, +nsSchemaLoader::Load(const nsAString& schemaURI, nsISchema **_retval) { NS_ENSURE_ARG_POINTER(_retval); - - nsCOMPtr resolvedURI; - nsresult rv = GetResolvedURI(schemaURI, "load", getter_AddRefs(resolvedURI)); - if (NS_FAILED(rv)) { - return rv; - } - nsCAutoString spec; - resolvedURI->GetSpec(spec); - - nsCOMPtr request(do_CreateInstance(NS_XMLHTTPREQUEST_CONTRACTID, &rv)); - if (!request) { - return rv; - } - - const nsAString& empty = EmptyString(); - rv = request->OpenRequest(NS_LITERAL_CSTRING("GET"), spec, PR_FALSE, empty, - empty); - if (NS_FAILED(rv)) { - return rv; - } - - // Force the mimetype of the returned stream to be xml. - rv = request->OverrideMimeType(NS_LITERAL_CSTRING("application/xml")); - if (NS_FAILED(rv)) { - return rv; - } - - rv = request->Send(nsnull); - if (NS_FAILED(rv)) { - return rv; - } nsCOMPtr document; - rv = request->GetResponseXML(getter_AddRefs(document)); - if (NS_FAILED(rv)) { - return rv; - } + nsresult rv = GetDocumentFromURI(schemaURI, getter_AddRefs(document)); + NS_ENSURE_SUCCESS(rv, rv); + + if (!document) + return NS_ERROR_SCHEMA_LOADING_ERROR; nsCOMPtr element; document->GetDocumentElement(getter_AddRefs(element)); @@ -711,7 +682,7 @@ nsSchemaLoader::Load(const nsAString& schemaURI, else { rv = NS_ERROR_SCHEMA_NOT_SCHEMA_ELEMENT; } - + return rv; } @@ -783,7 +754,7 @@ static const char* kSchemaNamespaces[] = {NS_SCHEMA_1999_NAMESPACE, static PRUint32 kSchemaNamespacesLength = sizeof(kSchemaNamespaces) / sizeof(const char*); /* nsISchema processSchemaElement (in nsIDOMElement element, in nsIWebServiceErrorHandler aErrorHandler); */ -NS_IMETHODIMP +NS_IMETHODIMP nsSchemaLoader::ProcessSchemaElement(nsIDOMElement* aElement, nsIWebServiceErrorHandler* aErrorHandler, nsISchema **aResult) @@ -815,7 +786,6 @@ nsSchemaLoader::ProcessSchemaElement(nsIDOMElement* aElement, // For now, ignore the following // annotations - // include // import // redefine // notation @@ -871,8 +841,142 @@ nsSchemaLoader::ProcessSchemaElement(nsIDOMElement* aElement, if (NS_SUCCEEDED(rv)) { rv = schemaInst->AddModelGroup(modelGroup); } + } + else if (tagName == nsSchemaAtoms::sInclude_atom) { + /* http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/structures.html#element-include + If we include a schema, it must either + (a) have the same targetNamespace as the including schema document or + (b) no targetNamespace at all + + If the uri to load doesn't resolve, it isn't a error. It is if it's an + invalid XML document or not a schema file + */ + + NS_NAMED_LITERAL_STRING(schemaLocationStr, "schemaLocation"); + + nsAutoString schemalocation; + childElement->GetAttribute(schemaLocationStr, schemalocation); + + // if empty, skip it + if (schemalocation.IsEmpty()) + continue; + + nsCOMPtr ios = do_GetIOService(); + NS_ENSURE_STATE(ios); + + nsCOMPtr document; + aElement->GetOwnerDocument(getter_AddRefs(document)); + + nsCOMPtr doc = do_QueryInterface(document); + NS_ENSURE_STATE(doc); + + nsCOMPtr uri; + + rv = NS_NewURI(getter_AddRefs(uri), + NS_ConvertUTF16toUTF8(schemalocation), + doc->GetDocumentCharacterSet().get(), + doc->GetDocumentURI()); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_STATE(uri); + + // since we could be going cross-domain, make sure we can load it by doing + // a principal same origin check. + + // get the base document's principal + nsIPrincipal *basePrincipal = doc->NodePrincipal(); + NS_ENSURE_STATE(basePrincipal); + + // check the security manager and do a same original check on the principal + nsCOMPtr secMan = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); + NS_ENSURE_STATE(secMan); + + // get a principal for the uri we are testing + nsCOMPtr testPrincipal; + rv = secMan->GetCodebasePrincipal(uri, getter_AddRefs(testPrincipal)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = secMan->CheckSameOriginPrincipal(basePrincipal, testPrincipal); + // if not allowed, continue onwards + if (NS_FAILED(rv)) + continue; + + // get the url + nsCAutoString spec; + uri->GetSpec(spec); + + nsCOMPtr includedDocument; + rv = GetDocumentFromURI(NS_ConvertUTF8toUTF16(spec), + getter_AddRefs(includedDocument)); + NS_ENSURE_SUCCESS(rv, rv); + + // if no document, it is an error + NS_ENSURE_STATE(includedDocument); + + // get the document element - it should be a xsd:schema + nsCOMPtr element; + includedDocument->GetDocumentElement(getter_AddRefs(element)); + + nsAutoString localName, nsUri; + element->GetLocalName(localName); + element->GetNamespaceURI(nsUri); + + PRBool correctNamespace = PR_FALSE; + PRUint32 i; + for (i = 0; i < kSchemaNamespacesLength; i++) { + if (nsUri.Equals(NS_ConvertASCIItoUTF16(kSchemaNamespaces[i]))) { + correctNamespace = PR_TRUE; + break; + } + } + + if (!correctNamespace || !localName.EqualsLiteral("schema")) { + // not a valid schema file + return NS_ERROR_SCHEMA_NOT_SCHEMA_ELEMENT; + } + + // XXX: check the target namespace requirements + + // import/append all elements in the included file to our schema element + nsCOMPtr ownerDoc; + rv = childElement->GetOwnerDocument(getter_AddRefs(ownerDoc)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_STATE(ownerDoc); + + nsCOMPtr tmpNode, importedNode, dummy; + element->GetFirstChild(getter_AddRefs(tmpNode)); + + // get the child element's next sibling so we have something to insert + // before while we are appending to the current schema document + unsigned short nodeType; + nsCOMPtr nextSibling; + childElement->GetNextSibling(getter_AddRefs(nextSibling)); + + while (tmpNode) { + tmpNode->GetNodeType(&nodeType); + + if (nodeType == nsIDOMNode::ELEMENT_NODE) { + rv = ownerDoc->ImportNode(tmpNode, PR_TRUE, + getter_AddRefs(importedNode)); + NS_ENSURE_SUCCESS(rv, rv); + + // InsertBefore can deal with a null nextSibling (will append) + rv = aElement->InsertBefore(importedNode, nextSibling, + getter_AddRefs(dummy)); + NS_ENSURE_SUCCESS(rv, rv); + } + + tmpNode->GetNextSibling(getter_AddRefs(dummy)); + tmpNode = dummy; + } + + // we twidle the iterator (reset), making sure to point it at the right + // place. We do this because the iterator takes a snapshot the DOMList, + // so we tell it to reinit itself and then reset it to the original index. + PRUint32 index = iterator.GetCurrentIndex(); + iterator.SetElement(aElement); + iterator.Reset(index); } else if (tagName != nsSchemaAtoms::sAnnotation_atom && - tagName != nsSchemaAtoms::sInclude_atom && tagName != nsSchemaAtoms::sImport_atom && tagName != nsSchemaAtoms::sRedefine_atom && tagName != nsSchemaAtoms::sNotation_atom) { @@ -3248,3 +3352,43 @@ nsSchemaLoader::ParseNameAndNS(const nsAString& aName, nsIDOMElement* aElement, return rv; } + +nsresult +nsSchemaLoader::GetDocumentFromURI(const nsAString& aUri, + nsIDOMDocument** aDocument) +{ + *aDocument = nsnull; + + nsCOMPtr resolvedURI; + nsresult rv = GetResolvedURI(aUri, "load", getter_AddRefs(resolvedURI)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr request = + do_CreateInstance(NS_XMLHTTPREQUEST_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCAutoString spec; + resolvedURI->GetSpec(spec); + + const nsAString& empty = EmptyString(); + rv = request->OpenRequest(NS_LITERAL_CSTRING("GET"), spec, PR_FALSE, empty, + empty); + NS_ENSURE_SUCCESS(rv, rv); + + // Force the mimetype of the returned stream to be xml. + rv = request->OverrideMimeType(NS_LITERAL_CSTRING("application/xml")); + NS_ENSURE_SUCCESS(rv, rv); + + rv = request->Send(nsnull); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr document; + rv = request->GetResponseXML(getter_AddRefs(document)); + NS_ENSURE_SUCCESS(rv, rv); + + if (document) { + document.swap(*aDocument); + } + + return NS_OK; +} diff --git a/extensions/webservices/schema/src/nsSchemaLoader.h b/extensions/webservices/schema/src/nsSchemaLoader.h index c6c9a496de33..981b94f1ffd1 100644 --- a/extensions/webservices/schema/src/nsSchemaLoader.h +++ b/extensions/webservices/schema/src/nsSchemaLoader.h @@ -224,6 +224,9 @@ protected: nsresult ParseNameAndNS(const nsAString& aName, nsIDOMElement* aElement, nsAString& aTypeName, nsAString& aTypeNS); + nsresult GetDocumentFromURI(const nsAString& aUri, + nsIDOMDocument** aDocument); + protected: nsInterfaceHashtable mSchemas; nsCOMPtr mBuiltinCollection;