From 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 03:47:29 +0200 Subject: Adding upstream version 115.8.0esr. Signed-off-by: Daniel Baumann --- testing/xpcshell/moz-http2/http2-cert.key | 28 + testing/xpcshell/moz-http2/http2-cert.key.keyspec | 1 + testing/xpcshell/moz-http2/http2-cert.pem | 19 + testing/xpcshell/moz-http2/http2-cert.pem.certspec | 4 + testing/xpcshell/moz-http2/moz-http2-child.js | 33 + testing/xpcshell/moz-http2/moz-http2.js | 1920 ++++++++++++++++++++ testing/xpcshell/moz-http2/proxy-cert.key | 28 + testing/xpcshell/moz-http2/proxy-cert.key.keyspec | 1 + testing/xpcshell/moz-http2/proxy-cert.pem | 19 + testing/xpcshell/moz-http2/proxy-cert.pem.certspec | 4 + 10 files changed, 2057 insertions(+) create mode 100644 testing/xpcshell/moz-http2/http2-cert.key create mode 100644 testing/xpcshell/moz-http2/http2-cert.key.keyspec create mode 100644 testing/xpcshell/moz-http2/http2-cert.pem create mode 100644 testing/xpcshell/moz-http2/http2-cert.pem.certspec create mode 100644 testing/xpcshell/moz-http2/moz-http2-child.js create mode 100644 testing/xpcshell/moz-http2/moz-http2.js create mode 100644 testing/xpcshell/moz-http2/proxy-cert.key create mode 100644 testing/xpcshell/moz-http2/proxy-cert.key.keyspec create mode 100644 testing/xpcshell/moz-http2/proxy-cert.pem create mode 100644 testing/xpcshell/moz-http2/proxy-cert.pem.certspec (limited to 'testing/xpcshell/moz-http2') diff --git a/testing/xpcshell/moz-http2/http2-cert.key b/testing/xpcshell/moz-http2/http2-cert.key new file mode 100644 index 0000000000..09e044f5e0 --- /dev/null +++ b/testing/xpcshell/moz-http2/http2-cert.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6iFGoRI4W1kH9 +braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEI +eqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6 +iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Za +qn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7 +LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs +2hgKNe2NAgMBAAECggEBAJ7LzjhhpFTsseD+j4XdQ8kvWCXOLpl4hNDhqUnaosWs +VZskBFDlrJ/gw+McDu+mUlpl8MIhlABO4atGPd6e6CKHzJPnRqkZKcXmrD2IdT9s +JbpZeec+XY+yOREaPNq4pLDN9fnKsF8SM6ODNcZLVWBSXn47kq18dQTPHcfLAFeI +r8vh6Pld90AqFRUw1YCDRoZOs3CqeZVqWHhiy1M3kTB/cNkcltItABppAJuSPGgz +iMnzbLm16+ZDAgQceNkIIGuHAJy4yrrK09vbJ5L7kRss9NtmA1hb6a4Mo7jmQXqg +SwbkcOoaO1gcoDpngckxW2KzDmAR8iRyWUbuxXxtlEECgYEA3W4dT//r9o2InE0R +TNqqnKpjpZN0KGyKXCmnF7umA3VkTVyqZ0xLi8cyY1hkYiDkVQ12CKwn1Vttt0+N +gSfvj6CQmLaRR94GVXNEfhg9Iv59iFrOtRPZWB3V4HwakPXOCHneExNx7O/JznLp +xD3BJ9I4GQ3oEXc8pdGTAfSMdCsCgYEA16dz2evDgKdn0v7Ak0rU6LVmckB3Gs3r +ta15b0eP7E1FmF77yVMpaCicjYkQL63yHzTi3UlA66jAnW0fFtzClyl3TEMnXpJR +3b5JCeH9O/Hkvt9Go5uLODMo70rjuVuS8gcK8myefFybWH/t3gXo59hspXiG+xZY +EKd7mEW8MScCgYEAlkcrQaYQwK3hryJmwWAONnE1W6QtS1oOtOnX6zWBQAul3RMs +2xpekyjHu8C7sBVeoZKXLt+X0SdR2Pz2rlcqMLHqMJqHEt1OMyQdse5FX8CT9byb +WS11bmYhR08ywHryL7J100B5KzK6JZC7smGu+5WiWO6lN2VTFb6cJNGRmS0CgYAo +tFCnp1qFZBOyvab3pj49lk+57PUOOCPvbMjo+ibuQT+LnRIFVA8Su+egx2got7pl +rYPMpND+KiIBFOGzXQPVqFv+Jwa9UPzmz83VcbRspiG47UfWBbvnZbCqSgZlrCU2 +TaIBVAMuEgS4VZ0+NPtbF3yaVv+TUQpaSmKHwVHeLQKBgCgGe5NVgB0u9S36ltit +tYlnPPjuipxv9yruq+nva+WKT0q/BfeIlH3IUf2qNFQhR6caJGv7BU7naqNGq80m +ks/J5ExR5vBpxzXgc7oBn2pyFJYckbJoccrqv48GRBigJpDjmo1f8wZ7fNt/ULH1 +NBinA5ZsT8d0v3QCr2xDJH9D +-----END PRIVATE KEY----- diff --git a/testing/xpcshell/moz-http2/http2-cert.key.keyspec b/testing/xpcshell/moz-http2/http2-cert.key.keyspec new file mode 100644 index 0000000000..4ad96d5159 --- /dev/null +++ b/testing/xpcshell/moz-http2/http2-cert.key.keyspec @@ -0,0 +1 @@ +default diff --git a/testing/xpcshell/moz-http2/http2-cert.pem b/testing/xpcshell/moz-http2/http2-cert.pem new file mode 100644 index 0000000000..1f89de1a45 --- /dev/null +++ b/testing/xpcshell/moz-http2/http2-cert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDEzCCAfugAwIBAgIUCTTdK3eSofAM6mNwAi4Z4YUn8WEwDQYJKoZIhvcNAQEL +BQAwGTEXMBUGA1UEAwwOIEhUVFAyIFRlc3QgQ0EwIhgPMjAxNzAxMDEwMDAwMDBa +GA8yMDI3MDEwMTAwMDAwMFowGzEZMBcGA1UEAwwQIEhUVFAyIFRlc3QgQ2VydDCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9 +PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3 +HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3Dg +Dw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7 +EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SK +lWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0C +AwEAAaNNMEswSQYDVR0RBEIwQIIJbG9jYWxob3N0gg9mb28uZXhhbXBsZS5jb22C +EGFsdDEuZXhhbXBsZS5jb22CEGFsdDIuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQEL +BQADggEBAE5aEiXOkvEYeWpMhkGheeeaKwgr44qiWJKC5N/8t+NprB3vNCbTMzE9 +09iWQh9EXbwMjMQ8H0uZwedek2sryxsTzxsdTC5qmEtxs/kbf0rTNUwQDjGHvzMk +gO+ULESdLTcIFJ57olHaZaXtPGm2ELJAOiEpsYFTafmCEPXZ/b+UkGsSkuVLSOIA +ClaIJgjff/ucvCvRwl79GzGDCoh3qpqhvxQpC/Fcdz1iQDYEVAmjgUrYJe1lTfj8 +ZozM1WIq8fQ3SCXTJK82CnX818tJio2PWq3uzb9vhpuxJJif7WoMP88Jpdh8zcEb +YL15XPzhQMyor2p6XfwNI3J6347fd7U= +-----END CERTIFICATE----- diff --git a/testing/xpcshell/moz-http2/http2-cert.pem.certspec b/testing/xpcshell/moz-http2/http2-cert.pem.certspec new file mode 100644 index 0000000000..69b3bc83e6 --- /dev/null +++ b/testing/xpcshell/moz-http2/http2-cert.pem.certspec @@ -0,0 +1,4 @@ +issuer: HTTP2 Test CA +subject: HTTP2 Test Cert +validity:20170101-20270101 +extension:subjectAlternativeName:localhost,foo.example.com,alt1.example.com,alt2.example.com diff --git a/testing/xpcshell/moz-http2/moz-http2-child.js b/testing/xpcshell/moz-http2/moz-http2-child.js new file mode 100644 index 0000000000..c8f5d99669 --- /dev/null +++ b/testing/xpcshell/moz-http2/moz-http2-child.js @@ -0,0 +1,33 @@ +/* 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/. */ + +/* eslint-env node */ + +function sendBackResponse(evalResult, e) { + const output = { result: evalResult, error: "", errorStack: "" }; + if (e) { + output.error = e.toString(); + output.errorStack = e.stack; + } + process.send(output); +} + +process.on("message", msg => { + const code = msg.code; + let evalResult = null; + try { + // eslint-disable-next-line no-eval + evalResult = eval(code); + if (evalResult instanceof Promise) { + evalResult + .then(x => sendBackResponse(x)) + .catch(e => sendBackResponse(undefined, e)); + return; + } + } catch (e) { + sendBackResponse(undefined, e); + return; + } + sendBackResponse(evalResult); +}); diff --git a/testing/xpcshell/moz-http2/moz-http2.js b/testing/xpcshell/moz-http2/moz-http2.js new file mode 100644 index 0000000000..334ccd8e1c --- /dev/null +++ b/testing/xpcshell/moz-http2/moz-http2.js @@ -0,0 +1,1920 @@ +/* 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/. */ + +// This module is the stateful server side of test_http2.js and is meant +// to have node be restarted in between each invocation + +/* eslint-env node */ + +var node_http2_root = "../node-http2"; +if (process.env.NODE_HTTP2_ROOT) { + node_http2_root = process.env.NODE_HTTP2_ROOT; +} +var http2 = require(node_http2_root); +var fs = require("fs"); +var url = require("url"); +var crypto = require("crypto"); +const dnsPacket = require(`${node_http2_root}/../dns-packet`); +const ip = require(`${node_http2_root}/../node_ip`); +const { fork } = require("child_process"); +const path = require("path"); +const zlib = require("zlib"); + +// Hook into the decompression code to log the decompressed name-value pairs +var compression_module = node_http2_root + "/lib/protocol/compressor"; +var http2_compression = require(compression_module); +var HeaderSetDecompressor = http2_compression.HeaderSetDecompressor; +var originalRead = HeaderSetDecompressor.prototype.read; +var lastDecompressor; +var decompressedPairs; +HeaderSetDecompressor.prototype.read = function () { + if (this != lastDecompressor) { + lastDecompressor = this; + decompressedPairs = []; + } + var pair = originalRead.apply(this, arguments); + if (pair) { + decompressedPairs.push(pair); + } + return pair; +}; + +var connection_module = node_http2_root + "/lib/protocol/connection"; +var http2_connection = require(connection_module); +var Connection = http2_connection.Connection; +var originalClose = Connection.prototype.close; +Connection.prototype.close = function (error, lastId) { + if (lastId !== undefined) { + this._lastIncomingStream = lastId; + } + + originalClose.apply(this, arguments); +}; + +var framer_module = node_http2_root + "/lib/protocol/framer"; +var http2_framer = require(framer_module); +var Serializer = http2_framer.Serializer; +var originalTransform = Serializer.prototype._transform; +var newTransform = function (frame, encoding, done) { + if (frame.type == "DATA") { + // Insert our empty DATA frame + const emptyFrame = {}; + emptyFrame.type = "DATA"; + emptyFrame.data = Buffer.alloc(0); + emptyFrame.flags = []; + emptyFrame.stream = frame.stream; + var buffers = []; + Serializer.DATA(emptyFrame, buffers); + Serializer.commonHeader(emptyFrame, buffers); + for (var i = 0; i < buffers.length; i++) { + this.push(buffers[i]); + } + + // Reset to the original version for later uses + Serializer.prototype._transform = originalTransform; + } + originalTransform.apply(this, arguments); +}; + +function getHttpContent(pathName) { + var content = + "" + + "" + + "HOORAY!" + + // 'You Win!' used in tests to check we reached this server + "You Win! (by requesting" + + pathName + + ")" + + ""; + return content; +} + +function generateContent(size) { + var content = ""; + for (var i = 0; i < size; i++) { + content += "0"; + } + return content; +} + +/* This takes care of responding to the multiplexed request for us */ +var m = { + mp1res: null, + mp2res: null, + buf: null, + mp1start: 0, + mp2start: 0, + + checkReady() { + if (this.mp1res != null && this.mp2res != null) { + this.buf = generateContent(30 * 1024); + this.mp1start = 0; + this.mp2start = 0; + this.send(this.mp1res, 0); + setTimeout(this.send.bind(this, this.mp2res, 0), 5); + } + }, + + send(res, start) { + var end = Math.min(start + 1024, this.buf.length); + var content = this.buf.substring(start, end); + res.write(content); + if (end < this.buf.length) { + setTimeout(this.send.bind(this, res, end), 10); + } else { + // Clear these variables so we can run the test again with --verify + if (res == this.mp1res) { + this.mp1res = null; + } else { + this.mp2res = null; + } + res.end(); + } + }, +}; + +var runlater = function () {}; +runlater.prototype = { + req: null, + resp: null, + fin: true, + + onTimeout: function onTimeout() { + this.resp.writeHead(200); + if (this.fin) { + this.resp.end("It's all good 750ms."); + } + }, +}; + +var runConnectLater = function () {}; +runConnectLater.prototype = { + req: null, + resp: null, + connect: false, + + onTimeout: function onTimeout() { + if (this.connect) { + this.resp.writeHead(200); + this.connect = true; + setTimeout(executeRunLaterCatchError, 50, this); + } else { + this.resp.end("HTTP/1.1 200\n\r\n\r"); + } + }, +}; + +var moreData = function () {}; +moreData.prototype = { + req: null, + resp: null, + iter: 3, + + onTimeout: function onTimeout() { + // 1mb of data + const content = generateContent(1024 * 1024); + this.resp.write(content); // 1mb chunk + this.iter--; + if (!this.iter) { + this.resp.end(); + } else { + setTimeout(executeRunLater, 1, this); + } + }, +}; + +function executeRunLater(arg) { + arg.onTimeout(); +} + +function executeRunLaterCatchError(arg) { + arg.onTimeout(); +} + +var h11required_conn = null; +var h11required_header = "yes"; +var didRst = false; +var rstConnection = null; +var illegalheader_conn = null; + +var gDoHPortsLog = []; +var gDoHNewConnLog = {}; +var gDoHRequestCount = 0; + +// eslint-disable-next-line complexity +function handleRequest(req, res) { + var u = ""; + if (req.url != undefined) { + u = url.parse(req.url, true); + } + var content = getHttpContent(u.pathname); + var push, push1, push1a, push2, push3; + + // PushService tests. + var pushPushServer1, pushPushServer2, pushPushServer3, pushPushServer4; + + function createCNameContent(payload) { + let packet = dnsPacket.decode(payload); + if ( + packet.questions[0].name == "cname.example.com" && + packet.questions[0].type == "A" + ) { + return dnsPacket.encode({ + id: 0, + type: "response", + flags: dnsPacket.RECURSION_DESIRED, + questions: [{ name: packet.questions[0].name, type: "A", class: "IN" }], + answers: [ + { + name: packet.questions[0].name, + ttl: 55, + type: "CNAME", + flush: false, + data: "pointing-elsewhere.example.com", + }, + ], + }); + } + if ( + packet.questions[0].name == "pointing-elsewhere.example.com" && + packet.questions[0].type == "A" + ) { + return dnsPacket.encode({ + id: 0, + type: "response", + flags: dnsPacket.RECURSION_DESIRED, + questions: [{ name: packet.questions[0].name, type: "A", class: "IN" }], + answers: [ + { + name: packet.questions[0].name, + ttl: 55, + type: "A", + flush: false, + data: "99.88.77.66", + }, + ], + }); + } + + return dnsPacket.encode({ + id: 0, + type: "response", + flags: dnsPacket.RECURSION_DESIRED | dnsPacket.rcodes.toRcode("NXDOMAIN"), + questions: [ + { + name: packet.questions[0].name, + type: packet.questions[0].type, + class: "IN", + }, + ], + answers: [], + }); + } + + function createCNameARecord() { + // test23 asks for cname-a.example.com + // this responds with a CNAME to here.example.com *and* an A record + // for here.example.com + let rContent; + + rContent = Buffer.from( + "0000" + + "0100" + + "0001" + // QDCOUNT + "0002" + // ANCOUNT + "00000000" + // NSCOUNT + ARCOUNT + "07636E616D652d61" + // cname-a + "076578616D706C6503636F6D00" + // .example.com + "00010001" + // question type (A) + question class (IN) + // answer record 1 + "C00C" + // name pointer to cname-a.example.com + "0005" + // type (CNAME) + "0001" + // class + "00000037" + // TTL + "0012" + // RDLENGTH + "0468657265" + // here + "076578616D706C6503636F6D00" + // .example.com + // answer record 2, the A entry for the CNAME above + "0468657265" + // here + "076578616D706C6503636F6D00" + // .example.com + "0001" + // type (A) + "0001" + // class + "00000037" + // TTL + "0004" + // RDLENGTH + "09080706", // IPv4 address + "hex" + ); + + return rContent; + } + + function responseType(packet, responseIP) { + if ( + !!packet.questions.length && + packet.questions[0].name == "confirm.example.com" && + packet.questions[0].type == "NS" + ) { + return "NS"; + } + + return ip.isV4Format(responseIP) ? "A" : "AAAA"; + } + + function handleAuth() { + // There's a Set-Cookie: header in the response for "/dns" , which this + // request subsequently would include if the http channel wasn't + // anonymous. Thus, if there's a cookie in this request, we know Firefox + // mishaved. If there's not, we're fine. + if (req.headers.cookie) { + res.writeHead(403); + res.end("cookie for me, not for you"); + return false; + } + if (req.headers.authorization != "user:password") { + res.writeHead(401); + res.end("bad boy!"); + return false; + } + + return true; + } + + function createDNSAnswer(response, packet, responseIP, requestPayload) { + // This shuts down the connection so we can test if the client reconnects + if (packet.questions.length && packet.questions[0].name == "closeme.com") { + response.stream.connection.close("INTERNAL_ERROR", response.stream.id); + return null; + } + + if (packet.questions.length && packet.questions[0].name.endsWith(".pd")) { + // Bug 1543811: test edns padding extension. Return whether padding was + // included via the first half of the ip address (1.1 vs 2.2) and the + // size of the request in the second half of the ip address allowing to + // verify that the correct amount of padding was added. + if ( + !!packet.additionals.length && + packet.additionals[0].type == "OPT" && + packet.additionals[0].options.some(o => o.type === "PADDING") + ) { + responseIP = + "1.1." + + ((requestPayload.length >> 8) & 0xff) + + "." + + (requestPayload.length & 0xff); + } else { + responseIP = + "2.2." + + ((requestPayload.length >> 8) & 0xff) + + "." + + (requestPayload.length & 0xff); + } + } + + if (u.query.corruptedAnswer) { + // DNS response header is 12 bytes, we check for this minimum length + // at the start of decoding so this is the simplest way to force + // a decode error. + return "\xFF\xFF\xFF\xFF"; + } + + // Because we send two TRR requests (A and AAAA), skip the first two + // requests when testing retry. + if (u.query.retryOnDecodeFailure && gDoHRequestCount < 2) { + gDoHRequestCount++; + return "\xFF\xFF\xFF\xFF"; + } + + function responseData() { + if ( + !!packet.questions.length && + packet.questions[0].name == "confirm.example.com" && + packet.questions[0].type == "NS" + ) { + return "ns.example.com"; + } + + return responseIP; + } + + let answers = []; + if ( + responseIP != "none" && + responseType(packet, responseIP) == packet.questions[0].type + ) { + answers.push({ + name: u.query.hostname ? u.query.hostname : packet.questions[0].name, + ttl: 55, + type: responseType(packet, responseIP), + flush: false, + data: responseData(), + }); + } + + // for use with test_dns_by_type_resolve.js + if (packet.questions[0].type == "TXT") { + answers.push({ + name: packet.questions[0].name, + type: packet.questions[0].type, + ttl: 55, + class: "IN", + flush: false, + data: Buffer.from( + "62586B67646D39705932556761584D6762586B676347467A63336476636D513D", + "hex" + ), + }); + } + + if (u.query.cnameloop) { + answers.push({ + name: "cname.example.com", + type: "CNAME", + ttl: 55, + class: "IN", + flush: false, + data: "pointing-elsewhere.example.com", + }); + } + + if (req.headers["accept-language"] || req.headers["user-agent"]) { + // If we get this header, don't send back any response. This should + // cause the tests to fail. This is easier then actually sending back + // the header value into test_trr.js + answers = []; + } + + let buf = dnsPacket.encode({ + type: "response", + id: packet.id, + flags: dnsPacket.RECURSION_DESIRED, + questions: packet.questions, + answers, + }); + + return buf; + } + + function getDelayFromPacket(packet, type) { + let delay = 0; + if (packet.questions[0].type == "A") { + delay = parseInt(u.query.delayIPv4); + } else if (packet.questions[0].type == "AAAA") { + delay = parseInt(u.query.delayIPv6); + } + + if (u.query.slowConfirm && type == "NS") { + delay += 1000; + } + + return delay; + } + + function writeDNSResponse(response, buf, delay, contentType) { + function writeResponse(resp, buffer) { + resp.setHeader("Set-Cookie", "trackyou=yes; path=/; max-age=100000;"); + resp.setHeader("Content-Type", contentType); + if (req.headers["accept-encoding"].includes("gzip")) { + zlib.gzip(buffer, function (err, result) { + resp.setHeader("Content-Encoding", "gzip"); + resp.setHeader("Content-Length", result.length); + try { + resp.writeHead(200); + resp.end(result); + } catch (e) { + // connection was closed by the time we started writing. + } + }); + } else { + const output = Buffer.from(buffer, "utf-8"); + resp.setHeader("Content-Length", output.length); + try { + resp.writeHead(200); + resp.write(output); + resp.end(""); + } catch (e) { + // connection was closed by the time we started writing. + } + } + } + + if (delay) { + setTimeout( + arg => { + writeResponse(arg[0], arg[1]); + }, + delay, + [response, buf] + ); + return; + } + + writeResponse(response, buf); + } + + if (req.httpVersionMajor === 2) { + res.setHeader("X-Connection-Http2", "yes"); + res.setHeader("X-Http2-StreamId", "" + req.stream.id); + } else { + res.setHeader("X-Connection-Http2", "no"); + } + + if (u.pathname === "/exit") { + res.setHeader("Content-Type", "text/plain"); + res.setHeader("Connection", "close"); + res.writeHead(200); + res.end("ok"); + process.exit(); + } + + if (req.method == "CONNECT") { + if (req.headers.host == "illegalhpacksoft.example.com:80") { + illegalheader_conn = req.stream.connection; + res.setHeader("Content-Type", "text/html"); + res.setHeader("x-softillegalhpack", "true"); + res.writeHead(200); + res.end(content); + return; + } else if (req.headers.host == "illegalhpackhard.example.com:80") { + res.setHeader("Content-Type", "text/html"); + res.setHeader("x-hardillegalhpack", "true"); + res.writeHead(200); + res.end(content); + return; + } else if (req.headers.host == "750.example.com:80") { + // This response will mock a response through a proxy to a HTTP server. + // After 750ms , a 200 response for the proxy will be sent then + // after additional 50ms a 200 response for the HTTP GET request. + let rl = new runConnectLater(); + rl.req = req; + rl.resp = res; + setTimeout(executeRunLaterCatchError, 750, rl); + return; + } else if (req.headers.host == "h11required.com:80") { + if (req.httpVersionMajor === 2) { + res.stream.reset("HTTP_1_1_REQUIRED"); + } + return; + } + } else if (u.pathname === "/750ms") { + let rl = new runlater(); + rl.req = req; + rl.resp = res; + setTimeout(executeRunLater, 750, rl); + return; + } else if (u.pathname === "/750msNoData") { + let rl = new runlater(); + rl.req = req; + rl.resp = res; + rl.fin = false; + setTimeout(executeRunLater, 750, rl); + return; + } else if (u.pathname === "/multiplex1" && req.httpVersionMajor === 2) { + res.setHeader("Content-Type", "text/plain"); + res.writeHead(200); + m.mp1res = res; + m.checkReady(); + return; + } else if (u.pathname === "/multiplex2" && req.httpVersionMajor === 2) { + res.setHeader("Content-Type", "text/plain"); + res.writeHead(200); + m.mp2res = res; + m.checkReady(); + return; + } else if (u.pathname === "/header") { + var val = req.headers["x-test-header"]; + if (val) { + res.setHeader("X-Received-Test-Header", val); + } + } else if (u.pathname === "/doubleheader") { + res.setHeader("Content-Type", "text/html"); + res.writeHead(200); + res.write(content); + res.writeHead(200); + res.end(); + return; + } else if (u.pathname === "/cookie_crumbling") { + res.setHeader("X-Received-Header-Pairs", JSON.stringify(decompressedPairs)); + } else if (u.pathname === "/push") { + push = res.push("/push.js"); + push.writeHead(200, { + "content-type": "application/javascript", + pushed: "yes", + "content-length": 11, + "X-Connection-Http2": "yes", + }); + push.end("// comments"); + content = '