From d128b03d14a4855f2d858f5422c22690358df267 Mon Sep 17 00:00:00 2001 From: robocoder <anthon.pang@gmail.com> Date: Sat, 21 May 2011 04:38:42 +0000 Subject: [PATCH] fixes #2441, fixes #1869 git-svn-id: http://dev.piwik.org/svn/trunk@4738 59fd770c-687e-43c8-a1e3-f5a4ff64c105 --- config/global.ini.php | 7 +++ core/Http.php | 98 +++++++++++++++++++++++++++++++++++----- tests/core/Http.test.php | 2 +- 3 files changed, 94 insertions(+), 13 deletions(-) diff --git a/config/global.ini.php b/config/global.ini.php index 495c9ccfc3..7e148a99b6 100644 --- a/config/global.ini.php +++ b/config/global.ini.php @@ -349,6 +349,13 @@ username = ; SMTP username password = ; SMTP password encryption = ; SMTP transport-layer encryption, either 'ssl', 'tls', or empty (i.e., none). +[proxy] +type = BASIC ; proxy type for outbound/outgoing connections; currently, only BASIC is supported +host = ; check your proxy configuration +port = ; there is no standard default, but 80, 1080, 3128, and 8080 are popular +username = ; if specified, password is mandatory +password = ; if specified, username is mandatory + [log] ;possible values for log: screen, database, file ; by default, standard logging/debug messages are hidden from screen diff --git a/core/Http.php b/core/Http.php index 8abde2605b..35d4eb9610 100644 --- a/core/Http.php +++ b/core/Http.php @@ -95,6 +95,36 @@ class Piwik_Http $contentLength = 0; $fileLength = 0; + // Piwik services behave like a proxy, so we should act like one. + $xff = 'X-Forwarded-For: ' + . (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !empty($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] . ',' : '') + . Piwik_IP::getIpFromHeader(); + $via = 'Via: ' + . (isset($_SERVER['HTTP_VIA']) && !empty($_SERVER['HTTP_VIA']) ? $_SERVER['HTTP_VIA'] . ', ' : '') + . Piwik_Version::VERSION . ' Piwik' + . ($userAgent ? " ($userAgent)" : ''); + $userAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'Piwik/'.Piwik_Version::VERSION; + + // proxy configuration + if(!empty($GLOBALS['PIWIK_TRACKER_MODE'])) + { + $proxyHost = Piwik_Tracker_Config::getInstance()->proxy['host']; + $proxyPort = Piwik_Tracker_Config::getInstance()->proxy['port']; + $proxyUser = Piwik_Tracker_Config::getInstance()->proxy['username']; + $proxyPassword = Piwik_Tracker_Config::getInstance()->proxy['password']; + } + else + { + $config = Zend_Registry::get('config'); + if($config !== false) + { + $proxyHost = $config->proxy->host; + $proxyPort = $config->proxy->port; + $proxyUser = $config->proxy->username; + $proxyPassword = $config->proxy->password; + } + } + if($method == 'socket') { // initialization @@ -118,22 +148,41 @@ class Piwik_Http $errno = null; $errstr = null; + $proxyAuth = null; + if(!empty($proxyHost) && !empty($proxyPort)) + { + $connectHost = $proxyHost; + $connectPort = $proxyPort; + if(!empty($proxyUser) && !empty($proxyPassword)) + { + $proxyAuth = 'Proxy-Authorization: Basic '.base64_encode("$proxyUser:$proxyPassword") ."\r\n"; + } + $requestHeader = "GET $aUrl HTTP/1.1\r\n"; + } + else + { + $connectHost = $host; + $connectPort = $port; + $requestHeader = "GET $path HTTP/1.0\r\n"; + } + // connection attempt - if (($fsock = @fsockopen($host, $port, $errno, $errstr, $timeout)) === false || !is_resource($fsock)) + if (($fsock = @fsockopen($connectHost, $connectPort, $errno, $errstr, $timeout)) === false || !is_resource($fsock)) { if(is_resource($file)) { @fclose($file); } throw new Exception("Error while connecting to: $host. Please try again later. $errstr"); } // send HTTP request header - fwrite($fsock, - "GET $path HTTP/1.0\r\n" - ."Host: $host".($port != 80 ? ':'.$port : '')."\r\n" - ."User-Agent: Piwik/".Piwik_Version::VERSION.($userAgent ? " $userAgent" : '')."\r\n" - .'Referer: http://'.Piwik_IP::getIpFromHeader()."/\r\n" + $requestHeader .= + "Host: $host".($port != 80 ? ':'.$port : '')."\r\n" + .($proxyAuth ? $proxyAuth : '') + .'User-Agent: '.$userAgent."\r\n" + .$xff."\r\n" + .$via."\r\n" ."Connection: close\r\n" - ."\r\n" - ); + ."\r\n"; + fwrite($fsock, $requestHeader); $streamMetaData = array('timed_out' => false); @stream_set_blocking($fsock, true); @@ -256,12 +305,24 @@ class Piwik_Http if(function_exists('stream_context_create')) { $stream_options = array( 'http' => array( - 'header' => 'User-Agent: Piwik/'.Piwik_Version::VERSION.($userAgent ? " $userAgent" : '')."\r\n" - .'Referer: http://'.Piwik_IP::getIpFromHeader()."/\r\n", + 'header' => 'User-Agent: '.$userAgent."\r\n" + .$xff."\r\n" + .$via."\r\n", 'max_redirects' => 5, // PHP 5.1.0 'timeout' => $timeout, // PHP 5.2.1 ) ); + + if(!empty($proxyHost) && !empty($proxyPort)) + { + $stream_options['http']['proxy'] = 'tcp://'.$proxyHost.':'.$proxyPort; + $stream_options['http']['request_fulluri'] = true; // required by squid proxy + if(!empty($proxyUser) && !empty($proxyPassword)) + { + $stream_options['http']['header'] .= 'Proxy-Authorization: Basic '.base64_encode("$proxyUser:$proxyPassword")."\r\n"; + } + } + $ctx = stream_context_create($stream_options); } @@ -284,14 +345,27 @@ class Piwik_Http { $ch = @curl_init(); + if(!empty($proxyHost) && !empty($proxyPort)) + { + @curl_setopt($ch, CURLOPT_PROXY, $proxyHost.':'.$proxyPort); + if(!empty($proxyUser) && !empty($proxyPassword)) + { + // PROXYAUTH defaults to BASIC + @curl_setopt($ch, CURLOPT_PROXYUSERPWD, $proxyUser.':'.$proxyPassword); + } + } + $curl_options = array( // internal to ext/curl CURLOPT_BINARYTRANSFER => is_resource($file), // curl options (sorted oldest to newest) CURLOPT_URL => $aUrl, - CURLOPT_REFERER => 'http://'.Piwik_IP::getIpFromHeader(), - CURLOPT_USERAGENT => 'Piwik/'.Piwik_Version::VERSION.($userAgent ? " $userAgent" : ''), + CURLOPT_USERAGENT => $userAgent, + CURLOPT_HTTPHEADER => array( + $xff, + $via, + ), CURLOPT_HEADER => false, CURLOPT_CONNECTTIMEOUT => $timeout, ); diff --git a/tests/core/Http.test.php b/tests/core/Http.test.php index 0f2d4a3111..7e3822ae59 100644 --- a/tests/core/Http.test.php +++ b/tests/core/Http.test.php @@ -29,7 +29,7 @@ class Test_Piwik_Http extends UnitTestCase var_dump($e->getMessage()); } - $this->assertTrue( preg_match('/^([0-9.]+)$/', $version) ); + $this->assertTrue( preg_match('/^([0-9.]+)$/', $version), $method ); } $destinationPath = PIWIK_USER_PATH . '/tmp/latest/LATEST'; -- GitLab