diff --git a/.travis.yml b/.travis.yml index 2582b2c..9fddda0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,11 @@ notifications: sudo: false +addons: + apt: + packages: + - stunnel4 + language: php php: diff --git a/src/Net/Http/HttpConnector.php b/src/Net/Http/HttpConnector.php index b7462a6..b6adc06 100644 --- a/src/Net/Http/HttpConnector.php +++ b/src/Net/Http/HttpConnector.php @@ -59,6 +59,10 @@ public function fetchFreshData($source, EncapsulatedOptions $options = null) $this->options->extractHttpContextOptions(), $options ? $options->extractHttpContextOptions() : [] ), + 'ssl' => [ + 'verify_peer' => false, + 'verify_peer_name' => false, + ], ]) )) { $error = error_get_last(); diff --git a/test/Functional/Porter/Net/Http/HttpConnectorTest.php b/test/Functional/Porter/Net/Http/HttpConnectorTest.php index 277c7dd..2bfc57a 100644 --- a/test/Functional/Porter/Net/Http/HttpConnectorTest.php +++ b/test/Functional/Porter/Net/Http/HttpConnectorTest.php @@ -12,6 +12,7 @@ final class HttpConnectorTest extends \PHPUnit_Framework_TestCase { const HOST = '[::1]:12345'; + const SSL_HOST = '[::1]:6666'; const URI = '/test?baz=qux'; private static $dir; @@ -33,12 +34,26 @@ public function testConnectionToLocalWebserver() { $server = $this->startServer('feedback'); $response = $this->fetch(new HttpConnector((new HttpOptions)->addHeader($header = 'Foo: Bar'))); - $this->stopServer($server); + $server->stop(); self::assertRegExp('[\AGET \Q' . self::HOST . self::URI . '\E HTTP/\d+\.\d+$]m', $response); self::assertRegExp("[^$header$]m", $response); } + /** + * @requires OS Linux + */ + public function testSslConnectionToLocalWebserver() + { + $this->startSsl(); + $server = $this->startServer('feedback'); + $response = $this->fetchViaSsl(); + $server->stop(); + $this->stopSsl(); + + self::assertRegExp('[\AGET \Q' . self::SSL_HOST . '\E/ HTTP/\d+\.\d+$]m', $response); + } + public function testConnectionTimeout() { $this->setExpectedException(HttpConnectionException::class); @@ -59,7 +74,7 @@ public function testErrorResponse() throw $exception; } finally { - $this->stopServer($server); + $server->stop(); } } @@ -70,15 +85,16 @@ public function testErrorResponse() */ private function startServer($script) { - $server = ( - new Process(sprintf( + $server = new Process( + sprintf( '%sphp -S %s %s.php', // Prevent forking on some Unix systems. file_exists('/bin/sh') ? 'exec ' : '', self::HOST, $script - )) - )->setWorkingDirectory(self::$dir); + ), + self::$dir + ); $server->start(); // Wait for server to spawn. @@ -86,7 +102,7 @@ private function startServer($script) $this->fetch(); }, function (\Exception $exception) { static $handler; - $handler = $handler ?: new ExponentialBackoffExceptionHandler(); + $handler = $handler ?: new ExponentialBackoffExceptionHandler; if (!$exception instanceof HttpConnectionException) { return false; @@ -98,9 +114,35 @@ private function startServer($script) return $server; } - private function stopServer(Process $server) + private function startSsl() { - $server->stop(); + $accept = strtr(self::SSL_HOST, $filter = ['[' => '', ']' => '']); + $connect = strtr(self::HOST, $filter); + $temp = tempnam(sys_get_temp_dir(), 'Porter'); + + // Generate SSL certificate. + `yes '' | openssl req -new -x509 -nodes -keyout '$temp' -out '$temp'`; + + $ssl = new Process( + "{ stunnel4 -fd 0 || stunnel -fd 0; } <<. + # Disable PID to run as non-root user. + pid= + # Must run as foreground process on Travis, for some reason. + foreground=yes + + [] + cert=$temp + accept=$accept + connect=$connect +."); + $ssl->start(); + + return $ssl; + } + + private function stopSsl() + { + `pkill stunnel`; } private function fetch(Connector $connector = null) @@ -109,4 +151,9 @@ private function fetch(Connector $connector = null) return $connector->fetch('http://' . self::HOST . self::URI); } + + private function fetchViaSsl() + { + return $this->connector->fetch('https://' . self::SSL_HOST); + } }