tests & bugfixes
authorMichael Wallner <mike@php.net>
Fri, 20 Jan 2012 22:02:26 +0000 (22:02 +0000)
committerMichael Wallner <mike@php.net>
Fri, 20 Jan 2012 22:02:26 +0000 (22:02 +0000)
18 files changed:
php_http_env.c
php_http_header_parser.c
php_http_headers.c
php_http_message.c
php_http_object.c
php_http_object.h
php_http_url.c
php_http_url.h
phpunit/HeaderTest.php [new file with mode: 0644]
phpunit/ObjectTest.php [new file with mode: 0644]
phpunit/ParamsTest.php
phpunit/UrlTest.php
tests/data/message_rr_empty.txt
tests/data/urls.txt
tests/envresponseheader001.phpt [new file with mode: 0644]
tests/message001.phpt
tests/phpunit.phpt [new file with mode: 0644]
tests/url001.phpt [new file with mode: 0644]

index ae09984..eb7a630 100644 (file)
@@ -662,8 +662,8 @@ PHP_METHOD(HttpEnv, getResponseStatusForCode)
 
 PHP_METHOD(HttpEnv, getResponseHeader)
 {
-       char *header_name_str;
-       int header_name_len;
+       char *header_name_str = NULL;
+       int header_name_len = 0;
 
        if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &header_name_str, &header_name_len)) {
                if (header_name_str && header_name_len) {
index 2ad9022..975df24 100644 (file)
@@ -152,14 +152,18 @@ PHP_HTTP_API STATUS php_http_header_parser_parse(php_http_header_parser_t *parse
                                const char *eol_str;
                                int eol_len;
 
-                               do {
+                               line_split: {
+                                       
                                        if ((eol_str = php_http_locate_bin_eol(buffer->data, buffer->used, &eol_len))) {
                                                if (eol_str + eol_len - buffer->data < buffer->used) {
-                                                       char nextline = *(eol_str + eol_len);
-
-                                                       if (nextline == '\t' || nextline == ' ') {
-                                                               php_http_buffer_cut(buffer, eol_str - buffer->data, eol_len);
-                                                               continue;
+                                                       char *nextline = eol_str + eol_len;
+
+                                                       if (*nextline == '\t' || *nextline == ' ') {
+                                                               while (nextline < buffer->data + buffer->used && (*nextline == '\t' || *nextline == ' ')) {
+                                                                       ++nextline;
+                                                               }
+                                                               php_http_buffer_cut(buffer, eol_str - buffer->data, nextline - eol_str);
+                                                               goto line_split;
                                                        }
                                                }
 
@@ -175,7 +179,7 @@ PHP_HTTP_API STATUS php_http_header_parser_parse(php_http_header_parser_t *parse
                                        } else {
                                                return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE);
                                        }
-                               } while (0);
+                               }
 
                                break;
                        }
index 3bc19de..226c763 100644 (file)
@@ -116,7 +116,7 @@ PHP_METHOD(HttpHeader, unserialize)
                                zend_hash_internal_pointer_reset(&ht);
                                switch (zend_hash_get_current_key_ex(&ht, &str, &len, &idx, 0, NULL)) {
                                        case HASH_KEY_IS_STRING:
-                                               zend_update_property_stringl(php_http_header_class_entry, getThis(), ZEND_STRL("name"), str, len TSRMLS_CC);
+                                               zend_update_property_stringl(php_http_header_class_entry, getThis(), ZEND_STRL("name"), str, len - 1 TSRMLS_CC);
                                                break;
                                        case HASH_KEY_IS_LONG:
                                                zend_update_property_long(php_http_header_class_entry, getThis(), ZEND_STRL("name"), idx TSRMLS_CC);
index ead5347..6436a1c 100644 (file)
@@ -124,17 +124,25 @@ PHP_HTTP_API php_http_message_t *php_http_message_parse(php_http_message_t *msg,
 {
        php_http_message_parser_t p;
        php_http_buffer_t buf;
+       int free_msg;
 
-       if (!msg) {
-               msg = php_http_message_init(NULL, 0 TSRMLS_CC);
-       }
        php_http_buffer_from_string_ex(&buf, str, len);
        php_http_message_parser_init(&p TSRMLS_CC);
-       php_http_message_parser_parse(&p, &buf, PHP_HTTP_MESSAGE_PARSER_CLEANUP, &msg);
+
+       if ((free_msg = !msg)) {
+               msg = php_http_message_init(NULL, 0 TSRMLS_CC);
+       }
+
+       if (FAILURE == php_http_message_parser_parse(&p, &buf, PHP_HTTP_MESSAGE_PARSER_CLEANUP, &msg)) {
+               if (free_msg) {
+                       php_http_message_free(&msg);
+               }
+               msg = NULL;
+       }
+
        php_http_message_parser_dtor(&p);
        php_http_buffer_dtor(&buf);
 
-       /* FIXME */
        return msg;
 }
 
@@ -1278,16 +1286,17 @@ PHP_METHOD(HttpMessage, __construct)
 
        with_error_handling(EH_THROW, php_http_exception_class_entry) {
                if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &message, &length) && message && length) {
-                       php_http_message_t *msg = obj->message;
+                       if (message && length) {
+                               php_http_message_t *msg = php_http_message_parse(NULL, message, length TSRMLS_CC);
 
-                       php_http_message_dtor(msg);
-                       with_error_handling(EH_THROW, php_http_exception_class_entry) {
-                               if ((obj->message = php_http_message_parse(msg, message, length TSRMLS_CC))) {
+                               if (!msg) {
+                                       php_http_error(HE_THROW, PHP_HTTP_E_MESSAGE, "could not parse message: %.*s", 25, message);
+                               } else {
+                                       php_http_message_dtor(obj->message);
+                                       obj->message = msg;{
                                        if (obj->message->parent) {
                                                obj->parent = php_http_message_object_new_ex(Z_OBJCE_P(getThis()), obj->message->parent, NULL TSRMLS_CC);
                                        }
-                               } else {
-                                       obj->message = php_http_message_init(msg, 0 TSRMLS_CC);
                                }
                        } end_error_handling();
                }
index 39e9116..602ebaa 100644 (file)
@@ -51,11 +51,6 @@ PHP_HTTP_API zend_error_handling_t php_http_object_get_error_handling(zval *obje
 #define PHP_HTTP_EMPTY_ARGS(method)                                            PHP_HTTP_EMPTY_ARGS_EX(HttpObject, method, 0)
 #define PHP_HTTP_OBJECT_ME(method, visibility)                 PHP_ME(HttpObject, method, PHP_HTTP_ARGS(HttpObject, method), visibility)
 
-PHP_HTTP_BEGIN_ARGS(factory, 1)
-       PHP_HTTP_ARG_VAL(class_name, 0)
-       PHP_HTTP_ARG_VAL(ctor_args, 0)
-PHP_HTTP_END_ARGS;
-
 PHP_HTTP_BEGIN_ARGS(setErrorHandling, 1)
        PHP_HTTP_ARG_VAL(eh, 0)
 PHP_HTTP_END_ARGS;
@@ -68,15 +63,20 @@ PHP_HTTP_END_ARGS;
 
 PHP_HTTP_EMPTY_ARGS(getDefaultErrorHandling);
 
+PHP_HTTP_BEGIN_ARGS(triggerError, 3)
+       PHP_HTTP_ARG_VAL(error_type, 0)
+       PHP_HTTP_ARG_VAL(error_code, 0)
+       PHP_HTTP_ARG_VAL(error_message, 0)
+PHP_HTTP_END_ARGS;
+
 zend_class_entry *php_http_object_class_entry;
 zend_function_entry php_http_object_method_entry[] = {
-       PHP_HTTP_OBJECT_ME(factory, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
-
        PHP_HTTP_OBJECT_ME(setErrorHandling, ZEND_ACC_PUBLIC)
        PHP_HTTP_OBJECT_ME(getErrorHandling, ZEND_ACC_PUBLIC)
        PHP_HTTP_OBJECT_ME(setDefaultErrorHandling, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
        PHP_HTTP_OBJECT_ME(getDefaultErrorHandling, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
-       
+       PHP_HTTP_OBJECT_ME(triggerError, ZEND_ACC_PUBLIC)
+
        EMPTY_FUNCTION_ENTRY
 };
 
@@ -104,33 +104,6 @@ zend_object_value php_http_object_new_ex(zend_class_entry *ce, void *nothing, ph
        return ov;
 }
 
-PHP_METHOD(HttpObject, factory)
-{
-       zval *ctor_args = NULL;
-       zend_class_entry *class_entry = NULL;
-       zval *object_ctor;
-       zend_fcall_info fci;
-       zend_fcall_info_cache fcc;
-
-       with_error_handling(EH_THROW, php_http_exception_class_entry) {
-               if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "C|a/!", &class_entry, &ctor_args)) {
-                       object_init_ex(return_value, class_entry);
-
-                       MAKE_STD_ZVAL(object_ctor);
-                       array_init(object_ctor);
-
-                       Z_ADDREF_P(return_value);
-                       add_next_index_zval(object_ctor, return_value);
-                       add_next_index_stringl(object_ctor, ZEND_STRL("__construct"), 1);
-
-                       zend_fcall_info_init(object_ctor, 0, &fci, &fcc, NULL, NULL TSRMLS_CC);
-                       zend_fcall_info_call(&fci, &fcc, NULL, ctor_args TSRMLS_CC);
-
-                       zval_ptr_dtor(&object_ctor);
-               }
-       } end_error_handling();
-}
-
 PHP_METHOD(HttpObject, getErrorHandling)
 {
        RETURN_PROP(php_http_object_class_entry, "errorHandling");
@@ -181,6 +154,17 @@ PHP_METHOD(HttpObject, setDefaultErrorHandling)
        }
 }
 
+PHP_METHOD(HttpObject, triggerError)
+{
+       long eh, code;
+       char *msg_str;
+       int msg_len;
+
+       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lls", &eh, &code, &msg_str, &msg_len)) {
+               php_http_error(eh TSRMLS_CC, code, "%.*s", msg_len, msg_str);
+       }
+}
+
 PHP_MINIT_FUNCTION(http_object)
 {
        PHP_HTTP_REGISTER_CLASS(http, Object, http_object, NULL, ZEND_ACC_ABSTRACT);
index 0d0ca92..975d150 100644 (file)
@@ -31,11 +31,11 @@ extern zend_object_value php_http_object_new_ex(zend_class_entry *ce, void *noth
 
 PHP_HTTP_API zend_error_handling_t php_http_object_get_error_handling(zval *object TSRMLS_DC);
 
-PHP_METHOD(HttpObject, factory);
 PHP_METHOD(HttpObject, setErrorHandling);
 PHP_METHOD(HttpObject, getErrorHandling);
 PHP_METHOD(HttpObject, setDefaultErrorHandling);
 PHP_METHOD(HttpObject, getDefaultErrorHandling);
+PHP_METHOD(HttpObject, triggerError);
 
 #endif
 
index 4a5d20d..b9ea708 100644 (file)
@@ -42,35 +42,98 @@ static inline char *localhostname(void)
        return estrndup("localhost", lenof("localhost"));
 }
 
-PHP_HTTP_API char *php_http_url_absolute(const char *url, int flags TSRMLS_DC)
+static php_url *php_http_url_from_env(php_url *url TSRMLS_DC)
 {
-       char *abs = NULL;
-       php_url *purl = NULL;
-       
-       if (url) {
-               purl = php_url_parse(abs = estrdup(url));
-               STR_SET(abs, NULL);
-               if (!purl) {
-                       php_http_error(HE_WARNING, PHP_HTTP_E_URL, "Could not parse URL (%s)", url);
-                       return NULL;
+       zval *https, *zhost, *zport;
+       long port;
+#ifdef HAVE_GETSERVBYPORT
+       struct servent *se;
+#endif
+
+       if (!url) {
+               url = ecalloc(1, sizeof(*url));
+       }
+
+       /* port */
+       zport = php_http_env_get_server_var(ZEND_STRL("SERVER_PORT"), 1 TSRMLS_CC);
+       if (zport && IS_LONG == is_numeric_string(Z_STRVAL_P(zport), Z_STRLEN_P(zport), &port, NULL, 0)) {
+               url->port = port;
+       }
+
+       /* scheme */
+       https = php_http_env_get_server_var(ZEND_STRL("HTTPS"), 1 TSRMLS_CC);
+       if (https && !strcasecmp(Z_STRVAL_P(https), "ON")) {
+               url->scheme = estrndup("https", lenof("https"));
+       } else switch (url->port) {
+               case 443:
+                       url->scheme = estrndup("https", lenof("https"));
+                       break;
+
+#ifndef HAVE_GETSERVBYPORT
+               default:
+#endif
+               case 80:
+               case 0:
+                       url->scheme = estrndup("http", lenof("http"));
+                       break;
+
+#ifdef HAVE_GETSERVBYPORT
+               default:
+                       if ((se = getservbyport(htons(url->port), "tcp")) && se->s_name) {
+                               url->scheme = estrdup(se->s_name);
+                       } else {
+                               url->scheme = estrndup("http", lenof("http"));
+                       }
+                       break;
+#endif
+       }
+
+       /* host */
+       if ((((zhost = php_http_env_get_server_var(ZEND_STRL("HTTP_HOST"), 1 TSRMLS_CC)) ||
+                       (zhost = php_http_env_get_server_var(ZEND_STRL("SERVER_NAME"), 1 TSRMLS_CC)) ||
+                       (zhost = php_http_env_get_server_var(ZEND_STRL("SERVER_ADDR"), 1 TSRMLS_CC)))) && Z_STRLEN_P(zhost)) {
+               url->host = estrndup(Z_STRVAL_P(zhost), Z_STRLEN_P(zhost));
+       } else {
+               url->host = localhostname();
+       }
+
+       /* path */
+       if (SG(request_info).request_uri && SG(request_info).request_uri[0]) {
+               const char *q = strchr(SG(request_info).request_uri, '?');
+
+               if (q) {
+                       url->path = estrndup(SG(request_info).request_uri, q - SG(request_info).request_uri);
+               } else {
+                       url->path = estrdup(SG(request_info).request_uri);
                }
        }
-       
-       php_http_url(flags, purl, NULL, NULL, &abs, NULL TSRMLS_CC);
-       
-       if (purl) {
-               php_url_free(purl);
+
+       /* query */
+       if (SG(request_info).query_string && SG(request_info).query_string[0]) {
+               url->query = estrdup(SG(request_info).query_string);
        }
-       
-       return abs;
+
+       return url;
 }
 
 PHP_HTTP_API void php_http_url(int flags, const php_url *old_url, const php_url *new_url, php_url **url_ptr, char **url_str, size_t *url_len TSRMLS_DC)
 {
-#if defined(HAVE_GETSERVBYPORT) || defined(HAVE_GETSERVBYNAME)
+       php_url *url, *tmp_url = NULL;
+#ifdef HAVE_GETSERVBYNAME
        struct servent *se;
 #endif
-       php_url *url = ecalloc(1, sizeof(php_url));
+
+       /* set from env if requested */
+       if (flags & PHP_HTTP_URL_FROM_ENV) {
+               php_url *env_url = php_http_url_from_env(NULL TSRMLS_CC);
+
+               php_http_url(flags ^ PHP_HTTP_URL_FROM_ENV, env_url, old_url, &tmp_url, NULL, NULL TSRMLS_CC);
+
+               php_url_free(env_url);
+               old_url = tmp_url;
+       }
+
+       url = ecalloc(1, sizeof(*url));
 
 #define __URLSET(u,n) \
        ((u)&&(u)->n)
@@ -131,128 +194,83 @@ PHP_HTTP_API void php_http_url(int flags, const php_url *old_url, const php_url
                __URLCPY(fragment);
        }
        
-       if (!url->scheme) {
-               if (flags & PHP_HTTP_URL_FROM_ENV) {
-                       zval *https = php_http_env_get_server_var(ZEND_STRL("HTTPS"), 1 TSRMLS_CC);
-                       if (https && !strcasecmp(Z_STRVAL_P(https), "ON")) {
-                               url->scheme = estrndup("https", lenof("https"));
-                       } else switch (url->port) {
-                               case 443:
-                                       url->scheme = estrndup("https", lenof("https"));
-                                       break;
+       /* done with copy & combine & strip */
 
-#ifndef HAVE_GETSERVBYPORT
-                               default:
-#endif
-                               case 80:
-                               case 0:
-                                       url->scheme = estrndup("http", lenof("http"));
-                                       break;
-                       
-#ifdef HAVE_GETSERVBYPORT
-                               default:
-                                       if ((se = getservbyport(htons(url->port), "tcp")) && se->s_name) {
-                                               url->scheme = estrdup(se->s_name);
-                                       } else {
-                                               url->scheme = estrndup("http", lenof("http"));
-                                       }
-                                       break;
-#endif
-                       }
-               } else {
-                       url->scheme = estrndup("http", lenof("http"));
-               }
+       if (flags & PHP_HTTP_URL_FROM_ENV) {
+               /* free old_url we tainted above */
+               php_url_free(tmp_url);
+       }
+
+       /* set some sane defaults */
+
+       if (!url->scheme) {
+               url->scheme = estrndup("http", lenof("http"));
        }
 
        if (!url->host) {
-               if (flags & PHP_HTTP_URL_FROM_ENV) {
-                       zval *zhost;
-                       
-                       if ((((zhost = php_http_env_get_server_var(ZEND_STRL("HTTP_HOST"), 1 TSRMLS_CC)) ||
-                                       (zhost = php_http_env_get_server_var(ZEND_STRL("SERVER_NAME"), 1 TSRMLS_CC)))) && Z_STRLEN_P(zhost)) {
-                               url->host = estrndup(Z_STRVAL_P(zhost), Z_STRLEN_P(zhost));
-                       } else {
-                               url->host = localhostname();
-                       }
-               } else {
-                       url->host = estrndup("localhost", lenof("localhost"));
-               }
+               url->host = estrndup("localhost", lenof("localhost"));
        }
        
        if (!url->path) {
-               if ((flags & PHP_HTTP_URL_FROM_ENV) && SG(request_info).request_uri && SG(request_info).request_uri[0]) {
-                       const char *q = strchr(SG(request_info).request_uri, '?');
-                       
-                       if (q) {
-                               url->path = estrndup(SG(request_info).request_uri, q - SG(request_info).request_uri);
-                       } else {
-                               url->path = estrdup(SG(request_info).request_uri);
-                       }
-               } else {
-                       url->path = estrndup("/", 1);
-               }
+               url->path = estrndup("/", 1);
        } else if (url->path[0] != '/') {
-               if ((flags & PHP_HTTP_URL_FROM_ENV) && SG(request_info).request_uri && SG(request_info).request_uri[0]) {
-                       size_t ulen = strlen(SG(request_info).request_uri);
-                       size_t plen = strlen(url->path);
-                       char *path;
-                       
-                       if (SG(request_info).request_uri[ulen-1] != '/') {
-                               for (--ulen; ulen && SG(request_info).request_uri[ulen - 1] != '/'; --ulen);
-                       }
-                       
-                       path = emalloc(ulen + plen + 1);
-                       memcpy(path, SG(request_info).request_uri, ulen);
-                       memcpy(path + ulen, url->path, plen);
-                       path[ulen + plen] = '\0';
-                       STR_SET(url->path, path);
-               } else {
-                       size_t plen = strlen(url->path);
-                       char *path = emalloc(plen + 1 + 1);
-                       
-                       path[0] = '/';
-                       memcpy(&path[1], url->path, plen + 1);
-                       STR_SET(url->path, path);
-               }
+               size_t plen = strlen(url->path);
+               char *path = emalloc(plen + 1 + 1);
+
+               path[0] = '/';
+               memcpy(&path[1], url->path, plen + 1);
+               STR_SET(url->path, path);
        }
        /* replace directory references if path is not a single slash */
        if (url->path[0] && (url->path[0] != '/' || url->path[1])) {
                char *ptr, *end = url->path + strlen(url->path) + 1;
                        
-               for (ptr = strstr(url->path, "/."); ptr; ptr = strstr(ptr, "/.")) {
-                       switch (ptr[2]) {
-                               case '\0':
-                                       ptr[1] = '\0';
-                                       break;
-                               
+               for (ptr = strchr(url->path, '/'); ptr; ptr = strchr(ptr, '/')) {
+                       switch (ptr[1]) {
                                case '/':
-                                       memmove(&ptr[1], &ptr[3], end - &ptr[3]);
+                                       memmove(&ptr[1], &ptr[2], end - &ptr[2]);
                                        break;
                                        
                                case '.':
-                                       if (ptr[3] == '/') {
-                                               char *pos = &ptr[4];
-                                               while (ptr != url->path) {
-                                                       if (*--ptr == '/') {
+                                       switch (ptr[2]) {
+                                               case '\0':
+                                                       ptr[1] = '\0';
+                                                       break;
+
+                                               case '/':
+                                                       memmove(&ptr[1], &ptr[3], end - &ptr[3]);
+                                                       break;
+
+                                               case '.':
+                                                       if (ptr[3] == '/') {
+                                                               char *pos = &ptr[4];
+                                                               while (ptr != url->path) {
+                                                                       if (*--ptr == '/') {
+                                                                               break;
+                                                                       }
+                                                               }
+                                                               memmove(&ptr[1], pos, end - pos);
                                                                break;
+                                                       } else if (!ptr[3]) {
+                                                               /* .. at the end */
+                                                               ptr[1] = '\0';
                                                        }
-                                               }
-                                               memmove(&ptr[1], pos, end - pos);
-                                               break;
-                                       } else if (!ptr[3]) {
-                                               /* .. at the end */
-                                               ptr[1] = '\0';
+                                                       /* no break */
+
+                                               default:
+                                                       /* something else */
+                                                       ++ptr;
+                                                       break;
                                        }
-                                       /* no break */
-                               
+                                       break;
+
                                default:
-                                       /* something else */
                                        ++ptr;
                                        break;
                        }
                }
        }
-       
+       /* unset default ports */
        if (url->port) {
                if (    ((url->port == 80) && !strcmp(url->scheme, "http"))
                        ||      ((url->port ==443) && !strcmp(url->scheme, "https"))
@@ -441,6 +459,7 @@ PHP_HTTP_BEGIN_ARGS(__construct, 0)
        PHP_HTTP_ARG_VAL(flags, 0)
 PHP_HTTP_END_ARGS;
 PHP_HTTP_EMPTY_ARGS(toString);
+PHP_HTTP_EMPTY_ARGS(toArray);
 
 PHP_HTTP_BEGIN_ARGS(mod, 1)
        PHP_HTTP_ARG_VAL(more_url_parts, 0)
@@ -453,6 +472,7 @@ zend_function_entry php_http_url_method_entry[] = {
        PHP_HTTP_URL_ME(mod, ZEND_ACC_PUBLIC)
        PHP_HTTP_URL_ME(toString, ZEND_ACC_PUBLIC)
        ZEND_MALIAS(HttpUrl, __toString, toString, PHP_HTTP_ARGS(HttpUrl, toString), ZEND_ACC_PUBLIC)
+       PHP_HTTP_URL_ME(toArray, ZEND_ACC_PUBLIC)
        EMPTY_FUNCTION_ENTRY
 };
 
@@ -527,7 +547,7 @@ PHP_METHOD(HttpUrl, mod)
        long flags = PHP_HTTP_URL_JOIN_PATH | PHP_HTTP_URL_JOIN_QUERY;
 
        if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z!|l", &new_url, &flags)) {
-               php_url *res_purl, *new_purl = NULL, *old_purl = NULL;
+               php_url *new_purl = NULL, *old_purl = NULL;
 
                if (new_url) {
                        switch (Z_TYPE_P(new_url)) {
@@ -549,9 +569,11 @@ PHP_METHOD(HttpUrl, mod)
                }
 
                if ((old_purl = php_http_url_from_struct(NULL, HASH_OF(getThis()) TSRMLS_CC))) {
-                       php_http_url(flags, old_purl, new_purl, &res_purl, NULL, NULL TSRMLS_CC);
+                       php_url *res_purl;
+
+                       ZVAL_OBJVAL(return_value, zend_objects_clone_obj(getThis() TSRMLS_CC), 0);
 
-                       Z_OBJVAL_P(return_value) = zend_objects_clone_obj(getThis() TSRMLS_CC);
+                       php_http_url(flags, old_purl, new_purl, &res_purl, NULL, NULL TSRMLS_CC);
                        php_http_url_to_struct(res_purl, return_value TSRMLS_CC);
 
                        php_url_free(res_purl);
@@ -580,6 +602,15 @@ PHP_METHOD(HttpUrl, toString)
        RETURN_EMPTY_STRING();
 }
 
+PHP_METHOD(HttpUrl, toArray)
+{
+       if (SUCCESS != zend_parse_parameters_none()) {
+               RETURN_FALSE;
+       }
+       array_init(return_value);
+       array_copy(HASH_OF(getThis()), HASH_OF(return_value));
+}
+
 PHP_MINIT_FUNCTION(http_url)
 {
        PHP_HTTP_REGISTER_CLASS(http, Url, http_url, php_http_object_class_entry, 0);
index db7a32e..4b7657c 100644 (file)
@@ -35,7 +35,6 @@
 #define PHP_HTTP_URL_FROM_ENV          0x1000
 
 PHP_HTTP_API void php_http_url(int flags, const php_url *old_url, const php_url *new_url, php_url **url_ptr, char **url_str, size_t *url_len TSRMLS_DC);
-PHP_HTTP_API char *php_http_url_absolute(const char *url, int flags TSRMLS_DC);
 
 PHP_HTTP_API STATUS php_http_url_encode_hash(HashTable *hash, const char *pre_encoded_str, size_t pre_encoded_len, char **encoded_str, size_t *encoded_len TSRMLS_DC);
 PHP_HTTP_API STATUS php_http_url_encode_hash_ex(HashTable *ht, php_http_buffer_t *str, const char *arg_sep_str, size_t arg_sep_len, const char *val_sep_str, size_t val_sep_len, const char *prefix_str, size_t prefix_len TSRMLS_DC);
@@ -163,6 +162,7 @@ extern zend_function_entry php_http_url_method_entry[];
 PHP_METHOD(HttpUrl, __construct);
 PHP_METHOD(HttpUrl, mod);
 PHP_METHOD(HttpUrl, toString);
+PHP_METHOD(HttpUrl, toArray);
 
 extern PHP_MINIT_FUNCTION(http_url);
 
diff --git a/phpunit/HeaderTest.php b/phpunit/HeaderTest.php
new file mode 100644 (file)
index 0000000..41d3af8
--- /dev/null
@@ -0,0 +1,27 @@
+<?php
+
+class HeaderTest extends PHPUnit_Framework_TestCase {
+    function setUp() {
+        $this->h = new http\Header("foo", "bar");
+    }
+    function testString() {
+        $this->assertEquals("Foo: bar", (string) $this->h);
+    }
+
+    function testSerialize() {
+        $this->assertEquals("Foo: bar", (string) unserialize(serialize($this->h)));
+    }
+
+    function testMatch() {
+        $ae = new http\Header("Accept-encoding", "gzip, deflate");
+        $this->assertTrue($ae->match("gzip", http\Header::MATCH_WORD));
+        $this->assertTrue($ae->match("gzip", http\Header::MATCH_WORD|http\Header::MATCH_CASE));
+        $this->assertFalse($ae->match("gzip", http\Header::MATCH_STRICT));
+        $this->assertTrue($ae->match("deflate", http\Header::MATCH_WORD));
+        $this->assertTrue($ae->match("deflate", http\Header::MATCH_WORD|http\Header::MATCH_CASE));
+        $this->assertFalse($ae->match("deflate", http\Header::MATCH_STRICT));
+
+        $this->assertFalse($ae->match("zip", http\Header::MATCH_WORD));
+        $this->assertFalse($ae->match("gzip", http\Header::MATCH_FULL));
+    }
+}
diff --git a/phpunit/ObjectTest.php b/phpunit/ObjectTest.php
new file mode 100644 (file)
index 0000000..bce3a52
--- /dev/null
@@ -0,0 +1,68 @@
+<?php
+
+class eh extends http\Object {
+}
+
+class ObjectTest extends PHPUnit_Framework_TestCase {
+    function testDefaultErrorHandling() {
+        $this->assertEquals(http\Object::EH_NORMAL, http\Object::getDefaultErrorHandling());
+        http\Object::setDefaultErrorHandling(http\Object::EH_SUPPRESS);
+        $this->assertEquals(http\Object::EH_SUPPRESS, http\Object::getDefaultErrorHandling());
+    }
+
+    function testErrorHandling() {
+        $eh = new eh;
+        $this->assertEquals(eh::EH_NORMAL, $eh->getErrorHandling());
+        $eh->setErrorHandling(eh::EH_SUPPRESS);
+        $this->assertEquals(eh::EH_SUPPRESS, $eh->getErrorHandling());
+    }
+
+    function testSuppress() {
+        http\Object::setDefaultErrorHandling(http\Object::EH_SUPPRESS);
+        (new eh)->triggerError(E_USER_WARNING, http\Exception::E_UNKNOWN, "suppress");
+    }
+
+    function testException() {
+        http\Object::setDefaultErrorHandling(http\Object::EH_THROW);
+        $this->setExpectedException("http\\Exception");
+        (new eh)->triggerError(E_USER_WARNING, http\Exception::E_UNKNOWN, "exception");
+    }
+
+    function testNormalError() {
+        http\Object::setDefaultErrorHandling(http\Object::EH_NORMAL);
+        $this->setExpectedException("PHPUnit_Framework_Error_Warning");
+        (new eh)->triggerError(E_USER_WARNING, http\Exception::E_UNKNOWN, "warning");
+    }
+
+    function testSuppress2() {
+        $eh = new eh;
+        $eh->setErrorHandling(http\Object::EH_SUPPRESS);
+        $eh->triggerError(E_USER_WARNING, http\Exception::E_UNKNOWN, "suppress");
+    }
+
+    function testException2() {
+        $eh = new eh;
+        $eh->setErrorHandling(http\Object::EH_THROW);
+        $this->setExpectedException("http\\Exception");
+        $eh->triggerError(E_USER_WARNING, http\Exception::E_UNKNOWN, "exception");
+    }
+
+    function testNormalError2() {
+        $eh = new eh;
+        $eh->setErrorHandling(http\Object::EH_NORMAL);
+        $this->setExpectedException("PHPUnit_Framework_Error_Warning");
+        $eh->triggerError(E_USER_WARNING, http\Exception::E_UNKNOWN, "warning");
+    }
+
+    function testUnknownDefaultErrorHandling() {
+        $this->setExpectedException("PHPUnit_Framework_Error_Warning");
+        http\Object::setDefaultErrorHandling(12345);
+    }
+
+    function testUnknownErrorHandling() {
+        $eh = new eh;
+        $this->setExpectedException("PHPUnit_Framework_Error_Warning");
+        $eh->setErrorHandling(12345);
+    }
+}
+
index 0e139b8..d441535 100644 (file)
@@ -17,6 +17,39 @@ class ParamsTest extends PHPUnit_Framework_TestCase {
         );
     }
 
+    function testEmpty() {
+        $p = new http\Params(NULL);
+        $this->assertEquals(array(), $p->params);
+    }
+
+    function testErrorOfToArrayWithArgs() {
+        $this->setExpectedException("PHPUnit_Framework_Error_Warning");
+        $p = new http\Params();
+        $p->toArray("dummy");
+    }
+
+    function testIntegerKeys() {
+        $p = new http\Params("0=nothing;1=yes");
+        $this->assertEquals(array("0" => array("value" => "nothing", "arguments" => array(1=>"yes"))), $p->params);
+        $this->assertEquals("0=nothing;1=yes", $p->toString());
+    }
+
+    function testBoolParamArguments() {
+        $p = new http\Params;
+        $container = array("value" => false, "arguments" => array("wrong" => false, "correct" => true));
+        $p["container"] = $container;
+        $this->assertEquals("container=0;wrong=0;correct", $p->toString());
+        $this->assertEquals(array("container" => $container), $p->toArray());
+    }
+
+    function testNoArgsForParam() {
+        $p = new http\Params;
+        $p["param"] = true;
+        $this->assertEquals("param", $p->toString());
+        $p["param"] = false;
+        $this->assertEquals("param=0", $p->toString());
+    }
+
     protected function runAssertions($p, $s) {
         $this->assertCount(3, $p->params);
         $this->assertArrayHasKey("foo", $p->params);
@@ -37,34 +70,35 @@ class ParamsTest extends PHPUnit_Framework_TestCase {
 
         $this->assertEquals($s, (string) $p);
 
-        $this->assertEquals(
+        $comp = array (
+            'foo' => 
             array (
-                'foo' => 
+                'value' => true,
+                'arguments' => 
                 array (
-                    'value' => true,
-                    'arguments' => 
-                    array (
-                    ),
                 ),
-                'bar' => 
+            ),
+            'bar' => 
+            array (
+                'value' => true,
+                'arguments' => 
                 array (
-                    'value' => true,
-                    'arguments' => 
-                    array (
-                        'arg' => '0',
-                        'bla' => true,
-                    ),
+                    'arg' => '0',
+                    'bla' => true,
                 ),
-                'gotit' => 
+            ),
+            'gotit' => 
+            array (
+                'value' => '0',
+                'arguments' => 
                 array (
-                    'value' => '0',
-                    'arguments' => 
-                    array (
-                        'now' => true,
-                    ),
+                    'now' => true,
                 ),
             ),
-            $p->params
         );
+
+        $this->assertEquals($comp, $p->params);
+        $a = new http\Params($p->params);
+        $this->assertEquals($comp, $a->toArray());
        }
 }
index ebd020f..3f66e52 100644 (file)
@@ -5,7 +5,7 @@ class UrlTest extends PHPUnit_Framework_TestCase {
        function setUp() {
                $this->url = "http://user:pass@www.example.com:8080/path/file.ext".
                        "?foo=bar&more[]=1&more[]=2#hash";
-       }
+    }
 
        function testStandard() {
                $this->assertEquals($this->url, (string) new http\Url($this->url));
@@ -25,6 +25,24 @@ class UrlTest extends PHPUnit_Framework_TestCase {
                $this->assertEquals(8080, $url->port);
                $this->assertEquals("/path/changed", $url->path);
                $this->assertEquals("foo=&more%5B0%5D=1&more%5B1%5D=2&added=this", $url->query);
-               $this->assertEmpty($url->fragment);
-       }
+        $this->assertEmpty($url->fragment);
+    }
+
+    function testMod() {
+        $tmp = new http\Url($this->url);
+        $mod = $tmp->mod(array("query" => "set=1"), http\Url::REPLACE);
+        $this->assertNotEquals($tmp->toArray(), $mod->toArray());
+        $this->assertEquals("set=1", $mod->query);
+        $this->assertEquals("new_fragment", $tmp->mod("#new_fragment")->fragment);
+    }
+
+    function testStrings() {
+        $url = new http\Url($this->url);
+        $this->assertEquals((string) $url, (string) new http\Url((string) $url));
+    }
+
+    function testArrays() {
+        $url = new http\Url($this->url);
+        $this->assertEquals($url->toArray(), (new http\Url($url->toArray()))->toArray());
+    }
 }
index 624d502..3ecefde 100644 (file)
@@ -4,7 +4,10 @@ Connection: close
 
 HTTP/1.1 200 OK
 Date: Wed, 25 Aug 2010 12:11:44 GMT
-Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6
+Server: Apache/2.2.16 (Unix) 
+    mod_ssl/2.2.16 
+    OpenSSL/1.0.0a 
+    mod_fastcgi/2.4.6
 Last-Modified: Wed, 28 Apr 2010 10:54:37 GMT
 ETag: "2002a-0-48549d615a35c"
 Accept-Ranges: bytes
index 4e83adb..dfef7c2 100644 (file)
@@ -44,6 +44,6 @@ http://www.cbs.com
 http://www.nbc.com
 http://slashdot.org
 http://www.bloglines.com
-http://www.techweb.com
+http://www.freecode.org
 http://www.newslink.org
 http://www.un.org
diff --git a/tests/envresponseheader001.phpt b/tests/envresponseheader001.phpt
new file mode 100644 (file)
index 0000000..fe7fc75
--- /dev/null
@@ -0,0 +1,21 @@
+--TEST--
+env response header
+--SKIPIF--
+<?php include "skipif.inc"; ?>
+--FILE--
+<?php
+
+http\Env::setResponseHeader("No", "way");
+http\Env::setResponseHeader("Foo", "bar");
+http\Env::setResponseHeader("No", null);
+
+print_r(http\Env::getResponseHeader());
+
+--EXPECTHEADERS--
+Foo: bar
+--EXPECTF--
+Array
+(
+    [X-Powered-By] => %s
+    [Foo] => bar
+)
index 8a10811..7b6b534 100644 (file)
@@ -10,6 +10,11 @@ echo "Test\n";
 
 use http\Message as HttpMessage;
 
+try {
+    echo new HttpMessage(" gosh\n nosh\n ");
+} catch (Exception $ignore) {
+}
+
 $m = new HttpMessage();
 echo $m;
 var_dump(
diff --git a/tests/phpunit.phpt b/tests/phpunit.phpt
new file mode 100644 (file)
index 0000000..4289ffd
--- /dev/null
@@ -0,0 +1,20 @@
+--TEST--
+unit tests
+--SKIPIF--
+<?php
+@include_once "PHPUnit/Autoload.php" or die("skip need PHPUnit in include_path");
+?>
+--FILE--
+<?php
+require_once "PHPUnit/Autoload.php";
+(new PHPUnit_TextUI_Command)->run([null, __DIR__."/../phpunit"]);
+?>
+--EXPECTF--
+PHPUnit %s by Sebastian Bergmann.
+
+%s
+
+Time: %s, Memory: %s
+
+OK (%d tests, %d assertions)
+
diff --git a/tests/url001.phpt b/tests/url001.phpt
new file mode 100644 (file)
index 0000000..6519ddf
--- /dev/null
@@ -0,0 +1,25 @@
+--TEST--
+url from env
+--SKIPIF--
+<? include "skippif.inc"; ?>
+--ENV--
+SERVER_PORT=55555
+HTTP_HOST=example.com
+--GET--
+s=b&i=0&e=&a[]=1&a[]=2
+--FILE--
+<?php
+printf("%s\n", new http\Url);
+printf("%s\n", new http\Url("other", "index"));
+printf("%s\n", new http\Url(array("scheme" => "https", "port" => 443)));
+printf("%s\n", new http\Url(array("path" => "/./up/../down/../././//index.php/.", "query" => null)));
+printf("%s\n", new http\Url(null, null, 0));
+?>
+DONE
+--EXPECTF--
+http://example.com:55555/?s=b&i=0&e=&a[]=1&a[]=2
+http://example.com:55555/index?s=b&i=0&e=&a[]=1&a[]=2
+https://example.com/?s=b&i=0&e=&a[]=1&a[]=2
+http://example.com:55555/index.php/
+http://localhost/
+DONE