blob: 10640affe2c112fdc2e7fed11be492917ef7231e [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 */
6import { createWriteStream } from 'fs';
7import * as http from 'http';
8import * as https from 'https';
9import { URL, urlToHttpOptions } from '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);
40 }
41 else {
42 response(res);
43 }
44 };
45 const request = options.protocol === 'https:'
46 ? https.request(options, requestCallback)
47 : http.request(options, requestCallback);
48 request.end();
49 return request;
50}
51/**
52 * @internal
53 */
54export function downloadFile(url, destinationPath, progressCallback) {
55 return new Promise((resolve, reject) => {
56 let downloadedBytes = 0;
57 let totalBytes = 0;
58 function onData(chunk) {
59 downloadedBytes += chunk.length;
60 progressCallback(downloadedBytes, totalBytes);
61 }
62 const request = httpRequest(url, 'GET', response => {
63 if (response.statusCode !== 200) {
64 const error = new Error(`Download failed: server returned code ${response.statusCode}. URL: ${url}`);
65 // consume response data to free up memory
66 response.resume();
67 reject(error);
68 return;
69 }
70 const file = createWriteStream(destinationPath);
71 file.on('finish', () => {
72 return resolve();
73 });
74 file.on('error', error => {
75 return reject(error);
76 });
77 response.pipe(file);
78 totalBytes = parseInt(response.headers['content-length'], 10);
79 if (progressCallback) {
80 response.on('data', onData);
81 }
82 });
83 request.on('error', error => {
84 return reject(error);
85 });
86 });
87}
88export async function getJSON(url) {
89 const text = await getText(url);
90 try {
91 return JSON.parse(text);
92 }
93 catch {
94 throw new Error('Could not parse JSON from ' + url.toString());
95 }
96}
97export function getText(url) {
98 return new Promise((resolve, reject) => {
99 const request = httpRequest(url, 'GET', response => {
100 let data = '';
101 if (response.statusCode && response.statusCode >= 400) {
102 return reject(new Error(`Got status code ${response.statusCode}`));
103 }
104 response.on('data', chunk => {
105 data += chunk;
106 });
107 response.on('end', () => {
108 try {
109 return resolve(String(data));
110 }
111 catch {
112 return reject(new Error('Chrome version not found'));
113 }
114 });
115 }, false);
116 request.on('error', err => {
117 reject(err);
118 });
119 });
120}
121//# sourceMappingURL=httpUtil.js.map