examples: Rewrite client example
This commit is contained in:
parent
d192a602f4
commit
666ab068ff
|
@ -20,7 +20,7 @@
|
||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
SUBDIRS = lib src tests doc
|
SUBDIRS = lib src examples tests doc
|
||||||
|
|
||||||
ACLOCAL_AMFLAGS = -I m4
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
|
|
||||||
|
|
|
@ -29,8 +29,8 @@ AM_CPPFLAGS = -Wall -I$(srcdir)/../lib/includes -I$(builddir)/../lib/includes \
|
||||||
AM_LDFLAGS = @OPENSSL_LIBS@
|
AM_LDFLAGS = @OPENSSL_LIBS@
|
||||||
LDADD = $(top_builddir)/lib/libnghttp2.la
|
LDADD = $(top_builddir)/lib/libnghttp2.la
|
||||||
|
|
||||||
noinst_PROGRAMS = spdycli
|
noinst_PROGRAMS = client
|
||||||
spdycli_SOURCES = spdycli.c
|
client_SOURCES = client.c
|
||||||
|
|
||||||
endif # ENABLE_EXAMPLES
|
endif # ENABLE_EXAMPLES
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* nghttp2 - SPDY Library
|
* nghttp2 - HTTP/2.0 C Library
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
* Copyright (c) 2013 Tatsuhiro Tsujikawa
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
* a copy of this software and associated documentation files (the
|
* a copy of this software and associated documentation files (the
|
||||||
|
@ -54,12 +54,12 @@ enum {
|
||||||
struct Connection {
|
struct Connection {
|
||||||
SSL *ssl;
|
SSL *ssl;
|
||||||
nghttp2_session *session;
|
nghttp2_session *session;
|
||||||
/* WANT_READ if SSL connection needs more input; or WANT_WRITE if it
|
/* WANT_READ if SSL/TLS connection needs more input; or WANT_WRITE
|
||||||
needs more output; or IO_NONE. This is necessary because SSL/TLS
|
if it needs more output; or IO_NONE. This is necessary because
|
||||||
re-negotiation is possible at any time. nghttp2 API offers
|
SSL/TLS re-negotiation is possible at any time. nghttp2 API
|
||||||
similar functions like nghttp2_session_want_read() and
|
offers similar functions like nghttp2_session_want_read() and
|
||||||
nghttp2_session_want_write() but they do not take into account
|
nghttp2_session_want_write() but they do not take into account
|
||||||
SSL connection. */
|
SSL/TSL connection. */
|
||||||
int want_io;
|
int want_io;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -131,29 +131,33 @@ static void diec(const char *func, int error_code)
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char CONTENT_LENGTH[] = "content-encoding";
|
||||||
|
static size_t CONTENT_LENGTH_LEN = sizeof(CONTENT_LENGTH) - 1;
|
||||||
|
static char GZIP[] = "gzip";
|
||||||
|
static size_t GZIP_LEN = sizeof(GZIP) - 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check response is content-encoding: gzip. We need this because SPDY
|
* Check response is content-encoding: gzip. We need this because
|
||||||
* client is required to support gzip.
|
* HTTP/2.0 client is required to support gzip.
|
||||||
*/
|
*/
|
||||||
static void check_gzip(struct Request *req, char **nv)
|
static void check_gzip(struct Request *req, nghttp2_nv *nva, size_t nvlen)
|
||||||
{
|
{
|
||||||
int gzip = 0;
|
|
||||||
size_t i;
|
size_t i;
|
||||||
for(i = 0; nv[i]; i += 2) {
|
|
||||||
if(strcmp("content-encoding", nv[i]) == 0) {
|
|
||||||
gzip = strcmp("gzip", nv[i+1]) == 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(gzip) {
|
|
||||||
int rv;
|
|
||||||
if(req->inflater) {
|
if(req->inflater) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
for(i = 0; i < nvlen; ++i) {
|
||||||
|
if(CONTENT_LENGTH_LEN == nva[i].namelen &&
|
||||||
|
memcmp(CONTENT_LENGTH, nva[i].name, nva[i].namelen) == 0 &&
|
||||||
|
GZIP_LEN == nva[i].valuelen &&
|
||||||
|
memcmp(GZIP, nva[i].value, nva[i].valuelen) == 0) {
|
||||||
|
int rv;
|
||||||
rv = nghttp2_gzip_inflate_new(&req->inflater);
|
rv = nghttp2_gzip_inflate_new(&req->inflater);
|
||||||
if(rv != 0) {
|
if(rv != 0) {
|
||||||
die("Can't allocate inflate stream.");
|
die("Can't allocate inflate stream.");
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,86 +222,85 @@ static ssize_t recv_callback(nghttp2_session *session,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The implementation of nghttp2_before_ctrl_send_callback type. We
|
* The implementation of nghttp2_before_frame_send_callback type. We
|
||||||
* use this function to get stream ID of the request. This is because
|
* use this function to get stream ID of the request. This is because
|
||||||
* stream ID is not known when we submit the request
|
* stream ID is not known when we submit the request
|
||||||
* (nghttp2_submit_request).
|
* (nghttp2_submit_request).
|
||||||
*/
|
*/
|
||||||
static void before_ctrl_send_callback(nghttp2_session *session,
|
static int before_frame_send_callback(nghttp2_session *session,
|
||||||
nghttp2_frame_type type,
|
|
||||||
nghttp2_frame *frame,
|
nghttp2_frame *frame,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
if(type == NGHTTP2_SYN_STREAM) {
|
if(frame->hd.type == NGHTTP2_HEADERS &&
|
||||||
|
frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
|
||||||
struct Request *req;
|
struct Request *req;
|
||||||
int stream_id = frame->syn_stream.stream_id;
|
int32_t stream_id = frame->hd.stream_id;
|
||||||
req = nghttp2_session_get_stream_user_data(session, stream_id);
|
req = nghttp2_session_get_stream_user_data(session, stream_id);
|
||||||
if(req && req->stream_id == -1) {
|
if(req && req->stream_id == -1) {
|
||||||
req->stream_id = stream_id;
|
req->stream_id = stream_id;
|
||||||
printf("[INFO] Stream ID = %d\n", stream_id);
|
printf("[INFO] Stream ID = %d\n", stream_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_ctrl_send_callback(nghttp2_session *session,
|
static int on_frame_send_callback(nghttp2_session *session,
|
||||||
nghttp2_frame_type type,
|
|
||||||
nghttp2_frame *frame, void *user_data)
|
nghttp2_frame *frame, void *user_data)
|
||||||
{
|
{
|
||||||
char **nv;
|
|
||||||
const char *name = NULL;
|
|
||||||
int32_t stream_id;
|
|
||||||
size_t i;
|
size_t i;
|
||||||
switch(type) {
|
switch(frame->hd.type) {
|
||||||
case NGHTTP2_SYN_STREAM:
|
|
||||||
nv = frame->syn_stream.nv;
|
|
||||||
name = "SYN_STREAM";
|
|
||||||
stream_id = frame->syn_stream.stream_id;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(name && nghttp2_session_get_stream_user_data(session, stream_id)) {
|
|
||||||
printf("[INFO] C ----------------------------> S (%s)\n", name);
|
|
||||||
for(i = 0; nv[i]; i += 2) {
|
|
||||||
printf(" %s: %s\n", nv[i], nv[i+1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void on_ctrl_recv_callback(nghttp2_session *session,
|
|
||||||
nghttp2_frame_type type,
|
|
||||||
nghttp2_frame *frame, void *user_data)
|
|
||||||
{
|
|
||||||
struct Request *req;
|
|
||||||
char **nv;
|
|
||||||
const char *name = NULL;
|
|
||||||
int32_t stream_id;
|
|
||||||
size_t i;
|
|
||||||
switch(type) {
|
|
||||||
case NGHTTP2_SYN_REPLY:
|
|
||||||
nv = frame->syn_reply.nv;
|
|
||||||
name = "SYN_REPLY";
|
|
||||||
stream_id = frame->syn_reply.stream_id;
|
|
||||||
break;
|
|
||||||
case NGHTTP2_HEADERS:
|
case NGHTTP2_HEADERS:
|
||||||
nv = frame->headers.nv;
|
if(nghttp2_session_get_stream_user_data(session, frame->hd.stream_id)) {
|
||||||
name = "HEADERS";
|
const nghttp2_nv *nva = frame->headers.nva;
|
||||||
stream_id = frame->headers.stream_id;
|
printf("[INFO] C ----------------------------> S (HEADERS)\n");
|
||||||
|
for(i = 0; i < frame->headers.nvlen; ++i) {
|
||||||
|
fwrite(nva[i].name, nva[i].namelen, 1, stdout);
|
||||||
|
printf(": ");
|
||||||
|
fwrite(nva[i].value, nva[i].valuelen, 1, stdout);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
case NGHTTP2_RST_STREAM:
|
||||||
|
printf("[INFO] C ----------------------------> S (RST_STREAM)\n");
|
||||||
|
break;
|
||||||
|
case NGHTTP2_GOAWAY:
|
||||||
|
printf("[INFO] C ----------------------------> S (GOAWAY)\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(!name) {
|
return 0;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
req = nghttp2_session_get_stream_user_data(session, stream_id);
|
static int on_frame_recv_callback(nghttp2_session *session,
|
||||||
|
nghttp2_frame *frame, void *user_data)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
switch(frame->hd.type) {
|
||||||
|
case NGHTTP2_HEADERS:
|
||||||
|
if(frame->headers.cat == NGHTTP2_HCAT_RESPONSE) {
|
||||||
|
const nghttp2_nv *nva = frame->headers.nva;
|
||||||
|
struct Request *req;
|
||||||
|
req = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
|
||||||
if(req) {
|
if(req) {
|
||||||
check_gzip(req, nv);
|
check_gzip(req, frame->headers.nva, frame->headers.nvlen);
|
||||||
printf("[INFO] C <---------------------------- S (%s)\n", name);
|
printf("[INFO] C <---------------------------- S (HEADERS)\n");
|
||||||
for(i = 0; nv[i]; i += 2) {
|
for(i = 0; i < frame->headers.nvlen; ++i) {
|
||||||
printf(" %s: %s\n", nv[i], nv[i+1]);
|
fwrite(nva[i].name, nva[i].namelen, 1, stdout);
|
||||||
|
printf(": ");
|
||||||
|
fwrite(nva[i].value, nva[i].valuelen, 1, stdout);
|
||||||
|
printf("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NGHTTP2_RST_STREAM:
|
||||||
|
printf("[INFO] C <---------------------------- S (RST_STREAM)\n");
|
||||||
|
break;
|
||||||
|
case NGHTTP2_GOAWAY:
|
||||||
|
printf("[INFO] C <---------------------------- S (GOAWAY)\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -306,20 +309,21 @@ static void on_ctrl_recv_callback(nghttp2_session *session,
|
||||||
* fetch 1 resource in this program, after reception of the response,
|
* fetch 1 resource in this program, after reception of the response,
|
||||||
* we submit GOAWAY and close the session.
|
* we submit GOAWAY and close the session.
|
||||||
*/
|
*/
|
||||||
static void on_stream_close_callback(nghttp2_session *session,
|
static int on_stream_close_callback(nghttp2_session *session,
|
||||||
int32_t stream_id,
|
int32_t stream_id,
|
||||||
nghttp2_status_code status_code,
|
nghttp2_error_code error_code,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct Request *req;
|
struct Request *req;
|
||||||
req = nghttp2_session_get_stream_user_data(session, stream_id);
|
req = nghttp2_session_get_stream_user_data(session, stream_id);
|
||||||
if(req) {
|
if(req) {
|
||||||
int rv;
|
int rv;
|
||||||
rv = nghttp2_submit_goaway(session, NGHTTP2_GOAWAY_OK);
|
rv = nghttp2_submit_goaway(session, NGHTTP2_NO_ERROR, NULL, 0);
|
||||||
if(rv != 0) {
|
if(rv != 0) {
|
||||||
diec("nghttp2_submit_goaway", rv);
|
diec("nghttp2_submit_goaway", rv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAX_OUTLEN 4096
|
#define MAX_OUTLEN 4096
|
||||||
|
@ -328,7 +332,7 @@ static void on_stream_close_callback(nghttp2_session *session,
|
||||||
* The implementation of nghttp2_on_data_chunk_recv_callback type. We
|
* The implementation of nghttp2_on_data_chunk_recv_callback type. We
|
||||||
* use this function to print the received response body.
|
* use this function to print the received response body.
|
||||||
*/
|
*/
|
||||||
static void on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
|
static int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
|
||||||
int32_t stream_id,
|
int32_t stream_id,
|
||||||
const uint8_t *data, size_t len,
|
const uint8_t *data, size_t len,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
|
@ -336,8 +340,8 @@ static void on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
|
||||||
struct Request *req;
|
struct Request *req;
|
||||||
req = nghttp2_session_get_stream_user_data(session, stream_id);
|
req = nghttp2_session_get_stream_user_data(session, stream_id);
|
||||||
if(req) {
|
if(req) {
|
||||||
printf("[INFO] C <---------------------------- S (DATA)\n");
|
printf("[INFO] C <---------------------------- S (DATA chunk)\n"
|
||||||
printf(" %lu bytes\n", (unsigned long int)len);
|
"%lu bytes\n", (unsigned long int)len);
|
||||||
if(req->inflater) {
|
if(req->inflater) {
|
||||||
while(len > 0) {
|
while(len > 0) {
|
||||||
uint8_t out[MAX_OUTLEN];
|
uint8_t out[MAX_OUTLEN];
|
||||||
|
@ -354,11 +358,11 @@ static void on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
|
||||||
len -= tlen;
|
len -= tlen;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* TODO add support gzip */
|
|
||||||
fwrite(data, 1, len, stdout);
|
fwrite(data, 1, len, stdout);
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -372,16 +376,16 @@ static void setup_nghttp2_callbacks(nghttp2_session_callbacks *callbacks)
|
||||||
memset(callbacks, 0, sizeof(nghttp2_session_callbacks));
|
memset(callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||||
callbacks->send_callback = send_callback;
|
callbacks->send_callback = send_callback;
|
||||||
callbacks->recv_callback = recv_callback;
|
callbacks->recv_callback = recv_callback;
|
||||||
callbacks->before_ctrl_send_callback = before_ctrl_send_callback;
|
callbacks->before_frame_send_callback = before_frame_send_callback;
|
||||||
callbacks->on_ctrl_send_callback = on_ctrl_send_callback;
|
callbacks->on_frame_send_callback = on_frame_send_callback;
|
||||||
callbacks->on_ctrl_recv_callback = on_ctrl_recv_callback;
|
callbacks->on_frame_recv_callback = on_frame_recv_callback;
|
||||||
callbacks->on_stream_close_callback = on_stream_close_callback;
|
callbacks->on_stream_close_callback = on_stream_close_callback;
|
||||||
callbacks->on_data_chunk_recv_callback = on_data_chunk_recv_callback;
|
callbacks->on_data_chunk_recv_callback = on_data_chunk_recv_callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Callback function for SSL/TLS NPN. Since this program only supports
|
* Callback function for TLS NPN. Since this program only supports
|
||||||
* SPDY protocol, if server does not offer SPDY protocol the nghttp2
|
* HTTP/2.0 protocol, if server does not offer HTTP/2.0 the nghttp2
|
||||||
* library supports, we terminate program.
|
* library supports, we terminate program.
|
||||||
*/
|
*/
|
||||||
static int select_next_proto_cb(SSL* ssl,
|
static int select_next_proto_cb(SSL* ssl,
|
||||||
|
@ -390,31 +394,26 @@ static int select_next_proto_cb(SSL* ssl,
|
||||||
void *arg)
|
void *arg)
|
||||||
{
|
{
|
||||||
int rv;
|
int rv;
|
||||||
uint16_t *spdy_proto_version;
|
/* nghttp2_select_next_protocol() selects HTTP/2.0 protocol the
|
||||||
/* nghttp2_select_next_protocol() selects SPDY protocol version the
|
|
||||||
nghttp2 library supports. */
|
nghttp2 library supports. */
|
||||||
rv = nghttp2_select_next_protocol(out, outlen, in, inlen);
|
rv = nghttp2_select_next_protocol(out, outlen, in, inlen);
|
||||||
if(rv <= 0) {
|
if(rv <= 0) {
|
||||||
die("Server did not advertise spdy/2 or spdy/3 protocol.");
|
die("Server did not advertise HTTP/2.0 protocol");
|
||||||
}
|
}
|
||||||
spdy_proto_version = (uint16_t*)arg;
|
|
||||||
*spdy_proto_version = rv;
|
|
||||||
return SSL_TLSEXT_ERR_OK;
|
return SSL_TLSEXT_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup SSL context. We pass |spdy_proto_version| to get negotiated
|
* Setup SSL/TLS context.
|
||||||
* SPDY protocol version in NPN callback.
|
|
||||||
*/
|
*/
|
||||||
static void init_ssl_ctx(SSL_CTX *ssl_ctx, uint16_t *spdy_proto_version)
|
static void init_ssl_ctx(SSL_CTX *ssl_ctx)
|
||||||
{
|
{
|
||||||
/* Disable SSLv2 and enable all workarounds for buggy servers */
|
/* Disable SSLv2 and enable all workarounds for buggy servers */
|
||||||
SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2);
|
SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2);
|
||||||
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
|
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
|
||||||
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
|
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
|
||||||
/* Set NPN callback */
|
/* Set NPN callback */
|
||||||
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb,
|
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL);
|
||||||
spdy_proto_version);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ssl_handshake(SSL *ssl, int fd)
|
static void ssl_handshake(SSL *ssl, int fd)
|
||||||
|
@ -479,9 +478,6 @@ static void make_non_block(int fd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Setting TCP_NODELAY is not mandatory for the SPDY protocol.
|
|
||||||
*/
|
|
||||||
static void set_tcp_nodelay(int fd)
|
static void set_tcp_nodelay(int fd)
|
||||||
{
|
{
|
||||||
int val = 1;
|
int val = 1;
|
||||||
|
@ -517,18 +513,15 @@ static void submit_request(struct Connection *connection, struct Request *req)
|
||||||
{
|
{
|
||||||
int pri = 0;
|
int pri = 0;
|
||||||
int rv;
|
int rv;
|
||||||
const char *nv[15];
|
const char *nv[13];
|
||||||
/* We always use SPDY/3 style header even if the negotiated protocol
|
/* Make sure that the last item is NULL */
|
||||||
version is SPDY/2. The library translates the header name as
|
|
||||||
necessary. Make sure that the last item is NULL! */
|
|
||||||
nv[0] = ":method"; nv[1] = "GET";
|
nv[0] = ":method"; nv[1] = "GET";
|
||||||
nv[2] = ":path"; nv[3] = req->path;
|
nv[2] = ":path"; nv[3] = req->path;
|
||||||
nv[4] = ":version"; nv[5] = "HTTP/1.1";
|
nv[4] = ":scheme"; nv[5] = "https";
|
||||||
nv[6] = ":scheme"; nv[7] = "https";
|
nv[6] = ":host"; nv[7] = req->hostport;
|
||||||
nv[8] = ":host"; nv[9] = req->hostport;
|
nv[8] = "accept"; nv[9] = "*/*";
|
||||||
nv[10] = "accept"; nv[11] = "*/*";
|
nv[10] = "user-agent"; nv[11] = "nghttp2/"NGHTTP2_VERSION;
|
||||||
nv[12] = "user-agent"; nv[13] = "nghttp2/"NGHTTP2_VERSION;
|
nv[12] = NULL;
|
||||||
nv[14] = NULL;
|
|
||||||
rv = nghttp2_submit_request(connection->session, pri, nv, NULL, req);
|
rv = nghttp2_submit_request(connection->session, pri, nv, NULL, req);
|
||||||
if(rv != 0) {
|
if(rv != 0) {
|
||||||
diec("nghttp2_submit_request", rv);
|
diec("nghttp2_submit_request", rv);
|
||||||
|
@ -583,7 +576,6 @@ static void fetch_uri(const struct URI *uri)
|
||||||
int rv;
|
int rv;
|
||||||
nfds_t npollfds = 1;
|
nfds_t npollfds = 1;
|
||||||
struct pollfd pollfds[1];
|
struct pollfd pollfds[1];
|
||||||
uint16_t spdy_proto_version;
|
|
||||||
|
|
||||||
request_init(&req, uri);
|
request_init(&req, uri);
|
||||||
|
|
||||||
|
@ -598,7 +590,7 @@ static void fetch_uri(const struct URI *uri)
|
||||||
if(ssl_ctx == NULL) {
|
if(ssl_ctx == NULL) {
|
||||||
dief("SSL_CTX_new", ERR_error_string(ERR_get_error(), NULL));
|
dief("SSL_CTX_new", ERR_error_string(ERR_get_error(), NULL));
|
||||||
}
|
}
|
||||||
init_ssl_ctx(ssl_ctx, &spdy_proto_version);
|
init_ssl_ctx(ssl_ctx);
|
||||||
ssl = SSL_new(ssl_ctx);
|
ssl = SSL_new(ssl_ctx);
|
||||||
if(ssl == NULL) {
|
if(ssl == NULL) {
|
||||||
dief("SSL_new", ERR_error_string(ERR_get_error(), NULL));
|
dief("SSL_new", ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
@ -610,13 +602,17 @@ static void fetch_uri(const struct URI *uri)
|
||||||
connection.ssl = ssl;
|
connection.ssl = ssl;
|
||||||
connection.want_io = IO_NONE;
|
connection.want_io = IO_NONE;
|
||||||
|
|
||||||
|
/* Send connection header in blocking I/O mode */
|
||||||
|
SSL_write(ssl, NGHTTP2_CLIENT_CONNECTION_HEADER,
|
||||||
|
NGHTTP2_CLIENT_CONNECTION_HEADER_LEN);
|
||||||
|
|
||||||
/* Here make file descriptor non-block */
|
/* Here make file descriptor non-block */
|
||||||
make_non_block(fd);
|
make_non_block(fd);
|
||||||
set_tcp_nodelay(fd);
|
set_tcp_nodelay(fd);
|
||||||
|
|
||||||
printf("[INFO] SPDY protocol version = %d\n", spdy_proto_version);
|
printf("[INFO] SSL/TLS handshake completed\n");
|
||||||
rv = nghttp2_session_client_new(&connection.session, spdy_proto_version,
|
rv = nghttp2_session_client_new(&connection.session, &callbacks,
|
||||||
&callbacks, &connection);
|
&connection);
|
||||||
if(rv != 0) {
|
if(rv != 0) {
|
||||||
diec("nghttp2_session_client_new", rv);
|
diec("nghttp2_session_client_new", rv);
|
||||||
}
|
}
|
||||||
|
@ -743,7 +739,7 @@ int main(int argc, char **argv)
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
if(argc < 2) {
|
if(argc < 2) {
|
||||||
die("Specify URI");
|
die("Specify a https URI");
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&act, 0, sizeof(struct sigaction));
|
memset(&act, 0, sizeof(struct sigaction));
|
Loading…
Reference in New Issue