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