Germán Lena
Germán Lena

Reputation: 887

Bad request with Twitter Streaming API and ReactPHP

I am working on a project that needs realtime data from twitter streaming api.

To do that I am using ReactPHP.

When I make the request to the twitter streamintg API, I am getting BadRequest response.

The request (with the payload) is the following:

POST /1.1/statuses/filter.json HTTP/1.0
Host: stream.twitter.com
User-Agent: React/alpha
Authorization: OAuth oauth_nonce="0f1add32ee06141004ea4c02d892bdaf",oauth_timestamp="1405130866",oauth_consumer_key="72XsNwUvJjw0xaSinIk1mzHL0",oauth_token="366141931-Zxljl6Ycwgdh9a5IYPqImJT5zeat2EJOAJOarTq6",oauth_signature_method="HMAC-SHA1",oauth_signature="Rs57ywc26IRNQA1l9zQZwoRMV5Q%3D"
Content-Type: application/x-www-form-urlencoded
Content-Length: 11

track=arg

and to do that I am using:

"jacobkiers/oauth": "1.0." => for oauth "react/http-client": "" => to connect to the streaming API

you can check the code here:

TwitterConnector.php

thanks

Upvotes: 0

Views: 366

Answers (2)

Germán Lena
Germán Lena

Reputation: 887

The previous comment fix the issue with the HTTP version. But I had another issue.

Twitters kept answering Unauthorize.

Debugging a little, I find out that the issue was that Reacts uses STREAM_CRYPTO_METHOD_TLS_CLIENT encription method instead of STREAM_CRYPTO_METHOD_SSLv23_CLIENT in

React\SocketClient\StreamEncryption

I cant find an elegant way to fix, just rewrite StreamEncryption to use SSL and SecureConnector to use the rewrited StreamEncryption

Upvotes: 0

WyriHaximus
WyriHaximus

Reputation: 1085

So the answer is really simple, you're making a HTTP 1.0 request while the Twitter API requires a HTTP 1.1 request.

The source of the problem resides in the Request object. In order to work around that I've quickly created two more classes. RequestData11:

<?php

use React\HttpClient\RequestData;

class RequestData11 extends RequestData
{
    public function setProtocolVersion($version)
    {
    }
}

And Client11:

<?php

use React\EventLoop\LoopInterface;
use React\HttpClient\Request;
use React\SocketClient\ConnectorInterface;

class Client11
{
    private $connectionManager;
    private $secureConnectionManager;

    public function __construct(ConnectorInterface $connector, ConnectorInterface     $secureConnector)
    {
        $this->connector = $connector;
        $this->secureConnector = $secureConnector;
    }

    public function request($method, $url, array $headers = array())
    {
        $requestData = new RequestData11($method, $url, $headers);
        $connectionManager = $this->getConnectorForScheme($requestData->getScheme());
        return new Request($connectionManager, $requestData);

    }

    private function getConnectorForScheme($scheme)
    {
        return ('https' === $scheme) ? $this->secureConnector : $this->connector;
    }
}

You normally would create a new client like this:

<?php

$client = $httpClientFactory->create($loop, $dnsResolver);

Instead you'll have to create it this way:

<?php

$connector = new Connector($loop, $dnsResolver);
$secureConnector = new SecureConnector($connector, $loop);
$client = new Client11($connector, $secureConnector);

This forces the client to use HTTP 1.1, beware though, the http-client is a 1.0 client so forcing it to 1.1 should only be done when you know what you're doing.

Note that you didn't lock the react\http-client version in your composer file so I have no clue what version you're using and the bove code might not work because of that.

Upvotes: 1

Related Questions