[FFmpeg-devel] [PATCH] fix http chunk encoding parsing

Eugene Kosov claprix at yandex.ru
Tue Dec 15 10:31:18 CET 2015


---
 ffserver.c | 77 ++++++++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 50 insertions(+), 27 deletions(-)

diff --git a/ffserver.c b/ffserver.c
index 029771c..b7f9616 100644
--- a/ffserver.c
+++ b/ffserver.c
@@ -138,7 +138,7 @@ typedef struct HTTPContext {
     int http_error;
     int post;
     int chunked_encoding;
-    int chunk_size;               /* 0 if it needs to be read */
+    int chunk_size; /* 0 if it needs to be read; negative if reading chunk footer */
     struct HTTPContext *next;
     int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
     int64_t data_count;
@@ -2598,36 +2598,37 @@ static int http_receive_data(HTTPContext *c)
 {
     HTTPContext *c1;
     int len, loop_run = 0;
+    char buf[16];
+    int buf_len = 0;
+
+    if (c->chunked_encoding && c->chunk_size == 0) {
+        for (;;) {
+            /* read chunk header, if present */
+            len = recv(c->fd, buf + buf_len, 1, 0);
+            buf_len += len;
+
+            if (len < 0) {
+                if (ff_neterrno() != AVERROR(EAGAIN) &&
+                    ff_neterrno() != AVERROR(EINTR))
+                    /* error : close connection */
+                    goto fail;
+                return 0;
+            }
 
-    while (c->chunked_encoding && !c->chunk_size &&
-           c->buffer_end > c->buffer_ptr) {
-        /* read chunk header, if present */
-        len = recv(c->fd, c->buffer_ptr, 1, 0);
-
-        if (len < 0) {
-            if (ff_neterrno() != AVERROR(EAGAIN) &&
-                ff_neterrno() != AVERROR(EINTR))
-                /* error : close connection */
+            if (len == 0 || ++loop_run > 10)
+                /* end of connection or no chunk size : close it */
                 goto fail;
-            return 0;
-        } else if (len == 0) {
-            /* end of connection : close it */
-            goto fail;
-        } else if (c->buffer_ptr - c->buffer >= 2 &&
-                   !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
-            c->chunk_size = strtol(c->buffer, 0, 16);
-            if (c->chunk_size == 0) // end of stream
-                goto fail;
-            c->buffer_ptr = c->buffer;
-            break;
-        } else if (++loop_run > 10)
-            /* no chunk header, abort */
-            goto fail;
-        else
-            c->buffer_ptr++;
+
+            if (buf_len > 1 && !memcmp(buf + buf_len - 2, "\r\n", 2)) {
+                c->chunk_size = strtol(buf, 0, 16);
+                if (c->chunk_size == 0) // end of stream
+                    goto fail;
+                break;
+            }
+        }
     }
 
-    if (c->buffer_end > c->buffer_ptr) {
+    if (c->buffer_end > c->buffer_ptr && c->chunk_size > 0) {
         len = recv(c->fd, c->buffer_ptr,
                    FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
         if (len < 0) {
@@ -2644,6 +2645,28 @@ static int http_receive_data(HTTPContext *c)
             c->data_count += len;
             update_datarate(&c->datarate, c->data_count);
         }
+
+        // Reading of chunk body is done. Now read 2 bytes of chunk footer.
+        if (!c->chunk_size)
+            c->chunk_size = -2;
+    }
+
+    if (c->chunked_encoding && c->chunk_size < 0) {
+        while (c->chunk_size < 0) {
+            len = recv(c->fd, buf, 1, 0);
+            if (len < 0) {
+                if (ff_neterrno() != AVERROR(EAGAIN) &&
+                    ff_neterrno() != AVERROR(EINTR))
+                    /* error : close connection */
+                    goto fail;
+                return 0;
+            }
+            if (len == 0) {
+                goto fail;
+            }
+
+            c->chunk_size += len;
+        }
     }
 
     if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
-- 
2.5.0


More information about the ffmpeg-devel mailing list