hewei.it 4 anos atrás
pai
commit
37705499e5

+ 2 - 2
cpputil/hmain.h

@@ -27,8 +27,8 @@ typedef struct main_ctx_s {
     char**  os_argv;
     char**  save_argv;
     char*   cmdline;
-    keyval_t    arg_kv;
-    StringList  arg_list;
+    keyval_t        arg_kv;
+    hv::StringList  arg_list;
 
     // env
     int     envc;

+ 2 - 0
cpputil/hpath.cpp

@@ -1,5 +1,7 @@
 #include "hpath.h"
 
+#include "hplatform.h"
+
 bool HPath::exists(const char* path) {
     return access(path, 0) == 0;
 }

+ 4 - 5
cpputil/hpath.h

@@ -4,7 +4,6 @@
 #include <string> // for std::string
 
 #include "hexport.h"
-#include "hplatform.h" // for stat
 
 class HV_EXPORT HPath {
 public:
@@ -17,10 +16,10 @@ public:
     // dirname  = /mnt/share/image
     // filename = test
     // suffixname = jpg
-    static std::string basename(const std::string& str);
-    static std::string dirname(const std::string& str);
-    static std::string filename(const std::string& str);
-    static std::string suffixname(const std::string& str);
+    static std::string basename(const std::string& filepath);
+    static std::string dirname(const std::string& filepath);
+    static std::string filename(const std::string& filepath);
+    static std::string suffixname(const std::string& filepath);
 
     static std::string join(const std::string& dir, const std::string& filename);
 };

+ 24 - 20
cpputil/hstring.cpp

@@ -9,13 +9,15 @@ static inline int vscprintf(const char* fmt, va_list ap) {
     return vsnprintf(NULL, 0, fmt, ap);
 }
 
-string asprintf(const char* fmt, ...) {
+namespace hv {
+
+std::string asprintf(const char* fmt, ...) {
     va_list ap;
     va_start(ap, fmt);
     int len = vscprintf(fmt, ap);
     va_end(ap);
 
-    string str;
+    std::string str;
     str.reserve(len+1);
     // must resize to set str.size
     str.resize(len);
@@ -27,7 +29,7 @@ string asprintf(const char* fmt, ...) {
     return str;
 }
 
-StringList split(const string& str, char delim) {
+StringList split(const std::string& str, char delim) {
     /*
     std::stringstream ss;
     ss << str;
@@ -52,7 +54,7 @@ StringList split(const string& str, char delim) {
     return res;
 }
 
-hv::KeyValue splitKV(const string& str, char kv_kv, char k_v) {
+hv::KeyValue splitKV(const std::string& str, char kv_kv, char k_v) {
     enum {
         s_key,
         s_value,
@@ -87,26 +89,26 @@ hv::KeyValue splitKV(const string& str, char kv_kv, char k_v) {
     return kvs;
 }
 
-string trim(const string& str, const char* chars) {
-    string::size_type pos1 = str.find_first_not_of(chars);
-    if (pos1 == string::npos)   return "";
+std::string trim(const std::string& str, const char* chars) {
+    std::string::size_type pos1 = str.find_first_not_of(chars);
+    if (pos1 == std::string::npos)   return "";
 
-    string::size_type pos2 = str.find_last_not_of(chars);
+    std::string::size_type pos2 = str.find_last_not_of(chars);
     return str.substr(pos1, pos2-pos1+1);
 }
 
-string trimL(const string& str, const char* chars) {
-    string::size_type pos = str.find_first_not_of(chars);
-    if (pos == string::npos)    return "";
+std::string trimL(const std::string& str, const char* chars) {
+    std::string::size_type pos = str.find_first_not_of(chars);
+    if (pos == std::string::npos)    return "";
     return str.substr(pos);
 }
 
-string trimR(const string& str, const char* chars) {
-    string::size_type pos = str.find_last_not_of(chars);
+std::string trimR(const std::string& str, const char* chars) {
+    std::string::size_type pos = str.find_last_not_of(chars);
     return str.substr(0, pos+1);
 }
 
-string trim_pairs(const string& str, const char* pairs) {
+std::string trim_pairs(const std::string& str, const char* pairs) {
     const char* s = str.c_str();
     const char* e = str.c_str() + str.size() - 1;
     const char* p = pairs;
@@ -121,15 +123,17 @@ string trim_pairs(const string& str, const char* pairs) {
     return is_pair ? str.substr(1, str.size()-2) : str;
 }
 
-string replace(const string& str, const string& find, const string& rep) {
-    string::size_type pos = 0;
-    string::size_type a = find.size();
-    string::size_type b = rep.size();
+std::string replace(const std::string& str, const std::string& find, const std::string& rep) {
+    std::string::size_type pos = 0;
+    std::string::size_type a = find.size();
+    std::string::size_type b = rep.size();
 
-    string res(str);
-    while ((pos = res.find(find, pos)) != string::npos) {
+    std::string res(str);
+    while ((pos = res.find(find, pos)) != std::string::npos) {
         res.replace(pos, a, rep);
         pos += b;
     }
     return res;
 }
+
+} // end namespace hv

+ 17 - 16
cpputil/hstring.h

@@ -6,11 +6,15 @@
 #include <sstream>
 
 #include "hexport.h"
-#include "hbase.h"
+#include "hplatform.h"
 #include "hmap.h"
 
-using std::string;
-typedef std::vector<string> StringList;
+#define SPACE_CHARS     " \t\r\n"
+#define PAIR_CHARS      "{}[]()<>\"\"\'\'``"
+
+namespace hv {
+
+typedef std::vector<std::string> StringList;
 
 // std::map<std::string, std::string, StringCaseLess>
 class StringCaseLess : public std::less<std::string> {
@@ -20,7 +24,6 @@ public:
     }
 };
 
-namespace hv {
 // NOTE: low-version NDK not provide std::to_string
 template<typename T>
 HV_INLINE std::string to_string(const T& t) {
@@ -36,20 +39,18 @@ HV_INLINE T from_string(const std::string& str) {
     iss >> t;
     return t;
 }
-}
-
-#define SPACE_CHARS     " \t\r\n"
-#define PAIR_CHARS      "{}[]()<>\"\"\'\'``"
 
-HV_EXPORT string asprintf(const char* fmt, ...);
+HV_EXPORT std::string asprintf(const char* fmt, ...);
 // x,y,z
-HV_EXPORT StringList split(const string& str, char delim = ',');
+HV_EXPORT StringList split(const std::string& str, char delim = ',');
 // user=amdin&pswd=123456
-HV_EXPORT hv::KeyValue splitKV(const string& str, char kv_kv = '&', char k_v = '=');
-HV_EXPORT string trim(const string& str, const char* chars = SPACE_CHARS);
-HV_EXPORT string trimL(const string& str, const char* chars = SPACE_CHARS);
-HV_EXPORT string trimR(const string& str, const char* chars = SPACE_CHARS);
-HV_EXPORT string trim_pairs(const string& str, const char* pairs = PAIR_CHARS);
-HV_EXPORT string replace(const string& str, const string& find, const string& rep);
+HV_EXPORT hv::KeyValue splitKV(const std::string& str, char kv_kv = '&', char k_v = '=');
+HV_EXPORT std::string trim(const std::string& str, const char* chars = SPACE_CHARS);
+HV_EXPORT std::string trimL(const std::string& str, const char* chars = SPACE_CHARS);
+HV_EXPORT std::string trimR(const std::string& str, const char* chars = SPACE_CHARS);
+HV_EXPORT std::string trim_pairs(const std::string& str, const char* pairs = PAIR_CHARS);
+HV_EXPORT std::string replace(const std::string& str, const std::string& find, const std::string& rep);
+
+} // end namespace hv
 
 #endif // HV_STRING_H_

+ 27 - 28
cpputil/iniparser.cpp

@@ -9,6 +9,8 @@
 #include "hfile.h"
 #include "hbase.h"
 
+using namespace hv;
+
 /**********************************
 # div
 
@@ -29,8 +31,8 @@ public:
         INI_NODE_TYPE_DIV,
         INI_NODE_TYPE_SPAN,
     } type;
-    string  label; // section|key|comment
-    string  value;
+    std::string  label; // section|key|comment
+    std::string  value;
     std::list<IniNode*>    children;
 
     virtual ~IniNode() {
@@ -56,7 +58,7 @@ public:
         }
     }
 
-    IniNode* Get(const string& label, Type type = INI_NODE_TYPE_KEY_VALUE) {
+    IniNode* Get(const std::string& label, Type type = INI_NODE_TYPE_KEY_VALUE) {
         for (auto pNode : children) {
             if (pNode->type == type && pNode->label == label) {
                 return pNode;
@@ -71,7 +73,7 @@ public:
     IniSection() : IniNode(), section(label) {
         type = INI_NODE_TYPE_SECTION;
     }
-    string &section;
+    std::string &section;
 };
 
 class IniKeyValue : public IniNode {
@@ -79,14 +81,14 @@ public:
     IniKeyValue() : IniNode(), key(label) {
         type = INI_NODE_TYPE_KEY_VALUE;
     }
-    string &key;
+    std::string &key;
 };
 
 class IniComment : public IniNode {
 public:
     IniComment() : IniNode(), comment(label) {
     }
-    string &comment;
+    std::string &comment;
 };
 
 IniParser::IniParser() {
@@ -131,11 +133,9 @@ int IniParser::LoadFromMem(const char* data) {
     ss << data;
     std::string strLine;
     int line = 0;
-    string::size_type pos;
+    std::string::size_type pos;
 
-    string      content;
-    string      comment;
-    string      strDiv;
+    std::string content, comment, strDiv;
     IniNode* pScopeNode = root_;
     IniNode* pNewNode = NULL;
     while (std::getline(ss, strLine)) {
@@ -151,7 +151,7 @@ int IniParser::LoadFromMem(const char* data) {
         // trim_comment
         comment = "";
         pos = content.find_first_of(_comment);
-        if (pos != string::npos) {
+        if (pos != std::string::npos) {
             comment = content.substr(pos);
             content = content.substr(0, pos);
         }
@@ -184,7 +184,7 @@ int IniParser::LoadFromMem(const char* data) {
             }
         } else {
             pos = content.find_first_of(_delim);
-            if (pos != string::npos) {
+            if (pos != std::string::npos) {
                 // key-value
                 pNewNode = new IniNode;
                 pNewNode->type = IniNode::INI_NODE_TYPE_KEY_VALUE;
@@ -218,7 +218,7 @@ int IniParser::LoadFromMem(const char* data) {
     return 0;
 }
 
-void IniParser::DumpString(IniNode* pNode, string& str) {
+void IniParser::DumpString(IniNode* pNode, std::string& str) {
     if (pNode == NULL)  return;
 
     if (pNode->type != IniNode::INI_NODE_TYPE_SPAN) {
@@ -256,8 +256,8 @@ void IniParser::DumpString(IniNode* pNode, string& str) {
     }
 }
 
-string IniParser::DumpString() {
-    string str;
+std::string IniParser::DumpString() {
+    std::string str;
     DumpString(root_, str);
     return str;
 }
@@ -267,7 +267,7 @@ int IniParser::Save() {
 }
 
 int IniParser::SaveAs(const char* filepath) {
-    string str = DumpString();
+    std::string str = DumpString();
     if (str.length() == 0) {
         return 0;
     }
@@ -281,7 +281,7 @@ int IniParser::SaveAs(const char* filepath) {
     return 0;
 }
 
-string IniParser::GetValue(const string& key, const string& section) {
+std::string IniParser::GetValue(const std::string& key, const std::string& section) {
     if (root_ == NULL)  return "";
 
     IniNode* pSection = root_;
@@ -296,7 +296,7 @@ string IniParser::GetValue(const string& key, const string& section) {
     return pKV->value;
 }
 
-void IniParser::SetValue(const string& key, const string& value, const string& section) {
+void IniParser::SetValue(const std::string& key, const std::string& value, const std::string& section) {
     if (root_ == NULL) {
         root_ = new IniNode;
     }
@@ -323,35 +323,34 @@ void IniParser::SetValue(const string& key, const string& value, const string& s
 }
 
 template<>
-HV_EXPORT bool IniParser::Get(const string& key, const string& section, bool defvalue) {
-    string str = GetValue(key, section);
+HV_EXPORT bool IniParser::Get(const std::string& key, const std::string& section, bool defvalue) {
+    std::string str = GetValue(key, section);
     return str.empty() ? defvalue : getboolean(str.c_str());
 }
 
 template<>
-HV_EXPORT int IniParser::Get(const string& key, const string& section, int defvalue) {
-    string str = GetValue(key, section);
+HV_EXPORT int IniParser::Get(const std::string& key, const std::string& section, int defvalue) {
+    std::string str = GetValue(key, section);
     return str.empty() ? defvalue : atoi(str.c_str());
 }
 
 template<>
-HV_EXPORT float IniParser::Get(const string& key, const string& section, float defvalue) {
-    string str = GetValue(key, section);
+HV_EXPORT float IniParser::Get(const std::string& key, const std::string& section, float defvalue) {
+    std::string str = GetValue(key, section);
     return str.empty() ? defvalue : atof(str.c_str());
 }
 
 template<>
-HV_EXPORT void IniParser::Set(const string& key, const bool& value, const string& section) {
+HV_EXPORT void IniParser::Set(const std::string& key, const bool& value, const std::string& section) {
     SetValue(key, value ? "true" : "false", section);
 }
 
 template<>
-HV_EXPORT void IniParser::Set(const string& key, const int& value, const string& section) {
+HV_EXPORT void IniParser::Set(const std::string& key, const int& value, const std::string& section) {
     SetValue(key, asprintf("%d", value), section);
 }
 
 template<>
-HV_EXPORT void IniParser::Set(const string& key, const float& value, const string& section) {
+HV_EXPORT void IniParser::Set(const std::string& key, const float& value, const std::string& section) {
     SetValue(key, asprintf("%f", value), section);
 }
-

+ 9 - 10
cpputil/iniparser.h

@@ -2,7 +2,6 @@
 #define HV_INI_PARSER_H_
 
 #include <string>
-using std::string;
 
 #include "hexport.h"
 
@@ -22,28 +21,28 @@ public:
     int Unload();
     int Reload();
 
-    string DumpString();
+    std::string DumpString();
     int Save();
     int SaveAs(const char* filepath);
 
-    string GetValue(const string& key, const string& section = "");
-    void   SetValue(const string& key, const string& value, const string& section = "");
+    std::string GetValue(const std::string& key, const std::string& section = "");
+    void        SetValue(const std::string& key, const std::string& value, const std::string& section = "");
 
     // T = [bool, int, float]
     template<typename T>
-    T Get(const string& key, const string& section = "", T defvalue = 0);
+    T Get(const std::string& key, const std::string& section = "", T defvalue = 0);
 
     // T = [bool, int, float]
     template<typename T>
-    void Set(const string& key, const T& value, const string& section = "");
+    void Set(const std::string& key, const T& value, const std::string& section = "");
 
 protected:
-    void DumpString(IniNode* pNode, string& str);
+    void DumpString(IniNode* pNode, std::string& str);
 
 public:
-    string  _comment;
-    string  _delim;
-    string  _filepath;
+    std::string _comment;
+    std::string _delim;
+    std::string _filepath;
 private:
     IniNode* root_;
 };

+ 5 - 4
examples/consul/consul.cpp

@@ -1,6 +1,7 @@
 #include "consul.h"
 
 #include "http_client.h"
+using namespace hv;
 
 #include "json.hpp"
 using json = nlohmann::json;
@@ -12,11 +13,11 @@ static const char url_register[] = "/agent/service/register";
 static const char url_deregister[] = "/agent/service/deregister";
 static const char url_discover[] = "/catalog/service";
 
-static string make_url(const char* ip, int port, const char* url) {
+static std::string make_url(const char* ip, int port, const char* url) {
     return asprintf(PROTOCOL "%s:%d/" API_VERSION "%s", ip, port, url);
 }
 
-static string make_ServiceID(consul_service_t* service) {
+static std::string make_ServiceID(consul_service_t* service) {
     return asprintf("%s-%s:%d", service->name, service->ip, service->port);
 }
 
@@ -81,7 +82,7 @@ int register_service(consul_node_t* node, consul_service_t* service, consul_heal
 }
 
 int deregister_service(consul_node_t* node, consul_service_t* service) {
-    string url = make_url(node->ip, node->port, url_deregister);
+    std::string url = make_url(node->ip, node->port, url_deregister);
     url += '/';
     url += make_ServiceID(service);
 
@@ -98,7 +99,7 @@ int deregister_service(consul_node_t* node, consul_service_t* service) {
 }
 
 int discover_services(consul_node_t* node, const char* service_name, std::vector<consul_service_t>& services) {
-    string url = make_url(node->ip, node->port, url_discover);
+    std::string url = make_url(node->ip, node->port, url_discover);
     url += '/';
     url += service_name;
 

+ 1 - 1
examples/hmain_test.cpp

@@ -78,7 +78,7 @@ int parse_confile(const char* confile) {
     }
 
     // logfile
-    string str = g_conf_ctx.parser->GetValue("logfile");
+    std::string str = g_conf_ctx.parser->GetValue("logfile");
     if (!str.empty()) {
         strncpy(g_main_ctx.logfile, str.c_str(), sizeof(g_main_ctx.logfile));
     }

+ 2 - 2
examples/httpd/handler.cpp

@@ -226,8 +226,8 @@ int Handler::restful(const HttpContextPtr& ctx) {
 }
 
 int Handler::login(const HttpContextPtr& ctx) {
-    string username = ctx->get("username");
-    string password = ctx->get("password");
+    std::string username = ctx->get("username");
+    std::string password = ctx->get("password");
     if (username.empty() || password.empty()) {
         response_status(ctx, 10001, "Miss username or password");
         return HTTP_STATUS_BAD_REQUEST;

+ 1 - 1
examples/httpd/httpd.cpp

@@ -56,7 +56,7 @@ int parse_confile(const char* confile) {
     }
 
     // logfile
-    string str = ini.GetValue("logfile");
+    std::string str = ini.GetValue("logfile");
     if (!str.empty()) {
         strncpy(g_main_ctx.logfile, str.c_str(), sizeof(g_main_ctx.logfile));
     }

+ 2 - 0
examples/nmap/nmap.cpp

@@ -4,6 +4,8 @@
 #include "hsocket.h"
 #include "netinet.h"
 
+using namespace hv;
+
 #define MAX_RECVFROM_TIMEOUT    5000 // ms
 #define MAX_SENDTO_PERSOCKET    1024
 

+ 3 - 1
http/HttpMessage.cpp

@@ -7,6 +7,8 @@
 #include "hurl.h"
 #include "http_parser.h" // for http_parser_url
 
+using namespace hv;
+
 char HttpMessage::s_date[32] = {0};
 
 bool HttpCookie::parse(const std::string& str) {
@@ -429,7 +431,7 @@ int HttpMessage::ParseBody() {
             return false;
         }
         boundary += strlen("boundary=");
-        string strBoundary(boundary);
+        std::string strBoundary(boundary);
         strBoundary = trim_pairs(strBoundary, "\"\"\'\'");
         return parse_multipart(body, form, strBoundary.c_str());
     }

+ 8 - 8
http/HttpMessage.h

@@ -45,7 +45,7 @@ struct HNetAddr {
     int             port;
 
     std::string ipport() {
-        return asprintf("%s:%d", ip.c_str(), port);
+        return hv::asprintf("%s:%d", ip.c_str(), port);
     }
 };
 
@@ -69,11 +69,11 @@ struct HV_EXPORT HttpCookie {
     std::string dump() const;
 };
 
-typedef std::map<std::string, std::string, StringCaseLess>  http_headers;
-typedef std::vector<HttpCookie>                             http_cookies;
-typedef std::string                                         http_body;
-typedef std::function<void(const char* data, size_t size)>  http_body_cb;
-typedef std::function<void(const char* data, size_t size)>  http_chunked_cb;
+typedef std::map<std::string, std::string, hv::StringCaseLess>  http_headers;
+typedef std::vector<HttpCookie>                                 http_cookies;
+typedef std::string                                             http_body;
+typedef std::function<void(const char* data, size_t size)>      http_body_cb;
+typedef std::function<void(const char* data, size_t size)>      http_chunked_cb;
 
 class HV_EXPORT HttpMessage {
 public:
@@ -361,7 +361,7 @@ public:
 
     // Range: bytes=0-4095
     void SetRange(long from = 0, long to = -1) {
-        headers["Range"] = asprintf("bytes=%ld-%ld", from, to);
+        headers["Range"] = hv::asprintf("bytes=%ld-%ld", from, to);
     }
     bool GetRange(long& from, long& to) {
         auto iter = headers.find("Range");
@@ -409,7 +409,7 @@ public:
 
     // Content-Range: bytes 0-4095/10240000
     void SetRange(long from, long to, long total) {
-        headers["Content-Range"] = asprintf("bytes %ld-%ld/%ld", from, to, total);
+        headers["Content-Range"] = hv::asprintf("bytes %ld-%ld/%ld", from, to, total);
     }
     bool GetRange(long& from, long& to, long& total) {
         auto iter = headers.find("Content-Range");

+ 2 - 0
http/client/http_client.cpp

@@ -16,6 +16,8 @@
 // for async
 #include "AsyncHttpClient.h"
 
+using namespace hv;
+
 struct http_client_s {
     std::string  host;
     int          port;

+ 3 - 1
http/http_content.cpp

@@ -4,6 +4,8 @@
 
 #include <string.h>
 
+using namespace hv;
+
 std::string dump_query_params(const QueryParams& query_params) {
     std::string query_string;
     for (auto& pair : query_params) {
@@ -134,7 +136,7 @@ struct multipart_parser_userdata {
                 StringList kv = split(trim(str, " "), '=');
                 if (kv.size() == 2) {
                     const char* key = kv.begin()->c_str();
-                    string value = *(kv.begin() + 1);
+                    std::string value = *(kv.begin() + 1);
                     value = trim_pairs(value, "\"\"\'\'");
                     if (strcmp(key, "name") == 0) {
                         name = value;

+ 0 - 3
http/server/HttpHandler.cpp

@@ -20,9 +20,6 @@ int HttpHandler::HandleHttpRequest() {
 
 preprocessor:
     state = HANDLE_BEGIN;
-    if (writer) {
-        writer->Begin();
-    }
     if (service->preprocessor) {
         status_code = service->preprocessor(pReq, pResp);
         if (status_code != 0) {

+ 21 - 3
http/server/HttpHandler.h

@@ -16,12 +16,17 @@ public:
     uint64_t                    last_recv_pong_time;
 
     WebSocketHandler() {
-        parser.reset(new WebSocketParser);
-        // channel.reset(new WebSocketChannel);
         last_send_ping_time = 0;
         last_recv_pong_time = 0;
     }
 
+    void Init(hio_t* io = NULL, ws_session_type type = WS_SERVER) {
+        parser.reset(new WebSocketParser);
+        if (io) {
+            channel.reset(new hv::WebSocketChannel(io, type));
+        }
+    }
+
     void onopen() {
         channel->status = hv::SocketChannel::CONNECTED;
     }
@@ -83,7 +88,13 @@ public:
         ws_service = NULL;
     }
 
-    bool Init(int http_version = 1) {
+    ~HttpHandler() {
+        if (writer) {
+            writer->status = hv::SocketChannel::DISCONNECTED;
+        }
+    }
+
+    bool Init(int http_version = 1, hio_t* io = NULL) {
         parser.reset(HttpParser::New(HTTP_SERVER, (enum http_version)http_version));
         if (parser == NULL) {
             return false;
@@ -98,6 +109,10 @@ public:
             resp->http_minor = 0;
         }
         parser->InitRequest(req.get());
+        if (io) {
+            writer.reset(new hv::HttpResponseWriter(io, resp));
+            writer->status = hv::SocketChannel::CONNECTED;
+        }
         return true;
     }
 
@@ -120,6 +135,9 @@ public:
         req->Reset();
         resp->Reset();
         parser->InitRequest(req.get());
+        if (writer) {
+            writer->Begin();
+        }
     }
 
     int FeedRecvData(const char* data, size_t len);

+ 2 - 9
http/server/HttpServer.cpp

@@ -104,15 +104,11 @@ static void on_recv(hio_t* io, void* _buf, int readbytes) {
         if (strncmp((char*)buf, HTTP2_MAGIC, MIN(readbytes, HTTP2_MAGIC_LEN)) == 0) {
             http_version = 2;
         }
-        if (!handler->Init(http_version)) {
+        if (!handler->Init(http_version, io)) {
             hloge("[%s:%d] unsupported HTTP%d", handler->ip, handler->port, http_version);
             hio_close(io);
             return;
         }
-        handler->writer.reset(new HttpResponseWriter(io, handler->resp));
-        if (handler->writer) {
-            handler->writer->status = SocketChannel::CONNECTED;
-        }
     }
 
     int nfeed = handler->FeedRecvData(buf, readbytes);
@@ -221,7 +217,7 @@ static void on_recv(hio_t* io, void* _buf, int readbytes) {
     // switch protocol to websocket
     if (upgrade && upgrade_protocol == HttpHandler::WEBSOCKET) {
         WebSocketHandler* ws = handler->SwitchWebSocket();
-        ws->channel.reset(new WebSocketChannel(io, WS_SERVER));
+        ws->Init(io);
         ws->parser->onMessage = std::bind(websocket_onmessage, std::placeholders::_1, std::placeholders::_2, io);
         // NOTE: cancel keepalive timer, judge alive by heartbeat.
         hio_set_keepalive_timeout(io, 0);
@@ -246,9 +242,6 @@ static void on_close(hio_t* io) {
             // onclose
             handler->WebSocketOnClose();
         }
-        if (handler->writer) {
-            handler->writer->status = SocketChannel::DISCONNECTED;
-        }
         hevent_set_userdata(io, NULL);
         delete handler;
     }

+ 2 - 2
http/server/HttpService.h

@@ -111,8 +111,8 @@ struct HV_EXPORT HttpService {
             http_async_handler* async_handler = NULL,
             http_handler* handler = NULL);
 
-    StringList Paths() {
-        StringList paths;
+    hv::StringList Paths() {
+        hv::StringList paths;
         for (auto& pair : api_handlers) {
             paths.emplace_back(pair.first);
         }

+ 1 - 0
unittest/hstring_test.cpp

@@ -1,4 +1,5 @@
 #include "hstring.h"
+using namespace hv;
 
 int main(int argc, char** argv) {
     /*