Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User agent and proxy options #21

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions R/default_objects.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
has_default_selenium_object <- function() {
!is.null(default_selenium_object()) &&
default_selenium_object()$is_alive()
}

default_selenium_object <- function() {
get_from_env("selenium")
}

set_default_selenium_object <- function(x) {
if (has_default_selenium_object()) {
default_selenium_object()$kill()
}

set_in_env(selenium = x)
}

default_selenium_options <- function() {
get_from_env("selenium_options")
}

set_default_selenium_options <- function(x) {
set_in_env(selenium_options = x)
}

# We manage our own default chromote object to make sure we make a new one
# whenever the arguments passed into chrome change.
default_chromote_object <- function() {
get_from_env("chromote")
}

has_default_chromote_object <- function() {
!is.null(default_chromote_object()) &&
default_chromote_object()$get_browser()$get_process()$is_alive()
}

set_default_chromote_object <- function(x) {
set_in_env(chromote = x)
}

default_chromote_args <- function() {
get_from_env("chromote_args")
}

set_default_chromote_args <- function(x) {
set_in_env(chromote_args = x)
}
24 changes: 0 additions & 24 deletions R/selenium.R

This file was deleted.

60 changes: 58 additions & 2 deletions R/session-options.R
Original file line number Diff line number Diff line change
Expand Up @@ -31,29 +31,85 @@
#' that you won't actually be able to see the browser as you control it.
#' For debugging purposes and interactive use, it is often useful to set
#' this to `FALSE`.
#' @param user_agent A string containing a custom user agent to use for all
#' requests.
#' @param proxy_server A proxy server to use for all requests. Either a string
#' of the form `"HOST:PORT"`, or a list containing the `host` and `port`.
#' Optionally, `username` and `password` can be provided if the proxy server
#' requires authentication.
#' @param extra_args A character vector of arguments. In `chromote_options()`,
#' these are passed to the Chrome process. In `selenium_client_options()`,
#' these are passed to the Selenium server process.
#' @param parent The parent chromote session.
#' @param width,height,targetId,wait_,auto_events Passed into
#' [chromote::ChromoteSession$new()][chromote::ChromoteSession].
#'
#'
#' @export
chromote_options <- function(headless = TRUE,
user_agent = NULL,
proxy_server = NULL,
extra_args = NULL,
parent = NULL,
width = 992,
height = 1323,
targetId = NULL, # nolint: object_name_linter
wait_ = TRUE,
auto_events = NULL) {
check_bool(headless)
check_string(user_agent, allow_null = TRUE)

if (!is.null(proxy_server)) {
if (is_string(proxy_server)) {
proxy_server <- list(server = url)
} else if (is.list(proxy_server)) {
check_string(proxy_server$host)
check_number_whole(proxy_server$port)

# TODO: Require chromote version that allows .enable() methods
check_string(proxy_server$username, allow_null = TRUE)
check_string(proxy_server$password, allow_null = TRUE)

if (!is.null(proxy_server$username) && is.null(proxy_server$password)) {
rlang::abort("`proxy_server$username` was provided but `proxy_server$password` was not.")
} else if (is.null(proxy_server$username) && !is.null(proxy_server$password)) {
rlang::abort("`proxy_server$password` was provided but `proxy_server$username` was not.")
}

proxy_server <- list(
server = paste0(proxy_server$host, ":", proxy_server$port),
username = proxy_server$username,
password = proxy_server$password
)
} else {
stop_input_type(proxy_server, c("a string", "a list"), allow_null = TRUE)
}
}

check_string(extra_args, allow_null = TRUE)
check_class(parent, "Chromote", allow_null = TRUE)
check_number_whole(width)
check_number_whole(height)
check_string(targetId, allow_null = TRUE)
check_bool(wait_)
check_bool(auto_events, allow_null = TRUE)

if (!is.null(parent)) {
if (!is.null(proxy_server)) {
rlang::warn(c(
"`proxy_server` requires passing in arguments to the Chrome process",
"x" = "Since `parent` was provided, `proxy_server` will be ignored."
))
}
if (!is.null(extra_args)) {
rlang::warn("Since `parent` was provided, `extra_args` will be ignored.")
}
}

result <- list(
headless = headless,
user_agent = user_agent,
proxy_server = proxy_server,
extra_args = extra_args,
parent = parent,
width = width,
height = height,
Expand Down Expand Up @@ -93,7 +149,7 @@ selenium_options <- function(client_options = selenium_client_options(),
#'
#' @param version The version of Selenium server to use.
#' @param port The port number to use.
#' @param selenium_manager,verbose,temp,path,interactive,echo_cmd,extra_args
#' @param selenium_manager,verbose,temp,path,interactive,echo_cmd
#' Passed into [selenium::selenium_server()].
#'
#' @export
Expand Down
100 changes: 82 additions & 18 deletions R/session.R
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,6 @@ selenider_session <- function(session = getOption("selenider.session"),
}
}



check_string(session, allow_null = TRUE)
check_string(browser, allow_null = TRUE)
check_number_decimal(timeout, allow_null = TRUE)
Expand Down Expand Up @@ -374,10 +372,6 @@ get_driver <- function(browser, options, driver) {
create_chromote_session_internal(options),
message = "Chromote session failed to start."
)

if (!options$headless) {
driver$view()
}
} else {
reuse_server <- inherits(options$server_options, "selenium_server_options") &&
has_default_selenium_object() &&
Expand Down Expand Up @@ -564,30 +558,100 @@ create_chromote_session_internal <- function(options = chromote_options()) {
rlang::check_installed("chromote")

parent <- options$parent
options <- options[!names(options) %in% c("parent", "headless")]
headless <- options$headless
user_agent <- options$user_agent
proxy_server <- options$proxy_server
extra_args <- options$extra_args
options <- options[!names(options) %in% c("parent", "headless", "user_agent", "proxy_server", "extra_args")]

timeout <- if (on_ci()) 60 * 5 else 60

withr::local_options(list(chromote.timeout = timeout))

if (is.null(parent) && default_chromote_object_alive()) {
reset_default_chromote_object()
args <- chromote::get_chrome_args()
if (!is.null(extra_args)) {
args <- unique(c(args, extra_args))
}

if (!is.null(proxy_server)) {
args <- args[-grepl("--proxy-server", args, fixed = TRUE)]
args <- c(
args,
paste0("--proxy-server=", proxy_server$server)
)
}

if (is.null(parent)) {
parent <- chromote::default_chromote_object()
last_args <- default_chromote_args()
last_chromote_object_alive <- has_default_chromote_object()

# We only need to create a new chrome process if we want the browser to take different arguments.
if (setequal(last_args, args) && last_chromote_object_alive) {
parent <- default_chromote_object()
} else {
if (last_chromote_object_alive) {
default_chromote_object()$close()
}

parent <- chromote::Chromote$new(
browser = chromote::Chrome$new(args = args)
)
set_default_chromote_object(parent)
set_default_chromote_args(args)
}
}

rlang::inject(chromote::ChromoteSession$new(parent = parent, !!!options))
}
driver <- rlang::inject(chromote::ChromoteSession$new(parent = parent, !!!options))

default_chromote_object_alive <- function() {
chromote::has_default_chromote_object() &&
!chromote::default_chromote_object()$get_browser()$get_process()$is_alive()
}
if (!headless) {
driver$view()
}

if (!is.null(user_agent)) {
driver$Network$setUserAgentOverride(userAgent = user_agent)
}

reset_default_chromote_object <- function() {
chromote::set_default_chromote_object(chromote::Chromote$new())
if (!is.null(proxy_server) && !is.null(proxy_server$username)) {
# Setup handlers for proxy server authentication
authenticate <- function(x) {
id <- x$requestId

response <- list(
response = "ProvideCredentials",
username = proxy_server$username,
password = proxy_server$password
)

driver$Fetch$continueWithAuth(
requestId = id,
authChallengeResponse = response
)
}

# Ignore requests that don't need authentication
continue_request <- function(x) {
id <- x$requestId

driver$Fetch$continueRequest(requestId = id)
}

driver$Fetch$enable(
patterns = list(
list(urlPattern = "*")
),
handleAuthRequests = TRUE
)

driver$Fetch$requestPaused(
callback_ = continue_request
)

driver$Fetch$authRequired(
callback_ = authenticate
)
}

driver
}

#' @rdname create_chromote_session
Expand Down
17 changes: 16 additions & 1 deletion man/chromote_options.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading