From: Michael Wallner Date: Sun, 22 May 2005 17:24:15 +0000 (+0000) Subject: * flush * X-Git-Tag: RELEASE_0_8_0~24 X-Git-Url: https://git.m6w6.name/?a=commitdiff_plain;h=781c90c0447166dd52ef881ae15751fa466c32fb;p=m6w6%2Fext-http * flush * - added PHP_FUNCTIONS: http_throttle, http_request_method_(register|unregister|exists|name) - added PHP_METHODS: HttpResponse::(set|get)ThrottleDelay, HttpResponse::(set|get)SendBuffersize - http_globals cleanup - added request methods to MINFO - register error code constants - added provisory http_message_dup() for the HttpMessage clone handler - added some missing functions in missing.c # gcc fixes follow --- diff --git a/config.w32 b/config.w32 index 76adf5f..f539b40 100644 --- a/config.w32 +++ b/config.w32 @@ -2,10 +2,11 @@ // $Id$ ARG_ENABLE("http", "whether to enable extended HTTP support", "no"); +ARG_WITH("http-curl-zend-mm", "wheter ext/http's curl should use zend mm"); if (PHP_HTTP != "no") { EXTENSION("http", - "http.c http_functions.c http_methods.c http_exception_object.c "+ + "missing.c http.c http_functions.c http_methods.c http_exception_object.c "+ "http_util_object.c http_message_object.c "+ "http_request_object.c http_response_object.c "+ "http_api.c http_auth_api.c http_cache_api.c "+ @@ -22,7 +23,10 @@ if (PHP_HTTP != "no") { CHECK_LIB("zlib.lib", "http", PHP_HTTP) && CHECK_LIB("winmm.lib", "http", PHP_HTTP)) { AC_DEFINE("HTTP_HAVE_CURL", 1, "Have CURL library"); + if (PHP_HTTP_CURL_ZEND_MM == "yes") { + AC_DEFINE("HTTP_CURL_USE_ZEND_MM", 1, "CURL library shall use Zend MM"); + } } else { WARNING("curl convenience functions not enabled; libraries and headers not found"); } -} +} \ No newline at end of file diff --git a/http.c b/http.c index b214c4c..7b90bd0 100644 --- a/http.c +++ b/http.c @@ -98,6 +98,7 @@ function_entry http_functions[] = { PHP_FE(http_negotiate_language, NULL) PHP_FE(http_negotiate_charset, NULL) PHP_FE(http_redirect, NULL) + PHP_FE(http_throttle, NULL) PHP_FE(http_send_status, NULL) PHP_FE(http_send_last_modified, NULL) PHP_FE(http_send_content_type, NULL) @@ -120,6 +121,10 @@ function_entry http_functions[] = { PHP_FE(http_post_fields, http_request_info_ref_5) PHP_FE(http_put_file, http_request_info_ref_4) PHP_FE(http_put_stream, http_request_info_ref_4) + PHP_FE(http_request_method_register, NULL) + PHP_FE(http_request_method_unregister, NULL) + PHP_FE(http_request_method_exists, NULL) + PHP_FE(http_request_method_name, NULL) #endif PHP_FE(http_auth_basic, NULL) PHP_FE(http_auth_basic_cb, NULL) @@ -150,54 +155,32 @@ zend_module_entry http_module_entry = { }; /* }}} */ +#ifdef HTTP_HAVE_CURL +# ifdef HTTP_CURL_USE_ZEND_MM +static void http_curl_free(void *p) { efree(p); } +static char *http_curl_strdup(const char *p) { return estrdup(p); } +static void *http_curl_malloc(size_t s) { return emalloc(s); } +static void *http_curl_realloc(void *p, size_t s) { return erealloc(p, s); } +static void *http_curl_calloc(size_t n, size_t s) { return ecalloc(n, s); } +# endif /* HTTP_CURL_USE_ZEND_MM */ +static void http_curl_freestr(void *s) { efree(*(char **)s); } +#endif /* HTTP_HAVE_CURL */ -static void free_to_free(void *s) -{ - efree(*(char **)s); -} - -/* {{{ void http_globals_ctor(zend_http_globals *) */ -#define http_globals_ctor _http_globals_ctor -static inline void _http_globals_ctor(zend_http_globals *http_globals) +/* {{{ http_globals */ +static inline void http_globals_init(zend_http_globals *G) { - http_globals->etag_started = 0; - http_globals->ctype = NULL; - http_globals->etag = NULL; - http_globals->lmod = 0; + memset(G, 0, sizeof(zend_http_globals)); + G->send.buffer_size = HTTP_SENDBUF_SIZE; + zend_hash_init(&G->request.methods.custom, 0, NULL, ZVAL_PTR_DTOR, 0); #ifdef HTTP_HAVE_CURL -# if LIBCURL_VERSION_NUM < 0x070c00 - memset(&http_globals->curlerr, 0, sizeof(http_globals->curlerr)); -# endif - zend_llist_init(&http_globals->to_free, sizeof(char *), free_to_free, 0); + zend_llist_init(&G->request.curl.copies, sizeof(char *), http_curl_freestr, 0); #endif - http_globals->allowed_methods = NULL; - http_globals->cache_log = NULL; } -/* }}} */ - -/* {{{ void http_globals_dtor() */ -#define http_globals_dtor() _http_globals_dtor(TSRMLS_C) -static inline void _http_globals_dtor(TSRMLS_D) +static inline void http_globals_free(zend_http_globals *G) { - HTTP_G(etag_started) = 0; - HTTP_G(lmod) = 0; - - if (HTTP_G(etag)) { - efree(HTTP_G(etag)); - HTTP_G(etag) = NULL; - } - - if (HTTP_G(ctype)) { - efree(HTTP_G(ctype)); - HTTP_G(ctype) = NULL; - } - -#ifdef HTTP_HAVE_CURL -# if LIBCURL_VERSION_NUM < 0x070c00 - memset(&HTTP_G(curlerr), 0, sizeof(HTTP_G(curlerr))); -# endif -#endif - + STR_FREE(G->send.content_type); + STR_FREE(G->send.unquoted_etag); + zend_hash_destroy(&G->request.methods.custom); } /* }}} */ @@ -222,28 +205,17 @@ PHP_INI_MH(http_update_allowed_methods) return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); } -#define http_update_cache_log OnUpdateString - PHP_INI_BEGIN() - HTTP_INI_ENTRY("http.allowed_methods", HTTP_KNOWN_METHODS, PHP_INI_ALL, allowed_methods) - HTTP_INI_ENTRY("http.cache_log", NULL, PHP_INI_ALL, cache_log) + HTTP_PHP_INI_ENTRY("http.allowed_methods", NULL, PHP_INI_ALL, http_update_allowed_methods, request.methods.allowed) + HTTP_PHP_INI_ENTRY("http.cache_log", NULL, PHP_INI_ALL, OnUpdateString, log.cache) PHP_INI_END() /* }}} */ -/* {{{ HTTP_CURL_USE_ZEND_MM */ -#if defined(HTTP_HAVE_CURL) && defined(HTTP_CURL_USE_ZEND_MM) -static void http_curl_free(void *p) { efree(p); } -static char *http_curl_strdup(const char *p) { return estrdup(p); } -static void *http_curl_malloc(size_t s) { return emalloc(s); } -static void *http_curl_realloc(void *p, size_t s) { return erealloc(p, s); } -static void *http_curl_calloc(size_t n, size_t s) { return ecalloc(n, s); } -#endif /* HTTP_HAVE_CURL && HTTP_CURL_USE_ZEND_MM */ -/* }}} */ /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(http) { - ZEND_INIT_MODULE_GLOBALS(http, http_globals_ctor, NULL); + ZEND_INIT_MODULE_GLOBALS(http, NULL, NULL); REGISTER_INI_ENTRIES(); #ifdef HTTP_HAVE_CURL @@ -260,13 +232,13 @@ PHP_MINIT_FUNCTION(http) #endif /* HTTP_HAVE_CURL */ #ifdef ZEND_ENGINE_2 - http_util_object_init(INIT_FUNC_ARGS_PASSTHRU); - http_message_object_init(INIT_FUNC_ARGS_PASSTHRU); - http_response_object_init(INIT_FUNC_ARGS_PASSTHRU); + http_util_object_init(); + http_message_object_init(); + http_response_object_init(); # ifdef HTTP_HAVE_CURL - http_request_object_init(INIT_FUNC_ARGS_PASSTHRU); + http_request_object_init(); # endif /* HTTP_HAVE_CURL */ - http_exception_object_init(INIT_FUNC_ARGS_PASSTHRU); + http_exception_object_init(); #endif /* ZEND_ENGINE_2 */ return SUCCESS; @@ -287,8 +259,13 @@ PHP_MSHUTDOWN_FUNCTION(http) /* {{{ PHP_RINIT_FUNCTION */ PHP_RINIT_FUNCTION(http) { - char *allowed_methods = INI_STR("http.allowed_methods"); - http_check_allowed_methods(allowed_methods, strlen(allowed_methods)); + char *m; + + if (m = INI_STR("http.allowed_methods")) { + http_check_allowed_methods(m, strlen(m)); + } + + http_globals_init(HTTP_GLOBALS); return SUCCESS; } /* }}} */ @@ -296,7 +273,7 @@ PHP_RINIT_FUNCTION(http) /* {{{ PHP_RSHUTDOWN_FUNCTION */ PHP_RSHUTDOWN_FUNCTION(http) { - http_globals_dtor(); + http_globals_free(HTTP_GLOBALS); return SUCCESS; } /* }}} */ @@ -322,19 +299,54 @@ PHP_MINFO_FUNCTION(http) # define HTTP_CURL_AVAIL(CLASS) "libcurl not available" #endif - char full_version_string[1024] = {0}; - snprintf(full_version_string, 1023, "%s (%s)", HTTP_PEXT_VERSION, HTTP_CURL_VERSION); +#include "php_http_request_api.h" php_info_print_table_start(); - php_info_print_table_row(2, "Extended HTTP support", "enabled"); - php_info_print_table_row(2, "Extension Version:", full_version_string); + { + char full_version_string[1024] = {0}; + snprintf(full_version_string, 1023, "%s (%s)", HTTP_PEXT_VERSION, HTTP_CURL_VERSION); + + php_info_print_table_row(2, "Extended HTTP support:", "enabled"); + php_info_print_table_row(2, "Extension Version:", full_version_string); + } php_info_print_table_end(); php_info_print_table_start(); - php_info_print_table_header(2, "Functionality", "Availability"); - php_info_print_table_row(2, "Miscellaneous Utilities:", HTTP_FUNC_AVAIL("HttpUtil, HttpMessage")); - php_info_print_table_row(2, "Extended HTTP Responses:", HTTP_FUNC_AVAIL("HttpResponse")); - php_info_print_table_row(2, "Extended HTTP Requests:", HTTP_CURL_AVAIL("HttpRequest")); + { + unsigned i; + zval **custom_method; + phpstr *known_request_methods = phpstr_new(); + phpstr *custom_request_methods = phpstr_new(); + + for (i = HTTP_NO_REQUEST_METHOD+1; i < HTTP_MAX_REQUEST_METHOD; ++i) { + phpstr_appendl(known_request_methods, http_request_method_name(i)); + phpstr_appends(known_request_methods, ", "); + } + FOREACH_HASH_VAL(&HTTP_G(request).methods.custom, custom_method) { + phpstr_append(custom_request_methods, Z_STRVAL_PP(custom_method), Z_STRLEN_PP(custom_method)); + phpstr_appends(custom_request_methods, ", "); + } + + phpstr_append(known_request_methods, PHPSTR_VAL(custom_request_methods), PHPSTR_LEN(custom_request_methods)); + phpstr_fix(known_request_methods); + phpstr_fix(custom_request_methods); + + php_info_print_table_row(2, "Known Request Methods:", PHPSTR_VAL(known_request_methods)); + php_info_print_table_row(2, "Custom Request Methods:", + PHPSTR_LEN(custom_request_methods) ? PHPSTR_VAL(custom_request_methods) : "none registered"); + + phpstr_free(known_request_methods); + phpstr_free(custom_request_methods); + } + php_info_print_table_end(); + + php_info_print_table_start(); + { + php_info_print_table_header(2, "Functionality", "Availability"); + php_info_print_table_row(2, "Miscellaneous Utilities:", HTTP_FUNC_AVAIL("HttpUtil, HttpMessage")); + php_info_print_table_row(2, "Extended HTTP Responses:", HTTP_FUNC_AVAIL("HttpResponse")); + php_info_print_table_row(2, "Extended HTTP Requests:", HTTP_CURL_AVAIL("HttpRequest")); + } php_info_print_table_end(); DISPLAY_INI_ENTRIES(); diff --git a/http_api.c b/http_api.c index fb43d99..079e451 100644 --- a/http_api.c +++ b/http_api.c @@ -70,7 +70,7 @@ void _http_error_ex(long type, long code, const char *format, ...) #ifdef ZEND_ENGINE_2 char *message; vspprintf(&message, 0, format, args); - zend_throw_exception(http_exception_get_default(), message, code TSRMLS_CC); + zend_throw_exception(http_exception_get_for_code(code), message, code TSRMLS_CC); #else type = E_WARNING; #endif @@ -146,9 +146,9 @@ PHP_HTTP_API const char *_http_chunked_decode(const char *encoded, size_t encode while (((e_ptr - encoded) - encoded_len) > 0) { char *n_ptr; size_t chunk_len = 0; - + chunk_len = strtol(e_ptr, &n_ptr, 16); - + if (n_ptr == e_ptr) { /* don't fail on apperently not encoded data */ if (e_ptr == encoded) { diff --git a/http_cache_api.c b/http_cache_api.c index c75b6dc..a70feb0 100644 --- a/http_cache_api.c +++ b/http_cache_api.c @@ -38,8 +38,8 @@ ZEND_EXTERN_MODULE_GLOBALS(http); /* {{{ STATUS http_cache_exit(char *, zend_bool) */ STATUS _http_cache_exit_ex(char *cache_token, zend_bool etag, zend_bool free_token TSRMLS_DC) { - if (HTTP_G(cache_log) && strlen(HTTP_G(cache_log))) { - php_stream *log = php_stream_open_wrapper(HTTP_G(cache_log), "ab", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL); + if (HTTP_G(log).cache && strlen(HTTP_G(log).cache)) { + php_stream *log = php_stream_open_wrapper(HTTP_G(log).cache, "ab", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL); if (log) { time_t now; @@ -76,17 +76,15 @@ PHP_HTTP_API char *_http_etag(const void *data_ptr, size_t data_len, http_send_m break; case SEND_RSRC: - if (!HTTP_G(ssb).sb.st_ino) { - if (php_stream_stat((php_stream *) data_ptr, &HTTP_G(ssb))) { - return NULL; - } - } - snprintf(ssb_buf, 127, "%ld=%ld=%ld", - HTTP_G(ssb).sb.st_mtime, - HTTP_G(ssb).sb.st_ino, - HTTP_G(ssb).sb.st_size - ); + { + php_stream_statbuf ssb; + + if (php_stream_stat((php_stream *) data_ptr, &ssb)) { + return NULL; + } + snprintf(ssb_buf, 127, "%ld=%ld=%ld", ssb.sb.st_mtime, ssb.sb.st_ino, ssb.sb.st_size); PHP_MD5Update(&ctx, ssb_buf, strlen(ssb_buf)); + } break; default: @@ -105,24 +103,13 @@ PHP_HTTP_API char *_http_etag(const void *data_ptr, size_t data_len, http_send_m /* {{{ time_t http_last_modified(void *, http_send_mode) */ PHP_HTTP_API time_t _http_last_modified(const void *data_ptr, http_send_mode data_mode TSRMLS_DC) { + php_stream_statbuf ssb; + switch (data_mode) { - case SEND_DATA: - { - return time(NULL); - } - - case SEND_RSRC: - { - php_stream_stat((php_stream *) data_ptr, &HTTP_G(ssb)); - return HTTP_G(ssb).sb.st_mtime; - } - - default: - { - php_stream_stat_path(Z_STRVAL_P((zval *) data_ptr), &HTTP_G(ssb)); - return HTTP_G(ssb).sb.st_mtime; - } + case SEND_DATA: return time(NULL); + case SEND_RSRC: return php_stream_stat((php_stream *) data_ptr, &ssb) ? 0 : ssb.sb.st_mtime; + default: return php_stream_stat_path(Z_STRVAL_P((zval *) data_ptr), &ssb) ? 0 : ssb.sb.st_mtime; } } /* }}} */ @@ -211,16 +198,15 @@ PHP_HTTP_API STATUS _http_cache_etag(const char *etag, size_t etag_len, } /* if no etag is given and we didn't already start ob_etaghandler -- start it */ - if (HTTP_G(etag_started)) { + if (HTTP_G(etag).started) { return SUCCESS; } - if (HTTP_G(etag_started) = (SUCCESS == php_start_ob_buffer_named("ob_etaghandler", HTTP_SENDBUF_SIZE, 1 TSRMLS_CC))) { + if (HTTP_G(etag).started = (SUCCESS == php_start_ob_buffer_named("ob_etaghandler", HTTP_SENDBUF_SIZE, 1 TSRMLS_CC))) { return SUCCESS; } else { return FAILURE; } - } /* }}} */ @@ -232,17 +218,17 @@ PHP_HTTP_API void _http_ob_etaghandler(char *output, uint output_len, unsigned char digest[16]; if (mode & PHP_OUTPUT_HANDLER_START) { - HTTP_G(etag_started) = 1; - PHP_MD5Init(&HTTP_G(etag_md5)); + HTTP_G(etag).started = 1; + PHP_MD5Init(&HTTP_G(etag).md5ctx); } - PHP_MD5Update(&HTTP_G(etag_md5), output, output_len); + PHP_MD5Update(&HTTP_G(etag).md5ctx, output, output_len); if (mode & PHP_OUTPUT_HANDLER_END) { - PHP_MD5Final(digest, &HTTP_G(etag_md5)); + PHP_MD5Final(digest, &HTTP_G(etag).md5ctx); /* just do that if desired */ - if (HTTP_G(etag_started)) { + if (HTTP_G(etag).started) { make_digest(etag, digest); http_send_header("Cache-Control: " HTTP_DEFAULT_CACHECONTROL); http_send_etag(etag, 32); diff --git a/http_exception_object.c b/http_exception_object.c index 44c5c2a..7ea4af5 100644 --- a/http_exception_object.c +++ b/http_exception_object.c @@ -31,13 +31,21 @@ #include "zend_exceptions.h" zend_class_entry *http_exception_object_ce; -zend_function_entry http_exception_object_fe[] = { - {NULL, NULL, NULL} -}; +zend_function_entry http_exception_object_fe[] = {{NULL, NULL, NULL}}; void _http_exception_object_init(INIT_FUNC_ARGS) { HTTP_REGISTER_CLASS(HttpException, http_exception_object, zend_exception_get_default(), 0); + + HTTP_LONG_CONSTANT("HTTP_E_UNKNOWN", HTTP_E_UNKOWN); + HTTP_LONG_CONSTANT("HTTP_E_PARSE", HTTP_E_PARSE); + HTTP_LONG_CONSTANT("HTTP_E_HEADER", HTTP_E_HEADER); + HTTP_LONG_CONSTANT("HTTP_E_OBUFFER", HTTP_E_OBUFFER); + HTTP_LONG_CONSTANT("HTTP_E_CURL", HTTP_E_CURL); + HTTP_LONG_CONSTANT("HTTP_E_ENCODE", HTTP_E_ENCODE); + HTTP_LONG_CONSTANT("HTTP_E_PARAM", HTTP_E_PARAM); + HTTP_LONG_CONSTANT("HTTP_E_URL", HTTP_E_URL); + HTTP_LONG_CONSTANT("HTTP_E_MSG", HTTP_E_MSG); } zend_class_entry *_http_exception_get_default() @@ -45,6 +53,11 @@ zend_class_entry *_http_exception_get_default() return http_exception_object_ce; } +zend_class_entry *_http_exception_get_for_code(long code) +{ + return http_exception_object_ce; +} + #endif /* diff --git a/http_functions.c b/http_functions.c index afe6f85..4b611e0 100644 --- a/http_functions.c +++ b/http_functions.c @@ -411,6 +411,35 @@ PHP_FUNCTION(ob_etaghandler) } /* }}} */ +/* {{{ proto void http_throttle(double sec[, long bytes = 2097152]) + * + * Use with http_send() API. + * + * Example: + * + * + * + */ +PHP_FUNCTION(http_throttle) +{ + long chunk_size; + double interval; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dl", &interval, &chunk_size)) { + return; + } + + HTTP_G(send).throttle_delay = interval; + HTTP_G(send).buffer_size = chunk_size; +} +/* }}} */ + /* {{{ proto void http_redirect([string url[, array params[, bool session,[ bool permanent]]]]) * * Redirect to a given url. @@ -893,25 +922,25 @@ PHP_FUNCTION(http_put_stream) php_stream *stream; php_stream_statbuf ssb; http_request_body body; - + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sr|a/!z", &URL, &URL_len, &resource, &options, &info)) { RETURN_FALSE; } - + php_stream_from_zval(stream, &resource); if (php_stream_stat(stream, &ssb)) { RETURN_FALSE; } - + if (info) { zval_dtor(info); array_init(info); } - + body.type = HTTP_REQUEST_BODY_UPLOADFILE; body.data = stream; body.size = ssb.sb.st_size; - + 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); @@ -921,6 +950,114 @@ PHP_FUNCTION(http_put_stream) } /* }}} */ +/* {{{ proto bool http_request() + */ +/* }}} */ + +/* {{{ proto long http_request_method_register(string method) + * + */ +PHP_FUNCTION(http_request_method_register) +{ + char *method; + int *method_len; + unsigned long existing; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &method, &method_len)) { + RETURN_FALSE; + } + if (existing = http_request_method_exists(1, 0, method)) { + RETURN_LONG((long) existing); + } + + RETVAL_LONG((long) http_request_method_register(method)); +} +/* }}} */ + +/* {{{ proto bool http_request_method_unregister(mixed method) + * + */ +PHP_FUNCTION(http_request_method_unregister) +{ + zval *method; + zend_bool numeric; + unsigned long existing; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &method)) { + RETURN_FALSE; + } + + switch (Z_TYPE_P(method)) + { + 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 { + unsigned long mn; + if (!(mn = http_request_method_exists(1, 0, Z_STRVAL_P(method)))) { + RETURN_FALSE; + } + zval_dtor(method); + ZVAL_LONG(method, (long)mn); + } + case IS_LONG: + RETURN_SUCCESS(http_request_method_unregister(Z_LVAL_P(method))); + default: + RETURN_FALSE; + } +} +/* }}} */ + +/* {{{ proto long http_request_method_exists(mixed method) + * + */ +PHP_FUNCTION(http_request_method_exists) +{ + IF_RETVAL_USED { + zval *method; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &method)) { + RETURN_FALSE; + } + + switch (Z_TYPE_P(method)) + { + case IS_OBJECT: + convert_to_string(method); + case IS_STRING: + if (is_numeric_string(Z_STRVAL_P(method), Z_STRLEN_P(method), NULL, NULL, 1)) { + convert_to_long(method); + } else { + RETURN_LONG((long) http_request_method_exists(1, 0, Z_STRVAL_P(method))); + } + case IS_LONG: + RETURN_LONG((long) http_request_method_exists(0, Z_LVAL_P(method), NULL)); + default: + RETURN_FALSE; + } + } +} +/* }}} */ + +/* {{{ proto string http_request_method_name(long method) + * + */ +PHP_FUNCTION(http_request_method_name) +{ + IF_RETVAL_USED { + long method; + + if ((SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &method)) || (method < 0)) { + RETURN_FALSE; + } + + RETURN_STRING(estrdup(http_request_method_name((unsigned long) method)), 0); + } +} +/* }}} */ #endif /* }}} HAVE_CURL */ diff --git a/http_message_api.c b/http_message_api.c index a0f5e59..47cd1dd 100644 --- a/http_message_api.c +++ b/http_message_api.c @@ -412,6 +412,21 @@ PHP_HTTP_API STATUS _http_message_send(http_message *message TSRMLS_DC) return rs; } +PHP_HTTP_API http_message *_http_message_dup(http_message *msg TSRMLS_DC) +{ + /* + * TODO: unroll + */ + http_message *new; + char *serialized_data; + size_t serialized_length; + + http_message_serialize(msg, &serialized_data, &serialized_length); + new = http_message_parse(serialized_data, serialized_length); + efree(serialized_data); + return new; +} + PHP_HTTP_API void _http_message_dtor(http_message *message) { if (message) { diff --git a/http_message_object.c b/http_message_object.c index f1a6705..e934f8b 100644 --- a/http_message_object.c +++ b/http_message_object.c @@ -38,6 +38,8 @@ static zval *_http_message_object_read_prop(zval *object, zval *member, int type static void _http_message_object_write_prop(zval *object, zval *member, zval *value TSRMLS_DC); #define http_message_object_get_props _http_message_object_get_props static HashTable *_http_message_object_get_props(zval *object TSRMLS_DC); +#define http_message_object_clone_obj _http_message_object_clone_obj +static inline zend_object_value _http_message_object_clone_obj(zval *object TSRMLS_DC); zend_class_entry *http_message_object_ce; zend_function_entry http_message_object_fe[] = { @@ -75,6 +77,7 @@ void _http_message_object_init(INIT_FUNC_ARGS) HTTP_LONG_CONSTANT("HTTP_MSG_REQUEST", HTTP_MSG_REQUEST); HTTP_LONG_CONSTANT("HTTP_MSG_RESPONSE", HTTP_MSG_RESPONSE); + http_message_object_handlers.clone_obj = http_message_object_clone_obj; http_message_object_handlers.read_property = http_message_object_read_prop; http_message_object_handlers.write_property = http_message_object_write_prop; http_message_object_handlers.get_properties = http_message_object_get_props; @@ -112,6 +115,11 @@ zend_object_value _http_message_object_new_ex(zend_class_entry *ce, http_message return ov; } +zend_object_value _http_message_object_clone(zval *this_ptr TSRMLS_DC) +{ + return http_message_object_clone_obj(this_ptr TSRMLS_CC); +} + static inline void _http_message_object_declare_default_properties(TSRMLS_D) { zend_class_entry *ce = http_message_object_ce; @@ -141,6 +149,12 @@ void _http_message_object_free(zend_object *object TSRMLS_DC) efree(o); } +static inline zend_object_value _http_message_object_clone_obj(zval *this_ptr TSRMLS_DC) +{ + getObject(http_message_object, obj); + return http_message_object_from_msg(http_message_dup(obj->message)); +} + static zval *_http_message_object_read_prop(zval *object, zval *member, int type TSRMLS_DC) { getObjectEx(http_message_object, obj, object); diff --git a/http_methods.c b/http_methods.c index 4588718..4d7518a 100644 --- a/http_methods.c +++ b/http_methods.c @@ -40,6 +40,8 @@ #ifdef ZEND_ENGINE_2 +ZEND_EXTERN_MODULE_GLOBALS(http) + /* {{{ HttpResponse */ /* {{{ proto void HttpResponse::__construct(bool cache, bool gzip) @@ -94,13 +96,15 @@ PHP_METHOD(HttpResponse, setCache) */ PHP_METHOD(HttpResponse, getCache) { - zval *do_cache = NULL; - getObject(http_response_object, obj); - NO_ARGS; - do_cache = GET_PROP(obj, cache); - RETURN_BOOL(Z_LVAL_P(do_cache)); + IF_RETVAL_USED { + zval *do_cache = NULL; + getObject(http_response_object, obj); + + do_cache = GET_PROP(obj, cache); + RETURN_BOOL(Z_LVAL_P(do_cache)); + } } /* }}}*/ @@ -128,13 +132,15 @@ PHP_METHOD(HttpResponse, setGzip) */ PHP_METHOD(HttpResponse, getGzip) { - zval *do_gzip = NULL; - getObject(http_response_object, obj); - NO_ARGS; - do_gzip = GET_PROP(obj, gzip); - RETURN_BOOL(Z_LVAL_P(do_gzip)); + IF_RETVAL_USED { + zval *do_gzip; + getObject(http_response_object, obj); + + do_gzip = GET_PROP(obj, gzip); + RETURN_BOOL(Z_LVAL_P(do_gzip)); + } } /* }}} */ @@ -171,13 +177,15 @@ PHP_METHOD(HttpResponse, setCacheControl) */ PHP_METHOD(HttpResponse, getCacheControl) { - zval *ccontrol; - getObject(http_response_object, obj); - NO_ARGS; - ccontrol = GET_PROP(obj, cacheControl); - RETURN_STRINGL(Z_STRVAL_P(ccontrol), Z_STRLEN_P(ccontrol), 1); + IF_RETVAL_USED { + zval *ccontrol; + getObject(http_response_object, obj); + + ccontrol = GET_PROP(obj, cacheControl); + RETURN_STRINGL(Z_STRVAL_P(ccontrol), Z_STRLEN_P(ccontrol), 1); + } } /* }}} */ @@ -212,13 +220,15 @@ PHP_METHOD(HttpResponse, setContentType) */ PHP_METHOD(HttpResponse, getContentType) { - zval *ctype; - getObject(http_response_object, obj); - NO_ARGS; - ctype = GET_PROP(obj, contentType); - RETURN_STRINGL(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1); + IF_RETVAL_USED { + zval *ctype; + getObject(http_response_object, obj); + + ctype = GET_PROP(obj, contentType); + RETURN_STRINGL(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1); + } } /* }}} */ @@ -258,20 +268,19 @@ PHP_METHOD(HttpResponse, setContentDisposition) */ PHP_METHOD(HttpResponse, getContentDisposition) { - zval *file; - zval *is_inline; - getObject(http_response_object, obj); + NO_ARGS; - if (ZEND_NUM_ARGS()) { - WRONG_PARAM_COUNT; - } + IF_RETVAL_USED { + zval *file, *is_inline; + getObject(http_response_object, obj); - file = GET_PROP(obj, dispoFile); - is_inline = GET_PROP(obj, dispoInline); + file = GET_PROP(obj, dispoFile); + is_inline = GET_PROP(obj, dispoInline); - array_init(return_value); - add_assoc_stringl(return_value, "filename", Z_STRVAL_P(file), Z_STRLEN_P(file), 1); - add_assoc_bool(return_value, "inline", Z_LVAL_P(is_inline)); + array_init(return_value); + add_assoc_stringl(return_value, "filename", Z_STRVAL_P(file), Z_STRLEN_P(file), 1); + add_assoc_bool(return_value, "inline", Z_LVAL_P(is_inline)); + } } /* }}} */ @@ -300,13 +309,79 @@ PHP_METHOD(HttpResponse, setETag) */ PHP_METHOD(HttpResponse, getETag) { - zval *etag; - getObject(http_response_object, obj); + NO_ARGS; + + IF_RETVAL_USED { + zval *etag; + getObject(http_response_object, obj); + + etag = GET_PROP(obj, eTag); + RETURN_STRINGL(Z_STRVAL_P(etag), Z_STRLEN_P(etag), 1); + } +} +/* }}} */ + +/* {{{ proto void HttpResponse::setThrottleDelay(double seconds) + * + */ +PHP_METHOD(HttpResponse, setThrottleDelay) +{ + double seconds; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &seconds)) { + getObject(http_response_object, obj); + + UPD_PROP(obj, double, throttleDelay, seconds); + } +} +/* }}} */ + +/* {{{ proto double HttpResponse::getThrottleDelay() + * + */ +PHP_METHOD(HttpResponse, getThrottleDelay) +{ + NO_ARGS; + + IF_RETVAL_USED { + zval *seconds; + getObject(http_response_object, obj); + + seconds = GET_PROP(obj, throttleDelay); + RETURN_DOUBLE(Z_DVAL_P(seconds)); + } +} +/* }}} */ + +/* {{{ proto void HttpResponse::setSendBuffersize(long bytes) + * + */ +PHP_METHOD(HttpResponse, setSendBuffersize) +{ + long bytes; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &bytes)) { + getObject(http_response_object, obj); + UPD_PROP(obj, long, sendBuffersize, bytes); + } +} +/* }}} */ + +/* {{{ proto long HttpResponse::getSendBuffersize() + * + */ +PHP_METHOD(HttpResponse, getSendBuffersize) +{ NO_ARGS; - etag = GET_PROP(obj, eTag); - RETURN_STRINGL(Z_STRVAL_P(etag), Z_STRLEN_P(etag), 1); + IF_RETVAL_USED { + zval *bytes; + getObject(http_response_object, obj); + + bytes = GET_PROP(obj, sendBuffersize); + RETURN_LONG(Z_LVAL_P(bytes)); + } } /* }}} */ @@ -337,13 +412,15 @@ PHP_METHOD(HttpResponse, setData) */ PHP_METHOD(HttpResponse, getData) { - zval *the_data; - getObject(http_response_object, obj); - NO_ARGS; - the_data = GET_PROP(obj, data); - RETURN_STRINGL(Z_STRVAL_P(the_data), Z_STRLEN_P(the_data), 1); + IF_RETVAL_USED { + zval *the_data; + getObject(http_response_object, obj); + + the_data = GET_PROP(obj, data); + RETURN_STRINGL(Z_STRVAL_P(the_data), Z_STRLEN_P(the_data), 1); + } } /* }}} */ @@ -376,13 +453,15 @@ PHP_METHOD(HttpResponse, setStream) */ PHP_METHOD(HttpResponse, getStream) { - zval *the_stream; - getObject(http_response_object, obj); - NO_ARGS; - the_stream = GET_PROP(obj, stream); - RETURN_RESOURCE(Z_LVAL_P(the_stream)); + IF_RETVAL_USED { + zval *the_stream; + getObject(http_response_object, obj); + + the_stream = GET_PROP(obj, stream); + RETURN_RESOURCE(Z_LVAL_P(the_stream)); + } } /* }}} */ @@ -414,13 +493,15 @@ PHP_METHOD(HttpResponse, setFile) */ PHP_METHOD(HttpResponse, getFile) { - zval *the_file; - getObject(http_response_object, obj); - NO_ARGS; - the_file = GET_PROP(obj, file); - RETURN_STRINGL(Z_STRVAL_P(the_file), Z_STRLEN_P(the_file), 1); + IF_RETVAL_USED { + zval *the_file; + getObject(http_response_object, obj); + + the_file = GET_PROP(obj, file); + RETURN_STRINGL(Z_STRVAL_P(the_file), Z_STRLEN_P(the_file), 1); + } } /* }}} */ @@ -456,6 +537,8 @@ PHP_METHOD(HttpResponse, send) /* caching */ if (Z_LVAL_P(do_cache)) { + char *cc_hdr; + int cc_len; zval *cctrl, *etag, *lmod, *ccraw; etag = GET_PROP(obj, eTag); @@ -464,14 +547,17 @@ PHP_METHOD(HttpResponse, send) ccraw = GET_PROP(obj, raw_cache_header); if (Z_LVAL_P(ccraw)) { - http_cache_etag(Z_STRVAL_P(etag), Z_STRLEN_P(etag), Z_STRVAL_P(cctrl), Z_STRLEN_P(cctrl)); - http_cache_last_modified(Z_LVAL_P(lmod), Z_LVAL_P(lmod) ? Z_LVAL_P(lmod) : time(NULL), Z_STRVAL_P(cctrl), Z_STRLEN_P(cctrl)); + cc_hdr = Z_STRVAL_P(cctrl); + cc_len = Z_STRLEN_P(cctrl); } else { char cc_header[42] = {0}; sprintf(cc_header, "%s, must-revalidate, max-age=0", Z_STRVAL_P(cctrl)); - http_cache_etag(Z_STRVAL_P(etag), Z_STRLEN_P(etag), cc_header, strlen(cc_header)); - http_cache_last_modified(Z_LVAL_P(lmod), Z_LVAL_P(lmod) ? Z_LVAL_P(lmod) : time(NULL), cc_header, strlen(cc_header)); + cc_hdr = cc_header; + cc_len = Z_STRLEN_P(cctrl) + lenof(", must-revalidate, max-age=0"); } + + http_cache_etag(Z_STRVAL_P(etag), Z_STRLEN_P(etag), cc_hdr, cc_len); + http_cache_last_modified(Z_LVAL_P(lmod), Z_LVAL_P(lmod) ? Z_LVAL_P(lmod) : time(NULL), cc_hdr, cc_len); } /* content type */ @@ -480,7 +566,7 @@ PHP_METHOD(HttpResponse, send) if (Z_STRLEN_P(ctype)) { http_send_content_type(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype)); } else { - http_send_content_type("application/x-octetstream", sizeof("application/x-octetstream") - 1); + http_send_content_type("application/x-octetstream", lenof("application/x-octetstream")); } } @@ -493,6 +579,15 @@ PHP_METHOD(HttpResponse, send) } } + /* throttling */ + { + zval *send_buffersize, *throttle_delay; + send_buffersize = GET_PROP(obj, sendBuffersize); + throttle_delay = GET_PROP(obj, throttleDelay); + HTTP_G(send).buffer_size = Z_LVAL_P(send_buffersize); + HTTP_G(send).throttle_delay = Z_DVAL_P(throttle_delay); + } + /* send */ { zval *send_mode = GET_PROP(obj, send_mode); @@ -579,12 +674,12 @@ PHP_METHOD(HttpMessage, __construct) */ PHP_METHOD(HttpMessage, getBody) { - zval *body; - getObject(http_message_object, obj); - NO_ARGS; - RETURN_PHPSTR(&obj->message->body, PHPSTR_FREE_NOT, 1); + IF_RETVAL_USED { + getObject(http_message_object, obj); + RETURN_PHPSTR(&obj->message->body, PHPSTR_FREE_NOT, 1); + } } /* }}} */ @@ -594,14 +689,16 @@ PHP_METHOD(HttpMessage, getBody) */ PHP_METHOD(HttpMessage, getHeaders) { - zval headers; - getObject(http_message_object, obj); - NO_ARGS; - Z_ARRVAL(headers) = &obj->message->hdrs; - array_init(return_value); - array_copy(&headers, return_value); + IF_RETVAL_USED { + zval headers; + getObject(http_message_object, obj); + + Z_ARRVAL(headers) = &obj->message->hdrs; + array_init(return_value); + array_copy(&headers, return_value); + } } /* }}} */ @@ -653,11 +750,12 @@ PHP_METHOD(HttpMessage, addHeaders) */ PHP_METHOD(HttpMessage, getType) { - getObject(http_message_object, obj); - NO_ARGS; - RETURN_LONG(obj->message->type); + IF_RETVAL_USED { + getObject(http_message_object, obj); + RETURN_LONG(obj->message->type); + } } /* }}} */ @@ -683,16 +781,18 @@ PHP_METHOD(HttpMessage, setType) */ PHP_METHOD(HttpMessage, getResponseCode) { - getObject(http_message_object, obj); - NO_ARGS; - if (!HTTP_MSG_TYPE(RESPONSE, obj->message)) { - http_error(E_NOTICE, HTTP_E_MSG, "HttpMessage is not of type HTTP_MSG_RESPONSE"); - RETURN_NULL(); - } + IF_RETVAL_USED { + getObject(http_message_object, obj); + + if (!HTTP_MSG_TYPE(RESPONSE, obj->message)) { + http_error(E_NOTICE, HTTP_E_MSG, "HttpMessage is not of type HTTP_MSG_RESPONSE"); + RETURN_NULL(); + } - RETURN_LONG(obj->message->info.response.code); + RETURN_LONG(obj->message->info.response.code); + } } /* }}} */ @@ -707,7 +807,7 @@ PHP_METHOD(HttpMessage, setResponseCode) long code; getObject(http_message_object, obj); - if (obj->message->type != HTTP_MSG_RESPONSE) { + if (!HTTP_MSG_TYPE(RESPONSE, obj->message)) { http_error(E_WARNING, HTTP_E_MSG, "HttpMessage is not of type HTTP_MSG_RESPONSE"); RETURN_FALSE; } @@ -732,16 +832,18 @@ PHP_METHOD(HttpMessage, setResponseCode) */ PHP_METHOD(HttpMessage, getRequestMethod) { - getObject(http_message_object, obj); - NO_ARGS; - if (obj->message->type != HTTP_MSG_REQUEST) { - http_error(E_NOTICE, HTTP_E_MSG, "HttpMessage is not of type HTTP_MSG_REQUEST"); - RETURN_NULL(); - } + IF_RETVAL_USED { + getObject(http_message_object, obj); - RETURN_STRING(obj->message->info.request.method, 1); + if (!HTTP_MSG_TYPE(REQUEST, obj->message)) { + http_error(E_NOTICE, HTTP_E_MSG, "HttpMessage is not of type HTTP_MSG_REQUEST"); + RETURN_NULL(); + } + + RETURN_STRING(obj->message->info.request.method, 1); + } } /* }}} */ @@ -756,7 +858,7 @@ PHP_METHOD(HttpMessage, setRequestMethod) int method_len; getObject(http_message_object, obj); - if (obj->message->type != HTTP_MSG_REQUEST) { + if (!HTTP_MSG_TYPE(REQUEST, obj->message)) { http_error(E_WARNING, HTTP_E_MSG, "HttpMessage is not of type HTTP_MSG_REQUEST"); RETURN_FALSE; } @@ -773,10 +875,7 @@ PHP_METHOD(HttpMessage, setRequestMethod) RETURN_FALSE; } - if (obj->message->info.request.method) { - efree(obj->message->info.request.method); - } - obj->message->info.request.method = estrndup(method, method_len); + STR_SET(obj->message->info.request.method, estrndup(method, method_len)); RETURN_TRUE; } /* }}} */ @@ -787,17 +886,19 @@ PHP_METHOD(HttpMessage, setRequestMethod) */ PHP_METHOD(HttpMessage, getRequestUri) { - zval *uri; - getObject(http_message_object, obj); - NO_ARGS; - if (obj->message->type != HTTP_MSG_REQUEST) { - http_error(E_WARNING, HTTP_E_MSG, "HttpMessage is not of type HTTP_MSG_REQUEST"); - RETURN_NULL(); - } + IF_RETVAL_USED { + zval *uri; + getObject(http_message_object, obj); - RETURN_STRING(obj->message->info.request.URI, 1); + if (!HTTP_MSG_TYPE(REQUEST, obj->message)) { + http_error(E_WARNING, HTTP_E_MSG, "HttpMessage is not of type HTTP_MSG_REQUEST"); + RETURN_NULL(); + } + + RETURN_STRING(obj->message->info.request.URI, 1); + } } /* }}} */ @@ -813,7 +914,7 @@ PHP_METHOD(HttpMessage, setRequestUri) int URIlen; getObject(http_message_object, obj); - if (obj->message->type != HTTP_MSG_REQUEST) { + if (!HTTP_MSG_TYPE(REQUEST, obj->message)) { http_error(E_WARNING, HTTP_E_MSG, "HttpMessage is not of type HTTP_MSG_REQUEST"); RETURN_FALSE; } @@ -825,10 +926,7 @@ PHP_METHOD(HttpMessage, setRequestUri) RETURN_FALSE; } - if (obj->message->info.request.URI) { - efree(obj->message->info.request.URI); - } - obj->message->info.request.URI = estrndup(URI, URIlen); + STR_SET(obj->message->info.request.URI, estrndup(URI, URIlen)); RETURN_TRUE; } /* }}} */ @@ -839,28 +937,30 @@ PHP_METHOD(HttpMessage, setRequestUri) */ PHP_METHOD(HttpMessage, getHttpVersion) { - char ver[4] = {0}; - float version; - getObject(http_message_object, obj); - NO_ARGS; - switch (obj->message->type) - { - case HTTP_MSG_RESPONSE: - version = obj->message->info.response.http_version; - break; + IF_RETVAL_USED { + char ver[4] = {0}; + float version; + getObject(http_message_object, obj); - case HTTP_MSG_REQUEST: - version = obj->message->info.request.http_version; - break; + switch (obj->message->type) + { + case HTTP_MSG_RESPONSE: + version = obj->message->info.response.http_version; + break; - case HTTP_MSG_NONE: - default: - RETURN_NULL(); + case HTTP_MSG_REQUEST: + version = obj->message->info.request.http_version; + break; + + case HTTP_MSG_NONE: + default: + RETURN_NULL(); + } + sprintf(ver, "%1.1f", version); + RETURN_STRINGL(ver, 3, 1); } - sprintf(ver, "%1.1f", version); - RETURN_STRINGL(ver, 3, 1); } /* }}} */ @@ -879,19 +979,19 @@ PHP_METHOD(HttpMessage, setHttpVersion) return; } - if (obj->message->type == HTTP_MSG_NONE) { + if (HTTP_MSG_TYPE(NONE, obj->message)) { http_error(E_WARNING, HTTP_E_MSG, "Message is neither of type HTTP_MSG_RESPONSE nor HTTP_MSG_REQUEST"); RETURN_FALSE; } - convert_to_double_ex(&zv); + convert_to_double(zv); sprintf(v, "%1.1f", Z_DVAL_P(zv)); if (strcmp(v, "1.0") && strcmp(v, "1.1")) { http_error_ex(E_WARNING, HTTP_E_PARAM, "Invalid HTTP protocol version (1.0 or 1.1): %s", v); RETURN_FALSE; } - if (obj->message->type == HTTP_MSG_RESPONSE) { + if (HTTP_MSG_TYPE(RESPONSE, obj->message)) { obj->message->info.response.http_version = (float) Z_DVAL_P(zv); } else { obj->message->info.request.http_version = (float) Z_DVAL_P(zv); @@ -906,14 +1006,16 @@ PHP_METHOD(HttpMessage, setHttpVersion) */ PHP_METHOD(HttpMessage, getParentMessage) { - getObject(http_message_object, obj); - NO_ARGS; - if (obj->message->parent) { - RETVAL_OBJVAL(obj->parent); - } else { - RETVAL_NULL(); + IF_RETVAL_USED { + getObject(http_message_object, obj); + + if (obj->message->parent) { + RETVAL_OBJVAL(obj->parent); + } else { + RETVAL_NULL(); + } } } /* }}} */ @@ -938,21 +1040,23 @@ PHP_METHOD(HttpMessage, send) */ PHP_METHOD(HttpMessage, toString) { - char *string; - size_t length; - zend_bool include_parent = 1; - getObject(http_message_object, obj); + IF_RETVAL_USED { + char *string; + size_t length; + zend_bool include_parent = 1; + getObject(http_message_object, obj); - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &include_parent)) { - RETURN_FALSE; - } + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &include_parent)) { + RETURN_FALSE; + } - if (include_parent) { - http_message_serialize(obj->message, &string, &length); - } else { - http_message_tostring(obj->message, &string, &length); + if (include_parent) { + http_message_serialize(obj->message, &string, &length); + } else { + http_message_tostring(obj->message, &string, &length); + } + RETURN_STRINGL(string, length, 0); } - RETURN_STRINGL(string, length, 0); } /* }}} */ @@ -1061,14 +1165,16 @@ PHP_METHOD(HttpRequest, setOptions) */ PHP_METHOD(HttpRequest, getOptions) { - zval *opts; - getObject(http_request_object, obj); - NO_ARGS; - opts = GET_PROP(obj, options); - array_init(return_value); - array_copy(opts, return_value); + IF_RETVAL_USED { + zval *opts; + getObject(http_request_object, obj); + + opts = GET_PROP(obj, options); + array_init(return_value); + array_copy(opts, return_value); + } } /* }}} */ @@ -1119,17 +1225,19 @@ PHP_METHOD(HttpRequest, setSslOptions) */ PHP_METHOD(HttpRequest, getSslOptions) { - zval *opts, **ssl_options; - getObject(http_request_object, obj); - NO_ARGS; - opts = GET_PROP(obj, options); + IF_RETVAL_USED { + zval *opts, **ssl_options; + getObject(http_request_object, obj); - array_init(return_value); + opts = GET_PROP(obj, options); - if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "ssl", sizeof("ssl"), (void **) &ssl_options)) { - array_copy(*ssl_options, return_value); + array_init(return_value); + + if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "ssl", sizeof("ssl"), (void **) &ssl_options)) { + array_copy(*ssl_options, return_value); + } } } /* }}} */ @@ -1182,17 +1290,19 @@ PHP_METHOD(HttpRequest, addHeaders) */ PHP_METHOD(HttpRequest, getHeaders) { - zval *opts, **headers; - getObject(http_request_object, obj); - NO_ARGS; - opts = GET_PROP(obj, options); + IF_RETVAL_USED { + zval *opts, **headers; + getObject(http_request_object, obj); - array_init(return_value); + opts = GET_PROP(obj, options); - if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "headers", sizeof("headers"), (void **) &headers)) { - array_copy(*headers, return_value); + array_init(return_value); + + if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "headers", sizeof("headers"), (void **) &headers)) { + array_copy(*headers, return_value); + } } } /* }}} */ @@ -1245,17 +1355,19 @@ PHP_METHOD(HttpRequest, addCookies) */ PHP_METHOD(HttpRequest, getCookies) { - zval *opts, **cookies; - getObject(http_request_object, obj); - NO_ARGS; - opts = GET_PROP(obj, options); + IF_RETVAL_USED { + zval *opts, **cookies; + getObject(http_request_object, obj); - array_init(return_value); + opts = GET_PROP(obj, options); - if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "cookies", sizeof("cookies"), (void **) &cookies)) { - array_copy(*cookies, return_value); + array_init(return_value); + + if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "cookies", sizeof("cookies"), (void **) &cookies)) { + array_copy(*cookies, return_value); + } } } /* }}} */ @@ -1300,13 +1412,15 @@ PHP_METHOD(HttpRequest, setURL) */ PHP_METHOD(HttpRequest, getURL) { - zval *URL; - getObject(http_request_object, obj); - NO_ARGS; - URL = GET_PROP(obj, url); - RETURN_STRINGL(Z_STRVAL_P(URL), Z_STRLEN_P(URL), 1); + IF_RETVAL_USED { + zval *URL; + getObject(http_request_object, obj); + + URL = GET_PROP(obj, url); + RETURN_STRINGL(Z_STRVAL_P(URL), Z_STRLEN_P(URL), 1); + } } /* }}} */ @@ -1335,13 +1449,15 @@ PHP_METHOD(HttpRequest, setMethod) */ PHP_METHOD(HttpRequest, getMethod) { - zval *meth; - getObject(http_request_object, obj); - NO_ARGS; - meth = GET_PROP(obj, method); - RETURN_LONG(Z_LVAL_P(meth)); + IF_RETVAL_USED { + zval *meth; + getObject(http_request_object, obj); + + meth = GET_PROP(obj, method); + RETURN_LONG(Z_LVAL_P(meth)); + } } /* }}} */ @@ -1376,13 +1492,15 @@ PHP_METHOD(HttpRequest, setContentType) */ PHP_METHOD(HttpRequest, getContentType) { - zval *ctype; - getObject(http_request_object, obj); - NO_ARGS; - ctype = GET_PROP(obj, contentType); - RETURN_STRINGL(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1); + IF_RETVAL_USED { + zval *ctype; + getObject(http_request_object, obj); + + ctype = GET_PROP(obj, contentType); + RETURN_STRINGL(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1); + } } /* }}} */ @@ -1423,13 +1541,15 @@ PHP_METHOD(HttpRequest, setQueryData) */ PHP_METHOD(HttpRequest, getQueryData) { - zval *qdata; - getObject(http_request_object, obj); - NO_ARGS; - qdata = GET_PROP(obj, queryData); - RETURN_STRINGL(Z_STRVAL_P(qdata), Z_STRLEN_P(qdata), 1); + IF_RETVAL_USED { + zval *qdata; + getObject(http_request_object, obj); + + qdata = GET_PROP(obj, queryData); + RETURN_STRINGL(Z_STRVAL_P(qdata), Z_STRLEN_P(qdata), 1); + } } /* }}} */ @@ -1526,14 +1646,16 @@ PHP_METHOD(HttpRequest, setPostFields) */ PHP_METHOD(HttpRequest, getPostFields) { - zval *post_data; - getObject(http_request_object, obj); - NO_ARGS; - post_data = GET_PROP(obj, postFields); - array_init(return_value); - array_copy(post_data, return_value); + IF_RETVAL_USED { + zval *post_data; + getObject(http_request_object, obj); + + post_data = GET_PROP(obj, postFields); + array_init(return_value); + array_copy(post_data, return_value); + } } /* }}} */ @@ -1600,15 +1722,17 @@ PHP_METHOD(HttpRequest, addPostFile) */ PHP_METHOD(HttpRequest, getPostFiles) { - zval *files; - getObject(http_request_object, obj); - NO_ARGS; - files = GET_PROP(obj, postFiles); + IF_RETVAL_USED { + zval *files; + getObject(http_request_object, obj); + + files = GET_PROP(obj, postFiles); - array_init(return_value); - array_copy(files, return_value); + array_init(return_value); + array_copy(files, return_value); + } } /* }}} */ @@ -1635,14 +1759,16 @@ PHP_METHOD(HttpRequest, unsetPostFiles) */ PHP_METHOD(HttpRequest, getResponseData) { - zval *data; - getObject(http_request_object, obj); - NO_ARGS; - data = GET_PROP(obj, responseData); - array_init(return_value); - array_copy(data, return_value); + IF_RETVAL_USED { + zval *data; + getObject(http_request_object, obj); + + data = GET_PROP(obj, responseData); + array_init(return_value); + array_copy(data, return_value); + } } /* }}} */ @@ -1652,27 +1778,29 @@ PHP_METHOD(HttpRequest, getResponseData) */ PHP_METHOD(HttpRequest, getResponseHeader) { - zval *data, **headers, **header; - char *header_name = NULL; - int header_len = 0; - getObject(http_response_object, obj); + IF_RETVAL_USED { + zval *data, **headers, **header; + char *header_name = NULL; + int header_len = 0; + getObject(http_response_object, obj); - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &header_name, &header_len)) { - RETURN_FALSE; - } + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &header_name, &header_len)) { + RETURN_FALSE; + } - data = GET_PROP(obj, responseData); - if (SUCCESS != zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &headers)) { - RETURN_FALSE; - } + data = GET_PROP(obj, responseData); + if (SUCCESS != zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &headers)) { + RETURN_FALSE; + } - if (!header_len || !header_name) { - array_init(return_value); - array_copy(*headers, return_value); - } else if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(headers), pretty_key(header_name, header_len, 1, 1), header_len + 1, (void **) &header)) { - RETURN_STRINGL(Z_STRVAL_PP(header), Z_STRLEN_PP(header), 1); - } else { - RETURN_FALSE; + if (!header_len || !header_name) { + array_init(return_value); + array_copy(*headers, return_value); + } else if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(headers), pretty_key(header_name, header_len, 1, 1), header_len + 1, (void **) &header)) { + RETURN_STRINGL(Z_STRVAL_PP(header), Z_STRLEN_PP(header), 1); + } else { + RETURN_FALSE; + } } } /* }}} */ @@ -1683,35 +1811,61 @@ PHP_METHOD(HttpRequest, getResponseHeader) */ PHP_METHOD(HttpRequest, getResponseCookie) { - zval *data, **headers; - char *cookie_name = NULL; - int cookie_len = 0; - getObject(http_request_object, obj); + IF_RETVAL_USED { + zval *data, **headers; + char *cookie_name = NULL; + int cookie_len = 0; + getObject(http_request_object, obj); - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &cookie_name, &cookie_len)) { - RETURN_FALSE; - } - - array_init(return_value); - - data = GET_PROP(obj, responseData); - if (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &headers)) { - ulong idx = 0; - char *key = NULL; - zval **header = NULL; + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &cookie_name, &cookie_len)) { + RETURN_FALSE; + } - FOREACH_HASH_KEYVAL(Z_ARRVAL_PP(headers), key, idx, header) { - if (key && !strcasecmp(key, "Set-Cookie")) { - /* several cookies? */ - if (Z_TYPE_PP(header) == IS_ARRAY) { - zval **cookie; + array_init(return_value); - FOREACH_HASH_VAL(Z_ARRVAL_PP(header), cookie) { + data = GET_PROP(obj, responseData); + if (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &headers)) { + ulong idx = 0; + char *key = NULL; + zval **header = NULL; + + FOREACH_HASH_KEYVAL(Z_ARRVAL_PP(headers), key, idx, header) { + if (key && !strcasecmp(key, "Set-Cookie")) { + /* several cookies? */ + if (Z_TYPE_PP(header) == IS_ARRAY) { + zval **cookie; + + FOREACH_HASH_VAL(Z_ARRVAL_PP(header), cookie) { + zval *cookie_hash; + MAKE_STD_ZVAL(cookie_hash); + array_init(cookie_hash); + + if (SUCCESS == http_parse_cookie(Z_STRVAL_PP(cookie), Z_ARRVAL_P(cookie_hash))) { + if (!cookie_len) { + add_next_index_zval(return_value, cookie_hash); + } else { + zval **name; + + if ( (SUCCESS == zend_hash_find(Z_ARRVAL_P(cookie_hash), "name", sizeof("name"), (void **) &name)) && + (!strcmp(Z_STRVAL_PP(name), cookie_name))) { + add_next_index_zval(return_value, cookie_hash); + return; /* <<< FOUND >>> */ + } else { + zval_dtor(cookie_hash); + efree(cookie_hash); + } + } + } else { + zval_dtor(cookie_hash); + efree(cookie_hash); + } + } + } else { zval *cookie_hash; MAKE_STD_ZVAL(cookie_hash); array_init(cookie_hash); - if (SUCCESS == http_parse_cookie(Z_STRVAL_PP(cookie), Z_ARRVAL_P(cookie_hash))) { + if (SUCCESS == http_parse_cookie(Z_STRVAL_PP(header), Z_ARRVAL_P(cookie_hash))) { if (!cookie_len) { add_next_index_zval(return_value, cookie_hash); } else { @@ -1720,7 +1874,6 @@ PHP_METHOD(HttpRequest, getResponseCookie) if ( (SUCCESS == zend_hash_find(Z_ARRVAL_P(cookie_hash), "name", sizeof("name"), (void **) &name)) && (!strcmp(Z_STRVAL_PP(name), cookie_name))) { add_next_index_zval(return_value, cookie_hash); - return; /* <<< FOUND >>> */ } else { zval_dtor(cookie_hash); efree(cookie_hash); @@ -1731,34 +1884,11 @@ PHP_METHOD(HttpRequest, getResponseCookie) efree(cookie_hash); } } - } else { - zval *cookie_hash; - MAKE_STD_ZVAL(cookie_hash); - array_init(cookie_hash); - - if (SUCCESS == http_parse_cookie(Z_STRVAL_PP(header), Z_ARRVAL_P(cookie_hash))) { - if (!cookie_len) { - add_next_index_zval(return_value, cookie_hash); - } else { - zval **name; - - if ( (SUCCESS == zend_hash_find(Z_ARRVAL_P(cookie_hash), "name", sizeof("name"), (void **) &name)) && - (!strcmp(Z_STRVAL_PP(name), cookie_name))) { - add_next_index_zval(return_value, cookie_hash); - } else { - zval_dtor(cookie_hash); - efree(cookie_hash); - } - } - } else { - zval_dtor(cookie_hash); - efree(cookie_hash); - } + break; } - break; + /* reset key */ + key = NULL; } - /* reset key */ - key = NULL; } } } @@ -1770,16 +1900,18 @@ PHP_METHOD(HttpRequest, getResponseCookie) */ PHP_METHOD(HttpRequest, getResponseBody) { - zval *data, **body; - getObject(http_request_object, obj); - NO_ARGS; - data = GET_PROP(obj, responseData); - if (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "body", sizeof("body"), (void **) &body)) { - RETURN_STRINGL(Z_STRVAL_PP(body), Z_STRLEN_PP(body), 1); - } else { - RETURN_FALSE; + IF_RETVAL_USED { + zval *data, **body; + getObject(http_request_object, obj); + + data = GET_PROP(obj, responseData); + if (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "body", sizeof("body"), (void **) &body)) { + RETURN_STRINGL(Z_STRVAL_PP(body), Z_STRLEN_PP(body), 1); + } else { + RETURN_FALSE; + } } } /* }}} */ @@ -1790,13 +1922,15 @@ PHP_METHOD(HttpRequest, getResponseBody) */ PHP_METHOD(HttpRequest, getResponseCode) { - zval *code; - getObject(http_request_object, obj); - NO_ARGS; - code = GET_PROP(obj, responseCode); - RETURN_LONG(Z_LVAL_P(code)); + IF_RETVAL_USED { + zval *code; + getObject(http_request_object, obj); + + code = GET_PROP(obj, responseCode); + RETURN_LONG(Z_LVAL_P(code)); + } } /* }}} */ @@ -1807,27 +1941,29 @@ PHP_METHOD(HttpRequest, getResponseCode) */ PHP_METHOD(HttpRequest, getResponseInfo) { - zval *info, **infop; - char *info_name = NULL; - int info_len = 0; - getObject(http_request_object, obj); + IF_RETVAL_USED { + zval *info, **infop; + char *info_name = NULL; + int info_len = 0; + getObject(http_request_object, obj); - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &info_name, &info_len)) { - RETURN_FALSE; - } + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &info_name, &info_len)) { + RETURN_FALSE; + } - info = GET_PROP(obj, responseInfo); + info = GET_PROP(obj, responseInfo); - if (info_len && info_name) { - if (SUCCESS == zend_hash_find(Z_ARRVAL_P(info), pretty_key(info_name, info_len, 0, 0), info_len + 1, (void **) &infop)) { - RETURN_ZVAL(*infop, 1, ZVAL_PTR_DTOR); + if (info_len && info_name) { + if (SUCCESS == zend_hash_find(Z_ARRVAL_P(info), pretty_key(info_name, info_len, 0, 0), info_len + 1, (void **) &infop)) { + RETURN_ZVAL(*infop, 1, ZVAL_PTR_DTOR); + } else { + http_error_ex(E_NOTICE, HTTP_E_PARAM, "Could not find response info named %s", info_name); + RETURN_FALSE; + } } else { - http_error_ex(E_NOTICE, HTTP_E_PARAM, "Could not find response info named %s", info_name); - RETURN_FALSE; + array_init(return_value); + array_copy(info, return_value); } - } else { - array_init(return_value); - array_copy(info, return_value); } } /* }}}*/ @@ -1838,16 +1974,18 @@ PHP_METHOD(HttpRequest, getResponseInfo) */ PHP_METHOD(HttpRequest, getResponseMessage) { - zval *message; - getObject(http_request_object, obj); - NO_ARGS; - message = GET_PROP(obj, responseMessage); - Z_TYPE_P(return_value) = IS_OBJECT; - return_value->is_ref = 1; - return_value->value.obj = message->value.obj; - zval_add_ref(&return_value); + IF_RETVAL_USED { + zval *message; + getObject(http_request_object, obj); + + message = GET_PROP(obj, responseMessage); + Z_TYPE_P(return_value) = IS_OBJECT; + return_value->is_ref = 1; + return_value->value.obj = message->value.obj; + zval_add_ref(&return_value); + } } /* {{{ proto bool HttpRequest::send() @@ -1908,7 +2046,9 @@ PHP_METHOD(HttpRequest, send) resp = GET_PROP(obj, responseData); // HTTP_URI_MAXLEN+1 long char * - request_uri = http_absolute_uri_ex(Z_STRVAL_P(URL), Z_STRLEN_P(URL), NULL, 0, NULL, 0, 0); + if (!(request_uri = http_absolute_uri_ex(Z_STRVAL_P(URL), Z_STRLEN_P(URL), NULL, 0, NULL, 0, 0))) { + RETURN_FALSE; + } if (Z_STRLEN_P(qdata) && (strlen(request_uri) < HTTP_URI_MAXLEN)) { if (!strchr(request_uri, '?')) { @@ -1933,7 +2073,7 @@ PHP_METHOD(HttpRequest, send) php_stream_statbuf ssb; zval *file = GET_PROP(obj, putFile); - if ( (stream = php_stream_open_wrapper(Z_STRVAL_P(file), , "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL)) && + if ( (stream = php_stream_open_wrapper(Z_STRVAL_P(file), , "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL)) && !php_stream_stat(stream, &ssb)) { body.type = HTTP_REQUEST_BODY_UPLOADFILE; body.data = stream; @@ -1963,11 +2103,11 @@ PHP_METHOD(HttpRequest, send) { http_request_body body; zval *post = GET_PROP(obj, postData); - + body.type = HTTP_REQUEST_BODY_CSTRING; body.data = Z_STRVAL_P(post); body.size = Z_STRLEN_P(post); - + status = http_request_ex(obj->ch, Z_LVAL_P(meth), request_uri, &body, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response); } break; diff --git a/http_request_api.c b/http_request_api.c index 19f25fa..0b71ef7 100644 --- a/http_request_api.c +++ b/http_request_api.c @@ -37,7 +37,7 @@ ZEND_EXTERN_MODULE_GLOBALS(http) #if LIBCURL_VERSION_NUM < 0x070c00 -# define curl_easy_strerror(code) HTTP_G(curlerr) +# define curl_easy_strerror(code) HTTP_G(request).curl.error #endif #define HTTP_CURL_INFO(I) HTTP_CURL_INFO_EX(I, I) @@ -156,6 +156,8 @@ PHP_HTTP_API STATUS _http_request_body_fill(http_request_body *body, HashTable * curl_formfree(http_post_data[0]); return FAILURE; } + } else { + http_error(E_NOTICE, HTTP_E_PARAM, "Post file array entry misses either 'name', 'type' or 'file' entry"); } } @@ -244,7 +246,7 @@ PHP_HTTP_API STATUS _http_request_ex(CURL *ch, http_request_method meth, const c HTTP_CURL_OPT(NOSIGNAL, 1); #endif #if LIBCURL_VERSION_NUM < 0x070c00 - HTTP_CURL_OPT(ERRORBUFFER, HTTP_G(curlerr)); + HTTP_CURL_OPT(ERRORBUFFER, HTTP_G(request).curl.error); #endif /* progress callback */ @@ -331,14 +333,13 @@ PHP_HTTP_API STATUS _http_request_ex(CURL *ch, http_request_method meth, const c if (zoption = http_curl_getopt(options, "useragent", IS_STRING)) { HTTP_CURL_OPT(USERAGENT, http_curl_copystr(Z_STRVAL_P(zoption))); } else { - HTTP_CURL_OPT(USERAGENT, - "PECL::HTTP/" HTTP_PEXT_VERSION " (PHP/" PHP_VERSION ")"); + HTTP_CURL_OPT(USERAGENT, "PECL::HTTP/" HTTP_PEXT_VERSION " (PHP/" PHP_VERSION ")"); } /* additional headers, array('name' => 'value') */ if (zoption = http_curl_getopt(options, "headers", IS_ARRAY)) { char *header_key; - long header_idx; + ulong header_idx; struct curl_slist *headers = NULL; FOREACH_KEY(zoption, header_key, header_idx) { @@ -363,7 +364,7 @@ PHP_HTTP_API STATUS _http_request_ex(CURL *ch, http_request_method meth, const c /* cookies, array('name' => 'value') */ if (zoption = http_curl_getopt(options, "cookies", IS_ARRAY)) { char *cookie_key = NULL; - long cookie_idx = 0; + ulong cookie_idx = 0; phpstr *qstr = phpstr_new(); FOREACH_KEY(zoption, cookie_key, cookie_idx) { @@ -427,7 +428,7 @@ PHP_HTTP_API STATUS _http_request_ex(CURL *ch, http_request_method meth, const c zval **param; FOREACH_KEYVAL(zoption, key, idx, param) { - if (key) {fprintf(stderr, "%s\n", key); + if (key) { HTTP_CURL_OPT_SSL_STRING(CERT); #if LIBCURL_VERSION_NUM >= 0x070903 HTTP_CURL_OPT_SSL_STRING(CERTTYPE); @@ -483,8 +484,8 @@ PHP_HTTP_API STATUS _http_request_ex(CURL *ch, http_request_method meth, const c break; default: - if ((meth > HTTP_NO_REQUEST_METHOD) && (meth < HTTP_MAX_REQUEST_METHOD)) { - curl_easy_setopt(ch, CURLOPT_CUSTOMREQUEST, http_request_methods[meth]); + if (http_request_method_exists(0, meth, NULL)) { + curl_easy_setopt(ch, CURLOPT_CUSTOMREQUEST, http_request_method_name(meth)); } else { http_error_ex(E_WARNING, HTTP_E_CURL, "Unsupported request method: %d", meth); status = FAILURE; @@ -580,7 +581,7 @@ PHP_HTTP_API STATUS _http_request_ex(CURL *ch, http_request_method meth, const c http_request_end: /* free strings copied with http_curl_copystr() */ - zend_llist_clean(&HTTP_G(to_free)); + zend_llist_clean(&HTTP_G(request).curl.copies); /* clean curl handle if acquired */ if (clean_curl) { @@ -597,16 +598,71 @@ http_request_end: } /* }}} */ -/* {{{ char *http_request_method_string(http_request_method) */ -PHP_HTTP_API const char *_http_request_method_string(http_request_method m) +/* {{{ char *http_request_method_name(http_request_method) */ +PHP_HTTP_API const char *_http_request_method_name(http_request_method m TSRMLS_DC) { - if ((m > HTTP_NO_REQUEST_METHOD) && (m < HTTP_MAX_REQUEST_METHOD)) { + zval **meth; + + if (HTTP_STD_REQUEST_METHOD(m)) { return http_request_methods[m]; } + + if (SUCCESS == zend_hash_index_find(&HTTP_G(request).methods.custom, HTTP_CUSTOM_REQUEST_METHOD(m), (void **) &meth)) { + return Z_STRVAL_PP(meth); + } + return http_request_methods[0]; } /* }}} */ +/* {{{ unsigned long http_request_method_exists(zend_bool, unsigned long, char *) */ +PHP_HTTP_API unsigned long _http_request_method_exists(zend_bool by_name, unsigned long id, const char *name TSRMLS_DC) +{ + if (by_name) { + unsigned i; + + for (i = HTTP_NO_REQUEST_METHOD + 1; i < HTTP_MAX_REQUEST_METHOD; ++i) { + if (!strcmp(name, http_request_methods[i])) { + return i; + } + } + { + zval **data; + char *key; + ulong idx; + + FOREACH_HASH_KEYVAL(&HTTP_G(request).methods.custom, key, idx, data) { + if (!strcmp(name, Z_STRVAL_PP(data))) { + return idx + HTTP_MAX_REQUEST_METHOD; + } + } + } + return 0; + } else { + return HTTP_STD_REQUEST_METHOD(id) || zend_hash_index_exists(&HTTP_G(request).methods.custom, HTTP_CUSTOM_REQUEST_METHOD(id)) ? id : 0; + } +} +/* }}} */ + +/* {{{ unsigned long http_request_method_register(char *) */ +PHP_HTTP_API unsigned long _http_request_method_register(const char *method TSRMLS_DC) +{ + zval array; + unsigned long meth_num = HTTP_G(request).methods.custom.nNextFreeElement + HTTP_MAX_REQUEST_METHOD; + + Z_ARRVAL(array) = &HTTP_G(request).methods.custom; + add_next_index_string(&array, estrdup(method), 0); + return meth_num; +} +/* }}} */ + +/* {{{ STATUS http_request_method_unregister(usngigned long) */ +PHP_HTTP_API STATUS _http_request_method_unregister(unsigned long method TSRMLS_DC) +{ + return zend_hash_index_del(&HTTP_G(request).methods.custom, HTTP_CUSTOM_REQUEST_METHOD(method)); +} +/* }}} */ + /* {{{ char *http_request_methods[] */ static const char *const http_request_methods[] = { "UNKOWN", @@ -649,7 +705,7 @@ static const char *const http_request_methods[] = { static inline char *_http_curl_copystr(const char *str TSRMLS_DC) { char *new_str = estrdup(str); - zend_llist_add_element(&HTTP_G(to_free), &new_str); + zend_llist_add_element(&HTTP_G(request).curl.copies, &new_str); return new_str; } /* }}} */ diff --git a/http_response_object.c b/http_response_object.c index aaa51f5..480479d 100644 --- a/http_response_object.c +++ b/http_response_object.c @@ -52,6 +52,12 @@ zend_function_entry http_response_object_fe[] = { PHP_ME(HttpResponse, setGzip, NULL, ZEND_ACC_PUBLIC) PHP_ME(HttpResponse, getGzip, NULL, ZEND_ACC_PUBLIC) + PHP_ME(HttpResponse, setThrottleDelay, NULL, ZEND_ACC_PUBLIC) + PHP_ME(HttpResponse, getThrottleDelay, NULL, ZEND_ACC_PUBLIC) + + PHP_ME(HttpResponse, setSendBuffersize, NULL, ZEND_ACC_PUBLIC) + PHP_ME(HttpResponse, getSendBuffersize, NULL, ZEND_ACC_PUBLIC) + PHP_ME(HttpResponse, setData, NULL, ZEND_ACC_PUBLIC) PHP_ME(HttpResponse, getData, NULL, ZEND_ACC_PUBLIC) @@ -105,6 +111,8 @@ static inline void _http_response_object_declare_default_properties(TSRMLS_D) DCL_PROP(PROTECTED, long, dispoInline, 0); DCL_PROP(PROTECTED, long, cache, 0); DCL_PROP(PROTECTED, long, gzip, 0); + DCL_PROP(PROTECTED, long, sendBuffersize, HTTP_SENDBUF_SIZE); + DCL_PROP(PROTECTED, double, throttleDelay, 0.0); DCL_PROP(PRIVATE, long, raw_cache_header, 0); DCL_PROP(PRIVATE, long, send_mode, -1); diff --git a/http_send_api.c b/http_send_api.c index 41ba305..4caf6ee 100644 --- a/http_send_api.c +++ b/http_send_api.c @@ -35,6 +35,57 @@ ZEND_EXTERN_MODULE_GLOBALS(http); +#define http_flush() _http_flush(TSRMLS_C) +/* {{{ static inline void http_flush() */ +static inline void _http_flush(TSRMLS_D) +{ + php_end_ob_buffer(1, 1 TSRMLS_CC); + sapi_flush(TSRMLS_C); +} +/* }}} */ + +#define http_sleep() _http_sleep(TSRMLS_C) +/* {{{ static inline void http_sleep() */ +static inline void _http_sleep(TSRMLS_D) +{ + if (HTTP_G(send).throttle_delay >= 0.001) { +#if defined(PHP_WIN32) + Sleep((DWORD) (HTTP_G(send).throttle_delay * 1000)); +#elif defined(HAVE_USLEEP) + usleep(HTTP_G(send).throttle_delay * 1000000); +#elif defined(HAVE_NANOSLEEP) + struct timespec req, rem; + + req.tv_sec = (time_t) HTTP_G(send).throttle_delay; + req.tv_nsec = (HTTP_G(send).throttle_delay * 1000000000) % 1000000000; + + while (nanosleep(&req, &rem) && (errno == EINTR) && (rem.tv_nsec > 1000000)) { + req.tv_sec = rem.tv_sec; + req.tv_nsec = rem.tv_nsec; + } +#endif + } +} +/* }}} */ + +#define HTTP_CHUNK_AVAIL(len) ((len -= HTTP_G(send).buffer_size) >= 0) +#define HTTP_CHUNK_WRITE(data, l, dofree, dosleep) \ + { \ + long size = (long) l; \ + \ + if ((1 > size) || (size - PHPWRITE(data, size))) { \ + if (dofree) { \ + efree(data); \ + } \ + return FAILURE; \ + } \ + \ + http_flush(); \ + if (dosleep) { \ + http_sleep(); \ + } \ + } + #define http_send_chunk(d, b, e, m) _http_send_chunk((d), (b), (e), (m) TSRMLS_CC) /* {{{ static STATUS http_send_chunk(const void *, size_t, size_t, http_send_mode) */ static STATUS _http_send_chunk(const void *data, size_t begin, size_t end, http_send_mode mode TSRMLS_DC) @@ -46,44 +97,23 @@ static STATUS _http_send_chunk(const void *data, size_t begin, size_t end, http_ case SEND_RSRC: { char *buf; - size_t read = 0; php_stream *s = (php_stream *) data; if (php_stream_seek(s, begin, SEEK_SET)) { return FAILURE; } - buf = (char *) ecalloc(1, HTTP_SENDBUF_SIZE); - /* read into buf and write out */ - while ((len -= HTTP_SENDBUF_SIZE) >= 0) { - if (!(read = php_stream_read(s, buf, HTTP_SENDBUF_SIZE))) { - efree(buf); - return FAILURE; - } - if (read - php_body_write(buf, read TSRMLS_CC)) { - efree(buf); - return FAILURE; - } - /* ob_flush() && flush() */ - php_end_ob_buffer(1, 1 TSRMLS_CC); - sapi_flush(TSRMLS_C); + buf = emalloc(HTTP_G(send).buffer_size); + + while (HTTP_CHUNK_AVAIL(len)) { + HTTP_CHUNK_WRITE(buf, php_stream_read(s, buf, HTTP_G(send).buffer_size), 1, 1); } /* read & write left over */ if (len) { - if (read = php_stream_read(s, buf, HTTP_SENDBUF_SIZE + len)) { - if (read - php_body_write(buf, read TSRMLS_CC)) { - efree(buf); - return FAILURE; - } - } else { - efree(buf); - return FAILURE; - } - /* ob_flush() & flush() */ - php_end_ob_buffer(1, 1 TSRMLS_CC); - sapi_flush(TSRMLS_C); + HTTP_CHUNK_WRITE(buf, php_stream_read(s, buf, HTTP_G(send).buffer_size + len), 1, 0); } + efree(buf); return SUCCESS; } @@ -92,25 +122,16 @@ static STATUS _http_send_chunk(const void *data, size_t begin, size_t end, http_ { char *s = (char *) data + begin; - while ((len -= HTTP_SENDBUF_SIZE) >= 0) { - if (HTTP_SENDBUF_SIZE - php_body_write(s, HTTP_SENDBUF_SIZE TSRMLS_CC)) { - return FAILURE; - } - s += HTTP_SENDBUF_SIZE; - /* ob_flush() & flush() */ - php_end_ob_buffer(1, 1 TSRMLS_CC); - sapi_flush(TSRMLS_C); + while (HTTP_CHUNK_AVAIL(len)) { + HTTP_CHUNK_WRITE(s, HTTP_G(send).buffer_size, 0, 1); + s += HTTP_G(send).buffer_size; } /* write left over */ if (len) { - if (HTTP_SENDBUF_SIZE + len - php_body_write(s, HTTP_SENDBUF_SIZE + len TSRMLS_CC)) { - return FAILURE; - } - /* ob_flush() & flush() */ - php_end_ob_buffer(1, 1 TSRMLS_CC); - sapi_flush(TSRMLS_C); + HTTP_CHUNK_WRITE(s, HTTP_G(send).buffer_size + len, 0, 0); } + return SUCCESS; } @@ -123,11 +144,11 @@ static STATUS _http_send_chunk(const void *data, size_t begin, size_t end, http_ /* {{{ STATUS http_send_status_header(int, char *) */ -PHP_HTTP_API STATUS _http_send_status_header(int status, const char *header TSRMLS_DC) +PHP_HTTP_API STATUS _http_send_status_header_ex(int status, const char *header, zend_bool replace TSRMLS_DC) { STATUS ret; sapi_header_line h = {(char *) header, header ? strlen(header) : 0, status}; - if (SUCCESS != (ret = sapi_header_op(SAPI_HEADER_REPLACE, &h TSRMLS_CC))) { + if (SUCCESS != (ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, &h TSRMLS_CC))) { http_error_ex(E_WARNING, HTTP_E_HEADER, "Could not send header: %s (%d)", header, status); } return ret; @@ -144,7 +165,7 @@ PHP_HTTP_API STATUS _http_send_last_modified(time_t t TSRMLS_DC) efree(date); /* remember */ - HTTP_G(lmod) = t; + HTTP_G(send).last_modified = t; return http_send_header(modified); } @@ -159,15 +180,13 @@ PHP_HTTP_API STATUS _http_send_etag(const char *etag, size_t etag_len TSRMLS_DC) char *etag_header; if (!etag_len){ - http_error_ex(E_WARNING, HTTP_E_HEADER, "Attempt to send empty ETag (previous: %s)\n", HTTP_G(etag)); + http_error_ex(E_WARNING, HTTP_E_HEADER, "Attempt to send empty ETag (previous: %s)\n", HTTP_G(send).unquoted_etag); return FAILURE; } /* remember */ - if (HTTP_G(etag)) { - efree(HTTP_G(etag)); - } - HTTP_G(etag) = estrdup(etag); + STR_FREE(HTTP_G(send).unquoted_etag); + HTTP_G(send).unquoted_etag = estrdup(etag); etag_header = ecalloc(1, sizeof("ETag: \"\"") + etag_len); sprintf(etag_header, "ETag: \"%s\"", etag); @@ -202,10 +221,8 @@ PHP_HTTP_API STATUS _http_send_content_type(const char *content_type, size_t ct_ } /* remember for multiple ranges */ - if (HTTP_G(ctype)) { - efree(HTTP_G(ctype)); - } - HTTP_G(ctype) = estrndup(content_type, ct_len); + STR_FREE(HTTP_G(send).content_type); + HTTP_G(send).content_type = estrndup(content_type, ct_len); ct_header = ecalloc(1, sizeof("Content-Type: ") + ct_len); sprintf(ct_header, "Content-Type: %s", content_type); @@ -248,6 +265,7 @@ PHP_HTTP_API STATUS _http_send_ranges(HashTable *ranges, const void *data, size_ if (SUCCESS != zend_hash_index_find(ranges, 0, (void **) &zrange) || SUCCESS != zend_hash_index_find(Z_ARRVAL_PP(zrange), 0, (void **) &begin) || SUCCESS != zend_hash_index_find(Z_ARRVAL_PP(zrange), 1, (void **) &end)) { + http_send_status(500); return FAILURE; } @@ -290,20 +308,20 @@ PHP_HTTP_API STATUS _http_send_ranges(HashTable *ranges, const void *data, size_ HTTP_CRLF, bound, - HTTP_G(ctype) ? HTTP_G(ctype) : "application/x-octetstream", + HTTP_G(send).content_type ? HTTP_G(send).content_type : "application/x-octetstream", **begin, **end, size ); - php_body_write(preface, strlen(preface) TSRMLS_CC); + PHPWRITE(preface, strlen(preface)); http_send_chunk(data, **begin, **end + 1, mode); } /* write boundary once more */ - php_body_write(HTTP_CRLF, sizeof(HTTP_CRLF) - 1 TSRMLS_CC); - php_body_write(bound, strlen(bound) TSRMLS_CC); - php_body_write("--", 2 TSRMLS_CC); + PHPWRITE(HTTP_CRLF, lenof(HTTP_CRLF)); + PHPWRITE(bound, strlen(bound)); + PHPWRITE("--", lenof("--")); return SUCCESS; } @@ -325,9 +343,9 @@ PHP_HTTP_API STATUS _http_send(const void *data_ptr, size_t data_size, http_send } /* stop on-the-fly etag generation */ - if (cache_etag = HTTP_G(etag_started)) { + if (cache_etag = HTTP_G(etag).started) { /* interrupt ob_etaghandler */ - HTTP_G(etag_started) = 0; + HTTP_G(etag).started = 0; } /* enable partial dl and resume */ @@ -344,8 +362,8 @@ PHP_HTTP_API STATUS _http_send(const void *data_ptr, size_t data_size, http_send /* Range Request - only send ranges if entity hasn't changed */ if ( range_status == RANGE_OK && - http_match_etag_ex("HTTP_IF_MATCH", HTTP_G(etag), 0) && - http_match_last_modified_ex("HTTP_IF_UNMODIFIED_SINCE", HTTP_G(lmod), 0)) { + http_match_etag_ex("HTTP_IF_MATCH", HTTP_G(send).unquoted_etag, 0) && + http_match_last_modified_ex("HTTP_IF_UNMODIFIED_SINCE", HTTP_G(send).last_modified, 0)) { STATUS result = http_send_ranges(&ranges, data_ptr, data_size, data_mode); zend_hash_destroy(&ranges); return result; @@ -353,26 +371,24 @@ PHP_HTTP_API STATUS _http_send(const void *data_ptr, size_t data_size, http_send zend_hash_destroy(&ranges); - /* send 304 Not Modified if etag matches */ + /* send 304 Not Modified if etag matches - DON'T return on ETag generation failure */ if (cache_etag) { char *etag = NULL; if (!(etag = http_etag(data_ptr, data_size, data_mode))) { - return FAILURE; - } - if (SUCCESS != http_send_etag(etag, 32)) { + http_error(E_NOTICE, HTTP_E_PARAM, "Failed to generate ETag for data source"); + } else { + http_send_etag(etag, 32); + if (http_match_etag("HTTP_IF_NONE_MATCH", etag)) { + return http_cache_exit_ex(etag, 1, 1); + } efree(etag); - return FAILURE; - } - if (http_match_etag("HTTP_IF_NONE_MATCH", etag)) { - return http_cache_exit_ex(etag, 1, 1); } - efree(etag); } /* send 304 Not Modified if last modified matches */ - if (http_match_last_modified("HTTP_IF_MODIFIED_SINCE", HTTP_G(lmod))) { - return http_cache_exit_ex(http_date(HTTP_G(lmod)), 0, 1); + if (http_match_last_modified("HTTP_IF_MODIFIED_SINCE", HTTP_G(send).last_modified)) { + return http_cache_exit_ex(http_date(HTTP_G(send).last_modified), 0, 1); } /* send full entity */ @@ -384,12 +400,13 @@ PHP_HTTP_API STATUS _http_send(const void *data_ptr, size_t data_size, http_send PHP_HTTP_API STATUS _http_send_stream_ex(php_stream *file, zend_bool close_stream TSRMLS_DC) { STATUS status; + php_stream_statbuf ssb; - if ((!file) || php_stream_stat(file, &HTTP_G(ssb))) { + if ((!file) || php_stream_stat(file, &ssb)) { return FAILURE; } - status = http_send(file, HTTP_G(ssb).sb.st_size, SEND_RSRC); + status = http_send(file, ssb.sb.st_size, SEND_RSRC); if (close_stream) { php_stream_close(file); @@ -399,7 +416,6 @@ PHP_HTTP_API STATUS _http_send_stream_ex(php_stream *file, zend_bool close_strea } /* }}} */ - /* * Local variables: * tab-width: 4 diff --git a/missing.c b/missing.c new file mode 100644 index 0000000..bbc4b3a --- /dev/null +++ b/missing.c @@ -0,0 +1,38 @@ + +#include "php.h" +#include "missing.h" + +int zend_declare_property_double(zend_class_entry *ce, char *name, int name_length, double value, int access_type TSRMLS_DC) +{ + zval *property; + + if (ce->type & ZEND_INTERNAL_CLASS) { + property = malloc(sizeof(zval)); + } else { + ALLOC_ZVAL(property); + } + INIT_PZVAL(property); + ZVAL_DOUBLE(property, value); + return zend_declare_property(ce, name, name_length, property, access_type TSRMLS_CC); +} + +void zend_update_property_double(zend_class_entry *scope, zval *object, char *name, int name_length, double value TSRMLS_DC) +{ + zval *tmp; + + ALLOC_ZVAL(tmp); + tmp->is_ref = 0; + tmp->refcount = 0; + ZVAL_DOUBLE(tmp, value); + zend_update_property(scope, object, name, name_length, tmp TSRMLS_CC); +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/missing.h b/missing.h new file mode 100644 index 0000000..b5f822e --- /dev/null +++ b/missing.h @@ -0,0 +1,18 @@ + +#ifndef PHP_HTTP_MISSING +#define PHP_HTTP_MISSING + +extern int zend_declare_property_double(zend_class_entry *ce, char *name, int name_length, double value, int access_type TSRMLS_DC); +extern void zend_update_property_double(zend_class_entry *scope, zval *object, char *name, int name_length, double value TSRMLS_DC); + +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/package.xml b/package.xml index 5e8ebd1..6791580 100644 --- a/package.xml +++ b/package.xml @@ -1,95 +1,96 @@ - - - - pecl_http - Extended HTTP support - - - - PHP License 3.0 - - - - mike - Michael Wallner - mike@php.net - lead - - - - - 0.8.0dev - 2005-05-00 - beta - - - - - - - CREDITS - EXPERIMENTAL - docs/functions.html - - http.dsp - config.w32 - config.m4 - - phpstr/phpstr.h - phpstr/phpstr.c - - php_http.h - php_http_std_defs.h - php_http_api.h - php_http_auth_api.h - php_http_cache_api.h - php_http_date_api.h - php_http_headers_api.h - php_http_message_api.h - php_http_request_api.h - php_http_send_api.h - php_http_url_api.h - php_http_util_object.h - php_http_message_object.h - php_http_request_object.h - php_http_response_object.h - php_http_exception_object.h - - http.c - http_functions.c - http_methods.c - http_api.c - http_auth_api.c - http_cache_api.c - http_date_api.c - http_headers_api.c - http_message_api.c - http_request_api.c - http_send_api.c - http_url_api.c - http_util_object.c - http_message_object.c - http_request_object.c - http_response_object.c - http_exception_object.c - - - - - + + + + pecl_http + Extended HTTP support + + + + PHP License 3.0 + + + + mike + Michael Wallner + mike@php.net + lead + + + + + 0.8.0dev + 2005-05-00 + beta + + + + + + + CREDITS + EXPERIMENTAL + docs/functions.html + + http.dsp + config.w32 + config.m4 + + phpstr/phpstr.h + phpstr/phpstr.c + + php_http.h + php_http_std_defs.h + php_http_api.h + php_http_auth_api.h + php_http_cache_api.h + php_http_date_api.h + php_http_headers_api.h + php_http_message_api.h + php_http_request_api.h + php_http_send_api.h + php_http_url_api.h + php_http_util_object.h + php_http_message_object.h + php_http_request_object.h + php_http_response_object.h + php_http_exception_object.h + + http.c + http_functions.c + http_methods.c + http_api.c + http_auth_api.c + http_cache_api.c + http_date_api.c + http_headers_api.c + http_message_api.c + http_request_api.c + http_send_api.c + http_url_api.c + http_util_object.c + http_message_object.c + http_request_object.c + http_response_object.c + http_exception_object.c + + + + + diff --git a/php_http.h b/php_http.h index 952639c..9b9b1e7 100644 --- a/php_http.h +++ b/php_http.h @@ -34,29 +34,51 @@ extern zend_module_entry http_module_entry; #define phpext_http_ptr &http_module_entry ZEND_BEGIN_MODULE_GLOBALS(http) - zend_bool etag_started; - PHP_MD5_CTX etag_md5; - php_stream_statbuf ssb; - char *ctype; - char *etag; - time_t lmod; - char *allowed_methods; - char *cache_log; + + struct _http_globals_etag { + zend_bool started; + PHP_MD5_CTX md5ctx; + } etag; + + struct _http_globals_log { + char *cache; + } log; + + struct _http_globals_send { + double throttle_delay; + size_t buffer_size; + char *content_type; + char *unquoted_etag; + time_t last_modified; + } send; + + struct _http_globals_request { + struct _http_globals_request_methods { + char *allowed; + HashTable custom; + } methods; #ifdef HTTP_HAVE_CURL + struct _http_globals_request_curl { + zend_llist copies; # if LIBCURL_VERSION_NUM < 0x070c00 - char curlerr[CURL_ERROR_SIZE + 1]; + char error[CURL_ERROR_SIZE + 1]; # endif - zend_llist to_free; + } curl; #endif /* HTTP_HAVE_CURL */ + } request; + ZEND_END_MODULE_GLOBALS(http) #ifdef ZTS # include "TSRM.h" # define HTTP_G(v) TSRMG(http_globals_id, zend_http_globals *, v) +# define HTTP_GLOBALS ((zend_http_globals *) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(http_globals_id)]) #else # define HTTP_G(v) (http_globals.v) +# define HTTP_GLOBALS http_globals #endif +#define getGlobals(G) zend_http_globals *G = HTTP_GLOBALS; PHP_FUNCTION(http_test); PHP_FUNCTION(http_date); @@ -64,6 +86,7 @@ PHP_FUNCTION(http_absolute_uri); PHP_FUNCTION(http_negotiate_language); PHP_FUNCTION(http_negotiate_charset); PHP_FUNCTION(http_redirect); +PHP_FUNCTION(http_throttle); PHP_FUNCTION(http_send_status); PHP_FUNCTION(http_send_last_modified); PHP_FUNCTION(http_send_content_type); @@ -86,6 +109,11 @@ PHP_FUNCTION(http_post_data); PHP_FUNCTION(http_post_fields); PHP_FUNCTION(http_put_file); PHP_FUNCTION(http_put_stream); +/*PHP_FUNCTION(http_request)*/ +PHP_FUNCTION(http_request_method_register); +PHP_FUNCTION(http_request_method_unregister); +PHP_FUNCTION(http_request_method_exists); +PHP_FUNCTION(http_request_method_name); #endif /* HTTP_HAVE_CURL */ PHP_FUNCTION(http_auth_basic); PHP_FUNCTION(http_auth_basic_cb); diff --git a/php_http_exception_object.h b/php_http_exception_object.h index e89c576..f309035 100644 --- a/php_http_exception_object.h +++ b/php_http_exception_object.h @@ -22,12 +22,15 @@ extern zend_class_entry *http_exception_object_ce; extern zend_function_entry http_exception_object_fe[]; -#define http_exception_object_init _http_exception_object_init +#define http_exception_object_init() _http_exception_object_init(INIT_FUNC_ARGS_PASSTHRU) extern void _http_exception_object_init(INIT_FUNC_ARGS); #define http_exception_get_default _http_exception_get_default extern zend_class_entry *_http_exception_get_default(); +#define http_exception_get_for_code(c) _http_exception_get_for_code(c) +extern zend_class_entry *_http_exception_get_for_code(long code); + #endif #endif diff --git a/php_http_message_api.h b/php_http_message_api.h index d529a0a..731e170 100644 --- a/php_http_message_api.h +++ b/php_http_message_api.h @@ -77,6 +77,9 @@ PHP_HTTP_API void _http_message_serialize(http_message *message, char **string, #define http_message_send(m) _http_message_send((m) TSRMLS_CC) PHP_HTTP_API STATUS _http_message_send(http_message *message TSRMLS_DC); +#define http_message_dup(m) _http_message_dup((m) TSRMLS_CC) +PHP_HTTP_API http_message *_http_message_dup(http_message *msg TSRMLS_DC); + #define http_message_dtor(m) _http_message_dtor((m)) PHP_HTTP_API void _http_message_dtor(http_message *message); diff --git a/php_http_message_object.h b/php_http_message_object.h index fb7a5bc..b3d4c14 100644 --- a/php_http_message_object.h +++ b/php_http_message_object.h @@ -30,13 +30,15 @@ typedef struct { extern zend_class_entry *http_message_object_ce; extern zend_function_entry http_message_object_fe[]; -#define http_message_object_init _http_message_object_init +#define http_message_object_init() _http_message_object_init(INIT_FUNC_ARGS_PASSTHRU) extern void _http_message_object_init(INIT_FUNC_ARGS); #define http_message_object_new _http_message_object_new extern zend_object_value _http_message_object_new(zend_class_entry *ce TSRMLS_DC); #define http_message_object_new_ex(ce, msg) _http_message_object_new_ex(ce, msg TSRMLS_CC) #define http_message_object_from_msg(msg) _http_message_object_new_ex(http_message_object_ce, msg TSRMLS_CC) extern zend_object_value _http_message_object_new_ex(zend_class_entry *ce, http_message *msg TSRMLS_DC); +#define http_message_object_clone(zobj) _http_message_object_clone(zobj TSRMLS_CC) +extern zend_object_value _http_message_object_clone(zval *object TSRMLS_DC); #define http_message_object_free _http_message_object_free extern void _http_message_object_free(zend_object *object TSRMLS_DC); diff --git a/php_http_request_api.h b/php_http_request_api.h index 269ef7b..bee4e70 100644 --- a/php_http_request_api.h +++ b/php_http_request_api.h @@ -63,6 +63,9 @@ typedef enum { HTTP_MAX_REQUEST_METHOD = 28 } http_request_method; +#define HTTP_STD_REQUEST_METHOD(m) ((m > HTTP_NO_REQUEST_METHOD) && (m < HTTP_MAX_REQUEST_METHOD)) +#define HTTP_CUSTOM_REQUEST_METHOD(m) (m - HTTP_MAX_REQUEST_METHOD) + #define HTTP_REQUEST_BODY_CSTRING 0 #define HTTP_REQUEST_BODY_CURLPOST 1 #define HTTP_REQUEST_BODY_UPLOADFILE 2 @@ -73,8 +76,17 @@ typedef struct { size_t size; } http_request_body; -#define http_request_method_string(m) _http_request_method((m)) -PHP_HTTP_API const char *_http_request_method_string(http_request_method m); +#define http_request_method_name(m) _http_request_method_name((m) TSRMLS_CC) +PHP_HTTP_API const char *_http_request_method_name(http_request_method m TSRMLS_DC); + +#define http_request_method_exists(u, l, c) _http_request_method_exists((u), (l), (c) TSRMLS_CC) +PHP_HTTP_API unsigned long _http_request_method_exists(zend_bool by_name, unsigned long id, const char *name TSRMLS_DC); + +#define http_request_method_register(m) _http_request_method_register((m) TSRMLS_CC) +PHP_HTTP_API unsigned long _http_request_method_register(const char *method TSRMLS_DC); + +#define http_request_method_unregister(mn) _http_request_method_unregister((mn) TSRMLS_CC) +PHP_HTTP_API STATUS _http_request_method_unregister(unsigned long method TSRMLS_DC); #define http_request_body_fill(b, fields, files) _http_request_body_fill((b), (fields), (files) TSRMLS_CC) PHP_HTTP_API STATUS _http_request_body_fill(http_request_body *body, HashTable *fields, HashTable *files TSRMLS_DC); diff --git a/php_http_request_object.h b/php_http_request_object.h index 3f87a17..6755669 100644 --- a/php_http_request_object.h +++ b/php_http_request_object.h @@ -37,7 +37,7 @@ typedef struct { extern zend_class_entry *http_request_object_ce; extern zend_function_entry http_request_object_fe[]; -#define http_request_object_init _http_request_object_init +#define http_request_object_init() _http_request_object_init(INIT_FUNC_ARGS_PASSTHRU) extern void _http_request_object_init(INIT_FUNC_ARGS); #define http_request_object_new _http_request_object_new extern zend_object_value _http_request_object_new(zend_class_entry *ce TSRMLS_DC); diff --git a/php_http_response_object.h b/php_http_response_object.h index 9767b5a..6484ac9 100644 --- a/php_http_response_object.h +++ b/php_http_response_object.h @@ -26,7 +26,7 @@ typedef struct { extern zend_class_entry *http_response_object_ce; extern zend_function_entry http_response_object_fe[]; -#define http_response_object_init _http_response_object_init +#define http_response_object_init() _http_response_object_init(INIT_FUNC_ARGS_PASSTHRU) extern void _http_response_object_init(INIT_FUNC_ARGS); #define http_response_object_new _http_response_object_new extern zend_object_value _http_response_object_new(zend_class_entry *ce TSRMLS_DC); @@ -46,6 +46,10 @@ PHP_METHOD(HttpResponse, setCacheControl); PHP_METHOD(HttpResponse, getCacheControl); PHP_METHOD(HttpResponse, setGzip); PHP_METHOD(HttpResponse, getGzip); +PHP_METHOD(HttpResponse, setThrottleDelay); +PHP_METHOD(HttpResponse, getThrottleDelay); +PHP_METHOD(HttpResponse, setSendBuffersize); +PHP_METHOD(HttpResponse, getSendBuffersize); PHP_METHOD(HttpResponse, setData); PHP_METHOD(HttpResponse, getData); PHP_METHOD(HttpResponse, setFile); diff --git a/php_http_send_api.h b/php_http_send_api.h index 5212915..c9de4d4 100644 --- a/php_http_send_api.h +++ b/php_http_send_api.h @@ -29,8 +29,10 @@ typedef enum { #define http_send_status(s) sapi_header_op(SAPI_HEADER_SET_STATUS, (void *) (s) TSRMLS_CC) #define http_send_header(h) http_send_status_header(0, (h)) -#define http_send_status_header(s, h) _http_send_status_header((s), (h) TSRMLS_CC) -PHP_HTTP_API STATUS _http_send_status_header(int status, const char *header TSRMLS_DC); +#define http_send_header_ex(h, r) http_send_status_header_ex(0, (h), (r)) +#define http_send_status_header(s, h) _http_send_status_header_ex((s), (h), 1 TSRMLS_CC) +#define http_send_status_header_ex(s, h, r) _http_send_status_header_ex((s), (h), (r) TSRMLS_CC) +PHP_HTTP_API STATUS _http_send_status_header_ex(int status, const char *header, zend_bool replace TSRMLS_DC); #define http_send_last_modified(t) _http_send_last_modified((t) TSRMLS_CC) PHP_HTTP_API STATUS _http_send_last_modified(time_t t TSRMLS_DC); diff --git a/php_http_std_defs.h b/php_http_std_defs.h index ab80130..4d36587 100644 --- a/php_http_std_defs.h +++ b/php_http_std_defs.h @@ -36,6 +36,11 @@ typedef int STATUS; /* lenof() */ #define lenof(S) (sizeof(S) - 1) +/* STR_SET() */ +#define STR_SET(target, source) \ + if(target) efree(target); \ + target = source + /* return bool (v == SUCCESS) */ #define RETVAL_SUCCESS(v) RETVAL_BOOL(SUCCESS == (v)) #define RETURN_SUCCESS(v) RETURN_BOOL(SUCCESS == (v)) @@ -63,6 +68,12 @@ typedef int STATUS; zend_error(E_NOTICE, "Wrong parameter count for %s()", get_active_function_name(TSRMLS_C)); \ } +/* check if return value is used */ +#define IF_RETVAL_USED \ + if (!return_value_used) { \ + return; \ + } else + /* CR LF */ #define HTTP_CRLF "\r\n" @@ -100,8 +111,8 @@ typedef int STATUS; /* server vars shorthand */ #define HTTP_SERVER_VARS Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]) -#define HTTP_INI_ENTRY(entry, default, scope, global) \ - STD_PHP_INI_ENTRY(entry, default, scope, http_update_##global, global, zend_http_globals, http_globals) +#define HTTP_PHP_INI_ENTRY(entry, default, scope, updater, global) \ + STD_PHP_INI_ENTRY(entry, default, scope, updater, global, zend_http_globals, http_globals) /* {{{ arrays */ #define FOREACH_VAL(array, val) FOREACH_HASH_VAL(Z_ARRVAL_P(array), val) diff --git a/php_http_util_object.h b/php_http_util_object.h index 08f42b6..b4aaf04 100644 --- a/php_http_util_object.h +++ b/php_http_util_object.h @@ -22,7 +22,7 @@ extern zend_class_entry *http_util_object_ce; extern zend_function_entry http_util_object_fe[]; -#define http_util_object_init _http_util_object_init +#define http_util_object_init() _http_util_object_init(INIT_FUNC_ARGS_PASSTHRU) extern void _http_util_object_init(INIT_FUNC_ARGS); PHP_METHOD(HttpUtil, date);