tor-browser

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

requests.js (5739B)


      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  createSelector,
      9 } = require("resource://devtools/client/shared/vendor/reselect.js");
     10 const {
     11  Filters,
     12  isFreetextMatch,
     13 } = require("resource://devtools/client/netmonitor/src/utils/filter-predicates.js");
     14 const {
     15  Sorters,
     16 } = require("resource://devtools/client/netmonitor/src/utils/sort-predicates.js");
     17 
     18 /**
     19 * Take clones into account when sorting.
     20 * If a request is a clone, use the original request for comparison.
     21 * If one of the compared request is a clone of the other, sort them next to each other.
     22 */
     23 function sortWithClones(requests, sorter, a, b) {
     24  const aId = a.id,
     25    bId = b.id;
     26 
     27  if (aId.endsWith("-clone")) {
     28    const aOrigId = aId.replace(/-clone$/, "");
     29    if (aOrigId === bId) {
     30      return +1;
     31    }
     32    a = requests.find(item => item.id === aOrigId);
     33  }
     34 
     35  if (bId.endsWith("-clone")) {
     36    const bOrigId = bId.replace(/-clone$/, "");
     37    if (bOrigId === aId) {
     38      return -1;
     39    }
     40    b = requests.find(item => item.id === bOrigId);
     41  }
     42 
     43  const defaultSorter = () => false;
     44  return sorter ? sorter(a, b) : defaultSorter;
     45 }
     46 
     47 const getActiveFilters = createSelector(
     48  state => state.filters.requestFilterTypes,
     49  requestFilterTypes =>
     50    Object.keys(requestFilterTypes)
     51      .filter(type => requestFilterTypes[type] && Filters[type])
     52      .map(type => Filters[type])
     53 );
     54 
     55 /**
     56 * Take clones into account when filtering. If a request is
     57 * a clone, it's not filtered out.
     58 */
     59 const getFilterWithCloneFn = createSelector(
     60  getActiveFilters,
     61  state => state.filters.requestFilterText,
     62  (activeFilters, requestFilterText) => {
     63    return r => {
     64      const isClone = r.id.endsWith("-clone");
     65      const matchesType = activeFilters.some(filter => filter(r));
     66      return (isClone || matchesType) && isFreetextMatch(r, requestFilterText);
     67    };
     68  }
     69 );
     70 
     71 const getTypeFilterFn = createSelector(
     72  getActiveFilters,
     73  activeFilters => r => activeFilters.some(filter => filter(r))
     74 );
     75 
     76 const getSortFn = createSelector(
     77  state => state.requests.requests,
     78  state => state.sort,
     79  (requests, sort) => {
     80    const sorter = Sorters[sort.type || "waterfall"];
     81    const ascending = sort.ascending ? +1 : -1;
     82    return (a, b) => ascending * sortWithClones(requests, sorter, a, b);
     83  }
     84 );
     85 
     86 const getSortedRequests = createSelector(
     87  state => state.requests.requests,
     88  getSortFn,
     89  (requests, sortFn) => [...requests].sort(sortFn)
     90 );
     91 
     92 const getDisplayedRequests = createSelector(
     93  state => state.requests.requests,
     94  getFilterWithCloneFn,
     95  getSortFn,
     96  (requests, filterFn, sortFn) => requests.filter(filterFn).sort(sortFn)
     97 );
     98 
     99 const getTypeFilteredRequests = createSelector(
    100  state => state.requests.requests,
    101  getTypeFilterFn,
    102  (requests, filterFn) => requests.filter(filterFn)
    103 );
    104 
    105 const getDisplayedRequestsSummary = createSelector(
    106  getDisplayedRequests,
    107  state => state.requests.lastEndedMs - state.requests.firstStartedMs,
    108  (requests, totalMs) => {
    109    if (requests.length === 0) {
    110      return { count: 0, bytes: 0, ms: 0 };
    111    }
    112 
    113    const totalBytes = requests.reduce(
    114      (totals, item) => {
    115        if (typeof item.contentSize == "number") {
    116          totals.contentSize += item.contentSize;
    117        }
    118 
    119        if (
    120          typeof item.transferredSize == "number" &&
    121          !(item.fromCache || item.fromServiceWorker || item.status === "304")
    122        ) {
    123          totals.transferredSize += item.transferredSize;
    124        }
    125 
    126        return totals;
    127      },
    128      { contentSize: 0, transferredSize: 0 }
    129    );
    130 
    131    return {
    132      count: requests.length,
    133      contentSize: totalBytes.contentSize,
    134      ms: totalMs,
    135      transferredSize: totalBytes.transferredSize,
    136    };
    137  }
    138 );
    139 
    140 const getSelectedRequest = createSelector(
    141  state => state.requests.requests,
    142  state => state.requests.selectedId,
    143  (requests, selectedId) =>
    144    selectedId ? requests.find(item => item.id === selectedId) : undefined
    145 );
    146 
    147 const isSelectedRequestVisible = createSelector(
    148  state => state.requests.selectedId,
    149  getDisplayedRequests,
    150  (selectedId, displayedRequests) =>
    151    displayedRequests.some(r => r.id === selectedId)
    152 );
    153 
    154 function getRequestById(state, id) {
    155  return state.requests.requests.find(item => item.id === id);
    156 }
    157 
    158 function getRequestByChannelId(state, channelId) {
    159  return [...state.requests.requests.values()].find(
    160    r => r.resourceId == channelId
    161  );
    162 }
    163 
    164 function getDisplayedRequestById(state, id) {
    165  return getDisplayedRequests(state).find(r => r.id === id);
    166 }
    167 
    168 /**
    169 * Returns the current recording boolean state (HTTP traffic is
    170 * monitored or not monitored)
    171 */
    172 function getRecordingState(state) {
    173  return state.requests.recording;
    174 }
    175 
    176 const getClickedRequest = createSelector(
    177  state => state.requests.requests,
    178  state => state.requests.clickedRequestId,
    179  (requests, clickedRequestId) =>
    180    requests.find(request => request.id == clickedRequestId)
    181 );
    182 
    183 /**
    184 * If a network override is set for the provided url, returns the override path.
    185 * Otherwise returns null.
    186 */
    187 function getOverriddenUrl(toolboxState, url) {
    188  return toolboxState.networkOverrides.mutableOverrides[url] || null;
    189 }
    190 
    191 function hasOverride(toolboxState) {
    192  return !!Object.keys(toolboxState.networkOverrides.mutableOverrides).length;
    193 }
    194 
    195 module.exports = {
    196  getClickedRequest,
    197  getDisplayedRequestById,
    198  getDisplayedRequests,
    199  getDisplayedRequestsSummary,
    200  getOverriddenUrl,
    201  getRecordingState,
    202  getRequestById,
    203  getRequestByChannelId,
    204  getSelectedRequest,
    205  getSortedRequests,
    206  getTypeFilteredRequests,
    207  hasOverride,
    208  isSelectedRequestVisible,
    209 };