Skip to main content

Requests

A Request is an outgoing HTTP request, such as the one an HTTP client sends. For a request the server received, use a server request, which behaves the same way and adds the server-side data.

Create a request​

use Dirthara\Http\Uri;
use Dirthara\Http\Request;
use Dirthara\Http\Factory\StreamFactory;

$request = new Request(
'POST',
new Uri('https://api.example.com/users'),
new StreamFactory()->createStream('{"name":"Ada"}'),
['Content-Type' => 'application/json'],
);
ParameterTypeDefaultMeaning
methodstringThe request method, such as 'GET'.
uriUriInterfaceThe URI the request is for.
bodyStreamInterfaceThe request body.
headersarray<string, string|string[]>[]Headers by name.
protocolVersionstring'1.1'The HTTP protocol version.

The request factory creates a request from a method and a URI or URI string, with an empty body.

Method​

getMethod() returns the method, and withMethod($method) changes it. The method keeps its case, because methods are case-sensitive: 'get' and 'GET' are different methods. A method must be a token, the same character set as a header name; anything else, including an empty string, throws InvalidRequestException::invalidMethod().

URI and the Host header​

When a request is created, a URI with a host sets the Host header, including a non-standard port such as example.com:8080, unless the headers already hold a non-empty Host. The Host header is placed first, as RFC 9112 asks.

withUri($uri, $preserveHost) changes the URI and updates Host to match:

URI has a hostpreserveHostRequest has a non-empty HostResult
YesfalseEitherHost is set from the new URI.
YestrueYesHost is kept.
YestrueNoHost is set from the new URI.
NoEitherEitherHost is kept.

A Host header set from the URI keeps any case the request already uses for it, such as host, and moves to the front of the headers.

Request target​

The request target is what goes on the request line, such as /users?page=2. Unless one was set, getRequestTarget() derives it from the URI: the path with exactly one leading slash, followed by ? and the query when there is one. An empty path gives /, a rootless path users gives /users, and //evil.example/path gives /evil.example/path, so leading slashes cannot make the target read as an authority.

The target derived from a URI is validated when the request is created and in withUri(). This package's Uri always produces a valid one, but a UriInterface from another library can return a path or query holding whitespace or a line break, which would split the request line. Such a URI throws InvalidRequestException::invalidRequestTarget().

withRequestTarget($target) sets it explicitly, for the other forms HTTP allows, such as * for OPTIONS or example.com:443 for CONNECT. An explicit target stays in place when the URI changes.

$options = $request->withMethod('OPTIONS')->withRequestTarget('*');

A target cannot be empty or contain whitespace or control characters; otherwise InvalidRequestException::invalidRequestTarget() is thrown.

note

The exception for an invalid request target carries neither the target in its message nor any context, because a target's query string can hold tokens.