Completed
Pull Request — master (#66)
by Jan
05:29
created

HttpGetRequest   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 211
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 100%

Importance

Changes 14
Bugs 6 Features 1
Metric Value
wmc 33
c 14
b 6
f 1
lcom 1
cbo 3
dl 0
loc 211
ccs 103
cts 103
cp 1
rs 9.3999

10 Methods

Rating   Name   Duplication   Size   Complexity  
A importURL() 0 20 3
A __construct() 0 13 4
A setOr() 0 8 2
A processRFSOption() 0 6 2
A getCurlOpts() 0 23 3
A getURL() 0 21 4
A setConfig() 0 4 1
B promptAuth() 0 25 6
B promptAuthWithUtil() 0 19 5
A genUA() 0 16 3
1
<?php
2
/*
3
 * hirak/prestissimo
4
 * @author Hiraku NAKANO
5
 * @license MIT https://github.com/hirak/prestissimo
6
 */
7
namespace Hirak\Prestissimo\Aspects;
8
9
use Composer\IO;
10
use Composer\Composer;
11
use Composer\Config as CConfig;
12
use Composer\Downloader;
13
14
/**
15
 * Simple Container for http-get request
16
 */
17
class HttpGetRequest
18
{
19
    public $origin;
20
    public $scheme = 'http';
21
    public $host = 'example.com';
22
    public $port = 80;
23
    public $path = '/';
24
25
    public $query = array();
26
    public $headers = array();
27
28
    public $curlOpts = array();
29
30
    public $username = null;
31
    public $password = null;
32
33
    public $maybePublic = false;
34
    public $verbose = false;
35
36
    /** @var CConfig */
37
    protected $config;
38
39
    /** @internal */
40
    const TOKEN_LABEL = 'access_token';
41
42
    /**
43
     * normalize url and authentication info
44
     * @param string $origin domain text
45
     * @param string $url
46
     * @param IO\IOInterface $io
47
     */
48 34
    public function __construct($origin, $url, IO\IOInterface $io)
49
    {
50 34
        $this->origin = $origin;
51 34
        $this->importURL($url);
52
53 34
        if ($this->username && $this->password) {
54 3
            $io->setAuthentication($origin, $this->username, $this->password);
55 34
        } elseif ($io->hasAuthentication($origin)) {
56 2
            $auth = $io->getAuthentication($origin);
57 2
            $this->username = $auth['username'];
58 2
            $this->password = $auth['password'];
59 2
        }
60 34
    }
61
62
    /**
63
     * @param string $url
64
     */
65 34
    public function importURL($url)
66
    {
67 34
        $struct = parse_url($url);
68
        // @codeCoverageIgnoreStart
69
        if (! $struct) {
70
            throw new \InvalidArgumentException("$url is not valid URL");
71
        }
72
        // @codeCoverageIgnoreEnd
73
74 34
        $this->scheme = self::setOr($struct, 'scheme', $this->scheme);
75 34
        $this->host = self::setOr($struct, 'host', $this->host);
76 34
        $this->port = self::setOr($struct, 'port', null);
77 34
        $this->path = self::setOr($struct, 'path', '');
78 34
        $this->username = self::setOr($struct, 'user', null);
79 34
        $this->password = self::setOr($struct, 'pass', null);
80
81 34
        if (! empty($struct['query'])) {
82 9
            parse_str($struct['query'], $this->query);
83 9
        }
84 34
    }
85
86
87
    /**
88
     * @param string $key
89
     * @param string $default
90
     */
91 34
    private static function setOr(array $struct, $key, $default = null)
92
    {
93 34
        if (!empty($struct[$key])) {
94 34
            return $struct[$key];
95
        }
96
97 34
        return $default;
98
    }
99
100
    /**
101
     * process option for RemortFileSystem
102
     * @return void
103
     */
104 7
    public function processRFSOption(array $options)
105
    {
106 7
        if (isset($options[static::TOKEN_LABEL])) {
107 1
            $this->query['access_token'] = $options[static::TOKEN_LABEL];
108 1
        }
109 7
    }
110
111 10
    public function getCurlOpts()
112
    {
113 10
        $curlOpts = $this->curlOpts + array(
114 10
            CURLOPT_HTTPGET => true,
115 10
            CURLOPT_FOLLOWLOCATION => true,
116 10
            CURLOPT_MAXREDIRS => 20,
117 10
            CURLOPT_ENCODING => 'gzip',
118 10
            CURLOPT_HTTPHEADER => $this->headers,
119 10
            CURLOPT_USERAGENT => $this->genUA(),
120 10
        );
121
122 10
        $curlOpts[CURLOPT_VERBOSE] = (bool)$this->verbose;
123
124 10
        if ($this->username && $this->password) {
125 1
            $curlOpts[CURLOPT_USERPWD] = "$this->username:$this->password";
126 1
        } else {
127 10
            unset($curlOpts[CURLOPT_USERPWD]);
128
        }
129
130 10
        $curlOpts[CURLOPT_URL] = $this->getUrl();
131
132 10
        return $curlOpts;
133
    }
134
135 17
    public function getURL()
136
    {
137 17
        if ($this->scheme) {
138 17
            $url = "$this->scheme://";
139 17
        } else {
140 1
            $url = '';
141
        }
142 17
        $url .= $this->host;
143
144 17
        if ($this->port) {
145 9
            $url .= ":$this->port";
146 9
        }
147
148 17
        $url .= $this->path;
149
150 17
        if ($this->query) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->query of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
151 9
            $url .= '?' . http_build_query($this->query);
152 9
        }
153
154 17
        return $url;
155
    }
156
157 5
    public function setConfig(CConfig $config)
158
    {
159 5
        $this->config = $config;
160 5
    }
161
162 6
    public function promptAuth(HttpGetResponse $res, IO\IOInterface $io)
163
    {
164 6
        $httpCode = $res->info['http_code'];
165
        // 404s are only handled for github
166 6
        if (404 === $httpCode) {
167 1
            return false;
168
        }
169
170
        // fail if the console is not interactive
171 5
        if (!$io->isInteractive() && ($httpCode === 401 || $httpCode === 403)) {
172 3
            $message = "The '{$this->getURL()}' URL required authentication.\nYou must be using the interactive console to authenticate";
173 3
            throw new Downloader\TransportException($message, $httpCode);
174
        }
175
176
        // fail if we already have auth
177 2
        if ($io->hasAuthentication($this->origin)) {
178 1
            throw new Downloader\TransportException("Invalid credentials for '{$this->getURL()}', aborting.", $httpCode);
179
        }
180
181 1
        $io->overwrite("    Authentication required (<info>$this->host</info>):");
182 1
        $username = $io->ask('      Username: ');
183 1
        $password = $io->askAndHideAnswer('      Password: ');
184 1
        $io->setAuthentication($this->origin, $username, $password);
185 1
        return true;
186
    }
187
188
    /**
189
     * @internal
190
     */
191 2
    public function promptAuthWithUtil($privateCode, $util, HttpGetResponse $res, IO\IOInterface $io)
192
    {
193 2
        $httpCode = $res->info['http_code'];
194 2
        $message = "\nCould not fetch {$this->getURL()}, enter your $this->origin credentials ";
195 2
        if ($privateCode === $httpCode) {
196 1
            $message .= 'to access private repos';
197 1
        } else {
198 1
            $message .= 'to go over the API rate limit';
199
        }
200 2
        if ($util->authorizeOAuth($this->origin)) {
201 1
            return true;
202
        }
203 2
        if ($io->isInteractive() &&
204 2
            $util->authorizeOAuthInteractively($this->origin, $message)) {
205 1
            return true;
206
        }
207
208 1
        throw new Downloader\TransportException("Could not authenticate against $this->origin", $httpCode);
209
    }
210
211 10
    public static function genUA()
212
    {
213 10
        static $ua;
214 10
        if ($ua) {
215 9
            return $ua;
216
        }
217 2
        $phpVersion = defined('HHVM_VERSION') ? 'HHVM ' . HHVM_VERSION : 'PHP ' . PHP_VERSION;
218
219 2
        return $ua = sprintf(
220 2
            'Composer/%s (%s; %s; %s)',
221 2
            str_replace('@package_version@', 'source', Composer::VERSION),
222 2
            php_uname('s'),
223 2
            php_uname('r'),
224
            $phpVersion
225 2
        );
226
    }
227
}
228