[grid] honor client-advertised se:remoteUrl for reachable BiDi/CDP/VNC URLs#17790
[grid] honor client-advertised se:remoteUrl for reachable BiDi/CDP/VNC URLs#17790titusfortner wants to merge 3 commits into
Conversation
PR Summary by QodoGrid: use client-advertised se:remoteUrl for reachable BiDi/CDP/VNC endpoints
AI Description
Diagram
High-Level Assessment
Files changed (13)
|
Code Review by Qodo
1.
|
|
Code review by qodo was updated up to the latest commit 9a20e5d |
|
Code review by qodo was updated up to the latest commit c8274b1 |
There was a problem hiding this comment.
Pull request overview
This PR makes Selenium Grid return BiDi/CDP/VNC endpoints (webSocketUrl, se:cdp, se:vnc) that are reachable from the client when Grid is accessed via Docker port-mapping or reverse proxies, by having clients advertise the URL they actually used to reach the Grid (se:remoteUrl) and teaching the Node to prefer it when rewriting proxied URLs (unless an operator-configured grid-url is set).
Changes:
- Add
se:remoteUrladvertising in all bindings (Java, JS, Python, Ruby, .NET) when starting remote sessions. - Update Grid Node URL rewriting to use
se:remoteUrlwhengrid-urlis not explicitly configured, while preserving credentials and keepinggrid-urlprecedence. - Add/adjust unit tests (notably Java Node tests and binding-level unit tests) to cover precedence and credential preservation.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| rb/spec/unit/selenium/webdriver/remote/driver_spec.rb | Updates request expectations to include se:remoteUrl in new-session payloads. |
| rb/lib/selenium/webdriver/remote/driver.rb | Ruby Remote driver now advertises se:remoteUrl based on the configured server URL. |
| py/test/unit/selenium/webdriver/remote/new_session_tests.py | Adjusts assertions to ignore the new se:remoteUrl capability when comparing payloads. |
| py/selenium/webdriver/remote/webdriver.py | Python Remote WebDriver adds se:remoteUrl for remote (non-service) sessions. |
| javascript/selenium-webdriver/index.js | JS Builder advertises se:remoteUrl when creating remote sessions. |
| java/test/org/openqa/selenium/remote/RemoteWebDriverUnitTest.java | Adds tests for advertising se:remoteUrl in Java RemoteWebDriver (remote vs local). |
| java/test/org/openqa/selenium/remote/RemoteWebDriverBuilderTest.java | Adds test ensuring builder-advertised se:remoteUrl is sent to the server. |
| java/test/org/openqa/selenium/grid/node/NodeTest.java | Adds regression tests for Node URL rewriting using se:remoteUrl, precedence, and credential preservation. |
| java/src/org/openqa/selenium/remote/RemoteWebDriverBuilder.java | Injects se:remoteUrl into alwaysMatch when a base URI is configured. |
| java/src/org/openqa/selenium/remote/RemoteWebDriver.java | Adds se:remoteUrl to capabilities when the RemoteWebDriver has a non-null base URI. |
| java/src/org/openqa/selenium/grid/node/local/LocalNodeFactory.java | Plumbs whether grid-url was explicitly specified into LocalNode construction. |
| java/src/org/openqa/selenium/grid/node/local/LocalNode.java | Rewrites BiDi/CDP/VNC URLs using resolved “public Grid URI” with precedence rules. |
| dotnet/src/webdriver/WebDriver.cs | .NET WebDriver adds se:remoteUrl when using HttpCommandExecutor (remote sessions). |
| dotnet/src/webdriver/Remote/HttpCommandExecutor.cs | Exposes the remote server URI internally to support se:remoteUrl advertising. |
|
Code review by qodo was updated up to the latest commit 2095666 |
2095666 to
66d29a8
Compare
Code Review by Qodo
1. Ruby http_client NoMethodError
|
| caps = process_options(options, capabilities) | ||
| http_client ||= Remote::Http::Default.new(client_config: client_config) | ||
| http_client.server_url = url || client_config&.server_url || "http://#{Platform.localhost}:4444/wd/hub" | ||
| caps['se:remoteUrl'] = http_client.client_config.server_url.to_s |
There was a problem hiding this comment.
3. Ruby http_client nomethoderror 🐞 Bug ≡ Correctness
Ruby Remote::Driver now unconditionally reads http_client.client_config.server_url when setting se:remoteUrl. If callers provide a custom http_client (supported by Remote::Bridge) that doesn’t expose client_config, driver construction will raise NoMethodError before a session is created.
Agent Prompt
### Issue description
`Remote::Driver#initialize` sets `caps['se:remoteUrl']` by dereferencing `http_client.client_config.server_url`. This assumes every caller-supplied HTTP client exposes `client_config`, but the public contract allows custom clients implementing the `Http::Default` protocol (not necessarily inheriting from `Http::Common`). This can raise `NoMethodError` at construction time.
### Issue Context
The code already has the authoritative remote URL available as `url || client_config&.server_url || default`, and it already assigns that into `http_client.server_url = ...`. The capability should be derived from that known value (or guarded behind `respond_to?(:client_config)`), rather than requiring `client_config` on the HTTP client.
### Fix Focus Areas
- rb/lib/selenium/webdriver/remote/driver.rb[34-47]
- rb/lib/selenium/webdriver/remote/bridge.rb[53-60]
### Suggested fix
1. Compute a `remote_url` local variable from `url || client_config&.server_url || default`.
2. Set both:
- `http_client.server_url = remote_url`
- `caps['se:remoteUrl'] = remote_url.to_s` (ensure trailing `/` if you want consistency with `ClientConfig#server_url` normalization)
3. Do **not** dereference `http_client.client_config` unless you first check `http_client.respond_to?(:client_config)`.
4. Add a regression test that passes a minimal custom http_client implementing `server_url=`/`call` but **not** `client_config`, and asserts initialization/session creation does not crash and that `se:remoteUrl` is present.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
🔗 Related Issues
Fixes #17782
Fixes #17788
💥 What does this PR do?
When a Grid is reached through Docker port-mapping or a reverse proxy, the BiDi/CDP/VNC URLs it hands back (
webSocketUrl,se:cdp,se:vnc) point at the Grid's own view of its address — e.g. a container-internalws://172.20.0.2:4444/...— which the client cannot reach, and causes attempted connections to error.The Grid currently addresses this with a
grid-urlconfiguration (--grid-url/SE_NODE_GRID_URL): when set to the externally-reachable address the Node uses it for the proxied URLs. Except:This PR has each bindiung advertise the url they actually reached the Grid on via a new
se:remoteUrlcapability, which the Node uses to build the proxied URLs. Additional connections to Docker then work with no extra configuration. Note that an explicitly configuredgrid-urlsetting still takes precedence.🔧 Implementation Notes
LocalNode.resolvePublicGridUri), so one server-side change makes the returned URLs reachable for every client; each binding only adds the small producer that sendsse:remoteUrl.resolvePublicGridUri: a configured public Grid URL (grid-url/ hub) is used as-is; otherwisese:remoteUrl; otherwise the Node's auto-detected address (previous behavior). So the capability only fills the gapgrid-urlleaves and never overrides operator intent.se:remoteUrlis not sent for local driver services (only for remote sessions), and when it is absent the behavior is unchanged for older clients.Host-header inference: the client is authoritative about its own reachable address, it is robust behind proxies, and it avoids changes to Grid routing.💡 Additional Considerations
https://user:key@host) are preserved in the resolved URL, identical to how an operator-configuredgrid-urlwith credentials already behaves. This keeps BiDi/CDP auth working against a basic-auth-protected Grid, where the returned websocket URL must carry the credentials. Under HTTPS these are protected in transit; the only residual is at-rest logging, consistent with the Grid already logging full capabilities today. Reducing that would be a separate, Grid-wide log-redaction change rather than mangling the URL the auth path depends on.ClientConfigto set local authentication and proxy behavior, in which case the connection URL carries no credentials andse:remoteUrlcarries none.🤖 AI assistance
🔄 Types of changes