• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3    return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6exports.DefaultFetcher = exports.BaseFetcher = void 0;
7const debug_1 = __importDefault(require("debug"));
8const fs_1 = __importDefault(require("fs"));
9const make_fetch_happen_1 = __importDefault(require("make-fetch-happen"));
10const util_1 = __importDefault(require("util"));
11const error_1 = require("./error");
12const tmpfile_1 = require("./utils/tmpfile");
13const log = (0, debug_1.default)('tuf:fetch');
14class BaseFetcher {
15    // Download file from given URL. The file is downloaded to a temporary
16    // location and then passed to the given handler. The handler is responsible
17    // for moving the file to its final location. The temporary file is deleted
18    // after the handler returns.
19    async downloadFile(url, maxLength, handler) {
20        return (0, tmpfile_1.withTempFile)(async (tmpFile) => {
21            const reader = await this.fetch(url);
22            let numberOfBytesReceived = 0;
23            const fileStream = fs_1.default.createWriteStream(tmpFile);
24            // Read the stream a chunk at a time so that we can check
25            // the length of the file as we go
26            try {
27                for await (const chunk of reader) {
28                    const bufferChunk = Buffer.from(chunk);
29                    numberOfBytesReceived += bufferChunk.length;
30                    if (numberOfBytesReceived > maxLength) {
31                        throw new error_1.DownloadLengthMismatchError('Max length reached');
32                    }
33                    await writeBufferToStream(fileStream, bufferChunk);
34                }
35            }
36            finally {
37                // Make sure we always close the stream
38                await util_1.default.promisify(fileStream.close).bind(fileStream)();
39            }
40            return handler(tmpFile);
41        });
42    }
43    // Download bytes from given URL.
44    async downloadBytes(url, maxLength) {
45        return this.downloadFile(url, maxLength, async (file) => {
46            const stream = fs_1.default.createReadStream(file);
47            const chunks = [];
48            for await (const chunk of stream) {
49                chunks.push(chunk);
50            }
51            return Buffer.concat(chunks);
52        });
53    }
54}
55exports.BaseFetcher = BaseFetcher;
56class DefaultFetcher extends BaseFetcher {
57    constructor(options = {}) {
58        super();
59        this.timeout = options.timeout;
60        this.retry = options.retry;
61    }
62    async fetch(url) {
63        log('GET %s', url);
64        const response = await (0, make_fetch_happen_1.default)(url, {
65            timeout: this.timeout,
66            retry: this.retry,
67        });
68        if (!response.ok || !response?.body) {
69            throw new error_1.DownloadHTTPError('Failed to download', response.status);
70        }
71        return response.body;
72    }
73}
74exports.DefaultFetcher = DefaultFetcher;
75const writeBufferToStream = async (stream, buffer) => {
76    return new Promise((resolve, reject) => {
77        stream.write(buffer, (err) => {
78            if (err) {
79                reject(err);
80            }
81            resolve(true);
82        });
83    });
84};
85