diff --git a/README.md b/README.md index c5fdd83..ec33665 100644 --- a/README.md +++ b/README.md @@ -61,10 +61,13 @@ mess with most of the low-level details. * [requestStreaming()](#requeststreaming) * [~~submit()~~](#submit) * [~~send()~~](#send) - * [withOptions()](#withoptions) + * [withTimeout()](#withtimeout) + * [withFollowRedirects()](#withfollowredirects) + * [withRejectErrorResponse()](#withrejecterrorresponse) * [withBase()](#withbase) * [withoutBase()](#withoutbase) * [withProtocolVersion()](#withprotocolversion) + * [~~withOptions()~~](#withoptions) * [ResponseInterface](#responseinterface) * [RequestInterface](#requestinterface) * [UriInterface](#uriinterface) @@ -211,13 +214,11 @@ response body and following any eventual [redirects](#redirects). See also disable following redirects altogether) and also [streaming](#streaming-response) below to not take receiving large response bodies into account for this timeout. -You can use the [`timeout` option](#withoptions) to pass a custom timeout value -in seconds like this: +You can use the [`withTimeout()` method](#withtimeout) to pass a custom timeout +value in seconds like this: ```php -$browser = $browser->withOptions(array( - 'timeout' => 10.0 -)); +$browser = $browser->withTimeout(10.0); $browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response) { // response received within 10 seconds maximum @@ -225,9 +226,9 @@ $browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response }); ``` -Similarly, you can use a negative timeout value to not apply a timeout at all -or use a `null` value to restore the default handling. -See also [`withOptions()`](#withoptions) for more details. +Similarly, you can use a bool `false` to not apply a timeout at all +or use a bool `true` value to restore the default handling. +See [`withTimeout()`](#withtimeout) for more details. If you're using a [streaming response body](#streaming-response), the time it takes to receive the response body stream will not be included in the timeout. @@ -267,8 +268,8 @@ using the `Authorization: Basic …` request header or allows you to set an expl By default, this library does not include an outgoing `Authorization` request header. If the server requires authentication, if may return a `401` (Unauthorized) -status code which will reject the request by default (see also -[`obeySuccessCode` option](#withoptions) below). +status code which will reject the request by default (see also the +[`withRejectErrorResponse()` method](#withrejecterrorresponse) below). In order to pass authentication details, you can simple pass the username and password as part of the request URL like this: @@ -329,15 +330,12 @@ possible privacy/security concerns. When following a redirect where the `Locatio response header contains authentication details, these details will be sent for following requests. -You can use the [`maxRedirects` option](#withoptions) to control the maximum -number of redirects to follow or the [`followRedirects` option](#withoptions) -to return any redirect responses as-is and apply custom redirection logic -like this: +You can use the [`withFollowRedirects()`](#withfollowredirects) method to +control the maximum number of redirects to follow or to return any redirect +responses as-is and apply custom redirection logic like this: ```php -$browser = $browser->withOptions(array( - 'followRedirects' => false -)); +$browser = $browser->withFollowRedirects(false); $browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response) { // any redirects will now end up here @@ -345,7 +343,7 @@ $browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response }); ``` -See also [`withOptions()`](#withoptions) for more details. +See also [`withFollowRedirects()`](#withfollowredirects) for more details. ### Blocking @@ -979,32 +977,129 @@ For an empty request body, if will only include a `Content-Length: 0` request header if the request method usually expects a request body (only applies to `POST`, `PUT` and `PATCH`). -#### withOptions() +#### withTimeout() -The `withOptions(array $options): Browser` method can be used to -change the options to use: +The `withTimeout(bool|number $timeout): Browser` method can be used to +change the maximum timeout used for waiting for pending requests. -The [`Browser`](#browser) class exposes several options for the handling of -HTTP transactions. These options resemble some of PHP's -[HTTP context options](https://www.php.net/manual/en/context.http.php) and -can be controlled via the following API (and their defaults): +You can pass in the number of seconds to use as a new timeout value: ```php -$newBrowser = $browser->withOptions(array( - 'timeout' => null, - 'followRedirects' => true, - 'maxRedirects' => 10, - 'obeySuccessCode' => true, - 'streaming' => false, // deprecated, see requestStreaming() instead -)); +$browser = $browser->withTimeout(10.0); ``` -See also [timeouts](#timeouts), [redirects](#redirects) and -[streaming](#streaming-response) for more details. +You can pass in a bool `false` to disable any timeouts. In this case, +requests can stay pending forever: + +```php +$browser = $browser->withTimeout(false); +``` + +You can pass in a bool `true` to re-enable default timeout handling. This +will respects PHP's `default_socket_timeout` setting (default 60s): + +```php +$browser = $browser->withTimeout(true); +``` + +See also [timeouts](#timeouts) for more details about timeout handling. Notice that the [`Browser`](#browser) is an immutable object, i.e. this method actually returns a *new* [`Browser`](#browser) instance with the -options applied. +given timeout value applied. + +#### withFollowRedirects() + +The `withTimeout(bool|int $$followRedirects): Browser` method can be used to +change how HTTP redirects will be followed. + +You can pass in the maximum number of redirects to follow: + +```php +$new = $browser->withFollowRedirects(5); +``` + +The request will automatically be rejected when the number of redirects +is exceeded. You can pass in a `0` to reject the request for any +redirects encountered: + +```php +$browser = $browser->withFollowRedirects(0); + +$browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response) { + // only non-redirected responses will now end up here + var_dump($response->getHeaders()); +}); +``` + +You can pass in a bool `false` to disable following any redirects. In +this case, requests will resolve with the redirection response instead +of following the `Location` response header: + +```php +$browser = $browser->withFollowRedirects(false); + +$browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response) { + // any redirects will now end up here + var_dump($response->getHeaderLine('Location')); +}); +``` + +You can pass in a bool `true` to re-enable default redirect handling. +This defaults to following a maximum of 10 redirects: + +```php +$browser = $browser->withFollowRedirects(true); +``` + +See also [redirects](#redirects) for more details about redirect handling. + +Notice that the [`Browser`](#browser) is an immutable object, i.e. this +method actually returns a *new* [`Browser`](#browser) instance with the +given redirect setting applied. + +#### withRejectErrorResponse() + +The `withRejectErrorResponse(bool $obeySuccessCode): Browser` method can be used to +change whether non-successful HTTP response status codes (4xx and 5xx) will be rejected. + +You can pass in a bool `false` to disable rejecting incoming responses +that use a 4xx or 5xx response status code. In this case, requests will +resolve with the response message indicating an error condition: + +```php +$browser = $browser->withRejectErrorResponse(false); + +$browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response) { + // any HTTP response will now end up here + var_dump($response->getStatusCode(), $response->getReasonPhrase()); +}); +``` + +You can pass in a bool `true` to re-enable default status code handling. +This defaults to rejecting any response status codes in the 4xx or 5xx +range with a [`ResponseException`](#responseexception): + +```php +$browser = $browser->withRejectErrorResponse(true); + +$browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response) { + // any successful HTTP response will now end up here + var_dump($response->getStatusCode(), $response->getReasonPhrase()); +}, function (Exception $e) { + if ($e instanceof Clue\React\Buzz\Message\ResponseException) { + // any HTTP response error message will now end up here + $response = $e->getResponse(); + var_dump($response->getStatusCode(), $response->getReasonPhrase()); + } else { + var_dump($e->getMessage()); + } +}); +``` + +Notice that the [`Browser`](#browser) is an immutable object, i.e. this +method actually returns a *new* [`Browser`](#browser) instance with the +given setting applied. #### withBase() @@ -1068,6 +1163,37 @@ Notice that the [`Browser`](#browser) is an immutable object, i.e. this method actually returns a *new* [`Browser`](#browser) instance with the new protocol version applied. +#### ~~withOptions()~~ + +> Deprecated since v2.9.0, see [`withTimeout()](#withtimeout), [`withFollowRedirects()`](#withfollowredirects) + and [`withRejectErrorResponse()`](#withrejecterrorresponse) instead. + +The deprecated `withOptions(array $options): Browser` method can be used to +change the options to use: + +The [`Browser`](#browser) class exposes several options for the handling of +HTTP transactions. These options resemble some of PHP's +[HTTP context options](https://www.php.net/manual/en/context.http.php) and +can be controlled via the following API (and their defaults): + +```php +// deprecated +$newBrowser = $browser->withOptions(array( + 'timeout' => null, // see withTimeout() instead + 'followRedirects' => true, // see withFollowRedirects() instead + 'maxRedirects' => 10, // see withFollowRedirects() instead + 'obeySuccessCode' => true, // see withRejectErrorResponse() instead + 'streaming' => false, // deprecated, see requestStreaming() instead +)); +``` + +See also [timeouts](#timeouts), [redirects](#redirects) and +[streaming](#streaming-response) for more details. + +Notice that the [`Browser`](#browser) is an immutable object, i.e. this +method actually returns a *new* [`Browser`](#browser) instance with the +options applied. + ### ResponseInterface The `Psr\Http\Message\ResponseInterface` represents the incoming response received from the [`Browser`](#browser). @@ -1101,7 +1227,7 @@ This is a standard interface defined in The `ResponseException` is an `Exception` sub-class that will be used to reject 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](#withoptions). +You can control this behavior via the [`withRejectErrorResponse()` method](#withrejecterrorresponse). The `getCode(): int` method can be used to return the HTTP response status code. diff --git a/src/Browser.php b/src/Browser.php index df5023c..4b6d3ce 100644 --- a/src/Browser.php +++ b/src/Browser.php @@ -458,6 +458,163 @@ public function send(RequestInterface $request) return $this->transaction->send($request); } + /** + * Changes the maximum timeout used for waiting for pending requests. + * + * You can pass in the number of seconds to use as a new timeout value: + * + * ```php + * $browser = $browser->withTimeout(10.0); + * ``` + * + * You can pass in a bool `false` to disable any timeouts. In this case, + * requests can stay pending forever: + * + * ```php + * $browser = $browser->withTimeout(false); + * ``` + * + * You can pass in a bool `true` to re-enable default timeout handling. This + * will respects PHP's `default_socket_timeout` setting (default 60s): + * + * ```php + * $browser = $browser->withTimeout(true); + * ``` + * + * See also [timeouts](#timeouts) for more details about timeout handling. + * + * Notice that the [`Browser`](#browser) is an immutable object, i.e. this + * method actually returns a *new* [`Browser`](#browser) instance with the + * given timeout value applied. + * + * @param bool|number $timeout + * @return self + */ + public function withTimeout($timeout) + { + if ($timeout === true) { + $timeout = null; + } elseif ($timeout === false) { + $timeout = -1; + } elseif ($timeout < 0) { + $timeout = 0; + } + + return $this->withOptions(array( + 'timeout' => $timeout, + )); + } + + /** + * Changes how HTTP redirects will be followed. + * + * You can pass in the maximum number of redirects to follow: + * + * ```php + * $new = $browser->withFollowRedirects(5); + * ``` + * + * The request will automatically be rejected when the number of redirects + * is exceeded. You can pass in a `0` to reject the request for any + * redirects encountered: + * + * ```php + * $browser = $browser->withFollowRedirects(0); + * + * $browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response) { + * // only non-redirected responses will now end up here + * var_dump($response->getHeaders()); + * }); + * ``` + * + * You can pass in a bool `false` to disable following any redirects. In + * this case, requests will resolve with the redirection response instead + * of following the `Location` response header: + * + * ```php + * $browser = $browser->withFollowRedirects(false); + * + * $browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response) { + * // any redirects will now end up here + * var_dump($response->getHeaderLine('Location')); + * }); + * ``` + * + * You can pass in a bool `true` to re-enable default redirect handling. + * This defaults to following a maximum of 10 redirects: + * + * ```php + * $browser = $browser->withFollowRedirects(true); + * ``` + * + * See also [redirects](#redirects) for more details about redirect handling. + * + * Notice that the [`Browser`](#browser) is an immutable object, i.e. this + * method actually returns a *new* [`Browser`](#browser) instance with the + * given redirect setting applied. + * + * @param bool|int $followRedirects + * @return self + */ + public function withFollowRedirects($followRedirects) + { + return $this->withOptions(array( + 'followRedirects' => $followRedirects !== false, + 'maxRedirects' => \is_bool($followRedirects) ? null : $followRedirects + )); + } + + /** + * Changes whether non-successful HTTP response status codes (4xx and 5xx) will be rejected. + * + * You can pass in a bool `false` to disable rejecting incoming responses + * that use a 4xx or 5xx response status code. In this case, requests will + * resolve with the response message indicating an error condition: + * + * ```php + * $browser = $browser->withRejectErrorResponse(false); + * + * $browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response) { + * // any HTTP response will now end up here + * var_dump($response->getStatusCode(), $response->getReasonPhrase()); + * }); + * ``` + * + * You can pass in a bool `true` to re-enable default status code handling. + * This defaults to rejecting any response status codes in the 4xx or 5xx + * range: + * + * ```php + * $browser = $browser->withRejectErrorResponse(true); + * + * $browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response) { + * // any successful HTTP response will now end up here + * var_dump($response->getStatusCode(), $response->getReasonPhrase()); + * }, function (Exception $e) { + * if ($e instanceof Clue\React\Buzz\Message\ResponseException) { + * // any HTTP response error message will now end up here + * $response = $e->getResponse(); + * var_dump($response->getStatusCode(), $response->getReasonPhrase()); + * } else { + * var_dump($e->getMessage()); + * } + * }); + * ``` + * + * Notice that the [`Browser`](#browser) is an immutable object, i.e. this + * method actually returns a *new* [`Browser`](#browser) instance with the + * given setting applied. + * + * @param bool $obeySuccessCode + * @return self + */ + public function withRejectErrorResponse($obeySuccessCode) + { + return $this->withOptions(array( + 'obeySuccessCode' => $obeySuccessCode, + )); + } + /** * Changes the base URL used to resolve relative URLs to. * @@ -524,55 +681,46 @@ public function withoutBase() } /** - * @param int $timeout + * Changes the HTTP protocol version that will be used for all subsequent requests. * - * @return Browser - */ - public function withTimeout($timeout) - { - return $this->withOptions(array( - 'timeout' => $timeout, - )); - } - - /** - * @param bool $followRedirects + * All the above [request methods](#request-methods) default to sending + * requests as HTTP/1.1. This is the preferred HTTP protocol version which + * also provides decent backwards-compatibility with legacy HTTP/1.0 + * servers. As such, there should rarely be a need to explicitly change this + * protocol version. * - * @return Browser - */ - public function withFollowRedirects($followRedirects) - { - return $this->withOptions(array( - 'followRedirects' => $followRedirects, - )); - } - - /** - * @param int $maxRedirects + * If you want to explicitly use the legacy HTTP/1.0 protocol version, you + * can use this method: * - * @return Browser - */ - public function withMaxRedirects($maxRedirects) - { - return $this->withOptions(array( - 'maxRedirects' => $maxRedirects, - )); - } - - /** - * @param bool $obeySuccessCode + * ```php + * $newBrowser = $browser->withProtocolVersion('1.0'); + * + * $newBrowser->get($url)->then(…); + * ``` * - * @return Browser + * Notice that the [`Browser`](#browser) is an immutable object, i.e. this + * method actually returns a *new* [`Browser`](#browser) instance with the + * new protocol version applied. + * + * @param string $protocolVersion HTTP protocol version to use, must be one of "1.1" or "1.0" + * @return self + * @throws InvalidArgumentException + * @since 2.8.0 */ - public function withObeySuccessCode($obeySuccessCode) + public function withProtocolVersion($protocolVersion) { - return $this->withOptions(array( - 'obeySuccessCode' => $obeySuccessCode, - )); + if (!\in_array($protocolVersion, array('1.0', '1.1'), true)) { + throw new InvalidArgumentException('Invalid HTTP protocol version, must be one of "1.1" or "1.0"'); + } + + $browser = clone $this; + $browser->protocolVersion = (string) $protocolVersion; + + return $browser; } /** - * Changes the [options](#options) to use: + * [Deprecated] Changes the [options](#options) to use: * * The [`Browser`](#browser) class exposes several options for the handling of * HTTP transactions. These options resemble some of PHP's @@ -580,11 +728,12 @@ public function withObeySuccessCode($obeySuccessCode) * can be controlled via the following API (and their defaults): * * ```php + * // deprecated * $newBrowser = $browser->withOptions(array( - * 'timeout' => null, - * 'followRedirects' => true, - * 'maxRedirects' => 10, - * 'obeySuccessCode' => true, + * 'timeout' => null, // see withTimeout() instead + * 'followRedirects' => true, // see withFollowRedirects() instead + * 'maxRedirects' => 10, // see withFollowRedirects() instead + * 'obeySuccessCode' => true, // see withRejectErrorResponse() instead * 'streaming' => false, // deprecated, see requestStreaming() instead * )); * ``` @@ -598,8 +747,10 @@ public function withObeySuccessCode($obeySuccessCode) * * @param array $options * @return self - * - * @deprecated Since 2.8.0 use withTimeout, withFollowRedirects, withMaxRedirects, or withObeySuccessCode instead. + * @deprecated 2.9.0 See self::withTimeout(), self::withFollowRedirects() and self::withRejectErrorResponse() instead. + * @see self::withTimeout() + * @see self::withFollowRedirects() + * @see self::withRejectErrorResponse() */ public function withOptions(array $options) { @@ -609,45 +760,6 @@ public function withOptions(array $options) return $browser; } - /** - * Changes the HTTP protocol version that will be used for all subsequent requests. - * - * All the above [request methods](#request-methods) default to sending - * requests as HTTP/1.1. This is the preferred HTTP protocol version which - * also provides decent backwards-compatibility with legacy HTTP/1.0 - * servers. As such, there should rarely be a need to explicitly change this - * protocol version. - * - * If you want to explicitly use the legacy HTTP/1.0 protocol version, you - * can use this method: - * - * ```php - * $newBrowser = $browser->withProtocolVersion('1.0'); - * - * $newBrowser->get($url)->then(…); - * ``` - * - * Notice that the [`Browser`](#browser) is an immutable object, i.e. this - * method actually returns a *new* [`Browser`](#browser) instance with the - * new protocol version applied. - * - * @param string $protocolVersion HTTP protocol version to use, must be one of "1.1" or "1.0" - * @return self - * @throws InvalidArgumentException - * @since 2.8.0 - */ - public function withProtocolVersion($protocolVersion) - { - if (!\in_array($protocolVersion, array('1.0', '1.1'), true)) { - throw new InvalidArgumentException('Invalid HTTP protocol version, must be one of "1.1" or "1.0"'); - } - - $browser = clone $this; - $browser->protocolVersion = (string) $protocolVersion; - - return $browser; - } - /** * @param string $method * @param string|UriInterface $url diff --git a/src/Message/ResponseException.php b/src/Message/ResponseException.php index 2b5ec44..081103a 100644 --- a/src/Message/ResponseException.php +++ b/src/Message/ResponseException.php @@ -9,7 +9,7 @@ * The `ResponseException` is an `Exception` sub-class that will be used to reject * 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). + * You can control this behavior via the [`withRejectErrorResponse()` method](#withrejecterrorresponse). * * The `getCode(): int` method can be used to * return the HTTP response status code. diff --git a/tests/BrowserTest.php b/tests/BrowserTest.php index b789f66..35c9a05 100644 --- a/tests/BrowserTest.php +++ b/tests/BrowserTest.php @@ -133,6 +133,76 @@ public function testSubmitSendsPostRequest() $this->browser->submit('http://example.com/', array()); } + public function testWithTimeoutTrueSetsDefaultTimeoutOption() + { + $this->sender->expects($this->once())->method('withOptions')->with(array('timeout' => null))->willReturnSelf(); + + $this->browser->withTimeout(true); + } + + public function testWithTimeoutFalseSetsNegativeTimeoutOption() + { + $this->sender->expects($this->once())->method('withOptions')->with(array('timeout' => -1))->willReturnSelf(); + + $this->browser->withTimeout(false); + } + + public function testWithTimeout10SetsTimeoutOption() + { + $this->sender->expects($this->once())->method('withOptions')->with(array('timeout' => 10))->willReturnSelf(); + + $this->browser->withTimeout(10); + } + + public function testWithTimeoutNegativeSetsZeroTimeoutOption() + { + $this->sender->expects($this->once())->method('withOptions')->with(array('timeout' => null))->willReturnSelf(); + + $this->browser->withTimeout(-10); + } + + public function testWithFollowRedirectsTrueSetsSenderOption() + { + $this->sender->expects($this->once())->method('withOptions')->with(array('followRedirects' => true, 'maxRedirects' => null))->willReturnSelf(); + + $this->browser->withFollowRedirects(true); + } + + public function testWithFollowRedirectsFalseSetsSenderOption() + { + $this->sender->expects($this->once())->method('withOptions')->with(array('followRedirects' => false, 'maxRedirects' => null))->willReturnSelf(); + + $this->browser->withFollowRedirects(false); + } + + public function testWithFollowRedirectsTenSetsSenderOption() + { + $this->sender->expects($this->once())->method('withOptions')->with(array('followRedirects' => true, 'maxRedirects' => 10))->willReturnSelf(); + + $this->browser->withFollowRedirects(10); + } + + public function testWithFollowRedirectsZeroSetsSenderOption() + { + $this->sender->expects($this->once())->method('withOptions')->with(array('followRedirects' => true, 'maxRedirects' => 0))->willReturnSelf(); + + $this->browser->withFollowRedirects(0); + } + + public function testWithRejectErrorResponseTrueSetsSenderOption() + { + $this->sender->expects($this->once())->method('withOptions')->with(array('obeySuccessCode' => true))->willReturnSelf(); + + $this->browser->withRejectErrorResponse(true); + } + + public function testWithRejectErrorResponseFalseSetsSenderOption() + { + $this->sender->expects($this->once())->method('withOptions')->with(array('obeySuccessCode' => false))->willReturnSelf(); + + $this->browser->withRejectErrorResponse(false); + } + public function testWithBase() { $browser = $this->browser->withBase('http://example.com/root'); diff --git a/tests/FunctionalBrowserTest.php b/tests/FunctionalBrowserTest.php index 97b7373..6e44f92 100644 --- a/tests/FunctionalBrowserTest.php +++ b/tests/FunctionalBrowserTest.php @@ -244,9 +244,9 @@ public function testTimeoutDelayedResponseAfterStreamingRequestShouldReject() /** * @doesNotPerformAssertions */ - public function testTimeoutNegativeShouldResolveSuccessfully() + public function testTimeoutFalseShouldResolveSuccessfully() { - Block\await($this->browser->withTimeout(-1)->get($this->base . 'get'), $this->loop); + Block\await($this->browser->withTimeout(false)->get($this->base . 'get'), $this->loop); } /** @@ -268,16 +268,16 @@ public function testRedirectRequestAbsolute() /** * @doesNotPerformAssertions */ - public function testNotFollowingRedirectsResolvesWithRedirectResult() + public function testFollowingRedirectsFalseResolvesWithRedirectResult() { $browser = $this->browser->withFollowRedirects(false); Block\await($browser->get($this->base . 'redirect-to?url=get'), $this->loop); } - public function testRejectingRedirectsRejects() + public function testFollowRedirectsZeroRejectsOnRedirect() { - $browser = $this->browser->withMaxRedirects(0); + $browser = $this->browser->withFollowRedirects(0); $this->setExpectedException('RuntimeException'); Block\await($browser->get($this->base . 'redirect-to?url=get'), $this->loop); @@ -368,6 +368,13 @@ public function testErrorStatusCodeRejectsWithResponseException() } } + public function testErrorStatusCodeDoesNotRejectWithRejectErrorResponseFalse() + { + $response = Block\await($this->browser->withRejectErrorResponse(false)->get($this->base . 'status/404'), $this->loop); + + $this->assertEquals(404, $response->getStatusCode()); + } + public function testPostString() { $response = Block\await($this->browser->post($this->base . 'post', array(), 'hello world'), $this->loop);