Skip to content

Commit

Permalink
Update README
Browse files Browse the repository at this point in the history
  • Loading branch information
legionth committed Apr 10, 2017
1 parent a5106b3 commit cb9d103
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 25 deletions.
135 changes: 120 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ This is an HTTP server which responds with `Hello World` to every request.
$loop = React\EventLoop\Factory::create();
$socket = new React\Socket\Server(8080, $loop);

$http = new Server($socket, function (RequestInterface $request) {
$http = new Server($socket, function (ServerRequestInterface $request) {
return new Response(
200,
array('Content-Type' => 'text/plain'),
Expand Down Expand Up @@ -54,7 +54,7 @@ constructor with the respective [request](#request) and
```php
$socket = new React\Socket\Server(8080, $loop);

$http = new Server($socket, function (RequestInterface $request) {
$http = new Server($socket, function (ServerRequestInterface $request) {
return new Response(
200,
array('Content-Type' => 'text/plain'),
Expand All @@ -75,7 +75,7 @@ $socket = new React\Socket\SecureServer($socket, $loop, array(
'local_cert' => __DIR__ . '/localhost.pem'
));

$http = new Server($socket, function (RequestInterface $request) {
$http = new Server($socket, function (ServerRequestInterface $request) {
return new Response(
200,
array('Content-Type' => 'text/plain'),
Expand Down Expand Up @@ -137,11 +137,13 @@ connections and then processing each incoming HTTP request.
The request object will be processed once the request headers have
been received by the client.
This request object implements the
[PSR-7 ServerRequestInterface](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-7-http-message.md#321-psrhttpmessageserverrequestinterface)
which in turn extends the
[PSR-7 RequestInterface](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-7-http-message.md#32-psrhttpmessagerequestinterface)
and will be passed to the callback function like this.

```php
$http = new Server($socket, function (RequestInterface $request) {
```php
$http = new Server($socket, function (ServerRequestInterface $request) {
$body = "The method of the request is: " . $request->getMethod();
$body .= "The requested path is: " . $request->getUri()->getPath();

Expand All @@ -153,8 +155,41 @@ $http = new Server($socket, function (RequestInterface $request) {
});
```

The `Server` will currently add server-side parameters, analog to the `$_SERVER` variable:

* `server_address`
The current IP address of the server
* `server_port`
The current port of the server
* `remote_address`
The IP address of the request sender
* `remote_port`
Port of the request sender
* `request_time`
Unix timestamp of the moment, the complete request header was received
* `request_time_float`
Unix timestamp in microseconds of the moment, the complete request header was
received

The `server` and `remote` parameters MAY missing if the client or server unexpected
closes the connection.

```php
$http = new Server($socket, function (ServerRequestInterface $request) {
$body = "Your IP is: " . $request->getServerParams()['remote_address'];

return new Response(
200,
array('Content-Type' => 'text/plain'),
$body
);
});
```

For more details about the request object, check out the documentation of
[PSR-7 RequestInterface](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-7-http-message.md#32-psrhttpmessagerequestinterface).
and
[PSR-7 ServerRequestInterface](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-7-http-message.md#321-psrhttpmessageserverrequestinterface)

Note that the request object will be processed once the request headers have
been received.
Expand Down Expand Up @@ -184,7 +219,7 @@ Instead, you should use the `ReactPHP ReadableStreamInterface` which
gives you access to the incoming request body as the individual chunks arrive:

```php
$http = new Server($socket, function (RequestInterface $request) {
$http = new Server($socket, function (ServerRequestInterface $request) {
return new Promise(function ($resolve, $reject) use ($request) {
$contentLength = 0;
$request->getBody()->on('data', function ($data) use (&$contentLength) {
Expand Down Expand Up @@ -248,7 +283,7 @@ Note that this value may be `null` if the request body size is unknown in
advance because the request message uses chunked transfer encoding.

```php
$http = new Server($socket, function (RequestInterface $request) {
$http = new Server($socket, function (ServerRequestInterface $request) {
$size = $request->getBody()->getSize();
if ($size === null) {
$body = 'The request does not contain an explicit length.';
Expand Down Expand Up @@ -290,6 +325,76 @@ Allowed).
can in fact use a streaming response body for the tunneled application data.
See also [example #21](examples) for more details.

The cookies of the request, will also be added to the request object by the `Server`:

```php
$http = new Server($socket, function (ServerRequestInterface $request) {
$key = 'react';
$value = 'php';

if ($request->getCookieParams() !== array()) {
$body = "Your cookie value is: " . $request->getCookieParams()[$key];

return new Response(
200,
array('Content-Type' => 'text/plain'),
$body
);
}

return new Response(
200,
array(
'Content-Type' => 'text/plain',
'Set-Cookie' => $key . '=' . $value
),
"Your cookie has been set."
);
});
```

The above example should be executed via a web browser, a cookie will be set
on the first request contation the key-value pair 'test=php'.
On a second request to the server the cookie is accessed by the `getCookieParams()`
method, and will be written into the body.

According to the cookie [RFC 6265](https://tools.ietf.org/html/rfc6265#section-4.1.1)
some non-alphanumeric characters are not allowed in the name or value.
Use the `urlencode()` function to encode such
non-alphanumeric characters.
This encoding is also used internally when decoding the name and value of cookies
(which is in line with other implementations, such as PHP's cookie functions).

```php
$http = new Server($socket, function (ServerRequestInterface $request) {
$key = 'react\php';

if (isset($request->getCookieParams()[$key])) {
$body = "Your cookie value is: " . $request->getCookieParams()[$key];

return new Response(
200,
array('Content-Type' => 'text/plain'),
$body
);
}

return new Response(
200,
array(
'Content-Type' => 'text/plain',
'Set-Cookie' => urlencode($key) . '=' . urlencode('test;more')
),
"Your cookie has been set."
);
});
```

The above example will set a cookie in the browser with the key 'react/php' and
the value 'test;more'.
The key and values received by the `getCookieParams()` method
are already decoded.

### Response

The callback function passed to the constructor of the [Server](#server)
Expand All @@ -308,7 +413,7 @@ but feel free to use any implemantation of the
`PSR-7 ResponseInterface` you prefer.

```php
$http = new Server($socket, function (RequestInterface $request) {
$http = new Server($socket, function (ServerRequestInterface $request) {
return new Response(
200,
array('Content-Type' => 'text/plain'),
Expand All @@ -327,7 +432,7 @@ To prevent this you SHOULD use a
This example shows how such a long-term action could look like:

```php
$server = new \React\Http\Server($socket, function (RequestInterface $request) use ($loop) {
$server = new \React\Http\Server($socket, function (ServerRequestInterface $request) use ($loop) {
return new Promise(function ($resolve, $reject) use ($request, $loop) {
$loop->addTimer(1.5, function() use ($loop, $resolve) {
$response = new Response(
Expand Down Expand Up @@ -355,7 +460,7 @@ Note that other implementations of the `PSR-7 ResponseInterface` likely
only support string.

```php
$server = new Server($socket, function (RequestInterface $request) use ($loop) {
$server = new Server($socket, function (ServerRequestInterface $request) use ($loop) {
$stream = new ReadableStream();

$timer = $loop->addPeriodicTimer(0.5, function () use ($stream) {
Expand Down Expand Up @@ -389,7 +494,7 @@ If you know the length of your stream body, you MAY specify it like this instead

```php
$stream = new ReadableStream()
$server = new Server($socket, function (RequestInterface $request) use ($loop, $stream) {
$server = new Server($socket, function (ServerRequestInterface $request) use ($loop, $stream) {
return new Response(
200,
array(
Expand Down Expand Up @@ -437,7 +542,7 @@ A `Date` header will be automatically added with the system date and time if non
You can add a custom `Date` header yourself like this:

```php
$server = new Server($socket, function (RequestInterface $request) {
$server = new Server($socket, function (ServerRequestInterface $request) {
return new Response(200, array('Date' => date('D, d M Y H:i:s T')));
});
```
Expand All @@ -446,7 +551,7 @@ If you don't have a appropriate clock to rely on, you should
unset this header with an empty string:

```php
$server = new Server($socket, function (RequestInterface $request) {
$server = new Server($socket, function (ServerRequestInterface $request) {
return new Response(200, array('Date' => ''));
});
```
Expand All @@ -455,7 +560,7 @@ Note that it will automatically assume a `X-Powered-By: react/alpha` header
unless your specify a custom `X-Powered-By` header yourself:

```php
$server = new Server($socket, function (RequestInterface $request) {
$server = new Server($socket, function (ServerRequestInterface $request) {
return new Response(200, array('X-Powered-By' => 'PHP 3'));
});
```
Expand All @@ -464,7 +569,7 @@ If you do not want to send this header at all, you can use an empty string as
value like this:

```php
$server = new Server($socket, function (RequestInterface $request) {
$server = new Server($socket, function (ServerRequestInterface $request) {
return new Response(200, array('X-Powered-By' => ''));
});
```
Expand Down
41 changes: 31 additions & 10 deletions src/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
* ```php
* $socket = new React\Socket\Server(8080, $loop);
*
* $http = new Server($socket, function (RequestInterface $request) {
* $http = new Server($socket, function (ServerRequestInterface $request) {
* return new Response(
* 200,
* array('Content-Type' => 'text/plain'),
Expand All @@ -47,7 +47,7 @@
* 'local_cert' => __DIR__ . '/localhost.pem'
* ));
*
* $http = new Server($socket, function (RequestInterface $request) {
* $http = new Server($socket, function (ServerRequestInterface $request) {
* return new Response(
* 200,
* array('Content-Type' => 'text/plain'),
Expand Down Expand Up @@ -82,6 +82,22 @@
* });
* ```
*
* The server will also emit an `error` event if you return an invalid
* type in the callback function or have a unhandled `Exception`.
* If your callback function throws an exception,
* the `Server` will emit a `RuntimeException` and add the thrown exception
* as previous:
*
* ```php
* $http->on('error', function (Exception $e) {
* echo 'Error: ' . $e->getMessage() . PHP_EOL;
* if ($e->getPrevious() !== null) {
* $previousException = $e->getPrevious();
* echo $previousException->getMessage() . PHP_EOL;
* }
* });
* ```
*
* Note that the request object can also emit an error.
* Check out [request](#request) for more details.
*
Expand All @@ -100,15 +116,17 @@ class Server extends EventEmitter
* as HTTP.
*
* For each request, it executes the callback function passed to the
* constructor with the respective [`Request`](#request) and
* [`Response`](#response) objects:
* constructor with the respective [`request`](#request) object:
*
* ```php
* $socket = new React\Socket\Server(8080, $loop);
*
* $http = new Server($socket, function (Request $request, Response $response) {
* $response->writeHead(200, array('Content-Type' => 'text/plain'));
* $response->end("Hello World!\n");
* $http = new Server($socket, function (ServerRequestInterface $request) {
* return new Response(
* 200,
* array('Content-Type' => 'text/plain'),
* "Hello World!\n"
* );
* });
* ```
*
Expand All @@ -122,9 +140,12 @@ class Server extends EventEmitter
* 'local_cert' => __DIR__ . '/localhost.pem'
* ));
*
* $http = new Server($socket, function (Request $request, Response $response) {
* $response->writeHead(200, array('Content-Type' => 'text/plain'));
* $response->end("Hello World!\n");
* $http = new Server($socket, function (ServerRequestInterface $request $request) {
* return new Response(
* 200,
* array('Content-Type' => 'text/plain'),
* "Hello World!\n"
* );
* });
*```
*
Expand Down

0 comments on commit cb9d103

Please sign in to comment.