String AsXML(const XmlNode& node, dword style) { StringBuffer r; if(style & XML_HEADER) r << XmlHeader(); if(style & XML_DOCTYPE) for(int i = 0; i < node.GetCount(); i++) { const XmlNode& m = node.Node(i); if(m.GetType() == XML_TAG) { r << XmlDocType(m.GetText()); break; } } style &= ~(XML_HEADER|XML_DOCTYPE); switch(node.GetType()) { case XML_PI: r << "<?" << node.GetText() << "?>\r\n"; break; case XML_DECL: r << "<!" << node.GetText() << ">\r\n"; break; case XML_COMMENT: r << "<!--" << node.GetText() << "-->\r\n"; break; case XML_DOC: for(int i = 0; i < node.GetCount(); i++) r << AsXML(node.Node(i), style); break; case XML_TEXT: r << DeXml(node.GetText()); break; case XML_TAG: XmlTag tag(node.GetText()); for(int i = 0; i < node.GetAttrCount(); i++) tag(node.AttrId(i), node.Attr(i)); if(node.GetCount()) { StringBuffer body; for(int i = 0; i < node.GetCount(); i++) body << AsXML(node.Node(i), style); r << tag(~body); } else r << tag(); } return r; }
String FormatXmlRpcError(int code, const char *text) { String r; r << XmlHeader() << "<methodResponse>" "<fault>" "<value>" "<struct>" "<member>" "<name>faultCode</name>" "<value><int>" << code << "</int></value>" "</member>" "<member>" "<name>faultString</name>" "<value><string>" << DeXml(text) << "</string></value>" "</member>" "</struct>" "</value>" "</fault>" "</methodResponse>" ; return r; }
RpcGet RpcRequest::Execute() { if(!shouldExecute) return RpcGet(); shouldExecute = false; String request; if(json) { ContentType("application/json"); static Atomic id; Json json; json("jsonrpc", "2.0") ("method", method); if(data.out.GetCount()) { JsonArray a; for(int i = 0; i < data.out.GetCount(); i++) { const Value& v = data.out[i]; if(v.Is<RawJsonText>()) a.CatRaw(v.To<RawJsonText>().json); else a << JsonRpcData(v); } json("params", a); } else if(data.out_map.GetCount()) { Json m; for(int i = 0; i < data.out_map.GetCount(); i++) { const Value& v = data.out_map.GetValue(i); String key = (String)data.out_map.GetKey(i); if(v.Is<RawJsonText>()) m.CatRaw(key, v.To<RawJsonText>().json); else m(key, JsonRpcData(v)); } json("params", m); } json("id", id); AtomicInc(id); request = ~json; } else { ContentType("text/xml"); request = XmlHeader(); request << XmlTag("methodCall")(XmlTag("methodName")(method) + FormatXmlRpcParams(data.out)); } if(sLogRpcCalls) { if(sLogRpcCallsCompress) RLOG("=== XmlRpc call request:\n" << CompressLog(request)); else RLOG("=== XmlRpc call request:\n" << request); } String response; New(); if(shorted) response = RpcExecuteShorted(request); else response = Post(request).Execute(); if(sLogRpcCalls) { if(sLogRpcCallsCompress) RLOG("=== XmlRpc call response:\n" << CompressLog(response)); else RLOG("=== XmlRpc call response:\n" << response); } RpcGet h; if(IsNull(response)) { faultCode = RPC_CLIENT_HTTP_ERROR; faultString = GetErrorDesc(); error = "Http request failed: " + faultString; LLOG(error); h.v = ErrorValue(error); return h; } if(json) { try { Value r = ParseJSON(response); if(IsValueMap(r)) { ValueMap m = r; Value result = m["result"]; if(!result.IsVoid()) { data.in.Clear(); data.in.Add(result); data.ii = 0; h.v = result; return h; } Value e = m["error"]; if(IsValueMap(e)) { Value c = e["code"]; Value m = e["message"]; if(IsNumber(c) && IsString(m)) { faultCode = e["code"]; faultString = e["message"]; error.Clear(); error << "Failed '" << faultString << "' (" << faultCode << ')'; LLOG(s); h.v = ErrorValue(error); return h; } } } String s; faultString = "Invalid response"; faultCode = RPC_CLIENT_RESPONSE_ERROR; error = faultString; LLOG(error); h.v = ErrorValue(error); return h; } catch(CParser::Error e) { String s; faultString = e; faultCode = RPC_CLIENT_JSON_ERROR; error.Clear(); error << "JSON Error: " << faultString; LLOG(error); h.v = ErrorValue(error); return h; } } else { 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); h.v = ErrorValue(error); return h; } } else { data.in = ParseXmlRpcParams(p); data.ii = 0; p.PassEnd(); } } catch(XmlError e) { String s; faultString = e; faultCode = RPC_CLIENT_XML_ERROR; error.Clear(); error << "XML Error: " << faultString; LLOG(error << ": " << p.GetPtr()); h.v = ErrorValue(error); return h; } h.v = data.in.GetCount() ? data.in[0] : Null; return h; } }
String XmlDoc(const char *name, const char *xmlbody) { return XmlHeader() + XmlDocType(name) + XmlTag(name)(xmlbody); }