From a268b537863f15bfb6032e60c6e969a7b740c17a Mon Sep 17 00:00:00 2001 From: Jesse Donat Date: Thu, 13 Jun 2024 10:50:03 -0500 Subject: [PATCH] Improve error handling on MockWebServer --- src/MockWebServer.php | 75 +++++++++++++++++++++++++++++++++---------- 1 file changed, 58 insertions(+), 17 deletions(-) diff --git a/src/MockWebServer.php b/src/MockWebServer.php index e3be42f..d242f98 100644 --- a/src/MockWebServer.php +++ b/src/MockWebServer.php @@ -2,6 +2,8 @@ namespace donatj\MockWebServer; +use donatj\MockWebServer\Exceptions\RuntimeException; + class MockWebServer { public const VND = 'VND.DonatStudios.MockWebServer'; @@ -190,17 +192,23 @@ private function getTmpDir() : string { $tmpPath = $tmpDir . DIRECTORY_SEPARATOR . 'MockWebServer'; if( !is_dir($tmpPath) ) { - mkdir($tmpPath); + if( !mkdir($tmpPath) && !is_dir($tmpPath) ) { + throw new \RuntimeException(sprintf('Directory "%s" was not created', $tmpPath)); + } } $tmpPath .= DIRECTORY_SEPARATOR . $this->port; if( !is_dir($tmpPath) ) { - mkdir($tmpPath); + if( !mkdir($tmpPath) && !is_dir($tmpPath) ) { + throw new \RuntimeException(sprintf('Directory "%s" was not created', $tmpPath)); + } } $tmpPath .= DIRECTORY_SEPARATOR . md5(microtime(true) . ':' . rand(0, 100000)); if( !is_dir($tmpPath) ) { - mkdir($tmpPath); + if( !mkdir($tmpPath) && !is_dir($tmpPath) ) { + throw new \RuntimeException(sprintf('Directory "%s" was not created', $tmpPath)); + } } return $tmpPath; @@ -213,6 +221,10 @@ public function getLastRequest() : ?RequestInfo { $path = $this->tmpDir . DIRECTORY_SEPARATOR . self::LAST_REQUEST_FILE; if( file_exists($path) ) { $content = file_get_contents($path); + if( $content === false ) { + throw new RuntimeException('failed to read last request'); + } + $data = @unserialize($content); if( $data instanceof RequestInfo ) { return $data; @@ -229,7 +241,7 @@ public function getLastRequest() : ?RequestInfo { * If offset is negative, the request will be that from the end of the requests. */ public function getRequestByOffset( int $offset ) : ?RequestInfo { - $reqs = glob($this->tmpDir . DIRECTORY_SEPARATOR . 'request.*'); + $reqs = glob($this->tmpDir . DIRECTORY_SEPARATOR . 'request.*') ?: []; natsort($reqs); $item = array_slice($reqs, $offset, 1); @@ -237,9 +249,17 @@ public function getRequestByOffset( int $offset ) : ?RequestInfo { return null; } - $path = reset($item); + $path = reset($item); + if( !$path ) { + return null; + } + $content = file_get_contents($path); - $data = @unserialize($content); + if( $content === false ) { + throw new RuntimeException("failed to read request from '{$path}'"); + } + + $data = @unserialize($content); if( $data instanceof RequestInfo ) { return $data; } @@ -266,10 +286,13 @@ public function getPort() : int { */ private function findOpenPort() : int { $sock = socket_create(AF_INET, SOCK_STREAM, 0); + if( $sock === false ) { + throw new RuntimeException('Failed to create socket'); + } // Bind the socket to an address/port if( !socket_bind($sock, $this->getHost(), 0) ) { - throw new Exceptions\RuntimeException('Could not bind to address'); + throw new RuntimeException('Could not bind to address'); } socket_getsockname($sock, $checkAddress, $checkPort); @@ -279,7 +302,7 @@ private function findOpenPort() : int { return $checkPort; } - throw new Exceptions\RuntimeException('Failed to find open port'); + throw new RuntimeException('Failed to find open port'); } private function isWindowsPlatform() : bool { @@ -287,7 +310,7 @@ private function isWindowsPlatform() : bool { } /** - * @return array{resource, resource[]} + * @return array{resource,array{resource,resource,resource}} */ private function startServer( string $fullCmd ) : array { if( !$this->isWindowsPlatform() ) { @@ -300,24 +323,42 @@ private function startServer( string $fullCmd ) : array { $cwd = null; $stdoutf = tempnam(sys_get_temp_dir(), 'MockWebServer.stdout'); + if( $stdoutf === false ) { + throw new RuntimeException('error creating stdout temp file'); + } + $stderrf = tempnam(sys_get_temp_dir(), 'MockWebServer.stderr'); + if( $stderrf === false ) { + throw new RuntimeException('error creating stderr temp file'); + } + + $stdin = fopen('php://stdin', 'rb'); + if( $stdin === false ) { + throw new RuntimeException('error opening stdin'); + } + + $stdout = fopen($stdoutf, 'ab'); + if( $stdout === false ) { + throw new RuntimeException('error opening stdout'); + } + + $stderr = fopen($stderrf, 'ab'); + if( $stderr === false ) { + throw new RuntimeException('error opening stderr'); + } - $descriptorSpec = [ - 0 => fopen('php://stdin', 'rb'), - 1 => fopen($stdoutf, 'a'), - 2 => fopen($stderrf, 'a'), - ]; + $descriptorSpec = [ $stdin, $stdout, $stderr ]; $process = proc_open($fullCmd, $descriptorSpec, $pipes, $cwd, $env, [ 'suppress_errors' => false, 'bypass_shell' => true, ]); - if( is_resource($process) ) { - return [ $process, $descriptorSpec ]; + if( $process === false ) { + throw new Exceptions\ServerException('Error starting server'); } - throw new Exceptions\ServerException('Error starting server'); + return [ $process, $descriptorSpec ]; } }