]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
http: response body often missing after specific request
authorScott Griepentrog <sgriepentrog@digium.com>
Fri, 28 Mar 2014 16:16:53 +0000 (16:16 +0000)
committerScott Griepentrog <sgriepentrog@digium.com>
Fri, 28 Mar 2014 16:16:53 +0000 (16:16 +0000)
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
main/manager.c
main/tcptls.c

index 81b48cd8f48b3079bc6cb38048c076d08a1aa80a..8d3427aebc7d447570221e931b64f2aa819679c2 100644 (file)
@@ -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;
 }
 
index a1770cfab4f4cae48d6f838c3b6a036d0bc37c55..9234eb8cbb4144996a60c6e33c407d7e3b78d011 100644 (file)
@@ -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));
                }
index e07f1f1a05e94e966980914083efab3cbe82afa3..417178c8f71d651221b4dc27f22662f939596d68 100644 (file)
@@ -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));
                }