From 419a1cedf0ebcf190b7c27634eb87db856c87192 Mon Sep 17 00:00:00 2001 From: Maxim Chernyshev Date: Wed, 2 May 2012 08:26:27 +0800 Subject: [PATCH 1/5] Proxy credentials are now passed as part of HTTP headers --- src/Composer/Util/StreamContextFactory.php | 38 ++++++++++++++++--- .../Test/Util/StreamContextFactoryTest.php | 13 +++---- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/Composer/Util/StreamContextFactory.php b/src/Composer/Util/StreamContextFactory.php index 6541d811b..9826628e3 100644 --- a/src/Composer/Util/StreamContextFactory.php +++ b/src/Composer/Util/StreamContextFactory.php @@ -35,20 +35,48 @@ final class StreamContextFactory if (isset($_SERVER['HTTP_PROXY']) || isset($_SERVER['http_proxy'])) { // Some systems seem to rely on a lowercased version instead... $proxy = isset($_SERVER['http_proxy']) ? $_SERVER['http_proxy'] : $_SERVER['HTTP_PROXY']; - + + $proxyURL = parse_url($proxy, PHP_URL_SCHEME) . "://"; + $proxyURL .= parse_url($proxy, PHP_URL_HOST); + + $proxyPort = parse_url($proxy, PHP_URL_PORT); + + if (isset($proxyPort)) { + $proxyURL .= ":" . $proxyPort; + } + // http(s):// is not supported in proxy - $proxy = str_replace(array('http://', 'https://'), array('tcp://', 'ssl://'), $proxy); + $proxyURL = str_replace(array('http://', 'https://'), array('tcp://', 'ssl://'), $proxyURL); - if (0 === strpos($proxy, 'ssl:') && !extension_loaded('openssl')) { + if (0 === strpos($proxyURL, 'ssl:') && !extension_loaded('openssl')) { throw new \RuntimeException('You must enable the openssl extension to use a proxy over https'); } $options['http'] = array( - 'proxy' => $proxy, + 'proxy' => $proxyURL, 'request_fulluri' => true, ); + + // Extract authentication credentials from the proxy url + $user = parse_url($proxy, PHP_URL_USER); + $pass = parse_url($proxy, PHP_URL_PASS); + + if (isset($user)) { + $auth = $user; + if (isset($pass)) { + $auth .= ":{$pass}"; + } + $auth = base64_encode($auth); + + // Preserve headers if already set in default options + if (isset($defaultOptions['http']) && isset($defaultOptions['http']['header'])) { + $defaultOptions['http']['header'] .= "Proxy-Authorization: Basic {$auth}\r\n"; + } else { + $options['http']['header'] = "Proxy-Authorization: Basic {$auth}\r\n"; + } + } } - + $options = array_merge_recursive($options, $defaultOptions); return stream_context_create($options, $defaultParams); diff --git a/tests/Composer/Test/Util/StreamContextFactoryTest.php b/tests/Composer/Test/Util/StreamContextFactoryTest.php index 8429d078b..0e9928ede 100644 --- a/tests/Composer/Test/Util/StreamContextFactoryTest.php +++ b/tests/Composer/Test/Util/StreamContextFactoryTest.php @@ -57,31 +57,30 @@ class StreamContextFactoryTest extends \PHPUnit_Framework_TestCase public function testHttpProxy() { - $_SERVER['http_proxy'] = 'http://username:password@proxyserver.net:port/'; - $_SERVER['HTTP_PROXY'] = 'http://proxyserver/'; + $_SERVER['http_proxy'] = 'http://username:password@proxyserver.net:1234'; + $_SERVER['HTTP_PROXY'] = 'http://proxyserver'; $context = StreamContextFactory::getContext(array('http' => array('method' => 'GET'))); $options = stream_context_get_options($context); - $this->assertSame('http://proxyserver/', $_SERVER['HTTP_PROXY']); - $this->assertEquals(array('http' => array( - 'proxy' => 'tcp://username:password@proxyserver.net:port/', + 'proxy' => 'tcp://proxyserver.net:1234', 'request_fulluri' => true, 'method' => 'GET', + 'header' => "Proxy-Authorization: Basic " . base64_encode('username:password') . "\r\n" )), $options); } public function testSSLProxy() { - $_SERVER['http_proxy'] = 'https://proxyserver/'; + $_SERVER['http_proxy'] = 'https://proxyserver'; if (extension_loaded('openssl')) { $context = StreamContextFactory::getContext(); $options = stream_context_get_options($context); $this->assertSame(array('http' => array( - 'proxy' => 'ssl://proxyserver/', + 'proxy' => 'ssl://proxyserver', 'request_fulluri' => true, )), $options); } else { From 8918551f297ef28f407646a225e02477f253d186 Mon Sep 17 00:00:00 2001 From: Maxim Chernyshev Date: Wed, 2 May 2012 09:22:59 +0800 Subject: [PATCH 2/5] Simplified proxy port determination and passed tests --- src/Composer/Util/StreamContextFactory.php | 14 ++++++++------ .../Test/Util/StreamContextFactoryTest.php | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Composer/Util/StreamContextFactory.php b/src/Composer/Util/StreamContextFactory.php index 384ff79dd..04561670e 100644 --- a/src/Composer/Util/StreamContextFactory.php +++ b/src/Composer/Util/StreamContextFactory.php @@ -43,17 +43,19 @@ final class StreamContextFactory if (isset($proxyPort)) { $proxyURL .= ":" . $proxyPort; + } else { + if ('http://' == substr($proxyURL, 0, 7)) { + $proxyURL .= ":80"; + } else if ('https://' == substr($proxyURL, 0, 8)) { + $proxyURL .= ":443"; + } } // http(s):// is not supported in proxy - if ('http://' == substr($proxy, 0, 7)) { - $proxy = 'tcp://' . rtrim(substr($proxy, 7), '/') . (parse_url($proxy, PHP_URL_PORT) ? '' : ':80'); - } else if ('https://' == substr($proxy, 0, 8)) { - $proxy = 'ssl://' . rtrim(substr($proxy, 8), '/') . (parse_url($proxy, PHP_URL_PORT) ? '' : ':443'); - } + $proxyURL = str_replace(array('http://', 'https://'), array('tcp://', 'ssl://'), $proxyURL); if (0 === strpos($proxyURL, 'ssl:') && !extension_loaded('openssl')) { - throw new \RuntimeException('You must enable the openssl extension to use a proxy over https'); + throw new \RuntimeException('You must enable the openssl extension to use a proxy over https'); } $options['http'] = array( diff --git a/tests/Composer/Test/Util/StreamContextFactoryTest.php b/tests/Composer/Test/Util/StreamContextFactoryTest.php index b50c0cef8..d39fbe340 100644 --- a/tests/Composer/Test/Util/StreamContextFactoryTest.php +++ b/tests/Composer/Test/Util/StreamContextFactoryTest.php @@ -97,7 +97,7 @@ class StreamContextFactoryTest extends \PHPUnit_Framework_TestCase $context = StreamContextFactory::getContext(); $options = stream_context_get_options($context); - $this->assertEquals(array('http' => array( + $this->assertEquals(array('http' => array( 'proxy' => $expected, 'request_fulluri' => true, )), $options); From 37476eb61f2cba5a557e2200da67dddf683a3ed4 Mon Sep 17 00:00:00 2001 From: Maxim Chernyshev Date: Wed, 2 May 2012 09:30:27 +0800 Subject: [PATCH 3/5] Fixed indentation --- src/Composer/Util/StreamContextFactory.php | 38 +++++++++---------- .../Test/Util/StreamContextFactoryTest.php | 4 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/Composer/Util/StreamContextFactory.php b/src/Composer/Util/StreamContextFactory.php index 04561670e..0cc591484 100644 --- a/src/Composer/Util/StreamContextFactory.php +++ b/src/Composer/Util/StreamContextFactory.php @@ -42,20 +42,20 @@ final class StreamContextFactory $proxyPort = parse_url($proxy, PHP_URL_PORT); if (isset($proxyPort)) { - $proxyURL .= ":" . $proxyPort; + $proxyURL .= ":" . $proxyPort; } else { - if ('http://' == substr($proxyURL, 0, 7)) { - $proxyURL .= ":80"; - } else if ('https://' == substr($proxyURL, 0, 8)) { - $proxyURL .= ":443"; - } + if ('http://' == substr($proxyURL, 0, 7)) { + $proxyURL .= ":80"; + } else if ('https://' == substr($proxyURL, 0, 8)) { + $proxyURL .= ":443"; + } } // http(s):// is not supported in proxy $proxyURL = str_replace(array('http://', 'https://'), array('tcp://', 'ssl://'), $proxyURL); if (0 === strpos($proxyURL, 'ssl:') && !extension_loaded('openssl')) { - throw new \RuntimeException('You must enable the openssl extension to use a proxy over https'); + throw new \RuntimeException('You must enable the openssl extension to use a proxy over https'); } $options['http'] = array( @@ -68,18 +68,18 @@ final class StreamContextFactory $pass = parse_url($proxy, PHP_URL_PASS); if (isset($user)) { - $auth = $user; - if (isset($pass)) { - $auth .= ":{$pass}"; - } - $auth = base64_encode($auth); - - // Preserve headers if already set in default options - if (isset($defaultOptions['http']) && isset($defaultOptions['http']['header'])) { - $defaultOptions['http']['header'] .= "Proxy-Authorization: Basic {$auth}\r\n"; - } else { - $options['http']['header'] = "Proxy-Authorization: Basic {$auth}\r\n"; - } + $auth = $user; + if (isset($pass)) { + $auth .= ":{$pass}"; + } + $auth = base64_encode($auth); + + // Preserve headers if already set in default options + if (isset($defaultOptions['http']) && isset($defaultOptions['http']['header'])) { + $defaultOptions['http']['header'] .= "Proxy-Authorization: Basic {$auth}\r\n"; + } else { + $options['http']['header'] = "Proxy-Authorization: Basic {$auth}\r\n"; + } } } diff --git a/tests/Composer/Test/Util/StreamContextFactoryTest.php b/tests/Composer/Test/Util/StreamContextFactoryTest.php index d39fbe340..7fa74e0d9 100644 --- a/tests/Composer/Test/Util/StreamContextFactoryTest.php +++ b/tests/Composer/Test/Util/StreamContextFactoryTest.php @@ -96,8 +96,8 @@ class StreamContextFactoryTest extends \PHPUnit_Framework_TestCase if (extension_loaded('openssl')) { $context = StreamContextFactory::getContext(); $options = stream_context_get_options($context); - - $this->assertEquals(array('http' => array( + + $this->assertEquals(array('http' => array( 'proxy' => $expected, 'request_fulluri' => true, )), $options); From 1ae0a1b7af21b7b07db0ec952b8599ba84915d9e Mon Sep 17 00:00:00 2001 From: Maxim Chernyshev Date: Wed, 2 May 2012 15:16:36 +0800 Subject: [PATCH 4/5] Follow-up coding standard fixes --- src/Composer/Util/StreamContextFactory.php | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Composer/Util/StreamContextFactory.php b/src/Composer/Util/StreamContextFactory.php index 0cc591484..c0e6a5f25 100644 --- a/src/Composer/Util/StreamContextFactory.php +++ b/src/Composer/Util/StreamContextFactory.php @@ -43,12 +43,10 @@ final class StreamContextFactory if (isset($proxyPort)) { $proxyURL .= ":" . $proxyPort; - } else { - if ('http://' == substr($proxyURL, 0, 7)) { - $proxyURL .= ":80"; - } else if ('https://' == substr($proxyURL, 0, 8)) { - $proxyURL .= ":443"; - } + } else if ('http://' == substr($proxyURL, 0, 7)) { + $proxyURL .= ":80"; + } else if ('https://' == substr($proxyURL, 0, 8)) { + $proxyURL .= ":443"; } // http(s):// is not supported in proxy @@ -75,14 +73,13 @@ final class StreamContextFactory $auth = base64_encode($auth); // Preserve headers if already set in default options - if (isset($defaultOptions['http']) && isset($defaultOptions['http']['header'])) { + if (isset($defaultOptions['http']['header'])) { $defaultOptions['http']['header'] .= "Proxy-Authorization: Basic {$auth}\r\n"; } else { $options['http']['header'] = "Proxy-Authorization: Basic {$auth}\r\n"; } } } - $options = array_merge_recursive($options, $defaultOptions); return stream_context_create($options, $defaultParams); From 5294cb222cd7b8cae17ac6a98a70534410eb8b12 Mon Sep 17 00:00:00 2001 From: Maxim Chernyshev Date: Wed, 2 May 2012 17:21:58 +0800 Subject: [PATCH 5/5] Precious community feedback-based refactoring --- src/Composer/Util/StreamContextFactory.php | 45 +++++++++---------- .../Test/Util/StreamContextFactoryTest.php | 2 +- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/Composer/Util/StreamContextFactory.php b/src/Composer/Util/StreamContextFactory.php index c0e6a5f25..df61b3c3e 100644 --- a/src/Composer/Util/StreamContextFactory.php +++ b/src/Composer/Util/StreamContextFactory.php @@ -34,21 +34,23 @@ final class StreamContextFactory // Handle system proxy if (isset($_SERVER['HTTP_PROXY']) || isset($_SERVER['http_proxy'])) { // Some systems seem to rely on a lowercased version instead... - $proxy = isset($_SERVER['http_proxy']) ? $_SERVER['http_proxy'] : $_SERVER['HTTP_PROXY']; - - $proxyURL = parse_url($proxy, PHP_URL_SCHEME) . "://"; - $proxyURL .= parse_url($proxy, PHP_URL_HOST); - - $proxyPort = parse_url($proxy, PHP_URL_PORT); - - if (isset($proxyPort)) { - $proxyURL .= ":" . $proxyPort; - } else if ('http://' == substr($proxyURL, 0, 7)) { + $proxy = parse_url(isset($_SERVER['http_proxy']) ? $_SERVER['http_proxy'] : $_SERVER['HTTP_PROXY']); + } else { + $proxy = false; + } + + if (false !== $proxy) { + $proxyURL = (isset($proxy['scheme']) ? $proxy['scheme'] : '') . '://'; + $proxyURL .= isset($proxy['host']) ? $proxy['host'] : ''; + + if (isset($proxy['port'])) { + $proxyURL .= ":" . $proxy['port']; + } elseif ('http://' == substr($proxyURL, 0, 7)) { $proxyURL .= ":80"; - } else if ('https://' == substr($proxyURL, 0, 8)) { + } elseif ('https://' == substr($proxyURL, 0, 8)) { $proxyURL .= ":443"; } - + // http(s):// is not supported in proxy $proxyURL = str_replace(array('http://', 'https://'), array('tcp://', 'ssl://'), $proxyURL); @@ -60,18 +62,14 @@ final class StreamContextFactory 'proxy' => $proxyURL, 'request_fulluri' => true, ); - - // Extract authentication credentials from the proxy url - $user = parse_url($proxy, PHP_URL_USER); - $pass = parse_url($proxy, PHP_URL_PASS); - - if (isset($user)) { - $auth = $user; - if (isset($pass)) { - $auth .= ":{$pass}"; + + if (isset($proxy['user'])) { + $auth = $proxy['user']; + if (isset($proxy['pass'])) { + $auth .= ':' . $proxy['pass']; } $auth = base64_encode($auth); - + // Preserve headers if already set in default options if (isset($defaultOptions['http']['header'])) { $defaultOptions['http']['header'] .= "Proxy-Authorization: Basic {$auth}\r\n"; @@ -80,8 +78,9 @@ final class StreamContextFactory } } } + $options = array_merge_recursive($options, $defaultOptions); - + return stream_context_create($options, $defaultParams); } } diff --git a/tests/Composer/Test/Util/StreamContextFactoryTest.php b/tests/Composer/Test/Util/StreamContextFactoryTest.php index 7fa74e0d9..dc60fe3bb 100644 --- a/tests/Composer/Test/Util/StreamContextFactoryTest.php +++ b/tests/Composer/Test/Util/StreamContextFactoryTest.php @@ -96,7 +96,7 @@ class StreamContextFactoryTest extends \PHPUnit_Framework_TestCase if (extension_loaded('openssl')) { $context = StreamContextFactory::getContext(); $options = stream_context_get_options($context); - + $this->assertEquals(array('http' => array( 'proxy' => $expected, 'request_fulluri' => true,