Skip to content

Commit a3b88a5

Browse files
author
Jake Champion
committed
feat: Add Dynamic Backends support
Dynamic Backends allows JavaScript projects to dynamically create new backend server definitions without having to deploy a new version of their Fastly Service. These backends function exactly as existing backends, and will _eventually_ be configurable in all the same ways as existing backends can via the Fastly Service defintion. The way I've implemented this feature is to have it only enabled when the property `fastly.allowDynamicBackends` is set to `true`. The reason for that is to try to make it a bit more obvious that Dynamic Backends is not the default approach for a fetch. (It's not the default approach as it can be a potential avenue for third-party JavaScript code within a project to send requests, potentially including sensitive/secret data, off to destinations that the JavaScript project was not intending, which could be a security issue.) The implementation of the property `fastly.allowDynamicBackends` doesn’t _yet_ gain any security advantages because a third-party dependency has access to the `fastly` global variable and can set `fastly.allowDynamicBackends = true` — there would be a security advantage when we have support for ES Modules and can then limit this property to only be writable from the top-level script and readable from other ES Modules. There are two ways to make use of Dynamic Backends within JavaScript projects. The first way is by omitting the `backend` property definition on the Request instance. The JavaScript Runtime will then create a Dynamic Backend definition using default configuration options. This approach is useful for JavaScript applications as it means that a standard `fetch` call will now be possible, which means libraries that use `fetch` should just work 🥳. E.G: ```js // Enable dynamic backends -- warning, this is potentially dangerous as third-party dependencies could make requests to their own backends, potentially including your sensitive/secret data fastly.allowDynamicBackends = true; // For any request, return the fastly homepage -- without defining a backend! addEventListener("fetch", event => { event.respondWith(fetch('https://www.fastly.com/')); }); ``` The second way is by creating a new Dynamic Backend using the JavaScript `Backend` class. This approach is useful for JavaScript applications that want to have control over the configuration of the new backend defintion, such as only allowing TLS 1.3 and disallowing older versions of TLS. The `Backend` class has a `toString` implementation which will return it's name, this means it can be attached to a Request instance. E.G. ```js // Enable dynamic backends -- warning, this is potentially dangerous as third-party dependencies could make requests to their own backends, potentially including your sensitive/secret data fastly.allowDynamicBackends = true; // For any request, return the fastly homepage -- without defining a backend! addEventListener("fetch", event => { // We are defining all the possible fields here but any number of fields can be defined - the ones which are not defined will use their default value instead. const backend = new Backend({ name: 'fastly', target: 'fastly.com', hostOverride: "www.fastly.com", connectTimeout: 1000, firstByteTimeout: 15000, betweenBytesTimeout: 10000, useSsl: true, sslMinVersion: 1.3, sslMaxVersion: 1.3, certificateHostname: "www.fastly.com", checkCertificate: true, caCertificate: `-----BEGIN CERTIFICATE----- MIIGgjCCBWqgAwIBAgIQASW9vtgUNIzM07bVg9HdEzANBgkqhkiG9w0BAQsFADBY MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEuMCwGA1UE AxMlR2xvYmFsU2lnbiBBdGxhcyBSMyBEViBUTFMgQ0EgMjAyMiBRMTAeFw0yMjAz MzExNDI4NTBaFw0yMzA1MDIxNDI4NDlaMBkxFzAVBgNVBAMMDnd3dy5mYXN0bHku Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmtLSpTiRzJaFiAEi Eua36KwkZBm647y7cEkYEu6GgStXAWtzDF4ttzI8q9iRpqlljFDjQF2EeWLXN2X2 MEQPxKOOkM+OuJny0pXDCkKiSGS6MwVzNqCNW5tnxkJMMUAq5ciyQFwF72Z+ymlo NGCl3CIDAJbHcudm4CiVR5ip7KYFH7uaBRLPXtMLX2lmQ1q2TbU/GXrbDhz5OXCD H9SKAUSHLqwLplj8mojxWayda9zy3bqbTVXsqRVW0Xar62T33Uis0fm+xW4hJbxf bya5I0aQbAjtxvEjfUa1kSalUqPwfHOXMvvXwoqUIKk1ndZScWl9TGLH84izTCPw bOVsTQIDAQABo4IDhTCCA4EwOwYDVR0RBDQwMoIOd3d3LmZhc3RseS5jb22CFGRl dmVsb3Blci5mYXN0bHkuY29tggpmYXN0bHkuY29tMA4GA1UdDwEB/wQEAwIFoDAd BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwHQYDVR0OBBYEFCYC4rPzDtR8 EI3XULw/wr8lfnv2MFcGA1UdIARQME4wCAYGZ4EMAQIBMEIGCisGAQQBoDIKAQMw NDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5jb20vcmVwb3Np dG9yeS8wDAYDVR0TAQH/BAIwADCBngYIKwYBBQUHAQEEgZEwgY4wQAYIKwYBBQUH MAGGNGh0dHA6Ly9vY3NwLmdsb2JhbHNpZ24uY29tL2NhL2dzYXRsYXNyM2R2dGxz Y2EyMDIycTEwSgYIKwYBBQUHMAKGPmh0dHA6Ly9zZWN1cmUuZ2xvYmFsc2lnbi5j b20vY2FjZXJ0L2dzYXRsYXNyM2R2dGxzY2EyMDIycTEuY3J0MB8GA1UdIwQYMBaA FJwqZ9C0gzFbgMspllV1CTc4uDylMEgGA1UdHwRBMD8wPaA7oDmGN2h0dHA6Ly9j cmwuZ2xvYmFsc2lnbi5jb20vY2EvZ3NhdGxhc3IzZHZ0bHNjYTIwMjJxMS5jcmww ggF/BgorBgEEAdZ5AgQCBIIBbwSCAWsBaQB3AK33vvp8/xDIi509nB4+GGq0Zyld z7EMJMqFhjTr3IKKAAABf+BhC9UAAAQDAEgwRgIhAI/TiJpulEywYHMuudQ6fYcK dl18wDnJtAD+3JqFkrXuAiEA+i6ryPZTeENZJ6wEgRnndsggk8blsfch13e4s76u WngAdQB6MoxU2LcttiDqOOBSHumEFnAyE4VNO9IrwTpXo1LrUgAAAX/gYQwqAAAE AwBGMEQCIEldTkse3joAWr1llSoi9EOle0K0hz086GrCjL5YDhXkAiARW5dUit2q Tq/mD+aN+XHfupYiYC7htPvHMWM6iUHPFgB3ALNzdwfhhFD4Y4bWBancEQlKeS2x ZwwLh9zwAw55NqWaAAABf+BhDFQAAAQDAEgwRgIhAIQ1nuPDm08OuXDmLBkreA7L LdGLmdhnJOdzOW0n7PDGAiEA4cEZYQ+uFrAoIHezQXBe05/ovXLacu5SVoInRJIK gBYwDQYJKoZIhvcNAQELBQADggEBAPH+sQGtGBE6BlC0Zp02rJo/1QCPC+/L1T1+ uErHb0175NKnxXmT0HYoXr3gduMoMFXQr0VkhtQzCq7OaAX89+UdQ/OkfdU6CK0z H4318J11ZShIHqGUCL+w27JsAgzJw/9UQBfT3FLCto735lwfo/l6HyD7qNqNYwhK UlkETWIEFB5CUAvG5mVmNbnUI8fnF3CvEB7IJcX9DxIkfsS08+4lMi3jHFMthJqY N5RGelXh07FAawRDugRPO0gh5bHo+hxZnWYTW9s6+A/D9E3pP2OJcyvhnvtWUrjg rgzylmjRmAH2KP86mK9jRwFvTdn666JZFKzpubei6XjWVdG/eS8= -----END CERTIFICATE-----`, // Colon-delimited list of permitted SSL Ciphers ciphers: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:!RC4", sniHostname: "www.fastly.com", }); event.respondWith(fetch('https://www.fastly.com/', { backend // Here we are configuring this request to use the dynamically define backend from above. })); }); ```
1 parent 23ba342 commit a3b88a5

File tree

11 files changed

+2512
-3
lines changed

11 files changed

+2512
-3
lines changed

c-dependencies/js-compute-runtime/builtins/backend.cpp

Lines changed: 705 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#ifndef JS_COMPUTE_RUNTIME_BACKEND_H
2+
#define JS_COMPUTE_RUNTIME_BACKEND_H
3+
4+
#include "builtin.h"
5+
6+
namespace builtins {
7+
8+
class Backend : public BuiltinImpl<Backend> {
9+
private:
10+
public:
11+
static constexpr const char *class_name = "Backend";
12+
static const int ctor_length = 1;
13+
enum Slots {
14+
Name,
15+
Target,
16+
HostOverride,
17+
ConnectTimeout,
18+
FirstByteTimeout,
19+
BetweenBytesTimeout,
20+
UseSsl,
21+
TlsMinVersion,
22+
TlsMaxVersion,
23+
CertificateHostname,
24+
CaCertificate,
25+
Ciphers,
26+
SniHostname,
27+
Count
28+
};
29+
30+
static const JSFunctionSpec methods[];
31+
static const JSPropertySpec properties[];
32+
33+
static JSString *name(JSContext *cx, JSObject *self);
34+
static JS::Result<mozilla::Ok> register_dynamic_backend(JSContext *cx, JS::HandleObject request);
35+
static JSObject *create(JSContext *cx, JS::HandleObject request);
36+
static bool set_target(JSContext *cx, JSObject *backend, JS::HandleValue target_val);
37+
static bool set_host_override(JSContext *cx, JSObject *backend, JS::HandleValue hostOverride_val);
38+
static bool set_name(JSContext *cx, JSObject *backend, JS::HandleValue name_val);
39+
static bool toString(JSContext *cx, unsigned argc, JS::Value *vp);
40+
static bool constructor(JSContext *cx, unsigned argc, JS::Value *vp);
41+
42+
static bool init_class(JSContext *cx, JS::HandleObject global);
43+
};
44+
45+
} // namespace builtins
46+
47+
#endif

c-dependencies/js-compute-runtime/builtins/fastly.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "builtins/fastly.h"
1313
#include "builtins/logger.h"
1414
#include "geo_ip.h"
15+
#include "host_call.h"
1516

1617
namespace builtins {
1718

@@ -21,6 +22,7 @@ JS::PersistentRooted<JSObject *> Fastly::env;
2122

2223
JS::PersistentRooted<JSObject *> Fastly::baseURL;
2324
JS::PersistentRooted<JSString *> Fastly::defaultBackend;
25+
bool Fastly::allowDynamicBackends = false;
2426

2527
bool Fastly::dump(JSContext *cx, unsigned argc, JS::Value *vp) {
2628
JS::CallArgs args = CallArgsFromVp(argc, vp);
@@ -179,10 +181,26 @@ bool Fastly::defaultBackend_set(JSContext *cx, unsigned argc, JS::Value *vp) {
179181
return true;
180182
}
181183

184+
bool Fastly::allowDynamicBackends_get(JSContext *cx, unsigned argc, JS::Value *vp) {
185+
JS::CallArgs args = CallArgsFromVp(argc, vp);
186+
args.rval().setBoolean(allowDynamicBackends);
187+
return true;
188+
}
189+
190+
bool Fastly::allowDynamicBackends_set(JSContext *cx, unsigned argc, JS::Value *vp) {
191+
JS::CallArgs args = CallArgsFromVp(argc, vp);
192+
allowDynamicBackends = JS::ToBoolean(args.get(0));
193+
args.rval().setUndefined();
194+
return true;
195+
}
196+
182197
const JSPropertySpec Fastly::properties[] = {
183198
JS_PSG("env", env_get, JSPROP_ENUMERATE),
184199
JS_PSGS("baseURL", baseURL_get, baseURL_set, JSPROP_ENUMERATE),
185-
JS_PSGS("defaultBackend", defaultBackend_get, defaultBackend_set, JSPROP_ENUMERATE), JS_PS_END};
200+
JS_PSGS("defaultBackend", defaultBackend_get, defaultBackend_set, JSPROP_ENUMERATE),
201+
JS_PSGS("allowDynamicBackends", allowDynamicBackends_get, allowDynamicBackends_set,
202+
JSPROP_ENUMERATE),
203+
JS_PS_END};
186204

187205
bool Fastly::create(JSContext *cx, JS::HandleObject global) {
188206
JS::RootedObject fastly(cx, JS_NewPlainObject(cx));

c-dependencies/js-compute-runtime/builtins/fastly.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class Fastly : public BuiltinNoConstructor<Fastly> {
1818

1919
static JS::PersistentRooted<JSObject *> baseURL;
2020
static JS::PersistentRooted<JSString *> defaultBackend;
21+
static bool allowDynamicBackends;
2122

2223
static const JSFunctionSpec methods[];
2324
static const JSPropertySpec properties[];
@@ -32,6 +33,8 @@ class Fastly : public BuiltinNoConstructor<Fastly> {
3233
static bool baseURL_set(JSContext *cx, unsigned argc, JS::Value *vp);
3334
static bool defaultBackend_get(JSContext *cx, unsigned argc, JS::Value *vp);
3435
static bool defaultBackend_set(JSContext *cx, unsigned argc, JS::Value *vp);
36+
static bool allowDynamicBackends_get(JSContext *cx, unsigned argc, JS::Value *vp);
37+
static bool allowDynamicBackends_set(JSContext *cx, unsigned argc, JS::Value *vp);
3538
static bool create(JSContext *cx, JS::HandleObject global);
3639
};
3740

c-dependencies/js-compute-runtime/error-numbers.msg

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,26 @@ MSG_DEF(JSMSG_OBJECT_STORE_PUT_CONTENT_STREAM, 0, JSEXN_TYPEERR,
5858
MSG_DEF(JSMSG_OBJECT_STORE_PUT_OVER_30_MB, 0, JSEXN_TYPEERR, "ObjectStore value can not be more than 30 Megabytes in size")
5959
MSG_DEF(JSMSG_READABLE_STREAM_LOCKED_OR_DISTRUBED, 0, JSEXN_TYPEERR, "Can't use a ReadableStream that's locked or has ever been read from or canceled")
6060
MSG_DEF(JSMSG_INVALID_CHARACTER_ERROR, 0, JSEXN_ERR, "String contains an invalid character")
61+
MSG_DEF(JSMSG_BACKEND_PARAMETER_NOT_OBJECT, 0, JSEXN_TYPEERR, "Backend constructor: configuration parameter must be an Object")
62+
MSG_DEF(JSMSG_BACKEND_NAME_NOT_SET, 0, JSEXN_TYPEERR, "Backend constructor: name can not be null or undefined")
63+
MSG_DEF(JSMSG_BACKEND_NAME_TOO_LONG, 0, JSEXN_TYPEERR, "Backend constructor: name can not be more than 254 characters")
64+
MSG_DEF(JSMSG_BACKEND_NAME_EMPTY, 0, JSEXN_TYPEERR, "Backend constructor: name can not be an empty string")
65+
MSG_DEF(JSMSG_BACKEND_TARGET_NOT_SET, 0, JSEXN_TYPEERR, "Backend constructor: target can not be null or undefined")
66+
MSG_DEF(JSMSG_BACKEND_TARGET_EMPTY, 0, JSEXN_TYPEERR, "Backend constructor: target can not be an empty string")
67+
MSG_DEF(JSMSG_BACKEND_TARGET_INVALID, 0, JSEXN_TYPEERR, "Backend constructor: target is not a valid host or IP address")
68+
MSG_DEF(JSMSG_BACKEND_CIPHERS_EMPTY, 0, JSEXN_TYPEERR, "Backend constructor: ciphers can not be an empty string")
69+
MSG_DEF(JSMSG_BACKEND_HOST_OVERRIDE_EMPTY, 0, JSEXN_TYPEERR, "Backend constructor: hostOverride can not be an empty string")
70+
MSG_DEF(JSMSG_BACKEND_CERTIFICATE_HOSTNAME_EMPTY, 0, JSEXN_TYPEERR, "Backend constructor: certificateHostname can not be an empty string")
71+
MSG_DEF(JSMSG_BACKEND_SNI_HOSTNAME_EMPTY, 0, JSEXN_TYPEERR, "Backend constructor: sniHostname can not be an empty string")
72+
MSG_DEF(JSMSG_BACKEND_CA_CERTIFICATE_EMPTY, 0, JSEXN_TYPEERR, "Backend constructor: caCertificate can not be an empty string")
73+
MSG_DEF(JSMSG_BACKEND_CONNECT_TIMEOUT_NEGATIVE, 0, JSEXN_RANGEERR, "Backend constructor: connectTimeout can not be a negative number")
74+
MSG_DEF(JSMSG_BACKEND_CONNECT_TIMEOUT_TOO_BIG, 0, JSEXN_RANGEERR, "Backend constructor: connectTimeout must be less than 2^32")
75+
MSG_DEF(JSMSG_BACKEND_FIRST_BYTE_TIMEOUT_NEGATIVE, 0, JSEXN_RANGEERR, "Backend constructor: firstByteTimeout can not be a negative number")
76+
MSG_DEF(JSMSG_BACKEND_FIRST_BYTE_TIMEOUT_TOO_BIG, 0, JSEXN_RANGEERR, "Backend constructor: firstByteTimeout must be less than 2^32")
77+
MSG_DEF(JSMSG_BACKEND_BETWEEN_BYTES_TIMEOUT_NEGATIVE, 0, JSEXN_RANGEERR, "Backend constructor: betweenBytesTimeout can not be a negative number")
78+
MSG_DEF(JSMSG_BACKEND_BETWEEN_BYTES_TIMEOUT_TOO_BIG, 0, JSEXN_RANGEERR, "Backend constructor: betweenBytesTimeout must be less than 2^32")
79+
MSG_DEF(JSMSG_BACKEND_TLS_MIN_INVALID, 0, JSEXN_RANGEERR, "Backend constructor: tlsMinVersion must be either 1, 1.1, 1.2, or 1.3")
80+
MSG_DEF(JSMSG_BACKEND_TLS_MAX_INVALID, 0, JSEXN_RANGEERR, "Backend constructor: tlsMaxVersion must be either 1, 1.1, 1.2, or 1.3")
81+
MSG_DEF(JSMSG_BACKEND_TLS_MIN_GREATER_THAN_TLS_MAX, 0, JSEXN_RANGEERR, "Backend constructor: tlsMinVersion must be less than or equal to tlsMaxVersion")
82+
MSG_DEF(JSMSG_BACKEND_PORT_INVALID, 0, JSEXN_RANGEERR, "Backend constructor: port must be more than 0 and less than 2^16 (65,536)")
6183
//clang-format on

c-dependencies/js-compute-runtime/js-compute-builtins.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "sequence.hpp"
3737

3838
#include "builtin.h"
39+
#include "builtins/backend.h"
3940
#include "builtins/cache-override.h"
4041
#include "builtins/compression-stream.h"
4142
#include "builtins/config-store.h"
@@ -4038,10 +4039,10 @@ bool fetch(JSContext *cx, unsigned argc, Value *vp) {
40384039
}
40394040

40404041
RootedString backend(cx, Request::backend(request));
4041-
if (!backend) {
4042+
if (!backend && builtins::Fastly::allowDynamicBackends == false) {
40424043
backend = builtins::Fastly::defaultBackend;
40434044
}
4044-
if (!backend) {
4045+
if (!backend && builtins::Fastly::allowDynamicBackends == false) {
40454046
size_t bytes_read;
40464047
RequestHandle handle = Request::request_handle(request);
40474048
UniqueChars buf(
@@ -4056,6 +4057,14 @@ bool fetch(JSContext *cx, unsigned argc, Value *vp) {
40564057
return ReturnPromiseRejectedWithPendingError(cx, args);
40574058
}
40584059

4060+
if (!backend && builtins::Fastly::allowDynamicBackends) {
4061+
JS::RootedObject dynamicBackend(cx, builtins::Backend::create(cx, request));
4062+
if (!dynamicBackend) {
4063+
return false;
4064+
}
4065+
backend.set(builtins::Backend::name(cx, dynamicBackend));
4066+
}
4067+
40594068
size_t backend_len;
40604069
UniqueChars backend_chars = encode(cx, backend, &backend_len);
40614070
if (!backend_chars)
@@ -4424,6 +4433,8 @@ bool define_fastly_sys(JSContext *cx, HandleObject global) {
44244433
if (!GlobalProperties::init(cx, global))
44254434
return false;
44264435

4436+
if (!builtins::Backend::init_class(cx, global))
4437+
return false;
44274438
if (!builtins::Fastly::create(cx, global))
44284439
return false;
44294440
if (!builtins::Console::create(cx, global))

c-dependencies/js-compute-runtime/js-compute-builtins.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ bool body_unusable(JSContext *cx, JS::HandleObject body);
104104
BodyHandle body_handle(JSObject *obj);
105105
template <BodyReadResult result_type>
106106
bool bodyAll(JSContext *cx, JS::CallArgs args, JS::HandleObject self);
107+
JS::Value url(JSObject *obj);
107108
} // namespace RequestOrResponse
108109

109110
int write_to_body_all(BodyHandle handle, const char *buf, size_t len);

c-dependencies/js-compute-runtime/xqd.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,45 @@ typedef struct {
5252
uint32_t handle;
5353
} ObjectStoreHandle;
5454

55+
// The values need to match https://docs.rs/fastly-sys/0.8.7/src/fastly_sys/lib.rs.html#86-108
56+
#define BACKEND_CONFIG_RESERVED (1u << 0)
57+
#define BACKEND_CONFIG_HOST_OVERRIDE (1u << 1)
58+
#define BACKEND_CONFIG_CONNECT_TIMEOUT (1u << 2)
59+
#define BACKEND_CONFIG_FIRST_BYTE_TIMEOUT (1u << 3)
60+
#define BACKEND_CONFIG_BETWEEN_BYTES_TIMEOUT (1u << 4)
61+
#define BACKEND_CONFIG_USE_SSL (1u << 5)
62+
#define BACKEND_CONFIG_SSL_MIN_VERSION (1u << 6)
63+
#define BACKEND_CONFIG_SSL_MAX_VERSION (1u << 7)
64+
#define BACKEND_CONFIG_CERT_HOSTNAME (1u << 8)
65+
#define BACKEND_CONFIG_CA_CERT (1u << 9)
66+
#define BACKEND_CONFIG_CIPHERS (1u << 10)
67+
#define BACKEND_CONFIG_SNI_HOSTNAME (1u << 11)
68+
69+
typedef enum TLS {
70+
VERSION_1 = 0,
71+
VERSION_1_1 = 1,
72+
VERSION_1_2 = 2,
73+
VERSION_1_3 = 3,
74+
} TLS;
75+
76+
typedef struct DynamicBackendConfig {
77+
char *host_override;
78+
uint32_t host_override_len;
79+
uint32_t connect_timeout_ms;
80+
uint32_t first_byte_timeout_ms;
81+
uint32_t between_bytes_timeout_ms;
82+
uint32_t ssl_min_version;
83+
uint32_t ssl_max_version;
84+
char *cert_hostname;
85+
uint32_t cert_hostname_len;
86+
char *ca_cert;
87+
uint32_t ca_cert_len;
88+
char *ciphers;
89+
uint32_t ciphers_len;
90+
char *sni_hostname;
91+
uint32_t sni_hostname_len;
92+
} DynamicBackendConfig;
93+
5594
#define INVALID_HANDLE (UINT32_MAX - 1)
5695

5796
typedef enum BodyWriteEnd {
@@ -104,6 +143,12 @@ int xqd_log_write(LogEndpointHandle endpoint_handle, const char *msg, size_t msg
104143
size_t *nwritten);
105144

106145
// Module fastly_http_req
146+
WASM_IMPORT("fastly_http_req", "register_dynamic_backend")
147+
int xqd_req_register_dynamic_backend(const char *name_prefix, size_t name_prefix_len,
148+
const char *target, size_t target_len,
149+
uint32_t backend_config_mask,
150+
DynamicBackendConfig *backend_configuration);
151+
107152
WASM_IMPORT("fastly_http_req", "body_downstream_get")
108153
int xqd_req_body_downstream_get(RequestHandle *req_handle_out, BodyHandle *body_handle_out);
109154

0 commit comments

Comments
 (0)