Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  moz-http2.js   Sprache: JAVA

 
/* 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 { spawn } = 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) {
  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(thisthis.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);
    }
  },
};

var resetLater = function () {};
resetLater.prototype = {
  resp: null,

  onTimeout: function onTimeout() {
    this.resp.stream.reset("HTTP_1_1_REQUIRED");
  },
};

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;
    }

    let answers = [];
    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")
      ) {
        // add padding to the response, because the client must be able ignore it
        answers.push({
          name: ".",
          type: "PADDING",
          data: Buffer.from(
            // PADDING_PADDING_PADDING
            "50414444494e475f50414444494e475f50414444494e47",
            "hex"
          ),
        });
        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;
    }

    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 = '


                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge