def sendXMLResult(response, obj, id=1, opt=None): """ send the result as an xml format """ response.content_type = 'text/xml' res = '<?xml version="1.0" encoding="UTF-8"?>\ <jsonrpc version="%s">\ <result>\ <status>True</status>\ <value>%s</value>\ </result>\ <version>%s</version>\ <id>%s</id>\ </jsonrpc>' % (get_api_version(), obj, get_version(), id) xml_options = "" if opt: xml_options = "\n<options>" + json2xml(opt) + "</options>" xml_object = json2xml(obj) res = """<?xml version="1.0" encoding="UTF-8"?> <jsonrpc version="2.0"> <result> <status>True</status> <value>%s</value> </result> <version>%s</version> <id>%s</id>%s </jsonrpc>""" % (xml_object, get_version(), id, xml_options) return res
def sendResult(response, obj, id=1, opt=None, status=True): ''' sendResult - return an json result document :param response: the pylons response object :type response: response object :param obj: simple result object like dict, sting or list :type obj: dict or list or string/unicode :param id: id value, for future versions :type id: int :param opt: optional parameter, which allows to provide more detail :type opt: None or simple type like dict, list or string/unicode :return: json rendered sting result :rtype: string ''' response.content_type = 'application/json' res = { "jsonrpc": get_api_version(), "result": { "status": status, "value": obj, }, "version": get_version(), "id": id } if opt is not None and len(opt) > 0: res["detail"] = opt return json.dumps(res, indent=3)
def sendXMLResult(response, obj, id=1): response.content_type = 'text/xml' res = '<?xml version="1.0" encoding="UTF-8"?>\ <jsonrpc version="%s">\ <result>\ <status>True</status>\ <value>%s</value>\ </result>\ <version>%s</version>\ <id>%s</id>\ </jsonrpc>' % (get_api_version(), obj, get_version(), id) return res
def sendXMLError(response, exception, id=1): response.content_type = 'text/xml' if not hasattr(exception, "getId"): errId = -311 errDesc = str(exception) else: errId = exception.getId() errDesc = exception.getDescription() res = '<?xml version="1.0" encoding="UTF-8"?>\ <jsonrpc version="%s">\ <result>\ <status>False</status>\ <error>\ <code>%s</code>\ <message>%s</message>\ </error>\ </result>\ <version>%s</version>\ <id>%s</id>\ </jsonrpc>' % (get_api_version(), errId, errDesc, get_version(), id) return res
def sendResultIterator(obj, id=1, opt=None, rp=None, page=None): ''' sendResultIterator - return an json result document in a streamed mode :param obj: iterator of generator object like dict, string or list :param id: id value, for future versions :param opt: optional parameter, which allows to provide more detail :param rp: results per page :param page: number of page :return: generator of response data (yield) ''' api_version = get_api_version() linotp_version = get_version() res = { "jsonrpc": api_version, "result": { "status": True, "value": "[DATA]", }, "version": linotp_version, "id": id } err = { "jsonrpc": api_version, "result": { "status": False, "error": {}, }, "version": linotp_version, "id": id } start_at = 0 stop_at = 0 if page: if not rp: rp = 16 try: start_at = int(page) * int(rp) stop_at = start_at + int(rp) except ValueError as exx: err['result']['error'] = { "code": 9876, "message": "%r" % exx, } log.exception("failed to convert paging request parameters: %r" % exx) yield json.dumps(err) # finally we signal end of error result raise StopIteration() typ = "%s" % type(obj) if 'generator' not in typ and 'iterator' not in typ: raise Exception('no iterator method for object %r' % obj) res = { "jsonrpc": api_version, "result": { "status": True, "value": "[DATA]", }, "version": linotp_version, "id": id } if page: res['result']['page'] = int(page) if opt is not None and len(opt) > 0: res["detail"] = opt surrounding = json.dumps(res) prefix, postfix = surrounding.split('"[DATA]"') # first return the opening yield prefix + " [" sep = "" counter = 0 for next_one in obj: counter = counter + 1 # are we running in paging mode? if page: if counter >= start_at and counter < stop_at: res = "%s%s\n" % (sep, next_one) sep = ',' yield res if counter >= stop_at: # stop iterating if we reached the last one of the page break else: # no paging - no limit res = "%s%s\n" % (sep, next_one) sep = ',' yield res # we add the amount of queried objects total = '"queried" : %d' % counter postfix = ', %s %s' % (total, postfix) # last return the closing yield "] " + postfix
def sendError(response, exception, id=1, context=None): ''' sendError - return a HTML or JSON error result document Default LinOTP behaviour in case of error is to try to always send a '200 OK' HTTP response that contains an error code and description in the body (JSON data). Some clients prefer a different HTTP status code, because it allows response filtering without parsing the body. If the client sends 'httperror=<INT>' in the request this will be honoured (in case of error) and that HTTP status will be set. If 'httperror' is set without a value (or an invalid value) status 500 will be used. If you would like this to happen only in some error conditions but not all you can set 'linotp.errors' in the LinOTP Config. Then the HTTP status defined by 'httperror' will ONLY be sent when the error that occurs in LinOTP matches one of the errors defined in 'linotp.errors'. In other cases '200 OK' with error code and description in the body will be returned. If 'linotp.errors' is unset all errors will cause responses with HTTP status 'httperror'. For example: Setup 1: * The client sends httperror=777 in the request * linotp.errors=233,567 Case 1.1: An exception is raised in LinOTP that has errId 233. - LinOTP will return a response with HTTP status 777. Case 1.2: An exception is raised with errId 555 - LinOTP will return a response with HTTP status 200. Setup 2: * The client sends httperror (empty) in the request * linotp.errors=233,567 Case 2.1: An exception is raised in LinOTP that has errId 233. - LinOTP will return a response with HTTP status 500. Case 2.2: An exception is raised with errId 555 - LinOTP will return a response with HTTP status 200. Setup 3: * The client sends httperror (empty) in the request * linotp.errors is not set Case 3.1: An exception is raised in LinOTP that has errId 233. - LinOTP will return a response with HTTP status 500. Case 3.2: An exception is raised with errId 555 - LinOTP will return a response with HTTP status 500. Setup 4: * NO httperror in request * linotp.errors=233,567 (or is unset, does not matter) Case 4.1: An exception is raised in LinOTP that has errId 233. - LinOTP will return a response with HTTP status 200. Case 4.2: An exception is raised with errId 555 - LinOTP will return a response with HTTP status 200. remark for 'context' parameter: the 'context' is especially required to catch errors from the _before_ methods. The return of a _before_ must be of type response and must have the attribute response._exception set, to stop further processing, which otherwise will have ugly results!! :param response: the pylon response object :type response: response object :param exception: should be a linotp exception (s. linotp.lib.error.py) :type exception: exception :param id: id value, for future versions :type id: int :param context: default is None or 'before' :type context: string :return: json rendered sting result :rtype: string ''' ret = '' errId = -311 ## handle the different types of exception: ## Exception, LinOtpError, str/unicode if hasattr(exception, '__class__') is True \ and isinstance(exception, Exception): errDesc = unicode(exception) if isinstance(exception, LinotpError): errId = exception.getId() elif type(exception) in [str, unicode]: errDesc = unicode(exception) else: errDesc = u"%r" % exception ## check if we have an additional request parameter 'httperror' ## which triggers the error to be delivered as HTTP Error httperror = _get_httperror_from_params(request) send_custom_http_status = False if httperror is not None: # Client wants custom HTTP status linotp_errors = c.linotpConfig.get('linotp.errors', None) if not linotp_errors: # Send custom HTTP status in every error case send_custom_http_status = True else: # Only send custom HTTP status in defined error cases if unicode(errId) in linotp_errors.split(','): send_custom_http_status = True else: send_custom_http_status = False if send_custom_http_status: # Send HTML response with HTTP status 'httperror' # Always set a reason, when no standard one found (e.g. custom HTTP # code like 444) use 'LinOTP Error' reason = httpErr.get(httperror, 'LinOTP Error') response.content_type = 'text/html' response.status = "%s %s" % (httperror, reason) code = httperror status = "%s %s" % (httperror, reason) desc = '[%s] %d: %s' % (get_version(), errId, errDesc) ret = resp % (code, status, code, status, desc) if context in ['before', 'after']: response._exception = exception response.text = u'' + ret ret = response else: # Send JSON response with HTTP status 200 OK response.content_type = 'application/json' res = { "jsonrpc": get_api_version(), "result": { "status": False, "error": { "code": errId, "message": errDesc, }, }, "version": get_version(), "id": id } ret = json.dumps(res, indent=3) if context in ['before', 'after']: response._exception = exception response.body = ret ret = response return ret
def sendResultIterator(obj, id=1, opt=None, rp=None, page=None): ''' sendResultIterator - return an json result document in a streamed mode :param obj: iterator of generator object like dict, string or list :param id: id value, for future versions :param opt: optional parameter, which allows to provide more detail :param rp: results per page :param page: number of page :return: generator of response data (yield) ''' api_version = get_api_version() linotp_version = get_version() res = {"jsonrpc": api_version, "result": {"status": True, "value": "[DATA]", }, "version": linotp_version, "id": id} err = {"jsonrpc": api_version, "result": {"status": False, "error": {}, }, "version": linotp_version, "id": id } start_at = 0 stop_at = 0 if page: if not rp: rp = 16 try: start_at = int(page) * int(rp) stop_at = start_at + int(rp) except ValueError as exx: err['result']['error'] = { "code": 9876, "message": "%r" % exx, } log.exception("failed to convert paging request parameters: %r" % exx) yield json.dumps(err) # finally we signal end of error result raise StopIteration() typ = "%s" % type(obj) if 'generator' not in typ and 'iterator' not in typ: raise Exception('no iterator method for object %r' % obj) res = {"jsonrpc": api_version, "result": {"status": True, "value": "[DATA]", }, "version": linotp_version, "id": id} if page: res['result']['page'] = int(page) if opt is not None and len(opt) > 0: res["detail"] = opt surrounding = json.dumps(res) prefix, postfix = surrounding.split('"[DATA]"') # first return the opening yield prefix + " [" sep = "" counter = 0 for next_one in obj: counter = counter + 1 # are we running in paging mode? if page: if counter >= start_at and counter < stop_at: res = "%s%s\n" % (sep, next_one) sep = ',' yield res if counter >= stop_at: # stop iterating if we reached the last one of the page break else: # no paging - no limit res = "%s%s\n" % (sep, next_one) sep = ',' yield res log.debug('Result iteration finished!') # we add the amount of queried objects total = '"queried" : %d' % counter postfix = ', %s %s' % (total, postfix) # last return the closing yield "] " + postfix
def sendError(response, exception, id=1, context=None): ''' sendError - return a HTML or JSON error result document Default LinOTP behaviour in case of error is to try to always send a '200 OK' HTTP response that contains an error code and description in the body (JSON data). Some clients prefer a different HTTP status code, because it allows response filtering without parsing the body. If the client sends 'httperror=<INT>' in the request this will be honoured (in case of error) and that HTTP status will be set. If 'httperror' is set without a value (or an invalid value) status 500 will be used. If you would like this to happen only in some error conditions but not all you can set 'linotp.errors' in the LinOTP Config. Then the HTTP status defined by 'httperror' will ONLY be sent when the error that occurs in LinOTP matches one of the errors defined in 'linotp.errors'. In other cases '200 OK' with error code and description in the body will be returned. If 'linotp.errors' is unset all errors will cause responses with HTTP status 'httperror'. For example: Setup 1: * The client sends httperror=777 in the request * linotp.errors=233,567 Case 1.1: An exception is raised in LinOTP that has errId 233. - LinOTP will return a response with HTTP status 777. Case 1.2: An exception is raised with errId 555 - LinOTP will return a response with HTTP status 200. Setup 2: * The client sends httperror (empty) in the request * linotp.errors=233,567 Case 2.1: An exception is raised in LinOTP that has errId 233. - LinOTP will return a response with HTTP status 500. Case 2.2: An exception is raised with errId 555 - LinOTP will return a response with HTTP status 200. Setup 3: * The client sends httperror (empty) in the request * linotp.errors is not set Case 3.1: An exception is raised in LinOTP that has errId 233. - LinOTP will return a response with HTTP status 500. Case 3.2: An exception is raised with errId 555 - LinOTP will return a response with HTTP status 500. Setup 4: * NO httperror in request * linotp.errors=233,567 (or is unset, does not matter) Case 4.1: An exception is raised in LinOTP that has errId 233. - LinOTP will return a response with HTTP status 200. Case 4.2: An exception is raised with errId 555 - LinOTP will return a response with HTTP status 200. remark for 'context' parameter: the 'context' is especially required to catch errors from the _before_ methods. The return of a _before_ must be of type response and must have the attribute response._exception set, to stop further processing, which otherwise will have ugly results!! :param response: the pylon response object :type response: response object :param exception: should be a linotp exception (s. linotp.lib.error.py) :type exception: exception :param id: id value, for future versions :type id: int :param context: default is None or 'before' :type context: string :return: json rendered sting result :rtype: string ''' ret = '' errId = -311 ## handle the different types of exception: ## Exception, LinOtpError, str/unicode if hasattr(exception, '__class__') == True \ and isinstance(exception, Exception): errDesc = unicode(exception) if isinstance(exception, LinotpError): errId = exception.getId() elif type(exception) in [str, unicode]: errDesc = unicode(exception) else: errDesc = u"%r" % exception ## check if we have an additional request parameter 'httperror' ## which triggers the error to be delivered as HTTP Error httperror = _get_httperror_from_params(request) send_custom_http_status = False if httperror is not None: # Client wants custom HTTP status linotp_errors = c.linotpConfig.get('linotp.errors', None) if not linotp_errors: # Send custom HTTP status in every error case send_custom_http_status = True else: # Only send custom HTTP status in defined error cases if unicode(errId) in linotp_errors.split(','): send_custom_http_status = True else: send_custom_http_status = False if send_custom_http_status: # Send HTML response with HTTP status 'httperror' # Always set a reason, when no standard one found (e.g. custom HTTP # code like 444) use 'LinOTP Error' reason = httpErr.get(httperror, 'LinOTP Error') response.content_type = 'text/html' response.status = "%s %s" % (httperror, reason) code = httperror status = "%s %s" % (httperror, reason) desc = '[%s] %d: %s' % (get_version(), errId, errDesc) ret = resp % (code, status, code, status, desc) if context in ['before', 'after']: response._exception = exception response.text = u'' + ret ret = response else: # Send JSON response with HTTP status 200 OK response.content_type = 'application/json' res = { "jsonrpc": get_api_version(), "result" : {"status": False, "error": { "code" : errId, "message" : errDesc, }, }, "version": get_version(), "id": id } ret = json.dumps(res, indent=3) if context in ['before', 'after']: response._exception = exception response.body = ret ret = response return ret