Logo

index : blog

---

  • summary
  • about
  • tree
  • log
  • branches
<< path: root/public/blog.git/html/tests/backend_curl.jai blob: ac9cdb421b3cefde289fb1f07ee8ad6a1302ee55 [raw] [clear marker]

        
0
1
2
3curl_dispatch :: (args: Args, is_set: Is_Set(Args)) {
4 url := URL;
5
6 if is_set.q {
7 if #complete args.q == {
8 case .ascii; url = URL_ASCII;
9 case .umlaut; url = URL_UMLAUT;
10 case .heavy; url = URL_HEAVY;
11 case .space; url = URL_SPACE;
12 case .verylong; url = URL_VERY_LONG;
13 }
14 }
15 else if is_set.cq {
16 url = args.cq;
17 }
18 else {
19 url = URL_ASCII;
20 }
21
22 url_limit :: 128;
23 url_continue_indicator := ifx url.count > url_limit then "..." else "";
24 log("Query: %%", slice(url, 0, url_limit), url_continue_indicator);
25
26 if is_set.os {
27 if #complete args.os == {
28 case .get; test_single(url, "GET", "Generic request", xx args.l, args.t);
29 case .head; test_single(url, "HEAD", "Generic request", xx args.l, args.t);
30 }
31 }
32 else if is_set.stream {
33 data, size_label := make_data(args.stream);
34 test_with_data(url, data, size_label, xx args.l, args.t);
35 }
36}
37
38
39#scope_file
40
41
42#import "Curl"()(LINUX_USE_SYSTEM_LIBRARY=false);
43
44
45URL_PAYLOAD_1_MB :: #run make_data_static(1);
46
47
48URL :: #run tprint("http://%:%", HOST, PORT);
49URL_ASCII :: #run tprint("%/search?q=test+string", URL);
50URL_UMLAUT :: #run tprint("%/search?q=test+123d\%C3\%B6ner", URL);
51URL_SPACE :: #run tprint("%/search?q=test+string ", URL);
52URL_HEAVY :: #run tprint("%/search?q=test+d\%C3\%B6\%C3\%B6\%C2\%B5\%C2\%B5\%C2\%B5\%3B\%3B\%3A\%3A\%2F\%2F\%2F\%2B\%2B\%2B\%2B\%2Bkadhf1012din\%C3\%9Fd\%C3\%9F13___\%5C\%5C", URL);
53URL_VERY_LONG :: #run tprint("%/search?q=%", URL, URL_PAYLOAD_1_MB);
54
55
56size_t :: u64;
57
58
59Transfer :: struct {
60 timeout: s32;
61 builder: String_Builder;
62}
63
64
65make_data :: (size_mb: float) -> *string, string {
66 mb_factor := 1024.0 * 1024.0;
67 size := ifx size_mb == 0.0 then 32 else cast(int, mb_factor * size_mb);
68 label := ifx size_mb == 0.0 then "32 Bytes (default)" else tprint("% MB", size_mb);
69
70 s := New(string);
71 s.count = size;
72 s.data = alloc(size);
73 memset(s.data, "A", size);
74 return s, label;
75}
76
77make_data_static :: (size_mb: float) -> string {
78 size := cast(int, 1024.0 * 1024.0 * size_mb);
79
80 s: string;
81 s.count = size;
82 s.data = alloc(size);
83 memset(s.data, "B", size);
84 return s;
85}
86
87request_make :: (
88 url: string,
89 data: string = "",
90 method: string = "",
91 headers: []string = .[],
92 include_headers: bool = false,
93 bytes_limit: s32 = 0,
94 drip_behavior: Drip_Behavior
95)
96 -> (response_body: string, response_code: int, curl_code: CURLcode)
97{
98 curl := curl_easy_init();
99 assert(curl != null);
100
101 my_url := ifx url then url else URL;
102
103 curl_easy_setopt(curl, .URL, temp_c_string(my_url));
104
105 if method then curl_easy_setopt(curl, .CUSTOMREQUEST, temp_c_string(method));
106
107 if data || (method && method != "GET")
108 then curl_easy_setopt(curl, .POSTFIELDS, temp_c_string(data));
109
110 if include_headers then curl_easy_setopt(curl, .HEADER, 1);
111 if method == "HEAD" then curl_easy_setopt(curl, .NOBODY, 1);
112
113 if headers.count {
114 slist: *curl_slist;
115 for headers slist = curl_slist_append(slist, temp_c_string(it));
116 curl_easy_setopt(curl, .HTTPHEADER, slist);
117 }
118
119 builder: String_Builder;
120 defer free_buffers(*builder);
121
122 if bytes_limit > 0 {
123 if #complete drip_behavior == {
124 case .send; curl_easy_setopt(curl, .MAX_SEND_SPEED_LARGE, bytes_limit);
125 case .recv; curl_easy_setopt(curl, .MAX_RECV_SPEED_LARGE, bytes_limit);
126 case .both;
127 curl_easy_setopt(curl, .MAX_SEND_SPEED_LARGE, bytes_limit);
128 curl_easy_setopt(curl, .MAX_RECV_SPEED_LARGE, bytes_limit);
129 }
130 }
131
132 curl_easy_setopt(curl, .ACCEPT_ENCODING, "identity");
133 curl_easy_setopt(curl, .WRITEFUNCTION, write_callback);
134 curl_easy_setopt(curl, .WRITEDATA, *builder);
135
136 curl_code: CURLcode = curl_easy_perform(curl);
137
138 response_code: int;
139 if curl_code == .OK then curl_easy_getinfo(curl, .RESPONSE_CODE, *response_code);
140
141 response_body: string = builder_to_string(*builder);
142 return response_body, response_code, curl_code;
143}
144
145write_callback :: (
146 ptr: *u8,
147 size: size_t,
148 nmemb: size_t,
149 userdata: *void
150)
151 -> size_t #c_call
152{
153 builder := cast(*String_Builder, userdata);
154
155 push_context {
156 log("Write byte: %", ptr);
157 append(builder, ptr, xx nmemb);
158 }
159
160 return nmemb;
161}
162
163
164/** Tests */
165
166test_with_data :: inline (
167 url: string,
168 data: *string,
169 name: string,
170 bytes_limit: s32 = 0,
171 behavior: Drip_Behavior
172) {
173 do_request_and_log(url, data, "POST", name, bytes_limit, behavior);
174}
175
176test_single :: inline (
177 url: string,
178 method: string,
179 name: string,
180 bytes_limit: s32 = 0,
181 behavior: Drip_Behavior
182) {
183 do_request_and_log(url, null, method, name, bytes_limit, behavior);
184}
185
186do_request_and_log :: (
187 url: string,
188 data: *string,
189 method: string,
190 name: string,
191 bytes_limit: s32,
192 behavior: Drip_Behavior
193) {
194 has_limit := ifx bytes_limit > 0 then tprint("(% bytes limit)", bytes_limit) else "";
195 log("Test: %, % (%)", name, has_limit, behavior);
196
197 data_deref := ifx data == null then "" else data.*;
198
199 response_body, http_code, curl_code := request_make(
200 url,
201 method=method,
202 data=data_deref,
203 bytes_limit=bytes_limit,
204 drip_behavior=behavior
205 );
206 log_vars(http_code, curl_code, slice(response_body, 0, 255));
207}
208
209
Copyright 2026  E766CB298A6D1E64 | Git-Thing heavily inspired by cgit