Selaa lähdekoodia

增加websocket支持

Dev User 1 kuukausi sitten
vanhempi
sitoutus
c7a9e1c457

+ 201 - 1
.gitignore

@@ -1,3 +1,203 @@
 /.vs
 /3rdparty/HP-Socket
-/out
+/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

+ 63 - 0
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
         {
+              /// <summary>
+            /// 消息类型
+            /// </summary>
+            /// <returns></returns>
+
+            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;
+            };
             /// <summary>
             /// 服务端缓存
             /// </summary>
@@ -187,6 +239,8 @@ namespace ylib
                 std::map<std::string, ssl_config> 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;
             };
+
+          
+           
         }
 
     }

+ 27 - 1
include/net/http_reqpack.h

@@ -31,7 +31,9 @@ namespace ylib
                 /// <param name="connid"></param>
                 /// <param name="server"></param>
                 /// <param name="website"></param>
-                reqpack(const std::string& url, const std::string& host, const ylib::buffer& data, uint64 connid, network::http::server* server,network::http::website* website);
+                /// <param name="msg_type"></param>
+                /// <param name="ws_msg"></param>
+                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<network::http::websocket_message> ws_msg = nullptr);
                 ~reqpack();
                 /// <summary>
                 /// 请求对象
@@ -78,11 +80,30 @@ namespace ylib
                 /// </summary>
                 /// <returns></returns>
                 ylib::json& extra() { return m_extra; }
+                /// <summary>
+                /// 消息类型
+                /// </summary>
+                /// <returns></returns>
+                network::http::message_type msg_type() { return m_msg_type; }
+                /// <summary>
+                /// WebSocket消息
+                /// </summary>
+                /// <returns></returns>
+                const std::shared_ptr<network::http::websocket_message>& ws_msg() { return m_ws_msg; }
+
+
+                /// <summary>
+                /// 设置为关闭连接包
+                /// </summary>
+                void set_close() { m_is_close = true; }
+                bool is_close() { return m_is_close; }
             private:
                 // 请求
                 std::shared_ptr<network::http::request> m_request;
                 // 回复
                 std::shared_ptr<network::http::response> m_response;
+                // WebSocket消息
+                std::shared_ptr<network::http::websocket_message> 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;
+                
             };
         }
     }

+ 0 - 1
include/net/http_request.h

@@ -84,7 +84,6 @@ namespace ylib
                 /// </summary>
                 /// <returns></returns>
                 ylib::buffer& body();
-
             private:
 
                 // reqpack

+ 7 - 1
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");
+                /// <summary>发送 WebSocket 帧。opcode 默认 0x1 文本;0x2二进制 0x8关闭 0xA pong</summary>
+                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<std::string, std::string>* 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);

+ 11 - 2
include/net/http_router.h

@@ -64,11 +64,16 @@ namespace ylib
                  * param
                  *      callback                :           触发回调
                  ******************************************************************/
-                void other(std::function<void(network::http::request*, network::http::response*)> callback);
+                void other(std::function<void(network::http::request*, network::http::response*,network::http::websocket_message*)> callback);
                 /******************************************************************
                  * function:数据接收后回调
                  ******************************************************************/
                 void on_recved(std::function<void(const ylib::buffer& begin, ylib::buffer* end)> callback);
+
+                /******************************************************************
+                 * function:关闭回调
+                 ******************************************************************/
+                void on_close(std::function<void(uint64 connid,network::http::websocket_message* ws_msg)> callback);
                 /******************************************************************
                  * function:数据发送前回调
                  * desc:不支持大文件断点传输方式
@@ -90,6 +95,8 @@ namespace ylib
             private:
                 // 添加任务
                 void push(reqpack* rp);
+                // 添加连接断开任务
+                void push_close(uint64 connid,std::shared_ptr<network::http::websocket_message> ws_msg);
                 // 是否为代理任务
                 bool is_proxy(reqpack* rp);
                 // 是否为CDN服务
@@ -102,11 +109,13 @@ namespace ylib
                 // 线程池
                 IHPThreadPool* m_threadpool;
                 // [回调] 未订阅请求
-                std::function<void(network::http::request*, network::http::response*)> m_callback_other;
+                std::function<void(network::http::request*, network::http::response*,network::http::websocket_message*)> m_callback_other;
                 // [回调] 接收后
                 std::function<void(const ylib::buffer& begin, ylib::buffer* end)> m_callback_recved;
                 // [回调] 发送前
                 std::function<void(const ylib::buffer& begin, ylib::buffer* end)> m_callback_sendbefore;
+                // [回调] 关闭
+                std::function<void(uint64 connid,network::http::websocket_message* ws_msg)> m_callback_close;
                 // 拦截器
                 std::unique_ptr<network::http::interceptor> m_interceptor;
                 // 订阅器

+ 2 - 0
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<websocket_message> ws_msg = nullptr);
             private:
                 // HPSERVER 指针
                 network::http::server* m_server;

+ 3 - 3
include/net/http_subscribe.h

@@ -19,8 +19,8 @@ namespace ylib
                 std::regex regex;
                 std::string pattern;
                 std::string extra;
-				std::function<void(network::http::request* request, network::http::response* response, const std::string& pattern, const std::string& extra)> callback;
-                std::function<void(network::http::request* request, network::http::response* response)> callback2;
+				std::function<void(network::http::request* request, network::http::response* response,network::http::websocket_message* ws_msg, const std::string& pattern, const std::string& extra)> callback;
+                std::function<void(network::http::request* request, network::http::response* response,network::http::websocket_message* ws_msg)> callback2;
             };
             /******************************************************
              * class:订阅器
@@ -30,7 +30,7 @@ namespace ylib
             public:
                 subscribe();
                 ~subscribe();
-                bool add(const std::string& pattern,const std::string& extra,std::function<void(network::http::request* request, network::http::response* response, const std::string& pattern, const std::string& extra)> callback);
+                bool add(const std::string& pattern,const std::string& extra,std::function<void(network::http::request* request, network::http::response* response,network::http::websocket_message* ws_msg, const std::string& pattern, const std::string& extra)> callback);
                 bool remove(const std::string& pattern);
                 bool exist(const std::string& pattern);
                 bool trigger(const std::string& url, network::http::reqpack* rp);

+ 9 - 4
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<network::http::websocket_message> 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::response>& network::http::reqpack::response
     }
     return m_response;
 }
+
 #endif

+ 22 - 4
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);

+ 20 - 4
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<void(network::http::request*,network::http::response*)> callback)
+void network::http::router::other(std::function<void(network::http::request*,network::http::response*,network::http::websocket_message*)> callback)
 {
     this->m_callback_other = callback;
 }
+void ylib::network::http::router::on_close(std::function<void(uint64 connid,network::http::websocket_message* ws_msg)> callback)
+{
+    m_callback_close = callback;
+}
 void ylib::network::http::router::on_recved(std::function<void(const ylib::buffer &begin, ylib::buffer* end)> 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<network::http::websocket_message> 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)
 {

+ 150 - 36
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<network::http::websocket_message> ws_msg = std::make_shared<network::http::websocket_message>();
+					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<network::http::websocket_message> ws_msg = std::make_shared<network::http::websocket_message>();
+			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<network::http::websocket_message> 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<network::http::websocket_message> ws_msg = std::make_shared<network::http::websocket_message>();
+	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<network::http::websocket_message> ws_msg = std::make_shared<network::http::websocket_message>();
+
+	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

+ 2 - 2
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<void(network::http::request* request, network::http::response* response, const std::string& pattern,const std::string& extra)> callback)
+bool network::http::subscribe::add(const std::string& pattern, const std::string& extra, std::function<void(network::http::request* request, network::http::response* response,network::http::websocket_message* ws_msg, const std::string& pattern,const std::string& extra)> callback)
 {
     std::unique_lock<std::shared_mutex> 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;
         }
     }