Completed
Pull Request — master (#348)
by Lukas
02:56
created

Fetcher::getBaseDownloadPath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 0
cts 3
cp 0
rs 10
cc 1
eloc 3
nc 1
nop 1
crap 2
1
<?php
2
/**
3
 * @author Victor Dubiniuk <[email protected]>
4
 *
5
 * @copyright Copyright (c) 2015, ownCloud, Inc.
6
 * @license AGPL-3.0
7
 *
8
 * This code is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License, version 3,
10
 * as published by the Free Software Foundation.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License, version 3,
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
19
 *
20
 */
21
22
namespace Owncloud\Updater\Utils;
23
24
use GuzzleHttp\Client;
25
use Owncloud\Updater\Utils\Feed;
26
27
class Fetcher {
28
29
	const DEFAULT_BASE_URL = 'https://updates.owncloud.com/server/';
30
31
	/**
32
	 * @var Locator $locator
33
	 */
34
	protected $locator;
35
36
	/**
37
	 * @var ConfigReader $configReader
38
	 */
39
	protected $configReader;
40
41
	/**
42
	 * @var Client $httpClient
43
	 */
44
	protected $httpClient;
45
	protected $requiredFeedEntries = [
46
		'version',
47
		'versionstring',
48
		'url'
49
	];
50
51
	/**
52
	 * Constructor
53
	 *
54
	 * @param Client $httpClient
55
	 * @param Locator $locator
56
	 * @param ConfigReader $configReader
57
	 */
58 3
	public function __construct(Client $httpClient, Locator $locator, ConfigReader $configReader){
59 3
		$this->httpClient = $httpClient;
60 3
		$this->locator = $locator;
61 3
		$this->configReader = $configReader;
62 3
	}
63
64
	/**
65
	 * Download new ownCloud package
66
	 * @param Feed $feed
67
	 * @param Callable $onProgress
68
	 * @throws \UnexpectedValueException
69
	 */
70
	public function getOwncloud(Feed $feed, callable $onProgress){
71
		if ($feed->isValid()){
72
			$downloadPath = $this->getBaseDownloadPath($feed);
73
			if (!is_writable(dirname($downloadPath))){
74
				throw new \Exception(dirname($downloadPath) . ' is not writable.');
75
			}
76
			$url = $feed->getUrl();
77
			$request = $this->httpClient->createRequest(
78
					'GET',
79
					$url,
80
					[
81
						'save_to' => $downloadPath,
82
						'timeout' => 600
83
					]
84
			);
85
			$request->getEmitter()->on('progress', $onProgress);
86
			$response = $this->httpClient->send($request);
87
			$this->validateResponse($response);
88
		}
89
	}
90
91
	/**
92
	 * Produce a local path to save the package to
93
	 * @param Feed $feed
94
	 * @return string
95
	 */
96
	public function getBaseDownloadPath(Feed $feed){
97
		$basePath = $this->locator->getDownloadBaseDir();
98
		return $basePath . '/' . $feed->getDownloadedFileName();
99
	}
100
101
	/**
102
	 * Get md5 sum for the package
103
	 * @param Feed $feed
104
	 * @return string
105
	 */
106
	public function getMd5(Feed $feed){
107
		$fullChecksum = $this->download($feed->getChecksumUrl());
108
		// we got smth like "5776cbd0a95637ade4b2c0d8694d8fca  -"
109
		//strip trailing space & dash
110
		return substr($fullChecksum, 0, 32);
111
	}
112
113
	/**
114
	 * Read update feed for new releases
115
	 * @return Feed
116
	 */
117 3
	public function getFeed(){
118 3
		$url = $this->getFeedUrl();
119 3
		$xml = $this->download($url);
120 3
		$tmp = [];
121 3
		if ($xml){
122 2
			$loadEntities = libxml_disable_entity_loader(true);
123 2
			$data = @simplexml_load_string($xml);
124 2
			libxml_disable_entity_loader($loadEntities);
125 2
			if ($data !== false){
126 1
				$tmp['version'] = (string) $data->version;
127 1
				$tmp['versionstring'] = (string) $data->versionstring;
128 1
				$tmp['url'] = (string) $data->url;
129 1
				$tmp['web'] = (string) $data->web;
130 1
			}
131 2
		}
132
133 3
		return new Feed($tmp);
134
	}
135
136 3
	public function getUpdateChannel(){
137 3
		$channel = $this->configReader->getByPath('apps.core.OC_Channel');
138 3
		if (is_null($channel)) {
139
			return $this->locator->getChannelFromVersionsFile();
140
		}
141
142 3
		return $channel;
143
	}
144
145
	/**
146
	 * Produce complete feed URL
147
	 * @return string
148
	 */
149 3
	protected function getFeedUrl(){
150 3
		$currentVersion = $this->configReader->getByPath('system.version');
151 3
		$version = explode('.', $currentVersion);
152 3
		$version['installed'] = $this->configReader->getByPath('apps.core.installedat');
153 3
		$version['updated'] = $this->configReader->getByPath('apps.core.lastupdatedat');
154 3
		$version['updatechannel'] = $this->getUpdateChannel();
155 3
		$version['edition'] = $this->configReader->getEdition();
156 3
		$version['build'] = $this->locator->getBuild();
157
158
		// Read updater server URL from config
159 3
		$updaterServerUrl = isset($this->configReader->get(['system'])['updater.server.url']) ? $this->configReader->get(['system'])['updater.server.url'] : '';
160 3
		if($updaterServerUrl === '') {
161 3
			$updaterServerUrl = self::DEFAULT_BASE_URL;
162 3
		}
163
164 3
		$url = $updaterServerUrl . '?version=' . implode('x', $version);
165 3
		return $url;
166
	}
167
168
	/**
169
	 * Get URL content
170
	 * @param string $url
171
	 * @return string
172
	 * @throws \UnexpectedValueException
173
	 */
174 3
	protected function download($url){
175 3
		$response = $this->httpClient->get($url, ['timeout' => 600]);
176 3
		$this->validateResponse($response);
177 3
		return $response->getBody()->getContents();
178
	}
179
180
	/**
181
	 * Check if request was successful
182
	 * @param \GuzzleHttp\Message\ResponseInterface $response
183
	 * @throws \UnexpectedValueException
184
	 */
185 3
	protected function validateResponse($response){
186 3
		if ($response->getStatusCode() !== 200){
187
			throw new \UnexpectedValueException(
188
					'Failed to download '
189
					. $response->getEffectiveUrl()
190
					. '. Server responded with '
191
					. $response->getStatusCode()
192
					. ' instead of 200.');
193
		}
194 3
	}
195
196
}
197