Bug 1181054 - Part 2: Refactor the code to extract an HTTP header from a buffer from FormDataParser; r=bkelly
authorEhsan Akhgari <ehsan@mozilla.com>
Sat, 24 Oct 2015 17:42:35 -0400
changeset 304693 370b6e4c66a6487656f848abf96b3968bd791cb5
parent 304692 3bcf816eb5ec6dbc08f2fd1653a4e64cdce2dc07
child 304694 3ca8546e3cc5fef952164aa97a0b85b8c90863b1
push id1001
push userraliiev@mozilla.com
push dateMon, 18 Jan 2016 19:06:03 +0000
treeherdermozilla-release@8b89261f3ac4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbkelly
bugs1181054
milestone44.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 1181054 - Part 2: Refactor the code to extract an HTTP header from a buffer from FormDataParser; r=bkelly
dom/fetch/FetchUtil.cpp
dom/fetch/FetchUtil.h
--- a/dom/fetch/FetchUtil.cpp
+++ b/dom/fetch/FetchUtil.cpp
@@ -117,16 +117,83 @@ FetchUtil::ConsumeBlob(nsISupports* aPar
 
   if (!blob) {
     aRv.Throw(NS_ERROR_DOM_UNKNOWN_ERR);
     return nullptr;
   }
   return blob.forget();
 }
 
+static bool
+FindCRLF(nsACString::const_iterator& aStart,
+         nsACString::const_iterator& aEnd)
+{
+  nsACString::const_iterator end(aEnd);
+  return FindInReadable(NS_LITERAL_CSTRING("\r\n"), aStart, end);
+}
+
+// Reads over a CRLF and positions start after it.
+static bool
+PushOverLine(nsACString::const_iterator& aStart)
+{
+  if (*aStart == nsCRT::CR && (aStart.size_forward() > 1) && *(++aStart) == nsCRT::LF) {
+    ++aStart; // advance to after CRLF
+    return true;
+  }
+
+  return false;
+}
+
+// static
+bool
+FetchUtil::ExtractHeader(nsACString::const_iterator& aStart,
+                         nsACString::const_iterator& aEnd,
+                         nsCString& aHeaderName,
+                         nsCString& aHeaderValue,
+                         bool* aWasEmptyHeader)
+{
+  MOZ_ASSERT(aWasEmptyHeader);
+  // Set it to a valid value here so we don't forget later.
+  *aWasEmptyHeader = false;
+
+  const char* beginning = aStart.get();
+  nsACString::const_iterator end(aEnd);
+  if (!FindCRLF(aStart, end)) {
+    return false;
+  }
+
+  if (aStart.get() == beginning) {
+    *aWasEmptyHeader = true;
+    return true;
+  }
+
+  nsAutoCString header(beginning, aStart.get() - beginning);
+
+  nsACString::const_iterator headerStart, headerEnd;
+  header.BeginReading(headerStart);
+  header.EndReading(headerEnd);
+  if (!FindCharInReadable(':', headerStart, headerEnd)) {
+    return false;
+  }
+
+  aHeaderName.Assign(StringHead(header, headerStart.size_backward()));
+  aHeaderName.CompressWhitespace();
+  if (!NS_IsValidHTTPToken(aHeaderName)) {
+    return false;
+  }
+
+  aHeaderValue.Assign(Substring(++headerStart, headerEnd));
+  if (!NS_IsReasonableHTTPHeaderValue(aHeaderValue)) {
+    return false;
+  }
+  aHeaderValue.CompressWhitespace();
+
+  return PushOverLine(aStart);
+}
+
 namespace {
 class MOZ_STACK_CLASS FillFormIterator final
   : public URLSearchParams::ForEachIterator
 {
 public:
   explicit FillFormIterator(nsFormData* aFormData)
     : mFormData(aFormData)
   {
@@ -209,77 +276,31 @@ private:
           return true;
         }
       }
     }
 
     return false;
   }
 
-  // Reads over a CRLF and positions start after it.
-  bool
-  PushOverLine(nsACString::const_iterator& aStart)
-  {
-    if (*aStart == nsCRT::CR && (aStart.size_forward() > 1) && *(++aStart) == nsCRT::LF) {
-      ++aStart; // advance to after CRLF
-      return true;
-    }
-
-    return false;
-  }
-
-  bool
-  FindCRLF(nsACString::const_iterator& aStart,
-           nsACString::const_iterator& aEnd)
-  {
-    nsACString::const_iterator end(aEnd);
-    return FindInReadable(NS_LITERAL_CSTRING("\r\n"), aStart, end);
-  }
-
   bool
   ParseHeader(nsACString::const_iterator& aStart,
               nsACString::const_iterator& aEnd,
               bool* aWasEmptyHeader)
   {
-    MOZ_ASSERT(aWasEmptyHeader);
-    // Set it to a valid value here so we don't forget later.
-    *aWasEmptyHeader = false;
-
-    const char* beginning = aStart.get();
-    nsACString::const_iterator end(aEnd);
-    if (!FindCRLF(aStart, end)) {
+    nsAutoCString headerName, headerValue;
+    if (!FetchUtil::ExtractHeader(aStart, aEnd,
+                                  headerName, headerValue,
+                                  aWasEmptyHeader)) {
       return false;
     }
-
-    if (aStart.get() == beginning) {
-      *aWasEmptyHeader = true;
+    if (*aWasEmptyHeader) {
       return true;
     }
 
-    nsAutoCString header(beginning, aStart.get() - beginning);
-
-    nsACString::const_iterator headerStart, headerEnd;
-    header.BeginReading(headerStart);
-    header.EndReading(headerEnd);
-    if (!FindCharInReadable(':', headerStart, headerEnd)) {
-      return false;
-    }
-
-    nsAutoCString headerName(StringHead(header, headerStart.size_backward()));
-    headerName.CompressWhitespace();
-    if (!NS_IsValidHTTPToken(headerName)) {
-      return false;
-    }
-
-    nsAutoCString headerValue(Substring(++headerStart, headerEnd));
-    if (!NS_IsReasonableHTTPHeaderValue(headerValue)) {
-      return false;
-    }
-    headerValue.CompressWhitespace();
-
     if (headerName.LowerCaseEqualsLiteral("content-disposition")) {
       nsCCharSeparatedTokenizer tokenizer(headerValue, ';');
       bool seenFormData = false;
       while (tokenizer.hasMoreTokens()) {
         const nsDependentCSubstring& token = tokenizer.nextToken();
         if (token.IsEmpty()) {
           continue;
         }
@@ -471,17 +492,17 @@ public:
           break;
 
         case PARSE_HEADER:
           bool emptyHeader;
           if (!ParseHeader(start, end, &emptyHeader)) {
             return false;
           }
 
-          if (!PushOverLine(start)) {
+          if (emptyHeader && !PushOverLine(start)) {
             return false;
           }
 
           mState = emptyHeader ? PARSE_BODY : PARSE_HEADER;
           break;
 
         case PARSE_BODY:
           if (mName.IsVoid()) {
--- a/dom/fetch/FetchUtil.h
+++ b/dom/fetch/FetchUtil.h
@@ -60,13 +60,23 @@ public:
 
   /**
    * Parses a UTF-8 encoded |aStr| as JSON, assigning the result to |aValue|.
    * Sets |aRv| to a syntax error if |aStr| contains invalid data.
    */
   static void
   ConsumeJson(JSContext* aCx, JS::MutableHandle<JS::Value> aValue,
               const nsString& aStr, ErrorResult& aRv);
+
+  /**
+   * Extracts an HTTP header from a substring range.
+   */
+  static bool
+  ExtractHeader(nsACString::const_iterator& aStart,
+                nsACString::const_iterator& aEnd,
+                nsCString& aHeaderName,
+                nsCString& aHeaderValue,
+                bool* aWasEmptyHeader);
 };
 
 } // namespace dom
 } // namespace mozilla
 #endif