Ketchup 0.2.2 → 0.2.3
raw patch · 83 files changed
+147/−45 lines, 83 filesbinary-addedPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
Files
- .git/COMMIT_EDITMSG +1/−1
- .git/FETCH_HEAD +2/−1
- .git/ORIG_HEAD +1/−1
- .git/index binary
- .git/logs/HEAD +5/−0
- .git/logs/refs/heads/master +5/−0
- .git/logs/refs/remotes/origin/gh-pages +1/−0
- .git/logs/refs/remotes/origin/master +5/−0
- .git/objects/01/51025fe33749b1b065bfaaddeac482e2554582 binary
- .git/objects/0c/06892b80ad9e05a48ed2f816c1bc9ef49ca69a binary
- .git/objects/0e/f1467fc037c2b698808c4f8670b06f437a44c5 +2/−0
- .git/objects/0f/f8579fbd897417b0d6dad6e920f8882138a7c0 binary
- .git/objects/12/103f6ad6c8b32cef7a550d8d4d8307f656b9ec binary
- .git/objects/19/29f404bd7463b75013763eac1c2fe1bbb03373 binary
- .git/objects/1b/4e38d4a513de8e2fc27d9619999a1732330561 binary
- .git/objects/1d/eac2fe1a42e35b994f1b855488f392c50f6a89 binary
- .git/objects/1f/964c52d8194986ca6879905fbd25488f457fae binary
- .git/objects/20/3fe722984873d04f9997788065406b008051c1 binary
- .git/objects/24/ee306a70ec71338f47f012e1a7ec5668e1851b binary
- .git/objects/27/af847de0afe29dffa87ef0d755c84f830e4941 binary
- .git/objects/29/6daef4bb0fb9e15cdcf2ed42512b88b79ed514 binary
- .git/objects/2c/373856c51ba9550fca9b27b974c3a63db3d7b9 binary
- .git/objects/2c/a5438db72b33a2c171f3e9ae9b73bd59c2fd49 binary
- .git/objects/2d/15c14173d23f664b955cd24f51c82f5f09d91d +1/−0
- .git/objects/35/cdbdae6aa4d9a87e4e3b7c1f21f1d2e90d691e binary
- .git/objects/3d/f33a565ba1673aeae361ffa0bdd75ad5aa87fb binary
- .git/objects/42/238709f16db39e5eaaf8841791e35d3c4484e3 binary
- .git/objects/46/4d078f996682b5330d9821891c67f6e58c303f binary
- .git/objects/4a/c44b6241517d43310da25b086e175b3b9c0b49 binary
- .git/objects/4a/d51f9dc87b6aa48cb614030521d957b8498622 +2/−0
- .git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 binary
- .git/objects/4b/839965d93e9f73dc1f00fac60ce31619cf27bf binary
- .git/objects/4b/b6b3f484c6c64383b85aff399a1f385357e138 binary
- .git/objects/4f/6d438c143bd74eb0fea554c57583a51f92e890 binary
- .git/objects/55/61e9ab1a9d86b8fcecc70202d0263cb525a1ed binary
- .git/objects/5a/6881a3d40966a591bf4431aaae918faa3d3ac5 +3/−0
- .git/objects/5b/b8bdb97c488abfbfcfe0925cd02d0db1df869d binary
- .git/objects/5c/d6ac78a332a4565cc05200276028bb0ad7b381 binary
- .git/objects/5e/48387ea9b3a9fa8fa903f54477534cf8d8dd62 binary
- .git/objects/60/c2748b7df2f5721d8c242094c744d7a777b56f binary
- .git/objects/63/fea90271bdd5df9433756fd72126105cdbe5b7 binary
- .git/objects/75/be0ead191c37fdda11fdd628c79538651403da binary
- .git/objects/76/86c4a999a50079bfd907f126625c1c46def3a3 binary
- .git/objects/82/94ea0d9b3cece7eab328cd560b903f4de899f2 binary
- .git/objects/85/fb86ec84907bcc86531dc82871948ff4d471fa binary
- .git/objects/87/675ebd8ba75eb85ed5ad0ba5888fce6076010c binary
- .git/objects/9a/6fccf7fcd2cd8aea37d5ec6057d9c18b6652a0 binary
- .git/objects/9b/b7324cccda0268cf5e5f318992da50b4f4f003 +4/−0
- .git/objects/9d/e2c9da7719f0fc9bc022d1377992812a7544bb binary
- .git/objects/9e/7e76a48901351049e9c6fe083ba4bb95c2c43f binary
- .git/objects/a4/0d122f65722cef8bbeaa4192b0c65f24e3dac8 binary
- .git/objects/a7/1ae79e4cf33baeecab2eeecf21ae31d35dd99f binary
- .git/objects/a9/cfae246b204d28cdead9aa089ae8a7cded99b0 binary
- .git/objects/ac/1fd40fffacfeb8c1880a86e9dc0aa50c9c3cf2 +1/−0
- .git/objects/ac/65ccb7a09106d00d93cb9ce559e6265ae9bdba binary
- .git/objects/b5/c49f759d54940ec00c97cc026a1e759eaeacc1 binary
- .git/objects/b6/4527d35ee22c00cd184fb921429a7db1984bf8 binary
- .git/objects/b8/3c2375bba608232746064adfdb067cf57e5d80 binary
- .git/objects/bb/f0dc8f66b96264fdfae4c0bf005d5338436767 binary
- .git/objects/bf/bd19dedb8b81537db010dab8523cf46ca5e8a8 binary
- .git/objects/d6/92ca264bd3fbdb96606ebd98c8386f57bcea99 binary
- .git/objects/d7/b08975219be4409e54bcb5fa9ae7a85def6e31 binary
- .git/objects/dd/9b5e8fb8df41e00992dcbedf38edd8c0d25531 binary
- .git/objects/e8/1ac2e44e625bbd33673dc01092b64e2ca8679f binary
- .git/objects/eb/218fa1ac0207d8e1eecff6a59b9789e1bc7df4 binary
- .git/objects/ed/f08a80f0a001b76e1fd26def6ae46c7d2d0cad binary
- .git/objects/f2/6ab906a9c670c4cf1c0d85fb9e2ba66049cd5b binary
- .git/objects/fe/f7206a98cfe55dcb825c24d91f8179fa26d8ab binary
- .git/refs/heads/master +1/−1
- .git/refs/remotes/origin/gh-pages +1/−0
- .git/refs/remotes/origin/master +1/−1
- .gitignore +3/−1
- .gitignore~ +5/−0
- Ketchup.cabal +4/−3
- Ketchup/Auth.hs +10/−0
- Ketchup/Chunked.hs +1/−1
- Ketchup/Chunked.hs~ +46/−0
- Ketchup/Httpd.hs +6/−8
- Ketchup/Routing.hs +26/−16
- Ketchup/Static.hs +2/−4
- README.md +1/−2
- example.hs +5/−5
- gendocs.sh +2/−0
@@ -1,1 +1,1 @@-0.2.2 - POST DATA+Fixed chunked encoding not working
@@ -1,1 +1,2 @@-a06d1fbe75dfe3b2ebe7e03bed4f97c8b05468e3 branch 'master' of github.com:Hamcha/ketchup+b83c2375bba608232746064adfdb067cf57e5d80 branch 'master' of github.com:Hamcha/ketchup+4ac44b6241517d43310da25b086e175b3b9c0b49 not-for-merge branch 'gh-pages' of github.com:Hamcha/ketchup
@@ -1,1 +1,1 @@-c09136db3f6d1b79503253d341373405dd2f0e13+b83c2375bba608232746064adfdb067cf57e5d80
binary file changed (976 → 976 bytes)
@@ -15,3 +15,8 @@ b473be4e130f0ee35eb42d4037b2c99ee5003326 c09136db3f6d1b79503253d341373405dd2f0e13 Hamcha <zikyky@gmail.com> 1401541834 +0200 commit: Switch to PCRE regexps c09136db3f6d1b79503253d341373405dd2f0e13 a06d1fbe75dfe3b2ebe7e03bed4f97c8b05468e3 Hamcha <zikyky@gmail.com> 1401998815 +0200 pull: Fast-forward a06d1fbe75dfe3b2ebe7e03bed4f97c8b05468e3 a8f041ca842f9d4b30406cf727910b74b3cc92d6 Hamcha <zikyky@gmail.com> 1402149852 +0200 commit: 0.2.2 - POST DATA+a8f041ca842f9d4b30406cf727910b74b3cc92d6 464d078f996682b5330d9821891c67f6e58c303f Hamcha <zikyky@gmail.com> 1402151933 +0200 commit: Prettier docs+464d078f996682b5330d9821891c67f6e58c303f a71ae79e4cf33baeecab2eeecf21ae31d35dd99f Hamcha <zikyky@gmail.com> 1402152719 +0200 commit: Tree shaking depenencies+a71ae79e4cf33baeecab2eeecf21ae31d35dd99f 0ef1467fc037c2b698808c4f8670b06f437a44c5 Hamcha <zikyky@gmail.com> 1402152846 +0200 commit: Updated readme+0ef1467fc037c2b698808c4f8670b06f437a44c5 b83c2375bba608232746064adfdb067cf57e5d80 Hamcha <zikyky@gmail.com> 1402175260 +0200 commit: Static doesn't depend on Routing anymore+b83c2375bba608232746064adfdb067cf57e5d80 4ad51f9dc87b6aa48cb614030521d957b8498622 Hamcha <zikyky@gmail.com> 1403296411 +0200 commit: Fixed chunked encoding not working
@@ -15,3 +15,8 @@ b473be4e130f0ee35eb42d4037b2c99ee5003326 c09136db3f6d1b79503253d341373405dd2f0e13 Hamcha <zikyky@gmail.com> 1401541834 +0200 commit: Switch to PCRE regexps c09136db3f6d1b79503253d341373405dd2f0e13 a06d1fbe75dfe3b2ebe7e03bed4f97c8b05468e3 Hamcha <zikyky@gmail.com> 1401998815 +0200 pull: Fast-forward a06d1fbe75dfe3b2ebe7e03bed4f97c8b05468e3 a8f041ca842f9d4b30406cf727910b74b3cc92d6 Hamcha <zikyky@gmail.com> 1402149852 +0200 commit: 0.2.2 - POST DATA+a8f041ca842f9d4b30406cf727910b74b3cc92d6 464d078f996682b5330d9821891c67f6e58c303f Hamcha <zikyky@gmail.com> 1402151933 +0200 commit: Prettier docs+464d078f996682b5330d9821891c67f6e58c303f a71ae79e4cf33baeecab2eeecf21ae31d35dd99f Hamcha <zikyky@gmail.com> 1402152719 +0200 commit: Tree shaking depenencies+a71ae79e4cf33baeecab2eeecf21ae31d35dd99f 0ef1467fc037c2b698808c4f8670b06f437a44c5 Hamcha <zikyky@gmail.com> 1402152846 +0200 commit: Updated readme+0ef1467fc037c2b698808c4f8670b06f437a44c5 b83c2375bba608232746064adfdb067cf57e5d80 Hamcha <zikyky@gmail.com> 1402175260 +0200 commit: Static doesn't depend on Routing anymore+b83c2375bba608232746064adfdb067cf57e5d80 4ad51f9dc87b6aa48cb614030521d957b8498622 Hamcha <zikyky@gmail.com> 1403296411 +0200 commit: Fixed chunked encoding not working
@@ -0,0 +1,1 @@+0000000000000000000000000000000000000000 4ac44b6241517d43310da25b086e175b3b9c0b49 Hamcha <zikyky@gmail.com> 1402364070 +0200 pull: storing head
@@ -14,3 +14,8 @@ b473be4e130f0ee35eb42d4037b2c99ee5003326 c09136db3f6d1b79503253d341373405dd2f0e13 Hamcha <zikyky@gmail.com> 1401541838 +0200 update by push c09136db3f6d1b79503253d341373405dd2f0e13 a06d1fbe75dfe3b2ebe7e03bed4f97c8b05468e3 Hamcha <zikyky@gmail.com> 1401998815 +0200 pull: fast-forward a06d1fbe75dfe3b2ebe7e03bed4f97c8b05468e3 a8f041ca842f9d4b30406cf727910b74b3cc92d6 Hamcha <zikyky@gmail.com> 1402149856 +0200 update by push+a8f041ca842f9d4b30406cf727910b74b3cc92d6 464d078f996682b5330d9821891c67f6e58c303f Hamcha <zikyky@gmail.com> 1402151936 +0200 update by push+464d078f996682b5330d9821891c67f6e58c303f a71ae79e4cf33baeecab2eeecf21ae31d35dd99f Hamcha <zikyky@gmail.com> 1402152722 +0200 update by push+a71ae79e4cf33baeecab2eeecf21ae31d35dd99f 0ef1467fc037c2b698808c4f8670b06f437a44c5 Hamcha <zikyky@gmail.com> 1402152850 +0200 update by push+0ef1467fc037c2b698808c4f8670b06f437a44c5 b83c2375bba608232746064adfdb067cf57e5d80 Hamcha <zikyky@gmail.com> 1402175263 +0200 update by push+b83c2375bba608232746064adfdb067cf57e5d80 4ad51f9dc87b6aa48cb614030521d957b8498622 Hamcha <zikyky@gmail.com> 1403296415 +0200 update by push
binary file changed (absent → 282 bytes)
binary file changed (absent → 178 bytes)
@@ -0,0 +1,2 @@+xA+Â0E]çÙ$m".½d&¶hl qQOo®àêÃ{<øi-eiÁZÑ<ôY¬]Íàc&bJnBAïPmTåÝ4@2q)[I$QDé±l=sYѧÍkÕ7*i&}þ.Ïý¹_ ×)å¢ÁôÑ 1ªÓ~É_ºoLMXW!.¢~ÛD
binary file changed (absent → 1705 bytes)
binary file changed (absent → 1047 bytes)
binary file changed (absent → 179 bytes)
binary file changed (absent → 499 bytes)
binary file changed (absent → 70 bytes)
binary file changed (absent → 1535 bytes)
binary file changed (absent → 918 bytes)
binary file changed (absent → 178 bytes)
binary file changed (absent → 884 bytes)
binary file changed (absent → 918 bytes)
binary file changed (absent → 1072 bytes)
binary file changed (absent → 178 bytes)
@@ -0,0 +1,1 @@+xKÊÉOR0µdp÷t³°LädàdÈÀðïß¿¦¦&&&& r200ôô/àÞ¶iNÓ©ÎêèÂóçJ8¬^<W
binary file changed (absent → 592 bytes)
binary file changed (absent → 46 bytes)
binary file changed (absent → 2871 bytes)
binary file changed (absent → 157 bytes)
binary file changed (absent → 159 bytes)
@@ -0,0 +1,2 @@+xAj!E³öµei« CÈjÈ5´¬drúx ¬þçñ|îµdÌË8E@Lb8ZRÊÆ8o2£Æ³Bó릾â)m@+Éø9òÖ¡³1o9¡ó¼-^PÅÇØû ±òáú[çñ|¿×X>_¹×7Ð Îj $D5é¼6ä_ºÉÀû£3¥qϥݡõßý<fWcJ
binary file changed (absent → 15 bytes)
binary file changed (absent → 158 bytes)
binary file changed (absent → 586 bytes)
binary file changed (absent → 1466 bytes)
binary file changed (absent → 1078 bytes)
@@ -0,0 +1,3 @@+xuRQoÚ@Þs~ E'$ÑiUUJ´M®9§9qäÂÓmûïó](¡ñBÎþ>Ûßg?ió½/~Çgðx3¹ßÜàûZmD9%«ggñß(ZYi¯Hi^É©4j«?:ð£Å(RëÒXM%´ÊJ¸$á°.ÜæÂ^p0|ÇÂþ°3|£dT¤Fr÷SÌûD¥üzNJ»ÓôéÕØUòMñ4;Ý:Âur§,¦dìÚÒ +£7å¨EqjíqrQHÖÇgb È=s`*[ø¸5aTûWW0l¸Ìÿ?å@ÚÜ9Ú8ȬYG{ Àîó®`f´Dyh¹>Hð J_·Ï SS¤`Q»PYÅn{¤2Òÿ¥9¦«@=dÉ}©ª(E3ï+&Áu̽®±@eRá¼/ߣ¶9³9L,+épTå` <0ò'zøÜëÁ¢Ýº5aAñl[b«»XóÊZëQúrBþáñÞGÌD¥ÉÌ£1«ªãëÄ9e/éÂÌÖÂ+µ"8ÿt~°ÔÆB³!¬Ô+Íá-FÑa 'ÇÂÆ£Êjè)¼·au.<Úê ´( e[»v£ð#cñÌ÷Òæû&¾¨v¿$iu T¢ëÀ5\ÚõMu<Iôx°QG
binary file changed (absent → 641 bytes)
binary file changed (absent → 696 bytes)
binary file changed (absent → 282 bytes)
binary file changed (absent → 533 bytes)
binary file changed (absent → 159 bytes)
binary file changed (absent → 682 bytes)
binary file changed (absent → 584 bytes)
binary file changed (absent → 673 bytes)
binary file changed (absent → 11349 bytes)
binary file changed (absent → 931 bytes)
binary file changed (absent → 3015 bytes)
@@ -0,0 +1,4 @@+xQÑnÓ0å¹_áí!1Õ$ ki¤CC6¡L¦=¸ömãÕµC|Ó´Bü;v´2Ƽù^ßsνç,´]ÉËWÏ£ÙU^|½¾ %n4¹¾y31öù4glVÌÈËâÃ㤨¹q+5\3vñZ"Vgµm·§±W¬øÄvkÀÃ3Âd,QÒ,éôvm\úËx2ôà0+\fÉû-±à[£¶)ÍA0û+(}R²À>%¢äµLo·ÑkJX B Ù{@Q6UYLXßN´2kRÖ°L©ÀM,£¤R{ ®@JÐ:Ý@NéUt*NÔªBâjáoãRZ±T:¾÷tè{¾åý¬¿õ¯,Ðc,9ºÍgçÅùí¨UFÚ6¶F[.IJ!r|B¾W|sß?>þ»»ËF"¬7uaå(Ò2Ê/!Õ¶/l4Daj߯ÐÜù¨¯ýÓÃÊàáÊÇS/¹w`@[z|éíldâãóíOˬ/»e¼^ùTé+¿Èá_¸ßâ·MþUõI¹ÿ«FvG<úÕ¤Ö»ÌBtþØàPöKX
binary file changed (absent → 489 bytes)
binary file changed (absent → 775 bytes)
binary file changed (absent → 627 bytes)
binary file changed (absent → 168 bytes)
binary file changed (absent → 281 bytes)
@@ -0,0 +1,1 @@+xuQßoÓ0æ¹ÅͼlÉQíuM"vDad4íÁµÝÆkøÚ´BüïØIÄ*ow§ïÇÝ}KãðúüâEv2¿ßo¯¡¢Û»7÷3` â×óâ¼Ã·wåÇÓWP6ÜzMÚYn¯?1`Q}ضmÚ§®Ycù÷QkÉCÐ3$Yu~û±>ÿÊx2ôäU\ÙF[R¨[½ËÙÌYRòP+¢ïrFjOÕ§ *ÞxEù]ù6¹`EF*>(Õ¶N¿'-2ì§Ñö ªFræâ6Þ3hɧQ¾RPðl:@ÇÎÙM¤t&^4º&ð§q)xJ¶¤MúäØ|Ç{l8ûªÈöpÙÉýl~U^ÝZm¥kSgãrXméÀéü¬ùZ-Âüôlúk:B|x(FÏ&Øÿtéä´ÌÙF[z×·NnJ"H5a^0ܤ¯£ûë u¸ °%t§Yq¡ÙA\}¬~Úk÷õ!¤Ï%!¾Ü]ú.¥ð9Þ¬ClÃuX fÈñó~g q俳5ü
binary file changed (absent → 56 bytes)
binary file changed (absent → 1550 bytes)
binary file changed (absent → 988 bytes)
binary file changed (absent → 180 bytes)
binary file changed (absent → 511 bytes)
binary file changed (absent → 542 bytes)
binary file changed (absent → 1040 bytes)
binary file changed (absent → 1403 bytes)
binary file changed (absent → 912 bytes)
binary file changed (absent → 281 bytes)
binary file changed (absent → 282 bytes)
binary file changed (absent → 1457 bytes)
binary file changed (absent → 1387 bytes)
binary file changed (absent → 593 bytes)
@@ -1,1 +1,1 @@-a8f041ca842f9d4b30406cf727910b74b3cc92d6+4ad51f9dc87b6aa48cb614030521d957b8498622
@@ -0,0 +1,1 @@+4ac44b6241517d43310da25b086e175b3b9c0b49
@@ -1,1 +1,1 @@-a8f041ca842f9d4b30406cf727910b74b3cc92d6+4ad51f9dc87b6aa48cb614030521d957b8498622
@@ -1,4 +1,6 @@ *.hi *.o example -dist+dist +docs +gendocs.sh
@@ -0,0 +1,5 @@+*.hi +*.o +example +dist +docs
@@ -1,5 +1,5 @@ Name: Ketchup -Version: 0.2.2 +Version: 0.2.3 Cabal-Version: >= 1.6 Build-Type: Simple License: MIT @@ -10,15 +10,16 @@ Category: Web, Ketchup Synopsis: A super small web framework for those who don't like big and fancy codebases Description: - Ketchup is a very small HTTP server implementation, the HTTPd itself is one file with - around 100 LoC! + Ketchup is a very small HTTP server implementation, currently under 300 LoC total! . Ketchup is also made to be as modular and embeddable as possible, if you want a cabal-free Haskell app, just take those two/three files you need and put it in your project! . Currently Ketchup comes with: . * Basic httpd functionality (IPV4 only for now) + . * Regexp routing with parameters (ie. \`/user/:name/(.\*)\`) + . * Static file handler (ie. \`static \".\"\` as route/handler) . Most of the project is dependency-free and only uses stuff included in Prelude, with the exception of Ketchup.Static who uses the mime-types package from Hackage, which is a single separately downloadable file.
@@ -0,0 +1,10 @@+{-# LANGUAGE OverloadedStrings #-} + +module Ketchup.Auth +( basicAuth +) where + +import qualified Data.ByteString.Char8 as B +import Ketchup.Utils + +basicAuth :: B.ByteString -> Handler
@@ -23,7 +23,7 @@ sendAll handle content where content = B.concat ["HTTP/1.1 ", statusMsg status, "\r\n\ - \Connection: close\r\n",heads,"\r\n\ + \Connection: close\r\n",heads,"\ \Transfer-Encoding: chunked\r\n\r\n"] heads = B.concat $ map toHeader headers toHeader x = B.concat [fst x, ": "
@@ -0,0 +1,46 @@+{-# LANGUAGE OverloadedStrings #-} + +module Ketchup.Chunked +( chunkHeaders +, chunk +, endchunk +) where + +import qualified Data.ByteString.Char8 as B +import qualified Data.List as List +import Ketchup.Httpd +import Ketchup.Utils +import Network +import Network.Socket.ByteString +import Numeric + +-- |Send HTTP reply headers and begin a Chunked transmission +chunkHeaders :: Socket -- ^ Socket to write to + -> Int -- ^ Status code + -> [(B.ByteString, [B.ByteString])] -- ^ Headers + -> IO () +chunkHeaders handle status headers = do + sendAll handle content + where + content = B.concat ["HTTP/1.1 ", statusMsg status, "\r\n\ + \Connection: close\r\n",heads,"\r\n\ + \Transfer-Encoding: chunked\r\n\r\n"] + heads = B.concat $ map toHeader headers + toHeader x = B.concat [fst x, ": " + ,B.concat $ List.intersperse "," $ snd x + ,"\r\n"] + +-- |Sends a chunk +chunk :: Socket -- ^ Socket to write to + -> B.ByteString -- ^ Content to write + -> IO () +chunk handle value = + sendAll handle content + where + content = B.concat [B.pack $ showHex (B.length value) "", + "\r\n", value, "\r\n"] + +-- |Send the final/closing chunk +endchunk :: Socket -- ^ Socket to write to + -> IO () +endchunk handle = sendAll handle "0\r\n\r\n"
@@ -8,14 +8,12 @@ ) where import Control.Concurrent (forkIO) -import qualified Data.ByteString as B -import qualified Data.ByteString.Char8 as C +import qualified Data.ByteString.Char8 as B import qualified Data.Map as Map import Network import qualified Network.Socket as NS import Network.Socket.ByteString import Ketchup.Utils -import System.IO type Headers = Map.Map B.ByteString [B.ByteString] type Handler = Socket -> HTTPRequest -> IO () @@ -36,8 +34,8 @@ (property, values) where property = head items - values = C.split ',' $ (trim . last) items - items = C.split ':' line + values = B.split ',' $ (trim . last) items + items = B.split ':' line -- Parses request body parseRequestBody :: B.ByteString -> [(B.ByteString, B.ByteString)] @@ -45,21 +43,21 @@ map sep items where sep = breakBS "=" - items = C.split '&' body + items = B.split '&' body -- Gets all request lines getRequest :: Socket -> IO ([B.ByteString], B.ByteString) getRequest client = do content <- recv client 1024 let (headers, body) = breakBS "\r\n\r\n" content - return (C.lines headers, body) + return (B.lines headers, body) -- Parses requests parseRequest :: ([B.ByteString], B.ByteString) -> HTTPRequest parseRequest reqlines = HTTPRequest { method=met, uri=ur, httpver=ver, headers=heads, body=body } where - [met, ur, ver] = C.words $ head headers -- First line is METHOD URI VERSION + [met, ur, ver] = B.words $ head headers -- First line is METHOD URI VERSION heads = Map.fromList $ map parseRequestLine $ tail headers body = snd reqlines headers = fst reqlines
@@ -1,48 +1,58 @@ {-# LANGUAGE OverloadedStrings #-} module Ketchup.Routing -( route +( Route (..) +, Parameters (..) +, route +, useHandler ) where -import qualified Data.ByteString.Char8 as C +import qualified Data.ByteString.Char8 as B import qualified Data.Map as M import Ketchup.Httpd import Ketchup.Utils import Network import qualified Text.Regex.PCRE as R +type Parameters = M.Map B.ByteString B.ByteString +type Route = Socket -> HTTPRequest -> Parameters -> IO () + -- |Router function -- Takes a list of routes and iterates through them for every requeust -route :: [(C.ByteString, (Socket -> HTTPRequest - -> (M.Map C.ByteString C.ByteString) -> IO ()))] -- ^ Routes - -> (Socket -> HTTPRequest -> IO ()) +route :: [(B.ByteString, Route)] -- ^ Routes + -> Handler route [] handle request = sendNotFound handle route (r:routes) handle request | match (uri request) (fst r) = (snd r) handle request $ params (uri request) (fst r) | otherwise = route routes handle request -match :: C.ByteString -> C.ByteString -> Bool +-- |Wrap a handler in a route +-- Lets you use a handler (no parameters) as a route +useHandler :: Handler -> Route +useHandler handler hnd req params = handler hnd req + +match :: B.ByteString -> B.ByteString -> Bool match url template = and $ zipWith compare urlparts tmpparts where compare x y | x == y = True - | or [C.null y, C.null x] = False - | C.head y == ':' = True + | or [B.null y, B.null x] = False + | B.head y == ':' = True | x R.=~ y = True | otherwise = False - urlparts = C.split '/' url - tmpparts = C.split '/' template + urlparts = B.split '/' url + tmpparts = B.split '/' template -params :: C.ByteString -> C.ByteString -> M.Map C.ByteString C.ByteString +params :: B.ByteString -> B.ByteString -> Parameters params url template = - M.fromList $ filter (not . C.null . fst) $ + M.fromList $ filter (not . B.null . fst) $ zipWith retrieve urlparts tmpparts where retrieve x y - | or [C.null y, C.null x] = ("","") - | C.head y == ':' = (C.tail y, x) + | or [B.null y, B.null x] = ("","") + | B.head y == ':' = (B.tail y, x) | otherwise = ("","") - urlparts = C.split '/' url - tmpparts = C.split '/' template + urlparts = B.split '/' url + tmpparts = B.split '/' template
@@ -5,19 +5,17 @@ ) where import qualified Data.ByteString.Char8 as B-import qualified Data.Map as M import Data.Text.Encoding import Ketchup.Httpd import Ketchup.Utils-import Network import Network.Mime import System.Directory (doesFileExist) -- |Static file handler -- Takes a directory and returns a route static :: B.ByteString -- ^ Path to serve static files from- -> Socket -> HTTPRequest -> (M.Map B.ByteString B.ByteString) -> IO ()-static folder hnd req params = do+ -> Handler+static folder hnd req = do let path = B.concat [folder, uri req] let sane = sanecheck path let strPath = B.unpack path
@@ -1,7 +1,6 @@ # Howdy, this is Ketchup! -Ketchup is a very small HTTP server implementation, the HTTPd itself is one file with -around 100 LoC! +Ketchup is a very small HTTP server implementation, currently [under 300 LoC total](http://ix.io/cQM)! Ketchup is also made to be as modular and embeddable as possible, if you want a cabal-free Haskell app, just take those two/three files you need and put it in your project!
@@ -34,11 +34,11 @@ print $ parseBody $ body req sendReply hnd 200 [("Content-Type", ["text/html"])] "OK!" -router = route [ ("/" , handle ) - , ("/greet/:user" , greet ) - , ("/chunk" , chunked ) - , ("/Ketchup/(.*)", static "." ) - , ("/post" , post ) +router = route [ ("/" , handle ) + , ("/greet/:user" , greet ) + , ("/chunk" , chunked ) + , ("/post" , post ) + , ("/Ketchup/(.*)", useHandler $ static "." ) ] main = do listenHTTP "*" 8080 router
@@ -0,0 +1,2 @@+mkdir docs+haddock --html --hoogle -U -o docs Ketchup/Chunked.hs Ketchup/Httpd.hs Ketchup/Routing.hs Ketchup/Static.hs Ketchup/Utils.hs