]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
examples/http2-serverpush: fix file handle leaks
authorViktor Szakats <commit@vsz.me>
Fri, 31 Oct 2025 02:33:14 +0000 (03:33 +0100)
committerViktor Szakats <commit@vsz.me>
Fri, 31 Oct 2025 12:14:12 +0000 (13:14 +0100)
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

docs/examples/http2-serverpush.c
tests/libtest/cli_h2_serverpush.c

index e97be991a8cb53c42fdd906a8ffcccc19077eecb..c12a5f7d2ea229e3d19b906517e0af71ce66fdf5 100644 (file)
@@ -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;
 }
index a865fdfd8f5b2180eb86f016c2d206436513fe42..10d369faafe4f686d030cdf5ed33bdc6025ccca8 100644 (file)
@@ -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);