From: Viktor Szakats Date: Fri, 31 Oct 2025 02:33:14 +0000 (+0100) Subject: examples/http2-serverpush: fix file handle leaks X-Git-Tag: curl-8_17_0~57 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4b85e489a45c81b235d3e47d1524cbe1d6b25b06;p=thirdparty%2Fcurl.git examples/http2-serverpush: fix file handle leaks Also: - tests/libtest/cli_h2_serverpush: re-sync formatting. Previously fixed in tests based on a local clang-tidy v20 report. Pointed out by TIOBE scanner via Coverity 2025.3.0. Follow-up to 83a8818cfebe5f2a4bab5c9ddc55fd64b5629296 #17706 Closes #19291 --- diff --git a/docs/examples/http2-serverpush.c b/docs/examples/http2-serverpush.c index e97be991a8..c12a5f7d2e 100644 --- a/docs/examples/http2-serverpush.c +++ b/docs/examples/http2-serverpush.c @@ -40,6 +40,8 @@ #error "too old libcurl, cannot do HTTP/2 server push!" #endif +static FILE *out_download; + static void dump(const char *text, unsigned char *ptr, size_t size, char nohex) { size_t i; @@ -127,21 +129,13 @@ static int my_trace(CURL *handle, curl_infotype type, static int setup(CURL *hnd, const char *url) { - FILE *out = fopen(OUTPUTFILE, "wb"); - if(!out) - /* failed */ - return 1; - - /* write to this file */ - curl_easy_setopt(hnd, CURLOPT_WRITEDATA, out); + out_download = fopen(OUTPUTFILE, "wb"); + if(!out_download) + return 1; /* failed */ /* set the same URL */ curl_easy_setopt(hnd, CURLOPT_URL, url); - /* please be verbose */ - curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); - curl_easy_setopt(hnd, CURLOPT_DEBUGFUNCTION, my_trace); - /* HTTP/2 please */ curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); @@ -149,13 +143,22 @@ static int setup(CURL *hnd, const char *url) curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYHOST, 0L); -#if (CURLPIPE_MULTIPLEX > 0) + /* write to this file */ + curl_easy_setopt(hnd, CURLOPT_WRITEDATA, out_download); + + /* please be verbose */ + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(hnd, CURLOPT_DEBUGFUNCTION, my_trace); + +#if CURLPIPE_MULTIPLEX > 0 /* wait for pipe connection to confirm */ curl_easy_setopt(hnd, CURLOPT_PIPEWAIT, 1L); #endif return 0; /* all is good */ } +static FILE *out_push; + /* called when there is an incoming push */ static int server_push_callback(CURL *parent, CURL *easy, @@ -167,7 +170,6 @@ static int server_push_callback(CURL *parent, size_t i; int *transfers = (int *)userp; char filename[128]; - FILE *out; static unsigned int count = 0; (void)parent; @@ -175,15 +177,15 @@ static int server_push_callback(CURL *parent, snprintf(filename, sizeof(filename), "push%u", count++); /* here's a new stream, save it in a new file for each new push */ - out = fopen(filename, "wb"); - if(!out) { + out_push = fopen(filename, "wb"); + if(!out_push) { /* if we cannot save it, deny it */ fprintf(stderr, "Failed to create output file for push\n"); return CURL_PUSH_DENY; } /* write to this file */ - curl_easy_setopt(easy, CURLOPT_WRITEDATA, out); + curl_easy_setopt(easy, CURLOPT_WRITEDATA, out_push); fprintf(stderr, "**** push callback approves stream %u, got %lu headers!\n", count, (unsigned long)num_headers); @@ -199,10 +201,10 @@ static int server_push_callback(CURL *parent, } (*transfers)++; /* one more */ + return CURL_PUSH_OK; } - /* * Download a file over HTTP/2, take care of server push. */ @@ -233,13 +235,13 @@ int main(int argc, char *argv[]) return 1; } - /* add the easy transfer */ - curl_multi_add_handle(multi_handle, easy); - curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); curl_multi_setopt(multi_handle, CURLMOPT_PUSHFUNCTION, server_push_callback); curl_multi_setopt(multi_handle, CURLMOPT_PUSHDATA, &transfers); + /* add the easy transfer */ + curl_multi_add_handle(multi_handle, easy); + do { struct CURLMsg *m; int still_running; /* keep number of running handles */ @@ -257,7 +259,6 @@ int main(int argc, char *argv[]) * created and added one or more easy handles but we need to clean them up * when we are done. */ - do { int msgq = 0; m = curl_multi_info_read(multi_handle, &msgq); @@ -274,5 +275,9 @@ int main(int argc, char *argv[]) curl_multi_cleanup(multi_handle); curl_global_cleanup(); + fclose(out_download); + if(out_push) + fclose(out_push); + return 0; } diff --git a/tests/libtest/cli_h2_serverpush.c b/tests/libtest/cli_h2_serverpush.c index a865fdfd8f..10d369faaf 100644 --- a/tests/libtest/cli_h2_serverpush.c +++ b/tests/libtest/cli_h2_serverpush.c @@ -54,7 +54,7 @@ static int setup_h2_serverpush(CURL *hnd, const char *url) static FILE *out_push; -/* called when there's an incoming push */ +/* called when there is an incoming push */ static int server_push_callback(CURL *parent, CURL *easy, size_t num_headers, @@ -66,9 +66,9 @@ static int server_push_callback(CURL *parent, int *transfers = (int *)userp; char filename[128]; static unsigned int count = 0; - int rv; (void)parent; + curl_msnprintf(filename, sizeof(filename) - 1, "push%u", count++); /* here's a new stream, save it in a new file for each new push */ @@ -76,8 +76,7 @@ static int server_push_callback(CURL *parent, if(!out_push) { /* if we cannot save it, deny it */ curl_mfprintf(stderr, "Failed to create output file for push\n"); - rv = CURL_PUSH_DENY; - goto out; + return CURL_PUSH_DENY; } /* write to this file */ @@ -98,10 +97,8 @@ static int server_push_callback(CURL *parent, } (*transfers)++; /* one more */ - rv = CURL_PUSH_OK; -out: - return rv; + return CURL_PUSH_OK; } /* @@ -112,7 +109,6 @@ static CURLcode test_cli_h2_serverpush(const char *URL) CURL *easy; CURLM *multi_handle; int transfers = 1; /* we start with one */ - struct CURLMsg *m; debug_config.nohex = TRUE; debug_config.tracetime = FALSE; @@ -123,9 +119,6 @@ static CURLcode test_cli_h2_serverpush(const char *URL) } multi_handle = curl_multi_init(); - curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); - curl_multi_setopt(multi_handle, CURLMOPT_PUSHFUNCTION, server_push_callback); - curl_multi_setopt(multi_handle, CURLMOPT_PUSHDATA, &transfers); easy = curl_easy_init(); if(setup_h2_serverpush(easy, URL)) { @@ -134,8 +127,14 @@ static CURLcode test_cli_h2_serverpush(const char *URL) return (CURLcode)1; } + curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); + curl_multi_setopt(multi_handle, CURLMOPT_PUSHFUNCTION, server_push_callback); + curl_multi_setopt(multi_handle, CURLMOPT_PUSHDATA, &transfers); + curl_multi_add_handle(multi_handle, easy); + do { + struct CURLMsg *m; int still_running; /* keep number of running handles */ CURLMcode mc = curl_multi_perform(multi_handle, &still_running);