+
+ switch (port) {
+ case 443:
+ scheme = estrndup("https", lenof("https"));
+ break;
+
+#if defined(ZTS) && !defined(HAVE_GETSERVBYPORT_R)
+ default:
+#elif !defined(ZTS) && !defined(HAVE_GETSERVBYPORT)
+ default:
+#endif
+ case 80:
+ case 0:
+ scheme = estrndup("http", lenof("http"));
+ break;
+
+#if defined(ZTS) && defined(HAVE_GETSERVBYPORT_R)
+ default:
+ do {
+ buf = erealloc(buf, len);
+ rc = getservbyport_r(htons(port), "tcp", &se_buf, buf, len, &se_res);
+ len *= 2;
+ } while (rc == ERANGE && len <= 0xfff);
+
+ if (!rc && se_res) {
+ scheme = estrdup(se_res->s_name);
+ } else {
+ scheme = estrndup("http", lenof("http"));
+ }
+
+ efree(buf);
+ break;
+
+#elif !defined(ZTS) && defined(HAVE_GETSERVBYPORT)
+ default:
+ if ((se = getservbyport(htons(port), "tcp")) && se->s_name) {
+ scheme = estrdup(se->s_name);
+ } else {
+ scheme = estrndup("http", lenof("http"));
+ }
+ break;
+#endif
+ }
+ return scheme;
+}
+
+static php_url *php_http_url_from_env(php_url *url TSRMLS_DC)
+{
+ zval *https, *zhost, *zport;
+ long port;
+
+ 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 {
+ url->scheme = scheme(url->port);
+ }
+
+ /* 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)) {
+ size_t stop_at = strspn(Z_STRVAL_P(zhost), "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-.");
+
+ url->host = estrndup(Z_STRVAL_P(zhost), stop_at);
+ } 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);
+ }
+ }
+
+ /* query */
+ if (SG(request_info).query_string && SG(request_info).query_string[0]) {
+ url->query = estrdup(SG(request_info).query_string);
+ }
+
+ return url;
+}
+
+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_url *url, *tmp_url = NULL;
+
+ /* 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));