Nothing
#' Perform a request and return a streaming connection
#'
#' @description
#' Use `req_perform_connection()` to perform a request if you want to stream the
#' response body. A response returned by `req_perform_connection()` includes a
#' connection as the body. You can then use [resp_stream_raw()],
#' [resp_stream_lines()], or [resp_stream_sse()] to retrieve data a chunk at a
#' time. Always finish up by closing the connection by calling
#' `close(response)`.
#'
#' This is an alternative interface to [req_perform_stream()] that returns a
#' [connection][base::connections] that you can use to pull the data, rather
#' than providing callbacks that the data is pushed to. This is useful if you
#' want to do other work in between handling inputs from the stream.
#'
#' @inheritParams req_perform
#' @param blocking When retrieving data, should the connection block and wait
#' for the desired information or immediately return what it has (possibly
#' nothing)?
#' @param verbosity How much information to print? This is a wrapper
#' around [req_verbose()] that uses an integer to control verbosity:
#'
#' * `0`: no output
#' * `1`: show headers
#' * `2`: show headers and bodies as they're streamed
#' * `3`: show headers, bodies, curl status messages, raw SSEs, and stream
#' buffer management
#'
#' Use [with_verbosity()] to control the verbosity of requests that
#' you can't affect directly.
#' @export
#' @examples
#' req <- request(example_url()) |>
#' req_url_path("/stream-bytes/32768")
#' resp <- req_perform_connection(req)
#'
#' length(resp_stream_raw(resp, kb = 16))
#' length(resp_stream_raw(resp, kb = 16))
#' # When the stream has no more data, you'll get an empty result:
#' length(resp_stream_raw(resp, kb = 16))
#'
#' # Always close the response when you're done
#' close(resp)
#'
#' # You can loop until complete with resp_stream_is_complete()
#' resp <- req_perform_connection(req)
#' while (!resp_stream_is_complete(resp)) {
#' print(length(resp_stream_raw(resp, kb = 12)))
#' }
#' close(resp)
req_perform_connection <- function(req, blocking = TRUE, verbosity = NULL) {
check_request(req)
check_bool(blocking)
# verbosity checked in req_verbosity_connection
req <- req_verbosity_connection(req, verbosity %||% httr2_verbosity())
req_prep <- req_prepare(req)
handle <- req_handle(req_prep)
the$last_request <- req
the$last_response <- NULL
tries <- 0
delay <- 0
max_tries <- retry_max_tries(req)
deadline <- Sys.time() + retry_max_seconds(req)
resp <- NULL
while (tries < max_tries && Sys.time() < deadline) {
retry_check_breaker(req, tries)
sys_sleep(delay, "for retry backoff")
if (!is.null(resp)) {
close(resp)
}
resp <- req_perform_connection1(req, handle, blocking = blocking)
if (retry_is_transient(req, resp)) {
tries <- tries + 1
delay <- retry_after(req, resp, tries)
signal(class = "httr2_retry", tries = tries, delay = delay)
} else {
break
}
}
req_completed(req)
if (!is_error(resp) && error_is_error(req, resp)) {
# Read full body if there's an error
conn <- resp$body
resp$body <- read_con(conn)
the$last_response <- resp
close(conn)
}
handle_resp(req, resp)
resp
}
# Like req_verbosity() but we want to print the streaming body when it's
# requested not when curl actually receives it
req_verbosity_connection <- function(req, verbosity, error_call = caller_env()) {
if (!is_integerish(verbosity, n = 1) || verbosity < 0 || verbosity > 3) {
cli::cli_abort("{.arg verbosity} must 0, 1, 2, or 3.", call = error_call)
}
req <- switch(verbosity + 1,
req,
req_verbose(req),
req_verbose(req, body_req = TRUE),
req_verbose(req, body_req = TRUE, info = TRUE)
)
if (verbosity > 1) {
req <- req_policies(
req,
show_streaming_body = verbosity >= 2,
show_streaming_buffer = verbosity >= 3
)
}
req
}
req_perform_connection1 <- function(req, handle, blocking = TRUE) {
the$last_request <- req
the$last_response <- NULL
signal(class = "httr2_perform_connection")
err <- capture_curl_error({
body <- curl::curl(req$url, handle = handle)
# Must open the stream in order to initiate the connection
suppressWarnings(open(body, "rbf", blocking = blocking))
})
if (is_error(err)) {
close(body)
return(err)
}
curl_data <- curl::handle_data(handle)
the$last_response <- create_response(req, curl_data, body)
the$last_response
}
# Make open mockable
open <- NULL
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.