Annotation of embedaddon/curl/lib/http2.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>