Put handler-case for usocket:connection-aborted-error around the right
[hunchentoot.git] / reply.lisp
blobe0ca6aecf3f6571f1925f984a65354210f75a833
1 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*-
2 ;;; $Header: /usr/local/cvsrep/hunchentoot/reply.lisp,v 1.20 2008/02/13 16:02:18 edi Exp $
4 ;;; Copyright (c) 2004-2009, Dr. Edmund Weitz. All rights reserved.
6 ;;; Redistribution and use in source and binary forms, with or without
7 ;;; modification, are permitted provided that the following conditions
8 ;;; are met:
10 ;;; * Redistributions of source code must retain the above copyright
11 ;;; notice, this list of conditions and the following disclaimer.
13 ;;; * Redistributions in binary form must reproduce the above
14 ;;; copyright notice, this list of conditions and the following
15 ;;; disclaimer in the documentation and/or other materials
16 ;;; provided with the distribution.
18 ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED
19 ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
24 ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 (in-package :hunchentoot)
32 (defclass reply ()
33 ((content-type :reader content-type
34 :documentation "The outgoing 'Content-Type' http
35 header which defaults to the value of *DEFAULT-CONTENT-TYPE*.")
36 (content-length :reader content-length
37 :initform nil
38 :documentation "The outgoing 'Content-Length'
39 http header which defaults NIL. If this is NIL, Hunchentoot will
40 compute the content length.")
41 (headers-out :initform nil
42 :reader headers-out
43 :documentation "An alist of the outgoing http headers
44 not including the 'Set-Cookie', 'Content-Length', and 'Content-Type'
45 headers. Use the functions HEADER-OUT and \(SETF HEADER-OUT) to
46 modify this slot.")
47 (return-code :initform +http-ok+
48 :accessor return-code
49 :documentation "The http return code of this
50 reply. The return codes Hunchentoot can handle are defined in
51 specials.lisp.")
52 (external-format :initform *hunchentoot-default-external-format*
53 :accessor reply-external-format
54 :documentation "The external format of the reply -
55 used for character output.")
56 (cookies-out :initform nil
57 :accessor cookies-out
58 :documentation "The outgoing cookies. This slot's
59 value should only be modified by the functions defined in
60 cookies.lisp."))
61 (:documentation "Objects of this class hold all the information
62 about an outgoing reply. They are created automatically by
63 Hunchentoot and can be accessed and modified by the corresponding
64 handler.
66 You should not mess with the slots of these objects directly, but you
67 can subclass REPLY in order to implement your own behaviour. See the
68 REPLY-CLASS slot of the ACCEPTOR class."))
70 (defmethod initialize-instance :after ((reply reply) &key)
71 (setf (header-out :content-type reply) *default-content-type*))
73 (defun headers-out* (&optional (reply *reply*))
74 "Returns an alist of the outgoing headers associated with the
75 REPLY object REPLY."
76 (headers-out reply))
78 (defun cookies-out* (&optional (reply *reply*))
79 "Returns an alist of the outgoing cookies associated with the
80 REPLY object REPLY."
81 (cookies-out reply))
83 (defun (setf cookies-out*) (new-value &optional (reply *reply*))
84 "Sets the alist of the outgoing cookies associated with the REPLY
85 object REPLY."
86 (setf (cookies-out reply) new-value))
88 (defun content-type* (&optional (reply *reply*))
89 "The outgoing 'Content-Type' http header of REPLY."
90 (content-type reply))
92 (defun (setf content-type*) (new-value &optional (reply *reply*))
93 "Sets the outgoing 'Content-Type' http header of REPLY."
94 (setf (header-out :content-type reply) new-value))
96 (defun content-length* (&optional (reply *reply*))
97 "The outgoing 'Content-Length' http header of REPLY."
98 (content-length reply))
100 (defun (setf content-length*) (new-value &optional (reply *reply*))
101 "Sets the outgoing 'Content-Length' http header of REPLY."
102 (setf (header-out :content-length reply) new-value))
104 (defun return-code* (&optional (reply *reply*))
105 "The http return code of REPLY. The return codes Hunchentoot can
106 handle are defined in specials.lisp."
107 (return-code reply))
109 (defun (setf return-code*) (new-value &optional (reply *reply*))
110 "Sets the http return code of REPLY."
111 (setf (return-code reply) new-value))
113 (defun reply-external-format* (&optional (reply *reply*))
114 "The external format of REPLY which is used for character output."
115 (reply-external-format reply))
117 (defun (setf reply-external-format*) (new-value &optional (reply *reply*))
118 "Sets the external format of REPLY."
119 (setf (reply-external-format reply) new-value))
121 (defun header-out-set-p (name &optional (reply *reply*))
122 "Returns a true value if the outgoing http header named NAME has
123 been specified already. NAME should be a keyword or a string."
124 (assoc* name (headers-out reply)))
126 (defun header-out (name &optional (reply *reply*))
127 "Returns the current value of the outgoing http header named NAME.
128 NAME should be a keyword or a string."
129 (cdr (assoc name (headers-out reply))))
131 (defun cookie-out (name &optional (reply *reply*))
132 "Returns the current value of the outgoing cookie named
133 NAME. Search is case-sensitive."
134 (cdr (assoc name (cookies-out reply) :test #'string=)))
136 (defgeneric (setf header-out) (new-value name &optional reply)
137 (:documentation "Changes the current value of the outgoing http
138 header named NAME \(a keyword or a string). If a header with this
139 name doesn't exist, it is created.")
140 (:method (new-value (name symbol) &optional (reply *reply*))
141 ;; the default method
142 (let ((entry (assoc name (headers-out reply))))
143 (if entry
144 (setf (cdr entry) new-value)
145 (setf (slot-value reply 'headers-out)
146 (acons name new-value (headers-out reply))))
147 new-value))
148 (:method (new-value (name string) &optional (reply *reply*))
149 "If NAME is a string, it is converted to a keyword first."
150 (setf (header-out (as-keyword name :destructivep nil) reply) new-value))
151 (:method :after (new-value (name (eql :content-length)) &optional (reply *reply*))
152 "Special case for the `Content-Length' header."
153 (check-type new-value integer)
154 (setf (slot-value reply 'content-length) new-value))
155 (:method :after (new-value (name (eql :content-type)) &optional (reply *reply*))
156 "Special case for the `Content-Type' header."
157 (check-type new-value string)
158 (setf (slot-value reply 'content-type) new-value)))