modern c++(c++17), cross-platform, header-only, easy to use http framework

Overview

cinatra--一个高效易用的c++ http框架

English | 中文

目录

使用cinatra常见问题汇总(FAQ)

cinatra简介

cinatra是一个高性能易用的http框架,它是用modern c++(c++17)开发的,它的目标是提供一个快速开发的c++ http框架。它的主要特点如下:

  1. 统一而简单的接口
  2. header-only
  3. 跨平台
  4. 高效
  5. 支持面向切面编程

cinatra目前支持了http1.1/1.0, ssl和websocket, 你可以用它轻易地开发一个http服务器,比如常见的数据库访问服务器、文件上传下载服务器、实时消息推送服务器,你也可以基于cinatra开发一个mqtt服务器。 cinatra是世界上性能最好的http服务器之一,性能测试详见性能测试

谁在用cinatra

cinatra目前被很多公司在使用,在这里可以看到谁在用cinatra.

如何使用

编译依赖

cinatra是基于boost.asio开发的,所以需要boost库。不过,cinatra同时也支持了ASIO_STANDALONE,你不必一定需要boost库。

cinatra需要的依赖项:

  1. C++17 编译器 (gcc 7.2, clang 4.0, Visual Studio 2017 update 15.5,或者更高的版本)
  2. Boost.Asio(或者独立的 Asio)
  3. Boost.System

使用

cinatra是header-only的,直接引用头文件既可。

快速示例

示例1:一个简单的hello world

#include "cinatra.hpp"
using namespace cinatra;

int main() {
	int max_thread_num = std::thread::hardware_concurrency();
	http_server server(max_thread_num);
	server.listen("0.0.0.0", "8080");
	server.set_http_handler<GET, POST>("/", [](request& req, response& res) {
		res.set_status_and_content(status_type::ok, "hello world");
	});

	server.run();
	return 0;
}

5行代码就可以实现一个简单http服务器了,用户不需要关注多少细节,直接写业务逻辑就行了。

示例2:展示如何取header和query以及错误返回

#include "cinatra.hpp"
using namespace cinatra;

int main() {
	http_server server(std::thread::hardware_concurrency());
	server.listen("0.0.0.0", "8080");
	server.set_http_handler<GET, POST>("/test", [](request& req, response& res) {
		auto name = req.get_header_value("name");
		if (name.empty()) {
			res.set_status_and_content(status_type::bad_request, "no name");
			return;
		}

		auto id = req.get_query_value("id");
		if (id.empty()) {
			res.set_status_and_content(status_type::bad_request);
			return;
		}

		res.set_status_and_content(status_type::ok, "hello world");
	});

	server.run();
	return 0;
}

示例3:面向切面的http服务器

#include "cinatra.hpp"
using namespace cinatra;

//日志切面
struct log_t
{
	bool before(request& req, response& res) {
		std::cout << "before log" << std::endl;
		return true;
	}

	bool after(request& req, response& res) {
		std::cout << "after log" << std::endl;
		return true;
	}
};

//校验的切面
struct check {
	bool before(request& req, response& res) {
		std::cout << "before check" << std::endl;
		if (req.get_header_value("name").empty()) {
			res.set_status_and_content(status_type::bad_request);
			return false;
		}
		return true;
	}

	bool after(request& req, response& res) {
		std::cout << "after check" << std::endl;
		return true;
	}
};

//将信息从中间件传输到处理程序
struct get_data {
	bool before(request& req, response& res) {
		req.set_aspect_data("hello", std::string("hello world"));
		return true;
	}
}

int main() {
	http_server server(std::thread::hardware_concurrency());
	server.listen("0.0.0.0", "8080");
	server.set_http_handler<GET, POST>("/aspect", [](request& req, response& res) {
		res.set_status_and_content(status_type::ok, "hello world");
	}, check{}, log_t{});

	server.set_http_handler<GET,POST>("/aspect/data", [](request& req, response& res) {
		std::string hello = req.get_aspect_data<std::string>("hello");
		res.set_status_and_content(status_type::ok, std::move(hello));
	}, get_data{});

	server.run();
	return 0;
}

本例中有两个切面,一个校验http请求的切面,一个是日志切面,这个切面用户可以根据需求任意增加。本例会先检查http请求的合法性,如果不合法就会返回bad request,合法就会进入下一个切面,即日志切面,日志切面会打印出一个before表示进入业务逻辑之前的处理,业务逻辑完成之后会打印after表示业务逻辑结束之后的处理。

示例4:文件上传

cinatra目前支持了multipart和octet-stream格式的上传。

multipart文件上传

#include <atomic>
#include "cinatra.hpp"
using namespace cinatra;

int main() {
	http_server server(std::thread::hardware_concurrency());
	server.listen("0.0.0.0", "8080");

	//http upload(multipart)
	server.set_http_handler<GET, POST>("/upload_multipart", [](request& req, response& res) {
		assert(req.get_content_type() == content_type::multipart);
		
		auto& files = req.get_upload_files();
		for (auto& file : files) {
			std::cout << file.get_file_path() << " " << file.get_file_size() << std::endl;
		}

		res.set_status_and_content(status_type::ok, "multipart finished");
	});

	server.run();
	return 0;
}

短短几行代码就可以实现一个http文件上传的服务器了,包含了异常处理和错误处理。

octet-stream文件上传

#include <atomic>
#include "cinatra.hpp"
using namespace cinatra;

int main() {
	http_server server(std::thread::hardware_concurrency());
	server.listen("0.0.0.0", "8080");

	//http upload(octet-stream)
	server.set_http_handler<GET, POST>("/upload_octet_stream", [](request& req, response& res) {
		assert(req.get_content_type() == content_type::octet_stream);
		auto& files = req.get_upload_files();
		for (auto& file : files) {
			std::cout << file.get_file_path() << " " << file.get_file_size() << std::endl;
		}

		res.set_status_and_content(status_type::ok, "octet-stream finished");
	});

	server.run();
	return 0;
}

示例5:文件下载

cinatra提供下载功能非常简单,不需要编写代码,具体方法:
1. 启动cinatra server
2. 将要下载的文件放到http server同一级的www目录下即可。
3. 如何下载:如果你把test.txt放到www之后,那么直接通过http://127.0.0.1:8090/test.txt下载即可。
//chunked download
//cinatra will send you the file, if the file is big file(more than 5M) the file will be downloaded by chunked. support continues download

示例6:websocket

#include "cinatra.hpp"
using namespace cinatra;

int main() {
	http_server server(std::thread::hardware_concurrency());
	server.listen("0.0.0.0", "8080");

	//web socket
	server.set_http_handler<GET, POST>("/ws", [](request& req, response& res) {
		assert(req.get_content_type() == content_type::websocket);

		req.on(ws_open, [](request& req){
			std::cout << "websocket start" << std::endl;
		});

		req.on(ws_message, [](request& req) {
			auto part_data = req.get_part_data();
			//echo
			std::string str = std::string(part_data.data(), part_data.length());
			req.get_conn<cinatra::NonSSL>()->send_ws_string(std::move(str));
			std::cout << part_data.data() << std::endl;
		});

		req.on(ws_error, [](request& req) {
			std::cout << "websocket pack error or network error" << std::endl;
		});
	});

	server.run();
	return 0;
}

示例7:io_service_inplace

本代码演示如何使用io_service_inplace,然后自己控制http server的运行线程以及循环。 使用 [http://[::1]:8080/close] (IPv6) 或者 [http://127.0.0.1:8080/close] (IPv4) 来关闭http server。

#include "cinatra.hpp"
using namespace cinatra;

int main() {

	bool is_running = true;
	http_server_<io_service_inplace> server;
	server.listen("8080");

	server.set_http_handler<GET, POST>("/", [](request& req, response& res) {
		res.set_status_and_content(status_type::ok, "hello world");
	});

	server.set_http_handler<GET, POST>("/close", [&](request& req, response& res) {
		res.set_status_and_content(status_type::ok, "will close");

		is_running = false;
		server.stop();
	});

	while(is_running)
		server.poll_one();

	return 0;
}

cinatra客户端使用

同步发get/post消息

同步和异步发送接口都是返回response_data,它有4个字段分别是:网络错误码、http状态码、返回的消息、返回的header。

void print(const response_data& result) {
    print(result.ec, result.status, result.resp_body, result.resp_headers.second);
}

void test_sync_client() {
    auto client = cinatra::client_factory::instance().new_client();
    std::string uri = "http://www.baidu.com";
    std::string uri1 = "http://cn.bing.com";
    std::string uri2 = "https://www.baidu.com";
    std::string uri3 = "https://cn.bing.com";
    
    response_data result = client->get(uri);
    print(result);

    response_data result1 = client->get(uri1);
    print(result1);

    print(client->post(uri, "hello"));
    print(client->post(uri1, "hello"));

#ifdef CINATRA_ENABLE_SSL
    response_data result2 = client->get(uri2);
    print(result2);

    response_data result3 = client->get(uri3);
    print(result3);

    response_data result4 = client->get(uri3);
    print(result4);

    response_data result5 = client->get(uri2);
    print(result5);
#endif
}

异步发get/post消息

void test_async_client() {
    
    std::string uri = "http://www.baidu.com";
    std::string uri1 = "http://cn.bing.com";
    std::string uri2 = "https://www.baidu.com";
    std::string uri3 = "https://cn.bing.com";

    {
        auto client = cinatra::client_factory::instance().new_client();
        client->async_get(uri, [](response_data data) {
            print(data);
        });
    }
    
    {
        auto client = cinatra::client_factory::instance().new_client();
        client->async_get(uri1, [](response_data data) {
            print(data);
        });
    }

    {
        auto client = cinatra::client_factory::instance().new_client();
        client->async_post(uri, "hello", [](response_data data) {
            print(data);
        });
    }

#ifdef CINATRA_ENABLE_SSL
    {
        auto client = cinatra::client_factory::instance().new_client();
        client->async_get(uri2, [](response_data data) {
            print(data);
        });
    }

    {
        auto client = cinatra::client_factory::instance().new_client();
        client->async_get(uri3, [](response_data data) {
            print(data);
        });
    }
#endif
}

文件上传

异步multipart文件上传。

void test_upload() {
    std::string uri = "http://cn.bing.com/";
    auto client = cinatra::client_factory::instance().new_client();
    client->upload(uri, "boost_1_72_0.7z", [](response_data data) {
        if (data.ec) {
            std::cout << data.ec.message() << "\n";
            return;
        }

        std::cout << data.resp_body << "\n"; //finished upload
    });
}

文件下载

提供了两个异步chunked下载接口,一个是直接下载到文件,一个是chunk回调给用户,由用户自己去处理下载的chunk数据

void test_download() {
    std::string uri = "http://www.httpwatch.com/httpgallery/chunked/chunkedimage.aspx";

    {
        auto client = cinatra::client_factory::instance().new_client();
        client->download(uri, "test.jpg", [](response_data data) {
            if (data.ec) {
                std::cout << data.ec.message() << "\n";
                return;
            }

            std::cout << "finished download\n";
        });
    }

    {
        auto client = cinatra::client_factory::instance().new_client();
        client->download(uri, [](auto ec, auto data) {
            if (ec) {
                std::cout << ec.message() << "\n";
                return;
            }

            if (data.empty()) {
                std::cout << "finished all \n";
            }
            else {
                std::cout << data.size() << "\n";
            }
        });
    }
}

性能测试

测试用例:

qps

qps-pipeline

注意事项

websocket的业务函数是会多次进入的,因此写业务逻辑的时候需要注意,推荐按照示例中的方式去做。

联系方式

[email protected]

qq群:340713904

http://purecpp.org/

https://github.com/qicosmos/cinatra

Comments
  • 关于项目的一些建议

    关于项目的一些建议

    1、首先这个项目所用到的编译器和库都比较新,能否加入类似gcc的./contrib/download_prerequisites,一键升级、安装所需版本的编译器及第三方库到编译项目所需的版本 2、是否考虑加入static_assets,将某个路径下所有请求定位到某个文件夹,比如请求css、js这类 3、建议将http response改为基于流,直接使用res << "hello world"的方式写入返回的内容 4、服务类构造函数的那个最大并发量参数及监听时设置ip地址没必要让用户传递,建议在头文件里面取消这俩参数

    opened by fawdlstty 36
  • 修改三个地方

    修改三个地方

    更新nlohmann,避免项目中的nlohmann_json与现在的nlohmann/json冲突 去掉LOG_INFO、LOG_WARN、LOG_CRIT三个定义 新增_CRT_SECURE_NO_WARNINGS、_SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING、_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS三个宏定义 #110

    opened by fawdlstty 16
  • 指定了c++17标准,运行例子报错,GCC-7.5.0

    指定了c++17标准,运行例子报错,GCC-7.5.0

    error: undefined reference to std::experimental::filesystem::v1::__cxx11::path::parent_path() const' error: undefined reference tostd::experimental::filesystem::v1::__cxx11::path::_M_split_cmpts()' error: undefined reference to `std::experimental::filesystem::v1::create_directories(std::experimental::filesystem::v1::__cxx11::path const&, std::error_code&)'

    opened by 424358225 12
  • gcc 7.3 mingw 64(64位), windows 10 boost 1.67, 能生成编译文件,但编译时出错!

    gcc 7.3 mingw 64(64位), windows 10 boost 1.67, 能生成编译文件,但编译时出错!

    编译命令如下: 生成编译文件成功,但编译时出错, 出错信息如下(粘贴部分内容,主要是thread, mutex报错。):

    F:\temp\cinatra-master>cmake . -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_FLAGS=" -m64 -Id:\mingw64\x86_64-w64-mingw32\include -Id:\mingw64\lib\gcc\x86_64-w64-mingw32\7.3.0\include\c++ -Ld:\mingw64\lib\gcc\x86_64-w64-mingw32\7.3.0 -std=c++17 -lstd++ -lpthread " -DENABLE_SSL=ON -DENALBE_GZIP=ON -DCMAKE_BUILD_TYPE=Release -DBOOST_INCLUDEDIR="e:\workspace_git\boost64_1_67\include" -G "MinGW Makefiles" -- Boost version: 1.67.0 -- Found the following Boost libraries: -- system -- Configuring done -- Generating done -- Build files have been written to: F:/temp/cinatra-master

    F:\temp\cinatra-master>mingw32-make -f Makefile cinatra [ 50%] Building CXX object CMakeFiles/cinatra.dir/main.cpp.obj In file included from F:\temp\cinatra-master\http_server.hpp:14:0, from F:\temp\cinatra-master\main.cpp:2: F:\temp\cinatra-master\io_service_pool.hpp: In member function 'void cinatra::io_service_pool::run()': F:\temp\cinatra-master\io_service_pool.hpp:26:37: error: 'thread' is not a member of 'std' std::vector<std::shared_ptrstd::thread > threads; ^~~~~~ F:\temp\cinatra-master\io_service_pool.hpp:26:37: note: suggested alternative: 'tera' std::vector<std::shared_ptrstd::thread > threads; ^~~~~~ tera F:\temp\cinatra-master\io_service_pool.hpp:26:43: error: template argument 1 is invalid std::vector<std::shared_ptrstd::thread > threads; ^ F:\temp\cinatra-master\io_service_pool.hpp:26:45: error: template argument 1 is invalid std::vector<std::shared_ptrstd::thread > threads; ^ F:\temp\cinatra-master\io_service_pool.hpp:26:45: error: template argument 2 is invalid F:\temp\cinatra-master\io_service_pool.hpp:28:13: error: request for member 'emplace_back' in 'threads', which is of non-class type 'int' threads.emplace_back(std::make_sharedstd::thread( ^~~~~~~~~~~~ F:\temp\cinatra-master\io_service_pool.hpp:28:48: error: 'thread' is not a member of 'std' threads.emplace_back(std::make_sharedstd::thread( ^~~~~~ F:\temp\cinatra-master\io_service_pool.hpp:28:48: note: suggested alternative: 'tera' threads.emplace_back(std::make_sharedstd::thread( ^~~~~~ tera F:\temp\cinatra-master\io_service_pool.hpp:31:24: error: no matching function for call to 'make_shared< >(cinatra::io_service_pool::run()::<lambda(cinatra::io_service_pool::io_service_ptr)>, gnu_cxx::alloc_traits<std::allocator<std::shared_ptrboost::asio::io_context > >::value_type&)' }, io_services[i])); ^ In file included from D:/mingw64/lib/gcc/x86_64-w64-mingw32/7.3.0/include/c++/memory:81:0, from E:/workspace_git/boost64_1_67/include/boost/asio/associated_allocator.hpp:19, from E:/workspace_git/boost64_1_67/include/boost/asio.hpp:20, from F:\temp\cinatra-master\use_asio.hpp:23, from F:\temp\cinatra-master\http_server.hpp:2, from F:\temp\cinatra-master\main.cpp:2: D:/mingw64/lib/gcc/x86_64-w64-mingw32/7.3.0/include/c++/bits/shared_ptr.h:703:5: note: candidate: template<class Tp, class ... Args> std::shared_ptr<Tp> std::make_shared(Args&& ...) make_shared(Args&&... args) ^~~~~~~~~~~ D:/mingw64/lib/gcc/x86_64-w64-mingw32/7.3.0/include/c++/bits/shared_ptr.h:703:5: note: template argument deduction/substitution failed: In file included from F:\temp\cinatra-master\http_server.hpp:14:0, from F:\temp\cinatra-master\main.cpp:2: F:\temp\cinatra-master\io_service_pool.hpp:31:24: error: template argument 1 is invalid }, io_services[i])); ^ F:\temp\cinatra-master\io_service_pool.hpp:34:40: error: request for member 'size' in 'threads', which is of non-class type 'int' for (std::size_t i = 0; i < threads.size(); ++i) ^~~~ F:\temp\cinatra-master\io_service_pool.hpp:35:14: error: invalid types 'int[std::size_t {aka long long unsigned int}]' for array subscript threads[i]->join(); ^ In file included from F:\temp\cinatra-master\request.hpp:12:0, from F:\temp\cinatra-master\connection.hpp:7, from F:\temp\cinatra-master\http_server.hpp:15, from F:\temp\cinatra-master\main.cpp:2: F:\temp\cinatra-master\session.hpp: At global scope: F:\temp\cinatra-master\session.hpp:107:8: error: 'mutex' in namespace 'std' does not name a type std::mutex mtx; ^~~~~ F:\temp\cinatra-master\session.hpp: In member function 'void cinatra::session::set_data(const string&, std::any)': F:\temp\cinatra-master\session.hpp:38:26: error: 'mutex' is not a member of 'std' std::unique_lockstd::mutex lock(mtx); ^~~~~ F:\temp\cinatra-master\session.hpp:38:26: note: suggested alternative: 'quoted' std::unique_lockstd::mutex lock(mtx); ^~~~~ quoted F:\temp\cinatra-master\session.hpp:38:31: error: template argument 1 is invalid std::unique_lockstd::mutex lock(mtx); ^ F:\temp\cinatra-master\session.hpp:38:38: error: 'mtx' was not declared in this scope std::unique_lockstd::mutex lock(mtx); ^~~~ F:\temp\cinatra-master\session.hpp: In member function 'T cinatra::session::get_data(const string&)': F:\temp\cinatra-master\session.hpp:45:26: error: 'mutex' is not a member of 'std' std::unique_lockstd::mutex lock(mtx); ^~~~~ F:\temp\cinatra-master\session.hpp:45:26: note: suggested alternative: 'quoted' std::unique_lockstd::mutex lock(mtx); ^~~~~ quoted F:\temp\cinatra-master\session.hpp:45:31: error: template argument 1 is invalid std::unique_lockstd::mutex lock(mtx); ^ F:\temp\cinatra-master\session.hpp:45:38: error: 'mtx_' was not declared in this scope std::unique_lockstd::mutex lock(mtx_); ^~~~ F:\temp\cinatra-master\session.hpp: In member function 'bool cinatra::session::has(const string&)': F:\temp\cinatra-master\session.hpp:55:26: error: 'mutex' is not a member of 'std' std::unique_lockstd::mutex lock(mtx_); ^~~~~ F:\temp\cinatra-master\session.hpp:55:26: note: suggested alternative: 'quoted' std::unique_lockstd::mutex lock(mtx_); ^~~~~ quoted F:\temp\cinatra-master\session.hpp:55:31: error: template argument 1 is invalid std::unique_lockstd::mutex lock(mtx_); ^ F:\temp\cinatra-master\session.hpp:55:38: error: 'mtx_' was not declared in this scope std::unique_lockstd::mutex lock(mtx_); ^~~~ F:\temp\cinatra-master\session.hpp: In member function 'void cinatra::session::set_max_age(time_t)': F:\temp\cinatra-master\session.hpp:66:26: error: 'mutex' is not a member of 'std' std::unique_lockstd::mutex lock(mtx_); ^~~~~

    opened by akeyliu 10
  • Check for cache

    Check for cache

    Hi,

    Newbie question. I'm trying to understand the code in http_server.hpp and I'm having a hard time understanding line 172:

    bool b = true;
    ((b&&(b = need_cache(std::forward<AP>(ap))), false),...);
    

    Could you please explain why there's a false? Eclipse tells me there's a syntax error, by the way.

    Thanks in advance, Allister

    opened by axx 9
  • [BugReport] Memory Leak on multipart_reader::currentHeaders

    [BugReport] Memory Leak on multipart_reader::currentHeaders

    在上传小文件时会偶尔翻车,加AddressSanitizer提示function multipart_reader::cbHeaderEnd()函数内heap-use-after-free on address。

    如图所示,将HTTP POST请求拆成2部分送达feed()函数 图链接 备用地址:draw.io

    • 我们称第一个request fragment送来的地址是bufferA 第一次把bufferA送入multipart_parser::feed()后,状态机调用multipart_reader::cbHeaderEnd()函数,将两个string_view存入multipart_headers::currentHeaders中,结束后currentHeaders.size()==1

    • 第二个request fragment随之到来,存于bufferB 依旧是feed()调用cbHeaderEnd(), 此时bufferA已经释放,导致上述两个multipart_headers::currentHeaders中的string_view悬空 程序再次调用multipart_reader::cbHeaderEnd()时,multimap试图读取原有string_views内容时读到了已经被释放的地址,在此处crash。

    如果幸运的话,分片不会把某一组header隔开,就不会触发bug。但也可以构造一个超级长的header,然后强行分片送抵服务器,就一定会触发。

    解决方案? 想到把using multipart_headers = std::multimap<std::string_view, std::string_view>; 改成using multipart_headers = std::multimap<std::string, std::string>; (我看到已经写了注释??) https://github.com/qicosmos/cinatra/blob/ba17d4a35a44e5db070f3a000643432140e9a862/include/cinatra/multipart_reader.hpp#L97-L98

    或者设计一个垃圾回收,触发multipart_reader::cbHeadersEnd()时,把之前的buffer再收掉。

    还有一个想法 buffer改用类似链表结构,把已经submit的string_view直接砍掉,会不会造成内存很零散?。。。

    另外还有一个enhancement 在class upload_file里面,打开文件失败了请给个提示。。

    第二组bug: feed()状态机不能处理多次送达的buffer

    针对这几行举例,依然是两个post碎片,CR没有随着第一次feed(buffer1)到来,而在下一次feed(buffer2)时才送来。但是string_view引用的buffer1已经没了。 https://github.com/qicosmos/cinatra/blob/ba17d4a35a44e5db070f3a000643432140e9a862/include/cinatra/multipart_parser.hpp#L148-L161

    第一次送来的buffer:

    -----------------------------4833311154639
    Content-Disposition: form-data; name="file"; filename="20190628001428.png" (结尾没有\r)
    

    第二次feed送来的buffer:

    \r
    Content-Type: image/png\r
    
    PNG<binary data......binary data......>
    -----------------------------4833311154639--
    

    错误依旧为 heap-use-after-free in cinatra::multipart_reader::cbHeaderEnd

    解决方案? 同上吧,我觉得存下来比较好,我们没办法保证数据包在哪里断掉。。

    第三组bug:当feed()分片到达时,可能会打断正在解析的header内容

    在multipart_reader.hpp中 self->currentHeaderNameself->currentHeaderValue 两个变量,第二次到达的会覆盖前一次到达的值。

    同样我觉得用string比较好操作,直接连接起来。。或者就滚动buffer,改下状态机不做multipart_parser.hpp#L192-L194

    这个bug的确定理由:

    Breakpoint at multipart_reader.hpp:90
    (gdb) p self->currentHeaderValue
    	form-data; name=\"file\"; filename=\"2019
    
    Breakpoint at multipart_reader.hpp:90
    (gdb) p self->currentHeaderValue
    	"0628001428.png\""
    
    Breakpoint at connection.hpp:562
    (gdb) p headers
    	std::multimap with 2 elements = {["Content-Disposition"] = "1428.png\"", ["Content-Type"] = "image/png"}
    
    bug 
    opened by vrqq 8
  • Remove asio::io_service, use asio::io_context

    Remove asio::io_service, use asio::io_context

    Followed network TS and newest boost asio implementation, io_service is marked as DEPRECATED.

    Please refer https://www.boost.org/doc/libs/1_66_0/doc/html/boost_asio/net_ts.html

    opened by HungMingWu 8
  • Keep alive does not work when serving static files.

    Keep alive does not work when serving static files.

    I found that the connection will always be closed when serving static files even I use HTTP/1.1 or specify Connection: Keep-Alive. I have checked the source code and there is no do_read() in the callback of write_chunked_data and the server will close the connection when chunked data has been all read, the state will be data_end in the source code and just close the connection without checking. Why does not cinatra support Keep-Alive for chunked data?

    opened by Kidsunbo 4
  • MFC工程里使用cinatra,在debug下编不过

    MFC工程里使用cinatra,在debug下编不过

    MFC工程里使用cinatra,在debug下编不过,因为utils.hpp里的http_method::TRACE会和ATl里的TRACE冲突(),请修正, 谢谢。

    Error: Error C2143 syntax error: missing '}' before 'ATL::CTraceFileAndLineInfo' inc\cinatra\utils.hpp 197

    opened by icegull 4
  • http_client.hpp 同步获取网页的问题

    http_client.hpp 同步获取网页的问题

    std::string uri = "http://txt.go.sohu.com/ip/soip";
    response_data result = client->get(uri);
    print(result);  // 打印resp_body的第一个字节丢失了(实际变成\0x00)
    printf("result: %s\n", result.resp_body.data()); // 此处由于第一个字节变成\x00造成打印空串
    

    造成以上问题是同步 client->get(uri); 里面还是异步调用,以下语句有问题 sp->set_value({ ec, status, result, get_resp_headers() }); 其中 result 是 string_view,保存的只有数据指针和大小。 read_chunk_body 中 callback 之后调用 clear_chunk_buffer(); 把指针指向的数据清空了。

    以上盼尽快修复。

    opened by idigger 4
  • [BugReport] Memory Leak on request.hpp

    [BugReport] Memory Leak on request.hpp

    在request.hpp的第87行,queries_ = parse_query(raw_url_.substr(pos+1, url_len_-pos-1));在substr时候产生了新的string,而parse_query函数传入值为string_view。在执行完这个函数后,所产生的substr失效,导致一系列string_view失效。 改成queries_ = parse_query(std::string_view{raw_url_}.substr(pos+1, url_len_-pos-1));即可! ( 要pull request吗<( ̄︶ ̄)/ )

    另外建议编译时可加参数-fsanitize=address 调AddressSanitizer

    bug 
    opened by vrqq 4
  • 考虑在后续版本中增强cinatra作为websocket 服务端的功能?

    考虑在后续版本中增强cinatra作为websocket 服务端的功能?

    req.on(ws_ping, [](request& req) -> bool {
    			std::string payload = req.get_part_data();//最多125字节的ping包payload数据
    			// check payload some attribute
    			return true; //true if a pong response should be sent, false will not;
    		});
    req.on(ws_pong, [](request& req) -> void {
    			std::string payload = req.get_part_data();////最多125字节的pong包payload数据
    		});
    req.on(ws_pong_timeout, [](request& req) -> void {
    			uint32_t timeout = req->get_timeout();
    			auto conn = req.get_conn<cinatra::NonSSL>();
    			conn->on_close();
    		});
    

    除开ws_open, ws_close, ws_error, ws_message四个data_proc_state的状态处理外 1.ws_ping接收到ping包,ws_pong接收到pong包,ws_pong_timeout一定时间未接收到pong包或任意消息。 希望增加有关这几种状态的处理 handler。 2.ping包和pong包中按照协议,应该允许用户同时发送不大于126字节的payload,我这里太需要这点cinatra在接口上能支持。 image

    opened by sese53 0
  • 中文文件名称下载失败

    中文文件名称下载失败

    测试用例:http://ip:port/Local/1 - 副本 (17).mp3 postman: image

    关键代码段: image 原因: std::ifstream 对于utf8编码字符串文件路径,打开异常

    处理方式: http请求参数默认utf8编码,使用file_system::u8path转码下 image 可用考虑处理下,谢谢!

    opened by blackStar1314 1
  • 还是set_http_handler的name参数类型问题

    还是set_http_handler的name参数类型问题

    今天就遇到#198 这个问题了。相关原因这个issues已经陈诉。

    void websocket_server::start() {
        server_.enable_timeout(false);
        server_.set_keep_alive_timeout(std::numeric_limits<long>::max());
        server_.listen(ip_, port_);
    
        std::string_view uri{"/usb_capture"};
        server_.set_http_handler<cinatra::GET, cinatra::POST>(
            uri, [this](cinatra::request& request, cinatra::response& response) {
                if (request.get_content_type() !=
                    cinatra::content_type::websocket) {
                    LOG_WARN << "someone use other protocol for websocket, type "
                                ": "
                             << static_cast<int>(request.get_content_type());
                }
    
                request.on(cinatra::ws_open, [this](cinatra::request& request) {
                    ws_connect_handler(request);
                });
    
                request.on(cinatra::ws_message, [this](cinatra::request& request) {
                    ws_message_handler(request);
                });
    
                request.on(cinatra::ws_close, [this](cinatra::request& request) {
                    ws_close_handler(request);
                });
    
                request.on(cinatra::ws_error, [this](cinatra::request& request) {
                    ws_error_handler(request);
                });
            });
    
        LOG_INFO << "start url ws://" << ip_ << ":" << port_ << uri;
    
        thread_ = std::make_unique<std::thread>([this] { main(); });
    }
    
    void websocket_server::main() {
        server_.run();
    }
    

    也是自己还没有完全转到string_view(用string_viewname的参数类型确实是更合理的)上的原因吧。希望写一点注释,不然那些习惯用string来保存字面量的使用者很容易犯这种生命周期的问题。

    opened by FlushHip 0
  • 快速示例语义有歧义可能导致编译不通过

    快速示例语义有歧义可能导致编译不通过

    void print(const cinatra::response_data& result) {
        print(result.ec, result.status, result.resp_body, result.resp_headers.second);
    }
    

    改为

    void my_print(const cinatra::response_data& result) {
        cinatra::print(result.ec, result.status, result.resp_body, result.resp_headers.second);
    }
    

    好一些,如果直接复制的话,会有个模板展开的报错,然后print不加上命名空间的话,也会有歧义。

    opened by luciouskami 1
Releases(v0.07)
Owner
qicosmos
purecpp.org 微信公账号purecpp
qicosmos
Header-only, event based, tiny and easy to use libuv wrapper in modern C++ - now available as also shared/static library!

Do you have a question that doesn't require you to open an issue? Join the gitter channel. If you use uvw and you want to say thanks or support the pr

Michele Caini 1.5k Sep 28, 2022
cuehttp is a modern c++ middleware framework for http(http/https)/websocket(ws/wss).

cuehttp 简介 cuehttp是一个使用Modern C++(C++17)编写的跨平台、高性能、易用的HTTP/WebSocket框架。基于中间件模式可以方便、高效、优雅的增加功能。cuehttp基于boost.asio开发,使用picohttpparser进行HTTP协议解析。内部依赖了nl

xcyl 27 Aug 15, 2022
H2O - the optimized HTTP/1, HTTP/2, HTTP/3 server

H2O - an optimized HTTP server with support for HTTP/1.x, HTTP/2 and HTTP/3 (experimental) Copyright (c) 2014-2019 DeNA Co., Ltd., Kazuho Oku, Tatsuhi

H2O 10.1k Oct 3, 2022
Pushpin is a reverse proxy server written in C++ that makes it easy to implement WebSocket, HTTP streaming, and HTTP long-polling services.

Pushpin is a reverse proxy server written in C++ that makes it easy to implement WebSocket, HTTP streaming, and HTTP long-polling services. The project is unique among realtime push solutions in that it is designed to address the needs of API creators. Pushpin is transparent to clients and integrates easily into an API stack.

Fanout 3.1k Sep 28, 2022
Cross-platform, efficient, customizable, and robust asynchronous HTTP/WebSocket server C++14 library with the right balance between performance and ease of use

What Is RESTinio? RESTinio is a header-only C++14 library that gives you an embedded HTTP/Websocket server. It is based on standalone version of ASIO

Stiffstream 886 Sep 24, 2022
modern C++(C++11), simple, easy to use rpc framework

modern C++(C++11), simple, easy to use rpc framework

qicosmos 1.1k Sep 30, 2022
BingBing 59 Sep 29, 2022
Brynet - Header Only Cross platform high performance TCP network library using C++ 11.

Brynet Header Only Cross platform high performance TCP network library using C++ 11. Build status Windows : Linux/MacOS : Features Header only Cross p

IronsDu 865 Oct 1, 2022
Easy-to-use HTTP C library

LibHTTP LibHTTP is a C library easy-to-use which implements the base of the HTTP protocol. Info's about LibHTTP LibHTTP is an easy-to-use HTTP library

null 6 Dec 10, 2021
A cross-platform HTTP client library with a focus on usability and speed

EasyHttp A cross-platform HTTP client library with a focus on usability and speed. Under its hood, EasyHttp uses POCO C++ Libraries and derives many o

Sony 146 Aug 9, 2022
A cross-platform network learning demos. Like high-performance http server

Network-Learn A cross-platform network learning demos (toys). And I try not to use 3rd-party libraries. Welcome to try it out and leave your comments.

Ho 229 24 Sep 6, 2022
Tiny cross-platform HTTP / HTTPS client library in C.

naett /nɛt:/ Tiny HTTP client library in C. Wraps native HTTP client functionality on macOS, Windows, Linux, iOS and Android in a single, simple non-b

Erik Agsjö 18 Sep 28, 2022
Cross-platform, single .h file HTTP server (Windows, Linux, Mac OS X)

EWS - Single .h File C Embeddable Web Server Latest Version: 1.1.4 released September 9, 2021 Supported platforms: Linux, Mac OS X, Windows License: B

Forrest Heller 77 Aug 8, 2022
Small and fast cross-platform networking library, with support for messaging, IPv6, HTTP, SSL and WebSocket.

frnetlib Frnetlib, is a cross-platform, small and fast networking library written in C++. There are no library dependencies (unless you want to use SS

Fred Nicolson 22 May 16, 2022
XQUIC Library released by Alibaba is a cross-platform implementation of QUIC and HTTP/3 protocol.

XQUIC 简体中文文档 README-zh-CN Introduction XQUIC Library released by Alibaba is … … a client and server implementation of QUIC and HTTP/3 as specified by

Alibaba 1.3k Sep 29, 2022
A C++ header-only HTTP/HTTPS server and client library

cpp-httplib A C++11 single-file header-only cross platform HTTP/HTTPS library. It's extremely easy to setup. Just include the httplib.h file in your c

null 7.9k Oct 6, 2022
Asynchronous, Header-only C++ HTTP-over-(TCP|UNIX Socket|STDIO) Library

CXXHTTP A C++ library implementing an asynchronous HTTP server and client. To clone this library, make sure you also clone the submodules. The --recur

null 25 Mar 19, 2021
tiny HTTP parser written in C (used in HTTP::Parser::XS et al.)

PicoHTTPParser Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase, Shigeo Mitsunari PicoHTTPParser is a tiny, primitive, fast HTTP r

H2O 1.5k Sep 28, 2022
Gromox - Groupware server backend with MAPI/HTTP, RPC/HTTP, IMAP, POP3 and PHP-MAPI support for grommunio

Gromox is the central groupware server component of grommunio. It is capable of serving as a replacement for Microsoft Exchange and compatibles. Conne

grommunio 122 Sep 23, 2022