Skip to content

File download.file() does not follow 302 redirects in Node.js [PATCH] #585

@HenrikBengtsson

Description

@HenrikBengtsson

It looks like download.file() does not follow redirected URLs.

Example

$ node webR-download.file.bug.js 
Node.js v v20.19.5
webR v0.5.7


download.file(<redirecting URL>):
Error fetching https://cran.r-universe.dev/bin/emscripten/contrib/4.5/listenv_0.10.0.tgz - Found. Redirecting to https://cdn.r-universe.dev/d9f4c99b3ea4a96ae2b5782941df7524a288a7bb26efb4c95caaca25e09bf6ac
trying URL 'https://cran.r-universe.dev/bin/emscripten/contrib/4.5/listenv_0.10.0.tgz'
Warning in download.file("https://cran.r-universe.dev/bin/emscripten/contrib/4.5/listenv_0.10.0.tgz",  :
  URL https://cran.r-universe.dev/bin/emscripten/contrib/4.5/listenv_0.10.0.tgz: Download failed. See the Javascript console for further information
Error: download from 'https://cran.r-universe.dev/bin/emscripten/contrib/4.5/listenv_0.10.0.tgz' failed


download.file(<directing URL>):
trying URL 'https://cdn.r-universe.dev/d9f4c99b3ea4a96ae2b5782941df7524a288a7bb26efb4c95caaca25e09bf6ac'
Success: TRUE

where webR-download.file.bug.js:

import { WebR } from "webr";
import WebSocket from "ws";

async function webr_eval_code(code) {
    let shelter = await new webR.Shelter()
    let result = await shelter.captureR(code, {
        withAutoprint: true,
        captureStreams: true,
        captureConditions: false
    })
    for (const { type, data } of result.output) {
        if (type === "stdout") {
            console.log(data);
        } else if (type === "stderr") {
            console.error(data);
        }
    }
    shelter.purge();
    return result;
}

console.log('Node.js v', process.version);

// Launch webR instance
const webR = new WebR();
await webR.init();
console.log("webR v" + webR.version);

console.log("\n\ndownload.file(<redirecting URL>):");
await webr_eval_code([
    'download.file("https://cran.r-universe.dev/bin/emscripten/contrib/4.5/listenv_0.10.0.tgz", "foo.tgz", mode = "wb")',
    'message("Success: ", file.exists("foo.tgz"))'
]);

console.log("\n\ndownload.file(<directing URL>):");
await webr_eval_code([
    'download.file("https://cdn.r-universe.dev/d9f4c99b3ea4a96ae2b5782941df7524a288a7bb26efb4c95caaca25e09bf6ac", "foo.tgz", mode = "wb")',
    'message("Success: ", file.exists("foo.tgz"))'
]);

process.exit(0);
$ curl --head https://cran.r-universe.dev/bin/emscripten/contrib/4.5/listenv_0.10.0.tgz
HTTP/2 302 
date: Tue, 16 Dec 2025 04:17:33 GMT
content-type: text/plain; charset=utf-8
content-length: 113
location: https://cdn.r-universe.dev/d9f4c99b3ea4a96ae2b5782941df7524a288a7bb26efb4c95caaca25e09bf6ac
server: cloudflare
x-powered-by: Express
access-control-allow-origin: *
cache-control: public, max-age=600
etag: W/"69194daf7b41ac9b6d02461c32"
last-modified: Tue, 16 Dec 2025 04:08:13 GMT
vary: Accept, accept-encoding
x-runiverse-cache: EXPIRED
age: 585
cf-cache-status: HIT
report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=kaEAPaGvD6zXJVNeTbIMmd3Fai3K66JatcYEANCek4Au05l0stmkqFnIuhkfzRlqDNkWPhkE%2BlOlQgOtN32dKlIAMFDxhgnruSQPIT%2BKDiCI"}]}
nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
cf-ray: 9aeb5f2a880aa43c-SJC
alt-svc: h3=":443"; ma=86400

PS. I think the culprit is in downloadFileContent(). I might have a patch, but need to test it a bit more. Stay tuned.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions