Passed
Push — master ( 16b801...e55e42 )
by Morris
11:05
created

Client::getRequestOptions()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 0
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
/**
4
 * @copyright Copyright (c) 2016, ownCloud, Inc.
5
 *
6
 * @author Lukas Reschke <[email protected]>
7
 * @author Robin Appelman <[email protected]>
8
 *
9
 * @license AGPL-3.0
10
 *
11
 * This code is free software: you can redistribute it and/or modify
12
 * it under the terms of the GNU Affero General Public License, version 3,
13
 * as published by the Free Software Foundation.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
 * GNU Affero General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Affero General Public License, version 3,
21
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
22
 *
23
 */
24
25
namespace OC\Http\Client;
26
27
use GuzzleHttp\Client as GuzzleClient;
28
use GuzzleHttp\RequestOptions;
29
use OCP\Http\Client\IClient;
30
use OCP\Http\Client\IResponse;
31
use OCP\ICertificateManager;
32
use OCP\IConfig;
33
34
/**
35
 * Class Client
36
 *
37
 * @package OC\Http
38
 */
39
class Client implements IClient {
40
	/** @var GuzzleClient */
41
	private $client;
42
	/** @var IConfig */
43
	private $config;
44
	/** @var ICertificateManager */
45
	private $certificateManager;
46
47
	/**
48
	 * @param IConfig $config
49
	 * @param ICertificateManager $certificateManager
50
	 * @param GuzzleClient $client
51
	 */
52
	public function __construct(
53
		IConfig $config,
54
		ICertificateManager $certificateManager,
55
		GuzzleClient $client
56
	) {
57
		$this->config = $config;
58
		$this->client = $client;
59
		$this->certificateManager = $certificateManager;
60
	}
61
62
	private function buildRequestOptions(array $options): array {
63
		$defaults = [
64
			RequestOptions::PROXY => $this->getProxyUri(),
65
			RequestOptions::VERIFY => $this->getCertBundle(),
66
		];
67
68
		$options = array_merge($defaults, $options);
69
70
		if (!isset($options[RequestOptions::HEADERS]['User-Agent'])) {
71
			$options[RequestOptions::HEADERS]['User-Agent'] = 'Nextcloud Server Crawler';
72
		}
73
74
		return $options;
75
	}
76
77
	private function getCertBundle(): string {
78
		if ($this->certificateManager->listCertificates() !== []) {
79
			return $this->certificateManager->getAbsoluteBundlePath();
80
		}
81
82
		// If the instance is not yet setup we need to use the static path as
83
		// $this->certificateManager->getAbsoluteBundlePath() tries to instantiiate
84
		// a view
85
		if ($this->config->getSystemValue('installed', false)) {
86
			return $this->certificateManager->getAbsoluteBundlePath(null);
87
		}
88
89
		return \OC::$SERVERROOT . '/resources/config/ca-bundle.crt';
90
	}
91
92
	/**
93
	 * Get the proxy URI
94
	 *
95
	 * @return string|null
96
	 */
97
	private function getProxyUri(): ?string {
98
		$proxyHost = $this->config->getSystemValue('proxy', null);
99
100
		if ($proxyHost === null) {
101
			return null;
102
		}
103
104
		$proxyUserPwd = $this->config->getSystemValue('proxyuserpwd', null);
105
106
		if ($proxyUserPwd === null) {
107
			return $proxyHost;
108
		}
109
110
		return $proxyUserPwd . '@' . $proxyHost;
111
	}
112
113
	/**
114
	 * Sends a GET request
115
	 *
116
	 * @param string $uri
117
	 * @param array $options Array such as
118
	 *              'query' => [
119
	 *                  'field' => 'abc',
120
	 *                  'other_field' => '123',
121
	 *                  'file_name' => fopen('/path/to/file', 'r'),
122
	 *              ],
123
	 *              'headers' => [
124
	 *                  'foo' => 'bar',
125
	 *              ],
126
	 *              'cookies' => ['
127
	 *                  'foo' => 'bar',
128
	 *              ],
129
	 *              'allow_redirects' => [
130
	 *                   'max'       => 10,  // allow at most 10 redirects.
131
	 *                   'strict'    => true,     // use "strict" RFC compliant redirects.
132
	 *                   'referer'   => true,     // add a Referer header
133
	 *                   'protocols' => ['https'] // only allow https URLs
134
	 *              ],
135
	 *              'save_to' => '/path/to/file', // save to a file or a stream
136
	 *              'verify' => true, // bool or string to CA file
137
	 *              'debug' => true,
138
	 *              'timeout' => 5,
139
	 * @return IResponse
140
	 * @throws \Exception If the request could not get completed
141
	 */
142
	public function get(string $uri, array $options = []): IResponse {
143
		$response = $this->client->request('get', $uri, $this->buildRequestOptions($options));
144
		$isStream = isset($options['stream']) && $options['stream'];
145
		return new Response($response, $isStream);
146
	}
147
148
	/**
149
	 * Sends a HEAD request
150
	 *
151
	 * @param string $uri
152
	 * @param array $options Array such as
153
	 *              'headers' => [
154
	 *                  'foo' => 'bar',
155
	 *              ],
156
	 *              'cookies' => ['
157
	 *                  'foo' => 'bar',
158
	 *              ],
159
	 *              'allow_redirects' => [
160
	 *                   'max'       => 10,  // allow at most 10 redirects.
161
	 *                   'strict'    => true,     // use "strict" RFC compliant redirects.
162
	 *                   'referer'   => true,     // add a Referer header
163
	 *                   'protocols' => ['https'] // only allow https URLs
164
	 *              ],
165
	 *              'save_to' => '/path/to/file', // save to a file or a stream
166
	 *              'verify' => true, // bool or string to CA file
167
	 *              'debug' => true,
168
	 *              'timeout' => 5,
169
	 * @return IResponse
170
	 * @throws \Exception If the request could not get completed
171
	 */
172
	public function head(string $uri, array $options = []): IResponse {
173
		$response = $this->client->request('head', $uri, $this->buildRequestOptions($options));
174
		return new Response($response);
175
	}
176
177
	/**
178
	 * Sends a POST request
179
	 *
180
	 * @param string $uri
181
	 * @param array $options Array such as
182
	 *              'body' => [
183
	 *                  'field' => 'abc',
184
	 *                  'other_field' => '123',
185
	 *                  'file_name' => fopen('/path/to/file', 'r'),
186
	 *              ],
187
	 *              'headers' => [
188
	 *                  'foo' => 'bar',
189
	 *              ],
190
	 *              'cookies' => ['
191
	 *                  'foo' => 'bar',
192
	 *              ],
193
	 *              'allow_redirects' => [
194
	 *                   'max'       => 10,  // allow at most 10 redirects.
195
	 *                   'strict'    => true,     // use "strict" RFC compliant redirects.
196
	 *                   'referer'   => true,     // add a Referer header
197
	 *                   'protocols' => ['https'] // only allow https URLs
198
	 *              ],
199
	 *              'save_to' => '/path/to/file', // save to a file or a stream
200
	 *              'verify' => true, // bool or string to CA file
201
	 *              'debug' => true,
202
	 *              'timeout' => 5,
203
	 * @return IResponse
204
	 * @throws \Exception If the request could not get completed
205
	 */
206
	public function post(string $uri, array $options = []): IResponse {
207
		if (isset($options['body']) && is_array($options['body'])) {
208
			$options['form_params'] = $options['body'];
209
			unset($options['body']);
210
		}
211
		$response = $this->client->request('post', $uri, $this->buildRequestOptions($options));
212
		return new Response($response);
213
	}
214
215
	/**
216
	 * Sends a PUT request
217
	 *
218
	 * @param string $uri
219
	 * @param array $options Array such as
220
	 *              'body' => [
221
	 *                  'field' => 'abc',
222
	 *                  'other_field' => '123',
223
	 *                  'file_name' => fopen('/path/to/file', 'r'),
224
	 *              ],
225
	 *              'headers' => [
226
	 *                  'foo' => 'bar',
227
	 *              ],
228
	 *              'cookies' => ['
229
	 *                  'foo' => 'bar',
230
	 *              ],
231
	 *              'allow_redirects' => [
232
	 *                   'max'       => 10,  // allow at most 10 redirects.
233
	 *                   'strict'    => true,     // use "strict" RFC compliant redirects.
234
	 *                   'referer'   => true,     // add a Referer header
235
	 *                   'protocols' => ['https'] // only allow https URLs
236
	 *              ],
237
	 *              'save_to' => '/path/to/file', // save to a file or a stream
238
	 *              'verify' => true, // bool or string to CA file
239
	 *              'debug' => true,
240
	 *              'timeout' => 5,
241
	 * @return IResponse
242
	 * @throws \Exception If the request could not get completed
243
	 */
244
	public function put(string $uri, array $options = []): IResponse {
245
		$response = $this->client->request('put', $uri, $this->buildRequestOptions($options));
246
		return new Response($response);
247
	}
248
249
	/**
250
	 * Sends a DELETE request
251
	 *
252
	 * @param string $uri
253
	 * @param array $options Array such as
254
	 *              'body' => [
255
	 *                  'field' => 'abc',
256
	 *                  'other_field' => '123',
257
	 *                  'file_name' => fopen('/path/to/file', 'r'),
258
	 *              ],
259
	 *              'headers' => [
260
	 *                  'foo' => 'bar',
261
	 *              ],
262
	 *              'cookies' => ['
263
	 *                  'foo' => 'bar',
264
	 *              ],
265
	 *              'allow_redirects' => [
266
	 *                   'max'       => 10,  // allow at most 10 redirects.
267
	 *                   'strict'    => true,     // use "strict" RFC compliant redirects.
268
	 *                   'referer'   => true,     // add a Referer header
269
	 *                   'protocols' => ['https'] // only allow https URLs
270
	 *              ],
271
	 *              'save_to' => '/path/to/file', // save to a file or a stream
272
	 *              'verify' => true, // bool or string to CA file
273
	 *              'debug' => true,
274
	 *              'timeout' => 5,
275
	 * @return IResponse
276
	 * @throws \Exception If the request could not get completed
277
	 */
278
	public function delete(string $uri, array $options = []): IResponse {
279
		$response = $this->client->request('delete', $uri, $this->buildRequestOptions($options));
280
		return new Response($response);
281
	}
282
283
	/**
284
	 * Sends a options request
285
	 *
286
	 * @param string $uri
287
	 * @param array $options Array such as
288
	 *              'body' => [
289
	 *                  'field' => 'abc',
290
	 *                  'other_field' => '123',
291
	 *                  'file_name' => fopen('/path/to/file', 'r'),
292
	 *              ],
293
	 *              'headers' => [
294
	 *                  'foo' => 'bar',
295
	 *              ],
296
	 *              'cookies' => ['
297
	 *                  'foo' => 'bar',
298
	 *              ],
299
	 *              'allow_redirects' => [
300
	 *                   'max'       => 10,  // allow at most 10 redirects.
301
	 *                   'strict'    => true,     // use "strict" RFC compliant redirects.
302
	 *                   'referer'   => true,     // add a Referer header
303
	 *                   'protocols' => ['https'] // only allow https URLs
304
	 *              ],
305
	 *              'save_to' => '/path/to/file', // save to a file or a stream
306
	 *              'verify' => true, // bool or string to CA file
307
	 *              'debug' => true,
308
	 *              'timeout' => 5,
309
	 * @return IResponse
310
	 * @throws \Exception If the request could not get completed
311
	 */
312
	public function options(string $uri, array $options = []): IResponse {
313
		$response = $this->client->request('options', $uri, $this->buildRequestOptions($options));
314
		return new Response($response);
315
	}
316
}
317