Skip to content

Commit 5e2b2ad

Browse files
committed
fix: carry request.cf through debug port via startEvent RPC param
Add cfBlobJson as a parameter to WorkerdBootstrap::startEvent() in the capnp schema, so request.cf travels as a first-class RPC value through the debug port. Sender (workerd-debug-port-client.c++): - startRequest() passes metadata.cfBlobJson via req.setCfBlobJson() on startEvent Receiver (server.c++): - startEvent() extracts cfBlobJson from RPC params, passes to EventDispatcherImpl - getHttpService() includes cfBlobJson in SubrequestMetadata when creating WorkerInterface - EventDispatcherImpl defers WorkerInterface creation (stores SubrequestChannel)
1 parent c0f9d42 commit 5e2b2ad

File tree

3 files changed

+43
-19
lines changed

3 files changed

+43
-19
lines changed

src/workerd/io/worker-interface.capnp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -792,11 +792,11 @@ interface EventDispatcher @0xf20697475ec1752d {
792792
interface WorkerdBootstrap {
793793
# Bootstrap interface exposed by workerd when serving Cap'n Proto RPC.
794794

795-
startEvent @0 () -> (dispatcher :EventDispatcher);
795+
startEvent @0 (cfBlobJson :Text) -> (dispatcher :EventDispatcher);
796796
# Start a new event. Exactly one event should be delivered to the returned EventDispatcher.
797797
#
798-
# TODO(someday): Pass cfBlobJson? Currently doesn't matter since the cf blob is only present for
799-
# HTTP requests which can be delivered over regular HTTP instead of capnp.
798+
# If the event is an HTTP request, `cfBlobJson` optionally carries the JSON-encoded `request.cf`
799+
# object. The dispatcher will pass it through to the worker via SubrequestMetadata.
800800
}
801801

802802
interface WorkerdDebugPort {

src/workerd/server/server.c++

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4929,14 +4929,17 @@ class Server::WorkerdBootstrapImpl final: public rpc::WorkerdBootstrap::Server {
49294929
httpOverCapnpFactory(httpOverCapnpFactory) {}
49304930

49314931
kj::Promise<void> startEvent(StartEventContext context) override {
4932-
// TODO(someday): Use cfBlobJson from the connection if there is one, or from RPC params
4933-
// if we add that? (Note that if a connection-level cf blob exists, it should take
4934-
// priority; we should only accept a cf blob from the client if we have a cfBlobHeader
4935-
// configured, which hints that this service trusts the client to provide the cf blob.)
4936-
4932+
// Extract the optional cf blob from the RPC params and pass it along with the
4933+
// service channel to EventDispatcherImpl. The cf blob will be included in
4934+
// SubrequestMetadata when creating the WorkerInterface for HTTP events.
4935+
kj::Maybe<kj::String> cfBlobJson;
4936+
auto params = context.getParams();
4937+
if (params.hasCfBlobJson()) {
4938+
cfBlobJson = kj::str(params.getCfBlobJson());
4939+
}
49374940
context.initResults(capnp::MessageSize{4, 1})
4938-
.setDispatcher(
4939-
kj::heap<EventDispatcherImpl>(httpOverCapnpFactory, service->startRequest({})));
4941+
.setDispatcher(kj::heap<EventDispatcherImpl>(
4942+
httpOverCapnpFactory, kj::addRef(*service), kj::mv(cfBlobJson)));
49404943
return kj::READY_NOW;
49414944
}
49424945

@@ -4946,14 +4949,22 @@ class Server::WorkerdBootstrapImpl final: public rpc::WorkerdBootstrap::Server {
49464949

49474950
class EventDispatcherImpl final: public rpc::EventDispatcher::Server {
49484951
public:
4949-
EventDispatcherImpl(
4950-
capnp::HttpOverCapnpFactory& httpOverCapnpFactory, kj::Own<WorkerInterface> worker)
4952+
EventDispatcherImpl(capnp::HttpOverCapnpFactory& httpOverCapnpFactory,
4953+
kj::Own<IoChannelFactory::SubrequestChannel> service,
4954+
kj::Maybe<kj::String> cfBlobJson)
49514955
: httpOverCapnpFactory(httpOverCapnpFactory),
4952-
worker(kj::mv(worker)) {}
4956+
service(kj::mv(service)),
4957+
cfBlobJson(kj::mv(cfBlobJson)) {}
49534958

49544959
kj::Promise<void> getHttpService(GetHttpServiceContext context) override {
4960+
// Create WorkerInterface with cf blob metadata (if provided via startEvent).
4961+
IoChannelFactory::SubrequestMetadata metadata;
4962+
KJ_IF_SOME(cf, cfBlobJson) {
4963+
metadata.cfBlobJson = kj::str(cf);
4964+
}
4965+
auto worker = getService()->startRequest(kj::mv(metadata));
49554966
context.initResults(capnp::MessageSize{4, 1})
4956-
.setHttp(httpOverCapnpFactory.kjToCapnp(getWorker()));
4967+
.setHttp(httpOverCapnpFactory.kjToCapnp(kj::mv(worker)));
49574968
return kj::READY_NOW;
49584969
}
49594970

@@ -5013,15 +5024,22 @@ class Server::WorkerdBootstrapImpl final: public rpc::WorkerdBootstrap::Server {
50135024

50145025
private:
50155026
capnp::HttpOverCapnpFactory& httpOverCapnpFactory;
5016-
kj::Maybe<kj::Own<WorkerInterface>> worker;
5027+
kj::Maybe<kj::Own<IoChannelFactory::SubrequestChannel>> service;
5028+
kj::Maybe<kj::String> cfBlobJson;
50175029

5018-
kj::Own<WorkerInterface> getWorker() {
5030+
kj::Own<IoChannelFactory::SubrequestChannel> getService() {
50195031
auto result =
5020-
kj::mv(KJ_ASSERT_NONNULL(worker, "EventDispatcher can only be used for one request"));
5021-
worker = kj::none;
5032+
kj::mv(KJ_ASSERT_NONNULL(service, "EventDispatcher can only be used for one request"));
5033+
service = kj::none;
50225034
return result;
50235035
}
50245036

5037+
kj::Own<WorkerInterface> getWorker() {
5038+
// For non-HTTP events (RPC, traces, etc.), create WorkerInterface with
5039+
// empty metadata since there's no HTTP request to extract cf from.
5040+
return getService()->startRequest({});
5041+
}
5042+
50255043
[[noreturn]] void throwUnsupported() {
50265044
JSG_FAIL_REQUIRE(Error, "RPC connections don't yet support this event type.");
50275045
}

src/workerd/server/workerd-debug-port-client.c++

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,13 @@ class WorkerdBootstrapSubrequestChannel final: public IoChannelFactory::Subreque
3131
connectionState(kj::mv(connectionState)) {}
3232

3333
kj::Own<WorkerInterface> startRequest(IoChannelFactory::SubrequestMetadata metadata) override {
34-
auto dispatcher = bootstrap.startEventRequest().send().getDispatcher();
34+
// Pass cfBlobJson as an RPC parameter on startEvent so the server can include it
35+
// in SubrequestMetadata when creating the WorkerInterface.
36+
auto req = bootstrap.startEventRequest();
37+
KJ_IF_SOME(cf, metadata.cfBlobJson) {
38+
req.setCfBlobJson(cf);
39+
}
40+
auto dispatcher = req.send().getDispatcher();
3541
// Attach connection ref for deferred proxying - the HTTP response body/WebSocket
3642
// will get this WorkerInterface attached, keeping the connection alive.
3743
return kj::heap<RpcWorkerInterface>(httpOverCapnpFactory, byteStreamFactory, kj::mv(dispatcher))

0 commit comments

Comments
 (0)