💾 Archived View for code.lanterne.chilliet.eu › vendor › mcmic › gemini-server › src › Server.php captured on 2021-12-17 at 13:26:06.
-=-=-=-=-=-=-
<?php declare(strict_types=1); namespace MCMic\Gemini; use Psr\Log; class Server { protected string $transport = 'tcp'; protected int $port = 1965; protected RequestLogger $requestLogger; /** * @var array<string,RequestHandler> */ protected array $handlers; public function __construct(int $port = 1965, ?RequestLogger $logger = null) { $this->port = $port; $this->requestLogger = ($logger ?? new RequestLogger()); } public function addHandler(RequestHandler $handler): void { $key = \idn_to_ascii($handler->host); if ($key === false) { throw new \Exception('Failed to punycode IDN'); } $this->handlers[$key] = $handler; } public function serve(): void { $context = stream_context_create( [ 'ssl' => [ 'verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true, 'verify_depth' => 0, 'SNI_enabled' => true, 'SNI_server_certs' => array_map( function (RequestHandler $handler): string { return $handler->certPath; }, $this->handlers ), //~ If set to true a peer_certificate context option will be created containing the peer certificate. 'capture_peer_cert' => true, ] ] ); $socket = stream_socket_server( $this->transport . '://[::]:' . $this->port, $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $context, ); if ($socket === false) { throw new \Exception($errstr, $errno); } else { $this->requestLogger->logger->info('Listening…'); while ($conn = stream_socket_accept($socket, -1, $peername)) { /* Enable TLS, any method but 1.0/1.1, meaning 1.2, and 1.3 if available in the PHP version */ $tlsSuccess = stream_socket_enable_crypto( $conn, true, STREAM_CRYPTO_METHOD_TLS_SERVER & ~STREAM_CRYPTO_METHOD_TLSv1_0_SERVER & ~STREAM_CRYPTO_METHOD_TLSv1_1_SERVER ); if ($tlsSuccess !== true) { fclose($conn); continue; } //~ print_r(stream_context_get_options($conn)); $requestString = fread($conn, 1024); try { if ($requestString === false) { $this->requestLogger->logRequest($peername, ''); throw new Exception('Bad request', 50); } $this->requestLogger->logRequest($peername, $requestString); $request = new Request($requestString); $request->assertValid(); if (isset($this->handlers[$request->punycodedHost])) { $response = $this->handlers[$request->punycodedHost]->handleWrapper($request); fwrite($conn, (string)$response); $this->requestLogger->logResponse($peername, $request, $response); } else { throw new Exception('Bad hostname', 50); } } catch (Exception $e) { fwrite($conn, (string)$e); if (isset($request)) { $this->requestLogger->logException($peername, $request, $e); } elseif (is_string($requestString)) { $this->requestLogger->logException($peername, $requestString, $e); } else { $this->requestLogger->logException($peername, '', $e); } } fclose($conn); } fclose($socket); } } }