hgouveia / node-downloader-helper

A simple http file downloader for node.js
MIT License
247 stars 54 forks source link

Download fails on second redirect #86

Closed bbreukelen closed 2 years ago

bbreukelen commented 2 years ago

Hello,

An http redirect works, but a second redirect fails on line 324. After the first redirect, getTotalSize expects the response to that redirect to be status 200. If it's another 301 or 302 it will fail. Would it be possible to loop the redirect process? I ran into it on dropbox who uses a double redirect for download links. For example: https://www.dropbox.com/s/nhr4ii7tl7cjaly/ski.mp4?dl=1

Thanks!

hgouveia commented 2 years ago

hello @bbreukelen i had checked this and i wasnt able to reproduce, the redirect is followed correctly, could you give me more information how to repro this? for example what options did you use and how you start the download? thanks

image

bbreukelen commented 2 years ago

I used the following code:

let download = new DownloaderHelper("https://www.dropbox.com/s/nhr4ii7tl7cjaly/ski.mp4?dl=1", "/tmp", {
                resumeIfFileExists: true,
                removeOnFail: false,
                removeOnStop: false,
                progressThrottle: 5000,
                fileName: "download.mp4",
                override: true
});

download.on('progress.throttled', (stats) => {
                console.log(`Download @ ${Math.ceil(stats.progress)}%`);
});

download.on("error", err => {
                console.log(`Download failed 1`, err);
});

download.on("end", () => {
                console.log(`Download completed`);
});

download
                .start()
                .catch(err => {
                console.log(`Download failed 2`, err);
});
hgouveia commented 2 years ago

Hello @bbreukelen i was able to reproduce with your example, i found a solution, could you try this code below before i release a new version? , this is your example, the only change is overriding of the getTotalSize function, let me know if working for you, also try without resume as well

const download = new DownloaderHelper('https://www.dropbox.com/s/nhr4ii7tl7cjaly/ski.mp4?dl=1',
    '/tmp', {
    resumeIfFileExists: true,
    removeOnFail: false,
    removeOnStop: false,
    progressThrottle: 5000,
    fileName: 'download.mp4',
    override: true
});
// ---------------------------------------------------[FIX]
download.getTotalSize = function () {
    const headers = Object.assign({}, this.__headers);
    if (headers.hasOwnProperty('range')) {
        delete headers['range'];
    }
    return new Promise((resolve, reject) => {
        const getRequest = (url, options) => {
            const req = this.__protocol.request(options, response => {
                if (this.__isRequireRedirect(response)) {
                    const redirectedURL = /^https?:\/\//.test(response.headers.location)
                        ? response.headers.location
                        : new URL(response.headers.location, url).href;
                    return getRequest(redirectedURL, this.__getOptions('HEAD', redirectedURL, headers));
                }
                if (response.statusCode !== 200) {
                    return reject(new Error(`Response status was ${response.statusCode}`));
                }
                resolve({
                    name: this.__getFileNameFromHeaders(response.headers, response),
                    total: parseInt(response.headers['content-length']) || null
                });
            });
            req.on('error', (err) => reject(err));
            req.on('timeout', () => reject(new Error('timeout')));
            req.on('uncaughtException', (err) => reject(err));
            req.end();
        };
        getRequest(this.url, this.__getOptions('HEAD', this.url, headers));
    });
};
// ---------------------------------------------------[END FIX]

download
    .on('progress.throttled', stats => console.log(`Download @ ${Math.ceil(stats.progress)}%`))
    .on('error', err => console.log(`Download failed 1`, err))
    .on('end', () => console.log(`Download completed`));
download
    .start()
    .catch(err => console.log(`Download failed 2`, err));
bbreukelen commented 2 years ago

Brilliant, that works fine, also when resuming a file. Thanks a lot!

hgouveia commented 2 years ago

Fixed on 2.1.1 please upgrade, thanks!