From 3c61493169df4e7b155917ddf440ded71cea1678 Mon Sep 17 00:00:00 2001 From: Mihai Pitu Date: Mon, 26 Aug 2013 22:41:16 +0300 Subject: [PATCH] Servlet request improvements --- .../dist/ModSecurityTestApp.war | Bin 115887 -> 105607 bytes .../commons/io/output/ProxyOutputStream.java | 170 +++++ .../commons/io/output/TeeOutputStream.java | 99 +++ .../org/modsecurity/ModSecurityFilter.java | 4 +- .../modsecurity/MsHttpServletResponse.java | 617 +----------------- 5 files changed, 278 insertions(+), 612 deletions(-) create mode 100644 java/ModSecurityTestApp/src/java/org/apache/commons/io/output/ProxyOutputStream.java create mode 100644 java/ModSecurityTestApp/src/java/org/apache/commons/io/output/TeeOutputStream.java diff --git a/java/ModSecurityTestApp/dist/ModSecurityTestApp.war b/java/ModSecurityTestApp/dist/ModSecurityTestApp.war index c4a32c98dee662d050bba6f70c5308f8f74e2c39..8525d7c34a30fc7de6cd4b7eb32b3fab0616ff82 100644 GIT binary patch delta 7301 zcmbVRd32Q5b-!=6PnsF6Xy1h-B+Y;%K*%6K62gFmB*11fOAJ~@mO#=7Y1q7Eti}b~ zG{pFe{Yt%njcOWa0YxB1U@*o6949TI?rDx|$E2s}Iq|9O(m$FUyK&v$ecz|ijBG;N z(fQu;z5DL{z5DLF_r6c3p41MGJ7U%}T5V3ED58UBGLFQQSP!6@|D2V3Hwsks2QOE8 zktkR7Mp32er$vpbZ-|Bjj4!3I-wY{YMXFxg8JE-LFOQHBK{qQzmkK)n?m*w}KqR@I zZCR+qY_UAU^~f#DZ&Ov{R~aukRAXQMb4DYfG&J-2hE z{-G~z2R_}l&tCh{(c7QC@yU6 z{r-LX_2C1V%a%APhGsj-O>?4A%ym*F&EsyBMt5;NpWiItqMD0^TrARPu|_q59E-Yo zy8<NULZg@`D)fZxq~a-pRx5?C4fOk3dKL<@_px+ADf(jtY5MhpQFdENL+OTR z8ghcxuJ(O`M1!E1wSktloy{$M>sng7eZV5fxolsXuP@N$?;QY>k}dV68w6RqeZ44K z19)fIQZGouKm*vJI}pH#ueTl49o@SJI?*fP0ef4wf50cm)#~f;_xm>XcLmTBy`qSm zEgb=0zxgJiv!%Da+t;udNs~UjW7@KX%*eUczq`N9x4f$x^HbLFvclI|wxeZF zi<@F8&P^Ulb5kv)XjJE>RPM~AH2KTvA|=aBv#5+;=5bNzreZ2_Qz?}QD$|F>v?YH+ zoq{r0NI6J=0?@QxDER=xK zsor|Y4t$B|rx;W;jgrsyCho(*aCShB`^c%#)&6vIg`@R)BxDCVKfHEI| zrnW1@l}fn|rC=M23Bk-WVe-2owH|KGK+8Iz^o>xu7NK-lv59*JY75IxV1pPXCoG}K z17({?HJI82Qr=;rF6?7B-tK@3cVg{53LqPxOM%QF!R$ zpxZKg{x-~lU*!h3V{)s4T!v=xzM(+!@i(xY3}a^rVY4VB5fS@cu4Yz5M&WgbmmIqe zW4dnBgY~5`lb&py&&Tm+b(IsIs5Ba<-oq`g6Kg~fOS8CzB9_Xyg(8;9xrHK@D!5gl z(QJ+8;EcESxAeBbzpIcU4>gKtQ7(_HMsDz%`%>k(MloM+DoqYXh!6Lah)Ra5wC^>7 z!9;iwt!7vW3qBgn4G%L`e@BNAvy51zg4x%GoJK^6h>(#4Eri1`14aT>x^YV5-K=Ge z=5d|NMS+_NsmP6!SEToSnv!+f^_Y?4D-l1ts8DZvZ#Kt*7-*5r&Bl_oc|(c{g^ z9wWPw!S2#A4EZ3MTuB{{`Vx4PdL@P(H%F%lF^Q%aewPOk3?dN@G2e84lcEbu(UXhI z93zbdBM3%?EiR~()ri$KVRg;7U0ps_#m>zTA$apm5j7ZL<+?p%@c)niuNo#m@n4U5 z8=(G;ioe^SSIffs!`Z@|zJ{&KVC$aBb{p7k2iumfu#Mze40skQiS!4r{>!7M?~WU} z=d~x}RDPR#UtH73d*hc~MYV{ZRftaWsRIeXE(HJm2>#zf&h!M;(IM2&QoVlZr&ptw zW4l(ss2cR|Tvd04kvFfdG?MJtw{O~28hq<-6OD%b-4Bdp{kQMO8#(hIKK!gqW$l@c zMe{b{5b(2*v-bINMS_S8(vR7>?2Ly0?dGD#2@B}umfs1h?sZWg?Q&5+4QRB6>wt@P z(;hDNYP64s_iOYJ&wAL2SnM|u7?`CX8^L5&`BVlM_Y`ZJdHEq?j9Mt|<4=9zSW z=??PT0~$TSohLa>e~ODkPI%qF;4wAl+dO)h2kSm%bu9SsqIjSq{;~ z&P|S|iXSJ_cQtxeqvxGEirNYP)pFH!z|n)r!@p3sN?HQ$PS zT>s>ynG0~EaMNs>1BO* zb+YvpI-&dBDd}z+qWj(S*IW$I3EWkf<0jfHAI%ff?QVFA8hI>F6hv*It=xN6Ue6QR zQQx2kxOY;vtP=S%{)WECz1Q6Iefj~nI^6U_ZvBW+ouboR49nnhQ6i5|7cXj#Hh)h~ zS3p)}i!zsOpz9$xaaRhJXReQcCp!`^pLW}E_+T`wSINm0r|xIS zZuIPMogSMh)rw@D-~>4rPDPmpu$gf4S?J~9FBdLlIzmH%LIU5z^1TKW9AyGfYjjKu zPPXCQmSBE8Ej5-Za-kdtM%H@9NfXrM9j7Sh@~0GSX|~p&=M+?JOSg@aOVCj&<(6B} zC5oxG&&-}2Y9PO%nR`?ysEPk#9>lKoXPPeaBu_}n$nlufOo42mIKx-?{q z(^NR~!nS5YYqOyAGQ_HK(9gz<3dF@ZYDM>edM?&_H!Z_bvN5t8v^KcJ`M4J}!2jM0 zo-5(gI4rKErXV!Wx05EYTBRV=(Q2@?C_;A5#@Kymv3_#M_9gh*HCn6DI*p=*M(c?_ zqw;zUUL8~$>3)>Fhn?mg78+Z}jvHGSf7;l)IIcXwQA!x4#M9z5CK$VCq}o*wd>3@F z0N$t?d$wp|$3RyYwqY>WIL;1m;7qZ5AeIfXkgZ}`m~2G5Bttesv7?(j%=>SM%}`rg z2emE1g|r^VdN)jG8BAq`5^aR}3DFFKPlKTqfJll(8z&s1dF{PWI@_i}oW&qjxe*m%#G1<__Ykan_ zfMue|P(q<+lyZWXD6{!IJ#1 z^G;$k?&vI~1&6g2`BEDWO*;;T4+pnXVdX3^0q9$BAlNjPnd-Apa4Dv=ncEmmmOqk5 zqxLkVPToQO7~w8!J%wMrj7aWcBO9QH#}amk4y*jAS0s$R(j%4&`Mh70$^ySg zl(oA=PHtQE*1i7zom+eS?b`-?ZM$(H**|A1f92WQ-PJlE#dn}&@_jws zb7YHObjXMLM0w$zX7si7`wa3~yF|tRMnFqn|17!PFCLWd?h=a&Zv&d4fU>L2-@C^o zf4E;%dhdkCn6^96)osoy9S{r3?lh~}-@evV+{#rAyq-Do!hkrgwq$!id{ClVwJ!>1 z3b$m_h?vh`q~*a8QLEnkY(&gejW0)p`Y-k+M97cupiJaSf)D@@b= z_^!VVgZvoZ?F`DH!C%XpXGK9C1OK-Z?Yj=(;>J%nqM^ZltKL#sq2J1m(`&2_nf9h| zs~MfwuD!DWF`A#1A=yMjgPSr#Gyc0o(~nm=BRAgE{&sPLZc6|KJcgUwN zm@I#Ae%}Q@5(<9mBUtJsYQ~z9BpE+$Qb(m`$EI0{_~Fnx@f#X!oek>wa@J2oqJkRn zb$)^j_0ZryRDyDuf~P3YT{(To3x536L{KiQ0%fKC%PNO-j*CRKnA~wJ=JEm_kbUE@ zAU37%^UDtxDe5)NMe@*j6UFAs;+u!y)A-pK!Ta~Mih6ssOTXEaB%hn$fBqa;{l4BD zbjlR4QZl^fF%WE319h#*@&)Kb4IJlzciQER*F~-VYhSv4s@*X;>UkZbFLWBCr@GSR zvDZy(b3dwElb%7u&(a8Nz1>WHud<{U4=s*|(`LtwG-mQQH26EY1L@#oy~DVVjIH~S6D`^U>_^s$v9R=@NgN%FuO zrsALH(Sj@Cqtot9hBKJ`D5WCsK`{{VHObeE3a~sn&B84U7Bz$GUo=X$@jjP47qFyA(inq+6+P5&2mCr*3lUwjIzYWeb z-rn3O9P)Q>nf4Y6hH!&%5pv(IlNnb;w!&V0MPz36H45tVb@!EZ270=uI6%1z6a}ks g&FaEcc3;_!fxb13b~q$LY%il!{L^CdQ=A`?zgwmH%(PbM_I$|LwguaL)Js zX1~&8>J$k(!yL_q5?jmv$EqO9^cWjPrF_Kxg+obgR1eN?PPZIw`E>!7i zE>Y>tT&~jBxmu+MwKA3dPP;|YBR<=Ij8d8P>Gwpbj6VK$GqW$}C8w(Cnc8DhnO_yR zvdSze*>2XnIy=qGd^{)F%-H6Cp~Ye5ik;a9mgSBm${p*UcWHbIBYy4g7Q;(E;+RZs0Xn)nrT+w;iXf@!k-`uUM%=I@-jY*J^r+@Jc z?Wqw&^33vIdjAC9qNYCY60dh-Ws}#lsHeB9$vdT`v#GD|#V?sO_}yO8UHPLT`#X2blTyhozZk7-6Q~aIq7C6?RL^F zF7nf@GS6*Nf4fcr>3^wCcj&Z-DQdl18Pk~BOPV${6?#3Jy@d@OT^l=np76rUm~^va zA5+E!XLmiTXIqzdO;5LnDaq{E@9pR;T-nj(ky=cZ)Y9ME>*@B&{EI!^o?fJ_OkBeh z6K?V^FHbdMOsEx2E$trvr@u)V&lKIz(bnDM?e7JE*%1JiH1)ODHEo>ZU-9Sc_;P@8 zZEWi8^O!>udKQ&r*Y@Ml6 zlZ72Jx=g2UD+#KMA9_D6`Qmd7R??=GmqF+z z1}-h)^gww$XDpvXb9K7Qpu6cFgQiolK?O7gqNTQ&0xqjIXb$a_rhNv@ppsyFh<^sn zq*(^tOZNrhGdVf%{zQ)Qr?tlUz&C^1sNJA4>2RJvX`*I>3aQAT@6djx)bMT|P9B54 zE8Xv>0|tGM<{I<>J;*dV++A({h#id$UsY9=pViu$RaaM+H83#X8^~I+q_nH6w68Dg z^2;GS4;gfj9+u@i!jy^L)_?*GC>R*t8>pdGrmD+o4bOvV2SD(}bt`px)SyH3m_bu% znn8!@2qY#(?H}}kG>^^=F&ZMNL#xP?*fxC~ zmm|TP)goz~o~B;^A68c6nYgGiN)MoqwyFX9D?((=hBE)w4^#XbpNcAu=v^kbC5Gt~ z)VJ6I7HCr^=Ll*(H89u(=*9Gz=$U;+MJ_SaEBAaVf*r|+iPLF}NHlU|MCMcqZXs3T zu2M*}s)q~{G&S-Xm7+gHmXgC2IvTKD(52k}%83-;Jd~qQA}x>RBX3Ba9JGKIB8{dB zs+7LSKZaU6(yC*m&C5JYHct}SZ@q_#4^vcQ-N}fW)XXDfL+x?W8#9Na^r@U>i-PLZSFP!RRfsQgn@ke?PcNC~A5bZ#uwPpUC#j$@RVrejet zrB0-2&JzbHKhz^ihD56&Y4*sz(b6~iM4ICe=xO*UmC}Lue5#}6KyEp$QfV^{(3L1( zNn2HFlBR|dL7HCDv_3MleoECYqjYT(WoVmeoHjrcw5zBHk9hUdq$<(RA%zs?@$iOSS#fpnVt2zMnd@?@^cb09~p* zq!?Wez9ayO@YzP$Am>`}&j$Fk35*ua0rCKqbs(8WUNE`=X#-8LI?DEHqUbYNf=$u* z;vi3j)0yN5RiZw~8?f_p(#}8$g`2?$lh?vHyUBlamfOb)$*JBo$Cmkr;A9D}-XiS3b zxBE%Qk}}+RKtFT!V`#T4q(_5oq@98)!~(S+QoQyejnrO(2)wND%rfVq4(NFKOQ%a{ z1C}nidgL^0(4b0BN3T+p1WP+$loo;X>4O+)?peqMB|T8 zRMb-_+afC)8ttk$!R*t}=upLMt9XP`5+@#`Nk?chOu=EAJSbZy#WpRJwIl1ZsvTA} z426whERIud;}E%zP;4kSQs}~pE>qyLkv0|dD4`0i45Gh~R%(^BPOG9zv_;gf)zW~r zoUYPV(sdei5A|TIMjMAY;uZIQaMh8v`*+4GS9W4ggX_pYkDiQ~xBz@Ff%=$@Em=mF z!ZZzlJlkMuz6GPW1LHqb!r=pjDSk)9yOZ|_XRDS!B4^GyYE_TuL?>UsC`_yf3 zzP}H4Q=ZlS&rZ&|r@9NA0Y!T1~AxPT}7x4xN$x@cF_oR01eZ#h%F|Jm2a zp-T5JJLd3T_f#y7FNywro9zCgH)o_p$xu%(lTqCbcd$adY!A*|Q>=-ioN97UZ&{!) zp7T@TAsbNonFf~YG_aAJI*nz@_rL!1*a%#*-pb&K!8(8QTWe#B(RT(mVhN3;nf{mF zs!a z^Asl+MspEQb&Bn3qbSR$A(0mUb@sWanJ2ku zJa3WQRwrL0g>6pWF6p&SMj&N8U*}|mQJS%GzMgLomhyLCpqFL?fA)7I(&x@!FGSMwPU0oesGiI{}<-Y#Djh^mSiQz=IdiuP*Jp+=DH3!sr z`udvM04%1Z2Y!FIcjdrFloDFnn|hmC5D2L1Zs}?5=x)OZv&Telt*5)q+YXqW5)nb~ zb2veP88LiO&c7R$3OpRcugr78zg)LwS$);l#-?;@0m?yxN2Nju-AI8=NFC{xI`Y32 zm1)!Yj=%#3ci6O!Z2#^LMg^*4`EWAt(fLlDzm0umI)4j$S_dSS6v&O^lz0_n3X>x+ zH;!M55*SH+{*8Y~_WyNps!taR!7qcGig$(CJ4hLOPPI6Eap4w|tg)zA*uQ?gr?)}5 znU=R13m-7D+VnnS)_3;zwVUC57^Q@czKSrTF8lTG6GcwY5UY7(xd*{ss9-iDpqbv|3*?Q(CS6vD#6wkj5xe z8ky3iV}{icdmXZadBhtJ?ynRHDAg#B-QL|Kj(0HFCUM5E4|_&LJ^)a#GiS7XZe_Ga z7^tr9_6~!UWHLlVxT&MN&l>gVv{ADl0m7C@?1Xs1(FXDnlSvZ-jo4~_KA7$=DsyF^ zs=KwSx3>o-(gl*5>&8~h%*nk#C^6Eagh_F0bkTXqal-d7TtBd}*Ffb5K26}6fwlzB zx8>*L240J0cRZ{wI)@OEzDdt00Xe*btz|Uhj zTiI#f0s5XnH^afDk>S9^g5KVyf!dBfuR#ash(WvQ76S(uyl$uK3<}U42JMm8o$|Uz zM*okZQ{ixvPerHrZiDZU5ZeLX`+tc}N#N{$5Tm+bS;4GXGiDb|mH6H+D`>_048E7| zGx$5a-{9}kpA6b7fjxH7`v%=byA1jjy<^ZX<@KJ_{gFO3=mYwV!T0k42)TdjqLFbX z9}W65{Uzc&v(nNx2K`F_x*9y*0;?x~kJAnM0`oJorhFm;?Mdh*_O;H{)E<)G=m?dR}4NRuSYq>pjYWNgI=ds0&mCjcpK;z zsEOgscmwD0p9m=*Gx#vQ7T7nH(_IGrlzt|aM*@WtIm^e7^HC`d8a%|ukfV{wT|8?die>Ma3zp(95zmHhJ4o zJWU@lIm@!t^?*m`7YzO(zi6<7qYQR}xcnnNU~nuj;+ObkT$!l7x60ak2EW3uA}SdU zDOPuOdfJ*g7xcFEcfsz3BGf{WccALSd!n|ZdxNJ{Z3=#k)0slY*1)qP`0iO_!;{wc zcQt!@%>ZU-#$Y5fLba;s;r}^MSnRH*Nl(?K9 z0{0|vk>B@OW?*t6FO3x~Xj&p11p*rrc}-yLG|uO*_Z)UNWR7=ShKn5Nc0K2Uh1E&{ zn-Nvh=GH^+`+vWptW)ezrDD6;upAt>bfw${VS;}nn2bf4cQc|;|NmD#?x~$W;LD7rZ_;(} zD!-+?%Ii_SA)>qk<((1b8xe-MiFSqhkAx=*Ev?2v8>8OmSA|>A0L_ewa2ZNkwLwp- z6slUK(AFx&9#kn*o=Tx2RSHF}(!I1#rBF{Q#cc&ryC_$rxqt<$;Y0EO&byfi1<28M zpF3}e*lj;bn)^7};E5ya2xp_*2%6|_+fj1LD_UMIsf%$VPGCr!z-Ua2Jxp;!6tCh0 zD2@mg5hp+~!73i5M7J+-581Gvg`yS?y^K8|3Y0(5bhU9#&79;b9*TEM0Z+~l<*I={ zMNjuBAGn8fkn)fq;4LL^pg<(RCA79FT6ZI?BoucdgcnUUp!`yZb}cAePdSJZ7a?po z6OrM0hy*W2NNgFcrt=Zky9klkE(FQ0M0yPZe7h0iyBook2M`!Lit=$E;#4Qm<%fvV zyha=87t{yK?NvOH(B;JlOh2x6R6F+8QRFmCkV=Cz1k|^57$6^o0g#aX-~61LDLuqs9ecSXL^Q;OC9+c(`;#u1|)WOn&SzYfl%spiB$eX z1)U{2IZ_4uO8^8??8Ds-B3iT=0hR$YT>&w^60yds5V5-&r1XKFU+M$uE)@(zf75j{;OFkv#HfkF=(dJ+(N7CEc~6n+$`4u(BP&npz>BgT3PwDg@u zgWUX>jV~Z4WXmM`8O-a@>4!SKs8bPQ^gkl{2Nf>V=_SyJUZz*@2Dwy#laXdCfr6|n zd76316sUMfAYZcvY4#x;dx8>`0>p8{-~-@qA&zzfLbf}=>l@Yj%&VyE2tFci8J`G% zI4xOVHvxOZ#sC(g8XW-}(qC%A7F6<4EDH;=imO5l9Zo*2qY&$GtX-T!1+V8;3x=f zsv)&-`yefpUV_j3Fg_|A4pX4R5X6!1eysR=VD$sIo_PrR@*skqk3c&fia>Nx1S6uz zo{}7Im%W2cqCu}d2{dsm{d%;aRwB`Mn`l=E+LgW`sya%d*hGCQ*#X|NX1Cy7c{bjI zzLWjh;)@jZw+1Eq_;p{k&tN8{zYz`-cD7-7wIU$ z13w4v;6{|;Vste7UPvQsIc$t6nR&3Y;eB9kzn{u2;LmVD^$SV@^fbTA#6Us3?R`k$9^S2#rG?PM?L4&q7FSVTcZ5dVx^7 z8+1qyBjjrUjl$?eVDk~M`5mzNJ+S!%*!%&K_Gtt*1tDw-#OsW}CKLHzgFNOwE=MX{ ziE@K1D}@8*@x`TTeSd-6{WW6RsL-@gAb>1VcA79-Ztmfq;VsNAL@MgRfnBodU}#o# zp$|PB-USY8LKeRcFlF#sq%t_o?K4TFW0vzx3OPleI?tArFF}nn1lN~FvPP+FkARS7 zL9kS$5fegLR0AAIyannW3+gj!C_+iFGq z#TXA8W}P?{S8)q(9XTV|s!sM?0Jcs6af`s#sbK3guyqF5T7uKqOx#P%!XjtWd@iNM zTt>A#mm0Vn*RS)bi5E~iS4J?UBZ4W4<1^LikL=?A$i_m92=A}eqGQdKL!(+Qh$#h1 zi}Dg6T1~OMl#;lX(zrf?@{vkZ9I_DQl@k4oe1EdQo_*jDtl>T|P>!gXCGApSWHU6x&Ww zLVjX9N>Z>YJ5=Q*W@U#}xnU2!_DSrN5+=5k{v=3n*H^S`IZl1VzBM4;1t8v95bq+& z;3k^L%@E-hn!&9!hdoroZM1^h@jc@uxL4mmUEGBmq8_z;v78g(W&D-?OYN)eAwl0x zf1|%!|6epmr+*~HevU&j)93V0lREew7z$X9qS=w2s~qo@Q!37AURIj@7MI1pUZt2_yoP)O|r;0!jHe;S4IE((&h$T_$3; z#o|(q#ieL`5&&1tWK(j8m{NI`xiW?Da?tS#pmP;I`MMfvU`vQT1P?8UPEH7&90_HT z<_l_qxK!X{gI+h$k&i`0Xk6~RF)-P~)~+lUZ-+y5Z3GZk2#6~L#04PYv9W~qteH=s zEc8}Z;7%Wo?ofIg58C8_3w@DQJ|^Qnqg7)8ut5m{3UXBSc?u*QBLy^>*7C<+%P>YSiiN z9I~gJSH@A3_d)jVgY12WCh>l_!{5by@%^}kK0r%Rw}Ky}76ioQSR!uybjyWz_(1$p z%V*8PsaV(`JE%1zO|2nmYBfbxNo*`R;L;~ByTOnIa3uQcMK^-(rsy7m=ssqOuFsV6 z5VUj2t}ArZm2Y{5pRjSJQ^#%b{czOP!`9i{mN-iBAf)mb)EhoK;^PXeX_dt`DF07R z*b?m0oo!Ej~dZZmm(Dc48z0=3Bj?z!UXPH|Jj(l2uywi zOkM^iuK<%*fywI%6Q4;6LB$Nb1u?M>D1aY4|KfbYv7m{G$#$ed6Nx&QhkVe)!Xzf>&Ks2E<2QlNTfpaS?7?>;s1vEfgT%=`i#W-{kc;DZi(w0aoap>i zAQvSM^x9K2evmdjLzm&d*mTni!1)s$`PT}t>9(d?v|t=!zk1q7Sn;gWKL2OL;LvFw zr{8l8jyY?vk3T-==tP{HO+rf?LiDxU4Gp}x4xTYSZyb17LJf(>=!%8oP`dR_GLF-g zjWAAEofs#KG|xvSx&KH}{3*HkGpLBa&?x>ZgzUd4hs8_rVPdu6-608ZTN^$~nM{$z zQ3#Cv0LIg%q|y*SI8NuJe^HtlhY+K6C8Ps)Y!(9^#wbC$WVl%o<2u}|_$<2;EjA|S zkg_drMue%%o%AKeGd^a7@XSK~NYF=0h99H^}1#K2uuT*g^}-HUjVCj_I>X3OYNw`!^S~b@xlv=C00ZQ~G)WE0%C`V9w%yyR#?o_r+Y0 z6q*@RHErxIm}RZZVoJ{;n^9HUGTY9gY~Pmn)+&M))K9t zAn?-~zF*Pis-^tP9F@D!%dQm31v+lvS@PS?!2TO}o~rrq2A-}mV|K9m}o%K`o-ChaCvIL_TbsEoK&>`8g#Hypvg{ab%h6nJ(Q z*C-%yHv>pju~f|Rzv|Zgg)^c88*jGO<&)NfGo-aR@Y>Css>XaQwbN&-TL1i*D1Usp z!=F()F0j_mhJt-`@)f;zLmkVrHV7E${;kXAL=GDp_++<5m^CN)>K*7V&+1`A+U7+L zarm4=6ouHa*jEZaghiKU@h~W#HU+!K``>MjQfpDG z?et@{Wv#-7BL6dO@&3;BY5sDL*+YGxeEW`_Zv-y&bBY$*9`06tNt%B|N5n*1ZpB3J zZ3y)U{PI>#R3JW+md0>2G;DcS~lE%8k`3Adf+K>2@2n41!q1my>adB59}G+la6#bA?G~ZsD{Op*B%dPT zRxkXwf9vTdq-&L0$v^=3K7I;F%nZC7;E@X5k2-&~t_S8`o>k$IkOqDMJ<9@RcW{pC zIqZ|{VLd;189f^V7w@qo^W!@J=Z*#isu~k;viF`H`Db~u0L-qnv0IrAr_HX?hKNekGwXmSNeo^6N zp5`eq0cXq0wH3WTK9++UF+9 + * See the protected methods for ways in which a subclass can easily decorate + * a stream with custom pre-, post- or error processing functionality. + * + * @author Stephen Colebourne + * @version $Id: ProxyOutputStream.java 1003340 2010-10-01 00:31:53Z sebb $ + */ +public class ProxyOutputStream extends FilterOutputStream { + + /** + * Constructs a new ProxyOutputStream. + * + * @param proxy the OutputStream to delegate to + */ + public ProxyOutputStream(OutputStream proxy) { + super(proxy); + // the proxy is stored in a protected superclass variable named 'out' + } + + /** + * Invokes the delegate's write(int) method. + * @param idx the byte to write + * @throws IOException if an I/O error occurs + */ + @Override + public void write(int idx) throws IOException { + try { + beforeWrite(1); + out.write(idx); + afterWrite(1); + } catch (IOException e) { + handleIOException(e); + } + } + + /** + * Invokes the delegate's write(byte[]) method. + * @param bts the bytes to write + * @throws IOException if an I/O error occurs + */ + @Override + public void write(byte[] bts) throws IOException { + try { + int len = bts != null ? bts.length : 0; + beforeWrite(len); + out.write(bts); + afterWrite(len); + } catch (IOException e) { + handleIOException(e); + } + } + + /** + * Invokes the delegate's write(byte[]) method. + * @param bts the bytes to write + * @param st The start offset + * @param end The number of bytes to write + * @throws IOException if an I/O error occurs + */ + @Override + public void write(byte[] bts, int st, int end) throws IOException { + try { + beforeWrite(end); + out.write(bts, st, end); + afterWrite(end); + } catch (IOException e) { + handleIOException(e); + } + } + + /** + * Invokes the delegate's flush() method. + * @throws IOException if an I/O error occurs + */ + @Override + public void flush() throws IOException { + try { + out.flush(); + } catch (IOException e) { + handleIOException(e); + } + } + + /** + * Invokes the delegate's close() method. + * @throws IOException if an I/O error occurs + */ + @Override + public void close() throws IOException { + try { + out.close(); + } catch (IOException e) { + handleIOException(e); + } + } + + /** + * Invoked by the write methods before the call is proxied. The number + * of bytes to be written (1 for the {@link #write(int)} method, buffer + * length for {@link #write(byte[])}, etc.) is given as an argument. + *

+ * Subclasses can override this method to add common pre-processing + * functionality without having to override all the write methods. + * The default implementation does nothing. + * + * @since Commons IO 2.0 + * @param n number of bytes to be written + * @throws IOException if the pre-processing fails + */ + protected void beforeWrite(int n) throws IOException { + } + + /** + * Invoked by the write methods after the proxied call has returned + * successfully. The number of bytes written (1 for the + * {@link #write(int)} method, buffer length for {@link #write(byte[])}, + * etc.) is given as an argument. + *

+ * Subclasses can override this method to add common post-processing + * functionality without having to override all the write methods. + * The default implementation does nothing. + * + * @since Commons IO 2.0 + * @param n number of bytes written + * @throws IOException if the post-processing fails + */ + protected void afterWrite(int n) throws IOException { + } + + /** + * Handle any IOExceptions thrown. + *

+ * This method provides a point to implement custom exception + * handling. The default behaviour is to re-throw the exception. + * @param e The IOException thrown + * @throws IOException if an I/O error occurs + * @since Commons IO 2.0 + */ + protected void handleIOException(IOException e) throws IOException { + throw e; + } + +} diff --git a/java/ModSecurityTestApp/src/java/org/apache/commons/io/output/TeeOutputStream.java b/java/ModSecurityTestApp/src/java/org/apache/commons/io/output/TeeOutputStream.java new file mode 100644 index 00000000..f4ffbcd9 --- /dev/null +++ b/java/ModSecurityTestApp/src/java/org/apache/commons/io/output/TeeOutputStream.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.io.output; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Classic splitter of OutputStream. Named after the unix 'tee' + * command. It allows a stream to be branched off so there + * are now two streams. + * + * @version $Id: TeeOutputStream.java 659817 2008-05-24 13:23:10Z niallp $ + */ +public class TeeOutputStream extends ProxyOutputStream { + + /** the second OutputStream to write to */ + protected OutputStream branch; + + /** + * Constructs a TeeOutputStream. + * @param out the main OutputStream + * @param branch the second OutputStream + */ + public TeeOutputStream( OutputStream out, OutputStream branch ) { + super(out); + this.branch = branch; + } + + /** + * Write the bytes to both streams. + * @param b the bytes to write + * @throws IOException if an I/O error occurs + */ + @Override + public synchronized void write(byte[] b) throws IOException { + super.write(b); + this.branch.write(b); + } + + /** + * Write the specified bytes to both streams. + * @param b the bytes to write + * @param off The start offset + * @param len The number of bytes to write + * @throws IOException if an I/O error occurs + */ + @Override + public synchronized void write(byte[] b, int off, int len) throws IOException { + super.write(b, off, len); + this.branch.write(b, off, len); + } + + /** + * Write a byte to both streams. + * @param b the byte to write + * @throws IOException if an I/O error occurs + */ + @Override + public synchronized void write(int b) throws IOException { + super.write(b); + this.branch.write(b); + } + + /** + * Flushes both streams. + * @throws IOException if an I/O error occurs + */ + @Override + public void flush() throws IOException { + super.flush(); + this.branch.flush(); + } + + /** + * Closes both streams. + * @throws IOException if an I/O error occurs + */ + @Override + public void close() throws IOException { + super.close(); + this.branch.close(); + } + +} diff --git a/java/ModSecurityTestApp/src/java/org/modsecurity/ModSecurityFilter.java b/java/ModSecurityTestApp/src/java/org/modsecurity/ModSecurityFilter.java index 9911114a..76ef4420 100644 --- a/java/ModSecurityTestApp/src/java/org/modsecurity/ModSecurityFilter.java +++ b/java/ModSecurityTestApp/src/java/org/modsecurity/ModSecurityFilter.java @@ -42,7 +42,7 @@ public class ModSecurityFilter implements Filter { HttpServletResponse httpResp = (HttpServletResponse) response; MsHttpTransaction httpTran = new MsHttpTransaction(httpReq, httpResp); //transaction object used by native code - try { + try { int status = modsecurity.onRequest(modsecurity.getConfFilename(), httpTran, modsecurity.checkModifiedConfig()); //modsecurity reloads only if primary config file is modified if (status != ModSecurity.DECLINED) { @@ -53,9 +53,7 @@ public class ModSecurityFilter implements Filter { //process request fc.doFilter(httpTran.getMsHttpRequest(), httpTran.getMsHttpResponse()); - status = modsecurity.onResponse(httpTran); - if (status != ModSecurity.OK && status != ModSecurity.DECLINED) { httpTran.getMsHttpResponse().reset(); httpTran.getMsHttpResponse().setStatus(status); diff --git a/java/ModSecurityTestApp/src/java/org/modsecurity/MsHttpServletResponse.java b/java/ModSecurityTestApp/src/java/org/modsecurity/MsHttpServletResponse.java index c0f0d314..72c255d8 100644 --- a/java/ModSecurityTestApp/src/java/org/modsecurity/MsHttpServletResponse.java +++ b/java/ModSecurityTestApp/src/java/org/modsecurity/MsHttpServletResponse.java @@ -3,67 +3,20 @@ package org.modsecurity; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.PrintWriter; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Locale; -import java.util.TimeZone; import javax.servlet.ServletOutputStream; -import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; public class MsHttpServletResponse extends HttpServletResponseWrapper { - private static final int INTERCEPT_OFF = 0; - private static final int INTERCEPT_ON = 1; - private static final int INTERCEPT_OBSERVE_ONLY = 2; - public static final String DEFAULT_CHARACTER_ENCODING = "ISO-8859-1"; - private int interceptMode = INTERCEPT_ON; - private ArrayList headers = new ArrayList(); - private ArrayList cookies = new ArrayList(); - private int status = -1; - private boolean committed = false; - private boolean suspended = false; - private boolean destroyed = false; - private String statusMessage; - private String contentType; - private String characterEncoding; - private int contentLength = -1; - private Locale locale; private MsOutputStream msOutputStream; private MsWriter msWriter; - protected SimpleDateFormat formats[] = { - new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US), - new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US), - new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) - }; - - private class Header { - - String name; - String value; - - Header(String name, String value) { - this.name = name; - this.value = value; - } - } + private boolean destroyed = false; + private boolean suspended; public MsHttpServletResponse(HttpServletResponse response) { super(response); - - characterEncoding = DEFAULT_CHARACTER_ENCODING; - TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT"); - formats[0].setTimeZone(GMT_ZONE); - formats[1].setTimeZone(GMT_ZONE); - formats[2].setTimeZone(GMT_ZONE); - locale = Locale.getDefault(); } public void destroy() throws IOException { @@ -71,40 +24,6 @@ public class MsHttpServletResponse extends HttpServletResponseWrapper { return; } - if (interceptMode == INTERCEPT_ON) { - if (status != -1) { - super.setStatus(status); - } - if (contentType != null) { - super.setContentType(contentType); - } - if (characterEncoding != null) { - super.setCharacterEncoding(characterEncoding); - } - if (contentLength != -1) { - super.setContentLength(contentLength); - } - if (locale != null) { - super.setLocale(locale); - } - - // send cookies - for (int i = 0, n = cookies.size(); i < n; i++) { - super.addCookie((Cookie) cookies.get(i)); - } - - // send headers - for (int i = 0, n = headers.size(); i < n; i++) { - Header h = (Header) headers.get(i); - // TODO don't send our cookie headers because - // they are not well implemented yet. Cookies - // are sent directly - if (h.name.compareTo("Set-Cookie") != 0) { - super.addHeader(h.name, h.value); - } - } - } - if (msWriter != null) { msWriter.commit(); } @@ -151,48 +70,26 @@ public class MsHttpServletResponse extends HttpServletResponseWrapper { } } - @Override - public String getContentType() { - if (interceptMode != INTERCEPT_OFF) { - return contentType; - } - return super.getContentType(); - } - @Override public ServletOutputStream getOutputStream() throws IllegalStateException, IOException { - if (interceptMode != INTERCEPT_OFF) { - if (msWriter != null) { - throw new IllegalStateException(); - } - if (msOutputStream == null) { - msOutputStream = new MsOutputStream(super.getOutputStream()); - } - if (interceptMode == INTERCEPT_ON) { - msOutputStream.setBuffering(true); - } - return msOutputStream; - } else { - return super.getOutputStream(); + if (msWriter != null) { + throw new IllegalStateException(); } + if (msOutputStream == null) { + msOutputStream = new MsOutputStream(super.getOutputStream()); + } + return msOutputStream; } @Override public PrintWriter getWriter() throws IllegalStateException, IOException { - if (interceptMode != INTERCEPT_OFF) { if (msOutputStream != null) { throw new IllegalStateException(); } if (msWriter == null) { msWriter = new MsWriter(super.getWriter()); } - if (interceptMode == INTERCEPT_ON) { - msWriter.setBuffering(true); - } return msWriter; - } else { - return super.getWriter(); - } } public ByteArrayInputStream getByteArrayStream() throws Exception { @@ -207,85 +104,6 @@ public class MsHttpServletResponse extends HttpServletResponseWrapper { return stream; } - @Override - public void setCharacterEncoding(String charset) { - if (interceptMode != INTERCEPT_ON) { - super.setCharacterEncoding(charset); - } - if (interceptMode != INTERCEPT_OFF) { - characterEncoding = charset; - } - } - - @Override - public void setContentLength(int contentLength) { - if (interceptMode != INTERCEPT_ON) { - super.setContentLength(contentLength); - } - if (interceptMode != INTERCEPT_OFF) { - this.contentLength = contentLength; - headers.add(new Header("Content-Length", Integer.toString(contentLength))); - } - } - - @Override - public void setContentType(String contentType) { - if (interceptMode != INTERCEPT_ON) { - super.setContentType(contentType); - } - if (interceptMode != INTERCEPT_OFF) { - this.contentType = contentType; - headers.add(new Header("Content-Type", contentType)); - } - } - - @Override - public void setBufferSize(int size) throws IllegalStateException { - super.setBufferSize(size); - } - - @Override - public int getBufferSize() { - return super.getBufferSize(); - } - - @Override - public void flushBuffer() throws IOException { - if (interceptMode != INTERCEPT_ON) { - super.flushBuffer(); - } - if (interceptMode != INTERCEPT_OFF) { - committed = true; - } - } - - @Override - public void resetBuffer() { - if (interceptMode != INTERCEPT_ON) { - super.resetBuffer(); - } - if (interceptMode != INTERCEPT_OFF) { - if (committed) { - throw new IllegalStateException(); - } - - if (msWriter != null) { - msWriter.reset(); - } - if (msOutputStream != null) { - msOutputStream.reset(); - } - } - } - - @Override - public boolean isCommitted() { - if (interceptMode != INTERCEPT_OFF) { - return committed; - } - return super.isCommitted(); - } - public void setBodyBytes(byte[] bytes) throws IOException { if (msOutputStream == null) { msWriter.reset(); @@ -296,423 +114,4 @@ public class MsHttpServletResponse extends HttpServletResponseWrapper { } } - @Override - public void reset() throws IllegalStateException { - if (interceptMode != INTERCEPT_ON) { - super.reset(); - } - if (interceptMode != INTERCEPT_OFF) { - if (committed) { - throw new IllegalStateException(); - } - - status = 200; - characterEncoding = DEFAULT_CHARACTER_ENCODING; - contentType = null; - contentLength = -1; - headers.clear(); - status = 200; - statusMessage = null; - - if (msWriter != null) { - msWriter.reset(); - } - if (msOutputStream != null) { - msOutputStream.reset(); - } - } - } - - @Override - public void setLocale(Locale locale) { - if (interceptMode != INTERCEPT_ON) { - super.setLocale(locale); - } - if (interceptMode != INTERCEPT_OFF) { - this.locale = locale; - } - } - - @Override - public Locale getLocale() { - if (interceptMode != INTERCEPT_OFF) { - return locale; - } - return super.getLocale(); - } - - @Override - public void addCookie(Cookie cookie) { - if (interceptMode != INTERCEPT_ON) { - super.addCookie(cookie); - } - if (interceptMode != INTERCEPT_OFF) { - cookies.add(cookie); - // TODO improve; these headers will not be - // sent to the client - StringBuilder sb = new StringBuilder(); - sb.append(cookie.getName()); - sb.append("="); - if (cookie.getDomain() != null) { - sb.append("; domain=").append(cookie.getDomain()); - } - if (cookie.getPath() != null) { - sb.append("; path=").append(cookie.getPath()); - } - if (cookie.getSecure()) { - sb.append("; secure"); - } - headers.add(new Header("Set-Cookie", sb.toString())); - } - } - - @Override - public void addDateHeader(String name, long value) { - SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); - format.setTimeZone(TimeZone.getTimeZone("GMT")); - this.addHeader(name, FastHttpDateFormat.formatDate(value, format)); - } - - @Override - public void addHeader(String name, String value) { - if (interceptMode != INTERCEPT_ON) { - super.addHeader(name, value); - } - if (interceptMode != INTERCEPT_OFF) { - headers.add(new Header(name, value)); - } - } - - @Override - public void addIntHeader(String name, int value) { - this.addHeader(name, Integer.toString(value)); - } - - @Override - public boolean containsHeader(String name) { - if (interceptMode == INTERCEPT_OFF) { - return super.containsHeader(name); - } else { - for (int i = 0, n = headers.size(); i < n; i++) { - Header h = (Header) headers.get(i); - if (h.name.compareTo(name) == 0) { - return true; - } - } - } - return false; - } - - @Override - public void setDateHeader(String name, long value) { - SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); - format.setTimeZone(TimeZone.getTimeZone("GMT")); - this.setHeader(name, FastHttpDateFormat.formatDate(value, format)); - } - - @Override - public void setHeader(String name, String value) { - if (interceptMode != INTERCEPT_ON) { - super.setHeader(name, value); - } - if (interceptMode != INTERCEPT_OFF) { - for (int i = 0, n = headers.size(); i < n; i++) { - Header h = (Header) headers.get(i); - if (h.name.compareTo(name) == 0) { - headers.remove(i); - i--; - } - } - headers.add(new Header(name, value)); - } - } - - @Override - public void setIntHeader(String name, int value) { - this.setHeader(name, Integer.toString(value)); - } - - @Override - public void setStatus(int status) { - if (interceptMode != INTERCEPT_ON) { - super.setStatus(status); - } - if (interceptMode != INTERCEPT_OFF) { - this.status = status; - } - } - - @Override - public void setStatus(int status, String message) { - if (interceptMode != INTERCEPT_ON) { - super.setStatus(status); - } - if (interceptMode != INTERCEPT_OFF) { - this.status = status; - this.statusMessage = message; - } - } - - @Override - public void sendError(int status) throws IOException { - if (interceptMode != INTERCEPT_ON) { - super.sendError(status); - } - if (interceptMode != INTERCEPT_OFF) { - this.status = status; - this.setSuspended(true); - } - } - - @Override - public void sendError(int status, String message) throws IOException { - if (interceptMode != INTERCEPT_ON) { - super.sendError(status); - } - if (interceptMode != INTERCEPT_OFF) { - this.status = status; - this.statusMessage = message; - this.setSuspended(true); - } - } - - /* -- Inspection methods ---------------------------------------------- */ - // TODO throw exception when interceptMode set to OFF - public Cookie[] getCookies() { - return (Cookie[]) cookies.toArray(new Cookie[cookies.size()]); - } - - @Override - public int getStatus() { - return status; - } - - public int getContentLength() { - return contentLength; - } - - public long getDateHeader(String name) throws IllegalArgumentException { - String value = this.getHeader(name); - if (value == null) { - return -1; - } - - long result = FastHttpDateFormat.parseDate(value, formats); - if (result == -1) { - throw new IllegalArgumentException(value); - } - - return result; - } - - @Override - public String getHeader(String name) { - for (int i = 0, n = headers.size(); i < n; i++) { - Header h = (Header) headers.get(i); - if (h.name.compareTo(name) == 0) { - return h.value; - } - } - return null; - } - - @Override - public Collection getHeaderNames() { - Collection headerNames = new LinkedList(); - for (int i = 0, n = headers.size(); i < n; i++) { - Header h = (Header) headers.get(i); - headerNames.add(h.value); - } - return headerNames; - } - - public int getIntHeader(String name) throws NumberFormatException { - String value = this.getHeader(name); - if (value == null) { - return -1; - } - return Integer.parseInt(value); - } - - @Override - public Collection getHeaders(String name) { - Collection headerValues = new LinkedList(); - for (int i = 0, n = headers.size(); i < n; i++) { - Header h = (Header) headers.get(i); - if (h.name.compareTo(name) == 0) { - headerValues.add(h.value); - } - } - return headerValues; - } -} - -/** - * Utility class to generate HTTP dates. - * - * @author Remy Maucherat - */ -final class FastHttpDateFormat { - - // -------------------------------------------------------------- Variables - /** - * HTTP date format. - */ - protected static final SimpleDateFormat format = - new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); - /** - * The set of SimpleDateFormat formats to use in getDateHeader(). - */ - protected static final SimpleDateFormat formats[] = { - new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US), - new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US), - new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) - }; - protected final static TimeZone gmtZone = TimeZone.getTimeZone("GMT"); - - /** - * GMT timezone - all HTTP dates are on GMT - */ - static { - - format.setTimeZone(gmtZone); - - formats[0].setTimeZone(gmtZone); - formats[1].setTimeZone(gmtZone); - formats[2].setTimeZone(gmtZone); - - } - /** - * Instant on which the currentDate object was generated. - */ - protected static long currentDateGenerated = 0L; - /** - * Current formatted date. - */ - protected static String currentDate = null; - /** - * Formatter cache. - */ - protected static final HashMap formatCache = new HashMap(); - /** - * Parser cache. - */ - protected static final HashMap parseCache = new HashMap(); - - // --------------------------------------------------------- Public Methods - /** - * Get the current date in HTTP format. - */ - public static String getCurrentDate() { - - long now = System.currentTimeMillis(); - if ((now - currentDateGenerated) > 1000) { - synchronized (format) { - if ((now - currentDateGenerated) > 1000) { - currentDateGenerated = now; - currentDate = format.format(new Date(now)); - } - } - } - return currentDate; - - } - - /** - * Get the HTTP format of the specified date. - */ - public static String formatDate(long value, DateFormat threadLocalformat) { - - String cachedDate = null; - Long longValue = new Long(value); - try { - cachedDate = (String) formatCache.get(longValue); - } catch (Exception e) { - } - if (cachedDate != null) { - return cachedDate; - } - - String newDate; - Date dateValue = new Date(value); - if (threadLocalformat != null) { - newDate = threadLocalformat.format(dateValue); - synchronized (formatCache) { - updateCache(formatCache, longValue, newDate); - } - } else { - synchronized (formatCache) { - newDate = format.format(dateValue); - updateCache(formatCache, longValue, newDate); - } - } - return newDate; - - } - - /** - * Try to parse the given date as a HTTP date. - */ - public static long parseDate(String value, - DateFormat[] threadLocalformats) { - - Long cachedDate = null; - try { - cachedDate = (Long) parseCache.get(value); - } catch (Exception e) { - } - if (cachedDate != null) { - return cachedDate.longValue(); - } - - Long date; - if (threadLocalformats != null) { - date = internalParseDate(value, threadLocalformats); - synchronized (parseCache) { - updateCache(parseCache, value, date); - } - } else { - synchronized (parseCache) { - date = internalParseDate(value, formats); - updateCache(parseCache, value, date); - } - } - if (date == null) { - return (-1L); - } else { - return date.longValue(); - } - - } - - /** - * Parse date with given formatters. - */ - private static Long internalParseDate(String value, DateFormat[] formats) { - Date date = null; - for (int i = 0; (date == null) && (i < formats.length); i++) { - try { - date = formats[i].parse(value); - } catch (ParseException e) { - } - } - if (date == null) { - return null; - } - return new Long(date.getTime()); - } - - /** - * Update cache. - */ - private static void updateCache(HashMap cache, Object key, - Object value) { - if (value == null) { - return; - } - if (cache.size() > 1000) { - cache.clear(); - } - cache.put(key, value); - } }