quickjs-tart

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

http2.c (96767B)


      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 
     25 #include "curl_setup.h"
     26 
     27 #ifdef USE_NGHTTP2
     28 #include <stdint.h>
     29 #include <nghttp2/nghttp2.h>
     30 #include "urldata.h"
     31 #include "bufq.h"
     32 #include "uint-hash.h"
     33 #include "http1.h"
     34 #include "http2.h"
     35 #include "http.h"
     36 #include "sendf.h"
     37 #include "select.h"
     38 #include "curlx/base64.h"
     39 #include "multiif.h"
     40 #include "url.h"
     41 #include "urlapi-int.h"
     42 #include "cfilters.h"
     43 #include "connect.h"
     44 #include "rand.h"
     45 #include "strdup.h"
     46 #include "curlx/strparse.h"
     47 #include "transfer.h"
     48 #include "curlx/dynbuf.h"
     49 #include "headers.h"
     50 /* The last 3 #include files should be in this order */
     51 #include "curl_printf.h"
     52 #include "curl_memory.h"
     53 #include "memdebug.h"
     54 
     55 #if (NGHTTP2_VERSION_NUM < 0x010c00)
     56 #error too old nghttp2 version, upgrade!
     57 #endif
     58 
     59 #ifdef CURL_DISABLE_VERBOSE_STRINGS
     60 #define nghttp2_session_callbacks_set_error_callback(x,y)
     61 #endif
     62 
     63 #if (NGHTTP2_VERSION_NUM >= 0x010c00)
     64 #define NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE 1
     65 #endif
     66 
     67 
     68 /* buffer dimensioning:
     69  * use 16K as chunk size, as that fits H2 DATA frames well */
     70 #define H2_CHUNK_SIZE           (16 * 1024)
     71 /* connection window size */
     72 #define H2_CONN_WINDOW_SIZE     (10 * 1024 * 1024)
     73 /* on receiving from TLS, we prep for holding a full stream window */
     74 #define H2_NW_RECV_CHUNKS       (H2_CONN_WINDOW_SIZE / H2_CHUNK_SIZE)
     75 /* on send into TLS, we just want to accumulate small frames */
     76 #define H2_NW_SEND_CHUNKS       1
     77 /* this is how much we want "in flight" for a stream, unthrottled  */
     78 #define H2_STREAM_WINDOW_SIZE_MAX   (10 * 1024 * 1024)
     79 /* this is how much we want "in flight" for a stream, initially, IFF
     80  * nghttp2 allows us to tweak the local window size. */
     81 #if NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
     82 #define H2_STREAM_WINDOW_SIZE_INITIAL  (64 * 1024)
     83 #else
     84 #define H2_STREAM_WINDOW_SIZE_INITIAL H2_STREAM_WINDOW_SIZE_MAX
     85 #endif
     86 /* keep smaller stream upload buffer (default h2 window size) to have
     87  * our progress bars and "upload done" reporting closer to reality */
     88 #define H2_STREAM_SEND_CHUNKS   ((64 * 1024) / H2_CHUNK_SIZE)
     89 /* spare chunks we keep for a full window */
     90 #define H2_STREAM_POOL_SPARES   (H2_CONN_WINDOW_SIZE / H2_CHUNK_SIZE)
     91 
     92 /* We need to accommodate the max number of streams with their window sizes on
     93  * the overall connection. Streams might become PAUSED which will block their
     94  * received QUOTA in the connection window. If we run out of space, the server
     95  * is blocked from sending us any data. See #10988 for an issue with this. */
     96 #define HTTP2_HUGE_WINDOW_SIZE (100 * H2_STREAM_WINDOW_SIZE_MAX)
     97 
     98 #define H2_SETTINGS_IV_LEN  3
     99 #define H2_BINSETTINGS_LEN 80
    100 
    101 static size_t populate_settings(nghttp2_settings_entry *iv,
    102                                 struct Curl_easy *data)
    103 {
    104   iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
    105   iv[0].value = Curl_multi_max_concurrent_streams(data->multi);
    106 
    107   iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
    108   iv[1].value = H2_STREAM_WINDOW_SIZE_INITIAL;
    109 
    110   iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
    111   iv[2].value = data->multi->push_cb != NULL;
    112 
    113   return 3;
    114 }
    115 
    116 static ssize_t populate_binsettings(uint8_t *binsettings,
    117                                     struct Curl_easy *data)
    118 {
    119   nghttp2_settings_entry iv[H2_SETTINGS_IV_LEN];
    120   size_t ivlen;
    121 
    122   ivlen = populate_settings(iv, data);
    123   /* this returns number of bytes it wrote or a negative number on error. */
    124   return nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN,
    125                                        iv, ivlen);
    126 }
    127 
    128 struct cf_h2_ctx {
    129   nghttp2_session *h2;
    130   /* The easy handle used in the current filter call, cleared at return */
    131   struct cf_call_data call_data;
    132 
    133   struct bufq inbufq;           /* network input */
    134   struct bufq outbufq;          /* network output */
    135   struct bufc_pool stream_bufcp; /* spares for stream buffers */
    136   struct dynbuf scratch;        /* scratch buffer for temp use */
    137 
    138   struct uint_hash streams; /* hash of `data->mid` to `h2_stream_ctx` */
    139   size_t drain_total; /* sum of all stream's UrlState drain */
    140   uint32_t max_concurrent_streams;
    141   uint32_t goaway_error;        /* goaway error code from server */
    142   int32_t remote_max_sid;       /* max id processed by server */
    143   int32_t local_max_sid;        /* max id processed by us */
    144 #ifdef DEBUGBUILD
    145   int32_t stream_win_max;       /* max h2 stream window size */
    146 #endif
    147   BIT(initialized);
    148   BIT(via_h1_upgrade);
    149   BIT(conn_closed);
    150   BIT(rcvd_goaway);
    151   BIT(sent_goaway);
    152   BIT(enable_push);
    153   BIT(nw_out_blocked);
    154 };
    155 
    156 /* How to access `call_data` from a cf_h2 filter */
    157 #undef CF_CTX_CALL_DATA
    158 #define CF_CTX_CALL_DATA(cf)  \
    159   ((struct cf_h2_ctx *)(cf)->ctx)->call_data
    160 
    161 static void h2_stream_hash_free(unsigned int id, void *stream);
    162 
    163 static void cf_h2_ctx_init(struct cf_h2_ctx *ctx, bool via_h1_upgrade)
    164 {
    165   Curl_bufcp_init(&ctx->stream_bufcp, H2_CHUNK_SIZE, H2_STREAM_POOL_SPARES);
    166   Curl_bufq_initp(&ctx->inbufq, &ctx->stream_bufcp, H2_NW_RECV_CHUNKS, 0);
    167   Curl_bufq_initp(&ctx->outbufq, &ctx->stream_bufcp, H2_NW_SEND_CHUNKS, 0);
    168   curlx_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER);
    169   Curl_uint_hash_init(&ctx->streams, 63, h2_stream_hash_free);
    170   ctx->remote_max_sid = 2147483647;
    171   ctx->via_h1_upgrade = via_h1_upgrade;
    172 #ifdef DEBUGBUILD
    173   {
    174     const char *p = getenv("CURL_H2_STREAM_WIN_MAX");
    175 
    176     ctx->stream_win_max = H2_STREAM_WINDOW_SIZE_MAX;
    177     if(p) {
    178       curl_off_t l;
    179       if(!curlx_str_number(&p, &l, INT_MAX))
    180         ctx->stream_win_max = (int32_t)l;
    181     }
    182   }
    183 #endif
    184   ctx->initialized = TRUE;
    185 }
    186 
    187 static void cf_h2_ctx_free(struct cf_h2_ctx *ctx)
    188 {
    189   if(ctx && ctx->initialized) {
    190     Curl_bufq_free(&ctx->inbufq);
    191     Curl_bufq_free(&ctx->outbufq);
    192     Curl_bufcp_free(&ctx->stream_bufcp);
    193     curlx_dyn_free(&ctx->scratch);
    194     Curl_uint_hash_destroy(&ctx->streams);
    195     memset(ctx, 0, sizeof(*ctx));
    196   }
    197   free(ctx);
    198 }
    199 
    200 static void cf_h2_ctx_close(struct cf_h2_ctx *ctx)
    201 {
    202   if(ctx->h2) {
    203     nghttp2_session_del(ctx->h2);
    204   }
    205 }
    206 
    207 static CURLcode nw_out_flush(struct Curl_cfilter *cf,
    208                              struct Curl_easy *data);
    209 
    210 static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
    211                                    struct Curl_easy *data);
    212 
    213 /**
    214  * All about the H2 internals of a stream
    215  */
    216 struct h2_stream_ctx {
    217   struct bufq sendbuf; /* request buffer */
    218   struct h1_req_parser h1; /* parsing the request */
    219   struct dynhds resp_trailers; /* response trailer fields */
    220   size_t resp_hds_len; /* amount of response header bytes in recvbuf */
    221   curl_off_t nrcvd_data;  /* number of DATA bytes received */
    222 
    223   char **push_headers;       /* allocated array */
    224   size_t push_headers_used;  /* number of entries filled in */
    225   size_t push_headers_alloc; /* number of entries allocated */
    226 
    227   int status_code; /* HTTP response status code */
    228   uint32_t error; /* stream error code */
    229   CURLcode xfer_result; /* Result of writing out response */
    230   int32_t local_window_size; /* the local recv window size */
    231   int32_t id; /* HTTP/2 protocol identifier for stream */
    232   BIT(resp_hds_complete); /* we have a complete, final response */
    233   BIT(closed); /* TRUE on stream close */
    234   BIT(reset);  /* TRUE on stream reset */
    235   BIT(close_handled); /* TRUE if stream closure is handled by libcurl */
    236   BIT(bodystarted);
    237   BIT(body_eos);    /* the complete body has been added to `sendbuf` and
    238                      * is being/has been processed from there. */
    239   BIT(write_paused);  /* stream write is paused */
    240 };
    241 
    242 #define H2_STREAM_CTX(ctx,data)                                         \
    243   ((struct h2_stream_ctx *)(                                            \
    244     data? Curl_uint_hash_get(&(ctx)->streams, (data)->mid) : NULL))
    245 
    246 static struct h2_stream_ctx *h2_stream_ctx_create(struct cf_h2_ctx *ctx)
    247 {
    248   struct h2_stream_ctx *stream;
    249 
    250   (void)ctx;
    251   stream = calloc(1, sizeof(*stream));
    252   if(!stream)
    253     return NULL;
    254 
    255   stream->id = -1;
    256   Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp,
    257                   H2_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE);
    258   Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
    259   Curl_dynhds_init(&stream->resp_trailers, 0, DYN_HTTP_REQUEST);
    260   stream->bodystarted = FALSE;
    261   stream->status_code = -1;
    262   stream->closed = FALSE;
    263   stream->close_handled = FALSE;
    264   stream->error = NGHTTP2_NO_ERROR;
    265   stream->local_window_size = H2_STREAM_WINDOW_SIZE_INITIAL;
    266   stream->nrcvd_data = 0;
    267   return stream;
    268 }
    269 
    270 static void free_push_headers(struct h2_stream_ctx *stream)
    271 {
    272   size_t i;
    273   for(i = 0; i < stream->push_headers_used; i++)
    274     free(stream->push_headers[i]);
    275   Curl_safefree(stream->push_headers);
    276   stream->push_headers_used = 0;
    277 }
    278 
    279 static void h2_stream_ctx_free(struct h2_stream_ctx *stream)
    280 {
    281   Curl_bufq_free(&stream->sendbuf);
    282   Curl_h1_req_parse_free(&stream->h1);
    283   Curl_dynhds_free(&stream->resp_trailers);
    284   free_push_headers(stream);
    285   free(stream);
    286 }
    287 
    288 static void h2_stream_hash_free(unsigned int id, void *stream)
    289 {
    290   (void)id;
    291   DEBUGASSERT(stream);
    292   h2_stream_ctx_free((struct h2_stream_ctx *)stream);
    293 }
    294 
    295 #ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
    296 static int32_t cf_h2_get_desired_local_win(struct Curl_cfilter *cf,
    297                                            struct Curl_easy *data)
    298 {
    299   (void)cf;
    300   if(data->set.max_recv_speed && data->set.max_recv_speed < INT32_MAX) {
    301     /* The transfer should only receive `max_recv_speed` bytes per second.
    302      * We restrict the stream's local window size, so that the server cannot
    303      * send us "too much" at a time.
    304      * This gets less precise the higher the latency. */
    305     return (int32_t)data->set.max_recv_speed;
    306   }
    307 #ifdef DEBUGBUILD
    308   else {
    309     struct cf_h2_ctx *ctx = cf->ctx;
    310     CURL_TRC_CF(data, cf, "stream_win_max=%d", ctx->stream_win_max);
    311     return ctx->stream_win_max;
    312   }
    313 #else
    314   return H2_STREAM_WINDOW_SIZE_MAX;
    315 #endif
    316 }
    317 
    318 static CURLcode cf_h2_update_local_win(struct Curl_cfilter *cf,
    319                                        struct Curl_easy *data,
    320                                        struct h2_stream_ctx *stream)
    321 {
    322   struct cf_h2_ctx *ctx = cf->ctx;
    323   int32_t dwsize;
    324   int rv;
    325 
    326   dwsize = (stream->write_paused || stream->xfer_result) ?
    327            0 : cf_h2_get_desired_local_win(cf, data);
    328   if(dwsize != stream->local_window_size) {
    329     int32_t wsize = nghttp2_session_get_stream_effective_local_window_size(
    330                       ctx->h2, stream->id);
    331     if(dwsize > wsize) {
    332       rv = nghttp2_session_set_local_window_size(ctx->h2, NGHTTP2_FLAG_NONE,
    333                                                  stream->id, dwsize);
    334       if(rv) {
    335         failf(data, "[%d] nghttp2 set_local_window_size(%d) failed: "
    336               "%s(%d)", stream->id, dwsize, nghttp2_strerror(rv), rv);
    337         return CURLE_HTTP2;
    338       }
    339       rv = nghttp2_submit_window_update(ctx->h2, NGHTTP2_FLAG_NONE,
    340                                         stream->id, dwsize - wsize);
    341       if(rv) {
    342         failf(data, "[%d] nghttp2_submit_window_update() failed: "
    343               "%s(%d)", stream->id, nghttp2_strerror(rv), rv);
    344         return CURLE_HTTP2;
    345       }
    346       stream->local_window_size = dwsize;
    347       CURL_TRC_CF(data, cf, "[%d] local window update by %d",
    348                   stream->id, dwsize - wsize);
    349     }
    350     else {
    351       rv = nghttp2_session_set_local_window_size(ctx->h2, NGHTTP2_FLAG_NONE,
    352                                                  stream->id, dwsize);
    353       if(rv) {
    354         failf(data, "[%d] nghttp2_session_set_local_window_size() failed: "
    355               "%s(%d)", stream->id, nghttp2_strerror(rv), rv);
    356         return CURLE_HTTP2;
    357       }
    358       stream->local_window_size = dwsize;
    359       CURL_TRC_CF(data, cf, "[%d] local window size now %d",
    360                   stream->id, dwsize);
    361     }
    362   }
    363   return CURLE_OK;
    364 }
    365 
    366 #else /* NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE */
    367 
    368 static CURLcode cf_h2_update_local_win(struct Curl_cfilter *cf,
    369                                        struct Curl_easy *data,
    370                                        struct h2_stream_ctx *stream)
    371 {
    372   (void)cf;
    373   (void)data;
    374   (void)stream;
    375   return CURLE_OK;
    376 }
    377 #endif /* !NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE */
    378 
    379 
    380 static CURLcode http2_data_setup(struct Curl_cfilter *cf,
    381                                  struct Curl_easy *data,
    382                                  struct h2_stream_ctx **pstream)
    383 {
    384   struct cf_h2_ctx *ctx = cf->ctx;
    385   struct h2_stream_ctx *stream;
    386 
    387   (void)cf;
    388   DEBUGASSERT(data);
    389   stream = H2_STREAM_CTX(ctx, data);
    390   if(stream) {
    391     *pstream = stream;
    392     return CURLE_OK;
    393   }
    394 
    395   stream = h2_stream_ctx_create(ctx);
    396   if(!stream)
    397     return CURLE_OUT_OF_MEMORY;
    398 
    399   if(!Curl_uint_hash_set(&ctx->streams, data->mid, stream)) {
    400     h2_stream_ctx_free(stream);
    401     return CURLE_OUT_OF_MEMORY;
    402   }
    403 
    404   *pstream = stream;
    405   return CURLE_OK;
    406 }
    407 
    408 static void http2_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
    409 {
    410   struct cf_h2_ctx *ctx = cf->ctx;
    411   struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
    412 
    413   DEBUGASSERT(ctx);
    414   if(!stream || !ctx->initialized)
    415     return;
    416 
    417   if(ctx->h2) {
    418     bool flush_egress = FALSE;
    419     /* returns error if stream not known, which is fine here */
    420     (void)nghttp2_session_set_stream_user_data(ctx->h2, stream->id, NULL);
    421 
    422     if(!stream->closed && stream->id > 0) {
    423       /* RST_STREAM */
    424       CURL_TRC_CF(data, cf, "[%d] premature DATA_DONE, RST stream",
    425                   stream->id);
    426       stream->closed = TRUE;
    427       stream->reset = TRUE;
    428       nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
    429                                 stream->id, NGHTTP2_STREAM_CLOSED);
    430       flush_egress = TRUE;
    431     }
    432 
    433     if(flush_egress) {
    434       (void)nghttp2_session_send(ctx->h2);
    435       (void)nw_out_flush(cf, data);
    436     }
    437   }
    438 
    439   Curl_uint_hash_remove(&ctx->streams, data->mid);
    440 }
    441 
    442 static int h2_client_new(struct Curl_cfilter *cf,
    443                          nghttp2_session_callbacks *cbs)
    444 {
    445   struct cf_h2_ctx *ctx = cf->ctx;
    446   nghttp2_option *o;
    447   nghttp2_mem mem = {NULL, Curl_nghttp2_malloc, Curl_nghttp2_free,
    448     Curl_nghttp2_calloc, Curl_nghttp2_realloc};
    449 
    450   int rc = nghttp2_option_new(&o);
    451   if(rc)
    452     return rc;
    453   /* We handle window updates ourself to enforce buffer limits */
    454   nghttp2_option_set_no_auto_window_update(o, 1);
    455 #if NGHTTP2_VERSION_NUM >= 0x013200
    456   /* with 1.50.0 */
    457   /* turn off RFC 9113 leading and trailing white spaces validation against
    458      HTTP field value. */
    459   nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation(o, 1);
    460 #endif
    461   rc = nghttp2_session_client_new3(&ctx->h2, cbs, cf, o, &mem);
    462   nghttp2_option_del(o);
    463   return rc;
    464 }
    465 
    466 static ssize_t send_callback(nghttp2_session *h2,
    467                              const uint8_t *mem, size_t length, int flags,
    468                              void *userp);
    469 static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
    470                          void *userp);
    471 static int cf_h2_on_invalid_frame_recv(nghttp2_session *session,
    472                                        const nghttp2_frame *frame,
    473                                        int lib_error_code,
    474                                        void *user_data);
    475 #ifndef CURL_DISABLE_VERBOSE_STRINGS
    476 static int on_frame_send(nghttp2_session *session, const nghttp2_frame *frame,
    477                          void *userp);
    478 #endif
    479 static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
    480                               int32_t stream_id,
    481                               const uint8_t *mem, size_t len, void *userp);
    482 static int on_stream_close(nghttp2_session *session, int32_t stream_id,
    483                            uint32_t error_code, void *userp);
    484 static int on_begin_headers(nghttp2_session *session,
    485                             const nghttp2_frame *frame, void *userp);
    486 static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
    487                      const uint8_t *name, size_t namelen,
    488                      const uint8_t *value, size_t valuelen,
    489                      uint8_t flags,
    490                      void *userp);
    491 #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
    492 static int error_callback(nghttp2_session *session, const char *msg,
    493                           size_t len, void *userp);
    494 #endif
    495 static CURLcode cf_h2_ctx_open(struct Curl_cfilter *cf,
    496                                struct Curl_easy *data)
    497 {
    498   struct cf_h2_ctx *ctx = cf->ctx;
    499   struct h2_stream_ctx *stream;
    500   CURLcode result = CURLE_OUT_OF_MEMORY;
    501   int rc;
    502   nghttp2_session_callbacks *cbs = NULL;
    503 
    504   DEBUGASSERT(!ctx->h2);
    505   DEBUGASSERT(ctx->initialized);
    506 
    507   rc = nghttp2_session_callbacks_new(&cbs);
    508   if(rc) {
    509     failf(data, "Couldn't initialize nghttp2 callbacks");
    510     goto out;
    511   }
    512 
    513   nghttp2_session_callbacks_set_send_callback(cbs, send_callback);
    514   nghttp2_session_callbacks_set_on_frame_recv_callback(cbs, on_frame_recv);
    515   nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(cbs,
    516     cf_h2_on_invalid_frame_recv);
    517 #ifndef CURL_DISABLE_VERBOSE_STRINGS
    518   nghttp2_session_callbacks_set_on_frame_send_callback(cbs, on_frame_send);
    519 #endif
    520   nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
    521     cbs, on_data_chunk_recv);
    522   nghttp2_session_callbacks_set_on_stream_close_callback(cbs, on_stream_close);
    523   nghttp2_session_callbacks_set_on_begin_headers_callback(
    524     cbs, on_begin_headers);
    525   nghttp2_session_callbacks_set_on_header_callback(cbs, on_header);
    526 #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
    527   nghttp2_session_callbacks_set_error_callback(cbs, error_callback);
    528 #endif
    529 
    530   /* The nghttp2 session is not yet setup, do it */
    531   rc = h2_client_new(cf, cbs);
    532   if(rc) {
    533     failf(data, "Couldn't initialize nghttp2");
    534     goto out;
    535   }
    536   ctx->max_concurrent_streams = DEFAULT_MAX_CONCURRENT_STREAMS;
    537 
    538   if(ctx->via_h1_upgrade) {
    539     /* HTTP/1.1 Upgrade issued. H2 Settings have already been submitted
    540      * in the H1 request and we upgrade from there. This stream
    541      * is opened implicitly as #1. */
    542     uint8_t binsettings[H2_BINSETTINGS_LEN];
    543     ssize_t binlen; /* length of the binsettings data */
    544 
    545     binlen = populate_binsettings(binsettings, data);
    546     if(binlen <= 0) {
    547       failf(data, "nghttp2 unexpectedly failed on pack_settings_payload");
    548       result = CURLE_FAILED_INIT;
    549       goto out;
    550     }
    551 
    552     result = http2_data_setup(cf, data, &stream);
    553     if(result)
    554       goto out;
    555     DEBUGASSERT(stream);
    556     stream->id = 1;
    557     /* queue SETTINGS frame (again) */
    558     rc = nghttp2_session_upgrade2(ctx->h2, binsettings, (size_t)binlen,
    559                                   data->state.httpreq == HTTPREQ_HEAD,
    560                                   NULL);
    561     if(rc) {
    562       failf(data, "nghttp2_session_upgrade2() failed: %s(%d)",
    563             nghttp2_strerror(rc), rc);
    564       result = CURLE_HTTP2;
    565       goto out;
    566     }
    567 
    568     rc = nghttp2_session_set_stream_user_data(ctx->h2, stream->id,
    569                                               data);
    570     if(rc) {
    571       infof(data, "http/2: failed to set user_data for stream %u",
    572             stream->id);
    573       DEBUGASSERT(0);
    574     }
    575     CURL_TRC_CF(data, cf, "created session via Upgrade");
    576   }
    577   else {
    578     nghttp2_settings_entry iv[H2_SETTINGS_IV_LEN];
    579     size_t ivlen;
    580 
    581     ivlen = populate_settings(iv, data);
    582     rc = nghttp2_submit_settings(ctx->h2, NGHTTP2_FLAG_NONE,
    583                                  iv, ivlen);
    584     if(rc) {
    585       failf(data, "nghttp2_submit_settings() failed: %s(%d)",
    586             nghttp2_strerror(rc), rc);
    587       result = CURLE_HTTP2;
    588       goto out;
    589     }
    590   }
    591 
    592   rc = nghttp2_session_set_local_window_size(ctx->h2, NGHTTP2_FLAG_NONE, 0,
    593                                              HTTP2_HUGE_WINDOW_SIZE);
    594   if(rc) {
    595     failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
    596           nghttp2_strerror(rc), rc);
    597     result = CURLE_HTTP2;
    598     goto out;
    599   }
    600 
    601   /* all set, traffic will be send on connect */
    602   result = CURLE_OK;
    603   CURL_TRC_CF(data, cf, "[0] created h2 session%s",
    604               ctx->via_h1_upgrade ? " (via h1 upgrade)" : "");
    605 
    606 out:
    607   if(cbs)
    608     nghttp2_session_callbacks_del(cbs);
    609   return result;
    610 }
    611 
    612 /*
    613  * Returns nonzero if current HTTP/2 session should be closed.
    614  */
    615 static int should_close_session(struct cf_h2_ctx *ctx)
    616 {
    617   return ctx->drain_total == 0 && !nghttp2_session_want_read(ctx->h2) &&
    618     !nghttp2_session_want_write(ctx->h2);
    619 }
    620 
    621 /*
    622  * Processes pending input left in network input buffer.
    623  * This function returns 0 if it succeeds, or -1 and error code will
    624  * be assigned to *err.
    625  */
    626 static int h2_process_pending_input(struct Curl_cfilter *cf,
    627                                     struct Curl_easy *data,
    628                                     CURLcode *err)
    629 {
    630   struct cf_h2_ctx *ctx = cf->ctx;
    631   const unsigned char *buf;
    632   size_t blen;
    633   ssize_t rv;
    634 
    635   while(Curl_bufq_peek(&ctx->inbufq, &buf, &blen)) {
    636 
    637     rv = nghttp2_session_mem_recv(ctx->h2, (const uint8_t *)buf, blen);
    638     if(rv < 0) {
    639       failf(data, "nghttp2 recv error %zd: %s", rv, nghttp2_strerror((int)rv));
    640       *err = CURLE_HTTP2;
    641       return -1;
    642     }
    643     Curl_bufq_skip(&ctx->inbufq, (size_t)rv);
    644     if(Curl_bufq_is_empty(&ctx->inbufq)) {
    645       break;
    646     }
    647     else {
    648       CURL_TRC_CF(data, cf, "process_pending_input: %zu bytes left "
    649                   "in connection buffer", Curl_bufq_len(&ctx->inbufq));
    650     }
    651   }
    652 
    653   if(nghttp2_session_check_request_allowed(ctx->h2) == 0) {
    654     /* No more requests are allowed in the current session, so
    655        the connection may not be reused. This is set when a
    656        GOAWAY frame has been received or when the limit of stream
    657        identifiers has been reached. */
    658     connclose(cf->conn, "http/2: No new requests allowed");
    659   }
    660 
    661   return 0;
    662 }
    663 
    664 /*
    665  * The server may send us data at any point (e.g. PING frames). Therefore,
    666  * we cannot assume that an HTTP/2 socket is dead just because it is readable.
    667  *
    668  * Check the lower filters first and, if successful, peek at the socket
    669  * and distinguish between closed and data.
    670  */
    671 static bool http2_connisalive(struct Curl_cfilter *cf, struct Curl_easy *data,
    672                               bool *input_pending)
    673 {
    674   struct cf_h2_ctx *ctx = cf->ctx;
    675   bool alive = TRUE;
    676 
    677   *input_pending = FALSE;
    678   if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
    679     return FALSE;
    680 
    681   if(*input_pending) {
    682     /* This happens before we have sent off a request and the connection is
    683        not in use by any other transfer, there should not be any data here,
    684        only "protocol frames" */
    685     CURLcode result;
    686     size_t nread;
    687 
    688     *input_pending = FALSE;
    689     result = Curl_cf_recv_bufq(cf->next, data, &ctx->inbufq, 0, &nread);
    690     if(!result) {
    691       CURL_TRC_CF(data, cf, "%zu bytes stray data read before trying "
    692                   "h2 connection", nread);
    693       if(h2_process_pending_input(cf, data, &result) < 0)
    694         /* immediate error, considered dead */
    695         alive = FALSE;
    696       else {
    697         alive = !should_close_session(ctx);
    698       }
    699     }
    700     else if(result != CURLE_AGAIN) {
    701       /* the read failed so let's say this is dead anyway */
    702       alive = FALSE;
    703     }
    704   }
    705 
    706   return alive;
    707 }
    708 
    709 static CURLcode http2_send_ping(struct Curl_cfilter *cf,
    710                                 struct Curl_easy *data)
    711 {
    712   struct cf_h2_ctx *ctx = cf->ctx;
    713   int rc;
    714 
    715   rc = nghttp2_submit_ping(ctx->h2, 0, ZERO_NULL);
    716   if(rc) {
    717     failf(data, "nghttp2_submit_ping() failed: %s(%d)",
    718           nghttp2_strerror(rc), rc);
    719    return CURLE_HTTP2;
    720   }
    721 
    722   rc = nghttp2_session_send(ctx->h2);
    723   if(rc) {
    724     failf(data, "nghttp2_session_send() failed: %s(%d)",
    725           nghttp2_strerror(rc), rc);
    726     return CURLE_SEND_ERROR;
    727   }
    728   return CURLE_OK;
    729 }
    730 
    731 /*
    732  * Store nghttp2 version info in this buffer.
    733  */
    734 void Curl_http2_ver(char *p, size_t len)
    735 {
    736   nghttp2_info *h2 = nghttp2_version(0);
    737   (void)msnprintf(p, len, "nghttp2/%s", h2->version_str);
    738 }
    739 
    740 static CURLcode nw_out_flush(struct Curl_cfilter *cf,
    741                              struct Curl_easy *data)
    742 {
    743   struct cf_h2_ctx *ctx = cf->ctx;
    744   size_t nwritten;
    745   CURLcode result;
    746 
    747   (void)data;
    748   if(Curl_bufq_is_empty(&ctx->outbufq))
    749     return CURLE_OK;
    750 
    751   result = Curl_cf_send_bufq(cf->next, data, &ctx->outbufq, NULL, 0,
    752                              &nwritten);
    753   if(result) {
    754     if(result == CURLE_AGAIN) {
    755       CURL_TRC_CF(data, cf, "flush nw send buffer(%zu) -> EAGAIN",
    756                   Curl_bufq_len(&ctx->outbufq));
    757       ctx->nw_out_blocked = 1;
    758     }
    759     return result;
    760   }
    761   return Curl_bufq_is_empty(&ctx->outbufq) ? CURLE_OK : CURLE_AGAIN;
    762 }
    763 
    764 /*
    765  * The implementation of nghttp2_send_callback type. Here we write |data| with
    766  * size |length| to the network and return the number of bytes actually
    767  * written. See the documentation of nghttp2_send_callback for the details.
    768  */
    769 static ssize_t send_callback(nghttp2_session *h2,
    770                              const uint8_t *buf, size_t blen, int flags,
    771                              void *userp)
    772 {
    773   struct Curl_cfilter *cf = userp;
    774   struct cf_h2_ctx *ctx = cf->ctx;
    775   struct Curl_easy *data = CF_DATA_CURRENT(cf);
    776   size_t nwritten;
    777   CURLcode result = CURLE_OK;
    778 
    779   (void)h2;
    780   (void)flags;
    781   DEBUGASSERT(data);
    782 
    783   if(!cf->connected)
    784     result = Curl_bufq_write(&ctx->outbufq, buf, blen, &nwritten);
    785   else
    786     result = Curl_cf_send_bufq(cf->next, data, &ctx->outbufq, buf, blen,
    787                                &nwritten);
    788 
    789   if(result) {
    790     if(result == CURLE_AGAIN) {
    791       ctx->nw_out_blocked = 1;
    792       return NGHTTP2_ERR_WOULDBLOCK;
    793     }
    794     failf(data, "Failed sending HTTP2 data");
    795     return NGHTTP2_ERR_CALLBACK_FAILURE;
    796   }
    797 
    798   if(!nwritten) {
    799     ctx->nw_out_blocked = 1;
    800     return NGHTTP2_ERR_WOULDBLOCK;
    801   }
    802   return (nwritten  > SSIZE_T_MAX) ?
    803     NGHTTP2_ERR_CALLBACK_FAILURE : (ssize_t)nwritten;
    804 }
    805 
    806 
    807 /* We pass a pointer to this struct in the push callback, but the contents of
    808    the struct are hidden from the user. */
    809 struct curl_pushheaders {
    810   struct Curl_easy *data;
    811   struct h2_stream_ctx *stream;
    812   const nghttp2_push_promise *frame;
    813 };
    814 
    815 /*
    816  * push header access function. Only to be used from within the push callback
    817  */
    818 char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
    819 {
    820   /* Verify that we got a good easy handle in the push header struct, mostly to
    821      detect rubbish input fast(er). */
    822   if(!h || !GOOD_EASY_HANDLE(h->data))
    823     return NULL;
    824   else {
    825     if(h->stream && num < h->stream->push_headers_used)
    826       return h->stream->push_headers[num];
    827   }
    828   return NULL;
    829 }
    830 
    831 /*
    832  * push header access function. Only to be used from within the push callback
    833  */
    834 char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
    835 {
    836   struct h2_stream_ctx *stream;
    837   size_t len;
    838   size_t i;
    839   /* Verify that we got a good easy handle in the push header struct,
    840      mostly to detect rubbish input fast(er). Also empty header name
    841      is just a rubbish too. We have to allow ":" at the beginning of
    842      the header, but header == ":" must be rejected. If we have ':' in
    843      the middle of header, it could be matched in middle of the value,
    844      this is because we do prefix match.*/
    845   if(!h || !GOOD_EASY_HANDLE(h->data) || !header || !header[0] ||
    846      !strcmp(header, ":") || strchr(header + 1, ':'))
    847     return NULL;
    848 
    849   stream = h->stream;
    850   if(!stream)
    851     return NULL;
    852 
    853   len = strlen(header);
    854   for(i = 0; i < stream->push_headers_used; i++) {
    855     if(!strncmp(header, stream->push_headers[i], len)) {
    856       /* sub-match, make sure that it is followed by a colon */
    857       if(stream->push_headers[i][len] != ':')
    858         continue;
    859       return &stream->push_headers[i][len + 1];
    860     }
    861   }
    862   return NULL;
    863 }
    864 
    865 static struct Curl_easy *h2_duphandle(struct Curl_cfilter *cf,
    866                                       struct Curl_easy *data)
    867 {
    868   struct Curl_easy *second = curl_easy_duphandle(data);
    869   if(second) {
    870     struct h2_stream_ctx *second_stream;
    871     http2_data_setup(cf, second, &second_stream);
    872     second->state.priority.weight = data->state.priority.weight;
    873   }
    874   return second;
    875 }
    876 
    877 static int set_transfer_url(struct Curl_easy *data,
    878                             struct curl_pushheaders *hp)
    879 {
    880   const char *v;
    881   CURLUcode uc;
    882   char *url = NULL;
    883   int rc = 0;
    884   CURLU *u = curl_url();
    885 
    886   if(!u)
    887     return 5;
    888 
    889   v = curl_pushheader_byname(hp, HTTP_PSEUDO_SCHEME);
    890   if(v) {
    891     uc = curl_url_set(u, CURLUPART_SCHEME, v, 0);
    892     if(uc) {
    893       rc = 1;
    894       goto fail;
    895     }
    896   }
    897 
    898   v = curl_pushheader_byname(hp, HTTP_PSEUDO_AUTHORITY);
    899   if(v) {
    900     uc = Curl_url_set_authority(u, v);
    901     if(uc) {
    902       rc = 2;
    903       goto fail;
    904     }
    905   }
    906 
    907   v = curl_pushheader_byname(hp, HTTP_PSEUDO_PATH);
    908   if(v) {
    909     uc = curl_url_set(u, CURLUPART_PATH, v, 0);
    910     if(uc) {
    911       rc = 3;
    912       goto fail;
    913     }
    914   }
    915 
    916   uc = curl_url_get(u, CURLUPART_URL, &url, 0);
    917   if(uc)
    918     rc = 4;
    919 fail:
    920   curl_url_cleanup(u);
    921   if(rc)
    922     return rc;
    923 
    924   if(data->state.url_alloc)
    925     free(data->state.url);
    926   data->state.url_alloc = TRUE;
    927   data->state.url = url;
    928   return 0;
    929 }
    930 
    931 static void discard_newhandle(struct Curl_cfilter *cf,
    932                               struct Curl_easy *newhandle)
    933 {
    934   http2_data_done(cf, newhandle);
    935   (void)Curl_close(&newhandle);
    936 }
    937 
    938 static int push_promise(struct Curl_cfilter *cf,
    939                         struct Curl_easy *data,
    940                         const nghttp2_push_promise *frame)
    941 {
    942   struct cf_h2_ctx *ctx = cf->ctx;
    943   int rv; /* one of the CURL_PUSH_* defines */
    944 
    945   CURL_TRC_CF(data, cf, "[%d] PUSH_PROMISE received",
    946               frame->promised_stream_id);
    947   if(data->multi->push_cb) {
    948     struct h2_stream_ctx *stream;
    949     struct h2_stream_ctx *newstream;
    950     struct curl_pushheaders heads;
    951     CURLMcode rc;
    952     CURLcode result;
    953     /* clone the parent */
    954     struct Curl_easy *newhandle = h2_duphandle(cf, data);
    955     if(!newhandle) {
    956       infof(data, "failed to duplicate handle");
    957       rv = CURL_PUSH_DENY; /* FAIL HARD */
    958       goto fail;
    959     }
    960 
    961     stream = H2_STREAM_CTX(ctx, data);
    962     if(!stream) {
    963       failf(data, "Internal NULL stream");
    964       discard_newhandle(cf, newhandle);
    965       rv = CURL_PUSH_DENY;
    966       goto fail;
    967     }
    968 
    969     heads.data = data;
    970     heads.stream = stream;
    971     heads.frame = frame;
    972 
    973     rv = set_transfer_url(newhandle, &heads);
    974     if(rv) {
    975       CURL_TRC_CF(data, cf, "[%d] PUSH_PROMISE, failed to set url -> %d",
    976                   frame->promised_stream_id, rv);
    977       discard_newhandle(cf, newhandle);
    978       rv = CURL_PUSH_DENY;
    979       goto fail;
    980     }
    981 
    982     Curl_set_in_callback(data, TRUE);
    983     rv = data->multi->push_cb(data, newhandle,
    984                               stream->push_headers_used, &heads,
    985                               data->multi->push_userp);
    986     Curl_set_in_callback(data, FALSE);
    987 
    988     /* free the headers again */
    989     free_push_headers(stream);
    990 
    991     if(rv) {
    992       DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT));
    993       /* denied, kill off the new handle again */
    994       CURL_TRC_CF(data, cf, "[%d] PUSH_PROMISE, denied by application -> %d",
    995                   frame->promised_stream_id, rv);
    996       discard_newhandle(cf, newhandle);
    997       goto fail;
    998     }
    999 
   1000     /* approved, add to the multi handle for processing. This
   1001      * assigns newhandle->mid. For the new `mid` we assign the
   1002      * h2_stream instance and remember the stream_id already known. */
   1003     rc = Curl_multi_add_perform(data->multi, newhandle, cf->conn);
   1004     if(rc) {
   1005       infof(data, "failed to add handle to multi");
   1006       discard_newhandle(cf, newhandle);
   1007       rv = CURL_PUSH_DENY;
   1008       goto fail;
   1009     }
   1010 
   1011     result = http2_data_setup(cf, newhandle, &newstream);
   1012     if(result) {
   1013       failf(data, "error setting up stream: %d", result);
   1014       discard_newhandle(cf, newhandle);
   1015       rv = CURL_PUSH_DENY;
   1016       goto fail;
   1017     }
   1018 
   1019     DEBUGASSERT(newstream);
   1020     newstream->id = frame->promised_stream_id;
   1021     newhandle->req.maxdownload = -1;
   1022     newhandle->req.size = -1;
   1023 
   1024     CURL_TRC_CF(data, cf, "promise easy handle added to multi, mid=%u",
   1025                 newhandle->mid);
   1026     rv = nghttp2_session_set_stream_user_data(ctx->h2,
   1027                                               newstream->id,
   1028                                               newhandle);
   1029     if(rv) {
   1030       infof(data, "failed to set user_data for stream %u",
   1031             newstream->id);
   1032       DEBUGASSERT(0);
   1033       rv = CURL_PUSH_DENY;
   1034       goto fail;
   1035     }
   1036 
   1037     /* success, remember max stream id processed */
   1038     if(newstream->id > ctx->local_max_sid)
   1039       ctx->local_max_sid = newstream->id;
   1040   }
   1041   else {
   1042     CURL_TRC_CF(data, cf, "Got PUSH_PROMISE, ignore it");
   1043     rv = CURL_PUSH_DENY;
   1044   }
   1045 fail:
   1046   return rv;
   1047 }
   1048 
   1049 static void h2_xfer_write_resp_hd(struct Curl_cfilter *cf,
   1050                                   struct Curl_easy *data,
   1051                                   struct h2_stream_ctx *stream,
   1052                                   const char *buf, size_t blen, bool eos)
   1053 {
   1054 
   1055   /* If we already encountered an error, skip further writes */
   1056   if(!stream->xfer_result) {
   1057     stream->xfer_result = Curl_xfer_write_resp_hd(data, buf, blen, eos);
   1058     if(!stream->xfer_result && !eos)
   1059       stream->xfer_result = cf_h2_update_local_win(cf, data, stream);
   1060     if(stream->xfer_result)
   1061       CURL_TRC_CF(data, cf, "[%d] error %d writing %zu bytes of headers",
   1062                   stream->id, stream->xfer_result, blen);
   1063   }
   1064 }
   1065 
   1066 static void h2_xfer_write_resp(struct Curl_cfilter *cf,
   1067                                struct Curl_easy *data,
   1068                                struct h2_stream_ctx *stream,
   1069                                const char *buf, size_t blen, bool eos)
   1070 {
   1071 
   1072   /* If we already encountered an error, skip further writes */
   1073   if(!stream->xfer_result)
   1074     stream->xfer_result = Curl_xfer_write_resp(data, buf, blen, eos);
   1075   /* If the transfer write is errored, we do not want any more data */
   1076   if(stream->xfer_result) {
   1077     struct cf_h2_ctx *ctx = cf->ctx;
   1078     CURL_TRC_CF(data, cf, "[%d] error %d writing %zu bytes of data, "
   1079                 "RST-ing stream",
   1080                 stream->id, stream->xfer_result, blen);
   1081     nghttp2_submit_rst_stream(ctx->h2, 0, stream->id,
   1082                               (uint32_t)NGHTTP2_ERR_CALLBACK_FAILURE);
   1083   }
   1084   else if(!stream->write_paused && Curl_xfer_write_is_paused(data)) {
   1085     CURL_TRC_CF(data, cf, "[%d] stream output paused", stream->id);
   1086     stream->write_paused = TRUE;
   1087   }
   1088   else if(stream->write_paused && !Curl_xfer_write_is_paused(data)) {
   1089     CURL_TRC_CF(data, cf, "[%d] stream output unpaused", stream->id);
   1090     stream->write_paused = FALSE;
   1091   }
   1092 
   1093   if(!stream->xfer_result && !eos)
   1094     stream->xfer_result = cf_h2_update_local_win(cf, data, stream);
   1095 }
   1096 
   1097 static CURLcode on_stream_frame(struct Curl_cfilter *cf,
   1098                                 struct Curl_easy *data,
   1099                                 const nghttp2_frame *frame)
   1100 {
   1101   struct cf_h2_ctx *ctx = cf->ctx;
   1102   struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
   1103   int32_t stream_id = frame->hd.stream_id;
   1104   int rv;
   1105 
   1106   if(!stream) {
   1107     CURL_TRC_CF(data, cf, "[%d] No stream_ctx set", stream_id);
   1108     return CURLE_FAILED_INIT;
   1109   }
   1110 
   1111   switch(frame->hd.type) {
   1112   case NGHTTP2_DATA:
   1113     CURL_TRC_CF(data, cf, "[%d] DATA, window=%d/%d",
   1114                 stream_id,
   1115                 nghttp2_session_get_stream_effective_recv_data_length(
   1116                   ctx->h2, stream->id),
   1117                 nghttp2_session_get_stream_effective_local_window_size(
   1118                   ctx->h2, stream->id));
   1119     /* If !body started on this stream, then receiving DATA is illegal. */
   1120     if(!stream->bodystarted) {
   1121       rv = nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
   1122                                      stream_id, NGHTTP2_PROTOCOL_ERROR);
   1123 
   1124       if(nghttp2_is_fatal(rv)) {
   1125         return CURLE_RECV_ERROR;
   1126       }
   1127     }
   1128     break;
   1129   case NGHTTP2_HEADERS:
   1130     if(stream->bodystarted) {
   1131       /* Only valid HEADERS after body started is trailer HEADERS. We
   1132          buffer them in on_header callback. */
   1133       break;
   1134     }
   1135 
   1136     /* nghttp2 guarantees that :status is received, and we store it to
   1137        stream->status_code. Fuzzing has proven this can still be reached
   1138        without status code having been set. */
   1139     if(stream->status_code == -1)
   1140       return CURLE_RECV_ERROR;
   1141 
   1142     /* Only final status code signals the end of header */
   1143     if(stream->status_code / 100 != 1)
   1144       stream->bodystarted = TRUE;
   1145     else
   1146       stream->status_code = -1;
   1147 
   1148     h2_xfer_write_resp_hd(cf, data, stream, STRCONST("\r\n"), stream->closed);
   1149 
   1150     if(stream->status_code / 100 != 1) {
   1151       stream->resp_hds_complete = TRUE;
   1152     }
   1153     Curl_multi_mark_dirty(data);
   1154     break;
   1155   case NGHTTP2_PUSH_PROMISE:
   1156     rv = push_promise(cf, data, &frame->push_promise);
   1157     if(rv) { /* deny! */
   1158       DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT));
   1159       rv = nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
   1160                                      frame->push_promise.promised_stream_id,
   1161                                      NGHTTP2_CANCEL);
   1162       if(nghttp2_is_fatal(rv))
   1163         return CURLE_SEND_ERROR;
   1164       else if(rv == CURL_PUSH_ERROROUT) {
   1165         CURL_TRC_CF(data, cf, "[%d] fail in PUSH_PROMISE received",
   1166                     stream_id);
   1167         return CURLE_RECV_ERROR;
   1168       }
   1169     }
   1170     break;
   1171   case NGHTTP2_RST_STREAM:
   1172     stream->closed = TRUE;
   1173     if(frame->rst_stream.error_code) {
   1174       stream->reset = TRUE;
   1175     }
   1176     Curl_multi_mark_dirty(data);
   1177     break;
   1178   case NGHTTP2_WINDOW_UPDATE:
   1179     if(CURL_WANT_SEND(data) && Curl_bufq_is_empty(&stream->sendbuf)) {
   1180       /* need more data, force processing of transfer */
   1181       Curl_multi_mark_dirty(data);
   1182     }
   1183     else if(!Curl_bufq_is_empty(&stream->sendbuf)) {
   1184       /* resume the potentially suspended stream */
   1185       rv = nghttp2_session_resume_data(ctx->h2, stream->id);
   1186       if(nghttp2_is_fatal(rv))
   1187         return CURLE_SEND_ERROR;
   1188     }
   1189     break;
   1190   default:
   1191     break;
   1192   }
   1193 
   1194   if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
   1195     if(!stream->closed && !stream->body_eos &&
   1196        ((stream->status_code >= 400) || (stream->status_code < 200))) {
   1197       /* The server did not give us a positive response and we are not
   1198        * done uploading the request body. We need to stop doing that and
   1199        * also inform the server that we aborted our side. */
   1200       CURL_TRC_CF(data, cf, "[%d] EOS frame with unfinished upload and "
   1201                   "HTTP status %d, abort upload by RST",
   1202                   stream_id, stream->status_code);
   1203       nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
   1204                                 stream->id, NGHTTP2_STREAM_CLOSED);
   1205       stream->closed = TRUE;
   1206     }
   1207     Curl_multi_mark_dirty(data);
   1208   }
   1209   return CURLE_OK;
   1210 }
   1211 
   1212 #ifndef CURL_DISABLE_VERBOSE_STRINGS
   1213 static int fr_print(const nghttp2_frame *frame, char *buffer, size_t blen)
   1214 {
   1215   switch(frame->hd.type) {
   1216     case NGHTTP2_DATA: {
   1217       return msnprintf(buffer, blen,
   1218                        "FRAME[DATA, len=%d, eos=%d, padlen=%d]",
   1219                        (int)frame->hd.length,
   1220                        !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM),
   1221                        (int)frame->data.padlen);
   1222     }
   1223     case NGHTTP2_HEADERS: {
   1224       return msnprintf(buffer, blen,
   1225                        "FRAME[HEADERS, len=%d, hend=%d, eos=%d]",
   1226                        (int)frame->hd.length,
   1227                        !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS),
   1228                        !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM));
   1229     }
   1230     case NGHTTP2_PRIORITY: {
   1231       return msnprintf(buffer, blen,
   1232                        "FRAME[PRIORITY, len=%d, flags=%d]",
   1233                        (int)frame->hd.length, frame->hd.flags);
   1234     }
   1235     case NGHTTP2_RST_STREAM: {
   1236       return msnprintf(buffer, blen,
   1237                        "FRAME[RST_STREAM, len=%d, flags=%d, error=%u]",
   1238                        (int)frame->hd.length, frame->hd.flags,
   1239                        frame->rst_stream.error_code);
   1240     }
   1241     case NGHTTP2_SETTINGS: {
   1242       if(frame->hd.flags & NGHTTP2_FLAG_ACK) {
   1243         return msnprintf(buffer, blen, "FRAME[SETTINGS, ack=1]");
   1244       }
   1245       return msnprintf(buffer, blen,
   1246                        "FRAME[SETTINGS, len=%d]", (int)frame->hd.length);
   1247     }
   1248     case NGHTTP2_PUSH_PROMISE: {
   1249       return msnprintf(buffer, blen,
   1250                        "FRAME[PUSH_PROMISE, len=%d, hend=%d]",
   1251                        (int)frame->hd.length,
   1252                        !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS));
   1253     }
   1254     case NGHTTP2_PING: {
   1255       return msnprintf(buffer, blen,
   1256                        "FRAME[PING, len=%d, ack=%d]",
   1257                        (int)frame->hd.length,
   1258                        frame->hd.flags&NGHTTP2_FLAG_ACK);
   1259     }
   1260     case NGHTTP2_GOAWAY: {
   1261       char scratch[128];
   1262       size_t s_len = CURL_ARRAYSIZE(scratch);
   1263       size_t len = (frame->goaway.opaque_data_len < s_len) ?
   1264         frame->goaway.opaque_data_len : s_len-1;
   1265       if(len)
   1266         memcpy(scratch, frame->goaway.opaque_data, len);
   1267       scratch[len] = '\0';
   1268       return msnprintf(buffer, blen, "FRAME[GOAWAY, error=%d, reason='%s', "
   1269                        "last_stream=%d]", frame->goaway.error_code,
   1270                        scratch, frame->goaway.last_stream_id);
   1271     }
   1272     case NGHTTP2_WINDOW_UPDATE: {
   1273       return msnprintf(buffer, blen,
   1274                        "FRAME[WINDOW_UPDATE, incr=%d]",
   1275                        frame->window_update.window_size_increment);
   1276     }
   1277     default:
   1278       return msnprintf(buffer, blen, "FRAME[%d, len=%d, flags=%d]",
   1279                        frame->hd.type, (int)frame->hd.length,
   1280                        frame->hd.flags);
   1281   }
   1282 }
   1283 
   1284 static int on_frame_send(nghttp2_session *session, const nghttp2_frame *frame,
   1285                          void *userp)
   1286 {
   1287   struct Curl_cfilter *cf = userp;
   1288   struct cf_h2_ctx *ctx = cf->ctx;
   1289   struct Curl_easy *data = CF_DATA_CURRENT(cf);
   1290 
   1291   (void)session;
   1292   DEBUGASSERT(data);
   1293   if(data && Curl_trc_cf_is_verbose(cf, data)) {
   1294     char buffer[256];
   1295     int len;
   1296     len = fr_print(frame, buffer, sizeof(buffer)-1);
   1297     buffer[len] = 0;
   1298     CURL_TRC_CF(data, cf, "[%d] -> %s", frame->hd.stream_id, buffer);
   1299   }
   1300   if((frame->hd.type == NGHTTP2_GOAWAY) && !ctx->sent_goaway) {
   1301     /* A GOAWAY not initiated by us, but by nghttp2 itself on detecting
   1302      * a protocol error on the connection */
   1303     failf(data, "nghttp2 shuts down connection with error %d: %s",
   1304           frame->goaway.error_code,
   1305           nghttp2_http2_strerror(frame->goaway.error_code));
   1306   }
   1307   return 0;
   1308 }
   1309 #endif /* !CURL_DISABLE_VERBOSE_STRINGS */
   1310 
   1311 static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
   1312                          void *userp)
   1313 {
   1314   struct Curl_cfilter *cf = userp;
   1315   struct cf_h2_ctx *ctx = cf->ctx;
   1316   struct Curl_easy *data = CF_DATA_CURRENT(cf), *data_s;
   1317   int32_t stream_id = frame->hd.stream_id;
   1318 
   1319   DEBUGASSERT(data);
   1320 #ifndef CURL_DISABLE_VERBOSE_STRINGS
   1321   if(Curl_trc_cf_is_verbose(cf, data)) {
   1322     char buffer[256];
   1323     int len;
   1324     len = fr_print(frame, buffer, sizeof(buffer)-1);
   1325     buffer[len] = 0;
   1326     CURL_TRC_CF(data, cf, "[%d] <- %s",frame->hd.stream_id, buffer);
   1327   }
   1328 #endif /* !CURL_DISABLE_VERBOSE_STRINGS */
   1329 
   1330   if(!stream_id) {
   1331     /* stream ID zero is for connection-oriented stuff */
   1332     DEBUGASSERT(data);
   1333     switch(frame->hd.type) {
   1334     case NGHTTP2_SETTINGS: {
   1335       if(!(frame->hd.flags & NGHTTP2_FLAG_ACK)) {
   1336         uint32_t max_conn = ctx->max_concurrent_streams;
   1337         ctx->max_concurrent_streams = nghttp2_session_get_remote_settings(
   1338             session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
   1339         ctx->enable_push = nghttp2_session_get_remote_settings(
   1340             session, NGHTTP2_SETTINGS_ENABLE_PUSH) != 0;
   1341         CURL_TRC_CF(data, cf, "[0] MAX_CONCURRENT_STREAMS: %d",
   1342                     ctx->max_concurrent_streams);
   1343         CURL_TRC_CF(data, cf, "[0] ENABLE_PUSH: %s",
   1344                     ctx->enable_push ? "TRUE" : "false");
   1345         if(data && max_conn != ctx->max_concurrent_streams) {
   1346           /* only signal change if the value actually changed */
   1347           CURL_TRC_CF(data, cf, "[0] notify MAX_CONCURRENT_STREAMS: %u",
   1348                       ctx->max_concurrent_streams);
   1349           Curl_multi_connchanged(data->multi);
   1350         }
   1351         /* Since the initial stream window is 64K, a request might be on HOLD,
   1352          * due to exhaustion. The (initial) SETTINGS may announce a much larger
   1353          * window and *assume* that we treat this like a WINDOW_UPDATE. Some
   1354          * servers send an explicit WINDOW_UPDATE, but not all seem to do that.
   1355          * To be safe, we UNHOLD a stream in order not to stall. */
   1356         if(CURL_WANT_SEND(data))
   1357           Curl_multi_mark_dirty(data);
   1358       }
   1359       break;
   1360     }
   1361     case NGHTTP2_GOAWAY:
   1362       ctx->rcvd_goaway = TRUE;
   1363       ctx->goaway_error = frame->goaway.error_code;
   1364       ctx->remote_max_sid = frame->goaway.last_stream_id;
   1365       if(data) {
   1366         infof(data, "received GOAWAY, error=%u, last_stream=%u",
   1367                     ctx->goaway_error, ctx->remote_max_sid);
   1368         Curl_multi_connchanged(data->multi);
   1369       }
   1370       break;
   1371     default:
   1372       break;
   1373     }
   1374     return 0;
   1375   }
   1376 
   1377   data_s = nghttp2_session_get_stream_user_data(session, stream_id);
   1378   if(!data_s) {
   1379     CURL_TRC_CF(data, cf, "[%d] No Curl_easy associated", stream_id);
   1380     return 0;
   1381   }
   1382 
   1383   return on_stream_frame(cf, data_s, frame) ? NGHTTP2_ERR_CALLBACK_FAILURE : 0;
   1384 }
   1385 
   1386 static int cf_h2_on_invalid_frame_recv(nghttp2_session *session,
   1387                                        const nghttp2_frame *frame,
   1388                                        int ngerr, void *userp)
   1389 {
   1390   struct Curl_cfilter *cf = userp;
   1391   struct cf_h2_ctx *ctx = cf->ctx;
   1392   struct Curl_easy *data;
   1393   int32_t stream_id = frame->hd.stream_id;
   1394 
   1395   data = nghttp2_session_get_stream_user_data(session, stream_id);
   1396   if(data) {
   1397     struct h2_stream_ctx *stream;
   1398 #ifndef CURL_DISABLE_VERBOSE_STRINGS
   1399     char buffer[256];
   1400     int len;
   1401     len = fr_print(frame, buffer, sizeof(buffer)-1);
   1402     buffer[len] = 0;
   1403     failf(data, "[HTTP2] [%d] received invalid frame: %s, error %d: %s",
   1404           stream_id, buffer, ngerr, nghttp2_strerror(ngerr));
   1405 #endif /* !CURL_DISABLE_VERBOSE_STRINGS */
   1406     stream = H2_STREAM_CTX(ctx, data);
   1407     if(stream) {
   1408       nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
   1409                                 stream->id, NGHTTP2_STREAM_CLOSED);
   1410       stream->error = ngerr;
   1411       stream->closed = TRUE;
   1412       stream->reset = TRUE;
   1413       return 0;  /* keep the connection alive */
   1414     }
   1415   }
   1416   return NGHTTP2_ERR_CALLBACK_FAILURE;
   1417 }
   1418 
   1419 static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
   1420                               int32_t stream_id,
   1421                               const uint8_t *mem, size_t len, void *userp)
   1422 {
   1423   struct Curl_cfilter *cf = userp;
   1424   struct cf_h2_ctx *ctx = cf->ctx;
   1425   struct h2_stream_ctx *stream;
   1426   struct Curl_easy *data_s;
   1427   (void)flags;
   1428 
   1429   DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
   1430   DEBUGASSERT(CF_DATA_CURRENT(cf));
   1431 
   1432   /* get the stream from the hash based on Stream ID */
   1433   data_s = nghttp2_session_get_stream_user_data(session, stream_id);
   1434   if(!data_s) {
   1435     /* Receiving a Stream ID not in the hash should not happen - unless
   1436        we have aborted a transfer artificially and there were more data
   1437        in the pipeline. Silently ignore. */
   1438     CURL_TRC_CF(CF_DATA_CURRENT(cf), cf, "[%d] Data for unknown",
   1439                 stream_id);
   1440     /* consumed explicitly as no one will read it */
   1441     nghttp2_session_consume(session, stream_id, len);
   1442     return 0;
   1443   }
   1444 
   1445   stream = H2_STREAM_CTX(ctx, data_s);
   1446   if(!stream)
   1447     return NGHTTP2_ERR_CALLBACK_FAILURE;
   1448 
   1449   h2_xfer_write_resp(cf, data_s, stream, (const char *)mem, len, FALSE);
   1450 
   1451   nghttp2_session_consume(ctx->h2, stream_id, len);
   1452   stream->nrcvd_data += (curl_off_t)len;
   1453   return 0;
   1454 }
   1455 
   1456 static int on_stream_close(nghttp2_session *session, int32_t stream_id,
   1457                            uint32_t error_code, void *userp)
   1458 {
   1459   struct Curl_cfilter *cf = userp;
   1460   struct cf_h2_ctx *ctx = cf->ctx;
   1461   struct Curl_easy *data_s, *call_data = CF_DATA_CURRENT(cf);
   1462   struct h2_stream_ctx *stream;
   1463   int rv;
   1464   (void)session;
   1465 
   1466   DEBUGASSERT(call_data);
   1467   /* stream id 0 is the connection, do not look there for streams. */
   1468   data_s = stream_id ?
   1469     nghttp2_session_get_stream_user_data(session, stream_id) : NULL;
   1470   if(!data_s) {
   1471     CURL_TRC_CF(call_data, cf,
   1472                 "[%d] on_stream_close, no easy set on stream", stream_id);
   1473     return 0;
   1474   }
   1475   if(!GOOD_EASY_HANDLE(data_s)) {
   1476     /* nghttp2 still has an easy registered for the stream which has
   1477      * been freed be libcurl. This points to a code path that does not
   1478      * trigger DONE or DETACH events as it must. */
   1479     CURL_TRC_CF(call_data, cf,
   1480                 "[%d] on_stream_close, not a GOOD easy on stream", stream_id);
   1481     (void)nghttp2_session_set_stream_user_data(session, stream_id, 0);
   1482     return NGHTTP2_ERR_CALLBACK_FAILURE;
   1483   }
   1484   stream = H2_STREAM_CTX(ctx, data_s);
   1485   if(!stream) {
   1486     CURL_TRC_CF(data_s, cf,
   1487                 "[%d] on_stream_close, GOOD easy but no stream", stream_id);
   1488     return NGHTTP2_ERR_CALLBACK_FAILURE;
   1489   }
   1490 
   1491   stream->closed = TRUE;
   1492   stream->error = error_code;
   1493   if(stream->error) {
   1494     stream->reset = TRUE;
   1495   }
   1496 
   1497   if(stream->error)
   1498     CURL_TRC_CF(data_s, cf, "[%d] RESET: %s (err %d)",
   1499               stream_id, nghttp2_http2_strerror(error_code), error_code);
   1500   else
   1501     CURL_TRC_CF(data_s, cf, "[%d] CLOSED", stream_id);
   1502   Curl_multi_mark_dirty(data_s);
   1503 
   1504   /* remove `data_s` from the nghttp2 stream */
   1505   rv = nghttp2_session_set_stream_user_data(session, stream_id, 0);
   1506   if(rv) {
   1507     infof(data_s, "http/2: failed to clear user_data for stream %u",
   1508           stream_id);
   1509     DEBUGASSERT(0);
   1510   }
   1511   return 0;
   1512 }
   1513 
   1514 static int on_begin_headers(nghttp2_session *session,
   1515                             const nghttp2_frame *frame, void *userp)
   1516 {
   1517   struct Curl_cfilter *cf = userp;
   1518   struct cf_h2_ctx *ctx = cf->ctx;
   1519   struct h2_stream_ctx *stream;
   1520   struct Curl_easy *data_s = NULL;
   1521 
   1522   (void)cf;
   1523   data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
   1524   if(!data_s) {
   1525     return 0;
   1526   }
   1527 
   1528   if(frame->hd.type != NGHTTP2_HEADERS) {
   1529     return 0;
   1530   }
   1531 
   1532   stream = H2_STREAM_CTX(ctx, data_s);
   1533   if(!stream || !stream->bodystarted) {
   1534     return 0;
   1535   }
   1536 
   1537   return 0;
   1538 }
   1539 
   1540 static void cf_h2_header_error(struct Curl_cfilter *cf,
   1541                                struct Curl_easy *data,
   1542                                struct h2_stream_ctx *stream,
   1543                                CURLcode result)
   1544 {
   1545   struct cf_h2_ctx *ctx = cf->ctx;
   1546 
   1547   failf(data, "Error receiving HTTP2 header: %d(%s)", result,
   1548         curl_easy_strerror(result));
   1549   if(stream) {
   1550     nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
   1551                               stream->id, NGHTTP2_STREAM_CLOSED);
   1552     stream->closed = TRUE;
   1553     stream->reset = TRUE;
   1554   }
   1555 }
   1556 
   1557 /* frame->hd.type is either NGHTTP2_HEADERS or NGHTTP2_PUSH_PROMISE */
   1558 static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
   1559                      const uint8_t *name, size_t namelen,
   1560                      const uint8_t *value, size_t valuelen,
   1561                      uint8_t flags,
   1562                      void *userp)
   1563 {
   1564   struct Curl_cfilter *cf = userp;
   1565   struct cf_h2_ctx *ctx = cf->ctx;
   1566   struct h2_stream_ctx *stream;
   1567   struct Curl_easy *data_s;
   1568   int32_t stream_id = frame->hd.stream_id;
   1569   CURLcode result;
   1570   (void)flags;
   1571 
   1572   DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
   1573 
   1574   /* get the stream from the hash based on Stream ID */
   1575   data_s = nghttp2_session_get_stream_user_data(session, stream_id);
   1576   if(!GOOD_EASY_HANDLE(data_s))
   1577     /* Receiving a Stream ID not in the hash should not happen, this is an
   1578        internal error more than anything else! */
   1579     return NGHTTP2_ERR_CALLBACK_FAILURE;
   1580 
   1581   stream = H2_STREAM_CTX(ctx, data_s);
   1582   if(!stream) {
   1583     failf(data_s, "Internal NULL stream");
   1584     return NGHTTP2_ERR_CALLBACK_FAILURE;
   1585   }
   1586 
   1587   /* Store received PUSH_PROMISE headers to be used when the subsequent
   1588      PUSH_PROMISE callback comes */
   1589   if(frame->hd.type == NGHTTP2_PUSH_PROMISE) {
   1590     char *h;
   1591 
   1592     if(!strcmp(HTTP_PSEUDO_AUTHORITY, (const char *)name)) {
   1593       /* pseudo headers are lower case */
   1594       int rc = 0;
   1595       char *check = aprintf("%s:%d", cf->conn->host.name,
   1596                             cf->conn->remote_port);
   1597       if(!check)
   1598         /* no memory */
   1599         return NGHTTP2_ERR_CALLBACK_FAILURE;
   1600       if(!curl_strequal(check, (const char *)value) &&
   1601          ((cf->conn->remote_port != cf->conn->given->defport) ||
   1602           !curl_strequal(cf->conn->host.name, (const char *)value))) {
   1603         /* This is push is not for the same authority that was asked for in
   1604          * the URL. RFC 7540 section 8.2 says: "A client MUST treat a
   1605          * PUSH_PROMISE for which the server is not authoritative as a stream
   1606          * error of type PROTOCOL_ERROR."
   1607          */
   1608         (void)nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
   1609                                         stream_id, NGHTTP2_PROTOCOL_ERROR);
   1610         rc = NGHTTP2_ERR_CALLBACK_FAILURE;
   1611       }
   1612       free(check);
   1613       if(rc)
   1614         return rc;
   1615     }
   1616 
   1617     if(!stream->push_headers) {
   1618       stream->push_headers_alloc = 10;
   1619       stream->push_headers = malloc(stream->push_headers_alloc *
   1620                                     sizeof(char *));
   1621       if(!stream->push_headers)
   1622         return NGHTTP2_ERR_CALLBACK_FAILURE;
   1623       stream->push_headers_used = 0;
   1624     }
   1625     else if(stream->push_headers_used ==
   1626             stream->push_headers_alloc) {
   1627       char **headp;
   1628       if(stream->push_headers_alloc > 1000) {
   1629         /* this is beyond crazy many headers, bail out */
   1630         failf(data_s, "Too many PUSH_PROMISE headers");
   1631         free_push_headers(stream);
   1632         return NGHTTP2_ERR_CALLBACK_FAILURE;
   1633       }
   1634       stream->push_headers_alloc *= 2;
   1635       headp = realloc(stream->push_headers,
   1636                       stream->push_headers_alloc * sizeof(char *));
   1637       if(!headp) {
   1638         free_push_headers(stream);
   1639         return NGHTTP2_ERR_CALLBACK_FAILURE;
   1640       }
   1641       stream->push_headers = headp;
   1642     }
   1643     h = aprintf("%s:%s", name, value);
   1644     if(h)
   1645       stream->push_headers[stream->push_headers_used++] = h;
   1646     return 0;
   1647   }
   1648 
   1649   if(stream->bodystarted) {
   1650     /* This is a trailer */
   1651     CURL_TRC_CF(data_s, cf, "[%d] trailer: %.*s: %.*s",
   1652                 stream->id, (int)namelen, name, (int)valuelen, value);
   1653     result = Curl_dynhds_add(&stream->resp_trailers,
   1654                              (const char *)name, namelen,
   1655                              (const char *)value, valuelen);
   1656     if(result) {
   1657       cf_h2_header_error(cf, data_s, stream, result);
   1658       return NGHTTP2_ERR_CALLBACK_FAILURE;
   1659     }
   1660 
   1661     return 0;
   1662   }
   1663 
   1664   if(namelen == sizeof(HTTP_PSEUDO_STATUS) - 1 &&
   1665      memcmp(HTTP_PSEUDO_STATUS, name, namelen) == 0) {
   1666     /* nghttp2 guarantees :status is received first and only once. */
   1667     char buffer[32];
   1668     result = Curl_http_decode_status(&stream->status_code,
   1669                                      (const char *)value, valuelen);
   1670     if(result) {
   1671       cf_h2_header_error(cf, data_s, stream, result);
   1672       return NGHTTP2_ERR_CALLBACK_FAILURE;
   1673     }
   1674     msnprintf(buffer, sizeof(buffer), HTTP_PSEUDO_STATUS ":%u\r",
   1675               stream->status_code);
   1676     result = Curl_headers_push(data_s, buffer, CURLH_PSEUDO);
   1677     if(result) {
   1678       cf_h2_header_error(cf, data_s, stream, result);
   1679       return NGHTTP2_ERR_CALLBACK_FAILURE;
   1680     }
   1681     curlx_dyn_reset(&ctx->scratch);
   1682     result = curlx_dyn_addn(&ctx->scratch, STRCONST("HTTP/2 "));
   1683     if(!result)
   1684       result = curlx_dyn_addn(&ctx->scratch, value, valuelen);
   1685     if(!result)
   1686       result = curlx_dyn_addn(&ctx->scratch, STRCONST(" \r\n"));
   1687     if(!result)
   1688       h2_xfer_write_resp_hd(cf, data_s, stream, curlx_dyn_ptr(&ctx->scratch),
   1689                             curlx_dyn_len(&ctx->scratch), FALSE);
   1690     if(result) {
   1691       cf_h2_header_error(cf, data_s, stream, result);
   1692       return NGHTTP2_ERR_CALLBACK_FAILURE;
   1693     }
   1694     /* if we receive data for another handle, wake that up */
   1695     if(CF_DATA_CURRENT(cf) != data_s)
   1696       Curl_multi_mark_dirty(data_s);
   1697 
   1698     CURL_TRC_CF(data_s, cf, "[%d] status: HTTP/2 %03d",
   1699                 stream->id, stream->status_code);
   1700     return 0;
   1701   }
   1702 
   1703   /* nghttp2 guarantees that namelen > 0, and :status was already
   1704      received, and this is not pseudo-header field . */
   1705   /* convert to an HTTP1-style header */
   1706   curlx_dyn_reset(&ctx->scratch);
   1707   result = curlx_dyn_addn(&ctx->scratch, (const char *)name, namelen);
   1708   if(!result)
   1709     result = curlx_dyn_addn(&ctx->scratch, STRCONST(": "));
   1710   if(!result)
   1711     result = curlx_dyn_addn(&ctx->scratch, (const char *)value, valuelen);
   1712   if(!result)
   1713     result = curlx_dyn_addn(&ctx->scratch, STRCONST("\r\n"));
   1714   if(!result)
   1715     h2_xfer_write_resp_hd(cf, data_s, stream, curlx_dyn_ptr(&ctx->scratch),
   1716                           curlx_dyn_len(&ctx->scratch), FALSE);
   1717   if(result) {
   1718     cf_h2_header_error(cf, data_s, stream, result);
   1719     return NGHTTP2_ERR_CALLBACK_FAILURE;
   1720   }
   1721   /* if we receive data for another handle, wake that up */
   1722   if(CF_DATA_CURRENT(cf) != data_s)
   1723     Curl_multi_mark_dirty(data_s);
   1724 
   1725   CURL_TRC_CF(data_s, cf, "[%d] header: %.*s: %.*s",
   1726               stream->id, (int)namelen, name, (int)valuelen, value);
   1727 
   1728   return 0; /* 0 is successful */
   1729 }
   1730 
   1731 static ssize_t req_body_read_callback(nghttp2_session *session,
   1732                                       int32_t stream_id,
   1733                                       uint8_t *buf, size_t length,
   1734                                       uint32_t *data_flags,
   1735                                       nghttp2_data_source *source,
   1736                                       void *userp)
   1737 {
   1738   struct Curl_cfilter *cf = userp;
   1739   struct cf_h2_ctx *ctx = cf->ctx;
   1740   struct Curl_easy *data_s;
   1741   struct h2_stream_ctx *stream = NULL;
   1742   CURLcode result;
   1743   ssize_t nread;
   1744   size_t n;
   1745   (void)source;
   1746 
   1747   (void)cf;
   1748   if(!stream_id)
   1749     return NGHTTP2_ERR_INVALID_ARGUMENT;
   1750 
   1751   /* get the stream from the hash based on Stream ID, stream ID zero is for
   1752      connection-oriented stuff */
   1753   data_s = nghttp2_session_get_stream_user_data(session, stream_id);
   1754   if(!data_s)
   1755     /* Receiving a Stream ID not in the hash should not happen, this is an
   1756        internal error more than anything else! */
   1757     return NGHTTP2_ERR_CALLBACK_FAILURE;
   1758 
   1759   stream = H2_STREAM_CTX(ctx, data_s);
   1760   if(!stream)
   1761     return NGHTTP2_ERR_CALLBACK_FAILURE;
   1762 
   1763   result = Curl_bufq_read(&stream->sendbuf, buf, length, &n);
   1764   if(result) {
   1765     if(result != CURLE_AGAIN)
   1766       return NGHTTP2_ERR_CALLBACK_FAILURE;
   1767     nread = 0;
   1768   }
   1769   else
   1770     nread = (ssize_t)n;
   1771 
   1772   CURL_TRC_CF(data_s, cf, "[%d] req_body_read(len=%zu) eos=%d -> %zd, %d",
   1773               stream_id, length, stream->body_eos, nread, result);
   1774 
   1775   if(stream->body_eos && Curl_bufq_is_empty(&stream->sendbuf)) {
   1776     *data_flags = NGHTTP2_DATA_FLAG_EOF;
   1777     return nread;
   1778   }
   1779   return (nread == 0) ? NGHTTP2_ERR_DEFERRED : nread;
   1780 }
   1781 
   1782 #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
   1783 static int error_callback(nghttp2_session *session,
   1784                           const char *msg,
   1785                           size_t len,
   1786                           void *userp)
   1787 {
   1788   struct Curl_cfilter *cf = userp;
   1789   struct Curl_easy *data = CF_DATA_CURRENT(cf);
   1790   (void)session;
   1791   failf(data, "%.*s", (int)len, msg);
   1792   return 0;
   1793 }
   1794 #endif
   1795 
   1796 /*
   1797  * Append headers to ask for an HTTP1.1 to HTTP2 upgrade.
   1798  */
   1799 CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
   1800                                     struct Curl_easy *data)
   1801 {
   1802   CURLcode result;
   1803   char *base64;
   1804   size_t blen;
   1805   struct SingleRequest *k = &data->req;
   1806   uint8_t binsettings[H2_BINSETTINGS_LEN];
   1807   ssize_t binlen; /* length of the binsettings data */
   1808 
   1809   binlen = populate_binsettings(binsettings, data);
   1810   if(binlen <= 0) {
   1811     failf(data, "nghttp2 unexpectedly failed on pack_settings_payload");
   1812     curlx_dyn_free(req);
   1813     return CURLE_FAILED_INIT;
   1814   }
   1815 
   1816   result = curlx_base64url_encode((const char *)binsettings, (size_t)binlen,
   1817                                   &base64, &blen);
   1818   if(result) {
   1819     curlx_dyn_free(req);
   1820     return result;
   1821   }
   1822 
   1823   result = curlx_dyn_addf(req,
   1824                           "Connection: Upgrade, HTTP2-Settings\r\n"
   1825                           "Upgrade: %s\r\n"
   1826                           "HTTP2-Settings: %s\r\n",
   1827                           NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64);
   1828   free(base64);
   1829 
   1830   k->upgr101 = UPGR101_H2;
   1831   data->conn->bits.asks_multiplex = TRUE;
   1832 
   1833   return result;
   1834 }
   1835 
   1836 static CURLcode http2_handle_stream_close(struct Curl_cfilter *cf,
   1837                                           struct Curl_easy *data,
   1838                                           struct h2_stream_ctx *stream,
   1839                                           size_t *pnlen)
   1840 {
   1841   CURLcode result;
   1842 
   1843   *pnlen = 0;
   1844   if(stream->error == NGHTTP2_REFUSED_STREAM) {
   1845     CURL_TRC_CF(data, cf, "[%d] REFUSED_STREAM, try again on a new "
   1846                 "connection", stream->id);
   1847     connclose(cf->conn, "REFUSED_STREAM"); /* do not use this anymore */
   1848     data->state.refused_stream = TRUE;
   1849     return CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
   1850   }
   1851   else if(stream->error != NGHTTP2_NO_ERROR) {
   1852     if(stream->resp_hds_complete && data->req.no_body) {
   1853       CURL_TRC_CF(data, cf, "[%d] error after response headers, but we did "
   1854                   "not want a body anyway, ignore: %s (err %u)",
   1855                   stream->id, nghttp2_http2_strerror(stream->error),
   1856                   stream->error);
   1857       stream->close_handled = TRUE;
   1858       return CURLE_OK;
   1859     }
   1860     failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %u)",
   1861           stream->id, nghttp2_http2_strerror(stream->error),
   1862           stream->error);
   1863     return CURLE_HTTP2_STREAM;
   1864   }
   1865   else if(stream->reset) {
   1866     failf(data, "HTTP/2 stream %u was reset", stream->id);
   1867     return data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP2;
   1868   }
   1869 
   1870   if(!stream->bodystarted) {
   1871     failf(data, "HTTP/2 stream %u was closed cleanly, but before getting "
   1872           " all response header fields, treated as error",
   1873           stream->id);
   1874     return CURLE_HTTP2_STREAM;
   1875   }
   1876 
   1877   if(Curl_dynhds_count(&stream->resp_trailers)) {
   1878     struct dynhds_entry *e;
   1879     struct dynbuf dbuf;
   1880     size_t i;
   1881 
   1882     result = CURLE_OK;
   1883     curlx_dyn_init(&dbuf, DYN_TRAILERS);
   1884     for(i = 0; i < Curl_dynhds_count(&stream->resp_trailers); ++i) {
   1885       e = Curl_dynhds_getn(&stream->resp_trailers, i);
   1886       if(!e)
   1887         break;
   1888       curlx_dyn_reset(&dbuf);
   1889       result = curlx_dyn_addf(&dbuf, "%.*s: %.*s\x0d\x0a",
   1890                             (int)e->namelen, e->name,
   1891                             (int)e->valuelen, e->value);
   1892       if(result)
   1893         break;
   1894       Curl_debug(data, CURLINFO_HEADER_IN, curlx_dyn_ptr(&dbuf),
   1895                  curlx_dyn_len(&dbuf));
   1896       result = Curl_client_write(data, CLIENTWRITE_HEADER|CLIENTWRITE_TRAILER,
   1897                                  curlx_dyn_ptr(&dbuf), curlx_dyn_len(&dbuf));
   1898       if(result)
   1899         break;
   1900     }
   1901     curlx_dyn_free(&dbuf);
   1902     if(result)
   1903       goto out;
   1904   }
   1905 
   1906   stream->close_handled = TRUE;
   1907   result = CURLE_OK;
   1908 
   1909 out:
   1910   CURL_TRC_CF(data, cf, "handle_stream_close -> %d, %zu", result, *pnlen);
   1911   return result;
   1912 }
   1913 
   1914 static int sweight_wanted(const struct Curl_easy *data)
   1915 {
   1916   /* 0 weight is not set by user and we take the nghttp2 default one */
   1917   return data->set.priority.weight ?
   1918     data->set.priority.weight : NGHTTP2_DEFAULT_WEIGHT;
   1919 }
   1920 
   1921 static int sweight_in_effect(const struct Curl_easy *data)
   1922 {
   1923   /* 0 weight is not set by user and we take the nghttp2 default one */
   1924   return data->state.priority.weight ?
   1925     data->state.priority.weight : NGHTTP2_DEFAULT_WEIGHT;
   1926 }
   1927 
   1928 /*
   1929  * h2_pri_spec() fills in the pri_spec struct, used by nghttp2 to send weight
   1930  * and dependency to the peer. It also stores the updated values in the state
   1931  * struct.
   1932  */
   1933 
   1934 static void h2_pri_spec(struct cf_h2_ctx *ctx,
   1935                         struct Curl_easy *data,
   1936                         nghttp2_priority_spec *pri_spec)
   1937 {
   1938   struct Curl_data_priority *prio = &data->set.priority;
   1939   struct h2_stream_ctx *depstream = H2_STREAM_CTX(ctx, prio->parent);
   1940   int32_t depstream_id = depstream ? depstream->id : 0;
   1941   nghttp2_priority_spec_init(pri_spec, depstream_id,
   1942                              sweight_wanted(data),
   1943                              data->set.priority.exclusive);
   1944   data->state.priority = *prio;
   1945 }
   1946 
   1947 /*
   1948  * Check if there is been an update in the priority /
   1949  * dependency settings and if so it submits a PRIORITY frame with the updated
   1950  * info.
   1951  * Flush any out data pending in the network buffer.
   1952  */
   1953 static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
   1954                                    struct Curl_easy *data)
   1955 {
   1956   struct cf_h2_ctx *ctx = cf->ctx;
   1957   struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
   1958   int rv = 0;
   1959 
   1960   if(stream && stream->id > 0 &&
   1961      ((sweight_wanted(data) != sweight_in_effect(data)) ||
   1962       (data->set.priority.exclusive != data->state.priority.exclusive) ||
   1963       (data->set.priority.parent != data->state.priority.parent)) ) {
   1964     /* send new weight and/or dependency */
   1965     nghttp2_priority_spec pri_spec;
   1966 
   1967     h2_pri_spec(ctx, data, &pri_spec);
   1968     CURL_TRC_CF(data, cf, "[%d] Queuing PRIORITY", stream->id);
   1969     DEBUGASSERT(stream->id != -1);
   1970     rv = nghttp2_submit_priority(ctx->h2, NGHTTP2_FLAG_NONE,
   1971                                  stream->id, &pri_spec);
   1972     if(rv)
   1973       goto out;
   1974   }
   1975 
   1976   ctx->nw_out_blocked = 0;
   1977   while(!rv && !ctx->nw_out_blocked && nghttp2_session_want_write(ctx->h2))
   1978     rv = nghttp2_session_send(ctx->h2);
   1979 
   1980 out:
   1981   if(nghttp2_is_fatal(rv)) {
   1982     CURL_TRC_CF(data, cf, "nghttp2_session_send error (%s)%d",
   1983                 nghttp2_strerror(rv), rv);
   1984     return CURLE_SEND_ERROR;
   1985   }
   1986   /* Defer flushing during the connect phase so that the SETTINGS and
   1987    * other initial frames are sent together with the first request.
   1988    * Unless we are 'connect_only' where the request will never come. */
   1989   if(!cf->connected && !cf->conn->connect_only)
   1990     return CURLE_OK;
   1991   return nw_out_flush(cf, data);
   1992 }
   1993 
   1994 static CURLcode stream_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
   1995                             struct h2_stream_ctx *stream,
   1996                             char *buf, size_t len, size_t *pnread)
   1997 {
   1998   struct cf_h2_ctx *ctx = cf->ctx;
   1999   CURLcode result = CURLE_AGAIN;
   2000 
   2001   (void)buf;
   2002   (void)len;
   2003   *pnread = 0;
   2004 
   2005   if(stream->xfer_result) {
   2006     CURL_TRC_CF(data, cf, "[%d] xfer write failed", stream->id);
   2007     result = stream->xfer_result;
   2008   }
   2009   else if(stream->closed) {
   2010     CURL_TRC_CF(data, cf, "[%d] returning CLOSE", stream->id);
   2011     result = http2_handle_stream_close(cf, data, stream, pnread);
   2012   }
   2013   else if(stream->reset ||
   2014           (ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) ||
   2015           (ctx->rcvd_goaway && ctx->remote_max_sid < stream->id)) {
   2016     CURL_TRC_CF(data, cf, "[%d] returning ERR", stream->id);
   2017     result = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP2;
   2018   }
   2019 
   2020   if(result && (result != CURLE_AGAIN))
   2021     CURL_TRC_CF(data, cf, "[%d] stream_recv(len=%zu) -> %d, %zu",
   2022                 stream->id, len, result, *pnread);
   2023   return result;
   2024 }
   2025 
   2026 static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
   2027                                     struct Curl_easy *data,
   2028                                     size_t data_max_bytes)
   2029 {
   2030   struct cf_h2_ctx *ctx = cf->ctx;
   2031   struct h2_stream_ctx *stream;
   2032   CURLcode result = CURLE_OK;
   2033   size_t nread;
   2034 
   2035   if(should_close_session(ctx)) {
   2036     CURL_TRC_CF(data, cf, "progress ingress, session is closed");
   2037     return CURLE_HTTP2;
   2038   }
   2039 
   2040   /* Process network input buffer fist */
   2041   if(!Curl_bufq_is_empty(&ctx->inbufq)) {
   2042     CURL_TRC_CF(data, cf, "Process %zu bytes in connection buffer",
   2043                 Curl_bufq_len(&ctx->inbufq));
   2044     if(h2_process_pending_input(cf, data, &result) < 0)
   2045       return result;
   2046   }
   2047 
   2048   /* Receive data from the "lower" filters, e.g. network until
   2049    * it is time to stop due to connection close or us not processing
   2050    * all network input */
   2051   while(!ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) {
   2052     stream = H2_STREAM_CTX(ctx, data);
   2053     if(stream && (stream->closed || !data_max_bytes)) {
   2054       /* We would like to abort here and stop processing, so that
   2055        * the transfer loop can handle the data/close here. However,
   2056        * this may leave data in underlying buffers that will not
   2057        * be consumed. */
   2058       if(!cf->next || !cf->next->cft->has_data_pending(cf->next, data))
   2059         Curl_multi_mark_dirty(data);
   2060       break;
   2061     }
   2062 
   2063     result = Curl_cf_recv_bufq(cf->next, data, &ctx->inbufq, 0, &nread);
   2064     if(result) {
   2065       if(result != CURLE_AGAIN) {
   2066         failf(data, "Failed receiving HTTP2 data: %d(%s)", result,
   2067               curl_easy_strerror(result));
   2068         return result;
   2069       }
   2070       break;
   2071     }
   2072     else if(nread == 0) {
   2073       CURL_TRC_CF(data, cf, "[0] ingress: connection closed");
   2074       ctx->conn_closed = TRUE;
   2075       break;
   2076     }
   2077     else {
   2078       CURL_TRC_CF(data, cf, "[0] ingress: read %zu bytes", nread);
   2079       data_max_bytes = (data_max_bytes > nread) ? (data_max_bytes - nread) : 0;
   2080     }
   2081 
   2082     if(h2_process_pending_input(cf, data, &result))
   2083       return result;
   2084     CURL_TRC_CF(data, cf, "[0] progress ingress: inbufg=%zu",
   2085                 Curl_bufq_len(&ctx->inbufq));
   2086   }
   2087 
   2088   if(ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) {
   2089     connclose(cf->conn, "GOAWAY received");
   2090   }
   2091 
   2092   CURL_TRC_CF(data, cf, "[0] progress ingress: done");
   2093   return CURLE_OK;
   2094 }
   2095 
   2096 static CURLcode cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
   2097                            char *buf, size_t len, size_t *pnread)
   2098 {
   2099   struct cf_h2_ctx *ctx = cf->ctx;
   2100   struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
   2101   CURLcode result, r2;
   2102   struct cf_call_data save;
   2103 
   2104   *pnread = 0;
   2105   if(!stream) {
   2106     /* Abnormal call sequence: either this transfer has never opened a stream
   2107      * (unlikely) or the transfer has been done, cleaned up its resources, but
   2108      * a read() is called anyway. It is not clear what the calling sequence
   2109      * is for such a case. */
   2110     failf(data, "http/2 recv on a transfer never opened "
   2111           "or already cleared, mid=%u", data->mid);
   2112     return CURLE_HTTP2;
   2113   }
   2114 
   2115   CF_DATA_SAVE(save, cf, data);
   2116 
   2117   result = stream_recv(cf, data, stream, buf, len, pnread);
   2118   if(result && (result != CURLE_AGAIN))
   2119     goto out;
   2120 
   2121   if(result) {
   2122     result = h2_progress_ingress(cf, data, len);
   2123     if(result)
   2124       goto out;
   2125 
   2126     result = stream_recv(cf, data, stream, buf, len, pnread);
   2127   }
   2128 
   2129   if(*pnread > 0) {
   2130     /* Now that we transferred this to the upper layer, we report
   2131      * the actual amount of DATA consumed to the H2 session, so
   2132      * that it adjusts stream flow control */
   2133     nghttp2_session_consume(ctx->h2, stream->id, *pnread);
   2134     if(stream->closed) {
   2135       CURL_TRC_CF(data, cf, "[%d] DRAIN closed stream", stream->id);
   2136       Curl_multi_mark_dirty(data);
   2137     }
   2138   }
   2139 
   2140 out:
   2141   r2 = h2_progress_egress(cf, data);
   2142   if(r2 == CURLE_AGAIN) {
   2143     /* pending data to send, need to be called again. Ideally, we
   2144      * monitor the socket for POLLOUT, but when not SENDING
   2145      * any more, we force processing of the transfer. */
   2146     if(!CURL_WANT_SEND(data))
   2147       Curl_multi_mark_dirty(data);
   2148   }
   2149   else if(r2) {
   2150     result = r2;
   2151   }
   2152   CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %d, %zu, "
   2153               "window=%d/%d, connection %d/%d",
   2154               stream->id, len, result, *pnread,
   2155               nghttp2_session_get_stream_effective_recv_data_length(
   2156                 ctx->h2, stream->id),
   2157               nghttp2_session_get_stream_effective_local_window_size(
   2158                 ctx->h2, stream->id),
   2159               nghttp2_session_get_local_window_size(ctx->h2),
   2160               HTTP2_HUGE_WINDOW_SIZE);
   2161 
   2162   CF_DATA_RESTORE(cf, save);
   2163   return result;
   2164 }
   2165 
   2166 static ssize_t cf_h2_body_send(struct Curl_cfilter *cf,
   2167                                struct Curl_easy *data,
   2168                                struct h2_stream_ctx *stream,
   2169                                const void *buf, size_t blen, bool eos,
   2170                                CURLcode *err)
   2171 {
   2172   struct cf_h2_ctx *ctx = cf->ctx;
   2173   size_t nwritten;
   2174 
   2175   if(stream->closed) {
   2176     if(stream->resp_hds_complete) {
   2177       /* Server decided to close the stream after having sent us a final
   2178        * response. This is valid if it is not interested in the request
   2179        * body. This happens on 30x or 40x responses.
   2180        * We silently discard the data sent, since this is not a transport
   2181        * error situation. */
   2182       CURL_TRC_CF(data, cf, "[%d] discarding data"
   2183                   "on closed stream with response", stream->id);
   2184       if(eos)
   2185         stream->body_eos = TRUE;
   2186       *err = CURLE_OK;
   2187       return (ssize_t)blen;
   2188     }
   2189     /* Server closed before we got a response, this is an error */
   2190     infof(data, "stream %u closed", stream->id);
   2191     *err = CURLE_SEND_ERROR;
   2192     return -1;
   2193   }
   2194 
   2195   *err = Curl_bufq_write(&stream->sendbuf, buf, blen, &nwritten);
   2196   if(*err)
   2197     return -1;
   2198 
   2199   if(eos && (blen == nwritten))
   2200     stream->body_eos = TRUE;
   2201 
   2202   if(eos || !Curl_bufq_is_empty(&stream->sendbuf)) {
   2203     /* resume the potentially suspended stream */
   2204     int rv = nghttp2_session_resume_data(ctx->h2, stream->id);
   2205     if(nghttp2_is_fatal(rv)) {
   2206       *err = CURLE_SEND_ERROR;
   2207       return -1;
   2208     }
   2209   }
   2210   return (ssize_t)nwritten;
   2211 }
   2212 
   2213 static CURLcode h2_submit(struct h2_stream_ctx **pstream,
   2214                           struct Curl_cfilter *cf, struct Curl_easy *data,
   2215                           const void *buf, size_t len,
   2216                           bool eos, size_t *pnwritten)
   2217 {
   2218   struct cf_h2_ctx *ctx = cf->ctx;
   2219   struct h2_stream_ctx *stream = NULL;
   2220   struct dynhds h2_headers;
   2221   nghttp2_nv *nva = NULL;
   2222   const void *body = NULL;
   2223   size_t nheader, bodylen, i;
   2224   nghttp2_data_provider data_prd;
   2225   int32_t stream_id;
   2226   nghttp2_priority_spec pri_spec;
   2227   ssize_t nwritten;
   2228   CURLcode result = CURLE_OK;
   2229 
   2230   *pnwritten = 0;
   2231   Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST);
   2232 
   2233   result = http2_data_setup(cf, data, &stream);
   2234   if(result)
   2235     goto out;
   2236 
   2237   nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, &result);
   2238   if(nwritten < 0)
   2239     goto out;
   2240   *pnwritten = (size_t)nwritten;
   2241   if(!stream->h1.done) {
   2242     /* need more data */
   2243     goto out;
   2244   }
   2245   DEBUGASSERT(stream->h1.req);
   2246 
   2247   result = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data);
   2248   if(result)
   2249     goto out;
   2250   /* no longer needed */
   2251   Curl_h1_req_parse_free(&stream->h1);
   2252 
   2253   nva = Curl_dynhds_to_nva(&h2_headers, &nheader);
   2254   if(!nva) {
   2255     result = CURLE_OUT_OF_MEMORY;
   2256     goto out;
   2257   }
   2258 
   2259   h2_pri_spec(ctx, data, &pri_spec);
   2260   if(!nghttp2_session_check_request_allowed(ctx->h2))
   2261     CURL_TRC_CF(data, cf, "send request NOT allowed (via nghttp2)");
   2262 
   2263   switch(data->state.httpreq) {
   2264   case HTTPREQ_POST:
   2265   case HTTPREQ_POST_FORM:
   2266   case HTTPREQ_POST_MIME:
   2267   case HTTPREQ_PUT:
   2268     data_prd.read_callback = req_body_read_callback;
   2269     data_prd.source.ptr = NULL;
   2270     stream_id = nghttp2_submit_request(ctx->h2, &pri_spec, nva, nheader,
   2271                                        &data_prd, data);
   2272     break;
   2273   default:
   2274     stream_id = nghttp2_submit_request(ctx->h2, &pri_spec, nva, nheader,
   2275                                        NULL, data);
   2276   }
   2277 
   2278   if(stream_id < 0) {
   2279     CURL_TRC_CF(data, cf, "send: nghttp2_submit_request error (%s)%u",
   2280                 nghttp2_strerror(stream_id), stream_id);
   2281     result = CURLE_SEND_ERROR;
   2282     goto out;
   2283   }
   2284 
   2285 #define MAX_ACC 60000  /* <64KB to account for some overhead */
   2286   if(Curl_trc_is_verbose(data)) {
   2287     size_t acc = 0;
   2288 
   2289     infof(data, "[HTTP/2] [%d] OPENED stream for %s",
   2290           stream_id, data->state.url);
   2291     for(i = 0; i < nheader; ++i) {
   2292       acc += nva[i].namelen + nva[i].valuelen;
   2293 
   2294       infof(data, "[HTTP/2] [%d] [%.*s: %.*s]", stream_id,
   2295             (int)nva[i].namelen, nva[i].name,
   2296             (int)nva[i].valuelen, nva[i].value);
   2297     }
   2298 
   2299     if(acc > MAX_ACC) {
   2300       infof(data, "[HTTP/2] Warning: The cumulative length of all "
   2301             "headers exceeds %d bytes and that could cause the "
   2302             "stream to be rejected.", MAX_ACC);
   2303     }
   2304   }
   2305 
   2306   stream->id = stream_id;
   2307 
   2308   body = (const char *)buf + *pnwritten;
   2309   bodylen = len - *pnwritten;
   2310 
   2311   if(bodylen || eos) {
   2312     ssize_t n = cf_h2_body_send(cf, data, stream, body, bodylen, eos, &result);
   2313     if(n >= 0)
   2314       *pnwritten += n;
   2315     else if(result == CURLE_AGAIN)
   2316       result = CURLE_OK;
   2317     else {
   2318       result = CURLE_SEND_ERROR;
   2319     }
   2320   }
   2321 
   2322 out:
   2323   CURL_TRC_CF(data, cf, "[%d] submit -> %d, %zu",
   2324               stream ? stream->id : -1, result, *pnwritten);
   2325   Curl_safefree(nva);
   2326   *pstream = stream;
   2327   Curl_dynhds_free(&h2_headers);
   2328   return result;
   2329 }
   2330 
   2331 static CURLcode cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
   2332                            const void *buf, size_t len, bool eos,
   2333                            size_t *pnwritten)
   2334 {
   2335   struct cf_h2_ctx *ctx = cf->ctx;
   2336   struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
   2337   struct cf_call_data save;
   2338   ssize_t nwritten;
   2339   CURLcode result = CURLE_OK, r2;
   2340 
   2341   CF_DATA_SAVE(save, cf, data);
   2342   *pnwritten = 0;
   2343 
   2344   if(!stream || stream->id == -1) {
   2345     result = h2_submit(&stream, cf, data, buf, len, eos, pnwritten);
   2346     if(result)
   2347       goto out;
   2348     DEBUGASSERT(stream);
   2349   }
   2350   else if(stream->body_eos) {
   2351     /* We already wrote this, but CURLE_AGAINed the call due to not
   2352      * being able to flush stream->sendbuf. Make a 0-length write
   2353      * to trigger flushing again.
   2354      * If this works, we report to have written `len` bytes. */
   2355     DEBUGASSERT(eos);
   2356     nwritten = cf_h2_body_send(cf, data, stream, buf, 0, eos, &result);
   2357     CURL_TRC_CF(data, cf, "[%d] cf_body_send last CHUNK -> %zd, %d, eos=%d",
   2358                 stream->id, nwritten, result, eos);
   2359     if(nwritten < 0) {
   2360       goto out;
   2361     }
   2362     *pnwritten = len;
   2363   }
   2364   else {
   2365     nwritten = cf_h2_body_send(cf, data, stream, buf, len, eos, &result);
   2366     CURL_TRC_CF(data, cf, "[%d] cf_body_send(len=%zu) -> %zd, %d, eos=%d",
   2367                 stream->id, len, nwritten, result, eos);
   2368     if(nwritten >= 0)
   2369       *pnwritten = (size_t)nwritten;
   2370   }
   2371 
   2372   /* Call the nghttp2 send loop and flush to write ALL buffered data,
   2373    * headers and/or request body completely out to the network */
   2374   r2 = h2_progress_egress(cf, data);
   2375 
   2376   /* if the stream has been closed in egress handling (nghttp2 does that
   2377    * when it does not like the headers, for example */
   2378   if(stream && stream->closed) {
   2379     infof(data, "stream %u closed", stream->id);
   2380     result = CURLE_SEND_ERROR;
   2381     goto out;
   2382   }
   2383   else if(r2 && (r2 != CURLE_AGAIN)) {
   2384     result = r2;
   2385     goto out;
   2386   }
   2387 
   2388   if(should_close_session(ctx)) {
   2389     /* nghttp2 thinks this session is done. If the stream has not been
   2390      * closed, this is an error state for out transfer */
   2391     if(stream && stream->closed) {
   2392       result = http2_handle_stream_close(cf, data, stream, pnwritten);
   2393     }
   2394     else {
   2395       CURL_TRC_CF(data, cf, "send: nothing to do in this session");
   2396       result = CURLE_HTTP2;
   2397     }
   2398   }
   2399 
   2400 out:
   2401   if(stream) {
   2402     CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) -> %d, %zu, "
   2403                 "eos=%d, h2 windows %d-%d (stream-conn), "
   2404                 "buffers %zu-%zu (stream-conn)",
   2405                 stream->id, len, result, *pnwritten,
   2406                 stream->body_eos,
   2407                 nghttp2_session_get_stream_remote_window_size(
   2408                   ctx->h2, stream->id),
   2409                 nghttp2_session_get_remote_window_size(ctx->h2),
   2410                 Curl_bufq_len(&stream->sendbuf),
   2411                 Curl_bufq_len(&ctx->outbufq));
   2412   }
   2413   else {
   2414     CURL_TRC_CF(data, cf, "cf_send(len=%zu) -> %d, %zu, "
   2415                 "connection-window=%d, nw_send_buffer(%zu)",
   2416                 len, result, *pnwritten,
   2417                 nghttp2_session_get_remote_window_size(ctx->h2),
   2418                 Curl_bufq_len(&ctx->outbufq));
   2419   }
   2420   CF_DATA_RESTORE(cf, save);
   2421   return result;
   2422 }
   2423 
   2424 static CURLcode cf_h2_flush(struct Curl_cfilter *cf,
   2425                             struct Curl_easy *data)
   2426 {
   2427   struct cf_h2_ctx *ctx = cf->ctx;
   2428   struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
   2429   struct cf_call_data save;
   2430   CURLcode result = CURLE_OK;
   2431 
   2432   CF_DATA_SAVE(save, cf, data);
   2433   if(stream && !Curl_bufq_is_empty(&stream->sendbuf)) {
   2434     /* resume the potentially suspended stream */
   2435     int rv = nghttp2_session_resume_data(ctx->h2, stream->id);
   2436     if(nghttp2_is_fatal(rv)) {
   2437       result = CURLE_SEND_ERROR;
   2438       goto out;
   2439     }
   2440   }
   2441 
   2442   result = h2_progress_egress(cf, data);
   2443 
   2444 out:
   2445   if(stream) {
   2446     CURL_TRC_CF(data, cf, "[%d] flush -> %d, "
   2447                 "h2 windows %d-%d (stream-conn), "
   2448                 "buffers %zu-%zu (stream-conn)",
   2449                 stream->id, result,
   2450                 nghttp2_session_get_stream_remote_window_size(
   2451                   ctx->h2, stream->id),
   2452                 nghttp2_session_get_remote_window_size(ctx->h2),
   2453                 Curl_bufq_len(&stream->sendbuf),
   2454                 Curl_bufq_len(&ctx->outbufq));
   2455   }
   2456   else {
   2457     CURL_TRC_CF(data, cf, "flush -> %d, "
   2458                 "connection-window=%d, nw_send_buffer(%zu)",
   2459                 result, nghttp2_session_get_remote_window_size(ctx->h2),
   2460                 Curl_bufq_len(&ctx->outbufq));
   2461   }
   2462   CF_DATA_RESTORE(cf, save);
   2463   return result;
   2464 }
   2465 
   2466 static void cf_h2_adjust_pollset(struct Curl_cfilter *cf,
   2467                                  struct Curl_easy *data,
   2468                                  struct easy_pollset *ps)
   2469 {
   2470   struct cf_h2_ctx *ctx = cf->ctx;
   2471   struct cf_call_data save;
   2472   curl_socket_t sock;
   2473   bool want_recv, want_send;
   2474 
   2475   if(!ctx->h2)
   2476     return;
   2477 
   2478   sock = Curl_conn_cf_get_socket(cf, data);
   2479   Curl_pollset_check(data, ps, sock, &want_recv, &want_send);
   2480   if(want_recv || want_send) {
   2481     struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
   2482     bool c_exhaust, s_exhaust;
   2483 
   2484     CF_DATA_SAVE(save, cf, data);
   2485     c_exhaust = want_send && !nghttp2_session_get_remote_window_size(ctx->h2);
   2486     s_exhaust = want_send && stream && stream->id >= 0 &&
   2487                 !nghttp2_session_get_stream_remote_window_size(ctx->h2,
   2488                                                                stream->id);
   2489     want_recv = (want_recv || c_exhaust || s_exhaust);
   2490     want_send = (!s_exhaust && want_send) ||
   2491                 (!c_exhaust && nghttp2_session_want_write(ctx->h2)) ||
   2492                 !Curl_bufq_is_empty(&ctx->outbufq);
   2493 
   2494     Curl_pollset_set(data, ps, sock, want_recv, want_send);
   2495     CF_DATA_RESTORE(cf, save);
   2496   }
   2497   else if(ctx->sent_goaway && !cf->shutdown) {
   2498     /* shutdown in progress */
   2499     CF_DATA_SAVE(save, cf, data);
   2500     want_send = nghttp2_session_want_write(ctx->h2) ||
   2501                 !Curl_bufq_is_empty(&ctx->outbufq);
   2502     want_recv = nghttp2_session_want_read(ctx->h2);
   2503     Curl_pollset_set(data, ps, sock, want_recv, want_send);
   2504     CF_DATA_RESTORE(cf, save);
   2505   }
   2506 }
   2507 
   2508 static CURLcode cf_h2_connect(struct Curl_cfilter *cf,
   2509                               struct Curl_easy *data,
   2510                               bool *done)
   2511 {
   2512   struct cf_h2_ctx *ctx = cf->ctx;
   2513   CURLcode result = CURLE_OK;
   2514   struct cf_call_data save;
   2515   bool first_time = FALSE;
   2516 
   2517   if(cf->connected) {
   2518     *done = TRUE;
   2519     return CURLE_OK;
   2520   }
   2521 
   2522   /* Connect the lower filters first */
   2523   if(!cf->next->connected) {
   2524     result = Curl_conn_cf_connect(cf->next, data, done);
   2525     if(result || !*done)
   2526       return result;
   2527   }
   2528 
   2529   *done = FALSE;
   2530 
   2531   CF_DATA_SAVE(save, cf, data);
   2532   DEBUGASSERT(ctx->initialized);
   2533   if(!ctx->h2) {
   2534     result = cf_h2_ctx_open(cf, data);
   2535     if(result)
   2536       goto out;
   2537     first_time = TRUE;
   2538   }
   2539 
   2540   if(!first_time) {
   2541     result = h2_progress_ingress(cf, data, H2_CHUNK_SIZE);
   2542     if(result)
   2543       goto out;
   2544   }
   2545 
   2546   /* Send out our SETTINGS and ACKs and such. If that blocks, we
   2547    * have it buffered and  can count this filter as being connected */
   2548   result = h2_progress_egress(cf, data);
   2549   if(result && (result != CURLE_AGAIN))
   2550     goto out;
   2551 
   2552   *done = TRUE;
   2553   cf->connected = TRUE;
   2554   result = CURLE_OK;
   2555 
   2556 out:
   2557   CURL_TRC_CF(data, cf, "cf_connect() -> %d, %d, ", result, *done);
   2558   CF_DATA_RESTORE(cf, save);
   2559   return result;
   2560 }
   2561 
   2562 static void cf_h2_close(struct Curl_cfilter *cf, struct Curl_easy *data)
   2563 {
   2564   struct cf_h2_ctx *ctx = cf->ctx;
   2565 
   2566   if(ctx) {
   2567     struct cf_call_data save;
   2568 
   2569     CF_DATA_SAVE(save, cf, data);
   2570     cf_h2_ctx_close(ctx);
   2571     CF_DATA_RESTORE(cf, save);
   2572     cf->connected = FALSE;
   2573   }
   2574   if(cf->next)
   2575     cf->next->cft->do_close(cf->next, data);
   2576 }
   2577 
   2578 static void cf_h2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
   2579 {
   2580   struct cf_h2_ctx *ctx = cf->ctx;
   2581 
   2582   (void)data;
   2583   if(ctx) {
   2584     cf_h2_ctx_free(ctx);
   2585     cf->ctx = NULL;
   2586   }
   2587 }
   2588 
   2589 static CURLcode cf_h2_shutdown(struct Curl_cfilter *cf,
   2590                                struct Curl_easy *data, bool *done)
   2591 {
   2592   struct cf_h2_ctx *ctx = cf->ctx;
   2593   struct cf_call_data save;
   2594   CURLcode result;
   2595   int rv;
   2596 
   2597   if(!cf->connected || !ctx->h2 || cf->shutdown || ctx->conn_closed) {
   2598     *done = TRUE;
   2599     return CURLE_OK;
   2600   }
   2601 
   2602   CF_DATA_SAVE(save, cf, data);
   2603 
   2604   if(!ctx->sent_goaway) {
   2605     ctx->sent_goaway = TRUE;
   2606     rv = nghttp2_submit_goaway(ctx->h2, NGHTTP2_FLAG_NONE,
   2607                                ctx->local_max_sid, 0,
   2608                                (const uint8_t *)"shutdown",
   2609                                sizeof("shutdown"));
   2610     if(rv) {
   2611       failf(data, "nghttp2_submit_goaway() failed: %s(%d)",
   2612             nghttp2_strerror(rv), rv);
   2613       result = CURLE_SEND_ERROR;
   2614       goto out;
   2615     }
   2616   }
   2617   /* GOAWAY submitted, process egress and ingress until nghttp2 is done. */
   2618   result = CURLE_OK;
   2619   if(nghttp2_session_want_write(ctx->h2) ||
   2620      !Curl_bufq_is_empty(&ctx->outbufq))
   2621     result = h2_progress_egress(cf, data);
   2622   if(!result && nghttp2_session_want_read(ctx->h2))
   2623     result = h2_progress_ingress(cf, data, 0);
   2624 
   2625   if(result == CURLE_AGAIN)
   2626     result = CURLE_OK;
   2627 
   2628   *done = (ctx->conn_closed ||
   2629            (!result && !nghttp2_session_want_write(ctx->h2) &&
   2630             !nghttp2_session_want_read(ctx->h2) &&
   2631             Curl_bufq_is_empty(&ctx->outbufq)));
   2632 
   2633 out:
   2634   CF_DATA_RESTORE(cf, save);
   2635   cf->shutdown = (result || *done);
   2636   return result;
   2637 }
   2638 
   2639 static CURLcode http2_data_pause(struct Curl_cfilter *cf,
   2640                                  struct Curl_easy *data,
   2641                                  bool pause)
   2642 {
   2643   struct cf_h2_ctx *ctx = cf->ctx;
   2644   struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
   2645 
   2646   DEBUGASSERT(data);
   2647   if(ctx && ctx->h2 && stream) {
   2648     CURLcode result;
   2649 
   2650     stream->write_paused = pause;
   2651     result = cf_h2_update_local_win(cf, data, stream);
   2652     if(result)
   2653       return result;
   2654 
   2655     /* attempt to send the window update */
   2656     (void)h2_progress_egress(cf, data);
   2657 
   2658     if(!pause) {
   2659       /* Unpausing a h2 transfer, requires it to be run again. The server
   2660        * may send new DATA on us increasing the flow window, and it may
   2661        * not. We may have already buffered and exhausted the new window
   2662        * by operating on things in flight during the handling of other
   2663        * transfers. */
   2664       Curl_multi_mark_dirty(data);
   2665     }
   2666     CURL_TRC_CF(data, cf, "[%d] stream now %spaused", stream->id,
   2667                 pause ? "" : "un");
   2668   }
   2669   return CURLE_OK;
   2670 }
   2671 
   2672 static CURLcode cf_h2_cntrl(struct Curl_cfilter *cf,
   2673                             struct Curl_easy *data,
   2674                             int event, int arg1, void *arg2)
   2675 {
   2676   CURLcode result = CURLE_OK;
   2677   struct cf_call_data save;
   2678 
   2679   (void)arg2;
   2680 
   2681   CF_DATA_SAVE(save, cf, data);
   2682   switch(event) {
   2683   case CF_CTRL_DATA_SETUP:
   2684     break;
   2685   case CF_CTRL_DATA_PAUSE:
   2686     result = http2_data_pause(cf, data, (arg1 != 0));
   2687     break;
   2688   case CF_CTRL_FLUSH:
   2689     result = cf_h2_flush(cf, data);
   2690     break;
   2691   case CF_CTRL_DATA_DONE:
   2692     http2_data_done(cf, data);
   2693     break;
   2694   default:
   2695     break;
   2696   }
   2697   CF_DATA_RESTORE(cf, save);
   2698   return result;
   2699 }
   2700 
   2701 static bool cf_h2_data_pending(struct Curl_cfilter *cf,
   2702                                const struct Curl_easy *data)
   2703 {
   2704   struct cf_h2_ctx *ctx = cf->ctx;
   2705 
   2706   if(ctx && !Curl_bufq_is_empty(&ctx->inbufq))
   2707     return TRUE;
   2708   return cf->next ? cf->next->cft->has_data_pending(cf->next, data) : FALSE;
   2709 }
   2710 
   2711 static bool cf_h2_is_alive(struct Curl_cfilter *cf,
   2712                            struct Curl_easy *data,
   2713                            bool *input_pending)
   2714 {
   2715   struct cf_h2_ctx *ctx = cf->ctx;
   2716   bool alive;
   2717   struct cf_call_data save;
   2718 
   2719   *input_pending = FALSE;
   2720   CF_DATA_SAVE(save, cf, data);
   2721   alive = (ctx && ctx->h2 && http2_connisalive(cf, data, input_pending));
   2722   CURL_TRC_CF(data, cf, "conn alive -> %d, input_pending=%d",
   2723               alive, *input_pending);
   2724   CF_DATA_RESTORE(cf, save);
   2725   return alive;
   2726 }
   2727 
   2728 static CURLcode cf_h2_keep_alive(struct Curl_cfilter *cf,
   2729                                  struct Curl_easy *data)
   2730 {
   2731   CURLcode result;
   2732   struct cf_call_data save;
   2733 
   2734   CF_DATA_SAVE(save, cf, data);
   2735   result = http2_send_ping(cf, data);
   2736   CF_DATA_RESTORE(cf, save);
   2737   return result;
   2738 }
   2739 
   2740 static CURLcode cf_h2_query(struct Curl_cfilter *cf,
   2741                             struct Curl_easy *data,
   2742                             int query, int *pres1, void *pres2)
   2743 {
   2744   struct cf_h2_ctx *ctx = cf->ctx;
   2745   struct cf_call_data save;
   2746   size_t effective_max;
   2747 
   2748   switch(query) {
   2749   case CF_QUERY_MAX_CONCURRENT:
   2750     DEBUGASSERT(pres1);
   2751 
   2752     CF_DATA_SAVE(save, cf, data);
   2753     if(!ctx->h2 || !nghttp2_session_check_request_allowed(ctx->h2)) {
   2754       /* the limit is what we have in use right now */
   2755       effective_max = CONN_ATTACHED(cf->conn);
   2756     }
   2757     else {
   2758       effective_max = ctx->max_concurrent_streams;
   2759     }
   2760     *pres1 = (effective_max > INT_MAX) ? INT_MAX : (int)effective_max;
   2761     CF_DATA_RESTORE(cf, save);
   2762     return CURLE_OK;
   2763   case CF_QUERY_STREAM_ERROR: {
   2764     struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
   2765     *pres1 = stream ? (int)stream->error : 0;
   2766     return CURLE_OK;
   2767   }
   2768   case CF_QUERY_NEED_FLUSH: {
   2769     struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
   2770     if(!Curl_bufq_is_empty(&ctx->outbufq) ||
   2771        (stream && !Curl_bufq_is_empty(&stream->sendbuf))) {
   2772       *pres1 = TRUE;
   2773       return CURLE_OK;
   2774     }
   2775     break;
   2776   }
   2777   case CF_QUERY_HTTP_VERSION:
   2778     *pres1 = 20;
   2779     return CURLE_OK;
   2780   default:
   2781     break;
   2782   }
   2783   return cf->next ?
   2784     cf->next->cft->query(cf->next, data, query, pres1, pres2) :
   2785     CURLE_UNKNOWN_OPTION;
   2786 }
   2787 
   2788 struct Curl_cftype Curl_cft_nghttp2 = {
   2789   "HTTP/2",
   2790   CF_TYPE_MULTIPLEX | CF_TYPE_HTTP,
   2791   CURL_LOG_LVL_NONE,
   2792   cf_h2_destroy,
   2793   cf_h2_connect,
   2794   cf_h2_close,
   2795   cf_h2_shutdown,
   2796   cf_h2_adjust_pollset,
   2797   cf_h2_data_pending,
   2798   cf_h2_send,
   2799   cf_h2_recv,
   2800   cf_h2_cntrl,
   2801   cf_h2_is_alive,
   2802   cf_h2_keep_alive,
   2803   cf_h2_query,
   2804 };
   2805 
   2806 static CURLcode http2_cfilter_add(struct Curl_cfilter **pcf,
   2807                                   struct Curl_easy *data,
   2808                                   struct connectdata *conn,
   2809                                   int sockindex,
   2810                                   bool via_h1_upgrade)
   2811 {
   2812   struct Curl_cfilter *cf = NULL;
   2813   struct cf_h2_ctx *ctx;
   2814   CURLcode result = CURLE_OUT_OF_MEMORY;
   2815 
   2816   DEBUGASSERT(data->conn);
   2817   ctx = calloc(1, sizeof(*ctx));
   2818   if(!ctx)
   2819     goto out;
   2820   cf_h2_ctx_init(ctx, via_h1_upgrade);
   2821 
   2822   result = Curl_cf_create(&cf, &Curl_cft_nghttp2, ctx);
   2823   if(result)
   2824     goto out;
   2825 
   2826   ctx = NULL;
   2827   Curl_conn_cf_add(data, conn, sockindex, cf);
   2828 
   2829 out:
   2830   if(result)
   2831     cf_h2_ctx_free(ctx);
   2832   *pcf = result ? NULL : cf;
   2833   return result;
   2834 }
   2835 
   2836 static CURLcode http2_cfilter_insert_after(struct Curl_cfilter *cf,
   2837                                            struct Curl_easy *data,
   2838                                            bool via_h1_upgrade)
   2839 {
   2840   struct Curl_cfilter *cf_h2 = NULL;
   2841   struct cf_h2_ctx *ctx;
   2842   CURLcode result = CURLE_OUT_OF_MEMORY;
   2843 
   2844   (void)data;
   2845   ctx = calloc(1, sizeof(*ctx));
   2846   if(!ctx)
   2847     goto out;
   2848   cf_h2_ctx_init(ctx, via_h1_upgrade);
   2849 
   2850   result = Curl_cf_create(&cf_h2, &Curl_cft_nghttp2, ctx);
   2851   if(result)
   2852     goto out;
   2853 
   2854   ctx = NULL;
   2855   Curl_conn_cf_insert_after(cf, cf_h2);
   2856 
   2857 out:
   2858   if(result)
   2859     cf_h2_ctx_free(ctx);
   2860   return result;
   2861 }
   2862 
   2863 bool Curl_http2_may_switch(struct Curl_easy *data)
   2864 {
   2865   if(Curl_conn_http_version(data, data->conn) < 20 &&
   2866      (data->state.http_neg.wanted & CURL_HTTP_V2x) &&
   2867      data->state.http_neg.h2_prior_knowledge) {
   2868 #ifndef CURL_DISABLE_PROXY
   2869     if(data->conn->bits.httpproxy && !data->conn->bits.tunnel_proxy) {
   2870       /* We do not support HTTP/2 proxies yet. Also it is debatable
   2871          whether or not this setting should apply to HTTP/2 proxies. */
   2872       infof(data, "Ignoring HTTP/2 prior knowledge due to proxy");
   2873       return FALSE;
   2874     }
   2875 #endif
   2876     return TRUE;
   2877   }
   2878   return FALSE;
   2879 }
   2880 
   2881 CURLcode Curl_http2_switch(struct Curl_easy *data)
   2882 {
   2883   struct Curl_cfilter *cf;
   2884   CURLcode result;
   2885 
   2886   DEBUGASSERT(Curl_conn_http_version(data, data->conn) < 20);
   2887 
   2888   result = http2_cfilter_add(&cf, data, data->conn, FIRSTSOCKET, FALSE);
   2889   if(result)
   2890     return result;
   2891   CURL_TRC_CF(data, cf, "switching connection to HTTP/2");
   2892 
   2893   data->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
   2894   Curl_multi_connchanged(data->multi);
   2895 
   2896   if(cf->next) {
   2897     bool done;
   2898     return Curl_conn_cf_connect(cf, data, &done);
   2899   }
   2900   return CURLE_OK;
   2901 }
   2902 
   2903 CURLcode Curl_http2_switch_at(struct Curl_cfilter *cf, struct Curl_easy *data)
   2904 {
   2905   struct Curl_cfilter *cf_h2;
   2906   CURLcode result;
   2907 
   2908   DEBUGASSERT(Curl_conn_http_version(data, data->conn) < 20);
   2909 
   2910   result = http2_cfilter_insert_after(cf, data, FALSE);
   2911   if(result)
   2912     return result;
   2913 
   2914   cf_h2 = cf->next;
   2915   cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
   2916   Curl_multi_connchanged(data->multi);
   2917 
   2918   if(cf_h2->next) {
   2919     bool done;
   2920     return Curl_conn_cf_connect(cf_h2, data, &done);
   2921   }
   2922   return CURLE_OK;
   2923 }
   2924 
   2925 CURLcode Curl_http2_upgrade(struct Curl_easy *data,
   2926                             struct connectdata *conn, int sockindex,
   2927                             const char *mem, size_t nread)
   2928 {
   2929   struct Curl_cfilter *cf;
   2930   struct cf_h2_ctx *ctx;
   2931   CURLcode result;
   2932 
   2933   DEBUGASSERT(Curl_conn_http_version(data, conn) <  20);
   2934   DEBUGASSERT(data->req.upgr101 == UPGR101_RECEIVED);
   2935 
   2936   result = http2_cfilter_add(&cf, data, conn, sockindex, TRUE);
   2937   if(result)
   2938     return result;
   2939   CURL_TRC_CF(data, cf, "upgrading connection to HTTP/2");
   2940 
   2941   DEBUGASSERT(cf->cft == &Curl_cft_nghttp2);
   2942   ctx = cf->ctx;
   2943 
   2944   if(nread > 0) {
   2945     /* Remaining data from the protocol switch reply is already using
   2946      * the switched protocol, ie. HTTP/2. We add that to the network
   2947      * inbufq. */
   2948     size_t copied;
   2949 
   2950     result = Curl_bufq_write(&ctx->inbufq,
   2951                              (const unsigned char *)mem, nread, &copied);
   2952     if(result) {
   2953       failf(data, "error on copying HTTP Upgrade response: %d", result);
   2954       return CURLE_RECV_ERROR;
   2955     }
   2956     if(copied < nread) {
   2957       failf(data, "connection buffer size could not take all data "
   2958             "from HTTP Upgrade response header: copied=%zu, datalen=%zu",
   2959             copied, nread);
   2960       return CURLE_HTTP2;
   2961     }
   2962     infof(data, "Copied HTTP/2 data in stream buffer to connection buffer"
   2963           " after upgrade: len=%zu", nread);
   2964   }
   2965 
   2966   conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
   2967   Curl_multi_connchanged(data->multi);
   2968 
   2969   if(cf->next) {
   2970     bool done;
   2971     return Curl_conn_cf_connect(cf, data, &done);
   2972   }
   2973   return CURLE_OK;
   2974 }
   2975 
   2976 /* Only call this function for a transfer that already got an HTTP/2
   2977    CURLE_HTTP2_STREAM error! */
   2978 bool Curl_h2_http_1_1_error(struct Curl_easy *data)
   2979 {
   2980   if(Curl_conn_http_version(data, data->conn) == 20) {
   2981     int err = Curl_conn_get_stream_error(data, data->conn, FIRSTSOCKET);
   2982     return err == NGHTTP2_HTTP_1_1_REQUIRED;
   2983   }
   2984   return FALSE;
   2985 }
   2986 
   2987 void *Curl_nghttp2_malloc(size_t size, void *user_data)
   2988 {
   2989   (void)user_data;
   2990   return Curl_cmalloc(size);
   2991 }
   2992 
   2993 void Curl_nghttp2_free(void *ptr, void *user_data)
   2994 {
   2995   (void)user_data;
   2996   Curl_cfree(ptr);
   2997 }
   2998 
   2999 void *Curl_nghttp2_calloc(size_t nmemb, size_t size, void *user_data)
   3000 {
   3001   (void)user_data;
   3002   return Curl_ccalloc(nmemb, size);
   3003 }
   3004 
   3005 void *Curl_nghttp2_realloc(void *ptr, size_t size, void *user_data)
   3006 {
   3007   (void)user_data;
   3008   return Curl_crealloc(ptr, size);
   3009 }
   3010 
   3011 #else /* !USE_NGHTTP2 */
   3012 
   3013 /* Satisfy external references even if http2 is not compiled in. */
   3014 #include <curl/curl.h>
   3015 
   3016 char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
   3017 {
   3018   (void) h;
   3019   (void) num;
   3020   return NULL;
   3021 }
   3022 
   3023 char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
   3024 {
   3025   (void) h;
   3026   (void) header;
   3027   return NULL;
   3028 }
   3029 
   3030 #endif /* USE_NGHTTP2 */