Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
82.14% covered (warning)
82.14%
23 / 28
66.67% covered (warning)
66.67%
4 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
HttpRequestExecutor
82.14% covered (warning)
82.14%
23 / 28
66.67% covered (warning)
66.67%
4 / 6
12.82
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setLogger
n/a
0 / 0
n/a
0 / 0
1
 execute
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 executePost
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 executeAndSave
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 executeHttpRequest
90.48% covered (success)
90.48%
19 / 21
0.00% covered (danger)
0.00%
0 / 1
6.03
 buildUserAgentString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace FileImporter\Services\Http;
4
5use FileImporter\Exceptions\HttpRequestException;
6use MediaWiki\Http\HttpRequestFactory;
7use MediaWiki\Http\MWHttpRequest;
8use Psr\Log\LoggerAwareInterface;
9use Psr\Log\LoggerInterface;
10use Psr\Log\NullLogger;
11
12/**
13 * @license GPL-2.0-or-later
14 * @author Addshore
15 */
16class HttpRequestExecutor implements LoggerAwareInterface {
17
18    private LoggerInterface $logger;
19
20    /**
21     * @param HttpRequestFactory $httpRequestFactory
22     * @param array $httpOptions in the following format:
23     * [
24     *     'originalRequest' => WebRequest|string[] When in array form, it's expected to have the
25     *         keys 'ip' and 'userAgent', {@see MWHttpRequest::setOriginalRequest},
26     *     'proxy' => string|false,
27     *     'timeout' => int|false Timeout of HTTP requests in seconds, false for default,
28     * ]
29     * @param int $maxFileSize in bytes
30     */
31    public function __construct(
32        private readonly HttpRequestFactory $httpRequestFactory,
33        private readonly array $httpOptions,
34        private readonly int $maxFileSize,
35    ) {
36        $this->logger = new NullLogger();
37    }
38
39    /**
40     * @codeCoverageIgnore
41     */
42    public function setLogger( LoggerInterface $logger ): void {
43        $this->logger = $logger;
44    }
45
46    /**
47     * @throws HttpRequestException
48     */
49    public function execute( string $url, array $parameters = [] ): MWHttpRequest {
50        return $this->executeHttpRequest( wfAppendQuery( $url, $parameters ) );
51    }
52
53    public function executePost( string $url, array $postData ): MWHttpRequest {
54        return $this->executeHttpRequest( $url, null, $postData );
55    }
56
57    /**
58     * @throws HttpRequestException
59     */
60    public function executeAndSave( string $url, string $filePath ): MWHttpRequest {
61        $chunkSaver = new FileChunkSaver( $filePath, $this->maxFileSize );
62        $chunkSaver->setLogger( $this->logger );
63        return $this->executeHttpRequest( $url, [ $chunkSaver, 'saveFileChunk' ] );
64    }
65
66    /**
67     * @throws HttpRequestException
68     */
69    private function executeHttpRequest(
70        string $url,
71        ?callable $callback = null,
72        ?array $postData = null
73    ): MWHttpRequest {
74        $options = [
75            'logger' => $this->logger,
76            'followRedirects' => true,
77        ];
78        if ( isset( $this->httpOptions['originalRequest'] ) ) {
79            $options['originalRequest'] = $this->httpOptions['originalRequest'];
80        }
81        if ( !empty( $this->httpOptions['proxy'] ) ) {
82            $options['proxy'] = $this->httpOptions['proxy'];
83        }
84        $timeout = $this->httpOptions['timeout'] ?? false;
85        if ( $timeout !== false ) {
86            $options['timeout'] = $timeout;
87        }
88        if ( $postData !== null ) {
89            $options['method'] = 'POST';
90            $options['postData'] = $postData;
91        }
92        $options['userAgent'] = $this->buildUserAgentString();
93
94        /** @var MWHttpRequest $request */
95        $request = $this->httpRequestFactory->create( $url, $options, __METHOD__ );
96
97        $request->setCallback( $callback );
98
99        $status = $request->execute();
100        if ( !$status->isOK() ) {
101            throw new HttpRequestException( $status, $request );
102        }
103
104        return $request;
105    }
106
107    private function buildUserAgentString(): string {
108        // TODO: Pull URL and version from ExtensionRegistry.
109        return 'mw-ext-FileImporter/* (https://www.mediawiki.org/wiki/Extension:FileImporter)';
110    }
111
112}