On Thu, Apr 11, 2002 at 01:10:31AM +0200, Edin Kadribasic wrote: > > I posted this patch earlier, but this has some improvements. First > > of all, it's tabified, so we have consistent style. It also has some > > performance improvements suggested by Cliff Woolley, including one that > > will significantly improve output buffering/copying. > > > > The main guts of the patch include a overhaul/rewrite of the > > php_output_filter. It no longer requires setaside brigades, and can > > handle exactly one FILE bucket (Which it promptly passes off to PHP for > > processing). If it finds no FILE bucket, it silently passes the brigade > > bits down to the next filter. After processing a FILE, it steps out of > > the way and passes all other brigades down the chain. > > > > The SEGVs reported earlier on this list and others are fixed with > > this patch, as well as some other potential problems. > > Great work. Could you please send the patch as an email attachment? You > should probably apply for the CVS account if you didn't have one already.
Attached, thanks. -aaron
Index: sapi/apache2filter/sapi_apache2.c =================================================================== RCS file: /repository/php4/sapi/apache2filter/sapi_apache2.c,v retrieving revision 1.61.2.1 diff -u -u -r1.61.2.1 sapi_apache2.c --- sapi/apache2filter/sapi_apache2.c 14 Mar 2002 10:57:00 -0000 1.61.2.1 +++ sapi/apache2filter/sapi_apache2.c 10 Apr 2002 20:36:27 -0000 @@ -48,26 +48,31 @@ { apr_bucket *b; apr_bucket_brigade *bb; + apr_bucket_alloc_t *ba; php_struct *ctx; - uint now; ctx = SG(server_context); if (str_length == 0) return 0; - bb = apr_brigade_create(ctx->f->r->pool); - while (str_length > 0) { - now = MIN(str_length, 4096); - b = apr_bucket_transient_create(str, now); - APR_BRIGADE_INSERT_TAIL(bb, b); - str += now; - str_length -= now; - } + ba = ctx->f->c->bucket_alloc; + bb = apr_brigade_create(ctx->f->r->pool, ba); + + b = apr_bucket_transient_create(str, str_length, ba); + APR_BRIGADE_INSERT_TAIL(bb, b); + + /* Add a Flush bucket to the end of this brigade, so that + * the transient buckets above are more likely to make it out + * the end of the filter instead of having to be copied into + * someone's setaside. */ + b = apr_bucket_flush_create(ba); + APR_BRIGADE_INSERT_TAIL(bb, b); + if (ap_pass_brigade(ctx->f->next, bb) != APR_SUCCESS) { php_handle_aborted_connection(); } - return str_length; + return 0; /* we wrote everything, we promise! */ } static int @@ -161,6 +166,7 @@ { php_struct *ctx = server_context; apr_bucket_brigade *bb; + apr_bucket_alloc_t *ba; apr_bucket *b; if (!server_context) @@ -171,8 +177,9 @@ * all further flush buckets. */ - bb = apr_brigade_create(ctx->f->r->pool); - b = apr_bucket_flush_create(); + ba = ctx->f->r->connection->bucket_alloc; + bb = apr_brigade_create(ctx->f->r->pool, ba); + b = apr_bucket_flush_create(ba); APR_BRIGADE_INSERT_TAIL(bb, b); if (ap_pass_brigade(ctx->f->next, bb) != APR_SUCCESS) { php_handle_aborted_connection(); @@ -230,13 +237,6 @@ AP_MODULE_DECLARE_DATA module php4_module; -#define INIT_CTX \ - if (ctx == NULL) { \ - /* Initialize filter context */ \ - SG(server_context) = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx)); \ - ctx->bb = apr_brigade_create(f->c->pool); \ - } - static int php_input_filter(ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes) { @@ -254,7 +254,10 @@ ctx = SG(server_context); - INIT_CTX; + if (ctx == NULL) { + /* Initialize filter context */ + SG(server_context) = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx)); + } if ((rv = ap_get_brigade(f->next, bb, mode, block, readbytes)) != APR_SUCCESS) { return rv; @@ -327,79 +330,67 @@ ap_add_common_vars(f->r); ap_add_cgi_vars(f->r); - ctx = SG(server_context); - INIT_CTX; - - ctx->f = f; - - /* states: - * 0: request startup - * 1: collecting data - * 2: script execution and request shutdown - */ - if (ctx->state == 0) { - - apply_config(conf); - - ctx->state++; - - php_apache_request_ctor(f, ctx TSRMLS_CC); + if (f->ctx == NULL) { + /* Initialize filter context */ + f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx)); + ctx->f = f; } - /* moves all buckets from bb to ctx->bb */ - ap_save_brigade(f, &ctx->bb, &bb, f->r->pool); + if (ctx->request_processed) { + return ap_pass_brigade(f->next, bb); + } - /* If we have received all data from the previous filters, - * we "flatten" the buckets by creating a single string buffer. - */ - if (ctx->state == 1 && APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(ctx->bb))) { + APR_BRIGADE_FOREACH(b, bb) { zend_file_handle zfd; - apr_bucket *eos; - /* We want to execute only one script per request. - * A bug in Apache or other filters could cause us - * to reenter php_filter during script execution, so - * we protect ourselves here. - */ - ctx->state = 2; + if (!ctx->request_processed && APR_BUCKET_IS_FILE(b)) { + const char *path; + apr_bucket_brigade *prebb = bb; + + /* Split the brigade into two brigades before and after + * the file bucket. Leave the "after the FILE" brigade + * in the original bb, so it gets passed outside of this + * loop. */ + bb = apr_brigade_split(prebb, b); + + /* Pass the "before the FILE" brigade here + * (if it's non-empty). */ + if (!APR_BRIGADE_EMPTY(prebb)) { + apr_status_t rv; + rv = ap_pass_brigade(f->next, prebb); + /* XXX: destroy the prebb, since we know we're + * done with it? */ + if (rv != APR_SUCCESS) { + php_handle_aborted_connection(); + } + } - /* Handle phpinfo/phpcredits/built-in images */ - if (!php_handle_special_queries(TSRMLS_C)) { + SG(server_context) = ctx; + apply_config(conf); + php_apache_request_ctor(f, ctx TSRMLS_CC); + + apr_file_name_get(&path, ((apr_bucket_file *) b->data)->fd); + zfd.type = ZEND_HANDLE_FILENAME; + zfd.filename = (char *) path; + zfd.free_filename = 0; + zfd.opened_path = NULL; - b = APR_BRIGADE_FIRST(ctx->bb); + php_execute_script(&zfd TSRMLS_CC); + php_apache_request_dtor(f TSRMLS_CC); - if (APR_BUCKET_IS_FILE(b)) { - const char *path; + ctx->request_processed = 1; - apr_file_name_get(&path, ((apr_bucket_file *) b->data)->fd); - - zfd.type = ZEND_HANDLE_FILENAME; - zfd.filename = (char *) path; - zfd.free_filename = 0; - zfd.opened_path = NULL; - - php_execute_script(&zfd TSRMLS_CC); - } else { - -#define PHP_NO_DATA "The PHP Filter did not receive suitable input data" - - eos = apr_bucket_transient_create(PHP_NO_DATA, sizeof(PHP_NO_DATA)-1); - APR_BRIGADE_INSERT_HEAD(bb, eos); - } - } - - php_apache_request_dtor(f TSRMLS_CC); + /* Delete the FILE bucket from the brigade. */ + apr_bucket_delete(b); - SG(server_context) = 0; - /* Pass EOS bucket to next filter to signal end of request */ - eos = apr_bucket_eos_create(); - APR_BRIGADE_INSERT_TAIL(bb, eos); - - return ap_pass_brigade(f->next, bb); - } else - apr_brigade_destroy(bb); + /* We won't handle any more buckets in this brigade, so + * it's ok to break out now. */ + break; + } + } - return APR_SUCCESS; + /* Pass whatever is left on the brigade. */ + return ap_pass_brigade(f->next, bb); } static apr_status_t Index: sapi/apache2filter/php_apache.h =================================================================== RCS file: /repository/php4/sapi/apache2filter/php_apache.h,v retrieving revision 1.10 diff -u -u -r1.10 php_apache.h --- sapi/apache2filter/php_apache.h 28 Feb 2002 08:27:20 -0000 1.10 +++ sapi/apache2filter/php_apache.h 10 Apr 2002 20:36:27 -0000 @@ -21,7 +21,6 @@ typedef struct php_struct { int state; - apr_bucket_brigade *bb; ap_filter_t *f; /* Length of post_data buffer */ int post_len; @@ -29,6 +28,8 @@ int post_idx; /* Buffer for request body filter */ char *post_data; + /* Whether or not we've processed PHP in the output filters yet. */ + int request_processed; } php_struct; int php_apache_register_module(void);
-- PHP Development Mailing List <http://www.php.net/> To unsubscribe, visit: http://www.php.net/unsub.php