New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

resourcetiming-compression

Package Overview
Dependencies
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

resourcetiming-compression - npm Package Compare versions

Comparing version 0.2.2 to 0.3.0

27

package.json

@@ -6,3 +6,3 @@ {

"author": "Nic Jansma",
"version": "0.2.2",
"version": "0.3.0",
"repository": {

@@ -25,19 +25,20 @@ "type": "git",

"gulp-eslint": "^2.0.0",
"gulp-mocha": "^1.1.1",
"gulp-mocha": "^2.2.0",
"gulp-rename": "^1.2.0",
"gulp-spawn-mocha": "^2.2.2",
"gulp-uglify": "^1.0.1",
"karma": "^0.12.31",
"karma-chrome-launcher": "^0.1.5",
"karma-coverage": "^0.2.6",
"karma": "^0.13.22",
"karma-chrome-launcher": "^1.0.1",
"karma-coverage": "^1.0.0",
"karma-expect": "^1.1.0",
"karma-firefox-launcher": "^0.1.4",
"karma-ie-launcher": "^0.1.5",
"karma-mocha": "^0.1.9",
"karma-opera-launcher": "^0.1.0",
"karma-phantomjs-launcher": "^0.1.4",
"karma-safari-launcher": "^0.1.1",
"karma-tap-reporter": "0.0.3",
"mocha": "^2.0.1"
"karma-firefox-launcher": "^1.0.0",
"karma-ie-launcher": "^1.0.0",
"karma-mocha": "^1.0.1",
"karma-opera-launcher": "^1.0.0",
"karma-phantomjs-launcher": "^1.0.0",
"karma-safari-launcher": "^1.0.0",
"karma-tap-reporter": "0.0.6",
"mocha": "^2.0.1",
"phantomjs-prebuilt": "^2.1.7"
}
}
# resourcetiming-compression.js
v0.2.2
v0.3.0

@@ -35,9 +35,9 @@ [http://nicj.net](http://nicj.net)

__Development:__ [resourcetiming-compression.js](https://github.com/nicjansma/resourcetiming-compression.js/raw/master/src/resourcetiming-compression.js) - 15kb
__Development:__ [resourcetiming-compression.js](https://github.com/nicjansma/resourcetiming-compression.js/raw/master/src/resourcetiming-compression.js) - 30kb
__Production:__ [resourcetiming-compression.min.js](https://github.com/nicjansma/resourcetiming-compression.js/raw/master/dist/resourcetiming-compression.min.js) - 4.5kb (minified / gzipped)
__Production:__ [resourcetiming-compression.min.js](https://github.com/nicjansma/resourcetiming-compression.js/raw/master/dist/resourcetiming-compression.min.js) - 2.4kb (minified / gzipped)
__Development:__ [resourcetiming-decompression.js](https://github.com/nicjansma/resourcetiming-compression.js/raw/master/src/resourcetiming-decompression.js) - 6.5kb
__Development:__ [resourcetiming-decompression.js](https://github.com/nicjansma/resourcetiming-compression.js/raw/master/src/resourcetiming-decompression.js) - 8.8kb
__Production:__ [resourcetiming-decompression.min.js](https://github.com/nicjansma/resourcetiming-compression.js/raw/master/dist/resourcetiming-decompression.min.js) - 2kb (minified / gzipped)
__Production:__ [resourcetiming-decompression.min.js](https://github.com/nicjansma/resourcetiming-compression.js/raw/master/dist/resourcetiming-decompression.min.js) - 1kb (minified / gzipped)

@@ -99,2 +99,63 @@ resourcetiming-compression.js is also available as the [npm resourcetiming-compression module](https://npmjs.org/package/resourcetiming-compression). You can install

## Resource Dimensions
If available, when [compressing the resources](http://nicj.net/compressing-resourcetiming/) via `compressResourceTiming()`, any resource that has a visible component on the page (such as an `IMG` element) will have its `height` `width` `top` and `left` values captured and included in the compressed data as well.
This information is encoded as a "special value" in the resource's timings array.
For each resource, multiple hits to the same URL are separated by a pipe (`|`) character:
```
{
// this resource was loaded twice with timings 70,1z,1c and 90,1,2
"http://blah.com/js/foo.js": "370,1z,1c|390,1,2"
}
```
(See the [blog post](http://nicj.net/compressing-resourcetiming/) for a description of how to interpret the values)
If the resource has visible elements on the page, they will be appended to this list of timings with a special prefix of `*0` ([Base36](https://en.wikipedia.org/wiki/Base36) encoded):
```
{
// this resource was loaded twice with timings 70,1z,1c and 90,1,2 and had
// dimensions of height = 1, width = 5, top = 10 and left = 11
"http://blah.com/js/foo.js": "370,1z,1c|390,1,2|*01,5,a,b"
}
```
## Resource Sizes
If available via [ResourceTiming2](https://www.w3.org/TR/resource-timing/), when [compressing the resources](http://nicj.net/compressing-resourcetiming/) via `compressResourceTiming()`, the resource's `transferSize`, `encodedBodySize` and `decodedBodySize` will be captured and included in the compressed data as well.
This information is encoded as a "special value" in the resource's timings array. They will be appended to the list of timings with a special prefix of `*1`:
The data will be stored in the order of: `[e, t, d]`.
* `e`: `encodedBodySize` is the [Base36](https://en.wikipedia.org/wiki/Base36) decoded value (`encodedBodySize = parseInt(e, 36)`)
* `t`:
* If a Base36 encoded number, `t` is the `transferSize` increase in size over `encodedBodySize` (`transferSize = parseInt(e, 36) + parseInt(t, 36)`)
* If the value of `"_"`, `transferSize` is `0`
* If missing, `transferSize` was either `0` or `undefined`
* `d`:
* If a Base36 encoded number, `d` is the `decodedBodySize` increase in size over `encodedBodySize` (`decodedBodySize = parseInt(e, 36) + parseInt(d, 36)`)
* If `0`, `encodedBodySize` is `0`
* If missing, `encodedBodySize` was either `0` or `undefined`
Taking the following example:
```
{
// this resource was loaded twice with timings 70,1z,1c and 90,1,2 and had
// transferSize
"http://blah.com/js/foo.js": "370,1z,1c|390,1,2|*1a,b,c"
}
```
Results in:
* `encodedBodySize` = `parseInt("a", 36)` = `10`
* `transferSize` = `parseInt("a", 36) + parseInt("b", 36)` = `21`
* `encodedBodySize` = `parseInt("a", 36) + parseInt("c", 36)` = `22`
## Tests

@@ -114,2 +175,9 @@

* v0.3.0 - 2016-07-11:
* Captures dimensions (px) of resources
* Captures resource sizes (bytes) from ResourceTiming2
* Breaks certain URLs up slightly so they don't trigger XSS filters
* Limits URLs to 500 characters, and adds the ability to trim other URLs
* Don't go more than 10 IFRAMEs deep (to avoid recursion bugs)
* Fixes browser bugs with incorrect timings
* v0.2.2 - 2016-06-01: Add 'html' initiatorType for root page

@@ -116,0 +184,0 @@ * v0.2.1 - 2016-04-04: Protect against X-O frame access that crashes some browsers

@@ -51,3 +51,37 @@ //

// Words that will be broken (by ensuring the optimized trie doesn't contain
// the whole string) in URLs, to ensure NoScript doesn't think this is an XSS attack
var DEFAULT_XSS_BREAK_WORDS = [
/(h)(ref)/gi,
/(s)(rc)/gi,
/(a)(ction)/gi
];
// Delimiter to use to break a XSS word
var XSS_BREAK_DELIM = "\n";
// Maximum number of characters in a URL
var DEFAULT_URL_LIMIT = 500;
// Any ResourceTiming data time that starts with this character is not a time,
// but something else (like dimension data)
var SPECIAL_DATA_PREFIX = "*";
// Dimension data special type
var SPECIAL_DATA_DIMENSION_TYPE = "0";
// Dimension data special type
var SPECIAL_DATA_SIZE_TYPE = "1";
/**
* List of URLs (strings or regexs) to trim
*/
ResourceTimingCompression.trimUrls = [];
/**
* Words to break to avoid XSS filters
*/
ResourceTimingCompression.xssBreakWords = DEFAULT_XSS_BREAK_WORDS;
/**
* Converts entries to a Trie:

@@ -69,3 +103,3 @@ * http://en.wikipedia.org/wiki/Trie

ResourceTimingCompression.convertToTrie = function(entries) {
var trie = {}, url, i, value, letters, letter, cur, node;
var trie = {}, url, urlFixed, i, value, letters, letter, cur, node;

@@ -77,4 +111,17 @@ for (url in entries) {

urlFixed = url;
// find any strings to break
for (i = 0; i < this.xssBreakWords.length; i++) {
// Add a XSS_BREAK_DELIM character after the first letter. optimizeTrie will
// ensure this sequence doesn't get combined.
urlFixed = urlFixed.replace(this.xssBreakWords[i], "$1" + XSS_BREAK_DELIM + "$2");
}
if (!entries.hasOwnProperty(url)) {
continue;
}
value = entries[url];
letters = url.split("");
letters = urlFixed.split("");
cur = trie;

@@ -119,3 +166,13 @@

// capture trie keys first as we'll be modifying it
var keys = [];
for (node in cur) {
if (cur.hasOwnProperty(node)) {
keys.push(node);
}
}
for (var i = 0; i < keys.length; i++) {
node = keys[i];
if (typeof cur[node] === "object") {

@@ -127,3 +184,13 @@ // optimize children

delete cur[node];
node = node + ret.name;
if (node === XSS_BREAK_DELIM) {
// If this node is a newline, which can't be in a regular URL,
// it's due to the XSS patch. Remove the placeholder character,
// and make sure this node isn't compressed by incrementing
// num to be greater than one.
node = ret.name;
num++;
} else {
node = node + ret.name;
}
cur[node] = ret.value;

@@ -173,4 +240,4 @@ }

// strip from microseconds to milliseconds only
var timeMs = Math.round(time),
startTimeMs = Math.round(startTime);
var timeMs = Math.round(time ? time : 0),
startTimeMs = Math.round(startTime ? startTime : 0);

@@ -221,34 +288,55 @@ return timeMs === 0 ? 0 : (timeMs - startTimeMs);

* @param {string} offset Offset in timing from root IFRA
*
* @param {number} depth Recursion depth
* @returns {PerformanceEntry[]} Performance entries
*/
ResourceTimingCompression.findPerformanceEntriesForFrame = function(frame, isTopWindow, offset) {
ResourceTimingCompression.findPerformanceEntriesForFrame = function(frame, isTopWindow, offset, depth) {
var entries = [], i, navEntries, navStart, frameNavStart, frameOffset, navEntry, t, frameLoc;
navStart = this.getNavStartTime(frame);
if (typeof isTopWindow === "undefined") {
isTopWindow = true;
}
// get sub-frames' entries first
if (frame.frames) {
for (i = 0; i < frame.frames.length; i++) {
frameNavStart = this.getNavStartTime(frame.frames[i]);
frameOffset = 0;
if (frameNavStart > navStart) {
frameOffset = offset + (frameNavStart - navStart);
}
if (typeof offset === "undefined") {
offset = 0;
}
entries = entries.concat(this.findPerformanceEntriesForFrame(frame.frames[i], false, frameOffset));
}
if (typeof depth === "undefined") {
depth = 0;
}
if (depth > 10) {
return entries;
}
try {
// Try to access location.href first to trigger any Cross-Origin
// warnings. There's also a bug in Chrome ~48 that might cause
// the browser to crash if accessing X-O frame.performance.
// https://code.google.com/p/chromium/issues/detail?id=585871
// This variable is not otherwise used.
frameLoc = frame.location && frame.location.href;
navStart = this.getNavStartTime(frame);
if (!("performance" in frame) ||
!frame.performance ||
!frame.performance.getEntriesByType) {
// get sub-frames' entries first
if (frame.frames) {
for (i = 0; i < frame.frames.length; i++) {
frameNavStart = this.getNavStartTime(frame.frames[i]);
frameOffset = 0;
if (frameNavStart > navStart) {
frameOffset = offset + (frameNavStart - navStart);
}
entries = entries.concat(this.findPerformanceEntriesForFrame(frame.frames[i], false, frameOffset));
}
}
try {
// Try to access location.href first to trigger any Cross-Origin
// warnings. There's also a bug in Chrome ~48 that might cause
// the browser to crash if accessing X-O frame.performance.
// https://code.google.com/p/chromium/issues/detail?id=585871
// This variable is not otherwise used.
frameLoc = frame.location && frame.location.href;
if (!("performance" in frame) ||
!frame.performance ||
!frame.performance.getEntriesByType) {
return entries;
}
} catch (e) {
// NOP
return entries;

@@ -266,4 +354,4 @@ }

name: frame.location.href,
startTime: 0,
initiatorType: "html",
startTime: 0,
redirectStart: navEntry.redirectStart,

@@ -284,20 +372,30 @@ redirectEnd: navEntry.redirectEnd,

t = frame.performance.timing;
entries.push({
name: frame.location.href,
initiatorType: "html",
startTime: 0,
redirectStart: t.redirectStart ? (t.redirectStart - t.navigationStart) : 0,
redirectEnd: t.redirectEnd ? (t.redirectEnd - t.navigationStart) : 0,
fetchStart: t.fetchStart ? (t.fetchStart - t.navigationStart) : 0,
domainLookupStart: t.domainLookupStart ? (t.domainLookupStart - t.navigationStart) : 0,
domainLookupEnd: t.domainLookupEnd ? (t.domainLookupEnd - t.navigationStart) : 0,
connectStart: t.connectStart ? (t.connectStart - t.navigationStart) : 0,
secureConnectionStart: t.secureConnectionStart ?
(t.secureConnectionStart - t.navigationStart) :
0,
connectEnd: t.connectEnd ? (t.connectEnd - t.navigationStart) : 0,
requestStart: t.requestStart ? (t.requestStart - t.navigationStart) : 0,
responseStart: t.responseStart ? (t.responseStart - t.navigationStart) : 0,
responseEnd: t.responseEnd ? (t.responseEnd - t.navigationStart) : 0
});
//
// Avoid browser bugs:
// 1. navigationStart being 0 in some cases
// 2. responseEnd being ~2x what navigationStart is
// (ensure the end is within 60 minutes of start)
//
if (t.navigationStart !== 0 &&
t.responseEnd <= (t.navigationStart + (60 * 60 * 1000))) {
entries.push({
name: frame.location.href,
startTime: 0,
initiatorType: "html",
redirectStart: t.redirectStart ? (t.redirectStart - t.navigationStart) : 0,
redirectEnd: t.redirectEnd ? (t.redirectEnd - t.navigationStart) : 0,
fetchStart: t.fetchStart ? (t.fetchStart - t.navigationStart) : 0,
domainLookupStart: t.domainLookupStart ? (t.domainLookupStart - t.navigationStart) : 0,
domainLookupEnd: t.domainLookupEnd ? (t.domainLookupEnd - t.navigationStart) : 0,
connectStart: t.connectStart ? (t.connectStart - t.navigationStart) : 0,
secureConnectionStart: t.secureConnectionStart ?
(t.secureConnectionStart - t.navigationStart) :
0,
connectEnd: t.connectEnd ? (t.connectEnd - t.navigationStart) : 0,
requestStart: t.requestStart ? (t.requestStart - t.navigationStart) : 0,
responseStart: t.responseStart ? (t.responseStart - t.navigationStart) : 0,
responseEnd: t.responseEnd ? (t.responseEnd - t.navigationStart) : 0
});
}
}

@@ -339,24 +437,276 @@ }

/**
* Converts a number to base-36
* Converts a number to base-36.
*
* If not a number or a string, or === 0, return "". This is to facilitate
* compression in the timing array, where "blanks" or 0s show as a series
* of trailing ",,,," that can be trimmed.
*
* If a string, return a string.
*
* @param {number} n Number
* @returns {number|string} Base-36 number, or empty string if undefined.
* @returns {string} Base-36 number, empty string, or string
*/
ResourceTimingCompression.toBase36 = function(n) {
return (typeof n === "number") ? n.toString(36) : "";
if (typeof n === "number" && n !== 0) {
return n.toString(36);
} else {
return typeof n === "string" ? n : "";
}
};
/**
* Gathers performance entries and optimizes the result.
* Finds all remote resources in the selected window that are visible, and returns an object
* keyed by the url with an array of height,width,top,left as the value
*
* @param {Window} win Window to search
* @returns {Object} Object with URLs of visible assets as keys, and Array[height, width, top, left] as value
*/
ResourceTimingCompression.getVisibleEntries = function(win) {
var els = ["IMG", "IFRAME"], entries = {}, x, y, doc = win.document;
// https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollX
// https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect
x = (win.pageXOffset !== undefined)
? win.pageXOffset
: (doc.documentElement || doc.body.parentNode || doc.body).scrollLeft;
y = (win.pageYOffset !== undefined)
? win.pageYOffset
: (doc.documentElement || doc.body.parentNode || doc.body).scrollTop;
// look at each IMG and IFRAME
els.forEach(function(elname) {
var elements = doc.getElementsByTagName(elname), el, i, rect;
for (i = 0; i < elements.length; i++) {
el = elements[i];
// look at this element if it has a src attribute, and we haven't already looked at it
if (el && el.src && !entries[el.src]) {
rect = el.getBoundingClientRect();
// Require both height & width to be non-zero
// IE <= 8 does not report rect.height/rect.width so we need offsetHeight & width
if ((rect.height || el.offsetHeight)
&& (rect.width || el.offsetWidth)) {
entries[el.src] = [
el.offsetHeight,
el.offsetWidth,
Math.round(rect.top + y),
Math.round(rect.left + x),
];
}
}
}
});
return entries;
};
/**
* Determines if the value is in the specified array
*
* @param {object} val Value
* @param {object[]} ary Array
*
* @returns {boolean} True if the value is in the array
*/
ResourceTimingCompression.inArray = function(val, ary) {
var i;
if (typeof val === "undefined" || typeof ary === "undefined" || !ary.length) {
return false;
}
for (i = 0; i < ary.length; i++) {
if (ary[i] === val) {
return true;
}
}
return false;
};
/**
* Gathers a filtered list of performance entries.
* @param {Window} win The Window
* @param {number} from Only get timings from
* @param {number} to Only get timings up to
* @param {string[]} initiatorTypes Array of initiator types
* @returns {ResourceTiming[]} Matching ResourceTiming entries
*/
ResourceTimingCompression.getFilteredResourceTiming = function(win, from, to, initiatorTypes) {
var entries = this.findPerformanceEntriesForFrame(win, true, 0, 0),
i, e, results = {}, initiatorType, url, data,
navStart = this.getNavStartTime(win);
if (!entries || !entries.length) {
return [];
}
var filteredEntries = [];
for (i = 0; i < entries.length; i++) {
e = entries[i];
// skip non-resource URLs
if (e.name.indexOf("about:") === 0 ||
e.name.indexOf("javascript:") === 0) {
continue;
}
// TODO: skip URLs we don't want to report
// if the user specified a "from" time, skip resources that started before then
if (from && (navStart + e.startTime) < from) {
continue;
}
// if we were given a final timestamp, don't add any resources that started after it
if (to && (navStart + e.startTime) > to) {
// We can also break at this point since the array is time sorted
break;
}
// if given an array of initiatorTypes to include, skip anything else
if (typeof initiatorTypes !== "undefined" && initiatorTypes !== "*" && initiatorTypes.length) {
if (!e.initiatorType || !this.inArray(e.initiatorType, initiatorTypes)) {
continue;
}
}
filteredEntries.push(e);
}
return filteredEntries;
};
/**
* Gets compressed content and transfer size information, if available
*
* @param {ResourceTiming} resource ResourceTiming bject
*
* @returns {string} Compressed data (or empty string, if not available)
*/
ResourceTimingCompression.compressSize = function(resource) {
var sTrans, sEnc, sDec, sizes;
// check to see if we can add content sizes
if (resource.encodedBodySize ||
resource.decodedBodySize ||
resource.transferSize) {
//
// transferSize: how many bytes were over the wire. It can be 0 in the case of X-O,
// or if it was fetched from a cache.
//
// encodedBodySize: the size after applying encoding (e.g. gzipped size). It is 0 if X-O.
//
// decodedBodySize: the size after removing encoding (e.g. the original content size). It is 0 if X-O.
//
// Here are the possible combinations of values: [encodedBodySize, transferSize, decodedBodySize]
//
// Cross-Origin resources w/out Timing-Allow-Origin set: [0, 0, 0] -> [0, 0, 0] -> [empty]
// 204: [0, t, 0] -> [0, t, 0] -> [e, t-e] -> [, t]
// 304: [e, t: t <=> e, d: d>=e] -> [e, t-e, d-e]
// 200 non-gzipped: [e, t: t>=e, d: d=e] -> [e, t-e]
// 200 gzipped: [e, t: t>=e, d: d>=e] -> [e, t-e, d-e]
// retrieved from cache non-gzipped: [e, 0, d: d=e] -> [e]
// retrieved from cache gzipped: [e, 0, d: d>=e] -> [e, _, d-e]
//
sTrans = resource.transferSize;
sEnc = resource.encodedBodySize;
sDec = resource.decodedBodySize;
// convert to an array
sizes = [sEnc, sTrans ? sTrans - sEnc : "_", sDec ? sDec - sEnc : 0];
// change everything to base36 and remove any trailing ,s
return sizes.map(this.toBase36).join(",").replace(/,+$/, "");
} else {
return "";
}
};
/* Cleans up a URL by removing the query string (if configured), and
* limits the URL to the specified size.
*
* @param {string} url URL to clean
* @param {number} urlLimit Maximum size, in characters, of the URL
*
* @returns {string} Cleaned up URL
*/
ResourceTimingCompression.cleanupURL = function(url, urlLimit) {
var qsStart;
if (!url || Object.prototype.toString.call(url) === "[object Array]") {
return "";
}
if (typeof urlLimit !== "undefined" && url && url.length > urlLimit) {
// We need to break this URL up. Try at the query string first.
qsStart = url.indexOf("?");
if (qsStart !== -1 && qsStart < urlLimit) {
url = url.substr(0, qsStart) + "?...";
} else {
// No query string, just stop at the limit
url = url.substr(0, urlLimit - 3) + "...";
}
}
return url;
};
/**
* Trims the URL according to the specified URL trim patterns,
* then applies a length limit.
*
* @param {string} url URL to trim
* @param {string} urlsToTrim List of URLs (strings or regexs) to trim
* @returns {string} Trimmed URL
*/
ResourceTimingCompression.trimUrl = function(url, urlsToTrim) {
var i, urlIdx, trim;
if (url && urlsToTrim) {
// trim the payload from any of the specified URLs
for (i = 0; i < urlsToTrim.length; i++) {
trim = urlsToTrim[i];
if (typeof trim === "string") {
urlIdx = url.indexOf(trim);
if (urlIdx !== -1) {
url = url.substr(0, urlIdx + trim.length) + "...";
break;
}
} else if (trim instanceof RegExp) {
if (trim.test(url)) {
// replace the URL with the first capture group
url = url.replace(trim, "$1") + "...";
}
}
}
}
// apply limits
return this.cleanupURL(url, DEFAULT_URL_LIMIT);
};
/**
* Gathers performance entries and compresses the result.
* @param {Window} [win] The Window
* @param {number} [from] Only get timings from
* @param {number} [to] Only get timings up to
* @returns {object} Optimized performance entries trie
*/
ResourceTimingCompression.getResourceTiming = function() {
ResourceTimingCompression.getResourceTiming = function(win, from, to) {
/* eslint no-script-url:0 */
var entries = this.findPerformanceEntriesForFrame(window, true, 0);
if (typeof win === "undefined") {
win = window;
}
var entries = ResourceTimingCompression.getFilteredResourceTiming(win, from, to);
if (!entries || !entries.length) {
return [];
return {};
}
return this.compressResourceTiming(entries);
return ResourceTimingCompression.compressResourceTiming(win, entries);
};

@@ -366,17 +716,16 @@

* Optimizes the specified set of performance entries.
* @param {Window} win The Window
* @param {object} entries Performance entries
* @returns {object} Optimized performance entries trie
*/
ResourceTimingCompression.compressResourceTiming = function(entries) {
ResourceTimingCompression.compressResourceTiming = function(win, entries) {
/* eslint no-script-url:0 */
var i, e, results = {}, initiatorType, url, data;
var i, e, results = {}, initiatorType, url, data, visibleEntries = {};
// gather visible entries on the page
visibleEntries = this.getVisibleEntries(win);
for (i = 0; i < entries.length; i++) {
e = entries[i];
if (e.name.indexOf("about:") === 0 ||
e.name.indexOf("javascript:") === 0) {
continue;
}
//

@@ -414,4 +763,10 @@ // Compress the RT data into a string:

url = e.name;
// add content and transfer size info
var compSize = this.compressSize(e);
if (compSize !== "") {
data += SPECIAL_DATA_PREFIX + SPECIAL_DATA_SIZE_TYPE + compSize;
}
url = this.trimUrl(e.name, this.trimUrls);
// if this entry already exists, add a pipe as a separator

@@ -421,3 +776,17 @@ if (results[url] !== undefined) {

} else {
results[url] = data;
// for the first time we see this URL, add resource dimensions if we have them
if (visibleEntries[url] !== undefined) {
// We use * as an additional separator to indicate it is not a new resource entry
// The following characters will not be URL encoded:
// *!-.()~_ but - and . are special to number representation so we don't use them
// After the *, the type of special data (ResourceTiming = 0) is added
results[url] =
SPECIAL_DATA_PREFIX +
SPECIAL_DATA_DIMENSION_TYPE +
visibleEntries[url].map(this.toBase36).join(",").replace(/,+$/, "")
+ "|"
+ data;
} else {
results[url] = data;
}
}

@@ -424,0 +793,0 @@ }

@@ -85,3 +85,9 @@ //

for (var i = 0; i < timings.length; i++) {
resources.push(this.decodeCompressedResource(timings[i], nodeKey));
var resourceData = timings[i];
if (resourceData.length > 0 && resourceData[0] === "*") {
// dimensions for this resource
continue;
}
resources.push(this.decodeCompressedResource(resourceData, nodeKey));
}

@@ -194,2 +200,57 @@ } else {

/**
* Decompresses size information back into the specified resource
*
* @param {string} compressed Compressed string
* @param {ResourceTiming} resource ResourceTiming bject
* @returns {ResourceTiming} ResourceTiming object with decompressed sizes
*/
ResourceTimingDecompression.decompressSize = function(compressed, resource) {
var split, i;
if (typeof resource === "undefined") {
resource = {};
}
split = compressed.split(",");
for (i = 0; i < split.length; i++) {
if (split[i] === "_") {
// special non-delta value
split[i] = 0;
} else {
// fill in missing numbers
if (split[i] === "") {
split[i] = 0;
}
// convert back from Base36
split[i] = parseInt(split[i], 36);
if (i > 0) {
// delta against first number
split[i] += split[0];
}
}
}
// fill in missing
if (split.length === 1) {
// transferSize is a delta from encodedSize
split.push(split[0]);
}
if (split.length === 2) {
// decodedSize is a delta from encodedSize
split.push(split[0]);
}
// re-add attributes to the resource
resource.encodedBodySize = split[0];
resource.transferSize = split[1];
resource.decodedBodySize = split[2];
return resource;
};
//

@@ -196,0 +257,0 @@ // Export to the appropriate location

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc