Fixed Bug #69000 (http\Url breaks down with very long URL query strings)
authorMichael Wallner <mike@php.net>
Sat, 7 Feb 2015 11:20:10 +0000 (12:20 +0100)
committerMichael Wallner <mike@php.net>
Sat, 7 Feb 2015 11:20:10 +0000 (12:20 +0100)
package.xml
php_http.h
php_http_buffer.c
php_http_url.c
tests/bug69000.phpt [new file with mode: 0644]

index c78bcea..b088310 100644 (file)
@@ -37,7 +37,7 @@ v2: http://dev.iworks.at/ext-http/lcov/ext/http/
   <email>mike@php.net</email>
   <active>yes</active>
  </lead>
- <date>2015-01-27</date>
+ <date>2015-02-07</date>
  <version>
   <release>2.2.1</release>
   <api>2.2.0</api>
@@ -48,6 +48,7 @@ v2: http://dev.iworks.at/ext-http/lcov/ext/http/
  </stability>
  <license>BSD, revised</license>
  <notes><![CDATA[
+* Fixed Bug #69000 (http\Url breaks down with very long URL query strings)
 ]]></notes>
  <contents>
   <dir name="/">
index 26de0f1..75f97df 100644 (file)
@@ -13,7 +13,7 @@
 #ifndef PHP_EXT_HTTP_H
 #define PHP_EXT_HTTP_H
 
-#define PHP_PECL_HTTP_VERSION "2.2.1dev"
+#define PHP_PECL_HTTP_VERSION "2.2.1"
 
 extern zend_module_entry http_module_entry;
 #define phpext_http_ptr &http_module_entry
index 6636e2c..00ec4b4 100644 (file)
@@ -45,7 +45,7 @@ PHP_HTTP_BUFFER_API size_t php_http_buffer_resize_ex(php_http_buffer_t *buf, siz
 {
        char *ptr = NULL;
 #if 0
-       fprintf(stderr, "RESIZE: len=%lu, size=%lu, used=%lu, free=%lu\n", len, buf->size, buf->used, buf->free);
+       fprintf(stderr, "RESIZE: len=%lu, size=%lu, used=%lu, free=%lu, total=%lu\n", len, buf->size, buf->used, buf->free, buf->free+buf->used);
 #endif
        if (buf->free < len) {
                size_t size = override_size ? override_size : buf->size;
@@ -74,10 +74,7 @@ PHP_HTTP_BUFFER_API size_t php_http_buffer_resize_ex(php_http_buffer_t *buf, siz
 
 PHP_HTTP_BUFFER_API char *php_http_buffer_account(php_http_buffer_t *buf, size_t to_account)
 {
-       /* it's probably already too late but check anyway */
-       if (to_account > buf->free) {
-               return NULL;
-       }
+       assert(to_account < buf->free);
 
        buf->free -= to_account;
        buf->used += to_account;
index 40fffba..b4a614e 100644 (file)
@@ -57,7 +57,7 @@ static inline char *localhostname(void)
        return estrndup("localhost", lenof("localhost"));
 }
 
-#define url(buf) ((php_http_url_t *) buf.data)
+#define url(buf) ((php_http_url_t *) (buf).data)
 
 static php_http_url_t *php_http_url_from_env(TSRMLS_D)
 {
@@ -139,13 +139,30 @@ void php_http_url(int flags, const php_url *old_url, const php_url *new_url, php
 
 #define url_isset(u,n) \
        ((u)&&(u)->n)
+#define url_append(buf, append) do { \
+       char *_ptr = (buf)->data; \
+       php_http_url_t *_url = (php_http_url_t *) _ptr, _mem = *_url; \
+       append; \
+       /* relocate */ \
+       if (_ptr != (buf)->data) { \
+               ptrdiff_t diff = (buf)->data - _ptr; \
+               _url = (php_http_url_t *) (buf)->data; \
+               if (_mem.scheme)        _url->scheme += diff; \
+               if (_mem.user)          _url->user += diff; \
+               if (_mem.pass)          _url->pass += diff; \
+               if (_mem.host)          _url->host += diff; \
+               if (_mem.path)          _url->path += diff; \
+               if (_mem.query)         _url->query += diff; \
+               if (_mem.fragment)      _url->fragment += diff; \
+       } \
+} while (0)
 #define url_copy(n) do { \
        if (url_isset(new_url, n)) { \
                url(buf)->n = &buf.data[buf.used]; \
-               php_http_buffer_append(&buf, new_url->n, strlen(new_url->n) + 1); \
+               url_append(&buf, php_http_buffer_append(&buf, new_url->n, strlen(new_url->n) + 1)); \
        } else if (url_isset(old_url, n)) { \
                url(buf)->n = &buf.data[buf.used]; \
-               php_http_buffer_append(&buf, old_url->n, strlen(old_url->n) + 1); \
+               url_append(&buf, php_http_buffer_append(&buf, old_url->n, strlen(old_url->n) + 1)); \
        } \
 } while (0)
 
@@ -196,9 +213,9 @@ php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_u
                        
                        url(buf)->path = &buf.data[buf.used];
                        if (path[0] != '/') {
-                               php_http_buffer_append(&buf, "/", 1);
+                               url_append(&buf, php_http_buffer_append(&buf, "/", 1));
                        }
-                       php_http_buffer_append(&buf, path, strlen(path) + 1);
+                       url_append(&buf, php_http_buffer_append(&buf, path, strlen(path) + 1));
                        efree(path);
                } else {
                        const char *path = NULL;
@@ -212,7 +229,7 @@ php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_u
                        if (path) {
                                url(buf)->path = &buf.data[buf.used];
 
-                               php_http_buffer_append(&buf, path, strlen(path) + 1);
+                               url_append(&buf, php_http_buffer_append(&buf, path, strlen(path) + 1));
                        }
 
 
@@ -236,7 +253,7 @@ php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_u
                        php_http_querystring_update(&qarr, NULL, &qstr TSRMLS_CC);
 
                        url(buf)->query = &buf.data[buf.used];
-                       php_http_buffer_append(&buf, Z_STRVAL(qstr), Z_STRLEN(qstr) + 1);
+                       url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL(qstr), Z_STRLEN(qstr) + 1));
 
                        zval_dtor(&qstr);
                        zval_dtor(&qarr);
@@ -413,25 +430,25 @@ php_http_url_t *php_http_url_from_struct(HashTable *ht)
        if (SUCCESS == zend_hash_find(ht, "scheme", sizeof("scheme"), (void *) &e)) {
                zval *cpy = php_http_ztyp(IS_STRING, *e);
                url(buf)->scheme = &buf.data[buf.used];
-               php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1);
+               url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1));
                zval_ptr_dtor(&cpy);
        }
        if (SUCCESS == zend_hash_find(ht, "user", sizeof("user"), (void *) &e)) {
                zval *cpy = php_http_ztyp(IS_STRING, *e);
                url(buf)->user = &buf.data[buf.used];
-               php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1);
+               url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1));
                zval_ptr_dtor(&cpy);
        }
        if (SUCCESS == zend_hash_find(ht, "pass", sizeof("pass"), (void *) &e)) {
                zval *cpy = php_http_ztyp(IS_STRING, *e);
                url(buf)->pass = &buf.data[buf.used];
-               php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1);
+               url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1));
                zval_ptr_dtor(&cpy);
        }
        if (SUCCESS == zend_hash_find(ht, "host", sizeof("host"), (void *) &e)) {
                zval *cpy = php_http_ztyp(IS_STRING, *e);
                url(buf)->host = &buf.data[buf.used];
-               php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1);
+               url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1));
                zval_ptr_dtor(&cpy);
        }
        if (SUCCESS == zend_hash_find(ht, "port", sizeof("port"), (void *) &e)) {
@@ -442,19 +459,19 @@ php_http_url_t *php_http_url_from_struct(HashTable *ht)
        if (SUCCESS == zend_hash_find(ht, "path", sizeof("path"), (void *) &e)) {
                zval *cpy = php_http_ztyp(IS_STRING, *e);
                url(buf)->path = &buf.data[buf.used];
-               php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1);
+               url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1));
                zval_ptr_dtor(&cpy);
        }
        if (SUCCESS == zend_hash_find(ht, "query", sizeof("query"), (void *) &e)) {
                zval *cpy = php_http_ztyp(IS_STRING, *e);
                url(buf)->query = &buf.data[buf.used];
-               php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1);
+               url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1));
                zval_ptr_dtor(&cpy);
        }
        if (SUCCESS == zend_hash_find(ht, "fragment", sizeof("fragment"), (void *) &e)) {
                zval *cpy = php_http_ztyp(IS_STRING, *e);
                url(buf)->fragment = &buf.data[buf.used];
-               php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1);
+               url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1));
                zval_ptr_dtor(&cpy);
        }
 
diff --git a/tests/bug69000.phpt b/tests/bug69000.phpt
new file mode 100644 (file)
index 0000000..9b23e47
--- /dev/null
@@ -0,0 +1,17 @@
+--TEST--
+Bug #69000 (http\Url breaks down with very long URL query strings)
+--SKIPIF--
+<?php 
+include "skipif.inc";
+?>
+--FILE--
+<?php 
+echo "Test\n";
+echo new http\Url("http://foo.bar/?".str_repeat("a", 1024));
+?>
+
+===DONE===
+--EXPECT--
+Test
+http://foo.bar/?aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+===DONE===