diff --git a/include/KBaseVirtualHost.h b/include/KBaseVirtualHost.h index fa9bfd5..8dc9c7d 100644 --- a/include/KBaseVirtualHost.h +++ b/include/KBaseVirtualHost.h @@ -15,6 +15,7 @@ #include "KConfigTree.h" #include "KPathHandler.h" #include "KSharedObj.h" +#include "serializable.h" #ifdef ENABLE_BLACK_LIST #include "KIpList.h" #endif @@ -22,6 +23,7 @@ void on_vh_event(void* data, kconfig::KConfigTree* tree, kconfig::KConfigEvent* class KApiPipeStream; class KVirtualHost; class KHttpFilterManage; +#if 0 class KDataAttribute { public: @@ -32,12 +34,13 @@ class KDataAttribute virtual KDataAttribute* add(const KString& name) = 0; virtual void build(KWStream& s, int format) = 0; }; +#endif class KVirtualHostEvent { public: virtual ~KVirtualHostEvent() { }; - virtual KDataAttribute* data() = 0; + virtual kgl::serializable* data() = 0; virtual void setStatus(const char* errMsg) = 0; virtual void redirect(const char* event) = 0; virtual void buildVh(KVirtualHost* vh) = 0; diff --git a/include/serializable.h b/include/serializable.h new file mode 100644 index 0000000..2fda34b --- /dev/null +++ b/include/serializable.h @@ -0,0 +1,124 @@ +#ifndef SERIALIZABLE_H +#define SERIALIZABLE_H +#include "KStream.h" +#include "KStringBuf.h" +#include "KXmlDocument.h" +#include +#include +namespace kgl { + using string = KString; + using wstream = KWStream; + enum class data_type { + STR, + OBJ, + INT, + STR_ARRAY, + OBJ_ARRAY, + INT_ARRAY + }; + enum class format { + xml_attribute, + xml_text, + json + }; + class data_value; + class serializable { + public: + ~serializable(); + serializable() { + + } + serializable(serializable&& a) noexcept { + data.swap(a.data); + } + serializable(const serializable& a) = delete; + + bool add(const string& name, const string& value); + bool add(const string& name, int64_t v); + serializable* add(const string& name); + + std::vector* add_string_array(const string& name); + std::vector* add_int_array(const string& name); + serializable* add_obj_array(const string& name); + serializable& operator = (serializable&& a) noexcept; + serializable& operator = (const serializable& a); + + bool get(const string& name, string& value) const; + const string& get(const string& name) const; + const string* getx(const string& name) const; + const int64_t get_int(const string& name) const; + void build(wstream& s, format fmt); + private: + std::map data; + }; + + class data_value { + public: + data_value(const string& value) { + type = data_type::STR; + this->str = new string(value); + } + data_value(int64_t v) :i{ v } { + type = data_type::INT; + } + data_value(data_type type); + data_value* add_ref() { + katom_inc((void*)&refs); + return this; + } + void release() { + if (katom_dec((void*)&refs) == 0) { + delete this; + } + } + data_type change_to_array() { + switch (type) { + case data_type::STR: + { + auto v = str; + strs = new std::vector{ *v }; + delete v; + type = data_type::STR_ARRAY; + break; + } + case data_type::INT: + { + auto v = i; + ints = new std::vector{ v }; + type = data_type::INT_ARRAY; + break; + } + case data_type::OBJ: + { + auto v = obj; + objs = new std::vector< serializable>(); + objs->emplace_back(std::move(*v)); + delete v; + type = data_type::OBJ_ARRAY; + break; + } + default: + break; + } + return type; + } + void build(const string& name, wstream& s, format fmt); + union { + std::vector* strs; //STR_ARRAY + std::vector* objs; //OBJ_ARRAY + std::vector* ints; //INT_ARRAY + string* str; //STR + serializable* obj; //OBJ + int64_t i; //INT + }; + data_type get_type() const { + return type; + } + private: + data_type type; + volatile int32_t refs = 1; + ~data_value(); + }; + +} +#endif diff --git a/module/whm/KWhmService.cpp b/module/whm/KWhmService.cpp index f3f84ec..935056e 100644 --- a/module/whm/KWhmService.cpp +++ b/module/whm/KWhmService.cpp @@ -41,32 +41,36 @@ bool KWhmService::service(KServiceProvider *provider) { provider->sendStatus(STATUS_OK, "OK"); const char *callName = uv->getx("whm_call"); const char* v = uv->getx("format"); - int format = OUTPUT_FORMAT_XML; - if (v && strcasecmp(v, "json") == 0) { - format = OUTPUT_FORMAT_JSON; + kgl::format fmt = kgl::format::xml_text; + if (v) { + if (strcasecmp(v, "json") == 0) { + fmt = kgl::format::json; + } else if (strcasecmp(v, "xml-attribute") == 0) { + fmt = kgl::format::xml_attribute; + } } KWStream *out = provider->getOutputStream(); - if (format == OUTPUT_FORMAT_XML) { + if (fmt!= kgl::format::json) { provider->sendUnknowHeader("Content-Type", "text/xml"); *out << "\n"; } else { provider->sendUnknowHeader("Content-Type", "application/json"); } if(callName){ - if (format == OUTPUT_FORMAT_XML) { + if (fmt != kgl::format::json) { *out << "<" << callName << " whm_version=\"1.0\">"; } else { *out << "{\"call\":\"" << callName << "\","; } int ret = package->process(callName,&context); - context.flush(ret, format); - if (format == OUTPUT_FORMAT_XML) { + context.flush(ret, fmt); + if (fmt != kgl::format::json) { *out << "\n"; } else { *out << "}"; } }else{ - if (format == OUTPUT_FORMAT_XML) { + if (fmt != kgl::format::json) { *out << "whm_call cann't be empty"; } else { *out << "{\"status\":\"404\",\"result\":\"whm_call cann't be empty\"}"; diff --git a/module/whm/WhmContext.cpp b/module/whm/WhmContext.cpp index a2f7e0d..fa8f656 100644 --- a/module/whm/WhmContext.cpp +++ b/module/whm/WhmContext.cpp @@ -36,6 +36,7 @@ bool WhmContext::add(const char* name, INT64 value) { void WhmContext::add(const char* name, KString& value) { add(name, value.c_str()); } +#if 0 WhmDataValue::WhmDataValue() { type = WhmDataType::OBJ; encode = false; @@ -152,9 +153,9 @@ void WhmDataValue::build(const KString& name, KWStream& s, int format) { } } } - +#endif bool WhmContext::add(const char* name, const char* value, bool encode) { - return data()->add(name, value, encode); + return data()->add(name, value); } bool WhmContext::add(const KString& name, const KString& value) { return data()->add(name, value); @@ -190,16 +191,16 @@ bool WhmContext::buildVh() { } return true; } -bool WhmContext::flush(int status, int format) { +bool WhmContext::flush(int status, kgl::format fmt) { KWStream* out = getOutputStream(); if (status > 0) { - if (format == OUTPUT_FORMAT_XML) { + if (fmt != kgl::format::json) { *out << " 0) { *out << " " << statusMsg; } *out << "\">\n"; - } else if (format == OUTPUT_FORMAT_JSON) { + } else { *out << "\"status\":\"" << status; if (statusMsg.size() > 0) { *out << " " << statusMsg; @@ -207,9 +208,9 @@ bool WhmContext::flush(int status, int format) { *out << "\",\"result\":{\n"; } } - dv.build(*out, format); + dv.build(*out, fmt); if (status > 0) { - if (format == OUTPUT_FORMAT_XML) { + if (fmt != kgl::format::json) { *out << "\n"; } else { *out << "}"; diff --git a/module/whm/WhmContext.h b/module/whm/WhmContext.h index b00f744..fb2da75 100644 --- a/module/whm/WhmContext.h +++ b/module/whm/WhmContext.h @@ -16,6 +16,8 @@ #include "KStream.h" #include "whm.h" #include "KExtendProgram.h" +#include "serializable.h" +#if 0 #define OUTPUT_FORMAT_XML 0 #define OUTPUT_FORMAT_JSON 1 class WhmDataAttribute; @@ -47,6 +49,11 @@ struct WhmDataValue { }; class WhmDataAttribute : public KDataAttribute { public: + ~WhmDataAttribute() { + for (auto it = data.begin(); it != data.end(); ++it) { + delete (*it).second; + } + } bool add(const KString& name, const KString& value, bool encode = false) override { auto it = data.find(name); if (it == data.end()) { @@ -58,7 +65,7 @@ class WhmDataAttribute : public KDataAttribute { return false; } (*it).second->strs->push_back(value); - return false; + return true; } bool add(const KString& name, int64_t value) override { auto it = data.find(name); @@ -109,6 +116,7 @@ class WhmDataAttribute : public KDataAttribute { } std::map data; }; +#endif class WhmContext : public KVirtualHostEvent, public KDynamicString { public: WhmContext(KServiceProvider* provider); @@ -166,11 +174,11 @@ class WhmContext : public KVirtualHostEvent, public KDynamicString { this->statusMsg += statusMsg; } } - bool flush(int status, int format = OUTPUT_FORMAT_XML); - KDataAttribute* data() override { + bool flush(int status, kgl::format fmt = kgl::format::xml_text); + kgl::serializable* data() override { return &dv; } - KDataAttribute* add(const KString& name) { + kgl::serializable* add(const KString& name) { return data()->add(name); } void add(const char* name, KString& value); @@ -194,7 +202,7 @@ class WhmContext : public KVirtualHostEvent, public KDynamicString { } char* save(char* p); private: - WhmDataAttribute dv; + kgl::serializable dv; std::list memorys; KServiceProvider* provider; KUrlValue urlValue; diff --git a/module/whm/WhmShell.cpp b/module/whm/WhmShell.cpp index 8d70cb8..0712c0b 100644 --- a/module/whm/WhmShell.cpp +++ b/module/whm/WhmShell.cpp @@ -1,16 +1,14 @@ #include "WhmShell.h" #include "WhmShellSession.h" -KTHREAD_FUNCTION whmShellAsyncThread(void *param) -{ - WhmShellContext *sc = (WhmShellContext *)param; - WhmShell *shell = sc->shell; +KTHREAD_FUNCTION whmShellAsyncThread(void* param) { + WhmShellContext* sc = (WhmShellContext*)param; + WhmShell* shell = sc->shell; assert(shell); shell->asyncRun(sc); KTHREAD_RETURN; } -WhmShell::WhmShell() -{ +WhmShell::WhmShell() { process = last = NULL; curProcess = NULL; head = end = NULL; @@ -18,8 +16,7 @@ WhmShell::WhmShell() merge_context = NULL; merge_context_running = false; } -WhmShell::~WhmShell() -{ +WhmShell::~WhmShell() { while (process) { last = process->next; delete process; @@ -29,12 +26,11 @@ WhmShell::~WhmShell() delete curProcess; } } -void WhmShell::flush() -{ +void WhmShell::flush() { lock.Lock(); while (head && kgl_current_sec - head->closedTime > 30) { context.erase(head->session); - WhmShellContext *sc = head; + WhmShellContext* sc = head; head = head->next; if (head) { head->prev = NULL; @@ -45,12 +41,11 @@ void WhmShell::flush() } lock.Unlock(); } -void WhmShell::readStdin(WhmShellContext *sc,WhmContext *context) -{ +void WhmShell::readStdin(WhmShellContext* sc, WhmContext* context) { //查找标准输入数据 - auto it = context->getUrlValue()->attribute.find("-"); - if (it!=context->getUrlValue()->attribute.end()) { - sc->in_buffer.write_all((*it).second.c_str(),(int)(*it).second.size()); + kgl::string stdin_str; + if (context->getUrlValue()->get("-", stdin_str)) { + sc->in_buffer.write_all(stdin_str.c_str(), stdin_str.size()); } } void WhmShell::initContext(WhmShellContext *sc,WhmContext *context) diff --git a/module/whm/WhmShellContext.h b/module/whm/WhmShellContext.h index 211af76..ede545a 100644 --- a/module/whm/WhmShellContext.h +++ b/module/whm/WhmShellContext.h @@ -72,7 +72,6 @@ class WhmShellContext : public KCountableEx,public KDynamicString } bool buildValue(const char *name,KStringBuf *s) { - std::map::iterator it; if (strncasecmp(name,"vh:",3)==0) { name += 3; if(ds){ @@ -89,7 +88,7 @@ class WhmShellContext : public KCountableEx,public KDynamicString const char *value = "/"; if (*name=='$') { name ++; - it = attribute.find(name); + auto it = attribute.find(name); if (it!=attribute.end()) { value = (*it).second.c_str(); } @@ -119,11 +118,10 @@ class WhmShellContext : public KCountableEx,public KDynamicString if (strncasecmp(name,"url:",4)==0) { name += 4; } - - it = attribute.find(name); + auto it = attribute.find(name); if (it!=attribute.end()) { *s << (*it).second; - } + } return true; } WhmShell *shell; diff --git a/src/KAccess.cpp b/src/KAccess.cpp index 06b5d50..f3b071f 100644 --- a/src/KAccess.cpp +++ b/src/KAccess.cpp @@ -999,13 +999,13 @@ bool KAccess::on_config_event(kconfig::KConfigTree* tree, kconfig::KConfigEvent* } void KAccess::build_action_attribute(KXmlAttribute& attribute, const KUrlValue& uv) { KStringBuf action; - action << uv.attribute["jump_type"]; - if (uv.attribute["jump_type"] == "server") { - action << ":" << uv.attribute["server"]; - } else if (uv.attribute["jump_type"] == "table") { - action << ":" << uv.attribute["table"]; - } else if (uv.attribute["jump_type"] == "wback") { - action << ":" << uv.attribute["wback"]; + action << uv["jump_type"]; + if (uv["jump_type"] == "server") { + action << ":" << uv["server"]; + } else if (uv["jump_type"] == "table") { + action << ":" << uv["table"]; + } else if (uv["jump_type"] == "wback") { + action << ":" << uv["wback"]; } attribute.emplace("action"_CS, action.str()); } diff --git a/src/KBaseVirtualHost.cpp b/src/KBaseVirtualHost.cpp index 6529a64..4d115b8 100644 --- a/src/KBaseVirtualHost.cpp +++ b/src/KBaseVirtualHost.cpp @@ -210,11 +210,13 @@ void KBaseVirtualHost::addMimeType(const char* ext, const char* type, kgl_compre void KBaseVirtualHost::listIndex(KVirtualHostEvent* ev) { KStringBuf s; lock.Lock(); - for (auto it = indexFiles.begin(); it != indexFiles.end(); it++) { - s << "\n"; + auto indexs = ev->data()->add_string_array("index"); + if (indexs) { + for (auto it = indexFiles.begin(); it != indexFiles.end(); it++) { + indexs->push_back((*it)); + } } lock.Unlock(); - ev->data()->add("indexs", s.str().c_str(), false); } void KBaseVirtualHost::getIndexHtml(const KString& url, KWStream& s) { s << ""; diff --git a/src/serializable.cpp b/src/serializable.cpp new file mode 100644 index 0000000..7486ef0 --- /dev/null +++ b/src/serializable.cpp @@ -0,0 +1,298 @@ +#include "serializable.h" +#include "KXmlEvent.h" +namespace kgl { + static void build_json_string(wstream& s, const string& v) { + s << "\""_CS; + for (size_t i = 0; i < v.size(); ++i) { + if (v[i] == '\\' || v[i] == '"') { + s << "\\"; + } + s << v[i]; + } + s << "\""_CS; + } + static void build_xml_text(wstream& s, const string& v) { + if (v.find('<') != string::npos) { + s << CDATA_START << v << CDATA_END; + return; + } + s << v; + return; + } + static inline void build_xml_attribute(wstream& s, const string& v) { + build_json_string(s, v); + } + data_value::data_value(data_type type) :type{ type } { + switch (type) { + case data_type::INT_ARRAY: + ints = new std::vector; + break; + case data_type::STR_ARRAY: + strs = new std::vector; + break; + case data_type::OBJ_ARRAY: + objs = new std::vector; + break; + case data_type::OBJ: + obj = new serializable; + break; + default: + throw std::bad_exception(); + } + } + data_value::~data_value() { + switch (type) { + case data_type::INT_ARRAY: + delete ints; + break; + case data_type::STR_ARRAY: + delete strs; + break; + case data_type::OBJ_ARRAY: + delete objs; + break; + case data_type::OBJ: + delete obj; + break; + case data_type::STR: + delete str; + break; + default: + break; + } + } + void data_value::build(const string& name, wstream& s, format fmt) { + switch (fmt) { + case format::xml_text: + switch (type) { + case data_type::OBJ: + s << "<"_CS << name << ">"_CS; + obj->build(s, fmt); + s << ""_CS; + return; + case data_type::OBJ_ARRAY: + for (auto it = objs->begin(); it != objs->end(); ++it) { + s << "<"_CS << name << ">"_CS; + (*it).build(s, fmt); + s << ""_CS; + } + return; + case data_type::STR: + s << "<"_CS << name << ">"_CS; + build_xml_text(s, *str); + s << ""_CS; + return; + case data_type::STR_ARRAY: + for (auto it = strs->begin(); it != strs->end(); ++it) { + s << "<"_CS << name << ">"_CS; + build_xml_text(s, (*it)); + s << ""_CS; + } + return; + case data_type::INT_ARRAY: + for (auto it = ints->begin(); it != ints->end(); ++it) { + s << "<"_CS << name << ">"_CS; + s << *it; + s << ""_CS; + } + return; + case data_type::INT: + s << "<"_CS << name << ">"_CS << this->i << ""_CS; + return; + } + break; + case format::json: + switch (type) { + case data_type::OBJ_ARRAY: + s << "\""_CS << name << "\":["_CS; + for (auto it = objs->begin(); it != objs->end(); ++it) { + if (it != objs->begin()) { + s << ","_CS; + } + s << "{"_CS; + (*it).build(s, fmt); + s << "}"_CS; + } + s << "]"; + return; + case data_type::OBJ: + s << "\""_CS << name << "\":{"_CS; + obj->build(s, fmt); + s << "}"_CS; + return; + case data_type::STR_ARRAY: + s << "\""_CS << name << "\":["_CS; + for (auto it = strs->begin(); it != strs->end(); ++it) { + if (it != strs->begin()) { + s << ","_CS; + } + build_json_string(s, *it); + } + s << "]"; + return; + case data_type::STR: + s << "\""_CS << name << "\":"_CS; + build_json_string(s, *str); + return; + case data_type::INT: + s << "\""_CS << name << "\":"_CS << this->i; + return; + case data_type::INT_ARRAY: + s << "\""_CS << name << "\":["_CS; + for (auto it = ints->begin(); it != ints->end(); ++it) { + if (it != ints->begin()) { + s << ","_CS; + } + s << (*it); + } + s << "]"; + return; + } + default: + break; + } + } + serializable::~serializable() { + for (auto it = data.begin(); it != data.end(); ++it) { + (*it).second->release(); + } + } + bool serializable::add(const string& name, const string& value) { + auto it = data.find(name); + if (it == data.end()) { + data_value* dv = new data_value(value); + data.emplace(name, dv); + return true; + } + auto dv = (*it).second; + switch (dv->get_type()) { + case data_type::STR: + dv->change_to_array(); + //[[fallthrough]]; + case data_type::STR_ARRAY: + dv->strs->push_back(value); + return true; + default: + break; + } + return false; + } + bool serializable::add(const string& name, int64_t value) { + auto it = data.find(name); + if (it == data.end()) { + data_value* dv = new data_value(value); + data.emplace(name, dv); + return true; + } + auto dv = (*it).second; + switch (dv->get_type()) { + case data_type::INT: + dv->change_to_array(); + //[[fallthrough]]; + case data_type::INT_ARRAY: + dv->ints->push_back(value); + return true; + default: + break; + } + return false; + } + serializable* serializable::add(const string& name) { + auto it = data.find(name); + if (it == data.end()) { + data_value* dv = new data_value(data_type::OBJ); + data.emplace(name, dv); + return dv->obj; + } + auto dv = (*it).second; + switch (dv->get_type()) { + case data_type::OBJ: + dv->change_to_array(); + //[[fallthrough]]; + case data_type::OBJ_ARRAY: + dv->objs->emplace_back(); + return &(*(dv->objs->rend())); + default: + break; + } + return nullptr; + } + std::vector* serializable::add_string_array(const string& name) { + auto it = data.find(name); + if (it == data.end()) { + data_value* dv = new data_value(data_type::OBJ_ARRAY); + data.emplace(name, dv); + return dv->strs; + } + return nullptr; + } + std::vector* serializable::add_int_array(const string& name) { + auto it = data.find(name); + if (it == data.end()) { + data_value* dv = new data_value(data_type::INT_ARRAY); + data.emplace(name, dv); + return dv->ints; + } + return nullptr; + } + serializable* serializable::add_obj_array(const string& name) { + auto it = data.find(name); + if (it == data.end()) { + data_value* dv = new data_value(data_type::OBJ_ARRAY); + data.emplace(name, dv); + dv->objs->emplace_back(); + return &(*(dv->objs->rend())); + } + return nullptr; + } + void serializable::build(wstream& s, format fmt) { + for (auto it = data.begin(); it != data.end(); ++it) { + if (fmt == format::json) { + if (it != data.begin()) { + s << ","; + } + } + (*it).second->build((*it).first, s, fmt); + } + } + bool serializable::get(const string& name, string& value) const { + auto it = data.find(name); + if (it == data.end() || (*it).second->get_type() != data_type::STR) { + return false; + } + value = *(*it).second->str; + return true; + } + const string& serializable::get(const string& name) const { + auto it = data.find(name); + if (it == data.end() || (*it).second->get_type() != data_type::STR) { + return string::empty_string; + } + return *(*it).second->str; + } + const string* serializable::getx(const string& name) const { + auto it = data.find(name); + if (it == data.end() || (*it).second->get_type() != data_type::STR) { + return nullptr; + } + return (*it).second->str; + } + const int64_t serializable::get_int(const string& name) const { + auto it = data.find(name); + if (it == data.end() || (*it).second->get_type() != data_type::INT) { + return 0; + } + return (*it).second->i; + } + serializable& serializable::operator = (serializable&& a) noexcept { + this->data.swap(a.data); + return *this; + } + serializable& serializable::operator = (const serializable& a) { + this->data = a.data; + for (auto it = data.begin(); it != data.end(); ++it) { + (*it).second->add_ref(); + } + return *this; + } +} \ No newline at end of file diff --git a/src/test.cpp b/src/test.cpp index 2248b2b..8300fa4 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -50,6 +50,7 @@ #include "KAsyncFetchObject.h" #include "KConfigTree.h" #include "KAutoArray.h" +#include "serializable.h" #ifdef ENABLE_ATOM #include "KAtomLock.h" #endif
" << LANG_OPERATOR << "idfile