tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

sort-predicates.js (9563B)


      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 "use strict";
      6 
      7 const {
      8  getAbbreviatedMimeType,
      9  getEndTime,
     10  getResponseTime,
     11  getResponseHeader,
     12  getStartTime,
     13  ipToLong,
     14 } = require("resource://devtools/client/netmonitor/src/utils/request-utils.js");
     15 const {
     16  RESPONSE_HEADERS,
     17 } = require("resource://devtools/client/netmonitor/src/constants.js");
     18 const {
     19  getUrlBaseName,
     20 } = require("resource://devtools/client/netmonitor/src/utils/request-utils.js");
     21 
     22 /**
     23 * Predicates used when sorting items.
     24 *
     25 * @param object first
     26 *        The first item used in the comparison.
     27 * @param object second
     28 *        The second item used in the comparison.
     29 * @return number
     30 *         <0 to sort first to a lower index than second
     31 *         =0 to leave first and second unchanged with respect to each other
     32 *         >0 to sort second to a lower index than first
     33 */
     34 
     35 function compareValues(first, second) {
     36  if (first === second) {
     37    return 0;
     38  }
     39  if (first === undefined) {
     40    return 1;
     41  }
     42  if (second === undefined) {
     43    return -1;
     44  }
     45  return first > second ? 1 : -1;
     46 }
     47 
     48 function waterfall(first, second) {
     49  const result = compareValues(first.startedMs, second.startedMs);
     50  return result || compareValues(first.id, second.id);
     51 }
     52 
     53 function priority(first, second) {
     54  const result = compareValues(first.priority, second.priority);
     55  return result || waterfall(first, second);
     56 }
     57 
     58 function status(first, second) {
     59  const result = compareValues(getStatusValue(first), getStatusValue(second));
     60  return result || waterfall(first, second);
     61 }
     62 
     63 function method(first, second) {
     64  const result = compareValues(first.method, second.method);
     65  return result || waterfall(first, second);
     66 }
     67 
     68 function file(first, second) {
     69  const firstUrl = first.urlDetails.baseNameWithQuery.toLowerCase();
     70  const secondUrl = second.urlDetails.baseNameWithQuery.toLowerCase();
     71  const result = compareValues(firstUrl, secondUrl);
     72  return result || waterfall(first, second);
     73 }
     74 
     75 function path(first, second) {
     76  const firstUrl = first.urlDetails.path.toLowerCase();
     77  const secondUrl = second.urlDetails.path.toLowerCase();
     78  const result = compareValues(firstUrl, secondUrl);
     79  return result || waterfall(first, second);
     80 }
     81 
     82 function url(first, second) {
     83  const firstUrl = first.url.toLowerCase();
     84  const secondUrl = second.url.toLowerCase();
     85  const result = compareValues(firstUrl, secondUrl);
     86  return result || waterfall(first, second);
     87 }
     88 
     89 function protocol(first, second) {
     90  const result = compareValues(first.httpVersion, second.httpVersion);
     91  return result || waterfall(first, second);
     92 }
     93 
     94 function scheme(first, second) {
     95  const result = compareValues(
     96    first.urlDetails.scheme,
     97    second.urlDetails.scheme
     98  );
     99  return result || waterfall(first, second);
    100 }
    101 
    102 function startTime(first, second) {
    103  const result = compareValues(getStartTime(first), getStartTime(second));
    104  return result || waterfall(first, second);
    105 }
    106 
    107 function endTime(first, second) {
    108  const result = compareValues(getEndTime(first), getEndTime(second));
    109  return result || waterfall(first, second);
    110 }
    111 
    112 function responseTime(first, second) {
    113  const result = compareValues(getResponseTime(first), getResponseTime(second));
    114  return result || waterfall(first, second);
    115 }
    116 
    117 function duration(first, second) {
    118  const result = compareValues(first.totalTime, second.totalTime);
    119  return result || waterfall(first, second);
    120 }
    121 
    122 function latency(first, second) {
    123  const { eventTimings: firstEventTimings = { timings: {} } } = first;
    124  const { eventTimings: secondEventTimings = { timings: {} } } = second;
    125  const result = compareValues(
    126    firstEventTimings.timings.wait,
    127    secondEventTimings.timings.wait
    128  );
    129  return result || waterfall(first, second);
    130 }
    131 
    132 function compareHeader(header, first, second) {
    133  const firstValue = getResponseHeader(first, header) || "";
    134  const secondValue = getResponseHeader(second, header) || "";
    135 
    136  let result;
    137 
    138  switch (header) {
    139    case "Content-Length": {
    140      result = compareValues(
    141        parseInt(firstValue, 10) || 0,
    142        parseInt(secondValue, 10) || 0
    143      );
    144      break;
    145    }
    146    case "Last-Modified": {
    147      result = compareValues(
    148        new Date(firstValue).valueOf() || -1,
    149        new Date(secondValue).valueOf() || -1
    150      );
    151      break;
    152    }
    153    default: {
    154      result = compareValues(firstValue, secondValue);
    155      break;
    156    }
    157  }
    158 
    159  return result || waterfall(first, second);
    160 }
    161 
    162 const responseHeaders = RESPONSE_HEADERS.reduce(
    163  (acc, header) =>
    164    Object.assign(acc, {
    165      [header]: (first, second) => compareHeader(header, first, second),
    166    }),
    167  {}
    168 );
    169 
    170 function domain(first, second) {
    171  const firstDomain = first.urlDetails.host.toLowerCase();
    172  const secondDomain = second.urlDetails.host.toLowerCase();
    173  const result = compareValues(firstDomain, secondDomain);
    174  return result || waterfall(first, second);
    175 }
    176 
    177 function remoteip(first, second) {
    178  const firstIP = ipToLong(first.remoteAddress);
    179  const secondIP = ipToLong(second.remoteAddress);
    180  const result = compareValues(firstIP, secondIP);
    181  return result || waterfall(first, second);
    182 }
    183 
    184 function cause(first, second) {
    185  const firstCause = first.cause.type;
    186  const secondCause = second.cause.type;
    187  const result = compareValues(firstCause, secondCause);
    188  return result || waterfall(first, second);
    189 }
    190 
    191 function initiator(first, second) {
    192  const firstCause = first.cause.type;
    193  const secondCause = second.cause.type;
    194 
    195  let firstInitiator = "";
    196  let firstInitiatorLineNumber = 0;
    197 
    198  if (first.cause.lastFrame) {
    199    firstInitiator = getUrlBaseName(first.cause.lastFrame.filename);
    200    firstInitiatorLineNumber = first.cause.lastFrame.lineNumber;
    201  }
    202 
    203  let secondInitiator = "";
    204  let secondInitiatorLineNumber = 0;
    205 
    206  if (second.cause.lastFrame) {
    207    secondInitiator = getUrlBaseName(second.cause.lastFrame.filename);
    208    secondInitiatorLineNumber = second.cause.lastFrame.lineNumber;
    209  }
    210 
    211  let result;
    212  // if both initiators don't have a stack trace, compare their causes
    213  if (!firstInitiator && !secondInitiator) {
    214    result = compareValues(firstCause, secondCause);
    215  } else if (!firstInitiator || !secondInitiator) {
    216    // if one initiator doesn't have a stack trace but the other does, former should precede the latter
    217    result = compareValues(firstInitiatorLineNumber, secondInitiatorLineNumber);
    218  } else {
    219    result = compareValues(firstInitiator, secondInitiator);
    220    if (result === 0) {
    221      result = compareValues(
    222        firstInitiatorLineNumber,
    223        secondInitiatorLineNumber
    224      );
    225    }
    226  }
    227 
    228  return result || waterfall(first, second);
    229 }
    230 
    231 function setCookies(first, second) {
    232  let { responseCookies: firstResponseCookies = { cookies: [] } } = first;
    233  let { responseCookies: secondResponseCookies = { cookies: [] } } = second;
    234  firstResponseCookies = firstResponseCookies.cookies || firstResponseCookies;
    235  secondResponseCookies =
    236    secondResponseCookies.cookies || secondResponseCookies;
    237  const result = compareValues(
    238    firstResponseCookies.length,
    239    secondResponseCookies.length
    240  );
    241  return result || waterfall(first, second);
    242 }
    243 
    244 function cookies(first, second) {
    245  let { requestCookies: firstRequestCookies = { cookies: [] } } = first;
    246  let { requestCookies: secondRequestCookies = { cookies: [] } } = second;
    247  firstRequestCookies = firstRequestCookies.cookies || firstRequestCookies;
    248  secondRequestCookies = secondRequestCookies.cookies || secondRequestCookies;
    249  const result = compareValues(
    250    firstRequestCookies.length,
    251    secondRequestCookies.length
    252  );
    253  return result || waterfall(first, second);
    254 }
    255 
    256 function type(first, second) {
    257  const firstType = getAbbreviatedMimeType(first.mimeType);
    258  const secondType = getAbbreviatedMimeType(second.mimeType);
    259  const result = compareValues(firstType, secondType);
    260  return result || waterfall(first, second);
    261 }
    262 
    263 function getStatusValue(item) {
    264  let value;
    265  if (item.blockedReason) {
    266    value = typeof item.blockedReason == "number" ? -item.blockedReason : -1000;
    267  } else if (item.status == null) {
    268    value = -2;
    269  } else {
    270    value = item.status;
    271  }
    272  return value;
    273 }
    274 
    275 function getTransferedSizeValue(item) {
    276  let value;
    277  if (item.blockedReason) {
    278    // Also properly group/sort various blocked reasons.
    279    value = typeof item.blockedReason == "number" ? -item.blockedReason : -1000;
    280  } else if (item.fromCache || item.status === "304") {
    281    value = -2;
    282  } else if (item.fromServiceWorker) {
    283    value = -3;
    284  } else if (typeof item.transferredSize == "number") {
    285    value = item.transferredSize;
    286    if (item.isRacing && typeof item.isRacing == "boolean") {
    287      value = -4;
    288    }
    289  } else if (item.transferredSize === null) {
    290    value = -5;
    291  }
    292  return value;
    293 }
    294 
    295 function transferred(first, second) {
    296  const result = compareValues(
    297    getTransferedSizeValue(first),
    298    getTransferedSizeValue(second)
    299  );
    300  return result || waterfall(first, second);
    301 }
    302 
    303 function contentSize(first, second) {
    304  const result = compareValues(first.contentSize, second.contentSize);
    305  return result || waterfall(first, second);
    306 }
    307 
    308 const sorters = {
    309  status,
    310  method,
    311  domain,
    312  file,
    313  path,
    314  protocol,
    315  scheme,
    316  cookies,
    317  setCookies,
    318  remoteip,
    319  cause,
    320  initiator,
    321  type,
    322  transferred,
    323  contentSize,
    324  startTime,
    325  endTime,
    326  responseTime,
    327  duration,
    328  latency,
    329  waterfall,
    330  url,
    331  priority,
    332 };
    333 exports.Sorters = Object.assign(sorters, responseHeaders);