Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
7 changes: 5 additions & 2 deletions packages/client-python/src/rocketride/mixins/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,8 +313,11 @@ def _get_websocket_uri(uri: str) -> str:
parsed = urllib.parse.urlparse(normalized)

ws_scheme = 'wss' if parsed.scheme in ('https', 'wss') else 'ws'
ws_uri = parsed._replace(scheme=ws_scheme)
return f'{ws_uri.geturl()}/task/service'
path = parsed.path.rstrip('/')
if not path.endswith('/task/service'):
path = f'{path}/task/service' if path else '/task/service'
ws_uri = parsed._replace(scheme=ws_scheme, path=path)
return ws_uri.geturl()

def _set_uri(self, uri: str) -> None:
"""Update the server URI (internal)."""
Expand Down
22 changes: 22 additions & 0 deletions packages/client-python/tests/test_connection_uri.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import pytest

from rocketride.mixins.connection import ConnectionMixin


@pytest.mark.parametrize(
('input_uri', 'expected_uri'),
[
('http://localhost:5565', 'ws://localhost:5565/task/service'),
('http://localhost:5565/', 'ws://localhost:5565/task/service'),
('https://cloud.rocketride.ai', 'wss://cloud.rocketride.ai/task/service'),
('https://cloud.rocketride.ai/', 'wss://cloud.rocketride.ai/task/service'),
('wss://cloud.rocketride.ai', 'wss://cloud.rocketride.ai/task/service'),
('wss://cloud.rocketride.ai/', 'wss://cloud.rocketride.ai/task/service'),
('wss://cloud.rocketride.ai/task/service', 'wss://cloud.rocketride.ai/task/service'),
('ws://localhost:5565', 'ws://localhost:5565/task/service'),
('ws://localhost:5565/', 'ws://localhost:5565/task/service'),
('ws://localhost:5565/task/service', 'ws://localhost:5565/task/service'),
],
Comment thread
coderabbitai[bot] marked this conversation as resolved.
)
def test_get_websocket_uri_normalizes_task_service_path(input_uri, expected_uri):
assert ConnectionMixin._get_websocket_uri(input_uri) == expected_uri
14 changes: 12 additions & 2 deletions packages/client-typescript/src/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -435,13 +435,23 @@ export class RocketRideClient extends DAPClient {
*/
private _getWebsocketUri(uri: string): string {
const httpUrl = RocketRideClient.normalizeUri(uri);
const SERVICE_PATH = '/task/service';

try {
const url = new URL(httpUrl);
const wsScheme = url.protocol === 'https:' || url.protocol === 'wss:' ? 'wss:' : 'ws:';
return `${wsScheme}//${url.host}/task/service`;
// Normalize the path: strip trailing slash, then append /task/service
// only if it isn't already present (prevents double-path when callers
// pass an already-normalized WebSocket endpoint).
let path = url.pathname.replace(/\/+$/, '');
if (!path.endsWith(SERVICE_PATH)) {
path = path ? `${path}${SERVICE_PATH}` : SERVICE_PATH;
}
return `${wsScheme}//${url.host}${path}`;
} catch {
return `${httpUrl}/task/service`;
// Fallback for unparseable URIs — same trailing-slash + dedup logic
const stripped = httpUrl.replace(/\/+$/, '');
return stripped.endsWith(SERVICE_PATH) ? stripped : `${stripped}${SERVICE_PATH}`;
Comment on lines +446 to +454
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether the TS test file already covers trailing-slash and pre-normalized-path cases.
rg -n "trailing|task/service" --type=ts packages/client-typescript/tests/

Repository: rocketride-org/rocketride-server

Length of output: 608


🏁 Script executed:

# First, read the actual test file context around the URI normalization tests
sed -n '2186,2200p' packages/client-typescript/tests/RocketRideClient.test.ts

Repository: rocketride-org/rocketride-server

Length of output: 681


🏁 Script executed:

# Read the code being tested to verify the logic matches the suggested test cases
sed -n '440,460p' packages/client-typescript/src/client/client.ts

Repository: rocketride-org/rocketride-server

Length of output: 880


TypeScript tests are missing the exact regression cases this PR fixes.

The existing RocketRideClient URI normalization suite (lines 2186-2198) covers only bare host inputs. The PR's stated fixes — preventing double trailing slashes (e.g., wss://host//task/service) and avoiding duplicate path segments (e.g., wss://host/task/service/task/service) — have no TS-side test coverage.

Suggested additions:

 it.each([
   ['wss://cloud.rocketride.ai', 'wss://cloud.rocketride.ai/task/service'],
   ['https://cloud.rocketride.ai', 'wss://cloud.rocketride.ai/task/service'],
   ['ws://localhost:5565', 'ws://localhost:5565/task/service'],
   ['http://localhost:5565', 'ws://localhost:5565/task/service'],
+  // trailing-slash regression: must not produce double slash
+  ['wss://cloud.rocketride.ai/', 'wss://cloud.rocketride.ai/task/service'],
+  ['https://cloud.rocketride.ai/', 'wss://cloud.rocketride.ai/task/service'],
+  ['http://localhost:5565/', 'ws://localhost:5565/task/service'],
+  // pre-normalized path: must not duplicate /task/service
+  ['wss://cloud.rocketride.ai/task/service', 'wss://cloud.rocketride.ai/task/service'],
+  ['https://cloud.rocketride.ai/task/service', 'wss://cloud.rocketride.ai/task/service'],
 ])('normalizes %s to %s', (inputUri, expectedUri) => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/client-typescript/src/client/client.ts` around lines 446 - 454, Add
TypeScript tests to the existing "RocketRideClient URI normalization" suite to
cover the regression cases this PR fixes: add cases that ensure duplicate
slashes are collapsed (e.g., input "wss://host//task/service" => normalized
"wss://host/task/service") and cases that prevent duplicated path segments
(e.g., input "wss://host/task/service/task/service" => normalized
"wss://host/task/service"). Place these new assertions alongside the existing
RocketRideClient tests (the suite referenced in client.ts URI normalization
logic that uses SERVICE_PATH and the try/catch path normalization), verifying
both the parsed/wsScheme branch and the fallback unparseable-URI branch produce
the expected single canonical path.

}
}

Expand Down
Loading