quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

h2_serverpush.c (5869B)


      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at https://curl.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  * SPDX-License-Identifier: curl
     22  *
     23  ***************************************************************************/
     24 #include "first.h"
     25 
     26 static int my_trace(CURL *handle, curl_infotype type,
     27                     char *data, size_t size, void *userp)
     28 {
     29   const char *text;
     30   (void)handle; /* prevent compiler warning */
     31   (void)userp;
     32   switch(type) {
     33   case CURLINFO_TEXT:
     34     curl_mfprintf(stderr, "== Info: %s", data);
     35     return 0;
     36   case CURLINFO_HEADER_OUT:
     37     text = "=> Send header";
     38     break;
     39   case CURLINFO_DATA_OUT:
     40     text = "=> Send data";
     41     break;
     42   case CURLINFO_SSL_DATA_OUT:
     43     text = "=> Send SSL data";
     44     break;
     45   case CURLINFO_HEADER_IN:
     46     text = "<= Recv header";
     47     break;
     48   case CURLINFO_DATA_IN:
     49     text = "<= Recv data";
     50     break;
     51   case CURLINFO_SSL_DATA_IN:
     52     text = "<= Recv SSL data";
     53     break;
     54   default: /* in case a new one is introduced to shock us */
     55     return 0;
     56   }
     57 
     58   dump(text, (unsigned char *)data, size, 1);
     59   return 0;
     60 }
     61 
     62 static FILE *out_download;
     63 
     64 static int setup_h2_serverpush(CURL *hnd, const char *url)
     65 {
     66   out_download = fopen("download_0.data", "wb");
     67   if(!out_download)
     68     return 1;  /* failed */
     69 
     70   curl_easy_setopt(hnd, CURLOPT_URL, url);
     71   curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
     72   curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, 0L);
     73   curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYHOST, 0L);
     74 
     75   curl_easy_setopt(hnd, CURLOPT_WRITEDATA, out_download);
     76 
     77   /* please be verbose */
     78   curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
     79   curl_easy_setopt(hnd, CURLOPT_DEBUGFUNCTION, my_trace);
     80 
     81   /* wait for pipe connection to confirm */
     82   curl_easy_setopt(hnd, CURLOPT_PIPEWAIT, 1L);
     83 
     84   return 0; /* all is good */
     85 }
     86 
     87 static FILE *out_push;
     88 
     89 /* called when there's an incoming push */
     90 static int server_push_callback(CURL *parent,
     91                                 CURL *easy,
     92                                 size_t num_headers,
     93                                 struct curl_pushheaders *headers,
     94                                 void *userp)
     95 {
     96   char *headp;
     97   size_t i;
     98   int *transfers = (int *)userp;
     99   char filename[128];
    100   static unsigned int count = 0;
    101   int rv;
    102 
    103   (void)parent; /* we have no use for this */
    104   curl_msnprintf(filename, sizeof(filename) - 1, "push%u", count++);
    105 
    106   /* here's a new stream, save it in a new file for each new push */
    107   out_push = fopen(filename, "wb");
    108   if(!out_push) {
    109     /* if we cannot save it, deny it */
    110     curl_mfprintf(stderr, "Failed to create output file for push\n");
    111     rv = CURL_PUSH_DENY;
    112     goto out;
    113   }
    114 
    115   /* write to this file */
    116   curl_easy_setopt(easy, CURLOPT_WRITEDATA, out_push);
    117 
    118   curl_mfprintf(stderr, "**** push callback approves stream %u, "
    119                 "got %lu headers!\n", count, (unsigned long)num_headers);
    120 
    121   for(i = 0; i < num_headers; i++) {
    122     headp = curl_pushheader_bynum(headers, i);
    123     curl_mfprintf(stderr, "**** header %lu: %s\n", (unsigned long)i, headp);
    124   }
    125 
    126   headp = curl_pushheader_byname(headers, ":path");
    127   if(headp) {
    128     curl_mfprintf(stderr, "**** The PATH is %s\n",
    129                   headp /* skip :path + colon */);
    130   }
    131 
    132   (*transfers)++; /* one more */
    133   rv = CURL_PUSH_OK;
    134 
    135 out:
    136   return rv;
    137 }
    138 
    139 /*
    140  * Download a file over HTTP/2, take care of server push.
    141  */
    142 static int test_h2_serverpush(int argc, char *argv[])
    143 {
    144   CURL *easy;
    145   CURLM *multi_handle;
    146   int transfers = 1; /* we start with one */
    147   struct CURLMsg *m;
    148   const char *url;
    149 
    150   if(argc != 2) {
    151     curl_mfprintf(stderr, "need URL as argument\n");
    152     return 2;
    153   }
    154   url = argv[1];
    155 
    156   multi_handle = curl_multi_init();
    157   curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
    158   curl_multi_setopt(multi_handle, CURLMOPT_PUSHFUNCTION, server_push_callback);
    159   curl_multi_setopt(multi_handle, CURLMOPT_PUSHDATA, &transfers);
    160 
    161   easy = curl_easy_init();
    162   if(setup_h2_serverpush(easy, url)) {
    163     fclose(out_download);
    164     curl_mfprintf(stderr, "failed\n");
    165     return 1;
    166   }
    167 
    168   curl_multi_add_handle(multi_handle, easy);
    169   do {
    170     int still_running; /* keep number of running handles */
    171     CURLMcode mc = curl_multi_perform(multi_handle, &still_running);
    172 
    173     if(still_running)
    174       /* wait for activity, timeout or "nothing" */
    175       mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL);
    176 
    177     if(mc)
    178       break;
    179 
    180     /*
    181      * A little caution when doing server push is that libcurl itself has
    182      * created and added one or more easy handles but we need to clean them up
    183      * when we are done.
    184      */
    185     do {
    186       int msgq = 0;
    187       m = curl_multi_info_read(multi_handle, &msgq);
    188       if(m && (m->msg == CURLMSG_DONE)) {
    189         CURL *e = m->easy_handle;
    190         transfers--;
    191         curl_multi_remove_handle(multi_handle, e);
    192         curl_easy_cleanup(e);
    193       }
    194     } while(m);
    195 
    196   } while(transfers); /* as long as we have transfers going */
    197 
    198   curl_multi_cleanup(multi_handle);
    199 
    200   fclose(out_download);
    201   if(out_push)
    202     fclose(out_push);
    203 
    204   return 0;
    205 }