- added missing HttpMessage::setBody()
[m6w6/ext-http] / http_functions.c
index ba2bd56135717d73c50e2ad40693e5179f29e5cd..617d223f1f335d381bdd085c04c7654c48a0dfa8 100644 (file)
 #ifdef HAVE_CONFIG_H
 #      include "config.h"
 #endif
-
 #include "php.h"
+
+#include "SAPI.h"
 #include "php_ini.h"
 #include "ext/standard/info.h"
-#include "ext/session/php_session.h"
 #include "ext/standard/php_string.h"
-
-#include "SAPI.h"
-
-#include "phpstr/phpstr.h"
+#if defined(HAVE_PHP_SESSION) && !defined(COMPILE_DL_SESSION)
+#      include "ext/session/php_session.h"
+#endif
 
 #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"
@@ -42,6 +41,8 @@
 #include "php_http_send_api.h"
 #include "php_http_url_api.h"
 
+#include "phpstr/phpstr.h"
+
 ZEND_EXTERN_MODULE_GLOBALS(http)
 
 /* {{{ proto string http_date([int timestamp])
@@ -203,7 +204,7 @@ PHP_FUNCTION(http_send_status)
                RETURN_FALSE;
        }
        if (status < 100 || status > 510) {
-               http_error_ex(E_WARNING, HTTP_E_HEADER, "Invalid HTTP status code (100-510): %d", status);
+               http_error_ex(HE_WARNING, HTTP_E_HEADER, "Invalid HTTP status code (100-510): %d", status);
                RETURN_FALSE;
        }
 
@@ -407,7 +408,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);
 }
 /* }}} */
 
@@ -416,7 +417,7 @@ PHP_FUNCTION(ob_etaghandler)
  * Use with http_send() API.
  *
  * Example:
- * <code>
+ * <pre>
  * <?php
  * // ~ 20 kbyte/s
  * # http_throttle(1, 20000);
@@ -424,7 +425,7 @@ PHP_FUNCTION(ob_etaghandler)
  * # http_throttle(0.1, 2000);
  * http_send_file('document.pdf');
  * ?>
- * </code>
+ * </pre>
  */
 PHP_FUNCTION(http_throttle)
 {
@@ -458,30 +459,65 @@ PHP_FUNCTION(http_redirect)
 {
        int url_len;
        size_t query_len = 0;
-       zend_bool session = 0, permanent = 0;
+       zend_bool session = 0, permanent = 0, free_params = 0;
        zval *params = NULL;
-       char *query, *url, *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;
        }
 
        /* append session info */
-       if (session && (PS(session_status) == php_session_active)) {
+       if (session) {
                if (!params) {
+                       free_params = 1;
                        MAKE_STD_ZVAL(params);
                        array_init(params);
                }
-               if (add_assoc_string(params, PS(session_name), PS(id), 1) != SUCCESS) {
-                       http_error(E_WARNING, HTTP_E_ENCODE, "Could not append session information");
+#ifdef HAVE_PHP_SESSION
+#      ifdef COMPILE_DL_SESSION
+               if (SUCCESS == zend_get_module_started("session")) {
+                       zval nm_retval, id_retval, func;
+                       
+                       INIT_PZVAL(&func);
+                       INIT_PZVAL(&nm_retval);
+                       INIT_PZVAL(&id_retval);
+                       ZVAL_NULL(&nm_retval);
+                       ZVAL_NULL(&id_retval);
+                       
+                       ZVAL_STRINGL(&func, "session_id", lenof("session_id"), 0);
+                       call_user_function(EG(function_table), NULL, &func, &id_retval, 0, NULL TSRMLS_CC);
+                       ZVAL_STRINGL(&func, "session_name", lenof("session_name"), 0);
+                       call_user_function(EG(function_table), NULL, &func, &nm_retval, 0, NULL TSRMLS_CC);
+                       
+                       if (    Z_TYPE(nm_retval) == IS_STRING && Z_STRLEN(nm_retval) &&
+                                       Z_TYPE(id_retval) == IS_STRING && Z_STRLEN(id_retval)) {
+                               if (add_assoc_stringl_ex(params, Z_STRVAL(nm_retval), Z_STRLEN(nm_retval)+1, 
+                                               Z_STRVAL(id_retval), Z_STRLEN(id_retval), 0) != SUCCESS) {
+                                       http_error(HE_WARNING, HTTP_E_RUNTIME, "Could not append session information");
+                               }
+                       }
+               }
+#      else
+               if (PS(session_status) == php_session_active) {
+                       if (add_assoc_string(params, PS(session_name), PS(id), 1) != SUCCESS) {
+                               http_error(HE_WARNING, HTTP_E_RUNTIME, "Could not append session information");
+                       }
                }
+#      endif
+#endif
        }
 
        /* treat params array with http_build_query() */
        if (params) {
                if (SUCCESS != http_urlencode_hash_ex(Z_ARRVAL_P(params), 0, NULL, 0, &query, &query_len)) {
+                       if (free_params) {
+                               zval_dtor(params);
+                               FREE_ZVAL(params);
+                       }
+                       if (query) {
+                               efree(query);
+                       }
                        RETURN_FALSE;
                }
        }
@@ -489,20 +525,27 @@ 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);
-               efree(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);
-
-       if ((SUCCESS == http_send_header(LOC)) && (SUCCESS == http_send_status((permanent ? 301 : 302)))) {
-               php_body_write(RED, strlen(RED) TSRMLS_CC);
-               RETURN_TRUE;
+       if (query) {
+               efree(query);
+       }
+       if (free_params) {
+               zval_dtor(params);
+               FREE_ZVAL(params);
        }
-       RETURN_FALSE;
+
+       RETURN_SUCCESS(http_exit_ex(permanent ? 301 : 302, LOC, RED, 1));
 }
 /* }}} */
 
@@ -572,60 +615,75 @@ 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:
+/* {{{ proto object http_parse_message(string message)
  *
+ * Parses (a) http_message(s) into a simple recursive object structure:
+ * 
  * <pre>
  * <?php
- * array(
- *     0 => array(
- *         'Response Status' => '200 Ok',
- *         'Content-Type' => 'text/plain',
- *         'Content-Language' => 'en-US'
- *     ),
- *     1 => "Hello World!"
- * );
+ * print_r(http_parse_message(http_get(URL, array('redirect' => 3)));
+ * 
+ * stdClass object
+ * (
+ *     [type] => 2
+ *     [httpVersion] => 1.1
+ *     [responseCode] => 200
+ *     [headers] => Array 
+ *         (
+ *             [Content-Length] => 3
+ *             [Server] => Apache
+ *         )
+ *     [body]  => Hi!
+ *     [parentMessage] => stdClass object
+ *     (
+ *         [type] => 2
+ *         [httpVersion] => 1.1
+ *         [responseCode] => 302
+ *         [headers] => Array 
+ *             (
+ *                 [Content-Length] => 0
+ *                 [Location] => ...
+ *             )
+ *         [body]  => 
+ *         [parentMessage] => ...
+ *     )
+ * )
  * ?>
  * </pre>
  */
-PHP_FUNCTION(http_split_response)
+PHP_FUNCTION(http_parse_message)
 {
-       zval *zresponse, *zbody, *zheaders;
-
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zresponse) != SUCCESS) {
-               RETURN_FALSE;
+       char *message;
+       int message_len;
+       http_message *msg = NULL;
+       
+       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &message, &message_len)) {
+               RETURN_NULL();
        }
-
-       convert_to_string(zresponse);
-
-       MAKE_STD_ZVAL(zbody);
-       MAKE_STD_ZVAL(zheaders);
-       array_init(zheaders);
-
-       if (SUCCESS != http_split_response(zresponse, zheaders, zbody)) {
-               http_error(E_WARNING, HTTP_E_PARSE, "Could not parse HTTP response");
-               RETURN_FALSE;
+       
+       
+       if (msg = http_message_parse(message, message_len)) {
+               object_init(return_value);
+               http_message_tostruct_recursive(msg, return_value);
+               http_message_free(&msg);
+       } else {
+               RETURN_NULL();
        }
-
-       array_init(return_value);
-       add_index_zval(return_value, 0, zheaders);
-       add_index_zval(return_value, 1, zbody);
 }
 /* }}} */
 
@@ -643,7 +701,6 @@ PHP_FUNCTION(http_parse_headers)
 
        array_init(return_value);
        if (SUCCESS != http_parse_headers(header, return_value)) {
-               http_error(E_WARNING, HTTP_E_PARSE, "Could not parse HTTP headers");
                zval_dtor(return_value);
                RETURN_FALSE;
        }
@@ -652,6 +709,7 @@ PHP_FUNCTION(http_parse_headers)
 
 /* {{{ proto array http_get_request_headers(void)
  *
+ * Get a list of incoming HTTP headers.
  */
 PHP_FUNCTION(http_get_request_headers)
 {
@@ -662,6 +720,43 @@ PHP_FUNCTION(http_get_request_headers)
 }
 /* }}} */
 
+/* {{{ proto string http_get_request_body(void)
+ *
+ * Get the raw request body (e.g. POST or PUT data).
+ */
+PHP_FUNCTION(http_get_request_body)
+{
+       char *body;
+       size_t length;
+
+       NO_ARGS;
+
+       if (SUCCESS == http_get_request_body(&body, &length)) {
+               RETURN_STRINGL(body, (int) length, 0);
+       } else {
+               RETURN_NULL();
+       }
+}
+/* }}} */
+
+/* {{{ proto bool http_match_request_header(string header, string value[, bool match_case = false])
+ *
+ * Match an incoming HTTP header.
+ */
+PHP_FUNCTION(http_match_request_header)
+{
+       char *header, *value;
+       int header_len, value_len;
+       zend_bool match_case = 0;
+
+       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|b", &header, &header_len, &value, &value_len, &match_case)) {
+               RETURN_FALSE;
+       }
+
+       RETURN_BOOL(http_match_request_header_ex(header, value, match_case));
+}
+/* }}} */
+
 /* {{{ HAVE_CURL */
 #ifdef HTTP_HAVE_CURL
 
@@ -700,7 +795,6 @@ PHP_FUNCTION(http_get_request_headers)
  *  - timeout:          int, seconds the request may take
  *  - connecttimeout:   int, seconds the connect may take
  *  - onprogress:       mixed, progress callback
- *  - ondebug:          mixed, debug callback
  * </pre>
  *
  * The optional third parameter will be filled with some additional information
@@ -728,7 +822,6 @@ PHP_FUNCTION(http_get_request_headers)
  *     'content_type' => 'text/html; charset=iso-8859-1',
  *     'redirect_time' => 0,
  *     'redirect_count' => 0,
- *     'private' => '',
  *     'http_connectcode' => 0,
  *     'httpauth_avail' => 0,
  *     'proxyauth_avail' => 0,
@@ -754,7 +847,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;
        }
@@ -785,14 +878,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.
@@ -821,11 +914,10 @@ 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;
        }
-       http_request_body_dtor(&body);
 }
 /* }}} */
 
@@ -858,7 +950,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;
        }
@@ -868,6 +960,9 @@ PHP_FUNCTION(http_post_fields)
 
 /* {{{ proto string http_put_file(string url, string file[, array options[, array &info]])
  *
+ * Performs an HTTP PUT request, uploading file.
+ * Returns the HTTP response as string.
+ * See http_get() for a full list of available options.
  */
 PHP_FUNCTION(http_put_file)
 {
@@ -902,7 +997,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;
        }
@@ -912,6 +1007,9 @@ PHP_FUNCTION(http_put_file)
 
 /* {{{ proto string http_put_stream(string url, resource stream[, array options[, array &info]])
  *
+ * Performs an HTTP PUT request, uploading stream.
+ * Returns the HTTP response as string.
+ * See http_get() for a full list of available options.
  */
 PHP_FUNCTION(http_put_stream)
 {
@@ -943,19 +1041,16 @@ 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();
        }
 }
 /* }}} */
 
-/* {{{ proto bool http_request()
- */
-/* }}} */
-
 /* {{{ proto long http_request_method_register(string method)
  *
+ * Register a custom request method.
  */
 PHP_FUNCTION(http_request_method_register)
 {
@@ -976,6 +1071,7 @@ PHP_FUNCTION(http_request_method_register)
 
 /* {{{ proto bool http_request_method_unregister(mixed method)
  *
+ * Unregister a previously registered custom request method.
  */
 PHP_FUNCTION(http_request_method_unregister)
 {
@@ -1011,6 +1107,7 @@ PHP_FUNCTION(http_request_method_unregister)
 
 /* {{{ proto long http_request_method_exists(mixed method)
  *
+ * Check if a request method is registered (or available by default).
  */
 PHP_FUNCTION(http_request_method_exists)
 {
@@ -1042,6 +1139,7 @@ PHP_FUNCTION(http_request_method_exists)
 
 /* {{{ proto string http_request_method_name(long method)
  *
+ * Get the literal string representation of a standard or registered request method.
  */
 PHP_FUNCTION(http_request_method_name)
 {
@@ -1059,116 +1157,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_credentials(&suser, &spass)) {
-               http_auth_header("Basic", realm);
-               RETURN_FALSE;
-       }
-
-       if (strcasecmp(suser, user)) {
-               http_auth_header("Basic", realm);
-               RETURN_FALSE;
-       }
-
-       if (strcmp(spass, pass)) {
-               http_auth_header("Basic", 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_credentials(&user, &pass)) {
-               http_auth_header("Basic", 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_header("Basic", realm);
-               }
-
-               RETURN_BOOL(result);
-       }
-}
-/* }}}*/
-
 /* {{{ Sara Golemons http_build_query() */
 #ifndef ZEND_ENGINE_2
 
@@ -1186,7 +1174,7 @@ PHP_FUNCTION(http_build_query)
        }
 
        if (Z_TYPE_P(formdata) != IS_ARRAY && Z_TYPE_P(formdata) != IS_OBJECT) {
-               http_error(E_WARNING, HTTP_E_PARAM, "Parameter 1 expected to be Array or Object.  Incorrect value given.");
+               http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Parameter 1 expected to be Array or Object.  Incorrect value given.");
                RETURN_FALSE;
        }
 
@@ -1196,12 +1184,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();
        }
 
@@ -1213,7 +1201,6 @@ PHP_FUNCTION(http_build_query)
 
 PHP_FUNCTION(http_test)
 {
-       RETURN_NULL();
 }
 
 /*
@@ -1224,3 +1211,4 @@ PHP_FUNCTION(http_test)
  * vim600: noet sw=4 ts=4 fdm=marker
  * vim<600: noet sw=4 ts=4
  */
+