From 90cb9c4711c1676b8581adbc28fef9cda4d530e1 Mon Sep 17 00:00:00 2001 From: Scott Griepentrog Date: Fri, 28 Mar 2014 16:16:53 +0000 Subject: [PATCH] http: response body often missing after specific request This patch works around a problem with the HTTP body being dropped from the response to a specific client and under specific circumstances: a) Client request comes from node.js user agent "Shred" via use of swagger-client library. b) Asterisk and Client are *not* on the same host or TCP/IP stack In testing this problem, it has been determined that the write of the HTTP body is lost, even if the data is written using low level write function. The only solution found is to instruct the TCP stack with the shutdown function to flush the last write and finish the transmission. See review for more details. ASTERISK-23548 #close (closes issue ASTERISK-23548) Reported by: Sam Galarneau Review: https://reviewboard.asterisk.org/r/3402/ ........ Merged revisions 411462 from http://svn.asterisk.org/svn/asterisk/branches/1.8 git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@411463 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- main/http.c | 7 ++++--- main/manager.c | 18 ++++++++++++++++++ main/tcptls.c | 10 ++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/main/http.c b/main/http.c index 81b48cd8f4..8d3427aebc 100644 --- a/main/http.c +++ b/main/http.c @@ -433,7 +433,9 @@ void ast_http_send(struct ast_tcptls_session_instance *ser, /* send content */ if (method != AST_HTTP_HEAD || status_code >= 400) { if (out) { - fprintf(ser->f, "%s", ast_str_buffer(out)); + if (fwrite(ast_str_buffer(out), content_length, 1, ser->f) != 1) { + ast_log(LOG_ERROR, "fwrite() failed: %s\n", strerror(errno)); + } } if (fd) { @@ -455,8 +457,7 @@ void ast_http_send(struct ast_tcptls_session_instance *ser, ast_free(out); } - fclose(ser->f); - ser->f = 0; + ast_tcptls_close_session_file(ser); return; } diff --git a/main/manager.c b/main/manager.c index a1770cfab4..9234eb8cbb 100644 --- a/main/manager.c +++ b/main/manager.c @@ -1491,6 +1491,15 @@ static void session_destructor(void *obj) } if (session->f != NULL) { + /* + * Issuing shutdown() is necessary here to avoid a race + * condition where the last data written may not appear + * in the the TCP stream. See ASTERISK-23548 + */ + fflush(session->f); + if (session->fd != -1) { + shutdown(session->fd, SHUT_RDWR); + } fclose(session->f); } if (eqe) { @@ -6413,12 +6422,21 @@ static void process_output(struct mansession *s, struct ast_str **out, struct as } if (s->f) { + /* + * Issuing shutdown() is necessary here to avoid a race + * condition where the last data written may not appear + * in the the TCP stream. See ASTERISK-23548 + */ + if (s->fd != -1) { + shutdown(s->fd, SHUT_RDWR); + } if (fclose(s->f)) { ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno)); } s->f = NULL; s->fd = -1; } else if (s->fd != -1) { + shutdown(s->fd, SHUT_RDWR); if (close(s->fd)) { ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); } diff --git a/main/tcptls.c b/main/tcptls.c index e07f1f1a05..417178c8f7 100644 --- a/main/tcptls.c +++ b/main/tcptls.c @@ -625,12 +625,22 @@ error: void ast_tcptls_close_session_file(struct ast_tcptls_session_instance *tcptls_session) { if (tcptls_session->f) { + /* + * Issuing shutdown() is necessary here to avoid a race + * condition where the last data written may not appear + * in the TCP stream. See ASTERISK-23548 + */ + fflush(tcptls_session->f); + if (tcptls_session->fd != -1) { + shutdown(tcptls_session->fd, SHUT_RDWR); + } if (fclose(tcptls_session->f)) { ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno)); } tcptls_session->f = NULL; tcptls_session->fd = -1; } else if (tcptls_session->fd != -1) { + shutdown(tcptls_session->fd, SHUT_RDWR); if (close(tcptls_session->fd)) { ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); } -- 2.47.2