Mercurial > hg > orthanc
annotate OrthancFramework/Sources/HttpServer/WebDavStorage.cpp @ 4232:688435755466
added DELETE in WebDAV, first working virtual filesystem
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 07 Oct 2020 13:00:57 +0200 |
parents | b313a0001893 |
children | ca2a55a62c81 |
rev | line source |
---|---|
4230 | 1 /** |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium | |
6 * | |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU Lesser General Public License | |
9 * as published by the Free Software Foundation, either version 3 of | |
10 * the License, or (at your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, but | |
13 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Lesser General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Lesser General Public | |
18 * License along with this program. If not, see | |
19 * <http://www.gnu.org/licenses/>. | |
20 **/ | |
21 | |
22 | |
23 #include "../PrecompiledHeaders.h" | |
24 #include "WebDavStorage.h" | |
25 | |
26 #include "../OrthancException.h" | |
27 #include "../SystemToolbox.h" | |
28 #include "../TemporaryFile.h" | |
29 #include "../Toolbox.h" | |
30 | |
31 namespace Orthanc | |
32 { | |
33 class WebDavStorage::StorageFile : public boost::noncopyable | |
34 { | |
35 private: | |
36 std::unique_ptr<TemporaryFile> file_; | |
37 std::string content_; | |
38 MimeType mime_; | |
39 boost::posix_time::ptime time_; | |
40 | |
41 void Touch() | |
42 { | |
43 time_ = boost::posix_time::second_clock::universal_time(); | |
44 } | |
45 | |
46 public: | |
47 StorageFile() : | |
48 mime_(MimeType_Binary) | |
49 { | |
50 Touch(); | |
51 } | |
52 | |
53 void SetContent(const std::string& content, | |
54 MimeType mime, | |
55 bool isMemory) | |
56 { | |
57 if (isMemory) | |
58 { | |
59 content_ = content; | |
60 file_.reset(); | |
61 } | |
62 else | |
63 { | |
64 content_.clear(); | |
65 file_.reset(new TemporaryFile); | |
66 file_->Write(content); | |
67 } | |
68 | |
69 mime_ = mime; | |
70 Touch(); | |
71 } | |
72 | |
73 MimeType GetMimeType() const | |
74 { | |
75 return mime_; | |
76 } | |
77 | |
78 void GetContent(std::string& target) const | |
79 { | |
80 if (file_.get() == NULL) | |
81 { | |
82 target = content_; | |
83 } | |
84 else | |
85 { | |
86 file_->Read(target); | |
87 } | |
88 } | |
89 | |
90 const boost::posix_time::ptime& GetTime() const | |
91 { | |
92 return time_; | |
93 } | |
94 | |
95 uint64_t GetContentLength() const | |
96 { | |
97 if (file_.get() == NULL) | |
98 { | |
99 return content_.size(); | |
100 } | |
101 else | |
102 { | |
103 return file_->GetFileSize(); | |
104 } | |
105 } | |
106 }; | |
107 | |
108 | |
109 class WebDavStorage::StorageFolder : public boost::noncopyable | |
110 { | |
111 private: | |
112 typedef std::map<std::string, StorageFile*> Files; | |
113 typedef std::map<std::string, StorageFolder*> Subfolders; | |
114 | |
115 Files files_; | |
116 Subfolders subfolders_; | |
117 | |
118 void CheckName(const std::string& name) | |
119 { | |
120 if (name.empty() || | |
121 name.find('/') != std::string::npos || | |
122 name.find('\\') != std::string::npos || | |
123 name.find('\0') != std::string::npos) | |
124 { | |
125 throw OrthancException(ErrorCode_ParameterOutOfRange, | |
126 "Bad resource name for WebDAV: " + name); | |
127 } | |
128 } | |
129 | |
130 bool IsExisting(const std::string& name) const | |
131 { | |
132 return (files_.find(name) != files_.end() || | |
133 subfolders_.find(name) != subfolders_.end()); | |
134 } | |
135 | |
136 public: | |
137 ~StorageFolder() | |
138 { | |
139 for (Files::iterator it = files_.begin(); it != files_.end(); ++it) | |
140 { | |
141 assert(it->second != NULL); | |
142 delete it->second; | |
143 } | |
144 | |
145 for (Subfolders::iterator it = subfolders_.begin(); it != subfolders_.end(); ++it) | |
146 { | |
147 assert(it->second != NULL); | |
148 delete it->second; | |
149 } | |
150 } | |
151 | |
152 const StorageFile* LookupFile(const std::string& name) const | |
153 { | |
154 Files::const_iterator found = files_.find(name); | |
155 if (found == files_.end()) | |
156 { | |
157 return NULL; | |
158 } | |
159 else | |
160 { | |
161 assert(found->second != NULL); | |
162 return found->second; | |
163 } | |
164 } | |
165 | |
166 bool CreateSubfolder(const std::string& name) | |
167 { | |
168 CheckName(name); | |
169 | |
170 if (IsExisting(name)) | |
171 { | |
172 LOG(ERROR) << "WebDAV folder already existing: " << name; | |
173 return false; | |
174 } | |
175 else | |
176 { | |
177 subfolders_[name] = new StorageFolder; | |
178 return true; | |
179 } | |
180 } | |
181 | |
182 bool StoreFile(const std::string& name, | |
183 const std::string& content, | |
184 MimeType mime, | |
185 bool isMemory) | |
186 { | |
187 CheckName(name); | |
188 | |
189 if (subfolders_.find(name) != subfolders_.end()) | |
190 { | |
191 LOG(ERROR) << "WebDAV folder already existing: " << name; | |
192 return false; | |
193 } | |
194 | |
195 Files::iterator found = files_.find(name); | |
196 if (found == files_.end()) | |
197 { | |
198 std::unique_ptr<StorageFile> f(new StorageFile); | |
199 f->SetContent(content, mime, isMemory); | |
200 files_[name] = f.release(); | |
201 } | |
202 else | |
203 { | |
204 assert(found->second != NULL); | |
205 found->second->SetContent(content, mime, isMemory); | |
206 } | |
207 | |
208 return true; | |
209 } | |
210 | |
211 StorageFolder* LookupFolder(const std::vector<std::string>& path) | |
212 { | |
213 if (path.empty()) | |
214 { | |
215 return this; | |
216 } | |
217 else | |
218 { | |
219 Subfolders::const_iterator found = subfolders_.find(path[0]); | |
220 if (found == subfolders_.end()) | |
221 { | |
222 return NULL; | |
223 } | |
224 else | |
225 { | |
226 assert(found->second != NULL); | |
227 | |
228 std::vector<std::string> p(path.begin() + 1, path.end()); | |
229 return found->second->LookupFolder(p); | |
230 } | |
231 } | |
232 } | |
233 | |
234 void ListCollection(Collection& collection) const | |
235 { | |
236 for (Files::const_iterator it = files_.begin(); it != files_.end(); ++it) | |
237 { | |
238 assert(it->second != NULL); | |
239 | |
240 std::unique_ptr<File> f(new File(it->first)); | |
241 f->SetContentLength(it->second->GetContentLength()); | |
242 f->SetCreationTime(it->second->GetTime()); | |
243 collection.AddResource(f.release()); | |
244 } | |
245 | |
246 for (Subfolders::const_iterator it = subfolders_.begin(); it != subfolders_.end(); ++it) | |
247 { | |
248 collection.AddResource(new Folder(it->first)); | |
249 } | |
250 } | |
251 }; | |
252 | |
253 | |
254 WebDavStorage::StorageFolder* WebDavStorage::LookupParentFolder(const std::vector<std::string>& path) | |
255 { | |
256 if (path.empty()) | |
257 { | |
258 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
259 } | |
260 | |
261 std::vector<std::string> p(path.begin(), path.end() - 1); | |
262 return root_->LookupFolder(p); | |
263 } | |
264 | |
265 | |
266 WebDavStorage::WebDavStorage(bool isMemory) : | |
267 root_(new StorageFolder), | |
268 isMemory_(isMemory) | |
269 { | |
270 } | |
271 | |
272 | |
273 bool WebDavStorage::IsExistingFolder(const std::vector<std::string>& path) | |
274 { | |
275 boost::recursive_mutex::scoped_lock lock(mutex_); | |
276 | |
277 return (root_->LookupFolder(path) != NULL); | |
278 } | |
279 | |
280 | |
281 bool WebDavStorage::ListCollection(Collection& collection, | |
282 const std::vector<std::string>& path) | |
283 { | |
284 boost::recursive_mutex::scoped_lock lock(mutex_); | |
285 | |
286 const StorageFolder* folder = root_->LookupFolder(path); | |
287 if (folder == NULL) | |
288 { | |
289 return false; | |
290 } | |
291 else | |
292 { | |
293 folder->ListCollection(collection); | |
294 return true; | |
295 } | |
296 } | |
297 | |
298 | |
299 bool WebDavStorage::GetFileContent(MimeType& mime, | |
300 std::string& content, | |
301 boost::posix_time::ptime& modificationTime, | |
302 const std::vector<std::string>& path) | |
303 { | |
304 boost::recursive_mutex::scoped_lock lock(mutex_); | |
305 | |
306 const StorageFolder* folder = LookupParentFolder(path); | |
307 if (folder == NULL) | |
308 { | |
309 return false; | |
310 } | |
311 else | |
312 { | |
313 const StorageFile* file = folder->LookupFile(path.back()); | |
314 if (file == NULL) | |
315 { | |
316 return false; | |
317 } | |
318 else | |
319 { | |
320 mime = file->GetMimeType(); | |
321 file->GetContent(content); | |
322 modificationTime = file->GetTime(); | |
323 return true; | |
324 } | |
325 } | |
326 } | |
327 | |
328 | |
329 bool WebDavStorage::StoreFile(const std::string& content, | |
330 const std::vector<std::string>& path) | |
331 { | |
332 boost::recursive_mutex::scoped_lock lock(mutex_); | |
333 | |
334 StorageFolder* folder = LookupParentFolder(path); | |
335 if (folder == NULL) | |
336 { | |
337 LOG(WARNING) << "Inexisting folder in WebDAV: " << Toolbox::FlattenUri(path); | |
338 return false; | |
339 } | |
340 else | |
341 { | |
342 LOG(INFO) << "Storing " << content.size() | |
343 << " bytes in WebDAV bucket: " << Toolbox::FlattenUri(path);; | |
344 | |
345 MimeType mime = SystemToolbox::AutodetectMimeType(path.back()); | |
346 return folder->StoreFile(path.back(), content, mime, isMemory_); | |
347 } | |
348 } | |
349 | |
350 | |
351 bool WebDavStorage::CreateFolder(const std::vector<std::string>& path) | |
352 { | |
353 boost::recursive_mutex::scoped_lock lock(mutex_); | |
354 | |
355 StorageFolder* folder = LookupParentFolder(path); | |
356 if (folder == NULL) | |
357 { | |
358 LOG(WARNING) << "Inexisting folder in WebDAV: " << Toolbox::FlattenUri(path); | |
359 return false; | |
360 } | |
361 else | |
362 { | |
363 LOG(INFO) << "Creating folder in WebDAV bucket: " << Toolbox::FlattenUri(path); | |
364 return folder->CreateSubfolder(path.back()); | |
365 } | |
366 } | |
4232
688435755466
added DELETE in WebDAV, first working virtual filesystem
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4230
diff
changeset
|
367 |
688435755466
added DELETE in WebDAV, first working virtual filesystem
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4230
diff
changeset
|
368 |
688435755466
added DELETE in WebDAV, first working virtual filesystem
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4230
diff
changeset
|
369 bool WebDavStorage::DeleteItem(const std::vector<std::string>& path) |
688435755466
added DELETE in WebDAV, first working virtual filesystem
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4230
diff
changeset
|
370 { |
688435755466
added DELETE in WebDAV, first working virtual filesystem
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4230
diff
changeset
|
371 // TODO |
688435755466
added DELETE in WebDAV, first working virtual filesystem
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4230
diff
changeset
|
372 return false; |
688435755466
added DELETE in WebDAV, first working virtual filesystem
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4230
diff
changeset
|
373 } |
4230 | 374 } |