mirror of
https://github.com/CrowCpp/Crow.git
synced 2024-06-07 21:10:44 +00:00
Merge branch 'master' into sessions
This commit is contained in:
commit
6b6eb5eb0b
@ -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
|
||||
|
@ -28,7 +28,7 @@ env:
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libboost-all-dev
|
||||
- libasio-dev
|
||||
- doxygen
|
||||
- mkdocs
|
||||
- graphviz
|
||||
|
@ -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)
|
||||
|
@ -103,7 +103,7 @@ CROW_ROUTE(app, "/add_json")
|
||||
More examples can be found [here](https://github.com/crowcpp/crow/tree/master/examples).
|
||||
|
||||
## Setting Up / Building
|
||||
Available [here](https://crowcpp.org/getting_started/setup).
|
||||
Available [here](https://crowcpp.org/master/getting_started/setup).
|
||||
|
||||
## Disclaimer
|
||||
CrowCpp/Crow is a project based on ipkn/crow. Neither CrowCpp, it's members, or this project have been associated with, or endorsed or supported by ipkn (Jaeseung Ha) in any way. We do use ipkn/crow's source code under the BSD-3 clause license and sometimes refer to the public comments available on the github repository. But we do not in any way claim to be associated with or in contact with ipkn (Jaeseung Ha) regarding CrowCpp or CrowCpp/Crow
|
||||
|
@ -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}
|
||||
)
|
||||
|
129
docs/getting_started/a_simple_webpage.md
Normal file
129
docs/getting_started/a_simple_webpage.md
Normal file
@ -0,0 +1,129 @@
|
||||
Hello World is a good start, but what if you want something a bit more fancy.. Something like an HTML document saying "Hello World". If that's what you want, follow along:
|
||||
|
||||
## Basic Webpage
|
||||
Let's start our webpage with.. well.. a webpage. But before we create a webpage we need to place it somewhere Crow recognizes, for now this directory is going to be called `templates`, but we can [change it later](../../guides/templating/#page).
|
||||
|
||||
Once our `templates` folder is created, we can create our HTML document inside it, let's call it `fancypage.html`.
|
||||
|
||||
After that we can just place something simple inside it like:
|
||||
``` html title="templates/fancypage.html"
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<p>Hello World!</p>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
<br>
|
||||
Now that we have our HTML page ready, let's take our Hello World example from earlier:
|
||||
``` cpp linenums="1"
|
||||
#include "crow.h"
|
||||
//#include "crow_all.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
crow::SimpleApp app; //define your crow application
|
||||
|
||||
//define your endpoint at the root directory
|
||||
CROW_ROUTE(app, "/")([](){
|
||||
return "Hello world";
|
||||
});
|
||||
|
||||
//set the port, set the app to run on multiple threads, and run the app
|
||||
app.port(18080).multithreaded().run();
|
||||
}
|
||||
```
|
||||
<br>
|
||||
|
||||
And now let's modify it so that it returns our cool page:
|
||||
``` cpp title="/main.cpp" linenums="1" hl_lines="10 11"
|
||||
#include "crow.h"
|
||||
//#include "crow_all.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
crow::SimpleApp app;
|
||||
|
||||
//define your endpoint at the root directory
|
||||
CROW_ROUTE(app, "/")([](){
|
||||
auto page = crow::mustache::load_text("fancypage.html");
|
||||
return page;
|
||||
});
|
||||
|
||||
app.port(18080).multithreaded().run();
|
||||
}
|
||||
```
|
||||
|
||||
Your project should look something something like:
|
||||
```
|
||||
./
|
||||
|-templates/
|
||||
| |-fancypage.html
|
||||
|
|
||||
|-main.cpp
|
||||
|-crow_all.h
|
||||
```
|
||||
or
|
||||
```
|
||||
./
|
||||
|-templates/
|
||||
| |-fancypage.html
|
||||
|
|
||||
|-crow/
|
||||
| |-include/...
|
||||
| |-crow.h
|
||||
|-main.cpp
|
||||
```
|
||||
|
||||
|
||||
Once the code is done compiling, if we call `http://localhost:18080/` we get our Hello World in an HTML document rather than just plain text.
|
||||
|
||||
!!! note
|
||||
|
||||
Compilation instructions are available for [Linux](../setup/linux#compiling-your-project), [MacOS](../setup/macos#compiling-using-a-compiler-directly), and [Windows](../setup/windows#getting-and-compiling-crow)
|
||||
|
||||
|
||||
## Template Webpage with a variable
|
||||
But we can make things even more exciting, we can greet a user by their name instead!!
|
||||
|
||||
Let's start with our webpage, and modify it with a little bit of [mustache](../../guides/templating) syntax:
|
||||
``` html title="templates/fancypage.html" hl_lines="4"
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<p>Hello {{person}}!</p> <!--(1)-->
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
1. `{{}}` in mustache define a simple variable
|
||||
|
||||
<br>
|
||||
Now let's modify our C++ code to use the variable we just added to our webpage (or template):
|
||||
``` cpp title="/main.cpp" linenums="1" hl_lines="9-12"
|
||||
#include "crow.h"
|
||||
//#include "crow_all.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
crow::SimpleApp app;
|
||||
|
||||
//define your endpoint at the root directory
|
||||
CROW_ROUTE(app, "/<string>")([](std::string name){ // (1)
|
||||
auto page = crow::mustache::load("fancypage.html"); // (2)
|
||||
crow::mustache::context ctx ({{"person", name}}); // (3)
|
||||
return page.render(ctx); //(4)
|
||||
});
|
||||
|
||||
app.port(18080).multithreaded().run();
|
||||
}
|
||||
```
|
||||
|
||||
1. We are adding a `string` variable to the URL and a counterpart (`std::string name`) to our Route, this can be anything the user wants.
|
||||
2. We are using `load()` instead of `load_text()` since we have an actual variable now.
|
||||
3. We are creating a new [context](../../guides/templating/#context) containing the `person` variable from our template and the `name` we got from the URL.
|
||||
4. we are using `render(ctx)` to apply our context to the template.
|
||||
|
||||
Now (after compiling the code and running the executable a second time) calling `http://localhost:18080/Bob` should return a webpage containing "Hello Bob!". **We did it!**
|
||||
|
||||
For more details on templates and HTML pages in Crow please go [here](../../guides/templating/)
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -38,7 +38,7 @@ Please note that the `port()` and `multithreaded()` methods aren't needed, Thoug
|
||||
|
||||
Once you've followed all the steps above, your code should look similar to this
|
||||
|
||||
``` cpp linenums="1"
|
||||
``` cpp title="main.cpp" linenums="1"
|
||||
#include "crow.h"
|
||||
//#include "crow_all.h"
|
||||
|
||||
@ -55,4 +55,7 @@ int main()
|
||||
app.port(18080).multithreaded().run();
|
||||
}
|
||||
```
|
||||
After building and running your .cpp file, you should be able to access your endpoint at [http://localhost:18080](http://localhost:18080). Opening this URL in your browser will show a white screen with "Hello world" typed on it.
|
||||
|
||||
You then need to compile your code on your [Linux](../setup/linux#compiling-your-project), [MacOS](../setup/macos#compiling-using-a-compiler-directly), or [Windows](../setup/windows#getting-and-compiling-crow) machine
|
||||
|
||||
After building your `.cpp` file and running the resulting executable, you should be able to access your endpoint at [http://localhost:18080](http://localhost:18080). Opening this URL in your browser will show a white screen with "Hello world" typed on it.
|
||||
|
@ -20,7 +20,7 @@ JSON read value, used for taking a JSON string and parsing it into `crow::json`.
|
||||
You can read individual items of the rvalue, but you cannot add items to it.<br>
|
||||
To do that, you need to convert it to a `wvalue`, which can be done by simply writing `#!cpp crow::json::wvalue wval (rval);` (assuming `rval` is your `rvalue`).<br><br>
|
||||
|
||||
For more info on read values go [here](/reference/classcrow_1_1json_1_1rvalue.html).<br><br>
|
||||
For more info on read values go [here](../../reference/classcrow_1_1json_1_1rvalue.html).<br><br>
|
||||
|
||||
## wvalue
|
||||
JSON write value, used for creating, editing and converting JSON to a string.<br><br>
|
||||
|
@ -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.
|
||||
|
@ -5,11 +5,15 @@ To create a websocket in Crow, you need a websocket route.<br>
|
||||
A websocket route differs from a normal route quite a bit. It uses A slightly altered `CROW_WEBSOCKET_ROUTE(app, "/url")` macro, which is then followed by a series of methods (with handlers inside) for each event. These are (sorted by order of execution):
|
||||
|
||||
|
||||
- `#!cpp onaccept([&](const crow::request&){handler code goes here})` (This handler has to return `bool`)
|
||||
- `#!cpp onaccept([&](const crow::request& req, void** userdata){handler code goes here})`
|
||||
- `#!cpp onopen([&](crow::websocket::connection& conn){handler code goes here})`
|
||||
- `#!cpp onmessage([&](crow::websocket::connection& conn, const std::string message, bool is_binary){handler code goes here})`
|
||||
- `#!cpp onerror([&](crow::websocket::connection& conn){handler code goes here})`
|
||||
- `#!cpp onclose([&](crow::websocket::connection& conn, const std::string reason){handler code goes here})`
|
||||
- `#!cpp onmessage([&](crow::websocket::connection& conn, const std::string& message, bool is_binary){handler code goes here})`
|
||||
- `#!cpp onerror([&](crow::websocket::connection& conn, const std::string& error_message){handler code goes here})`
|
||||
- `#!cpp onclose([&](crow::websocket::connection& conn, const std::string& reason){handler code goes here})`
|
||||
|
||||
!!! note
|
||||
|
||||
`onaccept` must return a boolean. In case `false` is returned, the connection is shut down, deleted, and no further communication is done.
|
||||
|
||||
!!! Warning
|
||||
|
||||
|
@ -94,7 +94,7 @@
|
||||
<div class="md-footer-meta__inner md-grid">
|
||||
|
||||
<!-- Copyright and theme information -->
|
||||
<div class="md-footer-copyright">
|
||||
<div class="md-footer-copyright" style="flex: 1;display: flex;justify-content: left;">
|
||||
{% if config.copyright %}
|
||||
<div class="md-footer-copyright__highlight">
|
||||
{{ config.copyright }}
|
||||
@ -103,7 +103,7 @@
|
||||
{{ extracopyright }}
|
||||
</div>
|
||||
|
||||
<a style="margin: auto .6rem; font-size: .64rem;" href="/privacy_policy.html">Privacy Policy</a>
|
||||
<a style="margin: auto .6rem; font-size: .64rem;text-align: center;flex: 1;display: flex;justify-content: center;" href="/privacy_policy.html">Privacy Policy</a>
|
||||
|
||||
<!-- Social links -->
|
||||
{% include "partials/social.html" %}
|
||||
|
@ -35,6 +35,8 @@
|
||||
--home-border-color: #ffffff20;
|
||||
--home-shadow-color: #00000040;
|
||||
--home-image-border: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.3) 50%, rgba(255, 255, 255, 0) 100%);
|
||||
--md-admonition-bg-color: #272a2b;
|
||||
--md-code-hl-color: rgba(255, 255, 0, 0.18);
|
||||
|
||||
}
|
||||
|
||||
|
@ -38,12 +38,6 @@ add_custom_target(example_ws_copy ALL DEPENDS ws.html)
|
||||
add_executable(basic_example example.cpp)
|
||||
add_warnings_optimizations(basic_example)
|
||||
target_link_libraries(basic_example PUBLIC Crow::Crow)
|
||||
add_custom_command(OUTPUT example_test.py
|
||||
COMMAND ${CMAKE_COMMAND} -E
|
||||
copy ${PROJECT_SOURCE_DIR}/example_test.py ${CMAKE_CURRENT_BINARY_DIR}/example_test.py
|
||||
DEPENDS ${PROJECT_SOURCE_DIR}/example_test.py
|
||||
)
|
||||
add_custom_target(example_copy ALL DEPENDS example_test.py)
|
||||
|
||||
if(CROW_AMALGAMATE)
|
||||
add_executable(example_with_all example_with_all.cpp)
|
||||
|
@ -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';
|
||||
}
|
||||
|
||||
|
@ -1,19 +0,0 @@
|
||||
from flask import Flask
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route("/")
|
||||
def hello():
|
||||
return "Hello World!"
|
||||
|
||||
@app.route("/about/<path:path>/hello")
|
||||
def hello1(path):
|
||||
return "about1"
|
||||
|
||||
@app.route("/about")
|
||||
def hello2():
|
||||
return "about2"
|
||||
|
||||
print app.url_map
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=8888)
|
@ -1,44 +0,0 @@
|
||||
import urllib
|
||||
assert "Hello World!" == urllib.urlopen('http://localhost:18080').read()
|
||||
assert "About Crow example." == urllib.urlopen('http://localhost:18080/about').read()
|
||||
assert 404 == urllib.urlopen('http://localhost:18080/list').getcode()
|
||||
assert "3 bottles of beer!" == urllib.urlopen('http://localhost:18080/hello/3').read()
|
||||
assert "100 bottles of beer!" == urllib.urlopen('http://localhost:18080/hello/100').read()
|
||||
assert 400 == urllib.urlopen('http://localhost:18080/hello/500').getcode()
|
||||
assert "3" == urllib.urlopen('http://localhost:18080/add_json', data='{"a":1,"b":2}').read()
|
||||
assert "3" == urllib.urlopen('http://localhost:18080/add/1/2').read()
|
||||
|
||||
# test persistent connection
|
||||
import socket
|
||||
import time
|
||||
s = socket.socket()
|
||||
s.connect(('localhost', 18080))
|
||||
for i in xrange(10):
|
||||
s.send('''GET / HTTP/1.1
|
||||
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))
|
||||
# invalid request, connection will be closed after timeout
|
||||
s.send('''GET / HTTP/1.1
|
||||
hHhHHefhwjkefhklwejfklwejf
|
||||
''')
|
||||
print s.recv(1024)
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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(...)
|
||||
|
@ -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
|
||||
|
||||
@ -293,14 +293,6 @@ namespace crow
|
||||
}
|
||||
}
|
||||
|
||||
/// Notify anything using `wait_for_server_start()` to proceed
|
||||
void notify_server_start()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(start_mutex_);
|
||||
server_started_ = true;
|
||||
cv_started_.notify_all();
|
||||
}
|
||||
|
||||
/// Run the server
|
||||
void run()
|
||||
{
|
||||
@ -370,7 +362,7 @@ namespace crow
|
||||
|
||||
void remove_websocket(crow::websocket::connection* conn)
|
||||
{
|
||||
std::remove(websockets_.begin(), websockets_.end(), conn);
|
||||
websockets_.erase(std::remove(websockets_.begin(), websockets_.end(), conn), websockets_.end());
|
||||
}
|
||||
|
||||
/// Print the routing paths defined for each HTTP method
|
||||
@ -387,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;
|
||||
}
|
||||
|
||||
@ -400,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;
|
||||
}
|
||||
|
||||
@ -412,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);
|
||||
@ -492,10 +484,17 @@ namespace crow
|
||||
/// Wait until the server has properly started
|
||||
void wait_for_server_start()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(start_mutex_);
|
||||
if (server_started_)
|
||||
return;
|
||||
cv_started_.wait(lock);
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(start_mutex_);
|
||||
if (!server_started_)
|
||||
cv_started_.wait(lock);
|
||||
}
|
||||
if (server_)
|
||||
server_->wait_for_start();
|
||||
#ifdef CROW_ENABLE_SSL
|
||||
else if (ssl_server_)
|
||||
ssl_server_->wait_for_start();
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
@ -508,6 +507,14 @@ namespace crow
|
||||
black_magic::tuple_extract<Middlewares, decltype(fwd)>(fwd))...);
|
||||
}
|
||||
|
||||
/// Notify anything using `wait_for_server_start()` to proceed
|
||||
void notify_server_start()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(start_mutex_);
|
||||
server_started_ = true;
|
||||
cv_started_.notify_all();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::uint8_t timeout_{5};
|
||||
@ -533,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_;
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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_;
|
||||
|
@ -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():
|
||||
|
@ -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();
|
||||
});
|
||||
|
||||
@ -153,6 +152,7 @@ namespace crow
|
||||
|
||||
std::thread(
|
||||
[this] {
|
||||
notify_start();
|
||||
io_service_.run();
|
||||
CROW_LOG_INFO << "Exiting.";
|
||||
})
|
||||
@ -175,6 +175,14 @@ namespace crow
|
||||
io_service_.stop(); // Close main io_service
|
||||
}
|
||||
|
||||
/// Wait until the server has properly started
|
||||
void wait_for_start()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(start_mutex_);
|
||||
if (!server_started_)
|
||||
cv_started_.wait(lock);
|
||||
}
|
||||
|
||||
void signal_clear()
|
||||
{
|
||||
signals_.clear();
|
||||
@ -217,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(
|
||||
@ -236,6 +244,14 @@ namespace crow
|
||||
}
|
||||
}
|
||||
|
||||
/// Notify anything using `wait_for_start()` to proceed
|
||||
void notify_start()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(start_mutex_);
|
||||
server_started_ = true;
|
||||
cv_started_.notify_all();
|
||||
}
|
||||
|
||||
private:
|
||||
asio::io_service io_service_;
|
||||
std::vector<std::unique_ptr<asio::io_service>> io_service_pool_;
|
||||
@ -243,8 +259,12 @@ namespace crow
|
||||
std::vector<std::function<std::string()>> get_cached_date_str_pool_;
|
||||
tcp::acceptor acceptor_;
|
||||
bool shutting_down_ = false;
|
||||
boost::asio::signal_set signals_;
|
||||
boost::asio::deadline_timer tick_timer_;
|
||||
bool server_started_{false};
|
||||
std::condition_variable cv_started_;
|
||||
std::mutex start_mutex_;
|
||||
asio::signal_set signals_;
|
||||
|
||||
asio::basic_waitable_timer<std::chrono::high_resolution_clock> tick_timer_;
|
||||
|
||||
Handler* handler_;
|
||||
uint16_t concurrency_{2};
|
||||
|
@ -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.
|
||||
@ -630,7 +681,7 @@ namespace crow
|
||||
return (option_ & error_bit) != 0;
|
||||
}
|
||||
|
||||
std::vector<std::string> keys()
|
||||
std::vector<std::string> keys() const
|
||||
{
|
||||
#ifndef CROW_JSON_NO_ERROR_CHECK
|
||||
if (t() != type::Object)
|
||||
@ -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:
|
||||
@ -1422,6 +1473,7 @@ namespace crow
|
||||
wvalue& operator=(wvalue&& r)
|
||||
{
|
||||
t_ = r.t_;
|
||||
nt = r.nt;
|
||||
num = r.num;
|
||||
s = std::move(r.s);
|
||||
l = std::move(r.l);
|
||||
@ -1784,12 +1836,12 @@ namespace crow
|
||||
enum
|
||||
{
|
||||
start,
|
||||
decp,
|
||||
decp, // Decimal point
|
||||
zero
|
||||
} f_state;
|
||||
char outbuf[128];
|
||||
MSC_COMPATIBLE_SPRINTF(outbuf, "%f", v.num.d);
|
||||
char *p = &outbuf[0], *o = nullptr;
|
||||
char *p = &outbuf[0], *o = nullptr; // o is the position of the first trailing 0
|
||||
f_state = start;
|
||||
while (*p != '\0')
|
||||
{
|
||||
@ -1797,15 +1849,17 @@ namespace crow
|
||||
char ch = *p;
|
||||
switch (f_state)
|
||||
{
|
||||
case start:
|
||||
case start: // Loop and lookahead until a decimal point is found
|
||||
if (ch == '.')
|
||||
{
|
||||
if (p + 1 && *(p + 1) == '0') p++;
|
||||
char fch = *(p + 1);
|
||||
// if the first character is 0, leave it be (this is so that "1.00000" becomes "1.0" and not "1.")
|
||||
if (fch != '\0' && fch == '0') p++;
|
||||
f_state = decp;
|
||||
}
|
||||
p++;
|
||||
break;
|
||||
case decp:
|
||||
case decp: // Loop until a 0 is found, if found, record its position
|
||||
if (ch == '0')
|
||||
{
|
||||
f_state = zero;
|
||||
@ -1813,7 +1867,7 @@ namespace crow
|
||||
}
|
||||
p++;
|
||||
break;
|
||||
case zero:
|
||||
case zero: // if a non 0 is found (e.g. 1.00004) remove the earlier recorded 0 position and look for more trailing 0s
|
||||
if (ch != '0')
|
||||
{
|
||||
o = nullptr;
|
||||
@ -1823,7 +1877,7 @@ namespace crow
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (o != nullptr)
|
||||
if (o != nullptr) // if any trailing 0s are found, terminate the string where they begin
|
||||
*o = '\0';
|
||||
out += outbuf;
|
||||
#undef MSC_COMPATIBLE_SPRINTF
|
||||
@ -1898,7 +1952,7 @@ namespace crow
|
||||
|
||||
|
||||
|
||||
//std::vector<boost::asio::const_buffer> dump_ref(wvalue& v)
|
||||
//std::vector<asio::const_buffer> dump_ref(wvalue& v)
|
||||
//{
|
||||
//}
|
||||
} // namespace json
|
||||
|
@ -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"
|
||||
|
||||
@ -69,7 +69,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_)
|
||||
{
|
||||
@ -106,14 +106,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;
|
||||
}
|
||||
|
||||
@ -148,10 +148,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;
|
||||
|
||||
@ -167,13 +185,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 = "; ";
|
||||
};
|
||||
@ -227,17 +245,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);
|
||||
@ -249,8 +265,6 @@ namespace crow
|
||||
if (pos == cookies.npos)
|
||||
break;
|
||||
pos++;
|
||||
while (pos < cookies.size() && cookies[pos] == ' ')
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -278,7 +292,7 @@ namespace crow
|
||||
C::handle
|
||||
context.aaa
|
||||
|
||||
App::context : private CookieParser::contetx, ...
|
||||
App::context : private CookieParser::contetx, ...
|
||||
{
|
||||
jar
|
||||
|
||||
|
@ -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++;
|
||||
}
|
||||
@ -379,6 +379,12 @@ namespace crow
|
||||
return rendered_template(ret);
|
||||
}
|
||||
|
||||
/// Apply the values from the context provided and output a returnable template from this mustache template
|
||||
rendered_template render(context&& ctx) const
|
||||
{
|
||||
return render(ctx);
|
||||
}
|
||||
|
||||
/// Output a returnable template from this mustache template
|
||||
std::string render_string() const
|
||||
{
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
#include "crow/http_parser_merged.h"
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <iostream>
|
||||
#include <boost/optional.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace crow
|
||||
{
|
||||
@ -106,10 +106,13 @@ inline int qs_parse(char* qs, char* qs_kv[], int qs_kv_size, bool parse_url = tr
|
||||
|
||||
// find the beginning of the k/v substrings or the fragment
|
||||
substr_ptr = parse_url ? qs + strcspn(qs, "?#") : qs;
|
||||
if (substr_ptr[0] != '\0')
|
||||
substr_ptr++;
|
||||
else
|
||||
return 0; // no query or fragment
|
||||
if (parse_url)
|
||||
{
|
||||
if (substr_ptr[0] != '\0')
|
||||
substr_ptr++;
|
||||
else
|
||||
return 0; // no query or fragment
|
||||
}
|
||||
|
||||
i=0;
|
||||
while(i<qs_kv_size)
|
||||
@ -191,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;
|
||||
}
|
||||
}
|
||||
@ -200,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;
|
||||
@ -229,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
|
||||
{
|
||||
@ -239,7 +242,7 @@ inline boost::optional<std::pair<std::string, std::string>> qs_dict_name2kv(cons
|
||||
}
|
||||
#endif // _qsSORTING
|
||||
|
||||
return boost::none;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
@ -509,8 +508,8 @@ namespace crow
|
||||
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_;
|
||||
std::function<void(crow::websocket::connection&, const std::string&)> error_handler_;
|
||||
std::function<bool(const crow::request&, void**)> accept_handler_;
|
||||
uint64_t max_payload_;
|
||||
bool max_payload_override_ = false;
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -5,8 +5,10 @@
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
#include <random>
|
||||
|
||||
@ -505,7 +507,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
|
||||
@ -810,5 +811,90 @@ namespace crow
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
@ -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
|
||||
{
|
||||
@ -75,8 +75,8 @@ namespace crow
|
||||
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):
|
||||
std::function<void(crow::websocket::connection&, const std::string&)> error_handler,
|
||||
std::function<bool(const crow::request&, void**)> accept_handler):
|
||||
adaptor_(std::move(adaptor)),
|
||||
handler_(handler),
|
||||
max_payload_bytes_(max_payload),
|
||||
@ -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);
|
||||
@ -96,13 +96,15 @@ namespace crow
|
||||
|
||||
if (accept_handler_)
|
||||
{
|
||||
if (!accept_handler_(req))
|
||||
void* ud = nullptr;
|
||||
if (!accept_handler_(req, &ud))
|
||||
{
|
||||
adaptor.close();
|
||||
handler_->remove_websocket(this);
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
userdata(ud);
|
||||
}
|
||||
|
||||
// Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
|
||||
@ -265,18 +267,27 @@ namespace crow
|
||||
/// Reading the actual payload.<br>
|
||||
void do_read()
|
||||
{
|
||||
if (has_sent_close_ && has_recv_close_)
|
||||
{
|
||||
close_connection_ = true;
|
||||
adaptor_.shutdown_readwrite();
|
||||
adaptor_.close();
|
||||
check_destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
is_reading = true;
|
||||
switch (state_)
|
||||
{
|
||||
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
|
||||
)
|
||||
|
||||
@ -304,7 +315,7 @@ namespace crow
|
||||
adaptor_.shutdown_readwrite();
|
||||
adaptor_.close();
|
||||
if (error_handler_)
|
||||
error_handler_(*this);
|
||||
error_handler_(*this, "Client connection not masked.");
|
||||
check_destroy();
|
||||
#endif
|
||||
}
|
||||
@ -330,7 +341,7 @@ namespace crow
|
||||
adaptor_.shutdown_readwrite();
|
||||
adaptor_.close();
|
||||
if (error_handler_)
|
||||
error_handler_(*this);
|
||||
error_handler_(*this, ec.message());
|
||||
check_destroy();
|
||||
}
|
||||
});
|
||||
@ -340,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;
|
||||
@ -368,7 +379,7 @@ namespace crow
|
||||
adaptor_.shutdown_readwrite();
|
||||
adaptor_.close();
|
||||
if (error_handler_)
|
||||
error_handler_(*this);
|
||||
error_handler_(*this, ec.message());
|
||||
check_destroy();
|
||||
}
|
||||
});
|
||||
@ -376,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;
|
||||
@ -403,7 +414,7 @@ namespace crow
|
||||
adaptor_.shutdown_readwrite();
|
||||
adaptor_.close();
|
||||
if (error_handler_)
|
||||
error_handler_(*this);
|
||||
error_handler_(*this, ec.message());
|
||||
check_destroy();
|
||||
}
|
||||
});
|
||||
@ -415,16 +426,16 @@ namespace crow
|
||||
close_connection_ = true;
|
||||
adaptor_.close();
|
||||
if (error_handler_)
|
||||
error_handler_(*this);
|
||||
error_handler_(*this, "Message length exceeds maximum paylaod.");
|
||||
check_destroy();
|
||||
}
|
||||
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;
|
||||
@ -444,7 +455,7 @@ namespace crow
|
||||
{
|
||||
close_connection_ = true;
|
||||
if (error_handler_)
|
||||
error_handler_(*this);
|
||||
error_handler_(*this, ec.message());
|
||||
adaptor_.shutdown_readwrite();
|
||||
adaptor_.close();
|
||||
check_destroy();
|
||||
@ -463,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)
|
||||
@ -473,9 +484,11 @@ namespace crow
|
||||
remaining_length_ -= bytes_transferred;
|
||||
if (remaining_length_ == 0)
|
||||
{
|
||||
handle_fragment();
|
||||
state_ = WebSocketReadState::MiniHeader;
|
||||
do_read();
|
||||
if (handle_fragment())
|
||||
{
|
||||
state_ = WebSocketReadState::MiniHeader;
|
||||
do_read();
|
||||
}
|
||||
}
|
||||
else
|
||||
do_read();
|
||||
@ -484,7 +497,7 @@ namespace crow
|
||||
{
|
||||
close_connection_ = true;
|
||||
if (error_handler_)
|
||||
error_handler_(*this);
|
||||
error_handler_(*this, ec.message());
|
||||
adaptor_.shutdown_readwrite();
|
||||
adaptor_.close();
|
||||
check_destroy();
|
||||
@ -511,7 +524,7 @@ namespace crow
|
||||
|
||||
///
|
||||
/// Unmasks the fragment, checks the opcode, merges fragments into 1 message body, and calls the appropriate handler.
|
||||
void handle_fragment()
|
||||
bool handle_fragment()
|
||||
{
|
||||
if (has_mask_)
|
||||
{
|
||||
@ -576,6 +589,7 @@ namespace crow
|
||||
is_close_handler_called_ = true;
|
||||
}
|
||||
check_destroy();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -592,6 +606,7 @@ namespace crow
|
||||
}
|
||||
|
||||
fragment_.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Send the buffers' data through the socket.
|
||||
@ -603,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_)
|
||||
{
|
||||
@ -648,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_;
|
||||
@ -670,8 +685,8 @@ namespace crow
|
||||
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_;
|
||||
std::function<void(crow::websocket::connection&, const std::string&)> error_handler_;
|
||||
std::function<bool(const crow::request&, void**)> accept_handler_;
|
||||
};
|
||||
} // namespace websocket
|
||||
} // namespace crow
|
||||
|
@ -11,7 +11,8 @@ theme:
|
||||
font: false
|
||||
language: 'en'
|
||||
features:
|
||||
navigation.tabs
|
||||
- navigation.tabs
|
||||
- content.code.annotate
|
||||
favicon: 'assets/favicon.svg'
|
||||
logo: 'assets/favicon.svg'
|
||||
icon:
|
||||
@ -54,6 +55,7 @@ nav:
|
||||
- MacOS: getting_started/setup/macos.md
|
||||
- Windows: getting_started/setup/windows.md
|
||||
- Your First Application: getting_started/your_first_application.md
|
||||
- A simple Webpage: getting_started/a_simple_webpage.md
|
||||
- Guides:
|
||||
- Different parts of Crow:
|
||||
- App: guides/app.md
|
||||
|
@ -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'
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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";
|
||||
@ -2240,7 +2246,7 @@ TEST_CASE("stream_response")
|
||||
app.validate();
|
||||
|
||||
// running the test on a separate thread to allow the client to sleep
|
||||
std::thread runTest([&app, &key_response, key_response_size]() {
|
||||
std::thread runTest([&app, &key_response, key_response_size, keyword_]() {
|
||||
auto _ = app.bindaddr(LOCALHOST_ADDRESS).port(45451).run_async();
|
||||
app.wait_for_server_start();
|
||||
asio::io_service is;
|
||||
@ -2257,15 +2263,21 @@ TEST_CASE("stream_response")
|
||||
asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
|
||||
c.send(asio::buffer(sendmsg));
|
||||
|
||||
//consuming the headers, since we don't need those for the test
|
||||
// consuming the headers, since we don't need those for the test
|
||||
static char buf[2048];
|
||||
size_t received_headers_bytes = 0;
|
||||
|
||||
// magic number is 102 (it's the size of the headers, which is how much this line below needs to read)
|
||||
const size_t headers_bytes = 102;
|
||||
while (received_headers_bytes < headers_bytes)
|
||||
received_headers_bytes += c.receive(asio::buffer(buf, 102));
|
||||
received += received_headers_bytes - headers_bytes; //add any extra that might have been received to the proper received count
|
||||
// Magic number is 102. It's the size of the headers, which is at
|
||||
// least how much we need to read. Since the header size may change
|
||||
// and break the test, we read twice as much as the header and
|
||||
// search in the received data for the first occurrence of keyword_.
|
||||
const size_t headers_bytes_and_some = 102 * 2;
|
||||
while (received_headers_bytes < headers_bytes_and_some)
|
||||
received_headers_bytes += c.receive(asio::buffer(buf + received_headers_bytes,
|
||||
sizeof(buf) / sizeof(buf[0]) - received_headers_bytes));
|
||||
|
||||
const std::string::size_type header_end_pos = std::string(buf, received_headers_bytes).find(keyword_);
|
||||
received += received_headers_bytes - header_end_pos; // add any extra that might have been received to the proper received count
|
||||
|
||||
while (received < key_response_size)
|
||||
{
|
||||
@ -2512,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
|
||||
@ -2915,12 +2927,18 @@ TEST_CASE("blueprint")
|
||||
TEST_CASE("base64")
|
||||
{
|
||||
unsigned char sample_bin[] = {0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e};
|
||||
std::string sample_bin_str(reinterpret_cast<char const*>(sample_bin),
|
||||
sizeof(sample_bin) / sizeof(sample_bin[0]));
|
||||
std::string sample_bin_enc = "FPucA9l+";
|
||||
std::string sample_bin_enc_url = "FPucA9l-";
|
||||
unsigned char sample_bin1[] = {0x14, 0xfb, 0x9c, 0x03, 0xd9};
|
||||
std::string sample_bin1_str(reinterpret_cast<char const*>(sample_bin1),
|
||||
sizeof(sample_bin1) / sizeof(sample_bin1[0]));
|
||||
std::string sample_bin1_enc = "FPucA9k=";
|
||||
std::string sample_bin1_enc_np = "FPucA9k";
|
||||
unsigned char sample_bin2[] = {0x14, 0xfb, 0x9c, 0x03};
|
||||
std::string sample_bin2_str(reinterpret_cast<char const*>(sample_bin2),
|
||||
sizeof(sample_bin2) / sizeof(sample_bin2[0]));
|
||||
std::string sample_bin2_enc = "FPucAw==";
|
||||
std::string sample_bin2_enc_np = "FPucAw";
|
||||
std::string sample_text = "Crow Allows users to handle requests that may not come from the network. This is done by calling the handle(req, res) method and providing a request and response objects. Which causes crow to identify and run the appropriate handler, returning the resulting response.";
|
||||
@ -2928,20 +2946,19 @@ TEST_CASE("base64")
|
||||
|
||||
|
||||
CHECK(crow::utility::base64encode(sample_text, sample_text.length()) == sample_base64);
|
||||
CHECK(crow::utility::base64encode((unsigned char*)sample_bin, 6) == sample_bin_enc);
|
||||
CHECK(crow::utility::base64encode_urlsafe((unsigned char*)sample_bin, 6) == sample_bin_enc_url);
|
||||
CHECK(crow::utility::base64encode((unsigned char*)sample_bin1, 5) == sample_bin1_enc);
|
||||
CHECK(crow::utility::base64encode((unsigned char*)sample_bin2, 4) == sample_bin2_enc);
|
||||
|
||||
CHECK(crow::utility::base64encode(sample_bin, 6) == sample_bin_enc);
|
||||
CHECK(crow::utility::base64encode_urlsafe(sample_bin, 6) == sample_bin_enc_url);
|
||||
CHECK(crow::utility::base64encode(sample_bin1, 5) == sample_bin1_enc);
|
||||
CHECK(crow::utility::base64encode(sample_bin2, 4) == sample_bin2_enc);
|
||||
|
||||
CHECK(crow::utility::base64decode(sample_base64) == sample_text);
|
||||
CHECK(crow::utility::base64decode(sample_base64, sample_base64.length()) == sample_text);
|
||||
CHECK(crow::utility::base64decode(sample_bin_enc, 8) == std::string(reinterpret_cast<char const*>(sample_bin)));
|
||||
CHECK(crow::utility::base64decode(sample_bin_enc_url, 8) == std::string(reinterpret_cast<char const*>(sample_bin)));
|
||||
CHECK(crow::utility::base64decode(sample_bin1_enc, 8) == std::string(reinterpret_cast<char const*>(sample_bin1)).substr(0, 5));
|
||||
CHECK(crow::utility::base64decode(sample_bin1_enc_np, 7) == std::string(reinterpret_cast<char const*>(sample_bin1)).substr(0, 5));
|
||||
CHECK(crow::utility::base64decode(sample_bin2_enc, 8) == std::string(reinterpret_cast<char const*>(sample_bin2)).substr(0, 4));
|
||||
CHECK(crow::utility::base64decode(sample_bin2_enc_np, 6) == std::string(reinterpret_cast<char const*>(sample_bin2)).substr(0, 4));
|
||||
CHECK(crow::utility::base64decode(sample_bin_enc, 8) == sample_bin_str);
|
||||
CHECK(crow::utility::base64decode(sample_bin_enc_url, 8) == sample_bin_str);
|
||||
CHECK(crow::utility::base64decode(sample_bin1_enc, 8) == sample_bin1_str);
|
||||
CHECK(crow::utility::base64decode(sample_bin1_enc_np, 7) == sample_bin1_str);
|
||||
CHECK(crow::utility::base64decode(sample_bin2_enc, 8) == sample_bin2_str);
|
||||
CHECK(crow::utility::base64decode(sample_bin2_enc_np, 6) == sample_bin2_str);
|
||||
} // base64
|
||||
|
||||
TEST_CASE("sanitize_filename")
|
||||
@ -3012,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;
|
||||
});
|
||||
@ -3032,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;
|
||||
});
|
||||
@ -3058,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();
|
||||
@ -3095,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);
|
||||
}
|
||||
|
57
vcpkg.json
57
vcpkg.json
@ -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"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user