From 18bc1144089cf886394f906b0f5f7c64363f6099 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Tue, 16 Apr 2013 22:37:15 -0400 Subject: [PATCH] [Http] Routing spike --- composer.json | 3 +- composer.lock | 135 +++++++++++++++++++++++--------- src/Ratchet/Http/HttpServer.php | 53 +++++++++---- 3 files changed, 138 insertions(+), 53 deletions(-) diff --git a/composer.json b/composer.json index 364b9fe..a7a7953 100644 --- a/composer.json +++ b/composer.json @@ -28,6 +28,7 @@ "php": ">=5.3.9" , "react/socket": "0.2.*" , "guzzle/http": "~3.0" - , "symfony/http-foundation": "~2.1" + , "symfony/http-foundation": "~2.2" + , "symfony/routing": "~2.2" } } diff --git a/composer.lock b/composer.lock index 9df5a60..882649e 100644 --- a/composer.lock +++ b/composer.lock @@ -1,5 +1,9 @@ { - "hash": "9ccce99ef687cb79dad8a4c581f38cc5", + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" + ], + "hash": "b51075c0a68acb956c32e59869790571", "packages": [ { "name": "evenement/evenement", @@ -42,17 +46,17 @@ }, { "name": "guzzle/common", - "version": "v3.3.0", + "version": "v3.4.1", "target-dir": "Guzzle/Common", "source": { "type": "git", "url": "https://github.com/guzzle/common.git", - "reference": "v3.3.0" + "reference": "v3.4.1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/common/zipball/v3.3.0", - "reference": "v3.3.0", + "url": "https://api.github.com/repos/guzzle/common/zipball/v3.4.1", + "reference": "v3.4.1", "shasum": "" }, "require": { @@ -62,7 +66,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.3-dev" } }, "autoload": { @@ -82,21 +86,21 @@ "event", "exception" ], - "time": "2013-03-04 00:41:45" + "time": "2013-04-16 20:56:26" }, { "name": "guzzle/http", - "version": "v3.3.0", + "version": "v3.4.1", "target-dir": "Guzzle/Http", "source": { "type": "git", "url": "https://github.com/guzzle/http.git", - "reference": "v3.3.0" + "reference": "v3.4.1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/http/zipball/v3.3.0", - "reference": "v3.3.0", + "url": "https://api.github.com/repos/guzzle/http/zipball/v3.4.1", + "reference": "v3.4.1", "shasum": "" }, "require": { @@ -111,7 +115,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.3-dev" } }, "autoload": { @@ -139,21 +143,21 @@ "http", "http client" ], - "time": "2013-03-03 21:40:51" + "time": "2013-04-16 20:27:11" }, { "name": "guzzle/parser", - "version": "v3.3.0", + "version": "v3.4.1", "target-dir": "Guzzle/Parser", "source": { "type": "git", "url": "https://github.com/guzzle/parser.git", - "reference": "v3.3.0" + "reference": "v3.4.1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/parser/zipball/v3.3.0", - "reference": "v3.3.0", + "url": "https://api.github.com/repos/guzzle/parser/zipball/v3.4.1", + "reference": "v3.4.1", "shasum": "" }, "require": { @@ -162,7 +166,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.3-dev" } }, "autoload": { @@ -183,31 +187,34 @@ "message", "url" ], - "time": "2013-01-12 21:43:21" + "time": "2013-03-07 22:13:59" }, { "name": "guzzle/stream", - "version": "v3.3.0", + "version": "v3.4.1", "target-dir": "Guzzle/Stream", "source": { "type": "git", "url": "https://github.com/guzzle/stream.git", - "reference": "v3.3.0" + "reference": "v3.4.1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/stream/zipball/v3.3.0", - "reference": "v3.3.0", + "url": "https://api.github.com/repos/guzzle/stream/zipball/v3.4.1", + "reference": "v3.4.1", "shasum": "" }, "require": { "guzzle/common": "self.version", "php": ">=5.3.2" }, + "suggest": { + "guzzle/http": "To convert Guzzle request objects to PHP streams" + }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.3-dev" } }, "autoload": { @@ -233,7 +240,7 @@ "component", "stream" ], - "time": "2013-03-03 03:07:02" + "time": "2013-04-06 18:28:51" }, { "name": "react/event-loop", @@ -367,17 +374,17 @@ }, { "name": "symfony/event-dispatcher", - "version": "v2.2.0", + "version": "v2.2.1", "target-dir": "Symfony/Component/EventDispatcher", "source": { "type": "git", "url": "https://github.com/symfony/EventDispatcher.git", - "reference": "v2.2.0-RC3" + "reference": "v2.2.1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.2.0-RC3", - "reference": "v2.2.0-RC3", + "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.2.1", + "reference": "v2.2.1", "shasum": "" }, "require": { @@ -421,17 +428,17 @@ }, { "name": "symfony/http-foundation", - "version": "v2.2.0", + "version": "v2.2.1", "target-dir": "Symfony/Component/HttpFoundation", "source": { "type": "git", "url": "https://github.com/symfony/HttpFoundation.git", - "reference": "v2.2.0" + "reference": "v2.2.1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/v2.2.0", - "reference": "v2.2.0", + "url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/v2.2.1", + "reference": "v2.2.1", "shasum": "" }, "require": { @@ -467,7 +474,65 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "http://symfony.com", - "time": "2013-02-26 09:42:13" + "time": "2013-04-06 10:15:43" + }, + { + "name": "symfony/routing", + "version": "v2.2.1", + "target-dir": "Symfony/Component/Routing", + "source": { + "type": "git", + "url": "https://github.com/symfony/Routing.git", + "reference": "v2.2.1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Routing/zipball/v2.2.1", + "reference": "v2.2.1", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "doctrine/common": ">=2.2,<3.0", + "psr/log": ">=1.0,<2.0", + "symfony/config": ">=2.2,<2.3-dev", + "symfony/yaml": ">=2.0,<3.0" + }, + "suggest": { + "doctrine/common": "~2.2", + "symfony/config": "2.2.*", + "symfony/yaml": "2.2.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Routing\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony Routing Component", + "homepage": "http://symfony.com", + "time": "2013-03-23 12:03:22" } ], "packages-dev": [ @@ -481,7 +546,7 @@ ], "platform": { - "php": ">=5.3.3" + "php": ">=5.3.9" }, "platform-dev": [ diff --git a/src/Ratchet/Http/HttpServer.php b/src/Ratchet/Http/HttpServer.php index ecac919..f1ba4dd 100644 --- a/src/Ratchet/Http/HttpServer.php +++ b/src/Ratchet/Http/HttpServer.php @@ -2,16 +2,15 @@ namespace Ratchet\Http; use Ratchet\MessageComponentInterface; use Ratchet\ConnectionInterface; - +use Guzzle\Http\Message\Response; use Symfony\Component\Routing\RouteCollection; +use Symfony\Component\Routing\Route; +use Symfony\Component\Routing\RequestContext; +use Symfony\Component\Routing\Matcher\UrlMatcher; +use Symfony\Component\Routing\Exception\MethodNotAllowedException; +use Symfony\Component\Routing\Exception\ResourceNotFoundException; class HttpServer implements MessageComponentInterface { - /** - * Decorated component - * @var HttpServerInterface - */ - protected $_decorating; - /** * Buffers incoming HTTP requests returning a Guzzle Request when coalesced * @var HttpRequestParser @@ -24,14 +23,24 @@ class HttpServer implements MessageComponentInterface { */ protected $_routes; - /** - * @todo Change parameter from HttpServerInterface to RouteCollection - */ - public function __construct(HttpServerInterface $component) { - $this->_decorating = $component; + public function __construct() { + $this->_routes = new RouteCollection; $this->_reqParser = new HttpRequestParser; } + /** + * @param string + * @param string + * @param Ratchet\Http\HttpServerInterface + * @param array + */ + public function addRoute($name, $path, MessageComponentInterface $controller, $allowedOrigins = array()) { + $this->_routes->add($name, new Route($path, array( + '_controller' => $controller + , 'allowedOrigins' => $allowedOrigins + ))); + } + /** * @{inheritdoc} */ @@ -53,15 +62,25 @@ class HttpServer implements MessageComponentInterface { return $this->close($from, 413); } - // check routes, return 404 or onOpen the route + $context = new RequestContext($request->getUrl(), $request->getMethod(), $request->getHost(), $request->getScheme(), $request->getPort()); + $matcher = new UrlMatcher($this->_routes, $context); - $from->Http->headers = true; - $from->Http->request = $request; + try { + $route = $matcher->match($request->getPath()); + } catch (MethodNotAllowedException $nae) { + return $this->close($from, 403); + } catch (ResourceNotFoundException $nfe) { + return $this->close($from, 404); + } - return $this->_decorating->onOpen($from, $request); + $from->Http->headers = true; + $from->Http->request = $request; + $from->Http->controller = $route['_controller']; + + return $from->Http->controller->onOpen($from, $request); } - $this->_decorating->onMessage($from, $msg); + $from->Http->controller->onMessage($from, $msg); } /**