From cf9967800843ea01e77b374b4d78fad4bc18a3f6 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Wed, 13 Apr 2005 13:37:09 +0000 Subject: [PATCH] - use custom error function - smarter response handling for http_request using http_message --- http_cache_api.c | 6 +- http_curl_api.c | 117 +++++++++++++++----------------------- http_functions.c | 58 ++++++++++--------- http_headers_api.c | 5 +- http_methods.c | 108 +++++++++++++++++++++-------------- http_request_object.c | 7 ++- http_send_api.c | 32 ++++------- http_url_api.c | 11 ++-- php_http_curl_api.h | 31 +++++----- php_http_request_object.h | 4 ++ 10 files changed, 189 insertions(+), 190 deletions(-) diff --git a/http_cache_api.c b/http_cache_api.c index 8df1ada..7d61040 100644 --- a/http_cache_api.c +++ b/http_cache_api.c @@ -157,7 +157,7 @@ PHP_HTTP_API STATUS _http_cache_last_modified(time_t last_modified, if (SUCCESS == http_send_status(304)) { zend_bailout(); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not send 304 Not Modified"); + http_error(E_WARNING, HTTP_E_HEADER, "Could not send 304 Not Modified"); return FAILURE; } } @@ -179,7 +179,7 @@ PHP_HTTP_API STATUS _http_cache_etag(const char *etag, size_t etag_len, if (SUCCESS == http_send_status(304)) { zend_bailout(); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not send 304 Not Modified"); + http_error(E_WARNING, HTTP_E_HEADER, "Could not send 304 Not Modified"); return FAILURE; } } @@ -191,7 +191,7 @@ PHP_HTTP_API STATUS _http_cache_etag(const char *etag, size_t etag_len, HTTP_G(etag_started) = 1; return SUCCESS; } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not start ob_etaghandler"); + http_error(E_WARNING, HTTP_E_OBUFFER, "Could not start ob_etaghandler"); return FAILURE; } } diff --git a/http_curl_api.c b/http_curl_api.c index b576b2f..2df24e5 100644 --- a/http_curl_api.c +++ b/http_curl_api.c @@ -49,52 +49,48 @@ ZEND_EXTERN_MODULE_GLOBALS(http) # define http_curl_error(code) curl_easy_strerror(code) #endif -#define http_curl_startup(ch, clean_curl, URL, options) \ +#define http_curl_startup(ch, clean_curl, URL, options, response) \ if (!ch) { \ if (!(ch = curl_easy_init())) { \ - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not initialize curl"); \ + http_error(E_WARNING, HTTP_E_CURL, "Could not initialize curl"); \ return FAILURE; \ } \ clean_curl = 1; \ } else { \ http_curl_reset(ch); \ } \ - http_curl_setopts(ch, URL, options); + http_curl_setopts(ch, URL, options, response); -#define http_curl_perform(ch, clean_curl) \ +#define http_curl_perform(ch, clean_curl, response) \ { \ CURLcode result; \ if (CURLE_OK != (result = curl_easy_perform(ch))) { \ - http_curl_cleanup(ch, clean_curl); \ - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not perform request: %s", curl_easy_strerror(result)); \ + http_error_ex(E_WARNING, HTTP_E_CURL, "Could not perform request: %s", curl_easy_strerror(result)); \ + http_curl_cleanup(ch, clean_curl, response); \ return FAILURE; \ } \ } -#define http_curl_cleanup(ch, clean_curl) \ - phpstr_dtor(&HTTP_G(curlbuf)); \ +#define http_curl_cleanup(ch, clean_curl, response) \ zend_llist_clean(&HTTP_G(to_free)); \ if (clean_curl) { \ curl_easy_cleanup(ch); \ ch = NULL; \ - } - -#define http_curl_copybuf(d, l) \ - phpstr_data(&HTTP_G(curlbuf), d, l) + } \ + phpstr_fix(PHPSTR(response)) #define http_curl_copystr(s) _http_curl_copystr((s) TSRMLS_CC) static inline char *_http_curl_copystr(const char *str TSRMLS_DC); -#define http_curl_setopts(c, u, o) _http_curl_setopts((c), (u), (o) TSRMLS_CC) -static void _http_curl_setopts(CURL *ch, const char *url, HashTable *options TSRMLS_DC); +#define http_curl_setopts(c, u, o, r) _http_curl_setopts((c), (u), (o), (r) TSRMLS_CC) +static void _http_curl_setopts(CURL *ch, const char *url, HashTable *options, phpstr *response TSRMLS_DC); #define http_curl_getopt(o, k) _http_curl_getopt((o), (k) TSRMLS_CC, 0) #define http_curl_getopt1(o, k, t1) _http_curl_getopt((o), (k) TSRMLS_CC, 1, (t1)) #define http_curl_getopt2(o, k, t1, t2) _http_curl_getopt((o), (k) TSRMLS_CC, 2, (t1), (t2)) static inline zval *_http_curl_getopt(HashTable *options, char *key TSRMLS_DC, int checks, ...); -static size_t http_curl_body_callback(char *, size_t, size_t, void *); -static size_t http_curl_hdrs_callback(char *, size_t, size_t, void *); +static size_t http_curl_callback(char *, size_t, size_t, void *); #define http_curl_getinfo(c, h) _http_curl_getinfo((c), (h) TSRMLS_CC) static inline void _http_curl_getinfo(CURL *ch, HashTable *info TSRMLS_DC); @@ -108,25 +104,10 @@ static inline char *_http_curl_copystr(const char *str TSRMLS_DC) } /* }}} */ -/* {{{ static size_t http_curl_body_callback(char *, size_t, size_t, void *) */ -static size_t http_curl_body_callback(char *buf, size_t len, size_t n, void *s) -{ - TSRMLS_FETCH(); - phpstr_append(&HTTP_G(curlbuf), buf, len *= n); - return len; -} -/* }}} */ - -/* {{{ static size_t http_curl_hdrs_callback(char *, size_t, size_t, void *) */ -static size_t http_curl_hdrs_callback(char *buf, size_t len, size_t n, void *s) +/* {{{ static size_t http_curl_callback(char *, size_t, size_t, void *) */ +static size_t http_curl_callback(char *buf, size_t len, size_t n, void *s) { - TSRMLS_FETCH(); - - /* discard previous headers */ - if (HTTP_G(curlbuf).used && (!strncmp(buf, "HTTP/1.", sizeof("HTTP/1.") - 1))) { - phpstr_free(&HTTP_G(curlbuf)); - } - phpstr_append(&HTTP_G(curlbuf), buf, len *= n); + phpstr_append(PHPSTR(s), buf, len *= n); return len; } /* }}} */ @@ -157,8 +138,8 @@ static inline zval *_http_curl_getopt(HashTable *options, char *key TSRMLS_DC, i } /* }}} */ -/* {{{ static void http_curl_setopts(CURL *, char *, HashTable *) */ -static void _http_curl_setopts(CURL *ch, const char *url, HashTable *options TSRMLS_DC) +/* {{{ static void http_curl_setopts(CURL *, char *, HashTable *, phpstr *) */ +static void _http_curl_setopts(CURL *ch, const char *url, HashTable *options, phpstr *response TSRMLS_DC) { zval *zoption; zend_bool range_req = 0; @@ -171,8 +152,10 @@ static void _http_curl_setopts(CURL *ch, const char *url, HashTable *options TSR HTTP_CURL_OPT(FILETIME, 1); HTTP_CURL_OPT(NOPROGRESS, 1); HTTP_CURL_OPT(AUTOREFERER, 1); - HTTP_CURL_OPT(WRITEFUNCTION, http_curl_body_callback); - HTTP_CURL_OPT(HEADERFUNCTION, http_curl_hdrs_callback); + HTTP_CURL_OPT(WRITEFUNCTION, http_curl_callback); + HTTP_CURL_OPT(HEADERFUNCTION, http_curl_callback); + HTTP_CURL_OPT(WRITEDATA, response); + HTTP_CURL_OPT(WRITEHEADER, response); #if defined(ZTS) && (LIBCURL_VERSION_NUM >= 0x070a00) HTTP_CURL_OPT(NOSIGNAL, 1); #endif @@ -496,108 +479,100 @@ static inline void _http_curl_getinfo(CURL *ch, HashTable *info TSRMLS_DC) } /* }}} */ -/* {{{ STATUS http_get_ex(CURL *, char *, HashTable *, HashTable *, char **, size_t *) */ -PHP_HTTP_API STATUS _http_get_ex(CURL *ch, const char *URL, HashTable *options, - HashTable *info, char **data, size_t *data_len TSRMLS_DC) +/* {{{ STATUS http_get_ex(CURL *, char *, HashTable *, HashTable *, phpstr *) */ +PHP_HTTP_API STATUS _http_get_ex(CURL *ch, const char *URL, HashTable *options, HashTable *info, phpstr *response TSRMLS_DC) { zend_bool clean_curl = 0; - http_curl_startup(ch, clean_curl, URL, options); + http_curl_startup(ch, clean_curl, URL, options, response); curl_easy_setopt(ch, CURLOPT_HTTPGET, 1); - http_curl_perform(ch, clean_curl); + http_curl_perform(ch, clean_curl, response); if (info) { http_curl_getinfo(ch, info); } - http_curl_copybuf(data, data_len); - http_curl_cleanup(ch, clean_curl); + http_curl_cleanup(ch, clean_curl, response); return SUCCESS; } -/* {{{ STATUS http_head_ex(CURL *, char *, HashTable *, HashTable *, char **data, size_t *) */ -PHP_HTTP_API STATUS _http_head_ex(CURL *ch, const char *URL, HashTable *options, - HashTable *info, char **data, size_t *data_len TSRMLS_DC) +/* {{{ STATUS http_head_ex(CURL *, char *, HashTable *, HashTable *, phpstr *) */ +PHP_HTTP_API STATUS _http_head_ex(CURL *ch, const char *URL, HashTable *options,HashTable *info, phpstr *response TSRMLS_DC) { zend_bool clean_curl = 0; - http_curl_startup(ch, clean_curl, URL, options); + http_curl_startup(ch, clean_curl, URL, options, response); curl_easy_setopt(ch, CURLOPT_NOBODY, 1); - http_curl_perform(ch, clean_curl); + http_curl_perform(ch, clean_curl, response); if (info) { http_curl_getinfo(ch, info); } - http_curl_copybuf(data, data_len); - http_curl_cleanup(ch, clean_curl); + http_curl_cleanup(ch, clean_curl, response); return SUCCESS; } -/* {{{ STATUS http_post_data_ex(CURL *, char *, char *, size_t, HashTable *, HashTable *, char **, size_t *) */ +/* {{{ STATUS http_post_data_ex(CURL *, char *, char *, size_t, HashTable *, HashTable *, phpstr *) */ PHP_HTTP_API STATUS _http_post_data_ex(CURL *ch, const char *URL, char *postdata, - size_t postdata_len, HashTable *options, HashTable *info, char **data, - size_t *data_len TSRMLS_DC) + size_t postdata_len, HashTable *options, HashTable *info, phpstr *response TSRMLS_DC) { zend_bool clean_curl = 0; - http_curl_startup(ch, clean_curl, URL, options); + http_curl_startup(ch, clean_curl, URL, options, response); curl_easy_setopt(ch, CURLOPT_POST, 1); curl_easy_setopt(ch, CURLOPT_POSTFIELDS, postdata); curl_easy_setopt(ch, CURLOPT_POSTFIELDSIZE, postdata_len); - http_curl_perform(ch, clean_curl); + http_curl_perform(ch, clean_curl, response); if (info) { http_curl_getinfo(ch, info); } - http_curl_copybuf(data, data_len); - http_curl_cleanup(ch, clean_curl); + http_curl_cleanup(ch, clean_curl, response); return SUCCESS; } /* }}} */ -/* {{{ STATUS http_post_array_ex(CURL *, char *, HashTable *, HashTable *, HashTable *, char **, size_t *) */ +/* {{{ STATUS http_post_array_ex(CURL *, char *, HashTable *, HashTable *, HashTable *, phpstr *) */ PHP_HTTP_API STATUS _http_post_array_ex(CURL *ch, const char *URL, HashTable *postarray, - HashTable *options, HashTable *info, char **data, size_t *data_len TSRMLS_DC) + HashTable *options, HashTable *info, phpstr *response TSRMLS_DC) { STATUS status; char *encoded; size_t encoded_len; if (SUCCESS != http_urlencode_hash_ex(postarray, 1, NULL, 0, &encoded, &encoded_len)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not encode post data"); + http_error(E_WARNING, HTTP_E_ENCODE, "Could not encode post data"); return FAILURE; } - status = http_post_data_ex(ch, URL, encoded, encoded_len, options, info, data, data_len); + status = http_post_data_ex(ch, URL, encoded, encoded_len, options, info, response); efree(encoded); return status; } /* }}} */ -/* {{{ STATUS http_post_curldata_ex(CURL *, char *, curl_httppost *, HashTable *, HashTable *, char **, size_t *) */ -PHP_HTTP_API STATUS _http_post_curldata_ex(CURL *ch, const char *URL, - struct curl_httppost *curldata, HashTable *options, HashTable *info, - char **data, size_t *data_len TSRMLS_DC) +/* {{{ STATUS http_post_curldata_ex(CURL *, char *, curl_httppost *, HashTable *, HashTable *, phpstr *) */ +PHP_HTTP_API STATUS _http_post_curldata_ex(CURL *ch, const char *URL, struct curl_httppost *curldata, + HashTable *options, HashTable *info, phpstr *response TSRMLS_DC) { zend_bool clean_curl = 0; - http_curl_startup(ch, clean_curl, URL, options); + http_curl_startup(ch, clean_curl, URL, options, response); curl_easy_setopt(ch, CURLOPT_POST, 1); curl_easy_setopt(ch, CURLOPT_HTTPPOST, curldata); - http_curl_perform(ch, clean_curl); + http_curl_perform(ch, clean_curl, response); if (info) { http_curl_getinfo(ch, info); } - http_curl_copybuf(data, data_len); - http_curl_cleanup(ch, clean_curl); + http_curl_cleanup(ch, clean_curl, response); return SUCCESS; } diff --git a/http_functions.c b/http_functions.c index 0b39b72..96f3277 100644 --- a/http_functions.c +++ b/http_functions.c @@ -203,7 +203,7 @@ PHP_FUNCTION(http_send_status) RETURN_FALSE; } if (status < 100 || status > 510) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid HTTP status code (100-510): %d", status); + http_error_ex(E_WARNING, HTTP_E_HEADER, "Invalid HTTP status code (100-510): %d", status); RETURN_FALSE; } @@ -410,7 +410,7 @@ PHP_FUNCTION(ob_httpetaghandler) if (mode & PHP_OUTPUT_HANDLER_START) { if (HTTP_G(etag_started)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "ob_httpetaghandler can only be used once"); + http_error(E_WARNING, HTTP_E_OBUFFER, "ob_httpetaghandler can only be used once"); RETURN_STRINGL(data, data_len, 1); } http_send_header("Cache-Control: " HTTP_DEFAULT_CACHECONTROL); @@ -418,7 +418,7 @@ PHP_FUNCTION(ob_httpetaghandler) } if (OG(ob_nesting_level) > 1) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "ob_httpetaghandler must be started prior to other output buffers"); + http_error(E_WARNING, HTTP_E_OBUFFER, "ob_httpetaghandler must be started prior to other output buffers"); RETURN_STRINGL(data, data_len, 1); } @@ -462,7 +462,7 @@ PHP_FUNCTION(http_redirect) array_init(params); } if (add_assoc_string(params, PS(session_name), PS(id), 1) != SUCCESS) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not append session information"); + http_error(E_WARNING, HTTP_E_ENCODE, "Could not append session information"); } } @@ -609,7 +609,7 @@ PHP_FUNCTION(http_split_response) array_init(zheaders); if (SUCCESS != http_split_response(zresponse, zheaders, zbody)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not parse HTTP response"); + http_error(E_WARNING, HTTP_E_PARSE, "Could not parse HTTP response"); RETURN_FALSE; } @@ -637,7 +637,7 @@ PHP_FUNCTION(http_parse_headers) header_len = rnrn - header + 2; } if (SUCCESS != http_parse_headers(header, header_len, return_value)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not parse HTTP headers"); + http_error(E_WARNING, HTTP_E_PARSE, "Could not parse HTTP headers"); zval_dtor(return_value); RETURN_FALSE; } @@ -730,10 +730,10 @@ PHP_FUNCTION(http_get_request_headers) */ PHP_FUNCTION(http_get) { - char *URL, *data = NULL; - size_t data_len = 0; - int URL_len; zval *options = NULL, *info = NULL; + char *URL; + int URL_len; + phpstr response; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a/!z", &URL, &URL_len, &options, &info) != SUCCESS) { RETURN_FALSE; @@ -744,8 +744,9 @@ PHP_FUNCTION(http_get) array_init(info); } - if (SUCCESS == http_get(URL, Z_ARRVAL_P(options), Z_ARRVAL_P(info), &data, &data_len)) { - RETURN_STRINGL(data, data_len, 0); + phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0); + if (SUCCESS == http_get(URL, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) { + RETURN_PHPSTR_VAL(response); } else { RETURN_FALSE; } @@ -760,10 +761,10 @@ PHP_FUNCTION(http_get) */ PHP_FUNCTION(http_head) { - char *URL, *data = NULL; - size_t data_len = 0; - int URL_len; zval *options = NULL, *info = NULL; + char *URL; + int URL_len; + phpstr response; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a/!z", &URL, &URL_len, &options, &info) != SUCCESS) { RETURN_FALSE; @@ -774,8 +775,9 @@ PHP_FUNCTION(http_head) array_init(info); } - if (SUCCESS == http_head(URL, Z_ARRVAL_P(options), Z_ARRVAL_P(info), &data, &data_len)) { - RETURN_STRINGL(data, data_len, 0); + phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0); + if (SUCCESS == http_head(URL, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) { + RETURN_PHPSTR_VAL(response); } else { RETURN_FALSE; } @@ -790,10 +792,10 @@ PHP_FUNCTION(http_head) */ PHP_FUNCTION(http_post_data) { - char *URL, *postdata, *data = NULL; - size_t data_len = 0; - int postdata_len, URL_len; zval *options = NULL, *info = NULL; + char *URL, *postdata; + int postdata_len, URL_len; + phpstr response; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!z", &URL, &URL_len, &postdata, &postdata_len, &options, &info) != SUCCESS) { RETURN_FALSE; @@ -804,8 +806,9 @@ PHP_FUNCTION(http_post_data) array_init(info); } - if (SUCCESS == http_post_data(URL, postdata, (size_t) postdata_len, Z_ARRVAL_P(options), Z_ARRVAL_P(info), &data, &data_len)) { - RETURN_STRINGL(data, data_len, 0); + phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0); + if (SUCCESS == http_post_data(URL, postdata, (size_t) postdata_len, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) { + RETURN_PHPSTR_VAL(response); } else { RETURN_FALSE; } @@ -820,10 +823,10 @@ PHP_FUNCTION(http_post_data) */ PHP_FUNCTION(http_post_array) { - char *URL, *data = NULL; - size_t data_len = 0; - int URL_len; zval *options = NULL, *info = NULL, *postdata; + char *URL; + int URL_len; + phpstr response; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa|a/!z", &URL, &URL_len, &postdata, &options, &info) != SUCCESS) { RETURN_FALSE; @@ -834,8 +837,9 @@ PHP_FUNCTION(http_post_array) array_init(info); } - if (SUCCESS == http_post_array(URL, Z_ARRVAL_P(postdata), Z_ARRVAL_P(options), Z_ARRVAL_P(info), &data, &data_len)) { - RETURN_STRINGL(data, data_len, 0); + phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0); + if (SUCCESS == http_post_array(URL, Z_ARRVAL_P(postdata), options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) { + RETURN_PHPSTR_VAL(response); } else { RETURN_FALSE; } @@ -972,7 +976,7 @@ PHP_FUNCTION(http_build_query) } if (Z_TYPE_P(formdata) != IS_ARRAY && Z_TYPE_P(formdata) != IS_OBJECT) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Parameter 1 expected to be Array or Object. Incorrect value given."); + http_error(E_WARNING, HTTP_E_PARAM, "Parameter 1 expected to be Array or Object. Incorrect value given."); RETURN_FALSE; } diff --git a/http_headers_api.c b/http_headers_api.c index cc4e609..09673e9 100644 --- a/http_headers_api.c +++ b/http_headers_api.c @@ -111,7 +111,7 @@ PHP_HTTP_API http_range_status _http_get_request_ranges(HashTable *ranges, size_ range = Z_STRVAL_P(zrange); if (strncmp(range, "bytes=", sizeof("bytes=") - 1)) { - php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Range header misses bytes="); + http_error(E_NOTICE, HTTP_E_HEADER, "Range header misses bytes="); return RANGE_NO; } @@ -248,7 +248,8 @@ PHP_HTTP_API STATUS _http_parse_headers_ex(char *header, size_t header_len, Z_ARRVAL(array) = headers; - if (header_len < 2) { + if (header_len < 2 || !strchr(header, ':')) { + http_error(E_WARNING, HTTP_E_PARSE, "Cannot parse too short or malformed HTTP headers"); return FAILURE; } diff --git a/http_methods.c b/http_methods.c index 23631c5..af7586d 100644 --- a/http_methods.c +++ b/http_methods.c @@ -27,6 +27,7 @@ #include "php_http_curl_api.h" #include "php_http_date_api.h" #include "php_http_headers_api.h" +#include "php_http_message_api.h" #include "php_http_send_api.h" #include "php_http_url_api.h" @@ -152,7 +153,7 @@ PHP_METHOD(HttpResponse, setCacheControl) } if ((!raw) && (strcmp(ccontrol, "public") && strcmp(ccontrol, "private") && strcmp(ccontrol, "no-cache"))) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache-Control '%s' doesn't match public, private or no-cache", ccontrol); + http_error_ex(E_WARNING, HTTP_E_PARAM, "Cache-Control '%s' doesn't match public, private or no-cache", ccontrol); RETURN_FALSE; } @@ -193,8 +194,7 @@ PHP_METHOD(HttpResponse, setContentType) } if (!strchr(ctype, '/')) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, - "Content type '%s' doesn't seem to contain a primary and a secondary part", ctype); + http_error_ex(E_WARNING, HTTP_E_PARAM, "Content type '%s' doesn't seem to contain a primary and a secondary part", ctype); RETURN_FALSE; } @@ -711,7 +711,7 @@ PHP_METHOD(HttpMessage, getHttpVersion) if (Z_TYPE_P(version) == IS_NULL) { RETURN_NULL(); } - + sprintf(ver, "1.1f", Z_DVAL_P(version)); RETURN_STRINGL(ver, 3, 1); } @@ -726,9 +726,9 @@ PHP_METHOD(HttpMessage, toString) char *string; size_t length; getObject(http_message_object, obj); - + NO_ARGS; - + http_message_tostring(obj->message, &string, &length); RETURN_STRINGL(string, length, 0); } @@ -1139,9 +1139,7 @@ PHP_METHOD(HttpRequest, setContentType) } if (!strchr(ctype, '/')) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, - "Content-Type '%s' doesn't seem to contain a primary and a secondary part", - ctype); + http_error_ex(E_WARNING, HTTP_E_PARAM, "Content-Type '%s' doesn't seem to contain a primary and a secondary part", ctype); RETURN_FALSE; } @@ -1352,7 +1350,7 @@ PHP_METHOD(HttpRequest, addPostFile) if (type_len) { if (!strchr(type, '/')) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Content-Type '%s' doesn't seem to contain a primary and a secondary part", type); + http_error_ex(E_WARNING, HTTP_E_PARAM, "Content-Type '%s' doesn't seem to contain a primary and a secondary part", type); RETURN_FALSE; } } else { @@ -1570,19 +1568,13 @@ PHP_METHOD(HttpRequest, getResponseBody) */ PHP_METHOD(HttpRequest, getResponseCode) { - zval **code, **hdrs, *data; + zval *code; getObject(http_request_object, obj); NO_ARGS; - data = GET_PROP(obj, responseData); - if ( (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &hdrs)) && - (SUCCESS == zend_hash_find(Z_ARRVAL_PP(hdrs), "Response Status", sizeof("Response Status"), (void **) &code))) { - RETVAL_STRINGL(Z_STRVAL_PP(code), Z_STRLEN_PP(code), 1); - convert_to_long(return_value); - } else { - RETURN_FALSE; - } + code = GET_PROP(obj, responseCode); + RETURN_LONG(Z_LVAL_P(code)); } /* }}} */ @@ -1608,7 +1600,7 @@ PHP_METHOD(HttpRequest, getResponseInfo) 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 { - php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not find response info named %s", info_name); + http_error_ex(E_NOTICE, HTTP_E_PARAM, "Could not find response info named %s", info_name); RETURN_FALSE; } } else { @@ -1618,6 +1610,24 @@ PHP_METHOD(HttpRequest, getResponseInfo) } /* }}}*/ +/* {{{ proto HttpMessage HttpRequest::getResponseMessage() + * + * Get the full response as HttpMessage object. + */ +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); +} + /* {{{ proto bool HttpRequest::send() * * Send the HTTP request. @@ -1628,8 +1638,13 @@ PHP_METHOD(HttpRequest, getResponseInfo) * $r = new HttpRequest('http://example.com/feed.rss', HTTP_GET); * $r->setOptions(array('lastmodified' => filemtime('local.rss'))); * $r->addQueryData(array('category' => 3)); - * if ($r->send() && $r->getResponseCode() == 200) { - * file_put_contents('local.rss', $r->getResponseBody()); + * try { + * $r->send(); + * if ($r->getResponseCode() == 200) { + * file_put_contents('local.rss', $r->getResponseBody()); + * } + * } catch (HttpException $ex) { + * echo $ex; * } * ?> * @@ -1651,8 +1666,7 @@ PHP_METHOD(HttpRequest, send) { STATUS status = FAILURE; zval *meth, *URL, *qdata, *opts, *info, *resp; - char *response_data, *request_uri; - size_t response_len; + char *request_uri; getObject(http_request_object, obj); NO_ARGS; @@ -1660,7 +1674,7 @@ PHP_METHOD(HttpRequest, send) SET_EH_THROW_HTTP(); if ((!obj->ch) && (!(obj->ch = curl_easy_init()))) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not initilaize cURL"); + http_error(E_WARNING, HTTP_E_CURL, "Could not initilaize curl"); RETURN_FALSE; } @@ -1686,11 +1700,11 @@ PHP_METHOD(HttpRequest, send) switch (Z_LVAL_P(meth)) { case HTTP_GET: - status = http_get_ex(obj->ch, request_uri, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &response_data, &response_len); + status = http_get_ex(obj->ch, request_uri, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response); break; case HTTP_HEAD: - status = http_head_ex(obj->ch, request_uri, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &response_data, &response_len); + status = http_head_ex(obj->ch, request_uri, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response); break; case HTTP_POST: @@ -1703,7 +1717,7 @@ PHP_METHOD(HttpRequest, send) if (!zend_hash_num_elements(Z_ARRVAL_P(post_files))) { /* urlencoded post */ - status = http_post_array_ex(obj->ch, request_uri, Z_ARRVAL_P(post_data), Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &response_data, &response_len); + status = http_post_array_ex(obj->ch, request_uri, Z_ARRVAL_P(post_data), Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response); } else { @@ -1748,7 +1762,7 @@ PHP_METHOD(HttpRequest, send) } } - status = http_post_curldata_ex(obj->ch, request_uri, http_post_data[0], Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &response_data, &response_len); + status = http_post_curldata_ex(obj->ch, request_uri, http_post_data[0], Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response); curl_formfree(http_post_data[0]); } } @@ -1762,26 +1776,32 @@ PHP_METHOD(HttpRequest, send) /* final data handling */ if (status == SUCCESS) { - char *body = NULL; - size_t body_len = 0; - zval *zheaders; + http_message *msg; - MAKE_STD_ZVAL(zheaders) - array_init(zheaders); + if (msg = http_message_parse(PHPSTR_VAL(&obj->response), PHPSTR_LEN(&obj->response))) { + zval *headers, *message; + char *body; + size_t body_len; - if (SUCCESS != http_split_response_ex(response_data, response_len, Z_ARRVAL_P(zheaders), &body, &body_len)) { - zval_dtor(zheaders); - efree(zheaders), - efree(response_data); - RETURN_FALSE; - } + UPD_PROP(obj, long, responseCode, msg->info.response.code); - add_assoc_zval(resp, "headers", zheaders); - add_assoc_stringl(resp, "body", body, body_len, 0); + MAKE_STD_ZVAL(headers) + array_init(headers); - efree(response_data); + zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); + phpstr_data(PHPSTR(msg), &body, &body_len); - RETURN_TRUE; + add_assoc_zval(resp, "headers", headers); + add_assoc_stringl(resp, "body", body, body_len, 0); + + message = GET_PROP(obj, responseMessage); + zval_dtor(message); + Z_TYPE_P(message) = IS_OBJECT; + message->value.obj = http_message_object_from_msg(msg); + SET_PROP(obj, responseMessage, message); + } else { + status = FAILURE; + } } SET_EH_NORMAL(); diff --git a/http_request_object.c b/http_request_object.c index 5887bf2..64a76ef 100644 --- a/http_request_object.c +++ b/http_request_object.c @@ -88,6 +88,7 @@ zend_function_entry http_request_object_fe[] = { PHP_ME(HttpRequest, getResponseCode, NULL, ZEND_ACC_PUBLIC) PHP_ME(HttpRequest, getResponseBody, NULL, ZEND_ACC_PUBLIC) PHP_ME(HttpRequest, getResponseInfo, NULL, ZEND_ACC_PUBLIC) + PHP_ME(HttpRequest, getResponseMessage, NULL, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; @@ -115,6 +116,8 @@ zend_object_value _http_request_object_new(zend_class_entry *ce TSRMLS_DC) o->zo.ce = ce; o->ch = curl_easy_init(); + phpstr_init_ex(&o->response, HTTP_CURLBUF_SIZE, 0); + ALLOC_HASHTABLE(OBJ_PROP(o)); zend_hash_init(OBJ_PROP(o), 0, NULL, ZVAL_PTR_DTOR, 0); zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); @@ -132,6 +135,8 @@ static inline void _http_request_object_declare_default_properties(TSRMLS_D) DCL_PROP_N(PROTECTED, options); DCL_PROP_N(PROTECTED, responseInfo); DCL_PROP_N(PROTECTED, responseData); + DCL_PROP_N(PROTECTED, responseCode); + DCL_PROP_N(PROTECTED, responseMessage); DCL_PROP_N(PROTECTED, postData); DCL_PROP_N(PROTECTED, postFiles); @@ -153,8 +158,8 @@ void _http_request_object_free(zend_object *object TSRMLS_DC) } if (o->ch) { curl_easy_cleanup(o->ch); - o->ch = NULL; } + phpstr_dtor(&o->response); efree(o); } diff --git a/http_send_api.c b/http_send_api.c index 44b29a5..9318efd 100644 --- a/http_send_api.c +++ b/http_send_api.c @@ -124,8 +124,12 @@ 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) { + STATUS ret; sapi_header_line h = {(char *) header, strlen(header), status}; - return sapi_header_op(SAPI_HEADER_REPLACE, &h TSRMLS_CC); + if (SUCCESS != (ret = sapi_header_op(SAPI_HEADER_REPLACE, &h TSRMLS_CC))) { + http_error_ex(E_WARNING, HTTP_E_HEADER, "Could not send header: %s (%d)", header, status); + } + return ret; } /* }}} */ @@ -154,8 +158,7 @@ PHP_HTTP_API STATUS _http_send_etag(const char *etag, size_t etag_len TSRMLS_DC) char *etag_header; if (!etag_len){ - php_error_docref(NULL TSRMLS_CC,E_ERROR, - "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(etag)); return FAILURE; } @@ -167,9 +170,7 @@ PHP_HTTP_API STATUS _http_send_etag(const char *etag, size_t etag_len TSRMLS_DC) etag_header = ecalloc(1, sizeof("ETag: \"\"") + etag_len); sprintf(etag_header, "ETag: \"%s\"", etag); - if (SUCCESS != (status = http_send_header(etag_header))) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Couldn't send '%s' header", etag_header); - } + status = http_send_header(etag_header); efree(etag_header); return status; } @@ -182,10 +183,7 @@ PHP_HTTP_API STATUS _http_send_cache_control(const char *cache_control, size_t c char *cc_header = ecalloc(1, sizeof("Cache-Control: ") + cc_len); sprintf(cc_header, "Cache-Control: %s", cache_control); - if (SUCCESS != (status = http_send_header(cc_header))) { - php_error_docref(NULL TSRMLS_CC, E_NOTICE, - "Could not send '%s' header", cc_header); - } + status = http_send_header(cc_header); efree(cc_header); return status; } @@ -198,9 +196,7 @@ PHP_HTTP_API STATUS _http_send_content_type(const char *content_type, size_t ct_ char *ct_header; if (!strchr(content_type, '/')) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, - "Content-Type '%s' doesn't seem to consist of a primary and a secondary part", - content_type); + http_error_ex(E_WARNING, HTTP_E_PARAM, "Content-Type '%s' doesn't seem to consist of a primary and a secondary part", content_type); return FAILURE; } @@ -212,11 +208,7 @@ PHP_HTTP_API STATUS _http_send_content_type(const char *content_type, size_t ct_ ct_header = ecalloc(1, sizeof("Content-Type: ") + ct_len); sprintf(ct_header, "Content-Type: %s", content_type); - - if (SUCCESS != (status = http_send_header(ct_header))) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, - "Couldn't send '%s' header", ct_header); - } + status = http_send_header(ct_header); efree(ct_header); return status; } @@ -236,9 +228,7 @@ PHP_HTTP_API STATUS _http_send_content_disposition(const char *filename, size_t sprintf(cd_header, "Content-Disposition: attachment; filename=\"%s\"", filename); } - if (SUCCESS != (status = http_send_header(cd_header))) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Couldn't send '%s' header", cd_header); - } + status = http_send_header(cd_header); efree(cd_header); return status; } diff --git a/http_url_api.c b/http_url_api.c index 8788064..459b618 100644 --- a/http_url_api.c +++ b/http_url_api.c @@ -59,13 +59,12 @@ PHP_HTTP_API char *_http_absolute_url_ex( if ((!url || !url_len) && ( (!(url = SG(request_info).request_uri)) || (!(url_len = strlen(SG(request_info).request_uri))))) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, - "Cannot build an absolute URI if supplied URL and REQUEST_URI is empty"); + http_error(E_WARNING, HTTP_E_PARAM, "Cannot build an absolute URI if supplied URL and REQUEST_URI is empty"); return NULL; } if (!(purl = php_url_parse((char *) url))) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not parse supplied URL"); + http_error_ex(E_WARNING, HTTP_E_PARSE, "Could not parse supplied URL: %s", url); return NULL; } @@ -116,7 +115,7 @@ PHP_HTTP_API char *_http_absolute_url_ex( #define HTTP_URI_STRLCATL(URL, full_len, add_string) HTTP_URI_STRLCAT(URL, full_len, add_string, strlen(add_string)) #define HTTP_URI_STRLCAT(URL, full_len, add_string, add_len) \ if ((full_len += add_len) > HTTP_URI_MAXLEN) { \ - php_error_docref(NULL TSRMLS_CC, E_NOTICE, \ + http_error_ex(E_NOTICE, HTTP_E_URL, \ "Absolute URI would have exceeded max URI length (%d bytes) - " \ "tried to add %d bytes ('%s')", \ HTTP_URI_MAXLEN, add_len, add_string); \ @@ -195,7 +194,6 @@ PHP_HTTP_API STATUS _http_urlencode_hash_ex(HashTable *hash, zend_bool override_ } if (SUCCESS != http_urlencode_hash_implementation(hash, qstr, arg_sep)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Couldn't encode query data"); phpstr_free(qstr); return FAILURE; } @@ -222,6 +220,7 @@ PHP_HTTP_API STATUS _http_urlencode_hash_implementation_ex( zval **zdata = NULL, *copyzval; if (!ht || !formstr) { + http_error(E_WARNING, HTTP_E_PARAM, "Invalid parameters"); return FAILURE; } @@ -260,7 +259,7 @@ PHP_HTTP_API STATUS _http_urlencode_hash_implementation_ex( #endif if (zend_hash_get_current_data_ex(ht, (void **)&zdata, NULL) == FAILURE || !zdata || !(*zdata)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error traversing form data array."); + http_error(E_WARNING, HTTP_E_ENCODE, "Error traversing form data array."); return FAILURE; } if (Z_TYPE_PP(zdata) == IS_ARRAY || Z_TYPE_PP(zdata) == IS_OBJECT) { diff --git a/php_http_curl_api.h b/php_http_curl_api.h index 586259e..df6f267 100644 --- a/php_http_curl_api.h +++ b/php_http_curl_api.h @@ -19,6 +19,7 @@ #define PHP_HTTP_CURL_API_H #include "php_http_std_defs.h" +#include "phpstr/phpstr.h" #ifdef PHP_WIN32 # include @@ -26,25 +27,25 @@ #include -#define http_get(u, o, i, d, l) _http_get_ex(NULL, (u), (o), (i), (d), (l) TSRMLS_CC) -#define http_get_ex(c, u, o, i, d, l) _http_get_ex((c), (u), (o), (i), (d), (l) TSRMLS_CC) -PHP_HTTP_API STATUS _http_get_ex(CURL *ch, const char *URL, HashTable *options, HashTable *info, char **data, size_t *data_len TSRMLS_DC); +#define http_get(u, o, i, r) _http_get_ex(NULL, (u), (o), (i), (r) TSRMLS_CC) +#define http_get_ex(c, u, o, i, r) _http_get_ex((c), (u), (o), (i), (r) TSRMLS_CC) +PHP_HTTP_API STATUS _http_get_ex(CURL *ch, const char *URL, HashTable *options, HashTable *info, phpstr *response TSRMLS_DC); -#define http_head(u, o, i, d, l) _http_head_ex(NULL, (u), (o), (i), (d), (l) TSRMLS_CC) -#define http_head_ex(c, u, o, i, d, l) _http_head_ex((c), (u), (o), (i), (d), (l) TSRMLS_CC) -PHP_HTTP_API STATUS _http_head_ex(CURL *ch, const char *URL, HashTable *options, HashTable *info, char **data, size_t *data_len TSRMLS_DC); +#define http_head(u, o, i, r) _http_head_ex(NULL, (u), (o), (i), (r) TSRMLS_CC) +#define http_head_ex(c, u, o, i, r) _http_head_ex((c), (u), (o), (i), (r) TSRMLS_CC) +PHP_HTTP_API STATUS _http_head_ex(CURL *ch, const char *URL, HashTable *options, HashTable *info, phpstr *response TSRMLS_DC); -#define http_post_data(u, pd, pl, o, i, d, l) _http_post_data_ex(NULL, (u), (pd), (pl), (o), (i), (d), (l) TSRMLS_CC) -#define http_post_data_ex(c, u, pd, pl, o, i, d, l) _http_post_data_ex((c), (u), (pd), (pl), (o), (i), (d), (l) TSRMLS_CC) -PHP_HTTP_API STATUS _http_post_data_ex(CURL *ch, const char *URL, char *postdata, size_t postdata_len, HashTable *options, HashTable *info, char **data, size_t *data_len TSRMLS_DC); +#define http_post_data(u, pd, pl, o, i, r) _http_post_data_ex(NULL, (u), (pd), (pl), (o), (i), (r) TSRMLS_CC) +#define http_post_data_ex(c, u, pd, pl, o, i, r) _http_post_data_ex((c), (u), (pd), (pl), (o), (i), (r) TSRMLS_CC) +PHP_HTTP_API STATUS _http_post_data_ex(CURL *ch, const char *URL, char *postdata, size_t postdata_len, HashTable *options, HashTable *info, phpstr *response TSRMLS_DC); -#define http_post_array(u, p, o, i, d, l) _http_post_array_ex(NULL, (u), (p), (o), (i), (d), (l) TSRMLS_CC) -#define http_post_array_ex(c, u, p, o, i, d, l) _http_post_array_ex((c), (u), (p), (o), (i), (d), (l) TSRMLS_CC) -PHP_HTTP_API STATUS _http_post_array_ex(CURL *ch, const char *URL, HashTable *postarray, HashTable *options, HashTable *info, char **data, size_t *data_len TSRMLS_DC); +#define http_post_array(u, p, o, i, r) _http_post_array_ex(NULL, (u), (p), (o), (i), (r) TSRMLS_CC) +#define http_post_array_ex(c, u, p, o, i, r) _http_post_array_ex((c), (u), (p), (o), (i), (r) TSRMLS_CC) +PHP_HTTP_API STATUS _http_post_array_ex(CURL *ch, const char *URL, HashTable *postarray, HashTable *options, HashTable *info, phpstr *response TSRMLS_DC); -#define http_post_curldata(u, h, o, i, d, l) _http_post_curldata_ex(NULL, (u), (h), (o), (i), (d), (l) TSRMLS_CC) -#define http_post_curldata_ex(c, u, h, o, i, d, l) _http_post_curldata_ex((c), (u), (h), (o), (i), (d), (l) TSRMLS_CC) -PHP_HTTP_API STATUS _http_post_curldata_ex(CURL *ch, const char *URL, struct curl_httppost *curldata, HashTable *options, HashTable *info, char **data, size_t *data_len TSRMLS_DC); +#define http_post_curldata(u, h, o, i, r) _http_post_curldata_ex(NULL, (u), (h), (o), (i), (r) TSRMLS_CC) +#define http_post_curldata_ex(c, u, h, o, i, r) _http_post_curldata_ex((c), (u), (h), (o), (i), (r) TSRMLS_CC) +PHP_HTTP_API STATUS _http_post_curldata_ex(CURL *ch, const char *URL, struct curl_httppost *curldata, HashTable *options, HashTable *info, phpstr *response TSRMLS_DC); #endif diff --git a/php_http_request_object.h b/php_http_request_object.h index 7cd3e74..9af6e8b 100644 --- a/php_http_request_object.h +++ b/php_http_request_object.h @@ -26,9 +26,12 @@ #include +#include "phpstr/phpstr.h" + typedef struct { zend_object zo; CURL *ch; + phpstr response; } http_request_object; typedef enum { @@ -85,6 +88,7 @@ PHP_METHOD(HttpRequest, getResponseCookie); PHP_METHOD(HttpRequest, getResponseCode); PHP_METHOD(HttpRequest, getResponseBody); PHP_METHOD(HttpRequest, getResponseInfo); +PHP_METHOD(HttpRequest, getResponseMessage); #endif #endif -- 2.30.2