Skip to content

Commit aa75bcd

Browse files
authored
Merge pull request #480 from clue-labs/request
Add `Request` class to represent outgoing HTTP request message
2 parents 383f984 + 7a27c49 commit aa75bcd

File tree

9 files changed

+149
-16
lines changed

9 files changed

+149
-16
lines changed

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ multiple concurrent HTTP requests without blocking.
7777
* [json()](#json)
7878
* [plaintext()](#plaintext)
7979
* [xml()](#xml)
80+
* [Request](#request-1)
8081
* [ServerRequest](#serverrequest)
8182
* [ResponseException](#responseexception)
8283
* [React\Http\Middleware](#reacthttpmiddleware)
@@ -2628,6 +2629,24 @@ $response = React\Http\Message\Response::xml(
26282629
)->withStatus(React\Http\Message\Response::STATUS_BAD_REQUEST);
26292630
```
26302631

2632+
#### Request
2633+
2634+
The `React\Http\Message\Request` class can be used to
2635+
respresent an outgoing HTTP request message.
2636+
2637+
This class implements the
2638+
[PSR-7 `RequestInterface`](https://www.php-fig.org/psr/psr-7/#32-psrhttpmessagerequestinterface)
2639+
which extends the
2640+
[PSR-7 `MessageInterface`](https://www.php-fig.org/psr/psr-7/#31-psrhttpmessagemessageinterface).
2641+
2642+
This is mostly used internally to represent each outgoing HTTP request
2643+
message for the HTTP client implementation. Likewise, you can also use this
2644+
class with other HTTP client implementations and for tests.
2645+
2646+
> Internally, this implementation builds on top of an existing outgoing
2647+
request message and only adds support for streaming. This base class is
2648+
considered an implementation detail that may change in the future.
2649+
26312650
#### ServerRequest
26322651

26332652
The `React\Http\Message\ServerRequest` class can be used to

src/Browser.php

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@
33
namespace React\Http;
44

55
use Psr\Http\Message\ResponseInterface;
6-
use RingCentral\Psr7\Request;
76
use RingCentral\Psr7\Uri;
87
use React\EventLoop\Loop;
98
use React\EventLoop\LoopInterface;
10-
use React\Http\Io\ReadableBodyStream;
119
use React\Http\Io\Sender;
1210
use React\Http\Io\Transaction;
11+
use React\Http\Message\Request;
1312
use React\Promise\PromiseInterface;
1413
use React\Socket\ConnectorInterface;
1514
use React\Stream\ReadableStreamInterface;
@@ -838,10 +837,6 @@ private function requestMayBeStreaming($method, $url, array $headers = array(),
838837
$url = Uri::resolve($this->baseUrl, $url);
839838
}
840839

841-
if ($body instanceof ReadableStreamInterface) {
842-
$body = new ReadableBodyStream($body);
843-
}
844-
845840
foreach ($this->defaultHeaders as $key => $value) {
846841
$explicitHeaderExists = false;
847842
foreach (\array_keys($headers) as $headerKey) {

src/Io/Transaction.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@
55
use Psr\Http\Message\RequestInterface;
66
use Psr\Http\Message\ResponseInterface;
77
use Psr\Http\Message\UriInterface;
8-
use React\Http\Message\Response;
9-
use RingCentral\Psr7\Request;
10-
use RingCentral\Psr7\Uri;
118
use React\EventLoop\LoopInterface;
9+
use React\Http\Message\Response;
1210
use React\Http\Message\ResponseException;
1311
use React\Promise\Deferred;
1412
use React\Promise\PromiseInterface;
1513
use React\Stream\ReadableStreamInterface;
14+
use RingCentral\Psr7\Uri;
1615

1716
/**
1817
* @internal

src/Message/Request.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
namespace React\Http\Message;
4+
5+
use Psr\Http\Message\RequestInterface;
6+
use Psr\Http\Message\StreamInterface;
7+
use Psr\Http\Message\UriInterface;
8+
use React\Http\Io\BufferedBody;
9+
use React\Http\Io\ReadableBodyStream;
10+
use React\Stream\ReadableStreamInterface;
11+
use RingCentral\Psr7\Request as BaseRequest;
12+
13+
/**
14+
* Respresents an outgoing HTTP request message.
15+
*
16+
* This class implements the
17+
* [PSR-7 `RequestInterface`](https://www.php-fig.org/psr/psr-7/#32-psrhttpmessagerequestinterface)
18+
* which extends the
19+
* [PSR-7 `MessageInterface`](https://www.php-fig.org/psr/psr-7/#31-psrhttpmessagemessageinterface).
20+
*
21+
* This is mostly used internally to represent each outgoing HTTP request
22+
* message for the HTTP client implementation. Likewise, you can also use this
23+
* class with other HTTP client implementations and for tests.
24+
*
25+
* > Internally, this implementation builds on top of an existing outgoing
26+
* request message and only adds support for streaming. This base class is
27+
* considered an implementation detail that may change in the future.
28+
*
29+
* @see RequestInterface
30+
*/
31+
final class Request extends BaseRequest implements RequestInterface
32+
{
33+
/**
34+
* @param string $method HTTP method for the request.
35+
* @param string|UriInterface $url URL for the request.
36+
* @param array<string,string|string[]> $headers Headers for the message.
37+
* @param string|ReadableStreamInterface|StreamInterface $body Message body.
38+
* @param string $version HTTP protocol version.
39+
* @throws \InvalidArgumentException for an invalid URL or body
40+
*/
41+
public function __construct(
42+
$method,
43+
$url,
44+
array $headers = array(),
45+
$body = '',
46+
$version = '1.1'
47+
) {
48+
if (\is_string($body)) {
49+
$body = new BufferedBody($body);
50+
} elseif ($body instanceof ReadableStreamInterface && !$body instanceof StreamInterface) {
51+
$body = new ReadableBodyStream($body);
52+
} elseif (!$body instanceof StreamInterface) {
53+
throw new \InvalidArgumentException('Invalid request body given');
54+
}
55+
56+
parent::__construct($method, $url, $headers, $body, $version);
57+
}
58+
}

src/Message/ServerRequest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use React\Http\Io\BufferedBody;
99
use React\Http\Io\HttpBodyStream;
1010
use React\Stream\ReadableStreamInterface;
11-
use RingCentral\Psr7\Request;
11+
use RingCentral\Psr7\Request as BaseRequest;
1212

1313
/**
1414
* Respresents an incoming server request message.
@@ -30,7 +30,7 @@
3030
*
3131
* @see ServerRequestInterface
3232
*/
33-
final class ServerRequest extends Request implements ServerRequestInterface
33+
final class ServerRequest extends BaseRequest implements ServerRequestInterface
3434
{
3535
private $attributes = array();
3636

tests/FunctionalBrowserTest.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,15 @@
77
use React\EventLoop\Loop;
88
use React\Http\Browser;
99
use React\Http\HttpServer;
10+
use React\Http\Message\Response;
1011
use React\Http\Message\ResponseException;
1112
use React\Http\Middleware\StreamingRequestMiddleware;
12-
use React\Http\Message\Response;
1313
use React\Promise\Promise;
1414
use React\Promise\Stream;
1515
use React\Socket\Connector;
1616
use React\Socket\SocketServer;
1717
use React\Stream\ReadableStreamInterface;
1818
use React\Stream\ThroughStream;
19-
use RingCentral\Psr7\Request;
2019

2120
class FunctionalBrowserTest extends TestCase
2221
{

tests/Io/SenderTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
use React\Http\Client\RequestData;
77
use React\Http\Io\ReadableBodyStream;
88
use React\Http\Io\Sender;
9+
use React\Http\Message\Request;
910
use React\Promise;
1011
use React\Stream\ThroughStream;
1112
use React\Tests\Http\TestCase;
12-
use RingCentral\Psr7\Request;
1313

1414
class SenderTest extends TestCase
1515
{

tests/Io/TransactionTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
use Psr\Http\Message\ResponseInterface;
88
use React\Http\Io\ReadableBodyStream;
99
use React\Http\Io\Transaction;
10+
use React\Http\Message\Request;
11+
use React\Http\Message\Response;
1012
use React\Http\Message\ResponseException;
1113
use React\EventLoop\Loop;
1214
use React\Promise;
1315
use React\Promise\Deferred;
1416
use React\Stream\ThroughStream;
1517
use React\Tests\Http\TestCase;
16-
use RingCentral\Psr7\Request;
17-
use RingCentral\Psr7\Response;
1818

1919
class TransactionTest extends TestCase
2020
{

tests/Message/RequestTest.php

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
namespace React\Tests\Http\Message;
4+
5+
use React\Http\Io\HttpBodyStream;
6+
use React\Http\Message\Request;
7+
use React\Stream\ThroughStream;
8+
use React\Tests\Http\TestCase;
9+
10+
class RequestTest extends TestCase
11+
{
12+
public function testConstructWithStringRequestBodyReturnsStringBodyWithAutomaticSize()
13+
{
14+
$request = new Request(
15+
'GET',
16+
'http://localhost',
17+
array(),
18+
'foo'
19+
);
20+
21+
$body = $request->getBody();
22+
$this->assertSame(3, $body->getSize());
23+
$this->assertEquals('foo', (string) $body);
24+
}
25+
26+
public function testConstructWithStreamingRequestBodyReturnsBodyWhichImplementsReadableStreamInterfaceWithUnknownSize()
27+
{
28+
$request = new Request(
29+
'GET',
30+
'http://localhost',
31+
array(),
32+
new ThroughStream()
33+
);
34+
35+
$body = $request->getBody();
36+
$this->assertInstanceOf('Psr\Http\Message\StreamInterface', $body);
37+
$this->assertInstanceOf('React\Stream\ReadableStreamInterface', $body);
38+
$this->assertNull($body->getSize());
39+
}
40+
41+
public function testConstructWithHttpBodyStreamReturnsBodyAsIs()
42+
{
43+
$request = new Request(
44+
'GET',
45+
'http://localhost',
46+
array(),
47+
$body = new HttpBodyStream(new ThroughStream(), 100)
48+
);
49+
50+
$this->assertSame($body, $request->getBody());
51+
}
52+
53+
public function testConstructWithNullBodyThrows()
54+
{
55+
$this->setExpectedException('InvalidArgumentException', 'Invalid request body given');
56+
new Request(
57+
'GET',
58+
'http://localhost',
59+
array(),
60+
null
61+
);
62+
}
63+
}

0 commit comments

Comments
 (0)