From dcdf887db50ab5944471e599532b1d6b3b3010a4 Mon Sep 17 00:00:00 2001 From: Timm Friebe Date: Thu, 2 Jun 2022 21:39:52 +0200 Subject: [PATCH] Add possibility to modify read and connect timeouts --- .../php/webservices/rest/Endpoint.class.php | 14 +++-- .../webservices/rest/RestRequest.class.php | 19 +++++- .../rest/io/Transmission.class.php | 3 + .../rest/unittest/TimeoutTest.class.php | 63 +++++++++++++++++++ 4 files changed, 93 insertions(+), 6 deletions(-) create mode 100755 src/test/php/webservices/rest/unittest/TimeoutTest.class.php diff --git a/src/main/php/webservices/rest/Endpoint.class.php b/src/main/php/webservices/rest/Endpoint.class.php index e3a6366..ac4e0dd 100755 --- a/src/main/php/webservices/rest/Endpoint.class.php +++ b/src/main/php/webservices/rest/Endpoint.class.php @@ -6,15 +6,16 @@ use lang\{Throwable, IllegalArgumentException}; use peer\URL; use peer\http\{HttpConnection, HttpRequest}; -use util\{URI, Authority}; use util\data\Marshalling; use util\log\Traceable; +use util\{URI, Authority}; use webservices\rest\io\{Buffered, Reader, Streamed, Traced, Transmission}; /** * Entry point class * - * @test xp://webservices.rest.unittest.EndpointTest + * @test webservices.rest.unittest.EndpointTest + * @test webservices.rest.unittest.ExecuteTest */ class Endpoint implements Traceable { protected $base, $formats, $transfer, $marshalling, $connections; @@ -186,12 +187,15 @@ public function setTrace($cat) { public function open(RestRequest $request) { $target= $this->base->resolve($request->path()); $conn= $this->connections->__invoke($target); - $conn->setConnectTimeout(10); - $conn->setTimeout(10); - $headers= array_merge($this->headers, $request->headers()); + + // Use request timeouts if supplied, otherwise use those of the connection + $timeouts= $request->timeouts(); + isset($timeouts[0]) && $conn->setTimeout($timeouts[0]); + isset($timeouts[1]) && $conn->setConnectTimeout($timeouts[1]); // RFC 6265: When the user agent generates an HTTP request, the user agent // MUST NOT attach more than one Cookie header field. + $headers= array_merge($this->headers, $request->headers()); $cookies= (array)$request->header('Cookie'); foreach ($request->cookies()->validFor($target) as $cookie) { $cookies[]= $cookie->name().'='.urlencode($cookie->value()); diff --git a/src/main/php/webservices/rest/RestRequest.class.php b/src/main/php/webservices/rest/RestRequest.class.php index d0cbb42..7cbe48e 100755 --- a/src/main/php/webservices/rest/RestRequest.class.php +++ b/src/main/php/webservices/rest/RestRequest.class.php @@ -3,7 +3,8 @@ /** * REST request * - * @test xp://webservices.rest.unittest.RestRequestTest + * @test webservices.rest.unittest.RestRequestTest + * @test webservices.rest.unittest.TimeoutTest */ class RestRequest { use Headers; @@ -11,6 +12,7 @@ class RestRequest { private $method, $path, $cookies; private $parameters= []; private $payload= null; + private $timeouts= [null, null]; /** * Creates a new REST request @@ -42,6 +44,9 @@ public function cookies() { return $this->cookies; } /** @return webservices.rest.Payload */ public function payload() { return $this->payload; } + /** @return (?float)[] */ + public function timeouts() { return $this->timeouts; } + /** * Uses a given HTTP method * @@ -86,6 +91,18 @@ public function passing($parameters) { return $this; } + /** + * Sets timeouts for reading and connecting + * + * @param ?float $read + * @param ?float $connect + * @return self + */ + public function waiting($read= null, $connect= null) { + $this->timeouts= [$read, $connect]; + return $this; + } + /** * Transfers a given payload, which is serialized according to the format * defined by the `Content-Type` header diff --git a/src/main/php/webservices/rest/io/Transmission.class.php b/src/main/php/webservices/rest/io/Transmission.class.php index d6fb0b4..5514bf9 100755 --- a/src/main/php/webservices/rest/io/Transmission.class.php +++ b/src/main/php/webservices/rest/io/Transmission.class.php @@ -19,6 +19,9 @@ public function __construct($conn, $request, $target= null) { $this->target= $target; } + /** @return peer.http.HttpConnection */ + public function connection() { return $this->conn; } + /** @return void */ public function start() { $this->output= $this->conn->open($this->request); diff --git a/src/test/php/webservices/rest/unittest/TimeoutTest.class.php b/src/test/php/webservices/rest/unittest/TimeoutTest.class.php new file mode 100755 index 0000000..3657e53 --- /dev/null +++ b/src/test/php/webservices/rest/unittest/TimeoutTest.class.php @@ -0,0 +1,63 @@ +endpoint= new Endpoint(self::API); + $this->conn= new HttpConnection(self::API); + } + + #[Test] + public function takes_timeouts_from_httpconnection() { + $endpoint= (clone $this->endpoint)->connecting(function($uri) { + $c= new HttpConnection($uri); + $c->setTimeout(600); + $c->setConnectTimeout(30); + return $c; + }); + $conn= $endpoint->open(new RestRequest('GET', '/'))->connection(); + + Assert::equals(600, $conn->getTimeout(), 'read'); + Assert::equals(30, $conn->getConnectTimeout(), 'connect'); + } + + #[Test] + public function default_timeouts() { + $conn= $this->endpoint->open(new RestRequest('GET', '/'))->connection(); + + Assert::equals($this->conn->getTimeout(), $conn->getTimeout(), 'read'); + Assert::equals($this->conn->getConnectTimeout(), $conn->getConnectTimeout(), 'connect'); + } + + #[Test] + public function change_read_timeout() { + $conn= $this->endpoint->open((new RestRequest('GET', '/'))->waiting(600, null))->connection(); + + Assert::equals(600, $conn->getTimeout(), 'read'); + Assert::equals($this->conn->getConnectTimeout(), $conn->getConnectTimeout(), 'connect'); + } + + #[Test] + public function change_connect_timeout() { + $conn= $this->endpoint->open((new RestRequest('GET', '/'))->waiting(null, 30))->connection(); + + Assert::equals($this->conn->getTimeout(), $conn->getTimeout(), 'read'); + Assert::equals(30, $conn->getConnectTimeout(), 'connect'); + } + + #[Test] + public function usage_via_resource_request_method() { + $conn= $this->endpoint->open($this->endpoint->resource('/')->request('GET')->waiting(600, 30))->connection(); + + Assert::equals(600, $conn->getTimeout(), 'read'); + Assert::equals(30, $conn->getConnectTimeout(), 'connect'); + } +} \ No newline at end of file