Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 28 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,10 @@ The `Browser` offers several methods that resemble the HTTP protocol methods:
```php
$browser->get($url, array $headers = array());
$browser->head($url, array $headers = array());
$browser->post($url, array $headers = array(), $content = '');
$browser->delete($url, array $headers = array(), $content = '');
$browser->put($url, array $headers = array(), $content = '');
$browser->patch($url, array $headers = array(), $content = '');
$browser->post($url, array $headers = array(), string|ReadableStreamInterface $content = '');
$browser->delete($url, array $headers = array(), string|ReadableStreamInterface $content = '');
$browser->put($url, array $headers = array(), string|ReadableStreamInterface $content = '');
$browser->patch($url, array $headers = array(), string|ReadableStreamInterface $content = '');
```

All the above methods default to sending requests as HTTP/1.0.
Expand Down Expand Up @@ -328,12 +328,17 @@ $browser->post($url, array(), $stream)->then(function (ResponseInterface $respon

#### submit()

The `submit($url, array $fields, $headers = array(), $method = 'POST')` method can be used to submit an array of field values similar to submitting a form (`application/x-www-form-urlencoded`).
The `submit($url, array $fields, $headers = array(), $method = 'POST'): PromiseInterface<ResponseInterface>` method can be used to
submit an array of field values similar to submitting a form (`application/x-www-form-urlencoded`).

```php
$browser->submit($url, array('user' => 'test', 'password' => 'secret'));
```

#### send()

The `send(RequestInterface $request)` method can be used to send an arbitrary
instance implementing the [`RequestInterface`](#requestinterface) (PSR-7).
The `send(RequestInterface $request): PromiseInterface<ResponseInterface>` method can be used to
send an arbitrary instance implementing the [`RequestInterface`](#requestinterface) (PSR-7).

All the above [predefined methods](#methods) default to sending requests as HTTP/1.0.
If you need a custom HTTP protocol method or version, then you may want to use this
Expand All @@ -348,7 +353,8 @@ $browser->send($request)->then(…);

#### withOptions()

The `withOptions(array $options)` method can be used to change the [options](#options) to use:
The `withOptions(array $options): Browser` method can be used to
change the [options](#options) to use:

```php
$newBrowser = $browser->withOptions($options);
Expand All @@ -361,8 +367,8 @@ See [options](#options) for more details.

#### withBase()

The `withBase($baseUri)` method can be used to change the base URI used to
resolve relative URIs to.
The `withBase($baseUri): Browser` method can be used to
change the base URI used to resolve relative URIs to.

```php
$newBrowser = $browser->withBase('http://api.example.com/v3');
Expand All @@ -371,12 +377,12 @@ $newBrowser = $browser->withBase('http://api.example.com/v3');
Notice that the [`Browser`](#browser) is an immutable object, i.e. the `withBase()` method
actually returns a *new* [`Browser`](#browser) instance with the given base URI applied.

Any requests to relative URIs will then be processed by first prepending the
base URI.
Please note that this merely prepends the base URI and does *not* resolve any
relative path references (like `../` etc.).
This is mostly useful for API calls where all endpoints (URIs) are located
under a common base URI scheme.
Any requests to relative URIs will then be processed by first prepending
the (absolute) base URI.
Please note that this merely prepends the base URI and does *not* resolve
any relative path references (like `../` etc.).
This is mostly useful for (RESTful) API calls where all endpoints (URIs)
are located under a common base URI scheme.

```php
// will request http://api.example.com/v3/example
Expand All @@ -385,7 +391,8 @@ $newBrowser->get('/example')->then(…);

#### withoutBase()

The `withoutBase()` method can be used to remove the base URI.
The `withoutBase(): Browser` method can be used to
remove the base URI.

```php
$newBrowser = $browser->withoutBase();
Expand Down Expand Up @@ -431,9 +438,11 @@ a request promise if the remote server returns a non-success status code
(anything but 2xx or 3xx).
You can control this behavior via the ["obeySuccessCode" option](#options).

The `getCode()` method can be used to return the HTTP response status code.
The `getCode(): int` method can be used to
return the HTTP response status code.

The `getResponse()` method can be used to access its underlying [`ResponseInteface`](#responseinterface) object.
The `getResponse(): ResponseInterface` method can be used to
access its underlying [`ResponseInterface`](#responseinterface) object.

## Advanced

Expand Down
132 changes: 107 additions & 25 deletions src/Browser.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use React\EventLoop\LoopInterface;
use React\Promise\PromiseInterface;
use React\Socket\ConnectorInterface;
use React\Stream\ReadableStreamInterface;

class Browser
{
Expand All @@ -20,7 +21,34 @@ class Browser
private $options = array();

/**
* Instantiate the Browser
* The `Browser` is responsible for sending HTTP requests to your HTTP server
* and keeps track of pending incoming HTTP responses.
* It also registers everything with the main [`EventLoop`](https://github.com/reactphp/event-loop#usage).
*
* ```php
* $loop = React\EventLoop\Factory::create();
*
* $browser = new Browser($loop);
* ```
*
* If you need custom connector settings (DNS resolution, TLS parameters, timeouts,
* proxy servers etc.), you can explicitly pass a custom instance of the
* [`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface):
*
* ```php
* $connector = new \React\Socket\Connector($loop, array(
* 'dns' => '127.0.0.1',
* 'tcp' => array(
* 'bindto' => '192.168.10.1:0'
* ),
* 'tls' => array(
* 'verify_peer' => false,
* 'verify_peer_name' => false
* )
* ));
*
* $browser = new Browser($loop, $connector);
* ```
*
* @param LoopInterface $loop
* @param ConnectorInterface|null $connector [optional] Connector to use.
Expand All @@ -34,7 +62,7 @@ public function __construct(LoopInterface $loop, ConnectorInterface $connector =

/**
* @param string|UriInterface $url URI for the request.
* @param array $headers
* @param array $headers
* @return PromiseInterface
*/
public function get($url, array $headers = array())
Expand All @@ -43,9 +71,9 @@ public function get($url, array $headers = array())
}

/**
* @param string|UriInterface $url URI for the request.
* @param array $headers
* @param string $content
* @param string|UriInterface $url URI for the request.
* @param array $headers
* @param string|ReadableStreamInterface $content
* @return PromiseInterface
*/
public function post($url, array $headers = array(), $content = '')
Expand All @@ -54,8 +82,8 @@ public function post($url, array $headers = array(), $content = '')
}

/**
* @param string|UriInterface $url URI for the request.
* @param array $headers
* @param string|UriInterface $url URI for the request.
* @param array $headers
* @return PromiseInterface
*/
public function head($url, array $headers = array())
Expand All @@ -64,9 +92,9 @@ public function head($url, array $headers = array())
}

/**
* @param string|UriInterface $url URI for the request.
* @param array $headers
* @param string $content
* @param string|UriInterface $url URI for the request.
* @param array $headers
* @param string|ReadableStreamInterface $content
* @return PromiseInterface
*/
public function patch($url, array $headers = array(), $content = '')
Expand All @@ -75,9 +103,9 @@ public function patch($url, array $headers = array(), $content = '')
}

/**
* @param string|UriInterface $url URI for the request.
* @param array $headers
* @param string $content
* @param string|UriInterface $url URI for the request.
* @param array $headers
* @param string|ReadableStreamInterface $content
* @return PromiseInterface
*/
public function put($url, array $headers = array(), $content = '')
Expand All @@ -86,9 +114,9 @@ public function put($url, array $headers = array(), $content = '')
}

/**
* @param string|UriInterface $url URI for the request.
* @param array $headers
* @param string $content
* @param string|UriInterface $url URI for the request.
* @param array $headers
* @param string|ReadableStreamInterface $content
* @return PromiseInterface
*/
public function delete($url, array $headers = array(), $content = '')
Expand All @@ -97,10 +125,16 @@ public function delete($url, array $headers = array(), $content = '')
}

/**
* @param string|UriInterface $url URI for the request.
* @param array $fields
* @param array $headers
* @param string $method
* Submits an array of field values similar to submitting a form (`application/x-www-form-urlencoded`).
*
* ```php
* $browser->submit($url, array('user' => 'test', 'password' => 'secret'));
* ```
*
* @param string|UriInterface $url URI for the request.
* @param array $fields
* @param array $headers
* @param string $method
* @return PromiseInterface
*/
public function submit($url, array $fields, $headers = array(), $method = 'POST')
Expand All @@ -112,6 +146,19 @@ public function submit($url, array $fields, $headers = array(), $method = 'POST'
}

/**
* Sends an arbitrary instance implementing the [`RequestInterface`](#requestinterface) (PSR-7).
*
* All the above [predefined methods](#methods) default to sending requests as HTTP/1.0.
* If you need a custom HTTP protocol method or version, then you may want to use this
* method:
*
* ```php
* $request = new Request('OPTIONS', $url);
* $request = $request->withProtocolVersion('1.1');
*
* $browser->send($request)->then(…);
* ```
*
* @param RequestInterface $request
* @return PromiseInterface
*/
Expand All @@ -128,11 +175,26 @@ public function send(RequestInterface $request)
}

/**
* Creates a new Browser instance with the given absolute base URI
* Changes the base URI used to resolve relative URIs to.
*
* ```php
* $newBrowser = $browser->withBase('http://api.example.com/v3');
* ```
*
* This is mostly useful for using (RESTful) HTTP APIs.
* Any relative URI passed to any of the request methods will simply be
* appended behind the given `$baseUri`.
* Notice that the [`Browser`](#browser) is an immutable object, i.e. the `withBase()` method
* actually returns a *new* [`Browser`](#browser) instance with the given base URI applied.
*
* Any requests to relative URIs will then be processed by first prepending
* the (absolute) base URI.
* Please note that this merely prepends the base URI and does *not* resolve
* any relative path references (like `../` etc.).
* This is mostly useful for (RESTful) API calls where all endpoints (URIs)
* are located under a common base URI scheme.
*
* ```php
* // will request http://api.example.com/v3/example
* $newBrowser->get('/example')->then(…);
* ```
*
* By definition of this library, a given base URI MUST always absolute and
* can not contain any placeholders.
Expand All @@ -155,7 +217,16 @@ public function withBase($baseUri)
}

/**
* Creates a new Browser instance *without* a base URL
* Removes the base URI.
*
* ```php
* $newBrowser = $browser->withoutBase();
* ```
*
* Notice that the [`Browser`](#browser) is an immutable object, i.e. the `withoutBase()` method
* actually returns a *new* [`Browser`](#browser) instance without any base URI applied.
*
* See also [`withBase()`](#withbase).
*
* @return self
* @see self::withBase()
Expand All @@ -169,6 +240,17 @@ public function withoutBase()
}

/**
* Changes the [options](#options) to use:
*
* ```php
* $newBrowser = $browser->withOptions($options);
* ```
*
* Notice that the [`Browser`](#browser) is an immutable object, i.e. the `withOptions()` method
* actually returns a *new* [`Browser`](#browser) instance with the [options](#options) applied.
*
* See [options](#options) for more details.
*
* @param array $options
* @return self
*/
Expand Down
5 changes: 3 additions & 2 deletions src/Io/Sender.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use React\HttpClient\Request as RequestStream;
use React\HttpClient\Response as ResponseStream;
use React\Promise;
use React\Promise\PromiseInterface;
use React\Promise\Deferred;
use React\Socket\Connector;
use React\Socket\ConnectorInterface;
Expand Down Expand Up @@ -88,8 +89,8 @@ public function send(RequestInterface $request, MessageFactory $messageFactory)
$body = $request->getBody();

// automatically assign a Content-Length header if the body size is known
if ($body->getSize() !== null && $body->getSize() !== 0 && $request->hasHeader('Content-Length') !== null) {
$request = $request->withHeader('Content-Length', $body->getSize());
if ($body->getSize() !== null && $body->getSize() !== 0 && !$request->hasHeader('Content-Length')) {
$request = $request->withHeader('Content-Length', (string)$body->getSize());
}

if ($body instanceof ReadableStreamInterface && $body->isReadable() && !$request->hasHeader('Content-Length')) {
Expand Down
Loading