Bug 1272298 - nsFormSubmission should support "\0" input string, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Fri, 13 May 2016 22:48:03 +0200
changeset 338421 e486707bccdc22b916d35a9c4350730d5c0b7d9d
parent 338420 bade5f18dc94268ddef4d156729d90bc66cf9fa0
child 338422 2ac62de7365d1557e3f2f53900f587cf4bc68cd9
push id1183
push userraliiev@mozilla.com
push dateMon, 05 Sep 2016 20:01:49 +0000
treeherdermozilla-release@3148731bed45 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1272298
milestone49.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1272298 - nsFormSubmission should support "\0" input string, r=smaug
dom/html/nsFormSubmission.cpp
embedding/components/webbrowserpersist/nsWebBrowserPersist.cpp
xpcom/io/nsEscape.cpp
xpcom/io/nsEscape.h
--- a/dom/html/nsFormSubmission.cpp
+++ b/dom/html/nsFormSubmission.cpp
@@ -112,17 +112,17 @@ protected:
   /**
    * URL encode a Unicode string by encoding it to bytes, converting linebreaks
    * properly, and then escaping many bytes as %xx.
    *
    * @param aStr the string to encode
    * @param aEncoded the encoded string [OUT]
    * @throws NS_ERROR_OUT_OF_MEMORY if we run out of memory
    */
-  nsresult URLEncode(const nsAString& aStr, nsCString& aEncoded);
+  nsresult URLEncode(const nsAString& aStr, nsACString& aEncoded);
 
 private:
   /**
    * The method of the submit (either NS_FORM_METHOD_GET or
    * NS_FORM_METHOD_POST).
    */
   int32_t mMethod;
 
@@ -358,33 +358,38 @@ nsFSURLEncoded::GetEncodedSubmission(nsI
     }
   }
 
   return rv;
 }
 
 // i18n helper routines
 nsresult
-nsFSURLEncoded::URLEncode(const nsAString& aStr, nsCString& aEncoded)
+nsFSURLEncoded::URLEncode(const nsAString& aStr, nsACString& aEncoded)
 {
   // convert to CRLF breaks
+  int32_t convertedBufLength = 0;
   char16_t* convertedBuf =
-    nsLinebreakConverter::ConvertUnicharLineBreaks(PromiseFlatString(aStr).get(),
+    nsLinebreakConverter::ConvertUnicharLineBreaks(aStr.BeginReading(),
                                                    nsLinebreakConverter::eLinebreakAny,
-                                                   nsLinebreakConverter::eLinebreakNet);
+                                                   nsLinebreakConverter::eLinebreakNet,
+                                                   aStr.Length(),
+                                                   &convertedBufLength);
   NS_ENSURE_TRUE(convertedBuf, NS_ERROR_OUT_OF_MEMORY);
 
+  nsAutoString convertedString;
+  convertedString.Adopt(convertedBuf, convertedBufLength);
+
   nsAutoCString encodedBuf;
-  nsresult rv = EncodeVal(nsDependentString(convertedBuf), encodedBuf, false);
-  free(convertedBuf);
+  nsresult rv = EncodeVal(convertedString, encodedBuf, false);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  char* escapedBuf = nsEscape(encodedBuf.get(), url_XPAlphas);
-  NS_ENSURE_TRUE(escapedBuf, NS_ERROR_OUT_OF_MEMORY);
-  aEncoded.Adopt(escapedBuf);
+  if (NS_WARN_IF(!NS_Escape(encodedBuf, aEncoded, url_XPAlphas))) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
 
   return NS_OK;
 }
 
 // --------------------------------------------------------------------------
 
 nsFSMultipartFormData::nsFSMultipartFormData(const nsACString& aCharset,
                                              nsIContent* aOriginatingElement)
--- a/embedding/components/webbrowserpersist/nsWebBrowserPersist.cpp
+++ b/embedding/components/webbrowserpersist/nsWebBrowserPersist.cpp
@@ -2119,17 +2119,17 @@ nsWebBrowserPersist::MakeFilenameFromURI
 
     nsCOMPtr<nsIURL> url(do_QueryInterface(aURI));
     if (url)
     {
         nsAutoCString nameFromURL;
         url->GetFileName(nameFromURL);
         if (mPersistFlags & PERSIST_FLAGS_DONT_CHANGE_FILENAMES)
         {
-            fileName.AssignWithConversion(NS_UnescapeURL(nameFromURL).get());
+            fileName.AssignWithConversion(NS_UnescapeURL(nameFromURL).BeginReading());
             aFilename = fileName;
             return NS_OK;
         }
         if (!nameFromURL.IsEmpty())
         {
             // Unescape the file name (GetFileName escapes it)
             NS_UnescapeURL(nameFromURL);
             uint32_t nameLength = 0;
--- a/xpcom/io/nsEscape.cpp
+++ b/xpcom/io/nsEscape.cpp
@@ -68,101 +68,102 @@ AppendPercentHex(char16_t* aBuffer, char
     aBuffer[i++] = hexCharsUpper[(aChar >> 8) & 0xF]; // high-byte low nibble
   }
   aBuffer[i++] = hexCharsUpper[(aChar >> 4) & 0xF]; // low-byte high nibble
   aBuffer[i++] = hexCharsUpper[aChar & 0xF]; // low-byte low nibble
   return i;
 }
 
 //----------------------------------------------------------------------------------------
-static char*
-nsEscapeCount(const char* aStr, nsEscapeMask aFlags, size_t* aOutLen)
+char*
+nsEscape(const char* aStr, nsEscapeMask aFlags)
 //----------------------------------------------------------------------------------------
 {
   if (!aStr) {
-    return 0;
+    return nullptr;
   }
 
-  size_t len = 0;
+  return nsEscapeWithLength(aStr, strlen(aStr), nullptr, aFlags);
+}
+
+//----------------------------------------------------------------------------------------
+char*
+nsEscapeWithLength(const char* aStr, size_t aLength, size_t* aOutputLength,
+                   nsEscapeMask aFlags)
+//----------------------------------------------------------------------------------------
+{
+  if (!aStr) {
+    return nullptr;
+  }
+
   size_t charsToEscape = 0;
 
   const unsigned char* src = (const unsigned char*)aStr;
-  while (*src) {
-    len++;
-    if (!IS_OK(*src++)) {
+  for (size_t i = 0; i < aLength; ++i) {
+    if (!IS_OK(src[i])) {
       charsToEscape++;
     }
   }
 
   // calculate how much memory should be allocated
   // original length + 2 bytes for each escaped character + terminating '\0'
   // do the sum in steps to check for overflow
-  size_t dstSize = len + 1 + charsToEscape;
-  if (dstSize <= len) {
-    return 0;
+  size_t dstSize = aLength + 1 + charsToEscape;
+  if (dstSize <= aLength) {
+    return nullptr;
   }
   dstSize += charsToEscape;
-  if (dstSize < len) {
-    return 0;
+  if (dstSize < aLength) {
+    return nullptr;
   }
 
   // fail if we need more than 4GB
   if (dstSize > UINT32_MAX) {
-    return 0;
+    return nullptr;
   }
 
   char* result = (char*)moz_xmalloc(dstSize);
   if (!result) {
-    return 0;
+    return nullptr;
   }
 
   unsigned char* dst = (unsigned char*)result;
   src = (const unsigned char*)aStr;
   if (aFlags == url_XPAlphas) {
-    for (size_t i = 0; i < len; ++i) {
+    for (size_t i = 0; i < aLength; ++i) {
       unsigned char c = *src++;
       if (IS_OK(c)) {
         *dst++ = c;
       } else if (c == ' ') {
         *dst++ = '+';  /* convert spaces to pluses */
       } else {
         *dst++ = HEX_ESCAPE;
         *dst++ = hexCharsUpper[c >> 4];  /* high nibble */
         *dst++ = hexCharsUpper[c & 0x0f];  /* low nibble */
       }
     }
   } else {
-    for (size_t i = 0; i < len; ++i) {
+    for (size_t i = 0; i < aLength; ++i) {
       unsigned char c = *src++;
       if (IS_OK(c)) {
         *dst++ = c;
       } else {
         *dst++ = HEX_ESCAPE;
         *dst++ = hexCharsUpper[c >> 4];  /* high nibble */
         *dst++ = hexCharsUpper[c & 0x0f];  /* low nibble */
       }
     }
   }
 
   *dst = '\0';     /* tack on eos */
-  if (aOutLen) {
-    *aOutLen = dst - (unsigned char*)result;
+  if (aOutputLength) {
+    *aOutputLength = dst - (unsigned char*)result;
   }
-  return result;
-}
 
-//----------------------------------------------------------------------------------------
-char*
-nsEscape(const char* aStr, nsEscapeMask aFlags)
-//----------------------------------------------------------------------------------------
-{
-  if (!aStr) {
-    return nullptr;
-  }
-  return nsEscapeCount(aStr, aFlags, nullptr);
+  return result;
 }
 
 //----------------------------------------------------------------------------------------
 char*
 nsUnescape(char* aStr)
 //----------------------------------------------------------------------------------------
 {
   nsUnescapeCount(aStr);
--- a/xpcom/io/nsEscape.h
+++ b/xpcom/io/nsEscape.h
@@ -26,18 +26,31 @@ typedef enum {
 } nsEscapeMask;
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /**
  * Escape the given string according to mask
- * @param str The string to escape
- * @param mask How to escape the string
+ * @param aSstr The string to escape
+ * @param aLength The length of the string to escape
+ * @param aOutputLen A pointer that will be used to store the length of the
+ *        output string, if not null
+ * @param aMask How to escape the string
+ * @return A newly allocated escaped string that must be free'd with
+ *         nsCRT::free, or null on failure
+ */
+char* nsEscapeWithLength(const char* aStr, size_t aLength, size_t* aOutputLen,
+                         nsEscapeMask aMask);
+
+/**
+ * Escape the given string according to mask
+ * @param aStr The string to escape
+ * @param aMask How to escape the string
  * @return A newly allocated escaped string that must be free'd with
  *         nsCRT::free, or null on failure
  */
 char* nsEscape(const char* aStr, nsEscapeMask aMask);
 
 char* nsUnescape(char* aStr);
 /* decode % escaped hex codes into character values,
  * modifies the parameter, returns the same buffer
@@ -179,30 +192,32 @@ const nsSubstring&
 NS_EscapeURL(const nsAFlatString& aStr, const nsTArray<char16_t>& aForbidden,
              nsSubstring& aResult);
 
 /**
  * CString version of nsEscape. Returns true on success, false
  * on out of memory. To reverse this function, use NS_UnescapeURL.
  */
 inline bool
-NS_Escape(const nsCString& aOriginal, nsCString& aEscaped,
+NS_Escape(const nsACString& aOriginal, nsACString& aEscaped,
           nsEscapeMask aMask)
 {
-  char* esc = nsEscape(aOriginal.get(), aMask);
+  size_t escLen = 0;
+  char* esc = nsEscapeWithLength(aOriginal.BeginReading(), aOriginal.Length(),
+                                 &escLen, aMask);
   if (! esc) {
     return false;
   }
-  aEscaped.Adopt(esc);
+  aEscaped.Adopt(esc, escLen);
   return true;
 }
 
 /**
  * Inline unescape of mutable string object.
  */
-inline nsCString&
-NS_UnescapeURL(nsCString& aStr)
+inline nsACString&
+NS_UnescapeURL(nsACString& aStr)
 {
   aStr.SetLength(nsUnescapeCount(aStr.BeginWriting()));
   return aStr;
 }
 
 #endif //  _ESCAPE_H_