- single LF aware http_chunked_decode()
authorMichael Wallner <mike@php.net>
Wed, 24 Aug 2005 13:05:00 +0000 (13:05 +0000)
committerMichael Wallner <mike@php.net>
Wed, 24 Aug 2005 13:05:00 +0000 (13:05 +0000)
http_api.c
php_http_api.h
tests/chunked_decode_001.phpt
tests/chunked_decode_002.phpt [new file with mode: 0644]

index d0f91c695db82d3176fe73525c80f5f1c3784a36..8246d5907a4e0022af76e1a338fdd944c94f1c34 100644 (file)
@@ -281,29 +281,28 @@ PHP_HTTP_API STATUS _http_get_request_body_ex(char **body, size_t *length, zend_
 /* }}} */
 
 /* {{{ char *http_chunked_decode(char *, size_t, char **, size_t *) */
-PHP_HTTP_API const char *_http_chunked_decode(const char *encoded, size_t encoded_len,
-       char **decoded, size_t *decoded_len TSRMLS_DC)
+PHP_HTTP_API const char *_http_chunked_decode(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len TSRMLS_DC)
 {
        const char *e_ptr;
        char *d_ptr;
-
+       
        *decoded_len = 0;
        *decoded = ecalloc(1, encoded_len);
        d_ptr = *decoded;
        e_ptr = encoded;
 
        while (((e_ptr - encoded) - encoded_len) > 0) {
-               int no_crlf = 0;
+               size_t chunk_len = 0, EOL_len = 0;
+               int eol_mismatch = 0;
                char *n_ptr;
-               size_t chunk_len = 0;
 
                chunk_len = strtol(e_ptr, &n_ptr, 16);
 
                /* check if:
                 * - we could not read in chunk size
-                * - chunk size is not followed by HTTP_CRLF|NUL
+                * - chunk size is not followed by (CR)LF|NUL
                 */
-               if ((n_ptr == e_ptr) || (*n_ptr && (no_crlf = strncmp(n_ptr, HTTP_CRLF, lenof(HTTP_CRLF))))) {
+               if ((n_ptr == e_ptr) || (*n_ptr && (eol_mismatch = n_ptr != http_locate_eol(e_ptr, &EOL_len)))) {
                        /* don't fail on apperently not encoded data */
                        if (e_ptr == encoded) {
                                memcpy(*decoded, encoded, encoded_len);
@@ -311,10 +310,14 @@ PHP_HTTP_API const char *_http_chunked_decode(const char *encoded, size_t encode
                                return encoded + encoded_len;
                        } else {
                                efree(*decoded);
-                               if (no_crlf) {
-                                       http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Invalid character (expected 0x0D 0x0A; got: 0x%x 0x%x)", *n_ptr, *(n_ptr + 1));
+                               if (eol_mismatch) {
+                                       if (EOL_len == 2) {
+                                               http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Invalid character (expected 0x0D 0x0A; got: 0x%X 0x%X)", *n_ptr, *(n_ptr + 1));
+                                       } else {
+                                               http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Invalid character (expected 0x0A; got: 0x%X)", *n_ptr);
+                                       }
                                } else {
-                                       char *error = estrndup(n_ptr, strcspn(n_ptr, "\r\n \0"));
+                                       char *error = estrndup(n_ptr, strcspn(n_ptr, "\r\n "));
                                        http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Invalid chunk size: '%s' at pos %d", error, n_ptr - encoded);
                                        efree(error);
                                }
@@ -330,9 +333,9 @@ PHP_HTTP_API const char *_http_chunked_decode(const char *encoded, size_t encode
                        break;
                }
 
-               memcpy(d_ptr, e_ptr += 2, chunk_len);
+               memcpy(d_ptr, e_ptr += EOL_len, chunk_len);
                d_ptr += chunk_len;
-               e_ptr += chunk_len + 2;
+               e_ptr += chunk_len + EOL_len;
                *decoded_len += chunk_len;
        }
 
index 8906e2cda71793ae61fc92852e73c4fa3f4d8c49..25d305cf414ca23a3f3b3b619ad1ac261e8ed5c1 100644 (file)
@@ -75,6 +75,17 @@ static inline const char *_http_locate_body(const char *message)
        }
 }
 
+#define http_locate_eol _http_locate_eol
+static inline const char *_http_locate_eol(const char *line, size_t *eol_len)
+{
+       const char *eol = strpbrk(line, "\r\n");
+       
+       if (eol_len) {
+               *eol_len = eol ? ((eol[0] == '\r' && eol[1] == '\n') ? 2 : 1) : 0;
+       }
+       return eol;
+}
+
 #endif
 
 /*
index 27f750b1bfecc6e9ad96af0c305fc91953412889..2575704c547f227c3d34efdfef21e4ce84c6e538 100644 (file)
@@ -1,5 +1,5 @@
 --TEST--
-http_chunked_decode()
+http_chunked_decode() "\r\n"
 --SKIPIF--
 <?php
 include 'skip.inc';
@@ -10,16 +10,16 @@ echo "-TEST\n";
 $data =
 "02\r\n".
 "ab\r\n".
-"03\r\n".
-"a\nc\r\n".
 "04\r\n".
-"abcd\r\n".
+"ra\nc\r\n".
+"06\r\n".
+"adabra\r\n".
 "0\r\n".
-"abracadabra\n";
+"nothing\n";
 var_dump(http_chunked_decode($data));
 ?>
 --EXPECTF--
 %sTEST
-string(9) "aba
-cabcd"
+string(12) "abra
+cadabra"
 
diff --git a/tests/chunked_decode_002.phpt b/tests/chunked_decode_002.phpt
new file mode 100644 (file)
index 0000000..8221ee8
--- /dev/null
@@ -0,0 +1,25 @@
+--TEST--
+http_chunked_decode() "\n"
+--SKIPIF--
+<?php
+include 'skip.inc';
+?>
+--FILE--
+<?php
+echo "-TEST\n";
+$data =
+"02\n".
+"ab\n".
+"04\n".
+"ra\nc\n".
+"06\n".
+"adabra\n".
+"0\n".
+"hidden\n";
+var_dump(http_chunked_decode($data));
+?>
+--EXPECTF--
+%sTEST
+string(12) "abra
+cadabra"
+