• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2021, 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  ***************************************************************************/
22 
23 #include "curl_setup.h"
24 
25 #ifdef USE_NGHTTP2
26 #include <nghttp2/nghttp2.h>
27 #include "urldata.h"
28 #include "http2.h"
29 #include "http.h"
30 #include "sendf.h"
31 #include "select.h"
32 #include "curl_base64.h"
33 #include "strcase.h"
34 #include "multiif.h"
35 #include "url.h"
36 #include "connect.h"
37 #include "strtoofft.h"
38 #include "strdup.h"
39 #include "dynbuf.h"
40 /* The last 3 #include files should be in this order */
41 #include "curl_printf.h"
42 #include "curl_memory.h"
43 #include "memdebug.h"
44 
45 #define H2_BUFSIZE 32768
46 
47 #if (NGHTTP2_VERSION_NUM < 0x010c00)
48 #error too old nghttp2 version, upgrade!
49 #endif
50 
51 #ifdef CURL_DISABLE_VERBOSE_STRINGS
52 #define nghttp2_session_callbacks_set_error_callback(x,y)
53 #endif
54 
55 #if (NGHTTP2_VERSION_NUM >= 0x010c00)
56 #define NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE 1
57 #endif
58 
59 #define HTTP2_HUGE_WINDOW_SIZE (32 * 1024 * 1024) /* 32 MB */
60 
61 #ifdef DEBUG_HTTP2
62 #define H2BUGF(x) x
63 #else
64 #define H2BUGF(x) do { } while(0)
65 #endif
66 
67 
68 static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
69                           char *mem, size_t len, CURLcode *err);
70 static bool http2_connisdead(struct Curl_easy *data,
71                              struct connectdata *conn);
72 static int h2_session_send(struct Curl_easy *data,
73                            nghttp2_session *h2);
74 static int h2_process_pending_input(struct Curl_easy *data,
75                                     struct http_conn *httpc,
76                                     CURLcode *err);
77 
78 /*
79  * Curl_http2_init_state() is called when the easy handle is created and
80  * allows for HTTP/2 specific init of state.
81  */
Curl_http2_init_state(struct UrlState * state)82 void Curl_http2_init_state(struct UrlState *state)
83 {
84   state->stream_weight = NGHTTP2_DEFAULT_WEIGHT;
85 }
86 
87 /*
88  * Curl_http2_init_userset() is called when the easy handle is created and
89  * allows for HTTP/2 specific user-set fields.
90  */
Curl_http2_init_userset(struct UserDefined * set)91 void Curl_http2_init_userset(struct UserDefined *set)
92 {
93   set->stream_weight = NGHTTP2_DEFAULT_WEIGHT;
94 }
95 
http2_getsock(struct Curl_easy * data,struct connectdata * conn,curl_socket_t * sock)96 static int http2_getsock(struct Curl_easy *data,
97                          struct connectdata *conn,
98                          curl_socket_t *sock)
99 {
100   const struct http_conn *c = &conn->proto.httpc;
101   struct SingleRequest *k = &data->req;
102   int bitmap = GETSOCK_BLANK;
103 
104   sock[0] = conn->sock[FIRSTSOCKET];
105 
106   if(!(k->keepon & KEEP_RECV_PAUSE))
107     /* Unless paused - in a HTTP/2 connection we can basically always get a
108        frame so we should always be ready for one */
109     bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
110 
111   /* we're still uploading or the HTTP/2 layer wants to send data */
112   if(((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND) ||
113      nghttp2_session_want_write(c->h2))
114     bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
115 
116   return bitmap;
117 }
118 
119 /*
120  * http2_stream_free() free HTTP2 stream related data
121  */
http2_stream_free(struct HTTP * http)122 static void http2_stream_free(struct HTTP *http)
123 {
124   if(http) {
125     Curl_dyn_free(&http->header_recvbuf);
126     for(; http->push_headers_used > 0; --http->push_headers_used) {
127       free(http->push_headers[http->push_headers_used - 1]);
128     }
129     free(http->push_headers);
130     http->push_headers = NULL;
131   }
132 }
133 
134 /*
135  * Disconnects *a* connection used for HTTP/2. It might be an old one from the
136  * connection cache and not the "main" one. Don't touch the easy handle!
137  */
138 
http2_disconnect(struct Curl_easy * data,struct connectdata * conn,bool dead_connection)139 static CURLcode http2_disconnect(struct Curl_easy *data,
140                                  struct connectdata *conn,
141                                  bool dead_connection)
142 {
143   struct http_conn *c = &conn->proto.httpc;
144   (void)dead_connection;
145 #ifndef DEBUG_HTTP2
146   (void)data;
147 #endif
148 
149   H2BUGF(infof(data, "HTTP/2 DISCONNECT starts now"));
150 
151   nghttp2_session_del(c->h2);
152   Curl_safefree(c->inbuf);
153 
154   H2BUGF(infof(data, "HTTP/2 DISCONNECT done"));
155 
156   return CURLE_OK;
157 }
158 
159 /*
160  * The server may send us data at any point (e.g. PING frames). Therefore,
161  * we cannot assume that an HTTP/2 socket is dead just because it is readable.
162  *
163  * Instead, if it is readable, run Curl_connalive() to peek at the socket
164  * and distinguish between closed and data.
165  */
http2_connisdead(struct Curl_easy * data,struct connectdata * conn)166 static bool http2_connisdead(struct Curl_easy *data, struct connectdata *conn)
167 {
168   int sval;
169   bool dead = TRUE;
170 
171   if(conn->bits.close)
172     return TRUE;
173 
174   sval = SOCKET_READABLE(conn->sock[FIRSTSOCKET], 0);
175   if(sval == 0) {
176     /* timeout */
177     dead = FALSE;
178   }
179   else if(sval & CURL_CSELECT_ERR) {
180     /* socket is in an error state */
181     dead = TRUE;
182   }
183   else if(sval & CURL_CSELECT_IN) {
184     /* readable with no error. could still be closed */
185     dead = !Curl_connalive(conn);
186     if(!dead) {
187       /* This happens before we've sent off a request and the connection is
188          not in use by any other transfer, there shouldn't be any data here,
189          only "protocol frames" */
190       CURLcode result;
191       struct http_conn *httpc = &conn->proto.httpc;
192       ssize_t nread = -1;
193       if(httpc->recv_underlying)
194         /* if called "too early", this pointer isn't setup yet! */
195         nread = ((Curl_recv *)httpc->recv_underlying)(
196           data, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result);
197       if(nread != -1) {
198         infof(data,
199               "%d bytes stray data read before trying h2 connection",
200               (int)nread);
201         httpc->nread_inbuf = 0;
202         httpc->inbuflen = nread;
203         if(h2_process_pending_input(data, httpc, &result) < 0)
204           /* immediate error, considered dead */
205           dead = TRUE;
206       }
207       else
208         /* the read failed so let's say this is dead anyway */
209         dead = TRUE;
210     }
211   }
212 
213   return dead;
214 }
215 
216 /*
217  * Set the transfer that is currently using this HTTP/2 connection.
218  */
set_transfer(struct http_conn * c,struct Curl_easy * data)219 static void set_transfer(struct http_conn *c,
220                          struct Curl_easy *data)
221 {
222   c->trnsfr = data;
223 }
224 
225 /*
226  * Get the transfer that is currently using this HTTP/2 connection.
227  */
get_transfer(struct http_conn * c)228 static struct Curl_easy *get_transfer(struct http_conn *c)
229 {
230   DEBUGASSERT(c && c->trnsfr);
231   return c->trnsfr;
232 }
233 
http2_conncheck(struct Curl_easy * data,struct connectdata * conn,unsigned int checks_to_perform)234 static unsigned int http2_conncheck(struct Curl_easy *data,
235                                     struct connectdata *conn,
236                                     unsigned int checks_to_perform)
237 {
238   unsigned int ret_val = CONNRESULT_NONE;
239   struct http_conn *c = &conn->proto.httpc;
240   int rc;
241   bool send_frames = false;
242 
243   if(checks_to_perform & CONNCHECK_ISDEAD) {
244     if(http2_connisdead(data, conn))
245       ret_val |= CONNRESULT_DEAD;
246   }
247 
248   if(checks_to_perform & CONNCHECK_KEEPALIVE) {
249     struct curltime now = Curl_now();
250     timediff_t elapsed = Curl_timediff(now, conn->keepalive);
251 
252     if(elapsed > data->set.upkeep_interval_ms) {
253       /* Perform an HTTP/2 PING */
254       rc = nghttp2_submit_ping(c->h2, 0, ZERO_NULL);
255       if(!rc) {
256         /* Successfully added a PING frame to the session. Need to flag this
257            so the frame is sent. */
258         send_frames = true;
259       }
260       else {
261        failf(data, "nghttp2_submit_ping() failed: %s(%d)",
262              nghttp2_strerror(rc), rc);
263       }
264 
265       conn->keepalive = now;
266     }
267   }
268 
269   if(send_frames) {
270     set_transfer(c, data); /* set the transfer */
271     rc = nghttp2_session_send(c->h2);
272     if(rc)
273       failf(data, "nghttp2_session_send() failed: %s(%d)",
274             nghttp2_strerror(rc), rc);
275   }
276 
277   return ret_val;
278 }
279 
280 /* called from http_setup_conn */
Curl_http2_setup_req(struct Curl_easy * data)281 void Curl_http2_setup_req(struct Curl_easy *data)
282 {
283   struct HTTP *http = data->req.p.http;
284   http->bodystarted = FALSE;
285   http->status_code = -1;
286   http->pausedata = NULL;
287   http->pauselen = 0;
288   http->closed = FALSE;
289   http->close_handled = FALSE;
290   http->mem = NULL;
291   http->len = 0;
292   http->memlen = 0;
293   http->error = NGHTTP2_NO_ERROR;
294 }
295 
296 /* called from http_setup_conn */
Curl_http2_setup_conn(struct connectdata * conn)297 void Curl_http2_setup_conn(struct connectdata *conn)
298 {
299   conn->proto.httpc.settings.max_concurrent_streams =
300     DEFAULT_MAX_CONCURRENT_STREAMS;
301 }
302 
303 /*
304  * HTTP2 handler interface. This isn't added to the general list of protocols
305  * but will be used at run-time when the protocol is dynamically switched from
306  * HTTP to HTTP2.
307  */
308 static const struct Curl_handler Curl_handler_http2 = {
309   "HTTP",                               /* scheme */
310   ZERO_NULL,                            /* setup_connection */
311   Curl_http,                            /* do_it */
312   Curl_http_done,                       /* done */
313   ZERO_NULL,                            /* do_more */
314   ZERO_NULL,                            /* connect_it */
315   ZERO_NULL,                            /* connecting */
316   ZERO_NULL,                            /* doing */
317   http2_getsock,                        /* proto_getsock */
318   http2_getsock,                        /* doing_getsock */
319   ZERO_NULL,                            /* domore_getsock */
320   http2_getsock,                        /* perform_getsock */
321   http2_disconnect,                     /* disconnect */
322   ZERO_NULL,                            /* readwrite */
323   http2_conncheck,                      /* connection_check */
324   ZERO_NULL,                            /* attach connection */
325   PORT_HTTP,                            /* defport */
326   CURLPROTO_HTTP,                       /* protocol */
327   CURLPROTO_HTTP,                       /* family */
328   PROTOPT_STREAM                        /* flags */
329 };
330 
331 static const struct Curl_handler Curl_handler_http2_ssl = {
332   "HTTPS",                              /* scheme */
333   ZERO_NULL,                            /* setup_connection */
334   Curl_http,                            /* do_it */
335   Curl_http_done,                       /* done */
336   ZERO_NULL,                            /* do_more */
337   ZERO_NULL,                            /* connect_it */
338   ZERO_NULL,                            /* connecting */
339   ZERO_NULL,                            /* doing */
340   http2_getsock,                        /* proto_getsock */
341   http2_getsock,                        /* doing_getsock */
342   ZERO_NULL,                            /* domore_getsock */
343   http2_getsock,                        /* perform_getsock */
344   http2_disconnect,                     /* disconnect */
345   ZERO_NULL,                            /* readwrite */
346   http2_conncheck,                      /* connection_check */
347   ZERO_NULL,                            /* attach connection */
348   PORT_HTTP,                            /* defport */
349   CURLPROTO_HTTPS,                      /* protocol */
350   CURLPROTO_HTTP,                       /* family */
351   PROTOPT_SSL | PROTOPT_STREAM          /* flags */
352 };
353 
354 /*
355  * Store nghttp2 version info in this buffer.
356  */
Curl_http2_ver(char * p,size_t len)357 void Curl_http2_ver(char *p, size_t len)
358 {
359   nghttp2_info *h2 = nghttp2_version(0);
360   (void)msnprintf(p, len, "nghttp2/%s", h2->version_str);
361 }
362 
363 /*
364  * The implementation of nghttp2_send_callback type. Here we write |data| with
365  * size |length| to the network and return the number of bytes actually
366  * written. See the documentation of nghttp2_send_callback for the details.
367  */
send_callback(nghttp2_session * h2,const uint8_t * mem,size_t length,int flags,void * userp)368 static ssize_t send_callback(nghttp2_session *h2,
369                              const uint8_t *mem, size_t length, int flags,
370                              void *userp)
371 {
372   struct connectdata *conn = (struct connectdata *)userp;
373   struct http_conn *c = &conn->proto.httpc;
374   struct Curl_easy *data = get_transfer(c);
375   ssize_t written;
376   CURLcode result = CURLE_OK;
377 
378   (void)h2;
379   (void)flags;
380 
381   if(!c->send_underlying)
382     /* called before setup properly! */
383     return NGHTTP2_ERR_CALLBACK_FAILURE;
384 
385   written = ((Curl_send*)c->send_underlying)(data, FIRSTSOCKET,
386                                              mem, length, &result);
387 
388   if(result == CURLE_AGAIN) {
389     return NGHTTP2_ERR_WOULDBLOCK;
390   }
391 
392   if(written == -1) {
393     failf(data, "Failed sending HTTP2 data");
394     return NGHTTP2_ERR_CALLBACK_FAILURE;
395   }
396 
397   if(!written)
398     return NGHTTP2_ERR_WOULDBLOCK;
399 
400   return written;
401 }
402 
403 
404 /* We pass a pointer to this struct in the push callback, but the contents of
405    the struct are hidden from the user. */
406 struct curl_pushheaders {
407   struct Curl_easy *data;
408   const nghttp2_push_promise *frame;
409 };
410 
411 /*
412  * push header access function. Only to be used from within the push callback
413  */
curl_pushheader_bynum(struct curl_pushheaders * h,size_t num)414 char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
415 {
416   /* Verify that we got a good easy handle in the push header struct, mostly to
417      detect rubbish input fast(er). */
418   if(!h || !GOOD_EASY_HANDLE(h->data))
419     return NULL;
420   else {
421     struct HTTP *stream = h->data->req.p.http;
422     if(num < stream->push_headers_used)
423       return stream->push_headers[num];
424   }
425   return NULL;
426 }
427 
428 /*
429  * push header access function. Only to be used from within the push callback
430  */
curl_pushheader_byname(struct curl_pushheaders * h,const char * header)431 char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
432 {
433   /* Verify that we got a good easy handle in the push header struct,
434      mostly to detect rubbish input fast(er). Also empty header name
435      is just a rubbish too. We have to allow ":" at the beginning of
436      the header, but header == ":" must be rejected. If we have ':' in
437      the middle of header, it could be matched in middle of the value,
438      this is because we do prefix match.*/
439   if(!h || !GOOD_EASY_HANDLE(h->data) || !header || !header[0] ||
440      !strcmp(header, ":") || strchr(header + 1, ':'))
441     return NULL;
442   else {
443     struct HTTP *stream = h->data->req.p.http;
444     size_t len = strlen(header);
445     size_t i;
446     for(i = 0; i<stream->push_headers_used; i++) {
447       if(!strncmp(header, stream->push_headers[i], len)) {
448         /* sub-match, make sure that it is followed by a colon */
449         if(stream->push_headers[i][len] != ':')
450           continue;
451         return &stream->push_headers[i][len + 1];
452       }
453     }
454   }
455   return NULL;
456 }
457 
458 /*
459  * This specific transfer on this connection has been "drained".
460  */
drained_transfer(struct Curl_easy * data,struct http_conn * httpc)461 static void drained_transfer(struct Curl_easy *data,
462                              struct http_conn *httpc)
463 {
464   DEBUGASSERT(httpc->drain_total >= data->state.drain);
465   httpc->drain_total -= data->state.drain;
466   data->state.drain = 0;
467 }
468 
469 /*
470  * Mark this transfer to get "drained".
471  */
drain_this(struct Curl_easy * data,struct http_conn * httpc)472 static void drain_this(struct Curl_easy *data,
473                        struct http_conn *httpc)
474 {
475   data->state.drain++;
476   httpc->drain_total++;
477   DEBUGASSERT(httpc->drain_total >= data->state.drain);
478 }
479 
duphandle(struct Curl_easy * data)480 static struct Curl_easy *duphandle(struct Curl_easy *data)
481 {
482   struct Curl_easy *second = curl_easy_duphandle(data);
483   if(second) {
484     /* setup the request struct */
485     struct HTTP *http = calloc(1, sizeof(struct HTTP));
486     if(!http) {
487       (void)Curl_close(&second);
488     }
489     else {
490       second->req.p.http = http;
491       Curl_dyn_init(&http->header_recvbuf, DYN_H2_HEADERS);
492       Curl_http2_setup_req(second);
493       second->state.stream_weight = data->state.stream_weight;
494     }
495   }
496   return second;
497 }
498 
set_transfer_url(struct Curl_easy * data,struct curl_pushheaders * hp)499 static int set_transfer_url(struct Curl_easy *data,
500                             struct curl_pushheaders *hp)
501 {
502   const char *v;
503   CURLU *u = curl_url();
504   CURLUcode uc;
505   char *url = NULL;
506   int rc = 0;
507 
508   v = curl_pushheader_byname(hp, ":scheme");
509   if(v) {
510     uc = curl_url_set(u, CURLUPART_SCHEME, v, 0);
511     if(uc) {
512       rc = 1;
513       goto fail;
514     }
515   }
516 
517   v = curl_pushheader_byname(hp, ":authority");
518   if(v) {
519     uc = curl_url_set(u, CURLUPART_HOST, v, 0);
520     if(uc) {
521       rc = 2;
522       goto fail;
523     }
524   }
525 
526   v = curl_pushheader_byname(hp, ":path");
527   if(v) {
528     uc = curl_url_set(u, CURLUPART_PATH, v, 0);
529     if(uc) {
530       rc = 3;
531       goto fail;
532     }
533   }
534 
535   uc = curl_url_get(u, CURLUPART_URL, &url, 0);
536   if(uc)
537     rc = 4;
538   fail:
539   curl_url_cleanup(u);
540   if(rc)
541     return rc;
542 
543   if(data->state.url_alloc)
544     free(data->state.url);
545   data->state.url_alloc = TRUE;
546   data->state.url = url;
547   return 0;
548 }
549 
push_promise(struct Curl_easy * data,struct connectdata * conn,const nghttp2_push_promise * frame)550 static int push_promise(struct Curl_easy *data,
551                         struct connectdata *conn,
552                         const nghttp2_push_promise *frame)
553 {
554   int rv; /* one of the CURL_PUSH_* defines */
555   H2BUGF(infof(data, "PUSH_PROMISE received, stream %u!",
556                frame->promised_stream_id));
557   if(data->multi->push_cb) {
558     struct HTTP *stream;
559     struct HTTP *newstream;
560     struct curl_pushheaders heads;
561     CURLMcode rc;
562     struct http_conn *httpc;
563     size_t i;
564     /* clone the parent */
565     struct Curl_easy *newhandle = duphandle(data);
566     if(!newhandle) {
567       infof(data, "failed to duplicate handle");
568       rv = CURL_PUSH_DENY; /* FAIL HARD */
569       goto fail;
570     }
571 
572     heads.data = data;
573     heads.frame = frame;
574     /* ask the application */
575     H2BUGF(infof(data, "Got PUSH_PROMISE, ask application!"));
576 
577     stream = data->req.p.http;
578     if(!stream) {
579       failf(data, "Internal NULL stream!");
580       (void)Curl_close(&newhandle);
581       rv = CURL_PUSH_DENY;
582       goto fail;
583     }
584 
585     rv = set_transfer_url(newhandle, &heads);
586     if(rv) {
587       (void)Curl_close(&newhandle);
588       rv = CURL_PUSH_DENY;
589       goto fail;
590     }
591 
592     Curl_set_in_callback(data, true);
593     rv = data->multi->push_cb(data, newhandle,
594                               stream->push_headers_used, &heads,
595                               data->multi->push_userp);
596     Curl_set_in_callback(data, false);
597 
598     /* free the headers again */
599     for(i = 0; i<stream->push_headers_used; i++)
600       free(stream->push_headers[i]);
601     free(stream->push_headers);
602     stream->push_headers = NULL;
603     stream->push_headers_used = 0;
604 
605     if(rv) {
606       DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT));
607       /* denied, kill off the new handle again */
608       http2_stream_free(newhandle->req.p.http);
609       newhandle->req.p.http = NULL;
610       (void)Curl_close(&newhandle);
611       goto fail;
612     }
613 
614     newstream = newhandle->req.p.http;
615     newstream->stream_id = frame->promised_stream_id;
616     newhandle->req.maxdownload = -1;
617     newhandle->req.size = -1;
618 
619     /* approved, add to the multi handle and immediately switch to PERFORM
620        state with the given connection !*/
621     rc = Curl_multi_add_perform(data->multi, newhandle, conn);
622     if(rc) {
623       infof(data, "failed to add handle to multi");
624       http2_stream_free(newhandle->req.p.http);
625       newhandle->req.p.http = NULL;
626       Curl_close(&newhandle);
627       rv = CURL_PUSH_DENY;
628       goto fail;
629     }
630 
631     httpc = &conn->proto.httpc;
632     rv = nghttp2_session_set_stream_user_data(httpc->h2,
633                                               frame->promised_stream_id,
634                                               newhandle);
635     if(rv) {
636       infof(data, "failed to set user_data for stream %d",
637             frame->promised_stream_id);
638       DEBUGASSERT(0);
639       rv = CURL_PUSH_DENY;
640       goto fail;
641     }
642     Curl_dyn_init(&newstream->header_recvbuf, DYN_H2_HEADERS);
643     Curl_dyn_init(&newstream->trailer_recvbuf, DYN_H2_TRAILERS);
644   }
645   else {
646     H2BUGF(infof(data, "Got PUSH_PROMISE, ignore it!"));
647     rv = CURL_PUSH_DENY;
648   }
649   fail:
650   return rv;
651 }
652 
653 /*
654  * multi_connchanged() is called to tell that there is a connection in
655  * this multi handle that has changed state (multiplexing become possible, the
656  * number of allowed streams changed or similar), and a subsequent use of this
657  * multi handle should move CONNECT_PEND handles back to CONNECT to have them
658  * retry.
659  */
multi_connchanged(struct Curl_multi * multi)660 static void multi_connchanged(struct Curl_multi *multi)
661 {
662   multi->recheckstate = TRUE;
663 }
664 
on_frame_recv(nghttp2_session * session,const nghttp2_frame * frame,void * userp)665 static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
666                          void *userp)
667 {
668   struct connectdata *conn = (struct connectdata *)userp;
669   struct http_conn *httpc = &conn->proto.httpc;
670   struct Curl_easy *data_s = NULL;
671   struct HTTP *stream = NULL;
672   struct Curl_easy *data = get_transfer(httpc);
673   int rv;
674   size_t left, ncopy;
675   int32_t stream_id = frame->hd.stream_id;
676   CURLcode result;
677 
678   if(!stream_id) {
679     /* stream ID zero is for connection-oriented stuff */
680     if(frame->hd.type == NGHTTP2_SETTINGS) {
681       uint32_t max_conn = httpc->settings.max_concurrent_streams;
682       H2BUGF(infof(data, "Got SETTINGS"));
683       httpc->settings.max_concurrent_streams =
684         nghttp2_session_get_remote_settings(
685           session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
686       httpc->settings.enable_push =
687         nghttp2_session_get_remote_settings(
688           session, NGHTTP2_SETTINGS_ENABLE_PUSH);
689       H2BUGF(infof(data, "MAX_CONCURRENT_STREAMS == %d",
690                    httpc->settings.max_concurrent_streams));
691       H2BUGF(infof(data, "ENABLE_PUSH == %s",
692                    httpc->settings.enable_push?"TRUE":"false"));
693       if(max_conn != httpc->settings.max_concurrent_streams) {
694         /* only signal change if the value actually changed */
695         infof(data,
696               "Connection state changed (MAX_CONCURRENT_STREAMS == %u)!",
697               httpc->settings.max_concurrent_streams);
698         multi_connchanged(data->multi);
699       }
700     }
701     return 0;
702   }
703   data_s = nghttp2_session_get_stream_user_data(session, stream_id);
704   if(!data_s) {
705     H2BUGF(infof(data,
706                  "No Curl_easy associated with stream: %x",
707                  stream_id));
708     return 0;
709   }
710 
711   stream = data_s->req.p.http;
712   if(!stream) {
713     H2BUGF(infof(data_s, "No proto pointer for stream: %x",
714                  stream_id));
715     return NGHTTP2_ERR_CALLBACK_FAILURE;
716   }
717 
718   H2BUGF(infof(data_s, "on_frame_recv() header %x stream %x",
719                frame->hd.type, stream_id));
720 
721   switch(frame->hd.type) {
722   case NGHTTP2_DATA:
723     /* If body started on this stream, then receiving DATA is illegal. */
724     if(!stream->bodystarted) {
725       rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
726                                      stream_id, NGHTTP2_PROTOCOL_ERROR);
727 
728       if(nghttp2_is_fatal(rv)) {
729         return NGHTTP2_ERR_CALLBACK_FAILURE;
730       }
731     }
732     break;
733   case NGHTTP2_HEADERS:
734     if(stream->bodystarted) {
735       /* Only valid HEADERS after body started is trailer HEADERS.  We
736          buffer them in on_header callback. */
737       break;
738     }
739 
740     /* nghttp2 guarantees that :status is received, and we store it to
741        stream->status_code. Fuzzing has proven this can still be reached
742        without status code having been set. */
743     if(stream->status_code == -1)
744       return NGHTTP2_ERR_CALLBACK_FAILURE;
745 
746     /* Only final status code signals the end of header */
747     if(stream->status_code / 100 != 1) {
748       stream->bodystarted = TRUE;
749       stream->status_code = -1;
750     }
751 
752     result = Curl_dyn_add(&stream->header_recvbuf, "\r\n");
753     if(result)
754       return NGHTTP2_ERR_CALLBACK_FAILURE;
755 
756     left = Curl_dyn_len(&stream->header_recvbuf) -
757       stream->nread_header_recvbuf;
758     ncopy = CURLMIN(stream->len, left);
759 
760     memcpy(&stream->mem[stream->memlen],
761            Curl_dyn_ptr(&stream->header_recvbuf) +
762            stream->nread_header_recvbuf,
763            ncopy);
764     stream->nread_header_recvbuf += ncopy;
765 
766     H2BUGF(infof(data_s, "Store %zu bytes headers from stream %u at %p",
767                  ncopy, stream_id, stream->mem));
768 
769     stream->len -= ncopy;
770     stream->memlen += ncopy;
771 
772     drain_this(data_s, httpc);
773     /* if we receive data for another handle, wake that up */
774     if(get_transfer(httpc) != data_s)
775       Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
776     break;
777   case NGHTTP2_PUSH_PROMISE:
778     rv = push_promise(data_s, conn, &frame->push_promise);
779     if(rv) { /* deny! */
780       int h2;
781       DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT));
782       h2 = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
783                                      frame->push_promise.promised_stream_id,
784                                      NGHTTP2_CANCEL);
785       if(nghttp2_is_fatal(h2))
786         return NGHTTP2_ERR_CALLBACK_FAILURE;
787       else if(rv == CURL_PUSH_ERROROUT) {
788         DEBUGF(infof(data_s, "Fail the parent stream (too)"));
789         return NGHTTP2_ERR_CALLBACK_FAILURE;
790       }
791     }
792     break;
793   default:
794     H2BUGF(infof(data_s, "Got frame type %x for stream %u!",
795                  frame->hd.type, stream_id));
796     break;
797   }
798   return 0;
799 }
800 
on_data_chunk_recv(nghttp2_session * session,uint8_t flags,int32_t stream_id,const uint8_t * mem,size_t len,void * userp)801 static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
802                               int32_t stream_id,
803                               const uint8_t *mem, size_t len, void *userp)
804 {
805   struct HTTP *stream;
806   struct Curl_easy *data_s;
807   size_t nread;
808   struct connectdata *conn = (struct connectdata *)userp;
809   struct http_conn *httpc = &conn->proto.httpc;
810   (void)session;
811   (void)flags;
812 
813   DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
814 
815   /* get the stream from the hash based on Stream ID */
816   data_s = nghttp2_session_get_stream_user_data(session, stream_id);
817   if(!data_s)
818     /* Receiving a Stream ID not in the hash should not happen, this is an
819        internal error more than anything else! */
820     return NGHTTP2_ERR_CALLBACK_FAILURE;
821 
822   stream = data_s->req.p.http;
823   if(!stream)
824     return NGHTTP2_ERR_CALLBACK_FAILURE;
825 
826   nread = CURLMIN(stream->len, len);
827   memcpy(&stream->mem[stream->memlen], mem, nread);
828 
829   stream->len -= nread;
830   stream->memlen += nread;
831 
832   drain_this(data_s, &conn->proto.httpc);
833 
834   /* if we receive data for another handle, wake that up */
835   if(get_transfer(httpc) != data_s)
836     Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
837 
838   H2BUGF(infof(data_s, "%zu data received for stream %u "
839                "(%zu left in buffer %p, total %zu)",
840                nread, stream_id,
841                stream->len, stream->mem,
842                stream->memlen));
843 
844   if(nread < len) {
845     stream->pausedata = mem + nread;
846     stream->pauselen = len - nread;
847     H2BUGF(infof(data_s, "NGHTTP2_ERR_PAUSE - %zu bytes out of buffer"
848                  ", stream %u",
849                  len - nread, stream_id));
850     data_s->conn->proto.httpc.pause_stream_id = stream_id;
851 
852     return NGHTTP2_ERR_PAUSE;
853   }
854 
855   /* pause execution of nghttp2 if we received data for another handle
856      in order to process them first. */
857   if(get_transfer(httpc) != data_s) {
858     data_s->conn->proto.httpc.pause_stream_id = stream_id;
859 
860     return NGHTTP2_ERR_PAUSE;
861   }
862 
863   return 0;
864 }
865 
on_stream_close(nghttp2_session * session,int32_t stream_id,uint32_t error_code,void * userp)866 static int on_stream_close(nghttp2_session *session, int32_t stream_id,
867                            uint32_t error_code, void *userp)
868 {
869   struct Curl_easy *data_s;
870   struct HTTP *stream;
871   struct connectdata *conn = (struct connectdata *)userp;
872   int rv;
873   (void)session;
874   (void)stream_id;
875 
876   if(stream_id) {
877     struct http_conn *httpc;
878     /* get the stream from the hash based on Stream ID, stream ID zero is for
879        connection-oriented stuff */
880     data_s = nghttp2_session_get_stream_user_data(session, stream_id);
881     if(!data_s) {
882       /* We could get stream ID not in the hash.  For example, if we
883          decided to reject stream (e.g., PUSH_PROMISE). */
884       return 0;
885     }
886     H2BUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u",
887                  nghttp2_http2_strerror(error_code), error_code, stream_id));
888     stream = data_s->req.p.http;
889     if(!stream)
890       return NGHTTP2_ERR_CALLBACK_FAILURE;
891 
892     stream->closed = TRUE;
893     httpc = &conn->proto.httpc;
894     drain_this(data_s, httpc);
895     Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
896     stream->error = error_code;
897 
898     /* remove the entry from the hash as the stream is now gone */
899     rv = nghttp2_session_set_stream_user_data(session, stream_id, 0);
900     if(rv) {
901       infof(data_s, "http/2: failed to clear user_data for stream %d!",
902             stream_id);
903       DEBUGASSERT(0);
904     }
905     if(stream_id == httpc->pause_stream_id) {
906       H2BUGF(infof(data_s, "Stopped the pause stream!"));
907       httpc->pause_stream_id = 0;
908     }
909     H2BUGF(infof(data_s, "Removed stream %u hash!", stream_id));
910     stream->stream_id = 0; /* cleared */
911   }
912   return 0;
913 }
914 
on_begin_headers(nghttp2_session * session,const nghttp2_frame * frame,void * userp)915 static int on_begin_headers(nghttp2_session *session,
916                             const nghttp2_frame *frame, void *userp)
917 {
918   struct HTTP *stream;
919   struct Curl_easy *data_s = NULL;
920   (void)userp;
921 
922   data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
923   if(!data_s) {
924     return 0;
925   }
926 
927   H2BUGF(infof(data_s, "on_begin_headers() was called"));
928 
929   if(frame->hd.type != NGHTTP2_HEADERS) {
930     return 0;
931   }
932 
933   stream = data_s->req.p.http;
934   if(!stream || !stream->bodystarted) {
935     return 0;
936   }
937 
938   return 0;
939 }
940 
941 /* Decode HTTP status code.  Returns -1 if no valid status code was
942    decoded. */
decode_status_code(const uint8_t * value,size_t len)943 static int decode_status_code(const uint8_t *value, size_t len)
944 {
945   int i;
946   int res;
947 
948   if(len != 3) {
949     return -1;
950   }
951 
952   res = 0;
953 
954   for(i = 0; i < 3; ++i) {
955     char c = value[i];
956 
957     if(c < '0' || c > '9') {
958       return -1;
959     }
960 
961     res *= 10;
962     res += c - '0';
963   }
964 
965   return res;
966 }
967 
968 /* 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)969 static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
970                      const uint8_t *name, size_t namelen,
971                      const uint8_t *value, size_t valuelen,
972                      uint8_t flags,
973                      void *userp)
974 {
975   struct HTTP *stream;
976   struct Curl_easy *data_s;
977   int32_t stream_id = frame->hd.stream_id;
978   struct connectdata *conn = (struct connectdata *)userp;
979   struct http_conn *httpc = &conn->proto.httpc;
980   CURLcode result;
981   (void)flags;
982 
983   DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
984 
985   /* get the stream from the hash based on Stream ID */
986   data_s = nghttp2_session_get_stream_user_data(session, stream_id);
987   if(!data_s)
988     /* Receiving a Stream ID not in the hash should not happen, this is an
989        internal error more than anything else! */
990     return NGHTTP2_ERR_CALLBACK_FAILURE;
991 
992   stream = data_s->req.p.http;
993   if(!stream) {
994     failf(data_s, "Internal NULL stream!");
995     return NGHTTP2_ERR_CALLBACK_FAILURE;
996   }
997 
998   /* Store received PUSH_PROMISE headers to be used when the subsequent
999      PUSH_PROMISE callback comes */
1000   if(frame->hd.type == NGHTTP2_PUSH_PROMISE) {
1001     char *h;
1002 
1003     if(!strcmp(":authority", (const char *)name)) {
1004       /* pseudo headers are lower case */
1005       int rc = 0;
1006       char *check = aprintf("%s:%d", conn->host.name, conn->remote_port);
1007       if(!check)
1008         /* no memory */
1009         return NGHTTP2_ERR_CALLBACK_FAILURE;
1010       if(!Curl_strcasecompare(check, (const char *)value) &&
1011          ((conn->remote_port != conn->given->defport) ||
1012           !Curl_strcasecompare(conn->host.name, (const char *)value))) {
1013         /* This is push is not for the same authority that was asked for in
1014          * the URL. RFC 7540 section 8.2 says: "A client MUST treat a
1015          * PUSH_PROMISE for which the server is not authoritative as a stream
1016          * error of type PROTOCOL_ERROR."
1017          */
1018         (void)nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
1019                                         stream_id, NGHTTP2_PROTOCOL_ERROR);
1020         rc = NGHTTP2_ERR_CALLBACK_FAILURE;
1021       }
1022       free(check);
1023       if(rc)
1024         return rc;
1025     }
1026 
1027     if(!stream->push_headers) {
1028       stream->push_headers_alloc = 10;
1029       stream->push_headers = malloc(stream->push_headers_alloc *
1030                                     sizeof(char *));
1031       if(!stream->push_headers)
1032         return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
1033       stream->push_headers_used = 0;
1034     }
1035     else if(stream->push_headers_used ==
1036             stream->push_headers_alloc) {
1037       char **headp;
1038       stream->push_headers_alloc *= 2;
1039       headp = Curl_saferealloc(stream->push_headers,
1040                                stream->push_headers_alloc * sizeof(char *));
1041       if(!headp) {
1042         stream->push_headers = NULL;
1043         return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
1044       }
1045       stream->push_headers = headp;
1046     }
1047     h = aprintf("%s:%s", name, value);
1048     if(h)
1049       stream->push_headers[stream->push_headers_used++] = h;
1050     return 0;
1051   }
1052 
1053   if(stream->bodystarted) {
1054     /* This is a trailer */
1055     H2BUGF(infof(data_s, "h2 trailer: %.*s: %.*s", namelen, name, valuelen,
1056                  value));
1057     result = Curl_dyn_addf(&stream->trailer_recvbuf,
1058                            "%.*s: %.*s\r\n", namelen, name,
1059                            valuelen, value);
1060     if(result)
1061       return NGHTTP2_ERR_CALLBACK_FAILURE;
1062 
1063     return 0;
1064   }
1065 
1066   if(namelen == sizeof(":status") - 1 &&
1067      memcmp(":status", name, namelen) == 0) {
1068     /* nghttp2 guarantees :status is received first and only once, and
1069        value is 3 digits status code, and decode_status_code always
1070        succeeds. */
1071     stream->status_code = decode_status_code(value, valuelen);
1072     DEBUGASSERT(stream->status_code != -1);
1073 
1074     result = Curl_dyn_add(&stream->header_recvbuf, "HTTP/2 ");
1075     if(result)
1076       return NGHTTP2_ERR_CALLBACK_FAILURE;
1077     result = Curl_dyn_addn(&stream->header_recvbuf, value, valuelen);
1078     if(result)
1079       return NGHTTP2_ERR_CALLBACK_FAILURE;
1080     /* the space character after the status code is mandatory */
1081     result = Curl_dyn_add(&stream->header_recvbuf, " \r\n");
1082     if(result)
1083       return NGHTTP2_ERR_CALLBACK_FAILURE;
1084     /* if we receive data for another handle, wake that up */
1085     if(get_transfer(httpc) != data_s)
1086       Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
1087 
1088     H2BUGF(infof(data_s, "h2 status: HTTP/2 %03d (easy %p)",
1089                  stream->status_code, data_s));
1090     return 0;
1091   }
1092 
1093   /* nghttp2 guarantees that namelen > 0, and :status was already
1094      received, and this is not pseudo-header field . */
1095   /* convert to a HTTP1-style header */
1096   result = Curl_dyn_addn(&stream->header_recvbuf, name, namelen);
1097   if(result)
1098     return NGHTTP2_ERR_CALLBACK_FAILURE;
1099   result = Curl_dyn_add(&stream->header_recvbuf, ": ");
1100   if(result)
1101     return NGHTTP2_ERR_CALLBACK_FAILURE;
1102   result = Curl_dyn_addn(&stream->header_recvbuf, value, valuelen);
1103   if(result)
1104     return NGHTTP2_ERR_CALLBACK_FAILURE;
1105   result = Curl_dyn_add(&stream->header_recvbuf, "\r\n");
1106   if(result)
1107     return NGHTTP2_ERR_CALLBACK_FAILURE;
1108   /* if we receive data for another handle, wake that up */
1109   if(get_transfer(httpc) != data_s)
1110     Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
1111 
1112   H2BUGF(infof(data_s, "h2 header: %.*s: %.*s", namelen, name, valuelen,
1113                value));
1114 
1115   return 0; /* 0 is successful */
1116 }
1117 
data_source_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)1118 static ssize_t data_source_read_callback(nghttp2_session *session,
1119                                          int32_t stream_id,
1120                                          uint8_t *buf, size_t length,
1121                                          uint32_t *data_flags,
1122                                          nghttp2_data_source *source,
1123                                          void *userp)
1124 {
1125   struct Curl_easy *data_s;
1126   struct HTTP *stream = NULL;
1127   size_t nread;
1128   (void)source;
1129   (void)userp;
1130 
1131   if(stream_id) {
1132     /* get the stream from the hash based on Stream ID, stream ID zero is for
1133        connection-oriented stuff */
1134     data_s = nghttp2_session_get_stream_user_data(session, stream_id);
1135     if(!data_s)
1136       /* Receiving a Stream ID not in the hash should not happen, this is an
1137          internal error more than anything else! */
1138       return NGHTTP2_ERR_CALLBACK_FAILURE;
1139 
1140     stream = data_s->req.p.http;
1141     if(!stream)
1142       return NGHTTP2_ERR_CALLBACK_FAILURE;
1143   }
1144   else
1145     return NGHTTP2_ERR_INVALID_ARGUMENT;
1146 
1147   nread = CURLMIN(stream->upload_len, length);
1148   if(nread > 0) {
1149     memcpy(buf, stream->upload_mem, nread);
1150     stream->upload_mem += nread;
1151     stream->upload_len -= nread;
1152     if(data_s->state.infilesize != -1)
1153       stream->upload_left -= nread;
1154   }
1155 
1156   if(stream->upload_left == 0)
1157     *data_flags = NGHTTP2_DATA_FLAG_EOF;
1158   else if(nread == 0)
1159     return NGHTTP2_ERR_DEFERRED;
1160 
1161   H2BUGF(infof(data_s, "data_source_read_callback: "
1162                "returns %zu bytes stream %u",
1163                nread, stream_id));
1164 
1165   return nread;
1166 }
1167 
1168 #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
error_callback(nghttp2_session * session,const char * msg,size_t len,void * userp)1169 static int error_callback(nghttp2_session *session,
1170                           const char *msg,
1171                           size_t len,
1172                           void *userp)
1173 {
1174   (void)session;
1175   (void)msg;
1176   (void)len;
1177   (void)userp;
1178   return 0;
1179 }
1180 #endif
1181 
populate_settings(struct Curl_easy * data,struct http_conn * httpc)1182 static void populate_settings(struct Curl_easy *data,
1183                               struct http_conn *httpc)
1184 {
1185   nghttp2_settings_entry *iv = httpc->local_settings;
1186 
1187   iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
1188   iv[0].value = Curl_multi_max_concurrent_streams(data->multi);
1189 
1190   iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
1191   iv[1].value = HTTP2_HUGE_WINDOW_SIZE;
1192 
1193   iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
1194   iv[2].value = data->multi->push_cb != NULL;
1195 
1196   httpc->local_settings_num = 3;
1197 }
1198 
Curl_http2_done(struct Curl_easy * data,bool premature)1199 void Curl_http2_done(struct Curl_easy *data, bool premature)
1200 {
1201   struct HTTP *http = data->req.p.http;
1202   struct http_conn *httpc = &data->conn->proto.httpc;
1203 
1204   /* there might be allocated resources done before this got the 'h2' pointer
1205      setup */
1206   Curl_dyn_free(&http->header_recvbuf);
1207   Curl_dyn_free(&http->trailer_recvbuf);
1208   if(http->push_headers) {
1209     /* if they weren't used and then freed before */
1210     for(; http->push_headers_used > 0; --http->push_headers_used) {
1211       free(http->push_headers[http->push_headers_used - 1]);
1212     }
1213     free(http->push_headers);
1214     http->push_headers = NULL;
1215   }
1216 
1217   if(!(data->conn->handler->protocol&PROTO_FAMILY_HTTP) ||
1218      !httpc->h2) /* not HTTP/2 ? */
1219     return;
1220 
1221   if(premature) {
1222     /* RST_STREAM */
1223     set_transfer(httpc, data); /* set the transfer */
1224     if(!nghttp2_submit_rst_stream(httpc->h2, NGHTTP2_FLAG_NONE,
1225                                   http->stream_id, NGHTTP2_STREAM_CLOSED))
1226       (void)nghttp2_session_send(httpc->h2);
1227 
1228     if(http->stream_id == httpc->pause_stream_id) {
1229       infof(data, "stopped the pause stream!");
1230       httpc->pause_stream_id = 0;
1231     }
1232   }
1233 
1234   if(data->state.drain)
1235     drained_transfer(data, httpc);
1236 
1237   /* -1 means unassigned and 0 means cleared */
1238   if(http->stream_id > 0) {
1239     int rv = nghttp2_session_set_stream_user_data(httpc->h2,
1240                                                   http->stream_id, 0);
1241     if(rv) {
1242       infof(data, "http/2: failed to clear user_data for stream %d!",
1243             http->stream_id);
1244       DEBUGASSERT(0);
1245     }
1246     set_transfer(httpc, NULL);
1247     http->stream_id = 0;
1248   }
1249 }
1250 
1251 /*
1252  * Initialize nghttp2 for a Curl connection
1253  */
http2_init(struct Curl_easy * data,struct connectdata * conn)1254 static CURLcode http2_init(struct Curl_easy *data, struct connectdata *conn)
1255 {
1256   if(!conn->proto.httpc.h2) {
1257     int rc;
1258     nghttp2_session_callbacks *callbacks;
1259 
1260     conn->proto.httpc.inbuf = malloc(H2_BUFSIZE);
1261     if(!conn->proto.httpc.inbuf)
1262       return CURLE_OUT_OF_MEMORY;
1263 
1264     rc = nghttp2_session_callbacks_new(&callbacks);
1265 
1266     if(rc) {
1267       failf(data, "Couldn't initialize nghttp2 callbacks!");
1268       return CURLE_OUT_OF_MEMORY; /* most likely at least */
1269     }
1270 
1271     /* nghttp2_send_callback */
1272     nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
1273     /* nghttp2_on_frame_recv_callback */
1274     nghttp2_session_callbacks_set_on_frame_recv_callback
1275       (callbacks, on_frame_recv);
1276     /* nghttp2_on_data_chunk_recv_callback */
1277     nghttp2_session_callbacks_set_on_data_chunk_recv_callback
1278       (callbacks, on_data_chunk_recv);
1279     /* nghttp2_on_stream_close_callback */
1280     nghttp2_session_callbacks_set_on_stream_close_callback
1281       (callbacks, on_stream_close);
1282     /* nghttp2_on_begin_headers_callback */
1283     nghttp2_session_callbacks_set_on_begin_headers_callback
1284       (callbacks, on_begin_headers);
1285     /* nghttp2_on_header_callback */
1286     nghttp2_session_callbacks_set_on_header_callback(callbacks, on_header);
1287 
1288     nghttp2_session_callbacks_set_error_callback(callbacks, error_callback);
1289 
1290     /* The nghttp2 session is not yet setup, do it */
1291     rc = nghttp2_session_client_new(&conn->proto.httpc.h2, callbacks, conn);
1292 
1293     nghttp2_session_callbacks_del(callbacks);
1294 
1295     if(rc) {
1296       failf(data, "Couldn't initialize nghttp2!");
1297       return CURLE_OUT_OF_MEMORY; /* most likely at least */
1298     }
1299   }
1300   return CURLE_OK;
1301 }
1302 
1303 /*
1304  * Append headers to ask for a HTTP1.1 to HTTP2 upgrade.
1305  */
Curl_http2_request_upgrade(struct dynbuf * req,struct Curl_easy * data)1306 CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
1307                                     struct Curl_easy *data)
1308 {
1309   CURLcode result;
1310   ssize_t binlen;
1311   char *base64;
1312   size_t blen;
1313   struct connectdata *conn = data->conn;
1314   struct SingleRequest *k = &data->req;
1315   uint8_t *binsettings = conn->proto.httpc.binsettings;
1316   struct http_conn *httpc = &conn->proto.httpc;
1317 
1318   populate_settings(data, httpc);
1319 
1320   /* this returns number of bytes it wrote */
1321   binlen = nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN,
1322                                          httpc->local_settings,
1323                                          httpc->local_settings_num);
1324   if(binlen <= 0) {
1325     failf(data, "nghttp2 unexpectedly failed on pack_settings_payload");
1326     Curl_dyn_free(req);
1327     return CURLE_FAILED_INIT;
1328   }
1329   conn->proto.httpc.binlen = binlen;
1330 
1331   result = Curl_base64url_encode(data, (const char *)binsettings, binlen,
1332                                  &base64, &blen);
1333   if(result) {
1334     Curl_dyn_free(req);
1335     return result;
1336   }
1337 
1338   result = Curl_dyn_addf(req,
1339                          "Connection: Upgrade, HTTP2-Settings\r\n"
1340                          "Upgrade: %s\r\n"
1341                          "HTTP2-Settings: %s\r\n",
1342                          NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64);
1343   free(base64);
1344 
1345   k->upgr101 = UPGR101_REQUESTED;
1346 
1347   return result;
1348 }
1349 
1350 /*
1351  * Returns nonzero if current HTTP/2 session should be closed.
1352  */
should_close_session(struct http_conn * httpc)1353 static int should_close_session(struct http_conn *httpc)
1354 {
1355   return httpc->drain_total == 0 && !nghttp2_session_want_read(httpc->h2) &&
1356     !nghttp2_session_want_write(httpc->h2);
1357 }
1358 
1359 /*
1360  * h2_process_pending_input() processes pending input left in
1361  * httpc->inbuf.  Then, call h2_session_send() to send pending data.
1362  * This function returns 0 if it succeeds, or -1 and error code will
1363  * be assigned to *err.
1364  */
h2_process_pending_input(struct Curl_easy * data,struct http_conn * httpc,CURLcode * err)1365 static int h2_process_pending_input(struct Curl_easy *data,
1366                                     struct http_conn *httpc,
1367                                     CURLcode *err)
1368 {
1369   ssize_t nread;
1370   char *inbuf;
1371   ssize_t rv;
1372 
1373   nread = httpc->inbuflen - httpc->nread_inbuf;
1374   inbuf = httpc->inbuf + httpc->nread_inbuf;
1375 
1376   set_transfer(httpc, data); /* set the transfer */
1377   rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread);
1378   if(rv < 0) {
1379     failf(data,
1380           "h2_process_pending_input: nghttp2_session_mem_recv() returned "
1381           "%zd:%s", rv, nghttp2_strerror((int)rv));
1382     *err = CURLE_RECV_ERROR;
1383     return -1;
1384   }
1385 
1386   if(nread == rv) {
1387     H2BUGF(infof(data,
1388                  "h2_process_pending_input: All data in connection buffer "
1389                  "processed"));
1390     httpc->inbuflen = 0;
1391     httpc->nread_inbuf = 0;
1392   }
1393   else {
1394     httpc->nread_inbuf += rv;
1395     H2BUGF(infof(data,
1396                  "h2_process_pending_input: %zu bytes left in connection "
1397                  "buffer",
1398                  httpc->inbuflen - httpc->nread_inbuf));
1399   }
1400 
1401   rv = h2_session_send(data, httpc->h2);
1402   if(rv) {
1403     *err = CURLE_SEND_ERROR;
1404     return -1;
1405   }
1406 
1407   if(nghttp2_session_check_request_allowed(httpc->h2) == 0) {
1408     /* No more requests are allowed in the current session, so
1409        the connection may not be reused. This is set when a
1410        GOAWAY frame has been received or when the limit of stream
1411        identifiers has been reached. */
1412     connclose(data->conn, "http/2: No new requests allowed");
1413   }
1414 
1415   if(should_close_session(httpc)) {
1416     struct HTTP *stream = data->req.p.http;
1417     H2BUGF(infof(data,
1418                  "h2_process_pending_input: nothing to do in this session"));
1419     if(stream->error)
1420       *err = CURLE_HTTP2;
1421     else {
1422       /* not an error per se, but should still close the connection */
1423       connclose(data->conn, "GOAWAY received");
1424       *err = CURLE_OK;
1425     }
1426     return -1;
1427   }
1428   return 0;
1429 }
1430 
1431 /*
1432  * Called from transfer.c:done_sending when we stop uploading.
1433  */
Curl_http2_done_sending(struct Curl_easy * data,struct connectdata * conn)1434 CURLcode Curl_http2_done_sending(struct Curl_easy *data,
1435                                  struct connectdata *conn)
1436 {
1437   CURLcode result = CURLE_OK;
1438 
1439   if((conn->handler == &Curl_handler_http2_ssl) ||
1440      (conn->handler == &Curl_handler_http2)) {
1441     /* make sure this is only attempted for HTTP/2 transfers */
1442     struct HTTP *stream = data->req.p.http;
1443     struct http_conn *httpc = &conn->proto.httpc;
1444     nghttp2_session *h2 = httpc->h2;
1445 
1446     if(stream->upload_left) {
1447       /* If the stream still thinks there's data left to upload. */
1448 
1449       stream->upload_left = 0; /* DONE! */
1450 
1451       /* resume sending here to trigger the callback to get called again so
1452          that it can signal EOF to nghttp2 */
1453       (void)nghttp2_session_resume_data(h2, stream->stream_id);
1454       (void)h2_process_pending_input(data, httpc, &result);
1455     }
1456 
1457     /* If nghttp2 still has pending frames unsent */
1458     if(nghttp2_session_want_write(h2)) {
1459       struct SingleRequest *k = &data->req;
1460       int rv;
1461 
1462       H2BUGF(infof(data, "HTTP/2 still wants to send data (easy %p)", data));
1463 
1464       /* and attempt to send the pending frames */
1465       rv = h2_session_send(data, h2);
1466       if(rv)
1467         result = CURLE_SEND_ERROR;
1468 
1469       if(nghttp2_session_want_write(h2)) {
1470          /* re-set KEEP_SEND to make sure we are called again */
1471          k->keepon |= KEEP_SEND;
1472       }
1473     }
1474   }
1475   return result;
1476 }
1477 
http2_handle_stream_close(struct connectdata * conn,struct Curl_easy * data,struct HTTP * stream,CURLcode * err)1478 static ssize_t http2_handle_stream_close(struct connectdata *conn,
1479                                          struct Curl_easy *data,
1480                                          struct HTTP *stream, CURLcode *err)
1481 {
1482   struct http_conn *httpc = &conn->proto.httpc;
1483 
1484   if(httpc->pause_stream_id == stream->stream_id) {
1485     httpc->pause_stream_id = 0;
1486   }
1487 
1488   drained_transfer(data, httpc);
1489 
1490   if(httpc->pause_stream_id == 0) {
1491     if(h2_process_pending_input(data, httpc, err) != 0) {
1492       return -1;
1493     }
1494   }
1495 
1496   DEBUGASSERT(data->state.drain == 0);
1497 
1498   /* Reset to FALSE to prevent infinite loop in readwrite_data function. */
1499   stream->closed = FALSE;
1500   if(stream->error == NGHTTP2_REFUSED_STREAM) {
1501     H2BUGF(infof(data, "REFUSED_STREAM (%d), try again on a new connection!",
1502                  stream->stream_id));
1503     connclose(conn, "REFUSED_STREAM"); /* don't use this anymore */
1504     data->state.refused_stream = TRUE;
1505     *err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
1506     return -1;
1507   }
1508   else if(stream->error != NGHTTP2_NO_ERROR) {
1509     failf(data, "HTTP/2 stream %d was not closed cleanly: %s (err %u)",
1510           stream->stream_id, nghttp2_http2_strerror(stream->error),
1511           stream->error);
1512     *err = CURLE_HTTP2_STREAM;
1513     return -1;
1514   }
1515 
1516   if(!stream->bodystarted) {
1517     failf(data, "HTTP/2 stream %d was closed cleanly, but before getting "
1518           " all response header fields, treated as error",
1519           stream->stream_id);
1520     *err = CURLE_HTTP2_STREAM;
1521     return -1;
1522   }
1523 
1524   if(Curl_dyn_len(&stream->trailer_recvbuf)) {
1525     char *trailp = Curl_dyn_ptr(&stream->trailer_recvbuf);
1526     char *lf;
1527 
1528     do {
1529       size_t len = 0;
1530       CURLcode result;
1531       /* each trailer line ends with a newline */
1532       lf = strchr(trailp, '\n');
1533       if(!lf)
1534         break;
1535       len = lf + 1 - trailp;
1536 
1537       Curl_debug(data, CURLINFO_HEADER_IN, trailp, len);
1538       /* pass the trailers one by one to the callback */
1539       result = Curl_client_write(data, CLIENTWRITE_HEADER, trailp, len);
1540       if(result) {
1541         *err = result;
1542         return -1;
1543       }
1544       trailp = ++lf;
1545     } while(lf);
1546   }
1547 
1548   stream->close_handled = TRUE;
1549 
1550   H2BUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close"));
1551   return 0;
1552 }
1553 
1554 /*
1555  * h2_pri_spec() fills in the pri_spec struct, used by nghttp2 to send weight
1556  * and dependency to the peer. It also stores the updated values in the state
1557  * struct.
1558  */
1559 
h2_pri_spec(struct Curl_easy * data,nghttp2_priority_spec * pri_spec)1560 static void h2_pri_spec(struct Curl_easy *data,
1561                         nghttp2_priority_spec *pri_spec)
1562 {
1563   struct HTTP *depstream = (data->set.stream_depends_on?
1564                             data->set.stream_depends_on->req.p.http:NULL);
1565   int32_t depstream_id = depstream? depstream->stream_id:0;
1566   nghttp2_priority_spec_init(pri_spec, depstream_id, data->set.stream_weight,
1567                              data->set.stream_depends_e);
1568   data->state.stream_weight = data->set.stream_weight;
1569   data->state.stream_depends_e = data->set.stream_depends_e;
1570   data->state.stream_depends_on = data->set.stream_depends_on;
1571 }
1572 
1573 /*
1574  * h2_session_send() checks if there's been an update in the priority /
1575  * dependency settings and if so it submits a PRIORITY frame with the updated
1576  * info.
1577  */
h2_session_send(struct Curl_easy * data,nghttp2_session * h2)1578 static int h2_session_send(struct Curl_easy *data,
1579                            nghttp2_session *h2)
1580 {
1581   struct HTTP *stream = data->req.p.http;
1582   struct http_conn *httpc = &data->conn->proto.httpc;
1583   set_transfer(httpc, data);
1584   if((data->set.stream_weight != data->state.stream_weight) ||
1585      (data->set.stream_depends_e != data->state.stream_depends_e) ||
1586      (data->set.stream_depends_on != data->state.stream_depends_on) ) {
1587     /* send new weight and/or dependency */
1588     nghttp2_priority_spec pri_spec;
1589     int rv;
1590 
1591     h2_pri_spec(data, &pri_spec);
1592 
1593     H2BUGF(infof(data, "Queuing PRIORITY on stream %u (easy %p)",
1594                  stream->stream_id, data));
1595     DEBUGASSERT(stream->stream_id != -1);
1596     rv = nghttp2_submit_priority(h2, NGHTTP2_FLAG_NONE, stream->stream_id,
1597                                  &pri_spec);
1598     if(rv)
1599       return rv;
1600   }
1601 
1602   return nghttp2_session_send(h2);
1603 }
1604 
http2_recv(struct Curl_easy * data,int sockindex,char * mem,size_t len,CURLcode * err)1605 static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
1606                           char *mem, size_t len, CURLcode *err)
1607 {
1608   ssize_t nread;
1609   struct connectdata *conn = data->conn;
1610   struct http_conn *httpc = &conn->proto.httpc;
1611   struct HTTP *stream = data->req.p.http;
1612 
1613   (void)sockindex; /* we always do HTTP2 on sockindex 0 */
1614 
1615   if(should_close_session(httpc)) {
1616     H2BUGF(infof(data,
1617                  "http2_recv: nothing to do in this session"));
1618     if(conn->bits.close) {
1619       /* already marked for closure, return OK and we're done */
1620       *err = CURLE_OK;
1621       return 0;
1622     }
1623     *err = CURLE_HTTP2;
1624     return -1;
1625   }
1626 
1627   if(stream->closed)
1628     /* closed overrides paused */
1629     return http2_handle_stream_close(conn, data, stream, err);
1630 
1631   /* Nullify here because we call nghttp2_session_send() and they
1632      might refer to the old buffer. */
1633   stream->upload_mem = NULL;
1634   stream->upload_len = 0;
1635 
1636   /*
1637    * At this point 'stream' is just in the Curl_easy the connection
1638    * identifies as its owner at this time.
1639    */
1640 
1641   if(stream->bodystarted &&
1642      stream->nread_header_recvbuf < Curl_dyn_len(&stream->header_recvbuf)) {
1643     /* If there is header data pending for this stream to return, do that */
1644     size_t left =
1645       Curl_dyn_len(&stream->header_recvbuf) - stream->nread_header_recvbuf;
1646     size_t ncopy = CURLMIN(len, left);
1647     memcpy(mem, Curl_dyn_ptr(&stream->header_recvbuf) +
1648            stream->nread_header_recvbuf, ncopy);
1649     stream->nread_header_recvbuf += ncopy;
1650 
1651     H2BUGF(infof(data, "http2_recv: Got %d bytes from header_recvbuf",
1652                  (int)ncopy));
1653     return ncopy;
1654   }
1655 
1656   H2BUGF(infof(data, "http2_recv: easy %p (stream %u) win %u/%u",
1657                data, stream->stream_id,
1658                nghttp2_session_get_local_window_size(httpc->h2),
1659                nghttp2_session_get_stream_local_window_size(httpc->h2,
1660                                                             stream->stream_id)
1661            ));
1662 
1663   if((data->state.drain) && stream->memlen) {
1664     H2BUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)",
1665                  stream->memlen, stream->stream_id,
1666                  stream->mem, mem));
1667     if(mem != stream->mem) {
1668       /* if we didn't get the same buffer this time, we must move the data to
1669          the beginning */
1670       memmove(mem, stream->mem, stream->memlen);
1671       stream->len = len - stream->memlen;
1672       stream->mem = mem;
1673     }
1674     if(httpc->pause_stream_id == stream->stream_id && !stream->pausedata) {
1675       /* We have paused nghttp2, but we have no pause data (see
1676          on_data_chunk_recv). */
1677       httpc->pause_stream_id = 0;
1678       if(h2_process_pending_input(data, httpc, err) != 0) {
1679         return -1;
1680       }
1681     }
1682   }
1683   else if(stream->pausedata) {
1684     DEBUGASSERT(httpc->pause_stream_id == stream->stream_id);
1685     nread = CURLMIN(len, stream->pauselen);
1686     memcpy(mem, stream->pausedata, nread);
1687 
1688     stream->pausedata += nread;
1689     stream->pauselen -= nread;
1690 
1691     if(stream->pauselen == 0) {
1692       H2BUGF(infof(data, "Unpaused by stream %u", stream->stream_id));
1693       DEBUGASSERT(httpc->pause_stream_id == stream->stream_id);
1694       httpc->pause_stream_id = 0;
1695 
1696       stream->pausedata = NULL;
1697       stream->pauselen = 0;
1698 
1699       /* When NGHTTP2_ERR_PAUSE is returned from
1700          data_source_read_callback, we might not process DATA frame
1701          fully.  Calling nghttp2_session_mem_recv() again will
1702          continue to process DATA frame, but if there is no incoming
1703          frames, then we have to call it again with 0-length data.
1704          Without this, on_stream_close callback will not be called,
1705          and stream could be hanged. */
1706       if(h2_process_pending_input(data, httpc, err) != 0) {
1707         return -1;
1708       }
1709     }
1710     H2BUGF(infof(data, "http2_recv: returns unpaused %zd bytes on stream %u",
1711                  nread, stream->stream_id));
1712     return nread;
1713   }
1714   else if(httpc->pause_stream_id) {
1715     /* If a stream paused nghttp2_session_mem_recv previously, and has
1716        not processed all data, it still refers to the buffer in
1717        nghttp2_session.  If we call nghttp2_session_mem_recv(), we may
1718        overwrite that buffer.  To avoid that situation, just return
1719        here with CURLE_AGAIN.  This could be busy loop since data in
1720        socket is not read.  But it seems that usually streams are
1721        notified with its drain property, and socket is read again
1722        quickly. */
1723     if(stream->closed)
1724       /* closed overrides paused */
1725       return 0;
1726     H2BUGF(infof(data, "stream %x is paused, pause id: %x",
1727                  stream->stream_id, httpc->pause_stream_id));
1728     *err = CURLE_AGAIN;
1729     return -1;
1730   }
1731   else {
1732     /* remember where to store incoming data for this stream and how big the
1733        buffer is */
1734     stream->mem = mem;
1735     stream->len = len;
1736     stream->memlen = 0;
1737 
1738     if(httpc->inbuflen == 0) {
1739       nread = ((Curl_recv *)httpc->recv_underlying)(
1740         data, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, err);
1741 
1742       if(nread == -1) {
1743         if(*err != CURLE_AGAIN)
1744           failf(data, "Failed receiving HTTP2 data");
1745         else if(stream->closed)
1746           /* received when the stream was already closed! */
1747           return http2_handle_stream_close(conn, data, stream, err);
1748 
1749         return -1;
1750       }
1751 
1752       if(nread == 0) {
1753         if(!stream->closed) {
1754           /* This will happen when the server or proxy server is SIGKILLed
1755              during data transfer. We should emit an error since our data
1756              received may be incomplete. */
1757           failf(data, "HTTP/2 stream %d was not closed cleanly before"
1758                 " end of the underlying stream",
1759                 stream->stream_id);
1760           *err = CURLE_HTTP2_STREAM;
1761           return -1;
1762         }
1763 
1764         H2BUGF(infof(data, "end of stream"));
1765         *err = CURLE_OK;
1766         return 0;
1767       }
1768 
1769       H2BUGF(infof(data, "nread=%zd", nread));
1770 
1771       httpc->inbuflen = nread;
1772 
1773       DEBUGASSERT(httpc->nread_inbuf == 0);
1774     }
1775     else {
1776       nread = httpc->inbuflen - httpc->nread_inbuf;
1777       (void)nread;  /* silence warning, used in debug */
1778       H2BUGF(infof(data, "Use data left in connection buffer, nread=%zd",
1779                    nread));
1780     }
1781 
1782     if(h2_process_pending_input(data, httpc, err))
1783       return -1;
1784   }
1785   if(stream->memlen) {
1786     ssize_t retlen = stream->memlen;
1787     H2BUGF(infof(data, "http2_recv: returns %zd for stream %u",
1788                  retlen, stream->stream_id));
1789     stream->memlen = 0;
1790 
1791     if(httpc->pause_stream_id == stream->stream_id) {
1792       /* data for this stream is returned now, but this stream caused a pause
1793          already so we need it called again asap */
1794       H2BUGF(infof(data, "Data returned for PAUSED stream %u",
1795                    stream->stream_id));
1796     }
1797     else if(!stream->closed) {
1798       drained_transfer(data, httpc);
1799     }
1800     else
1801       /* this stream is closed, trigger a another read ASAP to detect that */
1802       Curl_expire(data, 0, EXPIRE_RUN_NOW);
1803 
1804     return retlen;
1805   }
1806   if(stream->closed)
1807     return http2_handle_stream_close(conn, data, stream, err);
1808   *err = CURLE_AGAIN;
1809   H2BUGF(infof(data, "http2_recv returns AGAIN for stream %u",
1810                stream->stream_id));
1811   return -1;
1812 }
1813 
1814 /* Index where :authority header field will appear in request header
1815    field list. */
1816 #define AUTHORITY_DST_IDX 3
1817 
1818 /* USHRT_MAX is 65535 == 0xffff */
1819 #define HEADER_OVERFLOW(x) \
1820   (x.namelen > 0xffff || x.valuelen > 0xffff - x.namelen)
1821 
1822 /*
1823  * Check header memory for the token "trailers".
1824  * Parse the tokens as separated by comma and surrounded by whitespace.
1825  * Returns TRUE if found or FALSE if not.
1826  */
contains_trailers(const char * p,size_t len)1827 static bool contains_trailers(const char *p, size_t len)
1828 {
1829   const char *end = p + len;
1830   for(;;) {
1831     for(; p != end && (*p == ' ' || *p == '\t'); ++p)
1832       ;
1833     if(p == end || (size_t)(end - p) < sizeof("trailers") - 1)
1834       return FALSE;
1835     if(strncasecompare("trailers", p, sizeof("trailers") - 1)) {
1836       p += sizeof("trailers") - 1;
1837       for(; p != end && (*p == ' ' || *p == '\t'); ++p)
1838         ;
1839       if(p == end || *p == ',')
1840         return TRUE;
1841     }
1842     /* skip to next token */
1843     for(; p != end && *p != ','; ++p)
1844       ;
1845     if(p == end)
1846       return FALSE;
1847     ++p;
1848   }
1849 }
1850 
1851 typedef enum {
1852   /* Send header to server */
1853   HEADERINST_FORWARD,
1854   /* Don't send header to server */
1855   HEADERINST_IGNORE,
1856   /* Discard header, and replace it with "te: trailers" */
1857   HEADERINST_TE_TRAILERS
1858 } header_instruction;
1859 
1860 /* Decides how to treat given header field. */
inspect_header(const char * name,size_t namelen,const char * value,size_t valuelen)1861 static header_instruction inspect_header(const char *name, size_t namelen,
1862                                          const char *value, size_t valuelen) {
1863   switch(namelen) {
1864   case 2:
1865     if(!strncasecompare("te", name, namelen))
1866       return HEADERINST_FORWARD;
1867 
1868     return contains_trailers(value, valuelen) ?
1869            HEADERINST_TE_TRAILERS : HEADERINST_IGNORE;
1870   case 7:
1871     return strncasecompare("upgrade", name, namelen) ?
1872            HEADERINST_IGNORE : HEADERINST_FORWARD;
1873   case 10:
1874     return (strncasecompare("connection", name, namelen) ||
1875             strncasecompare("keep-alive", name, namelen)) ?
1876            HEADERINST_IGNORE : HEADERINST_FORWARD;
1877   case 16:
1878     return strncasecompare("proxy-connection", name, namelen) ?
1879            HEADERINST_IGNORE : HEADERINST_FORWARD;
1880   case 17:
1881     return strncasecompare("transfer-encoding", name, namelen) ?
1882            HEADERINST_IGNORE : HEADERINST_FORWARD;
1883   default:
1884     return HEADERINST_FORWARD;
1885   }
1886 }
1887 
http2_send(struct Curl_easy * data,int sockindex,const void * mem,size_t len,CURLcode * err)1888 static ssize_t http2_send(struct Curl_easy *data, int sockindex,
1889                           const void *mem, size_t len, CURLcode *err)
1890 {
1891   /*
1892    * Currently, we send request in this function, but this function is also
1893    * used to send request body. It would be nice to add dedicated function for
1894    * request.
1895    */
1896   int rv;
1897   struct connectdata *conn = data->conn;
1898   struct http_conn *httpc = &conn->proto.httpc;
1899   struct HTTP *stream = data->req.p.http;
1900   nghttp2_nv *nva = NULL;
1901   size_t nheader;
1902   size_t i;
1903   size_t authority_idx;
1904   char *hdbuf = (char *)mem;
1905   char *end, *line_end;
1906   nghttp2_data_provider data_prd;
1907   int32_t stream_id;
1908   nghttp2_session *h2 = httpc->h2;
1909   nghttp2_priority_spec pri_spec;
1910 
1911   (void)sockindex;
1912 
1913   H2BUGF(infof(data, "http2_send len=%zu", len));
1914 
1915   if(stream->stream_id != -1) {
1916     if(stream->close_handled) {
1917       infof(data, "stream %d closed", stream->stream_id);
1918       *err = CURLE_HTTP2_STREAM;
1919       return -1;
1920     }
1921     else if(stream->closed) {
1922       return http2_handle_stream_close(conn, data, stream, err);
1923     }
1924     /* If stream_id != -1, we have dispatched request HEADERS, and now
1925        are going to send or sending request body in DATA frame */
1926     stream->upload_mem = mem;
1927     stream->upload_len = len;
1928     rv = nghttp2_session_resume_data(h2, stream->stream_id);
1929     if(nghttp2_is_fatal(rv)) {
1930       *err = CURLE_SEND_ERROR;
1931       return -1;
1932     }
1933     rv = h2_session_send(data, h2);
1934     if(nghttp2_is_fatal(rv)) {
1935       *err = CURLE_SEND_ERROR;
1936       return -1;
1937     }
1938     len -= stream->upload_len;
1939 
1940     /* Nullify here because we call nghttp2_session_send() and they
1941        might refer to the old buffer. */
1942     stream->upload_mem = NULL;
1943     stream->upload_len = 0;
1944 
1945     if(should_close_session(httpc)) {
1946       H2BUGF(infof(data, "http2_send: nothing to do in this session"));
1947       *err = CURLE_HTTP2;
1948       return -1;
1949     }
1950 
1951     if(stream->upload_left) {
1952       /* we are sure that we have more data to send here.  Calling the
1953          following API will make nghttp2_session_want_write() return
1954          nonzero if remote window allows it, which then libcurl checks
1955          socket is writable or not.  See http2_perform_getsock(). */
1956       nghttp2_session_resume_data(h2, stream->stream_id);
1957     }
1958 
1959     H2BUGF(infof(data, "http2_send returns %zu for stream %u", len,
1960                  stream->stream_id));
1961     return len;
1962   }
1963 
1964   /* Calculate number of headers contained in [mem, mem + len) */
1965   /* Here, we assume the curl http code generate *correct* HTTP header
1966      field block */
1967   nheader = 0;
1968   for(i = 1; i < len; ++i) {
1969     if(hdbuf[i] == '\n' && hdbuf[i - 1] == '\r') {
1970       ++nheader;
1971       ++i;
1972     }
1973   }
1974   if(nheader < 2)
1975     goto fail;
1976 
1977   /* We counted additional 2 \r\n in the first and last line. We need 3
1978      new headers: :method, :path and :scheme. Therefore we need one
1979      more space. */
1980   nheader += 1;
1981   nva = malloc(sizeof(nghttp2_nv) * nheader);
1982   if(!nva) {
1983     *err = CURLE_OUT_OF_MEMORY;
1984     return -1;
1985   }
1986 
1987   /* Extract :method, :path from request line
1988      We do line endings with CRLF so checking for CR is enough */
1989   line_end = memchr(hdbuf, '\r', len);
1990   if(!line_end)
1991     goto fail;
1992 
1993   /* Method does not contain spaces */
1994   end = memchr(hdbuf, ' ', line_end - hdbuf);
1995   if(!end || end == hdbuf)
1996     goto fail;
1997   nva[0].name = (unsigned char *)":method";
1998   nva[0].namelen = strlen((char *)nva[0].name);
1999   nva[0].value = (unsigned char *)hdbuf;
2000   nva[0].valuelen = (size_t)(end - hdbuf);
2001   nva[0].flags = NGHTTP2_NV_FLAG_NONE;
2002   if(HEADER_OVERFLOW(nva[0])) {
2003     failf(data, "Failed sending HTTP request: Header overflow");
2004     goto fail;
2005   }
2006 
2007   hdbuf = end + 1;
2008 
2009   /* Path may contain spaces so scan backwards */
2010   end = NULL;
2011   for(i = (size_t)(line_end - hdbuf); i; --i) {
2012     if(hdbuf[i - 1] == ' ') {
2013       end = &hdbuf[i - 1];
2014       break;
2015     }
2016   }
2017   if(!end || end == hdbuf)
2018     goto fail;
2019   nva[1].name = (unsigned char *)":path";
2020   nva[1].namelen = strlen((char *)nva[1].name);
2021   nva[1].value = (unsigned char *)hdbuf;
2022   nva[1].valuelen = (size_t)(end - hdbuf);
2023   nva[1].flags = NGHTTP2_NV_FLAG_NONE;
2024   if(HEADER_OVERFLOW(nva[1])) {
2025     failf(data, "Failed sending HTTP request: Header overflow");
2026     goto fail;
2027   }
2028 
2029   nva[2].name = (unsigned char *)":scheme";
2030   nva[2].namelen = strlen((char *)nva[2].name);
2031   if(conn->handler->flags & PROTOPT_SSL)
2032     nva[2].value = (unsigned char *)"https";
2033   else
2034     nva[2].value = (unsigned char *)"http";
2035   nva[2].valuelen = strlen((char *)nva[2].value);
2036   nva[2].flags = NGHTTP2_NV_FLAG_NONE;
2037   if(HEADER_OVERFLOW(nva[2])) {
2038     failf(data, "Failed sending HTTP request: Header overflow");
2039     goto fail;
2040   }
2041 
2042   authority_idx = 0;
2043   i = 3;
2044   while(i < nheader) {
2045     size_t hlen;
2046 
2047     hdbuf = line_end + 2;
2048 
2049     /* check for next CR, but only within the piece of data left in the given
2050        buffer */
2051     line_end = memchr(hdbuf, '\r', len - (hdbuf - (char *)mem));
2052     if(!line_end || (line_end == hdbuf))
2053       goto fail;
2054 
2055     /* header continuation lines are not supported */
2056     if(*hdbuf == ' ' || *hdbuf == '\t')
2057       goto fail;
2058 
2059     for(end = hdbuf; end < line_end && *end != ':'; ++end)
2060       ;
2061     if(end == hdbuf || end == line_end)
2062       goto fail;
2063     hlen = end - hdbuf;
2064 
2065     if(hlen == 4 && strncasecompare("host", hdbuf, 4)) {
2066       authority_idx = i;
2067       nva[i].name = (unsigned char *)":authority";
2068       nva[i].namelen = strlen((char *)nva[i].name);
2069     }
2070     else {
2071       nva[i].namelen = (size_t)(end - hdbuf);
2072       /* Lower case the header name for HTTP/2 */
2073       Curl_strntolower((char *)hdbuf, hdbuf, nva[i].namelen);
2074       nva[i].name = (unsigned char *)hdbuf;
2075     }
2076     hdbuf = end + 1;
2077     while(*hdbuf == ' ' || *hdbuf == '\t')
2078       ++hdbuf;
2079     end = line_end;
2080 
2081     switch(inspect_header((const char *)nva[i].name, nva[i].namelen, hdbuf,
2082                           end - hdbuf)) {
2083     case HEADERINST_IGNORE:
2084       /* skip header fields prohibited by HTTP/2 specification. */
2085       --nheader;
2086       continue;
2087     case HEADERINST_TE_TRAILERS:
2088       nva[i].value = (uint8_t*)"trailers";
2089       nva[i].valuelen = sizeof("trailers") - 1;
2090       break;
2091     default:
2092       nva[i].value = (unsigned char *)hdbuf;
2093       nva[i].valuelen = (size_t)(end - hdbuf);
2094     }
2095 
2096     nva[i].flags = NGHTTP2_NV_FLAG_NONE;
2097     if(HEADER_OVERFLOW(nva[i])) {
2098       failf(data, "Failed sending HTTP request: Header overflow");
2099       goto fail;
2100     }
2101     ++i;
2102   }
2103 
2104   /* :authority must come before non-pseudo header fields */
2105   if(authority_idx && authority_idx != AUTHORITY_DST_IDX) {
2106     nghttp2_nv authority = nva[authority_idx];
2107     for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) {
2108       nva[i] = nva[i - 1];
2109     }
2110     nva[i] = authority;
2111   }
2112 
2113   /* Warn stream may be rejected if cumulative length of headers is too large.
2114      It appears nghttp2 will not send a header frame larger than 64KB. */
2115 #define MAX_ACC 60000  /* <64KB to account for some overhead */
2116   {
2117     size_t acc = 0;
2118 
2119     for(i = 0; i < nheader; ++i) {
2120       acc += nva[i].namelen + nva[i].valuelen;
2121 
2122       H2BUGF(infof(data, "h2 header: %.*s:%.*s",
2123                    nva[i].namelen, nva[i].name,
2124                    nva[i].valuelen, nva[i].value));
2125     }
2126 
2127     if(acc > MAX_ACC) {
2128       infof(data, "http2_send: Warning: The cumulative length of all "
2129             "headers exceeds %d bytes and that could cause the "
2130             "stream to be rejected.", MAX_ACC);
2131     }
2132   }
2133 
2134   h2_pri_spec(data, &pri_spec);
2135 
2136   H2BUGF(infof(data, "http2_send request allowed %d (easy handle %p)",
2137                nghttp2_session_check_request_allowed(h2), (void *)data));
2138 
2139   switch(data->state.httpreq) {
2140   case HTTPREQ_POST:
2141   case HTTPREQ_POST_FORM:
2142   case HTTPREQ_POST_MIME:
2143   case HTTPREQ_PUT:
2144     if(data->state.infilesize != -1)
2145       stream->upload_left = data->state.infilesize;
2146     else
2147       /* data sending without specifying the data amount up front */
2148       stream->upload_left = -1; /* unknown, but not zero */
2149 
2150     data_prd.read_callback = data_source_read_callback;
2151     data_prd.source.ptr = NULL;
2152     stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader,
2153                                        &data_prd, data);
2154     break;
2155   default:
2156     stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader,
2157                                        NULL, data);
2158   }
2159 
2160   Curl_safefree(nva);
2161 
2162   if(stream_id < 0) {
2163     H2BUGF(infof(data,
2164                  "http2_send() nghttp2_submit_request error (%s)%d",
2165                  nghttp2_strerror(stream_id), stream_id));
2166     *err = CURLE_SEND_ERROR;
2167     return -1;
2168   }
2169 
2170   infof(data, "Using Stream ID: %x (easy handle %p)",
2171         stream_id, (void *)data);
2172   stream->stream_id = stream_id;
2173 
2174   rv = h2_session_send(data, h2);
2175   if(rv) {
2176     H2BUGF(infof(data,
2177                  "http2_send() nghttp2_session_send error (%s)%d",
2178                  nghttp2_strerror(rv), rv));
2179 
2180     *err = CURLE_SEND_ERROR;
2181     return -1;
2182   }
2183 
2184   if(should_close_session(httpc)) {
2185     H2BUGF(infof(data, "http2_send: nothing to do in this session"));
2186     *err = CURLE_HTTP2;
2187     return -1;
2188   }
2189 
2190   /* If whole HEADERS frame was sent off to the underlying socket, the nghttp2
2191      library calls data_source_read_callback. But only it found that no data
2192      available, so it deferred the DATA transmission. Which means that
2193      nghttp2_session_want_write() returns 0 on http2_perform_getsock(), which
2194      results that no writable socket check is performed. To workaround this,
2195      we issue nghttp2_session_resume_data() here to bring back DATA
2196      transmission from deferred state. */
2197   nghttp2_session_resume_data(h2, stream->stream_id);
2198 
2199   return len;
2200 
2201 fail:
2202   free(nva);
2203   *err = CURLE_SEND_ERROR;
2204   return -1;
2205 }
2206 
Curl_http2_setup(struct Curl_easy * data,struct connectdata * conn)2207 CURLcode Curl_http2_setup(struct Curl_easy *data,
2208                           struct connectdata *conn)
2209 {
2210   CURLcode result;
2211   struct http_conn *httpc = &conn->proto.httpc;
2212   struct HTTP *stream = data->req.p.http;
2213 
2214   DEBUGASSERT(data->state.buffer);
2215 
2216   stream->stream_id = -1;
2217 
2218   Curl_dyn_init(&stream->header_recvbuf, DYN_H2_HEADERS);
2219   Curl_dyn_init(&stream->trailer_recvbuf, DYN_H2_TRAILERS);
2220 
2221   if((conn->handler == &Curl_handler_http2_ssl) ||
2222      (conn->handler == &Curl_handler_http2))
2223     return CURLE_OK; /* already done */
2224 
2225   if(conn->handler->flags & PROTOPT_SSL)
2226     conn->handler = &Curl_handler_http2_ssl;
2227   else
2228     conn->handler = &Curl_handler_http2;
2229 
2230   result = http2_init(data, conn);
2231   if(result) {
2232     Curl_dyn_free(&stream->header_recvbuf);
2233     return result;
2234   }
2235 
2236   infof(data, "Using HTTP2, server supports multiplexing");
2237   stream->upload_left = 0;
2238   stream->upload_mem = NULL;
2239   stream->upload_len = 0;
2240   stream->mem = data->state.buffer;
2241   stream->len = data->set.buffer_size;
2242 
2243   httpc->inbuflen = 0;
2244   httpc->nread_inbuf = 0;
2245 
2246   httpc->pause_stream_id = 0;
2247   httpc->drain_total = 0;
2248 
2249   conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
2250   conn->httpversion = 20;
2251   conn->bundle->multiuse = BUNDLE_MULTIPLEX;
2252 
2253   infof(data, "Connection state changed (HTTP/2 confirmed)");
2254   multi_connchanged(data->multi);
2255 
2256   return CURLE_OK;
2257 }
2258 
Curl_http2_switched(struct Curl_easy * data,const char * mem,size_t nread)2259 CURLcode Curl_http2_switched(struct Curl_easy *data,
2260                              const char *mem, size_t nread)
2261 {
2262   CURLcode result;
2263   struct connectdata *conn = data->conn;
2264   struct http_conn *httpc = &conn->proto.httpc;
2265   int rv;
2266   struct HTTP *stream = data->req.p.http;
2267 
2268   result = Curl_http2_setup(data, conn);
2269   if(result)
2270     return result;
2271 
2272   httpc->recv_underlying = conn->recv[FIRSTSOCKET];
2273   httpc->send_underlying = conn->send[FIRSTSOCKET];
2274   conn->recv[FIRSTSOCKET] = http2_recv;
2275   conn->send[FIRSTSOCKET] = http2_send;
2276 
2277   if(data->req.upgr101 == UPGR101_RECEIVED) {
2278     /* stream 1 is opened implicitly on upgrade */
2279     stream->stream_id = 1;
2280     /* queue SETTINGS frame (again) */
2281     rv = nghttp2_session_upgrade2(httpc->h2, httpc->binsettings, httpc->binlen,
2282                                   data->state.httpreq == HTTPREQ_HEAD, NULL);
2283     if(rv) {
2284       failf(data, "nghttp2_session_upgrade2() failed: %s(%d)",
2285             nghttp2_strerror(rv), rv);
2286       return CURLE_HTTP2;
2287     }
2288 
2289     rv = nghttp2_session_set_stream_user_data(httpc->h2,
2290                                               stream->stream_id,
2291                                               data);
2292     if(rv) {
2293       infof(data, "http/2: failed to set user_data for stream %d!",
2294             stream->stream_id);
2295       DEBUGASSERT(0);
2296     }
2297   }
2298   else {
2299     populate_settings(data, httpc);
2300 
2301     /* stream ID is unknown at this point */
2302     stream->stream_id = -1;
2303     rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE,
2304                                  httpc->local_settings,
2305                                  httpc->local_settings_num);
2306     if(rv) {
2307       failf(data, "nghttp2_submit_settings() failed: %s(%d)",
2308             nghttp2_strerror(rv), rv);
2309       return CURLE_HTTP2;
2310     }
2311   }
2312 
2313   rv = nghttp2_session_set_local_window_size(httpc->h2, NGHTTP2_FLAG_NONE, 0,
2314                                              HTTP2_HUGE_WINDOW_SIZE);
2315   if(rv) {
2316     failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
2317           nghttp2_strerror(rv), rv);
2318     return CURLE_HTTP2;
2319   }
2320 
2321   /* we are going to copy mem to httpc->inbuf.  This is required since
2322      mem is part of buffer pointed by stream->mem, and callbacks
2323      called by nghttp2_session_mem_recv() will write stream specific
2324      data into stream->mem, overwriting data already there. */
2325   if(H2_BUFSIZE < nread) {
2326     failf(data, "connection buffer size is too small to store data following "
2327           "HTTP Upgrade response header: buflen=%d, datalen=%zu",
2328           H2_BUFSIZE, nread);
2329     return CURLE_HTTP2;
2330   }
2331 
2332   infof(data, "Copying HTTP/2 data in stream buffer to connection buffer"
2333         " after upgrade: len=%zu",
2334         nread);
2335 
2336   if(nread)
2337     memcpy(httpc->inbuf, mem, nread);
2338 
2339   httpc->inbuflen = nread;
2340 
2341   DEBUGASSERT(httpc->nread_inbuf == 0);
2342 
2343   /* Good enough to call it an end once the remaining payload is copied to the
2344    * connection buffer.
2345    * Some servers (e.g. nghttpx v1.43.0) may fulfill stream 1 immediately
2346    * following the protocol switch other than waiting for the client-side
2347    * connection preface. If h2_process_pending_input is invoked here to parse
2348    * the remaining payload, stream 1 would be marked as closed too early and
2349    * thus ignored in http2_recv (following 252790c53).
2350    * The logic in lib/http.c and lib/transfer.c guarantees a following
2351    * http2_recv would be invoked very soon. */
2352 
2353   return CURLE_OK;
2354 }
2355 
Curl_http2_stream_pause(struct Curl_easy * data,bool pause)2356 CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause)
2357 {
2358   DEBUGASSERT(data);
2359   DEBUGASSERT(data->conn);
2360   /* if it isn't HTTP/2, we're done */
2361   if(!(data->conn->handler->protocol & PROTO_FAMILY_HTTP) ||
2362      !data->conn->proto.httpc.h2)
2363     return CURLE_OK;
2364 #ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
2365   else {
2366     struct HTTP *stream = data->req.p.http;
2367     struct http_conn *httpc = &data->conn->proto.httpc;
2368     uint32_t window = !pause * HTTP2_HUGE_WINDOW_SIZE;
2369     int rv = nghttp2_session_set_local_window_size(httpc->h2,
2370                                                    NGHTTP2_FLAG_NONE,
2371                                                    stream->stream_id,
2372                                                    window);
2373     if(rv) {
2374       failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
2375             nghttp2_strerror(rv), rv);
2376       return CURLE_HTTP2;
2377     }
2378 
2379     /* make sure the window update gets sent */
2380     rv = h2_session_send(data, httpc->h2);
2381     if(rv)
2382       return CURLE_SEND_ERROR;
2383 
2384     DEBUGF(infof(data, "Set HTTP/2 window size to %u for stream %u",
2385                  window, stream->stream_id));
2386 
2387 #ifdef DEBUGBUILD
2388     {
2389       /* read out the stream local window again */
2390       uint32_t window2 =
2391         nghttp2_session_get_stream_local_window_size(httpc->h2,
2392                                                      stream->stream_id);
2393       DEBUGF(infof(data, "HTTP/2 window size is now %u for stream %u",
2394                    window2, stream->stream_id));
2395     }
2396 #endif
2397   }
2398 #endif
2399   return CURLE_OK;
2400 }
2401 
Curl_http2_add_child(struct Curl_easy * parent,struct Curl_easy * child,bool exclusive)2402 CURLcode Curl_http2_add_child(struct Curl_easy *parent,
2403                               struct Curl_easy *child,
2404                               bool exclusive)
2405 {
2406   if(parent) {
2407     struct Curl_http2_dep **tail;
2408     struct Curl_http2_dep *dep = calloc(1, sizeof(struct Curl_http2_dep));
2409     if(!dep)
2410       return CURLE_OUT_OF_MEMORY;
2411     dep->data = child;
2412 
2413     if(parent->set.stream_dependents && exclusive) {
2414       struct Curl_http2_dep *node = parent->set.stream_dependents;
2415       while(node) {
2416         node->data->set.stream_depends_on = child;
2417         node = node->next;
2418       }
2419 
2420       tail = &child->set.stream_dependents;
2421       while(*tail)
2422         tail = &(*tail)->next;
2423 
2424       DEBUGASSERT(!*tail);
2425       *tail = parent->set.stream_dependents;
2426       parent->set.stream_dependents = 0;
2427     }
2428 
2429     tail = &parent->set.stream_dependents;
2430     while(*tail) {
2431       (*tail)->data->set.stream_depends_e = FALSE;
2432       tail = &(*tail)->next;
2433     }
2434 
2435     DEBUGASSERT(!*tail);
2436     *tail = dep;
2437   }
2438 
2439   child->set.stream_depends_on = parent;
2440   child->set.stream_depends_e = exclusive;
2441   return CURLE_OK;
2442 }
2443 
Curl_http2_remove_child(struct Curl_easy * parent,struct Curl_easy * child)2444 void Curl_http2_remove_child(struct Curl_easy *parent, struct Curl_easy *child)
2445 {
2446   struct Curl_http2_dep *last = 0;
2447   struct Curl_http2_dep *data = parent->set.stream_dependents;
2448   DEBUGASSERT(child->set.stream_depends_on == parent);
2449 
2450   while(data && data->data != child) {
2451     last = data;
2452     data = data->next;
2453   }
2454 
2455   DEBUGASSERT(data);
2456 
2457   if(data) {
2458     if(last) {
2459       last->next = data->next;
2460     }
2461     else {
2462       parent->set.stream_dependents = data->next;
2463     }
2464     free(data);
2465   }
2466 
2467   child->set.stream_depends_on = 0;
2468   child->set.stream_depends_e = FALSE;
2469 }
2470 
Curl_http2_cleanup_dependencies(struct Curl_easy * data)2471 void Curl_http2_cleanup_dependencies(struct Curl_easy *data)
2472 {
2473   while(data->set.stream_dependents) {
2474     struct Curl_easy *tmp = data->set.stream_dependents->data;
2475     Curl_http2_remove_child(data, tmp);
2476     if(data->set.stream_depends_on)
2477       Curl_http2_add_child(data->set.stream_depends_on, tmp, FALSE);
2478   }
2479 
2480   if(data->set.stream_depends_on)
2481     Curl_http2_remove_child(data->set.stream_depends_on, data);
2482 }
2483 
2484 /* Only call this function for a transfer that already got a HTTP/2
2485    CURLE_HTTP2_STREAM error! */
Curl_h2_http_1_1_error(struct Curl_easy * data)2486 bool Curl_h2_http_1_1_error(struct Curl_easy *data)
2487 {
2488   struct HTTP *stream = data->req.p.http;
2489   return (stream->error == NGHTTP2_HTTP_1_1_REQUIRED);
2490 }
2491 
2492 #else /* !USE_NGHTTP2 */
2493 
2494 /* Satisfy external references even if http2 is not compiled in. */
2495 #include <curl/curl.h>
2496 
curl_pushheader_bynum(struct curl_pushheaders * h,size_t num)2497 char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
2498 {
2499   (void) h;
2500   (void) num;
2501   return NULL;
2502 }
2503 
curl_pushheader_byname(struct curl_pushheaders * h,const char * header)2504 char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
2505 {
2506   (void) h;
2507   (void) header;
2508   return NULL;
2509 }
2510 
2511 #endif /* USE_NGHTTP2 */
2512