[med-svn] [r-cran-crul] 01/04: New upstream version 0.4.0

Andreas Tille tille at debian.org
Mon Oct 23 17:23:03 UTC 2017


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository r-cran-crul.

commit 0c4db4576c17c65158c1f55ae2b17fd468c4cdf9
Author: Andreas Tille <tille at debian.org>
Date:   Mon Oct 23 19:19:46 2017 +0200

    New upstream version 0.4.0
---
 DESCRIPTION                   |   8 ++---
 MD5                           |  64 +++++++++++++++++----------------
 NAMESPACE                     |   2 ++
 NEWS.md                       |  20 +++++++++++
 R/body.R                      |  30 ++++++++--------
 R/client.R                    |  80 +++++++++++++++++++++++++++++-------------
 R/cookies.R                   |  42 ++++++++++++++++++++++
 R/handle.R                    |  24 +++++++++++++
 R/httprequest.R               |  21 +++--------
 R/make_url.R                  |  12 ++-----
 R/post-requests.R             |  23 +++++++-----
 R/upload.R                    |  14 ++++++++
 R/writing-options.R           |   4 +--
 R/zzz.R                       |  49 +++++++++++++++++++++-----
 README.md                     |  55 ++++++++++++++++-------------
 build/vignette.rds            | Bin 264 -> 264 bytes
 inst/doc/async.Rmd            |  40 ++++++++++-----------
 inst/doc/async.html           |  40 ++++++++++-----------
 inst/doc/crul_vignette.Rmd    |  53 +++++++++++++++-------------
 inst/doc/crul_vignette.html   |  53 +++++++++++++++-------------
 inst/doc/how-to-use-crul.Rmd  |   8 ++---
 inst/doc/how-to-use-crul.html |   8 ++---
 man/HttpClient.Rd             |  11 ++++--
 man/HttpRequest.Rd            |   2 +-
 man/cookies.Rd                |  47 +++++++++++++++++++++++++
 man/post-requests.Rd          |  23 +++++++-----
 man/upload.Rd                 |  17 +++++++++
 man/writing-options.Rd        |   4 +--
 tests/testthat/test-async.R   |   4 +--
 tests/testthat/test-headers.R |   5 +--
 tests/testthat/test-paths.R   |   1 -
 tests/testthat/test-post.R    |  41 ++++++++++++++++++++++
 vignettes/async.Rmd           |  40 ++++++++++-----------
 vignettes/crul_vignette.Rmd   |  53 +++++++++++++++-------------
 vignettes/how-to-use-crul.Rmd |   8 ++---
 35 files changed, 594 insertions(+), 312 deletions(-)

diff --git a/DESCRIPTION b/DESCRIPTION
index 5a80054..981e75b 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -6,7 +6,7 @@ Description: A simple HTTP client, with tools for making HTTP requests,
     The package name is a play on curl, the widely used command line tool
     for HTTP, and this package is built on top of the R package 'curl', an
     interface to 'libcurl' (<https://curl.haxx.se/libcurl>).
-Version: 0.3.8
+Version: 0.4.0
 License: MIT + file LICENSE
 Authors at R: c(
     person("Scott", "Chamberlain", role = c("aut", "cre"),
@@ -14,15 +14,15 @@ Authors at R: c(
     )
 URL: https://github.com/ropensci/crul
 BugReports: https://github.com/ropensci/crul/issues
-Imports: curl (>= 2.6), R6 (>= 2.2.0), urltools (>= 1.6.0), httpcode
+Imports: curl (>= 2.8.1), R6 (>= 2.2.0), urltools (>= 1.6.0), httpcode
         (>= 0.2.0), mime
 Suggests: testthat, fauxpas (>= 0.1.0), webmockr (>= 0.1.0), knitr,
         jsonlite
 VignetteBuilder: knitr
 RoxygenNote: 6.0.1
 NeedsCompilation: no
-Packaged: 2017-06-13 23:08:55 UTC; sacmac
+Packaged: 2017-10-02 19:34:46 UTC; sacmac
 Author: Scott Chamberlain [aut, cre]
 Maintainer: Scott Chamberlain <myrmecocystus at gmail.com>
 Repository: CRAN
-Date/Publication: 2017-06-15 00:24:32 UTC
+Date/Publication: 2017-10-02 22:41:14 UTC
diff --git a/MD5 b/MD5
index 7e502cf..b52ed66 100644
--- a/MD5
+++ b/MD5
@@ -1,59 +1,63 @@
-54262102efdef0a076fc341ce3c0a9a1 *DESCRIPTION
+09b213a2f33af731a5d703be7099c634 *DESCRIPTION
 c5af52351472a750055a760a8924ce71 *LICENSE
-64a88c3cc94e69cba56f41c7028e35db *NAMESPACE
-ac5d5d245fe9278857e5ce36df5b63d7 *NEWS.md
+36f6a25cae65f5a67840c2251b17a3bf *NAMESPACE
+00beeeae66de780a2352a7c627c6f11a *NEWS.md
 038fea3e8221beba4df24bf3a82f2143 *R/async.R
 58a23acf1db567e90b3423e90d044400 *R/asyncvaried.R
 c672a32ee8516230026a87ce3eed2d82 *R/auth.R
-c6de1547ab52ff1cd67fb5c6aeeac61d *R/body.R
-779bdad5b9684b79c430a95081e32322 *R/client.R
+6d634ea85a8a2473a9fafb80cb30ebf0 *R/body.R
+b1f23ce750e9c9edc8e0a3c43e1db868 *R/client.R
+3c2ac6576b4ce8f80deba972d3ad7d30 *R/cookies.R
 a2d0cf3c78290e92312fedc3ea371c7d *R/crul-package.r
 f158cf1c763e34264ba3267a98aba3c1 *R/curl-options.R
 ce31dc346613d071e58f07d49bdb14eb *R/curl_options.R
 b077080e3625ecf58b23553f8aa33640 *R/delete-requests.R
 8f916ca18e13c4b6c544f2c284b9fabf *R/fetch.R
-47e71e1884900e76d9fe249b4a480fc8 *R/handle.R
+40023de8fc786d542e81b83b887a6dfb *R/handle.R
 7fe1bb2e5890da2188c2f3099ef5ccc1 *R/headers.R
 0cd2754bc2668203d10a1431d2713c4e *R/http-headers.R
-e011c5465b1cb7fc82f7cbd19ef9a210 *R/httprequest.R
-f48ecd3dc67376a23e154bf3c31dbc7d *R/make_url.R
+204e318df39fd88233fde810013323d7 *R/httprequest.R
+3960d3d3d6e9e2e37d9bc787e91d3ad6 *R/make_url.R
 12ad585abb34c0f016f71dc2957ba36f *R/mocking.R
 c24c9f7c882823a79d1d63a0d1d7d48c *R/onLoad.R
-6aa00afab8fd6fe2a1314e9026ab275e *R/post-requests.R
+b470a9d9f573d004bb9fa652075f1046 *R/post-requests.R
 7660da3918e7f65f037f957f9f17b058 *R/proxies.R
 ff10b92e14e29e606593ff962f732b7a *R/query.R
 75ffcf8110f089b7514af5ef01d9024f *R/response.R
 c757ba50136b5b24d9d295ea82a6d3dd *R/stubbed-response.R
+4fadc12ffde03e7588d4f0317c8bc5a2 *R/upload.R
 14c11771d130c3cc4ba9e9f475a2951d *R/use_agent.R
-c92e901a06260e4175002099a617aa60 *R/writing-options.R
-3cf213006f0168dcc61c520a2bcaccb6 *R/zzz.R
-fd0b2c1986cb95d91bc077e22563a172 *README.md
-0ca11f56c5744e9cae3f8996635ec09a *build/vignette.rds
-92dc9cd788c0843421c367fb67d167df *inst/doc/async.Rmd
-3362460f137641def1ff6a6a46a58cf7 *inst/doc/async.html
-825e63b8f0ea15919c61fd6d482897d0 *inst/doc/crul_vignette.Rmd
-e997b5a59446531ad53550cdaf6fe689 *inst/doc/crul_vignette.html
-7b77c12dd2c3a496f35ee648c144686a *inst/doc/how-to-use-crul.Rmd
-263d062b17490370e6c1c8f5f14c72ab *inst/doc/how-to-use-crul.html
+1e0326b2e481b1c05671663f3cc21ded *R/writing-options.R
+e287b0e8ecb69825eea1e9225018b382 *R/zzz.R
+009c773bd60f29fe019ff0b2822f3733 *README.md
+e8ff5788d3db029586ac1974815390c5 *build/vignette.rds
+63d9ba202524c58d790fe0aa193dd090 *inst/doc/async.Rmd
+8f35464cac1852f67d85b73add4b2fbc *inst/doc/async.html
+39534f03007fde66f48bf029dd91e528 *inst/doc/crul_vignette.Rmd
+4fd8a2b6584547ec33c1c8d0052326ad *inst/doc/crul_vignette.html
+6d930e5a6565f6242e3c9a50f339c0a3 *inst/doc/how-to-use-crul.Rmd
+48170834be72e5cc47604d2d745f5622 *inst/doc/how-to-use-crul.html
 4ce0044dbf2746868781235dce58a1d0 *man/Async.Rd
 f7d25bb9f12306064e5869c0e2bc0cd2 *man/AsyncVaried.Rd
-d21d0970e0cfdd86ce362dfd2eb937bb *man/HttpClient.Rd
-6b7e8e8b82a880dbb08cba3b1feaa4ef *man/HttpRequest.Rd
+cf39fa58fd9e99c49d8f0251e557a590 *man/HttpClient.Rd
+deee4f151be7fd6dfd9821e23a283185 *man/HttpRequest.Rd
 8ceb31c33528e8d7e6ce83b7e795ced6 *man/HttpResponse.Rd
 ed69669a250cc2b376ea1d8bedf74193 *man/HttpStubbedResponse.Rd
 af2f8ff1a1d271c642ff558c0aab7ad9 *man/auth.Rd
+c6f5bad94a644a8f655df7207ff66f0a *man/cookies.Rd
 1493a47d3b24e85b4a93a126945f8a45 *man/crul-package.Rd
 158948dd9ddccddd9013c959df1a5a36 *man/curl-options.Rd
 74f5415c416ad5d026bb49471c579452 *man/delete-requests.Rd
 992a0e61803fff336f4ea5b01568ebbc *man/handle.Rd
 5a2be8a76e37279e6a27e43af56e79cf *man/http-headers.Rd
 424b3a1de3812859e94ff209ceddd4d0 *man/mock.Rd
-c3abfb0ae2e49b45c602fdd817078a54 *man/post-requests.Rd
+3576e9d6382c51c7e83b0d07dcc13176 *man/post-requests.Rd
 b8e980c5139ae71b16809c2f2235ec67 *man/proxies.Rd
+2f451daaf7ac19f1b18a8174fcc583e3 *man/upload.Rd
 a1593980eb0f949136935f57df586863 *man/url_build.Rd
-8de29f9d478cf19c85cc8ae51510669e *man/writing-options.Rd
+9d2a329869f402316b3bcb4bf68c59ee *man/writing-options.Rd
 9d086d73e3d68be9f055a6103bf7be39 *tests/test-all.R
-5f166a9ddd900938232b65b17f7f492d *tests/testthat/test-async.R
+ff17e5fe2399153e6a627fded9e7bff0 *tests/testthat/test-async.R
 b69bc5f8b2a540e10094b75064274ffd *tests/testthat/test-asyncvaried.R
 bffa7e3d248142476657230ee4141457 *tests/testthat/test-auth.R
 c73212db04d129aa3f61d6f8cc8e967c *tests/testthat/test-client.R
@@ -61,11 +65,11 @@ c73212db04d129aa3f61d6f8cc8e967c *tests/testthat/test-client.R
 81c982a6d03502e5b48ce38d581e8fe8 *tests/testthat/test-get.R
 162d7395dce79723ab9902c42196aaef *tests/testthat/test-handle.R
 f703252d231c221048dbdd8e74db7a49 *tests/testthat/test-head.R
-4c95ffa8eac589fed3d1b33715d00e0d *tests/testthat/test-headers.R
+eb8f01337fba708050e1cb857384b64a *tests/testthat/test-headers.R
 af5e1e93f7903088d1db4a4bc6fb6565 *tests/testthat/test-mocking.R
 d97a38299ad7f3501b4bfc9aeab50310 *tests/testthat/test-patch.R
-a4606f5df98bf946e95ad53f4e25737c *tests/testthat/test-paths.R
-8e092d174768345a088f0ff4388542e9 *tests/testthat/test-post.R
+2781ddb04413e5703d4b932dd5f1a5e3 *tests/testthat/test-paths.R
+31fba8c2d3fca0387ba7f4cbc4a6a257 *tests/testthat/test-post.R
 3c4202f0d05f093d28d52228c50b9384 *tests/testthat/test-proxies.R
 da00093251bfe73573552e3fa54cc189 *tests/testthat/test-put.R
 4a636b8dcd87c9e911d1178bf93dedde *tests/testthat/test-query.R
@@ -75,6 +79,6 @@ ae1547b89f973f29f0d21fd526ccb7ce *tests/testthat/test-status.R
 6d6424b5f9549bb410a1e31ae9d99f67 *tests/testthat/test-url_build_parse.R
 b66e8ddf24d1ff5ffe66761e00d75a0e *tests/testthat/test-user-agent.R
 11807caff7a89ebc264d38dbdaf2cac3 *tests/testthat/test-utils.R
-92dc9cd788c0843421c367fb67d167df *vignettes/async.Rmd
-825e63b8f0ea15919c61fd6d482897d0 *vignettes/crul_vignette.Rmd
-7b77c12dd2c3a496f35ee648c144686a *vignettes/how-to-use-crul.Rmd
+63d9ba202524c58d790fe0aa193dd090 *vignettes/async.Rmd
+39534f03007fde66f48bf029dd91e528 *vignettes/crul_vignette.Rmd
+6d930e5a6565f6242e3c9a50f339c0a3 *vignettes/how-to-use-crul.Rmd
diff --git a/NAMESPACE b/NAMESPACE
index d5bb316..9e8bc41 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -1,5 +1,6 @@
 # Generated by roxygen2: do not edit by hand
 
+S3method(as.character,form_file)
 export(Async)
 export(AsyncVaried)
 export(HttpClient)
@@ -10,6 +11,7 @@ export(auth)
 export(handle)
 export(mock)
 export(proxy)
+export(upload)
 export(url_build)
 export(url_parse)
 importFrom(R6,R6Class)
diff --git a/NEWS.md b/NEWS.md
index d20bcf6..672f41f 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,3 +1,23 @@
+crul 0.4.0
+==========
+
+### NEW FEATURES
+
+* file uploads now work, see new function `upload()` and examples (#25)
+
+### MINOR IMPROVEMENTS
+
+* fixes to reused curl handles - within a connection object only,
+not across connection objects (#45)
+* `crul` now drops any options passed in to `opts` or to `...` that 
+are not in set of allowed curl options, see `curl::curl_options()` (#49)
+* cookies should now be persisted across requests within 
+a connection object, see new doc `?cookies` for how to set cookies (#44)
+* gather cainfo and use in curl options when applicable (#51)
+* remove `disk` and `stream` from `head` method in `HttpClient` 
+and `HttpRequest` as no body returned in a HEAD request
+
+
 crul 0.3.8
 ==========
 
diff --git a/R/body.R b/R/body.R
index f5c198a..ee393aa 100644
--- a/R/body.R
+++ b/R/body.R
@@ -32,22 +32,24 @@ prep_body <- function(body, encode, type = NULL) {
   if (is.character(body) || is.raw(body)) {
     return(raw_body(body, type = type))
   }
-  if ("files" %in% names(body)) {
-    con <- file(body$files$path, "rb")
-    size <- file.info(body$files$path)$size
+  if (inherits(body, "form_file")) {
+    con <- file(body$path, "rb")
+    size <- file.info(body$path)$size
     return(
       list(
-        post = TRUE,
-        readfunction = function(nbytes, ...) {
-          if (is.null(con)) return(raw())
-          bin <- readBin(con, "raw", nbytes)
-          if (length(bin) < nbytes) {
-            close(con)
-            con <<- NULL
-          }
-          bin
-        },
-        postfieldsize_large = size,
+        opts = list(
+          post = TRUE,
+          readfunction = function(nbytes, ...) {
+            if (is.null(con)) return(raw())
+            bin <- readBin(con, "raw", nbytes)
+            if (length(bin) < nbytes) {
+              close(con)
+              con <<- NULL
+            }
+            bin
+          },
+          postfieldsize_large = size
+        ),
         type = make_type(body$type)
       )
     )
diff --git a/R/client.R b/R/client.R
index 28cb882..ac4f251 100644
--- a/R/client.R
+++ b/R/client.R
@@ -20,7 +20,7 @@
 #'     \item{`delete(path, query, body, disk, stream, ...)`}{
 #'       Make a DELETE request
 #'     }
-#'     \item{`head(path, disk, stream, ...)`}{
+#'     \item{`head(path, ...)`}{
 #'       Make a HEAD request
 #'     }
 #'   }
@@ -43,8 +43,13 @@
 #'  post, postfields, postfieldsize, and customrequest
 #' }
 #'
+#' @section handles:
+#' curl handles are re-used on the level of the connection object, that is,
+#' each `HttpClient` object is separate from one another so as to better
+#' separate connections.
+#'
 #' @seealso [post-requests], [delete-requests], [http-headers],
-#' [writing-options]
+#' [writing-options], [cookies]
 #'
 #' @examples
 #' (x <- HttpClient$new(url = "https://httpbin.org"))
@@ -119,6 +124,7 @@ HttpClient <- R6::R6Class(
     },
 
     initialize = function(url, opts, proxies, auth, headers, handle) {
+      private$crul_h_pool <- new.env(hash = TRUE, parent = emptyenv())
       if (!missing(url)) self$url <- url
       if (!missing(opts)) self$opts <- opts
       if (!missing(proxies)) {
@@ -138,21 +144,17 @@ HttpClient <- R6::R6Class(
     get = function(path = NULL, query = list(), disk = NULL,
                    stream = NULL, ...) {
       curl_opts_check(...)
-      url <- make_url(self$url, self$handle, path, query)
+      url <- private$make_url(self$url, self$handle, path, query)
       rr <- list(
         url = url,
         method = "get",
-        options = list(
-          httpget = TRUE
-        ),
-        headers = list(
-          `User-Agent` = make_ua(),
-          `Accept-Encoding` = 'gzip, deflate'
-        )
+        options = ccp(list(httpget = TRUE, cainfo = find_cert_bundle())),
+        headers = def_head()
       )
       rr$headers <- norm_headers(rr$headers, self$headers)
       rr$options <- utils::modifyList(
         rr$options, c(self$opts, self$proxies, self$auth, ...))
+      rr$options <- curl_opts_fil(rr$options)
       rr$disk <- disk
       rr$stream <- stream
       private$make_request(rr)
@@ -161,7 +163,7 @@ HttpClient <- R6::R6Class(
     post = function(path = NULL, query = list(), body = NULL, disk = NULL,
                     stream = NULL, encode = "multipart", ...) {
       curl_opts_check(...)
-      url <- make_url(self$url, self$handle, path, query)
+      url <- private$make_url(self$url, self$handle, path, query)
       opts <- prep_body(body, encode)
       rr <- prep_opts("post", url, self, opts, ...)
       rr$disk <- disk
@@ -172,7 +174,7 @@ HttpClient <- R6::R6Class(
     put = function(path = NULL, query = list(), body = NULL, disk = NULL,
                    stream = NULL, encode = "multipart", ...) {
       curl_opts_check(...)
-      url <- make_url(self$url, self$handle, path, query)
+      url <- private$make_url(self$url, self$handle, path, query)
       opts <- prep_body(body, encode)
       rr <- prep_opts("put", url, self, opts, ...)
       rr$disk <- disk
@@ -183,7 +185,7 @@ HttpClient <- R6::R6Class(
     patch = function(path = NULL, query = list(), body = NULL, disk = NULL,
                      stream = NULL, encode = "multipart", ...) {
       curl_opts_check(...)
-      url <- make_url(self$url, self$handle, path, query)
+      url <- private$make_url(self$url, self$handle, path, query)
       opts <- prep_body(body, encode)
       rr <- prep_opts("patch", url, self, opts, ...)
       rr$disk <- disk
@@ -194,7 +196,7 @@ HttpClient <- R6::R6Class(
     delete = function(path = NULL, query = list(), body = NULL, disk = NULL,
                       stream = NULL, encode = "multipart", ...) {
       curl_opts_check(...)
-      url <- make_url(self$url, self$handle, path, query)
+      url <- private$make_url(self$url, self$handle, path, query)
       opts <- prep_body(body, encode)
       rr <- prep_opts("delete", url, self, opts, ...)
       rr$disk <- disk
@@ -202,29 +204,58 @@ HttpClient <- R6::R6Class(
       private$make_request(rr)
     },
 
-    head = function(path = NULL, disk = NULL, stream = NULL, ...) {
+    head = function(path = NULL, ...) {
       curl_opts_check(...)
-      url <- make_url(self$url, self$handle, path, NULL)
+      url <- private$make_url(self$url, self$handle, path, NULL)
       opts <- list(customrequest = "HEAD", nobody = TRUE)
       rr <- list(
         url = url,
         method = "head",
-        options = c(
-          opts,
-          useragent = make_ua()
-        ),
+        options = ccp(c(opts, cainfo = find_cert_bundle())),
         headers = self$headers
       )
-      rr$options <- utils::modifyList(rr$options,
-                                      c(self$opts, self$proxies, ...))
-      rr$disk <- disk
-      rr$stream <- stream
+      rr$options <- utils::modifyList(
+        rr$options,
+        c(self$opts, self$proxies, ...))
       private$make_request(rr)
+    },
+
+    handle_pop = function() {
+      name <- handle_make(self$url)
+      if (exists(name, envir = private$crul_h_pool)) {
+        rm(list = name, envir = private$crul_h_pool)
+      }
     }
   ),
 
   private = list(
     request = NULL,
+    crul_h_pool = NULL,
+    handle_find = function(x) {
+      z <- handle_make(x)
+      if (exists(z, private$crul_h_pool)) {
+        handle <- private$crul_h_pool[[z]]
+      } else {
+        handle <- handle(z)
+        private$crul_h_pool[[z]] <- handle
+      }
+      return(handle)
+    },
+
+    make_url = function(url = NULL, handle = NULL, path, query) {
+      if (!is.null(handle)) {
+        url <- handle$url
+      } else {
+        handle <- private$handle_find(url)
+        url <- handle$url
+      }
+      if (!is.null(path)) {
+        urltools::path(url) <- path
+      }
+      url <- gsub("\\s", "%20", url)
+      url <- add_query(query, url)
+      return(list(url = url, handle = handle$handle))
+    },
 
     make_request = function(opts) {
       if (xor(!is.null(opts$disk), !is.null(opts$stream))) {
@@ -247,6 +278,7 @@ HttpClient <- R6::R6Class(
         resp <- crul_fetch(opts)
       }
 
+      # build response
       HttpResponse$new(
         method = opts$method,
         url = resp$url,
diff --git a/R/cookies.R b/R/cookies.R
new file mode 100644
index 0000000..3673cba
--- /dev/null
+++ b/R/cookies.R
@@ -0,0 +1,42 @@
+#' Working with cookies
+#'
+#' @name cookies
+#' @examples
+#' x <- HttpClient$new(
+#'   url = "https://httpbin.org",
+#'   opts = list(
+#'     cookie = "c=1;f=5",
+#'     verbose = TRUE
+#'   )
+#' )
+#' x
+#'
+#' # set cookies
+#' (res <- x$get("cookies"))
+#' jsonlite::fromJSON(res$parse("UTF-8"))
+#'
+#' (x <- HttpClient$new(url = "https://httpbin.org"))
+#' res <- x$get("cookies/set", query = list(foo = 123, bar = "ftw"))
+#' jsonlite::fromJSON(res$parse("UTF-8"))
+#' curl::handle_cookies(handle = res$handle)
+#'
+#' # reuse handle
+#' res2 <- x$get("get", query = list(hello = "world"))
+#' jsonlite::fromJSON(res2$parse("UTF-8"))
+#' curl::handle_cookies(handle = res2$handle)
+#'
+#' # DOAJ
+#' x <- HttpClient$new(url = "https://doaj.org")
+#' res <- x$get("api/v1/journals/f3f2e7f23d444370ae5f5199f85bc100",
+#'   verbose = TRUE)
+#' res$response_headers$`set-cookie`
+#' curl::handle_cookies(handle = res$handle)
+#' res2 <- x$get("api/v1/journals/9abfb36b06404e8a8566e1a44180bbdc",
+#'   verbose = TRUE)
+#'
+#' ## reset handle
+#' x$handle_pop()
+#' ## cookies no longer sent, as handle reset
+#' res2 <- x$get("api/v1/journals/9abfb36b06404e8a8566e1a44180bbdc",
+#'   verbose = TRUE)
+NULL
diff --git a/R/handle.R b/R/handle.R
index a3c8914..63838af 100644
--- a/R/handle.R
+++ b/R/handle.R
@@ -13,3 +13,27 @@
 handle <- function(url, ...) {
   list(url = url, handle = curl::new_handle(...))
 }
+
+handle_pop <- function(url) {
+  name <- handle_make(url)
+  if (exists(name, envir = crul_global_pool)) {
+    rm(list = name, envir = crul_global_pool)
+  }
+}
+
+handle_make <- function(x) {
+  urltools::url_compose(urltools::url_parse(x))
+}
+
+crul_global_pool <- new.env(hash = TRUE, parent = emptyenv())
+
+handle_find <- function(x) {
+  z <- handle_make(x)
+  if (exists(z, crul_global_pool)) {
+    handle <- crul_global_pool[[z]]
+  } else {
+    handle <- handle(z)
+    crul_global_pool[[z]] <- handle
+  }
+  return(handle)
+}
diff --git a/R/httprequest.R b/R/httprequest.R
index 176160a..e53a52f 100644
--- a/R/httprequest.R
+++ b/R/httprequest.R
@@ -33,7 +33,7 @@
 #'     \item{`delete(path, query, body, disk, stream, ...)`}{
 #'       Define a DELETE request
 #'     }
-#'     \item{`head(path, disk, stream, ...)`}{
+#'     \item{`head(path, ...)`}{
 #'       Define a HEAD request
 #'     }
 #'     \item{`method()`}{
@@ -130,14 +130,8 @@ HttpRequest <- R6::R6Class(
       rr <- list(
         url = url,
         method = "get",
-        options = list(
-          httpget = TRUE,
-          useragent = make_ua()
-        ),
-        headers = list(
-          `User-Agent` = make_ua(),
-          `Accept-Encoding` = 'gzip, deflate'
-        )
+        options = ccp(list(httpget = TRUE, cainfo = find_cert_bundle())),
+        headers = def_head()
       )
       rr$headers <- norm_headers(rr$headers, self$headers)
       rr$options <- utils::modifyList(
@@ -196,23 +190,18 @@ HttpRequest <- R6::R6Class(
       return(self)
     },
 
-    head = function(path = NULL, disk = NULL, stream = NULL, ...) {
+    head = function(path = NULL, ...) {
       curl_opts_check(...)
       url <- make_url_async(self$url, self$handle, path, NULL)
       opts <- list(customrequest = "HEAD", nobody = TRUE)
       rr <- list(
         url = url,
         method = "head",
-        options = c(
-          opts,
-          useragent = make_ua()
-        ),
+        options = ccp(c(opts, cainfo = find_cert_bundle())),
         headers = self$headers
       )
       rr$options <- utils::modifyList(rr$options,
                                       c(self$opts, self$proxies, ...))
-      rr$disk <- disk
-      rr$stream <- stream
       self$payload <- rr
       return(self)
     },
diff --git a/R/make_url.R b/R/make_url.R
index 0f7f834..8e917d0 100644
--- a/R/make_url.R
+++ b/R/make_url.R
@@ -2,22 +2,14 @@ make_url <- function(url = NULL, handle = NULL, path, query) {
   if (!is.null(handle)) {
     url <- handle$url
   } else {
-    handle <- list(handle = curl::new_handle())
+    handle <- handle_find(url)
+    url <- handle$url
   }
-
   if (!is.null(path)) {
     urltools::path(url) <- path
   }
-
   url <- gsub("\\s", "%20", url)
-
   url <- add_query(query, url)
-  # if (length(query)) {
-  # for (i in seq_along(query)) {
-  #   url <- urltools::param_set(url, names(query)[i], query[[i]])
-  # }
-  # }
-
   return(list(url = url, handle = handle$handle))
 }
 
diff --git a/R/post-requests.R b/R/post-requests.R
index af50f0c..0e89d17 100644
--- a/R/post-requests.R
+++ b/R/post-requests.R
@@ -70,13 +70,20 @@
 #' jsonlite::fromJSON(res$parse("UTF-8"))
 #'
 #'
-#' # Upload files - STILL WORKING ON THIS
-#' # path <- file.path(Sys.getenv("R_DOC_DIR"), "html/logo.jpg")
-#' # (x <- HttpClient$new(url = "https://httpbin.org"))
-#' # x$post("post",
-#' #    body = list(
-#' #      files = list(path = path)
-#' #    )
-#' # )
+#' # Upload files
+#' ## image
+#' path <- file.path(Sys.getenv("R_DOC_DIR"), "html/logo.jpg")
+#' (x <- HttpClient$new(url = "https://httpbin.org"))
+#' res <- x$post(path = "post", body = list(y = upload(path)))
+#' res$content
 #'
+#' ## text file, in a list
+#' (x <- HttpClient$new(url = "https://httpbin.org"))
+#' file <- upload(system.file("CITATION"))
+#' res <- x$post(path = "post", body = list(y = file))
+#' jsonlite::fromJSON(res$parse("UTF-8"))
+#'
+#' ## text file, as data
+#' res <- x$post(path = "post", body = file)
+#' jsonlite::fromJSON(res$parse("UTF-8"))
 NULL
diff --git a/R/upload.R b/R/upload.R
new file mode 100644
index 0000000..e8cb538
--- /dev/null
+++ b/R/upload.R
@@ -0,0 +1,14 @@
+#' upload file
+#'
+#' @export
+#' @param path (character) a single path, file must exist
+#' @param type (character) a file type, guessed by [mime::guess_type] if
+#' not given
+upload <- function(path, type = NULL) {
+  stopifnot(is.character(path), length(path) == 1, file.exists(path))
+  if (is.null(type)) type <- mime::guess_type(path)
+  curl::form_file(path, type)
+}
+
+#' @export
+as.character.form_file <- function(x, ...) x
diff --git a/R/writing-options.R b/R/writing-options.R
index e011907..3fc86ef 100644
--- a/R/writing-options.R
+++ b/R/writing-options.R
@@ -2,12 +2,10 @@
 #'
 #' @name writing-options
 #' @examples
-#' (x <- HttpClient$new(url = "https://httpbin.org"))
-#'
 #' # write to disk
 #' (x <- HttpClient$new(url = "https://httpbin.org"))
 #' f <- tempfile()
-#' res <- x$get(disk = f)
+#' res <- x$get("get", disk = f)
 #' res$content # when using write to disk, content is a path
 #' readLines(res$content)
 #'
diff --git a/R/zzz.R b/R/zzz.R
index a9be0a5..f2827be 100644
--- a/R/zzz.R
+++ b/R/zzz.R
@@ -13,7 +13,6 @@ assert <- function(x, y) {
 
 prep_opts <- function(method, url, self, opts, ...) {
   if (method != "post") {
-    opts$opts$post <- NULL
     opts$opts$customrequest <- toupper(method)
   }
   if (!is.null(opts$type)) {
@@ -24,14 +23,8 @@ prep_opts <- function(method, url, self, opts, ...) {
   rr <- list(
     url = url,
     method = method,
-    options = as.list(c(
-      opts$opts
-    )),
-    headers = as.list(c(
-      opts$type,
-      `User-Agent` = make_ua(),
-      `Accept-Encoding` = 'gzip, deflate'
-    )),
+    options = ccp(as.list(c(opts$opts, cainfo = find_cert_bundle()))),
+    headers = as.list(c(opts$type, def_head())),
     fields = opts$fields
   )
   rr$headers <- norm_headers(rr$headers, self$headers)
@@ -39,6 +32,7 @@ prep_opts <- function(method, url, self, opts, ...) {
     rr$options,
     c(self$opts, self$proxies, self$auth, ...)
   )
+  rr$options <- curl_opts_fil(rr$options)
   return(rr)
 }
 
@@ -57,3 +51,40 @@ check_for_package <- function(x) {
     invisible(TRUE)
   }
 }
+
+def_head <- function() {
+  list(
+    `User-Agent` = make_ua(),
+    `Accept-Encoding` = 'gzip, deflate',
+    `Accept` = 'application/json, text/xml, application/xml, */*'
+  )
+}
+
+# drop any options that are not in the set of
+# valid curl options
+curl_opts_fil <- function(z) {
+  valco <- names(curl::curl_options())
+  z[names(z) %in% valco]
+}
+
+# drop named things
+drop_name <- function(x, y) {
+  x[!names(x) %in% y]
+}
+
+# adapted from https://github.com/hadley/httr
+find_cert_bundle <- function() {
+  if (.Platform$OS.type != "windows")
+    return()
+
+  env <- Sys.getenv("CURL_CA_BUNDLE")
+  if (!identical(env, ""))
+    return(env)
+
+  bundled <- file.path(R.home("etc"), "curl-ca-bundle.crt")
+  if (file.exists(bundled))
+    return(bundled)
+
+  # Fall back to certificate bundle in openssl
+  system.file("cacert.pem", package = "openssl")
+}
diff --git a/README.md b/README.md
index a49a2a2..a334d7d 100644
--- a/README.md
+++ b/README.md
@@ -25,10 +25,11 @@ of handling requests with different HTTP methods, options, etc.
 * `mock()` - Turn on/off mocking, via `webmockr`
 * `auth()` - Simple authentication helper
 * `proxy()` - Proxy helper
+* `upload()` - File upload helper
 
 Mocking:
 
-`crul` now integrates with [webmockr](https://github.com/ropensci/webmockr) to mock 
+`crul` now integrates with [webmockr](https://github.com/ropensci/webmockr) to mock
 HTTP requests.
 
 ## Installation
@@ -142,17 +143,19 @@ res$content
 #>   [1] 7b 0a 20 20 22 61 72 67 73 22 3a 20 7b 7d 2c 20 0a 20 20 22 68 65 61
 #>  [24] 64 65 72 73 22 3a 20 7b 0a 20 20 20 20 22 41 22 3a 20 22 68 65 6c 6c
 #>  [47] 6f 20 77 6f 72 6c 64 22 2c 20 0a 20 20 20 20 22 41 63 63 65 70 74 22
-#>  [70] 3a 20 22 2a 2f 2a 22 2c 20 0a 20 20 20 20 22 41 63 63 65 70 74 2d 45
-#>  [93] 6e 63 6f 64 69 6e 67 22 3a 20 22 67 7a 69 70 2c 20 64 65 66 6c 61 74
-#> [116] 65 22 2c 20 0a 20 20 20 20 22 43 6f 6e 6e 65 63 74 69 6f 6e 22 3a 20
-#> [139] 22 63 6c 6f 73 65 22 2c 20 0a 20 20 20 20 22 48 6f 73 74 22 3a 20 22
-#> [162] 68 74 74 70 62 69 6e 2e 6f 72 67 22 2c 20 0a 20 20 20 20 22 55 73 65
-#> [185] 72 2d 41 67 65 6e 74 22 3a 20 22 6c 69 62 63 75 72 6c 2f 37 2e 35 31
-#> [208] 2e 30 20 72 2d 63 75 72 6c 2f 32 2e 36 20 63 72 75 6c 2f 30 2e 33 2e
-#> [231] 38 22 0a 20 20 7d 2c 20 0a 20 20 22 6f 72 69 67 69 6e 22 3a 20 22 31
-#> [254] 35 37 2e 31 33 30 2e 31 37 39 2e 38 36 22 2c 20 0a 20 20 22 75 72 6c
-#> [277] 22 3a 20 22 68 74 74 70 73 3a 2f 2f 68 74 74 70 62 69 6e 2e 6f 72 67
-#> [300] 2f 67 65 74 22 0a 7d 0a
+#>  [70] 3a 20 22 61 70 70 6c 69 63 61 74 69 6f 6e 2f 6a 73 6f 6e 2c 20 74 65
+#>  [93] 78 74 2f 78 6d 6c 2c 20 61 70 70 6c 69 63 61 74 69 6f 6e 2f 78 6d 6c
+#> [116] 2c 20 2a 2f 2a 22 2c 20 0a 20 20 20 20 22 41 63 63 65 70 74 2d 45 6e
+#> [139] 63 6f 64 69 6e 67 22 3a 20 22 67 7a 69 70 2c 20 64 65 66 6c 61 74 65
+#> [162] 22 2c 20 0a 20 20 20 20 22 43 6f 6e 6e 65 63 74 69 6f 6e 22 3a 20 22
+#> [185] 63 6c 6f 73 65 22 2c 20 0a 20 20 20 20 22 48 6f 73 74 22 3a 20 22 68
+#> [208] 74 74 70 62 69 6e 2e 6f 72 67 22 2c 20 0a 20 20 20 20 22 55 73 65 72
+#> [231] 2d 41 67 65 6e 74 22 3a 20 22 6c 69 62 63 75 72 6c 2f 37 2e 35 34 2e
+#> [254] 30 20 72 2d 63 75 72 6c 2f 32 2e 38 2e 31 20 63 72 75 6c 2f 30 2e 34
+#> [277] 2e 30 22 0a 20 20 7d 2c 20 0a 20 20 22 6f 72 69 67 69 6e 22 3a 20 22
+#> [300] 31 35 37 2e 31 33 30 2e 31 37 39 2e 38 36 22 2c 20 0a 20 20 22 75 72
+#> [323] 6c 22 3a 20 22 68 74 74 70 73 3a 2f 2f 68 74 74 70 62 69 6e 2e 6f 72
+#> [346] 67 2f 67 65 74 22 0a 7d 0a
 ```
 
 HTTP method
@@ -169,11 +172,14 @@ Request headers
 ```r
 res$request_headers
 #> $`User-Agent`
-#> [1] "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"
+#> [1] "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0"
 #> 
 #> $`Accept-Encoding`
 #> [1] "gzip, deflate"
 #> 
+#> $Accept
+#> [1] "application/json, text/xml, application/xml, */*"
+#> 
 #> $a
 #> [1] "hello world"
 ```
@@ -193,7 +199,7 @@ res$response_headers
 #> [1] "meinheld/0.6.1"
 #> 
 #> $date
-#> [1] "Tue, 13 Jun 2017 22:25:04 GMT"
+#> [1] "Mon, 02 Oct 2017 19:20:21 GMT"
 #> 
 #> $`content-type`
 #> [1] "application/json"
@@ -208,10 +214,10 @@ res$response_headers
 #> [1] "Flask"
 #> 
 #> $`x-processed-time`
-#> [1] "0.000868082046509"
+#> [1] "0.000764131546021"
 #> 
 #> $`content-length`
-#> [1] "307"
+#> [1] "354"
 #> 
 #> $via
 #> [1] "1.1 vegur"
@@ -223,7 +229,7 @@ And you can parse the content with `parse()`
 ```r
 res$parse()
 #> No encoding supplied: defaulting to UTF-8.
-#> [1] "{\n  \"args\": {}, \n  \"headers\": {\n    \"A\": \"hello world\", \n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.51.0 r-curl/2.6 crul/0.3.8\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get\"\n}\n"
+#> [1] "{\n  \"args\": {}, \n  \"headers\": {\n    \"A\": \"hello world\", \n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get\"\n}\n"
 jsonlite::fromJSON(res$parse())
 #> No encoding supplied: defaulting to UTF-8.
 #> $args
@@ -234,7 +240,7 @@ jsonlite::fromJSON(res$parse())
 #> [1] "hello world"
 #> 
 #> $headers$Accept
-#> [1] "*/*"
+#> [1] "application/json, text/xml, application/xml, */*"
 #> 
 #> $headers$`Accept-Encoding`
 #> [1] "gzip, deflate"
@@ -246,7 +252,7 @@ jsonlite::fromJSON(res$parse())
 #> [1] "httpbin.org"
 #> 
 #> $headers$`User-Agent`
-#> [1] "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"
+#> [1] "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0"
 #> 
 #> 
 #> $origin
@@ -288,13 +294,13 @@ options/headers, etc. and you have to use the same HTTP method on all of them:
 res <- cc$get()
 lapply(res, function(z) z$parse("UTF-8"))
 #> [[1]]
-#> [1] "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' value='text/html;charset=utf8'>\n  <meta name='generator' value='Ronn/v0.7.3 (http://github.com/rtomayko/ronn/tree/0.7.3)'>\n  <title>httpbin(1): HTTP Client Testing Service</title>\n  <style type='text/css' media='all'>\n  /* style: man */\n  body#manpage {margin:0}\n  .mp {max-width:100ex;padding:0 9ex 1ex 4ex}\n  .mp p,.mp pre,.mp ul,.mp ol,.mp dl {margin:0 0 20px 0}\n  .mp h2 {margin:10px 0 0 0}\n  .mp > p,.mp [...]
+#> [1] "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' value='text/html;charset=utf8'>\n  <meta name='generator' value='Ronn/v0.7.3 (http://github.com/rtomayko/ronn/tree/0.7.3)'>\n  <title>httpbin(1): HTTP Client Testing Service</title>\n  <style type='text/css' media='all'>\n  /* style: man */\n  body#manpage {margin:0}\n  .mp {max-width:100ex;padding:0 9ex 1ex 4ex}\n  .mp p,.mp pre,.mp ul,.mp ol,.mp dl {margin:0 0 20px 0}\n  .mp h2 {margin:10px 0 0 0}\n  .mp > p,.mp [...]
 #> 
 #> [[2]]
-#> [1] "{\n  \"args\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.51.0 r-curl/2.6 crul/0.3.8\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get?a=5\"\n}\n"
+#> [1] "{\n  \"args\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get?a=5\"\n}\n"
 #> 
 #> [[3]]
-#> [1] "{\n  \"args\": {\n    \"foo\": \"bar\"\n  }, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.51.0 r-curl/2.6 crul/0.3.8\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get?foo=bar\"\n}\n"
+#> [1] "{\n  \"args\": {\n    \"foo\": \"bar\"\n  }, \n  \"headers\": {\n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get?foo=bar\"\n}\n"
 ```
 
 The `AsyncVaried` interface accepts any number of `HttpRequest` objects, which
@@ -333,8 +339,8 @@ out$status()
 #>   Message: OK
 #>   Explanation: Request fulfilled, document follows
 out$parse()
-#> [1] "{\n  \"args\": {}, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Foo\": \"bar\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.51.0 r-curl/2.6 crul/0.3.8\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get\"\n}\n"                                                                                                                                      [...]
-#> [2] "{\n  \"args\": {}, \n  \"data\": \"\", \n  \"files\": {}, \n  \"form\": {}, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Content-Length\": \"0\", \n    \"Content-Type\": \"application/x-www-form-urlencoded\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.51.0 r-curl/2.6 crul/0.3.8\"\n  }, \n  \"json\": null, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin [...]
+#> [1] "{\n  \"args\": {}, \n  \"headers\": {\n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Foo\": \"bar\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get\"\n}\n"                                                                                       [...]
+#> [2] "{\n  \"args\": {}, \n  \"data\": \"\", \n  \"files\": {}, \n  \"form\": {}, \n  \"headers\": {\n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Content-Length\": \"0\", \n    \"Content-Type\": \"application/x-www-form-urlencoded\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0\"\n  }, \n  \"json\": null, \n  \"origin\": \"1 [...]
 ```
 
 ## TO DO
@@ -354,4 +360,3 @@ for flexible and easy HTTP request caching
 * Get citation information for `crul` in R doing `citation(package = 'crul')`
 * Please note that this project is released with a [Contributor Code of Conduct](CONDUCT.md).
 By participating in this project you agree to abide by its terms.
-
diff --git a/build/vignette.rds b/build/vignette.rds
index b778fba..df3def4 100644
Binary files a/build/vignette.rds and b/build/vignette.rds differ
diff --git a/inst/doc/async.Rmd b/inst/doc/async.Rmd
index c0adf23..64d5f3b 100644
--- a/inst/doc/async.Rmd
+++ b/inst/doc/async.Rmd
@@ -63,18 +63,17 @@ Make request with any HTTP method
 #> <crul response> 
 #>   url: https://httpbin.org/get?a=5
 #>   request_headers: 
-#>     useragent: libcurl/7.51.0 r-curl/2.6 crul/0.3.8
 #>   response_headers: 
 #>     status: HTTP/1.1 200 OK
 #>     connection: keep-alive
 #>     server: meinheld/0.6.1
-#>     date: Tue, 13 Jun 2017 22:26:33 GMT
+#>     date: Mon, 02 Oct 2017 19:21:08 GMT
 #>     content-type: application/json
 #>     access-control-allow-origin: *
 #>     access-control-allow-credentials: true
 #>     x-powered-by: Flask
-#>     x-processed-time: 0.000774145126343
-#>     content-length: 302
+#>     x-processed-time: 0.00125598907471
+#>     content-length: 349
 #>     via: 1.1 vegur
 #>   params: 
 #>     a: 5
@@ -84,18 +83,17 @@ Make request with any HTTP method
 #> <crul response> 
 #>   url: https://httpbin.org/get?a=5&b=6
 #>   request_headers: 
-#>     useragent: libcurl/7.51.0 r-curl/2.6 crul/0.3.8
 #>   response_headers: 
 #>     status: HTTP/1.1 200 OK
 #>     connection: keep-alive
 #>     server: meinheld/0.6.1
-#>     date: Tue, 13 Jun 2017 22:26:33 GMT
+#>     date: Mon, 02 Oct 2017 19:21:07 GMT
 #>     content-type: application/json
 #>     access-control-allow-origin: *
 #>     access-control-allow-credentials: true
 #>     x-powered-by: Flask
-#>     x-processed-time: 0.00131487846375
-#>     content-length: 321
+#>     x-processed-time: 0.00107097625732
+#>     content-length: 368
 #>     via: 1.1 vegur
 #>   params: 
 #>     a: 5
@@ -106,17 +104,16 @@ Make request with any HTTP method
 #> <crul response> 
 #>   url: https://httpbin.org/ip
 #>   request_headers: 
-#>     useragent: libcurl/7.51.0 r-curl/2.6 crul/0.3.8
 #>   response_headers: 
 #>     status: HTTP/1.1 200 OK
 #>     connection: keep-alive
 #>     server: meinheld/0.6.1
-#>     date: Tue, 13 Jun 2017 22:26:33 GMT
+#>     date: Mon, 02 Oct 2017 19:21:08 GMT
 #>     content-type: application/json
 #>     access-control-allow-origin: *
 #>     access-control-allow-credentials: true
 #>     x-powered-by: Flask
-#>     x-processed-time: 0.000844955444336
+#>     x-processed-time: 0.000734090805054
 #>     content-length: 33
 #>     via: 1.1 vegur
 #>   status: 200
@@ -133,7 +130,7 @@ res[[1]]$url
 res[[1]]$success()
 #> [1] TRUE
 res[[1]]$parse("UTF-8")
-#> [1] "{\n  \"args\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.51.0 r-curl/2.6 crul/0.3.8\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get?a=5\"\n}\n"
+#> [1] "{\n  \"args\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get?a=5\"\n}\n"
 ```
 
 Or apply access/method calls aross many results, e.g., parse all results
@@ -142,10 +139,10 @@ Or apply access/method calls aross many results, e.g., parse all results
 ```r
 lapply(res, function(z) z$parse("UTF-8"))
 #> [[1]]
-#> [1] "{\n  \"args\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.51.0 r-curl/2.6 crul/0.3.8\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get?a=5\"\n}\n"
+#> [1] "{\n  \"args\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get?a=5\"\n}\n"
 #> 
 #> [[2]]
-#> [1] "{\n  \"args\": {\n    \"a\": \"5\", \n    \"b\": \"6\"\n  }, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.51.0 r-curl/2.6 crul/0.3.8\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get?a=5&b=6\"\n}\n"
+#> [1] "{\n  \"args\": {\n    \"a\": \"5\", \n    \"b\": \"6\"\n  }, \n  \"headers\": {\n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get?a=5&b=6\"\n}\n"
 #> 
 #> [[3]]
 #> [1] "{\n  \"origin\": \"157.130.179.86\"\n}\n"
@@ -200,8 +197,8 @@ Parse all results
 
 ```r
 res$parse()
-#> [1] "{\n  \"args\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.51.0 r-curl/2.6 crul/0.3.8\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get?a=5\"\n}\n"                                                                                                                                    [...]
-#> [2] "{\n  \"args\": {\n    \"a\": \"5\", \n    \"b\": \"6\"\n  }, \n  \"data\": \"\", \n  \"files\": {}, \n  \"form\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Content-Length\": \"137\", \n    \"Content-Type\": \"multipart/form-data; boundary=------------------------4cd6745fc264b623\", \n    \"Expect\": \"100-continue\", \n    \"Host\": \"httpbin.org\", \n    \"User-Age [...]
+#> [1] "{\n  \"args\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get?a=5\"\n}\n"                                                                                     [...]
+#> [2] "{\n  \"args\": {\n    \"a\": \"5\", \n    \"b\": \"6\"\n  }, \n  \"data\": \"\", \n  \"files\": {}, \n  \"form\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Content-Length\": \"137\", \n    \"Content-Type\": \"multipart/form-data; boundary=------------------------9223144570b5d592\", \n    \"Host\": \"httpbin.org\", \n    \ [...]
 ```
 
 
@@ -213,11 +210,11 @@ lapply(res$parse(), jsonlite::prettify)
 #>         "a": "5"
 #>     },
 #>     "headers": {
-#>         "Accept": "*/*",
+#>         "Accept": "application/json, text/xml, application/xml, */*",
 #>         "Accept-Encoding": "gzip, deflate",
 #>         "Connection": "close",
 #>         "Host": "httpbin.org",
-#>         "User-Agent": "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"
+#>         "User-Agent": "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0"
 #>     },
 #>     "origin": "157.130.179.86",
 #>     "url": "https://httpbin.org/get?a=5"
@@ -238,14 +235,13 @@ lapply(res$parse(), jsonlite::prettify)
 #>         "a": "5"
 #>     },
 #>     "headers": {
-#>         "Accept": "*/*",
+#>         "Accept": "application/json, text/xml, application/xml, */*",
 #>         "Accept-Encoding": "gzip, deflate",
 #>         "Connection": "close",
 #>         "Content-Length": "137",
-#>         "Content-Type": "multipart/form-data; boundary=------------------------4cd6745fc264b623",
-#>         "Expect": "100-continue",
+#>         "Content-Type": "multipart/form-data; boundary=------------------------9223144570b5d592",
 #>         "Host": "httpbin.org",
-#>         "User-Agent": "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"
+#>         "User-Agent": "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0"
 #>     },
 #>     "json": null,
 #>     "origin": "157.130.179.86",
diff --git a/inst/doc/async.html b/inst/doc/async.html
index 7f2c87f..320b2cf 100644
--- a/inst/doc/async.html
+++ b/inst/doc/async.html
@@ -157,18 +157,17 @@ $(document).ready(function () {
 #> <crul response> 
 #>   url: https://httpbin.org/get?a=5
 #>   request_headers: 
-#>     useragent: libcurl/7.51.0 r-curl/2.6 crul/0.3.8
 #>   response_headers: 
 #>     status: HTTP/1.1 200 OK
 #>     connection: keep-alive
 #>     server: meinheld/0.6.1
-#>     date: Tue, 13 Jun 2017 22:26:33 GMT
+#>     date: Mon, 02 Oct 2017 19:21:08 GMT
 #>     content-type: application/json
 #>     access-control-allow-origin: *
 #>     access-control-allow-credentials: true
 #>     x-powered-by: Flask
-#>     x-processed-time: 0.000774145126343
-#>     content-length: 302
+#>     x-processed-time: 0.00125598907471
+#>     content-length: 349
 #>     via: 1.1 vegur
 #>   params: 
 #>     a: 5
@@ -178,18 +177,17 @@ $(document).ready(function () {
 #> <crul response> 
 #>   url: https://httpbin.org/get?a=5&b=6
 #>   request_headers: 
-#>     useragent: libcurl/7.51.0 r-curl/2.6 crul/0.3.8
 #>   response_headers: 
 #>     status: HTTP/1.1 200 OK
 #>     connection: keep-alive
 #>     server: meinheld/0.6.1
-#>     date: Tue, 13 Jun 2017 22:26:33 GMT
+#>     date: Mon, 02 Oct 2017 19:21:07 GMT
 #>     content-type: application/json
 #>     access-control-allow-origin: *
 #>     access-control-allow-credentials: true
 #>     x-powered-by: Flask
-#>     x-processed-time: 0.00131487846375
-#>     content-length: 321
+#>     x-processed-time: 0.00107097625732
+#>     content-length: 368
 #>     via: 1.1 vegur
 #>   params: 
 #>     a: 5
@@ -200,17 +198,16 @@ $(document).ready(function () {
 #> <crul response> 
 #>   url: https://httpbin.org/ip
 #>   request_headers: 
-#>     useragent: libcurl/7.51.0 r-curl/2.6 crul/0.3.8
 #>   response_headers: 
 #>     status: HTTP/1.1 200 OK
 #>     connection: keep-alive
 #>     server: meinheld/0.6.1
-#>     date: Tue, 13 Jun 2017 22:26:33 GMT
+#>     date: Mon, 02 Oct 2017 19:21:08 GMT
 #>     content-type: application/json
 #>     access-control-allow-origin: *
 #>     access-control-allow-credentials: true
 #>     x-powered-by: Flask
-#>     x-processed-time: 0.000844955444336
+#>     x-processed-time: 0.000734090805054
 #>     content-length: 33
 #>     via: 1.1 vegur
 #>   status: 200</code></pre>
@@ -221,14 +218,14 @@ $(document).ready(function () {
 res[[1]]$success()
 #> [1] TRUE
 res[[1]]$parse("UTF-8")
-#> [1] "{\n  \"args\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.51.0 r-curl/2.6 crul/0.3.8\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"ur [...]
+#> [1] "{\n  \"args\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0\"\n  }, \n  \"origin\&quo [...]
 <p>Or apply access/method calls aross many results, e.g., parse all results</p>
 <pre class="r"><code>lapply(res, function(z) z$parse("UTF-8"))
 #> [[1]]
-#> [1] "{\n  \"args\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.51.0 r-curl/2.6 crul/0.3.8\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"ur [...]
+#> [1] "{\n  \"args\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0\"\n  }, \n  \"origin\&quo [...]
 #> 
 #> [[2]]
-#> [1] "{\n  \"args\": {\n    \"a\": \"5\", \n    \"b\": \"6\"\n  }, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.51.0 r-curl/2.6 crul/0.3.8\"\n  }, \n  \"origin\": \&q [...]
+#> [1] "{\n  \"args\": {\n    \"a\": \"5\", \n    \"b\": \"6\"\n  }, \n  \"headers\": {\n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.54.0 r-curl/2.8.1 crul/0 [...]
 #> 
 #> [[3]]
 #> [1] "{\n  \"origin\": \"157.130.179.86\"\n}\n"</code></pre>
@@ -270,8 +267,8 @@ req2$post(body = list(a = 5))
 <pre class="r"><code>res$request()</code></pre>
 <p>Parse all results</p>
 <pre class="r"><code>res$parse()
-#> [1] "{\n  \"args\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.51.0 r-curl/2.6 crul/0.3.8\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"ur [...]
-#> [2] "{\n  \"args\": {\n    \"a\": \"5\", \n    \"b\": \"6\"\n  }, \n  \"data\": \"\", \n  \"files\": {}, \n  \"form\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Content-Length\&quo [...]
+#> [1] "{\n  \"args\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0\"\n  }, \n  \"origin\&quo [...]
+#> [2] "{\n  \"args\": {\n    \"a\": \"5\", \n    \"b\": \"6\"\n  }, \n  \"data\": \"\", \n  \"files\": {}, \n  \"form\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"c [...]
 <pre class="r"><code>lapply(res$parse(), jsonlite::prettify)
 #> [[1]]
 #> {
@@ -279,11 +276,11 @@ req2$post(body = list(a = 5))
 #>         "a": "5"
 #>     },
 #>     "headers": {
-#>         "Accept": "*/*",
+#>         "Accept": "application/json, text/xml, application/xml, */*",
 #>         "Accept-Encoding": "gzip, deflate",
 #>         "Connection": "close",
 #>         "Host": "httpbin.org",
-#>         "User-Agent": "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"
+#>         "User-Agent": "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0"
 #>     },
 #>     "origin": "157.130.179.86",
 #>     "url": "https://httpbin.org/get?a=5"
@@ -304,14 +301,13 @@ req2$post(body = list(a = 5))
 #>         "a": "5"
 #>     },
 #>     "headers": {
-#>         "Accept": "*/*",
+#>         "Accept": "application/json, text/xml, application/xml, */*",
 #>         "Accept-Encoding": "gzip, deflate",
 #>         "Connection": "close",
 #>         "Content-Length": "137",
-#>         "Content-Type": "multipart/form-data; boundary=------------------------4cd6745fc264b623",
-#>         "Expect": "100-continue",
+#>         "Content-Type": "multipart/form-data; boundary=------------------------9223144570b5d592",
 #>         "Host": "httpbin.org",
-#>         "User-Agent": "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"
+#>         "User-Agent": "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0"
 #>     },
 #>     "json": null,
 #>     "origin": "157.130.179.86",
diff --git a/inst/doc/crul_vignette.Rmd b/inst/doc/crul_vignette.Rmd
index 9e86d89..8cb7c22 100644
--- a/inst/doc/crul_vignette.Rmd
+++ b/inst/doc/crul_vignette.Rmd
@@ -109,17 +109,19 @@ res$content
 #>   [1] 7b 0a 20 20 22 61 72 67 73 22 3a 20 7b 7d 2c 20 0a 20 20 22 68 65 61
 #>  [24] 64 65 72 73 22 3a 20 7b 0a 20 20 20 20 22 41 22 3a 20 22 68 65 6c 6c
 #>  [47] 6f 20 77 6f 72 6c 64 22 2c 20 0a 20 20 20 20 22 41 63 63 65 70 74 22
-#>  [70] 3a 20 22 2a 2f 2a 22 2c 20 0a 20 20 20 20 22 41 63 63 65 70 74 2d 45
-#>  [93] 6e 63 6f 64 69 6e 67 22 3a 20 22 67 7a 69 70 2c 20 64 65 66 6c 61 74
-#> [116] 65 22 2c 20 0a 20 20 20 20 22 43 6f 6e 6e 65 63 74 69 6f 6e 22 3a 20
-#> [139] 22 63 6c 6f 73 65 22 2c 20 0a 20 20 20 20 22 48 6f 73 74 22 3a 20 22
-#> [162] 68 74 74 70 62 69 6e 2e 6f 72 67 22 2c 20 0a 20 20 20 20 22 55 73 65
-#> [185] 72 2d 41 67 65 6e 74 22 3a 20 22 6c 69 62 63 75 72 6c 2f 37 2e 35 31
-#> [208] 2e 30 20 72 2d 63 75 72 6c 2f 32 2e 36 20 63 72 75 6c 2f 30 2e 33 2e
-#> [231] 38 22 0a 20 20 7d 2c 20 0a 20 20 22 6f 72 69 67 69 6e 22 3a 20 22 31
-#> [254] 35 37 2e 31 33 30 2e 31 37 39 2e 38 36 22 2c 20 0a 20 20 22 75 72 6c
-#> [277] 22 3a 20 22 68 74 74 70 73 3a 2f 2f 68 74 74 70 62 69 6e 2e 6f 72 67
-#> [300] 2f 67 65 74 22 0a 7d 0a
+#>  [70] 3a 20 22 61 70 70 6c 69 63 61 74 69 6f 6e 2f 6a 73 6f 6e 2c 20 74 65
+#>  [93] 78 74 2f 78 6d 6c 2c 20 61 70 70 6c 69 63 61 74 69 6f 6e 2f 78 6d 6c
+#> [116] 2c 20 2a 2f 2a 22 2c 20 0a 20 20 20 20 22 41 63 63 65 70 74 2d 45 6e
+#> [139] 63 6f 64 69 6e 67 22 3a 20 22 67 7a 69 70 2c 20 64 65 66 6c 61 74 65
+#> [162] 22 2c 20 0a 20 20 20 20 22 43 6f 6e 6e 65 63 74 69 6f 6e 22 3a 20 22
+#> [185] 63 6c 6f 73 65 22 2c 20 0a 20 20 20 20 22 48 6f 73 74 22 3a 20 22 68
+#> [208] 74 74 70 62 69 6e 2e 6f 72 67 22 2c 20 0a 20 20 20 20 22 55 73 65 72
+#> [231] 2d 41 67 65 6e 74 22 3a 20 22 6c 69 62 63 75 72 6c 2f 37 2e 35 34 2e
+#> [254] 30 20 72 2d 63 75 72 6c 2f 32 2e 38 2e 31 20 63 72 75 6c 2f 30 2e 34
+#> [277] 2e 30 22 0a 20 20 7d 2c 20 0a 20 20 22 6f 72 69 67 69 6e 22 3a 20 22
+#> [300] 31 35 37 2e 31 33 30 2e 31 37 39 2e 38 36 22 2c 20 0a 20 20 22 75 72
+#> [323] 6c 22 3a 20 22 68 74 74 70 73 3a 2f 2f 68 74 74 70 62 69 6e 2e 6f 72
+#> [346] 67 2f 67 65 74 22 0a 7d 0a
 ```
 
 HTTP method
@@ -136,11 +138,14 @@ Request headers
 ```r
 res$request_headers
 #> $`User-Agent`
-#> [1] "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"
+#> [1] "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0"
 #> 
 #> $`Accept-Encoding`
 #> [1] "gzip, deflate"
 #> 
+#> $Accept
+#> [1] "application/json, text/xml, application/xml, */*"
+#> 
 #> $a
 #> [1] "hello world"
 ```
@@ -160,7 +165,7 @@ res$response_headers
 #> [1] "meinheld/0.6.1"
 #> 
 #> $date
-#> [1] "Tue, 13 Jun 2017 22:26:40 GMT"
+#> [1] "Mon, 02 Oct 2017 19:21:12 GMT"
 #> 
 #> $`content-type`
 #> [1] "application/json"
@@ -175,10 +180,10 @@ res$response_headers
 #> [1] "Flask"
 #> 
 #> $`x-processed-time`
-#> [1] "0.000635147094727"
+#> [1] "0.000802993774414"
 #> 
 #> $`content-length`
-#> [1] "307"
+#> [1] "354"
 #> 
 #> $via
 #> [1] "1.1 vegur"
@@ -189,7 +194,7 @@ And you can parse the content with a provided function:
 
 ```r
 res$parse()
-#> [1] "{\n  \"args\": {}, \n  \"headers\": {\n    \"A\": \"hello world\", \n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.51.0 r-curl/2.6 crul/0.3.8\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get\"\n}\n"
+#> [1] "{\n  \"args\": {}, \n  \"headers\": {\n    \"A\": \"hello world\", \n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get\"\n}\n"
 jsonlite::fromJSON(res$parse())
 #> $args
 #> named list()
@@ -199,7 +204,7 @@ jsonlite::fromJSON(res$parse())
 #> [1] "hello world"
 #> 
 #> $headers$Accept
-#> [1] "*/*"
+#> [1] "application/json, text/xml, application/xml, */*"
 #> 
 #> $headers$`Accept-Encoding`
 #> [1] "gzip, deflate"
@@ -211,7 +216,7 @@ jsonlite::fromJSON(res$parse())
 #> [1] "httpbin.org"
 #> 
 #> $headers$`User-Agent`
-#> [1] "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"
+#> [1] "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0"
 #> 
 #> 
 #> $origin
@@ -243,7 +248,7 @@ f <- tempfile()
 res <- x$get(disk = f)
 # when using write to disk, content is a path
 res$content 
-#> [1] "/var/folders/gs/4khph0xs0436gmd2gdnwsg080000gn/T//RtmpF4Mh1B/file6fcc2a328add"
+#> [1] "/var/folders/gs/4khph0xs0436gmd2gdnwsg080000gn/T//RtmpQrTvWo/file146142af607c4"
 ```
 
 Read lines
@@ -275,11 +280,11 @@ readLines(res$content, n = 10)
 #>   auth: 
 #>   headers:
 res <- x$get('stream/5', stream = function(x) cat(rawToChar(x)))
-#> {"url": "https://httpbin.org/stream/5", "headers": {"Host": "httpbin.org", "Connection": "close", "Accept-Encoding": "gzip, deflate", "Accept": "*/*", "User-Agent": "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"}, "args": {}, "origin": "157.130.179.86", "id": 0}
-#> {"url": "https://httpbin.org/stream/5", "headers": {"Host": "httpbin.org", "Connection": "close", "Accept-Encoding": "gzip, deflate", "Accept": "*/*", "User-Agent": "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"}, "args": {}, "origin": "157.130.179.86", "id": 1}
-#> {"url": "https://httpbin.org/stream/5", "headers": {"Host": "httpbin.org", "Connection": "close", "Accept-Encoding": "gzip, deflate", "Accept": "*/*", "User-Agent": "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"}, "args": {}, "origin": "157.130.179.86", "id": 2}
-#> {"url": "https://httpbin.org/stream/5", "headers": {"Host": "httpbin.org", "Connection": "close", "Accept-Encoding": "gzip, deflate", "Accept": "*/*", "User-Agent": "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"}, "args": {}, "origin": "157.130.179.86", "id": 3}
-#> {"url": "https://httpbin.org/stream/5", "headers": {"Host": "httpbin.org", "Connection": "close", "Accept-Encoding": "gzip, deflate", "Accept": "*/*", "User-Agent": "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"}, "args": {}, "origin": "157.130.179.86", "id": 4}
+#> {"id": 0, "origin": "157.130.179.86", "args": {}, "headers": {"User-Agent": "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0", "Accept": "application/json, text/xml, application/xml, */*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Host": "httpbin.org"}, "url": "https://httpbin.org/stream/5"}
+#> {"id": 1, "origin": "157.130.179.86", "args": {}, "headers": {"User-Agent": "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0", "Accept": "application/json, text/xml, application/xml, */*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Host": "httpbin.org"}, "url": "https://httpbin.org/stream/5"}
+#> {"id": 2, "origin": "157.130.179.86", "args": {}, "headers": {"User-Agent": "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0", "Accept": "application/json, text/xml, application/xml, */*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Host": "httpbin.org"}, "url": "https://httpbin.org/stream/5"}
+#> {"id": 3, "origin": "157.130.179.86", "args": {}, "headers": {"User-Agent": "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0", "Accept": "application/json, text/xml, application/xml, */*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Host": "httpbin.org"}, "url": "https://httpbin.org/stream/5"}
+#> {"id": 4, "origin": "157.130.179.86", "args": {}, "headers": {"User-Agent": "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0", "Accept": "application/json, text/xml, application/xml, */*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Host": "httpbin.org"}, "url": "https://httpbin.org/stream/5"}
 # when streaming, content is NULL
 res$content 
 #> NULL
diff --git a/inst/doc/crul_vignette.html b/inst/doc/crul_vignette.html
index 2107449..331f46f 100644
--- a/inst/doc/crul_vignette.html
+++ b/inst/doc/crul_vignette.html
@@ -177,28 +177,33 @@ $(document).ready(function () {
 #>   [1] 7b 0a 20 20 22 61 72 67 73 22 3a 20 7b 7d 2c 20 0a 20 20 22 68 65 61
 #>  [24] 64 65 72 73 22 3a 20 7b 0a 20 20 20 20 22 41 22 3a 20 22 68 65 6c 6c
 #>  [47] 6f 20 77 6f 72 6c 64 22 2c 20 0a 20 20 20 20 22 41 63 63 65 70 74 22
-#>  [70] 3a 20 22 2a 2f 2a 22 2c 20 0a 20 20 20 20 22 41 63 63 65 70 74 2d 45
-#>  [93] 6e 63 6f 64 69 6e 67 22 3a 20 22 67 7a 69 70 2c 20 64 65 66 6c 61 74
-#> [116] 65 22 2c 20 0a 20 20 20 20 22 43 6f 6e 6e 65 63 74 69 6f 6e 22 3a 20
-#> [139] 22 63 6c 6f 73 65 22 2c 20 0a 20 20 20 20 22 48 6f 73 74 22 3a 20 22
-#> [162] 68 74 74 70 62 69 6e 2e 6f 72 67 22 2c 20 0a 20 20 20 20 22 55 73 65
-#> [185] 72 2d 41 67 65 6e 74 22 3a 20 22 6c 69 62 63 75 72 6c 2f 37 2e 35 31
-#> [208] 2e 30 20 72 2d 63 75 72 6c 2f 32 2e 36 20 63 72 75 6c 2f 30 2e 33 2e
-#> [231] 38 22 0a 20 20 7d 2c 20 0a 20 20 22 6f 72 69 67 69 6e 22 3a 20 22 31
-#> [254] 35 37 2e 31 33 30 2e 31 37 39 2e 38 36 22 2c 20 0a 20 20 22 75 72 6c
-#> [277] 22 3a 20 22 68 74 74 70 73 3a 2f 2f 68 74 74 70 62 69 6e 2e 6f 72 67
-#> [300] 2f 67 65 74 22 0a 7d 0a</code></pre>
+#>  [70] 3a 20 22 61 70 70 6c 69 63 61 74 69 6f 6e 2f 6a 73 6f 6e 2c 20 74 65
+#>  [93] 78 74 2f 78 6d 6c 2c 20 61 70 70 6c 69 63 61 74 69 6f 6e 2f 78 6d 6c
+#> [116] 2c 20 2a 2f 2a 22 2c 20 0a 20 20 20 20 22 41 63 63 65 70 74 2d 45 6e
+#> [139] 63 6f 64 69 6e 67 22 3a 20 22 67 7a 69 70 2c 20 64 65 66 6c 61 74 65
+#> [162] 22 2c 20 0a 20 20 20 20 22 43 6f 6e 6e 65 63 74 69 6f 6e 22 3a 20 22
+#> [185] 63 6c 6f 73 65 22 2c 20 0a 20 20 20 20 22 48 6f 73 74 22 3a 20 22 68
+#> [208] 74 74 70 62 69 6e 2e 6f 72 67 22 2c 20 0a 20 20 20 20 22 55 73 65 72
+#> [231] 2d 41 67 65 6e 74 22 3a 20 22 6c 69 62 63 75 72 6c 2f 37 2e 35 34 2e
+#> [254] 30 20 72 2d 63 75 72 6c 2f 32 2e 38 2e 31 20 63 72 75 6c 2f 30 2e 34
+#> [277] 2e 30 22 0a 20 20 7d 2c 20 0a 20 20 22 6f 72 69 67 69 6e 22 3a 20 22
+#> [300] 31 35 37 2e 31 33 30 2e 31 37 39 2e 38 36 22 2c 20 0a 20 20 22 75 72
+#> [323] 6c 22 3a 20 22 68 74 74 70 73 3a 2f 2f 68 74 74 70 62 69 6e 2e 6f 72
+#> [346] 67 2f 67 65 74 22 0a 7d 0a</code></pre>
 <p>HTTP method</p>
 <pre class="r"><code>res$method
 #> [1] "get"</code></pre>
 <p>Request headers</p>
 <pre class="r"><code>res$request_headers
 #> $`User-Agent`
-#> [1] "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"
+#> [1] "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0"
 #> 
 #> $`Accept-Encoding`
 #> [1] "gzip, deflate"
 #> 
+#> $Accept
+#> [1] "application/json, text/xml, application/xml, */*"
+#> 
 #> $a
 #> [1] "hello world"</code></pre>
 <p>Response headers</p>
@@ -213,7 +218,7 @@ $(document).ready(function () {
 #> [1] "meinheld/0.6.1"
 #> 
 #> $date
-#> [1] "Tue, 13 Jun 2017 22:26:40 GMT"
+#> [1] "Mon, 02 Oct 2017 19:21:12 GMT"
 #> 
 #> $`content-type`
 #> [1] "application/json"
@@ -228,16 +233,16 @@ $(document).ready(function () {
 #> [1] "Flask"
 #> 
 #> $`x-processed-time`
-#> [1] "0.000635147094727"
+#> [1] "0.000802993774414"
 #> 
 #> $`content-length`
-#> [1] "307"
+#> [1] "354"
 #> 
 #> $via
 #> [1] "1.1 vegur"</code></pre>
 <p>And you can parse the content with a provided function:</p>
 <pre class="r"><code>res$parse()
-#> [1] "{\n  \"args\": {}, \n  \"headers\": {\n    \"A\": \"hello world\", \n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.51.0 r-curl/2.6 crul/0.3.8\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \ [...]
+#> [1] "{\n  \"args\": {}, \n  \"headers\": {\n    \"A\": \"hello world\", \n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0\"\n  }, \n  \"ori [...]
 jsonlite::fromJSON(res$parse())
 #> $args
 #> named list()
@@ -247,7 +252,7 @@ jsonlite::fromJSON(res$parse())
 #> [1] "hello world"
 #> 
 #> $headers$Accept
-#> [1] "*/*"
+#> [1] "application/json, text/xml, application/xml, */*"
 #> 
 #> $headers$`Accept-Encoding`
 #> [1] "gzip, deflate"
@@ -259,7 +264,7 @@ jsonlite::fromJSON(res$parse())
 #> [1] "httpbin.org"
 #> 
 #> $headers$`User-Agent`
-#> [1] "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"
+#> [1] "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0"
 #> 
 #> 
 #> $origin
@@ -280,7 +285,7 @@ f <- tempfile()
 res <- x$get(disk = f)
 # when using write to disk, content is a path
 res$content 
-#> [1] "/var/folders/gs/4khph0xs0436gmd2gdnwsg080000gn/T//RtmpF4Mh1B/file6fcc2a328add"</code></pre>
+#> [1] "/var/folders/gs/4khph0xs0436gmd2gdnwsg080000gn/T//RtmpQrTvWo/file146142af607c4"</code></pre>
 <p>Read lines</p>
 <pre class="r"><code>readLines(res$content, n = 10)
 #>  [1] "<!DOCTYPE html>"                                                                           
@@ -304,11 +309,11 @@ res$content
 #>   auth: 
 #>   headers:
 res <- x$get('stream/5', stream = function(x) cat(rawToChar(x)))
-#> {"url": "https://httpbin.org/stream/5", "headers": {"Host": "httpbin.org", "Connection": "close", "Accept-Encoding": "gzip, deflate", "Accept": "*/*", "User-Agent": "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"}, "args": {}, "origin": "157.130.179.86", "id": 0}
-#> {"url": "https://httpbin.org/stream/5", "headers": {"Host": "httpbin.org", "Connection": "close", "Accept-Encoding": "gzip, deflate", "Accept": "*/*", "User-Agent": "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"}, "args": {}, "origin": "157.130.179.86", "id": 1}
-#> {"url": "https://httpbin.org/stream/5", "headers": {"Host": "httpbin.org", "Connection": "close", "Accept-Encoding": "gzip, deflate", "Accept": "*/*", "User-Agent": "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"}, "args": {}, "origin": "157.130.179.86", "id": 2}
-#> {"url": "https://httpbin.org/stream/5", "headers": {"Host": "httpbin.org", "Connection": "close", "Accept-Encoding": "gzip, deflate", "Accept": "*/*", "User-Agent": "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"}, "args": {}, "origin": "157.130.179.86", "id": 3}
-#> {"url": "https://httpbin.org/stream/5", "headers": {"Host": "httpbin.org", "Connection": "close", "Accept-Encoding": "gzip, deflate", "Accept": "*/*", "User-Agent": "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"}, "args": {}, "origin": "157.130.179.86", "id": 4}
+#> {"id": 0, "origin": "157.130.179.86", "args": {}, "headers": {"User-Agent": "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0", "Accept": "application/json, text/xml, application/xml, */*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Host": "httpbin.org"}, "url": "https://httpbin.org/stream/5"}
+#> {"id": 1, "origin": "157.130.179.86", "args": {}, "headers": {"User-Agent": "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0", "Accept": "application/json, text/xml, application/xml, */*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Host": "httpbin.org"}, "url": "https://httpbin.org/stream/5"}
+#> {"id": 2, "origin": "157.130.179.86", "args": {}, "headers": {"User-Agent": "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0", "Accept": "application/json, text/xml, application/xml, */*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Host": "httpbin.org"}, "url": "https://httpbin.org/stream/5"}
+#> {"id": 3, "origin": "157.130.179.86", "args": {}, "headers": {"User-Agent": "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0", "Accept": "application/json, text/xml, application/xml, */*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Host": "httpbin.org"}, "url": "https://httpbin.org/stream/5"}
+#> {"id": 4, "origin": "157.130.179.86", "args": {}, "headers": {"User-Agent": "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0", "Accept": "application/json, text/xml, application/xml, */*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Host": "httpbin.org"}, "url": "https://httpbin.org/stream/5"}
 # when streaming, content is NULL
 res$content 
 #> NULL</code></pre>
diff --git a/inst/doc/how-to-use-crul.Rmd b/inst/doc/how-to-use-crul.Rmd
index fc9951e..b786d9a 100644
--- a/inst/doc/how-to-use-crul.Rmd
+++ b/inst/doc/how-to-use-crul.Rmd
@@ -68,7 +68,7 @@ make_request("https://httpbin.org/get")
 #> 
 #> $headers
 #> $headers$Accept
-#> [1] "*/*"
+#> [1] "application/json, text/xml, application/xml, */*"
 #> 
 #> $headers$`Accept-Encoding`
 #> [1] "gzip, deflate"
@@ -80,7 +80,7 @@ make_request("https://httpbin.org/get")
 #> [1] "httpbin.org"
 #> 
 #> $headers$`User-Agent`
-#> [1] "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"
+#> [1] "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0"
 #> 
 #> 
 #> $origin
@@ -144,7 +144,7 @@ make_request2("https://api.crossref.org/works?rows=0")
 #> named list()
 #> 
 #> $message$`total-results`
-#> [1] 89155073
+#> [1] 91794003
 #> 
 #> $message$items
 #> list()
@@ -189,7 +189,7 @@ make_request2("https://api.crossref.org/works", query = list(rows = 0))
 #> named list()
 #> 
 #> $message$`total-results`
-#> [1] 89155073
+#> [1] 91794003
 #> 
 #> $message$items
 #> list()
diff --git a/inst/doc/how-to-use-crul.html b/inst/doc/how-to-use-crul.html
index ffbd184..971edd3 100644
--- a/inst/doc/how-to-use-crul.html
+++ b/inst/doc/how-to-use-crul.html
@@ -157,7 +157,7 @@ $(document).ready(function () {
 #> 
 #> $headers
 #> $headers$Accept
-#> [1] "*/*"
+#> [1] "application/json, text/xml, application/xml, */*"
 #> 
 #> $headers$`Accept-Encoding`
 #> [1] "gzip, deflate"
@@ -169,7 +169,7 @@ $(document).ready(function () {
 #> [1] "httpbin.org"
 #> 
 #> $headers$`User-Agent`
-#> [1] "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"
+#> [1] "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0"
 #> 
 #> 
 #> $origin
@@ -220,7 +220,7 @@ $(document).ready(function () {
 #> named list()
 #> 
 #> $message$`total-results`
-#> [1] 89155073
+#> [1] 91794003
 #> 
 #> $message$items
 #> list()
@@ -253,7 +253,7 @@ make_request2("https://api.crossref.org/works?rows=0", timeout_ms = 1)
 #> named list()
 #> 
 #> $message$`total-results`
-#> [1] 89155073
+#> [1] 91794003
 #> 
 #> $message$items
 #> list()
diff --git a/man/HttpClient.Rd b/man/HttpClient.Rd
index 833f47b..490dbf3 100644
--- a/man/HttpClient.Rd
+++ b/man/HttpClient.Rd
@@ -38,7 +38,7 @@ Make a PATCH request
 \item{\code{delete(path, query, body, disk, stream, ...)}}{
 Make a DELETE request
 }
-\item{\code{head(path, disk, stream, ...)}}{
+\item{\code{head(path, ...)}}{
 Make a HEAD request
 }
 }
@@ -59,6 +59,13 @@ for help
 post, postfields, postfieldsize, and customrequest
 }
 }
+\section{handles}{
+
+curl handles are re-used on the level of the connection object, that is,
+each \code{HttpClient} object is separate from one another so as to better
+separate connections.
+}
+
 \examples{
 (x <- HttpClient$new(url = "https://httpbin.org"))
 x$url
@@ -97,6 +104,6 @@ res <- x$get("get", query = list(a = 'hello world'))
 }
 \seealso{
 \link{post-requests}, \link{delete-requests}, \link{http-headers},
-\link{writing-options}
+\link{writing-options}, \link{cookies}
 }
 \keyword{datasets}
diff --git a/man/HttpRequest.Rd b/man/HttpRequest.Rd
index 32ff2fb..9179531 100644
--- a/man/HttpRequest.Rd
+++ b/man/HttpRequest.Rd
@@ -49,7 +49,7 @@ Define a PATCH request
 \item{\code{delete(path, query, body, disk, stream, ...)}}{
 Define a DELETE request
 }
-\item{\code{head(path, disk, stream, ...)}}{
+\item{\code{head(path, ...)}}{
 Define a HEAD request
 }
 \item{\code{method()}}{
diff --git a/man/cookies.Rd b/man/cookies.Rd
new file mode 100644
index 0000000..3d5b5b0
--- /dev/null
+++ b/man/cookies.Rd
@@ -0,0 +1,47 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/cookies.R
+\name{cookies}
+\alias{cookies}
+\title{Working with cookies}
+\description{
+Working with cookies
+}
+\examples{
+x <- HttpClient$new(
+  url = "https://httpbin.org",
+  opts = list(
+    cookie = "c=1;f=5",
+    verbose = TRUE
+  )
+)
+x
+
+# set cookies
+(res <- x$get("cookies"))
+jsonlite::fromJSON(res$parse("UTF-8"))
+
+(x <- HttpClient$new(url = "https://httpbin.org"))
+res <- x$get("cookies/set", query = list(foo = 123, bar = "ftw"))
+jsonlite::fromJSON(res$parse("UTF-8"))
+curl::handle_cookies(handle = res$handle)
+
+# reuse handle
+res2 <- x$get("get", query = list(hello = "world"))
+jsonlite::fromJSON(res2$parse("UTF-8"))
+curl::handle_cookies(handle = res2$handle)
+
+# DOAJ
+x <- HttpClient$new(url = "https://doaj.org")
+res <- x$get("api/v1/journals/f3f2e7f23d444370ae5f5199f85bc100",
+  verbose = TRUE)
+res$response_headers$`set-cookie`
+curl::handle_cookies(handle = res$handle)
+res2 <- x$get("api/v1/journals/9abfb36b06404e8a8566e1a44180bbdc",
+  verbose = TRUE)
+
+## reset handle
+x$handle_pop()
+## cookies no longer sent, as handle reset
+res2 <- x$get("api/v1/journals/9abfb36b06404e8a8566e1a44180bbdc",
+  verbose = TRUE)
+}
diff --git a/man/post-requests.Rd b/man/post-requests.Rd
index 676a8bd..6f7ae42 100644
--- a/man/post-requests.Rd
+++ b/man/post-requests.Rd
@@ -75,13 +75,20 @@ res <- x$patch("patch", body = "foo bar")
 jsonlite::fromJSON(res$parse("UTF-8"))
 
 
-# Upload files - STILL WORKING ON THIS
-# path <- file.path(Sys.getenv("R_DOC_DIR"), "html/logo.jpg")
-# (x <- HttpClient$new(url = "https://httpbin.org"))
-# x$post("post",
-#    body = list(
-#      files = list(path = path)
-#    )
-# )
+# Upload files
+## image
+path <- file.path(Sys.getenv("R_DOC_DIR"), "html/logo.jpg")
+(x <- HttpClient$new(url = "https://httpbin.org"))
+res <- x$post(path = "post", body = list(y = upload(path)))
+res$content
 
+## text file, in a list
+(x <- HttpClient$new(url = "https://httpbin.org"))
+file <- upload(system.file("CITATION"))
+res <- x$post(path = "post", body = list(y = file))
+jsonlite::fromJSON(res$parse("UTF-8"))
+
+## text file, as data
+res <- x$post(path = "post", body = file)
+jsonlite::fromJSON(res$parse("UTF-8"))
 }
diff --git a/man/upload.Rd b/man/upload.Rd
new file mode 100644
index 0000000..c9efd7b
--- /dev/null
+++ b/man/upload.Rd
@@ -0,0 +1,17 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/upload.R
+\name{upload}
+\alias{upload}
+\title{upload file}
+\usage{
+upload(path, type = NULL)
+}
+\arguments{
+\item{path}{(character) a single path, file must exist}
+
+\item{type}{(character) a file type, guessed by \link[mime:guess_type]{mime::guess_type} if
+not given}
+}
+\description{
+upload file
+}
diff --git a/man/writing-options.Rd b/man/writing-options.Rd
index 9550c05..6145a74 100644
--- a/man/writing-options.Rd
+++ b/man/writing-options.Rd
@@ -7,12 +7,10 @@
 Writing data options
 }
 \examples{
-(x <- HttpClient$new(url = "https://httpbin.org"))
-
 # write to disk
 (x <- HttpClient$new(url = "https://httpbin.org"))
 f <- tempfile()
-res <- x$get(disk = f)
+res <- x$get("get", disk = f)
 res$content # when using write to disk, content is a path
 readLines(res$content)
 
diff --git a/tests/testthat/test-async.R b/tests/testthat/test-async.R
index 8819ca9..f6b080b 100644
--- a/tests/testthat/test-async.R
+++ b/tests/testthat/test-async.R
@@ -119,8 +119,8 @@ context("Async - head")
 test_that("Async - head", {
   skip_on_cran()
 
-  aa <- Async$new(urls = c('https://httpbin.org/head',
-                           'https://httpbin.org/head'))
+  aa <- Async$new(urls = c('https://google.com',
+                           'https://nytimes.com'))
   out <- aa$head()
 
   expect_is(out, "list")
diff --git a/tests/testthat/test-headers.R b/tests/testthat/test-headers.R
index 36395ca..340c1b4 100644
--- a/tests/testthat/test-headers.R
+++ b/tests/testthat/test-headers.R
@@ -7,7 +7,7 @@ test_that("headers work - just default headers", {
   aa <- cli$get('get')
 
   expect_is(aa, "HttpResponse")
-  expect_named(aa$request_headers, c('User-Agent', 'Accept-Encoding'))
+  expect_named(aa$request_headers, c('User-Agent', 'Accept-Encoding', 'Accept'))
 })
 
 test_that("headers work - user headers passed", {
@@ -20,7 +20,8 @@ test_that("headers work - user headers passed", {
   bb <- cli$get('get')
 
   expect_is(bb, "HttpResponse")
-  expect_named(bb$request_headers, c('User-Agent', 'Accept-Encoding', 'hello'))
+  expect_named(bb$request_headers, c('User-Agent', 'Accept-Encoding',
+                                     'Accept', 'hello'))
   expect_true(
     any(grepl("Hello", names(jsonlite::fromJSON(bb$parse("UTF-8"))$headers))))
 })
diff --git a/tests/testthat/test-paths.R b/tests/testthat/test-paths.R
index c59f779..cfb22d6 100644
--- a/tests/testthat/test-paths.R
+++ b/tests/testthat/test-paths.R
@@ -45,5 +45,4 @@ test_that("path - work with routes that have spaces", {
   expect_is(bb, "HttpResponse")
   urlsp <- strsplit(bb$url, "/")[[1]]
   expect_equal(urlsp[length(urlsp)], 'Platanista%20gangetica')
-  expect_equal(bb$status_code, 200)
 })
diff --git a/tests/testthat/test-post.R b/tests/testthat/test-post.R
index 3de5f48..37ba489 100644
--- a/tests/testthat/test-post.R
+++ b/tests/testthat/test-post.R
@@ -36,3 +36,44 @@ test_that("post request with body", {
   expect_named(aa$request$fields, "hello")
   expect_equal(aa$request$fields[[1]], "world")
 })
+
+
+test_that("post request with file upload", {
+  skip_on_cran()
+
+  # txt file
+  ## as file
+  file <- upload(system.file("CITATION"))
+  cli <- HttpClient$new(url = "https://httpbin.org")
+  aa <- cli$post("post", body = list(a = file))
+
+  expect_is(aa, "HttpResponse")
+  expect_is(aa$content, "raw")
+  expect_null(aa$request$options$readfunction)
+  out <- jsonlite::fromJSON(aa$parse("UTF-8"))
+  expect_named(out$files, "a")
+  expect_match(out$files$a, "bibentry")
+
+  ## as data
+  aa2 <- cli$post("post", body = file)
+  expect_is(aa2, "HttpResponse")
+  expect_is(aa2$content, "raw")
+  expect_is(aa2$request$options$readfunction, "function")
+  out <- jsonlite::fromJSON(aa2$parse("UTF-8"))
+  expect_equal(length(out$files), 0)
+  expect_is(out$data, "character")
+  expect_match(out$data, "bibentry")
+
+
+  # binary file: jpeg
+  file <- upload(file.path(Sys.getenv("R_DOC_DIR"), "html/logo.jpg"))
+  cli <- HttpClient$new(url = "https://httpbin.org")
+  aa <- cli$post("post", body = list(a = file))
+
+  expect_is(aa, "HttpResponse")
+  expect_is(aa$content, "raw")
+  expect_named(aa$request$fields, "a")
+  out <- jsonlite::fromJSON(aa$parse("UTF-8"))
+  expect_named(out$files, "a")
+  expect_match(out$files$a, "data:image/jpeg")
+})
diff --git a/vignettes/async.Rmd b/vignettes/async.Rmd
index c0adf23..64d5f3b 100644
--- a/vignettes/async.Rmd
+++ b/vignettes/async.Rmd
@@ -63,18 +63,17 @@ Make request with any HTTP method
 #> <crul response> 
 #>   url: https://httpbin.org/get?a=5
 #>   request_headers: 
-#>     useragent: libcurl/7.51.0 r-curl/2.6 crul/0.3.8
 #>   response_headers: 
 #>     status: HTTP/1.1 200 OK
 #>     connection: keep-alive
 #>     server: meinheld/0.6.1
-#>     date: Tue, 13 Jun 2017 22:26:33 GMT
+#>     date: Mon, 02 Oct 2017 19:21:08 GMT
 #>     content-type: application/json
 #>     access-control-allow-origin: *
 #>     access-control-allow-credentials: true
 #>     x-powered-by: Flask
-#>     x-processed-time: 0.000774145126343
-#>     content-length: 302
+#>     x-processed-time: 0.00125598907471
+#>     content-length: 349
 #>     via: 1.1 vegur
 #>   params: 
 #>     a: 5
@@ -84,18 +83,17 @@ Make request with any HTTP method
 #> <crul response> 
 #>   url: https://httpbin.org/get?a=5&b=6
 #>   request_headers: 
-#>     useragent: libcurl/7.51.0 r-curl/2.6 crul/0.3.8
 #>   response_headers: 
 #>     status: HTTP/1.1 200 OK
 #>     connection: keep-alive
 #>     server: meinheld/0.6.1
-#>     date: Tue, 13 Jun 2017 22:26:33 GMT
+#>     date: Mon, 02 Oct 2017 19:21:07 GMT
 #>     content-type: application/json
 #>     access-control-allow-origin: *
 #>     access-control-allow-credentials: true
 #>     x-powered-by: Flask
-#>     x-processed-time: 0.00131487846375
-#>     content-length: 321
+#>     x-processed-time: 0.00107097625732
+#>     content-length: 368
 #>     via: 1.1 vegur
 #>   params: 
 #>     a: 5
@@ -106,17 +104,16 @@ Make request with any HTTP method
 #> <crul response> 
 #>   url: https://httpbin.org/ip
 #>   request_headers: 
-#>     useragent: libcurl/7.51.0 r-curl/2.6 crul/0.3.8
 #>   response_headers: 
 #>     status: HTTP/1.1 200 OK
 #>     connection: keep-alive
 #>     server: meinheld/0.6.1
-#>     date: Tue, 13 Jun 2017 22:26:33 GMT
+#>     date: Mon, 02 Oct 2017 19:21:08 GMT
 #>     content-type: application/json
 #>     access-control-allow-origin: *
 #>     access-control-allow-credentials: true
 #>     x-powered-by: Flask
-#>     x-processed-time: 0.000844955444336
+#>     x-processed-time: 0.000734090805054
 #>     content-length: 33
 #>     via: 1.1 vegur
 #>   status: 200
@@ -133,7 +130,7 @@ res[[1]]$url
 res[[1]]$success()
 #> [1] TRUE
 res[[1]]$parse("UTF-8")
-#> [1] "{\n  \"args\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.51.0 r-curl/2.6 crul/0.3.8\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get?a=5\"\n}\n"
+#> [1] "{\n  \"args\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get?a=5\"\n}\n"
 ```
 
 Or apply access/method calls aross many results, e.g., parse all results
@@ -142,10 +139,10 @@ Or apply access/method calls aross many results, e.g., parse all results
 ```r
 lapply(res, function(z) z$parse("UTF-8"))
 #> [[1]]
-#> [1] "{\n  \"args\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.51.0 r-curl/2.6 crul/0.3.8\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get?a=5\"\n}\n"
+#> [1] "{\n  \"args\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get?a=5\"\n}\n"
 #> 
 #> [[2]]
-#> [1] "{\n  \"args\": {\n    \"a\": \"5\", \n    \"b\": \"6\"\n  }, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.51.0 r-curl/2.6 crul/0.3.8\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get?a=5&b=6\"\n}\n"
+#> [1] "{\n  \"args\": {\n    \"a\": \"5\", \n    \"b\": \"6\"\n  }, \n  \"headers\": {\n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get?a=5&b=6\"\n}\n"
 #> 
 #> [[3]]
 #> [1] "{\n  \"origin\": \"157.130.179.86\"\n}\n"
@@ -200,8 +197,8 @@ Parse all results
 
 ```r
 res$parse()
-#> [1] "{\n  \"args\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.51.0 r-curl/2.6 crul/0.3.8\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get?a=5\"\n}\n"                                                                                                                                    [...]
-#> [2] "{\n  \"args\": {\n    \"a\": \"5\", \n    \"b\": \"6\"\n  }, \n  \"data\": \"\", \n  \"files\": {}, \n  \"form\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Content-Length\": \"137\", \n    \"Content-Type\": \"multipart/form-data; boundary=------------------------4cd6745fc264b623\", \n    \"Expect\": \"100-continue\", \n    \"Host\": \"httpbin.org\", \n    \"User-Age [...]
+#> [1] "{\n  \"args\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get?a=5\"\n}\n"                                                                                     [...]
+#> [2] "{\n  \"args\": {\n    \"a\": \"5\", \n    \"b\": \"6\"\n  }, \n  \"data\": \"\", \n  \"files\": {}, \n  \"form\": {\n    \"a\": \"5\"\n  }, \n  \"headers\": {\n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Content-Length\": \"137\", \n    \"Content-Type\": \"multipart/form-data; boundary=------------------------9223144570b5d592\", \n    \"Host\": \"httpbin.org\", \n    \ [...]
 ```
 
 
@@ -213,11 +210,11 @@ lapply(res$parse(), jsonlite::prettify)
 #>         "a": "5"
 #>     },
 #>     "headers": {
-#>         "Accept": "*/*",
+#>         "Accept": "application/json, text/xml, application/xml, */*",
 #>         "Accept-Encoding": "gzip, deflate",
 #>         "Connection": "close",
 #>         "Host": "httpbin.org",
-#>         "User-Agent": "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"
+#>         "User-Agent": "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0"
 #>     },
 #>     "origin": "157.130.179.86",
 #>     "url": "https://httpbin.org/get?a=5"
@@ -238,14 +235,13 @@ lapply(res$parse(), jsonlite::prettify)
 #>         "a": "5"
 #>     },
 #>     "headers": {
-#>         "Accept": "*/*",
+#>         "Accept": "application/json, text/xml, application/xml, */*",
 #>         "Accept-Encoding": "gzip, deflate",
 #>         "Connection": "close",
 #>         "Content-Length": "137",
-#>         "Content-Type": "multipart/form-data; boundary=------------------------4cd6745fc264b623",
-#>         "Expect": "100-continue",
+#>         "Content-Type": "multipart/form-data; boundary=------------------------9223144570b5d592",
 #>         "Host": "httpbin.org",
-#>         "User-Agent": "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"
+#>         "User-Agent": "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0"
 #>     },
 #>     "json": null,
 #>     "origin": "157.130.179.86",
diff --git a/vignettes/crul_vignette.Rmd b/vignettes/crul_vignette.Rmd
index 9e86d89..8cb7c22 100644
--- a/vignettes/crul_vignette.Rmd
+++ b/vignettes/crul_vignette.Rmd
@@ -109,17 +109,19 @@ res$content
 #>   [1] 7b 0a 20 20 22 61 72 67 73 22 3a 20 7b 7d 2c 20 0a 20 20 22 68 65 61
 #>  [24] 64 65 72 73 22 3a 20 7b 0a 20 20 20 20 22 41 22 3a 20 22 68 65 6c 6c
 #>  [47] 6f 20 77 6f 72 6c 64 22 2c 20 0a 20 20 20 20 22 41 63 63 65 70 74 22
-#>  [70] 3a 20 22 2a 2f 2a 22 2c 20 0a 20 20 20 20 22 41 63 63 65 70 74 2d 45
-#>  [93] 6e 63 6f 64 69 6e 67 22 3a 20 22 67 7a 69 70 2c 20 64 65 66 6c 61 74
-#> [116] 65 22 2c 20 0a 20 20 20 20 22 43 6f 6e 6e 65 63 74 69 6f 6e 22 3a 20
-#> [139] 22 63 6c 6f 73 65 22 2c 20 0a 20 20 20 20 22 48 6f 73 74 22 3a 20 22
-#> [162] 68 74 74 70 62 69 6e 2e 6f 72 67 22 2c 20 0a 20 20 20 20 22 55 73 65
-#> [185] 72 2d 41 67 65 6e 74 22 3a 20 22 6c 69 62 63 75 72 6c 2f 37 2e 35 31
-#> [208] 2e 30 20 72 2d 63 75 72 6c 2f 32 2e 36 20 63 72 75 6c 2f 30 2e 33 2e
-#> [231] 38 22 0a 20 20 7d 2c 20 0a 20 20 22 6f 72 69 67 69 6e 22 3a 20 22 31
-#> [254] 35 37 2e 31 33 30 2e 31 37 39 2e 38 36 22 2c 20 0a 20 20 22 75 72 6c
-#> [277] 22 3a 20 22 68 74 74 70 73 3a 2f 2f 68 74 74 70 62 69 6e 2e 6f 72 67
-#> [300] 2f 67 65 74 22 0a 7d 0a
+#>  [70] 3a 20 22 61 70 70 6c 69 63 61 74 69 6f 6e 2f 6a 73 6f 6e 2c 20 74 65
+#>  [93] 78 74 2f 78 6d 6c 2c 20 61 70 70 6c 69 63 61 74 69 6f 6e 2f 78 6d 6c
+#> [116] 2c 20 2a 2f 2a 22 2c 20 0a 20 20 20 20 22 41 63 63 65 70 74 2d 45 6e
+#> [139] 63 6f 64 69 6e 67 22 3a 20 22 67 7a 69 70 2c 20 64 65 66 6c 61 74 65
+#> [162] 22 2c 20 0a 20 20 20 20 22 43 6f 6e 6e 65 63 74 69 6f 6e 22 3a 20 22
+#> [185] 63 6c 6f 73 65 22 2c 20 0a 20 20 20 20 22 48 6f 73 74 22 3a 20 22 68
+#> [208] 74 74 70 62 69 6e 2e 6f 72 67 22 2c 20 0a 20 20 20 20 22 55 73 65 72
+#> [231] 2d 41 67 65 6e 74 22 3a 20 22 6c 69 62 63 75 72 6c 2f 37 2e 35 34 2e
+#> [254] 30 20 72 2d 63 75 72 6c 2f 32 2e 38 2e 31 20 63 72 75 6c 2f 30 2e 34
+#> [277] 2e 30 22 0a 20 20 7d 2c 20 0a 20 20 22 6f 72 69 67 69 6e 22 3a 20 22
+#> [300] 31 35 37 2e 31 33 30 2e 31 37 39 2e 38 36 22 2c 20 0a 20 20 22 75 72
+#> [323] 6c 22 3a 20 22 68 74 74 70 73 3a 2f 2f 68 74 74 70 62 69 6e 2e 6f 72
+#> [346] 67 2f 67 65 74 22 0a 7d 0a
 ```
 
 HTTP method
@@ -136,11 +138,14 @@ Request headers
 ```r
 res$request_headers
 #> $`User-Agent`
-#> [1] "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"
+#> [1] "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0"
 #> 
 #> $`Accept-Encoding`
 #> [1] "gzip, deflate"
 #> 
+#> $Accept
+#> [1] "application/json, text/xml, application/xml, */*"
+#> 
 #> $a
 #> [1] "hello world"
 ```
@@ -160,7 +165,7 @@ res$response_headers
 #> [1] "meinheld/0.6.1"
 #> 
 #> $date
-#> [1] "Tue, 13 Jun 2017 22:26:40 GMT"
+#> [1] "Mon, 02 Oct 2017 19:21:12 GMT"
 #> 
 #> $`content-type`
 #> [1] "application/json"
@@ -175,10 +180,10 @@ res$response_headers
 #> [1] "Flask"
 #> 
 #> $`x-processed-time`
-#> [1] "0.000635147094727"
+#> [1] "0.000802993774414"
 #> 
 #> $`content-length`
-#> [1] "307"
+#> [1] "354"
 #> 
 #> $via
 #> [1] "1.1 vegur"
@@ -189,7 +194,7 @@ And you can parse the content with a provided function:
 
 ```r
 res$parse()
-#> [1] "{\n  \"args\": {}, \n  \"headers\": {\n    \"A\": \"hello world\", \n    \"Accept\": \"*/*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.51.0 r-curl/2.6 crul/0.3.8\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get\"\n}\n"
+#> [1] "{\n  \"args\": {}, \n  \"headers\": {\n    \"A\": \"hello world\", \n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"gzip, deflate\", \n    \"Connection\": \"close\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0\"\n  }, \n  \"origin\": \"157.130.179.86\", \n  \"url\": \"https://httpbin.org/get\"\n}\n"
 jsonlite::fromJSON(res$parse())
 #> $args
 #> named list()
@@ -199,7 +204,7 @@ jsonlite::fromJSON(res$parse())
 #> [1] "hello world"
 #> 
 #> $headers$Accept
-#> [1] "*/*"
+#> [1] "application/json, text/xml, application/xml, */*"
 #> 
 #> $headers$`Accept-Encoding`
 #> [1] "gzip, deflate"
@@ -211,7 +216,7 @@ jsonlite::fromJSON(res$parse())
 #> [1] "httpbin.org"
 #> 
 #> $headers$`User-Agent`
-#> [1] "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"
+#> [1] "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0"
 #> 
 #> 
 #> $origin
@@ -243,7 +248,7 @@ f <- tempfile()
 res <- x$get(disk = f)
 # when using write to disk, content is a path
 res$content 
-#> [1] "/var/folders/gs/4khph0xs0436gmd2gdnwsg080000gn/T//RtmpF4Mh1B/file6fcc2a328add"
+#> [1] "/var/folders/gs/4khph0xs0436gmd2gdnwsg080000gn/T//RtmpQrTvWo/file146142af607c4"
 ```
 
 Read lines
@@ -275,11 +280,11 @@ readLines(res$content, n = 10)
 #>   auth: 
 #>   headers:
 res <- x$get('stream/5', stream = function(x) cat(rawToChar(x)))
-#> {"url": "https://httpbin.org/stream/5", "headers": {"Host": "httpbin.org", "Connection": "close", "Accept-Encoding": "gzip, deflate", "Accept": "*/*", "User-Agent": "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"}, "args": {}, "origin": "157.130.179.86", "id": 0}
-#> {"url": "https://httpbin.org/stream/5", "headers": {"Host": "httpbin.org", "Connection": "close", "Accept-Encoding": "gzip, deflate", "Accept": "*/*", "User-Agent": "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"}, "args": {}, "origin": "157.130.179.86", "id": 1}
-#> {"url": "https://httpbin.org/stream/5", "headers": {"Host": "httpbin.org", "Connection": "close", "Accept-Encoding": "gzip, deflate", "Accept": "*/*", "User-Agent": "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"}, "args": {}, "origin": "157.130.179.86", "id": 2}
-#> {"url": "https://httpbin.org/stream/5", "headers": {"Host": "httpbin.org", "Connection": "close", "Accept-Encoding": "gzip, deflate", "Accept": "*/*", "User-Agent": "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"}, "args": {}, "origin": "157.130.179.86", "id": 3}
-#> {"url": "https://httpbin.org/stream/5", "headers": {"Host": "httpbin.org", "Connection": "close", "Accept-Encoding": "gzip, deflate", "Accept": "*/*", "User-Agent": "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"}, "args": {}, "origin": "157.130.179.86", "id": 4}
+#> {"id": 0, "origin": "157.130.179.86", "args": {}, "headers": {"User-Agent": "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0", "Accept": "application/json, text/xml, application/xml, */*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Host": "httpbin.org"}, "url": "https://httpbin.org/stream/5"}
+#> {"id": 1, "origin": "157.130.179.86", "args": {}, "headers": {"User-Agent": "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0", "Accept": "application/json, text/xml, application/xml, */*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Host": "httpbin.org"}, "url": "https://httpbin.org/stream/5"}
+#> {"id": 2, "origin": "157.130.179.86", "args": {}, "headers": {"User-Agent": "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0", "Accept": "application/json, text/xml, application/xml, */*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Host": "httpbin.org"}, "url": "https://httpbin.org/stream/5"}
+#> {"id": 3, "origin": "157.130.179.86", "args": {}, "headers": {"User-Agent": "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0", "Accept": "application/json, text/xml, application/xml, */*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Host": "httpbin.org"}, "url": "https://httpbin.org/stream/5"}
+#> {"id": 4, "origin": "157.130.179.86", "args": {}, "headers": {"User-Agent": "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0", "Accept": "application/json, text/xml, application/xml, */*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Host": "httpbin.org"}, "url": "https://httpbin.org/stream/5"}
 # when streaming, content is NULL
 res$content 
 #> NULL
diff --git a/vignettes/how-to-use-crul.Rmd b/vignettes/how-to-use-crul.Rmd
index fc9951e..b786d9a 100644
--- a/vignettes/how-to-use-crul.Rmd
+++ b/vignettes/how-to-use-crul.Rmd
@@ -68,7 +68,7 @@ make_request("https://httpbin.org/get")
 #> 
 #> $headers
 #> $headers$Accept
-#> [1] "*/*"
+#> [1] "application/json, text/xml, application/xml, */*"
 #> 
 #> $headers$`Accept-Encoding`
 #> [1] "gzip, deflate"
@@ -80,7 +80,7 @@ make_request("https://httpbin.org/get")
 #> [1] "httpbin.org"
 #> 
 #> $headers$`User-Agent`
-#> [1] "libcurl/7.51.0 r-curl/2.6 crul/0.3.8"
+#> [1] "libcurl/7.54.0 r-curl/2.8.1 crul/0.4.0"
 #> 
 #> 
 #> $origin
@@ -144,7 +144,7 @@ make_request2("https://api.crossref.org/works?rows=0")
 #> named list()
 #> 
 #> $message$`total-results`
-#> [1] 89155073
+#> [1] 91794003
 #> 
 #> $message$items
 #> list()
@@ -189,7 +189,7 @@ make_request2("https://api.crossref.org/works", query = list(rows = 0))
 #> named list()
 #> 
 #> $message$`total-results`
-#> [1] 89155073
+#> [1] 91794003
 #> 
 #> $message$items
 #> list()

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/r-cran-crul.git



More information about the debian-med-commit mailing list