- add http_negotiate_content_type()
authorMichael Wallner <mike@php.net>
Sat, 19 Nov 2005 16:50:16 +0000 (16:50 +0000)
committerMichael Wallner <mike@php.net>
Sat, 19 Nov 2005 16:50:16 +0000 (16:50 +0000)
- fix bug in negotiator if accept headers contain spaces

http.c
http_functions.c
http_headers_api.c
package2.xml
php_http.h
php_http_headers_api.h
tests/negotiation_001.phpt

diff --git a/http.c b/http.c
index 567d45668156a84bfe264067af07d69b35a71cdd..ffbae18cdb8f848e301ab70b97f8a4293aacd9cb 100644 (file)
--- 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)
index 9156ccc393187ce2a6fa5912059f75133efc6b83..e731d9af041343c08112d467568f228d7d7a9f75 100644 (file)
@@ -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:
+ * <pre>
+ * <?php
+ * $ctypes = array('application/xhtml+xml', 'text/html');
+ * http_send_content_type(http_negotiate_content_type($ctypes));
+ * ?>
+ * </pre>
+ */
+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.
index c4d23c8a17824d1d172d88a033f74f4769dbf106..3cb9c9128626e48c4912c4deb665cd352c19f6b5 100644 (file)
@@ -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);
index 2f6ccd86029a619eeeb8872b1f5a5f21f310912d..316ac11c9a9c709398a08fa157716f4cff45be7a 100644 (file)
@@ -30,8 +30,8 @@
  </lead>
  <date>2005-00-00</date>
  <version>
-  <release>0.18.1</release>
-  <api>0.18.0</api>
+  <release>0.19.0</release>
+  <api>0.19.0</api>
  </version>
  <stability>
   <release>beta</release>
@@ -39,7 +39,9 @@
  </stability>
  <license>BSD, revised</license>
  <notes><![CDATA[
-* Fixed build with PHP-4 and PHP-5.0
+* Fixed bug in http_negotiate_*() when client sends spaces within accept headers
+
++ Added http_negotiate_content_type()
 ]]></notes>
  <contents>
   <dir name="/">
index 210055064f70f55ad3258e66ca9b75bd6f068e06..4ebbc5c60c0a34f2cd4e6ab8a41735a9bf05a668 100644 (file)
@@ -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);
index bc352699c8a139262998fc4ba1fd90448f0b8058..d0839561dd32f4df6cf56cf1a5ca14a8bc9bfb85 100644 (file)
@@ -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);
 
index e1af2ca4159de7444d02634b6ac8bd1aca4a10f8..d4b13ac0ccc416d7def7c71df2830bd588a5e273 100644 (file)
@@ -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