You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Dirk-Willem van Gulik <di...@webweaving.org> on 2021/08/07 16:33:49 UTC

Extra bucket brigade with just an EOS on an input filter at the end.

In some code (https://source.redwax.eu/svn/redwax/rs/mod_cms_verify/trunk/mod_cms_verify.c) I have in input filter (that checks a PKCS#7 signature before passing the payload on to a proxy/cgi-script, etc).

I am testing this with:

	echo  "field1=foo&field2=bar” |\
		openssl cms -sign -signer /tmp/sign.cert -outform DER -stream  |\
		 curl --data-binary @- -vvvv http://127.0.0.1:8080/show.cgi

Works well.

But I am seeing after all this going well an extra bucket brigade being passed; with 0 bytes. And I’d like to understand why.

Code is roughly ((https://source.redwax.eu/svn/redwax/rs/mod_cms_verify/trunk/mod_cms_verify.c for the real McCoy):

  static apr_status_t _input_filter(ap_filter_t * f,  apr_bucket_brigade * bbout, ….
  {
    verify_config_rec *conf = ap_get_module_config(r->per_dir_config, &cms_verify_module);
    request_rec *r = f->r;

    bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);

    if (state == NULL)  {
	setup some state..
	state->pbb_tmp = apr_brigade_create(r->pool, c->bucket_alloc);
	….
    }
    
    if (APR_BRIGADE_EMPTY(state->pbb_tmp)) {
	rv = ap_get_brigade(f->next, state->pbb_tmp, eMode, eBlock, nBytes);
	if (eMode == AP_MODE_EATCRLF || rv != APR_SUCCESS)
	    return rv;
    }

    while (!APR_BRIGADE_EMPTY(state->pbb_tmp)) {
	apr_bucket *pbkt_in = APR_BRIGADE_FIRST(state->pbb_tmp);
	const char *data;
	apr_size_t len;

	if (APR_BUCKET_IS_EOS(pbkt_in)) {
	    apr_bucket *pbkt_out = validate()..

	    if (pbkt_out is valid) 
  		    APR_BRIGADE_INSERT_TAIL(bbout, pbkt_out);

	    APR_BRIGADE_INSERT_TAIL(bbout, apr_bucket_eos_create(r->connection->bucket_alloc));
	    APR_BUCKET_REMOVE(pbkt_in);
	    break;
	}

	rv = apr_bucket_read(pbkt_in, &data, &len, eBlock);
	if (rv != APR_SUCCESS)
	    return rv;

	… add len bytes to a buffer

	apr_bucket_delete(pbkt_in);
    };
    return APR_SUCCESS;
   }

And mostly taken from mod_example.

What I am seeing is a first brigade with the POST content; with a terminating EOF. The bbout data makes it to the CGI script or (reverse) proxy. 

But I am then getting a second _input_filter call with a second brigade of just an EOS packet.

What causes that ? Or am I not running through the brigade properly ?

Dw


Re: Extra bucket brigade with just an EOS on an input filter at the end.

Posted by Joe Orton <jo...@redhat.com>.
On Sat, Aug 07, 2021 at 06:33:49PM +0200, Dirk-Willem van Gulik wrote: 
...
> What I am seeing is a first brigade with the POST content; with a 
> terminating EOF. The bbout data makes it to the CGI script or 
> (reverse) proxy.
> 
> But I am then getting a second _input_filter call with a second 
> brigade of just an EOS packet.
> 
> What causes that ? Or am I not running through the brigade properly ?

You're not doing anything wrong, it seems to be a "feature" of the way 
input filtering is implemented and should probably be better documented.  
I wrote this in mod_ssl:

        /* Surprisingly (and perhaps, wrongly), the request body can be
         * pulled from the input filter stack more than once; a
         * handler may read it, and ap_discard_request_body() will
         * attempt to do so again after *every* request.  So input
         * filters must be prepared to give up an EOS if invoked after
         * initially reading the request. The HTTP_IN filter does this
         * with its ->eos_sent flag. */

https://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/ssl_engine_io.c?view=markup#l2205

Regards, Joe