Exemple #1
0
CURLcode Curl_http2_switched(struct connectdata *conn,
                             const char *mem, size_t nread)
{
  CURLcode result;
  struct http_conn *httpc = &conn->proto.httpc;
  int rv;
  struct SessionHandle *data = conn->data;
  struct HTTP *stream = conn->data->req.protop;

  result = Curl_http2_setup(conn);
  if(result)
    return result;

  httpc->recv_underlying = (recving)conn->recv[FIRSTSOCKET];
  httpc->send_underlying = (sending)conn->send[FIRSTSOCKET];
  conn->recv[FIRSTSOCKET] = http2_recv;
  conn->send[FIRSTSOCKET] = http2_send;

  if(conn->data->req.upgr101 == UPGR101_RECEIVED) {
    /* stream 1 is opened implicitly on upgrade */
    stream->stream_id = 1;
    /* queue SETTINGS frame (again) */
    rv = nghttp2_session_upgrade(httpc->h2, httpc->binsettings,
                                 httpc->binlen, NULL);
    if(rv != 0) {
      failf(data, "nghttp2_session_upgrade() failed: %s(%d)",
            nghttp2_strerror(rv), rv);
      return CURLE_HTTP2;
    }
  }
  else {
    /* stream ID is unknown at this point */
    stream->stream_id = -1;
    rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE, NULL, 0);
    if(rv != 0) {
      failf(data, "nghttp2_submit_settings() failed: %s(%d)",
            nghttp2_strerror(rv), rv);
      return CURLE_HTTP2;
    }
  }

  rv = (int)nghttp2_session_mem_recv(httpc->h2, (const uint8_t*)mem, nread);

  if(rv != (int)nread) {
    failf(data, "nghttp2_session_mem_recv() failed: %s(%d)",
          nghttp2_strerror(rv), rv);
    return CURLE_HTTP2;
  }

  /* Try to send some frames since we may read SETTINGS already. */
  rv = nghttp2_session_send(httpc->h2);

  if(rv != 0) {
    failf(data, "nghttp2_session_send() failed: %s(%d)",
          nghttp2_strerror(rv), rv);
    return CURLE_HTTP2;
  }

  return CURLE_OK;
}
Exemple #2
0
static void send_client_connection_header(http2_session_data *session_data) {
  nghttp2_settings_entry iv[1] = {
      {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
  int rv;

  /* client 24 bytes magic string will be sent by nghttp2 library */
  rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv,
                               ARRLEN(iv));
  if (rv != 0) {
    errx(1, "Could not submit SETTINGS: %s", nghttp2_strerror(rv));
  }
}
Exemple #3
0
static
void newconn(struct evconnlistener *lev, evutil_socket_t sock, struct sockaddr *cli, int socklen, void *raw)
{
    server *serv = raw;
    session *sess;
    printf("New client\n");
    sess = calloc(1, sizeof(*sess));
    if(sess) {
        sess->serv = serv;
        sess->S.build_stream = buildstream;
        sess->S.cleanup = &cleanup_session;
        /* periodic timer */
        sess->pingtimer = event_new(serv->base, -1, EV_PERSIST, pingconn, sess);
        assert(sess->pingtimer);
        sess->S.bev = bufferevent_socket_new(serv->base, sock, BEV_OPT_CLOSE_ON_FREE);
        if(sess->S.bev) {
            h2session_setup_bev(&sess->S);
            bufferevent_enable(sess->S.bev, EV_READ);

            if(prepare_h2_session(sess)) {
                bufferevent_free(sess->S.bev);
                free(sess);
                printf("Client failed\n");
                return;

            } else {
                nghttp2_settings_entry iv[] = {
                    {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100},
                    {NGHTTP2_SETTINGS_ENABLE_PUSH, 0}
                };
                int rv;

                if ((rv=nghttp2_submit_settings(sess->S.h2sess, NGHTTP2_FLAG_NONE, iv, ARRLEN(iv))) ||
                        (rv=nghttp2_session_send(sess->S.h2sess)))
                {
                    printf("submit error: %s", nghttp2_strerror(rv));
                    cleanup_session(&sess->S);
                } else {
                    const struct timeval itvl = {5,0};
                    printf("Connection ready\n");
                    evtimer_add(sess->pingtimer, &itvl);
                }
            }
        }
    }
    if(!sess || !sess->S.bev) {
        fprintf(stderr, "No memory\n");
        free(sess);
        close(sock);
        return;
    }
}
Exemple #4
0
/* Send HTTP/2 client connection header, which includes 24 bytes
   magic octets and SETTINGS frame */
static int send_server_connection_header(http2_session_data *session_data) {
  nghttp2_settings_entry iv[1] = {
      {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
  int rv;

  rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv,
                               ARRLEN(iv));
  if (rv != 0) {
    warnx("Fatal error: %s", nghttp2_strerror(rv));
    return -1;
  }
  return 0;
}
Exemple #5
0
CURLcode Curl_http2_switched(struct connectdata *conn)
{
  CURLcode rc;
  struct http_conn *httpc = &conn->proto.httpc;
  int rv;
  struct SessionHandle *data = conn->data;

  httpc->recv_underlying = (recving)conn->recv[FIRSTSOCKET];
  httpc->send_underlying = (sending)conn->send[FIRSTSOCKET];
  conn->recv[FIRSTSOCKET] = http2_recv;
  conn->send[FIRSTSOCKET] = http2_send;

  rv = (int) ((Curl_send*)httpc->send_underlying)
    (conn, FIRSTSOCKET,
     NGHTTP2_CLIENT_CONNECTION_PREFACE,
     NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN,
     &rc);
  if(rc)
    /* TODO: This may get CURLE_AGAIN */
    return rc;

  if(rv != 24) {
    failf(data, "Only sent partial HTTP2 packet");
    return CURLE_SEND_ERROR;
  }

  if(conn->data->req.upgr101 == UPGR101_RECEIVED) {
    /* stream 1 is opened implicitly on upgrade */
    httpc->stream_id = 1;
    /* queue SETTINGS frame (again) */
    rv = nghttp2_session_upgrade(httpc->h2, httpc->binsettings,
                                 httpc->binlen, NULL);
    if(rv != 0) {
      failf(data, "nghttp2_session_upgrade() failed: %s(%d)",
            nghttp2_strerror(rv), rv);
      return CURLE_HTTP2;
    }
  }
  else {
    /* stream ID is unknown at this point */
    httpc->stream_id = -1;
    rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE, NULL, 0);
    if(rv != 0) {
      failf(data, "nghttp2_submit_settings() failed: %s(%d)",
            nghttp2_strerror(rv), rv);
      return CURLE_HTTP2;
    }
  }
  return CURLE_OK;
}
Exemple #6
0
static void send_client_connection_header(http2_session_data *session_data)
{
  nghttp2_settings_entry iv[1] = {
    { NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100 }
  };
  int rv;

  bufferevent_write(session_data->bev,
                    NGHTTP2_CLIENT_CONNECTION_PREFACE,
                    NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN);
  rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE,
                               iv, ARRLEN(iv));
  if(rv != 0) {
    errx(1, "Could not submit SETTINGS: %s", nghttp2_strerror(rv));
  }
}
Exemple #7
0
int Curl_http2_switched(struct connectdata *conn)
{
  int rv;
  CURLcode rc;
  struct http_conn *httpc = &conn->proto.httpc;
  /* we are switched! */
  /* Don't know this is needed here at this moment. Original
     handler->flags is still useful. */
  if(conn->handler->flags & PROTOPT_SSL)
    conn->handler = &Curl_handler_http2_ssl;
  else
    conn->handler = &Curl_handler_http2;

  httpc->recv_underlying = (recving)conn->recv[FIRSTSOCKET];
  httpc->send_underlying = (sending)conn->send[FIRSTSOCKET];
  conn->recv[FIRSTSOCKET] = http2_recv;
  conn->send[FIRSTSOCKET] = http2_send;
  infof(conn->data, "We have switched to HTTP2\n");
  httpc->bodystarted = FALSE;
  httpc->closed = FALSE;
  httpc->header_recvbuf = Curl_add_buffer_init();
  httpc->nread_header_recvbuf = 0;
  httpc->data = NULL;
  httpc->datalen = 0;
  httpc->upload_left = 0;
  httpc->upload_mem = NULL;
  httpc->upload_len = 0;

  conn->httpversion = 20;

  /* Put place holder for status line */
  Curl_add_buffer(httpc->header_recvbuf, "HTTP/2.0 200\r\n", 14);

  /* TODO: May get CURLE_AGAIN */
  rv = (int) ((Curl_send*)httpc->send_underlying)
    (conn, FIRSTSOCKET,
     NGHTTP2_CLIENT_CONNECTION_HEADER,
     NGHTTP2_CLIENT_CONNECTION_HEADER_LEN,
     &rc);
  assert(rv == 24);
  if(conn->data->req.upgr101 == UPGR101_RECEIVED) {
    /* stream 1 is opened implicitly on upgrade */
    httpc->stream_id = 1;
    /* queue SETTINGS frame (again) */
    rv = nghttp2_session_upgrade(httpc->h2, httpc->binsettings,
                                 httpc->binlen, NULL);
    if(rv != 0) {
      failf(conn->data, "nghttp2_session_upgrade() failed: %s(%d)",
            nghttp2_strerror(rv), rv);
      return -1;
    }
  }
  else {
    /* stream ID is unknown at this point */
    httpc->stream_id = -1;
    rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE, NULL, 0);
    if(rv != 0) {
      failf(conn->data, "nghttp2_submit_settings() failed: %s(%d)",
            nghttp2_strerror(rv), rv);
      return -1;
    }
  }
  return 0;
}
Exemple #8
0
apr_status_t h2_session_start(h2_session *session, int *rv)
{
    apr_status_t status = APR_SUCCESS;
    h2_config *config;
    nghttp2_settings_entry settings[3];
    
    AP_DEBUG_ASSERT(session);
    /* Start the conversation by submitting our SETTINGS frame */
    *rv = 0;
    config = h2_config_get(session->c);
    if (session->r) {
        const char *s, *cs;
        apr_size_t dlen; 
        h2_stream * stream;

        /* better for vhost matching */
        config = h2_config_rget(session->r);
        
        /* 'h2c' mode: we should have a 'HTTP2-Settings' header with
         * base64 encoded client settings. */
        s = apr_table_get(session->r->headers_in, "HTTP2-Settings");
        if (!s) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EINVAL, session->r,
                          APLOGNO(02931) 
                          "HTTP2-Settings header missing in request");
            return APR_EINVAL;
        }
        cs = NULL;
        dlen = h2_util_base64url_decode(&cs, s, session->pool);
        
        if (APLOGrdebug(session->r)) {
            char buffer[128];
            h2_util_hex_dump(buffer, 128, (char*)cs, dlen);
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, session->r,
                          "upgrading h2c session with HTTP2-Settings: %s -> %s (%d)",
                          s, buffer, (int)dlen);
        }
        
        *rv = nghttp2_session_upgrade(session->ngh2, (uint8_t*)cs, dlen, NULL);
        if (*rv != 0) {
            status = APR_EINVAL;
            ap_log_rerror(APLOG_MARK, APLOG_ERR, status, session->r,
                          APLOGNO(02932) "nghttp2_session_upgrade: %s", 
                          nghttp2_strerror(*rv));
            return status;
        }
        
        /* Now we need to auto-open stream 1 for the request we got. */
        *rv = stream_open(session, 1);
        if (*rv != 0) {
            status = APR_EGENERAL;
            ap_log_rerror(APLOG_MARK, APLOG_ERR, status, session->r,
                          APLOGNO(02933) "open stream 1: %s", 
                          nghttp2_strerror(*rv));
            return status;
        }
        
        stream = h2_stream_set_get(session->streams, 1);
        if (stream == NULL) {
            status = APR_EGENERAL;
            ap_log_rerror(APLOG_MARK, APLOG_ERR, status, session->r,
                          APLOGNO(02934) "lookup of stream 1");
            return status;
        }
        
        status = h2_stream_rwrite(stream, session->r);
        if (status != APR_SUCCESS) {
            return status;
        }
        status = stream_end_headers(session, stream, 1);
        if (status != APR_SUCCESS) {
            return status;
        }
    }

    settings[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
    settings[0].value = (uint32_t)session->max_stream_count;
    settings[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
    settings[1].value = h2_config_geti(config, H2_CONF_WIN_SIZE);
    settings[2].settings_id = NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE;
    settings[2].value = 64*1024;
    
    *rv = nghttp2_submit_settings(session->ngh2, NGHTTP2_FLAG_NONE,
                                 settings,
                                 sizeof(settings)/sizeof(settings[0]));
    if (*rv != 0) {
        status = APR_EGENERAL;
        ap_log_cerror(APLOG_MARK, APLOG_ERR, status, session->c,
                      APLOGNO(02935) "nghttp2_submit_settings: %s", 
                      nghttp2_strerror(*rv));
    }
    
    return status;
}
Exemple #9
0
    int nghttp2client_connect(httpclient *pclient, char *url, int port, http2_ssl_custom_conf_t *ssl_config, const struct URI *uri)
    {
        struct Connection connection;
        nghttp2_session_callbacks *callbacks;
        int rv;
        int ret = 0;
        struct Request req;
        request_init(&req, uri);

        if (0 == (ret = nghttp2s_client_conn(pclient, url, port, ssl_config))) {
            pclient->remote_port = HTTPS_PORT;
            nghttp2_socket.fd = pclient->fd.fd;
        } else {
            printf("https_client_conn failed %d\r\n", ret);
            /* Resource cleanup */
            mbedtls_ssl_close_notify( &(pclient->ssl) );
            mbedtls_net_free( &pclient->fd );
            mbedtls_x509_crt_free( &(ssl_config->verify_source.cacertl) );
            mbedtls_ssl_free( &(pclient->ssl) );
            mbedtls_ssl_config_free( &(ssl_config->conf) );
            mbedtls_ctr_drbg_free(&ctr_drbg);
            mbedtls_entropy_free(&entropy);
            request_free(&req);
            return ret;

        }

        //set_tcp_nodelay(nghttp2_socket.fd);

        connection.ssl = &(pclient->ssl);
        rv = nghttp2_session_callbacks_new(&callbacks);

        if (rv != 0) {
            printf("nghttp2_session_callbacks_new1 %d", rv);
        }

        setup_nghttp2_callbacks(callbacks);
        rv = nghttp2_session_client_new(&connection.session, callbacks, &connection);


        nghttp2_session_callbacks_del(callbacks);

        if (rv != 0) {
            printf("nghttp2_session_client_new2 %d", rv);
        }

        nghttp2_submit_settings(connection.session, NGHTTP2_FLAG_NONE, NULL, 0);

        /* Submit the HTTP request to the outbound queue. */

        submit_request(&connection, &req);

        /* Event loop */
        while (1) {
            int read_flag = 0;
            int write_flag = 0;

            write_flag = nghttp2_session_want_write(connection.session);
            if (write_flag) {
                int rv = nghttp2_session_send(connection.session);
                printf("nghttp2_session_send %d\r\n", rv);
                if (rv < 0) {
                    write_flag = 0;
                    //break;
                }
            }

            read_flag = nghttp2_session_want_read(connection.session);
            if (read_flag) {
                int rv = nghttp2_session_recv(connection.session);
                printf("nghttp2_session_recv %d\r\n", rv);
                if (rv < 0) {
                    read_flag = 0;
                    //break;
                }
            }

            printf("write_flag = %d, read_flag = %d\r\n", write_flag, read_flag);

            if ((read_flag == 0) && (write_flag == 0)) {
                printf("No active stream!\r\n");
                break;
            }
        }

        /* Resource cleanup */

        nghttp2_session_del(connection.session);

        mbedtls_ssl_close_notify( &(pclient->ssl) );
        mbedtls_net_free( &pclient->fd );
        mbedtls_x509_crt_free( &(ssl_config->verify_source.cacertl) );
        mbedtls_ssl_free( &(pclient->ssl) );
        mbedtls_ssl_config_free( &(ssl_config->conf) );
        mbedtls_ctr_drbg_free(&ctr_drbg);
        mbedtls_entropy_free(&entropy);

        request_free(&req);
        return 0;

    }
Exemple #10
0
apr_status_t h2_session_start(h2_session *session)
{
    assert(session);
    /* Start the conversation by submitting our SETTINGS frame */
    apr_status_t status = APR_SUCCESS;
    h2_config *config = h2_config_get(session->c);
    int rv = 0;
    
    if (session->r) {
        /* 'h2c' mode: we should have a 'HTTP2-Settings' header with
         * base64 encoded client settings. */
        const char *s = apr_table_get(session->r->headers_in, "HTTP2-Settings");
        if (!s) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EINVAL, session->r,
                          "HTTP2-Settings header missing in request");
            return APR_EINVAL;
        }
        int cslen = apr_base64_decode_len(s);
        char *cs = apr_pcalloc(session->r->pool, cslen);
        --cslen; /* apr also counts the terminating 0 */
        apr_base64_decode(cs, s);
        
        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, session->r,
                      "upgrading h2c session with nghttp2 from %s (%d)",
                      s, cslen);
        
        rv = nghttp2_session_upgrade(session->ngh2, (uint8_t*)cs, cslen, NULL);
        if (rv != 0) {
            status = APR_EGENERAL;
            ap_log_rerror(APLOG_MARK, APLOG_ERR, status, session->r,
                          "nghttp2_session_upgrade: %s", nghttp2_strerror(rv));
            return status;
        }
        
        /* Now we need to auto-open stream 1 for the request we got. */
        rv = stream_open(session, 1);
        if (rv != 0) {
            status = APR_EGENERAL;
            ap_log_rerror(APLOG_MARK, APLOG_ERR, status, session->r,
                          "open stream 1: %s", nghttp2_strerror(rv));
            return status;
        }
        
        h2_stream * stream = h2_stream_set_get(session->streams, 1);
        if (stream == NULL) {
            status = APR_EGENERAL;
            ap_log_rerror(APLOG_MARK, APLOG_ERR, status, session->r,
                          "lookup of stream 1");
            return status;
        }
        
        status = h2_stream_rwrite(stream, session->r);
        if (status != APR_SUCCESS) {
            return status;
        }
        status = stream_end_headers(session, stream, 1);
        if (status != APR_SUCCESS) {
            return status;
        }
        status = h2_stream_write_eos(stream);
        if (status != APR_SUCCESS) {
            return status;
        }
    }

    nghttp2_settings_entry settings[] = {
        { NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
            h2_config_geti(config, H2_CONF_MAX_HL_SIZE) },
        { NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
            h2_config_geti(config, H2_CONF_WIN_SIZE) },
        {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 
            h2_config_geti(config, H2_CONF_MAX_STREAMS) }, 
    };
    rv = nghttp2_submit_settings(session->ngh2, NGHTTP2_FLAG_NONE,
                                 settings,
                                 sizeof(settings)/sizeof(settings[0]));
    if (rv != 0) {
        status = APR_EGENERAL;
        ap_log_cerror(APLOG_MARK, APLOG_ERR, status, session->c,
                      "nghttp2_submit_settings: %s", nghttp2_strerror(rv));
    }
    
    return status;
}
Exemple #11
0
/*
 * Fetches the resource denoted by |uri|.
 */
static void fetch_uri(const struct URI *uri) {
  nghttp2_session_callbacks *callbacks;
  int fd;
  SSL_CTX *ssl_ctx;
  SSL *ssl;
  struct Request req;
  struct Connection connection;
  int rv;
  nfds_t npollfds = 1;
  struct pollfd pollfds[1];

  request_init(&req, uri);

  /* Establish connection and setup SSL */
  fd = connect_to(req.host, req.port);
  if (fd == -1) {
    die("Could not open file descriptor");
  }
  ssl_ctx = SSL_CTX_new(SSLv23_client_method());
  if (ssl_ctx == NULL) {
    dief("SSL_CTX_new", ERR_error_string(ERR_get_error(), NULL));
  }
  init_ssl_ctx(ssl_ctx);
  ssl = SSL_new(ssl_ctx);
  if (ssl == NULL) {
    dief("SSL_new", ERR_error_string(ERR_get_error(), NULL));
  }
  /* To simplify the program, we perform SSL/TLS handshake in blocking
     I/O. */
  ssl_handshake(ssl, fd);

  connection.ssl = ssl;
  connection.want_io = IO_NONE;

  /* Here make file descriptor non-block */
  make_non_block(fd);
  set_tcp_nodelay(fd);

  printf("[INFO] SSL/TLS handshake completed\n");

  rv = nghttp2_session_callbacks_new(&callbacks);

  if (rv != 0) {
    diec("nghttp2_session_callbacks_new", rv);
  }

  setup_nghttp2_callbacks(callbacks);

  rv = nghttp2_session_client_new(&connection.session, callbacks, &connection);

  nghttp2_session_callbacks_del(callbacks);

  if (rv != 0) {
    diec("nghttp2_session_client_new", rv);
  }

  rv = nghttp2_submit_settings(connection.session, NGHTTP2_FLAG_NONE, NULL, 0);

  if (rv != 0) {
    diec("nghttp2_submit_settings", rv);
  }

  /* Submit the HTTP request to the outbound queue. */
  submit_request(&connection, &req);

  pollfds[0].fd = fd;
  ctl_poll(pollfds, &connection);

  /* Event loop */
  while (nghttp2_session_want_read(connection.session) ||
         nghttp2_session_want_write(connection.session)) {
    int nfds = poll(pollfds, npollfds, -1);
    if (nfds == -1) {
      dief("poll", strerror(errno));
    }
    if (pollfds[0].revents & (POLLIN | POLLOUT)) {
      exec_io(&connection);
    }
    if ((pollfds[0].revents & POLLHUP) || (pollfds[0].revents & POLLERR)) {
      die("Connection error");
    }
    ctl_poll(pollfds, &connection);
  }

  /* Resource cleanup */
  nghttp2_session_del(connection.session);
  SSL_shutdown(ssl);
  SSL_free(ssl);
  SSL_CTX_free(ssl_ctx);
  shutdown(fd, SHUT_WR);
  close(fd);
  request_free(&req);
}
Exemple #12
0
CURLcode Curl_http2_switched(struct connectdata *conn,
                             const char *mem, size_t nread)
{
  CURLcode result;
  struct http_conn *httpc = &conn->proto.httpc;
  int rv;
  ssize_t nproc;
  struct SessionHandle *data = conn->data;
  struct HTTP *stream = conn->data->req.protop;

  result = Curl_http2_setup(conn);
  if(result)
    return result;

  httpc->recv_underlying = (recving)conn->recv[FIRSTSOCKET];
  httpc->send_underlying = (sending)conn->send[FIRSTSOCKET];
  conn->recv[FIRSTSOCKET] = http2_recv;
  conn->send[FIRSTSOCKET] = http2_send;

  if(conn->data->req.upgr101 == UPGR101_RECEIVED) {
    /* stream 1 is opened implicitly on upgrade */
    stream->stream_id = 1;
    /* queue SETTINGS frame (again) */
    rv = nghttp2_session_upgrade(httpc->h2, httpc->binsettings,
                                 httpc->binlen, NULL);
    if(rv != 0) {
      failf(data, "nghttp2_session_upgrade() failed: %s(%d)",
            nghttp2_strerror(rv), rv);
      return CURLE_HTTP2;
    }

    nghttp2_session_set_stream_user_data(httpc->h2,
                                         stream->stream_id,
                                         conn->data);
  }
  else {
    /* stream ID is unknown at this point */
    stream->stream_id = -1;
    rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE, NULL, 0);
    if(rv != 0) {
      failf(data, "nghttp2_submit_settings() failed: %s(%d)",
            nghttp2_strerror(rv), rv);
      return CURLE_HTTP2;
    }
  }

  /* we are going to copy mem to httpc->inbuf.  This is required since
     mem is part of buffer pointed by stream->mem, and callbacks
     called by nghttp2_session_mem_recv() will write stream specific
     data into stream->mem, overwriting data already there. */
  if(H2_BUFSIZE < nread) {
    failf(data, "connection buffer size is too small to store data following "
                "HTTP Upgrade response header: buflen=%zu, datalen=%zu",
          H2_BUFSIZE, nread);
    return CURLE_HTTP2;
  }

  infof(conn->data, "Copying HTTP/2 data in stream buffer to connection buffer"
                    " after upgrade: len=%zu\n",
        nread);

  memcpy(httpc->inbuf, mem, nread);
  httpc->inbuflen = nread;

  nproc = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)httpc->inbuf,
                                   httpc->inbuflen);

  if(nghttp2_is_fatal((int)nproc)) {
    failf(data, "nghttp2_session_mem_recv() failed: %s(%d)",
          nghttp2_strerror((int)nproc), (int)nproc);
    return CURLE_HTTP2;
  }

  DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", nproc));

  if((ssize_t)nread == nproc) {
    httpc->inbuflen = 0;
    httpc->nread_inbuf = 0;
  }
  else {
    httpc->nread_inbuf += nproc;
  }

  /* Try to send some frames since we may read SETTINGS already. */
  rv = nghttp2_session_send(httpc->h2);

  if(rv != 0) {
    failf(data, "nghttp2_session_send() failed: %s(%d)",
          nghttp2_strerror(rv), rv);
    return CURLE_HTTP2;
  }

  return CURLE_OK;
}
Exemple #13
0
static void run_nghttp2_session_send(void) {
  nghttp2_session *session;
  nghttp2_session_callbacks callbacks;
  nghttp2_nv nv[] = {MAKE_NV(":host", "example.org"),
                     MAKE_NV(":scheme", "https")};
  nghttp2_data_provider data_prd;
  nghttp2_settings_entry iv[2];
  my_user_data ud;
  int rv;
  memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
  callbacks.send_callback = null_send_callback;

  data_prd.read_callback = fixed_length_data_source_read_callback;
  ud.data_source_length = 64 * 1024;

  iv[0].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
  iv[0].value = 4096;
  iv[1].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
  iv[1].value = 100;

  rv = nghttp2_session_client_new3(&session, &callbacks, &ud, NULL,
                                   nghttp2_mem_fm());
  if (rv != 0) {
    goto client_new_fail;
  }
  rv = nghttp2_submit_request(session, NULL, nv, ARRLEN(nv), &data_prd, NULL);
  if (rv < 0) {
    goto fail;
  }
  rv = nghttp2_submit_headers(session, NGHTTP2_FLAG_NONE, -1, NULL, nv,
                              ARRLEN(nv), NULL);
  if (rv < 0) {
    goto fail;
  }
  rv = nghttp2_session_send(session);
  if (rv != 0) {
    goto fail;
  }
  /* The HEADERS submitted by the previous nghttp2_submit_headers will
     have stream ID 3. Send HEADERS to that stream. */
  rv = nghttp2_submit_headers(session, NGHTTP2_FLAG_NONE, 3, NULL, nv,
                              ARRLEN(nv), NULL);
  if (rv != 0) {
    goto fail;
  }
  rv = nghttp2_submit_data(session, NGHTTP2_FLAG_END_STREAM, 3, &data_prd);
  if (rv != 0) {
    goto fail;
  }
  rv = nghttp2_session_send(session);
  if (rv != 0) {
    goto fail;
  }
  rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, 3, NGHTTP2_CANCEL);
  if (rv != 0) {
    goto fail;
  }
  rv = nghttp2_session_send(session);
  if (rv != 0) {
    goto fail;
  }
  /* Sending against half-closed stream */
  rv = nghttp2_submit_headers(session, NGHTTP2_FLAG_NONE, 3, NULL, nv,
                              ARRLEN(nv), NULL);
  if (rv != 0) {
    goto fail;
  }
  rv = nghttp2_submit_data(session, NGHTTP2_FLAG_END_STREAM, 3, &data_prd);
  if (rv != 0) {
    goto fail;
  }
  rv = nghttp2_submit_ping(session, NGHTTP2_FLAG_NONE, NULL);
  if (rv != 0) {
    goto fail;
  }
  rv = nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 2);
  if (rv != 0) {
    goto fail;
  }
  rv = nghttp2_session_send(session);
  if (rv != 0) {
    goto fail;
  }
  rv = nghttp2_submit_goaway(session, NGHTTP2_FLAG_NONE, 100, NGHTTP2_NO_ERROR,
                             NULL, 0);
  if (rv != 0) {
    goto fail;
  }
  rv = nghttp2_session_send(session);
  if (rv != 0) {
    goto fail;
  }

fail:
  nghttp2_session_del(session);
client_new_fail:;
}