Merge branch 'master'

Conflicts:
	CMakeLists.txt
	examples/CMakeLists.txt
	include/crow/http_connection.h
	tests/CMakeLists.txt
This commit is contained in:
The-EDev 2021-01-21 06:56:02 +03:00
commit 78ee97124b
14 changed files with 398 additions and 120 deletions

3
.gitignore vendored
View File

@ -47,3 +47,6 @@ html/
*.cxxflags *.cxxflags
*.files *.files
*.includes *.includes
#VS-Code
.vscode

View File

@ -1,71 +1,77 @@
cmake_minimum_required(VERSION 3.15) #####################################
project (crow_all) # Define Project-Wide Settings
#####################################
cmake_minimum_required(VERSION 3.15.0 FATAL_ERROR)
# Define the Project Name and Description
project (crow_all LANGUAGES CXX)
# Define the module path
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
find_package(Tcmalloc) # Set required C++ Standard
find_package(Threads) set(CMAKE_CXX_STANDARD 11)
find_package(OpenSSL) set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
find_package(ZLIB REQUIRED)
if(OPENSSL_FOUND)
include_directories(${OPENSSL_INCLUDE_DIR})
endif()
include_directories(${ZLIB_INCLUDE_DIR})
find_program(CCACHE_FOUND ccache)
if(CCACHE_FOUND)
message("Found ccache ${CCACHE_FOUND}")
message("Using ccache to speed up compilation")
set(ENV{CCACHE_CPP2} "yes")
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
endif(CCACHE_FOUND)
if (NOT CMAKE_BUILD_TYPE) if (NOT CMAKE_BUILD_TYPE)
message(STATUS "No build type selected, default to Release") message(STATUS "No build type selected, default to Release")
set(CMAKE_BUILD_TYPE "Release") set(CMAKE_BUILD_TYPE "Release")
endif() endif()
if (MSVC) #####################################
set(Boost_USE_STATIC_LIBS "On") # Define Options
find_package( Boost 1.52 COMPONENTS system thread regex REQUIRED ) #####################################
else() option(BUILD_EXAMPLES "Builds the examples in the project" ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++14 -pedantic -Wextra") option(BUILD_TESTING "Builds the tests in the project" ON)
find_package( Boost 1.52 COMPONENTS system thread REQUIRED )
#####################################
# Define CMake Module Imports
#####################################
include(${CMAKE_SOURCE_DIR}/cmake/dependencies.cmake)
include(${CMAKE_SOURCE_DIR}/cmake/compiler_options.cmake)
#####################################
# Define project-wide imports
#####################################
# this can be alternatively (and as recommended way) done with target_include_directories()
if(BUILD_EXAMPLES OR BUILD_TESTING)
set(PROJECT_INCLUDE_DIR
${CMAKE_SOURCE_DIR}/include
)
include_directories("${PROJECT_INCLUDE_DIR}")
include_directories("${CMAKE_SOURCE_DIR}")
include_directories("${CMAKE_CURRENT_BINARY_DIR}") # To include crow_all.h
endif() endif()
include_directories(${Boost_INCLUDE_DIR}) #####################################
# Define Targets
set(PROJECT_INCLUDE_DIR #####################################
${PROJECT_SOURCE_DIR}/include add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/crow_all.h
COMMAND python ${CMAKE_SOURCE_DIR}/scripts/merge_all.py
${CMAKE_SOURCE_DIR}/include
${CMAKE_CURRENT_BINARY_DIR}/crow_all.h
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
DEPENDS ${CMAKE_SOURCE_DIR}/include/*.h ${CMAKE_SOURCE_DIR}/include/crow/*.h ${CMAKE_SOURCE_DIR}/include/crow/middlewares/*.h
) )
include_directories("${PROJECT_INCLUDE_DIR}") # Amalgamation
include_directories("${PROJECT_SOURCE_DIR}") add_custom_target(amalgamation ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/crow_all.h)
include_directories("${CMAKE_CURRENT_BINARY_DIR}") # To include crow_all.h
add_subdirectory(examples) # Examples
if(BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
if (MSVC) # Tests
else() if (NOT MSVC AND BUILD_TESTING)
add_subdirectory(tests) add_subdirectory(tests)
enable_testing() enable_testing()
add_test(NAME crow_test COMMAND ${CMAKE_CURRENT_BINARY_DIR}/tests/unittest) add_test(NAME crow_test COMMAND ${CMAKE_CURRENT_BINARY_DIR}/tests/unittest)
add_test(NAME template_test COMMAND ${CMAKE_CURRENT_BINARY_DIR}/tests/template/test.py WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests/template) add_test(NAME template_test COMMAND ${CMAKE_CURRENT_BINARY_DIR}/tests/template/test.py WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests/template)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/crow_all.h
COMMAND python ${PROJECT_SOURCE_DIR}/scripts/merge_all.py
${PROJECT_SOURCE_DIR}/include
${CMAKE_CURRENT_BINARY_DIR}/crow_all.h
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
DEPENDS ${PROJECT_SOURCE_DIR}/include/*.h ${PROJECT_SOURCE_DIR}/include/crow/*.h ${PROJECT_SOURCE_DIR}/include/crow/middlewares/*.h
)
add_custom_target(amalgamation ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/crow_all.h)
endif() endif()
#####################################
# Install Files
#####################################
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/crow_all.h DESTINATION include) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/crow_all.h DESTINATION include)

View File

@ -0,0 +1,22 @@
# Compiler options with hardening flags
if(MSVC)
list(APPEND compiler_options
/W4
/permissive-
$<$<CONFIG:RELEASE>:/O2 /Ob2>
$<$<CONFIG:MINSIZEREL>:/O1 /Ob1>
$<$<CONFIG:RELWITHDEBINFO>:/Zi /O2 /Ob1>
$<$<CONFIG:DEBUG>:/Zi /Ob0 /Od /RTC1>)
else(MSVC)
list(APPEND compiler_options
-Wall
-Wextra
-Wpedantic
$<$<CONFIG:RELEASE>:-O2>
$<$<CONFIG:DEBUG>:-O0 -g -p -pg>)
endif()

35
cmake/dependencies.cmake Normal file
View File

@ -0,0 +1,35 @@
# Dependencies
if(BUILD_EXAMPLES OR BUILD_TESTING)
find_program(CCACHE_FOUND ccache)
if(CCACHE_FOUND)
message("Found ccache ${CCACHE_FOUND}")
message("Using ccache to speed up compilation")
set(ENV{CCACHE_CPP2} "yes")
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
endif(CCACHE_FOUND)
find_package(Tcmalloc)
find_package(Threads)
if (MSVC)
set(Boost_USE_STATIC_LIBS ON)
find_package( Boost 1.64.0 COMPONENTS system thread regex REQUIRED )
else()
find_package( Boost 1.64.0 COMPONENTS system thread REQUIRED )
endif()
if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIR})
endif()
endif()
if(BUILD_EXAMPLES)
# OpenSSL is needed at runtime dynamically by some examples
# if it isn't installed, the examples won't be built
find_package(OpenSSL)
if(OPENSSL_FOUND)
include_directories(${OPENSSL_INCLUDE_DIR})
endif()
endif()

View File

@ -1 +1,61 @@
***HELP NEEDED*** You can set Crow up behind any HTTP proxy of your liking, but we will be focusing specifically on 2 of the most popular web server software solutions, Apache2 and Nginx.<br><br>
A reverse proxy allows you to use Crow without exposing it directly to the internet. It also allows you to, for example, have crow run on a certain specific domain name, subdomain, or even a path, such as `domain.abc/crow`.<br><br>
We advise that you set crow up behind some form of reverse proxy if you plan on running a production Crow server that isn't local.<br>
!!! warning "SSL"
When using a proxy, make sure that you **do not** compile Crow with SSL enabled. SSL should be handled by the proxy.
##Apache2
Assuming you have both Apache2 and the modules [proxy](https://httpd.apache.org/docs/2.4/mod/mod_proxy.html), [proxy_http](https://httpd.apache.org/docs/2.4/mod/mod_proxy_http.html), [proxy_html](https://httpd.apache.org/docs/2.4/mod/mod_proxy_html.html) (if you plan on serving html pages), and [proxy_wstunnel](https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html) (if you plan on using websockets). You will need to enable those modules, which you can do using the following commands:
```sh
a2enmod proxy
a2enmod proxy_http
a2enmod proxy_html
a2enmod proxy_wstunnel
```
Next up you'll need to change your configuration (default is `/etc/apache2/sites-enabled/000-default.conf`) and add the following lines (replace `localhost` and `40080` with the address and port you defined for your Crow App):
```
ProxyPass / http://localhost:40080
ProxyPassReverse / http://localhost:40080
```
If you want crow to run in a subdirectory (such as `domain.abc/crow`) you can use the `location` tag:
```
<Location "/crow">
ProxyPass http://localhost:40080
ProxyPassReverse http://localhost:40080
</Location>
```
!!! note
If you're using an Arch Linux based OS. You will have to access `/etc/httpd/conf/httpd.conf` to enable modules and change configuration
##Nginx
Setting Nginx up is slightly simpler than Apache, all you need is the Nginx package itself. Once you've installed it, go to the configuration file (usually a `.conf` file located in `/etc/nginx`) and add the following lines to your server section (replace `localhost` and `40080` with the address and port you defined for your Crow App):
```
location / {
proxy_pass http://localhost:40080/;
proxy_http_version 1.1;
}
```
Remember to remove or comment out any existing `location /` section.<br><br>
Alternatively, if you want to use a subdirectory, you can simply change the location parameter as such:
```
location /crow/ {
proxy_pass http://localhost:40080/;
proxy_http_version 1.1;
}
```

View File

@ -1,3 +1,36 @@
https://www.howtogeek.com/687970/how-to-run-a-linux-program-at-startup-with-systemd/ Using Systemd allows you to run any executable or script when the system starts. This can be useful when you don't want to re-run your Crow application every single time you restart your server.<br><br>
***HELP NEEDED*** ##Writing the Service Unit File
In order to have Systemd recognize your application, you need to create a `.service` file that explains how Systemd should handle your program.<br><br>
To create a service file, you need to go to `/etc/systemd/system` and create an empty text file with the extension `.service`, the file name can be anything.<br><br>
Once the file is created, open it using your favorite text editor and add the following:
```sh
[Unit]
Description=My revolutionary Crow application
Wants=network.target
After=syslog.target network-online.target
[Service]
Type=simple
ExecStart=/absolute/path/to/your/executable
Restart=on-failure
RestartSec=10
KillMode=process
[Install]
WantedBy=multi-user.target
```
You will then need to give the correct permission, this can be done by using the following command (a `sudo` maybe required):
```sh
chmod 640 /etc/systemd/system/crowthing.service
```
And that's it! You can now use your `systemctl` controls to `enable`, `start`, `stop`, or `disable` your Crow application.<br><br>
If you're not familiar with Systemd, `systemctl enable crowthing.service` will allow your Crow application to run at startup, `start` will start it, and the rest is simple.

77
docs/guides/testing.md Normal file
View File

@ -0,0 +1,77 @@
Unit tests can be written in 2 ways for a Crow application.<br><br>
##The handler method
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.
```cpp linenums="1"
CROW_ROUTE(app, "/place")
([] { return "hi"; });
app.validate(); //Used to make sure all the route handlers are in order.
{
request req;
response res;
req.url = "/place";
app.handle(req, res); //res will contain a code of 200, and a response body of "hi"
}
```
!!! note
This method is the simpler of the two and is usually all you really need to test your routes.
!!! warning
This method does not send any data, nor does it run any post handle code, so things like static file serving (as far as sending the actual data) or compression cannot be tested using this method.
##The client method
This method involves creating a simple [ASIO](https://think-async.com/Asio/) client that sends the request and receives the response. It is considerably more complex than the earlier method, but it is both more realistic and includes post handle operations.
```cpp linenums="1"
static char buf[2048];
SimpleApp app;
CROW_ROUTE(app, "/")([] { return "A"; });
auto _ = async(launch::async,[&] { app1.bindaddr("127.0.0.1").port(45451).run(); });
app.wait_for_server_start();
std::string sendmsg = "GET /\r\nContent-Length:3\r\nX-HeaderTest: 123\r\n\r\nA=B\r\n";
asio::io_service is;
{
asio::ip::tcp::socket c(is);
c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string("127.0.0.1"), 45451));
c.send(asio::buffer(sendmsg));
size_t recved = c.receive(asio::buffer(buf, 2048));
CHECK('A' == buf[recved - 1]); //This is specific to catch2 testing library, but it should give a general idea of how to read the response.
}
app.stop(); //THIS MUST RUN
}
```
The first part is straightforward, create an app and add a route.<br>
The second part is launching the app asynchronously and waiting until it starts.<br>
The third is formulating our HTTP request string, the format is:
```
METHOD /
Content-Length:123
header1:value1
header2:value2
BODY
```
Next an `io_service` is created, then a TCP socket is created with the `io_service` and is connected to the application.<br>
Then send the HTTP request string through the socket inside a buffer, and read the result into the buffer in `line 1`.<br>
Finally check the result against the expected one.
!!! warning
Be absolutely sure that the line `app.stop()` runs, whether the test fails or succeedes. Not running it WILL CAUSE OTHER TESTS TO FAIL AND THE TEST TO HANG UNTIL THE PROCESS IS TERMINATED.

View File

@ -1,76 +1,75 @@
cmake_minimum_required(VERSION 3.15) cmake_minimum_required(VERSION 3.15)
project (crow_examples) project (crow_examples)
# Define Required libraries
list(APPEND REQUIRED_LIBRARIES
${Boost_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
${ZLIB_LIBRARIES}
)
if (MSVC) if (MSVC)
add_executable(example_vs example_vs.cpp) add_executable(example_vs example_vs.cpp)
target_link_libraries(example_vs ${Boost_LIBRARIES}) target_compile_options(example_vs PRIVATE "${compiler_options}")
target_link_libraries(example_vs ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(example_vs )
target_link_libraries(example_vs ${ZLIB_LIBRARIES})
else () else ()
add_executable(helloworld helloworld.cpp) add_executable(helloworld helloworld.cpp)
target_link_libraries(helloworld ${Boost_LIBRARIES}) target_compile_options(helloworld PRIVATE "${compiler_options}")
target_link_libraries(helloworld ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(helloworld PUBLIC ${REQUIRED_LIBRARIES})
target_link_libraries(helloworld ${ZLIB_LIBRARIES})
add_executable(example_static_file example_static_file.cpp) add_executable(example_compression example_compression.cpp)
target_link_libraries(example_static_file ${Boost_LIBRARIES}) target_compile_options(example_compression PRIVATE "${compiler_options}")
target_link_libraries(example_static_file ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(example_compression ${REQUIRED_LIBRARIES})
target_link_libraries(example_static_file ${ZLIB_LIBRARIES})
add_executable(example_compression example_compression.cpp) # If OpenSSL is not found, the example won't be built
target_link_libraries(example_compression ${Boost_LIBRARIES}) if (OPENSSL_FOUND)
target_link_libraries(example_compression ${CMAKE_THREAD_LIBS_INIT}) add_executable(example_ssl ssl/example_ssl.cpp)
target_link_libraries(example_compression ${ZLIB_LIBRARIES}) target_compile_options(example_ssl PRIVATE "${compiler_options}")
target_link_libraries(example_ssl PUBLIC ${REQUIRED_LIBRARIES} ${OPENSSL_LIBRARIES})
else()
message(STATUS "example_ssl Example deactivated - OpenSSL was not found")
endif()
if (OPENSSL_FOUND) add_executable(example_websocket websocket/example_ws.cpp)
add_executable(example_ssl ssl/example_ssl.cpp) target_compile_options(example_websocket PRIVATE "${compiler_options}")
target_link_libraries(example_ssl ${Boost_LIBRARIES}) target_link_libraries(example_websocket )
target_link_libraries(example_ssl ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES}) target_link_libraries(example_websocket PUBLIC ${REQUIRED_LIBRARIES})
target_link_libraries(example_ssl ${ZLIB_LIBRARIES}) add_custom_command(OUTPUT ws.html
endif() COMMAND ${CMAKE_COMMAND} -E
copy ${PROJECT_SOURCE_DIR}/websocket/templates/ws.html ${CMAKE_CURRENT_BINARY_DIR}/templates/ws.html
DEPENDS ${PROJECT_SOURCE_DIR}/websocket/templates/ws.html
)
add_custom_target(example_ws_copy ALL DEPENDS ws.html)
add_executable(example_websocket websocket/example_ws.cpp) add_executable(basic_example example.cpp)
target_link_libraries(example_websocket ${Boost_LIBRARIES}) target_compile_options(basic_example PRIVATE "${compiler_options}")
target_link_libraries(example_websocket ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES}) target_link_libraries(basic_example PUBLIC ${REQUIRED_LIBRARIES})
target_link_libraries(example_websocket ${ZLIB_LIBRARIES})
add_custom_command(OUTPUT ws.html
COMMAND ${CMAKE_COMMAND} -E
copy ${PROJECT_SOURCE_DIR}/websocket/templates/ws.html ${CMAKE_CURRENT_BINARY_DIR}/templates/ws.html
DEPENDS ${PROJECT_SOURCE_DIR}/websocket/templates/ws.html
)
add_custom_target(example_ws_copy ALL DEPENDS ws.html)
add_executable(basic_example example.cpp) if (Tcmalloc_FOUND)
target_link_libraries(basic_example ${Boost_LIBRARIES}) target_link_libraries(basic_example ${Tcmalloc_LIBRARIES})
target_link_libraries(basic_example ${CMAKE_THREAD_LIBS_INIT}) endif(Tcmalloc_FOUND)
target_link_libraries(basic_example ${ZLIB_LIBRARIES})
if (Tcmalloc_FOUND) add_executable(example_with_all example_with_all.cpp)
target_link_libraries(basic_example ${Tcmalloc_LIBRARIES}) add_dependencies(example_with_all amalgamation)
endif(Tcmalloc_FOUND) target_compile_options(example_with_all PRIVATE "${compiler_options}")
target_link_libraries(example_with_all PUBLIC ${REQUIRED_LIBRARIES})
add_executable(example_with_all example_with_all.cpp) add_custom_command(OUTPUT example_test.py
add_dependencies(example_with_all amalgamation) COMMAND ${CMAKE_COMMAND} -E
target_link_libraries(example_with_all ${Boost_LIBRARIES}) copy ${PROJECT_SOURCE_DIR}/example_test.py ${CMAKE_CURRENT_BINARY_DIR}/example_test.py
target_link_libraries(example_with_all ${CMAKE_THREAD_LIBS_INIT}) DEPENDS ${PROJECT_SOURCE_DIR}/example_test.py
target_link_libraries(example_with_all ${ZLIB_LIBRARIES}) )
add_custom_target(example_copy ALL DEPENDS example_test.py)
add_custom_command(OUTPUT example_test.py add_executable(example_chat example_chat.cpp)
COMMAND ${CMAKE_COMMAND} -E target_compile_options(example_chat PRIVATE "${compiler_options}")
copy ${PROJECT_SOURCE_DIR}/example_test.py ${CMAKE_CURRENT_BINARY_DIR}/example_test.py target_link_libraries(example_chat PUBLIC ${REQUIRED_LIBRARIES})
DEPENDS ${PROJECT_SOURCE_DIR}/example_test.py
)
add_custom_target(example_copy ALL DEPENDS example_test.py)
add_executable(example_chat example_chat.cpp) add_custom_command(OUTPUT example_chat.html
target_link_libraries(example_chat ${Boost_LIBRARIES}) COMMAND ${CMAKE_COMMAND} -E
target_link_libraries(example_chat ${CMAKE_THREAD_LIBS_INIT}) copy ${PROJECT_SOURCE_DIR}/example_chat.html ${CMAKE_CURRENT_BINARY_DIR}/example_chat.html
target_link_libraries(example_chat ${ZLIB_LIBRARIES}) DEPENDS ${PROJECT_SOURCE_DIR}/example_chat.html
add_custom_command(OUTPUT example_chat.html )
COMMAND ${CMAKE_COMMAND} -E add_custom_target(example_chat_copy ALL DEPENDS example_chat.html)
copy ${PROJECT_SOURCE_DIR}/example_chat.html ${CMAKE_CURRENT_BINARY_DIR}/example_chat.html
DEPENDS ${PROJECT_SOURCE_DIR}/example_chat.html
)
add_custom_target(example_chat_copy ALL DEPENDS example_chat.html)
endif() endif()

View File

@ -357,7 +357,6 @@ namespace crow
(*middlewares_, ctx_, req_, res); (*middlewares_, ctx_, req_, res);
} }
std::string accept_encoding = req_.get_header_value("Accept-Encoding"); std::string accept_encoding = req_.get_header_value("Accept-Encoding");
if (!accept_encoding.empty() && res.compressed) if (!accept_encoding.empty() && res.compressed)
{ {
@ -380,6 +379,17 @@ namespace crow
default: default:
break; break;
} }
//if there is a redirection with a partial URL, treat the URL as a route.
std::string location = res.get_header_value("Location");
if (!location.empty() && location.find("://", 0) == std::string::npos)
{
#ifdef CROW_ENABLE_SSL
location.insert(0, "https://" + req_.get_header_value("Host"));
#else
location.insert(0, "http://" + req_.get_header_value("Host"));
#endif
res.set_header("location", location);
} }
prepare_buffers(); prepare_buffers();
@ -415,8 +425,11 @@ namespace crow
{300, "HTTP/1.1 300 Multiple Choices\r\n"}, {300, "HTTP/1.1 300 Multiple Choices\r\n"},
{301, "HTTP/1.1 301 Moved Permanently\r\n"}, {301, "HTTP/1.1 301 Moved Permanently\r\n"},
{302, "HTTP/1.1 302 Moved Temporarily\r\n"}, {302, "HTTP/1.1 302 Found\r\n"},
{303, "HTTP/1.1 303 See Other\r\n"},
{304, "HTTP/1.1 304 Not Modified\r\n"}, {304, "HTTP/1.1 304 Not Modified\r\n"},
{307, "HTTP/1.1 307 Temporary Redirect\r\n"},
{308, "HTTP/1.1 308 Permanent Redirect\r\n"},
{400, "HTTP/1.1 400 Bad Request\r\n"}, {400, "HTTP/1.1 400 Bad Request\r\n"},
{401, "HTTP/1.1 401 Unauthorized\r\n"}, {401, "HTTP/1.1 401 Unauthorized\r\n"},

View File

@ -26,8 +26,8 @@ namespace crow
struct request struct request
{ {
HTTPMethod method; HTTPMethod method;
std::string raw_url; ///< The full URL containing the host. std::string raw_url; ///< The full URL containing the `?` and URL parameters.
std::string url; ///< The Endpoint. std::string url; ///< The endpoint without any parameters.
query_string url_params; ///< The parameters associated with the request. (everything after the `?`) query_string url_params; ///< The parameters associated with the request. (everything after the `?`)
ci_map headers; ci_map headers;
std::string body; std::string body;

View File

@ -100,7 +100,37 @@ namespace crow
completed_ = false; completed_ = false;
} }
/// Return a "Temporary Redirect" response.
///
/// Location can either be a route or a full URL.
void redirect(const std::string& location) void redirect(const std::string& location)
{
code = 307;
set_header("Location", location);
}
/// Return a "Permanent Redirect" response.
///
/// Location can either be a route or a full URL.
void redirect_perm(const std::string& location)
{
code = 308;
set_header("Location", location);
}
/// Return a "Found (Moved Temporarily)" response.
///
/// Location can either be a route or a full URL.
void moved(const std::string& location)
{
code = 302;
set_header("Location", location);
}
/// Return a "Moved Permanently" response.
///
/// Location can either be a route or a full URL.
void moved_perm(const std::string& location)
{ {
code = 301; code = 301;
set_header("Location", location); set_header("Location", location);

View File

@ -18,6 +18,7 @@ theme:
repo: fontawesome/brands/github-square repo: fontawesome/brands/github-square
markdown_extensions: markdown_extensions:
- admonition
- pymdownx.highlight - pymdownx.highlight
- pymdownx.superfences - pymdownx.superfences
- pymdownx.inlinehilite - pymdownx.inlinehilite
@ -40,6 +41,7 @@ nav:
- SSL: guides/ssl.md - SSL: guides/ssl.md
- Static Files: guides/static.md - Static Files: guides/static.md
- Websockets: guides/websockets.md - Websockets: guides/websockets.md
- Writing Tests: guides/testing.md
- Server setup: - Server setup:
- Proxies: guides/proxies.md - Proxies: guides/proxies.md
- Systemd run on startup: guides/syste.md - Systemd run on startup: guides/syste.md

View File

@ -6,10 +6,9 @@ set(TEST_SRCS
) )
add_executable(unittest ${TEST_SRCS}) add_executable(unittest ${TEST_SRCS})
target_link_libraries(unittest ${Boost_LIBRARIES}) target_link_libraries(unittest ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${ZLIB_LIBRARIES})
target_link_libraries(unittest ${CMAKE_THREAD_LIBS_INIT}) # set target compile options as defined in the cmake/compiler_options.cmake Module
target_link_libraries(unittest ${ZLIB_LIBRARIES}) target_compile_options(unittest PRIVATE ${compiler_options})
set_target_properties(unittest PROPERTIES COMPILE_FLAGS "-Wall -Werror -std=c++14")
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set_target_properties(unittest PROPERTIES COMPILE_FLAGS "--coverage -fprofile-arcs -ftest-coverage") set_target_properties(unittest PROPERTIES COMPILE_FLAGS "--coverage -fprofile-arcs -ftest-coverage")

View File

@ -10,8 +10,7 @@ set(TEST_SRCS
) )
add_executable(mustachetest ${TEST_SRCS}) add_executable(mustachetest ${TEST_SRCS})
set_target_properties(mustachetest PROPERTIES COMPILE_FLAGS "-Wall -Werror -std=c++14") target_compile_options(mustachetest PRIVATE "${compiler_options}")
file(COPY DIRECTORY . DESTINATION ${CMAKE_CURRENT_BINARY_DIR} FILES_MATCHING PATTERN "*.json") file(COPY DIRECTORY . DESTINATION ${CMAKE_CURRENT_BINARY_DIR} FILES_MATCHING PATTERN "*.json")
add_custom_command(OUTPUT test.py add_custom_command(OUTPUT test.py