From 4e8e22ec61497a89ff3d29e8b7aa5d9a7c830dbc Mon Sep 17 00:00:00 2001 From: Nayan <33187059+GShadow5@users.noreply.github.com> Date: Thu, 8 May 2025 18:32:40 -0400 Subject: [PATCH] changes to send headers and body separately which fixes images not sending --- client_handler.c | 10 ++++++---- http_stuff.c | 44 +++++++++++++++++++++++++++++++++++++++++++- http_stuff.h | 13 +++++++++++++ public/image.png | Bin 0 -> 28411 bytes request_handler.c | 26 ++------------------------ request_handler.h | 3 +-- response_builder.c | 35 +++++++++++++++-------------------- 7 files changed, 80 insertions(+), 51 deletions(-) create mode 100644 public/image.png diff --git a/client_handler.c b/client_handler.c index 6b34768..956f2af 100644 --- a/client_handler.c +++ b/client_handler.c @@ -28,14 +28,16 @@ void* client_handler(void* args) { buffer[bytes_read] = '\0'; // Allocate space for response - char* response = NULL; - size_t response_length = BUFFER_SIZE; + http_response* response = create_http_response(); // Handle request - handle_request(buffer, bytes_read, &response, &response_length); + handle_request(buffer, bytes_read, response); // Send response - send(client, response, response_length, 0); + char* headers = response_headers_to_string(response); + send(client, headers, strlen(headers), 0); + send(client, response->body, response->content_length, 0); + send(client, "\r\n", 2, 0); free(response); return NULL; diff --git a/http_stuff.c b/http_stuff.c index 6d78318..81b8181 100644 --- a/http_stuff.c +++ b/http_stuff.c @@ -138,7 +138,7 @@ char* response_to_string(http_response* res) { total_length += strlen("Content-Length: "); total_length += strlen(content_lenth_str); total_length += len_crlf; - total_length += strlen(res->body); + total_length += res->content_length; total_length += len_crlf; total_length += 1; // For null terminator @@ -161,6 +161,48 @@ char* response_to_string(http_response* res) { return response; } +char* response_headers_to_string(http_response* res) { + // Define lengths + int total_length = 0; + int len_newline = strlen("\r\n"); + int len_crlf = strlen("\r\n\r\n"); + + char* content_lenth_str = (char*)malloc(10); + sprintf(content_lenth_str, "%zu", res->content_length); + + // Calculate total length + total_length += strlen(res->status_line); + total_length += len_newline; + for (int i = 0; i < res->num_headers; i++) { + total_length += strlen(res->headers[i].key); + total_length += strlen(": "); + total_length += strlen(res->headers[i].value); + total_length += len_newline; + } + total_length += strlen(res->content_type); + total_length += len_newline; + total_length += strlen("Content-Length: "); + total_length += strlen(content_lenth_str); + total_length += len_crlf; + total_length += 1; // For null terminator + + char* response = (char*)malloc(total_length); + strcpy(response, res->status_line); + strcat(response, "\r\n"); + for (int i = 0; i < res->num_headers; i++) { + strcat(response, res->headers[i].key); + strcat(response, ": "); + strcat(response, res->headers[i].value); + strcat(response, "\r\n"); + } + strcat(response, res->content_type); + strcat(response, "\r\n"); + strcat(response, "Content-Length: "); + strcat(response, content_lenth_str); + strcat(response, "\r\n\r\n"); + return response; +} + char* get_header_value_request(http_request* req, char* key) { // printf("Getting header value for key: %s\n", key); for (int i = 0; i < req->num_headers; i++) { diff --git a/http_stuff.h b/http_stuff.h index 600be75..5a81a73 100644 --- a/http_stuff.h +++ b/http_stuff.h @@ -139,6 +139,19 @@ void print_http_response(http_response* res); */ char* response_to_string(http_response* res); +/** + * Returns the string representation of an http_response struct WITHOUT the + * body. This function is meant to be used when sending a response over a + * socket. It allocates memory for the string and returns a pointer to it, so + * the caller is responsible for freeing the memory when it is no longer + * needed. + * + * @param res The response to convert to a string + * + * @return A pointer to the string representation of the response + */ +char* response_headers_to_string(http_response* res); + /** * Finds the value associated with a given key in an http_request's headers. * diff --git a/public/image.png b/public/image.png new file mode 100644 index 0000000000000000000000000000000000000000..bff699aa8a0fab312da3be3f02f1e25041c61736 GIT binary patch literal 28411 zcmb@tWmH>X`{r8;#Vyd{QlJ#KLUAX!y9al7cMDz|iaQhw?(S0D-QC?e^gZ*RwPwzo z^I_(E$lAI0+G{0wcAn(AuKRa~%E^eLAmSl@`0xQmTnwo2;RDp}`=byZ_Wg{0()GUs zl!Jn(;D_>2f`j)0#za6`;KPT?XryPoPwzE?t(dyQhYwif{~l1{3g6B@e6ao{4ir#w z1)Z!QsC}7R;XAJ=JrrIr1S|mgv7i7EVL-b%aOH2MGU;OraOigwGdyX`shaJ~?`FAP zQ{x4{)#BL9t!hI1V15@d<;eSoSyEG$(2{2PQmPvLeH&SBv=!jTDx2DUa?6O}+RNbB z8yWFBwHZxu==Y9_idx&Mqh+E!lucew4)6ByB>cjbV3@)n!hQGAzbtQV^JOjUZpSfb z0_L9k4d%I=xTAe_C73nU*+`gnbC>JuLv%R6K~6jlrlN0mj#M|U5*KOqR0V@8D^&0} z>XR*1ME7DL8>yr?tTCyv2a8}##EqoEFJED`dJkMrhLi3;6#DX|+mo8-eb&HFv-mY+ zf|l)g*$K^nhY@3rXwY=#7DU&T*I87g`#c@2>a2UiUK3ww`eIFcRovB9D2$JkAhj}i z*Ay^o*>@CY^{dSc3bdMQIO%}7)W(I0`l&uq76^PJ5*b=sD(VbkK+B!%!Mvjj3oMRB zELk`QJyHgvsmyM`W*YH@v=ZczJ41X7IYiW_*RS`unuz0@V}JX$NOVlQd{=p-G$TZC z_N~2F^x;_hN*V6Tc4HO-kC7)P$QHG>K;SjUF540^L}cF1SxBPx}S+ z)7v6g=K~xZKHXNuXm?plZQ+e`6*Ksz}xltizpwzvt59e)EfC#y47G2tCPSs zv9oSB&4k*+wnQb6Y_|+${&7NMqT+LuVU`$;zlE5RWXAp+tHBakR8hj>oM8ChW(;{c zLBsuO;+kDABWPY%E83c%oL^j0%_q=3Us%9(!UjvCM-UC`cD31-D3nx}ug*dAnZuWA z$5G+kv)DU4P0Xm)eQjy5$xXtWk%>*J1}mb(x(iwM@iYry@c!z)w=Nc*Oj}UJ-Iwe^ zH&)}9Ls@v_yMT)uQWh;HwQ@E==39=y3O8KL;MDca?0P#_onVEo^z0SlfPE*sfhJo2 zxrP*Q8g}RaT)|gU%3m&Dp(wVs>|D2G?FK4XEe4q53O! z&lULY_Q9G~tabb~CKu4pdCr$n+Xz}K<$pdCp*jKruZ3nyIxIh5!hDZlRGtO$xBU($ z!_Vj{pUdb-@^MA9tKjw1_F3|am^_j|Jxt>WZsP3dicn>IU(J$^W5jw!*_yze-Ej8X z)gwxp=In1`c;i~nU#ixg=q`uizmdLgtg;N**D80IjWOwf+^Rp)Uc@@yx9L^RaC9Cp zA-ftRM&12IX|*uS+@-!2gZD>UI(i}3ZAlcb=i81Ec6c9|4Jub{af2w@`*hYug=4SV zG9sb9U&7&-Iu)-a@;#+%8(cS;ds0O-vWj>9qYe1D@m?+~4oP$ur2VVm!^r=sll7 zEW@iNgAxaIhPULNu88$cO-)vKCHglzDDG!MlI-M@lo>ny`^hRTThJ_Fsamg&$i)_3 z5Hc*xDxgoD? z){K5n-I9!d_A^~QFU}Yn$tlAb9@gkPUG1FYlCQtq`rLep4U=AH^+o_arK1H8Eg?du zU)-kBFdF22Idq5~dbp)X4|&)Zh0w}j+qzq{z++XsIFbglW(vnDovMo3P0SN+`7|N= zc!&)KlH7M|(lB*T5hV0Gop5_r0o&AmEhal~3#^u(7pN6;mRV%RQwXg#q{8YdjUdwE zIO9@1_1+?w6=B>o{q=@v&nPjBq1E))8NvBfO=HGRJ43d^?9`W>`HHsMrZbpp!i(tR zsz($I;?1rRg;6MxSA%e3L{qC9ZgM|w4h78y}=05H{6IbU?A{7_@`W)U2LmcH@KfE5Xo5R#lAiow-WpdSIZyXcX~g(Zzgrl=W1veufjSQK00v_d!6bAYY{OvDK6zOpq-Du(=O+G|UoR752=GNC_ z$w$Ufi*auuMs#~3@lUDJYL~1&1;W6?xvLJ(YN+7s`GNhqwGJB>X-uugN&iz4H*ip-CHG+ay3$-L2&NpsQnWs1~IBe5M- zNd9_$vEa61@1fUves1x!q$>^C$G9#}7xZj4xUFZ-DP*8GriDG4Wn$##MH>+B&_s~< zy{SJbkVdPb!Z~$vHGh~m)ixPm*nNXXJ-K&UGEy$uSB0vJLfu>=fqcO|5{9~%bUyj{lbXSObXeg} zFF|f%ZHW%8Y-HkUb(fr(YXdt%b97?vD)r}R8&|-^k;zsN{FSp%jh7Q{LVrRMoplzd z$-T<1M_=3DQYsMb_52dU(#?bX)~5#csa`aU$O7)qkTv1=@}e&$&^U$^gqkFVU{4}? ztUX7Z4@W3IKjvbrGeuibd6DXI7H>ExNFUM0-|x^4BfXXi2p=_sT-3a@+U@e2o{tFb z`sc95l3Cs1)LbUe-7TTK&yr5Q`g#!C-1>Us@^k{>COQ3t_0#mg7Alv7$zC$ZY0kvtFU&Rjt(3mZ&N;=$tLN9GVUbu6z05 zov^ve-&}|@`cMP1m&5bP?^llALK>srK5>m|`K5?{%g`ujc{sE6VgK%toXdLh1~F`G zkaIm?=B^j0ad5$PCsawe(mmQN*R<&-2(V@w`?IuHNfGbBJ0j^4oeAFOldE{F{!6je z@8VYG@;egNgY@}=Pj7?f%wV+QHEdw5EjlQgK_qL6pS+(i-VSjgC)H$^FiOXR%8ZaR z{8-_lpXqb7$iBjL@S|*x zC*1FjVMytb>iJyv8X5+m~iGv?GeQWMXWoZ}g~c>lfrp z5yPOV1bwe?3r~^sOp$ zwC~ba@L23K7mxS%x;9q)YRyG7JfJ^o&EP;)<^%GM#wmbKGm>|8* z0jXmi^47UpdCaqJwZhbahi}lL2`q$2Bi@Wam=%Szdv0u#a_~(G5zgT*oY_a`tW3;Z zdJuSrUZiLexySdn<@1{NfjHxkGu!nM>@xSo)KgkdTcPfg{6V0(o!KwUf=9QGC+`4z zY+i6b1=upFOxMV+H_IwY?cBfy*>a)nX|M8X%pZEy`;4RXr4sX4HluH%gnuX$14cNo zi_MnXo7?-VXNbC9j?%8a9q1#&dR*SBCr&8%)$7p~?jEDu^Yx>1>jNt)@i4!DdgODO zrCFnbO5jvT{l+lc+}8@hL2o#1se8nB@Czb`@^@RL6jJ{!%aLR|J`oNU(kD4QRGJ6d z%dZ(4YpiSEbTAElp4pDuY>&JK2#?;-xMUKuoUmWsX@}yvDUJ z$1&JfE0!@yUOAvh!J^oZ^^xuCg{5(oj$h;?%#~8Ss9*awSl#DAvvWqgmC#NsoIRVR zmHLC=ahNsjw2#uUe#}5ti=oqj!K&-kVUvJ8SU*;2*HXUVFUn`*s|`|Mp10SV4e^`M zLB?;R`)vl&cX3}K>rilTigRe_hwG=3&Oml{En5x-i_y&+sOUwj&(&#WX0PN7?*TCZ z6Fxs+jZuv-0Wo2=l&SC62zx_#jNhf@PyOhWeX31==XnE(Cp8R52z@;aSkgX}Q8saXkH+velN! z;z~7}B9V(qZSc#BwW0Xg(SnHXP6bhKd`yli^^V14&V6$kn9b`mO@F6utQ>Y+9A}E$ z_S3iq@XeG~tJEnM4rQj7{X(5~^?o|*({IMoXRFTzuAz?!0#ej09x(=y_t#9KgBA*(i21oiFW&dBWWgSfu>}{h0!X4< zX?3Nzf?hI1c>Lk7E6Wdz7&-xU&%t)wAV!L>cVYyaZD64;H|B;w(T&KP@NtYo7G}Uz z;SBh?THvJ-hC^pLhEy%E6gZ8;Os;r#ANJwA?~;+7b&phl`Ys&iGk)_|%Ljb5df=MB zTxpbc_&^L6rR;RA!&;^OG@4ytfGZmV6)2B9=RR1iSZc0TmKIKNJF;0kAZx9Eoq}GO z{gI*a<<&7h{Od8(nR;ou4f?feOV|wBeOC@A;ZvS_o~JQAymlLwMIoiz^+>?^E)AdG zaDHwRYhhye)oHjeL%5fG)j*G%>(z`AyaTI{`X#US>eS7-CnaokS^~HB!Ks^))T zEDu~^0^}h?K>JK~nlD;uydq-hX+t*4cZZ`dYp!?5j8x+9#6hMLAz0)Tu-GxRIK zuhuLTP*%fyTdVAPUAd;8&p%mn z!<~3bqIVy{yI12XNhR_G*dJ^iWeyzATUpjR!NhiIri7) zE))sNu0~{RCLN!YG~s=vtV?Z}vxlb*vn~%$DTg1Xb=g&HHGLr)1*QXwA(18tEGbw| zQHG&DgzI?JWn;j7_=&wg+t@OWkC6F_eMj`pOeXkux!d1F#Xb zJg0*8vud`=^Mq?4$)t*eoRW$QS%YH|)4-#Dego z@PU*z>~;anZ@K?xzqOvjSmSt<5<_75GghJmp9(W}_M{toGx5=FJx}5y+1WZUyJ|AU zI`y&eM?a7T1`!8UG-E^Xx--;?jGrU_O1-q2+}TeAQTLxfC6+Dy|W~SN}wP z3-JrOH^9RQYG`Pv8?Mg2JTD9|2)v*B#2O$R{VIqRn}4!ceAexF0Z_3=La)iue$fv_ zjnVvoeE|7v-FqsuV+uj-9g5zB+^paL|JueZx$Y@t)5^OoJ-}3^FgPgd4GLHlrh7)K(t7q96dDKZt0~=(M$_rYa!k zf~7tAihwb}Le3#gWUKUh=6P5$M+6}7&--Wb+=54>PM8z)$xKOJIDqW%CttS&*Ks0b z&7^E1X*H=Xc4B147j9!fHDovI?D8l_(jH`3!`<|I0it_6siOB^%EG(IXbb>J)Q<(D z*=pyzJ6resAP{euaFdo$IAoKs6$DlD zoejP4KKq9ZL($>Hm&p$&Kc_=MxyD7&`&?^7?)?36?JTVIw}qqx`NbM#e{6>6_+Nse zj@Is1v5uK>hGr6vyZcmCHYV~JhVRU!Td{O!!nl@fPAB7glMjp#PX^U!K?Fg{V`Ty( zTsi4n!`mR+ig)iiQMU48mNI+n_KmJp{Q=}?5TV)mYbr(w23iJFVgq)M;lCpkYySCel>PXU2{P4QuV`b~h5 zE!X~5bp14Qu8D)g!ZDts?TC=Ks+Z+Uqj(%HI8SY?I?AZ%!DYBAa= zmYk}#=TE-8jB==t2?;Kdh#qn}df;WP>kdz}7MB*en28z-xDldZnh;k%kg6Xed;cqz zWPtl!eQ}b#wsAETjP?Z}?O*2z5+-|+4V(F#c$mYIQ4PI%R$%-riG;1~aXhdBzOgg#Qe(aqrgF32oy*4V2 za8hg5x*H|Dk}lvL95%WYDb>uiI6AC%(Ooe$<8Q0SfVlba;^keP@6OKJuPuh5B_azp zvP}Gu{AUS6I~L3Az)vQ$Im_>XU(TDYR|9lfWPDu7dGpDcfsQ%r5Ow+R*kEGfVi?i@ zXC<`H+AB9NcIzK5>1ICIiKES5PUghuV?)J@J?X{M}QaiB~NBi zD0NMJNN#}qWZ>Ld$F4!|xH&gENdkux3|^ZX^aRBsoE_b5D^}#q+mK*mC6b^CxJBU= z{FR+`NAHbI0_l=D#$^FHD*KUDCa_z1!or&euab^AruS1%GgpkV6=D*CLVEf5@@-LTG5$fQ|=jlFE;%=I@o5JT`uI%Bp&os4?V|OboXDhcCzLx$v_yqtc{^T)2eav*U zI4it=a?COD9=;Ms`=tmi{0pB6hQ5=MD#Q?5{zubB&KvwI0q>m}QqnJay8p+;E1EH% z(tgPsgs@7!UU9eQC%eT zepXqyFvf$veo0a>oiiSluW^bJ8h2ts z3&VZWx@V8+`wNLKnJn=t2ZR+DnKv}y&Godq`3+n?WqVdYHs5j<5Nm=IVO$bGkR zuHiqaX?>&^t=`n%!djXOU)o#AwySsIZB)zl5lioeRx;0eE$ELO5`bwLqi;^3(r5~5 z;Ds&{u4_-KPfb-5M=}ZfCV^6dC-C0pO85kJPRNKk!$b5IWy=sf_CGl9afhpT0mK2RfSVR!>`%Sy#TP7 zQ3M?=t$zF*&#WOY`peLj9sQAI^UmkVScMn|;lX)))K~bc8sCNS7zq7*02=Q?bS~AW zCI;om`&b`KqG!03j>h=2UoqOgVcw(XXz(IgC*%ZU<+0(uF_;A}$ACZ-=FZwdlKp1?Gh&# z8xb%o`xM;N+&yQ4E)jb*j**&wbkWe^!y#~`?0KVwhR46X_{qU5CUALjRg ziM9`(NMZRr169sU-04_P zb(ByN;+?p8d4{=F2Ocb1 z&9sx&U3N9_!K#XoBmSneLM{RI9Hf!DeV?5Vy!Y&YPYPW0+a#^}=>E@XOw;!mvDcke zU_#jR)qr%-v20*w#UvgHX{Obc+qXTPIEm>`yCg62SAXH=Gt{yy95PJj*1z6!h5yn{ z$@@<>y^E*7w;I?G5j*=b%oOm3V}g7uMW>UR8GZA<=_6lWfmZsbmsd-L^((1D3h#=6b2?_wzDZ7V>$7WGl^&WFduD!%0yqn2-8!P_ z_*-6GcxHaeBx62ZnpXZ#3Rjf556Z>twtuumPN)b54Q?{ z(_{lH5%L)uH9g&dB`H?{4+mn0p7|d~r>HCAekNQBy7H_~a^gxrX_kf=lWAM0sm8Ef zPlYC=7agq|l{2?I_WE$DL0*OGto7z+6ZN%3BdO$iAM5#H<%Hc<na} zg&n1IoB`9@)7A`)N%1I8nj zKXuLAEOdre%TGoQnm8LjnU)?myiR{M(@&zWC@ue7>``wp#gz)7D1qH2GuAt8zvB2E zwZ-He$YDNNw{?P|32|`YMkT;J87V~PjIs)XEitFE*EFN%*)##YspNGI{?F-Rj&Uji5OP{zXrf zN!pE#Mt2ch$fDr94~-o~`J8~}>yw4%DfF_z-GOX8>x{!WP55f?UGEX78K0M)6rdxV z0uX_9>oQQX;B{FOPiF3iM%h8ZVJTY3ddAbj-;e(4qI&5LwEH9W{BN+C3ncx3Xb;p-=T8mj~W7!d4xIo!M@VU}?G0G1xzwrYM&Q zA4rQv+}eexW(hPJ?5=mptt;d=;6V1xRh;j}4E8cVc>sZBUEO+7MWX{3XO4jAHx4(Ebq!N&8#$gy-zTOcJHKGAySkuSv6T z(7yBmbLSHPa3jnBUHt`i%p2pCtZZCXJjQcv8r+oXWXk9{P*{1H^xB+nxSoQ|C!%CY z@+0A$)HrMeecJUV+cOAMv_L!XutKQ1D;2#I_2KWky%BplM-z+U^4%O}OCb11(h#=7 zkD%iG7{aB~dw7!A_Id@FQy;~{h?BKdhzTz2`3MQ;$G%?&te?4h(;m{tYQYZbQcy1& zUI>V=k)^S4`Nd*q8Vj4kg|;CvZy3m7@xco9_2N+6ldARXFmR8U2!-#dlQDsw0k0y5 zg&E~-UM0-&z)Ridc{_$t>asGZPl~Nz)wT>Ll$f}8m%!{Vbi2u#0%ehgQd$;xY@+HEmtk0D^u{}bTCy7% zJoU90MS2{>8N#qO*0J}qDJ?b&%>TUY%@EVCl=Sts@O*%z<&vSyT6=s4w>W-E_&s%% zetitBzzPA0^*9~O-!B~9=01Ek4;$4T3*oqb45nx33)Jn#V3;O&#bM~9G7FovZ|gMX z$anHl^>P)KG2;j!_VHUQ+>ia{Or`~~^yWWmY_|KvvE~&n$$N#qtE4AaFnUca-SMnz zqJ}CLrQ?J!*?y0TugUBD*wo%vIOFYV+Jea@##t@CsK2-Qx^v_*dPNf;bQagnTC> z;>4u5L$7}ruz!*fydKlmrLaMI-rjRyq8P`ULmC@!!mS_U~taWp&Wj-j60cZ4(!t@U_d8R##d zE+-vNXw7{4M$yptHlX>)!&k0D!QLHc&Nsbci9=E&z>S~GY8;dT8t@nbGNV(p{;{!p zu`$zqjjmQrvBhx5iDMmU0DisSN-D5FXnKBzc))vK=E3>LbGrnw2akzL1AnzL(Wejp ziWa|oaAy}D=~MF{kA^zigFV)i+6D?iE&W6VpNayik?1?(%n&7Nk2$Xbjkh)oY zDYz$~&Y9S*j`xvG+G}`^f+-g!5}H%@SXVH$~Zm1~ooYP@gBh3$uZ_gi@JZ?_7 z(UO>WZSj7f2W&fsA%O=%&vCT;41C!AU1TL6hV0G<)D5w~pi;+>jtS^7o@11fu(FVNCs%K_l+ES zYKmB>Sl|(%baaj(ET^Et3#U434<2m}6iUknvp8#?C!JAY&)<^)Nn_c#^y#y2S`r+= ziJLeQ{o6W8+XnWuWgq%!qyVgos4v-8bc)yWnVFm5UR0DpHM4gJ5M#twq)*MH|O~5`#UT+?)!;Rw_cQ1++xPu^f~MkEZ<{K zi7}6n8|hyLzjJijo1d6dB*}wdySx3j;O{wba|K|+BZc2dlHqHGi&|bBXR`cS{Ba4P zDj}`&U;DUq4HJQaFLGrdBUD~l70}U_bYXk>xcgCJ{|+d9?P6?U-1%i*25bGRjVt?= z3+Boqm=`t%tWZdNu&98+G zUdiEwI-xP`3{hwlX)AjAQ1Eo#o*(W`gJ)Bo6MJ(eoe1|mv)UrQ3<9$N-_wPy=egbd z61BL?P%Uhub#(!?){mS!DcA9MQ)MO~g2)(RsrcLVTHzJ5||ahcOh z@-SQCX<98n!3@@=7;CPVm`k(}^%BvbbSG5kXU^RUmo)pe6D-K{in*nV2Ri9DT(^xi zm|ICxk%C^1k>Bx}b9F5;^ULP2b9aaKQCYDh?U$OPg+dqDyo?j_o{A+h&`{CZdE)#7h)ZNNF znx$^jKY30AIM!AL^Q;?3 zJWWqCc+$;g3o=Cap&MSNoz@DB{yoCNLS}%rM2w-!Uu0Itc;F&d9(8dapmgkM2&ngA zI^(W)nbwKVXOc#0czQ+X=NZ}o1}Rf5uX%b`<zKIcG93cue> zFB#ypWb3mmt#uCl9dbGHb#OX-+vCKcw}=QM6O*6a@VOJT`H#4-Yky9PHI1(iXGrdX zIl7>=m`EMj`x=uwrdANMd83kff5P*nbKv}4OC-VWzL+eDV_I86w(f=fss%5uSg!+lWCB(pyyXBlD5%2e|FG;SQ3|G0FT! zAz;K%Y?X4_fko}_Mw12lS}{wYopoD;J|ZQe8dDt&J{5HSG^)GmF2UN`Q-tlb82AA5 zuzyIrHB0>W6UD`=IDmj533{{}z_^T}r+15UpzALWsS#1p{&6M_< znnqHjKn`qP;fHx*-`eQCGstWBHDT-(&UeyI4`(<%+tE9RbQ;yo=o}I2G9vbT4CTV2 z{LYs{%0sHFY;q(F0_=#QY>BtRm{2>!>{=*f38O;-9ycbxpunP7rYCsuoW)w#J=spo zKJ{Ew&JbpfGiA84+tU_krYjqVyLgwr5G4n$RV4f3qLSbL*!o_M4dM@APZS{PULqKV zAmpA8AlrRlXHEs5R)TJloyylACtPBl?+DqG62c`DG#)q>Chc3R2*?jSVlM95vvM^4 zAvhAep=&mLp<_SE4D;xLk$2cS%YP}kQ_xld*QnDfiu(Cg`Bt9vUTxW$1Glwx zHfp==gRySN*Yq3&IatW@JxSmRnc#1XQts`y*yb(SubL@|8LXc*VD|CLc7okIs@mk@ z@uRV~+#NoVaux`GDVk#^6SFQXTKg+@yfp{*s>m_=F_lF8iliBfC~shh)Gnvp2AMd; znN$kHq#ACgG{c8R!bmRLo_@Nz#0cp26(oL03Fe8o(FZ_lsR2B-dh+GJkudW%*8_= z6a(GO&}R=OiM`WDGbl(&YjvX^+VlHMx#ya$8Yi{+xPF7d(|-SRbHnvNK1=(5;j?1? zO~17K$E9KXFI?LHVA=jx#q|Re+4llP+e{mnk0Bi0LtRQT7NuqUb{l}a?PDRCZYPe& zX_Ehe-DxK4E9={>1waPZBKP-LbJZj?0pSe~sA8{M`aJ~k4o*~uV|Hqc+;5}xWs#IU zeRRIvl{ae78vd~&z&xV&29Jk<)BxY2wd58Snkb&L}8QW>*vjsQ%kc7G_3(NZM4J->Q)zN0jVqWHD>}xZjCv@~^ zbk9dGn|GASJzv#tq05Qmd-G9nnUU()*3wD|dbJm>_uH7!{Yo8W=^HnZdVZ~`QWg69 zeL1-yWsL5d=66Y^v@k8_*I$-ox4j9A{n{9{cxW|W`9}VH^!vXY*`N-zca#aXbYN|j zJF^46w+|^uy*c0-Gi22b&IqkkFfXa-!u-c9L!=+KQNIb)EN?ZsL3){4wG#dv;aXNafox74;!o4|4Hmp}_0!Oi*D?9yoki=|&ALHeyxLGzEjv*or z->j@4yL>18@d9~p1B!~<6;X99AuJUGxhi!t(@GthRw8$J)>Z0-so^(L&3AKU@5PL$C&Pal z!`|Zs2noD0wnd2U!au?et*{S;4WDiIE3y@x&Rn6`3+0LrqGlFtsA>Kg1qE=uN~&I0 zbIT#uDGNgCN~{nbK_L`Xt?$i{uOt{@(vLVDq7Ok zUZ9j}+Dn$z>meqo&XQ824@mwRS`697=;&m?u<#}(r#CqzwL@O>bi(aQ`zx1N%Ej;` zGuM5UjWc4ea#=I3yGw&#>72npOHXkW_4n2B-=xp>aOGwf|6svh8_pQ)p8l1=W;KRe zYRWocMv@%x<;UacDc}3B%DYHSO|C^XKthRhx!RM%n^)>LxZy%5Qc(aFiA+z$obxkn zg4{n_%v$yI-LdMwI7E}&=3y1^Rzs-OhU#H9cylO}8n7oSdWPIs%QXXv`g1Nu?HaSN ze)H=nwZ6dS_D>I^daU4c*pdnzBdh`7naSs z*>=?;t2#tNj*?skkP4-i4Q{OP9p|vbsH-p8RX84*9=MeXDQBS>_VM$(6%>xR%Q@Si zuZUZaTN4WiXb_Xm-|13W@qTo?zOq>hecSc3MPj+&2$zC-CD`qe$#N9E-^TSDk!GG@ z^H#ipDRopf`}Y#iRC?04KCMF?!niqk-9xaOmfASv zQxtFRW^n*44l+#>xxrB&CVc7j$DO>O?4Llp4V}ehZ~k&X3jQ7DfS>(sP~z&`Y)PMM zuG4M7OM-*pL{te3evN!r{Ur>Yw!BFRC!cp_R}A5vI&+&_Fw&poKyBNUW(TR4eFzAo^t9Ez%F>vv4 zH7)`Ydxs-Hv-s|Ca)h>df+eG6gmA;!RX}(WWr<6FDkspY*7WW;!g3cDn5J{G)!m9A zxZj+z2^p_eZl7AAW2`sJI$3c@_NFI5qi6Taj#;@ay=)0ro5h+Gq)piGAJ&FIz^_wI z?>{h+H+)s^f1`;WT9us&?)?+bYFC?jD0T+js_M!*H~aM=J7T=%be>EO!pL>rHCW6j zoa0p@R3BUluxf)bN6&(*H6g|ax!{FF@UsTe{U}&)1WvPZ_WYIgPs~k4)E(Ptxa+rF znuVr(C=_iVg<@$Bm9P8?Ad0!FJ)hAyvt>5e6T>87*wk=xGDVH5&E~c(pP5;rz;rCm&AS z`xx-fYM}^CGb|zd3L5Zr>B6gzee$Cxt<6Rho)K(l#&(#za+Myp$reXLpcZlZ;WnA>~C)X=6ab^Ex;ybBA z3FyYeBAmA;`)X5C(FVeG>SN2}-Rg)0dcMGVevJ96_Oh;ZLMLg_4;_x-Ev^}Mu~ ziGF@`>@10e8a^_dq#uLc7D9Zes&V3N)3??QQZ@Y55G9~pf;Q9(uGKVMa`(zXXVr3B!7Lu6Y+Jl&to9ajX+h~N+zD%I zh5pVv+iB_Y&h04t*Hl3fP<{hf>nB2=*wd@TZ(U1dOhp5n+CUFFdc)o=t@QVq0ul$v zbpOZvH820bD~aEwpQ$u#q|mN}$7>!M)`k)2+dAPD*K{DBoGoxGJqIgC7k@bpy7ZBEX>WprouGrq)WMP~s3uG;q55Ex<17@4(s>9_T@9l$O#+ zN34e;Wa-$q%4W8Rx1La^-~*r65oXK1E#q=X6u)kf(%V)t{q4(c%2?%VhdPUvn4fcx zW8edvp7Hj}xwEt1*uGrjY430@gtiE;x!p=tlwz6U4M%SjW&C$!cl6$Ucjq8}XEs3X z_8AkNkdz)V%F8$T#EtYT;?H~tJ{MBk>1r}Y_I7#`&KNx!zoHv7Ev%WH^Hb6;~C;XUaRBtHFMLbkI_ z{cQd8G@tZ4vMTK8(xECpzi#tmmCSL+T0LL%m@wLb%+zVLz;zS5VJOc259{xwd%~ob zepK*yh}(o>zNexhZUeN%A%6$pSDvnnyKMNGZeM=FGMt%t1l00+(CG924f?J$gdLjV z$67=u)w7$FQ@LQfd$;fx>}^JNyEEM-sB;=2H@`f9u~RO5U2w{`-z^7HVLF6+A{G2+ zeEN}lpV&x^PppmnW3iq<;eC%jM%l~rpR$=9A4tjk*XQFyUe+l2N)GGnzdh@dp|UpU z7igKla7PHsK7_MDE`N68j`z+#A31@Ci(v_Rg#F^#ra!tZ=|gIh(0b@!8SyOmq=1!< z3|>{%e0__FdS`EKf!CV!>s62kVY4Xy%I77cmy6Jr|2~9_|2||8!~0er{kHI5KBuSS zc?~1^C;jyV5Wb%?@A_{or+V@C4SEB{8K8&hQQseps} zs2*^Be%L(4`o6Kh{y)gBgZAhYgouQs_ePG#{|tD&+);7)qrJKCytZ&5IZ0r=8yA8% zzFlG*GfIzzWV~bTcFe-~nr0Eap$wzYX{%J*EGh9L|Nk&v`)lv7_YNq(6I@$|(d*;u zs8~J?=JD^HH{i6@dlOUgE_p84>9b!g`)wb0=}JZEZE#zCtrzy6K008Jtt5_)WN)H0 zoE%AO#RdO;+91x6Ig-J_WlkH0aB&Fwn^jwpwk&k?)1Ln2z8>V~+zOP{pP|mV%+tO8;1{O}lRuwJa$qJpLvlefNOd@#KTp-{v&G z(mzMv*GOplm)0Jm$)I#Uy8+H204q~#|JzN39v^oY;Ts7R0cKJH2MRcY3QQ>6mEQciA=8A`h9e?ZbNeLS=)&{Z5bcc!h%U8c+ zVs%GdtBY5x?1^gwCPg;{b!SYP?j)Wfu1AeiD(lnPJVoc4erAN%$yTCcy~_xzkU7f! ziXZsm7Z+l!rG}=(9$e1Kk^Nm%L=cwpgQ`O71KcR}IOHf7MMCOuMZ5iBvVpVLjc=q) zTmL&CSXK!@rziSvz*`nRd(tK0k18a&i80()s80Br*1)X=WqSbVN=0A5_mlY;k&tAKn;cuiGb)$Ij8!k_yNUt~od|6G|vrURs#47(e}A?VVLr zT+y1XL+}K5E!={;Ly*EDxI4k!9fG?%6z;*@-95OwJHdmcE9pMxc8@#m?T0>({l06D zsx@k_@vk|*IXCp;-p-x}witgP3M{(znB<^qvFJuTUh0Zx?<^zE+v^lrAw^xKRRoMB zRFLP^;IU|d#QDnxD!>MCg+{aWvgKrMq zN}Y=;bWtPWtG>n+vUka1C%1RZIZgzT4{4z0PH>1&1>c(Uml<f@OG0VjKe#9_+p zzBlSIlp%S64S%PLH&cceYdrb*GTOw=ZWGLeqkDjRLQ*Y}Y3Wrw~-60L_ zsF24f4TgEw(1U|tE29%^o8R#7Lzpuu8jFz>mms;S5>S}E+)Af-gIjrh`kREybzm`H(QoUfg+c_ z(R+$CdZ-RF3HB%cSew#ut93bfYc;MQ!>In+0ZfSxERSlFxy^gk8dO^ z%sngIc-~Ow*JR!kFo@H^$RbZlbjep>y7BGC%=ZzYHIV!lsSNi5CAQsGA0)L^BF9Cb z@&N(zEpHcgMkAr}y&fn9#74kK@a{J;(c_Xb*|C+hD>&%7DTUX6%D%|05b8tOx;hp! zM1z0d9dx5HN*e^H2yro3GA1W%(MB>fBV&%UiX~S$la8fH^O?tuWJys|jg2!`Qc$@} zEj^s9aMY6Dnni9ew1lf49x$Vzcw#*&=nr{*6W%IEI3gNVvdY=5Dyfu6-ZWMPl*^s# zI7fEeXZUvCT2F>_^?}Wb`bPnRa|SF-_k1~0+Kzwm1OsOZsq_c`yr^piS1nj$c;IHH za3Ne)WnX4uBJcPxa%U!C-HGBmiwvbwyF9=bSKrUcXPXcmW zfqM{r^R3X~x27St#D>v61i@dtjX&6%lV~SbDf$EIHyZ^dGFaLum9~fo-hmCV`uZEA zr6qB_($Sn}zXo3|*Se-T-i(l=YT|$ueS+n4P;}Rr-R$ zxUaKWfhx#SolS+99hkV<6R%=%HK3;#0J3#87z=Ky**Bv}w-RRN%(Jdqm>I0zETrf2+jF(uHe-B%p#@&Hxu(lIUck9{*F)I)IzbgiHNs``$^yPu zlqEdiL?sbk+FD3qA-Mj!=Q%cL;~nAuL91dNLPKY5b1uZYR8Qz~iM7AR&E>*&WrO4x zpzwZVqLnhv%72CRk4LmOmXE=&phSx__l~N0g&O{R_*q5I?_>LbjOc?z_It;x1lygC zs7u$D^31BQok|w9u}T!3RUJcQ>Uaa^iOi9!UelbpJL*^ke#ReV+j4gBzWqGkjr4>X z1SjZqgeV;f?pl?GvGDOd1C3VboAlY?;2r{u9Vr}YJ@7t>rkPm7E@d!KkVrqJO}+cb zy|nmsfB3=Y^~06Bs)tvO%nYG1M6 z-roce8nE^k%@(%ok@aWFa~y?5`&f{*`Q=?hTp{23*_H@`U{ia>SCB+PTKjy*$z`(5 zBI4_BcE(&Wd|u8(;A)PM^Mx9(pM{jDx>xg%OwsO1zhtpjj+1xJL>izAZ&_XQKOy6O zc<4@3XIh4YJc+Q=Uu+uvVwx_mX@@u|^mYaRp+^Fr^)_Mj4>t#UK+<0W4}5Oi9ut1O zwBkuEET_86ps+|>p3KMMiwPOj%T0cK-aKKj%09H)#wbB`}dqzp`-O$k*mDK_zvT>s?U)RjijbwX8<6dO-u za8m}=d;Y}sED|u__eGnJP5(y@K0hew|Il(<66zTb0YO|FS^t3MDCp=BOpNsy{8ZD= zFVG`VY%No9kE5sLr-)_JS_Y(fE2@R{?t0cdsF$u8%`*qT zrY@)Q%ensuF6cx`Dom4*;`&x@gVfQ;heOT*pAKtk;9pjF;rD6f!&l$MHxe5ExFelO zUli27J7h>2;7KPx*M4LDA~KHoO%BHXqa-qddF0Vn97rtrDxK@&_7iL_oUF5^@rb0j3-Rq6^$-Wy;L@gtm1 zz;MfgH4glycSu7EMn5g#rSQO(NXI-laZOkb@cQ^s&jTr85ZbUgpMnh%b~qv_pH@uP z1IkfXGX(Ws$_1P|X|2$OG2vZe^dy`WIa|T_v9|Q?{0_f)xtv@=Cb0{=Bu-i#AI8N< zzUcSDDH+Q`?Ul7~)o#GmV~ISVr_js zymp{zHYlWKa)Bvng>kJm2E3?hckM%bf$gR{|^{o_9tiNfb=^2Yx}qcPkISYj~qeM0li3iFEZS{VoH zdRmrV)X7Q7d?QWojl;ZMdX`{yz>FJ%I+JFBIjg+{{3xs5a%jVimw`Pu?sEah)IKh0NmmVm!K4Yb(h5h<8h9CWt4I+A{tN3slL z(4gq;L=iw2%0seVF%hjo2mf+CtsrrtXL^^B!rMIEj8FZ7L=k~f>#Z)U@O$AR$4nkI zm2w^WH5cR?f*pE`mYKCM3cKaG{J0TAS-USR@Cf^6H#>Mh{h3P4&LJyv*u%M|f7MwcrPG{cp*T(CwKfE-r5HF|TMF zavDXR?HLx7_vRAC8a5KA18NF+@1;I=Ak66uJ1ajhrV`IRWOiWX{Wx5r$CP-DyYK4f z#0GjoR#LQ=^)PatsP_eg8RghDzaz$NZmgA_d!aLdFdx8Z#LlVA~+0 zoY(%SUcwHpS35x0_NbiL{rAknv5#ekzF6!LYs&5s?DG$kn>wvH-A~bJ33{i%h&>BH zd<;z$Z>|O&lHM%LSMMh@j%*dQu+XEdBX|8y`45E&RCPoyW5nl#@{y0M``z!pK*`1} z=u{JTLm+aGEOjud1yaC12A>9d9Y$mL0 zRKUCn^;@I&AC`Kv;?VEcsDXBKc{>)H&<)eLutrM|94UX5kg6BCG?YG~ws3$b1?%?l z+_$yJby5j{aB}D}(gtf`Tg8P~V59C1-9ql{y=gGPC1Rs4EFW88zv$zUt zMt}_lSxr9A-ahfl+}xVo81(0%69rp4UGR!;9Q~~t%46e}Hekcp&GN#HW=NLu@5c~h zsM~(sE5pgn?p#+YeRhUevSjf}f$7O7!KT_vTRL9yRc+rs3ux)_vqSZxy-9^zsj8d*xGyPx2Ii&Odrz3ua(Ugl}0g;IsB8=*nZSw5uw46E=~=1$f;X9Jb& z;24~$JlZ%`@ooII_x#9EMZwl*R!!AQ^cx+k^IG8G<)kX~<@{Ow@zD^92T|GKR*WZp zD&pJTUf7UWYYxdJ#?IX(Ikt%9Nq7#?bFUE8*)9JlKIsrmsg4{v>O4#S6Gw0eiBzkg z)n`^;3QC@^W{|6}TJfIMrKV4<3OH7UG29%xy#+FqP6*pg@uRkTu zXQiVB5Ke`RLQwlo8H(D@JP=@S-T8|3Ocg*BQP``$j2|p)Yi3jTcecC(6d{&O@`dNS zE83z|+adW^xk930i__LcI(JdIlvcvPWaK^$3w_mv9tRB>N>xM36ylCDhPBUprJjzi z=)&<^*+ZA8iVe=8-{Rzc4+t2mv2CChAD!*<;Qc+t%BJ4vgO3%3f(?@g>$B4!{!=Vt zM5{CO=>}h&X$=E0NrNjrmFkO30%bq+FSk4rNgg>x;nT}hvVot>d$oL6HOTHc_ro51 zPo6sXUTXb2QNI989STw9yW(+F(LvfKIk@rMV1(#svna*&8%2uU{tb5Z=|q$LqdLro zQH#C9uhL^lwWJ_{c0|3-mZAqC4F@K|mTSm?>$uJiXD;les9RywL|NIm?4S0lo+YN7 zyM>!JLWTzPbYfz}4!Q;HG6V*}-}}8KlxvUYO>KeW#VtPqPp&5r>V>QgNI6aeYRLuB z-BTvEaCnr|HXzZr?Nn~l^N{24ThwfxxU1gRh;!=*byEUHkTY@K@vZuFA0r2cGO*jii zdH&2G=KtE_%m4S?1h={gz5&bBj0TiFjWhpdIu4JH9y_jEhl)DhpcjJ86B|~?UcY|I z@>0`iIV|Yr`ZuCk>qf2ROBmhjdpu^pYL*XX*q; zlI~L3E8pOd5HIw9hFCs`H-j_G680$<%$D|NQSRz(dK%{>Rqj&;Z^K|;!JRk$G*Pt2 z=i~z&zL6h@abqycQ7UhX%^Nd0y3%~Y_G`ozwI!<$7)TP1s|5&&u@i4 zRkTZRA`L{O;;w8~y^~Wz=muDo2x8G0?|G$DOn5yQ4&<(aJCx(rlC8)GhRE(}FTCyR znXCs`pwuo0f|WhTvvCoq?7xTKR}M`oNhP~Pp8GRD`z`GLux|m6RGhe4>gxT}Ri5P| zUc^sHhr8Mf%PwOy1r&v(hvD%xA>ShjnI=~WDb>*Ii;NSO(Rvd4w)lR)VIfj*WogaE z1K7;@KvkfAZ1X}h7Kh&Y{V@~{1Zru)=s#koZc}iG?K|O)C_9D+<@^-SLmJwIk^h4w+Vu>KW@WiwCiMq@|>sJuX zphW1FF#htz-Z^-(ijUQY`I$?<&m}>XO?}OA7e~G~peYf+P1-6`&| z_bZaEpVN-$R04OYSmPYGdCJ#cQBhdX#13cV$<+${#3fLI(>3}gbhN3@*TS0vf`{tp zWxIv>YKWnt2N&%a?s&f*JxuqZcM84141p_SFNy@957O6^33z?V0}8>9vZ^u6qJ0+5 zf)~8xvPvu4SWT+SZ{oFPt8k%(s9{+elvjryzIWS7YYM&|g7Fcj`hv#rCZ2O7cSM&Y z4Ea!hgxC0#XjV=Tvq>T{j0)wpc42)k!)Kl)MA0`vPJK10I8f7{{I2QAHsA!(_Spo4 zYCMOC3+@n;Gn3j3s(|NiW%)QsOhJL4B)chs=Wt}+;qp(tawc$W!Vbl`Rm&%al{B=; zDV?55Up0^wPwsM{=Y7pk^lbHimOdMP2?J(WZM)s;1-)R7W75!4D{Qys1O4i1FwHOjZH_mH8MUD4>H2A-${D6cU2k+J?^WG7 zE!DvC&tJ0f$`6e zk55jPHLcgEJ95JE(xRE+9C$hE@{2Dtp## zqx2}-XeoX(wLqEsz1b>!4K%mT)I1o3ko?sYJ)O=4OKfK5 zJGU41WGSU!z6XDang!QtOYjn6{==>i19S0KWU`~Ai5Pz5{G?)9vsds3IM6{tC9e%@~v9uPSHFj{7k37fKSZW?3Lzi@_?{FFK z8}N$nvxGAgoPrj5(G9YYnl;ix%cZ4A!5cg#*yO`(!R4ay(0IPTJY8^LszFd$Op3D2 zmxL;fBOzTfpCUf@hwUv!7N7sw!KGFiROkxl1*?ndHwo3F6ritkOOG`A0CEQrk z(lE`<$=O<<_{}$3DFHdq+HR7Ul0k}y+LVtAAoW)v`w&x@EAh2U6%@Tob7(JO1WWbB z_7OHpB(#qm#I5BQ%&TI1u7Yq2AKYY}X|uG%PEaQjoO89R!<8@7>2UQi;P4wMIgy;0 zs`y>#{>y;H+%e=$6v4iKj$^C0b@#7bLRb^7$B1sLuoD7sJ4Rkx#TSv~l{{7nS-JE3 z_|*i)yL6>t)SlsmiH~@`dd(aMWJ+0KIsr=DN#7D++v)hXEEGb{>Ym)EITh59Q#0mB zS%GuQ(~3FSY(+-qyE*MFUy;mTNMi~)}v)Ft$MS{@ls<_gIXYF@c#^g zNnG~dl>r=pb83$vpN$`8ta0DR`;*to(c@;c#s3XTj7cZcf2ayA0#TY+28&+2gyI+=r4 zA2MKy@3Y}#-;ury2JdLfk&e!0zQe&s!oEj0->38vR;Wn9y&&U@f!6EVfo|U^nJV$l+(! zRE^cJYd%yCcRGS`DSJKv+(ObXF{d4=8`~&6=~B~2Oh^z}NYzYLJ*A8>p9FmswHf>t zXi(k+df?HO?8mx;*MDqIR2Nz=Zng$w`msyVmu$)w?kqX{fk`vI*zmAV?2@(BMM>H)A zZBGJH+5Pcu7l&jW8D+Fs2>pVQH=0w!0$)Ajj32k60Q0K@`JcTHcUxL?nL1;?3H~N) zxhq!k_z$fQ>^Q5KgmKQBE2L$ISE0wte^Q%!`WAPWUC;knQQv0=0(lOw>W|!IZ5?2; zyv{~_xY z0~}SR&G)j#&hHh~^QYVh0CDCXB@A7ECMPQ>m`xBT~B zA{g5i%{=}uY=Vn#Ah=I56vOoxP=__Nks8wQoHP%(PJbXch@lhj&2A!Vk(0zYE3WLW zWyTu*wPSt8T}=K#ZdT3U_$YnhMXV7nixqpf<2;uc>r_@#`70I4+nBO4$5;j&4F5r- zK`O5+U%NFs6IRM6Srs6cJvBi5x?W0GNbdknp(st=*2cf_8fr(7$DdRu8nDnt*!F$U zXd44r9Zzo{D7*)UqW}Z`vT@xs%zapqk97co`=?=7os)TE{-NOol=UJ(ZM8nWaT8|xC@prRJkF&FaT?;Gh$YtbuKuGl1e0IoRbi+ErVwHDczfO6> za$W@=+yQy?|7Qk7R0ff74$qMiXv4T>Sw^kGwnhx>0A^4T!Ds|i73Px2>1=>WHMyOL zdPO!|ZiAI;V>o=6#6lu*2UR4gDy_ag&Ud*RVq7Vzf%w-h|6UbCJ8^}8?B{IG6EBx7 zA_OEX*XG|oKa7G1qM>f4+;0FrP9+<~OOr{-0f1625K>jCy*7{UwB<(q*ZKhqmIfz* zaSPB(H`8)wzwgQA7FP|{BwTO1+|i1qGWI|`2XI*|gco9_c3We75}xPe(CuN9ia;(O z7Ibdx%D$C#A_x*P11APVpaT%kEfC6}B#nJ-Z6Ii7vLck%%#Ck#28ym9{iE=fnHS=r zVwXs;4-r4#HvXQi9i8aLHVGV_W=MNKYpb_y?wmU-a#$LsS$Uh^inI!oy;HEUEEW>E zaZXOoJ7}PBNoT2*u&Agtc$Z(?E81E5X+%iZfjnCKiM2WUroZ|?T4JLVaT=q`%)9iDcwl?gaPL$Prq|)DR$o9At)NSg)@$F8amhDL9 zd@rUF7Wl(Yg^11&Gd(uM*S}jJ+7!e0+KqwS61+;t5AsBAtDL)$)cH2UT;m@cg_WKd ztYn9$lQisLXlRy8teyZfu_9ki8(3SuK@tHz8{{WaYTE<{l+3PQdxB7f+6!l`xFPCD zLDO~~jNn`+zY8dsqHawgrIGN`JI)WSbOQT2Hp?AyGXHg(Rl;{Xk=WcDviR*M{7fqk z(GCuSn;V@~RiWW?k&XlnhVjV*^DZ6;sDE#dj*VT~8WC{;b5LZN0_5i0=F%+Ck?pC3 zJa%Y77zIC}r?dPf|HW(UJ?XVZamB0PtcP9(is zy~hlT$Yrq~7tL6mQ`QRf+FvPR1sBQ~cBRKAxVxzACJsxOxC_%x&Q6lB}# z&?j^OHAjb21_OPwC|d<(dd1jxe;jX3%tF(Av9pYnu8MfWm}!BXyC5a5Tq3UO*b`^4 zLwy#Qsx?i;DX&5it+q%9D|rJoYEPoqw4pmdahxa4jrCWor(vS%cpz1+a_?Ln zYt0-DUYAeNA%6->wj(6*$P?SRva=Fa5Q=jng9WAl%^Ys9T0mPo<2cR(+}6R$r{VGT ze`;SCskDkLM({H3j7A8}MKdo3nWSQDda^gyqajU2KRd$@mKRQKr9ne5fu0r)J;r8Y zDc)CCq*TF8`CBrz(*wV7(6^iqi0Gik^L`i6jn|^emuy`V1fTsgz^sDxG;RT9v5V(O zM}gH6A$xHw8Thjq*lcf|cGlzKMSSROFvSj^fHL>rQVLYcJ*%g??i}TeJE!2^AAVX`2OhNzB}P z8Cd6G=}tbOaw>~TN!L?Crg4#`jjWDLr_G$dV<1m*wY6Zq_1?Qxp;53hbCLu;jc!qG z_Iu)QUOH&->W!=!u@5t#kqk~_qF(g{@c;$5mmM}Z|yEfBWokqm^>bi^UfiLkJ zqrushlbShihS6`wa7Abl*Dqh{tRz-aD~_wVI27@iU>}y8NTJF$hmppA$lH*cGya-i zzl;X(*@nC45T9t7yWEG>*3U=1M?qCcd19ko_1$J<5?n&%5V7LXNtYH7UV}Fd0L*Mu z2m8hnfkJR{_xcYj1n)|%{dMe^ysTh*OK!<`ShQek8L=(5367Anb5J7dnMJyU8gY1> zsQDnNNDL1o*r;d)Z52(#r3F*)I7px-DL30n!3F7Ys|dcKI#3$&^5v2!`Iuu&?8vU{g^$c zf%0N(l5TCNV8Qc#ngHCs){s~n*O%%K(%`ZtxFL15)nr)XIh`s|pOZxiF4gbPX-Pc+ z0xrqW`fq#hmZS+k$2HX+K_Pj&L;ZScHopimmo6gvan*y5%^Fwj%UFv5XrHe0Xmi6T zx%A@WT>J>`I=njct#9k1W3CNc?AL%pb_uFrk!~-Qix_=T_R5S6RBXwcBnqPWFNQLQ zS#Z=)xrWiUiE*W6*ULAIJ{Cj-_`zOSvMmELeo0{9=Eu^d=U+4kdMiSiczWYHEcl%Z zGkx;)Tn(m>_XjkWsHh6~f?KA4ds@Djx{{IFN^h<~U literal 0 HcmV?d00001 diff --git a/request_handler.c b/request_handler.c index cee8107..8e4c313 100644 --- a/request_handler.c +++ b/request_handler.c @@ -3,41 +3,19 @@ void parse_http_request(char* request, int length, struct http_request* req); void debug_print_request(char* request); -void handle_request(char* request, int length, char** response, - size_t* response_length) { +void handle_request(char* request, int length, http_response* response) { // Terminate request with EOF so strtok stops at end of string request[length] = EOF; - // printf("Request ---------\n"); - // printf("%s\n---------\n", request); - - // debug_print_request(request); - - // printf("parsing request ---------\n"); // Parse request into struct http_request* req = create_http_request(); parse_http_request(request, length, req); - // print_http_request(req); - // printf("---------\n"); - // request_info_print(req); - // free_http_request(req); // Switch statement to handle different request types switch (req->method) { case GET: // Build response - http_response* res = create_http_response(); - response_handle_get(req, res); - // Convert response to string - char* response_string = response_to_string(res); - // Copy string to response - char* responsestr = (char*)malloc(strlen(response_string) + 1); - strcpy(responsestr, response_string); - *response = responsestr; - // Set response length - *response_length = strlen(response_string); - // Free response - free_http_response(res); + response_handle_get(req, response); break; case POST: diff --git a/request_handler.h b/request_handler.h index df9d2e1..d667602 100644 --- a/request_handler.h +++ b/request_handler.h @@ -8,7 +8,6 @@ #include "http_stuff.h" #include "response_builder.h" -void handle_request(char* request, int length, char** response, - size_t* response_length); +void handle_request(char* request, int length, http_response* response); #endif \ No newline at end of file diff --git a/response_builder.c b/response_builder.c index ce8f843..5b7ae30 100644 --- a/response_builder.c +++ b/response_builder.c @@ -8,42 +8,28 @@ void response_handle_get(http_request* req, http_response* res) { strcat(file_path, req->url); printf("%s\n", file_path); - serve_404(res); - return; - // Determine the file type char* ptr = file_path + strlen(file_path) - 1; - size_t etc_len = 0; while (*ptr != '.') { - etc_len++; ptr--; } - char* etc = (char*)malloc(etc_len + 1); - strncpy(etc, ptr, etc_len); - etc[etc_len] = '\0'; - printf("%s\n", etc); - if (strcmp(etc, ".html") == 0) { + if (strcmp(ptr, ".html") == 0) { response_build_static_file(file_path, HTML, OK, res); - } else if (strcmp(etc, ".jpg") == 0) { + } else if (strcmp(ptr, ".jpg") == 0) { serve_404(res); return; - } else if (strcmp(etc, ".png") == 0) { + } else if (strcmp(ptr, ".png") == 0) { + response_build_static_file(file_path, PNG, OK, res); + } else if (strcmp(ptr, ".css") == 0) { serve_404(res); return; - } else if (strcmp(etc, ".css") == 0) { - serve_404(res); - return; - } else if (strcmp(etc, ".js") == 0) { + } else if (strcmp(ptr, ".js") == 0) { serve_404(res); return; } else { serve_404(res); return; } - - // Serve 404 if file not found or file type not supported (html, jpg, png - // only) - // Serve the file } void response_build_static_file(char* file_path, content_type content_type, @@ -145,6 +131,15 @@ void response_build_static_file(char* file_path, content_type content_type, } // Set content type string res->content_type = content_type_str; + + // Add header for close connection + header_kv* close_connection = (header_kv*)malloc(sizeof(header_kv)); + close_connection->key = (char*)malloc(strlen("Connection") + 1); + close_connection->value = (char*)malloc(strlen("close") + 1); + strcpy(close_connection->key, "Connection"); + strcpy(close_connection->value, "close"); + res->headers = close_connection; + res->num_headers = 1; } void serve_404(http_response* res) {