test_http3_large_post.js (5065B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 registerCleanupFunction(async () => { 6 http3_clear_prefs(); 7 }); 8 9 add_task(async function setup() { 10 await http3_setup_tests("h3"); 11 }); 12 13 let Http3Listener = function (amount) { 14 this.amount = amount; 15 }; 16 17 Http3Listener.prototype = { 18 expectedStatus: Cr.NS_OK, 19 amount: 0, 20 onProgressMaxNotificationCount: 0, 21 onProgressNotificationCount: 0, 22 23 QueryInterface: ChromeUtils.generateQI(["nsIProgressEventSink"]), 24 25 getInterface(iid) { 26 if (iid.equals(Ci.nsIProgressEventSink)) { 27 return this; 28 } 29 throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE); 30 }, 31 32 onProgress(request, progress, progressMax) { 33 // we will get notifications for the request and the response. 34 if (progress === progressMax) { 35 this.onProgressMaxNotificationCount += 1; 36 } 37 // For a large upload there should be a multiple notifications. 38 this.onProgressNotificationCount += 1; 39 }, 40 41 onStatus() {}, 42 43 onStartRequest: function testOnStartRequest(request) { 44 Assert.equal(request.status, this.expectedStatus); 45 if (Components.isSuccessCode(this.expectedStatus)) { 46 Assert.equal(request.responseStatus, 200); 47 } 48 Assert.equal( 49 this.amount, 50 request.getResponseHeader("x-data-received-length") 51 ); 52 }, 53 54 onDataAvailable: function testOnDataAvailable(request, stream, off, cnt) { 55 read_stream(stream, cnt); 56 }, 57 58 onStopRequest: function testOnStopRequest(request) { 59 let httpVersion = ""; 60 try { 61 httpVersion = request.protocolVersion; 62 } catch (e) {} 63 Assert.equal(httpVersion, "h3"); 64 // We should get 2 correctOnProgress, i.e. one for request and one for the response. 65 Assert.equal(this.onProgressMaxNotificationCount, 2); 66 if (this.amount > 500000) { 67 // 10 is an arbitrary number, but we cannot calculate exact number 68 // because it depends on timing. 69 Assert.greater(this.onProgressNotificationCount, 10); 70 } 71 this.finish(); 72 }, 73 }; 74 75 function chanPromise(chan, listener) { 76 return new Promise(resolve => { 77 function finish(result) { 78 resolve(result); 79 } 80 listener.finish = finish; 81 chan.asyncOpen(listener); 82 }); 83 } 84 85 function makeChan(uri, amount) { 86 let chan = NetUtil.newChannel({ 87 uri, 88 loadUsingSystemPrincipal: true, 89 }).QueryInterface(Ci.nsIHttpChannel); 90 chan.loadFlags = Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI; 91 92 let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance( 93 Ci.nsIStringInputStream 94 ); 95 stream.setByteStringData(generateContent(amount)); 96 let uchan = chan.QueryInterface(Ci.nsIUploadChannel); 97 uchan.setUploadStream(stream, "text/plain", stream.available()); 98 chan.requestMethod = "POST"; 99 return chan; 100 } 101 102 // Generate a post. 103 function generateContent(size) { 104 let content = ""; 105 for (let i = 0; i < size; i++) { 106 content += "0"; 107 } 108 return content; 109 } 110 111 // Send a large post that can fit into a neqo stream buffer at once. 112 // But the amount of data is larger than the necko's default stream 113 // buffer side, therefore ReadSegments will be called multiple times. 114 add_task(async function test_large_post() { 115 let amount = 1 << 16; 116 let listener = new Http3Listener(amount); 117 let chan = makeChan("https://foo.example.com/post", amount); 118 chan.notificationCallbacks = listener; 119 await chanPromise(chan, listener); 120 }); 121 122 // Send a large post that cannot fit into a neqo stream buffer at once. 123 // StreamWritable events will trigger sending more data when the buffer 124 // space is freed 125 add_task(async function test_large_post2() { 126 let amount = 1 << 23; 127 let listener = new Http3Listener(amount); 128 let chan = makeChan("https://foo.example.com/post", amount); 129 chan.notificationCallbacks = listener; 130 await chanPromise(chan, listener); 131 }); 132 133 // Send a post in the same way viaduct does in bug 1749957. 134 add_task(async function test_bug1749957_bug1750056() { 135 let amount = 200; // Tests the bug as long as it's non-zero. 136 let uri = "https://foo.example.com/post"; 137 let listener = new Http3Listener(amount); 138 139 let chan = NetUtil.newChannel({ 140 uri, 141 loadUsingSystemPrincipal: true, 142 }).QueryInterface(Ci.nsIHttpChannel); 143 144 // https://searchfox.org/mozilla-central/rev/1920b17ac5988fcfec4e45e2a94478ebfbfc6f88/toolkit/components/viaduct/ViaductRequest.cpp#120-152 145 { 146 chan.requestMethod = "POST"; 147 chan.setRequestHeader("content-length", "" + amount, /* aMerge = */ false); 148 149 let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance( 150 Ci.nsIStringInputStream 151 ); 152 stream.setByteStringData(generateContent(amount)); 153 let uchan = chan.QueryInterface(Ci.nsIUploadChannel2); 154 uchan.explicitSetUploadStream( 155 stream, 156 /* aContentType = */ "", 157 /* aContentLength = */ -1, 158 "POST", 159 /* aStreamHasHeaders = */ false 160 ); 161 } 162 163 chan.notificationCallbacks = listener; 164 await chanPromise(chan, listener); 165 });