diff --git a/extensions/xforms/nsXFormsElementFactory.cpp b/extensions/xforms/nsXFormsElementFactory.cpp index bab8755877c..d1cf9c18425 100644 --- a/extensions/xforms/nsXFormsElementFactory.cpp +++ b/extensions/xforms/nsXFormsElementFactory.cpp @@ -37,10 +37,6 @@ * ***** END LICENSE BLOCK ***** */ #include "nsXFormsElementFactory.h" -#include "nsXFormsModelElement.h" -#include "nsXFormsInstanceElement.h" -#include "nsXFormsSubmissionElement.h" -#include "nsXFormsStubElement.h" #include "nsIDOMDocument.h" #include "nsXFormsAtoms.h" #include "nsIDocument.h" @@ -97,6 +93,11 @@ NS_HIDDEN_(nsresult) NS_NewXFormsToggleElement(nsIXTFElement **aResult); NS_HIDDEN_(nsresult) NS_NewXFormsCaseElement(nsIXTFElement **aResult); NS_HIDDEN_(nsresult) NS_NewXFormsSwitchElement(nsIXTFElement **aResult); +NS_HIDDEN_(nsresult) NS_NewXFormsModelElement(nsIXTFElement **aElement); +NS_HIDDEN_(nsresult) NS_NewXFormsSubmissionElement(nsIXTFElement **aElement); +NS_HIDDEN_(nsresult) NS_NewXFormsInstanceElement(nsIXTFElement **aElement); +NS_HIDDEN_(nsresult) NS_NewXFormsStubElement(nsIXTFElement **aElement); + NS_IMPL_ISUPPORTS2(nsXFormsElementFactory, nsIXTFElementFactory, nsIDOMNSFeatureFactory) diff --git a/extensions/xforms/nsXFormsModelElement.cpp b/extensions/xforms/nsXFormsModelElement.cpp index 534bb3f370a..3592de2341c 100644 --- a/extensions/xforms/nsXFormsModelElement.cpp +++ b/extensions/xforms/nsXFormsModelElement.cpp @@ -1644,7 +1644,8 @@ nsXFormsModelElement::ValidateDocument(nsIDOMDocument *aInstanceDocument, * SUBMIT_ABORT_SUBMISSION - abort submission (invalid node or empty required node) */ NS_IMETHODIMP -nsXFormsModelElement::HandleInstanceDataNode(nsIDOMNode *aInstanceDataNode, unsigned short *aResult) +nsXFormsModelElement::HandleInstanceDataNode(nsIDOMNode *aInstanceDataNode, + unsigned short *aResult) { // abort by default *aResult = SUBMIT_ABORT_SUBMISSION; diff --git a/extensions/xforms/nsXFormsSubmissionElement.cpp b/extensions/xforms/nsXFormsSubmissionElement.cpp index 40993809ba2..f8ccb0ab0e0 100644 --- a/extensions/xforms/nsXFormsSubmissionElement.cpp +++ b/extensions/xforms/nsXFormsSubmissionElement.cpp @@ -95,6 +95,7 @@ #include "nsIMIMEHeaderParam.h" #include "nsIExternalProtocolService.h" #include "nsEscape.h" +#include "nsAutoPtr.h" // namespace literals #define kXMLNSNameSpaceURI \ @@ -600,11 +601,18 @@ nsXFormsSubmissionElement::Submit() { LOG(("+++ nsXFormsSubmissionElement::Submit\n")); + NS_ENSURE_STATE(mElement); + nsresult rv; mIsSOAPRequest = PR_FALSE; + // // 1. ensure that we are not currently processing a xforms-submit (see E37) - NS_ENSURE_STATE(!mSubmissionActive); + if (mSubmissionActive) { + nsXFormsUtils::ReportError(NS_LITERAL_STRING("warnSubmitAlreadyRunning"), + mElement, nsIScriptError::warningFlag); + return NS_ERROR_FAILURE; + } mSubmissionActive = PR_TRUE; if (mActivator) @@ -615,17 +623,9 @@ nsXFormsSubmissionElement::Submit() nsAutoString replace; mElement->GetAttribute(NS_LITERAL_STRING("replace"), replace); mIsReplaceInstance = replace.EqualsLiteral("instance"); - - // XXX seems to be required by - // http://www.w3.org/TR/2003/REC-xforms-20031014/slice4.html#evt-revalidate - // but is it really needed for us? - nsCOMPtr model = GetModel(); - NS_ENSURE_STATE(model); - model->Recalculate(); - model->Revalidate(); - // 2. get selected node from the instance data (use xpath, gives us node - // iterator) + // + // 2. get selected node from the instance data nsCOMPtr data; rv = GetBoundInstanceData(getter_AddRefs(data)); NS_ENSURE_SUCCESS(rv, rv); @@ -636,26 +636,44 @@ nsXFormsSubmissionElement::Submit() return NS_OK; } - // 3. revalidate selected instance data (only for namespaces considered for - // serialization) + // + // 3. Create submission document (include namespaces, purge non-relevant + // nodes, check simple type validity) + nsCOMPtr submissionDoc; + rv = CreateSubmissionDoc(data, getter_AddRefs(submissionDoc)); + NS_ENSURE_SUCCESS(rv, rv); - // This is handled by the SerializeData() method + // + // 4. Validate document + // XXX: model->ValidateDocument(submissionDoc, &res); - // 4. serialize instance data + // + // 5. Convert submission document into the requested format // Checking the format only before starting the submission. mFormat = GetSubmissionFormat(mElement); NS_ENSURE_STATE(mFormat != 0); nsCOMPtr stream; nsCAutoString uri, contentType; - rv = SerializeData(data, uri, getter_AddRefs(stream), contentType); - NS_ENSURE_SUCCESS(rv, rv); + nsAutoString action; + mElement->GetAttribute(NS_LITERAL_STRING("action"), action); + CopyUTF16toUTF8(action, uri); + rv = SerializeData(submissionDoc, uri, getter_AddRefs(stream), contentType); + if (NS_FAILED(rv)) { + nsXFormsUtils::ReportError(NS_LITERAL_STRING("warnSubmitSerializeFailed"), + mElement, nsIScriptError::warningFlag); + return rv; + } - // 5. dispatch network request - + // + // 6. dispatch network request rv = SendData(uri, stream, contentType); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_FAILED(rv)) { + nsXFormsUtils::ReportError(NS_LITERAL_STRING("warnSubmitNetworkFailure"), + mElement, nsIScriptError::warningFlag); + return rv; + } return rv; } @@ -735,52 +753,31 @@ nsXFormsSubmissionElement::GetDefaultInstanceData(nsIDOMNode **result) } nsresult -nsXFormsSubmissionElement::SerializeData(nsIDOMNode *data, - nsCString &uri, - nsIInputStream **stream, - nsCString &contentType) +nsXFormsSubmissionElement::SerializeData(nsIDOMDocument *aData, + nsCString &aUri, + nsIInputStream **aStream, + nsCString &aContentType) { - // initialize uri to the given action - nsAutoString action; - mElement->GetAttribute(NS_LITERAL_STRING("action"), action); - CopyUTF16toUTF8(action, uri); - - // 'get' method: - // The URI is constructed as follows: - // o The submit URI from the action attribute is examined. If it does not - // already contain a ? (question mark) character, one is appended. If it - // does already contain a question mark character, then a separator - // character from the attribute separator is appended. - // o The serialized form data is appended to the URI. - if (mFormat & ENCODING_XML) - return SerializeDataXML(data, stream, contentType, nsnull); - - // Ensure the data is valid and required nodes are non-empty - // This is handled directly within SerializeDataXML() - nsCOMPtr model = GetModel(); - NS_ENSURE_STATE(model); - nsresult rv = CanSubmit(data, model, PR_FALSE); - NS_ENSURE_SUCCESS(rv, rv); + return SerializeDataXML(aData, aStream, aContentType); if (mFormat & ENCODING_URL) - return SerializeDataURLEncoded(data, uri, stream, contentType); + return SerializeDataURLEncoded(aData, aUri, aStream, aContentType); if (mFormat & ENCODING_MULTIPART_RELATED) - return SerializeDataMultipartRelated(data, stream, contentType); + return SerializeDataMultipartRelated(aData, aStream, aContentType); if (mFormat & ENCODING_MULTIPART_FORM_DATA) - return SerializeDataMultipartFormData(data, stream, contentType); + return SerializeDataMultipartFormData(aData, aStream, aContentType); NS_WARNING("unsupported submission encoding"); return NS_ERROR_UNEXPECTED; } nsresult -nsXFormsSubmissionElement::SerializeDataXML(nsIDOMNode *data, +nsXFormsSubmissionElement::SerializeDataXML(nsIDOMDocument *data, nsIInputStream **stream, - nsCString &contentType, - SubmissionAttachmentArray *attachments) + nsCString &contentType) { nsresult rv; nsAutoString mediaType; @@ -833,11 +830,6 @@ nsXFormsSubmissionElement::SerializeDataXML(nsIDOMNode *data, CopyUTF16toUTF8(mediaType, contentType); } - nsAutoString encoding; - mElement->GetAttribute(NS_LITERAL_STRING("encoding"), encoding); - if (encoding.IsEmpty()) - encoding.AssignLiteral("UTF-8"); - nsCOMPtr storage; NS_NewStorageStream(4096, PR_UINT32_MAX, getter_AddRefs(storage)); NS_ENSURE_TRUE(storage, NS_ERROR_OUT_OF_MEMORY); @@ -850,117 +842,14 @@ nsXFormsSubmissionElement::SerializeDataXML(nsIDOMNode *data, do_GetService("@mozilla.org/xmlextras/xmlserializer;1"); NS_ENSURE_STATE(serializer); - nsCOMPtr instDoc, submDoc; - data->GetOwnerDocument(getter_AddRefs(instDoc)); - - // XXX: We can't simply pass in data if !doc, since it crashes - if (!instDoc) { - // owner doc is null when the data node is the document (e.g., ref="/") - // so we can just get the document via QI. - instDoc = do_QueryInterface(data); - NS_ENSURE_STATE(instDoc); - - rv = CreateSubmissionDoc(instDoc, encoding, attachments, - getter_AddRefs(submDoc)); - } else { - // if we got a document, we need to create a new - rv = CreateSubmissionDoc(data, encoding, attachments, - getter_AddRefs(submDoc)); - } - - // clone and possibly modify the document for submission - NS_ENSURE_SUCCESS(rv, rv); - NS_ENSURE_STATE(submDoc); - - // We now need to add namespaces to the submission document. We get them - // from 3 sources - the main document's documentElement, the model and the - // xforms:instance that contains the submitted instance data node. - - nsCOMPtr instanceNode; - rv = nsXFormsUtils::GetInstanceNodeForData(data, getter_AddRefs(instanceNode)); - NS_ENSURE_SUCCESS(rv, rv); - - // add namespaces from the main document to the submission document, but only - // if the instance data is local, not remote. - PRBool serialize = PR_FALSE; - nsCOMPtr instanceElement(do_QueryInterface(instanceNode)); - - // make sure that this is a DOMElement. It won't be if it was lazy - // authored. Lazy authored instance documents don't inherit namespaces - // from parent nodes or the original document (in formsPlayer and Novell, - // at least). - if (instanceElement) { - PRBool hasSrc = PR_FALSE; - instanceElement->HasAttribute(NS_LITERAL_STRING("src"), &hasSrc); - serialize = !hasSrc; - } - - if (serialize) { - // Handle "includenamespaceprefixes" attribute, if present - nsStringHashSet* prefixHash = nsnull; - PRBool hasPrefixAttr = PR_FALSE; - mElement->HasAttribute(kIncludeNamespacePrefixes, &hasPrefixAttr); - if (hasPrefixAttr) { - rv = GetIncludeNSPrefixesAttr(&prefixHash); - NS_ENSURE_SUCCESS(rv, rv); - } - - // get the document element of the document we are going to submit - nsCOMPtr submDocElm; - submDoc->GetDocumentElement(getter_AddRefs(submDocElm)); - NS_ENSURE_STATE(submDocElm); - - // if submission document has empty default namespace attribute and if - // @includenamespaceprefixes attribute doesn't contain "#default" value then - // we should remove default namespace attribute (see the specs 11.3). - nsAutoString XMLNSAttrValue; - submDocElm->GetAttributeNS(kXMLNSNameSpaceURI, NS_LITERAL_STRING("xmlns"), - XMLNSAttrValue); - - if (XMLNSAttrValue.IsEmpty() && (!prefixHash || - !prefixHash->Contains(NS_LITERAL_STRING("#default")))) { - submDocElm->RemoveAttributeNS(kXMLNSNameSpaceURI, - NS_LITERAL_STRING("xmlns")); - } - - // handle namespaces on the root element of the instance document - nsCOMPtr instDocElm; - instDoc->GetDocumentElement(getter_AddRefs(instDocElm)); - nsCOMPtr instDocNode(do_QueryInterface(instDocElm)); - NS_ENSURE_STATE(instDocNode); - rv = AddNameSpaces(submDocElm, instDocNode, prefixHash); - NS_ENSURE_SUCCESS(rv, rv); - - // handle namespaces on the xforms:instance - rv = AddNameSpaces(submDocElm, instanceNode, prefixHash); - NS_ENSURE_SUCCESS(rv, rv); - - // handle namespaces on the model - nsCOMPtr model = GetModel(); - nsCOMPtr modelNode(do_QueryInterface(model)); - NS_ENSURE_STATE(modelNode); - rv = AddNameSpaces(submDocElm, modelNode, prefixHash); - NS_ENSURE_SUCCESS(rv, rv); - - // handle namespace on main document - nsCOMPtr mainDoc; - mElement->GetOwnerDocument(getter_AddRefs(mainDoc)); - NS_ENSURE_STATE(mainDoc); - - nsCOMPtr mainDocElm; - mainDoc->GetDocumentElement(getter_AddRefs(mainDocElm)); - nsCOMPtr mainDocNode(do_QueryInterface(mainDocElm)); - NS_ENSURE_STATE(mainDocNode); - - rv = AddNameSpaces(submDocElm, mainDocNode, prefixHash); - NS_ENSURE_SUCCESS(rv, rv); - - if (prefixHash) - delete prefixHash; - } - // Serialize content - rv = serializer->SerializeToStream(submDoc, sink, + nsAutoString encoding; + mElement->GetAttribute(NS_LITERAL_STRING("encoding"), encoding); + if (encoding.IsEmpty()) + encoding.AssignLiteral("UTF-8"); + + // XXX: should check @indent and possibly indent content. Bug 278761 + rv = serializer->SerializeToStream(data, sink, NS_LossyConvertUTF16toASCII(encoding)); NS_ENSURE_SUCCESS(rv, rv); @@ -972,7 +861,8 @@ nsXFormsSubmissionElement::SerializeDataXML(nsIDOMNode *data, } PRBool -nsXFormsSubmissionElement::CheckSameOrigin(nsIDocument *aBaseDocument, nsIURI *aTestURI) +nsXFormsSubmissionElement::CheckSameOrigin(nsIDocument *aBaseDocument, + nsIURI *aTestURI) { // we default to true to allow regular posts to work like html forms. PRBool allowSubmission = PR_TRUE; @@ -1056,9 +946,9 @@ nsXFormsSubmissionElement::CheckPermissionManager(nsIURI *aBaseURI) } nsresult -nsXFormsSubmissionElement::AddNameSpaces(nsIDOMElement* aTarget, - nsIDOMNode* aSource, - nsStringHashSet* aPrefixHash) +nsXFormsSubmissionElement::AddNameSpaces(nsIDOMElement *aTarget, + nsIDOMNode *aSource, + nsStringHashSet *aPrefixHash) { nsCOMPtr attrMap; nsCOMPtr attrNode; @@ -1145,12 +1035,124 @@ nsXFormsSubmissionElement::GetIncludeNSPrefixesAttr(nsStringHashSet** aHash) } nsresult -nsXFormsSubmissionElement::CreateSubmissionDoc(nsIDOMNode *source, - const nsString &encoding, - SubmissionAttachmentArray *attachments, - nsIDOMDocument **result) +nsXFormsSubmissionElement::CreateSubmissionDoc(nsIDOMNode *aRoot, + nsIDOMDocument **aReturnDoc) +{ + NS_ENSURE_ARG_POINTER(aRoot); + NS_ENSURE_ARG_POINTER(aReturnDoc); + + nsCOMPtr instDoc, submDoc; + aRoot->GetOwnerDocument(getter_AddRefs(instDoc)); + nsresult rv; + + if (!instDoc) { + // owner doc is null when the aRoot node is the document (e.g., ref="/") + // so we can just get the document via QI. + instDoc = do_QueryInterface(aRoot); + NS_ENSURE_STATE(instDoc); + + rv = CreatePurgedDoc(instDoc, getter_AddRefs(submDoc)); + } else { + rv = CreatePurgedDoc(aRoot, getter_AddRefs(submDoc)); + } + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_STATE(submDoc); + + // We now need to add namespaces to the submission document. We get them + // from 3 sources - the main document's documentElement, the model and the + // xforms:instance that contains the submitted instance data node. + + nsCOMPtr instanceNode; + rv = nsXFormsUtils::GetInstanceNodeForData(aRoot, + getter_AddRefs(instanceNode)); + NS_ENSURE_SUCCESS(rv, rv); + + // add namespaces from the main document to the submission document, but only + // if the instance data is local, not remote. + PRBool serialize = PR_FALSE; + nsCOMPtr instanceElement(do_QueryInterface(instanceNode)); + + // make sure that this is a DOMElement. It won't be if it was lazy + // authored. Lazy authored instance documents don't inherit namespaces + // from parent nodes or the original document (in formsPlayer and Novell, + // at least). + if (instanceElement) { + PRBool hasSrc = PR_FALSE; + instanceElement->HasAttribute(NS_LITERAL_STRING("src"), &hasSrc); + serialize = !hasSrc; + } + + if (serialize) { + // Handle "includenamespaceprefixes" attribute, if present + nsAutoPtr prefixHash; + PRBool hasPrefixAttr = PR_FALSE; + mElement->HasAttribute(kIncludeNamespacePrefixes, &hasPrefixAttr); + if (hasPrefixAttr) { + rv = GetIncludeNSPrefixesAttr(getter_Transfers(prefixHash)); + NS_ENSURE_SUCCESS(rv, rv); + } + + // get the document element of the document we are going to submit + nsCOMPtr submDocElm; + submDoc->GetDocumentElement(getter_AddRefs(submDocElm)); + NS_ENSURE_STATE(submDocElm); + + // if submission document has empty default namespace attribute and if + // @includenamespaceprefixes attribute doesn't contain "#default" value then + // we should remove default namespace attribute (see the specs 11.3). + nsAutoString XMLNSAttrValue; + submDocElm->GetAttributeNS(kXMLNSNameSpaceURI, NS_LITERAL_STRING("xmlns"), + XMLNSAttrValue); + + if (XMLNSAttrValue.IsEmpty() && (!prefixHash || + !prefixHash->Contains(NS_LITERAL_STRING("#default")))) { + submDocElm->RemoveAttributeNS(kXMLNSNameSpaceURI, + NS_LITERAL_STRING("xmlns")); + } + + // handle namespaces on the root element of the instance document + nsCOMPtr instDocElm; + instDoc->GetDocumentElement(getter_AddRefs(instDocElm)); + nsCOMPtr instDocNode(do_QueryInterface(instDocElm)); + NS_ENSURE_STATE(instDocNode); + rv = AddNameSpaces(submDocElm, instDocNode, prefixHash); + NS_ENSURE_SUCCESS(rv, rv); + + // handle namespaces on the xforms:instance + rv = AddNameSpaces(submDocElm, instanceNode, prefixHash); + NS_ENSURE_SUCCESS(rv, rv); + + // handle namespaces on the model + nsCOMPtr model = GetModel(); + nsCOMPtr modelNode(do_QueryInterface(model)); + NS_ENSURE_STATE(modelNode); + rv = AddNameSpaces(submDocElm, modelNode, prefixHash); + NS_ENSURE_SUCCESS(rv, rv); + + // handle namespace on main document + nsCOMPtr mainDoc; + mElement->GetOwnerDocument(getter_AddRefs(mainDoc)); + NS_ENSURE_STATE(mainDoc); + + nsCOMPtr mainDocElm; + mainDoc->GetDocumentElement(getter_AddRefs(mainDocElm)); + nsCOMPtr mainDocNode(do_QueryInterface(mainDocElm)); + NS_ENSURE_STATE(mainDocNode); + + rv = AddNameSpaces(submDocElm, mainDocNode, prefixHash); + NS_ENSURE_SUCCESS(rv, rv); + } + + NS_ADDREF(*aReturnDoc = submDoc); + + return NS_OK; +} + + +nsresult +nsXFormsSubmissionElement::CreatePurgedDoc(nsIDOMNode *source, + nsIDOMDocument **result) { - PRBool indent = GetBooleanAttr(NS_LITERAL_STRING("indent"), PR_FALSE); PRBool omit_xml_declaration = GetBooleanAttr(NS_LITERAL_STRING("omit-xml-declaration"), PR_FALSE); @@ -1183,11 +1185,16 @@ nsXFormsSubmissionElement::CreateSubmissionDoc(nsIDOMNode *source, getter_AddRefs(doc)); NS_ENSURE_STATE(doc); - if (!omit_xml_declaration) - { - nsAutoString buf - = NS_LITERAL_STRING("version=\"1.0\" encoding=\"") + encoding - + NS_LITERAL_STRING("\""); + if (!omit_xml_declaration) { + nsAutoString encoding; + mElement->GetAttribute(NS_LITERAL_STRING("encoding"), encoding); + if (encoding.IsEmpty()) + encoding.AssignLiteral("UTF-8"); + + nsAutoString buf = + NS_LITERAL_STRING("version=\"1.0\" encoding=\"") + + encoding + + NS_LITERAL_STRING("\""); nsCOMPtr pi; doc->CreateProcessingInstruction(NS_LITERAL_STRING("xml"), buf, @@ -1210,8 +1217,7 @@ nsXFormsSubmissionElement::CreateSubmissionDoc(nsIDOMNode *source, nsCOMPtr model = GetModel(); NS_ENSURE_STATE(model); - nsresult rv = CopyChildren(model, startNode, doc, doc, attachments, - cdataElements, indent, 0); + nsresult rv = CopyChildren(model, startNode, doc, doc, cdataElements, 0); NS_ENSURE_SUCCESS(rv, rv); NS_ADDREF(*result = doc); @@ -1219,196 +1225,158 @@ nsXFormsSubmissionElement::CreateSubmissionDoc(nsIDOMNode *source, } nsresult -nsXFormsSubmissionElement::CopyChildren(nsIModelElementPrivate* model, - nsIDOMNode *source, nsIDOMNode *dest, - nsIDOMDocument *destDoc, - SubmissionAttachmentArray *attachments, - const nsString &cdataElements, - PRBool indent, PRUint32 depth) +nsXFormsSubmissionElement::CreateAttachments(nsIModelElementPrivate *aModel, + nsIDOMNode *aNode, + SubmissionAttachmentArray *aAttachments) { - nsCOMPtr currentNode(source), node, destChild; + nsCOMPtr currentNode(aNode); - while (currentNode) - { - // if not indenting, then strip all unnecessary whitespace + while (currentNode) { + // If |currentNode| is an element node of type 'xsd:anyURI', we need to + // generate a ContentID for the child of this element, and append a new + // attachment to the attachments array. + PRUint32 encType; + nsresult rv; + if (NS_SUCCEEDED(GetElementEncodingType(currentNode, &encType, aModel)) && + encType == ELEMENT_ENCTYPE_URI) { + // ok, looks like we have a local file to upload + + nsCOMPtr content = do_QueryInterface(currentNode); + NS_ENSURE_STATE(content); + + nsIFile *file = + NS_STATIC_CAST(nsIFile *, + content->GetProperty(nsXFormsAtoms::uploadFileProperty)); + // NOTE: this value may be null if a file hasn't been selected. + + nsCString cid; + MakeMultipartContentID(cid); + + nsAutoString cidURI; + cidURI.AssignLiteral("cid:"); + AppendASCIItoUTF16(cid, cidURI); + + aAttachments->Append(file, cid); + + rv = currentNode->SetNodeValue(cidURI); + NS_ENSURE_SUCCESS(rv, rv); + } + + nsCOMPtr child; + currentNode->GetFirstChild(getter_AddRefs(child)); + if (child) { + rv = CreateAttachments(aModel, child, aAttachments); + NS_ENSURE_SUCCESS(rv, rv); + } + + nsCOMPtr node; + currentNode->GetNextSibling(getter_AddRefs(node)); + currentNode.swap(node); + } + + return NS_OK; +} + + +nsresult +nsXFormsSubmissionElement::CopyChildren(nsIModelElementPrivate *aModel, + nsIDOMNode *aSource, + nsIDOMNode *aDest, + nsIDOMDocument *aDestDoc, + const nsString &aCDATAElements, + PRUint32 aDepth) +{ + nsCOMPtr currentNode(aSource), node, destChild; + + while (currentNode) { // XXX importing the entire node is not quite right here... we also have // to iterate over the attributes since the attributes could somehow // (remains to be determined) reference external entities. - destDoc->ImportNode(currentNode, PR_FALSE, getter_AddRefs(destChild)); + aDestDoc->ImportNode(currentNode, PR_FALSE, getter_AddRefs(destChild)); NS_ENSURE_STATE(destChild); PRUint16 type; destChild->GetNodeType(&type); - if (type == nsIDOMNode::PROCESSING_INSTRUCTION_NODE) - { - nsCOMPtr pi = do_QueryInterface(destChild); - NS_ENSURE_STATE(pi); + switch (type) { + case nsIDOMNode::PROCESSING_INSTRUCTION_NODE: { + nsCOMPtr pi = do_QueryInterface(destChild); + NS_ENSURE_STATE(pi); - // ignore "" since we would have already inserted this. + // ignore "" since we would have already inserted this. + // XXXbeaufour: depends on omit-xml-decl, does it not? - nsAutoString target; - pi->GetTarget(target); - if (!target.EqualsLiteral("xml")) - dest->AppendChild(destChild, getter_AddRefs(node)); - } - else if (type == nsIDOMNode::TEXT_NODE) - { - // honor cdata-section-elements (see xslt spec section 16.1) - if (cdataElements.IsEmpty()) - { - dest->AppendChild(destChild, getter_AddRefs(node)); + nsAutoString target; + pi->GetTarget(target); + if (!target.EqualsLiteral("xml")) + aDest->AppendChild(destChild, getter_AddRefs(node)); + break; } - else - { - currentNode->GetParentNode(getter_AddRefs(node)); - NS_ENSURE_STATE(node); - nsAutoString name; - node->GetNodeName(name); - // check to see if name is mentioned on cdataElements - if (HasToken(cdataElements, name)) - { - nsCOMPtr textNode = do_QueryInterface(destChild); - NS_ENSURE_STATE(textNode); + case nsIDOMNode::TEXT_NODE: { + // honor cdata-section-elements (see xslt spec section 16.1) + if (aCDATAElements.IsEmpty()) { + aDest->AppendChild(destChild, getter_AddRefs(node)); + } else { + currentNode->GetParentNode(getter_AddRefs(node)); + NS_ENSURE_STATE(node); - nsAutoString textData; - textNode->GetData(textData); + nsAutoString name; + node->GetNodeName(name); + // check to see if name is mentioned on cdataElements + if (HasToken(aCDATAElements, name)) { + nsCOMPtr textNode = do_QueryInterface(destChild); + NS_ENSURE_STATE(textNode); - nsCOMPtr cdataNode; - destDoc->CreateCDATASection(textData, getter_AddRefs(cdataNode)); + nsAutoString textData; + textNode->GetData(textData); - dest->AppendChild(cdataNode, getter_AddRefs(node)); - } - else - { - dest->AppendChild(destChild, getter_AddRefs(node)); + nsCOMPtr cdataNode; + aDestDoc->CreateCDATASection(textData, getter_AddRefs(cdataNode)); + + aDest->AppendChild(cdataNode, getter_AddRefs(node)); + } else { + aDest->AppendChild(destChild, getter_AddRefs(node)); + } } } - } - else - { - PRUint16 handleNodeResult; - model->HandleInstanceDataNode(currentNode, &handleNodeResult); + default: { + PRUint16 handleNodeResult; + aModel->HandleInstanceDataNode(currentNode, &handleNodeResult); - /* - * SUBMIT_SERIALIZE_NODE - node is to be serialized - * SUBMIT_SKIP_NODE - node is not to be serialized - * SUBMIT_ABORT_SUBMISSION - abort submission (invalid node or empty required node) - */ - if (handleNodeResult == nsIModelElementPrivate::SUBMIT_SKIP_NODE) { - // skip node and subtree - currentNode->GetNextSibling(getter_AddRefs(node)); - currentNode.swap(node); - continue; - } else if (handleNodeResult == nsIModelElementPrivate::SUBMIT_ABORT_SUBMISSION) { - // abort - return NS_ERROR_ILLEGAL_VALUE; - } + /* + * SUBMIT_SERIALIZE_NODE - node is to be serialized + * SUBMIT_SKIP_NODE - node is not to be serialized + * SUBMIT_ABORT_SUBMISSION - abort submission (invalid node or empty required node) + */ + if (handleNodeResult == nsIModelElementPrivate::SUBMIT_SKIP_NODE) { + // skip node and subtree + currentNode->GetNextSibling(getter_AddRefs(node)); + currentNode.swap(node); + continue; + } else if (handleNodeResult == nsIModelElementPrivate::SUBMIT_ABORT_SUBMISSION) { + // abort + nsXFormsUtils::ReportError(NS_LITERAL_STRING("warnSubmitInvalidNode"), + currentNode, nsIScriptError::warningFlag); + return NS_ERROR_ILLEGAL_VALUE; + } - // If |currentNode| is an element node of type 'xsd:anyURI', and if we - // have an attachments array, then we need to perform multipart/related - // processing (i.e., generate a ContentID for the child of this element, - // and append a new attachment to the attachments array). - - PRUint32 encType; - if (attachments && - NS_SUCCEEDED(GetElementEncodingType(currentNode, &encType, model)) && - encType == ELEMENT_ENCTYPE_URI) - { - // ok, looks like we have a local file to upload - - nsCOMPtr content = do_QueryInterface(currentNode); - NS_ENSURE_STATE(content); - - nsIFile *file = - NS_STATIC_CAST(nsIFile *, - content->GetProperty(nsXFormsAtoms::uploadFileProperty)); - // NOTE: this value may be null if a file hasn't been selected. - - nsCString cid; - MakeMultipartContentID(cid); - - nsAutoString cidURI; - cidURI.AssignLiteral("cid:"); - AppendASCIItoUTF16(cid, cidURI); - - nsCOMPtr text; - destDoc->CreateTextNode(cidURI, getter_AddRefs(text)); - NS_ENSURE_STATE(text); - - destChild->AppendChild(text, getter_AddRefs(node)); - dest->AppendChild(destChild, getter_AddRefs(node)); - - attachments->Append(file, cid); - } - else - { - dest->AppendChild(destChild, getter_AddRefs(node)); + aDest->AppendChild(destChild, getter_AddRefs(node)); // recurse nsCOMPtr startNode; currentNode->GetFirstChild(getter_AddRefs(startNode)); - nsresult rv = CopyChildren(model, startNode, destChild, destDoc, - attachments, cdataElements, indent, - depth + 1); + nsresult rv = CopyChildren(aModel, startNode, destChild, aDestDoc, + aCDATAElements, aDepth + 1); NS_ENSURE_SUCCESS(rv, rv); + } } - - if (!depth) { - break; - } - - currentNode->GetNextSibling(getter_AddRefs(node)); - currentNode.swap(node); - } - return NS_OK; -} - -nsresult -nsXFormsSubmissionElement::CanSubmit(nsIDOMNode *aTopNode, - nsIModelElementPrivate *aModel, - PRBool aCheckSiblings) -{ - nsCOMPtr currentNode(aTopNode), node; - - while (currentNode) { - PRUint16 handleNodeResult; - aModel->HandleInstanceDataNode(currentNode, &handleNodeResult); - - /* - * SUBMIT_SERIALIZE_NODE - node is to be serialized - * SUBMIT_SKIP_NODE - node is not to be serialized - * SUBMIT_ABORT_SUBMISSION - abort submission - * (invalid node or empty required node) - */ - if (handleNodeResult == nsIModelElementPrivate::SUBMIT_SKIP_NODE) { - // skip node and subtree - currentNode->GetNextSibling(getter_AddRefs(node)); - currentNode.swap(node); - continue; - } else if (handleNodeResult == - nsIModelElementPrivate::SUBMIT_ABORT_SUBMISSION) { - - // abort - return NS_ERROR_ABORT; - } - NS_ASSERTION( - handleNodeResult == nsIModelElementPrivate::SUBMIT_SERIALIZE_NODE, - "unexpected node type"); - - // recurse - nsCOMPtr firstChild; - currentNode->GetFirstChild(getter_AddRefs(firstChild)); - - nsresult rv = CanSubmit(firstChild, aModel); - NS_ENSURE_SUCCESS(rv, rv); - - if (!aCheckSiblings) { + + if (!aDepth) { break; } @@ -1420,11 +1388,19 @@ nsXFormsSubmissionElement::CanSubmit(nsIDOMNode *aTopNode, } nsresult -nsXFormsSubmissionElement::SerializeDataURLEncoded(nsIDOMNode *data, +nsXFormsSubmissionElement::SerializeDataURLEncoded(nsIDOMDocument *data, nsCString &uri, nsIInputStream **stream, nsCString &contentType) { + // 'get' method: + // The URI is constructed as follows: + // o The submit URI from the action attribute is examined. If it does not + // already contain a ? (question mark) character, one is appended. If it + // does already contain a question mark character, then a separator + // character from the attribute separator is appended. + // o The serialized form data is appended to the URI. + nsCAutoString separator; { nsAutoString temp; @@ -1556,7 +1532,7 @@ nsXFormsSubmissionElement::AppendURLEncodedData(nsIDOMNode *data, } nsresult -nsXFormsSubmissionElement::SerializeDataMultipartRelated(nsIDOMNode *data, +nsXFormsSubmissionElement::SerializeDataMultipartRelated(nsIDOMDocument *data, nsIInputStream **stream, nsCString &contentType) { @@ -1573,13 +1549,15 @@ nsXFormsSubmissionElement::SerializeDataMultipartRelated(nsIDOMNode *data, MakeMultipartContentID(start); - // XXX we need to extend SerializeDataXML so that it has a mode in which it - // generates ContentIDs for elements of type xsd:anyURI, and returns a - // list of ContentID <-> URI mappings. + nsresult rv; + nsCOMPtr model(GetModel()); + NS_ENSURE_STATE(model); + SubmissionAttachmentArray attachments; + rv = CreateAttachments(model, data, &attachments); + NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr xml; - SubmissionAttachmentArray attachments; - nsresult rv = SerializeDataXML(data, getter_AddRefs(xml), type, &attachments); + rv = SerializeDataXML(data, getter_AddRefs(xml), type); NS_ENSURE_SUCCESS(rv, rv); // XXX we should output a 'charset=' with the 'Content-Type' header @@ -1594,8 +1572,7 @@ nsXFormsSubmissionElement::SerializeDataMultipartRelated(nsIDOMNode *data, multiStream->AppendStream(xml); - for (PRUint32 i=0; i fileStream; @@ -1644,7 +1621,7 @@ nsXFormsSubmissionElement::SerializeDataMultipartRelated(nsIDOMNode *data, } nsresult -nsXFormsSubmissionElement::SerializeDataMultipartFormData(nsIDOMNode *data, +nsXFormsSubmissionElement::SerializeDataMultipartFormData(nsIDOMDocument *data, nsIInputStream **stream, nsCString &contentType) { diff --git a/extensions/xforms/nsXFormsSubmissionElement.h b/extensions/xforms/nsXFormsSubmissionElement.h index 7a577f478da..004d0f8a7a4 100644 --- a/extensions/xforms/nsXFormsSubmissionElement.h +++ b/extensions/xforms/nsXFormsSubmissionElement.h @@ -105,31 +105,28 @@ public: NS_HIDDEN_(nsresult) GetSelectedInstanceElement(const nsAString &aInstance, nsIModelElementPrivate *aModel, nsIInstanceElementPrivate **result); - NS_HIDDEN_(nsresult) SerializeData(nsIDOMNode *data, nsCString &uri, + NS_HIDDEN_(nsresult) SerializeData(nsIDOMDocument *data, nsCString &uri, nsIInputStream **, nsCString &contentType); - NS_HIDDEN_(nsresult) SerializeDataXML(nsIDOMNode *data, nsIInputStream **, - nsCString &contentType, - SubmissionAttachmentArray *); - NS_HIDDEN_(nsresult) CreateSubmissionDoc(nsIDOMNode *source, - const nsString &encoding, - SubmissionAttachmentArray *, - nsIDOMDocument **result); + NS_HIDDEN_(nsresult) SerializeDataXML(nsIDOMDocument *data, nsIInputStream **, + nsCString &contentType); + NS_HIDDEN_(nsresult) CreatePurgedDoc(nsIDOMNode *source, + nsIDOMDocument **result); NS_HIDDEN_(nsresult) CopyChildren(nsIModelElementPrivate* model, nsIDOMNode *source, nsIDOMNode *dest, nsIDOMDocument *destDoc, - SubmissionAttachmentArray *, const nsString &cdataElements, - PRBool indent, PRUint32 depth); - NS_HIDDEN_(nsresult) SerializeDataURLEncoded(nsIDOMNode *data, nsCString &uri, + PRUint32 depth); + NS_HIDDEN_(nsresult) SerializeDataURLEncoded(nsIDOMDocument *data, + nsCString &uri, nsIInputStream **, nsCString &contentType); NS_HIDDEN_(void) AppendURLEncodedData(nsIDOMNode *data, const nsCString &sep, nsCString &buf); - NS_HIDDEN_(nsresult) SerializeDataMultipartRelated(nsIDOMNode *data, + NS_HIDDEN_(nsresult) SerializeDataMultipartRelated(nsIDOMDocument *data, nsIInputStream **, nsCString &contentType); - NS_HIDDEN_(nsresult) SerializeDataMultipartFormData(nsIDOMNode *data, + NS_HIDDEN_(nsresult) SerializeDataMultipartFormData(nsIDOMDocument *data, nsIInputStream **, nsCString &contentType); NS_HIDDEN_(nsresult) AppendMultipartFormData(nsIDOMNode *data, @@ -169,21 +166,6 @@ private: nsStringHashSet* aPrefixHash); nsresult GetIncludeNSPrefixesAttr(nsStringHashSet** aHash); - /** - * This walks the DOM tree, starting at aTopNode and invokes - * model->HandleInstanceDataNode()that ensures that the instance is valid, - * required conditions met...if so, then can submit. - * - * @param aTopNode Root instance node of tree to be evaluated - * @param aModel The model for the submission - * @param aCheckSiblings Check siblings too? - * @return NS_ERROR_ABORT if instance is not valid and empty - * required nodes, otherwise return NS_OK. - * - */ - nsresult CanSubmit(nsIDOMNode *aTopNode, nsIModelElementPrivate *aModel, - PRBool aCheckSiblings = PR_TRUE); - /** * Send xforms-submit-done/-error, depending on |aSucceeded| * @@ -191,6 +173,30 @@ private: * */ void EndSubmit(PRBool aSucceeded); + + /** + * Create submission document. + * + * This creates a new document, include namespaces, purges non-relevant + * nodes, and checks simple type validity. If a check fails, no document + * will be returned. + * + * @param aRoot The source node + * @param aReturnDoc The resulting document + */ + nsresult CreateSubmissionDoc(nsIDOMNode *aRoot, + nsIDOMDocument** aReturnDoc); + + /** + * Run through document and create attachment ids for xsd:anyURI nodes. This + * is used for "multipart/related". + * + * @param aModel The model to use + * @param aDoc The document to run through + * @param aAttachments Array of files and attachment ids + */ + nsresult CreateAttachments(nsIModelElementPrivate *aModel, nsIDOMNode *aDoc, + SubmissionAttachmentArray *aAttachments); }; NS_HIDDEN_(nsresult) diff --git a/extensions/xforms/resources/locale/en-US/xforms.properties b/extensions/xforms/resources/locale/en-US/xforms.properties index db91bbc9e2e..3b6e792a5f1 100644 --- a/extensions/xforms/resources/locale/en-US/xforms.properties +++ b/extensions/xforms/resources/locale/en-US/xforms.properties @@ -76,9 +76,13 @@ inlineInstanceNoChildError = XForms Error (37): Inline instance has no child ele inlineInstanceMultipleElementsError = XForms Error (38): Inline instance has multiple child elements. This is illegal. # Warning Messages: -warnSOAP = XForms Warning (1): You are using the SOAP post feature, which is an experimental feature! Beware that the functionality might change, and forms may stop working at any time. -warnMailtoBodyParam = XForms Warning (2): The submission action uri already contains a body parameter. -instDocumentInvalid = XForms Warning (3): Instance document did not validate. +warnSOAP = XForms Warning (1): You are using the SOAP post feature, which is an experimental feature! Beware that the functionality might change, and forms may stop working at any time. +warnMailtoBodyParam = XForms Warning (2): The submission action uri already contains a body parameter. +instDocumentInvalid = XForms Warning (3): Instance document did not validate. +warnSubmitAlreadyRunning = XForms Warning (4): Submission is already running. +warnSubmitInvalidNode = XForms Warning (5): Submission validation failed for node +warnSubmitSerializeFailed = XForms Warning (6): Submission failed to serialize data +warnSubmitNetworkFailure = XForms Warning (7): Submission could not send data to the network # XForms Permission Messages: xformsXDPermissionDialogTitle = Allowed Sites - XForms Cross Domain Access