Completed
Pull Request — master (#8359)
by Robin
32:03 queued 13:52
created
lib/private/Http/Client/ClientService.php 1 patch
Indentation   +19 added lines, -19 removed lines patch added patch discarded remove patch
@@ -36,25 +36,25 @@
 block discarded – undo
36 36
  * @package OC\Http
37 37
  */
38 38
 class ClientService implements IClientService {
39
-	/** @var IConfig */
40
-	private $config;
41
-	/** @var ICertificateManager */
42
-	private $certificateManager;
39
+    /** @var IConfig */
40
+    private $config;
41
+    /** @var ICertificateManager */
42
+    private $certificateManager;
43 43
 
44
-	/**
45
-	 * @param IConfig $config
46
-	 * @param ICertificateManager $certificateManager
47
-	 */
48
-	public function __construct(IConfig $config,
49
-								ICertificateManager $certificateManager) {
50
-		$this->config = $config;
51
-		$this->certificateManager = $certificateManager;
52
-	}
44
+    /**
45
+     * @param IConfig $config
46
+     * @param ICertificateManager $certificateManager
47
+     */
48
+    public function __construct(IConfig $config,
49
+                                ICertificateManager $certificateManager) {
50
+        $this->config = $config;
51
+        $this->certificateManager = $certificateManager;
52
+    }
53 53
 
54
-	/**
55
-	 * @return Client
56
-	 */
57
-	public function newClient(): IClient {
58
-		return new Client($this->config, $this->certificateManager, new GuzzleClient(), HandlerStack::create());
59
-	}
54
+    /**
55
+     * @return Client
56
+     */
57
+    public function newClient(): IClient {
58
+        return new Client($this->config, $this->certificateManager, new GuzzleClient(), HandlerStack::create());
59
+    }
60 60
 }
Please login to merge, or discard this patch.
lib/private/Http/Client/Client.php 2 patches
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -1,5 +1,5 @@  discard block
 block discarded – undo
1 1
 <?php
2
-declare(strict_types=1);
2
+declare(strict_types = 1);
3 3
 /**
4 4
  * @copyright Copyright (c) 2016, ownCloud, Inc.
5 5
  *
@@ -75,7 +75,7 @@  discard block
 block discarded – undo
75 75
 		}
76 76
 		$this->configured = true;
77 77
 
78
-		$this->stack->push(Middleware::mapRequest(function (RequestInterface $request) {
78
+		$this->stack->push(Middleware::mapRequest(function(RequestInterface $request) {
79 79
 			return $request
80 80
 				->withHeader('User-Agent', 'Nextcloud Server Crawler');
81 81
 		}));
@@ -101,7 +101,7 @@  discard block
 block discarded – undo
101 101
 			if ($this->config->getSystemValue('installed', false)) {
102 102
 				return $this->certificateManager->getAbsoluteBundlePath(null);
103 103
 			} else {
104
-				return \OC::$SERVERROOT . '/resources/config/ca-bundle.crt';
104
+				return \OC::$SERVERROOT.'/resources/config/ca-bundle.crt';
105 105
 			}
106 106
 		}
107 107
 	}
@@ -117,7 +117,7 @@  discard block
 block discarded – undo
117 117
 		$proxyUri = '';
118 118
 
119 119
 		if ($proxyUserPwd !== null) {
120
-			$proxyUri .= $proxyUserPwd . '@';
120
+			$proxyUri .= $proxyUserPwd.'@';
121 121
 		}
122 122
 		if ($proxyHost !== null) {
123 123
 			$proxyUri .= $proxyHost;
Please login to merge, or discard this patch.
Indentation   +283 added lines, -283 removed lines patch added patch discarded remove patch
@@ -39,302 +39,302 @@
 block discarded – undo
39 39
  * @package OC\Http
40 40
  */
41 41
 class Client implements IClient {
42
-	/** @var GuzzleClient */
43
-	private $client;
44
-	/** @var IConfig */
45
-	private $config;
46
-	/** @var ICertificateManager */
47
-	private $certificateManager;
48
-	private $configured = false;
49
-	/** @var HandlerStack */
50
-	private $stack;
42
+    /** @var GuzzleClient */
43
+    private $client;
44
+    /** @var IConfig */
45
+    private $config;
46
+    /** @var ICertificateManager */
47
+    private $certificateManager;
48
+    private $configured = false;
49
+    /** @var HandlerStack */
50
+    private $stack;
51 51
 
52
-	/**
53
-	 * @param IConfig $config
54
-	 * @param ICertificateManager $certificateManager
55
-	 * @param GuzzleClient $client
56
-	 */
57
-	public function __construct(
58
-		IConfig $config,
59
-		ICertificateManager $certificateManager,
60
-		GuzzleClient $client,
61
-		HandlerStack $stack
62
-	) {
63
-		$this->config = $config;
64
-		$this->client = $client;
65
-		$this->stack = $stack;
66
-		$this->certificateManager = $certificateManager;
67
-	}
52
+    /**
53
+     * @param IConfig $config
54
+     * @param ICertificateManager $certificateManager
55
+     * @param GuzzleClient $client
56
+     */
57
+    public function __construct(
58
+        IConfig $config,
59
+        ICertificateManager $certificateManager,
60
+        GuzzleClient $client,
61
+        HandlerStack $stack
62
+    ) {
63
+        $this->config = $config;
64
+        $this->client = $client;
65
+        $this->stack = $stack;
66
+        $this->certificateManager = $certificateManager;
67
+    }
68 68
 
69
-	/**
70
-	 * Sets the default options to the client
71
-	 */
72
-	private function setDefaultOptions() {
73
-		if ($this->configured) {
74
-			return;
75
-		}
76
-		$this->configured = true;
69
+    /**
70
+     * Sets the default options to the client
71
+     */
72
+    private function setDefaultOptions() {
73
+        if ($this->configured) {
74
+            return;
75
+        }
76
+        $this->configured = true;
77 77
 
78
-		$this->stack->push(Middleware::mapRequest(function (RequestInterface $request) {
79
-			return $request
80
-				->withHeader('User-Agent', 'Nextcloud Server Crawler');
81
-		}));
82
-	}
78
+        $this->stack->push(Middleware::mapRequest(function (RequestInterface $request) {
79
+            return $request
80
+                ->withHeader('User-Agent', 'Nextcloud Server Crawler');
81
+        }));
82
+    }
83 83
 
84
-	private function getRequestOptions() {
85
-		$options = [
86
-			'verify' => $this->getCertBundle(),
87
-		];
88
-		$proxyUri = $this->getProxyUri();
89
-		if ($proxyUri !== '') {
90
-			$options['proxy'] = $proxyUri;
91
-		}
92
-		return $options;
93
-	}
84
+    private function getRequestOptions() {
85
+        $options = [
86
+            'verify' => $this->getCertBundle(),
87
+        ];
88
+        $proxyUri = $this->getProxyUri();
89
+        if ($proxyUri !== '') {
90
+            $options['proxy'] = $proxyUri;
91
+        }
92
+        return $options;
93
+    }
94 94
 
95
-	private function getCertBundle() {
96
-		if ($this->certificateManager->listCertificates() !== []) {
97
-			return $this->certificateManager->getAbsoluteBundlePath();
98
-		} else {
99
-			// If the instance is not yet setup we need to use the static path as
100
-			// $this->certificateManager->getAbsoluteBundlePath() tries to instantiiate
101
-			// a view
102
-			if ($this->config->getSystemValue('installed', false)) {
103
-				return $this->certificateManager->getAbsoluteBundlePath(null);
104
-			} else {
105
-				return \OC::$SERVERROOT . '/resources/config/ca-bundle.crt';
106
-			}
107
-		}
108
-	}
95
+    private function getCertBundle() {
96
+        if ($this->certificateManager->listCertificates() !== []) {
97
+            return $this->certificateManager->getAbsoluteBundlePath();
98
+        } else {
99
+            // If the instance is not yet setup we need to use the static path as
100
+            // $this->certificateManager->getAbsoluteBundlePath() tries to instantiiate
101
+            // a view
102
+            if ($this->config->getSystemValue('installed', false)) {
103
+                return $this->certificateManager->getAbsoluteBundlePath(null);
104
+            } else {
105
+                return \OC::$SERVERROOT . '/resources/config/ca-bundle.crt';
106
+            }
107
+        }
108
+    }
109 109
 
110
-	/**
111
-	 * Get the proxy URI
112
-	 *
113
-	 * @return string
114
-	 */
115
-	private function getProxyUri(): string {
116
-		$proxyHost = $this->config->getSystemValue('proxy', null);
117
-		$proxyUserPwd = $this->config->getSystemValue('proxyuserpwd', null);
118
-		$proxyUri = '';
110
+    /**
111
+     * Get the proxy URI
112
+     *
113
+     * @return string
114
+     */
115
+    private function getProxyUri(): string {
116
+        $proxyHost = $this->config->getSystemValue('proxy', null);
117
+        $proxyUserPwd = $this->config->getSystemValue('proxyuserpwd', null);
118
+        $proxyUri = '';
119 119
 
120
-		if ($proxyUserPwd !== null) {
121
-			$proxyUri .= $proxyUserPwd . '@';
122
-		}
123
-		if ($proxyHost !== null) {
124
-			$proxyUri .= $proxyHost;
125
-		}
120
+        if ($proxyUserPwd !== null) {
121
+            $proxyUri .= $proxyUserPwd . '@';
122
+        }
123
+        if ($proxyHost !== null) {
124
+            $proxyUri .= $proxyHost;
125
+        }
126 126
 
127
-		return $proxyUri;
128
-	}
127
+        return $proxyUri;
128
+    }
129 129
 
130
-	/**
131
-	 * Sends a GET request
132
-	 *
133
-	 * @param string $uri
134
-	 * @param array $options Array such as
135
-	 *              'query' => [
136
-	 *                  'field' => 'abc',
137
-	 *                  'other_field' => '123',
138
-	 *                  'file_name' => fopen('/path/to/file', 'r'),
139
-	 *              ],
140
-	 *              'headers' => [
141
-	 *                  'foo' => 'bar',
142
-	 *              ],
143
-	 *              'cookies' => ['
144
-	 *                  'foo' => 'bar',
145
-	 *              ],
146
-	 *              'allow_redirects' => [
147
-	 *                   'max'       => 10,  // allow at most 10 redirects.
148
-	 *                   'strict'    => true,     // use "strict" RFC compliant redirects.
149
-	 *                   'referer'   => true,     // add a Referer header
150
-	 *                   'protocols' => ['https'] // only allow https URLs
151
-	 *              ],
152
-	 *              'save_to' => '/path/to/file', // save to a file or a stream
153
-	 *              'verify' => true, // bool or string to CA file
154
-	 *              'debug' => true,
155
-	 *              'timeout' => 5,
156
-	 * @return IResponse
157
-	 * @throws \Exception If the request could not get completed
158
-	 */
159
-	public function get(string $uri, array $options = []): IResponse {
160
-		$this->setDefaultOptions();
161
-		$response = $this->client->request('get', $uri, array_merge($options, $this->getRequestOptions()));
162
-		$isStream = isset($options['stream']) && $options['stream'];
163
-		return new Response($response, $isStream);
164
-	}
130
+    /**
131
+     * Sends a GET request
132
+     *
133
+     * @param string $uri
134
+     * @param array $options Array such as
135
+     *              'query' => [
136
+     *                  'field' => 'abc',
137
+     *                  'other_field' => '123',
138
+     *                  'file_name' => fopen('/path/to/file', 'r'),
139
+     *              ],
140
+     *              'headers' => [
141
+     *                  'foo' => 'bar',
142
+     *              ],
143
+     *              'cookies' => ['
144
+     *                  'foo' => 'bar',
145
+     *              ],
146
+     *              'allow_redirects' => [
147
+     *                   'max'       => 10,  // allow at most 10 redirects.
148
+     *                   'strict'    => true,     // use "strict" RFC compliant redirects.
149
+     *                   'referer'   => true,     // add a Referer header
150
+     *                   'protocols' => ['https'] // only allow https URLs
151
+     *              ],
152
+     *              'save_to' => '/path/to/file', // save to a file or a stream
153
+     *              'verify' => true, // bool or string to CA file
154
+     *              'debug' => true,
155
+     *              'timeout' => 5,
156
+     * @return IResponse
157
+     * @throws \Exception If the request could not get completed
158
+     */
159
+    public function get(string $uri, array $options = []): IResponse {
160
+        $this->setDefaultOptions();
161
+        $response = $this->client->request('get', $uri, array_merge($options, $this->getRequestOptions()));
162
+        $isStream = isset($options['stream']) && $options['stream'];
163
+        return new Response($response, $isStream);
164
+    }
165 165
 
166
-	/**
167
-	 * Sends a HEAD request
168
-	 *
169
-	 * @param string $uri
170
-	 * @param array $options Array such as
171
-	 *              'headers' => [
172
-	 *                  'foo' => 'bar',
173
-	 *              ],
174
-	 *              'cookies' => ['
175
-	 *                  'foo' => 'bar',
176
-	 *              ],
177
-	 *              'allow_redirects' => [
178
-	 *                   'max'       => 10,  // allow at most 10 redirects.
179
-	 *                   'strict'    => true,     // use "strict" RFC compliant redirects.
180
-	 *                   'referer'   => true,     // add a Referer header
181
-	 *                   'protocols' => ['https'] // only allow https URLs
182
-	 *              ],
183
-	 *              'save_to' => '/path/to/file', // save to a file or a stream
184
-	 *              'verify' => true, // bool or string to CA file
185
-	 *              'debug' => true,
186
-	 *              'timeout' => 5,
187
-	 * @return IResponse
188
-	 * @throws \Exception If the request could not get completed
189
-	 */
190
-	public function head(string $uri, array $options = []): IResponse {
191
-		$this->setDefaultOptions();
192
-		$response = $this->client->request('head', $uri, array_merge($options, $this->getRequestOptions()));
193
-		return new Response($response);
194
-	}
166
+    /**
167
+     * Sends a HEAD request
168
+     *
169
+     * @param string $uri
170
+     * @param array $options Array such as
171
+     *              'headers' => [
172
+     *                  'foo' => 'bar',
173
+     *              ],
174
+     *              'cookies' => ['
175
+     *                  'foo' => 'bar',
176
+     *              ],
177
+     *              'allow_redirects' => [
178
+     *                   'max'       => 10,  // allow at most 10 redirects.
179
+     *                   'strict'    => true,     // use "strict" RFC compliant redirects.
180
+     *                   'referer'   => true,     // add a Referer header
181
+     *                   'protocols' => ['https'] // only allow https URLs
182
+     *              ],
183
+     *              'save_to' => '/path/to/file', // save to a file or a stream
184
+     *              'verify' => true, // bool or string to CA file
185
+     *              'debug' => true,
186
+     *              'timeout' => 5,
187
+     * @return IResponse
188
+     * @throws \Exception If the request could not get completed
189
+     */
190
+    public function head(string $uri, array $options = []): IResponse {
191
+        $this->setDefaultOptions();
192
+        $response = $this->client->request('head', $uri, array_merge($options, $this->getRequestOptions()));
193
+        return new Response($response);
194
+    }
195 195
 
196
-	/**
197
-	 * Sends a POST request
198
-	 *
199
-	 * @param string $uri
200
-	 * @param array $options Array such as
201
-	 *              'body' => [
202
-	 *                  'field' => 'abc',
203
-	 *                  'other_field' => '123',
204
-	 *                  'file_name' => fopen('/path/to/file', 'r'),
205
-	 *              ],
206
-	 *              'headers' => [
207
-	 *                  'foo' => 'bar',
208
-	 *              ],
209
-	 *              'cookies' => ['
210
-	 *                  'foo' => 'bar',
211
-	 *              ],
212
-	 *              'allow_redirects' => [
213
-	 *                   'max'       => 10,  // allow at most 10 redirects.
214
-	 *                   'strict'    => true,     // use "strict" RFC compliant redirects.
215
-	 *                   'referer'   => true,     // add a Referer header
216
-	 *                   'protocols' => ['https'] // only allow https URLs
217
-	 *              ],
218
-	 *              'save_to' => '/path/to/file', // save to a file or a stream
219
-	 *              'verify' => true, // bool or string to CA file
220
-	 *              'debug' => true,
221
-	 *              'timeout' => 5,
222
-	 * @return IResponse
223
-	 * @throws \Exception If the request could not get completed
224
-	 */
225
-	public function post(string $uri, array $options = []): IResponse {
226
-		$this->setDefaultOptions();
227
-		if (isset($options['body']) && is_array($options['body'])) {
228
-			$options['form_params'] = $options['body'];
229
-			unset($options['body']);
230
-		}
231
-		$response = $this->client->request('post', $uri, array_merge($options, $this->getRequestOptions()));
232
-		return new Response($response);
233
-	}
196
+    /**
197
+     * Sends a POST request
198
+     *
199
+     * @param string $uri
200
+     * @param array $options Array such as
201
+     *              'body' => [
202
+     *                  'field' => 'abc',
203
+     *                  'other_field' => '123',
204
+     *                  'file_name' => fopen('/path/to/file', 'r'),
205
+     *              ],
206
+     *              'headers' => [
207
+     *                  'foo' => 'bar',
208
+     *              ],
209
+     *              'cookies' => ['
210
+     *                  'foo' => 'bar',
211
+     *              ],
212
+     *              'allow_redirects' => [
213
+     *                   'max'       => 10,  // allow at most 10 redirects.
214
+     *                   'strict'    => true,     // use "strict" RFC compliant redirects.
215
+     *                   'referer'   => true,     // add a Referer header
216
+     *                   'protocols' => ['https'] // only allow https URLs
217
+     *              ],
218
+     *              'save_to' => '/path/to/file', // save to a file or a stream
219
+     *              'verify' => true, // bool or string to CA file
220
+     *              'debug' => true,
221
+     *              'timeout' => 5,
222
+     * @return IResponse
223
+     * @throws \Exception If the request could not get completed
224
+     */
225
+    public function post(string $uri, array $options = []): IResponse {
226
+        $this->setDefaultOptions();
227
+        if (isset($options['body']) && is_array($options['body'])) {
228
+            $options['form_params'] = $options['body'];
229
+            unset($options['body']);
230
+        }
231
+        $response = $this->client->request('post', $uri, array_merge($options, $this->getRequestOptions()));
232
+        return new Response($response);
233
+    }
234 234
 
235
-	/**
236
-	 * Sends a PUT request
237
-	 *
238
-	 * @param string $uri
239
-	 * @param array $options Array such as
240
-	 *              'body' => [
241
-	 *                  'field' => 'abc',
242
-	 *                  'other_field' => '123',
243
-	 *                  'file_name' => fopen('/path/to/file', 'r'),
244
-	 *              ],
245
-	 *              'headers' => [
246
-	 *                  'foo' => 'bar',
247
-	 *              ],
248
-	 *              'cookies' => ['
249
-	 *                  'foo' => 'bar',
250
-	 *              ],
251
-	 *              'allow_redirects' => [
252
-	 *                   'max'       => 10,  // allow at most 10 redirects.
253
-	 *                   'strict'    => true,     // use "strict" RFC compliant redirects.
254
-	 *                   'referer'   => true,     // add a Referer header
255
-	 *                   'protocols' => ['https'] // only allow https URLs
256
-	 *              ],
257
-	 *              'save_to' => '/path/to/file', // save to a file or a stream
258
-	 *              'verify' => true, // bool or string to CA file
259
-	 *              'debug' => true,
260
-	 *              'timeout' => 5,
261
-	 * @return IResponse
262
-	 * @throws \Exception If the request could not get completed
263
-	 */
264
-	public function put(string $uri, array $options = []): IResponse {
265
-		$this->setDefaultOptions();
266
-		$response = $this->client->request('put', $uri, array_merge($options, $this->getRequestOptions()));
267
-		return new Response($response);
268
-	}
235
+    /**
236
+     * Sends a PUT request
237
+     *
238
+     * @param string $uri
239
+     * @param array $options Array such as
240
+     *              'body' => [
241
+     *                  'field' => 'abc',
242
+     *                  'other_field' => '123',
243
+     *                  'file_name' => fopen('/path/to/file', 'r'),
244
+     *              ],
245
+     *              'headers' => [
246
+     *                  'foo' => 'bar',
247
+     *              ],
248
+     *              'cookies' => ['
249
+     *                  'foo' => 'bar',
250
+     *              ],
251
+     *              'allow_redirects' => [
252
+     *                   'max'       => 10,  // allow at most 10 redirects.
253
+     *                   'strict'    => true,     // use "strict" RFC compliant redirects.
254
+     *                   'referer'   => true,     // add a Referer header
255
+     *                   'protocols' => ['https'] // only allow https URLs
256
+     *              ],
257
+     *              'save_to' => '/path/to/file', // save to a file or a stream
258
+     *              'verify' => true, // bool or string to CA file
259
+     *              'debug' => true,
260
+     *              'timeout' => 5,
261
+     * @return IResponse
262
+     * @throws \Exception If the request could not get completed
263
+     */
264
+    public function put(string $uri, array $options = []): IResponse {
265
+        $this->setDefaultOptions();
266
+        $response = $this->client->request('put', $uri, array_merge($options, $this->getRequestOptions()));
267
+        return new Response($response);
268
+    }
269 269
 
270
-	/**
271
-	 * Sends a DELETE request
272
-	 *
273
-	 * @param string $uri
274
-	 * @param array $options Array such as
275
-	 *              'body' => [
276
-	 *                  'field' => 'abc',
277
-	 *                  'other_field' => '123',
278
-	 *                  'file_name' => fopen('/path/to/file', 'r'),
279
-	 *              ],
280
-	 *              'headers' => [
281
-	 *                  'foo' => 'bar',
282
-	 *              ],
283
-	 *              'cookies' => ['
284
-	 *                  'foo' => 'bar',
285
-	 *              ],
286
-	 *              'allow_redirects' => [
287
-	 *                   'max'       => 10,  // allow at most 10 redirects.
288
-	 *                   'strict'    => true,     // use "strict" RFC compliant redirects.
289
-	 *                   'referer'   => true,     // add a Referer header
290
-	 *                   'protocols' => ['https'] // only allow https URLs
291
-	 *              ],
292
-	 *              'save_to' => '/path/to/file', // save to a file or a stream
293
-	 *              'verify' => true, // bool or string to CA file
294
-	 *              'debug' => true,
295
-	 *              'timeout' => 5,
296
-	 * @return IResponse
297
-	 * @throws \Exception If the request could not get completed
298
-	 */
299
-	public function delete(string $uri, array $options = []): IResponse {
300
-		$this->setDefaultOptions();
301
-		$response = $this->client->request('delete', $uri, array_merge($options, $this->getRequestOptions()));
302
-		return new Response($response);
303
-	}
270
+    /**
271
+     * Sends a DELETE request
272
+     *
273
+     * @param string $uri
274
+     * @param array $options Array such as
275
+     *              'body' => [
276
+     *                  'field' => 'abc',
277
+     *                  'other_field' => '123',
278
+     *                  'file_name' => fopen('/path/to/file', 'r'),
279
+     *              ],
280
+     *              'headers' => [
281
+     *                  'foo' => 'bar',
282
+     *              ],
283
+     *              'cookies' => ['
284
+     *                  'foo' => 'bar',
285
+     *              ],
286
+     *              'allow_redirects' => [
287
+     *                   'max'       => 10,  // allow at most 10 redirects.
288
+     *                   'strict'    => true,     // use "strict" RFC compliant redirects.
289
+     *                   'referer'   => true,     // add a Referer header
290
+     *                   'protocols' => ['https'] // only allow https URLs
291
+     *              ],
292
+     *              'save_to' => '/path/to/file', // save to a file or a stream
293
+     *              'verify' => true, // bool or string to CA file
294
+     *              'debug' => true,
295
+     *              'timeout' => 5,
296
+     * @return IResponse
297
+     * @throws \Exception If the request could not get completed
298
+     */
299
+    public function delete(string $uri, array $options = []): IResponse {
300
+        $this->setDefaultOptions();
301
+        $response = $this->client->request('delete', $uri, array_merge($options, $this->getRequestOptions()));
302
+        return new Response($response);
303
+    }
304 304
 
305 305
 
306
-	/**
307
-	 * Sends a options request
308
-	 *
309
-	 * @param string $uri
310
-	 * @param array $options Array such as
311
-	 *              'body' => [
312
-	 *                  'field' => 'abc',
313
-	 *                  'other_field' => '123',
314
-	 *                  'file_name' => fopen('/path/to/file', 'r'),
315
-	 *              ],
316
-	 *              'headers' => [
317
-	 *                  'foo' => 'bar',
318
-	 *              ],
319
-	 *              'cookies' => ['
320
-	 *                  'foo' => 'bar',
321
-	 *              ],
322
-	 *              'allow_redirects' => [
323
-	 *                   'max'       => 10,  // allow at most 10 redirects.
324
-	 *                   'strict'    => true,     // use "strict" RFC compliant redirects.
325
-	 *                   'referer'   => true,     // add a Referer header
326
-	 *                   'protocols' => ['https'] // only allow https URLs
327
-	 *              ],
328
-	 *              'save_to' => '/path/to/file', // save to a file or a stream
329
-	 *              'verify' => true, // bool or string to CA file
330
-	 *              'debug' => true,
331
-	 *              'timeout' => 5,
332
-	 * @return IResponse
333
-	 * @throws \Exception If the request could not get completed
334
-	 */
335
-	public function options(string $uri, array $options = []): IResponse {
336
-		$this->setDefaultOptions();
337
-		$response = $this->client->request('options', $uri, array_merge($options, $this->getRequestOptions()));
338
-		return new Response($response);
339
-	}
306
+    /**
307
+     * Sends a options request
308
+     *
309
+     * @param string $uri
310
+     * @param array $options Array such as
311
+     *              'body' => [
312
+     *                  'field' => 'abc',
313
+     *                  'other_field' => '123',
314
+     *                  'file_name' => fopen('/path/to/file', 'r'),
315
+     *              ],
316
+     *              'headers' => [
317
+     *                  'foo' => 'bar',
318
+     *              ],
319
+     *              'cookies' => ['
320
+     *                  'foo' => 'bar',
321
+     *              ],
322
+     *              'allow_redirects' => [
323
+     *                   'max'       => 10,  // allow at most 10 redirects.
324
+     *                   'strict'    => true,     // use "strict" RFC compliant redirects.
325
+     *                   'referer'   => true,     // add a Referer header
326
+     *                   'protocols' => ['https'] // only allow https URLs
327
+     *              ],
328
+     *              'save_to' => '/path/to/file', // save to a file or a stream
329
+     *              'verify' => true, // bool or string to CA file
330
+     *              'debug' => true,
331
+     *              'timeout' => 5,
332
+     * @return IResponse
333
+     * @throws \Exception If the request could not get completed
334
+     */
335
+    public function options(string $uri, array $options = []): IResponse {
336
+        $this->setDefaultOptions();
337
+        $response = $this->client->request('options', $uri, array_merge($options, $this->getRequestOptions()));
338
+        return new Response($response);
339
+    }
340 340
 }
Please login to merge, or discard this patch.
lib/private/Http/Client/Response.php 1 patch
Indentation   +41 added lines, -41 removed lines patch added patch discarded remove patch
@@ -33,51 +33,51 @@
 block discarded – undo
33 33
  * @package OC\Http
34 34
  */
35 35
 class Response implements IResponse {
36
-	/** @var ResponseInterface */
37
-	private $response;
36
+    /** @var ResponseInterface */
37
+    private $response;
38 38
 
39
-	/**
40
-	 * @var bool
41
-	 */
42
-	private $stream;
39
+    /**
40
+     * @var bool
41
+     */
42
+    private $stream;
43 43
 
44
-	/**
45
-	 * @param ResponseInterface $response
46
-	 * @param bool $stream
47
-	 */
48
-	public function __construct(ResponseInterface $response, $stream = false) {
49
-		$this->response = $response;
50
-		$this->stream = $stream;
51
-	}
44
+    /**
45
+     * @param ResponseInterface $response
46
+     * @param bool $stream
47
+     */
48
+    public function __construct(ResponseInterface $response, $stream = false) {
49
+        $this->response = $response;
50
+        $this->stream = $stream;
51
+    }
52 52
 
53
-	/**
54
-	 * @return string|resource
55
-	 */
56
-	public function getBody() {
57
-		return $this->stream ?
58
-			$this->response->getBody()->detach():
59
-			$this->response->getBody()->getContents();
60
-	}
53
+    /**
54
+     * @return string|resource
55
+     */
56
+    public function getBody() {
57
+        return $this->stream ?
58
+            $this->response->getBody()->detach():
59
+            $this->response->getBody()->getContents();
60
+    }
61 61
 
62
-	/**
63
-	 * @return int
64
-	 */
65
-	public function getStatusCode(): int {
66
-		return $this->response->getStatusCode();
67
-	}
62
+    /**
63
+     * @return int
64
+     */
65
+    public function getStatusCode(): int {
66
+        return $this->response->getStatusCode();
67
+    }
68 68
 
69
-	/**
70
-	 * @param string $key
71
-	 * @return string
72
-	 */
73
-	public function getHeader(string $key): string {
74
-		return $this->response->getHeader($key)[0];
75
-	}
69
+    /**
70
+     * @param string $key
71
+     * @return string
72
+     */
73
+    public function getHeader(string $key): string {
74
+        return $this->response->getHeader($key)[0];
75
+    }
76 76
 
77
-	/**
78
-	 * @return array
79
-	 */
80
-	public function getHeaders(): array {
81
-		return $this->response->getHeaders();
82
-	}
77
+    /**
78
+     * @return array
79
+     */
80
+    public function getHeaders(): array {
81
+        return $this->response->getHeaders();
82
+    }
83 83
 }
Please login to merge, or discard this patch.
lib/private/Files/Storage/DAV.php 2 patches
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -34,7 +34,6 @@
 block discarded – undo
34 34
 namespace OC\Files\Storage;
35 35
 
36 36
 use Exception;
37
-use GuzzleHttp\Exception\RequestException;
38 37
 use Psr\Http\Message\ResponseInterface;
39 38
 use Icewind\Streams\CallbackWrapper;
40 39
 use OC\Files\Filesystem;
Please login to merge, or discard this patch.
Indentation   +796 added lines, -796 removed lines patch added patch discarded remove patch
@@ -57,801 +57,801 @@
 block discarded – undo
57 57
  * @package OC\Files\Storage
58 58
  */
59 59
 class DAV extends Common {
60
-	/** @var string */
61
-	protected $password;
62
-	/** @var string */
63
-	protected $user;
64
-	/** @var string */
65
-	protected $authType;
66
-	/** @var string */
67
-	protected $host;
68
-	/** @var bool */
69
-	protected $secure;
70
-	/** @var string */
71
-	protected $root;
72
-	/** @var string */
73
-	protected $certPath;
74
-	/** @var bool */
75
-	protected $ready;
76
-	/** @var Client */
77
-	protected $client;
78
-	/** @var ArrayCache */
79
-	protected $statCache;
80
-	/** @var \OCP\Http\Client\IClientService */
81
-	protected $httpClientService;
82
-
83
-	/**
84
-	 * @param array $params
85
-	 * @throws \Exception
86
-	 */
87
-	public function __construct($params) {
88
-		$this->statCache = new ArrayCache();
89
-		$this->httpClientService = \OC::$server->getHTTPClientService();
90
-		if (isset($params['host']) && isset($params['user']) && isset($params['password'])) {
91
-			$host = $params['host'];
92
-			//remove leading http[s], will be generated in createBaseUri()
93
-			if (substr($host, 0, 8) == "https://") $host = substr($host, 8);
94
-			else if (substr($host, 0, 7) == "http://") $host = substr($host, 7);
95
-			$this->host = $host;
96
-			$this->user = $params['user'];
97
-			$this->password = $params['password'];
98
-			if (isset($params['authType'])) {
99
-				$this->authType = $params['authType'];
100
-			}
101
-			if (isset($params['secure'])) {
102
-				if (is_string($params['secure'])) {
103
-					$this->secure = ($params['secure'] === 'true');
104
-				} else {
105
-					$this->secure = (bool)$params['secure'];
106
-				}
107
-			} else {
108
-				$this->secure = false;
109
-			}
110
-			if ($this->secure === true) {
111
-				// inject mock for testing
112
-				$certManager = \OC::$server->getCertificateManager();
113
-				if (is_null($certManager)) { //no user
114
-					$certManager = \OC::$server->getCertificateManager(null);
115
-				}
116
-				$certPath = $certManager->getAbsoluteBundlePath();
117
-				if (file_exists($certPath)) {
118
-					$this->certPath = $certPath;
119
-				}
120
-			}
121
-			$this->root = $params['root'] ?? '/';
122
-			$this->root = '/' . ltrim($this->root, '/');
123
-			$this->root = rtrim($this->root, '/') . '/';
124
-		} else {
125
-			throw new \Exception('Invalid webdav storage configuration');
126
-		}
127
-	}
128
-
129
-	protected function init() {
130
-		if ($this->ready) {
131
-			return;
132
-		}
133
-		$this->ready = true;
134
-
135
-		$settings = [
136
-			'baseUri' => $this->createBaseUri(),
137
-			'userName' => $this->user,
138
-			'password' => $this->password,
139
-		];
140
-		if (isset($this->authType)) {
141
-			$settings['authType'] = $this->authType;
142
-		}
143
-
144
-		$proxy = \OC::$server->getConfig()->getSystemValue('proxy', '');
145
-		if ($proxy !== '') {
146
-			$settings['proxy'] = $proxy;
147
-		}
148
-
149
-		$this->client = new Client($settings);
150
-		$this->client->setThrowExceptions(true);
151
-		if ($this->secure === true && $this->certPath) {
152
-			$this->client->addCurlSetting(CURLOPT_CAINFO, $this->certPath);
153
-		}
154
-	}
155
-
156
-	/**
157
-	 * Clear the stat cache
158
-	 */
159
-	public function clearStatCache() {
160
-		$this->statCache->clear();
161
-	}
162
-
163
-	/** {@inheritdoc} */
164
-	public function getId() {
165
-		return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root;
166
-	}
167
-
168
-	/** {@inheritdoc} */
169
-	public function createBaseUri() {
170
-		$baseUri = 'http';
171
-		if ($this->secure) {
172
-			$baseUri .= 's';
173
-		}
174
-		$baseUri .= '://' . $this->host . $this->root;
175
-		return $baseUri;
176
-	}
177
-
178
-	/** {@inheritdoc} */
179
-	public function mkdir($path) {
180
-		$this->init();
181
-		$path = $this->cleanPath($path);
182
-		$result = $this->simpleResponse('MKCOL', $path, null, 201);
183
-		if ($result) {
184
-			$this->statCache->set($path, true);
185
-		}
186
-		return $result;
187
-	}
188
-
189
-	/** {@inheritdoc} */
190
-	public function rmdir($path) {
191
-		$this->init();
192
-		$path = $this->cleanPath($path);
193
-		// FIXME: some WebDAV impl return 403 when trying to DELETE
194
-		// a non-empty folder
195
-		$result = $this->simpleResponse('DELETE', $path . '/', null, 204);
196
-		$this->statCache->clear($path . '/');
197
-		$this->statCache->remove($path);
198
-		return $result;
199
-	}
200
-
201
-	/** {@inheritdoc} */
202
-	public function opendir($path) {
203
-		$this->init();
204
-		$path = $this->cleanPath($path);
205
-		try {
206
-			$response = $this->client->propFind(
207
-				$this->encodePath($path),
208
-				['{DAV:}href'],
209
-				1
210
-			);
211
-			if ($response === false) {
212
-				return false;
213
-			}
214
-			$content = [];
215
-			$files = array_keys($response);
216
-			array_shift($files); //the first entry is the current directory
217
-
218
-			if (!$this->statCache->hasKey($path)) {
219
-				$this->statCache->set($path, true);
220
-			}
221
-			foreach ($files as $file) {
222
-				$file = urldecode($file);
223
-				// do not store the real entry, we might not have all properties
224
-				if (!$this->statCache->hasKey($path)) {
225
-					$this->statCache->set($file, true);
226
-				}
227
-				$file = basename($file);
228
-				$content[] = $file;
229
-			}
230
-			return IteratorDirectory::wrap($content);
231
-		} catch (\Exception $e) {
232
-			$this->convertException($e, $path);
233
-		}
234
-		return false;
235
-	}
236
-
237
-	/**
238
-	 * Propfind call with cache handling.
239
-	 *
240
-	 * First checks if information is cached.
241
-	 * If not, request it from the server then store to cache.
242
-	 *
243
-	 * @param string $path path to propfind
244
-	 *
245
-	 * @return array|boolean propfind response or false if the entry was not found
246
-	 *
247
-	 * @throws ClientHttpException
248
-	 */
249
-	protected function propfind($path) {
250
-		$path = $this->cleanPath($path);
251
-		$cachedResponse = $this->statCache->get($path);
252
-		// we either don't know it, or we know it exists but need more details
253
-		if (is_null($cachedResponse) || $cachedResponse === true) {
254
-			$this->init();
255
-			try {
256
-				$response = $this->client->propFind(
257
-					$this->encodePath($path),
258
-					array(
259
-						'{DAV:}getlastmodified',
260
-						'{DAV:}getcontentlength',
261
-						'{DAV:}getcontenttype',
262
-						'{http://owncloud.org/ns}permissions',
263
-						'{http://open-collaboration-services.org/ns}share-permissions',
264
-						'{DAV:}resourcetype',
265
-						'{DAV:}getetag',
266
-					)
267
-				);
268
-				$this->statCache->set($path, $response);
269
-			} catch (ClientHttpException $e) {
270
-				if ($e->getHttpStatus() === 404) {
271
-					$this->statCache->clear($path . '/');
272
-					$this->statCache->set($path, false);
273
-					return false;
274
-				}
275
-				$this->convertException($e, $path);
276
-			} catch (\Exception $e) {
277
-				$this->convertException($e, $path);
278
-			}
279
-		} else {
280
-			$response = $cachedResponse;
281
-		}
282
-		return $response;
283
-	}
284
-
285
-	/** {@inheritdoc} */
286
-	public function filetype($path) {
287
-		try {
288
-			$response = $this->propfind($path);
289
-			if ($response === false) {
290
-				return false;
291
-			}
292
-			$responseType = [];
293
-			if (isset($response["{DAV:}resourcetype"])) {
294
-				/** @var ResourceType[] $response */
295
-				$responseType = $response["{DAV:}resourcetype"]->getValue();
296
-			}
297
-			return (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
298
-		} catch (\Exception $e) {
299
-			$this->convertException($e, $path);
300
-		}
301
-		return false;
302
-	}
303
-
304
-	/** {@inheritdoc} */
305
-	public function file_exists($path) {
306
-		try {
307
-			$path = $this->cleanPath($path);
308
-			$cachedState = $this->statCache->get($path);
309
-			if ($cachedState === false) {
310
-				// we know the file doesn't exist
311
-				return false;
312
-			} else if (!is_null($cachedState)) {
313
-				return true;
314
-			}
315
-			// need to get from server
316
-			return ($this->propfind($path) !== false);
317
-		} catch (\Exception $e) {
318
-			$this->convertException($e, $path);
319
-		}
320
-		return false;
321
-	}
322
-
323
-	/** {@inheritdoc} */
324
-	public function unlink($path) {
325
-		$this->init();
326
-		$path = $this->cleanPath($path);
327
-		$result = $this->simpleResponse('DELETE', $path, null, 204);
328
-		$this->statCache->clear($path . '/');
329
-		$this->statCache->remove($path);
330
-		return $result;
331
-	}
332
-
333
-	/** {@inheritdoc} */
334
-	public function fopen($path, $mode) {
335
-		$this->init();
336
-		$path = $this->cleanPath($path);
337
-		switch ($mode) {
338
-			case 'r':
339
-			case 'rb':
340
-				try {
341
-					$response = $this->httpClientService
342
-						->newClient()
343
-						->get($this->createBaseUri() . $this->encodePath($path), [
344
-							'auth' => [$this->user, $this->password],
345
-							'stream' => true
346
-						]);
347
-				} catch (\GuzzleHttp\Exception\ClientException $e) {
348
-					if ($e->getResponse() instanceof ResponseInterface
349
-						&& $e->getResponse()->getStatusCode() === 404) {
350
-						return false;
351
-					} else {
352
-						throw $e;
353
-					}
354
-				}
355
-
356
-				if ($response->getStatusCode() !== Http::STATUS_OK) {
357
-					if ($response->getStatusCode() === Http::STATUS_LOCKED) {
358
-						throw new \OCP\Lock\LockedException($path);
359
-					} else {
360
-						Util::writeLog("webdav client", 'Guzzle get returned status code ' . $response->getStatusCode(), Util::ERROR);
361
-					}
362
-				}
363
-
364
-				return $response->getBody();
365
-			case 'w':
366
-			case 'wb':
367
-			case 'a':
368
-			case 'ab':
369
-			case 'r+':
370
-			case 'w+':
371
-			case 'wb+':
372
-			case 'a+':
373
-			case 'x':
374
-			case 'x+':
375
-			case 'c':
376
-			case 'c+':
377
-				//emulate these
378
-				$tempManager = \OC::$server->getTempManager();
379
-				if (strrpos($path, '.') !== false) {
380
-					$ext = substr($path, strrpos($path, '.'));
381
-				} else {
382
-					$ext = '';
383
-				}
384
-				if ($this->file_exists($path)) {
385
-					if (!$this->isUpdatable($path)) {
386
-						return false;
387
-					}
388
-					if ($mode === 'w' or $mode === 'w+') {
389
-						$tmpFile = $tempManager->getTemporaryFile($ext);
390
-					} else {
391
-						$tmpFile = $this->getCachedFile($path);
392
-					}
393
-				} else {
394
-					if (!$this->isCreatable(dirname($path))) {
395
-						return false;
396
-					}
397
-					$tmpFile = $tempManager->getTemporaryFile($ext);
398
-				}
399
-				$handle = fopen($tmpFile, $mode);
400
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
401
-					$this->writeBack($tmpFile, $path);
402
-				});
403
-		}
404
-	}
405
-
406
-	/**
407
-	 * @param string $tmpFile
408
-	 */
409
-	public function writeBack($tmpFile, $path) {
410
-		$this->uploadFile($tmpFile, $path);
411
-		unlink($tmpFile);
412
-	}
413
-
414
-	/** {@inheritdoc} */
415
-	public function free_space($path) {
416
-		$this->init();
417
-		$path = $this->cleanPath($path);
418
-		try {
419
-			// TODO: cacheable ?
420
-			$response = $this->client->propfind($this->encodePath($path), ['{DAV:}quota-available-bytes']);
421
-			if ($response === false) {
422
-				return FileInfo::SPACE_UNKNOWN;
423
-			}
424
-			if (isset($response['{DAV:}quota-available-bytes'])) {
425
-				return (int)$response['{DAV:}quota-available-bytes'];
426
-			} else {
427
-				return FileInfo::SPACE_UNKNOWN;
428
-			}
429
-		} catch (\Exception $e) {
430
-			return FileInfo::SPACE_UNKNOWN;
431
-		}
432
-	}
433
-
434
-	/** {@inheritdoc} */
435
-	public function touch($path, $mtime = null) {
436
-		$this->init();
437
-		if (is_null($mtime)) {
438
-			$mtime = time();
439
-		}
440
-		$path = $this->cleanPath($path);
441
-
442
-		// if file exists, update the mtime, else create a new empty file
443
-		if ($this->file_exists($path)) {
444
-			try {
445
-				$this->statCache->remove($path);
446
-				$this->client->proppatch($this->encodePath($path), ['{DAV:}lastmodified' => $mtime]);
447
-				// non-owncloud clients might not have accepted the property, need to recheck it
448
-				$response = $this->client->propfind($this->encodePath($path), ['{DAV:}getlastmodified'], 0);
449
-				if ($response === false) {
450
-					return false;
451
-				}
452
-				if (isset($response['{DAV:}getlastmodified'])) {
453
-					$remoteMtime = strtotime($response['{DAV:}getlastmodified']);
454
-					if ($remoteMtime !== $mtime) {
455
-						// server has not accepted the mtime
456
-						return false;
457
-					}
458
-				}
459
-			} catch (ClientHttpException $e) {
460
-				if ($e->getHttpStatus() === 501) {
461
-					return false;
462
-				}
463
-				$this->convertException($e, $path);
464
-				return false;
465
-			} catch (\Exception $e) {
466
-				$this->convertException($e, $path);
467
-				return false;
468
-			}
469
-		} else {
470
-			$this->file_put_contents($path, '');
471
-		}
472
-		return true;
473
-	}
474
-
475
-	/**
476
-	 * @param string $path
477
-	 * @param string $data
478
-	 * @return int
479
-	 */
480
-	public function file_put_contents($path, $data) {
481
-		$path = $this->cleanPath($path);
482
-		$result = parent::file_put_contents($path, $data);
483
-		$this->statCache->remove($path);
484
-		return $result;
485
-	}
486
-
487
-	/**
488
-	 * @param string $path
489
-	 * @param string $target
490
-	 */
491
-	protected function uploadFile($path, $target) {
492
-		$this->init();
493
-
494
-		// invalidate
495
-		$target = $this->cleanPath($target);
496
-		$this->statCache->remove($target);
497
-		$source = fopen($path, 'r');
498
-
499
-		$this->httpClientService
500
-			->newClient()
501
-			->put($this->createBaseUri() . $this->encodePath($target), [
502
-				'body' => $source,
503
-				'auth' => [$this->user, $this->password]
504
-			]);
505
-
506
-		$this->removeCachedFile($target);
507
-	}
508
-
509
-	/** {@inheritdoc} */
510
-	public function rename($path1, $path2) {
511
-		$this->init();
512
-		$path1 = $this->cleanPath($path1);
513
-		$path2 = $this->cleanPath($path2);
514
-		try {
515
-			// overwrite directory ?
516
-			if ($this->is_dir($path2)) {
517
-				// needs trailing slash in destination
518
-				$path2 = rtrim($path2, '/') . '/';
519
-			}
520
-			$this->client->request(
521
-				'MOVE',
522
-				$this->encodePath($path1),
523
-				null,
524
-				[
525
-					'Destination' => $this->createBaseUri() . $this->encodePath($path2),
526
-				]
527
-			);
528
-			$this->statCache->clear($path1 . '/');
529
-			$this->statCache->clear($path2 . '/');
530
-			$this->statCache->set($path1, false);
531
-			$this->statCache->set($path2, true);
532
-			$this->removeCachedFile($path1);
533
-			$this->removeCachedFile($path2);
534
-			return true;
535
-		} catch (\Exception $e) {
536
-			$this->convertException($e);
537
-		}
538
-		return false;
539
-	}
540
-
541
-	/** {@inheritdoc} */
542
-	public function copy($path1, $path2) {
543
-		$this->init();
544
-		$path1 = $this->cleanPath($path1);
545
-		$path2 = $this->cleanPath($path2);
546
-		try {
547
-			// overwrite directory ?
548
-			if ($this->is_dir($path2)) {
549
-				// needs trailing slash in destination
550
-				$path2 = rtrim($path2, '/') . '/';
551
-			}
552
-			$this->client->request(
553
-				'COPY',
554
-				$this->encodePath($path1),
555
-				null,
556
-				[
557
-					'Destination' => $this->createBaseUri() . $this->encodePath($path2),
558
-				]
559
-			);
560
-			$this->statCache->clear($path2 . '/');
561
-			$this->statCache->set($path2, true);
562
-			$this->removeCachedFile($path2);
563
-			return true;
564
-		} catch (\Exception $e) {
565
-			$this->convertException($e);
566
-		}
567
-		return false;
568
-	}
569
-
570
-	/** {@inheritdoc} */
571
-	public function stat($path) {
572
-		try {
573
-			$response = $this->propfind($path);
574
-			if (!$response) {
575
-				return false;
576
-			}
577
-			return [
578
-				'mtime' => strtotime($response['{DAV:}getlastmodified']),
579
-				'size' => (int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0,
580
-			];
581
-		} catch (\Exception $e) {
582
-			$this->convertException($e, $path);
583
-		}
584
-		return array();
585
-	}
586
-
587
-	/** {@inheritdoc} */
588
-	public function getMimeType($path) {
589
-		$remoteMimetype = $this->getMimeTypeFromRemote($path);
590
-		if ($remoteMimetype === 'application/octet-stream') {
591
-			return \OC::$server->getMimeTypeDetector()->detectPath($path);
592
-		} else {
593
-			return $remoteMimetype;
594
-		}
595
-	}
596
-
597
-	public function getMimeTypeFromRemote($path) {
598
-		try {
599
-			$response = $this->propfind($path);
600
-			if ($response === false) {
601
-				return false;
602
-			}
603
-			$responseType = [];
604
-			if (isset($response["{DAV:}resourcetype"])) {
605
-				/** @var ResourceType[] $response */
606
-				$responseType = $response["{DAV:}resourcetype"]->getValue();
607
-			}
608
-			$type = (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
609
-			if ($type == 'dir') {
610
-				return 'httpd/unix-directory';
611
-			} elseif (isset($response['{DAV:}getcontenttype'])) {
612
-				return $response['{DAV:}getcontenttype'];
613
-			} else {
614
-				return 'application/octet-stream';
615
-			}
616
-		} catch (\Exception $e) {
617
-			return false;
618
-		}
619
-	}
620
-
621
-	/**
622
-	 * @param string $path
623
-	 * @return string
624
-	 */
625
-	public function cleanPath($path) {
626
-		if ($path === '') {
627
-			return $path;
628
-		}
629
-		$path = Filesystem::normalizePath($path);
630
-		// remove leading slash
631
-		return substr($path, 1);
632
-	}
633
-
634
-	/**
635
-	 * URL encodes the given path but keeps the slashes
636
-	 *
637
-	 * @param string $path to encode
638
-	 * @return string encoded path
639
-	 */
640
-	protected function encodePath($path) {
641
-		// slashes need to stay
642
-		return str_replace('%2F', '/', rawurlencode($path));
643
-	}
644
-
645
-	/**
646
-	 * @param string $method
647
-	 * @param string $path
648
-	 * @param string|resource|null $body
649
-	 * @param int $expected
650
-	 * @return bool
651
-	 * @throws StorageInvalidException
652
-	 * @throws StorageNotAvailableException
653
-	 */
654
-	protected function simpleResponse($method, $path, $body, $expected) {
655
-		$path = $this->cleanPath($path);
656
-		try {
657
-			$response = $this->client->request($method, $this->encodePath($path), $body);
658
-			return $response['statusCode'] == $expected;
659
-		} catch (ClientHttpException $e) {
660
-			if ($e->getHttpStatus() === 404 && $method === 'DELETE') {
661
-				$this->statCache->clear($path . '/');
662
-				$this->statCache->set($path, false);
663
-				return false;
664
-			}
665
-
666
-			$this->convertException($e, $path);
667
-		} catch (\Exception $e) {
668
-			$this->convertException($e, $path);
669
-		}
670
-		return false;
671
-	}
672
-
673
-	/**
674
-	 * check if curl is installed
675
-	 */
676
-	public static function checkDependencies() {
677
-		return true;
678
-	}
679
-
680
-	/** {@inheritdoc} */
681
-	public function isUpdatable($path) {
682
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_UPDATE);
683
-	}
684
-
685
-	/** {@inheritdoc} */
686
-	public function isCreatable($path) {
687
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_CREATE);
688
-	}
689
-
690
-	/** {@inheritdoc} */
691
-	public function isSharable($path) {
692
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_SHARE);
693
-	}
694
-
695
-	/** {@inheritdoc} */
696
-	public function isDeletable($path) {
697
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_DELETE);
698
-	}
699
-
700
-	/** {@inheritdoc} */
701
-	public function getPermissions($path) {
702
-		$this->init();
703
-		$path = $this->cleanPath($path);
704
-		$response = $this->propfind($path);
705
-		if ($response === false) {
706
-			return 0;
707
-		}
708
-		if (isset($response['{http://owncloud.org/ns}permissions'])) {
709
-			return $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
710
-		} else if ($this->is_dir($path)) {
711
-			return Constants::PERMISSION_ALL;
712
-		} else if ($this->file_exists($path)) {
713
-			return Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE;
714
-		} else {
715
-			return 0;
716
-		}
717
-	}
718
-
719
-	/** {@inheritdoc} */
720
-	public function getETag($path) {
721
-		$this->init();
722
-		$path = $this->cleanPath($path);
723
-		$response = $this->propfind($path);
724
-		if ($response === false) {
725
-			return null;
726
-		}
727
-		if (isset($response['{DAV:}getetag'])) {
728
-			return trim($response['{DAV:}getetag'], '"');
729
-		}
730
-		return parent::getEtag($path);
731
-	}
732
-
733
-	/**
734
-	 * @param string $permissionsString
735
-	 * @return int
736
-	 */
737
-	protected function parsePermissions($permissionsString) {
738
-		$permissions = Constants::PERMISSION_READ;
739
-		if (strpos($permissionsString, 'R') !== false) {
740
-			$permissions |= Constants::PERMISSION_SHARE;
741
-		}
742
-		if (strpos($permissionsString, 'D') !== false) {
743
-			$permissions |= Constants::PERMISSION_DELETE;
744
-		}
745
-		if (strpos($permissionsString, 'W') !== false) {
746
-			$permissions |= Constants::PERMISSION_UPDATE;
747
-		}
748
-		if (strpos($permissionsString, 'CK') !== false) {
749
-			$permissions |= Constants::PERMISSION_CREATE;
750
-			$permissions |= Constants::PERMISSION_UPDATE;
751
-		}
752
-		return $permissions;
753
-	}
754
-
755
-	/**
756
-	 * check if a file or folder has been updated since $time
757
-	 *
758
-	 * @param string $path
759
-	 * @param int $time
760
-	 * @throws \OCP\Files\StorageNotAvailableException
761
-	 * @return bool
762
-	 */
763
-	public function hasUpdated($path, $time) {
764
-		$this->init();
765
-		$path = $this->cleanPath($path);
766
-		try {
767
-			// force refresh for $path
768
-			$this->statCache->remove($path);
769
-			$response = $this->propfind($path);
770
-			if ($response === false) {
771
-				if ($path === '') {
772
-					// if root is gone it means the storage is not available
773
-					throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
774
-				}
775
-				return false;
776
-			}
777
-			if (isset($response['{DAV:}getetag'])) {
778
-				$cachedData = $this->getCache()->get($path);
779
-				$etag = null;
780
-				if (isset($response['{DAV:}getetag'])) {
781
-					$etag = trim($response['{DAV:}getetag'], '"');
782
-				}
783
-				if (!empty($etag) && $cachedData['etag'] !== $etag) {
784
-					return true;
785
-				} else if (isset($response['{http://open-collaboration-services.org/ns}share-permissions'])) {
786
-					$sharePermissions = (int)$response['{http://open-collaboration-services.org/ns}share-permissions'];
787
-					return $sharePermissions !== $cachedData['permissions'];
788
-				} else if (isset($response['{http://owncloud.org/ns}permissions'])) {
789
-					$permissions = $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
790
-					return $permissions !== $cachedData['permissions'];
791
-				} else {
792
-					return false;
793
-				}
794
-			} else {
795
-				$remoteMtime = strtotime($response['{DAV:}getlastmodified']);
796
-				return $remoteMtime > $time;
797
-			}
798
-		} catch (ClientHttpException $e) {
799
-			if ($e->getHttpStatus() === 405) {
800
-				if ($path === '') {
801
-					// if root is gone it means the storage is not available
802
-					throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
803
-				}
804
-				return false;
805
-			}
806
-			$this->convertException($e, $path);
807
-			return false;
808
-		} catch (\Exception $e) {
809
-			$this->convertException($e, $path);
810
-			return false;
811
-		}
812
-	}
813
-
814
-	/**
815
-	 * Interpret the given exception and decide whether it is due to an
816
-	 * unavailable storage, invalid storage or other.
817
-	 * This will either throw StorageInvalidException, StorageNotAvailableException
818
-	 * or do nothing.
819
-	 *
820
-	 * @param Exception $e sabre exception
821
-	 * @param string $path optional path from the operation
822
-	 *
823
-	 * @throws StorageInvalidException if the storage is invalid, for example
824
-	 * when the authentication expired or is invalid
825
-	 * @throws StorageNotAvailableException if the storage is not available,
826
-	 * which might be temporary
827
-	 */
828
-	protected function convertException(Exception $e, $path = '') {
829
-		\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
830
-		if ($e instanceof ClientHttpException) {
831
-			if ($e->getHttpStatus() === Http::STATUS_LOCKED) {
832
-				throw new \OCP\Lock\LockedException($path);
833
-			}
834
-			if ($e->getHttpStatus() === Http::STATUS_UNAUTHORIZED) {
835
-				// either password was changed or was invalid all along
836
-				throw new StorageInvalidException(get_class($e) . ': ' . $e->getMessage());
837
-			} else if ($e->getHttpStatus() === Http::STATUS_METHOD_NOT_ALLOWED) {
838
-				// ignore exception for MethodNotAllowed, false will be returned
839
-				return;
840
-			}
841
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
842
-		} else if ($e instanceof ClientException) {
843
-			// connection timeout or refused, server could be temporarily down
844
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
845
-		} else if ($e instanceof \InvalidArgumentException) {
846
-			// parse error because the server returned HTML instead of XML,
847
-			// possibly temporarily down
848
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
849
-		} else if (($e instanceof StorageNotAvailableException) || ($e instanceof StorageInvalidException)) {
850
-			// rethrow
851
-			throw $e;
852
-		}
853
-
854
-		// TODO: only log for now, but in the future need to wrap/rethrow exception
855
-	}
60
+    /** @var string */
61
+    protected $password;
62
+    /** @var string */
63
+    protected $user;
64
+    /** @var string */
65
+    protected $authType;
66
+    /** @var string */
67
+    protected $host;
68
+    /** @var bool */
69
+    protected $secure;
70
+    /** @var string */
71
+    protected $root;
72
+    /** @var string */
73
+    protected $certPath;
74
+    /** @var bool */
75
+    protected $ready;
76
+    /** @var Client */
77
+    protected $client;
78
+    /** @var ArrayCache */
79
+    protected $statCache;
80
+    /** @var \OCP\Http\Client\IClientService */
81
+    protected $httpClientService;
82
+
83
+    /**
84
+     * @param array $params
85
+     * @throws \Exception
86
+     */
87
+    public function __construct($params) {
88
+        $this->statCache = new ArrayCache();
89
+        $this->httpClientService = \OC::$server->getHTTPClientService();
90
+        if (isset($params['host']) && isset($params['user']) && isset($params['password'])) {
91
+            $host = $params['host'];
92
+            //remove leading http[s], will be generated in createBaseUri()
93
+            if (substr($host, 0, 8) == "https://") $host = substr($host, 8);
94
+            else if (substr($host, 0, 7) == "http://") $host = substr($host, 7);
95
+            $this->host = $host;
96
+            $this->user = $params['user'];
97
+            $this->password = $params['password'];
98
+            if (isset($params['authType'])) {
99
+                $this->authType = $params['authType'];
100
+            }
101
+            if (isset($params['secure'])) {
102
+                if (is_string($params['secure'])) {
103
+                    $this->secure = ($params['secure'] === 'true');
104
+                } else {
105
+                    $this->secure = (bool)$params['secure'];
106
+                }
107
+            } else {
108
+                $this->secure = false;
109
+            }
110
+            if ($this->secure === true) {
111
+                // inject mock for testing
112
+                $certManager = \OC::$server->getCertificateManager();
113
+                if (is_null($certManager)) { //no user
114
+                    $certManager = \OC::$server->getCertificateManager(null);
115
+                }
116
+                $certPath = $certManager->getAbsoluteBundlePath();
117
+                if (file_exists($certPath)) {
118
+                    $this->certPath = $certPath;
119
+                }
120
+            }
121
+            $this->root = $params['root'] ?? '/';
122
+            $this->root = '/' . ltrim($this->root, '/');
123
+            $this->root = rtrim($this->root, '/') . '/';
124
+        } else {
125
+            throw new \Exception('Invalid webdav storage configuration');
126
+        }
127
+    }
128
+
129
+    protected function init() {
130
+        if ($this->ready) {
131
+            return;
132
+        }
133
+        $this->ready = true;
134
+
135
+        $settings = [
136
+            'baseUri' => $this->createBaseUri(),
137
+            'userName' => $this->user,
138
+            'password' => $this->password,
139
+        ];
140
+        if (isset($this->authType)) {
141
+            $settings['authType'] = $this->authType;
142
+        }
143
+
144
+        $proxy = \OC::$server->getConfig()->getSystemValue('proxy', '');
145
+        if ($proxy !== '') {
146
+            $settings['proxy'] = $proxy;
147
+        }
148
+
149
+        $this->client = new Client($settings);
150
+        $this->client->setThrowExceptions(true);
151
+        if ($this->secure === true && $this->certPath) {
152
+            $this->client->addCurlSetting(CURLOPT_CAINFO, $this->certPath);
153
+        }
154
+    }
155
+
156
+    /**
157
+     * Clear the stat cache
158
+     */
159
+    public function clearStatCache() {
160
+        $this->statCache->clear();
161
+    }
162
+
163
+    /** {@inheritdoc} */
164
+    public function getId() {
165
+        return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root;
166
+    }
167
+
168
+    /** {@inheritdoc} */
169
+    public function createBaseUri() {
170
+        $baseUri = 'http';
171
+        if ($this->secure) {
172
+            $baseUri .= 's';
173
+        }
174
+        $baseUri .= '://' . $this->host . $this->root;
175
+        return $baseUri;
176
+    }
177
+
178
+    /** {@inheritdoc} */
179
+    public function mkdir($path) {
180
+        $this->init();
181
+        $path = $this->cleanPath($path);
182
+        $result = $this->simpleResponse('MKCOL', $path, null, 201);
183
+        if ($result) {
184
+            $this->statCache->set($path, true);
185
+        }
186
+        return $result;
187
+    }
188
+
189
+    /** {@inheritdoc} */
190
+    public function rmdir($path) {
191
+        $this->init();
192
+        $path = $this->cleanPath($path);
193
+        // FIXME: some WebDAV impl return 403 when trying to DELETE
194
+        // a non-empty folder
195
+        $result = $this->simpleResponse('DELETE', $path . '/', null, 204);
196
+        $this->statCache->clear($path . '/');
197
+        $this->statCache->remove($path);
198
+        return $result;
199
+    }
200
+
201
+    /** {@inheritdoc} */
202
+    public function opendir($path) {
203
+        $this->init();
204
+        $path = $this->cleanPath($path);
205
+        try {
206
+            $response = $this->client->propFind(
207
+                $this->encodePath($path),
208
+                ['{DAV:}href'],
209
+                1
210
+            );
211
+            if ($response === false) {
212
+                return false;
213
+            }
214
+            $content = [];
215
+            $files = array_keys($response);
216
+            array_shift($files); //the first entry is the current directory
217
+
218
+            if (!$this->statCache->hasKey($path)) {
219
+                $this->statCache->set($path, true);
220
+            }
221
+            foreach ($files as $file) {
222
+                $file = urldecode($file);
223
+                // do not store the real entry, we might not have all properties
224
+                if (!$this->statCache->hasKey($path)) {
225
+                    $this->statCache->set($file, true);
226
+                }
227
+                $file = basename($file);
228
+                $content[] = $file;
229
+            }
230
+            return IteratorDirectory::wrap($content);
231
+        } catch (\Exception $e) {
232
+            $this->convertException($e, $path);
233
+        }
234
+        return false;
235
+    }
236
+
237
+    /**
238
+     * Propfind call with cache handling.
239
+     *
240
+     * First checks if information is cached.
241
+     * If not, request it from the server then store to cache.
242
+     *
243
+     * @param string $path path to propfind
244
+     *
245
+     * @return array|boolean propfind response or false if the entry was not found
246
+     *
247
+     * @throws ClientHttpException
248
+     */
249
+    protected function propfind($path) {
250
+        $path = $this->cleanPath($path);
251
+        $cachedResponse = $this->statCache->get($path);
252
+        // we either don't know it, or we know it exists but need more details
253
+        if (is_null($cachedResponse) || $cachedResponse === true) {
254
+            $this->init();
255
+            try {
256
+                $response = $this->client->propFind(
257
+                    $this->encodePath($path),
258
+                    array(
259
+                        '{DAV:}getlastmodified',
260
+                        '{DAV:}getcontentlength',
261
+                        '{DAV:}getcontenttype',
262
+                        '{http://owncloud.org/ns}permissions',
263
+                        '{http://open-collaboration-services.org/ns}share-permissions',
264
+                        '{DAV:}resourcetype',
265
+                        '{DAV:}getetag',
266
+                    )
267
+                );
268
+                $this->statCache->set($path, $response);
269
+            } catch (ClientHttpException $e) {
270
+                if ($e->getHttpStatus() === 404) {
271
+                    $this->statCache->clear($path . '/');
272
+                    $this->statCache->set($path, false);
273
+                    return false;
274
+                }
275
+                $this->convertException($e, $path);
276
+            } catch (\Exception $e) {
277
+                $this->convertException($e, $path);
278
+            }
279
+        } else {
280
+            $response = $cachedResponse;
281
+        }
282
+        return $response;
283
+    }
284
+
285
+    /** {@inheritdoc} */
286
+    public function filetype($path) {
287
+        try {
288
+            $response = $this->propfind($path);
289
+            if ($response === false) {
290
+                return false;
291
+            }
292
+            $responseType = [];
293
+            if (isset($response["{DAV:}resourcetype"])) {
294
+                /** @var ResourceType[] $response */
295
+                $responseType = $response["{DAV:}resourcetype"]->getValue();
296
+            }
297
+            return (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
298
+        } catch (\Exception $e) {
299
+            $this->convertException($e, $path);
300
+        }
301
+        return false;
302
+    }
303
+
304
+    /** {@inheritdoc} */
305
+    public function file_exists($path) {
306
+        try {
307
+            $path = $this->cleanPath($path);
308
+            $cachedState = $this->statCache->get($path);
309
+            if ($cachedState === false) {
310
+                // we know the file doesn't exist
311
+                return false;
312
+            } else if (!is_null($cachedState)) {
313
+                return true;
314
+            }
315
+            // need to get from server
316
+            return ($this->propfind($path) !== false);
317
+        } catch (\Exception $e) {
318
+            $this->convertException($e, $path);
319
+        }
320
+        return false;
321
+    }
322
+
323
+    /** {@inheritdoc} */
324
+    public function unlink($path) {
325
+        $this->init();
326
+        $path = $this->cleanPath($path);
327
+        $result = $this->simpleResponse('DELETE', $path, null, 204);
328
+        $this->statCache->clear($path . '/');
329
+        $this->statCache->remove($path);
330
+        return $result;
331
+    }
332
+
333
+    /** {@inheritdoc} */
334
+    public function fopen($path, $mode) {
335
+        $this->init();
336
+        $path = $this->cleanPath($path);
337
+        switch ($mode) {
338
+            case 'r':
339
+            case 'rb':
340
+                try {
341
+                    $response = $this->httpClientService
342
+                        ->newClient()
343
+                        ->get($this->createBaseUri() . $this->encodePath($path), [
344
+                            'auth' => [$this->user, $this->password],
345
+                            'stream' => true
346
+                        ]);
347
+                } catch (\GuzzleHttp\Exception\ClientException $e) {
348
+                    if ($e->getResponse() instanceof ResponseInterface
349
+                        && $e->getResponse()->getStatusCode() === 404) {
350
+                        return false;
351
+                    } else {
352
+                        throw $e;
353
+                    }
354
+                }
355
+
356
+                if ($response->getStatusCode() !== Http::STATUS_OK) {
357
+                    if ($response->getStatusCode() === Http::STATUS_LOCKED) {
358
+                        throw new \OCP\Lock\LockedException($path);
359
+                    } else {
360
+                        Util::writeLog("webdav client", 'Guzzle get returned status code ' . $response->getStatusCode(), Util::ERROR);
361
+                    }
362
+                }
363
+
364
+                return $response->getBody();
365
+            case 'w':
366
+            case 'wb':
367
+            case 'a':
368
+            case 'ab':
369
+            case 'r+':
370
+            case 'w+':
371
+            case 'wb+':
372
+            case 'a+':
373
+            case 'x':
374
+            case 'x+':
375
+            case 'c':
376
+            case 'c+':
377
+                //emulate these
378
+                $tempManager = \OC::$server->getTempManager();
379
+                if (strrpos($path, '.') !== false) {
380
+                    $ext = substr($path, strrpos($path, '.'));
381
+                } else {
382
+                    $ext = '';
383
+                }
384
+                if ($this->file_exists($path)) {
385
+                    if (!$this->isUpdatable($path)) {
386
+                        return false;
387
+                    }
388
+                    if ($mode === 'w' or $mode === 'w+') {
389
+                        $tmpFile = $tempManager->getTemporaryFile($ext);
390
+                    } else {
391
+                        $tmpFile = $this->getCachedFile($path);
392
+                    }
393
+                } else {
394
+                    if (!$this->isCreatable(dirname($path))) {
395
+                        return false;
396
+                    }
397
+                    $tmpFile = $tempManager->getTemporaryFile($ext);
398
+                }
399
+                $handle = fopen($tmpFile, $mode);
400
+                return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
401
+                    $this->writeBack($tmpFile, $path);
402
+                });
403
+        }
404
+    }
405
+
406
+    /**
407
+     * @param string $tmpFile
408
+     */
409
+    public function writeBack($tmpFile, $path) {
410
+        $this->uploadFile($tmpFile, $path);
411
+        unlink($tmpFile);
412
+    }
413
+
414
+    /** {@inheritdoc} */
415
+    public function free_space($path) {
416
+        $this->init();
417
+        $path = $this->cleanPath($path);
418
+        try {
419
+            // TODO: cacheable ?
420
+            $response = $this->client->propfind($this->encodePath($path), ['{DAV:}quota-available-bytes']);
421
+            if ($response === false) {
422
+                return FileInfo::SPACE_UNKNOWN;
423
+            }
424
+            if (isset($response['{DAV:}quota-available-bytes'])) {
425
+                return (int)$response['{DAV:}quota-available-bytes'];
426
+            } else {
427
+                return FileInfo::SPACE_UNKNOWN;
428
+            }
429
+        } catch (\Exception $e) {
430
+            return FileInfo::SPACE_UNKNOWN;
431
+        }
432
+    }
433
+
434
+    /** {@inheritdoc} */
435
+    public function touch($path, $mtime = null) {
436
+        $this->init();
437
+        if (is_null($mtime)) {
438
+            $mtime = time();
439
+        }
440
+        $path = $this->cleanPath($path);
441
+
442
+        // if file exists, update the mtime, else create a new empty file
443
+        if ($this->file_exists($path)) {
444
+            try {
445
+                $this->statCache->remove($path);
446
+                $this->client->proppatch($this->encodePath($path), ['{DAV:}lastmodified' => $mtime]);
447
+                // non-owncloud clients might not have accepted the property, need to recheck it
448
+                $response = $this->client->propfind($this->encodePath($path), ['{DAV:}getlastmodified'], 0);
449
+                if ($response === false) {
450
+                    return false;
451
+                }
452
+                if (isset($response['{DAV:}getlastmodified'])) {
453
+                    $remoteMtime = strtotime($response['{DAV:}getlastmodified']);
454
+                    if ($remoteMtime !== $mtime) {
455
+                        // server has not accepted the mtime
456
+                        return false;
457
+                    }
458
+                }
459
+            } catch (ClientHttpException $e) {
460
+                if ($e->getHttpStatus() === 501) {
461
+                    return false;
462
+                }
463
+                $this->convertException($e, $path);
464
+                return false;
465
+            } catch (\Exception $e) {
466
+                $this->convertException($e, $path);
467
+                return false;
468
+            }
469
+        } else {
470
+            $this->file_put_contents($path, '');
471
+        }
472
+        return true;
473
+    }
474
+
475
+    /**
476
+     * @param string $path
477
+     * @param string $data
478
+     * @return int
479
+     */
480
+    public function file_put_contents($path, $data) {
481
+        $path = $this->cleanPath($path);
482
+        $result = parent::file_put_contents($path, $data);
483
+        $this->statCache->remove($path);
484
+        return $result;
485
+    }
486
+
487
+    /**
488
+     * @param string $path
489
+     * @param string $target
490
+     */
491
+    protected function uploadFile($path, $target) {
492
+        $this->init();
493
+
494
+        // invalidate
495
+        $target = $this->cleanPath($target);
496
+        $this->statCache->remove($target);
497
+        $source = fopen($path, 'r');
498
+
499
+        $this->httpClientService
500
+            ->newClient()
501
+            ->put($this->createBaseUri() . $this->encodePath($target), [
502
+                'body' => $source,
503
+                'auth' => [$this->user, $this->password]
504
+            ]);
505
+
506
+        $this->removeCachedFile($target);
507
+    }
508
+
509
+    /** {@inheritdoc} */
510
+    public function rename($path1, $path2) {
511
+        $this->init();
512
+        $path1 = $this->cleanPath($path1);
513
+        $path2 = $this->cleanPath($path2);
514
+        try {
515
+            // overwrite directory ?
516
+            if ($this->is_dir($path2)) {
517
+                // needs trailing slash in destination
518
+                $path2 = rtrim($path2, '/') . '/';
519
+            }
520
+            $this->client->request(
521
+                'MOVE',
522
+                $this->encodePath($path1),
523
+                null,
524
+                [
525
+                    'Destination' => $this->createBaseUri() . $this->encodePath($path2),
526
+                ]
527
+            );
528
+            $this->statCache->clear($path1 . '/');
529
+            $this->statCache->clear($path2 . '/');
530
+            $this->statCache->set($path1, false);
531
+            $this->statCache->set($path2, true);
532
+            $this->removeCachedFile($path1);
533
+            $this->removeCachedFile($path2);
534
+            return true;
535
+        } catch (\Exception $e) {
536
+            $this->convertException($e);
537
+        }
538
+        return false;
539
+    }
540
+
541
+    /** {@inheritdoc} */
542
+    public function copy($path1, $path2) {
543
+        $this->init();
544
+        $path1 = $this->cleanPath($path1);
545
+        $path2 = $this->cleanPath($path2);
546
+        try {
547
+            // overwrite directory ?
548
+            if ($this->is_dir($path2)) {
549
+                // needs trailing slash in destination
550
+                $path2 = rtrim($path2, '/') . '/';
551
+            }
552
+            $this->client->request(
553
+                'COPY',
554
+                $this->encodePath($path1),
555
+                null,
556
+                [
557
+                    'Destination' => $this->createBaseUri() . $this->encodePath($path2),
558
+                ]
559
+            );
560
+            $this->statCache->clear($path2 . '/');
561
+            $this->statCache->set($path2, true);
562
+            $this->removeCachedFile($path2);
563
+            return true;
564
+        } catch (\Exception $e) {
565
+            $this->convertException($e);
566
+        }
567
+        return false;
568
+    }
569
+
570
+    /** {@inheritdoc} */
571
+    public function stat($path) {
572
+        try {
573
+            $response = $this->propfind($path);
574
+            if (!$response) {
575
+                return false;
576
+            }
577
+            return [
578
+                'mtime' => strtotime($response['{DAV:}getlastmodified']),
579
+                'size' => (int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0,
580
+            ];
581
+        } catch (\Exception $e) {
582
+            $this->convertException($e, $path);
583
+        }
584
+        return array();
585
+    }
586
+
587
+    /** {@inheritdoc} */
588
+    public function getMimeType($path) {
589
+        $remoteMimetype = $this->getMimeTypeFromRemote($path);
590
+        if ($remoteMimetype === 'application/octet-stream') {
591
+            return \OC::$server->getMimeTypeDetector()->detectPath($path);
592
+        } else {
593
+            return $remoteMimetype;
594
+        }
595
+    }
596
+
597
+    public function getMimeTypeFromRemote($path) {
598
+        try {
599
+            $response = $this->propfind($path);
600
+            if ($response === false) {
601
+                return false;
602
+            }
603
+            $responseType = [];
604
+            if (isset($response["{DAV:}resourcetype"])) {
605
+                /** @var ResourceType[] $response */
606
+                $responseType = $response["{DAV:}resourcetype"]->getValue();
607
+            }
608
+            $type = (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
609
+            if ($type == 'dir') {
610
+                return 'httpd/unix-directory';
611
+            } elseif (isset($response['{DAV:}getcontenttype'])) {
612
+                return $response['{DAV:}getcontenttype'];
613
+            } else {
614
+                return 'application/octet-stream';
615
+            }
616
+        } catch (\Exception $e) {
617
+            return false;
618
+        }
619
+    }
620
+
621
+    /**
622
+     * @param string $path
623
+     * @return string
624
+     */
625
+    public function cleanPath($path) {
626
+        if ($path === '') {
627
+            return $path;
628
+        }
629
+        $path = Filesystem::normalizePath($path);
630
+        // remove leading slash
631
+        return substr($path, 1);
632
+    }
633
+
634
+    /**
635
+     * URL encodes the given path but keeps the slashes
636
+     *
637
+     * @param string $path to encode
638
+     * @return string encoded path
639
+     */
640
+    protected function encodePath($path) {
641
+        // slashes need to stay
642
+        return str_replace('%2F', '/', rawurlencode($path));
643
+    }
644
+
645
+    /**
646
+     * @param string $method
647
+     * @param string $path
648
+     * @param string|resource|null $body
649
+     * @param int $expected
650
+     * @return bool
651
+     * @throws StorageInvalidException
652
+     * @throws StorageNotAvailableException
653
+     */
654
+    protected function simpleResponse($method, $path, $body, $expected) {
655
+        $path = $this->cleanPath($path);
656
+        try {
657
+            $response = $this->client->request($method, $this->encodePath($path), $body);
658
+            return $response['statusCode'] == $expected;
659
+        } catch (ClientHttpException $e) {
660
+            if ($e->getHttpStatus() === 404 && $method === 'DELETE') {
661
+                $this->statCache->clear($path . '/');
662
+                $this->statCache->set($path, false);
663
+                return false;
664
+            }
665
+
666
+            $this->convertException($e, $path);
667
+        } catch (\Exception $e) {
668
+            $this->convertException($e, $path);
669
+        }
670
+        return false;
671
+    }
672
+
673
+    /**
674
+     * check if curl is installed
675
+     */
676
+    public static function checkDependencies() {
677
+        return true;
678
+    }
679
+
680
+    /** {@inheritdoc} */
681
+    public function isUpdatable($path) {
682
+        return (bool)($this->getPermissions($path) & Constants::PERMISSION_UPDATE);
683
+    }
684
+
685
+    /** {@inheritdoc} */
686
+    public function isCreatable($path) {
687
+        return (bool)($this->getPermissions($path) & Constants::PERMISSION_CREATE);
688
+    }
689
+
690
+    /** {@inheritdoc} */
691
+    public function isSharable($path) {
692
+        return (bool)($this->getPermissions($path) & Constants::PERMISSION_SHARE);
693
+    }
694
+
695
+    /** {@inheritdoc} */
696
+    public function isDeletable($path) {
697
+        return (bool)($this->getPermissions($path) & Constants::PERMISSION_DELETE);
698
+    }
699
+
700
+    /** {@inheritdoc} */
701
+    public function getPermissions($path) {
702
+        $this->init();
703
+        $path = $this->cleanPath($path);
704
+        $response = $this->propfind($path);
705
+        if ($response === false) {
706
+            return 0;
707
+        }
708
+        if (isset($response['{http://owncloud.org/ns}permissions'])) {
709
+            return $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
710
+        } else if ($this->is_dir($path)) {
711
+            return Constants::PERMISSION_ALL;
712
+        } else if ($this->file_exists($path)) {
713
+            return Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE;
714
+        } else {
715
+            return 0;
716
+        }
717
+    }
718
+
719
+    /** {@inheritdoc} */
720
+    public function getETag($path) {
721
+        $this->init();
722
+        $path = $this->cleanPath($path);
723
+        $response = $this->propfind($path);
724
+        if ($response === false) {
725
+            return null;
726
+        }
727
+        if (isset($response['{DAV:}getetag'])) {
728
+            return trim($response['{DAV:}getetag'], '"');
729
+        }
730
+        return parent::getEtag($path);
731
+    }
732
+
733
+    /**
734
+     * @param string $permissionsString
735
+     * @return int
736
+     */
737
+    protected function parsePermissions($permissionsString) {
738
+        $permissions = Constants::PERMISSION_READ;
739
+        if (strpos($permissionsString, 'R') !== false) {
740
+            $permissions |= Constants::PERMISSION_SHARE;
741
+        }
742
+        if (strpos($permissionsString, 'D') !== false) {
743
+            $permissions |= Constants::PERMISSION_DELETE;
744
+        }
745
+        if (strpos($permissionsString, 'W') !== false) {
746
+            $permissions |= Constants::PERMISSION_UPDATE;
747
+        }
748
+        if (strpos($permissionsString, 'CK') !== false) {
749
+            $permissions |= Constants::PERMISSION_CREATE;
750
+            $permissions |= Constants::PERMISSION_UPDATE;
751
+        }
752
+        return $permissions;
753
+    }
754
+
755
+    /**
756
+     * check if a file or folder has been updated since $time
757
+     *
758
+     * @param string $path
759
+     * @param int $time
760
+     * @throws \OCP\Files\StorageNotAvailableException
761
+     * @return bool
762
+     */
763
+    public function hasUpdated($path, $time) {
764
+        $this->init();
765
+        $path = $this->cleanPath($path);
766
+        try {
767
+            // force refresh for $path
768
+            $this->statCache->remove($path);
769
+            $response = $this->propfind($path);
770
+            if ($response === false) {
771
+                if ($path === '') {
772
+                    // if root is gone it means the storage is not available
773
+                    throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
774
+                }
775
+                return false;
776
+            }
777
+            if (isset($response['{DAV:}getetag'])) {
778
+                $cachedData = $this->getCache()->get($path);
779
+                $etag = null;
780
+                if (isset($response['{DAV:}getetag'])) {
781
+                    $etag = trim($response['{DAV:}getetag'], '"');
782
+                }
783
+                if (!empty($etag) && $cachedData['etag'] !== $etag) {
784
+                    return true;
785
+                } else if (isset($response['{http://open-collaboration-services.org/ns}share-permissions'])) {
786
+                    $sharePermissions = (int)$response['{http://open-collaboration-services.org/ns}share-permissions'];
787
+                    return $sharePermissions !== $cachedData['permissions'];
788
+                } else if (isset($response['{http://owncloud.org/ns}permissions'])) {
789
+                    $permissions = $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
790
+                    return $permissions !== $cachedData['permissions'];
791
+                } else {
792
+                    return false;
793
+                }
794
+            } else {
795
+                $remoteMtime = strtotime($response['{DAV:}getlastmodified']);
796
+                return $remoteMtime > $time;
797
+            }
798
+        } catch (ClientHttpException $e) {
799
+            if ($e->getHttpStatus() === 405) {
800
+                if ($path === '') {
801
+                    // if root is gone it means the storage is not available
802
+                    throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
803
+                }
804
+                return false;
805
+            }
806
+            $this->convertException($e, $path);
807
+            return false;
808
+        } catch (\Exception $e) {
809
+            $this->convertException($e, $path);
810
+            return false;
811
+        }
812
+    }
813
+
814
+    /**
815
+     * Interpret the given exception and decide whether it is due to an
816
+     * unavailable storage, invalid storage or other.
817
+     * This will either throw StorageInvalidException, StorageNotAvailableException
818
+     * or do nothing.
819
+     *
820
+     * @param Exception $e sabre exception
821
+     * @param string $path optional path from the operation
822
+     *
823
+     * @throws StorageInvalidException if the storage is invalid, for example
824
+     * when the authentication expired or is invalid
825
+     * @throws StorageNotAvailableException if the storage is not available,
826
+     * which might be temporary
827
+     */
828
+    protected function convertException(Exception $e, $path = '') {
829
+        \OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
830
+        if ($e instanceof ClientHttpException) {
831
+            if ($e->getHttpStatus() === Http::STATUS_LOCKED) {
832
+                throw new \OCP\Lock\LockedException($path);
833
+            }
834
+            if ($e->getHttpStatus() === Http::STATUS_UNAUTHORIZED) {
835
+                // either password was changed or was invalid all along
836
+                throw new StorageInvalidException(get_class($e) . ': ' . $e->getMessage());
837
+            } else if ($e->getHttpStatus() === Http::STATUS_METHOD_NOT_ALLOWED) {
838
+                // ignore exception for MethodNotAllowed, false will be returned
839
+                return;
840
+            }
841
+            throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
842
+        } else if ($e instanceof ClientException) {
843
+            // connection timeout or refused, server could be temporarily down
844
+            throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
845
+        } else if ($e instanceof \InvalidArgumentException) {
846
+            // parse error because the server returned HTML instead of XML,
847
+            // possibly temporarily down
848
+            throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
849
+        } else if (($e instanceof StorageNotAvailableException) || ($e instanceof StorageInvalidException)) {
850
+            // rethrow
851
+            throw $e;
852
+        }
853
+
854
+        // TODO: only log for now, but in the future need to wrap/rethrow exception
855
+    }
856 856
 }
857 857
 
Please login to merge, or discard this patch.
apps/files_external/lib/Lib/Storage/Swift.php 3 patches
Doc Comments   +4 added lines, -1 removed lines patch added patch discarded remove patch
@@ -83,7 +83,7 @@  discard block
 block discarded – undo
83 83
 
84 84
 	/**
85 85
 	 * @param string $path
86
-	 * @return mixed|string
86
+	 * @return string
87 87
 	 */
88 88
 	private function normalizePath(string $path) {
89 89
 		$path = trim($path, '/');
@@ -570,6 +570,9 @@  discard block
 block discarded – undo
570 570
 		return $this->container;
571 571
 	}
572 572
 
573
+	/**
574
+	 * @param string $path
575
+	 */
573 576
 	public function writeBack($tmpFile, $path) {
574 577
 		$fileData = fopen($tmpFile, 'r');
575 578
 		$this->objectStore->writeObject($path, $fileData);
Please login to merge, or discard this patch.
Indentation   +562 added lines, -562 removed lines patch added patch discarded remove patch
@@ -49,570 +49,570 @@
 block discarded – undo
49 49
 use OpenStack\ObjectStore\v1\Models\StorageObject;
50 50
 
51 51
 class Swift extends \OC\Files\Storage\Common {
52
-	/** @var SwiftFactory */
53
-	private $connectionFactory;
54
-	/**
55
-	 * @var \OpenStack\ObjectStore\v1\Models\Container
56
-	 */
57
-	private $container;
58
-	/**
59
-	 * @var string
60
-	 */
61
-	private $bucket;
62
-	/**
63
-	 * Connection parameters
64
-	 *
65
-	 * @var array
66
-	 */
67
-	private $params;
68
-
69
-	/** @var string */
70
-	private $id;
71
-
72
-	/** @var \OC\Files\ObjectStore\Swift */
73
-	private $objectStore;
74
-
75
-	/**
76
-	 * Key value cache mapping path to data object. Maps path to
77
-	 * \OpenCloud\OpenStack\ObjectStorage\Resource\DataObject for existing
78
-	 * paths and path to false for not existing paths.
79
-	 *
80
-	 * @var \OCP\ICache
81
-	 */
82
-	private $objectCache;
83
-
84
-	/**
85
-	 * @param string $path
86
-	 * @return mixed|string
87
-	 */
88
-	private function normalizePath(string $path) {
89
-		$path = trim($path, '/');
90
-
91
-		if (!$path) {
92
-			$path = '.';
93
-		}
94
-
95
-		$path = str_replace('#', '%23', $path);
96
-
97
-		return $path;
98
-	}
99
-
100
-	const SUBCONTAINER_FILE = '.subcontainers';
101
-
102
-	/**
103
-	 * translate directory path to container name
104
-	 *
105
-	 * @param string $path
106
-	 * @return string
107
-	 */
108
-
109
-	/**
110
-	 * Fetches an object from the API.
111
-	 * If the object is cached already or a
112
-	 * failed "doesn't exist" response was cached,
113
-	 * that one will be returned.
114
-	 *
115
-	 * @param string $path
116
-	 * @return StorageObject|bool object
117
-	 * or false if the object did not exist
118
-	 * @throws \OCP\Files\StorageAuthException
119
-	 * @throws \OCP\Files\StorageNotAvailableException
120
-	 */
121
-	private function fetchObject(string $path) {
122
-		if ($this->objectCache->hasKey($path)) {
123
-			// might be "false" if object did not exist from last check
124
-			return $this->objectCache->get($path);
125
-		}
126
-		try {
127
-			$object = $this->getContainer()->getObject($path);
128
-			$object->retrieve();
129
-			$this->objectCache->set($path, $object);
130
-			return $object;
131
-		} catch (BadResponseError $e) {
132
-			// Expected response is "404 Not Found", so only log if it isn't
133
-			if ($e->getResponse()->getStatusCode() !== 404) {
134
-				\OC::$server->getLogger()->logException($e, [
135
-					'level' => \OCP\Util::ERROR,
136
-					'app' => 'files_external',
137
-				]);
138
-			}
139
-			$this->objectCache->set($path, false);
140
-			return false;
141
-		}
142
-	}
143
-
144
-	/**
145
-	 * Returns whether the given path exists.
146
-	 *
147
-	 * @param string $path
148
-	 *
149
-	 * @return bool true if the object exist, false otherwise
150
-	 * @throws \OCP\Files\StorageAuthException
151
-	 * @throws \OCP\Files\StorageNotAvailableException
152
-	 */
153
-	private function doesObjectExist($path) {
154
-		return $this->fetchObject($path) !== false;
155
-	}
156
-
157
-	public function __construct($params) {
158
-		if ((empty($params['key']) and empty($params['password']))
159
-			or (empty($params['user']) && empty($params['userid'])) or empty($params['bucket'])
160
-			or empty($params['region'])
161
-		) {
162
-			throw new StorageBadConfigException("API Key or password, Username, Bucket and Region have to be configured.");
163
-		}
164
-
165
-		$user = isset($params['user']) ? $params['user'] : $params['userid'];
166
-		$this->id = 'swift::' . $user . md5($params['bucket']);
167
-
168
-		$bucketUrl = new Uri($params['bucket']);
169
-		if ($bucketUrl->getHost()) {
170
-			$params['bucket'] = basename($bucketUrl->getPath());
171
-			$params['endpoint_url'] = (string)$bucketUrl->withPath(dirname($bucketUrl->getPath()));
172
-		}
173
-
174
-		if (empty($params['url'])) {
175
-			$params['url'] = 'https://identity.api.rackspacecloud.com/v2.0/';
176
-		}
177
-
178
-		if (empty($params['service_name'])) {
179
-			$params['service_name'] = 'cloudFiles';
180
-		}
181
-
182
-		$params['autocreate'] = true;
183
-
184
-		if (isset($params['userid'])) {
185
-			$params['user'] = [
186
-				'id' => $params['userid'],
187
-				'password' => $params['password']
188
-			];
189
-		}
190
-
191
-		$this->params = $params;
192
-		// FIXME: private class...
193
-		$this->objectCache = new \OC\Cache\CappedMemoryCache();
194
-		$this->connectionFactory = new SwiftFactory(\OC::$server->getMemCacheFactory()->createDistributed('swift/'), $this->params);
195
-		$this->objectStore = new \OC\Files\ObjectStore\Swift($this->params, $this->connectionFactory);
196
-		$this->bucket = $params['bucket'];
197
-	}
198
-
199
-	public function mkdir($path) {
200
-		$path = $this->normalizePath($path);
201
-
202
-		if ($this->is_dir($path)) {
203
-			return false;
204
-		}
205
-
206
-		if ($path !== '.') {
207
-			$path .= '/';
208
-		}
209
-
210
-		try {
211
-			$this->getContainer()->createObject([
212
-				'name' => $path,
213
-				'content' => '',
214
-				'headers' => ['content-type' => 'httpd/unix-directory']
215
-			]);
216
-			// invalidate so that the next access gets the real object
217
-			// with all properties
218
-			$this->objectCache->remove($path);
219
-		} catch (BadResponseError $e) {
220
-			\OC::$server->getLogger()->logException($e, [
221
-				'level' => \OCP\Util::ERROR,
222
-				'app' => 'files_external',
223
-			]);
224
-			return false;
225
-		}
226
-
227
-		return true;
228
-	}
229
-
230
-	public function file_exists($path) {
231
-		$path = $this->normalizePath($path);
232
-
233
-		if ($path !== '.' && $this->is_dir($path)) {
234
-			$path .= '/';
235
-		}
236
-
237
-		return $this->doesObjectExist($path);
238
-	}
239
-
240
-	public function rmdir($path) {
241
-		$path = $this->normalizePath($path);
242
-
243
-		if (!$this->is_dir($path) || !$this->isDeletable($path)) {
244
-			return false;
245
-		}
246
-
247
-		$dh = $this->opendir($path);
248
-		while ($file = readdir($dh)) {
249
-			if (\OC\Files\Filesystem::isIgnoredDir($file)) {
250
-				continue;
251
-			}
252
-
253
-			if ($this->is_dir($path . '/' . $file)) {
254
-				$this->rmdir($path . '/' . $file);
255
-			} else {
256
-				$this->unlink($path . '/' . $file);
257
-			}
258
-		}
259
-
260
-		try {
261
-			$this->objectStore->deleteObject($path . '/');
262
-			$this->objectCache->remove($path . '/');
263
-		} catch (BadResponseError $e) {
264
-			\OC::$server->getLogger()->logException($e, [
265
-				'level' => \OCP\Util::ERROR,
266
-				'app' => 'files_external',
267
-			]);
268
-			return false;
269
-		}
270
-
271
-		return true;
272
-	}
273
-
274
-	public function opendir($path) {
275
-		$path = $this->normalizePath($path);
276
-
277
-		if ($path === '.') {
278
-			$path = '';
279
-		} else {
280
-			$path .= '/';
281
-		}
52
+    /** @var SwiftFactory */
53
+    private $connectionFactory;
54
+    /**
55
+     * @var \OpenStack\ObjectStore\v1\Models\Container
56
+     */
57
+    private $container;
58
+    /**
59
+     * @var string
60
+     */
61
+    private $bucket;
62
+    /**
63
+     * Connection parameters
64
+     *
65
+     * @var array
66
+     */
67
+    private $params;
68
+
69
+    /** @var string */
70
+    private $id;
71
+
72
+    /** @var \OC\Files\ObjectStore\Swift */
73
+    private $objectStore;
74
+
75
+    /**
76
+     * Key value cache mapping path to data object. Maps path to
77
+     * \OpenCloud\OpenStack\ObjectStorage\Resource\DataObject for existing
78
+     * paths and path to false for not existing paths.
79
+     *
80
+     * @var \OCP\ICache
81
+     */
82
+    private $objectCache;
83
+
84
+    /**
85
+     * @param string $path
86
+     * @return mixed|string
87
+     */
88
+    private function normalizePath(string $path) {
89
+        $path = trim($path, '/');
90
+
91
+        if (!$path) {
92
+            $path = '.';
93
+        }
94
+
95
+        $path = str_replace('#', '%23', $path);
96
+
97
+        return $path;
98
+    }
99
+
100
+    const SUBCONTAINER_FILE = '.subcontainers';
101
+
102
+    /**
103
+     * translate directory path to container name
104
+     *
105
+     * @param string $path
106
+     * @return string
107
+     */
108
+
109
+    /**
110
+     * Fetches an object from the API.
111
+     * If the object is cached already or a
112
+     * failed "doesn't exist" response was cached,
113
+     * that one will be returned.
114
+     *
115
+     * @param string $path
116
+     * @return StorageObject|bool object
117
+     * or false if the object did not exist
118
+     * @throws \OCP\Files\StorageAuthException
119
+     * @throws \OCP\Files\StorageNotAvailableException
120
+     */
121
+    private function fetchObject(string $path) {
122
+        if ($this->objectCache->hasKey($path)) {
123
+            // might be "false" if object did not exist from last check
124
+            return $this->objectCache->get($path);
125
+        }
126
+        try {
127
+            $object = $this->getContainer()->getObject($path);
128
+            $object->retrieve();
129
+            $this->objectCache->set($path, $object);
130
+            return $object;
131
+        } catch (BadResponseError $e) {
132
+            // Expected response is "404 Not Found", so only log if it isn't
133
+            if ($e->getResponse()->getStatusCode() !== 404) {
134
+                \OC::$server->getLogger()->logException($e, [
135
+                    'level' => \OCP\Util::ERROR,
136
+                    'app' => 'files_external',
137
+                ]);
138
+            }
139
+            $this->objectCache->set($path, false);
140
+            return false;
141
+        }
142
+    }
143
+
144
+    /**
145
+     * Returns whether the given path exists.
146
+     *
147
+     * @param string $path
148
+     *
149
+     * @return bool true if the object exist, false otherwise
150
+     * @throws \OCP\Files\StorageAuthException
151
+     * @throws \OCP\Files\StorageNotAvailableException
152
+     */
153
+    private function doesObjectExist($path) {
154
+        return $this->fetchObject($path) !== false;
155
+    }
156
+
157
+    public function __construct($params) {
158
+        if ((empty($params['key']) and empty($params['password']))
159
+            or (empty($params['user']) && empty($params['userid'])) or empty($params['bucket'])
160
+            or empty($params['region'])
161
+        ) {
162
+            throw new StorageBadConfigException("API Key or password, Username, Bucket and Region have to be configured.");
163
+        }
164
+
165
+        $user = isset($params['user']) ? $params['user'] : $params['userid'];
166
+        $this->id = 'swift::' . $user . md5($params['bucket']);
167
+
168
+        $bucketUrl = new Uri($params['bucket']);
169
+        if ($bucketUrl->getHost()) {
170
+            $params['bucket'] = basename($bucketUrl->getPath());
171
+            $params['endpoint_url'] = (string)$bucketUrl->withPath(dirname($bucketUrl->getPath()));
172
+        }
173
+
174
+        if (empty($params['url'])) {
175
+            $params['url'] = 'https://identity.api.rackspacecloud.com/v2.0/';
176
+        }
177
+
178
+        if (empty($params['service_name'])) {
179
+            $params['service_name'] = 'cloudFiles';
180
+        }
181
+
182
+        $params['autocreate'] = true;
183
+
184
+        if (isset($params['userid'])) {
185
+            $params['user'] = [
186
+                'id' => $params['userid'],
187
+                'password' => $params['password']
188
+            ];
189
+        }
190
+
191
+        $this->params = $params;
192
+        // FIXME: private class...
193
+        $this->objectCache = new \OC\Cache\CappedMemoryCache();
194
+        $this->connectionFactory = new SwiftFactory(\OC::$server->getMemCacheFactory()->createDistributed('swift/'), $this->params);
195
+        $this->objectStore = new \OC\Files\ObjectStore\Swift($this->params, $this->connectionFactory);
196
+        $this->bucket = $params['bucket'];
197
+    }
198
+
199
+    public function mkdir($path) {
200
+        $path = $this->normalizePath($path);
201
+
202
+        if ($this->is_dir($path)) {
203
+            return false;
204
+        }
205
+
206
+        if ($path !== '.') {
207
+            $path .= '/';
208
+        }
209
+
210
+        try {
211
+            $this->getContainer()->createObject([
212
+                'name' => $path,
213
+                'content' => '',
214
+                'headers' => ['content-type' => 'httpd/unix-directory']
215
+            ]);
216
+            // invalidate so that the next access gets the real object
217
+            // with all properties
218
+            $this->objectCache->remove($path);
219
+        } catch (BadResponseError $e) {
220
+            \OC::$server->getLogger()->logException($e, [
221
+                'level' => \OCP\Util::ERROR,
222
+                'app' => 'files_external',
223
+            ]);
224
+            return false;
225
+        }
226
+
227
+        return true;
228
+    }
229
+
230
+    public function file_exists($path) {
231
+        $path = $this->normalizePath($path);
232
+
233
+        if ($path !== '.' && $this->is_dir($path)) {
234
+            $path .= '/';
235
+        }
236
+
237
+        return $this->doesObjectExist($path);
238
+    }
239
+
240
+    public function rmdir($path) {
241
+        $path = $this->normalizePath($path);
242
+
243
+        if (!$this->is_dir($path) || !$this->isDeletable($path)) {
244
+            return false;
245
+        }
246
+
247
+        $dh = $this->opendir($path);
248
+        while ($file = readdir($dh)) {
249
+            if (\OC\Files\Filesystem::isIgnoredDir($file)) {
250
+                continue;
251
+            }
252
+
253
+            if ($this->is_dir($path . '/' . $file)) {
254
+                $this->rmdir($path . '/' . $file);
255
+            } else {
256
+                $this->unlink($path . '/' . $file);
257
+            }
258
+        }
259
+
260
+        try {
261
+            $this->objectStore->deleteObject($path . '/');
262
+            $this->objectCache->remove($path . '/');
263
+        } catch (BadResponseError $e) {
264
+            \OC::$server->getLogger()->logException($e, [
265
+                'level' => \OCP\Util::ERROR,
266
+                'app' => 'files_external',
267
+            ]);
268
+            return false;
269
+        }
270
+
271
+        return true;
272
+    }
273
+
274
+    public function opendir($path) {
275
+        $path = $this->normalizePath($path);
276
+
277
+        if ($path === '.') {
278
+            $path = '';
279
+        } else {
280
+            $path .= '/';
281
+        }
282 282
 
283 283
 //		$path = str_replace('%23', '#', $path); // the prefix is sent as a query param, so revert the encoding of #
284 284
 
285
-		try {
286
-			$files = [];
287
-			$objects = $this->getContainer()->listObjects([
288
-				'prefix' => $path,
289
-				'delimiter' => '/'
290
-			]);
291
-
292
-			/** @var StorageObject $object */
293
-			foreach ($objects as $object) {
294
-				$file = basename($object->name);
295
-				if ($file !== basename($path) && $file !== '.') {
296
-					$files[] = $file;
297
-				}
298
-			}
299
-
300
-			return IteratorDirectory::wrap($files);
301
-		} catch (\Exception $e) {
302
-			\OC::$server->getLogger()->logException($e, [
303
-				'level' => \OCP\Util::ERROR,
304
-				'app' => 'files_external',
305
-			]);
306
-			return false;
307
-		}
308
-
309
-	}
310
-
311
-	public function stat($path) {
312
-		$path = $this->normalizePath($path);
313
-
314
-		if ($path === '.') {
315
-			$path = '';
316
-		} else if ($this->is_dir($path)) {
317
-			$path .= '/';
318
-		}
319
-
320
-		try {
321
-			$object = $this->fetchObject($path);
322
-			if (!$object) {
323
-				return false;
324
-			}
325
-		} catch (BadResponseError $e) {
326
-			\OC::$server->getLogger()->logException($e, [
327
-				'level' => \OCP\Util::ERROR,
328
-				'app' => 'files_external',
329
-			]);
330
-			return false;
331
-		}
332
-
333
-		$dateTime = $object->lastModified ? \DateTime::createFromFormat(\DateTime::RFC1123, $object->lastModified) : false;
334
-		$mtime = $dateTime ? $dateTime->getTimestamp() : null;
335
-		$objectMetadata = $object->getMetadata();
336
-		if (isset($objectMetadata['timestamp'])) {
337
-			$mtime = $objectMetadata['timestamp'];
338
-		}
339
-
340
-		if (!empty($mtime)) {
341
-			$mtime = floor($mtime);
342
-		}
343
-
344
-		$stat = array();
345
-		$stat['size'] = (int)$object->contentLength;
346
-		$stat['mtime'] = $mtime;
347
-		$stat['atime'] = time();
348
-		return $stat;
349
-	}
350
-
351
-	public function filetype($path) {
352
-		$path = $this->normalizePath($path);
353
-
354
-		if ($path !== '.' && $this->doesObjectExist($path)) {
355
-			return 'file';
356
-		}
357
-
358
-		if ($path !== '.') {
359
-			$path .= '/';
360
-		}
361
-
362
-		if ($this->doesObjectExist($path)) {
363
-			return 'dir';
364
-		}
365
-	}
366
-
367
-	public function unlink($path) {
368
-		$path = $this->normalizePath($path);
369
-
370
-		if ($this->is_dir($path)) {
371
-			return $this->rmdir($path);
372
-		}
373
-
374
-		try {
375
-			$this->objectStore->deleteObject($path);
376
-			$this->objectCache->remove($path);
377
-			$this->objectCache->remove($path . '/');
378
-		} catch (BadResponseError $e) {
379
-			if ($e->getResponse()->getStatusCode() !== 404) {
380
-				\OC::$server->getLogger()->logException($e, [
381
-					'level' => \OCP\Util::ERROR,
382
-					'app' => 'files_external',
383
-				]);
384
-				throw $e;
385
-			}
386
-		}
387
-
388
-		return true;
389
-	}
390
-
391
-	public function fopen($path, $mode) {
392
-		$path = $this->normalizePath($path);
393
-
394
-		switch ($mode) {
395
-			case 'a':
396
-			case 'ab':
397
-			case 'a+':
398
-				return false;
399
-			case 'r':
400
-			case 'rb':
401
-				try {
402
-					return $this->objectStore->readObject($path);
403
-				} catch (BadResponseError $e) {
404
-					\OC::$server->getLogger()->logException($e, [
405
-						'level' => \OCP\Util::ERROR,
406
-						'app' => 'files_external',
407
-					]);
408
-					return false;
409
-				}
410
-			case 'w':
411
-			case 'wb':
412
-			case 'r+':
413
-			case 'w+':
414
-			case 'wb+':
415
-			case 'x':
416
-			case 'x+':
417
-			case 'c':
418
-			case 'c+':
419
-				if (strrpos($path, '.') !== false) {
420
-					$ext = substr($path, strrpos($path, '.'));
421
-				} else {
422
-					$ext = '';
423
-				}
424
-				$tmpFile = \OCP\Files::tmpFile($ext);
425
-				// Fetch existing file if required
426
-				if ($mode[0] !== 'w' && $this->file_exists($path)) {
427
-					if ($mode[0] === 'x') {
428
-						// File cannot already exist
429
-						return false;
430
-					}
431
-					$source = $this->fopen($path, 'r');
432
-					file_put_contents($tmpFile, $source);
433
-				}
434
-				$handle = fopen($tmpFile, $mode);
435
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
436
-					$this->writeBack($tmpFile, $path);
437
-				});
438
-		}
439
-	}
440
-
441
-	public function touch($path, $mtime = null) {
442
-		$path = $this->normalizePath($path);
443
-		if (is_null($mtime)) {
444
-			$mtime = time();
445
-		}
446
-		$metadata = ['timestamp' => $mtime];
447
-		if ($this->file_exists($path)) {
448
-			if ($this->is_dir($path) && $path !== '.') {
449
-				$path .= '/';
450
-			}
451
-
452
-			$object = $this->fetchObject($path);
453
-			if ($object->mergeMetadata($metadata)) {
454
-				// invalidate target object to force repopulation on fetch
455
-				$this->objectCache->remove($path);
456
-			}
457
-			return true;
458
-		} else {
459
-			$mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
460
-			$this->getContainer()->createObject([
461
-				'name' => $path,
462
-				'content' => '',
463
-				'headers' => ['content-type' => 'httpd/unix-directory']
464
-			]);
465
-			// invalidate target object to force repopulation on fetch
466
-			$this->objectCache->remove($path);
467
-			return true;
468
-		}
469
-	}
470
-
471
-	public function copy($path1, $path2) {
472
-		$path1 = $this->normalizePath($path1);
473
-		$path2 = $this->normalizePath($path2);
474
-
475
-		$fileType = $this->filetype($path1);
476
-		if ($fileType) {
477
-			// make way
478
-			$this->unlink($path2);
479
-		}
480
-
481
-		if ($fileType === 'file') {
482
-			try {
483
-				$source = $this->fetchObject($path1);
484
-				$source->copy([
485
-					'destination' => $this->bucket . '/' . $path2
486
-				]);
487
-				// invalidate target object to force repopulation on fetch
488
-				$this->objectCache->remove($path2);
489
-				$this->objectCache->remove($path2 . '/');
490
-			} catch (BadResponseError $e) {
491
-				\OC::$server->getLogger()->logException($e, [
492
-					'level' => \OCP\Util::ERROR,
493
-					'app' => 'files_external',
494
-				]);
495
-				return false;
496
-			}
497
-
498
-		} else if ($fileType === 'dir') {
499
-			try {
500
-				$source = $this->fetchObject($path1 . '/');
501
-				$source->copy([
502
-					'destination' => $this->bucket . '/' . $path2 . '/'
503
-				]);
504
-				// invalidate target object to force repopulation on fetch
505
-				$this->objectCache->remove($path2);
506
-				$this->objectCache->remove($path2 . '/');
507
-			} catch (BadResponseError $e) {
508
-				\OC::$server->getLogger()->logException($e, [
509
-					'level' => \OCP\Util::ERROR,
510
-					'app' => 'files_external',
511
-				]);
512
-				return false;
513
-			}
514
-
515
-			$dh = $this->opendir($path1);
516
-			while ($file = readdir($dh)) {
517
-				if (\OC\Files\Filesystem::isIgnoredDir($file)) {
518
-					continue;
519
-				}
520
-
521
-				$source = $path1 . '/' . $file;
522
-				$target = $path2 . '/' . $file;
523
-				$this->copy($source, $target);
524
-			}
525
-
526
-		} else {
527
-			//file does not exist
528
-			return false;
529
-		}
530
-
531
-		return true;
532
-	}
533
-
534
-	public function rename($path1, $path2) {
535
-		$path1 = $this->normalizePath($path1);
536
-		$path2 = $this->normalizePath($path2);
537
-
538
-		$fileType = $this->filetype($path1);
539
-
540
-		if ($fileType === 'dir' || $fileType === 'file') {
541
-			// copy
542
-			if ($this->copy($path1, $path2) === false) {
543
-				return false;
544
-			}
545
-
546
-			// cleanup
547
-			if ($this->unlink($path1) === false) {
548
-				throw new \Exception('failed to remove original');
549
-				$this->unlink($path2);
550
-				return false;
551
-			}
552
-
553
-			return true;
554
-		}
555
-
556
-		return false;
557
-	}
558
-
559
-	public function getId() {
560
-		return $this->id;
561
-	}
562
-
563
-	/**
564
-	 * Returns the initialized object store container.
565
-	 *
566
-	 * @return \OpenStack\ObjectStore\v1\Models\Container
567
-	 * @throws \OCP\Files\StorageAuthException
568
-	 * @throws \OCP\Files\StorageNotAvailableException
569
-	 */
570
-	public function getContainer() {
571
-		if (is_null($this->container)) {
572
-			$this->container = $this->connectionFactory->getContainer();
573
-
574
-			if (!$this->file_exists('.')) {
575
-				$this->mkdir('.');
576
-			}
577
-		}
578
-		return $this->container;
579
-	}
580
-
581
-	public function writeBack($tmpFile, $path) {
582
-		$fileData = fopen($tmpFile, 'r');
583
-		$this->objectStore->writeObject($path, $fileData);
584
-		// invalidate target object to force repopulation on fetch
585
-		$this->objectCache->remove($path);
586
-		unlink($tmpFile);
587
-	}
588
-
589
-	public function hasUpdated($path, $time) {
590
-		if ($this->is_file($path)) {
591
-			return parent::hasUpdated($path, $time);
592
-		}
593
-		$path = $this->normalizePath($path);
594
-		$dh = $this->opendir($path);
595
-		$content = array();
596
-		while (($file = readdir($dh)) !== false) {
597
-			$content[] = $file;
598
-		}
599
-		if ($path === '.') {
600
-			$path = '';
601
-		}
602
-		$cachedContent = $this->getCache()->getFolderContents($path);
603
-		$cachedNames = array_map(function ($content) {
604
-			return $content['name'];
605
-		}, $cachedContent);
606
-		sort($cachedNames);
607
-		sort($content);
608
-		return $cachedNames !== $content;
609
-	}
610
-
611
-	/**
612
-	 * check if curl is installed
613
-	 */
614
-	public static function checkDependencies() {
615
-		return true;
616
-	}
285
+        try {
286
+            $files = [];
287
+            $objects = $this->getContainer()->listObjects([
288
+                'prefix' => $path,
289
+                'delimiter' => '/'
290
+            ]);
291
+
292
+            /** @var StorageObject $object */
293
+            foreach ($objects as $object) {
294
+                $file = basename($object->name);
295
+                if ($file !== basename($path) && $file !== '.') {
296
+                    $files[] = $file;
297
+                }
298
+            }
299
+
300
+            return IteratorDirectory::wrap($files);
301
+        } catch (\Exception $e) {
302
+            \OC::$server->getLogger()->logException($e, [
303
+                'level' => \OCP\Util::ERROR,
304
+                'app' => 'files_external',
305
+            ]);
306
+            return false;
307
+        }
308
+
309
+    }
310
+
311
+    public function stat($path) {
312
+        $path = $this->normalizePath($path);
313
+
314
+        if ($path === '.') {
315
+            $path = '';
316
+        } else if ($this->is_dir($path)) {
317
+            $path .= '/';
318
+        }
319
+
320
+        try {
321
+            $object = $this->fetchObject($path);
322
+            if (!$object) {
323
+                return false;
324
+            }
325
+        } catch (BadResponseError $e) {
326
+            \OC::$server->getLogger()->logException($e, [
327
+                'level' => \OCP\Util::ERROR,
328
+                'app' => 'files_external',
329
+            ]);
330
+            return false;
331
+        }
332
+
333
+        $dateTime = $object->lastModified ? \DateTime::createFromFormat(\DateTime::RFC1123, $object->lastModified) : false;
334
+        $mtime = $dateTime ? $dateTime->getTimestamp() : null;
335
+        $objectMetadata = $object->getMetadata();
336
+        if (isset($objectMetadata['timestamp'])) {
337
+            $mtime = $objectMetadata['timestamp'];
338
+        }
339
+
340
+        if (!empty($mtime)) {
341
+            $mtime = floor($mtime);
342
+        }
343
+
344
+        $stat = array();
345
+        $stat['size'] = (int)$object->contentLength;
346
+        $stat['mtime'] = $mtime;
347
+        $stat['atime'] = time();
348
+        return $stat;
349
+    }
350
+
351
+    public function filetype($path) {
352
+        $path = $this->normalizePath($path);
353
+
354
+        if ($path !== '.' && $this->doesObjectExist($path)) {
355
+            return 'file';
356
+        }
357
+
358
+        if ($path !== '.') {
359
+            $path .= '/';
360
+        }
361
+
362
+        if ($this->doesObjectExist($path)) {
363
+            return 'dir';
364
+        }
365
+    }
366
+
367
+    public function unlink($path) {
368
+        $path = $this->normalizePath($path);
369
+
370
+        if ($this->is_dir($path)) {
371
+            return $this->rmdir($path);
372
+        }
373
+
374
+        try {
375
+            $this->objectStore->deleteObject($path);
376
+            $this->objectCache->remove($path);
377
+            $this->objectCache->remove($path . '/');
378
+        } catch (BadResponseError $e) {
379
+            if ($e->getResponse()->getStatusCode() !== 404) {
380
+                \OC::$server->getLogger()->logException($e, [
381
+                    'level' => \OCP\Util::ERROR,
382
+                    'app' => 'files_external',
383
+                ]);
384
+                throw $e;
385
+            }
386
+        }
387
+
388
+        return true;
389
+    }
390
+
391
+    public function fopen($path, $mode) {
392
+        $path = $this->normalizePath($path);
393
+
394
+        switch ($mode) {
395
+            case 'a':
396
+            case 'ab':
397
+            case 'a+':
398
+                return false;
399
+            case 'r':
400
+            case 'rb':
401
+                try {
402
+                    return $this->objectStore->readObject($path);
403
+                } catch (BadResponseError $e) {
404
+                    \OC::$server->getLogger()->logException($e, [
405
+                        'level' => \OCP\Util::ERROR,
406
+                        'app' => 'files_external',
407
+                    ]);
408
+                    return false;
409
+                }
410
+            case 'w':
411
+            case 'wb':
412
+            case 'r+':
413
+            case 'w+':
414
+            case 'wb+':
415
+            case 'x':
416
+            case 'x+':
417
+            case 'c':
418
+            case 'c+':
419
+                if (strrpos($path, '.') !== false) {
420
+                    $ext = substr($path, strrpos($path, '.'));
421
+                } else {
422
+                    $ext = '';
423
+                }
424
+                $tmpFile = \OCP\Files::tmpFile($ext);
425
+                // Fetch existing file if required
426
+                if ($mode[0] !== 'w' && $this->file_exists($path)) {
427
+                    if ($mode[0] === 'x') {
428
+                        // File cannot already exist
429
+                        return false;
430
+                    }
431
+                    $source = $this->fopen($path, 'r');
432
+                    file_put_contents($tmpFile, $source);
433
+                }
434
+                $handle = fopen($tmpFile, $mode);
435
+                return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
436
+                    $this->writeBack($tmpFile, $path);
437
+                });
438
+        }
439
+    }
440
+
441
+    public function touch($path, $mtime = null) {
442
+        $path = $this->normalizePath($path);
443
+        if (is_null($mtime)) {
444
+            $mtime = time();
445
+        }
446
+        $metadata = ['timestamp' => $mtime];
447
+        if ($this->file_exists($path)) {
448
+            if ($this->is_dir($path) && $path !== '.') {
449
+                $path .= '/';
450
+            }
451
+
452
+            $object = $this->fetchObject($path);
453
+            if ($object->mergeMetadata($metadata)) {
454
+                // invalidate target object to force repopulation on fetch
455
+                $this->objectCache->remove($path);
456
+            }
457
+            return true;
458
+        } else {
459
+            $mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
460
+            $this->getContainer()->createObject([
461
+                'name' => $path,
462
+                'content' => '',
463
+                'headers' => ['content-type' => 'httpd/unix-directory']
464
+            ]);
465
+            // invalidate target object to force repopulation on fetch
466
+            $this->objectCache->remove($path);
467
+            return true;
468
+        }
469
+    }
470
+
471
+    public function copy($path1, $path2) {
472
+        $path1 = $this->normalizePath($path1);
473
+        $path2 = $this->normalizePath($path2);
474
+
475
+        $fileType = $this->filetype($path1);
476
+        if ($fileType) {
477
+            // make way
478
+            $this->unlink($path2);
479
+        }
480
+
481
+        if ($fileType === 'file') {
482
+            try {
483
+                $source = $this->fetchObject($path1);
484
+                $source->copy([
485
+                    'destination' => $this->bucket . '/' . $path2
486
+                ]);
487
+                // invalidate target object to force repopulation on fetch
488
+                $this->objectCache->remove($path2);
489
+                $this->objectCache->remove($path2 . '/');
490
+            } catch (BadResponseError $e) {
491
+                \OC::$server->getLogger()->logException($e, [
492
+                    'level' => \OCP\Util::ERROR,
493
+                    'app' => 'files_external',
494
+                ]);
495
+                return false;
496
+            }
497
+
498
+        } else if ($fileType === 'dir') {
499
+            try {
500
+                $source = $this->fetchObject($path1 . '/');
501
+                $source->copy([
502
+                    'destination' => $this->bucket . '/' . $path2 . '/'
503
+                ]);
504
+                // invalidate target object to force repopulation on fetch
505
+                $this->objectCache->remove($path2);
506
+                $this->objectCache->remove($path2 . '/');
507
+            } catch (BadResponseError $e) {
508
+                \OC::$server->getLogger()->logException($e, [
509
+                    'level' => \OCP\Util::ERROR,
510
+                    'app' => 'files_external',
511
+                ]);
512
+                return false;
513
+            }
514
+
515
+            $dh = $this->opendir($path1);
516
+            while ($file = readdir($dh)) {
517
+                if (\OC\Files\Filesystem::isIgnoredDir($file)) {
518
+                    continue;
519
+                }
520
+
521
+                $source = $path1 . '/' . $file;
522
+                $target = $path2 . '/' . $file;
523
+                $this->copy($source, $target);
524
+            }
525
+
526
+        } else {
527
+            //file does not exist
528
+            return false;
529
+        }
530
+
531
+        return true;
532
+    }
533
+
534
+    public function rename($path1, $path2) {
535
+        $path1 = $this->normalizePath($path1);
536
+        $path2 = $this->normalizePath($path2);
537
+
538
+        $fileType = $this->filetype($path1);
539
+
540
+        if ($fileType === 'dir' || $fileType === 'file') {
541
+            // copy
542
+            if ($this->copy($path1, $path2) === false) {
543
+                return false;
544
+            }
545
+
546
+            // cleanup
547
+            if ($this->unlink($path1) === false) {
548
+                throw new \Exception('failed to remove original');
549
+                $this->unlink($path2);
550
+                return false;
551
+            }
552
+
553
+            return true;
554
+        }
555
+
556
+        return false;
557
+    }
558
+
559
+    public function getId() {
560
+        return $this->id;
561
+    }
562
+
563
+    /**
564
+     * Returns the initialized object store container.
565
+     *
566
+     * @return \OpenStack\ObjectStore\v1\Models\Container
567
+     * @throws \OCP\Files\StorageAuthException
568
+     * @throws \OCP\Files\StorageNotAvailableException
569
+     */
570
+    public function getContainer() {
571
+        if (is_null($this->container)) {
572
+            $this->container = $this->connectionFactory->getContainer();
573
+
574
+            if (!$this->file_exists('.')) {
575
+                $this->mkdir('.');
576
+            }
577
+        }
578
+        return $this->container;
579
+    }
580
+
581
+    public function writeBack($tmpFile, $path) {
582
+        $fileData = fopen($tmpFile, 'r');
583
+        $this->objectStore->writeObject($path, $fileData);
584
+        // invalidate target object to force repopulation on fetch
585
+        $this->objectCache->remove($path);
586
+        unlink($tmpFile);
587
+    }
588
+
589
+    public function hasUpdated($path, $time) {
590
+        if ($this->is_file($path)) {
591
+            return parent::hasUpdated($path, $time);
592
+        }
593
+        $path = $this->normalizePath($path);
594
+        $dh = $this->opendir($path);
595
+        $content = array();
596
+        while (($file = readdir($dh)) !== false) {
597
+            $content[] = $file;
598
+        }
599
+        if ($path === '.') {
600
+            $path = '';
601
+        }
602
+        $cachedContent = $this->getCache()->getFolderContents($path);
603
+        $cachedNames = array_map(function ($content) {
604
+            return $content['name'];
605
+        }, $cachedContent);
606
+        sort($cachedNames);
607
+        sort($content);
608
+        return $cachedNames !== $content;
609
+    }
610
+
611
+    /**
612
+     * check if curl is installed
613
+     */
614
+    public static function checkDependencies() {
615
+        return true;
616
+    }
617 617
 
618 618
 }
Please login to merge, or discard this patch.
Spacing   +19 added lines, -19 removed lines patch added patch discarded remove patch
@@ -1,5 +1,5 @@  discard block
 block discarded – undo
1 1
 <?php
2
-declare(strict_types=1);
2
+declare(strict_types = 1);
3 3
 /**
4 4
  * @copyright Copyright (c) 2016, ownCloud, Inc.
5 5
  *
@@ -163,12 +163,12 @@  discard block
 block discarded – undo
163 163
 		}
164 164
 
165 165
 		$user = isset($params['user']) ? $params['user'] : $params['userid'];
166
-		$this->id = 'swift::' . $user . md5($params['bucket']);
166
+		$this->id = 'swift::'.$user.md5($params['bucket']);
167 167
 
168 168
 		$bucketUrl = new Uri($params['bucket']);
169 169
 		if ($bucketUrl->getHost()) {
170 170
 			$params['bucket'] = basename($bucketUrl->getPath());
171
-			$params['endpoint_url'] = (string)$bucketUrl->withPath(dirname($bucketUrl->getPath()));
171
+			$params['endpoint_url'] = (string) $bucketUrl->withPath(dirname($bucketUrl->getPath()));
172 172
 		}
173 173
 
174 174
 		if (empty($params['url'])) {
@@ -250,16 +250,16 @@  discard block
 block discarded – undo
250 250
 				continue;
251 251
 			}
252 252
 
253
-			if ($this->is_dir($path . '/' . $file)) {
254
-				$this->rmdir($path . '/' . $file);
253
+			if ($this->is_dir($path.'/'.$file)) {
254
+				$this->rmdir($path.'/'.$file);
255 255
 			} else {
256
-				$this->unlink($path . '/' . $file);
256
+				$this->unlink($path.'/'.$file);
257 257
 			}
258 258
 		}
259 259
 
260 260
 		try {
261
-			$this->objectStore->deleteObject($path . '/');
262
-			$this->objectCache->remove($path . '/');
261
+			$this->objectStore->deleteObject($path.'/');
262
+			$this->objectCache->remove($path.'/');
263 263
 		} catch (BadResponseError $e) {
264 264
 			\OC::$server->getLogger()->logException($e, [
265 265
 				'level' => \OCP\Util::ERROR,
@@ -342,7 +342,7 @@  discard block
 block discarded – undo
342 342
 		}
343 343
 
344 344
 		$stat = array();
345
-		$stat['size'] = (int)$object->contentLength;
345
+		$stat['size'] = (int) $object->contentLength;
346 346
 		$stat['mtime'] = $mtime;
347 347
 		$stat['atime'] = time();
348 348
 		return $stat;
@@ -374,7 +374,7 @@  discard block
 block discarded – undo
374 374
 		try {
375 375
 			$this->objectStore->deleteObject($path);
376 376
 			$this->objectCache->remove($path);
377
-			$this->objectCache->remove($path . '/');
377
+			$this->objectCache->remove($path.'/');
378 378
 		} catch (BadResponseError $e) {
379 379
 			if ($e->getResponse()->getStatusCode() !== 404) {
380 380
 				\OC::$server->getLogger()->logException($e, [
@@ -432,7 +432,7 @@  discard block
 block discarded – undo
432 432
 					file_put_contents($tmpFile, $source);
433 433
 				}
434 434
 				$handle = fopen($tmpFile, $mode);
435
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
435
+				return CallbackWrapper::wrap($handle, null, null, function() use ($path, $tmpFile) {
436 436
 					$this->writeBack($tmpFile, $path);
437 437
 				});
438 438
 		}
@@ -482,11 +482,11 @@  discard block
 block discarded – undo
482 482
 			try {
483 483
 				$source = $this->fetchObject($path1);
484 484
 				$source->copy([
485
-					'destination' => $this->bucket . '/' . $path2
485
+					'destination' => $this->bucket.'/'.$path2
486 486
 				]);
487 487
 				// invalidate target object to force repopulation on fetch
488 488
 				$this->objectCache->remove($path2);
489
-				$this->objectCache->remove($path2 . '/');
489
+				$this->objectCache->remove($path2.'/');
490 490
 			} catch (BadResponseError $e) {
491 491
 				\OC::$server->getLogger()->logException($e, [
492 492
 					'level' => \OCP\Util::ERROR,
@@ -497,13 +497,13 @@  discard block
 block discarded – undo
497 497
 
498 498
 		} else if ($fileType === 'dir') {
499 499
 			try {
500
-				$source = $this->fetchObject($path1 . '/');
500
+				$source = $this->fetchObject($path1.'/');
501 501
 				$source->copy([
502
-					'destination' => $this->bucket . '/' . $path2 . '/'
502
+					'destination' => $this->bucket.'/'.$path2.'/'
503 503
 				]);
504 504
 				// invalidate target object to force repopulation on fetch
505 505
 				$this->objectCache->remove($path2);
506
-				$this->objectCache->remove($path2 . '/');
506
+				$this->objectCache->remove($path2.'/');
507 507
 			} catch (BadResponseError $e) {
508 508
 				\OC::$server->getLogger()->logException($e, [
509 509
 					'level' => \OCP\Util::ERROR,
@@ -518,8 +518,8 @@  discard block
 block discarded – undo
518 518
 					continue;
519 519
 				}
520 520
 
521
-				$source = $path1 . '/' . $file;
522
-				$target = $path2 . '/' . $file;
521
+				$source = $path1.'/'.$file;
522
+				$target = $path2.'/'.$file;
523 523
 				$this->copy($source, $target);
524 524
 			}
525 525
 
@@ -600,7 +600,7 @@  discard block
 block discarded – undo
600 600
 			$path = '';
601 601
 		}
602 602
 		$cachedContent = $this->getCache()->getFolderContents($path);
603
-		$cachedNames = array_map(function ($content) {
603
+		$cachedNames = array_map(function($content) {
604 604
 			return $content['name'];
605 605
 		}, $cachedContent);
606 606
 		sort($cachedNames);
Please login to merge, or discard this patch.
lib/private/Files/ObjectStore/Swift.php 1 patch
Indentation   +82 added lines, -82 removed lines patch added patch discarded remove patch
@@ -31,87 +31,87 @@
 block discarded – undo
31 31
 use OCP\Files\StorageAuthException;
32 32
 
33 33
 class Swift implements IObjectStore {
34
-	/**
35
-	 * @var array
36
-	 */
37
-	private $params;
38
-
39
-	/**
40
-	 * @var \OpenStack\ObjectStore\v1\Models\Container|null
41
-	 */
42
-	private $container = null;
43
-
44
-	/** @var SwiftFactory */
45
-	private $swiftFactory;
46
-
47
-	public function __construct($params, SwiftFactory $connectionFactory = null) {
48
-		$this->swiftFactory = $connectionFactory ?: new SwiftFactory(\OC::$server->getMemCacheFactory()->createDistributed('swift::'), $params);
49
-		$this->params = $params;
50
-	}
51
-
52
-	/**
53
-	 * @return \OpenStack\ObjectStore\v1\Models\Container
54
-	 * @throws StorageAuthException
55
-	 * @throws \OCP\Files\StorageNotAvailableException
56
-	 */
57
-	private function getContainer() {
58
-		return $this->swiftFactory->getContainer();
59
-	}
60
-
61
-	/**
62
-	 * @return string the container name where objects are stored
63
-	 */
64
-	public function getStorageId() {
65
-		return $this->params['container'];
66
-	}
67
-
68
-	/**
69
-	 * @param string $urn the unified resource name used to identify the object
70
-	 * @param resource $stream stream with the data to write
71
-	 * @throws \Exception from openstack lib when something goes wrong
72
-	 */
73
-	public function writeObject($urn, $stream) {
74
-		$this->getContainer()->createObject([
75
-			'name' => $urn,
76
-			'stream' => stream_for($stream)
77
-		]);
78
-	}
79
-
80
-	/**
81
-	 * @param string $urn the unified resource name used to identify the object
82
-	 * @return resource stream with the read data
83
-	 * @throws \Exception from openstack lib when something goes wrong
84
-	 */
85
-	public function readObject($urn) {
86
-		$object = $this->getContainer()->getObject($urn);
87
-
88
-		// we need to keep a reference to objectContent or
89
-		// the stream will be closed before we can do anything with it
90
-		$objectContent = $object->download();
91
-		$objectContent->rewind();
92
-
93
-		$stream = $objectContent->detach();
94
-		// save the object content in the context of the stream to prevent it being gc'd until the stream is closed
95
-		stream_context_set_option($stream, 'swift', 'content', $objectContent);
96
-
97
-		return RetryWrapper::wrap($stream);
98
-	}
99
-
100
-	/**
101
-	 * @param string $urn Unified Resource Name
102
-	 * @return void
103
-	 * @throws \Exception from openstack lib when something goes wrong
104
-	 */
105
-	public function deleteObject($urn) {
106
-		$this->getContainer()->getObject($urn)->delete();
107
-	}
108
-
109
-	/**
110
-	 * @return void
111
-	 * @throws \Exception from openstack lib when something goes wrong
112
-	 */
113
-	public function deleteContainer() {
114
-		$this->getContainer()->delete();
115
-	}
34
+    /**
35
+     * @var array
36
+     */
37
+    private $params;
38
+
39
+    /**
40
+     * @var \OpenStack\ObjectStore\v1\Models\Container|null
41
+     */
42
+    private $container = null;
43
+
44
+    /** @var SwiftFactory */
45
+    private $swiftFactory;
46
+
47
+    public function __construct($params, SwiftFactory $connectionFactory = null) {
48
+        $this->swiftFactory = $connectionFactory ?: new SwiftFactory(\OC::$server->getMemCacheFactory()->createDistributed('swift::'), $params);
49
+        $this->params = $params;
50
+    }
51
+
52
+    /**
53
+     * @return \OpenStack\ObjectStore\v1\Models\Container
54
+     * @throws StorageAuthException
55
+     * @throws \OCP\Files\StorageNotAvailableException
56
+     */
57
+    private function getContainer() {
58
+        return $this->swiftFactory->getContainer();
59
+    }
60
+
61
+    /**
62
+     * @return string the container name where objects are stored
63
+     */
64
+    public function getStorageId() {
65
+        return $this->params['container'];
66
+    }
67
+
68
+    /**
69
+     * @param string $urn the unified resource name used to identify the object
70
+     * @param resource $stream stream with the data to write
71
+     * @throws \Exception from openstack lib when something goes wrong
72
+     */
73
+    public function writeObject($urn, $stream) {
74
+        $this->getContainer()->createObject([
75
+            'name' => $urn,
76
+            'stream' => stream_for($stream)
77
+        ]);
78
+    }
79
+
80
+    /**
81
+     * @param string $urn the unified resource name used to identify the object
82
+     * @return resource stream with the read data
83
+     * @throws \Exception from openstack lib when something goes wrong
84
+     */
85
+    public function readObject($urn) {
86
+        $object = $this->getContainer()->getObject($urn);
87
+
88
+        // we need to keep a reference to objectContent or
89
+        // the stream will be closed before we can do anything with it
90
+        $objectContent = $object->download();
91
+        $objectContent->rewind();
92
+
93
+        $stream = $objectContent->detach();
94
+        // save the object content in the context of the stream to prevent it being gc'd until the stream is closed
95
+        stream_context_set_option($stream, 'swift', 'content', $objectContent);
96
+
97
+        return RetryWrapper::wrap($stream);
98
+    }
99
+
100
+    /**
101
+     * @param string $urn Unified Resource Name
102
+     * @return void
103
+     * @throws \Exception from openstack lib when something goes wrong
104
+     */
105
+    public function deleteObject($urn) {
106
+        $this->getContainer()->getObject($urn)->delete();
107
+    }
108
+
109
+    /**
110
+     * @return void
111
+     * @throws \Exception from openstack lib when something goes wrong
112
+     */
113
+    public function deleteContainer() {
114
+        $this->getContainer()->delete();
115
+    }
116 116
 
117 117
 }
Please login to merge, or discard this patch.
lib/private/Files/ObjectStore/SwiftFactory.php 2 patches
Indentation   +151 added lines, -151 removed lines patch added patch discarded remove patch
@@ -40,155 +40,155 @@
 block discarded – undo
40 40
 use OpenStack\ObjectStore\v1\Models\Container;
41 41
 
42 42
 class SwiftFactory {
43
-	private $cache;
44
-	private $params;
45
-	/** @var Container|null */
46
-	private $container = null;
47
-
48
-	public function __construct(ICache $cache, array $params) {
49
-		$this->cache = $cache;
50
-		$this->params = $params;
51
-	}
52
-
53
-	private function getCachedToken(string $cacheKey) {
54
-		$cachedTokenString = $this->cache->get($cacheKey . '/token');
55
-		if ($cachedTokenString) {
56
-			return json_decode($cachedTokenString);
57
-		} else {
58
-			return null;
59
-		}
60
-	}
61
-
62
-	private function cacheToken(Token $token, string $cacheKey) {
63
-		$this->cache->set($cacheKey . '/token', json_encode($token));
64
-	}
65
-
66
-	/**
67
-	 * @return OpenStack
68
-	 * @throws StorageAuthException
69
-	 */
70
-	private function getClient() {
71
-		if (isset($this->params['bucket'])) {
72
-			$this->params['container'] = $this->params['bucket'];
73
-		}
74
-		if (!isset($this->params['container'])) {
75
-			$this->params['container'] = 'owncloud';
76
-		}
77
-		if (!isset($this->params['autocreate'])) {
78
-			// should only be true for tests
79
-			$this->params['autocreate'] = false;
80
-		}
81
-		if (isset($this->params['user']) && is_array($this->params['user'])) {
82
-			$userName = $this->params['user']['id'];
83
-		} else {
84
-			if (!isset($this->params['username']) && isset($this->params['user'])) {
85
-				$this->params['username'] = $this->params['user'];
86
-			}
87
-			$userName = $this->params['username'];
88
-		}
89
-		if (!isset($this->params['tenantName']) && isset($this->params['tenant'])) {
90
-			$this->params['tenantName'] = $this->params['tenant'];
91
-		}
92
-
93
-		$cacheKey = $userName . '@' . $this->params['url'] . '/' . $this->params['bucket'];
94
-		$token = $this->getCachedToken($cacheKey);
95
-		$hasToken = is_array($token) && (new \DateTimeImmutable($token['expires_at'])) > (new \DateTimeImmutable('now'));
96
-		if ($hasToken) {
97
-			$this->params['cachedToken'] = $token;
98
-		}
99
-
100
-		$httpClient = new Client([
101
-			'base_uri' => TransportUtils::normalizeUrl($this->params['url']),
102
-			'handler' => HandlerStack::create()
103
-		]);
104
-
105
-		if (isset($this->params['user']) && isset($this->params['user']['id'])) {
106
-			return $this->auth(IdentityV3Service::factory($httpClient), $cacheKey);
107
-		} else {
108
-			return $this->auth(IdentityV2Service::factory($httpClient), $cacheKey);
109
-		}
110
-	}
111
-
112
-	/**
113
-	 * @param IdentityV2Service|IdentityV3Service $authService
114
-	 * @param string $cacheKey
115
-	 * @return OpenStack
116
-	 * @throws StorageAuthException
117
-	 */
118
-	private function auth($authService, string $cacheKey) {
119
-		$this->params['identityService'] = $authService;
120
-		$this->params['authUrl'] = $this->params['url'];
121
-		$client = new OpenStack($this->params);
122
-
123
-		if (!isset($this->params['cachedToken'])) {
124
-			try {
125
-				$token = $authService->generateToken($this->params);
126
-				$this->cacheToken($token, $cacheKey);
127
-			} catch (ConnectException $e) {
128
-				throw new StorageAuthException('Failed to connect to keystone, verify the keystone url', $e);
129
-			} catch (ClientException $e) {
130
-				$statusCode = $e->getResponse()->getStatusCode();
131
-				if ($statusCode === 404) {
132
-					throw new StorageAuthException('Keystone not found, verify the keystone url', $e);
133
-				} else if ($statusCode === 412) {
134
-					throw new StorageAuthException('Precondition failed, verify the keystone url', $e);
135
-				} else if ($statusCode === 401) {
136
-					throw new StorageAuthException('Authentication failed, verify the username, password and possibly tenant', $e);
137
-				} else {
138
-					throw new StorageAuthException('Unknown error', $e);
139
-				}
140
-			} catch (RequestException $e) {
141
-				throw new StorageAuthException('Connection reset while connecting to keystone, verify the keystone url', $e);
142
-			}
143
-		}
144
-
145
-		return $client;
146
-	}
147
-
148
-	/**
149
-	 * @return \OpenStack\ObjectStore\v1\Models\Container
150
-	 * @throws StorageAuthException
151
-	 * @throws StorageNotAvailableException
152
-	 */
153
-	public function getContainer() {
154
-		if (is_null($this->container)) {
155
-			$this->container = $this->createContainer();
156
-		}
157
-
158
-		return $this->container;
159
-	}
160
-
161
-	/**
162
-	 * @return \OpenStack\ObjectStore\v1\Models\Container
163
-	 * @throws StorageAuthException
164
-	 * @throws StorageNotAvailableException
165
-	 */
166
-	private function createContainer() {
167
-		$client = $this->getClient();
168
-		$objectStoreService = $client->objectStoreV1();
169
-
170
-		$autoCreate = isset($this->params['autocreate']) && $this->params['autocreate'] === true;
171
-		try {
172
-			$container = $objectStoreService->getContainer($this->params['container']);
173
-			if ($autoCreate) {
174
-				$container->getMetadata();
175
-			}
176
-			return $container;
177
-		} catch (BadResponseError $ex) {
178
-			// if the container does not exist and autocreate is true try to create the container on the fly
179
-			if ($ex->getResponse()->getStatusCode() === 404 && $autoCreate) {
180
-				return $objectStoreService->createContainer([
181
-					'name' => $this->params['container']
182
-				]);
183
-			} else {
184
-				throw new StorageNotAvailableException('Invalid response while trying to get container info', StorageNotAvailableException::STATUS_ERROR, $e);
185
-			}
186
-		} catch (ConnectException $e) {
187
-			/** @var RequestInterface $request */
188
-			$request = $e->getRequest();
189
-			$host = $request->getUri()->getHost() . ':' . $request->getUri()->getPort();
190
-			\OC::$server->getLogger()->error("Can't connect to object storage server at $host");
191
-			throw new StorageNotAvailableException("Can't connect to object storage server at $host", StorageNotAvailableException::STATUS_ERROR, $e);
192
-		}
193
-	}
43
+    private $cache;
44
+    private $params;
45
+    /** @var Container|null */
46
+    private $container = null;
47
+
48
+    public function __construct(ICache $cache, array $params) {
49
+        $this->cache = $cache;
50
+        $this->params = $params;
51
+    }
52
+
53
+    private function getCachedToken(string $cacheKey) {
54
+        $cachedTokenString = $this->cache->get($cacheKey . '/token');
55
+        if ($cachedTokenString) {
56
+            return json_decode($cachedTokenString);
57
+        } else {
58
+            return null;
59
+        }
60
+    }
61
+
62
+    private function cacheToken(Token $token, string $cacheKey) {
63
+        $this->cache->set($cacheKey . '/token', json_encode($token));
64
+    }
65
+
66
+    /**
67
+     * @return OpenStack
68
+     * @throws StorageAuthException
69
+     */
70
+    private function getClient() {
71
+        if (isset($this->params['bucket'])) {
72
+            $this->params['container'] = $this->params['bucket'];
73
+        }
74
+        if (!isset($this->params['container'])) {
75
+            $this->params['container'] = 'owncloud';
76
+        }
77
+        if (!isset($this->params['autocreate'])) {
78
+            // should only be true for tests
79
+            $this->params['autocreate'] = false;
80
+        }
81
+        if (isset($this->params['user']) && is_array($this->params['user'])) {
82
+            $userName = $this->params['user']['id'];
83
+        } else {
84
+            if (!isset($this->params['username']) && isset($this->params['user'])) {
85
+                $this->params['username'] = $this->params['user'];
86
+            }
87
+            $userName = $this->params['username'];
88
+        }
89
+        if (!isset($this->params['tenantName']) && isset($this->params['tenant'])) {
90
+            $this->params['tenantName'] = $this->params['tenant'];
91
+        }
92
+
93
+        $cacheKey = $userName . '@' . $this->params['url'] . '/' . $this->params['bucket'];
94
+        $token = $this->getCachedToken($cacheKey);
95
+        $hasToken = is_array($token) && (new \DateTimeImmutable($token['expires_at'])) > (new \DateTimeImmutable('now'));
96
+        if ($hasToken) {
97
+            $this->params['cachedToken'] = $token;
98
+        }
99
+
100
+        $httpClient = new Client([
101
+            'base_uri' => TransportUtils::normalizeUrl($this->params['url']),
102
+            'handler' => HandlerStack::create()
103
+        ]);
104
+
105
+        if (isset($this->params['user']) && isset($this->params['user']['id'])) {
106
+            return $this->auth(IdentityV3Service::factory($httpClient), $cacheKey);
107
+        } else {
108
+            return $this->auth(IdentityV2Service::factory($httpClient), $cacheKey);
109
+        }
110
+    }
111
+
112
+    /**
113
+     * @param IdentityV2Service|IdentityV3Service $authService
114
+     * @param string $cacheKey
115
+     * @return OpenStack
116
+     * @throws StorageAuthException
117
+     */
118
+    private function auth($authService, string $cacheKey) {
119
+        $this->params['identityService'] = $authService;
120
+        $this->params['authUrl'] = $this->params['url'];
121
+        $client = new OpenStack($this->params);
122
+
123
+        if (!isset($this->params['cachedToken'])) {
124
+            try {
125
+                $token = $authService->generateToken($this->params);
126
+                $this->cacheToken($token, $cacheKey);
127
+            } catch (ConnectException $e) {
128
+                throw new StorageAuthException('Failed to connect to keystone, verify the keystone url', $e);
129
+            } catch (ClientException $e) {
130
+                $statusCode = $e->getResponse()->getStatusCode();
131
+                if ($statusCode === 404) {
132
+                    throw new StorageAuthException('Keystone not found, verify the keystone url', $e);
133
+                } else if ($statusCode === 412) {
134
+                    throw new StorageAuthException('Precondition failed, verify the keystone url', $e);
135
+                } else if ($statusCode === 401) {
136
+                    throw new StorageAuthException('Authentication failed, verify the username, password and possibly tenant', $e);
137
+                } else {
138
+                    throw new StorageAuthException('Unknown error', $e);
139
+                }
140
+            } catch (RequestException $e) {
141
+                throw new StorageAuthException('Connection reset while connecting to keystone, verify the keystone url', $e);
142
+            }
143
+        }
144
+
145
+        return $client;
146
+    }
147
+
148
+    /**
149
+     * @return \OpenStack\ObjectStore\v1\Models\Container
150
+     * @throws StorageAuthException
151
+     * @throws StorageNotAvailableException
152
+     */
153
+    public function getContainer() {
154
+        if (is_null($this->container)) {
155
+            $this->container = $this->createContainer();
156
+        }
157
+
158
+        return $this->container;
159
+    }
160
+
161
+    /**
162
+     * @return \OpenStack\ObjectStore\v1\Models\Container
163
+     * @throws StorageAuthException
164
+     * @throws StorageNotAvailableException
165
+     */
166
+    private function createContainer() {
167
+        $client = $this->getClient();
168
+        $objectStoreService = $client->objectStoreV1();
169
+
170
+        $autoCreate = isset($this->params['autocreate']) && $this->params['autocreate'] === true;
171
+        try {
172
+            $container = $objectStoreService->getContainer($this->params['container']);
173
+            if ($autoCreate) {
174
+                $container->getMetadata();
175
+            }
176
+            return $container;
177
+        } catch (BadResponseError $ex) {
178
+            // if the container does not exist and autocreate is true try to create the container on the fly
179
+            if ($ex->getResponse()->getStatusCode() === 404 && $autoCreate) {
180
+                return $objectStoreService->createContainer([
181
+                    'name' => $this->params['container']
182
+                ]);
183
+            } else {
184
+                throw new StorageNotAvailableException('Invalid response while trying to get container info', StorageNotAvailableException::STATUS_ERROR, $e);
185
+            }
186
+        } catch (ConnectException $e) {
187
+            /** @var RequestInterface $request */
188
+            $request = $e->getRequest();
189
+            $host = $request->getUri()->getHost() . ':' . $request->getUri()->getPort();
190
+            \OC::$server->getLogger()->error("Can't connect to object storage server at $host");
191
+            throw new StorageNotAvailableException("Can't connect to object storage server at $host", StorageNotAvailableException::STATUS_ERROR, $e);
192
+        }
193
+    }
194 194
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -1,5 +1,5 @@  discard block
 block discarded – undo
1 1
 <?php
2
-declare(strict_types=1);
2
+declare(strict_types = 1);
3 3
 /**
4 4
  * @copyright Copyright (c) 2018 Robin Appelman <[email protected]>
5 5
  *
@@ -51,7 +51,7 @@  discard block
 block discarded – undo
51 51
 	}
52 52
 
53 53
 	private function getCachedToken(string $cacheKey) {
54
-		$cachedTokenString = $this->cache->get($cacheKey . '/token');
54
+		$cachedTokenString = $this->cache->get($cacheKey.'/token');
55 55
 		if ($cachedTokenString) {
56 56
 			return json_decode($cachedTokenString);
57 57
 		} else {
@@ -60,7 +60,7 @@  discard block
 block discarded – undo
60 60
 	}
61 61
 
62 62
 	private function cacheToken(Token $token, string $cacheKey) {
63
-		$this->cache->set($cacheKey . '/token', json_encode($token));
63
+		$this->cache->set($cacheKey.'/token', json_encode($token));
64 64
 	}
65 65
 
66 66
 	/**
@@ -90,7 +90,7 @@  discard block
 block discarded – undo
90 90
 			$this->params['tenantName'] = $this->params['tenant'];
91 91
 		}
92 92
 
93
-		$cacheKey = $userName . '@' . $this->params['url'] . '/' . $this->params['bucket'];
93
+		$cacheKey = $userName.'@'.$this->params['url'].'/'.$this->params['bucket'];
94 94
 		$token = $this->getCachedToken($cacheKey);
95 95
 		$hasToken = is_array($token) && (new \DateTimeImmutable($token['expires_at'])) > (new \DateTimeImmutable('now'));
96 96
 		if ($hasToken) {
@@ -186,7 +186,7 @@  discard block
 block discarded – undo
186 186
 		} catch (ConnectException $e) {
187 187
 			/** @var RequestInterface $request */
188 188
 			$request = $e->getRequest();
189
-			$host = $request->getUri()->getHost() . ':' . $request->getUri()->getPort();
189
+			$host = $request->getUri()->getHost().':'.$request->getUri()->getPort();
190 190
 			\OC::$server->getLogger()->error("Can't connect to object storage server at $host");
191 191
 			throw new StorageNotAvailableException("Can't connect to object storage server at $host", StorageNotAvailableException::STATUS_ERROR, $e);
192 192
 		}
Please login to merge, or discard this patch.
apps/files_external/lib/AppInfo/Application.php 1 patch
Indentation   +83 added lines, -83 removed lines patch added patch discarded remove patch
@@ -66,88 +66,88 @@
 block discarded – undo
66 66
  */
67 67
 class Application extends App implements IBackendProvider, IAuthMechanismProvider {
68 68
 
69
-	public function __construct(array $urlParams = array()) {
70
-		parent::__construct('files_external', $urlParams);
71
-
72
-		$container = $this->getContainer();
73
-
74
-		$container->registerService(IUserMountCache::class, function (IAppContainer $c) {
75
-			return $c->getServer()->query('UserMountCache');
76
-		});
77
-
78
-		$backendService = $container->query(BackendService::class);
79
-		$backendService->registerBackendProvider($this);
80
-		$backendService->registerAuthMechanismProvider($this);
81
-
82
-		// force-load auth mechanisms since some will register hooks
83
-		// TODO: obsolete these and use the TokenProvider to get the user's password from the session
84
-		$this->getAuthMechanisms();
85
-
86
-		// app developers: do NOT depend on this! it will disappear with oC 9.0!
87
-		\OC::$server->getEventDispatcher()->dispatch(
88
-			'OCA\\Files_External::loadAdditionalBackends'
89
-		);
90
-	}
91
-
92
-	/**
93
-	 * @{inheritdoc}
94
-	 */
95
-	public function getBackends() {
96
-		$container = $this->getContainer();
97
-
98
-		$backends = [
99
-			$container->query(Local::class),
100
-			$container->query(FTP::class),
101
-			$container->query(DAV::class),
102
-			$container->query(OwnCloud::class),
103
-			$container->query(SFTP::class),
104
-			$container->query(AmazonS3::class),
105
-			$container->query(Swift::class),
106
-			$container->query(SFTP_Key::class),
107
-			$container->query(SMB::class),
108
-			$container->query(SMB_OC::class),
109
-		];
110
-
111
-		return $backends;
112
-	}
113
-
114
-	/**
115
-	 * @{inheritdoc}
116
-	 */
117
-	public function getAuthMechanisms() {
118
-		$container = $this->getContainer();
119
-
120
-		return [
121
-			// AuthMechanism::SCHEME_NULL mechanism
122
-			$container->query(NullMechanism::class),
123
-
124
-			// AuthMechanism::SCHEME_BUILTIN mechanism
125
-			$container->query(Builtin::class),
126
-
127
-			// AuthMechanism::SCHEME_PASSWORD mechanisms
128
-			$container->query(Password::class),
129
-			$container->query(SessionCredentials::class),
130
-			$container->query(LoginCredentials::class),
131
-			$container->query(UserProvided::class),
132
-			$container->query(GlobalAuth::class),
133
-
134
-			// AuthMechanism::SCHEME_OAUTH1 mechanisms
135
-			$container->query(OAuth1::class),
136
-
137
-			// AuthMechanism::SCHEME_OAUTH2 mechanisms
138
-			$container->query(OAuth2::class),
139
-
140
-			// AuthMechanism::SCHEME_PUBLICKEY mechanisms
141
-			$container->query(RSA::class),
142
-
143
-			// AuthMechanism::SCHEME_OPENSTACK mechanisms
144
-			$container->query(OpenStackV2::class),
145
-			$container->query(OpenStackV3::class),
146
-			$container->query(Rackspace::class),
147
-
148
-			// Specialized mechanisms
149
-			$container->query(AccessKey::class),
150
-		];
151
-	}
69
+    public function __construct(array $urlParams = array()) {
70
+        parent::__construct('files_external', $urlParams);
71
+
72
+        $container = $this->getContainer();
73
+
74
+        $container->registerService(IUserMountCache::class, function (IAppContainer $c) {
75
+            return $c->getServer()->query('UserMountCache');
76
+        });
77
+
78
+        $backendService = $container->query(BackendService::class);
79
+        $backendService->registerBackendProvider($this);
80
+        $backendService->registerAuthMechanismProvider($this);
81
+
82
+        // force-load auth mechanisms since some will register hooks
83
+        // TODO: obsolete these and use the TokenProvider to get the user's password from the session
84
+        $this->getAuthMechanisms();
85
+
86
+        // app developers: do NOT depend on this! it will disappear with oC 9.0!
87
+        \OC::$server->getEventDispatcher()->dispatch(
88
+            'OCA\\Files_External::loadAdditionalBackends'
89
+        );
90
+    }
91
+
92
+    /**
93
+     * @{inheritdoc}
94
+     */
95
+    public function getBackends() {
96
+        $container = $this->getContainer();
97
+
98
+        $backends = [
99
+            $container->query(Local::class),
100
+            $container->query(FTP::class),
101
+            $container->query(DAV::class),
102
+            $container->query(OwnCloud::class),
103
+            $container->query(SFTP::class),
104
+            $container->query(AmazonS3::class),
105
+            $container->query(Swift::class),
106
+            $container->query(SFTP_Key::class),
107
+            $container->query(SMB::class),
108
+            $container->query(SMB_OC::class),
109
+        ];
110
+
111
+        return $backends;
112
+    }
113
+
114
+    /**
115
+     * @{inheritdoc}
116
+     */
117
+    public function getAuthMechanisms() {
118
+        $container = $this->getContainer();
119
+
120
+        return [
121
+            // AuthMechanism::SCHEME_NULL mechanism
122
+            $container->query(NullMechanism::class),
123
+
124
+            // AuthMechanism::SCHEME_BUILTIN mechanism
125
+            $container->query(Builtin::class),
126
+
127
+            // AuthMechanism::SCHEME_PASSWORD mechanisms
128
+            $container->query(Password::class),
129
+            $container->query(SessionCredentials::class),
130
+            $container->query(LoginCredentials::class),
131
+            $container->query(UserProvided::class),
132
+            $container->query(GlobalAuth::class),
133
+
134
+            // AuthMechanism::SCHEME_OAUTH1 mechanisms
135
+            $container->query(OAuth1::class),
136
+
137
+            // AuthMechanism::SCHEME_OAUTH2 mechanisms
138
+            $container->query(OAuth2::class),
139
+
140
+            // AuthMechanism::SCHEME_PUBLICKEY mechanisms
141
+            $container->query(RSA::class),
142
+
143
+            // AuthMechanism::SCHEME_OPENSTACK mechanisms
144
+            $container->query(OpenStackV2::class),
145
+            $container->query(OpenStackV3::class),
146
+            $container->query(Rackspace::class),
147
+
148
+            // Specialized mechanisms
149
+            $container->query(AccessKey::class),
150
+        ];
151
+    }
152 152
 
153 153
 }
Please login to merge, or discard this patch.
apps/files_external/lib/Lib/Auth/OpenStack/OpenStackV2.php 1 patch
Indentation   +14 added lines, -14 removed lines patch added patch discarded remove patch
@@ -31,19 +31,19 @@
 block discarded – undo
31 31
  */
32 32
 class OpenStackV2 extends AuthMechanism {
33 33
 
34
-	public function __construct(IL10N $l) {
35
-		$this
36
-			->setIdentifier('openstack::openstack')
37
-			->setScheme(self::SCHEME_OPENSTACK)
38
-			->setText($l->t('OpenStack v2'))
39
-			->addParameters([
40
-				new DefinitionParameter('user', $l->t('Username')),
41
-				(new DefinitionParameter('password', $l->t('Password')))
42
-					->setType(DefinitionParameter::VALUE_PASSWORD),
43
-				new DefinitionParameter('tenant', $l->t('Tenant name')),
44
-				new DefinitionParameter('url', $l->t('Identity endpoint URL')),
45
-			])
46
-		;
47
-	}
34
+    public function __construct(IL10N $l) {
35
+        $this
36
+            ->setIdentifier('openstack::openstack')
37
+            ->setScheme(self::SCHEME_OPENSTACK)
38
+            ->setText($l->t('OpenStack v2'))
39
+            ->addParameters([
40
+                new DefinitionParameter('user', $l->t('Username')),
41
+                (new DefinitionParameter('password', $l->t('Password')))
42
+                    ->setType(DefinitionParameter::VALUE_PASSWORD),
43
+                new DefinitionParameter('tenant', $l->t('Tenant name')),
44
+                new DefinitionParameter('url', $l->t('Identity endpoint URL')),
45
+            ])
46
+        ;
47
+    }
48 48
 
49 49
 }
Please login to merge, or discard this patch.