Bug 1272284 - Encode C0 controls in path, query and hash r=mcmanus
authorValentin Gosu <valentin.gosu@gmail.com>
Wed, 25 May 2016 16:23:38 +0200
changeset 337977 f8cb3324570e9479124a7f5ef1cb4a23b6b1465f
parent 337976 a10683e0ed001963fcf87a55d42b9e189fd4f481
child 337978 c18023d517ed93d0e506f410c28ddfa60a2e6eee
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmcmanus
bugs1272284
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 1272284 - Encode C0 controls in path, query and hash r=mcmanus MozReview-Commit-ID: 1zGRjVmAWts
netwerk/base/nsStandardURL.cpp
netwerk/test/unit/test_standardurl.js
--- a/netwerk/base/nsStandardURL.cpp
+++ b/netwerk/base/nsStandardURL.cpp
@@ -1302,21 +1302,16 @@ nsStandardURL::SetSpec(const nsACString 
     // filter out unexpected chars "\r\n\t" if necessary
     nsAutoCString filteredURI;
     net_FilterURIString(flat, filteredURI);
 
     if (filteredURI.Length() == 0) {
         return NS_ERROR_MALFORMED_URI;
     }
 
-    // NUL characters aren't allowed in the filtered URI.
-    if (filteredURI.Contains('\0')) {
-        return NS_ERROR_MALFORMED_URI;
-    }
-
     // Make a backup of the curent URL
     nsStandardURL prevURL(false,false);
     prevURL.CopyMembers(this, eHonorRef);
     Clear();
 
     if (IsSpecialProtocol(filteredURI)) {
         // Bug 652186: Replace all backslashes with slashes when parsing paths
         // Stop when we reach the query or the hash.
@@ -2520,17 +2515,17 @@ nsStandardURL::SetFilePath(const nsACStr
         return SetPath(flat);
 
     if (filepath && *filepath) {
         nsAutoCString spec;
         uint32_t dirPos, basePos, extPos;
         int32_t dirLen, baseLen, extLen;
         nsresult rv;
 
-        rv = mParser->ParseFilePath(filepath, -1,
+        rv = mParser->ParseFilePath(filepath, flat.Length(),
                                     &dirPos, &dirLen,
                                     &basePos, &baseLen,
                                     &extPos, &extLen);
         if (NS_FAILED(rv)) return rv;
 
         // build up new candidate spec
         spec.Assign(mSpec.get(), mPath.mPos);
 
@@ -2609,17 +2604,17 @@ nsStandardURL::SetQuery(const nsACString
             ShiftFromRef(-(mQuery.mLen + 1));
             mPath.mLen -= (mQuery.mLen + 1);
             mQuery.mPos = 0;
             mQuery.mLen = -1;
         }
         return NS_OK;
     }
 
-    int32_t queryLen = strlen(query);
+    int32_t queryLen = flat.Length();
     if (query[0] == '?') {
         query++;
         queryLen--;
     }
 
     if (mQuery.mLen < 0) {
         if (mRef.mLen < 0)
             mQuery.mPos = mSpec.Length();
@@ -2659,20 +2654,16 @@ nsStandardURL::SetRef(const nsACString &
 {
     ENSURE_MUTABLE();
 
     const nsPromiseFlatCString &flat = PromiseFlatCString(input);
     const char *ref = flat.get();
 
     LOG(("nsStandardURL::SetRef [ref=%s]\n", ref));
 
-    if (input.Contains('\0')) {
-        return NS_ERROR_MALFORMED_URI;
-    }
-
     if (mPath.mLen < 0)
         return SetPath(flat);
 
     if (mSpec.Length() + input.Length() - Ref().Length() > (uint32_t) net_GetURLMaxLength()) {
         return NS_ERROR_MALFORMED_URI;
     }
 
     InvalidateCache();
@@ -2689,17 +2680,17 @@ nsStandardURL::SetRef(const nsACString &
         return NS_OK;
     }
 
     int32_t refLen = flat.Length();
     if (ref[0] == '#') {
         ref++;
         refLen--;
     }
-    
+
     if (mRef.mLen < 0) {
         mSpec.Append('#');
         ++mPath.mLen;  // Include the # in the path.
         mRef.mPos = mSpec.Length();
         mRef.mLen = 0;
     }
 
     // If precent encoding is necessary, `ref` will point to `buf`'s content.
@@ -2760,17 +2751,17 @@ nsStandardURL::SetFileName(const nsACStr
             mExtension.mLen = -1;
         }
     }
     else {
         nsresult rv;
         URLSegment basename, extension;
 
         // let the parser locate the basename and extension
-        rv = mParser->ParseFileName(filename, -1,
+        rv = mParser->ParseFileName(filename, flat.Length(),
                                     &basename.mPos, &basename.mLen,
                                     &extension.mPos, &extension.mLen);
         if (NS_FAILED(rv)) return rv;
 
         if (basename.mLen < 0) {
             // remove existing filename
             if (mBasename.mLen >= 0) {
                 uint32_t len = mBasename.mLen;
--- a/netwerk/test/unit/test_standardurl.js
+++ b/netwerk/test/unit/test_standardurl.js
@@ -351,8 +351,44 @@ add_test(function test_trim_C0_and_space
 {
   var url = stringToURL("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f http://example.com/ \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f ");
   do_check_eq(url.spec, "http://example.com/");
   url.spec = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f http://test.com/ \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f ";
   do_check_eq(url.spec, "http://test.com/");
   Assert.throws(() => { url.spec = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19 "; }, "set empty spec");
   run_next_test();
 });
+
+// This tests that C0-and-space characters in the path, query and ref are
+// percent encoded.
+add_test(function test_encode_C0_and_space()
+{
+  function toHex(d) {
+    var hex = d.toString(16);
+    if (hex.length == 1)
+      hex = "0"+hex;
+    return hex.toUpperCase();
+  }
+
+  for (var i=0x0; i<=0x20; i++) {
+    // These characters get filtered - they are not encoded.
+    if (String.fromCharCode(i) == '\r' ||
+        String.fromCharCode(i) == '\n' ||
+        String.fromCharCode(i) == '\t') {
+      continue;
+    }
+    var url = stringToURL("http://example.com/pa" + String.fromCharCode(i) + "th?qu" + String.fromCharCode(i) +"ery#ha" + String.fromCharCode(i) + "sh");
+    do_check_eq(url.spec, "http://example.com/pa%" + toHex(i) + "th?qu%" + toHex(i) + "ery#ha%" + toHex(i) + "sh");
+  }
+
+  // Additionally, we need to check the setters.
+  var url = stringToURL("http://example.com/path?query#hash");
+  url.filePath = "pa\0th";
+  do_check_eq(url.spec, "http://example.com/pa%00th?query#hash");
+  url.query = "qu\0ery";
+  do_check_eq(url.spec, "http://example.com/pa%00th?qu%00ery#hash");
+  url.ref = "ha\0sh";
+  do_check_eq(url.spec, "http://example.com/pa%00th?qu%00ery#ha%00sh");
+  url.fileName = "fi\0le.name";
+  do_check_eq(url.spec, "http://example.com/fi%00le.name?qu%00ery#ha%00sh");
+
+  run_next_test();
+});