curl_dispatch :: (args: Args, is_set: Is_Set(Args)) { url := URL; if is_set.q { if #complete args.q == { case .ascii; url = URL_ASCII; case .umlaut; url = URL_UMLAUT; case .heavy; url = URL_HEAVY; case .space; url = URL_SPACE; case .verylong; url = URL_VERY_LONG; } } else if is_set.cq { url = args.cq; } else { url = URL_ASCII; } url_limit :: 128; url_continue_indicator := ifx url.count > url_limit then "..." else ""; log("Query: %%", slice(url, 0, url_limit), url_continue_indicator); if is_set.os { if #complete args.os == { case .get; test_single(url, "GET", "Generic request", xx args.l, args.t); case .head; test_single(url, "HEAD", "Generic request", xx args.l, args.t); } } else if is_set.stream { data, size_label := make_data(args.stream); test_with_data(url, data, size_label, xx args.l, args.t); } } #scope_file #import "Curl"()(LINUX_USE_SYSTEM_LIBRARY=false); URL_PAYLOAD_1_MB :: #run make_data_static(1); URL :: #run tprint("http://%:%", HOST, PORT); URL_ASCII :: #run tprint("%/search?q=test+string", URL); URL_UMLAUT :: #run tprint("%/search?q=test+123d\%C3\%B6ner", URL); URL_SPACE :: #run tprint("%/search?q=test+string ", URL); URL_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); URL_VERY_LONG :: #run tprint("%/search?q=%", URL, URL_PAYLOAD_1_MB); size_t :: u64; Transfer :: struct { timeout: s32; builder: String_Builder; } make_data :: (size_mb: float) -> *string, string { mb_factor := 1024.0 * 1024.0; size := ifx size_mb == 0.0 then 32 else cast(int, mb_factor * size_mb); label := ifx size_mb == 0.0 then "32 Bytes (default)" else tprint("% MB", size_mb); s := New(string); s.count = size; s.data = alloc(size); memset(s.data, "A", size); return s, label; } make_data_static :: (size_mb: float) -> string { size := cast(int, 1024.0 * 1024.0 * size_mb); s: string; s.count = size; s.data = alloc(size); memset(s.data, "B", size); return s; } request_make :: ( url: string, data: string = "", method: string = "", headers: []string = .[], include_headers: bool = false, bytes_limit: s32 = 0, drip_behavior: Drip_Behavior ) -> (response_body: string, response_code: int, curl_code: CURLcode) { curl := curl_easy_init(); assert(curl != null); my_url := ifx url then url else URL; curl_easy_setopt(curl, .URL, temp_c_string(my_url)); if method then curl_easy_setopt(curl, .CUSTOMREQUEST, temp_c_string(method)); if data || (method && method != "GET") then curl_easy_setopt(curl, .POSTFIELDS, temp_c_string(data)); if include_headers then curl_easy_setopt(curl, .HEADER, 1); if method == "HEAD" then curl_easy_setopt(curl, .NOBODY, 1); if headers.count { slist: *curl_slist; for headers slist = curl_slist_append(slist, temp_c_string(it)); curl_easy_setopt(curl, .HTTPHEADER, slist); } builder: String_Builder; defer free_buffers(*builder); if bytes_limit > 0 { if #complete drip_behavior == { case .send; curl_easy_setopt(curl, .MAX_SEND_SPEED_LARGE, bytes_limit); case .recv; curl_easy_setopt(curl, .MAX_RECV_SPEED_LARGE, bytes_limit); case .both; curl_easy_setopt(curl, .MAX_SEND_SPEED_LARGE, bytes_limit); curl_easy_setopt(curl, .MAX_RECV_SPEED_LARGE, bytes_limit); } } curl_easy_setopt(curl, .ACCEPT_ENCODING, "identity"); curl_easy_setopt(curl, .WRITEFUNCTION, write_callback); curl_easy_setopt(curl, .WRITEDATA, *builder); curl_code: CURLcode = curl_easy_perform(curl); response_code: int; if curl_code == .OK then curl_easy_getinfo(curl, .RESPONSE_CODE, *response_code); response_body: string = builder_to_string(*builder); return response_body, response_code, curl_code; } write_callback :: ( ptr: *u8, size: size_t, nmemb: size_t, userdata: *void ) -> size_t #c_call { builder := cast(*String_Builder, userdata); push_context { log("Write byte: %", ptr); append(builder, ptr, xx nmemb); } return nmemb; } /** Tests */ test_with_data :: inline ( url: string, data: *string, name: string, bytes_limit: s32 = 0, behavior: Drip_Behavior ) { do_request_and_log(url, data, "POST", name, bytes_limit, behavior); } test_single :: inline ( url: string, method: string, name: string, bytes_limit: s32 = 0, behavior: Drip_Behavior ) { do_request_and_log(url, null, method, name, bytes_limit, behavior); } do_request_and_log :: ( url: string, data: *string, method: string, name: string, bytes_limit: s32, behavior: Drip_Behavior ) { has_limit := ifx bytes_limit > 0 then tprint("(% bytes limit)", bytes_limit) else ""; log("Test: %, % (%)", name, has_limit, behavior); data_deref := ifx data == null then "" else data.*; response_body, http_code, curl_code := request_make( url, method=method, data=data_deref, bytes_limit=bytes_limit, drip_behavior=behavior ); log_vars(http_code, curl_code, slice(response_body, 0, 255)); }