/** * @param \swoole_server $serv * @param $fd * @param $from_id * @param $data */ function onReceive($serv, $fd, $from_id, $data) { $parser = new \HttpParser(); if (empty($this->buffers[$fd])) { $this->clearBuffer($fd); } $this->buffers[$fd] .= $data; $buffer =& $this->buffers[$fd]; $nparsed =& $this->nparsed[$fd]; $nparsed = $parser->execute($buffer, $nparsed); if ($parser->hasError()) { $serv->close($fd, $from_id); } else { if ($parser->isFinished()) { $this->clearBuffer($fd); $_SERVER = $parser->getEnvironment(); $_GET = array(); if (!empty($_SERVER['QUERY_STRING'])) { parse_str($_SERVER['QUERY_STRING'], $_GET); } if (!empty($_SERVER['REQUEST_BODY'])) { parse_str($_SERVER['REQUEST_BODY'], $_POST); } if (!empty($_SERVER['HTTP_COOKIE'])) { $_COOKIE = self::parseCookie($_SERVER['HTTP_COOKIE']); } $this->currentFd = $fd; call_user_func($this->_onRequest, $this); } } }
public function run(Promise &$promise) { $cli = new \swoole_client(SWOOLE_TCP, SWOOLE_SOCK_ASYNC); $urlInfo = parse_url($this->url); $timeout = $this->timeout; if (!isset($urlInfo['port'])) { $urlInfo['port'] = 80; } $httpParser = new \HttpParser(); $cli->on("connect", function ($cli) use($urlInfo, &$timeout, &$promise) { $cli->isConnected = true; $host = $urlInfo['host']; if ($urlInfo['port']) { $host .= ':' . $urlInfo['port']; } $req = array(); $req[] = "GET {$this->url} HTTP/1.1\r\n"; $req[] = "User-Agent: PHP swAsync\r\n"; $req[] = "Host:{$host}\r\n"; $req[] = "Connection:close\r\n"; $req[] = "\r\n"; $req = implode('', $req); $cli->send($req); }); $cli->on("receive", function ($cli, $data = "") use(&$httpParser, &$promise) { $ret = $httpParser->execute($data); if ($ret !== false) { Timer::del($cli->sock); $cli->isDone = true; if ($cli->isConnected()) { $cli->close(); } $promise->accept(['http_data' => $ret]); } }); $cli->on("error", function ($cli) use(&$promise) { Timer::del($cli->sock); $promise->accept(['http_data' => null, 'http_error' => 'Connect error']); }); $cli->on("close", function ($cli) use(&$promise) { }); if ($this->proxy) { $cli->connect($this->proxy['host'], $this->proxy['port'], 0.05); } else { $cli->connect($urlInfo['host'], $urlInfo['port'], 0.05); } $cli->isConnected = false; if (!$cli->errCode) { Timer::add($cli->sock, $this->timeout, function () use($cli, &$promise) { @$cli->close(); if ($cli->isConnected) { $promise->accept(['http_data' => null, 'http_error' => 'Http client read timeout']); } else { $promise->accept(['http_data' => null, 'http_error' => 'Http client connect timeout']); } }); } }
/** * Start serving requests to the application * @param callable */ public function start($app) { if (!($socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP))) { throw new Exception(socket_strerror(socket_last_error())); } if (!socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1)) { throw new Exception(socket_strerror(socket_last_error())); } if (!socket_bind($socket, $this->_host, $this->_port)) { throw new Exception(socket_strerror(socket_last_error())); } if (!socket_listen($socket)) { throw new Exception(socket_strerror(socket_last_error())); } while ($client = socket_accept($socket)) { $data = ''; $nparsed = 0; $h = new \HttpParser(); while ($d = socket_read($client, 1024 * 1024 * 1024)) { $data .= $d; $nparsed = $h->execute($data, $nparsed); if ($h->isFinished()) { break; } if ($h->hasError()) { socket_close($client); continue 2; // Skip to accept next connection.. } } $env = $h->getEnvironment(); global $argv; $env['SERVER_NAME'] = $this->_host; $env['SERVER_PORT'] = $this->_port; $env['SCRIPT_FILENAME'] = $argv[0]; socket_getpeername($client, $address); $env['REMOTE_ADDR'] = $address; list($status, $headers, $body) = call_user_func($app, $env); $response = new Response(); $response->setStatus($status); $response->setHeaders($headers); $response->setBody($body); foreach ($response as $chunk) { $len = strlen($chunk); $offset = 0; while ($offset < $len) { if (false === ($n = @socket_write($client, substr($chunk, $offset), $len - $offset))) { break 2; } $offset += $n; } } socket_close($client); } }
private function merge(MapInterface $http, MapInterface $html) : MapInterface { if (!$http->contains(HttpParser::key())) { return $html; } if (!$html->contains(HtmlParser::key())) { return $http; } return $http->put(self::key(), $http->get(HttpParser::key())->merge($html->get(HtmlParser::key()))); }
private function _child($socket, $app) { while ($client = socket_accept($socket)) { $data = ''; $nparsed = 0; $h = new HttpParser(); while ($d = socket_read($client, 1024 * 1024)) { $data .= $d; $nparsed = $h->execute($data, $nparsed); if ($h->isFinished()) { break; } if ($h->hasError()) { socket_close($client); continue 2; // } } $env = $h->getEnvironment(); $result = $app->call($env); $response = new Kelpie_Server_Response(); $response->setStatus($result[0]); $response->setHeaders($result[1]); $response->setBody($result[2]); foreach ($response as $chunk) { $len = strlen($chunk); $offset = 0; while ($offset < $len) { if (false === ($n = @socket_write($client, substr($chunk, $offset), $len - $offset))) { break 2; } $offset += $n; } } socket_close($client); } }
public function readRequest($stream) { $this->stream = $stream; $_headers_str = stream_get_line($this->stream, 0, "\r\n\r\n"); if (extension_loaded('httpparser')) { $parser = new \HttpParser(); $parser->execute($_headers_str, 0); $this->headers = $parser->getEnvironment(); unset($parser); } else { // native parsing // TODO: implement support for multiline headers (see http-spec for details) $_headers = explode("\r\n", $_headers_str); // getting headers list($http_method, $url, $http_version) = sscanf(array_shift($_headers), "%s %s %s"); $this->headers = array(); foreach ($_headers as $element) { $divider = strpos($element, ': '); $name = 'HTTP_' . str_replace('-', '_', strtoupper(substr($element, 0, $divider))); $value = substr($element, $divider + 2); $this->headers[$name] = $value; } unset($_headers, $first); $this->headers['HTTP_VERSION'] = $http_version; $this->headers['REQUEST_METHOD'] = $http_method; $this->headers['REQUEST_URI'] = $url; if (false === ($pos = strpos($url, '?'))) { $this->headers['PATH_INFO'] = $url; $this->headers['QUERY_STRING'] = ''; } else { $this->headers['PATH_INFO'] = substr($url, 0, $pos); $this->headers['QUERY_STRING'] = strval(substr($url, $pos + 1)); } } $this->headers['SERVER_SOFTWARE'] = 'appserver-in-php'; $this->headers['GATEWAY_INTERFACE'] = 'CGI/1.1'; $this->headers['SCRIPT_NAME'] = ''; if (isset($this->headers['HTTP_HOST'])) { if (false === ($pos = strpos($this->headers['HTTP_HOST'], ':'))) { $host = $this->headers['HTTP_HOST']; $port = 80; } else { $host = substr($this->headers['HTTP_HOST'], 0, $pos); $port = substr($this->headers['HTTP_HOST'], $pos + 1); } $this->headers['SERVER_NAME'] = $host; $this->headers['SERVER_PORT'] = strval($port); } else { $this->headers['SERVER_NAME'] = 'localhost'; $this->headers['SERVER_PORT'] = '80'; } if (isset($this->headers['HTTP_CONTENT_TYPE'])) { $this->headers['CONTENT_TYPE'] = $this->headers['HTTP_CONTENT_TYPE']; unset($this->headers['HTTP_CONTENT_TYPE']); } if (isset($this->headers['HTTP_CONTENT_LENGTH'])) { $this->headers['CONTENT_LENGTH'] = $this->headers['HTTP_CONTENT_LENGTH']; unset($this->headers['HTTP_CONTENT_LENGTH']); } else { $this->headers['CONTENT_LENGTH'] = 0; } ksort($this->headers); }