Skip to content

Commit 3313e1f

Browse files
committed
Add internal AbstractRequest base class for Request class (PSR-7)
1 parent 518ca68 commit 3313e1f

File tree

4 files changed

+609
-6
lines changed

4 files changed

+609
-6
lines changed

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2642,8 +2642,7 @@ This is mostly used internally to represent each outgoing HTTP request
26422642
message for the HTTP client implementation. Likewise, you can also use this
26432643
class with other HTTP client implementations and for tests.
26442644

2645-
> Internally, this implementation builds on top of an existing outgoing
2646-
request message and only adds support for streaming. This base class is
2645+
> Internally, this implementation builds on top of a base class which is
26472646
considered an implementation detail that may change in the future.
26482647

26492648
#### ServerRequest

src/Io/AbstractRequest.php

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
<?php
2+
3+
namespace React\Http\Io;
4+
5+
use Psr\Http\Message\RequestInterface;
6+
use Psr\Http\Message\StreamInterface;
7+
use Psr\Http\Message\UriInterface;
8+
use RingCentral\Psr7\Uri;
9+
10+
/**
11+
* [Internal] Abstract HTTP request base class (PSR-7)
12+
*
13+
* @internal
14+
* @see RequestInterface
15+
*/
16+
abstract class AbstractRequest extends AbstractMessage implements RequestInterface
17+
{
18+
/** @var ?string */
19+
private $requestTarget;
20+
21+
/** @var string */
22+
private $method;
23+
24+
/** @var UriInterface */
25+
private $uri;
26+
27+
/**
28+
* @param string $method
29+
* @param string|UriInterface $uri
30+
* @param array<string,string|string[]> $headers
31+
* @param StreamInterface $body
32+
* @param string unknown $protocolVersion
33+
*/
34+
protected function __construct(
35+
$method,
36+
$uri,
37+
array $headers,
38+
StreamInterface $body,
39+
$protocolVersion
40+
) {
41+
if (\is_string($uri)) {
42+
$uri = new Uri($uri);
43+
} elseif (!$uri instanceof UriInterface) {
44+
throw new \InvalidArgumentException(
45+
'Argument #2 ($uri) expected string|Psr\Http\Message\UriInterface'
46+
);
47+
}
48+
49+
// assign default `Host` request header from URI unless already given explicitly
50+
$host = $uri->getHost();
51+
if ($host !== '') {
52+
foreach ($headers as $name => $value) {
53+
if (\strtolower($name) === 'host' && $value !== array()) {
54+
$host = '';
55+
break;
56+
}
57+
}
58+
if ($host !== '') {
59+
$port = $uri->getPort();
60+
if ($port !== null && (!($port === 80 && $uri->getScheme() === 'http') || !($port === 443 && $uri->getScheme() === 'https'))) {
61+
$host .= ':' . $port;
62+
}
63+
64+
$headers = array('Host' => $host) + $headers;
65+
}
66+
}
67+
68+
parent::__construct($protocolVersion, $headers, $body);
69+
70+
$this->method = $method;
71+
$this->uri = $uri;
72+
}
73+
74+
public function getRequestTarget()
75+
{
76+
if ($this->requestTarget !== null) {
77+
return $this->requestTarget;
78+
}
79+
80+
$target = $this->uri->getPath();
81+
if ($target === '') {
82+
$target = '/';
83+
}
84+
if (($query = $this->uri->getQuery()) !== '') {
85+
$target .= '?' . $query;
86+
}
87+
88+
return $target;
89+
}
90+
91+
public function withRequestTarget($requestTarget)
92+
{
93+
if ((string) $requestTarget === $this->requestTarget) {
94+
return $this;
95+
}
96+
97+
$request = clone $this;
98+
$request->requestTarget = (string) $requestTarget;
99+
100+
return $request;
101+
}
102+
103+
public function getMethod()
104+
{
105+
return $this->method;
106+
}
107+
108+
public function withMethod($method)
109+
{
110+
if ((string) $method === $this->method) {
111+
return $this;
112+
}
113+
114+
$request = clone $this;
115+
$request->method = (string) $method;
116+
117+
return $request;
118+
}
119+
120+
public function getUri()
121+
{
122+
return $this->uri;
123+
}
124+
125+
public function withUri(UriInterface $uri, $preserveHost = false)
126+
{
127+
if ($uri === $this->uri) {
128+
return $this;
129+
}
130+
131+
$request = clone $this;
132+
$request->uri = $uri;
133+
134+
$host = $uri->getHost();
135+
$port = $uri->getPort();
136+
if ($port !== null && $host !== '' && (!($port === 80 && $uri->getScheme() === 'http') || !($port === 443 && $uri->getScheme() === 'https'))) {
137+
$host .= ':' . $port;
138+
}
139+
140+
// update `Host` request header if URI contains a new host and `$preserveHost` is false
141+
if ($host !== '' && (!$preserveHost || $request->getHeaderLine('Host') === '')) {
142+
// first remove all headers before assigning `Host` header to ensure it always comes first
143+
foreach (\array_keys($request->getHeaders()) as $name) {
144+
$request = $request->withoutHeader($name);
145+
}
146+
147+
// add `Host` header first, then all other original headers
148+
$request = $request->withHeader('Host', $host);
149+
foreach ($this->withoutHeader('Host')->getHeaders() as $name => $value) {
150+
$request = $request->withHeader($name, $value);
151+
}
152+
}
153+
154+
return $request;
155+
}
156+
}

src/Message/Request.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
use Psr\Http\Message\RequestInterface;
66
use Psr\Http\Message\StreamInterface;
77
use Psr\Http\Message\UriInterface;
8+
use React\Http\Io\AbstractRequest;
89
use React\Http\Io\BufferedBody;
910
use React\Http\Io\ReadableBodyStream;
1011
use React\Stream\ReadableStreamInterface;
11-
use RingCentral\Psr7\Request as BaseRequest;
1212

1313
/**
1414
* Respresents an outgoing HTTP request message.
@@ -22,13 +22,12 @@
2222
* message for the HTTP client implementation. Likewise, you can also use this
2323
* class with other HTTP client implementations and for tests.
2424
*
25-
* > Internally, this implementation builds on top of an existing outgoing
26-
* request message and only adds support for streaming. This base class is
25+
* > Internally, this implementation builds on top of a base class which is
2726
* considered an implementation detail that may change in the future.
2827
*
2928
* @see RequestInterface
3029
*/
31-
final class Request extends BaseRequest implements RequestInterface
30+
final class Request extends AbstractRequest implements RequestInterface
3231
{
3332
/**
3433
* @param string $method HTTP method for the request.

0 commit comments

Comments
 (0)