From 28bb78132445cbccbffac373a3bfa3b974eb876f Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 26 Feb 2014 15:51:06 +0100 Subject: [PATCH 1/2] Capture response bodies in exceptions when http requests fail --- .../Downloader/TransportException.php | 11 +++++++++ src/Composer/Util/RemoteFilesystem.php | 24 ++++++++++++------- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/Composer/Downloader/TransportException.php b/src/Composer/Downloader/TransportException.php index b28f8d470..2e4b42f01 100644 --- a/src/Composer/Downloader/TransportException.php +++ b/src/Composer/Downloader/TransportException.php @@ -18,6 +18,7 @@ namespace Composer\Downloader; class TransportException extends \RuntimeException { protected $headers; + protected $response; public function setHeaders($headers) { @@ -28,4 +29,14 @@ class TransportException extends \RuntimeException { return $this->headers; } + + public function setResponse($response) + { + $this->response = $response; + } + + public function getResponse() + { + return $this->response; + } } diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php index d3ecec03d..68c76f341 100644 --- a/src/Composer/Util/RemoteFilesystem.php +++ b/src/Composer/Util/RemoteFilesystem.php @@ -124,6 +124,9 @@ class RemoteFilesystem $fileUrl .= (false === strpos($fileUrl, '?') ? '?' : '&') . 'access_token='.$options['github-token']; unset($options['github-token']); } + if (isset($options['http'])) { + $options['http']['ignore_errors'] = true; + } $ctx = StreamContextFactory::getContext($fileUrl, $options, array('notification' => array($this, 'callbackGet'))); if ($this->progress) { @@ -145,6 +148,10 @@ class RemoteFilesystem if ($e instanceof TransportException && !empty($http_response_header[0])) { $e->setHeaders($http_response_header); } + if ($e instanceof TransportException && $result !== false) { + $e->setResponse($result); + } + $result = false; } if ($errorMessage && !ini_get('allow_url_fopen')) { $errorMessage = 'allow_url_fopen must be enabled in php.ini ('.$errorMessage.')'; @@ -154,10 +161,16 @@ class RemoteFilesystem throw $e; } - // fix for 5.4.0 https://bugs.php.net/bug.php?id=61336 + // fail 4xx and 5xx responses and capture the response if (!empty($http_response_header[0]) && preg_match('{^HTTP/\S+ ([45]\d\d)}i', $http_response_header[0], $match)) { - $result = false; $errorCode = $match[1]; + if (!$this->retry) { + $e = new TransportException('The "'.$this->fileUrl.'" file could not be downloaded ('.$http_response_header[0].')', $errorCode); + $e->setHeaders($http_response_header); + $e->setResponse($result); + throw $e; + } + $result = false; } // decode gzip @@ -250,12 +263,7 @@ class RemoteFilesystem $this->promptAuthAndRetry(); break; } - - if ($notificationCode === STREAM_NOTIFY_AUTH_REQUIRED) { - break; - } - - throw new TransportException('The "'.$this->fileUrl.'" file could not be downloaded ('.trim($message).')', $messageCode); + break; case STREAM_NOTIFY_AUTH_RESULT: if (403 === $messageCode) { From 5067d76dbc60f26992da4402c3f21af91bd4b57a Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 26 Feb 2014 16:01:31 +0100 Subject: [PATCH 2/2] Adjust test suite --- tests/Composer/Test/Util/RemoteFilesystemTest.php | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/tests/Composer/Test/Util/RemoteFilesystemTest.php b/tests/Composer/Test/Util/RemoteFilesystemTest.php index eabfe9ed5..92aa60630 100644 --- a/tests/Composer/Test/Util/RemoteFilesystemTest.php +++ b/tests/Composer/Test/Util/RemoteFilesystemTest.php @@ -130,18 +130,11 @@ class RemoteFilesystemTest extends \PHPUnit_Framework_TestCase $this->assertAttributeEquals(50, 'lastProgress', $fs); } - public function testCallbackGetNotifyFailure404() + public function testCallbackGetPassesThrough404() { $fs = new RemoteFilesystem($this->getMock('Composer\IO\IOInterface')); - try { - $this->callCallbackGet($fs, STREAM_NOTIFY_FAILURE, 0, 'HTTP/1.1 404 Not Found', 404, 0, 0); - $this->fail(); - } catch (\Exception $e) { - $this->assertInstanceOf('Composer\Downloader\TransportException', $e); - $this->assertEquals(404, $e->getCode()); - $this->assertContains('HTTP/1.1 404 Not Found', $e->getMessage()); - } + $this->assertNull($this->callCallbackGet($fs, STREAM_NOTIFY_FAILURE, 0, 'HTTP/1.1 404 Not Found', 404, 0, 0)); } public function testCaptureAuthenticationParamsFromUrl()