Mercurial > hg > orthanc
diff OrthancFramework/Sources/HttpServer/IWebDavBucket.cpp @ 4226:7bd5eab3ba25
prototyping IWebDavBucket
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Sun, 04 Oct 2020 13:23:53 +0200 |
parents | |
children | c8c0bbaaace3 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Sources/HttpServer/IWebDavBucket.cpp Sun Oct 04 13:23:53 2020 +0200 @@ -0,0 +1,220 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/>. + **/ + + +#include "../PrecompiledHeaders.h" +#include "IWebDavBucket.h" + +#include "../OrthancException.h" +#include "../Toolbox.h" + + +static boost::posix_time::ptime GetNow() +{ + return boost::posix_time::second_clock::universal_time(); +} + + +static std::string AddTrailingSlash(const std::string& s) +{ + if (s.empty() || + s[s.size() - 1] != '/') + { + return s + '/'; + } + else + { + return s; + } +} + + +namespace Orthanc +{ + void IWebDavBucket::Resource::SetNameInternal(const std::string& name) + { + if (name.find('/') != std::string::npos || + name.find('\\') != std::string::npos || + name.find('\0') != std::string::npos) + { + throw OrthancException(ErrorCode_ParameterOutOfRange, + "Bad resource name for WebDAV: " + name); + } + + name_ = name; + } + + + IWebDavBucket::Resource::Resource() : + hasModificationTime_(false), + creationTime_(GetNow()), + modificationTime_(GetNow()) + { + } + + + void IWebDavBucket::Resource::SetCreationTime(const boost::posix_time::ptime& t) + { + creationTime_ = t; + + if (!hasModificationTime_) + { + modificationTime_ = t; + } + } + + + void IWebDavBucket::Resource::SetModificationTime(const boost::posix_time::ptime& t) + { + modificationTime_ = t; + hasModificationTime_ = true; + } + + + void IWebDavBucket::Resource::Format(pugi::xml_node& node, + const std::string& parentPath) const + { + node.set_name("D:response"); + + std::string s = AddTrailingSlash(parentPath) + GetName(); + node.append_child("D:href").append_child(pugi::node_pcdata).set_value(s.c_str()); + + pugi::xml_node propstat = node.append_child("D:propstat"); + propstat.append_child("D:status").append_child(pugi::node_pcdata). + set_value("HTTP/1.1 200 OK"); + + pugi::xml_node prop = propstat.append_child("D:prop"); + + // IMPORTANT: The "Z" suffix is mandatory on Windows >= 7 + s = boost::posix_time::to_iso_extended_string(GetCreationTime()) + "Z"; + prop.append_child("D:creationdate").append_child(pugi::node_pcdata).set_value(s.c_str()); + + s = boost::posix_time::to_iso_extended_string(GetModificationTime()) + "Z"; + prop.append_child("D:getlastmodified").append_child(pugi::node_pcdata).set_value(s.c_str()); + +#if 0 + prop.append_child("D:lockdiscovery"); + pugi::xml_node lock = prop.append_child("D:supportedlock"); + + pugi::xml_node lockentry = lock.append_child("D:lockentry"); + lockentry.append_child("D:lockscope").append_child("D:exclusive"); + lockentry.append_child("D:locktype").append_child("D:write"); + + lockentry = lock.append_child("D:lockentry"); + lockentry.append_child("D:lockscope").append_child("D:shared"); + lockentry.append_child("D:locktype").append_child("D:write"); +#endif + } + + + IWebDavBucket::File::File(const std::string& name) : + contentLength_(0), + mime_(MimeType_Binary) + { + if (name.empty()) + { + throw OrthancException(ErrorCode_ParameterOutOfRange, + "Cannot use an empty filename in WebDAV"); + } + + SetNameInternal(name); + } + + + void IWebDavBucket::File::Format(pugi::xml_node& node, + const std::string& parentPath) const + { + Resource::Format(node, parentPath); + + pugi::xml_node prop = node.first_element_by_path("D:propstat/D:prop"); + prop.append_child("D:resourcetype"); + + std::string s = boost::lexical_cast<std::string>(contentLength_); + prop.append_child("D:getcontentlength").append_child(pugi::node_pcdata).set_value(s.c_str()); + + s = EnumerationToString(mime_); + prop.append_child("D:getcontenttype").append_child(pugi::node_pcdata).set_value(s.c_str()); + + prop.append_child("D:displayname").append_child(pugi::node_pcdata).set_value(GetName().c_str()); + } + + + void IWebDavBucket::Folder::Format(pugi::xml_node& node, + const std::string& parentPath) const + { + Resource::Format(node, parentPath); + + pugi::xml_node prop = node.first_element_by_path("D:propstat/D:prop"); + prop.append_child("D:resourcetype").append_child("D:collection"); + + //prop.append_child("D:getcontenttype").append_child(pugi::node_pcdata).set_value("httpd/unix-directory"); + + std::string s = GetName(); + prop.append_child("D:displayname").append_child(pugi::node_pcdata).set_value(s.c_str()); + } + + + IWebDavBucket::Collection::~Collection() + { + for (std::list<Resource*>::iterator it = resources_.begin(); it != resources_.end(); ++it) + { + assert(*it != NULL); + delete(*it); + } + } + + + void IWebDavBucket::Collection::AddResource(Resource* resource) // Takes ownership + { + if (resource == NULL) + { + throw OrthancException(ErrorCode_NullPointer); + } + else + { + resources_.push_back(resource); + } + } + + + void IWebDavBucket::Collection::Format(std::string& target, + const std::string& parentPath) const + { + pugi::xml_document doc; + + pugi::xml_node root = doc.append_child("D:multistatus"); + root.append_attribute("xmlns:D").set_value("DAV:"); + + for (std::list<Resource*>::const_iterator + it = resources_.begin(); it != resources_.end(); ++it) + { + assert(*it != NULL); + pugi::xml_node n = root.append_child(); + (*it)->Format(n, parentPath); + } + + pugi::xml_node decl = doc.prepend_child(pugi::node_declaration); + decl.append_attribute("version").set_value("1.0"); + decl.append_attribute("encoding").set_value("UTF-8"); + + Toolbox::XmlToString(target, doc); + } +}