Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ulixee
GitHub Repository: ulixee/secret-agent
Path: blob/main/plugins/default-browser-emulator/injected-scripts/window.chrome.ts
1029 views
1
function toSeconds(millis) {
2
let entry = (millis / 1000).toFixed(3);
3
if (entry.endsWith('0')) entry = entry.substr(0, entry.length - 1);
4
return parseFloat(entry);
5
}
6
7
interface PerformanceEntry {
8
loadEventEnd: number;
9
responseStart: number;
10
domContentLoadedEventEnd: number;
11
type: string;
12
nextHopProtocol: string;
13
}
14
15
// from https://developers.google.com/web/updates/2017/12/chrome-loadtimes-deprecated
16
const loadTimeConversion = {
17
requestTime() {
18
const ntEntry = performance.getEntriesByType('navigation')[0];
19
const start = ntEntry ? ntEntry.startTime : 0;
20
return toSeconds(start + performance.timeOrigin);
21
},
22
startLoadTime() {
23
const ntEntry = performance.getEntriesByType('navigation')[0];
24
const start = ntEntry ? ntEntry.startTime : 0;
25
return toSeconds(start + performance.timeOrigin);
26
},
27
commitLoadTime() {
28
const ntEntry = performance.getEntriesByType('navigation')[0];
29
const start = ntEntry ? ntEntry.responseStart : 0;
30
return toSeconds(start + performance.timeOrigin);
31
},
32
finishDocumentLoadTime() {
33
const ntEntry = performance.getEntriesByType('navigation')[0];
34
const start = ntEntry ? ntEntry.domContentLoadedEventEnd : 0;
35
return toSeconds(start + performance.timeOrigin);
36
},
37
finishLoadTime() {
38
const ntEntry = performance.getEntriesByType('navigation')[0];
39
const start = ntEntry ? ntEntry.loadEventEnd : 0;
40
return toSeconds(start + performance.timeOrigin);
41
},
42
firstPaintTime() {
43
let fpEntry: { startTime: number } = performance.getEntriesByType('paint')[0];
44
if (!fpEntry) {
45
const ntEntry = performance.getEntriesByType('navigation')[0];
46
const start = ntEntry ? ntEntry.loadEventEnd : 0;
47
fpEntry = { startTime: start + Math.random() * 85 };
48
}
49
return toSeconds(fpEntry.startTime + performance.timeOrigin);
50
},
51
navigationType() {
52
const ntEntry = performance.getEntriesByType('navigation')[0];
53
if (!ntEntry) return 'Other';
54
switch (ntEntry.type) {
55
case 'back_forward':
56
return 'BackForward';
57
case 'reload':
58
return 'Reload';
59
case 'prerender':
60
case 'navigate':
61
default:
62
return 'Other';
63
}
64
// case blink::kWebNavigationTypeLinkClicked:
65
// return "LinkClicked";
66
// case blink::kWebNavigationTypeFormSubmitted:
67
// return "FormSubmitted";
68
// case blink::kWebNavigationTypeFormResubmitted:
69
// return "Resubmitted";
70
},
71
wasFetchedViaSpdy() {
72
// SPDY is deprecated in favor of HTTP/2, but this implementation returns
73
// true for HTTP/2 or HTTP2+QUIC/39 as well.
74
const ntEntry = performance.getEntriesByType('navigation')[0];
75
if (!ntEntry) return true;
76
return ['h2', 'hq'].includes(ntEntry.nextHopProtocol);
77
},
78
wasNpnNegotiated() {
79
// NPN is deprecated in favor of ALPN, but this implementation returns true
80
// for HTTP/2 or HTTP2+QUIC/39 requests negotiated via ALPN.
81
const ntEntry = performance.getEntriesByType('navigation')[0];
82
if (!ntEntry) return true;
83
return ['h2', 'hq'].includes(ntEntry.nextHopProtocol);
84
},
85
connectionInfo() {
86
const ntEntry = performance.getEntriesByType('navigation')[0];
87
if (!ntEntry) return 'h2';
88
return ntEntry.nextHopProtocol;
89
},
90
};
91
92
const csiConversion = {
93
startE() {
94
const ntEntry = performance.getEntriesByType('navigation')[0];
95
const start = ntEntry ? ntEntry.loadEventEnd : 0;
96
return parseInt((start + performance.timeOrigin) as any, 10);
97
},
98
onloadT() {
99
const ntEntry = performance.getEntriesByType('navigation')[0];
100
const load = ntEntry ? ntEntry.domContentLoadedEventEnd : 0;
101
return parseInt((load + performance.timeOrigin) as any, 10);
102
},
103
pageT() {
104
return parseFloat(performance.now().toFixed(3));
105
},
106
tran() {
107
const ntEntry = performance.getEntriesByType('navigation')[0];
108
const type = ntEntry ? ntEntry.type : 'navigate';
109
// https://chromium.googlesource.com/chromium/src.git/+/master/chrome/renderer/loadtimes_extension_bindings.cc
110
switch (type) {
111
case 'back_forward':
112
return 6;
113
case 'reload':
114
return 16;
115
case 'prerender':
116
case 'navigate':
117
default:
118
return 15;
119
}
120
/**
121
*
122
const int kTransitionLink = 0;
123
124
case blink::kWebNavigationTypeLinkClicked:
125
case blink::kWebNavigationTypeFormSubmitted:
126
case blink::kWebNavigationTypeFormResubmitted:
127
return kTransitionLink;
128
*/
129
},
130
};
131
132
const polyfill = args.polyfill;
133
const { prevProperty, property } = polyfill;
134
if (args.updateLoadTimes) {
135
for (const [name, func] of Object.entries(loadTimeConversion)) {
136
property.loadTimes['new()'][name]['_$$value()'] = func;
137
}
138
for (const [name, func] of Object.entries(csiConversion)) {
139
property.csi['new()'][name]['_$$value()'] = func;
140
}
141
}
142
const descriptor = buildDescriptor(property);
143
addDescriptorAfterProperty('window', prevProperty, 'chrome', descriptor);
144
145