2 | import Data.ByteString
3 | import HTTP.API.Decode
5 | import HTTP.Header.Types
6 | import HTTP.RequestErr
9 | import IO.Async.Logging
15 | interface HTTPLocal where
16 | endOfURIPath : String
17 | floatingPointNumber : String
19 | invalidPath : String
21 | logLevel : LogLevel -> String
22 | missingBoundary : String
23 | missingFormDataPart : (part, parts : String) -> String
24 | missingHeader : String -> String
25 | missingQueryParameter : String -> String
26 | missingQueryValue : String -> String
27 | myMediaTypeNotAccepted : String -> String -> String
28 | naturalNumber : String
29 | outOfBounds : Show a => (min,max : a) -> String
30 | prettyDecodeErr : DecodeErr -> String
31 | prettyRequestErr : RequestErr -> String
32 | unsignedInteger : String
41 | valueString : String -> String
43 | valueString s = ": '\{s}'"
45 | dets : DecodeErr -> String
46 | dets (ContentErr _ ds) = ds
47 | dets (ReadErr _ _ ds) = ds
51 | commaSep : List String -> String
52 | commaSep = fastConcat . intersperse ","
55 | commaSepI : Interpolation a => List a -> String
56 | commaSepI = commaSep . map interpolate
59 | commaSepS : Show a => List a -> String
60 | commaSepS = commaSep . map show
62 | parameters {auto loc : HTTPLocal}
65 | Interpolation RequestErr where
66 | interpolate = prettyRequestErr
69 | Interpolation DecodeErr where
70 | interpolate = prettyDecodeErr
73 | decodeErr : Status -> DecodeErr -> RequestErr
74 | decodeErr s de = {message := "\{de}", details := dets de} (requestErr s)
79 | -> {auto r : Decode a}
81 | -> {auto s : Show a}
82 | -> {auto c : Cast a b}
86 | -> Either DecodeErr b
87 | bounded a t min max = refined t (outOfBounds min max) $
\v =>
88 | if (min <= v && v <= max) then Just (cast v) else Nothing
92 | decode (BS 0 _) = Left $
readErr naturalNumber empty
95 | then Right (cast $
decimal bs)
96 | else Left $
readErr naturalNumber bs
99 | Decode Integer where
100 | decode (BS 0 _) = Left $
readErr integer empty
101 | decode bs@(BS (S k) bv) =
102 | mapFst (setType integer) $
case head bv of
103 | 45 => map (negate . cast) (decodeAs Nat (BS k $
tail bv))
104 | _ => map cast $
decodeAs Nat bs
108 | decode = bounded Integer unsignedInteger 0 0xff
111 | Decode Bits16 where
112 | decode = bounded Integer unsignedInteger 0 0xffff
115 | Decode Bits32 where
116 | decode = bounded Integer unsignedInteger 0 0xffff_ffff
119 | Decode Bits64 where
120 | decode = bounded Integer unsignedInteger 0 0xffff_ffff_ffff_ffff
124 | decode = bounded Integer integer (-
0x80) 0x7f
128 | decode = bounded Integer integer (-
0x8000) 0x7fff
132 | decode = bounded Integer integer (-
0x8000_0000) 0x7fff_ffff
136 | decode = bounded Integer integer (-
0x8000_0000_0000_0000) 0x7fff_ffff_ffff_ffff
139 | Decode Double where
141 | case runBytes json bs of
142 | Right (JDouble x) => Right x
143 | Right (JInteger x) => Right $
cast x
144 | _ => Left $
readErr floatingPointNumber bs
146 | parameters {auto fj : FromJSON a}
149 | DecodeVia JSON a where
150 | fromBytes _ = mapFst (contentErr jsonValue) . parseBytes json Virtual
151 | decodeFrom = mapFst (contentErr jsonValue . JErr) . fromJSON
152 | mediaType = MT "application" "json"
154 | parameters {auto fd : FromFormData a}
157 | DecodeVia FormData a where
159 | case parameter "boundary" ps of
160 | Just b => Right $
multipart (fromString b) bs
161 | Nothing => Left $
Msg missingBoundary
162 | decodeFrom = fromFormData
163 | mediaType = MT "multipart" "form-data"
166 | getFDBytes : String -> FormData -> Either DecodeErr ByteString
168 | case find ((s ==) . name) xs of
169 | Nothing => Left $
Msg $
missingFormDataPart s (commaSep $
map name xs)
170 | Just p => Right p.content