Bug 1532530 - Avoid loss of upload data by webRequest API r=kmag
authorRob Wu <rob@robwu.nl>
Mon, 25 Mar 2019 21:16:49 +0000
changeset 466031 574c141c8dd619a00ffa90fc40c2ba614afb46da
parent 466030 40425ded3bad6ec5db3e3a2cba23cf3a0e447f75
child 466032 a0dcfd3d82f2f8c2407afbb45de34d455156a048
push id81392
push userrob@robwu.nl
push dateTue, 26 Mar 2019 00:46:51 +0000
treeherderautoland@574c141c8dd6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskmag
bugs1532530
milestone68.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 1532530 - Avoid loss of upload data by webRequest API r=kmag When an extension requests access to the request body of a request, `nsConverterInputStream` is used to parse the input streams that make up a request body. These input streams are later (re)used to upload the form data to the original destination (server). `nsConverterInputStream`'s destructor does however close the input streams, which results in data loss when the object is garbage-collected before the upload completes. This patch fixes the issue by explicitly nulling the underlying stream before returning from the form parser. Differential Revision: https://phabricator.services.mozilla.com/D24539
toolkit/modules/addons/WebRequestUpload.jsm
--- a/toolkit/modules/addons/WebRequestUpload.jsm
+++ b/toolkit/modules/addons/WebRequestUpload.jsm
@@ -187,16 +187,17 @@ function* getStreams(outerStream) {
  *        decoding errors.
  *
  * @returns {Map<string, Array<string>> | null}
  */
 function parseFormData(stream, channel, lenient = false) {
   const BUFFER_SIZE = 8192;
 
   let touchedStreams = new Set();
+  let converterStreams = [];
 
   /**
    * Creates a converter input stream from the given raw input stream,
    * and adds it to the list of streams to be rewound at the end of
    * parsing.
    *
    * Returns null if the given raw stream cannot be rewound.
    *
@@ -205,20 +206,22 @@ function parseFormData(stream, channel, 
    * @returns {ConverterInputStream | null}
    */
   function createTextStream(stream) {
     if (!(stream instanceof Ci.nsISeekableStream)) {
       return null;
     }
 
     touchedStreams.add(stream);
-    return ConverterInputStream(
+    let converterStream = ConverterInputStream(
       stream, "UTF-8", 0,
       lenient ? Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER
               : 0);
+    converterStreams.push(converterStream);
+    return converterStream;
   }
 
   /**
    * Reads a string of no more than the given length from the given text
    * stream.
    *
    * @param {ConverterInputStream} stream
    *        The stream to read.
@@ -377,16 +380,22 @@ function parseFormData(stream, channel, 
 
       case "application/x-www-form-urlencoded":
         return parseUrlEncoded(stream);
     }
   } finally {
     for (let stream of touchedStreams) {
       rewind(stream);
     }
+    for (let converterStream of converterStreams) {
+      // Release the reference to the underlying input stream, to prevent the
+      // destructor of nsConverterInputStream from closing the stream, which
+      // would cause uploads to break.
+      converterStream.init(null, null, 0, 0);
+    }
   }
 
   return null;
 }
 
 /**
  * Parses the form data of the given stream as either multipart/form-data or
  * x-www-form-urlencoded, and returns a map of its fields.