16827: Don't append '/' to requests with query params. Bump version
[arvados.git] / sdk / R / R / HttpRequest.R
index f5c11a176fd16fd1c14e9c365d24dd6aafbc369d..18b36f96898c2fa1be1d2e512a2fb158ac94294a 100644 (file)
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+
 HttpRequest <- R6::R6Class(
 
     "HttrRequest",
 
     public = list(
 
-        initialize = function() 
-        {
-        },
+        validContentTypes = NULL,
+        validVerbs = NULL,
 
-        GET = function(url, headers = NULL, queryFilters = NULL, limit = NULL, offset = NULL)
+        initialize = function()
         {
-            headers <- httr::add_headers(unlist(headers))
-            query <- private$createQuery(queryFilters, limit, offset)
-            url <- paste0(url, query)
-
-            serverResponse <- httr::GET(url = url, config = headers)
+            self$validContentTypes <- c("text", "raw")
+            self$validVerbs <- c("GET", "POST", "PUT", "DELETE", "PROPFIND", "MOVE", "COPY")
         },
 
-        PUT = function(url, headers = NULL, body = NULL,
-                       queryFilters = NULL, limit = 100, offset = 0)
+        exec = function(verb, url, headers = NULL, body = NULL, queryParams = NULL,
+                        retryTimes = 0)
         {
-            headers <- httr::add_headers(unlist(headers))
-            query <- private$createQuery(queryFilters, limit, offset)
-            url <- paste0(url, query)
+            if(!(verb %in% self$validVerbs))
+                stop("Http verb is not valid.")
 
-            serverResponse <- httr::PUT(url = url, config = headers, body = body)
-        },
+            urlQuery <- self$createQuery(queryParams)
+            url      <- paste0(url, urlQuery)
 
-        POST = function(url, headers = NULL, body = NULL,
-                        queryFilters = NULL, limit = 100, offset = 0)
-        {
-            headers <- httr::add_headers(unlist(headers))
-            query <- private$createQuery(queryFilters, limit, offset)
-            url <- paste0(url, query)
+            config <- httr::add_headers(unlist(headers))
+            if(toString(Sys.getenv("ARVADOS_API_HOST_INSECURE") == "TRUE"))
+               config$options = list(ssl_verifypeer = 0L)
 
-            serverResponse <- httr::POST(url = url, config = headers, body = body)
+            # times = 1 regular call + numberOfRetries
+            response <- httr::RETRY(verb, url = url, body = body,
+                                    config = config, times = retryTimes + 1)
         },
 
-        DELETE = function(url, headers = NULL, body = NULL,
-                          queryFilters = NULL, limit = NULL, offset = NULL)
+        createQuery = function(queryParams)
         {
-            headers <- httr::add_headers(unlist(headers))
-            query <- private$createQuery(queryFilters, limit, offset)
-            url <- paste0(url, query)
-
-            serverResponse <- httr::DELETE(url = url, config = headers)
-        },
+            queryParams <- Filter(Negate(is.null), queryParams)
 
-        PROPFIND = function(url, headers = NULL)
-        {
-            h <- curl::new_handle()
-            curl::handle_setopt(h, customrequest = "PROPFIND")
-            curl::handle_setheaders(h, .list = headers)
-
-            propfindResponse <- curl::curl_fetch_memory(url, h)
-        }
-    ),
-
-    private = list(
-
-        #Todo(Fudo): Refactor this and find a better way to build
-        # Python array from R list (recursion?)
-        createQuery = function(filters, limit, offset)
-        {
-            finalQuery <- NULL
-
-            if(!is.null(filters))
+            query <- sapply(queryParams, function(param)
             {
-                filters <- sapply(filters, function(filter)
-                {
-                    if(length(filter) != 3)
-                        stop("Filter list must have exacthey 3 elements.")
-
-                    attributeAndOperator = filter[c(1, 2)]
-                    filterList = filter[[3]]
-                    filterListIsPrimitive = TRUE
-                    if(length(filterList) > 1)
-                        filterListIsPrimitive = FALSE
+                if(is.list(param) || length(param) > 1)
+                    param <- RListToPythonList(param, ",")
 
-                    attributeAndOperator <- sapply(attributeAndOperator, function(component) {
-                        component <- paste0("\"", component, "\"")
-                    })
+                URLencode(as.character(param), reserved = T, repeated = T)
 
-                    filterList <- sapply(unlist(filterList), function(filter) {
-                        filter <- paste0("\"", filter, "\"")
-                    })
+            }, USE.NAMES = TRUE)
 
-                    filterList <- paste(filterList, collapse = ",+")
-
-                    if(!filterListIsPrimitive)
-                        filterList <- paste0("[", filterList, "]")
-
-                    filter <- c(attributeAndOperator, filterList)
-
-                    queryParameter <- paste(filter, collapse = ",+")
-                    queryParameter <- paste0("[", queryParameter, "]")
-        
-                })
-
-                filters <- paste(filters, collapse = ",+")
-                filters <- paste0("[", filters, "]")
-
-                encodedQuery <- URLencode(filters, reserved = T, repeated = T)
-
-                #Todo(Fudo): This is a hack for now. Find a proper solution.
-                encodedQuery <- stringr::str_replace_all(encodedQuery, "%2B", "+")
-
-                finalQuery <- c(finalQuery, paste0("filters=", encodedQuery))
+            if(length(query) > 0)
+            {
+                query <- paste0(names(query), "=", query, collapse = "&")
 
-                finalQuery
+                return(paste0("?", query))
             }
 
-            if(!is.null(limit))
-            {
-                if(!is.numeric(limit))
-                    stop("Limit must be a numeric type.")
-                
-                finalQuery <- c(finalQuery, paste0("limit=", limit))
-            }
+            return("")
+        },
 
-            if(!is.null(offset))
-            {
-                if(!is.numeric(offset))
-                    stop("Offset must be a numeric type.")
-                
-                finalQuery <- c(finalQuery, paste0("offset=", offset))
-            }
+        getConnection = function(url, headers, openMode)
+        {
+            h <- curl::new_handle()
+            curl::handle_setheaders(h, .list = headers)
 
-            if(length(finalQuery) > 1)
-            {
-                finalQuery <- paste0(finalQuery, collapse = "&")
-                finalQuery <- paste0("?", finalQuery)
-            }
+            if(toString(Sys.getenv("ARVADOS_API_HOST_INSECURE") == "TRUE"))
+               curl::handle_setopt(h, ssl_verifypeer = 0L)
 
-            finalQuery
+            conn <- curl::curl(url = url, open = openMode, handle = h)
         }
     ),