Merge "mw.widgets.CategorySelector: Prevent duplicates"
[lhc/web/wiklou.git] / includes / libs / MultiHttpClient.php
index 6af3ed5..6ad7741 100644 (file)
@@ -55,6 +55,8 @@ class MultiHttpClient {
        protected $maxConnsPerHost = 50;
        /** @var string|null proxy */
        protected $proxy;
+       /** @var string */
+       protected $userAgent = 'wikimedia/multi-http-client v1.0';
 
        /**
         * @param array $options
@@ -63,6 +65,7 @@ class MultiHttpClient {
         *   - proxy           : HTTP proxy to use
         *   - usePipelining   : whether to use HTTP pipelining if possible (for all hosts)
         *   - maxConnsPerHost : maximum number of concurrent connections (per host)
+        *   - userAgent       : The User-Agent header value to send
         * @throws Exception
         */
        public function __construct( array $options ) {
@@ -73,7 +76,7 @@ class MultiHttpClient {
                        }
                }
                static $opts = array(
-                       'connTimeout', 'reqTimeout', 'usePipelining', 'maxConnsPerHost', 'proxy'
+                       'connTimeout', 'reqTimeout', 'usePipelining', 'maxConnsPerHost', 'proxy', 'userAgent'
                );
                foreach ( $opts as $key ) {
                        if ( isset( $options[$key] ) ) {
@@ -335,6 +338,19 @@ class MultiHttpClient {
                        );
                } elseif ( $req['method'] === 'POST' ) {
                        curl_setopt( $ch, CURLOPT_POST, 1 );
+                       // Don't interpret POST parameters starting with '@' as file uploads, because this
+                       // makes it impossible to POST plain values starting with '@' (and causes security
+                       // issues potentially exposing the contents of local files).
+                       // The PHP manual says this option was introduced in PHP 5.5 defaults to true in PHP 5.6,
+                       // but we support lower versions, and the option doesn't exist in HHVM 5.6.99.
+                       if ( defined( 'CURLOPT_SAFE_UPLOAD' ) ) {
+                               curl_setopt( $ch, CURLOPT_SAFE_UPLOAD, true );
+                       } elseif ( is_array( $req['body'] ) ) {
+                               // In PHP 5.2 and later, '@' is interpreted as a file upload if POSTFIELDS
+                               // is an array, but not if it's a string. So convert $req['body'] to a string
+                               // for safety.
+                               $req['body'] = wfArrayToCgi( $req['body'] );
+                       }
                        curl_setopt( $ch, CURLOPT_POSTFIELDS, $req['body'] );
                } else {
                        if ( is_resource( $req['body'] ) || $req['body'] !== '' ) {
@@ -343,6 +359,10 @@ class MultiHttpClient {
                        $req['headers']['content-length'] = 0;
                }
 
+               if ( !isset( $req['headers']['user-agent'] ) ) {
+                       $req['headers']['user-agent'] = $this->userAgent;
+               }
+
                $headers = array();
                foreach ( $req['headers'] as $name => $value ) {
                        if ( strpos( $name, ': ' ) ) {