From c7a9e1c457f149358fe580cd4e12442ece9827d9 Mon Sep 17 00:00:00 2001 From: Dev User Date: Tue, 4 Aug 2026 20:06:33 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0websocket=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 202 +++++++++++++++++++++++++++++++++- include/net/http_define.h | 63 +++++++++++ include/net/http_reqpack.h | 28 ++++- include/net/http_request.h | 1 - include/net/http_response.h | 8 +- include/net/http_router.h | 13 ++- include/net/http_server_lst.h | 2 + include/net/http_subscribe.h | 6 +- src/net/http_reqpack.cpp | 13 ++- src/net/http_response.cpp | 26 ++++- src/net/http_router.cpp | 24 +++- src/net/http_server_lst.cpp | 186 +++++++++++++++++++++++++------ src/net/http_subscribe.cpp | 4 +- 13 files changed, 517 insertions(+), 59 deletions(-) diff --git a/.gitignore b/.gitignore index c406d65..23db8d6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,203 @@ /.vs /3rdparty/HP-Socket -/out \ No newline at end of file +/out +build/cmake_install.cmake +build/CMakeCache.txt +build/install_manifest.txt +build/Makefile +build/3rdparty/sqlite3/cmake_install.cmake +build/3rdparty/sqlite3/Makefile +build/3rdparty/sqlite3/CMakeFiles/CMakeDirectoryInformation.cmake +build/3rdparty/sqlite3/CMakeFiles/progress.marks +build/3rdparty/sqlite3/CMakeFiles/sqlite3.dir/build.make +build/3rdparty/sqlite3/CMakeFiles/sqlite3.dir/cmake_clean_target.cmake +build/3rdparty/sqlite3/CMakeFiles/sqlite3.dir/cmake_clean.cmake +build/3rdparty/sqlite3/CMakeFiles/sqlite3.dir/compiler_depend.internal +build/3rdparty/sqlite3/CMakeFiles/sqlite3.dir/compiler_depend.make +build/3rdparty/sqlite3/CMakeFiles/sqlite3.dir/compiler_depend.ts +build/3rdparty/sqlite3/CMakeFiles/sqlite3.dir/depend.make +build/3rdparty/sqlite3/CMakeFiles/sqlite3.dir/DependInfo.cmake +build/3rdparty/sqlite3/CMakeFiles/sqlite3.dir/flags.make +build/3rdparty/sqlite3/CMakeFiles/sqlite3.dir/link.txt +build/3rdparty/sqlite3/CMakeFiles/sqlite3.dir/progress.make +build/3rdparty/sqlite3/CMakeFiles/sqlite3.dir/shell.c.o +build/3rdparty/sqlite3/CMakeFiles/sqlite3.dir/shell.c.o.d +build/3rdparty/sqlite3/CMakeFiles/sqlite3.dir/sqlite3.c.o +build/3rdparty/sqlite3/CMakeFiles/sqlite3.dir/sqlite3.c.o.d +build/CMakeFiles/cmake.check_cache +build/CMakeFiles/CMakeDirectoryInformation.cmake +build/CMakeFiles/CMakeOutput.log +build/CMakeFiles/Makefile.cmake +build/CMakeFiles/Makefile2 +build/CMakeFiles/progress.marks +build/CMakeFiles/TargetDirectories.txt +build/CMakeFiles/3.22.1/CMakeCCompiler.cmake +build/CMakeFiles/3.22.1/CMakeCXXCompiler.cmake +build/CMakeFiles/3.22.1/CMakeDetermineCompilerABI_C.bin +build/CMakeFiles/3.22.1/CMakeDetermineCompilerABI_CXX.bin +build/CMakeFiles/3.22.1/CMakeSystem.cmake +build/CMakeFiles/3.22.1/CompilerIdC/a.out +build/CMakeFiles/3.22.1/CompilerIdC/CMakeCCompilerId.c +build/CMakeFiles/3.22.1/CompilerIdCXX/a.out +build/CMakeFiles/3.22.1/CompilerIdCXX/CMakeCXXCompilerId.cpp +build/lib/libsqlite3_d.a +build/lib/libylib_d.a +build/src/cmake_install.cmake +build/src/Makefile +build/src/CMakeFiles/CMakeDirectoryInformation.cmake +build/src/CMakeFiles/progress.marks +build/src/CMakeFiles/ylib.dir/build.make +build/src/CMakeFiles/ylib.dir/cmake_clean_target.cmake +build/src/CMakeFiles/ylib.dir/cmake_clean.cmake +build/src/CMakeFiles/ylib.dir/compiler_depend.internal +build/src/CMakeFiles/ylib.dir/compiler_depend.make +build/src/CMakeFiles/ylib.dir/compiler_depend.ts +build/src/CMakeFiles/ylib.dir/depend.make +build/src/CMakeFiles/ylib.dir/DependInfo.cmake +build/src/CMakeFiles/ylib.dir/flags.make +build/src/CMakeFiles/ylib.dir/link.txt +build/src/CMakeFiles/ylib.dir/progress.make +build/src/CMakeFiles/ylib.dir/base/buffer.cpp.o +build/src/CMakeFiles/ylib.dir/base/buffer.cpp.o.d +build/src/CMakeFiles/ylib.dir/base/conversion.cpp.o +build/src/CMakeFiles/ylib.dir/base/conversion.cpp.o.d +build/src/CMakeFiles/ylib.dir/base/environment.cpp.o +build/src/CMakeFiles/ylib.dir/base/environment.cpp.o.d +build/src/CMakeFiles/ylib.dir/base/error.cpp.o +build/src/CMakeFiles/ylib.dir/base/error.cpp.o.d +build/src/CMakeFiles/ylib.dir/base/exception.cpp.o +build/src/CMakeFiles/ylib.dir/base/exception.cpp.o.d +build/src/CMakeFiles/ylib.dir/base/log4.cpp.o +build/src/CMakeFiles/ylib.dir/base/log4.cpp.o.d +build/src/CMakeFiles/ylib.dir/db/mssql.cpp.o +build/src/CMakeFiles/ylib.dir/db/mssql.cpp.o.d +build/src/CMakeFiles/ylib.dir/db/mysql.cpp.o +build/src/CMakeFiles/ylib.dir/db/mysql.cpp.o.d +build/src/CMakeFiles/ylib.dir/db/sqler.cpp.o +build/src/CMakeFiles/ylib.dir/db/sqler.cpp.o.d +build/src/CMakeFiles/ylib.dir/db/sqlite.cpp.o +build/src/CMakeFiles/ylib.dir/db/sqlite.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/ftp_client.cpp.o +build/src/CMakeFiles/ylib.dir/net/ftp_client.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/http_agent.cpp.o +build/src/CMakeFiles/ylib.dir/net/http_agent.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/http_cache.cpp.o +build/src/CMakeFiles/ylib.dir/net/http_cache.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/http_cdn.cpp.o +build/src/CMakeFiles/ylib.dir/net/http_cdn.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/http_center.cpp.o +build/src/CMakeFiles/ylib.dir/net/http_center.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/http_client_cache.cpp.o +build/src/CMakeFiles/ylib.dir/net/http_client_cache.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/http_client_plus.cpp.o +build/src/CMakeFiles/ylib.dir/net/http_client_plus.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/http_controller.cpp.o +build/src/CMakeFiles/ylib.dir/net/http_controller.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/http_cookie.cpp.o +build/src/CMakeFiles/ylib.dir/net/http_cookie.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/http_header.cpp.o +build/src/CMakeFiles/ylib.dir/net/http_header.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/http_host.cpp.o +build/src/CMakeFiles/ylib.dir/net/http_host.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/http_interceptor.cpp.o +build/src/CMakeFiles/ylib.dir/net/http_interceptor.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/http_interface.cpp.o +build/src/CMakeFiles/ylib.dir/net/http_interface.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/http_reqpack.cpp.o +build/src/CMakeFiles/ylib.dir/net/http_reqpack.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/http_request.cpp.o +build/src/CMakeFiles/ylib.dir/net/http_request.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/http_response.cpp.o +build/src/CMakeFiles/ylib.dir/net/http_response.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/http_router.cpp.o +build/src/CMakeFiles/ylib.dir/net/http_router.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/http_server_lst.cpp.o +build/src/CMakeFiles/ylib.dir/net/http_server_lst.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/http_server.cpp.o +build/src/CMakeFiles/ylib.dir/net/http_server.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/http_session.cpp.o +build/src/CMakeFiles/ylib.dir/net/http_session.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/http_ssl.cpp.o +build/src/CMakeFiles/ylib.dir/net/http_ssl.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/http_subscribe.cpp.o +build/src/CMakeFiles/ylib.dir/net/http_subscribe.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/http_website.cpp.o +build/src/CMakeFiles/ylib.dir/net/http_website.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/http_wsserver.cpp.o +build/src/CMakeFiles/ylib.dir/net/http_wsserver.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/make_form.cpp.o +build/src/CMakeFiles/ylib.dir/net/make_form.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/tcp_agent_lst.cpp.o +build/src/CMakeFiles/ylib.dir/net/tcp_agent_lst.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/tcp_agent.cpp.o +build/src/CMakeFiles/ylib.dir/net/tcp_agent.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/tcp_client_lst.cpp.o +build/src/CMakeFiles/ylib.dir/net/tcp_client_lst.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/tcp_client.cpp.o +build/src/CMakeFiles/ylib.dir/net/tcp_client.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/tcp_forward.cpp.o +build/src/CMakeFiles/ylib.dir/net/tcp_forward.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/tcp_server_lst.cpp.o +build/src/CMakeFiles/ylib.dir/net/tcp_server_lst.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/tcp_server.cpp.o +build/src/CMakeFiles/ylib.dir/net/tcp_server.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/tcp2tcp.cpp.o +build/src/CMakeFiles/ylib.dir/net/tcp2tcp.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/ttu_client.cpp.o +build/src/CMakeFiles/ylib.dir/net/ttu_client.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/udp_node_lst.cpp.o +build/src/CMakeFiles/ylib.dir/net/udp_node_lst.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/udp_node.cpp.o +build/src/CMakeFiles/ylib.dir/net/udp_node.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/util.cpp.o +build/src/CMakeFiles/ylib.dir/net/util.cpp.o.d +build/src/CMakeFiles/ylib.dir/net/utt_server.cpp.o +build/src/CMakeFiles/ylib.dir/net/utt_server.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/cache.cpp.o +build/src/CMakeFiles/ylib.dir/util/cache.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/codec_des3.cpp.o +build/src/CMakeFiles/ylib.dir/util/codec_des3.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/codec.cpp.o +build/src/CMakeFiles/ylib.dir/util/codec.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/coroution.cpp.o +build/src/CMakeFiles/ylib.dir/util/coroution.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/debug.cpp.o +build/src/CMakeFiles/ylib.dir/util/debug.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/desktop.cpp.o +build/src/CMakeFiles/ylib.dir/util/desktop.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/file.cpp.o +build/src/CMakeFiles/ylib.dir/util/file.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/img.cpp.o +build/src/CMakeFiles/ylib.dir/util/img.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/ini.cpp.o +build/src/CMakeFiles/ylib.dir/util/ini.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/json.cpp.o +build/src/CMakeFiles/ylib.dir/util/json.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/localstorage.cpp.o +build/src/CMakeFiles/ylib.dir/util/localstorage.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/md5.cpp.o +build/src/CMakeFiles/ylib.dir/util/md5.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/mem.cpp.o +build/src/CMakeFiles/ylib.dir/util/mem.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/package.cpp.o +build/src/CMakeFiles/ylib.dir/util/package.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/print.cpp.o +build/src/CMakeFiles/ylib.dir/util/print.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/process.cpp.o +build/src/CMakeFiles/ylib.dir/util/process.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/sharedmem.cpp.o +build/src/CMakeFiles/ylib.dir/util/sharedmem.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/sqlite3.cpp.o +build/src/CMakeFiles/ylib.dir/util/sqlite3.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/strutils.cpp.o +build/src/CMakeFiles/ylib.dir/util/strutils.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/system.cpp.o +build/src/CMakeFiles/ylib.dir/util/system.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/thread.cpp.o +build/src/CMakeFiles/ylib.dir/util/thread.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/time.cpp.o +build/src/CMakeFiles/ylib.dir/util/time.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/timeout.cpp.o +build/src/CMakeFiles/ylib.dir/util/timeout.cpp.o.d +build/src/CMakeFiles/ylib.dir/util/window.cpp.o +build/src/CMakeFiles/ylib.dir/util/window.cpp.o.d diff --git a/include/net/http_define.h b/include/net/http_define.h index 4723008..ae0c652 100644 --- a/include/net/http_define.h +++ b/include/net/http_define.h @@ -34,12 +34,64 @@ #define HTTP_INTERCEPTOR_PRINT 0 // http lua 引擎 //#define HTTP_LUA_ENGINE 0 + + + + namespace ylib { namespace network { namespace http { + /// + /// 消息类型 + /// + /// + + enum message_type { + // 普通 + HTTP_SERVER_MESSAGE_TYPE_NORMAL = 0, + // WebSocket + HTTP_SERVER_MESSAGE_TYPE_WEBSOCKET = 1, + }; + enum ws_type { + // 升级 + HTTP_SERVER_WEBSOCKET_TYPE_UPGRADE = 0, + // 消息头 + HTTP_SERVER_WEBSOCKET_TYPE_MESSAGE_HEADER = 1, + // 消息包 + HTTP_SERVER_WEBSOCKET_TYPE_MESSAGE_BODY = 2, + // 关闭 + HTTP_SERVER_WEBSOCKET_TYPE_CLOSE = 3, + }; + struct websocket_message { + struct ws_header { + // 是否结束帧 + bool _final = false; + // 帧操作码 + // 0x0 连续帧 + // 0x1 文本帧 + // 0x2 二进制帧 + // 0x3-7 为非控制帧保留 + // 0x8 连接关闭 + // 0x9 ping + // 0xA pong + // 0xB-F 为控制帧保留 + int opcode = 0x00; + // 是否使用掩码 + uchar mask[4] = {0}; + // 长度 + uint64 length = 0; + }; + + ws_type type; + ws_header header; + + std::string sec_websocket_key; + std::string filepath; + uint64 connid = 0; + }; /// /// 服务端缓存 /// @@ -187,6 +239,8 @@ namespace ylib std::map cert; // 最大上传大小限制 uint64 max_upload_size = 0; + // 支持WebSocket + bool websocket_enable = false; }; class agent; @@ -221,6 +275,12 @@ namespace ylib std::string host; // 缓存路径 ylib::file_io cache_file; + // WS自定义数据 + std::string ws_filepath; + // 是WS + bool is_ws = false; + // WS消息 + websocket_message ws_msg; }; // 代理 struct proxy @@ -270,6 +330,9 @@ namespace ylib size_t offset = 0; size_t length = 0; }; + + + } } diff --git a/include/net/http_reqpack.h b/include/net/http_reqpack.h index b67c85a..59c266e 100644 --- a/include/net/http_reqpack.h +++ b/include/net/http_reqpack.h @@ -31,7 +31,9 @@ namespace ylib /// /// /// - reqpack(const std::string& url, const std::string& host, const ylib::buffer& data, uint64 connid, network::http::server* server,network::http::website* website); + /// + /// + reqpack(const std::string& url, const std::string& host, const ylib::buffer& data, uint64 connid, network::http::server* server,network::http::website* website, network::http::message_type msg_type, std::shared_ptr ws_msg = nullptr); ~reqpack(); /// /// 请求对象 @@ -78,11 +80,30 @@ namespace ylib /// /// ylib::json& extra() { return m_extra; } + /// + /// 消息类型 + /// + /// + network::http::message_type msg_type() { return m_msg_type; } + /// + /// WebSocket消息 + /// + /// + const std::shared_ptr& ws_msg() { return m_ws_msg; } + + + /// + /// 设置为关闭连接包 + /// + void set_close() { m_is_close = true; } + bool is_close() { return m_is_close; } private: // 请求 std::shared_ptr m_request; // 回复 std::shared_ptr m_response; + // WebSocket消息 + std::shared_ptr m_ws_msg; // httpserver network::http::server* m_server = nullptr; // 请求地址 @@ -97,6 +118,11 @@ namespace ylib uint64 m_connid = 0; // 附加数据 ylib::json m_extra; + // 消息类型 + network::http::message_type m_msg_type = HTTP_SERVER_MESSAGE_TYPE_NORMAL; + // 是否为关闭连接包 + bool m_is_close = false; + }; } } diff --git a/include/net/http_request.h b/include/net/http_request.h index beb669e..8f5f775 100644 --- a/include/net/http_request.h +++ b/include/net/http_request.h @@ -84,7 +84,6 @@ namespace ylib /// /// ylib::buffer& body(); - private: // reqpack diff --git a/include/net/http_response.h b/include/net/http_response.h index aa7df13..edbb461 100644 --- a/include/net/http_response.h +++ b/include/net/http_response.h @@ -20,6 +20,9 @@ namespace ylib public: response(network::http::reqpack* reqpack); ~response(); + bool send_header(ushort stateNum, const std::string& stateDesc = "OK"); + /// 发送 WebSocket 帧。opcode 默认 0x1 文本;0x2二进制 0x8关闭 0xA pong + bool send_ws(const char* buf, size_t buf_len, int opcode = 0x1); bool send(const char* buf, size_t buf_len, ushort stateNum = 200, const std::string& stateDesc = "OK"); bool send(const ylib::buffer& value, ushort stateNum = 200, const std::string& stateDesc = "OK"); bool send(const std::string& value, ushort stateNum = 200, const std::string& stateDesc = "OK"); @@ -28,7 +31,10 @@ namespace ylib std::map* headers(); bool redirect(const std::string& filepath, bool MovedPermanently = false); bool forward(const std::string& filepath); - public: + + void response_done(){m_response = true;} + bool is_response_done(){return m_response;} + public: ylib::json sjson; private: bool filecache(const uint64& last_modify_time); diff --git a/include/net/http_router.h b/include/net/http_router.h index 1f2ffe5..f63b5f5 100644 --- a/include/net/http_router.h +++ b/include/net/http_router.h @@ -64,11 +64,16 @@ namespace ylib * param * callback : 触发回调 ******************************************************************/ - void other(std::function callback); + void other(std::function callback); /****************************************************************** * function:数据接收后回调 ******************************************************************/ void on_recved(std::function callback); + + /****************************************************************** + * function:关闭回调 + ******************************************************************/ + void on_close(std::function callback); /****************************************************************** * function:数据发送前回调 * desc:不支持大文件断点传输方式 @@ -90,6 +95,8 @@ namespace ylib private: // 添加任务 void push(reqpack* rp); + // 添加连接断开任务 + void push_close(uint64 connid,std::shared_ptr ws_msg); // 是否为代理任务 bool is_proxy(reqpack* rp); // 是否为CDN服务 @@ -102,11 +109,13 @@ namespace ylib // 线程池 IHPThreadPool* m_threadpool; // [回调] 未订阅请求 - std::function m_callback_other; + std::function m_callback_other; // [回调] 接收后 std::function m_callback_recved; // [回调] 发送前 std::function m_callback_sendbefore; + // [回调] 关闭 + std::function m_callback_close; // 拦截器 std::unique_ptr m_interceptor; // 订阅器 diff --git a/include/net/http_server_lst.h b/include/net/http_server_lst.h index 1745ce0..889baae 100644 --- a/include/net/http_server_lst.h +++ b/include/net/http_server_lst.h @@ -44,6 +44,8 @@ namespace ylib EnHandleResult OnWSMessageHeader(IHttpServer* pSender, CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen); EnHandleResult OnWSMessageBody(IHttpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength); EnHandleResult OnWSMessageComplete(IHttpServer* pSender, CONNID dwConnID); + private: + bool _MessageComplete(IHttpServer* pSender,CONNID dwConnID,message_type msg_type,std::shared_ptr ws_msg = nullptr); private: // HPSERVER 指针 network::http::server* m_server; diff --git a/include/net/http_subscribe.h b/include/net/http_subscribe.h index fb36b72..8158b60 100644 --- a/include/net/http_subscribe.h +++ b/include/net/http_subscribe.h @@ -19,8 +19,8 @@ namespace ylib std::regex regex; std::string pattern; std::string extra; - std::function callback; - std::function callback2; + std::function callback; + std::function callback2; }; /****************************************************** * class:订阅器 @@ -30,7 +30,7 @@ namespace ylib public: subscribe(); ~subscribe(); - bool add(const std::string& pattern,const std::string& extra,std::function callback); + bool add(const std::string& pattern,const std::string& extra,std::function callback); bool remove(const std::string& pattern); bool exist(const std::string& pattern); bool trigger(const std::string& url, network::http::reqpack* rp); diff --git a/src/net/http_reqpack.cpp b/src/net/http_reqpack.cpp index 91fab20..5490c65 100644 --- a/src/net/http_reqpack.cpp +++ b/src/net/http_reqpack.cpp @@ -23,19 +23,23 @@ If you have any questions, please contact us: 1585346868@qq.com Or visit our web #include "net/http_response.h" #include "util/time.h" #define HPSERVER -ylib::network::http::reqpack::reqpack(const std::string& url, const std::string& host, const ylib::buffer& data, uint64 connid, network::http::server* server, network::http::website* website) +ylib::network::http::reqpack::reqpack(const std::string& url, const std::string& host, const ylib::buffer& data, uint64 connid, network::http::server* server, network::http::website* website, network::http::message_type msg_type, std::shared_ptr ws_msg) :m_url(url) ,m_host(host) ,m_data(data) ,m_connid(connid) ,m_server(server) + ,m_msg_type(msg_type) + ,m_ws_msg(ws_msg) { this->website(website); - - m_filepath = strutils::F(((IHttpServer*)m_server->hpserver())->GetUrlField((CONNID)m_connid, HUF_PATH)); + if(m_msg_type == network::http::HTTP_SERVER_MESSAGE_TYPE_WEBSOCKET){ + m_filepath = url; + }else{ + m_filepath = strutils::F(((IHttpServer*)m_server->hpserver())->GetUrlField((CONNID)m_connid, HUF_PATH)); + } // 防止访问上级目录 m_filepath = strutils::remove(m_filepath, ".."); - } ylib::network::http::reqpack::~reqpack() { @@ -59,4 +63,5 @@ const std::shared_ptr& network::http::reqpack::response } return m_response; } + #endif diff --git a/src/net/http_response.cpp b/src/net/http_response.cpp index 4d20fa0..5be92ec 100644 --- a/src/net/http_response.cpp +++ b/src/net/http_response.cpp @@ -58,6 +58,14 @@ ylib::network::http::response::~response() send((std::string)"The server does not return any data to the browser", 500, "Internal Server Error"); } } + +bool ylib::network::http::response::send_ws(const char* buf, size_t buf_len, int opcode) +{ + // 异步入队后 GetWSMessageState 可能已失效,由调用方指定 opcode + // 必须标记已响应,否则析构会再发 HTTP 500,把 WebSocket 连接打断 + m_response = true; + return (bool)HPSERVER->SendWSMessage((CONNID)m_reqpack->connid(), TRUE, 0, (BYTE)opcode, (const BYTE*)buf, (int)buf_len); +} bool ylib::network::http::response::send(const char* buf, size_t buf_len, ushort stateNum, const std::string& stateDesc) { @@ -85,10 +93,11 @@ bool ylib::network::http::response::send(const char* buf, size_t buf_len, ushort m_response = true; //合成THeader //Content-Type + if(view.length() > 0) { HEADER_SET("Content-Type", "text/html"); HEADER_SET("Content-Length", std::to_string((uint64)view.length())); - // 设置默认编码 + // 设置默认编码 { std::string value; auto iter = m_headers.find("Content-Type"); @@ -113,13 +122,22 @@ bool ylib::network::http::response::send(const char* buf, size_t buf_len, ushort idx++; } this->m_reqpack->server()->qps()->response(view.length()); - bool result = (bool)HPSERVER->SendResponse((CONNID)m_reqpack->connid(), stateNum, stateDesc.c_str(), headers, (int32)m_headers.size(), (const BYTE*)view.data(),(int)view.length()); + bool result = false; + if(view.length() > 0){ + result = (bool)HPSERVER->SendResponse((CONNID)m_reqpack->connid(), stateNum, stateDesc.c_str(), headers, (int32)m_headers.size(), (const BYTE*)view.data(),(int)view.length()); + }else{ + result = (bool)HPSERVER->SendResponse((CONNID)m_reqpack->connid(), stateNum, stateDesc.c_str(), headers, (int32)m_headers.size()); + } + delete[] headers; return result; } } - +bool ylib::network::http::response::send_header(ushort stateNum, const std::string& stateDesc) +{ + return send(NULL, 0, stateNum, stateDesc); +} bool ylib::network::http::response::send(const ylib::buffer& value, ushort stateNum, const std::string& stateDesc) { return send(value.data(), value.length(), stateNum, stateDesc); @@ -378,7 +396,7 @@ bool ylib::network::http::response::forward(const std::string& filepath) if(m_response == true) return false; m_response = true; - network::http::reqpack* reqpack = new network::http::reqpack(filepath,m_reqpack->host(),m_reqpack->body(),m_reqpack->connid(), m_reqpack->server(), m_reqpack->website()); + network::http::reqpack* reqpack = new network::http::reqpack(filepath,m_reqpack->host(),m_reqpack->body(),m_reqpack->connid(), m_reqpack->server(), m_reqpack->website(), m_reqpack->msg_type(), m_reqpack->ws_msg()); reqpack->extra() = m_reqpack->extra(); m_reqpack->website()->router()->push(reqpack); diff --git a/src/net/http_router.cpp b/src/net/http_router.cpp index 854d002..2611e7a 100644 --- a/src/net/http_router.cpp +++ b/src/net/http_router.cpp @@ -97,10 +97,14 @@ network::http::subscribe* ylib::network::http::router::subscribe() m_subscribe->center(center()); return m_subscribe.get(); } -void network::http::router::other(std::function callback) +void network::http::router::other(std::function callback) { this->m_callback_other = callback; } +void ylib::network::http::router::on_close(std::function callback) +{ + m_callback_close = callback; +} void ylib::network::http::router::on_recved(std::function callback) { m_callback_recved = callback; @@ -119,7 +123,12 @@ VOID __HP_CALL TaskProc_function(PVOID pvArg) } void ylib::network::http::router::__thread_callback(reqpack* rp) { - + if(rp->is_close()){ + if(m_callback_close != nullptr){ + m_callback_close((uint64)rp->connid(), rp->ws_msg().get()); + } + return; + } /*======== ======CDN服务==============*/ if (is_cdn(rp)) return; @@ -150,7 +159,7 @@ void ylib::network::http::router::__thread_callback(reqpack* rp) // 其它 if (m_callback_other != nullptr) - m_callback_other(rp->request().get(), rp->response().get()); + m_callback_other(rp->request().get(), rp->response().get(), rp->ws_msg().get()); } catch (const std::exception& e) { @@ -165,7 +174,14 @@ void ylib::network::http::router::push(reqpack *rp) { m_handle_queue.push(rp); } - +void ylib::network::http::router::push_close(uint64 connid,std::shared_ptr ws_msg) +{ + // url/host 必须是合法 string;传 0/nullptr 会按 const char* 构造 std::string 直接 logic_error + std::string url = (ws_msg != nullptr) ? ws_msg->filepath : std::string(); + reqpack* rp = new reqpack(url, std::string(), ylib::buffer(), connid, nullptr, nullptr, network::http::HTTP_SERVER_MESSAGE_TYPE_WEBSOCKET, ws_msg); + rp->set_close(); + m_handle_queue.push(rp); +} bool ylib::network::http::router::is_cdn(reqpack* rp) { diff --git a/src/net/http_server_lst.cpp b/src/net/http_server_lst.cpp index ed4ff5c..492dc00 100644 --- a/src/net/http_server_lst.cpp +++ b/src/net/http_server_lst.cpp @@ -31,8 +31,6 @@ If you have any questions, please contact us: 1585346868@qq.com Or visit our web #include "net/util.h" #include "net/http_cache.h" #include "util/codec.h" - -#define BARE_HP 0 ylib::network::http::http_server_lst::http_server_lst(server* server) { @@ -41,7 +39,7 @@ ylib::network::http::http_server_lst::http_server_lst(server* server) ylib::network::http::http_server_lst::~http_server_lst() { -} +} EnHandleResult ylib::network::http::http_server_lst::OnPrepareListen(ITcpServer* pSender, SOCKET soListen) { @@ -51,9 +49,7 @@ EnHandleResult ylib::network::http::http_server_lst::OnPrepareListen(ITcpServer* EnHandleResult ylib::network::http::http_server_lst::OnAccept(ITcpServer* pSender, CONNID dwConnID, UINT_PTR soClient) { //std::cout << "[OnAccept] HttpServerConnect:" << pSender->GetConnectionCount() << std::endl; -#if BARE_HP == 0 pSender->SetConnectionExtra(dwConnID, (PVOID)new temp_recv); -#endif #if HTTP_SERVER_DEBUG_PRINT == 1 ylib::log->info("OnAccept ("+std::to_string((uint64)dwConnID)+")","http_server"); #endif @@ -116,7 +112,6 @@ EnHandleResult ylib::network::http::http_server_lst::OnClose(ITcpServer* pSender #if HTTP_SERVER_DEBUG_PRINT == 1 ylib::log->info("OnClose ("+std::to_string((uint64)dwConnID)+")","http_server"); #endif -#if BARE_HP == 0 PVOID extra = 0; if (pSender->GetConnectionExtra(dwConnID, &extra)) { @@ -129,11 +124,26 @@ EnHandleResult ylib::network::http::http_server_lst::OnClose(ITcpServer* pSender m_server->agent()->disconnect(tr->agent_ssl,tr->agent_connid); } #endif + if(tr->is_ws){ + auto website = m_server->center()->website(tr->host); + if (website != nullptr) + { + std::shared_ptr ws_msg = std::make_shared(); + ws_msg->type = network::http::HTTP_SERVER_WEBSOCKET_TYPE_CLOSE; + ws_msg->filepath = tr->ws_filepath; + website->router()->push_close((uint64)dwConnID,ws_msg); + } + } + + delete tr; } } -#endif + + + + return HR_OK; } @@ -142,7 +152,7 @@ EnHttpParseResult ylib::network::http::http_server_lst::OnMessageBegin(IHttpServ #if HTTP_SERVER_DEBUG_PRINT == 1 ylib::log->info("OnMessageBegin ("+std::to_string((uint64)dwConnID)+")","http_server"); #endif -#if BARE_HP == 0 + PVOID extra = 0; if (pSender->GetConnectionExtra(dwConnID, &extra)) { @@ -151,7 +161,7 @@ EnHttpParseResult ylib::network::http::http_server_lst::OnMessageBegin(IHttpServ ((temp_recv*)extra)->data.clear(); } } -#endif + return HPR_OK; } @@ -161,16 +171,15 @@ EnHttpParseResult ylib::network::http::http_server_lst::OnRequestLine(IHttpServe // ylib::log->info("OnRequestLine ("+nstring::from((uint64)dwConnID)+")","http_server"); //#endif -#if BARE_HP == 0 PVOID extra = 0; if (pSender->GetConnectionExtra(dwConnID, &extra)) { if (extra != 0) { ((temp_recv*)extra)->url = lpszUrl; - } + ((temp_recv*)extra)->ws_filepath = std::string(lpszUrl); + } } -#endif return HPR_OK; } @@ -188,7 +197,6 @@ EnHttpParseResult ylib::network::http::http_server_lst::OnHeader(IHttpServer* pS #if HTTP_SERVER_DEBUG_PRINT == 1 ylib::log->info("OnHeader ("+std::to_string((uint64)dwConnID)+")"+lpszName+":"+lpszValue,"http_server"); #endif -#if BARE_HP == 0 if(strcmp(lpszName,"Host") == 0){ PVOID extra = 0; if (pSender->GetConnectionExtra(dwConnID, &extra)) @@ -200,7 +208,6 @@ EnHttpParseResult ylib::network::http::http_server_lst::OnHeader(IHttpServer* pS } } -#endif return HPR_OK; } @@ -232,6 +239,53 @@ EnHttpParseResult ylib::network::http::http_server_lst::OnUpgrade(IHttpServer* p ylib::log->info("OnUpgrade ("+std::to_string((uint64)dwConnID)+")","http_server"); #endif + if (m_server->center()->config().websocket_enable) + { + if (enUpgradeType == HUT_WEB_SOCKET) + { + + + PVOID extra = 0; + if (pSender->GetConnectionExtra(dwConnID, &extra)) + { + if (extra != 0) + { + ((temp_recv*)extra)->is_ws = true; + } + } + + + LPCSTR lpszValue = nullptr; + if (pSender->GetHeader(dwConnID,"Sec-WebSocket-Key", &lpszValue) == false) + return HPR_ERROR; + + // std::string value = std::string(lpszValue)+ "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + + // std::string accept_value = codec::base64::en(codec::sha1(value)); + + + + // THeader headers[3]; + // headers[0].name = "Connection"; + // headers[0].value = "Upgrade"; + // headers[1].name = "Upgrade"; + // headers[1].value = "WebSocket"; + // headers[2].name = "Sec-WebSocket-Accept"; + // headers[2].value = accept_value.c_str(); + // pSender->SendResponse(dwConnID, 101, "Switching Protocols", headers,3); + + std::shared_ptr ws_msg = std::make_shared(); + ws_msg->sec_websocket_key = std::string(lpszValue); + ws_msg->connid = (uint64)dwConnID; + ws_msg->type = network::http::HTTP_SERVER_WEBSOCKET_TYPE_UPGRADE; + if (_MessageComplete(pSender,dwConnID,network::http::HTTP_SERVER_MESSAGE_TYPE_WEBSOCKET,ws_msg)) + return HPR_OK; + return HPR_ERROR; + } + else + return HPR_ERROR; + } + return HPR_OK; } @@ -241,7 +295,6 @@ EnHttpParseResult ylib::network::http::http_server_lst::OnBody(IHttpServer* pSen ylib::log->info("OnBody ("+std::to_string((uint64)dwConnID)+")","http_server"); #endif -#if BARE_HP == 0 PVOID extra = 0; if (pSender->GetConnectionExtra(dwConnID, &extra)) { @@ -257,20 +310,11 @@ EnHttpParseResult ylib::network::http::http_server_lst::OnBody(IHttpServer* pSen } } } -#endif return HPR_OK; } - -EnHttpParseResult ylib::network::http::http_server_lst::OnMessageComplete(IHttpServer* pSender, CONNID dwConnID) +bool ylib::network::http::http_server_lst::_MessageComplete(IHttpServer* pSender,CONNID dwConnID,network::http::message_type msg_type,std::shared_ptr ws_msg) { -#if HTTP_SERVER_DEBUG_PRINT == 1 - ylib::log->info("OnMessageComplete ("+std::to_string((uint64)dwConnID)+")","http_server"); -#endif -#if BARE_HP == 1 - pSender->SendResponse(dwConnID, 200, "OK", nullptr, 0, (const BYTE*)"ONLY_HP_OK", 3); - return HPR_OK; -#endif - network::http::reqpack* rp = nullptr; + network::http::reqpack* rp = nullptr; temp_recv* tr = nullptr; { @@ -280,10 +324,10 @@ EnHttpParseResult ylib::network::http::http_server_lst::OnMessageComplete(IHttpS if (extra != 0) tr = (temp_recv*)extra; else - return HPR_OK; + return true; } else - return HPR_OK; + return true; } // QPS记录 @@ -294,10 +338,16 @@ EnHttpParseResult ylib::network::http::http_server_lst::OnMessageComplete(IHttpS { pSender->SendResponse(dwConnID, 404, "Not Found", nullptr, 0, (const BYTE*)"No fount site", 12); delete rp; - return HPR_OK; + return false; } // 创建请求包 - rp = new network::http::reqpack(tr->url, tr->host, tr->data, (uint64)dwConnID, m_server, website); + std::string url; + if(msg_type == network::http::HTTP_SERVER_MESSAGE_TYPE_WEBSOCKET){ + url = tr->ws_filepath; + }else{ + url = tr->url; + } + rp = new network::http::reqpack(url, tr->host, tr->data, (uint64)dwConnID, m_server, website, msg_type, ws_msg); // 开始前处理请求包 { @@ -310,13 +360,19 @@ EnHttpParseResult ylib::network::http::http_server_lst::OnMessageComplete(IHttpS rp->body() = end_data; } } - - // 追加置路由 website->router()->push(rp); - return HPR_OK; - + return true; +} +EnHttpParseResult ylib::network::http::http_server_lst::OnMessageComplete(IHttpServer* pSender, CONNID dwConnID) +{ +#if HTTP_SERVER_DEBUG_PRINT == 1 + ylib::log->info("OnMessageComplete ("+std::to_string((uint64)dwConnID)+")","http_server"); +#endif + if (_MessageComplete(pSender,dwConnID,network::http::HTTP_SERVER_MESSAGE_TYPE_NORMAL,nullptr)) + return HPR_OK; + return HPR_ERROR; } EnHttpParseResult ylib::network::http::http_server_lst::OnParseError(IHttpServer* pSender, CONNID dwConnID, int iErrorCode, LPCSTR lpszErrorDesc) @@ -339,16 +395,74 @@ EnHttpParseResult ylib::network::http::http_server_lst::OnParseError(IHttpServer EnHandleResult ylib::network::http::http_server_lst::OnWSMessageHeader(IHttpServer* pSender, CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen) { - return HR_OK; + + if(iReserved != 0) + return HR_ERROR; // 服务器不支持扩展 + + + std::shared_ptr ws_msg = std::make_shared(); + ws_msg->type = network::http::HTTP_SERVER_WEBSOCKET_TYPE_MESSAGE_HEADER; + ws_msg->connid = (uint64)dwConnID; + ws_msg->header._final = bFinal; + ws_msg->header.opcode = iOperationCode; + ws_msg->header.mask[0] = lpszMask[0]; + ws_msg->header.mask[1] = lpszMask[1]; + ws_msg->header.mask[2] = lpszMask[2]; + ws_msg->header.mask[3] = lpszMask[3]; + ws_msg->header.length = ullBodyLen; + + + + PVOID extra = 0; + if (pSender->GetConnectionExtra(dwConnID, &extra)) + { + if (extra != 0) + { + ((temp_recv*)extra)->data.clear(); + ((temp_recv*)extra)->ws_msg = *ws_msg.get(); + } + } + + + if (_MessageComplete(pSender,dwConnID,network::http::HTTP_SERVER_MESSAGE_TYPE_WEBSOCKET,ws_msg)) + return HR_OK; + return HR_ERROR; } EnHandleResult ylib::network::http::http_server_lst::OnWSMessageBody(IHttpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength) { + PVOID extra = 0; + if (pSender->GetConnectionExtra(dwConnID, &extra)) + { + if (extra != 0) + { + ((temp_recv*)extra)->data.append((char*)pData, iLength); + } + } return HR_OK; } EnHandleResult ylib::network::http::http_server_lst::OnWSMessageComplete(IHttpServer* pSender, CONNID dwConnID) { - return HR_OK; + + std::shared_ptr ws_msg = std::make_shared(); + + PVOID extra = 0; + if (pSender->GetConnectionExtra(dwConnID, &extra)) + { + if (extra != 0) + { + // 先带上 HEADER 缓存的 opcode 等信息;不要在这里 clear data, + // 否则 _MessageComplete 拷贝到 reqpack 的 body 会是空的 + *ws_msg.get() = ((temp_recv*)extra)->ws_msg; + } + } + ws_msg->type = network::http::HTTP_SERVER_WEBSOCKET_TYPE_MESSAGE_BODY; + ws_msg->connid = (uint64)dwConnID; + if(_MessageComplete(pSender,dwConnID,network::http::HTTP_SERVER_MESSAGE_TYPE_WEBSOCKET,ws_msg)) + { + return HR_OK; + } + return HR_ERROR; } #endif diff --git a/src/net/http_subscribe.cpp b/src/net/http_subscribe.cpp index abc536d..a777fde 100644 --- a/src/net/http_subscribe.cpp +++ b/src/net/http_subscribe.cpp @@ -30,7 +30,7 @@ network::http::subscribe::~subscribe() { clear(); } -bool network::http::subscribe::add(const std::string& pattern, const std::string& extra, std::function callback) +bool network::http::subscribe::add(const std::string& pattern, const std::string& extra, std::function callback) { std::unique_lock lock(m_rw_mutex); // 判断是否存在 @@ -81,7 +81,7 @@ bool network::http::subscribe::trigger(const std::string& url, network::http::re for (size_t i = 0; i < m_list.size(); i++) { if (std::regex_match(url.c_str(), m_list[i].regex)) { - m_list[i].callback(rp->request().get(), rp->response().get(), m_list[i].pattern, m_list[i].extra); + m_list[i].callback(rp->request().get(), rp->response().get(), rp->ws_msg().get(), m_list[i].pattern, m_list[i].extra); return true; } }