5

I'm having an issue providing custom response handling for cherrypy.HTTPError. The only content that I want displayed in the body of the response is a JSON-encoded dict (this is REST API). The source code seems to indicate that HTTPError.set_response() can be used to modify the cherrypy.response object ... to quote the comment in this method:

Modify cherrypy.response status, headers, and body to represent self. CherryPy uses this internally, but you can also use it to create an HTTPError object and set its output without *raising* the exception.

I have sub-classed HTTPError to provide my own body for the response. I call the base class methods to ensure that any necessary housekeeping takes place.

class APIError(cherrypy.HTTPError):
    def __init__(self, err_resp):
        super().__init__(status=err_resp['error_code'])
        self._api_err_resp = err_resp

    def set_response(self):
        super().set_response()
        response = cherrypy.serving.response
        response.body = json.dumps(self._api_err_resp).encode()

I can now call APIError without a problem, but the issue I have is that the CherryPy web server takes approx 10-15sec to respond to my client once my custom error is raised (I experience no delay if I use HTTPError). I've traced the source code, but can't find the cause of the delay.

Any help would be appreciated.

Rob

Rob
  • 301
  • 3
  • 10
  • Indeed strange. Have you found a solution? – Bart Friederichs May 01 '17 at 20:02
  • I had the same issue, also with the time. The problem was that the Content-Length header was not set properly; the length that was set was of the traceback, instead of the new message. Setting the header with `response.headers["Content-Length"] = len(json_error_mesage)` (where `json_error_mesage` is `json.dumps()` output) solved the issue. Found it using CURL which returned error 18 (see https://stackoverflow.com/questions/1759956/curl-error-18-transfer-closed-with-outstanding-read-data-remaining) – jmpcm Mar 05 '20 at 14:42

2 Answers2

1

Using cherrypy 16.0.2 on Python 3.7.2, 64bit, windows7 subclassing HTTPError does not cause unusual waiting times. Maybe you should try with a current version of cherrypy.

This is the code I used to test it:

import cherrypy as cp 

class APIError(cp.HTTPError):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self._json_error = kwargs

    def set_response(self):
        super().set_response()
        response = cp.serving.response
        response.body = json.dumps({'error': self._json_error}).encode('utf-8')

This example requires you to call APIError with the proper keywords status and message. For production use, I wrote a larger class where I pass status, json data and other data for logging and then call the super().__init__ with only the status code.

576i
  • 7,579
  • 12
  • 55
  • 92
0

I got it to work with this approach, which takes esp. into account jmpcm's comment on setting the content length:

class APIError(cherrypy.HTTPError):
    def __init__(self, status=500, message=None):
        super().__init__(status=status, message=message)
        self._json_error = json.dumps({'error': message}).encode('utf-8')
    def set_response(self):
        super().set_response()
        response = cherrypy.serving.response
        response.body = self._json_error
        response.headers["Content-Length"] = len(self._json_error)
        response.headers['Content-Type'] = 'application/json'

``
Blindfreddy
  • 622
  • 6
  • 12