Ratchet: Get incoming connection headers

Created on 5 Sep 2015  路  10Comments  路  Source: ratchetphp/Ratchet

I want to ask - before "upgrading" to a ws connection, the client sends an ordinary HTTP request to the server. Is there any way I could get this request's headers?

I am interested in using a custom type of session storage, and if I could get a hold of the session ID that would be a piece of cake.

Thanks in advance!

question

All 10 comments

Yup, you just need to put together each of the components with your own in between, rather than using the App class. Start with implementing the HttpServerInterface:

class RequestInterceptor implements \Ratchet\Http\HttpServerInterface {
    private $delegate;
    public function __construct(HttpServerInterface $delegate) {
        $this->delegate = $delegate;
    }

    public function onOpen(\Ratchet\ConnectionInterface $conn, \Guzzle\Http\Message\RequestInterface $req) {
        // Do your stuff with the request object
        $this->delegate->onOpen($conn, $req);
    }
    // implement the rest of the methods: onMessage, onClose, onOpen
}

Then build your application with various components:

$app = new \Ratchet\Server\IoServer(
    new \Ratchet\Http\HttpServer(
        new RequestInterceptor(
            new \Ratchet\WebSocket\WsServer(
                new MyApp
            )
        )
    )
);
$app->run();

Hey, thank you very much for the fast reply and great example!

Hello, I got a basic idea of what happens here regarding how to get the request headers. But I don't know exactly, how to implement it. When I start the Shell-Server, I get the following exception:

Catchable fatal error: Argument 2 passed to Ratchet\Server\IoServer::__construct() must be an instance of React\Socket\ServerInterface, integer given, called in C:\xampp\htdocs\wstest\bin\newWS.php on line 38 and defined in C:\xampp\htdocs\wstest\vendor\cboden\ratchet\src\Ratchet\Server\IoServer.php on line 41

I thought by implementing HttpServerInterface there would be an instance of ServerInterface. I don't know why an integer is being there. There must be an error somewhere - but I can't figure out.

Here are my classes and the server - I hope someone can help me. Btw: My goal is to read the phpsessid from the cookie to look it up in the redis-store (where my session-data is saved), so that I can access/read the user's session data (SSL available via HAProxy).

<?php
namespace App\Controller\Lib\Websocket;

use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Http\HttpServerInterface;
use Guzzle\Common\Collection;
use Guzzle\Http\QueryString;

class RequestInterceptor implements \Ratchet\Http\HttpServerInterface {

    protected $clients;
    private $delegate;

    public function __construct(HttpServerInterface $delegate) {
        $this->delegate = $delegate;  
    }

    public function onOpen(ConnectionInterface $conn, \Guzzle\Http\Message\RequestInterface $request = null) {
        $this->delegate->onOpen($conn, $req);
    }

    public function onMessage(ConnectionInterface $from, $msg) {

    }

    public function onClose(ConnectionInterface $conn) {

    }

    public function onError(ConnectionInterface $conn, \Exception $e) {

    }
}

Chat-Example

    namespace App\Controller\Lib\Websocket;

    use Ratchet\MessageComponentInterface;
    use Ratchet\ConnectionInterface;

class Chat implements MessageComponentInterface {
    protected $clients;

    public function __construct() {
        $this->clients = new \SplObjectStorage;
        echo "Server is up";
    }

    public function onOpen(ConnectionInterface $conn) {
        // Store the new connection to send messages to later
        $this->clients->attach($conn);

        echo "New connection! ({$conn->resourceId})\n";
    }

    public function onMessage(ConnectionInterface $from, $msg) {
        $numRecv = count($this->clients) - 1;
        echo sprintf('Connection %d sending message "%s" to %d other connection%s' . "\n"
            , $from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's');

        foreach ($this->clients as $client) {
            if ($from !== $client) {
                // The sender is not the receiver, send to each client connected
                $client->send($msg);
            }
        }
    }

    public function onClose(ConnectionInterface $conn) {
        // The connection is closed, remove it, as we can no longer send it messages
        $this->clients->detach($conn);

        echo "Connection {$conn->resourceId} has disconnected\n";
    }

    public function onError(ConnectionInterface $conn, \Exception $e) {
        echo "An error has occurred: {$e->getMessage()}\n";

        $conn->close();
    }
}`

Server

<?php
$app = new \Ratchet\Server\IoServer(
    new \Ratchet\Http\HttpServer(
        new RequestInterceptor(
            new \Ratchet\WebSocket\WsServer(
                new Chat()
            )
        )
    ),
        8443
);

$app->run();

Thanks in advance

@cboden I don't want to get on your nerves, but I can't get it work and it's urgent. Please give me a hint or a small code how to set up the RequestInterceptor-Class correctly so that I can get the requestdata (e.g. cookies). Sorry...

And sorry for the malformed code-box. Don't know what happend.

Thanks

The construct method is different from the factory method. Instead of creating a new IoServer you probably want to do $app = IoServer::factory.

@cboden Thank you very much! It works like a charm! Just tried to var_dump the $request-variable withn onOpen and all data (including PHPSESSID) have been echoed. In combination with ssl-encryption (due to HAProxy) this must be a good way to exchange basic session-data to identify the user on the ws-side. Or am I wrong?

Many thanks for the help and the great work on ratchetphp itself!

btw for the others - this is the working instanciation of the ws-server:

$app = IoServer::factory(
    new \Ratchet\Http\HttpServer(
        new RequestInterceptor(
            new \Ratchet\WebSocket\WsServer(
                new Chat()
            )
        )
    ),
        8443
);

I copied TheMiller2015's code but it is not working for me.
The Chat server works, I tested it without the RequestInterceptor and everything works as expected.
I had to change onOpen signature in RequestInterceptor because the interface defines $request as Psr\Http\Message\RequestInterface instead of Guzzle\Http\Message\RequestInterface.
The server launches, but the chat doesn't work. RequestInterceptor and Chat are instantiated, but nothing else seems to happen. I'm surely doing something wrong, but cannot find out what.
Thank you for any kind of help

@mfrattola This is most likely one of the backwards compatibility breaks in 0.4. See the migration documentation for more info.

Thank you for your answer. It was a problem on my part (the way I tried to make the connection) when using the RequestInterceptor. Now it is working.
Again, thanks.

I just copied the code and it worked fine. I get the data but it is all protected. I can see it on the console but can't use it in the chat class. Am I doing something wrong?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

nazar-pc picture nazar-pc  路  8Comments

rukavina picture rukavina  路  4Comments

maliknaik16 picture maliknaik16  路  8Comments

clarkk picture clarkk  路  6Comments

lubatti picture lubatti  路  6Comments