Merge "http: Support HTTP Basic Authentication"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Thu, 1 Dec 2016 20:09:02 +0000 (20:09 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Thu, 1 Dec 2016 20:09:02 +0000 (20:09 +0000)
1  2 
includes/http/Http.php
includes/http/MWHttpRequest.php

diff --combined includes/http/Http.php
@@@ -51,6 -51,8 +51,8 @@@ class Http 
         *    - userAgent           A user agent, if you want to override the default
         *                          MediaWiki/$wgVersion
         *    - logger              A \Psr\Logger\LoggerInterface instance for debug logging
+        *    - username            Username for HTTP Basic Authentication
+        *    - password            Password for HTTP Basic Authentication
         * @param string $caller The method making this request, for profiling
         * @return string|bool (bool)false on failure or a string on success
         */
@@@ -74,7 -76,7 +76,7 @@@
                } else {
                        $errors = $status->getErrorsByType( 'error' );
                        $logger = LoggerFactory::getInstance( 'http' );
 -                      $logger->warning( $status->getWikiText( false, false, 'en' ),
 +                      $logger->warning( Status::wrap( $status )->getWikiText( false, false, 'en' ),
                                [ 'error' => $errors, 'caller' => $caller, 'content' => $req->getContent() ] );
                        return false;
                }
@@@ -46,11 -46,9 +46,11 @@@ class MWHttpRequest implements LoggerAw
        protected $reqHeaders = [];
        protected $url;
        protected $parsedUrl;
 +      /** @var callable  */
        protected $callback;
        protected $maxRedirects = 5;
        protected $followRedirects = false;
 +      protected $connectTimeout;
  
        /**
         * @var CookieJar
@@@ -62,8 -60,7 +62,8 @@@
        protected $respStatus = "200 Ok";
        protected $respHeaders = [];
  
 -      public $status;
 +      /** @var StatusValue */
 +      protected $status;
  
        /**
         * @var Profiler
                }
  
                if ( !$this->parsedUrl || !Http::isValidURI( $this->url ) ) {
 -                      $this->status = Status::newFatal( 'http-invalid-url', $url );
 +                      $this->status = StatusValue::newFatal( 'http-invalid-url', $url );
                } else {
 -                      $this->status = Status::newGood( 100 ); // continue
 +                      $this->status = StatusValue::newGood( 100 ); // continue
                }
  
                if ( isset( $options['timeout'] ) && $options['timeout'] != 'default' ) {
                if ( isset( $options['userAgent'] ) ) {
                        $this->setUserAgent( $options['userAgent'] );
                }
+               if ( isset( $options['username'] ) && isset( $options['password'] ) ) {
+                       $this->setHeader(
+                               'Authorization',
+                               'Basic ' . base64_encode( $options['username'] . ':' . $options['password'] )
+                       );
+               }
  
                $members = [ "postData", "proxy", "noProxy", "sslVerifyHost", "caInfo",
                                "method", "followRedirects", "maxRedirects", "sslVerifyCert", "callback" ];
         * @param string $url Url to use
         * @param array $options (optional) extra params to pass (see Http::request())
         * @param string $caller The method making this request, for profiling
 -       * @throws MWException
 +       * @throws DomainException
         * @return CurlHttpRequest|PhpHttpRequest
         * @see MWHttpRequest::__construct
         */
                if ( !Http::$httpEngine ) {
                        Http::$httpEngine = function_exists( 'curl_init' ) ? 'curl' : 'php';
                } elseif ( Http::$httpEngine == 'curl' && !function_exists( 'curl_init' ) ) {
 -                      throw new MWException( __METHOD__ . ': curl (http://php.net/curl) is not installed, but' .
 +                      throw new DomainException( __METHOD__ . ': curl (http://php.net/curl) is not installed, but' .
                                ' Http::$httpEngine is set to "curl"' );
                }
  
                                return new CurlHttpRequest( $url, $options, $caller, Profiler::instance() );
                        case 'php':
                                if ( !wfIniGetBool( 'allow_url_fopen' ) ) {
 -                                      throw new MWException( __METHOD__ . ': allow_url_fopen ' .
 +                                      throw new DomainException( __METHOD__ . ': allow_url_fopen ' .
                                                'needs to be enabled for pure PHP http requests to ' .
                                                'work. If possible, curl should be used instead. See ' .
                                                'http://php.net/curl.'
                                }
                                return new PhpHttpRequest( $url, $options, $caller, Profiler::instance() );
                        default:
 -                              throw new MWException( __METHOD__ . ': The setting of Http::$httpEngine is not valid.' );
 +                              throw new DomainException( __METHOD__ . ': The setting of Http::$httpEngine is not valid.' );
                }
        }
  
         *
         * @return void
         */
 -      public function proxySetup() {
 +      protected function proxySetup() {
                // If there is an explicit proxy set and proxies are not disabled, then use it
                if ( $this->proxy && !$this->noProxy ) {
                        return;
         * Get an array of the headers
         * @return array
         */
 -      public function getHeaderList() {
 +      protected function getHeaderList() {
                $list = [];
  
                if ( $this->cookieJar ) {
         * bytes are reported handled than were passed to you, the HTTP fetch
         * will be aborted.
         *
 -       * @param callable $callback
 -       * @throws MWException
 +       * @param callable|null $callback
 +       * @throws InvalidArgumentException
         */
        public function setCallback( $callback ) {
 -              if ( !is_callable( $callback ) ) {
 -                      throw new MWException( 'Invalid MwHttpRequest callback' );
 +              if ( is_null( $callback ) ) {
 +                      $callback = [ $this, 'read' ];
 +              } elseif ( !is_callable( $callback ) ) {
 +                      throw new InvalidArgumentException( __METHOD__ . ': invalid callback' );
                }
                $this->callback = $callback;
        }
         * @param resource $fh
         * @param string $content
         * @return int
 +       * @internal
         */
        public function read( $fh, $content ) {
                $this->content .= $content;
        /**
         * Take care of whatever is necessary to perform the URI request.
         *
 -       * @return Status
 +       * @return StatusValue
 +       * @note currently returns Status for B/C
         */
        public function execute() {
 +              throw new LogicException( 'children must override this' );
 +      }
 +
 +      protected function prepare() {
                $this->content = "";
  
                if ( strtoupper( $this->method ) == "HEAD" ) {
                $this->proxySetup(); // set up any proxy as needed
  
                if ( !$this->callback ) {
 -                      $this->setCallback( [ $this, 'read' ] );
 +                      $this->setCallback( null );
                }
  
                if ( !isset( $this->reqHeaders['User-Agent'] ) ) {
        /**
         * Tells the MWHttpRequest object to use this pre-loaded CookieJar.
         *
 +       * To read response cookies from the jar, getCookieJar must be called first.
 +       *
         * @param CookieJar $jar
         */
        public function setCookieJar( $jar ) {
         * Set-Cookie headers.
         * @see Cookie::set
         * @param string $name
 -       * @param mixed $value
 +       * @param string $value
         * @param array $attr
         */
 -      public function setCookie( $name, $value = null, $attr = null ) {
 +      public function setCookie( $name, $value, $attr = [] ) {
                if ( !$this->cookieJar ) {
                        $this->cookieJar = new CookieJar;
                }
  
 +              if ( $this->parsedUrl && !isset( $attr['domain'] ) ) {
 +                      $attr['domain'] = $this->parsedUrl['host'];
 +              }
 +
                $this->cookieJar->setCookie( $name, $value, $attr );
        }