ErrorPtr VdcApiRequest::sendError(ErrorPtr aErrorToSend) { if (!Error::isOK(aErrorToSend)) { VdcApiErrorPtr ve = boost::dynamic_pointer_cast<VdcApiError>(aErrorToSend); if (ve) { // special VdcApiError, has extra user facing information return sendError((uint32_t)aErrorToSend->getErrorCode(), aErrorToSend->getErrorMessage(), ApiValuePtr(), ve->getErrorType(), ve->getUserFacingMessage()); } else { return sendError((uint32_t)aErrorToSend->getErrorCode(), aErrorToSend->getErrorMessage()); } } return ErrorPtr(); }
ErrorPtr VdcApiRequest::sendError(ErrorPtr aErrorToSend) { if (!Error::isOK(aErrorToSend)) { return sendError((uint32_t)aErrorToSend->getErrorCode(), aErrorToSend->getErrorMessage()); } return ErrorPtr(); }
ErrorPtr JsonRpcComm::sendError(const char *aJsonRpcId, ErrorPtr aErrorToSend) { if (!Error::isOK(aErrorToSend)) { return sendError(aJsonRpcId, (uint32_t)aErrorToSend->getErrorCode(), aErrorToSend->getErrorMessage()); } return ErrorPtr(); }
void P44VdcHost::sendCfgApiResponse(JsonCommPtr aJsonComm, JsonObjectPtr aResult, ErrorPtr aError) { // create response JsonObjectPtr response = JsonObject::newObj(); if (!Error::isOK(aError)) { // error, return error response response->add("error", JsonObject::newInt32((int32_t)aError->getErrorCode())); response->add("errormessage", JsonObject::newString(aError->getErrorMessage())); response->add("errordomain", JsonObject::newString(aError->getErrorDomain())); VdcApiErrorPtr ve = boost::dynamic_pointer_cast<VdcApiError>(aError); if (ve) { response->add("errortype", JsonObject::newInt32(ve->getErrorType())); response->add("userfacingmessage", JsonObject::newString(ve->getUserFacingMessage())); } } else { // no error, return result (if any) response->add("result", aResult); } LOG(LOG_DEBUG, "Config API response: %s", response->c_strValue()); aJsonComm->sendMessage(response); }
void JsonRpcComm::gotJson(ErrorPtr aError, JsonObjectPtr aJsonObject) { JsonRpcCommPtr keepMeAlive(this); // make sure this object lives until routine terminates ErrorPtr respErr; bool safeError = false; // set when reporting error is safe (i.e. not error possibly generated by malformed error, to prevent error loops) JsonObjectPtr idObj; const char *idString = NULL; if (Error::isOK(aError)) { // received proper JSON, now check JSON-RPC specifics FOCUSLOG("Received JSON message:\n %s\n", aJsonObject->c_strValue()); if (aJsonObject->isType(json_type_array)) { respErr = ErrorPtr(new JsonRpcError(JSONRPC_INVALID_REQUEST, "Invalid Request - batch mode not supported by this implementation")); } else if (!aJsonObject->isType(json_type_object)) { respErr = ErrorPtr(new JsonRpcError(JSONRPC_INVALID_REQUEST, "Invalid Request - request must be JSON object")); } else { // check request object fields const char *method = NULL; JsonObjectPtr o = aJsonObject->get("jsonrpc"); if (!o) respErr = ErrorPtr(new JsonRpcError(JSONRPC_INVALID_REQUEST, "Invalid Request - missing 'jsonrpc'")); else if (o->stringValue()!="2.0") respErr = ErrorPtr(new JsonRpcError(JSONRPC_INVALID_REQUEST, "Invalid Request - wrong version in 'jsonrpc'")); else { // get ID param (must be present for all messages except notification) idObj = aJsonObject->get("id"); if (idObj) idString = idObj->c_strValue(); JsonObjectPtr paramsObj = aJsonObject->get("params"); // JSON-RPC version is correct, check other params method = aJsonObject->getCString("method"); if (method) { // this is a request (responses don't have the method member) safeError = idObj!=NULL; // reporting error is safe if this is a method call. Other errors are reported only when reportAllErrors is set if (*method==0) respErr = ErrorPtr(new JsonRpcError(JSONRPC_INVALID_REQUEST, "Invalid Request - empty 'method'")); else { // looks like a valid method or notification call if (!jsonRequestHandler) { // no handler -> method cannot be executed respErr = ErrorPtr(new JsonRpcError(JSONRPC_METHOD_NOT_FOUND, "Method not found")); } else { if (paramsObj && !paramsObj->isType(json_type_array) && !paramsObj->isType(json_type_object)) { // invalid param object respErr = ErrorPtr(new JsonRpcError(JSONRPC_INVALID_REQUEST, "Invalid Request - 'params' must be object or array")); } else { // call handler to execute method or notification jsonRequestHandler(method, idString, paramsObj); } } } } else { // this is a response (requests always have a method member) // - check if result or error JsonObjectPtr respObj; if (!aJsonObject->get("result", respObj)) { // must be error, need further decoding respObj = aJsonObject->get("error"); if (!respObj) respErr = ErrorPtr(new JsonRpcError(JSONRPC_INTERNAL_ERROR, "Internal JSON-RPC error - response with neither 'result' nor 'error'")); else { // dissect error object ErrorCode errCode = JSONRPC_INTERNAL_ERROR; // Internal RPC error const char *errMsg = "malformed Error response"; // - try to get error code JsonObjectPtr o = respObj->get("code"); if (o) errCode = o->int32Value(); // - try to get error message o = respObj->get("message"); if (o) errMsg = o->c_strValue(); // compose error object from this respErr = ErrorPtr(new JsonRpcError(errCode, errMsg)); // also get optional data element respObj = respObj->get("data"); } } // Now we have either result or error.data in respObj, and respErr is Ok or contains the error code + message if (!idObj) { // errors without ID cannot be associated with calls made earlier, so just log the error LOG(LOG_WARNING,"JSON-RPC 2.0 warning: Received response with no or NULL 'id' that cannot be dispatched:\n %s\n", aJsonObject->c_strValue()); } else { // dispatch by ID uint32_t requestId = idObj->int32Value(); PendingAnswerMap::iterator pos = pendingAnswers.find(requestId); if (pos==pendingAnswers.end()) { // errors without ID cannot be associated with calls made earlier, so just log the error LOG(LOG_WARNING,"JSON-RPC 2.0 error: Received response with unknown 'id'=%d : %s\n", requestId, aJsonObject->c_strValue()); } else { // found callback JsonRpcResponseCB cb = pos->second; pendingAnswers.erase(pos); // erase cb(requestId, respErr, respObj); // call } respErr.reset(); // handled } } } } } else { // no proper JSON received, create error response if (aError->isDomain(JsonError::domain())) { // some kind of parsing error respErr = ErrorPtr(new JsonRpcError(JSONRPC_PARSE_ERROR, aError->description())); } else { // some other type of server error respErr = ErrorPtr(new JsonRpcError(JSONRPC_SERVER_ERROR, aError->description())); } } // auto-generate error response for internally created errors if (!Error::isOK(respErr)) { if (safeError || reportAllErrors) sendError(idString, respErr); else LOG(LOG_WARNING,"Received data that generated error which can't be sent back: Code=%d, Message='%s'\n", respErr->getErrorCode(), respErr->description().c_str()); } }