libzeep-3.0.2/0000775000175000017500000000000012162310454013006 5ustar maartenmaartenlibzeep-3.0.2/zeep/0000775000175000017500000000000012162310454013751 5ustar maartenmaartenlibzeep-3.0.2/zeep/exception.hpp0000664000175000017500000000152111750236762016472 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008-2012. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef SOAP_EXCEPTION_H #define SOAP_EXCEPTION_H #include #include namespace zeep { /// zeep::exception is a class used to throw zeep exception. class exception : public std::exception { public: /// \brief Create an exception with vsprintf like parameters exception(const char* message, ...); exception(const std::string& message) : m_message(message) {} // exception( // XML_Parser parser); // virtual ~exception() throw() {} virtual const char* what() const throw() { return m_message.c_str(); } protected: std::string m_message; }; } #endif libzeep-3.0.2/zeep/config.hpp0000664000175000017500000000625511777540137015755 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008-2012. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #pragma once /// Libzeep comes with its own XML parser implementation. If you prefer /// you can use expat instead. To do so you have to define the /// SOAP_XML_HAS_EXPAT_SUPPORT flag and then you can call the /// zeep::xml::document::set_parser_type function to specify expat. #ifndef SOAP_XML_HAS_EXPAT_SUPPORT #define SOAP_XML_HAS_EXPAT_SUPPORT 0 #endif /// The http server implementation in libzeep can use a /// preforked mode. That means the main process listens to /// a network port and passes the socket to a client process /// for doing the actual handling. The advantages for a setup /// like this is that if the client fails, the server can detect /// this and restart the client thereby guaranteeing a better /// uptime. #ifndef SOAP_SERVER_HAS_PREFORK #if defined(_MSC_VER) #define SOAP_SERVER_HAS_PREFORK 0 #else #define SOAP_SERVER_HAS_PREFORK 1 #endif #endif #ifndef LIBZEEP_DOXYGEN_INVOKED // see if we're using Visual C++, if so we have to include // some VC specific include files to make the standard C++ // keywords work. #if defined(_MSC_VER) # if defined(_MSC_EXTENSIONS) // why is it an extension to leave out something? # define and && # define and_eq &= # define bitand & # define bitor | # define compl ~ # define not ! # define not_eq != # define or || # define or_eq |= # define xor ^ # define xor_eq ^= # endif // _MSC_EXTENSIONS # pragma warning (disable : 4355) // this is used in Base Initializer list # pragma warning (disable : 4996) // unsafe function or variable # pragma warning (disable : 4068) // unknown pragma # pragma warning (disable : 4996) // stl copy() # pragma warning (disable : 4800) // BOOL conversion #endif // GCC 4.4 and before do not know nullptr #if defined (__GNUC__) && !defined(__GXX_EXPERIMENTAL_CXX0X__) const // this is a const object... class { public: template // convertible to any type operator T*() const // of null non-member { return 0; } // pointer... template // or any type of null operator T C::*() const // member pointer... { return 0; } private: void operator&() const; // whose address can't be taken } nullptr = {}; // and whose name is nullptr #endif /// fixes for cygwin/boost-1.43 combo /// source: /// https://svn.boost.org/trac/boost/attachment/ticket/4816/boost_asio_bug_cygwin_with_fix.cpp #ifdef __CYGWIN__ //////////////// FIX STARTS HERE /// 1st issue #include /// 2nd issue #include #ifdef cfgetospeed #define __cfgetospeed__impl(tp) cfgetospeed(tp) #undef cfgetospeed inline speed_t cfgetospeed(const struct termios *tp) { //return ((tp)->c_ospeed); return __cfgetospeed__impl(tp); } #undef __cfgetospeed__impl #endif /// cfgetospeed is a macro /// 3rd issue #undef __CYGWIN__ #include #define __CYGWIN__ //////////////// FIX ENDS HERE #endif #endif libzeep-3.0.2/zeep/http/0000775000175000017500000000000012162310454014730 5ustar maartenmaartenlibzeep-3.0.2/zeep/http/request.hpp0000664000175000017500000000240012071316303017123 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008-2012. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef SOAP_HTTP_REQUEST_HPP #define SOAP_HTTP_REQUEST_HPP #include #include namespace zeep { namespace http { /// request contains the parsed original HTTP request as received /// by the server. struct request { std::string method; ///< POST or GET std::string uri; ///< The uri as requested int http_version_major; ///< HTTP major number (usually 1) int http_version_minor; ///< HTTP major number (0 or 1) std::vector
headers; ///< A list with zeep::http::header values std::string payload; ///< For POST requests bool close; ///< Whether 'Connection: close' was specified // for redirects... std::string local_address; ///< The address the request was received upon unsigned short local_port; ///< The port number the request was received upon float accept(const char* type) const; ///< Return the value in the Accept header for type bool is_mobile() const; ///< Check HTTP_USER_AGENT to see if it is a mobile client }; } } #endif libzeep-3.0.2/zeep/http/header.hpp0000664000175000017500000000103211750236762016700 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef SOAP_HTTP_HEADER_H #define SOAP_HTTP_HEADER_H #include namespace zeep { namespace http { /// The header object contains the header lines as found in a /// HTTP Request. The lines are parsed into name / value pairs. struct header { std::string name; std::string value; }; } } #endif libzeep-3.0.2/zeep/http/webapp/0000775000175000017500000000000012162310454016206 5ustar maartenmaartenlibzeep-3.0.2/zeep/http/webapp/el.hpp0000664000175000017500000003367212052764674017351 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008-2011. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // expression language support // #pragma once #include #include #include #include #include #ifndef LIBZEEP_DOXYGEN_INVOKED typedef boost::int8_t int8; typedef boost::uint8_t uint8; typedef boost::int16_t int16; typedef boost::uint16_t uint16; typedef boost::int32_t int32; typedef boost::uint32_t uint32; typedef boost::int64_t int64; typedef boost::uint64_t uint64; #endif namespace zeep { namespace http { namespace el { namespace detail { class object_impl; class object_iterator_impl; }; class scope; /// This zeep::http::el::object class is a bridge to the `el` expression language. class object { public: /// object can have one of these basic types: enum object_type { null_type, array_type, struct_type, number_type, string_type }; object(); object(const object& o); explicit object(detail::object_impl* impl); ~object(); /// create an array object explicit object(const std::vector& v); explicit object(const std::vector& v); /// construct an object directly from some basic types explicit object(bool v); explicit object(int8 v); explicit object(uint8 v); explicit object(int16 v); explicit object(uint16 v); explicit object(int32 v); explicit object(uint32 v); explicit object(int64 v); explicit object(uint64 v); explicit object(float v); explicit object(double v); explicit object(const char* v); explicit object(const std::string& v); object& operator=(const object& o); /// assign an array object object& operator=(const std::vector& v); object& operator=(const std::vector& v); /// and assign some basic types object& operator=(bool v); object& operator=(int8 v); object& operator=(uint8 v); object& operator=(int16 v); object& operator=(uint16 v); object& operator=(int32 v); object& operator=(uint32 v); object& operator=(int64 v); object& operator=(uint64 v); object& operator=(float v); object& operator=(double v); object& operator=(const char* v); object& operator=(const std::string& v); object_type type() const; template T as() const; const object operator[](const std::string& name) const; const object operator[](const char* name) const; const object operator[](const object& index) const; object& operator[](const std::string& name); object& operator[](const char* name); object& operator[](const object& index); size_t count() const; bool empty() const; bool operator<(const object& rhs) const; bool operator==(const object& rhs) const; template class basic_iterator : public std::iterator { public: typedef typename std::iterator base_type; typedef typename base_type::reference reference; typedef typename base_type::pointer pointer; basic_iterator(); basic_iterator(const basic_iterator& other); basic_iterator(detail::object_impl* a); basic_iterator(detail::object_impl* a, int); basic_iterator(const detail::object_impl* a); basic_iterator(const detail::object_impl* a, int); ~basic_iterator(); basic_iterator& operator=(const basic_iterator& other); reference operator*() const; pointer operator->() const; basic_iterator& operator++(); basic_iterator operator++(int); bool operator==(const basic_iterator& other) const; bool operator!=(const basic_iterator& other) const; private: detail::object_iterator_impl* m_impl; }; typedef basic_iterator iterator; typedef basic_iterator const_iterator; iterator begin() { return iterator(m_impl); } iterator end() { return iterator(m_impl, -1); } const_iterator begin() const { return const_iterator(m_impl); } const_iterator end() const { return const_iterator(m_impl, -1); } friend iterator range_begin(object& x) { return x.begin(); } friend iterator range_end(object& x) { return x.end(); } friend const_iterator range_begin(const object& x) { return x.begin(); } friend const_iterator range_end(const object& x) { return x.end(); } friend std::ostream& operator<<(std::ostream& lhs, const object& rhs); std::string toJSON() const; private: friend object operator+(const object& a, const object& b); friend object operator-(const object& a, const object& b); friend object operator*(const object& a, const object& b); friend object operator%(const object& a, const object& b); friend object operator/(const object& a, const object& b); friend object operator-(const object& a); class detail::object_impl* m_impl; }; /// \brief Process the text in \a text and return `true` if the result is /// not empty, zero or false. /// /// The expression in \a text is processed and if the result of this /// expression is empty, false or zero then `false` is returned. /// \param scope The scope for this el script /// \param text The el script /// \return The result of the script bool process_el(const scope& scope, std::string& text); /// \brief Process the text in \a text. The result is put in \a result /// /// The expression in \a text is processed and the result is returned /// in \a result. /// \param scope The scope for this el script /// \param text The el script /// \return The result of the script void evaluate_el(const scope& scope, const std::string& text, object& result); /// \brief Process the text in \a text and replace it with the result /// /// The expressions found in \a text are processed and the output of /// the processing is used as a replacement value for the expressions. /// \param scope The scope for the el scripts /// \param text The text optionally containing el scripts. /// \return Returns true if \a text was changed. bool evaluate_el(const scope& scope, const std::string& text); // -------------------------------------------------------------------- class scope { public: scope(const request& req); explicit scope(const scope& next); template void put(const std::string& name, const T& value); template void put(const std::string& name, ForwardIterator begin, ForwardIterator end); const object& lookup(const std::string& name) const; const object& operator[](const std::string& name) const; object& lookup(const std::string& name); object& operator[](const std::string& name); const request& get_request() const; private: friend std::ostream& operator<<(std::ostream& lhs, const scope& rhs); scope& operator=(const scope&); typedef std::map data_map; data_map m_data; scope* m_next; const request* m_req; }; /// for debugging purposes std::ostream& operator<<(std::ostream& lhs, const scope& rhs); template inline void scope::put( const std::string& name, const T& value) { m_data[name] = object(value); } template<> inline void scope::put( const std::string& name, const object& value) { m_data[name] = value; } template inline void scope::put( const std::string& name, ForwardIterator begin, ForwardIterator end) { std::vector elements; while (begin != end) elements.push_back(object(*begin++)); m_data[name] = object(elements); } // -------------------------------------------------------------------- namespace detail { class object_iterator_impl; class object_impl { public: void reference() { ++m_refcount; } void release() { if (--m_refcount == 0) delete this; } object::object_type type() const { return m_type; } bool is_null() const { return m_type == object::null_type; } bool is_array() const { return m_type == object::array_type; } bool is_struct() const { return m_type == object::struct_type; } bool is_number() const { return m_type == object::number_type; } bool is_string() const { return m_type == object::string_type; } virtual void print(std::ostream& os) const = 0; virtual int compare(object_impl* rhs) const = 0; virtual int64 to_int() const; virtual double to_double() const; virtual std::string to_str() const; virtual std::string to_JSON() const; friend class object; protected: object_impl(object::object_type type = object::null_type) : m_refcount(1) , m_type(type) { } virtual ~object_impl() { } private: object_impl(const object_impl&); object_impl& operator=(const object_impl&); int32 m_refcount; object::object_type m_type; }; class base_array_object_impl : public object_impl { public: virtual size_t count() const = 0; virtual object_iterator_impl* create_iterator(bool begin) const = 0; virtual object& at(uint32 ix); virtual const object at(uint32 ix) const; protected: base_array_object_impl() : object_impl(object::array_type) { } }; class base_struct_object_impl : public object_impl { public: virtual object& field(const std::string& name) = 0; virtual const object field(const std::string& name) const = 0; protected: base_struct_object_impl() : object_impl(object::struct_type) { } }; class object_iterator_impl { public: void reference() { ++m_refcount; } void release() { if (--m_refcount == 0) delete this; } object_iterator_impl() : m_refcount(1) {} virtual void increment() = 0; virtual object& dereference() = 0; virtual bool equal(const object_iterator_impl* other) = 0; protected: virtual ~object_iterator_impl() {} private: int m_refcount; }; } // -------------------------------------------------------------------- template object::basic_iterator::basic_iterator() : m_impl(nullptr) { } template object::basic_iterator::basic_iterator(const basic_iterator& o) : m_impl(o.m_impl) { if (m_impl != nullptr) m_impl->reference(); } template object::basic_iterator::basic_iterator(detail::object_impl* a) : m_impl(nullptr) { detail::base_array_object_impl* impl = dynamic_cast(a); if (impl != nullptr) m_impl = impl->create_iterator(true); } template object::basic_iterator::basic_iterator(detail::object_impl* a, int) : m_impl(nullptr) { detail::base_array_object_impl* impl = dynamic_cast(a); if (impl != nullptr) m_impl = impl->create_iterator(false); } template object::basic_iterator::basic_iterator(const detail::object_impl* a) : m_impl(nullptr) { const detail::base_array_object_impl* impl = dynamic_cast(a); if (impl != nullptr) m_impl = impl->create_iterator(true); } template object::basic_iterator::basic_iterator(const detail::object_impl* a, int) : m_impl(nullptr) { const detail::base_array_object_impl* impl = dynamic_cast(a); if (impl != nullptr) m_impl = impl->create_iterator(false); } template object::basic_iterator::~basic_iterator() { if (m_impl != nullptr) m_impl->release(); } template object::basic_iterator& object::basic_iterator::operator=(const basic_iterator& o) { if (this != &o) { if (m_impl != nullptr) m_impl->release(); m_impl = o.m_impl; if (m_impl != nullptr) m_impl->reference(); } return *this; } template typename object::basic_iterator::reference object::basic_iterator::operator*() const { if (m_impl == nullptr) throw exception("dereferencing invalid object iterator"); return m_impl->dereference(); } template typename object::basic_iterator::pointer object::basic_iterator::operator->() const { if (m_impl == nullptr) throw exception("dereferencing invalid object iterator"); return &m_impl->dereference(); } template object::basic_iterator& object::basic_iterator::operator++() { if (m_impl == nullptr) throw exception("incrementing invalid object iterator"); m_impl->increment(); return *this; } template object::basic_iterator object::basic_iterator::operator++(int) { if (m_impl == nullptr) throw exception("incrementing invalid object iterator"); basic_iterator iter(*this); m_impl->increment(); return iter; } template bool object::basic_iterator::operator==(const basic_iterator& o) const { bool result; if (m_impl == nullptr and o.m_impl == nullptr) result = true; else if (m_impl == nullptr or o.m_impl == nullptr) throw exception("invalid object iterators"); else result = m_impl->equal(o.m_impl); return result; } template bool object::basic_iterator::operator!=(const basic_iterator& o) const { bool result; if (m_impl == nullptr and o.m_impl == nullptr) result = false; else if (m_impl == nullptr or o.m_impl == nullptr) throw exception("invalid object iterators"); else result = not m_impl->equal(o.m_impl); return result; } } } } #ifndef LIBZEEP_DOXYGEN_INVOKED // enable foreach (.., array object) namespace boost { // specialize range_mutable_iterator and range_const_iterator in namespace boost template<> struct range_mutable_iterator { typedef zeep::http::el::object::iterator type; }; template<> struct range_const_iterator { typedef zeep::http::el::object::const_iterator type; }; } #endif libzeep-3.0.2/zeep/http/connection.hpp0000664000175000017500000000260211750236762017613 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008-2012. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef SOAP_HTTP_CONNECTION_HPP #define SOAP_HTTP_CONNECTION_HPP #include #include #include #include #include #include namespace zeep { namespace http { /// The HTTP server implementation of libzeep is inspired by the example code /// as provided by boost::asio. These objects are not to be used directly. class connection : public boost::enable_shared_from_this , public boost::noncopyable { public: connection(boost::asio::io_service& service, request_handler& handler); void start(); void handle_read(const boost::system::error_code& ec, size_t bytes_transferred); void handle_write(const boost::system::error_code& ec); boost::asio::ip::tcp::socket& get_socket() { return m_socket; } private: boost::asio::ip::tcp::socket m_socket; request_parser m_request_parser; request_handler& m_request_handler; boost::array m_buffer; request m_request; reply m_reply; }; } } #endif libzeep-3.0.2/zeep/http/request_parser.hpp0000664000175000017500000000223411750236762020521 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008-2012. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef SOAP_HTTP_REQUEST_PARSER_HPP #define SOAP_HTTP_REQUEST_PARSER_HPP #include #include namespace zeep { namespace http { /// An HTTP request parser with support for Transfer-Encoding: Chunked class request_parser { public: request_parser(); void reset(); boost::tribool parse(request& req, const char* text, size_t length); private: typedef boost::tribool (request_parser::*state_parser)(request& req, char ch); boost::tribool parse_initial_line(request& req, char ch); boost::tribool parse_header(request& req, char ch); boost::tribool parse_empty_line(request& req, char ch); boost::tribool parse_chunk(request& req, char ch); boost::tribool parse_footer(request& req, char ch); boost::tribool parse_content(request& req, char ch); state_parser m_parser; int m_state; unsigned int m_chunk_size; std::string m_data; }; } } #endif libzeep-3.0.2/zeep/http/request_handler.hpp0000664000175000017500000000113411750236762020640 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008-2012. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef SOAP_HTTP_REQUEST_HANDLER_HPP #define SOAP_HTTP_REQUEST_HANDLER_HPP #include #include namespace zeep { namespace http { /// Simply an interface class request_handler { public: virtual void handle_request(boost::asio::ip::tcp::socket& socket, const request& req, reply& reply) = 0; }; } } #endif libzeep-3.0.2/zeep/http/webapp.hpp0000664000175000017500000002055512061575257016742 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008-2011. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // webapp is a base class used to construct web applications in C++ using libzeep // #pragma once #include #include #include #include #include #include #include #include #include #include #include #include // -------------------------------------------------------------------- // namespace zeep { namespace http { struct unauthorized_exception : public std::exception { unauthorized_exception(bool stale, const std::string& realm) : m_stale(stale) { std::string::size_type n = realm.length(); if (n >= sizeof(m_realm)) n = sizeof(m_realm) - 1; realm.copy(m_realm, n); m_realm[n] = 0; } bool m_stale; ///< Is true when the authorization information is valid but stale (too old) char m_realm[256]; ///< Realm for which the authorization failed }; #ifndef BOOST_XPRESSIVE_DOXYGEN_INVOKED namespace el { class scope; class object; } #endif class parameter_value { public: parameter_value() : m_defaulted(false) {} parameter_value(const std::string& v, bool defaulted) : m_v(v), m_defaulted(defaulted) {} template T as() const; bool empty() const { return m_v.empty(); } bool defaulted() const { return m_defaulted; } private: std::string m_v; bool m_defaulted; }; /// parameter_map is used to pass parameters from forms. The parameters can have 'any' type. /// Works a bit like the program_options code in boost. class parameter_map : public std::multimap { public: /// add a name/value pair as a string formatted as 'name=value' void add(const std::string& param); void add(std::string name, std::string value); void replace(std::string name, std::string value); template const parameter_value& get(const std::string& name, T defaultValue); }; /// webapp is a specialization of zeep::http::server, it is used to create /// interactive web applications. class webapp : public http::server { public: /// first parameter to constructor is the /// namespace to use in template XHTML files. webapp(const std::string& ns = "http://www.cmbi.ru.nl/libzeep/ml", const boost::filesystem::path& docroot = "."); virtual ~webapp(); virtual void set_docroot(const boost::filesystem::path& docroot); boost::filesystem::path get_docroot() const { return m_docroot; } protected: virtual void handle_request(const request& req, reply& rep); virtual void create_unauth_reply(bool stale, const std::string& realm, reply& rep); // webapp works with 'handlers' that are methods 'mounted' on a path in the requested URI typedef boost::function handler_type; /// assign a handler function to a path in the server's namespace /// Usually called like this: /// /// mount("page", boost::bind(&page_handler, this, _1, _2, _3)); /// /// Where page_handler is defined as: /// /// void my_server::page_handler(const request& request, const el::scope& scope, reply& reply); /// void mount(const std::string& path, handler_type handler); /// Default handler for serving files out of our doc root virtual void handle_file(const request& request, const el::scope& scope, reply& reply); /// Use load_template to fetch the XHTML template file virtual void load_template(const std::string& file, xml::document& doc); void load_template(const boost::filesystem::path& file, xml::document& doc) { load_template(file.string(), doc); } /// create a reply based on a template virtual void create_reply_from_template(const std::string& file, const el::scope& scope, reply& reply); /// process xml parses the XHTML and fills in the special tags and evaluates the el constructs virtual void process_xml(xml::node* node, const el::scope& scope, boost::filesystem::path dir); typedef boost::function processor_type; /// To add additional processors virtual void add_processor(const std::string& name, processor_type processor); /// default handler for mrs:include tags virtual void process_include(xml::element* node, const el::scope& scope, boost::filesystem::path dir); /// default handler for mrs:if tags virtual void process_if(xml::element* node, const el::scope& scope, boost::filesystem::path dir); /// default handler for mrs:iterate tags virtual void process_iterate(xml::element* node, const el::scope& scope, boost::filesystem::path dir); /// default handler for mrs:for tags virtual void process_for(xml::element* node, const el::scope& scope, boost::filesystem::path dir); /// default handler for mrs:number tags virtual void process_number(xml::element* node, const el::scope& scope, boost::filesystem::path dir); /// default handler for mrs:options tags virtual void process_options(xml::element* node, const el::scope& scope, boost::filesystem::path dir); /// default handler for mrs:option tags virtual void process_option(xml::element* node, const el::scope& scope, boost::filesystem::path dir); /// default handler for mrs:checkbox tags virtual void process_checkbox(xml::element* node, const el::scope& scope, boost::filesystem::path dir); /// default handler for mrs:url tags virtual void process_url(xml::element* node, const el::scope& scope, boost::filesystem::path dir); /// default handler for mrs:param tags virtual void process_param(xml::element* node, const el::scope& scope, boost::filesystem::path dir); /// default handler for mrs:embed tags virtual void process_embed(xml::element* node, const el::scope& scope, boost::filesystem::path dir); /// Initialize the el::scope object virtual void init_scope(el::scope& scope); /// Return a parameter_map containing the cookies as found in the current request virtual void get_cookies(const el::scope& scope, parameter_map& cookies); /// Return the original parameters as found in the current request virtual void get_parameters(const el::scope& scope, parameter_map& parameters); private: typedef std::map handler_map; typedef std::map processor_map; std::string m_ns; boost::filesystem::path m_docroot; handler_map m_dispatch_table; processor_map m_processor_table; }; template inline T parameter_value::as() const { T result; if (boost::is_arithmetic::value and m_v.empty()) result = 0; else result = boost::lexical_cast(m_v); return result; } template<> inline std::string parameter_value::as() const { return m_v; } template<> inline bool parameter_value::as() const { bool result = false; if (not m_v.empty() and m_v != "false") { if (m_v == "true") result = true; else { try { result = boost::lexical_cast(m_v) != 0; } catch (...) {} } } return result; } template inline const parameter_value& parameter_map::get( const std::string& name, T defaultValue) { iterator i = lower_bound(name); if (i == end() or i->first != name) i = insert(std::make_pair(name, parameter_value(boost::lexical_cast(defaultValue), true))); return i->second; } // specialisation for const char* template<> inline const parameter_value& parameter_map::get( const std::string& name, const char* defaultValue) { if (defaultValue == nullptr) defaultValue = ""; iterator i = lower_bound(name); if (i == end() or i->first != name) i = insert(std::make_pair(name, parameter_value(defaultValue, true))); else if (i->second.empty()) i->second = parameter_value(defaultValue, true); return i->second; } // specialisation for bool (if missing, value is false) template<> inline const parameter_value& parameter_map::get( const std::string& name, bool defaultValue) { iterator i = lower_bound(name); if (i == end() or i->first != name) i = insert(std::make_pair(name, parameter_value("false", true))); else if (i->second.empty()) i->second = parameter_value("false", true); return i->second; } } } libzeep-3.0.2/zeep/http/preforked-server.hpp0000664000175000017500000001366012076000575020740 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef SOAP_HTTP_PREFORKED_SERVER_HPP #define SOAP_HTTP_PREFORKED_SERVER_HPP #include #include #include /// preforked server support. /// A preforked server means you have a master process that listens to a port /// and whenever a request comes in, the socket is passed to a client. This /// client will then process the request. /// This approach has several advantages related to security and stability. /// /// The way it works in libzeep is, you still create a server that derives /// from zeep::server (if you need a SOAP server) or zeep::http::server (if /// you only want a HTTP server). You then create a /// zeep::http::preforked_server_base instance passing in the /// parameters required and then call run() on this preforked server. /// /// The preforked_server class records the way your server needs to be /// constructed. When this preforked_server is run, it forks and then /// constructs your server class in the child process. /// /// Example: /// /// class my_server { /// my_server(const string& my_param); /// .... /// /// zeep::http::preforked_server\ server("my extra param"); /// boost::thread t( /// boost::bind(&zeep::http::preforked_server\::run, &server, 2)); /// server.bind("0.0.0.0", 10333); /// /// ... // wait for signal to stop /// server.stop(); /// t.join(); /// /// The start_listening call is needed since we want to postpone opening network ports /// until after the child has been forked. For a single server this is obviously no problem /// but if you fork more than one child, the latter would inherit all open network connections /// from the previous children. namespace zeep { namespace http { class preforked_server_base { public: /// forks child and starts listening, should be a separate thread virtual void run(const std::string& address, short port, int nr_of_threads); virtual void start(); ///< signal the thread it can start listening: virtual void stop(); ///< stop the running thread #ifndef LIBZEEP_DOXYGEN_INVOKED virtual ~preforked_server_base(); protected: struct server_constructor_base { virtual ~server_constructor_base() {} virtual server* construct() = 0; }; template struct server_constructor; preforked_server_base(server_constructor_base* constructor); private: preforked_server_base(const preforked_server_base&); preforked_server_base& operator=(const preforked_server_base&); static bool read_socket_from_parent(int fd_socket, boost::asio::ip::tcp::socket& socket); static void write_socket_to_worker(int fd_socket, boost::asio::ip::tcp::socket& socket); void handle_accept(const boost::system::error_code& ec); server_constructor_base* m_constructor; boost::asio::io_service m_io_service; boost::asio::ip::tcp::acceptor m_acceptor; boost::asio::ip::tcp::socket m_socket; int m_fd; int m_pid; boost::mutex m_lock; #endif }; template struct preforked_server_base::server_constructor : public server_constructor_base { virtual server* construct() { return new Server(); } }; template struct preforked_server_base::server_constructor : public server_constructor_base { server_constructor(T0 t0) : m_t0(t0) {} virtual server* construct() { return new Server(m_t0); } private: typedef typename boost::remove_const< typename boost::remove_reference::type>::type value_type_0; value_type_0 m_t0; }; template struct preforked_server_base::server_constructor : public server_constructor_base { server_constructor(T0 t0, T1 t1) : m_t0(t0), m_t1(t1) {} virtual server* construct() { return new Server(m_t0, m_t1); } private: typedef typename boost::remove_const< typename boost::remove_reference::type>::type value_type_0; typedef typename boost::remove_const< typename boost::remove_reference::type>::type value_type_1; value_type_0 m_t0; value_type_1 m_t1; }; template struct preforked_server_base::server_constructor : public server_constructor_base { server_constructor(T0 t0, T1 t1, T2 t2) : m_t0(t0), m_t1(t1), m_t2(t2) {} virtual server* construct() { return new Server(m_t0, m_t1, m_t2); } private: typedef typename boost::remove_const< typename boost::remove_reference::type>::type value_type_0; typedef typename boost::remove_const< typename boost::remove_reference::type>::type value_type_1; typedef typename boost::remove_const< typename boost::remove_reference::type>::type value_type_2; value_type_0 m_t0; value_type_1 m_t1; value_type_2 m_t2; }; template class preforked_server : public preforked_server_base { typedef Server server_type; public: /// Four constructors, one without and three with parameters. preforked_server() : preforked_server_base(new server_constructor()) { } template preforked_server(T0 t0) : preforked_server_base(new server_constructor(t0)) { } template preforked_server(T0 t0, T1 t1) : preforked_server_base(new server_constructor(t0, t1)) { } template preforked_server(T0 t0, T1 t1, T2 t2) : preforked_server_base(new server_constructor(t0, t1, t2)) { } }; } } #endif libzeep-3.0.2/zeep/http/server.hpp0000664000175000017500000000513212121554615016754 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008-2012. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef SOAP_HTTP_SERVER_HPP #define SOAP_HTTP_SERVER_HPP #include #include #include #include namespace zeep { namespace http { /// The libzeep HTTP server implementation. Based on code found in boost::asio. class connection; /// Decode a URL using the RFC rules /// \param s The URL that needs to be decoded /// \return The decoded URL std::string decode_url(const std::string& s); /// Encode a URL using the RFC rules /// \param s The URL that needs to be encoded /// \return The encoded URL std::string encode_url(const std::string& s); class server : public request_handler { public: server(); /// Bind the server to \a address and \a port virtual void bind(const std::string& address, unsigned short port); virtual ~server(); virtual void run(int nr_of_threads); virtual void stop(); /// to extend the log entry for a current request, use this ostream: static std::ostream& log(); /// log_forwarded tells the HTTP server to use the last entry in X-Forwarded-For as client log entry void log_forwarded(bool v) { m_log_forwarded = v; } std::string address() const { return m_address; } unsigned short port() const { return m_port; } /// get_io_service has to be public since we need it to call notify_fork from child code boost::asio::io_service& get_io_service() { return m_io_service; } protected: virtual void handle_request(const request& req, reply& rep); /// the default entry logger virtual void log_request(const std::string& client, const request& req, const reply& rep, const boost::posix_time::ptime& start, const std::string& referer, const std::string& userAgent, const std::string& entry); private: friend class preforked_server_base; server(const server&); server& operator=(const server&); virtual void handle_request(boost::asio::ip::tcp::socket& socket, const request& req, reply& rep); void handle_accept(const boost::system::error_code& ec); boost::asio::io_service m_io_service; boost::shared_ptr m_acceptor; boost::thread_group m_threads; boost::shared_ptr m_new_connection; std::string m_address; unsigned short m_port; bool m_log_forwarded; }; } } #endif libzeep-3.0.2/zeep/http/reply.hpp0000664000175000017500000000576412125636672016624 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef SOAP_HTTP_REPLY_HPP #define SOAP_HTTP_REPLY_HPP #include #include #include #include #include namespace zeep { namespace http { /// Various predefined HTTP status codes enum status_type { cont = 100, ok = 200, created = 201, accepted = 202, no_content = 204, multiple_choices = 300, moved_permanently = 301, moved_temporarily = 302, not_modified = 304, bad_request = 400, unauthorized = 401, forbidden = 403, not_found = 404, internal_server_error = 500, not_implemented = 501, bad_gateway = 502, service_unavailable = 503 }; class reply { public: /// Create a reply, default is HTTP 1.0. Use 1.1 if you want to use keep alive e.g. reply(int version_major = 1, int version_minor = 0); reply(const reply&); ~reply(); reply& operator=(const reply&); void set_version(int version_major, int version_minor); /// Add a header with name \a name and value \a value void set_header(const std::string& name, const std::string& value); std::string get_content_type() const; void set_content_type( const std::string& type); ///< Set the Content-Type header /// Set the content and the content-type header void set_content(xml::document& doc); /// Set the content and the content-type header void set_content(xml::element* data); /// Set the content and the content-type header void set_content(const std::string& data, const std::string& contentType); /// To send a stream of data, with unknown size (using chunked transfer). /// reply takes ownership of \a data and deletes it when done. void set_content(std::istream* data, const std::string& contentType); void to_buffers(std::vector& buffers); /// for istream data, continues until data_to_buffers returns false bool data_to_buffers(std::vector& buffers); /// For debugging purposes std::string get_as_text(); std::size_t get_size() const; /// Create a standard reply based on a HTTP status code static reply stock_reply(status_type inStatus); /// Create a standard redirect reply with the specified \a location static reply redirect(const std::string& location); status_type get_status() const { return m_status; } private: int m_version_major, m_version_minor; status_type m_status; std::string m_status_line; std::vector
m_headers; std::string m_content; std::istream* m_data; std::vector m_buffer; }; } } #endif libzeep-3.0.2/zeep/envelope.hpp0000664000175000017500000000323511750236762016315 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008-2012. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) /// #ifndef SOAP_ENVELOPE_H #define SOAP_ENVELOPE_H #include #include /// Envelope is a wrapper around a SOAP envelope. Use it for /// input and output of correctly formatted SOAP messages. namespace zeep { class envelope : public boost::noncopyable { public: /// \brief Create an empty envelope envelope(); /// \brief Parse a SOAP message received from a client, /// throws an exception if the envelope is empty or invalid. envelope(xml::document& data); /// \brief The request element as contained in the original SOAP message xml::element* request() { return m_request; } private: xml::element* m_request; }; /// Wrap data into a SOAP envelope /// /// \param data The xml::element object to wrap into the envelope /// \return A new xml::element object containing the envelope. xml::element* make_envelope(xml::element* data); /// Create a standard SOAP Fault message for the string parameter /// /// \param message The string object containing a descriptive error message. /// \return A new xml::element object containing the fault envelope. xml::element* make_fault(const std::string& message); /// Create a standard SOAP Fault message for the exception object /// /// \param ex The exception object that was catched. /// \return A new xml::element object containing the fault envelope. xml::element* make_fault(const std::exception& ex); } #endif libzeep-3.0.2/zeep/xml/0000775000175000017500000000000012162310454014551 5ustar maartenmaartenlibzeep-3.0.2/zeep/xml/parser.hpp0000664000175000017500000001016511765427160016574 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2010-2011. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef SOAP_XML_PARSER_H #define SOAP_XML_PARSER_H #include #include #include #include namespace zeep { namespace xml { namespace detail { struct attr { std::string m_ns; std::string m_name; std::string m_value; bool m_id; // whether the attribute is defined as type ID in its ATTLIST decl }; } /// If an invalid_exception is thrown, it means the XML document is not valid: it does /// not conform the DTD specified in the XML document. /// This is only thrown when validation is enabled. /// /// The what() member of the exception object will contain an explanation. class invalid_exception : public zeep::exception { public: invalid_exception(const std::string& msg) : exception(msg) {} ~invalid_exception() throw () {} }; /// If an not_wf_exception is thrown, it means the XML document is not well formed. /// Often this means syntax errors, missing \< or \> characters, non matching open /// and close tags, etc. /// /// The what() member of the exception object will contain an explanation. class not_wf_exception : public zeep::exception { public: not_wf_exception(const std::string& msg) : exception(msg) {} ~not_wf_exception() throw () {} }; /// zeep::xml::parser is a SAX parser. After construction, you should assign /// call back handlers for the SAX events and then call parse(). class parser { public: #ifndef LIBZEEP_DOXYGEN_INVOKED typedef detail::attr attr_type; typedef std::list attr_list_type; #endif parser(std::istream& is); parser(const std::string& s); virtual ~parser(); boost::function start_element_handler; boost::function end_element_handler; boost::function character_data_handler; boost::function processing_instruction_handler; boost::function comment_handler; boost::function start_cdata_section_handler; boost::function end_cdata_section_handler; boost::function start_namespace_decl_handler; boost::function end_namespace_decl_handler; boost::function notation_decl_handler; boost::function external_entity_ref_handler; boost::function report_invalidation_handler; void parse(bool validate); #ifndef LIBZEEP_DOXYGEN_INVOKED protected: friend struct parser_imp; virtual void start_element(const std::string& name, const std::string& uri, const attr_list_type& atts); virtual void end_element(const std::string& name, const std::string& uri); virtual void character_data(const std::string& data); virtual void processing_instruction(const std::string& target, const std::string& data); virtual void comment(const std::string& data); virtual void start_cdata_section(); virtual void end_cdata_section(); virtual void start_namespace_decl(const std::string& prefix, const std::string& uri); virtual void end_namespace_decl(const std::string& prefix); virtual void notation_decl(const std::string& name, const std::string& systemId, const std::string& publicId); virtual void report_invalidation(const std::string& msg); virtual std::istream* external_entity_ref(const std::string& base, const std::string& pubid, const std::string& uri); struct parser_imp* m_impl; std::istream* m_istream; #endif }; } } #endif libzeep-3.0.2/zeep/xml/document.hpp0000664000175000017500000002041112126525621017102 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008-2012. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef SOAP_XML_DOCUMENT_H #define SOAP_XML_DOCUMENT_H #include #include #include #include #include #include namespace zeep { namespace xml { #if SOAP_XML_HAS_EXPAT_SUPPORT /// By default libzeep will use its own XML SAX parser, but you can use /// expat instead. enum parser_type { parser_zeep, parser_expat }; #endif struct document_imp; /// zeep::xml::document is the class that contains a parsed XML file. /// You can create an empty document and add nodes to it, or you can /// create it by specifying a string containing XML or an std::istream /// to parse. /// /// If you use an std::fstream to read a file, be sure to open the file /// ios::binary. Otherwise, the detection of text encoding might go wrong /// or the content can become corrupted. /// /// Default is to parse CDATA sections into zeep::xml::text nodes. If you /// want to preserve CDATA sections in the DOM tree, you have to call /// set_preserve_cdata before reading the file. /// /// By default a document is not validated. But you can turn on validation /// by using the appropriate constructor or read method, or by setting /// set_validating explicitly. The DTD's will be loaded from the base dir /// specified, but you can change this by assigning a external_entity_ref_handler. /// /// A document has one zeep::xml::root_node element. This root element /// can have only one zeep::xml::element child node. class document { public: /// \brief Constructor for an empty document. document(); /// \brief Constructor that will parse the XML passed in argument \a s document(const std::string& s); /// \brief Constructor that will parse the XML passed in argument \a is document(std::istream& is); /// \brief Constructor that will parse the XML passed in argument \a is. This /// constructor will also validate the input using DTD's found in \a base_dir document(std::istream& is, const boost::filesystem::path& base_dir); #ifndef LIBZEEP_DOXYGEN_INVOKED virtual ~document(); #endif // I/O void read(const std::string& s); ///< Replace the content of the document with the parsed XML in \a s void read(std::istream& is); ///< Replace the content of the document with the parsed XML in \a is void read(std::istream& is, const boost::filesystem::path& base_dir); ///< Replace the content of the document with the parsed XML in \a is and use validation based on DTD's found in \a base_dir virtual void write(writer& w) const; ///< Write the contents of the document as XML using zeep::xml::writer object \a w /// Serialization support template void serialize(const char* name, const T& data); ///< Serialize \a data into a document containing \a name as root node template void deserialize(const char* name, T& data); ///< Deserialize root node with name \a name into \a data. /// A valid xml document contains exactly one zeep::xml::root_node element root_node* root() const; /// The root has one child zeep::xml::element element* child() const; void child(element* e); // helper functions element_set find(const std::string& path) const ///< Return all zeep::xml::elements that match the XPath query \a path { return find(path.c_str()); } element* find_first(const std::string& path) const ///< Return the first zeep::xml::element that matches the XPath query \a path { return find_first(path.c_str()); } element_set find(const char* path) const; ///< Return all zeep::xml::elements that match the XPath query \a path element* find_first(const char* path) const; ///< Return the first zeep::xml::element that matches the XPath query \a path void find(const char* path, node_set& nodes) const; ///< Return all zeep::xml::nodes (attributes or elements) that match the XPath query \a path void find(const char* path, element_set& elements) const; ///< Return all zeep::xml::elements that match the XPath query \a path node* find_first_node(const char* path) const; ///< Return the first zeep::xml::node (attribute or element) that matches the XPath query \a path /// Compare two xml documents bool operator==(const document& doc) const; bool operator!=(const document& doc) const { return not operator==(doc); } /// If you want to validate the document using DTD files stored on disk, you can specifiy this directory prior to reading /// the document. void base_dir(const boost::filesystem::path& path); /// The default for libzeep is to locate the external reference based /// on sysid and base_dir. Only local files are loaded this way. /// You can specify a entity loader here if you want to be able to load /// DTD files from another source. boost::function external_entity_ref_handler; encoding_type encoding() const; ///< The text encoding as detected in the input. void encoding(encoding_type enc); ///< The text encoding to use for output // to format the output, use the following: int indent() const; ///< get number of spaces to indent elements: void indent(int indent); ///< set number of spaces to indent elements: // whether to have each element on a separate line bool wrap() const; ///< get wrap flag, whether elements will appear on their own line or not void wrap(bool wrap); ///< set wrap flag, whether elements will appear on their own line or not // reduce the whitespace in #PCDATA sections bool trim() const; ///< get trim flag, strips white space in #PCDATA sections void trim(bool trim); ///< set trim flag, strips white space in #PCDATA sections // suppress writing out comments bool no_comment() const; ///< get no_comment flag, suppresses the output of XML comments void no_comment(bool no_comment); ///< get no_comment flag, suppresses the output of XML comments /// options for parsing /// validating uses a DTD if it is defined void set_validating(bool validate); /// preserve cdata, preserves CDATA sections instead of converting them /// into text nodes. void set_preserve_cdata(bool preserve_cdata); #if SOAP_XML_HAS_EXPAT_SUPPORT /// By default, libzeep uses its own parser implementation. But if you prefer /// expat you can specify that here. static void set_parser_type(parser_type type); #endif #ifndef LIBZEEP_DOXYGEN_INVOKED protected: document(struct document_imp* impl); friend void process_document_elements(std::istream& data, const std::string& element_xpath, boost::function cb); #if SOAP_XML_HAS_EXPAT_SUPPORT static parser_type s_parser_type; #endif document_imp* create_imp(document* doc); document_imp* m_impl; private: document(const document&); document& operator=(const document&); #endif }; /// Using operator>> is an alternative for calling rhs.read(lhs); std::istream& operator>>(std::istream& lhs, document& rhs); /// Using operator<< is an alternative for calling writer w(lhs); rhs.write(w); std::ostream& operator<<(std::ostream& lhs, const document& rhs); /// \brief To read a document and process elements on the go, use this streaming input function. /// If the \a proc callback retuns false, processing is terminated. The \a doc_root parameter of /// the callback is the leading xml up to the first element. void process_document_elements(std::istream& data, const std::string& element_xpath, boost::function cb); #ifndef LIBZEEP_DOXYGEN_INVOKED template void document::serialize(const char* name, const T& data) { serializer sr(root()); sr.serialize_element(name, data); } template void document::deserialize(const char* name, T& data) { if (child() == nullptr) throw zeep::exception("empty document"); if (child()->name() != name) throw zeep::exception("root mismatch"); deserializer sr(root()); sr.deserialize_element(name, data); } #endif } } #endif libzeep-3.0.2/zeep/xml/serialize.hpp0000664000175000017500000010353712162310310017251 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef SOAP_XML_SERIALIZE_H #define SOAP_XML_SERIALIZE_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Lots of template wizardry here... // // The goal is to make a completely transparent XML serializer/deserializer // in order to translate SOAP messages into/out of native C++ types. // // The interface for the code below is compatible with the 'serialize' member // function required to use boost::serialization. /// \def SOAP_XML_ADD_ENUM(e,v) /// \brief A macro to add the name of an enum value to the serializer /// /// To be able to correctly use enum values in a schema file or when serializing, /// you have to specify the enum values. /// /// E.g., if you have a struct name Algorithm with values 'vector', 'dice' and 'jaccard' /// you would write: /// ///> enum Algorithm { vector, dice, jaccard }; ///> SOAP_XML_ADD_ENUM(Algorithm, vector); ///> SOAP_XML_ADD_ENUM(Algorithm, dice); ///> SOAP_XML_ADD_ENUM(Algorithm, jaccard); /// /// An alternative (better?) way to do this is: /// ///> zeep::xml::enum_map::instance("Algorithm").add_enum() ///> ("vector", vector) ///> ("dice", dice) ///> ("jaccard", jaccard); /// \def SOAP_XML_SET_STRUCT_NAME(s) /// \brief A macro to assign a name to a struct used in serialization. /// /// By default, libzeep uses the typeid(s).name() as the name for an element. /// That's often not what is intented. Calling this macro will make sure /// the type name you used in your code will be used instead. /// /// E.g., struct FindResult { ... } might end up with a mangled name in the /// schema. To use FindResult instead, call SOAP_XML_SET_STRUCT_NAME(FindResult); /// /// An alternative is to call, which allows different schema and struct names: /// zeep::xml::struct_serializer::set_struct_name("FindResult"); namespace zeep { namespace xml { #ifndef LIBZEEP_DOXYGEN_INVOKED const std::string kPrefix = "ns"; #endif /// Older versions of libzeep used to use boost::serialization::nvp as type to /// specify name/value pairs. This will continue to work, but to use attributes /// we come up with a special version of name/value pairs specific for libzeep. struct serializer; struct deserializer; template struct element_nvp : public boost::serialization::nvp { explicit element_nvp(const char* name, T& v) : boost::serialization::nvp(name, v) {} element_nvp(const element_nvp& rhs) : boost::serialization::nvp(rhs) {} }; template struct attribute_nvp : public boost::serialization::nvp { explicit attribute_nvp(const char* name, T& v) : boost::serialization::nvp(name, v) {} attribute_nvp(const attribute_nvp& rhs) : boost::serialization::nvp(rhs) {} }; template inline element_nvp make_element_nvp(const char* name, T& v) { return element_nvp(name, v); } template inline attribute_nvp make_attribute_nvp(const char* name, T& v) { return attribute_nvp(name, v); } #define ZEEP_ELEMENT_NAME_VALUE(name) \ zeep::xml::make_element_nvp(BOOST_PP_STRINGIZE(name), name) #define ZEEP_ATTRIBUTE_NAME_VALUE(name) \ zeep::xml::make_attribute_nvp(BOOST_PP_STRINGIZE(name), name) /// serializer, deserializer and schema_creator are classes that can be used /// to initiate the serialization. They are the Archive classes that are /// the first parameter to the templated function 'serialize' in the classes /// that can be serialized. (See boost::serialization for more info). /// serializer is the class that initiates the serialization process. struct serializer { serializer(container* node) : m_node(node) {} template serializer& operator&(const boost::serialization::nvp& rhs) { return serialize_element(rhs.name(), rhs.value()); } template serializer& operator&(const element_nvp& rhs) { return serialize_element(rhs.name(), rhs.value()); } template serializer& operator&(const attribute_nvp& rhs) { return serialize_attribute(rhs.name(), rhs.value()); } template serializer& serialize_element(const char* name, const T& data); template serializer& serialize_attribute(const char* name, const T& data); container* m_node; }; /// deserializer is the class that initiates the deserialization process. struct deserializer { deserializer(const container* node) : m_node(node) {} template deserializer& operator&(const boost::serialization::nvp& rhs) { return deserialize_element(rhs.name(), rhs.value()); } template deserializer& operator&(const element_nvp& rhs) { return deserialize_element(rhs.name(), rhs.value()); } template deserializer& operator&(const attribute_nvp& rhs) { return deserialize_attribute(rhs.name(), rhs.value()); } template deserializer& deserialize_element(const char* name, T& data); template deserializer& deserialize_attribute(const char* name, T& data); const container* m_node; }; #ifndef LIBZEEP_DOXYGEN_INVOKED typedef std::map type_map; #endif /// schema_creator is used by zeep::dispatcher to create schema files. struct schema_creator { schema_creator(type_map& types, element* node) : m_node(node), m_types(types) {} template schema_creator& operator&(const boost::serialization::nvp& rhs) { return add_element(rhs.name(), rhs.value()); } template schema_creator& operator&(const element_nvp& rhs) { return add_element(rhs.name(), rhs.value()); } template schema_creator& operator&(const attribute_nvp& rhs) { return add_attribute(rhs.name(), rhs.value()); } template schema_creator& add_element(const char* name, const T& value); template schema_creator& add_attribute(const char* name, const T& value); element* m_node; type_map& m_types; }; #ifndef LIBZEEP_DOXYGEN_INVOKED // The actual (de)serializers // // We have two kinds of serializers, basic type serializers can read and write // their values from/to strings. They also have a type_name that is used in // schema's, this should be the XSD standard name. These basic serializers are // used to write either XML element content or attribute values. // // The basic serializers should typedef a type value_type and also implement // the following functions: // // static std::string serialize_value(const value_type& value); // static value_type deserialize_value(const std::string& value); // static const char* type_name(); // // The basic serializers are accessed through another templated class, // serializer_type. // // All versions of serializer_type<> should implement the following // functions: // // static void serialize(element* n, const T& v); // static void serialize_child(container* n, const char* name, const T& v); // static void deserialize(const element* n, T& v); // static void deserialize_child(const container* n, const char* name, T& v); // static element* schema(const std::string& name); // static void register_type(type_map& types); // // Examples of specializations of serializer_type are serialize_container_type // and serialize_boost_optional. // arithmetic types are ints, doubles, etc... simply use lexical_cast to convert these template::value> struct arithmetic_schema_name {}; template struct arithmetic_schema_name { static const char* type_name() { return "xsd:byte"; } }; template struct arithmetic_schema_name { static const char* type_name() { return "xsd:unsignedByte"; } }; template struct arithmetic_schema_name { static const char* type_name() { return "xsd:short"; } }; template struct arithmetic_schema_name { static const char* type_name() { return "xsd:unsignedShort"; } }; template struct arithmetic_schema_name { static const char* type_name() { return "xsd:int"; } }; template struct arithmetic_schema_name { static const char* type_name() { return "xsd:unsignedInt"; } }; template struct arithmetic_schema_name { static const char* type_name() { return "xsd:long"; } }; template struct arithmetic_schema_name { static const char* type_name() { return "xsd:unsignedLong"; } }; template<> struct arithmetic_schema_name { static const char* type_name() { return "xsd:float"; } }; template<> struct arithmetic_schema_name { static const char* type_name() { return "xsd:double"; } }; template struct arithmetic_serializer : public arithmetic_schema_name { typedef T value_type; // use promoted type to force writing out char as an integer typedef typename boost::integral_promotion::type promoted_type; static std::string serialize_value(const value_type& value) { return boost::lexical_cast(static_cast(value)); } static value_type deserialize_value(const std::string& value) { return value.empty() ? 0 : static_cast(boost::lexical_cast(value)); } }; struct string_serializer { typedef std::string value_type; static const char* type_name() { return "xsd:string"; } static std::string serialize_value(const std::string& value) { return value; } static std::string deserialize_value(const std::string& value) { return value; } }; struct bool_serializer { typedef bool value_type; static const char* type_name() { return "xsd:boolean"; } static std::string serialize_value(bool value) { return value ? "true" : "false"; } static bool deserialize_value(const std::string& value) { return (value == "true" or value == "1"); } }; /// \brief serializer/deserializer for boost::posix_time::ptime /// boost::posix_time::ptime values are always assumed to be UTC struct boost_posix_time_ptime_serializer { typedef boost::posix_time::ptime value_type; static const char* type_name() { return "xsd:dateTime"; } /// Serialize the boost::posix_time::ptime as YYYY-MM-DDThh:mm:ssZ (zero UTC offset) static std::string serialize_value(const boost::posix_time::ptime& v) { return boost::posix_time::to_iso_extended_string(v).append("Z"); } /// Deserialize according to ISO8601 rules. /// If Zulu time is specified, then the parsed xsd:dateTime is returned. /// If an UTC offset is present, then the offset is subtracted from the xsd:dateTime, this yields UTC. /// If no UTC offset is present, then the xsd:dateTime is assumed to be local time and converted to UTC. static boost::posix_time::ptime deserialize_value(const std::string& s) { // We accept 3 general formats: // 1: date fields separated with dashes, time fields separated with colons, eg. 2013-02-17T15:25:20,502104+01:00 // 2: date fields not separated, time fields separated with colons, eg. 20130217T15:25:20,502104+01:00 // 3: date fields not separated, time fields not separated, eg. 20130217T152520,502104+01:00 // Apart from the separators, the 3 regexes are basically the same, i.e. they have the same fields // Note: boost::regex is threadsafe, so we can declare these statically // Format 1: // ^(-?\d{4})-(\d{2})-(\d{2})T(\d{2})(:(\d{2})(:(\d{2})([.,](\d+))?)?)?((Z)|([-+])(\d{2})(:(\d{2}))?)?$ // ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^^ ^ ^ ^ ^ // | | | | | | | | | | || | | | | // | | | | | | | | | | || | | | [16] UTC minutes offset // | | | | | | | | | | || | | [15] have UTC minutes offset? // | | | | | | | | | | || | [14] UTC hour offset // | | | | | | | | | | || [13] UTC offset sign // | | | | | | | | | | |[12] Zulu time // | | | | | | | | | | [11] have time zone? // | | | | | | | | | [10] fractional seconds // | | | | | | | | [9] have fractional seconds // | | | | | | | [8] seconds // | | | | | | [7] have seconds? // | | | | | [6] minutes // | | | | [5] have minutes? // | | | [4] hours // | | [3] day // | [2] month // [1] year static boost::regex re1("^(-?\\d{4})-(\\d{2})-(\\d{2})T(\\d{2})(:(\\d{2})(:(\\d{2})([.,](\\d+))?)?)?((Z)|([-+])(\\d{2})(:(\\d{2}))?)?$"); // Format 2: // ^(-?\d{4})(\d{2})(\d{2})T(\d{2})(:(\d{2})(:(\d{2})([.,]\d+)?)?)?((Z)|([-+])(\d{2})(:(\d{2}))?)?$ static boost::regex re2("^(-?\\d{4})(\\d{2})(\\d{2})T(\\d{2})(:(\\d{2})(:(\\d{2})([.,]\\d+)?)?)?((Z)|([-+])(\\d{2})(:(\\d{2}))?)?$"); // Format 3: // ^(-?\d{4})(\d{2})(\d{2})T(\d{2})((\d{2})((\d{2})([.,]\d+)?)?)?((Z)|([-+])(\d{2})(:(\d{2}))?)?$ static boost::regex re3("^(-?\\d{4})(\\d{2})(\\d{2})T(\\d{2})((\\d{2})((\\d{2})([.,]\\d+)?)?)?((Z)|([-+])(\\d{2})(:(\\d{2}))?)?$"); static const int f_year = 1; static const int f_month = 2; static const int f_day = 3; static const int f_hours = 4; static const int f_have_minutes = 5; static const int f_minutes = 6; static const int f_have_seconds = 7; static const int f_seconds = 8; static const int f_have_frac = 9; static const int f_frac = 10; static const int f_have_tz = 11; static const int f_zulu = 12; static const int f_offs_sign = 13; static const int f_offs_hours = 14; static const int f_have_offs_minutes = 15; static const int f_offs_minutes = 16; boost::smatch m; if (not boost::regex_match(s, m, re1)) { if (not boost::regex_match(s, m, re2)) { if (not boost::regex_match(s, m, re3)) { throw exception("Bad dateTime format"); } } } boost::gregorian::date d( boost::lexical_cast(m[f_year]) , boost::lexical_cast(m[f_month]) , boost::lexical_cast(m[f_day]) ); int hours = boost::lexical_cast(m[f_hours]); int minutes = 0, seconds = 0; if (m.length(f_have_minutes)) { minutes = boost::lexical_cast(m[f_minutes]); if (m.length(f_have_seconds)) { seconds = boost::lexical_cast(m[f_seconds]); } } boost::posix_time::time_duration t(hours, minutes, seconds); if (m.length(f_have_frac)) { double frac = boost::lexical_cast(std::string(".").append(std::string(m[f_frac]))); t += boost::posix_time::microseconds(static_cast((frac + .5) * 1e6)); } boost::posix_time::ptime result = boost::posix_time::ptime(d, t); if (m.length(f_have_tz)) { if (not m.length(f_zulu)) { std::string sign = m[f_offs_sign]; int hours = boost::lexical_cast(m[f_offs_hours]); int minutes = 0; if (m.length(f_have_offs_minutes)) { minutes = boost::lexical_cast(m[f_offs_minutes]); } boost::posix_time::time_duration offs(hours, minutes, 0); if (sign == "+") { result -= offs; } else { result += offs; } } } else { // Boost has no clear way of instantiating the *current* timezone, so // it's not possible to convert from local to UTC, using boost::local_time classes // For now, settle on using mktime... std::tm tm = boost::posix_time::to_tm(result); tm.tm_isdst = -1; std::time_t t = mktime(&tm); result = boost::posix_time::from_time_t(t); } return result; } }; /// \brief serializer/deserializer for boost::gregorian::date /// boost::gregorian::date values are assumed to be floating, i.e. we don't accept timezone info in dates struct boost_gregorian_date_serializer { typedef boost::gregorian::date value_type; static const char* type_name() { return "xsd:date"; } /// Serialize the boost::gregorian::date as YYYY-MM-DD static std::string serialize_value(container* parent, const std::string& name, const boost::gregorian::date& v) { return boost::gregorian::to_iso_extended_string(v); } /// Deserialize boost::gregorian::date according to ISO8601 rules, but without timezone. static boost::gregorian::date deserialize_value(const std::string& s) { // We accept 2 general formats: // 1: date fields separated with dashes, eg. 2013-02-17 // 2: date fields not separated, eg. 20130217 // Apart from the separators, the 2 regexes are basically the same, i.e. they have the same fields // Note: boost::regex is threadsafe, so we can declare these statically // Format 1: // ^(-?\d{4})-(\d{2})-(\d{2})$ // ^ ^ ^ // | | | // | | | // | | [3] day // | [2] month // [1] year static boost::regex re1("^(-?\\d{4})-(\\d{2})-(\\d{2})$"); // Format 2: // ^(-?\d{4})(\d{2})(\d{2})$ static boost::regex re2("^(-?\\d{4})(\\d{2})(\\d{2})$"); static const int f_year = 1; static const int f_month = 2; static const int f_day = 3; boost::smatch m; if (not boost::regex_match(s, m, re1)) { if (not boost::regex_match(s, m, re2)) { throw exception("Bad date format"); } } return boost::gregorian::date( boost::lexical_cast(m[f_year]) , boost::lexical_cast(m[f_month]) , boost::lexical_cast(m[f_day]) ); } }; /// \brief serializer/deserializer for boost::posix_time::time_duration /// boost::posix_time::time_duration values are assumed to be floating, i.e. we don't accept timezone info in times struct boost_posix_time_time_duration_serializer { typedef boost::posix_time::time_duration value_type; static const char* type_name() { return "xsd:time"; } /// Serialize the boost::posix_time::time_duration as hh:mm:ss,ffffff static std::string serialize_value(const boost::posix_time::time_duration& v) { return boost::posix_time::to_simple_string(v); } /// Deserialize boost::posix_time::time_duration according to ISO8601 rules, but without timezone. static boost::posix_time::time_duration deserialize_value(const std::string& s) { // We accept 2 general formats: // 1: time fields separated with colons, eg. 15:25:20,502104 // 2: time fields not separated, eg. 152520,502104 // Apart from the separators, the 2 regexes are basically the same, i.e. they have the same fields // Note: boost::regex is threadsafe, so we can declare these statically // Format 1: // ^(\d{2})(:(\d{2})(:(\d{2})([.,](\d+))?)?)?$ // ^ ^ ^ ^ ^ ^ ^ // | | | | | | | // | | | | | | [7] fractional seconds // | | | | | [6] have fractional seconds // | | | | [5] seconds // | | | [4] have seconds? // | | [3] minutes // | [2] have minutes? // [1] hours static boost::regex re1("^(\\d{2})(:(\\d{2})(:(\\d{2})([.,](\\d+))?)?)?$"); // Format 2: // ^(\d{2})((\d{2})((\d{2})([.,](\d+))?)?)?$ static boost::regex re2("^(\\d{2})((\\d{2})((\\d{2})([.,](\\d+))?)?)?$"); static const int f_hours = 1; static const int f_have_minutes = 2; static const int f_minutes = 3; static const int f_have_seconds = 4; static const int f_seconds = 5; static const int f_have_frac = 6; static const int f_frac = 7; boost::smatch m; if (not boost::regex_match(s, m, re1)) { if (not boost::regex_match(s, m, re2)) { throw exception("Bad time format"); } } int hours = boost::lexical_cast(m[f_hours]); int minutes = 0, seconds = 0; if (m.length(f_have_minutes)) { minutes = boost::lexical_cast(m[f_minutes]); if (m.length(f_have_seconds)) { seconds = boost::lexical_cast(m[f_seconds]); } } boost::posix_time::time_duration result = boost::posix_time::time_duration(hours, minutes, seconds); if (m.length(f_have_frac)) { double frac = boost::lexical_cast(std::string(".").append(std::string(m[f_frac]))); result += boost::posix_time::microseconds(static_cast((frac + .5) * 1e6)); } return result; } }; // code to serialize structs. // struct_serializer_archive is a helper class to be used as Archive template struct struct_serializer { static void serialize(Archive& stream, T& data) { data.serialize(stream, 0U); } }; template struct struct_serializer_impl { typedef Struct value_type; static std::string s_struct_name; static const char* type_name() { return s_struct_name.c_str(); } static void serialize(container* n, const value_type& value) { typedef struct_serializer archive; serializer sr(n); archive::serialize(sr, const_cast(value)); } static void deserialize(const container* n, value_type& v) { typedef struct_serializer archive; deserializer ds(n); archive::serialize(ds, v); } static element* schema(const std::string& name) { element* result(new element("xsd:element")); result->set_attribute("name", name); result->set_attribute("type", kPrefix + ':' + s_struct_name); result->set_attribute("minOccurs", "1"); result->set_attribute("maxOccurs", "1"); return result; } static void register_type(type_map& types) { element* n(new element("xsd:complexType")); n->set_attribute("name", s_struct_name); types[s_struct_name] = n; element* sequence(new element("xsd:sequence")); n->append(sequence); typedef struct_serializer archive; schema_creator schema(types, sequence); value_type v; archive::serialize(schema, v); } static void set_struct_name(const std::string& name) { s_struct_name = name; } }; template std::string struct_serializer_impl::s_struct_name = typeid(Struct).name(); #endif #define SOAP_XML_SET_STRUCT_NAME(s) zeep::xml::struct_serializer_impl::s_struct_name = BOOST_PP_STRINGIZE(s); // code to serialize enums. #ifndef LIBZEEP_DOXYGEN_INVOKED template struct enum_map { typedef typename std::map name_mapping_type; name_mapping_type m_name_mapping; std::string m_name; static enum_map& instance(const char* name = NULL) { static enum_map s_instance; if (name and s_instance.m_name.empty()) s_instance.m_name = name; return s_instance; } class add_enum_helper { friend struct enum_map; add_enum_helper(name_mapping_type& mapping) : m_mapping(mapping) {} name_mapping_type& m_mapping; public: add_enum_helper& operator()(const std::string& name, T value) { m_mapping[value] = name; return *this; } }; add_enum_helper add_enum() { return add_enum_helper(m_name_mapping); } }; #endif #define SOAP_XML_ADD_ENUM(e,v) zeep::xml::enum_map::instance(BOOST_PP_STRINGIZE(e)).m_name_mapping[v] = BOOST_PP_STRINGIZE(v); #ifndef LIBZEEP_DOXYGEN_INVOKED template struct enum_serializer { typedef T value_type; typedef enum_map t_enum_map; typedef std::map t_map; static const char* type_name() { static std::string s_type_name = t_enum_map::instance().m_name; return s_type_name.c_str(); } static std::string serialize_value(const T& value) { return t_enum_map::instance().m_name_mapping[value]; } static void serialize(container* n, const value_type& value) { n->str(serialize_value(value)); } static T deserialize_value(const std::string& value) { T result = T(); t_map& m = t_enum_map::instance().m_name_mapping; for (typename t_map::iterator e = m.begin(); e != m.end(); ++e) { if (e->second == value) { result = e->first; break; } } return result; } static void deserialize(const container* n, value_type& value) { value = deserialize_value(n->str()); } static element* schema(const std::string& name) { std::string my_type_name = type_name(); element* result(new element("xsd:element")); result->set_attribute("name", name); result->set_attribute("type", kPrefix + ':' + my_type_name); result->set_attribute("minOccurs", "1"); result->set_attribute("maxOccurs", "1"); return result; } static void register_type(type_map& types) { element* n(new element("xsd:simpleType")); n->set_attribute("name", type_name()); types[type_name()] = n; element* restriction(new element("xsd:restriction")); restriction->set_attribute("base", "xsd:string"); n->append(restriction); t_map& m = t_enum_map::instance().m_name_mapping; for (typename t_map::iterator e = m.begin(); e != m.end(); ++e) { element* en(new element("xsd:enumeration")); en->set_attribute("value", e->second); restriction->append(en); } } }; // a wrapper type for basic type serializers template struct wrapped_serializer : public Serializer { typedef typename Serializer::value_type value_type; static void serialize(container* n, const value_type& value) { n->str(Serializer::serialize_value(value)); } static void deserialize(const container* n, value_type& value) { value = Serializer::deserialize_value(n->str()); } static element* schema(const std::string& name) { element* n(new element("xsd:element")); n->set_attribute("name", name); n->set_attribute("type", Serializer::type_name()); n->set_attribute("minOccurs", "1"); n->set_attribute("maxOccurs", "1"); return n; } static void register_type(type_map& types) { } }; // a common base class for many serializer_type classes template struct basic_serializer_type : public Serializer { typedef typename Serializer::value_type value_type; typedef Serializer type_serializer_type; static void serialize_child(container* n, const char* name, const value_type& value) { element* e = new element(name); basic_serializer_type::serialize(e, value); n->append(e); } static void deserialize_child(const container* n, const char* name, value_type& value) { element* e = n->find_first(name); if (e != nullptr) basic_serializer_type::deserialize(e, value); else value = value_type(); } }; // serializer_type, the final interface for doing the actual work, is // a templated class with a default implementation that derives from // basic_serializer_type and a couple of specializations. template struct serializer_type : public basic_serializer_type< typename boost::mpl::if_c< boost::is_arithmetic::value, wrapped_serializer >, typename boost::mpl::if_c< boost::is_enum::value, enum_serializer, struct_serializer_impl >::type >::type> { }; template<> struct serializer_type : public basic_serializer_type > { }; template<> struct serializer_type : public basic_serializer_type > { }; template<> struct serializer_type : public basic_serializer_type > { }; template<> struct serializer_type : public basic_serializer_type > { }; template<> struct serializer_type : public basic_serializer_type > { }; // serializer for STL container types template struct serialize_container_type { typedef C container_type; typedef typename container_type::value_type value_type; typedef serializer_type base_serializer_type; static const char* type_name() { return base_serializer_type::type_name(); } static void serialize_child(container* n, const char* name, const container_type& value) { BOOST_FOREACH (const value_type& v, value) { base_serializer_type::serialize_child(n, name, v); } } static void deserialize_child(const container* n, const char* name, container_type& value) { // clear the value first value.clear(); BOOST_FOREACH (const element* e, *n) { if (e->name() != name) continue; value_type v; base_serializer_type::deserialize(e, v); value.push_back(v); } } static element* schema(const std::string& name) { element* result = base_serializer_type::schema(name); result->remove_attribute("minOccurs"); result->set_attribute("minOccurs", "0"); result->remove_attribute("maxOccurs"); result->set_attribute("maxOccurs", "unbounded"); return result; } static void register_type(type_map& types) { base_serializer_type::register_type(types); } }; template struct serializer_type > : public serialize_container_type > { }; template struct serializer_type > : public serialize_container_type > { }; template struct serializer_type > : public serialize_container_type > { }; template struct serializer_type > { typedef T value_type; typedef serializer_type base_serializer_type; static const char* type_name() { return base_serializer_type::type_name(); } static void serialize_child(container* n, const char* name, const boost::optional& value) { if (value.is_initialized()) base_serializer_type::serialize_child(n, name, value.get()); } static void deserialize_child(const container* n, const char* name, boost::optional& value) { // clear value first value.reset(); element* e = n->find_first(name); if (e != nullptr) { value_type v; base_serializer_type::deserialize_child(n, name, v); value = v; } } static element* schema(const std::string& name) { element* result = base_serializer_type::schema(name); result->remove_attribute("minOccurs"); result->set_attribute("minOccurs", "0"); result->remove_attribute("maxOccurs"); result->set_attribute("maxOccurs", "1"); return result; } static void register_type(type_map& types) { base_serializer_type::register_type(types); } }; // And finally, the implementation of serializer, deserializer and schema_creator. template serializer& serializer::serialize_element(const char* name, const T& value) { typedef typename boost::remove_const::type>::type value_type; typedef serializer_type type_serializer; type_serializer::serialize_child(m_node, name, value); return *this; } template serializer& serializer::serialize_attribute(const char* name, const T& value) { typedef typename boost::remove_const::type>::type value_type; typedef typename serializer_type::type_serializer_type type_serializer; element* e = dynamic_cast(m_node); if (e == nullptr) throw exception("can only create attributes for elements"); e->set_attribute(name, type_serializer::serialize_value(value)); return *this; } template deserializer& deserializer::deserialize_element(const char* name, T& value) { typedef typename boost::remove_const::type>::type value_type; typedef serializer_type type_serializer; type_serializer::deserialize_child(m_node, name, value); return *this; } template deserializer& deserializer::deserialize_attribute(const char* name, T& value) { typedef typename boost::remove_const::type>::type value_type; typedef typename serializer_type::type_serializer_type type_serializer; const element* e = dynamic_cast(m_node); if (e == nullptr) throw exception("can only deserialize attributes for elements"); else { std::string attr = e->get_attribute(name); if (not attr.empty()) value = type_serializer::deserialize_value(attr); } return *this; } template schema_creator& schema_creator::add_element(const char* name, const T& value) { typedef typename boost::remove_const::type>::type value_type; typedef serializer_type type_serializer; m_node->append(type_serializer::schema(name)); std::string type_name = type_serializer::type_name(); // we might be known already if (m_types.find(type_name) == m_types.end()) type_serializer::register_type(m_types); return *this; } template schema_creator& schema_creator::add_attribute(const char* name, const T& value) { typedef typename boost::remove_const::type>::type value_type; typedef serializer_type type_serializer; element* n(new element("xsd:attribute")); std::string type_name = type_serializer::type_name(); n->set_attribute("name", name); n->set_attribute("type", type_name); if (m_types.find(type_name) == m_types.end()) type_serializer::register_type(m_types); assert(m_node->parent() != nullptr); if (m_node->parent() != nullptr) m_node->parent()->append(n); return *this; } #endif } } #endif libzeep-3.0.2/zeep/xml/unicode_support.hpp0000664000175000017500000000547012035764756020533 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2010-2011. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef ZEEP_XML_UNICODE_SUPPORT_HPP #define ZEEP_XML_UNICODE_SUPPORT_HPP #include #include #include namespace zeep { namespace xml { /// We use our own unicode type since wchar_t might be too small. /// This type should be able to contain a UCS4 encoded character. typedef boost::uint32_t unicode; /// the supported encodings. Perhaps we should extend this list a bit? enum encoding_type { enc_UTF8, ///< UTF-8 enc_UTF16BE, ///< UTF-16 Big Endian enc_UTF16LE, ///< UTF 16 Little Endian enc_ISO88591 }; /// some character classification routines bool is_name_start_char(unicode uc); bool is_name_char(unicode uc); bool is_char(unicode uc); bool is_valid_system_literal_char(unicode uc); bool is_valid_system_literal(const std::string& s); bool is_valid_public_id_char(unicode uc); bool is_valid_public_id(const std::string& s); /// Convert a string from UCS4 to UTF-8 std::string wstring_to_string(const std::wstring& s); /// manipulate UTF-8 encoded strings void append(std::string& s, unicode ch); unicode pop_last_char(std::string& s); // inlines inline bool is_char(unicode uc) { return uc == 0x09 or uc == 0x0A or uc == 0x0D or (uc >= 0x020 and uc <= 0x0D7FF) or (uc >= 0x0E000 and uc <= 0x0FFFD) or (uc >= 0x010000 and uc <= 0x010FFFF); } inline void append(std::string& s, unicode uc) { if (uc < 0x080) s += (static_cast(uc)); else if (uc < 0x0800) { char ch[2] = { static_cast(0x0c0 | (uc >> 6)), static_cast(0x080 | (uc & 0x3f)) }; s.append(ch, 2); } else if (uc < 0x00010000) { char ch[3] = { static_cast(0x0e0 | (uc >> 12)), static_cast(0x080 | ((uc >> 6) & 0x3f)), static_cast(0x080 | (uc & 0x3f)) }; s.append(ch, 3); } else { char ch[4] = { static_cast(0x0f0 | (uc >> 18)), static_cast(0x080 | ((uc >> 12) & 0x3f)), static_cast(0x080 | ((uc >> 6) & 0x3f)), static_cast(0x080 | (uc & 0x3f)) }; s.append(ch, 4); } } inline unicode pop_last_char(std::string& s) { unicode result = 0; if (not s.empty()) { std::string::iterator ch = s.end() - 1; if ((*ch & 0x0080) == 0) { result = *ch; s.erase(ch); } else { int o = 0; do { result |= (*ch & 0x03F) << o; o += 6; --ch; } while (ch != s.begin() and (*ch & 0x0C0) == 0x080); switch (o) { case 6: result |= (*ch & 0x01F) << 6; break; case 12: result |= (*ch & 0x00F) << 12; break; case 18: result |= (*ch & 0x007) << 18; break; } s.erase(ch, s.end()); } } return result; } } } #endif libzeep-3.0.2/zeep/xml/doctype.hpp0000664000175000017500000002112511724100061016724 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2010-2011. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef ZEEP_XML_DOCTYPE_HPP #define ZEEP_XML_DOCTYPE_HPP #include #include #include #include #include #include namespace zeep { namespace xml { namespace doctype { // -------------------------------------------------------------------- // doctype support with full validation. class element; class attlist; class entity; class attribute; typedef std::vector entity_list; typedef std::vector element_list; typedef std::vector attribute_list; // -------------------------------------------------------------------- // validation of elements is done by the validator classes struct allowed_base; typedef allowed_base* allowed_ptr; typedef std::list allowed_list; struct state_base; typedef state_base* state_ptr; class validator { public: validator(); validator(allowed_ptr allowed); validator(const validator& other); validator& operator=(const validator& other); ~validator(); void reset(); bool allow(const std::string& name); bool allow_char_data(); bool done(); bool operator()(const std::string& name) { return allow(name); } private: friend std::ostream& operator<<(std::ostream& lhs, validator& rhs); state_ptr m_state; allowed_ptr m_allowed; int m_nr; static int s_next_nr; bool m_done; }; std::ostream& operator<<(std::ostream& lhs, validator& rhs); struct allowed_base { allowed_base() {} virtual ~allowed_base() {} virtual state_ptr create_state() const = 0; virtual bool element_content() const { return false; } virtual void print(std::ostream& os) = 0; }; struct allowed_any : public allowed_base { virtual state_ptr create_state() const; virtual void print(std::ostream& os); }; struct allowed_empty : public allowed_base { virtual state_ptr create_state() const; virtual void print(std::ostream& os); }; struct allowed_element : public allowed_base { allowed_element(const std::string& name) : m_name(name) {} virtual state_ptr create_state() const; virtual bool element_content() const { return true; } virtual void print(std::ostream& os); std::string m_name; }; struct allowed_repeated : public allowed_base { allowed_repeated(allowed_ptr allowed, char repetion) : m_allowed(allowed), m_repetition(repetion) { assert(allowed); } ~allowed_repeated(); virtual state_ptr create_state() const; virtual bool element_content() const; virtual void print(std::ostream& os); allowed_ptr m_allowed; char m_repetition; }; struct allowed_seq : public allowed_base { allowed_seq(allowed_ptr a) { add(a); } ~allowed_seq(); void add(allowed_ptr a); virtual state_ptr create_state() const; virtual bool element_content() const; virtual void print(std::ostream& os); allowed_list m_allowed; }; struct allowed_choice : public allowed_base { allowed_choice(bool mixed) : m_mixed(mixed) {} allowed_choice(allowed_ptr a, bool mixed) : m_mixed(mixed) { add(a); } ~allowed_choice(); void add(allowed_ptr a); virtual state_ptr create_state() const; virtual bool element_content() const; virtual void print(std::ostream& os); allowed_list m_allowed; bool m_mixed; }; // -------------------------------------------------------------------- enum AttributeType { attTypeString, attTypeTokenizedID, attTypeTokenizedIDREF, attTypeTokenizedIDREFS, attTypeTokenizedENTITY, attTypeTokenizedENTITIES, attTypeTokenizedNMTOKEN, attTypeTokenizedNMTOKENS, attTypeNotation, attTypeEnumerated }; enum AttributeDefault { attDefNone, attDefRequired, attDefImplied, attDefFixed, attDefDefault }; class attribute { public: attribute(const std::string& name, AttributeType type) : m_name(name), m_type(type), m_default(attDefNone), m_external(false) {} attribute(const std::string& name, AttributeType type, const std::vector& enums) : m_name(name), m_type(type), m_default(attDefNone) , m_enum(enums), m_external(false) {} const std::string& name() const { return m_name; } bool validate_value(std::string& value, const entity_list& entities) const; void set_default(AttributeDefault def, const std::string& value) { m_default = def; m_default_value = value; } boost::tuple get_default() const { return boost::make_tuple(m_default, m_default_value); } AttributeType get_type() const { return m_type; } AttributeDefault get_default_type() const { return m_default; } const std::vector& get_enums() const { return m_enum; } void external(bool external) { m_external = external; } bool external() const { return m_external; } private: // routines used to check _and_ reformat attribute value strings bool is_name(std::string& s) const; bool is_names(std::string& s) const; bool is_nmtoken(std::string& s) const; bool is_nmtokens(std::string& s) const; bool is_unparsed_entity(const std::string& s, const entity_list& l) const; std::string m_name; AttributeType m_type; AttributeDefault m_default; std::string m_default_value; std::vector m_enum; bool m_external; }; // -------------------------------------------------------------------- class element : boost::noncopyable { public: element(const std::string& name, bool declared, bool external) : m_name(name), m_allowed(nullptr), m_declared(declared), m_external(external) {} ~element(); void add_attribute(attribute* attr); const attribute* get_attribute(const std::string& name) const; const std::string& name() const { return m_name; } const attribute_list& attributes() const { return m_attlist; } void set_allowed(allowed_ptr allowed); void declared(bool declared) { m_declared = declared; } bool declared() const { return m_declared; } void external(bool external) { m_external = external; } bool external() const { return m_external; } bool empty() const; bool element_content() const; validator get_validator() const; private: std::string m_name; attribute_list m_attlist; allowed_ptr m_allowed; bool m_declared, m_external; }; // -------------------------------------------------------------------- class entity : boost::noncopyable { public: const std::string& name() const { return m_name; } const std::string& replacement() const { return m_replacement; } const std::string& path() const { return m_path; } bool parameter() const { return m_parameter; } bool parsed() const { return m_parsed; } void parsed(bool parsed) { m_parsed = parsed; } const std::string& ndata() const { return m_ndata; } void ndata(const std::string& ndata) { m_ndata = ndata; } bool external() const { return m_external; } bool externally_defined() const { return m_externally_defined; } void externally_defined(bool externally_defined) { m_externally_defined = externally_defined; } protected: entity(const std::string& name, const std::string& replacement, bool external, bool parsed) : m_name(name), m_replacement(replacement), m_parameter(false), m_parsed(parsed), m_external(external) , m_externally_defined(false) {} entity(const std::string& name, const std::string& replacement, const std::string& path) : m_name(name), m_replacement(replacement), m_path(path), m_parameter(true), m_parsed(true), m_external(true) , m_externally_defined(false) {} std::string m_name; std::string m_replacement; std::string m_ndata; std::string m_path; bool m_parameter; bool m_parsed; bool m_external; bool m_externally_defined; }; class general_entity : public entity { public: general_entity(const std::string& name, const std::string& replacement, bool external = false, bool parsed = true) : entity(name, replacement, external, parsed) {} }; class parameter_entity : public entity { public: parameter_entity(const std::string& name, const std::string& replacement, const std::string& path) : entity(name, replacement, path) {} }; } } } #endif libzeep-3.0.2/zeep/xml/xpath.hpp0000664000175000017500000000634412050724672016424 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008-2012. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include #include namespace zeep { namespace xml { class document; // -------------------------------------------------------------------- /// XPath's can contain variables. And variables can contain all kinds of data /// like strings, numbers and even node_sets. If you want to use variables, /// you can define a context, add your variables to it and then pass it on /// in the xpath::evaluate method. class context { public: #ifndef LIBZEEP_DOXYGEN_INVOKED context(); virtual ~context(); #endif template void set(const std::string& name, const T& value); template T get(const std::string& name); #ifndef LIBZEEP_DOXYGEN_INVOKED private: context(const context&); context& operator=(const context&); friend class xpath; struct context_imp* m_impl; #endif }; // -------------------------------------------------------------------- /// The actual xpath implementation. It expects an xpath in the constructor and /// this path _must_ be UTF-8 encoded. class xpath { public: xpath(const std::string& path); xpath(const char* path); xpath(const xpath& rhs); xpath& operator=(const xpath&); #ifndef LIBZEEP_DOXYGEN_INVOKED virtual ~xpath(); #endif /// evaluate returns a node_set. If you're only interested in zeep::xml::element /// results, you should call the evaluate() instantiation. template std::list evaluate(const node& root) const; /// The second evaluate method is used for xpaths that contain variables. template std::list evaluate(const node& root, context& ctxt) const; /// Returns true if the \a n node matches the XPath bool matches(const node* n) const; #ifndef LIBZEEP_DOXYGEN_INVOKED private: struct xpath_imp* m_impl; #endif }; #ifndef LIBZEEP_DOXYGEN_INVOKED // -------------------------------------------------------------------- // template specialisations. template void context::set(const std::string& name, const T& value) { // only implemented for the cases specialised below assert(false); } template<> void context::set(const std::string& name, const double& value); template<> void context::set(const std::string& name, const std::string& value); template T context::get(const std::string& name) { // only implemented for the cases specialised below assert(false); } template<> double context::get(const std::string& name); template<> std::string context::get(const std::string& name); // -------------------------------------------------------------------- template<> node_set xpath::evaluate(const node& root) const; template<> element_set xpath::evaluate(const node& root) const; template<> node_set xpath::evaluate(const node& root, context& ctxt) const; template<> element_set xpath::evaluate(const node& root, context& ctxt) const; #endif } } libzeep-3.0.2/zeep/xml/node.hpp0000664000175000017500000006237012125055164016222 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef SOAP_XML_NODE_HPP #define SOAP_XML_NODE_HPP #include #include #include #include #include #include #include namespace zeep { namespace xml { class writer; class node; typedef node* node_ptr; typedef std::list node_set; class element; typedef element* element_ptr; typedef std::list element_set; class root_node; class container; class xpath; #ifndef LIBZEEP_DOXYGEN_INVOKED extern const char kWhiteSpaceChar[]; // a static const char array containing a single space #endif // -------------------------------------------------------------------- /// Node is the abstract base class for all data contained in zeep XML documents. /// The DOM tree consists of nodes that are linked to each other, each /// node can have a parent and siblings pointed to by the next and /// previous members. All nodes in a DOM tree share a common root node. /// /// Nodes can have a name, and the XPath specification requires that a node can /// have a so-called expanded-name. This name consists of a local-name and a /// namespace which is a URI. And we can have a QName which is a concatenation of /// a prefix (that points to a namespace URI) and a local-name separated by a colon. /// /// To reduce storage requirements, names are stored in nodes as qnames, if at all. /// the convenience functions name() and prefix() parse the qname(). ns() returns /// the namespace URI for the node, if it can be resolved. /// /// Nodes inherit the namespace of their parent unless they override it which means /// resolving prefixes and namespaces is done hierarchically class node { public: // All nodes should be part of a single root node virtual root_node* root(); ///< The root node for this node virtual const root_node* root() const; ///< The root node for this node // basic access container* parent() { return m_parent; } ///< The root node for this node const container* parent() const { return m_parent; } ///< The root node for this node node* next() { return m_next; } ///< The next sibling const node* next() const { return m_next; } ///< The next sibling node* prev() { return m_prev; } ///< The previous sibling const node* prev() const { return m_prev; } ///< The previous sibling /// content of a xml:lang attribute of this element, or its nearest ancestor virtual std::string lang() const; /// Nodes can have a name, and the XPath specification requires that a node can /// have a so-called expanded-name. This name consists of a local-name and a /// namespace which is a URI. And we can have a QName which is a concatenation of /// a prefix (that points to a namespace URI) and a local-name separated by a colon. /// /// To reduce storage requirements, names are stored in nodes as qnames, if at all. virtual std::string qname() const; virtual std::string name() const; ///< The name for the node as parsed from the qname. virtual std::string prefix() const; ///< The prefix for the node as parsed from the qname. virtual std::string ns() const; ///< Returns the namespace URI for the node, if it can be resolved. virtual std::string namespace_for_prefix(const std::string& prefix) const; ///< Return the namespace URI for a prefix virtual std::string prefix_for_namespace(const std::string& uri) const; ///< Return the prefix for a namespace URI /// return all content concatenated, including that of children. virtual std::string str() const = 0; /// both attribute and element implement str(const string&), others will throw virtual void str(const std::string& value) { throw exception("cannot set str for this node"); } /// write out the concatenated content to a stream, separated by sep. virtual void write_content(std::ostream& os, const char* sep = kWhiteSpaceChar) const; /// writing out virtual void write(writer& w) const = 0; /// Compare the node with \a n virtual bool equals(const node* n) const; /// Deep clone the node virtual node* clone() const; /// debug routine virtual void validate(); #ifndef LIBZEEP_DOXYGEN_INVOKED protected: friend class container; friend class element; node(); virtual ~node(); virtual void insert_sibling(node* n, node* before); virtual void remove_sibling(node* n); void parent(container* p); void next(node* n); void prev(node* n); private: container* m_parent; node* m_next; node* m_prev; node(const node&); node& operator=(const node&); #endif }; // -------------------------------------------------------------------- /// Container is an abstract base class for nodes that can have multiple children. /// It provides iterators to iterate over children. Most often, you're only interested /// in iteration zeep::xml::element children, that's why zeep::xml::container::iterator /// iterates over only zeep::xml::element nodes, skipping all other nodes. If you want /// to iterate all nodes, use zeep::xml::container::node_iterator instead. /// /// An attempt has been made to make container conform to the STL container interface. class container : public node { public: /// container tries hard to be stl::container-like. ~container(); node* child() { return m_child; } const node* child() const { return m_child; } template std::list children() const; template class basic_iterator : public std::iterator { public: typedef typename std::iterator base_type; typedef typename base_type::reference reference; typedef typename base_type::pointer pointer; basic_iterator() : m_current(nullptr) {} basic_iterator(NodeType* e) : m_current(e) {} basic_iterator(const basic_iterator& other) : m_current(other.m_current) {} basic_iterator& operator=(const basic_iterator& other) { m_current = other.m_current; return *this; } basic_iterator& operator=(const NodeType* n) { m_current = n; return *this; } reference operator*() { return m_current; } pointer operator->() const { return m_current; } basic_iterator& operator++(); basic_iterator operator++(int) { basic_iterator iter(*this); operator++(); return iter; } basic_iterator& operator--(); basic_iterator operator--(int) { basic_iterator iter(*this); operator++(); return iter; } bool operator==(const basic_iterator& other) const { return m_current == other.m_current; } bool operator!=(const basic_iterator& other) const { return m_current != other.m_current; } template bool operator==(const RNodeType n) const { return m_current == n; } template bool operator!=(const RNodeType n) const { return m_current != n; } operator const pointer() const { return m_current; } operator pointer() { return m_current; } private: NodeType* m_current; }; typedef basic_iterator iterator; typedef basic_iterator node_iterator; iterator begin(); iterator end() { return iterator(); } node_iterator node_begin(); node_iterator node_end() { return node_iterator(); } boost::iterator_range nodes() { return boost::iterator_range(node_begin(), node_end()); } typedef basic_iterator const_iterator; typedef basic_iterator const_node_iterator; const_iterator begin() const; const_iterator end() const { return const_iterator(); } const_node_iterator node_begin() const; const_node_iterator node_end() const { return const_node_iterator(); } boost::iterator_range nodes() const { return boost::iterator_range(node_begin(), node_end()); } /// typedef iterator::value_type value_type; typedef iterator::reference reference; typedef iterator::pointer pointer; typedef iterator::difference_type difference_type; typedef unsigned long size_type; // rbegin // rend // size counts only the direct child nodes (not elements!) size_type size() const; size_type max_size() const { return std::numeric_limits::max(); } bool empty() const; node* front() const; node* back() const; template basic_iterator insert(basic_iterator position, NodeType* n); node_iterator insert(node* before, node* n); template void insert(Iterator position, Iterator first, Iterator last); template void erase(Iterator position); template void erase(Iterator first, Iterator last); void swap(container& cnt); void clear(); void push_front(node* n); void pop_front(); void push_back(node* n); void pop_back(); // old names virtual void append(node* n); virtual void remove(node* n); // remove does not delete n // xpath wrappers element_set find(const std::string& path) const { return find(path.c_str()); } element* find_first(const std::string& path) const { return find_first(path.c_str()); } element_set find(const char* path) const; element* find_first(const char* path) const; // xpath wrappers that can return attributes as well as elements: void find(const char* path, node_set& nodes) const; void find(const char* path, element_set& elements) const; node* find_first_node(const char* path) const; // debug routine virtual void validate(); protected: container(); node* m_child; node* m_last; }; // -------------------------------------------------------------------- /// All zeep::xml::document objects have exactly one zeep::xml::root_node member. /// root_node is a container with only one child element. class root_node : public container { public: root_node(); ~root_node(); // All nodes should be part of a single root node virtual root_node* root(); virtual const root_node* root() const; // root nodes have only one child element: element* child_element() const; void child_element(element* e); // string is the concatenation of the string-value of all // descendant text-nodes. virtual std::string str() const; // for adding other nodes, like processing instructions and comments virtual void append(node* n); virtual void write(writer& w) const; virtual bool equals(const node* n) const; }; // -------------------------------------------------------------------- /// A node containing a XML comment class comment : public node { public: comment() {} comment(const std::string& text) : m_text(text) {} virtual std::string str() const { return m_text; } virtual std::string text() const { return m_text; } void text(const std::string& text) { m_text = text; } virtual void write(writer& w) const; virtual bool equals(const node* n) const; virtual node* clone() const; private: std::string m_text; }; // -------------------------------------------------------------------- /// A node containing a XML processing instruction (like e.g. \) class processing_instruction : public node { public: processing_instruction() {} processing_instruction(const std::string& target, const std::string& text) : m_target(target), m_text(text) {} virtual std::string qname() const { return m_target; } virtual std::string str() const { return m_target + ' ' + m_text; } std::string target() const { return m_target; } void target(const std::string& target) { m_target = target; } virtual std::string text() const { return m_text; } void text(const std::string& text) { m_text = text; } virtual void write(writer& w) const; virtual bool equals(const node* n) const; virtual node* clone() const; private: std::string m_target; std::string m_text; }; // -------------------------------------------------------------------- /// A node containing text. class text : public node { public: text() {} text(const std::string& text) : m_text(text) {} virtual std::string str() const { return m_text; } virtual void str(const std::string& text) { m_text = text; } virtual void write_content(std::ostream& os, const char* sep = kWhiteSpaceChar) const { os << m_text; } void append(const std::string& text) { m_text.append(text); } virtual void write(writer& w) const; virtual bool equals(const node* n) const; virtual node* clone() const; protected: std::string m_text; }; // -------------------------------------------------------------------- /// A node containing the contents of a CDATA section. Normally, these nodes are /// converted to text nodes but you can specify to preserve them when parsing a /// document. class cdata : public text { public: cdata() {} cdata(const std::string& s) : text(s) {} virtual void write(writer& w) const; virtual bool equals(const node* n) const; virtual node* clone() const; }; // -------------------------------------------------------------------- /// An attribute is a node, has an element as parent, but is not a child of this parent (!) class attribute : public node { public: attribute(const std::string& qname, const std::string& value, bool id = false) : m_qname(qname), m_value(value), m_id(id) {} std::string qname() const { return m_qname; } std::string value() const { return m_value; } void value(const std::string& v) { m_value = v; } virtual std::string str() const { return m_value; } virtual void str(const std::string& value) { m_value = value; } virtual void write(writer& w) const; virtual bool equals(const node* n) const; virtual node* clone() const; virtual bool id() const { return m_id; } private: std::string m_qname, m_value; bool m_id; }; typedef std::list attribute_set; // -------------------------------------------------------------------- /// Just like an attribute, a name_space node is not a child of an element class name_space : public node { public: name_space(const std::string& prefix, const std::string& uri) : m_prefix(prefix), m_uri(uri) {} virtual std::string qname() const { return m_prefix; } virtual std::string ns() const { return ""; } virtual std::string prefix() const { return m_prefix; } void prefix(const std::string& p) { m_prefix = p; } std::string uri() const { return m_uri; } void uri(const std::string& u) { m_uri = u; } virtual std::string str() const { return uri(); } virtual void write(writer& w) const; virtual bool equals(const node* n) const; virtual node* clone() const; private: std::string m_prefix, m_uri; }; typedef std::list name_space_list; // -------------------------------------------------------------------- /// element is the most important zeep::xml::node object. It encapsulates a /// XML element as found in the XML document. It has a qname, can have children, /// attributes and a namespace. class element : public container { public: element(const std::string& qname); ~element(); virtual void write(writer& w) const; virtual bool equals(const node* n) const; virtual node* clone() const; virtual std::string str() const; virtual void str(const std::string& value) { content(value); } virtual void write_content(std::ostream& os, const char* sep = kWhiteSpaceChar) const; std::string qname() const { return m_qname; } std::string namespace_for_prefix(const std::string& prefix) const; std::string prefix_for_namespace(const std::string& uri) const; std::string content() const; void content(const std::string& content); std::string get_attribute(const std::string& qname) const; attribute* get_attribute_node(const std::string& qname) const; /// the DOCTYPE can specify some attributes as ID void set_attribute(const std::string& qname, const std::string& value, bool id = false); void remove_attribute(const std::string& qname); /// to set the default namespace, pass an empty string as prefix void set_name_space(const std::string& prefix, const std::string& uri); // void remove_name_space(const std::string& uri); /// The add_text method checks if the last added child is a text node, /// and if so, it appends the string to this node's value. Otherwise, /// it adds a new text node child with the new text. void add_text(const std::string& s); /// to iterate over the attribute nodes attribute_set attributes() const; /// to iterate over the namespace nodes name_space_list name_spaces() const; /// content of a xml:lang attribute of this element, or its nearest ancestor virtual std::string lang() const; /// content of the xml:id attribute, or the attribute that was defined to be /// of type ID by the DOCTYPE. std::string id() const; /// as a service to the user, we define an attribute iterator here class attribute_iterator : public std::iterator { public: attribute_iterator() : m_current(nullptr) {} attribute_iterator(attribute* e) : m_current(e) {} attribute_iterator(const attribute_iterator& other) : m_current(other.m_current) {} attribute_iterator& operator=(const attribute_iterator& other) { m_current = other.m_current; return *this; } reference operator*() const { return *m_current; } pointer operator->() const { return m_current; } attribute_iterator& operator++() { m_current = dynamic_cast(m_current->next()); return *this; } attribute_iterator operator++(int) { attribute_iterator iter(*this); operator++(); return iter; } attribute_iterator& operator--() { m_current = dynamic_cast(m_current->prev()); return *this; } attribute_iterator operator--(int) { attribute_iterator iter(*this); operator++(); return iter; } bool operator==(const attribute_iterator& other) const { return m_current == other.m_current; } bool operator!=(const attribute_iterator& other) const { return m_current != other.m_current; } pointer base() const { return m_current; } private: attribute* m_current; }; attribute_iterator attr_begin() { return attribute_iterator(m_attribute); } attribute_iterator attr_end() { return attribute_iterator(); } class const_attribute_iterator : public std::iterator { public: const_attribute_iterator() : m_current(nullptr) {} const_attribute_iterator(attribute* e) : m_current(e) {} const_attribute_iterator(const attribute_iterator& other) : m_current(other.base()) {} const_attribute_iterator(const const_attribute_iterator& other) : m_current(other.m_current) {} const_attribute_iterator& operator=(const const_attribute_iterator& other){ m_current = other.m_current; return *this; } reference operator*() const { return *m_current; } pointer operator->() const { return m_current; } const_attribute_iterator& operator++() { m_current = dynamic_cast(m_current->next()); return *this; } const_attribute_iterator operator++(int) { const_attribute_iterator iter(*this); operator++(); return iter; } const_attribute_iterator& operator--() { m_current = dynamic_cast(m_current->prev()); return *this; } const_attribute_iterator operator--(int) { const_attribute_iterator iter(*this); operator++(); return iter; } bool operator==(const const_attribute_iterator& other) const { return m_current == other.m_current; } bool operator!=(const const_attribute_iterator& other) const { return m_current != other.m_current; } pointer base() const { return m_current; } private: const attribute* m_current; }; const_attribute_iterator attr_begin() const { return const_attribute_iterator(m_attribute); } const_attribute_iterator attr_end() const { return const_attribute_iterator(); } #ifndef LIBZEEP_DOXYGEN_INVOKED protected: void add_name_space(name_space* ns); std::string m_qname; attribute* m_attribute; name_space* m_name_space; #endif }; /// This is probably only useful for debugging purposes std::ostream& operator<<(std::ostream& lhs, const node& rhs); bool operator==(const node& lhs, const node& rhs); /// very often, we want to iterate over child elements of an element /// therefore we have a templated version of children. template<> std::list container::children() const; template<> std::list container::children() const; template<> std::list container::children() const; // iterator inlines, specialised by the two types template<> inline container::basic_iterator& container::basic_iterator::operator++() { if (m_current == nullptr or m_current->next() == nullptr) m_current = nullptr; else { for (node* n = m_current->next(); n != nullptr; n = n->next()) { m_current = dynamic_cast(n); if (m_current != nullptr) break; } } return *this; } template<> inline container::basic_iterator& container::basic_iterator::operator--() { if (m_current == nullptr or m_current->prev() == nullptr) m_current = nullptr; else { for (node* n = m_current->prev(); n != nullptr; n = n->prev()) { m_current = dynamic_cast(n); if (m_current != nullptr) break; } } return *this; } template<> inline container::basic_iterator& container::basic_iterator::operator++() { if (m_current == nullptr or m_current->next() == nullptr) m_current = nullptr; else { for (const node* n = m_current->next(); n != nullptr; n = n->next()) { m_current = dynamic_cast(n); if (m_current != nullptr) break; } } return *this; } template<> inline container::basic_iterator& container::basic_iterator::operator--() { if (m_current == nullptr or m_current->prev() == nullptr) m_current = nullptr; else { for (const node* n = m_current->prev(); n != nullptr; n = n->prev()) { m_current = dynamic_cast(n); if (m_current != nullptr) break; } } return *this; } inline container::iterator container::begin() { element* first = nullptr; for (node* n = m_child; n != nullptr; n = n->next()) { first = dynamic_cast(n); if (first != nullptr) break; } return iterator(first); } inline container::node_iterator container::node_begin() { return node_iterator(m_child); } inline container::const_iterator container::begin() const { const element* first = nullptr; for (const node* n = m_child; n != nullptr; n = n->next()) { first = dynamic_cast(n); if (first != nullptr) break; } return const_iterator(first); } template<> inline container::basic_iterator& container::basic_iterator::operator++() { assert(m_current != nullptr); m_current = m_current->next(); return *this; } template<> inline container::basic_iterator& container::basic_iterator::operator--() { assert(m_current != nullptr); m_current = m_current->prev(); return *this; } template<> inline container::basic_iterator& container::basic_iterator::operator++() { assert(m_current != nullptr); m_current = m_current->next(); return *this; } template<> inline container::basic_iterator& container::basic_iterator::operator--() { assert(m_current != nullptr); m_current = m_current->prev(); return *this; } //inline container::iterator container::begin() //{ // element* first = nullptr; // // for (node* n = m_child; n != nullptr; n = n->next()) // { // first = dynamic_cast(n); // if (first != nullptr) // break; // } // return iterator(first); //} // //inline container::const_iterator container::begin() const //{ // const element* first = nullptr; // // for (const node* n = m_child; n != nullptr; n = n->next()) // { // first = dynamic_cast(n); // if (first != nullptr) // break; // } // return const_iterator(first); //} template container::basic_iterator container::insert(basic_iterator position, NodeType* n) { insert(*position, n); return basic_iterator(n); } template void container::insert(Iterator position, Iterator first, Iterator last) { node* p = *position; for (Iterator i = first; i != last; ++i) { insert(p, *i); p = *i; } } template void container::erase(Iterator position) { node* n = *position; remove(n); delete n; } template void container::erase(Iterator first, Iterator last) { while (first != last) { node* n = *first++; remove(n); delete n; } } } } #endif libzeep-3.0.2/zeep/xml/writer.hpp0000664000175000017500000001001712050724672016604 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef SOAP_XML_WRITER_HPP #define SOAP_XML_WRITER_HPP #include #include namespace zeep { namespace xml { #ifndef LIBZEEP_DOXYGEN_INVOKED extern std::string k_empty_string; #endif //! Use xml::writer to write XML documents to a stream //! The zeep::xml::writer class is used to write XML documents. It has //! several options that influence the way the data is written. E.g. it //! is possible to specify whether to wrap the elements and what indentation //! to use. The writer keeps track of opened elements and therefore knows //! how to close an element. //! //! The writer writes out XML 1.0 files. class writer { public: //! The constructor takes a std::ostream as argument writer(std::ostream& os); writer(std::ostream& os, bool write_decl, bool standalone = false); virtual ~writer(); // behaviour //! set_encoding is not yet implemented, we only support UTF-8 for now // void set_encoding(encoding_type enc) { m_encoding = enc; } //! the xml declaration flag () is the default behaviour void set_collapse_empty_elements(bool collapse) { m_collapse_empty = collapse; } //! escape whitespace into character refences can be specified. void set_escape_whitespace(bool escape) { m_escape_whitespace = escape; } //! do not write out comments void set_no_comment(bool no_comment) { m_no_comment = no_comment; } // actual writing routines //! write a xml declaration, version will be 1.0, standalone can be specified. virtual void xml_decl(bool standalone); //! To write an empty DOCTYPE specifying an external subset virtual void empty_doctype(const std::string& root, const std::string& dtd); //! This opens a DOCTYPE declaration. The root parameter is the name of the base element. virtual void doctype(const std::string& root, const std::string& pubid, const std::string& dtd); virtual void start_doctype(const std::string& root, const std::string& dtd); //! To write a NOTATION declaration virtual void notation(const std::string& name, const std::string& sysid, const std::string& pubid); //! End a DOCTYPE declaration. virtual void end_doctype(); // writing elements virtual void start_element(const std::string& name); virtual void end_element(); virtual void attribute(const std::string& name, const std::string& value); virtual void content(const std::string& content); void element(const std::string& name, const std::string& s) { start_element(name); content(s); end_element(); } virtual void cdata(const std::string& text); virtual void comment(const std::string& text); virtual void processing_instruction(const std::string& target, const std::string& text); protected: std::ostream& m_os; encoding_type m_encoding; float m_version; bool m_write_xml_decl; bool m_wrap; bool m_wrap_prolog; bool m_collapse_empty; bool m_escape_whitespace; bool m_trim; bool m_no_comment; int m_indent; int m_level; bool m_element_open; std::stack m_stack; bool m_wrote_element; bool m_prolog; #ifndef LIBZEEP_DOXYGEN_INVOKED private: writer(const writer&); writer& operator=(const writer&); #endif }; } } #endif libzeep-3.0.2/zeep/dispatcher.hpp0000664000175000017500000003562112126530031016612 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008-2012. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) /// Dispatcher is the class that implements the code to dispatch calls /// based on an incoming SOAP message. This code uses boost::fusion for /// most of its tricks. /// /// The way dispatches works is as follows. The class dispatches has a /// member called m_handlers which is a list of available methods bound /// to a SOAP action. You can add functions to this list by calling /// register_action. This function takes four arguments: /// - The name of the action as it is included in the schema. /// - A pointer to the owning object of the function. /// - The actual function/method. /// - A list of argument names. The number of names in this list /// is specified by the signature of the function and an error /// will be reported if these are not equal. /// /// The dispatcher will create a wrapping handler object for each of /// the registered actions. Each handler object has two main methods. /// One to do the actual call to the method as registered. This one /// uses the zeep::xml::serializer code to collect the values out of /// the SOAP message and passes these using fusion calls to the /// registered method. /// The second method of the handler class is collect which is used /// to collect all the information required to create a complete schema. #ifndef SOAP_DISPATCHER_H #if LIBZEEP_DOXYGEN_INVOKED || ! defined(BOOST_PP_IS_ITERATING) #include #include #include #include #include #include #include #include #include #include #include #include #include namespace zeep { namespace detail { using namespace xml; namespace f = boost::fusion; template struct parameter_deserializer { typedef Iterator result_type; element* m_node; parameter_deserializer(element* node) : m_node(node) {} // due to a change in fusion::accumulate we have to define both functors: template Iterator operator()(Iterator i, T& t) const { xml::deserializer d(m_node); d.deserialize_element(i->c_str(), t); return ++i; } template Iterator operator()(T& t, Iterator i) const { xml::deserializer d(m_node); d.deserialize_element(i->c_str(), t); return ++i; } }; template struct parameter_types { typedef Iterator result_type; type_map& m_types; element* m_node; parameter_types(type_map& types, element* node) : m_types(types), m_node(node) {} template Iterator operator()(Iterator i, T& t) const { xml::schema_creator d(m_types, m_node); d.add_element(i->c_str(), t); return ++i; } template Iterator operator()(T& t, Iterator i) const { xml::schema_creator d(m_types, m_node); d.add_element(i->c_str(), t); return ++i; } }; template struct handler_traits; // first specialization, no input arguments specified template struct handler_traits { typedef void(Class::*Function)(R&); typedef typename f::vector<> argument_type; typedef R response_type; static void invoke(Class* object, Function method, argument_type arguments, response_type& response) { (object->*method)(response); } }; #ifndef LIBZEEP_DOXYGEN_INVOKED // all the other specializations are specified at the bottom of this file #define BOOST_PP_FILENAME_1 #define BOOST_PP_ITERATION_LIMITS (1, 9) #include BOOST_PP_ITERATE() #endif // messages can be used by more than one action, so we need a way to avoid duplicates typedef std::map message_map; struct handler_base { handler_base(const std::string& action) : m_action(action) , m_response(action + "Response") {} virtual ~handler_base() {} virtual element* call(element* in) = 0; virtual void collect(type_map& types, message_map& messages, element* portType, element* binding) = 0; const std::string& get_action_name() const { return m_action; } std::string get_response_name() const { return m_response; } void set_response_name(const std::string& name) { m_response = name; } std::string m_action, m_response; }; template < class Class, typename Function > struct handler : public handler_base { typedef typename handler_traits::argument_type argument_type; typedef typename handler_traits::response_type response_type; enum { name_count = argument_type::size::value + 1 }; typedef const char* names_type[name_count]; handler(const char* action, Class* object, Function method, names_type& names) : handler_base(action) , m_object(object) , m_method(method) { copy(names, names + name_count, m_names.begin()); } virtual element* call(element* in) { // start by collecting all the parameters argument_type args; boost::fusion::accumulate(args, m_names.begin(), parameter_deserializer(in)); // now call the actual server code response_type response; handler_traits::invoke(m_object, m_method, args, response); // and serialize the result back into XML element* result(new element(get_response_name())); serializer sr(result); sr.serialize_element(m_names[name_count - 1].c_str(), response); // that's all, we're done return result; } virtual void collect(type_map& types, message_map& messages, element* portType, element* binding) { // the request type element* requestType(new element("xsd:element")); requestType->set_attribute("name", get_action_name()); types[get_action_name()] = requestType; element* complexType(new element("xsd:complexType")); requestType->append(complexType); element* sequence(new element("xsd:sequence")); complexType->append(sequence); argument_type args; boost::fusion::accumulate(args, m_names.begin(), parameter_types(types, sequence)); // and the response type element* responseType(new element("xsd:element")); responseType->set_attribute("name", get_response_name()); types[get_response_name()] = responseType; complexType = new element("xsd:complexType"); responseType->append(complexType); sequence = new element("xsd:sequence"); complexType->append(sequence); schema_creator wc(types, sequence); response_type response; wc.add_element(m_names[name_count - 1].c_str(), response); // now the wsdl operations element* message = new element("wsdl:message"); message->set_attribute("name", get_action_name() + "RequestMessage"); element* n = new element("wsdl:part"); n->set_attribute("name", "parameters"); n->set_attribute("element", kPrefix + ':' + get_action_name()); message->append(n); messages[message->get_attribute("name")] = message; message = new element("wsdl:message"); message->set_attribute("name", get_response_name() + "Message"); n = new element("wsdl:part"); n->set_attribute("name", "parameters"); n->set_attribute("element", kPrefix + ':' + get_response_name()); message->append(n); messages[message->get_attribute("name")] = message; // port type element* operation(new element("wsdl:operation")); operation->set_attribute("name", get_action_name()); element* input(new element("wsdl:input")); input->set_attribute("message", kPrefix + ':' + get_action_name() + "RequestMessage"); operation->append(input); element* output(new element("wsdl:output")); output->set_attribute("message", kPrefix + ':' + get_response_name() + "Message"); operation->append(output); portType->append(operation); // and the soap operations operation = new element("wsdl:operation"); operation->set_attribute("name", get_action_name()); binding->append(operation); element* soapOperation(new element("soap:operation")); soapOperation->set_attribute("soapAction", ""); soapOperation->set_attribute("style", "document"); operation->append(soapOperation); input = new element("wsdl:input"); operation->append(input); output = new element("wsdl:output"); operation->append(output); element* body(new element("soap:body")); body->set_attribute("use", "literal"); input->append(body); body = new element("soap:body"); body->set_attribute("use", "literal"); output->append(body); } Class* m_object; Function m_method; boost::array m_names; }; } class dispatcher { public: typedef std::vector handler_list; dispatcher(const std::string& ns, const std::string& service) : m_ns(ns) , m_service(service) {} virtual ~dispatcher() { for (handler_list::iterator cb = m_handlers.begin(); cb != m_handlers.end(); ++cb) delete *cb; } template< class Class, typename Function > void register_action(const char* action, Class* server, Function call, typename detail::handler::names_type& arg) { m_handlers.push_back(new detail::handler(action, server, call, arg)); } /// \brief Dispatch a SOAP message and return the result xml::element* dispatch(xml::element* in) { return dispatch(in->name(), in); } /// \brief Dispatch a SOAP message and return the result xml::element* dispatch(const std::string& action, xml::element* in) { // if (in->ns() != m_ns) // throw exception("Invalid request, no match for namespace"); handler_list::iterator cb = std::find_if( m_handlers.begin(), m_handlers.end(), boost::bind(&detail::handler_base::get_action_name, _1) == action); if (cb == m_handlers.end()) throw exception("Action %s is not defined", action.c_str()); xml::element* result = (*cb)->call(in); result->set_name_space("", m_ns); return result; } /// \brief Create a WSDL based on the registered actions xml::element* make_wsdl(const std::string& address) { // start by making the root node: wsdl:definitions xml::element* wsdl(new xml::element("wsdl:definitions")); wsdl->set_attribute("targetNamespace", m_ns); wsdl->set_name_space("wsdl", "http://schemas.xmlsoap.org/wsdl/"); wsdl->set_name_space(xml::kPrefix, m_ns); wsdl->set_name_space("soap", "http://schemas.xmlsoap.org/wsdl/soap/"); // add wsdl:types xml::element* types(new xml::element("wsdl:types")); wsdl->append(types); // add xsd:schema xml::element* schema(new xml::element("xsd:schema")); schema->set_attribute("targetNamespace", m_ns); schema->set_name_space("xsd", "http://www.w3.org/2001/XMLSchema"); schema->set_attribute("elementFormDefault", "qualified"); schema->set_attribute("attributeFormDefault", "unqualified"); types->append(schema); // add wsdl:binding xml::element* binding(new xml::element("wsdl:binding")); binding->set_attribute("name", m_service); binding->set_attribute("type", xml::kPrefix + ':' + m_service + "PortType"); // add soap:binding xml::element* soapBinding(new xml::element("soap:binding")); soapBinding->set_attribute("style", "document"); soapBinding->set_attribute("transport", "http://schemas.xmlsoap.org/soap/http"); binding->append(soapBinding); // add wsdl:portType xml::element* portType(new xml::element("wsdl:portType")); portType->set_attribute("name", m_service + "PortType"); // and the types xml::type_map typeMap; detail::message_map messageMap; for (handler_list::iterator cb = m_handlers.begin(); cb != m_handlers.end(); ++cb) (*cb)->collect(typeMap, messageMap, portType, binding); for (detail::message_map::iterator m = messageMap.begin(); m != messageMap.end(); ++m) wsdl->append(m->second); for (xml::type_map::iterator t = typeMap.begin(); t != typeMap.end(); ++t) schema->append(t->second); wsdl->append(portType); wsdl->append(binding); // finish with the wsdl:service xml::element* service(new xml::element("wsdl:service")); service->set_attribute("name", m_service); wsdl->append(service); xml::element* port(new xml::element("wsdl:port")); port->set_attribute("name", m_service); port->set_attribute("binding", xml::kPrefix + ':' + m_service); service->append(port); xml::element* soapAddress(new xml::element("soap:address")); soapAddress->set_attribute("location", address); port->append(soapAddress); return wsdl; } void set_response_name(const std::string& action, const std::string& name) { handler_list::iterator cb = std::find_if( m_handlers.begin(), m_handlers.end(), boost::bind(&detail::handler_base::get_action_name, _1) == action); if (cb == m_handlers.end()) throw exception("Action %s is not defined", action.c_str()); (*cb)->set_response_name(name); } std::string m_ns; std::string m_service; handler_list m_handlers; }; } #ifndef LIBZEEP_DOXYGEN_INVOKED #define SOAP_DISPATCHER_H #endif #else // BOOST_PP_IS_ITERATING // // Specializations for the handler_traits for a range of parameters // #define N BOOST_PP_ITERATION() template struct handler_traits { typedef void(Class::*Function)(BOOST_PP_ENUM_PARAMS(N,T), R&); #define M(z,j,data) typedef typename boost::remove_const::type>::type t_ ## j; BOOST_PP_REPEAT(N,M,~) #undef M typedef typename f::vector argument_type; typedef R response_type; #define M(z,j,data) f::at_c(arguments) static void invoke(Class* object, Function method, argument_type arguments, response_type& response) { (object->*method)(BOOST_PP_ENUM(N,M,~), response); } #undef M }; #endif #endif libzeep-3.0.2/zeep/server.hpp0000664000175000017500000000336011750236762016005 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008-2012. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef SOAP_SERVER_HPP #define SOAP_SERVER_HPP #include #include #include #include #include namespace zeep { /// zeep::server inherits from zeep::http::server and zeep::dispatcher to do its work. /// You construct a new server object by passing in a namespace in the \a ns parameter and /// a service name in the \a service parameter. /// /// If the server is behind a proxy, you'll also need to call set_location to specify the /// external address of your server. class server : public dispatcher , public http::server { public: /// The constructor takes two arguments /// \param ns The namespace as used for the WSDL and SOAP messages /// \param service The service name for this server server(const std::string& ns, const std::string& service); /// \brief Calls zeep::http::server and sets m_location if it wasn't already specified virtual void bind(const std::string& address, unsigned short port); /// If your server is located behind a reverse proxy, you'll have to specify the address /// where it can be found by clients. If you don't, the WSDL will contain an unreachable /// address. /// \param location The URL that specifies the external address of this server. void set_location(const std::string& location) { m_location = location; } protected: virtual void handle_request(const http::request& req, http::reply& rep); private: std::string m_location; }; } #endif libzeep-3.0.2/find-req.xml0000664000175000017500000000132311110247511015227 0ustar maartenmaarten sprot aap noot Dice true 0 15 libzeep-3.0.2/makefile0000664000175000017500000001173412162310310014503 0ustar maartenmaarten# Makefile for libzeep and a test/sample application using libzeep. # # Copyright Maarten L. Hekkelman, UMC St. Radboud 2008-2013. # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) # # You may have to edit the first three defines on top of this # makefile to match your current installation. #BOOST_LIB_SUFFIX = # e.g. '-mt' #BOOST = $(HOME)/projects/boost BOOST_LIB_DIR = $(BOOST:%=%/lib) BOOST_INC_DIR = $(BOOST:%=%/include) PREFIX ?= /usr/local LIBDIR ?= $(PREFIX)/lib INCDIR ?= $(PREFIX)/include MANDIR ?= $(PREFIX)/man/man3 DOCDIR ?= $(PREFIX)/share/libzeep BOOST_LIBS = system thread filesystem regex math_c99 BOOST_LIBS := $(BOOST_LIBS:%=boost_%$(BOOST_LIB_SUFFIX)) LIBS = $(BOOST_LIBS) stdc++ m pthread LDFLAGS += $(BOOST_LIB_DIR:%=-L%) $(LIBS:%=-l%) -g VERSION_MAJOR = 3.0 VERSION_MINOR = 2 VERSION = $(VERSION_MAJOR).$(VERSION_MINOR) DIST_NAME = libzeep-$(VERSION) SO_NAME = libzeep.so.$(VERSION_MAJOR) LIB_NAME = $(SO_NAME).$(VERSION_MINOR) CXX ?= c++ CFLAGS += -O2 $(BOOST_INC_DIR:%=-I%) -I. -fPIC -pthread -shared -std=c++0x #CFLAGS += -g $(BOOST_INC_DIR:%=-I%) -I. -fPIC -pthread -shared # -std=c++0x CFLAGS += -Wall CFLAGS += -g LD ?= ld VPATH += src OBJECTS = \ obj/doctype.o \ obj/document.o \ obj/exception.o \ obj/node.o \ obj/soap-envelope.o \ obj/parser.o \ obj/request.o \ obj/request_parser.o \ obj/reply.o \ obj/connection.o \ obj/http-server.o \ obj/preforked-http-server.o \ obj/soap-server.o \ obj/unicode_support.o \ obj/webapp.o \ obj/webapp-el.o \ obj/xpath.o \ obj/writer.o lib: libzeep.a # libzeep.so libzeep.a: $(OBJECTS) ld -r -o $@ $(OBJECTS) $(LIB_NAME): $(OBJECTS) $(CXX) -shared -o $@ -Wl,-soname=$(SO_NAME) $(LDFLAGS) $(OBJECTS) $(SO_NAME): $(LIB_NAME) ln -fs $(LIB_NAME) $@ libzeep.so: $(SO_NAME) ln -fs $(LIB_NAME) $@ # assuming zeep-test is build when install was not done already zeep-test: zeep-test.cpp libzeep.a $(CXX) $(BOOST_INC_DIR:%=-I%) -o $@ -I. zeep-test.cpp libzeep.a $(LDFLAGS) -lboost_date_time -lboost_regex install-libs: libzeep.so install -d $(LIBDIR) install $(LIB_NAME) $(LIBDIR)/$(LIB_NAME) ln -Tfs $(LIB_NAME) $(LIBDIR)/$(SO_NAME) strip --strip-unneeded $(LIBDIR)/$(LIB_NAME) install-dev: install -d $(MANDIR) $(LIBDIR) $(INCDIR)/zeep/xml $(INCDIR)/zeep/http $(INCDIR)/zeep/http/webapp install zeep/http/connection.hpp $(INCDIR)/zeep/http/connection.hpp install zeep/http/header.hpp $(INCDIR)/zeep/http/header.hpp install zeep/http/preforked-server.hpp $(INCDIR)/zeep/http/preforked-server.hpp install zeep/http/reply.hpp $(INCDIR)/zeep/http/reply.hpp install zeep/http/request.hpp $(INCDIR)/zeep/http/request.hpp install zeep/http/request_handler.hpp $(INCDIR)/zeep/http/request_handler.hpp install zeep/http/request_parser.hpp $(INCDIR)/zeep/http/request_parser.hpp install zeep/http/server.hpp $(INCDIR)/zeep/http/server.hpp install zeep/http/webapp.hpp $(INCDIR)/zeep/http/webapp.hpp install zeep/http/webapp/el.hpp $(INCDIR)/zeep/http/webapp/el.hpp install zeep/xml/doctype.hpp $(INCDIR)/zeep/xml/doctype.hpp install zeep/xml/document.hpp $(INCDIR)/zeep/xml/document.hpp install zeep/xml/node.hpp $(INCDIR)/zeep/xml/node.hpp install zeep/xml/parser.hpp $(INCDIR)/zeep/xml/parser.hpp install zeep/xml/serialize.hpp $(INCDIR)/zeep/xml/serialize.hpp install zeep/xml/unicode_support.hpp $(INCDIR)/zeep/xml/unicode_support.hpp install zeep/xml/writer.hpp $(INCDIR)/zeep/xml/writer.hpp install zeep/xml/xpath.hpp $(INCDIR)/zeep/xml/xpath.hpp install zeep/config.hpp $(INCDIR)/zeep/config.hpp install zeep/dispatcher.hpp $(INCDIR)/zeep/dispatcher.hpp install zeep/envelope.hpp $(INCDIR)/zeep/envelope.hpp install zeep/exception.hpp $(INCDIR)/zeep/exception.hpp install zeep/server.hpp $(INCDIR)/zeep/server.hpp install doc/libzeep.3 $(MANDIR)/libzeep.3 for d in . images libzeep zeep zeep/http zeep/http/preforked_server_base zeep/http/el \ zeep/http/el/object zeep/xml zeep/xml/doctype zeep/xml/container zeep/xml/element \ index; do install -d $(DOCDIR)/$$d; install doc/html/$$d/*.* $(DOCDIR)/$$d; done; install ./libzeep.a $(LIBDIR)/libzeep.a strip -SX $(LIBDIR)/libzeep.a ln -Tfs $(LIB_NAME) $(LIBDIR)/libzeep.so install: install-libs install-dev dist: lib rm -rf $(DIST_NAME) svn export . $(DIST_NAME) find doc/html | grep -v '.svn' | cpio -pvd $(DIST_NAME) rm -rf $(DIST_NAME)/tests tar czf $(DIST_NAME).tgz $(DIST_NAME) rm -rf $(DIST_NAME) cp $(DIST_NAME).tgz ../ppa/libzeep_$(VERSION).orig.tar.gz obj/%.o: %.cpp | obj $(CXX) -MD -c -o $@ $< $(CFLAGS) obj: mkdir -p obj include $(OBJECTS:%.o=%.d) $(OBJECTS:.o=.d): test: libzeep.a make -C tests clean: rm -rf obj/* libzeep.a libzeep.so* zeep-test $(DIST_NAME) $(DIST_NAME).tgz libzeep-3.0.2/changelog0000664000175000017500000000656012162310310014656 0ustar maartenmaartenVersion 3.0.2 - Change in zeep/xml/serialize.hpp for gcc 4.7 compiler Version 3.0.1 - added cast to uint32 in webapp-el to allow compilation on s390 Version 3.0 - Support for non-intrusive serialization. The call to serialize is now done by the templated struct zeep::xml::struct_serializer. You can create a specialization for this struct to do something else than calling MyClass::serialize. - xml::document now has serialize and deserialize members. - A streaming input added, process_document_elements calls the callback for all elements that match a given xpath. - ISO8859-1 support (finally) - some xpath additions (matches e.g.) - changed signature of various find routines to work with const char* - changed authentication mechanism in webapp to allow multiple realms - some small changes in writing out XML documents/xml::writer - added line number to validation error messages - process value tag of mrs:option tag - el processing returns original string if it does not contain an expression - in expression language, support var1[var2] constructs - fix in writing doctype declaration - insert/erase implementations of zeep::xml::node... - fixed bug in el implementation (dividing numbers) - extended log format of HTTP server to allow better awstat logs (using the extra fields for SOAP calls). Also writes the X-Forwarded-For client if any. - Patches provided by Patrick Rotsaert: serializer for xsd:time and optional data types based on boost::optional. - Split out log_request as a virtual method in http::server - Added quick and dirty test for requests from mobile clients - Added virtual destructors to all base classes. - OPTIONS and HEAD support in web server Version 2.9.0 - Added some calls to xml::writer to write e.g. xml-decl and doctypes Version 2.8.2 - Fix in unicode support code - Preliminary support for handling authentication Version 2.8.1 - removed boost::ptr_vector/ptr_list. - work around a crashing bug in el::object[string] when compiling with icpc Version 2.8.0 - write_content added. - nullptr instead of nil, added a stub for old compilers. - fix in el::object (mixing up uint64 and size_t) Version 2.6.3 - Fix for stack overflow in delete large XML documents Version 2.6.2 - Apparently the word size has changed on amd64/GNUC targets. I've switched to a more robust template selection algorithm for WSDL generation. Version 2.6.1 - Fix in keep-alive (clear reply object after each served reply) - Implemented missing at() virtual method for el::vector - Writing comments now validates output - check mounted paths instead of only the root for handlers - optimization flags in makefile Version 2.6.0 - Changed parameter_map (for webapp) into a multimap Version 2.5.2 - Throw exception when attempting to write null character. Version 2.5.1 - Removed the use of split_iterator from webapp since it generated crashes when built as a shared library... Version 2.5.0 - added webapp, a base class used to create web applications, it uses XHTML templates to fill in. It uses a script language to enable interaction with the C++ code. Version 2.1.0 - support for HTTP/1.1 - added multiplication in xpath expression language... oops - revised interface for container::iterator, now it is possible to use more STL and boost functions on a container directly, like: xml::container cnt = ...; foreach (node* n, cnt) { cout << n->name() << endl; } libzeep-3.0.2/src/0000775000175000017500000000000012162310454013575 5ustar maartenmaartenlibzeep-3.0.2/src/doctype.cpp0000664000175000017500000004254512125635713015771 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2010-2011. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #define _SCL_SECURE_NO_WARNINGS #include #include #include #include #include #include #include #define foreach BOOST_FOREACH #include #include #include #include #include using namespace std; using namespace tr1; namespace ba = boost::algorithm; namespace zeep { namespace xml { namespace doctype { // -------------------------------------------------------------------- // validator code // a refcounted state base class struct state_base : boost::enable_shared_from_this { state_base() : m_ref_count(1) {} virtual tr1::tuple allow(const string& name) = 0; virtual bool allow_char_data() { return false; } virtual bool allow_empty() { return false; } virtual void reset() {} void reference() { ++m_ref_count; } void release() { if (--m_ref_count == 0) delete this; } protected: virtual ~state_base() { assert(m_ref_count == 0); } private: int m_ref_count; }; struct state_any : public state_base { virtual tr1::tuple allow(const string& name) { return tr1::make_tuple(true, true); } virtual bool allow_char_data() { return true; } virtual bool allow_empty() { return true; } }; struct state_empty : public state_base { virtual tr1::tuple allow(const string& name) { return tr1::make_tuple(false, true); } virtual bool allow_empty() { return true; } }; struct state_element : public state_base { state_element(const string& name) : m_name(name), m_done(false) {} virtual tr1::tuple allow(const string& name) { bool result = false; if (not m_done and m_name == name) m_done = result = true; // m_done = true; return tr1::make_tuple(result, m_done); } virtual void reset() { m_done = false; } string m_name; bool m_done; }; struct state_repeated : public state_base { state_repeated(allowed_ptr sub) : m_sub(sub->create_state()), m_state(0) {} ~state_repeated() { m_sub->release(); } virtual void reset() { m_sub->reset(); m_state = 0; } virtual bool allow_char_data() { return m_sub->allow_char_data(); } state_ptr m_sub; int m_state; }; // repeat for ? struct state_repeated_zero_or_once : public state_repeated { state_repeated_zero_or_once(allowed_ptr sub) : state_repeated(sub) {} tr1::tuple allow(const string& name); virtual bool allow_empty() { return true; } }; tr1::tuple state_repeated_zero_or_once::allow(const string& name) { // use a state machine enum State { state_Start = 0, state_Loop }; bool result = false, done = false; switch (m_state) { case state_Start: tie(result, done) = m_sub->allow(name); if (result == true) m_state = state_Loop; else done = true; break; case state_Loop: tie(result, done) = m_sub->allow(name); if (result == false and done) done = true; break; } return tr1::make_tuple(result, done); } struct state_repeated_any : public state_repeated { state_repeated_any(allowed_ptr sub) : state_repeated(sub) {} tr1::tuple allow(const string& name); virtual bool allow_empty() { return true; } }; tr1::tuple state_repeated_any::allow(const string& name) { // use a state machine enum State { state_Start = 0, state_Loop }; bool result = false, done = false; switch (m_state) { case state_Start: tie(result, done) = m_sub->allow(name); if (result == true) m_state = state_Loop; else done = true; break; case state_Loop: tie(result, done) = m_sub->allow(name); if (result == false and done) { m_sub->reset(); tie(result, done) = m_sub->allow(name); if (result == false) done = true; } break; } return tr1::make_tuple(result, done); } struct state_repeated_at_least_once : public state_repeated { state_repeated_at_least_once(allowed_ptr sub) : state_repeated(sub) {} tr1::tuple allow(const string& name); virtual bool allow_empty() { return m_sub->allow_empty(); } }; tr1::tuple state_repeated_at_least_once::allow(const string& name) { // use a state machine enum State { state_Start = 0, state_FirstLoop, state_NextLoop }; bool result = false, done = false; switch (m_state) { case state_Start: tie(result, done) = m_sub->allow(name); if (result == true) m_state = state_FirstLoop; break; case state_FirstLoop: tie(result, done) = m_sub->allow(name); if (result == false and done) { m_sub->reset(); tie(result, done) = m_sub->allow(name); if (result == true) m_state = state_NextLoop; } break; case state_NextLoop: tie(result, done) = m_sub->allow(name); if (result == false and done) { m_sub->reset(); tie(result, done) = m_sub->allow(name); if (result == false) done = true; } break; } return tr1::make_tuple(result, done); } // allow a sequence struct state_seq : public state_base { state_seq(const allowed_list& allowed) : m_state(0) { foreach (allowed_ptr a, allowed) m_states.push_back(a->create_state()); } ~state_seq() { foreach (state_ptr s, m_states) s->release(); } virtual tr1::tuple allow(const string& name); virtual void reset() { m_state = 0; for_each(m_states.begin(), m_states.end(), boost::bind(&state_base::reset, _1)); } virtual bool allow_char_data() { bool result = false; foreach (state_ptr s, m_states) { if (s->allow_char_data()) { result = true; break; } } return result; } virtual bool allow_empty(); list m_states; list::iterator m_next; int m_state; }; tr1::tuple state_seq::allow(const string& name) { bool result = false, done = false; enum State { state_Start, state_Element }; switch (m_state) { case state_Start: m_next = m_states.begin(); if (m_next == m_states.end()) { done = true; break; } m_state = state_Element; // fall through case state_Element: tie(result, done) = (*m_next)->allow(name); while (result == false and done) { ++m_next; if (m_next == m_states.end()) { done = true; break; } tie(result, done) = (*m_next)->allow(name); } break; } return tr1::make_tuple(result, done); } bool state_seq::allow_empty() { bool result; if (m_states.empty()) result = true; else { result = accumulate(m_states.begin(), m_states.end(), true, boost::bind(&state_base::allow_empty, _2) and _1); } return result; } // allow one of a list struct state_choice : public state_base { state_choice(const allowed_list& allowed, bool mixed) : m_mixed(mixed) , m_state(0) { foreach (allowed_ptr a, allowed) m_states.push_back(a->create_state()); } ~state_choice() { foreach (state_ptr s, m_states) s->release(); } virtual tr1::tuple allow(const string& name); virtual void reset() { m_state = 0; for_each(m_states.begin(), m_states.end(), boost::bind(&state_base::reset, _1)); } virtual bool allow_char_data() { return m_mixed; } virtual bool allow_empty(); list m_states; bool m_mixed; int m_state; state_ptr m_sub; }; tr1::tuple state_choice::allow(const string& name) { bool result = false, done = false; enum State { state_Start, state_Choice }; switch (m_state) { case state_Start: for (list::iterator choice = m_states.begin(); choice != m_states.end(); ++choice) { tie(result, done) = (*choice)->allow(name); if (result == true) { m_sub = *choice; m_state = state_Choice; break; } } break; case state_Choice: tie(result, done) = m_sub->allow(name); break; } return tr1::make_tuple(result, done); } bool state_choice::allow_empty() { return m_mixed or find_if(m_states.begin(), m_states.end(), boost::bind(&state_base::allow_empty, _1)) != m_states.end(); } // -------------------------------------------------------------------- int validator::s_next_nr = 1; validator::validator() : m_state(new state_any()) , m_nr(0) , m_done(false) { } validator::validator(allowed_ptr allowed) : m_state(allowed->create_state()) , m_allowed(allowed) , m_nr(s_next_nr++) , m_done(m_state->allow_empty()) { } validator::validator(const validator& other) : m_state(other.m_state) , m_allowed(other.m_allowed) , m_nr(other.m_nr) , m_done(other.m_done) { m_state->reference(); } validator::~validator() { m_state->release(); } validator& validator::operator=(const validator& other) { if (&other != this) { m_nr = other.m_nr; if (m_state != other.m_state) { m_state->release(); m_state = other.m_state; m_state->reference(); } m_allowed = other.m_allowed; m_done = other.m_done; } return *this; } void validator::reset() { m_done = false; m_state->reset(); } bool validator::allow(const string& name) { bool result; tie(result, m_done) = m_state->allow(name); return result; } bool validator::allow_char_data() { return m_state->allow_char_data(); } bool validator::done() { return m_done; } std::ostream& operator<<(std::ostream& lhs, validator& rhs) { lhs << " +++ " << rhs.m_nr << " == "; if (rhs.m_allowed) rhs.m_allowed->print(lhs); return lhs; } // -------------------------------------------------------------------- state_ptr allowed_any::create_state() const { return new state_any(); } void allowed_any::print(ostream& os) { os << "ANY"; } // -------------------------------------------------------------------- state_ptr allowed_empty::create_state() const { return new state_empty(); } void allowed_empty::print(ostream& os) { os << "EMPTY"; } // -------------------------------------------------------------------- state_ptr allowed_element::create_state() const { return new state_element(m_name); } void allowed_element::print(ostream& os) { os << m_name; } // -------------------------------------------------------------------- allowed_repeated::~allowed_repeated() { delete m_allowed; } state_ptr allowed_repeated::create_state() const { switch (m_repetition) { case '?': return new state_repeated_zero_or_once(m_allowed); case '*': return new state_repeated_any(m_allowed); case '+': return new state_repeated_at_least_once(m_allowed); default: assert(false); throw zeep::exception("illegal repetition character"); } } void allowed_repeated::print(ostream& os) { m_allowed->print(os); os << m_repetition; } bool allowed_repeated::element_content() const { return m_allowed->element_content(); } // -------------------------------------------------------------------- allowed_seq::~allowed_seq() { foreach (allowed_ptr a, m_allowed) delete a; } void allowed_seq::add(allowed_ptr a) { m_allowed.push_back(a); } state_ptr allowed_seq::create_state() const { return new state_seq(m_allowed); } void allowed_seq::print(ostream& os) { os << '('; for (allowed_list::iterator s = m_allowed.begin(); s != m_allowed.end(); ++s) { (*s)->print(os); if (boost::next(s) != m_allowed.end()) os << ", "; } os << ')'; } bool allowed_seq::element_content() const { bool result = true; foreach (allowed_ptr a, m_allowed) { if (not a->element_content()) { result = false; break; } } return result; } // -------------------------------------------------------------------- allowed_choice::~allowed_choice() { foreach (allowed_ptr a, m_allowed) delete a; } void allowed_choice::add(allowed_ptr a) { m_allowed.push_back(a); } state_ptr allowed_choice::create_state() const { return new state_choice(m_allowed, m_mixed); } void allowed_choice::print(ostream& os) { os << '('; if (m_mixed) { os << "#PCDATA"; if (not m_allowed.empty()) os << "|"; } for (allowed_list::iterator s = m_allowed.begin(); s != m_allowed.end(); ++s) { (*s)->print(os); if (boost::next(s) != m_allowed.end()) os << "|"; } os << ')'; } bool allowed_choice::element_content() const { bool result = true; if (m_mixed) result = false; else { foreach (allowed_ptr a, m_allowed) { if (not a->element_content()) { result = false; break; } } } return result; } // -------------------------------------------------------------------- bool attribute::is_name(string& s) const { bool result = true; ba::trim(s); if (not s.empty()) { string::iterator c = s.begin(); if (c != s.end()) result = is_name_start_char(*c); while (result and ++c != s.end()) result = is_name_char(*c); } return result; } bool attribute::is_names(string& s) const { bool result = true; ba::trim(s); if (not s.empty()) { string::iterator c = s.begin(); string t; while (result and c != s.end()) { result = is_name_start_char(*c); t += *c; ++c; while (result and c != s.end() and is_name_char(*c)) { t += *c; ++c; } if (c == s.end()) break; result = isspace(*c) != 0; ++c; t += ' '; while (c != s.end() and isspace(*c)) ++c; } swap(s, t); } return result; } bool attribute::is_nmtoken(string& s) const { ba::trim(s); bool result = not s.empty(); string::iterator c = s.begin(); while (result and ++c != s.end()) result = is_name_char(*c); return result; } bool attribute::is_nmtokens(string& s) const { // remove leading and trailing spaces ba::trim(s); bool result = not s.empty(); string::iterator c = s.begin(); string t; while (result and c != s.end()) { result = false; do { if (not is_name_char(*c)) break; result = true; t += *c; ++c; } while (c != s.end()); if (not result or c == s.end()) break; result = false; do { if (not isspace((unsigned char)*c)) break; result = true; ++c; } while (c != s.end() and isspace((unsigned char)*c)); t += ' '; } if (result) swap(s, t); return result; } bool attribute::validate_value(string& value, const entity_list& entities) const { bool result = true; if (m_type == attTypeString) result = true; else if (m_type == attTypeTokenizedENTITY) { result = is_name(value); if (result) result = is_unparsed_entity(value, entities); } else if (m_type == attTypeTokenizedID or m_type == attTypeTokenizedIDREF) result = is_name(value); else if (m_type == attTypeTokenizedENTITIES) { result = is_names(value); if (result) { vector values; ba::split(values, value, ba::is_any_of(" ")); foreach (const string& v, values) { if (not is_unparsed_entity(v, entities)) { result = false; break; } } } } else if (m_type == attTypeTokenizedIDREFS) result = is_names(value); else if (m_type == attTypeTokenizedNMTOKEN) result = is_nmtoken(value); else if (m_type == attTypeTokenizedNMTOKENS) result = is_nmtokens(value); else if (m_type == attTypeEnumerated or m_type == attTypeNotation) { ba::trim(value); result = find(m_enum.begin(), m_enum.end(), value) != m_enum.end(); } if (result and m_default == attDefFixed and value != m_default_value) result = false; return result; } bool attribute::is_unparsed_entity(const string& s, const entity_list& l) const { bool result = false; entity_list::const_iterator i = find_if(l.begin(), l.end(), boost::bind(&entity::name, _1) == s); if (i != l.end()) result = (*i)->parsed() == false; return result; } // -------------------------------------------------------------------- element::~element() { foreach (attribute* attr, m_attlist) delete attr; delete m_allowed; } void element::set_allowed(allowed_ptr allowed) { if (allowed != m_allowed) { delete m_allowed; m_allowed = allowed; } } void element::add_attribute(attribute* attrib) { unique_ptr attr(attrib); if (find_if(m_attlist.begin(), m_attlist.end(), boost::bind(&attribute::name, _1) == attr->name()) == m_attlist.end()) m_attlist.push_back(attr.release()); } const attribute* element::get_attribute(const string& name) const { attribute_list::const_iterator dta = find_if(m_attlist.begin(), m_attlist.end(), boost::bind(&attribute::name, _1) == name); const attribute* result = nullptr; if (dta != m_attlist.end()) result = *dta; return result; } validator element::get_validator() const { validator valid; if (m_allowed) valid = validator(m_allowed); return valid; } bool element::empty() const { return dynamic_cast(m_allowed) != nullptr; } bool element::element_content() const { return m_allowed != nullptr and m_allowed->element_content(); } } } } libzeep-3.0.2/src/connection.cpp0000664000175000017500000000556211623215120016443 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include #include #include #include #include using namespace std; namespace zeep { namespace http { connection::connection(boost::asio::io_service& service, request_handler& handler) : m_socket(service) , m_request_handler(handler) { } void connection::start() { m_request = request(); // reset m_request.local_address = boost::lexical_cast(m_socket.local_endpoint().address()); m_request.local_port = m_socket.local_endpoint().port(); m_socket.async_read_some(boost::asio::buffer(m_buffer), boost::bind(&connection::handle_read, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } void connection::handle_read( const boost::system::error_code& ec, size_t bytes_transferred) { if (not ec) { boost::tribool result = m_request_parser.parse( m_request, m_buffer.data(), bytes_transferred); if (result) { m_reply.set_version(m_request.http_version_major, m_request.http_version_minor); m_request_handler.handle_request(m_socket, m_request, m_reply); vector buffers; m_reply.to_buffers(buffers); boost::asio::async_write(m_socket, buffers, boost::bind(&connection::handle_write, shared_from_this(), boost::asio::placeholders::error)); } else if (not result) { m_reply = reply::stock_reply(bad_request); vector buffers; m_reply.to_buffers(buffers); boost::asio::async_write(m_socket, buffers, boost::bind(&connection::handle_write, shared_from_this(), boost::asio::placeholders::error)); } else { m_socket.async_read_some(boost::asio::buffer(m_buffer), boost::bind(&connection::handle_read, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } } } void connection::handle_write(const boost::system::error_code& ec) { if (not ec) { vector buffers; if (m_reply.data_to_buffers(buffers)) { boost::asio::async_write(m_socket, buffers, boost::bind(&connection::handle_write, shared_from_this(), boost::asio::placeholders::error)); } else if (m_request.http_version_minor >= 1 and not m_request.close) { m_request_parser.reset(); m_request = request(); m_reply = reply(); m_socket.async_read_some(boost::asio::buffer(m_buffer), boost::bind(&connection::handle_read, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } else m_socket.close(); } } } } libzeep-3.0.2/src/node.cpp0000664000175000017500000005637412126525621015251 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include #include #include #include #include #define foreach BOOST_FOREACH #include #include #include #include #include #include #define nullptr NULL using namespace std; namespace ba = boost::algorithm; namespace zeep { namespace xml { const char kWhiteSpaceChar[] = " "; // -------------------------------------------------------------------- node::node() : m_parent(nullptr) , m_next(nullptr) , m_prev(nullptr) { } node::~node() { // avoid deep recursion and stack overflows while (m_next != nullptr) { node* n = m_next; m_next = n->m_next; n->m_next = nullptr; delete n; } } root_node* node::root() { root_node* result = nullptr; if (m_parent != nullptr) result = m_parent->root(); return result; } const root_node* node::root() const { const root_node* result = nullptr; if (m_parent != nullptr) result = m_parent->root(); return result; } bool node::equals(const node* n) const { bool result = typeid(this) == typeid(n); if (result) { if (m_next != nullptr and n->m_next != nullptr) result = m_next->equals(n->m_next); else result = (m_next == nullptr and n->m_next == nullptr); } return result; } node* node::clone() const { assert(false); throw zeep::exception("cannot clone this"); return nullptr; } string node::lang() const { string result; if (m_parent != nullptr) result = m_parent->lang(); return result; } void node::insert_sibling(node* n, node* before) { //#if DEBUG //validate(); //n->validate(); //if (before) before->validate(); //#endif node* p = this; while (p->m_next != nullptr and p->m_next != before) p = p->m_next; if (p->m_next != before and before != nullptr) throw zeep::exception("before argument in insert_sibling is not valid"); p->m_next = n; n->m_prev = p; n->m_parent = m_parent; n->m_next = before; if (before != nullptr) before->m_prev = n; //#if DEBUG //validate(); //n->validate(); //if (before) before->validate(); //#endif } void node::remove_sibling(node* n) { //#if DEBUG //validate(); //n->validate(); //#endif assert (this != n); if (this == n) throw exception("inconsistent node tree"); node* p = this; while (p != nullptr and p->m_next != n) p = p->m_next; if (p != nullptr and p->m_next == n) { p->m_next = n->m_next; if (p->m_next != nullptr) p->m_next->m_prev = p; n->m_next = n->m_prev = n->m_parent = nullptr; } else throw exception("remove for a node not found in the list"); //#if DEBUG //validate(); //n->validate(); //#endif } void node::parent(container* n) { assert(m_parent == nullptr); m_parent = n; } string node::qname() const { return ""; } string node::name() const { string qn = qname(); string::size_type s = qn.find(':'); if (s != string::npos) qn.erase(0, s + 1); return qn; } string node::prefix() const { string qn = qname(); string::size_type s = qn.find(':'); string p; if (s != string::npos) p = qn.substr(0, s); return p; } string node::ns() const { string result, p = prefix(); result = namespace_for_prefix(p); return result; } string node::namespace_for_prefix(const string& prefix) const { string result; if (m_parent != nullptr) result = m_parent->namespace_for_prefix(prefix); return result; } string node::prefix_for_namespace(const string& uri) const { string result; if (m_parent != nullptr) result = m_parent->prefix_for_namespace(uri); return result; } void node::write_content(ostream& os, const char* sep) const { // do nothing } void node::validate() { if (m_parent and dynamic_cast(this) != nullptr and (find(m_parent->node_begin(), m_parent->node_end(), this) == m_parent->node_end())) throw exception("validation error: parent does not know node"); if (m_next and m_next->m_prev != this) throw exception("validation error: m_next->m_prev != this"); if (m_prev and m_prev->m_next != this) throw exception("validation error: m_prev->m_next != this"); node* n = this; while (n != nullptr and n->m_next != this) n = n->m_next; if (n == this) throw exception("cycle in node list"); n = this; while (n != nullptr and n->m_prev != this) n = n->m_prev; if (n == this) throw exception("cycle in node list"); if (m_next) m_next->validate(); } // -------------------------------------------------------------------- // container_node container::container() : m_child(nullptr) , m_last(nullptr) { } container::~container() { delete m_child; } template<> node_set container::children() const { node_set result; node* child = m_child; while (child != nullptr) { result.push_back(child); child = child->next(); } return result; } template<> element_set container::children() const { element_set result; node* child = m_child; while (child != nullptr) { if (typeid(*child) == typeid(element)) result.push_back(static_cast(child)); child = child->next(); } return result; } void container::append(node_ptr n) { //#if DEBUG //validate(); //n->validate(); //#endif if (n != nullptr) { if (n->m_parent != nullptr) throw exception("attempt to append node that has already a parent"); if (n == nullptr) throw exception("attempt to append nullptr node"); if (m_child == nullptr) { m_last = m_child = n; m_child->m_next = m_child->m_prev = nullptr; n->parent(this); } else { m_last->insert_sibling(n, nullptr); m_last = n; } } //#if DEBUG //validate(); //n->validate(); //#endif } void container::remove(node_ptr n) { //#if DEBUG //validate(); //n->validate(); //#endif if (n != nullptr) { if (n->m_parent != this) throw exception("attempt to remove node whose parent is invalid"); if (m_child == n) { m_child = m_child->m_next; if (m_child != nullptr) m_child->m_prev = nullptr; else m_last = nullptr; n->m_next = n->m_prev = n->m_parent = nullptr; } else { if (m_last == n) m_last = n->m_prev; m_child->remove_sibling(n); } } //#if DEBUG //validate(); //n->validate(); //#endif } //element_set container::find(const xpath& path) const //{ // return path.evaluate(*this); //} // //element* container::find_first(const xpath& path) const //{ // element_set s = path.evaluate(*this); // // element* result = nullptr; // if (not s.empty()) // result = s.front(); // return result; //} element_set container::find(const char* path) const { return xpath(path).evaluate(*this); } element* container::find_first(const char* path) const { element_set s = xpath(path).evaluate(*this); element* result = nullptr; if (not s.empty()) result = s.front(); return result; } void container::find(const char* path, node_set& nodes) const { nodes = xpath(path).evaluate(*this); } void container::find(const char* path, element_set& elements) const { elements = xpath(path).evaluate(*this); } node* container::find_first_node(const char* path) const { node_set s = xpath(path).evaluate(*this); node* result = nullptr; if (not s.empty()) result = s.front(); return result; } container::size_type container::size() const { size_type result = 0; for (node* n = m_child; n != m_last; n = n->m_next) ++result; return result; } bool container::empty() const { return m_child == nullptr; } node* container::front() const { return m_child; } node* container::back() const { return m_last; } void container::swap(container& cnt) { std::swap(m_child, cnt.m_child); std::swap(m_last, cnt.m_last); for (node* n = m_child; n != m_last; n = n->m_next) n->m_parent = this; for (node* n = cnt.m_child; n != cnt.m_last; n = n->m_next) n->m_parent = &cnt; } void container::clear() { delete m_child; m_child = m_last = nullptr; } void container::push_front(node* n) { //#if DEBUG //validate(); //n->validate(); //#endif if (n == nullptr) throw exception("attempt to insert nullptr node"); if (n->m_next != nullptr or n->m_prev != nullptr) throw exception("attempt to insert a node that has next or prev"); if (n->m_parent != nullptr) throw exception("attempt to insert node that already has a parent"); n->parent(this); n->m_next = m_child; if (m_child != nullptr) m_child->m_prev = n; m_child = n; if (m_last == nullptr) m_last = m_child; //#if DEBUG //validate(); //n->validate(); //#endif } void container::pop_front() { //#if DEBUG //validate(); //#endif if (m_child != nullptr) { node* n = m_child; m_child = m_child->m_next; if (m_child != nullptr) m_child->m_prev = nullptr; if (n == m_last) m_last = nullptr; n->m_next = nullptr; delete n; } //#if DEBUG //validate(); //#endif } void container::push_back(node* n) { //#if DEBUG //validate(); //n->validate(); //#endif if (n == nullptr) throw exception("attempt to insert nullptr node"); if (n->m_next != nullptr or n->m_prev != nullptr) throw exception("attempt to insert a node that has next or prev"); if (n->m_parent != nullptr) throw exception("attempt to insert node that already has a parent"); if (m_child == nullptr) { m_last = m_child = n; m_child->m_next = m_child->m_prev = nullptr; n->parent(this); } else { m_last->insert_sibling(n, nullptr); m_last = n; } //#if DEBUG //validate(); //n->validate(); //#endif } void container::pop_back() { //#if DEBUG //validate(); //#endif if (m_last != nullptr) { if (m_last == m_child) { delete m_child; m_child = m_last = nullptr; } else { node* n = m_last; m_last = m_last->m_prev; m_last->m_next = nullptr; n->m_prev = nullptr; delete n; } } //#if DEBUG //validate(); //#endif } container::node_iterator container::insert(node* position, node* n) { if (n == nullptr) throw exception("attempt to insert nullptr node"); if (position and position->m_parent != this) throw exception("position has another parent"); if (n->m_next != nullptr or n->m_prev != nullptr) throw exception("attempt to insert a node that has next or prev"); if (n->m_parent != nullptr) throw exception("attempt to insert node that already has a parent"); //#if DEBUG //validate(); //n->validate(); // position->validate(); //#endif if (m_child == nullptr) { if (position != nullptr) throw exception("invalid position for empty container"); m_child = n; m_child->m_next = m_child->m_prev = nullptr; n->parent(this); } else if (m_child == position) // n becomes the first in the list { n->parent(this); n->m_next = m_child; m_child->m_prev = n; m_child = n; m_child->m_prev = nullptr; } else m_child->insert_sibling(n, position); if (m_last == nullptr) m_last = m_child; //#if DEBUG //validate(); //n->validate(); //#endif return node_iterator(n); } void container::validate() { //#if DEBUG // node::validate(); //#endif if (m_child or m_last) { if (m_child == nullptr or m_last == nullptr) throw exception("m_child/m_last error"); if (std::find(node_begin(), node_end(), m_child) == node_end()) throw exception("cannot find m_child in this"); if (std::find(node_begin(), node_end(), m_last) == node_end()) throw exception("cannot find m_last in this"); if (m_child->m_prev != nullptr) throw exception("m_child is not first in list"); if (m_last->m_next != nullptr) throw exception("m_last is not last in list"); //#if DEBUG // m_child->validate(); //#endif } } // -------------------------------------------------------------------- // root_node root_node::root_node() { } root_node::~root_node() { } root_node* root_node::root() { return this; } const root_node* root_node::root() const { return this; } string root_node::str() const { string result; element* e = child_element(); if (e != nullptr) result = e->str(); return result; } element* root_node::child_element() const { element* result = nullptr; node* n = m_child; while (n != nullptr and result == nullptr) { result = dynamic_cast(n); n = n->next(); } return result; } void root_node::child_element(element* child) { element* e = child_element(); if (e != nullptr) { container::remove(e); delete e; } if (child != nullptr) container::append(child); } void root_node::write(writer& w) const { node* child = m_child; while (child != nullptr) { child->write(w); child = child->next(); } } bool root_node::equals(const node* n) const { bool result = false; if (typeid(n) == typeid(*this)) { result = true; const root_node* e = static_cast(n); if (m_child != nullptr and e->m_child != nullptr) result = m_child->equals(e->m_child); else result = m_child == nullptr and e->m_child == nullptr; } return result; } void root_node::append(node* n) { if (dynamic_cast(n) != nullptr and child_element() == nullptr) child_element(static_cast(n)); else if (dynamic_cast(n) == nullptr and dynamic_cast(n) == nullptr) { throw exception("can only append comment and processing instruction nodes to a root_node"); } else container::append(n); } // -------------------------------------------------------------------- // comment void comment::write(writer& w) const { w.comment(m_text); } bool comment::equals(const node* n) const { return node::equals(n) and dynamic_cast(n) != nullptr and m_text == static_cast(n)->m_text; } node* comment::clone() const { return new comment(m_text); } // -------------------------------------------------------------------- // processing_instruction void processing_instruction::write(writer& w) const { w.processing_instruction(m_target, m_text); } bool processing_instruction::equals(const node* n) const { return node::equals(n) and dynamic_cast(n) != nullptr and m_text == static_cast(n)->m_text; } node* processing_instruction::clone() const { return new processing_instruction(m_target, m_target); } // -------------------------------------------------------------------- // text void text::write(writer& w) const { w.content(m_text); } bool text::equals(const node* n) const { return node::equals(n) and dynamic_cast(n) != NULL and m_text == static_cast(n)->m_text; } node* text::clone() const { return new text(m_text); } // -------------------------------------------------------------------- // cdata void cdata::write(writer& w) const { w.cdata(m_text); } bool cdata::equals(const node* n) const { return node::equals(n) and dynamic_cast(n) != NULL and m_text == static_cast(n)->m_text; } node* cdata::clone() const { return new cdata(m_text); } // -------------------------------------------------------------------- // attribute void attribute::write(writer& w) const { assert(false); } bool attribute::equals(const node* n) const { bool result = false; if (node::equals(n)) { const attribute* a = static_cast(n); result = m_qname == a->m_qname and m_value == a->m_value; } return result; } node* attribute::clone() const { return new attribute(m_qname, m_value, m_id); } // -------------------------------------------------------------------- // name_space void name_space::write(writer& w) const { assert(false); } bool name_space::equals(const node* n) const { bool result = false; if (node::equals(n)) { const name_space* ns = static_cast(n); result = m_prefix == ns->m_prefix and m_uri == ns->m_uri; } return result; } node* name_space::clone() const { return new name_space(m_prefix, m_uri); } // -------------------------------------------------------------------- // element element::element(const std::string& qname) : m_qname(qname) , m_attribute(nullptr) , m_name_space(nullptr) { } element::~element() { delete m_attribute; delete m_name_space; } string element::str() const { string result; const node* child = m_child; while (child != nullptr) { result += child->str(); child = child->next(); } return result; } string element::content() const { string result; const node* child = m_child; while (child != nullptr) { if (dynamic_cast(child) != nullptr) result += child->str(); child = child->next(); } return result; } void element::content(const string& s) { node* child = m_child; // remove all existing text nodes (including cdata ones) while (child != nullptr) { node* next = child->next(); if (dynamic_cast(child) != nullptr) { container::remove(child); delete child; } child = next; } // and add a new text node with the content append(new text(s)); } void element::add_text(const std::string& s) { text* textNode = dynamic_cast(m_last); if (textNode != nullptr and dynamic_cast(textNode) == nullptr) textNode->append(s); else append(new text(s)); } attribute_set element::attributes() const { attribute_set result; node* attr = m_attribute; while (attr != nullptr) { result.push_back(static_cast(attr)); attr = attr->next(); } return result; } name_space_list element::name_spaces() const { name_space_list result; node* ns = m_name_space; while (ns != nullptr) { result.push_back(static_cast(ns)); ns = ns->next(); } return result; } string element::get_attribute(const string& qname) const { string result; for (attribute* attr = m_attribute; attr != nullptr; attr = static_cast(attr->next())) { if (attr->qname() == qname) { result = attr->value(); break; } } return result; } attribute* element::get_attribute_node(const string& qname) const { attribute* attr = m_attribute; while (attr != nullptr) { if (attr->qname() == qname) break; attr = static_cast(attr->next()); } return attr; } void element::set_attribute(const string& qname, const string& value, bool id) { attribute* attr = get_attribute_node(qname); if (attr != nullptr) attr->value(value); else { attr = new attribute(qname, value, id); if (m_attribute == nullptr) { m_attribute = attr; m_attribute->parent(this); } else m_attribute->insert_sibling(attr, nullptr); } } void element::remove_attribute(const string& qname) { attribute* n = get_attribute_node(qname); if (n != nullptr) { assert(n->m_parent == this); if (m_attribute == n) { m_attribute = static_cast(m_attribute->m_next); if (m_attribute != nullptr) m_attribute->m_prev = nullptr; } else m_attribute->remove_sibling(n); } } string element::namespace_for_prefix(const string& prefix) const { string result; for (name_space* ns = m_name_space; ns != nullptr; ns = static_cast(ns->next())) { if (ns->prefix() == prefix) { result = ns->uri(); break; } } if (result.empty() and dynamic_cast(m_parent) != nullptr) result = static_cast(m_parent)->namespace_for_prefix(prefix); return result; } string element::prefix_for_namespace(const string& uri) const { string result; for (name_space* ns = m_name_space; ns != nullptr; ns = static_cast(ns->next())) { if (ns->uri() == uri) { result = ns->prefix(); break; } } if (result.empty() and dynamic_cast(m_parent) != nullptr) result = static_cast(m_parent)->prefix_for_namespace(uri); return result; } void element::set_name_space(const string& prefix, const string& uri) { name_space* ns; for (ns = m_name_space; ns != nullptr; ns = static_cast(ns->next())) { if (ns->prefix() == prefix) { ns->uri(uri); break; } } if (ns == nullptr) add_name_space(new name_space(prefix, uri)); } void element::add_name_space(name_space* ns) { if (m_name_space == nullptr) { m_name_space = ns; m_name_space->parent(this); } else m_name_space->insert_sibling(ns, nullptr); } string element::lang() const { string result = get_attribute("xml:lang"); if (result.empty()) result = node::lang(); return result; } string element::id() const { string result; attribute* attr = m_attribute; while (attr != nullptr) { if (attr->id()) { result = attr->value(); break; } attr = static_cast(attr->next()); } return result; } void element::write_content(ostream& os, const char* sep) const { node* child = m_child; while (child != nullptr) { child->write_content(os, sep); child = child->next(); if (sep != nullptr) os << sep; } } void element::write(writer& w) const { w.start_element(m_qname); attribute* attr = m_attribute; while (attr != nullptr) { w.attribute(attr->qname(), attr->value()); attr = static_cast(attr->next()); } name_space* ns = m_name_space; while (ns != nullptr) { if (ns->prefix().empty()) w.attribute("xmlns", ns->uri()); else w.attribute(string("xmlns:") + ns->prefix(), ns->uri()); ns = static_cast(ns->next()); } node* child = m_child; while (child != nullptr) { child->write(w); child = child->next(); } w.end_element(); } bool element::equals(const node* n) const { bool result = false; if (node::equals(n) and m_qname == static_cast(n)->m_qname) { result = true; const element* e = static_cast(n); if (m_child != nullptr and e->m_child != nullptr) result = m_child->equals(e->m_child); else result = m_child == nullptr and e->m_child == nullptr; if (result and m_attribute != nullptr and e->m_attribute != nullptr) result = m_attribute->equals(e->m_attribute); else result = m_attribute == nullptr and e->m_attribute == nullptr; if (result and m_name_space != nullptr and e->m_name_space != nullptr) result = m_name_space->equals(e->m_name_space); else result = m_name_space == nullptr and e->m_name_space == nullptr; } return result; } node* element::clone() const { element* result = new element(m_qname); attribute* attr = m_attribute; while (attr != nullptr) { result->set_attribute(attr->qname(), attr->value(), attr->id()); attr = static_cast(attr->next()); } name_space* ns = m_name_space; while (ns != nullptr) { result->add_name_space(static_cast(ns->clone())); ns = static_cast(ns->next()); } node* child = m_child; while (child != nullptr) { result->push_back(child->clone()); child = child->next(); } return result; } // -------------------------------------------------------------------- // operator<< ostream& operator<<(ostream& lhs, const node& rhs) { if (typeid(rhs) == typeid(node)) cout << "base class???"; else if (typeid(rhs) == typeid(root_node)) cout << "root_node"; else if (typeid(rhs) == typeid(element)) { cout << "element <" << static_cast(rhs).qname(); const element* e = static_cast(&rhs); foreach (const attribute* attr, e->attributes()) cout << ' ' << attr->qname() << "=\"" << attr->value() << '"'; cout << '>'; } else if (typeid(rhs) == typeid(comment)) cout << "comment"; else if (typeid(rhs) == typeid(processing_instruction)) cout << "processing_instruction"; else cout << typeid(rhs).name(); return lhs; } } // xml } // zeep libzeep-3.0.2/src/document-libxml2.cpp0000664000175000017500000001527312125635713017505 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2010-2011. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include #include #include #include #include #include #include #include #include #include #include #include #define foreach BOOST_FOREACH #include "document-imp.hpp" #include #include #include #include #include using namespace std; namespace ba = boost::algorithm; namespace fs = boost::filesystem; namespace zeep { namespace xml { // -------------------------------------------------------------------- struct libxml2_doc_imp : public document_imp { libxml2_doc_imp(document* doc); void ProcessNode( xmlTextReaderPtr reader); void StartElementHandler( xmlTextReaderPtr reader); void EndElementHandler( xmlTextReaderPtr reader); void CharacterDataHandler( xmlTextReaderPtr reader); void ProcessingInstructionHandler( xmlTextReaderPtr reader); void CommentHandler( xmlTextReaderPtr reader); static void ErrorHandler( void* arg, const char* msg, xmlParserSeverities severity, xmlTextReaderLocatorPtr locator); virtual void parse( istream& data); int m_depth; }; // -------------------------------------------------------------------- libxml2_doc_imp::libxml2_doc_imp(document* doc) : document_imp(doc) , m_depth(0) { } void libxml2_doc_imp::StartElementHandler( xmlTextReaderPtr inReader) { const char* qname = (const char*)xmlTextReaderConstName(inReader); if (qname == nullptr) throw exception("nullptr qname"); unique_ptr n(new element(qname)); if (m_cur == nullptr) m_root.child_element(n.get()); else m_cur->append(n.get()); m_cur = n.release(); unsigned int count = xmlTextReaderAttributeCount(inReader); for (unsigned int i = 0; i < count; ++i) { xmlTextReaderMoveToAttributeNo(inReader, i); m_cur->set_attribute( (const char*)xmlTextReaderConstName(inReader), (const char*)xmlTextReaderConstValue(inReader)); } const string name_prefix("xmlns:"); for (vector >::iterator ns = m_namespaces.begin(); ns != m_namespaces.end(); ++ns) m_cur->set_name_space(ns->first, ns->second); m_namespaces.clear(); if (xmlTextReaderIsEmptyElement(inReader)) EndElementHandler(inReader); else ++m_depth; } void libxml2_doc_imp::EndElementHandler( xmlTextReaderPtr inReader) { // if (m_cur == nullptr) // throw exception("Empty stack"); // // m_cur = dynamic_cast(m_cur->parent()); // --m_depth; if (m_cur != nullptr) { m_cur = dynamic_cast(m_cur->parent()); --m_depth; } } void libxml2_doc_imp::CharacterDataHandler( xmlTextReaderPtr inReader) { while (m_depth > 0 and m_depth != xmlTextReaderDepth(inReader)) { m_cur = dynamic_cast(m_cur->parent()); --m_depth; } if (m_cur == nullptr) throw exception("Empty stack"); m_cur->add_text((const char*)xmlTextReaderConstValue(inReader)); } void libxml2_doc_imp::ProcessingInstructionHandler( xmlTextReaderPtr inReader) { const char* target = (const char*)xmlTextReaderConstName(inReader); const char* data = (const char*)xmlTextReaderConstValue(inReader); if (m_cur != nullptr) m_cur->append(new processing_instruction(target, data)); else m_root.append(new processing_instruction(target, data)); } void libxml2_doc_imp::CommentHandler( xmlTextReaderPtr inReader) { const char* data = (const char*)xmlTextReaderConstValue(inReader); if (m_cur != nullptr) m_cur->append(new comment(data)); else m_root.append(new comment(data)); } void libxml2_doc_imp::ProcessNode( xmlTextReaderPtr reader) { switch (xmlTextReaderNodeType(reader)) { case XML_READER_TYPE_ELEMENT: StartElementHandler(reader); break; case XML_READER_TYPE_END_ELEMENT: EndElementHandler(reader); break; case XML_READER_TYPE_WHITESPACE: case XML_READER_TYPE_SIGNIFICANT_WHITESPACE: case XML_READER_TYPE_TEXT: case XML_READER_TYPE_CDATA: CharacterDataHandler(reader); break; case XML_READER_TYPE_PROCESSING_INSTRUCTION: ProcessingInstructionHandler(reader); break; case XML_READER_TYPE_COMMENT: // CommentHandler(reader); break; case XML_READER_TYPE_DOCUMENT: // cout << "document" << endl; break; case XML_READER_TYPE_DOCUMENT_TYPE: if (m_validating) xmlTextReaderSetParserProp(reader, XML_PARSER_VALIDATE, 1); break; case XML_READER_TYPE_DOCUMENT_FRAGMENT: // cout << "document fragment" << endl; break; case XML_READER_TYPE_NOTATION: cout << "notation" << endl; break; case XML_READER_TYPE_END_ENTITY: cout << "end entity" << endl; break; case XML_READER_TYPE_XML_DECLARATION: cout << "xml decl" << endl; break; } } void libxml2_doc_imp::ErrorHandler( void* arg, const char* msg, xmlParserSeverities severity, xmlTextReaderLocatorPtr locator) { throw invalid_exception(msg); } // -------------------------------------------------------------------- void libxml2_doc_imp::parse( istream& data) { // get length of file: data.seekg(0, ios::end); size_t length = data.tellg(); data.seekg(0, ios::beg); // allocate memory: vector buffer(length); // read data as a block: data.read(&buffer[0], length); bool valid = true; xmlTextReaderPtr reader = xmlReaderForMemory(&buffer[0], length, (fs::current_path().string() + "/").c_str(), nullptr, XML_PARSE_NOENT | XML_PARSE_DTDLOAD | XML_PARSE_DTDATTR | XML_PARSE_XINCLUDE); if (reader != nullptr) { xmlTextReaderSetErrorHandler(reader, &libxml2_doc_imp::ErrorHandler, this); try { int ret = xmlTextReaderRead(reader); while (ret == 1) { ProcessNode(reader); ret = xmlTextReaderRead(reader); } } catch (...) { xmlFreeTextReader(reader); throw; } if (xmlTextReaderIsValid(reader) != 1) valid = false; xmlFreeTextReader(reader); } if (m_validating and not valid) throw invalid_exception("document is not valid"); } // -------------------------------------------------------------------- libxml2_document::libxml2_document() : document(new libxml2_doc_imp(this)) { } libxml2_document::libxml2_document(const string& s) : document(new libxml2_doc_imp(this)) { istringstream is(s); read(is); } libxml2_document::libxml2_document(istream& is) : document(new libxml2_doc_imp(this)) { read(is); } } } libzeep-3.0.2/src/soap-envelope.cpp0000664000175000017500000000304011701066027017055 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include #include using namespace std; namespace zeep { envelope::envelope() : m_request(nullptr) { } envelope::envelope(xml::document& data) : m_request(nullptr) { const xml::xpath sRequestPath("/Envelope[namespace-uri()='http://schemas.xmlsoap.org/soap/envelope/']/Body[position()=1]/*[position()=1]"); list l = sRequestPath.evaluate(*data.root()); if (l.empty()) throw zeep::exception("Empty or invalid SOAP envelope passed"); m_request = l.front(); } xml::element* make_envelope(xml::element* data) { xml::element* env(new xml::element("env:Envelope")); env->set_name_space("env", "http://schemas.xmlsoap.org/soap/envelope/"); xml::element* body(new xml::element("env:Body")); env->append(body); body->append(data); return env; } xml::element* make_fault(const string& what) { xml::element* fault(new xml::element("env:Fault")); xml::element* faultCode(new xml::element("faultcode")); faultCode->content("env:Server"); fault->append(faultCode); xml::element* faultString(new xml::element("faultstring")); faultString->content(what); fault->append(faultString); return make_envelope(fault); } xml::element* make_fault(const std::exception& ex) { return make_fault(string(ex.what())); } } libzeep-3.0.2/src/webapp-el.cpp0000664000175000017500000011033312153035146016160 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008-2011. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // webapp::el is a set of classes used to implement an 'expression language' // A script language used in the XHTML templates used by the zeep webapp. // #include #include #include #define foreach BOOST_FOREACH #include #include #include #include #include using namespace std; namespace ba = boost::algorithm; namespace zeep { namespace http { namespace el { #define ZEEP_DEFINE_AS_INT(T) \ template<> T object::as() const \ { \ T result = 0; \ \ if (m_impl) \ result = static_cast(m_impl->to_int()); \ \ return result; \ } ZEEP_DEFINE_AS_INT(int8) ZEEP_DEFINE_AS_INT(uint8) ZEEP_DEFINE_AS_INT(int16) ZEEP_DEFINE_AS_INT(uint16) ZEEP_DEFINE_AS_INT(int32) ZEEP_DEFINE_AS_INT(uint32) ZEEP_DEFINE_AS_INT(int64) ZEEP_DEFINE_AS_INT(uint64) namespace detail { int64 object_impl::to_int() const { throw exception("cannot convert to requested type"); } double object_impl::to_double() const { throw exception("cannot convert to requested type"); } string object_impl::to_str() const { throw exception("cannot convert to requested type"); } string object_impl::to_JSON() const { throw exception("cannot convert to JSON string"); } object& base_array_object_impl::at(uint32 ix) { throw exception("method 'at' not implemented"); } const object base_array_object_impl::at(uint32 ix) const { throw exception("method 'at' not implemented"); } } class int_object_impl : public detail::object_impl { public: int_object_impl(int64 v) : detail::object_impl(object::number_type) , m_v(v) {} virtual void print(ostream& os) const { os << m_v; } virtual int compare(object_impl* rhs) const; virtual int64 to_int() const { return m_v; } virtual double to_double() const { return static_cast(m_v); } virtual string to_str() const { return boost::lexical_cast(m_v); } virtual string to_JSON() const { return boost::lexical_cast(m_v); } int64 m_v; }; class bool_object_impl : public int_object_impl { public: bool_object_impl(bool v) : int_object_impl(object::number_type) {} virtual void print(ostream& os) const { os << (m_v ? "true" : "false"); } virtual string to_str() const { return m_v ? "true" : "false"; } virtual string to_JSON() const { return m_v ? "true" : "false"; } }; class float_object_impl : public detail::object_impl { public: float_object_impl(double v) : detail::object_impl(object::number_type) , m_v(v) {} virtual void print(ostream& os) const { os << m_v; } virtual int compare(object_impl* rhs) const; virtual int64 to_int() const { return static_cast(tr1::round(m_v)); } virtual double to_double() const { return m_v; } virtual string to_str() const { return boost::lexical_cast(m_v); } virtual string to_JSON() const { return boost::lexical_cast(m_v); } double m_v; }; class string_object_impl : public detail::object_impl { public: string_object_impl(const string& v) : detail::object_impl(object::string_type) , m_v(v) {} virtual void print(ostream& os) const { os << '"' << m_v << '"'; } virtual int compare(object_impl* rhs) const; virtual int64 to_int() const { return boost::lexical_cast(m_v); } virtual double to_double() const { return boost::lexical_cast(m_v); } virtual string to_str() const { return m_v; } virtual string to_JSON() const { stringstream s; s << '"'; foreach (char ch, m_v) { switch (ch) { case '"': s << "\\\""; break; case '\\': s << "\\\\"; break; case '/': s << "\\/"; break; case 010: s << "\\b"; break; case '\t': s << "\\t"; break; case '\n': s << "\\n"; break; case 014: s << "\\f"; break; case '\r': s << "\\r"; break; default: { if ((unsigned int)(ch) < 040) s << "\\u" << hex << setfill('0') << setw(4) << int(ch); else s << ch; } } } s << '"'; return s.str(); } string m_v; }; class vector_object_iterator_impl : public detail::object_iterator_impl { public: vector_object_iterator_impl(vector::const_iterator i) : m_i(i) {} virtual void increment() { ++m_i; } virtual object& dereference() { return const_cast(*m_i); } virtual bool equal(const object_iterator_impl* other) { const vector_object_iterator_impl* rhs = dynamic_cast(other); if (rhs == nullptr) throw exception("comparing unequal iterators"); return rhs->m_i == m_i; } private: vector::const_iterator m_i; }; class vector_object_impl : public detail::base_array_object_impl { public: vector_object_impl(const vector& v) : m_v(v) {} vector_object_impl(const vector& v) { foreach (const string& s, v) m_v.push_back(object(s)); } virtual object& at(uint32 ix) { return m_v[ix]; } virtual const object at(uint32 ix) const { return m_v[ix]; } virtual object& operator[](const object& index) { return m_v[index.as()]; } virtual const object operator[](const object& index) const { return m_v[index.as()]; } virtual void print(ostream& os) const { os << '['; bool first = true; foreach (const object& o, m_v) { if (not first) os << ','; first = false; os << o; } os << ']'; } virtual int compare(object_impl* rhs) const; virtual size_t count() const { return m_v.size(); } virtual detail::object_iterator_impl* create_iterator(bool begin) const { if (begin) return new vector_object_iterator_impl(m_v.begin()); else return new vector_object_iterator_impl(m_v.end()); } virtual string to_JSON() const { stringstream s; s << '['; for (uint32 ix = 0; ix < m_v.size(); ++ix) { if (ix > 0) s << ','; s << m_v[ix].toJSON(); } s << ']'; return s.str(); } vector m_v; }; class struct_object_impl : public detail::base_struct_object_impl { public: virtual void print(ostream& os) const { os << '{'; bool first = true; typedef pair value_type; foreach (const value_type& o, m_v) { if (not first) os << ','; first = false; os << o.first << ':' << o.second; } os << '}'; } virtual int compare(object_impl* rhs) const; virtual object& field(const string& name) { // icpc creates crashing code on this line: // pair::iterator,bool> i = m_v.insert(make_pair(name, object())); map::iterator i = m_v.find(name); if (i == m_v.end()) { m_v[name] = object(); i = m_v.find(name); } return i->second; } virtual const object field(const string& name) const { object result; map::const_iterator i = m_v.find(name); if (i != m_v.end()) result = i->second; return result; } virtual string to_JSON() const { stringstream s; s << '{'; for (map::const_iterator o = m_v.begin(); o != m_v.end(); ++o) { if (o != m_v.begin()) s << ','; s << '"' << o->first << '"' << ':' << o->second.toJSON(); } s << '}'; return s.str(); } private: map m_v; }; // -------------------------------------------------------------------- // compare methods int int_object_impl::compare(object_impl* rhs) const { int result = 0; if (dynamic_cast(rhs)) { if (m_v < static_cast(rhs)->m_v) result = -1; else if (m_v > static_cast(rhs)->m_v) result = 1; } else if (dynamic_cast(rhs)) { if (m_v < static_cast(rhs)->m_v) result = -1; else if (m_v > static_cast(rhs)->m_v) result = 1; } else if (dynamic_cast(rhs)) { double rv = rhs->to_double(); if (m_v < rv) result = -1; else if (m_v > rv) result = 1; } else throw exception("incompatible types for compare"); return result; } int float_object_impl::compare(object_impl* rhs) const { int result = 0; if (dynamic_cast(rhs)) { if (m_v < static_cast(rhs)->m_v) result = -1; else if (m_v > static_cast(rhs)->m_v) result = 1; } else if (dynamic_cast(rhs)) { if (m_v < static_cast(rhs)->m_v) result = -1; else if (m_v > static_cast(rhs)->m_v) result = 1; } else if (dynamic_cast(rhs)) { double rv = rhs->to_double(); if (m_v < rv) result = -1; else if (m_v > rv) result = 1; } else throw exception("incompatible types for compare"); return result; } int string_object_impl::compare(object_impl* rhs) const { int result = 0; if (dynamic_cast(rhs)) { double v = to_double(); if (v < static_cast(rhs)->m_v) result = -1; else if (v > static_cast(rhs)->m_v) result = 1; } else if (dynamic_cast(rhs)) { double v = to_double(); if (v < static_cast(rhs)->m_v) result = -1; else if (v > static_cast(rhs)->m_v) result = 1; } else if (dynamic_cast(rhs)) result = m_v.compare(static_cast(rhs)->m_v); else throw exception("incompatible types for compare"); return result; } int vector_object_impl::compare(object_impl* rhs) const { int result = 0; if (dynamic_cast(rhs)) { if (m_v < static_cast(rhs)->m_v) result = -1; else if (m_v > static_cast(rhs)->m_v) result = -1; } else throw exception("incompatible types for compare"); return result; } int struct_object_impl::compare(object_impl* rhs) const { int result = 0; if (dynamic_cast(rhs)) { if (m_v != static_cast(rhs)->m_v) result = 1; } else throw exception("incompatible types for compare"); return result; } // -------------------------------------------------------------------- // basic object methods object::object() : m_impl(nullptr) { } object::object(detail::object_impl* impl) : m_impl(impl) { } object::object(const object& o) : m_impl(o.m_impl) { if (m_impl != nullptr) m_impl->reference(); } object::~object() { if (m_impl != nullptr) m_impl->release(); } object& object::operator=(const object& o) { if (this != &o) { if (m_impl != nullptr) m_impl->release(); m_impl = o.m_impl; if (m_impl != nullptr) m_impl->reference(); } return *this; } // -------------------------------------------------------------------- // explicit constructors and assignment object::object(const vector& v) : m_impl(new vector_object_impl(v)) { } object::object(const vector& v) : m_impl(new vector_object_impl(v)) { } object::object(bool v) // : m_impl(new bool_object_impl(v)) : m_impl(new int_object_impl(v)) { } object::object(int8 v) : m_impl(new int_object_impl(v)) { } object::object(uint8 v) : m_impl(new int_object_impl(v)) { } object::object(int16 v) : m_impl(new int_object_impl(v)) { } object::object(uint16 v) : m_impl(new int_object_impl(v)) { } object::object(int32 v) : m_impl(new int_object_impl(v)) { } object::object(uint32 v) : m_impl(new int_object_impl(v)) { } object::object(int64 v) : m_impl(new int_object_impl(v)) { } object::object(uint64 v) : m_impl(new int_object_impl(v)) { } object::object(float v) : m_impl(new float_object_impl(v)) { } object::object(double v) : m_impl(new float_object_impl(v)) { } object::object(const char* v) : m_impl(nullptr) { if (v != nullptr) m_impl = new string_object_impl(v); } object::object(const string& v) : m_impl(new string_object_impl(v)) { } object& object::operator=(const vector& v) { if (m_impl != nullptr) m_impl->release(); m_impl = new vector_object_impl(v); return *this; } object& object::operator=(const vector& v) { if (m_impl != nullptr) m_impl->release(); m_impl = new vector_object_impl(v); return *this; } object& object::operator=(bool v) { if (m_impl != nullptr) m_impl->release(); // m_impl = new bool_object_impl(v); m_impl = new int_object_impl(v); return *this; } object& object::operator=(int8 v) { if (m_impl != nullptr) m_impl->release(); m_impl = new int_object_impl(v); return *this; } object& object::operator=(uint8 v) { if (m_impl != nullptr) m_impl->release(); m_impl = new int_object_impl(v); return *this; } object& object::operator=(int16 v) { if (m_impl != nullptr) m_impl->release(); m_impl = new int_object_impl(v); return *this; } object& object::operator=(uint16 v) { if (m_impl != nullptr) m_impl->release(); m_impl = new int_object_impl(v); return *this; } object& object::operator=(int32 v) { if (m_impl != nullptr) m_impl->release(); m_impl = new int_object_impl(v); return *this; } object& object::operator=(uint32 v) { if (m_impl != nullptr) m_impl->release(); m_impl = new int_object_impl(v); return *this; } object& object::operator=(int64 v) { if (m_impl != nullptr) m_impl->release(); m_impl = new int_object_impl(v); return *this; } object& object::operator=(uint64 v) { if (m_impl != nullptr) m_impl->release(); m_impl = new int_object_impl(v); return *this; } object& object::operator=(float v) { if (m_impl != nullptr) m_impl->release(); m_impl = new float_object_impl(v); return *this; } object& object::operator=(double v) { if (m_impl != nullptr) m_impl->release(); m_impl = new float_object_impl(v); return *this; } object& object::operator=(const char* v) { if (m_impl != nullptr) m_impl->release(); if (v == nullptr) m_impl = nullptr; else m_impl = new string_object_impl(v); return *this; } object& object::operator=(const string& v) { if (m_impl != nullptr) m_impl->release(); m_impl = new string_object_impl(v); return *this; } object::object_type object::type() const { object_type result = null_type; if (m_impl != nullptr) result = m_impl->type(); return result; } size_t object::count() const { if (type() != array_type) throw exception("count/length is only defined for array types"); return static_cast(m_impl)->count(); } bool object::empty() const { bool result = true; switch (type()) { case null_type: result = true; break; case string_type: result = m_impl->to_str().empty(); break; case array_type: result = static_cast(m_impl)->count() == 0; break; case number_type: result = false; break; case struct_type: result = false; break; } return result; } template<> string object::as() const { string result; if (m_impl) result = m_impl->to_str(); return result; } template<> bool object::as() const { bool result = false; if (dynamic_cast(m_impl)) result = static_cast(m_impl)->m_v != 0; else if (dynamic_cast(m_impl)) result = static_cast(m_impl)->m_v != 0; else if (type() == array_type) result = static_cast(m_impl)->count() != 0; else if (type() == string_type) result = not as().empty() and as() != "false"; else if (type() == struct_type) result = true; return result; } template<> double object::as() const { double result = 0; if (m_impl) result = m_impl->to_double(); return result; } const object object::operator[](const string& name) const { object result; if (type() == struct_type) { const detail::base_struct_object_impl* impl = static_cast(m_impl); result = impl->field(name); } return result; } const object object::operator[](const char* name) const { if (name != nullptr) return operator[](string(name)); return object(); } const object object::operator[](const object& index) const { object result; switch (type()) { case array_type: { const detail::base_array_object_impl* impl = static_cast(m_impl); if (impl != nullptr and index.as() < impl->count()) result = impl->at(index.as()); break; } case struct_type: { const detail::base_struct_object_impl* impl = static_cast(m_impl); result = impl->field(index.as()); break; } default: ; // return null } return result; } object& object::operator[](const string& name) { if (name.empty()) throw exception("invalid empty name for structure object"); return operator[](object(name)); } object& object::operator[](const char* name) { if (name == nullptr) throw exception("invalid empty name for structure object"); return operator[](object(name)); } object& object::operator[](const object& index) { if (type() == array_type) { vector_object_impl* impl = static_cast(m_impl); return impl->at(index.as()); } else if (type() == struct_type) { struct_object_impl* impl = static_cast(m_impl); return impl->field(index.as()); } else { if (m_impl != nullptr) m_impl->release(); struct_object_impl* impl; m_impl = impl = new struct_object_impl(); return impl->field(index.as()); } } bool object::operator<(const object& rhs) const { bool result = false; if (m_impl != nullptr and rhs.m_impl != nullptr) result = m_impl->compare(rhs.m_impl) < 0; return result; } bool object::operator==(const object& rhs) const { bool result = false; if (m_impl != nullptr and rhs.m_impl != nullptr) result = m_impl->compare(rhs.m_impl) == 0; return result; } bool operator<=(const object& a, const object& b) { return a < b or a == b; } struct compare_object { compare_object(const string& field, bool descending) : m_field(field) , m_descending(descending) { } bool operator()(const object& a, const object& b) const; string m_field; bool m_descending; }; //void object::sort(const string& sort_field, bool descending) //{ // if (m_type == ot_array) // sort(m_array.begin(), m_array.end(), compare_object(sort_field, descending)); //} ostream& operator<<(ostream& os, const object& o) { if (o.m_impl != nullptr) o.m_impl->print(os); else os << "null"; return os; } string object::toJSON() const { string result; if (m_impl != nullptr) result = m_impl->to_JSON(); return result; } object operator+(const object& a, const object& b) { object result; if (a.m_impl != nullptr and b.m_impl != nullptr and typeid(*a.m_impl) == typeid(*b.m_impl)) { if (dynamic_cast(a.m_impl)) result = static_cast(a.m_impl)->m_v + static_cast(b.m_impl)->m_v; else if (dynamic_cast(a.m_impl)) result = static_cast(a.m_impl)->m_v + static_cast(b.m_impl)->m_v; else if (dynamic_cast(a.m_impl)) result = static_cast(a.m_impl)->m_v + static_cast(b.m_impl)->m_v; else throw exception("incompatible types in add operator"); } else if (dynamic_cast(a.m_impl) or dynamic_cast(b.m_impl)) result = a.as() + b.as(); else if (dynamic_cast(a.m_impl) or dynamic_cast(b.m_impl)) result = a.as() + b.as(); else result = a.as() + b.as(); return result; } object operator-(const object& a, const object& b) { object result; if (dynamic_cast(a.m_impl) or dynamic_cast(b.m_impl)) result = a.as() - b.as(); else result = a.as() - b.as(); return result; } object operator*(const object& a, const object& b) { object result; if (dynamic_cast(a.m_impl) or dynamic_cast(b.m_impl)) result = a.as() * b.as(); else result = a.as() * b.as(); return result; } object operator/(const object& a, const object& b) { return object(a.as() / b.as()); } object operator%(const object& a, const object& b) { object result; if (dynamic_cast(a.m_impl) or dynamic_cast(b.m_impl)) result = a.as() % b.as(); return result; } object operator-(const object& a) { object result; if (dynamic_cast(a.m_impl)) result = - a.as(); else result = - a.as(); return result; } bool compare_object::operator()(const object& a, const object& b) const { if (m_descending) return b[m_field] < a[m_field]; else return a[m_field] < b[m_field]; } // -------------------------------------------------------------------- // interpreter for expression language struct interpreter { typedef uint32 unicode; interpreter( const scope& scope) : m_scope(scope) {} template OutputIterator operator()(Match& m, OutputIterator out, boost::regex_constants::match_flag_type); object evaluate( const string& s); void process( string& s); void match( uint32 t); unsigned char next_byte(); unicode get_next_char(); void retract(); void get_next_token(); object parse_expr(); // or_expr ( '?' expr ':' expr )? object parse_or_expr(); // and_expr ( 'or' and_expr)* object parse_and_expr(); // equality_expr ( 'and' equality_expr)* object parse_equality_expr(); // relational_expr ( ('=='|'!=') relational_expr )? object parse_relational_expr(); // additive_expr ( ('<'|'<='|'>='|'>') additive_expr )* object parse_additive_expr(); // multiplicative_expr ( ('+'|'-') multiplicative_expr)* object parse_multiplicative_expr(); // unary_expr (('%'|'/') unary_expr)* object parse_unary_expr(); // ('-')? primary_expr object parse_primary_expr(); // '(' expr ')' | number | string const scope& m_scope; uint32 m_lookahead; string m_token_string; double m_token_number; string::const_iterator m_ptr, m_end; }; template inline OutputIterator interpreter::operator()(Match& m, OutputIterator out, boost::regex_constants::match_flag_type) { string s(m[1]); process(s); copy(s.begin(), s.end(), out); return out; } enum token_type { elt_undef, elt_eof, elt_number, elt_string, elt_object, elt_and, elt_or, elt_not, elt_empty, elt_eq, elt_ne, elt_lt, elt_le, elt_ge, elt_gt, elt_plus, elt_minus, elt_div, elt_mod, elt_mult, elt_lparen, elt_rparen, elt_lbracket, elt_rbracket, elt_if, elt_else, elt_dot }; object interpreter::evaluate( const string& s) { object result; try { m_ptr = s.begin(); m_end = s.end(); get_next_token(); if (m_lookahead != elt_eof) result = parse_expr(); match(elt_eof); } catch (exception& /* e */) { // if (VERBOSE) // cerr << e.what() << endl; } return result; } void interpreter::process( string& s) { try { m_ptr = s.begin(); m_end = s.end(); get_next_token(); object result; if (m_lookahead != elt_eof) result = parse_expr(); match(elt_eof); s = result.as(); } catch (exception& e) { // if (VERBOSE) // cerr << e.what() << endl; s = "error in el expression: "; s += e.what(); } } void interpreter::match( uint32 t) { if (t != m_lookahead) throw zeep::exception("syntax error"); get_next_token(); } unsigned char interpreter::next_byte() { char result = 0; if (m_ptr < m_end) { result = *m_ptr; ++m_ptr; } m_token_string += result; return static_cast(result); } // We assume all paths are in valid UTF-8 encoding interpreter::unicode interpreter::get_next_char() { unicode result = 0; unsigned char ch[5]; ch[0] = next_byte(); if ((ch[0] & 0x080) == 0) result = ch[0]; else if ((ch[0] & 0x0E0) == 0x0C0) { ch[1] = next_byte(); if ((ch[1] & 0x0c0) != 0x080) throw zeep::exception("Invalid utf-8"); result = ((ch[0] & 0x01F) << 6) | (ch[1] & 0x03F); } else if ((ch[0] & 0x0F0) == 0x0E0) { ch[1] = next_byte(); ch[2] = next_byte(); if ((ch[1] & 0x0c0) != 0x080 or (ch[2] & 0x0c0) != 0x080) throw zeep::exception("Invalid utf-8"); result = ((ch[0] & 0x00F) << 12) | ((ch[1] & 0x03F) << 6) | (ch[2] & 0x03F); } else if ((ch[0] & 0x0F8) == 0x0F0) { ch[1] = next_byte(); ch[2] = next_byte(); ch[3] = next_byte(); if ((ch[1] & 0x0c0) != 0x080 or (ch[2] & 0x0c0) != 0x080 or (ch[3] & 0x0c0) != 0x080) throw zeep::exception("Invalid utf-8"); result = ((ch[0] & 0x007) << 18) | ((ch[1] & 0x03F) << 12) | ((ch[2] & 0x03F) << 6) | (ch[3] & 0x03F); } if (result > 0x10ffff) throw zeep::exception("invalid utf-8 character (out of range)"); return result; } void interpreter::retract() { string::iterator c = m_token_string.end(); // skip one valid character back in the input buffer // since we've arrived here, we can safely assume input // is valid UTF-8 do --c; while ((*c & 0x0c0) == 0x080); if (m_ptr != m_end or *c != 0) m_ptr -= m_token_string.end() - c; m_token_string.erase(c, m_token_string.end()); } void interpreter::get_next_token() { enum State { els_Start, els_Equals, els_ExclamationMark, els_LessThan, els_GreaterThan, els_Number, els_NumberFraction, els_Name, els_Literal } state = els_Start; token_type token = elt_undef; double fraction = 1.0; unicode quoteChar = 0; m_token_string.clear(); while (token == elt_undef) { unicode ch = get_next_char(); switch (state) { case els_Start: switch (ch) { case 0: token = elt_eof; break; case '(': token = elt_lparen; break; case ')': token = elt_rparen; break; case '[': token = elt_lbracket; break; case ']': token = elt_rbracket; break; case ':': token = elt_else; break; case '?': token = elt_if; break; case '*': token = elt_mult; break; case '/': token = elt_div; break; case '+': token = elt_plus; break; case '-': token = elt_minus; break; case '.': token = elt_dot; break; case '=': state = els_Equals; break; case '!': state = els_ExclamationMark; break; case '<': state = els_LessThan; break; case '>': state = els_GreaterThan; break; case ' ': case '\n': case '\r': case '\t': m_token_string.clear(); break; case '\'': quoteChar = ch; state = els_Literal; break; case '"': quoteChar = ch; state = els_Literal; break; default: if (ch >= '0' and ch <= '9') { m_token_number = ch - '0'; state = els_Number; } else if (zeep::xml::is_name_start_char(ch)) state = els_Name; else throw zeep::exception((boost::format("invalid character (%1%) in expression") % ch).str()); } break; case els_Equals: if (ch != '=') retract(); token = elt_eq; break; case els_ExclamationMark: if (ch != '=') { retract(); throw zeep::exception("unexpected character ('!') in expression"); } token = elt_ne; break; case els_LessThan: if (ch == '=') token = elt_le; else { retract(); token = elt_lt; } break; case els_GreaterThan: if (ch == '=') token = elt_ge; else { retract(); token = elt_gt; } break; case els_Number: if (ch >= '0' and ch <= '9') m_token_number = 10 * m_token_number + (ch - '0'); else if (ch == '.') { fraction = 0.1; state = els_NumberFraction; } else { retract(); token = elt_number; } break; case els_NumberFraction: if (ch >= '0' and ch <= '9') { m_token_number += fraction * (ch - '0'); fraction /= 10; } else { retract(); token = elt_number; } break; case els_Name: if (ch == '.' or not zeep::xml::is_name_char(ch)) { retract(); if (m_token_string == "div") token = elt_div; else if (m_token_string == "mod") token = elt_mod; else if (m_token_string == "and") token = elt_and; else if (m_token_string == "or") token = elt_or; else if (m_token_string == "not") token = elt_not; else if (m_token_string == "empty") token = elt_empty; else if (m_token_string == "lt") token = elt_lt; else if (m_token_string == "le") token = elt_le; else if (m_token_string == "ge") token = elt_ge; else if (m_token_string == "gt") token = elt_gt; else if (m_token_string == "ne") token = elt_ne; else if (m_token_string == "eq") token = elt_eq; else token = elt_object; } break; case els_Literal: if (ch == 0) throw zeep::exception("run-away string, missing quote character?"); else if (ch == quoteChar) { token = elt_string; m_token_string = m_token_string.substr(1, m_token_string.length() - 2); } break; } } m_lookahead = token; } object interpreter::parse_expr() { object result = parse_or_expr(); if (m_lookahead == elt_if) { match(m_lookahead); object a = parse_expr(); match(elt_else); object b = parse_expr(); if (result.as()) result = a; else result = b; } return result; } object interpreter::parse_or_expr() { object result = parse_and_expr(); while (m_lookahead == elt_or) { match(m_lookahead); bool b1 = result.as(); bool b2 = parse_and_expr().as(); result = b1 or b2; } return result; } object interpreter::parse_and_expr() { object result = parse_equality_expr(); while (m_lookahead == elt_and) { match(m_lookahead); bool b1 = result.as(); bool b2 = parse_equality_expr().as(); result = b1 and b2; } return result; } object interpreter::parse_equality_expr() { object result = parse_relational_expr(); if (m_lookahead == elt_eq) { match(m_lookahead); result = (result == parse_relational_expr()); } else if (m_lookahead == elt_ne) { match(m_lookahead); result = not (result == parse_relational_expr()); } return result; } object interpreter::parse_relational_expr() { object result = parse_additive_expr(); switch (m_lookahead) { case elt_lt: match(m_lookahead); result = (result < parse_additive_expr()); break; case elt_le: match(m_lookahead); result = (result <= parse_additive_expr()); break; case elt_ge: match(m_lookahead); result = (parse_additive_expr() <= result); break; case elt_gt: match(m_lookahead); result = (parse_additive_expr() < result); break; default: break; } return result; } object interpreter::parse_additive_expr() { object result = parse_multiplicative_expr(); while (m_lookahead == elt_plus or m_lookahead == elt_minus) { if (m_lookahead == elt_plus) { match(m_lookahead); result = (result + parse_multiplicative_expr()); } else { match(m_lookahead); result = (result - parse_multiplicative_expr()); } } return result; } object interpreter::parse_multiplicative_expr() { object result = parse_unary_expr(); while (m_lookahead == elt_div or m_lookahead == elt_mod or m_lookahead == elt_mult) { if (m_lookahead == elt_mult) { match(m_lookahead); result = (result * parse_unary_expr()); } else if (m_lookahead == elt_div) { match(m_lookahead); result = (result / parse_unary_expr()); } else { match(m_lookahead); result = (result % parse_unary_expr()); } } return result; } object interpreter::parse_unary_expr() { object result; if (m_lookahead == elt_minus) { match(m_lookahead); result = -(parse_primary_expr()); } else if (m_lookahead == elt_not) { match(m_lookahead); result = not parse_primary_expr().as(); } else result = parse_primary_expr(); return result; } object interpreter::parse_primary_expr() { object result; switch (m_lookahead) { case elt_number: result = m_token_number; match(m_lookahead); break; case elt_string: result = m_token_string; match(m_lookahead); break; case elt_lparen: match(m_lookahead); result = parse_expr(); match(elt_rparen); break; case elt_object: result = m_scope.lookup(m_token_string); match(elt_object); for (;;) { if (m_lookahead == elt_dot) { match(m_lookahead); if (result.type() == object::array_type and (m_token_string == "count" or m_token_string == "length")) result = object((uint32)result.count()); else result = const_cast(result)[m_token_string]; match(elt_object); continue; } if (m_lookahead == elt_lbracket) { match(m_lookahead); object index = parse_expr(); match(elt_rbracket); if (index.empty() or (result.type() != object::array_type and result.type() != object::struct_type)) result = object(); else result = const_cast(result)[index]; continue; } break; } break; case elt_empty: match(m_lookahead); if (m_lookahead != elt_object) throw zeep::exception("syntax error, expected an object after operator 'empty'"); result = parse_primary_expr().empty(); break; default: throw zeep::exception("syntax error, expected number, string or object"); } return result; } // -------------------------------------------------------------------- // interpreter calls bool process_el( const el::scope& scope, string& text) { static const boost::regex re("\\$\\{([^}]+)\\}"); el::interpreter interpreter(scope); ostringstream os; ostream_iterator out(os); boost::regex_replace(out, text.begin(), text.end(), re, interpreter, boost::match_default | boost::format_all); bool result = false; if (os.str() != text) { //cerr << "processed \"" << text << "\" => \"" << os.str() << '"' << endl; text = os.str(); result = true; } return result; } void evaluate_el( const el::scope& scope, const string& text, el::object& result) { static const boost::regex re("^\\$\\{([^}]+)\\}$"); boost::smatch m; if (boost::regex_match(text, m, re)) { el::interpreter interpreter(scope); result = interpreter.evaluate(m[1]); //cerr << "evaluated \"" << text << "\" => \"" << result << '"' << endl; } else result = text; } bool evaluate_el( const el::scope& scope, const string& text) { el::object result; evaluate_el(scope, text, result); return result.as(); } // -------------------------------------------------------------------- // scope ostream& operator<<(ostream& lhs, const scope& rhs) { const scope* s = &rhs; while (s != nullptr) { foreach (scope::data_map::value_type e, s->m_data) lhs << e.first << " = " << e.second << endl; s = s->m_next; } return lhs; } scope::scope(const scope& next) : m_next(const_cast(&next)) , m_req(nullptr) { } scope::scope(const request& req) : m_next(nullptr) , m_req(&req) { } object& scope::operator[]( const string& name) { return lookup(name); } const object& scope::lookup( const string& name) const { map::const_iterator i = m_data.find(name); if (i != m_data.end()) return i->second; else if (m_next != nullptr) return m_next->lookup(name); static object s_null; return s_null; } const object& scope::operator[]( const string& name) const { return lookup(name); } object& scope::lookup( const string& name) { object* result = nullptr; map::iterator i = m_data.find(name); if (i != m_data.end()) result = &i->second; else if (m_next != nullptr) result = &m_next->lookup(name); else { m_data[name] = object(); result = &m_data[name]; } return *result; } const request& scope::get_request() const { if (m_next) return m_next->get_request(); if (m_req == nullptr) throw zeep::exception("Invalid scope, no request"); return *m_req; } } } } libzeep-3.0.2/src/document-expat.cpp0000664000175000017500000002516012125635713017251 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #if SOAP_XML_HAS_EXPAT_SUPPORT #include #include #include #include #include #include #include #include #include #include #define foreach BOOST_FOREACH #include #include "document-expat.hpp" #include #include using namespace std; namespace ba = boost::algorithm; namespace fs = boost::filesystem; namespace zeep { namespace xml { const char* kXML_Parser_Error_Messages[] = { "NONE", "NO_MEMORY", "SYNTAX", "NO_ELEMENTS", "INVALID_TOKEN", "UNCLOSED_TOKEN", "PARTIAL_CHAR", "TAG_MISMATCH", "DUPLICATE_ATTRIBUTE", "JUNK_AFTER_DOC_ELEMENT", "PARAM_ENTITY_REF", "UNDEFINED_ENTITY", "RECURSIVE_ENTITY_REF", "ASYNC_ENTITY", "BAD_CHAR_REF", "BINARY_ENTITY_REF", "ATTRIBUTE_EXTERNAL_ENTITY_REF", "MISPLACED_XML_PI", "UNKNOWN_ENCODING", "INCORRECT_ENCODING", "UNCLOSED_CDATA_SECTION", "EXTERNAL_ENTITY_HANDLING", "NOT_STANDALONE", "UNEXPECTED_STATE", "ENTITY_DECLARED_IN_PE", "FEATURE_REQUIRES_XML_DTD", "CANT_CHANGE_FEATURE_ONCE_PARSING", "UNBOUND_PREFIX", "UNDECLARING_PREFIX", "INCOMPLETE_PE", "XML_DECL", "TEXT_DECL", "PUBLICID", "SUSPENDED", "NOT_SUSPENDED", "ABORTED", "FINISHED", "SUSPEND_PE", "RESERVED_PREFIX_XML", "RESERVED_PREFIX_XMLNS", "RESERVED_NAMESPACE_URI", }; class expat_exception : public zeep::exception { public: expat_exception(XML_Parser parser); }; expat_exception::expat_exception( XML_Parser parser) : exception("") { try { stringstream s; XML_Error error = XML_GetErrorCode(parser); if (error <= XML_ERROR_RESERVED_NAMESPACE_URI) s << kXML_Parser_Error_Messages[error]; else s << "Unknown Expat error code"; s << endl << "Parse error at line " << XML_GetCurrentLineNumber(parser) << " column " << XML_GetCurrentColumnNumber(parser) << ":" << endl; int offset = 0, size = 0; const char* context = XML_GetInputContext(parser, &offset, &size); if (context != nullptr) s << string(context + offset, size) << endl; m_message = s.str(); } catch (...) { m_message = "oeps"; } } // -------------------------------------------------------------------- void expat_doc_imp::XML_StartElementHandler( void* userData, const XML_Char* name, const XML_Char** atts) { assert(name); static_cast(userData)->StartElementHandler(name, atts); } void expat_doc_imp::XML_EndElementHandler( void* userData, const XML_Char* name) { assert(name); static_cast(userData)->EndElementHandler(name); } void expat_doc_imp::XML_CharacterDataHandler( void* userData, const XML_Char* s, int len) { assert(s); static_cast(userData)->CharacterDataHandler(s, len); } void expat_doc_imp::XML_ProcessingInstructionHandler( void* userData, const XML_Char* target, const XML_Char* data) { assert(target); assert(data); static_cast(userData)->ProcessingInstructionHandler(target, data); } void expat_doc_imp::XML_CommentHandler( void* userData, const XML_Char* data) { assert(data); static_cast(userData)->CommentHandler(data); } void expat_doc_imp::XML_StartCdataSectionHandler( void *userData) { static_cast(userData)->StartCdataSectionHandler(); } void expat_doc_imp::XML_EndCdataSectionHandler( void *userData) { static_cast(userData)->EndCdataSectionHandler(); } void expat_doc_imp::XML_StartNamespaceDeclHandler( void* userData, const XML_Char* prefix, const XML_Char* uri) { assert(uri); static_cast(userData)->StartNamespaceDeclHandler(prefix ? prefix : "", uri); } void expat_doc_imp::XML_EndNamespaceDeclHandler( void* userData, const XML_Char* prefix) { static_cast(userData)->EndNamespaceDeclHandler(prefix ? prefix : ""); } void expat_doc_imp::XML_NotationDeclHandler( void* userData, const XML_Char* notationName, const XML_Char* base, const XML_Char* systemId, const XML_Char* publicId) { static_cast(userData)->NotationDeclHandler(notationName, base, systemId, publicId); } int expat_doc_imp::XML_ExternalEntityRefHandler( XML_Parser parser, const XML_Char* context, const XML_Char* base, const XML_Char* systemId, const XML_Char* publicId) { int result = XML_STATUS_OK; if (base != nullptr and systemId != nullptr) { fs::path basedir(base); fs::path file = basedir / systemId; if (fs::exists(file)) { fs::ifstream data(file, ios::binary); XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0); XML_SetBase(entParser, file.string().c_str()); data.seekg (0, ios::end); unsigned long length = data.tellg(); data.seekg (0, ios::beg); while (length > 0) { char buffer[256]; unsigned long k = length; if (k > sizeof(buffer)) k = sizeof(buffer); length -= k; data.read(buffer, k); result = XML_Parse(entParser, buffer, k, length == 0); if (result != XML_STATUS_OK) break; } XML_ParserFree(entParser); } } return result; } // -------------------------------------------------------------------- expat_doc_imp::expat_doc_imp(document* doc) : document_imp(doc) { } void expat_doc_imp::parse_name( const char* name, string& element, string& ns, string& prefix) { vector n3; ba::split(n3, name, ba::is_any_of("=")); if (n3.size() == 3) { ns = n3[0]; element = n3[1]; prefix = n3[2]; } else if (n3.size() == 2) { ns = n3[0]; element = n3[1]; if (not ns.empty()) prefix = prefix_for_namespace(ns); else prefix.clear(); } else { element = n3[0]; ns.clear(); prefix.clear(); } } void expat_doc_imp::StartElementHandler( const XML_Char* name, const XML_Char** atts) { string qname, uri, prefix; parse_name(name, qname, uri, prefix); if (not prefix.empty()) qname = prefix + ':' + qname; unique_ptr n(new element(qname)); if (m_cur == nullptr) m_root.child_element(n.get()); else m_cur->append(n.get()); m_cur = n.release(); for (const char** att = atts; *att; att += 2) { if (not att[0] or not att[1]) break; parse_name(att[0], qname, uri, prefix); if (not prefix.empty()) qname = prefix + ':' + qname; #pragma message("need to find the ID here") m_cur->set_attribute(qname, att[1], false); } const string name_prefix("xmlns:"); for (vector >::iterator ns = m_namespaces.begin(); ns != m_namespaces.end(); ++ns) m_cur->set_name_space(ns->first, ns->second); m_namespaces.clear(); n.release(); } void expat_doc_imp::EndElementHandler( const XML_Char* name) { if (m_cur == nullptr) throw exception("Empty stack"); m_cur = dynamic_cast(m_cur->parent()); } void expat_doc_imp::CharacterDataHandler( const XML_Char* s, int len) { if (m_cur == nullptr) throw exception("Empty stack"); if (m_cdata != nullptr) m_cdata->append(data); else m_cur->add_text(string(s, len)); } void expat_doc_imp::ProcessingInstructionHandler( const XML_Char* target, const XML_Char* data) { if (m_cur != nullptr) m_cur->append(new processing_instruction(target, data)); else m_root.append(new processing_instruction(target, data)); } void expat_doc_imp::CommentHandler( const XML_Char* data) { if (m_cur != nullptr) m_cur->append(new comment(data)); else m_root.append(new comment(data)); } void expat_doc_imp::StartCdataSectionHandler() { if (m_cur == nullptr) throw exception("empty stack"); if (m_cdata != nullptr) throw exception("Nested CDATA?"); m_cdata = new cdata(); m_cur->append(m_cdata); } void expat_doc_imp::EndCdataSectionHandler() { m_cdata = nullptr; } void expat_doc_imp::StartNamespaceDeclHandler( const XML_Char* prefix, const XML_Char* uri) { if (prefix == nullptr) prefix = ""; m_namespaces.push_back(make_pair(prefix, uri)); } void expat_doc_imp::EndNamespaceDeclHandler( const XML_Char* prefix) { } void expat_doc_imp::NotationDeclHandler( const XML_Char* notationName, const XML_Char* base, const XML_Char* systemId, const XML_Char* publicId) { notation n = { notationName ? notationName : "", systemId ? systemId : "", publicId ? publicId : "" }; list::iterator i = find_if(m_notations.begin(), m_notations.end(), boost::bind(¬ation::m_name, _1) >= notationName); m_notations.insert(i, n); } // -------------------------------------------------------------------- void expat_doc_imp::parse( istream& data) { XML_Parser p = XML_ParserCreateNS(nullptr, '='); if (p == nullptr) throw exception("failed to create expat parser object"); try { XML_SetParamEntityParsing(p, XML_PARAM_ENTITY_PARSING_ALWAYS); XML_UseForeignDTD(p, true); XML_SetBase(p, (fs::current_path().string() + "/").c_str()); XML_SetUserData(p, this); XML_SetElementHandler(p, XML_StartElementHandler, XML_EndElementHandler); XML_SetCharacterDataHandler(p, XML_CharacterDataHandler); XML_SetProcessingInstructionHandler(p, XML_ProcessingInstructionHandler); XML_SetCommentHandler(p, XML_CommentHandler); // XML_SetCdataSectionHandler(p, XML_StartCdataSectionHandler, XML_EndCdataSectionHandler); // XML_SetDefaultHandler(p, XML_DefaultHandler); // XML_SetDoctypeDeclHandler(p, XML_StartDoctypeDeclHandler, XML_EndDoctypeDeclHandler); // XML_SetUnparsedEntityDeclHandler(p, XML_UnparsedEntityDeclHandler); XML_SetExternalEntityRefHandler(p, XML_ExternalEntityRefHandler); XML_SetNotationDeclHandler(p, XML_NotationDeclHandler); XML_SetNamespaceDeclHandler(p, XML_StartNamespaceDeclHandler, XML_EndNamespaceDeclHandler); XML_SetReturnNSTriplet(p, true); // for some reason, readsome does not work when using // boost::iostreams::stream // and so we have to come up with a kludge. data.seekg (0, ios::end); unsigned long length = data.tellg(); data.seekg (0, ios::beg); while (length > 0) { char buffer[256]; unsigned long k = length; if (k > sizeof(buffer)) k = sizeof(buffer); length -= k; data.read(buffer, k); XML_Status err = XML_Parse(p, buffer, k, length == 0); if (err != XML_STATUS_OK) throw expat_exception(p); } } catch (std::exception& e) { XML_ParserFree(p); throw; } XML_ParserFree(p); } } // xml } // zeep #endif libzeep-3.0.2/src/document-expat.hpp0000664000175000017500000000612411543053426017253 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2010-2011. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef SOAP_XML_DOCUMENT_EXPAT_H #define SOAP_XML_DOCUMENT_EXPAT_H #include #include "document-imp.hpp" #if SOAP_XML_HAS_EXPAT_SUPPORT #include namespace zeep { namespace xml { struct expat_doc_imp : public document_imp { expat_doc_imp(document* doc); static void XML_StartElementHandler( void* userData, const XML_Char* name, const XML_Char** atts); static void XML_EndElementHandler( void* userData, const XML_Char* name); static void XML_CharacterDataHandler( void* userData, const XML_Char* s, int len); static void XML_ProcessingInstructionHandler( void* userData, const XML_Char* target, const XML_Char* data); static void XML_CommentHandler( void* userData, const XML_Char* data); static void XML_StartCdataSectionHandler( void *userData); static void XML_EndCdataSectionHandler( void *userData); static void XML_StartNamespaceDeclHandler( void* userData, const XML_Char* prefix, const XML_Char* uri); static void XML_EndNamespaceDeclHandler( void* userData, const XML_Char* prefix); static void XML_NotationDeclHandler( void* userData, const XML_Char* notationName, const XML_Char* base, const XML_Char* systemId, const XML_Char* publicId); static int XML_ExternalEntityRefHandler( XML_Parser parser, const XML_Char* context, const XML_Char* base, const XML_Char* systemId, const XML_Char* publicId); void StartElementHandler( const XML_Char* name, const XML_Char** atts); void EndElementHandler( const XML_Char* name); void CharacterDataHandler( const XML_Char* s, int len); void ProcessingInstructionHandler( const XML_Char* target, const XML_Char* data); void CommentHandler( const XML_Char* data); void StartCdataSectionHandler(); void EndCdataSectionHandler(); void StartNamespaceDeclHandler( const XML_Char* prefix, const XML_Char* uri); void EndNamespaceDeclHandler( const XML_Char* prefix); void NotationDeclHandler( const XML_Char* notationName, const XML_Char* base, const XML_Char* systemId, const XML_Char* publicId); void parse( std::istream& data); void parse_name( const char* name, std::string& element, std::string& ns, std::string& prefix); }; } } #endif #endif libzeep-3.0.2/src/writer.cpp0000664000175000017500000001643412121543422015623 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include #define foreach BOOST_FOREACH #include #include #include #include using namespace std; namespace ba = boost::algorithm; namespace zeep { namespace xml { string k_empty_string; writer::writer(std::ostream& os) : m_os(os) , m_encoding(enc_UTF8) , m_version(1.0f) , m_write_xml_decl(false) , m_wrap(true) , m_wrap_prolog(true) , m_collapse_empty(true) , m_escape_whitespace(false) , m_trim(false) , m_no_comment(false) , m_indent(2) , m_level(0) , m_element_open(false) , m_wrote_element(false) , m_prolog(true) { } writer::writer(std::ostream& os, bool write_decl, bool standalone) : m_os(os) , m_encoding(enc_UTF8) , m_version(1.0f) , m_write_xml_decl(write_decl) , m_wrap(true) , m_wrap_prolog(true) , m_collapse_empty(true) , m_escape_whitespace(false) , m_trim(false) , m_no_comment(false) , m_indent(2) , m_level(0) , m_element_open(false) , m_wrote_element(false) , m_prolog(true) { if (m_write_xml_decl) xml_decl(standalone); } writer::~writer() { } void writer::xml_decl(bool standalone) { if (m_write_xml_decl) { assert(m_encoding == enc_UTF8); if (m_version == 1.0f) m_os << ""; if (m_wrap_prolog) m_os << endl; m_write_xml_decl = false; } } void writer::doctype(const string& root, const string& pubid, const string& dtd) { m_os << ""; if (m_wrap_prolog) m_os << endl; } void writer::start_doctype(const string& root, const string& dtd) { m_os << ""; // if (m_wrap_prolog) m_os << endl; } void writer::empty_doctype(const string& root, const string& dtd) { m_os << ""; // if (m_wrap_prolog) m_os << endl; } void writer::notation(const string& name, const string& sysid, const string& pubid) { m_os << "'; // if (m_wrap_prolog) m_os << endl; } void writer::attribute(const string& name, const string& value) { if (not m_element_open) throw exception("no open element to write attribute to"); m_os << ' ' << name << "=\""; bool last_is_space = false; foreach (char c, value) { switch (c) { case '&': m_os << "&"; last_is_space = false; break; case '<': m_os << "<"; last_is_space = false; break; case '>': m_os << ">"; last_is_space = false; break; case '\"': m_os << """; last_is_space = false; break; case '\n': if (m_escape_whitespace) m_os << " "; else m_os << c; last_is_space = true; break; case '\r': if (m_escape_whitespace) m_os << " "; else m_os << c; last_is_space = false; break; case '\t': if (m_escape_whitespace) m_os << " "; else m_os << c; last_is_space = false; break; case ' ': if (not m_trim or not last_is_space) m_os << ' '; last_is_space = true; break; case 0: throw exception("Invalid null character in XML content"); default: if ((c >= 1 and c <= 8) or (c >= 0x0b and c <= 0x0c) or (c >= 0x0e and c <= 0x1f) or c == 0x7f) m_os << "&#" << hex << c << ';'; else m_os << c; last_is_space = false; break; } } m_os << '"'; } void writer::start_element(const string& qname) { if (m_element_open) { m_os << '>'; if (m_wrap) m_os << endl; } for (int i = 0; i < m_indent * m_level; ++i) m_os << ' '; ++m_level; m_os << '<' << qname; m_stack.push(qname); m_element_open = true; m_wrote_element = false; m_prolog = false; } void writer::end_element() { assert(m_level > 0); assert(not m_stack.empty()); if (m_level == 0 or m_stack.empty()) throw exception("inconsistent state in xml::writer"); --m_level; if (m_element_open) { if (m_collapse_empty) m_os << "/>"; else m_os << ">'; } else { if (m_wrote_element) { for (int i = 0; i < m_indent * m_level; ++i) m_os << ' '; } m_os << "'; } if (m_wrap) m_os << endl; m_stack.pop(); m_element_open = false; m_wrote_element = true; } void writer::cdata(const string& text) { if (m_element_open) { m_os << '>'; if (m_wrap) m_os << endl; } m_element_open = false; for (int i = 0; i < m_indent * m_level; ++i) m_os << ' '; m_os << ""; if (m_wrap) m_os << endl; } void writer::comment(const string& text) { if (not m_no_comment) { if (m_element_open) { m_os << '>'; if (m_wrap) m_os << endl; } m_element_open = false; for (int i = 0; i < m_indent * m_level; ++i) m_os << ' '; // m_os << ""; m_os << ""; if ((m_prolog and m_wrap_prolog) or (not m_prolog and m_wrap)) m_os << endl; } } void writer::processing_instruction(const string& target, const string& text) { if (m_element_open) m_os << '>'; m_element_open = false; for (int i = 0; i < m_indent * m_level; ++i) m_os << ' '; m_os << ""; if ((m_prolog and m_wrap_prolog) or (not m_prolog and m_wrap)) m_os << endl; } void writer::content(const string& text) { if (m_element_open) m_os << '>'; m_element_open = false; bool last_is_space = false; foreach (char c, text) { switch (c) { case '&': m_os << "&"; last_is_space = false; break; case '<': m_os << "<"; last_is_space = false; break; case '>': m_os << ">"; last_is_space = false; break; case '\"': m_os << """; last_is_space = false; break; case '\n': if (m_escape_whitespace) m_os << " "; else m_os << c; last_is_space = true; break; case '\r': if (m_escape_whitespace) m_os << " "; else m_os << c; last_is_space = false; break; case '\t': if (m_escape_whitespace) m_os << " "; else m_os << c; last_is_space = false; break; case ' ': if (not m_trim or not last_is_space) m_os << ' '; last_is_space = true; break; case 0: throw exception("Invalid null character in XML content"); default: if ((c >= 1 and c <= 8) or (c >= 0x0b and c <= 0x0c) or (c >= 0x0e and c <= 0x1f) or c == 0x7f) m_os << "&#" << hex << c << ';'; else m_os << c; last_is_space = false; break; } } m_wrote_element = false; } } } libzeep-3.0.2/src/request_parser.cpp0000664000175000017500000001600311777540137017363 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include #include using namespace std; namespace zeep { namespace http { namespace detail { bool is_tspecial(int c) { switch (c) { case '(': case ')': case '<': case '>': case '@': case ',': case ';': case ':': case '\\': case '"': case '/': case '[': case ']': case '?': case '=': case '{': case '}': case ' ': case '\t': return true; default: return false; } } } // detail request_parser::request_parser() : m_parser(NULL) { } void request_parser::reset() { m_parser = NULL; } boost::tribool request_parser::parse(request& req, const char* text, size_t length) { if (m_parser == NULL) { m_state = 0; m_data.clear(); req.http_version_major = 1; req.http_version_minor = 0; req.close = false; m_parser = &request_parser::parse_initial_line; } boost::tribool result = boost::indeterminate; while (length-- > 0 and boost::indeterminate(result)) result = (this->*m_parser)(req, *text++); return result; } boost::tribool request_parser::parse_initial_line(request& req, char ch) { boost::tribool result = boost::indeterminate; // a state machine to parse the initial request line // which consists of: // METHOD URI HTTP/1.0 (or 1.1) switch (m_state) { // we're parsing the method here case 0: if (isalpha(ch)) req.method += ch; else if (ch == ' ') ++m_state; else result = false; break; // we're parsing the URI here case 1: if (ch == ' ') ++m_state; else if (iscntrl(ch)) result = false; else req.uri += ch; break; // we're parsing the trailing HTTP/1.x here case 2: if (ch == 'H') ++m_state; else result = false; break; case 3: if (ch == 'T') ++m_state; else result = false; break; case 4: if (ch == 'T') ++m_state; else result = false; break; case 5: if (ch == 'P') ++m_state; else result = false; break; case 6: if (ch == '/') ++m_state; else result = false; break; case 7: if (ch == '1') ++m_state; else result = false; break; case 8: if (ch == '.') ++m_state; else if (ch == '\r') m_state = 11; else result = false; break; case 9: if (ch == '1' or ch == '0') { if (ch == '1') req.http_version_minor = 1; ++m_state; } else result = false; break; case 10: if (ch == '\r') ++m_state; else result = false; break; case 11: if (ch == '\n') { m_state = 0; m_parser = &request_parser::parse_header; } else result = false; break; } return result; } boost::tribool request_parser::parse_header(request& req, char ch) { boost::tribool result = boost::indeterminate; // parse the header lines, consisting of // NAME: VALUE // optionally followed by more VALUE prefixed by white space on the next lines switch (m_state) { case 0: // If the header starts with \r, it is the start of an empty line // which indicates the end of the header section if (ch == '\r') { m_parser = &request_parser::parse_empty_line; for (vector
::iterator h = req.headers.begin(); h != req.headers.end(); ++h) { if (h->name == "Transfer-Encoding" and h->value == "chunked") { m_parser = &request_parser::parse_chunk; break; } else if (h->name == "Content-Length") { stringstream s(h->value); s >> m_chunk_size; req.payload.reserve(m_chunk_size); m_state = 0; m_parser = &request_parser::parse_content; break; } } result = (this->*m_parser)(req, ch); } else if ((ch == ' ' or ch == '\t') and not req.headers.empty()) m_state = 10; else if (iscntrl(ch) or detail::is_tspecial(ch)) result = false; else { req.headers.push_back(header()); req.headers.back().name += ch; m_state = 1; } break; case 1: if (ch == ':') ++m_state; else if (iscntrl(ch) or detail::is_tspecial(ch)) result = false; else req.headers.back().name += ch; break; case 2: if (ch == ' ') ++m_state; else result = false; break; case 3: if (ch == '\r') ++m_state; else if (iscntrl(ch)) result = false; else req.headers.back().value += ch; break; case 4: if (ch == '\n') { if (req.headers.back().name == "Connection" and req.headers.back().value == "close") { req.close = true; } m_state = 0; } else result = false; break; case 10: if (ch == '\r') m_state = 4; else if (iscntrl(ch)) result = false; else if (not (ch == ' ' or ch == '\t')) { req.headers.back().value += ch; m_state = 3; } break; } return result; } boost::tribool request_parser::parse_empty_line(request& req, char ch) { boost::tribool result = boost::indeterminate; switch (m_state) { case 0: if (ch == '\r') ++m_state; else result = false; break; case 1: if (ch == '\n') result = true; else result = false; break; } return result; } boost::tribool request_parser::parse_chunk(request& req, char ch) { boost::tribool result = boost::indeterminate; switch (m_state) { // Transfer-Encoding: Chunked // lines starting with hex encoded length, optionally followed by text // then a newline (\r\n) and the actual length bytes. // This repeats until length is zero // start with empty line... case 0: if (ch == '\r') ++m_state; else result = false; break; case 1: if (ch == '\n') ++m_state; else result = false; break; // new chunk? case 2: if (isxdigit(ch)) { m_data = ch; ++m_state; } else if (ch == '\r') m_state = 10; else result = false; break; case 3: if (isxdigit(ch)) m_data += ch; else if (ch == ';') ++m_state; else if (ch == '\r') m_state = 5; else result = false; break; case 4: if (ch == '\r') ++m_state; else if (detail::is_tspecial(ch) or iscntrl(ch)) result = false; break; case 5: if (ch == '\n') { stringstream s(m_data); s >> hex >> m_chunk_size; if (m_chunk_size > 0) { req.payload.reserve(req.payload.size() + m_chunk_size); ++m_state; } else m_state = 2; } else result = false; break; case 6: req.payload += ch; if (--m_chunk_size == 0) m_state = 0; // restart break; // trailing \r\n case 10: if (ch == '\n') result = true; else result = false; break; } return result; } boost::tribool request_parser::parse_content(request& req, char ch) { boost::tribool result = boost::indeterminate; // here we simply read m_chunk_size of bytes and finish switch (m_state) { case 0: if (ch == '\r') ++m_state; else result = false; break; case 1: if (ch == '\n') ++m_state; else result = false; break; case 2: req.payload += ch; if (--m_chunk_size == 0) result = true; break; } return result; } } // http } // zeep libzeep-3.0.2/src/reply.cpp0000664000175000017500000002121412125636672015450 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include #define foreach BOOST_FOREACH #include #include #include #include #include #include #include #include using namespace std; namespace io = boost::iostreams; namespace zeep { namespace http { namespace detail { struct status_string { status_type code; const char* text; } kStatusStrings[] = { { cont, "Continue" }, { ok, "OK" }, { not_found, "Not Found" }, { created, "Created" }, { accepted, "Accepted" }, { no_content, "No Content" }, { multiple_choices, "Multiple Choices" }, { moved_permanently, "Moved Permanently" }, { moved_temporarily, "Found" }, { not_modified, "Not Modified" }, { bad_request, "Bad Request" }, { unauthorized, "Unauthorized" }, { forbidden, "Forbidden" }, { not_found, "Not Found" }, { internal_server_error,"Internal Server Error" }, { not_implemented, "Not Implemented" }, { bad_gateway, "Bad Gateway" }, { service_unavailable, "Service Unavailable" } }; const int kStatusStringCount = sizeof(kStatusStrings) / sizeof(status_string); string get_status_text(status_type status) { string result = "Internal Service Error"; for (int i = 0; i < kStatusStringCount; ++i) { if (kStatusStrings[i].code == status) { result = kStatusStrings[i].text; break; } } return result; } } // ---------------------------------------------------------------------------- namespace { const char kNameValueSeparator[] = { ':', ' ' }, kCRLF[] = { '\r', '\n' }; } reply::reply(int version_major, int version_minor) : m_version_major(version_major) , m_version_minor(version_minor) , m_status(internal_server_error) , m_data(nullptr) { using namespace boost::local_time; using namespace boost::posix_time; local_date_time t(local_sec_clock::local_time(time_zone_ptr())); local_time_facet* lf(new local_time_facet("%a, %d %b %Y %H:%M:%S GMT")); stringstream s; s.imbue(std::locale(std::locale(), lf)); s << t; set_header("Date", s.str()); set_header("Server", "libzeep"); } reply::reply(const reply& rhs) : m_version_major(rhs.m_version_major) , m_version_minor(rhs.m_version_minor) , m_status(rhs.m_status) , m_status_line(rhs.m_status_line) , m_headers(rhs.m_headers) , m_content(rhs.m_content) , m_data(nullptr) { } reply::~reply() { delete m_data; } reply& reply::operator=(const reply& rhs) { if (this != &rhs) { m_version_major = rhs.m_version_major; m_version_minor = rhs.m_version_minor; m_status = rhs.m_status; m_status_line = rhs.m_status_line; m_headers = rhs.m_headers; m_content = rhs.m_content; } return *this; } void reply::set_version(int version_major, int version_minor) { m_version_major = version_major; m_version_minor = version_minor; } void reply::set_header(const string& name, const string& value) { bool updated = false; foreach (header& h, m_headers) { if (h.name == name) { h.value = value; updated = true; break; } } if (not updated) { header nh = { name, value }; m_headers.push_back(nh); } } void reply::set_content(xml::element* data) { xml::document doc; doc.child(data); set_content(doc); } void reply::set_content(xml::document& doc) { stringstream s; xml::writer w(s); w.set_wrap(false); w.set_indent(0); // w.trim(true); doc.write(w); string contentType = "text/xml; charset=utf-8"; if (doc.child()->ns() == "http://www.w3.org/1999/xhtml") contentType = "application/xhtml+xml; charset=utf-8"; set_content(s.str(), contentType); } void reply::set_content(const string& data, const string& contentType) { m_content = data; m_status = ok; delete m_data; m_data = nullptr; set_header("Content-Length", boost::lexical_cast(m_content.length())); set_header("Content-Type", contentType); } void reply::set_content(istream* idata, const string& contentType) { delete m_data; m_data = idata; m_content.clear(); m_status = ok; set_header("Content-Type", contentType); // for HTTP/1.0 replies we need to calculate the data length if (m_version_major == 1 and m_version_minor == 0 and m_data != nullptr) { streamsize pos = m_data->rdbuf()->pubseekoff(0, ios_base::cur); streamsize length = m_data->rdbuf()->pubseekoff(0, ios_base::end); length -= pos; m_data->rdbuf()->pubseekoff(pos, ios_base::beg); set_header("Content-Length", boost::lexical_cast(length)); } else set_header("Transfer-Encoding", "chunked"); } string reply::get_content_type() const { string result; foreach (const header& h, m_headers) { if (h.name == "Content-Type") { result = h.value; break; } } return result; } void reply::set_content_type( const string& type) { foreach (header& h, m_headers) { if (h.name == "Content-Type") { h.value = type; break; } } } void reply::to_buffers(vector& buffers) { m_status_line = (boost::format("HTTP/%1%.%2% %3% %4%\r\n") % m_version_major % m_version_minor % m_status % detail::get_status_text(m_status)).str(); buffers.push_back(boost::asio::buffer(m_status_line)); foreach (header& h, m_headers) { buffers.push_back(boost::asio::buffer(h.name)); buffers.push_back(boost::asio::buffer(kNameValueSeparator)); buffers.push_back(boost::asio::buffer(h.value)); buffers.push_back(boost::asio::buffer(kCRLF)); } buffers.push_back(boost::asio::buffer(kCRLF)); buffers.push_back(boost::asio::buffer(m_content)); } bool reply::data_to_buffers(vector& buffers) { bool result = false; if (m_data != nullptr) { result = true; const unsigned int kMaxChunkSize = 10240; if (m_buffer.size() < kMaxChunkSize) m_buffer.insert(m_buffer.begin(), kMaxChunkSize, 0); else if (m_buffer.size() > kMaxChunkSize) m_buffer.erase(m_buffer.begin() + kMaxChunkSize, m_buffer.end()); streamsize n = m_data->readsome(&m_buffer[0], m_buffer.size()); // chunked encoding? if (m_version_major > 1 or m_version_minor >= 1) { if (n == 0) { buffers.push_back(boost::asio::buffer("0")); buffers.push_back(boost::asio::buffer(kCRLF)); buffers.push_back(boost::asio::buffer(kCRLF)); delete m_data; m_data = nullptr; } else { io::filtering_ostream out(io::back_inserter(m_buffer)); out << std::hex << n << '\r' << '\n'; out.flush(); buffers.push_back(boost::asio::buffer(&m_buffer[kMaxChunkSize], m_buffer.size() - kMaxChunkSize)); buffers.push_back(boost::asio::buffer(&m_buffer[0], n)); buffers.push_back(boost::asio::buffer(kCRLF)); } } else { if (n > 0) buffers.push_back(boost::asio::buffer(&m_buffer[0], n)); else { delete m_data; m_data = nullptr; result = false; } } } return result; } string reply::get_as_text() { // for best performance, we pre calculate memory requirements and reserve that first m_status_line = (boost::format("HTTP/%1%.%2% %3% %4%\r\n") % m_version_major % m_version_minor % m_status % detail::get_status_text(m_status)).str(); string result; result.reserve(get_size()); result = m_status_line; foreach (header& h, m_headers) { result += h.name; result += ": "; result += h.value; result += "\r\n"; } result += "\r\n"; result += m_content; return result; } size_t reply::get_size() const { size_t size = m_status_line.length(); foreach (const header& h, m_headers) size += h.name.length() + 2 + h.value.length() + 2; size += 2 + m_content.length(); return size; } reply reply::stock_reply(status_type status) { reply result; if (status != not_modified) { stringstream text; text << "

" << detail::get_status_text(status) << "

"; result.set_content(text.str(), "text/html; charset=utf-8"); } result.m_status = status; return result; } reply reply::redirect(const std::string& location) { reply result; result.m_status = moved_temporarily; string text = detail::get_status_text(moved_temporarily); result.m_content = string("") + text + "

" + boost::lexical_cast(moved_temporarily) + ' ' + text + "

"; result.set_header("Location", location); result.set_header("Content-Length", boost::lexical_cast(result.m_content.length())); result.set_header("Content-Type", "text/html; charset=utf-8"); return result; } } } libzeep-3.0.2/src/document.cpp0000664000175000017500000003110012125635713016121 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008-2012. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define foreach BOOST_FOREACH #include #include "document-imp.hpp" #include #include #include #include #if SOAP_XML_HAS_EXPAT_SUPPORT #include "document-expat.hpp" #endif using namespace std; namespace ba = boost::algorithm; namespace fs = boost::filesystem; namespace zeep { namespace xml { // -------------------------------------------------------------------- document_imp::document_imp(document* doc) : m_encoding(enc_UTF8) , m_standalone(false) , m_indent(2) , m_empty(true) , m_wrap(true) , m_trim(true) , m_escape_whitespace(false) , m_no_comment(false) , m_validating(false) , m_preserve_cdata(false) , m_doc(doc) , m_cur(nullptr) , m_cdata(nullptr) { } document_imp::~document_imp() { } string document_imp::prefix_for_namespace(const string& ns) { vector >::iterator i = find_if(m_namespaces.begin(), m_namespaces.end(), boost::bind(&pair::second, _1) == ns); string result; if (i != m_namespaces.end()) result = i->first; else if (m_cur != nullptr) result = m_cur->prefix_for_namespace(ns); else throw exception("namespace not found: %s", ns.c_str()); return result; } istream* document_imp::external_entity_ref(const string& base, const string& pubid, const string& sysid) { istream* result = nullptr; if (m_doc->external_entity_ref_handler) result = m_doc->external_entity_ref_handler(base, pubid, sysid); if (result == nullptr and not sysid.empty()) { fs::path path; if (base.empty()) path = sysid; else path = base + '/' + sysid; if (not fs::exists(path)) path = m_dtd_dir / path; if (fs::exists(path)) result = new fs::ifstream(m_dtd_dir / path, ios::binary); } return result; } // -------------------------------------------------------------------- struct zeep_document_imp : public document_imp { zeep_document_imp(document* doc); virtual void StartElementHandler(const string& name, const string& uri, const parser::attr_list_type& atts); virtual void EndElementHandler(const string& name, const string& uri); virtual void CharacterDataHandler(const string& data); virtual void ProcessingInstructionHandler(const string& target, const string& data); virtual void CommentHandler(const string& comment); virtual void StartCdataSectionHandler(); virtual void EndCdataSectionHandler(); virtual void StartNamespaceDeclHandler(const string& prefix, const string& uri); virtual void EndNamespaceDeclHandler(const string& prefix); virtual void NotationDeclHandler(const string& name, const string& sysid, const string& pubid); virtual void parse(istream& data); }; // -------------------------------------------------------------------- zeep_document_imp::zeep_document_imp(document* doc) : document_imp(doc) { } void zeep_document_imp::StartElementHandler(const string& name, const string& uri, const parser::attr_list_type& atts) { string qname = name; if (not uri.empty()) { string prefix = prefix_for_namespace(uri); if (not prefix.empty()) qname = prefix + ':' + name; } unique_ptr n(new element(qname)); if (m_cur == nullptr) m_root.child_element(n.get()); else m_cur->append(n.get()); m_cur = n.release(); foreach (const parser::attr_type& a, atts) { qname = a.m_name; if (not a.m_ns.empty()) qname = prefix_for_namespace(a.m_ns) + ':' + a.m_name; m_cur->set_attribute(qname, a.m_value, a.m_id); } for (vector >::iterator ns = m_namespaces.begin(); ns != m_namespaces.end(); ++ns) m_cur->set_name_space(ns->first, ns->second); m_namespaces.clear(); } void zeep_document_imp::EndElementHandler(const string& name, const string& uri) { if (m_cur == nullptr) throw exception("Empty stack"); if (m_cdata != nullptr) throw exception("CDATA section not closed"); m_cur = dynamic_cast(m_cur->parent()); } void zeep_document_imp::CharacterDataHandler(const string& data) { if (m_cur == nullptr) throw exception("Empty stack"); if (m_cdata != nullptr) m_cdata->append(data); else m_cur->add_text(data); } void zeep_document_imp::ProcessingInstructionHandler(const string& target, const string& data) { if (m_cur != nullptr) m_cur->append(new processing_instruction(target, data)); else m_root.append(new processing_instruction(target, data)); } void zeep_document_imp::CommentHandler(const string& s) { if (m_cur != nullptr) m_cur->append(new comment(s)); else m_root.append(new comment(s)); } void zeep_document_imp::StartCdataSectionHandler() { if (m_cur == nullptr) throw exception("empty stack"); if (m_cdata != nullptr) throw exception("Nested CDATA?"); m_cdata = new cdata(); m_cur->append(m_cdata); } void zeep_document_imp::EndCdataSectionHandler() { m_cdata = nullptr; } void zeep_document_imp::StartNamespaceDeclHandler(const string& prefix, const string& uri) { m_namespaces.push_back(make_pair(prefix, uri)); } void zeep_document_imp::EndNamespaceDeclHandler(const string& prefix) { } void zeep_document_imp::NotationDeclHandler( const string& name, const string& sysid, const string& pubid) { notation n = { name, sysid, pubid }; list::iterator i = find_if(m_notations.begin(), m_notations.end(), boost::bind(¬ation::m_name, _1) >= name); m_notations.insert(i, n); } // -------------------------------------------------------------------- void zeep_document_imp::parse( istream& data) { parser p(data); p.start_element_handler = boost::bind(&zeep_document_imp::StartElementHandler, this, _1, _2, _3); p.end_element_handler = boost::bind(&zeep_document_imp::EndElementHandler, this, _1, _2); p.character_data_handler = boost::bind(&zeep_document_imp::CharacterDataHandler, this, _1); if (m_preserve_cdata) { p.start_cdata_section_handler = boost::bind(&zeep_document_imp::StartCdataSectionHandler, this); p.end_cdata_section_handler = boost::bind(&zeep_document_imp::EndCdataSectionHandler, this); } p.start_namespace_decl_handler = boost::bind(&zeep_document_imp::StartNamespaceDeclHandler, this, _1, _2); p.processing_instruction_handler = boost::bind(&zeep_document_imp::ProcessingInstructionHandler, this, _1, _2); p.comment_handler = boost::bind(&zeep_document_imp::CommentHandler, this, _1); p.notation_decl_handler = boost::bind(&zeep_document_imp::NotationDeclHandler, this, _1, _2, _3); p.external_entity_ref_handler = boost::bind(&document_imp::external_entity_ref, this, _1, _2, _3); p.parse(m_validating); } // -------------------------------------------------------------------- #if SOAP_XML_HAS_EXPAT_SUPPORT parser_type document::s_parser_type = parser_zeep; document_imp* document::create_imp(document* doc) { document_imp* impl; if (s_parser_type == parser_expat) impl = new expat_doc_imp(doc); else if (s_parser_type == parser_zeep) impl = new zeep_document_imp(doc); else throw zeep::exception("invalid parser type specified"); return impl; } void document::set_parser_type(parser_type type) { s_parser_type = type; } #else document_imp* document::create_imp(document* doc) { return new zeep_document_imp(doc); } #endif document::document() : m_impl(create_imp(this)) { } document::document(const string& s) : m_impl(create_imp(this)) { istringstream is(s); read(is); } document::document(std::istream& is) : m_impl(create_imp(this)) { read(is); } document::document(std::istream& is, const boost::filesystem::path& base_dir) : m_impl(create_imp(this)) { read(is, base_dir); } document::document(document_imp* impl) : m_impl(impl) { } document::~document() { delete m_impl; } void document::read(const string& s) { istringstream is(s); read(is); } void document::read(istream& is) { m_impl->parse(is); } void document::read(istream& is, const boost::filesystem::path& base_dir) { set_validating(true); m_impl->m_dtd_dir = base_dir; m_impl->parse(is); } void document::write(writer& w) const { // w.set_xml_decl(true); // w.set_indent(m_impl->m_indent); // w.set_wrap(m_impl->m_wrap); // w.set_trim(m_impl->m_trim); // w.set_escape_whitespace(m_impl->m_escape_whitespace); // w.set_no_comment(m_impl->m_no_comment); element* e = m_impl->m_root.child_element(); if (e == nullptr) throw exception("cannot write an empty XML document"); w.xml_decl(m_impl->m_standalone); if (not m_impl->m_notations.empty()) { w.start_doctype(e->qname(), ""); foreach (const document_imp::notation& n, m_impl->m_notations) w.notation(n.m_name, n.m_sysid, n.m_pubid); w.end_doctype(); } m_impl->m_root.write(w); } root_node* document::root() const { return &m_impl->m_root; } element* document::child() const { return m_impl->m_root.child_element(); } void document::child(element* e) { return m_impl->m_root.child_element(e); } element_set document::find(const char* path) const { return m_impl->m_root.find(path); } element* document::find_first(const char* path) const { return m_impl->m_root.find_first(path); } void document::find(const char* path, node_set& nodes) const { m_impl->m_root.find(path, nodes); } void document::find(const char* path, element_set& elements) const { m_impl->m_root.find(path, elements); } node* document::find_first_node(const char* path) const { return m_impl->m_root.find_first_node(path); } void document::base_dir(const fs::path& path) { m_impl->m_dtd_dir = path; } encoding_type document::encoding() const { return m_impl->m_encoding; } void document::encoding(encoding_type enc) { m_impl->m_encoding = enc; } int document::indent() const { return m_impl->m_indent; } void document::indent(int indent) { m_impl->m_indent = indent; } bool document::wrap() const { return m_impl->m_wrap; } void document::wrap(bool wrap) { m_impl->m_wrap = wrap; } bool document::trim() const { return m_impl->m_trim; } void document::trim(bool trim) { m_impl->m_trim = trim; } bool document::no_comment() const { return m_impl->m_no_comment; } void document::no_comment(bool no_comment) { m_impl->m_no_comment = no_comment; } void document::set_validating(bool validate) { m_impl->m_validating = validate; } void document::set_preserve_cdata(bool preserve_cdata) { m_impl->m_preserve_cdata = preserve_cdata; } bool document::operator==(const document& other) const { return m_impl->m_root.equals(&other.m_impl->m_root); } istream& operator>>(istream& lhs, document& rhs) { rhs.read(lhs); return lhs; } ostream& operator<<(ostream& lhs, const document& rhs) { writer w(lhs); rhs.write(w); return lhs; } // -------------------------------------------------------------------- // // A visitor for elements that match the element_xpath. // struct visitor_imp : public zeep_document_imp { visitor_imp(document* doc, const string& element_xpath, boost::function cb); void EndElementHandler(const string& name, const string& uri); xpath mElementXPath; boost::function mCallback; }; // -------------------------------------------------------------------- visitor_imp::visitor_imp(document* doc, const string& element_xpath, boost::function cb) : zeep_document_imp(doc), mElementXPath(element_xpath), mCallback(cb) { } void visitor_imp::EndElementHandler(const string& name, const string& uri) { if (m_cur == nullptr) throw exception("Empty stack"); if (m_cdata != nullptr) throw exception("CDATA section not closed"); // see if we need to process this one if (mElementXPath.matches(m_cur)) { if (not mCallback(m_root.child(), m_cur)) ; // TODO stop processing, how? element* e = m_cur; m_cur = dynamic_cast(m_cur->parent()); if (m_cur == nullptr) m_root.child_element(nullptr); else { m_cur->remove(e); delete e; } } else m_cur = dynamic_cast(m_cur->parent()); } void process_document_elements(istream& data, const string& element_xpath, boost::function cb) { document doc(new visitor_imp(nullptr, element_xpath, cb)); doc.m_impl->m_doc = &doc; doc.m_impl->parse(data); } } // xml } // zeep libzeep-3.0.2/src/soap-server.cpp0000664000175000017500000000575211777540137016576 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include #include #include #include using namespace std; namespace ba = boost::algorithm; namespace fs = boost::filesystem; namespace zeep { server::server(const std::string& ns, const std::string& service) : dispatcher(ns, service) { } void server::bind(const std::string& address, unsigned short port) { http::server::bind(address, port); if (m_location.empty()) { if (port != 80) m_location = "http://" + address + ':' + boost::lexical_cast(port) + '/' + m_service; else m_location = "http://" + address + '/' + m_service; } } #if BOOST_FILESYSTEM_VERSION == 2 inline string to_string(const string& p) { return p; } #else inline string to_string(const boost::filesystem::path& p) { return p.string(); } #endif void server::handle_request(const http::request& req, http::reply& rep) { string action; try { xml::element* response; if (req.method == "POST") // must be a SOAP call { xml::document doc; doc.read(req.payload); envelope env(doc); xml::element* request = env.request(); action = request->name(); log() << action << ' '; response = make_envelope(dispatch(action, env.request())); } else if (req.method == "GET") { // start by sanitizing the request's URI string uri = req.uri; // strip off the http part including hostname and such if (ba::starts_with(uri, "http://")) { string::size_type s = uri.find_first_of('/', 7); if (s != string::npos) uri.erase(0, s); } // now make the path relative to the root while (uri.length() > 0 and uri[0] == '/') uri.erase(uri.begin()); fs::path path(uri); fs::path::iterator p = path.begin(); if (p == path.end()) throw http::bad_request; string root = to_string(*p++); if (root == "rest") { action = to_string(*p++); xml::element* request(new xml::element(action)); while (p != path.end()) { string name = http::decode_url(to_string(*p++)); if (p == path.end()) break; xml::element* param(new xml::element(name)); string value = http::decode_url(to_string(*p++)); param->content(value); request->append(param); } log() << action << ' '; response = make_envelope(dispatch(action, request)); } else if (root == "wsdl" or root == "?wsdl") { log() << "wsdl"; response = make_wsdl(m_location); } else { log() << req.uri; throw http::not_found; } } else throw http::bad_request; rep.set_content(response); } catch (std::exception& e) { rep.set_content(make_fault(e)); } catch (http::status_type& s) { rep = http::reply::stock_reply(s); } } } libzeep-3.0.2/src/xpath.cpp0000664000175000017500000017111012073032051015421 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include #include #include #include #include #include #include #include #include #include #define foreach BOOST_FOREACH #include #include #include #include #include #include #include #include //extern int VERBOSE; using namespace std; using namespace tr1; namespace ba = boost::algorithm; namespace zeep { namespace xml { // debug code ostream& operator<<(ostream& lhs, const node* rhs) { lhs << *rhs; return lhs; } // -------------------------------------------------------------------- enum Token { xp_Undef = 0, xp_EOF = 256, xp_LeftParenthesis, xp_RightParenthesis, xp_LeftBracket, xp_RightBracket, xp_Slash, xp_DoubleSlash, xp_Comma, xp_Name, xp_AxisSpec, xp_FunctionName, xp_NodeType, xp_OperatorUnion, xp_OperatorAdd, xp_OperatorSubstract, xp_OperatorEqual, xp_OperatorNotEqual, xp_OperatorLess, xp_OperatorLessOrEqual, xp_OperatorGreater, xp_OperatorGreaterOrEqual, // next four operators are pseudo tokens, i.e. they are returned as xp_Name from get_next_token xp_OperatorAnd, xp_OperatorOr, xp_OperatorMod, xp_OperatorDiv, xp_Literal, xp_Number, xp_Variable, xp_Asterisk, xp_Colon }; enum AxisType { ax_Ancestor, ax_AncestorOrSelf, ax_Attribute, ax_Child, ax_Descendant, ax_DescendantOrSelf, ax_Following, ax_FollowingSibling, ax_Namespace, ax_Parent, ax_Preceding, ax_PrecedingSibling, ax_Self, ax_AxisTypeCount }; const char* kAxisNames[ax_AxisTypeCount] = { "ancestor", "ancestor-or-self", "attribute", "child", "descendant", "descendant-or-self", "following", "following-sibling", "namespace", "parent", "preceding", "preceding-sibling", "self" }; enum CoreFunction { cf_Last, cf_Position, cf_Count, cf_Id, cf_LocalName, cf_NamespaceUri, cf_Name, cf_String, cf_Concat, cf_StartsWith, cf_Contains, cf_SubstringBefore, cf_SubstringAfter, cf_Substring, cf_StringLength, cf_NormalizeSpace, cf_Translate, cf_Boolean, cf_Not, cf_True, cf_False, cf_Lang, cf_Number, cf_Sum, cf_Floor, cf_Ceiling, cf_Round, cf_Comment, cf_CoreFunctionCount }; struct CoreFunctionInfo { const char* name; int arg_count; }; const int kOptionalArgument = -100; const CoreFunctionInfo kCoreFunctionInfo[cf_CoreFunctionCount] = { { "last", 0 }, { "position", 0 }, { "count", 1 }, { "id", 0 }, { "local-name", kOptionalArgument }, { "namespace-uri", kOptionalArgument }, { "name", kOptionalArgument }, { "string", kOptionalArgument }, { "concat", -2 }, { "starts-with", 2 }, { "contains", 2 }, { "substring-before", 2 }, { "substring-after", 2 }, { "substring", -2 }, { "string-length", kOptionalArgument }, { "normalize-space", kOptionalArgument }, { "translate", 3 }, { "boolean", 1 }, { "not", 1 }, { "true" , 0 }, { "false", 0 }, { "lang", 0 }, { "number", kOptionalArgument }, { "sum", 0 }, { "floor", 1 }, { "ceiling", 1 }, { "round", 1 }, { "comment", 1 }, }; // the expressions are implemented as interpreter objects // they return 'objects' that can hold various data. enum object_type { ot_undef, ot_node_set, ot_boolean, ot_number, ot_string }; class object { public: object(); object(node_set ns); object(bool b); object(double n); object(const string& s); object(const object& o); object& operator=(const object& o); bool operator==(const object o); bool operator<(const object o); object_type type() const { return m_type; } template const T as() const; private: object_type m_type; node_set m_node_set; bool m_boolean; double m_number; string m_string; }; object operator%(const object& lhs, const object& rhs); object operator/(const object& lhs, const object& rhs); object operator+(const object& lhs, const object& rhs); object operator-(const object& lhs, const object& rhs); object::object() : m_type(ot_undef) { } object::object(node_set ns) : m_type(ot_node_set) , m_node_set(ns) { } object::object(bool b) : m_type(ot_boolean) , m_boolean(b) { } object::object(double n) : m_type(ot_number) , m_number(n) { } object::object(const string& s) : m_type(ot_string) , m_string(s) { } object::object(const object& o) : m_type(o.m_type) { switch (m_type) { case ot_node_set: m_node_set = o.m_node_set; break; case ot_boolean: m_boolean = o.m_boolean; break; case ot_number: m_number = o.m_number; break; case ot_string: m_string = o.m_string; break; default: break; } } object& object::operator=(const object& o) { m_type = o.m_type; switch (m_type) { case ot_node_set: m_node_set = o.m_node_set; break; case ot_boolean: m_boolean = o.m_boolean; break; case ot_number: m_number = o.m_number; break; case ot_string: m_string = o.m_string; break; default: break; } return *this; } template<> const node_set& object::as() const { if (m_type != ot_node_set) throw exception("object is not of type node-set"); return m_node_set; } template<> const bool object::as() const { bool result; switch (m_type) { case ot_number: result = m_number != 0 and not tr1::isnan(m_number); break; case ot_node_set: result = not m_node_set.empty(); break; case ot_string: result = not m_string.empty(); break; case ot_boolean: result = m_boolean; break; default: result = false; break; } return result; } template<> const double object::as() const { double result; switch (m_type) { case ot_number: result = m_number; break; case ot_node_set: result = boost::lexical_cast(m_node_set.front()->str()); break; case ot_string: result = boost::lexical_cast(m_string); break; case ot_boolean: result = m_boolean; break; default: result = 0; break; } return result; } template<> const int object::as() const { if (m_type != ot_number) throw exception("object is not of type number"); return static_cast(tr1::round(m_number)); } template<> const string& object::as() const { if (m_type != ot_string) throw exception("object is not of type string"); return m_string; } template<> const string object::as() const { string result; switch (m_type) { case ot_number: result = boost::lexical_cast(m_number); break; case ot_string: result = m_string; break; case ot_boolean: result = (m_boolean ? "true" : "false"); break; case ot_node_set: if (not m_node_set.empty()) result = m_node_set.front()->str(); break; default: break; } return result; } bool object::operator==(const object o) { bool result = false; if (m_type == o.m_type) { switch (m_type) { case ot_node_set: result = m_node_set == o.m_node_set; break; case ot_boolean: result = m_boolean == o.m_boolean; break; case ot_number: result = m_number == o.m_number; break; case ot_string: result = m_string == o.m_string; break; default: break; } } else { if (m_type == ot_number or o.m_type == ot_number) result = as() == o.as(); else if (m_type == ot_string or o.m_type == ot_string) result = as() == o.as(); else if (m_type == ot_boolean or o.m_type == ot_boolean) result = as() == o.as(); } return result; } bool object::operator<(const object o) { bool result = false; switch (m_type) { case ot_node_set: result = m_node_set < o.m_node_set; break; case ot_boolean: result = m_boolean < o.m_boolean; break; case ot_number: result = m_number < o.m_number; break; case ot_string: result = m_string < o.m_string; break; default: break; } return result; } ostream& operator<<(ostream& lhs, object& rhs) { switch (rhs.type()) { case ot_undef: lhs << "undef()"; break; case ot_number: lhs << "number(" << rhs.as() << ')'; break; case ot_string: lhs << "string(" << rhs.as() << ')'; break; case ot_boolean: lhs << "boolean(" << (rhs.as() ? "true" : "false") << ')'; break; case ot_node_set: lhs << "node_set(#" << rhs.as().size() << ')'; break; } return lhs; } // -------------------------------------------------------------------- // visiting (or better, collecting) other nodes in the hierarchy is done here. template void iterate_children(container* context, node_set& s, bool deep, PREDICATE pred) { for (node* child = context->child(); child != nullptr; child = child->next()) { container* e = dynamic_cast(child); if (e == nullptr) continue; if (find(s.begin(), s.end(), child) != s.end()) continue; if (pred(e)) s.push_back(child); if (deep) iterate_children(e, s, true, pred); } } template void iterate_ancestor(container* e, node_set& s, PREDICATE pred) { for (;;) { e = dynamic_cast(e->parent()); if (e == nullptr) break; root_node* r = dynamic_cast(e); if (r != nullptr) break; if (pred(e)) s.push_back(e); } } template void iterate_preceding(node* n, node_set& s, bool sibling, PREDICATE pred) { while (n != nullptr) { if (n->prev() == nullptr) { if (sibling) break; n = n->parent(); continue; } n = n->prev(); container* e = dynamic_cast(n); if (e == nullptr) continue; if (pred(e)) s.push_back(e); if (sibling == false) iterate_children(e, s, true, pred); } } template void iterate_following(node* n, node_set& s, bool sibling, PREDICATE pred) { while (n != nullptr) { if (n->next() == nullptr) { if (sibling) break; n = n->parent(); continue; } n = n->next(); container* e = dynamic_cast(n); if (e == nullptr) continue; if (pred(e)) s.push_back(e); if (sibling == false) iterate_children(e, s, true, pred); } } template void iterate_attributes(element* e, node_set& s, PREDICATE pred) { foreach (attribute* a, e->attributes()) { if (pred(a)) s.push_back(a); } } template void iterate_namespaces(element* e, node_set& s, PREDICATE pred) { foreach (name_space* a, e->name_spaces()) { if (pred(a)) s.push_back(a); } } // -------------------------------------------------------------------- // context for the expressions // Need to add support for external variables here. struct context_imp { virtual ~context_imp() {} virtual object& get(const string& name) { return m_variables[name]; } virtual void set(const string& name, const object& value) { m_variables[name] = value; } map m_variables; }; struct expression_context : public context_imp { expression_context(context_imp& next, node* n, const node_set& s) : m_next(next), m_node(n), m_node_set(s) {} virtual object& get(const string& name) { return m_next.get(name); } virtual void set(const string& name, const object& value) { m_next.set(name, value); } void dump(); size_t position() const; size_t last() const; context_imp& m_next; node* m_node; const node_set& m_node_set; }; size_t expression_context::position() const { size_t result = 0; foreach (const node* n, m_node_set) { ++result; if (n == m_node) break; } if (result == 0) throw exception("invalid context for position"); return result; } size_t expression_context::last() const { return m_node_set.size(); } void expression_context::dump() { cout << "context node: " << *m_node << endl << "context node-set: "; copy(m_node_set.begin(), m_node_set.end(), ostream_iterator(cout, ", ")); cout << endl; } ostream& operator<<(ostream& lhs, expression_context& rhs) { rhs.dump(); return lhs; } void indent(int level) { while (level-- > 0) cout << ' '; } // -------------------------------------------------------------------- class expression { public: virtual ~expression() {} virtual object evaluate(expression_context& context) = 0; // print exists only for debugging purposes virtual void print(int level) = 0; }; typedef boost::shared_ptr expression_ptr; typedef list expression_list; // -------------------------------------------------------------------- class step_expression : public expression { public: step_expression(AxisType axis) : m_axis(axis) {} protected: template object evaluate(expression_context& context, T pred); AxisType m_axis; }; template object step_expression::evaluate(expression_context& context, T pred) { node_set result; container* context_element = dynamic_cast(context.m_node); if (context_element != nullptr) { switch (m_axis) { case ax_Parent: if (context_element->parent() != nullptr) { container* e = static_cast(context_element->parent()); if (pred(e)) result.push_back(context_element->parent()); } break; case ax_Ancestor: iterate_ancestor(context_element, result, pred); break; case ax_AncestorOrSelf: if (pred(context_element)) result.push_back(context_element); iterate_ancestor(context_element, result, pred); break; case ax_Self: if (pred(context_element)) result.push_back(context_element); break; case ax_Child: iterate_children(context_element, result, false, pred); break; case ax_Descendant: iterate_children(context_element, result, true, pred); break; case ax_DescendantOrSelf: if (pred(context_element)) result.push_back(context_element); iterate_children(context_element, result, true, pred); break; case ax_Following: iterate_following(context_element, result, false, pred); break; case ax_FollowingSibling: iterate_following(context_element, result, true, pred); break; case ax_Preceding: iterate_preceding(context_element, result, false, pred); break; case ax_PrecedingSibling: iterate_preceding(context_element, result, true, pred); break; case ax_Attribute: if (dynamic_cast(context_element) != nullptr) iterate_attributes(static_cast(context_element), result, pred); break; case ax_Namespace: if (dynamic_cast(context_element) != nullptr) iterate_namespaces(static_cast(context_element), result, pred); break; case ax_AxisTypeCount: ; } } return result; } // -------------------------------------------------------------------- class name_test_step_expression : public step_expression { public: name_test_step_expression(AxisType axis, const string& name) : step_expression(axis) , m_name(name) { m_test = boost::bind(&name_test_step_expression::name_matches, this, _1); } virtual object evaluate(expression_context& context); virtual void print(int level) { indent(level); cout << "name test step " << m_name << endl; } protected: bool name_matches(const node* n) { bool result = m_name == "*"; if (result == false) { const element* e = dynamic_cast(n); if (e != nullptr and e->name() == m_name) result = true; } if (result == false) { const attribute* a = dynamic_cast(n); if (a != nullptr and a->name() == m_name) result = true; } return result; } string m_name; boost::function m_test; }; object name_test_step_expression::evaluate(expression_context& context) { return step_expression::evaluate(context, m_test); } // -------------------------------------------------------------------- template class node_type_expression : public step_expression { public: node_type_expression(AxisType axis) : step_expression(axis) { m_test = boost::bind(&node_type_expression::test, _1); } virtual object evaluate(expression_context& context); virtual void print(int level) { indent(level); cout << "node type step " << typeid(T).name() << endl; } private: static bool test(const node* n) { return dynamic_cast(n) != nullptr; } boost::function m_test; }; template object node_type_expression::evaluate(expression_context& context) { return step_expression::evaluate(context, m_test); } // -------------------------------------------------------------------- class root_expression : public expression { public: virtual object evaluate(expression_context& context); virtual void print(int level) { indent(level); cout << "root" << endl; } }; object root_expression::evaluate(expression_context& context) { node_set result; result.push_back(context.m_node->root()); return result; } // -------------------------------------------------------------------- template class operator_expression : public expression { public: operator_expression(expression_ptr lhs, expression_ptr rhs) : m_lhs(lhs), m_rhs(rhs) {} virtual object evaluate(expression_context& context); virtual void print(int level) { indent(level); cout << "operator " << typeid(OP).name() << endl; m_lhs->print(level + 1); m_rhs->print(level + 1); } private: expression_ptr m_lhs, m_rhs; }; template<> object operator_expression::evaluate(expression_context& context) { object v1 = m_lhs->evaluate(context); object v2 = m_rhs->evaluate(context); return v1.as() + v2.as(); } template<> object operator_expression::evaluate(expression_context& context) { object v1 = m_lhs->evaluate(context); object v2 = m_rhs->evaluate(context); return v1.as() - v2.as(); } template<> object operator_expression::evaluate(expression_context& context) { object v1 = m_lhs->evaluate(context); object v2 = m_rhs->evaluate(context); return v1 == v2; } template<> object operator_expression::evaluate(expression_context& context) { object v1 = m_lhs->evaluate(context); object v2 = m_rhs->evaluate(context); return not (v1 == v2); } template<> object operator_expression::evaluate(expression_context& context) { object v1 = m_lhs->evaluate(context); object v2 = m_rhs->evaluate(context); return v1 < v2; } template<> object operator_expression::evaluate(expression_context& context) { object v1 = m_lhs->evaluate(context); object v2 = m_rhs->evaluate(context); return v1 < v2 or v1 == v2; } template<> object operator_expression::evaluate(expression_context& context) { object v1 = m_lhs->evaluate(context); object v2 = m_rhs->evaluate(context); return v2 < v1; } template<> object operator_expression::evaluate(expression_context& context) { object v1 = m_lhs->evaluate(context); object v2 = m_rhs->evaluate(context); return v2 < v1 or v1 == v2; } template<> object operator_expression::evaluate(expression_context& context) { object v1 = m_lhs->evaluate(context); object v2 = m_rhs->evaluate(context); return v1.as() and v2.as(); } template<> object operator_expression::evaluate(expression_context& context) { object v1 = m_lhs->evaluate(context); object v2 = m_rhs->evaluate(context); return v1.as() or v2.as(); } template<> object operator_expression::evaluate(expression_context& context) { object v1 = m_lhs->evaluate(context); object v2 = m_rhs->evaluate(context); return double(v1.as() % v2.as()); } template<> object operator_expression::evaluate(expression_context& context) { object v1 = m_lhs->evaluate(context); object v2 = m_rhs->evaluate(context); return v1.as() / v2.as(); } template<> object operator_expression::evaluate(expression_context& context) { object v1 = m_lhs->evaluate(context); object v2 = m_rhs->evaluate(context); return v1.as() * v2.as(); } // -------------------------------------------------------------------- class negate_expression : public expression { public: negate_expression(expression_ptr expr) : m_expr(expr) {} virtual object evaluate(expression_context& context); virtual void print(int level) { indent(level); cout << "negate" << endl; m_expr->print(level + 1); } private: expression_ptr m_expr; }; object negate_expression::evaluate(expression_context& context) { object v = m_expr->evaluate(context); return -v.as(); } // -------------------------------------------------------------------- class path_expression : public expression { public: path_expression(expression_ptr lhs, expression_ptr rhs) : m_lhs(lhs), m_rhs(rhs) {} virtual object evaluate(expression_context& context); virtual void print(int level) { indent(level); cout << "path" << endl; m_lhs->print(level + 1); m_rhs->print(level + 1); } private: expression_ptr m_lhs, m_rhs; }; object path_expression::evaluate(expression_context& context) { object v = m_lhs->evaluate(context); if (v.type() != ot_node_set) throw exception("filter does not evaluate to a node-set"); node_set result; foreach (node* n, v.as()) { expression_context ctxt(context, n, v.as()); node_set s = m_rhs->evaluate(ctxt).as(); copy(s.begin(), s.end(), back_inserter(result)); } return result; } // -------------------------------------------------------------------- class predicate_expression : public expression { public: predicate_expression(expression_ptr path, expression_ptr pred) : m_path(path), m_pred(pred) {} virtual object evaluate(expression_context& context); virtual void print(int level) { indent(level); cout << "predicate" << endl; m_path->print(level + 1); m_pred->print(level + 1); } private: expression_ptr m_path, m_pred; }; object predicate_expression::evaluate(expression_context& context) { object v = m_path->evaluate(context); node_set result; foreach (node* n, v.as()) { expression_context ctxt(context, n, v.as()); object test = m_pred->evaluate(ctxt); if (test.type() == ot_number) { if (ctxt.position() == test.as()) result.push_back(n); } else if (test.as()) result.push_back(n); } return result; } // -------------------------------------------------------------------- class variable_expression : public expression { public: variable_expression(const string& name) : m_var(name) {} virtual object evaluate(expression_context& context); virtual void print(int level) { indent(level); cout << "variable " << m_var << endl; } private: string m_var; }; object variable_expression::evaluate(expression_context& context) { return context.get(m_var); } // -------------------------------------------------------------------- class literal_expression : public expression { public: literal_expression(const string& lit) : m_lit(lit) {} virtual object evaluate(expression_context& context); virtual void print(int level) { indent(level); cout << "literal " << m_lit << endl; } private: string m_lit; }; object literal_expression::evaluate(expression_context& context) { return object(m_lit); } // -------------------------------------------------------------------- class number_expression : public expression { public: number_expression(double number) : m_number(number) {} virtual object evaluate(expression_context& context); virtual void print(int level) { indent(level); cout << "number " << m_number << endl; } private: double m_number; }; object number_expression::evaluate(expression_context& context) { return object(m_number); } // -------------------------------------------------------------------- template class core_function_expression : public expression { public: core_function_expression(expression_list& arguments) : m_args(arguments) {} virtual object evaluate(expression_context& context); virtual void print(int level) { indent(level); cout << "function call " << typeid(CF).name() << endl; for_each(m_args.begin(), m_args.end(), boost::bind(&expression::print, _1, level + 1)); } private: expression_list m_args; }; template object core_function_expression::evaluate(expression_context& context) { throw exception("unimplemented function "); return object(); } template<> object core_function_expression::evaluate(expression_context& context) { return object(double(context.position())); } template<> object core_function_expression::evaluate(expression_context& context) { return object(double(context.last())); } template<> object core_function_expression::evaluate(expression_context& context) { object v = m_args.front()->evaluate(context); size_t result = v.as().size(); return object(double(result)); } template<> object core_function_expression::evaluate(expression_context& context) { element* e = nullptr; if (m_args.empty()) e = dynamic_cast(context.m_node); else { object v = m_args.front()->evaluate(context); if (not v.as().empty()) e = dynamic_cast(v.as().front()); } if (e == nullptr) throw exception("argument is not an element in function 'id()'"); return e->id(); } template<> object core_function_expression::evaluate(expression_context& context) { node* n = nullptr; if (m_args.empty()) n = context.m_node; else { object v = m_args.front()->evaluate(context); if (not v.as().empty()) n = v.as().front(); } if (n == nullptr) throw exception("argument is not an element in function 'local-name'"); return n->name(); } template<> object core_function_expression::evaluate(expression_context& context) { node* n = nullptr; if (m_args.empty()) n = context.m_node; else { object v = m_args.front()->evaluate(context); if (not v.as().empty()) n = v.as().front(); } if (n == nullptr) throw exception("argument is not an element in function 'namespace-uri'"); return n->ns(); } template<> object core_function_expression::evaluate(expression_context& context) { node* n = nullptr; if (m_args.empty()) n = context.m_node; else { object v = m_args.front()->evaluate(context); if (not v.as().empty()) n = v.as().front(); } if (n == nullptr) throw exception("argument is not an element in function 'name'"); return n->qname(); } template<> object core_function_expression::evaluate(expression_context& context) { string result; if (m_args.empty()) result = context.m_node->str(); else { object v = m_args.front()->evaluate(context); result = v.as(); } return result; } template<> object core_function_expression::evaluate(expression_context& context) { string result; foreach (expression_ptr& e, m_args) { object v = e->evaluate(context); result += v.as(); } return result; } template<> object core_function_expression::evaluate(expression_context& context) { string result; if (m_args.empty()) result = context.m_node->str(); else { object v = m_args.front()->evaluate(context); result = v.as(); } return double(result.length()); } template<> object core_function_expression::evaluate(expression_context& context) { object v1 = m_args.front()->evaluate(context); object v2 = m_args.back()->evaluate(context); if (v1.type() != ot_string or v2.type() != ot_string) throw exception("expected two strings as argument for starts-with"); return v2.as().empty() or ba::starts_with(v1.as(), v2.as()); } template<> object core_function_expression::evaluate(expression_context& context) { object v1 = m_args.front()->evaluate(context); object v2 = m_args.back()->evaluate(context); if (v1.type() != ot_string or v2.type() != ot_string) throw exception("expected two strings as argument for contains"); return v2.as().empty() or v1.as().find(v2.as()) != string::npos; } template<> object core_function_expression::evaluate(expression_context& context) { object v1 = m_args.front()->evaluate(context); object v2 = m_args.back()->evaluate(context); if (v1.type() != ot_string or v2.type() != ot_string) throw exception("expected two strings as argument for substring-before"); string result; if (not v2.as().empty()) { string::size_type p = v1.as().find(v2.as()); if (p != string::npos) result = v1.as().substr(0, p); } return result; } template<> object core_function_expression::evaluate(expression_context& context) { object v1 = m_args.front()->evaluate(context); object v2 = m_args.back()->evaluate(context); if (v1.type() != ot_string or v2.type() != ot_string) throw exception("expected two strings as argument for substring-after"); string result; if (v2.as().empty()) result = v1.as(); else { string::size_type p = v1.as().find(v2.as()); if (p != string::npos and p + v2.as().length() < v1.as().length()) result = v1.as().substr(p + v2.as().length()); } return result; } template<> object core_function_expression::evaluate(expression_context& context) { expression_list::iterator a = m_args.begin(); object v1 = (*a)->evaluate(context); ++a; object v2 = (*a)->evaluate(context); ++a; object v3 = (*a)->evaluate(context); if (v1.type() != ot_string or v2.type() != ot_number or v3.type() != ot_number) throw exception("expected one string and two numbers as argument for substring"); return v1.as().substr(v2.as() - 1, v3.as()); } template<> object core_function_expression::evaluate(expression_context& context) { string s; if (m_args.empty()) s = context.m_node->str(); else { object v = m_args.front()->evaluate(context); s = v.as(); } string result; bool space = true; foreach (char c, s) { if (isspace(c)) { if (not space) result += ' '; space = true; } else { result += c; space = false; } } if (not result.empty() and space) result.erase(result.end() - 1); return result; } template<> object core_function_expression::evaluate(expression_context& context) { expression_list::iterator a = m_args.begin(); object v1 = (*a)->evaluate(context); ++a; object v2 = (*a)->evaluate(context); ++a; object v3 = (*a)->evaluate(context); if (v1.type() != ot_string or v2.type() != ot_string or v3.type() != ot_string) throw exception("expected three strings as arguments for translate"); const string& f = v2.as(); const string& r = v3.as(); string result; result.reserve(v1.as().length()); foreach (char c, v1.as()) { string::size_type fi = f.find(c); if (fi == string::npos) result += c; else if (fi < r.length()) result += r[fi]; } return result; } template<> object core_function_expression::evaluate(expression_context& context) { object v = m_args.front()->evaluate(context); return v.as(); } template<> object core_function_expression::evaluate(expression_context& context) { object v = m_args.front()->evaluate(context); return not v.as(); } template<> object core_function_expression::evaluate(expression_context& context) { return true; } template<> object core_function_expression::evaluate(expression_context& context) { return false; } template<> object core_function_expression::evaluate(expression_context& context) { object v = m_args.front()->evaluate(context); string test = v.as(); ba::to_lower(test); string lang = context.m_node->lang(); ba::to_lower(lang); bool result = test == lang; string::size_type s; if (result == false and (s = lang.find('-')) != string::npos) result = test == lang.substr(0, s); return result; } template<> object core_function_expression::evaluate(expression_context& context) { object v; if (m_args.size() == 1) v = m_args.front()->evaluate(context); else v = boost::lexical_cast(context.m_node->str()); return v.as(); } template<> object core_function_expression::evaluate(expression_context& context) { object v = m_args.front()->evaluate(context); return floor(v.as()); } template<> object core_function_expression::evaluate(expression_context& context) { object v = m_args.front()->evaluate(context); return ceil(v.as()); } template<> object core_function_expression::evaluate(expression_context& context) { object v = m_args.front()->evaluate(context); return tr1::round(v.as()); } // -------------------------------------------------------------------- class union_expression : public expression { public: union_expression(expression_ptr lhs, expression_ptr rhs) : m_lhs(lhs), m_rhs(rhs) {} virtual object evaluate(expression_context& context); virtual void print(int level) { indent(level); cout << "union" << endl; m_lhs->print(level + 1); m_rhs->print(level + 1); } private: expression_ptr m_lhs, m_rhs; }; object union_expression::evaluate(expression_context& context) { object v1 = m_lhs->evaluate(context); object v2 = m_rhs->evaluate(context); if (v1.type() != ot_node_set or v2.type() != ot_node_set) throw exception("union operator works only on node sets"); node_set s1 = v1.as(); node_set s2 = v2.as(); copy(s2.begin(), s2.end(), back_inserter(s1)); return s1; } // -------------------------------------------------------------------- struct xpath_imp { xpath_imp(); void reference(); void release(); node_set evaluate(node& root, context_imp& context); void parse(const string& path); void preprocess(const string& path); unsigned char next_byte(); unicode get_next_char(); void retract(); Token get_next_token(); string describe_token(Token token); void match(Token token); expression_ptr location_path(); expression_ptr absolute_location_path(); expression_ptr relative_location_path(); expression_ptr step(); expression_ptr node_test(AxisType axis); expression_ptr expr(); expression_ptr primary_expr(); expression_ptr function_call(); expression_ptr argument(); expression_ptr union_expr(); expression_ptr path_expr(); expression_ptr filter_expr(); expression_ptr or_expr(); expression_ptr and_expr(); expression_ptr equality_expr(); expression_ptr relational_expr(); expression_ptr additive_expr(); expression_ptr multiplicative_expr(); expression_ptr unary_expr(); // abbreviated steps are expanded like macros by the scanner string m_path; string::const_iterator m_begin, m_next, m_end; Token m_lookahead; string m_token_string; double m_token_number; AxisType m_token_axis; CoreFunction m_token_function; // the generated expression expression_ptr m_expr; private: ~xpath_imp(); long m_refcount; }; // -------------------------------------------------------------------- xpath_imp::xpath_imp() : m_refcount(1) { } xpath_imp::~xpath_imp() { } void xpath_imp::reference() { ++m_refcount; } void xpath_imp::release() { if (--m_refcount <= 0) delete this; } void xpath_imp::parse(const string& path) { // start by expanding the abbreviations in the path preprocess(path); m_begin = m_next = m_path.begin(); m_end = m_path.end(); m_lookahead = get_next_token(); m_expr = location_path(); while (m_lookahead == xp_OperatorUnion) { match(xp_OperatorUnion); m_expr.reset(new union_expression(m_expr, location_path())); } // if (VERBOSE) // m_expr->print(0); match(xp_EOF); } void xpath_imp::preprocess(const string& path) { // preprocessing consists of expanding abbreviations // replacements are: // @ => replaced by 'attribute::' // // => replaced by '/descendant-or-self::node()/' // . (if at a step location) => 'self::node()' // .. (if at a step location) => 'parent::node()' m_path.clear(); enum State { pp_Step, pp_Data, pp_Dot, pp_Slash, pp_String } state; state = pp_Step; unicode quoteChar = 0; for (string::const_iterator ch = path.begin(); ch != path.end(); ++ch) { switch (state) { case pp_Step: state = pp_Data; switch (*ch) { case '@': m_path += "attribute::"; break; case '.': state = pp_Dot; break; case '/': state = pp_Slash; break; case '\'': case '\"': m_path += *ch; quoteChar = *ch; state = pp_String; break; default: m_path += *ch; break; } break; case pp_Data: switch (*ch) { case '@': m_path += "attribute::"; break; case '/': state = pp_Slash; break; case '[': m_path += '['; state = pp_Step; break; case '\'': case '\"': m_path += *ch; quoteChar = *ch; state = pp_String; break; default: m_path += *ch; break; } break; case pp_Dot: if (*ch == '.') m_path += "parent::node()"; else { --ch; m_path += "self::node()"; } state = pp_Step; break; case pp_Slash: if (*ch == '/') m_path += "/descendant-or-self::node()/"; else { --ch; m_path += '/'; } state = pp_Step; break; case pp_String: m_path += *ch; if (static_cast(*ch) == quoteChar) state = pp_Data; break; } } } unsigned char xpath_imp::next_byte() { char result = 0; if (m_next < m_end) { result = *m_next; ++m_next; } m_token_string += result; return static_cast(result); } // We assume all paths are in valid UTF-8 encoding unicode xpath_imp::get_next_char() { unicode result = 0; unsigned char ch[5]; ch[0] = next_byte(); if ((ch[0] & 0x080) == 0) result = ch[0]; else if ((ch[0] & 0x0E0) == 0x0C0) { ch[1] = next_byte(); if ((ch[1] & 0x0c0) != 0x080) throw exception("Invalid utf-8"); result = ((ch[0] & 0x01F) << 6) | (ch[1] & 0x03F); } else if ((ch[0] & 0x0F0) == 0x0E0) { ch[1] = next_byte(); ch[2] = next_byte(); if ((ch[1] & 0x0c0) != 0x080 or (ch[2] & 0x0c0) != 0x080) throw exception("Invalid utf-8"); result = ((ch[0] & 0x00F) << 12) | ((ch[1] & 0x03F) << 6) | (ch[2] & 0x03F); } else if ((ch[0] & 0x0F8) == 0x0F0) { ch[1] = next_byte(); ch[2] = next_byte(); ch[3] = next_byte(); if ((ch[1] & 0x0c0) != 0x080 or (ch[2] & 0x0c0) != 0x080 or (ch[3] & 0x0c0) != 0x080) throw exception("Invalid utf-8"); result = ((ch[0] & 0x007) << 18) | ((ch[1] & 0x03F) << 12) | ((ch[2] & 0x03F) << 6) | (ch[3] & 0x03F); } if (result > 0x10ffff) throw exception("invalid utf-8 character (out of range)"); return result; } void xpath_imp::retract() { string::iterator c = m_token_string.end(); // skip one valid character back in the input buffer // since we've arrived here, we can safely assume input // is valid UTF-8 do --c; while ((*c & 0x0c0) == 0x080); if (m_next != m_end or *c != 0) m_next -= m_token_string.end() - c; m_token_string.erase(c, m_token_string.end()); } string xpath_imp::describe_token(Token token) { stringstream result; switch (token) { case xp_Undef: result << "undefined"; break; case xp_EOF: result << "end of expression"; break; case xp_LeftParenthesis: result << "left parenthesis"; break; case xp_RightParenthesis: result << "right parenthesis"; break; case xp_LeftBracket: result << "left bracket"; break; case xp_RightBracket: result << "right bracket"; break; case xp_Slash: result << "forward slash"; break; case xp_DoubleSlash: result << "double forward slash"; break; case xp_Comma: result << "comma"; break; case xp_Name: result << "name"; break; case xp_AxisSpec: result << "axis specification"; break; case xp_FunctionName: result << "function name"; break; case xp_NodeType: result << "node type specification"; break; case xp_OperatorUnion: result << "union operator"; break; case xp_OperatorAdd: result << "addition operator"; break; case xp_OperatorSubstract: result << "substraction operator"; break; case xp_OperatorEqual: result << "equals operator"; break; case xp_OperatorNotEqual: result << "not-equals operator"; break; case xp_OperatorLess: result << "less operator"; break; case xp_OperatorLessOrEqual:result << "less-or-equal operator"; break; case xp_OperatorGreater: result << "greater operator"; break; case xp_OperatorGreaterOrEqual: result << "greater-or-equal operator"; break; case xp_OperatorAnd: result << "logical-and operator"; break; case xp_OperatorOr: result << "logical-or operator"; break; case xp_OperatorMod: result << "modulus operator"; break; case xp_OperatorDiv: result << "division operator"; break; case xp_Literal: result << "literal"; break; case xp_Number: result << "number"; break; case xp_Variable: result << "variable"; break; case xp_Asterisk: result << "asterisk (or multiply)"; break; case xp_Colon: result << "colon"; break; } result << " {" << m_token_string << '}'; return result.str(); } Token xpath_imp::get_next_token() { enum State { xps_Start, xps_VariableStart, xps_ExclamationMark, xps_LessThan, xps_GreaterThan, xps_Number, xps_NumberFraction, xps_Name, xps_QName, xps_QName2, xps_Literal } state = xps_Start; Token token = xp_Undef; bool variable = false; double fraction = 1.0; unicode quoteChar = 0; m_token_string.clear(); while (token == xp_Undef) { unicode ch = get_next_char(); switch (state) { case xps_Start: switch (ch) { case 0: token = xp_EOF; break; case '(': token = xp_LeftParenthesis; break; case ')': token = xp_RightParenthesis; break; case '[': token = xp_LeftBracket; break; case ']': token = xp_RightBracket; break; case ',': token = xp_Comma; break; case ':': token = xp_Colon; break; case '$': state = xps_VariableStart; break; case '*': token = xp_Asterisk; break; case '/': token = xp_Slash; break; case '|': token = xp_OperatorUnion; break; case '+': token = xp_OperatorAdd; break; case '-': token = xp_OperatorSubstract; break; case '=': token = xp_OperatorEqual; break; case '!': state = xps_ExclamationMark; break; case '<': state = xps_LessThan; break; case '>': state = xps_GreaterThan; break; case ' ': case '\n': case '\r': case '\t': m_token_string.clear(); break; case '\'': quoteChar = ch; state = xps_Literal; break; case '"': quoteChar = ch; state = xps_Literal; break; case '@': token = xp_AxisSpec; m_token_axis = ax_Attribute; break; default: if (ch == '.') { m_token_number = 0; state = xps_NumberFraction; } else if (ch >= '0' and ch <= '9') { m_token_number = ch - '0'; state = xps_Number; } else if (is_name_start_char(ch)) state = xps_Name; else throw exception("invalid character in xpath"); } break; case xps_ExclamationMark: if (ch != '=') { retract(); throw exception("unexpected character ('!') in xpath"); } token = xp_OperatorNotEqual; break; case xps_LessThan: if (ch == '=') token = xp_OperatorLessOrEqual; else { retract(); token = xp_OperatorLess; } break; case xps_GreaterThan: if (ch == '=') token = xp_OperatorGreaterOrEqual; else { retract(); token = xp_OperatorGreater; } break; case xps_Number: if (ch >= '0' and ch <= '9') m_token_number = 10 * m_token_number + (ch - '0'); else if (ch == '.') { fraction = 0.1; state = xps_NumberFraction; } else { retract(); token = xp_Number; } break; case xps_NumberFraction: if (ch >= '0' and ch <= '9') { m_token_number += fraction * (ch - '0'); fraction /= 10; } else { retract(); token = xp_Number; } break; case xps_VariableStart: if (is_name_start_char(ch)) { variable = true; state = xps_Name; } else throw exception("invalid variable name or lone dollar character"); break; case xps_Name: if (ch == ':') state = xps_QName; else if (not is_name_char(ch)) { retract(); if (variable) token = xp_Variable; else token = xp_Name; } break; case xps_QName: if (ch != ':' and is_name_start_char(ch)) state = xps_QName2; else { retract(); // ch retract(); // ':' if (variable) token = xp_Variable; else token = xp_Name; } break; case xps_QName2: if (ch == ':' or not is_name_char(ch)) { retract(); if (variable) token = xp_Variable; else token = xp_Name; } break; case xps_Literal: if (ch == 0) throw exception("run-away string, missing quote character?"); else if (ch == quoteChar) { token = xp_Literal; m_token_string = m_token_string.substr(1, m_token_string.length() - 2); } break; } } if (token == xp_Name) // we've scanned a name, but it might as well be a function, nodetype or axis { // look forward and see what's ahead for (string::const_iterator c = m_next; c != m_end; ++c) { if (isspace(*c)) continue; if (*c == ':' and *(c + 1) == ':') // it must be an axis specifier { token = xp_AxisSpec; const int kAxisNameCount = sizeof(kAxisNames) / sizeof(const char*); const char** a = find(kAxisNames, kAxisNames + kAxisNameCount, m_token_string); if (*a != nullptr) m_token_axis = AxisType(a - kAxisNames); else throw exception("invalid axis specification %s", m_token_string.c_str()); // skip over the double colon m_next = c + 2; } else if (*c == '(') { if (m_token_string == "comment" or m_token_string == "text" or m_token_string == "processing-instruction" or m_token_string == "node") { token = xp_NodeType; // set input pointer after the parenthesis m_next = c + 1; while (m_next != m_end and isspace(*m_next)) ++m_next; if (*m_next != ')') throw exception("expected '()' after a node type specifier"); ++m_next; } else { for (int i = 0; i < cf_CoreFunctionCount; ++i) { if (m_token_string == kCoreFunctionInfo[i].name) { token = xp_FunctionName; m_token_function = CoreFunction(i); break; } } if (token != xp_FunctionName) throw exception("invalid function %s", m_token_string.c_str()); } } break; } } // if (VERBOSE) // cout << "get_next_token: " << describe_token(token) << endl; return token; } void xpath_imp::match(Token token) { if (m_lookahead == token) m_lookahead = get_next_token(); else { // aargh... syntax error string found = describe_token(m_lookahead); if (m_lookahead != xp_EOF and m_lookahead != xp_Undef) { found += " (\""; found += m_token_string; found += "\")"; } string expected = describe_token(token); stringstream s; s << "syntax error in xpath, expected " << expected << " but found " << found; throw exception(s.str()); } } expression_ptr xpath_imp::location_path() { bool absolute = false; if (m_lookahead == xp_Slash) { absolute = true; match(xp_Slash); } expression_ptr result(relative_location_path()); if (absolute) result.reset(new path_expression(expression_ptr(new root_expression()), result)); return result; } expression_ptr xpath_imp::relative_location_path() { expression_ptr result(step()); while (m_lookahead == xp_Slash) { match(xp_Slash); result.reset(new path_expression(result, step())); } return result; } expression_ptr xpath_imp::step() { expression_ptr result; AxisType axis = ax_Child; if (m_lookahead == xp_AxisSpec) { axis = m_token_axis; match(xp_AxisSpec); } result = node_test(axis); while (m_lookahead == xp_LeftBracket) { match(xp_LeftBracket); result.reset(new predicate_expression(result, expr())); match(xp_RightBracket); } return result; } expression_ptr xpath_imp::node_test(AxisType axis) { expression_ptr result; if (m_lookahead == xp_Asterisk) { result.reset(new name_test_step_expression(axis, m_token_string)); match(xp_Asterisk); } else if (m_lookahead == xp_NodeType) { // see if the name is followed by a parenthesis, if so, it must be a nodetype function string name = m_token_string; match(xp_NodeType); if (name == "comment") result.reset(new node_type_expression(axis)); else if (name == "text") result.reset(new node_type_expression(axis)); else if (name == "processing-instruction") result.reset(new node_type_expression(axis)); else if (name == "node") result.reset(new node_type_expression(axis)); else throw exception("invalid node type specified: %s", name.c_str()); } else { result.reset(new name_test_step_expression(axis, m_token_string)); match(xp_Name); } return result; } expression_ptr xpath_imp::expr() { expression_ptr result(and_expr()); while (m_lookahead == xp_Name and m_token_string == "or") { match(xp_Name); result.reset(new operator_expression(result, and_expr())); } return result; } expression_ptr xpath_imp::primary_expr() { expression_ptr result; switch (m_lookahead) { case xp_Variable: result.reset(new variable_expression(m_token_string.substr(1))); match(xp_Variable); break; case xp_LeftParenthesis: match(xp_LeftParenthesis); result = expr(); match(xp_RightParenthesis); break; case xp_Literal: result.reset(new literal_expression(m_token_string)); match(xp_Literal); break; case xp_Number: result.reset(new number_expression(m_token_number)); match(xp_Number); break; case xp_FunctionName: result = function_call(); break; default: throw exception("invalid primary expression in xpath"); } return result; } expression_ptr xpath_imp::function_call() { CoreFunction function = m_token_function; match(xp_FunctionName); match(xp_LeftParenthesis); expression_list arguments; if (m_lookahead != xp_RightParenthesis) { for (;;) { arguments.push_back(expr()); if (m_lookahead == xp_Comma) match(xp_Comma); else break; } } match(xp_RightParenthesis); expression_ptr result; int expected_arg_count = kCoreFunctionInfo[int(function)].arg_count; if (expected_arg_count > 0) { if (int(arguments.size()) != expected_arg_count) throw exception("invalid number of arguments for function %s", kCoreFunctionInfo[int(function)].name); } else if (expected_arg_count == kOptionalArgument) { if (arguments.size() > 1) throw exception("incorrect number of arguments for function %s", kCoreFunctionInfo[int(function)].name); } else if (expected_arg_count < 0 and int(arguments.size()) < -expected_arg_count) throw exception("insufficient number of arguments for function %s", kCoreFunctionInfo[int(function)].name); switch (function) { case cf_Last: result.reset(new core_function_expression(arguments)); break; case cf_Position: result.reset(new core_function_expression(arguments)); break; case cf_Count: result.reset(new core_function_expression(arguments)); break; case cf_Id: result.reset(new core_function_expression(arguments)); break; case cf_LocalName: result.reset(new core_function_expression(arguments)); break; case cf_NamespaceUri: result.reset(new core_function_expression(arguments)); break; case cf_Name: result.reset(new core_function_expression(arguments)); break; case cf_String: result.reset(new core_function_expression(arguments)); break; case cf_Concat: result.reset(new core_function_expression(arguments)); break; case cf_StartsWith: result.reset(new core_function_expression(arguments)); break; case cf_Contains: result.reset(new core_function_expression(arguments)); break; case cf_SubstringBefore:result.reset(new core_function_expression(arguments)); break; case cf_SubstringAfter: result.reset(new core_function_expression(arguments)); break; case cf_StringLength: result.reset(new core_function_expression(arguments)); break; case cf_NormalizeSpace: result.reset(new core_function_expression(arguments)); break; case cf_Translate: result.reset(new core_function_expression(arguments)); break; case cf_Boolean: result.reset(new core_function_expression(arguments)); break; case cf_Not: result.reset(new core_function_expression(arguments)); break; case cf_True: result.reset(new core_function_expression(arguments)); break; case cf_False: result.reset(new core_function_expression(arguments)); break; case cf_Lang: result.reset(new core_function_expression(arguments)); break; case cf_Number: result.reset(new core_function_expression(arguments)); break; case cf_Sum: result.reset(new core_function_expression(arguments)); break; case cf_Floor: result.reset(new core_function_expression(arguments)); break; case cf_Ceiling: result.reset(new core_function_expression(arguments)); break; case cf_Round: result.reset(new core_function_expression(arguments)); break; case cf_Comment: result.reset(new core_function_expression(arguments)); break; default: break; } return result; } expression_ptr xpath_imp::union_expr() { expression_ptr result(path_expr()); while (m_lookahead == xp_OperatorUnion) { match(m_lookahead); result.reset(new union_expression(result, path_expr())); } return result; } expression_ptr xpath_imp::path_expr() { expression_ptr result; if (m_lookahead == xp_Variable or m_lookahead == xp_LeftParenthesis or m_lookahead == xp_Literal or m_lookahead == xp_Number or m_lookahead == xp_FunctionName) { result = filter_expr(); if (m_lookahead == xp_Slash) { match(xp_Slash); result.reset(new path_expression(result, relative_location_path())); } } else result = location_path(); return result; } expression_ptr xpath_imp::filter_expr() { expression_ptr result(primary_expr()); while (m_lookahead == xp_LeftBracket) { match(xp_LeftBracket); result.reset(new predicate_expression(result, expr())); match(xp_RightBracket); } return result; } expression_ptr xpath_imp::and_expr() { expression_ptr result(equality_expr()); while (m_lookahead == xp_Name and m_token_string == "and") { match(xp_Name); result.reset(new operator_expression(result, equality_expr())); } return result; } expression_ptr xpath_imp::equality_expr() { expression_ptr result(relational_expr()); while (m_lookahead == xp_OperatorEqual or m_lookahead == xp_OperatorNotEqual) { Token op = m_lookahead; match(m_lookahead); if (op == xp_OperatorEqual) result.reset(new operator_expression(result, relational_expr())); else result.reset(new operator_expression(result, relational_expr())); } return result; } expression_ptr xpath_imp::relational_expr() { expression_ptr result(additive_expr()); while (m_lookahead == xp_OperatorLess or m_lookahead == xp_OperatorLessOrEqual or m_lookahead == xp_OperatorGreater or m_lookahead == xp_OperatorGreaterOrEqual) { Token op = m_lookahead; match(m_lookahead); expression_ptr rhs = additive_expr(); switch (op) { case xp_OperatorLess: result.reset(new operator_expression(result, rhs)); break; case xp_OperatorLessOrEqual: result.reset(new operator_expression(result, rhs)); break; case xp_OperatorGreater: result.reset(new operator_expression(result, rhs)); break; case xp_OperatorGreaterOrEqual: result.reset(new operator_expression(result, rhs)); break; default: break; } } return result; } expression_ptr xpath_imp::additive_expr() { expression_ptr result(multiplicative_expr()); while (m_lookahead == xp_OperatorAdd or m_lookahead == xp_OperatorSubstract) { Token op = m_lookahead; match(m_lookahead); if (op == xp_OperatorAdd) result.reset(new operator_expression(result, multiplicative_expr())); else result.reset(new operator_expression(result, multiplicative_expr())); } return result; } expression_ptr xpath_imp::multiplicative_expr() { expression_ptr result(unary_expr()); for (;;) { if (m_lookahead == xp_Asterisk) { match(m_lookahead); result.reset(new operator_expression(result, unary_expr())); continue; } if (m_lookahead == xp_Name and m_token_string == "mod") { match(m_lookahead); result.reset(new operator_expression(result, unary_expr())); continue; } if (m_lookahead == xp_Name and m_token_string == "div") { match(m_lookahead); result.reset(new operator_expression(result, unary_expr())); continue; } break; } return result; } expression_ptr xpath_imp::unary_expr() { expression_ptr result; if (m_lookahead == xp_OperatorSubstract) { match(xp_OperatorSubstract); result.reset(new negate_expression(unary_expr())); } else result = union_expr(); return result; } // -------------------------------------------------------------------- node_set xpath_imp::evaluate(node& root, context_imp& ctxt) { node_set empty; expression_context context(ctxt, &root, empty); return m_expr->evaluate(context).as(); } // -------------------------------------------------------------------- context::context() : m_impl(new context_imp) { } context::~context() { delete m_impl; } template<> void context::set(const string& name, const double& value) { m_impl->set(name, value); } template<> double context::get(const string& name) { return m_impl->get(name).as(); } template<> void context::set(const string& name, const string& value) { m_impl->set(name, value); } template<> string context::get(const string& name) { return m_impl->get(name).as(); } // -------------------------------------------------------------------- xpath::xpath(const string& path) : m_impl(new xpath_imp()) { m_impl->parse(path); } xpath::xpath(const char* path) : m_impl(new xpath_imp()) { string p; if (path != nullptr) p = path; m_impl->parse(p); } xpath::xpath(const xpath& rhs) : m_impl(rhs.m_impl) { m_impl->reference(); } xpath& xpath::operator=(const xpath& rhs) { if (this != &rhs) { m_impl->release(); m_impl = rhs.m_impl; m_impl->reference(); } return *this; } xpath::~xpath() { m_impl->release(); } template<> node_set xpath::evaluate(const node& root) const { context ctxt; return evaluate(root, ctxt); } template<> node_set xpath::evaluate(const node& root, context& ctxt) const { return m_impl->evaluate(const_cast(root), *ctxt.m_impl); } template<> element_set xpath::evaluate(const node& root) const { context ctxt; return evaluate(root, ctxt); } template<> element_set xpath::evaluate(const node& root, context& ctxt) const { element_set result; object s(m_impl->evaluate(const_cast(root), *ctxt.m_impl)); foreach (node* n, s.as()) { element* e = dynamic_cast(n); if (e != nullptr) result.push_back(e); } return result; } bool xpath::matches(const node* n) const { bool result = false; if (n != nullptr) { const node* root = n->root(); context ctxt; object s(m_impl->evaluate(const_cast(*root), *ctxt.m_impl)); foreach (node* e, s.as()) { if (e == n) { result = true; break; } } } return result; } } } libzeep-3.0.2/src/http-server.cpp0000664000175000017500000001552512150661555016604 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008-2011. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include #include #include #include #include #include #include #include #include #include #include #include #define foreach BOOST_FOREACH #include using namespace std; namespace ba = boost::algorithm; namespace zeep { namespace http { namespace detail { // a thread specific logger boost::thread_specific_ptr s_log; boost::mutex s_log_lock; } // -------------------------------------------------------------------- // decode_url function string decode_url(const string& s) { string result; for (string::const_iterator c = s.begin(); c != s.end(); ++c) { if (*c == '%') { if (s.end() - c >= 3) { int value; string s2(c + 1, c + 3); istringstream is(s2); if (is >> hex >> value) { result += static_cast(value); c += 2; } } } else if (*c == '+') result += ' '; else result += *c; } return result; } // -------------------------------------------------------------------- // encode_url function string encode_url(const string& s) { const unsigned char kURLAcceptable[96] = {/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 0,0,0,0,0,0,0,0,0,0,7,6,0,7,7,4, /* 2x !"#$%&'()*+,-./ */ 7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 4x @ABCDEFGHIJKLMNO */ 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7, /* 5X PQRSTUVWXYZ[\]^_ */ 0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 6x `abcdefghijklmno */ 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0 /* 7X pqrstuvwxyz{\}~ DEL */ }; const char kHex[] = "0123456789abcdef"; string result; for (string::const_iterator c = s.begin(); c != s.end(); ++c) { unsigned char a = (unsigned char)*c; if (not (a >= 32 and a < 128 and (kURLAcceptable[a - 32] & 4))) { result += '%'; result += kHex[a >> 4]; result += kHex[a & 15]; } else result += *c; } return result; } // -------------------------------------------------------------------- // http::server server::server() : m_log_forwarded(false) { using namespace boost::local_time; local_time_facet* lf(new local_time_facet("[%d/%b/%Y:%H:%M:%S %z]")); cout.imbue(locale(cout.getloc(), lf)); } void server::bind(const string& address, unsigned short port) { m_address = address; m_port = port; m_acceptor.reset(new boost::asio::ip::tcp::acceptor(m_io_service)); m_new_connection.reset(new connection(m_io_service, *this)); boost::asio::ip::tcp::resolver resolver(m_io_service); boost::asio::ip::tcp::resolver::query query(address, boost::lexical_cast(port)); boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query); m_acceptor->open(endpoint.protocol()); m_acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); m_acceptor->bind(endpoint); m_acceptor->listen(); m_acceptor->async_accept(m_new_connection->get_socket(), boost::bind(&server::handle_accept, this, boost::asio::placeholders::error)); } server::~server() { stop(); } void server::run(int nr_of_threads) { // keep the server at work until we call stop boost::asio::io_service::work work(m_io_service); for (int i = 0; i < nr_of_threads; ++i) { m_threads.create_thread( boost::bind(&boost::asio::io_service::run, &m_io_service)); } m_threads.join_all(); } void server::stop() { if (m_acceptor and m_acceptor->is_open()) m_acceptor->close(); m_io_service.stop(); } void server::handle_accept(const boost::system::error_code& ec) { if (not ec) { m_new_connection->start(); m_new_connection.reset(new connection(m_io_service, *this)); m_acceptor->async_accept(m_new_connection->get_socket(), boost::bind(&server::handle_accept, this, boost::asio::placeholders::error)); } } ostream& server::log() { if (detail::s_log.get() == NULL) detail::s_log.reset(new ostringstream); return *detail::s_log; } void server::handle_request(const request& req, reply& rep) { log() << req.uri; rep = reply::stock_reply(not_found); } void server::handle_request(boost::asio::ip::tcp::socket& socket, const request& req, reply& rep) { using namespace boost::posix_time; detail::s_log.reset(new ostringstream); ptime start = second_clock::local_time(); string referer("-"), userAgent("-"), accept, client; foreach (const header& h, req.headers) { if (m_log_forwarded and h.name == "X-Forwarded-For") { client = h.value; string::size_type comma = client.rfind(','); if (comma != string::npos) { if (comma < client.length() - 1 and client[comma + 1] == ' ') ++comma; client = client.substr(comma + 1, string::npos); } } else if (h.name == "Referer") referer = h.value; else if (h.name == "User-Agent") userAgent = h.value; else if (h.name == "Accept") accept = h.value; } try // asking for the remote endpoint address failed sometimes // causing aborting exceptions, so I moved it here. { if (client.empty()) { boost::asio::ip::address addr = socket.remote_endpoint().address(); client = boost::lexical_cast(addr); } // do the actual work. handle_request(req, rep); // work around buggy IE... also, using req.accept() doesn't work since it contains */* ... duh if (ba::starts_with(rep.get_content_type(), "application/xhtml+xml") and not ba::contains(accept, "application/xhtml+xml") and ba::contains(userAgent, "MSIE")) { rep.set_content_type("text/html; charset=utf-8"); } } catch (...) { rep = reply::stock_reply(internal_server_error); } try { log_request(client, req, rep, start, referer, userAgent, detail::s_log->str()); } catch (...) {} } void server::log_request(const string& client, const request& req, const reply& rep, const boost::posix_time::ptime& start, const string& referer, const string& userAgent, const string& entry) { // protect the output stream from garbled log messages boost::mutex::scoped_lock lock(detail::s_log_lock); using namespace boost::local_time; local_date_time start_local(start, time_zone_ptr()); cout << client << ' ' << "-" << ' ' << "-" << ' ' << start_local << ' ' << '"' << req.method << ' ' << req.uri << ' ' << "HTTP/" << req.http_version_major << '.' << req.http_version_minor << "\" " << rep.get_status() << ' ' << rep.get_size() << ' ' << '"' << referer << '"' << ' ' << '"' << userAgent << '"' << ' '; if (entry.empty()) cout << '-' << endl; else cout << '"' << entry << '"' << endl; } } } libzeep-3.0.2/src/exception.cpp0000664000175000017500000000442111705271513016304 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include #include #include //#include #include using namespace std; namespace zeep { const char* kXML_Parser_Error_Messages[] = { "NONE", "NO_MEMORY", "SYNTAX", "NO_ELEMENTS", "INVALID_TOKEN", "UNCLOSED_TOKEN", "PARTIAL_CHAR", "TAG_MISMATCH", "DUPLICATE_ATTRIBUTE", "JUNK_AFTER_DOC_ELEMENT", "PARAM_ENTITY_REF", "UNDEFINED_ENTITY", "RECURSIVE_ENTITY_REF", "ASYNC_ENTITY", "BAD_CHAR_REF", "BINARY_ENTITY_REF", "ATTRIBUTE_EXTERNAL_ENTITY_REF", "MISPLACED_XML_PI", "UNKNOWN_ENCODING", "INCORRECT_ENCODING", "UNCLOSED_CDATA_SECTION", "EXTERNAL_ENTITY_HANDLING", "NOT_STANDALONE", "UNEXPECTED_STATE", "ENTITY_DECLARED_IN_PE", "FEATURE_REQUIRES_XML_DTD", "CANT_CHANGE_FEATURE_ONCE_PARSING", "UNBOUND_PREFIX", "UNDECLARING_PREFIX", "INCOMPLETE_PE", "XML_DECL", "TEXT_DECL", "PUBLICID", "SUSPENDED", "NOT_SUSPENDED", "ABORTED", "FINISHED", "SUSPEND_PE", "RESERVED_PREFIX_XML", "RESERVED_PREFIX_XMLNS", "RESERVED_NAMESPACE_URI", }; exception::exception( const char* message, ...) { char msg_buffer[1024]; va_list vl; va_start(vl, message); #if defined(_MSC_VER) vsnprintf_s(msg_buffer, sizeof(msg_buffer), _TRUNCATE, message, vl); #else vsnprintf(msg_buffer, sizeof(msg_buffer), message, vl); #endif va_end(vl); m_message = msg_buffer; } //exception::exception( // XML_Parser parser) //{ // try // { // stringstream s; // // XML_Error error = XML_GetErrorCode(parser); // if (error <= XML_ERROR_RESERVED_NAMESPACE_URI) // s << kXML_Parser_Error_Messages[error]; // else // s << "Unknown Expat error code"; // // s << endl // << "Parse error at line " << XML_GetCurrentLineNumber(parser) // << " column " << XML_GetCurrentColumnNumber(parser) // << ":" << endl; // // int offset = 0, size = 0; // const char* context = XML_GetInputContext(parser, &offset, &size); // if (context != nullptr) // s << string(context + offset, size) << endl; // // m_message = s.str(); // } // catch (...) // { // m_message = "oeps"; // } //} } libzeep-3.0.2/src/preforked-http-server.cpp0000664000175000017500000001645312125635713020563 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #if SOAP_SERVER_HAS_PREFORK #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; namespace zeep { namespace http { preforked_server_base::preforked_server_base(server_constructor_base* constructor) : m_constructor(constructor) , m_acceptor(m_io_service) , m_socket(m_io_service) { m_lock.lock(); } preforked_server_base::~preforked_server_base() { if (m_pid > 0) // should never happen { kill(m_pid, SIGKILL); int status; waitpid(m_pid, &status, WUNTRACED | WCONTINUED); } m_io_service.stop(); delete m_constructor; } void preforked_server_base::run(const std::string& address, short port, int nr_of_threads) { try { // create a socket pair to pass the file descriptors through int sockfd[2]; int err = socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd); if (err < 0) throw exception("Error creating socket pair: %s", strerror(errno)); // fork m_pid = fork(); if (m_pid < 0) throw exception("Error forking worker application: %s", strerror(errno)); if (m_pid == 0) // child process { close(sockfd[0]); // remove the blocks on the signal handlers sigset_t wait_mask; sigemptyset(&wait_mask); pthread_sigmask(SIG_SETMASK, &wait_mask, 0); // Time to construct the Server object unique_ptr srvr(m_constructor->construct()); // run the server as a worker boost::thread t(boost::bind(&server::run, srvr.get(), nr_of_threads)); // now start the processing loop passing on file descriptors read // from the parent process try { for (;;) { boost::shared_ptr conn(new connection(srvr->get_io_service(), *srvr)); if (not read_socket_from_parent(sockfd[1], conn->get_socket())) break; conn->start(); } } catch (std::exception& e) { cerr << "Exception caught: " << e.what() << endl; exit(1); } srvr->stop(); t.join(); exit(0); } // first wait until we are allowed to start listening boost::mutex::scoped_lock lock(m_lock); // then bind the address here boost::asio::ip::tcp::resolver resolver(m_io_service); boost::asio::ip::tcp::resolver::query query(address, boost::lexical_cast(port)); boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query); m_acceptor.open(endpoint.protocol()); m_acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); m_acceptor.bind(endpoint); m_acceptor.listen(); m_acceptor.async_accept(m_socket, boost::bind(&preforked_server_base::handle_accept, this, boost::asio::placeholders::error)); // close one end of the pipe, save the other m_fd = sockfd[0]; close(sockfd[1]); // keep the server at work until we call stop boost::asio::io_service::work work(m_io_service); // start a thread to listen to the socket boost::thread thread( boost::bind(&boost::asio::io_service::run, &m_io_service)); thread.join(); // close the socket to the worker, this should terminate the child close(m_fd); m_fd = -1; // however, sometimes it doesn't, so we have to take some serious action // Anyway, we'll wait until child dies to avoid zombies // and to make sure the client really stops... int count = 5; // wait five seconds before killing client int status; while (count-- > 0) { if (waitpid(m_pid, &status, WUNTRACED | WCONTINUED | WNOHANG) == -1) break; if (WIFEXITED(status)) break; sleep(1); } if (not WIFEXITED(status)) kill(m_pid, SIGKILL); } catch (std::exception& e) { cerr << "Exception caught in running server: " << e.what() << endl; } } void preforked_server_base::start() { m_lock.unlock(); } bool preforked_server_base::read_socket_from_parent(int fd_socket, boost::asio::ip::tcp::socket& socket) { typedef boost::asio::ip::tcp::socket::native_type native_type; #if __APPLE__ // macos is special... assert(CMSG_SPACE(sizeof(int)) == 16); #endif struct msghdr msg; union { struct cmsghdr cm; #if __APPLE__ char control[16]; #else char control[CMSG_SPACE(sizeof(int))]; #endif } control_un; msg.msg_control = control_un.control; msg.msg_controllen = sizeof(control_un.control); msg.msg_name = nullptr; msg.msg_namelen = 0; boost::asio::ip::tcp::socket::endpoint_type peer_endpoint; struct iovec iov[1]; iov[0].iov_base = peer_endpoint.data(); iov[0].iov_len = peer_endpoint.capacity(); msg.msg_iov = iov; msg.msg_iovlen = 1; bool result = false; int n = recvmsg(fd_socket, &msg, 0); if (n >= 0) { peer_endpoint.resize(n); struct cmsghdr* cmptr CMSG_FIRSTHDR(&msg); if (cmptr != nullptr and cmptr->cmsg_len == CMSG_LEN(sizeof(int))) { if (cmptr->cmsg_level != SOL_SOCKET) cerr << "control level != SOL_SOCKET" << endl; else if (cmptr->cmsg_type != SCM_RIGHTS) cerr << "control type != SCM_RIGHTS"; else { /* Produces warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] int fd = *(reinterpret_cast(CMSG_DATA(cmptr))); */ native_type *fdptr = reinterpret_cast(CMSG_DATA(cmptr)); int fd = *fdptr; if (fd >= 0) { socket.assign(peer_endpoint.protocol(), fd); result = true; } } } } return result; } void preforked_server_base::write_socket_to_worker(int fd_socket, boost::asio::ip::tcp::socket& socket) { typedef boost::asio::ip::tcp::socket::native_type native_type; struct msghdr msg; union { struct cmsghdr cm; #if __APPLE__ char control[16]; #else char control[CMSG_SPACE(sizeof(native_type))]; #endif } control_un; msg.msg_control = control_un.control; msg.msg_controllen = sizeof(control_un.control); struct cmsghdr* cmptr = CMSG_FIRSTHDR(&msg); cmptr->cmsg_len = CMSG_LEN(sizeof(int)); cmptr->cmsg_level = SOL_SOCKET; cmptr->cmsg_type = SCM_RIGHTS; /* Procudes warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] *(reinterpret_cast(CMSG_DATA(cmptr))) = socket.native(); */ native_type *fdptr = reinterpret_cast(CMSG_DATA(cmptr)); *fdptr = socket.native(); msg.msg_name = nullptr; msg.msg_namelen = 0; struct iovec iov[1]; iov[0].iov_base = socket.remote_endpoint().data(); iov[0].iov_len = socket.remote_endpoint().size(); msg.msg_iov = iov; msg.msg_iovlen = 1; int err = sendmsg(fd_socket, &msg, 0); if (err < 0) throw exception("error passing filedescriptor: %s", strerror(errno)); } void preforked_server_base::stop() { m_io_service.stop(); } void preforked_server_base::handle_accept(const boost::system::error_code& ec) { if (not ec) { write_socket_to_worker(m_fd, m_socket); m_socket.close(); m_acceptor.async_accept(m_socket, boost::bind(&preforked_server_base::handle_accept, this, boost::asio::placeholders::error)); } } } } #endif libzeep-3.0.2/src/unicode_support.cpp0000664000175000017500000000413511727731055017540 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008-2012. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include #include using namespace std; namespace zeep { namespace xml { // some very basic code to check the class of scanned characters bool is_name_start_char(unicode uc) { return uc == L':' or (uc >= L'A' and uc <= L'Z') or uc == L'_' or (uc >= L'a' and uc <= L'z') or (uc >= 0x0C0 and uc <= 0x0D6) or (uc >= 0x0D8 and uc <= 0x0F6) or (uc >= 0x0F8 and uc <= 0x02FF) or (uc >= 0x0370 and uc <= 0x037D) or (uc >= 0x037F and uc <= 0x01FFF) or (uc >= 0x0200C and uc <= 0x0200D) or (uc >= 0x02070 and uc <= 0x0218F) or (uc >= 0x02C00 and uc <= 0x02FEF) or (uc >= 0x03001 and uc <= 0x0D7FF) or (uc >= 0x0F900 and uc <= 0x0FDCF) or (uc >= 0x0FDF0 and uc <= 0x0FFFD) or (uc >= 0x010000 and uc <= 0x0EFFFF); } bool is_name_char(unicode uc) { return uc == '-' or uc == '.' or (uc >= '0' and uc <= '9') or uc == 0x0B7 or is_name_start_char(uc) or (uc >= 0x00300 and uc <= 0x0036F) or (uc >= 0x0203F and uc <= 0x02040); } bool is_valid_system_literal_char(unicode uc) { return uc > 0x1f and uc != ' ' and uc != '<' and uc != '>' and uc != '"' and uc != '#'; } bool is_valid_system_literal(const string& s) { bool result = true; for (string::const_iterator ch = s.begin(); result == true and ch != s.end(); ++ch) result = is_valid_system_literal_char(*ch); return result; } bool is_valid_public_id_char(unicode uc) { static const string kPubChars(" \r\n-'()+,./:=?;!*#@$_%"); return (uc >= 'a' and uc <= 'z') or (uc >= 'A' and uc <= 'Z') or (uc >= '0' and uc <= '9') or (uc < 128 and kPubChars.find(static_cast(uc)) != string::npos); } bool is_valid_public_id(const string& s) { bool result = true; for (string::const_iterator ch = s.begin(); result == true and ch != s.end(); ++ch) result = is_valid_public_id_char(*ch); return result; } } } libzeep-3.0.2/src/parser.cpp0000664000175000017500000024110512125635713015607 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008-2012. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include #include #include #include #include #include #define foreach BOOST_FOREACH #include #include #include #include #include using namespace std; namespace ba = boost::algorithm; //#if DEBUG //extern int VERBOSE; //#endif namespace zeep { namespace xml { // -------------------------------------------------------------------- namespace { template struct value_saver { T& m_ref; T m_value; value_saver(T& value, const T& new_value) : m_ref(value), m_value(value) { m_ref = new_value; } ~value_saver() { m_ref = m_value; } }; class mini_stack { public: mini_stack() : m_ix(-1) {} unicode top() { assert(m_ix >= 0 and m_ix < int(sizeof(m_data) / sizeof(unicode))); return m_data[m_ix]; } void pop() { --m_ix; } void push(unicode uc) { ++m_ix; assert(m_ix < int(sizeof(m_data) / sizeof(unicode))); m_data[m_ix] = uc; } bool empty() const { return m_ix == -1; } private: unicode m_data[2]; int m_ix; }; bool is_absolute_path(const string& s) { bool result = false; if (not s.empty()) { if (s[0] == '/') result = true; else if (isalpha(s[0])) { string::const_iterator ch = s.begin() + 1; while (ch != s.end() and isalpha(*ch)) ++ch; result = ch != s.end() and *ch == ':'; } } return result; } } // parsing XML is somewhat like macro processing, // we can encounter entities that need to be expanded into replacement text // and so we declare data_source objects that can be stacked. class data_source; // exception generated by data_source class source_exception : public zeep::exception { public: source_exception(const string& msg) : exception(msg), m_wmsg(msg) {} ~source_exception() throw () {} string m_wmsg; }; // A data source can have a base dir which is the directory the data came from. // This information is needed when a relative uri is found in an external ID. class data_source { public: data_source(data_source* next) : m_next(next), m_base("."), m_encoding(enc_UTF8), m_line_nr(1) { static int sNextID = 0; m_id = sNextID++; } virtual ~data_source() {} // data_source is a virtual base class. Derivatives need to declare the next function. virtual unicode get_next_char() = 0; // to avoid recursively nested entity values, we have a check: virtual bool is_entity_on_stack(const string& name) { bool result = false; if (m_next != nullptr) result = m_next->is_entity_on_stack(name); return result; } void base(const string& dir) { m_base = dir; } const string& base() const { return m_base; } virtual bool auto_discard() const { return false; } data_source* next_data_source() const { return m_next; } encoding_type encoding() const { return m_encoding; } int id() const { return m_id; } int get_line_nr() const { return m_line_nr; } protected: data_source(const data_source&); data_source& operator=(const data_source&); data_source* m_next; // generates a linked list of data_sources string m_base; encoding_type m_encoding; int m_id; // for nesting checks int m_line_nr; // for reporting errors }; // -------------------------------------------------------------------- // An istream implementation of data_source. class istream_data_source : public data_source { public: istream_data_source(istream& data, data_source* next = nullptr) : data_source(next) , m_data(data) , m_char_buffer(0) , m_has_bom(false) { guess_encoding(); } istream_data_source(istream* data, data_source* next = nullptr) : data_source(next) , m_data(*data) , m_data_ptr(data) , m_char_buffer(0) , m_has_bom(false) { guess_encoding(); } bool has_bom() { return m_has_bom; } private: void guess_encoding(); void parse_text_decl(); virtual unicode get_next_char(); unicode next_utf8_char(); unicode next_utf16le_char(); unicode next_utf16be_char(); unicode next_iso88591_char(); unsigned char next_byte(); istream& m_data; unique_ptr m_data_ptr; unicode m_char_buffer; // used in detecting \r\n algorithm typedef unicode (istream_data_source::*next_func)(void); next_func m_next; bool m_has_bom; }; void istream_data_source::guess_encoding() { // see if there is a BOM // if there isn't, we assume the data is UTF-8 char ch1 = m_data.rdbuf()->sgetc(); if (ch1 == char(0xfe)) { char ch2 = m_data.rdbuf()->snextc(); if (ch2 == char(0xff)) { m_data.rdbuf()->snextc(); m_encoding = enc_UTF16BE; m_has_bom = true; } else m_data.rdbuf()->sungetc(); } else if (ch1 == char(0xff)) { char ch2 = m_data.rdbuf()->snextc(); if (ch2 == char(0xfe)) { m_data.rdbuf()->snextc(); m_encoding = enc_UTF16LE; m_has_bom = true; } else m_data.rdbuf()->sungetc(); } else if (ch1 == char(0xef)) { char ch2 = m_data.rdbuf()->snextc(); char ch3 = m_data.rdbuf()->snextc(); if (ch2 == char(0xbb) and ch3 == char(0xbf)) { m_data.rdbuf()->snextc(); m_encoding = enc_UTF8; m_has_bom = true; } else { m_data.rdbuf()->sungetc(); m_data.rdbuf()->sputbackc(ch1); } } switch (m_encoding) { case enc_UTF8: m_next = &istream_data_source::next_utf8_char; break; case enc_UTF16LE: m_next = &istream_data_source::next_utf16le_char; break; case enc_UTF16BE: m_next = &istream_data_source::next_utf16be_char; break; case enc_ISO88591: m_next = &istream_data_source::next_iso88591_char; break; } } inline unsigned char istream_data_source::next_byte() { int result = m_data.rdbuf()->sbumpc(); if (result == streambuf::traits_type::eof()) result = 0; return static_cast(result); } unicode istream_data_source::next_utf8_char() { unicode result = next_byte(); if (result & 0x080) { unsigned char ch[3]; if ((result & 0x0E0) == 0x0C0) { ch[0] = next_byte(); if ((ch[0] & 0x0c0) != 0x080) throw source_exception("Invalid utf-8"); result = ((result & 0x01F) << 6) | (ch[0] & 0x03F); } else if ((result & 0x0F0) == 0x0E0) { ch[0] = next_byte(); ch[1] = next_byte(); if ((ch[0] & 0x0c0) != 0x080 or (ch[1] & 0x0c0) != 0x080) throw source_exception("Invalid utf-8"); result = ((result & 0x00F) << 12) | ((ch[0] & 0x03F) << 6) | (ch[1] & 0x03F); } else if ((result & 0x0F8) == 0x0F0) { ch[0] = next_byte(); ch[1] = next_byte(); ch[2] = next_byte(); if ((ch[0] & 0x0c0) != 0x080 or (ch[1] & 0x0c0) != 0x080 or (ch[2] & 0x0c0) != 0x080) throw source_exception("Invalid utf-8"); result = ((result & 0x007) << 18) | ((ch[0] & 0x03F) << 12) | ((ch[1] & 0x03F) << 6) | (ch[2] & 0x03F); if (result > 0x10ffff) throw source_exception("invalid utf-8 character (out of range)"); } } return result; } unicode istream_data_source::next_utf16le_char() { unsigned char c1 = next_byte(), c2 = next_byte(); unicode result = (static_cast(c2) << 8) | c1; return result; } unicode istream_data_source::next_utf16be_char() { unsigned char c1 = next_byte(), c2 = next_byte(); unicode result = (static_cast(c1) << 8) | c2; return result; } unicode istream_data_source::next_iso88591_char() { return (unicode)next_byte(); } unicode istream_data_source::get_next_char() { unicode ch = m_char_buffer; if (ch == 0) ch = (this->*m_next)(); else m_char_buffer = 0; if (ch == '\r') { ch = (this->*m_next)(); if (ch != '\n') m_char_buffer = ch; ch = '\n'; } if (ch == '\n') ++m_line_nr; return ch; } // -------------------------------------------------------------------- class string_data_source : public data_source { public: string_data_source(const string& data, data_source* next = nullptr) : data_source(next) , m_data(data) , m_ptr(m_data.begin()) { } private: virtual unicode get_next_char(); string m_data; string::iterator m_ptr; }; unicode string_data_source::get_next_char() { unicode result = 0; if (m_ptr != m_data.end()) { result = static_cast(*m_ptr); ++m_ptr; if (result > 0x07f) { unsigned char ch[3]; if ((result & 0x0E0) == 0x0C0) { ch[0] = static_cast(*m_ptr); ++m_ptr; result = ((result & 0x01F) << 6) | (ch[0] & 0x03F); } else if ((result & 0x0F0) == 0x0E0) { ch[0] = static_cast(*m_ptr); ++m_ptr; ch[1] = static_cast(*m_ptr); ++m_ptr; result = ((result & 0x00F) << 12) | ((ch[0] & 0x03F) << 6) | (ch[1] & 0x03F); } else if ((result & 0x0F8) == 0x0F0) { ch[0] = static_cast(*m_ptr); ++m_ptr; ch[1] = static_cast(*m_ptr); ++m_ptr; ch[2] = static_cast(*m_ptr); ++m_ptr; result = ((result & 0x007) << 18) | ((ch[0] & 0x03F) << 12) | ((ch[1] & 0x03F) << 6) | (ch[2] & 0x03F); } } } if (result == '\n') ++m_line_nr; return result; } // -------------------------------------------------------------------- class entity_data_source : public string_data_source { public: entity_data_source(const string& entity_name, const string& entity_path, const string& text, data_source* next = nullptr) : string_data_source(text, next) , m_entity_name(entity_name) { base(entity_path); } virtual bool is_entity_on_stack(const string& name) { bool result = m_entity_name == name; if (result == false and m_next != nullptr) result = m_next->is_entity_on_stack(name); return result; } protected: string m_entity_name; }; // -------------------------------------------------------------------- class parameter_entity_data_source : public string_data_source { public: parameter_entity_data_source(const string& data, const string& base_dir, data_source* next = nullptr) : string_data_source(string(" ") + data + " ", next) { base(base_dir); } virtual bool auto_discard() const { return m_next != nullptr; } }; // -------------------------------------------------------------------- class valid_nesting_validator { public: valid_nesting_validator(data_source* source) : m_id(source->id()) {} void check(data_source* source) { if (source->id() != m_id) throw invalid_exception("proper nesting validation error"); } private: int m_id; }; // -------------------------------------------------------------------- struct parser_imp { parser_imp( istream& data, parser& parser); ~parser_imp(); // Here comes the parser part void parse(bool validate); // the productions. Some are inlined below for obvious reasons. // names of the productions try to follow those in the TR http://www.w3.org/TR/xml void prolog(); void xml_decl(); void text_decl(); void s(bool at_least_one = false); void eq(); void misc(); void element(doctype::validator& valid); void content(doctype::validator& valid, bool check_for_whitespace); void comment(); void pi(); void pereference(); void doctypedecl(); data_source* external_id(); boost::tuple read_external_id(); void intsubset(); void extsubset(); void declsep(); void conditionalsect(); void ignoresectcontents(); void markup_decl(); void element_decl(); void contentspec(doctype::element& element); doctype::allowed_ptr cp(); void attlist_decl(); void notation_decl(); void entity_decl(); void parameter_entity_decl(); void general_entity_decl(); void entity_value(); // at several locations we need to parse out entity references from strings: void parse_parameter_entity_declaration(string& s); void parse_general_entity_declaration(string& s); // same goes for attribute values string normalize_attribute_value(const string& s) { string_data_source data(s); return normalize_attribute_value(&data); } string normalize_attribute_value(data_source* data); // The scanner is next. We recognize the following tokens: enum XMLToken { xml_Undef, xml_Eof = 256, // these are tokens for the markup xml_XMLDecl, // xml_Content, // anything else up to the next element start }; // for debugging and error reporting we have the following describing routine string describe_token(int token); unicode get_next_char(); // Recognizing tokens differs if we are expecting markup or content in elements: int get_next_token(); int get_next_content(); // retract is used when we've read a character too much from the input stream void retract(); // match, check if the look-a-head token is really what we expect here. // throws if it isn't. Depending on the content flag we call either get_next_token or get_next_content // to find the next look-a-head token. void match(int token); // utility routine float parse_version(); // error handling routines void not_well_formed(const string& msg) const; void not_well_formed(const boost::format& msg) const { not_well_formed(msg.str()); } void not_valid(const string& msg) const; void not_valid(const boost::format& msg) const { not_valid(msg.str()); } // doctype support const doctype::entity& get_general_entity(const string& name) const; const doctype::entity& get_parameter_entity(const string& name) const; const doctype::element* get_element(const string& name) const; // Sometimes we need to reuse our parser/scanner to parse an external entity e.g. // We use stack based state objects to store the current state. struct parser_state { parser_state(parser_imp* imp, data_source* source) : m_impl(imp) , m_lookahead(0) , m_data_source(source) , m_version(1.0f) , m_encoding(enc_UTF8) , m_external_subset(true) , m_external_dtd(false) { swap_state(); } ~parser_state() { swap_state(); if (m_data_source != nullptr and m_data_source->auto_discard()) delete m_data_source; } void swap_state() { swap(m_impl->m_lookahead, m_lookahead); swap(m_impl->m_token, m_token); swap(m_impl->m_data_source, m_data_source); swap(m_impl->m_buffer, m_buffer); swap(m_impl->m_version, m_version); swap(m_impl->m_encoding, m_encoding); swap(m_impl->m_external_subset, m_external_subset); swap(m_impl->m_in_external_dtd, m_external_dtd); } parser_imp* m_impl; int m_lookahead; data_source* m_data_source; mini_stack m_buffer; string m_token; float m_version; encoding_type m_encoding; bool m_external_subset; bool m_external_dtd; }; // And during parsing we keep track of the namespaces we encounter. struct ns_state { ns_state(parser_imp* imp) : m_parser_imp(imp) , m_next(imp->m_ns) { m_parser_imp->m_ns = this; } ~ns_state() { m_parser_imp->m_ns = m_next; } parser_imp* m_parser_imp; string m_default_ns; ns_state* m_next; map m_known; string default_ns() { string result = m_default_ns; if (result.empty() and m_next != nullptr) result = m_next->default_ns(); return result; } string ns_for_prefix(const string& prefix) { string result; if (m_known.find(prefix) != m_known.end()) result = m_known[prefix]; else if (m_next != nullptr) result = m_next->ns_for_prefix(prefix); return result; } }; bool m_validating; bool m_has_dtd; int m_lookahead; data_source* m_data_source; mini_stack m_buffer; string m_token; float m_version; encoding_type m_encoding; bool m_standalone; parser& m_parser; ns_state* m_ns; bool m_in_doctype; // used to keep track where we are (parameter entities are only recognized inside a doctype section) bool m_external_subset; bool m_in_element; bool m_in_content; bool m_in_external_dtd; bool m_allow_parameter_entity_references; string m_root_element; doctype::entity_list m_parameter_entities; doctype::entity_list m_general_entities; doctype::element_list m_doctype; set m_notations; set m_ids; // attributes of type ID should be unique set m_unresolved_ids; // keep track of IDREFS that were not found yet }; // -------------------------------------------------------------------- // some inlines inline void parser_imp::s(bool at_least_one) { if (at_least_one) match(xml_Space); while (m_lookahead == xml_Space) match(xml_Space); } inline void parser_imp::eq() { s(); match('='); s(); } // -------------------------------------------------------------------- parser_imp::parser_imp( istream& data, parser& parser) : m_validating(true) , m_has_dtd(false) , m_lookahead(xml_Eof) , m_data_source(new istream_data_source(data, nullptr)) , m_version(1.0f) , m_standalone(false) , m_parser(parser) , m_ns(nullptr) , m_in_doctype(false) , m_external_subset(false) , m_in_element(false) , m_in_content(false) , m_in_external_dtd(false) , m_allow_parameter_entity_references(false) { m_token.reserve(10000); m_encoding = m_data_source->encoding(); // these entities are always recognized: m_general_entities.push_back(new doctype::general_entity("lt", "<")); m_general_entities.push_back(new doctype::general_entity("gt", ">")); m_general_entities.push_back(new doctype::general_entity("amp", "&")); m_general_entities.push_back(new doctype::general_entity("apos", "'")); m_general_entities.push_back(new doctype::general_entity("quot", """)); } parser_imp::~parser_imp() { // there may be parameter_entity_data_source's left in the stack // as a result of a validation error/exception while (m_data_source->auto_discard()) { data_source* next = m_data_source->next_data_source(); delete m_data_source; m_data_source = next; } foreach (doctype::entity* e, m_parameter_entities) delete e; foreach (doctype::entity* e, m_general_entities) delete e; foreach (doctype::element* e, m_doctype) delete e; delete m_data_source; } const doctype::entity& parser_imp::get_general_entity(const string& name) const { doctype::entity_list::const_iterator e = find_if(m_general_entities.begin(), m_general_entities.end(), boost::bind(&doctype::entity::name, _1) == name); if (e == m_general_entities.end()) not_well_formed(boost::format("undefined entity reference '%1%'") % name); return **e; } const doctype::entity& parser_imp::get_parameter_entity(const string& name) const { doctype::entity_list::const_iterator e = find_if(m_parameter_entities.begin(), m_parameter_entities.end(), boost::bind(&doctype::entity::name, _1) == name); if (e == m_parameter_entities.end()) { boost::format msg("Undefined parameter entity '%1%'"); if (m_standalone) not_well_formed(msg % m_token); else not_valid(msg % m_token); throw zeep::exception(msg.str()); } return **e; } const doctype::element* parser_imp::get_element(const string& name) const { const doctype::element* result = nullptr; doctype::element_list::const_iterator e = find_if(m_doctype.begin(), m_doctype.end(), boost::bind(&doctype::element::name, _1) == name); if (e != m_doctype.end()) result = *e; return result; } unicode parser_imp::get_next_char() { unicode result = 0; if (not m_buffer.empty()) // if buffer is not empty we already did all the validity checks { result = m_buffer.top(); m_buffer.pop(); } else { for (;;) { try { result = m_data_source->get_next_char(); } catch (source_exception& e) { not_well_formed(e.m_wmsg); } if (result == 0 and m_data_source->auto_discard()) { data_source* next = m_data_source->next_data_source(); delete m_data_source; m_data_source = next; if (m_data_source != nullptr) continue; } break; } if (result >= 0x080) { if (result == 0x0ffff or result == 0x0fffe) not_well_formed(boost::format("character 0x%x is not allowed") % int(result)); // surrogate support else if (result >= 0x0D800 and result <= 0x0DBFF) { unicode uc2 = get_next_char(); if (uc2 >= 0x0DC00 and uc2 <= 0x0DFFF) result = (result - 0x0D800) * 0x400 + (uc2 - 0x0DC00) + 0x010000; else not_well_formed("leading surrogate character without trailing surrogate character"); } else if (result >= 0x0DC00 and result <= 0x0DFFF) not_well_formed("trailing surrogate character without a leading surrogate"); } } // append(m_token, result); // somehow, append refuses to inline, so we have to do it ourselves if (result < 0x080) m_token += (static_cast (result)); else if (result < 0x0800) { char ch[2] = { static_cast (0x0c0 | (result >> 6)), static_cast (0x080 | (result & 0x3f)) }; m_token.append(ch, 2); } else if (result < 0x00010000) { char ch[3] = { static_cast (0x0e0 | (result >> 12)), static_cast (0x080 | ((result >> 6) & 0x3f)), static_cast (0x080 | (result & 0x3f)) }; m_token.append(ch, 3); } else { char ch[4] = { static_cast (0x0f0 | (result >> 18)), static_cast (0x080 | ((result >> 12) & 0x3f)), static_cast (0x080 | ((result >> 6) & 0x3f)), static_cast (0x080 | (result & 0x3f)) }; m_token.append(ch, 4); } return result; } void parser_imp::retract() { assert(not m_token.empty()); m_buffer.push(pop_last_char(m_token)); } void parser_imp::match(int token) { if (m_lookahead != token) { string expected = describe_token(token); string found = describe_token(m_lookahead); not_well_formed(boost::format("Error parsing XML, expected '%1%' but found '%2%' ('%3%')") % expected % found % m_token); } if (m_in_content) m_lookahead = get_next_content(); else { m_lookahead = get_next_token(); if (m_lookahead == xml_PEReference and m_allow_parameter_entity_references) pereference(); } } void parser_imp::not_well_formed(const string& msg) const { stringstream s; s << "Document (line: " << m_data_source->get_line_nr() << ") not well-formed: " << msg; throw not_wf_exception(s.str()); } void parser_imp::not_valid(const string& msg) const { if (m_validating) { stringstream s; s << "Document (line: " << m_data_source->get_line_nr() << ") invalid: " << msg; throw invalid_exception(s.str()); } else m_parser.report_invalidation(msg); } /* get_next_token is a hand optimised scanner for tokens in the input stream. */ int parser_imp::get_next_token() { enum State { state_Start = 0, state_WhiteSpace = 10, state_Tag = 20, state_String = 30, state_PERef = 40, state_Name = 50, state_CommentOrDoctype = 60, state_Comment = 70, state_DocTypeDecl = 80, state_PI = 90, }; int token = xml_Undef; unicode quote_char = 0; int state = state_Start; bool might_be_name = false; m_token.clear(); while (token == xml_Undef) { unicode uc = get_next_char(); switch (state) { // start scanning. case state_Start: if (uc == 0) token = xml_Eof; else if (uc == ' ' or uc == '\t' or uc == '\n') state = state_WhiteSpace; else if (uc == '<') state = state_Tag; else if (uc == '\'' or uc == '\"') { state = state_String; quote_char = uc; } else if (uc == '%') state = state_PERef; else if (is_name_start_char(uc)) { might_be_name = true; state = state_Name; } else if (is_name_char(uc)) state = state_Name; else token = uc; break; // collect all whitespace case state_WhiteSpace: if (uc != ' ' and uc != '\t' and uc != '\n') { retract(); token = xml_Space; } break; // We scanned a < character, decide what to do next. case state_Tag: if (uc == '!') // comment or doctype thing state = state_CommentOrDoctype; else if (uc == '/') // end tag token = xml_ETag; else if (uc == '?') // processing instruction state = state_PI; else // anything else { retract(); token = xml_STag; } break; // So we had case state_Comment: if (uc == '-') token = xml_Comment; else not_well_formed("Invalid formatted comment"); break; // scan for processing instructions case state_PI: if (not is_name_char(uc)) { retract(); // we treat the xml processing instruction separately. if (m_token.substr(2) == "xml") token = xml_XMLDecl; else if (ba::to_lower_copy(m_token.substr(2)) == "xml") not_well_formed(" in text else if (is_char(uc)) state = state_Content; // anything else break; // content. Only stop collecting character when uc is special case state_Content: if (uc == ']') state = state_Illegal; else if (uc == 0 or uc == '<' or uc == '&') { retract(); token = xml_Content; } else if (not is_char(uc)) not_well_formed("Illegal character in content text"); break; // beginning of a tag? case state_Tag: if (uc == '/') token = xml_ETag; else if (uc == '?') // processing instruction state = state_PI; else if (uc == '!') // comment or CDATA state = state_CommentOrCDATA; else { retract(); token = xml_STag; } break; // processing instructions case state_PI: if (not is_name_char(uc)) { retract(); token = xml_PI; } break; // comment or CDATA case state_CommentOrCDATA: if (uc == '-') // comment state = state_Comment; else if (uc == '[') state = state_CDATA; // CDATA else not_well_formed("invalid content"); break; case state_Comment: if (uc == '-') token = xml_Comment; else not_well_formed("invalid content"); break; // CDATA (we parsed ') { token = xml_CDSect; m_token = m_token.substr(9, m_token.length() - 12); } else if (uc == 0) not_well_formed("runaway cdata section"); else if (uc != ']') state = state_CDATA + 2; break; // reference, either a character reference or a general entity reference case state_Reference: if (uc == '#') state = state_Reference + 2; else if (is_name_start_char(uc)) state = state_Reference + 1; else not_well_formed("stray ampersand found in content"); break; case state_Reference + 1: if (not is_name_char(uc)) { if (uc != ';') not_well_formed("invalid entity found in content, missing semicolon?"); token = xml_Reference; m_token = m_token.substr(1, m_token.length() - 2); } break; case state_Reference + 2: if (uc == 'x') state = state_Reference + 4; else if (uc >= '0' and uc <= '9') { charref = uc - '0'; state += 1; } else not_well_formed("invalid character reference"); break; case state_Reference + 3: if (uc >= '0' and uc <= '9') charref = charref * 10 + (uc - '0'); else if (uc == ';') { if (not is_char(charref)) not_well_formed("Illegal character in content text"); m_token.clear(); append(m_token, charref); token = xml_Content; } else not_well_formed("invalid character reference"); break; case state_Reference + 4: if (uc >= 'a' and uc <= 'f') { charref = uc - 'a' + 10; state += 1; } else if (uc >= 'A' and uc <= 'F') { charref = uc - 'A' + 10; state += 1; } else if (uc >= '0' and uc <= '9') { charref = uc - '0'; state += 1; } else not_well_formed("invalid character reference"); break; case state_Reference + 5: if (uc >= 'a' and uc <= 'f') charref = (charref << 4) + (uc - 'a' + 10); else if (uc >= 'A' and uc <= 'F') charref = (charref << 4) + (uc - 'A' + 10); else if (uc >= '0' and uc <= '9') charref = (charref << 4) + (uc - '0'); else if (uc == ';') { if (not is_char(charref)) not_well_formed("Illegal character in content text"); m_token.clear(); append(m_token, charref); token = xml_Content; } else not_well_formed("invalid character reference"); break; // ]]> is illegal case state_Illegal: if (uc == ']') state += 1; else { retract(); state = state_Content; } break; case state_Illegal + 1: if (uc == '>') not_well_formed("the sequence ']]>' is illegal in content text"); else if (uc != ']') { retract(); retract(); state = state_Content; } break; default: assert(false); not_well_formed("state reached that should not be reachable"); } } //#if DEBUG // if (VERBOSE) // cout << "content: " << describe_token(token) << " (" << m_token << ')' << endl; //#endif return token; } string parser_imp::describe_token(int token) { string result; if (token > xml_Undef and token < xml_Eof) { stringstream s; if (isprint(token)) s << char(token); else s << "&#x" << hex << token << ';'; result = s.str(); } else { switch (XMLToken(token)) { case xml_Undef: result = "undefined"; break; case xml_Eof: result = "end of file"; break; case xml_XMLDecl: result = "'= 3) { string::const_iterator i = m_token.begin(); if (*i == '1' and *(i + 1) == '.') { result = 1.0f; float dec = 10; for (i += 2; i != m_token.end(); ++i) { if (*i < '0' or *i > '9') { result = -1; break; } result += (*i - '0') / dec; dec += 10; } } } if (result < 1.0 or result >= 2.0) not_well_formed(boost::format("Invalid version specified: '%1%'") % m_token); return result; } void parser_imp::parse(bool validate) { m_validating = validate; m_lookahead = get_next_token(); prolog(); doctype::validator valid; const doctype::element* e = get_element(m_root_element); if (m_has_dtd and e == nullptr and m_validating) not_valid(boost::format("Element '%1%' is not defined in DTD") % m_root_element); unique_ptr allowed(new doctype::allowed_element(m_root_element)); if (e != nullptr) valid = doctype::validator(allowed.get()); element(valid); misc(); if (m_lookahead != xml_Eof) not_well_formed("garbage at end of file"); if (not m_unresolved_ids.empty()) { not_valid(boost::format("document contains references to the following undefined ID's: '%1%'") % ba::join(m_unresolved_ids, ", ")); } } void parser_imp::prolog() { xml_decl(); misc(); if (m_lookahead == xml_DocType) { doctypedecl(); misc(); } else if (m_validating) not_valid("document type declaration is missing"); } void parser_imp::xml_decl() { if (m_lookahead == xml_XMLDecl) { match(xml_XMLDecl); s(true); if (m_token != "version") not_well_formed("expected a version attribute in XML declaration"); match(xml_Name); eq(); m_version = parse_version(); if (m_version >= 2.0 or m_version < 1.0) not_well_formed("This library only supports XML version 1.x"); match(xml_String); if (m_lookahead == xml_Space) { s(true); if (m_token == "encoding") { match(xml_Name); eq(); ba::to_upper(m_token); if (m_token == "UTF-8" or m_token == "US-ASCII") // ascii is a subset of utf-8 m_encoding = enc_UTF8; else if (m_token == "UTF-16") { if (m_encoding != enc_UTF16LE and m_encoding != enc_UTF16BE) not_well_formed("Inconsistent encoding attribute in XML declaration"); // cerr << "Inconsistent encoding attribute in XML declaration" << endl; m_encoding = enc_UTF16BE; } else if (m_token == "ISO-8859-1") m_encoding = enc_ISO88591; else not_well_formed(boost::format("Unsupported encoding value '%1%'") % m_token); match(xml_String); s(); } if (m_token == "standalone") { match(xml_Name); eq(); if (m_token != "yes" and m_token != "no") not_well_formed("Invalid XML declaration, standalone value should be either yes or no"); m_standalone = (m_token == "yes"); match(xml_String); s(); } } match('?'); match('>'); } } void parser_imp::text_decl() { if (m_lookahead == xml_XMLDecl) { match(xml_XMLDecl); s(true); if (m_token == "version") { match(xml_Name); eq(); m_version = parse_version(); if (m_version >= 2.0 or m_version < 1.0) throw exception("This library only supports XML version 1.x"); match(xml_String); s(true); } if (m_token != "encoding") not_well_formed("encoding attribute is mandatory in text declaration"); match(xml_Name); eq(); match(xml_String); s(); match('?'); match('>'); } } void parser_imp::misc() { for (;;) { switch (m_lookahead) { case xml_Space: s(); continue; case xml_Comment: comment(); continue; case xml_PI: pi(); continue; } break; } } void parser_imp::doctypedecl() { value_saver in_doctype(m_in_doctype, true); value_saver allow_parameter_entity_references(m_allow_parameter_entity_references, false); match(xml_DocType); m_has_dtd = true; s(true); string name = m_token; match(xml_Name); m_root_element = name; unique_ptr dtd; if (m_lookahead == xml_Space) { s(true); if (m_lookahead == xml_Name) { dtd.reset(external_id()); match(xml_String); } s(); } if (m_lookahead == '[') { match('['); intsubset(); match(']'); s(); } // internal subset takes precedence over external subset, so // if the external subset is defined, include it here. if (dtd.get() != nullptr) { // save the parser state parser_state save(this, dtd.get()); m_data_source = dtd.get(); m_lookahead = get_next_token(); m_in_external_dtd = true; text_decl(); extsubset(); if (m_lookahead != xml_Eof) not_well_formed("Error parsing external dtd"); m_in_external_dtd = false; } match('>'); // test if all ndata references can be resolved foreach (const doctype::entity* e, m_general_entities) { if (e->parsed() == false and m_notations.count(e->ndata()) == 0) not_valid(boost::format("Undefined NOTATION '%1%'") % e->ndata()); } // and the notations in the doctype attlists foreach (const doctype::element* element, m_doctype) { foreach (const doctype::attribute* attr, element->attributes()) { if (attr->get_type() != doctype::attTypeNotation) continue; foreach (const string& n, attr->get_enums()) { if (m_notations.count(n) == 0) not_valid(boost::format("Undefined NOTATION '%1%'") % n); } } } } void parser_imp::pereference() { const doctype::entity& e = get_parameter_entity(m_token); m_data_source = new parameter_entity_data_source(e.replacement(), e.path(), m_data_source); match(xml_PEReference); } void parser_imp::intsubset() { value_saver allow_parameter_entity_references(m_allow_parameter_entity_references, false); for (;;) { switch (m_lookahead) { case xml_Element: case xml_AttList: case xml_Entity: case xml_Notation: markup_decl(); continue; case xml_PI: pi(); continue; case xml_Comment: comment(); continue; case xml_Space: case xml_PEReference: declsep(); continue; } break; } } void parser_imp::declsep() { switch (m_lookahead) { case xml_PEReference: { const doctype::entity& e = get_parameter_entity(m_token); { parameter_entity_data_source source(e.replacement(), e.path()); parser_state state(this, &source); m_lookahead = get_next_token(); extsubset(); if (m_lookahead != xml_Eof) not_well_formed("parameter entity replacement should match external subset production"); } match(xml_PEReference); break; } case xml_Space: s(); break; } } void parser_imp::extsubset() { value_saver save(m_external_subset, true); value_saver allow_parameter_entity_references(m_allow_parameter_entity_references, false); for (;;) { switch (m_lookahead) { case xml_Element: case xml_AttList: case xml_Entity: case xml_Notation: markup_decl(); continue; case xml_IncludeIgnore: conditionalsect(); continue; case xml_PI: pi(); continue; case xml_Comment: comment(); continue; case xml_Space: case xml_PEReference: declsep(); continue; } break; } } void parser_imp::conditionalsect() { valid_nesting_validator check(m_data_source); match(xml_IncludeIgnore); s(); bool include = false; if (m_lookahead == xml_PEReference) { pereference(); s(); } if (m_token == "INCLUDE") include = true; else if (m_token == "IGNORE") include = false; else if (m_lookahead == xml_Name) not_well_formed(boost::format("Unexpected literal '%1%'") % m_token); match(xml_Name); check.check(m_data_source); s(); if (include) { match('['); extsubset(); match(']'); match (']'); check.check(m_data_source); match ('>'); } else { ignoresectcontents(); check.check(m_data_source); m_lookahead = get_next_token(); } } void parser_imp::ignoresectcontents() { // yet another tricky routine, skip int state = 0; bool done = false; while (not done) { unicode ch = get_next_char(); if (ch == 0) not_well_formed("runaway IGNORE section"); switch (state) { case 0: if (ch == ']') state = 1; else if (ch == '<') state = 10; break; case 1: if (ch == ']') state = 2; else { retract(); state = 0; } break; case 2: if (ch == '>') done = true; else if (ch != ']') { retract(); state = 0; } break; case 10: if (ch == '!') state = 11; else { retract(); state = 0; } break; case 11: if (ch == '[') { ignoresectcontents(); state = 0; } else { retract(); state = 0; } break; } } } void parser_imp::markup_decl() { value_saver allow_parameter_entity_references( m_allow_parameter_entity_references, m_external_subset); switch (m_lookahead) { case xml_Element: element_decl(); break; case xml_AttList: attlist_decl(); break; case xml_Entity: entity_decl(); break; case xml_Notation: notation_decl(); break; case xml_PI: pi(); break; case xml_Comment: comment(); break; case xml_Space: s(); break; } } void parser_imp::element_decl() { valid_nesting_validator check(m_data_source); match(xml_Element); s(true); string name = m_token; doctype::element_list::iterator e = find_if(m_doctype.begin(), m_doctype.end(), boost::bind(&doctype::element::name, _1) == name); if (e == m_doctype.end()) e = m_doctype.insert(m_doctype.end(), new doctype::element(name, true, m_in_external_dtd)); else if ((*e)->declared()) not_valid(boost::format("duplicate element declaration for element '%1%'") % name); else (*e)->external(m_in_external_dtd); match(xml_Name); s(true); contentspec(**e); s(); m_allow_parameter_entity_references = true; check.check(m_data_source); match('>'); } void parser_imp::contentspec(doctype::element& element) { if (m_lookahead == xml_Name) { if (m_token == "EMPTY") element.set_allowed(new doctype::allowed_empty); else if (m_token == "ANY") element.set_allowed(new doctype::allowed_any); else not_well_formed("Invalid element content specification"); match(xml_Name); } else { valid_nesting_validator check(m_data_source); match('('); unique_ptr allowed; s(); bool mixed = false; bool more = false; if (m_lookahead == '#') // Mixed { mixed = true; match(m_lookahead); if (m_token != "PCDATA") not_well_formed("Invalid element content specification, expected #PCDATA"); match(xml_Name); s(); set seen; while (m_lookahead == '|') { more = true; match('|'); s(); if (seen.count(m_token) > 0) not_valid("no duplicates allowed in mixed content for element declaration"); seen.insert(m_token); match(xml_Name); s(); } doctype::allowed_choice* choice = new doctype::allowed_choice(true); foreach (const string& c, seen) choice->add(new doctype::allowed_element(c)); allowed.reset(choice); } else // children { allowed.reset(cp()); s(); if (m_lookahead == ',') { doctype::allowed_seq* seq = new doctype::allowed_seq(allowed.release()); allowed.reset(seq); more = true; do { match(m_lookahead); s(); seq->add(cp()); s(); } while (m_lookahead == ','); } else if (m_lookahead == '|') { doctype::allowed_choice* choice = new doctype::allowed_choice(allowed.release(), false); allowed.reset(choice); more = true; do { match(m_lookahead); s(); choice->add(cp()); s(); } while (m_lookahead == '|'); } } s(); check.check(m_data_source); match(')'); if (m_lookahead == '*') { allowed.reset(new doctype::allowed_repeated(allowed.release(), '*')); match('*'); } else if (more) { if (mixed) { allowed.reset(new doctype::allowed_repeated(allowed.release(), '*')); match('*'); } else if (m_lookahead == '+') { allowed.reset(new doctype::allowed_repeated(allowed.release(), '+')); match('+'); } else if (m_lookahead == '?') { allowed.reset(new doctype::allowed_repeated(allowed.release(), '?')); match('?'); } } element.set_allowed(allowed.release()); } } doctype::allowed_ptr parser_imp::cp() { unique_ptr result; if (m_lookahead == '(') { valid_nesting_validator check(m_data_source); match('('); s(); result.reset(cp()); s(); if (m_lookahead == ',') { doctype::allowed_seq* seq = new doctype::allowed_seq(result.release()); result.reset(seq); do { match(m_lookahead); s(); seq->add(cp()); s(); } while (m_lookahead == ','); } else if (m_lookahead == '|') { doctype::allowed_choice* choice = new doctype::allowed_choice(result.release(), false); result.reset(choice); do { match(m_lookahead); s(); choice->add(cp()); s(); } while (m_lookahead == '|'); } s(); check.check(m_data_source); match(')'); } else { string name = m_token; match(xml_Name); result.reset(new doctype::allowed_element(name)); } switch (m_lookahead) { case '*': result.reset(new doctype::allowed_repeated(result.release(), '*')); match('*'); break; case '+': result.reset(new doctype::allowed_repeated(result.release(), '+')); match('+'); break; case '?': result.reset(new doctype::allowed_repeated(result.release(), '?')); match('?'); break; } return result.release(); } void parser_imp::entity_decl() { value_saver allow_parameter_entity_references(m_allow_parameter_entity_references, true); match(xml_Entity); s(true); if (m_lookahead == '%') // PEDecl parameter_entity_decl(); else general_entity_decl(); } void parser_imp::parameter_entity_decl() { match('%'); s(true); string name = m_token; match(xml_Name); s(true); string path; string value; m_allow_parameter_entity_references = false; // PEDef is either a EntityValue... if (m_lookahead == xml_String) { value = m_token; match(xml_String); parse_parameter_entity_declaration(value); } else // ... or an external id { boost::tie(path, value) = read_external_id(); match(xml_String); } s(); m_allow_parameter_entity_references = true; match('>'); if (find_if(m_parameter_entities.begin(), m_parameter_entities.end(), boost::bind(&doctype::entity::name, _1) == name) == m_parameter_entities.end()) { m_parameter_entities.push_back(new doctype::parameter_entity(name, value, path)); } } void parser_imp::general_entity_decl() { string name = m_token; match(xml_Name); s(true); string value, ndata; bool external = false; bool parsed = true; if (m_lookahead == xml_String) { value = m_token; match(xml_String); parse_general_entity_declaration(value); } else // ... or an ExternalID { string path; // not used boost::tie(path, value) = read_external_id(); match(xml_String); external = true; if (m_lookahead == xml_Space) { s(true); if (m_lookahead == xml_Name and m_token == "NDATA") { match(xml_Name); s(true); parsed = false; ndata = m_token; match(xml_Name); } } } s(); m_allow_parameter_entity_references = true; match('>'); if (find_if(m_general_entities.begin(), m_general_entities.end(), boost::bind(&doctype::entity::name, _1) == name) == m_general_entities.end()) { m_general_entities.push_back(new doctype::general_entity(name, value, external, parsed)); if (not parsed) m_general_entities.back()->ndata(ndata); if (m_in_external_dtd) m_general_entities.back()->externally_defined(true); } } void parser_imp::attlist_decl() { match(xml_AttList); s(true); string element = m_token; match(xml_Name); doctype::element_list::iterator dte = find_if(m_doctype.begin(), m_doctype.end(), boost::bind(&doctype::element::name, _1) == element); if (dte == m_doctype.end()) dte = m_doctype.insert(m_doctype.end(), new doctype::element(element, false, m_in_external_dtd)); // attdef while (m_lookahead == xml_Space) { s(true); if (m_lookahead != xml_Name) break; string name = m_token; match(xml_Name); s(true); unique_ptr attribute; // att type: several possibilities: if (m_lookahead == '(') // enumeration { vector enums; match(m_lookahead); s(); enums.push_back(m_token); if (m_lookahead == xml_Name) match(xml_Name); else match(xml_NMToken); s(); while (m_lookahead == '|') { match('|'); s(); enums.push_back(m_token); if (m_lookahead == xml_Name) match(xml_Name); else match(xml_NMToken); s(); } s(); match(')'); attribute.reset(new doctype::attribute(name, doctype::attTypeEnumerated, enums)); } else { string type = m_token; match(xml_Name); vector notations; if (type == "CDATA") attribute.reset(new doctype::attribute(name, doctype::attTypeString)); else if (type == "ID") attribute.reset(new doctype::attribute(name, doctype::attTypeTokenizedID)); else if (type == "IDREF") attribute.reset(new doctype::attribute(name, doctype::attTypeTokenizedIDREF)); else if (type == "IDREFS") attribute.reset(new doctype::attribute(name, doctype::attTypeTokenizedIDREFS)); else if (type == "ENTITY") attribute.reset(new doctype::attribute(name, doctype::attTypeTokenizedENTITY)); else if (type == "ENTITIES") attribute.reset(new doctype::attribute(name, doctype::attTypeTokenizedENTITIES)); else if (type == "NMTOKEN") attribute.reset(new doctype::attribute(name, doctype::attTypeTokenizedNMTOKEN)); else if (type == "NMTOKENS") attribute.reset(new doctype::attribute(name, doctype::attTypeTokenizedNMTOKENS)); else if (type == "NOTATION") { s(true); match('('); s(); notations.push_back(m_token); match(xml_Name); s(); while (m_lookahead == '|') { match('|'); s(); notations.push_back(m_token); match(xml_Name); s(); } s(); match(')'); attribute.reset(new doctype::attribute(name, doctype::attTypeNotation, notations)); } else not_well_formed("invalid attribute type"); } // att def s(true); string value; if (m_lookahead == '#') { match(m_lookahead); string def = m_token; match(xml_Name); if (def == "REQUIRED") attribute->set_default(doctype::attDefRequired, ""); else if (def == "IMPLIED") attribute->set_default(doctype::attDefImplied, ""); else if (def == "FIXED") { if (attribute->get_type() == doctype::attTypeTokenizedID) not_valid("the default declaration for an ID attribute declaration should be #IMPLIED or #REQUIRED"); s(true); string value = m_token; normalize_attribute_value(value); if (not value.empty() and not attribute->validate_value(value, m_general_entities)) { not_valid(boost::format("default value '%1%' for attribute '%2%' is not valid") % value % name); } attribute->set_default(doctype::attDefFixed, value); match(xml_String); } else not_well_formed("invalid attribute default"); } else { if (attribute->get_type() == doctype::attTypeTokenizedID) not_valid("the default declaration for an ID attribute declaration should be #IMPLIED or #REQUIRED"); string value = m_token; normalize_attribute_value(value); if (not value.empty() and not attribute->validate_value(value, m_general_entities)) { not_valid(boost::format("default value '%1%' for attribute '%2%' is not valid") % value % name); } attribute->set_default(doctype::attDefNone, value); match(xml_String); } if (attribute->get_type() == doctype::attTypeTokenizedID) { const doctype::attribute_list& atts = (*dte)->attributes(); if (find_if(atts.begin(), atts.end(), boost::bind(&doctype::attribute::get_type, _1) == doctype::attTypeTokenizedID) != atts.end()) not_valid("only one attribute per element can have the ID type"); } attribute->external(m_in_external_dtd); (*dte)->add_attribute(attribute.release()); } m_allow_parameter_entity_references = true; match('>'); } void parser_imp::notation_decl() { match(xml_Notation); s(true); string name = m_token, pubid, sysid; if (m_notations.count(name) > 0) not_valid("notation names should be unique"); m_notations.insert(name); match(xml_Name); s(true); if (m_token == "SYSTEM") { match(xml_Name); s(true); sysid = m_token; match(xml_String); if (not is_valid_system_literal(sysid)) not_well_formed("invalid system literal"); } else if (m_token == "PUBLIC") { match(xml_Name); s(true); pubid = m_token; match(xml_String); // validate the public ID if (not is_valid_public_id(pubid)) not_well_formed("Invalid public ID"); s(); if (m_lookahead == xml_String) { sysid = m_token; match(xml_String); } } else not_well_formed("Expected either SYSTEM or PUBLIC"); s(); m_allow_parameter_entity_references = true; match('>'); m_parser.notation_decl(name, sysid, pubid); } data_source* parser_imp::external_id() { data_source* result = nullptr; string pubid, sysid; if (m_token == "SYSTEM") { match(xml_Name); s(true); sysid = m_token; if (not is_valid_system_literal(sysid)) not_well_formed("invalid system literal"); } else if (m_token == "PUBLIC") { match(xml_Name); s(true); pubid = m_token; match(xml_String); // validate the public ID if (not is_valid_public_id(pubid)) not_well_formed("Invalid public ID"); s(true); sysid = m_token; } else not_well_formed("Expected external id starting with either SYSTEM or PUBLIC"); istream* is = m_parser.external_entity_ref(m_data_source->base(), pubid, sysid); if (is != nullptr) { result = new istream_data_source(is); string::size_type s = sysid.rfind('/'); if (s == string::npos) result->base(m_data_source->base()); else { sysid.erase(s, string::npos); if (is_absolute_path(sysid)) result->base(sysid); else result->base(m_data_source->base() + '/' + sysid); } } return result; } boost::tuple parser_imp::read_external_id() { string result; string path; unique_ptr data(external_id()); parser_state save(this, data.get()); if (m_data_source) { path = m_data_source->base(); m_lookahead = get_next_token(); text_decl(); result = m_token; while (unicode ch = get_next_char()) append(result, ch); } return boost::make_tuple(path, result); } void parser_imp::parse_parameter_entity_declaration(string& s) { string result; int state = 0; unicode charref = 0; string name; for (string::const_iterator i = s.begin(); i != s.end(); ++i) { unicode c = *i; switch (state) { case 0: if (c == '&') state = 1; else if (c == '%') { if (m_external_subset) { name.clear(); state = 20; } else not_well_formed("parameter entities may not occur in declarations that are not in an external subset"); } else append(result, c); break; case 1: if (c == '#') state = 2; else { result += '&'; append(result, c); state = 0; } break; case 2: if (c == 'x') state = 4; else if (c >= '0' and c <= '9') { charref = c - '0'; state = 3; } else not_well_formed("invalid character reference"); break; case 3: if (c >= '0' and c <= '9') charref = charref * 10 + (c - '0'); else if (c == ';') { if (not is_char(charref)) not_well_formed(boost::format("Illegal character referenced: 0x%x") % int(charref)); append(result, charref); state = 0; } else not_well_formed("invalid character reference"); break; case 4: if (c >= 'a' and c <= 'f') { charref = c - 'a' + 10; state = 5; } else if (c >= 'A' and c <= 'F') { charref = c - 'A' + 10; state = 5; } else if (c >= '0' and c <= '9') { charref = c - '0'; state = 5; } else not_well_formed("invalid character reference"); break; case 5: if (c >= 'a' and c <= 'f') charref = (charref << 4) + (c - 'a' + 10); else if (c >= 'A' and c <= 'F') charref = (charref << 4) + (c - 'A' + 10); else if (c >= '0' and c <= '9') charref = (charref << 4) + (c - '0'); else if (c == ';') { if (not is_char(charref)) not_well_formed(boost::format("Illegal character referenced: 0x%x") % int(charref)); append(result, charref); state = 0; } else not_well_formed("invalid character reference"); break; case 20: if (c == ';') { const doctype::entity& e = get_parameter_entity(name); result += e.replacement(); state = 0; } else if (is_name_char(c)) append(name, c); else not_well_formed("invalid parameter entity reference"); break; default: assert(false); not_well_formed("invalid state"); } } if (state != 0) not_well_formed("invalid reference"); swap(s, result); } // parse out the general and parameter entity references in a value string // for a general entity reference which is about to be stored. void parser_imp::parse_general_entity_declaration(string& s) { string result; int state = 0; unicode charref = 0; string name; for (string::const_iterator i = s.begin(); i != s.end(); ++i) { unicode c = *i; switch (state) { case 0: if (c == '&') state = 1; else if (c == '%') { if (m_external_subset) { name.clear(); state = 20; } else not_well_formed("parameter entities may not occur in declarations that are not in an external subset"); } else append(result, c); break; case 1: if (c == '#') state = 2; else if (is_name_start_char(c)) { name.clear(); append(name, c); state = 10; } break; case 2: if (c == 'x') state = 4; else if (c >= '0' and c <= '9') { charref = c - '0'; state = 3; } else not_well_formed("invalid character reference"); break; case 3: if (c >= '0' and c <= '9') charref = charref * 10 + (c - '0'); else if (c == ';') { if (not is_char(charref)) not_well_formed(boost::format("Illegal character referenced: 0x%x") % int(charref)); append(result, charref); state = 0; } else not_well_formed("invalid character reference"); break; case 4: if (c >= 'a' and c <= 'f') { charref = c - 'a' + 10; state = 5; } else if (c >= 'A' and c <= 'F') { charref = c - 'A' + 10; state = 5; } else if (c >= '0' and c <= '9') { charref = c - '0'; state = 5; } else not_well_formed("invalid character reference"); break; case 5: if (c >= 'a' and c <= 'f') charref = (charref << 4) + (c - 'a' + 10); else if (c >= 'A' and c <= 'F') charref = (charref << 4) + (c - 'A' + 10); else if (c >= '0' and c <= '9') charref = (charref << 4) + (c - '0'); else if (c == ';') { if (not is_char(charref)) not_well_formed(boost::format("Illegal character referenced: 0x%x") % int(charref)); append(result, charref); state = 0; } else not_well_formed("invalid character reference"); break; case 10: if (c == ';') { result += '&'; result += name; result += ';'; state = 0; } else if (is_name_char(c)) append(name, c); else not_well_formed("invalid entity reference"); break; case 20: if (c == ';') { const doctype::entity& e = get_parameter_entity(name); result += e.replacement(); state = 0; } else if (is_name_char(c)) append(name, c); else not_well_formed("invalid parameter entity reference"); break; default: assert(false); not_well_formed("invalid state"); } } if (state != 0) not_well_formed("invalid reference"); swap(s, result); } string parser_imp::normalize_attribute_value(data_source* data) { string result; unicode charref = 0; string name; enum State { state_Start, state_ReferenceStart, state_CharReferenceStart, state_HexCharReference, state_HexCharReference2, state_DecCharReference, state_EntityReference, } state = state_Start; for (;;) { unicode c = data->get_next_char(); if (c == 0) break; if (c == '<') not_well_formed("Attribute values may not contain '<' character"); switch (state) { case state_Start: if (c == '&') state = state_ReferenceStart; else if (c == ' ' or c == '\n' or c == '\t' or c == '\r') result += ' '; else append(result, c); break; case state_ReferenceStart: if (c == '#') state = state_CharReferenceStart; else if (is_name_start_char(c)) { name.clear(); append(name, c); state = state_EntityReference; } else not_well_formed("invalid reference found in attribute value"); break; case state_CharReferenceStart: if (c == 'x') state = state_HexCharReference; else if (c >= '0' and c <= '9') { charref = c - '0'; state = state_DecCharReference; } else not_well_formed("invalid character reference"); break; case state_DecCharReference: if (c >= '0' and c <= '9') charref = charref * 10 + (c - '0'); else if (c == ';') { if (not is_char(charref)) not_well_formed(boost::format("Illegal character referenced: 0x%x") % int(charref)); append(result, charref); state = state_Start; } else not_well_formed("invalid character reference"); break; case state_HexCharReference: if (c >= 'a' and c <= 'f') { charref = c - 'a' + 10; state = state_HexCharReference2; } else if (c >= 'A' and c <= 'F') { charref = c - 'A' + 10; state = state_HexCharReference2; } else if (c >= '0' and c <= '9') { charref = c - '0'; state = state_HexCharReference2; } else not_well_formed("invalid character reference"); break; case state_HexCharReference2: if (c >= 'a' and c <= 'f') charref = (charref << 4) + (c - 'a' + 10); else if (c >= 'A' and c <= 'F') charref = (charref << 4) + (c - 'A' + 10); else if (c >= '0' and c <= '9') charref = (charref << 4) + (c - '0'); else if (c == ';') { if (not is_char(charref)) not_well_formed(boost::format("Illegal character referenced: 0x%x") % int(charref)); append(result, charref); state = state_Start; } else not_well_formed("invalid character reference"); break; case state_EntityReference: if (c == ';') { if (data->is_entity_on_stack(name)) not_well_formed("infinite recursion in nested entity references"); const doctype::entity& e = get_general_entity(name); if (e.external()) not_well_formed("attribute value may not contain external entity reference"); if (e.externally_defined() and m_standalone) not_well_formed("document marked as standalone but an external entity is referenced"); entity_data_source next_data(name, m_data_source->base(), e.replacement(), data); string replacement = normalize_attribute_value(&next_data); result += replacement; state = state_Start; } else if (is_name_char(c)) append(name, c); else not_well_formed("invalid entity reference"); break; default: assert(false); not_well_formed("invalid state"); } } if (state != state_Start) not_well_formed("invalid reference"); return result; } void parser_imp::element(doctype::validator& valid) { value_saver in_element(m_in_element, true); value_saver in_content(m_in_content, false); match(xml_STag); string name = m_token; match(xml_Name); if (not valid(name)) not_valid(boost::format("element '%1%' not expected at this position") % name); const doctype::element* dte = get_element(name); if (m_has_dtd and dte == nullptr and m_validating) not_valid(boost::format("Element '%1%' is not defined in DTD") % name); doctype::validator sub_valid; if (dte != nullptr) sub_valid = dte->get_validator(); list attrs; ns_state ns(this); set seen; for (;;) { if (m_lookahead != xml_Space) break; s(true); if (m_lookahead != xml_Name) break; string attr_name = m_token; match(xml_Name); if (seen.count(attr_name) > 0) not_well_formed(boost::format("multiple values for attribute '%1%'") % attr_name); seen.insert(attr_name); eq(); string attr_value = normalize_attribute_value(m_token); match(xml_String); const doctype::attribute* dta = nullptr; if (dte != nullptr) dta = dte->get_attribute(attr_name); if (dta == nullptr and m_validating) not_valid(boost::format("undeclared attribute '%1%'") % attr_name); if (m_validating and dta != nullptr and dta->get_default_type() == doctype::attDefFixed and attr_value != boost::get<1>(dta->get_default())) { not_valid("invalid value specified for fixed attribute"); } // had a crash suddenly here deep down in ba::starts_with... if (attr_name == "xmlns" or attr_name.compare(0, 6, "xmlns:", 6) == 0) // namespace support { if (attr_name.length() == 5) { ns.m_default_ns = attr_value; m_parser.start_namespace_decl("", attr_value); } else { string prefix = attr_name.substr(6); ns.m_known[prefix] = attr_value; m_parser.start_namespace_decl(prefix, attr_value); } } else { bool id = (attr_name == "xml:id"); if (dta != nullptr) { string v(attr_value); if (not dta->validate_value(attr_value, m_general_entities)) { not_valid(boost::format("invalid value ('%2%') for attribute %1%") % attr_name % attr_value); } if (m_validating and m_standalone and dta->external() and v != attr_value) not_valid("attribute value modified as a result of an external defined attlist declaration, which is not valid in a standalone document"); if (dta->get_type() == doctype::attTypeTokenizedID) { id = true; if (m_ids.count(attr_value) > 0) { not_valid(boost::format("attribute value ('%1%') for attribute '%2%' is not unique") % attr_value % attr_name); } m_ids.insert(attr_value); if (m_unresolved_ids.count(attr_value) > 0) m_unresolved_ids.erase(attr_value); } else if (dta->get_type() == doctype::attTypeTokenizedIDREF) { if (attr_value.empty()) not_valid(boost::format("attribute value for attribute '%1%' may not be empty") % attr_name); if (not m_ids.count(attr_value)) m_unresolved_ids.insert(attr_value); } else if (dta->get_type() == doctype::attTypeTokenizedIDREFS) { if (attr_value.empty()) not_valid(boost::format("attribute value for attribute '%1%' may not be empty") % attr_name); string::size_type b = 0, e = attr_value.find(' '); while (e != string::npos) { if (e - b > 0) { string id = attr_value.substr(b, e); if (not m_ids.count(id)) m_unresolved_ids.insert(id); } b = e + 1; e = attr_value.find(' ', b); } if (b != string::npos and b < attr_value.length()) { string id = attr_value.substr(b); if (not m_ids.count(id)) m_unresolved_ids.insert(id); } } } detail::attr attr; attr.m_name = attr_name; attr.m_value = attr_value; attr.m_id = id; if (m_ns != nullptr) { string::size_type d = attr_name.find(':'); if (d != string::npos) { string ns = m_ns->ns_for_prefix(attr_name.substr(0, d)); if (not ns.empty()) { attr.m_ns = ns; attr.m_name = attr_name.substr(d + 1); } } } attrs.push_back(attr); } } // add missing attributes if (dte != nullptr) { foreach (const doctype::attribute* dta, dte->attributes()) { string attr_name = dta->name(); list::iterator attr = find_if(attrs.begin(), attrs.end(), boost::bind(&detail::attr::m_name, _1) == attr_name); doctype::AttributeDefault defType; string defValue; boost::tie(defType, defValue) = dta->get_default(); if (defType == doctype::attDefRequired) { if (attr == attrs.end()) not_valid(boost::format("missing #REQUIRED attribute '%1%' for element '%2%'") % attr_name % name); } else if (not defValue.empty() and attr == attrs.end()) { if (m_validating and m_standalone and dta->external()) not_valid("default value for attribute defined in external declaration which is not allowed in a standalone document"); detail::attr attr; attr.m_name = attr_name; attr.m_value = normalize_attribute_value(defValue); attr.m_id = false; if (m_ns != nullptr) { string::size_type d = attr_name.find(':'); if (d != string::npos) { string ns = m_ns->ns_for_prefix(attr_name.substr(0, d)); if (not ns.empty()) { attr.m_ns = ns; attr.m_name = attr_name.substr(d + 1); } } } attrs.push_back(attr); } } } // now find out the namespace we're supposed to pass string uri, raw(name); string::size_type c = name.find(':'); if (c != string::npos and c > 0) { uri = ns.ns_for_prefix(name.substr(0, c)); name.erase(0, c + 1); } else uri = ns.default_ns(); // sort the attributes (why? disabled to allow similar output) attrs.sort(boost::bind(&detail::attr::m_name, _1) < boost::bind(&detail::attr::m_name, _2)); if (m_lookahead == '/') { match('/'); m_parser.start_element(name, uri, attrs); m_parser.end_element(name, uri); } else { m_parser.start_element(name, uri, attrs); // open scope, we're entering a content production { value_saver save(m_in_content, true); match('>'); if (m_lookahead != xml_ETag) content(sub_valid, m_validating and m_standalone and dte->external() and dte->element_content()); } match(xml_ETag); if (m_token != raw) not_well_formed("end tag does not match start tag"); match(xml_Name); s(); m_parser.end_element(name, uri); } m_in_content = in_content.m_value; match('>'); if (m_validating and dte != nullptr and not sub_valid.done()) not_valid(boost::format("missing child elements for element '%1%'") % dte->name()); s(); } void parser_imp::content(doctype::validator& valid, bool check_for_whitespace) { do { switch (m_lookahead) { case xml_Content: if (valid.allow_char_data()) m_parser.character_data(m_token); else { ba::trim(m_token); if (m_token.empty()) { if (check_for_whitespace) not_valid("element declared in external subset contains white space"); } else not_valid(boost::format("character data '%1%' not allowed in element") % m_token); } match(xml_Content); break; case xml_Reference: { const doctype::entity& e = get_general_entity(m_token); if (m_data_source->is_entity_on_stack(m_token)) not_well_formed("infinite recursion of entity references"); if (e.externally_defined() and m_standalone) not_well_formed("document marked as standalone but an external entity is referenced"); if (not e.parsed()) not_well_formed("content has a general entity reference to an unparsed entity"); // scope { entity_data_source source(m_token, m_data_source->base(), e.replacement(), m_data_source); parser_state state(this, &source); m_lookahead = get_next_content(); m_in_external_dtd = e.externally_defined(); if (m_lookahead != xml_Eof) content(valid, check_for_whitespace); if (m_lookahead != xml_Eof) not_well_formed("entity reference should be a valid content production"); } match(xml_Reference); break; } case xml_STag: element(valid); break; case xml_PI: pi(); break; case xml_Comment: comment(); break; case xml_Space: s(); break; case xml_CDSect: if (not valid.allow_char_data()) not_valid(boost::format("character data '%1%' not allowed in element") % m_token); m_parser.start_cdata_section(); m_parser.character_data(m_token); m_parser.end_cdata_section(); match(xml_CDSect); break; default: match(xml_Content); // will fail and report error } } while (m_lookahead != xml_ETag and m_lookahead != xml_Eof); } void parser_imp::comment() { // m_lookahead == xml_Comment // read characters until we reach --> // check all characters in between for validity enum { state_Start, state_FirstHyphenSeen, state_SecondHyphenSeen, state_CommentClosed } state = state_Start; m_token.clear(); while (state != state_CommentClosed) { unicode ch = get_next_char(); if (ch == 0) not_well_formed("runaway comment"); if (not is_char(ch)) not_well_formed(boost::format("illegal character in content: '0x%x'") % int(ch)); switch (state) { case state_Start: if (ch == '-') state = state_FirstHyphenSeen; break; case state_FirstHyphenSeen: if (ch == '-') state = state_SecondHyphenSeen; else state = state_Start; break; case state_SecondHyphenSeen: if (ch == '>') state = state_CommentClosed; else not_well_formed("double hyphen found in comment"); break; case state_CommentClosed: assert(false); } } assert(m_token.length() >= 3); m_token.erase(m_token.end() - 3, m_token.end()); m_parser.comment(m_token); match(xml_Comment); } void parser_imp::pi() { // m_lookahead == xml_PI // read characters until we reach --> // check all characters in between for validity string pi_target = m_token.substr(2); if (pi_target.empty()) not_well_formed("processing instruction target missing"); // we treat the xml processing instruction separately. if (m_token.substr(2) == "xml") not_well_formed("xml declaration are only valid as the start of the file"); else if (ba::to_lower_copy(pi_target) == "xml") not_well_formed("') state = state_PIClosed; else if (ch != '?') state = state_Data; break; case state_PIClosed: assert(false); } } m_token.erase(m_token.end() - 2, m_token.end()); m_parser.processing_instruction(pi_target, m_token); match(xml_PI); } // -------------------------------------------------------------------- parser::parser(istream& data) : m_impl(new parser_imp(data, *this)) , m_istream(nullptr) { } parser::parser(const string& data) { m_istream = new istringstream(data); m_impl = new parser_imp(*m_istream, *this); } parser::~parser() { delete m_impl; delete m_istream; } void parser::parse(bool validate) { m_impl->parse(validate); } void parser::start_element(const string& name, const string& uri, const list& atts) { if (start_element_handler) start_element_handler(name, uri, atts); } void parser::end_element(const string& name, const string& uri) { if (end_element_handler) end_element_handler(name, uri); } void parser::character_data(const string& data) { if (character_data_handler) character_data_handler(data); } void parser::processing_instruction(const string& target, const string& data) { if (processing_instruction_handler) processing_instruction_handler(target, data); } void parser::comment(const string& data) { if (comment_handler) comment_handler(data); } void parser::start_cdata_section() { if (start_cdata_section_handler) start_cdata_section_handler(); } void parser::end_cdata_section() { if (end_cdata_section_handler) end_cdata_section_handler(); } void parser::start_namespace_decl(const string& prefix, const string& uri) { if (start_namespace_decl_handler) start_namespace_decl_handler(prefix, uri); } void parser::end_namespace_decl(const string& prefix) { if (end_namespace_decl_handler) end_namespace_decl_handler(prefix); } void parser::notation_decl(const string& name, const string& systemId, const string& publicId) { if (notation_decl_handler) notation_decl_handler(name, systemId, publicId); } istream* parser::external_entity_ref(const string& base, const string& pubid, const string& uri) { istream* result = nullptr; if (external_entity_ref_handler) result = external_entity_ref_handler(base, pubid, uri); return result; } void parser::report_invalidation(const string& msg) { if (report_invalidation_handler) report_invalidation_handler(msg); } } } libzeep-3.0.2/src/webapp.cpp0000664000175000017500000004673712073032051015573 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008-2011. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // webapp is a base class used to construct web applications in C++ using libzeep // #include #include #define foreach BOOST_FOREACH #include #include #include #include #include #include #include using namespace std; namespace ba = boost::algorithm; namespace io = boost::iostreams; namespace fs = boost::filesystem; namespace zeep { namespace http { // -------------------------------------------------------------------- // webapp::webapp( const std::string& ns, const fs::path& docroot) : m_ns(ns) , m_docroot(docroot) { m_processor_table["include"] = boost::bind(&webapp::process_include, this, _1, _2, _3); m_processor_table["if"] = boost::bind(&webapp::process_if, this, _1, _2, _3); m_processor_table["iterate"] = boost::bind(&webapp::process_iterate, this, _1, _2, _3); m_processor_table["for"] = boost::bind(&webapp::process_for, this, _1, _2, _3); m_processor_table["number"] = boost::bind(&webapp::process_number, this, _1, _2, _3); m_processor_table["options"] = boost::bind(&webapp::process_options, this, _1, _2, _3); m_processor_table["option"] = boost::bind(&webapp::process_option, this, _1, _2, _3); m_processor_table["checkbox"] = boost::bind(&webapp::process_checkbox, this, _1, _2, _3); m_processor_table["url"] = boost::bind(&webapp::process_url, this, _1, _2, _3); m_processor_table["param"] = boost::bind(&webapp::process_param, this, _1, _2, _3); m_processor_table["embed"] = boost::bind(&webapp::process_embed, this, _1, _2, _3); } webapp::~webapp() { } void webapp::set_docroot( const fs::path& path) { m_docroot = path; } void webapp::handle_request( const request& req, reply& rep) { string uri = req.uri; // shortcut, only handle GET, POST and PUT if (req.method != "GET" and req.method != "POST" and req.method != "PUT" and req.method != "OPTIONS" and req.method != "HEAD") { rep = reply::stock_reply(bad_request); return; } try { // start by sanitizing the request's URI, first parse the parameters string ps = req.payload; if (req.method != "POST") { string::size_type d = uri.find('?'); if (d != string::npos) { ps = uri.substr(d + 1); uri.erase(d, string::npos); } } // strip off the http part including hostname and such if (ba::starts_with(uri, "http://")) { string::size_type s = uri.find_first_of('/', 7); if (s != string::npos) uri.erase(0, s); } // now make the path relative to the root while (uri.length() > 0 and uri[0] == '/') uri.erase(uri.begin()); // decode the path elements string action = uri; string::size_type s = action.find('/'); if (s != string::npos) action.erase(s, string::npos); // set up the scope by putting some globals in it el::scope scope(req); scope.put("action", el::object(action)); scope.put("uri", el::object(uri)); s = uri.find('?'); if (s != string::npos) uri.erase(s, string::npos); scope.put("baseuri", uri); scope.put("mobile", req.is_mobile()); handler_map::iterator handler = m_dispatch_table.find(uri); if (handler == m_dispatch_table.end()) handler = m_dispatch_table.find(action); if (handler != m_dispatch_table.end()) { if (req.method == "OPTIONS") { rep = reply::stock_reply(ok); rep.set_header("Allow", "GET,HEAD,POST,OPTIONS"); rep.set_content("", "text/plain"); } else { init_scope(scope); handler->second(req, scope, rep); if (req.method == "HEAD") rep.set_content("", rep.get_content_type()); } } else throw not_found; } catch (unauthorized_exception& e) { create_unauth_reply(e.m_stale, e.m_realm, rep); } catch (status_type& s) { rep = reply::stock_reply(s); } catch (std::exception& e) { el::scope scope(req); scope.put("errormsg", el::object(e.what())); create_reply_from_template("error.html", scope, rep); } } void webapp::create_unauth_reply(bool stale, const string& realm, reply& rep) { rep = reply::stock_reply(unauthorized); } void webapp::mount(const std::string& path, handler_type handler) { m_dispatch_table[path] = handler; } void webapp::handle_file( const zeep::http::request& request, const el::scope& scope, zeep::http::reply& reply) { using namespace boost::local_time; using namespace boost::posix_time; fs::path file = get_docroot() / scope["baseuri"].as(); string ifModifiedSince; foreach (const zeep::http::header& h, request.headers) { if (h.name == "If-Modified-Since") { local_date_time modifiedSince(local_sec_clock::local_time(time_zone_ptr())); local_time_input_facet* lif1(new local_time_input_facet("%a, %d %b %Y %H:%M:%S GMT")); stringstream ss; ss.imbue(std::locale(std::locale::classic(), lif1)); ss.str(h.value); ss >> modifiedSince; local_date_time fileDate(from_time_t(fs::last_write_time(file)), time_zone_ptr()); if (fileDate <= modifiedSince) { reply = zeep::http::reply::stock_reply(zeep::http::not_modified); return; } break; } } fs::ifstream in(file, ios::binary); stringstream out; io::copy(in, out); string mimetype = "text/plain"; if (file.extension() == ".css") mimetype = "text/css"; else if (file.extension() == ".js") mimetype = "text/javascript"; else if (file.extension() == ".png") mimetype = "image/png"; else if (file.extension() == ".svg") mimetype = "image/svg+xml"; else if (file.extension() == ".html" or file.extension() == ".htm") mimetype = "text/html"; else if (file.extension() == ".xml" or file.extension() == ".xsl" or file.extension() == ".xslt") mimetype = "text/xml"; else if (file.extension() == ".xhtml") mimetype = "application/xhtml+xml"; reply.set_content(out.str(), mimetype); local_date_time t(local_sec_clock::local_time(time_zone_ptr())); local_time_facet* lf(new local_time_facet("%a, %d %b %Y %H:%M:%S GMT")); stringstream s; s.imbue(std::locale(std::cout.getloc(), lf)); ptime pt = from_time_t(boost::filesystem::last_write_time(file)); local_date_time t2(pt, time_zone_ptr()); s << t2; reply.set_header("Last-Modified", s.str()); } void webapp::load_template( const std::string& file, xml::document& doc) { fs::ifstream data(m_docroot / file, ios::binary); if (not data.is_open()) { if (not fs::exists(m_docroot)) throw exception((boost::format("configuration error, docroot not found: '%1%'") % m_docroot).str()); else { #if defined(_MSC_VER) char msg[1024] = ""; DWORD dw = ::GetLastError(); if (dw != NO_ERROR) { char* lpMsgBuf; int m = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&lpMsgBuf, 0, NULL); if (lpMsgBuf != nullptr) { // strip off the trailing whitespace characters while (m > 0 and isspace(lpMsgBuf[m - 1])) --m; lpMsgBuf[m] = 0; strncpy(msg, lpMsgBuf, sizeof(msg)); ::LocalFree(lpMsgBuf); } } throw exception((boost::format("error opening: %1% (%2%)") % (m_docroot / file) % msg).str()); #else throw exception((boost::format("error opening: %1% (%2%)") % (m_docroot / file) % strerror(errno)).str()); #endif } } doc.read(data); } void webapp::create_reply_from_template( const std::string& file, const el::scope& scope, reply& reply) { xml::document doc; doc.set_preserve_cdata(true); load_template(file, doc); xml::element* root = doc.child(); process_xml(root, scope, "/"); reply.set_content(doc); } void webapp::process_xml( xml::node* node, const el::scope& scope, fs::path dir) { xml::text* text = dynamic_cast(node); if (text != nullptr) { string s = text->str(); if (el::process_el(scope, s)) text->str(s); return; } xml::element* e = dynamic_cast(node); if (e == nullptr) return; // if node is one of our special nodes, we treat it here if (e->ns() == m_ns) { xml::container* parent = e->parent(); try { el::scope nested(scope); processor_map::iterator p = m_processor_table.find(e->name()); if (p != m_processor_table.end()) p->second(e, scope, dir); else throw exception((boost::format("unimplemented tag") % e->name()).str()); } catch (std::exception& ex) { xml::node* replacement = new xml::text( (boost::format("Error processing directive 'mrs:%1%': %2%") % e->name() % ex.what()).str()); parent->insert(e, replacement); } try { // assert(parent == e->parent()); // assert(find(parent->begin(), parent->end(), e) != parent->end()); parent->remove(e); delete e; } catch (exception& ex) { cerr << "exception: " << ex.what() << endl; cerr << *e << endl; } } else { foreach (xml::attribute& a, boost::iterator_range(e->attr_begin(), e->attr_end())) { string s = a.value(); if (process_el(scope, s)) a.value(s); } list nodes; copy(e->node_begin(), e->node_end(), back_inserter(nodes)); foreach (xml::node* n, nodes) { process_xml(n, scope, dir); } } } void webapp::add_processor( const std::string& name, processor_type processor) { m_processor_table[name] = processor; } void webapp::process_include( xml::element* node, const el::scope& scope, fs::path dir) { // an include directive, load file and include resulting content string file = node->get_attribute("file"); process_el(scope, file); if (file.empty()) throw exception("missing file attribute"); xml::document doc; doc.set_preserve_cdata(true); load_template(dir / file, doc); xml::element* replacement = doc.child(); doc.root()->remove(replacement); xml::container* parent = node->parent(); parent->insert(node, replacement); process_xml(replacement, scope, (dir / file).parent_path()); } void webapp::process_if( xml::element* node, const el::scope& scope, fs::path dir) { string test = node->get_attribute("test"); if (evaluate_el(scope, test)) { foreach (xml::node* c, node->nodes()) { xml::node* clone = c->clone(); xml::container* parent = node->parent(); assert(parent); parent->insert(node, clone); // insert before processing, to assign namespaces process_xml(clone, scope, dir); } } } void webapp::process_iterate( xml::element* node, const el::scope& scope, fs::path dir) { el::object collection = scope[node->get_attribute("collection")]; if (collection.type() != el::object::array_type) evaluate_el(scope, node->get_attribute("collection"), collection); string var = node->get_attribute("var"); if (var.empty()) throw exception("missing var attribute in mrs:iterate"); foreach (el::object& o, collection) { el::scope s(scope); s.put(var, o); foreach (xml::node* c, node->nodes()) { xml::node* clone = c->clone(); xml::container* parent = node->parent(); assert(parent); parent->insert(node, clone); // insert before processing, to assign namespaces process_xml(clone, s, dir); } } } void webapp::process_for( xml::element* node, const el::scope& scope, fs::path dir) { el::object b, e; evaluate_el(scope, node->get_attribute("begin"), b); evaluate_el(scope, node->get_attribute("end"), e); string var = node->get_attribute("var"); if (var.empty()) throw exception("missing var attribute in mrs:iterate"); for (int32 i = b.as(); i <= e.as(); ++i) { el::scope s(scope); s.put(var, el::object(i)); foreach (xml::node* c, node->nodes()) { xml::container* parent = node->parent(); assert(parent); xml::node* clone = c->clone(); parent->insert(node, clone); // insert before processing, to assign namespaces process_xml(clone, s, dir); } } } class with_thousands : public numpunct { protected: // char_type do_thousands_sep() const { return tsp; } string do_grouping() const { return "\03"; } // char_type do_decimal_point() const { return dsp; } }; void webapp::process_number( xml::element* node, const el::scope& scope, fs::path dir) { string number = node->get_attribute("n"); string format = node->get_attribute("f"); if (format == "#,##0B") // bytes, convert to a human readable form { const char kBase[] = { 'B', 'K', 'M', 'G', 'T', 'P', 'E' }; // whatever el::object n; evaluate_el(scope, number, n); uint64 nr = n.as(); int base = 0; while (nr > 1024) { nr /= 1024; ++base; } locale mylocale(locale(), new with_thousands); ostringstream s; s.imbue(mylocale); s.setf(ios::fixed, ios::floatfield); s.precision(1); s << nr << ' ' << kBase[base]; number = s.str(); } else if (format.empty() or ba::starts_with(format, "#,##0")) { el::object n; evaluate_el(scope, number, n); uint64 nr = n.as(); locale mylocale(locale(), new with_thousands); ostringstream s; s.imbue(mylocale); s << nr; number = s.str(); } zeep::xml::node* replacement = new zeep::xml::text(number); zeep::xml::container* parent = node->parent(); parent->insert(node, replacement); } void webapp::process_options( xml::element* node, const el::scope& scope, fs::path dir) { el::object collection = scope[node->get_attribute("collection")]; if (collection.type() != el::object::array_type) evaluate_el(scope, node->get_attribute("collection"), collection); string value = node->get_attribute("value"); string label = node->get_attribute("label"); string selected = node->get_attribute("selected"); if (not selected.empty()) { el::object o; evaluate_el(scope, selected, o); selected = o.as(); } foreach (el::object& o, collection) { zeep::xml::element* option = new zeep::xml::element("option"); if (not (value.empty() or label.empty())) { option->set_attribute("value", o[value].as()); if (selected == o[value].as()) option->set_attribute("selected", "selected"); option->add_text(o[label].as()); } else { option->set_attribute("value", o.as()); if (selected == o.as()) option->set_attribute("selected", "selected"); option->add_text(o.as()); } zeep::xml::container* parent = node->parent(); assert(parent); parent->insert(node, option); } } void webapp::process_option( xml::element* node, const el::scope& scope, fs::path dir) { string value = node->get_attribute("value"); if (not value.empty()) { el::object o; evaluate_el(scope, value, o); value = o.as(); } string selected = node->get_attribute("selected"); if (not selected.empty()) { el::object o; evaluate_el(scope, selected, o); selected = o.as(); } zeep::xml::element* option = new zeep::xml::element("option"); option->set_attribute("value", value); if (selected == value) option->set_attribute("selected", "selected"); zeep::xml::container* parent = node->parent(); assert(parent); parent->insert(node, option); foreach (zeep::xml::node* c, node->nodes()) { zeep::xml::node* clone = c->clone(); option->push_back(clone); process_xml(clone, scope, dir); } } void webapp::process_checkbox( xml::element* node, const el::scope& scope, fs::path dir) { string name = node->get_attribute("name"); if (not name.empty()) { el::object o; evaluate_el(scope, name, o); name = o.as(); } bool checked = false; if (not node->get_attribute("checked").empty()) { el::object o; evaluate_el(scope, node->get_attribute("checked"), o); checked = o.as(); } zeep::xml::element* checkbox = new zeep::xml::element("input"); checkbox->set_attribute("type", "checkbox"); checkbox->set_attribute("name", name); checkbox->set_attribute("value", "true"); if (checked) checkbox->set_attribute("checked", "true"); zeep::xml::container* parent = node->parent(); assert(parent); parent->insert(node, checkbox); foreach (zeep::xml::node* c, node->nodes()) { zeep::xml::node* clone = c->clone(); checkbox->push_back(clone); process_xml(clone, scope, dir); } } void webapp::process_url( xml::element* node, const el::scope& scope, fs::path dir) { string var = node->get_attribute("var"); parameter_map parameters; get_parameters(scope, parameters); foreach (zeep::xml::element* e, *node) { if (e->ns() == m_ns and e->name() == "param") { string name = e->get_attribute("name"); string value = e->get_attribute("value"); process_el(scope, value); parameters.replace(name, value); } } string url = scope["baseuri"].as(); bool first = true; foreach (parameter_map::value_type p, parameters) { if (first) url += '?'; else url += '&'; first = false; url += zeep::http::encode_url(p.first) + '=' + zeep::http::encode_url(p.second.as()); } el::scope& s(const_cast(scope)); s.put(var, url); } void webapp::process_param( xml::element* node, const el::scope& scope, fs::path dir) { throw exception("Invalid XML, cannot have a stand-alone mrs:param element"); } void webapp::process_embed( xml::element* node, const el::scope& scope, fs::path dir) { // an embed directive, load xml from attribute and include parsed content string xml = scope[node->get_attribute("var")].as(); if (xml.empty()) throw exception("Missing var attribute in embed tag"); zeep::xml::document doc; doc.set_preserve_cdata(true); doc.read(xml); zeep::xml::element* replacement = doc.child(); doc.root()->remove(replacement); zeep::xml::container* parent = node->parent(); parent->insert(node, replacement); process_xml(replacement, scope, dir); } void webapp::init_scope( el::scope& scope) { } void webapp::get_cookies( const el::scope& scope, parameter_map& cookies) { const request& req = scope.get_request(); foreach (const header& h, req.headers) { if (h.name != "Cookie") continue; vector rawCookies; ba::split(rawCookies, h.value, ba::is_any_of(";")); foreach (string& cookie, rawCookies) { ba::trim(cookie); cookies.add(cookie); } } } void webapp::get_parameters( const el::scope& scope, parameter_map& parameters) { const request& req = scope.get_request(); string ps; if (req.method == "POST") ps = req.payload; else if (req.method == "GET" or req.method == "PUT") { string::size_type d = req.uri.find('?'); if (d != string::npos) ps = req.uri.substr(d + 1); } while (not ps.empty()) { string::size_type e = ps.find_first_of("&;"); string param; if (e != string::npos) { param = ps.substr(0, e); ps.erase(0, e + 1); } else swap(param, ps); if (not param.empty()) parameters.add(param); } } // -------------------------------------------------------------------- // // add a name/value pair as a string formatted as 'name=value' void parameter_map::add( const string& param) { string name, value; string::size_type d = param.find('='); if (d != string::npos) { name = param.substr(0, d); value = param.substr(d + 1); } add(name, value); } void parameter_map::add( string name, string value) { name = decode_url(name); if (not value.empty()) value = decode_url(value); insert(make_pair(name, parameter_value(value, false))); } void parameter_map::replace( string name, string value) { if (count(name)) erase(lower_bound(name), upper_bound(name)); add(name, value); } } } libzeep-3.0.2/src/request.cpp0000664000175000017500000001033212121543422015766 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2012. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include #include #include #define foreach BOOST_FOREACH #include #include #include using namespace std; namespace zeep { namespace http { float request::accept(const char* type) const { float result = 1.0f; #define IDENT "[-+.a-z0-9]+" #define TYPE "\\*|" IDENT #define MEDIARANGE "\\s*(" TYPE ")/(" TYPE ").*?(?:;\\s*q=(\\d(?:\\.\\d?)?))?" static boost::regex rx(MEDIARANGE); assert(type); if (type == nullptr) return 1.0; string t1(type), t2; string::size_type s = t1.find('/'); if (s != string::npos) { t2 = t1.substr(s + 1); t1.erase(s, t1.length() - s); } foreach (const header& h, headers) { if (h.name != "Accept") continue; result = 0; string::size_type b = 0, e = h.value.find(','); for (;;) { if (e == string::npos) e = h.value.length(); string mediarange = h.value.substr(b, e - b); boost::smatch m; if (boost::regex_search(mediarange, m, rx)) { string type1 = m[1].str(); string type2 = m[2].str(); float value = 1.0f; if (m[3].matched) value = boost::lexical_cast(m[3].str()); if (type1 == t1 and type2 == t2) { result = value; break; } if ((type1 == t1 and type2 == "*") or (type1 == "*" and type2 == "*")) { if (result < value) result = value; } } if (e == h.value.length()) break; b = e + 1; while (b < h.value.length() and isspace(h.value[b])) ++b; e = h.value.find(',', b); } break; } return result; } const boost::regex b("(bb\\d+|meego).+mobile|android|avantgo|bada\\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino", boost::regex::icase), v("1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\\-(n|u)|c55\\/|capi|ccwa|cdm\\-|cell|chtm|cldc|cmd\\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\\-s|devi|dica|dmob|do(c|p)o|ds(12|\\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\\-|_)|g1 u|g560|gene|gf\\-5|g\\-mo|go(\\.w|od)|gr(ad|un)|haie|hcit|hd\\-(m|p|t)|hei\\-|hi(pt|ta)|hp( i|ip)|hs\\-c|ht(c(\\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\\-(20|go|ma)|i230|iac( |\\-|\\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\\/)|klon|kpt |kwc\\-|kyo(c|k)|le(no|xi)|lg( g|\\/(k|l|u)|50|54|\\-[a-w])|libw|lynx|m1\\-w|m3ga|m50\\/|ma(te|ui|xo)|mc(01|21|ca)|m\\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\\-2|po(ck|rt|se)|prox|psio|pt\\-g|qa\\-a|qc(07|12|21|32|60|\\-[2-7]|i\\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\\-|oo|p\\-)|sdk\\/|se(c(\\-|0|1)|47|mc|nd|ri)|sgh\\-|shar|sie(\\-|m)|sk\\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\\-|v\\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\\-|tdg\\-|tel(i|m)|tim\\-|t\\-mo|to(pl|sh)|ts(70|m\\-|m3|m5)|tx\\-9|up(\\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\\-|your|zeto|zte\\-", boost::regex::icase); bool request::is_mobile() const { // this code is adapted from code generated by http://detectmobilebrowsers.com/ bool result = false; foreach (const header& h, headers) { if (h.name != "User-Agent") continue; result = boost::regex_search(h.value, b) or boost::regex_match(h.value.substr(0, 4), v); break; } return result; } } // http } // zeep libzeep-3.0.2/src/document-imp.hpp0000664000175000017500000000246511702652373016726 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008-2012. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef SOAP_XML_DOCUMENT_IMP_H #define SOAP_XML_DOCUMENT_IMP_H #include #include namespace zeep { namespace xml { struct document_imp { document_imp(document* doc); virtual ~document_imp(); virtual void parse(std::istream& data) = 0; std::string prefix_for_namespace(const std::string& ns); root_node m_root; boost::filesystem::path m_dtd_dir; // some content information encoding_type m_encoding; bool m_standalone; int m_indent; bool m_empty; bool m_wrap; bool m_trim; bool m_escape_whitespace; bool m_no_comment; bool m_validating; bool m_preserve_cdata; std::istream* external_entity_ref(const std::string& base, const std::string& pubid, const std::string& sysid); struct notation { std::string m_name; std::string m_sysid; std::string m_pubid; }; document* m_doc; element* m_cur; // construction cdata* m_cdata; // only defined in a CDATA section std::vector > m_namespaces; std::list m_notations; }; } } #endif libzeep-3.0.2/zeep-test.prj0000664000175000017500000000500311547341534015452 0ustar maartenmaarten . ../boost/include /usr/include . src ../boost/lib /usr/lib exception.cpp soap-envelope.cpp soap-server.cpp connection.cpp http-server.cpp preforked-http-server.cpp reply.cpp request_parser.cpp webapp.cpp webapp-el.cpp document.cpp node.cpp doctype.cpp unicode_support.cpp writer.cpp xpath.cpp parser.cpp zeep-test.cpp boost_thread boost_program_options boost_filesystem boost_regex boost_math_c99 boost_system zeep-test Debug zeep-test /usr/bin/g++-4.5 DEBUG BOOST_FILESYSTEM_VERSION=2 -O0 -pthread -gdwarf-2 -std=c++0x -static-libgcc -pthread all no-deprecated zeep-test Release zeep-test /usr/bin/c++ NDEBUG -gdwarf-2 -O3 -static-libgcc -pthread all no-deprecated libzeep-3.0.2/zeep-test.cpp0000664000175000017500000002417512126557631015455 0ustar maartenmaarten// Copyright Maarten L. Hekkelman, Radboud University 2008-2012. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #ifdef NO_PREFORK #undef SOAP_SERVER_HAS_PREFORK #endif #if SOAP_SERVER_HAS_PREFORK #include #include #include #endif #include #include #include #include #include #include using namespace std; int TRACE, VERBOSE; // the data types used in our communication with the outside world // are wrapped in a namespace. namespace WSSearchNS { // the hit information enum HitType { HitTypeOne, HitTypeTwo }; struct Hit { HitType type; string db; string id; string title; float score; int v_int; unsigned int v_uint; long v_long; unsigned long v_ulong; long int v_long2; long unsigned int v_ulong2; long long v_longlong; unsigned long long v_ulonglong; int64 v_longlong2; uint64 v_ulonglong2; long int v_longlong3; unsigned long int v_ulonglong3; boost::posix_time::ptime v_ptime; boost::optional opt_text; template void serialize(Archive& ar, const unsigned int version) { ar & ZEEP_ATTRIBUTE_NAME_VALUE(type) & ZEEP_ATTRIBUTE_NAME_VALUE(db) & ZEEP_ATTRIBUTE_NAME_VALUE(id) & ZEEP_ELEMENT_NAME_VALUE(title) & ZEEP_ELEMENT_NAME_VALUE(v_int) & ZEEP_ELEMENT_NAME_VALUE(v_uint) & ZEEP_ELEMENT_NAME_VALUE(v_long) & ZEEP_ELEMENT_NAME_VALUE(v_ulong) & ZEEP_ELEMENT_NAME_VALUE(v_long2) & ZEEP_ELEMENT_NAME_VALUE(v_ulong2) & ZEEP_ELEMENT_NAME_VALUE(v_longlong) & ZEEP_ELEMENT_NAME_VALUE(v_ulonglong) & ZEEP_ELEMENT_NAME_VALUE(v_longlong2) & ZEEP_ELEMENT_NAME_VALUE(v_ulonglong2) & ZEEP_ELEMENT_NAME_VALUE(v_longlong3) & ZEEP_ELEMENT_NAME_VALUE(v_ulonglong3) & ZEEP_ELEMENT_NAME_VALUE(v_ptime) & ZEEP_ELEMENT_NAME_VALUE(score) & ZEEP_ELEMENT_NAME_VALUE(opt_text) ; } }; // and the FindResult type. struct FindResult { int count; vector hits; FindResult() : count(0) {} template void serialize(Archive& ar, const unsigned int version) { ar & zeep::xml::make_attribute_nvp("count", count) & zeep::xml::make_element_nvp("hit", hits); } }; // these are the supported algorithms for ranked searching enum Algorithm { Vector, Dice, Jaccard }; } namespace zeep { namespace xml { template struct struct_serializer { static void serialize(Archive& ar, WSSearchNS::Hit& hit) { // ar & BOOST_SERIALIZATION_NVP(hit.db) // & BOOST_SERIALIZATION_NVP(hit.id) // & BOOST_SERIALIZATION_NVP(hit.title) // & BOOST_SERIALIZATION_NVP(hit.score); hit.serialize(ar, 0); } }; template struct struct_serializer > { static void serialize(Archive& ar, std::pair& pair) { ar & BOOST_SERIALIZATION_NVP(pair.first); ar & BOOST_SERIALIZATION_NVP(pair.second); } }; } } // now construct a server that can do several things: // ListDatabanks: simply return the list of searchable databanks // Count: a simple call taking two parameters and returning one // Find: complex search routine taking several parameters and returning a complex type class my_server : public zeep::server { public: my_server( const string& my_param); void ListDatabanks( vector& databanks); void Count( const string& db, const string& booleanquery, unsigned int& result); void Find( const string& db, const vector& queryterms, WSSearchNS::Algorithm algorithm, bool alltermsrequired, const string& booleanfilter, int resultoffset, int maxresultcount, WSSearchNS::FindResult& out); void PairTest(const string& in, pair& out); void DateTimeTest( const boost::posix_time::ptime& in, boost::posix_time::ptime& out); void ForceStop(string& out); protected: /* Uncomment to have your custom http logger virtual void log_request(const boost::asio::ip::address& addr, const zeep::http::request& req, const zeep::http::reply& rep, const boost::posix_time::ptime& start, const std::string& referer, const std::string& userAgent, const std::string& entry) { cout << "Not logging :) ..." << endl; } */ private: string m_param; }; my_server::my_server(const string& param) : zeep::server("http://mrs.cmbi.ru.nl/mrsws/search", "zeep") , m_param(param) { set_location("http://131.174.88.174:10333"); using namespace WSSearchNS; zeep::xml::enum_map::instance("HitType").add_enum() ( "HitTypeOne", HitTypeOne ) ( "HitTypeTwo", HitTypeTwo ) ; zeep::xml::struct_serializer_impl::set_struct_name("Hit"); // The next call is needed since FindResult is defined in another namespace SOAP_XML_SET_STRUCT_NAME(FindResult); const char* kListDatabanksParameterNames[] = { "databank" }; register_action("ListDatabanks", this, &my_server::ListDatabanks, kListDatabanksParameterNames); const char* kCountParameterNames[] = { "db", "booleanquery", "response" }; register_action("Count", this, &my_server::Count, kCountParameterNames); // a new way of mapping enum values to strings. zeep::xml::enum_map::instance("Algorithm").add_enum() ( "Vector", Vector ) ( "Dice", Dice ) ( "Jaccard", Jaccard ) ; // this is the old, macro based way of mapping the enums: // SOAP_XML_ADD_ENUM(Algorithm, Vector); // SOAP_XML_ADD_ENUM(Algorithm, Dice); // SOAP_XML_ADD_ENUM(Algorithm, Jaccard); const char* kFindParameterNames[] = { "db", "queryterms", "algorithm", "alltermsrequired", "booleanfilter", "resultoffset", "maxresultcount", "out" }; register_action("Find", this, &my_server::Find, kFindParameterNames); const char* kDateTimeTestParameterNames[] = { "in", "out" }; register_action("DateTimeTest", this, &my_server::DateTimeTest, kDateTimeTestParameterNames); const char* kForceStopParameterNames[] = { "out" }; register_action("ForceStop", this, &my_server::ForceStop, kForceStopParameterNames); const char* kPairTestParameterNames[] = { "in", "out" }; zeep::xml::struct_serializer_impl >::set_struct_name("pair_of_ints"); register_action("PairTest", this, &my_server::PairTest, kPairTestParameterNames); } void my_server::ListDatabanks( vector& response) { response.push_back("sprot"); response.push_back("trembl"); } void my_server::Count( const string& db, const string& booleanquery, unsigned int& result) { if (db != "sprot" and db != "trembl" and db != "uniprot") throw zeep::exception("Unknown databank: %s", db.c_str()); log() << db; result = 10; } void my_server::Find( const string& db, const vector& queryterms, WSSearchNS::Algorithm algorithm, bool alltermsrequired, const string& booleanfilter, int resultoffset, int maxresultcount, WSSearchNS::FindResult& out) { log() << db; // mock up some fake answer... out.count = 3; WSSearchNS::Hit h = {}; h.db = "sprot"; h.id = "104k_thepa"; h.title = "bla bla bla"; h.score = 1.0f; h.v_ptime = boost::posix_time::microsec_clock::universal_time(); out.hits.push_back(h); h.db = "sprot"; h.id = "108_lyces"; h.title = "aap <&> noot mies"; h.score = 0.8f; h.opt_text = "Hallóóów"; out.hits.push_back(h); h.db = "param"; h.id = "param-id"; h.title = m_param; h.score = 0.6f; h.opt_text.reset(); out.hits.push_back(h); } void my_server::PairTest(const string& in, pair& out) { out.first = out.second = 1; } void my_server::DateTimeTest( const boost::posix_time::ptime& in, boost::posix_time::ptime& out) { log() << in; out = in; } void my_server::ForceStop( string& out) { exit(1); } int main(int argc, const char* argv[]) { #if SOAP_SERVER_HAS_PREFORK for (;;) { cout << "restarting server" << endl; sigset_t new_mask, old_mask; sigfillset(&new_mask); pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask); zeep::http::preforked_server server("bla bla"); boost::thread t( boost::bind(&zeep::http::preforked_server::run, &server, "131.174.88.174", 10333, 2)); server.start(); pthread_sigmask(SIG_SETMASK, &old_mask, 0); // Wait for signal indicating time to shut down. sigset_t wait_mask; sigemptyset(&wait_mask); sigaddset(&wait_mask, SIGINT); sigaddset(&wait_mask, SIGHUP); sigaddset(&wait_mask, SIGQUIT); sigaddset(&wait_mask, SIGTERM); sigaddset(&wait_mask, SIGCHLD); pthread_sigmask(SIG_BLOCK, &wait_mask, 0); int sig = 0; sigwait(&wait_mask, &sig); pthread_sigmask(SIG_SETMASK, &old_mask, 0); server.stop(); t.join(); if (sig == SIGCHLD) { int status, pid; pid = waitpid(-1, &status, WUNTRACED); if (pid != -1 and WIFSIGNALED(status)) cout << "child " << pid << " terminated by signal " << WTERMSIG(status) << endl; continue; } if (sig == SIGHUP) continue; break; } #elif defined(_MSC_VER) my_server server("blabla"); server.bind("0.0.0.0", 10333); boost::thread t(boost::bind(&my_server::run, &server, 2)); t.join(); #else for (;;) { sigset_t new_mask, old_mask; sigfillset(&new_mask); pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask); my_server server("blabla"); server.bind("0.0.0.0", 10333); boost::thread t(boost::bind(&my_server::run, &server, 2)); pthread_sigmask(SIG_SETMASK, &old_mask, 0); // Wait for signal indicating time to shut down. sigset_t wait_mask; sigemptyset(&wait_mask); sigaddset(&wait_mask, SIGINT); sigaddset(&wait_mask, SIGQUIT); sigaddset(&wait_mask, SIGTERM); sigaddset(&wait_mask, SIGHUP); pthread_sigmask(SIG_BLOCK, &wait_mask, 0); int sig = 0; sigwait(&wait_mask, &sig); server.stop(); t.join(); if (sig == SIGHUP) { cout << "restarting server" << endl; continue; } break; } #endif return 0; } libzeep-3.0.2/doc/0000775000175000017500000000000012162310454013553 5ustar maartenmaartenlibzeep-3.0.2/doc/Jamroot.jam0000664000175000017500000000000111756635106015662 0ustar maartenmaarten libzeep-3.0.2/doc/html/0000775000175000017500000000000012162310454014517 5ustar maartenmaartenlibzeep-3.0.2/doc/html/zeep/0000755000175000017500000000000012162310454015460 5ustar maartenmaartenlibzeep-3.0.2/doc/html/zeep/make_fault_idp7490768.html0000664000175000017500000001002512162310454022103 0ustar maartenmaarten Function make_fault

PrevUpHomeNext

Function make_fault

zeep::make_fault

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/envelope.hpp>


xml::element * make_fault(const std::exception & ex);

Description

Create a standard SOAP Fault message for the exception object

Parameters:

ex

The exception object that was catched.

Returns:

A new xml::element object containing the fault envelope.


PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/make_fault_idp7489904.html0000664000175000017500000001002512162310454022103 0ustar maartenmaarten Function make_fault

PrevUpHomeNext

Function make_fault

zeep::make_fault

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/envelope.hpp>


xml::element * make_fault(const std::exception & ex);

Description

Create a standard SOAP Fault message for the exception object

Parameters:

ex

The exception object that was catched.

Returns:

A new xml::element object containing the fault envelope.


PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/make_envelope.html0000664000175000017500000001003312162310454021157 0ustar maartenmaarten Function make_envelope

PrevUpHomeNext

Function make_envelope

zeep::make_envelope

Synopsis

Description

Wrap data into a SOAP envelope

Parameters:

data

The xml::element object to wrap into the envelope

Returns:

A new xml::element object containing the envelope.


PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/make_fault_idp5639792.html0000664000175000017500000001010212162310454022077 0ustar maartenmaarten Function make_fault

PrevUpHomeNext

Function make_fault

zeep::make_fault

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/envelope.hpp>


xml::element * make_fault(const std::string & message);

Description

Create a standard SOAP Fault message for the string parameter

Parameters:

message

The string object containing a descriptive error message.

Returns:

A new xml::element object containing the fault envelope.


PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/envelope.html0000664000175000017500000001326012162310454020167 0ustar maartenmaarten Class envelope

PrevUpHomeNext

Class envelope

zeep::envelope

Synopsis

Description

envelope public construct/copy/destruct

  1. envelope();
    Create an empty envelope.
  2. envelope(xml::document & data);
    Parse a SOAP message received from a client, throws an exception if the envelope is empty or invalid.

envelope public member functions

  1. xml::element * request();
    The request element as contained in the original SOAP message.

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/make_fault_idp7490464.html0000664000175000017500000001001712162310454022075 0ustar maartenmaarten Function make_fault

PrevUpHomeNext

Function make_fault

zeep::make_fault

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/envelope.hpp>


xml::element * make_fault(const std::exception & ex);

Description

Create a standard SOAP Fault message for the exception object

Parameters:

ex

The exception object that was catched.

Returns:

A new xml::element object containing the fault envelope.


PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/0000755000175000017500000000000012162310454016437 5ustar maartenmaartenlibzeep-3.0.2/doc/html/zeep/http/preforked_server_base/0000755000175000017500000000000012162310454023000 5ustar maartenmaartenlibzeep-3.0.2/doc/html/zeep/http/preforked_server_base/server_constructor_void_idp7525184.html0000664000175000017500000001362212162310454032304 0ustar maartenmaarten Struct template server_constructor<void(Server::*)(T0, T1)>

PrevUpHomeNext

Struct template server_constructor<void(Server::*)(T0, T1)>

zeep::http::preforked_server_base::server_constructor<void(Server::*)(T0, T1)>

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/preforked-server.hpp>


template<typename Server, typename T0, typename T1> 
struct server_constructor<void(Server::*)(T0, T1)> {

  // public member functions
   server_constructor(T0, T1);
  server * construct();
};

Description

server_constructor public member functions

  1.  server_constructor(T0 t0, T1 t1);
  2. server * construct();

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/preforked_server_base/server_constructor_void_idp7515648.html0000664000175000017500000001165512162310454032314 0ustar maartenmaarten Struct template server_constructor<void(Server::*)()>

PrevUpHomeNext

Struct template server_constructor<void(Server::*)()>

zeep::http::preforked_server_base::server_constructor<void(Server::*)()>

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/preforked-server.hpp>


template<typename Server> 
struct server_constructor<void(Server::*)()> {

  // public member functions
  server * construct();
};

Description

server_constructor public member functions

  1. server * construct();

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/preforked_server_base/server_constructor_void_idp7532080.html0000664000175000017500000001414012162310454032271 0ustar maartenmaarten Struct template server_constructor<void(Server::*)(T0, T1, T2)>

PrevUpHomeNext

Struct template server_constructor<void(Server::*)(T0, T1, T2)>

zeep::http::preforked_server_base::server_constructor<void(Server::*)(T0, T1, T2)>

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/preforked-server.hpp>


template<typename Server, typename T0, typename T1, typename T2> 
struct server_constructor<void(Server::*)(T0, T1, T2)> {

  // public member functions
   server_constructor(T0, T1, T2);
  server * construct();
};

Description

server_constructor public member functions

  1.  server_constructor(T0 t0, T1 t1, T2 t2);
  2. server * construct();

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/preforked_server_base/server_constructor_void_idp7224272.html0000664000175000017500000001413712162310454032300 0ustar maartenmaarten Struct template server_constructor<void(Server::*)(T0, T1, T2)>

PrevUpHomeNext

Struct template server_constructor<void(Server::*)(T0, T1, T2)>

zeep::http::preforked_server_base::server_constructor<void(Server::*)(T0, T1, T2)>

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/preforked-server.hpp>


template<typename Server, typename T0, typename T1, typename T2> 
struct server_constructor<void(Server::*)(T0, T1, T2)> {

  // public member functions
   server_constructor(T0, T1, T2);
  server * construct();
};

Description

server_constructor public member functions

  1.  server_constructor(T0 t0, T1 t1, T2 t2);
  2. server * construct();

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/preforked_server_base/server_constructor_void_idp7518960.html0000664000175000017500000001315712162310454032313 0ustar maartenmaarten Struct template server_constructor<void(Server::*)(T0)>

PrevUpHomeNext

Struct template server_constructor<void(Server::*)(T0)>

zeep::http::preforked_server_base::server_constructor<void(Server::*)(T0)>

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/preforked-server.hpp>


template<typename Server, typename T0> 
struct server_constructor<void(Server::*)(T0)> {

  // public member functions
   server_constructor(T0);
  server * construct();
};

Description

server_constructor public member functions

  1.  server_constructor(T0 t0);
  2. server * construct();

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/preforked_server_base/server_constructor_void_idp7531776.html0000664000175000017500000001414012162310454032304 0ustar maartenmaarten Struct template server_constructor<void(Server::*)(T0, T1, T2)>

PrevUpHomeNext

Struct template server_constructor<void(Server::*)(T0, T1, T2)>

zeep::http::preforked_server_base::server_constructor<void(Server::*)(T0, T1, T2)>

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/preforked-server.hpp>


template<typename Server, typename T0, typename T1, typename T2> 
struct server_constructor<void(Server::*)(T0, T1, T2)> {

  // public member functions
   server_constructor(T0, T1, T2);
  server * construct();
};

Description

server_constructor public member functions

  1.  server_constructor(T0 t0, T1 t1, T2 t2);
  2. server * construct();

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/preforked_server_base/server_constructor_void_idp7524320.html0000664000175000017500000001362212162310454032273 0ustar maartenmaarten Struct template server_constructor<void(Server::*)(T0, T1)>

PrevUpHomeNext

Struct template server_constructor<void(Server::*)(T0, T1)>

zeep::http::preforked_server_base::server_constructor<void(Server::*)(T0, T1)>

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/preforked-server.hpp>


template<typename Server, typename T0, typename T1> 
struct server_constructor<void(Server::*)(T0, T1)> {

  // public member functions
   server_constructor(T0, T1);
  server * construct();
};

Description

server_constructor public member functions

  1.  server_constructor(T0 t0, T1 t1);
  2. server * construct();

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/preforked_server_base/server_constructor_void_idp7519824.html0000664000175000017500000001315712162310454032313 0ustar maartenmaarten Struct template server_constructor<void(Server::*)(T0)>

PrevUpHomeNext

Struct template server_constructor<void(Server::*)(T0)>

zeep::http::preforked_server_base::server_constructor<void(Server::*)(T0)>

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/preforked-server.hpp>


template<typename Server, typename T0> 
struct server_constructor<void(Server::*)(T0)> {

  // public member functions
   server_constructor(T0);
  server * construct();
};

Description

server_constructor public member functions

  1.  server_constructor(T0 t0);
  2. server * construct();

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/preforked_server_base/server_constructor_void_idp7531216.html0000664000175000017500000001414012162310454032271 0ustar maartenmaarten Struct template server_constructor<void(Server::*)(T0, T1, T2)>

PrevUpHomeNext

Struct template server_constructor<void(Server::*)(T0, T1, T2)>

zeep::http::preforked_server_base::server_constructor<void(Server::*)(T0, T1, T2)>

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/preforked-server.hpp>


template<typename Server, typename T0, typename T1, typename T2> 
struct server_constructor<void(Server::*)(T0, T1, T2)> {

  // public member functions
   server_constructor(T0, T1, T2);
  server * construct();
};

Description

server_constructor public member functions

  1.  server_constructor(T0 t0, T1 t1, T2 t2);
  2. server * construct();

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/preforked_server_base/server_constructor_void_idp7217376.html0000664000175000017500000001362112162310454032304 0ustar maartenmaarten Struct template server_constructor<void(Server::*)(T0, T1)>

PrevUpHomeNext

Struct template server_constructor<void(Server::*)(T0, T1)>

zeep::http::preforked_server_base::server_constructor<void(Server::*)(T0, T1)>

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/preforked-server.hpp>


template<typename Server, typename T0, typename T1> 
struct server_constructor<void(Server::*)(T0, T1)> {

  // public member functions
   server_constructor(T0, T1);
  server * construct();
};

Description

server_constructor public member functions

  1.  server_constructor(T0 t0, T1 t1);
  2. server * construct();

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/preforked_server_base/server_constructor_void_idp7208704.html0000664000175000017500000001165412162310454032303 0ustar maartenmaarten Struct template server_constructor<void(Server::*)()>

PrevUpHomeNext

Struct template server_constructor<void(Server::*)()>

zeep::http::preforked_server_base::server_constructor<void(Server::*)()>

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/preforked-server.hpp>


template<typename Server> 
struct server_constructor<void(Server::*)()> {

  // public member functions
  server * construct();
};

Description

server_constructor public member functions

  1. server * construct();

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/preforked_server_base/server_constructor_void_idp7516208.html0000664000175000017500000001165512162310454032305 0ustar maartenmaarten Struct template server_constructor<void(Server::*)()>

PrevUpHomeNext

Struct template server_constructor<void(Server::*)()>

zeep::http::preforked_server_base::server_constructor<void(Server::*)()>

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/preforked-server.hpp>


template<typename Server> 
struct server_constructor<void(Server::*)()> {

  // public member functions
  server * construct();
};

Description

server_constructor public member functions

  1. server * construct();

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/preforked_server_base/server_constructor_void_idp7516512.html0000664000175000017500000001165512162310454032303 0ustar maartenmaarten Struct template server_constructor<void(Server::*)()>

PrevUpHomeNext

Struct template server_constructor<void(Server::*)()>

zeep::http::preforked_server_base::server_constructor<void(Server::*)()>

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/preforked-server.hpp>


template<typename Server> 
struct server_constructor<void(Server::*)()> {

  // public member functions
  server * construct();
};

Description

server_constructor public member functions

  1. server * construct();

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/preforked_server_base/server_constructor_void_idp7212016.html0000664000175000017500000001315612162310454032271 0ustar maartenmaarten Struct template server_constructor<void(Server::*)(T0)>

PrevUpHomeNext

Struct template server_constructor<void(Server::*)(T0)>

zeep::http::preforked_server_base::server_constructor<void(Server::*)(T0)>

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/preforked-server.hpp>


template<typename Server, typename T0> 
struct server_constructor<void(Server::*)(T0)> {

  // public member functions
   server_constructor(T0);
  server * construct();
};

Description

server_constructor public member functions

  1.  server_constructor(T0 t0);
  2. server * construct();

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/preforked_server_base/server_constructor_void_idp7524880.html0000664000175000017500000001362212162310454032306 0ustar maartenmaarten Struct template server_constructor<void(Server::*)(T0, T1)>

PrevUpHomeNext

Struct template server_constructor<void(Server::*)(T0, T1)>

zeep::http::preforked_server_base::server_constructor<void(Server::*)(T0, T1)>

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/preforked-server.hpp>


template<typename Server, typename T0, typename T1> 
struct server_constructor<void(Server::*)(T0, T1)> {

  // public member functions
   server_constructor(T0, T1);
  server * construct();
};

Description

server_constructor public member functions

  1.  server_constructor(T0 t0, T1 t1);
  2. server * construct();

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/preforked_server_base/server_constructor_void_idp7519520.html0000664000175000017500000001315712162310454032304 0ustar maartenmaarten Struct template server_constructor<void(Server::*)(T0)>

PrevUpHomeNext

Struct template server_constructor<void(Server::*)(T0)>

zeep::http::preforked_server_base::server_constructor<void(Server::*)(T0)>

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/preforked-server.hpp>


template<typename Server, typename T0> 
struct server_constructor<void(Server::*)(T0)> {

  // public member functions
   server_constructor(T0);
  server * construct();
};

Description

server_constructor public member functions

  1.  server_constructor(T0 t0);
  2. server * construct();

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/decode_url.html0000664000175000017500000000761612162310454021446 0ustar maartenmaarten Function decode_url

PrevUpHomeNext

Function decode_url

zeep::http::decode_url

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/server.hpp>


std::string decode_url(const std::string & s);

Description

Decode a URL using the RFC rules

Parameters:

s

The URL that needs to be decoded

Returns:

The decoded URL


PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/el/0000755000175000017500000000000012162310454017037 5ustar maartenmaartenlibzeep-3.0.2/doc/html/zeep/http/el/object.html0000664000175000017500000013660212162310454021205 0ustar maartenmaarten Class object

PrevUpHomeNext

Class object

zeep::http::el::object — This zeep::http::el::object class is a bridge to the `el` expression language.

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/webapp/el.hpp>


class object {
public:
  // types
  typedef basic_iterator< object >       iterator;      
  typedef basic_iterator< const object > const_iterator;

  // member classes/structs/unions
  template<typename ObjectType> 
  class basic_iterator {
  public:
    // types
    typedef std::iterator< std::forward_iterator_tag, ObjectType > base_type;
    typedef base_type::reference                                   reference;
    typedef base_type::pointer                                     pointer;  

    // construct/copy/destruct
    basic_iterator();
    basic_iterator(const basic_iterator &);
    basic_iterator(unspecified);
    basic_iterator(unspecified, int);
    basic_iterator(unspecified);
    basic_iterator(unspecified, int);
    basic_iterator& operator=(const basic_iterator &);
    ~basic_iterator();

    // public member functions
    reference operator*() const;
    pointer operator->() const;
    basic_iterator & operator++();
    basic_iterator operator++(int);
    bool operator==(const basic_iterator &) const;
    bool operator!=(const basic_iterator &) const;
  };

  // object can have one of these basic types: 
  enum object_type { null_type, array_type, struct_type, number_type, 
                     string_type };

  // construct/copy/destruct
  object();
  object(const object &);
  explicit object(unspecified);
  explicit object(const std::vector< object > &);
  explicit object(const std::vector< std::string > &);
  explicit object(bool);
  explicit object(int8);
  explicit object(uint8);
  explicit object(int16);
  explicit object(uint16);
  explicit object(int32);
  explicit object(uint32);
  explicit object(int64);
  explicit object(uint64);
  explicit object(float);
  explicit object(double);
  explicit object(const char *);
  explicit object(const std::string &);
  object& operator=(const object &);
  object& operator=(const std::vector< object > &);
  object& operator=(const std::vector< std::string > &);
  object& operator=(bool);
  object& operator=(int8);
  object& operator=(uint8);
  object& operator=(int16);
  object& operator=(uint16);
  object& operator=(int32);
  object& operator=(uint32);
  object& operator=(int64);
  object& operator=(uint64);
  object& operator=(float);
  object& operator=(double);
  object& operator=(const char *);
  object& operator=(const std::string &);
  ~object();

  // public member functions
  object_type type() const;
  template<typename T> T as() const;
  const object operator[](const std::string &) const;
  const object operator[](const char *) const;
  const object operator[](const object &) const;
  object & operator[](const std::string &);
  object & operator[](const char *);
  object & operator[](const object &);
  size_t count() const;
  bool empty() const;
  bool operator<(const object &) const;
  bool operator==(const object &) const;
  iterator begin();
  iterator end();
  const_iterator begin() const;
  const_iterator end() const;
  std::string toJSON() const;
};

Description

object public construct/copy/destruct

  1. object();
  2. object(const object & o);
  3. explicit object(unspecified impl);
  4. explicit object(const std::vector< object > & v);
    create an array object
  5. explicit object(const std::vector< std::string > & v);
  6. explicit object(bool v);
    construct an object directly from some basic types
  7. explicit object(int8 v);
  8. explicit object(uint8 v);
  9. explicit object(int16 v);
  10. explicit object(uint16 v);
  11. explicit object(int32 v);
  12. explicit object(uint32 v);
  13. explicit object(int64 v);
  14. explicit object(uint64 v);
  15. explicit object(float v);
  16. explicit object(double v);
  17. explicit object(const char * v);
  18. explicit object(const std::string & v);
  19. object& operator=(const object & o);
  20. object& operator=(const std::vector< object > & v);
    assign an array object
  21. object& operator=(const std::vector< std::string > & v);
  22. object& operator=(bool v);
    and assign some basic types
  23. object& operator=(int8 v);
  24. object& operator=(uint8 v);
  25. object& operator=(int16 v);
  26. object& operator=(uint16 v);
  27. object& operator=(int32 v);
  28. object& operator=(uint32 v);
  29. object& operator=(int64 v);
  30. object& operator=(uint64 v);
  31. object& operator=(float v);
  32. object& operator=(double v);
  33. object& operator=(const char * v);
  34. object& operator=(const std::string & v);
  35. ~object();

object public member functions

  1. object_type type() const;
  2. template<typename T> T as() const;
  3. const object operator[](const std::string & name) const;
  4. const object operator[](const char * name) const;
  5. const object operator[](const object & index) const;
  6. object & operator[](const std::string & name);
  7. object & operator[](const char * name);
  8. object & operator[](const object & index);
  9. size_t count() const;
  10. bool empty() const;
  11. bool operator<(const object & rhs) const;
  12. bool operator==(const object & rhs) const;
  13. iterator begin();
  14. iterator end();
  15. const_iterator begin() const;
  16. const_iterator end() const;
  17. std::string toJSON() const;

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/el/evaluate_el_idp7904656.html0000664000175000017500000001126212162310454023640 0ustar maartenmaarten Function evaluate_el

PrevUpHomeNext

Function evaluate_el

zeep::http::el::evaluate_el — Process the text in text. The result is put in result.

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/webapp/el.hpp>


void evaluate_el(const scope & scope, const std::string & text, 
                 object & result);

Description

The expression in text is processed and the result is returned in result.

Parameters:

scope

The scope for this el script

text

The el script

Returns:

The result of the script


PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/el/process_el.html0000664000175000017500000001071512162310454022071 0ustar maartenmaarten Function process_el

PrevUpHomeNext

Function process_el

zeep::http::el::process_el — Process the text in text and return `true` if the result is not empty, zero or false.

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/webapp/el.hpp>


bool process_el(const scope & scope, std::string & text);

Description

The expression in text is processed and if the result of this expression is empty, false or zero then `false` is returned.

Parameters:

scope

The scope for this el script

text

The el script

Returns:

The result of the script


PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/el/evaluate_el_idp7911648.html0000664000175000017500000001111412162310454023633 0ustar maartenmaarten Function evaluate_el

PrevUpHomeNext

Function evaluate_el

zeep::http::el::evaluate_el — Process the text in text and replace it with the result.

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/webapp/el.hpp>


bool evaluate_el(const scope & scope, const std::string & text);

Description

The expressions found in text are processed and the output of the processing is used as a replacement value for the expressions.

Parameters:

scope

The scope for the el scripts

text

The text optionally containing el scripts.

Returns:

Returns true if text was changed.


PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/el/object/0000755000175000017500000000000012162310454020305 5ustar maartenmaartenlibzeep-3.0.2/doc/html/zeep/http/el/object/basic_iterator.html0000664000175000017500000003546412162310454024203 0ustar maartenmaarten Class template basic_iterator

PrevUpHomeNext

Class template basic_iterator

zeep::http::el::object::basic_iterator

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/webapp/el.hpp>


template<typename ObjectType> 
class basic_iterator {
public:
  // types
  typedef std::iterator< std::forward_iterator_tag, ObjectType > base_type;
  typedef base_type::reference                                   reference;
  typedef base_type::pointer                                     pointer;  

  // construct/copy/destruct
  basic_iterator();
  basic_iterator(const basic_iterator &);
  basic_iterator(unspecified);
  basic_iterator(unspecified, int);
  basic_iterator(unspecified);
  basic_iterator(unspecified, int);
  basic_iterator& operator=(const basic_iterator &);
  ~basic_iterator();

  // public member functions
  reference operator*() const;
  pointer operator->() const;
  basic_iterator & operator++();
  basic_iterator operator++(int);
  bool operator==(const basic_iterator &) const;
  bool operator!=(const basic_iterator &) const;
};

Description

basic_iterator public construct/copy/destruct

  1. basic_iterator();
  2. basic_iterator(const basic_iterator & other);
  3. basic_iterator(unspecified a);
  4. basic_iterator(unspecified a, int);
  5. basic_iterator(unspecified a);
  6. basic_iterator(unspecified a, int);
  7. basic_iterator& operator=(const basic_iterator & other);
  8. ~basic_iterator();

basic_iterator public member functions

  1. reference operator*() const;
  2. pointer operator->() const;
  3. basic_iterator & operator++();
  4. basic_iterator operator++(int);
  5. bool operator==(const basic_iterator & other) const;
  6. bool operator!=(const basic_iterator & other) const;

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/el/evaluate_el_idp7911088.html0000664000175000017500000001111412162310454023631 0ustar maartenmaarten Function evaluate_el

PrevUpHomeNext

Function evaluate_el

zeep::http::el::evaluate_el — Process the text in text and replace it with the result.

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/webapp/el.hpp>


bool evaluate_el(const scope & scope, const std::string & text);

Description

The expressions found in text are processed and the output of the processing is used as a replacement value for the expressions.

Parameters:

scope

The scope for the el scripts

text

The text optionally containing el scripts.

Returns:

Returns true if text was changed.


PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/el/scope.html0000664000175000017500000004200212162310454021036 0ustar maartenmaarten Class scope

PrevUpHomeNext

Class scope

zeep::http::el::scope

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/webapp/el.hpp>


class scope {
public:
  // construct/copy/destruct
  scope(const request &);
  explicit scope(const scope &);
  scope& operator=(const scope &);

  // public member functions
  template<typename T> void put(const std::string &, const T &);
  template<typename ForwardIterator> 
    void put(const std::string &, ForwardIterator, ForwardIterator);
  const object & lookup(const std::string &) const;
  const object & operator[](const std::string &) const;
  object & lookup(const std::string &);
  object & operator[](const std::string &);
  const request & get_request() const;
  template<> void put(const std::string &, const object &);

  // friend functions
  friend std::ostream & operator<<(std::ostream &, const scope &);
};

Description

scope public construct/copy/destruct

  1. scope(const request & req);
  2. explicit scope(const scope & next);
  3. scope& operator=(const scope &);

scope public member functions

  1. template<typename T> void put(const std::string & name, const T & value);
  2. template<typename ForwardIterator> 
      void put(const std::string & name, ForwardIterator begin, 
               ForwardIterator end);
  3. const object & lookup(const std::string & name) const;
  4. const object & operator[](const std::string & name) const;
  5. object & lookup(const std::string & name);
  6. object & operator[](const std::string & name);
  7. const request & get_request() const;
  8. template<> void put(const std::string & name, const object & value);

scope friend functions

  1. friend std::ostream & operator<<(std::ostream & lhs, const scope & rhs);
    for debugging purposes

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/el/evaluate_el_idp7604160.html0000664000175000017500000001113312162310454023620 0ustar maartenmaarten Function evaluate_el

PrevUpHomeNext

Function evaluate_el

zeep::http::el::evaluate_el — Process the text in text and replace it with the result.

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/webapp/el.hpp>


bool evaluate_el(const scope & scope, const std::string & text);

Description

The expressions found in text are processed and the output of the processing is used as a replacement value for the expressions.

Parameters:

scope

The scope for the el scripts

text

The text optionally containing el scripts.

Returns:

Returns true if text was changed.


PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/el/evaluate_el_idp7596864.html0000664000175000017500000001130112162310454023642 0ustar maartenmaarten Function evaluate_el

PrevUpHomeNext

Function evaluate_el

zeep::http::el::evaluate_el — Process the text in text. The result is put in result.

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/webapp/el.hpp>


void evaluate_el(const scope & scope, const std::string & text, 
                 object & result);

Description

The expression in text is processed and the result is returned in result.

Parameters:

scope

The scope for this el script

text

The el script

Returns:

The result of the script


PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/el/evaluate_el_idp7904352.html0000664000175000017500000001126212162310454023631 0ustar maartenmaarten Function evaluate_el

PrevUpHomeNext

Function evaluate_el

zeep::http::el::evaluate_el — Process the text in text. The result is put in result.

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/webapp/el.hpp>


void evaluate_el(const scope & scope, const std::string & text, 
                 object & result);

Description

The expression in text is processed and the result is returned in result.

Parameters:

scope

The scope for this el script

text

The el script

Returns:

The result of the script


PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/el/evaluate_el_idp7903792.html0000664000175000017500000001126212162310454023640 0ustar maartenmaarten Function evaluate_el

PrevUpHomeNext

Function evaluate_el

zeep::http::el::evaluate_el — Process the text in text. The result is put in result.

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/webapp/el.hpp>


void evaluate_el(const scope & scope, const std::string & text, 
                 object & result);

Description

The expression in text is processed and the result is returned in result.

Parameters:

scope

The scope for this el script

text

The el script

Returns:

The result of the script


PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/el/evaluate_el_idp7911952.html0000664000175000017500000001111412162310454023631 0ustar maartenmaarten Function evaluate_el

PrevUpHomeNext

Function evaluate_el

zeep::http::el::evaluate_el — Process the text in text and replace it with the result.

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/webapp/el.hpp>


bool evaluate_el(const scope & scope, const std::string & text);

Description

The expressions found in text are processed and the output of the processing is used as a replacement value for the expressions.

Parameters:

scope

The scope for the el scripts

text

The text optionally containing el scripts.

Returns:

Returns true if text was changed.


PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/request.html0000664000175000017500000001610512162310454021022 0ustar maartenmaarten Struct request

PrevUpHomeNext

Struct request

zeep::http::request

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/request.hpp>


struct request {

  // public member functions
  float accept(const char *) const;
  bool is_mobile() const;

  // public data members
  std::string method;  // POST or GET. 
  std::string uri;  // The uri as requested. 
  int http_version_major;  // HTTP major number (usually 1) 
  int http_version_minor;  // HTTP major number (0 or 1) 
  std::vector< header > headers;  // A list with zeep::http::header values. 
  std::string payload;  // For POST requests. 
  bool close;  // Whether 'Connection: close' was specified. 
  std::string local_address;  // The address the request was received upon. 
  unsigned short local_port;  // The port number the request was received upon. 
};

Description

request contains the parsed original HTTP request as received by the server.

request public member functions

  1. float accept(const char * type) const;
    Return the value in the Accept header for type.
  2. bool is_mobile() const;
    Check HTTP_USER_AGENT to see if it is a mobile client.

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/preforked_server.html0000664000175000017500000001770512162310454022710 0ustar maartenmaarten Class template preforked_server

PrevUpHomeNext

Class template preforked_server

zeep::http::preforked_server

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/preforked-server.hpp>

template<typename Server> 
class preforked_server : public zeep::http::preforked_server_base {
public:
  // construct/copy/destruct
  preforked_server();
  template<typename T0> preforked_server(T0);
  template<typename T0, typename T1> preforked_server(T0, T1);
  template<typename T0, typename T1, typename T2> preforked_server(T0, T1, T2);
};

Description

preforked_server public construct/copy/destruct

  1. preforked_server();
    Four constructors, one without and three with parameters.
  2. template<typename T0> preforked_server(T0 t0);
  3. template<typename T0, typename T1> preforked_server(T0 t0, T1 t1);
  4. template<typename T0, typename T1, typename T2> 
      preforked_server(T0 t0, T1 t1, T2 t2);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/unauthorized_exception.html0000664000175000017500000001212112162310454024123 0ustar maartenmaarten Struct unauthorized_exception

PrevUpHomeNext

Struct unauthorized_exception

zeep::http::unauthorized_exception

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/webapp.hpp>


struct unauthorized_exception {
  // construct/copy/destruct
  unauthorized_exception(bool, const std::string &);

  // public data members
  bool m_stale;  // Is true when the authorization information is valid but stale (too old) 
  char m_realm;  // Realm for which the authorization failed. 
};

Description

unauthorized_exception public construct/copy/destruct

  1. unauthorized_exception(bool stale, const std::string & realm);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/reply.html0000664000175000017500000005047712162310454020477 0ustar maartenmaarten Class reply

PrevUpHomeNext

Class reply

zeep::http::reply

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/reply.hpp>


class reply {
public:
  // construct/copy/destruct
  reply(int = 1, int = 0);
  reply(const reply &);
  reply& operator=(const reply &);

  // public member functions
  void set_version(int, int);
  void set_header(const std::string &, const std::string &);
  std::string get_content_type() const;
  void set_content_type(const std::string &);
  void set_content(xml::document &);
  void set_content(xml::element *);
  void set_content(const std::string &, const std::string &);
  void set_content(std::istream *, const std::string &);
  void to_buffers(std::vector< boost::asio::const_buffer > &);
  bool data_to_buffers(std::vector< boost::asio::const_buffer > &);
  std::string get_as_text();
  std::size_t get_size() const;
  status_type get_status() const;

  // public static functions
  static reply stock_reply(status_type);
  static reply redirect(const std::string &);
};

Description

reply public construct/copy/destruct

  1. reply(int version_major = 1, int version_minor = 0);
    Create a reply, default is HTTP 1.0. Use 1.1 if you want to use keep alive e.g.
  2. reply(const reply &);
  3. reply& operator=(const reply &);

reply public member functions

  1. void set_version(int version_major, int version_minor);
  2. void set_header(const std::string & name, const std::string & value);
    Add a header with name name and value value.
  3. std::string get_content_type() const;
  4. void set_content_type(const std::string & type);
    Set the Content-Type header.
  5. void set_content(xml::document & doc);
    Set the content and the content-type header.
  6. void set_content(xml::element * data);
    Set the content and the content-type header.
  7. void set_content(const std::string & data, const std::string & contentType);
    Set the content and the content-type header.
  8. void set_content(std::istream * data, const std::string & contentType);

    To send a stream of data, with unknown size (using chunked transfer). reply takes ownership of data and deletes it when done.

  9. void to_buffers(std::vector< boost::asio::const_buffer > & buffers);
  10. bool data_to_buffers(std::vector< boost::asio::const_buffer > & buffers);
    for istream data, continues until data_to_buffers returns false
  11. std::string get_as_text();
    For debugging purposes.
  12. std::size_t get_size() const;
  13. status_type get_status() const;

reply public static functions

  1. static reply stock_reply(status_type inStatus);
    Create a standard reply based on a HTTP status code.
  2. static reply redirect(const std::string & location);
    Create a standard redirect reply with the specified location.

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/preforked_server_base.html0000664000175000017500000003152112162310454023672 0ustar maartenmaarten Class preforked_server_base

PrevUpHomeNext

Class preforked_server_base

zeep::http::preforked_server_base

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/preforked-server.hpp>


class preforked_server_base {
public:
  // member classes/structs/unions
  template<typename Server> 
  struct server_constructor<void(Server::*)()> {

    // public member functions
    server * construct();
  };
  template<typename Server, typename T0> 
  struct server_constructor<void(Server::*)(T0)> {

    // public member functions
     server_constructor(T0);
    server * construct();
  };
  template<typename Server, typename T0, typename T1> 
  struct server_constructor<void(Server::*)(T0, T1)> {

    // public member functions
     server_constructor(T0, T1);
    server * construct();
  };
  template<typename Server, typename T0, typename T1, typename T2> 
  struct server_constructor<void(Server::*)(T0, T1, T2)> {

    // public member functions
     server_constructor(T0, T1, T2);
    server * construct();
  };

  // public member functions
  void run(const std::string &, short, int);
  void start();
  void stop();
};

Description

preforked_server_base public member functions

  1. void run(const std::string & address, short port, int nr_of_threads);
    forks child and starts listening, should be a separate thread
  2. void start();
    signal the thread it can start listening:
  3. void stop();
    stop the running thread

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/parameter_value.html0000664000175000017500000001643712162310454022516 0ustar maartenmaarten Class parameter_value

PrevUpHomeNext

Class parameter_value

zeep::http::parameter_value

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/webapp.hpp>


class parameter_value {
public:
  // construct/copy/destruct
  parameter_value();
  parameter_value(const std::string &, bool);

  // public member functions
  template<typename T> T as() const;
  bool empty() const;
  bool defaulted() const;
};

Description

parameter_value public construct/copy/destruct

  1. parameter_value();
  2. parameter_value(const std::string & v, bool defaulted);

parameter_value public member functions

  1. template<typename T> T as() const;
  2. bool empty() const;
  3. bool defaulted() const;

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/connection.html0000664000175000017500000002162312162310454021472 0ustar maartenmaarten Class connection

PrevUpHomeNext

Class connection

zeep::http::connection

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/connection.hpp>


class connection {
public:
  // construct/copy/destruct
  connection(boost::asio::io_service &, request_handler &);

  // public member functions
  void start();
  void handle_read(const boost::system::error_code &, size_t);
  void handle_write(const boost::system::error_code &);
  boost::asio::ip::tcp::socket & get_socket();
};

Description

The HTTP server implementation of libzeep is inspired by the example code as provided by boost::asio. These objects are not to be used directly.

connection public construct/copy/destruct

  1. connection(boost::asio::io_service & service, request_handler & handler);

connection public member functions

  1. void start();
  2. void handle_read(const boost::system::error_code & ec, 
                     size_t bytes_transferred);
  3. void handle_write(const boost::system::error_code & ec);
  4. boost::asio::ip::tcp::socket & get_socket();

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/webapp.html0000664000175000017500000011753412162310454020620 0ustar maartenmaarten Class webapp

PrevUpHomeNext

Class webapp

zeep::http::webapp

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/webapp.hpp>


class webapp : public zeep::http::server {
public:
  // construct/copy/destruct
  webapp(const std::string & = "http://www.cmbi.ru.nl/libzeep/ml", 
         const boost::filesystem::path & = ".");
  ~webapp();

  // public member functions
  void set_docroot(const boost::filesystem::path &);
  boost::filesystem::path get_docroot() const;

  // protected member functions
  void handle_request(const request &, reply &);
  void create_unauth_reply(bool, const std::string &, reply &);
  void mount(const std::string &, handler_type);
  void handle_file(const request &, const el::scope &, reply &);
  void load_template(const std::string &, xml::document &);
  void load_template(const boost::filesystem::path &, xml::document &);
  void create_reply_from_template(const std::string &, const el::scope &, 
                                  reply &);
  void process_xml(xml::node *, const el::scope &, boost::filesystem::path);
  void add_processor(const std::string &, processor_type);
  void process_include(xml::element *, const el::scope &, 
                       boost::filesystem::path);
  void process_if(xml::element *, const el::scope &, boost::filesystem::path);
  void process_iterate(xml::element *, const el::scope &, 
                       boost::filesystem::path);
  void process_for(xml::element *, const el::scope &, boost::filesystem::path);
  void process_number(xml::element *, const el::scope &, 
                      boost::filesystem::path);
  void process_options(xml::element *, const el::scope &, 
                       boost::filesystem::path);
  void process_option(xml::element *, const el::scope &, 
                      boost::filesystem::path);
  void process_checkbox(xml::element *, const el::scope &, 
                        boost::filesystem::path);
  void process_url(xml::element *, const el::scope &, boost::filesystem::path);
  void process_param(xml::element *, const el::scope &, 
                     boost::filesystem::path);
  void process_embed(xml::element *, const el::scope &, 
                     boost::filesystem::path);
  void init_scope(el::scope &);
  void get_cookies(const el::scope &, parameter_map &);
  void get_parameters(const el::scope &, parameter_map &);
};

Description

webapp is a specialization of zeep::http::server, it is used to create interactive web applications.

webapp public construct/copy/destruct

  1. webapp(const std::string & ns = "http://www.cmbi.ru.nl/libzeep/ml", 
           const boost::filesystem::path & docroot = ".");

    first parameter to constructor is the namespace to use in template XHTML files.

  2. ~webapp();

webapp public member functions

  1. void set_docroot(const boost::filesystem::path & docroot);
  2. boost::filesystem::path get_docroot() const;

webapp protected member functions

  1. void handle_request(const request & req, reply & rep);
  2. void create_unauth_reply(bool stale, const std::string & realm, reply & rep);
  3. void mount(const std::string & path, handler_type handler);

    assign a handler function to a path in the server's namespace Usually called like this:

    mount("page", boost::bind(&page_handler, this, _1, _2, _3));

    Where page_handler is defined as:

    void my_server::page_handler(const request& request, const el::scope& scope, reply& reply);

  4. void handle_file(const request & request, const el::scope & scope, 
                     reply & reply);
    Default handler for serving files out of our doc root.
  5. void load_template(const std::string & file, xml::document & doc);
    Use load_template to fetch the XHTML template file.
  6. void load_template(const boost::filesystem::path & file, xml::document & doc);
  7. void create_reply_from_template(const std::string & file, 
                                    const el::scope & scope, reply & reply);
    create a reply based on a template
  8. void process_xml(xml::node * node, const el::scope & scope, 
                     boost::filesystem::path dir);
    process xml parses the XHTML and fills in the special tags and evaluates the el constructs
  9. void add_processor(const std::string & name, processor_type processor);
    To add additional processors.
  10. void process_include(xml::element * node, const el::scope & scope, 
                         boost::filesystem::path dir);
    default handler for mrs:include tags
  11. void process_if(xml::element * node, const el::scope & scope, 
                    boost::filesystem::path dir);
    default handler for mrs:if tags
  12. void process_iterate(xml::element * node, const el::scope & scope, 
                         boost::filesystem::path dir);
    default handler for mrs:iterate tags
  13. void process_for(xml::element * node, const el::scope & scope, 
                     boost::filesystem::path dir);
    default handler for mrs:for tags
  14. void process_number(xml::element * node, const el::scope & scope, 
                        boost::filesystem::path dir);
    default handler for mrs:number tags
  15. void process_options(xml::element * node, const el::scope & scope, 
                         boost::filesystem::path dir);
    default handler for mrs:options tags
  16. void process_option(xml::element * node, const el::scope & scope, 
                        boost::filesystem::path dir);
    default handler for mrs:option tags
  17. void process_checkbox(xml::element * node, const el::scope & scope, 
                          boost::filesystem::path dir);
    default handler for mrs:checkbox tags
  18. void process_url(xml::element * node, const el::scope & scope, 
                     boost::filesystem::path dir);
    default handler for mrs:url tags
  19. void process_param(xml::element * node, const el::scope & scope, 
                       boost::filesystem::path dir);
    default handler for mrs:param tags
  20. void process_embed(xml::element * node, const el::scope & scope, 
                       boost::filesystem::path dir);
    default handler for mrs:embed tags
  21. void init_scope(el::scope & scope);
    Initialize the el::scope object.
  22. void get_cookies(const el::scope & scope, parameter_map & cookies);
    Return a parameter_map containing the cookies as found in the current request.
  23. void get_parameters(const el::scope & scope, parameter_map & parameters);
    Return the original parameters as found in the current request.

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/server.html0000664000175000017500000005034712162310454020646 0ustar maartenmaarten Class server

PrevUpHomeNext

Class server

zeep::http::server

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/server.hpp>


class server : public zeep::http::request_handler {
public:
  // construct/copy/destruct
  server();
  server(const server &);
  server& operator=(const server &);
  ~server();

  // public member functions
  void bind(const std::string &, unsigned short);
  void run(int);
  void stop();
  void log_forwarded(bool);
  std::string address() const;
  unsigned short port() const;
  boost::asio::io_service & get_io_service();

  // public static functions
  static std::ostream & log();

  // protected member functions
  void handle_request(const request &, reply &);
  void log_request(const std::string &, const request &, const reply &, 
                   const boost::posix_time::ptime &, const std::string &, 
                   const std::string &, const std::string &);

  // private member functions
  void handle_request(boost::asio::ip::tcp::socket &, const request &, 
                      reply &);
  void handle_accept(const boost::system::error_code &);
};

Description

server public construct/copy/destruct

  1. server();
  2. server(const server &);
  3. server& operator=(const server &);
  4. ~server();

server public member functions

  1. void bind(const std::string & address, unsigned short port);
    Bind the server to address and port.
  2. void run(int nr_of_threads);
  3. void stop();
  4. void log_forwarded(bool v);
    log_forwarded tells the HTTP server to use the last entry in X-Forwarded-For as client log entry
  5. std::string address() const;
  6. unsigned short port() const;
  7. boost::asio::io_service & get_io_service();
    get_io_service has to be public since we need it to call notify_fork from child code

server public static functions

  1. static std::ostream & log();
    to extend the log entry for a current request, use this ostream:

server protected member functions

  1. void handle_request(const request & req, reply & rep);
  2. void log_request(const std::string & client, const request & req, 
                     const reply & rep, const boost::posix_time::ptime & start, 
                     const std::string & referer, const std::string & userAgent, 
                     const std::string & entry);
    the default entry logger

server private member functions

  1. void handle_request(boost::asio::ip::tcp::socket & socket, 
                        const request & req, reply & rep);
  2. void handle_accept(const boost::system::error_code & ec);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/header.html0000664000175000017500000000726212162310454020566 0ustar maartenmaarten Struct header

PrevUpHomeNext

Struct header

zeep::http::header

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/header.hpp>


struct header {

  // public data members
  std::string name;
  std::string value;
};

Description

The header object contains the header lines as found in a HTTP Request. The lines are parsed into name / value pairs.


PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/request_handler.html0000664000175000017500000001274312162310454022523 0ustar maartenmaarten Class request_handler

PrevUpHomeNext

Class request_handler

zeep::http::request_handler — Simply an interface.

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/request_handler.hpp>


class request_handler {
public:

  // public member functions
  void handle_request(boost::asio::ip::tcp::socket &, const request &, 
                      reply &);
};

Description

request_handler public member functions

  1. void handle_request(boost::asio::ip::tcp::socket & socket, 
                        const request & req, reply & reply);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/encode_url.html0000664000175000017500000000770712162310454021461 0ustar maartenmaarten Function encode_url

PrevUpHomeNext

Function encode_url

zeep::http::encode_url

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/server.hpp>


std::string encode_url(const std::string & s);

Description

Encode a URL using the RFC rules

Parameters:

s

The URL that needs to be encoded

Returns:

The encoded URL


PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/request_parser.html0000664000175000017500000003067012162310454022401 0ustar maartenmaarten Class request_parser

PrevUpHomeNext

Class request_parser

zeep::http::request_parser — An HTTP request parser with support for Transfer-Encoding: Chunked.

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/request_parser.hpp>


class request_parser {
public:
  // construct/copy/destruct
  request_parser();

  // public member functions
  void reset();
  boost::tribool parse(request &, const char *, size_t);

  // private member functions
  boost::tribool parse_initial_line(request &, char);
  boost::tribool parse_header(request &, char);
  boost::tribool parse_empty_line(request &, char);
  boost::tribool parse_chunk(request &, char);
  boost::tribool parse_footer(request &, char);
  boost::tribool parse_content(request &, char);
};

Description

request_parser public construct/copy/destruct

  1. request_parser();

request_parser public member functions

  1. void reset();
  2. boost::tribool parse(request & req, const char * text, size_t length);

request_parser private member functions

  1. boost::tribool parse_initial_line(request & req, char ch);
  2. boost::tribool parse_header(request & req, char ch);
  3. boost::tribool parse_empty_line(request & req, char ch);
  4. boost::tribool parse_chunk(request & req, char ch);
  5. boost::tribool parse_footer(request & req, char ch);
  6. boost::tribool parse_content(request & req, char ch);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/http/parameter_map.html0000664000175000017500000002570712162310454022157 0ustar maartenmaarten Class parameter_map

PrevUpHomeNext

Class parameter_map

zeep::http::parameter_map

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/http/webapp.hpp>


class parameter_map {
public:

  // public member functions
  void add(const std::string &);
  void add(std::string, std::string);
  void replace(std::string, std::string);
  template<typename T> const parameter_value & get(const std::string &, T);
  template<> const parameter_value & get(const std::string &, const char *);
  template<> const parameter_value & get(const std::string &, bool);
};

Description

parameter_map is used to pass parameters from forms. The parameters can have 'any' type. Works a bit like the program_options code in boost.

parameter_map public member functions

  1. void add(const std::string & param);
    add a name/value pair as a string formatted as 'name=value'
  2. void add(std::string name, std::string value);
  3. void replace(std::string name, std::string value);
  4. template<typename T> 
      const parameter_value & get(const std::string & name, T defaultValue);
  5. template<> 
      const parameter_value & 
      get(const std::string & name, const char * defaultValue);
  6. template<> 
      const parameter_value & get(const std::string & name, bool defaultValue);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/make_fault_idp5637248.html0000664000175000017500000001010212162310454022071 0ustar maartenmaarten Function make_fault

PrevUpHomeNext

Function make_fault

zeep::make_fault

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/envelope.hpp>


xml::element * make_fault(const std::string & message);

Description

Create a standard SOAP Fault message for the string parameter

Parameters:

message

The string object containing a descriptive error message.

Returns:

A new xml::element object containing the fault envelope.


PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/make_fault_idm2384.html0000664000175000017500000001011612162310454021631 0ustar maartenmaarten Function make_fault

PrevUpHomeNext

Function make_fault

zeep::make_fault

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/envelope.hpp>


xml::element * make_fault(const std::string & message);

Description

Create a standard SOAP Fault message for the string parameter

Parameters:

message

The string object containing a descriptive error message.

Returns:

A new xml::element object containing the fault envelope.


PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/0000755000175000017500000000000012162310454016260 5ustar maartenmaartenlibzeep-3.0.2/doc/html/zeep/xml/doctype/0000755000175000017500000000000012162310454017727 5ustar maartenmaartenlibzeep-3.0.2/doc/html/zeep/xml/doctype/allowed_repeated.html0000664000175000017500000001723212162310454024124 0ustar maartenmaarten Struct allowed_repeated

PrevUpHomeNext

Struct allowed_repeated

zeep::xml::doctype::allowed_repeated

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/doctype.hpp>


struct allowed_repeated : public zeep::xml::doctype::allowed_base {
  // construct/copy/destruct
  allowed_repeated(allowed_ptr, char);
  ~allowed_repeated();

  // public member functions
  state_ptr create_state() const;
  bool element_content() const;
  void print(std::ostream &);

  // public data members
  allowed_ptr m_allowed;
  char m_repetition;
};

Description

allowed_repeated public construct/copy/destruct

  1. allowed_repeated(allowed_ptr allowed, char repetion);
  2. ~allowed_repeated();

allowed_repeated public member functions

  1. state_ptr create_state() const;
  2. bool element_content() const;
  3. void print(std::ostream & os);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/doctype/allowed_element.html0000664000175000017500000001635412162310454023770 0ustar maartenmaarten Struct allowed_element

PrevUpHomeNext

Struct allowed_element

zeep::xml::doctype::allowed_element

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/doctype.hpp>


struct allowed_element : public zeep::xml::doctype::allowed_base {
  // construct/copy/destruct
  allowed_element(const std::string &);

  // public member functions
  state_ptr create_state() const;
  bool element_content() const;
  void print(std::ostream &);

  // public data members
  std::string m_name;
};

Description

allowed_element public construct/copy/destruct

  1. allowed_element(const std::string & name);

allowed_element public member functions

  1. state_ptr create_state() const;
  2. bool element_content() const;
  3. void print(std::ostream & os);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/doctype/validator.html0000664000175000017500000002377312162310454022620 0ustar maartenmaarten Class validator

PrevUpHomeNext

Class validator

zeep::xml::doctype::validator

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/doctype.hpp>


class validator {
public:
  // construct/copy/destruct
  validator();
  validator(allowed_ptr);
  validator(const validator &);
  validator& operator=(const validator &);
  ~validator();

  // public member functions
  void reset();
  bool allow(const std::string &);
  bool allow_char_data();
  bool done();
  bool operator()(const std::string &);
};

Description

validator public construct/copy/destruct

  1. validator();
  2. validator(allowed_ptr allowed);
  3. validator(const validator & other);
  4. validator& operator=(const validator & other);
  5. ~validator();

validator public member functions

  1. void reset();
  2. bool allow(const std::string & name);
  3. bool allow_char_data();
  4. bool done();
  5. bool operator()(const std::string & name);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/doctype/attribute.html0000664000175000017500000004537712162310454022642 0ustar maartenmaarten Class attribute

PrevUpHomeNext

Class attribute

zeep::xml::doctype::attribute

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/doctype.hpp>


class attribute {
public:
  // construct/copy/destruct
  attribute(const std::string &, AttributeType);
  attribute(const std::string &, AttributeType, 
            const std::vector< std::string > &);

  // public member functions
  const std::string & name() const;
  bool validate_value(std::string &, const entity_list &) const;
  void set_default(AttributeDefault, const std::string &);
  boost::tuple< AttributeDefault, std::string > get_default() const;
  AttributeType get_type() const;
  AttributeDefault get_default_type() const;
  const std::vector< std::string > & get_enums() const;
  void external(bool);
  bool external() const;

  // private member functions
  bool is_name(std::string &) const;
  bool is_names(std::string &) const;
  bool is_nmtoken(std::string &) const;
  bool is_nmtokens(std::string &) const;
  bool is_unparsed_entity(const std::string &, const entity_list &) const;
};

Description

attribute public construct/copy/destruct

  1. attribute(const std::string & name, AttributeType type);
  2. attribute(const std::string & name, AttributeType type, 
              const std::vector< std::string > & enums);

attribute public member functions

  1. const std::string & name() const;
  2. bool validate_value(std::string & value, const entity_list & entities) const;
  3. void set_default(AttributeDefault def, const std::string & value);
  4. boost::tuple< AttributeDefault, std::string > get_default() const;
  5. AttributeType get_type() const;
  6. AttributeDefault get_default_type() const;
  7. const std::vector< std::string > & get_enums() const;
  8. void external(bool external);
  9. bool external() const;

attribute private member functions

  1. bool is_name(std::string & s) const;
  2. bool is_names(std::string & s) const;
  3. bool is_nmtoken(std::string & s) const;
  4. bool is_nmtokens(std::string & s) const;
  5. bool is_unparsed_entity(const std::string & s, const entity_list & l) const;

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/doctype/allowed_seq.html0000664000175000017500000001755212162310454023130 0ustar maartenmaarten Struct allowed_seq

PrevUpHomeNext

Struct allowed_seq

zeep::xml::doctype::allowed_seq

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/doctype.hpp>


struct allowed_seq : public zeep::xml::doctype::allowed_base {
  // construct/copy/destruct
  allowed_seq(allowed_ptr);
  ~allowed_seq();

  // public member functions
  void add(allowed_ptr);
  state_ptr create_state() const;
  bool element_content() const;
  void print(std::ostream &);

  // public data members
  allowed_list m_allowed;
};

Description

allowed_seq public construct/copy/destruct

  1. allowed_seq(allowed_ptr a);
  2. ~allowed_seq();

allowed_seq public member functions

  1. void add(allowed_ptr a);
  2. state_ptr create_state() const;
  3. bool element_content() const;
  4. void print(std::ostream & os);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/doctype/general_entity.html0000664000175000017500000001343312162310454023634 0ustar maartenmaarten Class general_entity

PrevUpHomeNext

Class general_entity

zeep::xml::doctype::general_entity

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/doctype.hpp>


class general_entity : public zeep::xml::doctype::entity {
public:
  // construct/copy/destruct
  general_entity(const std::string &, const std::string &, bool = false, 
                 bool = true);
};

Description

general_entity public construct/copy/destruct

  1. general_entity(const std::string & name, const std::string & replacement, 
                   bool external = false, bool parsed = true);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/doctype/allowed_empty.html0000664000175000017500000001232012162310454023462 0ustar maartenmaarten Struct allowed_empty

PrevUpHomeNext

Struct allowed_empty

zeep::xml::doctype::allowed_empty

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/doctype.hpp>


struct allowed_empty : public zeep::xml::doctype::allowed_base {

  // public member functions
  state_ptr create_state() const;
  void print(std::ostream &);
};

Description

allowed_empty public member functions

  1. state_ptr create_state() const;
  2. void print(std::ostream & os);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/doctype/entity.html0000664000175000017500000003432612162310454022143 0ustar maartenmaarten Class entity

PrevUpHomeNext

Class entity

zeep::xml::doctype::entity

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/doctype.hpp>


class entity {
public:
  // construct/copy/destruct
  entity(const std::string &, const std::string &, bool, bool);
  entity(const std::string &, const std::string &, const std::string &);

  // public member functions
  const std::string & name() const;
  const std::string & replacement() const;
  const std::string & path() const;
  bool parameter() const;
  bool parsed() const;
  void parsed(bool);
  const std::string & ndata() const;
  void ndata(const std::string &);
  bool external() const;
  bool externally_defined() const;
  void externally_defined(bool);
};

Description

entity public construct/copy/destruct

  1. entity(const std::string & name, const std::string & replacement, 
           bool external, bool parsed);
  2. entity(const std::string & name, const std::string & replacement, 
           const std::string & path);

entity public member functions

  1. const std::string & name() const;
  2. const std::string & replacement() const;
  3. const std::string & path() const;
  4. bool parameter() const;
  5. bool parsed() const;
  6. void parsed(bool parsed);
  7. const std::string & ndata() const;
  8. void ndata(const std::string & ndata);
  9. bool external() const;
  10. bool externally_defined() const;
  11. void externally_defined(bool externally_defined);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/doctype/allowed_any.html0000664000175000017500000001226612162310454023124 0ustar maartenmaarten Struct allowed_any

PrevUpHomeNext

Struct allowed_any

zeep::xml::doctype::allowed_any

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/doctype.hpp>


struct allowed_any : public zeep::xml::doctype::allowed_base {

  // public member functions
  state_ptr create_state() const;
  void print(std::ostream &);
};

Description

allowed_any public member functions

  1. state_ptr create_state() const;
  2. void print(std::ostream & os);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/doctype/allowed_base.html0000664000175000017500000001535312162310454023247 0ustar maartenmaarten Struct allowed_base

PrevUpHomeNext

Struct allowed_base

zeep::xml::doctype::allowed_base

Synopsis

Description

allowed_base public construct/copy/destruct

  1. allowed_base();
  2. ~allowed_base();

allowed_base public member functions

  1. state_ptr create_state() const;
  2. bool element_content() const;
  3. void print(std::ostream & os);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/doctype/element.html0000664000175000017500000003214512162310454022255 0ustar maartenmaarten Class element

PrevUpHomeNext

Class element

zeep::xml::doctype::element

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/doctype.hpp>


class element {
public:
  // construct/copy/destruct
  element(const std::string &, bool, bool);
  ~element();

  // public member functions
  void add_attribute(attribute *);
  const attribute * get_attribute(const std::string &) const;
  const std::string & name() const;
  const attribute_list & attributes() const;
  void set_allowed(allowed_ptr);
  void declared(bool);
  bool declared() const;
  void external(bool);
  bool external() const;
  bool empty() const;
  bool element_content() const;
  validator get_validator() const;
};

Description

element public construct/copy/destruct

  1. element(const std::string & name, bool declared, bool external);
  2. ~element();

element public member functions

  1. void add_attribute(attribute * attr);
  2. const attribute * get_attribute(const std::string & name) const;
  3. const std::string & name() const;
  4. const attribute_list & attributes() const;
  5. void set_allowed(allowed_ptr allowed);
  6. void declared(bool declared);
  7. bool declared() const;
  8. void external(bool external);
  9. bool external() const;
  10. bool empty() const;
  11. bool element_content() const;
  12. validator get_validator() const;

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/doctype/allowed_choice.html0000664000175000017500000002114612162310454023564 0ustar maartenmaarten Struct allowed_choice

PrevUpHomeNext

Struct allowed_choice

zeep::xml::doctype::allowed_choice

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/doctype.hpp>


struct allowed_choice : public zeep::xml::doctype::allowed_base {
  // construct/copy/destruct
  allowed_choice(bool);
  allowed_choice(allowed_ptr, bool);
  ~allowed_choice();

  // public member functions
  void add(allowed_ptr);
  state_ptr create_state() const;
  bool element_content() const;
  void print(std::ostream &);

  // public data members
  allowed_list m_allowed;
  bool m_mixed;
};

Description

allowed_choice public construct/copy/destruct

  1. allowed_choice(bool mixed);
  2. allowed_choice(allowed_ptr a, bool mixed);
  3. ~allowed_choice();

allowed_choice public member functions

  1. void add(allowed_ptr a);
  2. state_ptr create_state() const;
  3. bool element_content() const;
  4. void print(std::ostream & os);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/doctype/parameter_entity.html0000664000175000017500000001331512162310454024176 0ustar maartenmaarten Class parameter_entity

PrevUpHomeNext

Class parameter_entity

zeep::xml::doctype::parameter_entity

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/doctype.hpp>


class parameter_entity : public zeep::xml::doctype::entity {
public:
  // construct/copy/destruct
  parameter_entity(const std::string &, const std::string &, 
                   const std::string &);
};

Description

parameter_entity public construct/copy/destruct

  1. parameter_entity(const std::string & name, const std::string & replacement, 
                     const std::string & path);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/text.html0000664000175000017500000002614612162310454020145 0ustar maartenmaarten Class text

PrevUpHomeNext

Class text

zeep::xml::text — A node containing text.

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/node.hpp>


class text : public zeep::xml::node {
public:
  // construct/copy/destruct
  text();
  text(const std::string &);

  // public member functions
  std::string str() const;
  void str(const std::string &);
  void write_content(std::ostream &, const char * = kWhiteSpaceChar) const;
  void append(const std::string &);
  void write(writer &) const;
  bool equals(const node *) const;
  node * clone() const;
};

Description

text public construct/copy/destruct

  1. text();
  2. text(const std::string & text);

text public member functions

  1. std::string str() const;
    return all content concatenated, including that of children.
  2. void str(const std::string & text);
  3. void write_content(std::ostream & os, const char * sep = kWhiteSpaceChar) const;
    write out the concatenated content to a stream, separated by sep.
  4. void append(const std::string & text);
  5. void write(writer & w) const;
    writing out
  6. bool equals(const node * n) const;
    Compare the node with n.
  7. node * clone() const;
    Deep clone the node.

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/xpath.html0000664000175000017500000002562412162310454020305 0ustar maartenmaarten Class xpath

PrevUpHome

Class xpath

zeep::xml::xpath

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/xpath.hpp>


class xpath {
public:
  // construct/copy/destruct
  xpath(const std::string &);
  xpath(const char *);
  xpath(const xpath &);
  xpath& operator=(const xpath &);

  // public member functions
  template<typename NODE_TYPE> 
    std::list< NODE_TYPE * > evaluate(const node &) const;
  template<typename NODE_TYPE> 
    std::list< NODE_TYPE * > evaluate(const node &, context &) const;
  bool matches(const node *) const;
};

Description

The actual xpath implementation. It expects an xpath in the constructor and this path _must_ be UTF-8 encoded.

xpath public construct/copy/destruct

  1. xpath(const std::string & path);
  2. xpath(const char * path);
  3. xpath(const xpath & rhs);
  4. xpath& operator=(const xpath &);

xpath public member functions

  1. template<typename NODE_TYPE> 
      std::list< NODE_TYPE * > evaluate(const node & root) const;

    evaluate returns a node_set. If you're only interested in zeep::xml::element results, you should call the evaluate<element>() instantiation.

  2. template<typename NODE_TYPE> 
      std::list< NODE_TYPE * > evaluate(const node & root, context & ctxt) const;
    The second evaluate method is used for xpaths that contain variables.
  3. bool matches(const node * n) const;
    Returns true if the n node matches the XPath.

PrevUpHome
libzeep-3.0.2/doc/html/zeep/xml/element/0000755000175000017500000000000012162310454017711 5ustar maartenmaartenlibzeep-3.0.2/doc/html/zeep/xml/element/attribute_iterator.html0000664000175000017500000003257612162310454024532 0ustar maartenmaarten Class attribute_iterator

PrevUpHomeNext

Class attribute_iterator

zeep::xml::element::attribute_iterator — as a service to the user, we define an attribute iterator here

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/node.hpp>



// as a service to the user, we define an attribute iterator here

class attribute_iterator {
public:
  // construct/copy/destruct
  attribute_iterator();
  attribute_iterator(attribute *);
  attribute_iterator(const attribute_iterator &);
  attribute_iterator& operator=(const attribute_iterator &);

  // public member functions
  reference operator*() const;
  pointer operator->() const;
  attribute_iterator & operator++();
  attribute_iterator operator++(int);
  attribute_iterator & operator--();
  attribute_iterator operator--(int);
  bool operator==(const attribute_iterator &) const;
  bool operator!=(const attribute_iterator &) const;
  pointer base() const;
};

Description

attribute_iterator public construct/copy/destruct

  1. attribute_iterator();
  2. attribute_iterator(attribute * e);
  3. attribute_iterator(const attribute_iterator & other);
  4. attribute_iterator& operator=(const attribute_iterator & other);

attribute_iterator public member functions

  1. reference operator*() const;
  2. pointer operator->() const;
  3. attribute_iterator & operator++();
  4. attribute_iterator operator++(int);
  5. attribute_iterator & operator--();
  6. attribute_iterator operator--(int);
  7. bool operator==(const attribute_iterator & other) const;
  8. bool operator!=(const attribute_iterator & other) const;
  9. pointer base() const;

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/element/const_attribute_iterator.html0000664000175000017500000003476612162310454025743 0ustar maartenmaarten Class const_attribute_iterator

PrevUpHomeNext

Class const_attribute_iterator

zeep::xml::element::const_attribute_iterator

Synopsis

Description

const_attribute_iterator public construct/copy/destruct

  1. const_attribute_iterator();
  2. const_attribute_iterator(attribute * e);
  3. const_attribute_iterator(const attribute_iterator & other);
  4. const_attribute_iterator(const const_attribute_iterator & other);
  5. const_attribute_iterator& operator=(const const_attribute_iterator & other);

const_attribute_iterator public member functions

  1. reference operator*() const;
  2. pointer operator->() const;
  3. const_attribute_iterator & operator++();
  4. const_attribute_iterator operator++(int);
  5. const_attribute_iterator & operator--();
  6. const_attribute_iterator operator--(int);
  7. bool operator==(const const_attribute_iterator & other) const;
  8. bool operator!=(const const_attribute_iterator & other) const;
  9. pointer base() const;

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/cdata.html0000664000175000017500000001714312162310454020232 0ustar maartenmaarten Class cdata

PrevUpHomeNext

Class cdata

zeep::xml::cdata

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/node.hpp>


class cdata : public zeep::xml::text {
public:
  // construct/copy/destruct
  cdata();
  cdata(const std::string &);

  // public member functions
  void write(writer &) const;
  bool equals(const node *) const;
  node * clone() const;
};

Description

A node containing the contents of a CDATA section. Normally, these nodes are converted to text nodes but you can specify to preserve them when parsing a document.

cdata public construct/copy/destruct

  1. cdata();
  2. cdata(const std::string & s);

cdata public member functions

  1. void write(writer & w) const;
    writing out
  2. bool equals(const node * n) const;
    Compare the node with n.
  3. node * clone() const;
    Deep clone the node.

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/invalid_exception.html0000664000175000017500000001306612162310454022662 0ustar maartenmaarten Class invalid_exception

PrevUpHomeNext

Class invalid_exception

zeep::xml::invalid_exception

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/parser.hpp>


class invalid_exception : public zeep::exception {
public:
  // construct/copy/destruct
  invalid_exception(const std::string &);
  ~invalid_exception();
};

Description

If an invalid_exception is thrown, it means the XML document is not valid: it does not conform the DTD specified in the XML document. This is only thrown when validation is enabled.

The what() member of the exception object will contain an explanation.

invalid_exception public construct/copy/destruct

  1. invalid_exception(const std::string & msg);
  2. ~invalid_exception();

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/not_wf_exception.html0000664000175000017500000001271112162310454022524 0ustar maartenmaarten Class not_wf_exception

PrevUpHomeNext

Class not_wf_exception

zeep::xml::not_wf_exception

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/parser.hpp>


class not_wf_exception : public zeep::exception {
public:
  // construct/copy/destruct
  not_wf_exception(const std::string &);
  ~not_wf_exception();
};

Description

If an not_wf_exception is thrown, it means the XML document is not well formed. Often this means syntax errors, missing < or > characters, non matching open and close tags, etc.

The what() member of the exception object will contain an explanation.

not_wf_exception public construct/copy/destruct

  1. not_wf_exception(const std::string & msg);
  2. ~not_wf_exception();

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/root_node.html0000664000175000017500000002611112162310454021141 0ustar maartenmaarten Class root_node

PrevUpHomeNext

Class root_node

zeep::xml::root_node

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/node.hpp>


class root_node : public zeep::xml::container {
public:
  // construct/copy/destruct
  root_node();
  ~root_node();

  // public member functions
  root_node * root();
  const root_node * root() const;
  element * child_element() const;
  void child_element(element *);
  std::string str() const;
  void append(node *);
  void write(writer &) const;
  bool equals(const node *) const;
};

Description

All zeep::xml::document objects have exactly one zeep::xml::root_node member. root_node is a container with only one child element.

root_node public construct/copy/destruct

  1. root_node();
  2. ~root_node();

root_node public member functions

  1. root_node * root();
    The root node for this node.
  2. const root_node * root() const;
    The root node for this node.
  3. element * child_element() const;
  4. void child_element(element * e);
  5. std::string str() const;
    return all content concatenated, including that of children.
  6. void append(node * n);
  7. void write(writer & w) const;
    writing out
  8. bool equals(const node * n) const;
    Compare the node with n.

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/attribute.html0000664000175000017500000002724612162310454021166 0ustar maartenmaarten Class attribute

PrevUpHomeNext

Class attribute

zeep::xml::attribute — An attribute is a node, has an element as parent, but is not a child of this parent (!)

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/node.hpp>


class attribute : public zeep::xml::node {
public:
  // construct/copy/destruct
  attribute(const std::string &, const std::string &, bool = false);

  // public member functions
  std::string qname() const;
  std::string value() const;
  void value(const std::string &);
  std::string str() const;
  void write(writer &) const;
  bool equals(const node *) const;
  node * clone() const;
  bool id() const;
};

Description

attribute public construct/copy/destruct

  1. attribute(const std::string & qname, const std::string & value, 
              bool id = false);

attribute public member functions

  1. std::string qname() const;

    Nodes can have a name, and the XPath specification requires that a node can have a so-called expanded-name. This name consists of a local-name and a namespace which is a URI. And we can have a QName which is a concatenation of a prefix (that points to a namespace URI) and a local-name separated by a colon.

    To reduce storage requirements, names are stored in nodes as qnames, if at all.

  2. std::string value() const;
  3. void value(const std::string & v);
  4. std::string str() const;
    return all content concatenated, including that of children.
  5. void write(writer & w) const;
    writing out
  6. bool equals(const node * n) const;
    Compare the node with n.
  7. node * clone() const;
    Deep clone the node.
  8. bool id() const;

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/container/0000755000175000017500000000000012162310454020242 5ustar maartenmaartenlibzeep-3.0.2/doc/html/zeep/xml/container/basic_iterator.html0000664000175000017500000006704112162310454024134 0ustar maartenmaarten Class template basic_iterator

PrevUpHomeNext

Class template basic_iterator

zeep::xml::container::basic_iterator

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/node.hpp>


template<typename NodeType> 
class basic_iterator {
public:
  // types
  typedef std::iterator< std::bidirectional_iterator_tag, NodeType * > base_type;
  typedef base_type::reference                                         reference;
  typedef base_type::pointer                                           pointer;  

  // construct/copy/destruct
  basic_iterator();
  basic_iterator(NodeType *);
  basic_iterator(const basic_iterator &);
  basic_iterator& operator=(const basic_iterator &);
  basic_iterator& operator=(const NodeType *);

  // public member functions
  reference operator*();
  pointer operator->() const;
  basic_iterator & operator++();
  basic_iterator operator++(int);
  basic_iterator & operator--();
  basic_iterator operator--(int);
  bool operator==(const basic_iterator &) const;
  bool operator!=(const basic_iterator &) const;
  template<typename RNodeType> bool operator==(const RNodeType) const;
  template<typename RNodeType> bool operator!=(const RNodeType) const;
  operator const pointer() const;
  operator pointer();
  template<> container::basic_iterator< element > & operator++();
  template<> container::basic_iterator< element > & operator--();
  template<> container::basic_iterator< const element > & operator++();
  template<> container::basic_iterator< const element > & operator--();
  template<> container::basic_iterator< node > & operator++();
  template<> container::basic_iterator< node > & operator--();
  template<> container::basic_iterator< const node > & operator++();
  template<> container::basic_iterator< const node > & operator--();
};

Description

basic_iterator public construct/copy/destruct

  1. basic_iterator();
  2. basic_iterator(NodeType * e);
  3. basic_iterator(const basic_iterator & other);
  4. basic_iterator& operator=(const basic_iterator & other);
  5. basic_iterator& operator=(const NodeType * n);

basic_iterator public member functions

  1. reference operator*();
  2. pointer operator->() const;
  3. basic_iterator & operator++();
  4. basic_iterator operator++(int);
  5. basic_iterator & operator--();
  6. basic_iterator operator--(int);
  7. bool operator==(const basic_iterator & other) const;
  8. bool operator!=(const basic_iterator & other) const;
  9. template<typename RNodeType> bool operator==(const RNodeType n) const;
  10. template<typename RNodeType> bool operator!=(const RNodeType n) const;
  11. operator const pointer() const;
  12. operator pointer();
  13. template<> container::basic_iterator< element > & operator++();
  14. template<> container::basic_iterator< element > & operator--();
  15. template<> container::basic_iterator< const element > & operator++();
  16. template<> container::basic_iterator< const element > & operator--();
  17. template<> container::basic_iterator< node > & operator++();
  18. template<> container::basic_iterator< node > & operator--();
  19. template<> container::basic_iterator< const node > & operator++();
  20. template<> container::basic_iterator< const node > & operator--();

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/comment.html0000664000175000017500000002342112162310454020614 0ustar maartenmaarten Class comment

PrevUpHomeNext

Class comment

zeep::xml::comment — A node containing a XML comment.

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/node.hpp>


class comment : public zeep::xml::node {
public:
  // construct/copy/destruct
  comment();
  comment(const std::string &);

  // public member functions
  std::string str() const;
  std::string text() const;
  void text(const std::string &);
  void write(writer &) const;
  bool equals(const node *) const;
  node * clone() const;
};

Description

comment public construct/copy/destruct

  1. comment();
  2. comment(const std::string & text);

comment public member functions

  1. std::string str() const;
    return all content concatenated, including that of children.
  2. std::string text() const;
  3. void text(const std::string & text);
  4. void write(writer & w) const;
    writing out
  5. bool equals(const node * n) const;
    Compare the node with n.
  6. node * clone() const;
    Deep clone the node.

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/name_space.html0000664000175000017500000003227612162310454021255 0ustar maartenmaarten Class name_space

PrevUpHomeNext

Class name_space

zeep::xml::name_space — Just like an attribute, a name_space node is not a child of an element.

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/node.hpp>


class name_space : public zeep::xml::node {
public:
  // construct/copy/destruct
  name_space(const std::string &, const std::string &);

  // public member functions
  std::string qname() const;
  std::string ns() const;
  std::string prefix() const;
  void prefix(const std::string &);
  std::string uri() const;
  void uri(const std::string &);
  std::string str() const;
  void write(writer &) const;
  bool equals(const node *) const;
  node * clone() const;
};

Description

name_space public construct/copy/destruct

  1. name_space(const std::string & prefix, const std::string & uri);

name_space public member functions

  1. std::string qname() const;

    Nodes can have a name, and the XPath specification requires that a node can have a so-called expanded-name. This name consists of a local-name and a namespace which is a URI. And we can have a QName which is a concatenation of a prefix (that points to a namespace URI) and a local-name separated by a colon.

    To reduce storage requirements, names are stored in nodes as qnames, if at all.

  2. std::string ns() const;
    Returns the namespace URI for the node, if it can be resolved.
  3. std::string prefix() const;
    The prefix for the node as parsed from the qname.
  4. void prefix(const std::string & p);
  5. std::string uri() const;
  6. void uri(const std::string & u);
  7. std::string str() const;
    return all content concatenated, including that of children.
  8. void write(writer & w) const;
    writing out
  9. bool equals(const node * n) const;
    Compare the node with n.
  10. node * clone() const;
    Deep clone the node.

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/parser.html0000664000175000017500000003574712162310454020464 0ustar maartenmaarten Class parser

PrevUpHomeNext

Class parser

zeep::xml::parser

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/parser.hpp>


class parser {
public:
  // construct/copy/destruct
  parser(std::istream &);
  parser(const std::string &);
  ~parser();

  // public member functions
  void parse(bool);

  // public data members
  boost::function< void(const std::string &name, const std::string &uri, const attr_list_type &atts)> start_element_handler;
  boost::function< void(const std::string &name, const std::string &uri)> end_element_handler;
  boost::function< void(const std::string &data)> character_data_handler;
  boost::function< void(const std::string &target, const std::string &data)> processing_instruction_handler;
  boost::function< void(const std::string &data)> comment_handler;
  boost::function< void()> start_cdata_section_handler;
  boost::function< void()> end_cdata_section_handler;
  boost::function< void(const std::string &prefix, const std::string &uri)> start_namespace_decl_handler;
  boost::function< void(const std::string &prefix)> end_namespace_decl_handler;
  boost::function< void(const std::string &name, const std::string &systemId, const std::string &publicId)> notation_decl_handler;
  boost::function< std::istream *(const std::string &base, const std::string &pubid, const std::string &uri)> external_entity_ref_handler;
  boost::function< void(const std::string &msg)> report_invalidation_handler;
};

Description

zeep::xml::parser is a SAX parser. After construction, you should assign call back handlers for the SAX events and then call parse().

parser public construct/copy/destruct

  1. parser(std::istream & is);
  2. parser(const std::string & s);
  3. ~parser();

parser public member functions

  1. void parse(bool validate);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/container.html0000664000175000017500000014521212162310454021137 0ustar maartenmaarten Class container

PrevUpHomeNext

Class container

zeep::xml::container

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/node.hpp>


class container : public zeep::xml::node {
public:
  // types
  typedef basic_iterator< element >       iterator;           
  typedef basic_iterator< node >          node_iterator;      
  typedef basic_iterator< const element > const_iterator;     
  typedef basic_iterator< const node >    const_node_iterator;
  typedef iterator::value_type            value_type;         
  typedef iterator::reference             reference;          
  typedef iterator::pointer               pointer;            
  typedef iterator::difference_type       difference_type;    
  typedef unsigned long                   size_type;          

  // member classes/structs/unions
  template<typename NodeType> 
  class basic_iterator {
  public:
    // types
    typedef std::iterator< std::bidirectional_iterator_tag, NodeType * > base_type;
    typedef base_type::reference                                         reference;
    typedef base_type::pointer                                           pointer;  

    // construct/copy/destruct
    basic_iterator();
    basic_iterator(NodeType *);
    basic_iterator(const basic_iterator &);
    basic_iterator& operator=(const basic_iterator &);
    basic_iterator& operator=(const NodeType *);

    // public member functions
    reference operator*();
    pointer operator->() const;
    basic_iterator & operator++();
    basic_iterator operator++(int);
    basic_iterator & operator--();
    basic_iterator operator--(int);
    bool operator==(const basic_iterator &) const;
    bool operator!=(const basic_iterator &) const;
    template<typename RNodeType> bool operator==(const RNodeType) const;
    template<typename RNodeType> bool operator!=(const RNodeType) const;
    operator const pointer() const;
    operator pointer();
    template<> container::basic_iterator< element > & operator++();
    template<> container::basic_iterator< element > & operator--();
    template<> container::basic_iterator< const element > & operator++();
    template<> container::basic_iterator< const element > & operator--();
    template<> container::basic_iterator< node > & operator++();
    template<> container::basic_iterator< node > & operator--();
    template<> container::basic_iterator< const node > & operator++();
    template<> container::basic_iterator< const node > & operator--();
  };

  // construct/copy/destruct
  container();
  ~container();

  // public member functions
  node * child();
  const node * child() const;
  template<typename NodeType> std::list< NodeType * > children() const;
  iterator begin();
  iterator end();
  node_iterator node_begin();
  node_iterator node_end();
  boost::iterator_range< node_iterator > nodes();
  const_iterator begin() const;
  const_iterator end() const;
  const_node_iterator node_begin() const;
  const_node_iterator node_end() const;
  boost::iterator_range< const_node_iterator > nodes() const;
  size_type size() const;
  size_type max_size() const;
  bool empty() const;
  node * front() const;
  node * back() const;
  template<typename NodeType> 
    basic_iterator< NodeType > insert(basic_iterator< NodeType >, NodeType *);
  node_iterator insert(node *, node *);
  template<typename Iterator> void insert(Iterator, Iterator, Iterator);
  template<typename Iterator> void erase(Iterator);
  template<typename Iterator> void erase(Iterator, Iterator);
  void swap(container &);
  void clear();
  void push_front(node *);
  void pop_front();
  void push_back(node *);
  void pop_back();
  void append(node *);
  void remove(node *);
  element_set find(const std::string &) const;
  element * find_first(const std::string &) const;
  element_set find(const char *) const;
  element * find_first(const char *) const;
  void find(const char *, node_set &) const;
  void find(const char *, element_set &) const;
  node * find_first_node(const char *) const;
  void validate();
};

Description

Container is an abstract base class for nodes that can have multiple children. It provides iterators to iterate over children. Most often, you're only interested in iteration zeep::xml::element children, that's why zeep::xml::container::iterator iterates over only zeep::xml::element nodes, skipping all other nodes. If you want to iterate all nodes, use zeep::xml::container::node_iterator instead.

An attempt has been made to make container conform to the STL container interface.

container public construct/copy/destruct

  1. container();
  2. ~container();
    container tries hard to be stl::container-like.

container public member functions

  1. node * child();
  2. const node * child() const;
  3. template<typename NodeType> std::list< NodeType * > children() const;

    very often, we want to iterate over child elements of an element therefore we have a templated version of children.

  4. iterator begin();
  5. iterator end();
  6. node_iterator node_begin();
  7. node_iterator node_end();
  8. boost::iterator_range< node_iterator > nodes();
  9. const_iterator begin() const;
  10. const_iterator end() const;
  11. const_node_iterator node_begin() const;
  12. const_node_iterator node_end() const;
  13. boost::iterator_range< const_node_iterator > nodes() const;
  14. size_type size() const;
  15. size_type max_size() const;
  16. bool empty() const;
  17. node * front() const;
  18. node * back() const;
  19. template<typename NodeType> 
      basic_iterator< NodeType > 
      insert(basic_iterator< NodeType > position, NodeType * n);
  20. node_iterator insert(node * before, node * n);
  21. template<typename Iterator> 
      void insert(Iterator position, Iterator first, Iterator last);
  22. template<typename Iterator> void erase(Iterator position);
  23. template<typename Iterator> void erase(Iterator first, Iterator last);
  24. void swap(container & cnt);
  25. void clear();
  26. void push_front(node * n);
  27. void pop_front();
  28. void push_back(node * n);
  29. void pop_back();
  30. void append(node * n);
  31. void remove(node * n);
  32. element_set find(const std::string & path) const;
  33. element * find_first(const std::string & path) const;
  34. element_set find(const char * path) const;
  35. element * find_first(const char * path) const;
  36. void find(const char * path, node_set & nodes) const;
  37. void find(const char * path, element_set & elements) const;
  38. node * find_first_node(const char * path) const;
  39. void validate();
    debug routine

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/processing_instruction.html0000664000175000017500000003211412162310454023766 0ustar maartenmaarten Class processing_instruction

PrevUpHomeNext

Class processing_instruction

zeep::xml::processing_instruction — A node containing a XML processing instruction (like e.g. <?php ?>)

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/node.hpp>


class processing_instruction : public zeep::xml::node {
public:
  // construct/copy/destruct
  processing_instruction();
  processing_instruction(const std::string &, const std::string &);

  // public member functions
  std::string qname() const;
  std::string str() const;
  std::string target() const;
  void target(const std::string &);
  std::string text() const;
  void text(const std::string &);
  void write(writer &) const;
  bool equals(const node *) const;
  node * clone() const;
};

Description

processing_instruction public construct/copy/destruct

  1. processing_instruction();
  2. processing_instruction(const std::string & target, const std::string & text);

processing_instruction public member functions

  1. std::string qname() const;

    Nodes can have a name, and the XPath specification requires that a node can have a so-called expanded-name. This name consists of a local-name and a namespace which is a URI. And we can have a QName which is a concatenation of a prefix (that points to a namespace URI) and a local-name separated by a colon.

    To reduce storage requirements, names are stored in nodes as qnames, if at all.

  2. std::string str() const;
    return all content concatenated, including that of children.
  3. std::string target() const;
  4. void target(const std::string & target);
  5. std::string text() const;
  6. void text(const std::string & text);
  7. void write(writer & w) const;
    writing out
  8. bool equals(const node * n) const;
    Compare the node with n.
  9. node * clone() const;
    Deep clone the node.

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/deserializer.html0000664000175000017500000001745012162310454021641 0ustar maartenmaarten Struct deserializer

PrevUpHomeNext

Struct deserializer

zeep::xml::deserializer

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/serialize.hpp>


struct deserializer {
  // construct/copy/destruct
  deserializer(container *);

  // public member functions
  template<typename T> 
    deserializer & operator&(const boost::serialization::nvp< T > &);
  template<typename T> deserializer & deserialize(const char *, T &);

  // public data members
  container * m_node;
};

Description

deserializer public construct/copy/destruct

  1. deserializer(container * node);

deserializer public member functions

  1. template<typename T> 
      deserializer & operator&(const boost::serialization::nvp< T > & rhs);
  2. template<typename T> deserializer & deserialize(const char * name, T & data);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/context.html0000664000175000017500000001421612162310454020640 0ustar maartenmaarten Class context

PrevUpHomeNext

Class context

zeep::xml::context

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/xpath.hpp>


class context {
public:

  // public member functions
  template<typename T> void set(const std::string &, const T &);
  template<typename T> T get(const std::string &);
};

Description

XPath's can contain variables. And variables can contain all kinds of data like strings, numbers and even node_sets. If you want to use variables, you can define a context, add your variables to it and then pass it on in the xpath::evaluate method.

context public member functions

  1. template<typename T> void set(const std::string & name, const T & value);
  2. template<typename T> T get(const std::string & name);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/writer.html0000664000175000017500000006355312162310454020500 0ustar maartenmaarten Class writer

PrevUpHomeNext

Class writer

zeep::xml::writer — Use xml::writer to write XML documents to a stream.

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/writer.hpp>


class writer {
public:
  // construct/copy/destruct
  writer(std::ostream &);
  writer(std::ostream &, bool, bool = false);
  ~writer();

  // public member functions
  void set_xml_decl(bool);
  void set_indent(int);
  void set_wrap(bool);
  void set_wrap_prolog(bool);
  void set_trim(bool);
  void set_collapse_empty_elements(bool);
  void set_escape_whitespace(bool);
  void set_no_comment(bool);
  void xml_decl(bool);
  void empty_doctype(const std::string &, const std::string &);
  void doctype(const std::string &, const std::string &, const std::string &);
  void start_doctype(const std::string &, const std::string &);
  void notation(const std::string &, const std::string &, const std::string &);
  void end_doctype();
  void start_element(const std::string &);
  void end_element();
  void attribute(const std::string &, const std::string &);
  void content(const std::string &);
  void element(const std::string &, const std::string &);
  void cdata(const std::string &);
  void comment(const std::string &);
  void processing_instruction(const std::string &, const std::string &);
};

Description

The zeep::xml::writer class is used to write XML documents. It has several options that influence the way the data is written. E.g. it is possible to specify whether to wrap the elements and what indentation to use. The writer keeps track of opened elements and therefore knows how to close an element.

The writer writes out XML 1.0 files.

writer public construct/copy/destruct

  1. writer(std::ostream & os);
    The constructor takes a std::ostream as argument.
  2. writer(std::ostream & os, bool write_decl, bool standalone = false);
  3. ~writer();

writer public member functions

  1. void set_xml_decl(bool flag);
    set_encoding is not yet implemented, we only support UTF-8 for now

    the xml declaration flag (<?xml version...) is not written by default

  2. void set_indent(int indentation);
    the indentation in number of spaces, default is two.
  3. void set_wrap(bool flag);
    default is to wrap XML files
  4. void set_wrap_prolog(bool flag);
    default is to wrap XML files
  5. void set_trim(bool flag);
    if the trim flag is set, all whitespace will be trimmed to one space exactly
  6. void set_collapse_empty_elements(bool collapse);
    collapsing empty elements (<empyt>) is the default behaviour
  7. void set_escape_whitespace(bool escape);
    escape whitespace into character refences can be specified.
  8. void set_no_comment(bool no_comment);
    do not write out comments
  9. void xml_decl(bool standalone);
    write a xml declaration, version will be 1.0, standalone can be specified.
  10. void empty_doctype(const std::string & root, const std::string & dtd);
    To write an empty DOCTYPE specifying an external subset.
  11. void doctype(const std::string & root, const std::string & pubid, 
                 const std::string & dtd);
    This opens a DOCTYPE declaration. The root parameter is the name of the base element.
  12. void start_doctype(const std::string & root, const std::string & dtd);
  13. void notation(const std::string & name, const std::string & sysid, 
                  const std::string & pubid);
    To write a NOTATION declaration.
  14. void end_doctype();
    End a DOCTYPE declaration.
  15. void start_element(const std::string & name);
  16. void end_element();
  17. void attribute(const std::string & name, const std::string & value);
  18. void content(const std::string & content);
  19. void element(const std::string & name, const std::string & s);
  20. void cdata(const std::string & text);
  21. void comment(const std::string & text);
  22. void processing_instruction(const std::string & target, 
                                const std::string & text);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/unicode.html0000664000175000017500000000655312162310454020607 0ustar maartenmaarten Type definition unicode

PrevUpHomeNext

Type definition unicode

unicode

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/unicode_support.hpp>


typedef boost::uint32_t unicode;

Description

We use our own unicode type since wchar_t might be too small. This type should be able to contain a UCS4 encoded character.


PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/serializer.html0000664000175000017500000002103712162310454021324 0ustar maartenmaarten Struct serializer

PrevUpHomeNext

Struct serializer

zeep::xml::serializer

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/serialize.hpp>


struct serializer {
  // construct/copy/destruct
  serializer(container *, bool = true);

  // public member functions
  template<typename T> 
    serializer & operator&(const boost::serialization::nvp< T > &);
  template<typename T> serializer & serialize(const char *, const T &);

  // public data members
  container * m_node;
  bool m_make_node;
};

Description

All serializers and deserializers work on an object that contains a pointer to the node just above the actual node holding their data. If any.

This means for the serializer that it has to create a new node, set the content and add it to the passed in node. For deserializers this means looking up the first child matching the name in the passed-in node to fetch the data from.

serializer public construct/copy/destruct

  1. serializer(container * node, bool make_node = true);

serializer public member functions

  1. template<typename T> 
      serializer & operator&(const boost::serialization::nvp< T > & rhs);
  2. template<typename T> serializer & serialize(const char * name, const T & data);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/wsdl_creator.html0000664000175000017500000001672712162310454021655 0ustar maartenmaarten Struct wsdl_creator

PrevUpHomeNext

Struct wsdl_creator

zeep::xml::wsdl_creator — wsdl_creator is used by zeep::dispatcher to create WSDL files.

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/serialize.hpp>


struct wsdl_creator {
  // construct/copy/destruct
  wsdl_creator(type_map &, element *, bool = true);

  // public member functions
  template<typename T> 
    wsdl_creator & operator&(const boost::serialization::nvp< T > &);

  // public data members
  element * m_node;
  type_map & m_types;
  bool m_make_node;
};

Description

wsdl_creator public construct/copy/destruct

  1. wsdl_creator(type_map & types, element * node, bool make_node = true);

wsdl_creator public member functions

  1. template<typename T> 
      wsdl_creator & operator&(const boost::serialization::nvp< T > & rhs);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/element.html0000664000175000017500000011400012162310454020575 0ustar maartenmaarten Class element

PrevUpHomeNext

Class element

zeep::xml::element

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/node.hpp>


class element : public zeep::xml::container {
public:
  // member classes/structs/unions

  // as a service to the user, we define an attribute iterator here

  class attribute_iterator {
  public:
    // construct/copy/destruct
    attribute_iterator();
    attribute_iterator(attribute *);
    attribute_iterator(const attribute_iterator &);
    attribute_iterator& operator=(const attribute_iterator &);

    // public member functions
    reference operator*() const;
    pointer operator->() const;
    attribute_iterator & operator++();
    attribute_iterator operator++(int);
    attribute_iterator & operator--();
    attribute_iterator operator--(int);
    bool operator==(const attribute_iterator &) const;
    bool operator!=(const attribute_iterator &) const;
    pointer base() const;
  };

  class const_attribute_iterator {
  public:
    // construct/copy/destruct
    const_attribute_iterator();
    const_attribute_iterator(attribute *);
    const_attribute_iterator(const attribute_iterator &);
    const_attribute_iterator(const const_attribute_iterator &);
    const_attribute_iterator& operator=(const const_attribute_iterator &);

    // public member functions
    reference operator*() const;
    pointer operator->() const;
    const_attribute_iterator & operator++();
    const_attribute_iterator operator++(int);
    const_attribute_iterator & operator--();
    const_attribute_iterator operator--(int);
    bool operator==(const const_attribute_iterator &) const;
    bool operator!=(const const_attribute_iterator &) const;
    pointer base() const;
  };
  // construct/copy/destruct
  element(const std::string &);
  ~element();

  // public member functions
  void write(writer &) const;
  bool equals(const node *) const;
  node * clone() const;
  std::string str() const;
  void write_content(std::ostream &, const char * = kWhiteSpaceChar) const;
  std::string qname() const;
  std::string namespace_for_prefix(const std::string &) const;
  std::string prefix_for_namespace(const std::string &) const;
  std::string content() const;
  void content(const std::string &);
  std::string get_attribute(const std::string &) const;
  attribute * get_attribute_node(const std::string &) const;
  void set_attribute(const std::string &, const std::string &, bool = false);
  void remove_attribute(const std::string &);
  void set_name_space(const std::string &, const std::string &);
  void add_text(const std::string &);
  attribute_set attributes() const;
  name_space_list name_spaces() const;
  std::string lang() const;
  std::string id() const;
  attribute_iterator attr_begin();
  attribute_iterator attr_end();
  const_attribute_iterator attr_begin() const;
  const_attribute_iterator attr_end() const;
};

Description

element is the most important zeep::xml::node object. It encapsulates a XML element as found in the XML document. It has a qname, can have children, attributes and a namespace.

element public construct/copy/destruct

  1. element(const std::string & qname);
  2. ~element();

element public member functions

  1. void write(writer & w) const;
    writing out
  2. bool equals(const node * n) const;
    Compare the node with n.
  3. node * clone() const;
    Deep clone the node.
  4. std::string str() const;
    return all content concatenated, including that of children.
  5. void write_content(std::ostream & os, const char * sep = kWhiteSpaceChar) const;
    write out the concatenated content to a stream, separated by sep.
  6. std::string qname() const;

    Nodes can have a name, and the XPath specification requires that a node can have a so-called expanded-name. This name consists of a local-name and a namespace which is a URI. And we can have a QName which is a concatenation of a prefix (that points to a namespace URI) and a local-name separated by a colon.

    To reduce storage requirements, names are stored in nodes as qnames, if at all.

  7. std::string namespace_for_prefix(const std::string & prefix) const;
    Return the namespace URI for a prefix.
  8. std::string prefix_for_namespace(const std::string & uri) const;
    Return the prefix for a namespace URI.
  9. std::string content() const;
  10. void content(const std::string & content);
  11. std::string get_attribute(const std::string & qname) const;
  12. attribute * get_attribute_node(const std::string & qname) const;
  13. void set_attribute(const std::string & qname, const std::string & value, 
                       bool id = false);
    the DOCTYPE can specify some attributes as ID
  14. void remove_attribute(const std::string & qname);
  15. void set_name_space(const std::string & prefix, const std::string & uri);
    to set the default namespace, pass an empty string as prefix
  16. void add_text(const std::string & s);

    The add_text method checks if the last added child is a text node, and if so, it appends the string to this node's value. Otherwise, it adds a new text node child with the new text.

  17. attribute_set attributes() const;
    to iterate over the attribute nodes
  18. name_space_list name_spaces() const;
    to iterate over the namespace nodes
  19. std::string lang() const;
    content of a xml:lang attribute of this element, or its nearest ancestor
  20. std::string id() const;

    content of the xml:id attribute, or the attribute that was defined to be of type ID by the DOCTYPE.

  21. attribute_iterator attr_begin();
  22. attribute_iterator attr_end();
  23. const_attribute_iterator attr_begin() const;
  24. const_attribute_iterator attr_end() const;

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/document.html0000664000175000017500000011415412162310454020774 0ustar maartenmaarten Class document

PrevUpHomeNext

Class document

zeep::xml::document

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/document.hpp>


class document {
public:
  // construct/copy/destruct
  document();
  document(const std::string &);
  document(std::istream &);
  document(std::istream &, const boost::filesystem::path &);

  // public member functions
  void read(const std::string &);
  void read(std::istream &);
  void read(std::istream &, const boost::filesystem::path &);
  void write(writer &) const;
  template<typename T> void serialize(const char *, const T &);
  template<typename T> void deserialize(const char *, T &);
  root_node * root() const;
  element * child() const;
  void child(element *);
  element_set find(const std::string &) const;
  element * find_first(const std::string &) const;
  element_set find(const char *) const;
  element * find_first(const char *) const;
  void find(const char *, node_set &) const;
  void find(const char *, element_set &) const;
  node * find_first_node(const char *) const;
  bool operator==(const document &) const;
  bool operator!=(const document &) const;
  void base_dir(const boost::filesystem::path &);
  encoding_type encoding() const;
  void encoding(encoding_type);
  int indent() const;
  void indent(int);
  bool wrap() const;
  void wrap(bool);
  bool trim() const;
  void trim(bool);
  bool no_comment() const;
  void no_comment(bool);
  void set_validating(bool);
  void set_preserve_cdata(bool);

  // public data members
  boost::function< std::istream *(const std::string &base, const std::string &pubid, const std::string &sysid)> external_entity_ref_handler;
};

Description

zeep::xml::document is the class that contains a parsed XML file. You can create an empty document and add nodes to it, or you can create it by specifying a string containing XML or an std::istream to parse.

If you use an std::fstream to read a file, be sure to open the file ios::binary. Otherwise, the detection of text encoding might go wrong or the content can become corrupted.

Default is to parse CDATA sections into zeep::xml::text nodes. If you want to preserve CDATA sections in the DOM tree, you have to call set_preserve_cdata before reading the file.

By default a document is not validated. But you can turn on validation by using the appropriate constructor or read method, or by setting set_validating explicitly. The DTD's will be loaded from the base dir specified, but you can change this by assigning a external_entity_ref_handler.

A document has one zeep::xml::root_node element. This root element can have only one zeep::xml::element child node.

document public construct/copy/destruct

  1. document();
    Constructor for an empty document.
  2. document(const std::string & s);
    Constructor that will parse the XML passed in argument s.
  3. document(std::istream & is);
    Constructor that will parse the XML passed in argument is.
  4. document(std::istream & is, const boost::filesystem::path & base_dir);
    Constructor that will parse the XML passed in argument is. This constructor will also validate the input using DTD's found in base_dir.

document public member functions

  1. void read(const std::string & s);
    Replace the content of the document with the parsed XML in s.
  2. void read(std::istream & is);
    Replace the content of the document with the parsed XML in is.
  3. void read(std::istream & is, const boost::filesystem::path & base_dir);
    Replace the content of the document with the parsed XML in is and use validation based on DTD's found in base_dir.
  4. void write(writer & w) const;
    Write the contents of the document as XML using zeep::xml::writer object w.
  5. template<typename T> void serialize(const char * name, const T & data);
    Serialization support.

    Serialize data into a document containing name as root node

  6. template<typename T> void deserialize(const char * name, T & data);
    Deserialize root node with name name into data.
  7. root_node * root() const;
    A valid xml document contains exactly one zeep::xml::root_node element.
  8. element * child() const;
    The root has one child zeep::xml::element.
  9. void child(element * e);
  10. element_set find(const std::string & path) const;
    < Return all zeep::xml::elements that match the XPath query path
  11. element * find_first(const std::string & path) const;
    < Return the first zeep::xml::element that matches the XPath query path
  12. element_set find(const char * path) const;
    Return all zeep::xml::elements that match the XPath query path.
  13. element * find_first(const char * path) const;
    Return the first zeep::xml::element that matches the XPath query path.
  14. void find(const char * path, node_set & nodes) const;
    Return all zeep::xml::nodes (attributes or elements) that match the XPath query path.
  15. void find(const char * path, element_set & elements) const;
    Return all zeep::xml::elements that match the XPath query path.
  16. node * find_first_node(const char * path) const;
    Return the first zeep::xml::node (attribute or element) that matches the XPath query path.
  17. bool operator==(const document & doc) const;
    Compare two xml documents.
  18. bool operator!=(const document & doc) const;
  19. void base_dir(const boost::filesystem::path & path);

    If you want to validate the document using DTD files stored on disk, you can specifiy this directory prior to reading the document.

  20. encoding_type encoding() const;
    The text encoding as detected in the input.
  21. void encoding(encoding_type enc);
    The text encoding to use for output.
  22. int indent() const;
    get number of spaces to indent elements:
  23. void indent(int indent);
    set number of spaces to indent elements:
  24. bool wrap() const;
    get wrap flag, whether elements will appear on their own line or not
  25. void wrap(bool wrap);
    set wrap flag, whether elements will appear on their own line or not
  26. bool trim() const;
    get trim flag, strips white space in #PCDATA sections
  27. void trim(bool trim);
    set trim flag, strips white space in #PCDATA sections
  28. bool no_comment() const;
    get no_comment flag, suppresses the output of XML comments
  29. void no_comment(bool no_comment);
    get no_comment flag, suppresses the output of XML comments
  30. void set_validating(bool validate);

    options for parsing validating uses a DTD if it is defined

  31. void set_preserve_cdata(bool preserve_cdata);

    preserve cdata, preserves CDATA sections instead of converting them into text nodes.

document public public data members

  1. boost::function< std::istream *(const std::string &base, const std::string &pubid, const std::string &sysid)> external_entity_ref_handler;

    The default for libzeep is to locate the external reference based on sysid and base_dir. Only local files are loaded this way. You can specify a entity loader here if you want to be able to load DTD files from another source.


PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/xml/node.html0000664000175000017500000005107512162310454020105 0ustar maartenmaarten Class node

PrevUpHomeNext

Class node

zeep::xml::node

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/node.hpp>


class node {
public:

  // public member functions
  root_node * root();
  const root_node * root() const;
  container * parent();
  const container * parent() const;
  node * next();
  const node * next() const;
  node * prev();
  const node * prev() const;
  std::string lang() const;
  std::string qname() const;
  std::string name() const;
  std::string prefix() const;
  std::string ns() const;
  std::string namespace_for_prefix(const std::string &) const;
  std::string prefix_for_namespace(const std::string &) const;
  std::string str() const;
  void write_content(std::ostream &, const char * = kWhiteSpaceChar) const;
  void write(writer &) const;
  bool equals(const node *) const;
  node * clone() const;
  void validate();
};

Description

Node is the abstract base class for all data contained in zeep XML documents. The DOM tree consists of nodes that are linked to each other, each node can have a parent and siblings pointed to by the next and previous members. All nodes in a DOM tree share a common root node.

Nodes can have a name, and the XPath specification requires that a node can have a so-called expanded-name. This name consists of a local-name and a namespace which is a URI. And we can have a QName which is a concatenation of a prefix (that points to a namespace URI) and a local-name separated by a colon.

To reduce storage requirements, names are stored in nodes as qnames, if at all. the convenience functions name() and prefix() parse the qname(). ns() returns the namespace URI for the node, if it can be resolved.

Nodes inherit the namespace of their parent unless they override it which means resolving prefixes and namespaces is done hierarchically

node public member functions

  1. root_node * root();
    The root node for this node.
  2. const root_node * root() const;
    The root node for this node.
  3. container * parent();
    The root node for this node.
  4. const container * parent() const;
    The root node for this node.
  5. node * next();
    The next sibling.
  6. const node * next() const;
    The next sibling.
  7. node * prev();
    The previous sibling.
  8. const node * prev() const;
    The previous sibling.
  9. std::string lang() const;
    content of a xml:lang attribute of this element, or its nearest ancestor
  10. std::string qname() const;

    Nodes can have a name, and the XPath specification requires that a node can have a so-called expanded-name. This name consists of a local-name and a namespace which is a URI. And we can have a QName which is a concatenation of a prefix (that points to a namespace URI) and a local-name separated by a colon.

    To reduce storage requirements, names are stored in nodes as qnames, if at all.

  11. std::string name() const;
    The name for the node as parsed from the qname.
  12. std::string prefix() const;
    The prefix for the node as parsed from the qname.
  13. std::string ns() const;
    Returns the namespace URI for the node, if it can be resolved.
  14. std::string namespace_for_prefix(const std::string & prefix) const;
    Return the namespace URI for a prefix.
  15. std::string prefix_for_namespace(const std::string & uri) const;
    Return the prefix for a namespace URI.
  16. std::string str() const;
    return all content concatenated, including that of children.
  17. void write_content(std::ostream & os, const char * sep = kWhiteSpaceChar) const;
    write out the concatenated content to a stream, separated by sep.
  18. void write(writer & w) const;
    writing out
  19. bool equals(const node * n) const;
    Compare the node with n.
  20. node * clone() const;
    Deep clone the node.
  21. void validate();
    debug routine

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/make_fault_idm38432.html0000664000175000017500000001010012162310454021705 0ustar maartenmaarten Function make_fault

PrevUpHomeNext

Function make_fault

zeep::make_fault

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/envelope.hpp>


xml::element * make_fault(const std::string & message);

Description

Create a standard SOAP Fault message for the string parameter

Parameters:

message

The string object containing a descriptive error message.

Returns:

A new xml::element object containing the fault envelope.


PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/server.html0000664000175000017500000002523212162310454017662 0ustar maartenmaarten Class server

PrevUpHomeNext

Class server

zeep::server

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/server.hpp>


class server : public zeep::dispatcher, public zeep::http::server {
public:
  // construct/copy/destruct
  server(const std::string &, const std::string &);

  // public member functions
  void bind(const std::string &, unsigned short);
  void set_location(const std::string &);

  // protected member functions
  void handle_request(const http::request &, http::reply &);
};

Description

zeep::server inherits from zeep::http::server and zeep::dispatcher to do its work. You construct a new server object by passing in a namespace in the ns parameter and a service name in the service parameter.

If the server is behind a proxy, you'll also need to call set_location to specify the external address of your server.

server public construct/copy/destruct

  1. server(const std::string & ns, const std::string & service);

    The constructor takes two arguments

    Parameters:

    ns

    The namespace as used for the WSDL and SOAP messages

    service

    The service name for this server

server public member functions

  1. void bind(const std::string & address, unsigned short port);
    Calls zeep::http::server and sets m_location if it wasn't already specified.
  2. void set_location(const std::string & location);

    If your server is located behind a reverse proxy, you'll have to specify the address where it can be found by clients. If you don't, the WSDL will contain an unreachable address.

    Parameters:

    location

    The URL that specifies the external address of this server.

server protected member functions

  1. void handle_request(const http::request & req, http::reply & rep);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/exception.html0000664000175000017500000001527512162310454020360 0ustar maartenmaarten Class exception

PrevUpHomeNext

Class exception

zeep::exception — zeep::exception is a class used to throw zeep exception.

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/exception.hpp>


class exception {
public:
  // construct/copy/destruct
  exception(const char *, ...);
  exception(const std::string &);
  ~exception();

  // public member functions
  const char * what() const;
};

Description

exception public construct/copy/destruct

  1. exception(const char * message, ...);
    Create an exception with vsprintf like parameters.
  2. exception(const std::string & message);
  3. ~exception();

exception public member functions

  1. const char * what() const;

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/dispatcher.html0000664000175000017500000003070112162310454020477 0ustar maartenmaarten Class dispatcher

PrevUpHomeNext

Class dispatcher

zeep::dispatcher

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/dispatcher.hpp>


class dispatcher {
public:
  // types
  typedef unspecified handler_list;

  // construct/copy/destruct
  dispatcher(const std::string &, const std::string &);
  ~dispatcher();

  // public member functions
  template<typename Class, typename Function> 
    void register_action(const char *, Class *, Function, unspecified);
  xml::element * dispatch(xml::element *);
  xml::element * dispatch(const std::string &, xml::element *);
  xml::element * make_wsdl(const std::string &);
  void set_response_name(const std::string &, const std::string &);

  // public data members
  std::string m_ns;
  std::string m_service;
  handler_list m_handlers;
};

Description

dispatcher public construct/copy/destruct

  1. dispatcher(const std::string & ns, const std::string & service);
  2. ~dispatcher();

dispatcher public member functions

  1. template<typename Class, typename Function> 
      void register_action(const char * action, Class * server, Function call, 
                           unspecified arg);
  2. xml::element * dispatch(xml::element * in);
    Dispatch a SOAP message and return the result.
  3. xml::element * dispatch(const std::string & action, xml::element * in);
    Dispatch a SOAP message and return the result.
  4. xml::element * make_wsdl(const std::string & address);
    Create a WSDL based on the registered actions.
  5. void set_response_name(const std::string & action, const std::string & name);

PrevUpHomeNext
libzeep-3.0.2/doc/html/zeep/make_fault_idp7182960.html0000664000175000017500000001003312162310454022072 0ustar maartenmaarten Function make_fault

PrevUpHomeNext

Function make_fault

zeep::make_fault

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/envelope.hpp>


xml::element * make_fault(const std::exception & ex);

Description

Create a standard SOAP Fault message for the exception object

Parameters:

ex

The exception object that was catched.

Returns:

A new xml::element object containing the fault envelope.


PrevUpHomeNext
libzeep-3.0.2/doc/html/SOAP_XML_HAS_EXPAT_SUPPORT.html0000664000175000017500000000625212162310454021564 0ustar maartenmaarten Macro SOAP_XML_HAS_EXPAT_SUPPORT

PrevUpHomeNext

Macro SOAP_XML_HAS_EXPAT_SUPPORT

SOAP_XML_HAS_EXPAT_SUPPORT

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/config.hpp>

SOAP_XML_HAS_EXPAT_SUPPORT

Description

Libzeep comes with its own XML parser implementation. If you prefer you can use expat instead. To do so you have to define the SOAP_XML_HAS_EXPAT_SUPPORT flag and then you can call the zeep::xml::document::set_parser_type function to specify expat.


PrevUpHomeNext
libzeep-3.0.2/doc/html/SOAP_XML_SET_STRUCT_NAME.html0000664000175000017500000000706612162310454021317 0ustar maartenmaarten Macro SOAP_XML_SET_STRUCT_NAME

PrevUpHomeNext

Macro SOAP_XML_SET_STRUCT_NAME

SOAP_XML_SET_STRUCT_NAME — A macro to assign a name to a struct used in serialization.

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/serialize.hpp>

SOAP_XML_SET_STRUCT_NAME(s)

Description

By default, libzeep uses the typeid(s).name() as the name for an element. That's often not what is intented. Calling this macro will make sure the type name you used in your code will be used instead.

E.g., struct FindResult { ... } might end up with a fancy name in the WSDL. To use FindResult instead, call SOAP_XML_SET_STRUCT_NAME(FindResult);

An alternative it to call, which allows different WSDL and struct names: zeep::xml::serialize_struct<FindResult>::set_struct_name("FindResult");


PrevUpHomeNext
libzeep-3.0.2/doc/html/boostbook.css0000664000175000017500000003344612162310454017244 0ustar maartenmaarten/*============================================================================= Copyright (c) 2004 Joel de Guzman http://spirit.sourceforge.net/ Distributed under the Boost Software License, Version 1.0. (See accompany- ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ /*============================================================================= Body defaults =============================================================================*/ body { margin: 1em; font-family: sans-serif; } /*============================================================================= Paragraphs =============================================================================*/ p { text-align: left; font-size: 10pt; line-height: 1.15; } /*============================================================================= Program listings =============================================================================*/ /* Code on paragraphs */ p tt.computeroutput { font-size: 9pt; } pre.synopsis { font-size: 9pt; margin: 1pc 4% 0pc 4%; padding: 0.5pc 0.5pc 0.5pc 0.5pc; } .programlisting, .screen { font-size: 9pt; display: block; margin: 1pc 4% 0pc 4%; padding: 0.5pc 0.5pc 0.5pc 0.5pc; } /* Program listings in tables don't get borders */ td .programlisting, td .screen { margin: 0pc 0pc 0pc 0pc; padding: 0pc 0pc 0pc 0pc; } /*============================================================================= Headings =============================================================================*/ h1, h2, h3, h4, h5, h6 { text-align: left; margin: 1em 0em 0.5em 0em; font-weight: bold; } h1 { font-size: 140%; } h2 { font-weight: bold; font-size: 140%; } h3 { font-weight: bold; font-size: 130%; } h4 { font-weight: bold; font-size: 120%; } h5 { font-weight: normal; font-style: italic; font-size: 110%; } h6 { font-weight: normal; font-style: italic; font-size: 100%; } /* Top page titles */ title, h1.title, h2.title h3.title, h4.title, h5.title, h6.title, .refentrytitle { font-weight: bold; margin-bottom: 1pc; } h1.title { font-size: 140% } h2.title { font-size: 140% } h3.title { font-size: 130% } h4.title { font-size: 120% } h5.title { font-size: 110% } h6.title { font-size: 100% } .section h1 { margin: 0em 0em 0.5em 0em; font-size: 140%; } .section h2 { font-size: 140% } .section h3 { font-size: 130% } .section h4 { font-size: 120% } .section h5 { font-size: 110% } .section h6 { font-size: 100% } /* Code on titles */ h1 tt.computeroutput { font-size: 140% } h2 tt.computeroutput { font-size: 140% } h3 tt.computeroutput { font-size: 130% } h4 tt.computeroutput { font-size: 130% } h5 tt.computeroutput { font-size: 130% } h6 tt.computeroutput { font-size: 130% } /*============================================================================= Author =============================================================================*/ h3.author { font-size: 100% } /*============================================================================= Lists =============================================================================*/ li { font-size: 10pt; line-height: 1.3; } /* Unordered lists */ ul { text-align: left; } /* Ordered lists */ ol { text-align: left; } /*============================================================================= Links =============================================================================*/ a { text-decoration: none; /* no underline */ } a:hover { text-decoration: underline; } /*============================================================================= Spirit style navigation =============================================================================*/ .spirit-nav { text-align: right; } .spirit-nav a { color: white; padding-left: 0.5em; } .spirit-nav img { border-width: 0px; } /*============================================================================= Copyright footer =============================================================================*/ .copyright-footer { text-align: right; font-size: 70%; } .copyright-footer p { text-align: right; font-size: 80%; } /*============================================================================= Table of contents =============================================================================*/ .toc { margin: 1pc 4% 0pc 4%; padding: 0.1pc 1pc 0.1pc 1pc; font-size: 80%; line-height: 1.15; } .boost-toc { float: right; padding: 0.5pc; } /* Code on toc */ .toc .computeroutput { font-size: 120% } /* No margin on nested menus */ .toc dl dl { margin: 0; } /*============================================================================= Tables =============================================================================*/ .table-title, div.table p.title { margin-left: 4%; padding-right: 0.5em; padding-left: 0.5em; } .informaltable table, .table table { width: 92%; margin-left: 4%; margin-right: 4%; } div.informaltable table, div.table table { padding: 4px; } /* Table Cells */ div.informaltable table tr td, div.table table tr td { padding: 0.5em; text-align: left; font-size: 9pt; } div.informaltable table tr th, div.table table tr th { padding: 0.5em 0.5em 0.5em 0.5em; border: 1pt solid white; font-size: 80%; } table.simplelist { width: auto !important; margin: 0em !important; padding: 0em !important; border: none !important; } table.simplelist td { margin: 0em !important; padding: 0em !important; text-align: left !important; font-size: 9pt !important; border: none !important; } /*============================================================================= Blurbs =============================================================================*/ div.note, div.tip, div.important, div.caution, div.warning, p.blurb { font-size: 9pt; /* A little bit smaller than the main text */ line-height: 1.2; display: block; margin: 1pc 4% 0pc 4%; padding: 0.5pc 0.5pc 0.5pc 0.5pc; } p.blurb img { padding: 1pt; } /*============================================================================= Variable Lists =============================================================================*/ div.variablelist { margin: 1em 0; } /* Make the terms in definition lists bold */ div.variablelist dl dt, span.term { font-weight: bold; font-size: 10pt; } div.variablelist table tbody tr td { text-align: left; vertical-align: top; padding: 0em 2em 0em 0em; font-size: 10pt; margin: 0em 0em 0.5em 0em; line-height: 1; } div.variablelist dl dt { margin-bottom: 0.2em; } div.variablelist dl dd { margin: 0em 0em 0.5em 2em; font-size: 10pt; } div.variablelist table tbody tr td p, div.variablelist dl dd p { margin: 0em 0em 0.5em 0em; line-height: 1; } /*============================================================================= Misc =============================================================================*/ /* Title of books and articles in bibliographies */ span.title { font-style: italic; } span.underline { text-decoration: underline; } span.strikethrough { text-decoration: line-through; } /* Copyright, Legal Notice */ div div.legalnotice p { text-align: left } /*============================================================================= Colors =============================================================================*/ @media screen { body { background-color: #FFFFFF; color: #000000; } /* Syntax Highlighting */ .keyword { color: #0000AA; } .identifier { color: #000000; } .special { color: #707070; } .preprocessor { color: #402080; } .char { color: teal; } .comment { color: #800000; } .string { color: teal; } .number { color: teal; } .white_bkd { background-color: #FFFFFF; } .dk_grey_bkd { background-color: #999999; } /* Links */ a, a .keyword, a .identifier, a .special, a .preprocessor a .char, a .comment, a .string, a .number { color: #005a9c; } a:visited, a:visited .keyword, a:visited .identifier, a:visited .special, a:visited .preprocessor a:visited .char, a:visited .comment, a:visited .string, a:visited .number { color: #9c5a9c; } h1 a, h2 a, h3 a, h4 a, h5 a, h6 a, h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover, h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited { text-decoration: none; /* no underline */ color: #000000; } /* Copyright, Legal Notice */ .copyright { color: #666666; font-size: small; } div div.legalnotice p { color: #666666; } /* Program listing */ pre.synopsis { border: 1px solid #DCDCDC; } .programlisting, .screen { border: 1px solid #DCDCDC; } td .programlisting, td .screen { border: 0px solid #DCDCDC; } /* Blurbs */ div.note, div.tip, div.important, div.caution, div.warning, p.blurb { border: 1px solid #DCDCDC; } /* Table of contents */ .toc { border: 1px solid #DCDCDC; } /* Tables */ div.informaltable table tr td, div.table table tr td { border: 1px solid #DCDCDC; } div.informaltable table tr th, div.table table tr th { background-color: #F0F0F0; border: 1px solid #DCDCDC; } .copyright-footer { color: #8F8F8F; } /* Misc */ span.highlight { color: #00A000; } } @media print { /* Links */ a { color: black; } a:visited { color: black; } .spirit-nav { display: none; } /* Program listing */ pre.synopsis { border: 1px solid gray; } .programlisting, .screen { border: 1px solid gray; } td .programlisting, td .screen { border: 0px solid #DCDCDC; } /* Table of contents */ .toc { border: 1px solid gray; } .informaltable table, .table table { border: 1px solid gray; border-collapse: collapse; } /* Tables */ div.informaltable table tr td, div.table table tr td { border: 1px solid gray; } div.informaltable table tr th, div.table table tr th { border: 1px solid gray; } table.simplelist tr td { border: none !important; } /* Misc */ span.highlight { font-weight: bold; } } /*============================================================================= Images =============================================================================*/ span.inlinemediaobject img { vertical-align: middle; } /*============================================================================== Super and Subscript: style so that line spacing isn't effected, see http://www.adobe.com/cfusion/communityengine/index.cfm?event=showdetails&productId=1&postId=5341 ==============================================================================*/ sup, sub { height: 0; line-height: 1; vertical-align: baseline; position: relative; } /* For internet explorer: */ * html sup, * html sub { vertical-align: bottom; } sup { bottom: 1ex; } sub { top: .5ex; } /*============================================================================== Indexes: pretty much the same as the TOC. ==============================================================================*/ .index { font-size: 80%; padding-top: 0px; padding-bottom: 0px; margin-top: 0px; margin-bottom: 0px; margin-left: 0px; } .index ul { padding-left: 3em; } .index p { padding: 2px; margin: 2px; } .index-entry-level-0 { font-weight: bold; } .index em { font-weight: bold; } libzeep-3.0.2/doc/html/index.html0000664000175000017500000002236312162310454016522 0ustar maartenmaarten libzeep 3.0

Next

libzeep 3.0

Maarten L. Hekkelman

Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)


Table of Contents

Overview
Introduction
XML Parser
XML Serialization
XPath 1.0
HTTP Server
SOAP Server
Creating a SOAP and REST server
Introduction
A real world example
Creating a Web Application
Introduction
The building blocks
Hello world!
Using forms
Using el script
Processing Tags
Reference
Header </home/maarten/projects/libzeep/zeep/config.hpp>
Header </home/maarten/projects/libzeep/zeep/dispatcher.hpp>
Header </home/maarten/projects/libzeep/zeep/envelope.hpp>
Header </home/maarten/projects/libzeep/zeep/exception.hpp>
Header </home/maarten/projects/libzeep/zeep/http/connection.hpp>
Header </home/maarten/projects/libzeep/zeep/http/header.hpp>
Header </home/maarten/projects/libzeep/zeep/http/preforked-server.hpp>
Header </home/maarten/projects/libzeep/zeep/http/reply.hpp>
Header </home/maarten/projects/libzeep/zeep/http/request.hpp>
Header </home/maarten/projects/libzeep/zeep/http/request_handler.hpp>
Header </home/maarten/projects/libzeep/zeep/http/request_parser.hpp>
Header </home/maarten/projects/libzeep/zeep/http/webapp.hpp>
Header </home/maarten/projects/libzeep/zeep/http/webapp/el.hpp>
Header </home/maarten/projects/libzeep/zeep/server.hpp>
Header </home/maarten/projects/libzeep/zeep/http/server.hpp>
Header </home/maarten/projects/libzeep/zeep/xml/doctype.hpp>
Header </home/maarten/projects/libzeep/zeep/xml/document.hpp>
Header </home/maarten/projects/libzeep/zeep/xml/node.hpp>
Header </home/maarten/projects/libzeep/zeep/xml/parser.hpp>
Header </home/maarten/projects/libzeep/zeep/xml/serialize.hpp>
Header </home/maarten/projects/libzeep/zeep/xml/unicode_support.hpp>
Header </home/maarten/projects/libzeep/zeep/xml/writer.hpp>
Header </home/maarten/projects/libzeep/zeep/xml/xpath.hpp>

Libzeep is packaged as one library, but actually contains two different libraries. The first part of libzeep consists of code to read, manipulate and write XML. It contains a validating XML parser, an XPath implementation to query a DOM tree, code to serialize objects into and out of XML and finally it contains an XML writing module.

The second part of libzeep is targeted to writing SOAP and REST servers as well as full web applications using C++. There is a simple HTTP server implementation, code to create SOAP (and REST) servers out of existing C++ objects and there is code to create complete web applications that work a bit like popular Java web application frameworks. The libzeep web application framework turns page templates consisting of XHTML with custom tags and a custom script language into HTML.

Last revised: March 26, 2013 at 09:37:22 GMT


Next
libzeep-3.0.2/doc/html/SOAP_XML_ADD_ENUM.html0000664000175000017500000000721012162310454020163 0ustar maartenmaarten Macro SOAP_XML_ADD_ENUM

PrevUpHomeNext

Macro SOAP_XML_ADD_ENUM

SOAP_XML_ADD_ENUM — A macro to add the name of an enum value to the serializer.

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/xml/serialize.hpp>

SOAP_XML_ADD_ENUM(e, v)

Description

To be able to correctly use enum values in a WSDL file or when serializing, you have to specify the enum values.

E.g., if you have a struct name Algorithm with values 'vector', 'dice' and 'jaccard' you would write:

> enum Algorithm { vector, dice, jaccard }; > SOAP_XML_ADD_ENUM(Algorithm, vector); > SOAP_XML_ADD_ENUM(Algorithm, dice); > SOAP_XML_ADD_ENUM(Algorithm, jaccard);

An alternative (better?) way to do this is:

> zeep::xml::enum_map<Algorithm>::instance("Algorithm").add_enum() > ("vector", vector) > ("dice", dice) > ("jaccard", jaccard);


PrevUpHomeNext
libzeep-3.0.2/doc/html/libzeep/0000755000175000017500000000000012162310454016147 5ustar maartenmaartenlibzeep-3.0.2/doc/html/libzeep/intro.html0000664000175000017500000007614112162310454020203 0ustar maartenmaarten Introduction

PrevUpHomeNext

Libzeep comes with a validating XML parser. Using this parser is as simple as writing:

#include <zeep/xml/document.hpp>
#include <fstream>

int main()
{
	std::ifstream file("test.xml");
	zeep::xml::document doc(file);
	...
}

This will parse the file text.xml and create an object doc containing the DOM tree. To traverse this tree you can use the various member functions of doc which derives from the generic zeep::xml::container class. Siblings in the DOM tree are stored as linked lists and some elements can have children. To make life easier, you can iterate over elements using STL iterators.

Suppose our test.xml file contains the following XML:

<persons>
	<person>
		<firstname>John</firstname>
		<lastname>Doe</lastname>
	</person>
	<person>
		<firstname>Jane</firstname>
		<lastname>Jones</lastname>
	</person>
</persons>

You could print out the file like this:

// a document contains at most one child node
zeep::xml::element* persons = doc.child();

// begin/end will return iterators to elements
for (zeep::xml::container::iterator person = persons->begin(); person != persons->end(); ++person)
{
	for (zeep::xml::container::iterator name = (*person)->begin(); name != (*person)->end(); ++name)
		std::cout << (*name)->name() << " = " << (*name)->content() << std::endl;
}

Of course, using the new for loop construct, this code would be much more readable:

for (auto person : *persons)
{
	for (auto name : *person)
		std::cout << name->name() << " = " << name->content() << std::endl;
}

But if your compiler does not support that syntax, you can always use boost::range instead:

BOOST_FOREACH (zeep::xml::element* person, *persons)
{
	BOOST_FOREACH (zeep::xml::element* name, *person)
		std::cout << name->name() << " = " << name->content() << std::endl;
}

Accessing attributes is done using the member function element::get_attribute().

An alternative way to read/write XML files is using serialization. To do this, we first construct a structure called Person. We add a templated function to this struct just like in boost::serialize and then we can read the file.

#include <zeep/xml/document.hpp>
#include <zeep/xml/serialize.hpp>
#include <vector>
#include <fstream>

struct Person
{
	std::string firstname;
	std::string lastname;

	template<class Archive>
	void serialize(Archive& ar, const unsigned int version)
	{
		ar & BOOST_SERIALIZATION_NVP(firstname) & BOOST_SERIALIZATION_NVP(lastname);
	}
};

int main()
{
	std::ifstream file("test.xml");
	zeep::xml::document doc(file);
	
	zeep::xml::deserializer ds(doc.child());
	std::vector<Person> person;
	
	// the variable name person must be the same as the name of the XML element person
	ds & BOOST_SERIALIZATION_NVP(person);
	
	// alternative is to use which allows another variable name:
	// ds & boost::serialization::make_nvp("person", person);
}

Since libzeep 3.0 we can reduce the code required.

int main()
{
	std::ifstream file("test.xml");
	zeep::xml::document doc(file);
	
	std::vector<Person> persons;
	
	// New way of deserializing persons
	doc.deserialize("persons", persons);
}

And to write out the persons, we do something similar.

zeep::xml::document doc;
doc.serialize("persons", persons);

std::ofstream file("test-out.xml");
file << doc;

To find out more about serialization, look at the reference for zeep::xml::serializer

Libzeep comes with a XPath 1.0 implementation. You can use this to locate elements in a DOM tree easily. For a complete description of the XPath specification you should read the documentation at e.g. http://www.w3.org/TR/xpath/ or http://www.w3schools.com/xpath/default.asp.

The way it works in libzeep is that you can call find() on an zeep::xml::element object and it will return a zeep::xml::element_set object which is actually a std::list of zeep::xml::element pointers of the elements that conform to the specification in XPath passed as parameter to find(). An alternative method find_first() can be used to return only the first element.

An example where we look for the first person in our test file with the lastname Jones:

zeep::xml::element* jones = doc.child()->find_first("//person[lastname='Jones']");

Creating a HTTP server with libzeep is as simple as:

#include <zeep/http/server.hpp>

class my_server : public zeep::http::server
{
	virtual void handle_request(const zeep::http::request& req, zeep::http::reply& rep)
	{
		...	// do something useful
	}
};

int main()
{
	my_server server;
	server.bind("0.0.0.0", 80);
	server.run(1);
}

Of course you will have to fill in the handle_request part...

Setting up a SOAP server is very easy. Let's continue with our test file and serve it as a SOAP/REST server. We already created the Person struct. The most simple server we can create is one that lists all persons in the test file:

#include <zeep/server.hpp>
#include <fstream>

using namespace std;

... // define the Person struct as above

class my_server : public zeep::server
{
  public:
	my_server();

	// The method we want to export
	void ListPersons(vector<Person>& result);
};

void my_server::ListPersons(vector<Person>& result)
{
	std::ifstream file("test.xml");
	zeep::xml::document doc(file);
	
	zeep::xml::deserializer ds(doc.child());
	ds & boost::serialization::make_nvp("person", result);
}

my_server::my_server() : zeep::server("http://www.example.org/soaptest", "soaptest")
{
	// assign a name to the Person struct (will appear in the WSDL e.g.)
	zeep::xml::serialize_struct<Person>::set_struct_name("person");
	
	// assign names to the parameters of the exported method, in this case there's only
	// one return value to name
	const char* kListPersonsParameterNames[] = { "response" };
	register_action("ListPersons", this, &my_server::ListPersons, kListPersonsParameterNames);
}

int main()
{
	my_server server;
	server.bind("192.168.0.1", 8083);
	server.run(1);	// keep our server single threaded
}

After building this server and running it, you can access the REST version of this routine at http://192.168.0.1:8083/rest/ListPersons and there's a WSDL at http://192.168.0.1:8083/wsdl


PrevUpHomeNext
libzeep-3.0.2/doc/html/libzeep/webapp.html0000664000175000017500000011317512162310454020325 0ustar maartenmaarten Creating a Web Application

PrevUpHomeNext

This section will guide you through all the code you have to write to create an interactive web application using libzeep. The way this works in libzeep looks a lot like popular frameworks found for Java. If you're familiar with JSP and e.g. Struts, you'll notice the similarities.

It is very inconvenient to write HTML code in C++ directly using string concatenations and streams. Therefore, a separation has been made. All HTML is put into XHTML template files. These template files can use special tags to generate HTML tags based on data provided by the server application. A script language that looks a lot like JSP 'Expression Language' (or el in short) is used to program conditional constructs. Communication between this el script and the server application is done via el::object data objects.

Let's start with a simple hello world example. We first create a template file, save this file as hello.xhtml.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xhtml PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/1999/xhtml">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Hello</title>
</head>
<body>
  <p>Hello, world!</p>
</body>
</html>

This is a very simple, strict XHTML 1.1 file. We will serve it with our server:

#include <zeep/http/webapp.hpp>
#include <boost/bind.hpp>

using namespace std;

class MyWebApp : public zeep::http::webapp
{
  public:
    MyWebApp();

    void handle_welcome(const zeep::http::request& request,
           const zeep::http::el::scope& scope, zeep::http::reply& reply);
};

MyWebApp::MyWebApp()
{
  mount("",      boost::bind(&MyWebApp::handle_welcome, this, _1, _2, _3));
}

void MyWebApp::handle_welcome(const zeep::http::request& request,
           const zeep::http::el::scope& scope, zeep::http::reply& reply)
{
  create_reply_from_template("hello.xhtml", scope, reply);
}

int main()
{
  MyWebApp server;
  server.bind("0.0.0.0", 80);
  server.run(1);
}

By calling mount with the empty string, we tell libzeep to redirect all access to the base URL to handle_welcome. This means that visiting the URL http://localhost/ should now return a page containing the string 'Hello, world!'.

Now lets create a form to pass some data from the browser to the server and back. Save the following file as form.xhtml.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xhtml PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/1999/xhtml">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:zeep="http://www.cmbi.ru.nl/libzeep/ml">
<head>
  <title>Form example</title>
</head>
<body>
  <zeep:if test="${name}">
    <p>Hello ${name}!</p>
  </zeep:if>
  <p>Please enter your name and press the Submit button</p>
  <form id="myForm" action="salute" method="get">
    <label>Name: <input id="name" type="text" name="name" value="${name}"/></label>
    <input type="submit" value="Submit" />
  </form>
</body>
</html>

We add the zeep prefix to our html tag, it has the value "http://www.cmbi.ru.nl/libzeep/ml" which is the same as the default value for the ns parameter in the zeep::http::webapp constructor. Note that the input tag has an attribute with value '${data}'. This is a piece of expression language script. This will be explained below:

#include <zeep/http/webapp.hpp>
#include <zeep/http/webapp/el.hpp>
#include <boost/bind.hpp>

using namespace std;

class MyWebApp : public zeep::http::webapp
{
  public:
    MyWebApp();

    void handle_welcome(const zeep::http::request& request,
           const zeep::http::el::scope& scope, zeep::http::reply& reply);
    void handle_salute(const zeep::http::request& request,
           const zeep::http::el::scope& scope, zeep::http::reply& reply);
};

MyWebApp::MyWebApp()
{
  mount("",       boost::bind(&MyWebApp::handle_welcome, this, _1, _2, _3));
  mount("salute", boost::bind(&MyWebApp::handle_salute, this, _1, _2, _3));
}

void MyWebApp::handle_welcome(const zeep::http::request& request,
           const zeep::http::el::scope& scope, zeep::http::reply& reply)
{
  create_reply_from_template("form.xhtml", scope, reply);
}

void MyWebApp::handle_salute(const zeep::http::request& request,
           const zeep::http::el::scope& scope, zeep::http::reply& reply)
{
  zeep::http::parameter_map params;
  get_parameters(scope, params);

  string name = params.get("name", "").as<string>();

  zeep::http::el::scope sub(scope);
  sub.put("name", name);

  create_reply_from_template("form.xhtml", sub, reply);
}

int main()
{
  MyWebApp server;
  server.bind("0.0.0.0", 80);
  server.run(1);
}

This time, we add a new handler for the 'salute' page. The form has an action that points to this salute page. As can be seen in the handle_salute method, we first collect the parameters passed in. Parameters are accessed by name. We then create a sub scope of the scope passed in. In this sub scope we put the value of the parameter so that the XHTML processor can access it. And then we return a reply based on the contents of the form.xhtml template and the contents of the sub scope we created.

el means Expression Language. It is a script language that tries to be like http://en.wikipedia.org/wiki/Unified_Expression_Language. The objects can be created in the C++ server code using the zeep::http::el::object class. Object created this way are then stored in an zeep::http::el::scope object and passed along to the XHTML processing code.

zeep::http::el::object objects can contain simple data and arrays. E.g., to create an array you could write:

using namespace zeep::http;

vector<el::object> ints;
for (int i = 0; i < 10; ++i)
{
	el::object int_object;
	int_object["value"] = i;
	ints.push_back(int_object);
}

scope.put("ints", el::object(ints));

And then you can access this in the XHTML:

1: ${ints[1].value}, 2: ${ints[2].value}

Which should output "1: 1, 2: 2"

The method create_reply_from_template takes the name of a template file and a scope to generate the output XHTML. We've already seen that el scripts are processed by this method. But there is more, several special tags in the template are processed in a special way. These tags are in a separate XML namespace. You can change this name space using the ns parameter in the zeep::http::webapp constructor, the default is http://www.cmbi.ru.nl/libzeep/ml.

In the template for the form example above you might have noticed the <zeep:if> tag. This tag takes one attribute called test and the value of this tag is interpreted as a el script. If the script evaluates to something other than empty, zero or false, the content of the <zeep:if> tag is included, otherwise it is discarded in the output.

There are several predefined processing tags which are summarized below. You can also add your own processing tags using the zeep::http::webapp::add_processor method. This method takes a std::string parameter for the name of the tag and a processor_type parameter which is a call back function.

Table 1. List of predefined processing tags

tag name (without prefix)

Description

Example

include

Takes one parameter named file and replaces the tag with the processed content of this file

<zeep:include file="menu.xhtml"/>

if

Takes one parameter named test containing an el script. This script is evaluated and if the result is not empty, zero or false, the content of the if tags is inserted in the output. Otherwise, the content is discarded.

<zeep:if test="${not empty name}">
  Hello ${name}
</zeep:if>

iterate

Takes two parameters, collection which contains an el script that evaluates to an array el::object and a name in var. The content of the iterate tag is included for each value of collection and var will contain the current value.

<ul><zeep:iterate collection="${names}" var="name">
  <li>${name}</li>
</zeep:iterate></ul>

for

Takes three parameters. The parameters begin and end should evaluate to a number. The parameter var contains a name that will be used to hold the current value when inserting the content of the for tag in each iteration of the for loop between begin and end.

<zeep:for begin="1" end="3" var="i">
  ${i},
</zeep:for>

number

Format the number in the n parameter using the f format. This is limited to the formats '#.##0' and '#.##0B' for now. The first formats an integer value using thousand separators, the second tries to format the integer value in a power of two multiplier (kibi, mebi, etc.) with a suffix of B, M, G, etc.

<zeep:number n="1024" f="0.00#B"/>
Will output 1K

options

This tag will insert multiple <option> tags for each element in the collection parameter. This collection paramter can contain an array of strings or it can contain an array of el::object. In the latter case, you can specify a value and label parameter to name the value and label fields of these objects. A selected parameter can be used to select the current value of the options.

<zeep:options collection="${names}"
  value="id" label="fullName" selected="1" />

option

Generate a single <option> tag with a value as specified in the value parameter. If selected evaluates to the same value as value, the option is selected. The content of the <option> tag is inserted in the final tag.

<zeep:option value="1" selected="${user}">
  John Doe
</zeep:option>

checkbox

Create an <input> tag with type checkbox. The parameter name is used as name attribute and the parameter checked is evaluated to see if the checkbox should be in checked mode.

<zeep:checkbox name='cb1' checked='${true}'>
  Check me
</zeep:checkbox>

url

The url processing tag creates a new variable in the current scope with the name as specified in the var parameter. It then creates a list of all original HTTP parameters for the current page. You can override these parameter, and add new ones, by adding <param> tags in the <url> tag.

<zeep:url var="next">
  <zeep:param name='page' value='${page + 1}'/>
<zeep:url>
<a href="${next}">Next page</a>

param

see url above.

 

embed

This tag takes the content of the var parameter which should contain valid XML and puts the processed value in the document.

<zeep:embed var="&lt;em&gt;hello, world!&lt;/em&gt;"/>



PrevUpHomeNext
libzeep-3.0.2/doc/html/libzeep/soap.html0000664000175000017500000005170312162310454020007 0ustar maartenmaarten Creating a SOAP and REST server

PrevUpHomeNext

SOAP and REST are two ways to export functionality over the web. Both have their strongness and weakness. SOAP enforces a strict type checking on input and output parameters. It works with a formal description file called WSDL that specifies all the exposed functionality and how to invoke this. Many tools exist that can read WSDL files and create client code that uses the exposed functions.

REST on the other hand, is much easier to use ad hoc. It passes the arguments to the invoked functions in the URL and uses standard GET, POST and PUT methods of the HTTP protocol.

libzeep is mainly focussed to using SOAP, but allows to access the exported functionality in a REST like way. Not all functions can be accessed this way, if the input parameters are some complex type, you're out of luck. This documentation will focus on SOAP, but if the function is simple, you can test it using REST from a browser.

Creating a SOAP server using libzeep is very easy. The bulk of the work is done by libzeep, you only have to specify what methods to expose and optionally what datatypes.

To demonstrate this, we will create a simple SOAP server that allows the client to search for documents in a databank. Lets start with the initial code, the declaration of our server object.

#include <zeep/server.hpp>

using namespace std;

class MyServer : public zeep::server
{
  public:

    struct MyHit
    {
      long   id;
      float  score;
      string title;

      template<class Archive>
      void serialize(Archive& ar, const unsigned int version)
      {
        ar & BOOST_SERIALIZATION_NVP(id) & BOOST_SERIALIZATION_NVP(score) & BOOST_SERIALIZATION_NVP(title);
      }
    };

    enum MyAlgorithm
    {
      algVector, algDice, algJaccard
    };

    MyServer();

    void CountDocuments(long& outCount);
    void GetDocument(long inID, string& outDocument);
    void FindDocument(const vector<string>& inTerms, MyAlgorithm inAlgorithm,
    vector<MyHit>& outResponse);
};

Nothing special so far. Apart from inheriting from zeep::server, this code could have been code you already had lying around. The addition of the serialize method to MyHit may also have been new to the code. The implementation of the actual server methods are also straightforward:

void MyServer::CountDocuments(long& outCount)
{
  long count = 1; 	// real code should return something more sensible of course
  outCount = count;
}

void MyServer::GetDocument(long inID, string& outDocument)
{
  if (inID == 1)
    outDocument = "The first document!";
  else
    throw zeep::exception("document %ld not found", inID);
}

void MyServer::FindDocument(const vector<string>& inTerms,
  MyAlgorithm inAlgorithm, vector<MyHit>& outResponse)
{
  if (inTerms.size() == 1 and inAlgorithm == algVector)
  {
    MyHit hit = { 1, 1.0f, "The first hit" };
    outResponse.push_back(hit);
  }
}

Not very useful code, but it gives you an idea how simple it is to create a server. You don't have to do anything special, it's still code you could have written for some other purpose. Note that the GetDocument method throws an exception. The result in a SOAP server will be a SOAP Fault being returned containing the text 'document x not found'.

Unfortunately, this is not all that needs to be done, we still have to tell libzeep what methods and what datatypes to expose. That's what we do in the constructor for MyServer.

MyServer::MyServer()
  : zeep::server("http://www.example.org/MyServer", "searchMyServer")
{
  // first export the data types, start with MyHit
  zeep::xml::serialize_struct<MyHit>::set_struct_name("hit");

  // and then the MyAlgorithm enum
  zeep::xml::enum_map<MyAlgorithm>::instance("algorithm").add_enum()
    ("vector", algVector)
    ("dice", algDice)
    ("jaccard", algJaccard);

  // Now export the methods, start with CountDocuments
  const char* kCountDocumentsParamNames[] = { "response" };
  register_action("CountDocuments", this, &MyServer::CountDocuments, kCountDocumentsParamNames);

  // then GetDocument
  const char* kGetDocumentParamNames[] = { "id", "response" };
  register_action("GetDocument", this, &MyServer::GetDocument, kGetDocumentParamNames);

  const char* kFindDocumentParamNames[] = { "terms", "algorithm", "response" };
  register_action("FindDocument", this, &MyServer::FindDocument, kFindDocumentParamNames);
}

We start the constructor by calling the constructor of our base class, zeep::server. We then continue by exporting the data types. Our MyHit datatype is exported under the name 'hit' and MyAlgorithm is exported as 'algorithm'. The various values of MyAlgorithm are exported under a new name as well.

After exporting the datatypes, we export the methods. We do this by calling register_action specifying the parameters for the exported method name, the callback to make and the names for the parameters. And that's all. All that's left is to write a main.

int main()
{
  MyServer server;
  server.bind("0.0.0.0", 80);
  server.run(1);
}

And that will run our code in a single threaded server. If you run this code on your local machine you can test the REST versions of the code by visiting the following URL's with a web browser:

http://localhost/rest/CountDocuments Will return a SOAP envelope containing 1 in a response element

http://localhost/rest/GetDocument/id/1

http://localhost/rest/GetDocument/id/2 Will return a SOAP Fault

http://localhost/rest/FindDocument/terms/bla/algorithm/vector


PrevUpHomeNext
libzeep-3.0.2/doc/html/images/0000775000175000017500000000000012162310454015764 5ustar maartenmaartenlibzeep-3.0.2/doc/html/images/alert.png0000664000175000017500000000113312162310454017577 0ustar maartenmaartenPNG  IHDRaDŽsBITOPLTE{♙PL9][U@5YH5*A>9ya50fffPD1-%"{dPfffK<LLK̙=;9{{{ $ɡmiTЦ70PNH;/O?\L:1!3.6+)" RJ5tRNS| pHYs B4%tEXtSoftwareMacromedia Fireworks MX 2004vIDATxm `4b$ s>wqb/w;߇NCd~`Z%G}?3& jĜ{)I՝KN$#"@!X ɷE%p!IENDB`libzeep-3.0.2/doc/html/images/tip.png0000664000175000017500000000070112162310454017264 0ustar maartenmaartenPNG  IHDR* bKGD#2IDATxu @!+x6KR+hJTaK >߁Rh~j?g0qF@!eH,0܆x0&p ^J5y=J % P<*ğ{j #7^L~!=&Ṳ; &rgߊFmͩP; ot6BJqC Xdui]}OL4+|) -CtEXtSoftware@(#)ImageMagick 4.2.8 99/08/01 cristy@mystic.es.dupont.com!*tEXtSignatureee9d877396ce267aeb0179d35f81b2ac3'tEXtPage25x24+0+0 IENDB`libzeep-3.0.2/doc/html/images/note.png0000664000175000017500000000075212162310454017443 0ustar maartenmaartenPNG  IHDRb$bKGD#2IDATxe!0 E}K C tAQCACQA+g4mɌoK. qc  D="s %dǜH1y%M8fK wֵ>i6g-NpYtL#ߟ ab;U#2V} ԣrVx]zTT1O H4]o zΧg"ӒNHlUu߯9`^\&# ҶQOMfff tRNS pHYs  ~%tEXtSoftwareMacromedia Fireworks MX 2004vtEXtCreation Time10/03/04ǯ nIDATxc %@bcnb`2!M a(2A a , 0L2p .`01an1Йl 0&X>/q#IENDB`libzeep-3.0.2/doc/html/images/next_disabled.png0000664000175000017500000000212612162310454021300 0ustar maartenmaartenPNG  IHDREgAMA|Q cHRMz%u0`:oPLTE$x tRNSIDATxbf?LYLb 1c` T $7 @Pu_U AT.?a tRNS pHYs  ~%tEXtSoftwareMacromedia Fireworks MX 2004vtEXtCreation Time10/03/04ǯ XIDATxc @bؾ e20A;@`V0  @  P`2 "j.mHn@r{R1P~dlIENDB`libzeep-3.0.2/doc/html/images/up.png0000664000175000017500000000056212162310454017121 0ustar maartenmaartenPNG  IHDR~+sBITO*PLTEfffC@>QOM&# `^\=tRNSE pHYs  ~%tEXtSoftwareMacromedia Fireworks MX 2004vtEXtCreation Time10/03/04ǯ rIDATxα 0F'XQ\=,%N%_:GAE=9*{ jQܰ5mܣ1c^p_E"\IENDB`libzeep-3.0.2/doc/html/images/warning.png0000664000175000017500000000233112162310454020136 0ustar maartenmaartenPNG  IHDRשPLTE!)1BJRZks{{{RRZZ{{99JJ11))))))!!p;bKGDHIDATxm}o0M5%%m szP^UDKnk[;һ?0n!qCtEXtSoftware@(#)ImageMagick 4.2.8 99/08/01 cristy@mystic.es.dupont.com!*tEXtSignaturec42b7d2d564aab588891979703f02b45OߓtEXtPage24x24+0+0r[ 1IENDB`libzeep-3.0.2/doc/html/images/important.png0000664000175000017500000000132212162310454020505 0ustar maartenmaartenPNG  IHDRשPLTE)))999BB1ZZ)ccBBBRRRkkBccRssRccckkk{{{9!9Z{c{JRZck{!19)11!ZRsckBc{bKGDCg bIDATxm S0 3E1KPTF'ǮQ]_iKB&F(6rc/Ѵ\Nh* 2p=:Jv?6| @}`^>s PvBɨ@d6"o;g`Ps+s%ǯ%@S{4ܾU-s"1ч?j<`g eZ* +æ2_Yv*lv~g Z[sY[Ða; =/oJĘ!fclRmRCtEXtSoftware@(#)ImageMagick 4.2.8 99/08/01 cristy@mystic.es.dupont.com!*tEXtSignaturec3ecc1fc5135d1e959695e569d213122riIENDB`libzeep-3.0.2/doc/html/images/up_disabled.png0000664000175000017500000000213312162310454020744 0ustar maartenmaartenPNG  IHDREgAMA|Q cHRMz%u0`:oPLTE}DtRNSEIDATxberB;T B C8Ą L Ą" &T! @1@l@_*ƿ , Ay*Y &d Fps13P'#Baf` &L@@a XcG(0N.3@:IENDB`libzeep-3.0.2/doc/html/images/toc-plus.png0000664000175000017500000000041012162310454020233 0ustar maartenmaartenPNG  IHDR )bKGD#2#IDATxch`#@C"ԣj?RJld:4CtEXtSoftware@(#)ImageMagick 4.2.8 99/08/01 cristy@mystic.es.dupont.com!*tEXtSignatureab17802e1ddae3211b1ce6bc3b08aec7{( tEXtPage15x9+0+07vIENDB`libzeep-3.0.2/doc/html/images/toc-blank.png0000664000175000017500000000047612162310454020353 0ustar maartenmaartenPNG  IHDR kd0PLTEO&IbKGDHIDATxc?|` h BhCtEXtSoftware@(#)ImageMagick 4.2.8 99/08/01 cristy@mystic.es.dupont.com!*tEXtSignaturef7e388dabd4ef0097714b5643fdd3cfbb tEXtPage15x9+0+07vIENDB`libzeep-3.0.2/doc/html/images/blank.png0000664000175000017500000000056612162310454017570 0ustar maartenmaartenPNG  IHDRL\gAMA a-IDATxA 0MF4 z;3'kX` 5kX` 5kX` 5kX` 5kX` 5kX` 5kX` 5kX` 5kX` 5kX` 5kX` 5kX` 5kX` 5kX` 5kX` 5kX` `fHfIENDB`libzeep-3.0.2/doc/html/images/prev.png0000664000175000017500000000051612162310454017450 0ustar maartenmaartenPNG  IHDR~+sBITO$PLTEfff333QOM&# ҋC@>`^\ tRNS pHYs  ~%tEXtSoftwareMacromedia Fireworks MX 2004vtEXtCreation Time10/03/04ǯ VIDATxc ^ b0t`200A &H„ @AP 0` B@$dslCvːݻleSf IENDB`libzeep-3.0.2/doc/html/images/draft.png0000664000175000017500000004205612162310454017601 0ustar maartenmaartenPNG  IHDRKZJgAMA a IDATxv۸asV8 BLhp7v8<[ w`9*i$4`-B ! xb^8x5oTGa0 s;&!b;07kBC}b$xkeY?|os$x cx? /󇄎 {w:Rqpt5Ih'xH1' 桕R4EAB;[ ?Hhŏ1}ZBNBHQvC4)rB29턶n}|CCkׯzA= 4ew i}dx4! ZHNWUŸC4b/_a~9B[4l/C4l,+4l)rϟ? 4`3&+m-c 8z%*i@55 WO#xyy9NB7?6ϳ3cNhLkظwNH1&i֮.yB e=9i4M8mrv/ .@b,5ẻVwͬ [ xm=oD% k v R"e2ʽV}Bv=%~n4M0\.OǽKkm{_ބ4Dd桿 8Z9ɧGHhT4{C% μ$ʤ k4!OT,;NB rzAHCyiʲ,NӂZikòvV41} 7}JyeѳIބ4<蛄zӾgiBcB rzi:InL녙~~~.K܅JrWB+iO}%BH$ 3?UNpEz2?,fNnXk]%kg~J~ZK=q ibߛyq|ArBkyݗۉ#1' _Ьvmۮy*[OSIH]Vބ4|ޑZMrnxޣ$eQI w*~o*i{Oθ Rb44Њ.uYTiI_;[IptЩJph:szs {SI8.j#u=M% H44#b=촞p8>OQcN>4! (Hh4! XE4UU" igMӐ{T.r8$u7! eFI??MHHQӄ44;}NLl AvNr.}CӮ$t⬧ iIS 0 iS +Ŗӄ4DND~1)`nEGF% `Hh8ɸ7! `HhxCNvWOFM]bO1U4 i;&9MH ӄ4`O1l.XN?uB>/7" 'ZQI ]p2iB+B@Hhʜ*! B$49sVJ @\H5qaqvuY'"D^Cm[2!אr<6j޻@H^(;4M֕! ;O }N1%oEQ$! /5t4^oy^UUUUί kxI] kPCCi>jh l,zzve8l,iNXNpdrCI>Ӟv,QtkTvF,4-)7Ri546AHث09::! `O@BIرe~iHh(`iqoWHh܎JY? n&qx5]"i2<&ڜ&J4 \*Ih`pnmOXuҴiQIHֆ4 'i)dP8Ih8Ĝ4􅜟󜄆+T!غi8BQy_^^i8AH804\ڭm[Ƙ_~eY%<*iø7pD4vn5rqoĉJqc.˒zq"ڒ{#B wވ40H9(@\q}BN#6Iy}},K9P)4|f~Zko=B$ygYVU1>2D.UU繜 uӈ! lVJYkEQy^UQ ! lBf}A=mnIO\ 9 fNh6ƔeYEe06V&5km4YIaMZ@Nc4 0Ȫ-9+1pFx4^H]ueEQ( kiFHAu]d5cn вjš2WiCHLOITSX;AN# Ba^ XReiY~Qʲmim\nFX8'Cx ! ?niaij^зl ~`~ ooo}?|.Zoa-cw2r"}ߟ1MTUKw] eY>???<8>|^sI=:"y◗5t:ep5,!MF<2i|BCW*RN| D6p/̩_.%w}Ж ._{,\54+*i`38,w&M4ϳXKsߺ,ˤ2:~42HY /diIS׵?U|Ǹ7 / wÕׇ0 r:( 9b+{9CVm+qoWGлC% lm.J)kP0RU/M?Id2i|_Q&$^u~LY]}\duuGa.ޖ-#kss:Haؒ fY2eqs>)y9i/B/7v\}Y[Zske75~QIbuu<[zE% kו;eZQL/b,˺i^-g2ĆeuefY_zW\Z*Q9:YU|c,x¶i j0qW>YKڐ^Xk*7&v)a|Vi vooo]׭Hi}$tQ߷6m4@6,M=;i[%!?69Lؒ F\݃WBN0"9[vG|e ޘ׿_k}:qC#J+Y$@1MӬÚwބPR:+䈎(Xup|ݼWOhHw,G꺮JEvEeMӐP4{uXZ맧`FRCOi.ZNHhB؇y7^u4Mߎ%>KpuCX>Hm:Z(W jmBvc?\IXIӄ&CRX')5{"FT D J,dۉ 4'8_u:8W7&ߑC$e w>NBSUrYsIy F Ry˪ye m$4GH{bq}E0ӫߑC$1KgmHhv/UNo/wxRXB(FԲglGDvZ+GnqZ7_j5mB/Aļ=$J|/ҟ_qW'KetߓEUUOOOө,[އe_n?YF:Y!ӏE#YT-U80 ZIiMI-O>FBe,VJɦfHh܋Jثmjyzz7I[,v,M0PId-BT{wx7ZήUUI}aOi`e)˲;Km+ʷf^6տ#_ WZN1t})VE 6?`ߜ:uݏӮMӐ^W@ve~L~Hh`I#"Z;ϳA$[k-7Z~SwA~X%ҁ.~DHcKKO$t(%9 u5gyJ]EHS}󼪪wNBb4!Nx,zZJjJ8///+w϶u]4A6yXZbpyaMdeZk<ш/&QI#NBk[2x{zǗ?ڲ,1$4B!H+} IDAT)gWUroleOOOr5! $۶dLZ7M|___y}! neOz\&On{'Xk-ےDBk\X`CZ9XW grʯʲl[AbI/^ dOx4ܓ}߯_RWU^N֣cڶm{Gz˧iJ/?1UU$4??pF^__o;/&:^1_x~Ϝ|>;y~}anZeYYeYfY˘Ll;Udw ]j^z_ 1{RC;OOtrʲӠ4r0r䆓K:~DH?xSt:UUUsG7H1d~&W#GH|Z_~eiwG^I74دb4ׯ_n_ZuݮZ+/%_i(a[w>Na 菤vR:}c_J>Ӏo4܏rp]ۮYʲiL68yOd8n|>:5tMlA%v]LN.u\8u!}hkh <#YD++!士m -IM8-/j.(<0b!9Oh+#eY:ajSJMӔD+)4gB L'ڊ8[N])EH?sJeYd`VN\mYk˲trҀ'>UIb_qX;HfsuoD++:HW\'믣 SxO 'J)cL{Vǜm @ABbᔢ*'kpn7OX<^8g 4v ';y1 dkmBv56}2 ]>gq#u]hTeۦQ8Ԟb7r2-f&dY䳋r0 8ק-磆|OWiN)pyu)9ŧ1feNf&)ZّɥdKPtzHZms5<0 Cu@҉!o&bYm[.r+a:Ȁ|A۶m:` -e3R}1( WEc-FʏЏY?~òI۠}O7𰔟ȩ:$+^q-Y00 I$ckmoѢ,KWcfsGy褁QoZWUu( WiX3 <&GsJH5iZ3!mͲ,h0Ƹ:rAo1?@B1MW# #gapr)P@'^celM%W}azGΙ3z^IkuʾnccwZm!Ůicqu?;"3? @1 (O=b{LEa(i|>; &4M0,u km4+{:z_v aGB]Gk&_cpzdQTχFuyElB;Y##Nni첫Oi^Ek4,vrc@9٘b|JEʮ->N:KFe$܈'іڶu:T4־RCZ+.u\ \~q9r#e)> t]v=5kr䟉<_c㑔<ҒZ+gr?Y/j1Ŷ,`wOx ! yyoc$,˲,`VJ}/,9돟$3[)@~1j[ίw;tx؃#WXZ;r߫|tUU5M#ߗeQE~$R巌'ǜ?5nq:RFHo)LNDnZ)U8-ijDKGr|!=G>X-㸮kלNoyB+ny]cO R1Y ޞmz=x qo e`|c?*/Slӷ;TBtwPz<5cRd a7Iΰ10 {r3YFŗs/g2(cEHG9MBozT\)u]dE"ٲH!c8wI,EtJOX˒ǻ]0\ BzӌrGNe܅2އ4 fFAx72Xk0 LBGNvA!`$7IhY<ϳ ^G-[Rt/+jh` $9[!Q2jD냗%654!?^nIbUJxdm9Rb&In q }u{iߣܲ+u]\JmّIJ):i!c{?/_B*޲,<@E$s< )܃s}oNK,˪zm0 {A !yw]z`M.RHw$2-[@lYON\f^^>@o>\`&jۂ&H 崵r(О,TȾ^ߵ"E%izf.NB1#SmNБ%]| bFH'n>2:N׭ga$4-B:}iz"܋;4/pYQ󙄎$?*VOkHB8&*VO;GB8,B@[$4##e_9MB88Bp$4GNÊ9Ihqř$4,C-IhFHݒrwBB;f$뺖7ABGl  oHhIh ! ??MB7rPNo2,}1&sB%Zi71Z,c1J)1F#'ظ4M:ܓqgcLu4 _U˯G]-\Eey/ն/m,*GX%8ھiZf)oRUei[aeiek$8JNoEQcZFɽnk)m CYyWUaxuYmO@i {{{KcH@VZ8 C4A7if8}솱8e GRaƽӉqo㐖sXӆ֧)zim>=0wv7Miǰn+Ƙii~D!=MS۶;3u4z{Qi^^^PsUUeYn}/J\?-eL[k1,3?@"}œHx++qIږI7<,G0 oooZbXV-kS-_ȟ9V7joez=.˲TeYJdYfonQe<8>hHtuu 0 Ȝ=H`|\<BZݵFf9LZe5)7**ߓm}_9xʓЛXa|&r>?&@=͸7} *RV{xezЛ.Z|1rq<^!Б,|l>M|'*JY<n6B1? Iu/Ga}lA8g[Et:i}10 yA&z:׷6MmAw D4Fg{QEYiʲdVxxcHhW꺞贜aby&l{yNO4M1&Ao:eAZ-'R8=b8SsK" ž4HN8!CMGd~QnI䯗Jk-oyv<4bi&,3s454iӓeYQny.bZݐb!w]iGx44M>˲TQr{`]?}dőLodYFB .E91( Wnr5/@NSUo^bkؓ>,Noǎz`_=7 vZ,7;?8;a #!놝\JL;._plJ|d)לz:Czz2}%X|7/7 繓B,yDkm[ n=$iZyd-={8SO-scꖐVө+ɑ4Mn}4G0Io<K Q?өיboN1&˲EvgipHr:=ڢ(VNK*,Ů&#er:1ZkcNn  iźeY npNeDN^_ЪiHƽAJphCNJ-LiX%|!T,e iEN1|g![29g뻻i"wZ+ \%XVG[+Ka-/!؏lֿ$48+ ipcH+]Ӡ׼Nf !#k3B\Ҋ W^7\ *TN'8w BZ#\.qDVEL޽ʸw\}Y(9͸iy$ޑYJ.9f{ǣZ-g{ߛy@;][|{ߛƘ_ťސ$7Gk]%!q}C!-hq|JNhTQv"Ry WH+r:q۶]cLUU(V8^.'b1'ƐVO|IR*ZxZkmuN6뚖1'ސVZ,SRF??aiʳ4EQuROҊvm[W eY]l ^ 90 08Y-icҊ^g]utka6|s~պsuihҊ~ۄ.˒0vҊr9Ϯzz#IDAT. "o6RUUS7ːV weY^CZN$4l"VaBkhB6NHN1yQ/[I*!s({\4 J-rzm&VpuM iuz&5t:4CZ =r+b?.epV"i,^CZn6XNK說؝~H+9--rwB rVI䴿h$8>29qi}dkh"tJZ촞&j9MBa.ծr#;֜秗'ޘ `XIiOO*!"iF݋ƽCW"z,ii<Üj~Z"|&RCw4004_YYk|לw^k$4$לv8}dnBgiCH$& IiREH!œ& a}iFH-& y#6i~І9MBAҏ$Ih8Bz9MBk,Ih8Bځ9]eUU$4 `9,FTOpXKs##st9i:+s(BڟsBڣr,iipƜ&!$4#B:orZ:!Χ9$:-bFH.Ih7Ж&m?`uIENDB`libzeep-3.0.2/doc/html/images/prev_disabled.png0000664000175000017500000000212512162310454021275 0ustar maartenmaartenPNG  IHDREgAMA|Q cHRMz%u0`:oPLTE1nU tRNSIDATxbflP@1| &w @1B !7 XbĄ)@,P!?̿B. C 01 ;D%3L7@0@Y-`ίpftA & H@a4@ e aB 8$-C6IENDB`libzeep-3.0.2/doc/html/images/toc-minus.png0000664000175000017500000000040312162310454020405 0ustar maartenmaartenPNG  IHDR )bKGD#2IDATxch`g  I׏j?}-pZECtEXtSoftware@(#)ImageMagick 4.2.8 99/08/01 cristy@mystic.es.dupont.com!*tEXtSignatureecf413ef47524404f90c44d8c7d12a2e݈ tEXtPage15x9+0+07vIENDB`libzeep-3.0.2/doc/html/images/smiley.png0000664000175000017500000000154312162310454017777 0ustar maartenmaartenPNG  IHDR&GsBITOPLTEutpQVR;ڗDB8~|x1-'dNJfdNcaYr<92YQM8f%!XULؖusknjKki_DA/IF>y^a^I𦸷ϏifHTP>nskk30$\YKZWC¾ܙfˍplMa~vzvVfffLI5GC:dbSieQ\YQKIBZ@<3RRBhfffa^Va^CpmOw}by|yUp[tRNSXl"T pHYs  ~tEXtCreation Time10/12/04Bs%tEXtSoftwareMacromedia Fireworks MX 2004v/IDATxm}W0oKID)X b`I8v8N֩i,|`w; ? M <_Ce ʸU}Ě䪖('(o^U] pM/\(a~^,W}6rA j1T@Ftk+}PW" M 7qDbS9 1:zUb7V*J k߃+:Rwg$_9p^$B U秽ff{y/Wvg؞Գ姹X#MXyjM^"Þ/i]0pIIENDB`libzeep-3.0.2/doc/html/index/0000755000175000017500000000000012162310454015624 5ustar maartenmaartenlibzeep-3.0.2/doc/html/index/s05.html0000664000175000017500000014510312162310454017127 0ustar maartenmaarten Reference

PrevUpHomeNext

Reference

namespace zeep {
  class envelope;
  xml::element * make_envelope(xml::element *);
  xml::element * make_fault(const std::string &);
  xml::element * make_fault(const std::exception &);
}
namespace zeep {
  namespace http {
    class connection;
  }
}
namespace zeep {
  namespace http {
    struct header;
  }
}
namespace zeep {
  namespace http {
    class preforked_server_base;
    template<typename Server> class preforked_server;
  }
}
namespace zeep {
  namespace http {
    class reply;

    // Various predefined HTTP status codes. 
    enum status_type { cont =                   100, 
                       ok =                     200, 
                       created =                201, 
                       accepted =               202, 
                       no_content =             204, 
                       multiple_choices =       300, 
                       moved_permanently =      301, 
                       moved_temporarily =      302, 
                       not_modified =           304, 
                       bad_request =            400, 
                       unauthorized =           401, 
                       forbidden =              403, 
                       not_found =              404, 
                       internal_server_error =  500, 
                       not_implemented =        501, 
                       bad_gateway =            502, 
                       service_unavailable =    503 };
  }
}
namespace zeep {
  namespace http {
    struct request;
  }
}
namespace zeep {
  namespace http {
    class request_handler;
  }
}
namespace zeep {
  namespace http {
    class request_parser;
  }
}
namespace zeep {
  namespace http {
    struct unauthorized_exception;

    class parameter_value;
    class parameter_map;
    class webapp;
    template<> std::string parameter_value::as<std::string >();
    namespace el {
    }
  }
}
namespace zeep {
  namespace http {
    namespace el {
      class object;
      class scope;
      bool process_el(const scope &, std::string &);
      void evaluate_el(const scope &, const std::string &, object &);
      bool evaluate_el(const scope &, const std::string &);

      // for debugging purposes 
      std::ostream & operator<<(std::ostream & lhs, const scope & rhs);
    }
  }
}
namespace zeep {
  class server;
}
namespace zeep {
  namespace http {
    class server;
    std::string decode_url(const std::string &);
    std::string encode_url(const std::string &);
  }
}
namespace zeep {
  namespace xml {
    namespace doctype {
      class validator;

      struct allowed_base;
      struct allowed_any;
      struct allowed_empty;
      struct allowed_element;
      struct allowed_repeated;
      struct allowed_seq;
      struct allowed_choice;

      class attribute;
      class element;
      class entity;
      class general_entity;
      class parameter_entity;

      enum AttributeType { attTypeString, attTypeTokenizedID, 
                           attTypeTokenizedIDREF, attTypeTokenizedIDREFS, 
                           attTypeTokenizedENTITY, attTypeTokenizedENTITIES, 
                           attTypeTokenizedNMTOKEN, attTypeTokenizedNMTOKENS, 
                           attTypeNotation, attTypeEnumerated };

      enum AttributeDefault { attDefNone, attDefRequired, attDefImplied, 
                              attDefFixed, attDefDefault };

      typedef std::vector< entity * > entity_list;
      typedef std::vector< element * > element_list;
      typedef std::vector< attribute * > attribute_list;
      typedef allowed_base * allowed_ptr;
      typedef std::list< allowed_ptr > allowed_list;
      typedef state_base * state_ptr;
      std::ostream & operator<<(std::ostream & lhs, validator & rhs);
    }
  }
}
namespace zeep {
  namespace xml {
    class document;

    // Using operator>> is an alternative for calling rhs.read(lhs);. 
    std::istream & operator>>(std::istream & lhs, document & rhs);

    // Using operator<< is an alternative for calling writer w(lhs); rhs.write(w);. 
    std::ostream & operator<<(std::ostream & lhs, const document & rhs);

    // To read a document and process elements on the go, use this streaming input function. If the proc callback retuns false, processing is terminated. The doc_root parameter of the callback is the leading xml up to the first element. 
    void process_document_elements(std::istream & data, 
                                   const std::string & element_xpath, 
                                   boost::function< bool(node *doc_root, element *e)> cb);
  }
}
namespace zeep {
  namespace xml {
    class node;
    class container;
    class root_node;
    class comment;
    class processing_instruction;
    class text;
    class cdata;
    class attribute;
    class name_space;
    class element;

    typedef node * node_ptr;
    typedef std::list< node_ptr > node_set;
    typedef element * element_ptr;
    typedef std::list< element_ptr > element_set;
    typedef std::list< attribute * > attribute_set;
    typedef std::list< name_space * > name_space_list;

    // This is probably only useful for debugging purposes. 
    std::ostream & operator<<(std::ostream & lhs, const node & rhs);
    bool operator==(const node & lhs, const node & rhs);
  }
}
namespace zeep {
  namespace xml {
    class invalid_exception;
    class not_wf_exception;
    class parser;
  }
}

SOAP_XML_SET_STRUCT_NAME(s)
SOAP_XML_ADD_ENUM(e, v)
namespace zeep {
  namespace xml {
    struct serializer;
    struct deserializer;
    struct wsdl_creator;
  }
}
namespace zeep {
  namespace xml {

    // the supported encodings. Perhaps we should extend this list a bit? 
    enum encoding_type { enc_UTF8, enc_UTF16BE, enc_UTF16LE, enc_ISO88591 };
    typedef boost::uint32_t unicode;

    // some character classification routines 
    bool is_name_start_char(unicode uc);
    bool is_name_char(unicode uc);
    bool is_char(unicode uc);
    bool is_valid_system_literal_char(unicode uc);
    bool is_valid_system_literal(const std::string & s);
    bool is_valid_public_id_char(unicode uc);
    bool is_valid_public_id(const std::string & s);

    // Convert a string from UCS4 to UTF-8. 
    std::string wstring_to_string(const std::wstring & s);

    // manipulate UTF-8 encoded strings 
    void append(std::string & s, unicode ch);
    unicode pop_last_char(std::string & s);
  }
}
namespace zeep {
  namespace xml {
    class writer;
  }
}
namespace zeep {
  namespace xml {
    class context;
    class xpath;
  }
}

PrevUpHomeNext
libzeep-3.0.2/doc/html/libzeep-doc_HTML.manifest0000664000175000017500000000445612162310454021301 0ustar maartenmaartenindex.html libzeep/intro.html libzeep/soap.html libzeep/webapp.html index/s05.html SOAP_XML_HAS_EXPAT_SUPPORT.html SOAP_SERVER_HAS_PREFORK.html zeep/dispatcher.html zeep/envelope.html zeep/make_envelope.html zeep/make_fault_idm38432.html zeep/make_fault_idp7490464.html zeep/exception.html zeep/http/connection.html zeep/http/header.html zeep/http/preforked_server_base.html zeep/http/preforked_server_base/server_constructor_void_idp7516208.html zeep/http/preforked_server_base/server_constructor_void_idp7519520.html zeep/http/preforked_server_base/server_constructor_void_idp7524880.html zeep/http/preforked_server_base/server_constructor_void_idp7531776.html zeep/http/preforked_server.html zeep/http/reply.html zeep/http/request.html zeep/http/request_handler.html zeep/http/request_parser.html zeep/http/unauthorized_exception.html zeep/http/parameter_value.html zeep/http/parameter_map.html zeep/http/webapp.html zeep/http/el/object.html zeep/http/el/object/basic_iterator.html zeep/http/el/scope.html zeep/http/el/process_el.html zeep/http/el/evaluate_el_idp7904352.html zeep/http/el/evaluate_el_idp7911648.html zeep/server.html zeep/http/server.html zeep/http/decode_url.html zeep/http/encode_url.html zeep/xml/doctype/validator.html zeep/xml/doctype/allowed_base.html zeep/xml/doctype/allowed_any.html zeep/xml/doctype/allowed_empty.html zeep/xml/doctype/allowed_element.html zeep/xml/doctype/allowed_repeated.html zeep/xml/doctype/allowed_seq.html zeep/xml/doctype/allowed_choice.html zeep/xml/doctype/attribute.html zeep/xml/doctype/element.html zeep/xml/doctype/entity.html zeep/xml/doctype/general_entity.html zeep/xml/doctype/parameter_entity.html zeep/xml/document.html zeep/xml/node.html zeep/xml/container.html zeep/xml/container/basic_iterator.html zeep/xml/root_node.html zeep/xml/comment.html zeep/xml/processing_instruction.html zeep/xml/text.html zeep/xml/cdata.html zeep/xml/attribute.html zeep/xml/name_space.html zeep/xml/element.html zeep/xml/element/attribute_iterator.html zeep/xml/element/const_attribute_iterator.html zeep/xml/invalid_exception.html zeep/xml/not_wf_exception.html zeep/xml/parser.html zeep/xml/serializer.html zeep/xml/deserializer.html zeep/xml/wsdl_creator.html SOAP_XML_SET_STRUCT_NAME.html SOAP_XML_ADD_ENUM.html zeep/xml/unicode.html zeep/xml/writer.html zeep/xml/context.html zeep/xml/xpath.html libzeep-3.0.2/doc/html/SOAP_SERVER_HAS_PREFORK.html0000664000175000017500000000644412162310454021130 0ustar maartenmaarten Macro SOAP_SERVER_HAS_PREFORK

PrevUpHomeNext

Macro SOAP_SERVER_HAS_PREFORK

SOAP_SERVER_HAS_PREFORK

Synopsis

// In header: </home/maarten/projects/libzeep/zeep/config.hpp>

SOAP_SERVER_HAS_PREFORK

Description

The http server implementation in libzeep can use a preforked mode. That means the main process listens to a network port and passes the socket to a client process for doing the actual handling. The advantages for a setup like this is that if the client fails, the server can detect this and restart the client thereby guaranteeing a better uptime.


PrevUpHomeNext
libzeep-3.0.2/doc/libzeep.30000664000175000017500000001041311751706104015274 0ustar maartenmaarten.TH libzeep 3 "12-jan-2009" "version 2.9" "subroutine" .SH NAME libzeep \- A C++ library for XML parsing, XPath, SOAP servers and web apps .SH SYNOPSIS .B #include .sp class my_server : public zeep::server .br { .br public: .br my_server(const char* addr, short port); .br void sum(int a, int b, int& c) { c = a + b; } .br }; .sp my_server::my_server(const char* addr, short port) .br : zeep::server("http//www.acme.org/...", addr, port) .br { .br const char kSumParameterNames[] = { "a", "b", "c" }; .br register_action("sum", this, &my_server::sum, kSumParameterNames); .br } .sp ... .sp int main() .br { .br my_server server("0.0.0.0", 10333); .br boost::thread t(boost::bind(&my_server::run, &server)); .br // and wait for a signal to stop using e.g. sigwait(3) .br ... .br } .sp .SH NOTE See HTML pages for more up-to-date documentation. E.g. at http://www.cmbi.ru.nl/libzeep/doc .SH DESCRIPTION Using libzeep you can create a SOAP server by deriving from .BR "zeep::server" . In the constructor of your server, you call the base class constructor with three arguments: .IR "ns" , a namespace for your SOAP server, .IR "address" , the address to listen to, usually "0.0.0.0" to listen to all available addresses. And .IR "port" , the port number to bind to. .sp SOAP actions are simply members of the server object and are registered using the .BI register_action member function of the .BI zeep::server base class. After initializing the server object, the .BI run member is called and the server then starts listening to the address and port specified. .sp The resulting web service application will process incoming request. There are three kinds of requests, the server can return an automatically generated .IR "WSDL" , it can process standard .I SOAP message send in .I SOAP envelopes and it can handle .I REST style requests which are mapped to corresponding .I SOAP messages internally. .sp The signature of the registered actions are used to generate all the code needed to serialize and deserialize .I SOAP envelopes and to create a corresponding .I WSDL file. The signature can be as simple as the example above but can also be as complex as in this one: .sp .BI " void myAction(" .br .BI " const std::vector& " input "," .br .BI " MyStructOut& " output "); " .sp In order to make this work, you have to notify the library of the mapping of your structure type to a name using the macro .B SOAP_XML_SET_STRUCT_NAME like this: .sp .BI " SOAP_XML_SET_STRUCT_NAME(MyStructIn); .br .BI " SOAP_XML_SET_STRUCT_NAME(MyStructOut); .sp Next to this, you have to provide a way to serialize and deserialize your structure. For this, libzeep uses the same mechanism as the .I Boost::serialize library, which means you have to add a templated member function called .B serialize to your structure. The result will look like this: .sp struct MyStructIn { .br string myField1; .br int myField2; .sp template .br void serialize(Archive& ar, const unsigned int version) .br { .br ar & BOOST_SERIALIZATION_NVP(myField1) .br & BOOST_SERIALIZATION_NVP(myField2); .br } .br }; .sp Similarly you can use enum's in an action signature or as structure member variables. Again we need to tell the library the type name for the enum and the possible enum values. We do this using the .B SOAP_XML_ADD_ENUM macro, like this: .sp enum MyEnum { "one", "two" }; .br SOAP_XML_ADD_ENUM(myEnum, one); SOAP_XML_ADD_ENUM(myEnum, two); .sp As shown above, you can also use std::vector containers in the signature of actions. Support for other STL containers is not implemented yet. .sp If the address used by clients of your server is different from the address of your local machine (which can happen if you're behind a reverse proxy e.g.) you can specify the location using the .B set_location member function of zeep::server. The specified address will then be used in the .I WSDL file. .sp .SH BUGS This documentation is seriously out of date. Look at the HTML version for more up-to-date documentation, you can find it at /usr/share/doc/libzeep-dev/html or at http://www.cmbi.ru.nl/libzeep/ Undoubtedly libzeep will contain bugs. One of the more obvious one is the missing support for signatures using STL containers other than std::vector. libzeep-3.0.2/doc/libzeep-doc.qbk0000664000175000017500000006127412124306024016455 0ustar maartenmaarten[article libzeep [quickbook 1.5] [version 3.0] [copyright 2012 Maarten L. Hekkelman] [license Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at [@http://www.boost.org/LICENSE_1_0.txt]) ] [authors [Hekkelman, Maarten L.]] ] [def __node__ [classref zeep::xml::node `zeep::xml::node`]] [def __element__ [classref zeep::xml::element `zeep::xml::element`]] [def __attribute__ [classref zeep::xml::attribute `zeep::xml::attribute`]] [def __container__ [classref zeep::xml::container `zeep::xml::container`]] [def __document__ [classref zeep::xml::document `zeep::xml::document`]] [def __serializer__ [classref zeep::xml::serializer `zeep::xml::serializer`]] [def __deserializer__ [classref zeep::xml::deserializer `zeep::xml::deserializer`]] [def __http_server__ [classref zeep::http::server `zeep::http::server`]] [def __http_request__ [classref zeep::http::request `zeep::http::request`]] [def __http_reply__ [classref zeep::http::reply `zeep::http::reply`]] [def __soap_server__ [classref zeep::server `zeep::server`]] [def __webapp__ [classref zeep::http::webapp `zeep::http::webapp`]] [def __add_processor__ [memberref zeep::http::webapp::add_processor `zeep::http::webapp::add_processor`]] [def __el_scope__ [classref zeep::http::el::scope `zeep::http::el::scope`]] [def __el_object__ [classref zeep::http::el::object `zeep::http::el::object`]] [section:overview Overview] Libzeep is packaged as one library, but actually contains two different libraries. The first part of libzeep consists of code to read, manipulate and write XML. It contains a validating XML parser, an XPath implementation to query a DOM tree, code to serialize objects into and out of XML and finally it contains an XML writing module. The second part of libzeep is targeted to writing SOAP and REST servers as well as full web applications using C++. There is a simple HTTP server implementation, code to create SOAP (and REST) servers out of existing C++ objects and there is code to create complete web applications that work a bit like popular Java web application frameworks. The libzeep web application framework turns page templates consisting of XHTML with custom tags and a custom script language into HTML. [endsect] [section:intro Introduction] [section:xml XML Parser] Libzeep comes with a validating XML parser. Using this parser is as simple as writing: #include #include int main() { std::ifstream file("test.xml"); __document__ doc(file); ... } This will parse the file =text.xml= and create an object `doc` containing the DOM tree. To traverse this tree you can use the various member functions of doc which derives from the generic __container__ class. Siblings in the DOM tree are stored as linked lists and some elements can have children. To make life easier, you can iterate over elements using STL iterators. Suppose our =test.xml= file contains the following XML:[teletype] John Doe Jane Jones You could print out the file like this:[c++] // a document contains at most one child node __element__* persons = doc.child(); // begin/end will return iterators to elements for (__container__::iterator person = persons->begin(); person != persons->end(); ++person) { for (__container__::iterator name = (*person)->begin(); name != (*person)->end(); ++name) std::cout << (*name)->name() << " = " << (*name)->content() << std::endl; } Of course, using the new for loop construct, this code would be much more readable: for (auto person : *persons) { for (auto name : *person) std::cout << name->name() << " = " << name->content() << std::endl; } But if your compiler does not support that syntax, you can always use `boost::range` instead: BOOST_FOREACH (__element__* person, *persons) { BOOST_FOREACH (__element__* name, *person) std::cout << name->name() << " = " << name->content() << std::endl; } Accessing attributes is done using the member function `element::get_attribute()`. [endsect] [section:xml_serialization XML Serialization] An alternative way to read/write XML files is using serialization. To do this, we first construct a structure called Person. We add a templated function to this struct just like in `boost::serialize` and then we can read the file. #include #include #include #include struct Person { std::string firstname; std::string lastname; template void serialize(Archive& ar, const unsigned int version) { ar & BOOST_SERIALIZATION_NVP(firstname) & BOOST_SERIALIZATION_NVP(lastname); } }; int main() { std::ifstream file("test.xml"); __document__ doc(file); __deserializer__ ds(doc.child()); std::vector person; // the variable name person must be the same as the name of the XML element person ds & BOOST_SERIALIZATION_NVP(person); // alternative is to use which allows another variable name: // ds & boost::serialization::make_nvp("person", person); } Since libzeep 3.0 we can reduce the code required. int main() { std::ifstream file("test.xml"); __document__ doc(file); std::vector persons; // New way of deserializing persons doc.deserialize("persons", persons); } And to write out the persons, we do something similar. __document__ doc; doc.serialize("persons", persons); std::ofstream file("test-out.xml"); file << doc; To find out more about serialization, look at the reference for __serializer__ [endsect] [section:xpath XPath 1.0] Libzeep comes with a [@http://www.w3.org/TR/xpath/ XPath 1.0] implementation. You can use this to locate elements in a DOM tree easily. For a complete description of the XPath specification you should read the documentation at e.g. [@http://www.w3.org/TR/xpath/] or [@http://www.w3schools.com/xpath/default.asp]. The way it works in libzeep is that you can call `find()` on an __element__ object and it will return a zeep::xml::element_set object which is actually a `std::list` of __element__ pointers of the elements that conform to the specification in XPath passed as parameter to `find()`. An alternative method `find_first()` can be used to return only the first element. An example where we look for the first person in our test file with the lastname Jones: __element__* jones = doc.child()->find_first("//person[lastname='Jones']"); [endsect] [section:http HTTP Server] Creating a HTTP server with libzeep is as simple as: #include class my_server : public __http_server__ { virtual void handle_request(const __http_request__& req, __http_reply__& rep) { ... // do something useful } }; int main() { my_server server; server.bind("0.0.0.0", 80); server.run(1); } Of course you will have to fill in the `handle_request` part... [endsect] [section:soap SOAP Server] Setting up a SOAP server is very easy. Let's continue with our test file and serve it as a SOAP/REST server. We already created the Person struct. The most simple server we can create is one that lists all persons in the test file: #include #include using namespace std; ... // define the Person struct as above class my_server : public __soap_server__ { public: my_server(); // The method we want to export void ListPersons(vector& result); }; void my_server::ListPersons(vector& result) { std::ifstream file("test.xml"); __document__ doc(file); __deserializer__ ds(doc.child()); ds & boost::serialization::make_nvp("person", result); } my_server::my_server() : __soap_server__("http://www.example.org/soaptest", "soaptest") { // assign a name to the Person struct (will appear in the WSDL e.g.) zeep::xml::serialize_struct::set_struct_name("person"); // assign names to the parameters of the exported method, in this case there's only // one return value to name const char* kListPersonsParameterNames[] = { "response" }; register_action("ListPersons", this, &my_server::ListPersons, kListPersonsParameterNames); } int main() { my_server server; server.bind("192.168.0.1", 8083); server.run(1); // keep our server single threaded } After building this server and running it, you can access the REST version of this routine at [@http://192.168.0.1:8083/rest/ListPersons] and there's a WSDL at [@http://192.168.0.1:8083/wsdl] [endsect] [endsect] [section:soap Creating a SOAP and REST server] [section:intro Introduction] SOAP and REST are two ways to export functionality over the web. Both have their strongness and weakness. SOAP enforces a strict type checking on input and output parameters. It works with a formal description file called WSDL that specifies all the exposed functionality and how to invoke this. Many tools exist that can read WSDL files and create client code that uses the exposed functions. REST on the other hand, is much easier to use ad hoc. It passes the arguments to the invoked functions in the URL and uses standard GET, POST and PUT methods of the HTTP protocol. libzeep is mainly focussed to using SOAP, but allows to access the exported functionality in a REST like way. Not all functions can be accessed this way, if the input parameters are some complex type, you're out of luck. This documentation will focus on SOAP, but if the function is simple, you can test it using REST from a browser. [endsect] [section:basics A real world example] Creating a SOAP server using libzeep is very easy. The bulk of the work is done by libzeep, you only have to specify what methods to expose and optionally what datatypes. To demonstrate this, we will create a simple SOAP server that allows the client to search for documents in a databank. Lets start with the initial code, the declaration of our server object. #include using namespace std; class MyServer : public __soap_server__ { public: struct MyHit { long id; float score; string title; template void serialize(Archive& ar, const unsigned int version) { ar & BOOST_SERIALIZATION_NVP(id) & BOOST_SERIALIZATION_NVP(score) & BOOST_SERIALIZATION_NVP(title); } }; enum MyAlgorithm { algVector, algDice, algJaccard }; MyServer(); void CountDocuments(long& outCount); void GetDocument(long inID, string& outDocument); void FindDocument(const vector& inTerms, MyAlgorithm inAlgorithm, vector& outResponse); }; Nothing special so far. Apart from inheriting from __soap_server__, this code could have been code you already had lying around. The addition of the `serialize` method to `MyHit` may also have been new to the code. The implementation of the actual server methods are also straightforward: void MyServer::CountDocuments(long& outCount) { long count = 1; // real code should return something more sensible of course outCount = count; } void MyServer::GetDocument(long inID, string& outDocument) { if (inID == 1) outDocument = "The first document!"; else throw zeep::exception("document %ld not found", inID); } void MyServer::FindDocument(const vector& inTerms, MyAlgorithm inAlgorithm, vector& outResponse) { if (inTerms.size() == 1 and inAlgorithm == algVector) { MyHit hit = { 1, 1.0f, "The first hit" }; outResponse.push_back(hit); } } Not very useful code, but it gives you an idea how simple it is to create a server. You don't have to do anything special, it's still code you could have written for some other purpose. Note that the GetDocument method throws an exception. The result in a SOAP server will be a SOAP Fault being returned containing the text 'document x not found'. Unfortunately, this is not all that needs to be done, we still have to tell libzeep what methods and what datatypes to expose. That's what we do in the constructor for `MyServer`. MyServer::MyServer() : __soap_server__("http://www.example.org/MyServer", "searchMyServer") { // first export the data types, start with MyHit zeep::xml::serialize_struct::set_struct_name("hit"); // and then the MyAlgorithm enum zeep::xml::enum_map::instance("algorithm").add_enum() ("vector", algVector) ("dice", algDice) ("jaccard", algJaccard); // Now export the methods, start with CountDocuments const char* kCountDocumentsParamNames[] = { "response" }; register_action("CountDocuments", this, &MyServer::CountDocuments, kCountDocumentsParamNames); // then GetDocument const char* kGetDocumentParamNames[] = { "id", "response" }; register_action("GetDocument", this, &MyServer::GetDocument, kGetDocumentParamNames); const char* kFindDocumentParamNames[] = { "terms", "algorithm", "response" }; register_action("FindDocument", this, &MyServer::FindDocument, kFindDocumentParamNames); } We start the constructor by calling the constructor of our base class, __soap_server__. We then continue by exporting the data types. Our MyHit datatype is exported under the name 'hit' and MyAlgorithm is exported as 'algorithm'. The various values of MyAlgorithm are exported under a new name as well. After exporting the datatypes, we export the methods. We do this by calling `register_action` specifying the parameters for the exported method name, the callback to make and the names for the parameters. And that's all. All that's left is to write a `main`. int main() { MyServer server; server.bind("0.0.0.0", 80); server.run(1); } And that will run our code in a single threaded server. If you run this code on your local machine you can test the REST versions of the code by visiting the following URL's with a web browser: [@http://localhost/rest/CountDocuments] Will return a SOAP envelope containing *1* in a response element [@http://localhost/rest/GetDocument/id/1] [@http://localhost/rest/GetDocument/id/2] Will return a SOAP Fault [@http://localhost/rest/FindDocument/terms/bla/algorithm/vector] [endsect] [endsect] [section:webapp Creating a Web Application] [section:intro Introduction] This section will guide you through all the code you have to write to create an interactive web application using libzeep. The way this works in libzeep looks a lot like popular frameworks found for Java. If you're familiar with JSP and e.g. Struts, you'll notice the similarities. [endsect] [section:basics The building blocks] It is very inconvenient to write HTML code in C++ directly using string concatenations and streams. Therefore, a separation has been made. All HTML is put into XHTML template files. These template files can use special tags to generate HTML tags based on data provided by the server application. A script language that looks a lot like JSP 'Expression Language' (or =el= in short) is used to program conditional constructs. Communication between this =el= script and the server application is done via =el::object= data objects. [endsect] [section:hello Hello world!] Let's start with a simple hello world example. We first create a template file, save this file as =hello.xhtml=.[teletype] Hello

Hello, world!

This is a very simple, strict XHTML 1.1 file. We will serve it with our server:[c++] #include #include using namespace std; class MyWebApp : public __webapp__ { public: MyWebApp(); void handle_welcome(const __http_request__& request, const __el_scope__& scope, __http_reply__& reply); }; MyWebApp::MyWebApp() { mount("", boost::bind(&MyWebApp::handle_welcome, this, _1, _2, _3)); } void MyWebApp::handle_welcome(const __http_request__& request, const __el_scope__& scope, __http_reply__& reply) { create_reply_from_template("hello.xhtml", scope, reply); } int main() { MyWebApp server; server.bind("0.0.0.0", 80); server.run(1); } By calling `mount` with the empty string, we tell libzeep to redirect all access to the base URL to handle_welcome. This means that visiting the URL [@http://localhost/] should now return a page containing the string 'Hello, world!'. [endsect] [section:forms Using forms] Now lets create a form to pass some data from the browser to the server and back. Save the following file as =form.xhtml=.[teletype] Form example

Hello ${name}!

Please enter your name and press the Submit button

We add the zeep prefix to our html tag, it has the value ="http://www.cmbi.ru.nl/libzeep/ml"= which is the same as the default value for the `ns` parameter in the __webapp__ constructor. Note that the input tag has an attribute with value '${data}'. This is a piece of expression language script. This will be explained below:[c++] #include #include #include using namespace std; class MyWebApp : public __webapp__ { public: MyWebApp(); void handle_welcome(const __http_request__& request, const __el_scope__& scope, __http_reply__& reply); void handle_salute(const __http_request__& request, const __el_scope__& scope, __http_reply__& reply); }; MyWebApp::MyWebApp() { mount("", boost::bind(&MyWebApp::handle_welcome, this, _1, _2, _3)); mount("salute", boost::bind(&MyWebApp::handle_salute, this, _1, _2, _3)); } void MyWebApp::handle_welcome(const __http_request__& request, const __el_scope__& scope, __http_reply__& reply) { create_reply_from_template("form.xhtml", scope, reply); } void MyWebApp::handle_salute(const __http_request__& request, const __el_scope__& scope, __http_reply__& reply) { zeep::http::parameter_map params; get_parameters(scope, params); string name = params.get("name", "").as(); __el_scope__ sub(scope); sub.put("name", name); create_reply_from_template("form.xhtml", sub, reply); } int main() { MyWebApp server; server.bind("0.0.0.0", 80); server.run(1); } This time, we add a new handler for the 'salute' page. The form has an action that points to this salute page. As can be seen in the `handle_salute` method, we first collect the parameters passed in. Parameters are accessed by name. We then create a sub scope of the scope passed in. In this sub scope we put the value of the parameter so that the XHTML processor can access it. And then we return a reply based on the contents of the =form.xhtml= template and the contents of the sub scope we created. [endsect] [section:el Using `el` script] `el` means /Expression Language/. It is a script language that tries to be like [@http://en.wikipedia.org/wiki/Unified_Expression_Language]. The objects can be created in the C++ server code using the __el_object__ class. Object created this way are then stored in an __el_scope__ object and passed along to the XHTML processing code. __el_object__ objects can contain simple data and arrays. E.g., to create an array you could write: using namespace zeep::http; vector ints; for (int i = 0; i < 10; ++i) { el::object int_object; int_object["value"] = i; ints.push_back(int_object); } scope.put("ints", el::object(ints)); And then you can access this in the XHTML:[teletype] 1: ${ints[1].value}, 2: ${ints[2].value} [c++]Which should output "1: 1, 2: 2" [endsect] [section:processing_tags Processing Tags] The method `create_reply_from_template` takes the name of a template file and a scope to generate the output XHTML. We've already seen that `el` scripts are processed by this method. But there is more, several special tags in the template are processed in a special way. These tags are in a separate XML namespace. You can change this name space using the `ns` parameter in the __webapp__ constructor, the default is =http://www.cmbi.ru.nl/libzeep/ml=. In the template for the form example above you might have noticed the == tag. This tag takes one attribute called `test` and the value of this tag is interpreted as a `el` script. If the script evaluates to something other than empty, zero or false, the content of the == tag is included, otherwise it is discarded in the output. There are several predefined processing tags which are summarized below. You can also add your own processing tags using the __add_processor__ method. This method takes a `std::string` parameter for the name of the tag and a `processor_type` parameter which is a call back function. [table List of predefined processing tags [[tag name (without prefix)][Description][Example]] [ [include] [Takes one parameter named `file` and replaces the tag with the processed content of this file] [ [^] ] ] [ [if] [Takes one parameter named `test` containing an `el` script. This script is evaluated and if the result is not empty, zero or false, the content of the `if` tags is inserted in the output. Otherwise, the content is discarded.] [[teletype] `` Hello ${name} `` ] ] [ [iterate] [Takes two parameters, `collection` which contains an `el` script that evaluates to an array `el::object` and a name in `var`. The content of the `iterate` tag is included for each value of `collection` and `var` will contain the current value.] [ ``
  • ${name}
`` ] ] [ [for] [Takes three parameters. The parameters `begin` and `end` should evaluate to a number. The parameter `var` contains a name that will be used to hold the current value when inserting the content of the `for` tag in each iteration of the for loop between `begin` and `end`.] [ `` ${i}, `` ] ] [ [number] [Format the number in the `n` parameter using the `f` format. This is limited to the formats ='#.##0'= and ='#.##0B'= for now. The first formats an integer value using thousand separators, the second tries to format the integer value in a power of two multiplier (kibi, mebi, etc.) with a suffix of `B`, `M`, `G`, etc.] [ `` Will output 1K `` ] ] [ [options] [This tag will insert multiple =