Subversion Repositories php-qbpwcf

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 liveuser 1
<?php
2
namespace Ratchet\RFC6455\Handshake;
3
use Psr\Http\Message\RequestInterface;
4
 
5
/**
6
 * These are checks to ensure the client requested handshake are valid
7
 * Verification rules come from section 4.2.1 of the RFC6455 document
8
 * @todo Currently just returning invalid - should consider returning appropriate HTTP status code error #s
9
 */
10
class RequestVerifier {
11
    const VERSION = 13;
12
 
13
    /**
14
     * Given an array of the headers this method will run through all verification methods
15
     * @param RequestInterface $request
16
     * @return bool TRUE if all headers are valid, FALSE if 1 or more were invalid
17
     */
18
    public function verifyAll(RequestInterface $request) {
19
        $passes = 0;
20
 
21
        $passes += (int)$this->verifyMethod($request->getMethod());
22
        $passes += (int)$this->verifyHTTPVersion($request->getProtocolVersion());
23
        $passes += (int)$this->verifyRequestURI($request->getUri()->getPath());
24
        $passes += (int)$this->verifyHost($request->getHeader('Host'));
25
        $passes += (int)$this->verifyUpgradeRequest($request->getHeader('Upgrade'));
26
        $passes += (int)$this->verifyConnection($request->getHeader('Connection'));
27
        $passes += (int)$this->verifyKey($request->getHeader('Sec-WebSocket-Key'));
28
        $passes += (int)$this->verifyVersion($request->getHeader('Sec-WebSocket-Version'));
29
 
30
        return (8 === $passes);
31
    }
32
 
33
    /**
34
     * Test the HTTP method.  MUST be "GET"
35
     * @param string
36
     * @return bool
37
     */
38
    public function verifyMethod($val) {
39
        return ('get' === strtolower($val));
40
    }
41
 
42
    /**
43
     * Test the HTTP version passed.  MUST be 1.1 or greater
44
     * @param string|int
45
     * @return bool
46
     */
47
    public function verifyHTTPVersion($val) {
48
        return (1.1 <= (double)$val);
49
    }
50
 
51
    /**
52
     * @param string
53
     * @return bool
54
     */
55
    public function verifyRequestURI($val) {
56
        if ($val[0] !== '/') {
57
            return false;
58
        }
59
 
60
        if (false !== strstr($val, '#')) {
61
            return false;
62
        }
63
 
64
        if (!extension_loaded('mbstring')) {
65
            return true;
66
        }
67
 
68
        return mb_check_encoding($val, 'US-ASCII');
69
    }
70
 
71
    /**
72
     * @param array $hostHeader
73
     * @return bool
74
     * @todo Once I fix HTTP::getHeaders just verify this isn't NULL or empty...or maybe need to verify it's a valid domain??? Or should it equal $_SERVER['HOST'] ?
75
     */
76
    public function verifyHost(array $hostHeader) {
77
        return (1 === count($hostHeader));
78
    }
79
 
80
    /**
81
     * Verify the Upgrade request to WebSockets.
82
     * @param  array $upgradeHeader MUST equal "websocket"
83
     * @return bool
84
     */
85
    public function verifyUpgradeRequest(array $upgradeHeader) {
86
        return (1 === count($upgradeHeader) && 'websocket' === strtolower($upgradeHeader[0]));
87
    }
88
 
89
    /**
90
     * Verify the Connection header
91
     * @param  array $connectionHeader MUST include "Upgrade"
92
     * @return bool
93
     */
94
    public function verifyConnection(array $connectionHeader) {
95
        foreach ($connectionHeader as $l) {
96
            $upgrades = array_filter(
97
                array_map('trim', array_map('strtolower', explode(',', $l))),
98
                function ($x) {
99
                    return 'upgrade' === $x;
100
                }
101
            );
102
            if (count($upgrades) > 0) {
103
                return true;
104
            }
105
        }
106
        return false;
107
    }
108
 
109
    /**
110
     * This function verifies the nonce is valid (64 big encoded, 16 bytes random string)
111
     * @param array $keyHeader
112
     * @return bool
113
     * @todo The spec says we don't need to base64_decode - can I just check if the length is 24 and not decode?
114
     * @todo Check the spec to see what the encoding of the key could be
115
     */
116
    public function verifyKey(array $keyHeader) {
117
        return (1 === count($keyHeader) && 16 === strlen(base64_decode($keyHeader[0])));
118
    }
119
 
120
    /**
121
     * Verify the version passed matches this RFC
122
     * @param string[] $versionHeader MUST equal ["13"]
123
     * @return bool
124
     */
125
    public function verifyVersion(array $versionHeader) {
126
        return (1 === count($versionHeader) && static::VERSION === (int)$versionHeader[0]);
127
    }
128
 
129
    /**
130
     * @todo Write logic for this method.  See section 4.2.1.8
131
     */
132
    public function verifyProtocol($val) {
133
    }
134
 
135
    /**
136
     * @todo Write logic for this method.  See section 4.2.1.9
137
     */
138
    public function verifyExtensions($val) {
139
    }
140
 
141
    public function getPermessageDeflateOptions(array $requestHeader, array $responseHeader) {
142
        $deflate = true;
143
        if (!isset($requestHeader['Sec-WebSocket-Extensions']) || count(array_filter($requestHeader['Sec-WebSocket-Extensions'], function ($val) {
144
            return 'permessage-deflate' === substr($val, 0, strlen('permessage-deflate'));
145
        })) === 0) {
146
             $deflate = false;
147
        }
148
 
149
        if (!isset($responseHeader['Sec-WebSocket-Extensions']) || count(array_filter($responseHeader['Sec-WebSocket-Extensions'], function ($val) {
150
                return 'permessage-deflate' === substr($val, 0, strlen('permessage-deflate'));
151
            })) === 0) {
152
            $deflate = false;
153
        }
154
 
155
        return [
156
            'deflate' => $deflate,
157
            'no_context_takeover' => false,
158
            'max_window_bits' => null,
159
            'request_no_context_takeover' => false,
160
            'request_max_window_bits' => null
161
        ];
162
    }
163
}