[tbnl-devel] Handling HTTP errors

Stefan Scholl stesch at no-spoon.de
Tue Mar 1 15:03:37 UTC 2005


Hi!

On 2004-07-31 02:10:11, Stefan Scholl wrote:
> Function send-output in modlisp.lisp handles the response for
> different return codes. E. g. there's a "The requested URL ~A was
> not found on this server." for the 404 (+http-not-found+).
> 
> How about letting the user change this behavior?
> 
> One could explain the error to the user. Maybe in another
> language.
> 
> Or think of all the funny 404 games. Remember the SGI babies?


I've implemented a very easy solution for this:

  [Special variable]
  *http-error-handler*

      This variable holds NIL or a function designator. The
      function gets called with an error code other than +http-ok+
      or +http-not-modified+ and can return the content of an error
      page. Return NIL if the submitted error can't be handled.
      (Note that the handler function can access the request and
      reply data.) 


Now my own error handler can see if it has something to say.
Checking error code and maybe some further data from the request.
Very KISS.

Patch attached.


Regards,
Stefan

-------------- next part --------------
diff -ru --exclude='*.fasl' --exclude='*~' tbnl-0.3.11/doc/index.html tbnl-0.3.11-stesch/doc/index.html
--- tbnl-0.3.11/doc/index.html	2005-03-01 15:46:11.746925000 +0100
+++ tbnl-0.3.11-stesch/doc/index.html	2005-03-01 15:56:07.729322000 +0100
@@ -223,6 +223,7 @@
       <li><a href='#http-token-p'><code>http-token-p</code></a>
       <li><a href='#*tmp-directory*'><code>*tmp-directory*</code></a>
       <li><a href='#*save-raw-post-data-p*'><code>*save-raw-post-data-p*</code></a>
+      <li><a href='#*http-error-handler*'><code>*http-error-handler*</code></a>
     </ol>
     <li><a href='#debug'>Debugging TBNL applications</a>
     <ol>
@@ -1521,6 +1522,17 @@
 saved and may be retrieved with <a
 href="#raw-post-data"><code>RAW-POST-DATA</code></a>.  </blockquote>
 
+<p><br>[Special variable]
+<br><a class=none
+name="*http-error-handler*"><b>*http-error-handler*</b></a>
+
+<blockquote><br>
+This variable holds <code>NIL</code> or a function designator. The function gets called with an error code
+other than <code>+http-ok+</code> or <code>+http-not-modified+</code> and can return the content of an
+error page. Return <code>NIL</code> if the submitted error can't be handled.<br>
+(Note that the handler function can access the request and reply data.)
+</blockquote>
+
 <h4><a class=none name="debug">Debugging TBNL applications</a></h4>
 
 If you want to debug your TBNL applications it is recommend that you start Apache (i.e. the <code>httpd</code> binary) with the <code>-X</code> command-line option. Then set <a href="#*debug-mode*"><code>*DEBUG-MODE*</code></a> to a <em>true</em> value and poke around in the listener. Good luck... :)
diff -ru --exclude='*.fasl' --exclude='*~' tbnl-0.3.11/modlisp.lisp tbnl-0.3.11-stesch/modlisp.lisp
--- tbnl-0.3.11/modlisp.lisp	2005-03-01 15:05:31.000000000 +0100
+++ tbnl-0.3.11-stesch/modlisp.lisp	2005-03-01 15:31:08.000000000 +0100
@@ -51,26 +51,30 @@
             return-code +http-internal-server-error+
             status-line (status-line return-code)))
     (unless (member return-code `(,+http-ok+ ,+http-not-modified+))
-      ;; handle common return codes other than 200
-      (setf (content-type *reply*)
+      ;; Call error handler, if any. Should return nil if it can't handle the error.
+      (when *http-error-handler*
+        (setq content (funcall *http-error-handler* return-code)))
+      ;; handle common return codes other than 200, which weren't handled by the error handler.
+      (unless content
+        (setf (content-type *reply*)
               "text/html; charset=iso-8859-1"
-            content
+              content
               (format nil "<html><head><title>~D ~A</title></head><body><h1>~A</h1>~A<p><hr><address><a href='http://httpd.apache.org/'>~A</a> / <a href='http://www.fractalconcept.com/asp/html/mod_lisp.html'>mod_lisp~A/~A</a> / <a href='http://weitz.de/tbnl/'>TBNL ~A</a> <a href='~A'>(~A ~A)</a> at ~A Port ~D</address></p></body></html>"
                       return-code status-line status-line
                       (case return-code
                         ((#.+http-internal-server-error+)
-                          content)
+                         content)
                         ((#.+http-moved-temporarily+ #.+http-moved-permanently+)
-                          (format nil "The document has moved <a href='~A'>here</a>"
-                                  (header-out "Location")))
+                         (format nil "The document has moved <a href='~A'>here</a>"
+                                 (header-out "Location")))
                         ((#.+http-authorization-required+)
-                          "The server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials \(e.g., bad password), or your browser doesn't understand how to supply the credentials required.")
+                         "The server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials \(e.g., bad password), or your browser doesn't understand how to supply the credentials required.")
                         ((#.+http-forbidden+)
-                          (format nil "You don't have permission to access ~A on this server."
-                                  (script-name)))
+                         (format nil "You don't have permission to access ~A on this server."
+                                 (script-name)))
                         ((#.+http-not-found+)
-                          (format nil "The requested URL ~A was not found on this server."
-                                  (script-name))))
+                         (format nil "The requested URL ~A was not found on this server."
+                                 (script-name))))
                       (or (header-in "server-baseversion") "Apache")
                       (or (header-in "modlisp-major-version") "")
                       (or (header-in "modlisp-version") "")
@@ -79,7 +83,7 @@
                       (lisp-implementation-type)
                       (lisp-implementation-version)
                       (host *request*)
-                      (server-port :request *request*))))
+                      (server-port :request *request*)))))
     ;; start with status line
     (write-header-line "Status" (format nil "~d ~a" return-code status-line))
     ;; if there's content write the corresponding headers
diff -ru --exclude='*.fasl' --exclude='*~' tbnl-0.3.11/packages.lisp tbnl-0.3.11-stesch/packages.lisp
--- tbnl-0.3.11/packages.lisp	2005-03-01 15:24:13.000000000 +0100
+++ tbnl-0.3.11-stesch/packages.lisp	2005-03-01 15:32:00.000000000 +0100
@@ -40,6 +40,7 @@
            #:*error*
            #:*default-content-type*
            #:*default-handler*
+           #:*http-error-handler*
            #:*default-log-level*
            #:*dispatch-table*
            #:*lisp-errors-log-level*
diff -ru --exclude='*.fasl' --exclude='*~' tbnl-0.3.11/specials.lisp tbnl-0.3.11-stesch/specials.lisp
--- tbnl-0.3.11/specials.lisp	2005-03-01 15:23:57.000000000 +0100
+++ tbnl-0.3.11-stesch/specials.lisp	2005-03-01 15:27:46.000000000 +0100
@@ -242,6 +242,9 @@
 (defparameter *default-handler* 'default-handler
   "The name of the function which is always returned by DEFAULT-DISPATCHER.")
 
+(defvar *http-error-handler* nil
+  "A list of error dispatch functions.")
+
 (defparameter *default-log-level* nil
   "The default log level for LOG-MESSAGE*")
 


More information about the Tbnl-devel mailing list