Bug 1433624 - Use rust-url's form-urlencoded parser; r?bz draft
authorAnthony Ramine <n.oxyde@gmail.com>
Fri, 26 Jan 2018 22:43:09 +0100
changeset 751019 d29f2d463feeb5ae1e7718015fc56df68718ccc5
parent 751018 a813cec0db4cea1022c7a7f17b2955e2ba4cc8a7
child 751020 d58ca3ed9826cca618597852972f29efe95a5b9e
push id97816
push userbmo:nox@mozilla.com
push dateSun, 04 Feb 2018 14:40:11 +0000
reviewersbz
bugs1433624
milestone60.0a1
Bug 1433624 - Use rust-url's form-urlencoded parser; r?bz That parser is already in rust-url, and will not copy into any intermediate string the contents of the form-urlencoded input, as long as it doesn't encounter percent-encoded bytes or malformed UTF-8 byte sequences. MozReview-Commit-ID: 9UYMNy7NQNP
netwerk/base/MozURL.cpp
netwerk/base/rust-url-capi/src/lib.rs
netwerk/base/rust-url-capi/src/rust-url-capi.h
--- a/netwerk/base/MozURL.cpp
+++ b/netwerk/base/MozURL.cpp
@@ -2,16 +2,34 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MozURL.h"
 #include "mozilla/Encoding.h"
 #include "nsReadableUtils.h"
 #include "rust-url-capi/src/rust-url-capi.h"
 
+extern "C" {
+struct ForEachWrapper
+{
+  nsAutoString& mName;
+  nsAutoString& mValue;
+  mozilla::MozURL::ForEachFormUrlencoded& mProcessor;
+};
+
+static bool
+CallForEach(const nsACString* aName, const nsACString* aValue, void* aContext)
+{
+  auto wrapper = static_cast<ForEachWrapper*>(aContext);
+  CopyUTF8toUTF16(*aName, wrapper->mName);
+  CopyUTF8toUTF16(*aValue, wrapper->mValue);
+  return wrapper->mProcessor.Process(wrapper->mName, wrapper->mValue);
+}
+}
+
 namespace mozilla {
 namespace net {
 
 NS_IMPL_ADDREF(MozURL)
 NS_IMPL_RELEASE(MozURL)
 
 /* static */ nsresult
 MozURL::Init(MozURL** aURL, const nsACString& aSpec, const MozURL* aBaseURL)
@@ -103,133 +121,28 @@ MozURL::GetRef(nsACString& aRef)
 }
 
 nsresult
 MozURL::GetOrigin(nsACString& aOrigin)
 {
   return rusturl_get_origin(mURL.get(), &aOrigin);
 }
 
-static void
-ConvertString(const nsACString& aInput, nsAString& aOutput)
-{
-  if (NS_FAILED(UTF_8_ENCODING->DecodeWithoutBOMHandling(aInput, aOutput))) {
-    MOZ_CRASH("Out of memory when converting URL params.");
-  }
-}
-
-static void
-DecodeString(const nsACString& aInput, nsAString& aOutput)
-{
-  nsACString::const_iterator start, end;
-  aInput.BeginReading(start);
-  aInput.EndReading(end);
-
-  nsCString unescaped;
-
-  while (start != end) {
-    // replace '+' with U+0020
-    if (*start == '+') {
-      unescaped.Append(' ');
-      ++start;
-      continue;
-    }
-
-    // Percent decode algorithm
-    if (*start == '%') {
-      nsACString::const_iterator first(start);
-      ++first;
-
-      nsACString::const_iterator second(first);
-      ++second;
-
-#define ASCII_HEX_DIGIT( x )    \
-  ((x >= 0x41 && x <= 0x46) ||  \
-   (x >= 0x61 && x <= 0x66) ||  \
-   (x >= 0x30 && x <= 0x39))
-
-#define HEX_DIGIT( x )              \
-   (*x >= 0x30 && *x <= 0x39        \
-     ? *x - 0x30                    \
-     : (*x >= 0x41 && *x <= 0x46    \
-        ? *x - 0x37                 \
-        : *x - 0x57))
-
-      if (first != end && second != end &&
-          ASCII_HEX_DIGIT(*first) && ASCII_HEX_DIGIT(*second)) {
-        unescaped.Append(HEX_DIGIT(first) * 16 + HEX_DIGIT(second));
-        start = ++second;
-        continue;
-
-      } else {
-        unescaped.Append('%');
-        ++start;
-        continue;
-      }
-    }
-
-    unescaped.Append(*start);
-    ++start;
-  }
-
-  ConvertString(unescaped, aOutput);
-}
-
 /* static */ bool
 MozURL::ParseFormUrlencoded(const nsACString& aInput,
                             ForEachFormUrlencoded& aProcessor)
 {
-  nsACString::const_iterator start, end;
-  aInput.BeginReading(start);
-  aInput.EndReading(end);
-  nsACString::const_iterator iter(start);
-
-  while (start != end) {
-    nsAutoCString string;
-
-    if (FindCharInReadable('&', iter, end)) {
-      string.Assign(Substring(start, iter));
-      start = ++iter;
-    } else {
-      string.Assign(Substring(start, end));
-      start = end;
-    }
-
-    if (string.IsEmpty()) {
-      continue;
-    }
-
-    nsACString::const_iterator eqStart, eqEnd;
-    string.BeginReading(eqStart);
-    string.EndReading(eqEnd);
-    nsACString::const_iterator eqIter(eqStart);
-
-    nsAutoCString name;
-    nsAutoCString value;
-
-    if (FindCharInReadable('=', eqIter, eqEnd)) {
-      name.Assign(Substring(eqStart, eqIter));
-
-      ++eqIter;
-      value.Assign(Substring(eqIter, eqEnd));
-    } else {
-      name.Assign(string);
-    }
-
-    nsAutoString decodedName;
-    DecodeString(name, decodedName);
-
-    nsAutoString decodedValue;
-    DecodeString(value, decodedValue);
-
-    if (!aProcessor.Process(decodedName, decodedValue)) {
-      return false;
-    }
-  }
-  return true;
+  nsAutoString name;
+  nsAutoString value;
+  ForEachWrapper wrapper = {
+    name,
+    value,
+    aProcessor
+  };
+  return rusturl_parse_form_urlencoded(&aInput, CallForEach, &wrapper);
 }
 
 class MOZ_STACK_CLASS ExtractURLParam final
   : public MozURL::ForEachFormUrlencoded
 {
 public:
   explicit ExtractURLParam(const nsAString& aName, nsAString& aValue)
     : mName(aName)
--- a/netwerk/base/rust-url-capi/src/lib.rs
+++ b/netwerk/base/rust-url-capi/src/lib.rs
@@ -3,20 +3,20 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 extern crate url;
 use url::{Url, ParseOptions, Position};
 use url::quirks;
 
 extern crate libc;
-use libc::size_t;
+use libc::{c_void, size_t};
 
 extern crate nsstring;
-use nsstring::nsACString;
+use nsstring::{nsACString, nsCStr};
 
 extern crate nserror;
 use nserror::*;
 
 use std::mem;
 use std::str;
 use std::ptr;
 
@@ -604,8 +604,22 @@ pub extern "C" fn rusturl_parse_ipv6addr
     Ok(host) => host,
     // XXX: Do we want to change our error message based on the error type?
     Err(_) => return NS_ERROR_MALFORMED_URI,
   };
 
   cont.assign(&h.to_string());
   NS_OK
 }
+
+#[no_mangle]
+pub extern "C" fn rusturl_parse_form_urlencoded(
+  input: &nsACString,
+  callback: extern "C" fn(&nsACString, &nsACString, *mut c_void) -> bool,
+  context: *mut c_void,
+) -> bool {
+  for (name, value) in url::form_urlencoded::parse(input) {
+    if !callback(&nsCStr::from(&*name), &nsCStr::from(&*value), context) {
+      return false;
+    }
+  }
+  true
+}
--- a/netwerk/base/rust-url-capi/src/rust-url-capi.h
+++ b/netwerk/base/rust-url-capi/src/rust-url-capi.h
@@ -49,13 +49,17 @@ nsresult rusturl_set_query(rusturl* url,
 nsresult rusturl_set_fragment(rusturl* url, const nsACString* fragment);
 
 nsresult rusturl_resolve(const rusturl* url, const nsACString* relative, nsACString* cont);
 nsresult rusturl_common_base_spec(const rusturl* url1, const rusturl* url2, nsACString* cont);
 nsresult rusturl_relative_spec(const rusturl* url1, const rusturl* url2, nsACString* cont);
 
 nsresult rusturl_parse_ipv6addr(const nsACString* input, nsACString* cont);
 
+bool rusturl_parse_form_urlencoded(const nsACString* input,
+                                   bool callback(const nsACString* key, const nsACString* value, void* ctx),
+                                   void *ctx);
+
 size_t sizeof_rusturl();
 
 }
 
 #endif // __RUST_URL_CAPI