hoppla
[m6w6/ext-http] / http_functions.c
index 550ce8ff7934169059a07e28a842c63f4a094525..869442d38238d458a9597b2a6f84d6adeea84356 100644 (file)
@@ -21,7 +21,7 @@
 #include "ext/standard/php_string.h"
 #include "zend_operators.h"
 
-#ifdef HAVE_PHP_SESSION
+#ifdef HTTP_HAVE_SESSION
 #      include "ext/session/php_session.h"
 #endif
 
@@ -55,13 +55,17 @@ PHP_FUNCTION(http_date)
        }
 
        if (t == -1) {
-               t = (long) HTTP_GET_REQUEST_TIME();
+               t = HTTP_G->request.time;
        }
 
        RETURN_STRING(http_date(t), 0);
 }
 /* }}} */
 
+#if PHP_MAJOR_VERSION == 4 && PHP_MINOR_VERSION == 3 && PHP_RELEASE_VERSION < 10
+#      define php_url_parse_ex(u, l) php_url_parse(u)
+#endif
+
 /* {{{ proto string http_build_url([mixed url[, mixed parts[, int flags = HTTP_URL_REPLACE[, array &new_url]]]])
  *
  * Build an URL.
@@ -77,7 +81,7 @@ PHP_FUNCTION(http_date)
  * <pre>
  *     - HTTP_URL_REPLACE:        (default) set parts of the second url will replace the parts in the first
  *     - HTTP_URL_JOIN_PATH:      the path of the second url will be merged into the one of the first
- *     - HTTP_URL_JOIN_QUERY:     the two querystrings will be merged naivly; no replacements are done
+ *     - HTTP_URL_JOIN_QUERY:     the two querystrings will be merged recursively
  *     - HTTP_URL_STRIP_USER:     the user part will not appear in the result
  *     - HTTP_URL_STRIP_PASS:     the password part will not appear in the result
  *     - HTTP_URL_STRIP_AUTH:     neither the user nor the password part will appear in the result
@@ -112,13 +116,13 @@ PHP_FUNCTION(http_build_url)
        zval *z_old_url = NULL, *z_new_url = NULL, *z_composed_url = NULL;
        php_url *old_url = NULL, *new_url = NULL, *composed_url = NULL;
 
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z/z/lz", &z_old_url, &z_new_url, &flags, &z_composed_url) != SUCCESS) {
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z!/z!/lz", &z_old_url, &z_new_url, &flags, &z_composed_url) != SUCCESS) {
                RETURN_FALSE;
        }
        
        if (z_new_url) {
                if (Z_TYPE_P(z_new_url) == IS_ARRAY || Z_TYPE_P(z_new_url) == IS_OBJECT) {
-                       new_url = array2url(HASH_OF(z_new_url));
+                       new_url = http_url_from_struct(NULL, HASH_OF(z_new_url));
                } else {
                        convert_to_string(z_new_url);
                        if (!(new_url = php_url_parse_ex(Z_STRVAL_P(z_new_url), Z_STRLEN_P(z_new_url)))) {
@@ -130,7 +134,7 @@ PHP_FUNCTION(http_build_url)
        
        if (z_old_url) {
                if (Z_TYPE_P(z_old_url) == IS_ARRAY || Z_TYPE_P(z_old_url) == IS_OBJECT) {
-                       old_url = array2url(HASH_OF(z_old_url));
+                       old_url = http_url_from_struct(NULL, HASH_OF(z_old_url));
                } else {
                        convert_to_string(z_old_url);
                        if (!(old_url = php_url_parse_ex(Z_STRVAL_P(z_old_url), Z_STRLEN_P(z_old_url)))) {
@@ -145,33 +149,7 @@ PHP_FUNCTION(http_build_url)
        
        if (z_composed_url) {
                http_build_url(flags, old_url, new_url, &composed_url, &url_str, &url_len);
-               
-               zval_dtor(z_composed_url);
-               array_init(z_composed_url);
-               if (composed_url->scheme) {
-                       add_assoc_string(z_composed_url, "scheme", composed_url->scheme, 1);
-               }
-               if (composed_url->user) {
-                       add_assoc_string(z_composed_url, "user", composed_url->user, 1);
-               }
-               if (composed_url->pass) {
-                       add_assoc_string(z_composed_url, "pass", composed_url->pass, 1);
-               }
-               if (composed_url->host) {
-                       add_assoc_string(z_composed_url, "host", composed_url->host, 1);
-               }
-               if (composed_url->port) {
-                       add_assoc_long(z_composed_url, "port", composed_url->port);
-               }
-               if (composed_url->path) {
-                       add_assoc_string(z_composed_url, "path", composed_url->path, 1);
-               }
-               if (composed_url->query) {
-                       add_assoc_string(z_composed_url, "query", composed_url->query, 1);
-               }
-               if (composed_url->fragment) {
-                       add_assoc_string(z_composed_url, "fragment", composed_url->fragment, 1);
-               }
+               http_url_tostruct(composed_url, z_composed_url);
                php_url_free(composed_url);
        } else {
                http_build_url(flags, old_url, new_url, NULL, &url_str, &url_len);
@@ -180,7 +158,9 @@ PHP_FUNCTION(http_build_url)
        if (new_url) {
                php_url_free(new_url);
        }
-       php_url_free(old_url);
+       if (old_url) {
+               php_url_free(old_url);
+       }
        
        RETURN_STRINGL(url_str, url_len, 0);
 }
@@ -454,7 +434,7 @@ PHP_FUNCTION(http_send_last_modified)
        }
 
        if (t == -1) {
-               t = (long) HTTP_GET_REQUEST_TIME();
+               t = HTTP_G->request.time;
        }
 
        RETURN_SUCCESS(http_send_last_modified(t));
@@ -534,7 +514,7 @@ PHP_FUNCTION(http_match_modified)
 
        // current time if not supplied (senseless though)
        if (t == -1) {
-               t = (long) HTTP_GET_REQUEST_TIME();
+               t = HTTP_G->request.time;
        }
 
        if (for_range) {
@@ -589,7 +569,7 @@ PHP_FUNCTION(http_match_etag)
  * Returns FALSE on failure, or *exits* with "304 Not Modified" if the entity is cached.
  * 
  * A log entry will be written to the cache log if the INI entry
- * http.cache_log is set and the cache attempt was successful.
+ * http.log.cache is set and the cache attempt was successful.
  */
 PHP_FUNCTION(http_cache_last_modified)
 {
@@ -602,7 +582,7 @@ PHP_FUNCTION(http_cache_last_modified)
        
        HTTP_CHECK_HEADERS_SENT(RETURN_FALSE);
 
-       t = (long) HTTP_GET_REQUEST_TIME();
+       t = HTTP_G->request.time;
 
        /* 0 or omitted */
        if (!last_modified) {
@@ -629,7 +609,7 @@ PHP_FUNCTION(http_cache_last_modified)
 /* {{{ proto bool http_cache_etag([string etag])
  *
  * Attempts to cache the sent entity by its ETag, either supplied or generated 
- * by the hash algorithm specified by the INI setting "http.etag_mode".
+ * by the hash algorithm specified by the INI setting "http.etag.mode".
  *
  * If the clients "If-None-Match" header matches the supplied/calculated
  * ETag, the body is considered cached on the clients side and
@@ -638,7 +618,7 @@ PHP_FUNCTION(http_cache_last_modified)
  * Returns FALSE on failure, or *exits* with "304 Not Modified" if the entity is cached.
  * 
  * A log entry is written to the cache log if the INI entry
- * "http.cache_log" is set and the cache attempt was successful.
+ * "http.log.cache" is set and the cache attempt was successful.
  */
 PHP_FUNCTION(http_cache_etag)
 {
@@ -658,7 +638,7 @@ PHP_FUNCTION(http_cache_etag)
 /* {{{ proto string ob_etaghandler(string data, int mode)
  *
  * For use with ob_start().  Output buffer handler generating an ETag with
- * the hash algorithm specified with the INI setting "http.etag_mode".
+ * the hash algorithm specified with the INI setting "http.etag.mode".
  */
 PHP_FUNCTION(ob_etaghandler)
 {
@@ -737,7 +717,7 @@ PHP_FUNCTION(http_throttle)
  * Returns FALSE on failure, or *exits* on success.
  * 
  * A log entry will be written to the redirect log, if the INI entry
- * "http.redirect_log" is set and the redirect attempt was successful.
+ * "http.log.redirect" is set and the redirect attempt was successful.
  */
 PHP_FUNCTION(http_redirect)
 {
@@ -752,7 +732,7 @@ PHP_FUNCTION(http_redirect)
                RETURN_FALSE;
        }
 
-#ifdef HAVE_PHP_SESSION
+#ifdef HTTP_HAVE_SESSION
        /* append session info */
        if (session) {
                if (!params) {
@@ -805,20 +785,18 @@ PHP_FUNCTION(http_redirect)
                FREE_ZVAL(params);
        }
        
-       switch (status)
-       {
+       switch (status) {
                case 300:
                        RETVAL_SUCCESS(http_send_status_header(status, LOC));
                        efree(LOC);
                        return;
-               break;
                
                case HTTP_REDIRECT_PERM:
                case HTTP_REDIRECT_FOUND:
                case HTTP_REDIRECT_POST:
                case HTTP_REDIRECT_PROXY:
                case HTTP_REDIRECT_TEMP:
-               break;
+                       break;
                
                case 306:
                default:
@@ -831,7 +809,7 @@ PHP_FUNCTION(http_redirect)
                        } else {
                                status = HTTP_REDIRECT_FOUND;
                        }
-               break;
+                       break;
        }
        
        RETURN_SUCCESS(http_exit_ex(status, LOC, RED, 1));
@@ -846,14 +824,14 @@ PHP_FUNCTION(http_redirect)
  */
 PHP_FUNCTION(http_send_data)
 {
-       zval *zdata;
+       int data_len;
+       char *data_buf;
 
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zdata) != SUCCESS) {
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data_buf, &data_len) != SUCCESS) {
                RETURN_FALSE;
        }
 
-       convert_to_string_ex(&zdata);
-       RETURN_SUCCESS(http_send_data(Z_STRVAL_P(zdata), Z_STRLEN_P(zdata)));
+       RETURN_SUCCESS(http_send_data(data_buf, data_len));
 }
 /* }}} */
 
@@ -1085,7 +1063,7 @@ PHP_FUNCTION(http_parse_cookie)
        HashPosition pos;
        http_cookie_list list;
        
-       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|la", &cookie, &cookie_len, &flags, &allowed_extras_array)) {
+       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|la!", &cookie, &cookie_len, &flags, &allowed_extras_array)) {
                RETURN_FALSE;
        }
        
@@ -1094,7 +1072,7 @@ PHP_FUNCTION(http_parse_cookie)
                FOREACH_VAL(pos, allowed_extras_array, entry) {
                        ZVAL_ADDREF(*entry);
                        convert_to_string_ex(entry);
-                       allowed_extras[i] = estrndup(Z_STRVAL_PP(entry), Z_STRLEN_PP(entry));
+                       allowed_extras[i++] = estrndup(Z_STRVAL_PP(entry), Z_STRLEN_PP(entry));
                        zval_ptr_dtor(entry);
                }
        }
@@ -1114,6 +1092,57 @@ PHP_FUNCTION(http_parse_cookie)
                efree(allowed_extras);
        }
 }
+/* }}} */
+
+/* {{{ proto string http_build_cookie(array cookie)
+ *
+ * Build a cookie string from an array/object like returned by http_parse_cookie().
+ */
+PHP_FUNCTION(http_build_cookie)
+{
+       char *str = NULL;
+       size_t len = 0;
+       zval *strct;
+       http_cookie_list list;
+       
+       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &strct)) {
+               RETURN_FALSE;
+       }
+       
+       http_cookie_list_fromstruct(&list, strct);
+       http_cookie_list_tostring(&list, &str, &len);
+       http_cookie_list_dtor(&list);
+       
+       RETURN_STRINGL(str, len, 0);
+}
+/* }}} */
+
+/* {{{ proto object http_parse_params(string param[, int flags = HTTP_PARAMS_DEFAULT])
+ *
+ * Parse parameter list.
+ */
+PHP_FUNCTION(http_parse_params)
+{
+       char *param;
+       int param_len;
+       zval *params;
+       long flags = HTTP_PARAMS_DEFAULT;
+       
+       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &param, &param_len, &flags)) {
+               RETURN_FALSE;
+       }
+       
+       params = ecalloc(1, sizeof(zval));
+       array_init(params);
+       if (SUCCESS != http_parse_params(param, flags, Z_ARRVAL_P(params))) {
+               zval_dtor(params);
+               FREE_ZVAL(params);
+               RETURN_FALSE;
+       }
+       object_init(return_value);
+       add_property_zval(return_value, "params", params);
+}
+/* }}} */
 
 /* {{{ proto array http_get_request_headers(void)
  *
@@ -1126,7 +1155,7 @@ PHP_FUNCTION(http_get_request_headers)
        NO_ARGS;
 
        array_init(return_value);
-       http_get_request_headers(return_value);
+       http_get_request_headers(Z_ARRVAL_P(return_value));
 }
 /* }}} */
 
@@ -1248,9 +1277,8 @@ PHP_FUNCTION(http_match_request_header)
  *  - cookies:          array, list of cookies as associative array
  *                      like array("cookie" => "value")
  *  - encodecookies:    bool, whether to urlencode the cookies (default: true)
- *  - resetcookies:     bool, wheter to reset the cookies
  *  - cookiestore:      string, path to a file where cookies are/will be stored
- *  - cookiesession:    bool, accept (true) or reset (false) sessioncookies
+ *  - cookiesession:    bool, don't load session cookies from cookiestore if TRUE
  *  - resume:           int, byte offset to start the download from;
  *                      if the server supports ranges
  *  - range:            array, array of arrays, each containing two integers,
@@ -1452,17 +1480,17 @@ PHP_FUNCTION(http_post_data)
  */
 PHP_FUNCTION(http_post_fields)
 {
-       zval *options = NULL, *info = NULL, *fields, *files = NULL;
+       zval *options = NULL, *info = NULL, *fields = NULL, *files = NULL;
        char *URL;
        int URL_len;
        http_request_body body;
        http_request request;
 
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa|aa/!z", &URL, &URL_len, &fields, &files, &options, &info) != SUCCESS) {
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa!|a!a/!z", &URL, &URL_len, &fields, &files, &options, &info) != SUCCESS) {
                RETURN_FALSE;
        }
 
-       if (!http_request_body_fill(&body, Z_ARRVAL_P(fields), files ? Z_ARRVAL_P(files) : NULL)) {
+       if (!http_request_body_fill(&body, fields ? Z_ARRVAL_P(fields) : NULL, files ? Z_ARRVAL_P(files) : NULL)) {
                RETURN_FALSE;
        }
 
@@ -1670,27 +1698,6 @@ PHP_FUNCTION(http_request)
 }
 /* }}} */
 
-static char *file_get_contents(char *file, size_t *len TSRMLS_DC)
-{
-       php_stream *s = NULL;
-       char *buf = NULL;
-       
-       if ((s = php_stream_open_wrapper_ex(file, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL, HTTP_DEFAULT_STREAM_CONTEXT))) {
-               *len = php_stream_copy_to_mem(s, &buf, (size_t) -1, 0);
-               php_stream_close(s);
-       } else {
-               *len = 0;
-       }
-       return buf;
-}
-struct FormData {
-       struct FormData *next;
-       int type;
-       char *line;
-       size_t length;
-};
-CURLcode Curl_getFormData(struct FormData **, struct curl_httppost *post, curl_off_t *size);
-
 /* {{{ proto string http_request_body_encode(array fields, array files)
  *
  * Generate x-www-form-urlencoded resp. form-data encoded request body.
@@ -1702,13 +1709,8 @@ PHP_FUNCTION(http_request_body_encode)
        zval *fields = NULL, *files = NULL;
        HashTable *fields_ht, *files_ht;
        http_request_body body;
-       phpstr rbuf;
-       struct FormData *data, *ptr;
-       curl_off_t size;
-       char *fdata = NULL;
-       size_t fsize = 0;
-       CURLcode rc;
-       int fgc_error = 0;
+       char *buf;
+       size_t len;
        
        if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a!a!", &fields, &files)) {
                RETURN_FALSE;
@@ -1716,53 +1718,13 @@ PHP_FUNCTION(http_request_body_encode)
        
        fields_ht = (fields && Z_TYPE_P(fields) == IS_ARRAY) ? Z_ARRVAL_P(fields) : NULL;
        files_ht = (files && Z_TYPE_P(files) == IS_ARRAY) ? Z_ARRVAL_P(files) : NULL;
-       if (!http_request_body_fill(&body, fields_ht, files_ht)) {
-               RETURN_FALSE;
-       }
-       
-       switch (body.type)
-       {
-               case HTTP_REQUEST_BODY_CURLPOST:
-                       if (CURLE_OK != (rc = Curl_getFormData(&data, body.data, &size))) {
-                               http_error_ex(HE_WARNING, HTTP_E_RUNTIME, "Could not encode request body: %s", curl_easy_strerror(rc));
-                               RETVAL_FALSE;
-                       } else {
-                               phpstr_init_ex(&rbuf, (size_t) size, PHPSTR_INIT_PREALLOC);
-                               for (ptr = data; ptr; ptr = ptr->next) {
-                                       if (!fgc_error) {
-                                               if (ptr->type) {
-                                                       if ((fdata = file_get_contents(ptr->line, &fsize TSRMLS_CC))) {
-                                                               phpstr_append(&rbuf, fdata, fsize);
-                                                               efree(fdata);
-                                                       } else {
-                                                               fgc_error = 1;
-                                                       }
-                                               } else {
-                                                       phpstr_append(&rbuf, ptr->line, ptr->length);
-                                               }
-                                       }
-                                       curl_free(ptr->line);
-                               }
-                               curl_free(data);
-                               if (fgc_error) {
-                                       phpstr_dtor(&rbuf);
-                                       RETVAL_FALSE;
-                               } else {
-                                       RETVAL_PHPSTR_VAL(&rbuf);
-                               }
-                       }
-                       http_request_body_dtor(&body);
-               break;
-               
-               case HTTP_REQUEST_BODY_CSTRING:
-                       RETVAL_STRINGL(body.data, body.size, 0);
-               break;
-               
-               default:
-                       http_request_body_dtor(&body);
-                       RETVAL_FALSE;
-               break;
+       if (http_request_body_fill(&body, fields_ht, files_ht) && (SUCCESS == http_request_body_encode(&body, &buf, &len))) {
+               RETVAL_STRINGL(buf, len, 0);
+       } else {
+               http_error(HE_WARNING, HTTP_E_RUNTIME, "Could not encode request body");
+               RETVAL_FALSE;
        }
+       http_request_body_dtor(&body);
 }
 #endif /* HTTP_HAVE_CURL */
 /* }}} HAVE_CURL */
@@ -1808,8 +1770,7 @@ PHP_FUNCTION(http_request_method_unregister)
                RETURN_FALSE;
        }
 
-       switch (Z_TYPE_P(method))
-       {
+       switch (Z_TYPE_P(method)) {
                case IS_OBJECT:
                        convert_to_string(method);
                case IS_STRING:
@@ -1841,15 +1802,14 @@ PHP_FUNCTION(http_request_method_unregister)
  */
 PHP_FUNCTION(http_request_method_exists)
 {
-       IF_RETVAL_USED {
+       if (return_value_used) {
                zval *method;
 
                if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &method)) {
                        RETURN_FALSE;
                }
 
-               switch (Z_TYPE_P(method))
-               {
+               switch (Z_TYPE_P(method)) {
                        case IS_OBJECT:
                                convert_to_string(method);
                        case IS_STRING:
@@ -1877,7 +1837,7 @@ PHP_FUNCTION(http_request_method_exists)
  */
 PHP_FUNCTION(http_request_method_name)
 {
-       IF_RETVAL_USED {
+       if (return_value_used) {
                long method;
 
                if ((SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &method)) || (method < 0)) {