frankenphp icon indicating copy to clipboard operation
frankenphp copied to clipboard

Concurrent file uploads hang when using HTTPS

Open pafael opened this issue 1 year ago • 4 comments

What happened?

I'm experiencing an issue where concurrent file uploads hang indefinitely when querying the site via https. Below is a super basic demonstration. It occurs with as few as 20 files depending on the machine and build type. Increasing the max_requests or the number of threads doesn't seem to help. It doesn't happen without https, or on a regular apache web server with https. Most of the time no error is shown in the logs, but I did get a go panic output once, not sure if it's related to this issue though...

Build Type

I tried both the docker version v1.2.5 (dunglas/frankenphp:latest) and the official static build with the same result, in worker mode (with octane) or not.

Operating system

Same problem both on my machine (WSL Ubuntu-22.04 x86_64) in local (PHP 8.3.12), and on a VPS running on Debian 12 (amd64, PHP 8.2.23) with a public domain.

PHP Page code example

<?php
if(isset($_FILES) && count($_FILES) > 0){
    echo json_encode(['status' => 'success']);
    exit;
}
?>
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
    </head>
    <body>


        <input multiple type="file" accept=".pdf"/>
        <button onclick="sendToServer()">Post files to server</button>

        <script>

           async function sendToServer() {
               const files = document.querySelector('input[type="file"]').files;
               const promises = [];
               for (let i = 0; i < files.length; i++) {
                   promises.push(postPromise(files[i]));
               }
               await Promise.all(promises);
               alert('All files uploaded');
           }

            function postPromise(file){
                return new Promise( function(resolve, reject){
                    const fd = new FormData();
                    fd.append('file', file);
                    fetch('savefile', {
                        method: 'POST',
                        body: fd
                    }).then(response => {
                       resolve(response);
                    }).catch(error => {
                       reject({
                           status: error.status,
                            statusText: error.statusText
                        });
                    });
                });
            }
        </script> 
    </body>
 </html>

Build Type

Custom (tell us more in the description)

Worker Mode

No

Operating System

GNU/Linux

CPU Architecture

x86_64

PHP configuration

PHP Version 8.3.11

Relevant log output

panic: error during PHP script execution
goroutine 67 [running, locked to thread]:
github.com/dunglas/frankenphp.go_handle_request()
        /go/src/app/frankenphp.go:496 +0x2dd

pafael avatar Oct 08 '24 06:10 pafael

What version of HTTP are you using?

Could you try if enabling full-duplex fixed the issue? https://caddyserver.com/docs/caddyfile/options#enable-full-duplex

dunglas avatar Oct 08 '24 07:10 dunglas

The requests are done with http/2.0 - for which the docs say that this enable_full_duplex option has no effect. I tried with the following Caddyfile and indeed it doesn't seem to have any effect.

{
   frankenphp
}

https://localhost:8000 {
   root * ./public
   encode zstd br gzip
   php_server {
      resolve_root_symlink
      enable_full_duplex
   }
}

pafael avatar Oct 08 '24 08:10 pafael

Thanks. Would you be able to create a minimal reproducer (like a tiny repository with a script reproducing the issue)? This would help a lot to debug.

dunglas avatar Oct 08 '24 12:10 dunglas

Sure, actually the PHP Code example of my first post is already it, but here it is.

pafael avatar Oct 08 '24 14:10 pafael