Completed
Pull Request — master (#68)
by Hiraku
10:16
created

HttpGetRequest::getURL()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 4

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 21
ccs 13
cts 13
cp 1
rs 9.0534
cc 4
eloc 12
nc 8
nop 0
crap 4
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 array $struct
89
     * @param string $key
90
     * @param string $default
91 34
     * @return mixed
92
     */
93 34
    private static function setOr(array $struct, $key, $default = null)
94 34
    {
95
        if (!empty($struct[$key])) {
96
            return $struct[$key];
97 34
        }
98
99
        return $default;
100
    }
101
102
    /**
103
     * process option for RemortFileSystem
104 7
     * @param array $options
105
     * @return void
106 7
     */
107 1
    public function processRFSOption(array $options)
108 1
    {
109 7
        if (isset($options[static::TOKEN_LABEL])) {
110
            $this->query['access_token'] = $options[static::TOKEN_LABEL];
111 10
        }
112
    }
113 10
114 10
    /**
115 10
     * @return array
116 10
     */
117 10
    public function getCurlOpts()
118 10
    {
119 10
        $headers = $this->headers;
120 10
        if ($this->username && $this->password) {
121
            foreach ($headers as $i => $header) {
122 10
                if (0 === strpos($header, 'Authentication:')) {
123
                    unset($headers[$i]);
124 10
                }
125 1
            }
126 1
            $headers[] = 'Authentication: Basic ' . base64_encode("$this->username:$this->password");
127 10
        }
128
129
        $curlOpts = $this->curlOpts + array(
130 10
            CURLOPT_HTTPGET => true,
131
            CURLOPT_FOLLOWLOCATION => true,
132 10
            CURLOPT_MAXREDIRS => 20,
133
            CURLOPT_ENCODING => 'gzip',
134
            CURLOPT_HTTPHEADER => $headers,
135 17
            CURLOPT_USERAGENT => $this->genUA(),
136
            CURLOPT_VERBOSE => (bool)$this->verbose,
137 17
            CURLOPT_URL => $this->getUrl(),
138 17
        );
139 17
        unset($curlOpts[CURLOPT_USERPWD]);
140 1
141
        return $curlOpts;
142 17
    }
143
144 17
    public function getURL()
145 9
    {
146 9
        if ($this->scheme) {
147
            $url = "$this->scheme://";
148 17
        } else {
149
            $url = '';
150 17
        }
151 9
        $url .= $this->host;
152 9
153
        if ($this->port) {
154 17
            $url .= ":$this->port";
155
        }
156
157 5
        $url .= $this->path;
158
159 5
        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...
160 5
            $url .= '?' . http_build_query($this->query);
161
        }
162 6
163
        return $url;
164 6
    }
165
166 6
    public function setConfig(CConfig $config)
167 1
    {
168
        $this->config = $config;
169
    }
170
171 5
    public function promptAuth(HttpGetResponse $res, IO\IOInterface $io)
172 3
    {
173 3
        $httpCode = $res->info['http_code'];
174
        // 404s are only handled for github
175
        if (404 === $httpCode) {
176
            return false;
177 2
        }
178 1
179
        // fail if the console is not interactive
180
        if (!$io->isInteractive() && ($httpCode === 401 || $httpCode === 403)) {
181 1
            $message = "The '{$this->getURL()}' URL required authentication.\nYou must be using the interactive console to authenticate";
182 1
            throw new Downloader\TransportException($message, $httpCode);
183 1
        }
184 1
185 1
        // fail if we already have auth
186
        if ($io->hasAuthentication($this->origin)) {
187
            throw new Downloader\TransportException("Invalid credentials for '{$this->getURL()}', aborting.", $httpCode);
188
        }
189
190
        $io->overwrite("    Authentication required (<info>$this->host</info>):");
191 2
        $username = $io->ask('      Username: ');
192
        $password = $io->askAndHideAnswer('      Password: ');
193 2
        $io->setAuthentication($this->origin, $username, $password);
194 2
        return true;
195 2
    }
196 1
197 1
    /**
198 1
     * @internal
199
     */
200 2
    public function promptAuthWithUtil($privateCode, $util, HttpGetResponse $res, IO\IOInterface $io)
201 1
    {
202
        $httpCode = $res->info['http_code'];
203 2
        $message = "\nCould not fetch {$this->getURL()}, enter your $this->origin credentials ";
204 2
        if ($privateCode === $httpCode) {
205 1
            $message .= 'to access private repos';
206
        } else {
207
            $message .= 'to go over the API rate limit';
208 1
        }
209
        if ($util->authorizeOAuth($this->origin)) {
210
            return true;
211 10
        }
212
        if ($io->isInteractive() &&
213 10
            $util->authorizeOAuthInteractively($this->origin, $message)) {
214 10
            return true;
215 9
        }
216
217 2
        throw new Downloader\TransportException("Could not authenticate against $this->origin", $httpCode);
218
    }
219 2
220 2
    public static function genUA()
221 2
    {
222 2
        static $ua;
223 2
        if ($ua) {
224
            return $ua;
225 2
        }
226
        $phpVersion = defined('HHVM_VERSION') ? 'HHVM ' . HHVM_VERSION : 'PHP ' . PHP_VERSION;
227
228
        return $ua = sprintf(
229
            'Composer/%s (%s; %s; %s)',
230
            str_replace('@package_version@', 'source', Composer::VERSION),
231
            php_uname('s'),
232
            php_uname('r'),
233
            $phpVersion
234
        );
235
    }
236
}
237