httpUtil.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /**
  2. * @license
  3. * Copyright 2023 Google Inc.
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. import { createWriteStream } from 'fs';
  7. import * as http from 'http';
  8. import * as https from 'https';
  9. import { URL, urlToHttpOptions } from 'url';
  10. import { ProxyAgent } from 'proxy-agent';
  11. export function headHttpRequest(url) {
  12. return new Promise(resolve => {
  13. const request = httpRequest(url, 'HEAD', response => {
  14. // consume response data free node process
  15. response.resume();
  16. resolve(response.statusCode === 200);
  17. }, false);
  18. request.on('error', () => {
  19. resolve(false);
  20. });
  21. });
  22. }
  23. export 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,
  32. agent: new ProxyAgent(),
  33. };
  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. // consume response data to free up memory
  41. // And prevents the connection from being kept alive
  42. res.resume();
  43. }
  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. */
  57. export 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. }
  91. export 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. }
  100. export 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