From 317440c48111f405a7dda6b9492e69f9731302cf Mon Sep 17 00:00:00 2001 From: tomato5040 <83554828+tomato5040@users.noreply.github.com> Date: Thu, 13 May 2021 14:24:44 -0500 Subject: [PATCH] Add files via upload --- ext/crow_all.h | 10611 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 10611 insertions(+) create mode 100644 ext/crow_all.h diff --git a/ext/crow_all.h b/ext/crow_all.h new file mode 100644 index 0000000..e816d32 --- /dev/null +++ b/ext/crow_all.h @@ -0,0 +1,10611 @@ +#pragma once +// settings for crow +// TODO - replace with runtime config. libucl? + +/* #ifdef - enables debug mode */ +//#define CROW_ENABLE_DEBUG + +/* #ifdef - enables logging */ +#define CROW_ENABLE_LOGGING + +/* #ifdef - enables ssl */ +//#define CROW_ENABLE_SSL + +/* #define - specifies log level */ +/* + Debug = 0 + Info = 1 + Warning = 2 + Error = 3 + Critical = 4 + + default to INFO +*/ +#ifndef CROW_LOG_LEVEL +#define CROW_LOG_LEVEL 1 +#endif + + +// compiler flags +#if __cplusplus >= 201402L +#define CROW_CAN_USE_CPP14 +#endif + +#if defined(_MSC_VER) +#if _MSC_VER < 1900 +#define CROW_MSVC_WORKAROUND +#define constexpr const +#define noexcept throw() +#endif +#endif + + + +#pragma once + +#include +#include +#include +#include +#include +#include + + + + +namespace crow +{ + enum class LogLevel + { +#ifndef ERROR + DEBUG = 0, + INFO, + WARNING, + ERROR, + CRITICAL, +#endif + + Debug = 0, + Info, + Warning, + Error, + Critical, + }; + + class ILogHandler { + public: + virtual void log(std::string message, LogLevel level) = 0; + }; + + class CerrLogHandler : public ILogHandler { + public: + void log(std::string message, LogLevel /*level*/) override { + std::cerr << message; + } + }; + + class logger { + + private: + // + static std::string timestamp() + { + char date[32]; + time_t t = time(0); + + tm my_tm; + +#if defined(_MSC_VER) or defined(__MINGW32__) + gmtime_s(&my_tm, &t); +#else + gmtime_r(&t, &my_tm); +#endif + + size_t sz = strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", &my_tm); + return std::string(date, date+sz); + } + + public: + + + logger(std::string prefix, LogLevel level) : level_(level) { + #ifdef CROW_ENABLE_LOGGING + stringstream_ << "(" << timestamp() << ") [" << prefix << "] "; + #endif + + } + ~logger() { + #ifdef CROW_ENABLE_LOGGING + if(level_ >= get_current_log_level()) { + stringstream_ << std::endl; + get_handler_ref()->log(stringstream_.str(), level_); + } + #endif + } + + // + template + logger& operator<<(T const &value) { + + #ifdef CROW_ENABLE_LOGGING + if(level_ >= get_current_log_level()) { + stringstream_ << value; + } + #endif + return *this; + } + + // + static void setLogLevel(LogLevel level) { + get_log_level_ref() = level; + } + + static void setHandler(ILogHandler* handler) { + get_handler_ref() = handler; + } + + static LogLevel get_current_log_level() { + return get_log_level_ref(); + } + + private: + // + static LogLevel& get_log_level_ref() + { + static LogLevel current_level = (LogLevel)CROW_LOG_LEVEL; + return current_level; + } + static ILogHandler*& get_handler_ref() + { + static CerrLogHandler default_handler; + static ILogHandler* current_handler = &default_handler; + return current_handler; + } + + // + std::ostringstream stringstream_; + LogLevel level_; + }; +} + +#define CROW_LOG_CRITICAL \ + if (crow::logger::get_current_log_level() <= crow::LogLevel::Critical) \ + crow::logger("CRITICAL", crow::LogLevel::Critical) +#define CROW_LOG_ERROR \ + if (crow::logger::get_current_log_level() <= crow::LogLevel::Error) \ + crow::logger("ERROR ", crow::LogLevel::Error) +#define CROW_LOG_WARNING \ + if (crow::logger::get_current_log_level() <= crow::LogLevel::Warning) \ + crow::logger("WARNING ", crow::LogLevel::Warning) +#define CROW_LOG_INFO \ + if (crow::logger::get_current_log_level() <= crow::LogLevel::Info) \ + crow::logger("INFO ", crow::LogLevel::Info) +#define CROW_LOG_DEBUG \ + if (crow::logger::get_current_log_level() <= crow::LogLevel::Debug) \ + crow::logger("DEBUG ", crow::LogLevel::Debug) + + + + +#pragma once + +#include +#include +#include +#include +#include + + + + +namespace crow +{ + namespace detail + { + ///Fast timer queue for fixed tick value. + class dumb_timer_queue + { + public: + static int tick; + using key = std::pair; + + void cancel(key& k) + { + auto self = k.first; + k.first = nullptr; + if (!self) + return; + + unsigned int index = (unsigned int)(k.second - self->step_); + if (index < self->dq_.size()) + self->dq_[index].second = nullptr; + } + + key add(std::function f) + { + dq_.emplace_back(std::chrono::steady_clock::now(), std::move(f)); + int ret = step_+dq_.size()-1; + + CROW_LOG_DEBUG << "timer add inside: " << this << ' ' << ret ; + return {this, ret}; + } + + void process() + { + if (!io_service_) + return; + + auto now = std::chrono::steady_clock::now(); + while(!dq_.empty()) + { + auto& x = dq_.front(); + if (now - x.first < std::chrono::seconds(tick)) + break; + if (x.second) + { + CROW_LOG_DEBUG << "timer call: " << this << ' ' << step_; + // we know that timer handlers are very simple currenty; call here + x.second(); + } + dq_.pop_front(); + step_++; + } + } + + void set_io_service(boost::asio::io_service& io_service) + { + io_service_ = &io_service; + } + + dumb_timer_queue() noexcept + { + } + + private: + boost::asio::io_service* io_service_{}; + std::deque>> dq_; + int step_{}; + }; + } +} + + + +/* + * + * TinySHA1 - a header only implementation of the SHA1 algorithm in C++. Based + * on the implementation in boost::uuid::details. + * + * SHA1 Wikipedia Page: http://en.wikipedia.org/wiki/SHA-1 + * + * Copyright (c) 2012-22 SAURAV MOHAPATRA + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef _TINY_SHA1_HPP_ +#define _TINY_SHA1_HPP_ +#include +#include +#include +#include +namespace sha1 +{ + class SHA1 + { + public: + typedef uint32_t digest32_t[5]; + typedef uint8_t digest8_t[20]; + inline static uint32_t LeftRotate(uint32_t value, size_t count) { + return (value << count) ^ (value >> (32-count)); + } + SHA1(){ reset(); } + virtual ~SHA1() {} + SHA1(const SHA1& s) { *this = s; } + const SHA1& operator = (const SHA1& s) { + memcpy(m_digest, s.m_digest, 5 * sizeof(uint32_t)); + memcpy(m_block, s.m_block, 64); + m_blockByteIndex = s.m_blockByteIndex; + m_byteCount = s.m_byteCount; + return *this; + } + SHA1& reset() { + m_digest[0] = 0x67452301; + m_digest[1] = 0xEFCDAB89; + m_digest[2] = 0x98BADCFE; + m_digest[3] = 0x10325476; + m_digest[4] = 0xC3D2E1F0; + m_blockByteIndex = 0; + m_byteCount = 0; + return *this; + } + SHA1& processByte(uint8_t octet) { + this->m_block[this->m_blockByteIndex++] = octet; + ++this->m_byteCount; + if(m_blockByteIndex == 64) { + this->m_blockByteIndex = 0; + processBlock(); + } + return *this; + } + SHA1& processBlock(const void* const start, const void* const end) { + const uint8_t* begin = static_cast(start); + const uint8_t* finish = static_cast(end); + while(begin != finish) { + processByte(*begin); + begin++; + } + return *this; + } + SHA1& processBytes(const void* const data, size_t len) { + const uint8_t* block = static_cast(data); + processBlock(block, block + len); + return *this; + } + const uint32_t* getDigest(digest32_t digest) { + size_t bitCount = this->m_byteCount * 8; + processByte(0x80); + if (this->m_blockByteIndex > 56) { + while (m_blockByteIndex != 0) { + processByte(0); + } + while (m_blockByteIndex < 56) { + processByte(0); + } + } else { + while (m_blockByteIndex < 56) { + processByte(0); + } + } + processByte(0); + processByte(0); + processByte(0); + processByte(0); + processByte( static_cast((bitCount>>24) & 0xFF)); + processByte( static_cast((bitCount>>16) & 0xFF)); + processByte( static_cast((bitCount>>8 ) & 0xFF)); + processByte( static_cast((bitCount) & 0xFF)); + + memcpy(digest, m_digest, 5 * sizeof(uint32_t)); + return digest; + } + const uint8_t* getDigestBytes(digest8_t digest) { + digest32_t d32; + getDigest(d32); + size_t di = 0; + digest[di++] = ((d32[0] >> 24) & 0xFF); + digest[di++] = ((d32[0] >> 16) & 0xFF); + digest[di++] = ((d32[0] >> 8) & 0xFF); + digest[di++] = ((d32[0]) & 0xFF); + + digest[di++] = ((d32[1] >> 24) & 0xFF); + digest[di++] = ((d32[1] >> 16) & 0xFF); + digest[di++] = ((d32[1] >> 8) & 0xFF); + digest[di++] = ((d32[1]) & 0xFF); + + digest[di++] = ((d32[2] >> 24) & 0xFF); + digest[di++] = ((d32[2] >> 16) & 0xFF); + digest[di++] = ((d32[2] >> 8) & 0xFF); + digest[di++] = ((d32[2]) & 0xFF); + + digest[di++] = ((d32[3] >> 24) & 0xFF); + digest[di++] = ((d32[3] >> 16) & 0xFF); + digest[di++] = ((d32[3] >> 8) & 0xFF); + digest[di++] = ((d32[3]) & 0xFF); + + digest[di++] = ((d32[4] >> 24) & 0xFF); + digest[di++] = ((d32[4] >> 16) & 0xFF); + digest[di++] = ((d32[4] >> 8) & 0xFF); + digest[di++] = ((d32[4]) & 0xFF); + return digest; + } + + protected: + void processBlock() { + uint32_t w[80]; + for (size_t i = 0; i < 16; i++) { + w[i] = (m_block[i*4 + 0] << 24); + w[i] |= (m_block[i*4 + 1] << 16); + w[i] |= (m_block[i*4 + 2] << 8); + w[i] |= (m_block[i*4 + 3]); + } + for (size_t i = 16; i < 80; i++) { + w[i] = LeftRotate((w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]), 1); + } + + uint32_t a = m_digest[0]; + uint32_t b = m_digest[1]; + uint32_t c = m_digest[2]; + uint32_t d = m_digest[3]; + uint32_t e = m_digest[4]; + + for (std::size_t i=0; i<80; ++i) { + uint32_t f = 0; + uint32_t k = 0; + + if (i<20) { + f = (b & c) | (~b & d); + k = 0x5A827999; + } else if (i<40) { + f = b ^ c ^ d; + k = 0x6ED9EBA1; + } else if (i<60) { + f = (b & c) | (b & d) | (c & d); + k = 0x8F1BBCDC; + } else { + f = b ^ c ^ d; + k = 0xCA62C1D6; + } + uint32_t temp = LeftRotate(a, 5) + f + e + k + w[i]; + e = d; + d = c; + c = LeftRotate(b, 30); + b = a; + a = temp; + } + + m_digest[0] += a; + m_digest[1] += b; + m_digest[2] += c; + m_digest[3] += d; + m_digest[4] += e; + } + private: + digest32_t m_digest; + uint8_t m_block[64]; + size_t m_blockByteIndex; + size_t m_byteCount; + }; +} +#endif + + + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace crow +{ +// ---------------------------------------------------------------------------- +// qs_parse (modified) +// https://github.com/bartgrantham/qs_parse +// ---------------------------------------------------------------------------- +/* Similar to strncmp, but handles URL-encoding for either string */ +int qs_strncmp(const char * s, const char * qs, size_t n); + + +/* Finds the beginning of each key/value pair and stores a pointer in qs_kv. + * Also decodes the value portion of the k/v pair *in-place*. In a future + * enhancement it will also have a compile-time option of sorting qs_kv + * alphabetically by key. */ +int qs_parse(char * qs, char * qs_kv[], int qs_kv_size); + + +/* Used by qs_parse to decode the value portion of a k/v pair */ +int qs_decode(char * qs); + + +/* Looks up the value according to the key on a pre-processed query string + * A future enhancement will be a compile-time option to look up the key + * in a pre-sorted qs_kv array via a binary search. */ +//char * qs_k2v(const char * key, char * qs_kv[], int qs_kv_size); + char * qs_k2v(const char * key, char * const * qs_kv, int qs_kv_size, int nth); + + +/* Non-destructive lookup of value, based on key. User provides the + * destinaton string and length. */ +char * qs_scanvalue(const char * key, const char * qs, char * val, size_t val_len); + +// TODO: implement sorting of the qs_kv array; for now ensure it's not compiled +#undef _qsSORTING + +// isxdigit _is_ available in , but let's avoid another header instead +#define CROW_QS_ISHEX(x) ((((x)>='0'&&(x)<='9') || ((x)>='A'&&(x)<='F') || ((x)>='a'&&(x)<='f')) ? 1 : 0) +#define CROW_QS_HEX2DEC(x) (((x)>='0'&&(x)<='9') ? (x)-48 : ((x)>='A'&&(x)<='F') ? (x)-55 : ((x)>='a'&&(x)<='f') ? (x)-87 : 0) +#define CROW_QS_ISQSCHR(x) ((((x)=='=')||((x)=='#')||((x)=='&')||((x)=='\0')) ? 0 : 1) + +inline int qs_strncmp(const char * s, const char * qs, size_t n) +{ + int i=0; + unsigned char u1, u2, unyb, lnyb; + + while(n-- > 0) + { + u1 = (unsigned char) *s++; + u2 = (unsigned char) *qs++; + + if ( ! CROW_QS_ISQSCHR(u1) ) { u1 = '\0'; } + if ( ! CROW_QS_ISQSCHR(u2) ) { u2 = '\0'; } + + if ( u1 == '+' ) { u1 = ' '; } + if ( u1 == '%' ) // easier/safer than scanf + { + unyb = (unsigned char) *s++; + lnyb = (unsigned char) *s++; + if ( CROW_QS_ISHEX(unyb) && CROW_QS_ISHEX(lnyb) ) + u1 = (CROW_QS_HEX2DEC(unyb) * 16) + CROW_QS_HEX2DEC(lnyb); + else + u1 = '\0'; + } + + if ( u2 == '+' ) { u2 = ' '; } + if ( u2 == '%' ) // easier/safer than scanf + { + unyb = (unsigned char) *qs++; + lnyb = (unsigned char) *qs++; + if ( CROW_QS_ISHEX(unyb) && CROW_QS_ISHEX(lnyb) ) + u2 = (CROW_QS_HEX2DEC(unyb) * 16) + CROW_QS_HEX2DEC(lnyb); + else + u2 = '\0'; + } + + if ( u1 != u2 ) + return u1 - u2; + if ( u1 == '\0' ) + return 0; + i++; + } + if ( CROW_QS_ISQSCHR(*qs) ) + return -1; + else + return 0; +} + + +inline int qs_parse(char * qs, char * qs_kv[], int qs_kv_size) +{ + int i, j; + char * substr_ptr; + + for(i=0; i means x iterations of this loop -> means *x+1* k/v pairs + + // we only decode the values in place, the keys could have '='s in them + // which will hose our ability to distinguish keys from values later + for(j=0; j> qs_dict_name2kv(const char * dict_name, char * const * qs_kv, int qs_kv_size, int nth = 0) +{ + int i; + size_t name_len, skip_to_eq, skip_to_brace_open, skip_to_brace_close; + + name_len = strlen(dict_name); + +#ifdef _qsSORTING +// TODO: binary search for key in the sorted qs_kv +#else // _qsSORTING + for(i=0; i 0 && + skip_to_brace_close > 0 && + nth == 0 ) + { + auto key = std::string(qs_kv[i] + skip_to_brace_open, skip_to_brace_close - skip_to_brace_open); + auto value = std::string(qs_kv[i] + skip_to_eq); + return boost::make_optional(std::make_pair(key, value)); + } + else + { + --nth; + } + } + } +#endif // _qsSORTING + + return boost::none; +} + + +inline char * qs_scanvalue(const char * key, const char * qs, char * val, size_t val_len) +{ + size_t i, key_len; + const char * tmp; + + // find the beginning of the k/v substrings + if ( (tmp = strchr(qs, '?')) != NULL ) + qs = tmp + 1; + + key_len = strlen(key); + while(qs[0] != '#' && qs[0] != '\0') + { + if ( qs_strncmp(key, qs, key_len) == 0 ) + break; + qs += strcspn(qs, "&") + 1; + } + + if ( qs[0] == '\0' ) return NULL; + + qs += strcspn(qs, "=&#"); + if ( qs[0] == '=' ) + { + qs++; + i = strcspn(qs, "&=#"); +#ifdef _MSC_VER + strncpy_s(val, val_len, qs, (val_len - 1)<(i + 1) ? (val_len - 1) : (i + 1)); +#else + strncpy(val, qs, (val_len - 1)<(i + 1) ? (val_len - 1) : (i + 1)); +#endif + qs_decode(val); + } + else + { + if ( val_len > 0 ) + val[0] = '\0'; + } + + return val; +} +} +// ---------------------------------------------------------------------------- + + +namespace crow +{ + class query_string + { + public: + static const int MAX_KEY_VALUE_PAIRS_COUNT = 256; + + query_string() + { + + } + + query_string(const query_string& qs) + : url_(qs.url_) + { + for(auto p:qs.key_value_pairs_) + { + key_value_pairs_.push_back((char*)(p-qs.url_.c_str()+url_.c_str())); + } + } + + query_string& operator = (const query_string& qs) + { + url_ = qs.url_; + key_value_pairs_.clear(); + for(auto p:qs.key_value_pairs_) + { + key_value_pairs_.push_back((char*)(p-qs.url_.c_str()+url_.c_str())); + } + return *this; + } + + query_string& operator = (query_string&& qs) + { + key_value_pairs_ = std::move(qs.key_value_pairs_); + char* old_data = (char*)qs.url_.c_str(); + url_ = std::move(qs.url_); + for(auto& p:key_value_pairs_) + { + p += (char*)url_.c_str() - old_data; + } + return *this; + } + + + query_string(std::string url) + : url_(std::move(url)) + { + if (url_.empty()) + return; + + key_value_pairs_.resize(MAX_KEY_VALUE_PAIRS_COUNT); + + int count = qs_parse(&url_[0], &key_value_pairs_[0], MAX_KEY_VALUE_PAIRS_COUNT); + key_value_pairs_.resize(count); + } + + void clear() + { + key_value_pairs_.clear(); + url_.clear(); + } + + friend std::ostream& operator<<(std::ostream& os, const query_string& qs) + { + os << "[ "; + for(size_t i = 0; i < qs.key_value_pairs_.size(); ++i) { + if (i) + os << ", "; + os << qs.key_value_pairs_[i]; + } + os << " ]"; + return os; + + } + + char* get (const std::string& name) const + { + char* ret = qs_k2v(name.c_str(), key_value_pairs_.data(), key_value_pairs_.size()); + return ret; + } + + std::vector get_list (const std::string& name) const + { + std::vector ret; + std::string plus = name + "[]"; + char* element = nullptr; + + int count = 0; + while(1) + { + element = qs_k2v(plus.c_str(), key_value_pairs_.data(), key_value_pairs_.size(), count++); + if (!element) + break; + ret.push_back(element); + } + return ret; + } + + std::unordered_map get_dict (const std::string& name) const + { + std::unordered_map ret; + + int count = 0; + while(1) + { + if (auto element = qs_dict_name2kv(name.c_str(), key_value_pairs_.data(), key_value_pairs_.size(), count++)) + ret.insert(*element); + else + break; + } + return ret; + } + + private: + std::string url_; + std::vector key_value_pairs_; + }; + +} // end namespace + + + +#pragma once +#include +#ifdef CROW_ENABLE_SSL +#include +#endif + + +#if BOOST_VERSION >= 107000 +#define GET_IO_SERVICE(s) ((boost::asio::io_context&)(s).get_executor().context()) +#else +#define GET_IO_SERVICE(s) ((s).get_io_service()) +#endif +namespace crow +{ + using namespace boost; + using tcp = asio::ip::tcp; + + struct SocketAdaptor + { + using context = void; + SocketAdaptor(boost::asio::io_service& io_service, context*) + : socket_(io_service) + { + } + + boost::asio::io_service& get_io_service() + { + return GET_IO_SERVICE(socket_); + } + + tcp::socket& raw_socket() + { + return socket_; + } + + tcp::socket& socket() + { + return socket_; + } + + tcp::endpoint remote_endpoint() + { + return socket_.remote_endpoint(); + } + + bool is_open() + { + return socket_.is_open(); + } + + void close() + { + boost::system::error_code ec; + socket_.close(ec); + } + + void shutdown_readwrite() + { + boost::system::error_code ec; + socket_.shutdown(boost::asio::socket_base::shutdown_type::shutdown_both, ec); + } + + void shutdown_write() + { + boost::system::error_code ec; + socket_.shutdown(boost::asio::socket_base::shutdown_type::shutdown_send, ec); + } + + void shutdown_read() + { + boost::system::error_code ec; + socket_.shutdown(boost::asio::socket_base::shutdown_type::shutdown_receive, ec); + } + + template + void start(F f) + { + f(boost::system::error_code()); + } + + tcp::socket socket_; + }; + +#ifdef CROW_ENABLE_SSL + struct SSLAdaptor + { + using context = boost::asio::ssl::context; + using ssl_socket_t = boost::asio::ssl::stream; + SSLAdaptor(boost::asio::io_service& io_service, context* ctx) + : ssl_socket_(new ssl_socket_t(io_service, *ctx)) + { + } + + boost::asio::ssl::stream& socket() + { + return *ssl_socket_; + } + + tcp::socket::lowest_layer_type& + raw_socket() + { + return ssl_socket_->lowest_layer(); + } + + tcp::endpoint remote_endpoint() + { + return raw_socket().remote_endpoint(); + } + + bool is_open() + { + return raw_socket().is_open(); + } + + void close() + { + boost::system::error_code ec; + raw_socket().close(ec); + } + + void shutdown_readwrite() + { + boost::system::error_code ec; + raw_socket().shutdown(boost::asio::socket_base::shutdown_type::shutdown_both, ec); + } + + void shutdown_write() + { + boost::system::error_code ec; + raw_socket().shutdown(boost::asio::socket_base::shutdown_type::shutdown_send, ec); + } + + void shutdown_read() + { + boost::system::error_code ec; + raw_socket().shutdown(boost::asio::socket_base::shutdown_type::shutdown_receive, ec); + } + + boost::asio::io_service& get_io_service() + { + return GET_IO_SERVICE(raw_socket()); + } + + template + void start(F f) + { + ssl_socket_->async_handshake(boost::asio::ssl::stream_base::server, + [f](const boost::system::error_code& ec) { + f(ec); + }); + } + + std::unique_ptr> ssl_socket_; + }; +#endif +} + + + +//This file is generated from nginx/conf/mime.types using nginx_mime2cpp.py +#include +#include + +namespace crow { + std::unordered_map mime_types { + {"shtml", "text/html"}, + {"htm", "text/html"}, + {"html", "text/html"}, + {"css", "text/css"}, + {"xml", "text/xml"}, + {"gif", "image/gif"}, + {"jpg", "image/jpeg"}, + {"jpeg", "image/jpeg"}, + {"js", "application/javascript"}, + {"atom", "application/atom+xml"}, + {"rss", "application/rss+xml"}, + {"mml", "text/mathml"}, + {"txt", "text/plain"}, + {"jad", "text/vnd.sun.j2me.app-descriptor"}, + {"wml", "text/vnd.wap.wml"}, + {"htc", "text/x-component"}, + {"png", "image/png"}, + {"svgz", "image/svg+xml"}, + {"svg", "image/svg+xml"}, + {"tiff", "image/tiff"}, + {"tif", "image/tiff"}, + {"wbmp", "image/vnd.wap.wbmp"}, + {"webp", "image/webp"}, + {"ico", "image/x-icon"}, + {"jng", "image/x-jng"}, + {"bmp", "image/x-ms-bmp"}, + {"woff", "font/woff"}, + {"woff2", "font/woff2"}, + {"ear", "application/java-archive"}, + {"war", "application/java-archive"}, + {"jar", "application/java-archive"}, + {"json", "application/json"}, + {"hqx", "application/mac-binhex40"}, + {"doc", "application/msword"}, + {"pdf", "application/pdf"}, + {"ai", "application/postscript"}, + {"eps", "application/postscript"}, + {"ps", "application/postscript"}, + {"rtf", "application/rtf"}, + {"m3u8", "application/vnd.apple.mpegurl"}, + {"kml", "application/vnd.google-earth.kml+xml"}, + {"kmz", "application/vnd.google-earth.kmz"}, + {"xls", "application/vnd.ms-excel"}, + {"eot", "application/vnd.ms-fontobject"}, + {"ppt", "application/vnd.ms-powerpoint"}, + {"odg", "application/vnd.oasis.opendocument.graphics"}, + {"odp", "application/vnd.oasis.opendocument.presentation"}, + {"ods", "application/vnd.oasis.opendocument.spreadsheet"}, + {"odt", "application/vnd.oasis.opendocument.text"}, + {"pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"}, + {"xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}, + {"docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}, + {"wmlc", "application/vnd.wap.wmlc"}, + {"7z", "application/x-7z-compressed"}, + {"cco", "application/x-cocoa"}, + {"jardiff", "application/x-java-archive-diff"}, + {"jnlp", "application/x-java-jnlp-file"}, + {"run", "application/x-makeself"}, + {"pm", "application/x-perl"}, + {"pl", "application/x-perl"}, + {"pdb", "application/x-pilot"}, + {"prc", "application/x-pilot"}, + {"rar", "application/x-rar-compressed"}, + {"rpm", "application/x-redhat-package-manager"}, + {"sea", "application/x-sea"}, + {"swf", "application/x-shockwave-flash"}, + {"sit", "application/x-stuffit"}, + {"tk", "application/x-tcl"}, + {"tcl", "application/x-tcl"}, + {"crt", "application/x-x509-ca-cert"}, + {"pem", "application/x-x509-ca-cert"}, + {"der", "application/x-x509-ca-cert"}, + {"xpi", "application/x-xpinstall"}, + {"xhtml", "application/xhtml+xml"}, + {"xspf", "application/xspf+xml"}, + {"zip", "application/zip"}, + {"dll", "application/octet-stream"}, + {"exe", "application/octet-stream"}, + {"bin", "application/octet-stream"}, + {"deb", "application/octet-stream"}, + {"dmg", "application/octet-stream"}, + {"img", "application/octet-stream"}, + {"iso", "application/octet-stream"}, + {"msm", "application/octet-stream"}, + {"msp", "application/octet-stream"}, + {"msi", "application/octet-stream"}, + {"kar", "audio/midi"}, + {"midi", "audio/midi"}, + {"mid", "audio/midi"}, + {"mp3", "audio/mpeg"}, + {"ogg", "audio/ogg"}, + {"m4a", "audio/x-m4a"}, + {"ra", "audio/x-realaudio"}, + {"3gp", "video/3gpp"}, + {"3gpp", "video/3gpp"}, + {"ts", "video/mp2t"}, + {"mp4", "video/mp4"}, + {"mpg", "video/mpeg"}, + {"mpeg", "video/mpeg"}, + {"mov", "video/quicktime"}, + {"webm", "video/webm"}, + {"flv", "video/x-flv"}, + {"m4v", "video/x-m4v"}, + {"mng", "video/x-mng"}, + {"asf", "video/x-ms-asf"}, + {"asx", "video/x-ms-asf"}, + {"wmv", "video/x-ms-wmv"}, + {"avi", "video/x-msvideo"} + }; +} + + + +#pragma once + +#include +#include +#include + +namespace crow +{ + struct ci_hash + { + size_t operator()(const std::string& key) const + { + std::size_t seed = 0; + std::locale locale; + + for(auto c : key) + { + boost::hash_combine(seed, std::toupper(c, locale)); + } + + return seed; + } + }; + + struct ci_key_eq + { + bool operator()(const std::string& l, const std::string& r) const + { + return boost::iequals(l, r); + } + }; + + using ci_map = std::unordered_multimap; +} + + + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + + + + +namespace crow +{ + namespace black_magic + { +#ifndef CROW_MSVC_WORKAROUND + struct OutOfRange + { + OutOfRange(unsigned /*pos*/, unsigned /*length*/) {} + }; + constexpr unsigned requires_in_range( unsigned i, unsigned len ) + { + return i >= len ? throw OutOfRange(i, len) : i; + } + + 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) + { + 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); + } + + constexpr bool is_equ_p(const char* a, const char* b, unsigned n) + { + return + *a == 0 && *b == 0 && n == 0 + ? true : + (*a == 0 || *b == 0) + ? false : + n == 0 + ? true : + *a != *b + ? false : + is_equ_p(a+1, b+1, n-1); + } + + constexpr bool is_equ_n(const_str a, unsigned ai, const_str b, unsigned bi, unsigned n) + { + 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); + } + + constexpr bool is_int(const_str s, unsigned i) + { + return is_equ_n(s, i, "", 0, 5); + } + + constexpr bool is_uint(const_str s, unsigned i) + { + return is_equ_n(s, i, "", 0, 6); + } + + constexpr bool is_float(const_str s, unsigned i) + { + return is_equ_n(s, i, "", 0, 7) || + is_equ_n(s, i, "", 0, 8); + } + + constexpr bool is_str(const_str s, unsigned i) + { + return is_equ_n(s, i, "", 0, 5) || + is_equ_n(s, i, "", 0, 8); + } + + constexpr bool is_path(const_str s, unsigned i) + { + return is_equ_n(s, i, "", 0, 6); + } +#endif + template + struct parameter_tag + { + static const int value = 0; + }; +#define CROW_INTERNAL_PARAMETER_TAG(t, i) \ +template <> \ +struct parameter_tag \ +{ \ + static const int value = i; \ +} + CROW_INTERNAL_PARAMETER_TAG(int, 1); + CROW_INTERNAL_PARAMETER_TAG(char, 1); + CROW_INTERNAL_PARAMETER_TAG(short, 1); + CROW_INTERNAL_PARAMETER_TAG(long, 1); + CROW_INTERNAL_PARAMETER_TAG(long long, 1); + CROW_INTERNAL_PARAMETER_TAG(unsigned int, 2); + CROW_INTERNAL_PARAMETER_TAG(unsigned char, 2); + CROW_INTERNAL_PARAMETER_TAG(unsigned short, 2); + CROW_INTERNAL_PARAMETER_TAG(unsigned long, 2); + CROW_INTERNAL_PARAMETER_TAG(unsigned long long, 2); + CROW_INTERNAL_PARAMETER_TAG(double, 3); + CROW_INTERNAL_PARAMETER_TAG(std::string, 4); +#undef CROW_INTERNAL_PARAMETER_TAG + template + struct compute_parameter_tag_from_args_list; + + template <> + struct compute_parameter_tag_from_args_list<> + { + static const int value = 0; + }; + + template + struct compute_parameter_tag_from_args_list + { + static const int sub_value = + compute_parameter_tag_from_args_list::value; + static const int value = + parameter_tag::type>::value + ? sub_value* 6 + parameter_tag::type>::value + : sub_value; + }; + + static inline bool is_parameter_tag_compatible(uint64_t a, uint64_t b) + { + if (a == 0) + return b == 0; + if (b == 0) + return a == 0; + int sa = a%6; + int sb = a%6; + if (sa == 5) sa = 4; + if (sb == 5) sb = 4; + if (sa != sb) + return false; + return is_parameter_tag_compatible(a/6, b/6); + } + + static inline unsigned find_closing_tag_runtime(const char* s, unsigned p) + { + return + s[p] == 0 + ? throw std::runtime_error("unmatched tag <") : + s[p] == '>' + ? p : find_closing_tag_runtime(s, p + 1); + } + + static inline uint64_t get_parameter_tag_runtime(const char* s, unsigned p = 0) + { + return + s[p] == 0 + ? 0 : + s[p] == '<' ? ( + std::strncmp(s+p, "", 5) == 0 + ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 1 : + std::strncmp(s+p, "", 6) == 0 + ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 2 : + (std::strncmp(s+p, "", 7) == 0 || + std::strncmp(s+p, "", 8) == 0) + ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 3 : + (std::strncmp(s+p, "", 5) == 0 || + std::strncmp(s+p, "", 8) == 0) + ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 4 : + std::strncmp(s+p, "", 6) == 0 + ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 5 : + throw std::runtime_error("invalid parameter type") + ) : + get_parameter_tag_runtime(s, p+1); + } +#ifndef CROW_MSVC_WORKAROUND + 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); + } +#endif + + 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); + + template + static int __test(...); + + static constexpr bool value = sizeof(__test(0)) == sizeof(char); + }; + + + 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