/** * Constructor * @param WakePHP $appInstance * @param IRequestUpstream $upstream. * @param $parent * @return \WakePHP\Core\Request */ public function __construct($appInstance, $upstream, $parent = null) { if (self::$emulMode) { return; } parent::__construct($appInstance, $upstream, $parent); }
/** * __construct * @param Application $appInstance [@todo description] * @param string $id [@todo description] * @param array $server [@todo description] * @return void */ public function __construct($appInstance, $id, $server) { $this->onWrite = new StackCallbacks(); $this->id = $id; $this->appInstance = $appInstance; $this->server = $server; if (isset($this->server['HTTP_COOKIE'])) { Generic::parseStr(strtr($this->server['HTTP_COOKIE'], Generic::$hvaltr), $this->cookie); } if (isset($this->server['QUERY_STRING'])) { Generic::parseStr($this->server['QUERY_STRING'], $this->get); } $this->addr = $server['REMOTE_ADDR']; $this->finishTimer = setTimeout(function ($timer) { $this->finish(); }, $this->timeout * 1000000.0); $this->appInstance->subscribe('c2s:' . $this->id, [$this, 'c2s']); $this->appInstance->subscribe('poll:' . $this->id, [$this, 'poll'], function ($redis) { $this->appInstance->publish('state:' . $this->id, 'started', function ($redis) { // @TODO: remove this callback }); }); }
/** * Process headers * @return bool */ protected function httpProcessHeaders() { $this->state = self::STATE_PREHANDSHAKE; 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 false; } if (isset($this->server['HTTP_COOKIE'])) { Generic::parse_str(strtr($this->server['HTTP_COOKIE'], Generic::$hvaltr), $this->cookie); } if (isset($this->server['QUERY_STRING'])) { Generic::parse_str($this->server['QUERY_STRING'], $this->get); } // ---------------------------------------------------------- // 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 ProtocolV13($this); } elseif ($this->server['HTTP_SEC_WEBSOCKET_VERSION'] === '13') { // newest protocol $this->protocol = new ProtocolV13($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 false; } } elseif (!isset($this->server['HTTP_SEC_WEBSOCKET_KEY1']) || !isset($this->server['HTTP_SEC_WEBSOCKET_KEY2'])) { $this->protocol = new ProtocolVE($this); } else { // Defaulting to HIXIE (Safari5 and many non-browser clients...) $this->protocol = new ProtocolV0($this); } // ---------------------------------------------------------- // End of protocol discovery // ---------------------------------------------------------- return true; }
/** * Parses multipart * @return void */ public function parseMultipart() { start: if ($this->frozen) { return; } if ($this->state === self::STATE_SEEKBOUNDARY) { // seek to the nearest boundary if (($p = $this->search('--' . $this->boundary . "\r\n")) === false) { return; } // we have found the nearest boundary at position $p if ($p > 0) { $extra = $this->read($p); if ($extra !== "\r\n") { $this->log('parseBody(): SEEKBOUNDARY: got unexpected data before boundary (length = ' . $p . '): ' . Debug::exportBytes($extra)); } } $this->drain(strlen($this->boundary) + 4); // drain $this->state = self::STATE_HEADERS; } if ($this->state === self::STATE_HEADERS) { // parse the part's headers $this->curPartDisp = false; $i = 0; do { $l = $this->readline(\EventBuffer::EOL_CRLF); if ($l === null) { return; } if ($l === '') { break; } $e = explode(':', $l, 2); $e[0] = strtr(strtoupper($e[0]), Generic::$htr); if (isset($e[1])) { $e[1] = ltrim($e[1]); } if ($e[0] === 'CONTENT_DISPOSITION' && isset($e[1])) { Generic::parse_str($e[1], $this->curPartDisp, true); if (!isset($this->curPartDisp['form-data'])) { break; } if (!isset($this->curPartDisp['name'])) { break; } $this->curPartDisp['name'] = trim($this->curPartDisp['name'], '"'); $name = $this->curPartDisp['name']; if (isset($this->curPartDisp['filename'])) { $this->curPartDisp['filename'] = trim($this->curPartDisp['filename'], '"'); if (!ini_get('file_uploads')) { break; } $this->req->attrs->files[$name] = ['name' => $this->curPartDisp['filename'], 'type' => '', 'tmp_name' => null, 'fp' => null, 'error' => UPLOAD_ERR_OK, 'size' => 0]; $this->curPart =& $this->req->attrs->files[$name]; $this->req->onUploadFileStart($this); $this->state = self::STATE_UPLOAD; } else { $this->curPart =& $this->req->attrs->post[$name]; $this->curPart = ''; } } elseif ($e[0] === 'CONTENT_TYPE' && isset($e[1])) { if (isset($this->curPartDisp['name']) && isset($this->curPartDisp['filename'])) { $this->curPart['type'] = $e[1]; } } } while ($i++ < 10); if ($this->state === self::STATE_HEADERS) { $this->state = self::STATE_BODY; } goto start; } if ($this->state === self::STATE_BODY || $this->state === self::STATE_UPLOAD) { // process the body $chunkEnd1 = $this->search("\r\n--" . $this->boundary . "\r\n"); $chunkEnd2 = $this->search("\r\n--" . $this->boundary . "--\r\n"); if ($chunkEnd1 === false && $chunkEnd2 === false) { /* we have only piece of Part in buffer */ $l = $this->length - strlen($this->boundary) - 8; if ($l <= 0) { return; } if ($this->state === self::STATE_BODY && isset($this->curPartDisp['name'])) { $this->curPart .= $this->read($l); } elseif ($this->state === self::STATE_UPLOAD && isset($this->curPartDisp['filename'])) { $this->curPart['size'] += $l; if ($this->req->getUploadMaxSize() < $this->curPart['size']) { $this->curPart['error'] = UPLOAD_ERR_INI_SIZE; $this->req->header('413 Request Entity Too Large'); $this->req->out(''); $this->req->finish(); } elseif ($this->maxFileSize && $this->maxFileSize < $this->curPart['size']) { $this->curPart['error'] = UPLOAD_ERR_FORM_SIZE; $this->req->header('413 Request Entity Too Large'); $this->req->out(''); $this->req->finish(); } else { $this->curChunkSize = $l; $this->req->onUploadFileChunk($this); } } } else { /* we have entire Part in buffer */ if ($chunkEnd1 === false) { $l = $chunkEnd2; $endOfMsg = true; } else { $l = $chunkEnd1; $endOfMsg = false; } if ($this->state === self::STATE_BODY && isset($this->curPartDisp['name'])) { $this->curPart .= $this->read($l); if ($this->curPartDisp['name'] === 'MAX_FILE_SIZE') { $this->maxFileSize = (int) $this->curPart; } } elseif ($this->state === self::STATE_UPLOAD && isset($this->curPartDisp['filename'])) { $this->curPart['size'] += $l; $this->curChunkSize = $l; $this->req->onUploadFileChunk($this, true); } $this->state = self::STATE_SEEKBOUNDARY; if ($endOfMsg) { // end of whole message $this->sendEOF(); } else { goto start; // let's read the next part } } } }
/** * On finish * @return void */ public function onFinish() { $this->appInstance->unsubscribe('s2c:' . $this->sessId, [$this, 's2c']); $this->appInstance->unsubscribe('w8in:' . $this->sessId, [$this, 'w8in']); Timer::remove($this->heartbeatTimer); if ($this->heartbeatOnFinish) { $this->sendFrame('h'); } parent::onFinish(); }
/** * Get cookie by name * @param string $name Name of cookie * @return string Contents */ protected function getCookieStr($name) { return \PHPDaemon\HTTPRequest\Generic::getString($this->attrs->cookie[$name]); }