/** * 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; } }