* 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
#ifndef ZEND_ENGINE_2
PHP_FE(http_build_query, NULL)
#endif
+ PHP_FE(ob_httpetaghandler, NULL)
{NULL, NULL, NULL}
};
/* }}} */
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);
}
/* }}} */
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)
}
/* }}} */
+/* {{{ 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 */
}
/* }}} */
+/* {{{ 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)
{
</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>
#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"
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);
#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);