From 930417f55598b5b4c54b44e20935450210454fdf Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Sat, 19 Nov 2005 16:50:16 +0000 Subject: [PATCH] - add http_negotiate_content_type() - fix bug in negotiator if accept headers contain spaces --- http.c | 1 + http_functions.c | 38 ++++++++++++++++++++++++++++++++++++++ http_headers_api.c | 22 ++++++++++++++++------ package2.xml | 8 +++++--- php_http.h | 1 + php_http_headers_api.h | 3 +++ tests/negotiation_001.phpt | 14 ++++++++++++++ 7 files changed, 78 insertions(+), 9 deletions(-) diff --git a/http.c b/http.c index 567d456..ffbae18 100644 --- a/http.c +++ b/http.c @@ -82,6 +82,7 @@ zend_function_entry http_functions[] = { PHP_FALIAS(http_absolute_uri, http_build_uri, NULL) PHP_FE(http_negotiate_language, http_arg_pass_ref_2) PHP_FE(http_negotiate_charset, http_arg_pass_ref_2) + PHP_FE(http_negotiate_content_type, http_arg_pass_ref_2) PHP_FE(http_redirect, NULL) PHP_FE(http_throttle, NULL) PHP_FE(http_send_status, NULL) diff --git a/http_functions.c b/http_functions.c index 9156ccc..e731d9a 100644 --- a/http_functions.c +++ b/http_functions.c @@ -251,6 +251,44 @@ PHP_FUNCTION(http_negotiate_charset) } /* }}} */ +/* {{{ proto string http_negotiate_ctype(array supported[, array &result]) + * + * This function negotiates the clients preferred content type based on its + * Accept HTTP header. The qualifier is recognized and content types + * without qualifier are rated highest. + * + * Expects an array as parameter cotaining the supported content types as values. + * If the optional second parameter is supplied, it will be filled with an + * array containing the negotiation results. + * + * Returns the negotiated content type or the default content type + * (i.e. first array entry) if none match. + * + * Example: + *
+ * 
+ * 
+ */ +PHP_FUNCTION(http_negotiate_content_type) +{ + zval *supported, *rs_array = NULL; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|z", &supported, &rs_array)) { + RETURN_FALSE; + } + + if (rs_array) { + zval_dtor(rs_array); + array_init(rs_array); + } + + HTTP_DO_NEGOTIATE(content_type, supported, rs_array); +} +/* }}} */ + /* {{{ proto bool http_send_status(int status) * * Send HTTP status code. diff --git a/http_headers_api.c b/http_headers_api.c index c4d23c8..3cb9c91 100644 --- a/http_headers_api.c +++ b/http_headers_api.c @@ -86,7 +86,7 @@ char *_http_negotiate_language_func(const char *test, double *quality, HashTable FOREACH_HASH_VAL(pos, supported, value) { int len = dash_test - test; #if HTTP_DBG_NEG - fprintf(stderr, "strncascmp('%s', '%s', %d)\n", Z_STRVAL_PP(value), test, len); + 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') || @@ -153,8 +153,9 @@ PHP_HTTP_API HashTable *_http_negotiate_q(const char *header, HashTable *support array_init(&array); FOREACH_HASH_VAL(pos, Z_ARRVAL(ex_arr), entry) { + int ident_len; double quality; - char *selected, *identifier; + char *selected, *identifier, *freeme; const char *separator; #if HTTP_DBG_NEG @@ -164,13 +165,22 @@ PHP_HTTP_API HashTable *_http_negotiate_q(const char *header, HashTable *support if ((separator = strchr(Z_STRVAL_PP(entry), ';'))) { const char *ptr = separator; - while (*++ptr && !isdigit(*ptr)); + while (*++ptr && !isdigit(*ptr) && '.' != *ptr); quality = atof(ptr); - identifier = estrndup(Z_STRVAL_PP(entry), separator - Z_STRVAL_PP(entry)); + identifier = estrndup(Z_STRVAL_PP(entry), ident_len = separator - Z_STRVAL_PP(entry)); } else { quality = 1000.0 - i++; - identifier = estrndup(Z_STRVAL_PP(entry), Z_STRLEN_PP(entry)); + identifier = estrndup(Z_STRVAL_PP(entry), ident_len = Z_STRLEN_PP(entry)); + } + freeme = identifier; + + while (isspace(*identifier)) { + ++identifier; + --ident_len; + } + while (isspace(identifier[ident_len - 1])) { + identifier[--ident_len] = '\0'; } if ((selected = neg(identifier, &quality, supported TSRMLS_CC))) { @@ -180,7 +190,7 @@ PHP_HTTP_API HashTable *_http_negotiate_q(const char *header, HashTable *support } } - efree(identifier); + efree(freeme); } result = Z_ARRVAL(array); diff --git a/package2.xml b/package2.xml index 2f6ccd8..316ac11 100644 --- a/package2.xml +++ b/package2.xml @@ -30,8 +30,8 @@ 2005-00-00 - 0.18.1 - 0.18.0 + 0.19.0 + 0.19.0 beta @@ -39,7 +39,9 @@ BSD, revised diff --git a/php_http.h b/php_http.h index 2100550..4ebbc5c 100644 --- a/php_http.h +++ b/php_http.h @@ -98,6 +98,7 @@ PHP_FUNCTION(http_date); PHP_FUNCTION(http_build_uri); PHP_FUNCTION(http_negotiate_language); PHP_FUNCTION(http_negotiate_charset); +PHP_FUNCTION(http_negotiate_content_type); PHP_FUNCTION(http_redirect); PHP_FUNCTION(http_throttle); PHP_FUNCTION(http_send_status); diff --git a/php_http_headers_api.h b/php_http_headers_api.h index bc35269..d083956 100644 --- a/php_http_headers_api.h +++ b/php_http_headers_api.h @@ -44,6 +44,7 @@ typedef char *(*negotiate_func_t)(const char *test, double *quality, HashTable * #define http_negotiate_language_func _http_negotiate_language_func extern char *_http_negotiate_language_func(const char *test, double *quality, HashTable *supported TSRMLS_DC); +#define http_negotiate_content_type_func _http_negotiate_default_func #define http_negotiate_encoding_func _http_negotiate_default_func #define http_negotiate_charset_func _http_negotiate_default_func #define http_negotiate_default_func _http_negotiate_default_func @@ -55,6 +56,8 @@ extern char *_http_negotiate_default_func(const char *test, double *quality, Has #define http_negotiate_charset_ex(supported) http_negotiate_q("HTTP_ACCEPT_CHARSET", (supported), http_negotiate_charset_func) #define http_negotiate_encoding(zsupported) http_negotiate_encoding_ex(Z_ARRVAL_P(zsupported)) #define http_negotiate_encoding_ex(supported) http_negotiate_q("HTTP_ACCEPT_ENCODING", (supported), http_negotiate_encoding_func) +#define http_negotiate_content_type(zsupported) http_negotiate_content_type_ex(Z_ARRVAL_P(zsupported)) +#define http_negotiate_content_type_ex(supported) http_negotiate_q("HTTP_ACCEPT", (supported), http_negotiate_content_type_func) #define http_negotiate_q(e, s, n) _http_negotiate_q((e), (s), (n) TSRMLS_CC) PHP_HTTP_API HashTable *_http_negotiate_q(const char *header, HashTable *supported, negotiate_func_t neg TSRMLS_DC); diff --git a/tests/negotiation_001.phpt b/tests/negotiation_001.phpt index e1af2ca..d4b13ac 100644 --- a/tests/negotiation_001.phpt +++ b/tests/negotiation_001.phpt @@ -5,6 +5,7 @@ negotiation include 'skip.inc'; ?> --ENV-- +HTTP_ACCEPT=application/xml, application/xhtml+xml, text/html ; q = .8 HTTP_ACCEPT_LANGUAGE=de-AT,de-DE;q=0.8,en-GB;q=0.3,en-US;q=0.2 HTTP_ACCEPT_CHARSET=ISO-8859-1,utf-8;q=0.7,*;q=0.7 --FILE-- @@ -16,12 +17,18 @@ $langs = array( $csets = array( array('utf-8', 'iso-8859-1'), ); +$ctype = array( + array('foo/bar', 'application/xhtml+xml', 'text/html') +); var_dump(http_negotiate_language($langs[0])); var_dump(http_negotiate_language($langs[0], $lresult)); var_dump(http_negotiate_charset($csets[0])); var_dump(http_negotiate_charset($csets[0], $cresult)); +var_dump(http_negotiate_content_type($ctype[0])); +var_dump(http_negotiate_content_type($ctype[0], $tresult)); print_r($lresult); print_r($cresult); +print_r($tresult); echo "Done\n"; --EXPECTF-- %sTEST @@ -29,6 +36,8 @@ string(2) "de" string(2) "de" string(10) "iso-8859-1" string(10) "iso-8859-1" +string(21) "application/xhtml+xml" +string(21) "application/xhtml+xml" Array ( [de] => 900 @@ -39,4 +48,9 @@ Array [iso-8859-1] => 1000 [utf-8] => 0.7 ) +Array +( + [application/xhtml+xml] => 999 + [text/html] => 0.8 +) Done -- 2.30.2