From ddd822f1dca51731cc9fc8199db3f1cc527fb01a Mon Sep 17 00:00:00 2001 From: "Matteo Nastasi (mop)" Date: Sun, 18 Aug 2013 17:05:09 +0200 Subject: [PATCH] add WebSocket to transports bouquet --- TODO.txt | 21 +- web/Obj/brisk.phh | 2 +- web/Obj/sac-a-push.phh | 17 +- web/Obj/transports.phh | 458 ++++++++++++++++++++++++++++++++++------- web/Obj/user.phh | 15 +- web/briskin5/index.php | 2 +- web/commons.js | 2 +- web/index.php | 57 +++-- web/ws.php | 16 +- web/xynt-streaming.js | 235 ++++++++++++++++++--- web/xynt_test01.php | 132 ++++++++++-- 11 files changed, 782 insertions(+), 175 deletions(-) diff --git a/TODO.txt b/TODO.txt index 404a808..568cf21 100644 --- a/TODO.txt +++ b/TODO.txt @@ -4,12 +4,23 @@ FEATURES | ----------+ - WEBSOCKET TRANSPORT - . client (xynt_streaming.js) - . server (transport.phh) + DONE . fini of ws stream + DONE . reactivate compression + DONE . fix xynt_test01 + DONE M2: brisk working + DONE . manage multiport apache config + DONE . manage headers correctly in sac-a-push + DONE . manage transport.close method where required + DONE . xynt_stream: manage fallback to multiple ports + DONE . manage fini for ws + POST . server: manage input data from clients + POST . manage ping/pong (seems not required) + + DONE . client (xynt_streaming.js) + DONE . server (transport.phh) + + DONE M1: xynt_test01.php working - M1: xynt_test01.php working - - . manage headers correctly in sac-a-push - improved S . db update (add components, maybe single string) diff --git a/web/Obj/brisk.phh b/web/Obj/brisk.phh index 707b20a..202113f 100644 --- a/web/Obj/brisk.phh +++ b/web/Obj/brisk.phh @@ -2344,6 +2344,7 @@ class Room break; case "index_rd_ifra.php": + // $enc = 'plain'; do { if (!isset($cookie['sess']) || (($user = $this->get_user($cookie['sess'], $idx)) == FALSE)) { @@ -2367,7 +2368,6 @@ class Room $content = ""; $user->stream_init($s_a_p->rndstr, $enc, $header, $header_out, $content, $get, $post, $cookie); - $response = headers_render($header_out, -1).$user->chunked_content($content); $response_l = mb_strlen($response, "ASCII"); diff --git a/web/Obj/sac-a-push.phh b/web/Obj/sac-a-push.phh index 502670d..0ae856e 100644 --- a/web/Obj/sac-a-push.phh +++ b/web/Obj/sac-a-push.phh @@ -221,6 +221,14 @@ function headers_render($header, $len) } else if (isset($header['HTTP-Response'])) { $s = sprintf("HTTP/1.1 %s\r\n", $header['HTTP-Response']); + foreach($header as $key => $value) { + if (strtolower($key) == "http-response") + continue; + $s .= sprintf("%s: %s\r\n", $key, $value); + } + if ($len >= 0) { + $s .= sprintf("Content-Length: %ld\r\n", $len); + } } else { $s = "HTTP/1.1 200 OK\r\n"; @@ -716,6 +724,10 @@ class Sac_a_push { if (isset($this->s2u[$id])) { // $user_a[$s2u[$id]]->disable(); if ($this->s2u[$id]->rd_socket_get() != NULL) { + // try to send close frame (for websocket) + $clo = $this->s2u[$id]->stream_close(); + $clo_l = mb_strlen($clo, "ASCII"); + @fwrite($sock, $clo, $clo_l); $this->s2u[$id]->rd_socket_set(NULL); } unset($this->s2u[$id]); @@ -849,7 +861,7 @@ class Sac_a_push { // echo "SPIA: [".substr($response, 0, 60)."...]\n"; // echo "SPIA: [".$response."]\n"; $response_l = mb_strlen($response, "ASCII"); - $wret = @fwrite($sock, $response); + $wret = @fwrite($sock, $response, $response_l); if ($wret < $response_l) { printf("TROUBLE WITH FWRITE: %d\n", $wret); $user->rd_cache_set(mb_substr($response, $wret, $response_l - $wret, "ASCII")); @@ -868,6 +880,9 @@ class Sac_a_push { } unset($this->socks[$id]); unset($this->s2u[$id]); + $clo = $user->stream_close(); + $clo_l = mb_strlen($clo, "ASCII"); + @fwrite($sock, $clo, $clo_l); fclose($sock); printf("CLOSE ON LOOP\n"); } diff --git a/web/Obj/transports.phh b/web/Obj/transports.phh index 3b6e79c..5ebfec4 100644 --- a/web/Obj/transports.phh +++ b/web/Obj/transports.phh @@ -3,7 +3,7 @@ * sac-a-push - Obj/transports.phh * * Copyright (C) 2012 Matteo Nastasi - * mailto: nastasi@alternativeoutput.it + * mailto: nastasi@alternativeoutput.it * matteo.nastasi@milug.org * web: http://www.alternativeoutput.it * @@ -36,6 +36,13 @@ * Mac | x | | | | | * * + * WS | IW | FF | Ch | Op | Ko | IE + * ------+----+----+----+----+----+---- + * Lnx | | | | | | + * Win | | | | | | + * Mac | | | | | | + * + * * XHR | IW | FF | Ch | Op | Ko | IE * ------+----+----+----+----+----+---- * Lnx | Y | | ^D | | Y | x @@ -52,18 +59,19 @@ * */ - class Transport_template { function Transport_template() { } // return string value is appended to the content of the returned page + // return FALSE if fails + // check with '===' operator to disambiguation between "" and FALSE return value function init($enc, $header, &$header_out, $init_string, $base, $step) { } - static function fini($init_string, $base, $blockerr) + function close() { } @@ -74,114 +82,395 @@ class Transport_template { function is_chunked() { } + + // return string to add to the stream to perform something to the engine + static function fini($init_string, $base, $blockerr) + { + return ""; + } } class Transport_websocket { - $magicGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + protected $magicGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; function Transport_websocket() { + $this->headerOriginRequired = false; + $this->headerSecWebSocketProtocolRequired = false; + $this->headerSecWebSocketExtensionsRequired = false; + + $this->sendingContinuous = false; + $this->sendingContinuous = false; + $this->partialMessage = ""; + + $this->hasSentClose = false; } - protected function doHandshake($user, $buffer) { - $magicGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - $headers = array(); - $lines = explode("\n",$buffer); - foreach ($lines as $line) { - if (strpos($line,":") !== false) { - $header = explode(":",$line,2); - $headers[strtolower(trim($header[0]))] = trim($header[1]); - } else if (stripos($line,"get ") !== false) { - preg_match("/GET (.*) HTTP/i", $buffer, $reqResource); - $headers['get'] = trim($reqResource[1]); + protected function extractHeaders($message) { + $header = array('fin' => $message[0] & chr(128), + 'rsv1' => $message[0] & chr(64), + 'rsv2' => $message[0] & chr(32), + 'rsv3' => $message[0] & chr(16), + 'opcode' => ord($message[0]) & 15, + 'hasmask' => $message[1] & chr(128), + 'length' => 0, + 'mask' => ""); + $header['length'] = (ord($message[1]) >= 128) ? ord($message[1]) - 128 : ord($message[1]); + + if ($header['length'] == 126) { + if ($header['hasmask']) { + $header['mask'] = $message[4] . $message[5] . $message[6] . $message[7]; } + $header['length'] = ord($message[2]) * 256 + + ord($message[3]); + } elseif ($header['length'] == 127) { + if ($header['hasmask']) { + $header['mask'] = $message[10] . $message[11] . $message[12] . $message[13]; + } + $header['length'] = ord($message[2]) * 65536 * 65536 * 65536 * 256 + + ord($message[3]) * 65536 * 65536 * 65536 + + ord($message[4]) * 65536 * 65536 * 256 + + ord($message[5]) * 65536 * 65536 + + ord($message[6]) * 65536 * 256 + + ord($message[7]) * 65536 + + ord($message[8]) * 256 + + ord($message[9]); + } elseif ($header['hasmask']) { + $header['mask'] = $message[2] . $message[3] . $message[4] . $message[5]; + } + //echo $this->strtohex($message); + //$this->printHeaders($header); + return $header; + } + + protected function extractPayload($message,$headers) { + $offset = 2; + if ($headers['hasmask']) { + $offset += 4; } - if (isset($headers['get'])) { - $user->requestedResource = $headers['get']; + if ($headers['length'] > 65535) { + $offset += 8; + } elseif ($headers['length'] > 125) { + $offset += 2; + } + return substr($message,$offset); + } + + protected function applyMask($headers,$payload) { + $effectiveMask = ""; + if ($headers['hasmask']) { + $mask = $headers['mask']; } else { - // todo: fail the connection - $handshakeResponse = "HTTP/1.1 405 Method Not Allowed\r\n\r\n"; + return $payload; } - if (!isset($headers['host']) || !$this->checkHost($headers['host'])) { - $handshakeResponse = "HTTP/1.1 400 Bad Request"; + + while (mb_strlen($effectiveMask, "ASCII") < mb_strlen($payload, "ASCII")) { + $effectiveMask .= $mask; } - if (!isset($headers['upgrade']) || strtolower($headers['upgrade']) != 'websocket') { - $handshakeResponse = "HTTP/1.1 400 Bad Request"; - } - if (!isset($headers['connection']) || strpos(strtolower($headers['connection']), 'upgrade') === FALSE) { - $handshakeResponse = "HTTP/1.1 400 Bad Request"; + while (mb_strlen($effectiveMask, "ASCII") > mb_strlen($payload, "ASCII")) { + $effectiveMask = substr($effectiveMask,0,-1); } - if (!isset($headers['sec-websocket-key'])) { - $handshakeResponse = "HTTP/1.1 400 Bad Request"; + return $effectiveMask ^ $payload; + } + + protected function checkRSVBits($headers,$user) { // override this method if you are using an extension where the RSV bits are used. + if (ord($headers['rsv1']) + ord($headers['rsv2']) + ord($headers['rsv3']) > 0) { + //$this->disconnect($user); // todo: fail connection + return true; + } + return false; + } + + protected function strtohex($str) { + $strout = ""; + for ($i = 0; $i < mb_strlen($str, "ASCII"); $i++) { + $strout .= (ord($str[$i])<16) ? "0" . dechex(ord($str[$i])) : dechex(ord($str[$i])); + $strout .= " "; + if ($i%32 == 7) { + $strout .= ": "; + } + if ($i%32 == 15) { + $strout .= ": "; + } + if ($i%32 == 23) { + $strout .= ": "; + } + if ($i%32 == 31) { + $strout .= "\n"; + } + } + return $strout . "\n"; + } + + function chunk($step, $cont) + { + return $this->frame('@BEGIN@'.$cont.'@END@'); // , 'text', TRUE); + } + + protected function frame($message, $messageType='text', $messageContinues=false) { + switch ($messageType) { + case 'continuous': + $b1 = 0; + break; + case 'text': + $b1 = ($this->sendingContinuous) ? 0 : 1; + break; + case 'binary': + $b1 = ($this->sendingContinuous) ? 0 : 2; + break; + case 'close': + $b1 = 8; + break; + case 'ping': + $b1 = 9; + break; + case 'pong': + $b1 = 10; + break; + } + if ($messageContinues) { + $this->sendingContinuous = true; } else { - + $b1 += 128; + $this->sendingContinuous = false; } - if (!isset($headers['sec-websocket-version']) || strtolower($headers['sec-websocket-version']) != 13) { - $handshakeResponse = "HTTP/1.1 426 Upgrade Required\r\nSec-WebSocketVersion: 13"; + + $length = mb_strlen($message, "ASCII"); + $lengthField = ""; + if ($length < 126) { + $b2 = $length; + } elseif ($length <= 65536) { + $b2 = 126; + $hexLength = dechex($length); + //$this->stdout("Hex Length: $hexLength"); + if (mb_strlen($hexLength, "ASCII")%2 == 1) { + $hexLength = '0' . $hexLength; + } + $n = mb_strlen($hexLength, "ASCII") - 2; + + for ($i = $n; $i >= 0; $i=$i-2) { + $lengthField = chr(hexdec(substr($hexLength, $i, 2))) . $lengthField; + } + while (mb_strlen($lengthField, "ASCII") < 2) { + $lengthField = chr(0) . $lengthField; + } + } else { + $b2 = 127; + $hexLength = dechex($length); + if (mb_strlen($hexLength, "ASCII")%2 == 1) { + $hexLength = '0' . $hexLength; + } + $n = mb_strlen($hexLength, "ASCII") - 2; + + for ($i = $n; $i >= 0; $i=$i-2) { + $lengthField = chr(hexdec(substr($hexLength, $i, 2))) . $lengthField; + } + while (mb_strlen($lengthField, "ASCII") < 8) { + $lengthField = chr(0) . $lengthField; + } } - if (($this->headerOriginRequired && !isset($headers['origin']) ) || ($this->headerOriginRequired && !$this->checkOrigin($headers['origin']))) { - $handshakeResponse = "HTTP/1.1 403 Forbidden"; + + return chr($b1) . chr($b2) . $lengthField . $message; + } + + protected function deframe($message) { + //echo $this->strtohex($message); + $headers = $this->extractHeaders($message); + $pongReply = false; + $willClose = false; + switch($headers['opcode']) { + case 0: + case 1: + case 2: + break; + case 8: + // todo: close the connection + $this->hasSentClose = true; + return ""; + case 9: + $pongReply = true; + case 10: + break; + default: + //$this->disconnect($user); // todo: fail connection + $willClose = true; + break; } - if (($this->headerSecWebSocketProtocolRequired && !isset($headers['sec-websocket-protocol'])) || ($this->headerSecWebSocketProtocolRequired && !$this->checkWebsocProtocol($header['sec-websocket-protocol']))) { - $handshakeResponse = "HTTP/1.1 400 Bad Request"; + + if ($this->handlingPartialPacket) { + $message = $this->partialBuffer . $message; + $this->handlingPartialPacket = false; + return $this->deframe($message); } - if (($this->headerSecWebSocketExtensionsRequired && !isset($headers['sec-websocket-extensions'])) || ($this->headerSecWebSocketExtensionsRequired && !$this->checkWebsocExtensions($header['sec-websocket-extensions']))) { - $handshakeResponse = "HTTP/1.1 400 Bad Request"; + + if ($this->checkRSVBits($headers,$this)) { + return false; } - - // Done verifying the _required_ headers and optionally required headers. - - if (isset($handshakeResponse)) { - socket_write($user->socket,$handshakeResponse,strlen($handshakeResponse)); - $this->disconnect($user->socket); + + if ($willClose) { + // todo: fail the connection return false; } - - $user->headers = $headers; - $user->handshake = $buffer; - - $webSocketKeyHash = sha1($headers['sec-websocket-key'] . $magicGUID); - - $rawToken = ""; - for ($i = 0; $i < 20; $i++) { - $rawToken .= chr(hexdec(substr($webSocketKeyHash,$i*2, 2))); + + $payload = $this->partialMessage . $this->extractPayload($message,$headers); + + if ($pongReply) { + $reply = $this->frame($payload,$this,'pong'); + // TODO FIXME ALL socket_write management + socket_write($user->socket,$reply,mb_strlen($reply, "ASCII")); + return false; + } + if (extension_loaded('mbstring')) { + if ($headers['length'] > mb_strlen($payload, "ASCII")) { + $this->handlingPartialPacket = true; + $this->partialBuffer = $message; + return false; + } + } else { + if ($headers['length'] > mb_strlen($payload, "ASCII")) { + $this->handlingPartialPacket = true; + $this->partialBuffer = $message; + return false; + } + } + + $payload = $this->applyMask($headers,$payload); + + if ($headers['fin']) { + $this->partialMessage = ""; + return $payload; } - $handshakeToken = base64_encode($rawToken) . "\r\n"; - - $subProtocol = (isset($headers['sec-websocket-protocol'])) ? $this->processProtocol($headers['sec-websocket-protocol']) : ""; - $extensions = (isset($headers['sec-websocket-extensions'])) ? $this->processExtensions($headers['sec-websocket-extensions']) : ""; - - $handshakeResponse = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: $handshakeToken$subProtocol$extensions\r\n"; - socket_write($user->socket,$handshakeResponse,strlen($handshakeResponse)); - $this->connected($user); + $this->partialMessage = $payload; + return false; } - - function init($enc, $header, &$header_out, $init_string, $base, $step) + + protected function checkHost($hostName) { + return true; // Override and return false if the host is not one that you would expect. + // Ex: You only want to accept hosts from the my-domain.com domain, + // but you receive a host from malicious-site.com instead. + } + + protected function checkOrigin($origin) { + return true; // Override and return false if the origin is not one that you would expect. + } + + protected function checkWebsocProtocol($protocol) { + return true; // Override and return false if a protocol is not found that you would expect. + } + + protected function checkWebsocExtensions($extensions) { + return true; // Override and return false if an extension is not found that you would expect. + } + + protected function processProtocol($protocol) { + return ""; // return either "Sec-WebSocket-Protocol: SelectedProtocolFromClientList\r\n" or return an empty string. + // The carriage return/newline combo must appear at the end of a non-empty string, and must not + // appear at the beginning of the string nor in an otherwise empty string, or it will be considered part of + // the response body, which will trigger an error in the client as it will not be formatted correctly. + } + + protected function processExtensions($extensions) { + return ""; // return either "Sec-WebSocket-Extensions: SelectedExtensions\r\n" or return an empty string. + } + + function init($enc, $headers, &$headers_out, $init_string, $base, $step) { - + if (0) { // TODO: what is ? + if (isset($headers['get'])) { + $this->requestedResource = $headers['get']; + } else { + // todo: fail the connection + $headers_out['HTTP-Response'] = "405 Method Not Allowed"; + } + } + if (!isset($headers['Host']) || !$this->checkHost($headers['Host'])) { + $headers_out['HTTP-Response'] = "400 Bad Request"; + } + if (!isset($headers['Upgrade']) || strtolower($headers['Upgrade']) != 'websocket') { + $headers_out['HTTP-Response'] = "400 Bad Request"; + } + if (!isset($headers['Connection']) || strpos(strtolower($headers['Connection']), 'upgrade') === FALSE) { + $headers_out['HTTP-Response'] = "400 Bad Request"; + } + if (!isset($headers['Sec-Websocket-Key'])) { + $headers_out['HTTP-Response'] = "400 Bad Request"; + } else { + } + if (!isset($headers['Sec-Websocket-Version']) || strtolower($headers['Sec-Websocket-Version']) != 13) { + $headers_out['HTTP-Response'] = "426 Upgrade Required"; + $headers_out['Sec-WebSocketVersion'] = "13"; + } + if ( ($this->headerOriginRequired && !isset($headers['Origin']) ) + || ($this->headerOriginRequired && !$this->checkOrigin($headers['Origin'])) ) { + $headers_out['HTTP-Response'] = "403 Forbidden"; + } + if ( ($this->headerSecWebSocketProtocolRequired && !isset($headers['Sec-Websocket-Protocol'])) + || ($this->headerSecWebSocketProtocolRequired && + !$this->checkWebsocProtocol($headers['Sec-Websocket-Protocol']))) { + $headers_out['HTTP-Response'] = "400 Bad Request"; + } + if ( ($this->headerSecWebSocketExtensionsRequired && !isset($headers['Sec-Websocket-Extensions'])) + || ($this->headerSecWebSocketExtensionsRequired && + !$this->checkWebsocExtensions($headers['Sec-Websocket-Extensions'])) ) { + $headers_out['HTTP-Response'] = "400 Bad Request"; + } - $ret = sprintf("@BEGIN@ /* %s */ @END@", $init_string); - if ($enc != 'plain') - $header_out['Content-Encoding'] = $enc; - $header_out['Cache-Control'] = 'no-cache, must-revalidate'; // HTTP/1.1 - $header_out['Expires'] = 'Mon, 26 Jul 1997 05:00:00 GMT'; // Date in the past - $header_out['Content-type'] = 'application/xml; charset="utf-8"'; + if (isset($headers_out['HTTP-Response'])) { + // TODO: check return management + return (FALSE); + } - return ($ret); + // TODO: verify both variables + // here there is a change of the socket status from start to handshaked + // th headers are saved too but without any further access so we skip it + + + + $inno = 'x3JJHMbDL1EzLkh9GBhXDw=='; + $outo = sha1($inno . $this->magicGUID); + $rawToken = ""; + for ($i = 0; $i < 20; $i++) { + $rawToken .= chr(hexdec(substr($outo,$i*2, 2))); + } + + $outo = base64_encode($rawToken); + + $webSocketKeyHash = sha1($headers['Sec-Websocket-Key'] . $this->magicGUID); + $rawToken = ""; + for ($i = 0; $i < 20; $i++) { + $rawToken .= chr(hexdec(substr($webSocketKeyHash,$i*2, 2))); + } + $handshakeToken = base64_encode($rawToken); + $subProtocol = (isset($headers['Sec-Websocket-Protocol'])) ? + $this->processProtocol($headers['Sec-Websocket-Protocol']) : ""; + $extensions = (isset($headers['Sec-Websocket-Extensions'])) ? + $this->processExtensions($headers['Sec-Websocket-Extensions']) : ""; + + $headers_out['HTTP-Response'] = "101 Switching Protocols"; + $headers_out['Upgrade'] = 'websocket'; + $headers_out['Connection'] = 'Upgrade'; + $headers_out['Sec-WebSocket-Accept'] = "$handshakeToken$subProtocol$extensions"; + + return (""); + } + + static function close() + { + return(chr(0x88).chr(0x02).chr(0xe8).chr(0x03)); } static function fini($init_string, $base, $blockerr) { - return (sprintf('@BEGIN@ %s window.onbeforeunload = null; window.onunload = null; document.location.assign("%sindex.php"); @END@', ($blockerr ? 'xstm.stop(); ' : ''), $base)); - return (""); + return (sprintf('@BEGIN@ %s window.onbeforeunload = null; window.onunload = null; document.location.assign("%sindex.php"); @END@', ($blockerr ? 'xstm.stop(); ' : ''), $base).self::close()); } - function chunk($step, $cont) + function is_chunked() { - return ("@BEGIN@".$cont."@END@"); + return FALSE; } + } class Transport_xhr { @@ -201,6 +490,11 @@ class Transport_xhr { return ($ret); } + function close() + { + return ""; + } + static function fini($init_string, $base, $blockerr) { return (sprintf('@BEGIN@ %s window.onbeforeunload = null; window.onunload = null; document.location.assign("%sindex.php"); @END@', ($blockerr ? 'xstm.stop(); ' : ''), $base)); @@ -232,7 +526,7 @@ class Transport_iframe { $header_out['Cache-Control'] = 'no-cache, must-revalidate'; // HTTP/1.1 $header_out['Expires'] = 'Mon, 26 Jul 1997 05:00:00 GMT'; // Date in the past $header_out['Content-type'] = 'text/html; charset="utf-8"'; - + $ret .= sprintf(" @@ -243,7 +537,7 @@ var xynt_streaming = \"ready\";", $base, $base); $ret .= sprintf("last_clean = %d;\n", ($step-1)); $ret .= sprintf(" window.onload = function () { try { if (xynt_streaming != \"ready\") { xynt_streaming.transp.stopped = true; } } catch(e) { /* console.log(\"catcha\"); */ } }; - + "); $ret .= sprintf("\n", $init_string); @@ -251,6 +545,11 @@ window.onload = function () { try { if (xynt_streaming != \"ready\") { xynt_stre return ($ret); } + function close() + { + return ""; + } + static function fini($init_string, $base, $blockerr) { $ret = ""; @@ -301,7 +600,10 @@ class Transport { static function create($transp) { - if ($transp == 'xhr') { + if ($transp == 'websocket') { + return new Transport_websocket(); + } + else if ($transp == 'xhr') { return new Transport_xhr(); } else if ($transp == 'htmlfile') { @@ -313,7 +615,7 @@ class Transport { } static function gettype($transp) { - if ($transp == 'xhr' || $transp == 'htmlfile') { + if ($transp == 'websocket' || $transp == 'xhr' || $transp == 'htmlfile') { return "Transport_".$transp; } else { diff --git a/web/Obj/user.phh b/web/Obj/user.phh index 55a3a75..2caf30a 100644 --- a/web/Obj/user.phh +++ b/web/Obj/user.phh @@ -720,7 +720,13 @@ function stream_init($init_string, $enc, $header, &$header_out, &$body, $get, $p $this->rd_data_set($curtime, $transp, $enc, $stat, $subst, $step, $from); - $body .= $this->rd_transp->init($enc, $header, &$header_out, $init_string, self::base_get(), $this->rd_scristp); + $ret = $this->rd_transp->init($enc, $header, &$header_out, $init_string, self::base_get(), $this->rd_scristp); + + if ($ret === FALSE) { + return FALSE; + } + + $body .= $ret; return TRUE; } @@ -760,6 +766,11 @@ function stream_keepalive($with_ping) return ($this->rd_transp->chunk( $this->rd_scristp++, ($with_ping ? "act_ping();" : NULL))); } +function stream_close() +{ + return ($this->rd_transp->close()); +} + static function base_get() { $c = get_called_class(); @@ -803,7 +814,7 @@ function chunked_content($content) return (sprintf("%X\r\n", $cont_comp_l).$cont_comp."\r\n"); } else { - return $content; + return $cont_comp; } } diff --git a/web/briskin5/index.php b/web/briskin5/index.php index af20289..15b449f 100644 --- a/web/briskin5/index.php +++ b/web/briskin5/index.php @@ -116,7 +116,7 @@ window.onload = function() { preferences_update(); sess = ""; - xstm = new xynt_streaming(window, "", null /* console */, gst, 'table_php', 'sess', sess, $('sandbox'), 'index_rd_ifra.php', function(com){eval(com);}); + xstm = new xynt_streaming(window, "", 80, 2, null /* console */, gst, 'table_php', 'sess', sess, $('sandbox'), 'index_rd_ifra.php', function(com){eval(com);}); xstm.hbit_set(heartbit); window.onbeforeunload = onbeforeunload_cb; diff --git a/web/commons.js b/web/commons.js index 4cf95dc..3021613 100644 --- a/web/commons.js +++ b/web/commons.js @@ -1195,7 +1195,7 @@ function url_complete(parent, url) } // alert("host: ["+host+"] path: ["+path+"]"); - if (url.substring(0,6) == 'http:/' || url.substring(0,7) == 'https:/') { + if (url.substring(0,6) == 'http:/' || url.substring(0,7) == 'https:/' || url.substring(0,4) == 'ws:/') { return (url); } else if (url.substring(0,1) == '/') { diff --git a/web/index.php b/web/index.php index 0b3076a..a3d283f 100644 --- a/web/index.php +++ b/web/index.php @@ -3,7 +3,7 @@ * brisk - index.php * * Copyright (C) 2006-2012 Matteo Nastasi - * mailto: nastasi@alternativeoutput.it + * mailto: nastasi@alternativeoutput.it * matteo.nastasi@milug.org * web: http://www.alternativeoutput.it * @@ -96,7 +96,7 @@ $mlang_room = array( 'userpasserr' => array('it' => 'Utente e/o password errati 'en' => 'mop'), 'st_visch_desc' => array('it' => 'vischio', 'en' => 'mop'), - + 'tit_ticker' => array('it' => 'scrivi un invito al tavolo e clicca', 'en' => 'write an invitation at the table and click'), 'itm_warr' => array('it' => 'garantisci', @@ -243,13 +243,13 @@ function index_main(&$room, $transp_type, &$header_out, $addr, $get, $post, $coo { GLOBAL $G_with_donors, $G_donors_cur, $G_donors_all; GLOBAL $G_with_topbanner, $G_topbanner, $G_is_local; - GLOBAL $G_with_sidebanner, $G_sidebanner; - GLOBAL $G_with_sidebanner2, $G_sidebanner2; + GLOBAL $G_with_sidebanner, $G_sidebanner; + GLOBAL $G_with_sidebanner2, $G_sidebanner2; GLOBAL $G_with_poll; GLOBAL $G_lang, $G_lng, $mlang_room; GLOBAL $BRISK_SHOWHTML, $BRISK_DEBUG, $_SERVER; - if (($sess = gpcs_var('sess', $get, $post, $cookie)) === FALSE) + if (($sess = gpcs_var('sess', $get, $post, $cookie)) === FALSE) $sess = ""; if (($name = gpcs_var('name', $get, $post, $cookie)) === FALSE) unset($name); @@ -270,14 +270,14 @@ function index_main(&$room, $transp_type, &$header_out, $addr, $get, $post, $coo $tables = ""; $standup = ""; $ACTION = "login"; - + if (isset($BRISK_SHOWHTML) == FALSE) { $is_table = FALSE; log_main("lock Room"); $curtime = time(); - + /* Actions */ - + if (validate_sess($sess)) { log_main("pre garbage_manager UNO"); $room->garbage_manager(TRUE); @@ -294,17 +294,15 @@ function index_main(&$room, $transp_type, &$header_out, $addr, $get, $post, $coo } $ACTION = "room"; } - } - + if ($ACTION == "login" && isset($name)) { - log_main("pre garbage_manager DUE"); - + if (isset($pass_private) == FALSE) { $pass_private = FALSE; } - + $room->garbage_manager(TRUE); /* try login */ @@ -315,9 +313,9 @@ function index_main(&$room, $transp_type, &$header_out, $addr, $get, $post, $coo $idx = -$idx - 1; $is_login = TRUE; } - + log_legal($curtime, $ipv4addr, $user, "STAT:LOGIN", ''); - + // recovery lost game if ($user->stat == "table") { $cookies = new Cookies(); @@ -327,38 +325,36 @@ function index_main(&$room, $transp_type, &$header_out, $addr, $get, $post, $coo $header_out['Location'] = "briskin5/index.php"; return TRUE; } - - + // setcookie ("sess", "", time() + 180); $room->standup_update(&$user); - } else { /* Login Rendering */ /* MLANG: "Utente e/o password errati.", "Il nickname deve contenere almeno una lettera o una cifra.", "Spiacenti, non ci sono più posti liberi. Riprova più tardi.", "Il tuo nickname è già in uso." */ /* - if ($idx == -3) + if ($idx == -3) $body .= '
'.$mlang_room['userpasserr'][$G_lang].'
'; else if ($idx == -2) // $body .= '
Il nickname deve contenere almeno una lettera o una cifra.
'; $body .= '
'.$mlang_room['userpassmust'][$G_lang].'
'; - else if ($idx == -1) + else if ($idx == -1) // $body .= '
Spiacenti, non ci sono più posti liberi. Riprova più tardi.
'; $body .= '
'.$mlang_room['userpassend'][$G_lang].'
'; else // $body .= '
Il tuo nickname è già in uso.
'; $body .= '
'.$mlang_room['userpassuse'][$G_lang].'
'; */ - - if ($idx == -3) + + if ($idx == -3) $sfx = 'err'; else if ($idx == -2) $sfx = 'must'; - else if ($idx == -1) + else if ($idx == -1) $sfx = 'end'; else $sfx = 'use'; - + $body .= '
'.$mlang_room['userpass'.$sfx][$G_lang].'
'; } } @@ -380,13 +376,13 @@ function index_main(&$room, $transp_type, &$header_out, $addr, $get, $post, $coo $i = $ii; else $i = TABLES_N - $ii - 1; - + if ($ii % 4 == 0) { $tables .= ''; } if (TRUE || !($user->flags & USER_FLAG_ISOLAUTH) || $ii < TABLES_AUTH_N) { $tables .= ''; - + $tables .= '
'.$mlang_room['tit_tabl'][$G_lang].$i.'
'; $tables .= sprintf('
', $i); $tables .= sprintf('
', $i); @@ -398,14 +394,13 @@ function index_main(&$room, $transp_type, &$header_out, $addr, $get, $post, $coo } } $tables .= '
'; - - + $standup .= '
'; $standup .= '
'; /* MLANG: "Giocatori in piedi" */ // $standup .= '
Giocatori in piedi - Come ottenere user e password -
'; $standup .= '
'.$mlang_room['standing'][$G_lang].'
'; - + $standup .= sprintf('
'); // MLANG Esco. $standup .= '
'; @@ -1071,7 +1066,7 @@ else { ?> sess = ""; -xstm = new xynt_streaming(window, "", null /* console */, gst, 'index_php', 'sess', sess, $('sandbox'), 'index_rd_ifra.php', function(com){eval(com);}); +xstm = new xynt_streaming(window, "", 80, 2, console, gst, 'index_php', 'sess', sess, $('sandbox'), 'index_rd_ifra.php', function(com){eval(com);}); xstm.hbit_set(heartbit); tra = new train($('room_tit')); window.onunload = onunload_cb; @@ -1132,7 +1127,7 @@ if ($is_login) { } printf("
"); -?> +?> sess"; ?>">
diff --git a/web/ws.php b/web/ws.php index 640c227..a21eb6f 100644 --- a/web/ws.php +++ b/web/ws.php @@ -1,5 +1,5 @@ @@ -16,13 +16,13 @@ window.onload = function() { var host = "ws://dodo.birds.van/brisk/xynt_test01.php?isstream=true&transp=websocket&f_test=1"; // SET THIS TO YOUR SERVER - + console.log("QUI"); try { socket = new WebSocket(host); console.log('WebSocket - status ' + socket.readyState); - + socket.onopen = function(msg) { if(this.readyState == 1) @@ -30,30 +30,30 @@ console.log("We are now connected to websocket server. readyState = " + this.readyState); } }; - + //Message received from websocket server socket.onmessage = function(msg) { console.log(" [ + ] Received: " + msg.data); }; - + //Connection closed socket.onclose = function(msg) { console.log("Disconnected - status " + this.readyState); }; - + socket.onerror = function() { console.log("Some error"); } } - + catch(ex) { console.log('Some exception : ' + ex); } - + }; //--> diff --git a/web/xynt-streaming.js b/web/xynt-streaming.js index 11f4f22..f80e8e8 100644 --- a/web/xynt-streaming.js +++ b/web/xynt-streaming.js @@ -1,5 +1,146 @@ // old targetpage == page and moved into start method +// +// CLASS transport_ws +// +function transport_ws(doc, xynt_streaming, page) +{ + this.ctx_new = ""; + var self = this; + + this.doc = doc; + this.failed = false; + this.xynt_streaming = xynt_streaming; + try { + this.ws = new WebSocket(page); + this.ws.onopen = function () { + self.xynt_streaming.log("onopen"); + if (this.readyState == 1) { + // connected + self.ws_cb("open"); + } + }; + this.ws.onmessage = function (msg) { + self.xynt_streaming.log("onmessage"); + // new data in msg.data + self.ctx_new += msg.data; + }; + this.ws.onclose = function (msg) { + self.xynt_streaming.log("onclose"); + self.ws_cb("close"); + }; + this.ws.onerror = function () { + // on error + self.xynt_streaming.log("onerror"); + self.ws_cb("error"); + }; + } + catch (ex) { + throw "websocket creation failed"; + } + + this.stopped = false; +} + +transport_ws.prototype = { + doc: null, + xynt_streaming: "ready", + ws: null, + stopped: true, + failed: false, + + ctx_old: "", + ctx_old_len: 0, + ctx_new: "", + + // script_clean: 0, + + destroy: function () { /* public */ + if (this.ws != null) { + this.ws_abort(); + } + delete this.ws; + }, + + ws_cb: function (from) { + var ret; + + if (from == "error") { + if (this.xynt_streaming != "ready") { + if (this.xynt_streaming.transp_fback > 0) { + this.xynt_streaming.transp_fback--; + this.stopped = true; + this.xynt_streaming.reload(); + } + } + } + if (this.ws != null && this.ws.readyState > 1) { + this.stopped = true; + } + }, + + ws_abort: function() { + if (this.ws != null) { + this.ws.close(); + } + }, + + xstr_is_init: function () { /* public */ + return (true); + }, + + /* only after a successfull is_initialized call */ + xstr_is_ready: function () { /* public */ + return (this.ws.readyState == 1); + }, + + xstr_set: function () { /* public */ + // already set + }, + + ctx_new_is_set: function () { /* public */ + return (this.ctx_new != null); + }, + + ctx_new_curlen_get: function () { /* public */ + return (this.ctx_new.length); + }, + + ctx_new_getchar: function(idx) { /* public */ + return (this.ctx_new[idx]); + }, + + ctx_old_len_is_set: function () { /* public */ + return (true); + }, + + ctx_old_len_get: function () { /* public */ + return (this.ctx_old_len); + }, + + ctx_old_len_set: function (len) { /* public */ + this.ctx_old_len = len; + }, + + ctx_old_len_add: function (len) { /* public */ + this.ctx_old_len += len; + }, + + new_part: function () { /* public */ + return (this.ctx_new.substr(this.ctx_old_len)); + }, + + scrcls_set: function (step) { /* public */ + // this.script_clean = step; + }, + + postproc: function () { + if (this.stopped && !this.xstr_is_ready()) { + this.xynt_streaming.reload(); + } + } +} + // // CLASS transport_xhr // @@ -232,8 +373,6 @@ transport_htmlfile.prototype = { } } - - // // CLASS transport_iframe // @@ -344,10 +483,12 @@ transport_iframe.prototype = { } } -function xynt_streaming(win, transp_type, console, gst, from, cookiename, sess, sandbox, page, cmdproc) +function xynt_streaming(win, transp_type, transp_port, transp_fback, console, gst, from, cookiename, sess, sandbox, page, cmdproc) { this.win = win; this.transp_type = transp_type; + this.transp_port = transp_port; + this.transp_fback = transp_fback; this.console = console; this.gst = gst; this.from = from; @@ -365,12 +506,13 @@ function xynt_streaming(win, transp_type, console, gst, from, cookiename, sess, this.mon_wrntime = this.mon_errtime / 2; this.mon_update(); - } xynt_streaming.prototype = { win: null, transp_type: null, + transp_port: 80, + transp_fback: 0, transp: null, console: null, gst: null, @@ -399,7 +541,7 @@ xynt_streaming.prototype = { watchdog_ct: 0, watchable: false, restart_n: 0, - comm_match: /_*@BEGIN@(.*?)@END@/g, + comm_match: /_*@BEGIN@(.*?)@END@/g, comm_clean: /_*@BEGIN@(.*?)@END@/, stream: "", the_end: false, @@ -442,7 +584,11 @@ xynt_streaming.prototype = { }, start: function() { /* public */ - if (this.the_end) + var transp_type; + var page; + + // this.log("start "+this.transp_type+" "+this.transp_fback); + if (this.the_end) return; createCookie(this.cookiename, sess, 24*365, this.cookiepath); @@ -452,26 +598,63 @@ xynt_streaming.prototype = { // page arrangement this.page = url_complete(this.win.location.href, this.page); - // stat, subst, this.gst.st - this.page = url_append_args(this.page, "sess", this.sess, "stat", stat, "subst", subst, "step", this.gst.st, "from", this.from); - this.log(this.page); + if (this.transp_fback > 0) { + transp_type = "websocket"; + transp_port = (this.transp_fback == 2 ? 80 : 8080); + } + else { + transp_type = this.transp_type; + transp_port = this.transp_port; + } + + if (transp_type == "websocket") { + var end_proto, first_slash; - // transport instantiation - if (this.transp_type == "xhr") { - this.page = url_append_args(this.page, "transp", "xhr"); - this.transp = new transport_xhr(this.doc, this, this.page); + // change protocol + this.log("precha ["+this.page+"]"); + end_proto = this.page.indexOf("://"); + first_slash = this.page.substring(end_proto+3).indexOf("/"); + + page = "ws://" + this.page.substring(end_proto+3, end_proto+3+first_slash) + ":" + transp_port + this.page.substring(end_proto+3 + first_slash); + } + else { + page = this.page; } - else if (this.transp_type == "iframe") { - this.page = url_append_args(this.page, "transp", "iframe"); - this.transp = new transport_iframe(this.doc, this, this.page); + // stat, subst, this.gst.st + + page = url_append_args(page, "sess", this.sess, "stat", stat, "subst", subst, "step", this.gst.st, "from", this.from); + // this.log("the page:"); + // this.log(page); + + try { + // transport instantiation + if (transp_type == "websocket") { + page = url_append_args(page, "transp", "websocket"); + this.transp = new transport_ws(this.doc, this, page); + } + else if (transp_type == "xhr") { + page = url_append_args(page, "transp", "xhr"); + this.transp = new transport_xhr(this.doc, this, page); + } + else if (transp_type == "iframe") { + page = url_append_args(page, "transp", "iframe"); + this.transp = new transport_iframe(this.doc, this, page); + } + else if (transp_type == "htmlfile") { + page = url_append_args(page, "transp", "htmlfile"); + this.transp = new transport_htmlfile(this.doc, this, page); + } + else + return; } - else if (this.transp_type == "htmlfile") { - this.page = url_append_args(this.page, "transp", "htmlfile"); - this.transp = new transport_htmlfile(this.doc, this, this.page); + catch (err) { + if (this.transp_fback > 0) { + this.transp_fback--; + this.start(); + return; + } } - else - return; // watchdog setting this.watchdog_ct = 0; @@ -528,7 +711,7 @@ xynt_streaming.prototype = { if (this.sandbox != null) { // from old: var zug = "POLL sess = "+sess+" stat = "+stat+" subst = "+subst+" step = "+this.gst.st+" step_loc = "+this.gst.st_loc+" step_loc_new = "+this.gst.st_loc_new+" STOP: "+this.stopped; - var zug = "WATCHDOG sess = ["+this.sess+"] step = "+this.gst.st+" step_loc = "+this.gst.st_loc+" step_loc_new = "+this.gst.st_loc_new; + var zug = "WATCHDOG sess = ["+this.sess+"] step = "+this.gst.st+" step_loc = "+this.gst.st_loc+" step_loc_new = "+this.gst.st_loc_new; if (zug != this.sandbox.innerHTML) this.sandbox.innerHTML = zug; } @@ -550,7 +733,7 @@ xynt_streaming.prototype = { } /* - on IE7 the the window frame scope is cleaned after the href is set, so we wait + on IE7 the the window frame scope is cleaned after the href is set, so we wait for a well know variable value before assign this object value to it (OO is a passion) */ // if (this.ifra.contentWindow.xynt_streaming == "ready") { @@ -571,7 +754,7 @@ xynt_streaming.prototype = { this.keepalive_old = this.keepalive_new; this.keepalives_equal = 0; } - + if (this.keepalives_equal >= this.keepalives_eq_max) { this.log("hs::watchdog: MAX ACHIEVED "+this.keepalives_equal); this.reload(); @@ -584,7 +767,7 @@ xynt_streaming.prototype = { // PICK COMMANDS FROM STREAM do { // alert("do--while begin ["+again+"]"); - // CHECK: maybe again here isn't needed + // CHECK: maybe again here isn't needed again = 0; try { /* if (typeof(this.ifra.contentWindow.ctx_new) == 'undefined' || @@ -664,7 +847,7 @@ xynt_streaming.prototype = { } else if (this.gst.comms.length > 0) { var singlecomm; - + singlecomm = this.gst.comms.shift(); // alert("EXE"+gugu); // $("xhrdeltalog").innerHTML = "EVALL: "+singlecomm.replace("<", "<", "g"); +"
"; diff --git a/web/xynt_test01.php b/web/xynt_test01.php index 6673d34..c0aa058 100644 --- a/web/xynt_test01.php +++ b/web/xynt_test01.php @@ -8,6 +8,59 @@ $desc = array( "Semplice: da 1 a 9 ogni secondo, poi ricomincia (status sempre v "Reload limiter: da 1 a 8 ogni secondo e chiude, 9 setta e chiude subito,
il client aspetta 3 secondi, e poi da 10 a N ogni secondo, (status sempre verde)."); +// trim(mb_convert_case($split[0], MB_CASE_TITLE, 'UTF-8')) + +function headers_render($header, $len) +{ + $cookies = ""; + + if (isset($header['Cookies'])) { + $cookies = $header['Cookies']->render(); + unset($header['Cookies']); + } + if (isset($header['Location'])) { + header(sprintf("HTTP/1.1 302 OK\r\n%sLocation: %s", $cookies, $header['Location'])); + } + else if (isset($header['HTTP-Response'])) { + header(sprintf("HTTP/1.1 %s", $header['HTTP-Response'])); + foreach($header as $key => $value) { + if (strtolower($key) == "http-response") + continue; + header(sprintf("%s: %s", $key, $value)); + } + if ($len >= 0) { + header(sprintf("Content-Length: %ld", $len)); + } + } + else { + header("HTTP/1.1 200 OK\r\n"); + + if (!isset($header['Date'])) + header(sprintf("Date: %s", date(DATE_RFC822))); + if (!isset($header['Connection'])) + header("Connection: close"); + if (!isset($header['Content-Type'])) + header("Content-Type: text/html"); + foreach($header as $key => $value) { + header(sprintf("%s: %s", $key, $value)); + } + if ($len >= 0) { + header(sprintf("Content-Length: %d", $len)); + } + else { + header("Cache-Control: no-cache, must-revalidate"); + header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); + if (!isset($header['Content-Encoding'])) { + header("Content-Encoding: chunked"); + } + header("Transfer-Encoding: chunked"); + } + header($cookies); + } + + return (TRUE); +} + $transs = array( "iframe", "websocket", "xhr", "htmlfile" ); if (!isset($f_trans)) $f_trans = $transs[0]; @@ -41,24 +94,23 @@ function xcape($s) return (str_replace($from, $to, htmlentities($s,ENT_COMPAT,"UTF-8"))); } -if ($isstream == "true") { +if (isset($isstream) && $isstream == "true") { require_once("Obj/transports.phh"); - if (isset($transp) && $transp == "websocket") { - $transp = new Transport_websocket(); + $trobj = new Transport_websocket(); } else if (isset($transp) && $transp == "xhr") { - $transp = new Transport_xhr(); + $trobj = new Transport_xhr(); } else if (isset($transp) && $transp == "htmlfile") { - $transp = new Transport_htmlfile(); + $trobj = new Transport_htmlfile(); } else { - $transp = new Transport_iframe(); + $trobj = new Transport_iframe(); } - $header_out = array(); + $headers_out = array(); $init_string = ""; for ($i = 0 ; $i < 4096 ; $i++) { @@ -67,31 +119,65 @@ if ($isstream == "true") { else $init_string .= chr(mt_rand(65, 90)); } - $header = array(); + $headers_in = getallheaders(); + $headers = array(); + foreach ($headers_in as $header_in => $value) { + $headers[mb_convert_case($header_in, MB_CASE_TITLE, 'UTF-8')] = $value; + } + $fp = fopen("/tmp/xynt.log", "a+"); + fprintf($fp, "here we are\n"); + fclose($fp); + + $body = $trobj->init("plain", $headers, $headers_out, $init_string, "", "0"); + + if ($body === FALSE) { + $fp = fopen("/tmp/xynt.log", "a+"); + fprintf($fp, "init failed\n"); + fclose($fp); + } + else { + $fp = fopen("/tmp/xynt.log", "a+"); + fprintf($fp, "after_init [%s] [%s]\n", $transp, print_r($headers_out, TRUE)); + fprintf($fp, "body [%s][%d]\n", $body, mb_strlen($body, "ASCII")); + fclose($fp); + } - $body = $transp->init("plain", $header, $header_out, $init_string, "", "0"); + if (isset($transp) && $transp == "websocket") { + header_remove('Connection'); + header_remove('Content-Encoding'); + header_remove('Content-Type'); + header_remove('Date'); + header_remove('Keep-Alive'); + header_remove('Server'); + header_remove('Transfer-Encoding'); + header_remove('Vary'); + header_remove('X-Powered-By'); - foreach ($header_out as $key => $value) { - header(sprintf("%s: %s", $key, $value)); + headers_render($headers_out, 100); } + $lnz = 0; + print($body); + $lnz += mb_strlen($body, "ASCII"); mop_flush(); switch ($f_test) { case 1: // from 1 to 9 into the innerHTML and than close for ($i = 1 ; $i < 10 ; $i++) { - $chunk = $transp->chunk($i, sprintf("\$('container').innerHTML = '%d';", $i)); + $chunk = $trobj->chunk($i, sprintf("\$('container').innerHTML = '%d';", $i)); print($chunk); mop_flush(); sleep(1); } + break; case 2: // from 1 to 9 into the innerHTML and than close for ($i = 1 ; $i < 10 ; $i++) { - $chunk = $transp->chunk($i, sprintf("gst.st++; \$('container').innerHTML = gst.st;")); + $chunk = $trobj->chunk($i, sprintf("gst.st++; \$('container').innerHTML = gst.st;")); print($chunk); + $lnz += mb_strlen($chunk, "ASCII"); mop_flush(); sleep(1); } @@ -99,7 +185,7 @@ if ($isstream == "true") { case 3: // from 1 to 9 with 60 secs after 8, the client js api must restart stream after 12 secs for ($i = 1 ; $i < 10 ; $i++) { - $chunk = $transp->chunk($i, sprintf("\$('container').innerHTML = '%d';", $i)); + $chunk = $trobj->chunk($i, sprintf("\$('container').innerHTML = '%d';", $i)); print($chunk); mop_flush(); sleep(1); @@ -111,10 +197,10 @@ if ($isstream == "true") { // from 1 to 9 into the innerHTML and than close for ($i = 1 ; $i < 10 ; $i++) { if ($i != 5) { - $chunk = $transp->chunk($i, sprintf("\$('container').innerHTML = '%d';", $i)); + $chunk = $trobj->chunk($i, sprintf("\$('container').innerHTML = '%d';", $i)); } else { - $chunk = $transp->chunk($i, sprintf("\$('container').innerHTML = '%d';|sleep(gst,3000);", $i)); + $chunk = $trobj->chunk($i, sprintf("\$('container').innerHTML = '%d';|sleep(gst,3000);", $i)); } print($chunk); mop_flush(); @@ -129,10 +215,10 @@ if ($isstream == "true") { case 6: case 7: case 8: - $chunk = $transp->chunk($i, sprintf("\$('container').innerHTML = '%s';", xcape($cont[$i - 6]))); + $chunk = $trobj->chunk($i, sprintf("\$('container').innerHTML = '%s';", xcape($cont[$i - 6]))); break; default: - $chunk = $transp->chunk($i, sprintf("\$('container').innerHTML = '%d';", $i)); + $chunk = $trobj->chunk($i, sprintf("\$('container').innerHTML = '%d';", $i)); break; } print($chunk); @@ -144,7 +230,7 @@ if ($isstream == "true") { case 6: // from 1 to 9 into the innerHTML and than close if ($step == 8) { - $chunk = $transp->chunk(1, sprintf("gst.st++; \$('container').innerHTML = gst.st;")); + $chunk = $trobj->chunk(1, sprintf("gst.st++; \$('container').innerHTML = gst.st;")); print($chunk); // without this usleep the delay is doubled in iframe stream because // no transp.xynt_streaming back-set is performed @@ -153,7 +239,7 @@ if ($isstream == "true") { } else { for ($i = 1 ; $i < 10 ; $i++) { - $chunk = $transp->chunk($i, sprintf("gst.st++; \$('container').innerHTML = gst.st;")); + $chunk = $trobj->chunk($i, sprintf("gst.st++; \$('container').innerHTML = gst.st;")); print($chunk); mop_flush(); if ($i < 9) @@ -162,6 +248,10 @@ if ($isstream == "true") { } break; } + + print($trobj->close()); + mop_flush(); + exit; } ?> @@ -182,7 +272,7 @@ if ($isstream == "true") { var gst = new globst(); window.onload = function() { - xstm = new xynt_streaming(window, "", null /* console */, gst, 'xynt_test01_php', 'sess', sess, null, 'xynt_test01.php?isstream=true&f_test=', function(com){eval(com);}); + xstm = new xynt_streaming(window, "", 80, 0, null /* console */, gst, 'xynt_test01_php', 'sess', sess, null, 'xynt_test01.php?isstream=true&f_test=', function(com){eval(com);}); xstm.hbit_set(heartbit); xstm.start(); } -- 2.17.1