From 946d3150bac8690f9e4100951d34bc2c0eeb55ed Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 24 Dec 2013 21:30:49 +0900 Subject: [PATCH] examples: Add minimum error handling for API functions --- examples/libevent-client.c | 74 ++++++++++++++++++------- examples/libevent-server.c | 110 +++++++++++++++++++++++++++---------- 2 files changed, 136 insertions(+), 48 deletions(-) diff --git a/examples/libevent-client.c b/examples/libevent-client.c index 28697acb..56896150 100644 --- a/examples/libevent-client.c +++ b/examples/libevent-client.c @@ -47,9 +47,10 @@ typedef struct { const char *uri; /* Parsed result of the |uri| */ struct http_parser_url *u; - /* The authroity portion of the |uri|, NULL-terminated */ + /* The authroity portion of the |uri|, not NULL-terminated */ char *authority; - /* The path portion of the |uri|, including query, NULL-terminated */ + /* The path portion of the |uri|, including query, not + NULL-terminated */ char *path; /* The length of the |authority| */ size_t authoritylen; @@ -87,6 +88,7 @@ static http2_stream_data* create_http2_stream_data(const char *uri, memcpy(stream_data->authority, &uri[u->field_data[UF_HOST].off], u->field_data[UF_HOST].len); + stream_data->pathlen = 0; if(u->field_set & (1 << UF_PATH)) { stream_data->pathlen = u->field_data[UF_PATH].len; } @@ -94,11 +96,19 @@ static http2_stream_data* create_http2_stream_data(const char *uri, /* +1 for '?' character */ stream_data->pathlen += u->field_data[UF_QUERY].len + 1; } - stream_data->path = malloc(stream_data->pathlen); - memcpy(stream_data->path, - &uri[u->field_data[UF_PATH].off], u->field_data[UF_PATH].len); - memcpy(stream_data->path + u->field_data[UF_PATH].len + 1, - &uri[u->field_data[UF_QUERY].off], u->field_data[UF_QUERY].len); + if(stream_data->pathlen > 0) { + stream_data->path = malloc(stream_data->pathlen); + if(u->field_set & (1 << UF_PATH)) { + memcpy(stream_data->path, + &uri[u->field_data[UF_PATH].off], u->field_data[UF_PATH].len); + } + if(u->field_set & (1 << UF_QUERY)) { + memcpy(stream_data->path + u->field_data[UF_PATH].len + 1, + &uri[u->field_data[UF_QUERY].off], u->field_data[UF_QUERY].len); + } + } else { + stream_data->path = NULL; + } return stream_data; } @@ -234,11 +244,16 @@ static int on_stream_close_callback(nghttp2_session *session, void *user_data) { http2_session_data *session_data = (http2_session_data*)user_data; + int rv; + if(session_data->stream_data->stream_id == stream_id) { fprintf(stderr, "Stream %d closed with error_code=%d\n", stream_id, error_code); - nghttp2_submit_goaway(session, NGHTTP2_FLAG_NONE, NGHTTP2_NO_ERROR, - NULL, 0); + rv = nghttp2_submit_goaway(session, NGHTTP2_FLAG_NONE, NGHTTP2_NO_ERROR, + NULL, 0); + if(rv != 0) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } } return 0; } @@ -302,11 +317,16 @@ 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_HEADER, NGHTTP2_CLIENT_CONNECTION_HEADER_LEN); - nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, - iv, ARRLEN(iv)); + 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)); + } } #define MAKE_NV(NAME, VALUE, VALUELEN) \ @@ -318,6 +338,7 @@ static void send_client_connection_header(http2_session_data *session_data) /* Send HTTP request to the remote peer */ static void submit_request(http2_session_data *session_data) { + int rv; http2_stream_data *stream_data = session_data->stream_data; const char *uri = stream_data->uri; const struct http_parser_url *u = stream_data->u; @@ -330,15 +351,25 @@ static void submit_request(http2_session_data *session_data) }; fprintf(stderr, "Request headers:\n"); print_headers(stderr, hdrs, ARRLEN(hdrs)); - nghttp2_submit_request(session_data->session, NGHTTP2_PRI_DEFAULT, - hdrs, ARRLEN(hdrs), NULL, stream_data); + rv = nghttp2_submit_request(session_data->session, NGHTTP2_PRI_DEFAULT, + hdrs, ARRLEN(hdrs), NULL, stream_data); + if(rv != 0) { + errx(1, "Could not submit HTTP request: %s", nghttp2_strerror(rv)); + } } /* Serialize the frame and send (or buffer) the data to bufferevent. */ -static void session_send(http2_session_data *session_data) +static int session_send(http2_session_data *session_data) { - nghttp2_session_send(session_data->session); + int rv; + + rv = nghttp2_session_send(session_data->session); + if(rv != 0) { + warnx("Fatal error: %s", nghttp2_strerror(rv)); + return -1; + } + return 0; } /* readcb for bufferevent. Here we get the data from the input buffer @@ -356,10 +387,13 @@ static void readcb(struct bufferevent *bev, void *ptr) if(rv < 0) { warnx("Fatal error: %s", nghttp2_strerror(rv)); delete_http2_session_data(session_data); - } else { - evbuffer_drain(input, rv); + return; + } + evbuffer_drain(input, rv); + if(session_send(session_data) != 0) { + delete_http2_session_data(session_data); + return; } - session_send(session_data); } /* writecb for bufferevent. To greaceful shutdown after sending or @@ -392,7 +426,9 @@ static void eventcb(struct bufferevent *bev, short events, void *ptr) initialize_nghttp2_session(session_data); send_client_connection_header(session_data); submit_request(session_data); - session_send(session_data); + if(session_send(session_data) != 0) { + delete_http2_session_data(session_data); + } return; } if(events & BEV_EVENT_EOF) { diff --git a/examples/libevent-server.c b/examples/libevent-server.c index d9150ca7..0c650270 100644 --- a/examples/libevent-server.c +++ b/examples/libevent-server.c @@ -222,16 +222,22 @@ static void delete_http2_session_data(http2_session_data *session_data) /* Serialize the frame and send (or buffer) the data to bufferevent. */ -static void session_send(http2_session_data *session_data) +static int session_send(http2_session_data *session_data) { - nghttp2_session_send(session_data->session); + int rv; + rv = nghttp2_session_send(session_data->session); + if(rv != 0) { + warnx("Fatal error: %s", nghttp2_strerror(rv)); + return -1; + } + return 0; } /* Read the data in the bufferevent and feed them into nghttp2 library function. Invocation of nghttp2_session_mem_recv() may make additional pending frames, so call session_send() at the end of the function. */ -static void session_recv(http2_session_data *session_data) +static int session_recv(http2_session_data *session_data) { int rv; struct evbuffer *input = bufferevent_get_input(session_data->bev); @@ -240,11 +246,13 @@ static void session_recv(http2_session_data *session_data) rv = nghttp2_session_mem_recv(session_data->session, data, datalen); if(rv < 0) { warnx("Fatal error: %s", nghttp2_strerror(rv)); - delete_http2_session_data(session_data); - } else { - evbuffer_drain(input, rv); + return -1; } - session_send(session_data); + evbuffer_drain(input, rv); + if(session_send(session_data) != 0) { + return -1; + } + return 0; } static ssize_t send_callback(nghttp2_session *session, @@ -364,21 +372,27 @@ static ssize_t file_read_callback return r; } -static void send_response(nghttp2_session *session, int32_t stream_id, - nghttp2_nv *nva, size_t nvlen, int fd) +static int send_response(nghttp2_session *session, int32_t stream_id, + nghttp2_nv *nva, size_t nvlen, int fd) { + int rv; nghttp2_data_provider data_prd; data_prd.source.fd = fd; data_prd.read_callback = file_read_callback; - nghttp2_submit_response(session, stream_id, nva, nvlen, &data_prd); + rv = nghttp2_submit_response(session, stream_id, nva, nvlen, &data_prd); + if(rv != 0) { + warnx("Fatal error: %s", nghttp2_strerror(rv)); + return -1; + } + return 0; } const char ERROR_HTML[] = "404" "

404 Not Found

"; -static void error_reply(nghttp2_session *session, - http2_stream_data *stream_data) +static int error_reply(nghttp2_session *session, + http2_stream_data *stream_data) { int rv; int pipefd[2]; @@ -388,16 +402,25 @@ static void error_reply(nghttp2_session *session, rv = pipe(pipefd); if(rv != 0) { - nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, - stream_data->stream_id, - NGHTTP2_INTERNAL_ERROR); - return; + warn("Could not create pipe"); + rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, + stream_data->stream_id, + NGHTTP2_INTERNAL_ERROR); + if(rv != 0) { + warnx("Fatal error: %s", nghttp2_strerror(rv)); + return -1; + } + return 0; } write(pipefd[1], ERROR_HTML, sizeof(ERROR_HTML) - 1); close(pipefd[1]); stream_data->fd = pipefd[0]; - send_response(session, stream_data->stream_id, hdrs, ARRLEN(hdrs), - pipefd[0]); + if(send_response(session, stream_data->stream_id, hdrs, ARRLEN(hdrs), + pipefd[0]) != 0) { + close(pipefd[0]); + return -1; + } + return 0; } /* Minimum check for directory traversal. Returns nonzero if it is @@ -426,24 +449,33 @@ static int on_request_recv_callback(nghttp2_session *session, stream_data = (http2_stream_data*)nghttp2_session_get_stream_user_data (session, stream_id); if(!stream_data->request_path) { - error_reply(session, stream_data); + if(error_reply(session, stream_data) != 0) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } return 0; } fprintf(stderr, "%s GET %s\n", session_data->client_addr, stream_data->request_path); if(!check_path(stream_data->request_path)) { - error_reply(session, stream_data); + if(error_reply(session, stream_data) != 0) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } return 0; } for(rel_path = stream_data->request_path; *rel_path == '/'; ++rel_path); fd = open(rel_path, O_RDONLY); if(fd == -1) { - error_reply(session, stream_data); + if(error_reply(session, stream_data) != 0) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } return 0; } stream_data->fd = fd; - send_response(session, stream_id, hdrs, ARRLEN(hdrs), fd); + if(send_response(session, stream_id, hdrs, ARRLEN(hdrs), fd) != 0) { + close(fd); + return NGHTTP2_ERR_CALLBACK_FAILURE; + } return 0; } @@ -474,20 +506,31 @@ static void initialize_nghttp2_session(http2_session_data *session_data) /* Send HTTP/2.0 client connection header, which includes 24 bytes magic octets and SETTINGS frame */ -static void send_server_connection_header(http2_session_data *session_data) +static int send_server_connection_header(http2_session_data *session_data) { nghttp2_settings_entry iv[1] = { { NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100 } }; - nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, - iv, ARRLEN(iv)); + 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; } /* readcb for bufferevent after client connection header was checked. */ static void readcb(struct bufferevent *bev, void *ptr) { - session_recv((http2_session_data*)ptr); + http2_session_data *session_data = (http2_session_data*)ptr; + if(session_recv(session_data) != 0) { + delete_http2_session_data(session_data); + return; + } } /* writecb for bufferevent. To greaceful shutdown after sending or @@ -509,7 +552,10 @@ static void writecb(struct bufferevent *bev, void *ptr) delete_http2_session_data(session_data); return; } - session_send(session_data); + if(session_send(session_data) != 0) { + delete_http2_session_data(session_data); + return; + } } /* eventcb for bufferevent */ @@ -551,8 +597,14 @@ static void handshake_readcb(struct bufferevent *bev, void *ptr) /* Process pending data in buffer since they are not notified further */ initialize_nghttp2_session(session_data); - send_server_connection_header(session_data); - session_recv(session_data); + if(send_server_connection_header(session_data) != 0) { + delete_http2_session_data(session_data); + return; + } + if(session_recv(session_data) != 0) { + delete_http2_session_data(session_data); + return; + } } }