Guzzle changes
Taking advantage of RequestFactory LSB New tests to make sure Guzzle returns what's expected
This commit is contained in:
parent
13009cf673
commit
ef6e777f31
@ -2,7 +2,7 @@
|
|||||||
<phpunit
|
<phpunit
|
||||||
forceCoversAnnotation="true"
|
forceCoversAnnotation="true"
|
||||||
mapTestClassNameToCoveredClassName="true"
|
mapTestClassNameToCoveredClassName="true"
|
||||||
bootstrap="tests/bootstrap.php"
|
bootstrap="vendor/autoload.php"
|
||||||
colors="true"
|
colors="true"
|
||||||
backupGlobals="false"
|
backupGlobals="false"
|
||||||
backupStaticAttributes="false"
|
backupStaticAttributes="false"
|
||||||
|
@ -1,222 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Component\WebSocket\Guzzle\Http\Message;
|
namespace Ratchet\Component\WebSocket\Guzzle\Http\Message;
|
||||||
use Guzzle\Common\Collection;
|
use Guzzle\Http\Message\RequestFactory as GuzzleRequestFactory;
|
||||||
use Guzzle\Http\EntityBody;
|
use Guzzle\Http\EntityBody;
|
||||||
use Guzzle\Http\QueryString;
|
|
||||||
use Guzzle\Http\Url;
|
|
||||||
use Guzzle\Http\Message\RequestFactoryInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default HTTP request factory used to create the default
|
|
||||||
* Guzzle\Http\Message\Request and Guzzle\Http\Message\EntityEnclosingRequest
|
|
||||||
* objects.
|
|
||||||
*/
|
|
||||||
class RequestFactory implements RequestFactoryInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var Standard request headers
|
|
||||||
*/
|
|
||||||
protected static $requestHeaders = array(
|
|
||||||
'accept', 'accept-charset', 'accept-encoding', 'accept-language',
|
|
||||||
'authorization', 'cache-control', 'connection', 'cookie',
|
|
||||||
'content-length', 'content-type', 'date', 'expect', 'from', 'host',
|
|
||||||
'if-match', 'if-modified-since', 'if-none-match', 'if-range',
|
|
||||||
'if-unmodified-since', 'max-forwards', 'pragma', 'proxy-authorization',
|
|
||||||
'range', 'referer', 'te', 'transfer-encoding', 'upgrade', 'user-agent',
|
|
||||||
'via', 'warning'
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var RequestFactory Singleton instance of the default request factory
|
|
||||||
*/
|
|
||||||
protected static $instance;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string Class to instantiate for GET, HEAD, and DELETE requests
|
|
||||||
*/
|
|
||||||
protected $requestClass = 'Guzzle\\Http\\Message\\EntityEnclosingRequest';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string Class to instantiate for POST and PUT requests
|
|
||||||
*/
|
|
||||||
protected $entityEnclosingRequestClass = 'Guzzle\\Http\\Message\\EntityEnclosingRequest';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a cached instance of the default request factory
|
|
||||||
*
|
|
||||||
* @return RequestFactory
|
|
||||||
*/
|
|
||||||
public static function getInstance()
|
|
||||||
{
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
if (!self::$instance) {
|
|
||||||
self::$instance = new self();
|
|
||||||
}
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
|
|
||||||
return self::$instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
class RequestFactory extends GuzzleRequestFactory {
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function parseMessage($message)
|
public function create($method, $url, $headers = null, $body = null) {
|
||||||
{
|
$c = $this->entityEnclosingRequestClass;
|
||||||
if (!$message) {
|
$request = new $c($method, $url, $headers);
|
||||||
return false;
|
if ($body) {
|
||||||
}
|
$request->setBody(EntityBody::factory($body));
|
||||||
|
|
||||||
$headers = new Collection();
|
|
||||||
$scheme = $host = $body = $method = $user = $pass = $query = $port = $version = $protocol = '';
|
|
||||||
$path = '/';
|
|
||||||
|
|
||||||
// Inspired by https://github.com/kriswallsmith/Buzz/blob/message-interfaces/lib/Buzz/Message/Parser/Parser.php#L16
|
|
||||||
$lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE);
|
|
||||||
for ($i = 0, $c = count($lines); $i < $c; $i += 2) {
|
|
||||||
|
|
||||||
$line = $lines[$i];
|
|
||||||
|
|
||||||
// If two line breaks were encountered, then this is the body
|
|
||||||
if (empty($line)) {
|
|
||||||
$body = implode('', array_slice($lines, $i + 2));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse message headers
|
|
||||||
$matches = array();
|
|
||||||
if (!$method && preg_match('#^(?P<method>[A-Za-z]+)\s+(?P<path>/.*)\s+(?P<protocol>\w+)/(?P<version>\d\.\d)\s*$#i', $line, $matches)) {
|
|
||||||
$method = strtoupper($matches['method']);
|
|
||||||
$protocol = strtoupper($matches['protocol']);
|
|
||||||
$path = $matches['path'];
|
|
||||||
$version = $matches['version'];
|
|
||||||
$scheme = 'http';
|
|
||||||
} else if (strpos($line, ':')) {
|
|
||||||
list($key, $value) = explode(':', $line, 2);
|
|
||||||
$key = trim($key);
|
|
||||||
// Normalize standard HTTP headers
|
|
||||||
if (in_array(strtolower($key), self::$requestHeaders)) {
|
|
||||||
$key = str_replace(' ', '-', ucwords(str_replace('-', ' ', $key)));
|
|
||||||
}
|
|
||||||
// Headers are case insensitive
|
|
||||||
$headers->add($key, trim($value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for the Host header
|
|
||||||
if (isset($headers['Host'])) {
|
|
||||||
$host = $headers['Host'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strpos($host, ':')) {
|
|
||||||
list($host, $port) = array_map('trim', explode(':', $host));
|
|
||||||
if ($port == 443) {
|
|
||||||
$scheme = 'https';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$port = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for basic authorization
|
|
||||||
$auth = isset($headers['Authorization']) ? $headers['Authorization'] : '';
|
|
||||||
|
|
||||||
if ($auth) {
|
|
||||||
list($type, $data) = explode(' ', $auth);
|
|
||||||
if (strtolower($type) == 'basic') {
|
|
||||||
$data = base64_decode($data);
|
|
||||||
list($user, $pass) = explode(':', $data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if a query is present
|
|
||||||
$qpos = strpos($path, '?');
|
|
||||||
if ($qpos) {
|
|
||||||
$query = substr($path, $qpos);
|
|
||||||
$path = substr($path, 0, $qpos);
|
|
||||||
}
|
|
||||||
|
|
||||||
return array(
|
|
||||||
'method' => $method,
|
|
||||||
'protocol' => $protocol,
|
|
||||||
'protocol_version' => $version,
|
|
||||||
'parts' => array(
|
|
||||||
'scheme' => $scheme,
|
|
||||||
'host' => $host,
|
|
||||||
'port' => $port,
|
|
||||||
'user' => $user,
|
|
||||||
'pass' => $pass,
|
|
||||||
'path' => $path,
|
|
||||||
'query' => $query
|
|
||||||
),
|
|
||||||
'headers' => $headers->getAll(),
|
|
||||||
'body' => $body
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function fromMessage($message)
|
|
||||||
{
|
|
||||||
$parsed = $this->parseMessage($message);
|
|
||||||
|
|
||||||
if (!$parsed) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$request = $this->fromParts($parsed['method'], $parsed['parts'],
|
|
||||||
$parsed['headers'], $parsed['body'], $parsed['protocol'],
|
|
||||||
$parsed['protocol_version']);
|
|
||||||
|
|
||||||
// EntityEnclosingRequest adds an "Expect: 100-Continue" header when
|
|
||||||
// using a raw request body for PUT or POST requests. This factory
|
|
||||||
// method should accurately reflect the message, so here we are
|
|
||||||
// removing the Expect header if one was not supplied in the message.
|
|
||||||
if (!isset($parsed['headers']['Expect'])) {
|
|
||||||
$request->removeHeader('Expect');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $request;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function fromParts($method, array $parts, $headers = null, $body = null, $protocol = 'HTTP', $protocolVersion = '1.1')
|
|
||||||
{
|
|
||||||
return $this->create($method, Url::buildUrl($parts, true), $headers, $body)
|
|
||||||
->setProtocolVersion($protocolVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function create($method, $url, $headers = null, $body = null)
|
|
||||||
{
|
|
||||||
if ($method != 'POST' && $method != 'PUT' && $method != 'PATCH') {
|
|
||||||
$c = $this->requestClass;
|
|
||||||
$request = new $c($method, $url, $headers);
|
|
||||||
if ($body) {
|
|
||||||
$request->setBody(EntityBody::factory($body));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$c = $this->entityEnclosingRequestClass;
|
|
||||||
$request = new $c($method, $url, $headers);
|
|
||||||
|
|
||||||
if ($body) {
|
|
||||||
if ($method == 'POST' && (is_array($body) || $body instanceof Collection)) {
|
|
||||||
$request->addPostFields($body);
|
|
||||||
} else if (is_resource($body) || $body instanceof EntityBody) {
|
|
||||||
$request->setBody($body, (string) $request->getHeader('Content-Type'));
|
|
||||||
} else {
|
|
||||||
$request->setBody((string) $body, (string) $request->getHeader('Content-Type'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix chunked transfers based on the passed headers
|
|
||||||
if (isset($headers['Transfer-Encoding']) && $headers['Transfer-Encoding'] == 'chunked') {
|
|
||||||
$request->removeHeader('Content-Length')
|
|
||||||
->setHeader('Transfer-Encoding', 'chunked');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $request;
|
return $request;
|
||||||
|
@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
namespace Ratchet\Tests\Component\WebSocket\Guzzle\Http\Message;
|
||||||
|
use Ratchet\Component\WebSocket\Guzzle\Http\Message\RequestFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers Ratchet\Component\WebSocket\Guzzle\Http\Message\RequestFactory
|
||||||
|
*/
|
||||||
|
class RequestFactoryTest extends \PHPUnit_Framework_TestCase {
|
||||||
|
protected $factory;
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
$this->factory = RequestFactory::getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMessageProvider() {
|
||||||
|
return array(
|
||||||
|
'status' => 'GET / HTTP/1.1'
|
||||||
|
, 'headers' => array(
|
||||||
|
'Upgrade' => 'WebSocket'
|
||||||
|
, 'Connection' => 'Upgrade'
|
||||||
|
, 'Host' => 'localhost:8000'
|
||||||
|
, 'Sec-WebSocket-Key1' => '> b3lU Z0 fh f 3+83394 6 (zG4'
|
||||||
|
, 'Sec-WebSocket-Key2' => ',3Z0X0677 dV-d [159 Z*4'
|
||||||
|
)
|
||||||
|
, 'body' => "123456\r\n\r\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function combineMessage($status, array $headers, $body = '') {
|
||||||
|
$message = $status . "\r\n";
|
||||||
|
|
||||||
|
foreach ($headers as $key => $val) {
|
||||||
|
$message .= "{$key}: {$val}\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$message .= "\r\n{$body}";
|
||||||
|
|
||||||
|
return $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExpectedDataFromGuzzleHeaders() {
|
||||||
|
$parts = $this->testMessageProvider();
|
||||||
|
$message = $this->combineMessage($parts['status'], $parts['headers'], $parts['body']);
|
||||||
|
$object = $this->factory->fromMessage($message);
|
||||||
|
|
||||||
|
foreach ($parts['headers'] as $key => $val) {
|
||||||
|
$this->assertEquals($val, $object->getHeader($key, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExpectedDataFromNonGuzzleHeaders() {
|
||||||
|
$parts = $this->testMessageProvider();
|
||||||
|
$message = $this->combineMessage($parts['status'], $parts['headers'], $parts['body']);
|
||||||
|
$object = $this->factory->fromMessage($message);
|
||||||
|
|
||||||
|
$this->assertNull($object->getHeader('Nope', true));
|
||||||
|
$this->assertNull($object->getHeader('Nope'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExpectedDataFromNonGuzzleBody() {
|
||||||
|
$parts = $this->testMessageProvider();
|
||||||
|
$message = $this->combineMessage($parts['status'], $parts['headers'], $parts['body']);
|
||||||
|
$object = $this->factory->fromMessage($message);
|
||||||
|
|
||||||
|
$this->assertEquals($parts['body'], (string)$object->getBody());
|
||||||
|
}
|
||||||
|
}
|
@ -125,4 +125,12 @@ class RFC6455Test extends \PHPUnit_Framework_TestCase {
|
|||||||
$this->_version->handshake($request);
|
$this->_version->handshake($request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testNewMessage() {
|
||||||
|
$this->assertInstanceOf('\\Ratchet\\Component\\WebSocket\\Version\\RFC6455\\Message', $this->_version->newMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNewFrame() {
|
||||||
|
$this->assertInstanceOf('\\Ratchet\\Component\\WebSocket\\Version\\RFC6455\\Frame', $this->_version->newFrame());
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,5 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
error_reporting(E_ALL | E_STRICT);
|
|
||||||
|
|
||||||
require_once dirname(__DIR__) . '/vendor/autoload.php';
|
|
Loading…
Reference in New Issue
Block a user