From 3b4bf01a7dd9e16f1df00c70b87a533a3cd17797 Mon Sep 17 00:00:00 2001 From: Antony Woods Date: Mon, 22 Sep 2014 21:34:22 +0100 Subject: URL params are now present as a ci_map variable of request --- include/http_request.h | 5 ++-- include/parser.h | 67 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/http_request.h b/include/http_request.h index 331bc80..24edb66 100644 --- a/include/http_request.h +++ b/include/http_request.h @@ -20,6 +20,7 @@ namespace crow { HTTPMethod method; std::string url; + ci_map url_params; ci_map headers; std::string body; @@ -30,8 +31,8 @@ namespace crow { } - request(HTTPMethod method, std::string url, ci_map headers, std::string body) - : method(method), url(std::move(url)), headers(std::move(headers)), body(std::move(body)) + request(HTTPMethod method, std::string url, ci_map url_params, ci_map headers, std::string body) + : method(method), url(std::move(url)), url_params(std::move(url_params)), headers(std::move(headers)), body(std::move(body)) { } diff --git a/include/parser.h b/include/parser.h index 869061c..bda4594 100644 --- a/include/parser.h +++ b/include/parser.h @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include "http_request.h" @@ -11,6 +13,62 @@ namespace crow template struct HTTPParser : public http_parser { + template + struct tokenize_by_char + { + template + bool operator()(It& next, It end, std::string & tok) + { + if (next == end) + return false; + const char dels = delimiter; + const char* del = &dels; + auto pos = std::search(next, end, del, del + 1); + tok.assign(next, pos); + next = pos; + if (next != end) + std::advance(next, 1); + return true; + } + + void reset() {} + }; + + static ci_map get_url_params(std::string url) + { + const char url_delimiter = '&'; + const char param_delimiter = '='; + ci_map ret; + + int qMarkPos = url.find("?"); + if(!(qMarkPos >=0 && qMarkPos != (url.length()-1))) { + return ret; + } + + auto params = url.substr(qMarkPos+1); + + // substitute ';' for '&' for recommended process of delimintation + // (http://www.w3.org/TR/1999/REC-html401-19991224/appendix/notes.html#h-B.2.2) + std::replace(params.begin(), params.end(), ';', url_delimiter); + + // url tokenizer + for (auto i : boost::tokenizer>(params)) { + std::string key, value; + auto parts = boost::tokenizer>(i); + int count = 0; + for(auto p = parts.begin(); p != parts.end(); ++p, ++count) { + if(count == 0){ + key = *p; + } else { + value = *p; + } + } + ret.insert(std::make_pair(key, value)); + } + + return ret; + } + static int on_message_begin(http_parser* self_) { HTTPParser* self = static_cast(self_); @@ -21,6 +79,10 @@ namespace crow { HTTPParser* self = static_cast(self_); self->url.insert(self->url.end(), at, at+length); + + // url params + self->url_params = get_url_params(self->url); + return 0; } static int on_header_field(http_parser* self_, const char* at, size_t length) @@ -115,6 +177,7 @@ namespace crow header_field.clear(); header_value.clear(); headers.clear(); + url_params.clear(); body.clear(); } @@ -130,7 +193,7 @@ namespace crow request to_request() const { - return request{(HTTPMethod)method, std::move(url), std::move(headers), std::move(body)}; + return request{(HTTPMethod)method, std::move(url), std::move(url_params), std::move(headers), std::move(body)}; } bool check_version(int major, int minor) const @@ -139,10 +202,12 @@ namespace crow } std::string url; + int header_building_state = 0; std::string header_field; std::string header_value; ci_map headers; + ci_map url_params; std::string body; Handler* handler_; -- cgit v1.2.3-54-g00ecf From 6890436742c89a01d00f26f796becb5e81c26e0b Mon Sep 17 00:00:00 2001 From: Antony Woods Date: Tue, 23 Sep 2014 21:02:26 +0100 Subject: Fixed sign comparisson warning --- include/parser.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/parser.h b/include/parser.h index bda4594..00bb155 100644 --- a/include/parser.h +++ b/include/parser.h @@ -40,7 +40,7 @@ namespace crow const char param_delimiter = '='; ci_map ret; - int qMarkPos = url.find("?"); + unsigned int qMarkPos = url.find("?"); if(!(qMarkPos >=0 && qMarkPos != (url.length()-1))) { return ret; } -- cgit v1.2.3-54-g00ecf From 06842721d7da53a2235e6e4071760588ec285f90 Mon Sep 17 00:00:00 2001 From: Antony Woods Date: Tue, 14 Oct 2014 09:48:35 +0100 Subject: Wrapped qs_parse as query_string and added tests --- README.md | 18 + amalgamate/crow_all.h | 4908 ++++++++++++++++++++++++--------------------- examples/example.cpp | 17 +- include/http_connection.h | 2 +- include/http_request.h | 8 +- include/parser.h | 73 +- include/query_string.h | 305 +++ include/routing.h | 7 +- tests/unittest.cpp | 117 ++ 9 files changed, 3083 insertions(+), 2372 deletions(-) create mode 100644 include/query_string.h (limited to 'include') diff --git a/README.md b/README.md index c6fa8a4..1400c0d 100644 --- a/README.md +++ b/README.md @@ -115,3 +115,21 @@ ctest #### OSX brew install boost google-perftools +### Attributions + +Crow uses the following libraries. + + qs_parse + + https://github.com/bartgrantham/qs_parse + + Copyright (c) 2010 Bart Grantham + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + diff --git a/amalgamate/crow_all.h b/amalgamate/crow_all.h index d732765..a567b5a 100644 --- a/amalgamate/crow_all.h +++ b/amalgamate/crow_all.h @@ -1,143 +1,964 @@ #pragma once -//#define CROW_JSON_NO_ERROR_CHECK - -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(__GNUG__) || defined(__clang__) -#define crow_json_likely(x) __builtin_expect(x, 1) -#define crow_json_unlikely(x) __builtin_expect(x, 0) -#else -#define crow_json_likely(x) x -#define crow_json_unlikely(x) x -#endif - +#include +#include +#include +#include namespace crow { - namespace mustache + namespace black_magic { - class template_t; - } + struct OutOfRange + { + OutOfRange(unsigned pos, unsigned length) {} + }; + constexpr unsigned requires_in_range( unsigned i, unsigned len ) + { + return i >= len ? throw OutOfRange(i, len) : i; + } - namespace json - { - inline void escape(const std::string& str, std::string& ret) + class const_str + { + const char * const begin_; + unsigned size_; + + public: + template< unsigned N > + constexpr const_str( const char(&arr)[N] ) : begin_(arr), size_(N - 1) { + static_assert( N >= 1, "not a string literal"); + } + constexpr char operator[]( unsigned i ) const { + return requires_in_range(i, size_), begin_[i]; + } + + constexpr operator const char *() const { + return begin_; + } + + constexpr const char* begin() const { return begin_; } + constexpr const char* end() const { return begin_ + size_; } + + constexpr unsigned size() const { + return size_; + } + }; + + + constexpr unsigned find_closing_tag(const_str s, unsigned p) + { + return s[p] == '>' ? p : find_closing_tag(s, p+1); + } + + constexpr bool is_valid(const_str s, unsigned i = 0, int f = 0) { - ret.reserve(ret.size() + str.size()+str.size()/4); - for(char c:str) - { - switch(c) - { - case '"': ret += "\\\""; break; - case '\\': ret += "\\\\"; break; - case '\n': ret += "\\n"; break; - case '\b': ret += "\\b"; break; - case '\f': ret += "\\f"; break; - case '\r': ret += "\\r"; break; - case '\t': ret += "\\t"; break; - default: - if (0 <= c && c < 0x20) - { - ret += "\\u00"; - auto to_hex = [](char c) - { - c = c&0xf; - if (c < 10) - return '0' + c; - return 'a'+c-10; - }; - ret += to_hex(c/16); - ret += to_hex(c%16); - } - else - ret += c; - break; - } - } + return + i == s.size() + ? f == 0 : + f < 0 || f >= 2 + ? false : + s[i] == '<' + ? is_valid(s, i+1, f+1) : + s[i] == '>' + ? is_valid(s, i+1, f-1) : + is_valid(s, i+1, f); } - inline std::string escape(const std::string& str) + + constexpr bool is_equ_p(const char* a, const char* b, unsigned n) { - std::string ret; - escape(str, ret); - return ret; + return + *a == 0 || *b == 0 + ? false : + n == 0 + ? true : + *a != *b + ? false : + is_equ_p(a+1, b+1, n-1); } - enum class type : char + constexpr bool is_equ_n(const_str a, unsigned ai, const_str b, unsigned bi, unsigned n) { - Null, - False, - True, - Number, - String, - List, - Object, - }; + return + ai + n > a.size() || bi + n > b.size() + ? false : + n == 0 + ? true : + a[ai] != b[bi] + ? false : + is_equ_n(a,ai+1,b,bi+1,n-1); + } - class rvalue; - rvalue load(const char* data, size_t size); + constexpr bool is_int(const_str s, unsigned i) + { + return is_equ_n(s, i, "", 0, 5); + } - namespace detail + constexpr bool is_uint(const_str s, unsigned i) { + return is_equ_n(s, i, "", 0, 6); + } - struct r_string - : boost::less_than_comparable, - boost::less_than_comparable, - boost::equality_comparable, - boost::equality_comparable - { - r_string() {}; - r_string(char* s, char* e) - : s_(s), e_(e) - {}; - ~r_string() - { - if (owned_) - delete[] s_; - } + constexpr bool is_float(const_str s, unsigned i) + { + return is_equ_n(s, i, "", 0, 7) || + is_equ_n(s, i, "", 0, 8); + } - r_string(const r_string& r) - { - *this = r; - } + constexpr bool is_str(const_str s, unsigned i) + { + return is_equ_n(s, i, "", 0, 5) || + is_equ_n(s, i, "", 0, 8); + } - r_string(r_string&& r) - { - *this = r; - } + constexpr bool is_path(const_str s, unsigned i) + { + return is_equ_n(s, i, "", 0, 6); + } - r_string& operator = (r_string&& r) - { - s_ = r.s_; - e_ = r.e_; - owned_ = r.owned_; - return *this; - } + constexpr uint64_t get_parameter_tag(const_str s, unsigned p = 0) + { + return + p == s.size() + ? 0 : + s[p] == '<' ? ( + is_int(s, p) + ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 1 : + is_uint(s, p) + ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 2 : + is_float(s, p) + ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 3 : + is_str(s, p) + ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 4 : + is_path(s, p) + ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 5 : + throw std::runtime_error("invalid parameter type") + ) : + get_parameter_tag(s, p+1); + } - r_string& operator = (const r_string& r) - { - s_ = r.s_; - e_ = r.e_; - owned_ = 0; - return *this; - } + template + struct S + { + template + using push = S; + template + using push_back = S; + template class U> + using rebind = U; + }; +template + struct CallHelper; + template + struct CallHelper> + { + template ()(std::declval()...)) + > + static char __test(int); - operator std::string () const - { - return std::string(s_, e_); - } + template + static int __test(...); + static constexpr bool value = sizeof(__test(0)) == sizeof(char); + }; - const char* begin() const { return s_; } - const char* end() const { return e_; } - size_t size() const { return end() - begin(); } + + template + struct single_tag_to_type + { + }; + + template <> + struct single_tag_to_type<1> + { + using type = int64_t; + }; + + template <> + struct single_tag_to_type<2> + { + using type = uint64_t; + }; + + template <> + struct single_tag_to_type<3> + { + using type = double; + }; + + template <> + struct single_tag_to_type<4> + { + using type = std::string; + }; + + template <> + struct single_tag_to_type<5> + { + using type = std::string; + }; + + + template + struct arguments + { + using subarguments = typename arguments::type; + using type = + typename subarguments::template push::type>; + }; + + template <> + struct arguments<0> + { + using type = S<>; + }; + + template + struct last_element_type + { + using type = typename std::tuple_element>::type; + }; + + + template <> + struct last_element_type<> + { + }; + + + // from http://stackoverflow.com/questions/13072359/c11-compile-time-array-with-logarithmic-evaluation-depth + template using Invoke = typename T::type; + + template struct seq{ using type = seq; }; + + template struct concat; + + template + struct concat, seq> + : seq{}; + + template + using Concat = Invoke>; + + template struct gen_seq; + template using GenSeq = Invoke>; + + template + struct gen_seq : Concat, GenSeq>{}; + + template<> struct gen_seq<0> : seq<>{}; + template<> struct gen_seq<1> : seq<0>{}; + + template + struct pop_back_helper; + + template + struct pop_back_helper, Tuple> + { + template