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