diff --git a/mozilla/content/base/public/nsIDocument.h b/mozilla/content/base/public/nsIDocument.h index fff910f6412..10485655c5d 100644 --- a/mozilla/content/base/public/nsIDocument.h +++ b/mozilla/content/base/public/nsIDocument.h @@ -39,6 +39,13 @@ class nsString; { 0x94c6ceb0, 0x9447, 0x11d1, \ {0x93, 0x23, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } +// specification for data to be sent via form "post" +class nsIPostData { +public: + virtual PRBool IsFile() = 0; // is the data a file (or raw data) + virtual const char* GetData() = 0; // get the file name or raw data +}; + //---------------------------------------------------------------------- // Document interface @@ -49,7 +56,7 @@ public: // returns the arena associated with this document. virtual nsIArena* GetArena() = 0; - virtual void LoadURL(nsIURL* aURL) = 0; + virtual void LoadURL(nsIURL* aURL, nsIPostData* aPostData = 0) = 0; virtual void StartDocumentLoad() = 0; virtual void PauseDocumentLoad() = 0; @@ -169,5 +176,7 @@ public: // XXX Belongs somewhere else extern NS_LAYOUT nsresult NS_NewHTMLDocument(nsIDocument** aInstancePtrResult); +extern NS_LAYOUT nsresult + NS_NewPostData(nsIPostData* aPostData, nsIPostData** aInstancePtrResult); #endif /* nsIDocument_h___ */ diff --git a/mozilla/content/base/src/nsDocument.cpp b/mozilla/content/base/src/nsDocument.cpp index b55c32284a6..add42e0beb0 100644 --- a/mozilla/content/base/src/nsDocument.cpp +++ b/mozilla/content/base/src/nsDocument.cpp @@ -39,6 +39,27 @@ static NS_DEFINE_IID(kIContentIID, NS_ICONTENT_IID); static NS_DEFINE_IID(kIDOMElementIID, NS_IDOMELEMENT_IID); static NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID); +NS_LAYOUT nsresult +NS_NewPostData(nsIPostData* aPostData, nsIPostData** aInstancePtrResult) +{ + *aInstancePtrResult = new nsPostData(aPostData); + return NS_OK; +} + +nsPostData::nsPostData(nsIPostData* aPostData) +{ + mIsFile = PR_FALSE; + mData = nsnull; + if (aPostData) { + mIsFile = aPostData->IsFile(); + const char* data = aPostData->GetData(); + if (data) { + PRInt32 len = strlen(data); + mData = new char[len+1]; + strcpy(mData, data); + } + } +} nsDocument::nsDocument() { diff --git a/mozilla/content/base/src/nsDocument.h b/mozilla/content/base/src/nsDocument.h index 4b8cdc4ef37..b1e844aea73 100644 --- a/mozilla/content/base/src/nsDocument.h +++ b/mozilla/content/base/src/nsDocument.h @@ -25,6 +25,17 @@ class nsISelection; +class nsPostData : public nsIPostData { +public: + nsPostData(PRBool aIsFile, char* aData) : mIsFile(aIsFile), mData(aData) {} + nsPostData(nsIPostData* aPostData); + PRBool IsFile() { return mIsFile; } + const char* GetData() { return mData; } +protected: + PRBool mIsFile; + char* mData; +}; + // Base class for our document implementations class nsDocument : public nsIDocument, public nsIDOMDocument, public nsIScriptObjectOwner { public: diff --git a/mozilla/content/html/document/src/nsHTMLDocument.cpp b/mozilla/content/html/document/src/nsHTMLDocument.cpp index 81f6615b372..36832987494 100644 --- a/mozilla/content/html/document/src/nsHTMLDocument.cpp +++ b/mozilla/content/html/document/src/nsHTMLDocument.cpp @@ -30,7 +30,7 @@ #include "nsIHTMLContent.h" #include "nsIDOMElement.h" #include "nsIDOMText.h" -#include "nsIPostToServer.h" //XXX temp +#include "nsIPostToServer.h" static NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID); static NS_DEFINE_IID(kIDOMElementIID, NS_IDOMELEMENT_IID); @@ -72,7 +72,7 @@ NS_IMETHODIMP nsHTMLDocument::QueryInterface(REFNSIID aIID, return nsDocument::QueryInterface(aIID, aInstancePtr); } -void nsHTMLDocument::LoadURL(nsIURL* aURL) +void nsHTMLDocument::LoadURL(nsIURL* aURL, nsIPostData* aPostData) { // Delete references to style sheets - this should be done in superclass... PRInt32 index = mStyleSheets.Count(); @@ -92,18 +92,18 @@ void nsHTMLDocument::LoadURL(nsIURL* aURL) mDocumentURL = aURL; NS_ADDREF(aURL); - // XXX temporary hack code static NS_DEFINE_IID(kPostToServerIID, NS_IPOSTTOSERVER_IID); - const char* temp = aURL->GetFile(); - if (temp != NULL && strcmp(temp,"/cgi-bin/post-query") == 0) { - nsIPostToServer* pts; - nsresult result = aURL->QueryInterface(kPostToServerIID, (void **)&pts); - if (NS_OK == result) { - char buf[100]; - //strcpy(&buf[0], "Content-type: application/x-www-form-urlencoded\nname=foo"); - strcpy(&buf[0], "name=foo"); - PRInt32 len = strlen(&buf[0]); - pts->SendData(&buf[0], len); + if (aPostData) { + const char* data = aPostData->GetData(); + if (data) { + nsIPostToServer* pts; + nsresult result = aURL->QueryInterface(kPostToServerIID, (void **)&pts); + if (aPostData->IsFile()) { + pts->SendDataFromFile(data); + } + else { + pts->SendData(data, strlen(data)); + } } } diff --git a/mozilla/content/html/document/src/nsHTMLDocument.h b/mozilla/content/html/document/src/nsHTMLDocument.h index ca62208840c..df2da149826 100644 --- a/mozilla/content/html/document/src/nsHTMLDocument.h +++ b/mozilla/content/html/document/src/nsHTMLDocument.h @@ -30,7 +30,7 @@ public: NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); - virtual void LoadURL(nsIURL* aURL); + virtual void LoadURL(nsIURL* aURL, nsIPostData* aPostData = 0); NS_IMETHOD SetTitle(const nsString& aTitle); diff --git a/mozilla/layout/base/public/nsIDocument.h b/mozilla/layout/base/public/nsIDocument.h index fff910f6412..10485655c5d 100644 --- a/mozilla/layout/base/public/nsIDocument.h +++ b/mozilla/layout/base/public/nsIDocument.h @@ -39,6 +39,13 @@ class nsString; { 0x94c6ceb0, 0x9447, 0x11d1, \ {0x93, 0x23, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } +// specification for data to be sent via form "post" +class nsIPostData { +public: + virtual PRBool IsFile() = 0; // is the data a file (or raw data) + virtual const char* GetData() = 0; // get the file name or raw data +}; + //---------------------------------------------------------------------- // Document interface @@ -49,7 +56,7 @@ public: // returns the arena associated with this document. virtual nsIArena* GetArena() = 0; - virtual void LoadURL(nsIURL* aURL) = 0; + virtual void LoadURL(nsIURL* aURL, nsIPostData* aPostData = 0) = 0; virtual void StartDocumentLoad() = 0; virtual void PauseDocumentLoad() = 0; @@ -169,5 +176,7 @@ public: // XXX Belongs somewhere else extern NS_LAYOUT nsresult NS_NewHTMLDocument(nsIDocument** aInstancePtrResult); +extern NS_LAYOUT nsresult + NS_NewPostData(nsIPostData* aPostData, nsIPostData** aInstancePtrResult); #endif /* nsIDocument_h___ */ diff --git a/mozilla/layout/base/src/nsDocument.cpp b/mozilla/layout/base/src/nsDocument.cpp index b55c32284a6..add42e0beb0 100644 --- a/mozilla/layout/base/src/nsDocument.cpp +++ b/mozilla/layout/base/src/nsDocument.cpp @@ -39,6 +39,27 @@ static NS_DEFINE_IID(kIContentIID, NS_ICONTENT_IID); static NS_DEFINE_IID(kIDOMElementIID, NS_IDOMELEMENT_IID); static NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID); +NS_LAYOUT nsresult +NS_NewPostData(nsIPostData* aPostData, nsIPostData** aInstancePtrResult) +{ + *aInstancePtrResult = new nsPostData(aPostData); + return NS_OK; +} + +nsPostData::nsPostData(nsIPostData* aPostData) +{ + mIsFile = PR_FALSE; + mData = nsnull; + if (aPostData) { + mIsFile = aPostData->IsFile(); + const char* data = aPostData->GetData(); + if (data) { + PRInt32 len = strlen(data); + mData = new char[len+1]; + strcpy(mData, data); + } + } +} nsDocument::nsDocument() { diff --git a/mozilla/layout/base/src/nsDocument.h b/mozilla/layout/base/src/nsDocument.h index 4b8cdc4ef37..b1e844aea73 100644 --- a/mozilla/layout/base/src/nsDocument.h +++ b/mozilla/layout/base/src/nsDocument.h @@ -25,6 +25,17 @@ class nsISelection; +class nsPostData : public nsIPostData { +public: + nsPostData(PRBool aIsFile, char* aData) : mIsFile(aIsFile), mData(aData) {} + nsPostData(nsIPostData* aPostData); + PRBool IsFile() { return mIsFile; } + const char* GetData() { return mData; } +protected: + PRBool mIsFile; + char* mData; +}; + // Base class for our document implementations class nsDocument : public nsIDocument, public nsIDOMDocument, public nsIScriptObjectOwner { public: diff --git a/mozilla/layout/html/document/src/nsHTMLDocument.cpp b/mozilla/layout/html/document/src/nsHTMLDocument.cpp index 81f6615b372..36832987494 100644 --- a/mozilla/layout/html/document/src/nsHTMLDocument.cpp +++ b/mozilla/layout/html/document/src/nsHTMLDocument.cpp @@ -30,7 +30,7 @@ #include "nsIHTMLContent.h" #include "nsIDOMElement.h" #include "nsIDOMText.h" -#include "nsIPostToServer.h" //XXX temp +#include "nsIPostToServer.h" static NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID); static NS_DEFINE_IID(kIDOMElementIID, NS_IDOMELEMENT_IID); @@ -72,7 +72,7 @@ NS_IMETHODIMP nsHTMLDocument::QueryInterface(REFNSIID aIID, return nsDocument::QueryInterface(aIID, aInstancePtr); } -void nsHTMLDocument::LoadURL(nsIURL* aURL) +void nsHTMLDocument::LoadURL(nsIURL* aURL, nsIPostData* aPostData) { // Delete references to style sheets - this should be done in superclass... PRInt32 index = mStyleSheets.Count(); @@ -92,18 +92,18 @@ void nsHTMLDocument::LoadURL(nsIURL* aURL) mDocumentURL = aURL; NS_ADDREF(aURL); - // XXX temporary hack code static NS_DEFINE_IID(kPostToServerIID, NS_IPOSTTOSERVER_IID); - const char* temp = aURL->GetFile(); - if (temp != NULL && strcmp(temp,"/cgi-bin/post-query") == 0) { - nsIPostToServer* pts; - nsresult result = aURL->QueryInterface(kPostToServerIID, (void **)&pts); - if (NS_OK == result) { - char buf[100]; - //strcpy(&buf[0], "Content-type: application/x-www-form-urlencoded\nname=foo"); - strcpy(&buf[0], "name=foo"); - PRInt32 len = strlen(&buf[0]); - pts->SendData(&buf[0], len); + if (aPostData) { + const char* data = aPostData->GetData(); + if (data) { + nsIPostToServer* pts; + nsresult result = aURL->QueryInterface(kPostToServerIID, (void **)&pts); + if (aPostData->IsFile()) { + pts->SendDataFromFile(data); + } + else { + pts->SendData(data, strlen(data)); + } } } diff --git a/mozilla/layout/html/document/src/nsHTMLDocument.h b/mozilla/layout/html/document/src/nsHTMLDocument.h index ca62208840c..df2da149826 100644 --- a/mozilla/layout/html/document/src/nsHTMLDocument.h +++ b/mozilla/layout/html/document/src/nsHTMLDocument.h @@ -30,7 +30,7 @@ public: NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); - virtual void LoadURL(nsIURL* aURL); + virtual void LoadURL(nsIURL* aURL, nsIPostData* aPostData = 0); NS_IMETHOD SetTitle(const nsString& aTitle); diff --git a/mozilla/layout/html/forms/src/nsForm.cpp b/mozilla/layout/html/forms/src/nsForm.cpp index f9865b27003..161a0dfc828 100644 --- a/mozilla/layout/html/forms/src/nsForm.cpp +++ b/mozilla/layout/html/forms/src/nsForm.cpp @@ -38,6 +38,15 @@ #include "nsILinkHandler.h" #include "nsInputRadio.h" #include "nsIRadioButton.h" +#include "nsInputFile.h" +#include "nsDocument.h" + +#include "net.h" +#include "xp_file.h" +#include "prio.h" +#include "prmem.h" + +#define CRLF "\015\012" // netlib has a general function (netlib\modules\liburl\src\escape.c) // which does url encoding. Since netlib is not yet available for raptor, @@ -45,7 +54,7 @@ // conver each non alphanumeric char to %XY where XY is the hexadecimal // equavalent of the binary representation of the character. // -void EscapeURLString(char* aInString, char* aOutString) +void URLEncode(char* aInString, char* aOutString) { if (nsnull == aInString) { return; @@ -68,11 +77,11 @@ void EscapeURLString(char* aInString, char* aOutString) *outChar = 0; // terminate the string } -nsString* EscapeURLString(nsString& aString) +nsString* URLEncode(nsString& aString) { char* inBuf = aString.ToNewCString(); char* outBuf = new char[ (strlen(inBuf) * 3) + 1 ]; - EscapeURLString(inBuf, outBuf); + URLEncode(inBuf, outBuf); nsString* result = new nsString(outBuf); delete [] outBuf; delete [] inBuf; @@ -134,8 +143,19 @@ public: virtual void Init(PRBool aReinit); + static nsString* gGET; + static nsString* gMULTIPART; + protected: void RemoveRadioGroups(); + void ProcessAsURLEncoded(PRBool aIsPost, nsIFormControl* aSubmitter, nsString& aData); + void ProcessAsMultipart(nsIFormControl* aSubmitter, nsString& aData); + static const char* GetFileNameWithinPath(char* aPathName); + + // the following are temporary until nspr and/or netlib provide them + static Temp_GetTempDir(char* aTempDirName); + static char* Temp_GenerateTempFileName(PRInt32 aMaxSize, char* aBuffer); + static void Temp_GetContentType(char* aPathName, char* aContentType); nsIAtom* mTag; nsIHTMLAttributes* mAttributes; @@ -154,6 +174,9 @@ protected: // CLASS nsForm +nsString* nsForm::gGET = new nsString("get"); +nsString* nsForm::gMULTIPART = new nsString("multipart/form-data"); + // Note: operator new zeros our memory nsForm::nsForm(nsIAtom* aTag) { @@ -269,47 +292,22 @@ void nsForm::OnSubmit(nsIPresContext* aPresContext, nsIFrame* aFrame, { nsString data; // this could be more efficient, by allocating a larger buffer - nsAutoString method; + nsAutoString method, enctype; GetAttribute("method", method); - PRBool isPost = PR_TRUE; - if (!method.EqualsIgnoreCase("post")) { - isPost = PR_FALSE; - data += '?'; + GetAttribute("enctype", enctype); + + PRBool isURLEncoded = (enctype.EqualsIgnoreCase(*gMULTIPART)) ? PR_FALSE : PR_TRUE; + + // for enctype=multipart/form-data, force it to be post + PRBool isPost = (method.EqualsIgnoreCase(*gGET) && isURLEncoded) ? PR_FALSE : PR_TRUE; + + if (isURLEncoded) { + ProcessAsURLEncoded(isPost, aSubmitter, data); + } + else { + ProcessAsMultipart(aSubmitter, data); } - PRBool firstTime = PR_TRUE; - - PRInt32 numChildren = mChildren.Count(); - // collect and encode the data from the children controls - for (PRInt32 childX = 0; childX < numChildren; childX++) { - nsIFormControl* child = (nsIFormControl*) mChildren.ElementAt(childX); - if (child->IsSuccessful(aSubmitter)) { - PRInt32 numValues = 0; - PRInt32 maxNumValues = child->GetMaxNumValues(); - if (maxNumValues <= 0) { - continue; - } - nsString* names = new nsString[maxNumValues]; - nsString* values = new nsString[maxNumValues]; - if (PR_TRUE == child->GetNamesValues(maxNumValues, numValues, values, names)) { - for (int valueX = 0; valueX < numValues; valueX++) { - if (PR_TRUE == firstTime) { - firstTime = PR_FALSE; - } else { - data += "&"; - } - nsString* convName = EscapeURLString(names[valueX]); - data += *convName; - delete convName; - data += "="; - nsString* convValue = EscapeURLString(values[valueX]); - data += *convValue; - delete convValue; - } - } - delete [] values; - } - } // make the url string nsILinkHandler* handler; @@ -339,13 +337,362 @@ void nsForm::OnSubmit(nsIPresContext* aPresContext, nsIFrame* aFrame, NS_IF_RELEASE(docURL); // Now pass on absolute url to the click handler - handler->OnLinkClick(aFrame, absURLSpec, target); + nsPostData postData(!isURLEncoded, data.ToNewCString()); + handler->OnLinkClick(aFrame, absURLSpec, target, &postData); DebugPrint("url", absURLSpec); DebugPrint("data", data); } } +void nsForm::ProcessAsURLEncoded(PRBool isPost, nsIFormControl* aSubmitter, nsString& aData) +{ + nsString buf; + PRBool firstTime = PR_TRUE; + + PRInt32 numChildren = mChildren.Count(); + // collect and encode the data from the children controls + for (PRInt32 childX = 0; childX < numChildren; childX++) { + nsIFormControl* child = (nsIFormControl*) mChildren.ElementAt(childX); + if (child->IsSuccessful(aSubmitter)) { + PRInt32 numValues = 0; + PRInt32 maxNumValues = child->GetMaxNumValues(); + if (maxNumValues <= 0) { + continue; + } + nsString* names = new nsString[maxNumValues]; + nsString* values = new nsString[maxNumValues]; + if (PR_TRUE == child->GetNamesValues(maxNumValues, numValues, values, names)) { + for (int valueX = 0; valueX < numValues; valueX++) { + if (PR_TRUE == firstTime) { + firstTime = PR_FALSE; + } else { + buf += "&"; + } + nsString* convName = URLEncode(names[valueX]); + buf += *convName; + delete convName; + buf += "="; + nsString* convValue = URLEncode(values[valueX]); + buf += *convValue; + delete convValue; + } + } + delete [] names; + delete [] values; + } + } + + aData.SetLength(0); + if (isPost) { + char size[16]; + sprintf(size, "%d", buf.Length()); + aData = "Content-type: application/x-www-form-urlencoded"; + aData += CRLF; + aData += "Content-Length: "; + aData += size; + aData += CRLF; + aData += CRLF; + } + else { + aData += '?'; + } + + aData += buf; +} + +// include the file name without the directory +const char* nsForm::GetFileNameWithinPath(char* aPathName) +{ + char* fileNameStart = PL_strrchr(aPathName, '\\'); // windows + if (!fileNameStart) { // try unix + fileNameStart = PL_strrchr(aPathName, '\\'); + } + if (fileNameStart) { + return fileNameStart+1; + } + else { + return aPathName; + } +} + +// this needs to be provided by a higher level, since navigator might override +// the temp directory. XXX does not check that parm is big enough +nsForm::Temp_GetTempDir(char* aTempDirName) +{ + aTempDirName[0] = 0; + const char* env; + + if ((env = (const char *) getenv("TMP")) == nsnull) { + if ((env = (const char *) getenv("TEMP")) == nsnull) { + strcpy(aTempDirName, "."); + } + } + if (*env == '\0') { // null string means "." + strcpy(aTempDirName, "."); + } + if (0 == aTempDirName[0]) { + strcpy(aTempDirName, env); + } + return PR_TRUE; +} + +// the following is a temporary measure until NET_cinfo_find_type or its +// replacement is available +void nsForm::Temp_GetContentType(char* aPathName, char* aContentType) +{ + if (!aPathName) { + strcpy(aContentType, "unknown"); + return; + } + + int len = strlen(aPathName); + if (len <= 0) { + strcpy(aContentType, "unknown"); + return; + } + + char* fileExt = &aPathName[len-1]; + for (int i = len-1; i >= 0; i--) { + if ('.' == aPathName[i]) { + break; + } + fileExt--; + } + if ((0 == nsCRT::strcasecmp(fileExt, ".html")) || + (0 == nsCRT::strcasecmp(fileExt, ".htm"))) { + strcpy(aContentType, "text/html"); + } + else if (0 == nsCRT::strcasecmp(fileExt, ".txt")) { + strcpy(aContentType, "text/plain"); + } + else if (0 == nsCRT::strcasecmp(fileExt, ".gif")) { + strcpy(aContentType, "image/gif"); + } + else if ((0 == nsCRT::strcasecmp(fileExt, ".jpeg")) || + (0 == nsCRT::strcasecmp(fileExt, ".jpg"))) { + strcpy(aContentType, "image/jpeg"); + } + else { // don't bother trying to do the others here + strcpy(aContentType, "unknown"); + } +} + + +#if 0 + char* tmpDir = aFileName; // copy name to fname */ + // Keep generating file names till we find one that's not in use + while ((*env != '\0') && count++ { + *ptr++ = *env++; + } + if (ptr[-1] != '\\' && ptr[-1] != '/') + *ptr++ = '\\'; /* append backslash if not in env variable */ + /* Append a suitable file name */ + next_file_num++; /* advance counter */ + sprintf(ptr, "JPG%03d.TMP", next_file_num); + /* Probe to see if file name is already in use */ + if ((tfile = fopen(fname, READ_BINARY)) == NULL) + break; + fclose(tfile); /* oops, it's there; close tfile & try again */ + } + + char* tempDir = getenv("temp"); + if (!tempDir) { + tempDir = getenv("tmp"); + } + if (tempDir) { + return PR_TRUE; + } + else { + return PR_FALSE; + } +#endif + +#define CONTENT_DISP "Content-Disposition: form-data; name=\"" +#define FILENAME "\"; filename=\"" +#define CONTENT_TYPE "Content-Type: " +#define CONTENT_ENCODING "Content-Encoding: " +#define BUFSIZE 1024 +#define MULTIPART "multipart/form-data" +#define END "--" + +void nsForm::ProcessAsMultipart(nsIFormControl* aSubmitter, nsString& aData) +{ + aData.SetLength(0); + char buffer[BUFSIZE]; + PRInt32 numChildren = mChildren.Count(); + + // construct a temporary file to put the data into + char tmpFileName[BUFSIZE]; + char* result = Temp_GenerateTempFileName((PRInt32)BUFSIZE, tmpFileName); + if (!result) { + return; + } + + PRFileDesc* tmpFile = PR_Open(tmpFileName, PR_CREATE_FILE | PR_WRONLY, 0644); + if (!tmpFile) { + return; + } + + // write the content-type, boundary to the tmp file + char boundary[80]; + sprintf(boundary, "-----------------------------%d%d%d", + boundary, rand(), rand(), rand()); + sprintf(buffer, "Content-type: %s; boundary=%s" CRLF, MULTIPART, boundary); + PRInt32 len = PR_Write(tmpFile, buffer, PL_strlen(buffer)); + if (len < 0) { + return; + } + + PRInt32 boundaryLen = PL_strlen(boundary); + PRInt32 contDispLen = PL_strlen(CONTENT_DISP); + PRInt32 crlfLen = PL_strlen(CRLF); + + // compute the content length, passing through all of the form controls + PRInt32 contentLen = crlfLen; // extra crlf after content-length header + + PRInt32 childX; // stupid compiler + for (childX = 0; childX < numChildren; childX++) { + nsIFormControl* child = (nsIFormControl*) mChildren.ElementAt(childX); + nsAutoString type; + child->GetType(type); + if (child->IsSuccessful(aSubmitter)) { + PRInt32 numValues = 0; + PRInt32 maxNumValues = child->GetMaxNumValues(); + if (maxNumValues <= 0) { + continue; + } + nsString* names = new nsString[maxNumValues]; + nsString* values = new nsString[maxNumValues]; + if (PR_FALSE == child->GetNamesValues(maxNumValues, numValues, values, names)) { + continue; + } + contentLen += boundaryLen + crlfLen; + contentLen += contDispLen; + for (int valueX = 0; valueX < numValues; valueX++) { + char* name = names[valueX].ToNewCString(); + char* value = values[valueX].ToNewCString(); + if ((0 == names[valueX].Length()) || (0 == values[valueX].Length())) { + continue; + } + contentLen += PL_strlen(name); + contentLen += 1 + crlfLen; // ending name quote plus CRLF + if (type.EqualsIgnoreCase(*nsInputFile::gFILE_TYPE)) { // + contentLen += PL_strlen(FILENAME); + + // include the file name without the directory + char* fileNameStart = PL_strrchr(value, '/'); // unix + if (!fileNameStart) { // try windows + fileNameStart = PL_strrchr(value, '\\'); + } + fileNameStart = (fileNameStart) ? fileNameStart+1 : value; + contentLen += PL_strlen(fileNameStart); + + // determine the content-type of the file + + char contentType[128]; + Temp_GetContentType(value, &contentType[0]); + contentLen += PL_strlen(CONTENT_TYPE); + contentLen += PL_strlen(contentType) + crlfLen + crlfLen; + + // get the size of the file + PRFileInfo fileInfo; + if (PR_SUCCESS == PR_GetFileInfo(value, &fileInfo)) { + contentLen += fileInfo.size; + } + } + else { + contentLen += PL_strlen(value) + crlfLen; + } + delete [] name; + delete [] value; + } + delete [] names; + delete [] values; + } + + aData = tmpFileName; + } + + contentLen += boundaryLen + PL_strlen(END) + crlfLen; + + // write the content + sprintf(buffer, "Content-Length: %ld" CRLF CRLF, contentLen); + PR_Write(tmpFile, buffer, PL_strlen(buffer)); + + // write the content passing through all of the form controls a 2nd time + for (childX = 0; childX < numChildren; childX++) { + nsIFormControl* child = (nsIFormControl*) mChildren.ElementAt(childX); + nsAutoString type; + child->GetType(type); + if (child->IsSuccessful(aSubmitter)) { + PRInt32 numValues = 0; + PRInt32 maxNumValues = child->GetMaxNumValues(); + if (maxNumValues <= 0) { + continue; + } + nsString* names = new nsString[maxNumValues]; + nsString* values = new nsString[maxNumValues]; + if (PR_FALSE == child->GetNamesValues(maxNumValues, numValues, values, names)) { + continue; + } + for (int valueX = 0; valueX < numValues; valueX++) { + char* name = names[valueX].ToNewCString(); + char* value = values[valueX].ToNewCString(); + if ((0 == names[valueX].Length()) || (0 == values[valueX].Length())) { + continue; + } + sprintf(buffer, "%s" CRLF, boundary); + PR_Write(tmpFile, buffer, PL_strlen(buffer)); + PR_Write(tmpFile, CONTENT_DISP, contDispLen); + PR_Write(tmpFile, name, PL_strlen(name)); + + if (type.EqualsIgnoreCase(*nsInputFile::gFILE_TYPE)) { // + PR_Write(tmpFile, FILENAME, PL_strlen(FILENAME)); + const char* fileNameStart = GetFileNameWithinPath(value); + PR_Write(tmpFile, fileNameStart, PL_strlen(fileNameStart)); + } + PR_Write(tmpFile, "\"" CRLF, PL_strlen("\"" CRLF)); // end content disp + + if (type.EqualsIgnoreCase(*nsInputFile::gFILE_TYPE)) { + // determine the content-type of the file + char contentType[128]; + Temp_GetContentType(value, &contentType[0]); + PR_Write(tmpFile, CONTENT_TYPE, PL_strlen(CONTENT_TYPE)); + PR_Write(tmpFile, contentType, PL_strlen(contentType)); + PR_Write(tmpFile, CRLF, PL_strlen(CRLF)); + PR_Write(tmpFile, CRLF, PL_strlen(CRLF)); // end content-type header + + PRFileDesc* contentFile = PR_Open(value, PR_RDONLY, 0644); + if(contentFile) { + PRInt32 size; + while((size = PR_Read(contentFile, buffer, BUFSIZE)) > 0) { + PR_Write(tmpFile, buffer, size); + } + PR_Close(contentFile); + } + } + else { + PR_Write(tmpFile, value, PL_strlen(value)); + PR_Write(tmpFile, CRLF, crlfLen); + } + delete [] name; + delete [] value; + } + delete [] names; + delete [] values; + } + } + + sprintf(buffer, "%s--" CRLF, boundary); + PR_Write(tmpFile, buffer, PL_strlen(buffer)); + + PR_Close(tmpFile); + + //StrAllocCopy(url_struct->post_data, tmpfilename); + //url_struct->post_data_is_file = TRUE; +} + void nsForm::OnTab() { @@ -555,3 +902,159 @@ NS_NewHTMLForm(nsIFormManager** aInstancePtrResult, return result; } +// THE FOLLOWING WAS TAKEN FROM CMD/WINFE/FEGUI AND MODIFIED TO JUST +// GENERATE A TEMPFILE NAME. + + +// Windows _tempnam() lets the TMP environment variable override things sent in +// so it look like we're going to have to make a temp name by hand +// +// The user should *NOT* free the returned string. It is stored in static space +// and so is not valid across multiple calls to this function +// +// The names generated look like +// c:\netscape\cache\m0.moz +// c:\netscape\cache\m1.moz +// up to... +// c:\netscape\cache\m9999999.moz +// after that if fails +// +char* nsForm::Temp_GenerateTempFileName(PRInt32 aMaxSize, char* file_buf) +{ + char directory[128]; + Temp_GetTempDir(&directory[0]); + static char ext[] = ".TMP"; + static char prefix[] = "nsform"; + + // We need to base our temporary file names on time, and not on sequential + // addition because of the cache not being updated when the user + // crashes and files that have been deleted are over written with + // other files; bad data. + // The 52 valid DOS file name characters are + // 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_^$~!#%&-{}@`'() + // We will only be using the first 32 of the choices. + // + // Time name format will be M+++++++.MOZ + // Where M is the single letter prefix (can be longer....) + // Where +++++++ is the 7 character time representation (a full 8.3 + // file name will be made). + // Where .MOZ is the file extension to be used. + // + // In the event that the time requested is the same time as the last call + // to this function, then the current time is incremented by one, + // as is the last time called to facilitate unique file names. + // In the event that the invented file name already exists (can't + // really happen statistically unless the clock is messed up or we + // manually incremented the time), then the times are incremented + // until an open name can be found. + // + // time_t (the time) has 32 bits, or 4,294,967,296 combinations. + // We will map the 32 bits into the 7 possible characters as follows: + // Starting with the lsb, sets of 5 bits (32 values) will be mapped + // over to the appropriate file name character, and then + // incremented to an approprate file name character. + // The left over 2 bits will be mapped into the seventh file name + // character. + // + + int i_letter, i_timechars, i_numtries = 0; + char ca_time[8]; + time_t this_call = (time_t)0; + + // We have to base the length of our time string on the length + // of the incoming prefix.... + // + i_timechars = 8 - strlen(prefix); + + // Infinite loop until the conditions are satisfied. + // There is no danger, unless every possible file name is used. + // + while(1) { + // We used to use the time to generate this. + // Now, we use some crypto to avoid bug #47027 + //RNG_GenerateGlobalRandomBytes((void *)&this_call, sizeof(this_call)); + char* output=(char *)&this_call; + size_t len = sizeof(this_call); + size_t i; + srand((unsigned int) PR_IntervalToMilliseconds(PR_IntervalNow())); + for (i=0;i> (i_letter * 5)) & 0x1F); + + // Convert any numbers to their equivalent ascii code + // + if(ca_time[i_letter] <= 9) { + ca_time[i_letter] += '0'; + } + // Convert the character to it's equivalent ascii code + // + else { + ca_time[i_letter] += 'A' - 10; + } + } + + // End the created time string. + // + ca_time[i_letter] = '\0'; + + // Reverse the time string. + // + _strrev(ca_time); + + // Create the fully qualified path and file name. + // + sprintf(file_buf, "%s\\%s%s%s", directory, prefix, ca_time, ext); + + // Determine if the file exists, and mark that we've tried yet + // another file name (mark to be used later). + // + // Use the system call instead of XP_Stat since we already + // know the name and we don't want recursion + // + struct _stat statinfo; + int status = _stat(file_buf, &statinfo); + i_numtries++; + + // If it does not exists, we are successful, return the name. + // + if(status == -1) { + // TRACE("Temp file name is %s\n", file_buf); + return(file_buf); + } + + // If there is no room for additional characters in the time, + // we'll have to return NULL here, or we go infinite. + // This is a one case scenario where the requested prefix is + // actually 8 letters long. + // Infinite loops could occur with a 7, 6, 5, etc character prefixes + // if available files are all eaten up (rare to impossible), in + // which case, we should check at some arbitrary frequency of + // tries before we give up instead of attempting to Vulcanize + // this code. Live long and prosper. + // + if(i_timechars == 0) { + break; + } + else if(i_numtries == 0x00FF) { + break; + } + } + + // Requested name is thought to be impossible to generate. + // + //TRACE("No more temp file names....\n"); + return(NULL); + +} + + diff --git a/mozilla/layout/html/forms/src/nsInputButton.cpp b/mozilla/layout/html/forms/src/nsInputButton.cpp index 83247e469eb..70b4b8f3aea 100644 --- a/mozilla/layout/html/forms/src/nsInputButton.cpp +++ b/mozilla/layout/html/forms/src/nsInputButton.cpp @@ -155,7 +155,7 @@ nsInputButton::~nsInputButton() PRBool nsInputButton::IsSuccessful(nsIFormControl* aSubmitter) const { - if ((void*)&mControl == (void*)aSubmitter) { + if ((kButton_Hidden == mType) || ((void*)&mControl == (void*)aSubmitter)) { return nsInputButtonSuper::IsSuccessful(aSubmitter); } return PR_FALSE; @@ -181,6 +181,7 @@ void nsInputButton::GetType(nsString& aResult) const return; } + // XXX put these and other literals into statics (e.g. gBUTTON_TYPE) switch (mType) { case kButton_Button: aResult.Append("button"); diff --git a/mozilla/layout/html/forms/src/nsInputFile.cpp b/mozilla/layout/html/forms/src/nsInputFile.cpp index 471d39ee261..55bb6847173 100644 --- a/mozilla/layout/html/forms/src/nsInputFile.cpp +++ b/mozilla/layout/html/forms/src/nsInputFile.cpp @@ -37,6 +37,7 @@ #include "nsIView.h" PRInt32 nsInputFileFrame::gSpacing = 40; +nsString* nsInputFile::gFILE_TYPE = new nsString("file"); nsInputFileFrame::nsInputFileFrame(nsIContent* aContent, nsIFrame* aParentFrame) : nsInlineFrame(aContent, aParentFrame) @@ -108,7 +109,8 @@ void nsInputFileFrame::MouseClicked(nsIPresContext* aPresContext) NS_IMETHODIMP nsInputFileFrame::MoveTo(nscoord aX, nscoord aY) { - if ( ((aX == 0) && (aY == 0)) || (aX != mRect.x) || (aY != mRect.y)) { + //if ( ((aX == 0) && (aY == 0)) || (aX != mRect.x) || (aY != mRect.y)) { + if ((aX != mRect.x) || (aY != mRect.y)) { nsIFrame* childFrame = mFirstChild; nscoord x = aX; nscoord y = aY; @@ -238,6 +240,31 @@ void nsInputFile::GetType(nsString& aResult) const } +PRInt32 +nsInputFile::GetMaxNumValues() +{ + return 1; +} + +PRBool +nsInputFile::GetNamesValues(PRInt32 aMaxNumValues, PRInt32& aNumValues, + nsString* aValues, nsString* aNames) +{ + if ((aMaxNumValues <= 0) || (nsnull == mName)) { + return PR_FALSE; + } + nsInput* text = (nsInput *)ChildAt(0); + // use our name and the text widgets value + aNames[0] = *mName; + nsITextWidget* textWidget = (nsITextWidget *)text->GetWidget(); + textWidget->GetText(aValues[0], 0); // the last parm is not used + + NS_IF_RELEASE(text); + aNumValues = 1; + + return PR_TRUE; +} + void nsInputFile::SetAttribute(nsIAtom* aAttribute, const nsString& aValue) { // get the text and set its relevant attributes diff --git a/mozilla/layout/html/forms/src/nsInputFile.h b/mozilla/layout/html/forms/src/nsInputFile.h index 51e6a54cae9..157a8ad5f72 100644 --- a/mozilla/layout/html/forms/src/nsInputFile.h +++ b/mozilla/layout/html/forms/src/nsInputFile.h @@ -47,6 +47,8 @@ protected: class nsInputFile : public nsInput { public: typedef nsInput nsInputFileSuper; + static nsString* gFILE_TYPE; + nsInputFile (nsIAtom* aTag, nsIFormManager* aManager); virtual nsresult CreateFrame(nsIPresContext* aPresContext, @@ -55,6 +57,9 @@ public: nsIFrame*& aResult); virtual void SetAttribute(nsIAtom* aAttribute, const nsString& aValue); + virtual PRInt32 GetMaxNumValues(); + virtual PRBool GetNamesValues(PRInt32 aMaxNumValues, PRInt32& aNumValues, + nsString* aValues, nsString* aNames); protected: virtual ~nsInputFile(); diff --git a/mozilla/layout/html/forms/src/nsInputFrame.cpp b/mozilla/layout/html/forms/src/nsInputFrame.cpp index 84a21516e62..eb07edde458 100644 --- a/mozilla/layout/html/forms/src/nsInputFrame.cpp +++ b/mozilla/layout/html/forms/src/nsInputFrame.cpp @@ -79,7 +79,8 @@ NS_METHOD nsInputFrame::SetRect(const nsRect& aRect) NS_METHOD nsInputFrame::MoveTo(nscoord aX, nscoord aY) { - if ( ((aX == 0) && (aY == 0)) || (aX != mRect.x) || (aY != mRect.y)) { + //if ( ((aX == 0) && (aY == 0)) || (aX != mRect.x) || (aY != mRect.y)) { + if ((aX != mRect.x) || (aY != mRect.y)) { mRect.x = aX; mRect.y = aY; diff --git a/mozilla/layout/html/tests/TestAttributes.cpp b/mozilla/layout/html/tests/TestAttributes.cpp index 68e36ad453d..d64ea1054f8 100644 --- a/mozilla/layout/html/tests/TestAttributes.cpp +++ b/mozilla/layout/html/tests/TestAttributes.cpp @@ -167,7 +167,7 @@ void testStrings(nsIDocument* aDoc) { class MyDocument : public nsDocument { public: MyDocument(); - void LoadURL(nsIURL* aURL); + void LoadURL(nsIURL* aURL, nsIPostData* aPostData); protected: virtual ~MyDocument(); @@ -181,7 +181,7 @@ MyDocument::~MyDocument() { } -void MyDocument::LoadURL(nsIURL* aURL) +void MyDocument::LoadURL(nsIURL* aURL, nsIPostData* aPostData) { } diff --git a/mozilla/webshell/public/nsIDocumentWidget.h b/mozilla/webshell/public/nsIDocumentWidget.h index e581cf903b1..3b94cffce8d 100644 --- a/mozilla/webshell/public/nsIDocumentWidget.h +++ b/mozilla/webshell/public/nsIDocumentWidget.h @@ -23,6 +23,7 @@ class nsIDocument; class nsString; class nsIScriptContext; +class nsIPostData; // Interface to the web widget. The web widget is a container for web // content. @@ -40,7 +41,7 @@ public: virtual void Hide() = 0; - NS_IMETHOD LoadURL(const nsString& aURLSpec) = 0; + NS_IMETHOD LoadURL(const nsString& aURLSpec, nsIPostData* aPostData = 0) = 0; virtual nsIWidget* GetWWWindow() = 0; diff --git a/mozilla/webshell/public/nsILinkHandler.h b/mozilla/webshell/public/nsILinkHandler.h index 9acd5d550c7..c9d5a147de8 100644 --- a/mozilla/webshell/public/nsILinkHandler.h +++ b/mozilla/webshell/public/nsILinkHandler.h @@ -22,6 +22,7 @@ #include "nsIWebWidget.h" class nsIFrame; class nsString; +class nsIPostData; struct nsGUIEvent; /* 52bd1e30-ce3f-11d1-9328-00805f8add32 */ @@ -52,8 +53,10 @@ public: * destination for the link. aTargetSpec indicates where the link is * targeted (it may be an empty string). */ - NS_IMETHOD OnLinkClick(nsIFrame* aFrame, const nsString& aURLSpec, - const nsString& aTargetSpec) = 0; + NS_IMETHOD OnLinkClick(nsIFrame* aFrame, + const nsString& aURLSpec, + const nsString& aTargetSpec, + nsIPostData* aPostData = 0) = 0; /** * Get the state of a link to a given absolute URL diff --git a/mozilla/webshell/src/nsLinkHandler.cpp b/mozilla/webshell/src/nsLinkHandler.cpp index 57eb551cebd..4be36dd32bc 100644 --- a/mozilla/webshell/src/nsLinkHandler.cpp +++ b/mozilla/webshell/src/nsLinkHandler.cpp @@ -16,6 +16,7 @@ * Reserved. */ #include "nsILinkHandler.h" +#include "nsIDocument.h" #include "nsString.h" #include "nsCRT.h" #include "prthread.h" @@ -40,28 +41,33 @@ public: // nsILinkHandler NS_IMETHOD Init(nsIWebWidget* aWidget); NS_IMETHOD GetWebWidget(nsIWebWidget** aResult); - NS_IMETHOD OnLinkClick(nsIFrame* aFrame, const nsString& aURLSpec, - const nsString& aTargetSpec); + NS_IMETHOD OnLinkClick(nsIFrame* aFrame, + const nsString& aURLSpec, + const nsString& aTargetSpec, + nsIPostData* aPostData = 0); NS_IMETHOD GetLinkState(const nsString& aURLSpec, nsLinkState& aState); void HandleLinkClickEvent(const nsString& aURLSpec, - const nsString& aTargetSpec); + const nsString& aTargetSpec, + nsIPostData* aPostDat = 0); nsIWebWidget* mWidget; + nsIPostData* mPostData; }; //---------------------------------------------------------------------- struct OnLinkClickEvent : public PLEvent { OnLinkClickEvent(LinkHandlerImpl* aHandler, const nsString& aURLSpec, - const nsString& aTargetSpec); + const nsString& aTargetSpec, nsIPostData* aPostData = 0); ~OnLinkClickEvent(); void HandleEvent(); LinkHandlerImpl* mHandler; - nsString* mURLSpec; - nsString* mTargetSpec; + nsString* mURLSpec; + nsString* mTargetSpec; + nsIPostData *mPostData; }; static void PR_CALLBACK HandleEvent(OnLinkClickEvent* aEvent) @@ -75,13 +81,18 @@ static void PR_CALLBACK DestroyEvent(OnLinkClickEvent* aEvent) } OnLinkClickEvent::OnLinkClickEvent(LinkHandlerImpl* aHandler, - const nsString& aURLSpec, - const nsString& aTargetSpec) + const nsString& aURLSpec, + const nsString& aTargetSpec, + nsIPostData* aPostData) { mHandler = aHandler; NS_ADDREF(aHandler); mURLSpec = new nsString(aURLSpec); mTargetSpec = new nsString(aTargetSpec); + mPostData = nsnull; + if (aPostData) { + NS_NewPostData(aPostData, &mPostData); + } PL_InitEvent(this, nsnull, (PLHandleEventProc) ::HandleEvent, @@ -98,11 +109,12 @@ OnLinkClickEvent::~OnLinkClickEvent() NS_IF_RELEASE(mHandler); if (nsnull != mURLSpec) delete mURLSpec; if (nsnull != mTargetSpec) delete mTargetSpec; + if (nsnull != mPostData) delete mPostData; } void OnLinkClickEvent::HandleEvent() { - mHandler->HandleLinkClickEvent(*mURLSpec, *mTargetSpec); + mHandler->HandleLinkClickEvent(*mURLSpec, *mTargetSpec, mPostData); } //---------------------------------------------------------------------- @@ -147,10 +159,11 @@ NS_IMETHODIMP LinkHandlerImpl::GetWebWidget(nsIWebWidget** aResult) NS_IMETHODIMP LinkHandlerImpl::OnLinkClick(nsIFrame* aFrame, const nsString& aURLSpec, - const nsString& aTargetSpec) + const nsString& aTargetSpec, + nsIPostData* aPostData) { - new OnLinkClickEvent(this, aURLSpec, aTargetSpec); + new OnLinkClickEvent(this, aURLSpec, aTargetSpec, aPostData); return NS_OK; } @@ -177,10 +190,10 @@ NS_IMETHODIMP LinkHandlerImpl::GetLinkState(const nsString& aURLSpec, nsLinkStat } void LinkHandlerImpl::HandleLinkClickEvent(const nsString& aURLSpec, - const nsString& aTargetSpec) + const nsString& aTargetSpec, nsIPostData* aPostData) { if (nsnull != mWidget) { - mWidget->LoadURL(aURLSpec); + mWidget->LoadURL(aURLSpec, aPostData); } } diff --git a/mozilla/webshell/src/nsWebWidget.cpp b/mozilla/webshell/src/nsWebWidget.cpp index 31535231116..aa9e23b99e1 100644 --- a/mozilla/webshell/src/nsWebWidget.cpp +++ b/mozilla/webshell/src/nsWebWidget.cpp @@ -81,8 +81,7 @@ public: NS_IMETHOD GetLinkHandler(nsILinkHandler** aResult); - NS_IMETHOD LoadURL(const nsString& aURL); - + NS_IMETHOD LoadURL(const nsString& aURL, nsIPostData* aPostData); virtual nsIDocument* GetDocument(); virtual void DumpContent(FILE* out); @@ -382,7 +381,7 @@ nsresult WebWidgetImpl::ProvideDefaultHandlers() // XXX need to save old document in case of failure? Does caller do that? -NS_IMETHODIMP WebWidgetImpl::LoadURL(const nsString& aURLSpec) +NS_IMETHODIMP WebWidgetImpl::LoadURL(const nsString& aURLSpec, nsIPostData* aPostData) { #ifdef NS_DEBUG printf("WebWidgetImpl::LoadURL: loadURL("); @@ -447,7 +446,7 @@ NS_IMETHODIMP WebWidgetImpl::LoadURL(const nsString& aURLSpec) // Now load the document mPresShell->EnterReflowLock(); - doc->LoadURL(url); + doc->LoadURL(url, aPostData); mPresShell->ExitReflowLock(); PRTime end = PR_Now(); diff --git a/mozilla/webshell/tests/viewer/samples/test8.html b/mozilla/webshell/tests/viewer/samples/test8.html index 29fac8d5a2b..2dc0669feac 100644 --- a/mozilla/webshell/tests/viewer/samples/test8.html +++ b/mozilla/webshell/tests/viewer/samples/test8.html @@ -65,11 +65,6 @@ a checkbox: an image submit. For now, click twice. - -

-
- a post test -