connectionManager = $connectionManager; $this->configuration = $configuration; $this->statisticsCollector = $statisticsCollector; } public function handle(Request $request, ConnectionInterface $httpConnection) { $subdomain = $this->detectSubdomain($request); $serverHost = $this->detectServerHost($request); if (is_null($subdomain)) { $httpConnection->send( respond_html($this->getView($httpConnection, 'server.homepage'), 200) ); $httpConnection->close(); return; } $controlConnection = $this->connectionManager->findControlConnectionForSubdomainAndServerHost($subdomain, $serverHost); if (is_null($controlConnection)) { $httpConnection->send( respond_html($this->getView($httpConnection, 'server.errors.404', ['subdomain' => $subdomain]), 404) ); $httpConnection->close(); return; } $this->statisticsCollector->incomingRequest(); $this->sendRequestToClient($request, $controlConnection, $httpConnection); } protected function detectSubdomain(Request $request): ?string { $subdomain = Str::before($request->header('Host'), '.'); return $subdomain === $request->header('Host') ? null : $subdomain; } protected function detectServerHost(Request $request): ?string { return Str::after($request->header('Host'), '.'); } protected function sendRequestToClient(Request $request, ControlConnection $controlConnection, ConnectionInterface $httpConnection) { $request = $this->prepareRequest($request, $controlConnection); $requestId = $request->header('X-Expose-Request-ID'); $httpConnection = $this->connectionManager->storeHttpConnection($httpConnection, $requestId); transform($this->passRequestThroughModifiers($request, $httpConnection), function (Request $request) use ($controlConnection, $requestId) { $controlConnection->once('proxy_ready_'.$requestId, function (ConnectionInterface $proxy) use ($request) { // Convert the Laravel request into a PSR7 request $psr17Factory = new Psr17Factory(); $psrHttpFactory = new PsrHttpFactory($psr17Factory, $psr17Factory, $psr17Factory, $psr17Factory); $request = $psrHttpFactory->createRequest($request); $binaryMsg = new Frame(str($request), true, Frame::OP_BINARY); $proxy->send($binaryMsg); }); $controlConnection->registerProxy($requestId); }); } protected function passRequestThroughModifiers(Request $request, HttpConnection $httpConnection): ?Request { foreach ($this->modifiers as $modifier) { $request = app($modifier)->handle($request, $httpConnection); if (is_null($request)) { break; } } return $request; } protected function prepareRequest(Request $request, ControlConnection $controlConnection): Request { $request::setTrustedProxies([$controlConnection->socket->remoteAddress, '127.0.0.1'], Request::HEADER_X_FORWARDED_ALL); $host = $controlConnection->serverHost; if (! $request->isSecure()) { $host .= ":{$this->configuration->port()}"; } $request->headers->set('Host', $controlConnection->host); $request->headers->set('X-Forwarded-Proto', $request->isSecure() ? 'https' : 'http'); $request->headers->set('X-Expose-Request-ID', uniqid()); $request->headers->set('Upgrade-Insecure-Requests', 1); $request->headers->set('X-Exposed-By', config('app.name').' '.config('app.version')); $request->headers->set('X-Original-Host', "{$controlConnection->subdomain}.{$host}"); $request->headers->set('X-Forwarded-Host', "{$controlConnection->subdomain}.{$host}"); return $request; } }