@@ -43,6 +43,7 @@ test "HttpParser supports contains and not_contains for headers" {
4343}
4444const std = @import ("std" );
4545const http = std .http ;
46+ const regex = @import ("regex" );
4647const HttpParser = @import ("./parser.zig" );
4748const Client = @import ("./http_client.zig" );
4849
@@ -55,99 +56,14 @@ fn extractHeaderName(key: []const u8) ![]const u8 {
5556}
5657
5758fn matchesRegex (text : []const u8 , pattern : []const u8 ) bool {
58- if (pattern .len == 0 ) return text .len == 0 ;
59+ var arena = std .heap .ArenaAllocator .init (std .heap .page_allocator );
60+ defer arena .deinit ();
61+ const allocator = arena .allocator ();
5962
60- // Handle anchors
61- const starts_with_anchor = pattern [0 ] == '^' ;
62- const ends_with_anchor = pattern .len > 0 and pattern [pattern .len - 1 ] == '$' ;
63+ const compiled_regex = regex .compile (allocator , pattern ) catch return false ;
64+ defer compiled_regex .deinit ();
6365
64- var actual_pattern = pattern ;
65- if (starts_with_anchor ) actual_pattern = pattern [1.. ];
66- if (ends_with_anchor and actual_pattern .len > 0 ) actual_pattern = actual_pattern [0.. actual_pattern .len - 1 ];
67-
68- if (starts_with_anchor and ends_with_anchor ) {
69- return matchesRegexAt (text , actual_pattern , 0 ) == text .len ;
70- } else if (starts_with_anchor ) {
71- return matchesRegexAt (text , actual_pattern , 0 ) != null ;
72- } else if (ends_with_anchor ) {
73- var i : usize = 0 ;
74- while (i <= text .len ) : (i += 1 ) {
75- if (matchesRegexAt (text [i .. ], actual_pattern , 0 )) | end_pos | {
76- if (i + end_pos == text .len ) return true ;
77- }
78- }
79- return false ;
80- } else {
81- var i : usize = 0 ;
82- while (i <= text .len ) : (i += 1 ) {
83- if (matchesRegexAt (text [i .. ], actual_pattern , 0 ) != null ) return true ;
84- }
85- return false ;
86- }
87- }
88-
89- fn matchesRegexAt (text : []const u8 , pattern : []const u8 , text_pos : usize ) ? usize {
90- var p_pos : usize = 0 ;
91- var t_pos = text_pos ;
92-
93- while (p_pos < pattern .len and t_pos < text .len ) {
94- if (p_pos + 1 < pattern .len and pattern [p_pos + 1 ] == '*' ) {
95- // Handle .* or character*
96- const match_char = pattern [p_pos ];
97- p_pos += 2 ; // Skip char and *
98-
99- // Try matching zero occurrences first
100- if (matchesRegexAt (text , pattern [p_pos .. ], t_pos )) | end_pos | {
101- return t_pos + end_pos ;
102- }
103-
104- // Try matching one or more occurrences
105- while (t_pos < text .len ) {
106- if (match_char == '.' or text [t_pos ] == match_char ) {
107- t_pos += 1 ;
108- if (matchesRegexAt (text , pattern [p_pos .. ], t_pos )) | end_pos | {
109- return t_pos + end_pos ;
110- }
111- } else {
112- break ;
113- }
114- }
115- return null ;
116- } else if (pattern [p_pos ] == '.' ) {
117- // Match any single character
118- t_pos += 1 ;
119- p_pos += 1 ;
120- } else if (pattern [p_pos ] == '[' ) {
121- // Character class
122- const close_bracket = std .mem .indexOfScalarPos (u8 , pattern , p_pos + 1 , ']' ) orelse return null ;
123- const char_class = pattern [p_pos + 1.. close_bracket ];
124- var matched = false ;
125- for (char_class ) | c | {
126- if (text [t_pos ] == c ) {
127- matched = true ;
128- break ;
129- }
130- }
131- if (! matched ) return null ;
132- t_pos += 1 ;
133- p_pos = close_bracket + 1 ;
134- } else {
135- // Literal character match
136- if (text [t_pos ] != pattern [p_pos ]) return null ;
137- t_pos += 1 ;
138- p_pos += 1 ;
139- }
140- }
141-
142- // Handle remaining .* patterns at end
143- while (p_pos + 1 < pattern .len and pattern [p_pos + 1 ] == '*' ) {
144- p_pos += 2 ;
145- }
146-
147- if (p_pos == pattern .len ) {
148- return t_pos - text_pos ;
149- }
150- return null ;
66+ return compiled_regex .match (text );
15167}
15268
15369pub fn check (request : * HttpParser.HttpRequest , response : Client.HttpResponse ) ! void {
0 commit comments