Completed
Pull Request — master (#8314)
by Robin
16:22
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   +554 added lines, -554 removed lines patch added patch discarded remove patch
@@ -49,562 +49,562 @@
 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']) 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
-		$this->id = 'swift::' . $params['user'] . md5($params['bucket']);
166
-
167
-		$bucketUrl = new Uri($params['bucket']);
168
-		if ($bucketUrl->getHost()) {
169
-			$params['bucket'] = basename($bucketUrl->getPath());
170
-			$params['endpoint_url'] = (string)$bucketUrl->withPath(dirname($bucketUrl->getPath()));
171
-		}
172
-
173
-		if (empty($params['url'])) {
174
-			$params['url'] = 'https://identity.api.rackspacecloud.com/v2.0/';
175
-		}
176
-
177
-		if (empty($params['service_name'])) {
178
-			$params['service_name'] = 'cloudFiles';
179
-		}
180
-
181
-		$params['autocreate'] = true;
182
-
183
-		$this->params = $params;
184
-		// FIXME: private class...
185
-		$this->objectCache = new \OC\Cache\CappedMemoryCache();
186
-		$this->connectionFactory = new SwiftFactory(\OC::$server->getMemCacheFactory()->createDistributed('swift/'), $this->params);
187
-		$this->objectStore = new \OC\Files\ObjectStore\Swift($this->params, $this->connectionFactory);
188
-		$this->bucket = $params['bucket'];
189
-	}
190
-
191
-	public function mkdir($path) {
192
-		$path = $this->normalizePath($path);
193
-
194
-		if ($this->is_dir($path)) {
195
-			return false;
196
-		}
197
-
198
-		if ($path !== '.') {
199
-			$path .= '/';
200
-		}
201
-
202
-		try {
203
-			$this->getContainer()->createObject([
204
-				'name' => $path,
205
-				'content' => '',
206
-				'headers' => ['content-type' => 'httpd/unix-directory']
207
-			]);
208
-			// invalidate so that the next access gets the real object
209
-			// with all properties
210
-			$this->objectCache->remove($path);
211
-		} catch (BadResponseError $e) {
212
-			\OC::$server->getLogger()->logException($e, [
213
-				'level' => \OCP\Util::ERROR,
214
-				'app' => 'files_external',
215
-			]);
216
-			return false;
217
-		}
218
-
219
-		return true;
220
-	}
221
-
222
-	public function file_exists($path) {
223
-		$path = $this->normalizePath($path);
224
-
225
-		if ($path !== '.' && $this->is_dir($path)) {
226
-			$path .= '/';
227
-		}
228
-
229
-		return $this->doesObjectExist($path);
230
-	}
231
-
232
-	public function rmdir($path) {
233
-		$path = $this->normalizePath($path);
234
-
235
-		if (!$this->is_dir($path) || !$this->isDeletable($path)) {
236
-			return false;
237
-		}
238
-
239
-		$dh = $this->opendir($path);
240
-		while ($file = readdir($dh)) {
241
-			if (\OC\Files\Filesystem::isIgnoredDir($file)) {
242
-				continue;
243
-			}
244
-
245
-			if ($this->is_dir($path . '/' . $file)) {
246
-				$this->rmdir($path . '/' . $file);
247
-			} else {
248
-				$this->unlink($path . '/' . $file);
249
-			}
250
-		}
251
-
252
-		try {
253
-			$this->objectStore->deleteObject($path . '/');
254
-			$this->objectCache->remove($path . '/');
255
-		} catch (BadResponseError $e) {
256
-			\OC::$server->getLogger()->logException($e, [
257
-				'level' => \OCP\Util::ERROR,
258
-				'app' => 'files_external',
259
-			]);
260
-			return false;
261
-		}
262
-
263
-		return true;
264
-	}
265
-
266
-	public function opendir($path) {
267
-		$path = $this->normalizePath($path);
268
-
269
-		if ($path === '.') {
270
-			$path = '';
271
-		} else {
272
-			$path .= '/';
273
-		}
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']) 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
+        $this->id = 'swift::' . $params['user'] . md5($params['bucket']);
166
+
167
+        $bucketUrl = new Uri($params['bucket']);
168
+        if ($bucketUrl->getHost()) {
169
+            $params['bucket'] = basename($bucketUrl->getPath());
170
+            $params['endpoint_url'] = (string)$bucketUrl->withPath(dirname($bucketUrl->getPath()));
171
+        }
172
+
173
+        if (empty($params['url'])) {
174
+            $params['url'] = 'https://identity.api.rackspacecloud.com/v2.0/';
175
+        }
176
+
177
+        if (empty($params['service_name'])) {
178
+            $params['service_name'] = 'cloudFiles';
179
+        }
180
+
181
+        $params['autocreate'] = true;
182
+
183
+        $this->params = $params;
184
+        // FIXME: private class...
185
+        $this->objectCache = new \OC\Cache\CappedMemoryCache();
186
+        $this->connectionFactory = new SwiftFactory(\OC::$server->getMemCacheFactory()->createDistributed('swift/'), $this->params);
187
+        $this->objectStore = new \OC\Files\ObjectStore\Swift($this->params, $this->connectionFactory);
188
+        $this->bucket = $params['bucket'];
189
+    }
190
+
191
+    public function mkdir($path) {
192
+        $path = $this->normalizePath($path);
193
+
194
+        if ($this->is_dir($path)) {
195
+            return false;
196
+        }
197
+
198
+        if ($path !== '.') {
199
+            $path .= '/';
200
+        }
201
+
202
+        try {
203
+            $this->getContainer()->createObject([
204
+                'name' => $path,
205
+                'content' => '',
206
+                'headers' => ['content-type' => 'httpd/unix-directory']
207
+            ]);
208
+            // invalidate so that the next access gets the real object
209
+            // with all properties
210
+            $this->objectCache->remove($path);
211
+        } catch (BadResponseError $e) {
212
+            \OC::$server->getLogger()->logException($e, [
213
+                'level' => \OCP\Util::ERROR,
214
+                'app' => 'files_external',
215
+            ]);
216
+            return false;
217
+        }
218
+
219
+        return true;
220
+    }
221
+
222
+    public function file_exists($path) {
223
+        $path = $this->normalizePath($path);
224
+
225
+        if ($path !== '.' && $this->is_dir($path)) {
226
+            $path .= '/';
227
+        }
228
+
229
+        return $this->doesObjectExist($path);
230
+    }
231
+
232
+    public function rmdir($path) {
233
+        $path = $this->normalizePath($path);
234
+
235
+        if (!$this->is_dir($path) || !$this->isDeletable($path)) {
236
+            return false;
237
+        }
238
+
239
+        $dh = $this->opendir($path);
240
+        while ($file = readdir($dh)) {
241
+            if (\OC\Files\Filesystem::isIgnoredDir($file)) {
242
+                continue;
243
+            }
244
+
245
+            if ($this->is_dir($path . '/' . $file)) {
246
+                $this->rmdir($path . '/' . $file);
247
+            } else {
248
+                $this->unlink($path . '/' . $file);
249
+            }
250
+        }
251
+
252
+        try {
253
+            $this->objectStore->deleteObject($path . '/');
254
+            $this->objectCache->remove($path . '/');
255
+        } catch (BadResponseError $e) {
256
+            \OC::$server->getLogger()->logException($e, [
257
+                'level' => \OCP\Util::ERROR,
258
+                'app' => 'files_external',
259
+            ]);
260
+            return false;
261
+        }
262
+
263
+        return true;
264
+    }
265
+
266
+    public function opendir($path) {
267
+        $path = $this->normalizePath($path);
268
+
269
+        if ($path === '.') {
270
+            $path = '';
271
+        } else {
272
+            $path .= '/';
273
+        }
274 274
 
275 275
 //		$path = str_replace('%23', '#', $path); // the prefix is sent as a query param, so revert the encoding of #
276 276
 
277
-		try {
278
-			$files = [];
279
-			$objects = $this->getContainer()->listObjects([
280
-				'prefix' => $path,
281
-				'delimiter' => '/'
282
-			]);
283
-
284
-			/** @var StorageObject $object */
285
-			foreach ($objects as $object) {
286
-				$file = basename($object->name);
287
-				if ($file !== basename($path) && $file !== '.') {
288
-					$files[] = $file;
289
-				}
290
-			}
291
-
292
-			return IteratorDirectory::wrap($files);
293
-		} catch (\Exception $e) {
294
-			\OC::$server->getLogger()->logException($e, [
295
-				'level' => \OCP\Util::ERROR,
296
-				'app' => 'files_external',
297
-			]);
298
-			return false;
299
-		}
300
-
301
-	}
302
-
303
-	public function stat($path) {
304
-		$path = $this->normalizePath($path);
305
-
306
-		if ($path === '.') {
307
-			$path = '';
308
-		} else if ($this->is_dir($path)) {
309
-			$path .= '/';
310
-		}
311
-
312
-		try {
313
-			$object = $this->fetchObject($path);
314
-			if (!$object) {
315
-				return false;
316
-			}
317
-		} catch (BadResponseError $e) {
318
-			\OC::$server->getLogger()->logException($e, [
319
-				'level' => \OCP\Util::ERROR,
320
-				'app' => 'files_external',
321
-			]);
322
-			return false;
323
-		}
324
-
325
-		$dateTime = $object->lastModified ? \DateTime::createFromFormat(\DateTime::RFC1123, $object->lastModified) : false;
326
-		$mtime = $dateTime ? $dateTime->getTimestamp() : null;
327
-		$objectMetadata = $object->getMetadata();
328
-		if (isset($objectMetadata['timestamp'])) {
329
-			$mtime = $objectMetadata['timestamp'];
330
-		}
331
-
332
-		if (!empty($mtime)) {
333
-			$mtime = floor($mtime);
334
-		}
335
-
336
-		$stat = array();
337
-		$stat['size'] = (int)$object->contentLength;
338
-		$stat['mtime'] = $mtime;
339
-		$stat['atime'] = time();
340
-		return $stat;
341
-	}
342
-
343
-	public function filetype($path) {
344
-		$path = $this->normalizePath($path);
345
-
346
-		if ($path !== '.' && $this->doesObjectExist($path)) {
347
-			return 'file';
348
-		}
349
-
350
-		if ($path !== '.') {
351
-			$path .= '/';
352
-		}
353
-
354
-		if ($this->doesObjectExist($path)) {
355
-			return 'dir';
356
-		}
357
-	}
358
-
359
-	public function unlink($path) {
360
-		$path = $this->normalizePath($path);
361
-
362
-		if ($this->is_dir($path)) {
363
-			return $this->rmdir($path);
364
-		}
365
-
366
-		try {
367
-			$this->objectStore->deleteObject($path);
368
-			$this->objectCache->remove($path);
369
-			$this->objectCache->remove($path . '/');
370
-		} catch (BadResponseError $e) {
371
-			if ($e->getResponse()->getStatusCode() !== 404) {
372
-				\OC::$server->getLogger()->logException($e, [
373
-					'level' => \OCP\Util::ERROR,
374
-					'app' => 'files_external',
375
-				]);
376
-				throw $e;
377
-			}
378
-		}
379
-
380
-		return true;
381
-	}
382
-
383
-	public function fopen($path, $mode) {
384
-		$path = $this->normalizePath($path);
385
-
386
-		switch ($mode) {
387
-			case 'a':
388
-			case 'ab':
389
-			case 'a+':
390
-				return false;
391
-			case 'r':
392
-			case 'rb':
393
-				try {
394
-					return $this->objectStore->readObject($path);
395
-				} catch (BadResponseError $e) {
396
-					\OC::$server->getLogger()->logException($e, [
397
-						'level' => \OCP\Util::ERROR,
398
-						'app' => 'files_external',
399
-					]);
400
-					return false;
401
-				}
402
-			case 'w':
403
-			case 'wb':
404
-			case 'r+':
405
-			case 'w+':
406
-			case 'wb+':
407
-			case 'x':
408
-			case 'x+':
409
-			case 'c':
410
-			case 'c+':
411
-				if (strrpos($path, '.') !== false) {
412
-					$ext = substr($path, strrpos($path, '.'));
413
-				} else {
414
-					$ext = '';
415
-				}
416
-				$tmpFile = \OCP\Files::tmpFile($ext);
417
-				// Fetch existing file if required
418
-				if ($mode[0] !== 'w' && $this->file_exists($path)) {
419
-					if ($mode[0] === 'x') {
420
-						// File cannot already exist
421
-						return false;
422
-					}
423
-					$source = $this->fopen($path, 'r');
424
-					file_put_contents($tmpFile, $source);
425
-				}
426
-				$handle = fopen($tmpFile, $mode);
427
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
428
-					$this->writeBack($tmpFile, $path);
429
-				});
430
-		}
431
-	}
432
-
433
-	public function touch($path, $mtime = null) {
434
-		$path = $this->normalizePath($path);
435
-		if (is_null($mtime)) {
436
-			$mtime = time();
437
-		}
438
-		$metadata = ['timestamp' => $mtime];
439
-		if ($this->file_exists($path)) {
440
-			if ($this->is_dir($path) && $path !== '.') {
441
-				$path .= '/';
442
-			}
443
-
444
-			$object = $this->fetchObject($path);
445
-			if ($object->mergeMetadata($metadata)) {
446
-				// invalidate target object to force repopulation on fetch
447
-				$this->objectCache->remove($path);
448
-			}
449
-			return true;
450
-		} else {
451
-			$mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
452
-			$this->getContainer()->createObject([
453
-				'name' => $path,
454
-				'content' => '',
455
-				'headers' => ['content-type' => 'httpd/unix-directory']
456
-			]);
457
-			// invalidate target object to force repopulation on fetch
458
-			$this->objectCache->remove($path);
459
-			return true;
460
-		}
461
-	}
462
-
463
-	public function copy($path1, $path2) {
464
-		$path1 = $this->normalizePath($path1);
465
-		$path2 = $this->normalizePath($path2);
466
-
467
-		$fileType = $this->filetype($path1);
468
-		if ($fileType) {
469
-			// make way
470
-			$this->unlink($path2);
471
-		}
472
-
473
-		if ($fileType === 'file') {
474
-			try {
475
-				$source = $this->fetchObject($path1);
476
-				$source->copy([
477
-					'destination' => $this->bucket . '/' . $path2
478
-				]);
479
-				// invalidate target object to force repopulation on fetch
480
-				$this->objectCache->remove($path2);
481
-				$this->objectCache->remove($path2 . '/');
482
-			} catch (BadResponseError $e) {
483
-				\OC::$server->getLogger()->logException($e, [
484
-					'level' => \OCP\Util::ERROR,
485
-					'app' => 'files_external',
486
-				]);
487
-				return false;
488
-			}
489
-
490
-		} else if ($fileType === 'dir') {
491
-			try {
492
-				$source = $this->fetchObject($path1 . '/');
493
-				$source->copy([
494
-					'destination' => $this->bucket . '/' . $path2 . '/'
495
-				]);
496
-				// invalidate target object to force repopulation on fetch
497
-				$this->objectCache->remove($path2);
498
-				$this->objectCache->remove($path2 . '/');
499
-			} catch (BadResponseError $e) {
500
-				\OC::$server->getLogger()->logException($e, [
501
-					'level' => \OCP\Util::ERROR,
502
-					'app' => 'files_external',
503
-				]);
504
-				return false;
505
-			}
506
-
507
-			$dh = $this->opendir($path1);
508
-			while ($file = readdir($dh)) {
509
-				if (\OC\Files\Filesystem::isIgnoredDir($file)) {
510
-					continue;
511
-				}
512
-
513
-				$source = $path1 . '/' . $file;
514
-				$target = $path2 . '/' . $file;
515
-				$this->copy($source, $target);
516
-			}
517
-
518
-		} else {
519
-			//file does not exist
520
-			return false;
521
-		}
522
-
523
-		return true;
524
-	}
525
-
526
-	public function rename($path1, $path2) {
527
-		$path1 = $this->normalizePath($path1);
528
-		$path2 = $this->normalizePath($path2);
529
-
530
-		$fileType = $this->filetype($path1);
531
-
532
-		if ($fileType === 'dir' || $fileType === 'file') {
533
-			// copy
534
-			if ($this->copy($path1, $path2) === false) {
535
-				return false;
536
-			}
537
-
538
-			// cleanup
539
-			if ($this->unlink($path1) === false) {
540
-				throw new \Exception('failed to remove original');
541
-				$this->unlink($path2);
542
-				return false;
543
-			}
544
-
545
-			return true;
546
-		}
547
-
548
-		return false;
549
-	}
550
-
551
-	public function getId() {
552
-		return $this->id;
553
-	}
554
-
555
-	/**
556
-	 * Returns the initialized object store container.
557
-	 *
558
-	 * @return \OpenStack\ObjectStore\v1\Models\Container
559
-	 * @throws \OCP\Files\StorageAuthException
560
-	 * @throws \OCP\Files\StorageNotAvailableException
561
-	 */
562
-	public function getContainer() {
563
-		if (is_null($this->container)) {
564
-			$this->container = $this->connectionFactory->getContainer();
565
-
566
-			if (!$this->file_exists('.')) {
567
-				$this->mkdir('.');
568
-			}
569
-		}
570
-		return $this->container;
571
-	}
572
-
573
-	public function writeBack($tmpFile, $path) {
574
-		$fileData = fopen($tmpFile, 'r');
575
-		$this->objectStore->writeObject($path, $fileData);
576
-		// invalidate target object to force repopulation on fetch
577
-		$this->objectCache->remove($path);
578
-		unlink($tmpFile);
579
-	}
580
-
581
-	public function hasUpdated($path, $time) {
582
-		if ($this->is_file($path)) {
583
-			return parent::hasUpdated($path, $time);
584
-		}
585
-		$path = $this->normalizePath($path);
586
-		$dh = $this->opendir($path);
587
-		$content = array();
588
-		while (($file = readdir($dh)) !== false) {
589
-			$content[] = $file;
590
-		}
591
-		if ($path === '.') {
592
-			$path = '';
593
-		}
594
-		$cachedContent = $this->getCache()->getFolderContents($path);
595
-		$cachedNames = array_map(function ($content) {
596
-			return $content['name'];
597
-		}, $cachedContent);
598
-		sort($cachedNames);
599
-		sort($content);
600
-		return $cachedNames !== $content;
601
-	}
602
-
603
-	/**
604
-	 * check if curl is installed
605
-	 */
606
-	public static function checkDependencies() {
607
-		return true;
608
-	}
277
+        try {
278
+            $files = [];
279
+            $objects = $this->getContainer()->listObjects([
280
+                'prefix' => $path,
281
+                'delimiter' => '/'
282
+            ]);
283
+
284
+            /** @var StorageObject $object */
285
+            foreach ($objects as $object) {
286
+                $file = basename($object->name);
287
+                if ($file !== basename($path) && $file !== '.') {
288
+                    $files[] = $file;
289
+                }
290
+            }
291
+
292
+            return IteratorDirectory::wrap($files);
293
+        } catch (\Exception $e) {
294
+            \OC::$server->getLogger()->logException($e, [
295
+                'level' => \OCP\Util::ERROR,
296
+                'app' => 'files_external',
297
+            ]);
298
+            return false;
299
+        }
300
+
301
+    }
302
+
303
+    public function stat($path) {
304
+        $path = $this->normalizePath($path);
305
+
306
+        if ($path === '.') {
307
+            $path = '';
308
+        } else if ($this->is_dir($path)) {
309
+            $path .= '/';
310
+        }
311
+
312
+        try {
313
+            $object = $this->fetchObject($path);
314
+            if (!$object) {
315
+                return false;
316
+            }
317
+        } catch (BadResponseError $e) {
318
+            \OC::$server->getLogger()->logException($e, [
319
+                'level' => \OCP\Util::ERROR,
320
+                'app' => 'files_external',
321
+            ]);
322
+            return false;
323
+        }
324
+
325
+        $dateTime = $object->lastModified ? \DateTime::createFromFormat(\DateTime::RFC1123, $object->lastModified) : false;
326
+        $mtime = $dateTime ? $dateTime->getTimestamp() : null;
327
+        $objectMetadata = $object->getMetadata();
328
+        if (isset($objectMetadata['timestamp'])) {
329
+            $mtime = $objectMetadata['timestamp'];
330
+        }
331
+
332
+        if (!empty($mtime)) {
333
+            $mtime = floor($mtime);
334
+        }
335
+
336
+        $stat = array();
337
+        $stat['size'] = (int)$object->contentLength;
338
+        $stat['mtime'] = $mtime;
339
+        $stat['atime'] = time();
340
+        return $stat;
341
+    }
342
+
343
+    public function filetype($path) {
344
+        $path = $this->normalizePath($path);
345
+
346
+        if ($path !== '.' && $this->doesObjectExist($path)) {
347
+            return 'file';
348
+        }
349
+
350
+        if ($path !== '.') {
351
+            $path .= '/';
352
+        }
353
+
354
+        if ($this->doesObjectExist($path)) {
355
+            return 'dir';
356
+        }
357
+    }
358
+
359
+    public function unlink($path) {
360
+        $path = $this->normalizePath($path);
361
+
362
+        if ($this->is_dir($path)) {
363
+            return $this->rmdir($path);
364
+        }
365
+
366
+        try {
367
+            $this->objectStore->deleteObject($path);
368
+            $this->objectCache->remove($path);
369
+            $this->objectCache->remove($path . '/');
370
+        } catch (BadResponseError $e) {
371
+            if ($e->getResponse()->getStatusCode() !== 404) {
372
+                \OC::$server->getLogger()->logException($e, [
373
+                    'level' => \OCP\Util::ERROR,
374
+                    'app' => 'files_external',
375
+                ]);
376
+                throw $e;
377
+            }
378
+        }
379
+
380
+        return true;
381
+    }
382
+
383
+    public function fopen($path, $mode) {
384
+        $path = $this->normalizePath($path);
385
+
386
+        switch ($mode) {
387
+            case 'a':
388
+            case 'ab':
389
+            case 'a+':
390
+                return false;
391
+            case 'r':
392
+            case 'rb':
393
+                try {
394
+                    return $this->objectStore->readObject($path);
395
+                } catch (BadResponseError $e) {
396
+                    \OC::$server->getLogger()->logException($e, [
397
+                        'level' => \OCP\Util::ERROR,
398
+                        'app' => 'files_external',
399
+                    ]);
400
+                    return false;
401
+                }
402
+            case 'w':
403
+            case 'wb':
404
+            case 'r+':
405
+            case 'w+':
406
+            case 'wb+':
407
+            case 'x':
408
+            case 'x+':
409
+            case 'c':
410
+            case 'c+':
411
+                if (strrpos($path, '.') !== false) {
412
+                    $ext = substr($path, strrpos($path, '.'));
413
+                } else {
414
+                    $ext = '';
415
+                }
416
+                $tmpFile = \OCP\Files::tmpFile($ext);
417
+                // Fetch existing file if required
418
+                if ($mode[0] !== 'w' && $this->file_exists($path)) {
419
+                    if ($mode[0] === 'x') {
420
+                        // File cannot already exist
421
+                        return false;
422
+                    }
423
+                    $source = $this->fopen($path, 'r');
424
+                    file_put_contents($tmpFile, $source);
425
+                }
426
+                $handle = fopen($tmpFile, $mode);
427
+                return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
428
+                    $this->writeBack($tmpFile, $path);
429
+                });
430
+        }
431
+    }
432
+
433
+    public function touch($path, $mtime = null) {
434
+        $path = $this->normalizePath($path);
435
+        if (is_null($mtime)) {
436
+            $mtime = time();
437
+        }
438
+        $metadata = ['timestamp' => $mtime];
439
+        if ($this->file_exists($path)) {
440
+            if ($this->is_dir($path) && $path !== '.') {
441
+                $path .= '/';
442
+            }
443
+
444
+            $object = $this->fetchObject($path);
445
+            if ($object->mergeMetadata($metadata)) {
446
+                // invalidate target object to force repopulation on fetch
447
+                $this->objectCache->remove($path);
448
+            }
449
+            return true;
450
+        } else {
451
+            $mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
452
+            $this->getContainer()->createObject([
453
+                'name' => $path,
454
+                'content' => '',
455
+                'headers' => ['content-type' => 'httpd/unix-directory']
456
+            ]);
457
+            // invalidate target object to force repopulation on fetch
458
+            $this->objectCache->remove($path);
459
+            return true;
460
+        }
461
+    }
462
+
463
+    public function copy($path1, $path2) {
464
+        $path1 = $this->normalizePath($path1);
465
+        $path2 = $this->normalizePath($path2);
466
+
467
+        $fileType = $this->filetype($path1);
468
+        if ($fileType) {
469
+            // make way
470
+            $this->unlink($path2);
471
+        }
472
+
473
+        if ($fileType === 'file') {
474
+            try {
475
+                $source = $this->fetchObject($path1);
476
+                $source->copy([
477
+                    'destination' => $this->bucket . '/' . $path2
478
+                ]);
479
+                // invalidate target object to force repopulation on fetch
480
+                $this->objectCache->remove($path2);
481
+                $this->objectCache->remove($path2 . '/');
482
+            } catch (BadResponseError $e) {
483
+                \OC::$server->getLogger()->logException($e, [
484
+                    'level' => \OCP\Util::ERROR,
485
+                    'app' => 'files_external',
486
+                ]);
487
+                return false;
488
+            }
489
+
490
+        } else if ($fileType === 'dir') {
491
+            try {
492
+                $source = $this->fetchObject($path1 . '/');
493
+                $source->copy([
494
+                    'destination' => $this->bucket . '/' . $path2 . '/'
495
+                ]);
496
+                // invalidate target object to force repopulation on fetch
497
+                $this->objectCache->remove($path2);
498
+                $this->objectCache->remove($path2 . '/');
499
+            } catch (BadResponseError $e) {
500
+                \OC::$server->getLogger()->logException($e, [
501
+                    'level' => \OCP\Util::ERROR,
502
+                    'app' => 'files_external',
503
+                ]);
504
+                return false;
505
+            }
506
+
507
+            $dh = $this->opendir($path1);
508
+            while ($file = readdir($dh)) {
509
+                if (\OC\Files\Filesystem::isIgnoredDir($file)) {
510
+                    continue;
511
+                }
512
+
513
+                $source = $path1 . '/' . $file;
514
+                $target = $path2 . '/' . $file;
515
+                $this->copy($source, $target);
516
+            }
517
+
518
+        } else {
519
+            //file does not exist
520
+            return false;
521
+        }
522
+
523
+        return true;
524
+    }
525
+
526
+    public function rename($path1, $path2) {
527
+        $path1 = $this->normalizePath($path1);
528
+        $path2 = $this->normalizePath($path2);
529
+
530
+        $fileType = $this->filetype($path1);
531
+
532
+        if ($fileType === 'dir' || $fileType === 'file') {
533
+            // copy
534
+            if ($this->copy($path1, $path2) === false) {
535
+                return false;
536
+            }
537
+
538
+            // cleanup
539
+            if ($this->unlink($path1) === false) {
540
+                throw new \Exception('failed to remove original');
541
+                $this->unlink($path2);
542
+                return false;
543
+            }
544
+
545
+            return true;
546
+        }
547
+
548
+        return false;
549
+    }
550
+
551
+    public function getId() {
552
+        return $this->id;
553
+    }
554
+
555
+    /**
556
+     * Returns the initialized object store container.
557
+     *
558
+     * @return \OpenStack\ObjectStore\v1\Models\Container
559
+     * @throws \OCP\Files\StorageAuthException
560
+     * @throws \OCP\Files\StorageNotAvailableException
561
+     */
562
+    public function getContainer() {
563
+        if (is_null($this->container)) {
564
+            $this->container = $this->connectionFactory->getContainer();
565
+
566
+            if (!$this->file_exists('.')) {
567
+                $this->mkdir('.');
568
+            }
569
+        }
570
+        return $this->container;
571
+    }
572
+
573
+    public function writeBack($tmpFile, $path) {
574
+        $fileData = fopen($tmpFile, 'r');
575
+        $this->objectStore->writeObject($path, $fileData);
576
+        // invalidate target object to force repopulation on fetch
577
+        $this->objectCache->remove($path);
578
+        unlink($tmpFile);
579
+    }
580
+
581
+    public function hasUpdated($path, $time) {
582
+        if ($this->is_file($path)) {
583
+            return parent::hasUpdated($path, $time);
584
+        }
585
+        $path = $this->normalizePath($path);
586
+        $dh = $this->opendir($path);
587
+        $content = array();
588
+        while (($file = readdir($dh)) !== false) {
589
+            $content[] = $file;
590
+        }
591
+        if ($path === '.') {
592
+            $path = '';
593
+        }
594
+        $cachedContent = $this->getCache()->getFolderContents($path);
595
+        $cachedNames = array_map(function ($content) {
596
+            return $content['name'];
597
+        }, $cachedContent);
598
+        sort($cachedNames);
599
+        sort($content);
600
+        return $cachedNames !== $content;
601
+    }
602
+
603
+    /**
604
+     * check if curl is installed
605
+     */
606
+    public static function checkDependencies() {
607
+        return true;
608
+    }
609 609
 
610 610
 }
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
  *
@@ -162,12 +162,12 @@  discard block
 block discarded – undo
162 162
 			throw new StorageBadConfigException("API Key or password, Username, Bucket and Region have to be configured.");
163 163
 		}
164 164
 
165
-		$this->id = 'swift::' . $params['user'] . md5($params['bucket']);
165
+		$this->id = 'swift::'.$params['user'].md5($params['bucket']);
166 166
 
167 167
 		$bucketUrl = new Uri($params['bucket']);
168 168
 		if ($bucketUrl->getHost()) {
169 169
 			$params['bucket'] = basename($bucketUrl->getPath());
170
-			$params['endpoint_url'] = (string)$bucketUrl->withPath(dirname($bucketUrl->getPath()));
170
+			$params['endpoint_url'] = (string) $bucketUrl->withPath(dirname($bucketUrl->getPath()));
171 171
 		}
172 172
 
173 173
 		if (empty($params['url'])) {
@@ -242,16 +242,16 @@  discard block
 block discarded – undo
242 242
 				continue;
243 243
 			}
244 244
 
245
-			if ($this->is_dir($path . '/' . $file)) {
246
-				$this->rmdir($path . '/' . $file);
245
+			if ($this->is_dir($path.'/'.$file)) {
246
+				$this->rmdir($path.'/'.$file);
247 247
 			} else {
248
-				$this->unlink($path . '/' . $file);
248
+				$this->unlink($path.'/'.$file);
249 249
 			}
250 250
 		}
251 251
 
252 252
 		try {
253
-			$this->objectStore->deleteObject($path . '/');
254
-			$this->objectCache->remove($path . '/');
253
+			$this->objectStore->deleteObject($path.'/');
254
+			$this->objectCache->remove($path.'/');
255 255
 		} catch (BadResponseError $e) {
256 256
 			\OC::$server->getLogger()->logException($e, [
257 257
 				'level' => \OCP\Util::ERROR,
@@ -334,7 +334,7 @@  discard block
 block discarded – undo
334 334
 		}
335 335
 
336 336
 		$stat = array();
337
-		$stat['size'] = (int)$object->contentLength;
337
+		$stat['size'] = (int) $object->contentLength;
338 338
 		$stat['mtime'] = $mtime;
339 339
 		$stat['atime'] = time();
340 340
 		return $stat;
@@ -366,7 +366,7 @@  discard block
 block discarded – undo
366 366
 		try {
367 367
 			$this->objectStore->deleteObject($path);
368 368
 			$this->objectCache->remove($path);
369
-			$this->objectCache->remove($path . '/');
369
+			$this->objectCache->remove($path.'/');
370 370
 		} catch (BadResponseError $e) {
371 371
 			if ($e->getResponse()->getStatusCode() !== 404) {
372 372
 				\OC::$server->getLogger()->logException($e, [
@@ -424,7 +424,7 @@  discard block
 block discarded – undo
424 424
 					file_put_contents($tmpFile, $source);
425 425
 				}
426 426
 				$handle = fopen($tmpFile, $mode);
427
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
427
+				return CallbackWrapper::wrap($handle, null, null, function() use ($path, $tmpFile) {
428 428
 					$this->writeBack($tmpFile, $path);
429 429
 				});
430 430
 		}
@@ -474,11 +474,11 @@  discard block
 block discarded – undo
474 474
 			try {
475 475
 				$source = $this->fetchObject($path1);
476 476
 				$source->copy([
477
-					'destination' => $this->bucket . '/' . $path2
477
+					'destination' => $this->bucket.'/'.$path2
478 478
 				]);
479 479
 				// invalidate target object to force repopulation on fetch
480 480
 				$this->objectCache->remove($path2);
481
-				$this->objectCache->remove($path2 . '/');
481
+				$this->objectCache->remove($path2.'/');
482 482
 			} catch (BadResponseError $e) {
483 483
 				\OC::$server->getLogger()->logException($e, [
484 484
 					'level' => \OCP\Util::ERROR,
@@ -489,13 +489,13 @@  discard block
 block discarded – undo
489 489
 
490 490
 		} else if ($fileType === 'dir') {
491 491
 			try {
492
-				$source = $this->fetchObject($path1 . '/');
492
+				$source = $this->fetchObject($path1.'/');
493 493
 				$source->copy([
494
-					'destination' => $this->bucket . '/' . $path2 . '/'
494
+					'destination' => $this->bucket.'/'.$path2.'/'
495 495
 				]);
496 496
 				// invalidate target object to force repopulation on fetch
497 497
 				$this->objectCache->remove($path2);
498
-				$this->objectCache->remove($path2 . '/');
498
+				$this->objectCache->remove($path2.'/');
499 499
 			} catch (BadResponseError $e) {
500 500
 				\OC::$server->getLogger()->logException($e, [
501 501
 					'level' => \OCP\Util::ERROR,
@@ -510,8 +510,8 @@  discard block
 block discarded – undo
510 510
 					continue;
511 511
 				}
512 512
 
513
-				$source = $path1 . '/' . $file;
514
-				$target = $path2 . '/' . $file;
513
+				$source = $path1.'/'.$file;
514
+				$target = $path2.'/'.$file;
515 515
 				$this->copy($source, $target);
516 516
 			}
517 517
 
@@ -592,7 +592,7 @@  discard block
 block discarded – undo
592 592
 			$path = '';
593 593
 		}
594 594
 		$cachedContent = $this->getCache()->getFolderContents($path);
595
-		$cachedNames = array_map(function ($content) {
595
+		$cachedNames = array_map(function($content) {
596 596
 			return $content['name'];
597 597
 		}, $cachedContent);
598 598
 		sort($cachedNames);
Please login to merge, or discard this patch.
lib/private/Files/ObjectStore/SwiftFactory.php 2 patches
Indentation   +120 added lines, -120 removed lines patch added patch discarded remove patch
@@ -39,136 +39,136 @@
 block discarded – undo
39 39
 use OpenStack\ObjectStore\v1\Models\Container;
40 40
 
41 41
 class SwiftFactory {
42
-	private $cache;
43
-	private $params;
44
-	/** @var Container|null */
45
-	private $container = null;
42
+    private $cache;
43
+    private $params;
44
+    /** @var Container|null */
45
+    private $container = null;
46 46
 
47
-	public function __construct(ICache $cache, array $params) {
48
-		$this->cache = $cache;
49
-		$this->params = $params;
50
-	}
47
+    public function __construct(ICache $cache, array $params) {
48
+        $this->cache = $cache;
49
+        $this->params = $params;
50
+    }
51 51
 
52
-	private function getCachedToken(string $cacheKey) {
53
-		$cachedTokenString = $this->cache->get($cacheKey . '/token');
54
-		if ($cachedTokenString) {
55
-			return json_decode($cachedTokenString);
56
-		} else {
57
-			return null;
58
-		}
59
-	}
52
+    private function getCachedToken(string $cacheKey) {
53
+        $cachedTokenString = $this->cache->get($cacheKey . '/token');
54
+        if ($cachedTokenString) {
55
+            return json_decode($cachedTokenString);
56
+        } else {
57
+            return null;
58
+        }
59
+    }
60 60
 
61
-	private function cacheToken(Token $token, string $cacheKey) {
62
-		$this->cache->set($cacheKey . '/token', json_encode($token));
63
-	}
61
+    private function cacheToken(Token $token, string $cacheKey) {
62
+        $this->cache->set($cacheKey . '/token', json_encode($token));
63
+    }
64 64
 
65
-	/**
66
-	 * @return OpenStack
67
-	 * @throws StorageAuthException
68
-	 */
69
-	private function getClient() {
70
-		if (isset($this->params['bucket'])) {
71
-			$this->params['container'] = $this->params['bucket'];
72
-		}
73
-		if (!isset($this->params['container'])) {
74
-			$this->params['container'] = 'owncloud';
75
-		}
76
-		if (!isset($this->params['autocreate'])) {
77
-			// should only be true for tests
78
-			$this->params['autocreate'] = false;
79
-		}
80
-		if (!isset($this->params['username']) && isset($this->params['user'])) {
81
-			$this->params['username'] = $this->params['user'];
82
-		}
83
-		if (!isset($this->params['tenantName']) && isset($this->params['tenant'])) {
84
-			$this->params['tenantName'] = $this->params['tenant'];
85
-		}
65
+    /**
66
+     * @return OpenStack
67
+     * @throws StorageAuthException
68
+     */
69
+    private function getClient() {
70
+        if (isset($this->params['bucket'])) {
71
+            $this->params['container'] = $this->params['bucket'];
72
+        }
73
+        if (!isset($this->params['container'])) {
74
+            $this->params['container'] = 'owncloud';
75
+        }
76
+        if (!isset($this->params['autocreate'])) {
77
+            // should only be true for tests
78
+            $this->params['autocreate'] = false;
79
+        }
80
+        if (!isset($this->params['username']) && isset($this->params['user'])) {
81
+            $this->params['username'] = $this->params['user'];
82
+        }
83
+        if (!isset($this->params['tenantName']) && isset($this->params['tenant'])) {
84
+            $this->params['tenantName'] = $this->params['tenant'];
85
+        }
86 86
 
87
-		$cacheKey = $this->params['username'] . '@' . $this->params['url'] . '/' . $this->params['bucket'];
88
-		$token = $this->getCachedToken($cacheKey);
89
-		$hasToken = is_array($token) && (new \DateTimeImmutable($token['expires_at'])) > (new \DateTimeImmutable('now'));
90
-		if ($hasToken) {
91
-			$this->params['cachedToken'] = $token;
92
-		}
93
-		$httpClient = new Client([
94
-			'base_uri' => TransportUtils::normalizeUrl($this->params['url']),
95
-			'handler' => HandlerStack::create()
96
-		]);
87
+        $cacheKey = $this->params['username'] . '@' . $this->params['url'] . '/' . $this->params['bucket'];
88
+        $token = $this->getCachedToken($cacheKey);
89
+        $hasToken = is_array($token) && (new \DateTimeImmutable($token['expires_at'])) > (new \DateTimeImmutable('now'));
90
+        if ($hasToken) {
91
+            $this->params['cachedToken'] = $token;
92
+        }
93
+        $httpClient = new Client([
94
+            'base_uri' => TransportUtils::normalizeUrl($this->params['url']),
95
+            'handler' => HandlerStack::create()
96
+        ]);
97 97
 
98
-		$authService = Service::factory($httpClient);
99
-		$this->params['identityService'] = $authService;
100
-		$this->params['authUrl'] = $this->params['url'];
101
-		$client = new OpenStack($this->params);
98
+        $authService = Service::factory($httpClient);
99
+        $this->params['identityService'] = $authService;
100
+        $this->params['authUrl'] = $this->params['url'];
101
+        $client = new OpenStack($this->params);
102 102
 
103
-		if (!$hasToken) {
104
-			try {
105
-				$token = $authService->generateToken($this->params);
106
-				$this->cacheToken($token, $cacheKey);
107
-			} catch (ConnectException $e) {
108
-				throw new StorageAuthException('Failed to connect to keystone, verify the keystone url', $e);
109
-			} catch (ClientException $e) {
110
-				$statusCode = $e->getResponse()->getStatusCode();
111
-				if ($statusCode === 404) {
112
-					throw new StorageAuthException('Keystone not found, verify the keystone url', $e);
113
-				} else if ($statusCode === 412) {
114
-					throw new StorageAuthException('Precondition failed, verify the keystone url', $e);
115
-				} else if ($statusCode === 401) {
116
-					throw new StorageAuthException('Authentication failed, verify the username, password and possibly tenant', $e);
117
-				} else {
118
-					throw new StorageAuthException('Unknown error', $e);
119
-				}
120
-			} catch (RequestException $e) {
121
-				throw new StorageAuthException('Connection reset while connecting to keystone, verify the keystone url', $e);
122
-			}
123
-		}
103
+        if (!$hasToken) {
104
+            try {
105
+                $token = $authService->generateToken($this->params);
106
+                $this->cacheToken($token, $cacheKey);
107
+            } catch (ConnectException $e) {
108
+                throw new StorageAuthException('Failed to connect to keystone, verify the keystone url', $e);
109
+            } catch (ClientException $e) {
110
+                $statusCode = $e->getResponse()->getStatusCode();
111
+                if ($statusCode === 404) {
112
+                    throw new StorageAuthException('Keystone not found, verify the keystone url', $e);
113
+                } else if ($statusCode === 412) {
114
+                    throw new StorageAuthException('Precondition failed, verify the keystone url', $e);
115
+                } else if ($statusCode === 401) {
116
+                    throw new StorageAuthException('Authentication failed, verify the username, password and possibly tenant', $e);
117
+                } else {
118
+                    throw new StorageAuthException('Unknown error', $e);
119
+                }
120
+            } catch (RequestException $e) {
121
+                throw new StorageAuthException('Connection reset while connecting to keystone, verify the keystone url', $e);
122
+            }
123
+        }
124 124
 
125
-		return $client;
126
-	}
125
+        return $client;
126
+    }
127 127
 
128
-	/**
129
-	 * @return \OpenStack\ObjectStore\v1\Models\Container
130
-	 * @throws StorageAuthException
131
-	 * @throws StorageNotAvailableException
132
-	 */
133
-	public function getContainer() {
134
-		if (is_null($this->container)) {
135
-			$this->container = $this->createContainer();
136
-		}
128
+    /**
129
+     * @return \OpenStack\ObjectStore\v1\Models\Container
130
+     * @throws StorageAuthException
131
+     * @throws StorageNotAvailableException
132
+     */
133
+    public function getContainer() {
134
+        if (is_null($this->container)) {
135
+            $this->container = $this->createContainer();
136
+        }
137 137
 
138
-		return $this->container;
139
-	}
138
+        return $this->container;
139
+    }
140 140
 
141
-	/**
142
-	 * @return \OpenStack\ObjectStore\v1\Models\Container
143
-	 * @throws StorageAuthException
144
-	 * @throws StorageNotAvailableException
145
-	 */
146
-	private function createContainer() {
147
-		$client = $this->getClient();
148
-		$objectStoreService = $client->objectStoreV1();
141
+    /**
142
+     * @return \OpenStack\ObjectStore\v1\Models\Container
143
+     * @throws StorageAuthException
144
+     * @throws StorageNotAvailableException
145
+     */
146
+    private function createContainer() {
147
+        $client = $this->getClient();
148
+        $objectStoreService = $client->objectStoreV1();
149 149
 
150
-		$autoCreate = isset($this->params['autocreate']) && $this->params['autocreate'] === true;
151
-		try {
152
-			$container = $objectStoreService->getContainer($this->params['container']);
153
-			if ($autoCreate) {
154
-				$container->getMetadata();
155
-			}
156
-			return $container;
157
-		} catch (BadResponseError $ex) {
158
-			// if the container does not exist and autocreate is true try to create the container on the fly
159
-			if ($ex->getResponse()->getStatusCode() === 404 && $autoCreate) {
160
-				return $objectStoreService->createContainer([
161
-					'name' => $this->params['container']
162
-				]);
163
-			} else {
164
-				throw new StorageNotAvailableException('Invalid response while trying to get container info', StorageNotAvailableException::STATUS_ERROR, $e);
165
-			}
166
-		} catch (ConnectException $e) {
167
-			/** @var RequestInterface $request */
168
-			$request = $e->getRequest();
169
-			$host = $request->getUri()->getHost() . ':' . $request->getUri()->getPort();
170
-			\OC::$server->getLogger()->error("Can't connect to object storage server at $host");
171
-			throw new StorageNotAvailableException("Can't connect to object storage server at $host", StorageNotAvailableException::STATUS_ERROR, $e);
172
-		}
173
-	}
150
+        $autoCreate = isset($this->params['autocreate']) && $this->params['autocreate'] === true;
151
+        try {
152
+            $container = $objectStoreService->getContainer($this->params['container']);
153
+            if ($autoCreate) {
154
+                $container->getMetadata();
155
+            }
156
+            return $container;
157
+        } catch (BadResponseError $ex) {
158
+            // if the container does not exist and autocreate is true try to create the container on the fly
159
+            if ($ex->getResponse()->getStatusCode() === 404 && $autoCreate) {
160
+                return $objectStoreService->createContainer([
161
+                    'name' => $this->params['container']
162
+                ]);
163
+            } else {
164
+                throw new StorageNotAvailableException('Invalid response while trying to get container info', StorageNotAvailableException::STATUS_ERROR, $e);
165
+            }
166
+        } catch (ConnectException $e) {
167
+            /** @var RequestInterface $request */
168
+            $request = $e->getRequest();
169
+            $host = $request->getUri()->getHost() . ':' . $request->getUri()->getPort();
170
+            \OC::$server->getLogger()->error("Can't connect to object storage server at $host");
171
+            throw new StorageNotAvailableException("Can't connect to object storage server at $host", StorageNotAvailableException::STATUS_ERROR, $e);
172
+        }
173
+    }
174 174
 }
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
  *
@@ -50,7 +50,7 @@  discard block
 block discarded – undo
50 50
 	}
51 51
 
52 52
 	private function getCachedToken(string $cacheKey) {
53
-		$cachedTokenString = $this->cache->get($cacheKey . '/token');
53
+		$cachedTokenString = $this->cache->get($cacheKey.'/token');
54 54
 		if ($cachedTokenString) {
55 55
 			return json_decode($cachedTokenString);
56 56
 		} else {
@@ -59,7 +59,7 @@  discard block
 block discarded – undo
59 59
 	}
60 60
 
61 61
 	private function cacheToken(Token $token, string $cacheKey) {
62
-		$this->cache->set($cacheKey . '/token', json_encode($token));
62
+		$this->cache->set($cacheKey.'/token', json_encode($token));
63 63
 	}
64 64
 
65 65
 	/**
@@ -84,7 +84,7 @@  discard block
 block discarded – undo
84 84
 			$this->params['tenantName'] = $this->params['tenant'];
85 85
 		}
86 86
 
87
-		$cacheKey = $this->params['username'] . '@' . $this->params['url'] . '/' . $this->params['bucket'];
87
+		$cacheKey = $this->params['username'].'@'.$this->params['url'].'/'.$this->params['bucket'];
88 88
 		$token = $this->getCachedToken($cacheKey);
89 89
 		$hasToken = is_array($token) && (new \DateTimeImmutable($token['expires_at'])) > (new \DateTimeImmutable('now'));
90 90
 		if ($hasToken) {
@@ -166,7 +166,7 @@  discard block
 block discarded – undo
166 166
 		} catch (ConnectException $e) {
167 167
 			/** @var RequestInterface $request */
168 168
 			$request = $e->getRequest();
169
-			$host = $request->getUri()->getHost() . ':' . $request->getUri()->getPort();
169
+			$host = $request->getUri()->getHost().':'.$request->getUri()->getPort();
170 170
 			\OC::$server->getLogger()->error("Can't connect to object storage server at $host");
171 171
 			throw new StorageNotAvailableException("Can't connect to object storage server at $host", StorageNotAvailableException::STATUS_ERROR, $e);
172 172
 		}
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.