summaryrefslogtreecommitdiffstats
path: root/netwerk/test/unit/test_http3_large_post.js
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/test/unit/test_http3_large_post.js')
-rw-r--r--netwerk/test/unit/test_http3_large_post.js165
1 files changed, 165 insertions, 0 deletions
diff --git a/netwerk/test/unit/test_http3_large_post.js b/netwerk/test/unit/test_http3_large_post.js
new file mode 100644
index 0000000000..2ed8e51bb4
--- /dev/null
+++ b/netwerk/test/unit/test_http3_large_post.js
@@ -0,0 +1,165 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+registerCleanupFunction(async () => {
+ http3_clear_prefs();
+});
+
+add_task(async function setup() {
+ await http3_setup_tests("h3-29");
+});
+
+let Http3Listener = function (amount) {
+ this.amount = amount;
+};
+
+Http3Listener.prototype = {
+ expectedStatus: Cr.NS_OK,
+ amount: 0,
+ onProgressMaxNotificationCount: 0,
+ onProgressNotificationCount: 0,
+
+ QueryInterface: ChromeUtils.generateQI(["nsIProgressEventSink"]),
+
+ getInterface(iid) {
+ if (iid.equals(Ci.nsIProgressEventSink)) {
+ return this;
+ }
+ throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE);
+ },
+
+ onProgress(request, progress, progressMax) {
+ // we will get notifications for the request and the response.
+ if (progress === progressMax) {
+ this.onProgressMaxNotificationCount += 1;
+ }
+ // For a large upload there should be a multiple notifications.
+ this.onProgressNotificationCount += 1;
+ },
+
+ onStatus(request, status, statusArg) {},
+
+ onStartRequest: function testOnStartRequest(request) {
+ Assert.equal(request.status, this.expectedStatus);
+ if (Components.isSuccessCode(this.expectedStatus)) {
+ Assert.equal(request.responseStatus, 200);
+ }
+ Assert.equal(
+ this.amount,
+ request.getResponseHeader("x-data-received-length")
+ );
+ },
+
+ onDataAvailable: function testOnDataAvailable(request, stream, off, cnt) {
+ read_stream(stream, cnt);
+ },
+
+ onStopRequest: function testOnStopRequest(request, status) {
+ let httpVersion = "";
+ try {
+ httpVersion = request.protocolVersion;
+ } catch (e) {}
+ Assert.equal(httpVersion, "h3-29");
+ // We should get 2 correctOnProgress, i.e. one for request and one for the response.
+ Assert.equal(this.onProgressMaxNotificationCount, 2);
+ if (this.amount > 500000) {
+ // 10 is an arbitrary number, but we cannot calculate exact number
+ // because it depends on timing.
+ Assert.ok(this.onProgressNotificationCount > 10);
+ }
+ this.finish();
+ },
+};
+
+function chanPromise(chan, listener) {
+ return new Promise(resolve => {
+ function finish(result) {
+ resolve(result);
+ }
+ listener.finish = finish;
+ chan.asyncOpen(listener);
+ });
+}
+
+function makeChan(uri, amount) {
+ let chan = NetUtil.newChannel({
+ uri,
+ loadUsingSystemPrincipal: true,
+ }).QueryInterface(Ci.nsIHttpChannel);
+ chan.loadFlags = Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI;
+
+ let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
+ Ci.nsIStringInputStream
+ );
+ stream.data = generateContent(amount);
+ let uchan = chan.QueryInterface(Ci.nsIUploadChannel);
+ uchan.setUploadStream(stream, "text/plain", stream.available());
+ chan.requestMethod = "POST";
+ return chan;
+}
+
+// Generate a post.
+function generateContent(size) {
+ let content = "";
+ for (let i = 0; i < size; i++) {
+ content += "0";
+ }
+ return content;
+}
+
+// Send a large post that can fit into a neqo stream buffer at once.
+// But the amount of data is larger than the necko's default stream
+// buffer side, therefore ReadSegments will be called multiple times.
+add_task(async function test_large_post() {
+ let amount = 1 << 16;
+ let listener = new Http3Listener(amount);
+ let chan = makeChan("https://foo.example.com/post", amount);
+ chan.notificationCallbacks = listener;
+ await chanPromise(chan, listener);
+});
+
+// Send a large post that cannot fit into a neqo stream buffer at once.
+// StreamWritable events will trigger sending more data when the buffer
+// space is freed
+add_task(async function test_large_post2() {
+ let amount = 1 << 23;
+ let listener = new Http3Listener(amount);
+ let chan = makeChan("https://foo.example.com/post", amount);
+ chan.notificationCallbacks = listener;
+ await chanPromise(chan, listener);
+});
+
+// Send a post in the same way viaduct does in bug 1749957.
+add_task(async function test_bug1749957_bug1750056() {
+ let amount = 200; // Tests the bug as long as it's non-zero.
+ let uri = "https://foo.example.com/post";
+ let listener = new Http3Listener(amount);
+
+ let chan = NetUtil.newChannel({
+ uri,
+ loadUsingSystemPrincipal: true,
+ }).QueryInterface(Ci.nsIHttpChannel);
+
+ // https://searchfox.org/mozilla-central/rev/1920b17ac5988fcfec4e45e2a94478ebfbfc6f88/toolkit/components/viaduct/ViaductRequest.cpp#120-152
+ {
+ chan.requestMethod = "POST";
+ chan.setRequestHeader("content-length", "" + amount, /* aMerge = */ false);
+
+ let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
+ Ci.nsIStringInputStream
+ );
+ stream.data = generateContent(amount);
+ let uchan = chan.QueryInterface(Ci.nsIUploadChannel2);
+ uchan.explicitSetUploadStream(
+ stream,
+ /* aContentType = */ "",
+ /* aContentLength = */ -1,
+ "POST",
+ /* aStreamHasHeaders = */ false
+ );
+ }
+
+ chan.notificationCallbacks = listener;
+ await chanPromise(chan, listener);
+});