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