Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
57.14% covered (warning)
57.14%
4 / 7
CRAP
79.41% covered (warning)
79.41%
27 / 34
HttpRequestExecutor
0.00% covered (danger)
0.00%
0 / 1
57.14% covered (warning)
57.14%
4 / 7
15.71
79.41% covered (warning)
79.41%
27 / 34
 __construct
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
5 / 5
 setLogger
n/a
0 / 0
1
n/a
0 / 0
 overrideRequestFactory
0.00% covered (danger)
0.00%
0 / 1
2.26
60.00% covered (warning)
60.00%
3 / 5
 execute
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 executePost
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 executeAndSave
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 3
 executeWithCallback
0.00% covered (danger)
0.00%
0 / 1
6.05
88.89% covered (warning)
88.89%
16 / 18
 buildUserAgentString
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
<?php
namespace FileImporter\Services\Http;
use FileImporter\Exceptions\HttpRequestException;
use MWException;
use MWHttpRequest;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
/**
 * @license GPL-2.0-or-later
 * @author Addshore
 */
class HttpRequestExecutor implements LoggerAwareInterface {
    /**
     * @var LoggerInterface
     */
    private $logger;
    /**
     * @var callable
     */
    private $requestFactoryCallable;
    /**
     * @var array
     */
    private $httpOptions;
    /**
     * @var int
     */
    private $maxFileSize;
    /**
     * @param array $httpOptions in the following format:
     * [
     *     'originalRequest' => WebRequest|string[] When in array form, it's expected to have the
     *         keys 'ip' and 'userAgent', {@see MWHttpRequest::setOriginalRequest},
     *     'proxy' => string|false,
     *     'timeout' => int|false Timeout of HTTP requests in seconds, false for default,
     * ]
     * @param int $maxFileSize in bytes
     */
    public function __construct( array $httpOptions, $maxFileSize ) {
        $this->requestFactoryCallable = [ MWHttpRequest::class, 'factory' ];
        $this->logger = new NullLogger();
        $this->maxFileSize = $maxFileSize;
        $this->httpOptions = $httpOptions;
    }
    /**
     * @param LoggerInterface $logger
     * @codeCoverageIgnore
     */
    public function setLogger( LoggerInterface $logger ) {
        $this->logger = $logger;
    }
    /**
     * @param callable $callable
     *
     * @throws MWException
     */
    public function overrideRequestFactory( callable $callable ) {
        if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
            throw new MWException(
                'Cannot override MWHttpRequest::factory callback in operation.'
            );
        }
        $this->requestFactoryCallable = $callable;
    }
    /**
     * @param string $url
     * @param array $parameters
     *
     * @return MWHttpRequest
     * @throws HttpRequestException
     */
    public function execute( $url, array $parameters = [] ) {
        return $this->executeWithCallback( wfAppendQuery( $url, $parameters ) );
    }
    /**
     * @param string $url
     * @param array $postData
     *
     * @return MWHttpRequest
     */
    public function executePost( $url, array $postData ) {
        return $this->executeWithCallback( $url, null, $postData );
    }
    /**
     * @param string $url
     * @param string $filePath
     *
     * @return MWHttpRequest
     * @throws HttpRequestException
     */
    public function executeAndSave( $url, $filePath ) {
        $chunkSaver = new FileChunkSaver( $filePath, $this->maxFileSize );
        $chunkSaver->setLogger( $this->logger );
        return $this->executeWithCallback( $url, [ $chunkSaver, 'saveFileChunk' ] );
    }
    /**
     * @param string $url
     * @param callable|null $callback
     * @param array|null $postData
     *
     * @return MWHttpRequest
     * @throws HttpRequestException
     */
    private function executeWithCallback( $url, $callback = null, $postData = null ) {
        $options = [
            'logger' => $this->logger,
            'followRedirects' => true,
        ];
        if ( isset( $this->httpOptions['originalRequest'] ) ) {
            $options['originalRequest'] = $this->httpOptions['originalRequest'];
        }
        if ( !empty( $this->httpOptions['proxy'] ) ) {
            $options['proxy'] = $this->httpOptions['proxy'];
        }
        $timeout = $this->httpOptions['timeout'] ?? false;
        if ( $timeout !== false ) {
            $options['timeout'] = $timeout;
        }
        if ( $postData !== null ) {
            $options['method'] = 'POST';
            $options['postData'] = $postData;
        }
        $options['userAgent'] = $this->buildUserAgentString();
        /** @var MWHttpRequest $request */
        $request = ( $this->requestFactoryCallable )( $url, $options, __METHOD__ );
        $request->setCallback( $callback );
        $status = $request->execute();
        if ( !$status->isOK() ) {
            throw new HttpRequestException( $status, $request );
        }
        return $request;
    }
    private function buildUserAgentString() {
        // TODO: Pull URL and version from ExtensionRegistry.
        return 'mw-ext-FileImporter/* (https://www.mediawiki.org/wiki/Extension:FileImporter)';
    }
}