blob: 2a1a753cd4af550338de661c3bc3e8e5d59fd040 [file] [log] [blame]
Randolf Jungbcb3bc82023-06-26 16:30:141/**
Alex Rudenkoaf11b7c2024-02-06 10:44:422 * @license
3 * Copyright 2023 Google Inc.
4 * SPDX-License-Identifier: Apache-2.0
Randolf Jungbcb3bc82023-06-26 16:30:145 */
Nikolay Vitkov95ea0452025-04-30 15:52:346import { createWriteStream } from 'node:fs';
7import * as http from 'node:http';
8import * as https from 'node:https';
9import { URL, urlToHttpOptions } from 'node:url';
Randolf Jung3e526312023-08-08 06:20:3910import { ProxyAgent } from 'proxy-agent';
Randolf Jungbcb3bc82023-06-26 16:30:1411export function headHttpRequest(url) {
12 return new Promise(resolve => {
13 const request = httpRequest(url, 'HEAD', response => {
Randolf Jung3e526312023-08-08 06:20:3914 // consume response data free node process
15 response.resume();
Randolf Jungbcb3bc82023-06-26 16:30:1416 resolve(response.statusCode === 200);
17 }, false);
18 request.on('error', () => {
19 resolve(false);
20 });
21 });
22}
23export function httpRequest(url, method, response, keepAlive = true) {
24 const options = {
25 protocol: url.protocol,
26 hostname: url.hostname,
27 port: url.port,
28 path: url.pathname + url.search,
29 method,
30 headers: keepAlive ? { Connection: 'keep-alive' } : undefined,
31 auth: urlToHttpOptions(url).auth,
Randolf Jung3e526312023-08-08 06:20:3932 agent: new ProxyAgent(),
Randolf Jungbcb3bc82023-06-26 16:30:1433 };
34 const requestCallback = (res) => {
35 if (res.statusCode &&
36 res.statusCode >= 300 &&
37 res.statusCode < 400 &&
38 res.headers.location) {
39 httpRequest(new URL(res.headers.location), method, response);
Alex Rudenko5fda6462024-04-17 12:18:0340 // consume response data to free up memory
41 // And prevents the connection from being kept alive
42 res.resume();
Randolf Jungbcb3bc82023-06-26 16:30:1443 }
44 else {
45 response(res);
46 }
47 };
48 const request = options.protocol === 'https:'
49 ? https.request(options, requestCallback)
50 : http.request(options, requestCallback);
51 request.end();
52 return request;
53}
54/**
55 * @internal
56 */
57export function downloadFile(url, destinationPath, progressCallback) {
58 return new Promise((resolve, reject) => {
59 let downloadedBytes = 0;
60 let totalBytes = 0;
61 function onData(chunk) {
62 downloadedBytes += chunk.length;
63 progressCallback(downloadedBytes, totalBytes);
64 }
65 const request = httpRequest(url, 'GET', response => {
66 if (response.statusCode !== 200) {
67 const error = new Error(`Download failed: server returned code ${response.statusCode}. URL: ${url}`);
68 // consume response data to free up memory
69 response.resume();
70 reject(error);
71 return;
72 }
73 const file = createWriteStream(destinationPath);
74 file.on('finish', () => {
75 return resolve();
76 });
77 file.on('error', error => {
78 return reject(error);
79 });
80 response.pipe(file);
81 totalBytes = parseInt(response.headers['content-length'], 10);
82 if (progressCallback) {
83 response.on('data', onData);
84 }
85 });
86 request.on('error', error => {
87 return reject(error);
88 });
89 });
90}
91export async function getJSON(url) {
92 const text = await getText(url);
93 try {
94 return JSON.parse(text);
95 }
96 catch {
97 throw new Error('Could not parse JSON from ' + url.toString());
98 }
99}
100export function getText(url) {
101 return new Promise((resolve, reject) => {
102 const request = httpRequest(url, 'GET', response => {
103 let data = '';
104 if (response.statusCode && response.statusCode >= 400) {
105 return reject(new Error(`Got status code ${response.statusCode}`));
106 }
107 response.on('data', chunk => {
108 data += chunk;
109 });
110 response.on('end', () => {
111 try {
112 return resolve(String(data));
113 }
114 catch {
115 return reject(new Error('Chrome version not found'));
116 }
117 });
118 }, false);
119 request.on('error', err => {
120 reject(err);
121 });
122 });
123}
124//# sourceMappingURL=httpUtil.js.map