wip: header test

This commit is contained in:
Orion Kindel 2024-12-04 21:51:15 -06:00
parent 7f5c022356
commit c0546a9a0d
Signed by untrusted user who does not match committer: orion
GPG Key ID: 6D4165AE4C928719
14 changed files with 4190 additions and 304 deletions

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,7 @@
{ {
"arrays": ">=7.3.0 <8.0.0" "arrays": ">=7.3.0 <8.0.0"
}, },
"b64",
{ {
"bifunctors": ">=6.0.0 <7.0.0" "bifunctors": ">=6.0.0 <7.0.0"
}, },
@ -38,9 +39,6 @@
{ {
"exceptions": ">=6.1.0 <7.0.0" "exceptions": ">=6.1.0 <7.0.0"
}, },
{
"ezfetch": ">=1.1.0 <2.0.0"
},
{ {
"foldable-traversable": ">=6.0.0 <7.0.0" "foldable-traversable": ">=6.0.0 <7.0.0"
}, },
@ -96,7 +94,6 @@
], ],
"build_plan": [ "build_plan": [
"aff", "aff",
"aff-promise",
"argonaut-codecs", "argonaut-codecs",
"argonaut-core", "argonaut-core",
"arraybuffer-types", "arraybuffer-types",
@ -115,7 +112,6 @@
"enums", "enums",
"exceptions", "exceptions",
"exists", "exists",
"ezfetch",
"filterable", "filterable",
"foldable-traversable", "foldable-traversable",
"foreign", "foreign",
@ -131,7 +127,6 @@
"lazy", "lazy",
"lists", "lists",
"maybe", "maybe",
"media-types",
"newtype", "newtype",
"node-buffer", "node-buffer",
"node-event-emitter", "node-event-emitter",
@ -168,9 +163,6 @@
"unsafe-coerce", "unsafe-coerce",
"url-immutable", "url-immutable",
"variant", "variant",
"web-dom",
"web-events",
"web-file",
"web-streams" "web-streams"
] ]
}, },
@ -800,15 +792,6 @@
"unsafe-coerce" "unsafe-coerce"
] ]
}, },
"aff-promise": {
"type": "registry",
"version": "4.0.0",
"integrity": "sha256-Kq5EupbUpXeUXx4JqGQE7/RTTz/H6idzWhsocwlEFhM=",
"dependencies": [
"aff",
"foreign"
]
},
"ansi": { "ansi": {
"type": "registry", "type": "registry",
"version": "7.0.0", "version": "7.0.0",
@ -1088,42 +1071,6 @@
"enums" "enums"
] ]
}, },
"ezfetch": {
"type": "registry",
"version": "1.1.0",
"integrity": "sha256-EA8KHFS6PMuOdZiFt7h0E5D5yCf7/sWAfsRJoCE/xP8=",
"dependencies": [
"aff",
"aff-promise",
"arraybuffer-types",
"b64",
"bifunctors",
"effect",
"either",
"exceptions",
"foldable-traversable",
"foreign",
"foreign-object",
"integers",
"maybe",
"newtype",
"node-buffer",
"node-streams",
"nullable",
"numbers",
"ordered-collections",
"prelude",
"record",
"simple-json",
"transformers",
"tuples",
"typelevel-prelude",
"unsafe-coerce",
"url-immutable",
"web-file",
"web-streams"
]
},
"filterable": { "filterable": {
"type": "registry", "type": "registry",
"version": "5.0.0", "version": "5.0.0",
@ -1361,15 +1308,6 @@
"prelude" "prelude"
] ]
}, },
"media-types": {
"type": "registry",
"version": "6.0.0",
"integrity": "sha256-n/4FoGBasbVSYscGVRSyBunQ6CZbL3jsYL+Lp01mc9k=",
"dependencies": [
"newtype",
"prelude"
]
},
"mmorph": { "mmorph": {
"type": "registry", "type": "registry",
"version": "7.0.0", "version": "7.0.0",
@ -2017,35 +1955,6 @@
"unsafe-coerce" "unsafe-coerce"
] ]
}, },
"web-dom": {
"type": "registry",
"version": "6.0.0",
"integrity": "sha256-1kSKWFDI4LupdmpjK01b1MMxDFW7jvatEgPgVmCmSBQ=",
"dependencies": [
"web-events"
]
},
"web-events": {
"type": "registry",
"version": "4.0.0",
"integrity": "sha256-YDt8b6u1tzGtnWyNRodne57iO8FNSGPaTCVzBUyUn4k=",
"dependencies": [
"datetime",
"enums",
"foreign",
"nullable"
]
},
"web-file": {
"type": "registry",
"version": "4.0.0",
"integrity": "sha256-1h5jPBkvjY71jLEdwVadXCx86/2inNoMBO//Rd3eCSU=",
"dependencies": [
"foreign",
"media-types",
"web-dom"
]
},
"web-streams": { "web-streams": {
"type": "registry", "type": "registry",
"version": "4.0.0", "version": "4.0.0",

View File

@ -1,6 +1,7 @@
package: package:
name: axon name: axon
dependencies: dependencies:
- b64
- parsing - parsing
- aff: ">=8.0.0 <9.0.0" - aff: ">=8.0.0 <9.0.0"
- argonaut-codecs: ">=9.1.0 <10.0.0" - argonaut-codecs: ">=9.1.0 <10.0.0"
@ -13,7 +14,6 @@ package:
- effect: ">=4.0.0 <5.0.0" - effect: ">=4.0.0 <5.0.0"
- either: ">=6.1.0 <7.0.0" - either: ">=6.1.0 <7.0.0"
- exceptions: ">=6.1.0 <7.0.0" - exceptions: ">=6.1.0 <7.0.0"
- ezfetch: ">=1.1.0 <2.0.0"
- foldable-traversable: ">=6.0.0 <7.0.0" - foldable-traversable: ">=6.0.0 <7.0.0"
- integers: ">=6.0.0 <7.0.0" - integers: ">=6.0.0 <7.0.0"
- maybe: ">=6.0.0 <7.0.0" - maybe: ">=6.0.0 <7.0.0"

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,10 @@
module Axon.Request.Parts.Class module Axon.Request.Parts.Class
( class RequestParts ( class RequestParts
, class RequestHandler
, invokeHandler
, extractRequestParts , extractRequestParts
, Header(..) , ExtractError(..)
, module Parts.Header
, module Parts.Method , module Parts.Method
, module Parts.Body , module Parts.Body
, module Path.Parts , module Path.Parts
@ -16,79 +19,90 @@ import Axon.Request.Method (Method)
import Axon.Request.Method as Method import Axon.Request.Method as Method
import Axon.Request.Parts.Body (Json(..), Stream(..)) import Axon.Request.Parts.Body (Json(..), Stream(..))
import Axon.Request.Parts.Body (Json(..), Stream(..)) as Parts.Body import Axon.Request.Parts.Body (Json(..), Stream(..)) as Parts.Body
import Axon.Request.Parts.Header (Header(..), HeaderMap(..))
import Axon.Request.Parts.Header (Header(..), HeaderMap(..)) as Parts.Header
import Axon.Request.Parts.Method (Connect(..), Delete(..), Get(..), Options(..), Patch(..), Post(..), Put(..), Trace(..)) import Axon.Request.Parts.Method (Connect(..), Delete(..), Get(..), Options(..), Patch(..), Post(..), Put(..), Trace(..))
import Axon.Request.Parts.Method (Get(..), Post(..), Put(..), Patch(..), Delete(..), Trace(..), Options(..), Connect(..)) as Parts.Method import Axon.Request.Parts.Method (Get(..), Post(..), Put(..), Patch(..), Delete(..), Trace(..), Options(..), Connect(..)) as Parts.Method
import Axon.Request.Parts.Path (Path(..)) as Path.Parts import Axon.Request.Parts.Path (Path(..)) as Path.Parts
import Axon.Request.Parts.Path (class DiscardTupledUnits, class PathParts, Path(..), discardTupledUnits, extractPathParts) import Axon.Request.Parts.Path (class DiscardTupledUnits, class PathParts, Path(..), discardTupledUnits, extractPathParts)
import Axon.Response (Response) import Control.Monad.Error.Class (liftEither, liftMaybe, throwError)
import Axon.Response as Response
import Control.Alternative (guard)
import Control.Monad.Except (ExceptT(..), runExceptT) import Control.Monad.Except (ExceptT(..), runExceptT)
import Control.Monad.Maybe.Trans (MaybeT(..), runMaybeT)
import Control.Monad.Trans.Class (lift)
import Data.Argonaut.Decode (class DecodeJson, decodeJson) import Data.Argonaut.Decode (class DecodeJson, decodeJson)
import Data.Argonaut.Decode.Error (printJsonDecodeError)
import Data.Array as Array import Data.Array as Array
import Data.Bifunctor (lmap) import Data.Bifunctor (bimap, lmap)
import Data.Either (Either(..), hush) import Data.Either (Either(..), note)
import Data.Generic.Rep (class Generic) import Data.Generic.Rep (class Generic)
import Data.Map as Map import Data.Map as Map
import Data.Maybe (Maybe(..)) import Data.Show.Generic (genericShow)
import Data.Newtype (class Newtype, wrap)
import Data.String.Lower as String.Lower import Data.String.Lower as String.Lower
import Data.Tuple.Nested (type (/\), (/\)) import Data.Tuple.Nested (type (/\), (/\))
import Data.URL as URL import Data.URL as URL
import Effect.Aff (Aff) import Effect.Aff (Aff)
import Effect.Aff.Class (class MonadAff, liftAff)
import Effect.Class (liftEffect) import Effect.Class (liftEffect)
import Node.Buffer (Buffer) import Node.Buffer (Buffer)
import Parsing (runParser) import Parsing (runParser)
import Parsing.String (parseErrorHuman)
newtype Header a = Header a data ExtractError
derive instance Generic (Header a) _ = ExtractError String
derive instance Newtype (Header a) _ | ExtractNext
derive newtype instance (Eq a) => Eq (Header a) | ExtractBadRequest String
derive newtype instance (Ord a) => Ord (Header a)
derive newtype instance (Show a) => Show (Header a) derive instance Generic ExtractError _
derive instance Eq ExtractError
instance Show ExtractError where show = genericShow
extractMethod :: extractMethod ::
forall a. forall a.
a -> a ->
Method -> Method ->
Request -> Request ->
Aff (Either Response (Maybe a)) Aff (Either ExtractError a)
extractMethod a method r = extractMethod a method r = runExceptT do
if Request.method r == method then when (Request.method r /= method) $ throwError ExtractNext
pure $ Right $ Just a pure a
else
pure $ Right Nothing class MonadAff m <= RequestHandler a m b | a -> b m where
invokeHandler :: Request -> a -> m (Either ExtractError b)
instance (MonadAff m, RequestHandler f m b, RequestParts a) => RequestHandler (a -> f) m b where
invokeHandler req f = runExceptT do
a <- ExceptT $ liftAff $ extractRequestParts @a req
ExceptT $ invokeHandler req (f a)
else instance (MonadAff m) => RequestHandler (m a) m a where
invokeHandler _ m = m <#> Right
class RequestParts a where class RequestParts a where
extractRequestParts :: Request -> Aff (Either Response (Maybe a)) extractRequestParts :: Request -> Aff (Either ExtractError a)
instance RequestParts Unit where instance RequestParts Unit where
extractRequestParts _ = pure unit # runMaybeT # runExceptT extractRequestParts _ = pure unit # runExceptT
instance RequestParts Request where instance RequestParts Request where
extractRequestParts r = pure r # runMaybeT # runExceptT extractRequestParts r = pure r # runExceptT
instance RequestParts String where instance RequestParts String where
extractRequestParts r = extractRequestParts r =
Request.bodyString r Request.bodyString r
<#> lmap (const $ Response.fromStatus 500) <#> lmap (const $ ExtractBadRequest "Expected body to be valid UTF-8")
# ExceptT
# lift
# runMaybeT
# runExceptT
instance RequestParts (Either Request.BodyStringError String) where instance RequestParts (Either Request.BodyStringError String) where
extractRequestParts r = extractRequestParts r = Request.bodyString r <#> Right
Request.bodyString r
<#> Just
<#> Right
instance TypedHeader a => RequestParts (Header a) where instance TypedHeader a => RequestParts (Header a) where
extractRequestParts r = runExceptT $ runMaybeT do extractRequestParts r = runExceptT do
value <- Request.headers r # Map.lookup (String.Lower.fromString $ headerName @a) # pure # MaybeT value <-
runParser value (headerValueParser @a) # hush # pure # MaybeT <#> Header Request.headers r
# Map.lookup (String.Lower.fromString $ headerName @a)
# liftMaybe ExtractNext
runParser value (headerValueParser @a)
# bimap (ExtractBadRequest <<< Array.intercalate "\n" <<< parseErrorHuman value 5) Header
# liftEither
instance RequestParts HeaderMap where
extractRequestParts r = runExceptT $ pure $ HeaderMap $ Request.headers r
instance (PathParts a b, DiscardTupledUnits b c) => RequestParts (Path a c) where instance (PathParts a b, DiscardTupledUnits b c) => RequestParts (Path a c) where
extractRequestParts r = extractRequestParts r =
@ -98,16 +112,14 @@ instance (PathParts a b, DiscardTupledUnits b c) => RequestParts (Path a c) wher
URL.PathRelative a -> a URL.PathRelative a -> a
_ -> [] _ -> []
extract = extractPathParts @a @b (Request.url r) extract = extractPathParts @a @b (Request.url r)
ensureConsumed (leftover /\ x) = guard (Array.null leftover) $> x ensureConsumed (leftover /\ x) = when (not $ Array.null leftover) (throwError ExtractNext) $> x
in in
segments segments
# extract # extract
# Right # note ExtractNext
# MaybeT
>>= ensureConsumed >>= ensureConsumed
<#> discardTupledUnits <#> discardTupledUnits
<#> Path <#> Path
# runMaybeT
# pure # pure
instance (DecodeJson a) => RequestParts (Json a) where instance (DecodeJson a) => RequestParts (Json a) where
@ -115,39 +127,26 @@ instance (DecodeJson a) => RequestParts (Json a) where
let let
jsonBody = jsonBody =
Request.bodyJSON r Request.bodyJSON r
<#> lmap (const $ Response.fromStatus 500) <#> lmap (ExtractBadRequest <<< show)
# ExceptT # ExceptT
# lift
decode j = decode j =
decodeJson j decodeJson j
# lmap (const $ Response.fromStatus 400) # lmap (ExtractBadRequest <<< printJsonDecodeError)
# pure # pure
# ExceptT # ExceptT
# lift
in in
jsonBody >>= decode <#> Json # runMaybeT # runExceptT jsonBody >>= decode <#> Json # runExceptT
instance RequestParts Buffer where instance RequestParts Buffer where
extractRequestParts r = extractRequestParts r =
let Request.bodyBuffer r
bufBody = <#> lmap (const $ ExtractBadRequest "Expected body")
Request.bodyBuffer r
<#> lmap (const $ Response.fromStatus 500)
# ExceptT
# lift
in
bufBody # runMaybeT # runExceptT
instance RequestParts Stream where instance RequestParts Stream where
extractRequestParts r = extractRequestParts r =
let Request.bodyReadable r
streamBody = <#> bimap (const $ ExtractBadRequest "Expected body") Stream
Request.bodyReadable r # liftEffect
<#> lmap (const $ Response.fromStatus 500)
# ExceptT
# lift
in
streamBody <#> Stream # runMaybeT # runExceptT # liftEffect
instance RequestParts Get where instance RequestParts Get where
extractRequestParts = extractMethod Get Method.GET extractRequestParts = extractMethod Get Method.GET
@ -174,7 +173,7 @@ instance RequestParts Trace where
extractRequestParts = extractMethod Trace Method.TRACE extractRequestParts = extractMethod Trace Method.TRACE
instance (RequestParts a, RequestParts b) => RequestParts (a /\ b) where instance (RequestParts a, RequestParts b) => RequestParts (a /\ b) where
extractRequestParts r = runExceptT $ runMaybeT do extractRequestParts r = runExceptT do
a <- extractRequestParts @a r # ExceptT # MaybeT a <- extractRequestParts @a r # ExceptT
b <- extractRequestParts @b r # ExceptT # MaybeT b <- extractRequestParts @b r # ExceptT
pure $ a /\ b pure $ a /\ b

View File

@ -0,0 +1,22 @@
module Axon.Request.Parts.Header where
import Prelude
import Data.Generic.Rep (class Generic)
import Data.Map (Map)
import Data.Newtype (class Newtype)
import Data.String.Lower (StringLower)
newtype Header a = Header a
derive instance Generic (Header a) _
derive instance Newtype (Header a) _
derive newtype instance (Eq a) => Eq (Header a)
derive newtype instance (Ord a) => Ord (Header a)
derive newtype instance (Show a) => Show (Header a)
newtype HeaderMap = HeaderMap (Map StringLower String)
derive instance Generic HeaderMap _
derive instance Newtype HeaderMap _
derive newtype instance Eq HeaderMap
derive newtype instance Ord HeaderMap
derive newtype instance Show HeaderMap

View File

@ -4,8 +4,6 @@ import Prelude
import Data.Argonaut.Core (Json, stringify) import Data.Argonaut.Core (Json, stringify)
import Effect (Effect) import Effect (Effect)
import Effect.Aff.HTTP.Form (Form, RawFormData) as HTTP
import Effect.Aff.HTTP.Form as HTTP.Form
import Node.Buffer (Buffer) import Node.Buffer (Buffer)
import Node.Stream as Stream import Node.Stream as Stream
@ -13,19 +11,14 @@ data Body
= BodyEmpty = BodyEmpty
| BodyString String | BodyString String
| BodyBuffer Buffer | BodyBuffer Buffer
| BodyFormData HTTP.RawFormData
| BodyReadable (Stream.Readable ()) | BodyReadable (Stream.Readable ())
instance Show Body where instance Show Body where
show BodyEmpty = "BodyEmpty" show BodyEmpty = "BodyEmpty"
show (BodyString s) = "BodyString " <> show s show (BodyString s) = "BodyString " <> show s
show (BodyBuffer _) = "BodyBuffer _" show (BodyBuffer _) = "BodyBuffer _"
show (BodyFormData _) = "BodyFormData _"
show (BodyReadable _) = "BodyReadable _" show (BodyReadable _) = "BodyReadable _"
formBody :: HTTP.Form -> Effect Body
formBody f = HTTP.Form.toRawFormData f <#> BodyFormData
stringBody :: String -> Body stringBody :: String -> Body
stringBody = BodyString stringBody = BodyString

View File

@ -15,7 +15,7 @@ module Axon.Response
import Prelude import Prelude
import Axon.Response.Body (Body(..)) import Axon.Response.Body (Body(..))
import Axon.Response.Body (Body(..), formBody) as Body import Axon.Response.Body (Body(..)) as Body
import Data.FoldableWithIndex (foldlWithIndex) import Data.FoldableWithIndex (foldlWithIndex)
import Data.Generic.Rep (class Generic) import Data.Generic.Rep (class Generic)
import Data.Map (Map) import Data.Map (Map)

165
src/Data.MIME.purs Normal file
View File

@ -0,0 +1,165 @@
module Data.MIME where
import Prelude
import Data.Eq.Generic (genericEq)
import Data.Generic.Rep (class Generic)
import Data.Show.Generic (genericShow)
data MIME = Other String | Aac | Abw | Arc | Avif | Avi | Azw | Bin | Bmp | Bz | Bz2 | Cda | Csh | Css | Csv | Doc | Docx | Eot | Epub | Gz | Gif | Html | Ico | Ics | Jar | Jpeg | Js | Json | Jsonld | Midi | Mp3 | Mp4 | Mpeg | Mpkg | Odp | Ods | Odt | Oga | Ogv | Ogx | Opus | Otf | Png | Pdf | Php | Ppt | Pptx | Rar | Rtf | Sh | Svg | Tar | Tif | Ts | Ttf | Txt | Vsd | Wav | Weba | Webm | Webp | Woff | Woff2 | Xhtml | Xls | Xlsx | Xml | Xul | Zip | Video3gp | Video3g2 | Archive7z
derive instance Generic MIME _
instance Show MIME where
show = genericShow
instance Eq MIME where
eq = genericEq
toString :: MIME -> String
toString (Other s) = s
toString Aac = "audio/aac"
toString Abw = "application/x-abiword"
toString Arc = "application/x-freearc"
toString Avif = "image/avif"
toString Avi = "video/x-msvideo"
toString Azw = "application/vnd.amazon.ebook"
toString Bin = "application/octet-stream"
toString Bmp = "image/bmp"
toString Bz = "application/x-bzip"
toString Bz2 = "application/x-bzip2"
toString Cda = "application/x-cdf"
toString Csh = "application/x-csh"
toString Css = "text/css"
toString Csv = "text/csv"
toString Doc = "application/msword"
toString Docx = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
toString Eot = "application/vnd.ms-fontobject"
toString Epub = "application/epub+zip"
toString Gz = "application/gzip"
toString Gif = "image/gif"
toString Html = "text/html"
toString Ico = "image/vnd.microsoft.icon"
toString Ics = "text/calendar"
toString Jar = "application/java-archive"
toString Jpeg = "image/jpeg"
toString Js = "text/javascript"
toString Json = "application/json"
toString Jsonld = "application/ld+json"
toString Midi = "audio/midi"
toString Mp3 = "audio/mpeg"
toString Mp4 = "video/mp4"
toString Mpeg = "video/mpeg"
toString Mpkg = "application/vnd.apple.installer+xml"
toString Odp = "application/vnd.oasis.opendocument.presentation"
toString Ods = "application/vnd.oasis.opendocument.spreadsheet"
toString Odt = "application/vnd.oasis.opendocument.text"
toString Oga = "audio/ogg"
toString Ogv = "video/ogg"
toString Ogx = "application/ogg"
toString Opus = "audio/opus"
toString Otf = "font/otf"
toString Png = "image/png"
toString Pdf = "application/pdf"
toString Php = "application/x-httpd-php"
toString Ppt = "application/vnd.ms-powerpoint"
toString Pptx = "application/vnd.openxmlformats-officedocument.presentationml.presentation"
toString Rar = "application/vnd.rar"
toString Rtf = "application/rtf"
toString Sh = "application/x-sh"
toString Svg = "image/svg+xml"
toString Tar = "application/x-tar"
toString Tif = "image/tiff"
toString Ts = "video/mp2t"
toString Ttf = "font/ttf"
toString Txt = "text/plain"
toString Vsd = "application/vnd.visio"
toString Wav = "audio/wav"
toString Weba = "audio/webm"
toString Webm = "video/webm"
toString Webp = "image/webp"
toString Woff = "font/woff"
toString Woff2 = "font/woff2"
toString Xhtml = "application/xhtml+xml"
toString Xls = "application/vnd.ms-excel"
toString Xlsx = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
toString Xml = "application/xml"
toString Xul = "application/vnd.mozilla.xul+xml"
toString Zip = "application/zip"
toString Video3gp = "video/3gpp"
toString Video3g2 = "video/3gpp2"
toString Archive7z = "application/x-7z-compressed"
fromString :: String -> MIME
fromString "audio/aac" = Aac
fromString "application/x-abiword" = Abw
fromString "application/x-freearc" = Arc
fromString "image/avif" = Avif
fromString "video/x-msvideo" = Avi
fromString "application/vnd.amazon.ebook" = Azw
fromString "application/octet-stream" = Bin
fromString "image/bmp" = Bmp
fromString "application/x-bzip" = Bz
fromString "application/x-bzip2" = Bz2
fromString "application/x-cdf" = Cda
fromString "application/x-csh" = Csh
fromString "text/css" = Css
fromString "text/csv" = Csv
fromString "application/msword" = Doc
fromString "application/vnd.openxmlformats-officedocument.wordprocessingml.document" = Docx
fromString "application/vnd.ms-fontobject" = Eot
fromString "application/epub+zip" = Epub
fromString "application/gzip" = Gz
fromString "image/gif" = Gif
fromString "text/html" = Html
fromString "image/vnd.microsoft.icon" = Ico
fromString "text/calendar" = Ics
fromString "application/java-archive" = Jar
fromString "image/jpeg" = Jpeg
fromString "text/javascript" = Js
fromString "application/json" = Json
fromString "application/ld+json" = Jsonld
fromString "audio/midi" = Midi
fromString "audio/mpeg" = Mp3
fromString "video/mp4" = Mp4
fromString "video/mpeg" = Mpeg
fromString "application/vnd.apple.installer+xml" = Mpkg
fromString "application/vnd.oasis.opendocument.presentation" = Odp
fromString "application/vnd.oasis.opendocument.spreadsheet" = Ods
fromString "application/vnd.oasis.opendocument.text" = Odt
fromString "audio/ogg" = Oga
fromString "video/ogg" = Ogv
fromString "application/ogg" = Ogx
fromString "audio/opus" = Opus
fromString "font/otf" = Otf
fromString "image/png" = Png
fromString "application/pdf" = Pdf
fromString "application/x-httpd-php" = Php
fromString "application/vnd.ms-powerpoint" = Ppt
fromString "application/vnd.openxmlformats-officedocument.presentationml.presentation" = Pptx
fromString "application/vnd.rar" = Rar
fromString "application/rtf" = Rtf
fromString "application/x-sh" = Sh
fromString "image/svg+xml" = Svg
fromString "application/x-tar" = Tar
fromString "image/tiff" = Tif
fromString "video/mp2t" = Ts
fromString "font/ttf" = Ttf
fromString "text/plain" = Txt
fromString "application/vnd.visio" = Vsd
fromString "audio/wav" = Wav
fromString "audio/webm" = Weba
fromString "video/webm" = Webm
fromString "image/webp" = Webp
fromString "font/woff" = Woff
fromString "font/woff2" = Woff2
fromString "application/xhtml+xml" = Xhtml
fromString "application/vnd.ms-excel" = Xls
fromString "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" = Xlsx
fromString "application/xml" = Xml
fromString "application/vnd.mozilla.xul+xml" = Xul
fromString "application/zip" = Zip
fromString "video/3gpp" = Video3gp
fromString "video/3gpp2" = Video3g2
fromString "application/x-7z-compressed" = Archive7z
fromString s = Other s

View File

@ -301,16 +301,6 @@ instance TypelevelMIME Midi where
fromValue _ = Nothing fromValue _ = Nothing
value = MIME.Midi value = MIME.Midi
data Mjs = Mjs
derive instance Generic Mjs _
derive instance Eq Mjs
instance Show Mjs where
show = genericShow
instance TypelevelMIME Mjs where
fromValue MIME.Mjs = Just Mjs
fromValue _ = Nothing
value = MIME.Mjs
data Mp3 = Mp3 data Mp3 = Mp3
derive instance Generic Mp3 _ derive instance Generic Mp3 _
derive instance Eq Mp3 derive instance Eq Mp3

View File

@ -0,0 +1,618 @@
module Test.Axon.Header.Typed where
import Prelude
import Axon.Header.Typed (class TypedHeader, Accept(..), AccessControlAllowCredentials(..), AccessControlAllowHeaders(..), AccessControlAllowMethods(..), AccessControlAllowOrigin(..), AccessControlExposeHeaders(..), AccessControlMaxAge(..), AccessControlRequestHeaders(..), AccessControlRequestMethod(..), Age(..), Allow(..), AuthScheme(..), Authorization(..), BasicAuth(..), BearerAuth(..), CacheControl(..), Connection(..), ConnectionClose(..), ContentDisposition(..), ContentDispositionAttachment(..), ContentDispositionFormData(..), ContentDispositionInline(..), ContentEncoding(..), ContentLength(..), ContentType(..), Wildcard(..), cacheControlDefaults, headerValueParser)
import Axon.Request.Method (Method(..))
import Control.Monad.Error.Class (liftEither)
import Data.Bifunctor (lmap)
import Data.Either (Either(..), isLeft)
import Data.Either.Nested as Either.Nested
import Data.MIME as MIME
import Data.Maybe (Maybe(..))
import Data.String.Lower as String.Lower
import Effect.Exception (error)
import Parsing (parseErrorMessage, runParser)
import Test.Spec (Spec, describe, it)
import Test.Spec.Assertions (shouldEqual, shouldNotEqual)
import Type.MIME as Type.MIME
is :: forall h. Eq h => Show h => TypedHeader h => String -> h -> Spec Unit
is i exp = it ("parses " <> show i) do
act <- runParser i (headerValueParser @h) # lmap (error <<< parseErrorMessage) # liftEither
act `shouldEqual` exp
isnt :: forall h. Eq h => Show h => TypedHeader h => String -> h -> Spec Unit
isnt i exp = it ("does not parse " <> show i) $
case runParser i (headerValueParser @h) of
Left _ -> pure unit
Right act -> exp `shouldNotEqual` act
spec :: Spec Unit
spec =
describe "Typed" do
describe "Accept String" do
"foo" `is` (Accept "foo")
"" `is` (Accept "")
describe "Accept MIME.MIME" do
"application/json" `is` (Accept MIME.Json)
"text/plain" `is` (Accept MIME.Txt)
"text/plain;charset=utf8" `is` (Accept $ MIME.Other "text/plain;charset=utf8")
"foo" `is` (Accept $ MIME.Other "foo")
describe "Accept Aac" do
"unknown" `isnt` Accept Type.MIME.Aac
"audio/aac" `is` Accept Type.MIME.Aac
describe "Accept Abw" do
"unknown" `isnt` Accept Type.MIME.Abw
"application/x-abiword" `is` Accept Type.MIME.Abw
describe "Accept Arc" do
"unknown" `isnt` Accept Type.MIME.Arc
"application/x-freearc" `is` Accept Type.MIME.Arc
describe "Accept Avif" do
"unknown" `isnt` Accept Type.MIME.Avif
"image/avif" `is` Accept Type.MIME.Avif
describe "Accept Avi" do
"unknown" `isnt` Accept Type.MIME.Avi
"video/x-msvideo" `is` Accept Type.MIME.Avi
describe "Accept Azw" do
"unknown" `isnt` Accept Type.MIME.Azw
"application/vnd.amazon.ebook" `is` Accept Type.MIME.Azw
describe "Accept Bin" do
"unknown" `isnt` Accept Type.MIME.Bin
"application/octet-stream" `is` Accept Type.MIME.Bin
describe "Accept Bmp" do
"unknown" `isnt` Accept Type.MIME.Bmp
"image/bmp" `is` Accept Type.MIME.Bmp
describe "Accept Bz" do
"unknown" `isnt` Accept Type.MIME.Bz
"application/x-bzip" `is` Accept Type.MIME.Bz
describe "Accept Bz2" do
"unknown" `isnt` Accept Type.MIME.Bz2
"application/x-bzip2" `is` Accept Type.MIME.Bz2
describe "Accept Cda" do
"unknown" `isnt` Accept Type.MIME.Cda
"application/x-cdf" `is` Accept Type.MIME.Cda
describe "Accept Csh" do
"unknown" `isnt` Accept Type.MIME.Csh
"application/x-csh" `is` Accept Type.MIME.Csh
describe "Accept Css" do
"unknown" `isnt` Accept Type.MIME.Css
"text/css" `is` Accept Type.MIME.Css
describe "Accept Csv" do
"unknown" `isnt` Accept Type.MIME.Csv
"text/csv" `is` Accept Type.MIME.Csv
describe "Accept Doc" do
"unknown" `isnt` Accept Type.MIME.Doc
"application/msword" `is` Accept Type.MIME.Doc
describe "Accept Docx" do
"unknown" `isnt` Accept Type.MIME.Docx
"application/vnd.openxmlformats-officedocument.wordprocessingml.document" `is` Accept Type.MIME.Docx
describe "Accept Eot" do
"unknown" `isnt` Accept Type.MIME.Eot
"application/vnd.ms-fontobject" `is` Accept Type.MIME.Eot
describe "Accept Epub" do
"unknown" `isnt` Accept Type.MIME.Epub
"application/epub+zip" `is` Accept Type.MIME.Epub
describe "Accept Gz" do
"unknown" `isnt` Accept Type.MIME.Gz
"application/gzip" `is` Accept Type.MIME.Gz
describe "Accept Gif" do
"unknown" `isnt` Accept Type.MIME.Gif
"image/gif" `is` Accept Type.MIME.Gif
describe "Accept Html" do
"unknown" `isnt` Accept Type.MIME.Html
"text/html" `is` Accept Type.MIME.Html
describe "Accept Ico" do
"unknown" `isnt` Accept Type.MIME.Ico
"image/vnd.microsoft.icon" `is` Accept Type.MIME.Ico
describe "Accept Ics" do
"unknown" `isnt` Accept Type.MIME.Ics
"text/calendar" `is` Accept Type.MIME.Ics
describe "Accept Jar" do
"unknown" `isnt` Accept Type.MIME.Jar
"application/java-archive" `is` Accept Type.MIME.Jar
describe "Accept Jpeg" do
"unknown" `isnt` Accept Type.MIME.Jpeg
"image/jpeg" `is` Accept Type.MIME.Jpeg
describe "Accept Js" do
"unknown" `isnt` Accept Type.MIME.Js
"text/javascript" `is` Accept Type.MIME.Js
describe "Accept Json" do
"unknown" `isnt` Accept Type.MIME.Json
"application/json" `is` Accept Type.MIME.Json
describe "Accept Jsonld" do
"unknown" `isnt` Accept Type.MIME.Jsonld
"application/ld+json" `is` Accept Type.MIME.Jsonld
describe "Accept Midi" do
"unknown" `isnt` Accept Type.MIME.Midi
"audio/midi" `is` Accept Type.MIME.Midi
describe "Accept Mp3" do
"unknown" `isnt` Accept Type.MIME.Mp3
"audio/mpeg" `is` Accept Type.MIME.Mp3
describe "Accept Mp4" do
"unknown" `isnt` Accept Type.MIME.Mp4
"video/mp4" `is` Accept Type.MIME.Mp4
describe "Accept Mpeg" do
"unknown" `isnt` Accept Type.MIME.Mpeg
"video/mpeg" `is` Accept Type.MIME.Mpeg
describe "Accept Mpkg" do
"unknown" `isnt` Accept Type.MIME.Mpkg
"application/vnd.apple.installer+xml" `is` Accept Type.MIME.Mpkg
describe "Accept Odp" do
"unknown" `isnt` Accept Type.MIME.Odp
"application/vnd.oasis.opendocument.presentation" `is` Accept Type.MIME.Odp
describe "Accept Ods" do
"unknown" `isnt` Accept Type.MIME.Ods
"application/vnd.oasis.opendocument.spreadsheet" `is` Accept Type.MIME.Ods
describe "Accept Odt" do
"unknown" `isnt` Accept Type.MIME.Odt
"application/vnd.oasis.opendocument.text" `is` Accept Type.MIME.Odt
describe "Accept Oga" do
"unknown" `isnt` Accept Type.MIME.Oga
"audio/ogg" `is` Accept Type.MIME.Oga
describe "Accept Ogv" do
"unknown" `isnt` Accept Type.MIME.Ogv
"video/ogg" `is` Accept Type.MIME.Ogv
describe "Accept Ogx" do
"unknown" `isnt` Accept Type.MIME.Ogx
"application/ogg" `is` Accept Type.MIME.Ogx
describe "Accept Opus" do
"unknown" `isnt` Accept Type.MIME.Opus
"audio/opus" `is` Accept Type.MIME.Opus
describe "Accept Otf" do
"unknown" `isnt` Accept Type.MIME.Otf
"font/otf" `is` Accept Type.MIME.Otf
describe "Accept Png" do
"unknown" `isnt` Accept Type.MIME.Png
"image/png" `is` Accept Type.MIME.Png
describe "Accept Pdf" do
"unknown" `isnt` Accept Type.MIME.Pdf
"application/pdf" `is` Accept Type.MIME.Pdf
describe "Accept Php" do
"unknown" `isnt` Accept Type.MIME.Php
"application/x-httpd-php" `is` Accept Type.MIME.Php
describe "Accept Ppt" do
"unknown" `isnt` Accept Type.MIME.Ppt
"application/vnd.ms-powerpoint" `is` Accept Type.MIME.Ppt
describe "Accept Pptx" do
"unknown" `isnt` Accept Type.MIME.Pptx
"application/vnd.openxmlformats-officedocument.presentationml.presentation" `is` Accept Type.MIME.Pptx
describe "Accept Rar" do
"unknown" `isnt` Accept Type.MIME.Rar
"application/vnd.rar" `is` Accept Type.MIME.Rar
describe "Accept Rtf" do
"unknown" `isnt` Accept Type.MIME.Rtf
"application/rtf" `is` Accept Type.MIME.Rtf
describe "Accept Sh" do
"unknown" `isnt` Accept Type.MIME.Sh
"application/x-sh" `is` Accept Type.MIME.Sh
describe "Accept Svg" do
"unknown" `isnt` Accept Type.MIME.Svg
"image/svg+xml" `is` Accept Type.MIME.Svg
describe "Accept Tar" do
"unknown" `isnt` Accept Type.MIME.Tar
"application/x-tar" `is` Accept Type.MIME.Tar
describe "Accept Tif" do
"unknown" `isnt` Accept Type.MIME.Tif
"image/tiff" `is` Accept Type.MIME.Tif
describe "Accept Ts" do
"unknown" `isnt` Accept Type.MIME.Ts
"video/mp2t" `is` Accept Type.MIME.Ts
describe "Accept Ttf" do
"unknown" `isnt` Accept Type.MIME.Ttf
"font/ttf" `is` Accept Type.MIME.Ttf
describe "Accept Txt" do
"unknown" `isnt` Accept Type.MIME.Txt
"text/plain" `is` Accept Type.MIME.Txt
describe "Accept Vsd" do
"unknown" `isnt` Accept Type.MIME.Vsd
"application/vnd.visio" `is` Accept Type.MIME.Vsd
describe "Accept Wav" do
"unknown" `isnt` Accept Type.MIME.Wav
"audio/wav" `is` Accept Type.MIME.Wav
describe "Accept Weba" do
"unknown" `isnt` Accept Type.MIME.Weba
"audio/webm" `is` Accept Type.MIME.Weba
describe "Accept Webm" do
"unknown" `isnt` Accept Type.MIME.Webm
"video/webm" `is` Accept Type.MIME.Webm
describe "Accept Webp" do
"unknown" `isnt` Accept Type.MIME.Webp
"image/webp" `is` Accept Type.MIME.Webp
describe "Accept Woff" do
"unknown" `isnt` Accept Type.MIME.Woff
"font/woff" `is` Accept Type.MIME.Woff
describe "Accept Woff2" do
"unknown" `isnt` Accept Type.MIME.Woff2
"font/woff2" `is` Accept Type.MIME.Woff2
describe "Accept Xhtml" do
"unknown" `isnt` Accept Type.MIME.Xhtml
"application/xhtml+xml" `is` Accept Type.MIME.Xhtml
describe "Accept Xls" do
"unknown" `isnt` Accept Type.MIME.Xls
"application/vnd.ms-excel" `is` Accept Type.MIME.Xls
describe "Accept Xlsx" do
"unknown" `isnt` Accept Type.MIME.Xlsx
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" `is` Accept Type.MIME.Xlsx
describe "Accept Xml" do
"unknown" `isnt` Accept Type.MIME.Xml
"application/xml" `is` Accept Type.MIME.Xml
describe "Accept Xul" do
"unknown" `isnt` Accept Type.MIME.Xul
"application/vnd.mozilla.xul+xml" `is` Accept Type.MIME.Xul
describe "Accept Zip" do
"unknown" `isnt` Accept Type.MIME.Zip
"application/zip" `is` Accept Type.MIME.Zip
describe "Accept Video3gp" do
"unknown" `isnt` Accept Type.MIME.Video3gp
"video/3gpp" `is` Accept Type.MIME.Video3gp
describe "Accept Video3g2" do
"unknown" `isnt` Accept Type.MIME.Video3g2
"video/3gpp2" `is` Accept Type.MIME.Video3g2
describe "Accept Archive7z" do
"unknown" `isnt` Accept Type.MIME.Archive7z
"application/x-7z-compressed" `is` Accept Type.MIME.Archive7z
describe "ContentType String" do
"foo" `is` (ContentType "foo")
"" `is` (ContentType "")
describe "ContentType MIME.MIME" do
"application/json" `is` (ContentType MIME.Json)
"text/plain" `is` (ContentType MIME.Txt)
"text/plain;charset=utf8" `is` (ContentType $ MIME.Other "text/plain;charset=utf8")
"foo" `is` (ContentType $ MIME.Other "foo")
describe "ContentType Aac" do
"unknown" `isnt` ContentType Type.MIME.Aac
"audio/aac" `is` ContentType Type.MIME.Aac
describe "ContentType Abw" do
"unknown" `isnt` ContentType Type.MIME.Abw
"application/x-abiword" `is` ContentType Type.MIME.Abw
describe "ContentType Arc" do
"unknown" `isnt` ContentType Type.MIME.Arc
"application/x-freearc" `is` ContentType Type.MIME.Arc
describe "ContentType Avif" do
"unknown" `isnt` ContentType Type.MIME.Avif
"image/avif" `is` ContentType Type.MIME.Avif
describe "ContentType Avi" do
"unknown" `isnt` ContentType Type.MIME.Avi
"video/x-msvideo" `is` ContentType Type.MIME.Avi
describe "ContentType Azw" do
"unknown" `isnt` ContentType Type.MIME.Azw
"application/vnd.amazon.ebook" `is` ContentType Type.MIME.Azw
describe "ContentType Bin" do
"unknown" `isnt` ContentType Type.MIME.Bin
"application/octet-stream" `is` ContentType Type.MIME.Bin
describe "ContentType Bmp" do
"unknown" `isnt` ContentType Type.MIME.Bmp
"image/bmp" `is` ContentType Type.MIME.Bmp
describe "ContentType Bz" do
"unknown" `isnt` ContentType Type.MIME.Bz
"application/x-bzip" `is` ContentType Type.MIME.Bz
describe "ContentType Bz2" do
"unknown" `isnt` ContentType Type.MIME.Bz2
"application/x-bzip2" `is` ContentType Type.MIME.Bz2
describe "ContentType Cda" do
"unknown" `isnt` ContentType Type.MIME.Cda
"application/x-cdf" `is` ContentType Type.MIME.Cda
describe "ContentType Csh" do
"unknown" `isnt` ContentType Type.MIME.Csh
"application/x-csh" `is` ContentType Type.MIME.Csh
describe "ContentType Css" do
"unknown" `isnt` ContentType Type.MIME.Css
"text/css" `is` ContentType Type.MIME.Css
describe "ContentType Csv" do
"unknown" `isnt` ContentType Type.MIME.Csv
"text/csv" `is` ContentType Type.MIME.Csv
describe "ContentType Doc" do
"unknown" `isnt` ContentType Type.MIME.Doc
"application/msword" `is` ContentType Type.MIME.Doc
describe "ContentType Docx" do
"unknown" `isnt` ContentType Type.MIME.Docx
"application/vnd.openxmlformats-officedocument.wordprocessingml.document" `is` ContentType Type.MIME.Docx
describe "ContentType Eot" do
"unknown" `isnt` ContentType Type.MIME.Eot
"application/vnd.ms-fontobject" `is` ContentType Type.MIME.Eot
describe "ContentType Epub" do
"unknown" `isnt` ContentType Type.MIME.Epub
"application/epub+zip" `is` ContentType Type.MIME.Epub
describe "ContentType Gz" do
"unknown" `isnt` ContentType Type.MIME.Gz
"application/gzip" `is` ContentType Type.MIME.Gz
describe "ContentType Gif" do
"unknown" `isnt` ContentType Type.MIME.Gif
"image/gif" `is` ContentType Type.MIME.Gif
describe "ContentType Html" do
"unknown" `isnt` ContentType Type.MIME.Html
"text/html" `is` ContentType Type.MIME.Html
describe "ContentType Ico" do
"unknown" `isnt` ContentType Type.MIME.Ico
"image/vnd.microsoft.icon" `is` ContentType Type.MIME.Ico
describe "ContentType Ics" do
"unknown" `isnt` ContentType Type.MIME.Ics
"text/calendar" `is` ContentType Type.MIME.Ics
describe "ContentType Jar" do
"unknown" `isnt` ContentType Type.MIME.Jar
"application/java-archive" `is` ContentType Type.MIME.Jar
describe "ContentType Jpeg" do
"unknown" `isnt` ContentType Type.MIME.Jpeg
"image/jpeg" `is` ContentType Type.MIME.Jpeg
describe "ContentType Js" do
"unknown" `isnt` ContentType Type.MIME.Js
"text/javascript" `is` ContentType Type.MIME.Js
describe "ContentType Json" do
"unknown" `isnt` ContentType Type.MIME.Json
"application/json" `is` ContentType Type.MIME.Json
describe "ContentType Jsonld" do
"unknown" `isnt` ContentType Type.MIME.Jsonld
"application/ld+json" `is` ContentType Type.MIME.Jsonld
describe "ContentType Midi" do
"unknown" `isnt` ContentType Type.MIME.Midi
"audio/midi" `is` ContentType Type.MIME.Midi
describe "ContentType Mp3" do
"unknown" `isnt` ContentType Type.MIME.Mp3
"audio/mpeg" `is` ContentType Type.MIME.Mp3
describe "ContentType Mp4" do
"unknown" `isnt` ContentType Type.MIME.Mp4
"video/mp4" `is` ContentType Type.MIME.Mp4
describe "ContentType Mpeg" do
"unknown" `isnt` ContentType Type.MIME.Mpeg
"video/mpeg" `is` ContentType Type.MIME.Mpeg
describe "ContentType Mpkg" do
"unknown" `isnt` ContentType Type.MIME.Mpkg
"application/vnd.apple.installer+xml" `is` ContentType Type.MIME.Mpkg
describe "ContentType Odp" do
"unknown" `isnt` ContentType Type.MIME.Odp
"application/vnd.oasis.opendocument.presentation" `is` ContentType Type.MIME.Odp
describe "ContentType Ods" do
"unknown" `isnt` ContentType Type.MIME.Ods
"application/vnd.oasis.opendocument.spreadsheet" `is` ContentType Type.MIME.Ods
describe "ContentType Odt" do
"unknown" `isnt` ContentType Type.MIME.Odt
"application/vnd.oasis.opendocument.text" `is` ContentType Type.MIME.Odt
describe "ContentType Oga" do
"unknown" `isnt` ContentType Type.MIME.Oga
"audio/ogg" `is` ContentType Type.MIME.Oga
describe "ContentType Ogv" do
"unknown" `isnt` ContentType Type.MIME.Ogv
"video/ogg" `is` ContentType Type.MIME.Ogv
describe "ContentType Ogx" do
"unknown" `isnt` ContentType Type.MIME.Ogx
"application/ogg" `is` ContentType Type.MIME.Ogx
describe "ContentType Opus" do
"unknown" `isnt` ContentType Type.MIME.Opus
"audio/opus" `is` ContentType Type.MIME.Opus
describe "ContentType Otf" do
"unknown" `isnt` ContentType Type.MIME.Otf
"font/otf" `is` ContentType Type.MIME.Otf
describe "ContentType Png" do
"unknown" `isnt` ContentType Type.MIME.Png
"image/png" `is` ContentType Type.MIME.Png
describe "ContentType Pdf" do
"unknown" `isnt` ContentType Type.MIME.Pdf
"application/pdf" `is` ContentType Type.MIME.Pdf
describe "ContentType Php" do
"unknown" `isnt` ContentType Type.MIME.Php
"application/x-httpd-php" `is` ContentType Type.MIME.Php
describe "ContentType Ppt" do
"unknown" `isnt` ContentType Type.MIME.Ppt
"application/vnd.ms-powerpoint" `is` ContentType Type.MIME.Ppt
describe "ContentType Pptx" do
"unknown" `isnt` ContentType Type.MIME.Pptx
"application/vnd.openxmlformats-officedocument.presentationml.presentation" `is` ContentType Type.MIME.Pptx
describe "ContentType Rar" do
"unknown" `isnt` ContentType Type.MIME.Rar
"application/vnd.rar" `is` ContentType Type.MIME.Rar
describe "ContentType Rtf" do
"unknown" `isnt` ContentType Type.MIME.Rtf
"application/rtf" `is` ContentType Type.MIME.Rtf
describe "ContentType Sh" do
"unknown" `isnt` ContentType Type.MIME.Sh
"application/x-sh" `is` ContentType Type.MIME.Sh
describe "ContentType Svg" do
"unknown" `isnt` ContentType Type.MIME.Svg
"image/svg+xml" `is` ContentType Type.MIME.Svg
describe "ContentType Tar" do
"unknown" `isnt` ContentType Type.MIME.Tar
"application/x-tar" `is` ContentType Type.MIME.Tar
describe "ContentType Tif" do
"unknown" `isnt` ContentType Type.MIME.Tif
"image/tiff" `is` ContentType Type.MIME.Tif
describe "ContentType Ts" do
"unknown" `isnt` ContentType Type.MIME.Ts
"video/mp2t" `is` ContentType Type.MIME.Ts
describe "ContentType Ttf" do
"unknown" `isnt` ContentType Type.MIME.Ttf
"font/ttf" `is` ContentType Type.MIME.Ttf
describe "ContentType Txt" do
"unknown" `isnt` ContentType Type.MIME.Txt
"text/plain" `is` ContentType Type.MIME.Txt
describe "ContentType Vsd" do
"unknown" `isnt` ContentType Type.MIME.Vsd
"application/vnd.visio" `is` ContentType Type.MIME.Vsd
describe "ContentType Wav" do
"unknown" `isnt` ContentType Type.MIME.Wav
"audio/wav" `is` ContentType Type.MIME.Wav
describe "ContentType Weba" do
"unknown" `isnt` ContentType Type.MIME.Weba
"audio/webm" `is` ContentType Type.MIME.Weba
describe "ContentType Webm" do
"unknown" `isnt` ContentType Type.MIME.Webm
"video/webm" `is` ContentType Type.MIME.Webm
describe "ContentType Webp" do
"unknown" `isnt` ContentType Type.MIME.Webp
"image/webp" `is` ContentType Type.MIME.Webp
describe "ContentType Woff" do
"unknown" `isnt` ContentType Type.MIME.Woff
"font/woff" `is` ContentType Type.MIME.Woff
describe "ContentType Woff2" do
"unknown" `isnt` ContentType Type.MIME.Woff2
"font/woff2" `is` ContentType Type.MIME.Woff2
describe "ContentType Xhtml" do
"unknown" `isnt` ContentType Type.MIME.Xhtml
"application/xhtml+xml" `is` ContentType Type.MIME.Xhtml
describe "ContentType Xls" do
"unknown" `isnt` ContentType Type.MIME.Xls
"application/vnd.ms-excel" `is` ContentType Type.MIME.Xls
describe "ContentType Xlsx" do
"unknown" `isnt` ContentType Type.MIME.Xlsx
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" `is` ContentType Type.MIME.Xlsx
describe "ContentType Xml" do
"unknown" `isnt` ContentType Type.MIME.Xml
"application/xml" `is` ContentType Type.MIME.Xml
describe "ContentType Xul" do
"unknown" `isnt` ContentType Type.MIME.Xul
"application/vnd.mozilla.xul+xml" `is` ContentType Type.MIME.Xul
describe "ContentType Zip" do
"unknown" `isnt` ContentType Type.MIME.Zip
"application/zip" `is` ContentType Type.MIME.Zip
describe "ContentType Video3gp" do
"unknown" `isnt` ContentType Type.MIME.Video3gp
"video/3gpp" `is` ContentType Type.MIME.Video3gp
describe "ContentType Video3g2" do
"unknown" `isnt` ContentType Type.MIME.Video3g2
"video/3gpp2" `is` ContentType Type.MIME.Video3g2
describe "ContentType Archive7z" do
"unknown" `isnt` ContentType Type.MIME.Archive7z
"application/x-7z-compressed" `is` ContentType Type.MIME.Archive7z
describe "AccessControlAllowCredentials" do
"true" `is` AccessControlAllowCredentials
"" `isnt` AccessControlAllowCredentials
"false" `isnt` AccessControlAllowCredentials
describe "AccessControlAllowHeaders" do
"*" `is` AccessControlAllowHeaders (Left Wildcard)
" * " `is` AccessControlAllowHeaders (Left Wildcard)
"* " `is` AccessControlAllowHeaders (Left Wildcard)
"Vary" `is` AccessControlAllowHeaders (Right $ pure $ String.Lower.fromString "Vary")
" Vary" `is` AccessControlAllowHeaders (Right $ pure $ String.Lower.fromString "Vary")
" Vary " `is` AccessControlAllowHeaders (Right $ pure $ String.Lower.fromString "Vary")
"Accept, Vary, Content-Type" `is` AccessControlAllowHeaders (Right $ (pure "Accept" <> pure "Vary" <> pure "Content-Type") <#> String.Lower.fromString)
describe "AccessControlAllowMethods" do
"*" `is` AccessControlAllowMethods (Left Wildcard)
" * " `is` AccessControlAllowMethods (Left Wildcard)
"* " `is` AccessControlAllowMethods (Left Wildcard)
"GET" `is` AccessControlAllowMethods (Right $ pure GET)
"get" `is` AccessControlAllowMethods (Right $ pure GET)
"GET, PATCH" `is` AccessControlAllowMethods (Right $ pure GET <> pure PATCH)
" GET , PATCH " `is` AccessControlAllowMethods (Right $ pure GET <> pure PATCH)
describe "AccessControlAllowOrigin" do
"*" `is` AccessControlAllowOrigin (Left Wildcard)
" * " `is` AccessControlAllowOrigin (Left Wildcard)
"* " `is` AccessControlAllowOrigin (Left Wildcard)
"foo" `is` AccessControlAllowOrigin (Right "foo")
" foo " `is` AccessControlAllowOrigin (Right "foo")
"https://example.com" `is` AccessControlAllowOrigin (Right "https://example.com")
describe "AccessControlExposeHeaders" do
"*" `is` AccessControlExposeHeaders (Left Wildcard)
" * " `is` AccessControlExposeHeaders (Left Wildcard)
"* " `is` AccessControlExposeHeaders (Left Wildcard)
"Vary" `is` AccessControlExposeHeaders (Right $ pure $ String.Lower.fromString "Vary")
" Vary" `is` AccessControlExposeHeaders (Right $ pure $ String.Lower.fromString "Vary")
" Vary " `is` AccessControlExposeHeaders (Right $ pure $ String.Lower.fromString "Vary")
"Accept, Vary, Content-Type" `is` AccessControlExposeHeaders (Right $ (pure "Accept" <> pure "Vary" <> pure "Content-Type") <#> String.Lower.fromString)
describe "AccessControlMaxAge" do
" 123 " `is` AccessControlMaxAge 123
" 0" `is` AccessControlMaxAge 0
"23190" `is` AccessControlMaxAge 23190
describe "AccessControlRequestHeaders" do
"Vary" `is` AccessControlRequestHeaders (pure $ String.Lower.fromString "Vary")
" Vary" `is` AccessControlRequestHeaders (pure $ String.Lower.fromString "Vary")
" Vary " `is` AccessControlRequestHeaders (pure $ String.Lower.fromString "Vary")
"Accept, Vary, Content-Type" `is` AccessControlRequestHeaders ((pure "Accept" <> pure "Vary" <> pure "Content-Type") <#> String.Lower.fromString)
describe "AccessControlRequestMethod" do
"GET" `is` AccessControlRequestMethod GET
"get" `is` AccessControlRequestMethod GET
" patCh " `is` AccessControlRequestMethod PATCH
describe "Age" do
" 123 " `is` Age 123
" 0" `is` Age 0
"23190" `is` Age 23190
describe "Allow" do
"GET" `is` Allow (pure GET)
"get" `is` Allow (pure GET)
"GET, PATCH" `is` Allow (pure GET <> pure PATCH)
" GET , PATCH " `is` Allow (pure GET <> pure PATCH)
describe "Authorization" do
"Foo bar" `is` Authorization (AuthScheme "Foo") "bar"
"Bing bar" `is` Authorization (AuthScheme "Bing") "bar"
" Bing bar " `is` Authorization (AuthScheme "Bing") "bar"
"bar" `isnt` Authorization (AuthScheme "Foo") "bar"
describe "BasicAuth" do
"Basic ZGVtbzpwQDU1dzByZA==" `is` BasicAuth {username: "demo", password: "p@55w0rd"}
"Bearer ZGVtbzpwQDU1dzByZA==" `isnt` BasicAuth {username: "demo", password: "p@55w0rd"}
"Basic foo" `isnt` BasicAuth {username: "demo", password: "p@55w0rd"}
describe "BearerAuth" do
"Bearer foo" `is` BearerAuth "foo"
"Basic foo" `isnt` BearerAuth "foo"
"Bearer foo " `is` BearerAuth "foo"
describe "CacheControl" do
"max-age=604800" `is` CacheControl (cacheControlDefaults {maxAge = Just 604800})
" max-age=604800 " `is` CacheControl (cacheControlDefaults {maxAge = Just 604800})
"max-age=604800, must-revalidate" `is` CacheControl (cacheControlDefaults {maxAge = Just 604800, mustRevalidate = true})
"max-age=20, s-maxage=10, no-cache, must-revalidate, proxy-revalidate, no-store, private, public, must-understand, no-transform, immutable, stale-while-revalidate, stale-if-error"
`is`
CacheControl (cacheControlDefaults {maxAge = Just 20, sMaxAge = Just 10, noCache = true, mustRevalidate = true, proxyRevalidate = true, noStore = true, private = true, public = true, mustUnderstand = true, noTransform = true, immutable = true, staleWhileRevalidate = true, staleIfError = true})
"" `isnt` CacheControl cacheControlDefaults
" " `isnt` CacheControl cacheControlDefaults
"foo=bar" `isnt` CacheControl cacheControlDefaults
"foo" `isnt` CacheControl cacheControlDefaults
" foo=bar " `isnt` CacheControl cacheControlDefaults
" foo " `isnt` CacheControl cacheControlDefaults
describe "Connection" do
"" `isnt` Connection (Left ConnectionClose)
" " `isnt` Connection (Left ConnectionClose)
"close" `is` Connection (Left ConnectionClose)
" close " `is` Connection (Left ConnectionClose)
" cLoSe " `is` Connection (Left ConnectionClose)
"fuaiowf" `is` Connection (Right $ pure $ String.Lower.fromString "fuaiowf")
" a , b , c,d" `is` Connection (Right $ String.Lower.fromString <$> (pure "a" <> pure "b" <> pure "c" <> pure "d"))
describe "ContentDisposition" do
"form-data" `is` ContentDisposition (Either.Nested.in3 $ ContentDispositionFormData {filename: Nothing, name: Nothing})
"form-data; name=\"foo\"" `is` ContentDisposition (Either.Nested.in3 $ ContentDispositionFormData {filename: Nothing, name: Just "foo"})
"form-data; filename=\"foo.txt\"" `is` ContentDisposition (Either.Nested.in3 $ ContentDispositionFormData {filename: Just "foo.txt", name: Nothing})
" form-data; filename=\"foo.txt\" ; name=\"foo\" " `is` ContentDisposition (Either.Nested.in3 $ ContentDispositionFormData {filename: Just "foo.txt", name: Just "foo"})
"attachment" `is` ContentDisposition (Either.Nested.in2 $ ContentDispositionAttachment {filename: Nothing})
"attachment; filename=\"foo.txt\"" `is` ContentDisposition (Either.Nested.in2 $ ContentDispositionAttachment {filename: Just "foo.txt"})
" attachment; filename=\"foo.txt\" " `is` ContentDisposition (Either.Nested.in2 $ ContentDispositionAttachment {filename: Just "foo.txt"})
"inline" `is` ContentDisposition (Either.Nested.in1 $ ContentDispositionInline)
"inline " `is` ContentDisposition (Either.Nested.in1 $ ContentDispositionInline)
" inline " `is` ContentDisposition (Either.Nested.in1 $ ContentDispositionInline)
describe "ContentEncoding" do
"gzip" `is` ContentEncoding (pure "gzip")
" gzip " `is` ContentEncoding (pure "gzip")
" gzip , deflate " `is` ContentEncoding (pure "gzip" <> pure "deflate")
describe "ContentLength" do
" 0 " `is` ContentLength 0
" 1 " `is` ContentLength 1
" 1212943817 " `is` ContentLength 1212943817
describe "ContentLocation" $ pure unit
describe "ContentRange" $ pure unit
describe "Cookie" $ pure unit
describe "Date" $ pure unit
describe "ETag" $ pure unit
describe "ExpectContinue" $ pure unit
describe "Expires" $ pure unit
describe "Host" $ pure unit
describe "IfMatch" $ pure unit
describe "IfNoneMatch" $ pure unit
describe "IfModifiedSince" $ pure unit
describe "IfRange" $ pure unit
describe "IfUnmodifiedSince" $ pure unit
describe "LastModified" $ pure unit
describe "Origin" $ pure unit
describe "ProxyAuthorization" $ pure unit
describe "Range" $ pure unit
describe "Referer" $ pure unit
describe "ReferrerPolicy" $ pure unit
describe "RetryAfter" $ pure unit
describe "SecWebsocketKey" $ pure unit
describe "SecWebsocketAccept" $ pure unit
describe "SecWebsocketVersion" $ pure unit
describe "Server" $ pure unit
describe "SetCookie" $ pure unit
describe "StrictTransportSecurity" $ pure unit
describe "TE" $ pure unit
describe "TransferEncoding" $ pure unit
describe "Upgrade" $ pure unit
describe "UserAgent" $ pure unit
describe "Vary"$ pure unit

View File

@ -0,0 +1,10 @@
module Test.Axon.Header where
import Prelude
import Test.Axon.Header.Typed as Typed
import Test.Spec (Spec, describe)
spec :: Spec Unit
spec = describe "Header" do
Typed.spec

View File

@ -2,19 +2,20 @@ module Test.Axon.Request.Parts where
import Prelude import Prelude
import Axon.Header.Typed (ContentType(..)) import Axon.Header.Typed (ContentType)
import Axon.Request (Request) import Axon.Request (Request)
import Axon.Request as Request import Axon.Request as Request
import Axon.Request.Method (Method(..)) import Axon.Request.Method (Method(..))
import Axon.Request.Parts.Class (Header(..), Json(..), Patch(..), Path(..), Post(..), extractRequestParts) import Axon.Request.Parts.Class (ExtractError(..), Header, Json(..), Patch, Path(..), Post(..), extractRequestParts, invokeHandler)
import Axon.Request.Parts.Path (type (/), IgnoreRest) import Axon.Request.Parts.Path (type (/), IgnoreRest)
import Control.Monad.Error.Class (liftEither, liftMaybe) import Control.Monad.Error.Class (liftEither)
import Data.Bifunctor (lmap) import Data.Bifunctor (lmap)
import Data.Either (Either(..)) import Data.Either (Either(..))
import Data.Map as Map import Data.Map as Map
import Data.Maybe (Maybe(..), fromJust) import Data.Maybe (fromJust)
import Data.Tuple.Nested (type (/\), (/\)) import Data.Tuple.Nested (type (/\), (/\))
import Data.URL as URL import Data.URL as URL
import Effect.Aff (Aff)
import Effect.Class (liftEffect) import Effect.Class (liftEffect)
import Effect.Exception (error) import Effect.Exception (error)
import Effect.Unsafe (unsafePerformEffect) import Effect.Unsafe (unsafePerformEffect)
@ -38,9 +39,8 @@ spec = describe "Parts" do
{ address: "127.0.0.1", port: 81 } { address: "127.0.0.1", port: 81 }
, method: GET , method: GET
} }
void $ extractRequestParts @Request req <#> lmap (error <<< show) _ :: Request <- invokeHandler req (pure @Aff) <#> lmap (error <<< show) >>= liftEither
>>= liftEither pure unit
>>= liftMaybe (error "was nothing")
it "extracts header, method, path, JSON body" do it "extracts header, method, path, JSON body" do
stream <- Buffer.fromString """{"firstName": "henry"}""" UTF8 stream <- Buffer.fromString """{"firstName": "henry"}""" UTF8
@ -55,12 +55,24 @@ spec = describe "Parts" do
{ address: "127.0.0.1", port: 81 } { address: "127.0.0.1", port: 81 }
, method: PATCH , method: PATCH
} }
a <-
extractRequestParts let
@(Patch /\ Header (ContentType MIME.Json) /\ (Path ("users" / Int) _) /\ Json { firstName :: String }) handler ::
req <#> lmap (error <<< show) >>= liftEither >>= liftMaybe Patch ->
(error "was nothing") Header (ContentType MIME.Json) ->
a `shouldEqual` (Patch /\ Header (ContentType MIME.Json) /\ Path 12 /\ Json { firstName: "henry" }) Path ("users" / Int) Int ->
Json { firstName :: String } ->
Aff String
handler _ _ (Path id) (Json {firstName}) = do
id `shouldEqual` 12
firstName `shouldEqual` "henry"
pure firstName
name <- invokeHandler req handler
<#> lmap (error <<< show)
>>= liftEither
name `shouldEqual` "henry"
describe "Path" do describe "Path" do
it "matches a route matching literal" do it "matches a route matching literal" do
@ -74,7 +86,6 @@ spec = describe "Parts" do
} }
a <- extractRequestParts @(Path "foo" _) req <#> lmap (error <<< show) a <- extractRequestParts @(Path "foo" _) req <#> lmap (error <<< show)
>>= liftEither >>= liftEither
>>= liftMaybe (error "was nothing")
a `shouldEqual` (Path unit) a `shouldEqual` (Path unit)
it "matches a route matching multiple literals" do it "matches a route matching multiple literals" do
@ -90,7 +101,6 @@ spec = describe "Parts" do
a <- extractRequestParts @(Path ("foo" / "bar" / "baz") _) req a <- extractRequestParts @(Path ("foo" / "bar" / "baz") _) req
<#> lmap (error <<< show) <#> lmap (error <<< show)
>>= liftEither >>= liftEither
>>= liftMaybe (error "was nothing")
a `shouldEqual` (Path unit) a `shouldEqual` (Path unit)
it "does not partially match a route ..." do it "does not partially match a route ..." do
@ -104,9 +114,7 @@ spec = describe "Parts" do
, method: GET , method: GET
} }
a <- extractRequestParts @(Path ("foo" / "bar") _) req a <- extractRequestParts @(Path ("foo" / "bar") _) req
<#> lmap (error <<< show) a `shouldEqual` (Left ExtractNext)
>>= liftEither
a `shouldEqual` Nothing
it "... but does if ends in IgnoreRest" do it "... but does if ends in IgnoreRest" do
req <- liftEffect $ Request.make req <- liftEffect $ Request.make
@ -121,7 +129,6 @@ spec = describe "Parts" do
a <- extractRequestParts @(Path ("foo" / "bar" / IgnoreRest) _) req a <- extractRequestParts @(Path ("foo" / "bar" / IgnoreRest) _) req
<#> lmap (error <<< show) <#> lmap (error <<< show)
>>= liftEither >>= liftEither
>>= liftMaybe (error "was nothing")
a `shouldEqual` (Path unit) a `shouldEqual` (Path unit)
it "extracts an int" do it "extracts an int" do
@ -137,7 +144,6 @@ spec = describe "Parts" do
a <- extractRequestParts @(Path ("foo" / Int / "bar") _) req a <- extractRequestParts @(Path ("foo" / Int / "bar") _) req
<#> lmap (error <<< show) <#> lmap (error <<< show)
>>= liftEither >>= liftEither
>>= liftMaybe (error "was nothing")
a `shouldEqual` (Path 123) a `shouldEqual` (Path 123)
it "extracts an int and a string" do it "extracts an int and a string" do
@ -153,7 +159,6 @@ spec = describe "Parts" do
a <- extractRequestParts @(Path ("foo" / Int / "bar" / String) _) req a <- extractRequestParts @(Path ("foo" / Int / "bar" / String) _) req
<#> lmap (error <<< show) <#> lmap (error <<< show)
>>= liftEither >>= liftEither
>>= liftMaybe (error "was nothing")
a `shouldEqual` (Path $ 123 /\ "baz") a `shouldEqual` (Path $ 123 /\ "baz")
describe "Body" do describe "Body" do
@ -169,7 +174,6 @@ spec = describe "Parts" do
a <- extractRequestParts @(Either Request.BodyStringError String) req a <- extractRequestParts @(Either Request.BodyStringError String) req
<#> lmap (error <<< show) <#> lmap (error <<< show)
>>= liftEither >>= liftEither
>>= liftMaybe (error "was nothing")
a `shouldEqual` (Right "foo") a `shouldEqual` (Right "foo")
it "extracts a string body from a readable stream" do it "extracts a string body from a readable stream" do
@ -186,12 +190,10 @@ spec = describe "Parts" do
a <- extractRequestParts @(Either Request.BodyStringError String) req a <- extractRequestParts @(Either Request.BodyStringError String) req
<#> lmap (error <<< show) <#> lmap (error <<< show)
>>= liftEither >>= liftEither
>>= liftMaybe (error "was nothing")
a `shouldEqual` (Right "foo") a `shouldEqual` (Right "foo")
a' <- extractRequestParts @String req <#> lmap (error <<< show) a' <- extractRequestParts @String req <#> lmap (error <<< show)
>>= liftEither >>= liftEither
>>= liftMaybe (error "was nothing")
a' `shouldEqual` "foo" a' `shouldEqual` "foo"
it "extracts a string body from a buffer" do it "extracts a string body from a buffer" do
@ -207,12 +209,10 @@ spec = describe "Parts" do
a <- extractRequestParts @(Either Request.BodyStringError String) req a <- extractRequestParts @(Either Request.BodyStringError String) req
<#> lmap (error <<< show) <#> lmap (error <<< show)
>>= liftEither >>= liftEither
>>= liftMaybe (error "was nothing")
a `shouldEqual` (Right "foo") a `shouldEqual` (Right "foo")
a' <- extractRequestParts @String req <#> lmap (error <<< show) a' <- extractRequestParts @String req <#> lmap (error <<< show)
>>= liftEither >>= liftEither
>>= liftMaybe (error "was nothing")
a' `shouldEqual` "foo" a' `shouldEqual` "foo"
it "extracts a JSON body" do it "extracts a JSON body" do
@ -230,5 +230,4 @@ spec = describe "Parts" do
a <- extractRequestParts @(Post /\ Json { foo :: Int, bar :: String }) req a <- extractRequestParts @(Post /\ Json { foo :: Int, bar :: String }) req
<#> lmap (error <<< show) <#> lmap (error <<< show)
>>= liftEither >>= liftEither
>>= liftMaybe (error "was nothing")
a `shouldEqual` (Post /\ Json { foo: 123, bar: "abc" }) a `shouldEqual` (Post /\ Json { foo: 123, bar: "abc" })

View File

@ -4,6 +4,7 @@ import Prelude
import Effect (Effect) import Effect (Effect)
import Test.Axon.Request as Test.Request import Test.Axon.Request as Test.Request
import Test.Axon.Header as Test.Header
import Test.Spec (describe) import Test.Spec (describe)
import Test.Spec.Reporter (specReporter) import Test.Spec.Reporter (specReporter)
import Test.Spec.Runner.Node (runSpecAndExitProcess) import Test.Spec.Runner.Node (runSpecAndExitProcess)
@ -11,3 +12,4 @@ import Test.Spec.Runner.Node (runSpecAndExitProcess)
main :: Effect Unit main :: Effect Unit
main = runSpecAndExitProcess [ specReporter ] $ describe "Axon" do main = runSpecAndExitProcess [ specReporter ] $ describe "Axon" do
Test.Request.spec Test.Request.spec
Test.Header.spec