mirror of
https://github.com/CrowCpp/Crow.git
synced 2024-06-07 21:10:44 +00:00
Merge branch 'master' into master
This commit is contained in:
commit
dea78e02a0
@ -44,6 +44,10 @@ This will generate a `crow_all.h` file which you can use in the following steps
|
||||
|
||||
|
||||
## Building Crow's tests/examples
|
||||
!!!note
|
||||
|
||||
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.
|
||||
3. Get Crow's source code (the entire source code).
|
||||
@ -55,3 +59,17 @@ This will generate a `crow_all.h` file which you can use in the following steps
|
||||
!!!note
|
||||
|
||||
You can add options like `-DCROW_ENABLE_SSL`, `-DCROW_ENABLE_COMPRESSION`, or `-DCROW_AMALGAMATE` to `3.c` to build their tests/examples.
|
||||
|
||||
## Compiling using a compiler directly
|
||||
All you need to do is run the following command:
|
||||
```
|
||||
g++ main.cpp -lpthread
|
||||
```
|
||||
!!!note
|
||||
|
||||
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.
|
||||
|
@ -5,7 +5,7 @@ Here's how you can install Crow on your Windows machine.
|
||||
Crow can be simply installed through VCPKG using the command `vcpkg install crow`
|
||||
|
||||
### Manually (source or release)
|
||||
#### Microsoft Visual Studio 2019 and VCPKG
|
||||
#### Microsoft Visual Studio and VCPKG
|
||||
The following guide will use `example_with_all.cpp` as the Crow application for demonstration purposes. VCPKG will be used only to install Crow's dependencies.
|
||||
|
||||
1. Generate `crow_all.h` by navigating to the `scripts` folder and running `python3 merge_all.py ..\include crow_all.h`.
|
||||
|
71
docs/guides/auth.md
Normal file
71
docs/guides/auth.md
Normal file
@ -0,0 +1,71 @@
|
||||
While Crow doesn't directly support HTTP authentication, it does provide all the tools you need to build your own. This tutorial will show you how to setup basic and token authentication using Crow.
|
||||
|
||||
## Shared information
|
||||
Every way boils down to the same basic flow:
|
||||
- The handler calls a verification function.
|
||||
- The handler provides a `request` and \<optionally\> a `response`.
|
||||
- The function returns a `bool` or `enum` status.
|
||||
- Handler either continues or stops executing based on the returned status.
|
||||
- Either the function or handler modify and `end()` the `response` in case of failure.
|
||||
|
||||
For the purposes of this tutorial, we will assume that the verification function is defined as `#!cpp bool verify(crow::request req, crow::response res)`
|
||||
|
||||
## Basic Auth
|
||||
Basic HTTP authentication requires the client to send the Username and Password as a single string, separated by a colon (':') and then encoded as base64. This data needs to be placed in the `Authorization` header of the request. A sample header using the credentials "Username" and "Password" would look like this: `Authorization: Basic VXNlcm5hbWU6UGFzc3dvcmQ=`.<br><br>
|
||||
|
||||
We don't need to worry about creating the request, we only need to extract the credentials from the `Authorization` header and verify them.
|
||||
!!! note
|
||||
|
||||
There are multiple ways to verify the credentials. Most involve checking the username in a database, then checking a hash of the password against the stored password hash for that username. This tutorial will not go over them
|
||||
|
||||
<br>
|
||||
|
||||
To do this we first need to get the `Authorization` header as a string by using the following code:
|
||||
```cpp
|
||||
std::string myauth = req.get_header_value("Authorization");
|
||||
```
|
||||
<br>
|
||||
|
||||
Next we need to isolate our encoded credentials and decode them as follows:
|
||||
```cpp
|
||||
std::string mycreds = myauth.substr(6);
|
||||
std::string d_mycreds = crow::utility::base64decode(mycreds, mycreds.size()/*, URLSafe? (true/false)*/);
|
||||
```
|
||||
<br>
|
||||
|
||||
Now that we have our `username:password` string, we only need to separate it into 2 different strings and verify their validity:
|
||||
```cpp
|
||||
size_t found = d_mycreds.find(':');
|
||||
std::string username = d_mycreds.substr(0, found);
|
||||
std::string password = d_mycreds.substr(found+1);
|
||||
|
||||
/*Verify validity of username and password here*/
|
||||
return true; //or false if the username/password are invalid
|
||||
```
|
||||
|
||||
## Token Auth
|
||||
Tokens are some form of unique data that a server can provide to a client in order to verify the client's identity later. While on the surface level they don't provide more security than a strong password, they are designed to be less valuable by being *temporary* and providing *limited access*. Variables like expiration time and access scopes are heavily reliant on the implementation however.<br><br>
|
||||
|
||||
### Access Tokens
|
||||
The kind of the token itself can vary depending on the implementation and project requirements: Many services use randomly generated strings as tokens. Then compare them against a database to retrieve the associated user data. Some services however prefer using data bearing tokens. One example of the latter kind is JWT, which uses JSON strings encoded in base64 and signed using a private key or an agreed upon secret. While this has the added hassle of signing the token to ensure that it's not been tampered with. It does allow for the client to issue tokens without ever needing to present a password or contact a server. The server would simply be able to verify the signature using the client's public key or secret.<br><br>
|
||||
|
||||
### Using an Access Token
|
||||
Authenticating with an access token usually involves 2 stages: The first being acquiring the access token from an authority (either by providing credentials such as a username and a password to a server or generating a signed token). The scope of the token (what kind of information it can read or change) is usually defined in this step.<br><br>
|
||||
|
||||
The second stage is simply presenting the Token to the server when requesting a resource. This is even simpler than using basic authentication. All the client needs to do is provide the `Authorization` header with a keyword (usually `Bearer`) followed by the token itself (for example: `Authorization: Bearer ABC123`). Once the client has done that the server will need to acquire this token, which can easily be done as follows:<br>
|
||||
|
||||
```cpp
|
||||
std::string myauth = req.get_header_value("Authorization");
|
||||
std::string mycreds = myauth.substr(7); // The length can change based on the keyword used
|
||||
|
||||
/*Verify validity of the token here*/
|
||||
return true; //or false if the token is invalid
|
||||
```
|
||||
<br>
|
||||
The way of verifying the token is largely up to the implementation, and involves either Bearer token decoding and verification, or database access, neither of which is in this tutorial's scope.<br><br>
|
||||
|
||||
### Refresh Tokens
|
||||
Some services may choose to provide a refresh token alongside the access token. this token can be used to request a new access token if the existing one has expired. It provides convenience and security in that it makes it possible to acquire new access tokens without the need to expose a password. The downside however is that it can allow a malicious entity to keep its access to a compromised account. As such refresh tokens need to be handled with care, kept secure, and always invalidated as soon as a client logs out or requests a new access token.
|
||||
|
||||
## Sessions
|
||||
While Crow does not provide built in support for user sessions, a community member was kind enough to provide their own implementation on one of the related issue, their comment along with the code is available [here](https://github.com/CrowCpp/Crow/issues/144#issuecomment-860384771) (Please keep in mind that while we appreciate all efforts to push Crow forward, we cannot provide support for this implementation unless it becomes part of the core project).
|
@ -39,6 +39,7 @@ namespace crow
|
||||
using ssl_context_t = boost::asio::ssl::context;
|
||||
#endif
|
||||
/// The main server application
|
||||
|
||||
///
|
||||
/// Use `SimpleApp` or `App<Middleware1, Middleware2, etc...>`
|
||||
template<typename... Middlewares>
|
||||
@ -57,6 +58,7 @@ namespace crow
|
||||
{}
|
||||
|
||||
/// Process an Upgrade request
|
||||
|
||||
///
|
||||
/// Currently used to upgrrade an HTTP connection to a WebSocket connection
|
||||
template<typename Adaptor>
|
||||
@ -77,12 +79,16 @@ namespace crow
|
||||
return router_.new_rule_dynamic(std::move(rule));
|
||||
}
|
||||
|
||||
/// Create a route using a rule (**Use CROW_ROUTE instead**)
|
||||
///Create a route using a rule (**Use CROW_ROUTE instead**)
|
||||
template<uint64_t Tag>
|
||||
auto route(std::string&& rule)
|
||||
#ifdef CROW_CAN_USE_CPP17
|
||||
-> typename std::invoke_result<decltype(&Router::new_rule_tagged<Tag>), Router, std::string&&>::type
|
||||
#ifdef CROW_GCC83_WORKAROUND
|
||||
auto& route(std::string&& rule)
|
||||
#else
|
||||
auto route(std::string&& rule)
|
||||
#endif
|
||||
#if defined CROW_CAN_USE_CPP17 && !defined CROW_GCC83_WORKAROUND
|
||||
-> typename std::invoke_result<decltype(&Router::new_rule_tagged<Tag>), Router, std::string&&>::type
|
||||
#elif !defined CROW_GCC83_WORKAROUND
|
||||
-> typename std::result_of<decltype (&Router::new_rule_tagged<Tag>)(Router, std::string&&)>::type
|
||||
#endif
|
||||
{
|
||||
@ -157,6 +163,7 @@ namespace crow
|
||||
}
|
||||
|
||||
/// Set the server's log level
|
||||
|
||||
///
|
||||
/// Possible values are:<br>
|
||||
/// crow::LogLevel::Debug (0)<br>
|
||||
@ -218,6 +225,7 @@ namespace crow
|
||||
}
|
||||
#endif
|
||||
/// A wrapper for `validate()` in the router
|
||||
|
||||
///
|
||||
/// Go through the rules, upgrade them if possible, and add them to the list of rules
|
||||
void validate()
|
||||
|
@ -526,7 +526,18 @@ namespace crow
|
||||
{
|
||||
is_writing = true;
|
||||
boost::asio::write(adaptor_.socket(), buffers_);
|
||||
res.do_stream_file(adaptor_);
|
||||
|
||||
if (res.file_info.statResult == 0)
|
||||
{
|
||||
std::ifstream is(res.file_info.path.c_str(), std::ios::in | std::ios::binary);
|
||||
char buf[16384];
|
||||
while (is.read(buf, sizeof(buf)).gcount() > 0)
|
||||
{
|
||||
std::vector<asio::const_buffer> buffers;
|
||||
buffers.push_back(boost::asio::buffer(buf));
|
||||
do_write_sync(buffers);
|
||||
}
|
||||
}
|
||||
|
||||
res.end();
|
||||
res.clear();
|
||||
@ -552,8 +563,30 @@ namespace crow
|
||||
else
|
||||
{
|
||||
is_writing = true;
|
||||
boost::asio::write(adaptor_.socket(), buffers_);
|
||||
res.do_stream_body(adaptor_);
|
||||
boost::asio::write(adaptor_.socket(), buffers_); // Write the response start / headers
|
||||
if (res.body.length() > 0)
|
||||
{
|
||||
std::string buf;
|
||||
std::vector<asio::const_buffer> buffers;
|
||||
|
||||
while (res.body.length() > 16384)
|
||||
{
|
||||
//buf.reserve(16385);
|
||||
buf = res.body.substr(0, 16384);
|
||||
res.body = res.body.substr(16384);
|
||||
buffers.clear();
|
||||
buffers.push_back(boost::asio::buffer(buf));
|
||||
do_write_sync(buffers);
|
||||
}
|
||||
// Collect whatever is left (less than 16KB) and send it down the socket
|
||||
// buf.reserve(is.length());
|
||||
buf = res.body;
|
||||
res.body.clear();
|
||||
|
||||
buffers.clear();
|
||||
buffers.push_back(boost::asio::buffer(buf));
|
||||
do_write_sync(buffers);
|
||||
}
|
||||
|
||||
res.end();
|
||||
res.clear();
|
||||
@ -637,6 +670,31 @@ 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) {
|
||||
if (!ec)
|
||||
{
|
||||
if (close_connection_)
|
||||
{
|
||||
adaptor_.shutdown_write();
|
||||
adaptor_.close();
|
||||
CROW_LOG_DEBUG << this << " from write (sync)(1)";
|
||||
check_destroy();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
CROW_LOG_ERROR << ec << " - happened while sending buffers";
|
||||
CROW_LOG_DEBUG << this << " from write (sync)(2)";
|
||||
check_destroy();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void check_destroy()
|
||||
{
|
||||
CROW_LOG_DEBUG << this << " is_reading " << is_reading << " is_writing " << is_writing;
|
||||
|
@ -53,7 +53,6 @@ namespace crow
|
||||
return crow::get_header_value(headers, key);
|
||||
}
|
||||
|
||||
// TODO find a better way to format this so that stuff aren't moved down a line
|
||||
// clang-format off
|
||||
response() {}
|
||||
explicit response(int code) : code(code) {}
|
||||
@ -122,6 +121,7 @@ namespace crow
|
||||
}
|
||||
|
||||
/// Return a "Temporary Redirect" response.
|
||||
|
||||
///
|
||||
/// Location can either be a route or a full URL.
|
||||
void redirect(const std::string& location)
|
||||
@ -131,6 +131,7 @@ namespace crow
|
||||
}
|
||||
|
||||
/// Return a "Permanent Redirect" response.
|
||||
|
||||
///
|
||||
/// Location can either be a route or a full URL.
|
||||
void redirect_perm(const std::string& location)
|
||||
@ -140,6 +141,7 @@ namespace crow
|
||||
}
|
||||
|
||||
/// Return a "Found (Moved Temporarily)" response.
|
||||
|
||||
///
|
||||
/// Location can either be a route or a full URL.
|
||||
void moved(const std::string& location)
|
||||
@ -149,6 +151,7 @@ namespace crow
|
||||
}
|
||||
|
||||
/// Return a "Moved Permanently" response.
|
||||
|
||||
///
|
||||
/// Location can either be a route or a full URL.
|
||||
void moved_perm(const std::string& location)
|
||||
@ -201,6 +204,7 @@ namespace crow
|
||||
}
|
||||
|
||||
/// This constains metadata (coming from the `stat` command) related to any static files associated with this response.
|
||||
|
||||
///
|
||||
/// Either a static file or a string body can be returned as 1 response.
|
||||
struct static_file_info
|
||||
@ -242,89 +246,10 @@ namespace crow
|
||||
}
|
||||
}
|
||||
|
||||
/// Stream a static file.
|
||||
template<typename Adaptor>
|
||||
void do_stream_file(Adaptor& adaptor)
|
||||
{
|
||||
if (file_info.statResult == 0)
|
||||
{
|
||||
std::ifstream is(file_info.path.c_str(), std::ios::in | std::ios::binary);
|
||||
write_streamed(is, adaptor);
|
||||
}
|
||||
}
|
||||
|
||||
/// Stream the response body (send the body in chunks).
|
||||
template<typename Adaptor>
|
||||
void do_stream_body(Adaptor& adaptor)
|
||||
{
|
||||
if (body.length() > 0)
|
||||
{
|
||||
write_streamed_string(body, adaptor);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool completed_{};
|
||||
std::function<void()> complete_request_handler_;
|
||||
std::function<bool()> is_alive_helper_;
|
||||
static_file_info file_info;
|
||||
|
||||
template<typename Stream, typename Adaptor>
|
||||
void write_streamed(Stream& is, Adaptor& adaptor)
|
||||
{
|
||||
char buf[16384];
|
||||
while (is.read(buf, sizeof(buf)).gcount() > 0)
|
||||
{
|
||||
std::vector<asio::const_buffer> buffers;
|
||||
buffers.push_back(boost::asio::buffer(buf));
|
||||
write_buffer_list(buffers, adaptor);
|
||||
}
|
||||
}
|
||||
|
||||
// THIS METHOD DOES MODIFY THE BODY, AS IN IT EMPTIES IT
|
||||
template<typename Adaptor>
|
||||
void write_streamed_string(std::string& is, Adaptor& adaptor)
|
||||
{
|
||||
std::string buf;
|
||||
std::vector<asio::const_buffer> buffers;
|
||||
|
||||
while (is.length() > 16384)
|
||||
{
|
||||
//buf.reserve(16385);
|
||||
buf = is.substr(0, 16384);
|
||||
is = is.substr(16384);
|
||||
push_and_write(buffers, buf, adaptor);
|
||||
}
|
||||
// Collect whatever is left (less than 16KB) and send it down the socket
|
||||
// buf.reserve(is.length());
|
||||
buf = is;
|
||||
is.clear();
|
||||
push_and_write(buffers, buf, adaptor);
|
||||
}
|
||||
|
||||
template<typename Adaptor>
|
||||
inline void push_and_write(std::vector<asio::const_buffer>& buffers, std::string& buf, Adaptor& adaptor)
|
||||
{
|
||||
buffers.clear();
|
||||
buffers.push_back(boost::asio::buffer(buf));
|
||||
write_buffer_list(buffers, adaptor);
|
||||
}
|
||||
|
||||
template<typename Adaptor>
|
||||
inline void write_buffer_list(std::vector<asio::const_buffer>& buffers, Adaptor& adaptor)
|
||||
{
|
||||
boost::asio::write(adaptor.socket(), buffers, [this](std::error_code ec, std::size_t) {
|
||||
if (!ec)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
CROW_LOG_ERROR << ec << " - happened while sending buffers";
|
||||
this->end();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
} // namespace crow
|
||||
|
@ -295,7 +295,7 @@ namespace crow
|
||||
return static_cast<int>(i());
|
||||
}
|
||||
|
||||
///Return any json value (not object or list) as a string.
|
||||
/// Return any json value (not object or list) as a string.
|
||||
explicit operator std::string() const
|
||||
{
|
||||
#ifndef CROW_JSON_NO_ERROR_CHECK
|
||||
@ -405,7 +405,7 @@ namespace crow
|
||||
return detail::r_string{start_, end_};
|
||||
}
|
||||
|
||||
///The list or object value
|
||||
/// The list or object value
|
||||
std::vector<rvalue> lo()
|
||||
{
|
||||
#ifndef CROW_JSON_NO_ERROR_CHECK
|
||||
@ -684,7 +684,7 @@ namespace crow
|
||||
lremain_--;
|
||||
}
|
||||
|
||||
/// determines num_type from the string.
|
||||
/// Determines num_type from the string.
|
||||
void determine_num_type()
|
||||
{
|
||||
if (t_ != type::Number)
|
||||
@ -1221,8 +1221,9 @@ namespace crow
|
||||
|
||||
|
||||
/// JSON write value.
|
||||
|
||||
///
|
||||
/// Value can mean any json value, including a JSON object.
|
||||
/// Value can mean any json value, including a JSON object.<br>
|
||||
/// Write means this class is used to primarily assemble JSON objects using keys and values and export those into a string.
|
||||
class wvalue : public returnable
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
// This file is generated from nginx/conf/mime.types using nginx_mime2cpp.py
|
||||
// This file is generated from nginx/conf/mime.types using nginx_mime2cpp.py on 2021-12-03.
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
@ -21,6 +21,7 @@ namespace crow
|
||||
{"jad", "text/vnd.sun.j2me.app-descriptor"},
|
||||
{"wml", "text/vnd.wap.wml"},
|
||||
{"htc", "text/x-component"},
|
||||
{"avif", "image/avif"},
|
||||
{"png", "image/png"},
|
||||
{"svgz", "image/svg+xml"},
|
||||
{"svg", "image/svg+xml"},
|
||||
@ -58,6 +59,7 @@ namespace crow
|
||||
{"xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
|
||||
{"docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
|
||||
{"wmlc", "application/vnd.wap.wmlc"},
|
||||
{"wasm", "application/wasm"},
|
||||
{"7z", "application/x-7z-compressed"},
|
||||
{"cco", "application/x-cocoa"},
|
||||
{"jardiff", "application/x-java-archive-diff"},
|
||||
|
@ -23,6 +23,7 @@ namespace crow
|
||||
};
|
||||
|
||||
///One part of the multipart message
|
||||
|
||||
///
|
||||
/// It is usually separated from other sections by a `boundary`
|
||||
struct part
|
||||
|
@ -11,6 +11,7 @@
|
||||
namespace crow
|
||||
{
|
||||
/// A wrapper for `nodejs/http-parser`.
|
||||
|
||||
///
|
||||
/// Used to generate a \ref crow.request from the TCP socket buffer.
|
||||
template<typename Handler>
|
||||
|
@ -363,6 +363,7 @@ namespace crow
|
||||
}
|
||||
|
||||
/// Get a value from a name, used for `?name=value`.
|
||||
|
||||
///
|
||||
/// Note: this method returns the value of the first occurrence of the key only, to return all occurrences, see \ref get_list().
|
||||
char* get (const std::string& name) const
|
||||
@ -391,6 +392,7 @@ namespace crow
|
||||
}
|
||||
|
||||
/// Returns a list of values, passed as `?name[]=value1&name[]=value2&...name[]=valuen` with n being the size of the list.
|
||||
|
||||
///
|
||||
/// Note: Square brackets in the above example are controlled by `use_brackets` boolean (true by default). If set to false, the example becomes `?name=value1,name=value2...name=valuen`
|
||||
std::vector<char*> get_list (const std::string& name, bool use_brackets = true) const
|
||||
@ -429,6 +431,7 @@ namespace crow
|
||||
}
|
||||
|
||||
/// Works similar to \ref get_list() except the brackets are mandatory must not be empty.
|
||||
|
||||
///
|
||||
/// For example calling `get_dict(yourname)` on `?yourname[sub1]=42&yourname[sub2]=84` would give a map containing `{sub1 : 42, sub2 : 84}`.
|
||||
///
|
||||
|
@ -22,6 +22,7 @@ namespace crow
|
||||
constexpr const uint16_t INVALID_BP_ID{0xFFFF};
|
||||
|
||||
/// A base class for all rules.
|
||||
|
||||
///
|
||||
/// Used to provide a common interface for code dealing with different types of rules.<br>
|
||||
/// A Rule provides a URL, allowed HTTP methods, and handlers.
|
||||
@ -362,6 +363,7 @@ namespace crow
|
||||
|
||||
|
||||
/// A rule dealing with websockets.
|
||||
|
||||
///
|
||||
/// Provides the interface for the user to put in the necessary handlers for a websocket to work.
|
||||
class WebSocketRule : public BaseRule
|
||||
@ -437,6 +439,7 @@ namespace crow
|
||||
};
|
||||
|
||||
/// Allows the user to assign parameters using functions.
|
||||
|
||||
///
|
||||
/// `rule.name("name").methods(HTTPMethod::POST)`
|
||||
template<typename T>
|
||||
@ -715,7 +718,7 @@ namespace crow
|
||||
Trie()
|
||||
{}
|
||||
|
||||
///Check whether or not the trie is empty.
|
||||
/// Check whether or not the trie is empty.
|
||||
bool is_empty()
|
||||
{
|
||||
return head_.children.empty();
|
||||
@ -1084,6 +1087,7 @@ namespace crow
|
||||
};
|
||||
|
||||
/// A blueprint can be considered a smaller section of a Crow app, specifically where the router is conecerned.
|
||||
|
||||
///
|
||||
/// You can use blueprints to assign a common prefix to rules' prefix, set custom static and template folders, and set a custom catchall route.
|
||||
/// You can also assign nest blueprints for maximum Compartmentalization.
|
||||
|
@ -57,3 +57,11 @@
|
||||
#define noexcept throw()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ == 8 && __GNUC_MINOR__ < 4
|
||||
#if __cplusplus > 201103L
|
||||
#define CROW_GCC83_WORKAROUND
|
||||
#else
|
||||
#error "GCC 8.1 - 8.3 has a bug that prevents crow from compiling with C++11. Please update GCC to > 8.3 or use C++ > 11."
|
||||
#endif
|
||||
#endif
|
||||
|
@ -14,7 +14,7 @@ namespace crow
|
||||
using namespace boost;
|
||||
using tcp = asio::ip::tcp;
|
||||
|
||||
///A wrapper for the asio::ip::tcp::socket and asio::ssl::stream
|
||||
/// A wrapper for the asio::ip::tcp::socket and asio::ssl::stream
|
||||
struct SocketAdaptor
|
||||
{
|
||||
using context = void;
|
||||
|
@ -41,15 +41,13 @@ namespace crow
|
||||
CROW_LOG_DEBUG << "task_timer cancelled: " << this << ' ' << id;
|
||||
}
|
||||
|
||||
///
|
||||
/// Schedule the given task to be executed after the default amount of
|
||||
/// ticks.
|
||||
/// Schedule the given task to be executed after the default amount of ticks.
|
||||
|
||||
///
|
||||
/// \return identifier_type Used to cancel the thread.
|
||||
/// It is not bound to this task_timer instance and in some cases could lead to
|
||||
/// undefined behavior if used with other task_timer objects or after the task
|
||||
/// has been successfully executed.
|
||||
///
|
||||
identifier_type schedule(const task_type& task)
|
||||
{
|
||||
tasks_.insert(
|
||||
@ -60,8 +58,8 @@ namespace crow
|
||||
return highest_id_;
|
||||
}
|
||||
|
||||
///
|
||||
/// Schedule the given task to be executed after the given time.
|
||||
|
||||
///
|
||||
/// \param timeout The amount of ticks (seconds) to wait before execution.
|
||||
///
|
||||
@ -69,7 +67,6 @@ namespace crow
|
||||
/// It is not bound to this task_timer instance and in some cases could lead to
|
||||
/// undefined behavior if used with other task_timer objects or after the task
|
||||
/// has been successfully executed.
|
||||
///
|
||||
identifier_type schedule(const task_type& task, std::uint8_t timeout)
|
||||
{
|
||||
tasks_.insert({++highest_id_,
|
||||
@ -78,16 +75,13 @@ namespace crow
|
||||
return highest_id_;
|
||||
}
|
||||
|
||||
///
|
||||
/// Set the default timeout for this task_timer instance. (Default: 5)
|
||||
///
|
||||
/// \param timeout The amount of ticks (seconds) to wait before execution.
|
||||
///
|
||||
void set_default_timeout(std::uint8_t timeout) { default_timeout_ = timeout; }
|
||||
|
||||
///
|
||||
/// \param timeout The amount of ticks (seconds) to wait before execution.
|
||||
void set_default_timeout(std::uint8_t timeout) { default_timeout_ = timeout; }
|
||||
|
||||
/// Get the default timeout. (Default: 5)
|
||||
///
|
||||
std::uint8_t get_default_timeout() const { return default_timeout_; }
|
||||
|
||||
private:
|
||||
|
@ -64,12 +64,11 @@ namespace crow
|
||||
class Connection : public connection
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// Constructor for a connection.
|
||||
|
||||
///
|
||||
/// Requires a request with an "Upgrade: websocket" header.<br>
|
||||
/// Automatically handles the handshake.
|
||||
///
|
||||
Connection(const crow::request& req, Adaptor&& adaptor,
|
||||
std::function<void(crow::websocket::connection&)> open_handler,
|
||||
std::function<void(crow::websocket::connection&, const std::string&, bool)> message_handler,
|
||||
@ -120,11 +119,10 @@ namespace crow
|
||||
adaptor_.get_io_service().post(handler);
|
||||
}
|
||||
|
||||
///
|
||||
/// Send a "Ping" message.
|
||||
|
||||
///
|
||||
/// Usually invoked to check if the other point is still online.
|
||||
///
|
||||
void send_ping(const std::string& msg) override
|
||||
{
|
||||
dispatch([this, msg] {
|
||||
@ -135,11 +133,10 @@ namespace crow
|
||||
});
|
||||
}
|
||||
|
||||
///
|
||||
/// Send a "Pong" message.
|
||||
|
||||
///
|
||||
/// Usually automatically invoked as a response to a "Ping" message.
|
||||
///
|
||||
void send_pong(const std::string& msg) override
|
||||
{
|
||||
dispatch([this, msg] {
|
||||
@ -172,11 +169,10 @@ namespace crow
|
||||
});
|
||||
}
|
||||
|
||||
///
|
||||
/// Send a close signal.
|
||||
|
||||
///
|
||||
/// Sets a flag to destroy the object once the message is sent.
|
||||
///
|
||||
void close(const std::string& msg) override
|
||||
{
|
||||
dispatch([this, msg] {
|
||||
@ -224,11 +220,10 @@ namespace crow
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Send the HTTP upgrade response.
|
||||
|
||||
///
|
||||
/// Finishes the handshake process, then starts reading messages from the socket.
|
||||
///
|
||||
void start(std::string&& hello)
|
||||
{
|
||||
static std::string header = "HTTP/1.1 101 Switching Protocols\r\n"
|
||||
@ -246,14 +241,13 @@ namespace crow
|
||||
do_read();
|
||||
}
|
||||
|
||||
///
|
||||
/// Read a websocket message.
|
||||
|
||||
///
|
||||
/// Involves:<br>
|
||||
/// Handling headers (opcodes, size).<br>
|
||||
/// Unmasking the payload.<br>
|
||||
/// Reading the actual payload.<br>
|
||||
///
|
||||
void do_read()
|
||||
{
|
||||
is_reading = true;
|
||||
@ -482,11 +476,10 @@ namespace crow
|
||||
return (mini_header_ & 0x0f00) >> 8;
|
||||
}
|
||||
|
||||
///
|
||||
/// Process the payload fragment.
|
||||
|
||||
///
|
||||
/// Unmasks the fragment, checks the opcode, merges fragments into 1 message body, and calls the appropriate handler.
|
||||
///
|
||||
void handle_fragment()
|
||||
{
|
||||
if (has_mask_)
|
||||
@ -569,11 +562,10 @@ namespace crow
|
||||
fragment_.clear();
|
||||
}
|
||||
|
||||
///
|
||||
/// Send the buffers' data through the socket.
|
||||
|
||||
///
|
||||
/// Also destroyes the object if the Close flag is set.
|
||||
///
|
||||
void do_write()
|
||||
{
|
||||
if (sending_buffers_.empty())
|
||||
|
@ -53,6 +53,8 @@ nav:
|
||||
- Compression: guides/compression.md
|
||||
- Websockets: guides/websockets.md
|
||||
- Writing Tests: guides/testing.md
|
||||
- Using Crow:
|
||||
- HTTP Authorization: guides/auth.md
|
||||
- Server setup:
|
||||
- Proxies: guides/proxies.md
|
||||
- Systemd run on startup: guides/syste.md
|
||||
|
@ -3,24 +3,33 @@
|
||||
#get mime.types file from the nginx repository at nginx/conf/mime.types
|
||||
#typical output filename: mime_types.h
|
||||
import sys
|
||||
from datetime import date
|
||||
|
||||
if len(sys.argv) != 3:
|
||||
print("Usage: {} <NGINX_MIME_TYPE_FILE_PATH> <CROW_OUTPUT_HEADER_PATH>".format(sys.argv[0]))
|
||||
if (len(sys.argv) != 3) and (len(sys.argv) != 2):
|
||||
print("Usage (local file): {} <NGINX_MIME_TYPE_FILE_PATH> <CROW_OUTPUT_HEADER_PATH>".format(sys.argv[0]))
|
||||
print("(downloads file) : {} <CROW_OUTPUT_HEADER_PATH>".format(sys.argv[0]))
|
||||
sys.exit(1)
|
||||
|
||||
file_path = sys.argv[1]
|
||||
output_path = sys.argv[2]
|
||||
if len(sys.argv) == 3:
|
||||
file_path = sys.argv[1]
|
||||
output_path = sys.argv[2]
|
||||
elif len(sys.argv) == 2:
|
||||
import requests
|
||||
open("mime.types", "wb").write(requests.get("https://hg.nginx.org/nginx/raw-file/tip/conf/mime.types").content)
|
||||
file_path = "mime.types"
|
||||
output_path = sys.argv[1]
|
||||
|
||||
tabspace = " "
|
||||
tabandahalfspace = " "
|
||||
def main():
|
||||
outLines = []
|
||||
outLines.append("//This file is generated from nginx/conf/mime.types using nginx_mime2cpp.py")
|
||||
outLines.append("// This file is generated from nginx/conf/mime.types using nginx_mime2cpp.py on " + date.today().strftime('%Y-%m-%d') + ".")
|
||||
outLines.extend([
|
||||
"#include <unordered_map>",
|
||||
"#include <string>",
|
||||
"",
|
||||
"namespace crow {",
|
||||
tabspace + "const std::unordered_map<std::string, std::string> mime_types {"])
|
||||
"namespace crow",
|
||||
"{",
|
||||
tabspace + "const std::unordered_map<std::string, std::string> mime_types{"])
|
||||
|
||||
with open(file_path, "r") as mtfile:
|
||||
incomplete = ""
|
||||
@ -39,11 +48,8 @@ def main():
|
||||
incompleteExists = False
|
||||
outLines.extend(mime_line_to_cpp(splitLine))
|
||||
|
||||
outLines[-1] = outLines[-1][:-1]
|
||||
outLines.extend([
|
||||
tabspace + "};",
|
||||
"}"
|
||||
])
|
||||
outLines[-1] = outLines[-1][:-1] + "};"
|
||||
outLines.append("}")
|
||||
|
||||
with open(output_path, "w") as mtcppfile:
|
||||
mtcppfile.writelines(x + '\n' for x in outLines)
|
||||
@ -55,7 +61,7 @@ def mime_line_to_cpp(mlist):
|
||||
if (mlist[i].endswith(";")):
|
||||
mlist[i] = mlist[i][:-1]
|
||||
for i in range (len(mlist)-1, 0, -1):
|
||||
stringReturn.append(tabspace*2 + "{\"" + mlist[i] + "\", \"" + mlist[0] + "\"},")
|
||||
stringReturn.append(tabandahalfspace + "{\"" + mlist[i] + "\", \"" + mlist[0] + "\"},")
|
||||
#print("created: " + stringReturn)
|
||||
return stringReturn
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user