compat with master
[m6w6/ext-http] / src / php_http_url.c
index 3c68996689b0ce60c3b7005e63698831c95053a6..65cc3d8097a3ab60a5267a3b32a4431ee7907eab 100644 (file)
 
 #include "php_http_api.h"
 
-#if PHP_HTTP_HAVE_LIBIDN2
-#      include <idn2.h>
-#endif
 #if PHP_HTTP_HAVE_LIBIDN
 #      include <idna.h>
 #endif
+#if PHP_HTTP_HAVE_LIBIDN2
+#      include <idn2.h>
+#endif
 #if PHP_HTTP_HAVE_LIBICU
 #      include <unicode/uidna.h>
 #endif
@@ -40,7 +40,7 @@
 static inline char *localhostname(void)
 {
        char hostname[1024] = {0};
-       
+
 #if PHP_WIN32
        if (SUCCESS == gethostname(hostname, lenof(hostname))) {
                return estrdup(hostname);
@@ -188,9 +188,9 @@ php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_u
        if (!(flags & PHP_HTTP_URL_STRIP_PASS)) {
                url_copy(pass);
        }
-       
+
        url_copy(host);
-       
+
        if (!(flags & PHP_HTTP_URL_STRIP_PORT)) {
                url(buf)->port = url_isset(new_url, port) ? new_url->port : ((old_url) ? old_url->port : 0);
        }
@@ -199,14 +199,14 @@ php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_u
                if ((flags & PHP_HTTP_URL_JOIN_PATH) && url_isset(old_url, path) && url_isset(new_url, path) && *new_url->path != '/') {
                        size_t old_path_len = strlen(old_url->path), new_path_len = strlen(new_url->path);
                        char *path = ecalloc(1, old_path_len + new_path_len + 1 + 1);
-                       
+
                        strcat(path, old_url->path);
                        if (path[old_path_len - 1] != '/') {
                                php_dirname(path, old_path_len);
                                strcat(path, "/");
                        }
                        strcat(path, new_url->path);
-                       
+
                        url(buf)->path = &buf.data[buf.used];
                        if (path[0] != '/') {
                                url_append(&buf, php_http_buffer_append(&buf, "/", 1));
@@ -235,16 +235,16 @@ php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_u
        if (!(flags & PHP_HTTP_URL_STRIP_QUERY)) {
                if ((flags & PHP_HTTP_URL_JOIN_QUERY) && url_isset(new_url, query) && url_isset(old_url, query)) {
                        zval qarr, qstr;
-                       
+
                        array_init(&qarr);
-                       
+
                        ZVAL_STRING(&qstr, old_url->query);
                        php_http_querystring_update(&qarr, &qstr, NULL);
                        zval_ptr_dtor(&qstr);
                        ZVAL_STRING(&qstr, new_url->query);
                        php_http_querystring_update(&qarr, &qstr, NULL);
                        zval_ptr_dtor(&qstr);
-                       
+
                        ZVAL_NULL(&qstr);
                        php_http_querystring_update(&qarr, NULL, &qstr);
 
@@ -261,7 +261,7 @@ php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_u
        if (!(flags & PHP_HTTP_URL_STRIP_FRAGMENT)) {
                url_copy(fragment);
        }
-       
+
        /* done with copy & combine & strip */
 
        if (flags & PHP_HTTP_URL_FROM_ENV) {
@@ -274,13 +274,13 @@ php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_u
        &&      url(buf)->path
        &&      url(buf)->path[0] && url(buf)->path[1]) {
                char *ptr, *end = url(buf)->path + strlen(url(buf)->path) + 1;
-                       
+
                for (ptr = strchr(url(buf)->path, '/'); ptr; ptr = strchr(ptr, '/')) {
                        switch (ptr[1]) {
                                case '/':
                                        memmove(&ptr[1], &ptr[2], end - &ptr[2]);
                                        break;
-                                       
+
                                case '.':
                                        switch (ptr[2]) {
                                                case '\0':
@@ -328,7 +328,7 @@ php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_u
                        url(buf)->port = 0;
                }
        }
-       
+
        return url(buf);
 }
 
@@ -663,7 +663,7 @@ php_http_url_t *php_http_url_copy(const php_http_url_t *url, zend_bool persisten
        return cpy;
 }
 
-static size_t parse_mb_utf8(unsigned *wc, const char *ptr, const char *end)
+static inline size_t parse_mb_utf8(unsigned *wc, const char *ptr, const char *end)
 {
        unsigned wchar;
        size_t consumed = utf8towc(&wchar, (const unsigned char *) ptr, end - ptr);
@@ -679,7 +679,7 @@ static size_t parse_mb_utf8(unsigned *wc, const char *ptr, const char *end)
 }
 
 #if PHP_HTTP_HAVE_WCHAR
-static size_t parse_mb_loc(unsigned *wc, const char *ptr, const char *end)
+static inline size_t parse_mb_loc(unsigned *wc, const char *ptr, const char *end)
 {
        wchar_t wchar;
        size_t consumed = 0;
@@ -723,7 +723,7 @@ static const char * const parse_what[] = {
 
 static const char parse_xdigits[] = "0123456789ABCDEF";
 
-static size_t parse_mb(struct parse_state *state, parse_mb_what_t what, const char *ptr, const char *end, const char *begin, zend_bool silent)
+static inline size_t parse_mb(struct parse_state *state, parse_mb_what_t what, const char *ptr, const char *end, const char *begin, zend_bool force_silent)
 {
        unsigned wchar;
        size_t consumed = 0;
@@ -767,7 +767,7 @@ static size_t parse_mb(struct parse_state *state, parse_mb_what_t what, const ch
                return consumed;
        }
 
-       if (!silent) {
+       if (!force_silent && !(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) {
                if (consumed) {
                        php_error_docref(NULL, E_WARNING,
                                        "Failed to parse %s; unexpected multibyte sequence 0x%x at pos %u in '%s'",
@@ -779,6 +779,11 @@ static size_t parse_mb(struct parse_state *state, parse_mb_what_t what, const ch
                }
        }
 
+       if (state->flags & PHP_HTTP_URL_IGNORE_ERRORS) {
+               state->buffer[state->offset++] = *ptr;
+               return 1;
+       }
+
        return 0;
 }
 
@@ -828,7 +833,7 @@ static ZEND_RESULT_CODE parse_userinfo(struct parse_state *state, const char *pt
                        break;
 
                default:
-                       if ((mb = parse_mb(state, PARSE_USERINFO, ptr, end, tmp, state->flags & PHP_HTTP_URL_SILENT_ERRORS))) {
+                       if ((mb = parse_mb(state, PARSE_USERINFO, ptr, end, tmp, 0))) {
                                ptr += mb - 1;
                                break;
                        }
@@ -854,7 +859,7 @@ static ZEND_RESULT_CODE parse_userinfo(struct parse_state *state, const char *pt
                        break;
 
                }
-       } while(++ptr != end);
+       } while(++ptr < end);
 
 
        state->buffer[state->offset++] = 0;
@@ -947,11 +952,11 @@ static ZEND_RESULT_CODE parse_gidn_2003(struct parse_state *state, size_t prev_l
        int rv = -1;
 
        if (state->flags & PHP_HTTP_URL_PARSE_MBUTF8) {
-               rv = idna_to_ascii_8z(state->url.host, &idn, IDNA_ALLOW_UNASSIGNED|IDNA_USE_STD3_ASCII_RULES);
+               rv = idna_to_ascii_8z(state->url.host, &idn, IDNA_ALLOW_UNASSIGNED);
        }
 #      if PHP_HTTP_HAVE_WCHAR
        else if (state->flags & PHP_HTTP_URL_PARSE_MBLOC) {
-               rv = idna_to_ascii_lz(state->url.host, &idn, IDNA_ALLOW_UNASSIGNED|IDNA_USE_STD3_ASCII_RULES);
+               rv = idna_to_ascii_lz(state->url.host, &idn, IDNA_ALLOW_UNASSIGNED);
        }
 #      endif
        if (rv != IDNA_SUCCESS) {
@@ -972,9 +977,7 @@ static ZEND_RESULT_CODE parse_gidn_2003(struct parse_state *state, size_t prev_l
 #endif
 
 #if HAVE_UIDNA_IDNTOASCII
-#      if PHP_HTTP_HAVE_LIBICU
-#              include <unicode/uidna.h>
-#      else
+#      if !PHP_HTTP_HAVE_LIBICU
 typedef uint16_t UChar;
 typedef enum { U_ZERO_ERROR = 0 } UErrorCode;
 int32_t uidna_IDNToASCII(const UChar *src, int32_t srcLength, UChar *dest, int32_t destCapacity, int32_t options, void *parseError, UErrorCode *status);
@@ -1003,11 +1006,11 @@ static ZEND_RESULT_CODE parse_uidn_2003(struct parse_state *state)
                goto error;
        }
 
-#      if __GNUC__
+#      if __GNUC__ >= 5
 #              pragma GCC diagnostic ignored "-Wdeprecated-declarations"
 #      endif
        ahost_len = uidna_IDNToASCII(uhost_str, uhost_len, ahost_str, 256, 3, NULL, &rc);
-#      if __GNUC__
+#      if __GNUC__ >= 5
 #              pragma GCC diagnostic pop
 #      endif
 
@@ -1034,16 +1037,13 @@ static ZEND_RESULT_CODE parse_uidn_2003(struct parse_state *state)
 }
 #endif
 
-#if HAVE_UIDNA_IDNTOASCII
-#      if PHP_HTTP_HAVE_LIBICU
-#              include <unicode/uidna.h>
-#      endif
+#if PHP_HTTP_HAVE_LIBICU && HAVE_UIDNA_NAMETOASCII_UTF8
 static ZEND_RESULT_CODE parse_uidn_2008(struct parse_state *state)
 {
        char *host_ptr, *error = NULL, ebuf[64] = {0};
        UErrorCode rc = U_ZERO_ERROR;
        UIDNAInfo info = UIDNA_INFO_INITIALIZER;
-       UIDNA *uidna = uidna_openUTS46(UIDNA_ALLOW_UNASSIGNED|UIDNA_USE_STD3_RULES, &rc);
+       UIDNA *uidna = uidna_openUTS46(UIDNA_ALLOW_UNASSIGNED, &rc);
 
        if (!uidna || U_FAILURE(rc)) {
                return FAILURE;
@@ -1189,12 +1189,12 @@ static ZEND_RESULT_CODE parse_widn_2003(struct parse_state *state)
 static ZEND_RESULT_CODE parse_idna(struct parse_state *state, size_t len)
 {
 #if PHP_HTTP_HAVE_IDNA2008
-       if ((state->flags & PHP_HTTP_URL_PARSE_TOIDN_2008)
+       if ((state->flags & PHP_HTTP_URL_PARSE_TOIDN_2008) == PHP_HTTP_URL_PARSE_TOIDN_2008
 #      if PHP_HTTP_HAVE_IDNA2003
-       || !(state->flags & PHP_HTTP_URL_PARSE_TOIDN_2003)
+       ||      (state->flags & PHP_HTTP_URL_PARSE_TOIDN_2003) != PHP_HTTP_URL_PARSE_TOIDN_2003
 #      endif
        ) {
-#if HAVE_UIDNA_NAMETOASCII_UTF8
+#if PHP_HTTP_HAVE_LIBICU && HAVE_UIDNA_NAMETOASCII_UTF8
                return parse_uidn_2008(state);
 #elif PHP_HTTP_HAVE_LIBIDN2
                return parse_gidn_2008(state, len);
@@ -1205,9 +1205,9 @@ static ZEND_RESULT_CODE parse_idna(struct parse_state *state, size_t len)
 #endif
 
 #if PHP_HTTP_HAVE_IDNA2003
-       if ((state->flags & PHP_HTTP_URL_PARSE_TOIDN_2003)
+       if ((state->flags & PHP_HTTP_URL_PARSE_TOIDN_2003) == PHP_HTTP_URL_PARSE_TOIDN_2003
 #      if PHP_HTTP_HAVE_IDNA2008
-       || !(state->flags & PHP_HTTP_URL_PARSE_TOIDN_2008)
+       ||      (state->flags & PHP_HTTP_URL_PARSE_TOIDN_2008) != PHP_HTTP_URL_PARSE_TOIDN_2008
 #endif
        ) {
 #if HAVE_UIDNA_IDNTOASCII
@@ -1224,7 +1224,7 @@ static ZEND_RESULT_CODE parse_idna(struct parse_state *state, size_t len)
        return parse_widn_2003(state);
 #endif
 
-#if HAVE_UIDNA_NAMETOASCII_UTF8
+#if PHP_HTTP_HAVE_LIBICU && HAVE_UIDNA_NAMETOASCII_UTF8
                return parse_uidn_2008(state);
 #elif PHP_HTTP_HAVE_LIBIDN2
                return parse_gidn_2008(state, len);
@@ -1416,7 +1416,7 @@ static ZEND_RESULT_CODE parse_hostinfo(struct parse_state *state, const char *pt
                                        return FAILURE;
                                }
                                break;
-                       } else if (!(mb = parse_mb(state, PARSE_HOSTINFO, ptr, end, tmp, state->flags & PHP_HTTP_URL_SILENT_ERRORS))) {
+                       } else if (!(mb = parse_mb(state, PARSE_HOSTINFO, ptr, end, tmp, 0))) {
                                if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) {
                                        return FAILURE;
                                }
@@ -1425,7 +1425,7 @@ static ZEND_RESULT_CODE parse_hostinfo(struct parse_state *state, const char *pt
                        label = ptr;
                        ptr += mb - 1;
                }
-       } while (++ptr != end);
+       } while (++ptr < end);
 
        if (!state->url.host) {
                len = state->offset - len;
@@ -1538,7 +1538,7 @@ static const char *parse_path(struct parse_state *state)
                        break;
 
                default:
-                       if (!(mb = parse_mb(state, PARSE_PATH, state->ptr, state->end, tmp, state->flags & PHP_HTTP_URL_SILENT_ERRORS))) {
+                       if (!(mb = parse_mb(state, PARSE_PATH, state->ptr, state->end, tmp, 0))) {
                                if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) {
                                        return NULL;
                                }
@@ -1628,7 +1628,7 @@ static const char *parse_query(struct parse_state *state)
                        break;
 
                default:
-                       if (!(mb = parse_mb(state, PARSE_QUERY, state->ptr, state->end, tmp, state->flags & PHP_HTTP_URL_SILENT_ERRORS))) {
+                       if (!(mb = parse_mb(state, PARSE_QUERY, state->ptr, state->end, tmp, 0))) {
                                if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) {
                                        return NULL;
                                }
@@ -1725,7 +1725,7 @@ static const char *parse_fragment(struct parse_state *state)
                        break;
 
                default:
-                       if (!(mb = parse_mb(state, PARSE_FRAGMENT, state->ptr, state->end, tmp, state->flags & PHP_HTTP_URL_SILENT_ERRORS))) {
+                       if (!(mb = parse_mb(state, PARSE_FRAGMENT, state->ptr, state->end, tmp, 0))) {
                                if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) {
                                        return NULL;
                                }
@@ -1792,7 +1792,7 @@ static const char *parse_scheme(struct parse_state *state)
                        }
                        state->ptr += mb - 1;
                }
-       } while (++state->ptr != state->end);
+       } while (++state->ptr < state->end);
 
 softfail:
        state->offset = 0;
@@ -1810,7 +1810,9 @@ php_http_url_t *php_http_url_parse(const char *str, size_t len, unsigned flags)
        state->maxlen = maxlen;
 
        if (!parse_scheme(state)) {
-               php_error_docref(NULL, E_WARNING, "Failed to parse URL scheme: '%s'", state->ptr);
+               if (!(flags & PHP_HTTP_URL_SILENT_ERRORS)) {
+                       php_error_docref(NULL, E_WARNING, "Failed to parse URL scheme: '%s'", state->ptr);
+               }
                efree(state);
                return NULL;
        }
@@ -1821,13 +1823,17 @@ php_http_url_t *php_http_url_parse(const char *str, size_t len, unsigned flags)
        }
 
        if (!parse_query(state)) {
-               php_error_docref(NULL, E_WARNING, "Failed to parse URL query: '%s'", state->ptr);
+               if (!(flags & PHP_HTTP_URL_SILENT_ERRORS)) {
+                       php_error_docref(NULL, E_WARNING, "Failed to parse URL query: '%s'", state->ptr);
+               }
                efree(state);
                return NULL;
        }
 
        if (!parse_fragment(state)) {
-               php_error_docref(NULL, E_WARNING, "Failed to parse URL fragment: '%s'", state->ptr);
+               if (!(flags & PHP_HTTP_URL_SILENT_ERRORS)) {
+                       php_error_docref(NULL, E_WARNING, "Failed to parse URL fragment: '%s'", state->ptr);
+               }
                efree(state);
                return NULL;
        }
@@ -1896,9 +1902,7 @@ PHP_METHOD(HttpUrl, __construct)
                flags |= PHP_HTTP_URL_FROM_ENV;
        }
 
-       if (flags & PHP_HTTP_URL_SILENT_ERRORS) {
-               zend_replace_error_handling(EH_SUPPRESS, NULL, &zeh);
-       } else if (flags & PHP_HTTP_URL_IGNORE_ERRORS) {
+       if (flags & (PHP_HTTP_URL_SILENT_ERRORS|PHP_HTTP_URL_IGNORE_ERRORS)) {
                zend_replace_error_handling(EH_NORMAL, NULL, &zeh);
        } else {
                zend_replace_error_handling(EH_THROW, php_http_get_exception_bad_url_class_entry(), &zeh);
@@ -1950,9 +1954,7 @@ PHP_METHOD(HttpUrl, mod)
 
        php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "z!|l", &new_url, &flags), invalid_arg, return);
 
-       if (flags & PHP_HTTP_URL_SILENT_ERRORS) {
-               zend_replace_error_handling(EH_SUPPRESS, NULL, &zeh);
-       } else if (flags & PHP_HTTP_URL_IGNORE_ERRORS) {
+       if (flags & (PHP_HTTP_URL_SILENT_ERRORS|PHP_HTTP_URL_IGNORE_ERRORS)) {
                zend_replace_error_handling(EH_NORMAL, NULL, &zeh);
        } else {
                zend_replace_error_handling(EH_THROW, php_http_get_exception_bad_url_class_entry(), &zeh);