http_util_object.c http_message_object.c http_request_object.c http_request_pool_api.c \
http_response_object.c http_exception_object.c http_requestpool_object.c \
http_api.c http_auth_api.c http_cache_api.c http_request_api.c http_date_api.c \
- http_headers_api.c http_message_api.c http_send_api.c http_url_api.c"
+ http_headers_api.c http_message_api.c http_send_api.c http_url_api.c \
+ http_info_api.c"
PHP_NEW_EXTENSION([http], $PHP_HTTP_SOURCES, [$ext_shared])
PHP_ADD_BUILD_DIR($ext_builddir/phpstr, 1)
PHP_SUBST([HTTP_SHARED_LIBADD])
"http_request_object.c http_response_object.c "+
"http_api.c http_auth_api.c http_cache_api.c http_request_pool_api.c "+
"http_request_api.c http_date_api.c http_headers_api.c "+
- "http_message_api.c http_send_api.c http_url_api.c ",
+ "http_message_api.c http_send_api.c http_url_api.c "+
+ "http_info_api.c",
null,
"/I\"" + configure_module_dirname + "/phpstr\"");
ADD_SOURCES(configure_module_dirname + "/phpstr", "phpstr.c", "http");
PHP_FE(http_send_stream, NULL)
PHP_FE(http_chunked_decode, NULL)
PHP_FE(http_parse_message, NULL)
- PHP_FE(http_split_response, NULL)
PHP_FE(http_parse_headers, NULL)
PHP_FE(http_get_request_headers, NULL)
PHP_FE(http_get_request_body, NULL)
PHP_INI_BEGIN()
HTTP_PHP_INI_ENTRY("http.allowed_methods", "", PHP_INI_ALL, http_update_allowed_methods, request.methods.allowed)
HTTP_PHP_INI_ENTRY("http.cache_log", "", PHP_INI_ALL, OnUpdateString, log.cache)
+ HTTP_PHP_INI_ENTRY("http.redirect_log", "", PHP_INI_ALL, OnUpdateString, log.redirect)
+ HTTP_PHP_INI_ENTRY("http.allowed_methods_log", "", PHP_INI_ALL, OnUpdateString, log.allowed_methods)
+ HTTP_PHP_INI_ENTRY("http.composite_log", "", PHP_INI_ALL, OnUpdateString, log.composite)
#ifdef ZEND_ENGINE_2
HTTP_PHP_INI_ENTRY("http.only_exceptions", "0", PHP_INI_ALL, OnUpdateBool, only_exceptions)
#endif
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);
+ phpstr_free(&known_request_methods);
+ phpstr_free(&custom_request_methods);
}
php_info_print_table_end();
#endif
# End Source File\r
# Begin Source File\r
\r
+SOURCE=.\http_info_api.c\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=.\phpstr\phpstr.c\r
# End Source File\r
# End Group\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=.\php_http_info_api.h\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=.\php_http_std_defs.h\r
# End Source File\r
# Begin Source File\r
ZEND_EXTERN_MODULE_GLOBALS(http);
-/* char *pretty_key(char *, size_t, zend_bool, zebd_bool) */
+/* char *pretty_key(char *, size_t, zend_bool, zend_bool) */
char *_http_pretty_key(char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen)
{
if (key && key_len) {
}
/* }}} */
-/* {{{ STATUS http_exit(int, char*) */
-STATUS _http_exit_ex(int status, char *header, zend_bool free_header TSRMLS_DC)
+/* {{{ STATUS http_exit(int, char*, char*, zend_bool) */
+STATUS _http_exit_ex(int status, char *header, char *body, zend_bool send_header TSRMLS_DC)
{
- if (SUCCESS != http_send_status_header(status, header)) {
+ char datetime[128];
+
+ if (SUCCESS != http_send_status_header(status, send_header ? header : NULL)) {
http_error_ex(HE_WARNING, HTTP_E_HEADER, "Failed to exit with status/header: %d - %s", status, header ? header : "");
- if (free_header && header) {
- efree(header);
- }
+ STR_FREE(header);
+ STR_FREE(body);
return FAILURE;
}
- if (free_header && header) {
- efree(header);
+ if (body) {
+ PHPWRITE(body, strlen(body));
+ }
+ {
+ time_t now;
+ struct tm nowtm;
+
+ time(&now);
+ strftime(datetime, sizeof(datetime), "%Y-%m-%d %H:%M:%S", php_localtime_r(&now, &nowtm));
+ }
+
+#define HTTP_LOG_WRITE(for, type, header) \
+ HTTP_LOG_WRITE_EX(for, type, header); \
+ HTTP_LOG_WRITE_EX(composite, type, header);
+
+#define HTTP_LOG_WRITE_EX(for, type, header) \
+ if (HTTP_G(log).##for && strlen(HTTP_G(log).##for)) { \
+ php_stream *log = php_stream_open_wrapper(HTTP_G(log).##for, "ab", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL); \
+ \
+ if (log) { \
+ php_stream_printf(log TSRMLS_CC, "%s [%12s] %32s <%s>%s", datetime, type, header, SG(request_info).request_uri, PHP_EOL); \
+ php_stream_close(log); \
+ } \
+ \
}
+ switch (status)
+ {
+ case 301: HTTP_LOG_WRITE(redirect, "301-REDIRECT", header); break;
+ case 302: HTTP_LOG_WRITE(redirect, "302-REDIRECT", header); break;
+ case 304: HTTP_LOG_WRITE(cache, "304-CACHE", header); break;
+ case 401: HTTP_LOG_WRITE(auth, "401-AUTH", header); break;
+ case 403: HTTP_LOG_WRITE(auth, "403-AUTH", header); break;
+ case 405: HTTP_LOG_WRITE(allowed_methods, "405-ALLOWED", header); break;
+ }
+ STR_FREE(header);
+ STR_FREE(body);
zend_bailout();
/* fake */
return SUCCESS;
zval **hsv;
zval **var;
- if (SUCCESS != zend_hash_find(&EG(symbol_table), "HTTP_SERVER_VARS", sizeof("HTTP_SERVER_VARS"), (void **) &hsv)) {
+ if (SUCCESS != zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &hsv)) {
return NULL;
}
if (SUCCESS != zend_hash_find(Z_ARRVAL_PP(hsv), (char *) key, key_size, (void **) &var)) {
}
/* }}} */
-/* {{{ STATUS http_split_response(char *, size_t, HashTable *, char **, size_t *) */
-PHP_HTTP_API STATUS _http_split_response(char *response, size_t response_len,
- HashTable *headers, char **body, size_t *body_len TSRMLS_DC)
-{
- char *header = response, *real_body = NULL;
-
- while (0 < (response_len - (response - header + 4))) {
- if ( (*response++ == '\r') &&
- (*response++ == '\n') &&
- (*response++ == '\r') &&
- (*response++ == '\n')) {
- real_body = response;
- break;
- }
- }
-
- if (real_body && (*body_len = (response_len - (real_body - header)))) {
- *body = ecalloc(1, *body_len + 1);
- memcpy(*body, real_body, *body_len);
- }
-
- return http_parse_headers_ex(header, headers, 1);
-}
+/* {{{ STATUS http_locate_body(char *, size_t) */
+PHP_HTTP_API
/* }}} */
/*
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(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;
- struct tm nowtm;
- char datetime[128];
-
- time(&now);
- strftime(datetime, sizeof(datetime), "%Y-%m-%d %H:%M:%S", php_localtime_r(&now, &nowtm));
- php_stream_printf(log TSRMLS_CC, "%s [%s] %32s %s\n", datetime, etag ? "ETAG":"LMOD", cache_token, SG(request_info).request_uri);
- php_stream_close(log);
- }
- }
- if (free_token && cache_token) {
- efree(cache_token);
- }
- return http_exit_ex(304, NULL, 0);
-}
-/* }}} */
-
/* {{{ char *http_etag(void *, size_t, http_send_mode) */
PHP_HTTP_API char *_http_etag(const void *data_ptr, size_t data_len, http_send_mode data_mode TSRMLS_DC)
{
PHP_HTTP_API STATUS _http_cache_last_modified(time_t last_modified,
time_t send_modified, const char *cache_control, size_t cc_len TSRMLS_DC)
{
+ char *sent_header = NULL;
+
if (cc_len && (SUCCESS != http_send_cache_control(cache_control, cc_len))) {
return FAILURE;
}
- if (SUCCESS != http_send_last_modified(send_modified)) {
+ if (SUCCESS != http_send_last_modified_ex(send_modified, &sent_header)) {
return FAILURE;
}
if (http_match_last_modified("HTTP_IF_MODIFIED_SINCE", last_modified)) {
- return http_cache_exit(http_date(last_modified), 0);
+ http_exit_ex(304, sent_header, NULL, 0);
+ } else {
+ STR_FREE(sent_header);
}
return SUCCESS;
PHP_HTTP_API STATUS _http_cache_etag(const char *etag, size_t etag_len,
const char *cache_control, size_t cc_len TSRMLS_DC)
{
+ char *sent_header = NULL;
+
if (cc_len && (SUCCESS != http_send_cache_control(cache_control, cc_len))) {
return FAILURE;
}
if (etag_len) {
- if (SUCCESS != http_send_etag(etag, etag_len)) {
+ if (SUCCESS != http_send_etag_ex(etag, etag_len, &sent_header)) {
return FAILURE;
}
- if (!http_match_etag("HTTP_IF_NONE_MATCH", etag)) {
- return SUCCESS;
+ if (http_match_etag("HTTP_IF_NONE_MATCH", etag)) {
+ http_exit_ex(304, sent_header, NULL, 0);
+ } else {
+ STR_FREE(sent_header);
}
- return http_cache_exit_ex((char *)etag, 1, 0);
+ return SUCCESS;
}
/* if no etag is given and we didn't already start ob_etaghandler -- start it */
/* just do that if desired */
if (HTTP_G(etag).started) {
+ char *sent_header = NULL;
+
make_digest(etag, digest);
http_send_cache_control(HTTP_DEFAULT_CACHECONTROL, lenof(HTTP_DEFAULT_CACHECONTROL));
- http_send_etag(etag, 32);
+ http_send_etag_ex(etag, 32, &sent_header);
if (http_match_etag("HTTP_IF_NONE_MATCH", etag)) {
- http_cache_exit_ex(etag, 1, 0);
+ http_exit_ex(304, sent_header, NULL, 0);
+ } else {
+ STR_FREE(sent_header);
}
}
}
size_t query_len = 0;
zend_bool session = 0, permanent = 0, free_params = 0;
zval *params = NULL;
- char *query = NULL, *url = NULL, *URI,
- LOC[HTTP_URI_MAXLEN + sizeof("Location: ")],
- RED[HTTP_URI_MAXLEN * 2 + sizeof("Redirecting to <a href=\"%s?%s\">%s?%s</a>.\n")];
+ char *query = NULL, *url = NULL, *URI, *LOC, *RED = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sa!/bb", &url, &url_len, ¶ms, &session, &permanent) != SUCCESS) {
RETURN_FALSE;
URI = http_absolute_uri(url);
if (query_len) {
- snprintf(LOC, HTTP_URI_MAXLEN + sizeof("Location: "), "Location: %s?%s", URI, query);
- sprintf(RED, "Redirecting to <a href=\"%s?%s\">%s?%s</a>.\n", URI, query, URI, query);
+ spprintf(&LOC, 0, "Location: %s?%s", URI, query);
+ if (SG(request_info).request_method && strcmp(SG(request_info).request_method, "HEAD")) {
+ spprintf(&RED, 0, "Redirecting to <a href=\"%s?%s\">%s?%s</a>.\n", URI, query, URI, query);
+ }
} else {
- snprintf(LOC, HTTP_URI_MAXLEN + sizeof("Location: "), "Location: %s", URI);
- sprintf(RED, "Redirecting to <a href=\"%s\">%s</a>.\n", URI, URI);
+ spprintf(&LOC, 0, "Location: %s", URI);
+ if (SG(request_info).request_method && strcmp(SG(request_info).request_method, "HEAD")) {
+ spprintf(&RED, 0, "Redirecting to <a href=\"%s\">%s</a>.\n", URI, URI);
+ }
}
efree(URI);
FREE_ZVAL(params);
}
- if ((SUCCESS == http_send_header_string(LOC)) && (SUCCESS == http_send_status((permanent ? 301 : 302)))) {
- if (SG(request_info).request_method && strcmp(SG(request_info).request_method, "HEAD")) {
- PHPWRITE(RED, strlen(RED));
- }
- RETURN_TRUE;
- }
- RETURN_FALSE;
+ RETURN_SUCCESS(http_exit_ex(permanent ? 301 : 302, LOC, RED, 1));
}
/* }}} */
}
/* }}} */
-/* {{{ proto array http_split_response(string http_response)
- *
- * This function splits an HTTP response into an array with headers and the
- * content body. The returned array may look simliar to the following example:
- *
- * <pre>
- * <?php
- * array(
- * 0 => array(
- * 'Response Status' => '200 Ok',
- * 'Content-Type' => 'text/plain',
- * 'Content-Language' => 'en-US'
- * ),
- * 1 => "Hello World!"
- * );
- * ?>
- * </pre>
- */
-PHP_FUNCTION(http_split_response)
-{
- char *response, *body;
- int response_len;
- size_t body_len;
- zval *zheaders;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &response, &response_len) != SUCCESS) {
- RETURN_FALSE;
- }
-
- MAKE_STD_ZVAL(zheaders);
- array_init(zheaders);
-
- if (SUCCESS != http_split_response(response, response_len, Z_ARRVAL_P(zheaders), &body, &body_len)) {
- RETURN_FALSE;
- }
-
- array_init(return_value);
- add_index_zval(return_value, 0, zheaders);
- add_index_stringl(return_value, 1, body, body_len, 0);
-}
-/* }}} */
-
-static void http_message_toobject_recursive(http_message *msg, zval *obj TSRMLS_DC)
-{
- zval *headers;
-
- add_property_long(obj, "type", msg->type);
- switch (msg->type)
- {
- case HTTP_MSG_RESPONSE:
- add_property_double(obj, "httpVersion", msg->info.response.http_version);
- add_property_long(obj, "responseCode", msg->info.response.code);
- break;
-
- case HTTP_MSG_REQUEST:
- add_property_double(obj, "httpVersion", msg->info.request.http_version);
- add_property_string(obj, "requestMethod", msg->info.request.method, 1);
- add_property_string(obj, "requestUri", msg->info.request.URI, 1);
- break;
- }
-
- MAKE_STD_ZVAL(headers);
- array_init(headers);
- zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
- add_property_zval(obj, "headers", headers);
- zval_ptr_dtor(&headers);
-
- add_property_stringl(obj, "body", PHPSTR_VAL(msg), PHPSTR_LEN(msg), 1);
-
- if (msg->parent) {
- zval *parent;
-
- MAKE_STD_ZVAL(parent);
- object_init(parent);
- add_property_zval(obj, "parentMessage", parent);
- http_message_toobject_recursive(msg->parent, parent TSRMLS_CC);
- zval_ptr_dtor(&parent);
- } else {
- add_property_null(obj, "parentMessage");
- }
- http_message_dtor(msg);
- efree(msg);
-}
-
/* {{{ proto object http_parse_message(string message)
*
* Parses (a) http_message(s) into a simple recursive object structure:
if (msg = http_message_parse(message, message_len)) {
object_init(return_value);
- http_message_toobject_recursive(msg, return_value TSRMLS_CC);
+ http_message_tostruct_recursive(msg, return_value);
} else {
RETURN_NULL();
}
* 'content_type' => 'text/html; charset=iso-8859-1',
* 'redirect_time' => 0,
* 'redirect_count' => 0,
- * 'private' => '',
* 'http_connectcode' => 0,
* 'httpauth_avail' => 0,
* 'proxyauth_avail' => 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);
+ RETURN_PHPSTR_VAL(&response);
} else {
RETURN_FALSE;
}
phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
if (SUCCESS == http_head(URL, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
- RETURN_PHPSTR_VAL(response);
+ RETURN_PHPSTR_VAL(&response);
} else {
RETURN_FALSE;
}
}
/* }}} */
-/* {{{ proto string http_post_data(string url, string data[, array options[, &info]])
+/* {{{ proto string http_post_data(string url, string data[, array options[, array &info]])
*
* Performs an HTTP POST request, posting data.
* Returns the HTTP response as string.
phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
if (SUCCESS == http_post(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
- RETVAL_PHPSTR_VAL(response);
+ RETVAL_PHPSTR_VAL(&response);
} else {
RETVAL_FALSE;
}
phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
if (SUCCESS == http_post(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
- RETVAL_PHPSTR_VAL(response);
+ RETVAL_PHPSTR_VAL(&response);
} else {
RETVAL_FALSE;
}
phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
if (SUCCESS == http_put(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
- RETVAL_PHPSTR_VAL(response);
+ RETVAL_PHPSTR_VAL(&response);
} else {
RETVAL_FALSE;
}
phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
if (SUCCESS == http_put(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
- RETURN_PHPSTR_VAL(response);
+ RETURN_PHPSTR_VAL(&response);
} else {
RETURN_NULL();
}
formstr = phpstr_new();
if (SUCCESS != http_urlencode_hash_implementation_ex(HASH_OF(formdata), formstr, arg_sep, prefix, prefix_len, NULL, 0, NULL, 0, (Z_TYPE_P(formdata) == IS_OBJECT ? formdata : NULL))) {
- phpstr_free(formstr);
+ phpstr_free(&formstr);
RETURN_FALSE;
}
if (!formstr->used) {
- phpstr_free(formstr);
+ phpstr_free(&formstr);
RETURN_NULL();
}
PHP_FUNCTION(http_test)
{
+ ulong idx;
+ char *key;
+ zval **data;
+ FOREACH_HASH_KEYVAL(&EG(symbol_table), key, idx, data) {
+ convert_to_string_ex(data);
+ fprintf(stderr, "\t %s => %s\n", key, Z_STRVAL_PP(data));
+ }
}
/*
#include "php_http_std_defs.h"
#include "php_http_api.h"
#include "php_http_headers_api.h"
+#include "php_http_info_api.h"
#include <ctype.h>
/* }}} */
/* {{{ STATUS http_parse_headers(char *, HashTable *, zend_bool) */
-PHP_HTTP_API STATUS _http_parse_headers_ex(const char *header, HashTable *headers, zend_bool prettify, http_parse_headers_callback_t func, void **callback_data TSRMLS_DC)
+PHP_HTTP_API STATUS _http_parse_headers_ex(const char *header, HashTable *headers, zend_bool prettify,
+ http_info_callback callback_func, void **callback_data TSRMLS_DC)
{
- const char *colon = NULL, *line = NULL, *begin = header, *crlfcrlf = NULL;
+ const char *colon = NULL, *line = NULL, *begin = header;
+ const char *body = http_locate_body(header);
size_t header_len;
zval array;
Z_ARRVAL(array) = headers;
-
- if (crlfcrlf = strstr(header, HTTP_CRLF HTTP_CRLF)) {
- header_len = crlfcrlf - header + lenof(HTTP_CRLF);
- } else {
- header_len = strlen(header) + 1;
- }
-
-
- if (header_len < 2 || !strchr(header, ':')) {
+ header_len = body ? body - header : strlen(header) + 1;
+
+/*
+ if (header_len < 2 || ((!lflf) && (!crlfcrlf) && (!strchr(header, ':')))) {
+ fprintf(stderr, "header_len: %lu, lflf: %p, crlfcrlf: %p, ':': %p\n(%s)\n",
+ header_len, lflf, crlfcrlf, strchr(header, ':'), header);
http_error(HE_WARNING, HTTP_E_MALFORMED_HEADERS, "Cannot parse too short or malformed HTTP headers");
return FAILURE;
}
-
+*/
line = header;
while (header_len >= (size_t) (line - begin)) {
switch (*line++)
{
+ case ':':
+ if (!colon) {
+ colon = line - 1;
+ }
+ break;
+
case 0:
--value_len; /* we don't have CR so value length is one char less */
case '\n':
if ((!(*line - 1)) || ((*line != ' ') && (*line != '\t'))) {
+ http_info i;
+
/* response/request line */
+ if (SUCCESS == http_info_parse(header, &i)) {
+ callback_func(callback_data, &headers, &i TSRMLS_CC);
+ http_info_dtor(&i);
+ Z_ARRVAL(array) = headers;
+ } else
+
+ /*
if ( (!strncmp(header, "HTTP/1.", lenof("HTTP/1."))) ||
(!strncmp(line - lenof("HTTP/1.x" HTTP_CRLF) + value_len, "HTTP/1.", lenof("HTTP/1.")))) {
if (func) {
Z_ARRVAL(array) = headers;
}
} else
+ */
/* "header: value" pair */
if (colon) {
header += line - header;
}
break;
-
- case ':':
- if (!colon) {
- colon = line - 1;
- }
- break;
}
}
return SUCCESS;
}
/* }}} */
-PHP_HTTP_API void _http_parse_headers_default_callback(const char *http_line, HashTable **headers, void **cb_data TSRMLS_DC)
-{
- zval array;
- char *crlf = NULL;
- size_t line_length;
- Z_ARRVAL(array) = *headers;
-
- if (crlf = strstr(http_line, HTTP_CRLF)) {
- line_length = crlf - http_line;
- } else {
- line_length = strlen(http_line);
- }
-
- /* response */
- if (!strncmp(http_line, "HTTP/1.", lenof("HTTP/1."))) {
- char *status = estrndup(http_line + lenof("HTTP/1.x "), line_length - lenof("HTTP/1.x "));
- add_assoc_stringl(&array, "Response Status", status, line_length - lenof("HTTP/1.x "), 0);
- } else
- /* request */
- if (!strncmp(http_line + line_length - lenof("HTTP/1.x"), "HTTP/1.", lenof("HTTP/1."))) {
- char *sep = strchr(http_line, ' ');
- char *url = estrndup(sep + 1, strstr(sep, "HTTP/1.") - sep + 1 + 1);
- char *met = estrndup(http_line, sep - http_line);
-
- add_assoc_stringl(&array, "Request Method", met, sep - http_line, 0);
- add_assoc_stringl(&array, "Request Uri", url, strstr(sep, "HTTP/1.") - sep + 1 + 1, 0);
- }
-}
-
/* {{{ void http_get_request_headers_ex(HashTable *, zend_bool) */
PHP_HTTP_API void _http_get_request_headers_ex(HashTable *headers, zend_bool prettify TSRMLS_DC)
{
Z_ARRVAL(array) = headers;
- if (SUCCESS == zend_hash_find(&EG(symbol_table), "HTTP_SERVER_VARS", sizeof("HTTP_SERVER_VARS"), (void **) &hsv)) {
+ if (SUCCESS == zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &hsv)) {
FOREACH_KEY(*hsv, key, idx) {
if (key && !strncmp(key, "HTTP_", 5)) {
zval **header;
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PECL :: http |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.0 of the PHP license, that |
+ | is bundled with this package in the file LICENSE, and is available |
+ | through the world-wide-web at http://www.php.net/license/3_0.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2004-2005 Michael Wallner <mike@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include "php.h"
+
+#include "php_http.h"
+#include "php_http_api.h"
+#include "php_http_std_defs.h"
+#include "php_http_info_api.h"
+
+#include <ctype.h>
+
+ZEND_EXTERN_MODULE_GLOBALS(http);
+
+PHP_HTTP_API void _http_info_default_callback(void **nothing, HashTable **headers, http_info *info TSRMLS_DC)
+{
+ zval array;
+ Z_ARRVAL(array) = *headers;
+
+ switch (info->type)
+ {
+ case IS_HTTP_REQUEST:
+ add_assoc_string(&array, "Request Method", HTTP_INFO(info).request.method, 1);
+ add_assoc_string(&array, "Request Uri", HTTP_INFO(info).request.URI, 1);
+ break;
+
+ case IS_HTTP_RESPONSE:
+ add_assoc_long(&array, "Response Code", (long) HTTP_INFO(info).response.code);
+ add_assoc_string(&array, "Response Status", HTTP_INFO(info).response.status, 1);
+ break;
+ }
+}
+
+PHP_HTTP_API void _http_info_dtor(http_info *info)
+{
+ http_info_t *i = (http_info_t *) info;
+
+ switch (info->type)
+ {
+ case IS_HTTP_REQUEST:
+ STR_SET(i->request.method, NULL);
+ STR_SET(i->request.URI, NULL);
+ break;
+
+ case IS_HTTP_RESPONSE:
+ STR_SET(i->response.status, NULL);
+ break;
+
+ default:
+ break;
+ }
+}
+
+PHP_HTTP_API STATUS _http_info_parse_ex(const char *pre_header, http_info *info, zend_bool silent TSRMLS_DC)
+{
+ const char *end, *http;
+
+ /* sane parameter */
+ if ((!pre_header) || (!*pre_header)) {
+ if (!silent) {
+ http_error(HE_WARNING, HTTP_E_MALFORMED_HEADERS, "Empty pre-header HTTP info");
+ }
+ return FAILURE;
+ }
+
+ /* where's the end of the line */
+ if (!((end = strchr(pre_header, '\r')) || (end = strchr(pre_header, '\n')))) {
+ end = pre_header + strlen(pre_header);
+ }
+
+ /* there must be HTTP/1.x in the line
+ * and nothing than SPACE or NUL after HTTP/1.x
+ */
+ if ( (!(http = strstr(pre_header, "HTTP/1."))) ||
+ (!(http < end)) ||
+ (!isdigit(http[lenof("HTTP/1.")])) ||
+ (http[lenof("HTTP/1.1")] && (!isspace(http[lenof("HTTP/1.1")])))) {
+ if (!silent) {
+ http_error(HE_WARNING, HTTP_E_MALFORMED_HEADERS, "Invalid or missing HTTP/1.x protocol identification");
+ }
+ return FAILURE;
+ }
+
+#if 0
+ {
+ char *line = estrndup(pre_header, end - pre_header);
+ fprintf(stderr, "http_parse_info('%s')\n", line);
+ efree(line);
+ }
+#endif
+
+ info->http.version = atof(http + lenof("HTTP/"));
+
+ /* is response */
+ if (pre_header == http) {
+ char *status = NULL;
+ const char *code = http + sizeof("HTTP/1.1");
+
+ info->type = IS_HTTP_RESPONSE;
+ HTTP_INFO(info).response.code = (code && (end > code)) ? strtol(code, &status, 10) : 0;
+ HTTP_INFO(info).response.status = (status && (end > ++status)) ? estrndup(status, end - status) : ecalloc(1,1);
+
+ return SUCCESS;
+ }
+
+ /* is request */
+ else {
+ const char *url = strchr(pre_header, ' ');
+
+ info->type = IS_HTTP_REQUEST;
+ if (url && http > url) {
+ HTTP_INFO(info).request.method = estrndup(pre_header, url - pre_header);
+ HTTP_INFO(info).request.URI = estrndup(url + 1, http - url - 2);
+ } else {
+ HTTP_INFO(info).request.method = ecalloc(1,1);
+ HTTP_INFO(info).request.URI = ecalloc(1,1);
+ }
+
+ return SUCCESS;
+ }
+}
+
+
+/*
+ * 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
+ */
+
ZEND_EXTERN_MODULE_GLOBALS(http);
-#define http_message_headers_cb _http_message_headers_cb
-static void _http_message_headers_cb(const char *http_line, HashTable **headers, void **message TSRMLS_DC)
+#define http_message_info_callback _http_message_info_callback
+static void _http_message_info_callback(http_message **message, HashTable **headers, http_info *info TSRMLS_DC)
{
- size_t line_length;
- char *crlf = NULL;
- http_message *new, *old = (http_message *) *message;
-
- if (crlf = strstr(http_line, HTTP_CRLF)) {
- line_length = crlf - http_line;
- } else {
- line_length = strlen(http_line);
- }
-
+ http_message *old = *message;
+
+ /* advance message */
if (old->type || zend_hash_num_elements(&old->hdrs) || PHPSTR_LEN(old)) {
- new = http_message_new();
-
- new->parent = old;
- *message = new;
- *headers = &new->hdrs;
- } else {
- new = old;
+ (*message) = http_message_new();
+ (*message)->parent = old;
+ (*headers) = &((*message)->hdrs);
}
-
- while (isspace(http_line[line_length-1])) --line_length;
-
- // response
- if (!strncmp(http_line, "HTTP/1.", lenof("HTTP/1."))) {
- new->type = HTTP_MSG_RESPONSE;
- new->info.response.http_version = atof(http_line + lenof("HTTP/"));
- new->info.response.code = atoi(http_line + lenof("HTTP/1.1 "));
- } else
- // request
- if (!strncmp(http_line + line_length - lenof("HTTP/1.1"), "HTTP/1.", lenof("HTTP/1."))) {
- const char *method_sep_uri = strchr(http_line, ' ');
- new->type = HTTP_MSG_REQUEST;
- new->info.request.http_version = atof(http_line + line_length - lenof("1.1"));
- new->info.request.method = estrndup(http_line, method_sep_uri - http_line);
- new->info.request.URI = estrndup(method_sep_uri + 1, http_line + line_length - method_sep_uri - 1 - lenof(" HTTP/1.1"));
+
+ (*message)->http.version = info->http.version;
+
+ switch (info->type)
+ {
+ case IS_HTTP_REQUEST:
+ (*message)->type = HTTP_MSG_REQUEST;
+ HTTP_INFO(*message).request.URI = estrdup(HTTP_INFO(info).request.URI);
+ HTTP_INFO(*message).request.method = estrdup(HTTP_INFO(info).request.method);
+ break;
+
+ case IS_HTTP_RESPONSE:
+ (*message)->type = HTTP_MSG_RESPONSE;
+ HTTP_INFO(*message).response.code = HTTP_INFO(info).response.code;
+ HTTP_INFO(*message).response.status = estrdup(HTTP_INFO(info).response.status);
+ break;
}
}
#define http_message_init_type _http_message_init_type
static inline void _http_message_init_type(http_message *message, http_message_type type)
{
+ message->http.version = .0;
+
switch (message->type = type)
{
case HTTP_MSG_RESPONSE:
- message->info.response.http_version = .0;
- message->info.response.code = 0;
+ message->http.info.response.code = 0;
+ message->http.info.response.status = NULL;
break;
case HTTP_MSG_REQUEST:
- message->info.request.http_version = .0;
- message->info.request.method = NULL;
- message->info.request.URI = NULL;
+ message->http.info.request.method = NULL;
+ message->http.info.request.URI = NULL;
break;
case HTTP_MSG_NONE:
if (type != message->type) {
/* free request info */
- if (message->type == HTTP_MSG_REQUEST) {
- if (message->info.request.method) {
- efree(message->info.request.method);
- }
- if (message->info.request.URI) {
- efree(message->info.request.URI);
- }
+ switch (message->type)
+ {
+ case HTTP_MSG_REQUEST:
+ STR_FREE(message->http.info.request.method);
+ STR_FREE(message->http.info.request.URI);
+ break;
+
+ case HTTP_MSG_RESPONSE:
+ STR_FREE(message->http.info.response.status);
+ break;
+
+ default:
+ break;
}
/* init */
PHP_HTTP_API http_message *_http_message_parse_ex(http_message *msg, const char *message, size_t message_length TSRMLS_DC)
{
- char *body = NULL;
+ char *body = NULL, *cr, *lf;
zend_bool free_msg = msg ? 0 : 1;
- if (message_length < HTTP_MSG_MIN_SIZE) {
- return NULL;
- }
-
- if (!message) {
+ if ((!message) || (message_length < HTTP_MSG_MIN_SIZE)) {
return NULL;
}
msg = http_message_init(msg);
- if (SUCCESS != http_parse_headers_cb(message, &msg->hdrs, 1, http_message_headers_cb, (void **) &msg)) {
+ if (SUCCESS != http_parse_headers_cb(message, &msg->hdrs, 1, (http_info_callback) http_message_info_callback, &msg)) {
if (free_msg) {
- http_message_free(msg);
+ http_message_free(&msg);
}
return NULL;
}
- /* header parsing stops at CRLF CRLF */
+ /* header parsing stops at (CR)LF (CR)LF */
if (body = strstr(message, HTTP_CRLF HTTP_CRLF)) {
zval *c;
const char *continue_at = NULL;
body += lenof(HTTP_CRLF HTTP_CRLF);
-
/* message has content-length header */
if (c = http_message_header(msg, "Content-Length")) {
long len = atol(Z_STRVAL_P(c));
{
case HTTP_MSG_REQUEST:
phpstr_appendf(&str, "%s %s HTTP/%1.1f" HTTP_CRLF,
- msg->info.request.method,
- msg->info.request.URI,
- msg->info.request.http_version);
+ msg->http.info.request.method,
+ msg->http.info.request.URI,
+ msg->http.version);
break;
case HTTP_MSG_RESPONSE:
- phpstr_appendf(&str, "HTTP/%1.1f %d" HTTP_CRLF,
- msg->info.response.http_version,
- msg->info.response.code);
+ phpstr_appendf(&str, "HTTP/%1.1f %d%s%s" HTTP_CRLF,
+ msg->http.version,
+ msg->http.info.response.code,
+ *msg->http.info.response.status ? " ":"",
+ msg->http.info.response.status);
break;
case HTTP_MSG_NONE:
phpstr_dtor(&str);
}
+PHP_HTTP_API void _http_message_tostruct_recursive(http_message *msg, zval *obj TSRMLS_DC)
+{
+ zval strct;
+ zval *headers;
+
+ Z_TYPE(strct) = IS_ARRAY;
+ Z_ARRVAL(strct) = HASH_OF(obj);
+
+ add_assoc_long(&strct, "type", msg->type);
+ add_assoc_double(&strct, "httpVersion", msg->http.version);
+ switch (msg->type)
+ {
+ case HTTP_MSG_RESPONSE:
+ add_assoc_long(&strct, "responseCode", msg->http.info.response.code);
+ add_assoc_string(&strct, "responseStatus", msg->http.info.response.status, 1);
+ break;
+
+ case HTTP_MSG_REQUEST:
+ add_assoc_string(&strct, "requestMethod", msg->http.info.request.method, 1);
+ add_assoc_string(&strct, "requestUri", msg->http.info.request.URI, 1);
+ break;
+ }
+
+ MAKE_STD_ZVAL(headers);
+ array_init(headers);
+ zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+ add_assoc_zval(&strct, "headers", headers);
+ zval_ptr_dtor(&headers);
+
+ add_assoc_stringl(&strct, "body", PHPSTR_VAL(msg), PHPSTR_LEN(msg), 1);
+
+ if (msg->parent) {
+ zval *parent;
+
+ MAKE_STD_ZVAL(parent);
+ if (Z_TYPE_P(obj) == IS_ARRAY) {
+ array_init(parent);
+ } else {
+ object_init(parent);
+ }
+ add_assoc_zval(&strct, "parentMessage", parent);
+ http_message_tostruct_recursive(msg->parent, parent);
+ zval_ptr_dtor(&parent);
+ } else {
+ add_assoc_null(&strct, "parentMessage");
+ }
+ http_message_dtor(msg);
+ efree(msg);
+}
+
PHP_HTTP_API STATUS _http_message_send(http_message *message TSRMLS_DC)
{
STATUS rs = FAILURE;
zval **data;
FOREACH_VAL(*val, data) {
- http_send_header_ex(key, strlen(key), Z_STRVAL_PP(data), Z_STRLEN_PP(data), first);
+ http_send_header_ex(key, strlen(key), Z_STRVAL_PP(data), Z_STRLEN_PP(data), first, NULL);
first = 0;
}
} else {
- http_send_header_ex(key, strlen(key), Z_STRVAL_PP(val), Z_STRLEN_PP(val), 1);
+ http_send_header_ex(key, strlen(key), Z_STRVAL_PP(val), Z_STRLEN_PP(val), 1, NULL);
}
key = NULL;
}
}
- rs = SUCCESS == http_send_status(message->info.response.code) &&
+ rs = SUCCESS == http_send_status(message->http.info.response.code) &&
SUCCESS == http_send_data(PHPSTR_VAL(message), PHPSTR_LEN(message)) ?
SUCCESS : FAILURE;
}
host = estrndup(Z_STRVAL_PP(zhost), host_len = Z_STRLEN_PP(zhost));
}
uri = http_absolute_uri_ex(
- message->info.request.URI, strlen(message->info.request.URI),
+ message->http.info.request.URI, strlen(message->http.info.request.URI),
NULL, 0, host, host_len, port);
efree(host);
} else {
- uri = http_absolute_uri(message->info.request.URI);
+ uri = http_absolute_uri(message->http.info.request.URI);
}
- if (!strcasecmp("POST", message->info.request.method)) {
+ if (!strcasecmp("POST", message->http.info.request.method)) {
http_request_body body = {HTTP_REQUEST_BODY_CSTRING, PHPSTR_VAL(message), PHPSTR_LEN(message)};
rs = http_post(uri, &body, Z_ARRVAL(options), NULL, NULL);
} else
- if (!strcasecmp("GET", message->info.request.method)) {
+ if (!strcasecmp("GET", message->http.info.request.method)) {
rs = http_get(uri, Z_ARRVAL(options), NULL, NULL);
} else
- if (!strcasecmp("HEAD", message->info.request.method)) {
+ if (!strcasecmp("HEAD", message->http.info.request.method)) {
rs = http_head(uri, Z_ARRVAL(options), NULL, NULL);
} else {
http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD,
"Cannot send HttpMessage. Request method %s not supported",
- message->info.request.method);
+ message->http.info.request.method);
}
efree(uri);
if (message) {
zend_hash_destroy(&message->hdrs);
phpstr_dtor(PHPSTR(message));
- if (HTTP_MSG_TYPE(REQUEST, message)) {
- if (message->info.request.method) {
- efree(message->info.request.method);
- message->info.request.method = NULL;
- }
- if (message->info.request.URI) {
- efree(message->info.request.URI);
- message->info.request.URI = NULL;
- }
+
+ switch (message->type)
+ {
+ case HTTP_MSG_REQUEST:
+ STR_SET(message->http.info.request.method, NULL);
+ STR_SET(message->http.info.request.URI, NULL);
+ break;
+
+ case HTTP_MSG_RESPONSE:
+ STR_SET(message->http.info.response.status, NULL);
+ break;
+
+ default:
+ break;
}
}
}
-PHP_HTTP_API void _http_message_free(http_message *message)
+PHP_HTTP_API void _http_message_free(http_message **message)
{
- if (message) {
- if (message->parent) {
- http_message_free(message->parent);
- message->parent = NULL;
+ if (*message) {
+ if ((*message)->parent) {
+ http_message_free(&(*message)->parent);
}
- http_message_dtor(message);
- efree(message);
+ http_message_dtor(*message);
+ efree(*message);
+ *message = NULL;
}
}
break;
case HTTP_MSG_PROPHASH_HTTP_VERSION:
- switch (msg->type)
- {
- case HTTP_MSG_REQUEST:
- RETVAL_DOUBLE(msg->info.request.http_version);
- break;
-
- case HTTP_MSG_RESPONSE:
- RETVAL_DOUBLE(msg->info.response.http_version);
- break;
-
- case HTTP_MSG_NONE:
- default:
- RETVAL_NULL();
- break;
- }
+ RETVAL_DOUBLE(msg->http.version);
break;
case HTTP_MSG_PROPHASH_BODY:
case HTTP_MSG_PROPHASH_PARENT_MESSAGE:
if (msg->parent) {
RETVAL_OBJVAL(obj->parent);
- Z_TYPE_P(return_value) = IS_OBJECT;
- return_value->value.obj = obj->parent;
- zend_objects_store_add_ref(return_value TSRMLS_CC);
} else {
RETVAL_NULL();
}
break;
case HTTP_MSG_PROPHASH_REQUEST_METHOD:
- if (HTTP_MSG_TYPE(REQUEST, msg) && msg->info.request.method) {
- RETVAL_STRING(msg->info.request.method, 1);
+ if (HTTP_MSG_TYPE(REQUEST, msg) && msg->http.info.request.method) {
+ RETVAL_STRING(msg->http.info.request.method, 1);
} else {
RETVAL_NULL();
}
break;
case HTTP_MSG_PROPHASH_REQUEST_URI:
- if (HTTP_MSG_TYPE(REQUEST, msg) && msg->info.request.URI) {
- RETVAL_STRING(msg->info.request.URI, 1);
+ if (HTTP_MSG_TYPE(REQUEST, msg) && msg->http.info.request.URI) {
+ RETVAL_STRING(msg->http.info.request.URI, 1);
} else {
RETVAL_NULL();
}
case HTTP_MSG_PROPHASH_RESPONSE_CODE:
if (HTTP_MSG_TYPE(RESPONSE, msg)) {
- RETVAL_LONG(msg->info.response.code);
+ RETVAL_LONG(msg->http.info.response.code);
} else {
RETVAL_NULL();
}
break;
-
+
+ case HTTP_MSG_PROPHASH_RESPONSE_STATUS:
+ if (HTTP_MSG_TYPE(RESPONSE, msg) && msg->http.info.response.status) {
+ RETVAL_STRING(msg->http.info.response.status, 1);
+ } else {
+ RETVAL_NULL();
+ }
+ break;
+
default:
RETVAL_NULL();
break;
{
case HTTP_MSG_PROPHASH_TYPE:
convert_to_long_ex(&value);
- if ((http_message_type) Z_LVAL_P(value) != msg->type) {
- if (HTTP_MSG_TYPE(REQUEST, msg)) {
- if (msg->info.request.method) {
- efree(msg->info.request.method);
- }
- if (msg->info.request.URI) {
- efree(msg->info.request.URI);
- }
- }
- msg->type = Z_LVAL_P(value);
- if (HTTP_MSG_TYPE(REQUEST, msg)) {
- msg->info.request.method = NULL;
- msg->info.request.URI = NULL;
- }
- }
-
+ http_message_set_type(msg, Z_LVAL_P(value));
break;
case HTTP_MSG_PROPHASH_HTTP_VERSION:
convert_to_double_ex(&value);
- switch (msg->type)
- {
- case HTTP_MSG_REQUEST:
- msg->info.request.http_version = Z_DVAL_P(value);
- break;
-
- case HTTP_MSG_RESPONSE:
- msg->info.response.http_version = Z_DVAL_P(value);
- break;
- }
+ msg->http.version = Z_DVAL_P(value);
break;
case HTTP_MSG_PROPHASH_BODY:
break;
case HTTP_MSG_PROPHASH_REQUEST_METHOD:
- convert_to_string_ex(&value);
if (HTTP_MSG_TYPE(REQUEST, msg)) {
- if (msg->info.request.method) {
- efree(msg->info.request.method);
- }
- msg->info.request.method = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value));
+ convert_to_string_ex(&value);
+ STR_SET(msg->http.info.request.method, estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)));
}
break;
case HTTP_MSG_PROPHASH_REQUEST_URI:
- convert_to_string_ex(&value);
if (HTTP_MSG_TYPE(REQUEST, msg)) {
- if (msg->info.request.URI) {
- efree(msg->info.request.URI);
- }
- msg->info.request.URI = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value));
+ convert_to_string_ex(&value);
+ STR_SET(msg->http.info.request.URI, estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)));
}
break;
case HTTP_MSG_PROPHASH_RESPONSE_CODE:
- convert_to_long_ex(&value);
if (HTTP_MSG_TYPE(RESPONSE, msg)) {
- msg->info.response.code = Z_LVAL_P(value);
+ convert_to_long_ex(&value);
+ msg->http.info.response.code = Z_LVAL_P(value);
}
break;
+
+ case HTTP_MSG_PROPHASH_RESPONSE_STATUS:
+ if (HTTP_MSG_TYPE(RESPONSE, msg)) {
+ convert_to_string_ex(&value);
+ STR_SET(msg->http.info.response.status, estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)));
+ }
+
}
}
zend_hash_clean(OBJ_PROP(obj));
ASSOC_PROP(obj, long, "type", msg->type);
- ASSOC_STRINGL(obj, "body", PHPSTR_VAL(msg), PHPSTR_LEN(msg));
-
- MAKE_STD_ZVAL(headers);
- array_init(headers);
-
- zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
- ASSOC_PROP(obj, zval, "headers", headers);
+ ASSOC_PROP(obj, double, "httpVersion", msg->http.version);
switch (msg->type)
{
case HTTP_MSG_REQUEST:
- ASSOC_PROP(obj, double, "httpVersion", msg->info.request.http_version);
ASSOC_PROP(obj, long, "responseCode", 0);
- ASSOC_STRING(obj, "requestMethod", msg->info.request.method);
- ASSOC_STRING(obj, "requestUri", msg->info.request.URI);
+ ASSOC_STRINGL(obj, "responseStatus", "", 0);
+ ASSOC_STRING(obj, "requestMethod", msg->http.info.request.method);
+ ASSOC_STRING(obj, "requestUri", msg->http.info.request.URI);
break;
case HTTP_MSG_RESPONSE:
- ASSOC_PROP(obj, double, "httpVersion", msg->info.response.http_version);
- ASSOC_PROP(obj, long, "responseCode", msg->info.response.code);
- ASSOC_STRING(obj, "requestMethod", "");
- ASSOC_STRING(obj, "requestUri", "");
+ ASSOC_PROP(obj, long, "responseCode", msg->http.info.response.code);
+ ASSOC_STRING(obj, "responseStatus", msg->http.info.response.status);
+ ASSOC_STRINGL(obj, "requestMethod", "", 0);
+ ASSOC_STRINGL(obj, "requestUri", "", 0);
break;
case HTTP_MSG_NONE:
default:
- ASSOC_PROP(obj, double, "httpVersion", 0.0);
ASSOC_PROP(obj, long, "responseCode", 0);
- ASSOC_STRING(obj, "requestMethod", "");
- ASSOC_STRING(obj, "requestUri", "");
+ ASSOC_STRINGL(obj, "responseStatus", "", 0);
+ ASSOC_STRINGL(obj, "requestMethod", "", 0);
+ ASSOC_STRINGL(obj, "requestUri", "", 0);
break;
}
+ MAKE_STD_ZVAL(headers);
+ array_init(headers);
+ zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+ ASSOC_PROP(obj, zval, "headers", headers);
+ ASSOC_STRINGL(obj, "body", PHPSTR_VAL(msg), PHPSTR_LEN(msg));
+
return OBJ_PROP(obj);
}
RETURN_NULL();
}
- RETURN_LONG(obj->message->info.response.code);
+ RETURN_LONG(obj->message->http.info.response.code);
}
}
/* }}} */
RETURN_FALSE;
}
- obj->message->info.response.code = code;
+ obj->message->http.info.response.code = code;
RETURN_TRUE;
}
/* }}} */
RETURN_NULL();
}
- RETURN_STRING(obj->message->info.request.method, 1);
+ RETURN_STRING(obj->message->http.info.request.method, 1);
}
}
/* }}} */
RETURN_FALSE;
}
- STR_SET(obj->message->info.request.method, estrndup(method, method_len));
+ STR_SET(obj->message->http.info.request.method, estrndup(method, method_len));
RETURN_TRUE;
}
/* }}} */
RETURN_NULL();
}
- RETURN_STRING(obj->message->info.request.URI, 1);
+ RETURN_STRING(obj->message->http.info.request.URI, 1);
}
}
/* }}} */
RETURN_FALSE;
}
- STR_SET(obj->message->info.request.URI, estrndup(URI, URIlen));
+ STR_SET(obj->message->http.info.request.URI, estrndup(URI, URIlen));
RETURN_TRUE;
}
/* }}} */
double version;
getObject(http_message_object, obj);
- switch (obj->message->type)
- {
- case HTTP_MSG_RESPONSE:
- version = obj->message->info.response.http_version;
- break;
-
- case HTTP_MSG_REQUEST:
- version = obj->message->info.request.http_version;
- break;
-
- case HTTP_MSG_NONE:
- default:
- RETURN_NULL();
- }
- sprintf(ver, "%1.1lf", version);
+ sprintf(ver, "%1.1lf", obj->message->http.version);
RETURN_STRINGL(ver, 3, 1);
}
}
return;
}
- if (HTTP_MSG_TYPE(NONE, obj->message)) {
- http_error(HE_WARNING, HTTP_E_MESSAGE_TYPE, "Message is neither of type HTTP_MSG_RESPONSE nor HTTP_MSG_REQUEST");
- RETURN_FALSE;
- }
-
convert_to_double(zv);
sprintf(v, "%1.1lf", Z_DVAL_P(zv));
if (strcmp(v, "1.0") && strcmp(v, "1.1")) {
RETURN_FALSE;
}
- if (HTTP_MSG_TYPE(RESPONSE, obj->message)) {
- obj->message->info.response.http_version = Z_DVAL_P(zv);
- } else {
- obj->message->info.request.http_version = Z_DVAL_P(zv);
- }
+ obj->message->http.version = Z_DVAL_P(zv);
RETURN_TRUE;
}
/* }}} */
phpstr_fix(qstr);
HTTP_CURL_OPT(COOKIE, http_request_data_copy(COPY_STRING, qstr->data));
}
- phpstr_free(qstr);
+ phpstr_free(&qstr);
} else {
HTTP_CURL_OPT(COOKIE, NULL);
}
} while ((response = response->parent) && (request = request->parent));
- http_message_free(free_msg);
+ http_message_free(&free_msg);
phpstr_fix(&obj->history);
}
- UPD_PROP(obj, long, responseCode, msg->info.response.code);
+ UPD_PROP(obj, long, responseCode, msg->http.info.response.code);
MAKE_STD_ZVAL(headers)
array_init(headers);
zval **data;
FOREACH_VAL(*value, data) {
- http_send_header_ex(name, strlen(name), Z_STRVAL_PP(data), Z_STRLEN_PP(data), first);
+ http_send_header_ex(name, strlen(name), Z_STRVAL_PP(data), Z_STRLEN_PP(data), first, NULL);
first = 0;
}
} else {
- http_send_header_ex(name, strlen(name), Z_STRVAL_PP(value), Z_STRLEN_PP(value), 1);
+ http_send_header_ex(name, strlen(name), Z_STRVAL_PP(value), Z_STRLEN_PP(value), 1, NULL);
}
name = NULL;
}
{
zval *cd = GET_STATIC_PROP(contentDisposition);
if (Z_STRLEN_P(cd)) {
- http_send_header_ex("Content-Disposition", lenof("Content-Disposition"), Z_STRVAL_P(cd), Z_STRLEN_P(cd), 1);
+ http_send_header_ex("Content-Disposition", lenof("Content-Disposition"), Z_STRVAL_P(cd), Z_STRLEN_P(cd), 1, NULL);
}
}
/* }}} */
/* {{{ STATUS http_send_header(char *, char *, zend_bool) */
-PHP_HTTP_API STATUS _http_send_header_ex(const char *name, size_t name_len, const char *value, size_t value_len, zend_bool replace TSRMLS_DC)
+PHP_HTTP_API STATUS _http_send_header_ex(const char *name, size_t name_len, const char *value, size_t value_len, zend_bool replace, char **sent_header TSRMLS_DC)
{
STATUS ret;
- size_t header_len = sizeof(": ") + name_len + value_len;
+ size_t header_len = sizeof(": ") + name_len + value_len + 1;
char *header = emalloc(header_len + 1);
header[header_len] = '\0';
/* }}} */
/* {{{ STATUS http_send_last_modified(int) */
-PHP_HTTP_API STATUS _http_send_last_modified(time_t t TSRMLS_DC)
+PHP_HTTP_API STATUS _http_send_last_modified_ex(time_t t, char **sent_header TSRMLS_DC)
{
STATUS ret;
char *date = http_date(t);
return FAILURE;
}
- ret = http_send_header("Last-Modified", date, 1);
+ ret = http_send_header_ex("Last-Modified", lenof("Last-Modifed"), date, strlen(date), 1, sent_header);
efree(date);
/* remember */
/* }}} */
/* {{{ STATUS http_send_etag(char *, size_t) */
-PHP_HTTP_API STATUS _http_send_etag(const char *etag, size_t etag_len TSRMLS_DC)
+PHP_HTTP_API STATUS _http_send_etag_ex(const char *etag, size_t etag_len, char **sent_header TSRMLS_DC)
{
STATUS status;
char *etag_header;
etag_header = ecalloc(1, sizeof("ETag: \"\"") + etag_len);
sprintf(etag_header, "ETag: \"%s\"", etag);
status = http_send_header_string(etag_header);
- efree(etag_header);
+
+ if (sent_header) {
+ *sent_header = etag_header;
+ } else {
+ efree(etag_header);
+ }
+
return status;
}
/* }}} */
STR_FREE(HTTP_G(send).content_type);
HTTP_G(send).content_type = estrndup(content_type, ct_len);
- return http_send_header_ex("Content-Type", lenof("Content-Type"), content_type, ct_len, 1);
+ return http_send_header_ex("Content-Type", lenof("Content-Type"), content_type, ct_len, 1, NULL);
}
/* }}} */
if (!(etag = http_etag(data_ptr, data_size, data_mode))) {
http_error(HE_NOTICE, HTTP_E_RUNTIME, "Failed to generate ETag for data source");
} else {
- http_send_etag(etag, 32);
+ char *sent_header = NULL;
+
+ http_send_etag_ex(etag, 32, &sent_header);
if (http_match_etag("HTTP_IF_NONE_MATCH", etag)) {
- return http_cache_exit_ex(etag, 1, 1);
+ return http_exit_ex(304, sent_header, NULL, 0);
+ } else {
+ STR_FREE(sent_header);
}
efree(etag);
}
/* send 304 Not Modified if last modified matches */
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);
+ char *sent_header = NULL;
+ http_send_last_modified_ex(HTTP_G(send).last_modified, &sent_header);
+ return http_exit_ex(304, sent_header, NULL, 0);
}
/* emit a content-length header */
}
if (SUCCESS != http_urlencode_hash_implementation(hash, qstr, arg_sep)) {
- phpstr_free(qstr);
+ phpstr_free(&qstr);
return FAILURE;
}
phpstr_data(qstr, encoded_data, encoded_len);
- phpstr_free(qstr);
+ phpstr_free(&qstr);
return SUCCESS;
}
HTTP_ARG_VAL(encoded_string, 0)
HTTP_END_ARGS;
-HTTP_BEGIN_ARGS(splitResponse, 1)
- HTTP_ARG_VAL(response_string, 0)
+HTTP_BEGIN_ARGS(parseMessage, 1)
+ HTTP_ARG_VAL(message_string, 0)
HTTP_END_ARGS;
HTTP_BEGIN_ARGS(parseHeaders, 1)
HTTP_UTIL_ALIAS(matchEtag, http_match_etag)
HTTP_UTIL_ALIAS(matchRequestHeader, http_match_request_header)
HTTP_UTIL_ALIAS(chunkedDecode, http_chunked_decode)
- HTTP_UTIL_ALIAS(splitResponse, http_split_response)
+ HTTP_UTIL_ALIAS(parseMessage, http_parse_message)
HTTP_UTIL_ALIAS(parseHeaders, http_parse_headers)
HTTP_UTIL_ALIAS(authBasic, http_auth_basic)
HTTP_UTIL_ALIAS(authBasicCallback, http_auth_basic_cb)
return retval;
}
-int trash(zend_class_entry *scope, char *name, size_t name_len, zval *value TSRMLS_DC)
-{
- int retval;
- zval **property = NULL;
- zend_class_entry *old_scope = EG(scope);
-
- EG(scope) = scope;
-
- if (!(property = zend_std_get_static_property(scope, name, name_len, 0 TSRMLS_CC))) {
- retval = FAILURE;
- } else if (*property == value) {
- retval = SUCCESS;
- } else if (scope->type & ZEND_INTERNAL_CLASS) {
- int refcount;
- zend_uchar is_ref;
-
- refcount = (*property)->refcount;
- is_ref = (*property)->is_ref;
-
- /* clean */
- switch (Z_TYPE_PP(property))
- {
- case IS_BOOL: case IS_LONG: case IS_NULL:
- break;
-
- case IS_RESOURCE:
- zend_list_delete(Z_LVAL_PP(property));
- break;
-
- case IS_STRING: case IS_CONSTANT:
- free(Z_STRVAL_PP(property));
- break;
-
- case IS_OBJECT:
- if (Z_OBJ_HT_PP(property)->del_ref) {
- Z_OBJ_HT_PP(property)->del_ref(*property TSRMLS_CC);
- }
- break;
-
- case IS_ARRAY: case IS_CONSTANT_ARRAY:
- if (Z_ARRVAL_PP(property) && Z_ARRVAL_PP(property) != &EG(symbol_table)) {
- zend_hash_destroy(Z_ARRVAL_PP(property));
- free(Z_ARRVAL_PP(property));
- }
- break;
- }
-
- /* copy */
- **property = *value;
-
- /* ctor */
- switch (Z_TYPE_PP(property))
- {
- case IS_BOOL: case IS_LONG: case IS_NULL:
- break;
-
- case IS_RESOURCE:
- zend_list_addref(Z_LVAL_PP(property));
- break;
-
- case IS_STRING: case IS_CONSTANT:
- Z_STRVAL_PP(property) = (char *) zend_strndup(Z_STRVAL_PP(property), Z_STRLEN_PP(property));
- break;
-
- case IS_OBJECT:
- if (Z_OBJ_HT_PP(property)->add_ref) {
- Z_OBJ_HT_PP(property)->add_ref(*property TSRMLS_CC);
- }
- break;
-
- case IS_ARRAY: case IS_CONSTANT_ARRAY:
- {
- if (Z_ARRVAL_PP(property) != &EG(symbol_table)) {
- zval *tmp;
- HashTable *old = Z_ARRVAL_PP(property);
-
- Z_ARRVAL_PP(property) = (HashTable *) malloc(sizeof(HashTable));
- zend_hash_init(Z_ARRVAL_PP(property), 0, NULL, ZVAL_PTR_DTOR, 0);
- zend_hash_copy(Z_ARRVAL_PP(property), old, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
- }
- }
- break;
- }
-
- (*property)->refcount = refcount;
- (*property)->is_ref = is_ref;
-
- retval = SUCCESS;
-
- } else {
- if (PZVAL_IS_REF(*property)) {
- zval_dtor(*property);
- (*property)->type = value->type;
- (*property)->value = value->value;
-
- if (value->refcount) {
- zval_copy_ctor(*property);
- }
-
- retval = SUCCESS;
- } else {
- value->refcount++;
- if (PZVAL_IS_REF(value)) {
- SEPARATE_ZVAL(&value);
- }
-
- retval = zend_hash_update(scope->static_members, name, name_len, &value, sizeof(zval *), NULL);
- }
- }
-
- if (!value->refcount) {
- zval_dtor(value);
- FREE_ZVAL(value);
- }
-
- EG(scope) = old_scope;
-
- return retval;
-}
-
int zend_update_static_property_bool(zend_class_entry *scope, char *name, size_t name_len, zend_bool value TSRMLS_DC)
{
zval *tmp = tmp_zval();
} etag;
struct _http_globals_log {
+ char *auth;
char *cache;
+ char *redirect;
+ char *allowed_methods;
+ char *composite;
} log;
struct _http_globals_send {
} methods;
#ifdef HTTP_HAVE_CURL
- struct _http_globlas_request_copies {
+ struct _http_globals_request_copies {
zend_llist strings;
zend_llist slists;
zend_llist contexts;
PHP_FUNCTION(http_send_file);
PHP_FUNCTION(http_send_stream);
PHP_FUNCTION(http_chunked_decode);
-PHP_FUNCTION(http_split_response);
PHP_FUNCTION(http_parse_message);
PHP_FUNCTION(http_parse_headers);
PHP_FUNCTION(http_get_request_headers);
#define http_error_ex _http_error_ex
extern void _http_error_ex(long type, long code, const char *format, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4);
-#define http_exit(s, h) http_exit_ex((s), (h), 1)
-#define http_exit_ex(s, h, f) _http_exit_ex((s), (h), (f) TSRMLS_CC)
-extern STATUS _http_exit_ex(int status, char *header, zend_bool free_header TSRMLS_DC);
+#define http_exit(s, h) http_exit_ex((s), (h), NULL, 1)
+#define http_exit_ex(s, h, b, e) _http_exit_ex((s), (h), (b), (e) TSRMLS_CC)
+extern STATUS _http_exit_ex(int status, char *header, char *body, zend_bool send_header TSRMLS_DC);
#define http_check_method(m) http_check_method_ex((m), HTTP_KNOWN_METHODS)
#define http_check_method_ex(m, a) _http_check_method_ex((m), (a))
#define http_chunked_decode(e, el, d, dl) _http_chunked_decode((e), (el), (d), (dl) TSRMLS_CC)
PHP_HTTP_API const char *_http_chunked_decode(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len TSRMLS_DC);
-#define http_split_response(r, rl, h, b, bl) _http_split_response((r), (rl), (h), (b), (bl) TSRMLS_CC)
-PHP_HTTP_API STATUS _http_split_response(char *response, size_t repsonse_len, HashTable *headers, char **body, size_t *body_len TSRMLS_DC);
+#define http_locate_body _http_locate_body
+static inline const char *_http_locate_body(const char *message)
+{
+ const char *cr = strstr(message, "\r\n\r\n");
+ const char *lf = strstr(message, "\n\n");
+
+ if (lf && cr) {
+ return MIN(lf + 2, cr + 4);
+ } else if (lf || cr) {
+ return MAX(lf + 2, cr + 4);
+ } else {
+ return NULL;
+ }
+}
#endif
#include "php_http_api.h"
#include "php_http_send_api.h"
-#define http_cache_exit(t, e) http_cache_exit_ex((t), (e), 1)
-#define http_cache_exit_ex(t, e, f) _http_cache_exit_ex((t), (e), (f) TSRMLS_CC)
-extern STATUS _http_cache_exit_ex(char *cache_token, zend_bool etag, zend_bool free_token TSRMLS_DC);
-
#define http_etag(p, l, m) _http_etag((p), (l), (m) TSRMLS_CC)
PHP_HTTP_API char *_http_etag(const void *data_ptr, size_t data_len, http_send_mode data_mode TSRMLS_DC);
#define PHP_HTTP_HEADERS_API_H
#include "php_http_std_defs.h"
+#include "php_http_info_api.h"
typedef enum {
RANGE_OK,
RANGE_ERR
} http_range_status;
-typedef void (*http_parse_headers_callback_t)(const char *http_line, HashTable **headers, void **callback_data TSRMLS_DC);
-
-#define http_parse_headers_default_callback _http_parse_headers_default_callback
-PHP_HTTP_API void _http_parse_headers_default_callback(const char *http_line, HashTable **headers, void **cb_data TSRMLS_DC);
-
-#define http_parse_headers(h, a) _http_parse_headers_ex((h), Z_ARRVAL_P(a), 1, _http_parse_headers_default_callback, NULL TSRMLS_CC)
-#define http_parse_headers_ex(h, ht, p) _http_parse_headers_ex((h), (ht), (p), _http_parse_headers_default_callback, NULL TSRMLS_CC)
+#define http_parse_headers(h, a) _http_parse_headers_ex((h), Z_ARRVAL_P(a), 1, http_info_default_callback, NULL TSRMLS_CC)
+#define http_parse_headers_ex(h, ht, p) _http_parse_headers_ex((h), (ht), (p), http_info_default_callback, NULL TSRMLS_CC)
#define http_parse_headers_cb(h, ht, p, f, d) _http_parse_headers_ex((h), (ht), (p), (f), (d) TSRMLS_CC)
-PHP_HTTP_API STATUS _http_parse_headers_ex(const char *header, HashTable *headers, zend_bool prettify, http_parse_headers_callback_t func, void **callback_data TSRMLS_DC);
+PHP_HTTP_API STATUS _http_parse_headers_ex(const char *header, HashTable *headers, zend_bool prettify, http_info_callback callback_func, void **callback_data TSRMLS_DC);
#define http_get_request_headers(h) _http_get_request_headers_ex(Z_ARRVAL_P(h), 1 TSRMLS_CC)
#define http_get_request_headers_ex(h, p) _http_get_request_headers_ex((h), (p) TSRMLS_CC)
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PECL :: http |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.0 of the PHP license, that |
+ | is bundled with this package in the file LICENSE, and is available |
+ | through the world-wide-web at http://www.php.net/license/3_0.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2004-2005 Michael Wallner <mike@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_HTTP_INFO_API_H
+#define PHP_HTTP_INFO_API_H
+
+#define IS_HTTP_REQUEST 1
+#define IS_HTTP_RESPONSE 2
+
+#define HTTP_INFO(ptr) (ptr)->http.info
+
+typedef struct {
+ char *method;
+ char *URI;
+} http_request_info;
+
+typedef struct {
+ int code;
+ char *status;
+} http_response_info;
+
+typedef union {
+ http_request_info request;
+ http_response_info response;
+} http_info_t;
+
+struct http_info {
+ http_info_t info;
+ double version;
+};
+
+typedef struct {
+ struct http_info http;
+ int type;
+} http_info;
+
+typedef void (*http_info_callback)(void **callback_data, HashTable **headers, http_info *info TSRMLS_DC);
+
+#define http_info_default_callback _http_info_default_callback
+PHP_HTTP_API void _http_info_default_callback(void **nothing, HashTable **headers, http_info *info TSRMLS_DC);
+#define http_info_dtor _http_info_dtor
+PHP_HTTP_API void _http_info_dtor(http_info *info);
+#define http_info_parse(p, i) _http_info_parse_ex((p), (i), 1 TSRMLS_CC)
+#define http_info_parse_ex(p, i, s) _http_info_parse_ex((p), (i), (s) TSRMLS_CC)
+PHP_HTTP_API STATUS _http__infoparse_ex(const char *pre_header, http_info *info , zend_bool silent 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
+ */
+
#ifndef PHP_HTTP_MESSAGE_API_H
#define PHP_HTTP_MESSAGE_API_H
+#include "php_http_info_api.h"
#include "phpstr/phpstr.h"
typedef enum {
- HTTP_MSG_NONE,
- HTTP_MSG_REQUEST,
- HTTP_MSG_RESPONSE
+ HTTP_MSG_NONE = 0,
+ HTTP_MSG_REQUEST = IS_HTTP_REQUEST,
+ HTTP_MSG_RESPONSE = IS_HTTP_RESPONSE,
} http_message_type;
typedef struct _http_message http_message;
phpstr body;
HashTable hdrs;
http_message_type type;
-
- union {
- struct {
- double http_version;
- char *method;
- char *URI;
- } request;
-
- struct {
- double http_version;
- int code;
- } response;
-
- } info;
-
+ struct http_info http;
http_message *parent;
};
-/* required minimum length of an HTTP message "HTTP/1.1 200\r\n" */
-#define HTTP_MSG_MIN_SIZE 15
+/* required minimum length of an HTTP message "HTTP/1.1" */
+#define HTTP_MSG_MIN_SIZE 8
/* shorthand for type checks */
#define HTTP_MSG_TYPE(TYPE, msg) ((msg) && ((msg)->type == HTTP_MSG_ ##TYPE))
#define http_message_serialize(m, s, l) _http_message_serialize((m), (s), (l))
PHP_HTTP_API void _http_message_serialize(http_message *message, char **string, size_t *length);
+#define http_message_tostruct_recursive(m, s) _http_message_tostruct_recursive((m), (s) TSRMLS_CC)
+PHP_HTTP_API void _http_message_tostruct_recursive(http_message *msg, zval *strct TSRMLS_DC);
+
#define http_message_send(m) _http_message_send((m) TSRMLS_CC)
PHP_HTTP_API STATUS _http_message_send(http_message *message TSRMLS_DC);
PHP_HTTP_API void _http_message_dtor(http_message *message);
#define http_message_free(m) _http_message_free((m))
-PHP_HTTP_API void _http_message_free(http_message *message);
+PHP_HTTP_API void _http_message_free(http_message **message);
#endif
#define http_send_status(s) sapi_header_op(SAPI_HEADER_SET_STATUS, (void *) (s) TSRMLS_CC)
#define http_send_header(n, v, r) _http_send_header_ex((n), strlen(n), (v), strlen(v), (r) TSRMLS_CC)
-#define http_send_header_ex(n, nl, v, vl, r) _http_send_header_ex((n), (nl), (v), (vl), (r) TSRMLS_CC)
-PHP_HTTP_API STATUS _http_send_header_ex(const char *name, size_t name_len, const char *value, size_t value_len, zend_bool replace TSRMLS_DC);
+#define http_send_header_ex(n, nl, v, vl, r, s) _http_send_header_ex((n), (nl), (v), (vl), (r), (s) TSRMLS_CC)
+PHP_HTTP_API STATUS _http_send_header_ex(const char *name, size_t name_len, const char *value, size_t value_len, zend_bool replace, char **sent_header TSRMLS_DC);
#define http_send_header_string(h) _http_send_status_header_ex(0, (h), 1 TSRMLS_CC)
#define http_send_header_string_ex(h, r) _http_send_status_header_ex(0, (h), (r) TSRMLS_CC)
#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);
+#define http_send_last_modified(t) _http_send_last_modified_ex((t), NULL TSRMLS_CC)
+#define http_send_last_modified_ex(t, s) _http_send_last_modified_ex((t), (s) TSRMLS_CC)
+PHP_HTTP_API STATUS _http_send_last_modified_ex(time_t t, char **sent_header TSRMLS_DC);
-#define http_send_etag(e, l) _http_send_etag((e), (l) TSRMLS_CC)
-PHP_HTTP_API STATUS _http_send_etag(const char *etag, size_t etag_len TSRMLS_DC);
+#define http_send_etag(e, l) _http_send_etag_ex((e), (l), NULL TSRMLS_CC)
+#define http_send_etag_ex(e, l, s) _http_send_etag_ex((e), (l), (s) TSRMLS_CC)
+PHP_HTTP_API STATUS _http_send_etag_ex(const char *etag, size_t etag_len, char **sent_header TSRMLS_DC);
-#define http_send_cache_control(cc, cl) http_send_header_ex("Cache-Control", lenof("Cache-Control"), (cc), (cl), 1)
+#define http_send_cache_control(cc, cl) http_send_header_ex("Cache-Control", lenof("Cache-Control"), (cc), (cl), 1, NULL)
#define http_send_content_type(c, l) _http_send_content_type((c), (l) TSRMLS_CC)
PHP_HTTP_API STATUS _http_send_content_type(const char *content_type, size_t ct_len TSRMLS_DC);
/* lenof() */
#define lenof(S) (sizeof(S) - 1)
+#ifndef MIN
+# define MIN(a,b) (a<b?a:b)
+#endif
+#ifndef MAX
+# define MAX(a,b) (a>b?a:b)
+#endif
+
/* STR_SET() */
-#define STR_SET(target, source) \
- if(target) efree(target); \
- target = source
+#ifndef STR_SET
+# define STR_SET(STR, SET) \
+ { \
+ STR_FREE(STR); \
+ STR = SET; \
+ }
+#endif
/* return bool (v == SUCCESS) */
#define RETVAL_SUCCESS(v) RETVAL_BOOL(SUCCESS == (v))
PHP_METHOD(HttpUtil, matchModified);
PHP_METHOD(HttpUtil, matchEtag);
PHP_METHOD(HttpUtil, chunkedDecode);
-PHP_METHOD(HttpUtil, splitResponse);
PHP_METHOD(HttpUtil, parseHeaders);
+PHP_METHOD(HttpUril, parseMessage);
PHP_METHOD(HttpUtil, authBasic);
PHP_METHOD(HttpUtil, authBasicCallback);
PHPSTR_API void phpstr_dtor(phpstr *buf)
{
- if (buf->data) {
- efree(buf->data);
- buf->data = NULL;
- }
+ STR_SET(buf->data, NULL);
buf->used = 0;
buf->free = 0;
}
-PHPSTR_API void phpstr_free(phpstr *buf)
+PHPSTR_API void phpstr_free(phpstr **buf)
{
- if (buf) {
- phpstr_dtor(buf);
- efree(buf);
+ if (*buf) {
+ phpstr_dtor(*buf);
+ efree(*buf);
+ *buf = NULL;
}
}
#include "php.h"
+#ifndef STR_SET
+# define STR_SET(STR, SET) \
+ { \
+ STR_FREE(STR); \
+ STR = SET; \
+ }
+#endif
+
#if defined(PHP_WIN32)
# if defined(PHPSTR_EXPORTS)
# define PHPSTR_API __declspec(dllexport)
#define FREE_PHPSTR_PTR(STR) efree(STR)
#define FREE_PHPSTR_VAL(STR) phpstr_dtor(STR)
-#define FREE_PHPSTR_ALL(STR) phpstr_free(STR)
+#define FREE_PHPSTR_ALL(STR) phpstr_free(&(STR))
#define FREE_PHPSTR(free, STR) \
switch (free) \
{ \
+ case PHPSTR_FREE_NOT: break; \
case PHPSTR_FREE_PTR: efree(STR); break; \
case PHPSTR_FREE_VAL: phpstr_dtor(STR); break; \
- case PHPSTR_FREE_ALL: phpstr_free(STR); break; \
- case PHPSTR_FREE_NOT: break; \
+ case PHPSTR_FREE_ALL: \
+ { \
+ phpstr *PTR = (STR); \
+ phpstr_free(&PTR); \
+ } \
+ break; \
default: break; \
}
#define RETURN_PHPSTR_PTR(STR) RETURN_PHPSTR((STR), PHPSTR_FREE_PTR, 0)
-#define RETURN_PHPSTR_VAL(STR) RETURN_PHPSTR(&(STR), PHPSTR_FREE_NOT, 0)
+#define RETURN_PHPSTR_VAL(STR) RETURN_PHPSTR((STR), PHPSTR_FREE_NOT, 0)
#define RETVAL_PHPSTR_PTR(STR) RETVAL_PHPSTR((STR), PHPSTR_FREE_PTR, 0)
-#define RETVAL_PHPSTR_VAL(STR) RETVAL_PHPSTR(&(STR), PHPSTR_FREE_NOT, 0)
+#define RETVAL_PHPSTR_VAL(STR) RETVAL_PHPSTR((STR), PHPSTR_FREE_NOT, 0)
/* RETURN_PHPSTR(buf, PHPSTR_FREE_PTR, 0) */
#define RETURN_PHPSTR(STR, free, dup) \
RETVAL_PHPSTR((STR), (free), (dup)); \
PHPSTR_API void phpstr_dtor(phpstr *buf);
/* free a phpstr object completely */
-PHPSTR_API void phpstr_free(phpstr *buf);
+PHPSTR_API void phpstr_free(phpstr **buf);
#endif
+++ /dev/null
---TEST--
-http_split_response()
---SKIPIF--
-<?php
-include 'skip.inc';
-?>
---FILE--
-<?php
-echo "-TEST\n";
-$data = "HTTP/1.1 200 Ok\r\nContent-Type: text/plain\r\nContent-Language: de-AT\r\nDate: Sat, 22 Jan 2005 18:10:02 GMT\r\n\r\nHallo Du!";
-var_export(http_split_response($data));
-echo "\nDone\n";
-?>
---EXPECTF--
-%sTEST
-array (
- 0 =>
- array (
- 'Response Status' => '200 Ok',
- 'Content-Type' => 'text/plain',
- 'Content-Language' => 'de-AT',
- 'Date' => 'Sat, 22 Jan 2005 18:10:02 GMT',
- ),
- 1 => 'Hallo Du!',
-)
-Done
-
+++ /dev/null
---TEST--
-http_split_response() list bug (mem-leaks)
---SKIPIF--
-<?php
-include 'skip.inc';
-?>
---FILE--
-<?php
-echo "Try\n";
-$data = "HTTP/1.1 200 Ok\r\nContent-Type: text/plain\r\nContent-Language: de-AT\r\nDate: Sat, 22 Jan 2005 18:10:02 GMT\r\n\r\nHallo Du!";
-class t {
- var $r = array();
- function fail($data) {
- list($this->r['headers'], $this->r['body']) = http_split_response($data);
- }
-}
-
-$t = new t;
-$t->fail($data);
-echo "Done\n";
-?>
---EXPECTF--
-%sTry
-Done