roadrunner-server / roadrunner

🀯 High-performance PHP application server, process manager written in Go and powered with plugins
https://docs.roadrunner.dev
MIT License
7.92k stars 411 forks source link

[πŸ› BUG]: FastCGI duplicated Content-Type #1705

Closed random-rage closed 1 year ago

random-rage commented 1 year ago

No duplicates πŸ₯².

What happened?

When I use FastCGI with Nginx configuration as in the RR documentation include fastcgi_params;, which implies adding the parameter fastcgi_param CONTENT_TYPE $content_type;, the Content-Type header is duplicated.

Nginx config:

server {
   listen 80;
   server_name _;

   location / {
      fastcgi_pass rr:9000;
      include fastcgi_params;

      access_log off;
      error_log off;
   }
}

Version (rr --version)

2023.2.2

How to reproduce the issue?

.rr.yaml:

version: '3'

rpc:
  listen: tcp://0.0.0.0:6001

server:
  command: "php index.php"

http:
  address: "0.0.0.0:8080"
  fcgi:
    address: "tcp://0.0.0.0:9000"

PHP Script:

<?php

declare(strict_types=1);

use Spiral\RoadRunner;
use Nyholm\Psr7;

include "vendor/autoload.php";

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

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

while ($req = $worker->waitRequest()) {
    var_dump($req->getHeaders());
    try {
        $rsp = new Psr7\Response();
        $rsp->getBody()->write('Hello world!');

        $worker->respond($rsp);
    } catch (Throwable $e) {
        $worker->getWorker()->error((string) $e);
    }
}

cURL request:

curl --location 'http://127.0.0.1:8080/' --header 'Content-Type: application/json' --data '{"hello":"world"}'

Relevant log output

rr-fastcgi-rr-1     | 2023-09-04T08:26:57+0000  DEBUG   server          worker is allocated {"pid": 15, "internal_event_name": "EventWorkerConstruct"}
rr-fastcgi-rr-1     | 2023-09-04T08:26:57+0000  DEBUG   server          worker is allocated {"pid": 14, "internal_event_name": "EventWorkerConstruct"}
rr-fastcgi-rr-1     | 2023-09-04T08:26:57+0000  DEBUG   server          worker is allocated {"pid": 16, "internal_event_name": "EventWorkerConstruct"}
rr-fastcgi-rr-1     | 2023-09-04T08:26:57+0000  DEBUG   server          worker is allocated {"pid": 13, "internal_event_name": "EventWorkerConstruct"}
rr-fastcgi-rr-1     | 2023-09-04T08:26:57+0000  DEBUG   http            http server was started {"address": "0.0.0.0:8080"}
rr-fastcgi-rr-1     | [INFO] RoadRunner server started; version: 2023.2.2, buildtime: 2023-08-10T16:38:29+0000
rr-fastcgi-rr-1     | 2023-09-04T08:27:00+0000  INFO    server          array(5) {
rr-fastcgi-rr-1     |   ["Host"]=>
rr-fastcgi-rr-1     |   array(1) {
rr-fastcgi-rr-1     |     [0]=>
rr-fastcgi-rr-1     |     string(14) "127.0.0.1:8080"
rr-fastcgi-rr-1     |   }
rr-fastcgi-rr-1     |   ["Content-Type"]=>
rr-fastcgi-rr-1     |   array(2) {
rr-fastcgi-rr-1     |     [0]=>
rr-fastcgi-rr-1     |     string(16) "application/json"
rr-fastcgi-rr-1     |     [1]=>
rr-fastcgi-rr-1     |     string(16) "application/json"
rr-fastcgi-rr-1     |   }
rr-fastcgi-rr-1     |   ["Content-Length"]=>
rr-fastcgi-rr-1     |   array(1) {
rr-fastcgi-rr-1     |
rr-fastcgi-rr-1     | 2023-09-04T08:27:00+0000  INFO    server              [0]=>
rr-fastcgi-rr-1     |     string(2) "17"
rr-fastcgi-rr-1     |   }
rr-fastcgi-rr-1     |   ["User-Agent"]=>
rr-fastcgi-rr-1     |   array(1) {
rr-fastcgi-rr-1     |     [0]=>
rr-fastcgi-rr-1     |     string(11) "curl/7.88.1"
rr-fastcgi-rr-1     |   }
rr-fastcgi-rr-1     |   ["Accept"]=>
rr-fastcgi-rr-1     |   array(1) {
rr-fastcgi-rr-1     |     [0]=>
rr-fastcgi-rr-1     |     string(3) "*/*"
rr-fastcgi-rr-1     |   }
rr-fastcgi-rr-1     | }
rr-fastcgi-rr-1     |
rr-fastcgi-rr-1     |
rr-fastcgi-rr-1     | 2023-09-04T08:27:00+0000  INFO    http            http log    {"status": 200, "method": "POST", "URI": "", "remote_address": "172.21.0.1:54144", "read_bytes": 17, "write_bytes": 12, "start": "2023-09-04T08:27:00+0000", "elapsed": "23.60096ms"}
cv65kr commented 1 year ago

Hi @random-rage Just to compare I checked same configuration for apache and there a no problem, there is only one header content-type. I diged a bit more with Nginx and looks like issue is with include fastcgi_params; and to be more precise fastcgi_param CONTENT_TYPE $content_type;. I debug RR and when RR received request from nginx headers are already duplicated so it's mean nginx sent it twice

Looks like RR is not main problem here. fyi @rustatian

I will try to play with it a bit more, to find root cause but for me smells like nginx misconfiguration

rustatian commented 1 year ago

Hey :wave: Yeah, I also guessed that the reason is misconfiguration. RR (and more specifically, the stdlib) can add a Content-Type header automatically, but if there is no such header in the request.

rustatian commented 1 year ago

@random-rage Hey :wave: I've double-checked this issue, looks like this headers comes twice from the NGINX. You may try to remove include fastcgi_params; or configure the headers more precisely.

random-rage commented 1 year ago

@random-rage Hey πŸ‘‹ I've double-checked this issue, looks like this headers comes twice from the NGINX. You may try to remove include fastcgi_params; or configure the headers more precisely.

Hello. When I delete include fastcgi_params; line, the request is not passed to PHP at all. If you think that everything is fine with RR, please add a description of this feature to the documentation https://roadrunner.dev/docs/app-server-nginx-with-rr/current/en

cv65kr commented 1 year ago

Well, you can remove include fastcgi_params; but documentations says some params are required https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html so you need to set up manually. I tested it and works as expected.

I tested it with pure implementation of GO (without RR) and result was exactly the same - duplicated headers.