Skip to content

Commit 6064adf

Browse files
authored
[rust] kj::http ffi wrappers (#5102)
1 parent c8ff253 commit 6064adf

File tree

17 files changed

+851
-3
lines changed

17 files changed

+851
-3
lines changed

build/kj_test.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ def kj_test(
1515
testonly = True,
1616
srcs = [src],
1717
deps = [
18+
"//deps/rust:runtime",
1819
"@capnp-cpp//src/kj:kj-test",
1920
] + deps,
2021
linkstatic = select({

build/wd_cc_benchmark.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ def wd_cc_benchmark(
2626
visibility = visibility,
2727
deps = deps + [
2828
"@workerd-google-benchmark//:benchmark_main",
29+
"//deps/rust:runtime",
2930
"//src/workerd/tests:bench-tools",
3031
],
3132
# use the same malloc we use for server

build/wd_cc_binary.bzl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ def wd_cc_binary(
44
name,
55
linkopts = [],
66
visibility = None,
7+
deps = [],
78
**kwargs):
89
"""Wrapper for cc_binary that sets common attributes
910
"""
@@ -29,6 +30,9 @@ def wd_cc_binary(
2930
"//conditions:default": [],
3031
}),
3132
visibility = visibility,
33+
deps = deps + [
34+
"//deps/rust:runtime",
35+
],
3236
**kwargs
3337
)
3438

compile_flags.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
-Iexternal/ncrypto/include
1717
-isystembazel-bin/external/sqlite3
1818
-Isrc
19+
-isystem/usr/lib/llvm-20/include/c++/v1
20+
-isystem/usr/lib/llvm-20/lib/clang/20/include
1921
-isystem/usr/lib/llvm-19/include/c++/v1
2022
-isystem/usr/lib/llvm-19/lib/clang/19/include
2123
-isystem/usr/include/x86_64-linux-gnu
@@ -53,6 +55,9 @@
5355
-isystembazel-bin/src/rust/cxx-integration/_virtual_includes/cxx-integration@cxx
5456
-isystembazel-bin/src/rust/cxx-integration-test/_virtual_includes/cxx-integration-test@cxx
5557
-isystembazel-bin/src/rust/dns/_virtual_includes/dns@cxx
58+
-isystembazel-bin/src/rust/kj/_virtual_includes/http.rs@cxx
59+
-isystembazel-bin/src/rust/kj/_virtual_includes/io.rs@cxx
60+
-isystembazel-bin/src/rust/kj/tests/_virtual_includes/lib.rs@cxx
5661
-isystembazel-bin/src/rust/python-parser/_virtual_includes/python-parser@cxx
5762
-isystembazel-bin/src/rust/net/_virtual_includes/net@cxx
5863
-isystembazel-bin/src/rust/transpiler/_virtual_includes/transpiler@cxx

src/rust/cxx-integration-test/BUILD.bazel

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ kj_test(
2222
src = "cxx-rust-integration-test.c++",
2323
deps = [
2424
":cxx-integration-test",
25-
"//deps/rust:runtime",
2625
"//src/rust/cxx-integration",
2726
"@capnp-cpp//src/kj:kj-async",
2827
"@workerd-cxx//kj-rs",

src/rust/kj/BUILD.bazel

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
load("//:build/wd_cc_library.bzl", "wd_cc_library")
2+
load("//:build/wd_rust_crate.bzl", "wd_rust_crate")
3+
4+
wd_rust_crate(
5+
name = "kj",
6+
cxx_bridge_deps = [
7+
"@capnp-cpp//src/kj/compat:kj-http",
8+
],
9+
cxx_bridge_srcs = [
10+
"http.rs",
11+
"io.rs",
12+
],
13+
proc_macro_deps = [
14+
"@crates_vendor//:async-trait",
15+
],
16+
visibility = ["//visibility:public"],
17+
deps = [
18+
":ffi",
19+
"@crates_vendor//:futures",
20+
"@crates_vendor//:static_assertions",
21+
],
22+
)
23+
24+
wd_cc_library(
25+
name = "ffi",
26+
srcs = [
27+
"ffi.c++",
28+
],
29+
hdrs = [
30+
"ffi.h",
31+
],
32+
linkstatic = select({
33+
"@platforms//os:windows": True,
34+
"//conditions:default": False,
35+
}),
36+
visibility = ["//visibility:public"],
37+
deps = [
38+
":http.rs@cxx",
39+
"//src/rust/cxx-integration",
40+
"@capnp-cpp//src/kj",
41+
"@capnp-cpp//src/kj/compat:kj-http",
42+
],
43+
)

src/rust/kj/ffi.c++

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright (c) 2017-2022 Cloudflare, Inc.
2+
// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3+
// https://opensource.org/licenses/Apache-2.0
4+
5+
#include "ffi.h"
6+
7+
#include <workerd/rust/kj/http.rs.h>
8+
9+
#include <kj/compat/http.h>
10+
11+
static_assert(sizeof(kj::rust::HttpConnectSettings) == 16, "HttpConnectSettings size mismatch");
12+
static_assert(alignof(kj::rust::HttpConnectSettings) == alignof(uint64_t), "HttpConnectSettings alignment mismatch");
13+
14+
namespace kj::rust {
15+
kj::Promise<void> connect(HttpService& service,
16+
::rust::Slice<const kj::byte> host,
17+
const HttpHeaders& headers,
18+
AsyncIoStream& connection,
19+
ConnectResponse& response,
20+
HttpConnectSettings settings) {
21+
auto strHost = kj::str(kj_rs::from<kj_rs::Rust>(host).asChars());
22+
return service.connect(strHost, headers, connection, response,
23+
{
24+
.useTls = settings.use_tls,
25+
.tlsStarter = settings.tls_starter,
26+
});
27+
}
28+
29+
} // namespace kj::rust

src/rust/kj/ffi.h

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Copyright (c) 2017-2022 Cloudflare, Inc.
2+
// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3+
// https://opensource.org/licenses/Apache-2.0
4+
5+
#pragma once
6+
7+
#include <kj-rs/convert.h>
8+
#include <rust/cxx.h>
9+
10+
#include <kj/compat/http.h>
11+
12+
namespace kj::rust {
13+
14+
struct HttpConnectSettings;
15+
16+
// --- Async IO
17+
18+
using AsyncInputStream = kj::AsyncInputStream;
19+
using AsyncOutputStream = kj::AsyncOutputStream;
20+
using AsyncIoStream = kj::AsyncIoStream;
21+
22+
// --- kj::HttpHeaders ffi
23+
24+
using BuiltinIndicesEnum = kj::HttpHeaders::BuiltinIndicesEnum;
25+
using HttpHeaders = kj::HttpHeaders;
26+
27+
inline kj::Own<kj::HttpHeaders> clone_shallow(const HttpHeaders& headers) {
28+
// there is no c++ stack frame to hold the new instance,
29+
// so sadly we have to heap allocate it.
30+
return kj::heap(headers.cloneShallow());
31+
}
32+
33+
inline kj::HttpHeaderId toHeaderId(BuiltinIndicesEnum id) {
34+
switch (id) {
35+
case kj::HttpHeaders::BuiltinIndicesEnum::CONNECTION:
36+
return kj::HttpHeaderId::CONNECTION;
37+
case kj::HttpHeaders::BuiltinIndicesEnum::KEEP_ALIVE:
38+
return kj::HttpHeaderId::KEEP_ALIVE;
39+
case kj::HttpHeaders::BuiltinIndicesEnum::TE:
40+
return kj::HttpHeaderId::TE;
41+
case kj::HttpHeaders::BuiltinIndicesEnum::TRAILER:
42+
return kj::HttpHeaderId::TRAILER;
43+
case kj::HttpHeaders::BuiltinIndicesEnum::UPGRADE:
44+
return kj::HttpHeaderId::UPGRADE;
45+
case kj::HttpHeaders::BuiltinIndicesEnum::CONTENT_LENGTH:
46+
return kj::HttpHeaderId::CONTENT_LENGTH;
47+
case kj::HttpHeaders::BuiltinIndicesEnum::TRANSFER_ENCODING:
48+
return kj::HttpHeaderId::TRANSFER_ENCODING;
49+
case kj::HttpHeaders::BuiltinIndicesEnum::SEC_WEBSOCKET_KEY:
50+
return kj::HttpHeaderId::SEC_WEBSOCKET_KEY;
51+
case kj::HttpHeaders::BuiltinIndicesEnum::SEC_WEBSOCKET_VERSION:
52+
return kj::HttpHeaderId::SEC_WEBSOCKET_VERSION;
53+
case kj::HttpHeaders::BuiltinIndicesEnum::SEC_WEBSOCKET_ACCEPT:
54+
return kj::HttpHeaderId::SEC_WEBSOCKET_ACCEPT;
55+
case kj::HttpHeaders::BuiltinIndicesEnum::SEC_WEBSOCKET_EXTENSIONS:
56+
return kj::HttpHeaderId::SEC_WEBSOCKET_EXTENSIONS;
57+
case kj::HttpHeaders::BuiltinIndicesEnum::HOST:
58+
return kj::HttpHeaderId::HOST;
59+
case kj::HttpHeaders::BuiltinIndicesEnum::DATE:
60+
return kj::HttpHeaderId::DATE;
61+
case kj::HttpHeaders::BuiltinIndicesEnum::LOCATION:
62+
return kj::HttpHeaderId::LOCATION;
63+
case kj::HttpHeaders::BuiltinIndicesEnum::CONTENT_TYPE:
64+
return kj::HttpHeaderId::CONTENT_TYPE;
65+
case kj::HttpHeaders::BuiltinIndicesEnum::RANGE:
66+
return kj::HttpHeaderId::RANGE;
67+
case kj::HttpHeaders::BuiltinIndicesEnum::CONTENT_RANGE:
68+
return kj::HttpHeaderId::CONTENT_RANGE;
69+
break;
70+
}
71+
}
72+
73+
inline void set_header(HttpHeaders& headers, BuiltinIndicesEnum id, ::rust::Str value) {
74+
headers.set(toHeaderId(id), kj::str(value));
75+
}
76+
77+
inline kj::Maybe<::rust::Slice<const kj::byte>> get_header(
78+
const HttpHeaders& headers, BuiltinIndicesEnum id) {
79+
auto header = headers.get(toHeaderId(id));
80+
return header.map([](auto header) { return header.asBytes().template as<kj_rs::Rust>(); });
81+
}
82+
83+
// --- kj::HttpService ffi
84+
using AsyncInputStream = kj::AsyncInputStream;
85+
using AsyncIoStream = kj::AsyncIoStream;
86+
using ConnectResponse = kj::HttpService::ConnectResponse;
87+
using HttpMethod = kj::HttpMethod;
88+
using HttpService = kj::HttpService;
89+
using HttpServiceResponse = kj::HttpService::Response;
90+
using TlsStarterCallback = kj::TlsStarterCallback;
91+
92+
inline kj::Promise<void> request(HttpService& service,
93+
HttpMethod method,
94+
::rust::Slice<const kj::byte> url,
95+
const HttpHeaders& headers,
96+
AsyncInputStream& request_body,
97+
HttpServiceResponse& response) {
98+
auto strUrl = kj::str(kj_rs::from<kj_rs::Rust>(url).asChars());
99+
co_await service.request(method, strUrl, headers, request_body, response);
100+
}
101+
102+
kj::Promise<void> connect(HttpService& service,
103+
::rust::Slice<const kj::byte> host,
104+
const HttpHeaders& headers,
105+
AsyncIoStream& connection,
106+
ConnectResponse& response,
107+
HttpConnectSettings settings);
108+
109+
} // namespace kj::rust

0 commit comments

Comments
 (0)