Handle react socket connections in multiple processes


Provides network address types for PHP


Automated dependency injection for PSR-11 containers



Created at 1 month ago
[💡FEATURE REQUEST]: Streaming request & responses

Thanks for all the effort you guys are putting into this.

How should this work? Can the php worker delegate the response sending to another process (maybe a php job, a go service, nodejs service, etc...) which will then stream the response via roadrunners RPC or am I on the wrong track?

Could you briefly outline how this should work?

Created at 1 month ago
[🐛 BUG]: X-Sendfile not working as expected

Hi @rustatian

thanks for your reply. I really like the idea behind roadrunner and in fact I've been looking for similar solutions within the PHP ecosystem. This one here seems the most promising.

I'm sure you already aware of the issue, just to make sure we have a common understanding of the topic and please correct me for the parts where I may be misguided or plainly wrong:

PHP has a huge disadvantage when it comes to large data transfers (i.e. applications that cause a lot of or slow i/o): It is Blocking by default. The problem is also outlined quite well in #923 - The worker cannot be re-used while it is not only processing the request (as by occupying CPU cycles) but also while sending the response. For small chunks of data this mostly unnoticed, but it becomes a limiting factor for larger or slow transfers (large responses, db i/o with high latency, etc...).

This can only be fully addressed by using an async framework like Amp or ReactPHP. But this would kick PSR-7 and especially PSR-15 off the table, since both are designed for the traditional blocking nature of PHP.

This whole Blocking-Issue is mitigated by various strategies of the existing SAPIs (Apache mod_php or pfp-fpm) like forking new processes for each request when required.

X-Sendfile is another Strategy here. Instead of opening a large file in php and streaming it to the http frontend which would block the whole Tread in the meantime, the PHP process Responds with this header and delegates sending this (Local!) File to the Application server which makes the Thread available for the next request. X-Sendfile is not a php framework specific implementation, but a http server strategy used by some.

Nginx has a similar option which is called X-Accel-Redirect. Instead of a Local File-Path, nginx requires this header to reference a resource of a internal location config, which would not only allow delegating local files, but remote resources as well (like files from an Amazon S3, Google Cloud Storage or the like).

The use case for "Why would you open/send the file in php and not address it directly?" is mostly the following: The file should be guarded by the php application and only be sent to the user/client when certain conditions of a business logic are met. That could be a check if the user is authenticated, has proper privileges, has provided a required payment, etc ...

So the traditional flow of the X-Sendfile feature is as follows:

  1. HTTP-Request is delegated to PHP
  2. PHP processed the request and sends a response that meets the following criteria
    • There is a `X-Sendfile' Response-Header
    • The response body is empty (optional)
  3. The http server intercepts the response in the following way:
    • The local file path will be read from the X-Sendfile response header (addressed as localfile here)
    • The X-Sendfile header is removed before sending the response headers to the client
    • The http server will open localfile and stream its content to the client after sending the response headers
    • The http server may remove or replace Content-Length or Transfer-Encoding response headers as needed
    • The http server may ignore or respect Content-Length or Transfer-Encoding response headers from the PHP response when streaming the contents of localfile
    • The http server may apply an existing Range request header and stream localfile accordingly. Necessary Response headers should be added.
    • If there is any response body from PHP it is discarded

Is this even possible with the current HTTP implementation of roadrunner? This is also just a compatibility feature to mitigate effects. #923 - as far as I understood - has way better approaches to handle these concerns and maybe X-Sendfile could also be implemented this way.

Created at 1 month ago
[🐛 BUG]: X-Sendfile not working as expected

No duplicates 🥲.

  • [X] I have searched for a similar issue in our bug tracker and didn't find any solutions.

What happened?

The advertised feature does not work as it is used in frameworks like Symfony.

The following worker should cause the webserver (roadrunner) to stream the file /some/local/file/on/server from the given location in the X-Sendfile response header.


use Spiral\RoadRunner;
use Nyholm\Psr7;

include "vendor/autoload.php";

$worker = RoadRunner\Worker::create();
$psrFactory = new Psr7\Factory\Psr17Factory();

$psr7 = new RoadRunner\Http\PSR7Worker($worker, $psrFactory, $psrFactory, $psrFactory);

while (true) {
    try {
        $request = $psr7->waitRequest();

        if (!($request instanceof \Psr\Http\Message\ServerRequestInterface)) { // Termination request received
    } catch (\Throwable) {
        $psr7->respond(new Psr7\Response(400)); // Bad Request

    try {
        $fileToSend = '/some/local/file/to/be/sent.mp4'; // Make sure this actually exists and it is readable by the webserver
        $response = new Psr7\Response(200);

            $response->withHeader('X-Sendfile', $fileToSend),
    } catch (\Throwable) {
        $psr7->respond(new Psr7\Response(500, [], 'Something Went Wrong!'));

With the PSR response created in the above code, apache's mod_xsendfile would remove the X-Sendfile header and the potential response body from the php response and stream the local file that is referenced by this header to the client.

Roadrunner just passes the (empty) response as is, including the X-Sendfile header.

As far as I checked the YouTube video to this feature and the go code - and correct me when I'm wrong here, it seems that Roadrunner expects X-Sendfile to be passed by the user agent as request header which is not what frameworks like Symfony expect and it is not how X-Sendfile (or X-Accel-Redirect for nginx) works. Additionally this introduces a Security issue by making all files in the current working directory accessible.

Version (rr --version)

rr version 2.12.1 (build time: 2022-12-01T12:41:56+0000, go1.19.3), OS: linux, arch: amd64

How to reproduce the issue?

Configure Roadrunner as described in the docs: https://roadrunner.dev/docs/middleware-sendfile/2.x/en And use the worker code above. Make sure the File used for X-Sendfile in PHP exists and is readable.

Relevant log output

No response

Created at 1 month ago
issue comment
Add psalm static analysis, improve type inference

After rebasing and many tiny adjustments (Psalm became MUCH more powerful over the last whole year, I decided that this is good to go as-is.

Thanks @tux-rampage, and sorry for dragging this on: very valuable work!

Thank you for finishing this. :+1:

Created at 2 months ago