- fix property access
[m6w6/ext-http] / http_functions.c
index ae27b5ea7f213ad46bb174b6a70c060b933c7ff1..63a3423bb52341443cecb476bf8caf2d60926af1 100644 (file)
@@ -20,6 +20,8 @@
 #endif
 #include "php.h"
 
+#include "zend_operators.h"
+
 #include "SAPI.h"
 #include "php_ini.h"
 #include "ext/standard/info.h"
@@ -31,9 +33,9 @@
 #include "php_http.h"
 #include "php_http_std_defs.h"
 #include "php_http_api.h"
-#include "php_http_auth_api.h"
 #include "php_http_request_api.h"
 #include "php_http_cache_api.h"
+#include "php_http_request_method_api.h"
 #include "php_http_request_api.h"
 #include "php_http_date_api.h"
 #include "php_http_headers_api.h"
@@ -98,11 +100,54 @@ PHP_FUNCTION(http_absolute_uri)
 }
 /* }}} */
 
-/* {{{ proto string http_negotiate_language(array supported[, string default = 'en-US'])
+#define HTTP_DO_NEGOTIATE(type, supported, as_array) \
+{ \
+       HashTable *result; \
+       if (result = http_negotiate_ ##type(supported)) { \
+               if (as_array) { \
+                       Z_TYPE_P(return_value) = IS_ARRAY; \
+                       Z_ARRVAL_P(return_value) = result; \
+               } else { \
+                       char *key; \
+                       uint key_len; \
+                       ulong idx; \
+                        \
+                       if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(result, &key, &key_len, &idx, 1, NULL)) { \
+                               RETVAL_STRINGL(key, key_len-1, 0); \
+                       } else { \
+                               RETVAL_NULL(); \
+                       } \
+                       zend_hash_destroy(result); \
+               } \
+       } else { \
+               if (as_array) { \
+                       zval **value; \
+                        \
+                       array_init(return_value); \
+                        \
+                       FOREACH_VAL(supported, value) { \
+                               convert_to_string_ex(value); \
+                               add_assoc_double(return_value, Z_STRVAL_PP(value), 1.0); \
+                       } \
+               } else { \
+                       zval **value; \
+                        \
+                       zend_hash_internal_pointer_reset(Z_ARRVAL_P(supported)); \
+                       if (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(supported), (void **) &value)) { \
+                               RETVAL_ZVAL(*value, 1, 0); \
+                       } else { \
+                               RETVAL_NULL(); \
+                       } \
+               } \
+       } \
+}
+
+
+/* {{{ proto string http_negotiate_language(array supported[, bool return_quality_array = false])
  *
  * This function negotiates the clients preferred language based on its
  * Accept-Language HTTP header.  It returns the negotiated language or
- * the default language if none match.
+ * the default language (i.e. first array entry) if none match.
  *
  * The qualifier is recognized and languages without qualifier are rated highest.
  *
@@ -129,26 +174,21 @@ PHP_FUNCTION(http_absolute_uri)
 PHP_FUNCTION(http_negotiate_language)
 {
        zval *supported;
-       char *def = NULL;
-       int def_len = 0;
+       zend_bool as_array = 0;
 
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|s", &supported, &def, &def_len) != SUCCESS) {
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|b", &supported, &as_array) != SUCCESS) {
                RETURN_FALSE;
        }
-
-       if (!def) {
-               def = "en-US";
-       }
-
-       RETURN_STRING(http_negotiate_language(supported, def), 0);
+       
+       HTTP_DO_NEGOTIATE(language, supported, as_array);
 }
 /* }}} */
 
-/* {{{ proto string http_negotiate_charset(array supported[, string default = 'iso-8859-1'])
+/* {{{ proto string http_negotiate_charset(array supported)
  *
  * This function negotiates the clients preferred charset based on its
  * Accept-Charset HTTP header.  It returns the negotiated charset or
- * the default charset if none match.
+ * the default charset (i.e. first array entry) if none match.
  *
  * The qualifier is recognized and charset without qualifier are rated highest.
  *
@@ -176,18 +216,13 @@ PHP_FUNCTION(http_negotiate_language)
 PHP_FUNCTION(http_negotiate_charset)
 {
        zval *supported;
-       char *def = NULL;
-       int def_len = 0;
+       zend_bool as_array = 0;
 
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|s", &supported, &def, &def_len) != SUCCESS) {
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|b", &supported, &as_array) != SUCCESS) {
                RETURN_FALSE;
        }
 
-       if (!def) {
-               def = "iso-8859-1";
-       }
-
-       RETURN_STRING(http_negotiate_charset(supported, def), 0);
+       HTTP_DO_NEGOTIATE(charset, supported, as_array);
 }
 /* }}} */
 
@@ -408,7 +443,7 @@ PHP_FUNCTION(ob_etaghandler)
        }
 
        Z_TYPE_P(return_value) = IS_STRING;
-       http_ob_etaghandler(data, data_len, &Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value), mode);
+       http_ob_etaghandler(data, data_len, &Z_STRVAL_P(return_value), (uint *) &Z_STRLEN_P(return_value), mode);
 }
 /* }}} */
 
@@ -461,9 +496,7 @@ PHP_FUNCTION(http_redirect)
        size_t query_len = 0;
        zend_bool session = 0, permanent = 0, free_params = 0;
        zval *params = NULL;
-       char *query = NULL, *url = NULL, *URI,
-               LOC[HTTP_URI_MAXLEN + sizeof("Location: ")],
-               RED[HTTP_URI_MAXLEN * 2 + sizeof("Redirecting to <a href=\"%s?%s\">%s?%s</a>.\n")];
+       char *query = NULL, *url = NULL, *URI, *LOC, *RED = NULL;
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sa!/bb", &url, &url_len, &params, &session, &permanent) != SUCCESS) {
                RETURN_FALSE;
@@ -527,11 +560,15 @@ PHP_FUNCTION(http_redirect)
        URI = http_absolute_uri(url);
 
        if (query_len) {
-               snprintf(LOC, HTTP_URI_MAXLEN + sizeof("Location: "), "Location: %s?%s", URI, query);
-               sprintf(RED, "Redirecting to <a href=\"%s?%s\">%s?%s</a>.\n", URI, query, URI, query);
+               spprintf(&LOC, 0, "Location: %s?%s", URI, query);
+               if (SG(request_info).request_method && strcmp(SG(request_info).request_method, "HEAD")) {
+                       spprintf(&RED, 0, "Redirecting to <a href=\"%s?%s\">%s?%s</a>.\n", URI, query, URI, query);
+               }
        } else {
-               snprintf(LOC, HTTP_URI_MAXLEN + sizeof("Location: "), "Location: %s", URI);
-               sprintf(RED, "Redirecting to <a href=\"%s\">%s</a>.\n", URI, URI);
+               spprintf(&LOC, 0, "Location: %s", URI);
+               if (SG(request_info).request_method && strcmp(SG(request_info).request_method, "HEAD")) {
+                       spprintf(&RED, 0, "Redirecting to <a href=\"%s\">%s</a>.\n", URI, URI);
+               }
        }
        
        efree(URI);
@@ -543,13 +580,7 @@ PHP_FUNCTION(http_redirect)
                FREE_ZVAL(params);
        }
 
-       if ((SUCCESS == http_send_header_string(LOC)) && (SUCCESS == http_send_status((permanent ? 301 : 302)))) {
-               if (SG(request_info).request_method && strcmp(SG(request_info).request_method, "HEAD")) {
-                       PHPWRITE(RED, strlen(RED));
-               }
-               RETURN_TRUE;
-       }
-       RETURN_FALSE;
+       RETURN_SUCCESS(http_exit_ex(permanent ? 301 : 302, LOC, RED, 1));
 }
 /* }}} */
 
@@ -619,104 +650,21 @@ PHP_FUNCTION(http_send_stream)
 PHP_FUNCTION(http_chunked_decode)
 {
        char *encoded = NULL, *decoded = NULL;
-       int encoded_len = 0, decoded_len = 0;
+       size_t decoded_len = 0;
+       int encoded_len = 0;
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &encoded, &encoded_len) != SUCCESS) {
                RETURN_FALSE;
        }
 
        if (NULL != http_chunked_decode(encoded, encoded_len, &decoded, &decoded_len)) {
-               RETURN_STRINGL(decoded, decoded_len, 0);
+               RETURN_STRINGL(decoded, (int) decoded_len, 0);
        } else {
                RETURN_FALSE;
        }
 }
 /* }}} */
 
-/* {{{ proto array http_split_response(string http_response)
- *
- * This function splits an HTTP response into an array with headers and the
- * content body. The returned array may look simliar to the following example:
- *
- * <pre>
- * <?php
- * array(
- *     0 => array(
- *         'Response Status' => '200 Ok',
- *         'Content-Type' => 'text/plain',
- *         'Content-Language' => 'en-US'
- *     ),
- *     1 => "Hello World!"
- * );
- * ?>
- * </pre>
- */
-PHP_FUNCTION(http_split_response)
-{
-       char *response, *body;
-       int response_len;
-       size_t body_len;
-       zval *zheaders;
-
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &response, &response_len) != SUCCESS) {
-               RETURN_FALSE;
-       }
-
-       MAKE_STD_ZVAL(zheaders);
-       array_init(zheaders);
-
-       if (SUCCESS != http_split_response(response, response_len, Z_ARRVAL_P(zheaders), &body, &body_len)) {
-               RETURN_FALSE;
-       }
-
-       array_init(return_value);
-       add_index_zval(return_value, 0, zheaders);
-       add_index_stringl(return_value, 1, body, body_len, 0);
-}
-/* }}} */
-
-static void http_message_toobject_recursive(http_message *msg, zval *obj TSRMLS_DC)
-{
-       zval *headers;
-       
-       add_property_long(obj, "type", msg->type);
-       switch (msg->type)
-       {
-               case HTTP_MSG_RESPONSE:
-                       add_property_double(obj, "httpVersion", msg->info.response.http_version);
-                       add_property_long(obj, "responseCode", msg->info.response.code);
-               break;
-               
-               case HTTP_MSG_REQUEST:
-                       add_property_double(obj, "httpVersion", msg->info.request.http_version);
-                       add_property_string(obj, "requestMethod", msg->info.request.method, 1);
-                       add_property_string(obj, "requestUri", msg->info.request.URI, 1);
-               break;
-       }
-       
-       MAKE_STD_ZVAL(headers);
-       array_init(headers);
-       zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
-       add_property_zval(obj, "headers", headers);
-       zval_ptr_dtor(&headers);
-       
-       add_property_stringl(obj, "body", PHPSTR_VAL(msg), PHPSTR_LEN(msg), 1);
-       
-       if (msg->parent) {
-               zval *parent;
-               
-               MAKE_STD_ZVAL(parent);
-               object_init(parent);
-               add_property_zval(obj, "parentMessage", parent);
-               http_message_toobject_recursive(msg->parent, parent TSRMLS_CC);
-               zval_ptr_dtor(&parent);
-       } else {
-               add_property_null(obj, "parentMessage");
-       }
-       http_message_dtor(msg);
-       efree(msg);
-}
-
 /* {{{ proto object http_parse_message(string message)
  *
  * Parses (a) http_message(s) into a simple recursive object structure:
@@ -766,7 +714,8 @@ PHP_FUNCTION(http_parse_message)
        
        if (msg = http_message_parse(message, message_len)) {
                object_init(return_value);
-               http_message_toobject_recursive(msg, return_value TSRMLS_CC);
+               http_message_tostruct_recursive(msg, return_value);
+               http_message_free(&msg);
        } else {
                RETURN_NULL();
        }
@@ -908,7 +857,6 @@ PHP_FUNCTION(http_match_request_header)
  *     'content_type' => 'text/html; charset=iso-8859-1',
  *     'redirect_time' => 0,
  *     'redirect_count' => 0,
- *     'private' => '',
  *     'http_connectcode' => 0,
  *     'httpauth_avail' => 0,
  *     'proxyauth_avail' => 0,
@@ -934,7 +882,7 @@ PHP_FUNCTION(http_get)
 
        phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
        if (SUCCESS == http_get(URL, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
-               RETURN_PHPSTR_VAL(response);
+               RETURN_PHPSTR_VAL(&response);
        } else {
                RETURN_FALSE;
        }
@@ -965,14 +913,14 @@ PHP_FUNCTION(http_head)
 
        phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
        if (SUCCESS == http_head(URL, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
-               RETURN_PHPSTR_VAL(response);
+               RETURN_PHPSTR_VAL(&response);
        } else {
                RETURN_FALSE;
        }
 }
 /* }}} */
 
-/* {{{ proto string http_post_data(string url, string data[, array options[, &info]])
+/* {{{ proto string http_post_data(string url, string data[, array options[, array &info]])
  *
  * Performs an HTTP POST request, posting data.
  * Returns the HTTP response as string.
@@ -1001,7 +949,7 @@ PHP_FUNCTION(http_post_data)
 
        phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
        if (SUCCESS == http_post(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
-               RETVAL_PHPSTR_VAL(response);
+               RETVAL_PHPSTR_VAL(&response);
        } else {
                RETVAL_FALSE;
        }
@@ -1037,7 +985,7 @@ PHP_FUNCTION(http_post_fields)
 
        phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
        if (SUCCESS == http_post(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
-               RETVAL_PHPSTR_VAL(response);
+               RETVAL_PHPSTR_VAL(&response);
        } else {
                RETVAL_FALSE;
        }
@@ -1084,7 +1032,7 @@ PHP_FUNCTION(http_put_file)
 
        phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
        if (SUCCESS == http_put(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
-               RETVAL_PHPSTR_VAL(response);
+               RETVAL_PHPSTR_VAL(&response);
        } else {
                RETVAL_FALSE;
        }
@@ -1128,12 +1076,14 @@ PHP_FUNCTION(http_put_stream)
 
        phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
        if (SUCCESS == http_put(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
-               RETURN_PHPSTR_VAL(response);
+               RETURN_PHPSTR_VAL(&response);
        } else {
                RETURN_NULL();
        }
 }
 /* }}} */
+#endif /* HTTP_HAVE_CURL */
+/* }}} HAVE_CURL */
 
 /* {{{ proto long http_request_method_register(string method)
  *
@@ -1173,7 +1123,6 @@ PHP_FUNCTION(http_request_method_unregister)
                case IS_OBJECT:
                        convert_to_string(method);
                case IS_STRING:
-#include "zend_operators.h"
                        if (is_numeric_string(Z_STRVAL_P(method), Z_STRLEN_P(method), NULL, NULL, 1)) {
                                convert_to_long(method);
                        } else {
@@ -1241,118 +1190,6 @@ PHP_FUNCTION(http_request_method_name)
        }
 }
 /* }}} */
-#endif
-/* }}} HAVE_CURL */
-
-
-/* {{{ proto bool http_auth_basic(string user, string pass[, string realm = "Restricted"])
- *
- * Example:
- * <pre>
- * <?php
- * if (!http_auth_basic('mike', 's3c|r3t')) {
- *     die('<h1>Authorization failed!</h1>');
- * }
- * ?>
- * </pre>
- */
-PHP_FUNCTION(http_auth_basic)
-{
-       char *realm = NULL, *user, *pass, *suser, *spass;
-       int r_len, u_len, p_len;
-
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s", &user, &u_len, &pass, &p_len, &realm, &r_len) != SUCCESS) {
-               RETURN_FALSE;
-       }
-
-       if (!realm) {
-               realm = "Restricted";
-       }
-
-       if (SUCCESS != http_auth_basic_credentials(&suser, &spass)) {
-               http_auth_basic_header(realm);
-               RETURN_FALSE;
-       }
-
-       if (strcasecmp(suser, user)) {
-               http_auth_basic_header(realm);
-               RETURN_FALSE;
-       }
-
-       if (strcmp(spass, pass)) {
-               http_auth_basic_header(realm);
-               RETURN_FALSE;
-       }
-
-       RETURN_TRUE;
-}
-/* }}} */
-
-/* {{{ proto bool http_auth_basic_cb(mixed callback[, string realm = "Restricted"])
- *
- * Example:
- * <pre>
- * <?php
- * function auth_cb($user, $pass)
- * {
- *     global $db;
- *     $query = 'SELECT pass FROM users WHERE user='. $db->quoteSmart($user);
- *     if (strlen($realpass = $db->getOne($query)) {
- *         return $pass === $realpass;
- *     }
- *     return false;
- * }
- * if (!http_auth_basic_cb('auth_cb')) {
- *     die('<h1>Authorization failed</h1>');
- * }
- * ?>
- * </pre>
- */
-PHP_FUNCTION(http_auth_basic_cb)
-{
-       zval *cb;
-       char *realm = NULL, *user, *pass;
-       int r_len;
-
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|s", &cb, &realm, &r_len) != SUCCESS) {
-               RETURN_FALSE;
-       }
-
-       if (!realm) {
-               realm = "Restricted";
-       }
-
-       if (SUCCESS != http_auth_basic_credentials(&user, &pass)) {
-               http_auth_basic_header(realm);
-               RETURN_FALSE;
-       }
-       {
-               zval *zparams[2] = {NULL, NULL}, retval;
-               int result = 0;
-
-               MAKE_STD_ZVAL(zparams[0]);
-               MAKE_STD_ZVAL(zparams[1]);
-               ZVAL_STRING(zparams[0], user, 0);
-               ZVAL_STRING(zparams[1], pass, 0);
-
-               if (SUCCESS == call_user_function(EG(function_table), NULL, cb,
-                               &retval, 2, zparams TSRMLS_CC)) {
-                       result = Z_LVAL(retval);
-               }
-
-               efree(user);
-               efree(pass);
-               efree(zparams[0]);
-               efree(zparams[1]);
-
-               if (!result) {
-                       http_auth_basic_header(realm);
-               }
-
-               RETURN_BOOL(result);
-       }
-}
-/* }}}*/
 
 /* {{{ Sara Golemons http_build_query() */
 #ifndef ZEND_ENGINE_2
@@ -1381,12 +1218,12 @@ PHP_FUNCTION(http_build_query)
 
        formstr = phpstr_new();
        if (SUCCESS != http_urlencode_hash_implementation_ex(HASH_OF(formdata), formstr, arg_sep, prefix, prefix_len, NULL, 0, NULL, 0, (Z_TYPE_P(formdata) == IS_OBJECT ? formdata : NULL))) {
-               phpstr_free(formstr);
+               phpstr_free(&formstr);
                RETURN_FALSE;
        }
 
        if (!formstr->used) {
-               phpstr_free(formstr);
+               phpstr_free(&formstr);
                RETURN_NULL();
        }