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


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:15