I have been wrong before...but...

mod_http2 needs to send out a file response:
1. it starts with the response body brigade: [file:0-len][eos]
2. it sends the first 16K frame by splitting the file bucket: 
   -> passing to core output: [heap:frame header][file:0-16k]
   -> remaining body:  [file:16K-len][eos]
3. core_output decides to setaside:
   -> setaside (deferred pool): [heap:frame header][file:0-16k]
   -> remaining body:  [file:16K-len][eos]
4. core_output sends and, sometimes, clears the deferred pool
   -> which closes the file descriptor
5. next 16K frame: [heap:frame header][file:16k-32K] results in APR_EBADF

What is different to HTTP/1?
a) http/1 sends the body in one pass when it can. file buckets are never split 
intentionally
b) http/1 sends with a request set in filter->r, so the filter brigade saving 
uses not a new, "deferred" pool, but the request pool. That means that the file 
bucket setaside becomes a NOP

b) is the thing mod_http2 can currently not emulate. There is no request_rec on 
the master connection, and yet the buckets belong to a http2 stream whose 
memory pool is under control. 

2.4.x seems to have similar handling in its output.

What to do? 
I. Not sending file buckets is safe, but http: performance will suffer severely.
II. Sending a new kind of "stream file" bucket that knows how to handle 
setaside better, would make it safe. However the sendfile() code in core will 
not trigger on those.
III. setaside the file to conn_rec->pool and apr_file_close() explicitly at end 
of stream. will work, but wastes a small amount of conn_rec->pool for each file.

I will go ahead and try III, but if you have another idea, I'm all ears.

-Stefan

Reply via email to