* added ob_httpetaghandler() (has major limitations compared to http_cache_etag())
authorMichael Wallner <mike@php.net>
Wed, 16 Feb 2005 16:25:47 +0000 (16:25 +0000)
committerMichael Wallner <mike@php.net>
Wed, 16 Feb 2005 16:25:47 +0000 (16:25 +0000)
* smarter ob handling in http_cache_etag() - used buffers will be fetched, freed
  and piped through again, so that everything passes the etag ob handler

http.c
http_api.c
package.xml
php_http.h
php_http_api.h

diff --git a/http.c b/http.c
index 0132ff93681d47a8953f6a4a2629b082d287e674..535a5aebe9a0dada0bdea5882a1819a8e68c4ae5 100644 (file)
--- a/http.c
+++ b/http.c
@@ -110,6 +110,7 @@ function_entry http_functions[] = {
 #ifndef ZEND_ENGINE_2
        PHP_FE(http_build_query, NULL)
 #endif
+       PHP_FE(ob_httpetaghandler, NULL)
        {NULL, NULL, NULL}
 };
 /* }}} */
@@ -440,31 +441,57 @@ PHP_FUNCTION(http_cache_etag)
                RETURN_FALSE;
        }
 
-       php_end_ob_buffers(0 TSRMLS_CC);
        http_send_header("Cache-Control: private, must-revalidate, max-age=0");
 
        if (etag_len) {
-               RETURN_SUCCESS(http_send_etag(etag, etag_len));
+               http_send_etag(etag, etag_len);
+               if (http_etag_match("HTTP_IF_NONE_MATCH", etag)) {
+                       if (SUCCESS == http_send_status(304)) {
+                               zend_bailout();
+                       } else {
+                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not send 304 Not Modified");
+                               RETURN_FALSE;
+                       }
+               }
        }
 
-       /* if no etag is given and we didn't already
-        * start ob_etaghandler -- start it
-        */
+       /* if no etag is given and we didn't already start ob_etaghandler -- start it */
        if (!HTTP_G(etag_started)) {
-               php_ob_set_internal_handler(_http_ob_etaghandler, (uint) 4096, "etag output handler", 0 TSRMLS_CC);
-               HTTP_G(etag_started) = 1;
-               RETURN_BOOL(php_start_ob_buffer_named("etag output handler", (uint) 4096, 0 TSRMLS_CC));
+               RETURN_BOOL(HTTP_G(etag_started) = (SUCCESS == http_start_ob_handler(_http_ob_etaghandler, "ob_etaghandler", 0, 1)));
        }
+       RETURN_TRUE;
+}
+/* }}} */
 
-       if (http_etag_match("HTTP_IF_NONE_MATCH", etag)) {
-               if (SUCCESS == http_send_status(304)) {
-                       zend_bailout();
-               } else {
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not send 304 Not Modified");
+/* {{{ proto string ob_httpetaghandler(string data, int mode)
+ *
+ * For use with ob_start(). Note that this has to be started as first output buffer.
+ */
+PHP_FUNCTION(ob_httpetaghandler)
+{
+       char *data;
+       int data_len;
+       long mode;
+       
+       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &data, &data_len, &mode)) {
+               RETURN_FALSE;
+       }
+       
+       if (mode & PHP_OUTPUT_HANDLER_START) {
+               if (HTTP_G(etag_started)) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "ob_etaghandler can only be used once");
                        RETURN_FALSE;
                }
+               if (OG(ob_nesting_level)) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "must be started prior to other output buffers");
+                       RETURN_FALSE;
+               }
+               http_send_header("Cache-Control: private, must-revalidate, max-age=0");
+               HTTP_G(etag_started) = 1;
        }
-
+       
+       Z_TYPE_P(return_value) = IS_STRING;
+       http_ob_etaghandler(data, data_len, &Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value), mode);
 }
 /* }}} */
 
index c5f25cfbb78b10d854b247c7a4e00fc5e55c5422..238dd5a1a2b565eb39f0369a87cf434e166268f2 100644 (file)
@@ -147,6 +147,8 @@ static int check_tzone(char *tzone);
 
 static char *pretty_key(char *key, int key_len, int uctitle, int xhyphen);
 
+static int http_ob_stack_get(php_ob_buffer *, php_ob_buffer **);
+
 /* {{{ HAVE_CURL */
 #ifdef HTTP_HAVE_CURL
 #define http_curl_initbuf(m) _http_curl_initbuf((m) TSRMLS_CC)
@@ -835,6 +837,20 @@ static char *pretty_key(char *key, int key_len, int uctitle, int xhyphen)
 }
 /* }}} */
 
+/* {{{ static STATUS http_ob_stack_get(php_ob_buffer *, php_ob_buffer **) */
+static STATUS http_ob_stack_get(php_ob_buffer *o, php_ob_buffer **s)
+{
+       static int i = 0;
+       php_ob_buffer *b = emalloc(sizeof(php_ob_buffer));
+       b->handler_name = estrdup(o->handler_name);
+       b->buffer = estrndup(o->buffer, o->text_length);
+       b->chunk_size = o->chunk_size;
+       b->erase = o->erase;
+       s[i++] = b;
+       return SUCCESS;
+}
+/* }}} */
+
 /* }}} internals */
 
 /* {{{ public API */
@@ -1095,6 +1111,43 @@ PHP_HTTP_API void _http_ob_etaghandler(char *output, uint output_len,
 }
 /* }}} */
 
+/* {{{ STATUS http_start_ob_handler(php_output_handler_func_t, char *, uint, zend_bool) */
+PHP_HTTP_API STATUS _http_start_ob_handler(php_output_handler_func_t handler_func, 
+       char *handler_name, uint chunk_size, zend_bool erase TSRMLS_DC)
+{
+       php_ob_buffer **stack;
+       int count, i;
+       STATUS result;
+       
+       count = OG(ob_nesting_level);
+       stack = emalloc(sizeof(php_ob_buffer *) * count);
+
+       if (count > 1) {
+               zend_stack_apply_with_argument(&OG(ob_buffers), ZEND_STACK_APPLY_BOTTOMUP, 
+                       (int (*)(void *elem, void *)) http_ob_stack_get, stack);
+       }
+       
+       if (count > 0) {
+               http_ob_stack_get(&OG(active_ob_buffer), stack);
+       }
+       
+       while (OG(ob_nesting_level)) {
+               php_end_ob_buffer(0, 0 TSRMLS_CC);
+       }
+       
+       php_ob_set_internal_handler(handler_func, 0, handler_name, 0 TSRMLS_CC);
+       result = php_start_ob_buffer_named(handler_name, chunk_size, erase TSRMLS_CC);
+       
+       for (i = 0; i < count; i++) {
+               php_ob_buffer *s = stack[i];
+               php_start_ob_buffer_named(s->handler_name, s->chunk_size, s->erase TSRMLS_CC);
+               php_body_write(s->buffer, s->text_length TSRMLS_CC);
+       }
+       
+       return result;
+}
+/* }}} */
+
 /* {{{ int http_modified_match(char *, int) */
 PHP_HTTP_API int _http_modified_match(const char *entry, const time_t t TSRMLS_DC)
 {
index 4d84dca4eb6951fdea880c92a6035a83d9fccc00..41dcd944097af8bbffad81d864453668c7b18620 100644 (file)
   </maintainers>
 
   <release>
-    <version>0.4.0</version>
+    <version>0.5.0</version>
     <date>2005-02-16</date>
     <state>alpha</state>
     <notes><![CDATA[
-* No need to initialize $info in http_(get|head|post*) functions anymore
-* Array keys of $info in http_(get|head|post*) functions are now lower case
-* Added http_get_request_headers()
-* Added http.allowed_methods INI entry
-* Fixed memory corruption in http_parse_headers() with empty header values
-* Fixed ETag caching
-* Fixed http_send_data()
-* Correctly send the full entity if the clients Range header is syntactically invalid
+* added ob_httpetaghandler() (has major limitations compared to http_cache_etag())
+* smarter ob handling in http_cache_etag() - used buffers will be fetched, freed
+  and piped through again, so that everything passes the etag ob handler
 ]]>
     </notes>
   </release>
index 105e4b661a8adcfa620f40c9917f6e56d62dfad8..29d868c06f8e09f467526b723d6693a0e4e37fb5 100644 (file)
@@ -18,7 +18,7 @@
 #ifndef PHP_EXT_HTTP_H
 #define PHP_EXT_HTTP_H
 
-#define PHP_EXT_HTTP_VERSION "0.4.0"
+#define PHP_EXT_HTTP_VERSION "0.5.0-dev"
 
 /* make compile on Win32 */
 #include "php_streams.h"
@@ -67,6 +67,8 @@ PHP_FUNCTION(http_post_array);
 PHP_FUNCTION(http_auth_basic);
 PHP_FUNCTION(http_auth_basic_cb);
 
+PHP_FUNCTION(ob_httpetaghandler);
+
 PHP_MINIT_FUNCTION(http);
 PHP_MSHUTDOWN_FUNCTION(http);
 PHP_RSHUTDOWN_FUNCTION(http);
index 9055e6616e4d1f2f40e8f49aa028ab52a42d1aa9..f28e30b9371657f6d698533266174265042c7ed8 100644 (file)
@@ -111,6 +111,9 @@ PHP_HTTP_API inline zval *_http_get_server_var(const char *key TSRMLS_DC);
 #define http_ob_etaghandler(o, l, ho, hl, m) _http_ob_etaghandler((o), (l), (ho), (hl), (m) TSRMLS_CC)
 PHP_HTTP_API void _http_ob_etaghandler(char *output, uint output_len, char **handled_output, uint *handled_output_len, int mode TSRMLS_DC);
 
+#define http_start_ob_handler(f, h, s, e) _http_start_ob_handler((f), (h), (s), (e) TSRMLS_CC)
+PHP_HTTP_API STATUS _http_start_ob_handler(php_output_handler_func_t handler_func, char *handler_name, uint chunk_size, zend_bool erase TSRMLS_DC);
+
 #define http_modified_match(entry, modified) _http_modified_match((entry), (modified) TSRMLS_CC)
 PHP_HTTP_API int _http_modified_match(const char *entry, const time_t t TSRMLS_DC);