diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29bb..000000000 diff --git a/.travis.yml b/.travis.yml index 038e6db6f..da40b46ca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,14 +30,12 @@ addons: packages: - libboost-all-dev - doxygen - - doxygen-doc - - doxygen-latex - - doxygen-gui + - mkdocs - graphviz before_install: - if [ "$TRAVIS_COMPILER" == "gcc" -a "$TRAVIS_CPU_ARCH" == "amd64" ]; then export PUSH_COVERAGE=ON; fi - - if [ "$TRAVIS_BRANCH" == "master" -a "$TRAVIS_PULL_REQUEST" == "false" -a "$PUSH_COVERAGE" == "ON" ]; then export TRAVIS_BUILD_DOCS=ON; fi + - if [ "$TRAVIS_BRANCH" == "master" -a "$TRAVIS_PULL_REQUEST" == "false" -a "$PUSH_COVERAGE" == "ON" ]; then export TRAVIS_BUILD_DOCS=ON; pip install mkdocs-material; fi install: - if [ "$PUSH_COVERAGE" == "ON" ]; then pip install --user cpp-coveralls; fi diff --git a/Doxyfile b/Doxyfile index 432e7aa5b..8eb0061fc 100644 --- a/Doxyfile +++ b/Doxyfile @@ -263,12 +263,6 @@ TAB_SIZE = 2 ALIASES = -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all @@ -990,7 +984,7 @@ FILTER_SOURCE_PATTERNS = # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. -USE_MDFILE_AS_MAINPAGE = readme.md +USE_MDFILE_AS_MAINPAGE = README.md #--------------------------------------------------------------------------- # Configuration options related to source browsing @@ -1119,7 +1113,7 @@ GENERATE_HTML = YES # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_OUTPUT = html +HTML_OUTPUT = site/reference # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). diff --git a/README.md b/README.md index b75081f77..6581ec9c1 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,39 @@ -![Crow logo](https://pixeldrain.com/api/file/DMc7xYye) +

-Crow is a C++ microframework for web. (inspired by Python Flask) +

A Fast and Easy to use microframework for the web.

+

+Build Status +Coverage Status +Documentation +Gitter +

-[![Build Status](https://travis-ci.com/mrozigor/crow.svg?branch=master)](https://travis-ci.com/mrozigor/crow) -[![Coverage Status](https://coveralls.io/repos/github/mrozigor/crow/badge.svg?branch=master)](https://coveralls.io/github/mrozigor/crow?branch=master) -[![Documentation](https://img.shields.io/badge/-Documentation-informational)](https://mrozigor.github.io/crow) -[![Gitter](https://badges.gitter.im/crowfork/community.svg)](https://gitter.im/crowfork/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +## Description + +Crow is a C++ microframework for running web services. It uses routing similar to Python's Flask which makes it easy to use. It is also extremely fast, beating multiple existing C++ frameworks as well as non C++ frameworks. + +### Features + - Easy Routing (similar to flask). + - Type-safe Handlers. + - Blazingly fast (see [this benchmark](https://github.com/ipkn/crow-benchmark) and [this benchmark](https://github.com/guteksan/REST-CPP-benchmark)). + - Built in JSON support. + - [Mustache](http://mustache.github.io/) based templating library (`crow::mustache`). + - Header only library (single header file available). + - Middleware support for extensions. + - HTTP/1.1 and Websocket support. + - Multi-part request and response support. + - Uses modern C++ (11/14) + +### Still in development + - [HTTP/2 support](https://github.com/mrozigor/crow/issues/8) + +## Documentation +Available [here](https://mrozigor.github.io/crow). + +## Examples + +#### Hello World ```c++ #include "crow.h" @@ -22,32 +49,8 @@ int main() } ``` -## Features - - - Easy routing - - Similiar to Flask - - Type-safe Handlers (see Example) - - Very Fast - - ![Benchmark Result in one chart](https://docs.google.com/spreadsheets/d/1KidO9XpuwCRZ2p_JRDJj2aep61H8Sh_KDOhApizv4LE/pubchart?oid=2041467789&format=image) - - More data on [crow-benchmark](https://github.com/ipkn/crow-benchmark) - - Fast built-in JSON parser (crow::json) - - You can also use [json11](https://github.com/dropbox/json11) or [rapidjson](https://github.com/miloyip/rapidjson) for better speed or readability - - [Mustache](http://mustache.github.io/) based templating library (crow::mustache) - - Header only - - All-in-one header file available - - Middleware support - - Websocket support - -## Still in development - - [Informational webpage](https://mrozigor.github.io/crow) (what is crow, guides, examples, etc..) - - [HTTP/2 support](https://github.com/mrozigor/crow/issues/8) - - ~~Built-in ORM~~ - - Check [sqlpp11](https://github.com/rbock/sqlpp11) if you want one. - -## Examples - #### JSON Response -```c++ +```cpp CROW_ROUTE(app, "/json") ([]{ crow::json::wvalue x; @@ -57,7 +60,7 @@ CROW_ROUTE(app, "/json") ``` #### Arguments -```c++ +```cpp CROW_ROUTE(app,"/hello/") ([](int count){ if (count > 100) @@ -68,7 +71,7 @@ CROW_ROUTE(app,"/hello/") }); ``` Handler arguments type check at compile time -```c++ +```cpp // Compile error with message "Handler type is mismatched with URL paramters" CROW_ROUTE(app,"/another/") ([](int a, int b){ @@ -77,7 +80,7 @@ CROW_ROUTE(app,"/another/") ``` #### Handling JSON Requests -```c++ +```cpp CROW_ROUTE(app, "/add_json") .methods("POST"_method) ([](const crow::request& req){ @@ -91,47 +94,17 @@ CROW_ROUTE(app, "/add_json") }); ``` -## How to Build +More examples can be found [here](https://github.com/mrozigor/crow/tree/master/examples). -If you just want to use crow, generate `crow_all.h` (use script `scripts/merge_all.py`) and include it. +## Setting Up / Building +Available [here](https://mrozigor.github.io/crow/getting_started/setup). -### Requirements - - - C++ compiler with good C++14 support. - - Tested on g++-9.3 and clang-7.0, AMD64 (x86_64) and Arm64 v8 - - boost 1.7 library. - - (optional) CMake to build tests and/or examples. - - (optional) Linking with tcmalloc/jemalloc is recommended for speed. - -### Building (Tests, Examples) - -Out-of-source build with CMake is recommended. - -``` -mkdir build -cd build -cmake .. -make -``` - -You can run tests with following commands: -``` -ctest -``` - -### Installing missing dependencies - -#### Ubuntu - sudo apt-get install build-essential libtcmalloc-minimal4 && sudo ln -s /usr/lib/libtcmalloc_minimal.so.4 /usr/lib/libtcmalloc_minimal.so - -#### OSX - brew install boost google-perftools ### Attributions Crow uses the following libraries. - http-parser + http-parser (used for converting http strings to crow::request objects) https://github.com/nodejs/http-parser @@ -160,7 +133,7 @@ Crow uses the following libraries. IN THE SOFTWARE. - qs_parse + qs_parse (used for reading query string parameters) https://github.com/bartgrantham/qs_parse @@ -175,7 +148,7 @@ Crow uses the following libraries. all copies or substantial portions of the Software. - TinySHA1 + TinySHA1 (used during the websocket handshake, not for security) https://github.com/mohaps/TinySHA1 diff --git a/docs/assets/crowlogo.svg b/docs/assets/crowlogo.svg new file mode 100644 index 000000000..056246387 --- /dev/null +++ b/docs/assets/crowlogo.svg @@ -0,0 +1,70 @@ + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/docs/assets/favicon.png b/docs/assets/favicon.png new file mode 100644 index 000000000..07d6489fa Binary files /dev/null and b/docs/assets/favicon.png differ diff --git a/docs/assets/favicon.svg b/docs/assets/favicon.svg new file mode 100644 index 000000000..1ee597f54 --- /dev/null +++ b/docs/assets/favicon.svg @@ -0,0 +1,66 @@ + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/docs/getting_started/setup.md b/docs/getting_started/setup.md new file mode 100644 index 000000000..03a0d75af --- /dev/null +++ b/docs/getting_started/setup.md @@ -0,0 +1,105 @@ +This page explains how to set Crow up for use with your porject. + + +##Requirements + - C++ compiler with good C++14 support. + - Continuous Testing on g++-9.3 and clang-7.0, AMD64 (x86_64) and Arm64 v8 + - C++11 should also work. + - boost library (1.70 or later). + - (optional) CMake and Python3 to build tests and/or examples. + - (optional) Linking with jemalloc/tcmalloc is recommended for speed. +

+ +##Installing Requirements +###Ubuntu +`sudo apt-get install libboost-all-dev` + +###OSX +`brew install boost` + +###Windows +Download boost from [here](https://www.boost.org/) and install it + +##Downloading +Either run `git clone https://github.com/mrozigor/crow.git` or download `crow_all.h` from the releases section. You can also download a zip of the project on github. + +##Includes folder +1. Copy the `/includes` folder to your project's root folder. +2. Add `#!cpp #include "path/to/includes/crow.h"` to your `.cpp` file. +3. For any middlewares, add `#!cpp #include "path/to/includes/middlewares/some_middleware.h"`. +

+ +##Single header file +If you've downloaded `crow_all.h`, you can skip to step 4. + +1. Make sure you have python 3 installed. +2. Open a terminal (or `cmd.exe`) instance in `/path/to/crow/scripts`. +3. Run `python merge_all.py ../include crow_all.h` (replace `/` with `\` if you're on Windows). +4. Copy the `crow_all.h` file to where you put your libraries (if you don't know where this is, you can put it anywhere). +5. Add `#!cpp #include "path/to/crow_all.h"` to your `.cpp` file. +

+**Note**: All middlewares are included with the merged header file, if you would like to include or exclude middlewares use the `-e` or `-i` arguments. +

+ +##building via CLI +To build a crow Project, do the following: + +###GCC (G++) + - Release: `g++ main.cpp -lpthread -lboost_system`. + - Debug: `g++ main.cpp -ggdb -lpthread -lboost_system -D CROW_ENABLE_DEBUG`. + - SSL: `g++ main.cpp -lssl -lpthread -lboost_system -D CROW_ENABLE_SSL`. + +###Clang + - Release: `clang++ main.cpp -lpthread -lboost_system`. + - Debug: `clang++ main.cpp -g -lpthread -lboost_system -DCROW_ENABLE_DEBUG`. + - SSL: `clang++ main.cpp -lssl -lpthread -lboost_system -DCROW_ENABLE_SSL`. + +###Microsoft Visual Studio +***Help needed*** + + +##building via CMake +Add the following to your `CMakeLists.txt`: +``` cmake linenums="1" +find_package(Threads) +find_package(OpenSSL) + +if(OPENSSL_FOUND) + include_directories(${OPENSSL_INCLUDE_DIR}) +endif() + +if (NOT CMAKE_BUILD_TYPE) + message(STATUS "No build type selected, default to Release") + set(CMAKE_BUILD_TYPE "Release") +endif() + +if (MSVC) + set(Boost_USE_STATIC_LIBS "On") + find_package( Boost 1.70 COMPONENTS system thread regex REQUIRED ) +else() + find_package( Boost 1.70 COMPONENTS system thread REQUIRED ) +endif() + +include_directories(${Boost_INCLUDE_DIR}) + +set(PROJECT_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include) + +include_directories("${PROJECT_INCLUDE_DIR}") +``` +**Note**: The last 2 lines are unnecessary if you're using `crow_all.h`. + +##Building Crow tests and examples +Out-of-source build with CMake is recommended. + +``` +mkdir build +cd build +cmake .. +make +``` +Running Cmake will create `crow_all.h` file and place it in the build directory. + +You can run tests with following commands: +``` +ctest -V +``` \ No newline at end of file diff --git a/docs/getting_started/your_first_application.md b/docs/getting_started/your_first_application.md new file mode 100644 index 000000000..1ee2d1597 --- /dev/null +++ b/docs/getting_started/your_first_application.md @@ -0,0 +1,55 @@ +This page shows how you can get started with a simple hello world application. + +##1. Include +Starting with an empty `main.cpp` file, add `#!cpp #include "crow.h"` or `#!cpp #include "crow_all.h"` if you're using the single header file. + +##2. App declaration +Next Create a `main()` and declare a `#!cpp crow::SimpleApp` inside, your code should look like this +``` cpp +int main() +{ + crow::SimpleApp app; +} +``` +The App (or SimpleApp) class organizes all the different parts of Crow and provides the developer (you) a simple interface to interact with these parts. +For more information, please go [here](/guides/app). + +##3. Adding routes +Once you have your app, the next step is to add routes (or endpoints). You can do so with the `CROW_ROUTE` macro. +``` cpp +CROW_ROUTE(app, "/")([](){ + return "Hello world"; +}); +``` +For more details on routes, please go [here](/guides/routes). + +#4. Running the app +Once you're happy with how you defined all your routes, you're going to want to instruct Crow to run your app. This is done using the `run()` method. +``` cpp +app.port(18080).multithreaded().run(); +``` +Please note that the `port()` and `multithreaded()` methods aren't needed, we just put them there to confuse you. Though not using `port()` will cause the default port (`80`) to be used.
+If you are using the default port, you can use `localhost` instead of `localhost:80` in your browser or client.
+ +##Putting it all together + +Once you've followed all the steps above, your code should look similar to this + +``` 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(); +} +``` +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. \ No newline at end of file diff --git a/docs/guides/app.md b/docs/guides/app.md new file mode 100644 index 000000000..639051958 --- /dev/null +++ b/docs/guides/app.md @@ -0,0 +1,29 @@ +A Crow app defines an interface to allow the developer access to all the different parts of the framework, without having to manually deal with each one.

+An app allows access to the http server (for handling connections), router (for handling URLs and requests), Middlewares (for extending Crow), amoung many others.

+ +Crow has 2 different app types: + +##SimpleApp +Has no middlewares. + +##App<m1, m2, ...> +Has middlewares. + +##Using the app +To use a Crow app, simply define `#!cpp crow::SimpleApp` or `#!cpp crow::App` if you're using middlewares.
+The methods of an app can be chained. That means that you can configure and run your app in the same code line. +``` cpp +app.bindaddr(192.168.1.2).port(443).ssl_file("certfile.crt","keyfile.key").multithreaded().run(); +``` +Or if you like your code neat +``` cpp +app.bindaddr(192.168.1.2) +.port(443) +.ssl_file("certfile.crt","keyfile.key") +.multithreaded() +.run(); +``` +

+ +For more info on middlewares, check out [this page](/guides/middleware).

+For more info on what functions are available to a Crow app, go [here](/reference/classcrow_1_1_crow.html). \ No newline at end of file diff --git a/docs/guides/json.md b/docs/guides/json.md new file mode 100644 index 000000000..544c354c5 --- /dev/null +++ b/docs/guides/json.md @@ -0,0 +1,29 @@ +Crow has built in support for JSON data.

+ +##rvalue +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.
+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`).

+ +For more info on read values go [here](/reference/classcrow_1_1json_1_1rvalue.html).

+ +#wvalue +JSON write value, used for creating, editing and converting JSON to a string.

+ +The types of values that `wvalue` can take are as follows:
+ +- `False`: from type `bool`. +- `True`: from type `bool`. +- `Number` + - `Floating_point`: from type `double`. + - `Signed_integer`: from type `int`. + - `Unsigned_integer`: from type `unsigned int`. +- `String`: from type `std::string`. +- `List`: from type `std::vector`. +- `Object`: from type `crow::json::wvalue`.
+This last type means that `wvalue` can have keys, this is done by simply assigning a value to whatever string key you like, something like `#!cpp wval["key1"] = val1;`. Keep in mind that val1 can be any of the above types.

+ +A JSON wvalue can be returned directly inside a route handler, this will canse the `content-type` header to automatically be set to `Application/json` and the JSON value will be converted to string and placed in the response body. For more information go to [Routes](/guides/routes).

+ +For more info on write values go [here](/reference/classcrow_1_1json_1_1wvalue.html). \ No newline at end of file diff --git a/docs/guides/logging.md b/docs/guides/logging.md new file mode 100644 index 000000000..66aa81eea --- /dev/null +++ b/docs/guides/logging.md @@ -0,0 +1,20 @@ +Crow comes with a simple and easy to use logging system.

+ +##Setting up logging level +You can set up the level at which crow displays logs by using the app's `loglevel(crow::logLevel)` method.

+ +The available log levels are as follows (please not that setting a level will also display all logs below this level): + +- Debug +- Info +- Warning +- Error +- Critical +

+ +To set a logLevel, just use `#!cpp app.loglevel(crow::logLevel::Warning)`, This will not show any debug or info logs. It will however still show error and critical logs.

+ +Please note that setting the Macro `CROW_ENABLE_DEBUG` during compilation will also set the log level to `Debug`. + +##Writing a log +Writing a log is as simple as `#!cpp CROW_LOG_ << "Hello";` (replace<LOG LEVEL> with the actual level in all caps, so you have `CROW_LOG_WARNING`). \ No newline at end of file diff --git a/docs/guides/middleware.md b/docs/guides/middleware.md new file mode 100644 index 000000000..856dddb1f --- /dev/null +++ b/docs/guides/middleware.md @@ -0,0 +1,29 @@ +Any middleware requires following 3 members: +##struct context +Storing data for the middleware; can be read from another middleware or handlers + + +##before_handle +Called before handling the request.
+If `res.end()` is called, the operation is halted. (`after_handle` will still be called)
+2 signatures:
+`#!cpp void before_handle(request& req, response& res, context& ctx)` + if you only need to access this middleware's context. +``` cpp +template +void before_handle(request& req, response& res, context& ctx, AllContext& all_ctx) +``` +You can access other middlewares' context by calling `#!cpp all_ctx.template get()`
+`#!cpp ctx == all_ctx.template get()` + + +##after_handle +Called after handling the request.
+ +`#!cpp void after_handle(request& req, response& res, context& ctx)` +``` cpp +template +void after_handle(request& req, response& res, context& ctx, AllContext& all_ctx) +``` +

+This was pulled from `cookie_parser.h`. Further Editing required, possibly use parts of [@ipkn's wiki page](https://github.com/ipkn/crow/wiki/Middleware). \ No newline at end of file diff --git a/docs/guides/multipart.md b/docs/guides/multipart.md new file mode 100644 index 000000000..645578ae7 --- /dev/null +++ b/docs/guides/multipart.md @@ -0,0 +1,20 @@ +Multipart is a way of forming HTTP requests or responses to contain multiple distinct parts.
+Such an approach allows a request to contain multiple different pieces of data with potentially conflicting data types in a single response payload.
+It is typically used either in html forms, or when uploading multiple files.

+ +The structure of a multipart request is typically consistent of:
+ +- A Header: Typically `multipart/form-data;boundary=`, This defines the HTTP message as being multipart, as well as defining the separator used to distinguish the different parts.
+- 1 or more parts: + - `--` + - Part header: typically `content-disposition: mime/type; name=""` (`mime/type` should be replaced with the actual mime-type), can also contain a `filename` property (separated from the rest by a `;` and structured similarly to the `name` property) + - Value +- `----`

+ +Crow supports multipart requests and responses though `crow::multipart::message`.
+A message can be created either by defining the headers, boundary, and individual parts and using them to create the message. or simply by reading a `crow::request`.

+ +Once a multipart message has been made, the individual parts can be accessed throught `mpmes.parts`, `parts` is an `std::vector`, so accessing the individual parts should be straightforward.
+In order to access the individual part's name or filename, something like `#!cpp mpmes.parts[0].headers[0].params["name"]` sould do the trick.

+ +For more info on Multipart messages, go [here](/reference/namespacecrow_1_1multipart.html) \ No newline at end of file diff --git a/docs/guides/proxies.md b/docs/guides/proxies.md new file mode 100644 index 000000000..1a78fefaa --- /dev/null +++ b/docs/guides/proxies.md @@ -0,0 +1 @@ +***HELP NEEDED*** \ No newline at end of file diff --git a/docs/guides/routes.md b/docs/guides/routes.md new file mode 100644 index 000000000..08b02581c --- /dev/null +++ b/docs/guides/routes.md @@ -0,0 +1,46 @@ +Routes define what happens when your client connects to a certain URL.
+ +##Macro +`CROW_ROUTE(app, url)`
+Can be replaced with `#!cpp app.route(url)` or `#!cpp app.route_dynamic(url)` if you're using VS2013 or want runtime url evaluation. Although this usage is **NOT** recommended. +##App +Which app class to assign the route to. +##Path (URL) +Which relative path is assigned to the route.
+Using `/hello` means the client will need to access `http://example.com/hello` in order to access the route.
+A path can have parameters, for example `/hello/` will allow a client to input an int into the url which will be in the handler (something like `http://example.com/hello/42`).
+Parameters can be ``, ``, ``, ``, or ``.
+It's worth nothing that the parameters also need to be defined in the handler, an example of using parameters would be to add 2 numbers based on input: +```cpp +CROW_ROUTE(app, "/add//") +([](int a, int b) +{ + return std::to_string(a+b); +}); +``` +you can see the first `` is defined as `a` and the second as `b`. If you were to run this and call `http://example.com/add/1/2`, the result would be a page with `3`. Exciting! +##Handler +Basically a piece of code that gets executed whenever the client calls the associated route, usually in the form of a [lambda expression](https://en.cppreference.com/w/cpp/language/lambda). It can be as simple as `#!cpp ([](){return "Hello World"})`.

+ +###Request +Handlers can also use information from the request by adding it as a parameter `#!cpp ([](const crow::request& req){...})`.

+ +You can also access the url parameters in the handler using `#!cpp req.url_params.get("param_name");`. If the parameter doesn't exist, `nullptr` is returned.

+ +For more information on `crow::request` go [here](/reference/structcrow_1_1request.html).

+ +###Response +Crow also provides the ability to define a response in the parameters by using `#!cpp ([](const crow::request& req, crow::response& res){...})`.
+If you don't want to use the request you can write `#!cpp ([](const crow::request& , crow::response& res){...})`.
+ Yes I know there's a pull request to make it as simple as `#!cpp ([](crow::response& res){...})`, but I can't test it and add it to the repository while writing this documentation.

+ +Please note that in order to return a response defined as a parameter you'll need to use `res.end();`.

+ +Alternatively, you can define the response in the body and return it (`#!cpp ([](){return crow::response()})`).
+ +For more information on `crow::response` go [here](/reference/structcrow_1_1response.html).

+ +###return statement +A `crow::response` is very strictly tied to a route. If you can have something in a response constructor, you can return it in a handler.

+The main return type is `std::string`. although you could also return a `crow::json::wvalue` directly. ***(Support for more data types including third party libraries is coming soon)***

+For more information on the specific constructors for a `crow::response` go [here](/reference/structcrow_1_1response.html). \ No newline at end of file diff --git a/docs/guides/ssl.md b/docs/guides/ssl.md new file mode 100644 index 000000000..ac3017b0e --- /dev/null +++ b/docs/guides/ssl.md @@ -0,0 +1,10 @@ +Crow supports HTTPS though SSL or TLS.

+ +When mentioning SSL in this documentation, it is often a reference to openSSL, which includes TLS. Don't worry, we don't use obsolete security standards :)

+ +To enable SSL, first your application needs to define either a `.crt` and `.key` files, or a `.pem` file. Once you have your files, you can add them to your app like this:
+`#!cpp app.ssl_file("/path/to/cert.crt", "/path/to/keyfile.key")` or `#!cpp app.ssl_file("/path/to/pem_file.pem")`. Please note that this method can be part of the app method chain, which means it can be followed by `.run()` or any other method.

+ +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.

+ +**IMPORTANT NOTICE**: If you plan on using a proxy like Nginx or Apache2, **DO NOT** use SSL in crow, instead define it in your proxy instead and keep the connection between the proxy and Crow non-SSL. \ No newline at end of file diff --git a/docs/guides/static.md b/docs/guides/static.md new file mode 100644 index 000000000..b28b9a88c --- /dev/null +++ b/docs/guides/static.md @@ -0,0 +1,14 @@ +A static file is any file that resides in the server's storage. + +Crow supports returning Static files as responses in 2 ways. + +##Implicit +Crow implicitly returns any static files placed in a `static` directory and any subdirectories, as long as the user calls the endpoint `/static/path/to/file`.

+The static folder or endpoint can be changed by defining the macros `CROW_STATIC_DRIECTORY "alternative_directory/"` and `CROW_STATIC_ENDPOINT "/alternative_endpoint/"`.
+static directory changes the directory in the server's filesystem, while the endpoint changes the URL that the client needs to access. + +##Explicit +You can directly return a static file by using the `crow::response` method `#!cpp response.set_static_file_info("path/to/file");`. The path is relative to the executable unless preceded by `/`, then it is an absolute path.
+Please keep in mind that using the `set_static_file_info` method does invalidate any data already in your response body.

+ +**Note**: Crow sets the `content-type` header automatically based on the file's extension, if an extension is unavailable or undefined, Crow uses `text/plain`, if you'd like to explicitly set a `content-type`, use `#!cpp response.set_header("content-type", "mime/type");` **AFTER** calling `set_static_file_info`. \ No newline at end of file diff --git a/docs/guides/syste.md b/docs/guides/syste.md new file mode 100644 index 000000000..3dab0f203 --- /dev/null +++ b/docs/guides/syste.md @@ -0,0 +1 @@ +https://www.howtogeek.com/687970/how-to-run-a-linux-program-at-startup-with-systemd/ diff --git a/docs/guides/templating.md b/docs/guides/templating.md new file mode 100644 index 000000000..ff7070f01 --- /dev/null +++ b/docs/guides/templating.md @@ -0,0 +1,23 @@ +Templating is when you return an html page with custom data. You can probably tell why that's useful.

+ +Crow supports [mustache](http://mustache.github.io) for templates through its own implementation `crow::mustache`.

+ +##Components of mustache + +There are 2 components of a mustaceh template: + +- Page +- Context + +###Page +The HTML page (including the mustache tags). usually loaded into `crow::mustache::template_t` Needs to be placed in "templates" directory (relative to where the crow executable is).

+ +For more inforation on how to formulate a template, see [this mustache manual](http://mustache.github.io/mustache.5.html). + +###Context +A JSON object containing the tags as keys and their values. `crow::mustache::context` is actually a [crow::json::wvalue](/guides/json#wvalue). + +##Returning a template +To return a mustache template, you need to load a page using `#!cpp auto page = crow::mustache::load("path/to/template.html");`, keep in mind that the path is relative to the templates directory.
+You also need to set up the context by useing `#!cpp crow::mustache::context ctx;`. Then you need to assign the keys and values, this can be done the same way you assign values to a json write value (`ctx["key"] = value;`).
+With your context and page ready, just `#!cpp return page.render(ctx);`. This will use the context data to return a filled template. \ No newline at end of file diff --git a/docs/guides/websockets.md b/docs/guides/websockets.md new file mode 100644 index 000000000..47d66c18e --- /dev/null +++ b/docs/guides/websockets.md @@ -0,0 +1,31 @@ +Websockets are a way of connecting a client and a server without the request response nature of HTTP.

+ +To create a websocket in Crow, you need a websocket route.
+A websocket route differs from a normal route quite a bit. While it uses the same `CROW_ROUTE(app, "/url")` macro, that's about where the similarities end.
+A websocket route follows the macro with `.websocket()` which is then followed by a series of methods (with handlers inside) for each event. These are: + +- `#!cpp onopen([&](crow::websocket::connection& conn){handler code goes here})` +- `#!cpp onaccept([&](const crow::request&){handler code goes here})` (This handler has to return bool) +- `#!cpp onmessage([&](crow::websocket::connection& conn, const std::string message, bool is_binary){handler code goes here})` +- `#!cpp onclose([&](crow::websocket::connection& conn, const std::string reason){handler code goes here})` +- `#!cpp onerror([&](crow::websocket::connection& conn){handler code goes here})`

+ +These event methods and their handlers can be chained. The full Route should look similar to this: +```cpp +CROW_ROUTE(app, "/ws") + .websocket() + .onopen([&](crow::websocket::connection& conn){ + do_something(); + }) + .onclose([&](crow::websocket::connection& conn, const std::string& reason){ + do_something(); + }) + .onmessage([&](crow::websocket::connection& /*conn*/, const std::string& data, bool is_binary){ + if (is_binary) + do_something(data); + else + do_something_else(data); + }); +``` +

+For more info go [here](/reference/classcrow_1_1_web_socket_rule.html). \ No newline at end of file diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 000000000..6327a2d7c --- /dev/null +++ b/docs/index.md @@ -0,0 +1,101 @@ +# +

+ +

A Fast and Easy to use microframework for the web.

+

+Build Status +Coverage Status +Documentation +Gitter +

+ + +## Description + +Crow is a C++ microframework for running web services. It uses routing similar to Python's Flask which makes it easy to use. It is also extremely fast, beating multiple existing C++ frameworks as well as non C++ frameworks. + +### Features + - Easy Routing (similar to flask). + - Type-safe Handlers. + - Blazingly fast (see [this benchmark](https://github.com/ipkn/crow-benchmark) and [this benchmark](https://github.com/guteksan/REST-CPP-benchmark)). + - Built in JSON support. + - [Mustache](http://mustache.github.io/) based templating library (`crow::mustache`). + - Header only library (single header file available). + - Middleware support for extensions. + - HTTP/1.1 and Websocket support. + - Multi-part request and response support. + - Uses modern C++ (11/14) + +### Still in development + - [HTTP/2 support](https://github.com/mrozigor/crow/issues/8) + +## Documentation +Available [here](https://mrozigor.github.io/crow). + +## Examples + +#### Hello World +```c++ +#include "crow.h" + +int main() +{ + crow::SimpleApp app; + + CROW_ROUTE(app, "/")([](){ + return "Hello world"; + }); + + app.port(18080).multithreaded().run(); +} +``` + +#### JSON Response +```cpp +CROW_ROUTE(app, "/json") +([]{ + crow::json::wvalue x; + x["message"] = "Hello, World!"; + return x; +}); +``` + +#### Arguments +```cpp +CROW_ROUTE(app,"/hello/") +([](int count){ + if (count > 100) + return crow::response(400); + std::ostringstream os; + os << count << " bottles of beer!"; + return crow::response(os.str()); +}); +``` +Handler arguments type check at compile time +```cpp +// Compile error with message "Handler type is mismatched with URL paramters" +CROW_ROUTE(app,"/another/") +([](int a, int b){ + return crow::response(500); +}); +``` + +#### Handling JSON Requests +```cpp +CROW_ROUTE(app, "/add_json") +.methods("POST"_method) +([](const crow::request& req){ + auto x = crow::json::load(req.body); + if (!x) + return crow::response(400); + int sum = x["a"].i()+x["b"].i(); + std::ostringstream os; + os << sum; + return crow::response{os.str()}; +}); +``` + +More examples can be found [here](https://github.com/mrozigor/crow/tree/master/examples). + +## Setting Up / Building +Available [here](https://mrozigor.github.io/crow/getting_started/setup). diff --git a/docs/stylesheets/Lato-Medium.ttf b/docs/stylesheets/Lato-Medium.ttf new file mode 100644 index 000000000..4684a7e14 Binary files /dev/null and b/docs/stylesheets/Lato-Medium.ttf differ diff --git a/docs/stylesheets/colors.css b/docs/stylesheets/colors.css new file mode 100644 index 000000000..aa0a82f38 --- /dev/null +++ b/docs/stylesheets/colors.css @@ -0,0 +1,6 @@ + +:root { + --md-primary-fg-color: #161616; + --md-accent-fg-color: #396A97; + --md-typeset-a-color: var(--md-accent-fg-color); +} diff --git a/docs/stylesheets/latofonts.css b/docs/stylesheets/latofonts.css new file mode 100644 index 000000000..97049c0ac --- /dev/null +++ b/docs/stylesheets/latofonts.css @@ -0,0 +1,10 @@ +/* Webfont: Lato-Medium */@font-face { + font-family: 'Lato'; + src: url('Lato-Medium.ttf') format('truetype'); + font-style: normal; + font-weight: normal; + text-rendering: optimizeLegibility; +} +body, input { + font-family: "Lato", -apple-system, Helvetica, Arial, sans-serif; +} diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 000000000..448b721fa --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,61 @@ +site_name: Crow + +# Repository +repo_name: mrozigor/crow +repo_url: https://github.com/mrozigor/crow +edit_uri: "" + +theme: + name: material + palette: + - scheme: Crow + font: false + language: 'en' + features: + navigation.tabs + favicon: 'assets/favicon.svg' + logo: 'assets/favicon.svg' + icon: + repo: fontawesome/brands/github-square + +markdown_extensions: + - pymdownx.highlight + - pymdownx.superfences + - pymdownx.inlinehilite + - pymdownx.keys + +nav: + - Home: index.md + - Getting Started: + - Setup: getting_started/setup.md + - Your First Application: getting_started/your_first_application.md + - Guides: + - Different parts of Crow: + - App: guides/app.md + - Routes: guides/routes.md + - Logging: guides/logging.md + - JSON: guides/json.md + - Templating (Mustache): guides/templating.md + - Multipart: guides/multipart.md + - Middleware: guides/middleware.md + - SSL: guides/ssl.md + - Static Files: guides/static.md + - Websockets: guides/websockets.md + - Server setup: + - Proxies: guides/proxies.md + - Systemd run on startup: guides/syste.md + - API Reference: + - API Reference: '/reference/index.html' + +extra: + social: + - icon: fontawesome/brands/github + link: https://github.com/mrozigor/crow + - icon: fontawesome/brands/gitter + link: https://gitter.im/crowfork/community + +extra_css: + - 'stylesheets/colors.css' + - 'stylesheets/latofonts.css' + +copyright: 'Copyright © 2020 Farook Al-Sammarraie' diff --git a/scripts/generateDocumentationAndDeploy.sh b/scripts/generateDocumentationAndDeploy.sh index dd995e73b..e5029be73 100644 --- a/scripts/generateDocumentationAndDeploy.sh +++ b/scripts/generateDocumentationAndDeploy.sh @@ -60,9 +60,15 @@ git config user.email "travis@travis-ci.org" # stayed the same and will only update the changed files. So the gh-pages branch # can be safely cleaned, and it is sure that everything pushed later is the new # documentation. -cp index.html .. +#cp index.html .. rm -rf * -mv ../index.html . +#mv ../index.html . + +# Copy the mkdocs documentation to the work directory and generate the mkdocs +# 'site' directory +cp ../../mkdocs.yml . +cp -r ../../docs . +mkdocs build # Need to create a .nojekyll file to allow filenames starting with an underscore # to be seen on the gh-pages site. Therefore creating an empty .nojekyll file. @@ -76,12 +82,21 @@ echo 'Generating Doxygen code documentation...' # Redirect both stderr and stdout to the log file AND the console. doxygen $DOXYFILE 2>&1 | tee doxygen.log +# Rename mkdocs' output folder to 'html' to retain compatibility with the +# existing index.html and the rest of this code. +# Also remove any remaining documentation files. +mv site/* . +rm -r site +rm mkdocs.yml +rm -r docs + ################################################################################ ##### Upload the documentation to the gh-pages branch of the repository. ##### # Only upload if Doxygen successfully created the documentation. -# Check this by verifying that the html directory and the file html/index.html -# both exist. This is a good indication that Doxygen did it's work. -if [ -d "html" ] && [ -f "html/index.html" ]; then +# Check this by verifying that the reference directory (for doxygen) and +# the file index.html (for mkdocs) both exist. +# This is a good indication that Doxygen and Mkdocs did their work. +if [ -d "reference" ] && [ -f "index.html" ]; then echo 'Uploading documentation to the gh-pages branch...' # Add everything in this directory (the Doxygen code documentation) to the