mirror of
https://github.com/php/php-src.git
synced 2024-09-21 09:57:23 +00:00
Fix bug #76922: FastCGI terminates conn after FCGI_GET_VALUES
Closes GH-12387
This commit is contained in:
parent
7e5fb564d6
commit
e3d1beb0f1
2
NEWS
2
NEWS
@ -24,6 +24,8 @@ PHP NEWS
|
|||||||
- FPM:
|
- FPM:
|
||||||
. Fixed bug GH-12232 (FPM: segfault dynamically loading extension without
|
. Fixed bug GH-12232 (FPM: segfault dynamically loading extension without
|
||||||
opcache). (Jakub Zelenka)
|
opcache). (Jakub Zelenka)
|
||||||
|
. Fixed bug #76922 (FastCGI terminates conn after FCGI_GET_VALUES).
|
||||||
|
(Jakub Zelenka)
|
||||||
|
|
||||||
- Intl:
|
- Intl:
|
||||||
. Removed the BC break on IntlDateFormatter::construct which threw an
|
. Removed the BC break on IntlDateFormatter::construct which threw an
|
||||||
|
@ -1202,7 +1202,7 @@ static int fcgi_read_request(fcgi_request *req)
|
|||||||
req->keep = 0;
|
req->keep = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 0;
|
return 2;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1470,7 +1470,8 @@ int fcgi_accept_request(fcgi_request *req)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
req->hook.on_read();
|
req->hook.on_read();
|
||||||
if (fcgi_read_request(req)) {
|
int read_result = fcgi_read_request(req);
|
||||||
|
if (read_result == 1) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (is_impersonate && !req->tcp) {
|
if (is_impersonate && !req->tcp) {
|
||||||
pipe = (HANDLE)_get_osfhandle(req->fd);
|
pipe = (HANDLE)_get_osfhandle(req->fd);
|
||||||
@ -1481,7 +1482,7 @@ int fcgi_accept_request(fcgi_request *req)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return req->fd;
|
return req->fd;
|
||||||
} else {
|
} else if (read_result == 0) {
|
||||||
fcgi_close(req, 1, 1);
|
fcgi_close(req, 1, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
43
sapi/fpm/tests/bug76922-fcgi-get-value-conn.phpt
Normal file
43
sapi/fpm/tests/bug76922-fcgi-get-value-conn.phpt
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
--TEST--
|
||||||
|
FPM: bug76922 - FCGI conn termination after FCGI_GET_VALUES
|
||||||
|
--SKIPIF--
|
||||||
|
<?php include "skipif.inc"; ?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once "tester.inc";
|
||||||
|
|
||||||
|
$cfg = <<<EOT
|
||||||
|
[global]
|
||||||
|
error_log = {{FILE:LOG}}
|
||||||
|
[unconfined]
|
||||||
|
listen = {{ADDR}}
|
||||||
|
pm = static
|
||||||
|
pm.max_children = 1
|
||||||
|
catch_workers_output = yes
|
||||||
|
EOT;
|
||||||
|
|
||||||
|
$code = <<<EOT
|
||||||
|
<?php
|
||||||
|
echo 1;
|
||||||
|
EOT;
|
||||||
|
|
||||||
|
$tester = new FPM\Tester($cfg, $code);
|
||||||
|
$tester->start();
|
||||||
|
$tester->expectLogStartNotices();
|
||||||
|
$tester->requestValues(connKeepAlive: true)->expectValue('FCGI_MPXS_CONNS', '0');
|
||||||
|
$tester->request(connKeepAlive: true)->expectBody('1');
|
||||||
|
$tester->requestValues(connKeepAlive: true)->expectValue('FCGI_MPXS_CONNS', '0');
|
||||||
|
$tester->terminate();
|
||||||
|
$tester->close();
|
||||||
|
|
||||||
|
?>
|
||||||
|
Done
|
||||||
|
--EXPECT--
|
||||||
|
Done
|
||||||
|
--CLEAN--
|
||||||
|
<?php
|
||||||
|
require_once "tester.inc";
|
||||||
|
FPM\Tester::clean();
|
||||||
|
?>
|
||||||
|
<?php
|
@ -60,9 +60,9 @@ class Client
|
|||||||
const OVERLOADED = 2;
|
const OVERLOADED = 2;
|
||||||
const UNKNOWN_ROLE = 3;
|
const UNKNOWN_ROLE = 3;
|
||||||
|
|
||||||
const MAX_CONNS = 'MAX_CONNS';
|
const MAX_CONNS = 'FCGI_MAX_CONNS';
|
||||||
const MAX_REQS = 'MAX_REQS';
|
const MAX_REQS = 'FCGI_MAX_REQS';
|
||||||
const MPXS_CONNS = 'MPXS_CONNS';
|
const MPXS_CONNS = 'FCGI_MPXS_CONNS';
|
||||||
|
|
||||||
const HEADER_LEN = 8;
|
const HEADER_LEN = 8;
|
||||||
|
|
||||||
@ -454,8 +454,8 @@ class Client
|
|||||||
fwrite($this->_sock, $this->buildPacket(self::GET_VALUES, $request, 0));
|
fwrite($this->_sock, $this->buildPacket(self::GET_VALUES, $request, 0));
|
||||||
|
|
||||||
$resp = $this->readPacket();
|
$resp = $this->readPacket();
|
||||||
if ($resp['type'] == self::GET_VALUES_RESULT) {
|
if (isset($resp['type']) && $resp['type'] == self::GET_VALUES_RESULT) {
|
||||||
return $this->readNvpair($resp['content'], $resp['length']);
|
return $this->readNvpair($resp['content'], $resp['contentLength']);
|
||||||
} else {
|
} else {
|
||||||
throw new \Exception('Unexpected response type, expecting GET_VALUES_RESULT');
|
throw new \Exception('Unexpected response type, expecting GET_VALUES_RESULT');
|
||||||
}
|
}
|
||||||
|
@ -434,3 +434,89 @@ class Response
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ValuesResponse
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private array $values;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string|array|null $values
|
||||||
|
*/
|
||||||
|
public function __construct($values = null)
|
||||||
|
{
|
||||||
|
if ( ! is_array($values)) {
|
||||||
|
if ( ! is_null($values) ) {
|
||||||
|
$this->error('Invalid values supplied', true);
|
||||||
|
}
|
||||||
|
$this->values = [];
|
||||||
|
} else {
|
||||||
|
$this->values = $values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expect value.
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param mixed $value
|
||||||
|
* @return ValuesResponse
|
||||||
|
*/
|
||||||
|
public function expectValue(string $name, $value = null)
|
||||||
|
{
|
||||||
|
if ( ! isset($this->values[$name])) {
|
||||||
|
return $this->error("Value $name not found in values");
|
||||||
|
}
|
||||||
|
if ( ! is_null($value) && $value !== $this->values[$name]) {
|
||||||
|
return $this->error("Value $name is {$this->values[$name]} but expected $value");
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get values.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getValues()
|
||||||
|
{
|
||||||
|
return $this->values;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Debug output data.
|
||||||
|
*
|
||||||
|
* @return ValuesResponse
|
||||||
|
*/
|
||||||
|
public function debugOutput()
|
||||||
|
{
|
||||||
|
echo ">>> ValuesResponse\n";
|
||||||
|
echo "----------------- Values -----------------\n";
|
||||||
|
var_dump($this->values);
|
||||||
|
echo "---------------------------------------\n\n";
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit error message
|
||||||
|
*
|
||||||
|
* @param string $message
|
||||||
|
* @param bool $throw
|
||||||
|
*
|
||||||
|
* @return ValuesResponse
|
||||||
|
*/
|
||||||
|
private function error(string $message, $throw = false): bool
|
||||||
|
{
|
||||||
|
$errorMessage = "ERROR: $message\n";
|
||||||
|
if ($throw) {
|
||||||
|
throw new \Exception($errorMessage);
|
||||||
|
}
|
||||||
|
$this->debugOutput();
|
||||||
|
echo $errorMessage;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -868,6 +868,38 @@ class Tester
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute request for getting FastCGI values.
|
||||||
|
*
|
||||||
|
* @param string|null $address
|
||||||
|
* @param bool $connKeepAlive
|
||||||
|
*
|
||||||
|
* @return ValuesResponse
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function requestValues(
|
||||||
|
string $address = null,
|
||||||
|
bool $connKeepAlive = false
|
||||||
|
): ValuesResponse {
|
||||||
|
if ($this->hasError()) {
|
||||||
|
return new Response(null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$valueResponse = new ValuesResponse(
|
||||||
|
$this->getClient($address, $connKeepAlive)->getValues(['FCGI_MPXS_CONNS'])
|
||||||
|
);
|
||||||
|
if ($this->debug) {
|
||||||
|
$this->response->debugOutput();
|
||||||
|
}
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
$this->error("Request for getting values failed", $exception);
|
||||||
|
$valueResponse = new ValuesResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $valueResponse;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get client.
|
* Get client.
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user