Back to index

lightning-sunbird  0.9+nobinonly
nsXFormsSubmissionElement.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla XForms support.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * IBM Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2004
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *  Darin Fisher <darin@meer.net>
00024  *  Doron Rosenberg <doronr@us.ibm.com>
00025  *  Merle Sterling <msterlin@us.ibm.com>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either the GNU General Public License Version 2 or later (the "GPL"), or
00029  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #ifdef DEBUG_darinf
00042 #include <stdio.h>
00043 #define LOG(args) printf args
00044 #else
00045 #define LOG(args)
00046 #endif
00047 
00048 #include <stdlib.h>
00049 
00050 #include "nsXFormsSubmissionElement.h"
00051 #include "nsXFormsAtoms.h"
00052 #include "nsIInstanceElementPrivate.h"
00053 #include "nsIXTFGenericElementWrapper.h"
00054 #include "nsIDOMDocument.h"
00055 #include "nsIDOMElement.h"
00056 #include "nsIDOMAttr.h"
00057 #include "nsIDOMText.h"
00058 #include "nsIDOMCDATASection.h"
00059 #include "nsIDOMEvent.h"
00060 #include "nsIDOMDocumentEvent.h"
00061 #include "nsIDOMEventTarget.h"
00062 #include "nsIDOMEventListener.h"
00063 #include "nsIDOM3Node.h"
00064 #include "nsIDOMNodeList.h"
00065 #include "nsIDOMXMLDocument.h"
00066 #include "nsIDOMXPathResult.h"
00067 #include "nsIDOMSerializer.h"
00068 #include "nsIDOMDOMImplementation.h"
00069 #include "nsIDOMProcessingInstruction.h"
00070 #include "nsIDOMParser.h"
00071 #include "nsIAttribute.h"
00072 #include "nsComponentManagerUtils.h"
00073 #include "nsStringStream.h"
00074 #include "nsIDocShell.h"
00075 #include "nsIInputStream.h"
00076 #include "nsIStorageStream.h"
00077 #include "nsIMultiplexInputStream.h"
00078 #include "nsIMIMEInputStream.h"
00079 #include "nsINameSpaceManager.h"
00080 #include "nsIContent.h"
00081 #include "nsIFileURL.h"
00082 #include "nsIMIMEService.h"
00083 #include "nsIUploadChannel.h"
00084 #include "nsIHttpChannel.h"
00085 #include "nsIScriptSecurityManager.h"
00086 #include "nsIPipe.h"
00087 #include "nsLinebreakConverter.h"
00088 #include "nsEscape.h"
00089 #include "nsString.h"
00090 #include "nsMemory.h"
00091 #include "nsCOMPtr.h"
00092 #include "nsNetUtil.h"
00093 #include "nsXFormsUtils.h"
00094 #include "nsIDOMNamedNodeMap.h"
00095 #include "nsIPermissionManager.h"
00096 #include "nsIPrefBranch.h"
00097 #include "nsIPrefService.h"
00098 #include "nsIMIMEHeaderParam.h"
00099 #include "nsIExternalProtocolService.h"
00100 #include "nsEscape.h"
00101 #include "nsAutoPtr.h"
00102 
00103 // namespace literals
00104 #define kXMLNSNameSpaceURI \
00105         NS_LITERAL_STRING("http://www.w3.org/2000/xmlns/")
00106 
00107 #define kIncludeNamespacePrefixes \
00108         NS_LITERAL_STRING("includenamespaceprefixes")
00109 
00110 // submission methods
00111 #define METHOD_GET                    0x01
00112 #define METHOD_POST                   0x02
00113 #define METHOD_PUT                    0x04
00114 
00115 // submission encodings
00116 #define ENCODING_XML                  0x10    // application/xml
00117 #define ENCODING_URL                  0x20    // application/x-www-form-urlencoded
00118 #define ENCODING_MULTIPART_RELATED    0x40    // multipart/related
00119 #define ENCODING_MULTIPART_FORM_DATA  0x80    // multipart/form-data
00120 
00121 // submission errors
00122 #define kError_SubmissionInProgress \
00123         NS_LITERAL_STRING("submission-in-progress");
00124 #define kError_NoData \
00125         NS_LITERAL_STRING("no-data");
00126 #define kError_ValidationError \
00127         NS_LITERAL_STRING("validation-error");
00128 #define kError_ParseError \
00129         NS_LITERAL_STRING("parse-error");
00130 #define kError_ResourceError \
00131         NS_LITERAL_STRING("resource-error");
00132 #define kError_TargetError \
00133         NS_LITERAL_STRING("target-error");
00134 
00135 struct SubmissionFormat
00136 {
00137   const char *method;
00138   PRUint32    format;
00139 };
00140 
00141 static const SubmissionFormat sSubmissionFormats[] = {
00142   { "post",            ENCODING_XML                 | METHOD_POST },
00143   { "get",             ENCODING_URL                 | METHOD_GET  },
00144   { "put",             ENCODING_XML                 | METHOD_PUT  },
00145   { "multipart-post",  ENCODING_MULTIPART_RELATED   | METHOD_POST },
00146   { "form-data-post",  ENCODING_MULTIPART_FORM_DATA | METHOD_POST },
00147   { "urlencoded-post", ENCODING_URL                 | METHOD_POST }
00148 };
00149 
00150 static PRUint32
00151 GetSubmissionFormat(nsIDOMElement *aElement)
00152 {
00153   nsAutoString method;
00154   aElement->GetAttribute(NS_LITERAL_STRING("method"), method);
00155 
00156   NS_ConvertUTF16toUTF8 utf8method(method);
00157   for (PRUint32 i=0; i<NS_ARRAY_LENGTH(sSubmissionFormats); ++i)
00158   {
00159     // XXX case sensitive compare ok?
00160     if (utf8method.Equals(sSubmissionFormats[i].method))
00161       return sSubmissionFormats[i].format;
00162   }
00163   return 0;
00164 }
00165 
00166 #define ELEMENT_ENCTYPE_STRING 0
00167 #define ELEMENT_ENCTYPE_URI    1
00168 #define ELEMENT_ENCTYPE_BASE64 2
00169 #define ELEMENT_ENCTYPE_HEX    3
00170 
00171 static void
00172 MakeMultipartBoundary(nsCString &boundary)
00173 {
00174   boundary.AssignLiteral("---------------------------");
00175   boundary.AppendInt(rand());
00176   boundary.AppendInt(rand());
00177   boundary.AppendInt(rand());
00178 }
00179 
00180 static void
00181 MakeMultipartContentID(nsCString &cid)
00182 {
00183   cid.AppendInt(rand(), 16);
00184   cid.Append('.');
00185   cid.AppendInt(rand(), 16);
00186   cid.AppendLiteral("@mozilla.org");
00187 }
00188 
00189 static nsresult
00190 URLEncode(const nsString &buf, nsCString &result)
00191 {
00192   // 1. convert to UTF-8
00193   // 2. normalize newlines to \r\n
00194   // 3. escape, converting ' ' to '+'
00195 
00196   NS_ConvertUTF16toUTF8 utf8Buf(buf);
00197 
00198   char *convertedBuf =
00199       nsLinebreakConverter::ConvertLineBreaks(utf8Buf.get(),
00200                                               nsLinebreakConverter::eLinebreakAny,
00201                                               nsLinebreakConverter::eLinebreakNet);
00202   NS_ENSURE_TRUE(convertedBuf, NS_ERROR_OUT_OF_MEMORY);
00203 
00204   char *escapedBuf = nsEscape(convertedBuf, url_XPAlphas);
00205   nsMemory::Free(convertedBuf);
00206 
00207   NS_ENSURE_TRUE(escapedBuf, NS_ERROR_OUT_OF_MEMORY);
00208 
00209   result.Adopt(escapedBuf);
00210   return NS_OK;
00211 }
00212 
00213 static void
00214 GetMimeTypeFromFile(nsIFile *file, nsCString &result)
00215 {
00216   nsCOMPtr<nsIMIMEService> mime = do_GetService("@mozilla.org/mime;1");
00217   if (mime)
00218     mime->GetTypeFromFile(file, result);
00219   if (result.IsEmpty())
00220     result.Assign("application/octet-stream");
00221 }
00222 
00223 static PRBool
00224 HasToken(const nsString &aTokenList, const nsString &aToken)
00225 {
00226   PRInt32 i = aTokenList.Find(aToken);
00227   if (i == kNotFound)
00228     return PR_FALSE;
00229   
00230   // else, check that leading and trailing characters are either
00231   // not present or whitespace (#x20, #x9, #xD or #xA).
00232 
00233   if (i > 0)
00234   {
00235     PRUnichar c = aTokenList[i - 1];
00236     if (!(c == 0x20 || c == 0x9 || c == 0xD || c == 0xA))
00237       return PR_FALSE;
00238   }
00239 
00240   if (i + aToken.Length() < aTokenList.Length())
00241   {
00242     PRUnichar c = aTokenList[i + aToken.Length()];
00243     if (!(c == 0x20 || c == 0x9 || c == 0xD || c == 0xA))
00244       return PR_FALSE;
00245   }
00246 
00247   return PR_TRUE;
00248 }
00249 
00250 // structure used to store information needed to generate attachments
00251 // for multipart/related submission.
00252 struct SubmissionAttachment
00253 {
00254   nsCOMPtr<nsIFile> file;
00255   nsCString         cid;
00256 };
00257 
00258 // an array of SubmissionAttachment objects
00259 class SubmissionAttachmentArray : nsVoidArray
00260 {
00261 public:
00262   SubmissionAttachmentArray() {}
00263  ~SubmissionAttachmentArray()
00264   {
00265     for (PRUint32 i=0; i<Count(); ++i)
00266       delete (SubmissionAttachment *) ElementAt(i);
00267   }
00268   nsresult Append(nsIFile *file, const nsCString &cid)
00269   {
00270     SubmissionAttachment *a = new SubmissionAttachment;
00271     if (!a)
00272       return NS_ERROR_OUT_OF_MEMORY;
00273     a->file = file;
00274     a->cid = cid;
00275     AppendElement(a);
00276     return NS_OK;
00277   }
00278   PRUint32 Count() const
00279   {
00280     return (PRUint32) nsVoidArray::Count();
00281   }
00282   SubmissionAttachment *Item(PRUint32 index)
00283   {
00284     return (SubmissionAttachment *) ElementAt(index);
00285   }
00286 };
00287 
00288 // nsISupports
00289 
00290 NS_IMPL_ISUPPORTS_INHERITED4(nsXFormsSubmissionElement,
00291                              nsXFormsStubElement,
00292                              nsIRequestObserver,
00293                              nsIXFormsSubmissionElement,
00294                              nsIInterfaceRequestor,
00295                              nsIChannelEventSink)
00296 
00297 // nsIXTFElement
00298 
00299 NS_IMETHODIMP
00300 nsXFormsSubmissionElement::OnDestroyed()
00301 {
00302   mElement = nsnull;
00303   return NS_OK;
00304 }
00305 
00306 NS_IMETHODIMP
00307 nsXFormsSubmissionElement::HandleDefault(nsIDOMEvent *aEvent, PRBool *aHandled)
00308 {
00309   if (!nsXFormsUtils::EventHandlingAllowed(aEvent, mElement))
00310     return NS_OK;
00311 
00312   nsAutoString type;
00313   aEvent->GetType(type);
00314   if (type.EqualsLiteral("xforms-submit")) {
00315     // If the submission is already active, do nothing.
00316     if (!mSubmissionActive && NS_FAILED(Submit())) {
00317       EndSubmit(PR_FALSE);
00318     }
00319 
00320     *aHandled = PR_TRUE;
00321   } else if (type.EqualsLiteral("xforms-submit-serialize")) {
00322     nsCOMPtr<nsIXFormsDOMEvent> xfEvent = do_QueryInterface(aEvent);
00323     if (xfEvent) {
00324       nsCOMPtr<nsIXFormsContextInfo> contextInfo;
00325       nsAutoString contextName;
00326       contextName.AssignLiteral("submission-body");
00327       xfEvent->GetContextInfo(contextName, getter_AddRefs(contextInfo));
00328       if (contextInfo) {
00329         nsAutoString submissionBody;
00330         contextInfo->GetStringValue(submissionBody);
00331         if (!submissionBody.EqualsLiteral(" ")) {
00332           // Save the new submission body.
00333           contextInfo->GetNodeValue(getter_AddRefs(mSubmissionBody));
00334         }
00335       }
00336     }
00337     *aHandled = PR_TRUE;
00338   } else {
00339     *aHandled = PR_FALSE;
00340   }
00341 
00342   return NS_OK;
00343 }
00344 
00345 // nsIXFormsSubmissionElement
00346 
00347 NS_IMETHODIMP
00348 nsXFormsSubmissionElement::SetActivator(nsIXFormsSubmitElement* aActivator)
00349 {
00350   if (!mActivator && !mSubmissionActive)
00351     mActivator = aActivator;
00352   return NS_OK;
00353 }
00354 
00355 // nsIXTFGenericElement
00356 
00357 NS_IMETHODIMP
00358 nsXFormsSubmissionElement::OnCreated(nsIXTFGenericElementWrapper *aWrapper)
00359 {
00360   aWrapper->SetNotificationMask(nsIXTFElement::NOTIFY_HANDLE_DEFAULT);
00361 
00362   nsCOMPtr<nsIDOMElement> node;
00363   aWrapper->GetElementNode(getter_AddRefs(node));
00364 
00365   // It's ok to keep a weak pointer to mElement.  mElement will have an
00366   // owning reference to this object, so as long as we null out mElement in
00367   // OnDestroyed, it will always be valid.
00368 
00369   mElement = node;
00370   NS_ASSERTION(mElement, "Wrapper is not an nsIDOMElement, we'll crash soon");
00371 
00372   return NS_OK;
00373 }
00374 
00375 // nsIInterfaceRequestor
00376 
00377 NS_IMETHODIMP
00378 nsXFormsSubmissionElement::GetInterface(const nsIID & aIID, void **aResult)
00379 {
00380   *aResult = nsnull;
00381   return QueryInterface(aIID, aResult);
00382 }
00383 
00384 // nsIChannelEventSink
00385 
00386 // It is possible that the submission element could well on its way to invalid
00387 // by the time that the below handlers are called.  If the document was
00388 // destroyed after we've already started submitting data then this will cause
00389 // mElement to become null.  Since the channel will hold a nsCOMPtr
00390 // to the nsXFormsSubmissionElement as a callback to the channel, this prevents
00391 // it from being freed up.  The channel will still be able to call the
00392 // nsIStreamListener functions that we implement here.  And calling
00393 // mChannel->Cancel() is no guarantee that these other notifications won't come
00394 // through if the timing is wrong.  So we need to check for mElement below
00395 // before we handle any of the stream notifications.
00396 
00397 
00398 NS_IMETHODIMP
00399 nsXFormsSubmissionElement::OnChannelRedirect(nsIChannel *aOldChannel,
00400                                              nsIChannel *aNewChannel,
00401                                              PRUint32    aFlags)
00402 {
00403   if (!mElement) {
00404     return NS_OK;
00405   }
00406 
00407   NS_PRECONDITION(aNewChannel, "Redirect without a channel?");
00408   nsCOMPtr<nsIURI> newURI;
00409   nsresult rv = aNewChannel->GetURI(getter_AddRefs(newURI));
00410   NS_ENSURE_SUCCESS(rv, rv);
00411 
00412   NS_ENSURE_STATE(mElement);
00413   nsCOMPtr<nsIDOMDocument> domDoc;
00414   mElement->GetOwnerDocument(getter_AddRefs(domDoc));
00415   nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
00416   NS_ENSURE_STATE(doc);
00417 
00418   if (!CheckSameOrigin(doc, newURI)) {
00419     nsXFormsUtils::ReportError(NS_LITERAL_STRING("submitSendOrigin"),
00420                                mElement);
00421     return NS_ERROR_ABORT;
00422   }
00423 
00424   return NS_OK;
00425 }
00426 
00427 NS_IMETHODIMP
00428 nsXFormsSubmissionElement::OnStartRequest(nsIRequest  *aRequest,
00429                                           nsISupports *aCtx)
00430 {
00431   return NS_OK;
00432 }
00433 
00434 NS_IMETHODIMP
00435 nsXFormsSubmissionElement::OnStopRequest(nsIRequest  *aRequest,
00436                                          nsISupports *aCtx,
00437                                          nsresult     aStatus)
00438 {
00439   LOG(("xforms submission complete [status=%x]\n", aStatus));
00440 
00441   if (!mElement) {
00442     return NS_OK;
00443   }
00444 
00445   nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
00446   NS_ASSERTION(channel, "request should be a channel");
00447 
00448   PRBool succeeded = NS_SUCCEEDED(aStatus);
00449   if (succeeded) {
00450     PRUint32 avail = 0;
00451     mPipeIn->Available(&avail);
00452     if (avail > 0) {
00453       nsresult rv;
00454 
00455       // Regardless of whether the response status represents success
00456       // or failure, we want to read the response. For an error response
00457       // nothing in the document is replaced, and submission processing
00458       // concludes after dispatching xforms-submit-error with appropriate
00459       // context information, including an error-type of resource-error.
00460       nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
00461       if (httpChannel) {
00462         PRUint32 response;
00463         nsresult rv = httpChannel->GetResponseStatus(&response);
00464         nsCAutoString statusText;
00465         httpChannel->GetResponseStatusText(statusText);
00466         httpChannel->VisitResponseHeaders(this);
00467         SetHttpContextInfo(response, NS_ConvertUTF8toUTF16(statusText));
00468 
00469         PRBool requestSucceeded;
00470         httpChannel->GetRequestSucceeded(&requestSucceeded);
00471         if (!requestSucceeded) {
00472           // Server returned an error response code. Parse the error
00473           // response body into an XML document for 'response-body'
00474           // context info.
00475           ParseErrorResponse(httpChannel);
00476           mSubmitError = kError_ResourceError;
00477           succeeded = PR_FALSE;
00478         } else {
00479           succeeded = PR_TRUE;
00480         }
00481       }
00482 
00483       if (succeeded) {
00484         if (mIsReplaceInstance) {
00485           rv = LoadReplaceInstance(channel);
00486         } else {
00487           nsAutoString replace;
00488           mElement->GetAttribute(NS_LITERAL_STRING("replace"), replace);
00489           if (replace.IsEmpty() || replace.EqualsLiteral("all")) {
00490             rv = LoadReplaceAll(channel);
00491           } else {
00492             // replace="none"
00493             rv = NS_OK;
00494           }
00495         }
00496         succeeded = NS_SUCCEEDED(rv);
00497       }
00498     } else {
00499       mSubmitError = kError_ResourceError;
00500     }
00501   }
00502   mPipeIn = 0;
00503 
00504   EndSubmit(succeeded);
00505 
00506   return NS_OK;
00507 }
00508 
00509 // private methods
00510 
00511 void
00512 nsXFormsSubmissionElement::EndSubmit(PRBool aSucceeded)
00513 {
00514   mSubmissionActive = PR_FALSE;
00515   if (mActivator) {
00516     mActivator->SetDisabled(PR_FALSE);
00517     mActivator = nsnull;
00518   }
00519 
00520   // If there were any errors, set 'error-type' context info.
00521   if (!mSubmitError.IsEmpty()) {
00522     nsCOMPtr<nsXFormsContextInfo> contextInfo =
00523       new nsXFormsContextInfo(mElement);
00524     if (contextInfo) {
00525       contextInfo->SetStringValue("error-type", mSubmitError);
00526       mContextInfo.AppendObject(contextInfo);
00527     }
00528   }
00529 
00530   nsXFormsUtils::DispatchEvent(mElement, aSucceeded ?
00531                                eEvent_SubmitDone : eEvent_SubmitError,
00532                                nsnull, nsnull, &mContextInfo);
00533 }
00534 
00535 already_AddRefed<nsIModelElementPrivate>
00536 nsXFormsSubmissionElement::GetModel()
00537 {
00538   nsCOMPtr<nsIDOMNode> parentNode;
00539   mElement->GetParentNode(getter_AddRefs(parentNode));
00540 
00541   nsIModelElementPrivate *model = nsnull;
00542   if (parentNode)
00543     CallQueryInterface(parentNode, &model);
00544   return model;
00545 }
00546 
00547 nsresult
00548 nsXFormsSubmissionElement::LoadReplaceInstance(nsIChannel *channel)
00549 {
00550   NS_ASSERTION(channel, "LoadReplaceInstance called with null channel?");
00551 
00552   // replace instance document
00553 
00554   nsCString contentCharset;
00555   channel->GetContentCharset(contentCharset);
00556 
00557   // use DOM parser to construct nsIDOMDocument
00558   nsCOMPtr<nsIDOMParser> parser = do_CreateInstance("@mozilla.org/xmlextras/domparser;1");
00559   NS_ENSURE_STATE(parser);
00560 
00561   PRUint32 contentLength;
00562   mPipeIn->Available(&contentLength);
00563 
00564   // set the base uri so that the document can get the correct security
00565   // principal (this has to be here to work on 1.8.0)
00566   // @see https://bugzilla.mozilla.org/show_bug.cgi?id=338451
00567   nsCOMPtr<nsIURI> uri;
00568   nsresult rv = channel->GetURI(getter_AddRefs(uri));
00569   NS_ENSURE_SUCCESS(rv, rv);
00570   rv = parser->SetBaseURI(uri);
00571   NS_ENSURE_SUCCESS(rv, rv);
00572 
00573   nsCOMPtr<nsIDOMDocument> newDoc;
00574   parser->ParseFromStream(mPipeIn, contentCharset.get(), contentLength,
00575                           "application/xml", getter_AddRefs(newDoc));
00576   // XXX Add URI, etc?
00577   if (!newDoc) {
00578     nsXFormsUtils::ReportError(NS_LITERAL_STRING("instanceParseError"),
00579                                mElement);
00580     mSubmitError = kError_ParseError;
00581     return NS_ERROR_UNEXPECTED;
00582   }
00583   
00584   // check for parsererror tag?  XXX is this needed?  or, is there a better way?
00585   nsCOMPtr<nsIDOMElement> docElem;
00586   newDoc->GetDocumentElement(getter_AddRefs(docElem));
00587   if (docElem) {
00588     nsAutoString tagName, namespaceURI;
00589     docElem->GetTagName(tagName);
00590     docElem->GetNamespaceURI(namespaceURI);
00591 
00592     // XXX this is somewhat of a hack.  we should instead be listening for an
00593     // 'error' event from the DOM, but gecko doesn't implement that event yet.
00594     if (tagName.EqualsLiteral("parsererror") &&
00595         namespaceURI.EqualsLiteral("http://www.mozilla.org/newlayout/xml/parsererror.xml")) {
00596       nsXFormsUtils::ReportError(NS_LITERAL_STRING("instanceParseError"),
00597                                  mElement);
00598       mSubmitError = kError_ParseError;
00599       return NS_ERROR_UNEXPECTED;
00600     }
00601   }
00602 
00603   // Get the appropriate instance node.  If the "instance" attribute is set,
00604   // then get that instance node.  Otherwise, get the one we are bound to.
00605   nsCOMPtr<nsIModelElementPrivate> model = GetModel();
00606   NS_ENSURE_STATE(model);
00607   nsCOMPtr<nsIInstanceElementPrivate> instanceElement;
00608   nsAutoString value;
00609   mElement->GetAttribute(NS_LITERAL_STRING("instance"), value);
00610   if (!value.IsEmpty()) {
00611     rv = GetSelectedInstanceElement(value, model,
00612                                     getter_AddRefs(instanceElement));
00613   } else {
00614     nsCOMPtr<nsIDOMNode> data;
00615     rv = GetBoundInstanceData(getter_AddRefs(data));
00616     if (NS_SUCCEEDED(rv)) {
00617       nsCOMPtr<nsIDOMNode> instanceNode;
00618       rv = nsXFormsUtils::GetInstanceNodeForData(data,
00619                                                  getter_AddRefs(instanceNode));
00620       NS_ENSURE_SUCCESS(rv, rv);
00621 
00622       instanceElement = do_QueryInterface(instanceNode);
00623     }
00624   }
00625 
00626   // replace the document referenced by this instance element with the info
00627   // returned back from the submission
00628   if (NS_SUCCEEDED(rv) && instanceElement) {
00629     instanceElement->SetInstanceDocument(newDoc);
00630 
00631     // refresh everything
00632     model->Rebuild();
00633     model->Recalculate();
00634     model->Revalidate();
00635     model->Refresh();
00636   } else {
00637     mSubmitError = kError_NoData;
00638   }
00639 
00640   return NS_OK;
00641 }
00642 
00643 nsresult
00644 nsXFormsSubmissionElement::GetSelectedInstanceElement(
00645                                             const nsAString &aInstanceID,
00646                                             nsIModelElementPrivate *aModel,
00647                                             nsIInstanceElementPrivate **aResult)
00648 {
00649   aModel->FindInstanceElement(aInstanceID, aResult);
00650   if (*aResult == nsnull) {
00651     // if failed to get desired instance, dispatch binding exception
00652     const PRUnichar *strings[] = { PromiseFlatString(aInstanceID).get() };
00653     nsXFormsUtils::ReportError(NS_LITERAL_STRING("instanceBindError"),
00654                                strings, 1, mElement, mElement);
00655     nsXFormsUtils::DispatchEvent(mElement, eEvent_BindingException);
00656     return NS_ERROR_FAILURE;
00657   }
00658 
00659   return NS_OK;
00660 }
00661 
00662 nsresult
00663 nsXFormsSubmissionElement::LoadReplaceAll(nsIChannel *channel)
00664 {
00665   // use nsIDocShell::loadStream, which may not be perfect ;-)
00666 
00667   // XXX do we need to transfer nsIChannel::securityInfo ???
00668 
00669   nsCOMPtr<nsIContent> content(do_QueryInterface(mElement));
00670   NS_ASSERTION(content, "mElement not implementing nsIContent?!");
00671   nsIDocument* doc = content->GetCurrentDoc();
00672   NS_ENSURE_STATE(doc);
00673 
00674   // the container is the docshell, and we use it as our provider of
00675   // notification callbacks.
00676   nsCOMPtr<nsISupports> container = doc->GetContainer();
00677   nsCOMPtr<nsIDocShell> docshell = do_QueryInterface(container);
00678 
00679   nsCOMPtr<nsIURI> uri;
00680   nsCString contentType, contentCharset;
00681 
00682   channel->GetURI(getter_AddRefs(uri));
00683   channel->GetContentType(contentType);
00684   channel->GetContentCharset(contentCharset);
00685 
00686   return docshell->LoadStream(mPipeIn, uri, contentType, contentCharset, nsnull);
00687 }
00688 
00689 nsresult
00690 nsXFormsSubmissionElement::Submit()
00691 {
00692   LOG(("+++ nsXFormsSubmissionElement::Submit\n"));
00693 
00694   NS_ENSURE_STATE(mElement);
00695 
00696   nsresult rv;
00697   mIsSOAPRequest = PR_FALSE;
00698 
00699   //
00700   // 1. ensure that we are not currently processing a xforms-submit (see E37)
00701   if (mSubmissionActive) {
00702     nsXFormsUtils::ReportError(NS_LITERAL_STRING("warnSubmitAlreadyRunning"),
00703                                mElement, nsIScriptError::warningFlag);
00704     mSubmitError = kError_SubmissionInProgress;
00705     return NS_ERROR_FAILURE;
00706   }
00707   mSubmissionActive = PR_TRUE;
00708   
00709   if (mActivator)
00710     mActivator->SetDisabled(PR_TRUE);
00711 
00712   // Someone may change the "replace" attribute during submission
00713   // and that would break the ::SameOriginCheck().
00714   nsAutoString replace;
00715   mElement->GetAttribute(NS_LITERAL_STRING("replace"), replace);
00716   mIsReplaceInstance = replace.EqualsLiteral("instance");
00717 
00718   // 2. Dispatch xforms-submit-serialize.
00719   // If the event context submission-body property string is empty, then no
00720   // operation is performed so that the submission will use the normal
00721   // serialization data. Otherwise, if the event context submission-body
00722   // property string is non-empty, then the serialization data for the
00723   // submission is set to be the content of the submission-body string.
00724   nsCOMPtr<nsXFormsContextInfo> contextInfo = new nsXFormsContextInfo(mElement);
00725   NS_ENSURE_TRUE(contextInfo, NS_ERROR_OUT_OF_MEMORY);
00726   nsAutoString submissionBody;
00727   submissionBody.AssignLiteral(" ");
00728   contextInfo->SetStringValue("submission-body", submissionBody);
00729   mContextInfo.AppendObject(contextInfo);
00730   nsXFormsUtils::DispatchEvent(mElement, eEvent_SubmitSerialize, nsnull,
00731                                nsnull, &mContextInfo);
00732 
00733   //
00734   // 2. get selected node from the instance data
00735   nsCOMPtr<nsIDOMNode> data;
00736   if (mSubmissionBody) {
00737     // submission-body property was modified during submit-serialize and its
00738     // contents is the new serialization data.
00739     data = mSubmissionBody;
00740   } else {
00741     // get selected node from the instance data.
00742     rv = GetBoundInstanceData(getter_AddRefs(data));
00743     NS_ENSURE_SUCCESS(rv, rv);
00744   }
00745 
00746   // No data to submit
00747   if (!data) {
00748     mSubmitError = kError_NoData;
00749     EndSubmit(PR_FALSE);
00750     return NS_OK;
00751   }
00752 
00753   //
00754   // 3. Create submission document (include namespaces, purge non-relevant
00755   // nodes, check simple type validity)
00756   nsCOMPtr<nsIDOMDocument> submissionDoc;
00757   if (!mSubmissionBody) {
00758     rv = CreateSubmissionDoc(data, getter_AddRefs(submissionDoc));
00759     NS_ENSURE_SUCCESS(rv, rv);
00760   }
00761 
00762   //
00763   // 4. Validate document
00764   // XXX: Some unresolved issues with this, see
00765   //      bug https://bugzilla.mozilla.org/show_bug.cgi?id=278762
00766   // if (GetBooleanAttr(NS_LITERAL_STRING("validate"), PR_TRUE))
00767   //   model->ValidateDocument(submissionDoc, &res);
00768 
00769   //
00770   // 5. Convert submission document into the requested format
00771   // Checking the format only before starting the submission.
00772   mFormat = GetSubmissionFormat(mElement);
00773   NS_ENSURE_STATE(mFormat != 0);
00774 
00775   nsCOMPtr<nsIInputStream> stream;
00776   nsCAutoString uri, contentType;
00777   GetSubmissionURI(uri);
00778 
00779   if (mSubmissionBody) {
00780     // submission-body property was modified during submit-serialize and we will
00781     // serialize it as a simple string.
00782     nsAutoString nodeValue;
00783     nsXFormsUtils::GetNodeValue(mSubmissionBody, nodeValue);
00784 
00785     // make new stream
00786     NS_NewCStringInputStream(getter_AddRefs(stream),
00787                              NS_ConvertUTF16toUTF8(nodeValue));
00788     NS_ENSURE_STATE(stream);
00789     contentType.AssignLiteral("application/xml");
00790     rv = NS_OK;
00791   } else {
00792     // Serialize a document based on the submission format and content type.
00793     rv = SerializeData(submissionDoc, uri, getter_AddRefs(stream), contentType);
00794   }
00795   if (NS_FAILED(rv)) {
00796     nsXFormsUtils::ReportError(NS_LITERAL_STRING("warnSubmitSerializeFailed"),
00797                                mElement, nsIScriptError::warningFlag);
00798     return rv;
00799   }
00800 
00801   //
00802   // 6. dispatch network request
00803   rv = SendData(uri, stream, contentType);
00804   if (NS_FAILED(rv)) {
00805     nsXFormsUtils::ReportError(NS_LITERAL_STRING("warnSubmitNetworkFailure"),
00806                                mElement, nsIScriptError::warningFlag);
00807     return rv;
00808   }
00809 
00810   return rv;
00811 }
00812 
00813 nsresult
00814 nsXFormsSubmissionElement::GetSubmissionURI(nsACString& aURI)
00815 {
00816   // Precedence:
00817   // 1. If the submission element has a resource element, the URI can be
00818   // specifed by either the 'value' attribute or the string content of the
00819   // resource element. If a submission has more than one resource child
00820   // element, the first resource element child must be selected for use.
00821   //
00822   // The resource element has precedence over both the 'resource' and
00823   // 'action' attributes.
00824   //
00825   // 2. If there is no resource element, the URI may be specified by either
00826   // the 'resource' or 'action' attributes with 'resource' having precedence
00827   // over 'action'.
00828   //
00829   // If no URI is specified via any of the above mechanisms we write a warning
00830   // message to the error console.
00831 
00832   nsresult rv = NS_OK;
00833   nsAutoString uri;
00834 
00835   // First check if submission has a resource child element.
00836   nsCOMPtr<nsIDOMNode> currentNode, node, resourceNode;
00837   mElement->GetFirstChild(getter_AddRefs(currentNode));
00838 
00839   PRUint16 nodeType;
00840 
00841   while (currentNode) {
00842     currentNode->GetNodeType(&nodeType);
00843     if (nodeType == nsIDOMNode::ELEMENT_NODE) {
00844       // Check if the element is a resource element.
00845       nsAutoString localName, namespaceURI;
00846       currentNode->GetLocalName(localName);
00847       currentNode->GetNamespaceURI(namespaceURI);
00848       if (localName.EqualsLiteral("resource") &&
00849           namespaceURI.EqualsLiteral(NS_NAMESPACE_XFORMS)) {
00850         resourceNode = currentNode;
00851         break;
00852       }
00853     }
00854 
00855     currentNode->GetNextSibling(getter_AddRefs(node));
00856     currentNode.swap(node);
00857   }
00858 
00859   if (resourceNode) {
00860     PRBool hasAttributes = PR_FALSE;
00861     resourceNode->HasAttributes(&hasAttributes);
00862     if (hasAttributes) {
00863       nsCOMPtr<nsIDOMElement> resourceElement(do_QueryInterface(currentNode));
00864       if (resourceElement) {
00865         resourceElement->GetAttribute(NS_LITERAL_STRING("value"), uri);
00866         if (!uri.IsEmpty()) {
00867           nsCOMPtr<nsIModelElementPrivate> model;
00868           nsCOMPtr<nsIDOMXPathResult> xpRes;
00869           PRBool usesModelBind = PR_FALSE;
00870           rv = nsXFormsUtils::EvaluateNodeBinding(resourceElement, 0,
00871                                                   NS_LITERAL_STRING("value"),
00872                                                   EmptyString(),
00873                                                   nsIDOMXPathResult::STRING_TYPE,
00874                                                   getter_AddRefs(model),
00875                                                   getter_AddRefs(xpRes),
00876                                                   &usesModelBind);
00877           NS_ENSURE_SUCCESS(rv, rv);
00878 
00879           if (xpRes) {
00880             // Truncate uri so GetStringValue replaces the contents with the
00881             // xpath result rather than appending to it.
00882             uri.Truncate();
00883             rv = xpRes->GetStringValue(uri);
00884             NS_ENSURE_SUCCESS(rv, rv);
00885           }
00886         }
00887       }
00888     } else {
00889       // No value attribute. Get the string content of the resource element.
00890       nsXFormsUtils::GetNodeValue(resourceNode, uri);
00891     }
00892   } else {
00893     // No resource element so check first for the resource attribute and then
00894     // the action attribute.
00895     mElement->GetAttribute(NS_LITERAL_STRING("resource"), uri);
00896     if (uri.IsEmpty()) {
00897       mElement->GetAttribute(NS_LITERAL_STRING("action"), uri);
00898     }
00899   }
00900 
00901   // If no URI is specified, write a warning to the console.
00902   if (uri.IsEmpty())
00903     nsXFormsUtils::ReportError(NS_LITERAL_STRING("warnSubmitURI"), mElement,
00904                                nsIScriptError::warningFlag);
00905 
00906   // Context Info: 'resource-uri'
00907   nsCOMPtr<nsXFormsContextInfo> contextInfo =
00908     new nsXFormsContextInfo(mElement);
00909   NS_ENSURE_TRUE(contextInfo, NS_ERROR_OUT_OF_MEMORY);
00910   contextInfo->SetStringValue("resource-uri", uri);
00911   mContextInfo.AppendObject(contextInfo);
00912 
00913   CopyUTF16toUTF8(uri, aURI);
00914 
00915   return rv;
00916 }
00917 
00918 nsresult
00919 nsXFormsSubmissionElement::OverrideRequestHeaders(nsIHttpChannel *aHttpChannel)
00920 {
00921 
00922   // Check to see if this submission element has any header elements.  Process
00923   // the header elements, which will find any name/value pairs and add them
00924   // to the channel's request header
00925 
00926   nsresult rv = NS_OK;
00927   nsCOMPtr<nsIDOMNode> currentNode, node, headerNode;
00928   mElement->GetFirstChild(getter_AddRefs(currentNode));
00929 
00930   PRUint16 nodeType;
00931 
00932   while (currentNode) {
00933     currentNode->GetNodeType(&nodeType);
00934     if (nodeType == nsIDOMNode::ELEMENT_NODE) {
00935       // Check if the element is a header element.
00936       nsAutoString localName, namespaceURI;
00937       currentNode->GetLocalName(localName);
00938       currentNode->GetNamespaceURI(namespaceURI);
00939       if (localName.EqualsLiteral("header") &&
00940           namespaceURI.EqualsLiteral(NS_NAMESPACE_XFORMS)) {
00941         headerNode = currentNode;
00942         nsAutoString name, value;
00943         rv = ProcessHeaderElement(headerNode, aHttpChannel);
00944         NS_ENSURE_SUCCESS(rv, rv);
00945       }
00946     }
00947 
00948     currentNode->GetNextSibling(getter_AddRefs(node));
00949     currentNode.swap(node);
00950   }
00951 
00952   return NS_OK;
00953 }
00954 
00955 nsresult
00956 nsXFormsSubmissionElement::ProcessHeaderElement(nsIDOMNode *aHeaderNode,
00957                                                 nsIHttpChannel *aHttpChannel)
00958 {
00959   // Take the given header node and look for name/value element pairs
00960   // underneath.  Evaluate their bindings, if any, and set those headers on
00961   // the submission request.
00962 
00963   NS_ENSURE_ARG(aHeaderNode);
00964 
00965   PRBool hasNodeset = PR_FALSE;
00966   nsCOMPtr<nsIDOMXPathResult> nodesetResult;
00967   PRInt32 contextSize = kNotFound;
00968   nsAutoString nodesetString(NS_LITERAL_STRING("nodeset"));
00969   nsresult rv;
00970   nsCOMPtr<nsIDOMElement> headerElement(do_QueryInterface(aHeaderNode));
00971   NS_ENSURE_STATE(headerElement);
00972   headerElement->HasAttribute(nodesetString, &hasNodeset);
00973 
00974   if (hasNodeset) {
00975     nsAutoString bindExpr;
00976     headerElement->GetAttribute(nodesetString, bindExpr);
00977     if (!bindExpr.IsEmpty()) {
00978       // Get the nodeset we are bound to
00979       nsCOMPtr<nsIModelElementPrivate> model;
00980       PRBool usesModelBind = PR_FALSE;
00981       rv = nsXFormsUtils::EvaluateNodeBinding(headerElement, 0, nodesetString,
00982                                               EmptyString(),
00983                                               nsIDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE,
00984                                               getter_AddRefs(model),
00985                                               getter_AddRefs(nodesetResult),
00986                                               &usesModelBind);
00987       NS_ENSURE_SUCCESS(rv, rv);
00988       PRUint32 tempSize;
00989       rv = nodesetResult->GetSnapshotLength(&tempSize);
00990       NS_ENSURE_SUCCESS(rv, rv);
00991       contextSize = (PRInt32)tempSize;
00992 
00993       if (contextSize <= 0) {
00994         return NS_OK;
00995       }
00996     }
00997   }
00998 
00999   // look for the name and value elements under the header element
01000 
01001   nsCOMPtr<nsIDOMNode> currentNode, node;
01002   headerElement->GetFirstChild(getter_AddRefs(currentNode));
01003   
01004   PRUint16 nodeType;
01005   nsAutoString nameExpr, nameValue, valueExpr, valueValue;
01006   PRBool useNameExpr = PR_FALSE, useValueExpr = PR_FALSE;
01007   nsCOMPtr<nsIDOMElement> nameElement, valueElement;
01008   
01009   while (currentNode && (!valueElement || !nameElement)) {
01010     currentNode->GetNodeType(&nodeType);
01011     if (nodeType == nsIDOMNode::ELEMENT_NODE) {
01012       nsAutoString localName, namespaceURI,
01013                    valueString(NS_LITERAL_STRING("value"));
01014       currentNode->GetLocalName(localName);
01015       currentNode->GetNamespaceURI(namespaceURI);
01016       if (localName.EqualsLiteral("name") &&
01017           namespaceURI.EqualsLiteral(NS_NAMESPACE_XFORMS) &&
01018           !nameElement) {
01019         nameElement = do_QueryInterface(currentNode);
01020         if (nameElement) {
01021           nameElement->HasAttribute(valueString, &useNameExpr);
01022           if (useNameExpr) {
01023             nameElement->GetAttribute(valueString, nameExpr);
01024             if (contextSize == kNotFound) {
01025               nsCOMPtr<nsIModelElementPrivate> model;
01026               PRBool usesModelBind = PR_FALSE;
01027               nsCOMPtr<nsIDOMXPathResult> xpRes;
01028               rv = nsXFormsUtils::EvaluateNodeBinding(nameElement, 0,
01029                                                       valueString, EmptyString(),
01030                                                       nsIDOMXPathResult::STRING_TYPE,
01031                                                       getter_AddRefs(model),
01032                                                       getter_AddRefs(xpRes),
01033                                                       &usesModelBind);
01034               NS_ENSURE_SUCCESS(rv, rv);
01035               if (xpRes) {
01036                 // Truncate nameValue so GetStringValue replaces the contents
01037                 // with the xpath result rather than appending to it.
01038                 nameValue.Truncate();
01039                 rv = xpRes->GetStringValue(nameValue);
01040                 NS_ENSURE_SUCCESS(rv, rv);
01041               }
01042             }
01043           } else {
01044             // No value attribute. Get the string content of the resource element.
01045             nsXFormsUtils::GetNodeValue(currentNode, nameValue);
01046           }
01047         }
01048       } else if (localName.Equals(valueString) &&
01049           namespaceURI.EqualsLiteral(NS_NAMESPACE_XFORMS) &&
01050           !valueElement) {
01051         valueElement = do_QueryInterface(currentNode);
01052         if (valueElement) {
01053           valueElement->HasAttribute(valueString, &useValueExpr);
01054           if (useValueExpr) {
01055             valueElement->GetAttribute(valueString, valueExpr);
01056             if (contextSize == kNotFound) {
01057               nsCOMPtr<nsIModelElementPrivate> model;
01058               PRBool usesModelBind = PR_FALSE;
01059               nsCOMPtr<nsIDOMXPathResult> xpRes;
01060               rv = nsXFormsUtils::EvaluateNodeBinding(valueElement, 0,
01061                                                       valueString, EmptyString(),
01062                                                       nsIDOMXPathResult::STRING_TYPE,
01063                                                       getter_AddRefs(model),
01064                                                       getter_AddRefs(xpRes),
01065                                                       &usesModelBind);
01066               NS_ENSURE_SUCCESS(rv, rv);
01067               if (xpRes) {
01068                 // Truncate valueValue so GetStringValue replaces the contents
01069                 // with the xpath result rather than appending to it.
01070                 valueValue.Truncate();
01071                 rv = xpRes->GetStringValue(valueValue);
01072                 NS_ENSURE_SUCCESS(rv, rv);
01073               }
01074             }
01075           } else {
01076             // No value attribute. Get the string content of the resource element.
01077             nsXFormsUtils::GetNodeValue(valueElement, valueValue);
01078           }
01079         }
01080       }
01081     }
01082     currentNode->GetNextSibling(getter_AddRefs(node));
01083     currentNode.swap(node);
01084   }
01085 
01086   NS_ENSURE_STATE(nameElement && valueElement);
01087 
01088   if (contextSize == kNotFound) {
01089     // if the header element didn't have any nodeset attribute we just have the
01090     // one name/value pair to worry about
01091 
01092     if (!nameValue.IsEmpty()) {
01093       rv = aHttpChannel->SetRequestHeader(NS_ConvertUTF16toUTF8(nameValue),
01094                                           NS_ConvertUTF16toUTF8(valueValue),
01095                                           PR_TRUE);
01096       NS_ENSURE_SUCCESS(rv, rv);
01097     }
01098     return NS_OK;
01099   }
01100 
01101   for (PRInt32 i = 0; i < contextSize; ++i) {
01102     // Get context node
01103     nsCOMPtr<nsIDOMNode> contextNode;
01104     rv = nodesetResult->SnapshotItem(i, getter_AddRefs(contextNode));
01105     NS_ENSURE_SUCCESS(rv, rv);
01106 
01107     if (contextNode) {
01108       nsCOMPtr<nsIDOMXPathResult> xpRes;
01109       if (!nameExpr.IsEmpty()) {
01110         rv = nsXFormsUtils::EvaluateXPath(nameExpr, contextNode, nameElement,
01111                                           nsIDOMXPathResult::STRING_TYPE,
01112                                           getter_AddRefs(xpRes));
01113         NS_ENSURE_SUCCESS(rv, rv);
01114         if (xpRes) {
01115           // Truncate nameValue so GetStringValue replaces the contents
01116           // with the xpath result rather than appending to it.
01117           nameValue.Truncate();
01118           rv = xpRes->GetStringValue(nameValue);
01119           NS_ENSURE_SUCCESS(rv, rv);
01120         }
01121       }
01122       if (!valueExpr.IsEmpty()) {
01123         rv = nsXFormsUtils::EvaluateXPath(valueExpr, contextNode, valueElement,
01124                                           nsIDOMXPathResult::STRING_TYPE,
01125                                           getter_AddRefs(xpRes));
01126         NS_ENSURE_SUCCESS(rv, rv);
01127         if (xpRes) {
01128           // Truncate valueValue so GetStringValue replaces the contents
01129           // with the xpath result rather than appending to it.
01130           valueValue.Truncate();
01131           rv = xpRes->GetStringValue(valueValue);
01132           NS_ENSURE_SUCCESS(rv, rv);
01133         }
01134       }
01135 
01136       if (!nameValue.IsEmpty()) {
01137         rv = aHttpChannel->SetRequestHeader(NS_ConvertUTF16toUTF8(nameValue),
01138                                             NS_ConvertUTF16toUTF8(valueValue),
01139                                             PR_TRUE);
01140         NS_ENSURE_SUCCESS(rv, rv);
01141       }
01142     }
01143   }
01144 
01145   return NS_OK;
01146 }
01147 
01148 nsresult
01149 nsXFormsSubmissionElement::GetBoundInstanceData(nsIDOMNode **result)
01150 {
01151   nsCOMPtr<nsIModelElementPrivate> model;
01152   nsCOMPtr<nsIDOMXPathResult> xpRes;
01153   PRBool usesModelBind;
01154   nsresult rv =
01155     nsXFormsUtils::EvaluateNodeBinding(mElement, 0,
01156                                        NS_LITERAL_STRING("ref"),
01157                                        NS_LITERAL_STRING("/"),
01158                                        nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE,
01159                                        getter_AddRefs(model),
01160                                        getter_AddRefs(xpRes),
01161                                        &usesModelBind);
01162 
01163   if (NS_FAILED(rv) || !xpRes)
01164     return NS_ERROR_UNEXPECTED;
01165 
01166   return usesModelBind ? xpRes->SnapshotItem(0, result)
01167                        : xpRes->GetSingleNodeValue(result);
01168 }
01169 
01170 PRBool
01171 nsXFormsSubmissionElement::GetBooleanAttr(const nsAString &name,
01172                                           PRBool defaultVal)
01173 {
01174   nsAutoString value;
01175   mElement->GetAttribute(name, value);
01176 
01177   // use defaultVal when value does not match a legal literal
01178 
01179   if (!value.IsEmpty())
01180   {
01181     if (value.EqualsLiteral("true") || value.EqualsLiteral("1"))
01182       return PR_TRUE;
01183     if (value.EqualsLiteral("false") || value.EqualsLiteral("0"))
01184       return PR_FALSE;
01185   }
01186   
01187   return defaultVal;
01188 }
01189 
01190 void
01191 nsXFormsSubmissionElement::GetDefaultInstanceData(nsIDOMNode **result)
01192 {
01193   *result = nsnull;
01194 
01195   // default <instance> element is the first <instance> child node of 
01196   // our parent, which should be a <model> element.
01197 
01198   nsCOMPtr<nsIDOMNode> parent;
01199   mElement->GetParentNode(getter_AddRefs(parent));
01200   if (!parent)
01201   {
01202     NS_WARNING("no parent node!");
01203     return;
01204   }
01205 
01206   nsCOMPtr<nsIXFormsModelElement> model = do_QueryInterface(parent);
01207   if (!model)
01208   {
01209     NS_WARNING("parent node is not a model");
01210     return;
01211   }
01212 
01213   nsCOMPtr<nsIDOMDocument> instanceDoc;
01214   model->GetInstanceDocument(EmptyString(), getter_AddRefs(instanceDoc));
01215 
01216   nsCOMPtr<nsIDOMElement> instanceDocElem;
01217   instanceDoc->GetDocumentElement(getter_AddRefs(instanceDocElem));
01218 
01219   NS_ADDREF(*result = instanceDocElem);
01220 }
01221 
01222 nsresult
01223 nsXFormsSubmissionElement::SerializeData(nsIDOMDocument  *aData,
01224                                          nsCString       &aUri,
01225                                          nsIInputStream **aStream,
01226                                          nsCString       &aContentType)
01227 {
01228   if (mFormat & ENCODING_XML)
01229     return SerializeDataXML(aData, aStream, aContentType);
01230 
01231   if (mFormat & ENCODING_URL)
01232     return SerializeDataURLEncoded(aData, aUri, aStream, aContentType);
01233 
01234   if (mFormat & ENCODING_MULTIPART_RELATED)
01235     return SerializeDataMultipartRelated(aData, aStream, aContentType);
01236 
01237   if (mFormat & ENCODING_MULTIPART_FORM_DATA)
01238     return SerializeDataMultipartFormData(aData, aStream, aContentType);
01239 
01240   NS_WARNING("unsupported submission encoding");
01241   return NS_ERROR_UNEXPECTED;
01242 }
01243 
01244 nsresult
01245 nsXFormsSubmissionElement::SerializeDataXML(nsIDOMDocument  *data,
01246                                             nsIInputStream **stream,
01247                                             nsCString        &contentType)
01248 {
01249   nsresult rv;
01250   nsAutoString mediaType;
01251   mElement->GetAttribute(NS_LITERAL_STRING("mediatype"), mediaType);
01252 
01253   // Check for SOAP Envelope and handle SOAP
01254   nsAutoString nodeName, nodeNS;
01255   nsCOMPtr<nsIDOMElement> docElem;
01256   data->GetDocumentElement(getter_AddRefs(docElem));
01257   if (docElem) {
01258     docElem->GetLocalName(nodeName);
01259     docElem->GetNamespaceURI(nodeNS);
01260   }
01261   if (nodeName.Equals(NS_LITERAL_STRING("Envelope")) &&
01262       nodeNS.Equals(NS_LITERAL_STRING(NS_NAMESPACE_SOAP_ENVELOPE))) {
01263     mIsSOAPRequest = PR_TRUE;
01264     nsXFormsUtils::ReportError(NS_LITERAL_STRING("warnSOAP"), mElement,
01265                                nsIScriptError::warningFlag);
01266     contentType.AssignLiteral("text/xml");
01267 
01268     if (!mediaType.IsEmpty()) {
01269       // copy charset from mediatype
01270       nsAutoString charset;
01271       nsCOMPtr<nsIMIMEHeaderParam> mimeHdrParser =
01272         do_GetService("@mozilla.org/network/mime-hdrparam;1");
01273       NS_ENSURE_STATE(mimeHdrParser);
01274       rv = mimeHdrParser->GetParameter(NS_ConvertUTF16toUTF8(mediaType),
01275                                        "charset", EmptyCString(), PR_FALSE,
01276                                        nsnull, charset);
01277       if (NS_SUCCEEDED(rv) && !charset.IsEmpty()) {
01278         contentType.AppendLiteral("; charset=");
01279         contentType.Append(NS_ConvertUTF16toUTF8(charset));
01280       }
01281     }
01282   }
01283 
01284   // Handle non-SOAP requests
01285   if (!mIsSOAPRequest) {
01286     if (mediaType.IsEmpty())
01287       contentType.AssignLiteral("application/xml");
01288     else
01289       CopyUTF16toUTF8(mediaType, contentType);
01290   }
01291   
01292   nsCOMPtr<nsIStorageStream> storage;
01293   NS_NewStorageStream(4096, PR_UINT32_MAX, getter_AddRefs(storage));
01294   NS_ENSURE_TRUE(storage, NS_ERROR_OUT_OF_MEMORY);
01295 
01296   nsCOMPtr<nsIOutputStream> sink;
01297   storage->GetOutputStream(0, getter_AddRefs(sink));
01298   NS_ENSURE_TRUE(sink, NS_ERROR_OUT_OF_MEMORY);
01299 
01300   nsCOMPtr<nsIDOMSerializer> serializer =
01301       do_GetService("@mozilla.org/xmlextras/xmlserializer;1");
01302   NS_ENSURE_STATE(serializer);
01303 
01304   // Serialize content
01305   nsAutoString encoding;
01306   mElement->GetAttribute(NS_LITERAL_STRING("encoding"), encoding);
01307   if (encoding.IsEmpty())
01308     encoding.AssignLiteral("UTF-8");
01309 
01310   // XXX: should check @indent and possibly indent content. Bug 278761
01311   rv = serializer->SerializeToStream(data, sink,
01312                                      NS_LossyConvertUTF16toASCII(encoding));
01313   NS_ENSURE_SUCCESS(rv, rv);
01314 
01315   // close the output stream, so that the input stream will not return
01316   // NS_BASE_STREAM_WOULD_BLOCK when it reaches end-of-stream.
01317   sink->Close();
01318 
01319   return storage->NewInputStream(0, stream);
01320 }
01321 
01322 PRBool
01323 nsXFormsSubmissionElement::CheckSameOrigin(nsIDocument *aBaseDocument,
01324                                            nsIURI      *aTestURI)
01325 {
01326   // we default to true to allow regular posts to work like html forms.
01327   PRBool allowSubmission = PR_TRUE;
01328 
01329   /* for replace="instance" or XML submission, we follow these strict guidelines:
01330        - we default to denying submission
01331        - if we are not replacing instance, then file:// urls can submit anywhere.
01332          We don't allow fetching of content for file:// urls since for example
01333          XMLHttpRequest doesn't, since file:// doesn't always mean it is local.
01334        - if we are still denying, we check the permission manager to see if the
01335          domain hosting the XForm has been granted permission to get/send data
01336          anywhere
01337        - lastly, if submission is still being denied, we do a same origin check
01338    */
01339   if (mFormat & (ENCODING_XML | ENCODING_MULTIPART_RELATED) || mIsReplaceInstance) {
01340 
01341     // if same origin is required, default to false
01342     allowSubmission = PR_FALSE;
01343     nsIURI *baseURI = aBaseDocument->GetDocumentURI();
01344 
01345     // if we don't replace the instance, we allow file:// to submit data anywhere
01346     if (!mIsReplaceInstance) {
01347       baseURI->SchemeIs("file", &allowSubmission);
01348     }
01349 
01350     // if none of the above checks have allowed the submission, we do a
01351     // same origin check.
01352     if (!allowSubmission) {
01353       // replace instance is both a send and a load
01354       nsXFormsUtils::ConnectionType mode;
01355       if (mIsReplaceInstance)
01356         mode = nsXFormsUtils::kXFormsActionLoadSend;
01357       else
01358         mode = nsXFormsUtils::kXFormsActionSend;
01359 
01360       allowSubmission =
01361         nsXFormsUtils::CheckConnectionAllowed(mElement, aTestURI, mode);
01362     }
01363   }
01364 
01365   return allowSubmission;
01366 }
01367 
01368 nsresult
01369 nsXFormsSubmissionElement::AddNameSpaces(nsIDOMElement   *aTarget,
01370                                          nsIDOMNode      *aSource,
01371                                          nsStringHashSet *aPrefixHash)
01372 {
01373   nsCOMPtr<nsIDOMNamedNodeMap> attrMap;
01374   nsCOMPtr<nsIDOMNode> attrNode;
01375   nsAutoString nsURI, localName, value;
01376 
01377   aSource->GetAttributes(getter_AddRefs(attrMap));
01378   NS_ENSURE_STATE(attrMap);
01379 
01380   PRUint32 length;
01381   attrMap->GetLength(&length);
01382 
01383   for (PRUint32 run = 0; run < length; ++run) {
01384     attrMap->Item(run, getter_AddRefs(attrNode));
01385     attrNode->GetNamespaceURI(nsURI);
01386 
01387     if (nsURI.Equals(kXMLNSNameSpaceURI)) {
01388       attrNode->GetLocalName(localName);
01389       attrNode->GetNodeValue(value);
01390 
01391       if (!localName.EqualsLiteral("xmlns")) {
01392         if (!aPrefixHash || aPrefixHash->Contains(localName)) {
01393           nsAutoString attrName(NS_LITERAL_STRING("xmlns:"));
01394           attrName.Append(localName);
01395           aTarget->SetAttributeNS(kXMLNSNameSpaceURI, attrName, value);
01396         }
01397       } else if (!aPrefixHash ||
01398                   aPrefixHash->Contains(NS_LITERAL_STRING("#default"))) {
01399         // only serialize the default namespace declaration if
01400         // includenamespaceprefixes is declared and it includes '#default'
01401         // or if we haven't already serialized it (none of the child elements
01402         // used it)
01403         PRBool hasDefaultNSAttr;
01404         aTarget->HasAttributeNS(kXMLNSNameSpaceURI,
01405                                 NS_LITERAL_STRING("xmlns"), &hasDefaultNSAttr);
01406 
01407         if (!hasDefaultNSAttr) {
01408           aTarget->SetAttributeNS(kXMLNSNameSpaceURI, localName, value);
01409         }
01410       }
01411     }
01412   }
01413 
01414   return NS_OK;
01415 }
01416 
01417 nsresult
01418 nsXFormsSubmissionElement::GetIncludeNSPrefixesAttr(nsStringHashSet** aHash)
01419 {
01420   NS_PRECONDITION(aHash, "null ptr");
01421   if (!aHash)
01422     return NS_ERROR_NULL_POINTER;
01423 
01424   *aHash = new nsStringHashSet();
01425   if (!*aHash)
01426     return NS_ERROR_OUT_OF_MEMORY;
01427   (*aHash)->Init(5);
01428 
01429   nsAutoString prefixes;
01430   mElement->GetAttribute(kIncludeNamespacePrefixes, prefixes);
01431 
01432   // Cycle through space-delimited list and populate hash set
01433   if (!prefixes.IsEmpty()) {
01434     PRInt32 start = 0, end;
01435     PRInt32 length = prefixes.Length();
01436 
01437     do {
01438       end = prefixes.FindCharInSet(" \t\r\n", start);
01439       if (end != kNotFound) {
01440         if (start != end) {   // this line handles consecutive space chars
01441           const nsAString& p = Substring(prefixes, start, end - start);
01442           (*aHash)->Put(p);
01443         }
01444         start = end + 1;
01445       }
01446     } while (end != kNotFound && start != length);
01447 
01448     if (start != length) {
01449       const nsAString& p = Substring(prefixes, start);
01450       (*aHash)->Put(p);
01451     }
01452   }
01453 
01454   return NS_OK;
01455 }
01456 
01457 nsresult
01458 nsXFormsSubmissionElement::CreateSubmissionDoc(nsIDOMNode      *aRoot,
01459                                                nsIDOMDocument **aReturnDoc)
01460 {
01461   NS_ENSURE_ARG_POINTER(aRoot);
01462   NS_ENSURE_ARG_POINTER(aReturnDoc);
01463 
01464   nsCOMPtr<nsIDOMDocument> instDoc, submDoc;
01465   aRoot->GetOwnerDocument(getter_AddRefs(instDoc));
01466   nsresult rv;
01467 
01468   if (!instDoc) {
01469     // owner doc is null when the aRoot node is the document (e.g., ref="/")
01470     // so we can just get the document via QI.
01471     instDoc = do_QueryInterface(aRoot);
01472     NS_ENSURE_STATE(instDoc);
01473 
01474     rv = CreatePurgedDoc(instDoc, getter_AddRefs(submDoc));
01475   } else {
01476     rv = CreatePurgedDoc(aRoot, getter_AddRefs(submDoc));
01477   }
01478   NS_ENSURE_SUCCESS(rv, rv);
01479   NS_ENSURE_STATE(submDoc);
01480 
01481   // We now need to add namespaces to the submission document.  We get them
01482   // from 3 sources - the main document's documentElement, the model and the
01483   // xforms:instance that contains the submitted instance data node.
01484 
01485   nsCOMPtr<nsIDOMNode> instanceNode;
01486   rv = nsXFormsUtils::GetInstanceNodeForData(aRoot,
01487                                              getter_AddRefs(instanceNode));
01488   NS_ENSURE_SUCCESS(rv, rv);
01489 
01490   // add namespaces from the main document to the submission document, but only
01491   // if the instance data is local, not remote.
01492   PRBool serialize = PR_FALSE;
01493   nsCOMPtr<nsIDOMElement> instanceElement(do_QueryInterface(instanceNode));
01494 
01495   // make sure that this is a DOMElement.  It won't be if it was lazy
01496   // authored.  Lazy authored instance documents don't inherit namespaces
01497   // from parent nodes or the original document (in formsPlayer and Novell,
01498   // at least).
01499   if (instanceElement) {
01500     PRBool hasSrc = PR_FALSE;
01501     instanceElement->HasAttribute(NS_LITERAL_STRING("src"), &hasSrc);
01502     serialize = !hasSrc;
01503   }
01504 
01505   if (serialize) {
01506     // Handle "includenamespaceprefixes" attribute, if present
01507     nsAutoPtr<nsStringHashSet> prefixHash;
01508     PRBool hasPrefixAttr = PR_FALSE;
01509     mElement->HasAttribute(kIncludeNamespacePrefixes, &hasPrefixAttr);
01510     if (hasPrefixAttr) {
01511       rv = GetIncludeNSPrefixesAttr(getter_Transfers(prefixHash));
01512       NS_ENSURE_SUCCESS(rv, rv);
01513     }
01514 
01515     // get the document element of the document we are going to submit
01516     nsCOMPtr<nsIDOMElement> submDocElm;
01517     submDoc->GetDocumentElement(getter_AddRefs(submDocElm));
01518     NS_ENSURE_STATE(submDocElm);
01519 
01520     // handle namespaces on the root element of the instance document
01521     nsCOMPtr<nsIDOMElement> instDocElm;
01522     instDoc->GetDocumentElement(getter_AddRefs(instDocElm));
01523     nsCOMPtr<nsIDOMNode> instDocNode(do_QueryInterface(instDocElm));
01524     NS_ENSURE_STATE(instDocNode);
01525     rv = AddNameSpaces(submDocElm, instDocNode, prefixHash);
01526     NS_ENSURE_SUCCESS(rv, rv);
01527 
01528     // handle namespaces on the xforms:instance
01529     rv = AddNameSpaces(submDocElm, instanceNode, prefixHash);
01530     NS_ENSURE_SUCCESS(rv, rv);
01531 
01532     // handle namespaces on the model
01533     nsCOMPtr<nsIModelElementPrivate> model = GetModel();
01534     nsCOMPtr<nsIDOMNode> modelNode(do_QueryInterface(model));
01535     NS_ENSURE_STATE(modelNode);
01536     rv = AddNameSpaces(submDocElm, modelNode, prefixHash);
01537     NS_ENSURE_SUCCESS(rv, rv);
01538 
01539     // handle namespace on main document
01540     nsCOMPtr<nsIDOMDocument> mainDoc;
01541     mElement->GetOwnerDocument(getter_AddRefs(mainDoc));
01542     NS_ENSURE_STATE(mainDoc);
01543 
01544     nsCOMPtr<nsIDOMElement> mainDocElm;
01545     mainDoc->GetDocumentElement(getter_AddRefs(mainDocElm));
01546     nsCOMPtr<nsIDOMNode> mainDocNode(do_QueryInterface(mainDocElm));
01547     NS_ENSURE_STATE(mainDocNode);
01548 
01549     rv = AddNameSpaces(submDocElm, mainDocNode, prefixHash);
01550     NS_ENSURE_SUCCESS(rv, rv);
01551   }
01552 
01553   NS_ADDREF(*aReturnDoc = submDoc);
01554 
01555   return NS_OK;
01556 }
01557 
01558 
01559 nsresult
01560 nsXFormsSubmissionElement::CreatePurgedDoc(nsIDOMNode      *source,
01561                                            nsIDOMDocument **result)
01562 {
01563   PRBool omit_xml_declaration
01564       = GetBooleanAttr(NS_LITERAL_STRING("omit-xml-declaration"), PR_FALSE);
01565 
01566   nsAutoString cdataElements;
01567   mElement->GetAttribute(NS_LITERAL_STRING("cdata-section-elements"),
01568                          cdataElements);
01569 
01570   // XXX cdataElements contains space delimited QNames.  these may have
01571   //     namespace prefixes relative to our document.  we need to translate
01572   //     them to the corresponding namespace prefix in the source document.
01573   //
01574   // XXX we'll just assume that the QNames correspond to node names since
01575   //     it's unclear how to resolve the namespace prefixes any other way.
01576 
01577   // source can be a document or just a node
01578   nsCOMPtr<nsIDOMDocument> sourceDoc(do_QueryInterface(source)), tmpDoc;
01579   nsCOMPtr<nsIDOMDOMImplementation> impl;
01580 
01581   if (sourceDoc) {
01582     sourceDoc->GetImplementation(getter_AddRefs(impl));
01583   } else {
01584     source->GetOwnerDocument(getter_AddRefs(tmpDoc));
01585     tmpDoc->GetImplementation(getter_AddRefs(impl));
01586   }
01587   NS_ENSURE_STATE(impl);
01588 
01589   nsCOMPtr<nsIDOMDocument> doc;
01590   impl->CreateDocument(EmptyString(), EmptyString(), nsnull,
01591                        getter_AddRefs(doc));
01592   NS_ENSURE_STATE(doc);
01593 
01594   // During the creation of the instance document (srcDoc) we set the security
01595   // principal to be the same as the XForms document to fix the bug
01596   // https://bugzilla.mozilla.org/show_bug.cgi?id=338451.  More info found in
01597   // the bug and in nsXFormsInstanceElement.cpp.  We need to make sure that
01598   // the principal from the document that we are preparing for submission
01599   // (subDoc) has this same principal or we might fail any origin comparisions
01600   // done by nsContentUtils::CheckSameOrigin that happen during this whole
01601   // process of submission.  There are a couple of places where the
01602   // principals for srcDoc and subDoc could be compared.  This only works for
01603   // gecko 1.8.  1.9 has a whole different way of managing principals and
01604   // security checking.
01605   nsCOMPtr<nsIDocument> subDoc(do_QueryInterface(doc)),
01606                         srcDoc(sourceDoc ? do_QueryInterface(sourceDoc)
01607                                          : do_QueryInterface(tmpDoc));
01608   subDoc->SetPrincipal(srcDoc->GetPrincipal());
01609 
01610   if (!omit_xml_declaration) {
01611     nsAutoString encoding;
01612     mElement->GetAttribute(NS_LITERAL_STRING("encoding"), encoding);
01613     if (encoding.IsEmpty())
01614       encoding.AssignLiteral("UTF-8");
01615 
01616     nsAutoString buf =
01617       NS_LITERAL_STRING("version=\"1.0\" encoding=\"") +
01618       encoding +
01619       NS_LITERAL_STRING("\"");
01620 
01621     if (GetBooleanAttr(NS_LITERAL_STRING("standalone"), PR_FALSE))
01622       buf += NS_LITERAL_STRING(" standalone=\"yes\"");
01623 
01624     nsCOMPtr<nsIDOMProcessingInstruction> pi;
01625     doc->CreateProcessingInstruction(NS_LITERAL_STRING("xml"), buf,
01626                                      getter_AddRefs(pi));
01627 
01628     nsCOMPtr<nsIDOMNode> newChild;
01629     doc->AppendChild(pi, getter_AddRefs(newChild));
01630   }
01631 
01632   // recursively walk the source document, copying nodes as appropriate
01633   nsCOMPtr<nsIModelElementPrivate> model = GetModel();
01634   NS_ENSURE_STATE(model);
01635   nsresult rv = NS_OK;
01636   // if it is a document, get the root element
01637   if (sourceDoc) {
01638     // Iterate over document child nodes to preserve document level
01639     // processing instructions and comment nodes.
01640     nsCOMPtr<nsIDOMNode> curDocNode, node, destChild;
01641     sourceDoc->GetFirstChild(getter_AddRefs(curDocNode));
01642     PRUint16 type;
01643     while (curDocNode) {
01644       curDocNode->GetNodeType(&type);
01645       if (type == nsIDOMNode::ELEMENT_NODE) {
01646         rv = CopyChildren(model, curDocNode, doc, doc, cdataElements, 0);
01647         NS_ENSURE_SUCCESS(rv, rv);
01648       } else {
01649         doc->ImportNode(curDocNode, PR_FALSE, getter_AddRefs(destChild));
01650         doc->AppendChild(destChild, getter_AddRefs(node));
01651       }
01652 
01653       curDocNode->GetNextSibling(getter_AddRefs(node));
01654       curDocNode.swap(node);
01655     }
01656   } else {
01657     rv = CopyChildren(model, source, doc, doc, cdataElements, 0);
01658     NS_ENSURE_SUCCESS(rv, rv);
01659   }
01660 
01661   NS_ADDREF(*result = doc);
01662   return NS_OK;
01663 }
01664 
01665 nsresult
01666 nsXFormsSubmissionElement::CreateAttachments(nsIModelElementPrivate *aModel,
01667                                              nsIDOMNode             *aNode,
01668                                              SubmissionAttachmentArray *aAttachments)
01669 {
01670   nsCOMPtr<nsIDOMNode> currentNode(aNode);
01671 
01672   while (currentNode) {
01673     PRUint16 currentNodeType;
01674     nsresult rv = currentNode->GetNodeType(&currentNodeType);
01675     NS_ENSURE_SUCCESS(rv, rv);
01676 
01677     // If |currentNode| is an element node of type 'xsd:anyURI', we need to
01678     // generate a ContentID for the child of this element, and append a new
01679     // attachment to the attachments array.
01680 
01681     PRUint32 encType;
01682     if (NS_SUCCEEDED(GetElementEncodingType(currentNode, &encType, aModel)) &&
01683         encType == ELEMENT_ENCTYPE_URI) {
01684       // ok, looks like we have a local file to upload
01685 
01686       // uploadFileProperty can exist on attribute nodes if an upload is bound
01687       // to an attribute.  But we'll have to look for such attributes as we
01688       // we encounter the element nodes that contain them.  We won't reach
01689       // attributes walking the child/sibling chain of nodes.  So here just
01690       // test for nsIContent.
01691       void* uploadFileProperty = nsnull;
01692       nsCOMPtr<nsIContent> content = do_QueryInterface(currentNode);
01693       if (content) {
01694         uploadFileProperty =
01695           content->GetProperty(nsXFormsAtoms::uploadFileProperty);
01696       }
01697 
01698       nsIFile *file = NS_STATIC_CAST(nsIFile *, uploadFileProperty);
01699       // NOTE: this value may be null if a file hasn't been selected.
01700 
01701       if (uploadFileProperty) {
01702         nsCString cid;
01703         cid.AssignLiteral("cid:");
01704         MakeMultipartContentID(cid);
01705   
01706         nsCOMPtr<nsIDOMNode> childNode;
01707       
01708         switch (currentNodeType) {
01709 
01710         case nsIDOMNode::TEXT_NODE:
01711         case nsIDOMNode::CDATA_SECTION_NODE:
01712         case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
01713         case nsIDOMNode::COMMENT_NODE:
01714           rv = currentNode->SetNodeValue(NS_ConvertUTF8toUTF16(cid));
01715           NS_ENSURE_SUCCESS(rv, rv);
01716       
01717           break;
01718       
01719         case nsIDOMNode::ELEMENT_NODE:
01720       
01721           rv = currentNode->GetFirstChild(getter_AddRefs(childNode));
01722           NS_ENSURE_SUCCESS(rv, rv);
01723       
01724           // shouldn't have to worry about the case of there not being a child
01725           // node here.  If uploadFileProperty is set then that means that
01726           // the node that 'currentNode' was cloned from has has gone through
01727           // through model.SetNodeValue, so should already have a text node
01728           // as the first child and no extraneous text nodes
01729           // following the first one.  We'll check to make sure, though.
01730           PRUint16 childType;
01731           rv = childNode->GetNodeType(&childType);
01732           NS_ENSURE_SUCCESS(rv, rv);
01733       
01734           if (childType == nsIDOMNode::TEXT_NODE ||
01735               childType == nsIDOMNode::CDATA_SECTION_NODE) {
01736             rv = childNode->SetNodeValue(NS_ConvertUTF8toUTF16(cid));
01737             NS_ENSURE_SUCCESS(rv, rv);
01738           } else {
01739             return NS_ERROR_UNEXPECTED;
01740           }
01741         }
01742         aAttachments->Append(file, cid);
01743       }
01744     }
01745 
01746     // look to see if the element node has any attributes with an
01747     // uploadFileProperty on it.
01748     if (currentNodeType == nsIDOMNode::ELEMENT_NODE) {
01749       PRBool hasAttributes = PR_FALSE;
01750       currentNode->HasAttributes(&hasAttributes);
01751       if (hasAttributes) {
01752         nsCOMPtr<nsIDOMNamedNodeMap> attrs;
01753         currentNode->GetAttributes(getter_AddRefs(attrs));
01754         NS_ENSURE_STATE(attrs);
01755         PRUint32 length;
01756         attrs->GetLength(&length);
01757         nsCOMPtr<nsIDOMNode> attrDOMNode;
01758         for (PRUint32 i = 0; i < length; ++i) {
01759           attrs->Item(i, getter_AddRefs(attrDOMNode));
01760           NS_ENSURE_STATE(attrDOMNode);
01761           nsCOMPtr<nsIAttribute> attr = do_QueryInterface(attrDOMNode);
01762           NS_ENSURE_STATE(attr);
01763           void *uploadFileProperty =
01764             attr->GetProperty(nsXFormsAtoms::uploadFileProperty);
01765   
01766           if (!uploadFileProperty) {
01767             continue;
01768           }
01769 
01770           nsIFile *file = NS_STATIC_CAST(nsIFile *, uploadFileProperty);
01771           nsCString cid;
01772           cid.AssignLiteral("cid:");
01773           MakeMultipartContentID(cid);
01774           rv = attrDOMNode->SetNodeValue(NS_ConvertUTF8toUTF16(cid));
01775           NS_ENSURE_SUCCESS(rv, rv);
01776           aAttachments->Append(file, cid);
01777         }
01778       }
01779     }
01780 
01781     nsCOMPtr<nsIDOMNode> child;
01782     currentNode->GetFirstChild(getter_AddRefs(child));
01783     if (child) {
01784       rv = CreateAttachments(aModel, child, aAttachments);
01785       NS_ENSURE_SUCCESS(rv, rv);
01786     }
01787 
01788     nsCOMPtr<nsIDOMNode> node;
01789     currentNode->GetNextSibling(getter_AddRefs(node));
01790     currentNode.swap(node);
01791   }
01792   
01793   return NS_OK;
01794 }
01795       
01796 static void
01797 ReleaseObject(void    *aObject,
01798               nsIAtom *aPropertyName,
01799               void    *aPropertyValue,
01800               void    *aData)
01801 {
01802   NS_STATIC_CAST(nsISupports *, aPropertyValue)->Release();
01803 }
01804 
01805 nsresult
01806 nsXFormsSubmissionElement::CopyChildren(nsIModelElementPrivate *aModel,
01807                                         nsIDOMNode             *aSource,
01808                                         nsIDOMNode             *aDest,
01809                                         nsIDOMDocument         *aDestDoc,
01810                                         const nsString         &aCDATAElements,
01811                                         PRUint32                aDepth)
01812 {
01813   PRBool validate = GetBooleanAttr(NS_LITERAL_STRING("validate"), PR_TRUE);
01814 
01815   nsCOMPtr<nsIDOMNode> currentNode(aSource), node, destChild;
01816 
01817   while (currentNode) {
01818     // XXX importing the entire node is not quite right here... we also have
01819     // to iterate over the attributes since the attributes could somehow
01820     // (remains to be determined) reference external entities.
01821 
01822     aDestDoc->ImportNode(currentNode, PR_FALSE, getter_AddRefs(destChild));
01823     NS_ENSURE_STATE(destChild);
01824 
01825     PRUint16 type;
01826     destChild->GetNodeType(&type);
01827     switch (type) {
01828       case nsIDOMNode::PROCESSING_INSTRUCTION_NODE: {
01829         nsCOMPtr<nsIDOMProcessingInstruction> pi = do_QueryInterface(destChild);
01830         NS_ENSURE_STATE(pi);
01831 
01832         // ignore "<?xml ... ?>" since we would have already inserted this.
01833         // XXXbeaufour: depends on omit-xml-decl, does it not?
01834 
01835         nsAutoString target;
01836         pi->GetTarget(target);
01837         if (!target.EqualsLiteral("xml"))
01838           aDest->AppendChild(destChild, getter_AddRefs(node));
01839         break;
01840       }
01841 
01842       case nsIDOMNode::TEXT_NODE: {
01843         // honor cdata-section-elements (see xslt spec section 16.1)
01844         if (aCDATAElements.IsEmpty()) {
01845           aDest->AppendChild(destChild, getter_AddRefs(node));
01846         } else {
01847           currentNode->GetParentNode(getter_AddRefs(node));
01848           NS_ENSURE_STATE(node);
01849 
01850           nsAutoString name;
01851           node->GetNodeName(name);
01852           // check to see if name is mentioned on cdataElements
01853           if (HasToken(aCDATAElements, name)) {
01854             nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(destChild);
01855             NS_ENSURE_STATE(textNode);
01856 
01857             nsAutoString textData;
01858             textNode->GetData(textData);
01859 
01860             nsCOMPtr<nsIDOMCDATASection> cdataNode;
01861             aDestDoc->CreateCDATASection(textData, getter_AddRefs(cdataNode));
01862 
01863             aDest->AppendChild(cdataNode, getter_AddRefs(node));
01864           } else {
01865             aDest->AppendChild(destChild, getter_AddRefs(node));
01866           }
01867         }
01868 
01869         break;
01870       }
01871 
01872       default: {
01873         PRUint16 handleNodeResult;
01874         aModel->HandleInstanceDataNode(currentNode, &handleNodeResult);
01875 
01876         /*
01877          *  SUBMIT_SERIALIZE_NODE   - node is to be serialized
01878          *  SUBMIT_SKIP_NODE        - node is not to be serialized
01879          *  SUBMIT_ABORT_SUBMISSION - abort submission (invalid node or empty required node)
01880          */
01881         if (handleNodeResult == nsIModelElementPrivate::SUBMIT_SKIP_NODE) {
01882           // skip node and subtree
01883           currentNode->GetNextSibling(getter_AddRefs(node));
01884           currentNode.swap(node);
01885           continue;
01886         } else if (validate &&
01887                    handleNodeResult ==
01888                      nsIModelElementPrivate::SUBMIT_ABORT_SUBMISSION) {
01889           // If node is invalid or empty required, then only fail if
01890           // @validate attribute is false
01891 
01892           // abort
01893           nsXFormsUtils::ReportError(NS_LITERAL_STRING("warnSubmitInvalidNode"),
01894                                      currentNode, nsIScriptError::warningFlag);
01895           mSubmitError = kError_ValidationError;
01896           return NS_ERROR_ILLEGAL_VALUE;
01897         }
01898 
01899         // ImportNode does not copy any properties of the currentNode. If the
01900         // node has an uploadFileProperty we need to copy it to the submission
01901         // document so that local files will be attached properly when the
01902         // submission format is multipart-related.
01903         aDest->AppendChild(destChild, getter_AddRefs(node));
01904 
01905         // If this node has attributes, make sure that we don't copy any
01906         // that aren't relevant, etc.
01907         PRBool hasAttrs = PR_FALSE;
01908         currentNode->HasAttributes(&hasAttrs);
01909         if ((type == nsIDOMNode::ELEMENT_NODE) && hasAttrs) {
01910           nsCOMPtr<nsIDOMNamedNodeMap> attrMap;
01911           nsCOMPtr<nsIDOMNode> attrDOMNode, tempNode;
01912         
01913           currentNode->GetAttributes(getter_AddRefs(attrMap));
01914           NS_ENSURE_STATE(attrMap);
01915         
01916           nsresult rv = NS_OK;
01917           PRUint32 length;
01918           nsCOMPtr<nsIDOMElement> destElem(do_QueryInterface(node));
01919           attrMap->GetLength(&length);
01920         
01921           for (PRUint32 run = 0; run < length; ++run) {
01922             attrMap->Item(run, getter_AddRefs(attrDOMNode));
01923             NS_ENSURE_STATE(attrDOMNode);
01924             aModel->HandleInstanceDataNode(attrDOMNode, &handleNodeResult);
01925 
01926             if (handleNodeResult ==
01927                        nsIModelElementPrivate::SUBMIT_ABORT_SUBMISSION) {
01928               // abort
01929               nsXFormsUtils::ReportError(NS_LITERAL_STRING("warnSubmitInvalidNode"),
01930                                          currentNode, nsIScriptError::warningFlag);
01931               mSubmitError = kError_ValidationError;
01932               return NS_ERROR_ILLEGAL_VALUE;
01933             }
01934 
01935             nsAutoString localName, namespaceURI;
01936 
01937             rv = attrDOMNode->GetLocalName(localName);
01938             NS_ENSURE_SUCCESS(rv, rv);
01939             rv = attrDOMNode->GetNamespaceURI(namespaceURI);
01940             NS_ENSURE_SUCCESS(rv, rv);
01941 
01942             if (handleNodeResult == nsIModelElementPrivate::SUBMIT_SKIP_NODE) {
01943               rv = destElem->RemoveAttributeNS(namespaceURI, localName);
01944               NS_ENSURE_SUCCESS(rv, rv);
01945             } else {
01946               // the cloning does not copy any properties of the currentNode. If
01947               // the attribute node has an uploadFileProperty we need to copy it
01948               // to the submission document so that local files will be attached
01949               // properly when the submission format is multipart-related.
01950               void* uploadFileProperty = nsnull;
01951               nsCOMPtr<nsIAttribute> attrNode(do_QueryInterface(attrDOMNode));
01952               if (attrNode) {
01953                 uploadFileProperty =
01954                   attrNode->GetProperty(nsXFormsAtoms::uploadFileProperty);
01955                 if (uploadFileProperty) {
01956                   nsCOMPtr<nsIDOMAttr> destDOMAttr;
01957                   rv = destElem->GetAttributeNodeNS(
01958                     namespaceURI, localName, getter_AddRefs(destDOMAttr));
01959                   NS_ENSURE_SUCCESS(rv, rv);
01960                   nsCOMPtr<nsIAttribute> destAttribute(
01961                     do_QueryInterface(destDOMAttr));
01962                   if (destAttribute) {
01963                     // Clone the local file so the same pointer isn't released
01964                     // twice
01965                     nsIFile *file =
01966                       NS_STATIC_CAST(nsIFile *, uploadFileProperty);
01967                     nsIFile *fileCopy = nsnull;
01968                     nsresult rv = file->Clone(&fileCopy);
01969                     NS_ENSURE_SUCCESS(rv, rv);
01970                     destAttribute->SetProperty(
01971                       nsXFormsAtoms::uploadFileProperty, fileCopy,
01972                       ReleaseObject);
01973                   }
01974                 }
01975               }
01976             }
01977           }
01978         }
01979 
01980         void* uploadFileProperty = nsnull;
01981         nsCOMPtr<nsIContent> currentNodeContent(do_QueryInterface(currentNode));
01982         if (currentNodeContent) {
01983           uploadFileProperty =
01984             currentNodeContent->GetProperty(nsXFormsAtoms::uploadFileProperty);
01985           if (uploadFileProperty) {
01986             nsCOMPtr<nsIContent> destChildContent(do_QueryInterface(node));
01987             if (destChildContent) {
01988               // Clone the local file so the same pointer isn't released twice.
01989               nsIFile *file = NS_STATIC_CAST(nsIFile *, uploadFileProperty);
01990               nsIFile *fileCopy = nsnull;
01991               nsresult rv = file->Clone(&fileCopy);
01992               NS_ENSURE_SUCCESS(rv, rv);
01993               destChildContent->SetProperty(nsXFormsAtoms::uploadFileProperty,
01994                                             fileCopy,
01995                                             ReleaseObject);
01996             }
01997           }
01998         }
01999 
02000         // recurse
02001         nsCOMPtr<nsIDOMNode> startNode;
02002         currentNode->GetFirstChild(getter_AddRefs(startNode));
02003 
02004         nsresult rv = CopyChildren(aModel, startNode, destChild, aDestDoc,
02005                                    aCDATAElements, aDepth + 1);
02006         NS_ENSURE_SUCCESS(rv, rv);
02007 
02008       }
02009     }
02010     
02011     if (!aDepth) {
02012       break;
02013     }
02014 
02015     currentNode->GetNextSibling(getter_AddRefs(node));
02016     currentNode.swap(node);
02017   }
02018 
02019   return NS_OK;
02020 }
02021 
02022 nsresult
02023 nsXFormsSubmissionElement::SerializeDataURLEncoded(nsIDOMDocument *data,
02024                                                    nsCString &uri,
02025                                                    nsIInputStream **stream,
02026                                                    nsCString &contentType)
02027 {
02028   // 'get' method:
02029   // The URI is constructed as follows:
02030   //  o The submit URI from the action attribute is examined. If it does not
02031   //    already contain a ? (question mark) character, one is appended. If it
02032   //    does already contain a question mark character, then a separator
02033   //    character from the attribute separator is appended.
02034   //  o The serialized form data is appended to the URI.
02035 
02036   nsCAutoString separator;
02037   {
02038     nsAutoString temp;
02039     mElement->GetAttribute(NS_LITERAL_STRING("separator"), temp);
02040     if (temp.IsEmpty())
02041     {
02042       separator.AssignLiteral(";");
02043     }
02044     else
02045     {
02046       // Separator per spec can only be |;| or |&|
02047       if (!temp.EqualsLiteral(";") && !temp.EqualsLiteral("&")) {
02048         // invalid separator, report the error and abort submission.
02049         // XXX: we probably should add a visual indicator
02050         const PRUnichar *strings[] = { temp.get() };
02051         nsXFormsUtils::ReportError(NS_LITERAL_STRING("invalidSeparator"),
02052                                    strings, 1, mElement, mElement);
02053         return NS_ERROR_ILLEGAL_VALUE;
02054       } else {
02055         CopyUTF16toUTF8(temp, separator);
02056       }
02057     }
02058   }
02059 
02060   if (mFormat & METHOD_GET)
02061   {
02062     if (uri.FindChar('?') == kNotFound)
02063       uri.Append('?');
02064     else
02065       uri.Append(separator);
02066     AppendURLEncodedData(data, separator, uri);
02067 
02068     *stream = nsnull;
02069     contentType.Truncate();
02070   }
02071   else if (mFormat & METHOD_POST)
02072   {
02073     nsCAutoString buf;
02074     AppendURLEncodedData(data, separator, buf);
02075 
02076     // make new stream
02077     NS_NewCStringInputStream(stream, buf);
02078     NS_ENSURE_STATE(*stream);
02079 
02080     contentType.AssignLiteral("application/x-www-form-urlencoded");
02081   }
02082   else
02083   {
02084     NS_WARNING("unexpected submission format");
02085     return NS_ERROR_UNEXPECTED;
02086   }
02087 
02088   // For HTML 4 compatibility sake, trailing separator is to be removed per an
02089   // upcoming erratum.
02090   if (StringEndsWith(uri, separator))
02091     uri.Cut(uri.Length() - 1, 1);
02092 
02093   return NS_OK;
02094 }
02095 
02096 void
02097 nsXFormsSubmissionElement::AppendURLEncodedData(nsIDOMNode *data,
02098                                                 const nsCString &separator,
02099                                                 nsCString &buf)
02100 {
02101   // 1. Each element node is visited in document order. Each element that has
02102   //    one text node child is selected for inclusion.
02103 
02104   // 2. Element nodes selected for inclusion are encoded as EltName=value{sep},
02105   //    where = is a literal character, {sep} is the separator character from the
02106   //    separator attribute on submission, EltName represents the element local
02107   //    name, and value represents the contents of the text node.
02108 
02109   // NOTE:
02110   //    The encoding of EltName and value are as follows: space characters are
02111   //    replaced by +, and then non-ASCII and reserved characters (as defined
02112   //    by [RFC 2396] as amended by subsequent documents in the IETF track) are
02113   //    escaped by replacing the character with one or more octets of the UTF-8
02114   //    representation of the character, with each octet in turn replaced by
02115   //    %HH, where HH represents the uppercase hexadecimal notation for the
02116   //    octet value and % is a literal character. Line breaks are represented
02117   //    as "CR LF" pairs (i.e., %0D%0A).
02118 
02119 #ifdef DEBUG_darinf
02120   nsAutoString nodeName;
02121   data->GetNodeName(nodeName);
02122   LOG(("+++ AppendURLEncodedData: inspecting <%s>\n",
02123       NS_ConvertUTF16toUTF8(nodeName).get()));
02124 #endif
02125 
02126   nsCOMPtr<nsIDOMNode> child;
02127   data->GetFirstChild(getter_AddRefs(child));
02128   if (!child)
02129     return;
02130 
02131   PRUint16 childType;
02132   child->GetNodeType(&childType);
02133 
02134   nsCOMPtr<nsIDOMNode> sibling;
02135   child->GetNextSibling(getter_AddRefs(sibling));
02136 
02137   if (!sibling && childType == nsIDOMNode::TEXT_NODE)
02138   {
02139     nsAutoString localName;
02140     data->GetLocalName(localName);
02141 
02142     nsAutoString value;
02143     child->GetNodeValue(value);
02144 
02145     LOG(("    appending data for <%s>\n", NS_ConvertUTF16toUTF8(localName).get()));
02146 
02147     nsCString encLocalName, encValue;
02148     URLEncode(localName, encLocalName);
02149     URLEncode(value, encValue);
02150 
02151     buf.Append(encLocalName + NS_LITERAL_CSTRING("=") + encValue + separator);
02152   }
02153   else
02154   {
02155     // call AppendURLEncodedData on each child node
02156     do
02157     {
02158       AppendURLEncodedData(child, separator, buf);
02159       child->GetNextSibling(getter_AddRefs(sibling));
02160       child.swap(sibling);
02161     }
02162     while (child);
02163   }
02164 }
02165 
02166 nsresult
02167 nsXFormsSubmissionElement::SerializeDataMultipartRelated(nsIDOMDocument *data,
02168                                                          nsIInputStream **stream,
02169                                                          nsCString &contentType)
02170 {
02171   NS_ASSERTION(mFormat & METHOD_POST, "unexpected submission method");
02172 
02173   nsCAutoString boundary;
02174   MakeMultipartBoundary(boundary);
02175 
02176   nsCOMPtr<nsIMultiplexInputStream> multiStream =
02177       do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1");
02178   NS_ENSURE_STATE(multiStream);
02179 
02180   nsCAutoString type, start;
02181 
02182   MakeMultipartContentID(start);
02183 
02184   nsresult rv;
02185   nsCOMPtr<nsIModelElementPrivate> model(GetModel());
02186   NS_ENSURE_STATE(model);
02187   SubmissionAttachmentArray attachments;
02188   rv = CreateAttachments(model, data, &attachments);
02189   NS_ENSURE_SUCCESS(rv, rv);
02190 
02191   nsCOMPtr<nsIInputStream> xml;
02192   rv = SerializeDataXML(data, getter_AddRefs(xml), type);
02193   NS_ENSURE_SUCCESS(rv, rv);
02194 
02195   // XXX we should output a 'charset=' with the 'Content-Type' header
02196 
02197   nsCString postDataChunk;
02198   postDataChunk += NS_LITERAL_CSTRING("--") + boundary
02199                 +  NS_LITERAL_CSTRING("\r\nContent-Type: ") + type
02200                 +  NS_LITERAL_CSTRING("\r\nContent-ID: <") + start
02201                 +  NS_LITERAL_CSTRING(">\r\n\r\n");
02202   rv = AppendPostDataChunk(postDataChunk, multiStream);
02203   NS_ENSURE_SUCCESS(rv, rv);
02204 
02205   multiStream->AppendStream(xml);
02206 
02207   for (PRUint32 i = 0; i < attachments.Count(); ++i) {
02208     SubmissionAttachment *a = attachments.Item(i);
02209 
02210     nsCOMPtr<nsIInputStream> fileStream;
02211     nsCAutoString type;
02212     
02213     // If the file upload control did not set a file to upload, then
02214     // we'll upload as if the file selected is empty.
02215     if (a->file)
02216     {
02217       NS_NewLocalFileInputStream(getter_AddRefs(fileStream), a->file);
02218       NS_ENSURE_SUCCESS(rv, rv);
02219 
02220       GetMimeTypeFromFile(a->file, type);
02221     }
02222     else
02223     {
02224       type.AssignLiteral("application/octet-stream");
02225     }
02226 
02227     postDataChunk += NS_LITERAL_CSTRING("\r\n--") + boundary
02228                   +  NS_LITERAL_CSTRING("\r\nContent-Type: ") + type
02229                   +  NS_LITERAL_CSTRING("\r\nContent-Transfer-Encoding: binary")
02230                   +  NS_LITERAL_CSTRING("\r\nContent-ID: <") + a->cid
02231                   +  NS_LITERAL_CSTRING(">\r\n\r\n");
02232     rv = AppendPostDataChunk(postDataChunk, multiStream);
02233     NS_ENSURE_SUCCESS(rv, rv);
02234 
02235     if (fileStream)
02236       multiStream->AppendStream(fileStream);
02237   }
02238 
02239   // final boundary
02240   postDataChunk += NS_LITERAL_CSTRING("\r\n--") + boundary
02241                 +  NS_LITERAL_CSTRING("--\r\n");
02242   rv = AppendPostDataChunk(postDataChunk, multiStream);
02243   NS_ENSURE_SUCCESS(rv, rv);
02244 
02245   contentType =
02246       NS_LITERAL_CSTRING("multipart/related; boundary=") + boundary +
02247       NS_LITERAL_CSTRING("; type=\"") + type +
02248       NS_LITERAL_CSTRING("\"; start=\"<") + start +
02249       NS_LITERAL_CSTRING(">\"");
02250 
02251   NS_ADDREF(*stream = multiStream);
02252   return NS_OK;
02253 }
02254 
02255 nsresult
02256 nsXFormsSubmissionElement::SerializeDataMultipartFormData(nsIDOMDocument *data,
02257                                                           nsIInputStream **stream,
02258                                                           nsCString &contentType)
02259 {
02260   NS_ASSERTION(mFormat & METHOD_POST, "unexpected submission method");
02261 
02262   // This format follows the rules for multipart/form-data MIME data streams in
02263   // [RFC 2388], with specific requirements of this serialization listed below:
02264   //  o Each element node is visited in document order.
02265   //  o Each element that has exactly one text node child is selected for
02266   //    inclusion.
02267   //  o Element nodes selected for inclusion are as encoded as
02268   //    Content-Disposition: form-data MIME parts as defined in [RFC 2387], with
02269   //    the name parameter being the element local name.
02270   //  o Element nodes of any datatype populated by upload are serialized as the
02271   //    specified content and additionally have a Content-Disposition filename
02272   //    parameter, if available.
02273   //  o The Content-Type must be text/plain except for xsd:base64Binary,
02274   //    xsd:hexBinary, and derived types, in which case the header represents the
02275   //    media type of the attachment if known, otherwise
02276   //    application/octet-stream. If a character set is applicable, the
02277   //    Content-Type may have a charset parameter.
02278 
02279   nsCAutoString boundary;
02280   MakeMultipartBoundary(boundary);
02281 
02282   nsCOMPtr<nsIMultiplexInputStream> multiStream =
02283       do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1");
02284   NS_ENSURE_STATE(multiStream);
02285 
02286   nsCString postDataChunk;
02287   nsresult rv = AppendMultipartFormData(data, boundary, postDataChunk, multiStream);
02288   NS_ENSURE_SUCCESS(rv, rv);
02289 
02290   postDataChunk += NS_LITERAL_CSTRING("--") + boundary
02291                 +  NS_LITERAL_CSTRING("--\r\n\r\n");
02292   rv = AppendPostDataChunk(postDataChunk, multiStream);
02293   NS_ENSURE_SUCCESS(rv, rv);
02294 
02295   contentType = NS_LITERAL_CSTRING("multipart/form-data; boundary=") + boundary;
02296 
02297   NS_ADDREF(*stream = multiStream);
02298   return NS_OK;
02299 }
02300 
02301 nsresult
02302 nsXFormsSubmissionElement::AppendMultipartFormData(nsIDOMNode *data,
02303                                                    const nsCString &boundary,
02304                                                    nsCString &postDataChunk,
02305                                                    nsIMultiplexInputStream *multiStream)
02306 {
02307 #ifdef DEBUG_darinf
02308   nsAutoString nodeName;
02309   data->GetNodeName(nodeName);
02310   LOG(("+++ AppendMultipartFormData: inspecting <%s>\n",
02311       NS_ConvertUTF16toUTF8(nodeName).get()));
02312 #endif
02313 
02314   nsresult rv;
02315 
02316   nsCOMPtr<nsIDOMNode> child;
02317   data->GetFirstChild(getter_AddRefs(child));
02318   if (!child)
02319     return NS_OK;
02320 
02321   PRUint16 childType;
02322   child->GetNodeType(&childType);
02323 
02324   nsCOMPtr<nsIDOMNode> sibling;
02325   child->GetNextSibling(getter_AddRefs(sibling));
02326 
02327   if (!sibling && childType == nsIDOMNode::TEXT_NODE)
02328   {
02329     nsAutoString localName;
02330     data->GetLocalName(localName);
02331 
02332     nsAutoString value;
02333     child->GetNodeValue(value);
02334 
02335     LOG(("    appending data for <%s>\n", NS_ConvertUTF16toUTF8(localName).get()));
02336 
02337     PRUint32 encType;
02338     rv = GetElementEncodingType(data, &encType);
02339     NS_ENSURE_SUCCESS(rv, rv);
02340 
02341     NS_ConvertUTF16toUTF8 encName(localName);
02342     encName.Adopt(nsLinebreakConverter::ConvertLineBreaks(encName.get(),
02343                   nsLinebreakConverter::eLinebreakAny,
02344                   nsLinebreakConverter::eLinebreakNet));
02345 
02346     postDataChunk += NS_LITERAL_CSTRING("--") + boundary
02347                   +  NS_LITERAL_CSTRING("\r\nContent-Disposition: form-data; name=\"")
02348                   +  encName + NS_LITERAL_CSTRING("\"");
02349 
02350     nsCAutoString contentType;
02351     nsCOMPtr<nsIInputStream> fileStream;
02352     if (encType == ELEMENT_ENCTYPE_URI)
02353     {
02354       void* uploadFileProperty = nsnull;
02355       nsCOMPtr<nsIContent> content = do_QueryInterface(data);
02356       if (content) {
02357         uploadFileProperty =
02358           content->GetProperty(nsXFormsAtoms::uploadFileProperty);
02359       } else {
02360         nsCOMPtr<nsIAttribute> attr = do_QueryInterface(data);
02361         NS_ENSURE_STATE(attr);
02362         uploadFileProperty =
02363           attr->GetProperty(nsXFormsAtoms::uploadFileProperty);
02364       }
02365       
02366       nsIFile *file = NS_STATIC_CAST(nsIFile *, uploadFileProperty);
02367 
02368       nsAutoString leafName;
02369       if (file)
02370       {
02371         NS_NewLocalFileInputStream(getter_AddRefs(fileStream), file);
02372 
02373         file->GetLeafName(leafName);
02374 
02375         // use mime service to get content-type
02376         GetMimeTypeFromFile(file, contentType);
02377       }
02378       else
02379       {
02380         contentType.AssignLiteral("application/octet-stream");
02381       }
02382 
02383       postDataChunk += NS_LITERAL_CSTRING("; filename=\"")
02384                     +  NS_ConvertUTF16toUTF8(leafName)
02385                     +  NS_LITERAL_CSTRING("\"");
02386     }
02387     else if (encType == ELEMENT_ENCTYPE_STRING)
02388     {
02389       contentType.AssignLiteral("text/plain; charset=UTF-8");
02390     }
02391     else
02392     {
02393       contentType.AssignLiteral("application/octet-stream");
02394     }
02395 
02396     postDataChunk += NS_LITERAL_CSTRING("\r\nContent-Type: ")
02397                   +  contentType
02398                   +  NS_LITERAL_CSTRING("\r\n\r\n");
02399 
02400     if (encType == ELEMENT_ENCTYPE_URI)
02401     {
02402       AppendPostDataChunk(postDataChunk, multiStream);
02403 
02404       if (fileStream)
02405         multiStream->AppendStream(fileStream);
02406 
02407       postDataChunk += NS_LITERAL_CSTRING("\r\n");
02408     }
02409     else
02410     {
02411       // for base64Binary and hexBinary types, we assume that the data is
02412       // already encoded.  this assumption is based on section 8.1.6 of the
02413       // xforms spec.
02414 
02415       // XXX UTF-8 ok?
02416       NS_ConvertUTF16toUTF8 encValue(value);
02417       encValue.Adopt(nsLinebreakConverter::ConvertLineBreaks(encValue.get(),
02418                      nsLinebreakConverter::eLinebreakAny,
02419                      nsLinebreakConverter::eLinebreakNet));
02420       postDataChunk += encValue + NS_LITERAL_CSTRING("\r\n");
02421     }
02422   }
02423   else
02424   {
02425     // call AppendMultipartFormData on each child node
02426     do
02427     {
02428       rv = AppendMultipartFormData(child, boundary, postDataChunk, multiStream);
02429       if (NS_FAILED(rv))
02430         return rv;
02431       child->GetNextSibling(getter_AddRefs(sibling));
02432       child.swap(sibling);
02433     }
02434     while (child);
02435   }
02436   return NS_OK;
02437 }
02438 
02439 nsresult
02440 nsXFormsSubmissionElement::AppendPostDataChunk(nsCString &postDataChunk,
02441                                                nsIMultiplexInputStream *multiStream)
02442 {
02443   nsCOMPtr<nsIInputStream> stream;
02444   NS_NewCStringInputStream(getter_AddRefs(stream), postDataChunk);
02445   NS_ENSURE_TRUE(stream, NS_ERROR_OUT_OF_MEMORY);
02446 
02447   multiStream->AppendStream(stream);
02448 
02449   postDataChunk.Truncate();
02450   return NS_OK;
02451 }
02452 
02453 nsresult
02454 nsXFormsSubmissionElement::GetElementEncodingType(nsIDOMNode             *node,
02455                                                   PRUint32               *encType,
02456                                                   nsIModelElementPrivate *aModel)
02457 {
02458   *encType = ELEMENT_ENCTYPE_STRING; // default
02459 
02460   // check for 'xsd:base64Binary', 'xsd:hexBinary', or 'xsd:anyURI'
02461   nsAutoString type, nsuri;
02462   nsresult rv;
02463   if (aModel) {
02464     rv = aModel->GetTypeFromNode(node, type, nsuri);
02465   } else {
02466     rv = nsXFormsUtils::ParseTypeFromNode(node, type, nsuri);
02467   }
02468   if (NS_SUCCEEDED(rv) &&
02469       nsuri.EqualsLiteral(NS_NAMESPACE_XML_SCHEMA) &&
02470       !type.IsEmpty())
02471   {
02472     if (type.Equals(NS_LITERAL_STRING("anyURI")))
02473       *encType = ELEMENT_ENCTYPE_URI;
02474     else if (type.Equals(NS_LITERAL_STRING("base64Binary")))
02475       *encType = ELEMENT_ENCTYPE_BASE64;
02476     else if (type.Equals(NS_LITERAL_STRING("hexBinary")))
02477       *encType = ELEMENT_ENCTYPE_HEX;
02478 
02479     // XXX need to handle derived types (fixing bug 263384 will help)
02480   }
02481 
02482   return NS_OK;
02483 }
02484 
02485 nsresult
02486 nsXFormsSubmissionElement::CreateFileStream(const nsString &absURI,
02487                                             nsIFile **resultFile,
02488                                             nsIInputStream **resultStream)
02489 {
02490   LOG(("nsXFormsSubmissionElement::CreateFileStream [%s]\n",
02491       NS_ConvertUTF16toUTF8(absURI).get()));
02492 
02493   nsCOMPtr<nsIURI> uri;
02494   NS_NewURI(getter_AddRefs(uri), absURI);
02495   NS_ENSURE_STATE(uri);
02496 
02497   // restrict to file:// -- XXX is this correct?
02498   PRBool schemeIsFile = PR_FALSE;
02499   uri->SchemeIs("file", &schemeIsFile);
02500   NS_ENSURE_STATE(schemeIsFile);
02501 
02502   // NOTE: QI to nsIFileURL just means that the URL corresponds to a 
02503   // local file resource, which is not restricted to file://
02504   nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(uri);
02505   NS_ENSURE_STATE(fileURL);
02506 
02507   fileURL->GetFile(resultFile);
02508   NS_ENSURE_STATE(*resultFile);
02509 
02510   return NS_NewLocalFileInputStream(resultStream, *resultFile);
02511 }
02512 
02513 nsresult
02514 nsXFormsSubmissionElement::SendData(const nsCString &uriSpec,
02515                                     nsIInputStream *stream,
02516                                     const nsCString &contentType)
02517 {
02518   LOG(("+++ sending to uri=%s [stream=%p]\n", uriSpec.get(), (void*) stream));
02519 
02520   nsCOMPtr<nsIDOMDocument> domDoc;
02521   mElement->GetOwnerDocument(getter_AddRefs(domDoc));
02522 
02523   nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
02524   NS_ENSURE_STATE(doc);
02525 
02526   nsCOMPtr<nsIIOService> ios = do_GetIOService();
02527   NS_ENSURE_STATE(ios);
02528 
02529   nsCOMPtr<nsIURI> currURI = doc->GetDocumentURI();
02530 
02531   // Any parameters appended to uriSpec are already ASCII-encoded per the rules
02532   // of section 11.6.  Use our standard document charset based canonicalization
02533   // for any other non-ASCII bytes.  (This might be important for compatibility
02534   // with legacy CGI processors.)
02535   nsCOMPtr<nsIURI> uri;
02536   ios->NewURI(uriSpec,
02537               doc->GetDocumentCharacterSet().get(),
02538               currURI,
02539               getter_AddRefs(uri));
02540   NS_ENSURE_STATE(uri);
02541 
02542   nsresult rv;
02543 
02544   // handle mailto: submission
02545   if (!mIsReplaceInstance) {
02546     PRBool isMailto;
02547     rv = uri->SchemeIs("mailto", &isMailto);
02548     NS_ENSURE_SUCCESS(rv, rv);
02549 
02550     if (isMailto) {
02551       nsCOMPtr<nsIExternalProtocolService> extProtService =
02552         do_GetService("@mozilla.org/uriloader/external-protocol-service;1");
02553       NS_ENSURE_STATE(extProtService);
02554 
02555       PRBool hasExposedMailClient;
02556       rv = extProtService->ExternalProtocolHandlerExists("mailto",
02557                                                          &hasExposedMailClient);
02558       NS_ENSURE_SUCCESS(rv, rv);
02559 
02560       if (hasExposedMailClient) {
02561         nsCAutoString mailtoUrl(uriSpec);
02562 
02563         // A mailto url looks like this: mailto:foo@bar.com, which can be followed
02564         // by parameters (subject and body).  The first parameter has to have an
02565         // "?" before it, and an additional one needs to have an "&".
02566         // So if "?" already exists in the string, we use "&".
02567 
02568         if (mailtoUrl.Find("&body=") != kNotFound ||
02569             mailtoUrl.Find("?body=") != kNotFound) {
02570           // body parameter already exists, so report a warning
02571           nsXFormsUtils::ReportError(NS_LITERAL_STRING("warnMailtoBodyParam"),
02572                                      mElement, nsIScriptError::warningFlag);
02573         }
02574 
02575         if (mailtoUrl.FindChar('?') != kNotFound)
02576           mailtoUrl.AppendLiteral("&body=");
02577         else
02578           mailtoUrl.AppendLiteral("?body=");
02579 
02580         // get the stream contents
02581         PRUint32 len, read, numReadIn = 1;
02582         rv = stream->Available(&len);
02583         NS_ENSURE_SUCCESS(rv, rv);
02584 
02585         char *buf = new char[len+1];
02586         if (buf == NULL) {
02587           return NS_ERROR_OUT_OF_MEMORY;
02588         }
02589         memset(buf, 0, len+1);
02590 
02591         // Read returns 0 if eos
02592         while (numReadIn != 0) {
02593           numReadIn = stream->Read(buf, len, &read);
02594           NS_EscapeURL(buf, read, esc_Query|esc_AlwaysCopy, mailtoUrl);
02595         }
02596 
02597         delete [] buf;
02598 
02599         // create an nsIUri out of the string
02600         nsCOMPtr<nsIURI> mailUri;
02601         ios->NewURI(mailtoUrl,
02602                     nsnull,
02603                     nsnull,
02604                     getter_AddRefs(mailUri));
02605         NS_ENSURE_STATE(mailUri);
02606 
02607         // let the OS handle the uri
02608         rv = extProtService->LoadURI(mailUri, nsnull);
02609 
02610         if (NS_FAILED(rv)) {
02611           // opening an mail client failed.
02612           nsXFormsUtils::ReportError(NS_LITERAL_STRING("submitMailtoFailed"),
02613                                      mElement);
02614           EndSubmit(PR_FALSE);
02615         } else {
02616           // the protocol service succeeded
02617           EndSubmit(PR_TRUE);
02618         }
02619 
02620       } else {
02621         // no system mail client found
02622         nsXFormsUtils::ReportError(NS_LITERAL_STRING("submitMailtoInit"),
02623                                    mElement);
02624         EndSubmit(PR_FALSE);
02625       }
02626 
02627       return NS_OK;
02628     }
02629   }
02630 
02631   if (!CheckSameOrigin(doc, uri)) {
02632     nsXFormsUtils::ReportError(NS_LITERAL_STRING("submitSendOrigin"),
02633                                mElement);
02634     return NS_ERROR_ABORT;
02635   }
02636 
02637   nsCOMPtr<nsIChannel> channel;
02638   ios->NewChannelFromURI(uri, getter_AddRefs(channel));
02639   NS_ENSURE_STATE(channel);
02640 
02641   PRBool ignoreStream = PR_FALSE;
02642   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
02643 
02644   if (httpChannel) {
02645     httpChannel->SetReferrer(currURI);
02646     OverrideRequestHeaders(httpChannel);
02647   }
02648 
02649   if (mFormat & METHOD_POST) {
02650     if (!httpChannel) {
02651       // The spec doesn't really say how to handle post with anything other
02652       // than http.  So we are free to make up our own rules.
02653       // The only other protocols we quasi support are file and mailto.  Mailto
02654       // has already been handled by this point.  For file we'll still do the
02655       // post, but we won't bother to 'send any data' since that really has
02656       // no meaning.  This will cause Mozilla to get the local file.
02657       // Since this is a kludgy kind of behavior to begin with (the user
02658       // really shouldn't use POST with file:/// to begin with) we'll
02659       // behave like formsPlayer and only allow this for replace="all" and
02660       // replace="none".  If replace="instance", we'll throw an
02661       // xforms-submit-error.  Again, this is for compliance with formsPlayer.
02662       // A good form author should never cause us to reach here!
02663       nsCAutoString scheme;
02664       rv = uri->GetScheme(scheme);
02665       NS_ENSURE_SUCCESS(rv, rv);
02666   
02667       PRBool allowSubmission = scheme.EqualsLiteral("file");
02668       if (allowSubmission) {
02669         if (!mIsReplaceInstance) {
02670           ignoreStream = PR_TRUE;
02671         } else {
02672           allowSubmission = PR_FALSE;
02673         }
02674       }
02675 
02676       if (!allowSubmission) {
02677         nsAutoString schemeTemp = NS_ConvertASCIItoUTF16(scheme);
02678         const PRUnichar *strings[] = { schemeTemp.get() };
02679         nsXFormsUtils::ReportError(NS_LITERAL_STRING("warnSubmitProtocolPost"),
02680                                    strings, 1, mElement, mElement,
02681                                    nsIScriptError::warningFlag);
02682         return NS_ERROR_UNEXPECTED;
02683       }
02684     }
02685   }
02686 
02687   // wrap the entire upload stream in a buffered input stream, so that
02688   // it can be read in large chunks.
02689   // XXX necko should probably do this (or something like this) for us.
02690   nsCOMPtr<nsIInputStream> bufferedStream;
02691   if (stream && !ignoreStream)
02692   {
02693     NS_NewBufferedInputStream(getter_AddRefs(bufferedStream), stream, 4096);
02694     NS_ENSURE_STATE(bufferedStream);
02695     nsCOMPtr<nsIUploadChannel> uploadChannel = do_QueryInterface(channel);
02696     NS_ENSURE_STATE(uploadChannel);
02697 
02698     // this in effect sets the request method of the channel to 'PUT'
02699     rv = uploadChannel->SetUploadStream(bufferedStream, contentType, -1);
02700     NS_ENSURE_SUCCESS(rv, rv);
02701   }
02702 
02703   if (mFormat & METHOD_POST && httpChannel) {
02704     // In this case we want to set the request header to have the method of
02705     // 'post'.  We need to leave this code after the call to SetUploadStream
02706     // since that will blindly overwrite the request header with a method of
02707     // 'put'
02708     rv = httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
02709     NS_ENSURE_SUCCESS(rv, rv);
02710   
02711     if (mIsSOAPRequest) {
02712       nsCOMPtr<nsIMIMEHeaderParam> mimeHdrParser =
02713         do_GetService("@mozilla.org/network/mime-hdrparam;1");
02714       NS_ENSURE_STATE(mimeHdrParser);
02715   
02716       nsAutoString mediatype, action;
02717       mElement->GetAttribute(NS_LITERAL_STRING("mediatype"),
02718                              mediatype);
02719       if (!mediatype.IsEmpty()) {
02720         
02721         rv = mimeHdrParser->GetParameter(NS_ConvertUTF16toUTF8(mediatype),
02722                                          "action", EmptyCString(), PR_FALSE,
02723                                          nsnull, action);
02724       }
02725       if (action.IsEmpty()) {
02726         action.AssignLiteral(" ");
02727       }
02728       rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("SOAPAction"),
02729                                          NS_ConvertUTF16toUTF8(action),
02730                                          PR_FALSE);
02731       NS_ENSURE_SUCCESS(rv, rv);
02732     }
02733   }
02734 
02735   // set loadGroup and notificationCallbacks
02736 
02737   nsCOMPtr<nsILoadGroup> loadGroup = doc->GetDocumentLoadGroup();
02738   channel->SetLoadGroup(loadGroup);
02739 
02740   // set LOAD_DOCUMENT_URI so throbber works during submit
02741   nsLoadFlags loadFlags = 0;
02742   channel->GetLoadFlags(&loadFlags);
02743   loadFlags |= nsIChannel::LOAD_DOCUMENT_URI;
02744   channel->SetLoadFlags(loadFlags);
02745 
02746   // create a pipe in which to store the response (yeah, this kind of
02747   // sucks since we'll use a lot of memory if the response is large).
02748   //
02749   // pipe uses non-blocking i/o since we are just using it for temporary
02750   // storage.
02751   //
02752   // pipe's maximum size is unlimited (gasp!)
02753 
02754   nsCOMPtr<nsIOutputStream> pipeOut;
02755   rv = NS_NewPipe(getter_AddRefs(mPipeIn), getter_AddRefs(pipeOut),
02756                   4096, PR_UINT32_MAX, PR_TRUE, PR_TRUE);
02757   NS_ENSURE_SUCCESS(rv, rv);
02758 
02759   // use a simple stream listener to tee our data into the pipe, and
02760   // notify us when the channel starts and stops.
02761 
02762   nsCOMPtr<nsIStreamListener> listener;
02763   rv = NS_NewSimpleStreamListener(getter_AddRefs(listener), pipeOut, this);
02764   NS_ENSURE_SUCCESS(rv, rv);
02765 
02766   channel->SetNotificationCallbacks(this);
02767   rv = channel->AsyncOpen(listener, nsnull);
02768   NS_ENSURE_SUCCESS(rv, rv);
02769 
02770   return rv;
02771 }
02772 
02773 // nsIHttpHeaderVisitor
02774 NS_IMETHODIMP
02775 nsXFormsSubmissionElement::VisitHeader(const nsACString &aHeader,
02776                                        const nsACString &aValue)
02777 {
02778   nsresult rv;
02779   nsCOMPtr<nsIDOMElement> rootElt;
02780   nsCOMPtr<nsIDOMNode> newChild;
02781 
02782   // Every time this callback is called, we add another
02783   // <header><name>aHeader</name><value>aValue</value></header> element
02784   // to the http header document. The header document is used to create
02785   // a nodeset of header elements in the context info.
02786   if (!mHttpHeaderDoc) {
02787     nsCOMPtr<nsIDOMDocument> doc;
02788     rv = mElement->GetOwnerDocument(getter_AddRefs(doc));
02789     NS_ENSURE_SUCCESS(rv, rv);
02790 
02791     nsCOMPtr<nsIDOMDOMImplementation> domImpl;
02792     rv = doc->GetImplementation(getter_AddRefs(domImpl));
02793     NS_ENSURE_SUCCESS(rv, rv);
02794 
02795     rv = domImpl->CreateDocument(EmptyString(), EmptyString(), nsnull,
02796                                  getter_AddRefs(mHttpHeaderDoc));
02797     NS_ENSURE_SUCCESS(rv, rv);
02798 
02799     rv = mHttpHeaderDoc->CreateElement(NS_LITERAL_STRING("headers"),
02800                                        getter_AddRefs(rootElt));
02801     NS_ENSURE_SUCCESS(rv, rv);
02802 
02803     mHttpHeaderDoc->AppendChild(rootElt, getter_AddRefs(newChild));
02804   }
02805 
02806   nsCOMPtr<nsIDOMElement> headerElt, nameElt, valueElt;
02807   nsCOMPtr<nsIDOMNode> rootNode;
02808 
02809   // Root <headers> element.
02810   rv = mHttpHeaderDoc->GetFirstChild(getter_AddRefs(rootNode));
02811   NS_ENSURE_SUCCESS(rv, rv);
02812 
02813   // <header>
02814   rv = mHttpHeaderDoc->CreateElement(NS_LITERAL_STRING("header"),
02815                                      getter_AddRefs(headerElt));
02816 
02817   // <name>
02818   rv = mHttpHeaderDoc->CreateElement(NS_LITERAL_STRING("name"),
02819                                      getter_AddRefs(nameElt));
02820   NS_ENSURE_SUCCESS(rv, rv);
02821 
02822   nsCOMPtr<nsIDOMText> nameTextNode;
02823   rv = mHttpHeaderDoc->CreateTextNode(NS_ConvertUTF8toUTF16(aHeader),
02824                                       getter_AddRefs(nameTextNode));
02825   NS_ENSURE_SUCCESS(rv, rv);
02826 
02827   nameElt->AppendChild(nameTextNode, getter_AddRefs(newChild));
02828   headerElt->AppendChild(nameElt, getter_AddRefs(newChild));
02829 
02830   // <value>
02831   rv = mHttpHeaderDoc->CreateElement(NS_LITERAL_STRING("value"),
02832                                      getter_AddRefs(valueElt));
02833   NS_ENSURE_SUCCESS(rv, rv);
02834 
02835   nsCOMPtr<nsIDOMText> valueTextNode;
02836   rv = mHttpHeaderDoc->CreateTextNode(NS_ConvertUTF8toUTF16(aValue),
02837                                       getter_AddRefs(valueTextNode));
02838   NS_ENSURE_SUCCESS(rv, rv);
02839 
02840   valueElt->AppendChild(valueTextNode, getter_AddRefs(newChild));
02841   headerElt->AppendChild(valueElt, getter_AddRefs(newChild));
02842 
02843   // Append <header> element to root <headers> element.
02844   rootElt = do_QueryInterface(rootNode);
02845   rootElt->AppendChild(headerElt, getter_AddRefs(newChild));
02846 
02847   return NS_OK;
02848 }
02849 
02850 nsresult
02851 nsXFormsSubmissionElement::SetContextInfo()
02852 {
02853 
02854   return NS_OK;
02855 }
02856 
02857 nsresult
02858 nsXFormsSubmissionElement::SetHttpContextInfo(PRUint32  aResponse,
02859                                               const nsAString &aResponseText)
02860 {
02861   nsresult rv;
02862 
02863   nsCOMPtr<nsXFormsContextInfo> contextInfo = new nsXFormsContextInfo(mElement);
02864   NS_ENSURE_TRUE(contextInfo, NS_ERROR_OUT_OF_MEMORY);
02865   // response-status-code
02866   if (aResponse > 0) {
02867     contextInfo->SetNumberValue("response-status-code", aResponse);
02868     mContextInfo.AppendObject(contextInfo);
02869   }
02870   // response-reason-phrase
02871   contextInfo = new nsXFormsContextInfo(mElement);
02872   NS_ENSURE_TRUE(contextInfo, NS_ERROR_OUT_OF_MEMORY);
02873   contextInfo->SetStringValue("response-reason-phrase", aResponseText);
02874   mContextInfo.AppendObject(contextInfo);
02875   // response-headers
02876   if (mHttpHeaderDoc) {
02877     nsCOMPtr<nsIDOMNode> rootNode;
02878     rv = mHttpHeaderDoc->GetFirstChild(getter_AddRefs(rootNode));
02879     NS_ENSURE_SUCCESS(rv, rv);
02880 
02881     nsCOMPtr<nsIDOMXPathResult> headerNodeset;
02882     nsAutoString expr;
02883     expr.AssignLiteral("header");
02884     rv = nsXFormsUtils::EvaluateXPath(expr, rootNode, rootNode,
02885                                       nsIDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE,
02886                                       getter_AddRefs(headerNodeset));
02887 
02888     NS_ENSURE_SUCCESS(rv, rv);
02889 
02890     if (headerNodeset) {
02891       contextInfo = new nsXFormsContextInfo(mElement);
02892       NS_ENSURE_TRUE(contextInfo, NS_ERROR_OUT_OF_MEMORY);
02893       contextInfo->SetNodesetValue("response-headers", headerNodeset);
02894       mContextInfo.AppendObject(contextInfo);
02895 #ifdef DEBUG
02896       PRUint32 nodesetSize = 0;
02897       headerNodeset->GetSnapshotLength(&nodesetSize);
02898       for (PRUint32 i = 0; i < nodesetSize; i++) {
02899         nsCOMPtr<nsIDOMNode> headerNode, nameNode, valueNode;
02900         headerNodeset->SnapshotItem(i, getter_AddRefs(headerNode));
02901         headerNode->GetFirstChild(getter_AddRefs(nameNode));
02902         nsAutoString name, value;
02903         nsXFormsUtils::GetNodeValue(nameNode, name);
02904         nameNode->GetNextSibling(getter_AddRefs(valueNode));
02905         nsXFormsUtils::GetNodeValue(valueNode, value);
02906       }
02907 #endif // DEBUG
02908     }
02909   }
02910 
02911   return NS_OK;
02912 }
02913 
02914 nsresult
02915 nsXFormsSubmissionElement::ParseErrorResponse(nsIChannel *aChannel)
02916 {
02917   // Context Info: response-body
02918   // When the error response specifies an XML media type as defined by
02919   // RFC 3023], the response body is parsed into an XML document and the
02920   // root element of the document is returned. If the parse fails, or if
02921   // the error response specifies a text media type (starting with text/),
02922   // then the response body is returned as a string.
02923   // Otherwise, an empty string is returned.
02924   nsCString contentCharset, contentType;
02925   aChannel->GetContentCharset(contentCharset);
02926   aChannel->GetContentType(contentType);
02927 
02928   // use DOM parser to construct nsIDOMDocument
02929   nsCOMPtr<nsIDOMParser> parser =
02930     do_CreateInstance("@mozilla.org/xmlextras/domparser;1");
02931   NS_ENSURE_STATE(parser);
02932 
02933   PRUint32 contentLength;
02934   mPipeIn->Available(&contentLength);
02935 
02936   // set the base uri so that the document can get the correct security
02937   // principal.
02938   nsCOMPtr<nsIURI> uri;
02939   nsresult rv = aChannel->GetURI(getter_AddRefs(uri));
02940   NS_ENSURE_SUCCESS(rv, rv);
02941   rv = parser->SetBaseURI(uri);
02942   NS_ENSURE_SUCCESS(rv, rv);
02943 
02944   // Try to parse the content into an XML document. If the parse fails, the
02945   // content type is not an XML type that ParseFromStream can handle. In that
02946   // case, read the response as a simple string.
02947   nsCOMPtr<nsXFormsContextInfo> contextInfo;
02948   nsCOMPtr<nsIDOMDocument> newDoc;
02949   rv = parser->ParseFromStream(mPipeIn, contentCharset.get(), contentLength,
02950                                contentType.get(), getter_AddRefs(newDoc));
02951   if (NS_SUCCEEDED(rv)) {
02952     // Succeeded in parsing the error response as an XML document.
02953     nsCOMPtr<nsIDOMNode> responseBody = do_QueryInterface(newDoc);
02954     if (newDoc) {
02955       contextInfo = new nsXFormsContextInfo(mElement);
02956       NS_ENSURE_TRUE(contextInfo, NS_ERROR_OUT_OF_MEMORY);
02957 
02958       contextInfo->SetNodeValue("response-body", responseBody);
02959       mContextInfo.AppendObject(contextInfo);
02960     }
02961   } else {
02962     // Read the content as a simple string and set a string into the
02963     // context info.
02964     PRUint32 len, read, numReadIn = 1;
02965     nsCAutoString responseBody;
02966 
02967     rv = mPipeIn->Available(&len);
02968     NS_ENSURE_SUCCESS(rv, rv);
02969 
02970     char *buf = new char[len+1];
02971     NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY);
02972     memset(buf, 0, len+1);
02973 
02974     // Read returns 0 if eos
02975     while (numReadIn != 0) {
02976       numReadIn = mPipeIn->Read(buf, len, &read);
02977       responseBody.Append(buf);
02978     }
02979     delete [] buf;
02980 
02981     // Set the string response body as context info.
02982     contextInfo = new nsXFormsContextInfo(mElement);
02983     NS_ENSURE_TRUE(contextInfo, NS_ERROR_OUT_OF_MEMORY);
02984     contextInfo->SetStringValue("response-body",
02985                                 NS_ConvertUTF8toUTF16(responseBody));
02986     mContextInfo.AppendObject(contextInfo);
02987   }
02988 
02989   return NS_OK;
02990 }
02991 
02992 // factory constructor
02993 
02994 nsresult
02995 NS_NewXFormsSubmissionElement(nsIXTFElement **aResult)
02996 {
02997   *aResult = new nsXFormsSubmissionElement();
02998   if (!*aResult)
02999     return NS_ERROR_OUT_OF_MEMORY;
03000 
03001   NS_ADDREF(*aResult);
03002   return NS_OK;
03003 }