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] Request field ordering with same names #136

Closed jetexe closed 5 years ago

jetexe commented 5 years ago
App Version
RR 1.3.6
PHP 7.2.15
Laravel 5.7.26

OS: Linux Ubuntu 18.04

Short description

Then you try to send post request with same field names RR takes first value. PHP-fpm or Laravel artisan serve gets last value

How reproduce this case

$ composer create-project laravel/laravel rr-post-test && cd rr-post-test
$ composer require spiral/roadrunner symfony/psr-http-message-bridge
$ touch worker.php .rr.local.yml

app/Http/Kernel.php:

    /**
     * The application's route middleware groups.
     *
     * @var array
     */
    protected $middlewareGroups = [
        'web' => [
            // ...
            //\App\Http\Middleware\VerifyCsrfToken::class, // <-- COMMENT this line
            // ...
        ],
    ];

.rr.local.yml:

rpc:
  enable: true
  listen: tcp://127.0.0.1:6001

http:
  address: 0.0.0.0:7000
  maxRequest: 128
  uploads:
    forbid: [".php", ".exe", ".bat"]
  workers:
    command: "php worker.php" # Allowed flags - `--force-https`, `--not-reset-connections`
    relay: "pipes"
    pool:
      numWorkers: 2
      maxJobs: 1
      allocateTimeout: 60
      destroyTimeout:  60

static:
  enable: true
  dir: "public"
  forbid: [".php"]

worker.php:

#!/usr/bin/env php
<?php

use Illuminate\Contracts\Http\Kernel;
use Illuminate\Foundation\Application;
use Symfony\Bridge\PsrHttpMessage\Factory\DiactorosFactory;
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;

\ini_set('display_errors', 'stderr');
require __DIR__ . '/vendor/autoload.php';

global $argv, $_SERVER;

$relay                 = new Spiral\Goridge\StreamRelay(STDIN, STDOUT);
$psr7                  = new Spiral\RoadRunner\PSR7Client(new Spiral\RoadRunner\Worker($relay));
$httpFoundationFactory = new HttpFoundationFactory;

/** @var Application $app */
$app = require __DIR__ . '/bootstrap/app.php';

/** @var Kernel $kernel */
$kernel = $app->make(Kernel::class);

while ($req = $psr7->acceptRequest()) {
    try {
        $request = Illuminate\Http\Request::createFromBase($httpFoundationFactory->createRequest($req));

        $response = $kernel->handle($request);

        $psr7factory  = new DiactorosFactory;
        $psr7response = $psr7factory->createResponse($response);
        $psr7->respond($psr7response);

        $kernel->terminate($request, $response);

        \gc_collect_cycles(); // keep the memory low (this will slow down your application a bit)
    } catch (\Throwable $e) {
        $psr7->getWorker()->error((string) $e);
    }
}

routes/web.php:

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::post('/post-test', function (Request $request) {
    return 'val = ' .  $request->input('name') . PHP_EOL;
});

Now, open two terminals and start 2 servers (rr on 7000 port and "native" serve on 8000):

$ rr serve -v -d -c ./.rr.local.yml
$ ./artisan serve

After that lets try to send some request to the "native" server:

$ curl --request POST  --url http://127.0.0.1:8000/post-test  --form name=first  --form name=second
second

PHP-fpm server:

$ curl --request POST  --url http://127.0.0.1:80/post-test  --form name=first  --form name=second
second

RR server :

$ curl --request POST  --url http://127.0.0.1:7000/post-test  --form name=first  --form name=second
first

As you can see, RR takes first parametr. All other servers takes last

wolfy-j commented 5 years ago

Thank you for the detailed description.

wolfy-j commented 5 years ago

Fixed in 1.3.7