@@ -11,6 +11,8 @@ const Request = zigly.http.Request;
1111const Logger = zigly .Logger ;
1212const Backend = zigly .Backend ;
1313const DynamicBackend = zigly .DynamicBackend ;
14+ const cache = zigly .cache ;
15+ const erl = zigly .erl ;
1416
1517fn start () ! void {
1618 var gpa = std .heap .GeneralPurposeAllocator (.{ .safety = true }){};
@@ -60,14 +62,26 @@ fn start() !void {
6062 _ = try request .isPost ();
6163 }
6264
63- {
65+ google_test : {
6466 var arena = ArenaAllocator .init (allocator );
6567 defer arena .deinit ();
66- var query = try Request .new ("GET" , "https://www.google.com" );
67- try query .setCachingPolicy (.{ .no_cache = true });
68- var response = try query .send ("google" );
69- const body = try response .body .readAll (arena .allocator (), 0 );
70- std .debug .print ("{s}\n " , .{body });
68+ var query = Request .new ("GET" , "https://www.google.com" ) catch | err | {
69+ std .debug .print ("Google request creation error: {}\n " , .{err });
70+ break :google_test ;
71+ };
72+ query .setCachingPolicy (.{ .no_cache = true }) catch | err | {
73+ std .debug .print ("Cache policy error: {}\n " , .{err });
74+ break :google_test ;
75+ };
76+ var response = query .send ("google" ) catch | err | {
77+ std .debug .print ("Google send error: {}\n " , .{err });
78+ break :google_test ;
79+ };
80+ const body = response .body .readAll (arena .allocator (), 0 ) catch | err | {
81+ std .debug .print ("Google body read error: {}\n " , .{err });
82+ break :google_test ;
83+ };
84+ std .debug .print ("Google response length: {}\n " , .{body .len });
7185 }
7286
7387 // Test the Apache combined log format function
@@ -84,12 +98,12 @@ fn start() !void {
8498 }
8599
86100 // Test dynamic backend registration (must be before finishing downstream response)
87- {
101+ dyn_backend_test : {
88102 std .debug .print ("Testing dynamic backends...\n " , .{});
89103
90104 // Register a dynamic backend to httpbin.org
91105 const dynamic_backend = DynamicBackend {
92- .name = "httpbin " ,
106+ .name = "httpbin_dyn " ,
93107 .target = "httpbin.org:443" ,
94108 .use_ssl = true ,
95109 .host_override = "httpbin.org" ,
@@ -100,38 +114,191 @@ fn start() !void {
100114 .between_bytes_timeout_ms = 10000 ,
101115 };
102116
103- const dyn_backend = try dynamic_backend .register ();
117+ const dyn_backend = dynamic_backend .register () catch | err | {
118+ std .debug .print ("Dynamic backend registration error: {}\n " , .{err });
119+ break :dyn_backend_test ;
120+ };
104121 std .debug .print ("Dynamic backend registered: {s}\n " , .{dyn_backend .name });
105122
106123 // Check if backend exists
107- const exists = try Backend .exists ("httpbin" ) ;
124+ const exists = Backend .exists ("httpbin_dyn" ) catch false ;
108125 std .debug .print ("Backend exists: {}\n " , .{exists });
109126
110127 // Check if backend is dynamic
111- const is_dynamic = try dyn_backend .isDynamic ();
128+ const is_dynamic = dyn_backend .isDynamic () catch false ;
112129 std .debug .print ("Backend is dynamic: {}\n " , .{is_dynamic });
113130
114131 // Check if backend uses SSL
115- const is_ssl = try dyn_backend .isSsl ();
132+ const is_ssl = dyn_backend .isSsl () catch false ;
116133 std .debug .print ("Backend uses SSL: {}\n " , .{is_ssl });
117134
118135 // Get backend port
119- const port = try dyn_backend .getPort ();
136+ const port = dyn_backend .getPort () catch 0 ;
120137 std .debug .print ("Backend port: {}\n " , .{port });
121138
122139 // Make a request using the dynamic backend
123140 var arena = ArenaAllocator .init (allocator );
124141 defer arena .deinit ();
125142
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 ();
143+ var query = Request .new ("GET" , "https://httpbin.org/get" ) catch | err | {
144+ std .debug .print ("Request creation error: {}\n " , .{err });
145+ break :dyn_backend_test ;
146+ };
147+ var dyn_response = query .send ("httpbin_dyn" ) catch | err | {
148+ std .debug .print ("Request send error: {}\n " , .{err });
149+ break :dyn_backend_test ;
150+ };
151+ const status = dyn_response .getStatus () catch 0 ;
129152 std .debug .print ("Response status from dynamic backend: {}\n " , .{status });
130153
131- const body = try dyn_response .body .readAll (arena .allocator (), 1024 );
154+ const body = dyn_response .body .readAll (arena .allocator (), 1024 ) catch | err | {
155+ std .debug .print ("Body read error: {}\n " , .{err });
156+ break :dyn_backend_test ;
157+ };
132158 std .debug .print ("Response body (first 200 chars): {s}\n " , .{body [0.. @min (body .len , 200 )]});
133159 }
134160
161+ // Test cache transactions
162+ cache_test : {
163+ std .debug .print ("Testing cache transactions...\n " , .{});
164+
165+ const cache_key = "test-cache-key-12345" ;
166+ const cache_body = "Hello from cache!" ;
167+
168+ // Insert into cache (simple test without metadata)
169+ var insert_body = cache .insert (cache_key , .{
170+ .max_age_ns = cache .secondsToNs (60 ),
171+ }) catch | err | {
172+ std .debug .print ("Cache insert error: {}\n " , .{err });
173+ break :cache_test ;
174+ };
175+ _ = try insert_body .write (cache_body );
176+ try insert_body .close ();
177+
178+ std .debug .print ("Cache insert completed\n " , .{});
179+
180+ // Lookup from cache
181+ var entry = cache .lookup (cache_key , .{}) catch | err | {
182+ std .debug .print ("Cache lookup error: {}\n " , .{err });
183+ break :cache_test ;
184+ };
185+ const state = try entry .getState ();
186+ std .debug .print ("Cache state - found: {}, usable: {}, stale: {}\n " , .{
187+ state .isFound (),
188+ state .isUsable (),
189+ state .isStale (),
190+ });
191+
192+ if (state .isFound ()) {
193+ var arena = ArenaAllocator .init (allocator );
194+ defer arena .deinit ();
195+
196+ var body = try entry .getBody (null );
197+ const content = try body .readAll (arena .allocator (), 1024 );
198+ std .debug .print ("Cache body: {s}\n " , .{content });
199+ }
200+
201+ try entry .close ();
202+ std .debug .print ("Cache test completed\n " , .{});
203+ }
204+
205+ // Test transactional cache lookup
206+ tx_test : {
207+ std .debug .print ("Testing transactional cache...\n " , .{});
208+
209+ const tx_key = "test-transaction-key-67890" ;
210+
211+ // Transactional lookup (request-collapsing)
212+ var tx = cache .transactionLookup (tx_key , .{}) catch | err | {
213+ std .debug .print ("Transaction lookup error: {}\n " , .{err });
214+ break :tx_test ;
215+ };
216+ const tx_state = try tx .getState ();
217+
218+ if (tx_state .mustInsertOrUpdate ()) {
219+ std .debug .print ("Transaction requires insert\n " , .{});
220+ var result = try tx .insert (.{
221+ .max_age_ns = cache .secondsToNs (30 ),
222+ });
223+ _ = try result .body .write ("Transaction cached content" );
224+ try result .body .close ();
225+ std .debug .print ("Transaction insert completed\n " , .{});
226+ } else {
227+ std .debug .print ("Transaction found existing entry\n " , .{});
228+ }
229+
230+ try tx .close ();
231+ std .debug .print ("Transaction test completed\n " , .{});
232+ }
233+
234+ // Test rate limiting (ERL)
235+ erl_test : {
236+ std .debug .print ("Testing rate limiting...\n " , .{});
237+
238+ // Test rate counter
239+ const rc = erl .RateCounter .open ("test_rc" );
240+ rc .increment ("client-ip-192.168.1.1" , 1 ) catch | err | {
241+ std .debug .print ("Rate counter increment error: {}\n " , .{err });
242+ break :erl_test ;
243+ };
244+ std .debug .print ("Rate counter incremented\n " , .{});
245+
246+ const rate = rc .lookupRate ("client-ip-192.168.1.1" , 10 ) catch | err | {
247+ std .debug .print ("Rate lookup error: {}\n " , .{err });
248+ break :erl_test ;
249+ };
250+ std .debug .print ("Rate for client: {}\n " , .{rate });
251+
252+ const count = rc .lookupCount ("client-ip-192.168.1.1" , 60 ) catch | err | {
253+ std .debug .print ("Count lookup error: {}\n " , .{err });
254+ break :erl_test ;
255+ };
256+ std .debug .print ("Count for client: {}\n " , .{count });
257+
258+ // Test penalty box
259+ const pb = erl .PenaltyBox .open ("test_pb" );
260+ const in_pb_before = pb .has ("bad-actor" ) catch | err | {
261+ std .debug .print ("Penalty box has error: {}\n " , .{err });
262+ break :erl_test ;
263+ };
264+ std .debug .print ("Bad actor in penalty box before: {}\n " , .{in_pb_before });
265+
266+ pb .add ("bad-actor" , 300 ) catch | err | {
267+ std .debug .print ("Penalty box add error: {}\n " , .{err });
268+ break :erl_test ;
269+ };
270+ std .debug .print ("Added bad actor to penalty box\n " , .{});
271+
272+ const in_pb_after = pb .has ("bad-actor" ) catch | err | {
273+ std .debug .print ("Penalty box has (after) error: {}\n " , .{err });
274+ break :erl_test ;
275+ };
276+ std .debug .print ("Bad actor in penalty box after: {}\n " , .{in_pb_after });
277+
278+ // Test combined rate limiter
279+ const limiter = erl .RateLimiter .init (.{
280+ .rate_counter = "test_rc" ,
281+ .penalty_box = "test_pb" ,
282+ .window_seconds = 10 ,
283+ .limit = 100 ,
284+ .ttl_seconds = 300 ,
285+ });
286+
287+ const result = limiter .checkRate ("test-entry" , 1 ) catch | err | {
288+ std .debug .print ("Rate check error: {}\n " , .{err });
289+ break :erl_test ;
290+ };
291+ std .debug .print ("Rate check result: {s}\n " , .{if (result == .allowed ) "allowed" else "blocked" });
292+
293+ const is_allowed = limiter .isAllowed ("test-entry" , 1 ) catch | err | {
294+ std .debug .print ("Is allowed error: {}\n " , .{err });
295+ break :erl_test ;
296+ };
297+ std .debug .print ("Is allowed: {}\n " , .{is_allowed });
298+
299+ std .debug .print ("Rate limiting test completed\n " , .{});
300+ }
301+
135302 // Final response to client
136303 {
137304 var response = downstream .response ;
0 commit comments