From 1431ddde8dfaedd03e96b4350b7f92b8d039bd43 Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Thu, 20 Nov 2025 14:19:23 -0800 Subject: [PATCH] fix(rivetkit): uri encode actor ids to fix cloudfalre workers actor id with generation --- engine/packages/engine/tests/common/actors.rs | 3 ++- .../packages/guard/src/routing/pegboard_gateway.rs | 10 +++++++--- .../cloudflare-workers/src/manager-driver.ts | 4 ++-- .../driver-test-suite/test-inline-client-driver.ts | 12 +++++++++--- .../packages/rivetkit/src/manager/gateway.ts | 2 +- .../packages/rivetkit/src/manager/router.ts | 2 +- 6 files changed, 22 insertions(+), 11 deletions(-) diff --git a/engine/packages/engine/tests/common/actors.rs b/engine/packages/engine/tests/common/actors.rs index 08772a0d07..9bfb04d6f7 100644 --- a/engine/packages/engine/tests/common/actors.rs +++ b/engine/packages/engine/tests/common/actors.rs @@ -437,9 +437,10 @@ pub async fn ping_actor_websocket_via_guard(guard_port: u16, actor_id: &str) -> .expect("Failed to create WebSocket request"); // Add protocols for routing through guard to actor + // URL encode the actor ID since colons are not allowed in WebSocket protocol names request.headers_mut().insert( "Sec-WebSocket-Protocol", - format!("rivet, rivet_target.actor, rivet_actor.{}", actor_id) + format!("rivet, rivet_target.actor, rivet_actor.{}", urlencoding::encode(&actor_id)) .parse() .unwrap(), ); diff --git a/engine/packages/guard/src/routing/pegboard_gateway.rs b/engine/packages/guard/src/routing/pegboard_gateway.rs index 67d02102b5..026d9c8e8b 100644 --- a/engine/packages/guard/src/routing/pegboard_gateway.rs +++ b/engine/packages/guard/src/routing/pegboard_gateway.rs @@ -60,7 +60,7 @@ pub async fn route_request( let protocols: Vec<&str> = protocols_header.split(',').map(|p| p.trim()).collect(); - let actor_id = protocols + let actor_id_raw = protocols .iter() .find_map(|p| p.strip_prefix(WS_PROTOCOL_ACTOR)) .ok_or_else(|| { @@ -70,6 +70,10 @@ pub async fn route_request( .build() })?; + let actor_id = urlencoding::decode(actor_id_raw) + .context("invalid url encoding in actor id")? + .to_string(); + let token = protocols .iter() .find_map(|p| p.strip_prefix(WS_PROTOCOL_TOKEN)); @@ -95,11 +99,11 @@ pub async fn route_request( .transpose() .context("invalid x-rivet-token header")?; - (actor_id, token) + (actor_id.to_string(), token) }; // Find actor to route to - let actor_id = Id::parse(actor_id_str).context("invalid x-rivet-actor header")?; + let actor_id = Id::parse(&actor_id_str).context("invalid x-rivet-actor header")?; route_request_inner(ctx, shared_state, actor_id, path, token).await } diff --git a/rivetkit-typescript/packages/cloudflare-workers/src/manager-driver.ts b/rivetkit-typescript/packages/cloudflare-workers/src/manager-driver.ts index d50f700f33..d4fcc05b7c 100644 --- a/rivetkit-typescript/packages/cloudflare-workers/src/manager-driver.ts +++ b/rivetkit-typescript/packages/cloudflare-workers/src/manager-driver.ts @@ -86,7 +86,7 @@ export class CloudflareActorsManagerDriver implements ManagerDriver { const protocols: string[] = []; protocols.push(WS_PROTOCOL_STANDARD); protocols.push(`${WS_PROTOCOL_TARGET}actor`); - protocols.push(`${WS_PROTOCOL_ACTOR}${actorId}`); + protocols.push(`${WS_PROTOCOL_ACTOR}${encodeURIComponent(actorId)}`); protocols.push(`${WS_PROTOCOL_ENCODING}${encoding}`); if (params) { protocols.push( @@ -205,7 +205,7 @@ export class CloudflareActorsManagerDriver implements ManagerDriver { const protocols: string[] = []; protocols.push(WS_PROTOCOL_STANDARD); protocols.push(`${WS_PROTOCOL_TARGET}actor`); - protocols.push(`${WS_PROTOCOL_ACTOR}${actorId}`); + protocols.push(`${WS_PROTOCOL_ACTOR}${encodeURIComponent(actorId)}`); protocols.push(`${WS_PROTOCOL_ENCODING}${encoding}`); if (params) { protocols.push( diff --git a/rivetkit-typescript/packages/rivetkit/src/driver-test-suite/test-inline-client-driver.ts b/rivetkit-typescript/packages/rivetkit/src/driver-test-suite/test-inline-client-driver.ts index f25376b2f3..f273d2170e 100644 --- a/rivetkit-typescript/packages/rivetkit/src/driver-test-suite/test-inline-client-driver.ts +++ b/rivetkit-typescript/packages/rivetkit/src/driver-test-suite/test-inline-client-driver.ts @@ -12,6 +12,7 @@ import { WS_PROTOCOL_ACTOR, WS_PROTOCOL_CONN_PARAMS, WS_PROTOCOL_ENCODING, + WS_PROTOCOL_STANDARD, WS_PROTOCOL_TARGET, WS_TEST_PROTOCOL_PATH, } from "@/common/actor-router-consts"; @@ -180,12 +181,11 @@ export function createTestInlineClientDriver( const wsProtocol = wsUrl.protocol === "https:" ? "wss:" : "ws:"; const finalWsUrl = `${wsProtocol}//${wsUrl.host}${wsUrl.pathname}`; - logger().debug({ msg: "connecting to websocket", url: finalWsUrl }); - // Build protocols for the connection const protocols: string[] = []; + protocols.push(WS_PROTOCOL_STANDARD); protocols.push(`${WS_PROTOCOL_TARGET}actor`); - protocols.push(`${WS_PROTOCOL_ACTOR}${actorId}`); + protocols.push(`${WS_PROTOCOL_ACTOR}${encodeURIComponent(actorId)}`); protocols.push(`${WS_PROTOCOL_ENCODING}${encoding}`); protocols.push( `${WS_TEST_PROTOCOL_PATH}${encodeURIComponent(normalizedPath)}`, @@ -196,6 +196,12 @@ export function createTestInlineClientDriver( ); } + logger().debug({ + msg: "connecting to websocket", + url: finalWsUrl, + protocols, + }); + // Create and return the WebSocket // Node & browser WebSocket types are incompatible const ws = new WebSocket(finalWsUrl, protocols) as any; diff --git a/rivetkit-typescript/packages/rivetkit/src/manager/gateway.ts b/rivetkit-typescript/packages/rivetkit/src/manager/gateway.ts index 1927bc0025..32002af148 100644 --- a/rivetkit-typescript/packages/rivetkit/src/manager/gateway.ts +++ b/rivetkit-typescript/packages/rivetkit/src/manager/gateway.ts @@ -222,7 +222,7 @@ async function handleWebSocketGateway( if (protocol.startsWith(WS_PROTOCOL_TARGET)) { target = protocol.substring(WS_PROTOCOL_TARGET.length); } else if (protocol.startsWith(WS_PROTOCOL_ACTOR)) { - actorId = protocol.substring(WS_PROTOCOL_ACTOR.length); + actorId = decodeURIComponent(protocol.substring(WS_PROTOCOL_ACTOR.length)); } else if (protocol.startsWith(WS_PROTOCOL_ENCODING)) { encodingRaw = protocol.substring(WS_PROTOCOL_ENCODING.length); } else if (protocol.startsWith(WS_PROTOCOL_CONN_PARAMS)) { diff --git a/rivetkit-typescript/packages/rivetkit/src/manager/router.ts b/rivetkit-typescript/packages/rivetkit/src/manager/router.ts index 5a537e647a..99ad3b8cb2 100644 --- a/rivetkit-typescript/packages/rivetkit/src/manager/router.ts +++ b/rivetkit-typescript/packages/rivetkit/src/manager/router.ts @@ -565,7 +565,7 @@ function addManagerRoutes( for (const protocol of protocols) { if (protocol.startsWith(WS_PROTOCOL_ACTOR)) { - actorId = protocol.substring(WS_PROTOCOL_ACTOR.length); + actorId = decodeURIComponent(protocol.substring(WS_PROTOCOL_ACTOR.length)); } else if (protocol.startsWith(WS_PROTOCOL_ENCODING)) { encoding = protocol.substring( WS_PROTOCOL_ENCODING.length,