Skip to content
File

Blob: src/rust/kj/ffi.h

cpp155 lines
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 
12namespace kj::rust {
13 
14struct HttpConnectSettings;
15 
16// --- Async IO
17 
18using AsyncInputStream = kj::AsyncInputStream;
19using AsyncOutputStream = kj::AsyncOutputStream;
20using AsyncIoStream = kj::AsyncIoStream;
21 
22inline kj::Promise<void> async_output_stream_write(
23 AsyncOutputStream& stream, ::rust::Slice<const kj::byte> buffer) {
24 return stream.write(kj::from<kj_rs::Rust>(buffer));
25}
26 
27inline kj::Promise<void> async_output_stream_when_write_disconnected(AsyncOutputStream& stream) {
28 return stream.whenWriteDisconnected();
29}
30 
31// --- kj::HttpHeaders ffi
32 
33using BuiltinIndicesEnum = kj::HttpHeaders::BuiltinIndicesEnum;
34using HttpHeaderTable = kj::HttpHeaderTable;
35using HttpHeaders = kj::HttpHeaders;
36using HttpHeaderId = kj::HttpHeaderId;
37 
38inline kj::Own<kj::HttpHeaders> new_http_headers(const HttpHeaderTable& table) {
39 // There is no C++ stack frame to hold the new instance, so we heap allocate it for Rust.
40 return kj::heap<kj::HttpHeaders>(table);
41}
42 
43inline kj::Own<kj::HttpHeaders> clone_shallow(const HttpHeaders& headers) {
44 // there is no c++ stack frame to hold the new instance,
45 // so sadly we have to heap allocate it.
46 return kj::heap(headers.cloneShallow());
47}
48 
49inline kj::HttpHeaderId toHeaderId(BuiltinIndicesEnum id) {
50 switch (id) {
51 case kj::HttpHeaders::BuiltinIndicesEnum::CONNECTION:
52 return kj::HttpHeaderId::CONNECTION;
53 case kj::HttpHeaders::BuiltinIndicesEnum::KEEP_ALIVE:
54 return kj::HttpHeaderId::KEEP_ALIVE;
55 case kj::HttpHeaders::BuiltinIndicesEnum::TE:
56 return kj::HttpHeaderId::TE;
57 case kj::HttpHeaders::BuiltinIndicesEnum::TRAILER:
58 return kj::HttpHeaderId::TRAILER;
59 case kj::HttpHeaders::BuiltinIndicesEnum::UPGRADE:
60 return kj::HttpHeaderId::UPGRADE;
61 case kj::HttpHeaders::BuiltinIndicesEnum::CONTENT_LENGTH:
62 return kj::HttpHeaderId::CONTENT_LENGTH;
63 case kj::HttpHeaders::BuiltinIndicesEnum::TRANSFER_ENCODING:
64 return kj::HttpHeaderId::TRANSFER_ENCODING;
65 case kj::HttpHeaders::BuiltinIndicesEnum::SEC_WEBSOCKET_KEY:
66 return kj::HttpHeaderId::SEC_WEBSOCKET_KEY;
67 case kj::HttpHeaders::BuiltinIndicesEnum::SEC_WEBSOCKET_VERSION:
68 return kj::HttpHeaderId::SEC_WEBSOCKET_VERSION;
69 case kj::HttpHeaders::BuiltinIndicesEnum::SEC_WEBSOCKET_ACCEPT:
70 return kj::HttpHeaderId::SEC_WEBSOCKET_ACCEPT;
71 case kj::HttpHeaders::BuiltinIndicesEnum::SEC_WEBSOCKET_EXTENSIONS:
72 return kj::HttpHeaderId::SEC_WEBSOCKET_EXTENSIONS;
73 case kj::HttpHeaders::BuiltinIndicesEnum::HOST:
74 return kj::HttpHeaderId::HOST;
75 case kj::HttpHeaders::BuiltinIndicesEnum::DATE:
76 return kj::HttpHeaderId::DATE;
77 case kj::HttpHeaders::BuiltinIndicesEnum::LOCATION:
78 return kj::HttpHeaderId::LOCATION;
79 case kj::HttpHeaders::BuiltinIndicesEnum::CONTENT_TYPE:
80 return kj::HttpHeaderId::CONTENT_TYPE;
81 case kj::HttpHeaders::BuiltinIndicesEnum::RANGE:
82 return kj::HttpHeaderId::RANGE;
83 case kj::HttpHeaders::BuiltinIndicesEnum::CONTENT_RANGE:
84 return kj::HttpHeaderId::CONTENT_RANGE;
85 break;
86 }
87}
88 
89inline void set_header(HttpHeaders& headers, BuiltinIndicesEnum id, ::rust::Str value) {
90 headers.set(toHeaderId(id), kj::str(value));
91}
92 
93inline kj::Maybe<::rust::Slice<const kj::byte>> get_header(
94 const HttpHeaders& headers, BuiltinIndicesEnum id) {
95 auto header = headers.get(toHeaderId(id));
96 return header.map([](auto header) { return header.asBytes().template as<kj_rs::Rust>(); });
97}
98 
99inline kj::Maybe<::rust::Slice<const kj::byte>> get_header_by_id(
100 const HttpHeaders& headers, const HttpHeaderId& id) {
101 auto header = headers.get(id);
102 return header.map([](auto header) { return header.asBytes().template as<kj_rs::Rust>(); });
103}
104 
105// --- kj::HttpService ffi
106using AsyncInputStream = kj::AsyncInputStream;
107using AsyncIoStream = kj::AsyncIoStream;
108using ConnectResponse = kj::HttpService::ConnectResponse;
109using HttpMethod = kj::HttpMethod;
110using HttpService = kj::HttpService;
111using HttpServiceResponse = kj::HttpService::Response;
112using TlsStarterCallback = kj::TlsStarterCallback;
113 
114inline kj::Own<AsyncOutputStream> response_send(HttpServiceResponse& response,
115 uint32_t statusCode,
116 ::rust::Str statusText,
117 const HttpHeaders& headers,
118 kj::Maybe<uint64_t> expectedBodySize) {
119 return response.send(statusCode, kj::str(statusText), headers, expectedBodySize);
120}
121 
122inline void connect_response_accept(ConnectResponse& response,
123 uint32_t statusCode,
124 ::rust::Str statusText,
125 const HttpHeaders& headers) {
126 response.accept(statusCode, kj::str(statusText), headers);
127}
128 
129inline kj::Own<AsyncOutputStream> connect_response_reject(ConnectResponse& response,
130 uint32_t statusCode,
131 ::rust::Str statusText,
132 const HttpHeaders& headers,
133 kj::Maybe<uint64_t> expectedBodySize) {
134 return response.reject(statusCode, kj::str(statusText), headers, expectedBodySize);
135}
136 
137inline kj::Promise<void> request(HttpService& service,
138 HttpMethod method,
139 ::rust::Slice<const kj::byte> url,
140 const HttpHeaders& headers,
141 AsyncInputStream& request_body,
142 HttpServiceResponse& response) {
143 auto strUrl = kj::str(kj::from<kj_rs::Rust>(url).asChars());
144 co_await service.request(method, strUrl, headers, request_body, response);
145}
146 
147kj::Promise<void> connect(HttpService& service,
148 ::rust::Slice<const kj::byte> host,
149 const HttpHeaders& headers,
150 AsyncIoStream& connection,
151 ConnectResponse& response,
152 HttpConnectSettings settings);
153 
154} // namespace kj::rust