Skip to content

Commit ef70fc2

Browse files
Important fix: Whilst apache sends name-value pairs in individual params records, nginx utilises that the specification allows them to be sent in the same record. This is now accounted for.
1 parent 7e04e46 commit ef70fc2

File tree

3 files changed

+58
-36
lines changed

3 files changed

+58
-36
lines changed

src/ConnectionHandler/ConnectionHandler.php

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -246,37 +246,61 @@ private function processParamsRecord($requestId, $contentData)
246246
return;
247247
}
248248

249-
$initialBytes = unpack('C5', $contentData);
249+
do {
250+
$this->readNameValuePair($requestId, $contentData);
251+
} while (strlen($contentData) > 0);
252+
}
250253

251-
$extendedLengthName = $initialBytes[1] & 0x80;
252-
$extendedLengthValue = $extendedLengthName ? $initialBytes[5] & 0x80 : $initialBytes[2] & 0x80;
254+
/**
255+
* Read a FastCGI name-value pair from a buffer and add it to the request params
256+
*
257+
* @param int $requestId The request id that sent the name-value pair
258+
* @param string $buffer The buffer to read the pair from (pass by reference)
259+
*/
260+
private function readNameValuePair($requestId, &$buffer)
261+
{
262+
$nameLength = $this->readFieldLength($buffer);
263+
$valueLength = $this->readFieldLength($buffer);
253264

254-
$structureFormat = (
255-
($extendedLengthName ? 'N' : 'C').'nameLength/'.
256-
($extendedLengthValue ? 'N' : 'C').'valueLength'
265+
$contentFormat = (
266+
'a'.$nameLength.'name/'.
267+
'a'.$valueLength.'value/'
257268
);
258269

259-
$structure = unpack($structureFormat, $contentData);
270+
$content = unpack($contentFormat, $buffer);
271+
$this->requests[$requestId]['params'][$content['name']] = $content['value'];
260272

261-
if ($extendedLengthName) {
262-
$structure['nameLength'] &= 0x7FFFFFFF;
263-
}
273+
$buffer = substr($buffer, $nameLength + $valueLength);
274+
}
264275

265-
if ($extendedLengthValue) {
266-
$structure['valueLength'] &= 0x7FFFFFFF;
276+
/**
277+
* Read the field length of a FastCGI name-value pair from a buffer
278+
*
279+
* @param string $buffer The buffer to read the field length from (pass by reference)
280+
*
281+
* @return int The length of the field
282+
*/
283+
private function readFieldLength(&$buffer)
284+
{
285+
$block = unpack('C4', $buffer);
286+
$skip = 1;
287+
288+
if ($block[1] & 0x80) {
289+
$length = (
290+
(($block[1] & 0x7F) << 24) |
291+
($block[2] << 16) |
292+
($block[3] << 8) |
293+
$block[4]
294+
);
295+
296+
$skip = 4;
297+
} else {
298+
$length = $block[1];
267299
}
268300

269-
$skipLength = ($extendedLengthName ? 4 : 1) + ($extendedLengthValue ? 4 : 1);
270-
271-
$contentFormat = (
272-
'x'.$skipLength.'/'.
273-
'a'.$structure['nameLength'].'name/'.
274-
'a'.$structure['valueLength'].'value/'
275-
);
301+
$buffer = substr($buffer, $skip);
276302

277-
$content = unpack($contentFormat, $contentData);
278-
279-
$this->requests[$requestId]['params'][$content['name']] = $content['value'];
303+
return $length;
280304
}
281305

282306
/**

test/Client/ConnectionWrapper.php

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,7 @@ public function readRecord(\PHPUnit_Framework_TestCase $testCase)
9797
public function writeRequest($requestId, array $params, $body)
9898
{
9999
$this->writeBeginRequestRecord($requestId, DaemonInterface::FCGI_RESPONDER, 0);
100-
101-
foreach ($params as $name => $value) {
102-
$this->writeParamsRecord($requestId, $name, $value);
103-
}
100+
$this->writeParamsRecord($requestId, $params);
104101

105102
$this->writeParamsRecord($requestId);
106103

@@ -147,13 +144,12 @@ public function writeBeginRequestRecord($requestId, $role, $flags)
147144
/**
148145
* Write a params record.
149146
*
150-
* @param int $requestId
151-
* @param string $name
152-
* @param string $value
147+
* @param int $requestId
148+
* @param array $params
153149
*/
154-
public function writeParamsRecord($requestId, $name = null, $value = null)
150+
public function writeParamsRecord($requestId, array $params = null)
155151
{
156-
if (null === $name && null === $value) {
152+
if (null === $params) {
157153
$this->writeRecord(DaemonInterface::FCGI_PARAMS, $requestId);
158154

159155
return;
@@ -171,11 +167,13 @@ public function writeParamsRecord($requestId, $name = null, $value = null)
171167
}
172168
};
173169

174-
$addLength($name);
175-
$addLength($value);
170+
foreach ($params as $name => $value) {
171+
$addLength($name);
172+
$addLength($value);
176173

177-
$content .= $name;
178-
$content .= $value;
174+
$content .= $name;
175+
$content .= $value;
176+
}
179177

180178
$contentLength = strlen($content);
181179
$paddingLength = ((int) ceil(((float) $contentLength) / 8.0) * 8) - $contentLength;

test/ConnectionHandler/ConnectionHandlerTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public function testShutdown()
103103

104104
// Write half of the first request (id 0)
105105
$context['clientWrapper']->writeBeginRequestRecord(0, DaemonInterface::FCGI_RESPONDER, DaemonInterface::FCGI_KEEP_CONNECTION);
106-
$context['clientWrapper']->writeParamsRecord(0, 'foo', 'bar');
106+
$context['clientWrapper']->writeParamsRecord(0, ['foo' => 'bar']);
107107
$context['clientWrapper']->writeParamsRecord(0);
108108

109109
// Process first half of the first request

0 commit comments

Comments
 (0)