#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
static inline char *localhostname(void)
{
char hostname[1024] = {0};
-
+
#if PHP_WIN32
if (SUCCESS == gethostname(hostname, lenof(hostname))) {
return estrdup(hostname);
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);
}
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));
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);
if (!(flags & PHP_HTTP_URL_STRIP_FRAGMENT)) {
url_copy(fragment);
}
-
+
/* done with copy & combine & strip */
if (flags & PHP_HTTP_URL_FROM_ENV) {
&& 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':
url(buf)->port = 0;
}
}
-
+
return url(buf);
}
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);
}
#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;
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;
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'",
}
}
+ if (state->flags & PHP_HTTP_URL_IGNORE_ERRORS) {
+ state->buffer[state->offset++] = *ptr;
+ return 1;
+ }
+
return 0;
}
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;
}
break;
}
- } while(++ptr != end);
+ } while(++ptr < end);
state->buffer[state->offset++] = 0;
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) {
#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);
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
}
#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;
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);
#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
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);
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;
}
label = ptr;
ptr += mb - 1;
}
- } while (++ptr != end);
+ } while (++ptr < end);
if (!state->url.host) {
len = state->offset - len;
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;
}
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;
}
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;
}
}
state->ptr += mb - 1;
}
- } while (++state->ptr != state->end);
+ } while (++state->ptr < state->end);
softfail:
state->offset = 0;
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;
}
}
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;
}
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);
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);