From bcd246076540a8353fa55fc0a5e19343c1a2dbc9 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 14 Aug 2015 13:03:08 +0200 Subject: Implement package search service mockup --- web/apache/request | 12 ++--- web/apache/request.cxx | 125 +++++++----------------------------------- web/mime-url-encoding | 26 +++++++++ web/mime-url-encoding.cxx | 135 ++++++++++++++++++++++++++++++++++++++++++++++ web/module | 12 +++++ web/xhtml | 53 ++++++++++++------ 6 files changed, 236 insertions(+), 127 deletions(-) create mode 100644 web/mime-url-encoding create mode 100644 web/mime-url-encoding.cxx (limited to 'web') diff --git a/web/apache/request b/web/apache/request index 59d4600..88b38a9 100644 --- a/web/apache/request +++ b/web/apache/request @@ -43,6 +43,11 @@ namespace web int flush (); + // Get request path. + // + virtual const path_type& + path (); + // Get request body data stream. // virtual std::istream& @@ -93,12 +98,6 @@ namespace web void parse_parameters (const char* args); - static void - mime_url_encode (const char* v, std::ostream& o); - - static std::string - mime_url_decode (const char* b, const char* e, bool trim = false); - bool get_write_state () const noexcept {return write_state_;} @@ -129,6 +128,7 @@ namespace web std::unique_ptr out_; std::unique_ptr in_buf_; std::unique_ptr in_; + path_type path_; std::unique_ptr parameters_; std::unique_ptr cookies_; std::unique_ptr form_data_; diff --git a/web/apache/request.cxx b/web/apache/request.cxx index 7727b35..497d2d6 100644 --- a/web/apache/request.cxx +++ b/web/apache/request.cxx @@ -14,18 +14,20 @@ #include // unique_ptr #include #include +#include #include #include // move() #include #include +#include + using namespace std; namespace web { namespace apache { - istream& request:: content () { @@ -46,10 +48,25 @@ namespace web return *in_; } + const path& request:: + path () + { + if (path_.empty ()) + { + path_ = path_type (rec_->uri); + + // Module request handler can not be called if URI is empty. + // + assert (!path_.empty ()); + } + + return path_; + } + const name_values& request:: parameters () { - if (!parameters_) + if (parameters_ == nullptr) { parameters_.reset (new name_values ()); @@ -70,7 +87,7 @@ namespace web const name_values& request:: cookies () { - if (!cookies_) + if (cookies_ == nullptr) { cookies_.reset (new name_values ()); @@ -264,107 +281,5 @@ namespace web n = e ? e + 1 : 0; } } - - void request:: - mime_url_encode (const char* v, ostream& o) - { - char f (o.fill ()); - ios_base::fmtflags g (o.flags ()); - o << hex << uppercase << right << setfill ('0'); - - char c; - - while ((c = *v++) != '\0') - { - if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || - (c >= '0' && c <= '9')) - { - o << c; - } - else - switch (c) - { - case ' ': o << '+'; break; - case '.': - case '_': - case '-': - case '~': o << c; break; - default: - { - o << "%" << setw (2) << static_cast (c); - break; - } - } - } - - o.flags (g); - o.fill (f); - } - - string request:: - mime_url_decode (const char* b, const char* e, bool trim) - { - if (trim) - { - b += strspn (b, " "); - - if (b >= e) - return string (); - - while (*--e == ' '); - ++e; - } - - string value; - value.reserve (e - b); - - char bf[3]; - bf[2] = '\0'; - - while (b != e) - { - char c (*b++); - - switch (c) - { - case '+': - { - value.append (" "); - break; - } - case '%': - { - if (*b == '\0' || b[1] == '\0') - { - throw invalid_argument ( - "::web::apache::request::mime_url_decode short"); - } - - *bf = *b; - bf[1] = b[1]; - - char* ebf (nullptr); - size_t vl (strtoul (bf, &ebf, 16)); - - if (*ebf != '\0') - { - throw invalid_argument ( - "::web::apache::request::mime_url_decode wrong"); - } - - value.append (1, static_cast (vl)); - b += 2; - break; - } - default: - { - value.append (1, c); - break; - } - } - } - - return value; - } } } diff --git a/web/mime-url-encoding b/web/mime-url-encoding new file mode 100644 index 0000000..9ae5d6d --- /dev/null +++ b/web/mime-url-encoding @@ -0,0 +1,26 @@ +// file : web/mime-url-encoding -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef WEB_MIME_URL_ENCODING +#define WEB_MIME_URL_ENCODING + +#include +#include + +namespace web +{ + void + mime_url_encode (const char* v, std::ostream& o); + + std::string + mime_url_encode (const char* v); + + std::string + mime_url_encode (const std::string& v); + + std::string + mime_url_decode (const char* b, const char* e, bool trim = false); +} + +#endif // WEB_MIME_URL_ENCODING diff --git a/web/mime-url-encoding.cxx b/web/mime-url-encoding.cxx new file mode 100644 index 0000000..1d68bf3 --- /dev/null +++ b/web/mime-url-encoding.cxx @@ -0,0 +1,135 @@ +// file : web/mime-url-encoding.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include + +#include // hex, uppercase, right +#include +#include // setw(), setfill () +#include +#include +#include // size_t, strspn() +#include // invalid_argument + +using namespace std; + +namespace web +{ + // Encode characters different from unreserved ones specified in + // "2.3. Unreserved Characters" of http://tools.ietf.org/html/rfc3986. + // + void + mime_url_encode (const char* v, ostream& o) + { + char f (o.fill ()); + ostream::fmtflags g (o.flags ()); + o << hex << uppercase << right << setfill ('0'); + + char c; + while ((c = *v++) != '\0') + { + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9')) + { + o << c; + } + else + { + switch (c) + { + case ' ': o << '+'; break; + case '.': + case '_': + case '-': + case '~': o << c; break; + default: + { + o << "%" << setw (2) << static_cast (c); + break; + } + } + } + } + + o.flags (g); + o.fill (f); + } + + string + mime_url_encode (const char* v) + { + stringstream o; + mime_url_encode (v, o); + return o.str (); + } + + string + mime_url_encode (const string& v) + { + return mime_url_encode (v.c_str ()); + } + + string + mime_url_decode (const char* b, const char* e, bool trim) + { + if (trim) + { + b += strspn (b, " "); + + if (b >= e) + return string (); + + while (*--e == ' '); + ++e; + } + + string value; + value.reserve (e - b); + + char bf[3]; + bf[2] = '\0'; + + while (b != e) + { + char c (*b++); + switch (c) + { + case '+': + { + value.append (" "); + break; + } + case '%': + { + if (*b == '\0' || b[1] == '\0') + { + throw invalid_argument ("::web::mime_url_decode short"); + } + + *bf = *b; + bf[1] = b[1]; + + char* ebf (nullptr); + size_t vl (strtoul (bf, &ebf, 16)); + + if (*ebf != '\0') + { + throw invalid_argument ("::web::mime_url_decode wrong"); + } + + value.append (1, static_cast (vl)); + b += 2; + break; + } + default: + { + value.append (1, c); + break; + } + } + } + + return value; + } +} diff --git a/web/module b/web/module index e1cccf0..7398d45 100644 --- a/web/module +++ b/web/module @@ -13,6 +13,8 @@ #include // move() #include // runtime_error +#include + namespace web { // HTTP status code. @@ -68,10 +70,20 @@ namespace web }; using name_values = std::vector; + using path = butl::path; class request { public: + using path_type = web::path; + + // Corresponds to abs_path portion of HTTP URL as described in + // "3.2.2 HTTP URL" of http://tools.ietf.org/html/rfc2616. + // Returns '/' if no abs_path is present in URL. + // + virtual const path_type& + path () = 0; + //@@ Why not pass parameters directly? Lazy parsing? //@@ Why not have something like operator[] for lookup? Probably // in name_values. diff --git a/web/xhtml b/web/xhtml index b8d6ce0..4fc6119 100644 --- a/web/xhtml +++ b/web/xhtml @@ -5,6 +5,8 @@ #ifndef WEB_XHTML #define WEB_XHTML +#include // function + #include namespace web @@ -36,9 +38,9 @@ namespace web // namespace xhtml { - const char* xmlns = "http://www.w3.org/1999/xhtml"; + const char* const xmlns = "http://www.w3.org/1999/xhtml"; - using serializer_func = void (*) (xml::serializer&); + using serializer_func = std::function; struct attr_value_base { @@ -124,7 +126,10 @@ namespace web operator() (xml::serializer& s) const {s.start_element (xmlns, name);} virtual serializer_func - operator~ () const {return [](xml::serializer& s) {s.end_element ();};} + operator~ () const + { + return [this](xml::serializer& s) {s.end_element (xmlns, name);}; + } // s << elem(attr1 = 123, attr2 = "abc"); // @@ -143,8 +148,11 @@ namespace web return attr_element (*this, a1); } - protected: - element () = default; +// @@ Now always need to provide element name, so operator~ () could create +// the lambda capable to pass a valid name to end_element call. +// +// protected: +// element () = default; }; struct inline_element: element @@ -162,9 +170,9 @@ namespace web virtual serializer_func operator~ () const { - return [](xml::serializer& s) + return [this](xml::serializer& s) { - s.end_element (); s.resume_indentation (); + s.end_element (xmlns, name); s.resume_indentation (); }; } }; @@ -194,7 +202,10 @@ namespace web operator() (xml::serializer& s) const {s.start_attribute (name);} virtual serializer_func - operator~ () const {return [](xml::serializer& s) {s.end_attribute ();};} + operator~ () const + { + return [this](xml::serializer& s) {s.end_attribute (name);}; + } }; // Elements. @@ -206,13 +217,13 @@ namespace web // struct html_element: element { - html_element () {} // Uninitialized const static. + html_element (): element ("html") {} virtual void operator() (xml::serializer& s) const { s.doctype_decl ("html"); - s.start_element (xmlns, "html"); + s.start_element (xmlns, name); s.namespace_decl (xmlns, ""); } }; @@ -220,12 +231,12 @@ namespace web struct head_element: element { - head_element () {} // Uninitialized const static. + head_element (): element ("head") {} virtual void operator() (xml::serializer& s) const { - s.start_element (xmlns, "head"); + s.start_element (xmlns, name); s.start_element (xmlns, "meta"); s.attribute ("charset", "UTF-8"); s.end_element (); @@ -233,10 +244,13 @@ namespace web }; static const head_element HEAD; + static const element BODY ("body"); + static const element DIV ("div"); + static const element P ("p"); + static const element STYLE ("style"); static const element TITLE ("title"); - static const element BODY ("body"); - static const element P ("p"); + static const inline_element A ("a"); static const inline_element B ("b"); static const inline_element I ("i"); static const inline_element U ("u"); @@ -246,9 +260,16 @@ namespace web // Attributes. // - static const attribute ID ("id"); static const attribute CLASS ("class"); - static const attribute STYLE ("style"); + static const attribute HREF ("href"); + static const attribute ID ("id"); + static const attribute TYPE ("type"); + +// @@ Attribute variable names clash with element variable names. +// Should we prefix/suffix attribute names like _STYLE, STYLE_ or there +// are some better ideas ? +// +// static const attribute STYLE ("style"); } } -- cgit v1.1