Repository navigation
Expand file tree
/
Copy pathutils.js
More file actions
110 lines (95 loc) · 3.66 KB
/
Copy pathutils.js
File metadata and controls
110 lines (95 loc) · 3.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import { stat } from 'fs/promises';
import { resolve } from 'path';
import * as logger from './logger.js';
export async function run_hook_file(hook_file_path, cdp, request, response, provided_logger) {
const utils_logger = provided_logger || logger.get_logger();
async function file_exists(path) {
try {
const stats = await stat(path);
return stats.isFile();
} catch {
return false;
}
}
const abs_hook_file_path = resolve(hook_file_path);
if (await file_exists(abs_hook_file_path)) {
const hook_module = await import(abs_hook_file_path);
if (typeof hook_module.hook !== 'function') {
utils_logger.error('"hook" export not found or not a function for hook file.', {
hook_file: abs_hook_file_path
});
process.exit(1);
}
await hook_module.hook(cdp, request, response, utils_logger);
} else {
utils_logger.error('Hook file does not exist or is not a file.', {
hook_file: abs_hook_file_path
});
process.exit(1);
}
}
export function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
export function convert_headers_array(flat_headers) {
const result = [];
for (let i = 0; i < flat_headers.length; i += 2) {
result.push({
key: flat_headers[i],
value: flat_headers[i + 1],
});
}
return result;
}
export function response_has_no_body(method, status_code) {
return method.toUpperCase() === 'HEAD' || status_code < 200 ||
status_code === 204 || status_code === 205 || status_code === 304;
}
export function fetch_headers_to_proxy_response_headers(fetch_headers, body, method, status_code) {
// Chrome has already decoded the body. Rebuild framing for the downstream
// connection instead of forwarding the upstream compression/transfer framing.
const excluded_names = new Set([
'content-encoding', 'content-length', 'transfer-encoding', 'trailer',
'connection', 'keep-alive', 'proxy-connection', 'te', 'upgrade'
]);
for (const header of fetch_headers) {
if (header && typeof header.name === 'string' && header.name.toLowerCase() === 'connection') {
for (const name of header.value.split(',')) {
excluded_names.add(name.trim().toLowerCase());
}
}
}
const formatted_headers = Object.create(null);
for (const header of fetch_headers) {
if (!header || typeof header.name !== 'string') {
continue;
}
const name = header.name.toLowerCase();
if (name.startsWith(':') || excluded_names.has(name)) {
continue;
}
const previous = formatted_headers[name];
if (typeof previous === 'undefined') {
formatted_headers[name] = header.value;
} else if (Array.isArray(previous)) {
previous.push(header.value);
} else {
// In particular, Set-Cookie must remain separate header fields.
formatted_headers[name] = [previous, header.value];
}
}
// HEAD/304 lengths describe a selected representation, not this empty body.
// Its decoded size is unknown; omit the optional length. 1xx/204 forbid it.
if (!response_has_no_body(method, status_code) || status_code === 205) {
formatted_headers['content-length'] = String(body.length);
}
return formatted_headers;
}
import { timingSafeEqual } from "crypto";
export const time_safe_compare = (a, b) => {
try {
return timingSafeEqual(Buffer.from(a, "utf8"), Buffer.from(b, "utf8"));
} catch {
return false;
}
};