Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add OutgoingRequestInterface #6698

Merged
merged 9 commits into from
Oct 28, 2022
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
4 changes: 1 addition & 3 deletions app/Controllers/BaseController.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
namespace App\Controllers;

use CodeIgniter\Controller;
use CodeIgniter\HTTP\CLIRequest;
use CodeIgniter\HTTP\IncomingRequest;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Psr\Log\LoggerInterface;
Expand All @@ -24,7 +22,7 @@ abstract class BaseController extends Controller
/**
* Instance of the main Request object.
*
* @var CLIRequest|IncomingRequest
* @var RequestInterface
*/
protected $request;

Expand Down
10 changes: 5 additions & 5 deletions phpstan-baseline.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -270,11 +270,6 @@ parameters:
count: 1
path: system/HTTP/Request.php

-
message: "#^Property CodeIgniter\\\\HTTP\\\\Request\\:\\:\\$uri \\(CodeIgniter\\\\HTTP\\\\URI\\) in empty\\(\\) is not falsy\\.$#"
count: 1
path: system/HTTP/Request.php

-
message: "#^Property CodeIgniter\\\\HTTP\\\\URI\\:\\:\\$fragment \\(string\\) on left side of \\?\\? is not nullable\\.$#"
count: 1
Expand Down Expand Up @@ -459,3 +454,8 @@ parameters:
message: "#^Property Config\\\\View\\:\\:\\$plugins \\(array\\) on left side of \\?\\? is not nullable\\.$#"
count: 1
path: system/View/Parser.php

-
message: "#^Constructor of class CodeIgniter\\\\HTTP\\\\CURLRequest has an unused parameter \\$config\\.$#"
count: 1
path: system/HTTP/CURLRequest.php
4 changes: 2 additions & 2 deletions system/HTTP/CURLRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
/**
* A lightweight HTTP client for sending synchronous HTTP requests via cURL.
*/
class CURLRequest extends Request
class CURLRequest extends OutgoingRequest
{
/**
* The response object associated with this request
Expand Down Expand Up @@ -103,7 +103,7 @@ public function __construct(App $config, URI $uri, ?ResponseInterface $response
throw HTTPException::forMissingCurl(); // @codeCoverageIgnore
}

parent::__construct($config);
parent::__construct('GET', $uri);

$this->response = $response;
$this->baseURI = $uri->useRawQueryString();
Expand Down
4 changes: 4 additions & 0 deletions system/HTTP/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ public function getBody()
*
* @deprecated Use Message::headers() to make room for PSR-7
*
* @TODO Incompatible return value with PSR-7
*
* @codeCoverageIgnore
*/
public function getHeaders(): array
Expand All @@ -76,6 +78,8 @@ public function getHeaders(): array
*
* @deprecated Use Message::header() to make room for PSR-7
*
* @TODO Incompatible return value with PSR-7
*
* @codeCoverageIgnore
*/
public function getHeader(string $name)
Expand Down
161 changes: 161 additions & 0 deletions system/HTTP/OutgoingRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
<?php

/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace CodeIgniter\HTTP;

/**
* Representation of an outgoing, client-side request.
*/
class OutgoingRequest extends Message implements OutgoingRequestInterface
MGatner marked this conversation as resolved.
Show resolved Hide resolved
{
/**
* Request method.
*
* @var string
*/
protected $method;

/**
* A URI instance.
*
* @var URI|null
*/
protected $uri;

/**
* @param string $method HTTP method
* @param string|null $body
*/
public function __construct(
string $method,
?URI $uri = null,
array $headers = [],
$body = null,
string $version = '1.1'
) {
$this->method = $method;
$this->uri = $uri;

foreach ($headers as $header => $value) {
$this->setHeader($header, $value);
}

$this->body = $body;
$this->protocolVersion = $version;

if (! $this->hasHeader('Host') && $this->uri->getHost() !== '') {
$this->setHeader('Host', $this->getHostFromUri($this->uri));
}
}

private function getHostFromUri(URI $uri): string
{
$host = $uri->getHost();

return $host . ($uri->getPort() ? ':' . $uri->getPort() : '');
}

/**
* Get the request method.
*
* @param bool $upper Whether to return in upper or lower case.
*
* @deprecated The $upper functionality will be removed and this will revert to its PSR-7 equivalent
*/
public function getMethod(bool $upper = false): string
{
return ($upper) ? strtoupper($this->method) : strtolower($this->method);
}

/**
* Sets the request method. Used when spoofing the request.
*
* @return $this
*
* @deprecated Use withMethod() instead for immutability
*/
public function setMethod(string $method)
{
$this->method = $method;

return $this;
}

/**
* Returns an instance with the specified method.
*
* @param string $method
*
* @return static
*/
public function withMethod($method)
{
$request = clone $this;
$request->method = $method;

return $request;
}

/**
* Retrieves the URI instance.
*
* @return URI|null
*/
public function getUri()
{
return $this->uri;
}

/**
* Returns an instance with the provided URI.
*
* @param URI $uri New request URI to use.
* @param bool $preserveHost Preserve the original state of the Host header.
*
* @return static
*/
public function withUri(URI $uri, $preserveHost = false)
{
$request = clone $this;
$request->uri = $uri;

if ($preserveHost) {
if ($this->isHostHeaderMissingOrEmpty() && $uri->getHost() !== '') {
$request->setHeader('Host', $this->getHostFromUri($uri));

return $request;
}

if ($this->isHostHeaderMissingOrEmpty() && $uri->getHost() === '') {
return $request;
}

if (! $this->isHostHeaderMissingOrEmpty()) {
return $request;
}
}

if ($uri->getHost() !== '') {
$request->setHeader('Host', $this->getHostFromUri($uri));
}

return $request;
}

private function isHostHeaderMissingOrEmpty(): bool
MGatner marked this conversation as resolved.
Show resolved Hide resolved
{
if (! $this->hasHeader('Host')) {
return true;
}

return $this->header('Host')->getValue() === '';
}
}
94 changes: 94 additions & 0 deletions system/HTTP/OutgoingRequestInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php

/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace CodeIgniter\HTTP;

use InvalidArgumentException;

/**
* Representation of an outgoing, client-side request.
*
* Corresponds to Psr7\RequestInterface.
*/
interface OutgoingRequestInterface extends MessageInterface
MGatner marked this conversation as resolved.
Show resolved Hide resolved
{
/**
* Get the request method.
* An extension of PSR-7's getMethod to allow casing.
*
* @param bool $upper Whether to return in upper or lower case.
*
* @deprecated The $upper functionality will be removed and this will revert to its PSR-7 equivalent
*/
public function getMethod(bool $upper = false): string;

/**
* Return an instance with the provided HTTP method.
*
* While HTTP method names are typically all uppercase characters, HTTP
* method names are case-sensitive and thus implementations SHOULD NOT
* modify the given string.
*
* This method MUST be implemented in such a way as to retain the
* immutability of the message, and MUST return an instance that has the
* changed request method.
*
* @param string $method Case-sensitive method.
*
* @return static
*
* @throws InvalidArgumentException for invalid HTTP methods.
*/
public function withMethod($method);

/**
* Retrieves the URI instance.
*
* @see http://tools.ietf.org/html/rfc3986#section-4.3
*
* @return URI
*/
public function getUri();

/**
* Returns an instance with the provided URI.
*
* This method MUST update the Host header of the returned request by
* default if the URI contains a host component. If the URI does not
* contain a host component, any pre-existing Host header MUST be carried
* over to the returned request.
*
* You can opt-in to preserving the original state of the Host header by
* setting `$preserveHost` to `true`. When `$preserveHost` is set to
* `true`, this method interacts with the Host header in the following ways:
*
* - If the Host header is missing or empty, and the new URI contains
* a host component, this method MUST update the Host header in the returned
* request.
* - If the Host header is missing or empty, and the new URI does not contain a
* host component, this method MUST NOT update the Host header in the returned
* request.
* - If a Host header is present and non-empty, this method MUST NOT update
* the Host header in the returned request.
*
* This method MUST be implemented in such a way as to retain the
* immutability of the message, and MUST return an instance that has the
* new UriInterface instance.
*
* @see http://tools.ietf.org/html/rfc3986#section-4.3
*
* @param URI $uri New request URI to use.
* @param bool $preserveHost Preserve the original state of the Host header.
*
* @return static
*/
public function withUri(URI $uri, $preserveHost = false);
}
21 changes: 4 additions & 17 deletions system/HTTP/Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@
namespace CodeIgniter\HTTP;

use CodeIgniter\Validation\FormatRules;
use Config\App;

/**
* Representation of an HTTP request.
* Representation of an incoming, server-side HTTP request.
*/
class Request extends Message implements RequestInterface
class Request extends OutgoingRequest implements RequestInterface
MGatner marked this conversation as resolved.
Show resolved Hide resolved
{
use RequestTrait;

Expand All @@ -29,24 +30,10 @@ class Request extends Message implements RequestInterface
*/
protected $proxyIPs;

/**
* Request method.
*
* @var string
*/
protected $method;

/**
* A URI instance.
*
* @var URI
*/
protected $uri;

/**
* Constructor.
*
* @param object $config
* @param App $config
*
* @deprecated The $config is no longer needed and will be removed in a future version
*/
Expand Down
Loading