Nothing
#' Download a file
#'
#' Uses either the curl package for R versions older than 3.2.0,
#' otherwise a wrapper around [download.file()].
#'
#' We respect the `download.file.method` setting of the user. If it is
#' not set, then see `download_method()` for choosing a method.
#'
#' Authentication can be supplied three ways:
#' * By setting `auth_token`. This will append an HTTP `Authorization`
#' header: `Authorization: token {auth_token}`.
#' * By setting `basic_auth` to a list with elements `user` and `password`.
#' This will append a proper `Authorization: Basic {encoded_password}`
#' HTTP header.
#' * By specifying the proper `headers` directly.
#'
#' If both `auth_token` and `basic_auth` are specified, that's an error.
#' `auth_token` and `basic_auth` are _appended_ to `headers`, so they
#' take precedence over an `Authorization` header that is specified
#' directly in `headers`.
#'
#' @param path Path to download to. `dirname(path)` must exist.
#' @param url URL.
#' @param auth_token Token for token-based authentication or `NULL`.
#' @param basic_auth List with `user` and `password` for basic HTTP
#' authentication, or `NULL`.
#' @param quiet Passed to [download.file()] or [curl::curl_download()].
#' @param headers Named character vector of HTTP headers to use.
#' @return `path`, if the download was successful.
#'
#' @keywords internal
#' @importFrom utils compareVersion
download <- function(path, url, auth_token = NULL, basic_auth = NULL,
quiet = TRUE, headers = NULL) {
if (!is.null(basic_auth) && !is.null(auth_token)) {
stop("Cannot use both Basic and Token authentication at the same time")
}
if (!is.null(basic_auth)) {
userpass <- paste0(basic_auth$user, ":", basic_auth$password)
auth <- paste("Basic", base64_encode(charToRaw(userpass)))
headers <- c(headers, Authorization = auth)
}
if (!is.null(auth_token)) {
headers <- c(headers, Authorization = paste("token", auth_token))
}
if (getRversion() < "3.2.0") {
curl_download(url, path, quiet, headers)
} else {
base_download(url, path, quiet, headers)
}
path
}
base_download <- function(url, path, quiet, headers) {
method <- download_method()
status <- if (method == "wget") {
base_download_wget(url, path, quiet, headers)
} else if (method =="curl") {
base_download_curl(url, path, quiet, headers)
} else if (getRversion() < "3.6.0") {
base_download_noheaders(url, path, quiet, headers, method)
} else {
base_download_headers(url, path, quiet, headers, method)
}
if (status != 0) stop("Cannot download file from ", url, call. = FALSE)
path
}
base_download_wget <- function(url, path, quiet, headers) {
extra <- getOption("download.file.extra")
if (length(headers)) {
qh <- shQuote(paste0(names(headers), ": ", headers))
extra <- c(extra, paste0("--header=", qh))
}
with_options(
list(download.file.extra = extra),
suppressWarnings(
utils::download.file(
url,
path,
method = "wget",
quiet = quiet,
mode = "wb",
extra = extra
)
)
)
}
base_download_curl <- function(url, path, quiet, headers) {
extra <- getOption("download.file.extra")
# always add `-L`, so that curl follows redirects. GitHub in particular uses
# 302 redirects extensively, so without -L these requests fail.
extra <- c(extra, "--fail", "-L")
if (length(headers)) {
qh <- shQuote(paste0(names(headers), ": ", headers))
extra <- c(extra, paste("-H", qh))
}
with_options(
list(download.file.extra = extra),
suppressWarnings(
utils::download.file(
url,
path,
method = "curl",
quiet = quiet,
mode = "wb",
extra = extra
)
)
)
}
base_download_noheaders <- function(url, path, quiet, headers, method) {
if (length(headers)) {
if (method == "wininet" && getRversion() < "3.6.0") {
warning(paste(
"R (< 3.6.0) cannot send HTTP headers with the `wininet` download method.",
"This download will likely fail. Please choose a different download",
"method, via the `download.file.method` option. The `libcurl` method is",
"best, if available, and the `wget` and `curl` methods work as well,",
"if the corresponding external tool is available. See `?download.file`"))
}
get("unlockBinding", baseenv())("makeUserAgent", asNamespace("utils"))
orig <- get("makeUserAgent", envir = asNamespace("utils"))
on.exit({
assign("makeUserAgent", orig, envir = asNamespace("utils"))
lockBinding("makeUserAgent", asNamespace("utils"))
}, add = TRUE)
ua <- orig(FALSE)
flathead <- paste0(names(headers), ": ", headers, collapse = "\r\n")
agent <- paste0(ua, "\r\n", flathead)
assign(
"makeUserAgent",
envir = asNamespace("utils"),
function(format = TRUE) {
if (format) {
paste0("User-Agent: ", agent, "\r\n")
} else {
agent
}
})
}
suppressWarnings(
utils::download.file(
url,
path,
method = method,
quiet = quiet,
mode = "wb"
)
)
}
base_download_headers <- function(url, path, quiet, headers, method) {
suppressWarnings(
utils::download.file(
url,
path,
method = method,
quiet = quiet,
mode = "wb",
headers = headers
)
)
}
has_curl <- function() isTRUE(unname(capabilities("libcurl")))
download_method <- function() {
user_option <- getOption("download.file.method")
if (!is.null(user_option)) {
## The user wants what the user wants
user_option
} else if (has_curl()) {
## If we have libcurl, it is usually the best option
"libcurl"
} else if (compareVersion(get_r_version(), "3.3") == -1 &&
os_type() == "windows") {
## Before 3.3 we select wininet on Windows
"wininet"
} else {
## Otherwise this is probably hopeless, but let R select, and
## try something
"auto"
}
}
curl_download <- function(url, path, quiet, headers) {
if (!pkg_installed("curl")) {
stop("The 'curl' package is required if R is older than 3.2.0")
}
handle <- curl::new_handle()
if (!is.null(headers)) curl::handle_setheaders(handle, .list = headers)
curl::curl_download(url, path, quiet = quiet, mode = "wb", handle = handle)
}
true_download_method <- function(x) {
if (identical(x, "auto")) {
auto_download_method()
} else {
x
}
}
auto_download_method <- function() {
if (isTRUE(capabilities("libcurl"))) {
"libcurl"
} else if (isTRUE(capabilities("http/ftp"))) {
"internal"
} else if (nzchar(Sys.which("wget"))) {
"wget"
} else if (nzchar(Sys.which("curl"))) {
"curl"
} else {
""
}
}
download_method_secure <- function() {
method <- true_download_method(download_method())
if (method %in% c("wininet", "libcurl", "wget", "curl")) {
# known good methods
TRUE
} else if (identical(method, "internal")) {
# only done before R 3.3
if (utils::compareVersion(get_r_version(), "3.3") == -1) {
# if internal then see if were using windows internal with inet2
identical(Sys.info()[["sysname"]], "Windows") && utils::setInternet2(NA)
} else {
FALSE
}
} else {
# method with unknown properties (e.g. "lynx") or unresolved auto
FALSE
}
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.