Parse response header data as returned by curl_fetch, either as a set of strings or into a named list.
Details
The parse_headers_list function parses the headers into a normalized (lowercase field names, trimmed whitespace) named list.
If a request has followed redirects, the data can contain multiple sets of headers. When multiple = TRUE, the function returns a list with the response headers for each request. By default it only returns the headers of the final request.
Examples
req <- curl_fetch_memory("https://hb.cran.dev/redirect/3")
parse_headers(req$headers)
#> [1] "HTTP/2 200 "
#> [2] "date: Mon, 11 May 2026 16:26:29 GMT"
#> [3] "content-type: application/json"
#> [4] "server: cloudflare"
#> [5] "nel: {\"report_to\":\"cf-nel\",\"success_fraction\":0.0,\"max_age\":604800}"
#> [6] "access-control-allow-origin: *"
#> [7] "access-control-allow-credentials: true"
#> [8] "x-powered-by: Flask"
#> [9] "x-processed-time: 0"
#> [10] "cf-cache-status: DYNAMIC"
#> [11] "report-to: {\"group\":\"cf-nel\",\"max_age\":604800,\"endpoints\":[{\"url\":\"https://a.nel.cloudflare.com/report/v4?s=bz5ZbDTIbsHGU%2F6jmqqZIZ0To9%2B7Na4McWoO%2FBqHHp%2B4K0pe3E1H7jQuUmzhocMoycn9cS9l%2BQ9yqe6d24bzW%2BJ1v23Gcy18n%2FbdbESM3A93tDpsLHruKKQ16oNq0g%3D%3D\"}]}"
#> [12] "content-encoding: zstd"
#> [13] "cf-ray: 9fa28badbf370abb-CMH"
#> [14] "alt-svc: h3=\":443\"; ma=86400"
parse_headers(req$headers, multiple = TRUE)
#> [[1]]
#> [1] "HTTP/2 302 "
#> [2] "date: Mon, 11 May 2026 16:26:29 GMT"
#> [3] "content-type: text/html; charset=utf-8"
#> [4] "server: cloudflare"
#> [5] "nel: {\"report_to\":\"cf-nel\",\"success_fraction\":0.0,\"max_age\":604800}"
#> [6] "location: /relative-redirect/2"
#> [7] "access-control-allow-origin: *"
#> [8] "access-control-allow-credentials: true"
#> [9] "x-powered-by: Flask"
#> [10] "x-processed-time: 0"
#> [11] "cf-cache-status: DYNAMIC"
#> [12] "report-to: {\"group\":\"cf-nel\",\"max_age\":604800,\"endpoints\":[{\"url\":\"https://a.nel.cloudflare.com/report/v4?s=jNDDVQa53AYCWSGhgRl%2FBnkI0jUdYoqdjA5fnbGBV5RsF9XAIXlksH6qDXWmLtfQHE%2Fcqu2YX6G9UiQrUA%2F9lYjMUDj8qK%2F3h4qIVPsyFYBsCHPq24OCV7pdlXwyow%3D%3D\"}]}"
#> [13] "cf-ray: 9fa28bad2eab0abb-CMH"
#> [14] "alt-svc: h3=\":443\"; ma=86400"
#>
#> [[2]]
#> [1] "HTTP/2 302 "
#> [2] "date: Mon, 11 May 2026 16:26:29 GMT"
#> [3] "content-type: text/html; charset=utf-8"
#> [4] "server: cloudflare"
#> [5] "nel: {\"report_to\":\"cf-nel\",\"success_fraction\":0.0,\"max_age\":604800}"
#> [6] "location: /relative-redirect/1"
#> [7] "access-control-allow-origin: *"
#> [8] "access-control-allow-credentials: true"
#> [9] "x-powered-by: Flask"
#> [10] "x-processed-time: 0"
#> [11] "cf-cache-status: DYNAMIC"
#> [12] "report-to: {\"group\":\"cf-nel\",\"max_age\":604800,\"endpoints\":[{\"url\":\"https://a.nel.cloudflare.com/report/v4?s=qUY99EJi8bBw6Nxb6tN%2FzUyhayalD9xzt%2BWsY%2BFVULILVbCd2PBkN%2FJh5J8cwGfxPJ%2FQlMfGykB0S2i6O0dfPTUEMkpqMEJW46Yf1NfVb07zX4AulsjTVeZ%2F1PrWtQ%3D%3D\"}]}"
#> [13] "cf-ray: 9fa28bad5ed10abb-CMH"
#> [14] "alt-svc: h3=\":443\"; ma=86400"
#>
#> [[3]]
#> [1] "HTTP/2 302 "
#> [2] "date: Mon, 11 May 2026 16:26:29 GMT"
#> [3] "content-type: text/html; charset=utf-8"
#> [4] "server: cloudflare"
#> [5] "nel: {\"report_to\":\"cf-nel\",\"success_fraction\":0.0,\"max_age\":604800}"
#> [6] "location: /get"
#> [7] "access-control-allow-origin: *"
#> [8] "access-control-allow-credentials: true"
#> [9] "x-powered-by: Flask"
#> [10] "x-processed-time: 0"
#> [11] "cf-cache-status: DYNAMIC"
#> [12] "report-to: {\"group\":\"cf-nel\",\"max_age\":604800,\"endpoints\":[{\"url\":\"https://a.nel.cloudflare.com/report/v4?s=rdLxz7JYbJevZVTfWSveGzh4XA1TDHQX39o9jIceYQ%2B149am214UpFHWVs59CylBbbd%2FleWV9XkGWvs7yyAnhJAepKxCY97xWmXk5NWT6%2BC5c3rZGQndz3XZznloDw%3D%3D\"}]}"
#> [13] "cf-ray: 9fa28bad8f090abb-CMH"
#> [14] "alt-svc: h3=\":443\"; ma=86400"
#>
#> [[4]]
#> [1] "HTTP/2 200 "
#> [2] "date: Mon, 11 May 2026 16:26:29 GMT"
#> [3] "content-type: application/json"
#> [4] "server: cloudflare"
#> [5] "nel: {\"report_to\":\"cf-nel\",\"success_fraction\":0.0,\"max_age\":604800}"
#> [6] "access-control-allow-origin: *"
#> [7] "access-control-allow-credentials: true"
#> [8] "x-powered-by: Flask"
#> [9] "x-processed-time: 0"
#> [10] "cf-cache-status: DYNAMIC"
#> [11] "report-to: {\"group\":\"cf-nel\",\"max_age\":604800,\"endpoints\":[{\"url\":\"https://a.nel.cloudflare.com/report/v4?s=bz5ZbDTIbsHGU%2F6jmqqZIZ0To9%2B7Na4McWoO%2FBqHHp%2B4K0pe3E1H7jQuUmzhocMoycn9cS9l%2BQ9yqe6d24bzW%2BJ1v23Gcy18n%2FbdbESM3A93tDpsLHruKKQ16oNq0g%3D%3D\"}]}"
#> [12] "content-encoding: zstd"
#> [13] "cf-ray: 9fa28badbf370abb-CMH"
#> [14] "alt-svc: h3=\":443\"; ma=86400"
#>
# Parse into named list
parse_headers_list(req$headers)
#> $date
#> [1] "Mon, 11 May 2026 16:26:29 GMT"
#>
#> $`content-type`
#> [1] "application/json"
#>
#> $server
#> [1] "cloudflare"
#>
#> $nel
#> [1] "{\"report_to\":\"cf-nel\",\"success_fraction\":0.0,\"max_age\":604800}"
#>
#> $`access-control-allow-origin`
#> [1] "*"
#>
#> $`access-control-allow-credentials`
#> [1] "true"
#>
#> $`x-powered-by`
#> [1] "Flask"
#>
#> $`x-processed-time`
#> [1] "0"
#>
#> $`cf-cache-status`
#> [1] "DYNAMIC"
#>
#> $`report-to`
#> [1] "{\"group\":\"cf-nel\",\"max_age\":604800,\"endpoints\":[{\"url\":\"https://a.nel.cloudflare.com/report/v4?s=bz5ZbDTIbsHGU%2F6jmqqZIZ0To9%2B7Na4McWoO%2FBqHHp%2B4K0pe3E1H7jQuUmzhocMoycn9cS9l%2BQ9yqe6d24bzW%2BJ1v23Gcy18n%2FbdbESM3A93tDpsLHruKKQ16oNq0g%3D%3D\"}]}"
#>
#> $`content-encoding`
#> [1] "zstd"
#>
#> $`cf-ray`
#> [1] "9fa28badbf370abb-CMH"
#>
#> $`alt-svc`
#> [1] "h3=\":443\"; ma=86400"
#>