Skip to content

Commit

Permalink
Merge pull request #24 from xp-forge/feature/timeout
Browse files Browse the repository at this point in the history
Add possibility to modify read and connect timeouts
  • Loading branch information
thekid committed Jun 3, 2022
2 parents 2259ca9 + dcdf887 commit db3f77b
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 6 deletions.
14 changes: 9 additions & 5 deletions src/main/php/webservices/rest/Endpoint.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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());
Expand Down
19 changes: 18 additions & 1 deletion src/main/php/webservices/rest/RestRequest.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
/**
* REST request
*
* @test xp://webservices.rest.unittest.RestRequestTest
* @test webservices.rest.unittest.RestRequestTest
* @test webservices.rest.unittest.TimeoutTest
*/
class RestRequest {
use Headers;

private $method, $path, $cookies;
private $parameters= [];
private $payload= null;
private $timeouts= [null, null];

/**
* Creates a new REST request
Expand Down Expand Up @@ -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
*
Expand Down Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions src/main/php/webservices/rest/io/Transmission.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
63 changes: 63 additions & 0 deletions src/test/php/webservices/rest/unittest/TimeoutTest.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php namespace webservices\rest\unittest;

use peer\http\HttpConnection;
use unittest\{Assert, Before, Test};
use webservices\rest\{Endpoint, RestRequest};

class TimeoutTest {
const API = 'https://api.example.com';

private $endpoint, $conn;

#[Before]
public function endpoint() {
$this->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');
}
}

0 comments on commit db3f77b

Please sign in to comment.