+PHP_HTTP_API STATUS _http_start_ob_etaghandler(TSRMLS_D)
+{
+ /* already running? */
+ if (php_ob_handler_used("ob_etaghandler" TSRMLS_CC)) {
+ http_error(HE_WARNING, HTTP_E_RUNTIME, "ob_etaghandler can only be used once");
+ return FAILURE;
+ }
+
+ HTTP_G->etag.started = 1;
+ return php_start_ob_buffer_named("ob_etaghandler", HTTP_G->send.buffer_size, 0 TSRMLS_CC);
+}
+
+PHP_HTTP_API zend_bool _http_interrupt_ob_etaghandler(TSRMLS_D)
+{
+ if (HTTP_G->etag.started) {
+ HTTP_G->etag.started = 0;
+ if (HTTP_G->etag.ctx) {
+ efree(HTTP_G->etag.ctx);
+ HTTP_G->etag.ctx = NULL;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+/* {{{ void http_ob_etaghandler(char *, uint, char **, uint *, int) */
+void _http_ob_etaghandler(char *output, uint output_len,
+ char **handled_output, uint *handled_output_len, int mode TSRMLS_DC)
+{
+ /* passthru */
+ *handled_output_len = output_len;
+ *handled_output = estrndup(output, output_len);
+
+ /* are we supposed to run? */
+ if (HTTP_G->etag.started) {
+ /* initialize the etag context */
+ if (mode & PHP_OUTPUT_HANDLER_START) {
+ HTTP_G->etag.ctx = http_etag_init();
+ }
+
+ /* update */
+ http_etag_update(HTTP_G->etag.ctx, output, output_len);
+
+ /* finish */
+ if (mode & PHP_OUTPUT_HANDLER_END) {
+ char *sent_header = NULL;
+ char *etag = http_etag_finish(HTTP_G->etag.ctx);
+
+ HTTP_G->etag.ctx = NULL;
+
+ http_send_cache_control(HTTP_DEFAULT_CACHECONTROL, lenof(HTTP_DEFAULT_CACHECONTROL));
+ http_send_etag_ex(etag, strlen(etag), &sent_header);
+
+ if (http_match_etag("HTTP_IF_NONE_MATCH", etag)) {
+ /* force exit; ob within ob does not work */
+ HTTP_G->force_exit = 1;
+ http_exit_ex(304, sent_header, etag, 0);
+ }
+
+ STR_FREE(sent_header);
+ STR_FREE(etag);
+ }
+ }
+}
+/* }}} */