crowcpp / crow Goto Github PK
View Code? Open in Web Editor NEWA Fast and Easy to use microframework for the web.
Home Page: https://crowcpp.org
License: Other
A Fast and Easy to use microframework for the web.
Home Page: https://crowcpp.org
License: Other
I'm unable to compile Crow in Visual Studio 2019 using the combined crow_all.h file in an otherwise empty project with just the very simply Crow example.
Using the "Release v0.2" version of crow_all.h I get 31 compile errors. Using a version compile from the latest commit I get three errors as follows:
------ Build started: Project: \ConsoleApplication7, Configuration: Release x64 ------
ConsoleApplication7.cpp
Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:
- add -D_WIN32_WINNT=0x0601 to the compiler command line; or
- add _WIN32_WINNT=0x0601 to your project's Preprocessor Definitions.
Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target).
\ConsoleApplication7\crow_all.h(1089,37): warning C4267: '=': conversion from 'size_t' to 'int', possible loss of data
\ConsoleApplication7\crow_all.h(1338,1): warning C4267: 'argument': conversion from 'size_t' to 'int', possible loss of data
\ConsoleApplication7\crow_all.h(1351,1): warning C4267: 'argument': conversion from 'size_t' to 'int', possible loss of data
\ConsoleApplication7\crow_all.h(1366,1): warning C4267: 'argument': conversion from 'size_t' to 'int', possible loss of data
\ConsoleApplication7\crow_all.h(2777,39): warning C4267: 'argument': conversion from 'size_t' to 'uint32_t', possible loss of data
\ConsoleApplication7\crow_all.h(3043,1): warning C4267: 'return': conversion from 'size_t' to 'int', possible loss of data
\ConsoleApplication7\crow_all.h(3291,1): warning C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data
\ConsoleApplication7\crow_all.h(3310,1): warning C4267: '=': conversion from 'size_t' to 'int', possible loss of data
\ConsoleApplication7\crow_all.h(3312,1): warning C4267: 'argument': conversion from 'size_t' to '_Ty', possible loss of data
with
[
_Ty=int
]
\ConsoleApplication7\crow_all.h(3408,1): warning C4267: 'argument': conversion from 'size_t' to 'int', possible loss of data
\ConsoleApplication7\crow_all.h(3536,1): warning C4267: 'argument': conversion from 'size_t' to 'int', possible loss of data
\ConsoleApplication7\crow_all.h(3545,1): warning C4267: 'argument': conversion from 'size_t' to 'int', possible loss of data
\ConsoleApplication7\crow_all.h(3604,1): warning C4267: '=': conversion from 'size_t' to 'int', possible loss of data
\ConsoleApplication7\crow_all.h(3691,1): warning C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data
\ConsoleApplication7\crow_all.h(6240,42): warning C4244: '=': conversion from '__int64' to 'uint16_t', possible loss of data
\ConsoleApplication7\crow_all.h(6247,42): warning C4244: '=': conversion from '__int64' to 'uint16_t', possible loss of data
\ConsoleApplication7\crow_all.h(6254,42): warning C4244: '=': conversion from '__int64' to 'uint16_t', possible loss of data
\ConsoleApplication7\crow_all.h(6263,46): warning C4244: '=': conversion from '__int64' to 'uint16_t', possible loss of data
\ConsoleApplication7\crow_all.h(6356,31): warning C4244: '=': conversion from '__int64' to 'uint16_t', possible loss of data
\ConsoleApplication7\crow_all.h(6496,1): warning C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data
\ConsoleApplication7\crow_all.h(7937,1): warning C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data
\ConsoleApplication7\crow_all.h(8703,108): warning C4244: 'argument': conversion from '__int64' to 'unsigned int', possible loss of data
\ConsoleApplication7\crow_all.h(8721,109): warning C4244: 'argument': conversion from '__int64' to 'unsigned int', possible loss of data
\ConsoleApplication7\crow_all.h(8739,111): warning C4244: 'argument': conversion from '__int64' to 'unsigned int', possible loss of data
\ConsoleApplication7\crow_all.h(8758,1): warning C4267: 'argument': conversion from 'size_t' to 'unsigned int', possible loss of data
\ConsoleApplication7\crow_all.h(8771,1): warning C4267: 'argument': conversion from 'size_t' to 'unsigned int', possible loss of data
\ConsoleApplication7\crow_all.h(8784,1): warning C4267: 'argument': conversion from 'size_t' to 'unsigned int', possible loss of data
\ConsoleApplication7\crow_all.h(8826,1): warning C4267: '+=': conversion from 'size_t' to 'unsigned int', possible loss of data
\ConsoleApplication7\crow_all.h(8908,1): warning C4267: 'return': conversion from 'size_t' to 'unsigned int', possible loss of data
\ConsoleApplication7\crow_all.h(8954,1): warning C4267: 'argument': conversion from 'size_t' to 'unsigned int', possible loss of data
\ConsoleApplication7\crow_all.h(10513,19): error C2039: 'set_static_file_info': is not a member of 'crow::response'
\ConsoleApplication7\crow_all.h(7638): message : see declaration of 'crow::response'
\ConsoleApplication7\crow_all.h(10508): message : while compiling class template member function 'void crow::Crow<>::run(void)'
\ConsoleApplication7\\ConsoleApplication7.cpp(19): message : see reference to function template instantiation 'void crow::Crow<>::run(void)' being compiled
\ConsoleApplication7\\ConsoleApplication7.cpp(13): message : see reference to class template instantiation 'crow::Crow<>' being compiled
\ConsoleApplication7\crow_all.h(10508,1): error C2039: '__this': is not a member of 'crow::response'
\ConsoleApplication7\crow_all.h(7638): message : see declaration of 'crow::response'
Done building project "\ConsoleApplication7.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Thank you again for your work.
ipkn#319, ipkn#269
I've run into this problem myself (while testing SSL file transfer), although it doesn't happen all the time, and seems to happen randomly for me.
ipkn#347 is a possible fix
Edit: While i do believe the PR above is useful, it does not fix the SSL refresh issue, more research needed.
I was trying to build the websocket example in using G++ and the build seems to be failing and am not sure exactly what the problem is - I'm new to the language and terrible at debugging so trying to provide as much information as possible for potential bug (or more likely an issue on my environment).
OS - CentOS7 (RH)
gcc/g++ version 8.3.1.20190223
I'm not sure what version of boost I am using but pulled from github just the other day when building
I have Codeblocks to link with -lpthread and -lboost_system on build and also tried to add a search directory as /usr/local/include (just incase there was some link to this directory)
Line 10580 - Internal compiler error: in write_expression, at cp/mangle.c:3050
Codeblocks seems to pull open crow_all.h and points me to the following method:
//Create a route using a rule (**USE CROW_ROUTE instead**)
template <uint64_t Tag>
auto route(std::string&& rule)
-> typename std::result_of<decltype(&Router::new_rule_tagged<Tag>)(Router, std::string&&)>::type
{
return router_.new_rule_tagged<Tag>(std::move(rule));
}
Let me know i you have any questions I have missed or suggestions
I'm sorry if this has already been addressed, but I'm wondering about writing a basic unit test.
For example, the type of test you might write for Flask, and simulating a client request:
def test_empty_db(client):
"""Start with a blank database."""
rv = client.get('/')
assert b'No entries here so far' in rv.data
I thought I might find something here, but I haven't. Can anyone point me in the right direction?
middleware.h
only contains a cookie handling middleware, while it's important to handle cookies, the middleware isn't being used by any core part, neither is it necessary to run a basic server.
I suggest separating the cookie parser and more middlewares into a separate repository. or at least a name change.
@mrozigor what do you think?
from ipkn/crow#377
The problem with some of the comments there though is that they use line numbers in crow_all.h which means that the smallest change in any header file puts that number way off. Best to use method names or namespaces.
Support the websocket extension permessage-deflate
. ipkn/crow#329 should help (use existing zlib implementation if possible)
Let users set the server name
I'm using crow for a lightweight webservices server and I have to implement a CZML one, which requires event-stream.
Is it already supported in any way?
As a Visual Studio user it seems to be beyond me to be able to build the "crow_all.h" file myself.
Is there any chance someone could provide this file here, as they used to do on the previous version of the project? It would be a huge help to those of us less competent.
If that's not feasible, then perhaps you could provide an simple example of how the "merge_all.py" script should be used, because right now it makes no sense to me.
Many thanks for all your efforts.
Crow currently uses version 2.3.0
, latest version is 2.9.4
, might be best to upgrade since a skim of the changelog shows memory leak plugs.
Some way of combining similar requests or modulating the application, with their own prefixes, and maybe even middlewares.
Based on Flask's blueprints
Compiler complaints the following which does not happened in BOOST version == 1.74 and it does not happened in ipkn/crow master branch.
/home/workspace/http_server_c/crow/include/crow/http_response.h:188:106: note: no known conversion for argument 1 from ‘boost::system::error_code’ to ‘std::error_code’
In file included from /home/workspace/http_server_c/crow/include/crow/http_response.h:7:0,
from /home/workspace/http_server_c/crow/include/crow/routing.h:12,
from /home/workspace/http_server_c/crow/include/crow/app.h:16,
from /home/workspace/http_server_c/crow/include/crow.h:3,
from examples/helloworld.cpp:1:
/home/workspace/http_server_c/crow/include/crow/json.h: In function ‘void crow::json::escape(const string&, std::__cxx11::string&)’:
/home/workspace/http_server_c/crow/include/crow/json.h:50:31: warning: comparison is always true due to limited range of data type [-Wtype-limits]
if (0 <= c && c < 0x20)
^
In file included from /home/local/libs/armnn-devenv/boost_armhf_install/include/boost/asio/write.hpp:618:0,
from /home/local/libs/armnn-devenv/boost_armhf_install/include/boost/asio/buffered_write_stream.hpp:29,
from /home/local/libs/armnn-devenv/boost_armhf_install/include/boost/asio/buffered_stream.hpp:22,
from /home/local/libs/armnn-devenv/boost_armhf_install/include/boost/asio.hpp:38,
from /home/workspace/http_server_c/crow/include/crow/http_request.h:3,
from /home/workspace/http_server_c/crow/include/crow/http_response.h:8,
from /home/workspace/http_server_c/crow/include/crow/routing.h:12,
from /home/workspace/http_server_c/crow/include/crow/app.h:16,
from /home/workspace/http_server_c/crow/include/crow.h:3,
from examples/helloworld.cpp:1:
/home/local/libs/armnn-devenv/boost_armhf_install/include/boost/asio/impl/write.hpp: In instantiation of ‘std::size_t boost::asio::write(SyncWriteStream&, const ConstBufferSequence&, CompletionCondition, boost::system::error_code&) [with SyncWriteStream = boost::asio::basic_stream_socket<boost::asio::ip::tcp>; ConstBufferSequence = std::vector<boost::asio::const_buffer>; CompletionCondition = crow::response::do_write_sendfile(Adaptor) [with Adaptor = crow::SocketAdaptor*]::<lambda(std::error_code, std::size_t)>; std::size_t = unsigned int]’:
/home/local/libs/armnn-devenv/boost_armhf_install/include/boost/asio/impl/write.hpp:80:40: required from ‘std::size_t boost::asio::write(SyncWriteStream&, const ConstBufferSequence&, CompletionCondition) [with SyncWriteStream = boost::asio::basic_stream_socket<boost::asio::ip::tcp>; ConstBufferSequence = std::vector<boost::asio::const_buffer>; CompletionCondition = crow::response::do_write_sendfile(Adaptor) [with Adaptor = crow::SocketAdaptor*]::<lambda(std::error_code, std::size_t)>; std::size_t = unsigned int]’
/home/workspace/http_server_c/crow/include/crow/http_response.h:188:39: required from ‘void crow::response::do_write_sendfile(Adaptor) [with Adaptor = crow::SocketAdaptor*]’
/home/workspace/http_server_c/crow/include/crow/http_connection.h:471:13: required from ‘void crow::Connection<Adaptor, Handler, Middlewares>::do_write_static() [with Adaptor = crow::SocketAdaptor; Handler = crow::Crow<>; Middlewares = {}]’
/home/workspace/http_server_c/crow/include/crow/http_connection.h:358:32: required from ‘void crow::Connection<Adaptor, Handler, Middlewares>::complete_request() [with Adaptor = crow::SocketAdaptor; Handler = crow::Crow<>; Middlewares = {}]’
/home/workspace/http_server_c/crow/include/crow/http_connection.h:322:61: required from ‘crow::Connection<Adaptor, Handler, Middlewares>::handle()::<lambda()> [with Adaptor = crow::SocketAdaptor; Handler = crow::Crow<>; Middlewares = {}]’
/home/workspace/http_server_c/crow/include/crow/http_connection.h:322:54: [ skipping 13 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/home/workspace/http_server_c/crow/include/crow/http_server.h:197:25: required from ‘crow::Server<Handler, Adaptor, Middlewares>::do_accept()::<lambda(boost::system::error_code)> [with Handler = crow::Crow<>; Adaptor = crow::SocketAdaptor; Middlewares = {}]’
/home/workspace/http_server_c/crow/include/crow/http_server.h:193:28: required from ‘struct crow::Server<Handler, Adaptor, Middlewares>::do_accept() [with Handler = crow::Crow<>; Adaptor = crow::SocketAdaptor; Middlewares = {}]::<lambda(class boost::system::error_code)>’
/home/workspace/http_server_c/crow/include/crow/http_server.h:192:13: required from ‘void crow::Server<Handler, Adaptor, Middlewares>::do_accept() [with Handler = crow::Crow<>; Adaptor = crow::SocketAdaptor; Middlewares = {}]’
/home/workspace/http_server_c/crow/include/crow/http_server.h:160:22: required from ‘void crow::Server<Handler, Adaptor, Middlewares>::run() [with Handler = crow::Crow<>; Adaptor = crow::SocketAdaptor; Middlewares = {}]’
/home/workspace/http_server_c/crow/include/crow/app.h:123:17: required from ‘void crow::Crow<Middlewares>::run() [with Middlewares = {}]’
examples/helloworld.cpp:12:25: required from here
/home/local/libs/armnn-devenv/boost_armhf_install/include/boost/asio/impl/write.hpp:46:29: error: no match for call to ‘(crow::response::do_write_sendfile(Adaptor) [with Adaptor = crow::SocketAdaptor*]::<lambda(std::error_code, std::size_t)>) (boost::system::error_code&, std::size_t&)’
completion_condition(ec, total_transferred)));
^
In file included from /home/workspace/http_server_c/crow/include/crow/routing.h:12:0,
from /home/workspace/http_server_c/crow/include/crow/app.h:16,
from /home/workspace/http_server_c/crow/include/crow.h:3,
from examples/helloworld.cpp:1:
/home/workspace/http_server_c/crow/include/crow/http_response.h:188:106: note: candidate: crow::response::do_write_sendfile(Adaptor)::<lambda(std::error_code, std::size_t)> [with Adaptor = crow::SocketAdaptor*; std::size_t = unsigned int]
boost::asio::write(adaptor->socket(), buffers, [this](std::error_code ec, std::size_t)
^
/home/workspace/http_server_c/crow/include/crow/http_response.h:188:106: note: no known conversion for argument 1 from ‘boost::system::error_code’ to ‘std::error_code’
In file included from /home/local/libs/armnn-devenv/boost_armhf_install/include/boost/asio/write.hpp:618:0,
from /home/local/libs/armnn-devenv/boost_armhf_install/include/boost/asio/buffered_write_stream.hpp:29,
from /home/local/libs/armnn-devenv/boost_armhf_install/include/boost/asio/buffered_stream.hpp:22,
from /home/local/libs/armnn-devenv/boost_armhf_install/include/boost/asio.hpp:38,
from /home/workspace/http_server_c/crow/include/crow/http_request.h:3,
from /home/workspace/http_server_c/crow/include/crow/http_response.h:8,
from /home/workspace/http_server_c/crow/include/crow/routing.h:12,
from /home/workspace/http_server_c/crow/include/crow/app.h:16,
from /home/workspace/http_server_c/crow/include/crow.h:3,
from examples/helloworld.cpp:1:
/home/local/libs/armnn-devenv/boost_armhf_install/include/boost/asio/impl/write.hpp:53:31: error: no match for call to ‘(crow::response::do_write_sendfile(Adaptor) [with Adaptor = crow::SocketAdaptor*]::<lambda(std::error_code, std::size_t)>) (boost::system::error_code&, std::size_t&)’
completion_condition(ec, total_transferred)));
^
In file included from /home/workspace/http_server_c/crow/include/crow/routing.h:12:0,
from /home/workspace/http_server_c/crow/include/crow/app.h:16,
from /home/workspace/http_server_c/crow/include/crow.h:3,
from examples/helloworld.cpp:1:
/home/workspace/http_server_c/crow/include/crow/http_response.h:188:106: note: candidate: crow::response::do_write_sendfile(Adaptor)::<lambda(std::error_code, std::size_t)> [with Adaptor = crow::SocketAdaptor*; std::size_t = unsigned int]
boost::asio::write(adaptor->socket(), buffers, [this](std::error_code ec, std::size_t)
^
/home/workspace/http_server_c/crow/include/crow/http_response.h:188:106: note: no known conversion for argument 1 from ‘boost::system::error_code’ to ‘std::error_code’
Makefile:52: recipe for target 'helloworld' failed
https://crowcpp.org/guides/templating/ states:
The HTML page (including the mustache tags). It is usually loaded into crow::mustache::template_t. It needs to be placed in templates directory (relative to where the crow executable is).
This seems to be incorrect on version 0.2 at least, where it seems that the templates/
folder needs to be in the current working directory.
So it should state:
The HTML page (including the mustache tags). It is usually loaded into crow::mustache::template_t. It needs to be placed in the templates directory which should be in the current working directory of the crow executable.
Missing template files get silently ignored (even on the debug log level), too. This should not be the case...
To put it simply, if you want Crow to run SSL (I mean OpenSSL, which includes TLS), you have to enable it using the flag CROW_ENABLE_SSL, which means that a program can either be compiled as SSL or not. Yet when compiling for SSL, Crow retains almost all the non SSL functionality (I'm saying almost because i'm not 100% sure it retains all the classes and methods). All these classes go unused since now all the routes are defined for HTTPS rather than HTTP. This creates 2 main consequences:
This is a problem primarily because a large portion of the code is just going unused. Either all non SSL classes should be removed if SSL is enabled, or Crow should automatically redirect HTTP requests to HTTPS.
Thinking about this, it might be possible to have a non SSL crow app only to redirect to the SSL version, although testing is needed to confirm or deny this.
in response to ipkn/crow#45, ipkn/crow#180, ipkn/crow#288.
We could either use the wiki and just explain things or set something like doxygen up.
either way some explanation as to how every part works and some form of API reference is needed.
We have .travis.yml, we just might need to change things like the compiler or notification channel, and we'll be able to run unit tests again.
#7 probably depends on this.
So the API reference is coming along nicely (about as nice as trying to type what I learned in the past 20 minutes in a coherent readable manner).
But I don't believe this is it, sure it is helpful if someone wants to go to the next level in using crow (or even editing it). But there should be something for people who are just starting out with Crow or C++ even (me 2 months ago).
Currently we have examples to fulfill this role. But I get the feeling They're not enough. Things like setting up the environment, connecting to a proxy, compiling with SSL, creating middlewares, even creating crow_all.h are not in these examples, and frankly the examples themselves aren't documented, they don't mention any quirks or tricks that might come up, nor do they explain why things are the way they are.
To be frank, currently our documentation mirrors that of ASIO, which holy crap do I hate going through.
So the solution in my opinion is having the API reference (doxygen stuff) be only 1 part of a much larger documentation effort, @ipkn was trying to accomplish this via the wiki. This could be done the same way or through increasing the size of the github.io to add tutorials, introductions, and explanations (they all probably mean the same thing I'm just overexpressing).
We can later move this out of github.io into our own website, I mean.. we have a logo, the only thing left is everything else.
I believe this is an important step to take for crow to go from "just another C++ project" to something actually viable in a production environment, and I would like it if we could do this either before or around v0.3 (I know the line between0.3 and 1.0 is getting more and more blurry).
ipkn#169, ipkn#46, ipkn#37, ipkn#8
Seems to be the logical continuation of static file serving, because as far as I understand, the connection times out regardless of what's going on, so a large static file is extremely likely not to be sent fully.
implemented in ipkn#312
Currently Crow uses the http and websocket proxy modules in Apache and Nginx to allow them to handle connections rather than crow itself. This can be slow and a potentially better approach would be to instead have a module translate the HTTP requests to Crow format and responses to something Apache and Nginx can send.
In response to ipkn/crow#371
ipkn#144
Should support compression and decompression for http requests.
This could be needed before HTTP/2 could be implemented.
Basically have a folder for every crow version + a latest folder, update only the latest folder, then a release rename latest to version name.
As this version is maintained and the ipkn version is not, could you push your fork to Conan one day?
It is not quite great to only have the unmaintained version there.
Lambdas are optional element in mustache spec. Currently not implemented at all.
In response to ipkn/crow#367
I just compiled the example HTTP hello_world program with clang-10.0.0-4ubuntu1
and lld-10.0.0
:
clang++ -std=c++17 -Oz -Wall -flto -fno-asynchronous-unwind-tables -fno-unwind-tables -fmerge-all-constants
-I /path/to/crow/ -fvisibility=hidden
-s -Wl,-icf=all,--gc-sections,--as-needed -flto -Wl,--plugin-opt=O3 -fuse-ld=lld
-lpthread -lboost_system
and the executable I get is 192K:
192K hello.out
The size of executable is much larger than I expected.
As a comparison, libnghttp2
which fully supports HTTP/2.0 is much smaller:
160K /usr/lib/x86_64-linux-gnu/libnghttp2.so.14.19.0
To find out what is taking so much size, I used bloaty
to analyze the makeup of this program:
FILE SIZE VM SIZE
-------------- --------------
52.8% 99.9Ki 53.0% 99.8Ki .text
14.4% 27.3Ki 14.5% 27.3Ki .rodata
12.0% 22.7Ki 12.0% 22.7Ki .eh_frame
3.9% 7.47Ki 3.9% 7.41Ki .dynstr
3.7% 6.95Ki 3.7% 6.89Ki .gcc_except_table
2.9% 5.45Ki 2.9% 5.39Ki .dynsym
2.5% 4.73Ki 2.5% 4.66Ki .rela.plt
1.8% 3.47Ki 1.8% 3.41Ki .eh_frame_hdr
1.7% 3.19Ki 1.7% 3.12Ki .plt
0.9% 1.70Ki 0.8% 1.58Ki .got.plt
0.8% 1.52Ki 0.2% 320 [15 Others]
0.0% 0 0.7% 1.30Ki .bss
0.4% 819 0.0% 0 [Unmapped]
0.0% 0 0.4% 784 .bss.rel.ro
0.4% 759 0.4% 759 [LOAD #2 [R]]
0.4% 680 0.3% 616 .data
0.3% 616 0.3% 552 .rela.dyn
0.3% 544 0.2% 480 .gnu.version_r
0.3% 524 0.2% 460 .gnu.version
0.3% 512 0.2% 448 .dynamic
0.2% 476 0.2% 412 .gnu.hash
100.0% 189Ki 100.0% 188Ki TOTAL
and found that there is 99.9KB of assembly for the hello_world program which is suprisingly large, given that crow is header-only library that only supports HTTP/1.0, clang
should be able to produce much smaller code.
Perhaps crow
overuse virtual function and should consider use CRTP, a template techique, to replace these virtual base classes and the size of executable will be much smaller and the performance also will be better.
The .eh_frame
also takes 22.7KB which makes me want to disable exception all together to make the executable smaller, but crow
clearly hasn't support -fno-exceptions
yet.
Defining CROW_STATIC_ENDPOINT
as described in https://crowcpp.org/guides/static/ and here https://github.com/CrowCpp/crow/blob/4e801d085ae1f1ab72d1ee080796b2241f01cd0b/examples/example_static_file.cpp#L2 leads to compilation error in the following minimal example:
// disabling this define fixes the error
#define CROW_STATIC_ENDPOINT "static_"
#include "crow_all.h"
int main() {
crow::SimpleApp app;
app.port(8080).run();
return 0;
}
The error looks like:
[ 33%] Building CXX object CMakeFiles/bin.dir/main.cc.o
In file included from /home/user/dev/test/2021-02-09 crow race condition test/main.cc:4:
/home/user/dev/test/2021-02-09 crow race condition test/crow_all.h: In instantiation of ‘typename std::enable_if<(((! crow::black_magic::CallHelper<Func, crow::black_magic::S<Args ...> >::value) && (! crow::black_magic::CallHelper<Func, crow::black_magic::S<crow::request, Args ...> >::value)) && (! crow::black_magic::CallHelper<Func, crow::black_magic::S<crow::response&, Args ...> >::value)), void>::type crow::TaggedRule<Args>::operator()(Func&&) [with Func = crow::Crow<Middlewares>::run<{}>::<lambda(const crow::request&, crow::response&, std::string)>; Args = {}; typename std::enable_if<(((! crow::black_magic::CallHelper<Func, crow::black_magic::S<Args ...> >::value) && (! crow::black_magic::CallHelper<Func, crow::black_magic::S<crow::request, Args ...> >::value)) && (! crow::black_magic::CallHelper<Func, crow::black_magic::S<crow::response&, Args ...> >::value)), void>::type = void]’:
/home/user/dev/test/2021-02-09 crow race condition test/crow_all.h:10846:13: required from ‘void crow::Crow<Middlewares>::run() [with Middlewares = {}]’
/home/user/dev/test/2021-02-09 crow race condition test/main.cc:8:22: required from here
/home/user/dev/test/2021-02-09 crow race condition test/crow_all.h:8792:94: error: static assertion failed: Handler type is mismatched with URL parameters
8791 | static_assert(black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
| ~~~~~~~~
8792 | black_magic::CallHelper<Func, black_magic::S<crow::request, Args...>>::value ||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
8793 | black_magic::CallHelper<Func, black_magic::S<crow::request, crow::response&, Args...>>::value
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/user/dev/test/2021-02-09 crow race condition test/crow_all.h:8796:56: error: no match for call to ‘(crow::Crow<Middlewares>::run<{}>::<lambda(const crow::request&, crow::response&, std::string)>) (crow::request, crow::response&)’
8796 | static_assert(std::is_same<void, decltype(f(std::declval<crow::request>(), std::declval<crow::response&>(), std::declval<Args>()...))>::value,
| ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/user/dev/test/2021-02-09 crow race condition test/crow_all.h:8796:56: note: candidate: ‘void (*)(const crow::request&, crow::response&, std::string)’ {aka ‘void (*)(const crow::request&, crow::response&, std::__cxx11::basic_string<char>)’} (conversion)
/home/user/dev/test/2021-02-09 crow race condition test/crow_all.h:8796:56: note: candidate expects 4 arguments, 3 provided
In file included from /home/user/dev/test/2021-02-09 crow race condition test/main.cc:4:
/home/user/dev/test/2021-02-09 crow race condition test/crow_all.h:10846:14: note: candidate: ‘crow::Crow<Middlewares>::run<{}>::<lambda(const crow::request&, crow::response&, std::string)>’
10846 | ([](const crow::request&, crow::response& res, std::string file_path_partial)
| ^
/home/user/dev/test/2021-02-09 crow race condition test/crow_all.h:10846:14: note: candidate expects 3 arguments, 2 provided
In file included from /home/user/dev/test/2021-02-09 crow race condition test/main.cc:4:
/home/user/dev/test/2021-02-09 crow race condition test/crow_all.h:8799:26: error: no match for ‘operator=’ (operand types are ‘std::function<void(const crow::request&, crow::response&)>’ and ‘std::remove_reference<crow::Crow<Middlewares>::run<{}>::<lambda(const crow::request&, crow::response&, std::string)>&>::type’ {aka ‘crow::Crow<Middlewares>::run<{}>::<lambda(const crow::request&, crow::response&, std::string)>’})
8799 | handler_ = std::move(f);
| ~~~~~~~~~^~~~~~~~~~~~~~
In file included from /usr/include/c++/10.2.0/functional:59,
from /usr/include/boost/system/detail/error_category.hpp:17,
from /usr/include/boost/system/detail/error_code.hpp:13,
from /usr/include/boost/system/error_code.hpp:13,
from /usr/include/boost/asio/detail/throw_error.hpp:19,
from /usr/include/boost/asio/detail/impl/posix_event.ipp:23,
from /usr/include/boost/asio/detail/posix_event.hpp:172,
from /usr/include/boost/asio/detail/event.hpp:25,
from /usr/include/boost/asio/execution/blocking_adaptation.hpp:19,
from /usr/include/boost/asio/execution.hpp:22,
from /usr/include/boost/asio/system_executor.hpp:20,
from /usr/include/boost/asio/associated_executor.hpp:22,
from /usr/include/boost/asio.hpp:21,
from /home/user/dev/test/2021-02-09 crow race condition test/crow_all.h:2894,
from /home/user/dev/test/2021-02-09 crow race condition test/main.cc:4:
/usr/include/c++/10.2.0/bits/std_function.h:396:7: note: candidate: ‘std::function<_Res(_ArgTypes ...)>& std::function<_Res(_ArgTypes ...)>::operator=(const std::function<_Res(_ArgTypes ...)>&) [with _Res = void; _ArgTypes = {const crow::request&, crow::response&}]’
396 | operator=(const function& __x)
| ^~~~~~~~
/usr/include/c++/10.2.0/bits/std_function.h:396:33: note: no known conversion for argument 1 from ‘std::remove_reference<crow::Crow<Middlewares>::run<{}>::<lambda(const crow::request&, crow::response&, std::string)>&>::type’ {aka ‘crow::Crow<Middlewares>::run<{}>::<lambda(const crow::request&, crow::response&, std::string)>’} to ‘const std::function<void(const crow::request&, crow::response&)>&’
396 | operator=(const function& __x)
| ~~~~~~~~~~~~~~~~^~~
/usr/include/c++/10.2.0/bits/std_function.h:414:7: note: candidate: ‘std::function<_Res(_ArgTypes ...)>& std::function<_Res(_ArgTypes ...)>::operator=(std::function<_Res(_ArgTypes ...)>&&) [with _Res = void; _ArgTypes = {const crow::request&, crow::response&}]’
414 | operator=(function&& __x) noexcept
| ^~~~~~~~
/usr/include/c++/10.2.0/bits/std_function.h:414:28: note: no known conversion for argument 1 from ‘std::remove_reference<crow::Crow<Middlewares>::run<{}>::<lambda(const crow::request&, crow::response&, std::string)>&>::type’ {aka ‘crow::Crow<Middlewares>::run<{}>::<lambda(const crow::request&, crow::response&, std::string)>’} to ‘std::function<void(const crow::request&, crow::response&)>&&’
414 | operator=(function&& __x) noexcept
| ~~~~~~~~~~~^~~
/usr/include/c++/10.2.0/bits/std_function.h:428:7: note: candidate: ‘std::function<_Res(_ArgTypes ...)>& std::function<_Res(_ArgTypes ...)>::operator=(std::nullptr_t) [with _Res = void; _ArgTypes = {const crow::request&, crow::response&}; std::nullptr_t = std::nullptr_t]’
428 | operator=(nullptr_t) noexcept
| ^~~~~~~~
/usr/include/c++/10.2.0/bits/std_function.h:428:17: note: no known conversion for argument 1 from ‘std::remove_reference<crow::Crow<Middlewares>::run<{}>::<lambda(const crow::request&, crow::response&, std::string)>&>::type’ {aka ‘crow::Crow<Middlewares>::run<{}>::<lambda(const crow::request&, crow::response&, std::string)>’} to ‘std::nullptr_t’
428 | operator=(nullptr_t) noexcept
| ^~~~~~~~~
/usr/include/c++/10.2.0/bits/std_function.h:457:2: note: candidate: ‘template<class _Functor> std::function<_Res(_ArgTypes ...)>::_Requires<std::function<_Res(_ArgTypes ...)>::_Callable<typename std::decay<_Functor>::type>, std::function<_Res(_ArgTypes ...)>&> std::function<_Res(_ArgTypes ...)>::operator=(_Functor&&) [with _Functor = _Functor; _Res = void; _ArgTypes = {const crow::request&, crow::response&}]’
457 | operator=(_Functor&& __f)
| ^~~~~~~~
/usr/include/c++/10.2.0/bits/std_function.h:457:2: note: template argument deduction/substitution failed:
/usr/include/c++/10.2.0/bits/std_function.h: In substitution of ‘template<class _Res, class ... _ArgTypes> template<class _Cond, class _Tp> using _Requires = typename std::enable_if<_Cond::value, _Tp>::type [with _Cond = std::function<void(const crow::request&, crow::response&)>::_Callable<crow::Crow<Middlewares>::run<{}>::<lambda(const crow::request&, crow::response&, std::string)>, std::__invoke_result<crow::Crow<Middlewares>::run<{}>::<lambda(const crow::request&, crow::response&, std::string)>&, const crow::request&, crow::response&> >; _Tp = std::function<void(const crow::request&, crow::response&)>&; _Res = void; _ArgTypes = {const crow::request&, crow::response&}]’:
/usr/include/c++/10.2.0/bits/std_function.h:457:2: required by substitution of ‘template<class _Functor> std::function<void(const crow::request&, crow::response&)>::_Requires<std::function<void(const crow::request&, crow::response&)>::_Callable<typename std::decay<_Tp>::type, std::__invoke_result<typename std::decay<_Tp>::type&, const crow::request&, crow::response&> >, std::function<void(const crow::request&, crow::response&)>&> std::function<void(const crow::request&, crow::response&)>::operator=<_Functor>(_Functor&&) [with _Functor = crow::Crow<Middlewares>::run<{}>::<lambda(const crow::request&, crow::response&, std::string)>]’
/home/user/dev/test/2021-02-09 crow race condition test/crow_all.h:8799:26: required from ‘typename std::enable_if<(((! crow::black_magic::CallHelper<Func, crow::black_magic::S<Args ...> >::value) && (! crow::black_magic::CallHelper<Func, crow::black_magic::S<crow::request, Args ...> >::value)) && (! crow::black_magic::CallHelper<Func, crow::black_magic::S<crow::response&, Args ...> >::value)), void>::type crow::TaggedRule<Args>::operator()(Func&&) [with Func = crow::Crow<Middlewares>::run<{}>::<lambda(const crow::request&, crow::response&, std::string)>; Args = {}; typename std::enable_if<(((! crow::black_magic::CallHelper<Func, crow::black_magic::S<Args ...> >::value) && (! crow::black_magic::CallHelper<Func, crow::black_magic::S<crow::request, Args ...> >::value)) && (! crow::black_magic::CallHelper<Func, crow::black_magic::S<crow::response&, Args ...> >::value)), void>::type = void]’
/home/user/dev/test/2021-02-09 crow race condition test/crow_all.h:10846:13: required from ‘void crow::Crow<Middlewares>::run() [with Middlewares = {}]’
/home/user/dev/test/2021-02-09 crow race condition test/main.cc:8:22: required from here
/usr/include/c++/10.2.0/bits/std_function.h:319:8: error: no type named ‘type’ in ‘struct std::enable_if<false, std::function<void(const crow::request&, crow::response&)>&>’
319 | using _Requires = typename enable_if<_Cond::value, _Tp>::type;
| ^~~~~~~~~
/home/user/dev/test/2021-02-09 crow race condition test/crow_all.h: In instantiation of ‘typename std::enable_if<(((! crow::black_magic::CallHelper<Func, crow::black_magic::S<Args ...> >::value) && (! crow::black_magic::CallHelper<Func, crow::black_magic::S<crow::request, Args ...> >::value)) && (! crow::black_magic::CallHelper<Func, crow::black_magic::S<crow::response&, Args ...> >::value)), void>::type crow::TaggedRule<Args>::operator()(Func&&) [with Func = crow::Crow<Middlewares>::run<{}>::<lambda(const crow::request&, crow::response&, std::string)>; Args = {}; typename std::enable_if<(((! crow::black_magic::CallHelper<Func, crow::black_magic::S<Args ...> >::value) && (! crow::black_magic::CallHelper<Func, crow::black_magic::S<crow::request, Args ...> >::value)) && (! crow::black_magic::CallHelper<Func, crow::black_magic::S<crow::response&, Args ...> >::value)), void>::type = void]’:
/home/user/dev/test/2021-02-09 crow race condition test/crow_all.h:10846:13: required from ‘void crow::Crow<Middlewares>::run() [with Middlewares = {}]’
/home/user/dev/test/2021-02-09 crow race condition test/main.cc:8:22: required from here
/usr/include/c++/10.2.0/bits/std_function.h:466:2: note: candidate: ‘template<class _Functor> std::function<_Res(_ArgTypes ...)>& std::function<_Res(_ArgTypes ...)>::operator=(std::reference_wrapper<_Functor>) [with _Functor = _Functor; _Res = void; _ArgTypes = {const crow::request&, crow::response&}]’
466 | operator=(reference_wrapper<_Functor> __f) noexcept
| ^~~~~~~~
/usr/include/c++/10.2.0/bits/std_function.h:466:2: note: template argument deduction/substitution failed:
In file included from /home/user/dev/test/2021-02-09 crow race condition test/main.cc:4:
/home/user/dev/test/2021-02-09 crow race condition test/crow_all.h:8799:26: note: ‘crow::Crow<Middlewares>::run<{}>::<lambda(const crow::request&, crow::response&, std::string)>’ is not derived from ‘std::reference_wrapper<_Tp>’
8799 | handler_ = std::move(f);
| ~~~~~~~~~^~~~~~~~~~~~~~
make[3]: *** [CMakeFiles/bin.dir/build.make:82: CMakeFiles/bin.dir/main.cc.o] Error 1
make[2]: *** [CMakeFiles/Makefile2:123: CMakeFiles/bin.dir/all] Error 2
make[1]: *** [CMakeFiles/Makefile2:103: CMakeFiles/run.dir/rule] Error 2
make: *** [Makefile:137: run] Error 2
The compiler call looks like:
/usr/bin/c++ -DBOOST_ALL_NO_LIB -DBOOST_SYSTEM_DYN_LINK -pthread -o CMakeFiles/bin.dir/main.cc.o -c "/<path>/main.cc"
I'm using commit 4e801d0 and gcc 10.2.0 on Arch.
websocket.h
is seemingly not being tested at all, should probably be addressedmustache.h
is quite low, not sure why, should probably be investigated.. mustachetest is not generating gcov filesThis is me daydreaming but it would be nice if middlewares could be defined per route as well as per server. Those defined per server will run on every request as usual, but the ones defined per route will run only on that request (I'm mainly talking about before_handle
and after_handle
)
Add another method to configure how many seconds a timeout takes.
Redirection is done through res.redirect("URL")
, only problem with that is that it requires an absolute URL, meaning the code has to contain the whole http://domain.xyz/
which is an inconvenience.
However just having routes instead of full URLs isn't as simple as it may seem, requiring the request's URL in order to create the new URL, the problem with that is that it can't be part of the response code, since the response doesn't get any request reference.
In short, 2 solutions seem feasible:
Related to ipkn#346
#include "crow_all.hpp"
int main() {
crow::SimpleApp app;
CROW_ROUTE(app, "/")([](){
return "Hello world";
});
app.port(18080).multithreaded().run();
}
This crashes in the app.port-line with an error in the depths of boost
template<class E> BOOST_NORETURN void throw_exception( E const & e )
{
throw_exception_assert_compatibility( e );
throw wrapexcept<E>( e );
}
I am using boost 1.75, windows 10 and clang ( llvm11 ).
The test for streaming response bodies randomly fails because the client fails to receive the first 1-5 bytes, which causes all subsequent comparisons to fail as well, a potential fix was to check the length, but this fix only checks if the last x bytes are missing.
the following PRs could be useful.
they should probably be cloned, tested (thoroughly, we don't need another sendifle), cleaned up, and merged.
in the handler lambda, if you do return value_item
withvalue_time
being a list crow::json::wvalue
object, you get nothing, it only works if you do return crow::response(value_item)
.
This is also true for all other non object types.
This is the code I used
CROW_ROUTE(app, "/json/thing")
([](){
crow::json::wvalue value_item;
std::vector<int> value_list;
value_list.emplace_back(5);
value_list.emplace_back(2);
value_list.emplace_back(3);
value_list.emplace_back(4);
value_item = value_list;
return value_item;
});
Crow does not check the mask bit, instead it applies the mask regardless (since the mask is always 0 if the mask bit is not set), but this would still involve memory allocation, asio reading, and a loop containing XOR and MOD operations.
a better implementation would be to check the mask bit and ignore any operation if the bit isn't set.
we have JSON mode, basically sets the content-type header to application/json, just make the same thing for multipart, instead of converting to string and returning that, something like:
CROW_ROUTE(app,"/multipart")
([](const crow::request& req){
crow::multipart::message msg(req);
return msg;
});
HEAD
should return the same response as GET
, just without the body.OPTIONS
should return an Allow
header with the allowed methods, separated by ,
.in response to ipkn/crow#47, ipkn/crow#219, ipkn/crow#292.
I'm not sure how to go about this, a good place to start implementing would be the comments of the issues themselves, and maybe we could also take a look at this to further understand how to implement the standard fully.
Im building a website based on crow that features HTML pages that include linked images.
Here is a "minimum breaking example": https://github.com/rittelle/test-crow-race-condition
http://localhost:8080 should show a very simple webpage with an image.
Sometimes some XML code appears instead of the webpage. A look at the requests in the developer tools reveals that crow seems to sometimes respond with the content of static/image.svg
instead of the intended content of /
from main.cc
. This is not happening every time (but most of the time for me, which is quite annoying), so it's maybe something like a race condition between the routes when both are requested?
The error also does not occur, when:
static
folder
static/
routes in general and the other routes?crow_all.h
from 4e801d0I didn't try other browser / OSes, yet. I may find the time to further investigate in the next days, but I don't know the codebase; any pointers would be appreciated ;) .
A simple unittest guide with an example, include both simple tests and TCP socket based tests.
Most people building websites nowadays use nginx
or appache
to reverse proxy the real dynamic content server instead of directly expose the underlying server directly as
nginx
and appache
are much more battle tested and has less bug.nginx
and appache
is probably much better than crow
nginx
and appache
and know how to tune them. Some might even has special patch applied to them for their own use caseThere are broader audience who needs fastCGI in their content server.
While nginx
and appache
can also proxy http, it is slower than fastCGI as
and nobody in their right mind would proxy their underlying content server over https as it is too heavy weight.
The right solution here is fastCGI. It is designed for this kind of application, so the experience programming with fastCGI is probably better than http.
Thus I think crow should have fastCGI support as it is extremely important.
I found archive of the specification of fastCGI here and it also has a reference implementation of fastCGI library fcgi2.
There are also kcgi and fastcgipp that are C
and C++
server that supports fastCGI.
Some tests require app.stop();
to be run after the REQUIRE()
(or ASSERT_XYZ
with the old system).
It seems that the old system allowed the rest of the code to be run if an assertion fails, allowing app.stop();
to run, ending the test. This doesn't seem to be the case with Catch, which causes the test to basically run in an infinite loop if a test that requires app.stop();
fails.
Have the /static
directory be fully accessible to clients, this is similar to how Flask handles static files.
This can be done either by having a /static/<path>
rule be always present (possible with an option to disable it). or with middleware that checks for any requests that start with /static
and just does a set_static_file_info
to whatever the request url is.
ipkn#386 is somewhat related.
Hi,
I met a problem while compiling on Windows:
on http_response.h the static_file_info is only defined if !defined(_WIN32)
http_connection.h uses it without _WIN32 checking
also app.h calls set_static_file info if CROW_DISABLE_STATIC_DIR is not defined
It was not immediately obvious to me, why the static_file_info part is disabled on _WIN32 compile.
The code compiles with Microsoft Visual studio, thus the easiest way to avoid the problem was to remove the condition in http_response.h I should understand it first though...
Eero
discussion in ipkn#250
Currently Crow only supports this with its own JSON data type, no xml, no anything.
one potential solution would be to create a response constructor argument that specifies the content type (as opposed to just headers), this can be done by using an extention (e.g. xml
) and then using mime_types.h
to get the proper content-type header.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.