fix chunked postdata parsing
authorFelix Fietkau <nbd@openwrt.org>
Thu, 3 Jan 2013 01:49:36 +0000 (02:49 +0100)
committerFelix Fietkau <nbd@openwrt.org>
Thu, 3 Jan 2013 01:49:36 +0000 (02:49 +0100)
client.c
uhttpd.h

index 6a0c4bf9cf4a0ab9b1ead291338151681c6316fe..408a8132b1645c03207faec7cf0fe5771be9463d 100644 (file)
--- a/client.c
+++ b/client.c
@@ -261,15 +261,16 @@ static bool client_data_cb(struct client *cl, char *buf, int len)
                return false;
 
        while (len) {
+               int offset = 0;
                char *sep;
 
-               r->content_length -= cur_len;
                consumed += cur_len;
                buf += cur_len;
                len -= cur_len;
                cur_len = min(r->content_length, len);
 
                if (cur_len) {
+                       r->content_length -= cur_len;
                        if (d->data_send)
                                d->data_send(cl, buf, cur_len);
                        continue;
@@ -278,28 +279,44 @@ static bool client_data_cb(struct client *cl, char *buf, int len)
                if (!r->transfer_chunked)
                        break;
 
-               sep = strstr(buf, "\r\n");
+               if (r->transfer_chunked > 1)
+                       offset = 2;
+
+               sep = strstr(buf + offset, "\r\n");
                if (!sep)
                        break;
 
                *sep = 0;
                cur_len = sep + 2 - buf;
 
-               r->content_length = strtoul(buf, &sep, 16);
+               r->content_length = strtoul(buf + offset, &sep, 16);
+               r->transfer_chunked++;
 
                /* invalid chunk length */
                if (sep && *sep)
-                       return false;
+                       goto abort;
 
                /* empty chunk == eof */
-               if (!r->content_length) {
+               if (!r->content_length)
                        r->transfer_chunked = false;
-                       continue;
-               }
+
+               continue;
+
+abort:
+               consumed = len;
+               r->content_length = 0;
+               r->transfer_chunked = 0;
+               break;
        }
 
        ustream_consume(cl->us, consumed);
-       return r->content_length || r->transfer_chunked;
+       if (!r->content_length && !r->transfer_chunked) {
+               if (cl->dispatch.data_done)
+                       cl->dispatch.data_done(cl);
+
+               cl->state = CLIENT_STATE_DONE;
+       }
+       return false;
 }
 
 static bool client_header_cb(struct client *cl, char *buf, int len)
@@ -345,8 +362,6 @@ static void client_read_cb(struct client *cl)
                if (!read_cbs[cl->state](cl, str, len)) {
                        if (len == us->r.buffer_len)
                                uh_header_error(cl, 413, "Request Entity Too Large");
-                       if (cl->dispatch.data_done)
-                               cl->dispatch.data_done(cl);
                        break;
                }
        } while(1);
index c36d3bba624ec76959b0b6fb81f4e0fb4a7fcf06..b2404f400efa5b238da4fd35e3d47dfffcc2b167 100644 (file)
--- a/uhttpd.h
+++ b/uhttpd.h
@@ -81,7 +81,7 @@ struct http_request {
        int redirect_status;
        int content_length;
        bool expect_cont;
-       bool transfer_chunked;
+       uint8_t transfer_chunked;
        const char *url;
        const struct auth_realm *realm;
 };