From d0d7b67ad7d72bffdbceca6ed4263ccff4157517 Mon Sep 17 00:00:00 2001
From: Chris Boden <cboden@gmail.com>
Date: Sun, 31 May 2015 13:54:43 -0400
Subject: [PATCH] Ues pecl_http if available, cleanup

pecl_http if available to parse HTTP requests (5x faster)
Update ConnectionContext to match latest RFC interface
Removed Guzzle integration test (now using PSR-7 API)
---
 composer.json                                 |  5 +-
 src/Ratchet/Http/HttpRequestParser.php        | 26 ++++++-
 src/Ratchet/WebSocket/ConnectionContext.php   |  7 +-
 .../Http/Message/RequestFactoryTest.php       | 67 -------------------
 4 files changed, 33 insertions(+), 72 deletions(-)
 delete mode 100644 tests/unit/Http/Guzzle/Http/Message/RequestFactoryTest.php

diff --git a/composer.json b/composer.json
index 79b22b5..72a8283 100644
--- a/composer.json
+++ b/composer.json
@@ -2,7 +2,7 @@
     "name": "cboden/ratchet"
   , "type": "library"
   , "description": "PHP WebSocket library"
-  , "keywords": ["WebSockets", "Server", "Ratchet", "Sockets"]
+  , "keywords": ["WebSockets", "Server", "Ratchet", "Sockets", "WebSocket"]
   , "homepage": "http://socketo.me"
   , "license": "MIT"
   , "authors": [
@@ -22,6 +22,9 @@
             "Ratchet\\": "src/Ratchet"
         }
     }
+  , "suggest": {
+      "ext-pecl_http": "^2.0"
+    }
   , "require": {
         "php": ">=5.3.9"
       , "react/socket": "^0.3 || ^0.4"
diff --git a/src/Ratchet/Http/HttpRequestParser.php b/src/Ratchet/Http/HttpRequestParser.php
index 286a3cb..25bf489 100644
--- a/src/Ratchet/Http/HttpRequestParser.php
+++ b/src/Ratchet/Http/HttpRequestParser.php
@@ -2,11 +2,11 @@
 namespace Ratchet\Http;
 use Ratchet\MessageInterface;
 use Ratchet\ConnectionInterface;
-use GuzzleHttp\Psr7 as g7;
+use GuzzleHttp\Psr7 as gPsr;
 
 /**
  * This class receives streaming data from a client request
- * and parses HTTP headers, returning a Guzzle Request object
+ * and parses HTTP headers, returning a PSR-7 Request object
  * once it's been buffered
  */
 class HttpRequestParser implements MessageInterface {
@@ -37,7 +37,7 @@ class HttpRequestParser implements MessageInterface {
         }
 
         if ($this->isEom($context->httpBuffer)) {
-            $request = g7\parse_request($context->httpBuffer);
+            $request = $this->parse($context->httpBuffer);
 
             unset($context->httpBuffer);
 
@@ -53,4 +53,24 @@ class HttpRequestParser implements MessageInterface {
     public function isEom($message) {
         return (boolean)strpos($message, static::EOM);
     }
+
+    /**
+     * @param string $headers
+     * @return \Psr\Http\Message\RequestInterface
+     */
+    public function parse($headers) {
+        if (function_exists('http_parse_message')) {
+            $parts = http_parse_message($headers);
+
+            return new gPsr\Request(
+                $parts->requestMethod
+              , $parts->requestUrl
+              , $parts->headers
+              , null
+              , $parts->httpVersion
+            );
+        } else {
+            return gPsr\parse_request($headers);
+        }
+    }
 }
diff --git a/src/Ratchet/WebSocket/ConnectionContext.php b/src/Ratchet/WebSocket/ConnectionContext.php
index 92b8ef6..20fb58b 100644
--- a/src/Ratchet/WebSocket/ConnectionContext.php
+++ b/src/Ratchet/WebSocket/ConnectionContext.php
@@ -2,6 +2,7 @@
 namespace Ratchet\WebSocket;
 use Ratchet\ConnectionInterface;
 use Ratchet\MessageComponentInterface;
+use Ratchet\RFC6455\Messaging\Protocol\Frame;
 use Ratchet\RFC6455\Messaging\Protocol\FrameInterface;
 use Ratchet\RFC6455\Messaging\Protocol\MessageInterface;
 use Ratchet\RFC6455\Messaging\Streaming\ContextInterface;
@@ -36,6 +37,8 @@ class ConnectionContext implements ContextInterface {
 
     public function setFrame(FrameInterface $frame = null) {
         $this->frame = $frame;
+
+        return $frame;
     }
 
     /**
@@ -47,6 +50,8 @@ class ConnectionContext implements ContextInterface {
 
     public function setMessage(MessageInterface $message = null) {
         $this->message = $message;
+
+        return $message;
     }
 
     /**
@@ -61,7 +66,7 @@ class ConnectionContext implements ContextInterface {
     }
 
     public function onPing(FrameInterface $frame) {
-        $pong = new \Ratchet\RFC6455\Messaging\Protocol\Frame($frame->getPayload(), true, $frame::OP_PONG);
+        $pong = new Frame($frame->getPayload(), true, Frame::OP_PONG);
 
         $this->conn->send($pong);
     }
diff --git a/tests/unit/Http/Guzzle/Http/Message/RequestFactoryTest.php b/tests/unit/Http/Guzzle/Http/Message/RequestFactoryTest.php
deleted file mode 100644
index 7860f72..0000000
--- a/tests/unit/Http/Guzzle/Http/Message/RequestFactoryTest.php
+++ /dev/null
@@ -1,67 +0,0 @@
-<?php
-namespace Ratchet\Http\Guzzle\Http\Message;
-use Ratchet\Http\Guzzle\Http\Message\RequestFactory;
-
-/**
- * @covers Ratchet\Http\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());
-    }
-}