Uploaded image for project: 'Blesta Core'
  1. Blesta Core
  2. CORE-5697

Download Manager: Output buffering issue on HTTP/2 web servers for file downloads

    Details

    • Type: Bug
    • Status: Open
    • Priority: Major
    • Resolution: Unresolved
    • Affects Version/s: 5.13.0
    • Fix Version/s: 6.0.0-b2
    • Component/s: Plugins
    • Labels:
      None

      Description

      To reproduce, try to download a file when running Apache http/2. Not that downloads seem to hang randomly.

      Summary

      The code at components/download/download.php:241 uses readfile() to stream files through PHP, which is incompatible with Apache's mod_http2 due to its response buffering behavior.

      Root Cause Analysis

      Looking at the output() method (lines 232-248):

        private function output($file, $type)
        {
            switch ($type) {
                case 'data':
                    echo $file;
                    break;
                case 'file':
                    readfile($file);  // <-- This is the problem
                    break;
                case 'xsendfile':
                    $this->setHeader('X-Sendfile', $file);
                    break;
            }
        }
      

      Why this fails with HTTP/2:

      • mod_http2 buffers the entire PHP response before transmitting to properly frame HTTP/2 streams
      • readfile() sends data through PHP's output buffer, which mod_http2 waits to complete
      • Browsers using HTTP/2 see the download stall; wget/curl work because they default to HTTP/1.1

      Good News

      The code already supports X-Sendfile (xsendfile mode on line 244-245), which completely bypasses this issue by having Apache serve the file directly instead of PHP.

      Recommended Fixes

      Option 1: Output buffer management (partial fix)

      Add before readfile():

        while (ob_get_level()) {
            ob_end_clean();
        }
        if (function_exists('apache_setenv')) {
            apache_setenv('no-gzip', '1');
        }
        @ini_set('zlib.output_compression', 'Off');
        flush();
      

      This helps but may not fully resolve mod_http2 buffering.

      Option 2: Promote X-Sendfile usage (recommended)

      Document and encourage enabling mod_xsendfile for production environments with HTTP/2. This is the cleanest solution since:

      • Apache handles the file transfer directly
      • Bypasses PHP output buffering entirely
      • More memory-efficient for large files

      Option 3: Chunked reading with flushing

      Replace readfile($file) with:

        $handle = fopen($file, 'rb');
        while (!feof($handle)) {
            echo fread($handle, 8192);
            ob_flush();
            flush();
        }
        fclose($handle);
      

      This is still susceptible to mod_http2 buffering but may help in some configurations.

        Activity

        Hide
        admin Paul Phillips added a comment -

        See Ticket #1161841 for possible solution and original report.

        Show
        admin Paul Phillips added a comment - See Ticket #1161841 for possible solution and original report.

          People

          • Assignee:
            Unassigned
            Reporter:
            admin Paul Phillips
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated: