示例#1
0
    def initialize(self, service=0):

        self.service_id = service
        self.db_conn = self.application.db_pool.connect()
        self.mail = Mail(options.mail_server)
        self._args = None
        super(BaseHandler, self).initialize()
示例#2
0
class BaseHandler(RequestHandler):

    logname = 'NamelessHereForEvermore'

    def write_response(self, status_code, description, data=None, error=None,
                       reason=None, http_code=None):

        ts = datetime.today().strftime("%Y-%m-%d %H:%M:%S")
        status = str(status_code)
        int_status = int(status_code)

        sig = ''.join((status, description, json.dumps(data), ts, 'Vanzilla'))
        sig = hashlib.sha1(sig).hexdigest()

        if not http_code:
            if int_status in httputil.responses:
                http_code = int_status
            else:
                http_code = 500

        if not reason:
            reason = self._reason

        self.set_status(http_code, reason=reason)

        self.my_response = {
            'status': int_status,
            'description': description,
            'sig': sig,
            'timestamp': ts,
        }

        if data:
            self.my_response['data'] = data
        if error:
            self.my_response['error'] = str(error)

        self.set_header('Content-Type', 'application/json')
        self.write(json.dumps(self.my_response))

    def initialize(self, service=0):

        self.service_id = service
        self.db_conn = self.application.db_pool.connect()
        self.mail = Mail(options.mail_server)
        self._args = None
        super(BaseHandler, self).initialize()

    def prepare(self):

        super(BaseHandler, self).prepare()
        # If the handler is using RecordHTTPMixin, self.reqid
        # will be set to the id of the relevant http_reqs DB record
        if hasattr(self, 'reqid'):
            uid = self.reqid
        else:
            uid = uuid.uuid4()
        self.log = RequestLogger(
            self.logname, uid, self.application.settings['log_level'])
        self.client = Client(self.log, self.db_conn, self.service_id)

    def on_finish(self):

        super(BaseHandler, self).on_finish()
        self.db_conn.close()

        critical_error_codes = [500, 501, 502, 503, 504]
        status = int(self.my_response['status'])
        if hasattr(self, 'my_response') and status in critical_error_codes:
            uri = self.request.uri
            message = ''
            if hasattr(self, 'args'):
                args = pformat(dict(self.args.__dict__.items()))
                message += 'Arguments: \n' + args + '\n\n'
            message += 'Response: \n' + pformat(self.my_response)
            opt = self.application.options
            self.mail.send(opt.maifrom, opt.mailto,
                           '[Vanzilla-app] %s' % uri, message)

    def write_error(self, status_code, **kwargs):

        critical_error_codes = [500, 501, 502, 503, 504]

        if status_code in critical_error_codes and 'exc_info' in kwargs:
            current_exc = traceback.format_exc()
            message = ''.join((
                'Generated by %s \n\n' % self.request.uri,
                'Traceback: \n %s \n\n' % current_exc,
            ))
            opt = self.application.options
            self.mail.send(opt.maifrom, opt.mailto,
                           '[Vanzilla-core] Critical Error', message)

        if self.settings.get("serve_traceback") and "exc_info" in kwargs:
            # in debug mode, try to send a traceback
            self.set_header('Content-Type', 'text/plain')
            for line in traceback.format_exception(*kwargs["exc_info"]):
                self.write(line)
            self.finish()
        else:
            if 'exc_info' in kwargs:
                error = None
                exc = kwargs['exc_info'][1]
                if hasattr(exc, 'log_message'):
                    error = exc.log_message
                else:
                    error = str(exc)
            self.write_response(status_code, description=self._reason, error=error)
            self.finish()

    def decode_argument(self, data, name=None):

        """
        this function try to find the encoding charset
        then decode the data to UNICODE

        At least we will have the same encoding for all data
        """

        if isinstance(data, str):
            for enc in ('utf_8', 'latin_1', 'cp1252', 'ascii'):
                try:
                    data = data.decode(enc)
                except UnicodeDecodeError:
                    if enc == "ascii":
                        data = data.decode('ascii', errors='ignore')
                else:
                    break
        elif hasattr(data, 'items'):
            for k, v in data.items():
                data[k] = self.decode_argument(v)
        elif hasattr(data, '__getitem__'):
            for i, datum in enumerate(data):
                data[i] = self.decode_argument(datum)

        return data

    def get_and_check_args(self, arg_specs):

        """
        Parameters
          arg_specs, list of tuples like:
            [
                (<arg_name>, <regular_expresssion>, <default_value>, <type_function>),
                ...
            ]
          where:
            arg_name is the name of the argument
            regular_expression is a regex string against which the argument value
              will be checked, or None to skip regex check.
            default_value is the default value if the user did not supply one, or
              None if the user MUST supply a value. We recommend you use the empty
              string '' if the arg is optional but doesn't have a meaningful
              default value.
            type_function is a function that will be applied to the argument value,
              most commonly a type conversion function (int, float, etc.), or the
              value None to get the raw string. **Note that the default value is
              NOT passed through this function; if you use the type int, supply
              an int default if you want consistent values.**

          Example:
            class MyHandler(BaseHandler):
                arg_specs = [
                  ('my_int', r'^[0-9]*$', 0, int),
                  ('json_list', r'^\[([^,]+(,[^,]+)*)?\]', None, json.loads),
                  ('mandatory_arg', r'^.*$', NO_DEFAULT, None),
                ]

        Returns
          ArgTuple object (with arg names as attributes)

          Example
            args = get_and_check_args(arg_specs)
            args.my_int
              0
            args.json_list
              None
            args.mandatory_arg
              'some user supplied value'
        """

        names = []
        values = []
        for name, regex, default, typefunc in arg_specs:
            names.append(name)
            if default is NO_DEFAULT:
                # Special value set in tornado.web meaning no default
                default = self._ARG_DEFAULT
            value = self.get_argument(name, default)
            if regex is not None:
                if re.search(regex, value) is None:
                    raise ArgumentValueError(name, value, regex)
            if typefunc is not None:
                try:
                    value = typefunc(value)
                except ValueError:
                    raise ArgumentTypeError(name, value, typefunc)
            values.append(value)

        ArgTuple = namedtuple('ArgTuple', names)
        return ArgTuple(values)

    @property
    def args(self):

        """
        You can magically access all arguments defined in
        self.arg_specs through this attribute, for example if you
        have defined the argument 'amount', you can access it with

        self.args.amount

        Argument parsing and checking is done behind the scenes.
        """

        if not self._args and hasattr(self, 'arg_specs'):
            self._args = self.get_and_check_args(self.arg_specs)

        return self._args