packages feed

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)

+ Ketchup.Routing: type Parameters = Map ByteString ByteString
+ Ketchup.Routing: type Route = Socket -> HTTPRequest -> Parameters -> IO ()
+ Ketchup.Routing: useHandler :: Handler -> Route
- Ketchup.Routing: route :: [(ByteString, Socket -> HTTPRequest -> (Map ByteString ByteString) -> IO ())] -> (Socket -> HTTPRequest -> IO ())
+ Ketchup.Routing: route :: [(ByteString, Route)] -> Handler
- Ketchup.Static: static :: ByteString -> Socket -> HTTPRequest -> (Map ByteString ByteString) -> IO ()
+ Ketchup.Static: static :: ByteString -> Handler

Files

.git/COMMIT_EDITMSG view
@@ -1,1 +1,1 @@-0.2.2 - POST DATA+Fixed chunked encoding not working
.git/FETCH_HEAD view
@@ -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
.git/ORIG_HEAD view
@@ -1,1 +1,1 @@-c09136db3f6d1b79503253d341373405dd2f0e13+b83c2375bba608232746064adfdb067cf57e5d80
.git/index view

binary file changed (976 → 976 bytes)

.git/logs/HEAD view
@@ -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
.git/logs/refs/heads/master view
@@ -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
+ .git/logs/refs/remotes/origin/gh-pages view
@@ -0,0 +1,1 @@+0000000000000000000000000000000000000000 4ac44b6241517d43310da25b086e175b3b9c0b49 Hamcha <zikyky@gmail.com> 1402364070 +0200	pull: storing head
.git/logs/refs/remotes/origin/master view
@@ -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
+ .git/objects/01/51025fe33749b1b065bfaaddeac482e2554582 view

binary file changed (absent → 282 bytes)

+ .git/objects/0c/06892b80ad9e05a48ed2f816c1bc9ef49ca69a view

binary file changed (absent → 178 bytes)

+ .git/objects/0e/f1467fc037c2b698808c4f8670b06f437a44c5 view
@@ -0,0 +1,2 @@+x•ŽA+Â0E]çْ™$m".½€˜d&¶hl	qQOo®àêÃ{<øi-eiÁZÑ<ôY¬]ˆÍàc&bJnBAPmTåÝ4@2q)[I$QD铱l=sYѧÍkÕ7*i&}þ.Ïý¹_…–×)­å¢Á“ôÑ 1ªÓ~­É_‘ºoLMXW!.¢~ەD
+ .git/objects/0f/f8579fbd897417b0d6dad6e920f8882138a7c0 view

binary file changed (absent → 1705 bytes)

+ .git/objects/12/103f6ad6c8b32cef7a550d8d4d8307f656b9ec view

binary file changed (absent → 1047 bytes)

+ .git/objects/19/29f404bd7463b75013763eac1c2fe1bbb03373 view

binary file changed (absent → 179 bytes)

+ .git/objects/1b/4e38d4a513de8e2fc27d9619999a1732330561 view

binary file changed (absent → 499 bytes)

+ .git/objects/1d/eac2fe1a42e35b994f1b855488f392c50f6a89 view

binary file changed (absent → 70 bytes)

+ .git/objects/1f/964c52d8194986ca6879905fbd25488f457fae view

binary file changed (absent → 1535 bytes)

+ .git/objects/20/3fe722984873d04f9997788065406b008051c1 view

binary file changed (absent → 918 bytes)

+ .git/objects/24/ee306a70ec71338f47f012e1a7ec5668e1851b view

binary file changed (absent → 178 bytes)

+ .git/objects/27/af847de0afe29dffa87ef0d755c84f830e4941 view

binary file changed (absent → 884 bytes)

+ .git/objects/29/6daef4bb0fb9e15cdcf2ed42512b88b79ed514 view

binary file changed (absent → 918 bytes)

+ .git/objects/2c/373856c51ba9550fca9b27b974c3a63db3d7b9 view

binary file changed (absent → 1072 bytes)

+ .git/objects/2c/a5438db72b33a2c171f3e9ae9b73bd59c2fd49 view

binary file changed (absent → 178 bytes)

+ .git/objects/2d/15c14173d23f664b955cd24f51c82f5f09d91d view
@@ -0,0 +1,1 @@+xKÊÉOR0µdp÷t³°Lädàd˜ÈÀðïß¿¦¦&&&& Šr200‰ôô/àÞ¶iNÓ©ÎêèŠÂóçJ8‚¬^<W
+ .git/objects/35/cdbdae6aa4d9a87e4e3b7c1f21f1d2e90d691e view

binary file changed (absent → 592 bytes)

+ .git/objects/3d/f33a565ba1673aeae361ffa0bdd75ad5aa87fb view

binary file changed (absent → 46 bytes)

+ .git/objects/42/238709f16db39e5eaaf8841791e35d3c4484e3 view

binary file changed (absent → 2871 bytes)

+ .git/objects/46/4d078f996682b5330d9821891c67f6e58c303f view

binary file changed (absent → 157 bytes)

+ .git/objects/4a/c44b6241517d43310da25b086e175b3b9c0b49 view

binary file changed (absent → 159 bytes)

+ .git/objects/4a/d51f9dc87b6aa48cb614030521d957b8498622 view
@@ -0,0 +1,2 @@+x•ŽAj!E³öµei«
CÈjÈ5´¬ž–އdrúx…¬þçñ|dÌË8E@‚ŽLb­8ZRÊÆ8o2£Æ•’³Bƒó릾â)m@+†Éø9òÖ¡³1o9¡ó¼-^–PÅÇØû	±òáú[Žçñ|¿×X>_¹×7Ð
­Îj
$D5é¼6ä_’º•ÉÀû£3¥qϥݡõßý<fW‹cJ
+ .git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 view

binary file changed (absent → 15 bytes)

+ .git/objects/4b/839965d93e9f73dc1f00fac60ce31619cf27bf view

binary file changed (absent → 158 bytes)

+ .git/objects/4b/b6b3f484c6c64383b85aff399a1f385357e138 view

binary file changed (absent → 586 bytes)

+ .git/objects/4f/6d438c143bd74eb0fea554c57583a51f92e890 view

binary file changed (absent → 1466 bytes)

+ .git/objects/55/61e9ab1a9d86b8fcecc70202d0263cb525a1ed view

binary file changed (absent → 1078 bytes)

+ .git/objects/5a/6881a3d40966a591bf4431aaae918faa3d3ac5 view
@@ -0,0 +1,3 @@+xuRQoÚ@Þs~…E'$’ÑiUUJ­´ŽMž“®9§9qäÓmûïó](¡ñBÎþ>Ûßg?ió½/~Çgðx3¹Ÿß܏àûZm„D9%«Šggñß(ZYi„¯Hi^•É”©4jƒ«?:ðš£Å(RëÒX‚M%´Ê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úrBþáñÞGÌD¥ÉÌ£1«ª„ãëÄ9e—‚/é„ÂÌÖ†‰+µ"8ÿt~°Ô“ÆB³!¬Ô+˜›ŠÍá-FÑa	'ÇÂÆ£ˆÊjè‡)¼·au.<Úê ´(…e[»v£ð#cñÌ÷Òæû&¾¨v¿­$iu T˜¢ëÀ5\„Úõ›Mu<Iôx°QG
+ .git/objects/5b/b8bdb97c488abfbfcfe0925cd02d0db1df869d view

binary file changed (absent → 641 bytes)

+ .git/objects/5c/d6ac78a332a4565cc05200276028bb0ad7b381 view

binary file changed (absent → 696 bytes)

+ .git/objects/5e/48387ea9b3a9fa8fa903f54477534cf8d8dd62 view

binary file changed (absent → 282 bytes)

+ .git/objects/60/c2748b7df2f5721d8c242094c744d7a777b56f view

binary file changed (absent → 533 bytes)

+ .git/objects/63/fea90271bdd5df9433756fd72126105cdbe5b7 view

binary file changed (absent → 159 bytes)

+ .git/objects/75/be0ead191c37fdda11fdd628c79538651403da view

binary file changed (absent → 682 bytes)

+ .git/objects/76/86c4a999a50079bfd907f126625c1c46def3a3 view

binary file changed (absent → 584 bytes)

+ .git/objects/82/94ea0d9b3cece7eab328cd560b903f4de899f2 view

binary file changed (absent → 673 bytes)

+ .git/objects/85/fb86ec84907bcc86531dc82871948ff4d471fa view

binary file changed (absent → 11349 bytes)

+ .git/objects/87/675ebd8ba75eb85ed5ad0ba5888fce6076010c view

binary file changed (absent → 931 bytes)

+ .git/objects/9a/6fccf7fcd2cd8aea37d5ec6057d9c18b6652a0 view

binary file changed (absent → 3015 bytes)

+ .git/objects/9b/b7324cccda0268cf5e5f318992da50b4f4f003 view
@@ -0,0 +1,4 @@+x­QÑnÓ0å¹_ᙗí!1Õ$ ki¤CC6¡L€¦=¸ömãÕµC|Ó´Bü;v´2Ƽù^ßsνç,´]ÉËWϒ£ÙU^|½¾ %n4¹¾y3—1öù4glVÌȗËâ܌㤨¹q+•5\3vñ‘Z"VgŒµm·§±­W¬øÄvkÀÃ3Âd,QÒ,éôvm\úËx2™ôà0+\fɐû-±Šà[£¶)Í­A0û+(}•R„²À>%¢äµLoŠ·ÑkJX– B
Ù{@Q6Uœ—YƒLXßN´2kRÖ°L©ÀM,œ£¤R‡{
®@JÐ:Ý@‡NéU€t*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“|é“íl’‰†dâãóí™Oˬ/»e‚ƒ¼^ùTé†+¿Èá_¸ßâ·MþUõI¹ÿ«FvG<–úÕ¤Ö»ÌBtþØàPö”KX
+ .git/objects/9d/e2c9da7719f0fc9bc022d1377992812a7544bb view

binary file changed (absent → 489 bytes)

+ .git/objects/9e/7e76a48901351049e9c6fe083ba4bb95c2c43f view

binary file changed (absent → 775 bytes)

+ .git/objects/a4/0d122f65722cef8bbeaa4192b0c65f24e3dac8 view

binary file changed (absent → 627 bytes)

+ .git/objects/a7/1ae79e4cf33baeecab2eeecf21ae31d35dd99f view

binary file changed (absent → 168 bytes)

+ .git/objects/a9/cfae246b204d28cdead9aa089ae8a7cded99b0 view

binary file changed (absent → 281 bytes)

+ .git/objects/ac/1fd40fffacfeb8c1880a86e9dc0aa50c9c3cf2 view
@@ -0,0 +1,1 @@+xuQßoÓ0æ¹ÅͼlÉQíuM"vDad4íÁµÝƛk‡øÚ´BüïØIÄ*ow§ïÇÝ}Kã–ðúüâEv2¿™•ßo¯¡¢Û»7‹÷3`	â×ó⼜÷wånjÓWP6ÜzMÚYn¯?1`Q}‰Ø¶mڞ§®Ycù÷QkÉC™Ð3•$Y‘u~û±>ÿ‡Êx2™ôäU\ÙF[R¨[½ËÙÌYR–’òP+¢ïrFjOÕ§ *ÞxEù]ù6¹`€EFšŒ*>(Õ¶N¿'-2짙Ñö	ªF­ræ„â6Þ3h”É™§ƒQ¾RŠPðl:@ÇÎÙM¤t&^4º&ð§q)xJ¶¤MúäŽØ|Ç{l8ûªÈöpˆÙÉýl~U^ݏZm¥kSgãrXm­ˆéÀéü¬ùZ-Âüôlúk:B|x(FÏ&Øÿtéä´ÌÙF[–z×·NnJ"H5a^ƒ0܇¤¯£ûë…u¸ °Ÿ%t§Yq¡ÙA€\}¬~ڐk÷õ!—¤Ï%!¾Ü]ú.¥ð9Þ¬C˜lÃuX Ÿfȃñó~Œg…q俳5ü
+ .git/objects/ac/65ccb7a09106d00d93cb9ce559e6265ae9bdba view

binary file changed (absent → 56 bytes)

+ .git/objects/b5/c49f759d54940ec00c97cc026a1e759eaeacc1 view

binary file changed (absent → 1550 bytes)

+ .git/objects/b6/4527d35ee22c00cd184fb921429a7db1984bf8 view

binary file changed (absent → 988 bytes)

+ .git/objects/b8/3c2375bba608232746064adfdb067cf57e5d80 view

binary file changed (absent → 180 bytes)

+ .git/objects/bb/f0dc8f66b96264fdfae4c0bf005d5338436767 view

binary file changed (absent → 511 bytes)

+ .git/objects/bf/bd19dedb8b81537db010dab8523cf46ca5e8a8 view

binary file changed (absent → 542 bytes)

+ .git/objects/d6/92ca264bd3fbdb96606ebd98c8386f57bcea99 view

binary file changed (absent → 1040 bytes)

+ .git/objects/d7/b08975219be4409e54bcb5fa9ae7a85def6e31 view

binary file changed (absent → 1403 bytes)

+ .git/objects/dd/9b5e8fb8df41e00992dcbedf38edd8c0d25531 view

binary file changed (absent → 912 bytes)

+ .git/objects/e8/1ac2e44e625bbd33673dc01092b64e2ca8679f view

binary file changed (absent → 281 bytes)

+ .git/objects/eb/218fa1ac0207d8e1eecff6a59b9789e1bc7df4 view

binary file changed (absent → 282 bytes)

+ .git/objects/ed/f08a80f0a001b76e1fd26def6ae46c7d2d0cad view

binary file changed (absent → 1457 bytes)

+ .git/objects/f2/6ab906a9c670c4cf1c0d85fb9e2ba66049cd5b view

binary file changed (absent → 1387 bytes)

+ .git/objects/fe/f7206a98cfe55dcb825c24d91f8179fa26d8ab view

binary file changed (absent → 593 bytes)

.git/refs/heads/master view
@@ -1,1 +1,1 @@-a8f041ca842f9d4b30406cf727910b74b3cc92d6+4ad51f9dc87b6aa48cb614030521d957b8498622
+ .git/refs/remotes/origin/gh-pages view
@@ -0,0 +1,1 @@+4ac44b6241517d43310da25b086e175b3b9c0b49
.git/refs/remotes/origin/master view
@@ -1,1 +1,1 @@-a8f041ca842f9d4b30406cf727910b74b3cc92d6+4ad51f9dc87b6aa48cb614030521d957b8498622
.gitignore view
@@ -1,4 +1,6 @@ *.hi
 *.o
 example
-dist+dist
+docs
+gendocs.sh
+ .gitignore~ view
@@ -0,0 +1,5 @@+*.hi
+*.o
+example
+dist
+docs
Ketchup.cabal view
@@ -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.
+ Ketchup/Auth.hs view
@@ -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
Ketchup/Chunked.hs view
@@ -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, ": "
+ Ketchup/Chunked.hs~ view
@@ -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"
Ketchup/Httpd.hs view
@@ -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
Ketchup/Routing.hs view
@@ -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
Ketchup/Static.hs view
@@ -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
README.md view
@@ -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!
 
example.hs view
@@ -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
+ gendocs.sh view
@@ -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