webutils/0000755000176200001440000000000014677727225012133 5ustar liggesuserswebutils/tests/0000755000176200001440000000000014677335714013273 5ustar liggesuserswebutils/tests/testthat/0000755000176200001440000000000014677727225015135 5ustar liggesuserswebutils/tests/testthat/logo.orig0000644000176200001440000003716114677335714016765 0ustar liggesusersExifMM*bj(1$r2i-'-'Adobe Photoshop CC 2015 (Macintosh)2016:02:15 08:02:12dL&.(6aHH Adobe_CMAdobed            "?   3!1AQa"q2B#$Rb34rC%Scs5&DTdE£t6UeuF'Vfv7GWgw5!1AQaq"2B#R3$brCScs4%&5DTdEU6teuFVfv'7GWgw ?81zx{qs9dѷ{m{N/ZebUwumAٷ{]ۙqC'2Ӝ<:1ǵfCoOHr9Oh~sPRwGּ{rMT]{g3uT6S:]=Fǎm h,䱌`oѲG0?{tkO]ݟbLJ?U*IY1O_f_7񔕯f? Photoshop 3.08BIM%8BIM:g printOutputClrSenumClrSRGBCNm TEXTCamera RGB ProfileInteenumInteClrmMpBlboolprintSixteenBitbool printerNameTEXTOfficejet Pro 8500 A909gprintProofSetupObjc Proof Setup proofSetupBltnenum builtinProof proofCMYK8BIM;-printOutputOptionsCptnboolClbrboolRgsMboolCrnCboolCntCboolLblsboolNgtvboolEmlDboolIntrboolBckgObjcRGBCRd doub@oGrn doub@oBl doub@oBrdTUntF#RltBld UntF#RltRsltUntF#Pxl@r vectorDataboolPgPsenumPgPsPgPCLeftUntF#RltTop UntF#RltScl UntF#Prc@YcropWhenPrintingboolcropRectBottomlong cropRectLeftlong cropRectRightlong cropRectToplong8BIM,,8BIM&?8BIM 8BIM8BIM 8BIM' 8BIMH/fflff/ff2Z5-8BIMp8BIM8BIM8BIM08BIM-8BIM@@8BIM8BIM?LdRlogodLnullboundsObjcRct1Top longLeftlongBtomlongLRghtlongdslicesVlLsObjcslicesliceIDlonggroupIDlongoriginenum ESliceOrigin autoGeneratedTypeenum ESliceTypeImg boundsObjcRct1Top longLeftlongBtomlongLRghtlongdurlTEXTnullTEXTMsgeTEXTaltTagTEXTcellTextIsHTMLboolcellTextTEXT horzAlignenumESliceHorzAligndefault vertAlignenumESliceVertAligndefault bgColorTypeenumESliceBGColorTypeNone topOutsetlong leftOutsetlong bottomOutsetlong rightOutsetlong8BIM( ?8BIM8BIM }Ha Adobe_CMAdobed            "?   3!1AQa"q2B#$Rb34rC%Scs5&DTdE£t6UeuF'Vfv7GWgw5!1AQaq"2B#R3$brCScs4%&5DTdEU6teuFVfv'7GWgw ?81zx{qs9dѷ{m{N/ZebUwumAٷ{]ۙqC'2Ӝ<:1ǵfCoOHr9Oh~sPRwGּ{rMT]{g3uT6S:]=Fǎm h,䱌`oѲG0?{tkO]ݟbLJ?U*IY1O_f_7񔕯f?8BIM!]Adobe PhotoshopAdobe Photoshop CC 20158BIMZhttp://ns.adobe.com/xap/1.0/ XICC_PROFILE HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)KmAdobed@      Ld   s!1AQa"q2B#R3b$r%C4Scs5D'6Tdt& EFVU(eufv7GWgw8HXhx)9IYiy*:JZjzm!1AQa"q2#BRbr3$4CS%cs5DT &6E'dtU7()󄔤euFVfvGWgw8HXhx9IYiy*:JZjz ?c.GUHe"/3xQ{o;&%д?f1qpg-Klvʰ(}E1^Fm.:ު!Y׆m7_2(_,? ٖ-4̗֟eW>ԿO}iXaN_QCK4̗խ?gf&K{+ߑd>@  v1~[o~L~{i䯚,bmռM?}g2~t_L滳5Z Vx#q|9hiH.]/+|wlYeDTz?PA хsc_]ƟZp?P#rƿnޙ?Yo0k/SUZyQ{a`~;_s/?vm]rUDT c~`Vyڬ.L&n,:* $0 6=F3 mx&'R_v״ ~yj+Ͷmz,Rw(ښOq}ouY^sH?wS_YŚ:e(+-ȧG*V\$o/*OqX<GyY)IrdJUB??j]! ̿?{Ɖͳ~y/o)ڽy{ao<-Ӏ ȌƀPoCv6>ќa9Q:>ޛQ2&0Wͅϖ-.&FHC錈7fg8OȿR¯1BΙ˺ly_JPq g[VoI%CN_T+_wIe|k:vBݲQC_ȢߖYć.I 3[jrM_jЮ? , >;+Ė1Aʙ"W9 9~mUCvG|2\fjooΏ_.ZO~p>g,[}B~/;km4g:̧.hqH^4c΢<{bGj7:|W6]!Yl-'OKF1+ٰ,w&Ŷ~(;>-$$1gv$1ܒORs~6:bm ^jF'irj֤TPDpDgTV~]B>^^}Odžٮի:~:Xޡx#_ c~Zk^E#^g ;G8aWvޠZ%li/I ߚc ,dyߛBd,JfW\W4Xf!.8 i,L//#~z~\Eh|8vzpk -RvRT=Zy.XJ$O OŜ lx#* ݇G :X?]F}A)%'dpj{û?BjL>U$U}WO70os \[Υ&E(UGPqWΞtvuvwǫ:PY"O!(ɉ1y-#_yv:BT~1U&$ );#pUѕ##$MIծ*ggq|s\Fo6Ng* @nms~ۤAݾ7L{_{S'?C|=?>5yϞ jK+_6jQUDyLHI+9CPG.c_m?1_G(ϊg+0g/wo[s?SEvM^fׇ?y|9+_~b;GxKz??iyUy^?_|~z\JÕv`vOp|&wx<\w/W?'{webutils/tests/testthat/posttypes0000644000176200001440000005431214677335714017135 0ustar liggesusers--------------------------ef343c1f05a612c3 Content-Disposition: form-data; name="foo" blabla --------------------------ef343c1f05a612c3 Content-Disposition: form-data; name="bar" boeboe --------------------------ef343c1f05a612c3 Content-Disposition: form-data; name="iris" Content-Type: application/rda X @ffffff@@@ffffff@@@ffffff@@@@@333333@333333@333333@333333@@@ffffff@@ffffff@@ffffff@ffffff@ffffff@333333@@@@@@333333@@@@@@@@@ffffff@@@@@ffffff@333333@ffffff@ffffff@333333@@@@@@@@333333@@ffffff@@@@@ffffff@ffffff@@ffffff@333333@@ffffff@@ffffff@333333@ffffff@@ffffff@333333@@@@@@333333@@@@@333333@ffffff@@@ffffff@333333@@ffffff@@@@ffffff@@333333@333333@ffffff@333333@@ffffff@@333333@@@@@333333@@333333@@@@@@@ffffff@@333333@@@@ffffff@@@@@@333333@ffffff@@333333@@@@@@333333@333333@@@333333@@@@ @@ @@ @333333@ 333333@ 333333@333333@@ @ 333333@@@@@333333@ @ffffff@ffffff@ 333333@ @ @ ffffff@ 333333@@ 333333@ @ 333333@ @@ 333333@ffffff@@@ @ @ @@ 333333@ @ffffff@ @ @ffffff@@ffffff@ @ @ ffffff@ @ @@ffffff@ffffff@ffffff@ ffffff@333333@333333@@@@@333333@333333@@@@@@ @ffffff@@ffffff@333333@@ffffff@@333333@@333333@333333@@@@ 333333@@ffffff@@@@@@ffffff@@@333333@333333@@ffffff@ ffffff@@@333333@@@@333333@@ @ @@@@ffffff@ @@ffffff@@@ @ffffff@ffffff@@ ffffff@ @ffffff@@ffffff@@ffffff@ffffff@ffffff@ffffff@@@ 333333@@@@@@@ @ ffffff@@@@ 333333@?ffffff?ffffff???ffffff?333333?ffffff??ffffff????ffffff?񙙙?333333???ffffff?333333??333333???333333?ffffff????ffffff?????ffffff??333333??ffffff???????ffffff?ffffff??ffffff??ffffff@@@@@ffffff@@@ ffffff@ffffff@333333@ @@@@ @@@ffffff@@333333@333333@@@@333333@@333333@@@ @ffffff@ @333333@ffffff@@@@@ffffff@@@ffffff@@ ffffff@@@@333333@@ffffff@@ffffff@@ffffff@333333@ffffff@@333333@333333@ffffff@ffffff@333333@@@ffffff@333333@@@@@@@@@@@333333@@ffffff@333333@ffffff@@ffffff@ffffff@ffffff@ffffff@ffffff@@333333@@ffffff@ffffff@ffffff@@@@@@@ffffff?ə?ə?ə?ə?ə?ٙ?333333?ə?ə??ə?ə???ə?ٙ?ٙ?333333?333333?333333?ə?ٙ?ə??ə?ə?ٙ?ə?ə?ə?ə?ٙ??ə?ə?ə?ə??ə?ə?333333?333333?ə?333333?ٙ?333333?ə?ə?ə?ə?ffffff?????????ffffff????ffffff??ffffff????񙙙????333333??ffffff?ffffff?333333???񙙙??333333????????333333?ffffff?333333???333333???񙙙?@?ffffff@?@@?333333??@@?ffffff@@@333333@ffffff?@@ffffff?@ffffff@@?@???@??ffffff@@??ffffff@ffffff@333333??@@333333@ffffff?ffffff@ffffff@@ffffff?ffffff@@ffffff?  levels setosa versicolor virginica class factor names Sepal.Length Sepal.Width Petal.Length Petal.Width Species row.names j data.frame --------------------------ef343c1f05a612c3 Content-Disposition: form-data; name="description"; filename="DESCRIPTION" Content-Type: application/octet-stream Package: base Version: 3.3.3 Priority: base Title: The R Base Package Author: R Core Team and contributors worldwide Maintainer: R Core Team Description: Base R functions. License: Part of R 3.3.3 Suggests: methods Built: R 3.3.3; ; 2017-03-07 18:47:16 UTC; unix --------------------------ef343c1f05a612c3 Content-Disposition: form-data; name="logo"; filename="logo.jpg" Content-Type: image/jpeg ExifMM*bj(1$r2i-'-'Adobe Photoshop CC 2015 (Macintosh)2016:02:15 08:02:12dL&.(6aHH Adobe_CMAdobed            "?   3!1AQa"q2B#$Rb34rC%Scs5&DTdE£t6UeuF'Vfv7GWgw5!1AQaq"2B#R3$brCScs4%&5DTdEU6teuFVfv'7GWgw ?81zx{qs9dѷ{m{N/ZebUwumAٷ{]ۙqC'2Ӝ<:1ǵfCoOHr9Oh~sPRwGּ{rMT]{g3uT6S:]=Fǎm h,䱌`oѲG0?{tkO]ݟbLJ?U*IY1O_f_7񔕯f? Photoshop 3.08BIM%8BIM:g printOutputClrSenumClrSRGBCNm TEXTCamera RGB ProfileInteenumInteClrmMpBlboolprintSixteenBitbool printerNameTEXTOfficejet Pro 8500 A909gprintProofSetupObjc Proof Setup proofSetupBltnenum builtinProof proofCMYK8BIM;-printOutputOptionsCptnboolClbrboolRgsMboolCrnCboolCntCboolLblsboolNgtvboolEmlDboolIntrboolBckgObjcRGBCRd doub@oGrn doub@oBl doub@oBrdTUntF#RltBld UntF#RltRsltUntF#Pxl@r vectorDataboolPgPsenumPgPsPgPCLeftUntF#RltTop UntF#RltScl UntF#Prc@YcropWhenPrintingboolcropRectBottomlong cropRectLeftlong cropRectRightlong cropRectToplong8BIM,,8BIM&?8BIM 8BIM8BIM 8BIM' 8BIMH/fflff/ff2Z5-8BIMp8BIM8BIM8BIM08BIM-8BIM@@8BIM8BIM?LdRlogodLnullboundsObjcRct1Top longLeftlongBtomlongLRghtlongdslicesVlLsObjcslicesliceIDlonggroupIDlongoriginenum ESliceOrigin autoGeneratedTypeenum ESliceTypeImg boundsObjcRct1Top longLeftlongBtomlongLRghtlongdurlTEXTnullTEXTMsgeTEXTaltTagTEXTcellTextIsHTMLboolcellTextTEXT horzAlignenumESliceHorzAligndefault vertAlignenumESliceVertAligndefault bgColorTypeenumESliceBGColorTypeNone topOutsetlong leftOutsetlong bottomOutsetlong rightOutsetlong8BIM( ?8BIM8BIM }Ha Adobe_CMAdobed            "?   3!1AQa"q2B#$Rb34rC%Scs5&DTdE£t6UeuF'Vfv7GWgw5!1AQaq"2B#R3$brCScs4%&5DTdEU6teuFVfv'7GWgw ?81zx{qs9dѷ{m{N/ZebUwumAٷ{]ۙqC'2Ӝ<:1ǵfCoOHr9Oh~sPRwGּ{rMT]{g3uT6S:]=Fǎm h,䱌`oѲG0?{tkO]ݟbLJ?U*IY1O_f_7񔕯f?8BIM!]Adobe PhotoshopAdobe Photoshop CC 20158BIMZhttp://ns.adobe.com/xap/1.0/ XICC_PROFILE HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)KmAdobed@      Ld   s!1AQa"q2B#R3b$r%C4Scs5D'6Tdt& EFVU(eufv7GWgw8HXhx)9IYiy*:JZjzm!1AQa"q2#BRbr3$4CS%cs5DT &6E'dtU7()󄔤euFVfvGWgw8HXhx9IYiy*:JZjz ?c.GUHe"/3xQ{o;&%д?f1qpg-Klvʰ(}E1^Fm.:ު!Y׆m7_2(_,? ٖ-4̗֟eW>ԿO}iXaN_QCK4̗խ?gf&K{+ߑd>@  v1~[o~L~{i䯚,bmռM?}g2~t_L滳5Z Vx#q|9hiH.]/+|wlYeDTz?PA хsc_]ƟZp?P#rƿnޙ?Yo0k/SUZyQ{a`~;_s/?vm]rUDT c~`Vyڬ.L&n,:* $0 6=F3 mx&'R_v״ ~yj+Ͷmz,Rw(ښOq}ouY^sH?wS_YŚ:e(+-ȧG*V\$o/*OqX<GyY)IrdJUB??j]! ̿?{Ɖͳ~y/o)ڽy{ao<-Ӏ ȌƀPoCv6>ќa9Q:>ޛQ2&0Wͅϖ-.&FHC錈7fg8OȿR¯1BΙ˺ly_JPq g[VoI%CN_T+_wIe|k:vBݲQC_ȢߖYć.I 3[jrM_jЮ? , >;+Ė1Aʙ"W9 9~mUCvG|2\fjooΏ_.ZO~p>g,[}B~/;km4g:̧.hqH^4c΢<{bGj7:|W6]!Yl-'OKF1+ٰ,w&Ŷ~(;>-$$1gv$1ܒORs~6:bm ^jF'irj֤TPDpDgTV~]B>^^}Odžٮի:~:Xޡx#_ c~Zk^E#^g ;G8aWvޠZ%li/I ߚc ,dyߛBd,JfW\W4Xf!.8 i,L//#~z~\Eh|8vzpk -RvRT=Zy.XJ$O OŜ lx#* ݇G :X?]F}A)%'dpj{û?BjL>U$U}WO70os \[Υ&E(UGPqWΞtvuvwǫ:PY"O!(ɉ1y-#_yv:BT~1U&$ );#pUѕ##$MIծ*ggq|s\Fo6Ng* @nms~ۤAݾ7L{_{S'?C|=?>5yϞ jK+_6jQUDyLHI+9CPG.c_m?1_G(ϊg+0g/wo[s?SEvM^fׇ?y|9+_~b;GxKz??iyUy^?_|~z\JÕv`vOp|&wx<\w/W?'{ --------------------------ef343c1f05a612c3-- webutils/tests/testthat/description.orig0000644000176200001440000000043614677335714020343 0ustar liggesusersPackage: base Version: 3.3.3 Priority: base Title: The R Base Package Author: R Core Team and contributors worldwide Maintainer: R Core Team Description: Base R functions. License: Part of R 3.3.3 Suggests: methods Built: R 3.3.3; ; 2017-03-07 18:47:16 UTC; unix webutils/tests/testthat/iris.orig0000644000176200001440000001323514677335714016767 0ustar liggesusersX @ffffff@@@ffffff@@@ffffff@@@@@333333@333333@333333@333333@@@ffffff@@ffffff@@ffffff@ffffff@ffffff@333333@@@@@@333333@@@@@@@@@ffffff@@@@@ffffff@333333@ffffff@ffffff@333333@@@@@@@@333333@@ffffff@@@@@ffffff@ffffff@@ffffff@333333@@ffffff@@ffffff@333333@ffffff@@ffffff@333333@@@@@@333333@@@@@333333@ffffff@@@ffffff@333333@@ffffff@@@@ffffff@@333333@333333@ffffff@333333@@ffffff@@333333@@@@@333333@@333333@@@@@@@ffffff@@333333@@@@ffffff@@@@@@333333@ffffff@@333333@@@@@@333333@333333@@@333333@@@@ @@ @@ @333333@ 333333@ 333333@333333@@ @ 333333@@@@@333333@ @ffffff@ffffff@ 333333@ @ @ ffffff@ 333333@@ 333333@ @ 333333@ @@ 333333@ffffff@@@ @ @ @@ 333333@ @ffffff@ @ @ffffff@@ffffff@ @ @ ffffff@ @ @@ffffff@ffffff@ffffff@ ffffff@333333@333333@@@@@333333@333333@@@@@@ @ffffff@@ffffff@333333@@ffffff@@333333@@333333@333333@@@@ 333333@@ffffff@@@@@@ffffff@@@333333@333333@@ffffff@ ffffff@@@333333@@@@333333@@ @ @@@@ffffff@ @@ffffff@@@ @ffffff@ffffff@@ ffffff@ @ffffff@@ffffff@@ffffff@ffffff@ffffff@ffffff@@@ 333333@@@@@@@ @ ffffff@@@@ 333333@?ffffff?ffffff???ffffff?333333?ffffff??ffffff????ffffff?񙙙?333333???ffffff?333333??333333???333333?ffffff????ffffff?????ffffff??333333??ffffff???????ffffff?ffffff??ffffff??ffffff@@@@@ffffff@@@ ffffff@ffffff@333333@ @@@@ @@@ffffff@@333333@333333@@@@333333@@333333@@@ @ffffff@ @333333@ffffff@@@@@ffffff@@@ffffff@@ ffffff@@@@333333@@ffffff@@ffffff@@ffffff@333333@ffffff@@333333@333333@ffffff@ffffff@333333@@@ffffff@333333@@@@@@@@@@@333333@@ffffff@333333@ffffff@@ffffff@ffffff@ffffff@ffffff@ffffff@@333333@@ffffff@ffffff@ffffff@@@@@@@ffffff?ə?ə?ə?ə?ə?ٙ?333333?ə?ə??ə?ə???ə?ٙ?ٙ?333333?333333?333333?ə?ٙ?ə??ə?ə?ٙ?ə?ə?ə?ə?ٙ??ə?ə?ə?ə??ə?ə?333333?333333?ə?333333?ٙ?333333?ə?ə?ə?ə?ffffff?????????ffffff????ffffff??ffffff????񙙙????333333??ffffff?ffffff?333333???񙙙??333333????????333333?ffffff?333333???333333???񙙙?@?ffffff@?@@?333333??@@?ffffff@@@333333@ffffff?@@ffffff?@ffffff@@?@???@??ffffff@@??ffffff@ffffff@333333??@@333333@ffffff?ffffff@ffffff@@ffffff?ffffff@@ffffff?  levels setosa versicolor virginica class factor names Sepal.Length Sepal.Width Petal.Length Petal.Width Species row.names j data.framewebutils/tests/testthat/test-parse.R0000644000176200001440000000221514677335714017345 0ustar liggesuserscontext("fixed post data") # Example with various types from 'curl' vignette test_that("parsing example post", { buf <- readBin("posttypes", raw(), 1e6) out <- parse_multipart(buf, "------------------------ef343c1f05a612c3") # foo = "blabla" expect_equal(rawToChar(out$foo$value), "blabla") expect_null(out$foo$content_type) # bar = charToRaw("boeboe") expect_equal(out$bar$value, charToRaw("boeboe")) expect_null(out$foo$content_type) # iris = form_data(serialize(iris, NULL), "application/rda"), expect_equal(out$iris$value, readBin('iris.orig', raw(), 1e5)) expect_equal(out$iris$content_type, "application/rda") # description = form_file(system.file("DESCRIPTION")), expect_equal(out$description$value, readBin('description.orig', raw(), 1e5)); expect_equal(out$description$content_type, "application/octet-stream") expect_equal(out$description$filename, "DESCRIPTION") # logo = form_file(file.path(Sys.getenv("R_DOC_DIR"), "html/logo.jpg"), "image/jpeg") expect_equal(out$logo$value, readBin('logo.orig', raw(), 1e5)); expect_equal(out$logo$content_type, "image/jpeg") expect_equal(out$logo$filename, "logo.jpg") }) webutils/tests/testthat/test-echo.R0000644000176200001440000000445014677335714017154 0ustar liggesuserscontext("echo with httpuv") # Example with various types from 'curl' vignette test_that("test echo from httpuv", { desc <- system.file("DESCRIPTION") logo <- file.path(Sys.getenv("R_DOC_DIR"), "html/logo.jpg") h <- curl::handle_setform(curl::new_handle(forbid_reuse = TRUE), foo = "blabla", bar = charToRaw("boeboe"), iris = curl::form_data(serialize(iris, NULL), "application/rda"), description = curl::form_file(desc), logo = curl::form_file(logo, "image/jpeg") ) req <- curl::curl_echo(h, port = httpuv::randomPort()) formdata <- parse_http(req$body, req$content_type) # foo = "blabla" expect_equal(rawToChar(formdata$foo$value), "blabla") expect_null(formdata$foo$content_type) # bar = charToRaw("boeboe") expect_equal(formdata$bar$value, charToRaw("boeboe")) expect_null(formdata$foo$content_type) # iris = form_data(serialize(iris, NULL), "application/rda"), expect_equal(formdata$iris$value, serialize(iris, NULL), "application/rda") expect_equal(formdata$iris$content_type, "application/rda") # description = form_file(system.file("DESCRIPTION")), expect_equal(formdata$description$value, readBin(desc, raw(), 1e5)) expect_equal(formdata$description$content_type, "application/octet-stream") expect_equal(formdata$description$filename, "DESCRIPTION") # logo = form_file(file.path(Sys.getenv("R_DOC_DIR"), "html/logo.jpg"), "image/jpeg") expect_equal(formdata$logo$value, readBin(logo, raw(), 1e5)); expect_equal(formdata$logo$content_type, "image/jpeg") expect_equal(formdata$logo$filename, "logo.jpg") }) test_that("Echo a big file", { # Create a random file (~30 MB) # Note: can test even bigger files but curl_echo() is a bit slow on Windows tmp <- tempfile() size <- if(.Platform$OS.type == "windows"){ 1e5 } else { runif(1, 3e6, 4e6) } buf <- serialize(rnorm(size), NULL) writeBin(buf, tmp) on.exit(unlink(tmp)) # Roundtrip via httpuv h <- curl::handle_setform(curl::new_handle(forbid_reuse = TRUE), myfile = curl::form_file(tmp)) req <- curl::curl_echo(h, port = httpuv::randomPort()) formdata <- parse_http(req$body, req$content_type) # Tests expect_length(formdata$myfile$value, file.info(tmp)$size) expect_identical(formdata$myfile$filename, basename(tmp)) expect_identical(formdata$myfile$value, buf) }) webutils/tests/testthat/test-encoding.R0000644000176200001440000000065414677335714020026 0ustar liggesuserscontext("encoding") test_that("Encoding is retained", { strings <- c( "Zürich", "北京填鴨们", "ผัดไทย", "寿司", rawToChar(as.raw(1:40)), "?foo&bar=baz!bla\n" ) encstr <- curl::curl_escape(strings) data <- paste(encstr, encstr, collapse = "&", sep = "=") out <- webutils::parse_query(data) expect_equal(names(out), strings) expect_equal(unlist(unname(out)), strings) }) webutils/tests/testthat.R0000644000176200001440000000007414677335714015257 0ustar liggesuserslibrary(testthat) library(webutils) test_check("webutils") webutils/MD50000644000176200001440000000266714677727225012456 0ustar liggesuserse02f1ad97586f23bb5442ddc8173dae3 *DESCRIPTION 1ee0683cce6d3479250337954c075d63 *LICENSE 0a3b86119731bfb2f20a16f7c64d2a4a *NAMESPACE 0814879ad4d31920b2674d0c0c83c668 *NEWS e50083c8730bed2b45211c3484ab2c50 *R/demo_httpuv.R 0ac8d36b127986a2faf9b0e42a2f4125 *R/demo_rhttpd.R 58fa1d93b5be91118fffee790ed02bda *R/get_boundary.R ab12805b718cbf4df2a567080cc88314 *R/parse_http.R e47ccfa13dab8f8e2cd6096c53264eae *R/parse_multipart.R 81d4d3f635a583718d74a97bf9833942 *R/parse_query.R 380bdbd403433141f41e806ddbdacb05 *R/util.R c2e0f93503193f7f6e8dd4bdc008e196 *inst/testpage.html e463eed305607a900446f86e13946aa0 *man/demo_httpuv.Rd 27c6149587d67c61c3a80520b67c7e89 *man/demo_rhttpd.Rd bb6b8d4ace31978cf3ff2e4e1309c8dd *man/parse_http.Rd 6cde09d800519b0ed0ca439df8247cb1 *man/parse_multipart.Rd ef049c9bcde8adffaac2ea4b2326545e *man/parse_query.Rd fb7033cc923e51999b6d244a1603d193 *src/memmem.c b56fbad89241b7653a875c1d3baa83cf *src/register.c 9c5907103c6c232c24ad444a207707c8 *src/split.c 954ef331d77f9d124a7ec223c96a9ba5 *tests/testthat.R b2c346791c435576d7be9eb22d81f227 *tests/testthat/description.orig 50cfdda3936e196ffb5c0eccca1255f1 *tests/testthat/iris.orig 12f1db814335beab91f8d3b968396842 *tests/testthat/logo.orig c233475583871bb26d093b1706640feb *tests/testthat/posttypes 2da2972161714a5025a13e2162227979 *tests/testthat/test-echo.R 97c52398efd6cbf5cef5a639038fa728 *tests/testthat/test-encoding.R 529d2bca1cddda33060130ae5d5529bd *tests/testthat/test-parse.R webutils/R/0000755000176200001440000000000014677335714012332 5ustar liggesuserswebutils/R/demo_rhttpd.R0000644000176200001440000000475414677335714015000 0ustar liggesusers#' Demo multipart parser with rhttpd #' #' Starts the Rhttpd web server and hosts a simple form including a file #' upload to demo the multipart parser. # #' @export #' @family demo demo_rhttpd <- function(){ rhttpd_handler <- function(reqpath, reqquery, reqbody, reqheaders){ # Extract HTTP content type and method from strange rhttpd format content_type <- grep("Content-Type:", strsplit(rawToChar(reqheaders), "\n")[[1]], ignore.case=TRUE, value=TRUE); content_type <- sub("Content-Type: ?", "", content_type, ignore.case=TRUE); http_method <- grep("Request-Method:", strsplit(rawToChar(reqheaders), "\n")[[1]], ignore.case=TRUE, value=TRUE); http_method <- sub("Request-Method: ?", "", http_method, ignore.case=TRUE); # Show HTML page for GET requests. if(tolower(http_method) %in% c("post", "put") && length(reqbody)){ # Parse the multipart/form-data message("Received HTTP POST request.") # Check for multipart() postdata <- parse_http(reqbody, content_type) # Print it to the R console (just for fun) utils::str(postdata) # process this form username <- rawToChar(as.raw(postdata$username$value)) email <- rawToChar(as.raw(postdata$email_address$value)) food <- rawToChar(as.raw(postdata$food$value)) picture <- file.path(getwd(), basename(postdata$picture$filename)) writeBin(as.raw(postdata$picture$value), picture) # return summary to the client list( "payload" = paste0("User: ", username, "\nEmail: ", email, "\nPicture (copy): ", picture,"\nFood: ", food, "\n"), "content-type" = "text/plain", "headers" = NULL, "status code" = 200 ) } else { message("Received HTTP GET request: ", reqpath) testpage <- system.file("testpage.html", package="webutils"); stopifnot(file.exists(testpage)) list( "payload" = readBin(testpage, raw(), n=file.info(testpage)$size), "content-type" = "text/html", "headers" = NULL, "status code" = 200 ) } } # Start rhttpd and get port port <- if(R.version[["svn rev"]] < 67550) { try(tools::startDynamicHelp(TRUE), silent=TRUE); utils::getFromNamespace("httpdPort", "tools"); } else { tools::startDynamicHelp(NA); } handlers_env <- utils::getFromNamespace(".httpd.handlers.env", "tools") assign("test", rhttpd_handler, handlers_env) url <- paste0("http://localhost:", port, "/custom/test") message("Opening ", url) utils::browseURL(url) } webutils/R/parse_multipart.R0000644000176200001440000000471114677335714015673 0ustar liggesusers#' Parse a multipart/form-data request #' #' Parse a multipart/form-data request, which is usually generated from a HTML form #' submission. The parameters can include both text values as well as binary files. #' They can be distinguished from the presence of a `filename` attribute. #' #' A multipart/form-data request consists of a single body which contains one or more #' values plus meta-data, separated using a boundary string. This boundary string #' is chosen by the client (e.g. the browser) and specified in the `Content-Type` #' header of the HTTP request. There is no escaping; it is up to the client to choose #' a boundary string that does not appear in one of the values. #' #' The parser is written in pure R, but still pretty fast because it uses the regex #' engine. #' #' @export #' @param body body of the HTTP request. Must be raw or character vector. #' @param boundary boundary string as specified in the `Content-Type` request header. #' @examples \dontrun{example form #' demo_rhttpd() #' } parse_multipart <- function(body, boundary){ # Some HTTP daemons give the body as a string instead of raw. if(is.character(body)) body <- charToRaw(paste(body, collapse="")) if(is.character(boundary)) boundary <- charToRaw(boundary) # Heavy lifting in C stopifnot(is.raw(body), is.raw(boundary)) form_data <- split_by_boundary(body, boundary) # Output out <- lapply(form_data, function(val){ headers <- parse_header(val[[1]]) c(list( value = val[[2]] ), headers) }) names(out) <- sapply(out, `[[`, 'name'); out } parse_header <- function(buf){ headers <- strsplit(rawToChar(buf), "\r\n", fixed = TRUE)[[1]] out <- split_names(headers, ": ") if(length(out$content_disposition)){ pieces <- strsplit(out$content_disposition, "; ")[[1]] out$content_disposition <- pieces[1] out <- c(out, lapply(split_names(pieces[-1], "="), unquote)) } out } #' @useDynLib webutils R_split_boundary split_by_boundary <- function(body, boundary){ .Call(R_split_boundary, body, boundary) } #' @useDynLib webutils R_split_string split_by_string <- function(string, split = ":"){ .Call(R_split_string, string, split) } #' @useDynLib webutils R_unquote unquote <- function(string){ .Call(R_unquote, string) } split_names <- function(x, split){ matches <- lapply(x, split_by_string, split) names <- chartr("-", "_", tolower(sapply(matches, `[[`, 1))) values <- lapply(matches, `[[`, 2) structure(values, names = names); } webutils/R/get_boundary.R0000644000176200001440000000102114677335714015131 0ustar liggesusersget_boundary <- function(content_type){ # Check for multipart header if(!grepl("multipart/form-data;", content_type, fixed = TRUE)) stop("Content type is not multipart/form-data: ", content_type) if(!grepl("boundary=", content_type, fixed = TRUE)) stop("Multipart content-type header without boundary: ", content_type) # Extract bounary m <- regexpr('boundary=[^; ]{2,}', content_type, ignore.case = TRUE) boundary <- sub('boundary=','',regmatches(content_type, m)[[1]]) sub('^"(.*)"$', "\\1", boundary) } webutils/R/parse_query.R0000644000176200001440000000201214677335714015007 0ustar liggesusers#' Parse query string #' #' Parse http parameters from a query string. This includes unescaping #' of url-encoded values. #' #' For http GET requests, the query string is specified #' in the URL after the question mark. For http POST or PUT requests, the query #' string can be used in the request body when the `Content-Type` header #' is set to `application/x-www-form-urlencoded`. #' #' @export #' @param query a url-encoded query string #' @examples q <- "foo=1%2B1%3D2&bar=yin%26yang" #' parse_query(q) parse_query <- function(query){ if(is.raw(query)) query <- rawToChar(query); stopifnot(is.character(query)); #httpuv includes the question mark in query string query <- sub("^[?]", "", query) query <- chartr('+',' ', query) #split by & character argstr <- strsplit(query, "&", fixed = TRUE)[[1]] args <- lapply(argstr, function(x){ curl::curl_unescape(strsplit(x, "=", fixed = TRUE)[[1]]) }) values <- lapply(args, `[`, 2) names(values) <- vapply(args, `[`, character(1), 1) return(values) } webutils/R/parse_http.R0000644000176200001440000000276514677335714014640 0ustar liggesusers#' Parse http request #' #' Parse the body of a http request, based on the `Content-Type` request #' header. Currently supports the three most important content types: #' `application/x-www-form-urlencoded` with [parse_query()], #' `multipart/form-data` with [parse_multipart()], and `application/json` #' with [jsonlite::fromJSON()]. #' #' @export #' @param body request body of the http request #' @param content_type content-type http request header as specified by the client #' @param ... additional arguments passed to parser function #' @importFrom jsonlite fromJSON #' @examples # Parse json encoded payload: #' parse_http('{"foo":123, "bar":true}', 'application/json') #' #' # Parse url-encoded payload #' parse_http("foo=1%2B1%3D2&bar=yin%26yang", "application/x-www-form-urlencoded") #' #' \dontrun{use demo app to parse multipart/form-data payload #' demo_rhttpd() #' } parse_http <- function(body, content_type, ...){ # Remove header name if present content_type <- sub("Content-Type: ?", "", content_type, ignore.case=TRUE); # Switch by content-type if(grepl("multipart/form-data;", content_type, fixed = TRUE)){ return(parse_multipart(body, get_boundary(content_type))) } else if(grepl("application/x-www-form-urlencoded", content_type, fixed=TRUE)){ return(parse_query(body)) } else if(grepl("(text|application)/json", content_type)){ if(is.raw(body)) body <- rawToChar(body) return(fromJSON(body, ...)) } else { stop("Unsupported Content-Type: ", content_type) } } webutils/R/util.R0000644000176200001440000000052314677335714013432 0ustar liggesusers# Override default for call. argument stop <- function(..., call. = FALSE){ base::stop(..., call. = FALSE) } # Strip trailing whitespace trail <- function(str){ str <- sub("\\s+$", "", str, perl = TRUE); sub("^\\s+", "", str, perl = TRUE); } rawToChar <- function(x){ out <- base::rawToChar(x) Encoding(out) <- 'UTF-8' out } webutils/R/demo_httpuv.R0000644000176200001440000000403114677335714015011 0ustar liggesusers#' Demo multipart parser with httpuv #' #' Starts the httpuv web server and hosts a simple form including a file #' upload to demo the multipart parser. # #' @export #' @family demo #' @param port which port number to run the http server demo_httpuv <- function(port = 9359){ rook_handler <- function(env){ # See Rook spec content_type <- env[["CONTENT_TYPE"]] http_method <- env[["REQUEST_METHOD"]] body <- env[["rook.input"]]$read() path <- env[["PATH_INFO"]] # Show HTML page for GET requests. if(tolower(http_method) %in% c("post", "put")){ # Parse the multipart/form-data message("Received HTTP POST request.") postdata <- parse_http(body, content_type) # Print it to the R console (just for fun) utils::str(postdata) # process this form username <- rawToChar(as.raw(postdata$username$value)) email <- rawToChar(as.raw(postdata$email_address$value)) food <- rawToChar(as.raw(postdata$food$value)) picture <- file.path(getwd(), basename(postdata$picture$filename)) writeBin(postdata$picture$value, picture) # return summary to the client list( status = 200, body = paste0("User: ", username, "\nEmail: ", email, "\nPicture (copy): ", picture,"\nFood: ", food, "\n"), headers = c("Content-Type" = "text/plain") ) } else { message("Received HTTP GET request: ", path) testpage <- system.file("testpage.html", package="webutils"); stopifnot(file.exists(testpage)) list ( status = 200, body = paste(readLines(testpage), collapse="\n"), headers = c("Content-Type" = "text/html") ) } } # Start httpuv if(!length(port)) port <- httpuv::randomPort() server_id <- httpuv::startServer("0.0.0.0", port, list(call = rook_handler)) on.exit({ message("stopping server") httpuv::stopServer(server_id) }, add = TRUE) url <- paste0("http://localhost:", port, "/") message("Opening ", url) utils::browseURL(url) repeat { httpuv::service() } } webutils/NEWS0000644000176200001440000000120614677505072012623 0ustar liggesusers1.2.1 - Fix Rd link 'anchor' 1.2.0 - Remove quotes from bounary if any (#8) - Use httpuv::randomPort() in tests and examples 1.1 - Allow charset in multipart Content-Type (#3) 1.0 - Ignore additional fields such as charset from the multipart boundary - Fix a unit test to avoid a bug in libcurl: https://github.com/curl/curl/issues/4246 - Make curl_echo() unit test faster on Windows 0.6 - Use curl_unescape() in parse_query() because utils::URLdecode() is broken for UTF-8 - Assume UTF-8 for all strings in rawToChar() 0.5 - Rewrite of multipart parser in C - Use the new curl::curl_echo() function to test the parser webutils/src/0000755000176200001440000000000014677335714012720 5ustar liggesuserswebutils/src/split.c0000644000176200001440000000505714677335714014226 0ustar liggesusers#define _GNU_SOURCE #include #include #include //from memmem.c void * fallback_memmem(const void *h0, size_t k, const void *n0, size_t l); #if !defined(_WIN32) && !defined(__sun) #define my_memmem memmem #else #define my_memmem fallback_memmem #endif //split by first CRLF SEXP split_header(unsigned char * haystack, size_t n){ SEXP out = PROTECT(allocVector(VECSXP, 2)); unsigned char * cur = my_memmem(haystack, n, "\r\n\r\n", 4); if(cur){ size_t len = cur - haystack; SEXP header = allocVector(RAWSXP, len); memcpy(RAW(header), haystack, len); SET_VECTOR_ELT(out, 0, header); SEXP body = allocVector(RAWSXP, n - len - 4); memcpy(RAW(body), cur + 4, n - len - 4); SET_VECTOR_ELT(out, 1, body); haystack = cur + 4; n -= len + 4; } SEXP body = allocVector(RAWSXP, n); memcpy(RAW(body), haystack, n); SET_VECTOR_ELT(out, 1, body); UNPROTECT(1); return out; } //split by arbitrary string SEXP R_split_boundary(SEXP body, SEXP boundary){ unsigned char * haystack = RAW(body); unsigned char * needle = RAW(boundary); //expect no more than 1000 boundaries unsigned char * offsets[1000] = { 0 }; //initial values size_t n = Rf_length(body); size_t m = Rf_length(boundary); //find the needles int count = 0; unsigned char * cur = NULL; for(count = 0; (cur = my_memmem(haystack, n, needle, m)) && (n > m); count++){ offsets[count] = cur; n = n - (cur - haystack) - m; haystack = cur + m; } //extract the if(count < 2) return allocVector(VECSXP, 0); //extract the payloads SEXP out = PROTECT(allocVector(VECSXP, count - 1)); for(int i = 0; i < count - 1; i++){ unsigned char * start = offsets[i] + m + 2; //drop ending CRLF unsigned char * end = offsets[i+1] - 4; //drop beginning CRLF + boundary preamble "--" size_t len = end - start; SET_VECTOR_ELT(out, i, split_header(start, len)); } UNPROTECT(1); return out; } SEXP R_split_string(SEXP string, SEXP split){ const char * str = CHAR(STRING_ELT(string, 0)); const char * cut = CHAR(STRING_ELT(split, 0)); char * out = strstr(str, cut); if(!out) return string; SEXP res = PROTECT(allocVector(STRSXP, 2)); SET_STRING_ELT(res, 0, mkCharLen(str, out - str)); SET_STRING_ELT(res, 1, mkChar(out + strlen(cut))); UNPROTECT(1); return res; } SEXP R_unquote(SEXP string){ const char * str = CHAR(STRING_ELT(string, 0)); size_t len = strlen(str); if(len > 1 && str[0] == '"' && str[len-1] == '"') return ScalarString(mkCharLen(str + 1, len - 2)); return string; } webutils/src/memmem.c0000644000176200001440000001136014677335714014342 0ustar liggesusers/*- * Copyright (c) 2005-2014 Rich Felker, et al. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include static char *twobyte_memmem(const unsigned char *h, size_t k, const unsigned char *n) { uint16_t nw = n[0]<<8 | n[1], hw = h[0]<<8 | h[1]; for (h++, k--; k; k--, hw = hw<<8 | *++h) if (hw == nw) return (char *)h-1; return 0; } static char *threebyte_memmem(const unsigned char *h, size_t k, const unsigned char *n) { uint32_t nw = n[0]<<24 | n[1]<<16 | n[2]<<8; uint32_t hw = h[0]<<24 | h[1]<<16 | h[2]<<8; for (h+=2, k-=2; k; k--, hw = (hw|*++h)<<8) if (hw == nw) return (char *)h-2; return 0; } static char *fourbyte_memmem(const unsigned char *h, size_t k, const unsigned char *n) { uint32_t nw = n[0]<<24 | n[1]<<16 | n[2]<<8 | n[3]; uint32_t hw = h[0]<<24 | h[1]<<16 | h[2]<<8 | h[3]; for (h+=3, k-=3; k; k--, hw = hw<<8 | *++h) if (hw == nw) return (char *)h-3; return 0; } #define MAX(a,b) ((a)>(b)?(a):(b)) #define MIN(a,b) ((a)<(b)?(a):(b)) #define BITOP(a,b,op) \ ((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a)))) /* * Two Way string search algorithm, with a bad shift table applied to the last * byte of the window. A bit array marks which entries in the shift table are * initialized to avoid fully initializing a 1kb/2kb table. * * Reference: CROCHEMORE M., PERRIN D., 1991, Two-way string-matching, * Journal of the ACM 38(3):651-675 */ static char *twoway_memmem(const unsigned char *h, const unsigned char *z, const unsigned char *n, size_t l) { size_t i, ip, jp, k, p, ms, p0, mem, mem0; size_t byteset[32 / sizeof(size_t)] = { 0 }; size_t shift[256]; /* Computing length of needle and fill shift table */ for (i=0; i n[jp+k]) { jp += k; k = 1; p = jp - ip; } else { ip = jp++; k = p = 1; } } ms = ip; p0 = p; /* And with the opposite comparison */ ip = -1; jp = 0; k = p = 1; while (jp+k ms+1) ms = ip; else p = p0; /* Periodic needle? */ if (memcmp(n, n+p, ms+1)) { mem0 = 0; p = MAX(ms, l-ms-1) + 1; } else mem0 = l-p; mem = 0; /* Search loop */ for (;;) { /* If remainder of haystack is shorter than needle, done */ if (z-h < l) return 0; /* Check last byte first; advance by shift on mismatch */ if (BITOP(byteset, h[l-1], &)) { k = l-shift[h[l-1]]; if (k) { if (mem0 && mem && k < p) k = l-p; h += k; mem = 0; continue; } } else { h += l; mem = 0; continue; } /* Compare right half */ for (k=MAX(ms+1,mem); kmem && n[k-1] == h[k-1]; k--); if (k <= mem) return (char *)h; h += p; mem = mem0; } } void * fallback_memmem(const void *h0, size_t k, const void *n0, size_t l) { const unsigned char *h = h0, *n = n0; /* Return immediately on empty needle */ if (!l) return (void *)h; /* Return immediately when needle is longer than haystack */ if (k #include void R_init_webutils(DllInfo* info) { R_registerRoutines(info, NULL, NULL, NULL, NULL); R_useDynamicSymbols(info, TRUE); } webutils/NAMESPACE0000644000176200001440000000043114677335714013346 0ustar liggesusers# Generated by roxygen2: do not edit by hand export(demo_httpuv) export(demo_rhttpd) export(parse_http) export(parse_multipart) export(parse_query) importFrom(jsonlite,fromJSON) useDynLib(webutils,R_split_boundary) useDynLib(webutils,R_split_string) useDynLib(webutils,R_unquote) webutils/LICENSE0000644000176200001440000000005114677505072013126 0ustar liggesusersYEAR: 2017 COPYRIGHT HOLDER: Jeroen Ooms webutils/inst/0000755000176200001440000000000014677335714013106 5ustar liggesuserswebutils/inst/testpage.html0000644000176200001440000000270714677335714015616 0ustar liggesusers Multipart test page

multipart/form-data test

A simple form to test the R multipart/form-data parser.

webutils/man/0000755000176200001440000000000014677335714012704 5ustar liggesuserswebutils/man/parse_http.Rd0000644000176200001440000000212614677335714015345 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/parse_http.R \name{parse_http} \alias{parse_http} \title{Parse http request} \usage{ parse_http(body, content_type, ...) } \arguments{ \item{body}{request body of the http request} \item{content_type}{content-type http request header as specified by the client} \item{...}{additional arguments passed to parser function} } \description{ Parse the body of a http request, based on the \code{Content-Type} request header. Currently supports the three most important content types: \code{application/x-www-form-urlencoded} with \code{\link[=parse_query]{parse_query()}}, \code{multipart/form-data} with \code{\link[=parse_multipart]{parse_multipart()}}, and \code{application/json} with \code{\link[jsonlite:fromJSON]{jsonlite::fromJSON()}}. } \examples{ # Parse json encoded payload: parse_http('{"foo":123, "bar":true}', 'application/json') # Parse url-encoded payload parse_http("foo=1\%2B1\%3D2&bar=yin\%26yang", "application/x-www-form-urlencoded") \dontrun{use demo app to parse multipart/form-data payload demo_rhttpd() } } webutils/man/demo_rhttpd.Rd0000644000176200001440000000060414677335714015504 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/demo_rhttpd.R \name{demo_rhttpd} \alias{demo_rhttpd} \title{Demo multipart parser with rhttpd} \usage{ demo_rhttpd() } \description{ Starts the Rhttpd web server and hosts a simple form including a file upload to demo the multipart parser. } \seealso{ Other demo: \code{\link{demo_httpuv}()} } \concept{demo} webutils/man/demo_httpuv.Rd0000644000176200001440000000072314677335714015533 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/demo_httpuv.R \name{demo_httpuv} \alias{demo_httpuv} \title{Demo multipart parser with httpuv} \usage{ demo_httpuv(port = 9359) } \arguments{ \item{port}{which port number to run the http server} } \description{ Starts the httpuv web server and hosts a simple form including a file upload to demo the multipart parser. } \seealso{ Other demo: \code{\link{demo_rhttpd}()} } \concept{demo} webutils/man/parse_multipart.Rd0000644000176200001440000000226214677335714016410 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/parse_multipart.R \name{parse_multipart} \alias{parse_multipart} \title{Parse a multipart/form-data request} \usage{ parse_multipart(body, boundary) } \arguments{ \item{body}{body of the HTTP request. Must be raw or character vector.} \item{boundary}{boundary string as specified in the \code{Content-Type} request header.} } \description{ Parse a multipart/form-data request, which is usually generated from a HTML form submission. The parameters can include both text values as well as binary files. They can be distinguished from the presence of a \code{filename} attribute. } \details{ A multipart/form-data request consists of a single body which contains one or more values plus meta-data, separated using a boundary string. This boundary string is chosen by the client (e.g. the browser) and specified in the \code{Content-Type} header of the HTTP request. There is no escaping; it is up to the client to choose a boundary string that does not appear in one of the values. The parser is written in pure R, but still pretty fast because it uses the regex engine. } \examples{ \dontrun{example form demo_rhttpd() } } webutils/man/parse_query.Rd0000644000176200001440000000125514677335714015535 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/parse_query.R \name{parse_query} \alias{parse_query} \title{Parse query string} \usage{ parse_query(query) } \arguments{ \item{query}{a url-encoded query string} } \description{ Parse http parameters from a query string. This includes unescaping of url-encoded values. } \details{ For http GET requests, the query string is specified in the URL after the question mark. For http POST or PUT requests, the query string can be used in the request body when the \code{Content-Type} header is set to \code{application/x-www-form-urlencoded}. } \examples{ q <- "foo=1\%2B1\%3D2&bar=yin\%26yang" parse_query(q) } webutils/DESCRIPTION0000644000176200001440000000170014677727225013637 0ustar liggesusersPackage: webutils Type: Package Title: Utility Functions for Developing Web Applications Version: 1.2.2 Authors@R: person("Jeroen", "Ooms", role = c("aut", "cre"), email = "jeroenooms@gmail.com", comment = c(ORCID = "0000-0002-4035-0289")) Description: Parses http request data in application/json, multipart/form-data, or application/x-www-form-urlencoded format. Includes example of hosting and parsing html form data in R using either 'httpuv' or 'Rhttpd'. License: MIT + file LICENSE URL: https://jeroen.r-universe.dev/webutils BugReports: https://github.com/jeroen/webutils/issues Imports: curl (>= 2.5), jsonlite Suggests: httpuv, testthat RoxygenNote: 7.3.2.9000 Language: en-US Encoding: UTF-8 NeedsCompilation: yes Packaged: 2024-10-03 14:13:23 UTC; jeroen Author: Jeroen Ooms [aut, cre] () Maintainer: Jeroen Ooms Repository: CRAN Date/Publication: 2024-10-04 09:00:05 UTC