/** * Encoding to escape and unescape character to valid CDATA characters * ------------------------------------------------------------------- * Character XML escape sequence name * * '"' """ quote * '&' "&" amp * '\'' "'" apostrophe * '<' "<" lower than * '>' ">" greater than * ------------------------------------------------------------------- */ static inline unsigned char* u_set_quot(unsigned char* restrict r) { u_put_unalignedp32(r, U_MULTICHAR_CONSTANT32('&','q','u','o')); u_put_unalignedp16(r+4, U_MULTICHAR_CONSTANT16('t',';')); return r + U_CONSTANT_SIZE("""); } static inline unsigned char* u_set_amp(unsigned char* restrict r) { u_put_unalignedp32(r, U_MULTICHAR_CONSTANT32('&','a','m','p')); r[4] = ';'; return r + U_CONSTANT_SIZE("&"); } static inline unsigned char* u_set_apos(unsigned char* restrict r)
int URDBClientImage::handlerRead() { U_TRACE(0, "URDBClientImage::handlerRead()") u_clientimage_flag.u = 0; if (UClientImage_Base::genericRead() == false) { if (U_ClientImage_state == U_PLUGIN_HANDLER_AGAIN) U_RETURN(U_NOTIFIER_OK); // NOT BLOCKING... U_INTERNAL_ASSERT_EQUALS(U_ClientImage_state, U_PLUGIN_HANDLER_ERROR) U_RETURN(U_NOTIFIER_DELETE); } #ifdef U_LOG_ENABLE if (UClientImage_Base::logbuf) { *UClientImage_Base::request = *UClientImage_Base::rbuffer; UClientImage_Base::logRequest(); } #endif // check for RPC request URPC::resetInfo(); if (URPC::readRequest(UClientImage_Base::socket) == false) U_RETURN(U_NOTIFIER_DELETE); UClientImage_Base::wbuffer->setBuffer(U_CAPACITY); // Process the RPC message int result; const char* res = STR_200; const char* ptr = UClientImage_Base::rbuffer->data(); enum { RPC_METHOD_FIND = U_MULTICHAR_CONSTANT32('F','I','N','D'), RPC_METHOD_STORE = U_MULTICHAR_CONSTANT32('S','T','R','0'), RPC_METHOD_REPLACE = U_MULTICHAR_CONSTANT32('S','T','R','1'), RPC_METHOD_REMOVE = U_MULTICHAR_CONSTANT32('R','E','M','V'), RPC_METHOD_SUBSTITUTE0 = U_MULTICHAR_CONSTANT32('S','U','B','0'), RPC_METHOD_SUBSTITUTE1 = U_MULTICHAR_CONSTANT32('S','U','B','1'), RPC_METHOD_PRINT0 = U_MULTICHAR_CONSTANT32('P','R','T','0'), RPC_METHOD_PRINT1 = U_MULTICHAR_CONSTANT32('P','R','T','1'), RPC_METHOD_REORGANIZE = U_MULTICHAR_CONSTANT32('R','O','R','G'), RPC_METHOD_BEGIN_TRANSACTION = U_MULTICHAR_CONSTANT32('B','T','R','N'), RPC_METHOD_ABORT_TRANSACTION = U_MULTICHAR_CONSTANT32('A','T','R','N'), RPC_METHOD_COMMIT_TRANSACTION = U_MULTICHAR_CONSTANT32('C','T','R','N') }; switch (*(int32_t*)ptr) { case RPC_METHOD_FIND: { if (rdb->find((*URPC::rpc_info)[0])) { // Build the response: 200 uint32_t size = rdb->data.dsize; (void) UClientImage_Base::wbuffer->reserve(U_TOKEN_LN + size); UStringExt::buildTokenInt(res = STR_200, size, *UClientImage_Base::wbuffer); (void) UClientImage_Base::wbuffer->append((const char*)rdb->data.dptr, size); } else { // Build the response: 400 UStringExt::buildTokenInt(res = STR_400, 0, *UClientImage_Base::wbuffer); } } break; case RPC_METHOD_STORE: case RPC_METHOD_REPLACE: { // ------------------------------------------------------ // Write a key/value pair to a reliable database // ------------------------------------------------------ // RETURN VALUE // ------------------------------------------------------ // 0: Everything was OK // -1: flag was RDB_INSERT and this key already existed // -3: disk full writing to the journal file // ------------------------------------------------------ // #define RDB_INSERT 0 // Insertion of new entries only // #define RDB_REPLACE 1 // Allow replacing existing entries // ------------------------------------------------------ result = rdb->store((*URPC::rpc_info)[0], (*URPC::rpc_info)[1], ptr[3] == '0' ? RDB_INSERT : RDB_REPLACE); switch (result) { case 0: res = STR_200; break; // 0: Everything was OK case -1: res = STR_401; break; // -1: flag was RDB_INSERT and this key already existed case -3: res = STR_500; break; // -3: disk full writing to the journal file } UStringExt::buildTokenInt(res, 0, *UClientImage_Base::wbuffer); } break; case RPC_METHOD_REMOVE: { // --------------------------------------------------------- // Mark a key/value as deleted // --------------------------------------------------------- // RETURN VALUE // --------------------------------------------------------- // 0: Everything was OK // -1: The entry was not in the database // -2: The entry was already marked deleted in the hash-tree // -3: disk full writing to the journal file // --------------------------------------------------------- result = rdb->remove((*URPC::rpc_info)[0]); switch (result) { case 0: res = STR_200; break; // 0: Everything was OK case -1: res = STR_400; break; // -1: The entry was not in the database case -2: res = STR_402; break; // -2: The entry was already marked deleted in the hash-tree case -3: res = STR_500; break; // -3: disk full writing to the journal file } UStringExt::buildTokenInt(res, 0, *UClientImage_Base::wbuffer); } break; case RPC_METHOD_SUBSTITUTE0: case RPC_METHOD_SUBSTITUTE1: { // ---------------------------------------------------------- // Substitute a key/value with a new key/value (remove+store) // ---------------------------------------------------------- // RETURN VALUE // ---------------------------------------------------------- // 0: Everything was OK // -1: The entry was not in the database // -2: The entry was marked deleted in the hash-tree // -3: disk full writing to the journal file // -4: flag was RDB_INSERT and the new key already existed // ---------------------------------------------------------- // #define RDB_INSERT 0 // Insertion of new entries only // #define RDB_REPLACE 1 // Allow replacing existing entries result = rdb->substitute((*URPC::rpc_info)[0], (*URPC::rpc_info)[1], (*URPC::rpc_info)[2], ptr[3] == '0' ? RDB_INSERT : RDB_REPLACE); switch (result) { case 0: res = STR_200; break; // 0: Everything was OK case -1: res = STR_400; break; // -1: The entry was not in the database case -2: res = STR_402; break; // -2: The entry was marked deleted in the hash-tree case -3: res = STR_500; break; // -3: disk full writing to the journal file case -4: res = STR_401; break; // -4: flag was RDB_INSERT and the new key already existed } UStringExt::buildTokenInt(res, 0, *UClientImage_Base::wbuffer); } break; case RPC_METHOD_PRINT0: case RPC_METHOD_PRINT1: { // Build the response: 200 UString tmp = (ptr[3] == '0' ? rdb->print() : rdb->printSorted()); UStringExt::buildTokenInt(res = STR_200, tmp.size(), *UClientImage_Base::wbuffer); UClientImage_Base::wbuffer->append(tmp); } break; case RPC_METHOD_REORGANIZE: { res = (rdb->reorganize() ? STR_200 : STR_500); UStringExt::buildTokenInt(res, 0, *UClientImage_Base::wbuffer); } break; case RPC_METHOD_BEGIN_TRANSACTION: { res = (rdb->beginTransaction() ? STR_200 : STR_500); UStringExt::buildTokenInt(res, 0, *UClientImage_Base::wbuffer); } break; case RPC_METHOD_ABORT_TRANSACTION: { rdb->abortTransaction(); UStringExt::buildTokenInt(res = STR_200, 0, *UClientImage_Base::wbuffer); } break; case RPC_METHOD_COMMIT_TRANSACTION: { rdb->commitTransaction(); UStringExt::buildTokenInt(res = STR_200, 0, *UClientImage_Base::wbuffer); } break; default: { UStringExt::buildTokenInt(res = STR_500, 0, *UClientImage_Base::wbuffer); } break; } U_SRV_LOG_WITH_ADDR("method %.4S return %s for", ptr, res); return UClientImage_Base::handlerResponse(); }