]> gitweb @ CieloNegro.org - Lucu.git/blob - Network/HTTP/Lucu/Response.hs
Reimplement MultipartForm
[Lucu.git] / Network / HTTP / Lucu / Response.hs
1 {-# LANGUAGE
2     DeriveDataTypeable
3   , OverloadedStrings
4   , RecordWildCards
5   , UnboxedTuples
6   , UnicodeSyntax
7   , ViewPatterns
8   #-}
9
10 -- |Definition of things related on HTTP response.
11 module Network.HTTP.Lucu.Response
12     ( StatusCode(..)
13     , printStatusCode
14
15     , Response(..)
16     , emptyResponse
17     , resCanHaveBody
18     , printResponse
19
20     , isInformational
21     , isSuccessful
22     , isRedirection
23     , isError
24     , isClientError
25     , isServerError
26     )
27     where
28 import Data.Ascii (Ascii, AsciiBuilder)
29 import qualified Data.Ascii as A
30 import Data.Monoid.Unicode
31 import Data.Typeable
32 import Network.HTTP.Lucu.Headers
33 import Network.HTTP.Lucu.HttpVersion
34 import Network.HTTP.Lucu.Utils
35 import Prelude.Unicode
36
37 -- |This is the definition of HTTP status code.
38 -- 'Network.HTTP.Lucu.Resource.setStatus' accepts these named status
39 -- codes so you don't have to memorize, for instance, that \"Gateway
40 -- Timeout\" is 504.
41 data StatusCode = Continue
42                 | SwitchingProtocols
43                 | Processing
44                 -- 
45                 | Ok
46                 | Created
47                 | Accepted
48                 | NonAuthoritativeInformation
49                 | NoContent
50                 | ResetContent
51                 | PartialContent
52                 | MultiStatus
53                 --
54                 | MultipleChoices
55                 | MovedPermanently
56                 | Found
57                 | SeeOther
58                 | NotModified
59                 | UseProxy
60                 | TemporaryRedirect
61                 --
62                 | BadRequest
63                 | Unauthorized
64                 | PaymentRequired
65                 | Forbidden
66                 | NotFound
67                 | MethodNotAllowed
68                 | NotAcceptable
69                 | ProxyAuthenticationRequired
70                 | RequestTimeout
71                 | Conflict
72                 | Gone
73                 | LengthRequired
74                 | PreconditionFailed
75                 | RequestEntityTooLarge
76                 | RequestURITooLarge
77                 | UnsupportedMediaType
78                 | RequestRangeNotSatisfiable
79                 | ExpectationFailed
80                 | UnprocessableEntitiy
81                 | Locked
82                 | FailedDependency
83                 --
84                 | InternalServerError
85                 | NotImplemented
86                 | BadGateway
87                 | ServiceUnavailable
88                 | GatewayTimeout
89                 | HttpVersionNotSupported
90                 | InsufficientStorage
91                   deriving (Eq, Show, Typeable)
92
93 -- |Convert a 'StatusCode' to an 'AsciiBuilder'.
94 printStatusCode ∷ StatusCode → AsciiBuilder
95 {-# INLINEABLE printStatusCode #-}
96 printStatusCode (statusCode → (# num, msg #))
97     = ( show3 num            ⊕
98         A.toAsciiBuilder " " ⊕
99         A.toAsciiBuilder msg
100       )
101
102 -- |This is the definition of an HTTP response.
103 data Response = Response {
104       resVersion ∷ !HttpVersion
105     , resStatus  ∷ !StatusCode
106     , resHeaders ∷ !Headers
107     } deriving (Show, Eq)
108
109 instance HasHeaders Response where
110     getHeaders         = resHeaders
111     setHeaders res hdr = res { resHeaders = hdr }
112
113 -- |Returns an HTTP\/1.1 'Response' with no header fields.
114 emptyResponse ∷ StatusCode → Response
115 emptyResponse sc
116     = Response {
117         resVersion = HttpVersion 1 1
118       , resStatus  = sc
119       , resHeaders = (∅)
120       }
121
122 -- |Returns 'True' iff a given 'Response' allows the existence of
123 -- response entity body.
124 resCanHaveBody ∷ Response → Bool
125 {-# INLINEABLE resCanHaveBody #-}
126 resCanHaveBody (Response {..})
127     | isInformational resStatus = False
128     | resStatus ≡ NoContent     = False
129     | resStatus ≡ ResetContent  = False
130     | resStatus ≡ NotModified   = False
131     | otherwise                 = True
132
133 -- |Convert a 'Response' to 'AsciiBuilder'.
134 printResponse ∷ Response → AsciiBuilder
135 {-# INLINEABLE printResponse #-}
136 printResponse (Response {..})
137     = printHttpVersion resVersion ⊕
138       A.toAsciiBuilder " "        ⊕
139       printStatusCode  resStatus  ⊕
140       A.toAsciiBuilder "\x0D\x0A" ⊕
141       printHeaders     resHeaders
142
143 -- |@'isInformational' sc@ returns 'True' iff @sc < 200@.
144 isInformational ∷ StatusCode → Bool
145 {-# INLINE isInformational #-}
146 isInformational = satisfy (< 200)
147
148 -- |@'isSuccessful' sc@ returns 'True' iff @200 <= sc < 300@.
149 isSuccessful ∷ StatusCode → Bool
150 {-# INLINE isSuccessful #-}
151 isSuccessful = satisfy (\ n → n ≥ 200 ∧ n < 300)
152
153 -- |@'isRedirection' sc@ returns 'True' iff @300 <= sc < 400@.
154 isRedirection ∷ StatusCode → Bool
155 {-# INLINE isRedirection #-}
156 isRedirection = satisfy (\ n → n ≥ 300 ∧ n < 400)
157
158 -- |@'isError' sc@ returns 'True' iff @400 <= sc@
159 isError ∷ StatusCode → Bool
160 {-# INLINE isError #-}
161 isError = satisfy (≥ 400)
162
163 -- |@'isClientError' sc@ returns 'True' iff @400 <= sc < 500@.
164 isClientError ∷ StatusCode → Bool
165 {-# INLINE isClientError #-}
166 isClientError = satisfy (\ n → n ≥ 400 ∧ n < 500)
167
168 -- |@'isServerError' sc@ returns 'True' iff @500 <= sc@.
169 isServerError ∷ StatusCode → Bool
170 {-# INLINE isServerError #-}
171 isServerError = satisfy (≥ 500)
172
173 satisfy ∷ (Int → Bool) → StatusCode → Bool
174 {-# INLINE satisfy #-}
175 satisfy p (statusCode → (# num, _ #)) = p num
176
177 statusCode ∷ StatusCode → (# Int, Ascii #)
178 {-# INLINEABLE statusCode #-}
179
180 statusCode Continue                    = (# 100, "Continue"                      #)
181 statusCode SwitchingProtocols          = (# 101, "Switching Protocols"           #)
182 statusCode Processing                  = (# 102, "Processing"                    #)
183
184 statusCode Ok                          = (# 200, "OK"                            #)
185 statusCode Created                     = (# 201, "Created"                       #)
186 statusCode Accepted                    = (# 202, "Accepted"                      #)
187 statusCode NonAuthoritativeInformation = (# 203, "Non Authoritative Information" #)
188 statusCode NoContent                   = (# 204, "No Content"                    #)
189 statusCode ResetContent                = (# 205, "Reset Content"                 #)
190 statusCode PartialContent              = (# 206, "Partial Content"               #)
191 statusCode MultiStatus                 = (# 207, "Multi Status"                  #)
192
193 statusCode MultipleChoices             = (# 300, "Multiple Choices"              #)
194 statusCode MovedPermanently            = (# 301, "Moved Permanently"             #)
195 statusCode Found                       = (# 302, "Found"                         #)
196 statusCode SeeOther                    = (# 303, "See Other"                     #)
197 statusCode NotModified                 = (# 304, "Not Modified"                  #)
198 statusCode UseProxy                    = (# 305, "Use Proxy"                     #)
199 statusCode TemporaryRedirect           = (# 306, "Temporary Redirect"            #)
200
201 statusCode BadRequest                  = (# 400, "Bad Request"                   #)
202 statusCode Unauthorized                = (# 401, "Unauthorized"                  #)
203 statusCode PaymentRequired             = (# 402, "Payment Required"              #)
204 statusCode Forbidden                   = (# 403, "Forbidden"                     #)
205 statusCode NotFound                    = (# 404, "Not Found"                     #)
206 statusCode MethodNotAllowed            = (# 405, "Method Not Allowed"            #)
207 statusCode NotAcceptable               = (# 406, "Not Acceptable"                #)
208 statusCode ProxyAuthenticationRequired = (# 407, "Proxy Authentication Required" #)
209 statusCode RequestTimeout              = (# 408, "Request Timeout"               #)
210 statusCode Conflict                    = (# 409, "Conflict"                      #)
211 statusCode Gone                        = (# 410, "Gone"                          #)
212 statusCode LengthRequired              = (# 411, "Length Required"               #)
213 statusCode PreconditionFailed          = (# 412, "Precondition Failed"           #)
214 statusCode RequestEntityTooLarge       = (# 413, "Request Entity Too Large"      #)
215 statusCode RequestURITooLarge          = (# 414, "Request URI Too Large"         #)
216 statusCode UnsupportedMediaType        = (# 415, "Unsupported Media Type"        #)
217 statusCode RequestRangeNotSatisfiable  = (# 416, "Request Range Not Satisfiable" #)
218 statusCode ExpectationFailed           = (# 417, "Expectation Failed"            #)
219 statusCode UnprocessableEntitiy        = (# 422, "Unprocessable Entity"          #)
220 statusCode Locked                      = (# 423, "Locked"                        #)
221 statusCode FailedDependency            = (# 424, "Failed Dependency"             #)
222
223 statusCode InternalServerError         = (# 500, "Internal Server Error"         #)
224 statusCode NotImplemented              = (# 501, "Not Implemented"               #)
225 statusCode BadGateway                  = (# 502, "Bad Gateway"                   #)
226 statusCode ServiceUnavailable          = (# 503, "Service Unavailable"           #)
227 statusCode GatewayTimeout              = (# 504, "Gateway Timeout"               #)
228 statusCode HttpVersionNotSupported     = (# 505, "HTTP Version Not Supported"    #)
229 statusCode InsufficientStorage         = (# 507, "Insufficient Storage"          #)
230 -- FIXME: Textual representations should also include numbers.
231 -- FIXME: StatusCode should be a type class rather than a type.