function Transport_template() {
}
- function init($enc, &$header_out, $init_string, $base, $step)
+ // return string value is appended to the content of the returned page
+ function init($enc, $header, &$header_out, $init_string, $base, $step)
{
}
function chunk($step, $cont)
{
}
+
+ function is_chunked()
+ {
+ }
}
+class Transport_websocket {
+ $magicGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+
+ function Transport_websocket() {
+ }
+
+ 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]);
+ }
+ }
+ if (isset($headers['get'])) {
+ $user->requestedResource = $headers['get'];
+ } else {
+ // todo: fail the connection
+ $handshakeResponse = "HTTP/1.1 405 Method Not Allowed\r\n\r\n";
+ }
+ if (!isset($headers['host']) || !$this->checkHost($headers['host'])) {
+ $handshakeResponse = "HTTP/1.1 400 Bad Request";
+ }
+ 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";
+ }
+ if (!isset($headers['sec-websocket-key'])) {
+ $handshakeResponse = "HTTP/1.1 400 Bad Request";
+ } else {
+
+ }
+ if (!isset($headers['sec-websocket-version']) || strtolower($headers['sec-websocket-version']) != 13) {
+ $handshakeResponse = "HTTP/1.1 426 Upgrade Required\r\nSec-WebSocketVersion: 13";
+ }
+ if (($this->headerOriginRequired && !isset($headers['origin']) ) || ($this->headerOriginRequired && !$this->checkOrigin($headers['origin']))) {
+ $handshakeResponse = "HTTP/1.1 403 Forbidden";
+ }
+ 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->headerSecWebSocketExtensionsRequired && !isset($headers['sec-websocket-extensions'])) || ($this->headerSecWebSocketExtensionsRequired && !$this->checkWebsocExtensions($header['sec-websocket-extensions']))) {
+ $handshakeResponse = "HTTP/1.1 400 Bad Request";
+ }
+
+ // Done verifying the _required_ headers and optionally required headers.
+
+ if (isset($handshakeResponse)) {
+ socket_write($user->socket,$handshakeResponse,strlen($handshakeResponse));
+ $this->disconnect($user->socket);
+ 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)));
+ }
+ $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);
+ }
+
+
+ function init($enc, $header, &$header_out, $init_string, $base, $step)
+ {
+
+
+
+
+ $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"';
+
+ return ($ret);
+ }
+
+ 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 ("");
+ }
+
+ function chunk($step, $cont)
+ {
+ return ("@BEGIN@".$cont."@END@");
+ }
+}
+
class Transport_xhr {
function Transport_xhr() {
}
- function init($enc, &$header_out, $init_string, $base, $step)
+ function init($enc, $header, &$header_out, $init_string, $base, $step)
{
$ret = sprintf("@BEGIN@ /* %s */ @END@", $init_string);
if ($enc != 'plain')
{
return ("@BEGIN@".$cont."@END@");
}
+
+ function is_chunked()
+ {
+ return TRUE;
+ }
}
class Transport_iframe {
function Transport_iframe() {
}
- function init($enc, &$header_out, $init_string, $base, $step)
+ function init($enc, $header, &$header_out, $init_string, $base, $step)
{
$ret = "";
push(\"%s\");\n// -->\n</script>", $step, escpush($cont) );
}
}
+
+ function is_chunked()
+ {
+ return TRUE;
+ }
}
class Transport_htmlfile extends Transport_iframe {
var $rd_cache; // place where store failed fwrite data
var $rd_zls; // zlibstream object handle if compressed stream, else FALSE
var $rd_transp; // class that define stream encapsulation type (iframe, xhr, ...)
+ var $rd_is_chunked; // is the transport chunked or not ?
var $comm; // commands array
// var $asta_card; //
$thiz->rd_cache = "";
$thiz->rd_zls = FALSE;
$thiz->rd_transp = NULL;
+ $thiz->rd_is_chunked = FALSE;
$thiz->asta_card = -2;
$thiz->asta_pnt = -1;
$this->rd_kalive = $curtime + RD_KEEPALIVE_TOUT;
$this->rd_zls = ZLibStream::create($enc);
$this->rd_transp = Transport::create($transp);
+ $this->rd_is_chunked = $this->rd_transp->is_chunked();
}
function rd_socket_get() {
stat
step
*/
-function stream_init($init_string, $enc, &$header_out, &$body, $get, $post, $cookie)
+function stream_init($init_string, $enc, $header, &$header_out, &$body, $get, $post, $cookie)
{
$curtime = time();
$this->rd_data_set($curtime, $transp, $enc, $stat, $subst, $step, $from);
- $body .= $this->rd_transp->init($enc, &$header_out, $init_string, self::base_get(), $this->rd_scristp);
+ $body .= $this->rd_transp->init($enc, $header, &$header_out, $init_string, self::base_get(), $this->rd_scristp);
return TRUE;
}
return (FALSE);
}
+ function is_chunked()
+ {
+ return $this->rd_is_chunked;
+ }
+
+
+ function chunked_content($content)
+ {
+ if ($this->rd_zls) {
+ $cont_comp = $this->rd_zls->compress_chunk($content);
+ }
+ else {
+ $cont_comp = $content;
+ }
+ $cont_comp_l = mb_strlen($cont_comp, "ASCII");
+ // printf("CHUNK: [%s]\n", $content);
+
+ if ($this->is_chunked()) {
+ return (sprintf("%X\r\n", $cont_comp_l).$cont_comp."\r\n");
+ }
+ else {
+ return $content;
+ }
+ }
+
+ function chunked_fini()
+ {
+ return sprintf("0\r\n");
+ }
+
+
} // end class User