Explorar o código

Merge pull request #1 from walkor/master

update
Leonardo %!s(int64=8) %!d(string=hai) anos
pai
achega
ebfe4d45c2
Modificáronse 4 ficheiros con 106 adicións e 26 borrados
  1. 49 3
      Connection/TcpConnection.php
  2. 3 1
      Events/React.php
  3. 40 13
      Protocols/Http.php
  4. 14 9
      Worker.php

+ 49 - 3
Connection/TcpConnection.php

@@ -108,6 +108,13 @@ class TcpConnection extends ConnectionInterface
     public $protocol = null;
 
     /**
+     * Transport (tcp/udp/unix/ssl).
+     *
+     * @var string
+     */
+    public $transport = 'tcp';
+
+    /**
      * Which worker belong to.
      *
      * @var Worker
@@ -207,6 +214,13 @@ class TcpConnection extends ConnectionInterface
     protected $_isPaused = false;
 
     /**
+     * SSL handshake completed or not
+     *
+     * @var bool
+     */
+    protected $_sslHandshakeCompleted = false;
+
+    /**
      * Construct.
      *
      * @param resource $socket
@@ -236,6 +250,10 @@ class TcpConnection extends ConnectionInterface
      */
     public function send($send_buffer, $raw = false)
     {
+        if ($this->_status === self::STATUS_CLOSING || $this->_status === self::STATUS_CLOSED) {
+            return false;
+        }
+
         // Try to call protocol::encode($send_buffer) before sending.
         if (false === $raw && $this->protocol) {
             $parser      = $this->protocol;
@@ -245,7 +263,9 @@ class TcpConnection extends ConnectionInterface
             }
         }
 
-        if ($this->_status === self::STATUS_INITIAL || $this->_status === self::STATUS_CONNECTING) {
+        if ($this->_status !== self::STATUS_ESTABLISH ||
+            ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true)
+        ) {
             if ($this->_sendBuffer) {
                 if ($this->bufferIsFull()) {
                     self::$statistics['send_fail']++;
@@ -255,10 +275,9 @@ class TcpConnection extends ConnectionInterface
             $this->_sendBuffer .= $send_buffer;
             $this->checkBufferWillFull();
             return null;
-        } elseif ($this->_status === self::STATUS_CLOSING || $this->_status === self::STATUS_CLOSED) {
-            return false;
         }
 
+
         // Attempt to send data directly.
         if ($this->_sendBuffer === '') {
             $len = @fwrite($this->_socket, $send_buffer);
@@ -366,6 +385,33 @@ class TcpConnection extends ConnectionInterface
      */
     public function baseRead($socket, $check_eof = true)
     {
+        // SSL handshake.
+        if ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true) {
+            stream_set_blocking($socket, true);
+            stream_set_timeout($socket, 1);
+            $ret = stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_SSLv23_SERVER);
+            if(!$ret) {
+                echo new \Exception('ssl handshake fail, stream_socket_enable_crypto return ' . var_export($ret, true));
+                return $this->destroy();
+            }
+            if (isset($this->onSslHandshake)) {
+                try {
+                    call_user_func($this->onSslHandshake, $this);
+                } catch (\Exception $e) {
+                    self::log($e);
+                    exit(250);
+                } catch (\Error $e) {
+                    self::log($e);
+                    exit(250);
+                }
+            }
+            $this->_sslHandshakeCompleted = true;
+            if ($this->_sendBuffer) {
+                Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite'));
+            }
+            return;
+        }
+
         $buffer = fread($socket, self::READ_BUFFER_SIZE);
 
         // Check connection closed.

+ 3 - 1
Events/React.php

@@ -87,7 +87,9 @@ class React implements LoopInterface
                 return $this->_loop->removeSignal($fd);
             case EventInterface::EV_TIMER:
             case EventInterface::EV_TIMER_ONCE;
-                return  $this->_loop->cancelTimer($fd);
+                if ($fd !== null){
+                    return  $this->_loop->cancelTimer($fd);
+                }
         }
         return false;
     }

+ 40 - 13
Protocols/Http.php

@@ -22,6 +22,12 @@ use Workerman\Worker;
 class Http
 {
     /**
+      * The supported HTTP methods
+      * @var array
+      */
+    public static $methods = array('GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS');
+
+    /**
      * Check the integrity of the package.
      *
      * @param string        $recv_buffer
@@ -40,24 +46,37 @@ class Http
         }
 
         list($header,) = explode("\r\n\r\n", $recv_buffer, 2);
-        if (0 === strpos($recv_buffer, "POST")) {
-            // find Content-Length
-            $match = array();
-            if (preg_match("/\r\nContent-Length: ?(\d+)/i", $header, $match)) {
-                $content_length = $match[1];
-                return $content_length + strlen($header) + 4;
-            } else {
-                return 0;
-            }
-        } elseif (0 === strpos($recv_buffer, "GET")) {
-            return strlen($header) + 4;
-        } else {
+        $method = substr($header, 0, strpos($header, ' '));
+
+        if(in_array($method, static::$methods)) {
+            return static::getRequestSize($header, $method);
+        }else{
             $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n", true);
             return 0;
         }
     }
 
     /**
+      * Get whole size of the request
+      * includes the request headers and request body.
+      * @param string $header The request headers
+      * @param string $method The request method
+      * @return integer
+      */
+    protected static function getRequestSize($header, $method)
+    {
+        if($method=='GET') {
+            return strlen($header) + 4;
+        }
+        $match = array();
+        if (preg_match("/\r\nContent-Length: ?(\d+)/i", $header, $match)) {
+            $content_length = isset($match[1]) ? $match[1] : 0;
+            return $content_length + strlen($header) + 4;
+        }
+        return 0;
+    }
+
+    /**
      * Parse $_POST、$_GET、$_COOKIE.
      *
      * @param string        $recv_buffer
@@ -144,10 +163,18 @@ class Http
             } else {
                 parse_str($http_body, $_POST);
                 // $GLOBALS['HTTP_RAW_POST_DATA']
-                $GLOBALS['HTTP_RAW_POST_DATA'] = $http_body;
+                $GLOBALS['HTTP_RAW_REQUEST_DATA'] = $GLOBALS['HTTP_RAW_POST_DATA'] = $http_body;
             }
         }
 
+        if ($_SERVER['REQUEST_METHOD'] === 'PUT') {
+                $GLOBALS['HTTP_RAW_REQUEST_DATA'] = $http_body;
+        }
+
+        if ($_SERVER['REQUEST_METHOD'] === 'DELETE') {
+                $GLOBALS['HTTP_RAW_REQUEST_DATA'] = $http_body;
+        }
+
         // QUERY_STRING
         $_SERVER['QUERY_STRING'] = parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY);
         if ($_SERVER['QUERY_STRING']) {

+ 14 - 9
Worker.php

@@ -33,7 +33,7 @@ class Worker
      *
      * @var string
      */
-    const VERSION = '3.3.6';
+    const VERSION = '3.3.7';
 
     /**
      * Status starting.
@@ -411,10 +411,7 @@ class Worker
         'tcp'   => 'tcp',
         'udp'   => 'udp',
         'unix'  => 'unix',
-        'ssl'   => 'tcp',
-        'sslv2' => 'tcp',
-        'sslv3' => 'tcp',
-        'tls'   => 'tcp'
+        'ssl'   => 'tcp'
     );
 
     /**
@@ -1408,7 +1405,6 @@ class Worker
         // Autoload.
         Autoloader::setRootPath($this->_autoloadRootPath);
 
-        $local_socket = $this->_socketName;
         // Get the application layer communication protocol and listening address.
         list($scheme, $address) = explode(':', $this->_socketName, 2);
         // Check application layer protocol class.
@@ -1425,11 +1421,15 @@ class Worker
                     }
                 }
             }
-            $local_socket = $this->transport . ":" . $address;
+            if (!isset(self::$_builtinTransports[$this->transport])) {
+                throw new \Exception('Bad worker->transport ' . var_export($this->transport, true));
+            }
         } else {
-            $this->transport = self::$_builtinTransports[$scheme];
+            $this->transport = $scheme;
         }
 
+        $local_socket = self::$_builtinTransports[$this->transport] . ":" . $address;
+
         // Flag.
         $flags  = $this->transport === 'udp' ? STREAM_SERVER_BIND : STREAM_SERVER_BIND | STREAM_SERVER_LISTEN;
         $errno  = 0;
@@ -1445,8 +1445,12 @@ class Worker
             throw new Exception($errmsg);
         }
 
+        if ($this->transport === 'ssl') {
+            stream_socket_enable_crypto($this->_mainSocket, false);
+        }
+
         // Try to open keepalive for tcp and disable Nagle algorithm.
-        if (function_exists('socket_import_stream') && $this->transport === 'tcp') {
+        if (function_exists('socket_import_stream') && self::$_builtinTransports[$this->transport] === 'tcp') {
             $socket = socket_import_stream($this->_mainSocket);
             @socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1);
             @socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1);
@@ -1575,6 +1579,7 @@ class Worker
         $this->connections[$connection->id] = $connection;
         $connection->worker                 = $this;
         $connection->protocol               = $this->protocol;
+        $connection->transport              = $this->transport;
         $connection->onMessage              = $this->onMessage;
         $connection->onClose                = $this->onClose;
         $connection->onError                = $this->onError;