diff --git a/src/Adapter/Swoole.php b/src/Adapter/Swoole.php index 627c431..65308ba 100644 --- a/src/Adapter/Swoole.php +++ b/src/Adapter/Swoole.php @@ -208,7 +208,7 @@ private function executeRequest( RequestOptions $options, ?callable $chunkCallback ): Response { - if (!preg_match('~^https?://~i', $url)) { + if (!str_starts_with($url, 'http://') && !str_starts_with($url, 'https://')) { $url = 'http://' . $url; } diff --git a/src/Client.php b/src/Client.php index 50ac37a..ebbac89 100644 --- a/src/Client.php +++ b/src/Client.php @@ -53,6 +53,19 @@ public function __construct(?Adapter $adapter = null) $this->adapter = $adapter ?? new Curl(); } + protected string $baseUrl = ''; + + public function setBaseUrl(string $baseUrl): self + { + $this->baseUrl = $baseUrl; + return $this; + } + + public function getBaseUrl(): string + { + return $this->baseUrl; + } + /** * @param string $key * @param string $value @@ -166,7 +179,7 @@ public function setMaxRetries(int $maxRetries): self * * @param array $flags * @return self - */ + */ public function setJsonEncodeFlags(array $flags): self { $this->jsonEncodeFlags = array_reduce($flags, function ($carry, $flag) { @@ -289,6 +302,10 @@ public function fetch( ?int $timeoutMs = null, ?int $connectTimeoutMs = null, ): Response { + if (!empty($this->baseUrl) && !str_starts_with($url, 'http://') && !str_starts_with($url, 'https://')) { + $url = rtrim($this->baseUrl, '/') . '/' . ltrim($url, '/'); + } + if (!in_array($method, [self::METHOD_PATCH, self::METHOD_GET, self::METHOD_CONNECT, self::METHOD_DELETE, self::METHOD_POST, self::METHOD_HEAD, self::METHOD_OPTIONS, self::METHOD_PUT, self::METHOD_TRACE])) { throw new Exception("Unsupported HTTP method"); } diff --git a/tests/ClientTest.php b/tests/ClientTest.php index 59843e3..c453a90 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -320,6 +320,146 @@ public function testSetGetUserAgent(): void $this->assertSame($userAgent, $client->getUserAgent()); } + /** + * Test setting and getting the base URL. + * @return void + */ + public function testSetGetBaseUrl(): void + { + $client = new Client(); + $baseUrl = "http://localhost:8000"; + + $client->setBaseUrl($baseUrl); + + $this->assertEquals($baseUrl, $client->getBaseUrl()); + } + + /** + * Test base URL prepending to relative URLs. + * @return void + */ + public function testBaseUrlWithRelativePath(): void + { + $client = new Client(); + $client->setBaseUrl('http://localhost:8000'); + + $resp = $client->fetch( + url: '', + method: Client::METHOD_GET + ); + + if ($resp->getStatusCode() === 200) { + /** @var array $respData */ + $respData = $resp->json(); + $this->assertEquals($respData['method'], Client::METHOD_GET); + $this->assertEquals($respData['url'], 'localhost:8000'); + } else { + echo "Please configure your PHP inbuilt SERVER"; + } + } + + /** + * Test base URL with path appending. + * @return void + */ + public function testBaseUrlWithPath(): void + { + $client = new Client(); + $client->setBaseUrl('http://localhost:8000'); + + $resp = $client->fetch( + url: 'redirect', + method: Client::METHOD_GET + ); + + if ($resp->getStatusCode() === 200) { + /** @var array $respData */ + $respData = $resp->json(); + $this->assertEquals($respData['page'], "redirectedPage"); + } else { + echo "Please configure your PHP inbuilt SERVER"; + } + } + + /** + * Test base URL doesn't interfere with absolute URLs. + * @return void + */ + public function testBaseUrlWithAbsoluteUrl(): void + { + $client = new Client(); + $client->setBaseUrl('http://example.com'); + + $resp = $client->fetch( + url: 'http://localhost:8000', + method: Client::METHOD_GET + ); + + if ($resp->getStatusCode() === 200) { + /** @var array $respData */ + $respData = $resp->json(); + $this->assertEquals($respData['method'], Client::METHOD_GET); + $this->assertEquals($respData['url'], 'localhost:8000'); + } else { + echo "Please configure your PHP inbuilt SERVER"; + } + } + + /** + * Test base URL with query parameters. + * @return void + */ + public function testBaseUrlWithQuery(): void + { + $client = new Client(); + $client->setBaseUrl('http://localhost:8000'); + + $resp = $client->fetch( + url: '', + method: Client::METHOD_GET, + query: [ + 'name' => 'John Doe', + 'age' => '30', + ] + ); + + if ($resp->getStatusCode() === 200) { + /** @var array $respData */ + $respData = $resp->json(); + $this->assertEquals($respData['method'], Client::METHOD_GET); + $this->assertEquals( + json_encode($respData['query']), + json_encode(['name' => 'John Doe', 'age' => '30']) + ); + } else { + echo "Please configure your PHP inbuilt SERVER"; + } + } + + /** + * Test base URL with trailing slash normalization. + * @return void + */ + public function testBaseUrlTrailingSlashNormalization(): void + { + $client = new Client(); + + // Test with trailing slash in base URL + $client->setBaseUrl('http://localhost:8000/'); + $resp = $client->fetch( + url: '/redirect', + method: Client::METHOD_GET + ); + + if ($resp->getStatusCode() === 200) { + /** @var array $respData */ + $respData = $resp->json(); + $this->assertEquals($respData['page'], "redirectedPage"); + } else { + echo "Please configure your PHP inbuilt SERVER"; + } + } + /** * Data provider for testFetch * @return array>