Merge pull request #457 from CrowCpp/ls-boostless

Deboostify Crow
This commit is contained in:
Farook Al-Sammarraie 2022-06-18 17:23:58 +03:00 committed by GitHub
commit ee0e0254d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 417 additions and 279 deletions

View File

@ -25,7 +25,7 @@ steps:
- export TRAVIS_JOB_ID=$DRONE_BUILD_NUMBER
- export COVERALLS_PULL_REQUEST=$DRONE_PULL_REQUEST
- apt-get -y update
- apt-get -y install libboost-all-dev doxygen mkdocs graphviz zlib1g-dev gcc clang clang-format make cmake python3 python3-pip git openssl libssl-dev jq wget curl
- apt-get -y install libasio-dev doxygen mkdocs graphviz zlib1g-dev gcc clang clang-format make cmake python3 python3-pip git openssl libssl-dev jq wget curl
- git clone https://github.com/CrowCpp/cpp-coveralls.git
- cd cpp-coveralls
- pip3 install . --no-input
@ -73,7 +73,7 @@ steps:
commands:
- export DEBIAN_FRONTEND=noninteractive
- apt-get -y update
- apt-get -y install libboost-all-dev zlib1g-dev gcc clang make cmake python3 openssl libssl-dev
- apt-get -y install libasio-dev zlib1g-dev gcc clang make cmake python3 openssl libssl-dev
- mkdir build
- cd build
- cmake --version
@ -123,7 +123,7 @@ steps:
- export TRAVIS_BRANCH=$DRONE_REPO_BRANCH
- export TRAVIS_JOB_ID=$DRONE_BUILD_NUMBER
- apt-get -y update
- apt-get -y install libboost-all-dev doxygen mkdocs graphviz zlib1g-dev gcc clang make cmake python3 python3-pip git openssl libssl-dev
- apt-get -y install libasio-dev doxygen mkdocs graphviz zlib1g-dev gcc clang make cmake python3 python3-pip git openssl libssl-dev
- pip3 install mkdocs-material mkdocs-redirects pyyaml mkdocs-meta-descriptions-plugin --no-input
- git clone https://github.com/CrowCpp/cpp-coveralls.git
- cd cpp-coveralls
@ -170,7 +170,7 @@ steps:
commands:
- export DEBIAN_FRONTEND=noninteractive
- apt-get -y update
- apt-get -y install libboost-all-dev zlib1g-dev gcc clang make cmake python3 openssl libssl-dev
- apt-get -y install libasio-dev zlib1g-dev gcc clang make cmake python3 openssl libssl-dev
- mkdir build
- cd build
- cmake --version

View File

@ -28,7 +28,7 @@ env:
addons:
apt:
packages:
- libboost-all-dev
- libasio-dev
- doxygen
- mkdocs
- graphviz

View File

@ -52,14 +52,17 @@ target_include_directories(Crow
$<INSTALL_INTERFACE:include>
)
find_package(Boost 1.64 COMPONENTS system date_time REQUIRED)
find_path(ASIO_INCLUDE_DIR asio.hpp REQUIRED)
find_package(Threads REQUIRED)
target_link_libraries(Crow
INTERFACE
Boost::boost Boost::system Boost::date_time
Threads::Threads
)
target_include_directories(Crow
INTERFACE
${ASIO_INCLUDE_DIR}
)
if("compression" IN_LIST CROW_FEATURES)
find_package(ZLIB REQUIRED)

View File

@ -1,7 +1,7 @@
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
find_dependency(Boost 1.64 COMPONENTS system date_time)
find_path(ASIO_INCLUDE_DIR asio.hpp REQUIRED)
find_dependency(Threads)
set(CROW_INSTALLED_FEATURES "@CROW_FEATURES@")
@ -41,3 +41,8 @@ set_target_properties(Crow::Crow PROPERTIES
INTERFACE_COMPILE_DEFINITIONS "${_CROW_ICD}"
INTERFACE_LINK_LIBRARIES "${_CROW_ILL}"
)
target_include_directories(Crow::Crow
INTERFACE
${ASIO_INCLUDE_DIR}
)

View File

@ -3,7 +3,7 @@ Here's how you can install Crow on your favorite GNU/Linux distro.
### Requirements
- C++ compiler with at least C++11 support.
- boost library & development headers (1.64 or later).
- Asio development headers (1.10.9 or later).
- **(optional)** ZLib for HTTP Compression.
- **(optional)** OpenSSL for HTTPS support.
- **(optional)** CMake for building tests, examples, and/or installing Crow.
@ -91,6 +91,3 @@ All you need to do is run the following command:
g++ main.cpp -lpthread
```
You can use arguments like `-DCROW_ENABLE_DEBUG`, `-DCROW_ENABLE_COMPRESSION -lz` for HTTP Compression, or `-DCROW_ENABLE_SSL -lssl` for HTTPS support, or even replace g++ with clang++.
!!! warning
If you're using a version of boost prior to 1.69, you'll need to add the argument `-lboost_system` in order for you Crow application to compile correctly.

View File

@ -24,20 +24,20 @@ This will generate a `crow_all.h` file which you can use in the following steps
## Setting up your Crow project
### Using XCode
1. Download and install [Homebrew](https://brew.sh).
2. Run `brew install boost` in your terminal.
2. Run `brew install asio` in your terminal.
3. Create a new XCode project (macOS -> Command Line Tool).
4. Change the following project settings:
=== "Multiple Headers"
1. Add header search paths for crow's include folder and boost's folder (`/usr/local/include`, `/usr/local/Cellar/boost/include`, and where you placed Crow's `include` folder)
2. Add linker flags (`-lpthread` and `-lboost_system` if you're running an old version of boost)
1. Add header search paths for crow's include folder and asio's folder (`/usr/local/include`, `/usr/local/Cellar/asio/include`, and where you placed Crow's `include` folder)
2. Add linker flags (`-lpthread`)
=== "Single Header"
1. Place `crow_all.h` inside your project folder and add it to the project in XCode (you need to use File -> Add files to "project_name")
2. Add header search paths for boost's folder (`/usr/local/include`, and `/usr/local/Cellar/boost/include`)
3. Add linker flags (`-lpthread` and `-lboost_system` if you're running an old version of boost)
2. Add header search paths for asio's folder (`/usr/local/include`, and `/usr/local/Cellar/asio/include`)
3. Add linker flags (`-lpthread`)
5. Write your Crow application in `main.cpp` (something like the Hello World example will work).
6. Press `▶` to compile and run your Crow application.
@ -49,7 +49,7 @@ This will generate a `crow_all.h` file which you can use in the following steps
This tutorial can be used for Crow projects built with CMake as well
1. Download and install [Homebrew](https://brew.sh).
2. Run `brew install cmake boost` in your terminal.
2. Run `brew install cmake asio` in your terminal.
3. Get Crow's source code (the entire source code).
3. Run the following Commands:
1. `mkdir build`
@ -70,6 +70,3 @@ g++ main.cpp -lpthread
You'll need to install GCC via `brew install gcc`. the Clang compiler should be part of XCode or XCode command line tools.
You can use arguments like `-DCROW_ENABLE_DEBUG`, `-DCROW_ENABLE_COMPRESSION -lz` for HTTP Compression, or `-DCROW_ENABLE_SSL -lssl` for HTTPS support, or even replace g++ with clang++.
!!! warning
If you're using a version of boost prior to 1.69, you'll need to add the argument `-lboost_system` in order for you Crow application to compile correctly.

View File

@ -10,8 +10,8 @@ To enable SSL, first your application needs to define either a `.crt` and `.key`
You also need to define `CROW_ENABLE_SSL` in your compiler definitions (`g++ main.cpp -DCROW_ENABLE_SSL` for example) or `set(CROW_FEATURES ssl)` in `CMakeLists.txt`.
You can also set your own SSL context (by using `boost::asio::ssl::context ctx`) and then applying it via the `#!cpp app.ssl(ctx)` method.<br><br>
You can also set your own SSL context (by using `asio::ssl::context ctx`) and then applying it via the `#!cpp app.ssl(ctx)` method.<br><br>
!!! warning
If you plan on using a proxy like Nginx or Apache2, **DO NOT** use SSL in crow, instead define it in your proxy and keep the connection between the proxy and Crow non-SSL.

View File

@ -1,7 +1,5 @@
#include "crow.h"
#include <sstream>
class ExampleLogHandler : public crow::ILogHandler
{
public:
@ -179,7 +177,7 @@ int main()
// To see in action submit something like '/params?pew=42'
if (req.url_params.get("pew") != nullptr)
{
double countD = boost::lexical_cast<double>(req.url_params.get("pew"));
double countD = crow::utility::lexical_cast<double>(req.url_params.get("pew"));
os << "The value of 'pew' is " << countD << '\n';
}

View File

@ -1,7 +1,5 @@
#include "crow.h"
#include <sstream>
class ExampleLogHandler : public crow::ILogHandler
{
public:
@ -110,7 +108,7 @@ int main()
os << "The key 'foo' was " << (req.url_params.get("foo") == nullptr ? "not " : "") << "found.\n";
if (req.url_params.get("pew") != nullptr)
{
double countD = boost::lexical_cast<double>(req.url_params.get("pew"));
double countD = crow::utility::lexical_cast<double>(req.url_params.get("pew"));
os << "The value of 'pew' is " << countD << '\n';
}
auto count = req.url_params.get_list("count");

View File

@ -1,7 +1,5 @@
#include "crow_all.h"
#include <sstream>
class ExampleLogHandler : public crow::ILogHandler
{
public:
@ -100,7 +98,7 @@ int main()
os << "The key 'foo' was " << (req.url_params.get("foo") == nullptr ? "not " : "") << "found.\n";
if (req.url_params.get("pew") != nullptr)
{
double countD = boost::lexical_cast<double>(req.url_params.get("pew"));
double countD = crow::utility::lexical_cast<double>(req.url_params.get("pew"));
os << "The value of 'pew' is " << countD << '\n';
}
auto count = req.url_params.get_list("count");

View File

@ -14,7 +14,7 @@ int main()
// Use .pem file
//app.port(18080).ssl_file("test.pem").run();
// Use custom context; see boost::asio::ssl::context
// Use custom context; see asio::ssl::context
/*
* crow::ssl_context_t ctx;
* ctx.set_verify_mode(...)

View File

@ -39,7 +39,7 @@
namespace crow
{
#ifdef CROW_ENABLE_SSL
using ssl_context_t = boost::asio::ssl::context;
using ssl_context_t = asio::ssl::context;
#endif
/// The main server application
@ -379,12 +379,12 @@ namespace crow
self_t& ssl_file(const std::string& crt_filename, const std::string& key_filename)
{
ssl_used_ = true;
ssl_context_.set_verify_mode(boost::asio::ssl::verify_peer);
ssl_context_.set_verify_mode(boost::asio::ssl::verify_client_once);
ssl_context_.set_verify_mode(asio::ssl::verify_peer);
ssl_context_.set_verify_mode(asio::ssl::verify_client_once);
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);
asio::ssl::context::default_workarounds | asio::ssl::context::no_sslv2 | asio::ssl::context::no_sslv3);
return *this;
}
@ -392,11 +392,11 @@ namespace crow
self_t& ssl_file(const std::string& pem_filename)
{
ssl_used_ = true;
ssl_context_.set_verify_mode(boost::asio::ssl::verify_peer);
ssl_context_.set_verify_mode(boost::asio::ssl::verify_client_once);
ssl_context_.set_verify_mode(asio::ssl::verify_peer);
ssl_context_.set_verify_mode(asio::ssl::verify_client_once);
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);
asio::ssl::context::default_workarounds | asio::ssl::context::no_sslv2 | asio::ssl::context::no_sslv3);
return *this;
}
@ -404,16 +404,16 @@ namespace crow
self_t& ssl_chainfile(const std::string& crt_filename, const std::string& key_filename)
{
ssl_used_ = true;
ssl_context_.set_verify_mode(boost::asio::ssl::verify_peer);
ssl_context_.set_verify_mode(boost::asio::ssl::verify_client_once);
ssl_context_.set_verify_mode(asio::ssl::verify_peer);
ssl_context_.set_verify_mode(asio::ssl::verify_client_once);
ssl_context_.use_certificate_chain_file(crt_filename);
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);
asio::ssl::context::default_workarounds | asio::ssl::context::no_sslv2 | asio::ssl::context::no_sslv3);
return *this;
}
self_t& ssl(boost::asio::ssl::context&& ctx)
self_t& ssl(asio::ssl::context&& ctx)
{
ssl_used_ = true;
ssl_context_ = std::move(ctx);
@ -540,7 +540,7 @@ namespace crow
#ifdef CROW_ENABLE_SSL
std::unique_ptr<ssl_server_t> ssl_server_;
bool ssl_used_{false};
ssl_context_t ssl_context_{boost::asio::ssl::context::sslv23};
ssl_context_t ssl_context_{asio::ssl::context::sslv23};
#endif
std::unique_ptr<server_t> server_;

View File

@ -1,8 +1,8 @@
#pragma once
#include <boost/algorithm/string/predicate.hpp>
#include <boost/functional/hash.hpp>
#include <locale>
#include <unordered_map>
#include "crow/utility.h"
namespace crow
{
@ -15,12 +15,17 @@ namespace crow
std::locale locale;
for (auto c : key)
{
boost::hash_combine(seed, std::toupper(c, locale));
}
hash_combine(seed, std::toupper(c, locale));
return seed;
}
private:
static inline void hash_combine(std::size_t& seed, char v)
{
std::hash<char> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
};
/// Equals function for ci_map (unordered_multimap).
@ -28,7 +33,7 @@ namespace crow
{
bool operator()(const std::string& l, const std::string& r) const
{
return boost::iequals(l, r);
return utility::string_equals(l, r);
}
};

View File

@ -1,8 +1,6 @@
#pragma once
#include <boost/asio.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/array.hpp>
#define ASIO_STANDALONE
#include <asio.hpp>
#include <atomic>
#include <chrono>
#include <vector>
@ -18,10 +16,10 @@
#include "crow/middleware.h"
#include "crow/socket_adaptors.h"
#include "crow/compression.h"
#include "crow/utility.h"
namespace crow
{
using namespace boost;
using tcp = asio::ip::tcp;
@ -37,7 +35,7 @@ namespace crow
public:
Connection(
boost::asio::io_service& io_service,
asio::io_service& io_service,
Handler* handler,
const std::string& server_name,
std::tuple<Middlewares...>* middlewares,
@ -79,7 +77,7 @@ namespace crow
void start()
{
adaptor_.start([this](const boost::system::error_code& ec) {
adaptor_.start([this](const asio::error_code& ec) {
if (!ec)
{
start_deadline();
@ -144,7 +142,7 @@ namespace crow
}
}
CROW_LOG_INFO << "Request: " << boost::lexical_cast<std::string>(adaptor_.remote_endpoint()) << " " << this << " HTTP/" << (char)(req.http_ver_major + '0') << "." << (char)(req.http_ver_minor + '0') << ' ' << method_name(req.method) << " " << req.url;
CROW_LOG_INFO << "Request: " << utility::lexical_cast<std::string>(adaptor_.remote_endpoint()) << " " << this << " HTTP/" << (char)(req.http_ver_major + '0') << "." << (char)(req.http_ver_minor + '0') << ' ' << method_name(req.method) << " " << req.url;
need_to_call_after_handlers_ = false;
@ -374,7 +372,7 @@ namespace crow
void do_write_static()
{
is_writing = true;
boost::asio::write(adaptor_.socket(), buffers_);
asio::write(adaptor_.socket(), buffers_);
if (res.file_info.statResult == 0)
{
@ -383,7 +381,7 @@ namespace crow
while (is.read(buf, sizeof(buf)).gcount() > 0)
{
std::vector<asio::const_buffer> buffers;
buffers.push_back(boost::asio::buffer(buf));
buffers.push_back(asio::buffer(buf));
do_write_sync(buffers);
}
}
@ -420,7 +418,7 @@ namespace crow
else
{
is_writing = true;
boost::asio::write(adaptor_.socket(), buffers_); // Write the response start / headers
asio::write(adaptor_.socket(), buffers_); // Write the response start / headers
cancel_deadline_timer();
if (res.body.length() > 0)
{
@ -433,7 +431,7 @@ namespace crow
buf = res.body.substr(0, 16384);
res.body = res.body.substr(16384);
buffers.clear();
buffers.push_back(boost::asio::buffer(buf));
buffers.push_back(asio::buffer(buf));
do_write_sync(buffers);
}
// Collect whatever is left (less than 16KB) and send it down the socket
@ -442,7 +440,7 @@ namespace crow
res.body.clear();
buffers.clear();
buffers.push_back(boost::asio::buffer(buf));
buffers.push_back(asio::buffer(buf));
do_write_sync(buffers);
}
is_writing = false;
@ -465,8 +463,8 @@ namespace crow
//auto self = this->shared_from_this();
is_reading = true;
adaptor_.socket().async_read_some(
boost::asio::buffer(buffer_),
[this](const boost::system::error_code& ec, std::size_t bytes_transferred) {
asio::buffer(buffer_),
[this](const asio::error_code& ec, std::size_t bytes_transferred) {
bool error_while_reading = true;
if (!ec)
{
@ -512,9 +510,9 @@ namespace crow
{
//auto self = this->shared_from_this();
is_writing = true;
boost::asio::async_write(
asio::async_write(
adaptor_.socket(), buffers_,
[&](const boost::system::error_code& ec, std::size_t /*bytes_transferred*/) {
[&](const asio::error_code& ec, std::size_t /*bytes_transferred*/) {
is_writing = false;
res.clear();
res_body_copy_.clear();
@ -539,7 +537,7 @@ namespace crow
inline void do_write_sync(std::vector<asio::const_buffer>& buffers)
{
boost::asio::write(adaptor_.socket(), buffers, [&](std::error_code ec, std::size_t) {
asio::write(adaptor_.socket(), buffers, [&](asio::error_code ec, std::size_t) {
if (!ec)
{
return false;
@ -590,7 +588,7 @@ namespace crow
Adaptor adaptor_;
Handler* handler_;
boost::array<char, 4096> buffer_;
std::array<char, 4096> buffer_;
HTTPParser<Connection> parser_;
request req_;
@ -599,7 +597,7 @@ namespace crow
bool close_connection_ = false;
const std::string& server_name_;
std::vector<boost::asio::const_buffer> buffers_;
std::vector<asio::const_buffer> buffers_;
std::string content_length_;
std::string date_str_;

View File

@ -1,6 +1,7 @@
#pragma once
#include <boost/asio.hpp>
#define ASIO_STANDALONE
#include <asio.hpp>
#include "crow/common.h"
#include "crow/ci_map.h"
@ -35,7 +36,7 @@ namespace crow
void* middleware_context{};
void* middleware_container{};
boost::asio::io_service* io_service{};
asio::io_service* io_service{};
/// Construct an empty request. (sets the method to `GET`)
request():

View File

@ -1,10 +1,10 @@
#pragma once
#include <chrono>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/asio.hpp>
#define ASIO_STANDALONE
#include <asio.hpp>
#ifdef CROW_ENABLE_SSL
#include <boost/asio/ssl.hpp>
#include <asio/ssl.hpp>
#endif
#include <cstdint>
#include <atomic>
@ -19,7 +19,6 @@
namespace crow
{
using namespace boost;
using tcp = asio::ip::tcp;
template<typename Handler, typename Adaptor = SocketAdaptor, typename... Middlewares>
@ -27,7 +26,7 @@ namespace crow
{
public:
Server(Handler* handler, std::string bindaddr, uint16_t port, std::string server_name = std::string("Crow/") + VERSION, std::tuple<Middlewares...>* middlewares = nullptr, uint16_t concurrency = 1, uint8_t timeout = 5, typename Adaptor::context* adaptor_ctx = nullptr):
acceptor_(io_service_, tcp::endpoint(boost::asio::ip::address::from_string(bindaddr), port)),
acceptor_(io_service_, tcp::endpoint(asio::ip::address::from_string(bindaddr), port)),
signals_(io_service_),
tick_timer_(io_service_),
handler_(handler),
@ -50,8 +49,8 @@ namespace crow
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) {
tick_timer_.expires_after(std::chrono::milliseconds(tick_interval_.count()));
tick_timer_.async_wait([this](const asio::error_code& ec) {
if (ec)
return;
on_tick();
@ -62,7 +61,7 @@ namespace crow
{
uint16_t worker_thread_count = concurrency_ - 1;
for (int i = 0; i < worker_thread_count; i++)
io_service_pool_.emplace_back(new boost::asio::io_service());
io_service_pool_.emplace_back(new asio::io_service());
get_cached_date_str_pool_.resize(worker_thread_count);
task_timer_pool_.resize(worker_thread_count);
@ -125,9 +124,9 @@ namespace crow
if (tick_function_ && tick_interval_.count() > 0)
{
tick_timer_.expires_from_now(boost::posix_time::milliseconds(tick_interval_.count()));
tick_timer_.expires_after(std::chrono::milliseconds(tick_interval_.count()));
tick_timer_.async_wait(
[this](const boost::system::error_code& ec) {
[this](const asio::error_code& ec) {
if (ec)
return;
on_tick();
@ -142,7 +141,7 @@ namespace crow
CROW_LOG_INFO << "Call `app.loglevel(crow::LogLevel::Warning)` to hide Info level logs.";
signals_.async_wait(
[&](const boost::system::error_code& /*error*/, int /*signal_number*/) {
[&](const asio::error_code& /*error*/, int /*signal_number*/) {
stop();
});
@ -226,7 +225,7 @@ namespace crow
acceptor_.async_accept(
p->socket(),
[this, p, &is, service_idx](boost::system::error_code ec) {
[this, p, &is, service_idx](asio::error_code ec) {
if (!ec)
{
is.post(
@ -263,8 +262,9 @@ namespace crow
bool server_started_{false};
std::condition_variable cv_started_;
std::mutex start_mutex_;
boost::asio::signal_set signals_;
boost::asio::deadline_timer tick_timer_;
asio::signal_set signals_;
asio::basic_waitable_timer<std::chrono::high_resolution_clock> tick_timer_;
Handler* handler_;
uint16_t concurrency_{2};

View File

@ -12,9 +12,6 @@
#include <iostream>
#include <algorithm>
#include <memory>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/operators.hpp>
#include <vector>
#include <cmath>
@ -117,7 +114,7 @@ namespace crow
namespace detail
{
/// A read string implementation with comparison functionality.
struct r_string : boost::less_than_comparable<r_string>, boost::less_than_comparable<r_string, std::string>, boost::equality_comparable<r_string>, boost::equality_comparable<r_string, std::string>
struct r_string
{
r_string(){};
r_string(char* s, char* e):
@ -186,31 +183,85 @@ namespace crow
owned_ = 1;
}
friend rvalue crow::json::load(const char* data, size_t size);
friend bool operator==(const r_string& l, const r_string& r);
friend bool operator==(const std::string& l, const r_string& r);
friend bool operator==(const r_string& l, const std::string& r);
template<typename T, typename U>
inline static bool equals(const T& l, const U& r)
{
if (l.size() != r.size())
return false;
for (size_t i = 0; i < l.size(); i++)
{
if (*(l.begin() + i) != *(r.begin() + i))
return false;
}
return true;
}
};
inline bool operator<(const r_string& l, const r_string& r)
{
return boost::lexicographical_compare(l, r);
return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
}
inline bool operator<(const r_string& l, const std::string& r)
{
return boost::lexicographical_compare(l, r);
return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
}
inline bool operator<(const std::string& l, const r_string& r)
{
return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
}
inline bool operator>(const r_string& l, const r_string& r)
{
return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
}
inline bool operator>(const r_string& l, const std::string& r)
{
return boost::lexicographical_compare(r, l);
return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
}
inline bool operator>(const std::string& l, const r_string& r)
{
return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
}
inline bool operator==(const r_string& l, const r_string& r)
{
return boost::equals(l, r);
return r_string::equals(l, r);
}
inline bool operator==(const r_string& l, const std::string& r)
{
return boost::equals(l, r);
return r_string::equals(l, r);
}
inline bool operator==(const std::string& l, const r_string& r)
{
return r_string::equals(l, r);
}
inline bool operator!=(const r_string& l, const r_string& r)
{
return !(l == r);
}
inline bool operator!=(const r_string& l, const std::string& r)
{
return !(l == r);
}
inline bool operator!=(const std::string& l, const r_string& r)
{
return !(l == r);
}
} // namespace detail
@ -349,13 +400,13 @@ namespace crow
{
case type::Number:
case type::String:
return boost::lexical_cast<int64_t>(start_, end_ - start_);
return utility::lexical_cast<int64_t>(start_, end_ - start_);
default:
const std::string msg = "expected number, got: " + std::string(get_type_str(t()));
throw std::runtime_error(msg);
}
#endif
return boost::lexical_cast<int64_t>(start_, end_ - start_);
return utility::lexical_cast<int64_t>(start_, end_ - start_);
}
/// The unsigned integer value.
@ -366,12 +417,12 @@ namespace crow
{
case type::Number:
case type::String:
return boost::lexical_cast<uint64_t>(start_, end_ - start_);
return utility::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_);
return utility::lexical_cast<uint64_t>(start_, end_ - start_);
}
/// The double precision floating-point number value.
@ -381,7 +432,7 @@ namespace crow
if (t() != type::Number)
throw std::runtime_error("value is not number");
#endif
return boost::lexical_cast<double>(start_, end_ - start_);
return utility::lexical_cast<double>(start_, end_ - start_);
}
/// The boolean value.
@ -968,8 +1019,8 @@ namespace crow
{
state = NumberParsingState::ZeroFirst;
}
else if (state == NumberParsingState::Digits ||
state == NumberParsingState::DigitsAfterE ||
else if (state == NumberParsingState::Digits ||
state == NumberParsingState::DigitsAfterE ||
state == NumberParsingState::DigitsAfterPoints)
{
// ok; pass
@ -997,8 +1048,8 @@ namespace crow
{
state = NumberParsingState::Digits;
}
else if (state == NumberParsingState::Digits ||
state == NumberParsingState::DigitsAfterE ||
else if (state == NumberParsingState::Digits ||
state == NumberParsingState::DigitsAfterE ||
state == NumberParsingState::DigitsAfterPoints)
{
// ok; pass
@ -1046,12 +1097,12 @@ namespace crow
case 'e':
case 'E':
state = static_cast<NumberParsingState>("\7\7\7\5\5\7\7"[state]);
/*if (state == NumberParsingState::Digits ||
/*if (state == NumberParsingState::Digits ||
state == NumberParsingState::DigitsAfterPoints)
{
state = NumberParsingState::E;
}
else
else
return {};*/
break;
default:
@ -1898,7 +1949,7 @@ namespace crow
//std::vector<boost::asio::const_buffer> dump_ref(wvalue& v)
//std::vector<asio::const_buffer> dump_ref(wvalue& v)
//{
//}
} // namespace json

View File

@ -1,7 +1,7 @@
#pragma once
#include <iomanip>
#include <boost/optional.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <memory>
#include "crow/utility.h"
#include "crow/http_request.h"
#include "crow/http_response.h"
@ -65,7 +65,7 @@ namespace crow
if (expires_at_)
{
ss << DIVIDER << "Expires="
<< std::put_time(expires_at_.get_ptr(), HTTP_DATE_FORMAT);
<< std::put_time(expires_at_.get(), HTTP_DATE_FORMAT);
}
if (max_age_)
{
@ -93,14 +93,14 @@ namespace crow
// Expires attribute
Cookie& expires(const std::tm& time)
{
expires_at_ = time;
expires_at_ = std::unique_ptr<std::tm>(new std::tm(time));
return *this;
}
// Max-Age attribute
Cookie& max_age(long long seconds)
{
max_age_ = seconds;
max_age_ = std::unique_ptr<long long>(new long long(seconds));
return *this;
}
@ -135,10 +135,28 @@ namespace crow
// SameSite attribute
Cookie& same_site(SameSitePolicy ssp)
{
same_site_ = ssp;
same_site_ = std::unique_ptr<SameSitePolicy>(new SameSitePolicy(ssp));
return *this;
}
Cookie(const Cookie& c):
key_(c.key_),
value_(c.value_),
domain_(c.domain_),
path_(c.path_),
secure_(c.secure_),
httponly_(c.httponly_)
{
if (c.max_age_)
max_age_ = std::unique_ptr<long long>(new long long(*c.max_age_));
if (c.expires_at_)
expires_at_ = std::unique_ptr<std::tm>(new std::tm(*c.expires_at_));
if (c.same_site_)
same_site_ = std::unique_ptr<SameSitePolicy>(new SameSitePolicy(*c.same_site_));
}
private:
Cookie() = default;
@ -154,13 +172,13 @@ namespace crow
private:
std::string key_;
std::string value_;
boost::optional<long long> max_age_{};
std::unique_ptr<long long> max_age_{};
std::string domain_ = "";
std::string path_ = "";
bool secure_ = false;
bool httponly_ = false;
boost::optional<std::tm> expires_at_{};
boost::optional<SameSitePolicy> same_site_{};
std::unique_ptr<std::tm> expires_at_{};
std::unique_ptr<SameSitePolicy> same_site_{};
static constexpr const char* DIVIDER = "; ";
};
@ -207,17 +225,15 @@ namespace crow
if (pos_equal == cookies.npos)
break;
std::string name = cookies.substr(pos, pos_equal - pos);
boost::trim(name);
name = utility::trim(name);
pos = pos_equal + 1;
while (pos < cookies.size() && cookies[pos] == ' ')
pos++;
if (pos == cookies.size())
break;
size_t pos_semicolon = cookies.find(';', pos);
std::string value = cookies.substr(pos, pos_semicolon - pos);
boost::trim(value);
value = utility::trim(value);
if (value[0] == '"' && value[value.size() - 1] == '"')
{
value = value.substr(1, value.size() - 2);
@ -229,8 +245,6 @@ namespace crow
if (pos == cookies.npos)
break;
pos++;
while (pos < cookies.size() && cookies[pos] == ' ')
pos++;
}
}
@ -258,7 +272,7 @@ namespace crow
C::handle
context.aaa
App::context : private CookieParser::contetx, ...
App::context : private CookieParser::contetx, ...
{
jar

View File

@ -258,7 +258,7 @@ namespace crow
}
break;
default:
throw std::runtime_error("not implemented tag type" + boost::lexical_cast<std::string>(static_cast<int>(ctx.t())));
throw std::runtime_error("not implemented tag type" + utility::lexical_cast<std::string>(static_cast<int>(ctx.t())));
}
}
break;
@ -324,7 +324,7 @@ namespace crow
current = action.pos;
break;
default:
throw std::runtime_error("{{#: not implemented context type: " + boost::lexical_cast<std::string>(static_cast<int>(ctx.t())));
throw std::runtime_error("{{#: not implemented context type: " + utility::lexical_cast<std::string>(static_cast<int>(ctx.t())));
break;
}
break;
@ -333,7 +333,7 @@ namespace crow
stack.pop_back();
break;
default:
throw std::runtime_error("not implemented " + boost::lexical_cast<std::string>(static_cast<int>(action.t)));
throw std::runtime_error("not implemented " + utility::lexical_cast<std::string>(static_cast<int>(action.t)));
}
current++;
}

View File

@ -2,7 +2,6 @@
#include <string>
#include <unordered_map>
#include <boost/algorithm/string.hpp>
#include <algorithm>
#include "crow/http_parser_merged.h"

View File

@ -6,7 +6,7 @@
#include <vector>
#include <unordered_map>
#include <iostream>
#include <boost/optional.hpp>
#include <memory>
namespace crow
{
@ -194,7 +194,7 @@ inline char * qs_k2v(const char * key, char * const * qs_kv, int qs_kv_size, int
// return (zero-char value) ? ptr to trailing '\0' : ptr to value
if(nth == 0)
return qs_kv[i] + skip;
else
else
--nth;
}
}
@ -203,7 +203,7 @@ inline char * qs_k2v(const char * key, char * const * qs_kv, int qs_kv_size, int
return nullptr;
}
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)
inline std::unique_ptr<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;
@ -232,7 +232,7 @@ inline boost::optional<std::pair<std::string, std::string>> qs_dict_name2kv(cons
{
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));
return std::unique_ptr<std::pair<std::string, std::string>>(new std::pair<std::string, std::string>(key, value));
}
else
{
@ -242,7 +242,7 @@ inline boost::optional<std::pair<std::string, std::string>> qs_dict_name2kv(cons
}
#endif // _qsSORTING
return boost::none;
return nullptr;
}

View File

@ -5,7 +5,6 @@
#include <tuple>
#include <unordered_map>
#include <memory>
#include <boost/lexical_cast.hpp>
#include <vector>
#include <algorithm>
#include <type_traits>

View File

@ -1,28 +1,29 @@
#pragma once
#include <boost/asio.hpp>
#define ASIO_STANDALONE
#include <asio.hpp>
#ifdef CROW_ENABLE_SSL
#include <boost/asio/ssl.hpp>
#include <asio/ssl.hpp>
#endif
#include "crow/settings.h"
#if BOOST_VERSION >= 107000
#define GET_IO_SERVICE(s) ((boost::asio::io_context&)(s).get_executor().context())
#include <asio/version.hpp>
#if ASIO_VERSION >= 101300 // 1.13.0
#define GET_IO_SERVICE(s) ((asio::io_context&)(s).get_executor().context())
#else
#define GET_IO_SERVICE(s) ((s).get_io_service())
#endif
namespace crow
{
using namespace boost;
using tcp = asio::ip::tcp;
/// A wrapper for the asio::ip::tcp::socket and asio::ssl::stream
struct SocketAdaptor
{
using context = void;
SocketAdaptor(boost::asio::io_service& io_service, context*):
SocketAdaptor(asio::io_service& io_service, context*):
socket_(io_service)
{}
boost::asio::io_service& get_io_service()
asio::io_service& get_io_service()
{
return GET_IO_SERVICE(socket_);
}
@ -51,32 +52,32 @@ namespace crow
void close()
{
boost::system::error_code ec;
asio::error_code ec;
socket_.close(ec);
}
void shutdown_readwrite()
{
boost::system::error_code ec;
socket_.shutdown(boost::asio::socket_base::shutdown_type::shutdown_both, ec);
asio::error_code ec;
socket_.shutdown(asio::socket_base::shutdown_type::shutdown_both, ec);
}
void shutdown_write()
{
boost::system::error_code ec;
socket_.shutdown(boost::asio::socket_base::shutdown_type::shutdown_send, ec);
asio::error_code ec;
socket_.shutdown(asio::socket_base::shutdown_type::shutdown_send, ec);
}
void shutdown_read()
{
boost::system::error_code ec;
socket_.shutdown(boost::asio::socket_base::shutdown_type::shutdown_receive, ec);
asio::error_code ec;
socket_.shutdown(asio::socket_base::shutdown_type::shutdown_receive, ec);
}
template<typename F>
void start(F f)
{
f(boost::system::error_code());
f(asio::error_code());
}
tcp::socket socket_;
@ -85,13 +86,13 @@ namespace crow
#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):
using context = asio::ssl::context;
using ssl_socket_t = asio::ssl::stream<tcp::socket>;
SSLAdaptor(asio::io_service& io_service, context* ctx):
ssl_socket_(new ssl_socket_t(io_service, *ctx))
{}
boost::asio::ssl::stream<tcp::socket>& socket()
asio::ssl::stream<tcp::socket>& socket()
{
return *ssl_socket_;
}
@ -116,7 +117,7 @@ namespace crow
{
if (is_open())
{
boost::system::error_code ec;
asio::error_code ec;
raw_socket().close(ec);
}
}
@ -125,8 +126,8 @@ namespace crow
{
if (is_open())
{
boost::system::error_code ec;
raw_socket().shutdown(boost::asio::socket_base::shutdown_type::shutdown_both, ec);
asio::error_code ec;
raw_socket().shutdown(asio::socket_base::shutdown_type::shutdown_both, ec);
}
}
@ -134,8 +135,8 @@ namespace crow
{
if (is_open())
{
boost::system::error_code ec;
raw_socket().shutdown(boost::asio::socket_base::shutdown_type::shutdown_send, ec);
asio::error_code ec;
raw_socket().shutdown(asio::socket_base::shutdown_type::shutdown_send, ec);
}
}
@ -143,12 +144,12 @@ namespace crow
{
if (is_open())
{
boost::system::error_code ec;
raw_socket().shutdown(boost::asio::socket_base::shutdown_type::shutdown_receive, ec);
asio::error_code ec;
raw_socket().shutdown(asio::socket_base::shutdown_type::shutdown_receive, ec);
}
}
boost::asio::io_service& get_io_service()
asio::io_service& get_io_service()
{
return GET_IO_SERVICE(raw_socket());
}
@ -156,13 +157,13 @@ namespace crow
template<typename F>
void start(F f)
{
ssl_socket_->async_handshake(boost::asio::ssl::stream_base::server,
[f](const boost::system::error_code& ec) {
ssl_socket_->async_handshake(asio::ssl::stream_base::server,
[f](const asio::error_code& ec) {
f(ec);
});
}
std::unique_ptr<boost::asio::ssl::stream<tcp::socket>> ssl_socket_;
std::unique_ptr<asio::ssl::stream<tcp::socket>> ssl_socket_;
};
#endif
} // namespace crow

View File

@ -1,6 +1,9 @@
#pragma once
#include <boost/asio.hpp>
#define ASIO_STANDALONE
#include <asio.hpp>
#include <asio/basic_waitable_timer.hpp>
#include <chrono>
#include <functional>
#include <map>
@ -25,15 +28,15 @@ namespace crow
using time_type = clock_type::time_point;
public:
task_timer(boost::asio::io_service& io_service):
io_service_(io_service), deadline_timer_(io_service_)
task_timer(asio::io_service& io_service):
io_service_(io_service), timer_(io_service_)
{
deadline_timer_.expires_from_now(boost::posix_time::seconds(1));
deadline_timer_.async_wait(
timer_.expires_after(std::chrono::seconds(1));
timer_.async_wait(
std::bind(&task_timer::tick_handler, this, std::placeholders::_1));
}
~task_timer() { deadline_timer_.cancel(); }
~task_timer() { timer_.cancel(); }
void cancel(identifier_type id)
{
@ -107,21 +110,21 @@ namespace crow
if (tasks_.empty()) highest_id_ = 0;
}
void tick_handler(const boost::system::error_code& ec)
void tick_handler(const asio::error_code& ec)
{
if (ec) return;
process_tasks();
deadline_timer_.expires_from_now(boost::posix_time::seconds(1));
deadline_timer_.async_wait(
timer_.expires_after(std::chrono::seconds(1));
timer_.async_wait(
std::bind(&task_timer::tick_handler, this, std::placeholders::_1));
}
private:
std::uint8_t default_timeout_{5};
boost::asio::io_service& io_service_;
boost::asio::deadline_timer deadline_timer_;
asio::io_service& io_service_;
asio::basic_waitable_timer<clock_type> timer_;
std::map<identifier_type, std::pair<time_type, task_type>> tasks_;
// A continuosly increasing number to be issued to threads to identify them.

View File

@ -5,8 +5,10 @@
#include <tuple>
#include <type_traits>
#include <cstring>
#include <cctype>
#include <functional>
#include <string>
#include <sstream>
#include <unordered_map>
#include "crow/settings.h"
@ -500,7 +502,6 @@ namespace crow
{
static constexpr auto value = get_index_of_element_from_tuple_by_type_impl<T, N + 1, Args...>::value;
};
} // namespace detail
namespace utility
@ -780,5 +781,90 @@ namespace crow
}
}
/**
* @brief Checks two string for equality.
* Always returns false if strings differ in size.
* Defaults to case-insensitive comparison.
*/
inline static bool string_equals(const std::string& l, const std::string& r, bool case_sensitive = false)
{
if (l.length() != r.length())
return false;
for (size_t i = 0; i < l.length(); i++)
{
if (case_sensitive)
{
if (l[i] != r[i])
return false;
}
else
{
if (std::toupper(l[i]) != std::toupper(r[i]))
return false;
}
}
return true;
}
template<typename T, typename U>
inline static T lexical_cast(const U& v)
{
std::stringstream stream;
T res;
stream << v;
stream >> res;
return res;
}
template<typename T>
inline static T lexical_cast(const char* v, size_t count)
{
std::stringstream stream;
T res;
stream.write(v, count);
stream >> res;
return res;
}
/// Return a copy of the given string with its
/// leading and trailing whitespaces removed.
inline static std::string trim(const std::string& v)
{
if (v.empty())
return "";
size_t begin = 0, end = v.length();
size_t i;
for (i = 0; i < v.length(); i++)
{
if (!std::isspace(v[i]))
{
begin = i;
break;
}
}
if (i == v.length())
return "";
for (i = v.length(); i > 0; i--)
{
if (!std::isspace(v[i - 1]))
{
end = i;
break;
}
}
return v.substr(begin, end - begin);
}
} // namespace utility
} // namespace crow

View File

@ -1,10 +1,10 @@
#pragma once
#include <boost/algorithm/string/predicate.hpp>
#include <boost/array.hpp>
#include <array>
#include "crow/logging.h"
#include "crow/socket_adaptors.h"
#include "crow/http_request.h"
#include "crow/TinySHA1.hpp"
#include "crow/utility.h"
namespace crow
{
@ -86,7 +86,7 @@ namespace crow
error_handler_(std::move(error_handler)),
accept_handler_(std::move(accept_handler))
{
if (!boost::iequals(req.get_header_value("upgrade"), "websocket"))
if (!utility::string_equals(req.get_header_value("upgrade"), "websocket"))
{
adaptor.close();
handler_->remove_websocket(this);
@ -282,12 +282,12 @@ namespace crow
case WebSocketReadState::MiniHeader:
{
mini_header_ = 0;
//boost::asio::async_read(adaptor_.socket(), boost::asio::buffer(&mini_header_, 1),
//asio::async_read(adaptor_.socket(), 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
asio::buffer(&mini_header_, 2),
[this](const asio::error_code& ec, std::size_t
#ifdef CROW_ENABLE_DEBUG
bytes_transferred
bytes_transferred
#endif
)
@ -351,11 +351,11 @@ namespace crow
{
remaining_length_ = 0;
remaining_length16_ = 0;
boost::asio::async_read(
adaptor_.socket(), boost::asio::buffer(&remaining_length16_, 2),
[this](const boost::system::error_code& ec, std::size_t
asio::async_read(
adaptor_.socket(), asio::buffer(&remaining_length16_, 2),
[this](const asio::error_code& ec, std::size_t
#ifdef CROW_ENABLE_DEBUG
bytes_transferred
bytes_transferred
#endif
) {
is_reading = false;
@ -387,11 +387,11 @@ namespace crow
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
asio::async_read(
adaptor_.socket(), asio::buffer(&remaining_length_, 8),
[this](const asio::error_code& ec, std::size_t
#ifdef CROW_ENABLE_DEBUG
bytes_transferred
bytes_transferred
#endif
) {
is_reading = false;
@ -431,11 +431,11 @@ namespace crow
}
else if (has_mask_)
{
boost::asio::async_read(
adaptor_.socket(), boost::asio::buffer((char*)&mask_, 4),
[this](const boost::system::error_code& ec, std::size_t
asio::async_read(
adaptor_.socket(), asio::buffer((char*)&mask_, 4),
[this](const asio::error_code& ec, std::size_t
#ifdef CROW_ENABLE_DEBUG
bytes_transferred
bytes_transferred
#endif
) {
is_reading = false;
@ -474,8 +474,8 @@ namespace crow
if (remaining_length_ < to_read)
to_read = remaining_length_;
adaptor_.socket().async_read_some(
boost::asio::buffer(buffer_, static_cast<std::size_t>(to_read)),
[this](const boost::system::error_code& ec, std::size_t bytes_transferred) {
asio::buffer(buffer_, static_cast<std::size_t>(to_read)),
[this](const asio::error_code& ec, std::size_t bytes_transferred) {
is_reading = false;
if (!ec)
@ -618,15 +618,15 @@ namespace crow
if (sending_buffers_.empty())
{
sending_buffers_.swap(write_buffers_);
std::vector<boost::asio::const_buffer> buffers;
std::vector<asio::const_buffer> buffers;
buffers.reserve(sending_buffers_.size());
for (auto& s : sending_buffers_)
{
buffers.emplace_back(boost::asio::buffer(s));
buffers.emplace_back(asio::buffer(s));
}
boost::asio::async_write(
asio::async_write(
adaptor_.socket(), buffers,
[&](const boost::system::error_code& ec, std::size_t /*bytes_transferred*/) {
[&](const asio::error_code& ec, std::size_t /*bytes_transferred*/) {
sending_buffers_.clear();
if (!ec && !close_connection_)
{
@ -663,7 +663,7 @@ namespace crow
std::vector<std::string> sending_buffers_;
std::vector<std::string> write_buffers_;
boost::array<char, 4096> buffer_;
std::array<char, 4096> buffer_;
bool is_binary_;
std::string message_;
std::string fragment_;

View File

@ -6,7 +6,7 @@ pkgdesc="A Fast and Easy to use C++ microframework for the web."
arch=(any)
url="https://crowcpp.org"
license=('custom:BSD-3-Clause')
depends=('boost>=1.64.0')
depends=('asio')
optdepends=('openssl: HTTPS support' 'zlib: HTTP compression support' 'cmake: Choose this if you plan on using CMake for your Crow project')
conflicts=("$pkgname-git")
changelog='changelog.md'

View File

@ -8,8 +8,6 @@
#define LOCALHOST_ADDRESS "127.0.0.1"
using namespace boost;
// TODO(EDev): SSL test with .pem file
TEST_CASE("SSL")
{
@ -76,8 +74,8 @@ TEST_CASE("SSL")
CHECK(std::string("Hello world, I'm keycrt.").substr((z * -1)) == to_test);
}
boost::system::error_code ec;
c.lowest_layer().shutdown(boost::asio::socket_base::shutdown_type::shutdown_both, ec);
asio::error_code ec;
c.lowest_layer().shutdown(asio::socket_base::shutdown_type::shutdown_both, ec);
}
/*

View File

@ -596,7 +596,7 @@ TEST_CASE("undefined_status_code")
asio::ip::tcp::socket socket(is);
socket.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string(LOCALHOST_ADDRESS), app.port()));
boost::asio::streambuf request;
asio::streambuf request;
std::ostream request_stream(&request);
request_stream << "GET " << route << " HTTP/1.0\r\n";
request_stream << "Host: " << LOCALHOST_ADDRESS << "\r\n";
@ -604,10 +604,10 @@ TEST_CASE("undefined_status_code")
request_stream << "Connection: close\r\n\r\n";
// Send the request.
boost::asio::write(socket, request);
asio::write(socket, request);
boost::asio::streambuf response;
boost::asio::read_until(socket, response, "\r\n");
asio::streambuf response;
asio::read_until(socket, response, "\r\n");
std::istream response_stream(&response);
std::string http_version;
@ -759,7 +759,7 @@ TEST_CASE("json_read_real")
for (auto x : v)
{
CROW_LOG_DEBUG << x;
CHECK(json::load(x).d() == boost::lexical_cast<double>(x));
CHECK(json::load(x).d() == utility::lexical_cast<double>(x));
}
auto ret = json::load(
@ -1702,9 +1702,15 @@ TEST_CASE("middleware_cookieparser_format")
}
// expires
{
auto tp = boost::posix_time::time_from_string("2000-11-01 23:59:59.000");
std::time_t tp;
std::time(&tp);
std::tm* tm = std::gmtime(&tp);
std::istringstream ss("2000-11-01 23:59:59");
ss >> std::get_time(tm, "%Y-%m-%d %H:%M:%S");
std::mktime(tm);
auto c = Cookie("key", "value")
.expires(boost::posix_time::to_tm(tp));
.expires(*tm);
auto s = c.dump();
CHECK(valid(s, 2));
CHECK(s.find("Expires=Wed, 01 Nov 2000 23:59:59 GMT") != std::string::npos);
@ -1936,10 +1942,10 @@ TEST_CASE("simple_url_params")
c.receive(asio::buffer(buf, 2048));
c.close();
CHECK(boost::lexical_cast<int>(last_url_params.get("int")) == 100);
CHECK(boost::lexical_cast<double>(last_url_params.get("double")) ==
CHECK(utility::lexical_cast<int>(last_url_params.get("int")) == 100);
CHECK(utility::lexical_cast<double>(last_url_params.get("double")) ==
123.45);
CHECK(boost::lexical_cast<bool>(last_url_params.get("boolean")));
CHECK(utility::lexical_cast<bool>(last_url_params.get("boolean")));
}
// check single array value
sendmsg = "GET /params?tmnt[]=leonardo\r\n\r\n";
@ -2518,8 +2524,8 @@ TEST_CASE("websocket_max_payload")
}
}
boost::system::error_code ec;
c.lowest_layer().shutdown(boost::asio::socket_base::shutdown_type::shutdown_both, ec);
asio::error_code ec;
c.lowest_layer().shutdown(asio::socket_base::shutdown_type::shutdown_both, ec);
app.stop();
} // websocket_max_payload
@ -3023,7 +3029,7 @@ TEST_CASE("timeout")
asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
auto receive_future = async(launch::async, [&]() {
boost::system::error_code ec;
asio::error_code ec;
c.receive(asio::buffer(buf, 2048), 0, ec);
return ec;
});
@ -3043,7 +3049,7 @@ TEST_CASE("timeout")
size_t received;
auto receive_future = async(launch::async, [&]() {
boost::system::error_code ec;
asio::error_code ec;
received = c.receive(asio::buffer(buf, 2048), 0, ec);
return ec;
});
@ -3069,9 +3075,9 @@ TEST_CASE("timeout")
TEST_CASE("task_timer")
{
using work_guard_type = boost::asio::executor_work_guard<boost::asio::io_service::executor_type>;
using work_guard_type = asio::executor_work_guard<asio::io_service::executor_type>;
boost::asio::io_service io_service;
asio::io_service io_service;
work_guard_type work_guard(io_service.get_executor());
thread io_thread([&io_service]() {
io_service.run();
@ -3106,3 +3112,39 @@ TEST_CASE("task_timer")
io_service.stop();
io_thread.join();
} // task_timer
TEST_CASE("trim")
{
CHECK(utility::trim("") == "");
CHECK(utility::trim("0") == "0");
CHECK(utility::trim(" a") == "a");
CHECK(utility::trim("b ") == "b");
CHECK(utility::trim(" c ") == "c");
CHECK(utility::trim(" a b ") == "a b");
CHECK(utility::trim(" ") == "");
}
TEST_CASE("string_equals")
{
CHECK(utility::string_equals("a", "aa") == false);
CHECK(utility::string_equals("a", "b") == false);
CHECK(utility::string_equals("", "") == true);
CHECK(utility::string_equals("abc", "abc") == true);
CHECK(utility::string_equals("ABC", "abc") == true);
CHECK(utility::string_equals("a", "aa", true) == false);
CHECK(utility::string_equals("a", "b", true) == false);
CHECK(utility::string_equals("", "", true) == true);
CHECK(utility::string_equals("abc", "abc", true) == true);
CHECK(utility::string_equals("ABC", "abc", true) == false);
}
TEST_CASE("lexical_cast")
{
CHECK(utility::lexical_cast<int>(4) == 4);
CHECK(utility::lexical_cast<double>(4) == 4.0);
CHECK(utility::lexical_cast<int>("5") == 5);
CHECK(utility::lexical_cast<string>(4) == "4");
CHECK(utility::lexical_cast<float>("10", 2) == 10.0f);
}

View File

@ -3,32 +3,7 @@
"version-string": "master",
"dependencies": [
{
"name": "boost-array",
"version>=": "1.70.0"
},
{
"name": "boost-algorithm",
"version>=": "1.70.0"
},
{
"name": "boost-asio",
"version>=": "1.70.0"
},
{
"name": "boost-date-time",
"version>=": "1.70.0"
},
{
"name": "boost-functional",
"version>=": "1.70.0"
},
{
"name": "boost-lexical-cast",
"version>=": "1.70.0"
},
{
"name": "boost-optional",
"version>=": "1.70.0"
"name": "asio"
},
{
"name": "openssl"
@ -37,35 +12,5 @@
"name": "zlib"
}
],
"overrides": [
{
"name": "boost-array",
"version": "1.70.0"
},
{
"name": "boost-algorithm",
"version": "1.70.0"
},
{
"name": "boost-asio",
"version-semver": "1.70.0-2"
},
{
"name": "boost-date-time",
"version": "1.70.0"
},
{
"name": "boost-functional",
"version": "1.70.0"
},
{
"name": "boost-lexical-cast",
"version": "1.70.0"
},
{
"name": "boost-optional",
"version": "1.70.0"
}
],
"builtin-baseline": "44d94c2edbd44f0c01d66c2ad95eb6982a9a61bc"
}