// Generate a small and a large post with known pre-calculated md5 sums function generateContent(size) { var content = ""; for (var i = 0; i < size; i++) {
content += "0";
} return content;
}
var posts = [];
posts.push(generateContent(10));
posts.push(generateContent(250000));
posts.push(generateContent(128000));
// pre-calculated md5sums (in hex) of the above posts var md5s = [ "f1b708bba17f1ce948dc979f4d7092bc", "2ef8d3b6c8f329318eb1a119b12622b6",
];
var bigListenerData = generateContent(128 * 1024); var bigListenerMD5 = "8f607cfdd2c87d6a7eedb657dafbd836";
function checkIsHttp2(request) { try { if (request.getResponseHeader("X-Firefox-Spdy") == "h2") { if (request.getResponseHeader("X-Connection-Http2") == "yes") { returntrue;
} returnfalse; // Weird case, but the server disagrees with us
}
} catch (e) { // Nothing to do here
} returnfalse;
}
Http2MultiplexListener.prototype.onDataAvailable = function (
request,
stream,
off,
cnt
) { this.onDataAvailableFired = true; this.isHttp2Connection = checkIsHttp2(request); this.streamID = parseInt(request.getResponseHeader("X-Http2-StreamID")); var data = read_stream(stream, cnt); this.buffer = this.buffer.concat(data);
};
Http2MultiplexListener.prototype.onStopRequest = function (request) { Assert.ok(this.onStartRequestFired); Assert.ok(this.onDataAvailableFired); Assert.ok(this.isHttp2Connection); Assert.equal(this.buffer, multiplexContent);
request.QueryInterface(Ci.nsIProxiedChannel); // This is what does most of the hard work for us var httpProxyConnectResponseCode = request.httpProxyConnectResponseCode; var streamID = this.streamID; this.finish({ httpProxyConnectResponseCode, streamID });
};
// Does the appropriate checks for header gatewaying var Http2HeaderListener = function (name, callback) { this.name = name; this.callback = callback;
};
Http2HeaderListener.prototype = new Http2CheckListener();
Http2HeaderListener.prototype.value = "";
function checkContinuedHeaders(getHeader, headerPrefix, headerText) { for (var i = 0; i < 265; i++) { Assert.equal(getHeader(headerPrefix + 1), headerText);
}
}
// Does the appropriate checks for a large GET response var Http2BigListener = function () {};
Http2BigListener.prototype = new Http2CheckListener();
Http2BigListener.prototype.buffer = "";
Http2BigListener.prototype.onDataAvailable = function (
request,
stream,
off,
cnt
) { this.onDataAvailableFired = true; this.isHttp2Connection = checkIsHttp2(request); this.buffer = this.buffer.concat(read_stream(stream, cnt)); // We know the server should send us the same data as our big post will be, // so the md5 should be the same Assert.equal(bigListenerMD5, request.getResponseHeader("X-Expected-MD5"));
};
Http2BigListener.prototype.onStopRequest = function (request) { Assert.ok(this.onStartRequestFired); Assert.ok(this.onDataAvailableFired); Assert.ok(this.isHttp2Connection);
// Don't want to flood output, so don't use do_check_eq Assert.equal(this.buffer, bigListenerData);
request.QueryInterface(Ci.nsIProxiedChannel); var httpProxyConnectResponseCode = request.httpProxyConnectResponseCode; this.finish({ httpProxyConnectResponseCode });
};
var Http2HugeSuspendedListener = function () {};
Http2HugeSuspendedListener.prototype = new Http2CheckListener();
Http2HugeSuspendedListener.prototype.count = 0;
onStartRequest: function testOnStartRequest(request) { this.onStartRequestFired = true; if (!Components.isSuccessCode(request.status)) {
do_throw("Channel should have a success code! (" + request.status + ")");
}
// test a large download that creates stream flow control and // confirm we can do another independent stream while the download // stream is stuck
async function test_http2_blocking_download(serverPort) { var chan = makeHTTPChannel(`https://localhost:${serverPort}/bigdownload`); var internalChannel = chan.QueryInterface(Ci.nsIHttpChannelInternal);
internalChannel.initialRwin = 500000; // make the stream.suspend push back in h2 var p = new Promise(resolve => { var listener = new Http2CheckListener();
listener.finish = resolve;
listener.expected = 3 * 1024 * 1024;
chan.asyncOpen(listener);
chan.suspend();
}); // wait 5 seconds so that stream flow control kicks in and then see if we // can do a basic transaction (i.e. session not blocked). afterwards resume // channel
do_timeout(5000, function () { var simpleChannel = makeHTTPChannel(`https://localhost:${serverPort}/`); var sl = new ResumeStalledChannelListener();
sl.resumable = chan;
simpleChannel.asyncOpen(sl);
}); return p;
}
// Make sure we make a HTTP2 connection and both us and the server mark it as such
async function test_http2_basic(serverPort, origin = "localhost") { var chan = makeHTTPChannel(`https://${origin}:${serverPort}/`); var p = new Promise(resolve => { var listener = new Http2CheckListener();
listener.finish = resolve;
chan.asyncOpen(listener);
}); return p;
}
async function test_http2_basic_unblocked_dep(
serverPort,
origin = "localhost"
) { var chan = makeHTTPChannel(
`https://${origin}:${serverPort}/basic_unblocked_dep`
); var cos = chan.QueryInterface(Ci.nsIClassOfService);
cos.addClassFlags(Ci.nsIClassOfService.Unblocked); returnnew Promise(resolve => { var listener = new Http2CheckListener();
listener.finish = resolve;
chan.asyncOpen(listener);
});
}
// make sure we don't use h2 when disallowed
async function test_http2_nospdy(serverPort, origin = "localhost") { var chan = makeHTTPChannel(`https://${origin}:${serverPort}/`); returnnew Promise(resolve => { var listener = new Http2CheckListener();
listener.finish = resolve; var internalChannel = chan.QueryInterface(Ci.nsIHttpChannelInternal);
internalChannel.allowSpdy = false;
listener.shouldBeHttp2 = false;
chan.asyncOpen(listener);
});
}
// Support for making sure XHR works over SPDY function checkXhr(xhr, finish) { if (xhr.readyState != 4) { return;
}
for (var i = 0; i < concurrent_listener.target; i++) {
concurrent_channels[i] = makeHTTPChannel(
`https://${origin}:${serverPort}/750msPost`
);
concurrent_channels[i].loadFlags = Ci.nsIRequest.LOAD_BYPASS_CACHE; var stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
Ci.nsIStringInputStream
);
stream.setByteStringData(posts[2]); var uchan = concurrent_channels[i].QueryInterface(Ci.nsIUploadChannel);
uchan.setUploadStream(stream, "text/plain", stream.available());
concurrent_channels[i].requestMethod = "POST";
concurrent_channels[i].asyncOpen(concurrent_listener);
}
});
}
// Test to make sure we get multiplexing right
async function test_http2_multiplex(serverPort) {
let chan1 = makeHTTPChannel(`https://localhost:${serverPort}/multiplex1`);
let chan2 = makeHTTPChannel(`https://localhost:${serverPort}/multiplex2`);
let listener1 = new Http2MultiplexListener();
let listener2 = new Http2MultiplexListener();
let promises = [];
let p1 = new Promise(resolve => {
listener1.finish = resolve;
});
promises.push(p1);
let p2 = new Promise(resolve => {
listener2.finish = resolve;
});
promises.push(p2);
// Test to make sure we gateway non-standard headers properly
async function test_http2_header(serverPort, origin = "localhost") {
let chan = makeHTTPChannel(`https://${origin}:${serverPort}/header`);
let hvalue = "Headers are fun";
chan.setRequestHeader("X-Test-Header", hvalue, false); returnnew Promise(resolve => {
let listener = new Http2HeaderListener("X-Received-Test-Header", function (
received_hvalue
) { Assert.equal(received_hvalue, hvalue);
});
listener.finish = resolve;
chan.asyncOpen(listener);
});
}
// Test to make sure headers with invalid characters in the name are rejected
async function test_http2_invalid_response_header(
serverPort,
invalid_kind,
origin = "localhost"
) { returnnew Promise(resolve => { var listener = new Http2CheckListener();
listener.finish = resolve;
listener.shouldSucceed = false; var chan = makeHTTPChannel(
`https://${origin}:${serverPort}/invalid_response_header/${invalid_kind}`
);
chan.asyncOpen(listener);
});
}
// Test to make sure cookies are split into separate fields before compression
async function test_http2_cookie_crumbling(serverPort, origin = "localhost") { var chan = makeHTTPChannel(
`https://${origin}:${serverPort}/cookie_crumbling`
); var cookiesSent = ["a=b", "c=d01234567890123456789", "e=f"].sort();
chan.setRequestHeader("Cookie", cookiesSent.join("; "), false); returnnew Promise(resolve => { var listener = new Http2HeaderListener("X-Received-Header-Pairs", function (
pairsReceived
) { var cookiesReceived = JSON.parse(pairsReceived)
.filter(function (pair) { return pair[0] == "cookie";
})
.map(function (pair) { return pair[1];
})
.sort(); Assert.equal(cookiesReceived.length, cookiesSent.length);
cookiesReceived.forEach(function (cookieReceived, index) { Assert.equal(cookiesSent[index], cookieReceived);
});
});
listener.finish = resolve;
chan.asyncOpen(listener);
});
}
// this is a basic test where the server sends a simple document with 2 header // blocks. bug 1027364
async function test_http2_doubleheader(serverPort, origin = "localhost") { var chan = makeHTTPChannel(`https://${origin}:${serverPort}/doubleheader`); returnnew Promise(resolve => { var listener = new Http2CheckListener();
listener.finish = resolve;
chan.asyncOpen(listener);
});
}
// Make sure we handle GETs that cover more than 2 frames properly
async function test_http2_big(serverPort, origin = "localhost") { var chan = makeHTTPChannel(`https://${origin}:${serverPort}/big`); returnnew Promise(resolve => { var listener = new Http2BigListener();
listener.finish = resolve;
chan.asyncOpen(listener);
});
}
async function test_http2_huge_suspended(serverPort, origin = "localhost") { var chan = makeHTTPChannel(`https://${origin}:${serverPort}/huge`); returnnew Promise(resolve => { var listener = new Http2HugeSuspendedListener();
listener.finish = resolve;
chan.asyncOpen(listener);
chan.suspend();
do_timeout(500, chan.resume);
});
}
// Support for doing a POST function do_post(content, chan, listener, method) { var stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
Ci.nsIStringInputStream
);
stream.setByteStringData(content);
var uchan = chan.QueryInterface(Ci.nsIUploadChannel);
uchan.setUploadStream(stream, "text/plain", stream.available());
chan.requestMethod = method;
chan.asyncOpen(listener);
}
// Make sure we can do a simple POST
async function test_http2_post(serverPort, origin = "localhost") { var chan = makeHTTPChannel(`https://${origin}:${serverPort}/post`); var p = new Promise(resolve => { var listener = new Http2PostListener(md5s[0]);
listener.finish = resolve;
do_post(posts[0], chan, listener, "POST");
}); return p;
}
async function test_http2_empty_post(serverPort, origin = "localhost") { var chan = makeHTTPChannel(`https://${origin}:${serverPort}/post`); var p = new Promise(resolve => { var listener = new Http2PostListener("0");
listener.finish = resolve;
do_post("", chan, listener, "POST");
}); return p;
}
// Make sure we can do a simple PATCH
async function test_http2_patch(serverPort, origin = "localhost") { var chan = makeHTTPChannel(`https://${origin}:${serverPort}/patch`); returnnew Promise(resolve => { var listener = new Http2PostListener(md5s[0]);
listener.finish = resolve;
do_post(posts[0], chan, listener, "PATCH");
});
}
// Make sure we can do a POST that covers more than 2 frames
async function test_http2_post_big(serverPort, origin = "localhost") { var chan = makeHTTPChannel(`https://${origin}:${serverPort}/post`); returnnew Promise(resolve => { var listener = new Http2PostListener(md5s[1]);
listener.finish = resolve;
do_post(posts[1], chan, listener, "POST");
});
}
// test that we use h1 without the mandatory cipher suite available when // offering at most tls1.2
async function test_http2_wrongsuite_tls12(serverPort, origin = "localhost") {
Services.prefs.setBoolPref( "security.ssl3.ecdhe_rsa_aes_128_gcm_sha256", false
);
Services.prefs.setIntPref("security.tls.version.max", 3); var chan = makeHTTPChannel(`https://${origin}:${serverPort}/wrongsuite`);
chan.loadFlags =
Ci.nsIRequest.LOAD_FRESH_CONNECTION |
Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI; returnnew Promise(resolve => { var listener = new WrongSuiteListener();
listener.finish = resolve;
chan.asyncOpen(listener);
});
}
// test that we use h2 when offering tls1.3 or higher regardless of if the // mandatory cipher suite is available
async function test_http2_wrongsuite_tls13(serverPort, origin = "localhost") {
Services.prefs.setBoolPref( "security.ssl3.ecdhe_rsa_aes_128_gcm_sha256", false
); var chan = makeHTTPChannel(`https://${origin}:${serverPort}/wrongsuite`);
chan.loadFlags =
Ci.nsIRequest.LOAD_FRESH_CONNECTION |
Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI; returnnew Promise(resolve => { var listener = new WrongSuiteListener();
listener.finish = resolve;
listener.shouldBeHttp2 = true;
chan.asyncOpen(listener);
});
}
async function test_http2_h11required_stream(serverPort, origin = "localhost") { var chan = makeHTTPChannel(
`https://${origin}:${serverPort}/h11required_stream`
); returnnew Promise(resolve => { var listener = new Http2CheckListener();
listener.finish = resolve;
listener.shouldBeHttp2 = false;
chan.asyncOpen(listener);
});
}
function H11RequiredSessionListener() {}
H11RequiredSessionListener.prototype = new Http2CheckListener();
H11RequiredSessionListener.prototype.onStopRequest = function (request) { var streamReused = request.getResponseHeader("X-H11Required-Stream-Ok"); Assert.equal(streamReused, "yes");
request.QueryInterface(Ci.nsIProxiedChannel); var httpProxyConnectResponseCode = request.httpProxyConnectResponseCode; this.finish({ httpProxyConnectResponseCode });
};
async function test_http2_h11required_session(
serverPort,
origin = "localhost"
) { var chan = makeHTTPChannel(
`https://${origin}:${serverPort}/h11required_session`
); returnnew Promise(resolve => { var listener = new H11RequiredSessionListener();
listener.finish = resolve;
listener.shouldBeHttp2 = false;
chan.asyncOpen(listener);
});
}
async function test_http2_retry_rst(serverPort, origin = "localhost") { var chan = makeHTTPChannel(`https://${origin}:${serverPort}/rstonce`); returnnew Promise(resolve => { var listener = new Http2CheckListener();
listener.finish = resolve;
chan.asyncOpen(listener);
});
}
// Server resets the first H2 request with RST_STREAM CANCEL; the retry succeeds.
async function test_http2_unknown_rst(serverPort, origin = "localhost") { var chan = makeHTTPChannel(
`https://${origin}:${serverPort}/unknown_rst_once`
); returnnew Promise(resolve => { var listener = new Http2CheckListener();
listener.finish = resolve;
chan.asyncOpen(listener);
});
}
async function test_http2_continuations_over_max_response_limit(
loadGroup,
serverPort,
origin = "localhost"
) { var chan = makeHTTPChannel(
`https://${origin}:${serverPort}/hugecontinuedheaders?size=385`
);
chan.loadGroup = loadGroup; returnnew Promise(resolve => { var listener = new Http2CheckListener();
listener.finish = resolve;
listener.shouldSucceed = false;
listener.noResponseStatus = true;
chan.asyncOpen(listener);
});
}
function Http2IllegalHpackValidationListener() {}
Http2IllegalHpackValidationListener.prototype = new Http2CheckListener();
Http2IllegalHpackValidationListener.prototype.shouldGoAway = false;
Http2IllegalHpackValidationListener.prototype.onStopRequest = function (
request
) { var wentAway = request.getResponseHeader("X-Did-Goaway") === "yes"; Assert.equal(wentAway, this.shouldGoAway);
request.QueryInterface(Ci.nsIProxiedChannel); var httpProxyConnectResponseCode = request.httpProxyConnectResponseCode; this.finish({ httpProxyConnectResponseCode });
};
function Http2IllegalHpackListener() {}
Http2IllegalHpackListener.prototype = new Http2CheckListener();
Http2IllegalHpackListener.prototype.shouldGoAway = false;
Http2IllegalHpackListener.prototype.onStopRequest = function () { var chan = makeHTTPChannel(
`https://${this.origin}:${this.serverPort}/illegalhpack_validate`
); var listener = new Http2IllegalHpackValidationListener();
listener.finish = this.finish;
listener.shouldGoAway = this.shouldGoAway;
chan.asyncOpen(listener);
};
async function test_http2_illegalhpacksoft(serverPort, origin = "localhost") { var chan = makeHTTPChannel(
`https://${origin}:${serverPort}/illegalhpacksoft`
); returnnew Promise(resolve => { var listener = new Http2IllegalHpackListener();
listener.finish = resolve;
listener.serverPort = serverPort;
listener.origin = origin;
listener.shouldGoAway = false;
listener.shouldSucceed = false;
chan.asyncOpen(listener);
});
}
async function test_http2_illegalhpackhard(serverPort, origin = "localhost") { var chan = makeHTTPChannel(
`https://${origin}:${serverPort}/illegalhpackhard`
); returnnew Promise(resolve => { var listener = new Http2IllegalHpackListener();
listener.finish = resolve;
listener.serverPort = serverPort;
listener.origin = origin;
listener.shouldGoAway = true;
listener.shouldSucceed = false;
chan.asyncOpen(listener);
});
}
async function test_http2_folded_header(
loadGroup,
serverPort,
origin = "localhost"
) { var chan = makeHTTPChannel(`https://${origin}:${serverPort}/foldedheader`);
chan.loadGroup = loadGroup; returnnew Promise(resolve => { var listener = new Http2CheckListener();
listener.finish = resolve;
listener.shouldSucceed = false;
chan.asyncOpen(listener);
});
}
async function test_http2_empty_data(serverPort, origin = "localhost") { var chan = makeHTTPChannel(`https://${origin}:${serverPort}/emptydata`); returnnew Promise(resolve => { var listener = new Http2CheckListener();
listener.finish = resolve;
chan.asyncOpen(listener);
});
}
async function test_http2_continuation_stream_zero(
serverPort,
origin = "localhost"
) { var chan = makeHTTPChannel(
`https://${origin}:${serverPort}/continuation_stream_zero`
); returnnew Promise(resolve => { var listener = new Http2CheckListener();
listener.finish = resolve;
listener.shouldSucceed = false;
chan.asyncOpen(listener);
});
}
async function test_http2_status_phrase(serverPort, origin = "localhost") { var chan = makeHTTPChannel(`https://${origin}:${serverPort}/statusphrase`); returnnew Promise(resolve => { var listener = new Http2CheckListener();
listener.finish = resolve;
listener.shouldSucceed = false;
chan.asyncOpen(listener);
});
}
var PulledDiskCacheListener = function () {};
PulledDiskCacheListener.prototype = new Http2CheckListener();
PulledDiskCacheListener.prototype.EXPECTED_DATA = "this was pulled via h2";
PulledDiskCacheListener.prototype.readData = "";
PulledDiskCacheListener.prototype.onDataAvailable = function testOnDataAvailable(request, stream, off, cnt) { this.onDataAvailableFired = true; this.isHttp2Connection = checkIsHttp2(request); this.accum += cnt; this.readData += read_stream(stream, cnt);
};
PulledDiskCacheListener.prototype.onStopRequest = function testOnStopRequest(
request,
status
) { Assert.equal(this.EXPECTED_DATA, this.readData);
Http2CheckListener.prorotype.onStopRequest.call(this, request, status);
};
const DISK_CACHE_DATA = "this is from disk cache";
onStartRequest: function testOnStartRequest(request) { this.onStartRequestFired = true; if (!Components.isSuccessCode(request.status)) {
do_throw("Channel should have a success code! (" + request.status + ")");
}
onStopRequest: function testOnStopRequest(request, status) { Assert.ok(this.onStartRequestFired); Assert.ok(Components.isSuccessCode(status)); Assert.ok(this.onDataAvailableFired); Assert.equal(this.readData, DISK_CACHE_DATA);
evict_cache_entries("disk");
syncWithCacheIOThread(() => { // Now that we know the entry is out of the disk cache, check to make sure // we don't have this hiding in the push cache somewhere - if we do, it // didn't get cancelled, and we have a bug. var chan = makeHTTPChannel(
`https://localhost:${this.serverPort}/diskcache`
); var listener = new PulledDiskCacheListener();
listener.finish = this.finish;
chan.loadGroup = this.loadGroup;
chan.asyncOpen(listener);
});
},
};
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.16 Sekunden
(vorverarbeitet am 2026-09-28)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.