Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ docs
^docs$
^pkgdown$
^\.github$
^.*\.code-workspace$
^revdep$
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: dataone
Version: 2.3.0
Date: 2025-10-08
Date: 2025-12-05
Title: R Interface to the DataONE REST API
Authors@R: c( person("Matthew B.", "Jones", role = c("aut","cre"), email = "jones@nceas.ucsb.edu", comment=c(ORCID = "0000-0003-0077-4738")),
person("Peter", "Slaughter", role = "aut", email = "slaughter@nceas.ucsb.edu", comment=c(ORCID = "0000-0002-2192-403X")),
Expand Down
8 changes: 8 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# Version 2.3.0

## Bug Fixes

* Fix documentaion links and cross-references (#306)
* isCertExpired() test produces timezone mismatch warning (#304)
* Fix windows TLS error by forcing TLS 1.2 client side (#308)

# Version 2.2.2

## New Features and functions
Expand Down
18 changes: 11 additions & 7 deletions R/CNode.R
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,16 @@ setMethod("CNode", signature("character"), function(x) {
else stop(sprintf("Unknown DataONE environment: %s", x))
}

## create new D1Client object and insert uri endpoint
## create new CNode object and insert uri endpoint
result <- new("CNode")
# Get the node listing for just this CN using just the baseURL, as we don't know the API version number
# yet that is needed to construct the service URL.
response <- GET(CN_URI)
nconfig <- httr::config()
if (is_windows()) {
# On windows, TLS 1.3 is not supported, so we need to force TLS 1.2
nconfig <- c(nconfig, config(sslversion = 6L) ) # 6L corresponds to CURL_SSLVERSION_TLSv1_2
}
response <- GET(CN_URI, config = nconfig)
if(response$status_code != "200") {
stop(sprintf("Error accessing %s: %s\n", CN_URI, getErrorDescription(response)))
}
Expand Down Expand Up @@ -161,7 +166,7 @@ setGeneric("listFormats", function(x, ...) {
#' @export
setMethod("listFormats", signature("CNode"), function(x) {
url <- paste(x@endpoint,"formats",sep="/")
response <- GET(url, user_agent(get_user_agent()))
response <- auth_get(url, nconfig = user_agent(get_user_agent()), node=x)
# Use charset 'utf-8' if not specified in response headers
charset <- "utf-8"
if("content-type" %in% names(response$headers)) {
Expand Down Expand Up @@ -225,7 +230,7 @@ setGeneric("getFormat", function(x, ...) {
#' @export
setMethod("getFormat", signature("CNode"), function(x, formatId) {
url <- paste(x@endpoint,"formats", URLencode(formatId, reserved=T), sep="/")
response <- GET(url, user_agent(get_user_agent()))
response <- auth_get(url, nconfig = user_agent(get_user_agent()), node=x)

if(response$status_code != "200") {
return(NULL)
Expand All @@ -250,7 +255,7 @@ setMethod("getFormat", signature("CNode"), function(x, formatId) {
#' }
setMethod("getChecksum", signature("CNode"), function(x, pid, ...) {
url <- paste(x@endpoint, "checksum", URLencode(pid, reserved=T), sep="/")
response <- GET(url, user_agent(get_user_agent()))
response <- auth_get(url, nconfig = user_agent(get_user_agent()), node=x)
if (is.raw(response$content)) {
tmpres <- content(response, as="raw")
resultText <- rawToChar(tmpres)
Expand Down Expand Up @@ -295,8 +300,7 @@ setMethod("listNodes", signature("CNode"), function(x, url=as.character(NA), ...
if(is.na(url)) {
url <- paste(x@endpoint, "node", sep="/")
}
# Don't need authorized access, so call GET directly vs auth_get
response <- GET(url)
response <- auth_get(url, nconfig = user_agent(get_user_agent()), node=x)
if(response$status_code != "200") {
return(NULL)
}
Expand Down
1 change: 0 additions & 1 deletion R/D1Client.R
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,6 @@ setGeneric("getD1Object", function(x, identifier, ...) {

#' @rdname getD1Object
setMethod("getD1Object", "D1Client", function(x, identifier) {
#d1o <- get(x@cn, identifier) # Resolve the object location
return(getDataObject(x, identifier))
})

Expand Down
13 changes: 9 additions & 4 deletions R/D1Node.R
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ setMethod("getQueryEngineDescription", signature("D1Node"), function(x, queryEng

url <- paste(x@endpoint, "query", queryEngineName, sep="/")
# Send the request
response<-GET(url)
response <- auth_get(url, node=x)
if(response$status_code != "200") {
warning(sprintf("Error getting query engine description %s\n", getErrorDescription(response)))
return(list())
Expand Down Expand Up @@ -439,7 +439,12 @@ setMethod("listObjects", signature("D1Node"), function(x,

url <- paste(x@endpoint, "object", sep="/")
# Send the request
response<-GET(url, query=params)
nconfig <- httr::config()
if (is_windows()) {
# On windows, TLS 1.3 is not supported, so we need to force TLS 1.2
nconfig <- c(nconfig, config(sslversion = 6L) ) # 6L corresponds to CURL_SSLVERSION_TLSv1_2
}
response<-GET(url, config = nconfig, query=params)
if (is.raw(response$content)) {
tmpres <- content(response, as="raw")
resultText <- rawToChar(tmpres)
Expand Down Expand Up @@ -480,7 +485,7 @@ setMethod("listQueryEngines", signature("D1Node"), function(x) {

url <- paste(x@endpoint, "query", sep="/")
# Send the request
response<-GET(url)
response <- auth_get(url, node=x)
if (is.raw(response$content)) {
tmpres <- content(response, as="raw")
resultText <- rawToChar(tmpres)
Expand Down Expand Up @@ -582,7 +587,7 @@ setMethod("ping", signature("D1Node"), function(x) {

url <- paste(x@endpoint, "monitor/ping", sep="/")
# Send the request
response<-GET(url)
response <- auth_get(url, node=x)

if (response$status_code == 200) {
return(TRUE)
Expand Down
7 changes: 6 additions & 1 deletion R/MNode.R
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,12 @@ setMethod("getCapabilities", signature("MNode"), function(x) {
url <- paste(x@endpoint, "node", sep="/")
# Don't need privileged access, so call GET directly vs auth_get

response <- GET(url, user_agent(get_user_agent()))
nconfig <- user_agent(get_user_agent())
if (is_windows()) {
# On windows, TLS 1.3 is not supported, so we need to force TLS 1.2
nconfig <- c(nconfig, config(sslversion = 6L) ) # 6L corresponds to CURL_SSLVERSION_TLSv1_2
}
response <- GET(url, config = nconfig)
# Use charset 'utf-8' if not specified in response headers
charset <- "utf-8"
if(response$status_code != "200") {
Expand Down
33 changes: 26 additions & 7 deletions R/auth_request.R
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ auth_get <- function(url, nconfig=config(), node, path = NULL) {
if (missing(url) || missing(node)) {
stop("Error: url or node is missing. Please report this error.")
}
if (is_windows()) {
# On windows, TLS 1.3 is not supported, so we need to force TLS 1.2
nconfig <- c(nconfig, config(sslversion = 6L) ) # 6L corresponds to CURL_SSLVERSION_TLSv1_2
}
am <- AuthenticationManager()
if(isAuthValid(am, node)) {
if(getAuthMethod(am, node) == "token") {
Expand Down Expand Up @@ -125,6 +129,10 @@ auth_head <- function(url, nconfig=config(), node) {
if (missing(url) || missing(node)) {
stop("Error: url or node is missing. Please report this error.")
}
if (is_windows()) {
# On windows, TLS 1.3 is not supported, so we need to force TLS 1.2
nconfig <- c(nconfig, config(sslversion = 6L) ) # 6L corresponds to CURL_SSLVERSION_TLSv1_2
}
am <- AuthenticationManager()
if(isAuthValid(am, node)) {
if(getAuthMethod(am, node) == "token") {
Expand Down Expand Up @@ -159,23 +167,27 @@ auth_head <- function(url, nconfig=config(), node) {
#' @return the response object from the method
#' @import httr
auth_put_post_delete <- function(method, url, encode="multipart", body=NULL, node) {

nconfig <- httr::config(user_agent(get_user_agent()))
if (is_windows()) {
# On windows, TLS 1.3 is not supported, so we need to force TLS 1.2
nconfig <- c(config(sslversion = 6L) ) # 6L corresponds to CURL_SSLVERSION_TLSv1_2
}
am <- AuthenticationManager()
if(!missing(node) && isAuthValid(am, node)) {
if(getAuthMethod(am, node) == "token") {
# Authentication will use an authentication token.
authToken <- getToken(am, node)
switch(method,
post={
response=POST(url, encode=encode, body=body, config(tcp_keepalive = as.numeric(1)), add_headers(Authorization = sprintf("Bearer %s", authToken)), user_agent(get_user_agent()))
response=POST(url, encode=encode, body=body, nconfig, config(tcp_keepalive = as.numeric(1)), add_headers(Authorization = sprintf("Bearer %s", authToken)))
return(response)
},
put={
response=PUT(url, encode=encode, body=body, add_headers(Authorization = sprintf("Bearer %s", authToken)), user_agent(get_user_agent()))
response=PUT(url, encode=encode, body=body, nconfig, add_headers(Authorization = sprintf("Bearer %s", authToken)))
return(response)
},
delete={
response=DELETE(url, encode=encode, body=body, add_headers(Authorization = sprintf("Bearer %s", authToken)), user_agent(get_user_agent()))
response=DELETE(url, encode=encode, body=body, nconfig, add_headers(Authorization = sprintf("Bearer %s", authToken)))
return(response)},
{
stop('Method not supported.')
Expand All @@ -186,15 +198,15 @@ auth_put_post_delete <- function(method, url, encode="multipart", body=NULL, nod
cert <- getCert(am)
switch(method,
post={
response=POST(url, encode=encode, body=body, config=config(sslcert = cert), user_agent(get_user_agent()))
response=POST(url, encode=encode, body=body, nconfig, config=config(sslcert = cert))
return(response)
},
put={
response=PUT(url, encode=encode, body=body, config=config(sslcert = cert), user_agent(get_user_agent()))
response=PUT(url, encode=encode, body=body, nconfig, config=config(sslcert = cert))
return(response)
},
delete={
response=DELETE(url, encode=encode, body=body, config=config(sslcert = cert), user_agent(get_user_agent()))
response=DELETE(url, encode=encode, body=body, nconfig, config=config(sslcert = cert))
return(response)},
{
stop('Method not supported.')
Expand Down Expand Up @@ -277,4 +289,11 @@ get_user_agent <- function() {
paste(info$R.version$major, info$R.version$minor, sep="."),
httrVersion)
return(local_agent)
}

#' Is the OS Windows?
#' @description Check if the current operating system is Windows.
#' @return TRUE if the OS is Windows, FALSE otherwise.
is_windows <- function() {
return(.Platform$OS.type == "windows")
}
34 changes: 33 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
- [Package source code on Github](https://github.com/DataONEorg/rdataone)
- [**Submit Bugs and feature requests**](https://github.com/DataONEorg/rdataone/issues)

Provides read and write access to data and metadata from the [DataONE network
Provides read and write access to data and metadata from the global [DataONE network
of data repositories](https://www.dataone.org/network/), including the
[KNB Data Repository](https://knb.ecoinformatics.org), [Dryad](https://datadryad.org/),
and the NSF [Arctic Data Center](https://arcticdata.io) and dozens of other
Expand Down Expand Up @@ -73,6 +73,38 @@ library(dataone)

The *dataone* R package should be available for use at this point.

### Windows issues with TLS 1.3

Some users report problems with curl on Windows recently failing to connect when using TLS 1.3 connections, with the following error:

```
> library(dataone)
> cn <- CNode("PROD")
Error in curl::curl_fetch_memory(url, handle = handle) :
Failure when receiving data from the peer [cn.dataone.org]:
schannel: failed to read data from server: SEC_E_CONTEXT_EXPIRED (0x80090317) - The context has expired and can no longer be used.
```

This seems to be associated with changes to the Schannel SSL backend on Windows in how it handles requests for client-side x509 certificates under TLS1.3, which no longer functions properly under Windows. Switching to using the OpenSSL backend (as described in [issue #308](https://github.com/DataONEorg/rdataone/issues/308#issue-3471229735)) seems to fix the problem but is probably not a great long-term solution. Here's a workaround by setting an environment variable to tell curl to use the OpenSSL backend:

```
write('CURL_SSL_BACKEND=openssl', file = "~/.Renviron", append = TRUE)
```
Restart the R session and verify that OpenSSL is now active (no longer in parenthesis):

```
> curl::curl_version()$ssl_version
Initiating curl with CURL_SSL_BACKEND: openssl
[1] "OpenSSL/3.5.0 (Schannel)"
```

Now, try the code again and it should work:

```
> library(dataone)
> cn <- CNode("PROD")
```

## Quick Start

See the full manual (`help(dataone)`) for documentation.
Expand Down
36 changes: 11 additions & 25 deletions cran-comments.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,17 @@
## Test environments
Dear CRAN maintainers,

* macOS 13.7.6: R 4.5.1

* Ubuntu 18.04 R 4.1.3
* Windows (via win-builder): x86_64-w64-mingw32 (64-bit) R Under development (unstable) (2022-06-08 r82470 ucrt)
* Windows (via win-builder): x86_64-w64-mingw32 (64-bit) R 4.2.0 (2022-04-22 ucrt)
* Windows (via win-builder): x86_64-w64-mingw32 (64-bit) R 4.1.3 (2022-03-10)
* rhub::check_for_cran()
* Windows Server 2008 R2 SP1, R-release, 32/64 bit
* Windows Server 2022, R-devel, 64 bit
* Fedora Linux, R-devel, clang, gfortran
* Fedora Linux, R-devel, GCC
* macOS 10.13.6 High Sierra, R-release, CRAN's setup
* Apple Silicon (M1), macOS 11.6 Big Sur, R-release
Please find a new release of the R package 'dataone' for your consideration. This package was recently archived because I had been unable to fix issues with TLS 1.3 support on Windows clients. I have temporarily disabled TLS 1.3 support and fallback to TLS 1.2 in the underlying 'curl' package on windows clients, which has resolved the issue. I will continue to investigate a more permanent solution for future releases, but it seems that Windows clients are not yet fully compatible with TLS 1.3 (see https://windowsforum.com/threads/tls-1-3-iis-express-on-windows-11-mtls-breakage-workarounds-and-outlook.379408/).

## Changes since last release
## Test environments

* Remove hash dependency (#293)
* Add support for new method signature for D1Client (#252)
* Ensure rightsHolder persists when uploading a data package (#292)
* Fix bug where 'publc = TRUE' argument did not set public read on all objects (#285)
* Account for edge case errors in 'archive()' (#236)
* Windows (via win-builder): x86_64-w64-mingw32 (64-bit) R version 4.5.2 (2025-10-31 ucrt)
* Windows (via win-builder): x86_64-w64-mingw32 (64-bit) R Under development (unstable) (2025-12-04 r89100 ucrt)
* macOS Sequoia 15.7.2: aarch64-apple-darwin20 R version 4.5.2 (2025-10-31)
* macOS Ventura 13.7.6: aarch64-apple-darwin20 R version 4.5.2 (2025-10-31)
* Ubuntu 24.04.3 LTS: x86_64-pc-linux-gnu R version 4.5.2 (2025-10-31)
* Ubuntu 24.04.3 LTS: x86_64-pc-linux-gnu R version 4.4.3 (2025-02-28)
* Ubuntu 24.04.3 LTS: x86_64-pc-linux-gnu R Under development (unstable) (2025-12-02 r89085)

## R CMD check results

* There were no NOTEs, ERRORs, or WARNINGs.

## Downstream dependencies

* The downstream dependencies have been checked with revdepcheck::revdep_check(), without any problems being reported.
* There were no NOTEs, ERRORs, or WARNINGs except for those related to this being a new package submission after archive, and a false positive on a spelling check for a proper noun.
Loading
Loading