},
{
"name": "laminas/laminas-diactoros",
- "version": "2.11.1",
+ "version": "2.11.2",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-diactoros.git",
- "reference": "25b11d422c2e5dad868f68619888763b30f91e2d"
+ "reference": "78846cbce0550ec174508a646f46fd6dee76099b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/25b11d422c2e5dad868f68619888763b30f91e2d",
- "reference": "25b11d422c2e5dad868f68619888763b30f91e2d",
+ "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/78846cbce0550ec174508a646f46fd6dee76099b",
+ "reference": "78846cbce0550ec174508a646f46fd6dee76099b",
"shasum": ""
},
"require": {
"type": "community_bridge"
}
],
- "time": "2022-06-28T21:07:29+00:00"
+ "time": "2022-06-29T14:15:02+00:00"
},
{
"name": "laminas/laminas-httphandlerrunner",
},
{
"name": "laminas/laminas-diactoros",
- "version": "2.11.1",
- "version_normalized": "2.11.1.0",
+ "version": "2.11.2",
+ "version_normalized": "2.11.2.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-diactoros.git",
- "reference": "25b11d422c2e5dad868f68619888763b30f91e2d"
+ "reference": "78846cbce0550ec174508a646f46fd6dee76099b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/25b11d422c2e5dad868f68619888763b30f91e2d",
- "reference": "25b11d422c2e5dad868f68619888763b30f91e2d",
+ "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/78846cbce0550ec174508a646f46fd6dee76099b",
+ "reference": "78846cbce0550ec174508a646f46fd6dee76099b",
"shasum": ""
},
"require": {
"psalm/plugin-phpunit": "^0.14.0",
"vimeo/psalm": "^4.3"
},
- "time": "2022-06-28T21:07:29+00:00",
+ "time": "2022-06-29T14:15:02+00:00",
"type": "library",
"extra": {
"laminas": {
</file>
<file src="src/ServerRequestFactory.php">
<LessSpecificReturnStatement occurrences="1"/>
- <MixedArgument occurrences="1">
+ <MixedArgument occurrences="2">
<code>$headers['cookie']</code>
+ <code>$host</code>
</MixedArgument>
+ <MixedArgumentTypeCoercion occurrences="1">
+ <code>$headers</code>
+ </MixedArgumentTypeCoercion>
<MixedAssignment occurrences="3">
<code>$iisUrlRewritten</code>
<code>$requestUri</code>
<MixedReturnStatement occurrences="1">
<code>$defaults</code>
</MixedReturnStatement>
+ <MixedReturnTypeCoercion occurrences="1">
+ <code>self::marshalHostAndPortFromHeader($host)</code>
+ </MixedReturnTypeCoercion>
<MoreSpecificReturnType occurrences="1">
<code>ServerRequest</code>
</MoreSpecificReturnType>
return $requestFilter(new ServerRequest(
$server,
$files,
- self::marshalUriFromSapi($server),
+ self::marshalUriFromSapi($server, $headers),
marshalMethodFromSapi($server),
'php://input',
$headers,
/**
* Marshal a Uri instance based on the values present in the $_SERVER array and headers.
*
+ * @param array<string, string|list<string>> $headers
* @param array $server SAPI parameters
*/
- private static function marshalUriFromSapi(array $server) : Uri
+ private static function marshalUriFromSapi(array $server, array $headers) : Uri
{
$uri = new Uri('');
$uri = $uri->withScheme($https ? 'https' : 'http');
// Set the host
- [$host, $port] = self::marshalHostAndPort($server);
+ [$host, $port] = self::marshalHostAndPort($server, $headers);
if (! empty($host)) {
$uri = $uri->withHost($host);
if (! empty($port)) {
/**
* Marshal the host and port from the PHP environment.
*
+ * @param array<string, string|list<string>> $headers
* @return array{string, int|null} Array of two items, host and port,
* in that order (can be passed to a list() operation).
*/
- private static function marshalHostAndPort(array $server) : array
+ private static function marshalHostAndPort(array $server, array $headers) : array
{
static $defaults = ['', null];
+ $host = self::getHeaderFromArray('host', $headers, false);
+ if ($host !== false) {
+ return self::marshalHostAndPortFromHeader($host);
+ }
+
if (! isset($server['SERVER_NAME'])) {
return $defaults;
}
return 'on' === strtolower($https);
}
+
+ /**
+ * @param string|list<string> $host
+ * @return array Array of two items, host and port, in that order (can be
+ * passed to a list() operation).
+ */
+ private static function marshalHostAndPortFromHeader($host): array
+ {
+ if (is_array($host)) {
+ $host = implode(', ', $host);
+ }
+
+ $port = null;
+
+ // works for regname, IPv4 & IPv6
+ if (preg_match('|\:(\d+)$|', $host, $matches)) {
+ $host = substr($host, 0, -1 * (strlen($matches[1]) + 1));
+ $port = (int) $matches[1];
+ }
+
+ return [$host, $port];
+ }
+
+ /**
+ * Retrieve a header value from an array of headers using a case-insensitive lookup.
+ *
+ * @param array<string, string|list<string>> $headers Key/value header pairs
+ * @param mixed $default Default value to return if header not found
+ * @return mixed
+ */
+ private static function getHeaderFromArray(string $name, array $headers, $default = null)
+ {
+ $header = strtolower($name);
+ $headers = array_change_key_case($headers, CASE_LOWER);
+ if (! array_key_exists($header, $headers)) {
+ return $default;
+ }
+
+ if (is_string($headers[$header])) {
+ return $headers[$header];
+ }
+
+ return implode(', ', $headers[$header]);
+ }
}