mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-07-11 22:03:01 -06:00
Core/XmlRpc (xmlrpc over TcpSocket)
git-svn-id: svn://ultimatepp.org/upp/trunk@4851 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
074720c311
commit
fa0252d883
10 changed files with 671 additions and 282 deletions
122
uppsrc/Core/XmlRpc/Client.cpp
Normal file
122
uppsrc/Core/XmlRpc/Client.cpp
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
#include "XmlRpc.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
#define LLOG(x) // LOG(x)
|
||||
|
||||
static bool sLogRpcCalls;
|
||||
|
||||
void LogXmlRpcRequests(bool b)
|
||||
{
|
||||
sLogRpcCalls = b;
|
||||
}
|
||||
|
||||
XmlRpcRequest& XmlRpcRequest::Url(const char *url)
|
||||
{
|
||||
shorted = true;
|
||||
if(url && *url) {
|
||||
HttpRequest::Url(url);
|
||||
shorted = false;
|
||||
}
|
||||
shouldExecute = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
XmlRpcRequest& XmlRpcRequest::Method(const char *name)
|
||||
{
|
||||
shouldExecute = true;
|
||||
method = name;
|
||||
data.Reset();
|
||||
error.Clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
XmlRpcRequest::XmlRpcRequest(const char *url)
|
||||
{
|
||||
Url(url);
|
||||
ContentType("text/xml");
|
||||
RequestTimeout(30000);
|
||||
}
|
||||
|
||||
XmlRpcRequest::XmlRpcRequest()
|
||||
{
|
||||
Url(NULL);
|
||||
ContentType("text/xml");
|
||||
RequestTimeout(30000);
|
||||
}
|
||||
|
||||
String XmlRpcExecute(const String& request, const char *group, const char *peeraddr);
|
||||
|
||||
Value XmlRpcRequest::Retry()
|
||||
{
|
||||
ClearError();
|
||||
shouldExecute = true;
|
||||
return Execute();
|
||||
}
|
||||
|
||||
Value XmlRpcRequest::Execute()
|
||||
{
|
||||
if(!shouldExecute)
|
||||
return Value();
|
||||
shouldExecute = false;
|
||||
String request = XmlHeader();
|
||||
request << XmlTag("methodCall")(XmlTag("methodName")(method) + FormatXmlRpcParams(data.out));
|
||||
if(sLogRpcCalls)
|
||||
RLOG("XmlRpc call request:\n" << request);
|
||||
String response;
|
||||
New();
|
||||
if(shorted)
|
||||
response = XmlRpcExecute(request, "", "127.0.0.1");
|
||||
else
|
||||
response = Post(request).Execute();
|
||||
if(sLogRpcCalls)
|
||||
RLOG("XmlRpc call response:\n" << response);
|
||||
if(IsNull(response)) {
|
||||
faultCode = XMLRPC_CLIENT_HTTP_ERROR;
|
||||
faultString = GetErrorDesc();
|
||||
error = "Http request failed: " + faultString;
|
||||
LLOG(error);
|
||||
return ErrorValue(error);
|
||||
}
|
||||
XmlParser p(response);
|
||||
try {
|
||||
p.ReadPI();
|
||||
p.PassTag("methodResponse");
|
||||
if(p.Tag("fault")) {
|
||||
Value m = ParseXmlRpcValue(p);
|
||||
if(IsValueMap(m)) {
|
||||
ValueMap mm = m;
|
||||
faultString = mm["faultString"];
|
||||
faultCode = mm["faultCode"];
|
||||
error.Clear();
|
||||
error << "Failed '" << faultString << "' (" << faultCode << ')';
|
||||
LLOG(s);
|
||||
return ErrorValue(error);
|
||||
}
|
||||
}
|
||||
else {
|
||||
data.in = ParseXmlRpcParams(p);
|
||||
data.ii = 0;
|
||||
p.PassEnd();
|
||||
}
|
||||
}
|
||||
catch(XmlError e) {
|
||||
String s;
|
||||
faultString = e;
|
||||
faultCode = XMLRPC_CLIENT_XML_ERROR;
|
||||
error.Clear();
|
||||
error << "XML Error: " << faultString;
|
||||
LLOG(error << ": " << p.GetPtr());
|
||||
return ErrorValue(error);
|
||||
}
|
||||
return data.in.GetCount() ? data.in[0] : Null;
|
||||
}
|
||||
|
||||
void XmlRpcRequest::ClearError()
|
||||
{
|
||||
faultCode = 0;
|
||||
faultString.Clear();
|
||||
error.Clear();
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
185
uppsrc/Core/XmlRpc/Server.cpp
Normal file
185
uppsrc/Core/XmlRpc/Server.cpp
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
#include "XmlRpc.h"
|
||||
#include "XmlRpc.h"
|
||||
|
||||
#define LLOG(x) // DLOG(x)
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
typedef void (*XmlRpcFnPtr)(XmlRpcData&);
|
||||
|
||||
static StaticMutex XmlRpcMapMutex;
|
||||
|
||||
VectorMap<String, XmlRpcFnPtr>& XmlRpcMap(const char *group)
|
||||
{
|
||||
static VectorMap<String, VectorMap< String, void (*)(XmlRpcData&) > > mm;
|
||||
return mm.GetAdd(group);
|
||||
}
|
||||
|
||||
void Register(const char *name, void (*method)(XmlRpcData&), const char *group)
|
||||
{
|
||||
Mutex::Lock __(XmlRpcMapMutex);
|
||||
XmlRpcMap(group).Add(name, method);
|
||||
}
|
||||
|
||||
XmlRpcFnPtr XmlRpcMapGet(const char *group, const char *name)
|
||||
{
|
||||
Mutex::Lock __(XmlRpcMapMutex);
|
||||
return XmlRpcMap(group).Get(name, NULL);
|
||||
}
|
||||
|
||||
String (*sXmlRpcMethodFilter)(const String& methodname);
|
||||
|
||||
void SetXmlRpcMethodFilter(String (*filter)(const String& methodname))
|
||||
{
|
||||
sXmlRpcMethodFilter = filter;
|
||||
}
|
||||
|
||||
void ThrowXmlRpcError(int code, const char *s)
|
||||
{
|
||||
XmlRpcError e;
|
||||
e.code = code;
|
||||
e.text = s;
|
||||
throw e;
|
||||
}
|
||||
|
||||
void ThrowXmlRpcError(const char *s)
|
||||
{
|
||||
ThrowXmlRpcError(-1, s);
|
||||
}
|
||||
|
||||
static Stream *xmlrpc_trace;
|
||||
static int xmlrpc_trace_level;
|
||||
|
||||
void SetXmlRpcServerTrace(Stream& s, int level)
|
||||
{
|
||||
xmlrpc_trace = &s;
|
||||
xmlrpc_trace_level = level;
|
||||
}
|
||||
|
||||
String XmlRpcExecute(const String& request, const char *group, const char *peeraddr)
|
||||
{
|
||||
if(xmlrpc_trace && xmlrpc_trace_level == 1)
|
||||
*xmlrpc_trace << "XmlRpcRequest:\n" << request << '\n';
|
||||
XmlParser p(request);
|
||||
XmlRpcData data;
|
||||
String methodname;
|
||||
try {
|
||||
String r = XmlHeader();
|
||||
r << "<methodResponse>\r\n";
|
||||
p.ReadPI();
|
||||
p.PassTag("methodCall");
|
||||
p.PassTag("methodName");
|
||||
methodname = p.ReadText();
|
||||
LLOG("method name: " << methodname);
|
||||
if(xmlrpc_trace && xmlrpc_trace_level == 0)
|
||||
*xmlrpc_trace << "XmlRpcRequest method:\n" << methodname << '\n';
|
||||
p.PassEnd();
|
||||
data.peeraddr = peeraddr;
|
||||
data.in = ParseXmlRpcParams(p);
|
||||
XmlRpcMapMutex.Enter();
|
||||
if(sXmlRpcMethodFilter)
|
||||
methodname = (*sXmlRpcMethodFilter)(methodname);
|
||||
void (*fn)(XmlRpcData&) = XmlRpcMapGet(group, methodname);
|
||||
if(fn) {
|
||||
(*fn)(data);
|
||||
if(IsValueArray(data.out)) {
|
||||
ValueArray va = data.out;
|
||||
if(va.GetCount() && IsError(va[0])) {
|
||||
LLOG("ProcessingError");
|
||||
return FormatXmlRpcError(XMLRPC_SERVER_PROCESSING_ERROR, "Processing error: " + GetErrorText(data.out[0]));
|
||||
}
|
||||
r << FormatXmlRpcParams(data.out);
|
||||
}
|
||||
r << "\r\n</methodResponse>\r\n";
|
||||
}
|
||||
else {
|
||||
XmlRpcMapMutex.Leave();
|
||||
return FormatXmlRpcError(XMLRPC_UNKNOWN_METHOD_ERROR, "\'" + methodname + "\' method is unknown");
|
||||
}
|
||||
p.PassEnd();
|
||||
if(xmlrpc_trace)
|
||||
if(xmlrpc_trace_level == 0)
|
||||
*xmlrpc_trace << "XmlRpc finished OK\n";
|
||||
else
|
||||
*xmlrpc_trace << "Server response:\n" << r << '\n';
|
||||
return r;
|
||||
}
|
||||
catch(XmlRpcError e) {
|
||||
LLOG("Client error: " << e.text);
|
||||
if(xmlrpc_trace)
|
||||
*xmlrpc_trace << "Client error: " << e.text << '\n';
|
||||
return FormatXmlRpcError(e.code, e.text);
|
||||
}
|
||||
catch(XmlError e) {
|
||||
LLOG("XmlError " << e << ": " << p.GetPtr());
|
||||
if(xmlrpc_trace)
|
||||
*xmlrpc_trace << "XmlError: " << e << '\n';
|
||||
return FormatXmlRpcError(XMLRPC_SERVER_XML_ERROR, "XML Error: " + e);
|
||||
}
|
||||
catch(ValueTypeMismatch) {
|
||||
LLOG("ValueTypeMismatch at parameter " << data.ii);
|
||||
if(xmlrpc_trace)
|
||||
*xmlrpc_trace << "ValueTypeMismatch at parameter " << data.ii << '\n';
|
||||
return FormatXmlRpcError(XMLRPC_SERVER_PARAM_ERROR, "Parameter mismatch at parameter " + AsString(data.ii));
|
||||
}
|
||||
return Null;
|
||||
}
|
||||
|
||||
|
||||
bool XmlRpcPerform(TcpSocket& http, const char *group)
|
||||
{
|
||||
LLOG("=== Accepted connection ===================================================");
|
||||
String request = ToUpper(http.GetLine());
|
||||
LLOG(request);
|
||||
if(http.IsError() || request.GetCount() == 0)
|
||||
return false;
|
||||
if(request.Find("POST") >= 0 || request.Find("HTTP") >= 0) {
|
||||
VectorMap<String, String> hdr;
|
||||
for(;;) {
|
||||
String s = http.GetLine();
|
||||
if(s.IsEmpty()) break;
|
||||
LLOG(s);
|
||||
int q = s.Find(':');
|
||||
if(q >= 0)
|
||||
hdr.GetAdd(s.Mid(0, q)) = TrimLeft(s.Mid(q + 1));
|
||||
}
|
||||
if(!http.IsError()) {
|
||||
int len = atoi(hdr.Get("Content-Length", ""));
|
||||
String r;
|
||||
if(len > 0 && len < 1024 * 1024 * 1024) {
|
||||
r = XmlRpcExecute(http.GetAll(len), group, http.GetPeerAddr());
|
||||
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++ XMLRPC server\r\n"
|
||||
"Content-Length: " << r.GetCount() << "\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Content-Type: text/xml\r\n\r\n"
|
||||
<< r;
|
||||
LLOG(response);
|
||||
http.Put(response);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
http.Put("HTTP/1.0 400 Bad request\r\n"
|
||||
"Server: U++\r\n\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool XmlRpcServerLoop(int port, const char *group)
|
||||
{
|
||||
TcpSocket rpc;
|
||||
if(!rpc.Listen(port, 5))
|
||||
return false;
|
||||
for(;;) {
|
||||
TcpSocket http;
|
||||
if(rpc.Accept(http))
|
||||
XmlRpcPerform(http, group);
|
||||
}
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
#include "XmlRpc.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
void ValueCheck(bool b)
|
||||
{
|
||||
if(!b)
|
||||
|
|
@ -108,3 +110,5 @@ void ValuePut(Value& v, const ValueMap& vm)
|
|||
{
|
||||
v = vm;
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
#include "XmlRpc.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
Value ParseXmlRpcValue(XmlParser& p)
|
||||
{
|
||||
Value r;
|
||||
|
|
@ -182,3 +184,5 @@ String FormatXmlRpcError(int code, const char *text)
|
|||
<< "</fault></methodResponse>\r\n";
|
||||
return r;
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
336
uppsrc/Core/XmlRpc/XmlRpc.h
Normal file
336
uppsrc/Core/XmlRpc/XmlRpc.h
Normal file
|
|
@ -0,0 +1,336 @@
|
|||
#ifndef _XmlRpc_XmlRpc_h
|
||||
#define _XmlRpc_XmlRpc_h
|
||||
|
||||
#include <Web/Web.h>
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
enum {
|
||||
XMLRPC_CLIENT_HTTP_ERROR = -1000000,
|
||||
XMLRPC_CLIENT_XML_ERROR,
|
||||
XMLRPC_CLIENT_RETTYPE_ERROR,
|
||||
XMLRPC_SERVER_PARAM_ERROR,
|
||||
XMLRPC_SERVER_XML_ERROR,
|
||||
XMLRPC_SERVER_PROCESSING_ERROR,
|
||||
XMLRPC_UNKNOWN_METHOD_ERROR,
|
||||
};
|
||||
|
||||
struct ValueTypeMismatch {};
|
||||
|
||||
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 <class T>
|
||||
void ValueGet(Array<T>& 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 <class T>
|
||||
void ValueGet(Vector<T>& 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 <class T>
|
||||
void ValueGet(ArrayMap<String, T>& x, const Value& v)
|
||||
{
|
||||
ValueCheck(IsValueMap(v));
|
||||
ValueMap vm = v;
|
||||
const Index<Value>& k = vm.GetKeys();
|
||||
ValueArray va = vm.GetValues();
|
||||
x.Clear();
|
||||
for(int i = 0; i < k.GetCount(); i++)
|
||||
x.Add(k[i], va[i]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValueGet(VectorMap<String, T>& x, const Value& v)
|
||||
{
|
||||
ValueCheck(IsValueMap(v));
|
||||
ValueMap vm = v;
|
||||
const Index<Value>& k = vm.GetKeys();
|
||||
ValueArray va = vm.GetValues();
|
||||
x.Clear();
|
||||
for(int i = 0; i < k.GetCount(); i++)
|
||||
x.Add(k[i], va[i]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValueGet(ArrayMap<int, T>& x, const Value& v)
|
||||
{
|
||||
ValueCheck(IsValueMap(v));
|
||||
ValueMap vm = v;
|
||||
const Index<Value>& 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 <class T>
|
||||
void ValueGet(VectorMap<int, T>& x, const Value& v)
|
||||
{
|
||||
ValueCheck(IsValueMap(v));
|
||||
ValueMap vm = v;
|
||||
const Index<Value>& 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);
|
||||
|
||||
template <class T>
|
||||
Value AsXmlRpcValue(const T& x)
|
||||
{
|
||||
Value vs;
|
||||
ValuePut(vs, x);
|
||||
return vs;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValuePut(Value& v, const Array<T>& x)
|
||||
{
|
||||
ValueArray va;
|
||||
for(int i = 0; i < x.GetCount(); i++)
|
||||
va.Add(AsXmlRpcValue(x[i]));
|
||||
v = va;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValuePut(Value& v, const Vector<T>& x)
|
||||
{
|
||||
ValueArray va;
|
||||
for(int i = 0; i < x.GetCount(); i++)
|
||||
va.Add(AsXmlRpcValue(x[i]));
|
||||
v = va;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValuePut(Value& v, const ArrayMap<String, T>& 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 <class T>
|
||||
void ValuePut(Value& v, const VectorMap<String, T>& 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 <class T>
|
||||
void ValuePut(Value& v, const ArrayMap<int, T>& 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 <class T>
|
||||
void ValuePut(Value& v, const VectorMap<int, T>& 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;
|
||||
}
|
||||
|
||||
struct ValueMapper {
|
||||
ValueMap map;
|
||||
bool get;
|
||||
|
||||
template <class T>
|
||||
ValueMapper& operator()(const char *name, T& x) {
|
||||
if(get)
|
||||
ValueGet(x, map[name]);
|
||||
else {
|
||||
Value v;
|
||||
ValuePut(v, x);
|
||||
map.Add(name, v);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void ValueGetStruct_(T& x, const Value& v) {
|
||||
ValueCheck(IsNull(v) || IsValueMap(v));
|
||||
ValueMapper m;
|
||||
m.map = v;
|
||||
m.get = true;
|
||||
x.Map(m);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValuePutStruct_(Value& v, const T& x) {
|
||||
ValueMapper m;
|
||||
m.get = false;
|
||||
const_cast<T&>(x).Map(m);
|
||||
v = m.map;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct XmlRpcStruct {
|
||||
friend void ValueGet(T& x, const Value& v) { ValueGetStruct_(x, v); }
|
||||
friend void ValuePut(Value& v, const T& x) { ValuePutStruct_(v, x); }
|
||||
};
|
||||
|
||||
#define XMLRPC_STRUCT(T) \
|
||||
inline void ValueGet(T& x, const Value& v) { ValueGetStruct_(x, v); } \
|
||||
inline void ValuePut(Value& v, const T& x) { ValuePutStruct_(v, x); }
|
||||
|
||||
Value ParseXmlRpcValue(XmlParser& p);
|
||||
Value ParseXmlRpcParam(XmlParser& p);
|
||||
ValueArray ParseXmlRpcParams(XmlParser& p);
|
||||
|
||||
struct XmlRpcData {
|
||||
String peeraddr;
|
||||
ValueArray in;
|
||||
int ii;
|
||||
ValueArray out;
|
||||
|
||||
Value Get() { if(ii >= in.GetCount()) throw ValueTypeMismatch(); return in[ii++]; }
|
||||
|
||||
template <class T>
|
||||
XmlRpcData& operator>>(T& x) { ValueGet(x, Get()); return *this; }
|
||||
|
||||
template <class T>
|
||||
XmlRpcData& operator<<(const T& x) { Value v; ValuePut(v, x); out.Add(v); return *this; }
|
||||
template <class T>
|
||||
void Set(int i, const T& x) { Value v; ValuePut(v, x); out.Set(i, v); }
|
||||
|
||||
void Reset() { in.Clear(); out.Clear(); ii = 0; }
|
||||
|
||||
XmlRpcData() { 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)(XmlRpcData&), const char *group = NULL);
|
||||
void SetXmlRpcMethodFilter(String (*filter)(const String& methodname));
|
||||
bool XmlRpcPerform(TcpSocket& http, const char *group);
|
||||
bool XmlRpcServerLoop(int port, const char *group);
|
||||
|
||||
#define XMLRPC_METHOD(x) \
|
||||
void xmlrpc##x(XmlRpcData& rpc); \
|
||||
INITBLOCK { Register(#x, xmlrpc##x); } \
|
||||
void xmlrpc##x(XmlRpcData& rpc)
|
||||
|
||||
#define XMLRPC_GMETHOD(x, group) \
|
||||
void xmlrpc##x(XmlRpcData& rpc); \
|
||||
INITBLOCK { Register(#x, xmlrpc##x, group); } \
|
||||
void xmlrpc##x(XmlRpcData& rpc)
|
||||
|
||||
struct XmlRpcError {
|
||||
int code;
|
||||
String text;
|
||||
};
|
||||
|
||||
void ThrowXmlRpcError(int code, const char *s);
|
||||
void ThrowXmlRpcError(const char *s);
|
||||
|
||||
class XmlRpcRequest : HttpRequest {
|
||||
bool shorted;
|
||||
XmlRpcData data;
|
||||
String method;
|
||||
String error;
|
||||
String faultString;
|
||||
int faultCode;
|
||||
bool shouldExecute;
|
||||
|
||||
public:
|
||||
XmlRpcRequest& Method(const char *name);
|
||||
|
||||
template <class T>
|
||||
XmlRpcRequest& operator<<(const T& x) { data << x; return *this; }
|
||||
template <class T>
|
||||
void Set(int i, const T& x) { data.Set(i, x); }
|
||||
|
||||
Value Execute();
|
||||
Value Retry();
|
||||
|
||||
template <class T>
|
||||
bool operator>>(T& x) { if(Execute().IsError()) return false;
|
||||
try { data >> x; } catch(ValueTypeMismatch) { return false; } return true; }
|
||||
XmlRpcRequest& 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)> \
|
||||
XmlRpcRequest& 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();
|
||||
|
||||
XmlRpcRequest& Url(const char *url);
|
||||
|
||||
XmlRpcRequest(const char *url);
|
||||
XmlRpcRequest();
|
||||
};
|
||||
|
||||
void LogXmlRpcRequests(bool b = true);
|
||||
|
||||
void SetXmlRpcServerTrace(Stream& s, int level = 1);
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
description "XML-RPC support package (both server and client stuff)\3770,128,128";
|
||||
|
||||
uses
|
||||
Web;
|
||||
|
||||
file
|
||||
XmlRpc.h,
|
||||
Value.cpp,
|
||||
Xml.cpp,
|
||||
Server.cpp,
|
||||
Client.cpp;
|
||||
|
||||
4
uppsrc/Core/XmlRpc/init
Normal file
4
uppsrc/Core/XmlRpc/init
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#ifndef _Core_XmlRpc_icpp_init_stub
|
||||
#define _Core_XmlRpc_icpp_init_stub
|
||||
#include "Web/init"
|
||||
#endif
|
||||
|
|
@ -32,24 +32,6 @@ void SetXmlRpcMethodFilter(String (*filter)(const String& methodname))
|
|||
sXmlRpcMethodFilter = filter;
|
||||
}
|
||||
|
||||
struct XmlRpcError {
|
||||
int code;
|
||||
String text;
|
||||
};
|
||||
|
||||
void ThrowXmlRpcError(int code, const char *s)
|
||||
{
|
||||
XmlRpcError e;
|
||||
e.code = code;
|
||||
e.text = s;
|
||||
throw e;
|
||||
}
|
||||
|
||||
void ThrowXmlRpcError(const char *s)
|
||||
{
|
||||
ThrowXmlRpcError(-1, s);
|
||||
}
|
||||
|
||||
static Stream *xmlrpc_trace;
|
||||
static int xmlrpc_trace_level;
|
||||
|
||||
|
|
@ -186,7 +168,7 @@ bool XmlRpcPerform(Socket& http, const char *group)
|
|||
bool XmlRpcServer(int port, const char *group)
|
||||
{
|
||||
Socket rpc;
|
||||
if(!ServerSocket(rpc, 1234, true, 5))
|
||||
if(!ServerSocket(rpc, port, true, 5))
|
||||
return false;
|
||||
for(;;) {
|
||||
Socket http;
|
||||
|
|
|
|||
|
|
@ -1,272 +1,14 @@
|
|||
#ifndef _XmlRpc_XmlRpc_h
|
||||
#define _XmlRpc_XmlRpc_h
|
||||
#ifndef _XmlRpc_XmlRpc2_h
|
||||
#define _XmlRpc_XmlRpc2_h
|
||||
|
||||
#include <Web/Web.h>
|
||||
#include <Core/XmlRpc/XmlRpc.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
enum {
|
||||
XMLRPC_CLIENT_HTTP_ERROR = -1000000,
|
||||
XMLRPC_CLIENT_XML_ERROR,
|
||||
XMLRPC_CLIENT_RETTYPE_ERROR,
|
||||
XMLRPC_SERVER_PARAM_ERROR,
|
||||
XMLRPC_SERVER_XML_ERROR,
|
||||
XMLRPC_SERVER_PROCESSING_ERROR,
|
||||
XMLRPC_UNKNOWN_METHOD_ERROR,
|
||||
};
|
||||
|
||||
struct ValueTypeMismatch {};
|
||||
|
||||
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 <class T>
|
||||
void ValueGet(Array<T>& 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 <class T>
|
||||
void ValueGet(Vector<T>& 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 <class T>
|
||||
void ValueGet(ArrayMap<String, T>& x, const Value& v)
|
||||
{
|
||||
ValueCheck(IsValueMap(v));
|
||||
ValueMap vm = v;
|
||||
const Index<Value>& k = vm.GetKeys();
|
||||
ValueArray va = vm.GetValues();
|
||||
x.Clear();
|
||||
for(int i = 0; i < k.GetCount(); i++)
|
||||
x.Add(k[i], va[i]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValueGet(VectorMap<String, T>& x, const Value& v)
|
||||
{
|
||||
ValueCheck(IsValueMap(v));
|
||||
ValueMap vm = v;
|
||||
const Index<Value>& k = vm.GetKeys();
|
||||
ValueArray va = vm.GetValues();
|
||||
x.Clear();
|
||||
for(int i = 0; i < k.GetCount(); i++)
|
||||
x.Add(k[i], va[i]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValueGet(ArrayMap<int, T>& x, const Value& v)
|
||||
{
|
||||
ValueCheck(IsValueMap(v));
|
||||
ValueMap vm = v;
|
||||
const Index<Value>& 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 <class T>
|
||||
void ValueGet(VectorMap<int, T>& x, const Value& v)
|
||||
{
|
||||
ValueCheck(IsValueMap(v));
|
||||
ValueMap vm = v;
|
||||
const Index<Value>& 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);
|
||||
|
||||
template <class T>
|
||||
Value AsXmlRpcValue(const T& x)
|
||||
{
|
||||
Value vs;
|
||||
ValuePut(vs, x);
|
||||
return vs;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValuePut(Value& v, const Array<T>& x)
|
||||
{
|
||||
ValueArray va;
|
||||
for(int i = 0; i < x.GetCount(); i++)
|
||||
va.Add(AsXmlRpcValue(x[i]));
|
||||
v = va;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValuePut(Value& v, const Vector<T>& x)
|
||||
{
|
||||
ValueArray va;
|
||||
for(int i = 0; i < x.GetCount(); i++)
|
||||
va.Add(AsXmlRpcValue(x[i]));
|
||||
v = va;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValuePut(Value& v, const ArrayMap<String, T>& 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 <class T>
|
||||
void ValuePut(Value& v, const VectorMap<String, T>& 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 <class T>
|
||||
void ValuePut(Value& v, const ArrayMap<int, T>& 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 <class T>
|
||||
void ValuePut(Value& v, const VectorMap<int, T>& 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;
|
||||
}
|
||||
|
||||
struct ValueMapper {
|
||||
ValueMap map;
|
||||
bool get;
|
||||
|
||||
template <class T>
|
||||
ValueMapper& operator()(const char *name, T& x) {
|
||||
if(get)
|
||||
ValueGet(x, map[name]);
|
||||
else {
|
||||
Value v;
|
||||
ValuePut(v, x);
|
||||
map.Add(name, v);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void ValueGetStruct_(T& x, const Value& v) {
|
||||
ValueCheck(IsNull(v) || IsValueMap(v));
|
||||
ValueMapper m;
|
||||
m.map = v;
|
||||
m.get = true;
|
||||
x.Map(m);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValuePutStruct_(Value& v, const T& x) {
|
||||
ValueMapper m;
|
||||
m.get = false;
|
||||
const_cast<T&>(x).Map(m);
|
||||
v = m.map;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct XmlRpcStruct {
|
||||
friend void ValueGet(T& x, const Value& v) { ValueGetStruct_(x, v); }
|
||||
friend void ValuePut(Value& v, const T& x) { ValuePutStruct_(v, x); }
|
||||
};
|
||||
|
||||
#define XMLRPC_STRUCT(T) \
|
||||
inline void ValueGet(T& x, const Value& v) { ValueGetStruct_(x, v); } \
|
||||
inline void ValuePut(Value& v, const T& x) { ValuePutStruct_(v, x); }
|
||||
|
||||
Value ParseXmlRpcValue(XmlParser& p);
|
||||
Value ParseXmlRpcParam(XmlParser& p);
|
||||
ValueArray ParseXmlRpcParams(XmlParser& p);
|
||||
|
||||
struct XmlRpcData {
|
||||
String peeraddr;
|
||||
ValueArray in;
|
||||
int ii;
|
||||
ValueArray out;
|
||||
|
||||
Value Get() { if(ii >= in.GetCount()) throw ValueTypeMismatch(); return in[ii++]; }
|
||||
|
||||
template <class T>
|
||||
XmlRpcData& operator>>(T& x) { ValueGet(x, Get()); return *this; }
|
||||
|
||||
template <class T>
|
||||
XmlRpcData& operator<<(const T& x) { Value v; ValuePut(v, x); out.Add(v); return *this; }
|
||||
template <class T>
|
||||
void Set(int i, const T& x) { Value v; ValuePut(v, x); out.Set(i, v); }
|
||||
|
||||
void Reset() { in.Clear(); out.Clear(); ii = 0; }
|
||||
|
||||
XmlRpcData() { 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)(XmlRpcData&), const char *group = NULL);
|
||||
void SetXmlRpcMethodFilter(String (*filter)(const String& methodname));
|
||||
bool XmlRpcPerform(Socket& http, const char *group);
|
||||
bool XmlRpcServer(int port = 80, const char *group = NULL);
|
||||
|
||||
#define XMLRPC_METHOD(x) \
|
||||
void xmlrpc##x(XmlRpcData& rpc); \
|
||||
INITBLOCK { Register(#x, xmlrpc##x); } \
|
||||
void xmlrpc##x(XmlRpcData& rpc)
|
||||
|
||||
#define XMLRPC_GMETHOD(x, group) \
|
||||
void xmlrpc##x(XmlRpcData& rpc); \
|
||||
INITBLOCK { Register(#x, xmlrpc##x, group); } \
|
||||
void xmlrpc##x(XmlRpcData& rpc)
|
||||
|
||||
void ThrowXmlRpcError(int code, const char *s);
|
||||
void ThrowXmlRpcError(const char *s);
|
||||
|
||||
class XmlRpcCall {
|
||||
bool shorted;
|
||||
HttpClient server;
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@ uses
|
|||
|
||||
file
|
||||
XmlRpc.h,
|
||||
Value.cpp,
|
||||
Xml.cpp,
|
||||
Client.cpp,
|
||||
Server.cpp,
|
||||
xrs readonly separator,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue