fetch.js
function get(address, contentType, redirs = 0, tries = 0) {
    return new Promise((fulfill, reject) => {
        const { host, path } = url.parse(address);
        const options = {
            headers: { 'User-Agent': 'peerio-updater/1.0' },
            timeout: REQUEST_TIMEOUT,
            host,
            path
        };
        const req = https.get(options, res => {
            if (res.statusCode === 404) {
                reject(new Error(`Not found: ${address}`));
                return;
            }
            if (res.statusCode >= 300 && res.statusCode < 400 && res.headers['location']) {
                res.resume();
                if (redirs >= MAX_REDIRECTS) {
                    reject(new Error('Too many redirects'));
                    return;
                }
                let location = res.headers['location']; // always string according to Node docs
                if (!/^https?:/.test(location)) {
                    location = url.resolve(address, location);
                }
                if (!location.startsWith('https:')) {
                    reject(new Error(`Unsafe redirect to ${location}`));
                    return;
                }
                fulfill(get(location, contentType, redirs + 1, tries));
                return;
            }
            if (res.statusCode !== 200) {
                res.resume();
                if (tries < MAX_RETRIES) {
                    fulfill(waitBeforeRetry(tries).then(() =>
                        get(address, contentType, 0, tries + 1))
                    );
                } else {
                    reject(new Error(`Request failed with status ${res.statusCode}`));
                }
                return;
            }
            if (contentType) {
                let got = res.headers['content-type'] || '';
                // Strip anything after ';' (e.g. application/json; charset=utf8)
                const semicolon = got.indexOf(';')
                if (semicolon >= 0) got = got.substring(0, semicolon);
                if (contentType !== got) {
                    res.resume();
                    reject(new Error(`Unexpected content type: ${got}`));
                    return;
                }
            }
            fulfill(res);
        });

        const handleError = err => {
            if (tries < MAX_RETRIES) {
                fulfill(waitBeforeRetry(tries).then(() =>
                    get(address, contentType, 0, tries + 1))
                );
            } else {
                reject(new Error(`Request failed: ${err.message}`));
            }
        };

        req.on('error', handleError);
        req.on('timeout', () => {
            req.abort();
            handleError(new Error('Request timed out'));
        });
    });
}
function get(address, contentType, redirs = 0, tries = 0) {
    return new Promise((fulfill, reject) => {
        const { host, path } = url.parse(address);
        const options = {
            headers: { 'User-Agent': 'peerio-updater/1.0' },
            timeout: REQUEST_TIMEOUT,
            host,
            path
        };
        const req = https.get(options, res => {
            if (res.statusCode === 404) {
                reject(new Error(`Not found: ${address}`));
                return;
            }
            if (res.statusCode >= 300 && res.statusCode < 400 && res.headers['location']) {
                res.resume();
                if (redirs >= MAX_REDIRECTS) {
                    reject(new Error('Too many redirects'));
                    return;
                }
                let location = res.headers['location']; // always string according to Node docs
                if (!/^https?:/.test(location)) {
                    location = url.resolve(address, location);
                }
                if (!location.startsWith('https:')) {
                    reject(new Error(`Unsafe redirect to ${location}`));
                    return;
                }
                fulfill(get(location, contentType, redirs + 1, tries));
                return;
            }
            if (res.statusCode !== 200) {
                res.resume();
                if (tries < MAX_RETRIES) {
                    fulfill(waitBeforeRetry(tries).then(() =>
                        get(address, contentType, 0, tries + 1))
                    );
                } else {
                    reject(new Error(`Request failed with status ${res.statusCode}`));
                }
                return;
            }
            if (contentType) {
                let got = res.headers['content-type'] || '';
                // Strip anything after ';' (e.g. application/json; charset=utf8)
                const semicolon = got.indexOf(';')
                if (semicolon >= 0) got = got.substring(0, semicolon);
                if (contentType !== got) {
                    res.resume();
                    reject(new Error(`Unexpected content type: ${got}`));
                    return;
                }
            }
            fulfill(res);
        });

        const handleError = err => {
            if (tries < MAX_RETRIES) {
                fulfill(waitBeforeRetry(tries).then(() =>
                    get(address, contentType, 0, tries + 1))
                );
            } else {
                reject(new Error(`Request failed: ${err.message}`));
            }
        };

        req.on('error', handleError);
        req.on('timeout', () => {
            req.abort();
            handleError(new Error('Request timed out'));
        });
    });
}
function get ( address , contentType , redirs = 0 , tries = 0 ) { return new Promise ( ( fulfill , reject ) => { const { host , path } = url . parse ( address ) ; const options = { headers : { 'User-Agent' : 'peerio-updater/1.0' } , timeout : REQUEST_TIMEOUT , host , path } ; const req = https . get ( options , res => { if ( res . statusCode === 404 ) { reject ( new Error ( ` ${ address } ` ) ) ; return ; } if ( res . statusCode >= 300 && res . statusCode < 400 && res . headers [ 'location' ] ) { res . resume ( ) ; if ( redirs >= MAX_REDIRECTS ) { reject ( new Error ( 'Too many redirects' ) ) ; return ; } let location = res . headers [ 'location' ] ; // always string according to Node docs if ( ! / ^https?: / . test ( location ) ) { location = url . resolve ( address , location ) ; } if ( ! location . startsWith ( 'https:' ) ) { reject ( new Error ( ` ${ location } ` ) ) ; return ; } fulfill ( get ( location , contentType , redirs + 1 , tries ) ) ; return ; } if ( res . statusCode !== 200 ) { res . resume ( ) ; if ( tries < MAX_RETRIES ) { fulfill ( waitBeforeRetry ( tries ) . then ( ( ) => get ( address , contentType , 0 , tries + 1 ) ) ) ; } else { reject ( new Error ( ` ${ res . statusCode } ` ) ) ; } return ; } if ( contentType ) { let got = res . headers [ 'content-type' ] || '' ; // Strip anything after ';' (e.g. application/json; charset=utf8) const semicolon = got . indexOf ( ';' ) if ( semicolon >= 0 ) got = got . substring ( 0 , semicolon ) ; if ( contentType !== got ) { res . resume ( ) ; reject ( new Error ( ` ${ got } ` ) ) ; return ; } } fulfill ( res ) ; } ) ; const handleError = err => { if ( tries < MAX_RETRIES ) { fulfill ( waitBeforeRetry ( tries ) . then ( ( ) => get ( address , contentType , 0 , tries + 1 ) ) ) ; } else { reject ( new Error ( ` ${ err . message } ` ) ) ; } } ; req . on ( 'error' , handleError ) ; req . on ( 'timeout' , ( ) => { req . abort ( ) ; handleError ( new Error ( 'Request timed out' ) ) ; } ) ; } ) ; }
Initiates get request and returns a promise resolving to response object.

Handles redirects up to MAX_REDIRECTS.
Repeats on errors (except for 404) up to MAX_RETRIES times.

On success, the response must be fully consumed by the caller to avoid
leaking memory.

@param {string} address - requested URL (must start with `https://`)
@param {string?} [contentType] - expected content-type or undefined/null to not check it
@returns {Promise<https.IncomingMessage>}
Initiates get request and returns a promise resolving to response object .