X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=blobdiff_plain;f=http_headers_api.c;h=c778662f5f2029cd36760c883e7fd98512882bc2;hp=b2a2081e18ae79bd5cf8a1c601befd238972a08f;hb=669d2e6a8bdc642b6b52693f4593f199ddd7e8d2;hpb=94e87723fd916f0fe9e72f2280433b06e295bf79 diff --git a/http_headers_api.c b/http_headers_api.c index b2a2081..c778662 100644 --- a/http_headers_api.c +++ b/http_headers_api.c @@ -1,37 +1,28 @@ /* - +----------------------------------------------------------------------+ - | 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 | - +----------------------------------------------------------------------+ + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2006, Michael Wallner | + +--------------------------------------------------------------------+ */ /* $Id$ */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#include "php.h" +#include "php_http.h" -#include "ext/standard/php_string.h" #include "ext/standard/url.h" +#include "ext/standard/php_string.h" -#include "php_http.h" -#include "php_http_std_defs.h" #include "php_http_api.h" #include "php_http_headers_api.h" -#include "php_http_info_api.h" -#include - -ZEND_EXTERN_MODULE_GLOBALS(http); +#ifndef HTTP_DBG_NEG +# define HTTP_DBG_NEG 0 +#endif /* {{{ static int http_sort_q(const void *, const void *) */ static int http_sort_q(const void *a, const void *b TSRMLS_DC) @@ -52,55 +43,142 @@ static int http_sort_q(const void *a, const void *b TSRMLS_DC) } /* }}} */ -/* {{{ char *http_negotiate_q(char *, HashTable *, char *) */ -PHP_HTTP_API char *_http_negotiate_q(const char *entry, const HashTable *supported, const char *def TSRMLS_DC) +/* {{{ char *http_negotiate_language_func */ +char *_http_negotiate_language_func(const char *test, double *quality, HashTable *supported TSRMLS_DC) { - zval *zaccept, zdelim, zarray, zentries, **zentry, **zsupp; - char *q_ptr = NULL, *key = NULL; - int i = 0; - ulong idx = 0; - double qual; - - HTTP_GSC(zaccept, entry, estrdup(def)); - - array_init(&zarray); - array_init(&zentries); - - Z_STRVAL(zdelim) = ","; - Z_STRLEN(zdelim) = 1; - - php_explode(&zdelim, zaccept, &zarray, -1); - - FOREACH_HASH_VAL(Z_ARRVAL(zarray), zentry) { - if (q_ptr = strrchr(Z_STRVAL_PP(zentry), ';')) { - qual = strtod(q_ptr + 3, NULL); - *q_ptr = 0; - q_ptr = NULL; - } else { - qual = 1000.0 - i++; + zval **value; + HashPosition pos; + const char *dash_test; + + FOREACH_HASH_VAL(pos, supported, value) { +#if HTTP_DBG_NEG + fprintf(stderr, "strcasecmp('%s', '%s')\n", Z_STRVAL_PP(value), test); +#endif + if (!strcasecmp(Z_STRVAL_PP(value), test)) { + return Z_STRVAL_PP(value); } - /* TODO: support primaries only, too */ - FOREACH_HASH_VAL((HashTable *)supported, zsupp) { - if (!strcasecmp(Z_STRVAL_PP(zsupp), Z_STRVAL_PP(zentry))) { - add_assoc_double(&zentries, Z_STRVAL_PP(zsupp), qual); - break; + } + + /* no distinct match found, so try primaries */ + if ((dash_test = strchr(test, '-'))) { + FOREACH_HASH_VAL(pos, supported, value) { + int len = dash_test - test; +#if HTTP_DBG_NEG + fprintf(stderr, "strncasecmp('%s', '%s', %d)\n", Z_STRVAL_PP(value), test, len); +#endif + if ( (!strncasecmp(Z_STRVAL_PP(value), test, len)) && + ( (Z_STRVAL_PP(value)[len] == '\0') || + (Z_STRVAL_PP(value)[len] == '-'))) { + *quality *= .9; + return Z_STRVAL_PP(value); } } } - zval_dtor(&zarray); - - zend_hash_sort(Z_ARRVAL(zentries), zend_qsort, http_sort_q, 0 TSRMLS_CC); + + return NULL; +} +/* }}} */ - FOREACH_HASH_KEY(Z_ARRVAL(zentries), key, idx) { - if (key) { - key = estrdup(key); - zval_dtor(&zentries); - return key; +/* {{{ char *http_negotiate_default_func */ +char *_http_negotiate_default_func(const char *test, double *quality, HashTable *supported TSRMLS_DC) +{ + zval **value; + HashPosition pos; + + FOREACH_HASH_VAL(pos, supported, value) { +#if HTTP_DBG_NEG + fprintf(stderr, "strcasecmp('%s', '%s')\n", Z_STRVAL_PP(value), test); +#endif + if (!strcasecmp(Z_STRVAL_PP(value), test)) { + return Z_STRVAL_PP(value); } } - zval_dtor(&zentries); + + return NULL; +} +/* }}} */ - return estrdup(def); +/* {{{ HashTable *http_negotiate_q(const char *, HashTable *, negotiate_func_t) */ +PHP_HTTP_API HashTable *_http_negotiate_q(const char *header, HashTable *supported, negotiate_func_t neg TSRMLS_DC) +{ + zval *accept; + HashTable *result = NULL; + +#if HTTP_DBG_NEG + fprintf(stderr, "Reading header %s: ", header); +#endif + HTTP_GSC(accept, header, NULL); +#if HTTP_DBG_NEG + fprintf(stderr, "%s\n", Z_STRVAL_P(accept)); +#endif + + if (Z_STRLEN_P(accept)) { + zval ex_arr, ex_del; + + INIT_PZVAL(&ex_del); + INIT_PZVAL(&ex_arr); + ZVAL_STRINGL(&ex_del, ",", 1, 0); + array_init(&ex_arr); + + php_explode(&ex_del, accept, &ex_arr, -1); + + if (zend_hash_num_elements(Z_ARRVAL(ex_arr)) > 0) { + int i = 0; + HashPosition pos; + zval **entry, array; + + INIT_PZVAL(&array); + array_init(&array); + + FOREACH_HASH_VAL(pos, Z_ARRVAL(ex_arr), entry) { + int ident_len; + double quality; + char *selected, *identifier, *freeme; + const char *separator; + +#if HTTP_DBG_NEG + fprintf(stderr, "Checking %s\n", Z_STRVAL_PP(entry)); +#endif + + if ((separator = strchr(Z_STRVAL_PP(entry), ';'))) { + const char *ptr = separator; + + while (*++ptr && !isdigit(*ptr) && '.' != *ptr); + + quality = atof(ptr); + identifier = estrndup(Z_STRVAL_PP(entry), ident_len = separator - Z_STRVAL_PP(entry)); + } else { + quality = 1000.0 - i++; + identifier = estrndup(Z_STRVAL_PP(entry), ident_len = Z_STRLEN_PP(entry)); + } + freeme = identifier; + + while (isspace(*identifier)) { + ++identifier; + --ident_len; + } + while (ident_len && isspace(identifier[ident_len - 1])) { + identifier[--ident_len] = '\0'; + } + + if ((selected = neg(identifier, &quality, supported TSRMLS_CC))) { + /* don't overwrite previously set with higher quality */ + if (!zend_hash_exists(Z_ARRVAL(array), selected, strlen(selected) + 1)) { + add_assoc_double(&array, selected, quality); + } + } + + efree(freeme); + } + + result = Z_ARRVAL(array); + zend_hash_sort(result, zend_qsort, http_sort_q, 0 TSRMLS_CC); + } + + zval_dtor(&ex_arr); + } + + return result; } /* }}} */ @@ -253,13 +331,17 @@ PHP_HTTP_API STATUS _http_parse_headers_ex(const char *header, HashTable *header size_t header_len; zval array; - Z_ARRVAL(array) = headers; - header_len = body ? body - header : strlen(header) + 1; + INIT_ZARR(array, headers); + + if (body) { + header_len = body - header; + } else { + header_len = strlen(header) + 1; + } line = header; - - while (header_len >= (size_t) (line - begin)) { + + if (header_len) do { int value_len = 0; - switch (*line++) { case ':': @@ -271,7 +353,7 @@ PHP_HTTP_API STATUS _http_parse_headers_ex(const char *header, HashTable *header case 0: --value_len; /* we don't have CR so value length is one char less */ case '\n': - if ((!(*line - 1)) || ((*line != ' ') && (*line != '\t'))) { + if ((!*(line - 1)) || ((*line != ' ') && (*line != '\t'))) { http_info i; /* response/request line */ @@ -310,7 +392,7 @@ PHP_HTTP_API STATUS _http_parse_headers_ex(const char *header, HashTable *header } /* if we already have got such a header make an array of those */ - if (SUCCESS == zend_hash_find(headers, key, keylen + 1, (void **) &previous)) { + if (SUCCESS == zend_hash_find(headers, key, keylen + 1, (void *) &previous)) { /* convert to array */ if (Z_TYPE_PP(previous) != IS_ARRAY) { convert_to_array(*previous); @@ -328,7 +410,8 @@ PHP_HTTP_API STATUS _http_parse_headers_ex(const char *header, HashTable *header } break; } - } + } while (header_len > (size_t) (line - begin)); + return SUCCESS; } /* }}} */ @@ -338,23 +421,40 @@ PHP_HTTP_API void _http_get_request_headers_ex(HashTable *headers, zend_bool pre { char *key = NULL; ulong idx = 0; + uint keylen = 0; zval array, **hsv; + HashPosition pos; Z_ARRVAL(array) = headers; - - 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; +#ifdef ZEND_ENGINE_2 + zend_is_auto_global("_SERVER", lenof("_SERVER") TSRMLS_CC); +#endif + if (SUCCESS == zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void *) &hsv)) { + FOREACH_KEYLEN(pos, *hsv, key, keylen, idx) { + if (key && keylen > 6 && !strncmp(key, "HTTP_", 5)) { + zval **header, *orig; key += 5; + keylen -= 6; if (prettify) { - key = pretty_key(key, strlen(key), 1, 1); + key = pretty_key(estrndup(key, keylen), keylen, 1, 1); } - zend_hash_get_current_data(Z_ARRVAL_PP(hsv), (void **) &header); + zend_hash_get_current_data_ex(Z_ARRVAL_PP(hsv), (void *) &header, &pos); + + orig = *header; + convert_to_string_ex(header); add_assoc_stringl(&array, key, Z_STRVAL_PP(header), Z_STRLEN_PP(header), 1); + if (orig != *header) { + zval_ptr_dtor(header); + } + + if (prettify) { + efree(key); + } + key = NULL; + keylen = 0; } } } @@ -364,26 +464,19 @@ PHP_HTTP_API void _http_get_request_headers_ex(HashTable *headers, zend_bool pre /* {{{ zend_bool http_match_request_header(char *, char *) */ PHP_HTTP_API zend_bool _http_match_request_header_ex(const char *header, const char *value, zend_bool match_case TSRMLS_DC) { - char *name, *key = NULL; - ulong idx; + char *name; + uint name_len = strlen(header); zend_bool result = 0; HashTable headers; + zval **data; - name = pretty_key(estrdup(header), strlen(header), 1, 1); + name = pretty_key(estrndup(header, name_len), name_len, 1, 1); zend_hash_init(&headers, 0, NULL, ZVAL_PTR_DTOR, 0); http_get_request_headers_ex(&headers, 1); - FOREACH_HASH_KEY(&headers, key, idx) { - if (key && (!strcmp(key, name))) { - zval **data; - - if (SUCCESS == zend_hash_get_current_data(&headers, (void **) &data)) { - result = (match_case ? strcmp(Z_STRVAL_PP(data), value) : strcasecmp(Z_STRVAL_PP(data), value)) ? 0 : 1; - } - break; - } + if (SUCCESS == zend_hash_find(&headers, name, name_len+1, (void *) &data)) { + result = (match_case ? strcmp(Z_STRVAL_PP(data), value) : strcasecmp(Z_STRVAL_PP(data), value)) ? 0 : 1; } - zend_hash_destroy(&headers); efree(name);