PK!`=,, cls/basic.sonuȯELF>` @%@8@||      $$Ptd,,QtdRtd  PPGNUXgibKβZ # @ BE|qX H  u a 8 &R"_P! rX! fP!  H  __gmon_start___init_fini_ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalize_Jv_RegisterClassesgetopt_longoptargnl_cli_cls_parse_ematchrtnl_basic_set_ematchrtnl_tc_str2handlertnl_basic_set_targetputsexitnl_geterrornl_cli_fatal__stack_chk_failnl_cli_tc_registernl_cli_tc_unregisterlibpthread.so.0libm.so.6libc.so.6_edata__bss_start_endbasic.soGLIBC_2.4GLIBC_2.2.5Uii ui  0  p    `      !  8! p           ( 0 8 @ H  P  X  `  h p x  HH HtH5 % @% h% h% h%z h%r h%j h%b h%Z hp%R h`%J h P%B h @%: h 0%2 h %* h H= @H= @H H= UH)HHw]H, Ht]@H H= UH)HHHH?HHu]H Ht]H@=Y u'H= UHt H= =h]0 @f.H= t&H HtUH= H]WKf.AWAVAUIATAUHSHdH%(HD$1H\$IH  HIHDD$ht_tt*euH LH0#LHfDH LH8Ax/4$LvH=t1DAHH H5FDH13몐HD$dH3%(uH[]A\A]A^A_^RGK 8pOC tN=$"t6M}(G=c\J%8LCxW!gȵKeAV;7չz uC_hA8ֈ︡N} /I3Ȇގ i~3H7͞z8f@ X"<'B+[%Ld`b5'eM4 ԉ &'0lr@4ܪA0 xɘap~{rvX87q%|# [gYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.text.fini.rodata.eh_frame_hdr.eh_frame.init_array.fini_array.jcr.data.rel.ro.dynamic.got.got.plt.data.bss.gnu_debuglink.gnu_debugdata $o8( ((X08o2EoHH0Txx^BP hH H cp p n` ` 4t z2 ,      0  P! P!P!d!,$PK!FVsXX cls/cgroup.sonuȯELF> @X@8@  `h  $$Ptd ,,QtdRtd PPGNU3cB<ߖl @ BE|qX ( u a 8 R" 1 %  ( __gmon_start___init_fini_ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalize_Jv_RegisterClassesgetopt_longputsexitoptargnl_cli_cls_parse_ematchrtnl_cgroup_set_ematch__stack_chk_failnl_cli_tc_registernl_cli_tc_unregisterlibpthread.so.0libm.so.6libc.so.6_edata__bss_start_endcgroup.soGLIBC_2.4GLIBC_2.2.5ii @ui J                         ( 0 8 @  H  P  X ` HH HtcH5 % @% h% h% h% h% h% h% h%z hp%r h`%j h PH= @H= D@H H= UH)HHw]H Ht]@H H= UH)HHHH?HHu]Ho Ht]H@=y u'H=W UHt H=* =h]P @f.H= t&H HtUH= H]WKf.AUIATAUHSHdH%(HD$1H\$H A HIHDD$4t?ethuH=v1RfHQ LH0LH#뙐HD$dH3%(u H[]A\A]HHhe:helpematchcgroupUsage: nl-cls-add [...] cgroup [OPTIONS]... OPTIONS -h, --help Show this help text. -e, --ematch=EXPR Ematch expression EXAMPLE nl-cls-add --dev=eth0 --parent=q_root cgroup;,HHXXpzRx $HFJ w?;*3$"<DBED D(D@ (A ABBA  x   6 (   o ( V  8h ooovo fv h e  cgroup.so.debugg7zXZִF!t/ ]?Eh=ڊ2Ns\ٕv%wPz<ڗ\L>3RɹrwCD5e>B4˽S-)}{Y` (4C/n7y)R8K)g7{23,wVN}E 6Μ"wyU֬4&Α4o}f1oZ&% {%c3Vnm8څF{> jJS)0Һ:^ :;X%C8-"!~l <4\e7ۚ řrr')me{Mޟc 'alo@'Xg,6`ʆjE_]cV@gN@vڨٷdKVb;TZj"1z R rҭ+;;g *B_^S) H&ا?n) hܬmRu!gdƐ-R˭:wvHt:_T;4p\: 瑥IŤ|c)ķi,|^k'zXQU f᫃)"}{fG)/ (\c)ѠixA.C ~lIZun-θ7!4z{Iרv!gh~sي<Nu-M0D9I-:iYvqsqϏ\)sptc;i̳} yy!jgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.text.fini.rodata.eh_frame_hdr.eh_frame.init_array.fini_array.jcr.data.rel.ro.dynamic.got.got.plt.data.bss.gnu_debuglink.gnu_debugdata $o8( ((0  V8ovv*Eo0Th^B88 h((cPPn t z2  ,       0 h   $,PPK!i*  qdisc/blackhole.sonuȯELF>@ @8@      $$Ptd8 8 8 ,,QtdRtd HHGNUmOn^]'ד%ﶠ}  @ BE|qX  u a 8 R"     D __gmon_start___init_fini_ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalize_Jv_RegisterClassesgetopt_longputs__stack_chk_failnl_cli_tc_registernl_cli_tc_unregisterlibpthread.so.0libm.so.6libc.so.6_edata__bss_start_endblackhole.soGLIBC_2.4GLIBC_2.2.5ii ui    @   ` R  W            ( 0 8 @  H  HH Ht[H5 % @% h% h% h% h% h% h% hH= @H= t@H H= UH)HHw]H Ht]@H H= UH)HHHH?HHu]H Ht]H@= u'H= UHt H= =h]` @f.H=P t&HW HtUH=: H]WKf.ATAUHSHdH%(HD$1H\$htCH l HUIHDD$_uHD$dH3%(uH[]A\ÐH=1HHhhelpblackholeUsage: nl-qdisc-add [...] blackhole [OPTIONS]... OPTIONS --help Show this help text. EXAMPLE # Drop all outgoing packets on eth1 nl-qdisc-add --dev=eth1 --parent=root blackhole;,HxpzRx $FJ w?;*3$"4DBDD D0\  AABB |  @   D   o(   h08 oooo FVfvR hW blackhole.so.debugW7zXZִF!t/ ]?Eh=ڊ2N^ ުEj pjx r-ܾqd6K^sˑ }L>w2( 6h҅|39u0Vgm' Kks㶼j\S )-P8 ˇ{ߟyIZ\CSMa}me5TU\H+=6t'94tEm䶘.1ɨN,oҿZ\b>YʡH czoc[ѤGjP JmKRT`tj.r G svFw&kdk`i*]hjD?Uݠ3[-I6O9s< edL[P.J [4EkMv#)4BmEQVe:-TYe!jI  > evdfk(ٴF/b!b\I9Q\=7RID:V6H> W_˚OVޜƨHƜ$V5Ӑ}_18G(ߖ߁$h(kkgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.text.fini.rodata.eh_frame_hdr.eh_frame.init_array.fini_array.jcr.data.rel.ro.dynamic.got.got.plt.data.bss.gnu_debuglink.gnu_debugdata $o8( ((08o"Eo0T008^Bhh hc00ntD D z2P P 8 8 ,h h       ( P` `p  0PK!6S,,qdisc/fq_codel.sonuȯELF> @%@8@,,      $$PtdHHH,,QtdRtd  PPGNUZknv[6d,v)D6_ @ BE|qX K :u a 8 ^R"! ! !    __gmon_start___init_fini_ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalize_Jv_RegisterClassesgetopt_longoptargnl_cli_parse_u32rtnl_qdisc_fq_codel_set_targetrtnl_qdisc_fq_codel_set_limitputsrtnl_qdisc_fq_codel_set_flowsrtnl_qdisc_fq_codel_set_intervalrtnl_qdisc_fq_codel_set_quantum__stack_chk_failnl_cli_tc_registernl_cli_tc_unregisterlibpthread.so.0libm.so.6libc.so.6_edata__bss_start_endfq_codel.soGLIBC_2.4GLIBC_2.2.5ii ui  p    0        % ! + ! 4 `! ; x!            ( 0 8 @ H  P  X  `  h p x HH5 HtH5B %D @%B h%: h%2 h%* h%" h% h% h%  hp% h`% h P% h @% h 0% h H= @H= $@H H= UH)HHw]H Ht]@H H= UH)HHHH?HHu]H Ht]H@=Y u'H= UHt H= =h]0 @f.H=X t&Hg HtUH=B H]WKf.AUIATAUHSHdH%(HD$1H\$H  H"IHDD$GWHʺz7׌&c %uНk2yqF^7q Tv0]A*_LOQ#'gʪҪ_/U)/-uKO1vWP\|^ L * N?:]{Ƹ.ztgߣ \"=jhE>۳;Ѿ&-9-J#r+W8oAz%!7' H嚸+AԼF<0~SgOy5דӐ.x?!:h3ԸЙ wJ꼰E$( @ N+eή?ku坳 $X\͋PLLs =@6O)Κ< Dm9e* M<-aa>sfc`;5>I`B5vNM6\jgެ7蟨@֖Lvr[z = ̊l KxwK^$FoO0`]"g'WJyXܷ1u eYmR"?],J%Ġ(R7B=zegYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.text.fini.rodata.eh_frame_hdr.eh_frame.init_array.fini_array.jcr.data.rel.ro.dynamic.got.got.plt.data.bss.gnu_debuglink.gnu_debugdata $o8( ((@0hh8o::0Eopp0T^Bhh8 h c n ct  z2  8HH,xx      0   ! !!!0$PK!PPqdisc/bfifo.sonuȯELF> @P@8@\ \  `h  $$Ptdh h h ,,QtdRtd PPGNU/K/= V  @ BE|qX ( u a 8 R" 0 $  ( __gmon_start___init_fini_ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalize_Jv_RegisterClassesgetopt_longoptargnl_size2intrtnl_qdisc_fifo_set_limitputsnl_cli_fatal__stack_chk_failnl_cli_tc_registernl_cli_tc_unregisterlibpthread.so.0libm.so.6libc.so.6_edata__bss_start_endbfifo.soGLIBC_2.4GLIBC_2.2.5ii >ui H                           ( 0 8 @ H  P  X ` HH HtH5 % @% h% h% h% h% h% h% h%z hp%r h`%j h PH= @H= D@H H= UH)HHw]H Ht]@H H= UH)HHHH?HHu]Ho Ht]H@=y u'H=W UHt H=* =h]P @f.H= t&H HtUH= H]WKf.AWAVIAUATAUHSHdH%(HD$1H\$H = HIHDD$@t?ht.=uL=` I?`IxADL@H=iHD$dH3%(u)H[]A\A]A^A_DIH5^1HHhhelplimitbfifoUsage: nl-qdisc-add [...] bfifo [OPTIONS]... OPTIONS --help Show this help text. --limit=LIMIT Maximum queue length in number of bytes. EXAMPLE # Attach bfifo with a 4KB bytes limit to eth1 nl-qdisc-add --dev=eth1 --parent=root bfifo --limit=4096Unable to parse bfifo limit "%s": Invalid format.;,HpzRx $FJ w?;*3$"LD0BBE B(D0D8DP 8A0A(B BBBF     5 (   o ( T  8h oooto fv h   bfifo.so.debugK7zXZִF!t/ ]?Eh=ڊ2Ns\ٕv%wPz<ڗw!C"壻nKM|ؔx|nwY:-^ils3@βxǂT;ssi1TvrDBdY T%p<K~47k1O_4q Jcۇ3 `&ӥE_olCt(=Ԃ:Lj ՜QBHYQ4#w YrX4R&-{-K+ ɶ'HCߡHhi7փ_?_"1KzbwBߞ^w,04QT8} B5ѩpƳꖎ,:-j t1ǀjN ]x+-+ D`}eWd^a_`n ]ND]jr: Ĺ+qF#KؐIX6u")-,zC~Z l=]"sKoXjY9 [c,ƶӭjՉދ9ɫ,%1TяFJS]#rJLhLS΍q<^e03{@}M1!Y }_pO_EF[q$*#$YCWoWbQo[<]ڡWzOXN8Rc=:-Y$cEc~gYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.text.fini.rodata.eh_frame_hdr.eh_frame.init_array.fini_array.jcr.data.rel.ro.dynamic.got.got.plt.data.bss.gnu_debuglink.gnu_debugdata $o8( ((0  T8ott*Eo0Th^B88 h((cPPn t z2 xh h ,       0 h   $(LPK!K00qdisc/pfifo.sonuȯELF>@0@8@  @H  $$Ptd ,,QtdRtd PPGNU x ʃ<}+} @ BE|qX  u a 8 R" (    l __gmon_start___init_fini_ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalize_Jv_RegisterClassesgetopt_longoptargnl_cli_parse_u32rtnl_qdisc_fifo_set_limitputs__stack_chk_failnl_cli_tc_registernl_cli_tc_unregisterlibpthread.so.0libm.so.6libc.so.6_edata__bss_start_endpfifo.soGLIBC_2.4GLIBC_2.2.5 ii 6ui @   @   ` z                    ( 0 8 @ H  P  X HH Ht{H5 % @% h% h% h% h% h% h% h% hp% h`H=  @H= T@H  H= UH)HHw]H Ht]@H H= UH)HHHH?HHu]H Ht]H@= u'H= UHt H=z =h] @f.H=H t&HW HtUH=2 H]WKf.AUIATAUHSHdH%(HD$1H\$H q HIHDD$Tt;ht*=uH H8L:H=IHD$dH3%(u H[]A\A]HHhhelplimitpfifoUsage: nl-qdisc-add [...] pfifo [OPTIONS]... OPTIONS --help Show this help text. --limit=LIMIT Maximum queue length in number of packets. EXAMPLE # Attach pfifo with a 32 packet limit to eth1 nl-qdisc-add --dev=eth1 --parent=root pfifo --limit=32;,XHpzRx $FJ w?;*3$"<DBED D(D@ (A ABBA P ( @   -  l   o( L  h oooTo &6FVfvz h  pfifo.so.debugܢ z7zXZִF!t/ ]?Eh=ڊ2NN SD{SL, YKedi񣡨åoaI@ݤO̪޺%#q;/@"t#oޟ#i{:x#,Quc`SIe"4,؉L_:De$UP*G(vIZfa Dg'9ВtF. 9*&z h_E1J^l;<_+%&ɞû+VH@ _jVh٭}MX:tU kb6/uIv+`0p|#%ߒE{wC߈LSw{C\5@^3 [ψNaG$2u=lKFSqkUqBBm#{1:NozyWF#N*HWJ%*p$0A5.ܸFs@Ⱥ*əRK nw _Z]([hLHcl3)膐dCH '$z" YvyPA1ʊÆ ktg}Jfw6Q1R󚡹Bv,Q]ʴ7JU2KbwUV>P#QǢsT66x{ylqR,(Ӵ\^o[Jֺ+b提Q,`f̋ʋЎn`z똀I a$VSªQDYiYugYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.text.fini.rodata.eh_frame_hdr.eh_frame.init_array.fini_array.jcr.data.rel.ro.dynamic.got.got.plt.data.bss.gnu_debuglink.gnu_debugdata $o8( ((0L8oTT(Eo0Th^B hcntl l z2x x @ ,       0 `` `  $(PK!`qdisc/ingress.sonuȯELF>@@8@     $$Ptd   ,,QtdRtd HHGNUt;!ٌX*  @ BE|qX  u a 8 R"     D __gmon_start___init_fini_ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalize_Jv_RegisterClassesgetopt_longputs__stack_chk_failnl_cli_tc_registernl_cli_tc_unregisterlibpthread.so.0libm.so.6libc.so.6_edata__bss_start_endingress.soGLIBC_2.4GLIBC_2.2.5ii ui    @   ` R  W            ( 0 8 @  H  HH Ht[H5 % @% h% h% h% h% h% h% hH= @H= t@H H= UH)HHw]H Ht]@H H= UH)HHHH?HHu]H Ht]H@= u'H= UHt H= =h]` @f.H=P t&HW HtUH=: H]WKf.ATAUHSHdH%(HD$1H\$htCH l HUIHDD$_uHD$dH3%(uH[]A\ÐH=)HHhhelpingressUsage: nl-qdisc-add [...] ingress OPTIONS --help Show this help text. EXAMPLE # Attach ingress to eth1 nl-qdisc-add --dev=eth1 --parent=root ingress;,HpzRx $FJ w?;*3$"4D0BDD D0\  AABB |  @   D   o(   h08 oooo FVfvR hW ingress.so.debuggFz7zXZִF!t/ ]?Eh=ڊ2N^ j pjx r-`M29h HMsc.n兗4ả"'̜\"SI^՘(dW>;'g.yn+2+Ά<,_qM8CYkK8*hQ15]Qe]mKh_^( *| uJ:zS{gCZIn\q2QܗhѲ&Z_ӛcA`C tXUR-~e7]#t򳔌"[DQ){bR3&75t0ֵ6o!(K~6 -w’'F&Ds,ٱgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.text.fini.rodata.eh_frame_hdr.eh_frame.init_array.fini_array.jcr.data.rel.ro.dynamic.got.got.plt.data.bss.gnu_debuglink.gnu_debugdata $o8( ((08o"Eo0T008^Bhh hc00ntD D z2P P   ,H H       ( P` `p  ,PK!-- qdisc/hfsc.sonuȯELF> @&@8@LL      $$Ptd<<QtdRtd  PPGNU&/Y.5fd,6 @ BE|qX C (u a 8 VR"~P" X" P"   __gmon_start___init_fini_ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalize_Jv_RegisterClasses__strdupstrstrstrchrstrtoulfree__stack_chk_failgetopt_longoptargrtnl_class_hfsc_set_rscrtnl_class_hfsc_set_uscrtnl_class_hfsc_set_fscputsnl_cli_fatalnl_cli_parse_u32rtnl_qdisc_hfsc_set_defclsnl_cli_tc_registernl_cli_tc_unregisterlibpthread.so.0libm.so.6libc.so.6_edata__bss_start_endhfsc.soGLIBC_2.4GLIBC_2.2.5ii ui    @       * / ! *@! 7`! :! B! =! @!  " @8" P        ( 0 8 @ H  P  X  `  h  p x      HH HtH5 % @% h%  h% h% h% h% h% h% hp% h`% h P% h @% h 0% h % h % h% h% h% hH= HH= HH= HH= HH H= UH)HHw]HL Ht]@H H= UH)HHHH?HHu]H/ Ht]H@=y u'H= UHt H= h]P @f.H= t&H HtUH= H]WKf.AWAVAUATIUSHdH%(HD$1*HHfH5HH6xLp,LHHH LL94$AHH5 HHxLx,LhHHH LL9<$AtxHH5HHt`xHhtVH H^H9,$It=H}E,$Et$1E|$HL$dH3 %(uLH[]A\A]A^A_fDH@fHE1 DE1\lff.AWAVAAUIATE1USHHdH%(HD$81L|$H\$ H|$H  HMLDD$8=Ch=uHL HH8H|$HA@==mH HH8pH|$HA;H HH8>H|$HA fDH= HD$8dH3%(HH[]A\A]A^A_fHa HH8H|$HDEuH5i1kfH H5rH1FH H5RH1&H H52H1H H5H1Mff.AUIATAUHSHdH%(HD$1H\$H A HIHDD$t;ht*=uH$ H8LH=THD$dH3%(u H[]A\A]dHHm1:d:m2:hInvalid argumentshvhelpdefaultrtlsulhfscUsage: nl-class-add [...] hfsc [OPTIONS]... OPTIONS --help Show this help text. --ls=SC Link-sharing service curve --rt=SC Real-time service curve --sc=SC Specifiy both of the above --ul=SC Upper limit where SC := [ [ m1 bits ] d usec ] m2 bits EXAMPLE # Attach class 1:1 to hfsc qdisc 1: and use rt and ls curve nl-class-add --dev=eth1 --parent=1: --classid=1:1 hfsc --sc=m1:250,d:8,m2:100Unable to parse sc "%s": Invalid format.Usage: nl-qdisc-add [...] hfsc [OPTIONS]... OPTIONS --help Show this help text. --default=ID Default class for unclassified traffic. EXAMPLE # Create hfsc root qdisc 1: and direct unclassified traffic to class 1:10 nl-qdisc-add --dev=eth1 --parent=root --handle=1: hfsc --default=10;<8Xhx`H zRx $0FJ w?;*3$"LDBBB B(D0A8DPF 8A0A(B BBBG LpDBBE E(D0F8D@ 8A0A(B BBBJ <pBED D(D@ (A ABBA $ KP< KP @  k{   o(     oooo   & 6 F V f v   *h/*h7:B=@@Phfsc.so.debugYs7zXZִF!t/ ]?Eh=ڊ2N.gDqktg>ә}մx/i98h‹Nwo+nƷ'_+;JR6of'}x㻿8>! c5Uclk~>J?enuVO6jt9W(e3Fd,E۩᪅{|Xc$? {5gK,b)nڊ 0u8'V0*䷥g0T&\ϐ>Bռ)׫#ao&vbF鄲X3g9 r?ܮJ.v}lK-PS!,1ޞr1D)3 2+ $O J4S^+#}opO| cA4Rp˴K՝a*v6UHcnj؄4>C#}Qlݻ<,|c@u[^w >X6e;4l}_7Og(USCǨY_ۂ,Yd/KS @8#f >K K8Rzgbcjϙ@NEa/OޙיޔƌwǘtiuM8]4=!h=%]q9"H*]Dxعq G'F=?v}RF&mS2eXK+ag͜j`TUBQأ݉x^S|9e:g؇OWsoSMsA]O`/3-|Xg`L"!*S{ygYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.text.fini.rodata.eh_frame_hdr.eh_frame.init_array.fini_array.jcr.data.rel.ro.dynamic.got.got.plt.data.bss.gnu_debuglink.gnu_debugdata $o8( ((08o:Eo0T^B  h c 0n t z2<T      0   P" P"P"d"T%PK!m,, qdisc/plug.sonuȯELF> @%@8@      $$Ptd   ,,QtdRtd  PPGNUdmE֨"A# @ BE|qX  u a 8 2R"kp! ~x! rp!    __gmon_start___init_fini_ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalize_Jv_RegisterClassesgetopt_longoptargnl_cli_parse_u32rtnl_qdisc_plug_set_limitrtnl_qdisc_plug_release_indefiniteputsrtnl_qdisc_plug_bufferrtnl_qdisc_plug_release_one__stack_chk_failnl_cli_tc_registernl_cli_tc_unregisterlibpthread.so.0libm.so.6libc.so.6_edata__bss_start_endplug.soGLIBC_2.4GLIBC_2.2.5aii ui           * / 5 < ! H @! [ X!             ( 0 8 @ H  P  X  ` h p HH HtH5 % @% h% h% h% h% h% h% h% hp% h`%z h P%r h @%j h 0H=) @H= $@H@ H=2 UH)HHw]H| Ht]@H  H= UH)HHHH?HHu]H_ Ht]H@= u'H=G UHt H= =h] @f.H= t&H HtUH= H]WKf.AUIATAUHSHdH%(HD$1H\$H 1 HIHDD$Dt[=tx.ht>=uHH H8LN@=tQ=uLH=HD$dH3%(u1H[]A\A]fLKL;{HHhhelplimitbufferrelease-onerelease-indefiniteplugUsage: nl-qdisc-add [...] plug [OPTIONS]... OPTIONS --help Show this help text. --limit Maximum queue length in bytes. --buffer create a new buffer(plug) and queue incoming traffic into it. --release-one release traffic from previous buffer. --release-indefinite stop buffering and release all (buffered and new) packets. EXAMPLE # Attach plug qdisc with 32KB queue size to ifb0 nl-qdisc-add --dev=ifb0 --parent=root plug --limit=32768 # Plug network traffic arriving at ifb0 nl-qdisc-add --dev=ifb0 --parent=root --update plug --buffer # Unplug traffic arriving at ifb0 indefinitely nl-qdisc-add --dev=ifb0 --parent=root --update plug --release-indefinite # If operating in output buffering mode: # at time t=t0, create a new output buffer b0 to hold network output nl-qdisc-add --dev=ifb0 --parent=root --update plug --buffer # at time t=t1, take a checkpoint c0, create a new output buffer b1 nl-qdisc-add --dev=ifb0 --parent=root --update plug --buffer # at time t=t1+r, after c0 is committed, release b0 nl-qdisc-add --dev=ifb0 --parent=root --update plug --release-one # at time t=t2, take a checkpoint c1, create a new output buffer b2 nl-qdisc-add --dev=ifb0 --parent=root --update plug --buffer # at time t=t2+r, after c1 is committed, release b1 nl-qdisc-add --dev=ifb0 --parent=root --update plug --release-one;, HpzRx $FJ w?;*3$"<DBED D(D@ (A ABBJ H    GWa    oP(    P o ooo  V f v  * h/ 5 < H [ plug.so.debug7zXZִF!t/ ]?Eh=ڊ2Nx1ۇ [IZ9D~z;LLZ)Te!&`M~[ Ֆؔd3[^a[`U+&2O"0ݶpXџ wll,1Lrud81zerI3Z((EeՄ`I`phK!L[I7ڎZM>1y]V|dw2]zE_*RI,q)(SV+e,+vfi! 78|”Uˇ[jOiJc ǫ U1M-x!ژ":gYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.text.fini.rodata.eh_frame_hdr.eh_frame.init_array.fini_array.jcr.data.rel.ro.dynamic.got.got.plt.data.bss.gnu_debuglink.gnu_debugdata $o8( (((0PP8o.Eo  0TPP^B  h c@ @ n  t  z2( (   ,PP      0 x p! p!p!!$$PK!89.. qdisc/htb.sonuȯELF> @'@8@      $$Ptd44QtdRtd  PPGNU+n O2n8-  @ BE|qX @ k ,u=  a 8 ~QR"" " "  @  __gmon_start___init_fini_ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalize_Jv_RegisterClassesgetopt_longputsoptargnl_size2intrtnl_htb_set_cbufferrtnl_htb_set_ceilnl_cli_parse_u32rtnl_htb_set_priortnl_htb_set_rbufferrtnl_htb_set_quantumrtnl_htb_set_ratenl_cli_fatal__stack_chk_failrtnl_htb_set_defclsrtnl_htb_set_rate2quantumnl_cli_tc_registernl_cli_tc_unregisterlibpthread.so.0libm.so.6libc.so.6_edata__bss_start_endhtb.soGLIBC_2.4GLIBC_2.2.5ii ui      @     % *! .@! %`! 6! ;! C! H! N" M@" TX"  " T" @          ( 0 8 @ H  P  X  `  h p x      HH HtH5 % @% h% h% h% h% h%z h%r h%j hp%b h`%Z h P%R h @%J h 0%B h %: h %2 h%* h%" h% hH= HH= HH= HH=y HH H= UH)HHw]H Ht]@H H= UH)HHHH?HHu]H Ht]H@=i u'H= UHt H=z h]@ @f.H=H t&HW HtUH=2 H]WKf.AWAVAUIATAUHSHdH%(HD$1H\$@H I H"IHDD$t/=J=? huH=HHD$dH3%(H[]A\A]A^A_D=|k=hL=I I?HIDL=DL= I?HIDLB DH H8Lf.L= I?QHIDL DL= I?!HIDLDL=a I?HIDLZUDIH5&1IH5n1IH513IH5f1mCIH51MSAUIATAUHSHdH%(HD$1H\$H Q HIHDD$Dt=tX=t1huH=UHD$dH3%(uNH[]A\A]DH H8LzfH H8LWZHHhhvhelpr2qdefaultratequantumceilpriocbursthtbUsage: nl-class-add [...] htb [OPTIONS]... OPTIONS --help Show this help text. --rate=RATE Rate limit. --ceil=RATE Rate limit while borrowing (default: equal to --rate). --prio=PRIO Priority, lower is served first (default: 0). --quantum=SIZE Amount of bytes to serve at once (default: rate/r2q). --burst=SIZE Max charge size of rate burst buffer (default: auto). --cburst=SIZE Max charge size of ceil rate burst buffer (default: auto) EXAMPLE # Attach class 1:1 to htb qdisc 1: and rate limit it to 20mbit nl-class-add --dev=eth1 --parent=1: --classid=1:1 htb --rate=20mbitUnable to parse htb rate "%s": Invalid format.Unable to parse htb ceil rate "%s": Invalid format.Unable to parse quantum "%s": Invalid format.Unable to parse burst "%s": Invalid format.Unable to parse cburst "%s": Invalid format.Usage: nl-qdisc-add [...] htb [OPTIONS]... OPTIONS --help Show this help text. --r2q=DIV Rate to quantum divisor (default: 10) --default=ID Default class for unclassified traffic. EXAMPLE # Create htb root qdisc 1: and direct unclassified traffic to class 1:10 nl-qdisc-add --dev=eth1 --parent=root --handle=1: htb --default=10;4P (8xzRx $0FJ w?;*3$"LD}BBB E(D0D8DP 8A0A(B BBBF <BED D(D@q (A ABBF  KP KP @   @   o(    8X oooo v   & 6 F V f v %h*.%h6;CHNMT T@htb.so.debugTG7zXZִF!t/  ]?Eh=ڊ2Na oBW'G(O\9n 8U zDIBuqCBQxw1bSx ՝epTO5?G 4Zku_“(h3ѯpŔh^άDչ1?dQAj$8uFبT0WN3PQAQ!'_Z:]G~⫁la8T?-aw?P[۴2Uqg(> νjU|$?*7LG&v):d+;{uQ{-~e\8LBikUW^ N|sPK!qq#__pycache__/__init__.cpython-36.pycnu[3 . g@sdS)Nrrr/usr/lib/python3.6/__init__.pysPK!ֹ +__pycache__/chardetect.cpython-36.opt-1.pycnu[3 . g @srdZddlmZmZmZddlZddlZddlmZddl m Z ddl m Z d dd Z dd d Zed krnedS)a Script which takes one or more file paths and reports on their detected encodings Example:: % chardetect somefile someotherfile somefile: windows-1252 with confidence 0.5 someotherfile: ascii with confidence 1.0 If no paths are provided, it takes its input from stdin. )absolute_importprint_functionunicode_literalsN) __version__)PY2)UniversalDetectorstdincCs|t}x&|D]}t|}|j||jr Pq W|j|j}trP|jtj d}|drndj ||d|dSdj |SdS)z Return a string describing the probable encoding of a file or list of strings. :param lines: The lines to get the encoding of. :type lines: Iterable of bytes :param name: Name of file or collection of lines :type name: str ignoreencodingz{0}: {1} with confidence {2}Z confidencez{0}: no resultN) r bytearrayZfeeddonecloseresultrdecodesysgetfilesystemencodingformat)linesnameulinerr /usr/lib/python3.6/chardetect.pydescription_ofs     rcCstjdd}|jddtjddtr(tjntjjgd|jdd d jt d |j |}x4|j D]*}|j rxt dtjdt t||jq^WdS)z Handles command line arguments and gets things started. :param argv: List of arguments, as if specified on the command-line. If None, ``sys.argv[1:]`` is used instead. :type argv: list of str zVTakes one or more file paths and reports their detected encodings) descriptioninputz^File whose encoding we would like to determine. (default: stdin)rb*)helptypenargsdefaultz --versionversionz %(prog)s {0})actionr"z0You are running chardetect interactively. Press z8CTRL-D twice at the start of a blank line to signal the z4end of your input. If you want help, run chardetect z--help )fileNzhYou are running chardetect interactively. Press CTRL-D twice at the start of a blank line to signal the zYou are running chardetect interactively. Press CTRL-D twice at the start of a blank line to signal the end of your input. If you want help, run chardetect zYou are running chardetect interactively. Press CTRL-D twice at the start of a blank line to signal the end of your input. If you want help, run chardetect --help )argparseArgumentParser add_argumentZFileTyperrrbufferrr parse_argsrisattyprintstderrrr)argvparserargsfrrrmain6s     r1__main__)r)N)__doc__Z __future__rrrr%rZchardetrZchardet.compatrZchardet.universaldetectorrrr1__name__rrrrs     PK!ֹ %__pycache__/chardetect.cpython-36.pycnu[3 . g @srdZddlmZmZmZddlZddlZddlmZddl m Z ddl m Z d dd Z dd d Zed krnedS)a Script which takes one or more file paths and reports on their detected encodings Example:: % chardetect somefile someotherfile somefile: windows-1252 with confidence 0.5 someotherfile: ascii with confidence 1.0 If no paths are provided, it takes its input from stdin. )absolute_importprint_functionunicode_literalsN) __version__)PY2)UniversalDetectorstdincCs|t}x&|D]}t|}|j||jr Pq W|j|j}trP|jtj d}|drndj ||d|dSdj |SdS)z Return a string describing the probable encoding of a file or list of strings. :param lines: The lines to get the encoding of. :type lines: Iterable of bytes :param name: Name of file or collection of lines :type name: str ignoreencodingz{0}: {1} with confidence {2}Z confidencez{0}: no resultN) r bytearrayZfeeddonecloseresultrdecodesysgetfilesystemencodingformat)linesnameulinerr /usr/lib/python3.6/chardetect.pydescription_ofs     rcCstjdd}|jddtjddtr(tjntjjgd|jdd d jt d |j |}x4|j D]*}|j rxt dtjdt t||jq^WdS)z Handles command line arguments and gets things started. :param argv: List of arguments, as if specified on the command-line. If None, ``sys.argv[1:]`` is used instead. :type argv: list of str zVTakes one or more file paths and reports their detected encodings) descriptioninputz^File whose encoding we would like to determine. (default: stdin)rb*)helptypenargsdefaultz --versionversionz %(prog)s {0})actionr"z0You are running chardetect interactively. Press z8CTRL-D twice at the start of a blank line to signal the z4end of your input. If you want help, run chardetect z--help )fileNzhYou are running chardetect interactively. Press CTRL-D twice at the start of a blank line to signal the zYou are running chardetect interactively. Press CTRL-D twice at the start of a blank line to signal the end of your input. If you want help, run chardetect zYou are running chardetect interactively. Press CTRL-D twice at the start of a blank line to signal the end of your input. If you want help, run chardetect --help )argparseArgumentParser add_argumentZFileTyperrrbufferrr parse_argsrisattyprintstderrrr)argvparserargsfrrrmain6s     r1__main__)r)N)__doc__Z __future__rrrr%rZchardetrZchardet.compatrZchardet.universaldetectorrrr1__name__rrrrs     PK!_ݭ chardetect.pynu[#!/usr/bin/env python """ Script which takes one or more file paths and reports on their detected encodings Example:: % chardetect somefile someotherfile somefile: windows-1252 with confidence 0.5 someotherfile: ascii with confidence 1.0 If no paths are provided, it takes its input from stdin. """ from __future__ import absolute_import, print_function, unicode_literals import argparse import sys from chardet import __version__ from chardet.compat import PY2 from chardet.universaldetector import UniversalDetector def description_of(lines, name='stdin'): """ Return a string describing the probable encoding of a file or list of strings. :param lines: The lines to get the encoding of. :type lines: Iterable of bytes :param name: Name of file or collection of lines :type name: str """ u = UniversalDetector() for line in lines: line = bytearray(line) u.feed(line) # shortcut out of the loop to save reading further - particularly useful if we read a BOM. if u.done: break u.close() result = u.result if PY2: name = name.decode(sys.getfilesystemencoding(), 'ignore') if result['encoding']: return '{0}: {1} with confidence {2}'.format(name, result['encoding'], result['confidence']) else: return '{0}: no result'.format(name) def main(argv=None): """ Handles command line arguments and gets things started. :param argv: List of arguments, as if specified on the command-line. If None, ``sys.argv[1:]`` is used instead. :type argv: list of str """ # Get command line arguments parser = argparse.ArgumentParser( description="Takes one or more file paths and reports their detected \ encodings") parser.add_argument('input', help='File whose encoding we would like to determine. \ (default: stdin)', type=argparse.FileType('rb'), nargs='*', default=[sys.stdin if PY2 else sys.stdin.buffer]) parser.add_argument('--version', action='version', version='%(prog)s {0}'.format(__version__)) args = parser.parse_args(argv) for f in args.input: if f.isatty(): print("You are running chardetect interactively. Press " + "CTRL-D twice at the start of a blank line to signal the " + "end of your input. If you want help, run chardetect " + "--help\n", file=sys.stderr) print(description_of(f, f.name)) if __name__ == '__main__': main() PK!̬iicli.hnu[/* +----------------------------------------------------------------------+ | PHP Version 7 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2018 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Johannes Schlueter | +----------------------------------------------------------------------+ */ /* $Id$ */ #ifndef CLI_H #define CLI_H #ifdef PHP_WIN32 # define PHP_CLI_API __declspec(dllexport) #elif defined(__GNUC__) && __GNUC__ >= 4 # define PHP_CLI_API __attribute__ ((visibility("default"))) #else # define PHP_CLI_API #endif extern PHP_CLI_API size_t sapi_cli_single_write(const char *str, size_t str_length); typedef struct { size_t (*cli_shell_write)(const char *str, size_t str_length); size_t (*cli_shell_ub_write)(const char *str, size_t str_length); int (*cli_shell_run)(void); } cli_shell_callbacks_t; extern PHP_CLI_API cli_shell_callbacks_t *php_cli_get_shell_callbacks(); #endif /* CLI_H */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ PK!1]>>php_cli_process_title.hnu[/* +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2016 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Keyur Govande (kgovande@gmail.com) | +----------------------------------------------------------------------+ */ /* $Id$ */ #ifndef PHP_PS_TITLE_HEADER #define PHP_PS_TITLE_HEADER ZEND_BEGIN_ARG_INFO(arginfo_cli_set_process_title, 0) ZEND_ARG_INFO(0, title) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO(arginfo_cli_get_process_title, 0) ZEND_END_ARG_INFO() PHP_FUNCTION(cli_set_process_title); PHP_FUNCTION(cli_get_process_title); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ PK!uRs php_cli.cnu[/* +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2016 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Edin Kadribasic | | Marcus Boerger | | Johannes Schlueter | | Parts based on CGI SAPI Module by | | Rasmus Lerdorf, Stig Bakken and Zeev Suraski | +----------------------------------------------------------------------+ */ /* $Id$ */ #include "php.h" #include "php_globals.h" #include "php_variables.h" #include "zend_hash.h" #include "zend_modules.h" #include "zend_interfaces.h" #include "ext/reflection/php_reflection.h" #include "SAPI.h" #include #include "php.h" #ifdef PHP_WIN32 #include "win32/time.h" #include "win32/signal.h" #include #endif #if HAVE_SYS_TIME_H #include #endif #if HAVE_UNISTD_H #include #endif #if HAVE_SIGNAL_H #include #endif #if HAVE_SETLOCALE #include #endif #include "zend.h" #include "zend_extensions.h" #include "php_ini.h" #include "php_globals.h" #include "php_main.h" #include "fopen_wrappers.h" #include "ext/standard/php_standard.h" #include "cli.h" #ifdef PHP_WIN32 #include #include #include "win32/php_registry.h" #endif #if HAVE_SIGNAL_H #include #endif #ifdef __riscos__ #include #endif #include "zend_compile.h" #include "zend_execute.h" #include "zend_highlight.h" #include "zend_indent.h" #include "zend_exceptions.h" #include "php_getopt.h" #ifndef PHP_CLI_WIN32_NO_CONSOLE #include "php_cli_server.h" #endif #include "ps_title.h" #include "php_cli_process_title.h" #ifndef PHP_WIN32 # define php_select(m, r, w, e, t) select(m, r, w, e, t) #else # include "win32/select.h" #endif #if defined(PHP_WIN32) && defined(HAVE_OPENSSL) # include "openssl/applink.c" #endif PHPAPI extern char *php_ini_opened_path; PHPAPI extern char *php_ini_scanned_path; PHPAPI extern char *php_ini_scanned_files; #ifndef O_BINARY #define O_BINARY 0 #endif #define PHP_MODE_STANDARD 1 #define PHP_MODE_HIGHLIGHT 2 #define PHP_MODE_INDENT 3 #define PHP_MODE_LINT 4 #define PHP_MODE_STRIP 5 #define PHP_MODE_CLI_DIRECT 6 #define PHP_MODE_PROCESS_STDIN 7 #define PHP_MODE_REFLECTION_FUNCTION 8 #define PHP_MODE_REFLECTION_CLASS 9 #define PHP_MODE_REFLECTION_EXTENSION 10 #define PHP_MODE_REFLECTION_EXT_INFO 11 #define PHP_MODE_REFLECTION_ZEND_EXTENSION 12 #define PHP_MODE_SHOW_INI_CONFIG 13 cli_shell_callbacks_t cli_shell_callbacks = { NULL, NULL, NULL }; PHP_CLI_API cli_shell_callbacks_t *php_cli_get_shell_callbacks() { return &cli_shell_callbacks; } const char HARDCODED_INI[] = "html_errors=0\n" "register_argc_argv=1\n" "implicit_flush=1\n" "output_buffering=0\n" "max_execution_time=0\n" "max_input_time=-1\n\0"; const opt_struct OPTIONS[] = { {'a', 0, "interactive"}, {'B', 1, "process-begin"}, {'C', 0, "no-chdir"}, /* for compatibility with CGI (do not chdir to script directory) */ {'c', 1, "php-ini"}, {'d', 1, "define"}, {'E', 1, "process-end"}, {'e', 0, "profile-info"}, {'F', 1, "process-file"}, {'f', 1, "file"}, {'h', 0, "help"}, {'i', 0, "info"}, {'l', 0, "syntax-check"}, {'m', 0, "modules"}, {'n', 0, "no-php-ini"}, {'q', 0, "no-header"}, /* for compatibility with CGI (do not generate HTTP headers) */ {'R', 1, "process-code"}, {'H', 0, "hide-args"}, {'r', 1, "run"}, {'s', 0, "syntax-highlight"}, {'s', 0, "syntax-highlighting"}, {'S', 1, "server"}, {'t', 1, "docroot"}, {'w', 0, "strip"}, {'?', 0, "usage"},/* help alias (both '?' and 'usage') */ {'v', 0, "version"}, {'z', 1, "zend-extension"}, {10, 1, "rf"}, {10, 1, "rfunction"}, {11, 1, "rc"}, {11, 1, "rclass"}, {12, 1, "re"}, {12, 1, "rextension"}, {13, 1, "rz"}, {13, 1, "rzendextension"}, {14, 1, "ri"}, {14, 1, "rextinfo"}, {15, 0, "ini"}, {'-', 0, NULL} /* end of args */ }; static int print_module_info(zend_module_entry *module TSRMLS_DC) /* {{{ */ { php_printf("%s\n", module->name); return ZEND_HASH_APPLY_KEEP; } /* }}} */ static int module_name_cmp(const void *a, const void *b TSRMLS_DC) /* {{{ */ { Bucket *f = *((Bucket **) a); Bucket *s = *((Bucket **) b); return strcasecmp(((zend_module_entry *)f->pData)->name, ((zend_module_entry *)s->pData)->name); } /* }}} */ static void print_modules(TSRMLS_D) /* {{{ */ { HashTable sorted_registry; zend_module_entry tmp; zend_hash_init(&sorted_registry, 50, NULL, NULL, 1); zend_hash_copy(&sorted_registry, &module_registry, NULL, &tmp, sizeof(zend_module_entry)); zend_hash_sort(&sorted_registry, zend_qsort, module_name_cmp, 0 TSRMLS_CC); zend_hash_apply(&sorted_registry, (apply_func_t) print_module_info TSRMLS_CC); zend_hash_destroy(&sorted_registry); } /* }}} */ static int print_extension_info(zend_extension *ext, void *arg TSRMLS_DC) /* {{{ */ { php_printf("%s\n", ext->name); return ZEND_HASH_APPLY_KEEP; } /* }}} */ static int extension_name_cmp(const zend_llist_element **f, const zend_llist_element **s TSRMLS_DC) /* {{{ */ { return strcmp(((zend_extension *)(*f)->data)->name, ((zend_extension *)(*s)->data)->name); } /* }}} */ static void print_extensions(TSRMLS_D) /* {{{ */ { zend_llist sorted_exts; zend_llist_copy(&sorted_exts, &zend_extensions); sorted_exts.dtor = NULL; zend_llist_sort(&sorted_exts, extension_name_cmp TSRMLS_CC); zend_llist_apply(&sorted_exts, (llist_apply_func_t) print_extension_info TSRMLS_CC); zend_llist_destroy(&sorted_exts); } /* }}} */ #ifndef STDOUT_FILENO #define STDOUT_FILENO 1 #endif static inline int sapi_cli_select(int fd TSRMLS_DC) { fd_set wfd, dfd; struct timeval tv; int ret; FD_ZERO(&wfd); FD_ZERO(&dfd); PHP_SAFE_FD_SET(fd, &wfd); tv.tv_sec = FG(default_socket_timeout); tv.tv_usec = 0; ret = php_select(fd+1, &dfd, &wfd, &dfd, &tv); return ret != -1; } PHP_CLI_API size_t sapi_cli_single_write(const char *str, uint str_length TSRMLS_DC) /* {{{ */ { #ifdef PHP_WRITE_STDOUT long ret; #else size_t ret; #endif if (cli_shell_callbacks.cli_shell_write) { size_t shell_wrote; shell_wrote = cli_shell_callbacks.cli_shell_write(str, str_length TSRMLS_CC); if (shell_wrote > -1) { return shell_wrote; } } #ifdef PHP_WRITE_STDOUT do { ret = write(STDOUT_FILENO, str, str_length); } while (ret <= 0 && errno == EAGAIN && sapi_cli_select(STDOUT_FILENO TSRMLS_CC)); if (ret <= 0) { return 0; } return ret; #else ret = fwrite(str, 1, MIN(str_length, 16384), stdout); return ret; #endif } /* }}} */ static int sapi_cli_ub_write(const char *str, uint str_length TSRMLS_DC) /* {{{ */ { const char *ptr = str; uint remaining = str_length; size_t ret; if (!str_length) { return 0; } if (cli_shell_callbacks.cli_shell_ub_write) { int ub_wrote; ub_wrote = cli_shell_callbacks.cli_shell_ub_write(str, str_length TSRMLS_CC); if (ub_wrote > -1) { return ub_wrote; } } while (remaining > 0) { ret = sapi_cli_single_write(ptr, remaining TSRMLS_CC); if (!ret) { #ifndef PHP_CLI_WIN32_NO_CONSOLE php_handle_aborted_connection(); #endif break; } ptr += ret; remaining -= ret; } return (ptr - str); } /* }}} */ static void sapi_cli_flush(void *server_context) /* {{{ */ { /* Ignore EBADF here, it's caused by the fact that STDIN/STDOUT/STDERR streams * are/could be closed before fflush() is called. */ if (fflush(stdout)==EOF && errno!=EBADF) { #ifndef PHP_CLI_WIN32_NO_CONSOLE php_handle_aborted_connection(); #endif } } /* }}} */ static char *php_self = ""; static char *script_filename = ""; static void sapi_cli_register_variables(zval *track_vars_array TSRMLS_DC) /* {{{ */ { unsigned int len; char *docroot = ""; /* In CGI mode, we consider the environment to be a part of the server * variables */ php_import_environment_variables(track_vars_array TSRMLS_CC); /* Build the special-case PHP_SELF variable for the CLI version */ len = strlen(php_self); if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &php_self, len, &len TSRMLS_CC)) { php_register_variable("PHP_SELF", php_self, track_vars_array TSRMLS_CC); } if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_NAME", &php_self, len, &len TSRMLS_CC)) { php_register_variable("SCRIPT_NAME", php_self, track_vars_array TSRMLS_CC); } /* filenames are empty for stdin */ len = strlen(script_filename); if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_FILENAME", &script_filename, len, &len TSRMLS_CC)) { php_register_variable("SCRIPT_FILENAME", script_filename, track_vars_array TSRMLS_CC); } if (sapi_module.input_filter(PARSE_SERVER, "PATH_TRANSLATED", &script_filename, len, &len TSRMLS_CC)) { php_register_variable("PATH_TRANSLATED", script_filename, track_vars_array TSRMLS_CC); } /* just make it available */ len = 0U; if (sapi_module.input_filter(PARSE_SERVER, "DOCUMENT_ROOT", &docroot, len, &len TSRMLS_CC)) { php_register_variable("DOCUMENT_ROOT", docroot, track_vars_array TSRMLS_CC); } } /* }}} */ static void sapi_cli_log_message(char *message TSRMLS_DC) /* {{{ */ { fprintf(stderr, "%s\n", message); } /* }}} */ static int sapi_cli_deactivate(TSRMLS_D) /* {{{ */ { fflush(stdout); if(SG(request_info).argv0) { free(SG(request_info).argv0); SG(request_info).argv0 = NULL; } return SUCCESS; } /* }}} */ static char* sapi_cli_read_cookies(TSRMLS_D) /* {{{ */ { return NULL; } /* }}} */ static int sapi_cli_header_handler(sapi_header_struct *h, sapi_header_op_enum op, sapi_headers_struct *s TSRMLS_DC) /* {{{ */ { return 0; } /* }}} */ static int sapi_cli_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) /* {{{ */ { /* We do nothing here, this function is needed to prevent that the fallback * header handling is called. */ return SAPI_HEADER_SENT_SUCCESSFULLY; } /* }}} */ static void sapi_cli_send_header(sapi_header_struct *sapi_header, void *server_context TSRMLS_DC) /* {{{ */ { } /* }}} */ static int php_cli_startup(sapi_module_struct *sapi_module) /* {{{ */ { if (php_module_startup(sapi_module, NULL, 0)==FAILURE) { return FAILURE; } return SUCCESS; } /* }}} */ /* {{{ sapi_cli_ini_defaults */ /* overwriteable ini defaults must be set in sapi_cli_ini_defaults() */ #define INI_DEFAULT(name,value)\ Z_SET_REFCOUNT(tmp, 0);\ Z_UNSET_ISREF(tmp); \ ZVAL_STRINGL(&tmp, zend_strndup(value, sizeof(value)-1), sizeof(value)-1, 0);\ zend_hash_update(configuration_hash, name, sizeof(name), &tmp, sizeof(zval), NULL);\ static void sapi_cli_ini_defaults(HashTable *configuration_hash) { zval tmp; INI_DEFAULT("report_zend_debug", "0"); INI_DEFAULT("display_errors", "1"); } /* }}} */ /* {{{ sapi_module_struct cli_sapi_module */ static sapi_module_struct cli_sapi_module = { "cli", /* name */ "Command Line Interface", /* pretty name */ php_cli_startup, /* startup */ php_module_shutdown_wrapper, /* shutdown */ NULL, /* activate */ sapi_cli_deactivate, /* deactivate */ sapi_cli_ub_write, /* unbuffered write */ sapi_cli_flush, /* flush */ NULL, /* get uid */ NULL, /* getenv */ php_error, /* error handler */ sapi_cli_header_handler, /* header handler */ sapi_cli_send_headers, /* send headers handler */ sapi_cli_send_header, /* send header handler */ NULL, /* read POST data */ sapi_cli_read_cookies, /* read Cookies */ sapi_cli_register_variables, /* register server variables */ sapi_cli_log_message, /* Log message */ NULL, /* Get request time */ NULL, /* Child terminate */ STANDARD_SAPI_MODULE_PROPERTIES }; /* }}} */ /* {{{ arginfo ext/standard/dl.c */ ZEND_BEGIN_ARG_INFO(arginfo_dl, 0) ZEND_ARG_INFO(0, extension_filename) ZEND_END_ARG_INFO() /* }}} */ static const zend_function_entry additional_functions[] = { ZEND_FE(dl, arginfo_dl) PHP_FE(cli_set_process_title, arginfo_cli_set_process_title) PHP_FE(cli_get_process_title, arginfo_cli_get_process_title) {NULL, NULL, NULL} }; /* {{{ php_cli_usage */ static void php_cli_usage(char *argv0) { char *prog; prog = strrchr(argv0, '/'); if (prog) { prog++; } else { prog = "php"; } printf( "Usage: %s [options] [-f] [--] [args...]\n" " %s [options] -r [--] [args...]\n" " %s [options] [-B ] -R [-E ] [--] [args...]\n" " %s [options] [-B ] -F [-E ] [--] [args...]\n" " %s [options] -S : [-t docroot]\n" " %s [options] -- [args...]\n" " %s [options] -a\n" "\n" #if (HAVE_LIBREADLINE || HAVE_LIBEDIT) && !defined(COMPILE_DL_READLINE) " -a Run as interactive shell\n" #else " -a Run interactively\n" #endif " -c | Look for php.ini file in this directory\n" " -n No php.ini file will be used\n" " -d foo[=bar] Define INI entry foo with value 'bar'\n" " -e Generate extended information for debugger/profiler\n" " -f Parse and execute .\n" " -h This help\n" " -i PHP information\n" " -l Syntax check only (lint)\n" " -m Show compiled in modules\n" " -r Run PHP without using script tags \n" " -B Run PHP before processing input lines\n" " -R Run PHP for every input line\n" " -F Parse and execute for every input line\n" " -E Run PHP after processing all input lines\n" " -H Hide any passed arguments from external tools.\n" " -S : Run with built-in web server.\n" " -t Specify document root for built-in web server.\n" " -s Output HTML syntax highlighted source.\n" " -v Version number\n" " -w Output source with stripped comments and whitespace.\n" " -z Load Zend extension .\n" "\n" " args... Arguments passed to script. Use -- args when first argument\n" " starts with - or script is read from stdin\n" "\n" " --ini Show configuration file names\n" "\n" " --rf Show information about function .\n" " --rc Show information about class .\n" " --re Show information about extension .\n" " --rz Show information about Zend extension .\n" " --ri Show configuration for extension .\n" "\n" , prog, prog, prog, prog, prog, prog, prog); } /* }}} */ static php_stream *s_in_process = NULL; static void cli_register_file_handles(TSRMLS_D) /* {{{ */ { zval *zin, *zout, *zerr; php_stream *s_in, *s_out, *s_err; php_stream_context *sc_in=NULL, *sc_out=NULL, *sc_err=NULL; zend_constant ic, oc, ec; MAKE_STD_ZVAL(zin); MAKE_STD_ZVAL(zout); MAKE_STD_ZVAL(zerr); s_in = php_stream_open_wrapper_ex("php://stdin", "rb", 0, NULL, sc_in); s_out = php_stream_open_wrapper_ex("php://stdout", "wb", 0, NULL, sc_out); s_err = php_stream_open_wrapper_ex("php://stderr", "wb", 0, NULL, sc_err); if (s_in==NULL || s_out==NULL || s_err==NULL) { FREE_ZVAL(zin); FREE_ZVAL(zout); FREE_ZVAL(zerr); if (s_in) php_stream_close(s_in); if (s_out) php_stream_close(s_out); if (s_err) php_stream_close(s_err); return; } #if PHP_DEBUG /* do not close stdout and stderr */ s_out->flags |= PHP_STREAM_FLAG_NO_CLOSE; s_err->flags |= PHP_STREAM_FLAG_NO_CLOSE; #endif s_in_process = s_in; php_stream_to_zval(s_in, zin); php_stream_to_zval(s_out, zout); php_stream_to_zval(s_err, zerr); ic.value = *zin; ic.flags = CONST_CS; ic.name = zend_strndup(ZEND_STRL("STDIN")); ic.name_len = sizeof("STDIN"); ic.module_number = 0; zend_register_constant(&ic TSRMLS_CC); oc.value = *zout; oc.flags = CONST_CS; oc.name = zend_strndup(ZEND_STRL("STDOUT")); oc.name_len = sizeof("STDOUT"); oc.module_number = 0; zend_register_constant(&oc TSRMLS_CC); ec.value = *zerr; ec.flags = CONST_CS; ec.name = zend_strndup(ZEND_STRL("STDERR")); ec.name_len = sizeof("STDERR"); ec.module_number = 0; zend_register_constant(&ec TSRMLS_CC); FREE_ZVAL(zin); FREE_ZVAL(zout); FREE_ZVAL(zerr); } /* }}} */ static const char *param_mode_conflict = "Either execute direct code, process stdin or use a file.\n"; /* {{{ cli_seek_file_begin */ static int cli_seek_file_begin(zend_file_handle *file_handle, char *script_file, int *lineno TSRMLS_DC) { int c; *lineno = 1; file_handle->type = ZEND_HANDLE_FP; file_handle->opened_path = NULL; file_handle->free_filename = 0; if (!(file_handle->handle.fp = VCWD_FOPEN(script_file, "rb"))) { php_printf("Could not open input file: %s\n", script_file); return FAILURE; } file_handle->filename = script_file; /* #!php support */ c = fgetc(file_handle->handle.fp); if (c == '#' && (c = fgetc(file_handle->handle.fp)) == '!') { while (c != '\n' && c != '\r' && c != EOF) { c = fgetc(file_handle->handle.fp); /* skip to end of line */ } /* handle situations where line is terminated by \r\n */ if (c == '\r') { if (fgetc(file_handle->handle.fp) != '\n') { long pos = ftell(file_handle->handle.fp); fseek(file_handle->handle.fp, pos - 1, SEEK_SET); } } *lineno = 2; } else { rewind(file_handle->handle.fp); } return SUCCESS; } /* }}} */ static int do_cli(int argc, char **argv TSRMLS_DC) /* {{{ */ { int c; zend_file_handle file_handle; int behavior = PHP_MODE_STANDARD; char *reflection_what = NULL; volatile int request_started = 0; volatile int exit_status = 0; char *php_optarg = NULL, *orig_optarg = NULL; int php_optind = 1, orig_optind = 1; char *exec_direct=NULL, *exec_run=NULL, *exec_begin=NULL, *exec_end=NULL; char *arg_free=NULL, **arg_excp=&arg_free; char *script_file=NULL, *translated_path = NULL; int interactive=0; int lineno = 0; const char *param_error=NULL; int hide_argv = 0; zend_try { CG(in_compilation) = 0; /* not initialized but needed for several options */ EG(uninitialized_zval_ptr) = NULL; while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) { switch (c) { case 'i': /* php info & quit */ if (php_request_startup(TSRMLS_C)==FAILURE) { goto err; } request_started = 1; php_print_info(0xFFFFFFFF TSRMLS_CC); php_output_end_all(TSRMLS_C); exit_status = (c == '?' && argc > 1 && !strchr(argv[1], c)); goto out; case 'v': /* show php version & quit */ php_printf("PHP %s (%s) (built: %s %s) %s\nCopyright (c) 1997-2016 The PHP Group\n%s", PHP_VERSION, cli_sapi_module.name, __DATE__, __TIME__, #if ZEND_DEBUG && defined(HAVE_GCOV) "(DEBUG GCOV)", #elif ZEND_DEBUG "(DEBUG)", #elif defined(HAVE_GCOV) "(GCOV)", #else "", #endif get_zend_version() ); sapi_deactivate(TSRMLS_C); goto out; case 'm': /* list compiled in modules */ if (php_request_startup(TSRMLS_C)==FAILURE) { goto err; } request_started = 1; php_printf("[PHP Modules]\n"); print_modules(TSRMLS_C); php_printf("\n[Zend Modules]\n"); print_extensions(TSRMLS_C); php_printf("\n"); php_output_end_all(TSRMLS_C); exit_status=0; goto out; default: break; } } /* Set some CLI defaults */ SG(options) |= SAPI_OPTION_NO_CHDIR; php_optind = orig_optind; php_optarg = orig_optarg; while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) { switch (c) { case 'a': /* interactive mode */ if (!interactive) { if (behavior != PHP_MODE_STANDARD) { param_error = param_mode_conflict; break; } interactive=1; } break; case 'C': /* don't chdir to the script directory */ /* This is default so NOP */ break; case 'F': if (behavior == PHP_MODE_PROCESS_STDIN) { if (exec_run || script_file) { param_error = "You can use -R or -F only once.\n"; break; } } else if (behavior != PHP_MODE_STANDARD) { param_error = param_mode_conflict; break; } behavior=PHP_MODE_PROCESS_STDIN; script_file = php_optarg; break; case 'f': /* parse file */ if (behavior == PHP_MODE_CLI_DIRECT || behavior == PHP_MODE_PROCESS_STDIN) { param_error = param_mode_conflict; break; } else if (script_file) { param_error = "You can use -f only once.\n"; break; } script_file = php_optarg; break; case 'l': /* syntax check mode */ if (behavior != PHP_MODE_STANDARD) { break; } behavior=PHP_MODE_LINT; break; #if 0 /* not yet operational, see also below ... */ case '': /* generate indented source mode*/ if (behavior == PHP_MODE_CLI_DIRECT || behavior == PHP_MODE_PROCESS_STDIN) { param_error = "Source indenting only works for files.\n"; break; } behavior=PHP_MODE_INDENT; break; #endif case 'q': /* do not generate HTTP headers */ /* This is default so NOP */ break; case 'r': /* run code from command line */ if (behavior == PHP_MODE_CLI_DIRECT) { if (exec_direct || script_file) { param_error = "You can use -r only once.\n"; break; } } else if (behavior != PHP_MODE_STANDARD || interactive) { param_error = param_mode_conflict; break; } behavior=PHP_MODE_CLI_DIRECT; exec_direct=php_optarg; break; case 'R': if (behavior == PHP_MODE_PROCESS_STDIN) { if (exec_run || script_file) { param_error = "You can use -R or -F only once.\n"; break; } } else if (behavior != PHP_MODE_STANDARD) { param_error = param_mode_conflict; break; } behavior=PHP_MODE_PROCESS_STDIN; exec_run=php_optarg; break; case 'B': if (behavior == PHP_MODE_PROCESS_STDIN) { if (exec_begin) { param_error = "You can use -B only once.\n"; break; } } else if (behavior != PHP_MODE_STANDARD || interactive) { param_error = param_mode_conflict; break; } behavior=PHP_MODE_PROCESS_STDIN; exec_begin=php_optarg; break; case 'E': if (behavior == PHP_MODE_PROCESS_STDIN) { if (exec_end) { param_error = "You can use -E only once.\n"; break; } } else if (behavior != PHP_MODE_STANDARD || interactive) { param_error = param_mode_conflict; break; } behavior=PHP_MODE_PROCESS_STDIN; exec_end=php_optarg; break; case 's': /* generate highlighted HTML from source */ if (behavior == PHP_MODE_CLI_DIRECT || behavior == PHP_MODE_PROCESS_STDIN) { param_error = "Source highlighting only works for files.\n"; break; } behavior=PHP_MODE_HIGHLIGHT; break; case 'w': if (behavior == PHP_MODE_CLI_DIRECT || behavior == PHP_MODE_PROCESS_STDIN) { param_error = "Source stripping only works for files.\n"; break; } behavior=PHP_MODE_STRIP; break; case 'z': /* load extension file */ zend_load_extension(php_optarg); break; case 'H': hide_argv = 1; break; case 10: behavior=PHP_MODE_REFLECTION_FUNCTION; reflection_what = php_optarg; break; case 11: behavior=PHP_MODE_REFLECTION_CLASS; reflection_what = php_optarg; break; case 12: behavior=PHP_MODE_REFLECTION_EXTENSION; reflection_what = php_optarg; break; case 13: behavior=PHP_MODE_REFLECTION_ZEND_EXTENSION; reflection_what = php_optarg; break; case 14: behavior=PHP_MODE_REFLECTION_EXT_INFO; reflection_what = php_optarg; break; case 15: behavior = PHP_MODE_SHOW_INI_CONFIG; break; default: break; } } if (param_error) { PUTS(param_error); exit_status=1; goto err; } if (interactive) { #if (HAVE_LIBREADLINE || HAVE_LIBEDIT) && !defined(COMPILE_DL_READLINE) printf("Interactive shell\n\n"); #else printf("Interactive mode enabled\n\n"); #endif fflush(stdout); } CG(interactive) = interactive; /* only set script_file if not set already and not in direct mode and not at end of parameter list */ if (argc > php_optind && !script_file && behavior!=PHP_MODE_CLI_DIRECT && behavior!=PHP_MODE_PROCESS_STDIN && strcmp(argv[php_optind-1],"--")) { script_file=argv[php_optind]; php_optind++; } if (script_file) { if (cli_seek_file_begin(&file_handle, script_file, &lineno TSRMLS_CC) != SUCCESS) { goto err; } else { char real_path[MAXPATHLEN]; if (VCWD_REALPATH(script_file, real_path)) { translated_path = strdup(real_path); } script_filename = script_file; } } else { /* We could handle PHP_MODE_PROCESS_STDIN in a different manner */ /* here but this would make things only more complicated. And it */ /* is consitent with the way -R works where the stdin file handle*/ /* is also accessible. */ file_handle.filename = "-"; file_handle.handle.fp = stdin; } file_handle.type = ZEND_HANDLE_FP; file_handle.opened_path = NULL; file_handle.free_filename = 0; php_self = (char*)file_handle.filename; /* before registering argv to module exchange the *new* argv[0] */ /* we can achieve this without allocating more memory */ SG(request_info).argc=argc-php_optind+1; arg_excp = argv+php_optind-1; arg_free = argv[php_optind-1]; SG(request_info).path_translated = translated_path? translated_path: (char*)file_handle.filename; argv[php_optind-1] = (char*)file_handle.filename; SG(request_info).argv=argv+php_optind-1; if (php_request_startup(TSRMLS_C)==FAILURE) { *arg_excp = arg_free; fclose(file_handle.handle.fp); PUTS("Could not startup.\n"); goto err; } request_started = 1; CG(start_lineno) = lineno; *arg_excp = arg_free; /* reconstuct argv */ if (hide_argv) { int i; for (i = 1; i < argc; i++) { memset(argv[i], 0, strlen(argv[i])); } } zend_is_auto_global("_SERVER", sizeof("_SERVER")-1 TSRMLS_CC); PG(during_request_startup) = 0; switch (behavior) { case PHP_MODE_STANDARD: if (strcmp(file_handle.filename, "-")) { cli_register_file_handles(TSRMLS_C); } if (interactive && cli_shell_callbacks.cli_shell_run) { exit_status = cli_shell_callbacks.cli_shell_run(TSRMLS_C); } else { php_execute_script(&file_handle TSRMLS_CC); exit_status = EG(exit_status); } break; case PHP_MODE_LINT: exit_status = php_lint_script(&file_handle TSRMLS_CC); if (exit_status==SUCCESS) { zend_printf("No syntax errors detected in %s\n", file_handle.filename); } else { zend_printf("Errors parsing %s\n", file_handle.filename); } break; case PHP_MODE_STRIP: if (open_file_for_scanning(&file_handle TSRMLS_CC)==SUCCESS) { zend_strip(TSRMLS_C); } goto out; break; case PHP_MODE_HIGHLIGHT: { zend_syntax_highlighter_ini syntax_highlighter_ini; if (open_file_for_scanning(&file_handle TSRMLS_CC)==SUCCESS) { php_get_highlight_struct(&syntax_highlighter_ini); zend_highlight(&syntax_highlighter_ini TSRMLS_CC); } goto out; } break; #if 0 /* Zeev might want to do something with this one day */ case PHP_MODE_INDENT: open_file_for_scanning(&file_handle TSRMLS_CC); zend_indent(); zend_file_handle_dtor(file_handle.handle TSRMLS_CC); goto out; break; #endif case PHP_MODE_CLI_DIRECT: cli_register_file_handles(TSRMLS_C); if (zend_eval_string_ex(exec_direct, NULL, "Command line code", 1 TSRMLS_CC) == FAILURE) { exit_status=254; } break; case PHP_MODE_PROCESS_STDIN: { char *input; size_t len, index = 0; zval *argn, *argi; cli_register_file_handles(TSRMLS_C); if (exec_begin && zend_eval_string_ex(exec_begin, NULL, "Command line begin code", 1 TSRMLS_CC) == FAILURE) { exit_status=254; } ALLOC_ZVAL(argi); Z_TYPE_P(argi) = IS_LONG; Z_LVAL_P(argi) = index; INIT_PZVAL(argi); zend_hash_update(&EG(symbol_table), "argi", sizeof("argi"), &argi, sizeof(zval *), NULL); while (exit_status == SUCCESS && (input=php_stream_gets(s_in_process, NULL, 0)) != NULL) { len = strlen(input); while (len-- && (input[len]=='\n' || input[len]=='\r')) { input[len] = '\0'; } ALLOC_ZVAL(argn); Z_TYPE_P(argn) = IS_STRING; Z_STRLEN_P(argn) = ++len; Z_STRVAL_P(argn) = estrndup(input, len); INIT_PZVAL(argn); zend_hash_update(&EG(symbol_table), "argn", sizeof("argn"), &argn, sizeof(zval *), NULL); Z_LVAL_P(argi) = ++index; if (exec_run) { if (zend_eval_string_ex(exec_run, NULL, "Command line run code", 1 TSRMLS_CC) == FAILURE) { exit_status=254; } } else { if (script_file) { if (cli_seek_file_begin(&file_handle, script_file, &lineno TSRMLS_CC) != SUCCESS) { exit_status = 1; } else { CG(start_lineno) = lineno; php_execute_script(&file_handle TSRMLS_CC); exit_status = EG(exit_status); } } } efree(input); } if (exec_end && zend_eval_string_ex(exec_end, NULL, "Command line end code", 1 TSRMLS_CC) == FAILURE) { exit_status=254; } break; } case PHP_MODE_REFLECTION_FUNCTION: case PHP_MODE_REFLECTION_CLASS: case PHP_MODE_REFLECTION_EXTENSION: case PHP_MODE_REFLECTION_ZEND_EXTENSION: { zend_class_entry *pce = NULL; zval *arg, *ref; zend_execute_data execute_data; switch (behavior) { default: break; case PHP_MODE_REFLECTION_FUNCTION: if (strstr(reflection_what, "::")) { pce = reflection_method_ptr; } else { pce = reflection_function_ptr; } break; case PHP_MODE_REFLECTION_CLASS: pce = reflection_class_ptr; break; case PHP_MODE_REFLECTION_EXTENSION: pce = reflection_extension_ptr; break; case PHP_MODE_REFLECTION_ZEND_EXTENSION: pce = reflection_zend_extension_ptr; break; } MAKE_STD_ZVAL(arg); ZVAL_STRING(arg, reflection_what, 1); ALLOC_ZVAL(ref); object_init_ex(ref, pce); INIT_PZVAL(ref); memset(&execute_data, 0, sizeof(zend_execute_data)); EG(current_execute_data) = &execute_data; EX(function_state).function = pce->constructor; zend_call_method_with_1_params(&ref, pce, &pce->constructor, "__construct", NULL, arg); if (EG(exception)) { zval *msg = zend_read_property(zend_exception_get_default(TSRMLS_C), EG(exception), "message", sizeof("message")-1, 0 TSRMLS_CC); zend_printf("Exception: %s\n", Z_STRVAL_P(msg)); zval_ptr_dtor(&EG(exception)); EG(exception) = NULL; } else { zend_call_method_with_1_params(NULL, reflection_ptr, NULL, "export", NULL, ref); } zval_ptr_dtor(&ref); zval_ptr_dtor(&arg); break; } case PHP_MODE_REFLECTION_EXT_INFO: { int len = strlen(reflection_what); char *lcname = zend_str_tolower_dup(reflection_what, len); zend_module_entry *module; if (zend_hash_find(&module_registry, lcname, len+1, (void**)&module) == FAILURE) { if (!strcmp(reflection_what, "main")) { display_ini_entries(NULL); } else { zend_printf("Extension '%s' not present.\n", reflection_what); exit_status = 1; } } else { php_info_print_module(module TSRMLS_CC); } efree(lcname); break; } case PHP_MODE_SHOW_INI_CONFIG: { zend_printf("Configuration File (php.ini) Path: %s\n", PHP_CONFIG_FILE_PATH); zend_printf("Loaded Configuration File: %s\n", php_ini_opened_path ? php_ini_opened_path : "(none)"); zend_printf("Scan for additional .ini files in: %s\n", php_ini_scanned_path ? php_ini_scanned_path : "(none)"); zend_printf("Additional .ini files parsed: %s\n", php_ini_scanned_files ? php_ini_scanned_files : "(none)"); break; } } } zend_end_try(); out: if (request_started) { php_request_shutdown((void *) 0); } if (translated_path) { free(translated_path); } if (exit_status == 0) { exit_status = EG(exit_status); } return exit_status; err: sapi_deactivate(TSRMLS_C); zend_ini_deactivate(TSRMLS_C); exit_status = 1; goto out; } /* }}} */ /* {{{ main */ #ifdef PHP_CLI_WIN32_NO_CONSOLE int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) #else int main(int argc, char *argv[]) #endif { #ifdef ZTS void ***tsrm_ls; #endif #ifdef PHP_CLI_WIN32_NO_CONSOLE int argc = __argc; char **argv = __argv; #endif int c; int exit_status = SUCCESS; int module_started = 0, sapi_started = 0; char *php_optarg = NULL; int php_optind = 1, use_extended_info = 0; char *ini_path_override = NULL; char *ini_entries = NULL; int ini_entries_len = 0; int ini_ignore = 0; sapi_module_struct *sapi_module = &cli_sapi_module; /* * Do not move this initialization. It needs to happen before argv is used * in any way. */ argv = save_ps_args(argc, argv); cli_sapi_module.additional_functions = additional_functions; #if defined(PHP_WIN32) && defined(_DEBUG) && defined(PHP_WIN32_DEBUG_HEAP) { int tmp_flag; _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); tmp_flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); tmp_flag |= _CRTDBG_DELAY_FREE_MEM_DF; tmp_flag |= _CRTDBG_LEAK_CHECK_DF; _CrtSetDbgFlag(tmp_flag); } #endif #ifdef HAVE_SIGNAL_H #if defined(SIGPIPE) && defined(SIG_IGN) signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE in standalone mode so that sockets created via fsockopen() don't kill PHP if the remote site closes it. in apache|apxs mode apache does that for us! thies@thieso.net 20000419 */ #endif #endif #ifdef ZTS tsrm_startup(1, 1, 0, NULL); tsrm_ls = ts_resource(0); #endif #ifdef PHP_WIN32 _fmode = _O_BINARY; /*sets default for file streams to binary */ setmode(_fileno(stdin), O_BINARY); /* make the stdio mode be binary */ setmode(_fileno(stdout), O_BINARY); /* make the stdio mode be binary */ setmode(_fileno(stderr), O_BINARY); /* make the stdio mode be binary */ #endif while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2))!=-1) { switch (c) { case 'c': if (ini_path_override) { free(ini_path_override); } ini_path_override = strdup(php_optarg); break; case 'n': ini_ignore = 1; break; case 'd': { /* define ini entries on command line */ int len = strlen(php_optarg); char *val; if ((val = strchr(php_optarg, '='))) { val++; if (!isalnum(*val) && *val != '"' && *val != '\'' && *val != '\0') { ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("\"\"\n\0")); memcpy(ini_entries + ini_entries_len, php_optarg, (val - php_optarg)); ini_entries_len += (val - php_optarg); memcpy(ini_entries + ini_entries_len, "\"", 1); ini_entries_len++; memcpy(ini_entries + ini_entries_len, val, len - (val - php_optarg)); ini_entries_len += len - (val - php_optarg); memcpy(ini_entries + ini_entries_len, "\"\n\0", sizeof("\"\n\0")); ini_entries_len += sizeof("\n\0\"") - 2; } else { ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("\n\0")); memcpy(ini_entries + ini_entries_len, php_optarg, len); memcpy(ini_entries + ini_entries_len + len, "\n\0", sizeof("\n\0")); ini_entries_len += len + sizeof("\n\0") - 2; } } else { ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("=1\n\0")); memcpy(ini_entries + ini_entries_len, php_optarg, len); memcpy(ini_entries + ini_entries_len + len, "=1\n\0", sizeof("=1\n\0")); ini_entries_len += len + sizeof("=1\n\0") - 2; } break; } #ifndef PHP_CLI_WIN32_NO_CONSOLE case 'S': sapi_module = &cli_server_sapi_module; cli_server_sapi_module.additional_functions = server_additional_functions; break; #endif case 'h': /* help & quit */ case '?': php_cli_usage(argv[0]); goto out; case 'i': case 'v': case 'm': sapi_module = &cli_sapi_module; goto exit_loop; case 'e': /* enable extended info output */ use_extended_info = 1; break; } } exit_loop: sapi_module->ini_defaults = sapi_cli_ini_defaults; sapi_module->php_ini_path_override = ini_path_override; sapi_module->phpinfo_as_text = 1; sapi_module->php_ini_ignore_cwd = 1; sapi_startup(sapi_module); sapi_started = 1; sapi_module->php_ini_ignore = ini_ignore; sapi_module->executable_location = argv[0]; if (sapi_module == &cli_sapi_module) { if (ini_entries) { ini_entries = realloc(ini_entries, ini_entries_len + sizeof(HARDCODED_INI)); memmove(ini_entries + sizeof(HARDCODED_INI) - 2, ini_entries, ini_entries_len + 1); memcpy(ini_entries, HARDCODED_INI, sizeof(HARDCODED_INI) - 2); } else { ini_entries = malloc(sizeof(HARDCODED_INI)); memcpy(ini_entries, HARDCODED_INI, sizeof(HARDCODED_INI)); } ini_entries_len += sizeof(HARDCODED_INI) - 2; } sapi_module->ini_entries = ini_entries; /* startup after we get the above ini override se we get things right */ if (sapi_module->startup(sapi_module) == FAILURE) { /* there is no way to see if we must call zend_ini_deactivate() * since we cannot check if EG(ini_directives) has been initialised * because the executor's constructor does not set initialize it. * Apart from that there seems no need for zend_ini_deactivate() yet. * So we goto out_err.*/ exit_status = 1; goto out; } module_started = 1; /* -e option */ if (use_extended_info) { CG(compiler_options) |= ZEND_COMPILE_EXTENDED_INFO; } zend_first_try { #ifndef PHP_CLI_WIN32_NO_CONSOLE if (sapi_module == &cli_sapi_module) { #endif exit_status = do_cli(argc, argv TSRMLS_CC); #ifndef PHP_CLI_WIN32_NO_CONSOLE } else { exit_status = do_cli_server(argc, argv TSRMLS_CC); } #endif } zend_end_try(); out: if (ini_path_override) { free(ini_path_override); } if (ini_entries) { free(ini_entries); } if (module_started) { php_module_shutdown(TSRMLS_C); } if (sapi_started) { sapi_shutdown(); } #ifdef ZTS tsrm_shutdown(); #endif /* * Do not move this de-initialization. It needs to happen right before * exiting. */ cleanup_ps_args(argv); exit(exit_status); } /* }}} */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: sw=4 ts=4 fdm=marker * vim<600: sw=4 ts=4 */ PK!vʢ%%php_cli_server.cnu[/* +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2016 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Moriyoshi Koizumi | | Xinchen Hui | +----------------------------------------------------------------------+ */ /* $Id: php_cli.c 306938 2011-01-01 02:17:06Z felipe $ */ #include #include #include #include #ifdef PHP_WIN32 # include # include # include "win32/time.h" # include "win32/signal.h" # include "win32/php_registry.h" # include #else # include "php_config.h" #endif #ifdef __riscos__ #include #endif #if HAVE_TIME_H #include #endif #if HAVE_SYS_TIME_H #include #endif #if HAVE_UNISTD_H #include #endif #if HAVE_SIGNAL_H #include #endif #if HAVE_SETLOCALE #include #endif #if HAVE_DLFCN_H #include #endif #include "SAPI.h" #include "php.h" #include "php_ini.h" #include "php_main.h" #include "php_globals.h" #include "php_variables.h" #include "zend_hash.h" #include "zend_modules.h" #include "fopen_wrappers.h" #include "zend_compile.h" #include "zend_execute.h" #include "zend_highlight.h" #include "zend_indent.h" #include "zend_exceptions.h" #include "php_getopt.h" #ifndef PHP_WIN32 # define php_select(m, r, w, e, t) select(m, r, w, e, t) # define SOCK_EINVAL EINVAL # define SOCK_EAGAIN EAGAIN # define SOCK_EINTR EINTR # define SOCK_EADDRINUSE EADDRINUSE #else # include "win32/select.h" # define SOCK_EINVAL WSAEINVAL # define SOCK_EAGAIN WSAEWOULDBLOCK # define SOCK_EINTR WSAEINTR # define SOCK_EADDRINUSE WSAEADDRINUSE #endif #ifndef S_ISDIR #define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) #endif #include "ext/standard/file.h" /* for php_set_sock_blocking() :-( */ #include "ext/standard/php_smart_str.h" #include "ext/standard/html.h" #include "ext/standard/url.h" /* for php_raw_url_decode() */ #include "ext/standard/php_string.h" /* for php_dirname() */ #include "php_network.h" #include "php_http_parser.h" #include "php_cli_server.h" #include "php_cli_process_title.h" #define OUTPUT_NOT_CHECKED -1 #define OUTPUT_IS_TTY 1 #define OUTPUT_NOT_TTY 0 typedef struct php_cli_server_poller { fd_set rfds, wfds; struct { fd_set rfds, wfds; } active; php_socket_t max_fd; } php_cli_server_poller; typedef struct php_cli_server_request { enum php_http_method request_method; int protocol_version; char *request_uri; size_t request_uri_len; char *vpath; size_t vpath_len; char *path_translated; size_t path_translated_len; char *path_info; size_t path_info_len; char *query_string; size_t query_string_len; HashTable headers; HashTable headers_original_case; char *content; size_t content_len; const char *ext; size_t ext_len; struct stat sb; } php_cli_server_request; typedef struct php_cli_server_chunk { struct php_cli_server_chunk *next; enum php_cli_server_chunk_type { PHP_CLI_SERVER_CHUNK_HEAP, PHP_CLI_SERVER_CHUNK_IMMORTAL } type; union { struct { void *block; char *p; size_t len; } heap; struct { const char *p; size_t len; } immortal; } data; } php_cli_server_chunk; typedef struct php_cli_server_buffer { php_cli_server_chunk *first; php_cli_server_chunk *last; } php_cli_server_buffer; typedef struct php_cli_server_content_sender { php_cli_server_buffer buffer; } php_cli_server_content_sender; typedef struct php_cli_server_client { struct php_cli_server *server; php_socket_t sock; struct sockaddr *addr; socklen_t addr_len; char *addr_str; size_t addr_str_len; php_http_parser parser; unsigned int request_read:1; char *current_header_name; size_t current_header_name_len; unsigned int current_header_name_allocated:1; size_t post_read_offset; php_cli_server_request request; unsigned int content_sender_initialized:1; php_cli_server_content_sender content_sender; int file_fd; } php_cli_server_client; typedef struct php_cli_server { php_socket_t server_sock; php_cli_server_poller poller; int is_running; char *host; int port; int address_family; char *document_root; size_t document_root_len; char *router; size_t router_len; socklen_t socklen; HashTable clients; } php_cli_server; typedef struct php_cli_server_http_response_status_code_pair { int code; const char *str; } php_cli_server_http_response_status_code_pair; typedef struct php_cli_server_ext_mime_type_pair { const char *ext; const char *mime_type; } php_cli_server_ext_mime_type_pair; static php_cli_server_http_response_status_code_pair status_map[] = { { 100, "Continue" }, { 101, "Switching Protocols" }, { 200, "OK" }, { 201, "Created" }, { 202, "Accepted" }, { 203, "Non-Authoritative Information" }, { 204, "No Content" }, { 205, "Reset Content" }, { 206, "Partial Content" }, { 300, "Multiple Choices" }, { 301, "Moved Permanently" }, { 302, "Found" }, { 303, "See Other" }, { 304, "Not Modified" }, { 305, "Use Proxy" }, { 307, "Temporary Redirect" }, { 308, "Permanent Redirect" }, { 400, "Bad Request" }, { 401, "Unauthorized" }, { 402, "Payment Required" }, { 403, "Forbidden" }, { 404, "Not Found" }, { 405, "Method Not Allowed" }, { 406, "Not Acceptable" }, { 407, "Proxy Authentication Required" }, { 408, "Request Timeout" }, { 409, "Conflict" }, { 410, "Gone" }, { 411, "Length Required" }, { 412, "Precondition Failed" }, { 413, "Request Entity Too Large" }, { 414, "Request-URI Too Long" }, { 415, "Unsupported Media Type" }, { 416, "Requested Range Not Satisfiable" }, { 417, "Expectation Failed" }, { 426, "Upgrade Required" }, { 428, "Precondition Required" }, { 429, "Too Many Requests" }, { 431, "Request Header Fields Too Large" }, { 451, "Unavailable For Legal Reasons"}, { 500, "Internal Server Error" }, { 501, "Not Implemented" }, { 502, "Bad Gateway" }, { 503, "Service Unavailable" }, { 504, "Gateway Timeout" }, { 505, "HTTP Version Not Supported" }, { 511, "Network Authentication Required" }, }; static php_cli_server_http_response_status_code_pair template_map[] = { { 400, "

%s

Your browser sent a request that this server could not understand.

" }, { 404, "

%s

The requested resource %s was not found on this server.

" }, { 500, "

%s

The server is temporarily unavailable.

" }, { 501, "

%s

Request method not supported.

" } }; static php_cli_server_ext_mime_type_pair mime_type_map[] = { { "html", "text/html" }, { "htm", "text/html" }, { "js", "text/javascript" }, { "css", "text/css" }, { "gif", "image/gif" }, { "jpg", "image/jpeg" }, { "jpeg", "image/jpeg" }, { "jpe", "image/jpeg" }, { "pdf", "application/pdf" }, { "png", "image/png" }, { "svg", "image/svg+xml" }, { "txt", "text/plain" }, { "webm", "video/webm" }, { "ogv", "video/ogg" }, { "ogg", "audio/ogg" }, { "3gp", "video/3gpp" }, /* This is standard video format used for MMS in phones */ { "apk", "application/vnd.android.package-archive" }, { "avi", "video/x-msvideo" }, { "bmp", "image/x-ms-bmp" }, { "csv", "text/comma-separated-values" }, { "doc", "application/msword" }, { "docx", "application/msword" }, { "flac", "audio/flac" }, { "gz", "application/x-gzip" }, { "gzip", "application/x-gzip" }, { "ics", "text/calendar" }, { "kml", "application/vnd.google-earth.kml+xml" }, { "kmz", "application/vnd.google-earth.kmz" }, { "m4a", "audio/mp4" }, { "mp3", "audio/mpeg" }, { "mp4", "video/mp4" }, { "mpg", "video/mpeg" }, { "mpeg", "video/mpeg" }, { "mov", "video/quicktime" }, { "odp", "application/vnd.oasis.opendocument.presentation" }, { "ods", "application/vnd.oasis.opendocument.spreadsheet" }, { "odt", "application/vnd.oasis.opendocument.text" }, { "oga", "audio/ogg" }, { "pdf", "application/pdf" }, { "pptx", "application/vnd.ms-powerpoint" }, { "pps", "application/vnd.ms-powerpoint" }, { "qt", "video/quicktime" }, { "swf", "application/x-shockwave-flash" }, { "tar", "application/x-tar" }, { "text", "text/plain" }, { "tif", "image/tiff" }, { "wav", "audio/wav" }, { "wmv", "video/x-ms-wmv" }, { "xls", "application/vnd.ms-excel" }, { "xlsx", "application/vnd.ms-excel" }, { "zip", "application/x-zip-compressed" }, { "xml", "application/xml" }, { "xsl", "application/xml" }, { "xsd", "application/xml" }, { NULL, NULL } }; static int php_cli_output_is_tty = OUTPUT_NOT_CHECKED; static size_t php_cli_server_client_send_through(php_cli_server_client *client, const char *str, size_t str_len); static php_cli_server_chunk *php_cli_server_chunk_heap_new_self_contained(size_t len); static void php_cli_server_buffer_append(php_cli_server_buffer *buffer, php_cli_server_chunk *chunk); static void php_cli_server_logf(const char *format TSRMLS_DC, ...); static void php_cli_server_log_response(php_cli_server_client *client, int status, const char *message TSRMLS_DC); ZEND_DECLARE_MODULE_GLOBALS(cli_server); /* {{{ static char php_cli_server_css[] * copied from ext/standard/info.c */ static const char php_cli_server_css[] = "\n"; /* }}} */ #ifdef PHP_WIN32 int php_cli_server_get_system_time(char *buf) { struct _timeb system_time; errno_t err; if (buf == NULL) { return -1; } _ftime(&system_time); err = ctime_s(buf, 52, &(system_time.time) ); if (err) { return -1; } return 0; } #else int php_cli_server_get_system_time(char *buf) { struct timeval tv; struct tm tm; gettimeofday(&tv, NULL); /* TODO: should be checked for NULL tm/return vaue */ php_localtime_r(&tv.tv_sec, &tm); php_asctime_r(&tm, buf); return 0; } #endif static void char_ptr_dtor_p(char **p) /* {{{ */ { pefree(*p, 1); } /* }}} */ static char *get_last_error() /* {{{ */ { return pestrdup(strerror(errno), 1); } /* }}} */ static int status_comp(const void *a, const void *b) /* {{{ */ { const php_cli_server_http_response_status_code_pair *pa = (const php_cli_server_http_response_status_code_pair *) a; const php_cli_server_http_response_status_code_pair *pb = (const php_cli_server_http_response_status_code_pair *) b; if (pa->code < pb->code) { return -1; } else if (pa->code > pb->code) { return 1; } return 0; } /* }}} */ static const char *get_status_string(int code) /* {{{ */ { php_cli_server_http_response_status_code_pair needle, *result = NULL; needle.code = code; needle.str = NULL; result = bsearch(&needle, status_map, sizeof(status_map) / sizeof(needle), sizeof(needle), status_comp); if (result) { return result->str; } /* Returning NULL would require complicating append_http_status_line() to * not segfault in that case, so let's just return a placeholder, since RFC * 2616 requires a reason phrase. This is basically what a lot of other Web * servers do in this case anyway. */ return "Unknown Status Code"; } /* }}} */ static const char *get_template_string(int code) /* {{{ */ { size_t e = (sizeof(template_map) / sizeof(php_cli_server_http_response_status_code_pair)); size_t s = 0; while (e != s) { size_t c = MIN((e + s + 1) / 2, e - 1); int d = template_map[c].code; if (d > code) { e = c; } else if (d < code) { s = c; } else { return template_map[c].str; } } return NULL; } /* }}} */ static void append_http_status_line(smart_str *buffer, int protocol_version, int response_code, int persistent) /* {{{ */ { if (!response_code) { response_code = 200; } smart_str_appendl_ex(buffer, "HTTP", 4, persistent); smart_str_appendc_ex(buffer, '/', persistent); smart_str_append_generic_ex(buffer, protocol_version / 100, persistent, int, _unsigned); smart_str_appendc_ex(buffer, '.', persistent); smart_str_append_generic_ex(buffer, protocol_version % 100, persistent, int, _unsigned); smart_str_appendc_ex(buffer, ' ', persistent); smart_str_append_generic_ex(buffer, response_code, persistent, int, _unsigned); smart_str_appendc_ex(buffer, ' ', persistent); smart_str_appends_ex(buffer, get_status_string(response_code), persistent); smart_str_appendl_ex(buffer, "\r\n", 2, persistent); } /* }}} */ static void append_essential_headers(smart_str* buffer, php_cli_server_client *client, int persistent) /* {{{ */ { { char **val; if (SUCCESS == zend_hash_find(&client->request.headers, "host", sizeof("host"), (void**)&val)) { smart_str_appendl_ex(buffer, "Host", sizeof("Host") - 1, persistent); smart_str_appendl_ex(buffer, ": ", sizeof(": ") - 1, persistent); smart_str_appends_ex(buffer, *val, persistent); smart_str_appendl_ex(buffer, "\r\n", 2, persistent); } } smart_str_appendl_ex(buffer, "Connection: close\r\n", sizeof("Connection: close\r\n") - 1, persistent); } /* }}} */ static const char *get_mime_type(const char *ext, size_t ext_len) /* {{{ */ { php_cli_server_ext_mime_type_pair *pair; for (pair = mime_type_map; pair->ext; pair++) { size_t len = strlen(pair->ext); if (len == ext_len && memcmp(pair->ext, ext, len) == 0) { return pair->mime_type; } } return NULL; } /* }}} */ PHP_FUNCTION(apache_request_headers) /* {{{ */ { php_cli_server_client *client; HashTable *headers; char *key; uint key_len; char **value_pointer; HashPosition pos; if (zend_parse_parameters_none() == FAILURE) { return; } client = SG(server_context); headers = &client->request.headers_original_case; array_init_size(return_value, zend_hash_num_elements(headers)); zend_hash_internal_pointer_reset_ex(headers, &pos); while (zend_hash_get_current_data_ex(headers, (void **)&value_pointer, &pos) == SUCCESS) { zend_hash_get_current_key_ex(headers, &key, &key_len, NULL, 0, &pos); add_assoc_string_ex(return_value, key, key_len, *value_pointer, 1); zend_hash_move_forward_ex(headers, &pos); } } /* }}} */ static void add_response_header(sapi_header_struct *h, zval *return_value TSRMLS_DC) /* {{{ */ { char *s, *p; int len; ALLOCA_FLAG(use_heap) if (h->header_len > 0) { p = strchr(h->header, ':'); len = p - h->header; if (p && (len > 0)) { while (len > 0 && (h->header[len-1] == ' ' || h->header[len-1] == '\t')) { len--; } if (len) { s = do_alloca(len + 1, use_heap); memcpy(s, h->header, len); s[len] = 0; do { p++; } while (*p == ' ' || *p == '\t'); add_assoc_stringl_ex(return_value, s, len+1, p, h->header_len - (p - h->header), 1); free_alloca(s, use_heap); } } } } /* }}} */ PHP_FUNCTION(apache_response_headers) /* {{{ */ { if (zend_parse_parameters_none() == FAILURE) { return; } if (!&SG(sapi_headers).headers) { RETURN_FALSE; } array_init(return_value); zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t)add_response_header, return_value TSRMLS_CC); } /* }}} */ /* {{{ cli_server module */ static void cli_server_init_globals(zend_cli_server_globals *cg TSRMLS_DC) { cg->color = 0; } PHP_INI_BEGIN() STD_PHP_INI_BOOLEAN("cli_server.color", "0", PHP_INI_ALL, OnUpdateBool, color, zend_cli_server_globals, cli_server_globals) PHP_INI_END() static PHP_MINIT_FUNCTION(cli_server) { ZEND_INIT_MODULE_GLOBALS(cli_server, cli_server_init_globals, NULL); REGISTER_INI_ENTRIES(); return SUCCESS; } static PHP_MSHUTDOWN_FUNCTION(cli_server) { UNREGISTER_INI_ENTRIES(); return SUCCESS; } static PHP_MINFO_FUNCTION(cli_server) { DISPLAY_INI_ENTRIES(); } zend_module_entry cli_server_module_entry = { STANDARD_MODULE_HEADER, "cli_server", NULL, PHP_MINIT(cli_server), PHP_MSHUTDOWN(cli_server), NULL, NULL, PHP_MINFO(cli_server), PHP_VERSION, STANDARD_MODULE_PROPERTIES }; /* }}} */ ZEND_BEGIN_ARG_INFO(arginfo_no_args, 0) ZEND_END_ARG_INFO() const zend_function_entry server_additional_functions[] = { PHP_FE(cli_set_process_title, arginfo_cli_set_process_title) PHP_FE(cli_get_process_title, arginfo_cli_get_process_title) PHP_FE(apache_request_headers, arginfo_no_args) PHP_FE(apache_response_headers, arginfo_no_args) PHP_FALIAS(getallheaders, apache_request_headers, arginfo_no_args) {NULL, NULL, NULL} }; static int sapi_cli_server_startup(sapi_module_struct *sapi_module) /* {{{ */ { if (php_module_startup(sapi_module, &cli_server_module_entry, 1) == FAILURE) { return FAILURE; } return SUCCESS; } /* }}} */ static int sapi_cli_server_ub_write(const char *str, uint str_length TSRMLS_DC) /* {{{ */ { php_cli_server_client *client = SG(server_context); if (!client) { return 0; } return php_cli_server_client_send_through(client, str, str_length); } /* }}} */ static void sapi_cli_server_flush(void *server_context) /* {{{ */ { php_cli_server_client *client = server_context; TSRMLS_FETCH(); if (!client) { return; } if (client->sock < 0) { php_handle_aborted_connection(); return; } if (!SG(headers_sent)) { sapi_send_headers(TSRMLS_C); SG(headers_sent) = 1; } } /* }}} */ static int sapi_cli_server_discard_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) /* {{{ */{ return SAPI_HEADER_SENT_SUCCESSFULLY; } /* }}} */ static int sapi_cli_server_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) /* {{{ */ { php_cli_server_client *client = SG(server_context); smart_str buffer = { 0 }; sapi_header_struct *h; zend_llist_position pos; if (client == NULL || SG(request_info).no_headers) { return SAPI_HEADER_SENT_SUCCESSFULLY; } if (SG(sapi_headers).http_status_line) { smart_str_appends(&buffer, SG(sapi_headers).http_status_line); smart_str_appendl(&buffer, "\r\n", 2); } else { append_http_status_line(&buffer, client->request.protocol_version, SG(sapi_headers).http_response_code, 0); } append_essential_headers(&buffer, client, 0); h = (sapi_header_struct*)zend_llist_get_first_ex(&sapi_headers->headers, &pos); while (h) { if (h->header_len) { smart_str_appendl(&buffer, h->header, h->header_len); smart_str_appendl(&buffer, "\r\n", 2); } h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos); } smart_str_appendl(&buffer, "\r\n", 2); php_cli_server_client_send_through(client, buffer.c, buffer.len); smart_str_free(&buffer); return SAPI_HEADER_SENT_SUCCESSFULLY; } /* }}} */ static char *sapi_cli_server_read_cookies(TSRMLS_D) /* {{{ */ { php_cli_server_client *client = SG(server_context); char **val; if (FAILURE == zend_hash_find(&client->request.headers, "cookie", sizeof("cookie"), (void**)&val)) { return NULL; } return *val; } /* }}} */ static int sapi_cli_server_read_post(char *buf, uint count_bytes TSRMLS_DC) /* {{{ */ { php_cli_server_client *client = SG(server_context); if (client->request.content) { size_t content_len = client->request.content_len; size_t nbytes_copied = MIN(client->post_read_offset + count_bytes, content_len) - client->post_read_offset; memmove(buf, client->request.content + client->post_read_offset, nbytes_copied); client->post_read_offset += nbytes_copied; return nbytes_copied; } return 0; } /* }}} */ static void sapi_cli_server_register_variable(zval *track_vars_array, const char *key, const char *val TSRMLS_DC) /* {{{ */ { char *new_val = (char *)val; uint new_val_len; if (NULL == val) { return; } if (sapi_module.input_filter(PARSE_SERVER, (char*)key, &new_val, strlen(val), &new_val_len TSRMLS_CC)) { php_register_variable_safe((char *)key, new_val, new_val_len, track_vars_array TSRMLS_CC); } } /* }}} */ static int sapi_cli_server_register_entry_cb(char **entry TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ { zval *track_vars_array = va_arg(args, zval *); if (hash_key->nKeyLength) { char *real_key, *key; uint i; key = estrndup(hash_key->arKey, hash_key->nKeyLength); for(i=0; inKeyLength; i++) { if (key[i] == '-') { key[i] = '_'; } else { key[i] = toupper(key[i]); } } spprintf(&real_key, 0, "%s_%s", "HTTP", key); if (strcmp(key, "CONTENT_TYPE") == 0 || strcmp(key, "CONTENT_LENGTH") == 0) { sapi_cli_server_register_variable(track_vars_array, key, *entry TSRMLS_CC); } sapi_cli_server_register_variable(track_vars_array, real_key, *entry TSRMLS_CC); efree(key); efree(real_key); } return ZEND_HASH_APPLY_KEEP; } /* }}} */ static void sapi_cli_server_register_variables(zval *track_vars_array TSRMLS_DC) /* {{{ */ { php_cli_server_client *client = SG(server_context); sapi_cli_server_register_variable(track_vars_array, "DOCUMENT_ROOT", client->server->document_root TSRMLS_CC); { char *tmp; if ((tmp = strrchr(client->addr_str, ':'))) { char addr[64], port[8]; strncpy(port, tmp + 1, 8); port[7] = '\0'; strncpy(addr, client->addr_str, tmp - client->addr_str); addr[tmp - client->addr_str] = '\0'; sapi_cli_server_register_variable(track_vars_array, "REMOTE_ADDR", addr TSRMLS_CC); sapi_cli_server_register_variable(track_vars_array, "REMOTE_PORT", port TSRMLS_CC); } else { sapi_cli_server_register_variable(track_vars_array, "REMOTE_ADDR", client->addr_str TSRMLS_CC); } } { char *tmp; spprintf(&tmp, 0, "PHP %s Development Server", PHP_VERSION); sapi_cli_server_register_variable(track_vars_array, "SERVER_SOFTWARE", tmp TSRMLS_CC); efree(tmp); } { char *tmp; spprintf(&tmp, 0, "HTTP/%d.%d", client->request.protocol_version / 100, client->request.protocol_version % 100); sapi_cli_server_register_variable(track_vars_array, "SERVER_PROTOCOL", tmp TSRMLS_CC); efree(tmp); } sapi_cli_server_register_variable(track_vars_array, "SERVER_NAME", client->server->host TSRMLS_CC); { char *tmp; spprintf(&tmp, 0, "%i", client->server->port); sapi_cli_server_register_variable(track_vars_array, "SERVER_PORT", tmp TSRMLS_CC); efree(tmp); } sapi_cli_server_register_variable(track_vars_array, "REQUEST_URI", client->request.request_uri TSRMLS_CC); sapi_cli_server_register_variable(track_vars_array, "REQUEST_METHOD", SG(request_info).request_method TSRMLS_CC); sapi_cli_server_register_variable(track_vars_array, "SCRIPT_NAME", client->request.vpath TSRMLS_CC); if (SG(request_info).path_translated) { sapi_cli_server_register_variable(track_vars_array, "SCRIPT_FILENAME", SG(request_info).path_translated TSRMLS_CC); } else if (client->server->router) { char *temp; spprintf(&temp, 0, "%s/%s", client->server->document_root, client->server->router); sapi_cli_server_register_variable(track_vars_array, "SCRIPT_FILENAME", temp TSRMLS_CC); efree(temp); } if (client->request.path_info) { sapi_cli_server_register_variable(track_vars_array, "PATH_INFO", client->request.path_info TSRMLS_CC); } if (client->request.path_info_len) { char *tmp; spprintf(&tmp, 0, "%s%s", client->request.vpath, client->request.path_info); sapi_cli_server_register_variable(track_vars_array, "PHP_SELF", tmp TSRMLS_CC); efree(tmp); } else { sapi_cli_server_register_variable(track_vars_array, "PHP_SELF", client->request.vpath TSRMLS_CC); } if (client->request.query_string) { sapi_cli_server_register_variable(track_vars_array, "QUERY_STRING", client->request.query_string TSRMLS_CC); } zend_hash_apply_with_arguments(&client->request.headers TSRMLS_CC, (apply_func_args_t)sapi_cli_server_register_entry_cb, 1, track_vars_array); } /* }}} */ static void sapi_cli_server_log_message(char *msg TSRMLS_DC) /* {{{ */ { char buf[52]; if (php_cli_server_get_system_time(buf) != 0) { memmove(buf, "unknown time, can't be fetched", sizeof("unknown time, can't be fetched")); } else { size_t l = strlen(buf); if (l > 0) { buf[l - 1] = '\0'; } else { memmove(buf, "unknown", sizeof("unknown")); } } fprintf(stderr, "[%s] %s\n", buf, msg); } /* }}} */ /* {{{ sapi_module_struct cli_server_sapi_module */ sapi_module_struct cli_server_sapi_module = { "cli-server", /* name */ "Built-in HTTP server", /* pretty name */ sapi_cli_server_startup, /* startup */ php_module_shutdown_wrapper, /* shutdown */ NULL, /* activate */ NULL, /* deactivate */ sapi_cli_server_ub_write, /* unbuffered write */ sapi_cli_server_flush, /* flush */ NULL, /* get uid */ NULL, /* getenv */ php_error, /* error handler */ NULL, /* header handler */ sapi_cli_server_send_headers, /* send headers handler */ NULL, /* send header handler */ sapi_cli_server_read_post, /* read POST data */ sapi_cli_server_read_cookies, /* read Cookies */ sapi_cli_server_register_variables, /* register server variables */ sapi_cli_server_log_message, /* Log message */ NULL, /* Get request time */ NULL, /* Child terminate */ STANDARD_SAPI_MODULE_PROPERTIES }; /* }}} */ static int php_cli_server_poller_ctor(php_cli_server_poller *poller) /* {{{ */ { FD_ZERO(&poller->rfds); FD_ZERO(&poller->wfds); poller->max_fd = -1; return SUCCESS; } /* }}} */ static void php_cli_server_poller_add(php_cli_server_poller *poller, int mode, int fd) /* {{{ */ { if (mode & POLLIN) { PHP_SAFE_FD_SET(fd, &poller->rfds); } if (mode & POLLOUT) { PHP_SAFE_FD_SET(fd, &poller->wfds); } if (fd > poller->max_fd) { poller->max_fd = fd; } } /* }}} */ static void php_cli_server_poller_remove(php_cli_server_poller *poller, int mode, int fd) /* {{{ */ { if (mode & POLLIN) { PHP_SAFE_FD_CLR(fd, &poller->rfds); } if (mode & POLLOUT) { PHP_SAFE_FD_CLR(fd, &poller->wfds); } #ifndef PHP_WIN32 if (fd == poller->max_fd) { while (fd > 0) { fd--; if (PHP_SAFE_FD_ISSET(fd, &poller->rfds) || PHP_SAFE_FD_ISSET(fd, &poller->wfds)) { break; } } poller->max_fd = fd; } #endif } /* }}} */ static int php_cli_server_poller_poll(php_cli_server_poller *poller, struct timeval *tv) /* {{{ */ { memmove(&poller->active.rfds, &poller->rfds, sizeof(poller->rfds)); memmove(&poller->active.wfds, &poller->wfds, sizeof(poller->wfds)); return php_select(poller->max_fd + 1, &poller->active.rfds, &poller->active.wfds, NULL, tv); } /* }}} */ static int php_cli_server_poller_iter_on_active(php_cli_server_poller *poller, void *opaque, int(*callback)(void *, int fd, int events)) /* {{{ */ { int retval = SUCCESS; #ifdef PHP_WIN32 struct socket_entry { SOCKET fd; int events; } entries[FD_SETSIZE * 2]; php_socket_t fd = 0; size_t i; struct socket_entry *n = entries, *m; for (i = 0; i < poller->active.rfds.fd_count; i++) { n->events = POLLIN; n->fd = poller->active.rfds.fd_array[i]; n++; } m = n; for (i = 0; i < poller->active.wfds.fd_count; i++) { struct socket_entry *e; SOCKET fd = poller->active.wfds.fd_array[i]; for (e = entries; e < m; e++) { if (e->fd == fd) { e->events |= POLLOUT; } } if (e == m) { assert(n < entries + FD_SETSIZE * 2); n->events = POLLOUT; n->fd = fd; n++; } } { struct socket_entry *e = entries; for (; e < n; e++) { if (SUCCESS != callback(opaque, e->fd, e->events)) { retval = FAILURE; } } } #else php_socket_t fd; const php_socket_t max_fd = poller->max_fd; for (fd=0 ; fd<=max_fd ; fd++) { if (PHP_SAFE_FD_ISSET(fd, &poller->active.rfds)) { if (SUCCESS != callback(opaque, fd, POLLIN)) { retval = FAILURE; } } if (PHP_SAFE_FD_ISSET(fd, &poller->active.wfds)) { if (SUCCESS != callback(opaque, fd, POLLOUT)) { retval = FAILURE; } } } #endif return retval; } /* }}} */ static size_t php_cli_server_chunk_size(const php_cli_server_chunk *chunk) /* {{{ */ { switch (chunk->type) { case PHP_CLI_SERVER_CHUNK_HEAP: return chunk->data.heap.len; case PHP_CLI_SERVER_CHUNK_IMMORTAL: return chunk->data.immortal.len; } return 0; } /* }}} */ static void php_cli_server_chunk_dtor(php_cli_server_chunk *chunk) /* {{{ */ { switch (chunk->type) { case PHP_CLI_SERVER_CHUNK_HEAP: if (chunk->data.heap.block != chunk) { pefree(chunk->data.heap.block, 1); } break; case PHP_CLI_SERVER_CHUNK_IMMORTAL: break; } } /* }}} */ static void php_cli_server_buffer_dtor(php_cli_server_buffer *buffer) /* {{{ */ { php_cli_server_chunk *chunk, *next; for (chunk = buffer->first; chunk; chunk = next) { next = chunk->next; php_cli_server_chunk_dtor(chunk); pefree(chunk, 1); } } /* }}} */ static void php_cli_server_buffer_ctor(php_cli_server_buffer *buffer) /* {{{ */ { buffer->first = NULL; buffer->last = NULL; } /* }}} */ static void php_cli_server_buffer_append(php_cli_server_buffer *buffer, php_cli_server_chunk *chunk) /* {{{ */ { php_cli_server_chunk *last; for (last = chunk; last->next; last = last->next); if (!buffer->last) { buffer->first = chunk; } else { buffer->last->next = chunk; } buffer->last = last; } /* }}} */ static void php_cli_server_buffer_prepend(php_cli_server_buffer *buffer, php_cli_server_chunk *chunk) /* {{{ */ { php_cli_server_chunk *last; for (last = chunk; last->next; last = last->next); last->next = buffer->first; if (!buffer->last) { buffer->last = last; } buffer->first = chunk; } /* }}} */ static size_t php_cli_server_buffer_size(const php_cli_server_buffer *buffer) /* {{{ */ { php_cli_server_chunk *chunk; size_t retval = 0; for (chunk = buffer->first; chunk; chunk = chunk->next) { retval += php_cli_server_chunk_size(chunk); } return retval; } /* }}} */ static php_cli_server_chunk *php_cli_server_chunk_immortal_new(const char *buf, size_t len) /* {{{ */ { php_cli_server_chunk *chunk = pemalloc(sizeof(php_cli_server_chunk), 1); if (!chunk) { return NULL; } chunk->type = PHP_CLI_SERVER_CHUNK_IMMORTAL; chunk->next = NULL; chunk->data.immortal.p = buf; chunk->data.immortal.len = len; return chunk; } /* }}} */ static php_cli_server_chunk *php_cli_server_chunk_heap_new(char *block, char *buf, size_t len) /* {{{ */ { php_cli_server_chunk *chunk = pemalloc(sizeof(php_cli_server_chunk), 1); if (!chunk) { return NULL; } chunk->type = PHP_CLI_SERVER_CHUNK_HEAP; chunk->next = NULL; chunk->data.heap.block = block; chunk->data.heap.p = buf; chunk->data.heap.len = len; return chunk; } /* }}} */ static php_cli_server_chunk *php_cli_server_chunk_heap_new_self_contained(size_t len) /* {{{ */ { php_cli_server_chunk *chunk = pemalloc(sizeof(php_cli_server_chunk) + len, 1); if (!chunk) { return NULL; } chunk->type = PHP_CLI_SERVER_CHUNK_HEAP; chunk->next = NULL; chunk->data.heap.block = chunk; chunk->data.heap.p = (char *)(chunk + 1); chunk->data.heap.len = len; return chunk; } /* }}} */ static void php_cli_server_content_sender_dtor(php_cli_server_content_sender *sender) /* {{{ */ { php_cli_server_buffer_dtor(&sender->buffer); } /* }}} */ static void php_cli_server_content_sender_ctor(php_cli_server_content_sender *sender) /* {{{ */ { php_cli_server_buffer_ctor(&sender->buffer); } /* }}} */ static int php_cli_server_content_sender_send(php_cli_server_content_sender *sender, php_socket_t fd, size_t *nbytes_sent_total) /* {{{ */ { php_cli_server_chunk *chunk, *next; size_t _nbytes_sent_total = 0; for (chunk = sender->buffer.first; chunk; chunk = next) { ssize_t nbytes_sent; next = chunk->next; switch (chunk->type) { case PHP_CLI_SERVER_CHUNK_HEAP: nbytes_sent = send(fd, chunk->data.heap.p, chunk->data.heap.len, 0); if (nbytes_sent < 0) { *nbytes_sent_total = _nbytes_sent_total; return php_socket_errno(); } else if (nbytes_sent == chunk->data.heap.len) { php_cli_server_chunk_dtor(chunk); pefree(chunk, 1); sender->buffer.first = next; if (!next) { sender->buffer.last = NULL; } } else { chunk->data.heap.p += nbytes_sent; chunk->data.heap.len -= nbytes_sent; } _nbytes_sent_total += nbytes_sent; break; case PHP_CLI_SERVER_CHUNK_IMMORTAL: nbytes_sent = send(fd, chunk->data.immortal.p, chunk->data.immortal.len, 0); if (nbytes_sent < 0) { *nbytes_sent_total = _nbytes_sent_total; return php_socket_errno(); } else if (nbytes_sent == chunk->data.immortal.len) { php_cli_server_chunk_dtor(chunk); pefree(chunk, 1); sender->buffer.first = next; if (!next) { sender->buffer.last = NULL; } } else { chunk->data.immortal.p += nbytes_sent; chunk->data.immortal.len -= nbytes_sent; } _nbytes_sent_total += nbytes_sent; break; } } *nbytes_sent_total = _nbytes_sent_total; return 0; } /* }}} */ static int php_cli_server_content_sender_pull(php_cli_server_content_sender *sender, int fd, size_t *nbytes_read) /* {{{ */ { ssize_t _nbytes_read; php_cli_server_chunk *chunk = php_cli_server_chunk_heap_new_self_contained(131072); _nbytes_read = read(fd, chunk->data.heap.p, chunk->data.heap.len); if (_nbytes_read < 0) { char *errstr = get_last_error(); TSRMLS_FETCH(); php_cli_server_logf("%s" TSRMLS_CC, errstr); pefree(errstr, 1); php_cli_server_chunk_dtor(chunk); pefree(chunk, 1); return 1; } chunk->data.heap.len = _nbytes_read; php_cli_server_buffer_append(&sender->buffer, chunk); *nbytes_read = _nbytes_read; return 0; } /* }}} */ #if HAVE_UNISTD_H static int php_cli_is_output_tty() /* {{{ */ { if (php_cli_output_is_tty == OUTPUT_NOT_CHECKED) { php_cli_output_is_tty = isatty(STDOUT_FILENO); } return php_cli_output_is_tty; } /* }}} */ #endif static void php_cli_server_log_response(php_cli_server_client *client, int status, const char *message TSRMLS_DC) /* {{{ */ { int color = 0, effective_status = status; char *basic_buf, *message_buf = "", *error_buf = ""; zend_bool append_error_message = 0; if (PG(last_error_message)) { switch (PG(last_error_type)) { case E_ERROR: case E_CORE_ERROR: case E_COMPILE_ERROR: case E_USER_ERROR: case E_PARSE: if (status == 200) { /* the status code isn't changed by a fatal error, so fake it */ effective_status = 500; } append_error_message = 1; break; } } #if HAVE_UNISTD_H if (CLI_SERVER_G(color) && php_cli_is_output_tty() == OUTPUT_IS_TTY) { if (effective_status >= 500) { /* server error: red */ color = 1; } else if (effective_status >= 400) { /* client error: yellow */ color = 3; } else if (effective_status >= 200) { /* success: green */ color = 2; } } #endif /* basic */ spprintf(&basic_buf, 0, "%s [%d]: %s", client->addr_str, status, client->request.request_uri); if (!basic_buf) { return; } /* message */ if (message) { spprintf(&message_buf, 0, " - %s", message); if (!message_buf) { efree(basic_buf); return; } } /* error */ if (append_error_message) { spprintf(&error_buf, 0, " - %s in %s on line %d", PG(last_error_message), PG(last_error_file), PG(last_error_lineno)); if (!error_buf) { efree(basic_buf); if (message) { efree(message_buf); } return; } } if (color) { php_cli_server_logf("\x1b[3%dm%s%s%s\x1b[0m" TSRMLS_CC, color, basic_buf, message_buf, error_buf); } else { php_cli_server_logf("%s%s%s" TSRMLS_CC, basic_buf, message_buf, error_buf); } efree(basic_buf); if (message) { efree(message_buf); } if (append_error_message) { efree(error_buf); } } /* }}} */ static void php_cli_server_logf(const char *format TSRMLS_DC, ...) /* {{{ */ { char *buf = NULL; va_list ap; #ifdef ZTS va_start(ap, tsrm_ls); #else va_start(ap, format); #endif vspprintf(&buf, 0, format, ap); va_end(ap); if (!buf) { return; } if (sapi_module.log_message) { sapi_module.log_message(buf TSRMLS_CC); } efree(buf); } /* }}} */ static int php_network_listen_socket(const char *host, int *port, int socktype, int *af, socklen_t *socklen, char **errstr TSRMLS_DC) /* {{{ */ { int retval = SOCK_ERR; int err = 0; struct sockaddr *sa = NULL, **p, **sal; int num_addrs = php_network_getaddresses(host, socktype, &sal, errstr TSRMLS_CC); if (num_addrs == 0) { return -1; } for (p = sal; *p; p++) { if (sa) { pefree(sa, 1); sa = NULL; } retval = socket((*p)->sa_family, socktype, 0); if (retval == SOCK_ERR) { continue; } switch ((*p)->sa_family) { #if HAVE_GETADDRINFO && HAVE_IPV6 case AF_INET6: sa = pemalloc(sizeof(struct sockaddr_in6), 1); if (!sa) { closesocket(retval); retval = SOCK_ERR; *errstr = NULL; goto out; } *(struct sockaddr_in6 *)sa = *(struct sockaddr_in6 *)*p; ((struct sockaddr_in6 *)sa)->sin6_port = htons(*port); *socklen = sizeof(struct sockaddr_in6); break; #endif case AF_INET: sa = pemalloc(sizeof(struct sockaddr_in), 1); if (!sa) { closesocket(retval); retval = SOCK_ERR; *errstr = NULL; goto out; } *(struct sockaddr_in *)sa = *(struct sockaddr_in *)*p; ((struct sockaddr_in *)sa)->sin_port = htons(*port); *socklen = sizeof(struct sockaddr_in); break; default: /* Unknown family */ *socklen = 0; closesocket(retval); continue; } #ifdef SO_REUSEADDR { int val = 1; setsockopt(retval, SOL_SOCKET, SO_REUSEADDR, (char*)&val, sizeof(val)); } #endif if (bind(retval, sa, *socklen) == SOCK_CONN_ERR) { err = php_socket_errno(); if (err == SOCK_EINVAL || err == SOCK_EADDRINUSE) { goto out; } closesocket(retval); retval = SOCK_ERR; continue; } err = 0; *af = sa->sa_family; if (*port == 0) { if (getsockname(retval, sa, socklen)) { err = php_socket_errno(); goto out; } switch (sa->sa_family) { #if HAVE_GETADDRINFO && HAVE_IPV6 case AF_INET6: *port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port); break; #endif case AF_INET: *port = ntohs(((struct sockaddr_in *)sa)->sin_port); break; } } break; } if (retval == SOCK_ERR) { goto out; } if (listen(retval, SOMAXCONN)) { err = php_socket_errno(); goto out; } out: if (sa) { pefree(sa, 1); } if (sal) { php_network_freeaddresses(sal); } if (err) { if (retval >= 0) { closesocket(retval); } if (errstr) { *errstr = php_socket_strerror(err, NULL, 0); } return SOCK_ERR; } return retval; } /* }}} */ static int php_cli_server_request_ctor(php_cli_server_request *req) /* {{{ */ { req->protocol_version = 0; req->request_uri = NULL; req->request_uri_len = 0; req->vpath = NULL; req->vpath_len = 0; req->path_translated = NULL; req->path_translated_len = 0; req->path_info = NULL; req->path_info_len = 0; req->query_string = NULL; req->query_string_len = 0; zend_hash_init(&req->headers, 0, NULL, (void(*)(void*))char_ptr_dtor_p, 1); zend_hash_init(&req->headers_original_case, 0, NULL, NULL, 1); req->content = NULL; req->content_len = 0; req->ext = NULL; req->ext_len = 0; return SUCCESS; } /* }}} */ static void php_cli_server_request_dtor(php_cli_server_request *req) /* {{{ */ { if (req->request_uri) { pefree(req->request_uri, 1); } if (req->vpath) { pefree(req->vpath, 1); } if (req->path_translated) { pefree(req->path_translated, 1); } if (req->path_info) { pefree(req->path_info, 1); } if (req->query_string) { pefree(req->query_string, 1); } zend_hash_destroy(&req->headers); zend_hash_destroy(&req->headers_original_case); if (req->content) { pefree(req->content, 1); } } /* }}} */ static void php_cli_server_request_translate_vpath(php_cli_server_request *request, const char *document_root, size_t document_root_len) /* {{{ */ { struct stat sb; static const char *index_files[] = { "index.php", "index.html", NULL }; char *buf = safe_pemalloc(1, request->vpath_len, 1 + document_root_len + 1 + sizeof("index.html"), 1); char *p = buf, *prev_path = NULL, *q, *vpath; size_t prev_path_len = 0; int is_static_file = 0; if (!buf) { return; } memmove(p, document_root, document_root_len); p += document_root_len; vpath = p; if (request->vpath_len > 0 && request->vpath[0] != '/') { *p++ = DEFAULT_SLASH; } q = request->vpath + request->vpath_len; while (q > request->vpath) { if (*q-- == '.') { is_static_file = 1; break; } } memmove(p, request->vpath, request->vpath_len); #ifdef PHP_WIN32 q = p + request->vpath_len; do { if (*q == '/') { *q = '\\'; } } while (q-- > p); #endif p += request->vpath_len; *p = '\0'; q = p; while (q > buf) { if (!stat(buf, &sb)) { if (sb.st_mode & S_IFDIR) { const char **file = index_files; if (q[-1] != DEFAULT_SLASH) { *q++ = DEFAULT_SLASH; } while (*file) { size_t l = strlen(*file); memmove(q, *file, l + 1); if (!stat(buf, &sb) && (sb.st_mode & S_IFREG)) { q += l; break; } file++; } if (!*file || is_static_file) { if (prev_path) { pefree(prev_path, 1); } pefree(buf, 1); return; } } break; /* regular file */ } if (prev_path) { pefree(prev_path, 1); *q = DEFAULT_SLASH; } while (q > buf && *(--q) != DEFAULT_SLASH); prev_path_len = p - q; prev_path = pestrndup(q, prev_path_len, 1); *q = '\0'; } if (prev_path) { request->path_info_len = prev_path_len; #ifdef PHP_WIN32 while (prev_path_len--) { if (prev_path[prev_path_len] == '\\') { prev_path[prev_path_len] = '/'; } } #endif request->path_info = prev_path; pefree(request->vpath, 1); request->vpath = pestrndup(vpath, q - vpath, 1); request->vpath_len = q - vpath; request->path_translated = buf; request->path_translated_len = q - buf; } else { pefree(request->vpath, 1); request->vpath = pestrndup(vpath, q - vpath, 1); request->vpath_len = q - vpath; request->path_translated = buf; request->path_translated_len = q - buf; } #ifdef PHP_WIN32 { uint i = 0; for (;ivpath_len;i++) { if (request->vpath[i] == '\\') { request->vpath[i] = '/'; } } } #endif request->sb = sb; } /* }}} */ static void normalize_vpath(char **retval, size_t *retval_len, const char *vpath, size_t vpath_len, int persistent) /* {{{ */ { char *decoded_vpath = NULL; char *decoded_vpath_end; char *p; *retval = NULL; decoded_vpath = pestrndup(vpath, vpath_len, persistent); if (!decoded_vpath) { return; } decoded_vpath_end = decoded_vpath + php_raw_url_decode(decoded_vpath, vpath_len); #ifdef PHP_WIN32 { char *p = decoded_vpath; do { if (*p == '\\') { *p = '/'; } } while (*p++); } #endif p = decoded_vpath; if (p < decoded_vpath_end && *p == '/') { char *n = p; while (n < decoded_vpath_end && *n == '/') n++; memmove(++p, n, decoded_vpath_end - n); decoded_vpath_end -= n - p; } while (p < decoded_vpath_end) { char *n = p; while (n < decoded_vpath_end && *n != '/') n++; if (n - p == 2 && p[0] == '.' && p[1] == '.') { if (p > decoded_vpath) { --p; for (;;) { if (p == decoded_vpath) { if (*p == '/') { p++; } break; } if (*(--p) == '/') { p++; break; } } } while (n < decoded_vpath_end && *n == '/') n++; memmove(p, n, decoded_vpath_end - n); decoded_vpath_end -= n - p; } else if (n - p == 1 && p[0] == '.') { while (n < decoded_vpath_end && *n == '/') n++; memmove(p, n, decoded_vpath_end - n); decoded_vpath_end -= n - p; } else { if (n < decoded_vpath_end) { char *nn = n; while (nn < decoded_vpath_end && *nn == '/') nn++; p = n + 1; memmove(p, nn, decoded_vpath_end - nn); decoded_vpath_end -= nn - p; } else { p = n; } } } *decoded_vpath_end = '\0'; *retval = decoded_vpath; *retval_len = decoded_vpath_end - decoded_vpath; } /* }}} */ /* {{{ php_cli_server_client_read_request */ static int php_cli_server_client_read_request_on_message_begin(php_http_parser *parser) { return 0; } static int php_cli_server_client_read_request_on_path(php_http_parser *parser, const char *at, size_t length) { php_cli_server_client *client = parser->data; { char *vpath; size_t vpath_len; normalize_vpath(&vpath, &vpath_len, at, length, 1); client->request.vpath = vpath; client->request.vpath_len = vpath_len; } return 0; } static int php_cli_server_client_read_request_on_query_string(php_http_parser *parser, const char *at, size_t length) { php_cli_server_client *client = parser->data; client->request.query_string = pestrndup(at, length, 1); client->request.query_string_len = length; return 0; } static int php_cli_server_client_read_request_on_url(php_http_parser *parser, const char *at, size_t length) { php_cli_server_client *client = parser->data; client->request.request_method = parser->method; client->request.request_uri = pestrndup(at, length, 1); client->request.request_uri_len = length; return 0; } static int php_cli_server_client_read_request_on_fragment(php_http_parser *parser, const char *at, size_t length) { return 0; } static int php_cli_server_client_read_request_on_header_field(php_http_parser *parser, const char *at, size_t length) { php_cli_server_client *client = parser->data; if (client->current_header_name_allocated) { pefree(client->current_header_name, 1); client->current_header_name_allocated = 0; } client->current_header_name = (char *)at; client->current_header_name_len = length; return 0; } static int php_cli_server_client_read_request_on_header_value(php_http_parser *parser, const char *at, size_t length) { php_cli_server_client *client = parser->data; char *value = pestrndup(at, length, 1); if (!value) { return 1; } { /* strip off the colon */ char *orig_header_name = estrndup(client->current_header_name, client->current_header_name_len); char *lc_header_name = zend_str_tolower_dup(client->current_header_name, client->current_header_name_len); zend_hash_add(&client->request.headers, lc_header_name, client->current_header_name_len + 1, &value, sizeof(char *), NULL); zend_hash_add(&client->request.headers_original_case, orig_header_name, client->current_header_name_len + 1, &value, sizeof(char *), NULL); efree(lc_header_name); efree(orig_header_name); } if (client->current_header_name_allocated) { pefree(client->current_header_name, 1); client->current_header_name_allocated = 0; } return 0; } static int php_cli_server_client_read_request_on_headers_complete(php_http_parser *parser) { php_cli_server_client *client = parser->data; if (client->current_header_name_allocated) { pefree(client->current_header_name, 1); client->current_header_name_allocated = 0; } client->current_header_name = NULL; return 0; } static int php_cli_server_client_read_request_on_body(php_http_parser *parser, const char *at, size_t length) { php_cli_server_client *client = parser->data; if (!client->request.content) { client->request.content = pemalloc(parser->content_length, 1); if (!client->request.content) { return -1; } client->request.content_len = 0; } client->request.content = perealloc(client->request.content, client->request.content_len + length, 1); memmove(client->request.content + client->request.content_len, at, length); client->request.content_len += length; return 0; } static int php_cli_server_client_read_request_on_message_complete(php_http_parser *parser) { php_cli_server_client *client = parser->data; client->request.protocol_version = parser->http_major * 100 + parser->http_minor; php_cli_server_request_translate_vpath(&client->request, client->server->document_root, client->server->document_root_len); { const char *vpath = client->request.vpath, *end = vpath + client->request.vpath_len, *p = end; client->request.ext = end; client->request.ext_len = 0; while (p > vpath) { --p; if (*p == '.') { ++p; client->request.ext = p; client->request.ext_len = end - p; break; } } } client->request_read = 1; return 0; } static int php_cli_server_client_read_request(php_cli_server_client *client, char **errstr TSRMLS_DC) { char buf[16384]; static const php_http_parser_settings settings = { php_cli_server_client_read_request_on_message_begin, php_cli_server_client_read_request_on_path, php_cli_server_client_read_request_on_query_string, php_cli_server_client_read_request_on_url, php_cli_server_client_read_request_on_fragment, php_cli_server_client_read_request_on_header_field, php_cli_server_client_read_request_on_header_value, php_cli_server_client_read_request_on_headers_complete, php_cli_server_client_read_request_on_body, php_cli_server_client_read_request_on_message_complete }; size_t nbytes_consumed; int nbytes_read; if (client->request_read) { return 1; } nbytes_read = recv(client->sock, buf, sizeof(buf) - 1, 0); if (nbytes_read < 0) { int err = php_socket_errno(); if (err == SOCK_EAGAIN) { return 0; } *errstr = php_socket_strerror(err, NULL, 0); return -1; } else if (nbytes_read == 0) { *errstr = estrdup("Unexpected EOF"); return -1; } client->parser.data = client; nbytes_consumed = php_http_parser_execute(&client->parser, &settings, buf, nbytes_read); if (nbytes_consumed != nbytes_read) { if (buf[0] & 0x80 /* SSLv2 */ || buf[0] == 0x16 /* SSLv3/TLSv1 */) { *errstr = estrdup("Unsupported SSL request"); } else { *errstr = estrdup("Malformed HTTP request"); } return -1; } if (client->current_header_name) { char *header_name = safe_pemalloc(client->current_header_name_len, 1, 1, 1); if (!header_name) { return -1; } memmove(header_name, client->current_header_name, client->current_header_name_len); client->current_header_name = header_name; client->current_header_name_allocated = 1; } return client->request_read ? 1: 0; } /* }}} */ static size_t php_cli_server_client_send_through(php_cli_server_client *client, const char *str, size_t str_len) /* {{{ */ { struct timeval tv = { 10, 0 }; ssize_t nbytes_left = str_len; do { ssize_t nbytes_sent = send(client->sock, str + str_len - nbytes_left, nbytes_left, 0); if (nbytes_sent < 0) { int err = php_socket_errno(); if (err == SOCK_EAGAIN) { int nfds = php_pollfd_for(client->sock, POLLOUT, &tv); if (nfds > 0) { continue; } else if (nfds < 0) { /* error */ php_handle_aborted_connection(); return nbytes_left; } else { /* timeout */ php_handle_aborted_connection(); return nbytes_left; } } else { php_handle_aborted_connection(); return nbytes_left; } } nbytes_left -= nbytes_sent; } while (nbytes_left > 0); return str_len; } /* }}} */ static void php_cli_server_client_populate_request_info(const php_cli_server_client *client, sapi_request_info *request_info) /* {{{ */ { char **val; request_info->request_method = php_http_method_str(client->request.request_method); request_info->proto_num = client->request.protocol_version; request_info->request_uri = client->request.request_uri; request_info->path_translated = client->request.path_translated; request_info->query_string = client->request.query_string; request_info->content_length = client->request.content_len; request_info->auth_user = request_info->auth_password = request_info->auth_digest = NULL; if (SUCCESS == zend_hash_find(&client->request.headers, "content-type", sizeof("content-type"), (void**)&val)) { request_info->content_type = *val; } } /* }}} */ static void destroy_request_info(sapi_request_info *request_info) /* {{{ */ { } /* }}} */ static int php_cli_server_client_ctor(php_cli_server_client *client, php_cli_server *server, int client_sock, struct sockaddr *addr, socklen_t addr_len TSRMLS_DC) /* {{{ */ { client->server = server; client->sock = client_sock; client->addr = addr; client->addr_len = addr_len; { char *addr_str = 0; long addr_str_len = 0; php_network_populate_name_from_sockaddr(addr, addr_len, &addr_str, &addr_str_len, NULL, 0 TSRMLS_CC); client->addr_str = pestrndup(addr_str, addr_str_len, 1); client->addr_str_len = addr_str_len; efree(addr_str); } php_http_parser_init(&client->parser, PHP_HTTP_REQUEST); client->request_read = 0; client->current_header_name = NULL; client->current_header_name_len = 0; client->current_header_name_allocated = 0; client->post_read_offset = 0; if (FAILURE == php_cli_server_request_ctor(&client->request)) { return FAILURE; } client->content_sender_initialized = 0; client->file_fd = -1; return SUCCESS; } /* }}} */ static void php_cli_server_client_dtor(php_cli_server_client *client) /* {{{ */ { php_cli_server_request_dtor(&client->request); if (client->file_fd >= 0) { close(client->file_fd); client->file_fd = -1; } pefree(client->addr, 1); pefree(client->addr_str, 1); if (client->content_sender_initialized) { php_cli_server_content_sender_dtor(&client->content_sender); } } /* }}} */ static void php_cli_server_close_connection(php_cli_server *server, php_cli_server_client *client TSRMLS_DC) /* {{{ */ { #ifdef DEBUG php_cli_server_logf("%s Closing" TSRMLS_CC, client->addr_str); #endif zend_hash_index_del(&server->clients, client->sock); } /* }}} */ static int php_cli_server_send_error_page(php_cli_server *server, php_cli_server_client *client, int status TSRMLS_DC) /* {{{ */ { char *escaped_request_uri = NULL; size_t escaped_request_uri_len; const char *status_string = get_status_string(status); const char *content_template = get_template_string(status); char *errstr = get_last_error(); assert(status_string && content_template); php_cli_server_content_sender_ctor(&client->content_sender); client->content_sender_initialized = 1; escaped_request_uri = php_escape_html_entities_ex((unsigned char *)client->request.request_uri, client->request.request_uri_len, &escaped_request_uri_len, 0, ENT_QUOTES, NULL, 0 TSRMLS_CC); { static const char prologue_template[] = "%d %s"; php_cli_server_chunk *chunk = php_cli_server_chunk_heap_new_self_contained(strlen(prologue_template) + 3 + strlen(status_string) + 1); if (!chunk) { goto fail; } snprintf(chunk->data.heap.p, chunk->data.heap.len, prologue_template, status, status_string, escaped_request_uri); chunk->data.heap.len = strlen(chunk->data.heap.p); php_cli_server_buffer_append(&client->content_sender.buffer, chunk); } { php_cli_server_chunk *chunk = php_cli_server_chunk_immortal_new(php_cli_server_css, sizeof(php_cli_server_css) - 1); if (!chunk) { goto fail; } php_cli_server_buffer_append(&client->content_sender.buffer, chunk); } { static const char template[] = ""; php_cli_server_chunk *chunk = php_cli_server_chunk_immortal_new(template, sizeof(template) - 1); if (!chunk) { goto fail; } php_cli_server_buffer_append(&client->content_sender.buffer, chunk); } { php_cli_server_chunk *chunk = php_cli_server_chunk_heap_new_self_contained(strlen(content_template) + escaped_request_uri_len + 3 + strlen(status_string) + 1); if (!chunk) { goto fail; } snprintf(chunk->data.heap.p, chunk->data.heap.len, content_template, status_string, escaped_request_uri); chunk->data.heap.len = strlen(chunk->data.heap.p); php_cli_server_buffer_append(&client->content_sender.buffer, chunk); } { static const char epilogue_template[] = ""; php_cli_server_chunk *chunk = php_cli_server_chunk_immortal_new(epilogue_template, sizeof(epilogue_template) - 1); if (!chunk) { goto fail; } php_cli_server_buffer_append(&client->content_sender.buffer, chunk); } { php_cli_server_chunk *chunk; smart_str buffer = { 0 }; append_http_status_line(&buffer, client->request.protocol_version, status, 1); if (!buffer.c) { /* out of memory */ goto fail; } append_essential_headers(&buffer, client, 1); smart_str_appends_ex(&buffer, "Content-Type: text/html; charset=UTF-8\r\n", 1); smart_str_appends_ex(&buffer, "Content-Length: ", 1); smart_str_append_generic_ex(&buffer, php_cli_server_buffer_size(&client->content_sender.buffer), 1, size_t, _unsigned); smart_str_appendl_ex(&buffer, "\r\n", 2, 1); smart_str_appendl_ex(&buffer, "\r\n", 2, 1); chunk = php_cli_server_chunk_heap_new(buffer.c, buffer.c, buffer.len); if (!chunk) { smart_str_free_ex(&buffer, 1); goto fail; } php_cli_server_buffer_prepend(&client->content_sender.buffer, chunk); } php_cli_server_log_response(client, status, errstr ? errstr : "?" TSRMLS_CC); php_cli_server_poller_add(&server->poller, POLLOUT, client->sock); if (errstr) { pefree(errstr, 1); } efree(escaped_request_uri); return SUCCESS; fail: if (errstr) { pefree(errstr, 1); } efree(escaped_request_uri); return FAILURE; } /* }}} */ static int php_cli_server_dispatch_script(php_cli_server *server, php_cli_server_client *client TSRMLS_DC) /* {{{ */ { if (strlen(client->request.path_translated) != client->request.path_translated_len) { /* can't handle paths that contain nul bytes */ return php_cli_server_send_error_page(server, client, 400 TSRMLS_CC); } { zend_file_handle zfd; zfd.type = ZEND_HANDLE_FILENAME; zfd.filename = SG(request_info).path_translated; zfd.handle.fp = NULL; zfd.free_filename = 0; zfd.opened_path = NULL; zend_try { php_execute_script(&zfd TSRMLS_CC); } zend_end_try(); } php_cli_server_log_response(client, SG(sapi_headers).http_response_code, NULL TSRMLS_CC); return SUCCESS; } /* }}} */ static int php_cli_server_begin_send_static(php_cli_server *server, php_cli_server_client *client TSRMLS_DC) /* {{{ */ { int fd; int status = 200; if (client->request.path_translated && strlen(client->request.path_translated) != client->request.path_translated_len) { /* can't handle paths that contain nul bytes */ return php_cli_server_send_error_page(server, client, 400 TSRMLS_CC); } #ifdef PHP_WIN32 /* The win32 namespace will cut off trailing dots and spaces. Since the VCWD functionality isn't used here, a sophisticated functionality would have to be reimplemented to know ahead there are no files with invalid names there. The simplest is just to forbid invalid filenames, which is done here. */ if (client->request.path_translated && ('.' == client->request.path_translated[client->request.path_translated_len-1] || ' ' == client->request.path_translated[client->request.path_translated_len-1])) { return php_cli_server_send_error_page(server, client, 500 TSRMLS_CC); } #endif fd = client->request.path_translated ? open(client->request.path_translated, O_RDONLY): -1; if (fd < 0) { return php_cli_server_send_error_page(server, client, 404 TSRMLS_CC); } php_cli_server_content_sender_ctor(&client->content_sender); client->content_sender_initialized = 1; client->file_fd = fd; { php_cli_server_chunk *chunk; smart_str buffer = { 0 }; const char *mime_type = get_mime_type(client->request.ext, client->request.ext_len); if (!mime_type) { mime_type = "application/octet-stream"; } append_http_status_line(&buffer, client->request.protocol_version, status, 1); if (!buffer.c) { /* out of memory */ php_cli_server_log_response(client, 500, NULL TSRMLS_CC); return FAILURE; } append_essential_headers(&buffer, client, 1); smart_str_appendl_ex(&buffer, "Content-Type: ", sizeof("Content-Type: ") - 1, 1); smart_str_appends_ex(&buffer, mime_type, 1); if (strncmp(mime_type, "text/", 5) == 0) { smart_str_appends_ex(&buffer, "; charset=UTF-8", 1); } smart_str_appendl_ex(&buffer, "\r\n", 2, 1); smart_str_appends_ex(&buffer, "Content-Length: ", 1); smart_str_append_generic_ex(&buffer, client->request.sb.st_size, 1, size_t, _unsigned); smart_str_appendl_ex(&buffer, "\r\n", 2, 1); smart_str_appendl_ex(&buffer, "\r\n", 2, 1); chunk = php_cli_server_chunk_heap_new(buffer.c, buffer.c, buffer.len); if (!chunk) { smart_str_free_ex(&buffer, 1); php_cli_server_log_response(client, 500, NULL TSRMLS_CC); return FAILURE; } php_cli_server_buffer_append(&client->content_sender.buffer, chunk); } php_cli_server_log_response(client, 200, NULL TSRMLS_CC); php_cli_server_poller_add(&server->poller, POLLOUT, client->sock); return SUCCESS; } /* }}} */ static int php_cli_server_request_startup(php_cli_server *server, php_cli_server_client *client TSRMLS_DC) { /* {{{ */ char **auth; php_cli_server_client_populate_request_info(client, &SG(request_info)); if (SUCCESS == zend_hash_find(&client->request.headers, "authorization", sizeof("authorization"), (void**)&auth)) { php_handle_auth_data(*auth TSRMLS_CC); } SG(sapi_headers).http_response_code = 200; if (FAILURE == php_request_startup(TSRMLS_C)) { /* should never be happen */ destroy_request_info(&SG(request_info)); return FAILURE; } PG(during_request_startup) = 0; return SUCCESS; } /* }}} */ static int php_cli_server_request_shutdown(php_cli_server *server, php_cli_server_client *client TSRMLS_DC) { /* {{{ */ php_request_shutdown(0); php_cli_server_close_connection(server, client TSRMLS_CC); destroy_request_info(&SG(request_info)); SG(server_context) = NULL; SG(rfc1867_uploaded_files) = NULL; return SUCCESS; } /* }}} */ static int php_cli_server_dispatch_router(php_cli_server *server, php_cli_server_client *client TSRMLS_DC) /* {{{ */ { int decline = 0; zend_file_handle zfd; char *old_cwd; ALLOCA_FLAG(use_heap) old_cwd = do_alloca(MAXPATHLEN, use_heap); old_cwd[0] = '\0'; php_ignore_value(VCWD_GETCWD(old_cwd, MAXPATHLEN - 1)); zfd.type = ZEND_HANDLE_FILENAME; zfd.filename = server->router; zfd.handle.fp = NULL; zfd.free_filename = 0; zfd.opened_path = NULL; zend_try { zval *retval = NULL; if (SUCCESS == zend_execute_scripts(ZEND_REQUIRE TSRMLS_CC, &retval, 1, &zfd)) { if (retval) { decline = Z_TYPE_P(retval) == IS_BOOL && !Z_LVAL_P(retval); zval_ptr_dtor(&retval); } } else { decline = 1; } } zend_end_try(); if (old_cwd[0] != '\0') { php_ignore_value(VCWD_CHDIR(old_cwd)); } free_alloca(old_cwd, use_heap); return decline; } /* }}} */ static int php_cli_server_dispatch(php_cli_server *server, php_cli_server_client *client TSRMLS_DC) /* {{{ */ { int is_static_file = 0; SG(server_context) = client; if (client->request.ext_len != 3 || memcmp(client->request.ext, "php", 3) || !client->request.path_translated) { is_static_file = 1; } if (server->router || !is_static_file) { if (FAILURE == php_cli_server_request_startup(server, client TSRMLS_CC)) { SG(server_context) = NULL; php_cli_server_close_connection(server, client TSRMLS_CC); destroy_request_info(&SG(request_info)); return SUCCESS; } } if (server->router) { if (!php_cli_server_dispatch_router(server, client TSRMLS_CC)) { php_cli_server_request_shutdown(server, client TSRMLS_CC); return SUCCESS; } } if (!is_static_file) { if (SUCCESS == php_cli_server_dispatch_script(server, client TSRMLS_CC) || SUCCESS != php_cli_server_send_error_page(server, client, 500 TSRMLS_CC)) { if (SG(sapi_headers).http_response_code == 304) { SG(sapi_headers).send_default_content_type = 0; } php_cli_server_request_shutdown(server, client TSRMLS_CC); return SUCCESS; } } else { if (server->router) { static int (*send_header_func)(sapi_headers_struct * TSRMLS_DC); send_header_func = sapi_module.send_headers; /* do not generate default content type header */ SG(sapi_headers).send_default_content_type = 0; /* we don't want headers to be sent */ sapi_module.send_headers = sapi_cli_server_discard_headers; php_request_shutdown(0); sapi_module.send_headers = send_header_func; SG(sapi_headers).send_default_content_type = 1; SG(rfc1867_uploaded_files) = NULL; } if (SUCCESS != php_cli_server_begin_send_static(server, client TSRMLS_CC)) { php_cli_server_close_connection(server, client TSRMLS_CC); } SG(server_context) = NULL; return SUCCESS; } SG(server_context) = NULL; destroy_request_info(&SG(request_info)); return SUCCESS; } /* }}} */ static void php_cli_server_dtor(php_cli_server *server TSRMLS_DC) /* {{{ */ { zend_hash_destroy(&server->clients); if (server->server_sock >= 0) { closesocket(server->server_sock); } if (server->host) { pefree(server->host, 1); } if (server->document_root) { pefree(server->document_root, 1); } if (server->router) { pefree(server->router, 1); } } /* }}} */ static void php_cli_server_client_dtor_wrapper(php_cli_server_client **p) /* {{{ */ { closesocket((*p)->sock); php_cli_server_poller_remove(&(*p)->server->poller, POLLIN | POLLOUT, (*p)->sock); php_cli_server_client_dtor(*p); pefree(*p, 1); } /* }}} */ static int php_cli_server_ctor(php_cli_server *server, const char *addr, const char *document_root, const char *router TSRMLS_DC) /* {{{ */ { int retval = SUCCESS; char *host = NULL; char *errstr = NULL; char *_document_root = NULL; char *_router = NULL; int err = 0; int port = 3000; php_socket_t server_sock = SOCK_ERR; char *p = NULL; if (addr[0] == '[') { host = pestrdup(addr + 1, 1); if (!host) { return FAILURE; } p = strchr(host, ']'); if (p) { *p++ = '\0'; if (*p == ':') { port = strtol(p + 1, &p, 10); if (port <= 0 || port > 65535) { p = NULL; } } else if (*p != '\0') { p = NULL; } } } else { host = pestrdup(addr, 1); if (!host) { return FAILURE; } p = strchr(host, ':'); if (p) { *p++ = '\0'; port = strtol(p, &p, 10); if (port <= 0 || port > 65535) { p = NULL; } } } if (!p) { fprintf(stderr, "Invalid address: %s\n", addr); retval = FAILURE; goto out; } server_sock = php_network_listen_socket(host, &port, SOCK_STREAM, &server->address_family, &server->socklen, &errstr TSRMLS_CC); if (server_sock == SOCK_ERR) { php_cli_server_logf("Failed to listen on %s:%d (reason: %s)" TSRMLS_CC, host, port, errstr ? errstr: "?"); efree(errstr); retval = FAILURE; goto out; } server->server_sock = server_sock; err = php_cli_server_poller_ctor(&server->poller); if (SUCCESS != err) { goto out; } php_cli_server_poller_add(&server->poller, POLLIN, server_sock); server->host = host; server->port = port; zend_hash_init(&server->clients, 0, NULL, (void(*)(void*))php_cli_server_client_dtor_wrapper, 1); { size_t document_root_len = strlen(document_root); _document_root = pestrndup(document_root, document_root_len, 1); if (!_document_root) { retval = FAILURE; goto out; } server->document_root = _document_root; server->document_root_len = document_root_len; } if (router) { size_t router_len = strlen(router); _router = pestrndup(router, router_len, 1); if (!_router) { retval = FAILURE; goto out; } server->router = _router; server->router_len = router_len; } else { server->router = NULL; server->router_len = 0; } server->is_running = 1; out: if (retval != SUCCESS) { if (host) { pefree(host, 1); } if (_document_root) { pefree(_document_root, 1); } if (_router) { pefree(_router, 1); } if (server_sock > -1) { closesocket(server_sock); } } return retval; } /* }}} */ static int php_cli_server_recv_event_read_request(php_cli_server *server, php_cli_server_client *client TSRMLS_DC) /* {{{ */ { char *errstr = NULL; int status = php_cli_server_client_read_request(client, &errstr TSRMLS_CC); if (status < 0) { php_cli_server_logf("%s Invalid request (%s)" TSRMLS_CC, client->addr_str, errstr); efree(errstr); php_cli_server_close_connection(server, client TSRMLS_CC); return FAILURE; } else if (status == 1 && client->request.request_method == PHP_HTTP_NOT_IMPLEMENTED) { return php_cli_server_send_error_page(server, client, 501 TSRMLS_CC); } else if (status == 1) { php_cli_server_poller_remove(&server->poller, POLLIN, client->sock); php_cli_server_dispatch(server, client TSRMLS_CC); } else { php_cli_server_poller_add(&server->poller, POLLIN, client->sock); } return SUCCESS; } /* }}} */ static int php_cli_server_send_event(php_cli_server *server, php_cli_server_client *client TSRMLS_DC) /* {{{ */ { if (client->content_sender_initialized) { if (client->file_fd >= 0 && !client->content_sender.buffer.first) { size_t nbytes_read; if (php_cli_server_content_sender_pull(&client->content_sender, client->file_fd, &nbytes_read)) { php_cli_server_close_connection(server, client TSRMLS_CC); return FAILURE; } if (nbytes_read == 0) { close(client->file_fd); client->file_fd = -1; } } { size_t nbytes_sent; int err = php_cli_server_content_sender_send(&client->content_sender, client->sock, &nbytes_sent); if (err && err != SOCK_EAGAIN) { php_cli_server_close_connection(server, client TSRMLS_CC); return FAILURE; } } if (!client->content_sender.buffer.first && client->file_fd < 0) { php_cli_server_close_connection(server, client TSRMLS_CC); } } return SUCCESS; } /* }}} */ typedef struct php_cli_server_do_event_for_each_fd_callback_params { #ifdef ZTS void ***tsrm_ls; #endif php_cli_server *server; int(*rhandler)(php_cli_server*, php_cli_server_client* TSRMLS_DC); int(*whandler)(php_cli_server*, php_cli_server_client* TSRMLS_DC); } php_cli_server_do_event_for_each_fd_callback_params; static int php_cli_server_do_event_for_each_fd_callback(void *_params, int fd, int event) /* {{{ */ { php_cli_server_do_event_for_each_fd_callback_params *params = _params; #ifdef ZTS void ***tsrm_ls = params->tsrm_ls; #endif php_cli_server *server = params->server; if (server->server_sock == fd) { php_cli_server_client *client = NULL; php_socket_t client_sock; socklen_t socklen = server->socklen; struct sockaddr *sa = pemalloc(server->socklen, 1); if (!sa) { return FAILURE; } client_sock = accept(server->server_sock, sa, &socklen); if (client_sock < 0) { char *errstr; errstr = php_socket_strerror(php_socket_errno(), NULL, 0); php_cli_server_logf("Failed to accept a client (reason: %s)" TSRMLS_CC, errstr); efree(errstr); pefree(sa, 1); return SUCCESS; } if (SUCCESS != php_set_sock_blocking(client_sock, 0 TSRMLS_CC)) { pefree(sa, 1); closesocket(client_sock); return SUCCESS; } if (!(client = pemalloc(sizeof(php_cli_server_client), 1)) || FAILURE == php_cli_server_client_ctor(client, server, client_sock, sa, socklen TSRMLS_CC)) { php_cli_server_logf("Failed to create a new request object" TSRMLS_CC); pefree(sa, 1); closesocket(client_sock); return SUCCESS; } #ifdef DEBUG php_cli_server_logf("%s Accepted" TSRMLS_CC, client->addr_str); #endif zend_hash_index_update(&server->clients, client_sock, &client, sizeof(client), NULL); php_cli_server_recv_event_read_request(server, client TSRMLS_CC); } else { php_cli_server_client **client; if (SUCCESS == zend_hash_index_find(&server->clients, fd, (void **)&client)) { if (event & POLLIN) { params->rhandler(server, *client TSRMLS_CC); } if (event & POLLOUT) { params->whandler(server, *client TSRMLS_CC); } } } return SUCCESS; } /* }}} */ static void php_cli_server_do_event_for_each_fd(php_cli_server *server, int(*rhandler)(php_cli_server*, php_cli_server_client* TSRMLS_DC), int(*whandler)(php_cli_server*, php_cli_server_client* TSRMLS_DC) TSRMLS_DC) /* {{{ */ { php_cli_server_do_event_for_each_fd_callback_params params = { #ifdef ZTS tsrm_ls, #endif server, rhandler, whandler }; php_cli_server_poller_iter_on_active(&server->poller, ¶ms, php_cli_server_do_event_for_each_fd_callback); } /* }}} */ static int php_cli_server_do_event_loop(php_cli_server *server TSRMLS_DC) /* {{{ */ { int retval = SUCCESS; while (server->is_running) { struct timeval tv = { 1, 0 }; int n = php_cli_server_poller_poll(&server->poller, &tv); if (n > 0) { php_cli_server_do_event_for_each_fd(server, php_cli_server_recv_event_read_request, php_cli_server_send_event TSRMLS_CC); } else if (n == 0) { /* do nothing */ } else { int err = php_socket_errno(); if (err != SOCK_EINTR) { char *errstr = php_socket_strerror(err, NULL, 0); php_cli_server_logf("%s" TSRMLS_CC, errstr); efree(errstr); retval = FAILURE; goto out; } } } out: return retval; } /* }}} */ static php_cli_server server; static void php_cli_server_sigint_handler(int sig) /* {{{ */ { server.is_running = 0; } /* }}} */ int do_cli_server(int argc, char **argv TSRMLS_DC) /* {{{ */ { char *php_optarg = NULL; int php_optind = 1; int c; const char *server_bind_address = NULL; extern const opt_struct OPTIONS[]; const char *document_root = NULL; const char *router = NULL; char document_root_buf[MAXPATHLEN]; while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2))!=-1) { switch (c) { case 'S': server_bind_address = php_optarg; break; case 't': document_root = php_optarg; break; } } if (document_root) { struct stat sb; if (stat(document_root, &sb)) { fprintf(stderr, "Directory %s does not exist.\n", document_root); return 1; } if (!S_ISDIR(sb.st_mode)) { fprintf(stderr, "%s is not a directory.\n", document_root); return 1; } if (VCWD_REALPATH(document_root, document_root_buf)) { document_root = document_root_buf; } } else { char *ret = NULL; #if HAVE_GETCWD ret = VCWD_GETCWD(document_root_buf, MAXPATHLEN); #elif HAVE_GETWD ret = VCWD_GETWD(document_root_buf); #endif document_root = ret ? document_root_buf: "."; } if (argc > php_optind) { router = argv[php_optind]; } if (FAILURE == php_cli_server_ctor(&server, server_bind_address, document_root, router TSRMLS_CC)) { return 1; } sapi_module.phpinfo_as_text = 0; { char buf[52]; if (php_cli_server_get_system_time(buf) != 0) { memmove(buf, "unknown time, can't be fetched", sizeof("unknown time, can't be fetched")); } printf("PHP %s Development Server started at %s" "Listening on http://%s\n" "Document root is %s\n" "Press Ctrl-C to quit.\n", PHP_VERSION, buf, server_bind_address, document_root); } #if defined(HAVE_SIGNAL_H) && defined(SIGINT) signal(SIGINT, php_cli_server_sigint_handler); #endif php_cli_server_do_event_loop(&server TSRMLS_CC); php_cli_server_dtor(&server TSRMLS_CC); return 0; } /* }}} */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ PK!4g/ / php_cli_process_title.cnu[/* +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2016 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Keyur Govande (kgovande@gmail.com) | +----------------------------------------------------------------------+ */ /* $Id$ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include "php_cli_process_title.h" #include "ps_title.h" /* {{{ proto boolean cli_set_process_title(string arg) Return a boolean to confirm if the process title was successfully changed or not */ PHP_FUNCTION(cli_set_process_title) { char *title = NULL; int title_len; int rc; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &title, &title_len) == FAILURE) { return; } rc = set_ps_title(title); if (rc == PS_TITLE_SUCCESS) { RETURN_TRUE; } php_error_docref(NULL TSRMLS_CC, E_WARNING, "cli_set_process_title had an error: %s", ps_title_errno(rc)); RETURN_FALSE; } /* }}} */ /* {{{ proto string cli_get_process_title() Return a string with the current process title. NULL if error. */ PHP_FUNCTION(cli_get_process_title) { int length = 0; const char* title = NULL; int rc; if (zend_parse_parameters_none() == FAILURE) { return; } rc = get_ps_title(&length, &title); if (rc != PS_TITLE_SUCCESS) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "cli_get_process_title had an error: %s", ps_title_errno(rc)); RETURN_NULL(); } RETURN_STRINGL(title, length, 1); } /* }}} */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ PK!V ps_title.hnu[/* +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2016 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Keyur Govande | +----------------------------------------------------------------------+ */ /* $Id$ */ #ifndef PS_TITLE_HEADER #define PS_TITLE_HEADER #define PS_TITLE_SUCCESS 0 #define PS_TITLE_NOT_AVAILABLE 1 #define PS_TITLE_NOT_INITIALIZED 2 #define PS_TITLE_BUFFER_NOT_AVAILABLE 3 #define PS_TITLE_WINDOWS_ERROR 4 extern char** save_ps_args(int argc, char** argv); extern int set_ps_title(const char* new_str); extern int get_ps_title(int* displen, const char** string); extern const char* ps_title_errno(int rc); extern int is_ps_title_available(); extern void cleanup_ps_args(char **argv); #endif // PS_TITLE_HEADER PK!saFYEEphp_cli_server.hnu[/* +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2016 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Moriyoshi Koizumi | +----------------------------------------------------------------------+ */ /* $Id: php_cli.c 306938 2011-01-01 02:17:06Z felipe $ */ #ifndef PHP_CLI_SERVER_H #define PHP_CLI_SERVER_H #include "SAPI.h" extern const zend_function_entry server_additional_functions[]; extern sapi_module_struct cli_server_sapi_module; extern int do_cli_server(int argc, char **argv TSRMLS_DC); ZEND_BEGIN_MODULE_GLOBALS(cli_server) short color; ZEND_END_MODULE_GLOBALS(cli_server) #ifdef ZTS #define CLI_SERVER_G(v) TSRMG(cli_server_globals_id, zend_cli_server_globals *, v) #else #define CLI_SERVER_G(v) (cli_server_globals.v) #endif #endif /* PHP_CLI_SERVER_H */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ PK!lW00 ps_title.cnu[/* * PostgreSQL is released under the PostgreSQL License, a liberal Open Source * license, similar to the BSD or MIT licenses. * PostgreSQL Database Management System (formerly known as Postgres, then as * Postgres95) * * Portions Copyright (c) 1996-2015, The PostgreSQL Global Development Group * * Portions Copyright (c) 1994, The Regents of the University of California * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without a written * agreement is hereby granted, provided that the above copyright notice * and this paragraph and the following two paragraphs appear in all copies. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, * EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN * "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * The following code is adopted from the PostgreSQL's ps_status(.h/.c). */ #include "ps_title.h" #include #ifdef HAVE_UNISTD_H #include #endif #include #include #ifdef PHP_WIN32 #include "config.w32.h" #include #include #else #include "php_config.h" extern char** environ; #endif #ifdef HAVE_SYS_PSTAT_H #include /* for HP-UX */ #endif #ifdef HAVE_PS_STRINGS #include /* for old BSD */ #include #endif #if defined(DARWIN) #include #endif /* * Ways of updating ps display: * * PS_USE_SETPROCTITLE * use the function setproctitle(const char *, ...) * (newer BSD systems) * PS_USE_PSTAT * use the pstat(PSTAT_SETCMD, ) * (HPUX) * PS_USE_PS_STRINGS * assign PS_STRINGS->ps_argvstr = "string" * (some BSD systems) * PS_USE_CHANGE_ARGV * assign argv[0] = "string" * (some other BSD systems) * PS_USE_CLOBBER_ARGV * write over the argv and environment area * (Linux and most SysV-like systems) * PS_USE_WIN32 * push the string out as the name of a Windows event * PS_USE_NONE * don't update ps display * (This is the default, as it is safest.) */ #if defined(HAVE_SETPROCTITLE) #define PS_USE_SETPROCTITLE #elif defined(HAVE_SYS_PSTAT_H) && defined(PSTAT_SETCMD) #define PS_USE_PSTAT #elif defined(HAVE_PS_STRINGS) #define PS_USE_PS_STRINGS #elif defined(BSD) && !defined(DARWIN) #define PS_USE_CHANGE_ARGV #elif defined(__linux__) || defined(_AIX) || defined(__sgi) || (defined(sun) && !defined(BSD)) || defined(ultrix) || defined(__osf__) || defined(DARWIN) #define PS_USE_CLOBBER_ARGV #elif defined(PHP_WIN32) #define PS_USE_WIN32 #else #define PS_USE_NONE #endif /* Different systems want the buffer padded differently */ #if defined(_AIX) || defined(__linux__) || defined(DARWIN) #define PS_PADDING '\0' #else #define PS_PADDING ' ' #endif #ifdef PS_USE_WIN32 static char windows_error_details[64]; static char ps_buffer[MAX_PATH]; static const size_t ps_buffer_size = MAX_PATH; #elif defined(PS_USE_CLOBBER_ARGV) static char *ps_buffer; /* will point to argv area */ static size_t ps_buffer_size; /* space determined at run time */ static char *empty_environ[] = {0}; /* empty environment */ #else #define PS_BUFFER_SIZE 256 static char ps_buffer[PS_BUFFER_SIZE]; static const size_t ps_buffer_size = PS_BUFFER_SIZE; #endif static size_t ps_buffer_cur_len; /* actual string length in ps_buffer */ /* save the original argv[] location here */ static int save_argc; static char** save_argv; /* * This holds the 'locally' allocated environ from the save_ps_args method. * This is subsequently free'd at exit. */ static char** frozen_environ, **new_environ; /* * Call this method early, before any code has used the original argv passed in * from main(). * If needed, this code will make deep copies of argv and environ and return * these to the caller for further use. The original argv is then 'clobbered' * to store the process title. */ char** save_ps_args(int argc, char** argv) { save_argc = argc; save_argv = argv; #if defined(PS_USE_CLOBBER_ARGV) /* * If we're going to overwrite the argv area, count the available space. * Also move the environment to make additional room. */ { char* end_of_area = NULL; int non_contiguous_area = 0; int i; /* * check for contiguous argv strings */ for (i = 0; (non_contiguous_area == 0) && (i < argc); i++) { if (i != 0 && end_of_area + 1 != argv[i]) non_contiguous_area = 1; end_of_area = argv[i] + strlen(argv[i]); } /* * check for contiguous environ strings following argv */ for (i = 0; (non_contiguous_area == 0) && (environ[i] != NULL); i++) { if (end_of_area + 1 != environ[i]) non_contiguous_area = 1; end_of_area = environ[i] + strlen(environ[i]); } if (non_contiguous_area != 0) goto clobber_error; ps_buffer = argv[0]; ps_buffer_size = end_of_area - argv[0]; /* * move the environment out of the way */ new_environ = (char **) malloc((i + 1) * sizeof(char *)); frozen_environ = (char **) malloc((i + 1) * sizeof(char *)); if (!new_environ || !frozen_environ) goto clobber_error; for (i = 0; environ[i] != NULL; i++) { new_environ[i] = strdup(environ[i]); if (!new_environ[i]) goto clobber_error; } new_environ[i] = NULL; environ = new_environ; memcpy((char *)frozen_environ, (char *)new_environ, sizeof(char *) * (i + 1)); } #endif /* PS_USE_CLOBBER_ARGV */ #if defined(PS_USE_CHANGE_ARGV) || defined(PS_USE_CLOBBER_ARGV) /* * If we're going to change the original argv[] then make a copy for * argument parsing purposes. * * (NB: do NOT think to remove the copying of argv[]! * On some platforms, getopt() keeps pointers into the argv array, and * will get horribly confused when it is re-called to analyze a subprocess' * argument string if the argv storage has been clobbered meanwhile. * Other platforms have other dependencies on argv[].) */ { char** new_argv; int i; new_argv = (char **) malloc((argc + 1) * sizeof(char *)); if (!new_argv) goto clobber_error; for (i = 0; i < argc; i++) { new_argv[i] = strdup(argv[i]); if (!new_argv[i]) goto clobber_error; } new_argv[argc] = NULL; #if defined(DARWIN) /* * Darwin (and perhaps other NeXT-derived platforms?) has a static * copy of the argv pointer, which we may fix like so: */ *_NSGetArgv() = new_argv; #endif argv = new_argv; } #endif /* PS_USE_CHANGE_ARGV or PS_USE_CLOBBER_ARGV */ #if defined(PS_USE_CLOBBER_ARGV) { /* make extra argv slots point at end_of_area (a NUL) */ int i; for (i = 1; i < save_argc; i++) save_argv[i] = ps_buffer + ps_buffer_size; } #endif /* PS_USE_CLOBBER_ARGV */ #ifdef PS_USE_CHANGE_ARGV save_argv[0] = ps_buffer; /* ps_buffer here is a static const array of size PS_BUFFER_SIZE */ save_argv[1] = NULL; #endif /* PS_USE_CHANGE_ARGV */ return argv; #if defined(PS_USE_CHANGE_ARGV) || defined(PS_USE_CLOBBER_ARGV) clobber_error: /* probably can't happen?! * if we ever get here, argv still points to originally passed * in argument */ save_argv = NULL; save_argc = 0; ps_buffer = NULL; ps_buffer_size = 0; return argv; #endif /* PS_USE_CHANGE_ARGV or PS_USE_CLOBBER_ARGV */ } /* * Returns PS_TITLE_SUCCESS if the OS supports this functionality * and the init function was called. * Otherwise returns NOT_AVAILABLE or NOT_INITIALIZED */ int is_ps_title_available() { #ifdef PS_USE_NONE return PS_TITLE_NOT_AVAILABLE; /* disabled functionality */ #endif if (!save_argv) return PS_TITLE_NOT_INITIALIZED; #ifdef PS_USE_CLOBBER_ARGV if (!ps_buffer) return PS_TITLE_BUFFER_NOT_AVAILABLE; #endif /* PS_USE_CLOBBER_ARGV */ return PS_TITLE_SUCCESS; } /* * Convert error codes into error strings */ const char* ps_title_errno(int rc) { switch(rc) { case PS_TITLE_SUCCESS: return "Success"; case PS_TITLE_NOT_AVAILABLE: return "Not available on this OS"; case PS_TITLE_NOT_INITIALIZED: return "Not initialized correctly"; case PS_TITLE_BUFFER_NOT_AVAILABLE: return "Buffer not contiguous"; #ifdef PS_USE_WIN32 case PS_TITLE_WINDOWS_ERROR: sprintf(windows_error_details, "Windows error code: %d", GetLastError()); return windows_error_details; #endif } return "Unknown error code"; } /* * Set a new process title. * Returns the appropriate error code if if there's an error * (like the functionality is compile time disabled, or the * save_ps_args() was not called. * Else returns 0 on success. */ int set_ps_title(const char* title) { int rc = is_ps_title_available(); if (rc != PS_TITLE_SUCCESS) return rc; strncpy(ps_buffer, title, ps_buffer_size); ps_buffer[ps_buffer_size - 1] = '\0'; ps_buffer_cur_len = strlen(ps_buffer); #ifdef PS_USE_SETPROCTITLE setproctitle("%s", ps_buffer); #endif #ifdef PS_USE_PSTAT { union pstun pst; pst.pst_command = ps_buffer; pstat(PSTAT_SETCMD, pst, ps_buffer_cur_len, 0, 0); } #endif /* PS_USE_PSTAT */ #ifdef PS_USE_PS_STRINGS PS_STRINGS->ps_nargvstr = 1; PS_STRINGS->ps_argvstr = ps_buffer; #endif /* PS_USE_PS_STRINGS */ #ifdef PS_USE_CLOBBER_ARGV /* pad unused memory */ if (ps_buffer_cur_len < ps_buffer_size) { memset(ps_buffer + ps_buffer_cur_len, PS_PADDING, ps_buffer_size - ps_buffer_cur_len); } #endif /* PS_USE_CLOBBER_ARGV */ #ifdef PS_USE_WIN32 { if (!SetConsoleTitle(ps_buffer)) return PS_TITLE_WINDOWS_ERROR; } #endif /* PS_USE_WIN32 */ return PS_TITLE_SUCCESS; } /* * Returns the current ps_buffer value into string. On some platforms * the string will not be null-terminated, so return the effective * length into *displen. * The return code indicates the error. */ int get_ps_title(int *displen, const char** string) { int rc = is_ps_title_available(); if (rc != PS_TITLE_SUCCESS) return rc; #ifdef PS_USE_WIN32 if (!(ps_buffer_cur_len = GetConsoleTitle(ps_buffer, ps_buffer_size))) return PS_TITLE_WINDOWS_ERROR; #endif *displen = (int)ps_buffer_cur_len; *string = ps_buffer; return PS_TITLE_SUCCESS; } /* * Clean up the allocated argv and environ if applicable. Only call * this right before exiting. * This isn't needed per-se because the OS will clean-up anyway, but * having and calling this will ensure Valgrind doesn't output 'false * positives'. */ void cleanup_ps_args(char **argv) { #ifndef PS_USE_NONE if (save_argv) { save_argv = NULL; save_argc = 0; #ifdef PS_USE_CLOBBER_ARGV { int i; for (i = 0; frozen_environ[i] != NULL; i++) free(frozen_environ[i]); free(frozen_environ); free(new_environ); /* leave a sane environment behind since some atexit() handlers call getenv(). */ environ = empty_environ; } #endif /* PS_USE_CLOBBER_ARGV */ #if defined(PS_USE_CHANGE_ARGV) || defined(PS_USE_CLOBBER_ARGV) { int i; for (i=0; argv[i] != NULL; i++) free(argv[i]); free(argv); } #endif /* PS_USE_CHANGE_ARGV or PS_USE_CLOBBER_ARGV */ } #endif /* PS_USE_NONE */ return; } PK!8php_http_parser.hnu[/* Copyright 2009,2010 Ryan Dahl * * 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. */ /* modified by Moriyoshi Koizumi to make it fit to PHP source tree. */ #ifndef php_http_parser_h #define php_http_parser_h #ifdef __cplusplus extern "C" { #endif #include #if defined(_WIN32) && !defined(__MINGW32__) # include # include "config.w32.h" #else # include "php_config.h" #endif #include "php_stdint.h" /* Compile with -DPHP_HTTP_PARSER_STRICT=0 to make less checks, but run * faster */ #ifndef PHP_HTTP_PARSER_STRICT # define PHP_HTTP_PARSER_STRICT 1 #else # define PHP_HTTP_PARSER_STRICT 0 #endif /* Maximium header size allowed */ #define PHP_HTTP_MAX_HEADER_SIZE (80*1024) typedef struct php_http_parser php_http_parser; typedef struct php_http_parser_settings php_http_parser_settings; /* Callbacks should return non-zero to indicate an error. The parser will * then halt execution. * * The one exception is on_headers_complete. In a PHP_HTTP_RESPONSE parser * returning '1' from on_headers_complete will tell the parser that it * should not expect a body. This is used when receiving a response to a * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: * chunked' headers that indicate the presence of a body. * * http_data_cb does not return data chunks. It will be call arbitrarally * many times for each string. E.G. you might get 10 callbacks for "on_path" * each providing just a few characters more data. */ typedef int (*php_http_data_cb) (php_http_parser*, const char *at, size_t length); typedef int (*php_http_cb) (php_http_parser*); /* Request Methods */ enum php_http_method { PHP_HTTP_DELETE = 0 , PHP_HTTP_GET , PHP_HTTP_HEAD , PHP_HTTP_POST , PHP_HTTP_PUT , PHP_HTTP_PATCH /* pathological */ , PHP_HTTP_CONNECT , PHP_HTTP_OPTIONS , PHP_HTTP_TRACE /* webdav */ , PHP_HTTP_COPY , PHP_HTTP_LOCK , PHP_HTTP_MKCOL , PHP_HTTP_MOVE , PHP_HTTP_MKCALENDAR , PHP_HTTP_PROPFIND , PHP_HTTP_PROPPATCH , PHP_HTTP_UNLOCK /* subversion */ , PHP_HTTP_REPORT , PHP_HTTP_MKACTIVITY , PHP_HTTP_CHECKOUT , PHP_HTTP_MERGE /* upnp */ , PHP_HTTP_MSEARCH , PHP_HTTP_NOTIFY , PHP_HTTP_SUBSCRIBE , PHP_HTTP_UNSUBSCRIBE /* unknown, not implemented */ , PHP_HTTP_NOT_IMPLEMENTED }; enum php_http_parser_type { PHP_HTTP_REQUEST, PHP_HTTP_RESPONSE, PHP_HTTP_BOTH }; struct php_http_parser { /** PRIVATE **/ unsigned char type : 2; unsigned char flags : 6; unsigned char state; unsigned char header_state; unsigned char index; uint32_t nread; ssize_t content_length; /** READ-ONLY **/ unsigned short http_major; unsigned short http_minor; unsigned short status_code; /* responses only */ unsigned char method; /* requests only */ /* 1 = Upgrade header was present and the parser has exited because of that. * 0 = No upgrade header present. * Should be checked when http_parser_execute() returns in addition to * error checking. */ char upgrade; /** PUBLIC **/ void *data; /* A pointer to get hook to the "connection" or "socket" object */ }; struct php_http_parser_settings { php_http_cb on_message_begin; php_http_data_cb on_path; php_http_data_cb on_query_string; php_http_data_cb on_url; php_http_data_cb on_fragment; php_http_data_cb on_header_field; php_http_data_cb on_header_value; php_http_cb on_headers_complete; php_http_data_cb on_body; php_http_cb on_message_complete; }; void php_http_parser_init(php_http_parser *parser, enum php_http_parser_type type); size_t php_http_parser_execute(php_http_parser *parser, const php_http_parser_settings *settings, const char *data, size_t len); /* If php_http_should_keep_alive() in the on_headers_complete or * on_message_complete callback returns true, then this will be should be * the last message on the connection. * If you are the server, respond with the "Connection: close" header. * If you are the client, close the connection. */ int php_http_should_keep_alive(php_http_parser *parser); /* Returns a string version of the HTTP method. */ const char *php_http_method_str(enum php_http_method); #ifdef __cplusplus } #endif #endif PK! Pphp_http_parser.cnu[/* Copyright 2009,2010 Ryan Dahl * * 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 #include "php_http_parser.h" #ifndef MIN # define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif #define CALLBACK2(FOR) \ do { \ if (settings->on_##FOR) { \ if (0 != settings->on_##FOR(parser)) return (p - data); \ } \ } while (0) #define MARK(FOR) \ do { \ FOR##_mark = p; \ } while (0) #define CALLBACK_NOCLEAR(FOR) \ do { \ if (FOR##_mark) { \ if (settings->on_##FOR) { \ if (0 != settings->on_##FOR(parser, \ FOR##_mark, \ p - FOR##_mark)) \ { \ return (p - data); \ } \ } \ } \ } while (0) #ifdef PHP_WIN32 # undef CALLBACK #endif #define CALLBACK(FOR) \ do { \ CALLBACK_NOCLEAR(FOR); \ FOR##_mark = NULL; \ } while (0) #define PROXY_CONNECTION "proxy-connection" #define CONNECTION "connection" #define CONTENT_LENGTH "content-length" #define TRANSFER_ENCODING "transfer-encoding" #define UPGRADE "upgrade" #define CHUNKED "chunked" #define KEEP_ALIVE "keep-alive" #define CLOSE "close" static const char *method_strings[] = { "DELETE" , "GET" , "HEAD" , "POST" , "PUT" , "PATCH" , "CONNECT" , "OPTIONS" , "TRACE" , "COPY" , "LOCK" , "MKCOL" , "MOVE" , "MKCALENDAR" , "PROPFIND" , "PROPPATCH" , "UNLOCK" , "REPORT" , "MKACTIVITY" , "CHECKOUT" , "MERGE" , "M-SEARCH" , "NOTIFY" , "SUBSCRIBE" , "UNSUBSCRIBE" , "NOTIMPLEMENTED" }; /* Tokens as defined by rfc 2616. Also lowercases them. * token = 1* * separators = "(" | ")" | "<" | ">" | "@" * | "," | ";" | ":" | "\" | <"> * | "/" | "[" | "]" | "?" | "=" * | "{" | "}" | SP | HT */ static const char tokens[256] = { /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ 0, 0, 0, 0, 0, 0, 0, 0, /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ 0, 0, 0, 0, 0, 0, 0, 0, /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ 0, 0, 0, 0, 0, 0, 0, 0, /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ 0, 0, 0, 0, 0, 0, 0, 0, /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ ' ', '!', '"', '#', '$', '%', '&', '\'', /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ 0, 0, '*', '+', 0, '-', '.', '/', /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ '0', '1', '2', '3', '4', '5', '6', '7', /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ '8', '9', 0, 0, 0, 0, 0, 0, /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ 'x', 'y', 'z', 0, 0, 0, '^', '_', /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ 'x', 'y', 'z', 0, '|', '}', '~', 0 }; static const int8_t unhex[256] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 }; static const uint8_t normal_url_char[256] = { /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ 0, 0, 0, 0, 0, 0, 0, 0, /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ 0, 0, 0, 0, 0, 0, 0, 0, /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ 0, 0, 0, 0, 0, 0, 0, 0, /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ 0, 0, 0, 0, 0, 0, 0, 0, /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ 0, 1, 1, 0, 1, 1, 1, 1, /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ 1, 1, 1, 1, 1, 1, 1, 1, /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ 1, 1, 1, 1, 1, 1, 1, 1, /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ 1, 1, 1, 1, 1, 1, 1, 0, /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ 1, 1, 1, 1, 1, 1, 1, 1, /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ 1, 1, 1, 1, 1, 1, 1, 1, /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ 1, 1, 1, 1, 1, 1, 1, 1, /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ 1, 1, 1, 1, 1, 1, 1, 1, /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ 1, 1, 1, 1, 1, 1, 1, 1, /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ 1, 1, 1, 1, 1, 1, 1, 1, /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ 1, 1, 1, 1, 1, 1, 1, 1, /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ 1, 1, 1, 1, 1, 1, 1, 0 }; enum state { s_dead = 1 /* important that this is > 0 */ , s_start_req_or_res , s_res_or_resp_H , s_start_res , s_res_H , s_res_HT , s_res_HTT , s_res_HTTP , s_res_first_http_major , s_res_http_major , s_res_first_http_minor , s_res_http_minor , s_res_first_status_code , s_res_status_code , s_res_status , s_res_line_almost_done , s_start_req , s_req_method , s_req_spaces_before_url , s_req_schema , s_req_schema_slash , s_req_schema_slash_slash , s_req_host , s_req_port , s_req_path , s_req_query_string_start , s_req_query_string , s_req_fragment_start , s_req_fragment , s_req_http_start , s_req_http_H , s_req_http_HT , s_req_http_HTT , s_req_http_HTTP , s_req_first_http_major , s_req_http_major , s_req_first_http_minor , s_req_http_minor , s_req_line_almost_done , s_header_field_start , s_header_field , s_header_value_start , s_header_value , s_header_almost_done , s_headers_almost_done /* Important: 's_headers_almost_done' must be the last 'header' state. All * states beyond this must be 'body' states. It is used for overflow * checking. See the PARSING_HEADER() macro. */ , s_chunk_size_start , s_chunk_size , s_chunk_size_almost_done , s_chunk_parameters , s_chunk_data , s_chunk_data_almost_done , s_chunk_data_done , s_body_identity , s_body_identity_eof }; #define PARSING_HEADER(state) (state <= s_headers_almost_done && 0 == (parser->flags & F_TRAILING)) enum header_states { h_general = 0 , h_C , h_CO , h_CON , h_matching_connection , h_matching_proxy_connection , h_matching_content_length , h_matching_transfer_encoding , h_matching_upgrade , h_connection , h_content_length , h_transfer_encoding , h_upgrade , h_matching_transfer_encoding_chunked , h_matching_connection_keep_alive , h_matching_connection_close , h_transfer_encoding_chunked , h_connection_keep_alive , h_connection_close }; enum flags { F_CHUNKED = 1 << 0 , F_CONNECTION_KEEP_ALIVE = 1 << 1 , F_CONNECTION_CLOSE = 1 << 2 , F_TRAILING = 1 << 3 , F_UPGRADE = 1 << 4 , F_SKIPBODY = 1 << 5 }; #define CR '\r' #define LF '\n' #define LOWER(c) (unsigned char)(c | 0x20) #define TOKEN(c) tokens[(unsigned char)c] #define start_state (parser->type == PHP_HTTP_REQUEST ? s_start_req : s_start_res) #if HTTP_PARSER_STRICT # define STRICT_CHECK(cond) if (cond) goto error # define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead) #else # define STRICT_CHECK(cond) # define NEW_MESSAGE() start_state #endif size_t php_http_parser_execute (php_http_parser *parser, const php_http_parser_settings *settings, const char *data, size_t len) { char c, ch; const char *p = data, *pe; size_t to_read; enum state state = (enum state) parser->state; enum header_states header_state = (enum header_states) parser->header_state; uint32_t index = parser->index; uint32_t nread = parser->nread; /* technically we could combine all of these (except for url_mark) into one variable, saving stack space, but it seems more clear to have them separated. */ const char *header_field_mark = 0; const char *header_value_mark = 0; const char *fragment_mark = 0; const char *query_string_mark = 0; const char *path_mark = 0; const char *url_mark = 0; if (len == 0) { if (state == s_body_identity_eof) { CALLBACK2(message_complete); } return 0; } if (state == s_header_field) header_field_mark = data; if (state == s_header_value) header_value_mark = data; if (state == s_req_fragment) fragment_mark = data; if (state == s_req_query_string) query_string_mark = data; if (state == s_req_path) path_mark = data; if (state == s_req_path || state == s_req_schema || state == s_req_schema_slash || state == s_req_schema_slash_slash || state == s_req_port || state == s_req_query_string_start || state == s_req_query_string || state == s_req_host || state == s_req_fragment_start || state == s_req_fragment) url_mark = data; for (p=data, pe=data+len; p != pe; p++) { ch = *p; if (PARSING_HEADER(state)) { ++nread; /* Buffer overflow attack */ if (nread > PHP_HTTP_MAX_HEADER_SIZE) goto error; } switch (state) { case s_dead: /* this state is used after a 'Connection: close' message * the parser will error out if it reads another message */ goto error; case s_start_req_or_res: { if (ch == CR || ch == LF) break; parser->flags = 0; parser->content_length = -1; CALLBACK2(message_begin); if (ch == 'H') state = s_res_or_resp_H; else { parser->type = PHP_HTTP_REQUEST; goto start_req_method_assign; } break; } case s_res_or_resp_H: if (ch == 'T') { parser->type = PHP_HTTP_RESPONSE; state = s_res_HT; } else { if (ch != 'E') goto error; parser->type = PHP_HTTP_REQUEST; parser->method = PHP_HTTP_HEAD; index = 2; state = s_req_method; } break; case s_start_res: { parser->flags = 0; parser->content_length = -1; CALLBACK2(message_begin); switch (ch) { case 'H': state = s_res_H; break; case CR: case LF: break; default: goto error; } break; } case s_res_H: STRICT_CHECK(ch != 'T'); state = s_res_HT; break; case s_res_HT: STRICT_CHECK(ch != 'T'); state = s_res_HTT; break; case s_res_HTT: STRICT_CHECK(ch != 'P'); state = s_res_HTTP; break; case s_res_HTTP: STRICT_CHECK(ch != '/'); state = s_res_first_http_major; break; case s_res_first_http_major: if (ch < '1' || ch > '9') goto error; parser->http_major = ch - '0'; state = s_res_http_major; break; /* major HTTP version or dot */ case s_res_http_major: { if (ch == '.') { state = s_res_first_http_minor; break; } if (ch < '0' || ch > '9') goto error; parser->http_major *= 10; parser->http_major += ch - '0'; if (parser->http_major > 999) goto error; break; } /* first digit of minor HTTP version */ case s_res_first_http_minor: if (ch < '0' || ch > '9') goto error; parser->http_minor = ch - '0'; state = s_res_http_minor; break; /* minor HTTP version or end of request line */ case s_res_http_minor: { if (ch == ' ') { state = s_res_first_status_code; break; } if (ch < '0' || ch > '9') goto error; parser->http_minor *= 10; parser->http_minor += ch - '0'; if (parser->http_minor > 999) goto error; break; } case s_res_first_status_code: { if (ch < '0' || ch > '9') { if (ch == ' ') { break; } goto error; } parser->status_code = ch - '0'; state = s_res_status_code; break; } case s_res_status_code: { if (ch < '0' || ch > '9') { switch (ch) { case ' ': state = s_res_status; break; case CR: state = s_res_line_almost_done; break; case LF: state = s_header_field_start; break; default: goto error; } break; } parser->status_code *= 10; parser->status_code += ch - '0'; if (parser->status_code > 999) goto error; break; } case s_res_status: /* the human readable status. e.g. "NOT FOUND" * we are not humans so just ignore this */ if (ch == CR) { state = s_res_line_almost_done; break; } if (ch == LF) { state = s_header_field_start; break; } break; case s_res_line_almost_done: STRICT_CHECK(ch != LF); state = s_header_field_start; break; case s_start_req: { if (ch == CR || ch == LF) break; parser->flags = 0; parser->content_length = -1; CALLBACK2(message_begin); if (ch < 'A' || 'Z' < ch) goto error; start_req_method_assign: parser->method = (enum php_http_method) 0; index = 1; switch (ch) { case 'C': parser->method = PHP_HTTP_CONNECT; /* or COPY, CHECKOUT */ break; case 'D': parser->method = PHP_HTTP_DELETE; break; case 'G': parser->method = PHP_HTTP_GET; break; case 'H': parser->method = PHP_HTTP_HEAD; break; case 'L': parser->method = PHP_HTTP_LOCK; break; case 'M': parser->method = PHP_HTTP_MKCOL; /* or MOVE, MKCALENDAR, MKACTIVITY, MERGE, M-SEARCH */ break; case 'N': parser->method = PHP_HTTP_NOTIFY; break; case 'O': parser->method = PHP_HTTP_OPTIONS; break; case 'P': parser->method = PHP_HTTP_POST; /* or PROPFIND or PROPPATCH or PUT */ break; case 'R': parser->method = PHP_HTTP_REPORT; break; case 'S': parser->method = PHP_HTTP_SUBSCRIBE; break; case 'T': parser->method = PHP_HTTP_TRACE; break; case 'U': parser->method = PHP_HTTP_UNLOCK; /* or UNSUBSCRIBE */ break; default: parser->method = PHP_HTTP_NOT_IMPLEMENTED; break; } state = s_req_method; break; } case s_req_method: { const char *matcher; if (ch == '\0') goto error; matcher = method_strings[parser->method]; if (ch == ' ') { if (parser->method != PHP_HTTP_NOT_IMPLEMENTED && matcher[index] != '\0') { parser->method = PHP_HTTP_NOT_IMPLEMENTED; } state = s_req_spaces_before_url; } else if (parser->method == PHP_HTTP_NOT_IMPLEMENTED || ch == matcher[index]) { ; /* nada */ } else if (parser->method == PHP_HTTP_CONNECT) { if (index == 1 && ch == 'H') { parser->method = PHP_HTTP_CHECKOUT; } else if (index == 2 && ch == 'P') { parser->method = PHP_HTTP_COPY; } else { parser->method = PHP_HTTP_NOT_IMPLEMENTED; } } else if (parser->method == PHP_HTTP_MKCOL) { if (index == 1 && ch == 'O') { parser->method = PHP_HTTP_MOVE; } else if (index == 3 && ch == 'A') { parser->method = PHP_HTTP_MKCALENDAR; } else if (index == 1 && ch == 'E') { parser->method = PHP_HTTP_MERGE; } else if (index == 1 && ch == '-') { parser->method = PHP_HTTP_MSEARCH; } else if (index == 2 && ch == 'A') { parser->method = PHP_HTTP_MKACTIVITY; } else { parser->method = PHP_HTTP_NOT_IMPLEMENTED; } } else if (index == 1 && parser->method == PHP_HTTP_POST && ch == 'R') { parser->method = PHP_HTTP_PROPFIND; /* or HTTP_PROPPATCH */ } else if (index == 1 && parser->method == PHP_HTTP_POST && ch == 'U') { parser->method = PHP_HTTP_PUT; } else if (index == 1 && parser->method == PHP_HTTP_POST && ch == 'A') { parser->method = PHP_HTTP_PATCH; } else if (index == 2 && parser->method == PHP_HTTP_UNLOCK && ch == 'S') { parser->method = PHP_HTTP_UNSUBSCRIBE; } else if (index == 4 && parser->method == PHP_HTTP_PROPFIND && ch == 'P') { parser->method = PHP_HTTP_PROPPATCH; } else { parser->method = PHP_HTTP_NOT_IMPLEMENTED; } ++index; break; } case s_req_spaces_before_url: { if (ch == ' ') break; if (ch == '/' || ch == '*') { MARK(url); MARK(path); state = s_req_path; break; } c = LOWER(ch); if (c >= 'a' && c <= 'z') { MARK(url); state = s_req_schema; break; } goto error; } case s_req_schema: { c = LOWER(ch); if (c >= 'a' && c <= 'z') break; if (ch == ':') { state = s_req_schema_slash; break; } else if (ch == '.') { state = s_req_host; break; } else if ('0' <= ch && ch <= '9') { state = s_req_host; break; } goto error; } case s_req_schema_slash: STRICT_CHECK(ch != '/'); state = s_req_schema_slash_slash; break; case s_req_schema_slash_slash: STRICT_CHECK(ch != '/'); state = s_req_host; break; case s_req_host: { c = LOWER(ch); if (c >= 'a' && c <= 'z') break; if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '-') break; switch (ch) { case ':': state = s_req_port; break; case '/': MARK(path); state = s_req_path; break; case ' ': /* The request line looks like: * "GET http://foo.bar.com HTTP/1.1" * That is, there is no path. */ CALLBACK(url); state = s_req_http_start; break; default: goto error; } break; } case s_req_port: { if (ch >= '0' && ch <= '9') break; switch (ch) { case '/': MARK(path); state = s_req_path; break; case ' ': /* The request line looks like: * "GET http://foo.bar.com:1234 HTTP/1.1" * That is, there is no path. */ CALLBACK(url); state = s_req_http_start; break; default: goto error; } break; } case s_req_path: { if (normal_url_char[(unsigned char)ch]) break; switch (ch) { case ' ': CALLBACK(url); CALLBACK(path); state = s_req_http_start; break; case CR: CALLBACK(url); CALLBACK(path); parser->http_major = 0; parser->http_minor = 9; state = s_req_line_almost_done; break; case LF: CALLBACK(url); CALLBACK(path); parser->http_major = 0; parser->http_minor = 9; state = s_header_field_start; break; case '?': CALLBACK(path); state = s_req_query_string_start; break; case '#': CALLBACK(path); state = s_req_fragment_start; break; default: goto error; } break; } case s_req_query_string_start: { if (normal_url_char[(unsigned char)ch]) { MARK(query_string); state = s_req_query_string; break; } switch (ch) { case '?': break; /* XXX ignore extra '?' ... is this right? */ case ' ': CALLBACK(url); state = s_req_http_start; break; case CR: CALLBACK(url); parser->http_major = 0; parser->http_minor = 9; state = s_req_line_almost_done; break; case LF: CALLBACK(url); parser->http_major = 0; parser->http_minor = 9; state = s_header_field_start; break; case '#': state = s_req_fragment_start; break; default: goto error; } break; } case s_req_query_string: { if (normal_url_char[(unsigned char)ch]) break; switch (ch) { case '?': /* allow extra '?' in query string */ break; case ' ': CALLBACK(url); CALLBACK(query_string); state = s_req_http_start; break; case CR: CALLBACK(url); CALLBACK(query_string); parser->http_major = 0; parser->http_minor = 9; state = s_req_line_almost_done; break; case LF: CALLBACK(url); CALLBACK(query_string); parser->http_major = 0; parser->http_minor = 9; state = s_header_field_start; break; case '#': CALLBACK(query_string); state = s_req_fragment_start; break; default: goto error; } break; } case s_req_fragment_start: { if (normal_url_char[(unsigned char)ch]) { MARK(fragment); state = s_req_fragment; break; } switch (ch) { case ' ': CALLBACK(url); state = s_req_http_start; break; case CR: CALLBACK(url); parser->http_major = 0; parser->http_minor = 9; state = s_req_line_almost_done; break; case LF: CALLBACK(url); parser->http_major = 0; parser->http_minor = 9; state = s_header_field_start; break; case '?': MARK(fragment); state = s_req_fragment; break; case '#': break; default: goto error; } break; } case s_req_fragment: { if (normal_url_char[(unsigned char)ch]) break; switch (ch) { case ' ': CALLBACK(url); CALLBACK(fragment); state = s_req_http_start; break; case CR: CALLBACK(url); CALLBACK(fragment); parser->http_major = 0; parser->http_minor = 9; state = s_req_line_almost_done; break; case LF: CALLBACK(url); CALLBACK(fragment); parser->http_major = 0; parser->http_minor = 9; state = s_header_field_start; break; case '?': case '#': break; default: goto error; } break; } case s_req_http_start: switch (ch) { case 'H': state = s_req_http_H; break; case ' ': break; default: goto error; } break; case s_req_http_H: STRICT_CHECK(ch != 'T'); state = s_req_http_HT; break; case s_req_http_HT: STRICT_CHECK(ch != 'T'); state = s_req_http_HTT; break; case s_req_http_HTT: STRICT_CHECK(ch != 'P'); state = s_req_http_HTTP; break; case s_req_http_HTTP: STRICT_CHECK(ch != '/'); state = s_req_first_http_major; break; /* first digit of major HTTP version */ case s_req_first_http_major: if (ch < '1' || ch > '9') goto error; parser->http_major = ch - '0'; state = s_req_http_major; break; /* major HTTP version or dot */ case s_req_http_major: { if (ch == '.') { state = s_req_first_http_minor; break; } if (ch < '0' || ch > '9') goto error; parser->http_major *= 10; parser->http_major += ch - '0'; if (parser->http_major > 999) goto error; break; } /* first digit of minor HTTP version */ case s_req_first_http_minor: if (ch < '0' || ch > '9') goto error; parser->http_minor = ch - '0'; state = s_req_http_minor; break; /* minor HTTP version or end of request line */ case s_req_http_minor: { if (ch == CR) { state = s_req_line_almost_done; break; } if (ch == LF) { state = s_header_field_start; break; } /* XXX allow spaces after digit? */ if (ch < '0' || ch > '9') goto error; parser->http_minor *= 10; parser->http_minor += ch - '0'; if (parser->http_minor > 999) goto error; break; } /* end of request line */ case s_req_line_almost_done: { if (ch != LF) goto error; state = s_header_field_start; break; } case s_header_field_start: { if (ch == CR) { state = s_headers_almost_done; break; } if (ch == LF) { /* they might be just sending \n instead of \r\n so this would be * the second \n to denote the end of headers*/ state = s_headers_almost_done; goto headers_almost_done; } c = TOKEN(ch); if (!c) goto error; MARK(header_field); index = 0; state = s_header_field; switch (c) { case 'c': header_state = h_C; break; case 'p': header_state = h_matching_proxy_connection; break; case 't': header_state = h_matching_transfer_encoding; break; case 'u': header_state = h_matching_upgrade; break; default: header_state = h_general; break; } break; } case s_header_field: { c = TOKEN(ch); if (c) { switch (header_state) { case h_general: break; case h_C: index++; header_state = (c == 'o' ? h_CO : h_general); break; case h_CO: index++; header_state = (c == 'n' ? h_CON : h_general); break; case h_CON: index++; switch (c) { case 'n': header_state = h_matching_connection; break; case 't': header_state = h_matching_content_length; break; default: header_state = h_general; break; } break; /* connection */ case h_matching_connection: index++; if (index > sizeof(CONNECTION)-1 || c != CONNECTION[index]) { header_state = h_general; } else if (index == sizeof(CONNECTION)-2) { header_state = h_connection; } break; /* proxy-connection */ case h_matching_proxy_connection: index++; if (index > sizeof(PROXY_CONNECTION)-1 || c != PROXY_CONNECTION[index]) { header_state = h_general; } else if (index == sizeof(PROXY_CONNECTION)-2) { header_state = h_connection; } break; /* content-length */ case h_matching_content_length: index++; if (index > sizeof(CONTENT_LENGTH)-1 || c != CONTENT_LENGTH[index]) { header_state = h_general; } else if (index == sizeof(CONTENT_LENGTH)-2) { header_state = h_content_length; } break; /* transfer-encoding */ case h_matching_transfer_encoding: index++; if (index > sizeof(TRANSFER_ENCODING)-1 || c != TRANSFER_ENCODING[index]) { header_state = h_general; } else if (index == sizeof(TRANSFER_ENCODING)-2) { header_state = h_transfer_encoding; } break; /* upgrade */ case h_matching_upgrade: index++; if (index > sizeof(UPGRADE)-1 || c != UPGRADE[index]) { header_state = h_general; } else if (index == sizeof(UPGRADE)-2) { header_state = h_upgrade; } break; case h_connection: case h_content_length: case h_transfer_encoding: case h_upgrade: if (ch != ' ') header_state = h_general; break; default: assert(0 && "Unknown header_state"); break; } break; } if (ch == ':') { CALLBACK(header_field); state = s_header_value_start; break; } if (ch == CR) { state = s_header_almost_done; CALLBACK(header_field); break; } if (ch == LF) { CALLBACK(header_field); state = s_header_field_start; break; } goto error; } case s_header_value_start: { if (ch == ' ') break; MARK(header_value); state = s_header_value; index = 0; c = LOWER(ch); if (ch == CR) { CALLBACK(header_value); header_state = h_general; state = s_header_almost_done; break; } if (ch == LF) { CALLBACK(header_value); state = s_header_field_start; break; } switch (header_state) { case h_upgrade: parser->flags |= F_UPGRADE; header_state = h_general; break; case h_transfer_encoding: /* looking for 'Transfer-Encoding: chunked' */ if ('c' == c) { header_state = h_matching_transfer_encoding_chunked; } else { header_state = h_general; } break; case h_content_length: if (ch < '0' || ch > '9') goto error; parser->content_length = ch - '0'; break; case h_connection: /* looking for 'Connection: keep-alive' */ if (c == 'k') { header_state = h_matching_connection_keep_alive; /* looking for 'Connection: close' */ } else if (c == 'c') { header_state = h_matching_connection_close; } else { header_state = h_general; } break; default: header_state = h_general; break; } break; } case s_header_value: { c = LOWER(ch); if (ch == CR) { CALLBACK(header_value); state = s_header_almost_done; break; } if (ch == LF) { CALLBACK(header_value); goto header_almost_done; } switch (header_state) { case h_general: break; case h_connection: case h_transfer_encoding: assert(0 && "Shouldn't get here."); break; case h_content_length: if (ch == ' ') break; if (ch < '0' || ch > '9') goto error; parser->content_length *= 10; parser->content_length += ch - '0'; break; /* Transfer-Encoding: chunked */ case h_matching_transfer_encoding_chunked: index++; if (index > sizeof(CHUNKED)-1 || c != CHUNKED[index]) { header_state = h_general; } else if (index == sizeof(CHUNKED)-2) { header_state = h_transfer_encoding_chunked; } break; /* looking for 'Connection: keep-alive' */ case h_matching_connection_keep_alive: index++; if (index > sizeof(KEEP_ALIVE)-1 || c != KEEP_ALIVE[index]) { header_state = h_general; } else if (index == sizeof(KEEP_ALIVE)-2) { header_state = h_connection_keep_alive; } break; /* looking for 'Connection: close' */ case h_matching_connection_close: index++; if (index > sizeof(CLOSE)-1 || c != CLOSE[index]) { header_state = h_general; } else if (index == sizeof(CLOSE)-2) { header_state = h_connection_close; } break; case h_transfer_encoding_chunked: case h_connection_keep_alive: case h_connection_close: if (ch != ' ') header_state = h_general; break; default: state = s_header_value; header_state = h_general; break; } break; } case s_header_almost_done: header_almost_done: { STRICT_CHECK(ch != LF); state = s_header_field_start; switch (header_state) { case h_connection_keep_alive: parser->flags |= F_CONNECTION_KEEP_ALIVE; break; case h_connection_close: parser->flags |= F_CONNECTION_CLOSE; break; case h_transfer_encoding_chunked: parser->flags |= F_CHUNKED; break; default: break; } break; } case s_headers_almost_done: headers_almost_done: { STRICT_CHECK(ch != LF); if (parser->flags & F_TRAILING) { /* End of a chunked request */ CALLBACK2(message_complete); state = NEW_MESSAGE(); break; } nread = 0; if (parser->flags & F_UPGRADE || parser->method == PHP_HTTP_CONNECT) { parser->upgrade = 1; } /* Here we call the headers_complete callback. This is somewhat * different than other callbacks because if the user returns 1, we * will interpret that as saying that this message has no body. This * is needed for the annoying case of receiving a response to a HEAD * request. */ if (settings->on_headers_complete) { switch (settings->on_headers_complete(parser)) { case 0: break; case 1: parser->flags |= F_SKIPBODY; break; default: return p - data; /* Error */ } } /* Exit, the rest of the connect is in a different protocol. */ if (parser->upgrade) { CALLBACK2(message_complete); return (p - data); } if (parser->flags & F_SKIPBODY) { CALLBACK2(message_complete); state = NEW_MESSAGE(); } else if (parser->flags & F_CHUNKED) { /* chunked encoding - ignore Content-Length header */ state = s_chunk_size_start; } else { if (parser->content_length == 0) { /* Content-Length header given but zero: Content-Length: 0\r\n */ CALLBACK2(message_complete); state = NEW_MESSAGE(); } else if (parser->content_length > 0) { /* Content-Length header given and non-zero */ state = s_body_identity; } else { if (parser->type == PHP_HTTP_REQUEST || php_http_should_keep_alive(parser)) { /* Assume content-length 0 - read the next */ CALLBACK2(message_complete); state = NEW_MESSAGE(); } else { /* Read body until EOF */ state = s_body_identity_eof; } } } break; } case s_body_identity: to_read = MIN(pe - p, (size_t)parser->content_length); if (to_read > 0) { if (settings->on_body) settings->on_body(parser, p, to_read); p += to_read - 1; parser->content_length -= to_read; if (parser->content_length == 0) { CALLBACK2(message_complete); state = NEW_MESSAGE(); } } break; /* read until EOF */ case s_body_identity_eof: to_read = pe - p; if (to_read > 0) { if (settings->on_body) settings->on_body(parser, p, to_read); p += to_read - 1; } break; case s_chunk_size_start: { assert(parser->flags & F_CHUNKED); c = unhex[(unsigned char)ch]; if (c == -1) goto error; parser->content_length = c; state = s_chunk_size; break; } case s_chunk_size: { assert(parser->flags & F_CHUNKED); if (ch == CR) { state = s_chunk_size_almost_done; break; } c = unhex[(unsigned char)ch]; if (c == -1) { if (ch == ';' || ch == ' ') { state = s_chunk_parameters; break; } goto error; } parser->content_length *= 16; parser->content_length += c; break; } case s_chunk_parameters: { assert(parser->flags & F_CHUNKED); /* just ignore this shit. TODO check for overflow */ if (ch == CR) { state = s_chunk_size_almost_done; break; } break; } case s_chunk_size_almost_done: { assert(parser->flags & F_CHUNKED); STRICT_CHECK(ch != LF); if (parser->content_length == 0) { parser->flags |= F_TRAILING; state = s_header_field_start; } else { state = s_chunk_data; } break; } case s_chunk_data: { assert(parser->flags & F_CHUNKED); to_read = MIN(pe - p, (size_t)(parser->content_length)); if (to_read > 0) { if (settings->on_body) settings->on_body(parser, p, to_read); p += to_read - 1; } if (to_read == parser->content_length) { state = s_chunk_data_almost_done; } parser->content_length -= to_read; break; } case s_chunk_data_almost_done: assert(parser->flags & F_CHUNKED); STRICT_CHECK(ch != CR); state = s_chunk_data_done; break; case s_chunk_data_done: assert(parser->flags & F_CHUNKED); STRICT_CHECK(ch != LF); state = s_chunk_size_start; break; default: assert(0 && "unhandled state"); goto error; } } CALLBACK_NOCLEAR(header_field); CALLBACK_NOCLEAR(header_value); CALLBACK_NOCLEAR(fragment); CALLBACK_NOCLEAR(query_string); CALLBACK_NOCLEAR(path); CALLBACK_NOCLEAR(url); parser->state = state; parser->header_state = header_state; parser->index = index; parser->nread = nread; return len; error: parser->state = s_dead; return (p - data); } int php_http_should_keep_alive (php_http_parser *parser) { if (parser->http_major > 0 && parser->http_minor > 0) { /* HTTP/1.1 */ if (parser->flags & F_CONNECTION_CLOSE) { return 0; } else { return 1; } } else { /* HTTP/1.0 or earlier */ if (parser->flags & F_CONNECTION_KEEP_ALIVE) { return 1; } else { return 0; } } } const char * php_http_method_str (enum php_http_method m) { return method_strings[m]; } void php_http_parser_init (php_http_parser *parser, enum php_http_parser_type t) { parser->type = t; parser->state = (t == PHP_HTTP_REQUEST ? s_start_req : (t == PHP_HTTP_RESPONSE ? s_start_res : s_start_req_or_res)); parser->nread = 0; parser->upgrade = 0; parser->flags = 0; parser->method = 0; } PK!`=,, cls/basic.sonuȯPK!FVsXX ,cls/cgroup.sonuȯPK!i*  iIqdisc/blackhole.sonuȯPK!6S,,eqdisc/fq_codel.sonuȯPK!PPqdisc/bfifo.sonuȯPK!K00zqdisc/pfifo.sonuȯPK!`qdisc/ingress.sonuȯPK!-- @qdisc/hfsc.sonuȯPK!m,, =qdisc/plug.sonuȯPK!89.. *Cqdisc/htb.sonuȯPK!2 ~q__init__.pynu[PK!qq)q__pycache__/__init__.cpython-36.opt-1.pycnu[PK!qq#r__pycache__/__init__.cpython-36.pycnu[PK!ֹ +Hs__pycache__/chardetect.cpython-36.opt-1.pycnu[PK!ֹ %\__pycache__/chardetect.cpython-36.pycnu[PK!_ݭ jchardetect.pynu[PK!̬iiYcli.hnu[PK!1]>>php_cli_process_title.hnu[PK!uRs |php_cli.cnu[PK!vʢ%%u@php_cli_server.cnu[PK!4g/ / Zfphp_cli_process_title.cnu[PK!V pps_title.hnu[PK!saFYEEwphp_cli_server.hnu[PK!lW00 'ps_title.cnu[PK!8php_http_parser.hnu[PK! PQphp_http_parser.cnu[PKT