diff --git a/lib/filelib.php b/lib/filelib.php index b893cf22f98..69d8da0e18d 100644 --- a/lib/filelib.php +++ b/lib/filelib.php @@ -2683,7 +2683,8 @@ class curl { public $emulateredirects = null; /** @var array cURL options */ - private $options; + protected $options; + /** @var string Proxy host */ private $proxy_host = ''; /** @var string Proxy auth */ @@ -2975,7 +2976,7 @@ class curl { * @param array $options * @return resource The curl handle */ - private function apply_opt($curl, $options) { + protected function apply_opt($curl, $options) { // Clean up $this->cleanopt(); // set cookie @@ -3004,15 +3005,36 @@ class curl { } $this->setopt($options); - // reset before set options + + // Reset before set options. curl_setopt($curl, CURLOPT_HEADERFUNCTION, array(&$this,'formatHeader')); - // set headers + + // Setting the User-Agent based on options provided. + $useragent = ''; + + if (!empty($options['CURLOPT_USERAGENT'])) { + $useragent = $options['CURLOPT_USERAGENT']; + } else if (!empty($this->options['CURLOPT_USERAGENT'])) { + $useragent = $this->options['CURLOPT_USERAGENT']; + } else { + $useragent = 'MoodleBot/1.0'; + } + + // Set headers. if (empty($this->header)) { $this->setHeader(array( - 'User-Agent: MoodleBot/1.0', + 'User-Agent: ' . $useragent, 'Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'Connection: keep-alive' )); + } else if (!in_array('User-Agent: ' . $useragent, $this->header)) { + // Remove old User-Agent if one existed. + // We have to partial search since we don't know what the original User-Agent is. + if ($match = preg_grep('/User-Agent.*/', $this->header)) { + $key = array_keys($match)[0]; + unset($this->header[$key]); + } + $this->setHeader(array('User-Agent: ' . $useragent)); } curl_setopt($curl, CURLOPT_HTTPHEADER, $this->header); diff --git a/lib/tests/filelib_test.php b/lib/tests/filelib_test.php index cab417d00c2..f74e655f391 100644 --- a/lib/tests/filelib_test.php +++ b/lib/tests/filelib_test.php @@ -878,4 +878,80 @@ EOF; $this->assertEquals('image', $mimeinfo['png']['string']); $this->assertEquals(true, $mimeinfo['txt']['defaulticon']); } + + /** + * Test curl agent settings. + */ + public function test_curl_useragent() { + $curl = new curl_extended(); + $options = $curl->get_options(); + $this->assertNotEmpty($options); + + $curl->call_apply_opt($options); + $this->assertTrue(in_array('User-Agent: MoodleBot/1.0', $curl->header)); + $this->assertFalse(in_array('User-Agent: Test/1.0', $curl->header)); + + $options['CURLOPT_USERAGENT'] = 'Test/1.0'; + $curl->call_apply_opt($options); + $this->assertTrue(in_array('User-Agent: Test/1.0', $curl->header)); + $this->assertFalse(in_array('User-Agent: MoodleBot/1.0', $curl->header)); + + $curl->set_option('CURLOPT_USERAGENT', 'AnotherUserAgent/1.0'); + $curl->call_apply_opt(); + $this->assertTrue(in_array('User-Agent: AnotherUserAgent/1.0', $curl->header)); + $this->assertFalse(in_array('User-Agent: Test/1.0', $curl->header)); + + $curl->set_option('CURLOPT_USERAGENT', 'AnotherUserAgent/1.1'); + $options = $curl->get_options(); + $curl->call_apply_opt($options); + $this->assertTrue(in_array('User-Agent: AnotherUserAgent/1.1', $curl->header)); + $this->assertFalse(in_array('User-Agent: AnotherUserAgent/1.0', $curl->header)); + + $curl->unset_option('CURLOPT_USERAGENT'); + $curl->call_apply_opt(); + $this->assertTrue(in_array('User-Agent: MoodleBot/1.0', $curl->header)); + } +} + +/** + * Test-specific class to allow easier testing of curl functions. + * + * @copyright 2015 Dave Cooper + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class curl_extended extends curl { + /** + * Accessor for options array. + */ + public function get_options() { + return $this->options; + } + + /** + * Setter for options array. + * @param string $option + * @param string $value + */ + public function set_option($option, $value) { + $this->options[$option] = $value; + } + + /** + * Unsets an option on the curl object + * @param string $option + */ + public function unset_option($option) { + unset($this->options[$option]); + } + + /** + * Wrapper to access the curl::apply_opt() function + * + * @param array $options + * @return resource The curl handle + */ + public function call_apply_opt($options = null) { + $ch = curl_init(); + return $this->apply_opt($ch, $options); + } }