3 * sac-a-push - Obj/transports.phh
5 * Copyright (C) 2012 Matteo Nastasi
6 * mailto: nastasi@alternativeoutput.it
7 * matteo.nastasi@milug.org
8 * web: http://www.alternativeoutput.it
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABLILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details. You should have received a
19 * copy of the GNU General Public License along with this program; if
20 * not, write to the Free Software Foundation, Inc, 59 Temple Place -
21 * Suite 330, Boston, MA 02111-1307, USA.
27 * Values: Y: works, N: not works, @: continuous download,
28 * D: continuous download after first reload
32 * Iframe| IW | FF | Ch | Op | Ko | IE
33 * ------+----+----+----+----+----+----
34 * Lnx | D | | @ | | @ | x
35 * Win | x | D | @ | @ | | D
39 * XHR | IW | FF | Ch | Op | Ko | IE
40 * ------+----+----+----+----+----+----
41 * Lnx | Y | | ^D | | Y | x
42 * Win | x | Y | Y | | | N
46 * HtmlFl| IW | FF | Ch | Op | Ko | IE
47 * ------+----+----+----+----+----+----
49 * Win | x | N | N | | | Y* (* seems delay between click and load of a new page)
56 class Transport_template {
58 function Transport_template() {
61 // return string value is appended to the content of the returned page
62 function init($enc, $header, &$header_out, $init_string, $base, $step)
66 static function fini($init_string, $base, $blockerr)
70 function chunk($step, $cont)
79 class Transport_websocket {
80 $magicGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
82 function Transport_websocket() {
85 protected function doHandshake($user, $buffer) {
86 $magicGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
88 $lines = explode("\n",$buffer);
89 foreach ($lines as $line) {
90 if (strpos($line,":") !== false) {
91 $header = explode(":",$line,2);
92 $headers[strtolower(trim($header[0]))] = trim($header[1]);
93 } else if (stripos($line,"get ") !== false) {
94 preg_match("/GET (.*) HTTP/i", $buffer, $reqResource);
95 $headers['get'] = trim($reqResource[1]);
98 if (isset($headers['get'])) {
99 $user->requestedResource = $headers['get'];
101 // todo: fail the connection
102 $handshakeResponse = "HTTP/1.1 405 Method Not Allowed\r\n\r\n";
104 if (!isset($headers['host']) || !$this->checkHost($headers['host'])) {
105 $handshakeResponse = "HTTP/1.1 400 Bad Request";
107 if (!isset($headers['upgrade']) || strtolower($headers['upgrade']) != 'websocket') {
108 $handshakeResponse = "HTTP/1.1 400 Bad Request";
110 if (!isset($headers['connection']) || strpos(strtolower($headers['connection']), 'upgrade') === FALSE) {
111 $handshakeResponse = "HTTP/1.1 400 Bad Request";
113 if (!isset($headers['sec-websocket-key'])) {
114 $handshakeResponse = "HTTP/1.1 400 Bad Request";
118 if (!isset($headers['sec-websocket-version']) || strtolower($headers['sec-websocket-version']) != 13) {
119 $handshakeResponse = "HTTP/1.1 426 Upgrade Required\r\nSec-WebSocketVersion: 13";
121 if (($this->headerOriginRequired && !isset($headers['origin']) ) || ($this->headerOriginRequired && !$this->checkOrigin($headers['origin']))) {
122 $handshakeResponse = "HTTP/1.1 403 Forbidden";
124 if (($this->headerSecWebSocketProtocolRequired && !isset($headers['sec-websocket-protocol'])) || ($this->headerSecWebSocketProtocolRequired && !$this->checkWebsocProtocol($header['sec-websocket-protocol']))) {
125 $handshakeResponse = "HTTP/1.1 400 Bad Request";
127 if (($this->headerSecWebSocketExtensionsRequired && !isset($headers['sec-websocket-extensions'])) || ($this->headerSecWebSocketExtensionsRequired && !$this->checkWebsocExtensions($header['sec-websocket-extensions']))) {
128 $handshakeResponse = "HTTP/1.1 400 Bad Request";
131 // Done verifying the _required_ headers and optionally required headers.
133 if (isset($handshakeResponse)) {
134 socket_write($user->socket,$handshakeResponse,strlen($handshakeResponse));
135 $this->disconnect($user->socket);
139 $user->headers = $headers;
140 $user->handshake = $buffer;
142 $webSocketKeyHash = sha1($headers['sec-websocket-key'] . $magicGUID);
145 for ($i = 0; $i < 20; $i++) {
146 $rawToken .= chr(hexdec(substr($webSocketKeyHash,$i*2, 2)));
148 $handshakeToken = base64_encode($rawToken) . "\r\n";
150 $subProtocol = (isset($headers['sec-websocket-protocol'])) ? $this->processProtocol($headers['sec-websocket-protocol']) : "";
151 $extensions = (isset($headers['sec-websocket-extensions'])) ? $this->processExtensions($headers['sec-websocket-extensions']) : "";
153 $handshakeResponse = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: $handshakeToken$subProtocol$extensions\r\n";
154 socket_write($user->socket,$handshakeResponse,strlen($handshakeResponse));
155 $this->connected($user);
159 function init($enc, $header, &$header_out, $init_string, $base, $step)
165 $ret = sprintf("@BEGIN@ /* %s */ @END@", $init_string);
167 $header_out['Content-Encoding'] = $enc;
168 $header_out['Cache-Control'] = 'no-cache, must-revalidate'; // HTTP/1.1
169 $header_out['Expires'] = 'Mon, 26 Jul 1997 05:00:00 GMT'; // Date in the past
170 $header_out['Content-type'] = 'application/xml; charset="utf-8"';
175 static function fini($init_string, $base, $blockerr)
177 return (sprintf('@BEGIN@ %s window.onbeforeunload = null; window.onunload = null; document.location.assign("%sindex.php"); @END@', ($blockerr ? 'xstm.stop(); ' : ''), $base));
181 function chunk($step, $cont)
183 return ("@BEGIN@".$cont."@END@");
187 class Transport_xhr {
189 function Transport_xhr() {
192 function init($enc, $header, &$header_out, $init_string, $base, $step)
194 $ret = sprintf("@BEGIN@ /* %s */ @END@", $init_string);
196 $header_out['Content-Encoding'] = $enc;
197 $header_out['Cache-Control'] = 'no-cache, must-revalidate'; // HTTP/1.1
198 $header_out['Expires'] = 'Mon, 26 Jul 1997 05:00:00 GMT'; // Date in the past
199 $header_out['Content-type'] = 'application/xml; charset="utf-8"';
204 static function fini($init_string, $base, $blockerr)
206 return (sprintf('@BEGIN@ %s window.onbeforeunload = null; window.onunload = null; document.location.assign("%sindex.php"); @END@', ($blockerr ? 'xstm.stop(); ' : ''), $base));
210 function chunk($step, $cont)
212 return ("@BEGIN@".$cont."@END@");
215 function is_chunked()
221 class Transport_iframe {
223 function Transport_iframe() {
226 function init($enc, $header, &$header_out, $init_string, $base, $step)
231 $header_out['Content-Encoding'] = $enc;
232 $header_out['Cache-Control'] = 'no-cache, must-revalidate'; // HTTP/1.1
233 $header_out['Expires'] = 'Mon, 26 Jul 1997 05:00:00 GMT'; // Date in the past
234 $header_out['Content-type'] = 'text/html; charset="utf-8"';
236 $ret .= sprintf("<html>
238 <script type=\"text/javascript\" src=\"%scommons.js\"></script>
239 <script type=\"text/javascript\" src=\"%sxynt-streaming-ifra.js\"></script>
240 <script type=\"text/javascript\">
241 var xynt_streaming = \"ready\";", $base, $base);
243 $ret .= sprintf("last_clean = %d;\n", ($step-1));
245 window.onload = function () { try { if (xynt_streaming != \"ready\") { xynt_streaming.transp.stopped = true; } } catch(e) { /* console.log(\"catcha\"); */ } };
249 $ret .= sprintf("<!-- \n%s -->\n", $init_string);
254 static function fini($init_string, $base, $blockerr)
257 $ret .= sprintf("<html>
259 <script type=\"text/javascript\" src=\"%scommons.js\"></script>
260 <script type=\"text/javascript\" src=\"%sxynt-streaming-ifra.js\"></script>
261 <script type=\"text/javascript\">
262 var xynt_streaming = \"ready\";", $base, $base);
264 window.onload = function () { try { if (xynt_streaming != \"ready\") { xynt_streaming.reload(); } } catch(e) { /* console.log(\"catcha\"); */ } };
268 $ret .= sprintf("<!-- \n%s -->\n", $init_string);
269 $ret .= sprintf("<script id='hs%d' type='text/javascript'><!--
272 </script>", 0, escpush($blockerr) );
276 function chunk($step, $cont)
279 return sprintf("<script id='hs%d' type='text/javascript'><!--
280 push(null);\n// -->\n</script>", $step);
283 return sprintf("<script id='hs%d' type='text/javascript'><!--
284 push(\"%s\");\n// -->\n</script>", $step, escpush($cont) );
288 function is_chunked()
294 class Transport_htmlfile extends Transport_iframe {
302 static function create($transp)
304 if ($transp == 'xhr') {
305 return new Transport_xhr();
307 else if ($transp == 'htmlfile') {
308 return new Transport_htmlfile();
311 return new Transport_iframe();
314 static function gettype($transp)
316 if ($transp == 'xhr' || $transp == 'htmlfile') {
317 return "Transport_".$transp;
320 return 'Transport_iframe';