commit 5b51cf7d301c6f8d5fd3a939dea602c7484111ed Author: David Fifield david@bamsoftware.com Date: Mon Sep 8 16:43:37 2014 -0700
Fix readIntoBuf when starting with a non-empty buffer.
readIntoBuf concatenates results from multiple reads until a buffer is filled. There was a mistake whenever the current offset was not 0: the second argument is an absolute index, not a length relative to the first argument.
The affected line of code was: this.buf.subarray(this.buf.length - this.bytesToRead, n).set(data) For example, if bytesToRead were 100, and readIntoBuf were called with 20 bytes available, the data would be stored in the buffer as: this.buf.subarray(100 - 100, 20).set(<array with length 20>) So far, so good. The first 20 elements of the array would be set. When the next read happened, say there are 80 bytes available, the call would be: this.buf.subarray(100 - 80, 80).set(<array with length 80>) The code was trying to store an 80-length array in a 60-length subarray, and failed with RangeError: invalid array length
I'm pretty sure this bug was the cause of "tbb bundle with meek takes (literally) hours to connect" https://trac.torproject.org/projects/tor/ticket/11612 It would be more likely to happen during initial bootstrapping, because that's when the client sends some large bunches of data (they can be about 80 KB), which are more likely to be split into two sends. I was able to reproduce the described error by altering meek-client to split its sends into two, with a 500-millisecond delay in between. --- firefox/components/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/firefox/components/main.js b/firefox/components/main.js index ec98d15..1b71412 100644 --- a/firefox/components/main.js +++ b/firefox/components/main.js @@ -340,7 +340,7 @@ MeekHTTPHelper.RequestReader.prototype = { readIntoBuf: function(input) { var n = Math.min(input.available(), this.bytesToRead); var data = input.readByteArray(n); - this.buf.subarray(this.buf.length - this.bytesToRead, n).set(data) + this.buf.subarray(this.buf.length - this.bytesToRead).set(data); this.bytesToRead -= n; },