Skip to content

Commit

Permalink
Avoid infinite recursion bug in server.c++ coroutine (#987)
Browse files Browse the repository at this point in the history
  • Loading branch information
jasnell authored Aug 7, 2023
1 parent e0d189b commit c6f439c
Showing 1 changed file with 45 additions and 45 deletions.
90 changes: 45 additions & 45 deletions src/workerd/server/server.c++
Original file line number Diff line number Diff line change
Expand Up @@ -2385,62 +2385,62 @@ public:
rewriter(kj::mv(rewriter)) {}

kj::Promise<void> run() {
kj::AuthenticatedStream stream = co_await listener->acceptAuthenticated();
for (;;) {
kj::AuthenticatedStream stream = co_await listener->acceptAuthenticated();

kj::Maybe<kj::String> cfBlobJson;
if (!rewriter->hasCfBlobHeader()) {
// Construct a cf blob describing the client identity.

kj::PeerIdentity* peerId;

KJ_IF_MAYBE(tlsId,
kj::dynamicDowncastIfAvailable<kj::TlsPeerIdentity>(*stream.peerIdentity)) {
peerId = &tlsId->getNetworkIdentity();
kj::Maybe<kj::String> cfBlobJson;
if (!rewriter->hasCfBlobHeader()) {
// Construct a cf blob describing the client identity.

// TODO(someday): Add client certificate info to the cf blob? At present, KJ only
// supplies the common name, but that doesn't even seem to be one of the fields that
// Cloudflare-hosted Workers receive. We should probably try to match those.
} else {
peerId = stream.peerIdentity;
}
kj::PeerIdentity* peerId;

KJ_IF_MAYBE(remote,
kj::dynamicDowncastIfAvailable<kj::NetworkPeerIdentity>(*peerId)) {
cfBlobJson = kj::str("{\"clientIp\": \"", escapeJsonString(remote->toString()), "\"}");
} else KJ_IF_MAYBE(local,
kj::dynamicDowncastIfAvailable<kj::LocalPeerIdentity>(*peerId)) {
auto creds = local->getCredentials();
KJ_IF_MAYBE(tlsId,
kj::dynamicDowncastIfAvailable<kj::TlsPeerIdentity>(*stream.peerIdentity)) {
peerId = &tlsId->getNetworkIdentity();

kj::Vector<kj::String> parts;
KJ_IF_MAYBE(p, creds.pid) {
parts.add(kj::str("\"clientPid\":", *p));
}
KJ_IF_MAYBE(u, creds.uid) {
parts.add(kj::str("\"clientUid\":", *u));
// TODO(someday): Add client certificate info to the cf blob? At present, KJ only
// supplies the common name, but that doesn't even seem to be one of the fields that
// Cloudflare-hosted Workers receive. We should probably try to match those.
} else {
peerId = stream.peerIdentity;
}

cfBlobJson = kj::str("{", kj::strArray(parts, ","), "}");
}
}
KJ_IF_MAYBE(remote,
kj::dynamicDowncastIfAvailable<kj::NetworkPeerIdentity>(*peerId)) {
cfBlobJson = kj::str("{\"clientIp\": \"", escapeJsonString(remote->toString()), "\"}");
} else KJ_IF_MAYBE(local,
kj::dynamicDowncastIfAvailable<kj::LocalPeerIdentity>(*peerId)) {
auto creds = local->getCredentials();

auto conn = kj::heap<Connection>(*this, kj::mv(cfBlobJson));
kj::Vector<kj::String> parts;
KJ_IF_MAYBE(p, creds.pid) {
parts.add(kj::str("\"clientPid\":", *p));
}
KJ_IF_MAYBE(u, creds.uid) {
parts.add(kj::str("\"clientUid\":", *u));
}

static auto constexpr listen = [](kj::Own<HttpListener> self,
kj::Own<Connection> conn,
kj::Own<kj::AsyncIoStream> stream) -> kj::Promise<void> {
try {
co_await conn->listedHttp.httpServer.listenHttp(kj::mv(stream));
} catch (...) {
KJ_LOG(ERROR, kj::getCaughtExceptionAsKj());
cfBlobJson = kj::str("{", kj::strArray(parts, ","), "}");
}
}
};

// Run the connection handler loop in the global task set, so that run() waits for open
// connections to finish before returning, even if the listener loop is canceled. However,
// do not consider exceptions from a specific connection to be fatal.
owner.tasks.add(listen(kj::addRef(*this), kj::mv(conn), kj::mv(stream.stream)));
auto conn = kj::heap<Connection>(*this, kj::mv(cfBlobJson));

co_await run();
static auto constexpr listen = [](kj::Own<HttpListener> self,
kj::Own<Connection> conn,
kj::Own<kj::AsyncIoStream> stream) -> kj::Promise<void> {
try {
co_await conn->listedHttp.httpServer.listenHttp(kj::mv(stream));
} catch (...) {
KJ_LOG(ERROR, kj::getCaughtExceptionAsKj());
}
};

// Run the connection handler loop in the global task set, so that run() waits for open
// connections to finish before returning, even if the listener loop is canceled. However,
// do not consider exceptions from a specific connection to be fatal.
owner.tasks.add(listen(kj::addRef(*this), kj::mv(conn), kj::mv(stream.stream)));
}
}

private:
Expand Down

0 comments on commit c6f439c

Please sign in to comment.