Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 362a560

Browse files
committed
Add support for dynamic backends
1 parent 467e9c5 commit 362a560

4 files changed

Lines changed: 259 additions & 10 deletions

File tree

src/tests.zig

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ const Dictionary = zigly.Dictionary;
99
const UserAgent = zigly.UserAgent;
1010
const Request = zigly.http.Request;
1111
const Logger = zigly.Logger;
12+
const Backend = zigly.Backend;
13+
const DynamicBackend = zigly.DynamicBackend;
1214

1315
fn start() !void {
1416
var gpa = std.heap.GeneralPurposeAllocator(.{ .safety = true }){};
@@ -81,24 +83,62 @@ fn start() !void {
8183
try request.logApacheCombined(arena.allocator(), "access_log", 404, 0);
8284
}
8385

86+
// Test dynamic backend registration (must be before finishing downstream response)
8487
{
88+
std.debug.print("Testing dynamic backends...\n", .{});
89+
90+
// Register a dynamic backend to httpbin.org
91+
const dynamic_backend = DynamicBackend{
92+
.name = "httpbin",
93+
.target = "httpbin.org:443",
94+
.use_ssl = true,
95+
.host_override = "httpbin.org",
96+
.sni_hostname = "httpbin.org",
97+
.cert_hostname = "httpbin.org",
98+
.connect_timeout_ms = 5000,
99+
.first_byte_timeout_ms = 15000,
100+
.between_bytes_timeout_ms = 10000,
101+
};
102+
103+
const dyn_backend = try dynamic_backend.register();
104+
std.debug.print("Dynamic backend registered: {s}\n", .{dyn_backend.name});
105+
106+
// Check if backend exists
107+
const exists = try Backend.exists("httpbin");
108+
std.debug.print("Backend exists: {}\n", .{exists});
109+
110+
// Check if backend is dynamic
111+
const is_dynamic = try dyn_backend.isDynamic();
112+
std.debug.print("Backend is dynamic: {}\n", .{is_dynamic});
113+
114+
// Check if backend uses SSL
115+
const is_ssl = try dyn_backend.isSsl();
116+
std.debug.print("Backend uses SSL: {}\n", .{is_ssl});
117+
118+
// Get backend port
119+
const port = try dyn_backend.getPort();
120+
std.debug.print("Backend port: {}\n", .{port});
121+
122+
// Make a request using the dynamic backend
85123
var arena = ArenaAllocator.init(allocator);
86124
defer arena.deinit();
87125

88-
var response = downstream.response;
89-
try response.headers.set("X-MyHeader", "XYZ");
126+
var query = try Request.new("GET", "https://httpbin.org/get");
127+
var dyn_response = try query.send("httpbin");
128+
const status = try dyn_response.getStatus();
129+
std.debug.print("Response status from dynamic backend: {}\n", .{status});
90130

91-
try response.setStatus(205);
92-
try response.body.writeAll("OK!\n");
93-
try response.finish();
131+
const body = try dyn_response.body.readAll(arena.allocator(), 1024);
132+
std.debug.print("Response body (first 200 chars): {s}\n", .{body[0..@min(body.len, 200)]});
94133
}
95134

135+
// Final response to client
96136
{
97-
var arena = ArenaAllocator.init(allocator);
98-
defer arena.deinit();
99-
var query = try Request.new("GET", "https://www.google.com");
100-
var upstream_response = try query.send("google");
101-
try downstream.response.pipe(&upstream_response, false, false);
137+
var response = downstream.response;
138+
try response.headers.set("X-MyHeader", "XYZ");
139+
try response.setStatus(200);
140+
try response.body.writeAll("All tests passed!\n");
141+
try response.finish();
102142
}
103143
}
104144

src/zigly.zig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,7 @@ pub const http = lib.http;
99
pub const downstream = lib.downstream;
1010
pub const geo = lib.geo;
1111
pub const kv = lib.kv;
12+
pub const backend = lib.backend;
13+
pub const Backend = lib.Backend;
14+
pub const DynamicBackend = lib.DynamicBackend;
1215
pub const compatibilityCheck = lib.compatibilityCheck;

src/zigly/backend.zig

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
const std = @import("std");
2+
const mem = std.mem;
3+
const Allocator = mem.Allocator;
4+
5+
const wasm = @import("wasm.zig");
6+
const errors = @import("errors.zig");
7+
const fastly = errors.fastly;
8+
const FastlyError = errors.FastlyError;
9+
10+
pub const TlsVersion = wasm.TlsVersion;
11+
pub const BackendHealth = wasm.BackendHealth;
12+
13+
pub const Backend = struct {
14+
name: []const u8,
15+
16+
/// Check if a backend with this name exists.
17+
pub fn exists(name: []const u8) !bool {
18+
var result: wasm.BackendExists = undefined;
19+
try fastly(wasm.FastlyBackend.exists(name.ptr, name.len, &result));
20+
return result != 0;
21+
}
22+
23+
/// Check if this backend is healthy.
24+
pub fn isHealthy(self: Backend) !BackendHealth {
25+
var result: wasm.BackendHealth = undefined;
26+
try fastly(wasm.FastlyBackend.is_healthy(self.name.ptr, self.name.len, &result));
27+
return result;
28+
}
29+
30+
/// Check if this backend was created dynamically.
31+
pub fn isDynamic(self: Backend) !bool {
32+
var result: wasm.IsDynamic = undefined;
33+
try fastly(wasm.FastlyBackend.is_dynamic(self.name.ptr, self.name.len, &result));
34+
return result != 0;
35+
}
36+
37+
/// Check if this backend uses SSL/TLS.
38+
pub fn isSsl(self: Backend) !bool {
39+
var result: wasm.IsSsl = undefined;
40+
try fastly(wasm.FastlyBackend.is_ssl(self.name.ptr, self.name.len, &result));
41+
return result != 0;
42+
}
43+
44+
/// Get the host for this backend.
45+
pub fn getHost(self: Backend, buf: []u8) ![]const u8 {
46+
var nwritten: usize = undefined;
47+
try fastly(wasm.FastlyBackend.get_host(self.name.ptr, self.name.len, buf.ptr, buf.len, &nwritten));
48+
return buf[0..nwritten];
49+
}
50+
51+
/// Get the host override for this backend.
52+
pub fn getOverrideHost(self: Backend, buf: []u8) ![]const u8 {
53+
var nwritten: usize = undefined;
54+
try fastly(wasm.FastlyBackend.get_override_host(self.name.ptr, self.name.len, buf.ptr, buf.len, &nwritten));
55+
return buf[0..nwritten];
56+
}
57+
58+
/// Get the port for this backend.
59+
pub fn getPort(self: Backend) !u16 {
60+
var result: wasm.Port = undefined;
61+
try fastly(wasm.FastlyBackend.get_port(self.name.ptr, self.name.len, &result));
62+
return result;
63+
}
64+
65+
/// Get the connect timeout in milliseconds.
66+
pub fn getConnectTimeoutMs(self: Backend) !u32 {
67+
var result: wasm.TimeoutMs = undefined;
68+
try fastly(wasm.FastlyBackend.get_connect_timeout_ms(self.name.ptr, self.name.len, &result));
69+
return result;
70+
}
71+
72+
/// Get the first byte timeout in milliseconds.
73+
pub fn getFirstByteTimeoutMs(self: Backend) !u32 {
74+
var result: wasm.TimeoutMs = undefined;
75+
try fastly(wasm.FastlyBackend.get_first_byte_timeout_ms(self.name.ptr, self.name.len, &result));
76+
return result;
77+
}
78+
79+
/// Get the between bytes timeout in milliseconds.
80+
pub fn getBetweenBytesTimeoutMs(self: Backend) !u32 {
81+
var result: wasm.TimeoutMs = undefined;
82+
try fastly(wasm.FastlyBackend.get_between_bytes_timeout_ms(self.name.ptr, self.name.len, &result));
83+
return result;
84+
}
85+
86+
/// Get the minimum SSL/TLS version.
87+
pub fn getSslMinVersion(self: Backend) !TlsVersion {
88+
var result: wasm.TlsVersion = undefined;
89+
try fastly(wasm.FastlyBackend.get_ssl_min_version(self.name.ptr, self.name.len, &result));
90+
return result;
91+
}
92+
93+
/// Get the maximum SSL/TLS version.
94+
pub fn getSslMaxVersion(self: Backend) !TlsVersion {
95+
var result: wasm.TlsVersion = undefined;
96+
try fastly(wasm.FastlyBackend.get_ssl_max_version(self.name.ptr, self.name.len, &result));
97+
return result;
98+
}
99+
};
100+
101+
pub const DynamicBackend = struct {
102+
name: []const u8,
103+
target: []const u8,
104+
host_override: ?[]const u8 = null,
105+
connect_timeout_ms: ?u32 = null,
106+
first_byte_timeout_ms: ?u32 = null,
107+
between_bytes_timeout_ms: ?u32 = null,
108+
use_ssl: bool = false,
109+
ssl_min_version: ?TlsVersion = null,
110+
ssl_max_version: ?TlsVersion = null,
111+
cert_hostname: ?[]const u8 = null,
112+
ca_cert: ?[]const u8 = null,
113+
ciphers: ?[]const u8 = null,
114+
sni_hostname: ?[]const u8 = null,
115+
dont_pool: bool = false,
116+
grpc: bool = false,
117+
118+
/// Register the dynamic backend and return a Backend handle.
119+
pub fn register(self: DynamicBackend) !Backend {
120+
var mask: wasm.BackendConfigOptions = 0;
121+
var config: wasm.DynamicBackendConfig = undefined;
122+
123+
@memset(std.mem.asBytes(&config), 0);
124+
125+
if (self.host_override) |host| {
126+
mask |= wasm.BACKEND_CONFIG_OPTIONS_HOST_OVERRIDE;
127+
config.host_override = @constCast(host.ptr);
128+
config.host_override_len = @intCast(host.len);
129+
}
130+
131+
if (self.connect_timeout_ms) |timeout| {
132+
mask |= wasm.BACKEND_CONFIG_OPTIONS_CONNECT_TIMEOUT;
133+
config.connect_timeout_ms = timeout;
134+
}
135+
136+
if (self.first_byte_timeout_ms) |timeout| {
137+
mask |= wasm.BACKEND_CONFIG_OPTIONS_FIRST_BYTE_TIMEOUT;
138+
config.first_byte_timeout_ms = timeout;
139+
}
140+
141+
if (self.between_bytes_timeout_ms) |timeout| {
142+
mask |= wasm.BACKEND_CONFIG_OPTIONS_BETWEEN_BYTES_TIMEOUT;
143+
config.between_bytes_timeout_ms = timeout;
144+
}
145+
146+
if (self.use_ssl) {
147+
mask |= wasm.BACKEND_CONFIG_OPTIONS_USE_SSL;
148+
}
149+
150+
if (self.ssl_min_version) |version| {
151+
mask |= wasm.BACKEND_CONFIG_OPTIONS_SSL_MIN_VERSION;
152+
config.ssl_min_version = version;
153+
}
154+
155+
if (self.ssl_max_version) |version| {
156+
mask |= wasm.BACKEND_CONFIG_OPTIONS_SSL_MAX_VERSION;
157+
config.ssl_max_version = version;
158+
}
159+
160+
if (self.cert_hostname) |hostname| {
161+
mask |= wasm.BACKEND_CONFIG_OPTIONS_CERT_HOSTNAME;
162+
config.cert_hostname = @constCast(hostname.ptr);
163+
config.cert_hostname_len = @intCast(hostname.len);
164+
}
165+
166+
if (self.ca_cert) |cert| {
167+
mask |= wasm.BACKEND_CONFIG_OPTIONS_CA_CERT;
168+
config.ca_cert = @constCast(cert.ptr);
169+
config.ca_cert_len = @intCast(cert.len);
170+
}
171+
172+
if (self.ciphers) |c| {
173+
mask |= wasm.BACKEND_CONFIG_OPTIONS_CIPHERS;
174+
config.ciphers = @constCast(c.ptr);
175+
config.ciphers_len = @intCast(c.len);
176+
}
177+
178+
if (self.sni_hostname) |hostname| {
179+
mask |= wasm.BACKEND_CONFIG_OPTIONS_SNI_HOSTNAME;
180+
config.sni_hostname = @constCast(hostname.ptr);
181+
config.sni_hostname_len = @intCast(hostname.len);
182+
}
183+
184+
if (self.dont_pool) {
185+
mask |= wasm.BACKEND_CONFIG_OPTIONS_DONT_POOL;
186+
}
187+
188+
if (self.grpc) {
189+
mask |= wasm.BACKEND_CONFIG_OPTIONS_GRPC;
190+
}
191+
192+
try fastly(wasm.FastlyHttpReq.register_dynamic_backend(
193+
self.name.ptr,
194+
self.name.len,
195+
self.target.ptr,
196+
self.target.len,
197+
mask,
198+
&config,
199+
));
200+
201+
return Backend{ .name = self.name };
202+
}
203+
};

src/zigly/lib.zig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ pub const http = @import("http.zig");
1313
pub const downstream = http.downstream;
1414
pub const geo = @import("geo.zig");
1515
pub const kv = @import("kv.zig");
16+
pub const backend = @import("backend.zig");
17+
pub const Backend = backend.Backend;
18+
pub const DynamicBackend = backend.DynamicBackend;
1619

1720
/// Check that the module is compatible with the current version of the API.
1821
pub fn compatibilityCheck() !void {

0 commit comments

Comments
 (0)