X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Fm_rpc_json.cpp;h=e57bb77b5be0c4a550699fec07d586768804e317;hb=6d03943426dcce76ba66567a9b18425a5ebb4c0c;hp=c0e4e14d9d4b22fd1a49b0a1fe0291686be7cdcc;hpb=bb1b08b0354620fad367c79471c99d7a836dc6e9;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modules/m_rpc_json.cpp b/src/modules/m_rpc_json.cpp index c0e4e14d9..e57bb77b5 100644 --- a/src/modules/m_rpc_json.cpp +++ b/src/modules/m_rpc_json.cpp @@ -2,2101 +2,367 @@ * | Inspire Internet Relay Chat Daemon | * +------------------------------------+ * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits * * This program is free but copyrighted software; see - * the file COPYING for details. + * the file COPYING for details. * * --------------------------------------------------- */ -#include -#include -#include -#include -#include - #include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "configreader.h" -#include "modules.h" -#include "inspsocket.h" #include "httpd.h" -#include "json.h" +#include "rpc.h" +#include -/* $ModDesc: Provides a JSON-RPC interface for modules using m_httpd.so */ +/* $ModDesc: Encode and decode JSON-RPC requests for modules */ +/* $ModDep: httpd.h rpc.h */ -class ModuleRpcJson : public Module +class JsonException : public std::exception { - void MthModuleVersion (HTTPRequest *http, json::Value &request, json::Value &response) + private: + std::string _what; + public: + JsonException(const std::string &swhat) + : _what(swhat) { - Version v = this->GetVersion(); - std::string result = ConvToStr(v.Major) + "." + ConvToStr(v.Minor) + "." + ConvToStr(v.Revision) + "." + ConvToStr(v.Build); - response["result"] = result; } - void system_list_methods (HTTPRequest *http, json::Value &request, json::Value &response) + virtual ~JsonException() throw() { } + + virtual const char *what() const throw() { - unsigned i = 0; - json::Value method_list (json::arrayValue); - - json::rpc::method_map::iterator it; - for (it = json::rpc::methods.begin(); it != json::rpc::methods.end(); ++it) - { - method_list[i] = json::Value (it->first); - i++; - } - - response["result"] = method_list; + return _what.c_str(); } +}; + +class ModuleRpcJson : public Module +{ + private: public: - ModuleRpcJson(InspIRCd* Me) : Module(Me) + ModuleRpcJson() { - ServerInstance->PublishInterface("JSON-RPC", this); - json::rpc::add_method ("system.listMethods", (Module *)this, (void (Module::*)(HTTPRequest*, json::Value&, json::Value&))&ModuleRpcJson::system_list_methods); - json::rpc::add_method ("ircd.moduleVersion", (Module *)this, (void (Module::*)(HTTPRequest*, json::Value&, json::Value&))&ModuleRpcJson::MthModuleVersion); + ServerInstance->Modules->PublishInterface("RPC", this); + Implementation eventlist[] = { I_OnEvent }; + ServerInstance->Modules->Attach(eventlist, this, 1); } - void OnEvent(Event* event) + virtual ~ModuleRpcJson() { - std::stringstream data(""); + ServerInstance->Modules->UnpublishInterface("RPC", this); + } + virtual Version GetVersion() + { + return Version("Encode and decode JSON-RPC requests for modules", VF_SERVICEPROVIDER | VF_VENDOR, API_VERSION); + } + + + virtual void OnEvent(Event *event) + { if (event->GetEventID() == "httpd_url") { - HTTPRequest* http = (HTTPRequest*)event->GetData(); + HTTPRequest *req = (HTTPRequest*) event->GetData(); - if (http->GetURI() == "/jsonrpc" && http->GetType() == "POST") + if ((req->GetURI() == "/rpc/json") || (req->GetURI() == "/rpc/json/")) { + std::stringstream data; + + RPCValue *reqobj = NULL; + try { - std::string response_text; - json::rpc::process (http, response_text, http->GetPostData().c_str()); - data << response_text; + reqobj = this->JSONParse(req->GetPostData()); + + if (!reqobj || (reqobj->GetType() != RPCObject)) + throw JsonException("RPC requests must be in the form of a single object"); + + RPCValue *method = reqobj->GetObject("method"); + if (!method || method->GetType() != RPCString) + throw JsonException("RPC requests must have a 'method' string field"); + + RPCValue *params = reqobj->GetObject("params"); + if (!params || params->GetType() != RPCArray) + throw JsonException("RPC requests must have a 'params' array field"); + + RPCRequest modreq("json", method->GetString(), params); + Event mev((char*) &modreq, this, "RPCMethod"); + mev.Send(); + + if (!modreq.claimed) + throw JsonException("Unrecognized method"); + + if (!modreq.error.empty()) + { + data << "{\"result\":null,\"error\":\"" << modreq.error << "\""; + } + else + { + data << "{\"result\":"; + this->JSONSerialize(modreq.result, data); + data << ",\"error\":null"; + } + + if (reqobj->GetObject("id")) + { + data << ",\"id\":"; + this->JSONSerialize(reqobj->GetObject("id"), data); + } + data << "}"; + + delete reqobj; + reqobj = NULL; } - catch (std::runtime_error &) + catch (std::exception &e) { - data << "{ \"result\": \"JSON Fault\", \"error\": \"Invalid RPC call\", \"id\": 1}"; + if (reqobj) + delete reqobj; + data << "{\"result\":null,\"error\":\"" << e.what() << "\"}"; } - /* Send the document back to m_httpd */ - HTTPDocument response(http->sock, &data, 200, "X-Powered-By: m_rpc_json.so\r\n" - "Content-Type: application/json; charset=iso-8859-1\r\n"); - Request req((char*)&response, (Module*)this, event->GetSource()); - req.Send(); + HTTPDocument response(req->sock, &data, 200); + response.headers.SetHeader("X-Powered-By", "m_rpc_json.so"); + response.headers.SetHeader("Content-Type", "application/json"); + response.headers.SetHeader("Connection", "Keep-Alive"); + + Request rreq((char*) &response, (Module*) this, event->GetSource()); + rreq.Send(); } } } - void Implements(char* List) + void AttachToParent(RPCValue *parent, RPCValue *child, const std::string &key = "") { - List[I_OnEvent] = 1; + if (!parent || !child) + return; + + if (parent->GetType() == RPCArray) + parent->ArrayAdd(child); + else if (parent->GetType() == RPCObject) + parent->ObjectAdd(key, child); + else + throw JsonException("Cannot add a value to a non-container"); } - virtual ~ModuleRpcJson() + void AttachToParentReset(RPCValue *parent, RPCValue *&child, std::string &key) { - ServerInstance->UnpublishInterface("JSON-RPC", this); + AttachToParent(parent, child, key); + child = NULL; + key.clear(); } - virtual Version GetVersion() + RPCValue *JSONParse(const std::string &data) { - return Version(0, 1, 0, 0, VF_VENDOR, API_VERSION); - } -}; - -namespace json -{ - ValueIteratorBase::ValueIteratorBase () - { - } - - - ValueIteratorBase::ValueIteratorBase (const Value::ObjectValues::iterator ¤t) - : current_ (current) - { - } - - Value & - ValueIteratorBase::deref () const - { - return current_->second; - } - - - void - ValueIteratorBase::increment () - { - ++current_; - } - - - void - ValueIteratorBase::decrement () - { - --current_; - } - - - ValueIteratorBase::difference_type - ValueIteratorBase::computeDistance (const SelfType &other) const - { - return difference_type (std::distance (current_, other.current_)); - } - - - bool - ValueIteratorBase::isEqual (const SelfType &other) const - { - return current_ == other.current_; - } - - - void - ValueIteratorBase::copy (const SelfType &other) - { - current_ = other.current_; - } - - - Value - ValueIteratorBase::key () const - { - const Value::CZString czstring = (*current_).first; - if (czstring.c_str ()) - { - if (czstring.isStaticString ()) - return Value (StaticString (czstring.c_str ())); - return Value (czstring.c_str ()); - } - return Value (czstring.index ()); - } - - - unsigned - ValueIteratorBase::index () const - { - const Value::CZString czstring = (*current_).first; - if (!czstring.c_str ()) - return czstring.index (); - return unsigned (-1); - } - - - char const * - ValueIteratorBase::memberName () const - { - char const *name = (*current_).first.c_str (); - return name ? name : ""; - } - - - ValueConstIterator::ValueConstIterator () - { - } - - - ValueConstIterator::ValueConstIterator (const Value::ObjectValues::iterator ¤t) - : ValueIteratorBase (current) - { - } - - ValueConstIterator & - ValueConstIterator::operator = (const ValueIteratorBase &other) - { - copy (other); - return *this; - } - - - ValueIterator::ValueIterator () - { - } - - - ValueIterator::ValueIterator (const Value::ObjectValues::iterator ¤t) - : ValueIteratorBase (current) - { - } - - ValueIterator::ValueIterator (const ValueConstIterator &other) - : ValueIteratorBase (other) - { - } - - ValueIterator::ValueIterator (const ValueIterator &other) - : ValueIteratorBase (other) - { - } - - ValueIterator & - ValueIterator::operator = (const SelfType &other) - { - copy (other); - return *this; - } -} - -namespace json -{ - inline bool - in (char c, char c1, char c2, char c3, char c4) - { - return c == c1 || c == c2 || c == c3 || c == c4; - } - - inline bool - in (char c, char c1, char c2, char c3, char c4, char c5) - { - return c == c1 || c == c2 || c == c3 || c == c4 || c == c5; - } - - - Reader::Reader () - { - } - - bool - Reader::parse (const std::string &document, - Value &root) - { - document_ = document; - char const *begin = document_.c_str (); - char const *end = begin + document_.length (); - return parse (begin, end, root); - } - - bool - Reader::parse (std::istream& sin, - Value &root) - { - std::string doc; - std::getline (sin, doc, (char)EOF); - return parse (doc, root); - } - - bool - Reader::parse (char const *beginDoc, char const *endDOc, - Value &root) - { - begin_ = beginDoc; - end_ = endDOc; - current_ = begin_; - lastValueEnd_ = 0; - lastValue_ = 0; - errors_.clear (); - while (!nodes_.empty ()) - nodes_.pop (); - nodes_.push (&root); - - bool successful = readValue (); - return successful; - } - - - bool - Reader::readValue () - { - Token token; - do - readToken (token); - while (token.type_ == tokenComment); - bool successful = true; - - switch (token.type_) - { - case tokenObjectBegin: - successful = readObject (); - break; - case tokenArrayBegin: - successful = readArray (); - break; - case tokenNumber: - successful = decodeNumber (token); - break; - case tokenString: - successful = decodeString (token); - break; - case tokenTrue: - currentValue () = true; - break; - case tokenFalse: - currentValue () = false; - break; - case tokenNull: - currentValue () = Value (); - break; - default: - return addError ("Syntax error: value, object or array expected.", token); - } - - return successful; - } - - - bool - Reader::expectToken (TokenType type, Token &token, char const *message) - { - readToken (token); - if (token.type_ != type) - return addError (message, token); - return true; - } - - - bool - Reader::readToken (Token &token) - { - skipSpaces (); - token.start_ = current_; - char c = getNextChar (); - bool ok = true; - switch (c) - { - case '{': - token.type_ = tokenObjectBegin; - break; - case '}': - token.type_ = tokenObjectEnd; - break; - case '[': - token.type_ = tokenArrayBegin; - break; - case ']': - token.type_ = tokenArrayEnd; - break; - case '"': - token.type_ = tokenString; - ok = readString (); - break; -#if 0 -#ifdef __GNUC__ - case '0'...'9': -#endif -#else - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - case '8': case '9': -#endif - case '-': - token.type_ = tokenNumber; - readNumber (); - break; - case 't': - token.type_ = tokenTrue; - ok = match ("rue", 3); - break; - case 'f': - token.type_ = tokenFalse; - ok = match ("alse", 4); - break; - case 'n': - token.type_ = tokenNull; - ok = match ("ull", 3); - break; - case ',': - token.type_ = tokenArraySeparator; - break; - case ':': - token.type_ = tokenMemberSeparator; - break; - case 0: - token.type_ = tokenEndOfStream; - break; - default: - ok = false; - break; - } - if (!ok) - token.type_ = tokenError; - token.end_ = current_; - return true; - } - - - void - Reader::skipSpaces () - { - while (current_ != end_) - { - char c = *current_; - if (c == ' ' || c == '\t' || c == '\r' || c == '\n') - ++current_; - else - break; - } - } - - - bool - Reader::match (Location pattern, int patternLength) - { - if (end_ - current_ < patternLength) - return false; - int index = patternLength; - while (index--) - if (current_[index] != pattern[index]) - return false; - current_ += patternLength; - return true; - } - - - void - Reader::readNumber () - { - while (current_ != end_) - { - if (!(*current_ >= '0' && *current_ <= '9') && - !in (*current_, '.', 'e', 'E', '+', '-')) - break; - ++current_; - } - } - - bool - Reader::readString () - { - char c = 0; - while (current_ != end_) - { - c = getNextChar (); - if (c == '\\') - getNextChar (); - else if (c == '"') - break; - } - return c == '"'; - } - - - bool - Reader::readObject () - { - Token tokenName; - std::string name; - currentValue () = Value (objectValue); - while (readToken (tokenName)) - { - if (tokenName.type_ == tokenObjectEnd && name.empty ()) // empty object - return true; - if (tokenName.type_ != tokenString) - break; - - name = ""; - if (!decodeString (tokenName, name)) - return recoverFromError (tokenObjectEnd); - - Token colon; - if (!readToken (colon) || colon.type_ != tokenMemberSeparator) - { - return addErrorAndRecover ("Missing ':' after object member name", - colon, - tokenObjectEnd); - } - Value &value = currentValue ()[ name ]; - nodes_.push (&value); - bool ok = readValue (); - nodes_.pop (); - if (!ok) // error already set - return recoverFromError (tokenObjectEnd); - - Token comma; - if (!readToken (comma) - || (comma.type_ != tokenObjectEnd && - comma.type_ != tokenArraySeparator)) - { - return addErrorAndRecover ("Missing ',' or '}' in object declaration", - comma, - tokenObjectEnd); - } - if (comma.type_ == tokenObjectEnd) - return true; - } - return addErrorAndRecover ("Missing '}' or object member name", - tokenName, - tokenObjectEnd); - } - - - bool - Reader::readArray () - { - currentValue () = Value (arrayValue); - skipSpaces (); - if (*current_ == ']') // empty array - { - Token endArray; - readToken (endArray); - return true; - } - int index = 0; - while (true) - { - Value &value = currentValue ()[ index++ ]; - nodes_.push (&value); - bool ok = readValue (); - nodes_.pop (); - if (!ok) // error already set - return recoverFromError (tokenArrayEnd); - - Token token; - if (!readToken (token) - || (token.type_ != tokenArraySeparator && - token.type_ != tokenArrayEnd)) - { - return addErrorAndRecover ("Missing ',' or ']' in array declaration", - token, - tokenArrayEnd); - } - if (token.type_ == tokenArrayEnd) - break; - } - return true; - } - - - bool - Reader::decodeNumber (Token &token) - { - bool isDouble = false; - for (Location inspect = token.start_; inspect != token.end_; ++inspect) - { - isDouble = isDouble - || in (*inspect, '.', 'e', 'E', '+') - || (*inspect == '-' && inspect != token.start_); - } - if (isDouble) - return decodeDouble (token); - Location current = token.start_; - bool isNegative = *current == '-'; - if (isNegative) - ++current; - unsigned threshold = (isNegative ? unsigned (-Value::minInt) - : Value::maxUInt) / 10; - unsigned value = 0; - while (current < token.end_) - { - char c = *current++; - if (c < '0' || c > '9') - return addError ("'" + std::string (token.start_, token.end_) + "' is not a number.", token); - if (value >= threshold) - return decodeDouble (token); - value = value * 10 + unsigned (c - '0'); - } - if (isNegative) - currentValue () = -int (value); - else if (value <= unsigned (Value::maxInt)) - currentValue () = int (value); - else - currentValue () = value; - return true; - } - - - bool - Reader::decodeDouble (Token &token) - { - double value = 0; - const int bufferSize = 32; - int count; - int length = int (token.end_ - token.start_); - if (length <= bufferSize) - { - char buffer[bufferSize]; - memcpy (buffer, token.start_, length); - buffer[length] = 0; - count = sscanf (buffer, "%lf", &value); - } - else - { - std::string buffer (token.start_, token.end_); - count = sscanf (buffer.c_str (), "%lf", &value); - } - - if (count != 1) - return addError ("'" + std::string (token.start_, token.end_) + "' is not a number.", token); - currentValue () = value; - return true; - } - - - bool - Reader::decodeString (Token &token) - { - std::string decoded; - if (!decodeString (token, decoded)) - return false; - currentValue () = decoded; - return true; - } - - - bool - Reader::decodeString (Token &token, std::string &decoded) - { - Location current = token.start_ + 1; // skip '"' - Location end = token.end_ - 1; // do not include '"' - decoded.reserve (long (end - current)); - - while (current != end) - { - char c = *current++; - if (expect_false (c == '"')) - break; - else if (expect_false (c == '\\')) - { - if (expect_false (current == end)) - return addError ("Empty escape sequence in string", token, current); - char escape = *current++; - switch (escape) - { - case '"': - case '/': - case '\\': decoded += escape; break; - - case 'b': decoded += '\010'; break; - case 't': decoded += '\011'; break; - case 'n': decoded += '\012'; break; - case 'f': decoded += '\014'; break; - case 'r': decoded += '\015'; break; - case 'u': + bool pisobject = false; + bool instring = false; + std::string stmp; + std::string vkey; + std::string pvkey; + RPCValue *aparent = NULL; + RPCValue *value = NULL; + + for (std::string::const_iterator i = data.begin(); i != data.end(); i++) { - unsigned unicode; - if (!decodeUnicodeEscapeSequence (token, current, end, unicode)) - return false; - // @todo encode unicode as utf8. - // @todo remember to alter the writer too. - } - break; - default: - return addError ("Bad escape sequence in string", token, current); - } - } - else - { - decoded += c; - } - } - - return true; - } - - - bool - Reader::decodeUnicodeEscapeSequence (Token &token, - Location ¤t, - Location end, - unsigned &unicode) - { - if (end - current < 4) - return addError ("Bad unicode escape sequence in string: four digits expected.", token, current); - unicode = 0; - for (int index = 0; index < 4; ++index) - { - char c = *current++; - unicode *= 16; - if (c >= '0' && c <= '9') - unicode += c - '0'; - else if (c >= 'a' && c <= 'f') - unicode += c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - unicode += c - 'A' + 10; - else - return addError ("Bad unicode escape sequence in string: hexadecimal digit expected.", token, current); - } - return true; - } - - - bool - Reader::addError (const std::string &message, - Token &token, - Location extra) - { - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = extra; - errors_.push_back (info); - return false; - } - - - bool - Reader::recoverFromError (TokenType skipUntilToken) - { - int errorCount = int (errors_.size ()); - Token skip; - while (true) - { - if (!readToken (skip)) - errors_.resize (errorCount); // discard errors caused by recovery - if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) - break; - } - errors_.resize (errorCount); - return false; - } - - - bool - Reader::addErrorAndRecover (const std::string &message, - Token &token, - TokenType skipUntilToken) - { - addError (message, token); - return recoverFromError (skipUntilToken); - } - - - Value & - Reader::currentValue () - { - return *(nodes_.top ()); - } - - - char - Reader::getNextChar () - { - if (current_ == end_) - return 0; - return *current_++; - } - - - void - Reader::getLocationLineAndColumn (Location location, - int &line, - int &column) const - { - Location current = begin_; - Location lastLineStart = current; - line = 0; - while (current < location && current != end_) - { - char c = *current++; - if (c == '\r') - { - if (*current == '\n') - ++current; - lastLineStart = current; - ++line; - } - else if (c == '\n') - { - lastLineStart = current; - ++line; - } - } - // column & line start at 1 - column = int (location - lastLineStart) + 1; - ++line; - } - - - std::string - Reader::getLocationLineAndColumn (Location location) const - { - int line, column; - getLocationLineAndColumn (location, line, column); - char buffer[18+16+16+1]; - sprintf (buffer, "Line %d, Column %d", line, column); - return buffer; - } - - - std::string - Reader::error_msgs () const - { - std::string formattedMessage; - for (Errors::const_iterator itError = errors_.begin (); - itError != errors_.end (); - ++itError) - { - const ErrorInfo &error = *itError; - formattedMessage += "* " + getLocationLineAndColumn (error.token_.start_) + "\n"; - formattedMessage += " " + error.message_ + "\n"; - if (error.extra_) - formattedMessage += "See " + getLocationLineAndColumn (error.extra_) + " for detail.\n"; - } - return formattedMessage; - } -} // namespace json - -namespace json -{ - void - unreachable_internal (char const *file, int line, char const *function) - { - char buf[1024]; - snprintf (buf, 1024, "%s (%d) [%s] critical: Unreachable line reached.", - file, line, function); - - throw std::runtime_error (buf); - } - - void - throw_unless_internal (char const *file, int line, char const *function, char const *condition) - { - char buf[1024]; - snprintf (buf, 1024, "%s (%d) [%s] critical: Assertion `%s' failed.", - file, line, function, condition); - - throw std::runtime_error (buf); - } - - void - throw_msg_unless_internal (char const *file, int line, char const *function, char const *message) - { - char buf[1024]; - snprintf (buf, 1024, "%s (%d) [%s] critical: %s.", - file, line, function, message); - - throw std::runtime_error (buf); - } - -#define throw_unreachable unreachable_internal (__FILE__, __LINE__, CURFUNC) -#define throw_unless(condition) if (!expect_false (condition)) throw_unless_internal (__FILE__, __LINE__, CURFUNC, #condition) -#define throw_msg_unless(condition, message) if (!expect_false (condition)) throw_msg_unless_internal (__FILE__, __LINE__, CURFUNC, message) - - const Value Value::null; - const int Value::minInt = int (~ (unsigned (-1)/2)); - const int Value::maxInt = int (unsigned (-1)/2); - const unsigned Value::maxUInt = unsigned (-1); - - ValueAllocator::~ValueAllocator () - { - } - - class DefaultValueAllocator : public ValueAllocator - { - public: - virtual ~DefaultValueAllocator () - { - } - - virtual char *makeMemberName (char const *memberName) - { - return duplicateStringValue (memberName); - } - - virtual void releaseMemberName (char *memberName) - { - releaseStringValue (memberName); - } - - virtual char *duplicateStringValue (char const *value, unsigned length = unknown) - { - //@todo invesgate this old optimization -#if 0 - if (!value || value[0] == 0) - return 0; -#endif - - if (length == unknown) - length = (unsigned)strlen (value); - char *newString = static_cast (malloc (length + 1)); - memcpy (newString, value, length); - newString[length] = 0; - return newString; - } - - virtual void releaseStringValue (char *value) - { - if (value) - free (value); - } - }; - - static ValueAllocator *&valueAllocator () - { - static DefaultValueAllocator defaultAllocator; - static ValueAllocator *valueAllocator = &defaultAllocator; - return valueAllocator; - } - - static struct DummyValueAllocatorInitializer { - DummyValueAllocatorInitializer () - { - valueAllocator (); // ensure valueAllocator () statics are initialized before main (). - } - } dummyValueAllocatorInitializer; - - - - Value::CZString::CZString (int index) - : cstr_ (0) - , index_ (index) - { - } - - Value::CZString::CZString (char const *cstr, DuplicationPolicy allocate) - : cstr_ (allocate == duplicate ? valueAllocator()->makeMemberName (cstr) - : cstr) - , index_ (allocate) - { - } - - Value::CZString::CZString (const CZString &other) - : cstr_ (other.index_ != noDuplication && other.cstr_ != 0 - ? valueAllocator()->makeMemberName (other.cstr_) - : other.cstr_) - , index_ (other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate) - : other.index_) - { - } - - Value::CZString::~CZString () - { - if (cstr_ && index_ == duplicate) - valueAllocator()->releaseMemberName (const_cast (cstr_)); - } - - void - Value::CZString::swap (CZString &other) - { - std::swap (cstr_, other.cstr_); - std::swap (index_, other.index_); - } - - Value::CZString & - Value::CZString::operator = (const CZString &other) - { - CZString temp (other); - swap (temp); - return *this; - } - - bool - Value::CZString::operator < (const CZString &other) const - { - if (cstr_) - return strcmp (cstr_, other.cstr_) < 0; - return index_ < other.index_; - } - - bool - Value::CZString::operator == (const CZString &other) const - { - if (cstr_) - return strcmp (cstr_, other.cstr_) == 0; - return index_ == other.index_; - } - - - int - Value::CZString::index () const - { - return index_; - } - - - char const * - Value::CZString::c_str () const - { - return cstr_; - } - - bool - Value::CZString::isStaticString () const - { - return index_ == noDuplication; - } - - - // class Value::Value - - Value::Value (ValueType type) - : type_ (type) - , allocated_ (0) - { - switch (type) - { - case nullValue: - break; - case intValue: - case uintValue: - value_.int_ = 0; - break; - case realValue: - value_.real_ = 0.0; - break; - case stringValue: - value_.string_ = 0; - break; - case arrayValue: - case objectValue: - value_.map_ = new ObjectValues (); - break; - case booleanValue: - value_.bool_ = false; - break; - default: - throw_unreachable; - } - } - - - Value::Value (int value) - : type_ (intValue) - { - value_.int_ = value; - } - - - Value::Value (unsigned value) - : type_ (uintValue) - { - value_.uint_ = value; - } - - Value::Value (double value) - : type_ (realValue) - { - value_.real_ = value; - } - - Value::Value (char const *value) - : type_ (stringValue) - , allocated_ (true) - { - value_.string_ = valueAllocator()->duplicateStringValue (value); - } - - Value::Value (const std::string &value) - : type_ (stringValue) - , allocated_ (true) - { - value_.string_ = valueAllocator()->duplicateStringValue (value.c_str (), (unsigned)value.length ()); - } - - Value::Value (const StaticString &value) - : type_ (stringValue) - , allocated_ (false) - { - value_.string_ = const_cast (value.c_str ()); - } - - - Value::Value (bool value) - : type_ (booleanValue) - { - value_.bool_ = value; - } - - - Value::Value (const Value &other) - : type_ (other.type_) - { - switch (type_) - { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - value_ = other.value_; - break; - case stringValue: - if (other.value_.string_) - { - value_.string_ = valueAllocator()->duplicateStringValue (other.value_.string_); - allocated_ = true; - } - else - value_.string_ = 0; - break; - case arrayValue: - case objectValue: - value_.map_ = new ObjectValues (*other.value_.map_); - break; - default: - throw_unreachable; - } - } - - - Value::~Value () - { - switch (type_) - { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - break; - case stringValue: - if (allocated_) - valueAllocator()->releaseStringValue (value_.string_); - break; - case arrayValue: - case objectValue: - delete value_.map_; - break; - default: - throw_unreachable; - } - } - - Value & - Value::operator = (const Value &other) - { - Value temp (other); - swap (temp); - return *this; - } - - void - Value::swap (Value &other) - { - ValueType temp = type_; - type_ = other.type_; - other.type_ = temp; - std::swap (value_, other.value_); - int temp2 = allocated_; - allocated_ = other.allocated_; - other.allocated_ = temp2; - } - - ValueType - Value::type () const - { - return type_; - } - - bool - Value::operator < (const Value &other) const - { - int typeDelta = type_ - other.type_; - if (typeDelta) - return typeDelta < 0 ? true : false; - switch (type_) - { - case nullValue: - return false; - case intValue: - return value_.int_ < other.value_.int_; - case uintValue: - return value_.uint_ < other.value_.uint_; - case realValue: - return value_.real_ < other.value_.real_; - case booleanValue: - return value_.bool_ < other.value_.bool_; - case stringValue: - return (value_.string_ == 0 && other.value_.string_) - || (other.value_.string_ - && value_.string_ - && strcmp (value_.string_, other.value_.string_) < 0); - case arrayValue: - case objectValue: - { - int delta = int (value_.map_->size () - other.value_.map_->size ()); - if (delta) - return delta < 0; - return (*value_.map_) < (*other.value_.map_); - } - default: - throw_unreachable; - } - return 0; // unreachable - } - - bool - Value::operator <= (const Value &other) const - { - return !(other > *this); - } - - bool - Value::operator >= (const Value &other) const - { - return !(*this < other); - } - - bool - Value::operator > (const Value &other) const - { - return other < *this; - } - - bool - Value::operator == (const Value &other) const - { - if (type_ != other.type_) - return false; - - switch (type_) - { - case nullValue: - return true; - case intValue: - return value_.int_ == other.value_.int_; - case uintValue: - return value_.uint_ == other.value_.uint_; - case realValue: - return value_.real_ == other.value_.real_; - case booleanValue: - return value_.bool_ == other.value_.bool_; - case stringValue: - return (value_.string_ == other.value_.string_) - || (other.value_.string_ - && value_.string_ - && strcmp (value_.string_, other.value_.string_) == 0); - case arrayValue: - case objectValue: - return value_.map_->size () == other.value_.map_->size () - && (*value_.map_) == (*other.value_.map_); - default: - throw_unreachable; - } - return 0; // unreachable - } - - bool - Value::operator != (const Value &other) const - { - return !(*this == other); - } - - Value::operator char const * () const - { - throw_unless (type_ == stringValue); - return value_.string_; - } - - - Value::operator std::string () const - { - switch (type_) - { - case nullValue: - return ""; - case stringValue: - return value_.string_ ? value_.string_ : ""; - case booleanValue: - return value_.bool_ ? "true" : "false"; - case intValue: - case uintValue: - case realValue: - case arrayValue: - case objectValue: - throw_msg_unless (false, "Type is not convertible to string"); - default: - throw_unreachable; - } - return ""; // unreachable - } - - Value::operator int () const - { - switch (type_) - { - case nullValue: - return 0; - case intValue: - return value_.int_; - case uintValue: - throw_msg_unless (value_.uint_ < (unsigned)maxInt, "integer out of signed integer range"); - return value_.uint_; - case realValue: - throw_msg_unless (value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range"); - return int (value_.real_); - case booleanValue: - return value_.bool_ ? 1 : 0; - case stringValue: - case arrayValue: - case objectValue: - throw_msg_unless (false, "Type is not convertible to int"); - default: - throw_unreachable; - } - return 0; // unreachable; - } - - Value::operator unsigned () const - { - switch (type_) - { - case nullValue: - return 0; - case intValue: - throw_msg_unless (value_.int_ >= 0, "Negative integer can not be converted to unsigned integer"); - return value_.int_; - case uintValue: - return value_.uint_; - case realValue: - throw_msg_unless (value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range"); - return unsigned (value_.real_); - case booleanValue: - return value_.bool_ ? 1 : 0; - case stringValue: - case arrayValue: - case objectValue: - throw_msg_unless (false, "Type is not convertible to uint"); - default: - throw_unreachable; - } - return 0; // unreachable; - } - - Value::operator double () const - { - switch (type_) - { - case nullValue: - return 0.0; - case intValue: - return value_.int_; - case uintValue: - return value_.uint_; - case realValue: - return value_.real_; - case booleanValue: - return value_.bool_ ? 1.0 : 0.0; - case stringValue: - case arrayValue: - case objectValue: - throw_msg_unless (false, "Type is not convertible to double"); - default: - throw_unreachable; - } - return 0; // unreachable; - } - - Value::operator bool () const - { - switch (type_) - { - case nullValue: - return false; - case intValue: - case uintValue: - return value_.int_ != 0; - case realValue: - return value_.real_ != 0.0; - case booleanValue: - return value_.bool_; - case stringValue: - return value_.string_ && value_.string_[0] != 0; - case arrayValue: - case objectValue: - return value_.map_->size () != 0; - default: - throw_unreachable; - } - return false; // unreachable; - } - - - bool - Value::isConvertibleTo (ValueType other) const - { - switch (type_) - { - case nullValue: - return true; - case intValue: - return (other == nullValue && value_.int_ == 0) - || other == intValue - || (other == uintValue && value_.int_ >= 0) - || other == realValue - || other == stringValue - || other == booleanValue; - case uintValue: - return (other == nullValue && value_.uint_ == 0) - || (other == intValue && value_.uint_ <= (unsigned)maxInt) - || other == uintValue - || other == realValue - || other == stringValue - || other == booleanValue; - case realValue: - return (other == nullValue && value_.real_ == 0.0) - || (other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt) - || (other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt) - || other == realValue - || other == stringValue - || other == booleanValue; - case booleanValue: - return (other == nullValue && value_.bool_ == false) - || other == intValue - || other == uintValue - || other == realValue - || other == stringValue - || other == booleanValue; - case stringValue: - return other == stringValue - || (other == nullValue && (!value_.string_ || value_.string_[0] == 0)); - case arrayValue: - return other == arrayValue - || (other == nullValue && value_.map_->size () == 0); - case objectValue: - return other == objectValue - || (other == nullValue && value_.map_->size () == 0); - default: - throw_unreachable; - } - return false; // unreachable; - } - - - /// Number of values in array or object - unsigned - Value::size () const - { - switch (type_) - { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - case stringValue: - return 0; - case arrayValue: // size of the array is highest index + 1 - if (!value_.map_->empty ()) - { - ObjectValues::const_iterator itLast = value_.map_->end (); - --itLast; - return itLast->first.index ()+1; - } - return 0; - case objectValue: - return int (value_.map_->size ()); - default: - throw_unreachable; - } - return 0; // unreachable; - } - - - bool - Value::empty () const - { - if (isNull () || isArray () || isObject ()) - return size () == 0u; - else - return false; - } - - - bool - Value::operator ! () const - { - return isNull (); - } - - - void - Value::clear () - { - throw_unless (type_ == nullValue || type_ == arrayValue || type_ == objectValue); - - switch (type_) - { - case arrayValue: - case objectValue: - value_.map_->clear (); - break; - default: - break; - } - } - - void - Value::resize (unsigned newSize) - { - throw_unless (type_ == nullValue || type_ == arrayValue); - if (type_ == nullValue) - *this = Value (arrayValue); - unsigned oldSize = size (); - if (newSize == 0) - clear (); - else if (newSize > oldSize) - (*this)[ newSize - 1 ]; - else - { - for (unsigned index = newSize; index < oldSize; ++index) - value_.map_->erase (index); - throw_unless (size () == newSize); - } - } - - - Value & - Value::operator [] (int index) - { - return operator [] (static_cast (index)); - } - - - Value & - Value::operator [] (unsigned index) - { - throw_unless (type_ == nullValue || type_ == arrayValue); - if (type_ == nullValue) - *this = Value (arrayValue); - CZString key (index); - ObjectValues::iterator it = value_.map_->lower_bound (key); - if (it != value_.map_->end () && it->first == key) - return it->second; - - ObjectValues::value_type defaultValue (key, null); - it = value_.map_->insert (it, defaultValue); - return it->second; - } - - - const Value & - Value::operator [] (int index) const - { - return operator [] (static_cast (index)); - } - - - const Value & - Value::operator [] (unsigned index) const - { - throw_unless (type_ == nullValue || type_ == arrayValue); - if (type_ == nullValue) - return null; - CZString key (index); - ObjectValues::const_iterator it = value_.map_->find (key); - if (it == value_.map_->end ()) - return null; - return it->second; - } - - - Value & - Value::operator [] (char const *key) - { - return resolveReference (key, false); - } - - - Value & - Value::resolveReference (char const *key, bool isStatic) - { - throw_unless (type_ == nullValue || type_ == objectValue); - if (type_ == nullValue) - *this = Value (objectValue); - CZString actualKey (key, isStatic ? CZString::noDuplication - : CZString::duplicateOnCopy); - ObjectValues::iterator it = value_.map_->lower_bound (actualKey); - if (it != value_.map_->end () && it->first == actualKey) - return it->second; - - ObjectValues::value_type defaultValue (actualKey, null); - it = value_.map_->insert (it, defaultValue); - Value &value = it->second; - return value; - } - - - Value - Value::get (int index, const Value &defaultValue) const - { - return get (static_cast (index), defaultValue); - } - - - Value - Value::get (unsigned index, const Value &defaultValue) const - { - const Value *value = &((*this)[index]); - return value == &null ? defaultValue : *value; - } - - - bool - Value::isValidIndex (int index) const - { - return isValidIndex (static_cast (index)); - } - - - bool - Value::isValidIndex (unsigned index) const - { - return index < size (); - } - - - - const Value & - Value::operator [] (char const *key) const - { - throw_unless (type_ == nullValue || type_ == objectValue); - if (type_ == nullValue) - return null; - CZString actualKey (key, CZString::noDuplication); - ObjectValues::const_iterator it = value_.map_->find (actualKey); - if (it == value_.map_->end ()) - return null; - return it->second; - } - - - Value & - Value::operator [] (const std::string &key) - { - return (*this)[ key.c_str () ]; - } - - - const Value & - Value::operator [] (const std::string &key) const - { - return (*this)[ key.c_str () ]; - } - - Value & - Value::operator [] (const StaticString &key) - { - return resolveReference (key, true); - } - - - Value & - Value::append (const Value &value) - { - return (*this)[size ()] = value; - } - - - Value - Value::get (char const *key, const Value &defaultValue) const - { - const Value *value = &((*this)[key]); - return value == &null ? defaultValue : *value; - } - - - Value - Value::get (const std::string &key, const Value &defaultValue) const - { - return get (key.c_str (), defaultValue); - } - - Value - Value::removeMember (char const *key) - { - throw_unless (type_ == nullValue || type_ == objectValue); - if (type_ == nullValue) - return null; - CZString actualKey (key, CZString::noDuplication); - ObjectValues::iterator it = value_.map_->find (actualKey); - if (it == value_.map_->end ()) - return null; - Value old (it->second); - value_.map_->erase (it); - return old; - } - - Value - Value::removeMember (const std::string &key) - { - return removeMember (key.c_str ()); - } - - bool - Value::isMember (char const *key) const - { - const Value *value = &((*this)[key]); - return value != &null; - } - - - bool - Value::isMember (const std::string &key) const - { - return isMember (key.c_str ()); - } - - - Value::Members - Value::getMemberNames () const - { - throw_unless (type_ == nullValue || type_ == objectValue); - if (type_ == nullValue) - return Value::Members (); - Members members; - members.reserve (value_.map_->size ()); - ObjectValues::const_iterator it; - ObjectValues::const_iterator itEnd = value_.map_->end (); - for (it = value_.map_->begin (); it != itEnd; ++it) - members.push_back (std::string (it->first.c_str())); - return members; - } - - bool - Value::isNull () const - { - return type_ == nullValue; - } - - - bool - Value::isBool () const - { - return type_ == booleanValue; - } - - - bool - Value::isInt () const - { - return type_ == intValue; - } - - - bool - Value::isUInt () const - { - return type_ == uintValue; - } - - - bool - Value::isIntegral () const - { - return type_ == intValue - || type_ == uintValue - || type_ == booleanValue; - } - - - bool - Value::isDouble () const - { - return type_ == realValue; - } - - - bool - Value::isNumeric () const - { - return isIntegral () || isDouble (); - } - - - bool - Value::isString () const - { - return type_ == stringValue; - } - - - bool - Value::isArray () const - { - return type_ == nullValue || type_ == arrayValue; - } - - - bool - Value::isObject () const - { - return type_ == nullValue || type_ == objectValue; - } + if (instring) + { + // TODO escape sequences + if (*i == '"') + { + instring = false; + if (pisobject && vkey.empty()) + vkey = stmp; + else + value = new RPCValue(stmp); - Value::const_iterator - Value::begin () const - { - switch (type_) - { - case arrayValue: - case objectValue: - if (value_.map_) - return const_iterator (value_.map_->begin ()); - break; - default: - break; - } - return const_iterator (); - } + stmp.clear(); + } + else + stmp += *i; - Value::const_iterator - Value::end () const - { - switch (type_) - { - case arrayValue: - case objectValue: - if (value_.map_) - return const_iterator (value_.map_->end ()); - break; - default: - break; - } - return const_iterator (); - } + continue; + } + if ((*i == ' ') || (*i == '\t') || (*i == '\r') || (*i == '\n')) + continue; - Value::iterator - Value::begin () - { - switch (type_) - { - case arrayValue: - case objectValue: - if (value_.map_) - return iterator (value_.map_->begin ()); - break; - default: - break; - } - return iterator (); - } + if (*i == '{') + { + // Begin object + if ((value) || (pisobject && vkey.empty())) + throw JsonException("Unexpected begin object token ('{')"); + + RPCValue *nobj = new RPCValue(RPCObject, aparent); + aparent = nobj; + pvkey = vkey; + vkey.clear(); + pisobject = true; + } + else if (*i == '}') + { + // End object + if ((!aparent) || (!pisobject) || (!vkey.empty() && !value)) + throw JsonException("Unexpected end object token ('}')"); + + // End value + if (value) + AttachToParentReset(aparent, value, vkey); + + if (!aparent->parent) + return aparent; + + value = aparent; + aparent = aparent->parent; + vkey = pvkey; + pvkey.clear(); + pisobject = (aparent->GetType() == RPCObject); + } + else if (*i == '"') + { + // Begin string + if (value) + throw JsonException("Unexpected begin string token ('\"')"); - Value::iterator - Value::end () - { - switch (type_) - { - case arrayValue: - case objectValue: - if (value_.map_) - return iterator (value_.map_->end ()); - break; - default: - break; - } - return iterator (); - } -} // namespace json + instring = true; + } + else if (*i == ':') + { + if ((!aparent) || (!pisobject) || (vkey.empty()) || (value)) + throw JsonException("Unexpected object value token (':')"); + } + else if (*i == ',') + { + if ((!aparent) || (!value) || ((pisobject) && (vkey.empty()))) + throw JsonException("Unexpected value seperator token (',')"); -namespace json -{ - static void uintToString (unsigned value, - char *¤t) - { - *--current = 0; - do - { - *--current = (value % 10) + '0'; - value /= 10; - } - while (value != 0); - } + AttachToParentReset(aparent, value, vkey); + } + else if (*i == '[') + { + // Begin array + if ((value) || (pisobject && vkey.empty())) + throw JsonException("Unexpected begin array token ('[')"); + + RPCValue *nar = new RPCValue(RPCArray, aparent); + aparent = nar; + pvkey = vkey; + vkey.clear(); + pisobject = false; + } + else if (*i == ']') + { + // End array (also an end value delimiter) + if (!aparent || pisobject) + throw JsonException("Unexpected end array token (']')"); - std::string valueToString (int value) - { - char buffer[32]; - char *current = buffer + sizeof (buffer); - bool isNegative = value < 0; - if (isNegative) - value = -value; - uintToString (unsigned (value), current); - if (isNegative) - *--current = '-'; - throw_unless (current >= buffer); - return current; - } + if (value) + AttachToParentReset(aparent, value, vkey); + if (!aparent->parent) + return aparent; - std::string valueToString (unsigned value) - { - char buffer[32]; - char *current = buffer + sizeof (buffer); - uintToString (value, current); - throw_unless (current >= buffer); - return current; - } + value = aparent; + aparent = aparent->parent; + vkey = pvkey; + pvkey.clear(); + pisobject = (aparent->GetType() == RPCObject); + } + else + { + // Numbers, false, null, and true fall under this heading. + if ((*i == 't') && ((i + 3) < data.end()) && (*(i + 1) == 'r') && (*(i + 2) == 'u') && (*(i + 3) == 'e')) + { + value = new RPCValue(true); + i += 3; + } + else if ((*i == 'f') && ((i + 4) < data.end()) && (*(i + 1) == 'a') && (*(i + 2) == 'l') && (*(i + 3) == 's') && (*(i + 4) == 'e')) + { + value = new RPCValue(false); + i += 4; + } + else if ((*i == 'n') && ((i + 3) < data.end()) && (*(i + 1) == 'u') && (*(i + 2) == 'l') && (*(i + 3) == 'l')) + { + value = new RPCValue(); + i += 3; + } + else if ((*i == '-') || (*i == '+') || (*i == '.') || ((*i >= '0') && (*i <= '9'))) + { + std::string ds = std::string(i, data.end()); + char *eds = NULL; - std::string valueToString (double value) - { - char buffer[32]; - sprintf (buffer, "%.16g", value); - return buffer; - } + errno = 0; + double v = strtod(ds.c_str(), &eds); + if (errno != 0) + throw JsonException("Error parsing numeric value"); - std::string valueToString (bool value) - { - return value ? "true" : "false"; - } + value = new RPCValue(v); - std::string valueToQuotedString (char const *value) - { - // Not sure how to handle unicode... - if (std::strpbrk (value, "\"\\\b\f\n\r\t") == NULL) - return std::string ("\"") + value + "\""; - // We have to walk value and escape any special characters. - // Appending to std::string is not efficient, but this should be rare. - // (Note: forward slashes are *not* rare, but I am not escaping them.) - unsigned maxsize = strlen (value) * 2 + 3; // allescaped+quotes+NULL - std::string result; - result.reserve (maxsize); // to avoid lots of mallocs - result += "\""; - for (char const* c=value; *c != 0; ++c){ - switch (*c){ - case '\"': - result += "\\\""; - break; - case '\\': - result += "\\\\"; - break; - case '\b': - result += "\\b"; - break; - case '\f': - result += "\\f"; - break; - case '\n': - result += "\\n"; - break; - case '\r': - result += "\\r"; - break; - case '\t': - result += "\\t"; - break; - case '/': - // Even though \/ is considered a legal escape in JSON, a bare - // slash is also legal, so I see no reason to escape it. - // (I hope I am not misunderstanding something.) - default: - result += *c; - } - } - result += "\""; - return result; - } + i += eds - ds.c_str() - 1; + } + else + throw JsonException("Unknown data in value portion"); + } + } - // Class Writer - std::string - Writer::write (const Value &root) - { - document_ = ""; - writeValue (root); - document_ += "\n"; - return document_; - } + if (instring) + throw JsonException("Unterminated string"); + if (aparent && pisobject) + throw JsonException("Unterminated object"); + else if (aparent && !pisobject) + throw JsonException("Unterminated array"); - void - Writer::writeValue (const Value &value) - { - switch (value.type ()) - { - case nullValue: - document_ += "null"; - break; - case intValue: - document_ += valueToString (static_cast (value)); - break; - case uintValue: - document_ += valueToString (static_cast (value)); - break; - case realValue: - document_ += valueToString (static_cast (value)); - break; - case stringValue: - document_ += valueToQuotedString (static_cast (value)); - break; - case booleanValue: - document_ += valueToString (static_cast (value)); - break; - case arrayValue: - { - document_ += "["; - int size = value.size (); - for (int index = 0; index < size; ++index) - { - if (index > 0) - document_ += ","; - writeValue (value[index]); - } - document_ += "]"; - } - break; - case objectValue: - { - Value::Members members (value.getMemberNames ()); - document_ += "{"; - for (Value::Members::iterator it = members.begin (); - it != members.end (); - ++it) - { - const std::string &name = *it; - if (it != members.begin ()) - document_ += ","; - document_ += valueToQuotedString (name.c_str ()); - document_ += ":"; - writeValue (value[name]); - } - document_ += "}"; + if (value) + return value; + else + throw JsonException("No JSON data found"); } - break; - } - } -} // namespace json - -/** - * RPC - */ -namespace json -{ - namespace rpc - { - method_map methods; - - void - add_method (char *name, Module const *mod, method mth) - { - mfp m = { mod, mth }; - methods[name] = m; - } - - void - service (HTTPRequest *http, Value &request, Value &response) - { - char const *methodName = static_cast (request["method"]); - - method_map::iterator mthit = methods.find (methodName); - if (mthit != methods.end ()) + void JSONSerialize(RPCValue *value, std::stringstream &re) { - mfp m = mthit->second; - Module *mod = new Module (*m.mod); - method mth = m.mth; - (mod->*mth) (http, request, response); - delete mod; + int ac; + switch (value->GetType()) + { + case RPCNull: + re << "null"; + break; + case RPCBoolean: + re << ((value->GetBool()) ? "true" : "false"); + break; + case RPCInteger: + re << value->GetInt(); + break; + case RPCString: + re << "\"" << value->GetString() << "\""; + break; + case RPCArray: + re << "["; + ac = value->ArraySize(); + for (int i = 0; i < ac; i++) + { + this->JSONSerialize(value->GetArray(i), re); + if (i != (ac - 1)) + re << ","; + } + re << "]"; + break; + case RPCObject: + re << "{"; + std::pair its = value->GetObjectIterator(); + while (its.first != its.second) + { + re << "\"" << its.first->first << "\":"; + this->JSONSerialize(its.first->second, re); + if (++its.first != its.second) + re << ","; + } + re << "}"; + break; + } } - } - - void - process (HTTPRequest *http, std::string &response_text, char const *request_text) - { - std::string text; - bool parse_success; - Value request (objectValue); - Value response (objectValue); - Reader r; - Writer w; - - response["error"] = Value(nullValue); - response["result"] = Value(nullValue); - - parse_success = r.parse (request_text, request_text + strlen (request_text), request); - - response["id"] = request["id"]; - - service (http, request, response); - - text = w.write (response); - - response_text = text.c_str (); - - return; - } - } // namespace rpc -} // namespace json +}; MODULE_INIT(ModuleRpcJson)