aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--.travis.yml11
-rw-r--r--CMakeLists.txt29
-rw-r--r--README.md43
-rw-r--r--amalgamate/crow_all.h4090
-rw-r--r--amalgamate/merge_all.py3
-rw-r--r--conanfile.py28
-rw-r--r--examples/CMakeLists.txt14
-rw-r--r--examples/example.cpp26
-rw-r--r--examples/example_chat.cpp4
-rw-r--r--examples/example_test.py18
-rw-r--r--examples/example_vs.cpp1
-rw-r--r--examples/example_with_all.cpp6
-rw-r--r--examples/websocket/example_ws.cpp48
-rw-r--r--examples/websocket/templates/ws.html42
-rw-r--r--include/crow.h225
-rw-r--r--include/crow/TinySHA1.hpp196
-rw-r--r--include/crow/app.h242
-rw-r--r--include/crow/ci_map.h (renamed from include/ci_map.h)0
-rw-r--r--include/crow/common.h (renamed from include/common.h)51
-rw-r--r--include/crow/dumb_timer_queue.h (renamed from include/dumb_timer_queue.h)2
-rw-r--r--include/crow/http_connection.h (renamed from include/http_connection.h)61
-rw-r--r--include/crow/http_parser_merged.h (renamed from include/http_parser_merged.h)804
-rw-r--r--include/crow/http_request.h (renamed from include/http_request.h)25
-rw-r--r--include/crow/http_response.h (renamed from include/http_response.h)7
-rw-r--r--include/crow/http_server.h (renamed from include/http_server.h)77
-rw-r--r--include/crow/json.h (renamed from include/json.h)86
-rw-r--r--include/crow/logging.h (renamed from include/logging.h)34
-rw-r--r--include/crow/middleware.h (renamed from include/middleware.h)6
-rw-r--r--include/crow/middleware_context.h (renamed from include/middleware_context.h)6
-rw-r--r--include/crow/mustache.h (renamed from include/mustache.h)13
-rw-r--r--include/crow/parser.h (renamed from include/parser.h)9
-rw-r--r--include/crow/query_string.h (renamed from include/query_string.h)69
-rw-r--r--include/crow/routing.h (renamed from include/routing.h)216
-rw-r--r--include/crow/settings.h (renamed from include/settings.h)12
-rw-r--r--include/crow/socket_adaptors.h (renamed from include/socket_adaptors.h)26
-rw-r--r--include/crow/utility.h (renamed from include/utility.h)49
-rw-r--r--include/crow/websocket.h506
-rw-r--r--tests/template/mustachetest.cpp4
-rw-r--r--tests/unittest.cpp47
40 files changed, 4890 insertions, 2249 deletions
diff --git a/.gitignore b/.gitignore
index 6dcb0a2..cfe8b64 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,3 +33,6 @@ build
.directory
crow_all.h
+
+# conan.io
+build/
diff --git a/.travis.yml b/.travis.yml
index c4c48dc..d7a50c4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,7 @@
language: cpp
sudo: false
+cache: ccache
notifications:
irc: "chat.freenode.net##crow"
@@ -11,14 +12,22 @@ compiler:
env:
matrix:
- COMPILER=g++-4.8 CCOMPILER=gcc-4.8 PUSH_COVERAGE=ON
+ - COMPILER=g++-4.9 CCOMPILER=gcc-4.9
+ - COMPILER=g++-5 CCOMPILER=gcc-5
+ - COMPILER=clang++-3.6 CCOMPILER=clang-3.6
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- boost-latest
+ - llvm-toolchain-precise
+ - llvm-toolchain-precise-3.6
packages:
- g++-4.8
+ - g++-4.9
+ - g++-5
+ - clang-3.6
- libboost1.55-all-dev
- python-pip
@@ -36,4 +45,4 @@ script: make -j2 && ctest -j2
after_success:
- cd ..
- - if [ "PUSH_COVERAGE" == "ON" ]; then coveralls --gcov gcov-4.8 -i include --gcov-options '\-lp'; fi
+ - if [ "$PUSH_COVERAGE" == "ON" ]; then coveralls --gcov gcov-4.8 -i include --gcov-options '\-lp'; fi
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 07a058b..2f0eb3f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,8 +1,27 @@
cmake_minimum_required(VERSION 2.8)
project (crow_all)
+
+if(EXISTS "${CMAKE_BINARY_DIR}/conanbuildinfo.cmake")
+include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
+conan_basic_setup()
+endif()
+
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
find_package(Tcmalloc)
find_package(Threads)
+find_package(OpenSSL)
+if(OPENSSL_FOUND)
+ include_directories(${OPENSSL_INCLUDE_DIR})
+endif()
+
+find_program(CCACHE_FOUND ccache)
+if(CCACHE_FOUND)
+ message("Found ccache ${CCACHE_FOUND}")
+ message("Using ccache to speed up compilation")
+ set(ENV{CCACHE_CPP2} "yes")
+ set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
+ set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
+endif(CCACHE_FOUND)
if (NOT CMAKE_BUILD_TYPE)
message(STATUS "No build type selected, default to Release")
@@ -12,21 +31,21 @@ endif()
if (MSVC)
set(Boost_USE_STATIC_LIBS "On")
-find_package( Boost 1.52 COMPONENTS date_time filesystem system thread regex REQUIRED )
+find_package( Boost 1.52 COMPONENTS system thread regex REQUIRED )
else()
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++1y")
-find_package( Boost 1.52 COMPONENTS date_time filesystem system thread REQUIRED )
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++1y -pedantic -Wextra")
+find_package( Boost 1.52 COMPONENTS system thread REQUIRED )
endif()
include_directories( ${Boost_INCLUDE_DIR} )
-set(PROJECT_INCLUDE_DIR
+set(PROJECT_INCLUDE_DIR
${PROJECT_SOURCE_DIR}/include
)
include_directories("${PROJECT_INCLUDE_DIR}")
include_directories("${PROJECT_SOURCE_DIR}")
-
+
#add_subdirectory(src)
add_subdirectory(examples)
if (MSVC)
diff --git a/README.md b/README.md
index 60a9af5..f6261b4 100644
--- a/README.md
+++ b/README.md
@@ -29,10 +29,12 @@ int main()
- ![Benchmark Result in one chart](https://docs.google.com/spreadsheets/d/1KidO9XpuwCRZ2p_JRDJj2aep61H8Sh_KDOhApizv4LE/pubchart?oid=2041467789&format=image)
- More data on [crow-benchmark](https://github.com/ipkn/crow-benchmark)
- Fast built-in JSON parser (crow::json)
+ - You can also use [json11](https://github.com/dropbox/json11) or [rapidjson](https://github.com/miloyip/rapidjson) for better speed or readability
- [Mustache](http://mustache.github.io/) based templating library (crow::mustache)
- Header only
- - Provide an amalgamated header file `crow_all.h' with every features
+ - Provide an amalgamated header file `crow_all.h` with every features
- Middleware support
+ - Websocket support
## Still in development
- ~~Built-in ORM~~
@@ -127,6 +129,35 @@ ctest
Crow uses the following libraries.
+ http-parser
+
+ https://github.com/nodejs/http-parser
+
+ http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright
+ Igor Sysoev.
+
+ Additional changes are licensed under the same terms as NGINX and
+ copyright Joyent, Inc. and other Node contributors. All rights reserved.
+
+ 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.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+
qs_parse
https://github.com/bartgrantham/qs_parse
@@ -141,3 +172,13 @@ Crow uses the following libraries.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
+
+ TinySHA1
+
+ https://github.com/mohaps/TinySHA1
+
+ TinySHA1 - a header only implementation of the SHA1 algorithm. Based on the implementation in boost::uuid::details
+
+ Copyright (c) 2012-22 SAURAV MOHAPATRA mohaps@gmail.com
+ 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.
diff --git a/amalgamate/crow_all.h b/amalgamate/crow_all.h
index 74676ef..0c88e5d 100644
--- a/amalgamate/crow_all.h
+++ b/amalgamate/crow_all.h
@@ -1,3 +1,911 @@
+/*
+ *
+ * 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 <mohaps@gmail.com>
+ *
+ * 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 <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <stdint.h>
+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<const uint8_t*>(start);
+ const uint8_t* finish = static_cast<const uint8_t*>(end);
+ while(begin != finish) {
+ processByte(*begin);
+ begin++;
+ }
+ return *this;
+ }
+ SHA1& processBytes(const void* const data, size_t len) {
+ const uint8_t* block = static_cast<const uint8_t*>(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<unsigned char>((bitCount>>24) & 0xFF));
+ processByte( static_cast<unsigned char>((bitCount>>16) & 0xFF));
+ processByte( static_cast<unsigned char>((bitCount>>8 ) & 0xFF));
+ processByte( static_cast<unsigned char>((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
+// 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
+*/
+#define CROW_LOG_LEVEL 1
+
+
+// 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 <cstdint>
+#include <stdexcept>
+#include <tuple>
+#include <type_traits>
+#include <cstring>
+#include <functional>
+#include <string>
+
+
+
+
+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, "<int>", 0, 5);
+ }
+
+ constexpr bool is_uint(const_str s, unsigned i)
+ {
+ return is_equ_n(s, i, "<uint>", 0, 6);
+ }
+
+ constexpr bool is_float(const_str s, unsigned i)
+ {
+ return is_equ_n(s, i, "<float>", 0, 7) ||
+ is_equ_n(s, i, "<double>", 0, 8);
+ }
+
+ constexpr bool is_str(const_str s, unsigned i)
+ {
+ return is_equ_n(s, i, "<str>", 0, 5) ||
+ is_equ_n(s, i, "<string>", 0, 8);
+ }
+
+ constexpr bool is_path(const_str s, unsigned i)
+ {
+ return is_equ_n(s, i, "<path>", 0, 6);
+ }
+#endif
+ template <typename T>
+ struct parameter_tag
+ {
+ static const int value = 0;
+ };
+#define CROW_INTERNAL_PARAMETER_TAG(t, i) \
+template <> \
+struct parameter_tag<t> \
+{ \
+ 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 <typename ... Args>
+ struct compute_parameter_tag_from_args_list;
+
+ template <>
+ struct compute_parameter_tag_from_args_list<>
+ {
+ static const int value = 0;
+ };
+
+ template <typename Arg, typename ... Args>
+ struct compute_parameter_tag_from_args_list<Arg, Args...>
+ {
+ static const int sub_value =
+ compute_parameter_tag_from_args_list<Args...>::value;
+ static const int value =
+ parameter_tag<typename std::decay<Arg>::type>::value
+ ? sub_value* 6 + parameter_tag<typename std::decay<Arg>::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, "<int>", 5) == 0
+ ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 1 :
+ std::strncmp(s+p, "<uint>", 6) == 0
+ ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 2 :
+ (std::strncmp(s+p, "<float>", 7) == 0 ||
+ std::strncmp(s+p, "<double>", 8) == 0)
+ ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 3 :
+ (std::strncmp(s+p, "<str>", 5) == 0 ||
+ std::strncmp(s+p, "<string>", 8) == 0)
+ ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 4 :
+ std::strncmp(s+p, "<path>", 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 <typename ... T>
+ struct S
+ {
+ template <typename U>
+ using push = S<U, T...>;
+ template <typename U>
+ using push_back = S<T..., U>;
+ template <template<typename ... Args> class U>
+ using rebind = U<T...>;
+ };
+template <typename F, typename Set>
+ struct CallHelper;
+ template <typename F, typename ...Args>
+ struct CallHelper<F, S<Args...>>
+ {
+ template <typename F1, typename ...Args1, typename =
+ decltype(std::declval<F1>()(std::declval<Args1>()...))
+ >
+ static char __test(int);
+
+ template <typename ...>
+ static int __test(...);
+
+ static constexpr bool value = sizeof(__test<F, Args...>(0)) == sizeof(char);
+ };
+
+
+ template <int N>
+ 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 <uint64_t Tag>
+ struct arguments
+ {
+ using subarguments = typename arguments<Tag/6>::type;
+ using type =
+ typename subarguments::template push<typename single_tag_to_type<Tag%6>::type>;
+ };
+
+ template <>
+ struct arguments<0>
+ {
+ using type = S<>;
+ };
+
+ template <typename ... T>
+ struct last_element_type
+ {
+ using type = typename std::tuple_element<sizeof...(T)-1, std::tuple<T...>>::type;
+ };
+
+
+ template <>
+ struct last_element_type<>
+ {
+ };
+
+
+ // from http://stackoverflow.com/questions/13072359/c11-compile-time-array-with-logarithmic-evaluation-depth
+ template<class T> using Invoke = typename T::type;
+
+ template<unsigned...> struct seq{ using type = seq; };
+
+ template<class S1, class S2> struct concat;
+
+ template<unsigned... I1, unsigned... I2>
+ struct concat<seq<I1...>, seq<I2...>>
+ : seq<I1..., (sizeof...(I1)+I2)...>{};
+
+ template<class S1, class S2>
+ using Concat = Invoke<concat<S1, S2>>;
+
+ template<unsigned N> struct gen_seq;
+ template<unsigned N> using GenSeq = Invoke<gen_seq<N>>;
+
+ template<unsigned N>
+ struct gen_seq : Concat<GenSeq<N/2>, GenSeq<N - N/2>>{};
+
+ template<> struct gen_seq<0> : seq<>{};
+ template<> struct gen_seq<1> : seq<0>{};
+
+ template <typename Seq, typename Tuple>
+ struct pop_back_helper;
+
+ template <unsigned ... N, typename Tuple>
+ struct pop_back_helper<seq<N...>, Tuple>
+ {
+ template <template <typename ... Args> class U>
+ using rebind = U<typename std::tuple_element<N, Tuple>::type...>;
+ };
+
+ template <typename ... T>
+ struct pop_back //: public pop_back_helper<typename gen_seq<sizeof...(T)-1>::type, std::tuple<T...>>
+ {
+ template <template <typename ... Args> class U>
+ using rebind = typename pop_back_helper<typename gen_seq<sizeof...(T)-1>::type, std::tuple<T...>>::template rebind<U>;
+ };
+
+ template <>
+ struct pop_back<>
+ {
+ template <template <typename ... Args> class U>
+ using rebind = U<>;
+ };
+
+ // from http://stackoverflow.com/questions/2118541/check-if-c0x-parameter-pack-contains-a-type
+ template < typename Tp, typename... List >
+ struct contains : std::true_type {};
+
+ template < typename Tp, typename Head, typename... Rest >
+ struct contains<Tp, Head, Rest...>
+ : std::conditional< std::is_same<Tp, Head>::value,
+ std::true_type,
+ contains<Tp, Rest...>
+ >::type {};
+
+ template < typename Tp >
+ struct contains<Tp> : std::false_type {};
+
+ template <typename T>
+ struct empty_context
+ {
+ };
+
+ template <typename T>
+ struct promote
+ {
+ using type = T;
+ };
+
+#define CROW_INTERNAL_PROMOTE_TYPE(t1, t2) \
+ template<> \
+ struct promote<t1> \
+ { \
+ using type = t2; \
+ }
+
+ CROW_INTERNAL_PROMOTE_TYPE(char, int64_t);
+ CROW_INTERNAL_PROMOTE_TYPE(short, int64_t);
+ CROW_INTERNAL_PROMOTE_TYPE(int, int64_t);
+ CROW_INTERNAL_PROMOTE_TYPE(long, int64_t);
+ CROW_INTERNAL_PROMOTE_TYPE(long long, int64_t);
+ CROW_INTERNAL_PROMOTE_TYPE(unsigned char, uint64_t);
+ CROW_INTERNAL_PROMOTE_TYPE(unsigned short, uint64_t);
+ CROW_INTERNAL_PROMOTE_TYPE(unsigned int, uint64_t);
+ CROW_INTERNAL_PROMOTE_TYPE(unsigned long, uint64_t);
+ CROW_INTERNAL_PROMOTE_TYPE(unsigned long long, uint64_t);
+ CROW_INTERNAL_PROMOTE_TYPE(float, double);
+#undef CROW_INTERNAL_PROMOTE_TYPE
+
+ template <typename T>
+ using promote_t = typename promote<T>::type;
+
+ } // namespace black_magic
+
+ namespace detail
+ {
+
+ template <class T, std::size_t N, class... Args>
+ struct get_index_of_element_from_tuple_by_type_impl
+ {
+ static constexpr auto value = N;
+ };
+
+ template <class T, std::size_t N, class... Args>
+ struct get_index_of_element_from_tuple_by_type_impl<T, N, T, Args...>
+ {
+ static constexpr auto value = N;
+ };
+
+ template <class T, std::size_t N, class U, class... Args>
+ struct get_index_of_element_from_tuple_by_type_impl<T, N, U, Args...>
+ {
+ static constexpr auto value = get_index_of_element_from_tuple_by_type_impl<T, N + 1, Args...>::value;
+ };
+
+ } // namespace detail
+
+ namespace utility
+ {
+ template <class T, class... Args>
+ T& get_element_by_type(std::tuple<Args...>& t)
+ {
+ return std::get<detail::get_index_of_element_from_tuple_by_type_impl<T, 0, Args...>::value>(t);
+ }
+
+ template<typename T>
+ struct function_traits;
+
+#ifndef CROW_MSVC_WORKAROUND
+ template<typename T>
+ struct function_traits : public function_traits<decltype(&T::operator())>
+ {
+ using parent_t = function_traits<decltype(&T::operator())>;
+ static const size_t arity = parent_t::arity;
+ using result_type = typename parent_t::result_type;
+ template <size_t i>
+ using arg = typename parent_t::template arg<i>;
+
+ };
+#endif
+
+ template<typename ClassType, typename R, typename ...Args>
+ struct function_traits<R(ClassType::*)(Args...) const>
+ {
+ static const size_t arity = sizeof...(Args);
+
+ typedef R result_type;
+
+ template <size_t i>
+ using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
+ };
+
+ template<typename ClassType, typename R, typename ...Args>
+ struct function_traits<R(ClassType::*)(Args...)>
+ {
+ static const size_t arity = sizeof...(Args);
+
+ typedef R result_type;
+
+ template <size_t i>
+ using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
+ };
+
+ template<typename R, typename ...Args>
+ struct function_traits<std::function<R(Args...)>>
+ {
+ static const size_t arity = sizeof...(Args);
+
+ typedef R result_type;
+
+ template <size_t i>
+ using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
+ };
+
+ inline static std::string base64encode(const char* data, size_t size, const char* key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
+ {
+ std::string ret;
+ ret.resize((size+2) / 3 * 4);
+ auto it = ret.begin();
+ while(size >= 3)
+ {
+ *it++ = key[(((unsigned char)*data)&0xFC)>>2];
+ unsigned char h = (((unsigned char)*data++) & 0x03) << 4;
+ *it++ = key[h|((((unsigned char)*data)&0xF0)>>4)];
+ h = (((unsigned char)*data++) & 0x0F) << 2;
+ *it++ = key[h|((((unsigned char)*data)&0xC0)>>6)];
+ *it++ = key[((unsigned char)*data++)&0x3F];
+
+ size -= 3;
+ }
+ if (size == 1)
+ {
+ *it++ = key[(((unsigned char)*data)&0xFC)>>2];
+ unsigned char h = (((unsigned char)*data++) & 0x03) << 4;
+ *it++ = key[h];
+ *it++ = '=';
+ *it++ = '=';
+ }
+ else if (size == 2)
+ {
+ *it++ = key[(((unsigned char)*data)&0xFC)>>2];
+ unsigned char h = (((unsigned char)*data++) & 0x03) << 4;
+ *it++ = key[h|((((unsigned char)*data)&0xF0)>>4)];
+ h = (((unsigned char)*data++) & 0x0F) << 2;
+ *it++ = key[h];
+ *it++ = '=';
+ }
+ return ret;
+ }
+
+ inline static std::string base64encode_urlsafe(const char* data, size_t size)
+ {
+ return base64encode(data, size, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
+ }
+
+
+ } // namespace utility
+}
+
+
+
+#pragma once
+#include <boost/asio.hpp>
+#ifdef CROW_ENABLE_SSL
+#include <boost/asio/ssl.hpp>
+#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 socket_.get_io_service();
+ }
+
+ 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()
+ {
+ socket_.close();
+ }
+
+ template <typename F>
+ 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<tcp::socket>;
+ SSLAdaptor(boost::asio::io_service& io_service, context* ctx)
+ : ssl_socket_(new ssl_socket_t(io_service, *ctx))
+ {
+ }
+
+ boost::asio::ssl::stream<tcp::socket>& 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()
+ {
+ raw_socket().close();
+ }
+
+ boost::asio::io_service& get_io_service()
+ {
+ return raw_socket().get_io_service();
+ }
+
+ template <typename F>
+ 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<boost::asio::ssl::stream<tcp::socket>> ssl_socket_;
+ };
+#endif
+}
+
+
+
#pragma once
#include <stdio.h>
@@ -5,7 +913,10 @@
#include <string>
#include <vector>
#include <iostream>
+#include <boost/optional.hpp>
+namespace crow
+{
// ----------------------------------------------------------------------------
// qs_parse (modified)
// https://github.com/bartgrantham/qs_parse
@@ -195,6 +1106,37 @@ inline char * qs_k2v(const char * key, char * const * qs_kv, int qs_kv_size, int
return NULL;
}
+inline boost::optional<std::pair<std::string, std::string>> 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;
+
+ name_len = strlen(dict_name) + 1;
+
+#ifdef _qsSORTING
+// TODO: binary search for key in the sorted qs_kv
+#else // _qsSORTING
+ for(i=0; i<qs_kv_size; i++)
+ {
+ // we rely on the unambiguous '=' to find the value in our k/v pair
+ if ( qs_strncmp(dict_name, qs_kv[i], name_len) == 0)
+ {
+ skip = strcspn(qs_kv[i], "=");
+ if ( qs_kv[i][skip] == '=' )
+ skip++;
+ // return (zero-char value) ? ptr to trailing '\0' : ptr to value
+ if(nth == 0)
+ return boost::make_optional(std::make_pair(std::string(qs_kv[i] + 1),
+ std::string(qs_kv[i] + skip)));
+ else
+ --nth;
+ }
+ }
+#endif // _qsSORTING
+
+ return boost::none;
+}
+
inline char * qs_scanvalue(const char * key, const char * qs, char * val, size_t val_len)
{
@@ -231,6 +1173,7 @@ inline char * qs_scanvalue(const char * key, const char * qs, char * val, size_t
return val;
}
+}
// ----------------------------------------------------------------------------
@@ -334,6 +1277,25 @@ namespace crow
}
+ std::vector<std::pair<std::string, std::string>> get_dict (const std::string& name) const
+ {
+ std::vector<std::pair<std::string, std::string>> 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.push_back(*element);
+ else
+ break;
+ }
+ return ret;
+ }
+
+
+
+
+
private:
std::string url_;
std::vector<char*> key_value_pairs_;
@@ -345,6 +1307,152 @@ namespace crow
#pragma once
+#include <string>
+#include <cstdio>
+#include <cstdlib>
+#include <ctime>
+#include <iostream>
+#include <sstream>
+
+
+
+
+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;
+
+#ifdef _MSC_VER
+ 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 <typename T>
+ 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
+
//#define CROW_JSON_NO_ERROR_CHECK
#include <string>
@@ -357,6 +1465,9 @@ namespace crow
#include <boost/operators.hpp>
#include <vector>
+
+
+
#if defined(__GNUG__) || defined(__clang__)
#define crow_json_likely(x) __builtin_expect(x, 1)
#define crow_json_unlikely(x) __builtin_expect(x, 0)
@@ -437,7 +1548,7 @@ namespace crow
case type::Object: return "Object";
default: return "Unknown";
}
- };
+ }
class rvalue;
rvalue load(const char* data, size_t size);
@@ -476,6 +1587,8 @@ namespace crow
s_ = r.s_;
e_ = r.e_;
owned_ = r.owned_;
+ if (r.owned_)
+ r.owned_ = 0;
return *this;
}
@@ -509,7 +1622,7 @@ namespace crow
return os;
}
private:
- void force(char* s, uint32_t length)
+ void force(char* s, uint32_t /*length*/)
{
s_ = s;
owned_ = 1;
@@ -607,6 +1720,11 @@ namespace crow
return i();
}
+ explicit operator uint64_t() const
+ {
+ return u();
+ }
+
explicit operator int() const
{
return (int)i();
@@ -639,6 +1757,20 @@ namespace crow
return boost::lexical_cast<int64_t>(start_, end_-start_);
}
+ uint64_t u() const
+ {
+#ifndef CROW_JSON_NO_ERROR_CHECK
+ switch (t()) {
+ case type::Number:
+ case type::String:
+ return boost::lexical_cast<uint64_t>(start_, end_-start_);
+ default:
+ throw std::runtime_error(std::string("expected number, got: ") + get_type_str(t()));
+ }
+#endif
+ return boost::lexical_cast<uint64_t>(start_, end_-start_);
+ }
+
double d() const
{
#ifndef CROW_JSON_NO_ERROR_CHECK
@@ -1016,7 +2148,7 @@ namespace crow
//static const char* escaped = "\"\\/\b\f\n\r\t";
struct Parser
{
- Parser(char* data, size_t size)
+ Parser(char* data, size_t /*size*/)
: data(data)
{
}
@@ -1438,17 +2570,16 @@ namespace crow
s = r.s();
return;
case type::List:
- l = std::move(std::unique_ptr<std::vector<wvalue>>(new std::vector<wvalue>{}));
+ l = std::unique_ptr<std::vector<wvalue>>(new std::vector<wvalue>{});
l->reserve(r.size());
for(auto it = r.begin(); it != r.end(); ++it)
l->emplace_back(*it);
return;
case type::Object:
- o = std::move(
- std::unique_ptr<
+ o = std::unique_ptr<
std::unordered_map<std::string, wvalue>
>(
- new std::unordered_map<std::string, wvalue>{}));
+ new std::unordered_map<std::string, wvalue>{});
for(auto it = r.begin(); it != r.end(); ++it)
o->emplace(it->key(), *it);
return;
@@ -1594,7 +2725,7 @@ namespace crow
reset();
t_ = type::List;
if (!l)
- l = std::move(std::unique_ptr<std::vector<wvalue>>(new std::vector<wvalue>{}));
+ l = std::unique_ptr<std::vector<wvalue>>(new std::vector<wvalue>{});
l->clear();
l->resize(v.size());
size_t idx = 0;
@@ -1611,7 +2742,7 @@ namespace crow
reset();
t_ = type::List;
if (!l)
- l = std::move(std::unique_ptr<std::vector<wvalue>>(new std::vector<wvalue>{}));
+ l = std::unique_ptr<std::vector<wvalue>>(new std::vector<wvalue>{});
if (l->size() < index+1)
l->resize(index+1);
return (*l)[index];
@@ -1632,11 +2763,10 @@ namespace crow
reset();
t_ = type::Object;
if (!o)
- o = std::move(
- std::unique_ptr<
+ o = std::unique_ptr<
std::unordered_map<std::string, wvalue>
>(
- new std::unordered_map<std::string, wvalue>{}));
+ new std::unordered_map<std::string, wvalue>{});
return (*o)[str];
}
@@ -2291,7 +3421,11 @@ namespace crow
inline std::string default_loader(const std::string& filename)
{
- std::ifstream inf(detail::get_template_base_directory_ref() + filename);
+ std::string path = detail::get_template_base_directory_ref();
+ if (!(path.back() == '/' || path.back() == '\\'))
+ path += '/';
+ path += filename;
+ std::ifstream inf(path);
if (!inf)
return {};
return {std::istreambuf_iterator<char>(inf), std::istreambuf_iterator<char>()};
@@ -2322,6 +3456,11 @@ namespace crow
detail::get_loader_ref() = std::move(loader);
}
+ inline std::string load_text(const std::string& filename)
+ {
+ return detail::get_loader_ref()(filename);
+ }
+
inline template_t load(const std::string& filename)
{
return compile(detail::get_loader_ref()(filename));
@@ -2352,16 +3491,16 @@ namespace crow
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
-#ifndef http_parser_h
-#define http_parser_h
+#ifndef CROW_http_parser_h
+#define CROW_http_parser_h
#ifdef __cplusplus
extern "C" {
#endif
/* Also update SONAME in the Makefile whenever you change these. */
-#define HTTP_PARSER_VERSION_MAJOR 2
-#define HTTP_PARSER_VERSION_MINOR 3
-#define HTTP_PARSER_VERSION_PATCH 0
+#define CROW_HTTP_PARSER_VERSION_MAJOR 2
+#define CROW_HTTP_PARSER_VERSION_MINOR 3
+#define CROW_HTTP_PARSER_VERSION_PATCH 0
#include <sys/types.h>
#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600)
@@ -2382,8 +3521,8 @@ typedef unsigned __int64 uint64_t;
/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
* faster
*/
-#ifndef HTTP_PARSER_STRICT
-# define HTTP_PARSER_STRICT 1
+#ifndef CROW_HTTP_PARSER_STRICT
+# define CROW_HTTP_PARSER_STRICT 1
#endif
/* Maximium header size allowed. If the macro is not defined
@@ -2393,8 +3532,8 @@ typedef unsigned __int64 uint64_t;
* the effective limit on the size of the header, define the macro
* to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff)
*/
-#ifndef HTTP_MAX_HEADER_SIZE
-# define HTTP_MAX_HEADER_SIZE (80*1024)
+#ifndef CROW_HTTP_MAX_HEADER_SIZE
+# define CROW_HTTP_MAX_HEADER_SIZE (80*1024)
#endif
typedef struct http_parser http_parser;
@@ -2419,46 +3558,46 @@ typedef int (*http_cb) (http_parser*);
/* Request Methods */
-#define HTTP_METHOD_MAP(XX) \
- XX(0, DELETE, DELETE) \
- XX(1, GET, GET) \
- XX(2, HEAD, HEAD) \
- XX(3, POST, POST) \
- XX(4, PUT, PUT) \
+#define CROW_HTTP_METHOD_MAP(CROW_XX) \
+ CROW_XX(0, DELETE, DELETE) \
+ CROW_XX(1, GET, GET) \
+ CROW_XX(2, HEAD, HEAD) \
+ CROW_XX(3, POST, POST) \
+ CROW_XX(4, PUT, PUT) \
/* pathological */ \
- XX(5, CONNECT, CONNECT) \
- XX(6, OPTIONS, OPTIONS) \
- XX(7, TRACE, TRACE) \
+ CROW_XX(5, CONNECT, CONNECT) \
+ CROW_XX(6, OPTIONS, OPTIONS) \
+ CROW_XX(7, TRACE, TRACE) \
/* webdav */ \
- XX(8, COPY, COPY) \
- XX(9, LOCK, LOCK) \
- XX(10, MKCOL, MKCOL) \
- XX(11, MOVE, MOVE) \
- XX(12, PROPFIND, PROPFIND) \
- XX(13, PROPPATCH, PROPPATCH) \
- XX(14, SEARCH, SEARCH) \
- XX(15, UNLOCK, UNLOCK) \
+ CROW_XX(8, COPY, COPY) \
+ CROW_XX(9, LOCK, LOCK) \
+ CROW_XX(10, MKCOL, MKCOL) \
+ CROW_XX(11, MOVE, MOVE) \
+ CROW_XX(12, PROPFIND, PROPFIND) \
+ CROW_XX(13, PROPPATCH, PROPPATCH) \
+ CROW_XX(14, SEARCH, SEARCH) \
+ CROW_XX(15, UNLOCK, UNLOCK) \
/* subversion */ \
- XX(16, REPORT, REPORT) \
- XX(17, MKACTIVITY, MKACTIVITY) \
- XX(18, CHECKOUT, CHECKOUT) \
- XX(19, MERGE, MERGE) \
+ CROW_XX(16, REPORT, REPORT) \
+ CROW_XX(17, MKACTIVITY, MKACTIVITY) \
+ CROW_XX(18, CHECKOUT, CHECKOUT) \
+ CROW_XX(19, MERGE, MERGE) \
/* upnp */ \
- XX(20, MSEARCH, M-SEARCH) \
- XX(21, NOTIFY, NOTIFY) \
- XX(22, SUBSCRIBE, SUBSCRIBE) \
- XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \
+ CROW_XX(20, MSEARCH, M-SEARCH) \
+ CROW_XX(21, NOTIFY, NOTIFY) \
+ CROW_XX(22, SUBSCRIBE, SUBSCRIBE) \
+ CROW_XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \
/* RFC-5789 */ \
- XX(24, PATCH, PATCH) \
- XX(25, PURGE, PURGE) \
+ CROW_XX(24, PATCH, PATCH) \
+ CROW_XX(25, PURGE, PURGE) \
/* CalDAV */ \
- XX(26, MKCALENDAR, MKCALENDAR) \
+ CROW_XX(26, MKCALENDAR, MKCALENDAR) \
enum http_method
{
-#define XX(num, name, string) HTTP_##name = num,
- HTTP_METHOD_MAP(XX)
-#undef XX
+#define CROW_XX(num, name, string) HTTP_##name = num,
+ CROW_HTTP_METHOD_MAP(CROW_XX)
+#undef CROW_XX
};
@@ -2480,58 +3619,58 @@ enum flags
*
* The provided argument should be a macro that takes 2 arguments.
*/
-#define HTTP_ERRNO_MAP(XX) \
+#define CROW_HTTP_ERRNO_MAP(CROW_XX) \
/* No error */ \
- XX(OK, "success") \
+ CROW_XX(OK, "success") \
\
/* Callback-related errors */ \
- XX(CB_message_begin, "the on_message_begin callback failed") \
- XX(CB_url, "the on_url callback failed") \
- XX(CB_header_field, "the on_header_field callback failed") \
- XX(CB_header_value, "the on_header_value callback failed") \
- XX(CB_headers_complete, "the on_headers_complete callback failed") \
- XX(CB_body, "the on_body callback failed") \
- XX(CB_message_complete, "the on_message_complete callback failed") \
- XX(CB_status, "the on_status callback failed") \
+ CROW_XX(CB_message_begin, "the on_message_begin callback failed") \
+ CROW_XX(CB_url, "the on_url callback failed") \
+ CROW_XX(CB_header_field, "the on_header_field callback failed") \
+ CROW_XX(CB_header_value, "the on_header_value callback failed") \
+ CROW_XX(CB_headers_complete, "the on_headers_complete callback failed") \
+ CROW_XX(CB_body, "the on_body callback failed") \
+ CROW_XX(CB_message_complete, "the on_message_complete callback failed") \
+ CROW_XX(CB_status, "the on_status callback failed") \
\
/* Parsing-related errors */ \
- XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
- XX(HEADER_OVERFLOW, \
+ CROW_XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
+ CROW_XX(HEADER_OVERFLOW, \
"too many header bytes seen; overflow detected") \
- XX(CLOSED_CONNECTION, \
+ CROW_XX(CLOSED_CONNECTION, \
"data received after completed connection: close message") \
- XX(INVALID_VERSION, "invalid HTTP version") \
- XX(INVALID_STATUS, "invalid HTTP status code") \
- XX(INVALID_METHOD, "invalid HTTP method") \
- XX(INVALID_URL, "invalid URL") \
- XX(INVALID_HOST, "invalid host") \
- XX(INVALID_PORT, "invalid port") \
- XX(INVALID_PATH, "invalid path") \
- XX(INVALID_QUERY_STRING, "invalid query string") \
- XX(INVALID_FRAGMENT, "invalid fragment") \
- XX(LF_EXPECTED, "LF character expected") \
- XX(INVALID_HEADER_TOKEN, "invalid character in header") \
- XX(INVALID_CONTENT_LENGTH, \
+ CROW_XX(INVALID_VERSION, "invalid HTTP version") \
+ CROW_XX(INVALID_STATUS, "invalid HTTP status code") \
+ CROW_XX(INVALID_METHOD, "invalid HTTP method") \
+ CROW_XX(INVALID_URL, "invalid URL") \
+ CROW_XX(INVALID_HOST, "invalid host") \
+ CROW_XX(INVALID_PORT, "invalid port") \
+ CROW_XX(INVALID_PATH, "invalid path") \
+ CROW_XX(INVALID_QUERY_STRING, "invalid query string") \
+ CROW_XX(INVALID_FRAGMENT, "invalid fragment") \
+ CROW_XX(LF_EXPECTED, "CROW_LF character expected") \
+ CROW_XX(INVALID_HEADER_TOKEN, "invalid character in header") \
+ CROW_XX(INVALID_CONTENT_LENGTH, \
"invalid character in content-length header") \
- XX(INVALID_CHUNK_SIZE, \
+ CROW_XX(INVALID_CHUNK_SIZE, \
"invalid character in chunk size header") \
- XX(INVALID_CONSTANT, "invalid constant string") \
- XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
- XX(STRICT, "strict mode assertion failed") \
- XX(PAUSED, "parser is paused") \
- XX(UNKNOWN, "an unknown error occurred")
+ CROW_XX(INVALID_CONSTANT, "invalid constant string") \
+ CROW_XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
+ CROW_XX(STRICT, "strict mode assertion failed") \
+ CROW_XX(PAUSED, "parser is paused") \
+ CROW_XX(UNKNOWN, "an unknown error occurred")
/* Define HPE_* values for each errno value above */
-#define HTTP_ERRNO_GEN(n, s) HPE_##n,
+#define CROW_HTTP_ERRNO_GEN(n, s) HPE_##n,
enum http_errno {
- HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
+ CROW_HTTP_ERRNO_MAP(CROW_HTTP_ERRNO_GEN)
};
-#undef HTTP_ERRNO_GEN
+#undef CROW_HTTP_ERRNO_GEN
/* Get an http_errno value from an http_parser */
-#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno)
+#define CROW_HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno)
struct http_parser {
@@ -2686,70 +3825,70 @@ int http_body_is_final(const http_parser *parser);
#include <string.h>
#include <limits.h>
-#ifndef ULLONG_MAX
-# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */
+#ifndef CROW_ULLONG_MAX
+# define CROW_ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */
#endif
-#ifndef MIN
-# define MIN(a,b) ((a) < (b) ? (a) : (b))
+#ifndef CROW_MIN
+# define CROW_MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
-#ifndef ARRAY_SIZE
-# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#ifndef CROW_ARRAY_SIZE
+# define CROW_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#endif
-#ifndef BIT_AT
-# define BIT_AT(a, i) \
+#ifndef CROW_BIT_AT
+# define CROW_BIT_AT(a, i) \
(!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \
(1 << ((unsigned int) (i) & 7))))
#endif
-#ifndef ELEM_AT
-# define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v))
+#ifndef CROW_ELEM_AT
+# define CROW_ELEM_AT(a, i, v) ((unsigned int) (i) < CROW_ARRAY_SIZE(a) ? (a)[(i)] : (v))
#endif
-#define SET_ERRNO(e) \
+#define CROW_SET_ERRNO(e) \
do { \
parser->http_errno = (e); \
} while(0)
/* Run the notify callback FOR, returning ER if it fails */
-#define CALLBACK_NOTIFY_(FOR, ER) \
+#define CROW_CALLBACK_NOTIFY_(FOR, ER) \
do { \
- assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \
+ assert(CROW_HTTP_PARSER_ERRNO(parser) == HPE_OK); \
\
if (settings->on_##FOR) { \
if (0 != settings->on_##FOR(parser)) { \
- SET_ERRNO(HPE_CB_##FOR); \
+ CROW_SET_ERRNO(HPE_CB_##FOR); \
} \
\
/* We either errored above or got paused; get out */ \
- if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \
+ if (CROW_HTTP_PARSER_ERRNO(parser) != HPE_OK) { \
return (ER); \
} \
} \
} while (0)
/* Run the notify callback FOR and consume the current byte */
-#define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1)
+#define CROW_CALLBACK_NOTIFY(FOR) CROW_CALLBACK_NOTIFY_(FOR, p - data + 1)
/* Run the notify callback FOR and don't consume the current byte */
-#define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data)
+#define CROW_CALLBACK_NOTIFY_NOADVANCE(FOR) CROW_CALLBACK_NOTIFY_(FOR, p - data)
/* Run data callback FOR with LEN bytes, returning ER if it fails */
-#define CALLBACK_DATA_(FOR, LEN, ER) \
+#define CROW_CALLBACK_DATA_(FOR, LEN, ER) \
do { \
- assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \
+ assert(CROW_HTTP_PARSER_ERRNO(parser) == HPE_OK); \
\
if (FOR##_mark) { \
if (settings->on_##FOR) { \
if (0 != settings->on_##FOR(parser, FOR##_mark, (LEN))) { \
- SET_ERRNO(HPE_CB_##FOR); \
+ CROW_SET_ERRNO(HPE_CB_##FOR); \
} \
\
/* We either errored above or got paused; get out */ \
- if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \
+ if (CROW_HTTP_PARSER_ERRNO(parser) != HPE_OK) { \
return (ER); \
} \
} \
@@ -2758,15 +3897,15 @@ do { \
} while (0)
/* Run the data callback FOR and consume the current byte */
-#define CALLBACK_DATA(FOR) \
- CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1)
+#define CROW_CALLBACK_DATA(FOR) \
+ CROW_CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1)
/* Run the data callback FOR and don't consume the current byte */
-#define CALLBACK_DATA_NOADVANCE(FOR) \
- CALLBACK_DATA_(FOR, p - FOR##_mark, p - data)
+#define CROW_CALLBACK_DATA_NOADVANCE(FOR) \
+ CROW_CALLBACK_DATA_(FOR, p - FOR##_mark, p - data)
/* Set the mark FOR; non-destructive if mark is already set */
-#define MARK(FOR) \
+#define CROW_MARK(FOR) \
do { \
if (!FOR##_mark) { \
FOR##_mark = p; \
@@ -2774,14 +3913,14 @@ do { \
} while (0)
-#define PROXY_CONNECTION "proxy-connection"
-#define CONNECTION "connection"
-#define CONTENT_LENGTH "content-length"
-#define TRANSFER_ENCODING "transfer-encoding"
-#define UPGRADE "upgrade"
-#define CHUNKED "chunked"
-#define KEEP_ALIVE "keep-alive"
-#define CLOSE "close"
+#define CROW_PROXY_CONNECTION "proxy-connection"
+#define CROW_CONNECTION "connection"
+#define CROW_CONTENT_LENGTH "content-length"
+#define CROW_TRANSFER_ENCODING "transfer-encoding"
+#define CROW_UPGRADE "upgrade"
+#define CROW_CHUNKED "chunked"
+#define CROW_KEEP_ALIVE "keep-alive"
+#define CROW_CLOSE "close"
@@ -2853,7 +3992,7 @@ enum state
/* Important: 's_headers_done' must be the last 'header' state. All
* states beyond this must be 'body' states. It is used for overflow
- * checking. See the PARSING_HEADER() macro.
+ * checking. See the CROW_PARSING_HEADER() macro.
*/
, s_chunk_data
@@ -2867,7 +4006,7 @@ enum state
};
-#define PARSING_HEADER(state) (state <= s_headers_done)
+#define CROW_PARSING_HEADER(state) (state <= s_headers_done)
enum header_states
@@ -2911,48 +4050,48 @@ enum http_host_state
};
/* Macros for character classes; depends on strict-mode */
-#define CR '\r'
-#define LF '\n'
-#define LOWER(c) (unsigned char)(c | 0x20)
-#define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z')
-#define IS_NUM(c) ((c) >= '0' && (c) <= '9')
-#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))
-#define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f'))
-#define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \
+#define CROW_CR '\r'
+#define CROW_LF '\n'
+#define CROW_LOWER(c) (unsigned char)(c | 0x20)
+#define CROW_IS_ALPHA(c) (CROW_LOWER(c) >= 'a' && CROW_LOWER(c) <= 'z')
+#define CROW_IS_NUM(c) ((c) >= '0' && (c) <= '9')
+#define CROW_IS_ALPHANUM(c) (CROW_IS_ALPHA(c) || CROW_IS_NUM(c))
+#define CROW_IS_HEX(c) (CROW_IS_NUM(c) || (CROW_LOWER(c) >= 'a' && CROW_LOWER(c) <= 'f'))
+#define CROW_IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \
(c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \
(c) == ')')
-#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \
+#define CROW_IS_USERINFO_CHAR(c) (CROW_IS_ALPHANUM(c) || CROW_IS_MARK(c) || (c) == '%' || \
(c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \
(c) == '$' || (c) == ',')
-#if HTTP_PARSER_STRICT
-#define TOKEN(c) (tokens[(unsigned char)c])
-#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c))
-#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
+#if CROW_HTTP_PARSER_STRICT
+#define CROW_TOKEN(c) (tokens[(unsigned char)c])
+#define CROW_IS_URL_CHAR(c) (CROW_BIT_AT(normal_url_char, (unsigned char)c))
+#define CROW_IS_HOST_CHAR(c) (CROW_IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
#else
-#define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c])
-#define IS_URL_CHAR(c) \
- (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80))
-#define IS_HOST_CHAR(c) \
- (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
+#define CROW_TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c])
+#define CROW_IS_URL_CHAR(c) \
+ (CROW_BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80))
+#define CROW_IS_HOST_CHAR(c) \
+ (CROW_IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
#endif
-#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res)
+#define CROW_start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res)
-#if HTTP_PARSER_STRICT
-# define STRICT_CHECK(cond) \
+#if CROW_HTTP_PARSER_STRICT
+# define CROW_STRICT_CHECK(cond) \
do { \
if (cond) { \
- SET_ERRNO(HPE_STRICT); \
+ CROW_SET_ERRNO(HPE_STRICT); \
goto error; \
} \
} while (0)
-# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead)
+# define CROW_NEW_MESSAGE() (http_should_keep_alive(parser) ? CROW_start_state : s_dead)
#else
-# define STRICT_CHECK(cond)
-# define NEW_MESSAGE() start_state
+# define CROW_STRICT_CHECK(cond)
+# define CROW_NEW_MESSAGE() CROW_start_state
#endif
@@ -2973,10 +4112,10 @@ int http_message_needs_eof(const http_parser *parser);
inline enum state
parse_url_char(enum state s, const char ch)
{
-#if HTTP_PARSER_STRICT
-# define T(v) 0
+#if CROW_HTTP_PARSER_STRICT
+# define CROW_T(v) 0
#else
-# define T(v) v
+# define CROW_T(v) v
#endif
@@ -2984,7 +4123,7 @@ static const uint8_t normal_url_char[32] = {
/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
- 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0,
+ 0 | CROW_T(2) | 0 | 0 | CROW_T(16) | 0 | 0 | 0,
/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
@@ -3001,7 +4140,7 @@ static const uint8_t normal_url_char[32] = {
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
-/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
+/* 80 P 81 Q 82 R 83 S 84 CROW_T 85 U 86 V 87 W */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
@@ -3014,13 +4153,13 @@ static const uint8_t normal_url_char[32] = {
/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, };
-#undef T
+#undef CROW_T
if (ch == ' ' || ch == '\r' || ch == '\n') {
return s_dead;
}
-#if HTTP_PARSER_STRICT
+#if CROW_HTTP_PARSER_STRICT
if (ch == '\t' || ch == '\f') {
return s_dead;
}
@@ -3036,14 +4175,14 @@ static const uint8_t normal_url_char[32] = {
return s_req_path;
}
- if (IS_ALPHA(ch)) {
+ if (CROW_IS_ALPHA(ch)) {
return s_req_schema;
}
break;
case s_req_schema:
- if (IS_ALPHA(ch)) {
+ if (CROW_IS_ALPHA(ch)) {
return s;
}
@@ -3087,14 +4226,14 @@ static const uint8_t normal_url_char[32] = {
return s_req_server_with_at;
}
- if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') {
+ if (CROW_IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') {
return s_req_server;
}
break;
case s_req_path:
- if (IS_URL_CHAR(ch)) {
+ if (CROW_IS_URL_CHAR(ch)) {
return s;
}
@@ -3110,7 +4249,7 @@ static const uint8_t normal_url_char[32] = {
case s_req_query_string_start:
case s_req_query_string:
- if (IS_URL_CHAR(ch)) {
+ if (CROW_IS_URL_CHAR(ch)) {
return s_req_query_string;
}
@@ -3126,7 +4265,7 @@ static const uint8_t normal_url_char[32] = {
break;
case s_req_fragment_start:
- if (IS_URL_CHAR(ch)) {
+ if (CROW_IS_URL_CHAR(ch)) {
return s_req_fragment;
}
@@ -3141,7 +4280,7 @@ static const uint8_t normal_url_char[32] = {
break;
case s_req_fragment:
- if (IS_URL_CHAR(ch)) {
+ if (CROW_IS_URL_CHAR(ch)) {
return s;
}
@@ -3168,9 +4307,9 @@ inline size_t http_parser_execute (http_parser *parser,
{
static const char *method_strings[] =
{
-#define XX(num, name, string) #string,
- HTTP_METHOD_MAP(XX)
-#undef XX
+#define CROW_XX(num, name, string) #string,
+ CROW_HTTP_METHOD_MAP(CROW_XX)
+#undef CROW_XX
};
/* Tokens as defined by rfc 2616. Also lowercases them.
@@ -3238,17 +4377,17 @@ static const int8_t unhex[256] =
const char *status_mark = 0;
/* We're in an error state. Don't bother doing anything. */
- if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
+ if (CROW_HTTP_PARSER_ERRNO(parser) != HPE_OK) {
return 0;
}
if (len == 0) {
switch (parser->state) {
case s_body_identity_eof:
- /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if
+ /* Use of CROW_CALLBACK_NOTIFY() here would erroneously return 1 byte read if
* we got paused.
*/
- CALLBACK_NOTIFY_NOADVANCE(message_complete);
+ CROW_CALLBACK_NOTIFY_NOADVANCE(message_complete);
return 0;
case s_dead:
@@ -3258,7 +4397,7 @@ static const int8_t unhex[256] =
return 0;
default:
- SET_ERRNO(HPE_INVALID_EOF_STATE);
+ CROW_SET_ERRNO(HPE_INVALID_EOF_STATE);
return 1;
}
}
@@ -3290,21 +4429,21 @@ static const int8_t unhex[256] =
for (p=data; p != data + len; p++) {
ch = *p;
- if (PARSING_HEADER(parser->state)) {
+ if (CROW_PARSING_HEADER(parser->state)) {
++parser->nread;
/* Don't allow the total size of the HTTP headers (including the status
- * line) to exceed HTTP_MAX_HEADER_SIZE. This check is here to protect
+ * line) to exceed CROW_HTTP_MAX_HEADER_SIZE. This check is here to protect
* embedders against denial-of-service attacks where the attacker feeds
* us a never-ending header that the embedder keeps buffering.
*
* This check is arguably the responsibility of embedders but we're doing
* it on the embedder's behalf because most won't bother and this way we
- * make the web a little safer. HTTP_MAX_HEADER_SIZE is still far bigger
+ * make the web a little safer. CROW_HTTP_MAX_HEADER_SIZE is still far bigger
* than any reasonable request or response so this should never affect
* day-to-day operation.
*/
- if (parser->nread > (HTTP_MAX_HEADER_SIZE)) {
- SET_ERRNO(HPE_HEADER_OVERFLOW);
+ if (parser->nread > (CROW_HTTP_MAX_HEADER_SIZE)) {
+ CROW_SET_ERRNO(HPE_HEADER_OVERFLOW);
goto error;
}
}
@@ -3316,23 +4455,23 @@ static const int8_t unhex[256] =
/* this state is used after a 'Connection: close' message
* the parser will error out if it reads another message
*/
- if (ch == CR || ch == LF)
+ if (ch == CROW_CR || ch == CROW_LF)
break;
- SET_ERRNO(HPE_CLOSED_CONNECTION);
+ CROW_SET_ERRNO(HPE_CLOSED_CONNECTION);
goto error;
case s_start_req_or_res:
{
- if (ch == CR || ch == LF)
+ if (ch == CROW_CR || ch == CROW_LF)
break;
parser->flags = 0;
- parser->content_length = ULLONG_MAX;
+ parser->content_length = CROW_ULLONG_MAX;
if (ch == 'H') {
parser->state = s_res_or_resp_H;
- CALLBACK_NOTIFY(message_begin);
+ CROW_CALLBACK_NOTIFY(message_begin);
} else {
parser->type = HTTP_REQUEST;
parser->state = s_start_req;
@@ -3348,7 +4487,7 @@ static const int8_t unhex[256] =
parser->state = s_res_HT;
} else {
if (ch != 'E') {
- SET_ERRNO(HPE_INVALID_CONSTANT);
+ CROW_SET_ERRNO(HPE_INVALID_CONSTANT);
goto error;
}
@@ -3362,49 +4501,49 @@ static const int8_t unhex[256] =
case s_start_res:
{
parser->flags = 0;
- parser->content_length = ULLONG_MAX;
+ parser->content_length = CROW_ULLONG_MAX;
switch (ch) {
case 'H':
parser->state = s_res_H;
break;
- case CR:
- case LF:
+ case CROW_CR:
+ case CROW_LF:
break;
default:
- SET_ERRNO(HPE_INVALID_CONSTANT);
+ CROW_SET_ERRNO(HPE_INVALID_CONSTANT);
goto error;
}
- CALLBACK_NOTIFY(message_begin);
+ CROW_CALLBACK_NOTIFY(message_begin);
break;
}
case s_res_H:
- STRICT_CHECK(ch != 'T');
+ CROW_STRICT_CHECK(ch != 'T');
parser->state = s_res_HT;
break;
case s_res_HT:
- STRICT_CHECK(ch != 'T');
+ CROW_STRICT_CHECK(ch != 'T');
parser->state = s_res_HTT;
break;
case s_res_HTT:
- STRICT_CHECK(ch != 'P');
+ CROW_STRICT_CHECK(ch != 'P');
parser->state = s_res_HTTP;
break;
case s_res_HTTP:
- STRICT_CHECK(ch != '/');
+ CROW_STRICT_CHECK(ch != '/');
parser->state = s_res_first_http_major;
break;
case s_res_first_http_major:
if (ch < '0' || ch > '9') {
- SET_ERRNO(HPE_INVALID_VERSION);
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -3420,8 +4559,8 @@ static const int8_t unhex[256] =
break;
}
- if (!IS_NUM(ch)) {
- SET_ERRNO(HPE_INVALID_VERSION);
+ if (!CROW_IS_NUM(ch)) {
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -3429,7 +4568,7 @@ static const int8_t unhex[256] =
parser->http_major += ch - '0';
if (parser->http_major > 999) {
- SET_ERRNO(HPE_INVALID_VERSION);
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -3438,8 +4577,8 @@ static const int8_t unhex[256] =
/* first digit of minor HTTP version */
case s_res_first_http_minor:
- if (!IS_NUM(ch)) {
- SET_ERRNO(HPE_INVALID_VERSION);
+ if (!CROW_IS_NUM(ch)) {
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -3455,8 +4594,8 @@ static const int8_t unhex[256] =
break;
}
- if (!IS_NUM(ch)) {
- SET_ERRNO(HPE_INVALID_VERSION);
+ if (!CROW_IS_NUM(ch)) {
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -3464,7 +4603,7 @@ static const int8_t unhex[256] =
parser->http_minor += ch - '0';
if (parser->http_minor > 999) {
- SET_ERRNO(HPE_INVALID_VERSION);
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -3473,12 +4612,12 @@ static const int8_t unhex[256] =
case s_res_first_status_code:
{
- if (!IS_NUM(ch)) {
+ if (!CROW_IS_NUM(ch)) {
if (ch == ' ') {
break;
}
- SET_ERRNO(HPE_INVALID_STATUS);
+ CROW_SET_ERRNO(HPE_INVALID_STATUS);
goto error;
}
parser->status_code = ch - '0';
@@ -3488,19 +4627,19 @@ static const int8_t unhex[256] =
case s_res_status_code:
{
- if (!IS_NUM(ch)) {
+ if (!CROW_IS_NUM(ch)) {
switch (ch) {
case ' ':
parser->state = s_res_status_start;
break;
- case CR:
+ case CROW_CR:
parser->state = s_res_line_almost_done;
break;
- case LF:
+ case CROW_LF:
parser->state = s_header_field_start;
break;
default:
- SET_ERRNO(HPE_INVALID_STATUS);
+ CROW_SET_ERRNO(HPE_INVALID_STATUS);
goto error;
}
break;
@@ -3510,7 +4649,7 @@ static const int8_t unhex[256] =
parser->status_code += ch - '0';
if (parser->status_code > 999) {
- SET_ERRNO(HPE_INVALID_STATUS);
+ CROW_SET_ERRNO(HPE_INVALID_STATUS);
goto error;
}
@@ -3519,51 +4658,51 @@ static const int8_t unhex[256] =
case s_res_status_start:
{
- if (ch == CR) {
+ if (ch == CROW_CR) {
parser->state = s_res_line_almost_done;
break;
}
- if (ch == LF) {
+ if (ch == CROW_LF) {
parser->state = s_header_field_start;
break;
}
- MARK(status);
+ CROW_MARK(status);
parser->state = s_res_status;
parser->index = 0;
break;
}
case s_res_status:
- if (ch == CR) {
+ if (ch == CROW_CR) {
parser->state = s_res_line_almost_done;
- CALLBACK_DATA(status);
+ CROW_CALLBACK_DATA(status);
break;
}
- if (ch == LF) {
+ if (ch == CROW_LF) {
parser->state = s_header_field_start;
- CALLBACK_DATA(status);
+ CROW_CALLBACK_DATA(status);
break;
}
break;
case s_res_line_almost_done:
- STRICT_CHECK(ch != LF);
+ CROW_STRICT_CHECK(ch != CROW_LF);
parser->state = s_header_field_start;
break;
case s_start_req:
{
- if (ch == CR || ch == LF)
+ if (ch == CROW_CR || ch == CROW_LF)
break;
parser->flags = 0;
- parser->content_length = ULLONG_MAX;
+ parser->content_length = CROW_ULLONG_MAX;
- if (!IS_ALPHA(ch)) {
- SET_ERRNO(HPE_INVALID_METHOD);
+ if (!CROW_IS_ALPHA(ch)) {
+ CROW_SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
@@ -3586,12 +4725,12 @@ static const int8_t unhex[256] =
case 'T': parser->method = HTTP_TRACE; break;
case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break;
default:
- SET_ERRNO(HPE_INVALID_METHOD);
+ CROW_SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
parser->state = s_req_method;
- CALLBACK_NOTIFY(message_begin);
+ CROW_CALLBACK_NOTIFY(message_begin);
break;
}
@@ -3600,7 +4739,7 @@ static const int8_t unhex[256] =
{
const char *matcher;
if (ch == '\0') {
- SET_ERRNO(HPE_INVALID_METHOD);
+ CROW_SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
@@ -3615,7 +4754,7 @@ static const int8_t unhex[256] =
} else if (parser->index == 2 && ch == 'P') {
parser->method = HTTP_COPY;
} else {
- SET_ERRNO(HPE_INVALID_METHOD);
+ CROW_SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
} else if (parser->method == HTTP_MKCOL) {
@@ -3630,14 +4769,14 @@ static const int8_t unhex[256] =
} else if (parser->index == 3 && ch == 'A') {
parser->method = HTTP_MKCALENDAR;
} else {
- SET_ERRNO(HPE_INVALID_METHOD);
+ CROW_SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
} else if (parser->method == HTTP_SUBSCRIBE) {
if (parser->index == 1 && ch == 'E') {
parser->method = HTTP_SEARCH;
} else {
- SET_ERRNO(HPE_INVALID_METHOD);
+ CROW_SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
} else if (parser->index == 1 && parser->method == HTTP_POST) {
@@ -3648,7 +4787,7 @@ static const int8_t unhex[256] =
} else if (ch == 'A') {
parser->method = HTTP_PATCH;
} else {
- SET_ERRNO(HPE_INVALID_METHOD);
+ CROW_SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
} else if (parser->index == 2) {
@@ -3656,24 +4795,24 @@ static const int8_t unhex[256] =
if (ch == 'R') {
parser->method = HTTP_PURGE;
} else {
- SET_ERRNO(HPE_INVALID_METHOD);
+ CROW_SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
} else if (parser->method == HTTP_UNLOCK) {
if (ch == 'S') {
parser->method = HTTP_UNSUBSCRIBE;
} else {
- SET_ERRNO(HPE_INVALID_METHOD);
+ CROW_SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
} else {
- SET_ERRNO(HPE_INVALID_METHOD);
+ CROW_SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
} else if (parser->index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') {
parser->method = HTTP_PROPPATCH;
} else {
- SET_ERRNO(HPE_INVALID_METHOD);
+ CROW_SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
@@ -3685,14 +4824,14 @@ static const int8_t unhex[256] =
{
if (ch == ' ') break;
- MARK(url);
+ CROW_MARK(url);
if (parser->method == HTTP_CONNECT) {
parser->state = s_req_server_start;
}
parser->state = parse_url_char((enum state)parser->state, ch);
if (parser->state == s_dead) {
- SET_ERRNO(HPE_INVALID_URL);
+ CROW_SET_ERRNO(HPE_INVALID_URL);
goto error;
}
@@ -3707,14 +4846,14 @@ static const int8_t unhex[256] =
switch (ch) {
/* No whitespace allowed here */
case ' ':
- case CR:
- case LF:
- SET_ERRNO(HPE_INVALID_URL);
+ case CROW_CR:
+ case CROW_LF:
+ CROW_SET_ERRNO(HPE_INVALID_URL);
goto error;
default:
parser->state = parse_url_char((enum state)parser->state, ch);
if (parser->state == s_dead) {
- SET_ERRNO(HPE_INVALID_URL);
+ CROW_SET_ERRNO(HPE_INVALID_URL);
goto error;
}
}
@@ -3733,21 +4872,21 @@ static const int8_t unhex[256] =
switch (ch) {
case ' ':
parser->state = s_req_http_start;
- CALLBACK_DATA(url);
+ CROW_CALLBACK_DATA(url);
break;
- case CR:
- case LF:
+ case CROW_CR:
+ case CROW_LF:
parser->http_major = 0;
parser->http_minor = 9;
- parser->state = (ch == CR) ?
+ parser->state = (ch == CROW_CR) ?
s_req_line_almost_done :
s_header_field_start;
- CALLBACK_DATA(url);
+ CROW_CALLBACK_DATA(url);
break;
default:
parser->state = parse_url_char((enum state)parser->state, ch);
if (parser->state == s_dead) {
- SET_ERRNO(HPE_INVALID_URL);
+ CROW_SET_ERRNO(HPE_INVALID_URL);
goto error;
}
}
@@ -3762,35 +4901,35 @@ static const int8_t unhex[256] =
case ' ':
break;
default:
- SET_ERRNO(HPE_INVALID_CONSTANT);
+ CROW_SET_ERRNO(HPE_INVALID_CONSTANT);
goto error;
}
break;
case s_req_http_H:
- STRICT_CHECK(ch != 'T');
+ CROW_STRICT_CHECK(ch != 'T');
parser->state = s_req_http_HT;
break;
case s_req_http_HT:
- STRICT_CHECK(ch != 'T');
+ CROW_STRICT_CHECK(ch != 'T');
parser->state = s_req_http_HTT;
break;
case s_req_http_HTT:
- STRICT_CHECK(ch != 'P');
+ CROW_STRICT_CHECK(ch != 'P');
parser->state = s_req_http_HTTP;
break;
case s_req_http_HTTP:
- STRICT_CHECK(ch != '/');
+ CROW_STRICT_CHECK(ch != '/');
parser->state = s_req_first_http_major;
break;
/* first digit of major HTTP version */
case s_req_first_http_major:
if (ch < '1' || ch > '9') {
- SET_ERRNO(HPE_INVALID_VERSION);
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -3806,8 +4945,8 @@ static const int8_t unhex[256] =
break;
}
- if (!IS_NUM(ch)) {
- SET_ERRNO(HPE_INVALID_VERSION);
+ if (!CROW_IS_NUM(ch)) {
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -3815,7 +4954,7 @@ static const int8_t unhex[256] =
parser->http_major += ch - '0';
if (parser->http_major > 999) {
- SET_ERRNO(HPE_INVALID_VERSION);
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -3824,8 +4963,8 @@ static const int8_t unhex[256] =
/* first digit of minor HTTP version */
case s_req_first_http_minor:
- if (!IS_NUM(ch)) {
- SET_ERRNO(HPE_INVALID_VERSION);
+ if (!CROW_IS_NUM(ch)) {
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -3836,20 +4975,20 @@ static const int8_t unhex[256] =
/* minor HTTP version or end of request line */
case s_req_http_minor:
{
- if (ch == CR) {
+ if (ch == CROW_CR) {
parser->state = s_req_line_almost_done;
break;
}
- if (ch == LF) {
+ if (ch == CROW_LF) {
parser->state = s_header_field_start;
break;
}
/* XXX allow spaces after digit? */
- if (!IS_NUM(ch)) {
- SET_ERRNO(HPE_INVALID_VERSION);
+ if (!CROW_IS_NUM(ch)) {
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -3857,7 +4996,7 @@ static const int8_t unhex[256] =
parser->http_minor += ch - '0';
if (parser->http_minor > 999) {
- SET_ERRNO(HPE_INVALID_VERSION);
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -3867,8 +5006,8 @@ static const int8_t unhex[256] =
/* end of request line */
case s_req_line_almost_done:
{
- if (ch != LF) {
- SET_ERRNO(HPE_LF_EXPECTED);
+ if (ch != CROW_LF) {
+ CROW_SET_ERRNO(HPE_LF_EXPECTED);
goto error;
}
@@ -3878,26 +5017,26 @@ static const int8_t unhex[256] =
case s_header_field_start:
{
- if (ch == CR) {
+ if (ch == CROW_CR) {
parser->state = s_headers_almost_done;
break;
}
- if (ch == LF) {
+ if (ch == CROW_LF) {
/* they might be just sending \n instead of \r\n so this would be
* the second \n to denote the end of headers*/
parser->state = s_headers_almost_done;
goto reexecute_byte;
}
- c = TOKEN(ch);
+ c = CROW_TOKEN(ch);
if (!c) {
- SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
+ CROW_SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
goto error;
}
- MARK(header_field);
+ CROW_MARK(header_field);
parser->index = 0;
parser->state = s_header_field;
@@ -3928,7 +5067,7 @@ static const int8_t unhex[256] =
case s_header_field:
{
- c = TOKEN(ch);
+ c = CROW_TOKEN(ch);
if (c) {
switch (parser->header_state) {
@@ -3964,10 +5103,10 @@ static const int8_t unhex[256] =
case h_matching_connection:
parser->index++;
- if (parser->index > sizeof(CONNECTION)-1
- || c != CONNECTION[parser->index]) {
+ if (parser->index > sizeof(CROW_CONNECTION)-1
+ || c != CROW_CONNECTION[parser->index]) {
parser->header_state = h_general;
- } else if (parser->index == sizeof(CONNECTION)-2) {
+ } else if (parser->index == sizeof(CROW_CONNECTION)-2) {
parser->header_state = h_connection;
}
break;
@@ -3976,10 +5115,10 @@ static const int8_t unhex[256] =
case h_matching_proxy_connection:
parser->index++;
- if (parser->index > sizeof(PROXY_CONNECTION)-1
- || c != PROXY_CONNECTION[parser->index]) {
+ if (parser->index > sizeof(CROW_PROXY_CONNECTION)-1
+ || c != CROW_PROXY_CONNECTION[parser->index]) {
parser->header_state = h_general;
- } else if (parser->index == sizeof(PROXY_CONNECTION)-2) {
+ } else if (parser->index == sizeof(CROW_PROXY_CONNECTION)-2) {
parser->header_state = h_connection;
}
break;
@@ -3988,10 +5127,10 @@ static const int8_t unhex[256] =
case h_matching_content_length:
parser->index++;
- if (parser->index > sizeof(CONTENT_LENGTH)-1
- || c != CONTENT_LENGTH[parser->index]) {
+ if (parser->index > sizeof(CROW_CONTENT_LENGTH)-1
+ || c != CROW_CONTENT_LENGTH[parser->index]) {
parser->header_state = h_general;
- } else if (parser->index == sizeof(CONTENT_LENGTH)-2) {
+ } else if (parser->index == sizeof(CROW_CONTENT_LENGTH)-2) {
parser->header_state = h_content_length;
}
break;
@@ -4000,10 +5139,10 @@ static const int8_t unhex[256] =
case h_matching_transfer_encoding:
parser->index++;
- if (parser->index > sizeof(TRANSFER_ENCODING)-1
- || c != TRANSFER_ENCODING[parser->index]) {
+ if (parser->index > sizeof(CROW_TRANSFER_ENCODING)-1
+ || c != CROW_TRANSFER_ENCODING[parser->index]) {
parser->header_state = h_general;
- } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) {
+ } else if (parser->index == sizeof(CROW_TRANSFER_ENCODING)-2) {
parser->header_state = h_transfer_encoding;
}
break;
@@ -4012,10 +5151,10 @@ static const int8_t unhex[256] =
case h_matching_upgrade:
parser->index++;
- if (parser->index > sizeof(UPGRADE)-1
- || c != UPGRADE[parser->index]) {
+ if (parser->index > sizeof(CROW_UPGRADE)-1
+ || c != CROW_UPGRADE[parser->index]) {
parser->header_state = h_general;
- } else if (parser->index == sizeof(UPGRADE)-2) {
+ } else if (parser->index == sizeof(CROW_UPGRADE)-2) {
parser->header_state = h_upgrade;
}
break;
@@ -4036,35 +5175,35 @@ static const int8_t unhex[256] =
if (ch == ':') {
parser->state = s_header_value_discard_ws;
- CALLBACK_DATA(header_field);
+ CROW_CALLBACK_DATA(header_field);
break;
}
- if (ch == CR) {
+ if (ch == CROW_CR) {
parser->state = s_header_almost_done;
- CALLBACK_DATA(header_field);
+ CROW_CALLBACK_DATA(header_field);
break;
}
- if (ch == LF) {
+ if (ch == CROW_LF) {
parser->state = s_header_field_start;
- CALLBACK_DATA(header_field);
+ CROW_CALLBACK_DATA(header_field);
break;
}
- SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
+ CROW_SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
goto error;
}
case s_header_value_discard_ws:
if (ch == ' ' || ch == '\t') break;
- if (ch == CR) {
+ if (ch == CROW_CR) {
parser->state = s_header_value_discard_ws_almost_done;
break;
}
- if (ch == LF) {
+ if (ch == CROW_LF) {
parser->state = s_header_value_discard_lws;
break;
}
@@ -4073,12 +5212,12 @@ static const int8_t unhex[256] =
case s_header_value_start:
{
- MARK(header_value);
+ CROW_MARK(header_value);
parser->state = s_header_value;
parser->index = 0;
- c = LOWER(ch);
+ c = CROW_LOWER(ch);
switch (parser->header_state) {
case h_upgrade:
@@ -4096,8 +5235,8 @@ static const int8_t unhex[256] =
break;
case h_content_length:
- if (!IS_NUM(ch)) {
- SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
+ if (!CROW_IS_NUM(ch)) {
+ CROW_SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
goto error;
}
@@ -4126,19 +5265,19 @@ static const int8_t unhex[256] =
case s_header_value:
{
- if (ch == CR) {
+ if (ch == CROW_CR) {
parser->state = s_header_almost_done;
- CALLBACK_DATA(header_value);
+ CROW_CALLBACK_DATA(header_value);
break;
}
- if (ch == LF) {
+ if (ch == CROW_LF) {
parser->state = s_header_almost_done;
- CALLBACK_DATA_NOADVANCE(header_value);
+ CROW_CALLBACK_DATA_NOADVANCE(header_value);
goto reexecute_byte;
}
- c = LOWER(ch);
+ c = CROW_LOWER(ch);
switch (parser->header_state) {
case h_general:
@@ -4155,8 +5294,8 @@ static const int8_t unhex[256] =
if (ch == ' ') break;
- if (!IS_NUM(ch)) {
- SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
+ if (!CROW_IS_NUM(ch)) {
+ CROW_SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
goto error;
}
@@ -4165,8 +5304,8 @@ static const int8_t unhex[256] =
t += ch - '0';
/* Overflow? Test against a conservative limit for simplicity. */
- if ((ULLONG_MAX - 10) / 10 < parser->content_length) {
- SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
+ if ((CROW_ULLONG_MAX - 10) / 10 < parser->content_length) {
+ CROW_SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
goto error;
}
@@ -4177,10 +5316,10 @@ static const int8_t unhex[256] =
/* Transfer-Encoding: chunked */
case h_matching_transfer_encoding_chunked:
parser->index++;
- if (parser->index > sizeof(CHUNKED)-1
- || c != CHUNKED[parser->index]) {
+ if (parser->index > sizeof(CROW_CHUNKED)-1
+ || c != CROW_CHUNKED[parser->index]) {
parser->header_state = h_general;
- } else if (parser->index == sizeof(CHUNKED)-2) {
+ } else if (parser->index == sizeof(CROW_CHUNKED)-2) {
parser->header_state = h_transfer_encoding_chunked;
}
break;
@@ -4188,10 +5327,10 @@ static const int8_t unhex[256] =
/* looking for 'Connection: keep-alive' */
case h_matching_connection_keep_alive:
parser->index++;
- if (parser->index > sizeof(KEEP_ALIVE)-1
- || c != KEEP_ALIVE[parser->index]) {
+ if (parser->index > sizeof(CROW_KEEP_ALIVE)-1
+ || c != CROW_KEEP_ALIVE[parser->index]) {
parser->header_state = h_general;
- } else if (parser->index == sizeof(KEEP_ALIVE)-2) {
+ } else if (parser->index == sizeof(CROW_KEEP_ALIVE)-2) {
parser->header_state = h_connection_keep_alive;
}
break;
@@ -4199,9 +5338,9 @@ static const int8_t unhex[256] =
/* looking for 'Connection: close' */
case h_matching_connection_close:
parser->index++;
- if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) {
+ if (parser->index > sizeof(CROW_CLOSE)-1 || c != CROW_CLOSE[parser->index]) {
parser->header_state = h_general;
- } else if (parser->index == sizeof(CLOSE)-2) {
+ } else if (parser->index == sizeof(CROW_CLOSE)-2) {
parser->header_state = h_connection_close;
}
break;
@@ -4222,7 +5361,7 @@ static const int8_t unhex[256] =
case s_header_almost_done:
{
- STRICT_CHECK(ch != LF);
+ CROW_STRICT_CHECK(ch != CROW_LF);
parser->state = s_header_value_lws;
break;
@@ -4256,7 +5395,7 @@ static const int8_t unhex[256] =
case s_header_value_discard_ws_almost_done:
{
- STRICT_CHECK(ch != LF);
+ CROW_STRICT_CHECK(ch != CROW_LF);
parser->state = s_header_value_discard_lws;
break;
}
@@ -4268,21 +5407,21 @@ static const int8_t unhex[256] =
break;
} else {
/* header value was empty */
- MARK(header_value);
+ CROW_MARK(header_value);
parser->state = s_header_field_start;
- CALLBACK_DATA_NOADVANCE(header_value);
+ CROW_CALLBACK_DATA_NOADVANCE(header_value);
goto reexecute_byte;
}
}
case s_headers_almost_done:
{
- STRICT_CHECK(ch != LF);
+ CROW_STRICT_CHECK(ch != CROW_LF);
if (parser->flags & F_TRAILING) {
/* End of a chunked request */
- parser->state = NEW_MESSAGE();
- CALLBACK_NOTIFY(message_complete);
+ parser->state = CROW_NEW_MESSAGE();
+ CROW_CALLBACK_NOTIFY(message_complete);
break;
}
@@ -4298,7 +5437,7 @@ static const int8_t unhex[256] =
* is needed for the annoying case of recieving a response to a HEAD
* request.
*
- * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so
+ * We'd like to use CROW_CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so
* we have to simulate it by handling a change in errno below.
*/
if (settings->on_headers_complete) {
@@ -4311,12 +5450,12 @@ static const int8_t unhex[256] =
break;
default:
- SET_ERRNO(HPE_CB_headers_complete);
+ CROW_SET_ERRNO(HPE_CB_headers_complete);
return p - data; /* Error */
}
}
- if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
+ if (CROW_HTTP_PARSER_ERRNO(parser) != HPE_OK) {
return p - data;
}
@@ -4325,37 +5464,37 @@ static const int8_t unhex[256] =
case s_headers_done:
{
- STRICT_CHECK(ch != LF);
+ CROW_STRICT_CHECK(ch != CROW_LF);
parser->nread = 0;
/* Exit, the rest of the connect is in a different protocol. */
if (parser->upgrade) {
- parser->state = NEW_MESSAGE();
- CALLBACK_NOTIFY(message_complete);
+ parser->state = CROW_NEW_MESSAGE();
+ CROW_CALLBACK_NOTIFY(message_complete);
return (p - data) + 1;
}
if (parser->flags & F_SKIPBODY) {
- parser->state = NEW_MESSAGE();
- CALLBACK_NOTIFY(message_complete);
+ parser->state = CROW_NEW_MESSAGE();
+ CROW_CALLBACK_NOTIFY(message_complete);
} else if (parser->flags & F_CHUNKED) {
/* chunked encoding - ignore Content-Length header */
parser->state = s_chunk_size_start;
} else {
if (parser->content_length == 0) {
/* Content-Length header given but zero: Content-Length: 0\r\n */
- parser->state = NEW_MESSAGE();
- CALLBACK_NOTIFY(message_complete);
- } else if (parser->content_length != ULLONG_MAX) {
+ parser->state = CROW_NEW_MESSAGE();
+ CROW_CALLBACK_NOTIFY(message_complete);
+ } else if (parser->content_length != CROW_ULLONG_MAX) {
/* Content-Length header given and non-zero */
parser->state = s_body_identity;
} else {
if (parser->type == HTTP_REQUEST ||
!http_message_needs_eof(parser)) {
/* Assume content-length 0 - read the next */
- parser->state = NEW_MESSAGE();
- CALLBACK_NOTIFY(message_complete);
+ parser->state = CROW_NEW_MESSAGE();
+ CROW_CALLBACK_NOTIFY(message_complete);
} else {
/* Read body until EOF */
parser->state = s_body_identity_eof;
@@ -4368,25 +5507,25 @@ static const int8_t unhex[256] =
case s_body_identity:
{
- uint64_t to_read = MIN(parser->content_length,
+ uint64_t to_read = CROW_MIN(parser->content_length,
(uint64_t) ((data + len) - p));
assert(parser->content_length != 0
- && parser->content_length != ULLONG_MAX);
+ && parser->content_length != CROW_ULLONG_MAX);
/* The difference between advancing content_length and p is because
* the latter will automaticaly advance on the next loop iteration.
* Further, if content_length ends up at 0, we want to see the last
* byte again for our message complete callback.
*/
- MARK(body);
+ CROW_MARK(body);
parser->content_length -= to_read;
p += to_read - 1;
if (parser->content_length == 0) {
parser->state = s_message_done;
- /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte.
+ /* Mimic CROW_CALLBACK_DATA_NOADVANCE() but with one extra byte.
*
* The alternative to doing this is to wait for the next byte to
* trigger the data callback, just as in every other case. The
@@ -4395,7 +5534,7 @@ static const int8_t unhex[256] =
* complete-on-length. It's not clear that this distinction is
* important for applications, but let's keep it for now.
*/
- CALLBACK_DATA_(body, p - body_mark + 1, p - data);
+ CROW_CALLBACK_DATA_(body, p - body_mark + 1, p - data);
goto reexecute_byte;
}
@@ -4404,14 +5543,14 @@ static const int8_t unhex[256] =
/* read until EOF */
case s_body_identity_eof:
- MARK(body);
+ CROW_MARK(body);
p = data + len - 1;
break;
case s_message_done:
- parser->state = NEW_MESSAGE();
- CALLBACK_NOTIFY(message_complete);
+ parser->state = CROW_NEW_MESSAGE();
+ CROW_CALLBACK_NOTIFY(message_complete);
break;
case s_chunk_size_start:
@@ -4421,7 +5560,7 @@ static const int8_t unhex[256] =
unhex_val = unhex[(unsigned char)ch];
if (unhex_val == -1) {
- SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
+ CROW_SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
goto error;
}
@@ -4436,7 +5575,7 @@ static const int8_t unhex[256] =
assert(parser->flags & F_CHUNKED);
- if (ch == CR) {
+ if (ch == CROW_CR) {
parser->state = s_chunk_size_almost_done;
break;
}
@@ -4449,7 +5588,7 @@ static const int8_t unhex[256] =
break;
}
- SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
+ CROW_SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
goto error;
}
@@ -4458,8 +5597,8 @@ static const int8_t unhex[256] =
t += unhex_val;
/* Overflow? Test against a conservative limit for simplicity. */
- if ((ULLONG_MAX - 16) / 16 < parser->content_length) {
- SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
+ if ((CROW_ULLONG_MAX - 16) / 16 < parser->content_length) {
+ CROW_SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
goto error;
}
@@ -4471,7 +5610,7 @@ static const int8_t unhex[256] =
{
assert(parser->flags & F_CHUNKED);
/* just ignore this shit. TODO check for overflow */
- if (ch == CR) {
+ if (ch == CROW_CR) {
parser->state = s_chunk_size_almost_done;
break;
}
@@ -4481,7 +5620,7 @@ static const int8_t unhex[256] =
case s_chunk_size_almost_done:
{
assert(parser->flags & F_CHUNKED);
- STRICT_CHECK(ch != LF);
+ CROW_STRICT_CHECK(ch != CROW_LF);
parser->nread = 0;
@@ -4496,17 +5635,17 @@ static const int8_t unhex[256] =
case s_chunk_data:
{
- uint64_t to_read = MIN(parser->content_length,
+ uint64_t to_read = CROW_MIN(parser->content_length,
(uint64_t) ((data + len) - p));
assert(parser->flags & F_CHUNKED);
assert(parser->content_length != 0
- && parser->content_length != ULLONG_MAX);
+ && parser->content_length != CROW_ULLONG_MAX);
/* See the explanation in s_body_identity for why the content
* length and data pointers are managed this way.
*/
- MARK(body);
+ CROW_MARK(body);
parser->content_length -= to_read;
p += to_read - 1;
@@ -4520,21 +5659,21 @@ static const int8_t unhex[256] =
case s_chunk_data_almost_done:
assert(parser->flags & F_CHUNKED);
assert(parser->content_length == 0);
- STRICT_CHECK(ch != CR);
+ CROW_STRICT_CHECK(ch != CROW_CR);
parser->state = s_chunk_data_done;
- CALLBACK_DATA(body);
+ CROW_CALLBACK_DATA(body);
break;
case s_chunk_data_done:
assert(parser->flags & F_CHUNKED);
- STRICT_CHECK(ch != LF);
+ CROW_STRICT_CHECK(ch != CROW_LF);
parser->nread = 0;
parser->state = s_chunk_size_start;
break;
default:
assert(0 && "unhandled state");
- SET_ERRNO(HPE_INVALID_INTERNAL_STATE);
+ CROW_SET_ERRNO(HPE_INVALID_INTERNAL_STATE);
goto error;
}
}
@@ -4545,7 +5684,7 @@ static const int8_t unhex[256] =
*
* We use the NOADVANCE() variety of callbacks here because 'p' has already
* overflowed 'data' and this allows us to correct for the off-by-one that
- * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p'
+ * we'd otherwise have (since CROW_CALLBACK_DATA() is meant to be run with a 'p'
* value that's in-bounds).
*/
@@ -4555,17 +5694,17 @@ static const int8_t unhex[256] =
(body_mark ? 1 : 0) +
(status_mark ? 1 : 0)) <= 1);
- CALLBACK_DATA_NOADVANCE(header_field);
- CALLBACK_DATA_NOADVANCE(header_value);
- CALLBACK_DATA_NOADVANCE(url);
- CALLBACK_DATA_NOADVANCE(body);
- CALLBACK_DATA_NOADVANCE(status);
+ CROW_CALLBACK_DATA_NOADVANCE(header_field);
+ CROW_CALLBACK_DATA_NOADVANCE(header_value);
+ CROW_CALLBACK_DATA_NOADVANCE(url);
+ CROW_CALLBACK_DATA_NOADVANCE(body);
+ CROW_CALLBACK_DATA_NOADVANCE(status);
return len;
error:
- if (HTTP_PARSER_ERRNO(parser) == HPE_OK) {
- SET_ERRNO(HPE_UNKNOWN);
+ if (CROW_HTTP_PARSER_ERRNO(parser) == HPE_OK) {
+ CROW_SET_ERRNO(HPE_UNKNOWN);
}
return (p - data);
@@ -4588,7 +5727,7 @@ http_message_needs_eof (const http_parser *parser)
return 0;
}
- if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) {
+ if ((parser->flags & F_CHUNKED) || parser->content_length != CROW_ULLONG_MAX) {
return 0;
}
@@ -4620,11 +5759,11 @@ http_method_str (enum http_method m)
{
static const char *method_strings[] =
{
-#define XX(num, name, string) #string,
- HTTP_METHOD_MAP(XX)
-#undef XX
+#define CROW_XX(num, name, string) #string,
+ CROW_HTTP_METHOD_MAP(CROW_XX)
+#undef CROW_XX
};
- return ELEM_AT(method_strings, m, "<unknown>");
+ return CROW_ELEM_AT(method_strings, m, "<unknown>");
}
@@ -4642,14 +5781,14 @@ http_parser_init (http_parser *parser, enum http_parser_type t)
inline const char *
http_errno_name(enum http_errno err) {
/* Map errno values to strings for human-readable output */
-#define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s },
+#define CROW_HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s },
static struct {
const char *name;
const char *description;
} http_strerror_tab[] = {
- HTTP_ERRNO_MAP(HTTP_STRERROR_GEN)
+ CROW_HTTP_ERRNO_MAP(CROW_HTTP_STRERROR_GEN)
};
-#undef HTTP_STRERROR_GEN
+#undef CROW_HTTP_STRERROR_GEN
assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));
return http_strerror_tab[err].name;
}
@@ -4657,14 +5796,14 @@ static struct {
inline const char *
http_errno_description(enum http_errno err) {
/* Map errno values to strings for human-readable output */
-#define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s },
+#define CROW_HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s },
static struct {
const char *name;
const char *description;
} http_strerror_tab[] = {
- HTTP_ERRNO_MAP(HTTP_STRERROR_GEN)
+ CROW_HTTP_ERRNO_MAP(CROW_HTTP_STRERROR_GEN)
};
-#undef HTTP_STRERROR_GEN
+#undef CROW_HTTP_STRERROR_GEN
assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));
return http_strerror_tab[err].description;
}
@@ -4678,7 +5817,7 @@ http_parse_host_char(enum http_host_state s, const char ch) {
return s_http_host_start;
}
- if (IS_USERINFO_CHAR(ch)) {
+ if (CROW_IS_USERINFO_CHAR(ch)) {
return s_http_userinfo;
}
break;
@@ -4688,14 +5827,14 @@ http_parse_host_char(enum http_host_state s, const char ch) {
return s_http_host_v6_start;
}
- if (IS_HOST_CHAR(ch)) {
+ if (CROW_IS_HOST_CHAR(ch)) {
return s_http_host;
}
break;
case s_http_host:
- if (IS_HOST_CHAR(ch)) {
+ if (CROW_IS_HOST_CHAR(ch)) {
return s_http_host;
}
@@ -4714,7 +5853,7 @@ http_parse_host_char(enum http_host_state s, const char ch) {
/* FALLTHROUGH */
case s_http_host_v6_start:
- if (IS_HEX(ch) || ch == ':' || ch == '.') {
+ if (CROW_IS_HEX(ch) || ch == ':' || ch == '.') {
return s_http_host_v6;
}
@@ -4722,7 +5861,7 @@ http_parse_host_char(enum http_host_state s, const char ch) {
case s_http_host_port:
case s_http_host_port_start:
- if (IS_NUM(ch)) {
+ if (CROW_IS_NUM(ch)) {
return s_http_host_port;
}
@@ -4912,9 +6051,9 @@ http_parser_pause(http_parser *parser, int paused) {
* state. In non-debug builds, there's not much that we can do about this
* other than ignore it.
*/
- if (HTTP_PARSER_ERRNO(parser) == HPE_OK ||
- HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) {
- SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK);
+ if (CROW_HTTP_PARSER_ERRNO(parser) == HPE_OK ||
+ CROW_HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) {
+ CROW_SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK);
} else {
assert(0 && "Attempting to pause parser in error state");
}
@@ -4927,45 +6066,45 @@ http_body_is_final(const struct http_parser *parser) {
inline unsigned long
http_parser_version(void) {
- return HTTP_PARSER_VERSION_MAJOR * 0x10000 |
- HTTP_PARSER_VERSION_MINOR * 0x00100 |
- HTTP_PARSER_VERSION_PATCH * 0x00001;
+ return CROW_HTTP_PARSER_VERSION_MAJOR * 0x10000 |
+ CROW_HTTP_PARSER_VERSION_MINOR * 0x00100 |
+ CROW_HTTP_PARSER_VERSION_PATCH * 0x00001;
}
-#undef HTTP_METHOD_MAP
-#undef HTTP_ERRNO_MAP
-#undef SET_ERRNO
-#undef CALLBACK_NOTIFY_
-#undef CALLBACK_NOTIFY
-#undef CALLBACK_NOTIFY_NOADVANCE
-#undef CALLBACK_DATA_
-#undef CALLBACK_DATA
-#undef CALLBACK_DATA_NOADVANCE
-#undef MARK
-#undef PROXY_CONNECTION
-#undef CONNECTION
-#undef CONTENT_LENGTH
-#undef TRANSFER_ENCODING
-#undef UPGRADE
-#undef CHUNKED
-#undef KEEP_ALIVE
-#undef CLOSE
-#undef PARSING_HEADER
-#undef CR
-#undef LF
-#undef LOWER
-#undef IS_ALPHA
-#undef IS_NUM
-#undef IS_ALPHANUM
-#undef IS_HEX
-#undef IS_MARK
-#undef IS_USERINFO_CHAR
-#undef TOKEN
-#undef IS_URL_CHAR
-#undef IS_HOST_CHAR
-#undef start_state
-#undef STRICT_CHECK
-#undef NEW_MESSAGE
+#undef CROW_HTTP_METHOD_MAP
+#undef CROW_HTTP_ERRNO_MAP
+#undef CROW_SET_ERRNO
+#undef CROW_CALLBACK_NOTIFY_
+#undef CROW_CALLBACK_NOTIFY
+#undef CROW_CALLBACK_NOTIFY_NOADVANCE
+#undef CROW_CALLBACK_DATA_
+#undef CROW_CALLBACK_DATA
+#undef CROW_CALLBACK_DATA_NOADVANCE
+#undef CROW_MARK
+#undef CROW_PROXY_CONNECTION
+#undef CROW_CONNECTION
+#undef CROW_CONTENT_LENGTH
+#undef CROW_TRANSFER_ENCODING
+#undef CROW_UPGRADE
+#undef CROW_CHUNKED
+#undef CROW_KEEP_ALIVE
+#undef CROW_CLOSE
+#undef CROW_PARSING_HEADER
+#undef CROW_CR
+#undef CROW_LF
+#undef CROW_LOWER
+#undef CROW_IS_ALPHA
+#undef CROW_IS_NUM
+#undef CROW_IS_ALPHANUM
+#undef CROW_IS_HEX
+#undef CROW_IS_MARK
+#undef CROW_IS_USERINFO_CHAR
+#undef CROW_TOKEN
+#undef CROW_IS_URL_CHAR
+#undef CROW_IS_HOST_CHAR
+#undef CROW_start_state
+#undef CROW_STRICT_CHECK
+#undef CROW_NEW_MESSAGE
#ifdef __cplusplus
}
@@ -4976,324 +6115,6 @@ http_parser_version(void) {
#pragma once
-#include <boost/algorithm/string/predicate.hpp>
-#include <boost/functional/hash.hpp>
-#include <unordered_map>
-
-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<std::string, std::string, ci_hash, ci_key_eq>;
-}
-
-
-
-#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
-*/
-#define CROW_LOG_LEVEL 1
-
-
-// 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 <boost/asio.hpp>
-
-
-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)
- {
- }
-
- 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()
- {
- socket_.close();
- }
-
- template <typename F>
- void start(F f)
- {
- f(boost::system::error_code());
- }
-
- tcp::socket socket_;
- };
-
-#ifdef CROW_ENABLE_SSL
- struct SSLAdaptor
- {
- using context = boost::asio::ssl::context;
- SSLAdaptor(boost::asio::io_service& io_service, context* ctx)
- : ssl_socket_(io_service, *ctx)
- {
- }
-
- boost::asio::ssl::stream<tcp::socket>& 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()
- {
- raw_socket().close();
- }
-
- template <typename F>
- void start(F f)
- {
- ssl_socket_.async_handshake(boost::asio::ssl::stream_base::server,
- [f](const boost::system::error_code& ec) {
- f(ec);
- });
- }
-
- boost::asio::ssl::stream<tcp::socket> ssl_socket_;
- };
-#endif
-}
-
-
-
-#pragma once
-
-#include <string>
-#include <cstdio>
-#include <cstdlib>
-#include <ctime>
-#include <iostream>
-#include <sstream>
-
-
-
-
-namespace crow
-{
- enum class LogLevel
- {
- DEBUG,
- 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;
-
-#ifdef _MSC_VER
- 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 <typename T>
- 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 <boost/asio.hpp>
#include <deque>
#include <functional>
@@ -5379,512 +6200,6 @@ namespace crow
#pragma once
-#include <cstdint>
-#include <stdexcept>
-#include <tuple>
-#include <type_traits>
-#include <cstring>
-#include <functional>
-
-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, "<int>", 0, 5);
- }
-
- constexpr bool is_uint(const_str s, unsigned i)
- {
- return is_equ_n(s, i, "<uint>", 0, 6);
- }
-
- constexpr bool is_float(const_str s, unsigned i)
- {
- return is_equ_n(s, i, "<float>", 0, 7) ||
- is_equ_n(s, i, "<double>", 0, 8);
- }
-
- constexpr bool is_str(const_str s, unsigned i)
- {
- return is_equ_n(s, i, "<str>", 0, 5) ||
- is_equ_n(s, i, "<string>", 0, 8);
- }
-
- constexpr bool is_path(const_str s, unsigned i)
- {
- return is_equ_n(s, i, "<path>", 0, 6);
- }
-#endif
- template <typename T>
- struct parameter_tag
- {
- static const int value = 0;
- };
-#define CROW_INTERNAL_PARAMETER_TAG(t, i) \
-template <> \
-struct parameter_tag<t> \
-{ \
- 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 <typename ... Args>
- struct compute_parameter_tag_from_args_list;
-
- template <>
- struct compute_parameter_tag_from_args_list<>
- {
- static const int value = 0;
- };
-
- template <typename Arg, typename ... Args>
- struct compute_parameter_tag_from_args_list<Arg, Args...>
- {
- static const int sub_value =
- compute_parameter_tag_from_args_list<Args...>::value;
- static const int value =
- parameter_tag<typename std::decay<Arg>::type>::value
- ? sub_value* 6 + parameter_tag<typename std::decay<Arg>::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, "<int>", 5) == 0
- ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 1 :
- std::strncmp(s+p, "<uint>", 6) == 0
- ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 2 :
- (std::strncmp(s+p, "<float>", 7) == 0 ||
- std::strncmp(s+p, "<double>", 8) == 0)
- ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 3 :
- (std::strncmp(s+p, "<str>", 5) == 0 ||
- std::strncmp(s+p, "<string>", 8) == 0)
- ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 4 :
- std::strncmp(s+p, "<path>", 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 <typename ... T>
- struct S
- {
- template <typename U>
- using push = S<U, T...>;
- template <typename U>
- using push_back = S<T..., U>;
- template <template<typename ... Args> class U>
- using rebind = U<T...>;
- };
-template <typename F, typename Set>
- struct CallHelper;
- template <typename F, typename ...Args>
- struct CallHelper<F, S<Args...>>
- {
- template <typename F1, typename ...Args1, typename =
- decltype(std::declval<F1>()(std::declval<Args1>()...))
- >
- static char __test(int);
-
- template <typename ...>
- static int __test(...);
-
- static constexpr bool value = sizeof(__test<F, Args...>(0)) == sizeof(char);
- };
-
-
- template <int N>
- 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 <uint64_t Tag>
- struct arguments
- {
- using subarguments = typename arguments<Tag/6>::type;
- using type =
- typename subarguments::template push<typename single_tag_to_type<Tag%6>::type>;
- };
-
- template <>
- struct arguments<0>
- {
- using type = S<>;
- };
-
- template <typename ... T>
- struct last_element_type
- {
- using type = typename std::tuple_element<sizeof...(T)-1, std::tuple<T...>>::type;
- };
-
-
- template <>
- struct last_element_type<>
- {
- };
-
-
- // from http://stackoverflow.com/questions/13072359/c11-compile-time-array-with-logarithmic-evaluation-depth
- template<class T> using Invoke = typename T::type;
-
- template<unsigned...> struct seq{ using type = seq; };
-
- template<class S1, class S2> struct concat;
-
- template<unsigned... I1, unsigned... I2>
- struct concat<seq<I1...>, seq<I2...>>
- : seq<I1..., (sizeof...(I1)+I2)...>{};
-
- template<class S1, class S2>
- using Concat = Invoke<concat<S1, S2>>;
-
- template<unsigned N> struct gen_seq;
- template<unsigned N> using GenSeq = Invoke<gen_seq<N>>;
-
- template<unsigned N>
- struct gen_seq : Concat<GenSeq<N/2>, GenSeq<N - N/2>>{};
-
- template<> struct gen_seq<0> : seq<>{};
- template<> struct gen_seq<1> : seq<0>{};
-
- template <typename Seq, typename Tuple>
- struct pop_back_helper;
-
- template <unsigned ... N, typename Tuple>
- struct pop_back_helper<seq<N...>, Tuple>
- {
- template <template <typename ... Args> class U>
- using rebind = U<typename std::tuple_element<N, Tuple>::type...>;
- };
-
- template <typename ... T>
- struct pop_back //: public pop_back_helper<typename gen_seq<sizeof...(T)-1>::type, std::tuple<T...>>
- {
- template <template <typename ... Args> class U>
- using rebind = typename pop_back_helper<typename gen_seq<sizeof...(T)-1>::type, std::tuple<T...>>::template rebind<U>;
- };
-
- template <>
- struct pop_back<>
- {
- template <template <typename ... Args> class U>
- using rebind = U<>;
- };
-
- // from http://stackoverflow.com/questions/2118541/check-if-c0x-parameter-pack-contains-a-type
- template < typename Tp, typename... List >
- struct contains : std::true_type {};
-
- template < typename Tp, typename Head, typename... Rest >
- struct contains<Tp, Head, Rest...>
- : std::conditional< std::is_same<Tp, Head>::value,
- std::true_type,
- contains<Tp, Rest...>
- >::type {};
-
- template < typename Tp >
- struct contains<Tp> : std::false_type {};
-
- template <typename T>
- struct empty_context
- {
- };
-
- template <typename T>
- struct promote
- {
- using type = T;
- };
-
-#define CROW_INTERNAL_PROMOTE_TYPE(t1, t2) \
- template<> \
- struct promote<t1> \
- { \
- using type = t2; \
- }
-
- CROW_INTERNAL_PROMOTE_TYPE(char, int64_t);
- CROW_INTERNAL_PROMOTE_TYPE(short, int64_t);
- CROW_INTERNAL_PROMOTE_TYPE(int, int64_t);
- CROW_INTERNAL_PROMOTE_TYPE(long, int64_t);
- CROW_INTERNAL_PROMOTE_TYPE(long long, int64_t);
- CROW_INTERNAL_PROMOTE_TYPE(unsigned char, uint64_t);
- CROW_INTERNAL_PROMOTE_TYPE(unsigned short, uint64_t);
- CROW_INTERNAL_PROMOTE_TYPE(unsigned int, uint64_t);
- CROW_INTERNAL_PROMOTE_TYPE(unsigned long, uint64_t);
- CROW_INTERNAL_PROMOTE_TYPE(unsigned long long, uint64_t);
- CROW_INTERNAL_PROMOTE_TYPE(float, double);
-#undef CROW_INTERNAL_PROMOTE_TYPE
-
- template <typename T>
- using promote_t = typename promote<T>::type;
-
- } // namespace black_magic
-
- namespace detail
- {
-
- template <class T, std::size_t N, class... Args>
- struct get_index_of_element_from_tuple_by_type_impl
- {
- static constexpr auto value = N;
- };
-
- template <class T, std::size_t N, class... Args>
- struct get_index_of_element_from_tuple_by_type_impl<T, N, T, Args...>
- {
- static constexpr auto value = N;
- };
-
- template <class T, std::size_t N, class U, class... Args>
- struct get_index_of_element_from_tuple_by_type_impl<T, N, U, Args...>
- {
- static constexpr auto value = get_index_of_element_from_tuple_by_type_impl<T, N + 1, Args...>::value;
- };
-
- } // namespace detail
-
- namespace utility
- {
- template <class T, class... Args>
- T& get_element_by_type(std::tuple<Args...>& t)
- {
- return std::get<detail::get_index_of_element_from_tuple_by_type_impl<T, 0, Args...>::value>(t);
- }
-
- template<typename T>
- struct function_traits;
-
-#ifndef CROW_MSVC_WORKAROUND
- template<typename T>
- struct function_traits : public function_traits<decltype(&T::operator())>
- {
- using parent_t = function_traits<decltype(&T::operator())>;
- static const size_t arity = parent_t::arity;
- using result_type = typename parent_t::result_type;
- template <size_t i>
- using arg = typename parent_t::template arg<i>;
-
- };
-#endif
-
- template<typename ClassType, typename R, typename ...Args>
- struct function_traits<R(ClassType::*)(Args...) const>
- {
- static const size_t arity = sizeof...(Args);
-
- typedef R result_type;
-
- template <size_t i>
- using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
- };
-
- template<typename ClassType, typename R, typename ...Args>
- struct function_traits<R(ClassType::*)(Args...)>
- {
- static const size_t arity = sizeof...(Args);
-
- typedef R result_type;
-
- template <size_t i>
- using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
- };
-
- template<typename R, typename ...Args>
- struct function_traits<std::function<R(Args...)>>
- {
- static const size_t arity = sizeof...(Args);
-
- typedef R result_type;
-
- template <size_t i>
- using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
- };
-
- } // namespace utility
-}
-
-
-
-#pragma once
-
#include <vector>
#include <string>
#include <stdexcept>
@@ -5896,7 +6211,8 @@ namespace crow
{
enum class HTTPMethod
{
- DELETE,
+#ifndef DELETE
+ DELETE = 0,
GET,
HEAD,
POST,
@@ -5904,27 +6220,37 @@ namespace crow
CONNECT,
OPTIONS,
TRACE,
+#endif
+
+ Delete = 0,
+ Get,
+ Head,
+ Post,
+ Put,
+ Connect,
+ Options,
+ Trace,
};
inline std::string method_name(HTTPMethod method)
{
switch(method)
{
- case HTTPMethod::DELETE:
+ case HTTPMethod::Delete:
return "DELETE";
- case HTTPMethod::GET:
+ case HTTPMethod::Get:
return "GET";
- case HTTPMethod::HEAD:
+ case HTTPMethod::Head:
return "HEAD";
- case HTTPMethod::POST:
+ case HTTPMethod::Post:
return "POST";
- case HTTPMethod::PUT:
+ case HTTPMethod::Put:
return "PUT";
- case HTTPMethod::CONNECT:
+ case HTTPMethod::Connect:
return "CONNECT";
- case HTTPMethod::OPTIONS:
+ case HTTPMethod::Options:
return "OPTIONS";
- case HTTPMethod::TRACE:
+ case HTTPMethod::Trace:
return "TRACE";
}
return "invalid";
@@ -5996,25 +6322,64 @@ namespace crow
}
#ifndef CROW_MSVC_WORKAROUND
-constexpr crow::HTTPMethod operator "" _method(const char* str, size_t len)
+constexpr crow::HTTPMethod operator "" _method(const char* str, size_t /*len*/)
{
return
- crow::black_magic::is_equ_p(str, "GET", 3) ? crow::HTTPMethod::GET :
- crow::black_magic::is_equ_p(str, "DELETE", 6) ? crow::HTTPMethod::DELETE :
- crow::black_magic::is_equ_p(str, "HEAD", 4) ? crow::HTTPMethod::HEAD :
- crow::black_magic::is_equ_p(str, "POST", 4) ? crow::HTTPMethod::POST :
- crow::black_magic::is_equ_p(str, "PUT", 3) ? crow::HTTPMethod::PUT :
- crow::black_magic::is_equ_p(str, "OPTIONS", 7) ? crow::HTTPMethod::OPTIONS :
- crow::black_magic::is_equ_p(str, "CONNECT", 7) ? crow::HTTPMethod::CONNECT :
- crow::black_magic::is_equ_p(str, "TRACE", 5) ? crow::HTTPMethod::TRACE :
+ crow::black_magic::is_equ_p(str, "GET", 3) ? crow::HTTPMethod::Get :
+ crow::black_magic::is_equ_p(str, "DELETE", 6) ? crow::HTTPMethod::Delete :
+ crow::black_magic::is_equ_p(str, "HEAD", 4) ? crow::HTTPMethod::Head :
+ crow::black_magic::is_equ_p(str, "POST", 4) ? crow::HTTPMethod::Post :
+ crow::black_magic::is_equ_p(str, "PUT", 3) ? crow::HTTPMethod::Put :
+ crow::black_magic::is_equ_p(str, "OPTIONS", 7) ? crow::HTTPMethod::Options :
+ crow::black_magic::is_equ_p(str, "CONNECT", 7) ? crow::HTTPMethod::Connect :
+ crow::black_magic::is_equ_p(str, "TRACE", 5) ? crow::HTTPMethod::Trace :
throw std::runtime_error("invalid http method");
-};
+}
#endif
#pragma once
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/functional/hash.hpp>
+#include <unordered_map>
+
+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<std::string, std::string, ci_hash, ci_key_eq>;
+}
+
+
+
+#pragma once
+
+#include <boost/asio.hpp>
+
@@ -6035,6 +6400,8 @@ namespace crow
return empty;
}
+ struct DetachHelper;
+
struct request
{
HTTPMethod method;
@@ -6045,9 +6412,10 @@ namespace crow
std::string body;
void* middleware_context{};
+ boost::asio::io_service* io_service{};
request()
- : method(HTTPMethod::GET)
+ : method(HTTPMethod::Get)
{
}
@@ -6066,12 +6434,519 @@ namespace crow
return crow::get_header_value(headers, key);
}
+ template<typename CompletionHandler>
+ void post(CompletionHandler handler)
+ {
+ io_service->post(handler);
+ }
+
+ template<typename CompletionHandler>
+ void dispatch(CompletionHandler handler)
+ {
+ io_service->dispatch(handler);
+ }
+
};
}
#pragma once
+#include <boost/algorithm/string/predicate.hpp>
+
+
+
+
+
+
+
+namespace crow
+{
+ namespace websocket
+ {
+ enum class WebSocketReadState
+ {
+ MiniHeader,
+ Len16,
+ Len64,
+ Mask,
+ Payload,
+ };
+
+ struct connection
+ {
+ virtual void send_binary(const std::string& msg) = 0;
+ virtual void send_text(const std::string& msg) = 0;
+ virtual void close(const std::string& msg = "quit") = 0;
+ virtual ~connection(){}
+
+ void userdata(void* u) { userdata_ = u; }
+ void* userdata() { return userdata_; }
+
+ private:
+ void* userdata_;
+ };
+
+ template <typename Adaptor>
+ class Connection : public connection
+ {
+ public:
+ Connection(const crow::request& req, Adaptor&& adaptor,
+ std::function<void(crow::websocket::connection&)> open_handler,
+ std::function<void(crow::websocket::connection&, const std::string&, bool)> message_handler,
+ std::function<void(crow::websocket::connection&, const std::string&)> close_handler,
+ std::function<void(crow::websocket::connection&)> error_handler)
+ : adaptor_(std::move(adaptor)), open_handler_(std::move(open_handler)), message_handler_(std::move(message_handler)), close_handler_(std::move(close_handler)), error_handler_(std::move(error_handler))
+ {
+ if (!boost::iequals(req.get_header_value("upgrade"), "websocket"))
+ {
+ adaptor.close();
+ delete this;
+ return;
+ }
+ // Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
+ // Sec-WebSocket-Version: 13
+ std::string magic = req.get_header_value("Sec-WebSocket-Key") + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+ sha1::SHA1 s;
+ s.processBytes(magic.data(), magic.size());
+ uint8_t digest[20];
+ s.getDigestBytes(digest);
+ start(crow::utility::base64encode((char*)digest, 20));
+ }
+
+ template<typename CompletionHandler>
+ void dispatch(CompletionHandler handler)
+ {
+ adaptor_.get_io_service().dispatch(handler);
+ }
+
+ template<typename CompletionHandler>
+ void post(CompletionHandler handler)
+ {
+ adaptor_.get_io_service().post(handler);
+ }
+
+ void send_pong(const std::string& msg)
+ {
+ dispatch([this, msg]{
+ char buf[3] = "\x8A\x00";
+ buf[1] += msg.size();
+ write_buffers_.emplace_back(buf, buf+2);
+ write_buffers_.emplace_back(msg);
+ do_write();
+ });
+ }
+
+ void send_binary(const std::string& msg) override
+ {
+ dispatch([this, msg]{
+ auto header = build_header(2, msg.size());
+ write_buffers_.emplace_back(std::move(header));
+ write_buffers_.emplace_back(msg);
+ do_write();
+ });
+ }
+
+ void send_text(const std::string& msg) override
+ {
+ dispatch([this, msg]{
+ auto header = build_header(1, msg.size());
+ write_buffers_.emplace_back(std::move(header));
+ write_buffers_.emplace_back(msg);
+ do_write();
+ });
+ }
+
+ void close(const std::string& msg) override
+ {
+ dispatch([this, msg]{
+ has_sent_close_ = true;
+ if (has_recv_close_ && !is_close_handler_called_)
+ {
+ is_close_handler_called_ = true;
+ if (close_handler_)
+ close_handler_(*this, msg);
+ }
+ auto header = build_header(0x8, msg.size());
+ write_buffers_.emplace_back(std::move(header));
+ write_buffers_.emplace_back(msg);
+ do_write();
+ });
+ }
+
+ protected:
+
+ std::string build_header(int opcode, size_t size)
+ {
+ char buf[2+8] = "\x80\x00";
+ buf[0] += opcode;
+ if (size < 126)
+ {
+ buf[1] += size;
+ return {buf, buf+2};
+ }
+ else if (size < 0x10000)
+ {
+ buf[1] += 126;
+ *(uint16_t*)(buf+2) = htons((uint16_t)size);
+ return {buf, buf+4};
+ }
+ else
+ {
+ buf[1] += 127;
+ *(uint64_t*)(buf+2) = ((1==htonl(1)) ? (uint64_t)size : ((uint64_t)htonl((size) & 0xFFFFFFFF) << 32) | htonl((size) >> 32));
+ return {buf, buf+10};
+ }
+ }
+
+ void start(std::string&& hello)
+ {
+ static std::string header = "HTTP/1.1 101 Switching Protocols\r\n"
+ "Upgrade: websocket\r\n"
+ "Connection: Upgrade\r\n"
+ "Sec-WebSocket-Accept: ";
+ static std::string crlf = "\r\n";
+ write_buffers_.emplace_back(header);
+ write_buffers_.emplace_back(std::move(hello));
+ write_buffers_.emplace_back(crlf);
+ write_buffers_.emplace_back(crlf);
+ do_write();
+ if (open_handler_)
+ open_handler_(*this);
+ do_read();
+ }
+
+ void do_read()
+ {
+ is_reading = true;
+ switch(state_)
+ {
+ case WebSocketReadState::MiniHeader:
+ {
+ //boost::asio::async_read(adaptor_.socket(), boost::asio::buffer(&mini_header_, 1),
+ adaptor_.socket().async_read_some(boost::asio::buffer(&mini_header_, 2),
+ [this](const boost::system::error_code& ec, std::size_t bytes_transferred)
+ {
+ is_reading = false;
+ mini_header_ = htons(mini_header_);
+#ifdef CROW_ENABLE_DEBUG
+
+ if (!ec && bytes_transferred != 2)
+ {
+ throw std::runtime_error("WebSocket:MiniHeader:async_read fail:asio bug?");
+ }
+#endif
+
+ if (!ec && ((mini_header_ & 0x80) == 0x80))
+ {
+ if ((mini_header_ & 0x7f) == 127)
+ {
+ state_ = WebSocketReadState::Len64;
+ }
+ else if ((mini_header_ & 0x7f) == 126)
+ {
+ state_ = WebSocketReadState::Len16;
+ }
+ else
+ {
+ remaining_length_ = mini_header_ & 0x7f;
+ state_ = WebSocketReadState::Mask;
+ }
+ do_read();
+ }
+ else
+ {
+ close_connection_ = true;
+ adaptor_.close();
+ if (error_handler_)
+ error_handler_(*this);
+ check_destroy();
+ }
+ });
+ }
+ break;
+ case WebSocketReadState::Len16:
+ {
+ remaining_length_ = 0;
+ boost::asio::async_read(adaptor_.socket(), boost::asio::buffer(&remaining_length_, 2),
+ [this](const boost::system::error_code& ec, std::size_t bytes_transferred)
+ {
+ is_reading = false;
+ remaining_length_ = ntohs(*(uint16_t*)&remaining_length_);
+#ifdef CROW_ENABLE_DEBUG
+ if (!ec && bytes_transferred != 2)
+ {
+ throw std::runtime_error("WebSocket:Len16:async_read fail:asio bug?");
+ }
+#endif
+
+ if (!ec)
+ {
+ state_ = WebSocketReadState::Mask;
+ do_read();
+ }
+ else
+ {
+ close_connection_ = true;
+ adaptor_.close();
+ if (error_handler_)
+ error_handler_(*this);
+ check_destroy();
+ }
+ });
+ }
+ break;
+ case WebSocketReadState::Len64:
+ {
+ boost::asio::async_read(adaptor_.socket(), boost::asio::buffer(&remaining_length_, 8),
+ [this](const boost::system::error_code& ec, std::size_t bytes_transferred)
+ {
+ is_reading = false;
+ remaining_length_ = ((1==ntohl(1)) ? (remaining_length_) : ((uint64_t)ntohl((remaining_length_) & 0xFFFFFFFF) << 32) | ntohl((remaining_length_) >> 32));
+#ifdef CROW_ENABLE_DEBUG
+ if (!ec && bytes_transferred != 8)
+ {
+ throw std::runtime_error("WebSocket:Len16:async_read fail:asio bug?");
+ }
+#endif
+
+ if (!ec)
+ {
+ state_ = WebSocketReadState::Mask;
+ do_read();
+ }
+ else
+ {
+ close_connection_ = true;
+ adaptor_.close();
+ if (error_handler_)
+ error_handler_(*this);
+ check_destroy();
+ }
+ });
+ }
+ break;
+ case WebSocketReadState::Mask:
+ boost::asio::async_read(adaptor_.socket(), boost::asio::buffer((char*)&mask_, 4),
+ [this](const boost::system::error_code& ec, std::size_t bytes_transferred)
+ {
+ is_reading = false;
+#ifdef CROW_ENABLE_DEBUG
+ if (!ec && bytes_transferred != 4)
+ {
+ throw std::runtime_error("WebSocket:Mask:async_read fail:asio bug?");
+ }
+#endif
+
+ if (!ec)
+ {
+ state_ = WebSocketReadState::Payload;
+ do_read();
+ }
+ else
+ {
+ close_connection_ = true;
+ if (error_handler_)
+ error_handler_(*this);
+ adaptor_.close();
+ }
+ });
+ break;
+ case WebSocketReadState::Payload:
+ {
+ size_t to_read = buffer_.size();
+ if (remaining_length_ < to_read)
+ to_read = remaining_length_;
+ adaptor_.socket().async_read_some( boost::asio::buffer(buffer_, to_read),
+ [this](const boost::system::error_code& ec, std::size_t bytes_transferred)
+ {
+ is_reading = false;
+
+ if (!ec)
+ {
+ fragment_.insert(fragment_.end(), buffer_.begin(), buffer_.begin() + bytes_transferred);
+ remaining_length_ -= bytes_transferred;
+ if (remaining_length_ == 0)
+ {
+ handle_fragment();
+ state_ = WebSocketReadState::MiniHeader;
+ do_read();
+ }
+ }
+ else
+ {
+ close_connection_ = true;
+ if (error_handler_)
+ error_handler_(*this);
+ adaptor_.close();
+ }
+ });
+ }
+ break;
+ }
+ }
+
+ bool is_FIN()
+ {
+ return mini_header_ & 0x8000;
+ }
+
+ int opcode()
+ {
+ return (mini_header_ & 0x0f00) >> 8;
+ }
+
+ void handle_fragment()
+ {
+ for(decltype(fragment_.length()) i = 0; i < fragment_.length(); i ++)
+ {
+ fragment_[i] ^= ((char*)&mask_)[i%4];
+ }
+ switch(opcode())
+ {
+ case 0: // Continuation
+ {
+ message_ += fragment_;
+ if (is_FIN())
+ {
+ if (message_handler_)
+ message_handler_(*this, message_, is_binary_);
+ message_.clear();
+ }
+ }
+ case 1: // Text
+ {
+ is_binary_ = false;
+ message_ += fragment_;
+ if (is_FIN())
+ {
+ if (message_handler_)
+ message_handler_(*this, message_, is_binary_);
+ message_.clear();
+ }
+ }
+ break;
+ case 2: // Binary
+ {
+ is_binary_ = true;
+ message_ += fragment_;
+ if (is_FIN())
+ {
+ if (message_handler_)
+ message_handler_(*this, message_, is_binary_);
+ message_.clear();
+ }
+ }
+ break;
+ case 0x8: // Close
+ {
+ has_recv_close_ = true;
+ if (!has_sent_close_)
+ {
+ close(fragment_);
+ }
+ else
+ {
+ adaptor_.close();
+ close_connection_ = true;
+ if (!is_close_handler_called_)
+ {
+ if (close_handler_)
+ close_handler_(*this, fragment_);
+ is_close_handler_called_ = true;
+ }
+ check_destroy();
+ }
+ }
+ break;
+ case 0x9: // Ping
+ {
+ send_pong(fragment_);
+ }
+ break;
+ case 0xA: // Pong
+ {
+ pong_received_ = true;
+ }
+ break;
+ }
+
+ fragment_.clear();
+ }
+
+ void do_write()
+ {
+ if (sending_buffers_.empty())
+ {
+ sending_buffers_.swap(write_buffers_);
+ std::vector<boost::asio::const_buffer> buffers;
+ buffers.reserve(sending_buffers_.size());
+ for(auto& s:sending_buffers_)
+ {
+ buffers.emplace_back(boost::asio::buffer(s));
+ }
+ boost::asio::async_write(adaptor_.socket(), buffers,
+ [&](const boost::system::error_code& ec, std::size_t /*bytes_transferred*/)
+ {
+ sending_buffers_.clear();
+ if (!ec && !close_connection_)
+ {
+ if (!write_buffers_.empty())
+ do_write();
+ if (has_sent_close_)
+ close_connection_ = true;
+ }
+ else
+ {
+ close_connection_ = true;
+ check_destroy();
+ }
+ });
+ }
+ }
+
+ void check_destroy()
+ {
+ //if (has_sent_close_ && has_recv_close_)
+ if (!is_close_handler_called_)
+ if (close_handler_)
+ close_handler_(*this, "uncleanly");
+ if (sending_buffers_.empty() && !is_reading)
+ delete this;
+ }
+ private:
+ Adaptor adaptor_;
+
+ std::vector<std::string> sending_buffers_;
+ std::vector<std::string> write_buffers_;
+
+ boost::array<char, 4096> buffer_;
+ bool is_binary_;
+ std::string message_;
+ std::string fragment_;
+ WebSocketReadState state_{WebSocketReadState::MiniHeader};
+ uint64_t remaining_length_{0};
+ bool close_connection_{false};
+ bool is_reading{false};
+ uint32_t mask_;
+ uint16_t mini_header_;
+ bool has_sent_close_{false};
+ bool has_recv_close_{false};
+ bool error_occured_{false};
+ bool pong_received_{false};
+ bool is_close_handler_called_{false};
+
+ std::function<void(crow::websocket::connection&)> open_handler_;
+ std::function<void(crow::websocket::connection&, const std::string&, bool)> message_handler_;
+ std::function<void(crow::websocket::connection&, const std::string&)> close_handler_;
+ std::function<void(crow::websocket::connection&)> error_handler_;
+ };
+ }
+}
+
+
+
+#pragma once
#include <string>
#include <unordered_map>
@@ -6218,6 +7093,11 @@ namespace crow
return request{(HTTPMethod)method, std::move(raw_url), std::move(url), std::move(url_params), std::move(headers), std::move(body)};
}
+ bool is_upgrade() const
+ {
+ return upgrade;
+ }
+
bool check_version(int major, int minor) const
{
return http_major == major && http_minor == minor;
@@ -6249,6 +7129,7 @@ namespace crow
+
namespace crow
{
template <typename Adaptor, typename Handler, typename ... Middlewares>
@@ -6374,185 +7255,6 @@ namespace crow
#pragma once
-#include <boost/algorithm/string/trim.hpp>
-
-
-
-
-
-namespace crow
-{
- // Any middleware requires following 3 members:
-
- // struct context;
- // storing data for the middleware; can be read from another middleware or handlers
-
- // before_handle
- // called before handling the request.
- // if res.end() is called, the operation is halted.
- // (still call after_handle of this middleware)
- // 2 signatures:
- // void before_handle(request& req, response& res, context& ctx)
- // if you only need to access this middlewares context.
- // template <typename AllContext>
- // void before_handle(request& req, response& res, context& ctx, AllContext& all_ctx)
- // you can access another middlewares' context by calling `all_ctx.template get<MW>()'
- // ctx == all_ctx.template get<CurrentMiddleware>()
-
- // after_handle
- // called after handling the request.
- // void after_handle(request& req, response& res, context& ctx)
- // template <typename AllContext>
- // void after_handle(request& req, response& res, context& ctx, AllContext& all_ctx)
-
- struct CookieParser
- {
- struct context
- {
- std::unordered_map<std::string, std::string> jar;
- std::unordered_map<std::string, std::string> cookies_to_add;
-
- std::string get_cookie(const std::string& key)
- {
- if (jar.count(key))
- return jar[key];
- return {};
- }
-
- void set_cookie(const std::string& key, const std::string& value)
- {
- cookies_to_add.emplace(key, value);
- }
- };
-
- void before_handle(request& req, response& res, context& ctx)
- {
- int count = req.headers.count("Cookie");
- if (!count)
- return;
- if (count > 1)
- {
- res.code = 400;
- res.end();
- return;
- }
- std::string cookies = req.get_header_value("Cookie");
- size_t pos = 0;
- while(pos < cookies.size())
- {
- size_t pos_equal = cookies.find('=', pos);
- if (pos_equal == cookies.npos)
- break;
- std::string name = cookies.substr(pos, pos_equal-pos);
- boost::trim(name);
- pos = pos_equal+1;
- while(pos < cookies.size() && cookies[pos] == ' ') pos++;
- if (pos == cookies.size())
- break;
-
- std::string value;
-
- if (cookies[pos] == '"')
- {
- int dquote_meet_count = 0;
- pos ++;
- size_t pos_dquote = pos-1;
- do
- {
- pos_dquote = cookies.find('"', pos_dquote+1);
- dquote_meet_count ++;
- } while(pos_dquote < cookies.size() && cookies[pos_dquote-1] == '\\');
- if (pos_dquote == cookies.npos)
- break;
-
- if (dquote_meet_count == 1)
- value = cookies.substr(pos, pos_dquote - pos);
- else
- {
- value.clear();
- value.reserve(pos_dquote-pos);
- for(size_t p = pos; p < pos_dquote; p++)
- {
- // FIXME minimal escaping
- if (cookies[p] == '\\' && p + 1 < pos_dquote)
- {
- p++;
- if (cookies[p] == '\\' || cookies[p] == '"')
- value += cookies[p];
- else
- {
- value += '\\';
- value += cookies[p];
- }
- }
- else
- value += cookies[p];
- }
- }
-
- ctx.jar.emplace(std::move(name), std::move(value));
- pos = cookies.find(";", pos_dquote+1);
- if (pos == cookies.npos)
- break;
- pos++;
- while(pos < cookies.size() && cookies[pos] == ' ') pos++;
- if (pos == cookies.size())
- break;
- }
- else
- {
- size_t pos_semicolon = cookies.find(';', pos);
- value = cookies.substr(pos, pos_semicolon - pos);
- boost::trim(value);
- ctx.jar.emplace(std::move(name), std::move(value));
- pos = pos_semicolon;
- if (pos == cookies.npos)
- break;
- pos ++;
- while(pos < cookies.size() && cookies[pos] == ' ') pos++;
- if (pos == cookies.size())
- break;
- }
- }
- }
-
- void after_handle(request& req, response& res, context& ctx)
- {
- for(auto& cookie:ctx.cookies_to_add)
- {
- res.add_header("Set-Cookie", cookie.first + "=" + cookie.second);
- }
- }
- };
-
- /*
- App<CookieParser, AnotherJarMW> app;
- A B C
- A::context
- int aa;
-
- ctx1 : public A::context
- ctx2 : public ctx1, public B::context
- ctx3 : public ctx2, public C::context
-
- C depends on A
-
- C::handle
- context.aaa
-
- App::context : private CookieParser::contetx, ...
- {
- jar
-
- }
-
- SimpleApp
- */
-}
-
-
-
-#pragma once
#include <cstdint>
#include <utility>
@@ -6573,6 +7275,8 @@ namespace crow
+
+
namespace crow
{
class BaseRule
@@ -6588,8 +7292,26 @@ namespace crow
}
virtual void validate() = 0;
+ std::unique_ptr<BaseRule> upgrade()
+ {
+ if (rule_to_upgrade_)
+ return std::move(rule_to_upgrade_);
+ return {};
+ }
virtual void handle(const request&, response&, const routing_params&) = 0;
+ virtual void handle_upgrade(const request&, response& res, SocketAdaptor&&)
+ {
+ res = response(404);
+ res.end();
+ }
+#ifdef CROW_ENABLE_SSL
+ virtual void handle_upgrade(const request&, response& res, SSLAdaptor&&)
+ {
+ res = response(404);
+ res.end();
+ }
+#endif
uint32_t get_methods()
{
@@ -6597,10 +7319,13 @@ namespace crow
}
protected:
- uint32_t methods_{1<<(int)HTTPMethod::GET};
+ uint32_t methods_{1<<(int)HTTPMethod::Get};
std::string rule_;
std::string name_;
+
+ std::unique_ptr<BaseRule> rule_to_upgrade_;
+
friend class Router;
template <typename T>
friend struct RuleParameterTraits;
@@ -6693,7 +7418,7 @@ namespace crow
struct Wrapped
{
template <typename ... Args>
- void set(Func f, typename std::enable_if<
+ void set_(Func f, typename std::enable_if<
!std::is_same<typename std::tuple_element<0, std::tuple<Args..., void>>::type, const request&>::value
, int>::type = 0)
{
@@ -6727,7 +7452,7 @@ namespace crow
};
template <typename ... Args>
- void set(Func f, typename std::enable_if<
+ void set_(Func f, typename std::enable_if<
std::is_same<typename std::tuple_element<0, std::tuple<Args..., void>>::type, const request&>::value &&
!std::is_same<typename std::tuple_element<1, std::tuple<Args..., void, void>>::type, response&>::value
, int>::type = 0)
@@ -6742,7 +7467,7 @@ namespace crow
}
template <typename ... Args>
- void set(Func f, typename std::enable_if<
+ void set_(Func f, typename std::enable_if<
std::is_same<typename std::tuple_element<0, std::tuple<Args..., void>>::type, const request&>::value &&
std::is_same<typename std::tuple_element<1, std::tuple<Args..., void, void>>::type, response&>::value
, int>::type = 0)
@@ -6792,10 +7517,82 @@ namespace crow
}
}
+ class WebSocketRule : public BaseRule
+ {
+ using self_t = WebSocketRule;
+ public:
+ WebSocketRule(std::string rule)
+ : BaseRule(std::move(rule))
+ {
+ }
+
+ void validate() override
+ {
+ }
+
+ void handle(const request&, response& res, const routing_params&) override
+ {
+ res = response(404);
+ res.end();
+ }
+
+ void handle_upgrade(const request& req, response&, SocketAdaptor&& adaptor) override
+ {
+ new crow::websocket::Connection<SocketAdaptor>(req, std::move(adaptor), open_handler_, message_handler_, close_handler_, error_handler_);
+ }
+#ifdef CROW_ENABLE_SSL
+ void handle_upgrade(const request& req, response&, SSLAdaptor&& adaptor) override
+ {
+ new crow::websocket::Connection<SSLAdaptor>(req, std::move(adaptor), open_handler_, message_handler_, close_handler_, error_handler_);
+ }
+#endif
+
+ template <typename Func>
+ self_t& onopen(Func f)
+ {
+ open_handler_ = f;
+ return *this;
+ }
+
+ template <typename Func>
+ self_t& onmessage(Func f)
+ {
+ message_handler_ = f;
+ return *this;
+ }
+
+ template <typename Func>
+ self_t& onclose(Func f)
+ {
+ close_handler_ = f;
+ return *this;
+ }
+
+ template <typename Func>
+ self_t& onerror(Func f)
+ {
+ error_handler_ = f;
+ return *this;
+ }
+
+ protected:
+ std::function<void(crow::websocket::connection&)> open_handler_;
+ std::function<void(crow::websocket::connection&, const std::string&, bool)> message_handler_;
+ std::function<void(crow::websocket::connection&, const std::string&)> close_handler_;
+ std::function<void(crow::websocket::connection&)> error_handler_;
+ };
+
template <typename T>
struct RuleParameterTraits
{
using self_t = T;
+ WebSocketRule& websocket()
+ {
+ auto p =new WebSocketRule(((self_t*)this)->rule_);
+ ((self_t*)this)->rule_to_upgrade_.reset(p);
+ return *p;
+ }
+
self_t& name(std::string name) noexcept
{
((self_t*)this)->name_ = std::move(name);
@@ -6815,6 +7612,7 @@ namespace crow
((self_t*)this)->methods_ |= 1 << (int)method;
return (self_t&)*this;
}
+
};
class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
@@ -6874,7 +7672,7 @@ namespace crow
throw std::runtime_error("route_dynamic: Handler type is mismatched with URL parameters: " + rule_);
}
auto ret = detail::routing_handler_call_helper::Wrapped<Func, typename function_t::template arg<Indices>...>();
- ret.template set<
+ ret.template set_<
typename function_t::template arg<Indices>...
>(std::move(f));
return ret;
@@ -6902,7 +7700,7 @@ namespace crow
{
}
- void validate()
+ void validate() override
{
if (!handler_)
{
@@ -7368,16 +8166,85 @@ public:
for(auto& rule:rules_)
{
if (rule)
+ {
+ auto upgraded = rule->upgrade();
+ if (upgraded)
+ rule = std::move(upgraded);
rule->validate();
+ }
}
}
+ template <typename Adaptor>
+ void handle_upgrade(const request& req, response& res, Adaptor&& adaptor)
+ {
+ auto found = trie_.find(req.url);
+ unsigned rule_index = found.first;
+ if (!rule_index)
+ {
+ CROW_LOG_DEBUG << "Cannot match rules " << req.url;
+ res = response(404);
+ res.end();
+ return;
+ }
+
+ if (rule_index >= rules_.size())
+ throw std::runtime_error("Trie internal structure corrupted!");
+
+ if (rule_index == RULE_SPECIAL_REDIRECT_SLASH)
+ {
+ CROW_LOG_INFO << "Redirecting to a url with trailing slash: " << req.url;
+ res = response(301);
+
+ // TODO absolute url building
+ if (req.get_header_value("Host").empty())
+ {
+ res.add_header("Location", req.url + "/");
+ }
+ else
+ {
+ res.add_header("Location", "http://" + req.get_header_value("Host") + req.url + "/");
+ }
+ res.end();
+ return;
+ }
+
+ if ((rules_[rule_index]->get_methods() & (1<<(uint32_t)req.method)) == 0)
+ {
+ CROW_LOG_DEBUG << "Rule found but method mismatch: " << req.url << " with " << method_name(req.method) << "(" << (uint32_t)req.method << ") / " << rules_[rule_index]->get_methods();
+ res = response(404);
+ res.end();
+ return;
+ }
+
+ CROW_LOG_DEBUG << "Matched rule (upgrade) '" << rules_[rule_index]->rule_ << "' " << (uint32_t)req.method << " / " << rules_[rule_index]->get_methods();
+
+ // any uncaught exceptions become 500s
+ try
+ {
+ rules_[rule_index]->handle_upgrade(req, res, std::move(adaptor));
+ }
+ catch(std::exception& e)
+ {
+ CROW_LOG_ERROR << "An uncaught exception occurred: " << e.what();
+ res = response(500);
+ res.end();
+ return;
+ }
+ catch(...)
+ {
+ CROW_LOG_ERROR << "An uncaught exception occurred. The type was unknown so no information was available.";
+ res = response(500);
+ res.end();
+ return;
+ }
+ }
+
void handle(const request& req, response& res)
{
auto found = trie_.find(req.url);
unsigned rule_index = found.first;
- CROW_LOG_DEBUG << "???" << rule_index;
if (!rule_index)
{
@@ -7518,6 +8385,185 @@ namespace crow
#pragma once
+#include <boost/algorithm/string/trim.hpp>
+
+
+
+
+
+namespace crow
+{
+ // Any middleware requires following 3 members:
+
+ // struct context;
+ // storing data for the middleware; can be read from another middleware or handlers
+
+ // before_handle
+ // called before handling the request.
+ // if res.end() is called, the operation is halted.
+ // (still call after_handle of this middleware)
+ // 2 signatures:
+ // void before_handle(request& req, response& res, context& ctx)
+ // if you only need to access this middlewares context.
+ // template <typename AllContext>
+ // void before_handle(request& req, response& res, context& ctx, AllContext& all_ctx)
+ // you can access another middlewares' context by calling `all_ctx.template get<MW>()'
+ // ctx == all_ctx.template get<CurrentMiddleware>()
+
+ // after_handle
+ // called after handling the request.
+ // void after_handle(request& req, response& res, context& ctx)
+ // template <typename AllContext>
+ // void after_handle(request& req, response& res, context& ctx, AllContext& all_ctx)
+
+ struct CookieParser
+ {
+ struct context
+ {
+ std::unordered_map<std::string, std::string> jar;
+ std::unordered_map<std::string, std::string> cookies_to_add;
+
+ std::string get_cookie(const std::string& key)
+ {
+ if (jar.count(key))
+ return jar[key];
+ return {};
+ }
+
+ void set_cookie(const std::string& key, const std::string& value)
+ {
+ cookies_to_add.emplace(key, value);
+ }
+ };
+
+ void before_handle(request& req, response& res, context& ctx)
+ {
+ int count = req.headers.count("Cookie");
+ if (!count)
+ return;
+ if (count > 1)
+ {
+ res.code = 400;
+ res.end();
+ return;
+ }
+ std::string cookies = req.get_header_value("Cookie");
+ size_t pos = 0;
+ while(pos < cookies.size())
+ {
+ size_t pos_equal = cookies.find('=', pos);
+ if (pos_equal == cookies.npos)
+ break;
+ std::string name = cookies.substr(pos, pos_equal-pos);
+ boost::trim(name);
+ pos = pos_equal+1;
+ while(pos < cookies.size() && cookies[pos] == ' ') pos++;
+ if (pos == cookies.size())
+ break;
+
+ std::string value;
+
+ if (cookies[pos] == '"')
+ {
+ int dquote_meet_count = 0;
+ pos ++;
+ size_t pos_dquote = pos-1;
+ do
+ {
+ pos_dquote = cookies.find('"', pos_dquote+1);
+ dquote_meet_count ++;
+ } while(pos_dquote < cookies.size() && cookies[pos_dquote-1] == '\\');
+ if (pos_dquote == cookies.npos)
+ break;
+
+ if (dquote_meet_count == 1)
+ value = cookies.substr(pos, pos_dquote - pos);
+ else
+ {
+ value.clear();
+ value.reserve(pos_dquote-pos);
+ for(size_t p = pos; p < pos_dquote; p++)
+ {
+ // FIXME minimal escaping
+ if (cookies[p] == '\\' && p + 1 < pos_dquote)
+ {
+ p++;
+ if (cookies[p] == '\\' || cookies[p] == '"')
+ value += cookies[p];
+ else
+ {
+ value += '\\';
+ value += cookies[p];
+ }
+ }
+ else
+ value += cookies[p];
+ }
+ }
+
+ ctx.jar.emplace(std::move(name), std::move(value));
+ pos = cookies.find(";", pos_dquote+1);
+ if (pos == cookies.npos)
+ break;
+ pos++;
+ while(pos < cookies.size() && cookies[pos] == ' ') pos++;
+ if (pos == cookies.size())
+ break;
+ }
+ else
+ {
+ size_t pos_semicolon = cookies.find(';', pos);
+ value = cookies.substr(pos, pos_semicolon - pos);
+ boost::trim(value);
+ ctx.jar.emplace(std::move(name), std::move(value));
+ pos = pos_semicolon;
+ if (pos == cookies.npos)
+ break;
+ pos ++;
+ while(pos < cookies.size() && cookies[pos] == ' ') pos++;
+ if (pos == cookies.size())
+ break;
+ }
+ }
+ }
+
+ void after_handle(request& /*req*/, response& res, context& ctx)
+ {
+ for(auto& cookie:ctx.cookies_to_add)
+ {
+ res.add_header("Set-Cookie", cookie.first + "=" + cookie.second);
+ }
+ }
+ };
+
+ /*
+ App<CookieParser, AnotherJarMW> app;
+ A B C
+ A::context
+ int aa;
+
+ ctx1 : public A::context
+ ctx2 : public ctx1, public B::context
+ ctx3 : public ctx2, public C::context
+
+ C depends on A
+
+ C::handle
+ context.aaa
+
+ App::context : private CookieParser::contetx, ...
+ {
+ jar
+
+ }
+
+ SimpleApp
+ */
+}
+
+
+
+#pragma once
#include <boost/asio.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/lexical_cast.hpp>
@@ -7625,28 +8671,28 @@ namespace crow
template <typename MW, typename Context, typename ParentContext>
typename std::enable_if<!is_before_handle_arity_3_impl<MW>::value>::type
- before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& parent_ctx)
+ before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
{
mw.before_handle(req, res, ctx.template get<MW>(), ctx);
}
template <typename MW, typename Context, typename ParentContext>
typename std::enable_if<is_before_handle_arity_3_impl<MW>::value>::type
- before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& parent_ctx)
+ before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
{
mw.before_handle(req, res, ctx.template get<MW>());
}
template <typename MW, typename Context, typename ParentContext>
typename std::enable_if<!is_after_handle_arity_3_impl<MW>::value>::type
- after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& parent_ctx)
+ after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
{
mw.after_handle(req, res, ctx.template get<MW>(), ctx);
}
template <typename MW, typename Context, typename ParentContext>
typename std::enable_if<is_after_handle_arity_3_impl<MW>::value>::type
- after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& parent_ctx)
+ after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
{
mw.after_handle(req, res, ctx.template get<MW>());
}
@@ -7673,14 +8719,14 @@ namespace crow
}
template <int N, typename Context, typename Container>
- bool middleware_call_helper(Container& middlewares, request& req, response& res, Context& ctx)
+ bool middleware_call_helper(Container& /*middlewares*/, request& /*req*/, response& /*res*/, Context& /*ctx*/)
{
return false;
}
template <int N, typename Context, typename Container>
typename std::enable_if<(N<0)>::type
- after_handlers_call_helper(Container& middlewares, Context& context, request& req, response& res)
+ after_handlers_call_helper(Container& /*middlewares*/, Context& /*context*/, request& /*req*/, response& /*res*/)
{
}
@@ -7783,6 +8829,7 @@ namespace crow
req_ = std::move(parser_.to_request());
request& req = req_;
+
if (parser_.check_version(1, 0))
{
// HTTP/1.0
@@ -7809,6 +8856,20 @@ namespace crow
is_invalid_request = true;
res = response(400);
}
+ if (parser_.is_upgrade())
+ {
+ if (req.get_header_value("upgrade") == "h2c")
+ {
+ // TODO HTTP/2
+ // currently, ignore upgrade header
+ }
+ else
+ {
+ close_connection_ = true;
+ handler_->handle_upgrade(req, res, std::move(adaptor_));
+ return;
+ }
+ }
}
CROW_LOG_INFO << "Request: " << boost::lexical_cast<std::string>(adaptor_.remote_endpoint()) << " " << this << " HTTP/" << parser_.http_major << "." << parser_.http_minor << ' '
@@ -7823,6 +8884,7 @@ namespace crow
ctx_ = detail::context<Middlewares...>();
req.middleware_context = (void*)&ctx_;
+ req.io_service = &adaptor_.get_io_service();
detail::middleware_call_helper<0, decltype(ctx_), decltype(*middlewares_), Middlewares...>(*middlewares_, req, res, ctx_);
if (!res.completed_)
@@ -7885,6 +8947,7 @@ namespace crow
{401, "HTTP/1.1 401 Unauthorized\r\n"},
{403, "HTTP/1.1 403 Forbidden\r\n"},
{404, "HTTP/1.1 404 Not Found\r\n"},
+ {422, "HTTP/1.1 422 Unprocessable Entity\r\n"},
{500, "HTTP/1.1 500 Internal Server Error\r\n"},
{501, "HTTP/1.1 501 Not Implemented\r\n"},
@@ -7978,7 +9041,7 @@ namespace crow
if (!ec)
{
bool ret = parser_.feed(buffer_.data(), bytes_transferred);
- if (ret && adaptor_.is_open() && !close_connection_)
+ if (ret && adaptor_.is_open())
{
error_while_reading = false;
}
@@ -7993,6 +9056,14 @@ namespace crow
CROW_LOG_DEBUG << this << " from read(1)";
check_destroy();
}
+ else if (close_connection_)
+ {
+ cancel_deadline_timer();
+ parser_.done();
+ is_reading = false;
+ check_destroy();
+ // adaptor will close after write
+ }
else if (!need_to_call_after_handlers_)
{
start_deadline();
@@ -8011,7 +9082,7 @@ namespace crow
//auto self = this->shared_from_this();
is_writing = true;
boost::asio::async_write(adaptor_.socket(), buffers_,
- [&](const boost::system::error_code& ec, std::size_t bytes_transferred)
+ [&](const boost::system::error_code& ec, std::size_t /*bytes_transferred*/)
{
is_writing = false;
res.clear();
@@ -8049,7 +9120,7 @@ namespace crow
timer_queue.cancel(timer_cancel_key_);
}
- void start_deadline(int timeout = 5)
+ void start_deadline(/*int timeout = 5*/)
{
cancel_deadline_timer();
@@ -8105,6 +9176,7 @@ namespace crow
#pragma once
+#include <chrono>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/asio.hpp>
#ifdef CROW_ENABLE_SSL
@@ -8136,6 +9208,7 @@ namespace crow
Server(Handler* handler, std::string bindaddr, uint16_t port, std::tuple<Middlewares...>* middlewares = nullptr, uint16_t concurrency = 1, typename Adaptor::context* adaptor_ctx = nullptr)
: acceptor_(io_service_, tcp::endpoint(boost::asio::ip::address::from_string(bindaddr), port)),
signals_(io_service_, SIGINT, SIGTERM),
+ tick_timer_(io_service_),
handler_(handler),
concurrency_(concurrency),
port_(port),
@@ -8145,6 +9218,24 @@ namespace crow
{
}
+ void set_tick_function(std::chrono::milliseconds d, std::function<void()> f)
+ {
+ tick_interval_ = d;
+ tick_function_ = f;
+ }
+
+ void on_tick()
+ {
+ tick_function_();
+ tick_timer_.expires_from_now(boost::posix_time::milliseconds(tick_interval_.count()));
+ tick_timer_.async_wait([this](const boost::system::error_code& ec)
+ {
+ if (ec)
+ return;
+ on_tick();
+ });
+ }
+
void run()
{
if (concurrency_ < 0)
@@ -8156,9 +9247,10 @@ namespace crow
timer_queue_pool_.resize(concurrency_);
std::vector<std::future<void>> v;
+ std::atomic<int> init_count(0);
for(uint16_t i = 0; i < concurrency_; i ++)
v.push_back(
- std::async(std::launch::async, [this, i]{
+ std::async(std::launch::async, [this, i, &init_count]{
// thread local date string get function
auto last = std::chrono::steady_clock::now();
@@ -8207,20 +9299,36 @@ namespace crow
};
timer.async_wait(handler);
- io_service_pool_[i]->run();
+ init_count ++;
+ try
+ {
+ io_service_pool_[i]->run();
+ } catch(std::exception& e)
+ {
+ CROW_LOG_ERROR << "Worker Crash: An uncaught exception occurred: " << e.what();
+ }
}));
+
+ if (tick_function_ && tick_interval_.count() > 0)
+ {
+ tick_timer_.expires_from_now(boost::posix_time::milliseconds(tick_interval_.count()));
+ tick_timer_.async_wait([this](const boost::system::error_code& ec)
+ {
+ if (ec)
+ return;
+ on_tick();
+ });
+ }
+
CROW_LOG_INFO << server_name_ << " server is running, local port " << port_;
signals_.async_wait(
- [&](const boost::system::error_code& error, int signal_number){
+ [&](const boost::system::error_code& /*error*/, int /*signal_number*/){
stop();
});
- for (int i = 0; i < concurrency_; i++)
- {
- while (timer_queue_pool_[i] == nullptr)
- std::this_thread::yield();
- }
+ while(concurrency_ != init_count)
+ std::this_thread::yield();
do_accept();
@@ -8275,6 +9383,7 @@ namespace crow
std::vector<std::function<std::string()>> get_cached_date_str_pool_;
tcp::acceptor acceptor_;
boost::asio::signal_set signals_;
+ boost::asio::deadline_timer tick_timer_;
Handler* handler_;
uint16_t concurrency_{1};
@@ -8283,6 +9392,9 @@ namespace crow
std::string bindaddr_;
unsigned int roundrobin_index_{};
+ std::chrono::milliseconds tick_interval_;
+ std::function<void()> tick_function_;
+
std::tuple<Middlewares...>* middlewares_;
#ifdef CROW_ENABLE_SSL
@@ -8297,6 +9409,7 @@ namespace crow
#pragma once
+#include <chrono>
#include <string>
#include <functional>
#include <memory>
@@ -8345,6 +9458,12 @@ namespace crow
{
}
+ template <typename Adaptor>
+ void handle_upgrade(const request& req, response& res, Adaptor&& adaptor)
+ {
+ router_.handle_upgrade(req, res, adaptor);
+ }
+
void handle(const request& req, response& res)
{
router_.handle(req, res);
@@ -8398,14 +9517,30 @@ namespace crow
#ifdef CROW_ENABLE_SSL
if (use_ssl_)
{
- ssl_server_t server(this, bindaddr_, port_, &middlewares_, concurrency_, &ssl_context_);
- server.run();
+ ssl_server_ = std::move(std::unique_ptr<ssl_server_t>(new ssl_server_t(this, bindaddr_, port_, &middlewares_, concurrency_, &ssl_context_)));
+ ssl_server_->set_tick_function(tick_interval_, tick_function_);
+ ssl_server_->run();
}
else
#endif
{
- server_t server(this, bindaddr_, port_, &middlewares_, concurrency_, nullptr);
- server.run();
+ server_ = std::move(std::unique_ptr<server_t>(new server_t(this, bindaddr_, port_, &middlewares_, concurrency_, nullptr)));
+ server_->set_tick_function(tick_interval_, tick_function_);
+ server_->run();
+ }
+ }
+
+ void stop()
+ {
+#ifdef CROW_ENABLE_SSL
+ if (use_ssl_)
+ {
+ ssl_server_->stop();
+ }
+ else
+#endif
+ {
+ server_->stop();
}
}
@@ -8456,7 +9591,7 @@ namespace crow
#else
template <typename T, typename ... Remain>
- self_t& ssl_file(T&& t, Remain&&...)
+ self_t& ssl_file(T&&, Remain&&...)
{
// We can't call .ssl() member function unless CROW_ENABLE_SSL is defined.
static_assert(
@@ -8467,7 +9602,7 @@ namespace crow
}
template <typename T>
- self_t& ssl(T&& ctx)
+ self_t& ssl(T&&)
{
// We can't call .ssl() member function unless CROW_ENABLE_SSL is defined.
static_assert(
@@ -8494,17 +9629,34 @@ namespace crow
return utility::get_element_by_type<T, Middlewares...>(middlewares_);
}
+ template <typename Duration, typename Func>
+ self_t& tick(Duration d, Func f) {
+ tick_interval_ = std::chrono::duration_cast<std::chrono::milliseconds>(d);
+ tick_function_ = f;
+ return *this;
+ }
+
private:
uint16_t port_ = 80;
uint16_t concurrency_ = 1;
std::string bindaddr_ = "0.0.0.0";
Router router_;
+ std::chrono::milliseconds tick_interval_;
+ std::function<void()> tick_function_;
+
std::tuple<Middlewares...> middlewares_;
+
+#ifdef CROW_ENABLE_SSL
+ std::unique_ptr<ssl_server_t> ssl_server_;
+#endif
+ std::unique_ptr<server_t> server_;
};
template <typename ... Middlewares>
using App = Crow<Middlewares...>;
using SimpleApp = Crow<>;
-};
+}
+
+#pragma once
diff --git a/amalgamate/merge_all.py b/amalgamate/merge_all.py
index 273ea87..afa0124 100644
--- a/amalgamate/merge_all.py
+++ b/amalgamate/merge_all.py
@@ -11,7 +11,8 @@ if len(sys.argv) > 1:
OUTPUT = 'crow_all.h'
re_depends = re.compile('^#include "(.*)"', re.MULTILINE)
-headers = [x.rsplit('/', 1)[-1] for x in glob(pt.join(header_path, '*.h'))]
+headers = [x.rsplit('/', 1)[-1] for x in glob(pt.join(header_path, '*.h*'))]
+headers += ['crow/' + x.rsplit('/', 1)[-1] for x in glob(pt.join(header_path, 'crow/*.h*'))]
print(headers)
edges = defaultdict(list)
for header in headers:
diff --git a/conanfile.py b/conanfile.py
new file mode 100644
index 0000000..1f7546a
--- /dev/null
+++ b/conanfile.py
@@ -0,0 +1,28 @@
+from conans import ConanFile, CMake
+
+
+class CrowConan(ConanFile):
+ name = "Crow"
+ version = "0.1"
+ url = "https://github.com/ipkn/crow"
+ license = "MIT; see https://github.com/ipkn/crow/blob/master/LICENSE"
+ generators = "cmake"
+ settings = "os", "compiler", "build_type", "arch"
+
+ requires = (("Boost/1.60.0@lasote/stable"),
+ ("OpenSSL/1.0.2i@lasote/stable"))
+
+ # No exports necessary
+
+ def source(self):
+ # this will create a hello subfolder, take it into account
+ self.run("git clone https://github.com/ipkn/crow.git")
+
+ def build(self):
+ cmake = CMake(self.settings)
+ self.run('cmake %s/crow %s' % (self.conanfile_directory, cmake.command_line))
+ self.run("cmake --build . %s" % cmake.build_config)
+ self.run("make")
+
+ def package(self):
+ self.copy("*.h", dst="include", src="amalgamate")
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 22139ad..3c9b0b0 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -11,9 +11,21 @@ add_executable(helloworld helloworld.cpp)
target_link_libraries(helloworld ${Boost_LIBRARIES})
target_link_libraries(helloworld ${CMAKE_THREAD_LIBS_INIT})
+if (OPENSSL_FOUND)
add_executable(example_ssl ssl/example_ssl.cpp)
target_link_libraries(example_ssl ${Boost_LIBRARIES})
-target_link_libraries(example_ssl ${CMAKE_THREAD_LIBS_INIT} ssl crypto)
+target_link_libraries(example_ssl ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES})
+endif()
+
+add_executable(example_websocket websocket/example_ws.cpp)
+target_link_libraries(example_websocket ${Boost_LIBRARIES})
+target_link_libraries(example_websocket ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES})
+add_custom_command(OUTPUT ws.html
+ COMMAND ${CMAKE_COMMAND} -E
+ copy ${PROJECT_SOURCE_DIR}/websocket/templates/ws.html ${CMAKE_CURRENT_BINARY_DIR}/templates/ws.html
+ DEPENDS ${PROJECT_SOURCE_DIR}/websocket/templates/ws.html
+ )
+add_custom_target(example_ws_copy ALL DEPENDS ws.html)
add_executable(example example.cpp)
#target_link_libraries(example crow)
diff --git a/examples/example.cpp b/examples/example.cpp
index dec57cd..87231a2 100644
--- a/examples/example.cpp
+++ b/examples/example.cpp
@@ -1,11 +1,10 @@
#include "crow.h"
-#include "json.h"
#include <sstream>
class ExampleLogHandler : public crow::ILogHandler {
public:
- void log(std::string message, crow::LogLevel level) override {
+ void log(std::string /*message*/, crow::LogLevel /*level*/) override {
// cerr << "ExampleLogHandler -> " << message;
}
};
@@ -28,12 +27,12 @@ struct ExampleMiddleware
{
};
- void before_handle(crow::request& req, crow::response& res, context& ctx)
+ void before_handle(crow::request& /*req*/, crow::response& /*res*/, context& /*ctx*/)
{
CROW_LOG_DEBUG << " - MESSAGE: " << message;
}
- void after_handle(crow::request& req, crow::response& res, context& ctx)
+ void after_handle(crow::request& /*req*/, crow::response& /*res*/, context& /*ctx*/)
{
// no-op
}
@@ -85,7 +84,7 @@ int main()
// To see it in action submit {ip}:18080/add/1/2 and you should receive 3 (exciting, isn't it)
CROW_ROUTE(app,"/add/<int>/<int>")
- ([](const crow::request& req, crow::response& res, int a, int b){
+ ([](const crow::request& /*req*/, crow::response& res, int a, int b){
std::ostringstream os;
os << a+b;
res.write(os.str());
@@ -106,6 +105,9 @@ int main()
// * Select 'raw' and then JSON
// * Add {"a": 1, "b": 1}
// * Send and you should receive 2
+
+ // A simpler way for json example:
+ // * curl -d '{"a":1,"b":2}' {ip}:18080/add_json
CROW_ROUTE(app, "/add_json")
.methods("POST"_method)
([](const crow::request& req){
@@ -144,9 +146,23 @@ int main()
for(const auto& countVal : count) {
os << " - " << countVal << '\n';
}
+
+ // To get a dictionary from the request
+ // You have to submit something like '/params?mydict[a]=b&mydict[abcd]=42' to have a list of pairs ((a, b) and (abcd, 42))
+ auto mydict = req.url_params.get_dict("mydict");
+ os << "The key 'dict' contains " << mydict.size() << " value(s).\n";
+ for(const auto& mydictVal : mydict) {
+ os << " - " << mydictVal.first << " -> " << mydictVal.second << '\n';
+ }
+
return crow::response{os.str()};
});
+ CROW_ROUTE(app, "/large")
+ ([]{
+ return std::string(512*1024, ' ');
+ });
+
// ignore all log
crow::logger::setLogLevel(crow::LogLevel::DEBUG);
//crow::logger::setHandler(std::make_shared<ExampleLogHandler>());
diff --git a/examples/example_chat.cpp b/examples/example_chat.cpp
index ae031b7..d187f51 100644
--- a/examples/example_chat.cpp
+++ b/examples/example_chat.cpp
@@ -1,6 +1,4 @@
#include "crow.h"
-#include "json.h"
-#include "mustache.h"
#include <string>
#include <vector>
#include <chrono>
@@ -50,7 +48,7 @@ int main()
});
CROW_ROUTE(app, "/logs/<int>")
- ([](const crow::request& req, crow::response& res, int after){
+ ([](const crow::request& /*req*/, crow::response& res, int after){
CROW_LOG_INFO << "logs with last " << after;
if (after < (int)msgs.size())
{
diff --git a/examples/example_test.py b/examples/example_test.py
index e2bf651..d252df0 100644
--- a/examples/example_test.py
+++ b/examples/example_test.py
@@ -18,11 +18,27 @@ for i in xrange(10):
Host: localhost\r\n\r\n''');
assert 'Hello World!' in s.recv(1024)
+# test large
+s = socket.socket()
+s.connect(('localhost', 18080))
+s.send('''GET /large HTTP/1.1
+Host: localhost\r\nConnection: close\r\n\r\n''')
+r = ''
+while True:
+ d = s.recv(1024*1024)
+ if not d:
+ break;
+ r += d
+ print len(r), len(d)
+print len(r), r[:100]
+assert len(r) > 512*1024
+
# test timeout
s = socket.socket()
s.connect(('localhost', 18080))
-print 'ERROR REQUEST'
+# invalid request, connection will be closed after timeout
s.send('''GET / HTTP/1.1
hHhHHefhwjkefhklwejfklwejf
''')
print s.recv(1024)
+
diff --git a/examples/example_vs.cpp b/examples/example_vs.cpp
index 95f46b0..dbc4d31 100644
--- a/examples/example_vs.cpp
+++ b/examples/example_vs.cpp
@@ -1,5 +1,4 @@
#include "crow.h"
-#include "json.h"
#include <sstream>
diff --git a/examples/example_with_all.cpp b/examples/example_with_all.cpp
index 55e2715..56ac4cd 100644
--- a/examples/example_with_all.cpp
+++ b/examples/example_with_all.cpp
@@ -4,7 +4,7 @@
class ExampleLogHandler : public crow::ILogHandler {
public:
- void log(std::string message, crow::LogLevel level) override {
+ void log(std::string /*message*/, crow::LogLevel /*level*/) override {
// cerr << "ExampleLogHandler -> " << message;
}
};
@@ -42,7 +42,7 @@ int main()
});
CROW_ROUTE(app,"/add/<int>/<int>")
- ([](const crow::request& req, crow::response& res, int a, int b){
+ ([](const crow::request& /*req*/, crow::response& res, int a, int b){
std::ostringstream os;
os << a+b;
res.write(os.str());
@@ -85,7 +85,7 @@ int main()
});
// ignore all log
- crow::logger::setLogLevel(crow::LogLevel::DEBUG);
+ crow::logger::setLogLevel(crow::LogLevel::Debug);
//crow::logger::setHandler(std::make_shared<ExampleLogHandler>());
app.port(18080)
diff --git a/examples/websocket/example_ws.cpp b/examples/websocket/example_ws.cpp
new file mode 100644
index 0000000..173d062
--- /dev/null
+++ b/examples/websocket/example_ws.cpp
@@ -0,0 +1,48 @@
+#include "crow.h"
+#include <unordered_set>
+#include <mutex>
+
+
+int main()
+{
+ crow::SimpleApp app;
+
+ std::mutex mtx;;
+ std::unordered_set<crow::websocket::connection*> users;
+
+ CROW_ROUTE(app, "/ws")
+ .websocket()
+ .onopen([&](crow::websocket::connection& conn){
+ CROW_LOG_INFO << "new websocket connection";
+ std::lock_guard<std::mutex> _(mtx);
+ users.insert(&conn);
+ })
+ .onclose([&](crow::websocket::connection& conn, const std::string& reason){
+ CROW_LOG_INFO << "websocket connection closed: " << reason;
+ std::lock_guard<std::mutex> _(mtx);
+ users.erase(&conn);
+ })
+ .onmessage([&](crow::websocket::connection& /*conn*/, const std::string& data, bool is_binary){
+ std::lock_guard<std::mutex> _(mtx);
+ for(auto u:users)
+ if (is_binary)
+ u->send_binary(data);
+ else
+ u->send_text(data);
+ });
+
+ CROW_ROUTE(app, "/")
+ ([]{
+ char name[256];
+ gethostname(name, 256);
+ crow::mustache::context x;
+ x["servername"] = name;
+
+ auto page = crow::mustache::load("ws.html");
+ return page.render(x);
+ });
+
+ app.port(40080)
+ .multithreaded()
+ .run();
+}
diff --git a/examples/websocket/templates/ws.html b/examples/websocket/templates/ws.html
new file mode 100644
index 0000000..2d38fdf
--- /dev/null
+++ b/examples/websocket/templates/ws.html
@@ -0,0 +1,42 @@
+<!doctype html>
+<html>
+<head>
+ <script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
+</head>
+<body>
+ <input id="msg" type="text"></input>
+ <button id="send">
+ Send
+ </button><BR>
+ <textarea id="log" cols=100 rows=50>
+ </textarea>
+ <script>
+var sock = new WebSocket("ws://{{servername}}:40080/ws");
+
+sock.onopen = ()=>{
+ console.log('open')
+}
+sock.onerror = (e)=>{
+ console.log('error',e)
+}
+sock.onclose = ()=>{
+ console.log('close')
+}
+sock.onmessage = (e)=>{
+ $("#log").val(
+ e.data +"\n" + $("#log").val());
+}
+$("#msg").keypress(function(e){
+ if (e.which == 13)
+ {
+ sock.send($("#msg").val());
+ $("#msg").val("");
+ }
+});
+$("#send").click(()=>{
+ sock.send($("#msg").val());
+ $("#msg").val("");
+});
+ </script>
+</body>
+</html>
diff --git a/include/crow.h b/include/crow.h
index 31b96cb..9a0c22e 100644
--- a/include/crow.h
+++ b/include/crow.h
@@ -1,204 +1,23 @@
#pragma once
-
-#include <string>
-#include <functional>
-#include <memory>
-#include <future>
-#include <cstdint>
-#include <type_traits>
-#include <thread>
-
-#include "settings.h"
-#include "logging.h"
-#include "utility.h"
-#include "routing.h"
-#include "middleware_context.h"
-#include "http_request.h"
-#include "http_server.h"
-
-
-#ifdef CROW_MSVC_WORKAROUND
-#define CROW_ROUTE(app, url) app.route_dynamic(url)
-#else
-#define CROW_ROUTE(app, url) app.route<crow::black_magic::get_parameter_tag(url)>(url)
-#endif
-
-namespace crow
-{
-#ifdef CROW_ENABLE_SSL
- using ssl_context_t = boost::asio::ssl::context;
-#endif
- template <typename ... Middlewares>
- class Crow
- {
- public:
- using self_t = Crow;
- using server_t = Server<Crow, SocketAdaptor, Middlewares...>;
-#ifdef CROW_ENABLE_SSL
- using ssl_server_t = Server<Crow, SSLAdaptor, Middlewares...>;
-#endif
- Crow()
- {
- }
-
- void handle(const request& req, response& res)
- {
- router_.handle(req, res);
- }
-
- DynamicRule& route_dynamic(std::string&& rule)
- {
- return router_.new_rule_dynamic(std::move(rule));
- }
-
- template <uint64_t Tag>
- auto route(std::string&& rule)
- -> typename std::result_of<decltype(&Router::new_rule_tagged<Tag>)(Router, std::string&&)>::type
- {
- return router_.new_rule_tagged<Tag>(std::move(rule));
- }
-
- self_t& port(std::uint16_t port)
- {
- port_ = port;
- return *this;
- }
-
- self_t& bindaddr(std::string bindaddr)
- {
- bindaddr_ = bindaddr;
- return *this;
- }
-
- self_t& multithreaded()
- {
- return concurrency(std::thread::hardware_concurrency());
- }
-
- self_t& concurrency(std::uint16_t concurrency)
- {
- if (concurrency < 1)
- concurrency = 1;
- concurrency_ = concurrency;
- return *this;
- }
-
- void validate()
- {
- router_.validate();
- }
-
- void run()
- {
- validate();
-#ifdef CROW_ENABLE_SSL
- if (use_ssl_)
- {
- ssl_server_t server(this, bindaddr_, port_, &middlewares_, concurrency_, &ssl_context_);
- server.run();
- }
- else
-#endif
- {
- server_t server(this, bindaddr_, port_, &middlewares_, concurrency_, nullptr);
- server.run();
- }
- }
-
- void debug_print()
- {
- CROW_LOG_DEBUG << "Routing:";
- router_.debug_print();
- }
-
-#ifdef CROW_ENABLE_SSL
- self_t& ssl_file(const std::string& crt_filename, const std::string& key_filename)
- {
- use_ssl_ = true;
- ssl_context_.set_verify_mode(boost::asio::ssl::verify_peer);
- ssl_context_.use_certificate_file(crt_filename, ssl_context_t::pem);
- ssl_context_.use_private_key_file(key_filename, ssl_context_t::pem);
- ssl_context_.set_options(
- boost::asio::ssl::context::default_workarounds
- | boost::asio::ssl::context::no_sslv2
- | boost::asio::ssl::context::no_sslv3
- );
- return *this;
- }
-
- self_t& ssl_file(const std::string& pem_filename)
- {
- use_ssl_ = true;
- ssl_context_.set_verify_mode(boost::asio::ssl::verify_peer);
- ssl_context_.load_verify_file(pem_filename);
- ssl_context_.set_options(
- boost::asio::ssl::context::default_workarounds
- | boost::asio::ssl::context::no_sslv2
- | boost::asio::ssl::context::no_sslv3
- );
- return *this;
- }
-
- self_t& ssl(boost::asio::ssl::context&& ctx)
- {
- use_ssl_ = true;
- ssl_context_ = std::move(ctx);
- return *this;
- }
-
-
- bool use_ssl_{false};
- ssl_context_t ssl_context_{boost::asio::ssl::context::sslv23};
-
-#else
- template <typename T, typename ... Remain>
- self_t& ssl_file(T&& t, Remain&&...)
- {
- // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined.
- static_assert(
- // make static_assert dependent to T; always false
- std::is_base_of<T, void>::value,
- "Define CROW_ENABLE_SSL to enable ssl support.");
- return *this;
- }
-
- template <typename T>
- self_t& ssl(T&& ctx)
- {
- // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined.
- static_assert(
- // make static_assert dependent to T; always false
- std::is_base_of<T, void>::value,
- "Define CROW_ENABLE_SSL to enable ssl support.");
- return *this;
- }
-#endif
-
- // middleware
- using context_t = detail::context<Middlewares...>;
- template <typename T>
- typename T::context& get_context(const request& req)
- {
- static_assert(black_magic::contains<T, Middlewares...>::value, "App doesn't have the specified middleware type.");
- auto& ctx = *reinterpret_cast<context_t*>(req.middleware_context);
- return ctx.template get<T>();
- }
-
- template <typename T>
- T& get_middleware()
- {
- return utility::get_element_by_type<T, Middlewares...>(middlewares_);
- }
-
- private:
- uint16_t port_ = 80;
- uint16_t concurrency_ = 1;
- std::string bindaddr_ = "0.0.0.0";
- Router router_;
-
- std::tuple<Middlewares...> middlewares_;
- };
- template <typename ... Middlewares>
- using App = Crow<Middlewares...>;
- using SimpleApp = Crow<>;
-};
+#include "crow/query_string.h"
+#include "crow/http_parser_merged.h"
+#include "crow/ci_map.h"
+#include "crow/TinySHA1.hpp"
+#include "crow/settings.h"
+#include "crow/socket_adaptors.h"
+#include "crow/json.h"
+#include "crow/mustache.h"
+#include "crow/logging.h"
+#include "crow/dumb_timer_queue.h"
+#include "crow/utility.h"
+#include "crow/common.h"
+#include "crow/http_request.h"
+#include "crow/websocket.h"
+#include "crow/parser.h"
+#include "crow/http_response.h"
+#include "crow/middleware.h"
+#include "crow/routing.h"
+#include "crow/middleware_context.h"
+#include "crow/http_connection.h"
+#include "crow/http_server.h"
+#include "crow/app.h"
diff --git a/include/crow/TinySHA1.hpp b/include/crow/TinySHA1.hpp
new file mode 100644
index 0000000..70af046
--- /dev/null
+++ b/include/crow/TinySHA1.hpp
@@ -0,0 +1,196 @@
+/*
+ *
+ * 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 <mohaps@gmail.com>
+ *
+ * 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 <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <stdint.h>
+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<const uint8_t*>(start);
+ const uint8_t* finish = static_cast<const uint8_t*>(end);
+ while(begin != finish) {
+ processByte(*begin);
+ begin++;
+ }
+ return *this;
+ }
+ SHA1& processBytes(const void* const data, size_t len) {
+ const uint8_t* block = static_cast<const uint8_t*>(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<unsigned char>((bitCount>>24) & 0xFF));
+ processByte( static_cast<unsigned char>((bitCount>>16) & 0xFF));
+ processByte( static_cast<unsigned char>((bitCount>>8 ) & 0xFF));
+ processByte( static_cast<unsigned char>((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
diff --git a/include/crow/app.h b/include/crow/app.h
new file mode 100644
index 0000000..cb72d3a
--- /dev/null
+++ b/include/crow/app.h
@@ -0,0 +1,242 @@
+#pragma once
+
+#include <chrono>
+#include <string>
+#include <functional>
+#include <memory>
+#include <future>
+#include <cstdint>
+#include <type_traits>
+#include <thread>
+
+#include "crow/settings.h"
+#include "crow/logging.h"
+#include "crow/utility.h"
+#include "crow/routing.h"
+#include "crow/middleware_context.h"
+#include "crow/http_request.h"
+#include "crow/http_server.h"
+
+
+#ifdef CROW_MSVC_WORKAROUND
+#define CROW_ROUTE(app, url) app.route_dynamic(url)
+#else
+#define CROW_ROUTE(app, url) app.route<crow::black_magic::get_parameter_tag(url)>(url)
+#endif
+
+namespace crow
+{
+#ifdef CROW_ENABLE_SSL
+ using ssl_context_t = boost::asio::ssl::context;
+#endif
+ template <typename ... Middlewares>
+ class Crow
+ {
+ public:
+ using self_t = Crow;
+ using server_t = Server<Crow, SocketAdaptor, Middlewares...>;
+#ifdef CROW_ENABLE_SSL
+ using ssl_server_t = Server<Crow, SSLAdaptor, Middlewares...>;
+#endif
+ Crow()
+ {
+ }
+
+ template <typename Adaptor>
+ void handle_upgrade(const request& req, response& res, Adaptor&& adaptor)
+ {
+ router_.handle_upgrade(req, res, adaptor);
+ }
+
+ void handle(const request& req, response& res)
+ {
+ router_.handle(req, res);
+ }
+
+ DynamicRule& route_dynamic(std::string&& rule)
+ {
+ return router_.new_rule_dynamic(std::move(rule));
+ }
+
+ template <uint64_t Tag>
+ auto route(std::string&& rule)
+ -> typename std::result_of<decltype(&Router::new_rule_tagged<Tag>)(Router, std::string&&)>::type
+ {
+ return router_.new_rule_tagged<Tag>(std::move(rule));
+ }
+
+ self_t& port(std::uint16_t port)
+ {
+ port_ = port;
+ return *this;
+ }
+
+ self_t& bindaddr(std::string bindaddr)
+ {
+ bindaddr_ = bindaddr;
+ return *this;
+ }
+
+ self_t& multithreaded()
+ {
+ return concurrency(std::thread::hardware_concurrency());
+ }
+
+ self_t& concurrency(std::uint16_t concurrency)
+ {
+ if (concurrency < 1)
+ concurrency = 1;
+ concurrency_ = concurrency;
+ return *this;
+ }
+
+ void validate()
+ {
+ router_.validate();
+ }
+
+ void run()
+ {
+ validate();
+#ifdef CROW_ENABLE_SSL
+ if (use_ssl_)
+ {
+ ssl_server_ = std::move(std::unique_ptr<ssl_server_t>(new ssl_server_t(this, bindaddr_, port_, &middlewares_, concurrency_, &ssl_context_)));
+ ssl_server_->set_tick_function(tick_interval_, tick_function_);
+ ssl_server_->run();
+ }
+ else
+#endif
+ {
+ server_ = std::move(std::unique_ptr<server_t>(new server_t(this, bindaddr_, port_, &middlewares_, concurrency_, nullptr)));
+ server_->set_tick_function(tick_interval_, tick_function_);
+ server_->run();
+ }
+ }
+
+ void stop()
+ {
+#ifdef CROW_ENABLE_SSL
+ if (use_ssl_)
+ {
+ ssl_server_->stop();
+ }
+ else
+#endif
+ {
+ server_->stop();
+ }
+ }
+
+ void debug_print()
+ {
+ CROW_LOG_DEBUG << "Routing:";
+ router_.debug_print();
+ }
+
+#ifdef CROW_ENABLE_SSL
+ self_t& ssl_file(const std::string& crt_filename, const std::string& key_filename)
+ {
+ use_ssl_ = true;
+ ssl_context_.set_verify_mode(boost::asio::ssl::verify_peer);
+ ssl_context_.use_certificate_file(crt_filename, ssl_context_t::pem);
+ ssl_context_.use_private_key_file(key_filename, ssl_context_t::pem);
+ ssl_context_.set_options(
+ boost::asio::ssl::context::default_workarounds
+ | boost::asio::ssl::context::no_sslv2
+ | boost::asio::ssl::context::no_sslv3
+ );
+ return *this;
+ }
+
+ self_t& ssl_file(const std::string& pem_filename)
+ {
+ use_ssl_ = true;
+ ssl_context_.set_verify_mode(boost::asio::ssl::verify_peer);
+ ssl_context_.load_verify_file(pem_filename);
+ ssl_context_.set_options(
+ boost::asio::ssl::context::default_workarounds
+ | boost::asio::ssl::context::no_sslv2
+ | boost::asio::ssl::context::no_sslv3
+ );
+ return *this;
+ }
+
+ self_t& ssl(boost::asio::ssl::context&& ctx)
+ {
+ use_ssl_ = true;
+ ssl_context_ = std::move(ctx);
+ return *this;
+ }
+
+
+ bool use_ssl_{false};
+ ssl_context_t ssl_context_{boost::asio::ssl::context::sslv23};
+
+#else
+ template <typename T, typename ... Remain>
+ self_t& ssl_file(T&&, Remain&&...)
+ {
+ // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined.
+ static_assert(
+ // make static_assert dependent to T; always false
+ std::is_base_of<T, void>::value,
+ "Define CROW_ENABLE_SSL to enable ssl support.");
+ return *this;
+ }
+
+ template <typename T>
+ self_t& ssl(T&&)
+ {
+ // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined.
+ static_assert(
+ // make static_assert dependent to T; always false
+ std::is_base_of<T, void>::value,
+ "Define CROW_ENABLE_SSL to enable ssl support.");
+ return *this;
+ }
+#endif
+
+ // middleware
+ using context_t = detail::context<Middlewares...>;
+ template <typename T>
+ typename T::context& get_context(const request& req)
+ {
+ static_assert(black_magic::contains<T, Middlewares...>::value, "App doesn't have the specified middleware type.");
+ auto& ctx = *reinterpret_cast<context_t*>(req.middleware_context);
+ return ctx.template get<T>();
+ }
+
+ template <typename T>
+ T& get_middleware()
+ {
+ return utility::get_element_by_type<T, Middlewares...>(middlewares_);
+ }
+
+ template <typename Duration, typename Func>
+ self_t& tick(Duration d, Func f) {
+ tick_interval_ = std::chrono::duration_cast<std::chrono::milliseconds>(d);
+ tick_function_ = f;
+ return *this;
+ }
+
+ private:
+ uint16_t port_ = 80;
+ uint16_t concurrency_ = 1;
+ std::string bindaddr_ = "0.0.0.0";
+ Router router_;
+
+ std::chrono::milliseconds tick_interval_;
+ std::function<void()> tick_function_;
+
+ std::tuple<Middlewares...> middlewares_;
+
+#ifdef CROW_ENABLE_SSL
+ std::unique_ptr<ssl_server_t> ssl_server_;
+#endif
+ std::unique_ptr<server_t> server_;
+ };
+ template <typename ... Middlewares>
+ using App = Crow<Middlewares...>;
+ using SimpleApp = Crow<>;
+}
diff --git a/include/ci_map.h b/include/crow/ci_map.h
index 155d54f..155d54f 100644
--- a/include/ci_map.h
+++ b/include/crow/ci_map.h
diff --git a/include/common.h b/include/crow/common.h
index 8808d6a..84d1361 100644
--- a/include/common.h
+++ b/include/crow/common.h
@@ -4,13 +4,14 @@
#include <string>
#include <stdexcept>
#include <iostream>
-#include "utility.h"
+#include "crow/utility.h"
namespace crow
{
enum class HTTPMethod
{
- DELETE,
+#ifndef DELETE
+ DELETE = 0,
GET,
HEAD,
POST,
@@ -18,27 +19,37 @@ namespace crow
CONNECT,
OPTIONS,
TRACE,
+#endif
+
+ Delete = 0,
+ Get,
+ Head,
+ Post,
+ Put,
+ Connect,
+ Options,
+ Trace,
};
inline std::string method_name(HTTPMethod method)
{
switch(method)
{
- case HTTPMethod::DELETE:
+ case HTTPMethod::Delete:
return "DELETE";
- case HTTPMethod::GET:
+ case HTTPMethod::Get:
return "GET";
- case HTTPMethod::HEAD:
+ case HTTPMethod::Head:
return "HEAD";
- case HTTPMethod::POST:
+ case HTTPMethod::Post:
return "POST";
- case HTTPMethod::PUT:
+ case HTTPMethod::Put:
return "PUT";
- case HTTPMethod::CONNECT:
+ case HTTPMethod::Connect:
return "CONNECT";
- case HTTPMethod::OPTIONS:
+ case HTTPMethod::Options:
return "OPTIONS";
- case HTTPMethod::TRACE:
+ case HTTPMethod::Trace:
return "TRACE";
}
return "invalid";
@@ -110,17 +121,17 @@ namespace crow
}
#ifndef CROW_MSVC_WORKAROUND
-constexpr crow::HTTPMethod operator "" _method(const char* str, size_t len)
+constexpr crow::HTTPMethod operator "" _method(const char* str, size_t /*len*/)
{
return
- crow::black_magic::is_equ_p(str, "GET", 3) ? crow::HTTPMethod::GET :
- crow::black_magic::is_equ_p(str, "DELETE", 6) ? crow::HTTPMethod::DELETE :
- crow::black_magic::is_equ_p(str, "HEAD", 4) ? crow::HTTPMethod::HEAD :
- crow::black_magic::is_equ_p(str, "POST", 4) ? crow::HTTPMethod::POST :
- crow::black_magic::is_equ_p(str, "PUT", 3) ? crow::HTTPMethod::PUT :
- crow::black_magic::is_equ_p(str, "OPTIONS", 7) ? crow::HTTPMethod::OPTIONS :
- crow::black_magic::is_equ_p(str, "CONNECT", 7) ? crow::HTTPMethod::CONNECT :
- crow::black_magic::is_equ_p(str, "TRACE", 5) ? crow::HTTPMethod::TRACE :
+ crow::black_magic::is_equ_p(str, "GET", 3) ? crow::HTTPMethod::Get :
+ crow::black_magic::is_equ_p(str, "DELETE", 6) ? crow::HTTPMethod::Delete :
+ crow::black_magic::is_equ_p(str, "HEAD", 4) ? crow::HTTPMethod::Head :
+ crow::black_magic::is_equ_p(str, "POST", 4) ? crow::HTTPMethod::Post :
+ crow::black_magic::is_equ_p(str, "PUT", 3) ? crow::HTTPMethod::Put :
+ crow::black_magic::is_equ_p(str, "OPTIONS", 7) ? crow::HTTPMethod::Options :
+ crow::black_magic::is_equ_p(str, "CONNECT", 7) ? crow::HTTPMethod::Connect :
+ crow::black_magic::is_equ_p(str, "TRACE", 5) ? crow::HTTPMethod::Trace :
throw std::runtime_error("invalid http method");
-};
+}
#endif
diff --git a/include/dumb_timer_queue.h b/include/crow/dumb_timer_queue.h
index 6b690bb..fd51518 100644
--- a/include/dumb_timer_queue.h
+++ b/include/crow/dumb_timer_queue.h
@@ -6,7 +6,7 @@
#include <chrono>
#include <thread>
-#include "logging.h"
+#include "crow/logging.h"
namespace crow
{
diff --git a/include/http_connection.h b/include/crow/http_connection.h
index 69b87b0..1537d17 100644
--- a/include/http_connection.h
+++ b/include/crow/http_connection.h
@@ -7,15 +7,15 @@
#include <chrono>
#include <vector>
-#include "http_parser_merged.h"
+#include "crow/http_parser_merged.h"
-#include "parser.h"
-#include "http_response.h"
-#include "logging.h"
-#include "settings.h"
-#include "dumb_timer_queue.h"
-#include "middleware_context.h"
-#include "socket_adaptors.h"
+#include "crow/parser.h"
+#include "crow/http_response.h"
+#include "crow/logging.h"
+#include "crow/settings.h"
+#include "crow/dumb_timer_queue.h"
+#include "crow/middleware_context.h"
+#include "crow/socket_adaptors.h"
namespace crow
{
@@ -98,28 +98,28 @@ namespace crow
template <typename MW, typename Context, typename ParentContext>
typename std::enable_if<!is_before_handle_arity_3_impl<MW>::value>::type
- before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& parent_ctx)
+ before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
{
mw.before_handle(req, res, ctx.template get<MW>(), ctx);
}
template <typename MW, typename Context, typename ParentContext>
typename std::enable_if<is_before_handle_arity_3_impl<MW>::value>::type
- before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& parent_ctx)
+ before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
{
mw.before_handle(req, res, ctx.template get<MW>());
}
template <typename MW, typename Context, typename ParentContext>
typename std::enable_if<!is_after_handle_arity_3_impl<MW>::value>::type
- after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& parent_ctx)
+ after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
{
mw.after_handle(req, res, ctx.template get<MW>(), ctx);
}
template <typename MW, typename Context, typename ParentContext>
typename std::enable_if<is_after_handle_arity_3_impl<MW>::value>::type
- after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& parent_ctx)
+ after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
{
mw.after_handle(req, res, ctx.template get<MW>());
}
@@ -146,14 +146,14 @@ namespace crow
}
template <int N, typename Context, typename Container>
- bool middleware_call_helper(Container& middlewares, request& req, response& res, Context& ctx)
+ bool middleware_call_helper(Container& /*middlewares*/, request& /*req*/, response& /*res*/, Context& /*ctx*/)
{
return false;
}
template <int N, typename Context, typename Container>
typename std::enable_if<(N<0)>::type
- after_handlers_call_helper(Container& middlewares, Context& context, request& req, response& res)
+ after_handlers_call_helper(Container& /*middlewares*/, Context& /*context*/, request& /*req*/, response& /*res*/)
{
}
@@ -176,7 +176,7 @@ namespace crow
}
#ifdef CROW_ENABLE_DEBUG
- static int connectionCount;
+ static std::atomic<int> connectionCount;
#endif
template <typename Adaptor, typename Handler, typename ... Middlewares>
class Connection
@@ -256,6 +256,7 @@ namespace crow
req_ = std::move(parser_.to_request());
request& req = req_;
+
if (parser_.check_version(1, 0))
{
// HTTP/1.0
@@ -282,6 +283,20 @@ namespace crow
is_invalid_request = true;
res = response(400);
}
+ if (parser_.is_upgrade())
+ {
+ if (req.get_header_value("upgrade") == "h2c")
+ {
+ // TODO HTTP/2
+ // currently, ignore upgrade header
+ }
+ else
+ {
+ close_connection_ = true;
+ handler_->handle_upgrade(req, res, std::move(adaptor_));
+ return;
+ }
+ }
}
CROW_LOG_INFO << "Request: " << boost::lexical_cast<std::string>(adaptor_.remote_endpoint()) << " " << this << " HTTP/" << parser_.http_major << "." << parser_.http_minor << ' '
@@ -296,6 +311,7 @@ namespace crow
ctx_ = detail::context<Middlewares...>();
req.middleware_context = (void*)&ctx_;
+ req.io_service = &adaptor_.get_io_service();
detail::middleware_call_helper<0, decltype(ctx_), decltype(*middlewares_), Middlewares...>(*middlewares_, req, res, ctx_);
if (!res.completed_)
@@ -358,6 +374,7 @@ namespace crow
{401, "HTTP/1.1 401 Unauthorized\r\n"},
{403, "HTTP/1.1 403 Forbidden\r\n"},
{404, "HTTP/1.1 404 Not Found\r\n"},
+ {422, "HTTP/1.1 422 Unprocessable Entity\r\n"},
{500, "HTTP/1.1 500 Internal Server Error\r\n"},
{501, "HTTP/1.1 501 Not Implemented\r\n"},
@@ -451,7 +468,7 @@ namespace crow
if (!ec)
{
bool ret = parser_.feed(buffer_.data(), bytes_transferred);
- if (ret && adaptor_.is_open() && !close_connection_)
+ if (ret && adaptor_.is_open())
{
error_while_reading = false;
}
@@ -466,6 +483,14 @@ namespace crow
CROW_LOG_DEBUG << this << " from read(1)";
check_destroy();
}
+ else if (close_connection_)
+ {
+ cancel_deadline_timer();
+ parser_.done();
+ is_reading = false;
+ check_destroy();
+ // adaptor will close after write
+ }
else if (!need_to_call_after_handlers_)
{
start_deadline();
@@ -484,7 +509,7 @@ namespace crow
//auto self = this->shared_from_this();
is_writing = true;
boost::asio::async_write(adaptor_.socket(), buffers_,
- [&](const boost::system::error_code& ec, std::size_t bytes_transferred)
+ [&](const boost::system::error_code& ec, std::size_t /*bytes_transferred*/)
{
is_writing = false;
res.clear();
@@ -522,7 +547,7 @@ namespace crow
timer_queue.cancel(timer_cancel_key_);
}
- void start_deadline(int timeout = 5)
+ void start_deadline(/*int timeout = 5*/)
{
cancel_deadline_timer();
diff --git a/include/http_parser_merged.h b/include/crow/http_parser_merged.h
index e058517..2a10252 100644
--- a/include/http_parser_merged.h
+++ b/include/crow/http_parser_merged.h
@@ -19,16 +19,16 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
-#ifndef http_parser_h
-#define http_parser_h
+#ifndef CROW_http_parser_h
+#define CROW_http_parser_h
#ifdef __cplusplus
extern "C" {
#endif
/* Also update SONAME in the Makefile whenever you change these. */
-#define HTTP_PARSER_VERSION_MAJOR 2
-#define HTTP_PARSER_VERSION_MINOR 3
-#define HTTP_PARSER_VERSION_PATCH 0
+#define CROW_HTTP_PARSER_VERSION_MAJOR 2
+#define CROW_HTTP_PARSER_VERSION_MINOR 3
+#define CROW_HTTP_PARSER_VERSION_PATCH 0
#include <sys/types.h>
#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600)
@@ -49,8 +49,8 @@ typedef unsigned __int64 uint64_t;
/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
* faster
*/
-#ifndef HTTP_PARSER_STRICT
-# define HTTP_PARSER_STRICT 1
+#ifndef CROW_HTTP_PARSER_STRICT
+# define CROW_HTTP_PARSER_STRICT 1
#endif
/* Maximium header size allowed. If the macro is not defined
@@ -60,8 +60,8 @@ typedef unsigned __int64 uint64_t;
* the effective limit on the size of the header, define the macro
* to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff)
*/
-#ifndef HTTP_MAX_HEADER_SIZE
-# define HTTP_MAX_HEADER_SIZE (80*1024)
+#ifndef CROW_HTTP_MAX_HEADER_SIZE
+# define CROW_HTTP_MAX_HEADER_SIZE (80*1024)
#endif
typedef struct http_parser http_parser;
@@ -86,46 +86,46 @@ typedef int (*http_cb) (http_parser*);
/* Request Methods */
-#define HTTP_METHOD_MAP(XX) \
- XX(0, DELETE, DELETE) \
- XX(1, GET, GET) \
- XX(2, HEAD, HEAD) \
- XX(3, POST, POST) \
- XX(4, PUT, PUT) \
+#define CROW_HTTP_METHOD_MAP(CROW_XX) \
+ CROW_XX(0, DELETE, DELETE) \
+ CROW_XX(1, GET, GET) \
+ CROW_XX(2, HEAD, HEAD) \
+ CROW_XX(3, POST, POST) \
+ CROW_XX(4, PUT, PUT) \
/* pathological */ \
- XX(5, CONNECT, CONNECT) \
- XX(6, OPTIONS, OPTIONS) \
- XX(7, TRACE, TRACE) \
+ CROW_XX(5, CONNECT, CONNECT) \
+ CROW_XX(6, OPTIONS, OPTIONS) \
+ CROW_XX(7, TRACE, TRACE) \
/* webdav */ \
- XX(8, COPY, COPY) \
- XX(9, LOCK, LOCK) \
- XX(10, MKCOL, MKCOL) \
- XX(11, MOVE, MOVE) \
- XX(12, PROPFIND, PROPFIND) \
- XX(13, PROPPATCH, PROPPATCH) \
- XX(14, SEARCH, SEARCH) \
- XX(15, UNLOCK, UNLOCK) \
+ CROW_XX(8, COPY, COPY) \
+ CROW_XX(9, LOCK, LOCK) \
+ CROW_XX(10, MKCOL, MKCOL) \
+ CROW_XX(11, MOVE, MOVE) \
+ CROW_XX(12, PROPFIND, PROPFIND) \
+ CROW_XX(13, PROPPATCH, PROPPATCH) \
+ CROW_XX(14, SEARCH, SEARCH) \
+ CROW_XX(15, UNLOCK, UNLOCK) \
/* subversion */ \
- XX(16, REPORT, REPORT) \
- XX(17, MKACTIVITY, MKACTIVITY) \
- XX(18, CHECKOUT, CHECKOUT) \
- XX(19, MERGE, MERGE) \
+ CROW_XX(16, REPORT, REPORT) \
+ CROW_XX(17, MKACTIVITY, MKACTIVITY) \
+ CROW_XX(18, CHECKOUT, CHECKOUT) \
+ CROW_XX(19, MERGE, MERGE) \
/* upnp */ \
- XX(20, MSEARCH, M-SEARCH) \
- XX(21, NOTIFY, NOTIFY) \
- XX(22, SUBSCRIBE, SUBSCRIBE) \
- XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \
+ CROW_XX(20, MSEARCH, M-SEARCH) \
+ CROW_XX(21, NOTIFY, NOTIFY) \
+ CROW_XX(22, SUBSCRIBE, SUBSCRIBE) \
+ CROW_XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \
/* RFC-5789 */ \
- XX(24, PATCH, PATCH) \
- XX(25, PURGE, PURGE) \
+ CROW_XX(24, PATCH, PATCH) \
+ CROW_XX(25, PURGE, PURGE) \
/* CalDAV */ \
- XX(26, MKCALENDAR, MKCALENDAR) \
+ CROW_XX(26, MKCALENDAR, MKCALENDAR) \
enum http_method
{
-#define XX(num, name, string) HTTP_##name = num,
- HTTP_METHOD_MAP(XX)
-#undef XX
+#define CROW_XX(num, name, string) HTTP_##name = num,
+ CROW_HTTP_METHOD_MAP(CROW_XX)
+#undef CROW_XX
};
@@ -147,58 +147,58 @@ enum flags
*
* The provided argument should be a macro that takes 2 arguments.
*/
-#define HTTP_ERRNO_MAP(XX) \
+#define CROW_HTTP_ERRNO_MAP(CROW_XX) \
/* No error */ \
- XX(OK, "success") \
+ CROW_XX(OK, "success") \
\
/* Callback-related errors */ \
- XX(CB_message_begin, "the on_message_begin callback failed") \
- XX(CB_url, "the on_url callback failed") \
- XX(CB_header_field, "the on_header_field callback failed") \
- XX(CB_header_value, "the on_header_value callback failed") \
- XX(CB_headers_complete, "the on_headers_complete callback failed") \
- XX(CB_body, "the on_body callback failed") \
- XX(CB_message_complete, "the on_message_complete callback failed") \
- XX(CB_status, "the on_status callback failed") \
+ CROW_XX(CB_message_begin, "the on_message_begin callback failed") \
+ CROW_XX(CB_url, "the on_url callback failed") \
+ CROW_XX(CB_header_field, "the on_header_field callback failed") \
+ CROW_XX(CB_header_value, "the on_header_value callback failed") \
+ CROW_XX(CB_headers_complete, "the on_headers_complete callback failed") \
+ CROW_XX(CB_body, "the on_body callback failed") \
+ CROW_XX(CB_message_complete, "the on_message_complete callback failed") \
+ CROW_XX(CB_status, "the on_status callback failed") \
\
/* Parsing-related errors */ \
- XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
- XX(HEADER_OVERFLOW, \
+ CROW_XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
+ CROW_XX(HEADER_OVERFLOW, \
"too many header bytes seen; overflow detected") \
- XX(CLOSED_CONNECTION, \
+ CROW_XX(CLOSED_CONNECTION, \
"data received after completed connection: close message") \
- XX(INVALID_VERSION, "invalid HTTP version") \
- XX(INVALID_STATUS, "invalid HTTP status code") \
- XX(INVALID_METHOD, "invalid HTTP method") \
- XX(INVALID_URL, "invalid URL") \
- XX(INVALID_HOST, "invalid host") \
- XX(INVALID_PORT, "invalid port") \
- XX(INVALID_PATH, "invalid path") \
- XX(INVALID_QUERY_STRING, "invalid query string") \
- XX(INVALID_FRAGMENT, "invalid fragment") \
- XX(LF_EXPECTED, "LF character expected") \
- XX(INVALID_HEADER_TOKEN, "invalid character in header") \
- XX(INVALID_CONTENT_LENGTH, \
+ CROW_XX(INVALID_VERSION, "invalid HTTP version") \
+ CROW_XX(INVALID_STATUS, "invalid HTTP status code") \
+ CROW_XX(INVALID_METHOD, "invalid HTTP method") \
+ CROW_XX(INVALID_URL, "invalid URL") \
+ CROW_XX(INVALID_HOST, "invalid host") \
+ CROW_XX(INVALID_PORT, "invalid port") \
+ CROW_XX(INVALID_PATH, "invalid path") \
+ CROW_XX(INVALID_QUERY_STRING, "invalid query string") \
+ CROW_XX(INVALID_FRAGMENT, "invalid fragment") \
+ CROW_XX(LF_EXPECTED, "CROW_LF character expected") \
+ CROW_XX(INVALID_HEADER_TOKEN, "invalid character in header") \
+ CROW_XX(INVALID_CONTENT_LENGTH, \
"invalid character in content-length header") \
- XX(INVALID_CHUNK_SIZE, \
+ CROW_XX(INVALID_CHUNK_SIZE, \
"invalid character in chunk size header") \
- XX(INVALID_CONSTANT, "invalid constant string") \
- XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
- XX(STRICT, "strict mode assertion failed") \
- XX(PAUSED, "parser is paused") \
- XX(UNKNOWN, "an unknown error occurred")
+ CROW_XX(INVALID_CONSTANT, "invalid constant string") \
+ CROW_XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
+ CROW_XX(STRICT, "strict mode assertion failed") \
+ CROW_XX(PAUSED, "parser is paused") \
+ CROW_XX(UNKNOWN, "an unknown error occurred")
/* Define HPE_* values for each errno value above */
-#define HTTP_ERRNO_GEN(n, s) HPE_##n,
+#define CROW_HTTP_ERRNO_GEN(n, s) HPE_##n,
enum http_errno {
- HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
+ CROW_HTTP_ERRNO_MAP(CROW_HTTP_ERRNO_GEN)
};
-#undef HTTP_ERRNO_GEN
+#undef CROW_HTTP_ERRNO_GEN
/* Get an http_errno value from an http_parser */
-#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno)
+#define CROW_HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno)
struct http_parser {
@@ -353,70 +353,70 @@ int http_body_is_final(const http_parser *parser);
#include <string.h>
#include <limits.h>
-#ifndef ULLONG_MAX
-# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */
+#ifndef CROW_ULLONG_MAX
+# define CROW_ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */
#endif
-#ifndef MIN
-# define MIN(a,b) ((a) < (b) ? (a) : (b))
+#ifndef CROW_MIN
+# define CROW_MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
-#ifndef ARRAY_SIZE
-# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#ifndef CROW_ARRAY_SIZE
+# define CROW_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#endif
-#ifndef BIT_AT
-# define BIT_AT(a, i) \
+#ifndef CROW_BIT_AT
+# define CROW_BIT_AT(a, i) \
(!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \
(1 << ((unsigned int) (i) & 7))))
#endif
-#ifndef ELEM_AT
-# define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v))
+#ifndef CROW_ELEM_AT
+# define CROW_ELEM_AT(a, i, v) ((unsigned int) (i) < CROW_ARRAY_SIZE(a) ? (a)[(i)] : (v))
#endif
-#define SET_ERRNO(e) \
+#define CROW_SET_ERRNO(e) \
do { \
parser->http_errno = (e); \
} while(0)
/* Run the notify callback FOR, returning ER if it fails */
-#define CALLBACK_NOTIFY_(FOR, ER) \
+#define CROW_CALLBACK_NOTIFY_(FOR, ER) \
do { \
- assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \
+ assert(CROW_HTTP_PARSER_ERRNO(parser) == HPE_OK); \
\
if (settings->on_##FOR) { \
if (0 != settings->on_##FOR(parser)) { \
- SET_ERRNO(HPE_CB_##FOR); \
+ CROW_SET_ERRNO(HPE_CB_##FOR); \
} \
\
/* We either errored above or got paused; get out */ \
- if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \
+ if (CROW_HTTP_PARSER_ERRNO(parser) != HPE_OK) { \
return (ER); \
} \
} \
} while (0)
/* Run the notify callback FOR and consume the current byte */
-#define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1)
+#define CROW_CALLBACK_NOTIFY(FOR) CROW_CALLBACK_NOTIFY_(FOR, p - data + 1)
/* Run the notify callback FOR and don't consume the current byte */
-#define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data)
+#define CROW_CALLBACK_NOTIFY_NOADVANCE(FOR) CROW_CALLBACK_NOTIFY_(FOR, p - data)
/* Run data callback FOR with LEN bytes, returning ER if it fails */
-#define CALLBACK_DATA_(FOR, LEN, ER) \
+#define CROW_CALLBACK_DATA_(FOR, LEN, ER) \
do { \
- assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \
+ assert(CROW_HTTP_PARSER_ERRNO(parser) == HPE_OK); \
\
if (FOR##_mark) { \
if (settings->on_##FOR) { \
if (0 != settings->on_##FOR(parser, FOR##_mark, (LEN))) { \
- SET_ERRNO(HPE_CB_##FOR); \
+ CROW_SET_ERRNO(HPE_CB_##FOR); \
} \
\
/* We either errored above or got paused; get out */ \
- if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \
+ if (CROW_HTTP_PARSER_ERRNO(parser) != HPE_OK) { \
return (ER); \
} \
} \
@@ -425,15 +425,15 @@ do { \
} while (0)
/* Run the data callback FOR and consume the current byte */
-#define CALLBACK_DATA(FOR) \
- CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1)
+#define CROW_CALLBACK_DATA(FOR) \
+ CROW_CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1)
/* Run the data callback FOR and don't consume the current byte */
-#define CALLBACK_DATA_NOADVANCE(FOR) \
- CALLBACK_DATA_(FOR, p - FOR##_mark, p - data)
+#define CROW_CALLBACK_DATA_NOADVANCE(FOR) \
+ CROW_CALLBACK_DATA_(FOR, p - FOR##_mark, p - data)
/* Set the mark FOR; non-destructive if mark is already set */
-#define MARK(FOR) \
+#define CROW_MARK(FOR) \
do { \
if (!FOR##_mark) { \
FOR##_mark = p; \
@@ -441,14 +441,14 @@ do { \
} while (0)
-#define PROXY_CONNECTION "proxy-connection"
-#define CONNECTION "connection"
-#define CONTENT_LENGTH "content-length"
-#define TRANSFER_ENCODING "transfer-encoding"
-#define UPGRADE "upgrade"
-#define CHUNKED "chunked"
-#define KEEP_ALIVE "keep-alive"
-#define CLOSE "close"
+#define CROW_PROXY_CONNECTION "proxy-connection"
+#define CROW_CONNECTION "connection"
+#define CROW_CONTENT_LENGTH "content-length"
+#define CROW_TRANSFER_ENCODING "transfer-encoding"
+#define CROW_UPGRADE "upgrade"
+#define CROW_CHUNKED "chunked"
+#define CROW_KEEP_ALIVE "keep-alive"
+#define CROW_CLOSE "close"
@@ -520,7 +520,7 @@ enum state
/* Important: 's_headers_done' must be the last 'header' state. All
* states beyond this must be 'body' states. It is used for overflow
- * checking. See the PARSING_HEADER() macro.
+ * checking. See the CROW_PARSING_HEADER() macro.
*/
, s_chunk_data
@@ -534,7 +534,7 @@ enum state
};
-#define PARSING_HEADER(state) (state <= s_headers_done)
+#define CROW_PARSING_HEADER(state) (state <= s_headers_done)
enum header_states
@@ -578,48 +578,48 @@ enum http_host_state
};
/* Macros for character classes; depends on strict-mode */
-#define CR '\r'
-#define LF '\n'
-#define LOWER(c) (unsigned char)(c | 0x20)
-#define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z')
-#define IS_NUM(c) ((c) >= '0' && (c) <= '9')
-#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))
-#define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f'))
-#define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \
+#define CROW_CR '\r'
+#define CROW_LF '\n'
+#define CROW_LOWER(c) (unsigned char)(c | 0x20)
+#define CROW_IS_ALPHA(c) (CROW_LOWER(c) >= 'a' && CROW_LOWER(c) <= 'z')
+#define CROW_IS_NUM(c) ((c) >= '0' && (c) <= '9')
+#define CROW_IS_ALPHANUM(c) (CROW_IS_ALPHA(c) || CROW_IS_NUM(c))
+#define CROW_IS_HEX(c) (CROW_IS_NUM(c) || (CROW_LOWER(c) >= 'a' && CROW_LOWER(c) <= 'f'))
+#define CROW_IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \
(c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \
(c) == ')')
-#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \
+#define CROW_IS_USERINFO_CHAR(c) (CROW_IS_ALPHANUM(c) || CROW_IS_MARK(c) || (c) == '%' || \
(c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \
(c) == '$' || (c) == ',')
-#if HTTP_PARSER_STRICT
-#define TOKEN(c) (tokens[(unsigned char)c])
-#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c))
-#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
+#if CROW_HTTP_PARSER_STRICT
+#define CROW_TOKEN(c) (tokens[(unsigned char)c])
+#define CROW_IS_URL_CHAR(c) (CROW_BIT_AT(normal_url_char, (unsigned char)c))
+#define CROW_IS_HOST_CHAR(c) (CROW_IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
#else
-#define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c])
-#define IS_URL_CHAR(c) \
- (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80))
-#define IS_HOST_CHAR(c) \
- (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
+#define CROW_TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c])
+#define CROW_IS_URL_CHAR(c) \
+ (CROW_BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80))
+#define CROW_IS_HOST_CHAR(c) \
+ (CROW_IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
#endif
-#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res)
+#define CROW_start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res)
-#if HTTP_PARSER_STRICT
-# define STRICT_CHECK(cond) \
+#if CROW_HTTP_PARSER_STRICT
+# define CROW_STRICT_CHECK(cond) \
do { \
if (cond) { \
- SET_ERRNO(HPE_STRICT); \
+ CROW_SET_ERRNO(HPE_STRICT); \
goto error; \
} \
} while (0)
-# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead)
+# define CROW_NEW_MESSAGE() (http_should_keep_alive(parser) ? CROW_start_state : s_dead)
#else
-# define STRICT_CHECK(cond)
-# define NEW_MESSAGE() start_state
+# define CROW_STRICT_CHECK(cond)
+# define CROW_NEW_MESSAGE() CROW_start_state
#endif
@@ -640,10 +640,10 @@ int http_message_needs_eof(const http_parser *parser);
inline enum state
parse_url_char(enum state s, const char ch)
{
-#if HTTP_PARSER_STRICT
-# define T(v) 0
+#if CROW_HTTP_PARSER_STRICT
+# define CROW_T(v) 0
#else
-# define T(v) v
+# define CROW_T(v) v
#endif
@@ -651,7 +651,7 @@ static const uint8_t normal_url_char[32] = {
/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
- 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0,
+ 0 | CROW_T(2) | 0 | 0 | CROW_T(16) | 0 | 0 | 0,
/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
@@ -668,7 +668,7 @@ static const uint8_t normal_url_char[32] = {
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
-/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
+/* 80 P 81 Q 82 R 83 S 84 CROW_T 85 U 86 V 87 W */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
@@ -681,13 +681,13 @@ static const uint8_t normal_url_char[32] = {
/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, };
-#undef T
+#undef CROW_T
if (ch == ' ' || ch == '\r' || ch == '\n') {
return s_dead;
}
-#if HTTP_PARSER_STRICT
+#if CROW_HTTP_PARSER_STRICT
if (ch == '\t' || ch == '\f') {
return s_dead;
}
@@ -703,14 +703,14 @@ static const uint8_t normal_url_char[32] = {
return s_req_path;
}
- if (IS_ALPHA(ch)) {
+ if (CROW_IS_ALPHA(ch)) {
return s_req_schema;
}
break;
case s_req_schema:
- if (IS_ALPHA(ch)) {
+ if (CROW_IS_ALPHA(ch)) {
return s;
}
@@ -754,14 +754,14 @@ static const uint8_t normal_url_char[32] = {
return s_req_server_with_at;
}
- if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') {
+ if (CROW_IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') {
return s_req_server;
}
break;
case s_req_path:
- if (IS_URL_CHAR(ch)) {
+ if (CROW_IS_URL_CHAR(ch)) {
return s;
}
@@ -777,7 +777,7 @@ static const uint8_t normal_url_char[32] = {
case s_req_query_string_start:
case s_req_query_string:
- if (IS_URL_CHAR(ch)) {
+ if (CROW_IS_URL_CHAR(ch)) {
return s_req_query_string;
}
@@ -793,7 +793,7 @@ static const uint8_t normal_url_char[32] = {
break;
case s_req_fragment_start:
- if (IS_URL_CHAR(ch)) {
+ if (CROW_IS_URL_CHAR(ch)) {
return s_req_fragment;
}
@@ -808,7 +808,7 @@ static const uint8_t normal_url_char[32] = {
break;
case s_req_fragment:
- if (IS_URL_CHAR(ch)) {
+ if (CROW_IS_URL_CHAR(ch)) {
return s;
}
@@ -835,9 +835,9 @@ inline size_t http_parser_execute (http_parser *parser,
{
static const char *method_strings[] =
{
-#define XX(num, name, string) #string,
- HTTP_METHOD_MAP(XX)
-#undef XX
+#define CROW_XX(num, name, string) #string,
+ CROW_HTTP_METHOD_MAP(CROW_XX)
+#undef CROW_XX
};
/* Tokens as defined by rfc 2616. Also lowercases them.
@@ -905,17 +905,17 @@ static const int8_t unhex[256] =
const char *status_mark = 0;
/* We're in an error state. Don't bother doing anything. */
- if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
+ if (CROW_HTTP_PARSER_ERRNO(parser) != HPE_OK) {
return 0;
}
if (len == 0) {
switch (parser->state) {
case s_body_identity_eof:
- /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if
+ /* Use of CROW_CALLBACK_NOTIFY() here would erroneously return 1 byte read if
* we got paused.
*/
- CALLBACK_NOTIFY_NOADVANCE(message_complete);
+ CROW_CALLBACK_NOTIFY_NOADVANCE(message_complete);
return 0;
case s_dead:
@@ -925,7 +925,7 @@ static const int8_t unhex[256] =
return 0;
default:
- SET_ERRNO(HPE_INVALID_EOF_STATE);
+ CROW_SET_ERRNO(HPE_INVALID_EOF_STATE);
return 1;
}
}
@@ -957,21 +957,21 @@ static const int8_t unhex[256] =
for (p=data; p != data + len; p++) {
ch = *p;
- if (PARSING_HEADER(parser->state)) {
+ if (CROW_PARSING_HEADER(parser->state)) {
++parser->nread;
/* Don't allow the total size of the HTTP headers (including the status
- * line) to exceed HTTP_MAX_HEADER_SIZE. This check is here to protect
+ * line) to exceed CROW_HTTP_MAX_HEADER_SIZE. This check is here to protect
* embedders against denial-of-service attacks where the attacker feeds
* us a never-ending header that the embedder keeps buffering.
*
* This check is arguably the responsibility of embedders but we're doing
* it on the embedder's behalf because most won't bother and this way we
- * make the web a little safer. HTTP_MAX_HEADER_SIZE is still far bigger
+ * make the web a little safer. CROW_HTTP_MAX_HEADER_SIZE is still far bigger
* than any reasonable request or response so this should never affect
* day-to-day operation.
*/
- if (parser->nread > (HTTP_MAX_HEADER_SIZE)) {
- SET_ERRNO(HPE_HEADER_OVERFLOW);
+ if (parser->nread > (CROW_HTTP_MAX_HEADER_SIZE)) {
+ CROW_SET_ERRNO(HPE_HEADER_OVERFLOW);
goto error;
}
}
@@ -983,23 +983,23 @@ static const int8_t unhex[256] =
/* this state is used after a 'Connection: close' message
* the parser will error out if it reads another message
*/
- if (ch == CR || ch == LF)
+ if (ch == CROW_CR || ch == CROW_LF)
break;
- SET_ERRNO(HPE_CLOSED_CONNECTION);
+ CROW_SET_ERRNO(HPE_CLOSED_CONNECTION);
goto error;
case s_start_req_or_res:
{
- if (ch == CR || ch == LF)
+ if (ch == CROW_CR || ch == CROW_LF)
break;
parser->flags = 0;
- parser->content_length = ULLONG_MAX;
+ parser->content_length = CROW_ULLONG_MAX;
if (ch == 'H') {
parser->state = s_res_or_resp_H;
- CALLBACK_NOTIFY(message_begin);
+ CROW_CALLBACK_NOTIFY(message_begin);
} else {
parser->type = HTTP_REQUEST;
parser->state = s_start_req;
@@ -1015,7 +1015,7 @@ static const int8_t unhex[256] =
parser->state = s_res_HT;
} else {
if (ch != 'E') {
- SET_ERRNO(HPE_INVALID_CONSTANT);
+ CROW_SET_ERRNO(HPE_INVALID_CONSTANT);
goto error;
}
@@ -1029,49 +1029,49 @@ static const int8_t unhex[256] =
case s_start_res:
{
parser->flags = 0;
- parser->content_length = ULLONG_MAX;
+ parser->content_length = CROW_ULLONG_MAX;
switch (ch) {
case 'H':
parser->state = s_res_H;
break;
- case CR:
- case LF:
+ case CROW_CR:
+ case CROW_LF:
break;
default:
- SET_ERRNO(HPE_INVALID_CONSTANT);
+ CROW_SET_ERRNO(HPE_INVALID_CONSTANT);
goto error;
}
- CALLBACK_NOTIFY(message_begin);
+ CROW_CALLBACK_NOTIFY(message_begin);
break;
}
case s_res_H:
- STRICT_CHECK(ch != 'T');
+ CROW_STRICT_CHECK(ch != 'T');
parser->state = s_res_HT;
break;
case s_res_HT:
- STRICT_CHECK(ch != 'T');
+ CROW_STRICT_CHECK(ch != 'T');
parser->state = s_res_HTT;
break;
case s_res_HTT:
- STRICT_CHECK(ch != 'P');
+ CROW_STRICT_CHECK(ch != 'P');
parser->state = s_res_HTTP;
break;
case s_res_HTTP:
- STRICT_CHECK(ch != '/');
+ CROW_STRICT_CHECK(ch != '/');
parser->state = s_res_first_http_major;
break;
case s_res_first_http_major:
if (ch < '0' || ch > '9') {
- SET_ERRNO(HPE_INVALID_VERSION);
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -1087,8 +1087,8 @@ static const int8_t unhex[256] =
break;
}
- if (!IS_NUM(ch)) {
- SET_ERRNO(HPE_INVALID_VERSION);
+ if (!CROW_IS_NUM(ch)) {
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -1096,7 +1096,7 @@ static const int8_t unhex[256] =
parser->http_major += ch - '0';
if (parser->http_major > 999) {
- SET_ERRNO(HPE_INVALID_VERSION);
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -1105,8 +1105,8 @@ static const int8_t unhex[256] =
/* first digit of minor HTTP version */
case s_res_first_http_minor:
- if (!IS_NUM(ch)) {
- SET_ERRNO(HPE_INVALID_VERSION);
+ if (!CROW_IS_NUM(ch)) {
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -1122,8 +1122,8 @@ static const int8_t unhex[256] =
break;
}
- if (!IS_NUM(ch)) {
- SET_ERRNO(HPE_INVALID_VERSION);
+ if (!CROW_IS_NUM(ch)) {
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -1131,7 +1131,7 @@ static const int8_t unhex[256] =
parser->http_minor += ch - '0';
if (parser->http_minor > 999) {
- SET_ERRNO(HPE_INVALID_VERSION);
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -1140,12 +1140,12 @@ static const int8_t unhex[256] =
case s_res_first_status_code:
{
- if (!IS_NUM(ch)) {
+ if (!CROW_IS_NUM(ch)) {
if (ch == ' ') {
break;
}
- SET_ERRNO(HPE_INVALID_STATUS);
+ CROW_SET_ERRNO(HPE_INVALID_STATUS);
goto error;
}
parser->status_code = ch - '0';
@@ -1155,19 +1155,19 @@ static const int8_t unhex[256] =
case s_res_status_code:
{
- if (!IS_NUM(ch)) {
+ if (!CROW_IS_NUM(ch)) {
switch (ch) {
case ' ':
parser->state = s_res_status_start;
break;
- case CR:
+ case CROW_CR:
parser->state = s_res_line_almost_done;
break;
- case LF:
+ case CROW_LF:
parser->state = s_header_field_start;
break;
default:
- SET_ERRNO(HPE_INVALID_STATUS);
+ CROW_SET_ERRNO(HPE_INVALID_STATUS);
goto error;
}
break;
@@ -1177,7 +1177,7 @@ static const int8_t unhex[256] =
parser->status_code += ch - '0';
if (parser->status_code > 999) {
- SET_ERRNO(HPE_INVALID_STATUS);
+ CROW_SET_ERRNO(HPE_INVALID_STATUS);
goto error;
}
@@ -1186,51 +1186,51 @@ static const int8_t unhex[256] =
case s_res_status_start:
{
- if (ch == CR) {
+ if (ch == CROW_CR) {
parser->state = s_res_line_almost_done;
break;
}
- if (ch == LF) {
+ if (ch == CROW_LF) {
parser->state = s_header_field_start;
break;
}
- MARK(status);
+ CROW_MARK(status);
parser->state = s_res_status;
parser->index = 0;
break;
}
case s_res_status:
- if (ch == CR) {
+ if (ch == CROW_CR) {
parser->state = s_res_line_almost_done;
- CALLBACK_DATA(status);
+ CROW_CALLBACK_DATA(status);
break;
}
- if (ch == LF) {
+ if (ch == CROW_LF) {
parser->state = s_header_field_start;
- CALLBACK_DATA(status);
+ CROW_CALLBACK_DATA(status);
break;
}
break;
case s_res_line_almost_done:
- STRICT_CHECK(ch != LF);
+ CROW_STRICT_CHECK(ch != CROW_LF);
parser->state = s_header_field_start;
break;
case s_start_req:
{
- if (ch == CR || ch == LF)
+ if (ch == CROW_CR || ch == CROW_LF)
break;
parser->flags = 0;
- parser->content_length = ULLONG_MAX;
+ parser->content_length = CROW_ULLONG_MAX;
- if (!IS_ALPHA(ch)) {
- SET_ERRNO(HPE_INVALID_METHOD);
+ if (!CROW_IS_ALPHA(ch)) {
+ CROW_SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
@@ -1253,12 +1253,12 @@ static const int8_t unhex[256] =
case 'T': parser->method = HTTP_TRACE; break;
case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break;
default:
- SET_ERRNO(HPE_INVALID_METHOD);
+ CROW_SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
parser->state = s_req_method;
- CALLBACK_NOTIFY(message_begin);
+ CROW_CALLBACK_NOTIFY(message_begin);
break;
}
@@ -1267,7 +1267,7 @@ static const int8_t unhex[256] =
{
const char *matcher;
if (ch == '\0') {
- SET_ERRNO(HPE_INVALID_METHOD);
+ CROW_SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
@@ -1282,7 +1282,7 @@ static const int8_t unhex[256] =
} else if (parser->index == 2 && ch == 'P') {
parser->method = HTTP_COPY;
} else {
- SET_ERRNO(HPE_INVALID_METHOD);
+ CROW_SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
} else if (parser->method == HTTP_MKCOL) {
@@ -1297,14 +1297,14 @@ static const int8_t unhex[256] =
} else if (parser->index == 3 && ch == 'A') {
parser->method = HTTP_MKCALENDAR;
} else {
- SET_ERRNO(HPE_INVALID_METHOD);
+ CROW_SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
} else if (parser->method == HTTP_SUBSCRIBE) {
if (parser->index == 1 && ch == 'E') {
parser->method = HTTP_SEARCH;
} else {
- SET_ERRNO(HPE_INVALID_METHOD);
+ CROW_SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
} else if (parser->index == 1 && parser->method == HTTP_POST) {
@@ -1315,7 +1315,7 @@ static const int8_t unhex[256] =
} else if (ch == 'A') {
parser->method = HTTP_PATCH;
} else {
- SET_ERRNO(HPE_INVALID_METHOD);
+ CROW_SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
} else if (parser->index == 2) {
@@ -1323,24 +1323,24 @@ static const int8_t unhex[256] =
if (ch == 'R') {
parser->method = HTTP_PURGE;
} else {
- SET_ERRNO(HPE_INVALID_METHOD);
+ CROW_SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
} else if (parser->method == HTTP_UNLOCK) {
if (ch == 'S') {
parser->method = HTTP_UNSUBSCRIBE;
} else {
- SET_ERRNO(HPE_INVALID_METHOD);
+ CROW_SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
} else {
- SET_ERRNO(HPE_INVALID_METHOD);
+ CROW_SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
} else if (parser->index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') {
parser->method = HTTP_PROPPATCH;
} else {
- SET_ERRNO(HPE_INVALID_METHOD);
+ CROW_SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
@@ -1352,14 +1352,14 @@ static const int8_t unhex[256] =
{
if (ch == ' ') break;
- MARK(url);
+ CROW_MARK(url);
if (parser->method == HTTP_CONNECT) {
parser->state = s_req_server_start;
}
parser->state = parse_url_char((enum state)parser->state, ch);
if (parser->state == s_dead) {
- SET_ERRNO(HPE_INVALID_URL);
+ CROW_SET_ERRNO(HPE_INVALID_URL);
goto error;
}
@@ -1374,14 +1374,14 @@ static const int8_t unhex[256] =
switch (ch) {
/* No whitespace allowed here */
case ' ':
- case CR:
- case LF:
- SET_ERRNO(HPE_INVALID_URL);
+ case CROW_CR:
+ case CROW_LF:
+ CROW_SET_ERRNO(HPE_INVALID_URL);
goto error;
default:
parser->state = parse_url_char((enum state)parser->state, ch);
if (parser->state == s_dead) {
- SET_ERRNO(HPE_INVALID_URL);
+ CROW_SET_ERRNO(HPE_INVALID_URL);
goto error;
}
}
@@ -1400,21 +1400,21 @@ static const int8_t unhex[256] =
switch (ch) {
case ' ':
parser->state = s_req_http_start;
- CALLBACK_DATA(url);
+ CROW_CALLBACK_DATA(url);
break;
- case CR:
- case LF:
+ case CROW_CR:
+ case CROW_LF:
parser->http_major = 0;
parser->http_minor = 9;
- parser->state = (ch == CR) ?
+ parser->state = (ch == CROW_CR) ?
s_req_line_almost_done :
s_header_field_start;
- CALLBACK_DATA(url);
+ CROW_CALLBACK_DATA(url);
break;
default:
parser->state = parse_url_char((enum state)parser->state, ch);
if (parser->state == s_dead) {
- SET_ERRNO(HPE_INVALID_URL);
+ CROW_SET_ERRNO(HPE_INVALID_URL);
goto error;
}
}
@@ -1429,35 +1429,35 @@ static const int8_t unhex[256] =
case ' ':
break;
default:
- SET_ERRNO(HPE_INVALID_CONSTANT);
+ CROW_SET_ERRNO(HPE_INVALID_CONSTANT);
goto error;
}
break;
case s_req_http_H:
- STRICT_CHECK(ch != 'T');
+ CROW_STRICT_CHECK(ch != 'T');
parser->state = s_req_http_HT;
break;
case s_req_http_HT:
- STRICT_CHECK(ch != 'T');
+ CROW_STRICT_CHECK(ch != 'T');
parser->state = s_req_http_HTT;
break;
case s_req_http_HTT:
- STRICT_CHECK(ch != 'P');
+ CROW_STRICT_CHECK(ch != 'P');
parser->state = s_req_http_HTTP;
break;
case s_req_http_HTTP:
- STRICT_CHECK(ch != '/');
+ CROW_STRICT_CHECK(ch != '/');
parser->state = s_req_first_http_major;
break;
/* first digit of major HTTP version */
case s_req_first_http_major:
if (ch < '1' || ch > '9') {
- SET_ERRNO(HPE_INVALID_VERSION);
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -1473,8 +1473,8 @@ static const int8_t unhex[256] =
break;
}
- if (!IS_NUM(ch)) {
- SET_ERRNO(HPE_INVALID_VERSION);
+ if (!CROW_IS_NUM(ch)) {
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -1482,7 +1482,7 @@ static const int8_t unhex[256] =
parser->http_major += ch - '0';
if (parser->http_major > 999) {
- SET_ERRNO(HPE_INVALID_VERSION);
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -1491,8 +1491,8 @@ static const int8_t unhex[256] =
/* first digit of minor HTTP version */
case s_req_first_http_minor:
- if (!IS_NUM(ch)) {
- SET_ERRNO(HPE_INVALID_VERSION);
+ if (!CROW_IS_NUM(ch)) {
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -1503,20 +1503,20 @@ static const int8_t unhex[256] =
/* minor HTTP version or end of request line */
case s_req_http_minor:
{
- if (ch == CR) {
+ if (ch == CROW_CR) {
parser->state = s_req_line_almost_done;
break;
}
- if (ch == LF) {
+ if (ch == CROW_LF) {
parser->state = s_header_field_start;
break;
}
/* XXX allow spaces after digit? */
- if (!IS_NUM(ch)) {
- SET_ERRNO(HPE_INVALID_VERSION);
+ if (!CROW_IS_NUM(ch)) {
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -1524,7 +1524,7 @@ static const int8_t unhex[256] =
parser->http_minor += ch - '0';
if (parser->http_minor > 999) {
- SET_ERRNO(HPE_INVALID_VERSION);
+ CROW_SET_ERRNO(HPE_INVALID_VERSION);
goto error;
}
@@ -1534,8 +1534,8 @@ static const int8_t unhex[256] =
/* end of request line */
case s_req_line_almost_done:
{
- if (ch != LF) {
- SET_ERRNO(HPE_LF_EXPECTED);
+ if (ch != CROW_LF) {
+ CROW_SET_ERRNO(HPE_LF_EXPECTED);
goto error;
}
@@ -1545,26 +1545,26 @@ static const int8_t unhex[256] =
case s_header_field_start:
{
- if (ch == CR) {
+ if (ch == CROW_CR) {
parser->state = s_headers_almost_done;
break;
}
- if (ch == LF) {
+ if (ch == CROW_LF) {
/* they might be just sending \n instead of \r\n so this would be
* the second \n to denote the end of headers*/
parser->state = s_headers_almost_done;
goto reexecute_byte;
}
- c = TOKEN(ch);
+ c = CROW_TOKEN(ch);
if (!c) {
- SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
+ CROW_SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
goto error;
}
- MARK(header_field);
+ CROW_MARK(header_field);
parser->index = 0;
parser->state = s_header_field;
@@ -1595,7 +1595,7 @@ static const int8_t unhex[256] =
case s_header_field:
{
- c = TOKEN(ch);
+ c = CROW_TOKEN(ch);
if (c) {
switch (parser->header_state) {
@@ -1631,10 +1631,10 @@ static const int8_t unhex[256] =
case h_matching_connection:
parser->index++;
- if (parser->index > sizeof(CONNECTION)-1
- || c != CONNECTION[parser->index]) {
+ if (parser->index > sizeof(CROW_CONNECTION)-1
+ || c != CROW_CONNECTION[parser->index]) {
parser->header_state = h_general;
- } else if (parser->index == sizeof(CONNECTION)-2) {
+ } else if (parser->index == sizeof(CROW_CONNECTION)-2) {
parser->header_state = h_connection;
}
break;
@@ -1643,10 +1643,10 @@ static const int8_t unhex[256] =
case h_matching_proxy_connection:
parser->index++;
- if (parser->index > sizeof(PROXY_CONNECTION)-1
- || c != PROXY_CONNECTION[parser->index]) {
+ if (parser->index > sizeof(CROW_PROXY_CONNECTION)-1
+ || c != CROW_PROXY_CONNECTION[parser->index]) {
parser->header_state = h_general;
- } else if (parser->index == sizeof(PROXY_CONNECTION)-2) {
+ } else if (parser->index == sizeof(CROW_PROXY_CONNECTION)-2) {
parser->header_state = h_connection;
}
break;
@@ -1655,10 +1655,10 @@ static const int8_t unhex[256] =
case h_matching_content_length:
parser->index++;
- if (parser->index > sizeof(CONTENT_LENGTH)-1
- || c != CONTENT_LENGTH[parser->index]) {
+ if (parser->index > sizeof(CROW_CONTENT_LENGTH)-1
+ || c != CROW_CONTENT_LENGTH[parser->index]) {
parser->header_state = h_general;
- } else if (parser->index == sizeof(CONTENT_LENGTH)-2) {
+ } else if (parser->index == sizeof(CROW_CONTENT_LENGTH)-2) {
parser->header_state = h_content_length;
}
break;
@@ -1667,10 +1667,10 @@ static const int8_t unhex[256] =
case h_matching_transfer_encoding:
parser->index++;
- if (parser->index > sizeof(TRANSFER_ENCODING)-1
- || c != TRANSFER_ENCODING[parser->index]) {
+ if (parser->index > sizeof(CROW_TRANSFER_ENCODING)-1
+ || c != CROW_TRANSFER_ENCODING[parser->index]) {
parser->header_state = h_general;
- } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) {
+ } else if (parser->index == sizeof(CROW_TRANSFER_ENCODING)-2) {
parser->header_state = h_transfer_encoding;
}
break;
@@ -1679,10 +1679,10 @@ static const int8_t unhex[256] =
case h_matching_upgrade:
parser->index++;
- if (parser->index > sizeof(UPGRADE)-1
- || c != UPGRADE[parser->index]) {
+ if (parser->index > sizeof(CROW_UPGRADE)-1
+ || c != CROW_UPGRADE[parser->index]) {
parser->header_state = h_general;
- } else if (parser->index == sizeof(UPGRADE)-2) {
+ } else if (parser->index == sizeof(CROW_UPGRADE)-2) {
parser->header_state = h_upgrade;
}
break;
@@ -1703,35 +1703,35 @@ static const int8_t unhex[256] =
if (ch == ':') {
parser->state = s_header_value_discard_ws;
- CALLBACK_DATA(header_field);
+ CROW_CALLBACK_DATA(header_field);
break;
}
- if (ch == CR) {
+ if (ch == CROW_CR) {
parser->state = s_header_almost_done;
- CALLBACK_DATA(header_field);
+ CROW_CALLBACK_DATA(header_field);
break;
}
- if (ch == LF) {
+ if (ch == CROW_LF) {
parser->state = s_header_field_start;
- CALLBACK_DATA(header_field);
+ CROW_CALLBACK_DATA(header_field);
break;
}
- SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
+ CROW_SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
goto error;
}
case s_header_value_discard_ws:
if (ch == ' ' || ch == '\t') break;
- if (ch == CR) {
+ if (ch == CROW_CR) {
parser->state = s_header_value_discard_ws_almost_done;
break;
}
- if (ch == LF) {
+ if (ch == CROW_LF) {
parser->state = s_header_value_discard_lws;
break;
}
@@ -1740,12 +1740,12 @@ static const int8_t unhex[256] =
case s_header_value_start:
{
- MARK(header_value);
+ CROW_MARK(header_value);
parser->state = s_header_value;
parser->index = 0;
- c = LOWER(ch);
+ c = CROW_LOWER(ch);
switch (parser->header_state) {
case h_upgrade:
@@ -1763,8 +1763,8 @@ static const int8_t unhex[256] =
break;
case h_content_length:
- if (!IS_NUM(ch)) {
- SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
+ if (!CROW_IS_NUM(ch)) {
+ CROW_SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
goto error;
}
@@ -1793,19 +1793,19 @@ static const int8_t unhex[256] =
case s_header_value:
{
- if (ch == CR) {
+ if (ch == CROW_CR) {
parser->state = s_header_almost_done;
- CALLBACK_DATA(header_value);
+ CROW_CALLBACK_DATA(header_value);
break;
}
- if (ch == LF) {
+ if (ch == CROW_LF) {
parser->state = s_header_almost_done;
- CALLBACK_DATA_NOADVANCE(header_value);
+ CROW_CALLBACK_DATA_NOADVANCE(header_value);
goto reexecute_byte;
}
- c = LOWER(ch);
+ c = CROW_LOWER(ch);
switch (parser->header_state) {
case h_general:
@@ -1822,8 +1822,8 @@ static const int8_t unhex[256] =
if (ch == ' ') break;
- if (!IS_NUM(ch)) {
- SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
+ if (!CROW_IS_NUM(ch)) {
+ CROW_SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
goto error;
}
@@ -1832,8 +1832,8 @@ static const int8_t unhex[256] =
t += ch - '0';
/* Overflow? Test against a conservative limit for simplicity. */
- if ((ULLONG_MAX - 10) / 10 < parser->content_length) {
- SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
+ if ((CROW_ULLONG_MAX - 10) / 10 < parser->content_length) {
+ CROW_SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
goto error;
}
@@ -1844,10 +1844,10 @@ static const int8_t unhex[256] =
/* Transfer-Encoding: chunked */
case h_matching_transfer_encoding_chunked:
parser->index++;
- if (parser->index > sizeof(CHUNKED)-1
- || c != CHUNKED[parser->index]) {
+ if (parser->index > sizeof(CROW_CHUNKED)-1
+ || c != CROW_CHUNKED[parser->index]) {
parser->header_state = h_general;
- } else if (parser->index == sizeof(CHUNKED)-2) {
+ } else if (parser->index == sizeof(CROW_CHUNKED)-2) {
parser->header_state = h_transfer_encoding_chunked;
}
break;
@@ -1855,10 +1855,10 @@ static const int8_t unhex[256] =
/* looking for 'Connection: keep-alive' */
case h_matching_connection_keep_alive:
parser->index++;
- if (parser->index > sizeof(KEEP_ALIVE)-1
- || c != KEEP_ALIVE[parser->index]) {
+ if (parser->index > sizeof(CROW_KEEP_ALIVE)-1
+ || c != CROW_KEEP_ALIVE[parser->index]) {
parser->header_state = h_general;
- } else if (parser->index == sizeof(KEEP_ALIVE)-2) {
+ } else if (parser->index == sizeof(CROW_KEEP_ALIVE)-2) {
parser->header_state = h_connection_keep_alive;
}
break;
@@ -1866,9 +1866,9 @@ static const int8_t unhex[256] =
/* looking for 'Connection: close' */
case h_matching_connection_close:
parser->index++;
- if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) {
+ if (parser->index > sizeof(CROW_CLOSE)-1 || c != CROW_CLOSE[parser->index]) {
parser->header_state = h_general;
- } else if (parser->index == sizeof(CLOSE)-2) {
+ } else if (parser->index == sizeof(CROW_CLOSE)-2) {
parser->header_state = h_connection_close;
}
break;
@@ -1889,7 +1889,7 @@ static const int8_t unhex[256] =
case s_header_almost_done:
{
- STRICT_CHECK(ch != LF);
+ CROW_STRICT_CHECK(ch != CROW_LF);
parser->state = s_header_value_lws;
break;
@@ -1923,7 +1923,7 @@ static const int8_t unhex[256] =
case s_header_value_discard_ws_almost_done:
{
- STRICT_CHECK(ch != LF);
+ CROW_STRICT_CHECK(ch != CROW_LF);
parser->state = s_header_value_discard_lws;
break;
}
@@ -1935,21 +1935,21 @@ static const int8_t unhex[256] =
break;
} else {
/* header value was empty */
- MARK(header_value);
+ CROW_MARK(header_value);
parser->state = s_header_field_start;
- CALLBACK_DATA_NOADVANCE(header_value);
+ CROW_CALLBACK_DATA_NOADVANCE(header_value);
goto reexecute_byte;
}
}
case s_headers_almost_done:
{
- STRICT_CHECK(ch != LF);
+ CROW_STRICT_CHECK(ch != CROW_LF);
if (parser->flags & F_TRAILING) {
/* End of a chunked request */
- parser->state = NEW_MESSAGE();
- CALLBACK_NOTIFY(message_complete);
+ parser->state = CROW_NEW_MESSAGE();
+ CROW_CALLBACK_NOTIFY(message_complete);
break;
}
@@ -1965,7 +1965,7 @@ static const int8_t unhex[256] =
* is needed for the annoying case of recieving a response to a HEAD
* request.
*
- * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so
+ * We'd like to use CROW_CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so
* we have to simulate it by handling a change in errno below.
*/
if (settings->on_headers_complete) {
@@ -1978,12 +1978,12 @@ static const int8_t unhex[256] =
break;
default:
- SET_ERRNO(HPE_CB_headers_complete);
+ CROW_SET_ERRNO(HPE_CB_headers_complete);
return p - data; /* Error */
}
}
- if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
+ if (CROW_HTTP_PARSER_ERRNO(parser) != HPE_OK) {
return p - data;
}
@@ -1992,37 +1992,37 @@ static const int8_t unhex[256] =
case s_headers_done:
{
- STRICT_CHECK(ch != LF);
+ CROW_STRICT_CHECK(ch != CROW_LF);
parser->nread = 0;
/* Exit, the rest of the connect is in a different protocol. */
if (parser->upgrade) {
- parser->state = NEW_MESSAGE();
- CALLBACK_NOTIFY(message_complete);
+ parser->state = CROW_NEW_MESSAGE();
+ CROW_CALLBACK_NOTIFY(message_complete);
return (p - data) + 1;
}
if (parser->flags & F_SKIPBODY) {
- parser->state = NEW_MESSAGE();
- CALLBACK_NOTIFY(message_complete);
+ parser->state = CROW_NEW_MESSAGE();
+ CROW_CALLBACK_NOTIFY(message_complete);
} else if (parser->flags & F_CHUNKED) {
/* chunked encoding - ignore Content-Length header */
parser->state = s_chunk_size_start;
} else {
if (parser->content_length == 0) {
/* Content-Length header given but zero: Content-Length: 0\r\n */
- parser->state = NEW_MESSAGE();
- CALLBACK_NOTIFY(message_complete);
- } else if (parser->content_length != ULLONG_MAX) {
+ parser->state = CROW_NEW_MESSAGE();
+ CROW_CALLBACK_NOTIFY(message_complete);
+ } else if (parser->content_length != CROW_ULLONG_MAX) {
/* Content-Length header given and non-zero */
parser->state = s_body_identity;
} else {
if (parser->type == HTTP_REQUEST ||
!http_message_needs_eof(parser)) {
/* Assume content-length 0 - read the next */
- parser->state = NEW_MESSAGE();
- CALLBACK_NOTIFY(message_complete);
+ parser->state = CROW_NEW_MESSAGE();
+ CROW_CALLBACK_NOTIFY(message_complete);
} else {
/* Read body until EOF */
parser->state = s_body_identity_eof;
@@ -2035,25 +2035,25 @@ static const int8_t unhex[256] =
case s_body_identity:
{
- uint64_t to_read = MIN(parser->content_length,
+ uint64_t to_read = CROW_MIN(parser->content_length,
(uint64_t) ((data + len) - p));
assert(parser->content_length != 0
- && parser->content_length != ULLONG_MAX);
+ && parser->content_length != CROW_ULLONG_MAX);
/* The difference between advancing content_length and p is because
* the latter will automaticaly advance on the next loop iteration.
* Further, if content_length ends up at 0, we want to see the last
* byte again for our message complete callback.
*/
- MARK(body);
+ CROW_MARK(body);
parser->content_length -= to_read;
p += to_read - 1;
if (parser->content_length == 0) {
parser->state = s_message_done;
- /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte.
+ /* Mimic CROW_CALLBACK_DATA_NOADVANCE() but with one extra byte.
*
* The alternative to doing this is to wait for the next byte to
* trigger the data callback, just as in every other case. The
@@ -2062,7 +2062,7 @@ static const int8_t unhex[256] =
* complete-on-length. It's not clear that this distinction is
* important for applications, but let's keep it for now.
*/
- CALLBACK_DATA_(body, p - body_mark + 1, p - data);
+ CROW_CALLBACK_DATA_(body, p - body_mark + 1, p - data);
goto reexecute_byte;
}
@@ -2071,14 +2071,14 @@ static const int8_t unhex[256] =
/* read until EOF */
case s_body_identity_eof:
- MARK(body);
+ CROW_MARK(body);
p = data + len - 1;
break;
case s_message_done:
- parser->state = NEW_MESSAGE();
- CALLBACK_NOTIFY(message_complete);
+ parser->state = CROW_NEW_MESSAGE();
+ CROW_CALLBACK_NOTIFY(message_complete);
break;
case s_chunk_size_start:
@@ -2088,7 +2088,7 @@ static const int8_t unhex[256] =
unhex_val = unhex[(unsigned char)ch];
if (unhex_val == -1) {
- SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
+ CROW_SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
goto error;
}
@@ -2103,7 +2103,7 @@ static const int8_t unhex[256] =
assert(parser->flags & F_CHUNKED);
- if (ch == CR) {
+ if (ch == CROW_CR) {
parser->state = s_chunk_size_almost_done;
break;
}
@@ -2116,7 +2116,7 @@ static const int8_t unhex[256] =
break;
}
- SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
+ CROW_SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
goto error;
}
@@ -2125,8 +2125,8 @@ static const int8_t unhex[256] =
t += unhex_val;
/* Overflow? Test against a conservative limit for simplicity. */
- if ((ULLONG_MAX - 16) / 16 < parser->content_length) {
- SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
+ if ((CROW_ULLONG_MAX - 16) / 16 < parser->content_length) {
+ CROW_SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
goto error;
}
@@ -2138,7 +2138,7 @@ static const int8_t unhex[256] =
{
assert(parser->flags & F_CHUNKED);
/* just ignore this shit. TODO check for overflow */
- if (ch == CR) {
+ if (ch == CROW_CR) {
parser->state = s_chunk_size_almost_done;
break;
}
@@ -2148,7 +2148,7 @@ static const int8_t unhex[256] =
case s_chunk_size_almost_done:
{
assert(parser->flags & F_CHUNKED);
- STRICT_CHECK(ch != LF);
+ CROW_STRICT_CHECK(ch != CROW_LF);
parser->nread = 0;
@@ -2163,17 +2163,17 @@ static const int8_t unhex[256] =
case s_chunk_data:
{
- uint64_t to_read = MIN(parser->content_length,
+ uint64_t to_read = CROW_MIN(parser->content_length,
(uint64_t) ((data + len) - p));
assert(parser->flags & F_CHUNKED);
assert(parser->content_length != 0
- && parser->content_length != ULLONG_MAX);
+ && parser->content_length != CROW_ULLONG_MAX);
/* See the explanation in s_body_identity for why the content
* length and data pointers are managed this way.
*/
- MARK(body);
+ CROW_MARK(body);
parser->content_length -= to_read;
p += to_read - 1;
@@ -2187,21 +2187,21 @@ static const int8_t unhex[256] =
case s_chunk_data_almost_done:
assert(parser->flags & F_CHUNKED);
assert(parser->content_length == 0);
- STRICT_CHECK(ch != CR);
+ CROW_STRICT_CHECK(ch != CROW_CR);
parser->state = s_chunk_data_done;
- CALLBACK_DATA(body);
+ CROW_CALLBACK_DATA(body);
break;
case s_chunk_data_done:
assert(parser->flags & F_CHUNKED);
- STRICT_CHECK(ch != LF);
+ CROW_STRICT_CHECK(ch != CROW_LF);
parser->nread = 0;
parser->state = s_chunk_size_start;
break;
default:
assert(0 && "unhandled state");
- SET_ERRNO(HPE_INVALID_INTERNAL_STATE);
+ CROW_SET_ERRNO(HPE_INVALID_INTERNAL_STATE);
goto error;
}
}
@@ -2212,7 +2212,7 @@ static const int8_t unhex[256] =
*
* We use the NOADVANCE() variety of callbacks here because 'p' has already
* overflowed 'data' and this allows us to correct for the off-by-one that
- * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p'
+ * we'd otherwise have (since CROW_CALLBACK_DATA() is meant to be run with a 'p'
* value that's in-bounds).
*/
@@ -2222,17 +2222,17 @@ static const int8_t unhex[256] =
(body_mark ? 1 : 0) +
(status_mark ? 1 : 0)) <= 1);
- CALLBACK_DATA_NOADVANCE(header_field);
- CALLBACK_DATA_NOADVANCE(header_value);
- CALLBACK_DATA_NOADVANCE(url);
- CALLBACK_DATA_NOADVANCE(body);
- CALLBACK_DATA_NOADVANCE(status);
+ CROW_CALLBACK_DATA_NOADVANCE(header_field);
+ CROW_CALLBACK_DATA_NOADVANCE(header_value);
+ CROW_CALLBACK_DATA_NOADVANCE(url);
+ CROW_CALLBACK_DATA_NOADVANCE(body);
+ CROW_CALLBACK_DATA_NOADVANCE(status);
return len;
error:
- if (HTTP_PARSER_ERRNO(parser) == HPE_OK) {
- SET_ERRNO(HPE_UNKNOWN);
+ if (CROW_HTTP_PARSER_ERRNO(parser) == HPE_OK) {
+ CROW_SET_ERRNO(HPE_UNKNOWN);
}
return (p - data);
@@ -2255,7 +2255,7 @@ http_message_needs_eof (const http_parser *parser)
return 0;
}
- if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) {
+ if ((parser->flags & F_CHUNKED) || parser->content_length != CROW_ULLONG_MAX) {
return 0;
}
@@ -2287,11 +2287,11 @@ http_method_str (enum http_method m)
{
static const char *method_strings[] =
{
-#define XX(num, name, string) #string,
- HTTP_METHOD_MAP(XX)
-#undef XX
+#define CROW_XX(num, name, string) #string,
+ CROW_HTTP_METHOD_MAP(CROW_XX)
+#undef CROW_XX
};
- return ELEM_AT(method_strings, m, "<unknown>");
+ return CROW_ELEM_AT(method_strings, m, "<unknown>");
}
@@ -2309,14 +2309,14 @@ http_parser_init (http_parser *parser, enum http_parser_type t)
inline const char *
http_errno_name(enum http_errno err) {
/* Map errno values to strings for human-readable output */
-#define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s },
+#define CROW_HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s },
static struct {
const char *name;
const char *description;
} http_strerror_tab[] = {
- HTTP_ERRNO_MAP(HTTP_STRERROR_GEN)
+ CROW_HTTP_ERRNO_MAP(CROW_HTTP_STRERROR_GEN)
};
-#undef HTTP_STRERROR_GEN
+#undef CROW_HTTP_STRERROR_GEN
assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));
return http_strerror_tab[err].name;
}
@@ -2324,14 +2324,14 @@ static struct {
inline const char *
http_errno_description(enum http_errno err) {
/* Map errno values to strings for human-readable output */
-#define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s },
+#define CROW_HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s },
static struct {
const char *name;
const char *description;
} http_strerror_tab[] = {
- HTTP_ERRNO_MAP(HTTP_STRERROR_GEN)
+ CROW_HTTP_ERRNO_MAP(CROW_HTTP_STRERROR_GEN)
};
-#undef HTTP_STRERROR_GEN
+#undef CROW_HTTP_STRERROR_GEN
assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));
return http_strerror_tab[err].description;
}
@@ -2345,7 +2345,7 @@ http_parse_host_char(enum http_host_state s, const char ch) {
return s_http_host_start;
}
- if (IS_USERINFO_CHAR(ch)) {
+ if (CROW_IS_USERINFO_CHAR(ch)) {
return s_http_userinfo;
}
break;
@@ -2355,14 +2355,14 @@ http_parse_host_char(enum http_host_state s, const char ch) {
return s_http_host_v6_start;
}
- if (IS_HOST_CHAR(ch)) {
+ if (CROW_IS_HOST_CHAR(ch)) {
return s_http_host;
}
break;
case s_http_host:
- if (IS_HOST_CHAR(ch)) {
+ if (CROW_IS_HOST_CHAR(ch)) {
return s_http_host;
}
@@ -2381,7 +2381,7 @@ http_parse_host_char(enum http_host_state s, const char ch) {
/* FALLTHROUGH */
case s_http_host_v6_start:
- if (IS_HEX(ch) || ch == ':' || ch == '.') {
+ if (CROW_IS_HEX(ch) || ch == ':' || ch == '.') {
return s_http_host_v6;
}
@@ -2389,7 +2389,7 @@ http_parse_host_char(enum http_host_state s, const char ch) {
case s_http_host_port:
case s_http_host_port_start:
- if (IS_NUM(ch)) {
+ if (CROW_IS_NUM(ch)) {
return s_http_host_port;
}
@@ -2579,9 +2579,9 @@ http_parser_pause(http_parser *parser, int paused) {
* state. In non-debug builds, there's not much that we can do about this
* other than ignore it.
*/
- if (HTTP_PARSER_ERRNO(parser) == HPE_OK ||
- HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) {
- SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK);
+ if (CROW_HTTP_PARSER_ERRNO(parser) == HPE_OK ||
+ CROW_HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) {
+ CROW_SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK);
} else {
assert(0 && "Attempting to pause parser in error state");
}
@@ -2594,45 +2594,45 @@ http_body_is_final(const struct http_parser *parser) {
inline unsigned long
http_parser_version(void) {
- return HTTP_PARSER_VERSION_MAJOR * 0x10000 |
- HTTP_PARSER_VERSION_MINOR * 0x00100 |
- HTTP_PARSER_VERSION_PATCH * 0x00001;
+ return CROW_HTTP_PARSER_VERSION_MAJOR * 0x10000 |
+ CROW_HTTP_PARSER_VERSION_MINOR * 0x00100 |
+ CROW_HTTP_PARSER_VERSION_PATCH * 0x00001;
}
-#undef HTTP_METHOD_MAP
-#undef HTTP_ERRNO_MAP
-#undef SET_ERRNO
-#undef CALLBACK_NOTIFY_
-#undef CALLBACK_NOTIFY
-#undef CALLBACK_NOTIFY_NOADVANCE
-#undef CALLBACK_DATA_
-#undef CALLBACK_DATA
-#undef CALLBACK_DATA_NOADVANCE
-#undef MARK
-#undef PROXY_CONNECTION
-#undef CONNECTION
-#undef CONTENT_LENGTH
-#undef TRANSFER_ENCODING
-#undef UPGRADE
-#undef CHUNKED
-#undef KEEP_ALIVE
-#undef CLOSE
-#undef PARSING_HEADER
-#undef CR
-#undef LF
-#undef LOWER
-#undef IS_ALPHA
-#undef IS_NUM
-#undef IS_ALPHANUM
-#undef IS_HEX
-#undef IS_MARK
-#undef IS_USERINFO_CHAR
-#undef TOKEN
-#undef IS_URL_CHAR
-#undef IS_HOST_CHAR
-#undef start_state
-#undef STRICT_CHECK
-#undef NEW_MESSAGE
+#undef CROW_HTTP_METHOD_MAP
+#undef CROW_HTTP_ERRNO_MAP
+#undef CROW_SET_ERRNO
+#undef CROW_CALLBACK_NOTIFY_
+#undef CROW_CALLBACK_NOTIFY
+#undef CROW_CALLBACK_NOTIFY_NOADVANCE
+#undef CROW_CALLBACK_DATA_
+#undef CROW_CALLBACK_DATA
+#undef CROW_CALLBACK_DATA_NOADVANCE
+#undef CROW_MARK
+#undef CROW_PROXY_CONNECTION
+#undef CROW_CONNECTION
+#undef CROW_CONTENT_LENGTH
+#undef CROW_TRANSFER_ENCODING
+#undef CROW_UPGRADE
+#undef CROW_CHUNKED
+#undef CROW_KEEP_ALIVE
+#undef CROW_CLOSE
+#undef CROW_PARSING_HEADER
+#undef CROW_CR
+#undef CROW_LF
+#undef CROW_LOWER
+#undef CROW_IS_ALPHA
+#undef CROW_IS_NUM
+#undef CROW_IS_ALPHANUM
+#undef CROW_IS_HEX
+#undef CROW_IS_MARK
+#undef CROW_IS_USERINFO_CHAR
+#undef CROW_TOKEN
+#undef CROW_IS_URL_CHAR
+#undef CROW_IS_HOST_CHAR
+#undef CROW_start_state
+#undef CROW_STRICT_CHECK
+#undef CROW_NEW_MESSAGE
#ifdef __cplusplus
}
diff --git a/include/http_request.h b/include/crow/http_request.h
index 75bce73..a70c299 100644
--- a/include/http_request.h
+++ b/include/crow/http_request.h
@@ -1,8 +1,10 @@
#pragma once
-#include "common.h"
-#include "ci_map.h"
-#include "query_string.h"
+#include <boost/asio.hpp>
+
+#include "crow/common.h"
+#include "crow/ci_map.h"
+#include "crow/query_string.h"
namespace crow
{
@@ -17,6 +19,8 @@ namespace crow
return empty;
}
+ struct DetachHelper;
+
struct request
{
HTTPMethod method;
@@ -27,9 +31,10 @@ namespace crow
std::string body;
void* middleware_context{};
+ boost::asio::io_service* io_service{};
request()
- : method(HTTPMethod::GET)
+ : method(HTTPMethod::Get)
{
}
@@ -48,5 +53,17 @@ namespace crow
return crow::get_header_value(headers, key);
}
+ template<typename CompletionHandler>
+ void post(CompletionHandler handler)
+ {
+ io_service->post(handler);
+ }
+
+ template<typename CompletionHandler>
+ void dispatch(CompletionHandler handler)
+ {
+ io_service->dispatch(handler);
+ }
+
};
}
diff --git a/include/http_response.h b/include/crow/http_response.h
index 23f312a..f5e03b4 100644
--- a/include/http_response.h
+++ b/include/crow/http_response.h
@@ -1,9 +1,10 @@
#pragma once
#include <string>
#include <unordered_map>
-#include "json.h"
-#include "http_request.h"
-#include "ci_map.h"
+
+#include "crow/json.h"
+#include "crow/http_request.h"
+#include "crow/ci_map.h"
namespace crow
{
diff --git a/include/http_server.h b/include/crow/http_server.h
index fbe470d..787fdb8 100644
--- a/include/http_server.h
+++ b/include/crow/http_server.h
@@ -1,5 +1,6 @@
#pragma once
+#include <chrono>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/asio.hpp>
#ifdef CROW_ENABLE_SSL
@@ -12,9 +13,9 @@
#include <memory>
-#include "http_connection.h"
-#include "logging.h"
-#include "dumb_timer_queue.h"
+#include "crow/http_connection.h"
+#include "crow/logging.h"
+#include "crow/dumb_timer_queue.h"
namespace crow
{
@@ -28,6 +29,7 @@ namespace crow
Server(Handler* handler, std::string bindaddr, uint16_t port, std::tuple<Middlewares...>* middlewares = nullptr, uint16_t concurrency = 1, typename Adaptor::context* adaptor_ctx = nullptr)
: acceptor_(io_service_, tcp::endpoint(boost::asio::ip::address::from_string(bindaddr), port)),
signals_(io_service_, SIGINT, SIGTERM),
+ tick_timer_(io_service_),
handler_(handler),
concurrency_(concurrency),
port_(port),
@@ -37,6 +39,24 @@ namespace crow
{
}
+ void set_tick_function(std::chrono::milliseconds d, std::function<void()> f)
+ {
+ tick_interval_ = d;
+ tick_function_ = f;
+ }
+
+ void on_tick()
+ {
+ tick_function_();
+ tick_timer_.expires_from_now(boost::posix_time::milliseconds(tick_interval_.count()));
+ tick_timer_.async_wait([this](const boost::system::error_code& ec)
+ {
+ if (ec)
+ return;
+ on_tick();
+ });
+ }
+
void run()
{
if (concurrency_ < 0)
@@ -48,9 +68,10 @@ namespace crow
timer_queue_pool_.resize(concurrency_);
std::vector<std::future<void>> v;
+ std::atomic<int> init_count(0);
for(uint16_t i = 0; i < concurrency_; i ++)
v.push_back(
- std::async(std::launch::async, [this, i]{
+ std::async(std::launch::async, [this, i, &init_count]{
// thread local date string get function
auto last = std::chrono::steady_clock::now();
@@ -99,20 +120,44 @@ namespace crow
};
timer.async_wait(handler);
- io_service_pool_[i]->run();
+ init_count ++;
+ while(1)
+ {
+ try
+ {
+ if (io_service_pool_[i]->run() == 0)
+ {
+ // when io_service.run returns 0, there are no more works to do.
+ break;
+ }
+ } catch(std::exception& e)
+ {
+ CROW_LOG_ERROR << "Worker Crash: An uncaught exception occurred: " << e.what();
+ }
+ }
}));
- CROW_LOG_INFO << server_name_ << " server is running, local port " << port_;
+
+ if (tick_function_ && tick_interval_.count() > 0)
+ {
+ tick_timer_.expires_from_now(boost::posix_time::milliseconds(tick_interval_.count()));
+ tick_timer_.async_wait([this](const boost::system::error_code& ec)
+ {
+ if (ec)
+ return;
+ on_tick();
+ });
+ }
+
+ CROW_LOG_INFO << server_name_ << " server is running on port " << port_
+ << " using " << concurrency_ << " threads";
signals_.async_wait(
- [&](const boost::system::error_code& error, int signal_number){
+ [&](const boost::system::error_code& /*error*/, int /*signal_number*/){
stop();
});
- for (int i = 0; i < concurrency_; i++)
- {
- while (timer_queue_pool_[i] == nullptr)
- std::this_thread::yield();
- }
+ while(concurrency_ != init_count)
+ std::this_thread::yield();
do_accept();
@@ -156,6 +201,10 @@ namespace crow
p->start();
});
}
+ else
+ {
+ delete p;
+ }
do_accept();
});
}
@@ -167,6 +216,7 @@ namespace crow
std::vector<std::function<std::string()>> get_cached_date_str_pool_;
tcp::acceptor acceptor_;
boost::asio::signal_set signals_;
+ boost::asio::deadline_timer tick_timer_;
Handler* handler_;
uint16_t concurrency_{1};
@@ -175,6 +225,9 @@ namespace crow
std::string bindaddr_;
unsigned int roundrobin_index_{};
+ std::chrono::milliseconds tick_interval_;
+ std::function<void()> tick_function_;
+
std::tuple<Middlewares...>* middlewares_;
#ifdef CROW_ENABLE_SSL
diff --git a/include/json.h b/include/crow/json.h
index c2ce20e..3d9ed18 100644
--- a/include/json.h
+++ b/include/crow/json.h
@@ -12,6 +12,8 @@
#include <boost/operators.hpp>
#include <vector>
+#include "crow/settings.h"
+
#if defined(__GNUG__) || defined(__clang__)
#define crow_json_likely(x) __builtin_expect(x, 1)
#define crow_json_unlikely(x) __builtin_expect(x, 0)
@@ -92,7 +94,7 @@ namespace crow
case type::Object: return "Object";
default: return "Unknown";
}
- };
+ }
class rvalue;
rvalue load(const char* data, size_t size);
@@ -131,6 +133,8 @@ namespace crow
s_ = r.s_;
e_ = r.e_;
owned_ = r.owned_;
+ if (r.owned_)
+ r.owned_ = 0;
return *this;
}
@@ -164,7 +168,7 @@ namespace crow
return os;
}
private:
- void force(char* s, uint32_t length)
+ void force(char* s, uint32_t /*length*/)
{
s_ = s;
owned_ = 1;
@@ -262,6 +266,11 @@ namespace crow
return i();
}
+ explicit operator uint64_t() const
+ {
+ return u();
+ }
+
explicit operator int() const
{
return (int)i();
@@ -294,6 +303,20 @@ namespace crow
return boost::lexical_cast<int64_t>(start_, end_-start_);
}
+ uint64_t u() const
+ {
+#ifndef CROW_JSON_NO_ERROR_CHECK
+ switch (t()) {
+ case type::Number:
+ case type::String:
+ return boost::lexical_cast<uint64_t>(start_, end_-start_);
+ default:
+ throw std::runtime_error(std::string("expected number, got: ") + get_type_str(t()));
+ }
+#endif
+ return boost::lexical_cast<uint64_t>(start_, end_-start_);
+ }
+
double d() const
{
#ifndef CROW_JSON_NO_ERROR_CHECK
@@ -671,7 +694,7 @@ namespace crow
//static const char* escaped = "\"\\/\b\f\n\r\t";
struct Parser
{
- Parser(char* data, size_t size)
+ Parser(char* data, size_t /*size*/)
: data(data)
{
}
@@ -1093,17 +1116,16 @@ namespace crow
s = r.s();
return;
case type::List:
- l = std::move(std::unique_ptr<std::vector<wvalue>>(new std::vector<wvalue>{}));
+ l = std::unique_ptr<std::vector<wvalue>>(new std::vector<wvalue>{});
l->reserve(r.size());
for(auto it = r.begin(); it != r.end(); ++it)
l->emplace_back(*it);
return;
case type::Object:
- o = std::move(
- std::unique_ptr<
+ o = std::unique_ptr<
std::unordered_map<std::string, wvalue>
>(
- new std::unordered_map<std::string, wvalue>{}));
+ new std::unordered_map<std::string, wvalue>{});
for(auto it = r.begin(); it != r.end(); ++it)
o->emplace(it->key(), *it);
return;
@@ -1242,6 +1264,23 @@ namespace crow
return *this;
}
+ wvalue& operator=(std::vector<wvalue>&& v)
+ {
+ if (t_ != type::List)
+ reset();
+ t_ = type::List;
+ if (!l)
+ l = std::unique_ptr<std::vector<wvalue>>(new std::vector<wvalue>{});
+ l->clear();
+ l->resize(v.size());
+ size_t idx = 0;
+ for(auto& x:v)
+ {
+ (*l)[idx++] = std::move(x);
+ }
+ return *this;
+ }
+
template <typename T>
wvalue& operator=(const std::vector<T>& v)
{
@@ -1249,7 +1288,7 @@ namespace crow
reset();
t_ = type::List;
if (!l)
- l = std::move(std::unique_ptr<std::vector<wvalue>>(new std::vector<wvalue>{}));
+ l = std::unique_ptr<std::vector<wvalue>>(new std::vector<wvalue>{});
l->clear();
l->resize(v.size());
size_t idx = 0;
@@ -1266,7 +1305,7 @@ namespace crow
reset();
t_ = type::List;
if (!l)
- l = std::move(std::unique_ptr<std::vector<wvalue>>(new std::vector<wvalue>{}));
+ l = std::unique_ptr<std::vector<wvalue>>(new std::vector<wvalue>{});
if (l->size() < index+1)
l->resize(index+1);
return (*l)[index];
@@ -1287,14 +1326,31 @@ namespace crow
reset();
t_ = type::Object;
if (!o)
- o = std::move(
- std::unique_ptr<
+ o = std::unique_ptr<
std::unordered_map<std::string, wvalue>
>(
- new std::unordered_map<std::string, wvalue>{}));
+ new std::unordered_map<std::string, wvalue>{});
return (*o)[str];
}
+ std::vector<std::string> keys() const {
+ std::vector<std::string> result;
+ switch (t_) {
+ case type::Null: return result;
+ case type::False: return result;
+ case type::True: return result;
+ case type::Number: return result;
+ case type::String: return result;
+ case type::List: return result;
+ case type::Object: {
+ for (auto& kv:*o) {
+ result.push_back(kv.first);
+ }
+ return result;
+ }
+ }
+ }
+
size_t estimate_length() const
{
switch(t_)
@@ -1335,7 +1391,6 @@ namespace crow
return 1;
}
-
friend void dump_internal(const wvalue& v, std::string& out);
friend std::string dump(const wvalue& v);
};
@@ -1356,7 +1411,12 @@ namespace crow
case type::Number:
{
char outbuf[128];
+#ifdef _MSC_VER
+ sprintf_s(outbuf, 128, "%g", v.d);
+#else
sprintf(outbuf, "%g", v.d);
+#endif
+
out += outbuf;
}
break;
diff --git a/include/logging.h b/include/crow/logging.h
index b915e6e..9c8bfbb 100644
--- a/include/logging.h
+++ b/include/crow/logging.h
@@ -7,17 +7,25 @@
#include <iostream>
#include <sstream>
-#include "settings.h"
+#include "crow/settings.h"
namespace crow
{
enum class LogLevel
{
- DEBUG,
+#ifndef ERROR
+ DEBUG = 0,
INFO,
WARNING,
ERROR,
CRITICAL,
+#endif
+
+ Debug = 0,
+ Info,
+ Warning,
+ Error,
+ Critical,
};
class ILogHandler {
@@ -27,7 +35,7 @@ namespace crow
class CerrLogHandler : public ILogHandler {
public:
- void log(std::string message, LogLevel level) override {
+ void log(std::string message, LogLevel /*level*/) override {
std::cerr << message;
}
};
@@ -117,18 +125,18 @@ namespace crow
}
#define CROW_LOG_CRITICAL \
- if (crow::logger::get_current_log_level() <= crow::LogLevel::CRITICAL) \
- crow::logger("CRITICAL", crow::LogLevel::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)
+ 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)
+ 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)
+ 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)
+ if (crow::logger::get_current_log_level() <= crow::LogLevel::Debug) \
+ crow::logger("DEBUG ", crow::LogLevel::Debug)
diff --git a/include/middleware.h b/include/crow/middleware.h
index ec54476..5e3ea32 100644
--- a/include/middleware.h
+++ b/include/crow/middleware.h
@@ -1,7 +1,7 @@
#pragma once
#include <boost/algorithm/string/trim.hpp>
-#include "http_request.h"
-#include "http_response.h"
+#include "crow/http_request.h"
+#include "crow/http_response.h"
namespace crow
{
@@ -139,7 +139,7 @@ namespace crow
}
}
- void after_handle(request& req, response& res, context& ctx)
+ void after_handle(request& /*req*/, response& res, context& ctx)
{
for(auto& cookie:ctx.cookies_to_add)
{
diff --git a/include/middleware_context.h b/include/crow/middleware_context.h
index daaaa5c..6885c13 100644
--- a/include/middleware_context.h
+++ b/include/crow/middleware_context.h
@@ -1,8 +1,8 @@
#pragma once
-#include "utility.h"
-#include "http_request.h"
-#include "http_response.h"
+#include "crow/utility.h"
+#include "crow/http_request.h"
+#include "crow/http_response.h"
namespace crow
{
diff --git a/include/mustache.h b/include/crow/mustache.h
index b596b45..bfb9f14 100644
--- a/include/mustache.h
+++ b/include/crow/mustache.h
@@ -4,7 +4,7 @@
#include <fstream>
#include <iterator>
#include <functional>
-#include "json.h"
+#include "crow/json.h"
namespace crow
{
namespace mustache
@@ -520,7 +520,11 @@ namespace crow
inline std::string default_loader(const std::string& filename)
{
- std::ifstream inf(detail::get_template_base_directory_ref() + filename);
+ std::string path = detail::get_template_base_directory_ref();
+ if (!(path.back() == '/' || path.back() == '\\'))
+ path += '/';
+ path += filename;
+ std::ifstream inf(path);
if (!inf)
return {};
return {std::istreambuf_iterator<char>(inf), std::istreambuf_iterator<char>()};
@@ -551,6 +555,11 @@ namespace crow
detail::get_loader_ref() = std::move(loader);
}
+ inline std::string load_text(const std::string& filename)
+ {
+ return detail::get_loader_ref()(filename);
+ }
+
inline template_t load(const std::string& filename)
{
return compile(detail::get_loader_ref()(filename));
diff --git a/include/parser.h b/include/crow/parser.h
index f6b748b..4a4f57e 100644
--- a/include/parser.h
+++ b/include/crow/parser.h
@@ -6,8 +6,8 @@
#include <boost/tokenizer.hpp>
#include <algorithm>
-#include "http_parser_merged.h"
-#include "http_request.h"
+#include "crow/http_parser_merged.h"
+#include "crow/http_request.h"
namespace crow
{
@@ -143,6 +143,11 @@ namespace crow
return request{(HTTPMethod)method, std::move(raw_url), std::move(url), std::move(url_params), std::move(headers), std::move(body)};
}
+ bool is_upgrade() const
+ {
+ return upgrade;
+ }
+
bool check_version(int major, int minor) const
{
return http_major == major && http_minor == minor;
diff --git a/include/query_string.h b/include/crow/query_string.h
index 03e5cfd..ee61e30 100644
--- a/include/query_string.h
+++ b/include/crow/query_string.h
@@ -4,8 +4,12 @@
#include <string.h>
#include <string>
#include <vector>
+#include <unordered_map>
#include <iostream>
+#include <boost/optional.hpp>
+namespace crow
+{
// ----------------------------------------------------------------------------
// qs_parse (modified)
// https://github.com/bartgrantham/qs_parse
@@ -195,6 +199,48 @@ inline char * qs_k2v(const char * key, char * const * qs_kv, int qs_kv_size, int
return NULL;
}
+inline boost::optional<std::pair<std::string, std::string>> 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<qs_kv_size; i++)
+ {
+ if ( strncmp(dict_name, qs_kv[i], name_len) == 0 )
+ {
+ skip_to_eq = strcspn(qs_kv[i], "=");
+ if ( qs_kv[i][skip_to_eq] == '=' )
+ skip_to_eq++;
+ skip_to_brace_open = strcspn(qs_kv[i], "[");
+ if ( qs_kv[i][skip_to_brace_open] == '[' )
+ skip_to_brace_open++;
+ skip_to_brace_close = strcspn(qs_kv[i], "]");
+
+ if ( skip_to_brace_open <= skip_to_brace_close &&
+ skip_to_brace_open > 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)
{
@@ -220,8 +266,12 @@ inline char * qs_scanvalue(const char * key, const char * qs, char * val, size_t
{
qs++;
i = strcspn(qs, "&=#");
- strncpy(val, qs, (val_len-1)<(i+1) ? (val_len-1) : (i+1));
- qs_decode(val);
+#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
{
@@ -231,6 +281,7 @@ inline char * qs_scanvalue(const char * key, const char * qs, char * val, size_t
return val;
}
+}
// ----------------------------------------------------------------------------
@@ -333,6 +384,20 @@ namespace crow
return ret;
}
+ std::unordered_map<std::string, std::string> get_dict (const std::string& name) const
+ {
+ std::unordered_map<std::string, std::string> 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_;
diff --git a/include/routing.h b/include/crow/routing.h
index 3261134..cdfa480 100644
--- a/include/routing.h
+++ b/include/crow/routing.h
@@ -8,11 +8,12 @@
#include <boost/lexical_cast.hpp>
#include <vector>
-#include "common.h"
-#include "http_response.h"
-#include "http_request.h"
-#include "utility.h"
-#include "logging.h"
+#include "crow/common.h"
+#include "crow/http_response.h"
+#include "crow/http_request.h"
+#include "crow/utility.h"
+#include "crow/logging.h"
+#include "crow/websocket.h"
namespace crow
{
@@ -29,8 +30,26 @@ namespace crow
}
virtual void validate() = 0;
+ std::unique_ptr<BaseRule> upgrade()
+ {
+ if (rule_to_upgrade_)
+ return std::move(rule_to_upgrade_);
+ return {};
+ }
virtual void handle(const request&, response&, const routing_params&) = 0;
+ virtual void handle_upgrade(const request&, response& res, SocketAdaptor&&)
+ {
+ res = response(404);
+ res.end();
+ }
+#ifdef CROW_ENABLE_SSL
+ virtual void handle_upgrade(const request&, response& res, SSLAdaptor&&)
+ {
+ res = response(404);
+ res.end();
+ }
+#endif
uint32_t get_methods()
{
@@ -38,10 +57,13 @@ namespace crow
}
protected:
- uint32_t methods_{1<<(int)HTTPMethod::GET};
+ uint32_t methods_{1<<(int)HTTPMethod::Get};
std::string rule_;
std::string name_;
+
+ std::unique_ptr<BaseRule> rule_to_upgrade_;
+
friend class Router;
template <typename T>
friend struct RuleParameterTraits;
@@ -134,7 +156,7 @@ namespace crow
struct Wrapped
{
template <typename ... Args>
- void set(Func f, typename std::enable_if<
+ void set_(Func f, typename std::enable_if<
!std::is_same<typename std::tuple_element<0, std::tuple<Args..., void>>::type, const request&>::value
, int>::type = 0)
{
@@ -168,7 +190,7 @@ namespace crow
};
template <typename ... Args>
- void set(Func f, typename std::enable_if<
+ void set_(Func f, typename std::enable_if<
std::is_same<typename std::tuple_element<0, std::tuple<Args..., void>>::type, const request&>::value &&
!std::is_same<typename std::tuple_element<1, std::tuple<Args..., void, void>>::type, response&>::value
, int>::type = 0)
@@ -183,7 +205,7 @@ namespace crow
}
template <typename ... Args>
- void set(Func f, typename std::enable_if<
+ void set_(Func f, typename std::enable_if<
std::is_same<typename std::tuple_element<0, std::tuple<Args..., void>>::type, const request&>::value &&
std::is_same<typename std::tuple_element<1, std::tuple<Args..., void, void>>::type, response&>::value
, int>::type = 0)
@@ -233,10 +255,90 @@ namespace crow
}
}
+ class WebSocketRule : public BaseRule
+ {
+ using self_t = WebSocketRule;
+ public:
+ WebSocketRule(std::string rule)
+ : BaseRule(std::move(rule))
+ {
+ }
+
+ void validate() override
+ {
+ }
+
+ void handle(const request&, response& res, const routing_params&) override
+ {
+ res = response(404);
+ res.end();
+ }
+
+ void handle_upgrade(const request& req, response&, SocketAdaptor&& adaptor) override
+ {
+ new crow::websocket::Connection<SocketAdaptor>(req, std::move(adaptor), open_handler_, message_handler_, close_handler_, error_handler_, accept_handler_);
+ }
+#ifdef CROW_ENABLE_SSL
+ void handle_upgrade(const request& req, response&, SSLAdaptor&& adaptor) override
+ {
+ new crow::websocket::Connection<SSLAdaptor>(req, std::move(adaptor), open_handler_, message_handler_, close_handler_, error_handler_, accept_handler_);
+ }
+#endif
+
+ template <typename Func>
+ self_t& onopen(Func f)
+ {
+ open_handler_ = f;
+ return *this;
+ }
+
+ template <typename Func>
+ self_t& onmessage(Func f)
+ {
+ message_handler_ = f;
+ return *this;
+ }
+
+ template <typename Func>
+ self_t& onclose(Func f)
+ {
+ close_handler_ = f;
+ return *this;
+ }
+
+ template <typename Func>
+ self_t& onerror(Func f)
+ {
+ error_handler_ = f;
+ return *this;
+ }
+
+ template <typename Func>
+ self_t& onaccept(Func f)
+ {
+ accept_handler_ = f;
+ return *this;
+ }
+
+ protected:
+ std::function<void(crow::websocket::connection&)> open_handler_;
+ std::function<void(crow::websocket::connection&, const std::string&, bool)> message_handler_;
+ std::function<void(crow::websocket::connection&, const std::string&)> close_handler_;
+ std::function<void(crow::websocket::connection&)> error_handler_;
+ std::function<bool(const crow::request&)> accept_handler_;
+ };
+
template <typename T>
struct RuleParameterTraits
{
using self_t = T;
+ WebSocketRule& websocket()
+ {
+ auto p =new WebSocketRule(((self_t*)this)->rule_);
+ ((self_t*)this)->rule_to_upgrade_.reset(p);
+ return *p;
+ }
+
self_t& name(std::string name) noexcept
{
((self_t*)this)->name_ = std::move(name);
@@ -256,6 +358,7 @@ namespace crow
((self_t*)this)->methods_ |= 1 << (int)method;
return (self_t&)*this;
}
+
};
class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
@@ -315,7 +418,7 @@ namespace crow
throw std::runtime_error("route_dynamic: Handler type is mismatched with URL parameters: " + rule_);
}
auto ret = detail::routing_handler_call_helper::Wrapped<Func, typename function_t::template arg<Indices>...>();
- ret.template set<
+ ret.template set_<
typename function_t::template arg<Indices>...
>(std::move(f));
return ret;
@@ -343,7 +446,7 @@ namespace crow
{
}
- void validate()
+ void validate() override
{
if (!handler_)
{
@@ -361,10 +464,16 @@ namespace crow
static_assert(!std::is_same<void, decltype(f(std::declval<Args>()...))>::value,
"Handler function cannot have void return type; valid return types: string, int, crow::resposne, crow::json::wvalue");
- handler_ = [f = std::move(f)](const request&, response& res, Args ... args){
+ handler_ = (
+#ifdef CROW_CAN_USE_CPP14
+ [f = std::move(f)]
+#else
+ [f]
+#endif
+ (const request&, response& res, Args ... args){
res = response(f(args...));
res.end();
- };
+ });
}
template <typename Func>
@@ -380,10 +489,16 @@ namespace crow
static_assert(!std::is_same<void, decltype(f(std::declval<crow::request>(), std::declval<Args>()...))>::value,
"Handler function cannot have void return type; valid return types: string, int, crow::resposne, crow::json::wvalue");
- handler_ = [f = std::move(f)](const crow::request& req, crow::response& res, Args ... args){
+ handler_ = (
+#ifdef CROW_CAN_USE_CPP14
+ [f = std::move(f)]
+#else
+ [f]
+#endif
+ (const crow::request& req, crow::response& res, Args ... args){
res = response(f(req, args...));
res.end();
- };
+ });
}
template <typename Func>
@@ -809,16 +924,85 @@ public:
for(auto& rule:rules_)
{
if (rule)
+ {
+ auto upgraded = rule->upgrade();
+ if (upgraded)
+ rule = std::move(upgraded);
rule->validate();
+ }
}
}
+ template <typename Adaptor>
+ void handle_upgrade(const request& req, response& res, Adaptor&& adaptor)
+ {
+ auto found = trie_.find(req.url);
+ unsigned rule_index = found.first;
+ if (!rule_index)
+ {
+ CROW_LOG_DEBUG << "Cannot match rules " << req.url;
+ res = response(404);
+ res.end();
+ return;
+ }
+
+ if (rule_index >= rules_.size())
+ throw std::runtime_error("Trie internal structure corrupted!");
+
+ if (rule_index == RULE_SPECIAL_REDIRECT_SLASH)
+ {
+ CROW_LOG_INFO << "Redirecting to a url with trailing slash: " << req.url;
+ res = response(301);
+
+ // TODO absolute url building
+ if (req.get_header_value("Host").empty())
+ {
+ res.add_header("Location", req.url + "/");
+ }
+ else
+ {
+ res.add_header("Location", "http://" + req.get_header_value("Host") + req.url + "/");
+ }
+ res.end();
+ return;
+ }
+
+ if ((rules_[rule_index]->get_methods() & (1<<(uint32_t)req.method)) == 0)
+ {
+ CROW_LOG_DEBUG << "Rule found but method mismatch: " << req.url << " with " << method_name(req.method) << "(" << (uint32_t)req.method << ") / " << rules_[rule_index]->get_methods();
+ res = response(404);
+ res.end();
+ return;
+ }
+
+ CROW_LOG_DEBUG << "Matched rule (upgrade) '" << rules_[rule_index]->rule_ << "' " << (uint32_t)req.method << " / " << rules_[rule_index]->get_methods();
+
+ // any uncaught exceptions become 500s
+ try
+ {
+ rules_[rule_index]->handle_upgrade(req, res, std::move(adaptor));
+ }
+ catch(std::exception& e)
+ {
+ CROW_LOG_ERROR << "An uncaught exception occurred: " << e.what();
+ res = response(500);
+ res.end();
+ return;
+ }
+ catch(...)
+ {
+ CROW_LOG_ERROR << "An uncaught exception occurred. The type was unknown so no information was available.";
+ res = response(500);
+ res.end();
+ return;
+ }
+ }
+
void handle(const request& req, response& res)
{
auto found = trie_.find(req.url);
unsigned rule_index = found.first;
- CROW_LOG_DEBUG << "???" << rule_index;
if (!rule_index)
{
diff --git a/include/settings.h b/include/crow/settings.h
index fc9392c..5c67f3b 100644
--- a/include/settings.h
+++ b/include/crow/settings.h
@@ -8,16 +8,16 @@
/* #ifdef - enables logging */
#define CROW_ENABLE_LOGGING
-/* #ifdef - enables SSL */
+/* #ifdef - enables ssl */
//#define CROW_ENABLE_SSL
/* #define - specifies log level */
/*
- DEBUG = 0
- INFO = 1
- WARNING = 2
- ERROR = 3
- CRITICAL = 4
+ Debug = 0
+ Info = 1
+ Warning = 2
+ Error = 3
+ Critical = 4
default to INFO
*/
diff --git a/include/socket_adaptors.h b/include/crow/socket_adaptors.h
index 201360c..eebd50f 100644
--- a/include/socket_adaptors.h
+++ b/include/crow/socket_adaptors.h
@@ -1,6 +1,9 @@
#pragma once
#include <boost/asio.hpp>
-#include "settings.h"
+#ifdef CROW_ENABLE_SSL
+#include <boost/asio/ssl.hpp>
+#endif
+#include "crow/settings.h"
namespace crow
{
using namespace boost;
@@ -14,6 +17,11 @@ namespace crow
{
}
+ boost::asio::io_service& get_io_service()
+ {
+ return socket_.get_io_service();
+ }
+
tcp::socket& raw_socket()
{
return socket_;
@@ -52,20 +60,21 @@ namespace crow
struct SSLAdaptor
{
using context = boost::asio::ssl::context;
+ using ssl_socket_t = boost::asio::ssl::stream<tcp::socket>;
SSLAdaptor(boost::asio::io_service& io_service, context* ctx)
- : ssl_socket_(io_service, *ctx)
+ : ssl_socket_(new ssl_socket_t(io_service, *ctx))
{
}
boost::asio::ssl::stream<tcp::socket>& socket()
{
- return ssl_socket_;
+ return *ssl_socket_;
}
tcp::socket::lowest_layer_type&
raw_socket()
{
- return ssl_socket_.lowest_layer();
+ return ssl_socket_->lowest_layer();
}
tcp::endpoint remote_endpoint()
@@ -83,16 +92,21 @@ namespace crow
raw_socket().close();
}
+ boost::asio::io_service& get_io_service()
+ {
+ return raw_socket().get_io_service();
+ }
+
template <typename F>
void start(F f)
{
- ssl_socket_.async_handshake(boost::asio::ssl::stream_base::server,
+ ssl_socket_->async_handshake(boost::asio::ssl::stream_base::server,
[f](const boost::system::error_code& ec) {
f(ec);
});
}
- boost::asio::ssl::stream<tcp::socket> ssl_socket_;
+ std::unique_ptr<boost::asio::ssl::stream<tcp::socket>> ssl_socket_;
};
#endif
}
diff --git a/include/utility.h b/include/crow/utility.h
index cf12158..43503e8 100644
--- a/include/utility.h
+++ b/include/crow/utility.h
@@ -6,6 +6,9 @@
#include <type_traits>
#include <cstring>
#include <functional>
+#include <string>
+
+#include "crow/settings.h"
namespace crow
{
@@ -14,7 +17,7 @@ namespace crow
#ifndef CROW_MSVC_WORKAROUND
struct OutOfRange
{
- OutOfRange(unsigned pos, unsigned length) {}
+ OutOfRange(unsigned /*pos*/, unsigned /*length*/) {}
};
constexpr unsigned requires_in_range( unsigned i, unsigned len )
{
@@ -129,7 +132,7 @@ template <> \
struct parameter_tag<t> \
{ \
static const int value = i; \
-};
+}
CROW_INTERNAL_PARAMETER_TAG(int, 1);
CROW_INTERNAL_PARAMETER_TAG(char, 1);
CROW_INTERNAL_PARAMETER_TAG(short, 1);
@@ -499,5 +502,47 @@ template <typename F, typename Set>
using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
};
+ inline static std::string base64encode(const char* data, size_t size, const char* key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
+ {
+ std::string ret;
+ ret.resize((size+2) / 3 * 4);
+ auto it = ret.begin();
+ while(size >= 3)
+ {
+ *it++ = key[(((unsigned char)*data)&0xFC)>>2];
+ unsigned char h = (((unsigned char)*data++) & 0x03) << 4;
+ *it++ = key[h|((((unsigned char)*data)&0xF0)>>4)];
+ h = (((unsigned char)*data++) & 0x0F) << 2;
+ *it++ = key[h|((((unsigned char)*data)&0xC0)>>6)];
+ *it++ = key[((unsigned char)*data++)&0x3F];
+
+ size -= 3;
+ }
+ if (size == 1)
+ {
+ *it++ = key[(((unsigned char)*data)&0xFC)>>2];
+ unsigned char h = (((unsigned char)*data++) & 0x03) << 4;
+ *it++ = key[h];
+ *it++ = '=';
+ *it++ = '=';
+ }
+ else if (size == 2)
+ {
+ *it++ = key[(((unsigned char)*data)&0xFC)>>2];
+ unsigned char h = (((unsigned char)*data++) & 0x03) << 4;
+ *it++ = key[h|((((unsigned char)*data)&0xF0)>>4)];
+ h = (((unsigned char)*data++) & 0x0F) << 2;
+ *it++ = key[h];
+ *it++ = '=';
+ }
+ return ret;
+ }
+
+ inline static std::string base64encode_urlsafe(const char* data, size_t size)
+ {
+ return base64encode(data, size, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
+ }
+
+
} // namespace utility
}
diff --git a/include/crow/websocket.h b/include/crow/websocket.h
new file mode 100644
index 0000000..d21d7e9
--- /dev/null
+++ b/include/crow/websocket.h
@@ -0,0 +1,506 @@
+#pragma once
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/array.hpp>
+#include "crow/socket_adaptors.h"
+#include "crow/http_request.h"
+#include "crow/TinySHA1.hpp"
+
+namespace crow
+{
+ namespace websocket
+ {
+ enum class WebSocketReadState
+ {
+ MiniHeader,
+ Len16,
+ Len64,
+ Mask,
+ Payload,
+ };
+
+ struct connection
+ {
+ virtual void send_binary(const std::string& msg) = 0;
+ virtual void send_text(const std::string& msg) = 0;
+ virtual void close(const std::string& msg = "quit") = 0;
+ virtual ~connection(){}
+
+ void userdata(void* u) { userdata_ = u; }
+ void* userdata() { return userdata_; }
+
+ private:
+ void* userdata_;
+ };
+
+ template <typename Adaptor>
+ class Connection : public connection
+ {
+ public:
+ Connection(const crow::request& req, Adaptor&& adaptor,
+ std::function<void(crow::websocket::connection&)> open_handler,
+ std::function<void(crow::websocket::connection&, const std::string&, bool)> message_handler,
+ std::function<void(crow::websocket::connection&, const std::string&)> close_handler,
+ std::function<void(crow::websocket::connection&)> error_handler,
+ std::function<bool(const crow::request&)> accept_handler)
+ : adaptor_(std::move(adaptor)), open_handler_(std::move(open_handler)), message_handler_(std::move(message_handler)), close_handler_(std::move(close_handler)), error_handler_(std::move(error_handler))
+ , accept_handler_(std::move(accept_handler))
+ {
+ if (!boost::iequals(req.get_header_value("upgrade"), "websocket"))
+ {
+ adaptor.close();
+ delete this;
+ return;
+ }
+
+ if (accept_handler_)
+ {
+ if (!accept_handler_(req))
+ {
+ adaptor.close();
+ delete this;
+ return;
+ }
+ }
+
+ // Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
+ // Sec-WebSocket-Version: 13
+ std::string magic = req.get_header_value("Sec-WebSocket-Key") + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+ sha1::SHA1 s;
+ s.processBytes(magic.data(), magic.size());
+ uint8_t digest[20];
+ s.getDigestBytes(digest);
+ start(crow::utility::base64encode((char*)digest, 20));
+ }
+
+ template<typename CompletionHandler>
+ void dispatch(CompletionHandler handler)
+ {
+ adaptor_.get_io_service().dispatch(handler);
+ }
+
+ template<typename CompletionHandler>
+ void post(CompletionHandler handler)
+ {
+ adaptor_.get_io_service().post(handler);
+ }
+
+ void send_pong(const std::string& msg)
+ {
+ dispatch([this, msg]{
+ char buf[3] = "\x8A\x00";
+ buf[1] += msg.size();
+ write_buffers_.emplace_back(buf, buf+2);
+ write_buffers_.emplace_back(msg);
+ do_write();
+ });
+ }
+
+ void send_binary(const std::string& msg) override
+ {
+ dispatch([this, msg]{
+ auto header = build_header(2, msg.size());
+ write_buffers_.emplace_back(std::move(header));
+ write_buffers_.emplace_back(msg);
+ do_write();
+ });
+ }
+
+ void send_text(const std::string& msg) override
+ {
+ dispatch([this, msg]{
+ auto header = build_header(1, msg.size());
+ write_buffers_.emplace_back(std::move(header));
+ write_buffers_.emplace_back(msg);
+ do_write();
+ });
+ }
+
+ void close(const std::string& msg) override
+ {
+ dispatch([this, msg]{
+ has_sent_close_ = true;
+ if (has_recv_close_ && !is_close_handler_called_)
+ {
+ is_close_handler_called_ = true;
+ if (close_handler_)
+ close_handler_(*this, msg);
+ }
+ auto header = build_header(0x8, msg.size());
+ write_buffers_.emplace_back(std::move(header));
+ write_buffers_.emplace_back(msg);
+ do_write();
+ });
+ }
+
+ protected:
+
+ std::string build_header(int opcode, size_t size)
+ {
+ char buf[2+8] = "\x80\x00";
+ buf[0] += opcode;
+ if (size < 126)
+ {
+ buf[1] += size;
+ return {buf, buf+2};
+ }
+ else if (size < 0x10000)
+ {
+ buf[1] += 126;
+ *(uint16_t*)(buf+2) = htons((uint16_t)size);
+ return {buf, buf+4};
+ }
+ else
+ {
+ buf[1] += 127;
+ *(uint64_t*)(buf+2) = ((1==htonl(1)) ? (uint64_t)size : ((uint64_t)htonl((size) & 0xFFFFFFFF) << 32) | htonl((size) >> 32));
+ return {buf, buf+10};
+ }
+ }
+
+ void start(std::string&& hello)
+ {
+ static std::string header = "HTTP/1.1 101 Switching Protocols\r\n"
+ "Upgrade: websocket\r\n"
+ "Connection: Upgrade\r\n"
+ "Sec-WebSocket-Accept: ";
+ static std::string crlf = "\r\n";
+ write_buffers_.emplace_back(header);
+ write_buffers_.emplace_back(std::move(hello));
+ write_buffers_.emplace_back(crlf);
+ write_buffers_.emplace_back(crlf);
+ do_write();
+ if (open_handler_)
+ open_handler_(*this);
+ do_read();
+ }
+
+ void do_read()
+ {
+ is_reading = true;
+ switch(state_)
+ {
+ case WebSocketReadState::MiniHeader:
+ {
+ //boost::asio::async_read(adaptor_.socket(), boost::asio::buffer(&mini_header_, 1),
+ adaptor_.socket().async_read_some(boost::asio::buffer(&mini_header_, 2),
+ [this](const boost::system::error_code& ec, std::size_t bytes_transferred)
+ {
+ is_reading = false;
+ mini_header_ = htons(mini_header_);
+#ifdef CROW_ENABLE_DEBUG
+
+ if (!ec && bytes_transferred != 2)
+ {
+ throw std::runtime_error("WebSocket:MiniHeader:async_read fail:asio bug?");
+ }
+#endif
+
+ if (!ec && ((mini_header_ & 0x80) == 0x80))
+ {
+ if ((mini_header_ & 0x7f) == 127)
+ {
+ state_ = WebSocketReadState::Len64;
+ }
+ else if ((mini_header_ & 0x7f) == 126)
+ {
+ state_ = WebSocketReadState::Len16;
+ }
+ else
+ {
+ remaining_length_ = mini_header_ & 0x7f;
+ state_ = WebSocketReadState::Mask;
+ }
+ do_read();
+ }
+ else
+ {
+ close_connection_ = true;
+ adaptor_.close();
+ if (error_handler_)
+ error_handler_(*this);
+ check_destroy();
+ }
+ });
+ }
+ break;
+ case WebSocketReadState::Len16:
+ {
+ remaining_length_ = 0;
+ uint16_t remaining_length16_ = 0;
+ boost::asio::async_read(adaptor_.socket(), boost::asio::buffer(&remaining_length16_, 2),
+ [this,&remaining_length16_](const boost::system::error_code& ec, std::size_t bytes_transferred)
+ {
+ is_reading = false;
+ remaining_length16_ = ntohs(remaining_length16_);
+ remaining_length_ = remaining_length16_;
+#ifdef CROW_ENABLE_DEBUG
+ if (!ec && bytes_transferred != 2)
+ {
+ throw std::runtime_error("WebSocket:Len16:async_read fail:asio bug?");
+ }
+#endif
+
+ if (!ec)
+ {
+ state_ = WebSocketReadState::Mask;
+ do_read();
+ }
+ else
+ {
+ close_connection_ = true;
+ adaptor_.close();
+ if (error_handler_)
+ error_handler_(*this);
+ check_destroy();
+ }
+ });
+ }
+ break;
+ case WebSocketReadState::Len64:
+ {
+ boost::asio::async_read(adaptor_.socket(), boost::asio::buffer(&remaining_length_, 8),
+ [this](const boost::system::error_code& ec, std::size_t bytes_transferred)
+ {
+ is_reading = false;
+ remaining_length_ = ((1==ntohl(1)) ? (remaining_length_) : ((uint64_t)ntohl((remaining_length_) & 0xFFFFFFFF) << 32) | ntohl((remaining_length_) >> 32));
+#ifdef CROW_ENABLE_DEBUG
+ if (!ec && bytes_transferred != 8)
+ {
+ throw std::runtime_error("WebSocket:Len16:async_read fail:asio bug?");
+ }
+#endif
+
+ if (!ec)
+ {
+ state_ = WebSocketReadState::Mask;
+ do_read();
+ }
+ else
+ {
+ close_connection_ = true;
+ adaptor_.close();
+ if (error_handler_)
+ error_handler_(*this);
+ check_destroy();
+ }
+ });
+ }
+ break;
+ case WebSocketReadState::Mask:
+ boost::asio::async_read(adaptor_.socket(), boost::asio::buffer((char*)&mask_, 4),
+ [this](const boost::system::error_code& ec, std::size_t bytes_transferred)
+ {
+ is_reading = false;
+#ifdef CROW_ENABLE_DEBUG
+ if (!ec && bytes_transferred != 4)
+ {
+ throw std::runtime_error("WebSocket:Mask:async_read fail:asio bug?");
+ }
+#endif
+
+ if (!ec)
+ {
+ state_ = WebSocketReadState::Payload;
+ do_read();
+ }
+ else
+ {
+ close_connection_ = true;
+ if (error_handler_)
+ error_handler_(*this);
+ adaptor_.close();
+ }
+ });
+ break;
+ case WebSocketReadState::Payload:
+ {
+ size_t to_read = buffer_.size();
+ if (remaining_length_ < to_read)
+ to_read = remaining_length_;
+ adaptor_.socket().async_read_some( boost::asio::buffer(buffer_, to_read),
+ [this](const boost::system::error_code& ec, std::size_t bytes_transferred)
+ {
+ is_reading = false;
+
+ if (!ec)
+ {
+ fragment_.insert(fragment_.end(), buffer_.begin(), buffer_.begin() + bytes_transferred);
+ remaining_length_ -= bytes_transferred;
+ if (remaining_length_ == 0)
+ {
+ handle_fragment();
+ state_ = WebSocketReadState::MiniHeader;
+ do_read();
+ }
+ }
+ else
+ {
+ close_connection_ = true;
+ if (error_handler_)
+ error_handler_(*this);
+ adaptor_.close();
+ }
+ });
+ }
+ break;
+ }
+ }
+
+ bool is_FIN()
+ {
+ return mini_header_ & 0x8000;
+ }
+
+ int opcode()
+ {
+ return (mini_header_ & 0x0f00) >> 8;
+ }
+
+ void handle_fragment()
+ {
+ for(decltype(fragment_.length()) i = 0; i < fragment_.length(); i ++)
+ {
+ fragment_[i] ^= ((char*)&mask_)[i%4];
+ }
+ switch(opcode())
+ {
+ case 0: // Continuation
+ {
+ message_ += fragment_;
+ if (is_FIN())
+ {
+ if (message_handler_)
+ message_handler_(*this, message_, is_binary_);
+ message_.clear();
+ }
+ }
+ case 1: // Text
+ {
+ is_binary_ = false;
+ message_ += fragment_;
+ if (is_FIN())
+ {
+ if (message_handler_)
+ message_handler_(*this, message_, is_binary_);
+ message_.clear();
+ }
+ }
+ break;
+ case 2: // Binary
+ {
+ is_binary_ = true;
+ message_ += fragment_;
+ if (is_FIN())
+ {
+ if (message_handler_)
+ message_handler_(*this, message_, is_binary_);
+ message_.clear();
+ }
+ }
+ break;
+ case 0x8: // Close
+ {
+ has_recv_close_ = true;
+ if (!has_sent_close_)
+ {
+ close(fragment_);
+ }
+ else
+ {
+ adaptor_.close();
+ close_connection_ = true;
+ if (!is_close_handler_called_)
+ {
+ if (close_handler_)
+ close_handler_(*this, fragment_);
+ is_close_handler_called_ = true;
+ }
+ check_destroy();
+ }
+ }
+ break;
+ case 0x9: // Ping
+ {
+ send_pong(fragment_);
+ }
+ break;
+ case 0xA: // Pong
+ {
+ pong_received_ = true;
+ }
+ break;
+ }
+
+ fragment_.clear();
+ }
+
+ void do_write()
+ {
+ if (sending_buffers_.empty())
+ {
+ sending_buffers_.swap(write_buffers_);
+ std::vector<boost::asio::const_buffer> buffers;
+ buffers.reserve(sending_buffers_.size());
+ for(auto& s:sending_buffers_)
+ {
+ buffers.emplace_back(boost::asio::buffer(s));
+ }
+ boost::asio::async_write(adaptor_.socket(), buffers,
+ [&](const boost::system::error_code& ec, std::size_t /*bytes_transferred*/)
+ {
+ sending_buffers_.clear();
+ if (!ec && !close_connection_)
+ {
+ if (!write_buffers_.empty())
+ do_write();
+ if (has_sent_close_)
+ close_connection_ = true;
+ }
+ else
+ {
+ close_connection_ = true;
+ check_destroy();
+ }
+ });
+ }
+ }
+
+ void check_destroy()
+ {
+ //if (has_sent_close_ && has_recv_close_)
+ if (!is_close_handler_called_)
+ if (close_handler_)
+ close_handler_(*this, "uncleanly");
+ if (sending_buffers_.empty() && !is_reading)
+ delete this;
+ }
+ private:
+ Adaptor adaptor_;
+
+ std::vector<std::string> sending_buffers_;
+ std::vector<std::string> write_buffers_;
+
+ boost::array<char, 4096> buffer_;
+ bool is_binary_;
+ std::string message_;
+ std::string fragment_;
+ WebSocketReadState state_{WebSocketReadState::MiniHeader};
+ uint64_t remaining_length_{0};
+ bool close_connection_{false};
+ bool is_reading{false};
+ uint32_t mask_;
+ uint16_t mini_header_;
+ bool has_sent_close_{false};
+ bool has_recv_close_{false};
+ bool error_occured_{false};
+ bool pong_received_{false};
+ bool is_close_handler_called_{false};
+
+ std::function<void(crow::websocket::connection&)> open_handler_;
+ std::function<void(crow::websocket::connection&, const std::string&, bool)> message_handler_;
+ std::function<void(crow::websocket::connection&, const std::string&)> close_handler_;
+ std::function<void(crow::websocket::connection&)> error_handler_;
+ std::function<bool(const crow::request&)> accept_handler_;
+ };
+ }
+}
diff --git a/tests/template/mustachetest.cpp b/tests/template/mustachetest.cpp
index 1caf537..0041889 100644
--- a/tests/template/mustachetest.cpp
+++ b/tests/template/mustachetest.cpp
@@ -2,8 +2,8 @@
#include <fstream>
#include <string>
#include <iterator>
-#include "mustache.h"
-#include "json.h"
+#include "crow/mustache.h"
+#include "crow/json.h"
using namespace std;
using namespace crow;
using namespace crow::mustache;
diff --git a/tests/unittest.cpp b/tests/unittest.cpp
index 164cbf0..a85f7bc 100644
--- a/tests/unittest.cpp
+++ b/tests/unittest.cpp
@@ -3,16 +3,9 @@
#include <iostream>
#include <sstream>
#include <vector>
-#include "settings.h"
+#include "crow.h"
#undef CROW_LOG_LEVEL
#define CROW_LOG_LEVEL 0
-#include "routing.h"
-#include "utility.h"
-#include "crow.h"
-#include "json.h"
-#include "mustache.h"
-#include "middleware.h"
-#include "query_string.h"
using namespace std;
using namespace crow;
@@ -38,7 +31,7 @@ template <typename ...Args>
void fail(Args...args) { error_print(args...);failed__ = true; }
#define ASSERT_TRUE(x) if (!(x)) fail(__FILE__ ":", __LINE__, ": Assert fail: expected ", #x, " is true, at " __FILE__ ":",__LINE__)
-#define ASSERT_EQUAL(a, b) if ((a) != (b)) fail(__FILE__ ":", __LINE__, ": Assert fail: expected ", (a), " actual " , (b), ", " #a " == " #b ", at " __FILE__ ":",__LINE__)
+#define ASSERT_EQUAL(a, b) if ((a) != (b)) fail(__FILE__ ":", __LINE__, ": Assert fail: expected ", (a), " actual ", (b), ", " #a " == " #b ", at " __FILE__ ":",__LINE__)
#define ASSERT_NOTEQUAL(a, b) if ((a) == (b)) fail(__FILE__ ":", __LINE__, ": Assert fail: not expected ", (a), ", " #a " != " #b ", at " __FILE__ ":",__LINE__)
#define ASSERT_THROW(x) \
try \
@@ -323,12 +316,12 @@ TEST(http_method)
CROW_ROUTE(app, "/get_only")
.methods("GET"_method)
- ([](const request& req){
+ ([](const request& /*req*/){
return "get";
});
CROW_ROUTE(app, "/post_only")
.methods("POST"_method)
- ([](const request& req){
+ ([](const request& /*req*/){
return "post";
});
@@ -519,6 +512,10 @@ TEST(json_read)
ASSERT_EQUAL(false, z["bools"][1].b());
ASSERT_EQUAL(1.2, z["doubles"][0].d());
ASSERT_EQUAL(-3.4, z["doubles"][1].d());
+
+ std::string s3 = R"({"uint64": 18446744073709551615})";
+ auto z1 = json::load(s3);
+ ASSERT_EQUAL(18446744073709551615ull, z1["uint64"].u());
}
TEST(json_read_real)
@@ -666,11 +663,11 @@ struct NullMiddleware
struct context {};
template <typename AllContext>
- void before_handle(request& req, response& res, context& ctx, AllContext& all_ctx)
+ void before_handle(request&, response&, context&, AllContext&)
{}
template <typename AllContext>
- void after_handle(request& req, response& res, context& ctx, AllContext& all_ctx)
+ void after_handle(request&, response&, context&, AllContext&)
{}
};
@@ -678,10 +675,10 @@ struct NullSimpleMiddleware
{
struct context {};
- void before_handle(request& req, response& res, context& ctx)
+ void before_handle(request& /*req*/, response& /*res*/, context& /*ctx*/)
{}
- void after_handle(request& req, response& res, context& ctx)
+ void after_handle(request& /*req*/, response& /*res*/, context& /*ctx*/)
{}
};
@@ -703,13 +700,13 @@ struct IntSettingMiddleware
struct context { int val; };
template <typename AllContext>
- void before_handle(request& req, response& res, context& ctx, AllContext& all_ctx)
+ void before_handle(request&, response&, context& ctx, AllContext& )
{
ctx.val = 1;
}
template <typename AllContext>
- void after_handle(request& req, response& res, context& ctx, AllContext& all_ctx)
+ void after_handle(request&, response&, context& ctx, AllContext& )
{
ctx.val = 2;
}
@@ -724,12 +721,12 @@ struct FirstMW
std::vector<string> v;
};
- void before_handle(request& req, response& res, context& ctx)
+ void before_handle(request& /*req*/, response& /*res*/, context& ctx)
{
ctx.v.push_back("1 before");
}
- void after_handle(request& req, response& res, context& ctx)
+ void after_handle(request& /*req*/, response& /*res*/, context& ctx)
{
ctx.v.push_back("1 after");
test_middleware_context_vector = ctx.v;
@@ -740,7 +737,7 @@ struct SecondMW
{
struct context {};
template <typename AllContext>
- void before_handle(request& req, response& res, context& ctx, AllContext& all_ctx)
+ void before_handle(request& req, response& res, context&, AllContext& all_ctx)
{
all_ctx.template get<FirstMW>().v.push_back("2 before");
if (req.url == "/break")
@@ -748,7 +745,7 @@ struct SecondMW
}
template <typename AllContext>
- void after_handle(request& req, response& res, context& ctx, AllContext& all_ctx)
+ void after_handle(request&, response&, context&, AllContext& all_ctx)
{
all_ctx.template get<FirstMW>().v.push_back("2 after");
}
@@ -758,13 +755,13 @@ struct ThirdMW
{
struct context {};
template <typename AllContext>
- void before_handle(request& req, response& res, context& ctx, AllContext& all_ctx)
+ void before_handle(request&, response&, context&, AllContext& all_ctx)
{
all_ctx.template get<FirstMW>().v.push_back("3 before");
}
template <typename AllContext>
- void after_handle(request& req, response& res, context& ctx, AllContext& all_ctx)
+ void after_handle(request&, response&, context&, AllContext& all_ctx)
{
all_ctx.template get<FirstMW>().v.push_back("3 after");
}
@@ -1070,12 +1067,12 @@ TEST(route_dynamic)
});
app.route_dynamic("/set4")
- ([&](const request& req){
+ ([&](const request&){
x = 4;
return "";
});
app.route_dynamic("/set5")
- ([&](const request& req, response& res){
+ ([&](const request&, response& res){
x = 5;
res.end();
});