From 43e1289eed437e37005ebc2e640bb3841b2cc2c8 Mon Sep 17 00:00:00 2001 From: cxl Date: Tue, 13 Nov 2012 07:53:32 +0000 Subject: [PATCH] Core: LoadFile checks whether path is a file (because POSIX opens a dir too), Core/Rpc: StopRpcServerTrace git-svn-id: svn://ultimatepp.org/upp/trunk@5546 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppsrc/Core/Rpc/Rpc.h | 699 +++++++++++++++++++------------------ uppsrc/Core/Rpc/Server.cpp | 565 +++++++++++++++--------------- uppsrc/Core/Rpc/init | 1 - uppsrc/Core/Stream.cpp | 8 +- 4 files changed, 641 insertions(+), 632 deletions(-) diff --git a/uppsrc/Core/Rpc/Rpc.h b/uppsrc/Core/Rpc/Rpc.h index 928fa618f..ce31f9971 100644 --- a/uppsrc/Core/Rpc/Rpc.h +++ b/uppsrc/Core/Rpc/Rpc.h @@ -1,349 +1,350 @@ -#ifndef Rpc_Rpc_h -#define Rpc_Rpc_h - -#include - -NAMESPACE_UPP - -enum { - RPC_SERVER_JSON_ERROR = -32700, // Parse error - RPC_SERVER_JSON_REQUEST_ERROR = -32600, // Invalid Request - RPC_UNKNOWN_METHOD_ERROR = -32601, // Method not found - RPC_SERVER_PARAM_ERROR = -32602, // Invalid params - RPC_SERVER_PROCESSING_ERROR = -32000, // Server error - - RPC_SERVER_XML_ERROR, - - RPC_CLIENT_HTTP_ERROR = -1000000, - RPC_CLIENT_XML_ERROR, - RPC_CLIENT_JSON_ERROR, - RPC_CLIENT_RESPONSE_ERROR, -}; - -struct ValueTypeMismatch {}; - -String FormatIso8601(Time t); -Time ScanIso8601(const String& p); -Value JsonRpcData(const Value& v); - -struct RawJsonText { - String json; -}; - -void ValueCheck(bool b); - -void ValueGet(int& n, const Value& v); -void ValueGet(bool& b, const Value& v); -void ValueGet(String& s, const Value& v); -void ValueGet(double& x, const Value& v); -void ValueGet(Date& x, const Value& v); -void ValueGet(Time& x, const Value& v); -void ValueGet(Value& t, const Value& v); -void ValueGet(ValueArray& va, const Value& v); -void ValueGet(ValueMap& vm, const Value& v); - -template -void ValueGet(Array& x, const Value& v) -{ - ValueCheck(IsValueArray(v)); - ValueArray va = v; - x.SetCount(va.GetCount()); - for(int i = 0; i < va.GetCount(); i++) - ValueGet(x[i], va[i]); -} - -template -void ValueGet(Vector& x, const Value& v) -{ - ValueCheck(IsValueArray(v)); - ValueArray va = v; - x.SetCount(va.GetCount()); - for(int i = 0; i < va.GetCount(); i++) - ValueGet(x[i], va[i]); -} - -template -void ValueGet(ArrayMap& x, const Value& v) -{ - ValueCheck(IsValueMap(v)); - ValueMap vm = v; - const Index& k = vm.GetKeys(); - ValueArray va = vm.GetValues(); - x.Clear(); - for(int i = 0; i < k.GetCount(); i++) - x.Add(k[i], va[i]); -} - -template -void ValueGet(VectorMap& x, const Value& v) -{ - ValueCheck(IsValueMap(v)); - ValueMap vm = v; - const Index& k = vm.GetKeys(); - ValueArray va = vm.GetValues(); - x.Clear(); - for(int i = 0; i < k.GetCount(); i++) - x.Add(k[i], va[i]); -} - -template -void ValueGet(ArrayMap& x, const Value& v) -{ - ValueCheck(IsValueMap(v)); - ValueMap vm = v; - const Index& k = vm.GetKeys(); - ValueArray va = vm.GetValues(); - x.Clear(); - for(int i = 0; i < k.GetCount(); i++) - x.Add(atoi(AsString(k[i])), va[i]); -} - -template -void ValueGet(VectorMap& x, const Value& v) -{ - ValueCheck(IsValueMap(v)); - ValueMap vm = v; - const Index& k = vm.GetKeys(); - ValueArray va = vm.GetValues(); - x.Clear(); - for(int i = 0; i < k.GetCount(); i++) - x.Add(atoi(AsString(k[i])), va[i]); -} - -void ValuePut(Value& v, int n); -void ValuePut(Value& v, const String& s); -void ValuePut(Value& v, const char *s); -void ValuePut(Value& v, double x); -void ValuePut(Value& v, bool x); -void ValuePut(Value& v, const Date& x); -void ValuePut(Value& v, const Time& x); -void ValuePut(Value& v, const Value& t); -void ValuePut(Value& v, const ValueArray& va); -void ValuePut(Value& v, const ValueMap& vm); -void ValuePut(Value& v, const Json& json); - -template -Value AsXmlRpcValue(const T& x) -{ - Value vs; - ValuePut(vs, x); - return vs; -} - -template -void ValuePut(Value& v, const Array& x) -{ - ValueArray va; - for(int i = 0; i < x.GetCount(); i++) - va.Add(AsXmlRpcValue(x[i])); - v = va; -} - -template -void ValuePut(Value& v, const Vector& x) -{ - ValueArray va; - for(int i = 0; i < x.GetCount(); i++) - va.Add(AsXmlRpcValue(x[i])); - v = va; -} - -template -void ValuePut(Value& v, const ArrayMap& x) -{ - ValueMap vm; - for(int i = 0; i < x.GetCount(); i++) - if(!x.IsUnlinked(i)) - vm.Add(x.GetKey(i), AsXmlRpcValue(x[i])); - v = vm; -} - -template -void ValuePut(Value& v, const VectorMap& x) -{ - ValueMap vm; - for(int i = 0; i < x.GetCount(); i++) - if(!x.IsUnlinked(i)) - vm.Add(x.GetKey(i), AsXmlRpcValue(x[i])); - v = vm; -} - -template -void ValuePut(Value& v, const ArrayMap& x) -{ - ValueMap vm; - for(int i = 0; i < x.GetCount(); i++) - if(!x.IsUnlinked(i)) - vm.Add(AsString(x.GetKey(i)), AsXmlRpcValue(x[i])); - v = vm; -} - -template -void ValuePut(Value& v, const VectorMap& x) -{ - ValueMap vm; - for(int i = 0; i < x.GetCount(); i++) - if(!x.IsUnlinked(i)) - vm.Add(AsString(x.GetKey(i)), AsXmlRpcValue(x[i])); - v = vm; -} - -Value ParseXmlRpcValue(XmlParser& p); -Value ParseXmlRpcParam(XmlParser& p); -ValueArray ParseXmlRpcParams(XmlParser& p); - -struct RpcGet { - Value v; - - template - operator T() { T x; ValueGet(x, v); return x; } - - String ToString() const { return v.ToString(); } -}; - -struct RpcData { - String peeraddr; - ValueArray in; - int ii; - ValueMap in_map; - ValueArray out; - ValueMap out_map; - - Value Get() { if(ii >= in.GetCount()) throw ValueTypeMismatch(); return in[ii++]; } - - template - RpcData& operator>>(T& x) { ValueGet(x, Get()); return *this; } - - RpcGet operator++(int) { RpcGet h; h.v = Get(); return h; } - - RpcGet operator[](const char *id) { RpcGet h; h.v = in_map[id]; return h; } - - template - RpcData& operator<<(const T& x) { ASSERT(out_map.GetCount() == 0); Value v; ValuePut(v, x); out.Add(v); return *this; } - - template - void Set(int i, const T& x) { ASSERT(out_map.GetCount() == 0); Value v; ValuePut(v, x); out.Set(i, v); } - - template - void operator=(const T& x) { operator<<(x); } - - void Reset() { in.Clear(); out.Clear(); ii = 0; } - - RpcData() { ii = 0; } -}; - -String FormatXmlRpcValue(const Value& value); -String FormatXmlRpcParam(const Value& param); -String FormatXmlRpcParams(const ValueArray& params); - -String FormatXmlRpcError(int code, const char *text); - -void Register(const char *name, void (*method)(RpcData&), const char *group = NULL); - -#define RPC_METHOD(name) void name(RpcData& rpc); INITBLOCK { Register(#name, name); } void name(RpcData& rpc) -#define RPC_GMETHOD(name, group) void name(RpcData& rpc); INITBLOCK { Register(#name, name, group); } void name(RpcData& rpc) - -struct RpcError { - int code; - String text; -}; - -void SetRpcMethodFilter(String (*filter)(const String& methodname)); -String RpcExecute(const String& request, const char *group, const char *peeraddr); -bool RpcPerform(TcpSocket& http, const char *group); -bool RpcServerLoop(int port, const char *group = NULL); - -void ThrowRpcError(int code, const char *s); -void ThrowRpcError(const char *s); - -class RpcRequest : HttpRequest { - bool shorted; - RpcData data; - String method; - String error; - String faultString; - int faultCode; - bool shouldExecute; - bool json, notification; - void Init(); - -public: - RpcRequest& Method(const char *name); - - template - RpcRequest& operator<<(const T& x) { data << x; return *this; } - template - void Set(int i, const T& x) { data.Set(i, x); } - template - RpcRequest& Named(const char *id, const T& x) { data.out_map.Add(id, x); return *this; } - - RpcGet Execute(); - RpcGet Retry(); - - template - bool operator>>(T& x) { if(Execute().v.IsError()) return false; - try { data >> x; } catch(ValueTypeMismatch) { return false; } return true; } - - RpcRequest& operator()(const char *method) { Method(method); return *this; } - -#define E__Templ(I) class COMBINE(T, I) -#define E__Decl(I) const COMBINE(T, I)& COMBINE(p, I) -#define E__Param(I) *this << COMBINE(p, I) -#define E__Body(I) \ - template <__List##I(E__Templ)> \ - RpcRequest& operator()(const char *method, __List##I(E__Decl)) { \ - Method(method); \ - __List##I(E__Param); \ - return *this; \ - } - - __Expand20(E__Body) - -#undef E__Templ -#undef E__Decl -#undef E__Param -#undef E__Body - - String GetFaultString() const { return faultString; } - int GetFaultCode() const { return faultCode; } - String GetError() const { return error; } - String GetMethod() const { return method; } - void ClearError(); - - RpcRequest& Url(const char *url); - - RpcRequest& JsonRpc() { json = true; return *this; } - RpcRequest& Notification() { notification = true; return *this; } - - RpcRequest(const char *url); - RpcRequest(); -}; - -struct XmlRpcRequest : RpcRequest { - XmlRpcRequest(const char *url) : RpcRequest(url) {} - XmlRpcRequest() {} -}; - -struct JsonRpcRequest : RpcRequest { - JsonRpcRequest(const char *url) : RpcRequest(url) { JsonRpc(); } - JsonRpcRequest() { JsonRpc(); } -}; - -struct JsonRpcRequestNamed : RpcRequest { - template - JsonRpcRequestNamed& operator()(const char *id, const T& x) { Named(id, x); return *this; } - JsonRpcRequestNamed& operator()(const char *method) { Method(method); return *this; } - - JsonRpcRequestNamed(const char *url) : RpcRequest(url) { JsonRpc(); } - JsonRpcRequestNamed() { JsonRpc(); } -}; - -void LogRpcRequests(bool b = true); - -void SetRpcServerTrace(Stream& s, int level = 1); - -#include "legacy.h" - -END_UPP_NAMESPACE - -#endif +#ifndef Rpc_Rpc_h +#define Rpc_Rpc_h + +#include + +NAMESPACE_UPP + +enum { + RPC_SERVER_JSON_ERROR = -32700, // Parse error + RPC_SERVER_JSON_REQUEST_ERROR = -32600, // Invalid Request + RPC_UNKNOWN_METHOD_ERROR = -32601, // Method not found + RPC_SERVER_PARAM_ERROR = -32602, // Invalid params + RPC_SERVER_PROCESSING_ERROR = -32000, // Server error + + RPC_SERVER_XML_ERROR, + + RPC_CLIENT_HTTP_ERROR = -1000000, + RPC_CLIENT_XML_ERROR, + RPC_CLIENT_JSON_ERROR, + RPC_CLIENT_RESPONSE_ERROR, +}; + +struct ValueTypeMismatch {}; + +String FormatIso8601(Time t); +Time ScanIso8601(const String& p); +Value JsonRpcData(const Value& v); + +struct RawJsonText { + String json; +}; + +void ValueCheck(bool b); + +void ValueGet(int& n, const Value& v); +void ValueGet(bool& b, const Value& v); +void ValueGet(String& s, const Value& v); +void ValueGet(double& x, const Value& v); +void ValueGet(Date& x, const Value& v); +void ValueGet(Time& x, const Value& v); +void ValueGet(Value& t, const Value& v); +void ValueGet(ValueArray& va, const Value& v); +void ValueGet(ValueMap& vm, const Value& v); + +template +void ValueGet(Array& x, const Value& v) +{ + ValueCheck(IsValueArray(v)); + ValueArray va = v; + x.SetCount(va.GetCount()); + for(int i = 0; i < va.GetCount(); i++) + ValueGet(x[i], va[i]); +} + +template +void ValueGet(Vector& x, const Value& v) +{ + ValueCheck(IsValueArray(v)); + ValueArray va = v; + x.SetCount(va.GetCount()); + for(int i = 0; i < va.GetCount(); i++) + ValueGet(x[i], va[i]); +} + +template +void ValueGet(ArrayMap& x, const Value& v) +{ + ValueCheck(IsValueMap(v)); + ValueMap vm = v; + const Index& k = vm.GetKeys(); + ValueArray va = vm.GetValues(); + x.Clear(); + for(int i = 0; i < k.GetCount(); i++) + x.Add(k[i], va[i]); +} + +template +void ValueGet(VectorMap& x, const Value& v) +{ + ValueCheck(IsValueMap(v)); + ValueMap vm = v; + const Index& k = vm.GetKeys(); + ValueArray va = vm.GetValues(); + x.Clear(); + for(int i = 0; i < k.GetCount(); i++) + x.Add(k[i], va[i]); +} + +template +void ValueGet(ArrayMap& x, const Value& v) +{ + ValueCheck(IsValueMap(v)); + ValueMap vm = v; + const Index& k = vm.GetKeys(); + ValueArray va = vm.GetValues(); + x.Clear(); + for(int i = 0; i < k.GetCount(); i++) + x.Add(atoi(AsString(k[i])), va[i]); +} + +template +void ValueGet(VectorMap& x, const Value& v) +{ + ValueCheck(IsValueMap(v)); + ValueMap vm = v; + const Index& k = vm.GetKeys(); + ValueArray va = vm.GetValues(); + x.Clear(); + for(int i = 0; i < k.GetCount(); i++) + x.Add(atoi(AsString(k[i])), va[i]); +} + +void ValuePut(Value& v, int n); +void ValuePut(Value& v, const String& s); +void ValuePut(Value& v, const char *s); +void ValuePut(Value& v, double x); +void ValuePut(Value& v, bool x); +void ValuePut(Value& v, const Date& x); +void ValuePut(Value& v, const Time& x); +void ValuePut(Value& v, const Value& t); +void ValuePut(Value& v, const ValueArray& va); +void ValuePut(Value& v, const ValueMap& vm); +void ValuePut(Value& v, const Json& json); + +template +Value AsXmlRpcValue(const T& x) +{ + Value vs; + ValuePut(vs, x); + return vs; +} + +template +void ValuePut(Value& v, const Array& x) +{ + ValueArray va; + for(int i = 0; i < x.GetCount(); i++) + va.Add(AsXmlRpcValue(x[i])); + v = va; +} + +template +void ValuePut(Value& v, const Vector& x) +{ + ValueArray va; + for(int i = 0; i < x.GetCount(); i++) + va.Add(AsXmlRpcValue(x[i])); + v = va; +} + +template +void ValuePut(Value& v, const ArrayMap& x) +{ + ValueMap vm; + for(int i = 0; i < x.GetCount(); i++) + if(!x.IsUnlinked(i)) + vm.Add(x.GetKey(i), AsXmlRpcValue(x[i])); + v = vm; +} + +template +void ValuePut(Value& v, const VectorMap& x) +{ + ValueMap vm; + for(int i = 0; i < x.GetCount(); i++) + if(!x.IsUnlinked(i)) + vm.Add(x.GetKey(i), AsXmlRpcValue(x[i])); + v = vm; +} + +template +void ValuePut(Value& v, const ArrayMap& x) +{ + ValueMap vm; + for(int i = 0; i < x.GetCount(); i++) + if(!x.IsUnlinked(i)) + vm.Add(AsString(x.GetKey(i)), AsXmlRpcValue(x[i])); + v = vm; +} + +template +void ValuePut(Value& v, const VectorMap& x) +{ + ValueMap vm; + for(int i = 0; i < x.GetCount(); i++) + if(!x.IsUnlinked(i)) + vm.Add(AsString(x.GetKey(i)), AsXmlRpcValue(x[i])); + v = vm; +} + +Value ParseXmlRpcValue(XmlParser& p); +Value ParseXmlRpcParam(XmlParser& p); +ValueArray ParseXmlRpcParams(XmlParser& p); + +struct RpcGet { + Value v; + + template + operator T() { T x; ValueGet(x, v); return x; } + + String ToString() const { return v.ToString(); } +}; + +struct RpcData { + String peeraddr; + ValueArray in; + int ii; + ValueMap in_map; + ValueArray out; + ValueMap out_map; + + Value Get() { if(ii >= in.GetCount()) throw ValueTypeMismatch(); return in[ii++]; } + + template + RpcData& operator>>(T& x) { ValueGet(x, Get()); return *this; } + + RpcGet operator++(int) { RpcGet h; h.v = Get(); return h; } + + RpcGet operator[](const char *id) { RpcGet h; h.v = in_map[id]; return h; } + + template + RpcData& operator<<(const T& x) { ASSERT(out_map.GetCount() == 0); Value v; ValuePut(v, x); out.Add(v); return *this; } + + template + void Set(int i, const T& x) { ASSERT(out_map.GetCount() == 0); Value v; ValuePut(v, x); out.Set(i, v); } + + template + void operator=(const T& x) { operator<<(x); } + + void Reset() { in.Clear(); out.Clear(); ii = 0; } + + RpcData() { ii = 0; } +}; + +String FormatXmlRpcValue(const Value& value); +String FormatXmlRpcParam(const Value& param); +String FormatXmlRpcParams(const ValueArray& params); + +String FormatXmlRpcError(int code, const char *text); + +void Register(const char *name, void (*method)(RpcData&), const char *group = NULL); + +#define RPC_METHOD(name) void name(RpcData& rpc); INITBLOCK { Register(#name, name); } void name(RpcData& rpc) +#define RPC_GMETHOD(name, group) void name(RpcData& rpc); INITBLOCK { Register(#name, name, group); } void name(RpcData& rpc) + +struct RpcError { + int code; + String text; +}; + +void SetRpcMethodFilter(String (*filter)(const String& methodname)); +String RpcExecute(const String& request, const char *group, const char *peeraddr); +bool RpcPerform(TcpSocket& http, const char *group); +bool RpcServerLoop(int port, const char *group = NULL); + +void ThrowRpcError(int code, const char *s); +void ThrowRpcError(const char *s); + +class RpcRequest : HttpRequest { + bool shorted; + RpcData data; + String method; + String error; + String faultString; + int faultCode; + bool shouldExecute; + bool json, notification; + void Init(); + +public: + RpcRequest& Method(const char *name); + + template + RpcRequest& operator<<(const T& x) { data << x; return *this; } + template + void Set(int i, const T& x) { data.Set(i, x); } + template + RpcRequest& Named(const char *id, const T& x) { data.out_map.Add(id, x); return *this; } + + RpcGet Execute(); + RpcGet Retry(); + + template + bool operator>>(T& x) { if(Execute().v.IsError()) return false; + try { data >> x; } catch(ValueTypeMismatch) { return false; } return true; } + + RpcRequest& operator()(const char *method) { Method(method); return *this; } + +#define E__Templ(I) class COMBINE(T, I) +#define E__Decl(I) const COMBINE(T, I)& COMBINE(p, I) +#define E__Param(I) *this << COMBINE(p, I) +#define E__Body(I) \ + template <__List##I(E__Templ)> \ + RpcRequest& operator()(const char *method, __List##I(E__Decl)) { \ + Method(method); \ + __List##I(E__Param); \ + return *this; \ + } + + __Expand20(E__Body) + +#undef E__Templ +#undef E__Decl +#undef E__Param +#undef E__Body + + String GetFaultString() const { return faultString; } + int GetFaultCode() const { return faultCode; } + String GetError() const { return error; } + String GetMethod() const { return method; } + void ClearError(); + + RpcRequest& Url(const char *url); + + RpcRequest& JsonRpc() { json = true; return *this; } + RpcRequest& Notification() { notification = true; return *this; } + + RpcRequest(const char *url); + RpcRequest(); +}; + +struct XmlRpcRequest : RpcRequest { + XmlRpcRequest(const char *url) : RpcRequest(url) {} + XmlRpcRequest() {} +}; + +struct JsonRpcRequest : RpcRequest { + JsonRpcRequest(const char *url) : RpcRequest(url) { JsonRpc(); } + JsonRpcRequest() { JsonRpc(); } +}; + +struct JsonRpcRequestNamed : RpcRequest { + template + JsonRpcRequestNamed& operator()(const char *id, const T& x) { Named(id, x); return *this; } + JsonRpcRequestNamed& operator()(const char *method) { Method(method); return *this; } + + JsonRpcRequestNamed(const char *url) : RpcRequest(url) { JsonRpc(); } + JsonRpcRequestNamed() { JsonRpc(); } +}; + +void LogRpcRequests(bool b = true); + +void SetRpcServerTrace(Stream& s, int level = 1); +void StopRpcServerTrace(); + +#include "legacy.h" + +END_UPP_NAMESPACE + +#endif diff --git a/uppsrc/Core/Rpc/Server.cpp b/uppsrc/Core/Rpc/Server.cpp index 061fb899f..135207af7 100644 --- a/uppsrc/Core/Rpc/Server.cpp +++ b/uppsrc/Core/Rpc/Server.cpp @@ -1,280 +1,285 @@ -#include "Rpc.h" - -#define LLOG(x) // DLOG(x) - -NAMESPACE_UPP - -typedef void (*RpcFnPtr)(RpcData&); - -static StaticMutex RpcMapMutex; - -VectorMap& RpcMap(const char *group) -{ - static VectorMap > mm; - return mm.GetAdd(group); -} - -void Register(const char *name, void (*method)(RpcData&), const char *group) -{ - Mutex::Lock __(RpcMapMutex); - RpcMap(group).Add(name, method); -} - -RpcFnPtr RpcMapGet(const char *group, const char *name) -{ - Mutex::Lock __(RpcMapMutex); - return RpcMap(group).Get(name, NULL); -} - -String (*sRpcMethodFilter)(const String& methodname); - -void SetRpcMethodFilter(String (*filter)(const String& methodname)) -{ - sRpcMethodFilter = filter; -} - -void ThrowRpcError(int code, const char *s) -{ - RpcError e; - e.code = code; - e.text = s; - throw e; -} - -void ThrowRpcError(const char *s) -{ - ThrowRpcError(RPC_SERVER_PROCESSING_ERROR, s); -} - -static Stream *rpc_trace; -static int rpc_trace_level; - -void SetRpcServerTrace(Stream& s, int level) -{ - rpc_trace = &s; - rpc_trace_level = level; -} - -bool CallRpcMethod(RpcData& data, const char *group, String methodname) -{ - LLOG("method name: " << methodname); - if(rpc_trace && rpc_trace_level == 0) - *rpc_trace << "RpcRequest method:\n" << methodname << '\n'; - if(sRpcMethodFilter) - methodname = (*sRpcMethodFilter)(methodname); - void (*fn)(RpcData&) = RpcMapGet(group, methodname); - if(!fn) - return false; - (*fn)(data); - return true; -} - -String DoXmlRpc(const String& request, const char *group, const char *peeraddr) -{ - XmlParser p(request); - RpcData data; - try { - String methodname; - String r = XmlHeader(); - r << "\r\n"; - p.ReadPI(); - p.PassTag("methodCall"); - p.PassTag("methodName"); - methodname = p.ReadText(); - p.PassEnd(); - data.peeraddr = peeraddr; - data.in = ParseXmlRpcParams(p); - if(CallRpcMethod(data, group, methodname)) { - if(IsValueArray(data.out)) { - ValueArray va = data.out; - if(va.GetCount() && IsError(va[0])) { - LLOG("ProcessingError"); - String e = GetErrorText(data.out[0]); - if(rpc_trace) - *rpc_trace << "Processing error: " << e << '\n'; - return FormatXmlRpcError(RPC_SERVER_PROCESSING_ERROR, "Processing error: " + e); - } - r << FormatXmlRpcParams(data.out); - } - r << "\r\n\r\n"; - } - else - return FormatXmlRpcError(RPC_UNKNOWN_METHOD_ERROR, "\'" + methodname + "\' method is unknown"); - p.PassEnd(); - return r; - } - catch(RpcError e) { - LLOG("Processing error: " << e.text); - if(rpc_trace) - *rpc_trace << "Processing error: " << e.text << '\n'; - return FormatXmlRpcError(e.code, e.text); - } - catch(XmlError e) { - LLOG("XmlError " << e << ": " << p.GetPtr()); - if(rpc_trace) - *rpc_trace << "XmlError: " << e << '\n'; - return FormatXmlRpcError(RPC_SERVER_XML_ERROR, "XML Error: " + e); - } - catch(ValueTypeMismatch) { - LLOG("ValueTypeMismatch at parameter " << data.ii); - if(rpc_trace) - *rpc_trace << "ValueTypeMismatch at parameter " << data.ii << '\n'; - return FormatXmlRpcError(RPC_SERVER_PARAM_ERROR, "Parameter mismatch at parameter " + AsString(data.ii)); - } - return Null; -} - -String JsonRpcError(int code, const char *text, const Value& id) -{ - Json m; - m("jsonrpc", "2.0"); - ValueMap err; - err.Add("code", code); - err.Add("message", text); - m("error", err); - m("id", id); - return m; -} - -String ProcessJsonRpc(const Value& v, const char *group, const char *peeraddr) -{ - LLOG("Parsed JSON request: " << v); - Value id = v["id"]; - Value methodname = v["method"]; - Value param = v["params"]; - RpcData data; - data.peeraddr = peeraddr; - if(param.Is()) - data.in_map = param; - else - data.in = param; - try { - if(CallRpcMethod(data, group, methodname)) { - if(IsValueArray(data.out)) { - ValueArray va = data.out; - Value result = Null; - if(va.GetCount()) { - if(IsError(va[0])) { - LLOG("ProcessingError"); - String e = GetErrorText(data.out[0]); - if(rpc_trace) - *rpc_trace << "Processing error: " << e << '\n'; - return JsonRpcError(RPC_SERVER_PROCESSING_ERROR, "Processing error: " + e, id); - } - result = JsonRpcData(va[0]); - } - Json json; - json("jsonrpc", "2.0"); - if(result.Is()) - json.CatRaw("result", result.To().json); - else - json("result", result); - json("id", id); - return json; - } - } - return JsonRpcError(RPC_UNKNOWN_METHOD_ERROR, "Method not found", id); - } - catch(RpcError e) { - LLOG("Processing error: " << e.text); - if(rpc_trace) - *rpc_trace << "Processing error: " << e.text << '\n'; - return JsonRpcError(e.code, e.text, id); - } - catch(ValueTypeMismatch) { - LLOG("ValueTypeMismatch at parameter " << data.ii); - if(rpc_trace) - *rpc_trace << "ValueTypeMismatch at parameter " << data.ii << '\n'; - return JsonRpcError(RPC_SERVER_PARAM_ERROR, "Invalid params", id); - } -} - -String DoJsonRpc(const String& request, const char *group, const char *peeraddr) -{ - try { - Value v = ParseJSON(request); - if(v.Is()) - return ProcessJsonRpc(v, group, peeraddr); - if(v.Is()) { - JsonArray a; - for(int i = 0; i < v.GetCount(); i++) - a.CatRaw(ProcessJsonRpc(v[i], group, peeraddr)); - return v.GetCount() ? ~a : String(); - } - } - catch(CParser::Error e) {} - return AsJSON(JsonRpcError(RPC_SERVER_JSON_ERROR, "Parse error", Null)); -} - -String RpcExecute(const String& request, const char *group, const char *peeraddr, bool& json) -{ - if(rpc_trace && rpc_trace_level == 1) - *rpc_trace << "RPC Request:\n" << request << '\n'; - CParser p(request); - String r; - if(p.Char('{') || p.Char('[')) { - json = true; - r = DoJsonRpc(request, group, peeraddr); - } - else { - json = false; - r = DoXmlRpc(request, group, peeraddr); - } - if(rpc_trace) - if(rpc_trace_level == 0) - *rpc_trace << "Rpc finished OK\n"; - else - *rpc_trace << "Server response:\n" << r << '\n'; - return r; -} - -String RpcExecute(const String& request, const char *group, const char *peeraddr) -{ - bool dummy; - return RpcExecute(request, group, peeraddr, dummy); -} - -bool RpcPerform(TcpSocket& http, const char *group) -{ - LLOG("=== Accepted connection ==================================================="); - HttpHeader hdr; - if(hdr.Read(http) && hdr.GetMethod() == "POST") { - int len = atoi(hdr["content-length"]); - if(len > 0 && len < 1024 * 1024 * 1024) { - bool json; - String r = RpcExecute(http.GetAll(len), group, http.GetPeerAddr(), json); - LLOG("--------- Server response:\n" << r << "============="); - String response; - String ts = WwwFormat(GetUtcTime()); - response << - "HTTP/1.0 200 OK\r\n" - "Date: " << ts << "\r\n" - "Server: U++ RPC server\r\n" - "Content-Length: " << r.GetCount() << "\r\n" - "Connection: close\r\n" - "Content-Type: text/" << (json ? "json" : "xml") << "\r\n\r\n" - << r; - LLOG(response); - if(r.GetCount()) - http.Put(response); - return true; - } - } - http.Put("HTTP/1.0 400 Bad request\r\n" - "Server: U++\r\n\r\n"); - return false; -} - -bool RpcServerLoop(int port, const char *group) -{ - TcpSocket rpc; - if(!rpc.Listen(port, 5)) - return false; - for(;;) { - TcpSocket http; - if(http.Accept(rpc)) - RpcPerform(http, group); - } -} - -END_UPP_NAMESPACE +#include "Rpc.h" + +#define LLOG(x) // DLOG(x) + +NAMESPACE_UPP + +typedef void (*RpcFnPtr)(RpcData&); + +static StaticMutex RpcMapMutex; + +VectorMap& RpcMap(const char *group) +{ + static VectorMap > mm; + return mm.GetAdd(group); +} + +void Register(const char *name, void (*method)(RpcData&), const char *group) +{ + Mutex::Lock __(RpcMapMutex); + RpcMap(group).Add(name, method); +} + +RpcFnPtr RpcMapGet(const char *group, const char *name) +{ + Mutex::Lock __(RpcMapMutex); + return RpcMap(group).Get(name, NULL); +} + +String (*sRpcMethodFilter)(const String& methodname); + +void SetRpcMethodFilter(String (*filter)(const String& methodname)) +{ + sRpcMethodFilter = filter; +} + +void ThrowRpcError(int code, const char *s) +{ + RpcError e; + e.code = code; + e.text = s; + throw e; +} + +void ThrowRpcError(const char *s) +{ + ThrowRpcError(RPC_SERVER_PROCESSING_ERROR, s); +} + +static Stream *rpc_trace; +static int rpc_trace_level; + +void SetRpcServerTrace(Stream& s, int level) +{ + rpc_trace = &s; + rpc_trace_level = level; +} + +void StopRpcServerTrace() +{ + rpc_trace = NULL; +} + +bool CallRpcMethod(RpcData& data, const char *group, String methodname) +{ + LLOG("method name: " << methodname); + if(rpc_trace && rpc_trace_level == 0) + *rpc_trace << "RpcRequest method:\n" << methodname << '\n'; + if(sRpcMethodFilter) + methodname = (*sRpcMethodFilter)(methodname); + void (*fn)(RpcData&) = RpcMapGet(group, methodname); + if(!fn) + return false; + (*fn)(data); + return true; +} + +String DoXmlRpc(const String& request, const char *group, const char *peeraddr) +{ + XmlParser p(request); + RpcData data; + try { + String methodname; + String r = XmlHeader(); + r << "\r\n"; + p.ReadPI(); + p.PassTag("methodCall"); + p.PassTag("methodName"); + methodname = p.ReadText(); + p.PassEnd(); + data.peeraddr = peeraddr; + data.in = ParseXmlRpcParams(p); + if(CallRpcMethod(data, group, methodname)) { + if(IsValueArray(data.out)) { + ValueArray va = data.out; + if(va.GetCount() && IsError(va[0])) { + LLOG("ProcessingError"); + String e = GetErrorText(data.out[0]); + if(rpc_trace) + *rpc_trace << "Processing error: " << e << '\n'; + return FormatXmlRpcError(RPC_SERVER_PROCESSING_ERROR, "Processing error: " + e); + } + r << FormatXmlRpcParams(data.out); + } + r << "\r\n\r\n"; + } + else + return FormatXmlRpcError(RPC_UNKNOWN_METHOD_ERROR, "\'" + methodname + "\' method is unknown"); + p.PassEnd(); + return r; + } + catch(RpcError e) { + LLOG("Processing error: " << e.text); + if(rpc_trace) + *rpc_trace << "Processing error: " << e.text << '\n'; + return FormatXmlRpcError(e.code, e.text); + } + catch(XmlError e) { + LLOG("XmlError " << e << ": " << p.GetPtr()); + if(rpc_trace) + *rpc_trace << "XmlError: " << e << '\n'; + return FormatXmlRpcError(RPC_SERVER_XML_ERROR, "XML Error: " + e); + } + catch(ValueTypeMismatch) { + LLOG("ValueTypeMismatch at parameter " << data.ii); + if(rpc_trace) + *rpc_trace << "ValueTypeMismatch at parameter " << data.ii << '\n'; + return FormatXmlRpcError(RPC_SERVER_PARAM_ERROR, "Parameter mismatch at parameter " + AsString(data.ii)); + } + return Null; +} + +String JsonRpcError(int code, const char *text, const Value& id) +{ + Json m; + m("jsonrpc", "2.0"); + ValueMap err; + err.Add("code", code); + err.Add("message", text); + m("error", err); + m("id", id); + return m; +} + +String ProcessJsonRpc(const Value& v, const char *group, const char *peeraddr) +{ + LLOG("Parsed JSON request: " << v); + Value id = v["id"]; + Value methodname = v["method"]; + Value param = v["params"]; + RpcData data; + data.peeraddr = peeraddr; + if(param.Is()) + data.in_map = param; + else + data.in = param; + try { + if(CallRpcMethod(data, group, methodname)) { + if(IsValueArray(data.out)) { + ValueArray va = data.out; + Value result = Null; + if(va.GetCount()) { + if(IsError(va[0])) { + LLOG("ProcessingError"); + String e = GetErrorText(data.out[0]); + if(rpc_trace) + *rpc_trace << "Processing error: " << e << '\n'; + return JsonRpcError(RPC_SERVER_PROCESSING_ERROR, "Processing error: " + e, id); + } + result = JsonRpcData(va[0]); + } + Json json; + json("jsonrpc", "2.0"); + if(result.Is()) + json.CatRaw("result", result.To().json); + else + json("result", result); + json("id", id); + return json; + } + } + return JsonRpcError(RPC_UNKNOWN_METHOD_ERROR, "Method not found", id); + } + catch(RpcError e) { + LLOG("Processing error: " << e.text); + if(rpc_trace) + *rpc_trace << "Processing error: " << e.text << '\n'; + return JsonRpcError(e.code, e.text, id); + } + catch(ValueTypeMismatch) { + LLOG("ValueTypeMismatch at parameter " << data.ii); + if(rpc_trace) + *rpc_trace << "ValueTypeMismatch at parameter " << data.ii << '\n'; + return JsonRpcError(RPC_SERVER_PARAM_ERROR, "Invalid params", id); + } +} + +String DoJsonRpc(const String& request, const char *group, const char *peeraddr) +{ + try { + Value v = ParseJSON(request); + if(v.Is()) + return ProcessJsonRpc(v, group, peeraddr); + if(v.Is()) { + JsonArray a; + for(int i = 0; i < v.GetCount(); i++) + a.CatRaw(ProcessJsonRpc(v[i], group, peeraddr)); + return v.GetCount() ? ~a : String(); + } + } + catch(CParser::Error e) {} + return AsJSON(JsonRpcError(RPC_SERVER_JSON_ERROR, "Parse error", Null)); +} + +String RpcExecute(const String& request, const char *group, const char *peeraddr, bool& json) +{ + if(rpc_trace && rpc_trace_level == 1) + *rpc_trace << "RPC Request:\n" << request << '\n'; + CParser p(request); + String r; + if(p.Char('{') || p.Char('[')) { + json = true; + r = DoJsonRpc(request, group, peeraddr); + } + else { + json = false; + r = DoXmlRpc(request, group, peeraddr); + } + if(rpc_trace) + if(rpc_trace_level == 0) + *rpc_trace << "Rpc finished OK\n"; + else + *rpc_trace << "Server response:\n" << r << '\n'; + return r; +} + +String RpcExecute(const String& request, const char *group, const char *peeraddr) +{ + bool dummy; + return RpcExecute(request, group, peeraddr, dummy); +} + +bool RpcPerform(TcpSocket& http, const char *group) +{ + LLOG("=== Accepted connection ==================================================="); + HttpHeader hdr; + if(hdr.Read(http) && hdr.GetMethod() == "POST") { + int len = atoi(hdr["content-length"]); + if(len > 0 && len < 1024 * 1024 * 1024) { + bool json; + String r = RpcExecute(http.GetAll(len), group, http.GetPeerAddr(), json); + LLOG("--------- Server response:\n" << r << "============="); + String response; + String ts = WwwFormat(GetUtcTime()); + response << + "HTTP/1.0 200 OK\r\n" + "Date: " << ts << "\r\n" + "Server: U++ RPC server\r\n" + "Content-Length: " << r.GetCount() << "\r\n" + "Connection: close\r\n" + "Content-Type: text/" << (json ? "json" : "xml") << "\r\n\r\n" + << r; + LLOG(response); + if(r.GetCount()) + http.Put(response); + return true; + } + } + http.Put("HTTP/1.0 400 Bad request\r\n" + "Server: U++\r\n\r\n"); + return false; +} + +bool RpcServerLoop(int port, const char *group) +{ + TcpSocket rpc; + if(!rpc.Listen(port, 5)) + return false; + for(;;) { + TcpSocket http; + if(http.Accept(rpc)) + RpcPerform(http, group); + } +} + +END_UPP_NAMESPACE diff --git a/uppsrc/Core/Rpc/init b/uppsrc/Core/Rpc/init index ef62a6844..e96437af8 100644 --- a/uppsrc/Core/Rpc/init +++ b/uppsrc/Core/Rpc/init @@ -1,4 +1,3 @@ #ifndef _Core_Rpc_icpp_init_stub #define _Core_Rpc_icpp_init_stub -#include "Web/init" #endif diff --git a/uppsrc/Core/Stream.cpp b/uppsrc/Core/Stream.cpp index d12ee0e7b..986e3cce6 100644 --- a/uppsrc/Core/Stream.cpp +++ b/uppsrc/Core/Stream.cpp @@ -1496,8 +1496,12 @@ String LoadStream(Stream& in) { } String LoadFile(const char *filename) { - FileIn in(filename); - return LoadStream(in); + FindFile ff(filename); + if(ff && ff.IsFile()) { + FileIn in(filename); + return LoadStream(in); + } + return String::GetVoid(); } bool SaveStream(Stream& out, const String& data) {