1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
|
(in-package :araneida)
(defgeneric start-listening (listener &key &allow-other-keys))
(defgeneric stop-listening (listener &key abort &allow-other-keys))
(defgeneric listening-p (listener))
(defmethod listening-p ((listener http-listener))
(and (http-listener-socket listener) t))
;; Be honest, this was a bad name anyway. We don't call break, we merely
;; omit to handle the condition
(defvar *break-on-handler-errors* nil
"deprecated; see *restart-on-handler-errors* instead")
(defvar *restart-on-handler-errors* t
"Controls the disposition of errors signalled during handler methods. If T, a backtrace will be printed to *TRACE-OUTPUT* and the ABORT-RESPONSE restart will be invoked to continue with the next request. It may also be a designator for a function: if so it will be called with the consition signalled and should handle it, or return T or NIL which will be handled as above")
(defmacro with-accept-flets (&body body)
`(labels ((do-it (listener s)
(let ((r (read-request-from-stream listener s)))
(handler-case
(handle-request-using-listener
listener (http-listener-handler listener) r)
(response-sent () nil)
(http-error (c)
(request-send-error r (http-error-code c)
:log-message (http-error-message c)
:client-message (http-error-client-message c))))))
(accept (listener)
(listener-accept-stream listener)))
(with-simple-restart
(abort-response "Abort this response and answer another request")
;; expectation is that socket-accept will not block, because we
;; are invoked when select() says something is ready. we really
;; ought to set the master socket non-blocking to be sure.
(let ((*debugger-hook* #'handler-debugger-hook))
,@body))))
(defgeneric handle-request-using-listener (http-listener handler request))
(defmethod handle-request-using-listener ((l http-listener) handler request)
(handle-request (http-listener-handler l) request))
(defun function-designator-p (n)
;; there really ought to be a better way to do this.
(cond ((functionp n) t)
((member n '(t nil)) nil)
((keywordp n) nil)
((symbolp n) t)
((and (consp n) (eql (car n) 'setf) (symbolp (cadr n))) t)
(t nil)))
(defun handler-debugger-hook (condition old-hook)
(declare (ignore old-hook))
(when
(or *break-on-handler-errors*
(if (function-designator-p *restart-on-handler-errors*)
(funcall *restart-on-handler-errors* condition)
*restart-on-handler-errors*))
(platform-handle-debugger-condition condition)
(invoke-restart 'abort-response)))
|