/**
  * Called when new data received.
  * @param string New received data.
  * @return void
  */
 public function stdin($buf)
 {
     $this->buf .= $buf;
     if ($this->state === self::STATE_ROOT) {
         if (strpos($this->buf, "<policy-file-request/>") !== FALSE) {
             $FP = FlashPolicyServer::getInstance();
             if ($FP && $FP->policyData) {
                 $this->write($FP->policyData . "");
             }
             $this->finish();
             return;
         }
         $i = 0;
         while (($l = $this->gets()) !== FALSE) {
             if ($i++ > 100) {
                 break;
             }
             if ($l === "\r\n") {
                 $this->state = self::STATE_HANDSHAKING;
                 if (isset($this->server['HTTP_SEC_WEBSOCKET_EXTENSIONS'])) {
                     $str = strtolower($this->server['HTTP_SEC_WEBSOCKET_EXTENSIONS']);
                     $str = preg_replace($this->extensionsCleanRegex, '', $str);
                     $this->extensions = explode(', ', $str);
                 }
                 if (!isset($this->server['HTTP_CONNECTION']) || !preg_match('~(?:^|\\W)Upgrade(?:\\W|$)~i', $this->server['HTTP_CONNECTION']) || !isset($this->server['HTTP_UPGRADE']) || strtolower($this->server['HTTP_UPGRADE']) !== 'websocket') {
                     $this->finish();
                     return;
                 }
                 if (isset($this->server['HTTP_COOKIE'])) {
                     HTTPRequest::parse_str(strtr($this->server['HTTP_COOKIE'], HTTPRequest::$hvaltr), $this->cookie);
                 }
                 // ----------------------------------------------------------
                 // Protocol discovery, based on HTTP headers...
                 // ----------------------------------------------------------
                 if (isset($this->server['HTTP_SEC_WEBSOCKET_VERSION'])) {
                     // HYBI
                     if ($this->server['HTTP_SEC_WEBSOCKET_VERSION'] == '8') {
                         // Version 8 (FF7, Chrome14)
                         $this->protocol = new WebSocketProtocolV13($this);
                     } elseif ($this->server['HTTP_SEC_WEBSOCKET_VERSION'] == '13') {
                         // newest protocol
                         $this->protocol = new WebSocketProtocolV13($this);
                     } else {
                         Daemon::$process->log(get_class($this) . '::' . __METHOD__ . " : Websocket protocol version " . $this->server['HTTP_SEC_WEBSOCKET_VERSION'] . ' is not yet supported for client "' . $this->addr . '"');
                         $this->finish();
                         return;
                     }
                 } elseif (!isset($this->server['HTTP_SEC_WEBSOCKET_KEY1']) || !isset($this->server['HTTP_SEC_WEBSOCKET_KEY2'])) {
                     $this->protocol = new WebSocketProtocolVE($this);
                 } else {
                     // Defaulting to HIXIE (Safari5 and many non-browser clients...)
                     $this->protocol = new WebSocketProtocolV0($this);
                 }
                 // ----------------------------------------------------------
                 // End of protocol discovery
                 // ----------------------------------------------------------
             } elseif (!$this->firstline) {
                 $this->firstline = true;
                 $e = explode(' ', $l);
                 $u = parse_url(isset($e[1]) ? $e[1] : '');
                 $this->server['REQUEST_METHOD'] = $e[0];
                 $this->server['REQUEST_URI'] = $u['path'] . (isset($u['query']) ? '?' . $u['query'] : '');
                 $this->server['DOCUMENT_URI'] = $u['path'];
                 $this->server['PHP_SELF'] = $u['path'];
                 $this->server['QUERY_STRING'] = isset($u['query']) ? $u['query'] : NULL;
                 $this->server['SCRIPT_NAME'] = $this->server['DOCUMENT_URI'] = isset($u['path']) ? $u['path'] : '/';
                 $this->server['SERVER_PROTOCOL'] = isset($e[2]) ? trim($e[2]) : '';
                 list($this->server['REMOTE_ADDR'], $this->server['REMOTE_PORT']) = explode(':', $this->addr);
             } else {
                 $e = explode(': ', $l);
                 if (isset($e[1])) {
                     $this->server['HTTP_' . strtoupper(strtr($e[0], HTTPRequest::$htr))] = rtrim($e[1], "\r\n");
                 }
             }
         }
     }
     if ($this->state === self::STATE_HANDSHAKING) {
         if (!$this->handshake($this->buf)) {
             return;
         }
         $this->buf = '';
         $this->state = self::STATE_HANDSHAKED;
     }
     if ($this->state === self::STATE_HANDSHAKED) {
         if (!isset($this->protocol)) {
             Daemon::$process->log(get_class($this) . '::' . __METHOD__ . ' : Cannot find session-related websocket protocol for client "' . $this->addr . '"');
             $this->finish();
             return;
         }
         $this->protocol->onRead();
     }
 }
 /**
  * Called when new data received.
  * @return void
  */
 public function onRead()
 {
     start:
     $buf = $this->read($this->readPacketSize);
     if ($this->state === self::STATE_ROOT) {
         if (strlen($buf) === 0) {
             return;
         }
         if (strpos($buf, "<policy-file-request/>") !== false) {
             if (($FP = FlashPolicyServer::getInstance()) && $FP->policyData) {
                 $this->write($FP->policyData . "");
             }
             $this->finish();
             return;
         }
         $rid = ++Daemon::$process->reqCounter;
         $this->state = self::STATE_HEADERS;
         $req = new stdClass();
         $req->attrs = new stdClass();
         $req->attrs->request = array();
         $req->attrs->get = array();
         $req->attrs->post = array();
         $req->attrs->cookie = array();
         $req->attrs->server = array();
         $req->attrs->files = array();
         $req->attrs->session = null;
         $req->attrs->id = $rid;
         $req->attrs->params_done = false;
         $req->attrs->stdin_done = false;
         $req->attrs->stdinbuf = '';
         $req->attrs->stdinlen = 0;
         $req->attrs->inbuf = '';
         $req->attrs->chunked = false;
         $req->queueId = $rid;
         $req->conn = $this;
         $this->req = $req;
     } else {
         if (!$this->req) {
             Daemon::log('Unexpected input (HTTP request).');
             return;
         }
         $req = $this->req;
     }
     if ($this->state === self::STATE_HEADERS) {
         $req->attrs->inbuf .= $buf;
         $buf = '';
         if (($p = strpos($req->attrs->inbuf, "\r\n\r\n")) !== false) {
             $headers = binarySubstr($req->attrs->inbuf, 0, $p);
             $headersArray = explode("\r\n", $headers);
             $req->attrs->inbuf = binarySubstr($req->attrs->inbuf, $p + 4);
             $command = explode(' ', $headersArray[0]);
             $u = isset($command[1]) ? parse_url($command[1]) : false;
             if ($u === false) {
                 $this->badRequest($req);
                 return;
             }
             $req->attrs->server['REQUEST_METHOD'] = $command[0];
             $req->attrs->server['REQUEST_TIME'] = time();
             $req->attrs->server['REQUEST_TIME_FLOAT'] = microtime(true);
             $req->attrs->server['REQUEST_URI'] = $u['path'] . (isset($u['query']) ? '?' . $u['query'] : '');
             $req->attrs->server['DOCUMENT_URI'] = $u['path'];
             $req->attrs->server['PHP_SELF'] = $u['path'];
             $req->attrs->server['QUERY_STRING'] = isset($u['query']) ? $u['query'] : null;
             $req->attrs->server['SCRIPT_NAME'] = $req->attrs->server['DOCUMENT_URI'] = isset($u['path']) ? $u['path'] : '/';
             $req->attrs->server['SERVER_PROTOCOL'] = isset($command[2]) ? $command[2] : 'HTTP/1.1';
             list($req->attrs->server['REMOTE_ADDR'], $req->attrs->server['REMOTE_PORT']) = explode(':', $this->addr);
             for ($i = 1, $n = sizeof($headersArray); $i < $n; ++$i) {
                 $e = explode(': ', $headersArray[$i]);
                 if (isset($e[1])) {
                     $req->attrs->server['HTTP_' . strtoupper(strtr($e[0], HTTPRequest::$htr))] = $e[1];
                 }
             }
             if (isset($u['host'])) {
                 $req->attrs->server['HTTP_HOST'] = $u['host'];
             }
             $req->attrs->params_done = true;
             if (isset($req->attrs->server['HTTP_CONNECTION']) && preg_match('~(?:^|\\W)Upgrade(?:\\W|$)~i', $req->attrs->server['HTTP_CONNECTION']) && isset($req->attrs->server['HTTP_UPGRADE']) && strtolower($req->attrs->server['HTTP_UPGRADE']) === 'websocket') {
                 if ($this->pool->WS) {
                     $this->pool->WS->inheritFromRequest($req, $this->pool);
                     return;
                 } else {
                     $this->finish();
                     return;
                 }
             } else {
                 $req = Daemon::$appResolver->getRequest($req, $this->pool, isset($this->pool->config->responder->value) ? $this->pool->config->responder->value : null);
                 $req->conn = $this;
                 $this->req = $req;
             }
             if ($req instanceof stdClass) {
                 $this->endRequest($req, 0, 0);
             } else {
                 if ($this->pool->config->sendfile->value && (!$this->pool->config->sendfileonlybycommand->value || isset($req->attrs->server['USE_SENDFILE'])) && !isset($req->attrs->server['DONT_USE_SENDFILE'])) {
                     $fn = FS::tempnam($this->pool->config->sendfiledir->value, $this->pool->config->sendfileprefix->value);
                     $req->sendfp = FS::open($fn, 'wb');
                     $req->header('X-Sendfile: ' . $fn);
                 }
                 $buf = $req->attrs->inbuf;
                 $req->attrs->inbuf = '';
                 $this->state = self::STATE_CONTENT;
             }
         } else {
             return;
             // not enough data
         }
     }
     if ($this->state === self::STATE_CONTENT) {
         $req->stdin($buf);
         $buf = '';
         if ($req->attrs->stdin_done) {
             $this->state = self::STATE_ROOT;
         } else {
             return;
         }
     }
     if ($req->attrs->stdin_done && $req->attrs->params_done) {
         if ($this->pool->variablesOrder === null) {
             $req->attrs->request = $req->attrs->get + $req->attrs->post + $req->attrs->cookie;
         } else {
             for ($i = 0, $s = strlen($this->pool->variablesOrder); $i < $s; ++$i) {
                 $char = $this->pool->variablesOrder[$i];
                 if ($char == 'G') {
                     $req->attrs->request += $req->attrs->get;
                 } elseif ($char == 'P') {
                     $req->attrs->request += $req->attrs->post;
                 } elseif ($char == 'C') {
                     $req->attrs->request += $req->attrs->cookie;
                 }
             }
         }
         Daemon::$process->timeLastReq = time();
     } else {
         goto start;
     }
 }