From 00abdb31f027713600bf88132354155683ae6050 Mon Sep 17 00:00:00 2001 From: Doczom Date: Sun, 10 Mar 2024 00:59:52 +0500 Subject: [PATCH] Update to 0.2.2 version Added new features: - begin_send_response - finish_send_response The close_server function has been updated and support for many flags for creating a response has been added Added a "chunked" type transmission New test modules have been added: - a module for server management - a module for test chunked transmission --- bin/httpd | Bin 4853 -> 5693 bytes bin/httpd.ini | 2 + bin/modules/srv_control.obj | Bin 0 -> 1032 bytes bin/modules/test_unit.obj | Bin 1759 -> 1767 bytes bin/modules/test_unit4.obj | Bin 692 -> 700 bytes bin/modules/test_unit5.obj | Bin 0 -> 702 bytes bin/modules/test_unit_2.obj | Bin 1819 -> 1830 bytes example/srv_control.asm | 148 ++++++++++++ example/test_unit4.asm | 2 +- example/test_unit5.asm | 84 +++++++ example/test_unit_2.asm | 5 +- httpd.asm | 27 ++- httpd_lib.inc | 53 ++++- module_api.inc | 24 +- readme.md | 2 +- settings.inc | 3 + sys_func.inc | 442 +++++++++++++++++++++++++++--------- 17 files changed, 658 insertions(+), 134 deletions(-) create mode 100644 bin/modules/srv_control.obj create mode 100644 bin/modules/test_unit5.obj create mode 100644 example/srv_control.asm create mode 100644 example/test_unit5.asm diff --git a/bin/httpd b/bin/httpd index b1b99438708a77d6b8b9f115baa2bc4873163662..cb5d05354800afac97f286de8f68cc7948c49bad 100644 GIT binary patch delta 2318 zcmZ`)eM}Tr5P#f9Ij(oy3J0Ew^pKNatiUPwea1r$tC25-18aq#9xjMLVYk7=<{-;8 z-EJ}Hrq;$ZDMFf5)7IAhAu*nO=>-!_B{5CYj}$HKHlkEOL6K}{mOI5ZeaXC;osZv} zH*enCM@uii9-rgNEpip6*~17Syq=KzWi^E@YaF>J*kY)=;$8zt;qE54?6 zdxP5+a;&$8xSj}g4rL$QP-JDo)jMt{XWpBDGC&mwtLAzvAZvnh9LShG>QTm;F+tfH z)F*>}b5LFYa#Kj=b1VhY^fOuZb$d-Mhar@AnfZW_LkX;5yz{*Etl-j}yJ&>Nt2hUN z%Ay9pV;&)0aR4&j8A3DopHZM(5K<~B8TE8P@Am8!||B$ zuzlUE#y7}pYJMuI2{Cb3!P=TPGnw%toKZgiy?t;pj7KmgXamw6Z>Js7%E3pp( z!mZHe4gR|?rKnVMx&LcaT1aAWH&6q@#J1*51i}t^Jaqx5W<_~*WktZLd&eW5)U5W# zOv`e<%$lXMAe78D8GfFIPo;%tRgk}CGIRDgmT@E6K$b1cs5k1bX>4gPI)m22a@ZVK zo?>Tddo?7Wb;J^^6yY3uK_X0aJMw(Fj*|0r&JuyZuEqjdXV9&WzcCvFz7UOS9NY-S z|4~J%C^x-3h7dX*rXo2;7b70mF7jfnnl{?f8XlY}fPfw&&N{9?Y#aMCKf(1=6#;Dy zs8pmXpMGmjyaD9*`YSr}z*wcH%l~Dn=y0I{ZX@&xT@Er`J;y}{vaj3Z^X`HT7I&f3 z6?C$9kA0QbJc=UkC|^iOnY0ExLO34K(CmM3*yTY8v?Ii|t#T^w@WewreGgiYegk4) z(-bg!cOOmQtfhe`vh0E+TCPKt1S8g#*9A6fQ0TzPH^8cSrv`2*V>7ol#vp2ElUF9} zlYsVZ0LLM~GUDhf3%sZ(E9I}b=`Udw$^TfEOMTr;tni8g76f)ng|O_sY&iq{=>c$+ zW4d4l*V}wH)qWXdKHJdVqi|h7i$(z`pheS3MM7gcP%lN`h?H)N2<~cVN^A>HUfvAW z7e|foYJu4 zrF~%SE0*>Eb4x`q2ejz+g<0I7i}T`pE**Jl_u%m+7--Fr|&f!c4br`es z;(UO*bO5Fso1vJ0at?=L_?0ew6>u^pq3naf@cPH%-?~LfbC&sd7SPmk699OPjUV=t zCPLg&(xhmQSgAVpSoB0J(PLW>W*J;W@pwem!jCZOs7*(h2zdH+k`KP+beq)h=)!13 zqDrsy@ehKre4!X;h*!BL#Epi$sO#fOsalGl0`B5`|4fwlsiDF0e~+1%Y)n)&kBK?P z1XaqoSZ9n^Z5k8Xj7i(S8-ruPVv?#o^qDBA&T2`8x?<@QV2Xu44Q4ug);Rny6hNOq zH4ASo#N2#%A~Hr*886O{Tot>ewx-6jpQ)^^S#RB6UEAQX;t4r%j3CddeyendT>~N=Y;73+u~k8Y(>XD_k}EYY$Y`90UlOtvTd5VAPA-BOBG= zC0;UF#o@@simWxAQut@4666=AOP1K$FC1}d*~4Mh9{@evL= delta 1637 zcmZWpdrVtZ7(ZNIg%)~STA%|FMlmd7K*!i(CWZmUFb69e6wt_H5xi7<#I@=oTT41j zt~X1_Zeoo7;jn~1mbj?<2eLSMWsP%~t!|kH{?KUfMi#foqtJ~Vf9JMlQ%~}p$M^ld z?>pyvoUcpPit-xmO|ABpa$6iB-#lp1--qgxrfyr3s!k|D*&%9v!=h+Np7z^>xXIWjb}fK8BlwYT@pU`;~NuAYJZ zzF>{!?cNvsGlSv{sm_{h3k^@Xwc*Nf+?p5~mhZ|-NqcL1wqBkkvH&t=l5m zi2wkhZfkBcEm!Jd0G(~hK|LlVgme2#U7a(!=mVEm&2l(>1{DZ1aY0zX8o zWT382@rqM;4Q`Z_O-ehF)J!P}W|04=NvHDZeM*<>sfrgwK&klzWQ!tUqoa&BAdq6WhL3Y$)j=iVkzPyl9yz>BrkCM#HdwR|^Js~#n zPKCz}aBh~Gs+yIbB64YJfp;sS@^Zu~3*I4a#3f65e=x!SH1VuDmCqraZBxdvIF)ml zgNY1w3W1!Rs6%8fX)(=LPZYDgPu&Zw1C_Zjv#THe0KCZ}==fkUagxLJln6qPd%T5` z_7b1K+C|_nDVc~JtNV_?CU7oZV6{gp*+D6d$#&C9R$DRdz8E)m0=XxbUdA+Ejga0G zHt`oIA49zSTMT=9gHknO^VR-4bqX%m{9F*d z0_(`|Lo899PnhCjx+*-#gi-cc#y%KjS1`7-4gZ%;a+sxRi(`k$Dw!=g@*rO!dkpW! zmzUb)dxk1?EjNCouHPBk)iuHwUTnzdj%%Mo8{P!{3JQag@$_6!1*ise1k?jcg=>~r zC7uxWb4-EQ7#SJpKi2 zXb4E~>dVQP58z3mG%afJU@u-gdD26%2c;lX3hOhw?buJ?urvFc=lMVXd11E{i^JmT z4&6!s;DhZ!EUQ~83ppB2!~itJukmPp3SR`2Vpda`8im5qLY<5KNn`{mj21!ZkMt|E zZI&6lUjWSd^4dNo+EdB(?f7ojfHXiLoyE*bpApohTbnDt+0e87mrM5o@b@rudhIEe zboK7@`5PMp5ZSfwX41>!!0HBHy%I=DXm*XwA-ysWAwsBm<^;Nw<#IN zF^@A|h%a9G<6XOyNlpjSIh<@HfjM<*L#?5~M6E_Wk1&UL)V)Pr(ok*nCT&og5z`}0 z*D=hh$*7hk6E^Yfy6xPyQI7S*P(4zm2q>m5)#R$9-6;^+7%7lTj?G-hB2Cq%7IAdq znT@7J&l`+2H95y6vPuk>>iOYu+(^EBCN#~HuniZ=%xRKxxF?Yq0<4>JS*sWU7W@n( diff --git a/bin/modules/test_unit4.obj b/bin/modules/test_unit4.obj index 190a0e3b8e9c7d507bb84f4ca2cc83371715dcb3..7773ac7641b605e35f1ebb069620795206c47b6b 100644 GIT binary patch delta 44 zcmdnOx`&n1hmnb)e(#&qriq-&jBh6D%5&afU|*KH}U|U*0R3eQjsO4v diff --git a/bin/modules/test_unit5.obj b/bin/modules/test_unit5.obj new file mode 100644 index 0000000000000000000000000000000000000000..5367c5d6dbbf761f61c425130431fb7110a9f287 GIT binary patch literal 702 zcmeZaWMZh_`zE!8iGhKc0R&nY_0n<@OTcUh(FLSZfcO?8gwGA66c_>=^imQ_5+Ooh z@(qxD2gDvgvp|3ih#eRL4j3K?3-2yb;c2vE0Gd!Lw7&)@(e1}_@Fmmdr8_`|#>XAv zV1OvfSO*jc`!Bi!DBOCW#5JJvcostzL->EuJ3x^v?hGIa;%x!(WHLZ*f$@Yh)Db+O z-~%AS(T~)7DC7w1LaclQXs++ zKvO^f6b>L;3V^sBh(Tb&gp87sf|U5oyvz~?D7!eds0_wV&dD!Mg(#&XDG0O+6cKC; zrf`-!oaF~+g~C}ea8@#$l?7)N!dVq?RvnyW1!vg-S)e#&V{n3txxvM};9?*bK-9TL f1o#Jq1T( zMKGfSC>!=))Bz~hdVs%0fATjb6-KVj(#*FR8TU^9&N6MX11rbmUe*utJwPQu#K6X| P2+mpyXKk50hpip}b}}C2 delta 122 zcmZ3+H=B>shmnb)_uGlohZ8xaIrlO#Fr+XrF!WB;mFLU>auk^v7?y4fQ JPF~Jd4*;d59fbe@ diff --git a/example/srv_control.asm b/example/srv_control.asm new file mode 100644 index 0000000..e930ed0 --- /dev/null +++ b/example/srv_control.asm @@ -0,0 +1,148 @@ +; test api 0.1.0 - get cmd path and get context unit +format MS COFF ;<- this is lib format +public @EXPORT as 'EXPORTS' + +NO_DEBUG_INPUT = 0 +include "macros.inc" +purge mov,add,sub +include "proc32.inc" + +include '../module_api.inc' + +section '.flat' code readable align 16 + +unit_init: + xor eax, eax + push esi edi + mov esi, [esp + 4*2 + 4] + + cmp dword[esi + IMPORT_DATA.version], API_VERSION + jne .exit + + mov edi, IMPORT + mov ecx, [esi + IMPORT_DATA.sizeof] + shr ecx, 2 ; div 4 + rep movsd + + ; create unit context + invoke IMPORT.Alloc, 4096 ; for cmd path + test eax, eax + jz .exit + + mov esi, [esp + 4*2 + 8] + mov edi, eax + test esi, esi + jz .exit + pushfd + cld +@@: + movsb + cmp byte[esi - 1], 0 + jnz @b + + mov esi, [esp + 4*3 + 8] + mov edi, text_board.token + movsd + movsw + + popfd + ;unit init successful +.exit: + pop edi esi + ret 8 + + +server_entry: + push esi edi + mov esi, [esp + 4*2 + 4] ; request context + + mov edi, [esp + 4*2 + 8] ; unit context + cmp dword[edi], 0 + je .err_403 + + ; check arg "token" + + invoke IMPORT.find_uri_arg, esi, key_token + test eax, eax + jz .err_403 + mov ecx, esi + mov esi, eax + + cmpsd + jne .err_403_1 + cmpsw + jne .err_403_1 + cmpsb + jne .err_403_1 + cmp byte[edi - 1], 0 + jne .err_403_1 + mov esi, ecx + ; check command + + invoke IMPORT.find_uri_arg, esi, key_cmd + test eax, eax + jz .no_shutdown + + cmp word[eax], 'S' + jnz .no_shutdown + + invoke IMPORT.close_server +.no_shutdown: + + invoke IMPORT.create_resp, esi, 0 + test eax, eax + jz .exit + + push eax + invoke IMPORT.send_resp, eax, text_board, text_board.size + invoke IMPORT.destruct_resp +.exit: + pop edi esi + ret 8 +.err_403_1: + mov esi, ecx +.err_403: + invoke IMPORT.create_resp, esi, FLAG_NO_CACHE_CONTROL\ + + FLAG_NO_CONTENT_ENCODING + test eax, eax + jz .exit + + mov edi, eax + invoke IMPORT.set_http_status, edi, dword '403' + invoke IMPORT.send_resp, edi, text403, text403.length + invoke IMPORT.destruct_resp, edi + jmp .exit + + +server_close: + mov ecx, [esp + 4] + invoke IMPORT.Free, ecx + ret 4 + + +section '.data' data readable writable align 16 + +key_token: + db 'token', 0 +key_cmd: + db 'cmd',0 + +text403: + db 'Access to server management is prohibited.',\ + ' An unknown token has been entered' +.length = $ - text403 + +text_board: + db '

Control panel of simple-httpd

Stop Server' +.size = $ - text_board + +@EXPORT: +export \ + unit_init, 'httpd_init', \ + server_entry, 'httpd_serv',\ + server_close, 'httpd_close' + + +IMPORT IMPORT_DATA \ No newline at end of file diff --git a/example/test_unit4.asm b/example/test_unit4.asm index e55cb60..43b6112 100644 --- a/example/test_unit4.asm +++ b/example/test_unit4.asm @@ -88,7 +88,7 @@ section '.data' data readable writable align 16 text_no_cmd: db 'For this unit in config not set arguments' -.size = $ - $$ +.size = $ - text_no_cmd @EXPORT: export \ diff --git a/example/test_unit5.asm b/example/test_unit5.asm new file mode 100644 index 0000000..ba73eb0 --- /dev/null +++ b/example/test_unit5.asm @@ -0,0 +1,84 @@ +; test api 0.1.0 - get cmd path and get context unit +format MS COFF ;<- this is lib format +public @EXPORT as 'EXPORTS' + +NO_DEBUG_INPUT = 0 +include "macros.inc" +purge mov,add,sub +include "proc32.inc" + +include '../module_api.inc' + +section '.flat' code readable align 16 + +unit_init: + xor eax, eax + push esi edi + mov esi, [esp + 4*2 + 4] + + cmp dword[esi + IMPORT_DATA.version], API_VERSION + jne .exit + + mov edi, IMPORT + mov ecx, [esi + IMPORT_DATA.sizeof] + shr ecx, 2 ; div 4 + rep movsd + + mov eax, 1 ;no zero return - module init successful +.exit: + pop edi esi + ret 8 + + +server_entry: + push esi edi + mov esi, [esp + 4*2 + 4] ; request context + + invoke IMPORT.create_resp, esi, FLAG_TRANSFER_CHUNKED\ + + FLAG_NO_CONTENT_LENGTH\ + + FLAG_NO_SERVER_HEADER\ + + FLAG_NO_CONTENT_ENCODING\ + + FLAG_NO_CONNECTION\ + + FLAG_NO_CACHE_CONTROL + test eax, eax + jz .exit + + push eax + mov edi, eax + invoke IMPORT.begin_send_resp, edi, 0, 0 + + invoke IMPORT.send_resp, edi, text_no_cmd, text_no_cmd.size + invoke IMPORT.send_resp, edi, text_no_cmd2, text_no_cmd2.size + invoke IMPORT.send_resp, edi, text_no_cmd3, text_no_cmd3.size + + invoke IMPORT.finish_send_resp, edi + invoke IMPORT.destruct_resp +.exit: + pop edi esi + ret 8 + +server_close: + + ret 4 + + +section '.data' data readable writable align 16 + +text_no_cmd: + db 'chunk 1
' +.size = $ - text_no_cmd +text_no_cmd2: + db 'chunk 2 - new size chunk
' +.size = $ - text_no_cmd2 +text_no_cmd3: + db 'chunk 3 - end chunk' +.size = $ - text_no_cmd3 + +@EXPORT: +export \ + unit_init, 'httpd_init', \ + server_entry, 'httpd_serv',\ + server_close, 'httpd_close' + + +IMPORT IMPORT_DATA \ No newline at end of file diff --git a/example/test_unit_2.asm b/example/test_unit_2.asm index cc21380..372ae78 100644 --- a/example/test_unit_2.asm +++ b/example/test_unit_2.asm @@ -138,7 +138,7 @@ server_entry: .send_data: ; eax - ptr to buffer mov edi, eax board_input 'create_resp' - invoke IMPORT.create_resp, esi, 0 + invoke IMPORT.create_resp, esi, FLAG_KEEP_ALIVE test eax, eax jz .exit @@ -153,7 +153,8 @@ server_entry: .err_404: ; send resp 404 board_input 'err404' - invoke IMPORT.create_resp, esi, 0 + invoke IMPORT.create_resp, esi, FLAG_NO_CACHE_CONTROL\ + + FLAG_NO_CONTENT_ENCODING test eax, eax jz .exit diff --git a/httpd.asm b/httpd.asm index d5a0f3c..cdaa59e 100644 --- a/httpd.asm +++ b/httpd.asm @@ -1,10 +1,10 @@ ;*****************************************************************************; -; Copyright (C) 2023, Mikhail Frolov aka Doczom . All rights reserved. ; +; Copyright (C) 2023-2024, Mikhail Frolov aka Doczom . All rights reserved. ; ; Distributed under terms of the 3-Clause BSD License. ; ; ; ; httpd - Simple http server for Kolibri OS. ; ; ; -; Version 0.1.0, 10 December 2023 ; +; Version 0.2.2, 10 March 2024 ; ; ; ;*****************************************************************************; @@ -36,10 +36,12 @@ START: test eax, eax jnz .err_settings - mov ecx, PATH - cmp byte[ecx],0 - jnz @f mov ecx, default_ini_path + cmp byte[PATH],0 + jz @f + + mov ecx, PATH + @@: ; get settings call load_settings ; ecx -> string to config file @@ -70,14 +72,21 @@ START: jz .listen_err .mainloop: - mcall 23, 100 ; get event to network stack + cmp dword[srv_shutdown], 1 + jz .shutdown + + mcall 23, 100 ; get event to network stack test eax, eax jz .mainloop + cmp dword[srv_stop], 1 + jz .mainloop + push dword thread_connect call CreateThread ; not save PID jmp .mainloop +.shutdown: .listen_err: .bind_err: push dword[srv_socket] @@ -237,6 +246,7 @@ default_ini_path: db 'httpd.ini',0 ini_section_units: db 'MODULES',0 ini_section_main: db 'MAIN', 0 +ini_section_tls db 'TLS',0 ini_key_ip db 'ip',0 ini_key_port db 'port',0 @@ -285,6 +295,8 @@ EXPORT_DATA: ; in modules for this table using struct IMPORT_DATA dd find_uri_arg dd find_header dd close_server + dd begin_send_resp + dd finish_send_resp dd base_response dd GLOBAL_DATA @@ -293,7 +305,8 @@ EXPORT_DATA: ; in modules for this table using struct IMPORT_DATA ; DATA ;UDATA - +srv_stop: rd 1 ; set 1 for skip new connections +srv_shutdown: rd 1 ; set 1 for ending working server srv_backlog: rd 1 ; maximum number of simultaneous open connections srv_socket: rd 1 diff --git a/httpd_lib.inc b/httpd_lib.inc index e5f17d9..ad97635 100644 --- a/httpd_lib.inc +++ b/httpd_lib.inc @@ -82,16 +82,52 @@ ; db 13, 10 ;.size = $ - http_err_response -default_http_version: db 'HTTP/1.1 ' +default_http_version: + db 'HTTP/1.1 ' .length = $ - default_http_version +default_http_connection: + db 'Connection: ' +.value = $ - default_http_connection + db 'close ', 13, 10 ; or keep-alive +.length = $ - default_http_connection + +default_http_cont_encod: + db 'Content-Encoding: identity', 13, 10 +.length = $ - default_http_cont_encod + +default_http_cont_type: + db 'Content-type: text/html', 13, 10 +.length = $ - default_http_cont_type + +default_http_cache_ctl: + db 'Cache-Control: no-cache', 13, 10 +.length = $ - default_http_cache_ctl + +default_http_cont_len: + db 'Content-length: ' + db '0000000000000000000000', 13, 10 +.length = $ - default_http_cont_len + +default_http_header_server: + db 'Server: simple-httpd/0.3.0', 13, 10 +.length = $ - default_http_header_server + +http_header_transfer_chunked: + db 'Transfer-Encoding: chunked', 13, 10 +.length = $ - http_header_transfer_chunked + +;default_http_date_header: +; db 'Date: ' +;.date: db 'Sun, 30 Oct 2022 09:29:13 GMT',13, 10 +;.length = $ - default_http_date_header + + http_response_err_501: db 'HTTP/1.1 ' db '501 ',13, 10 db 'Error parsing your request message. The version is not supported or another error.' - db 'Server: simple-httpd/0.0.1', 13, 10 - ;db 'Content-length: 91', 13, 10 - ;db 'Content-type: text/plain', 13, 10; + db 'Server: simple-httpd/0.3.0', 13, 10 db 'Connection: close', 13, 10 db 13, 10 .size = $ - http_response_err_501 @@ -99,7 +135,7 @@ http_response_err_501: http_response_err_404: db 'HTTP/1.1 ' db '404 ',13, 10 - db 'Server: simple-httpd/0.0.1', 13, 10 + db 'Server: simple-httpd/0.3.0', 13, 10 db 'Content-length: 45', 13, 10 db 'Content-type: text/plain', 13, 10; db 'Connection: close', 13, 10 @@ -110,7 +146,7 @@ http_response_err_404: http_response_options: db 'HTTP/1.1 ' db '204 ',13, 10 - db 'Server: simple-httpd/0.0.1', 13, 10 + db 'Server: simple-httpd/0.3.0', 13, 10 db 'Allow: OPTIONS, GET, POST', 13, 10 db 'Connection: close', 13, 10 db 13, 10 @@ -124,7 +160,7 @@ response: db 'HTTP/1.1 ' .code = $ - response db '000 ',13, 10 - db 'Server: simple-httpd/0.0.1', 13, 10 + db 'Server: simple-httpd/0.3.0', 13, 10 db 'Cache-Control: no-cache', 13, 10 db 'Content-Encoding: ' .content_encod = $ - response @@ -179,3 +215,6 @@ STD_MIME_TYPE_ARR: _DIV_10_: dd 10 _DIV_100_: dd 100 _DIV_1000_: dd 1000 + +hex_chars: + db '0123456789ABCDEF' diff --git a/module_api.inc b/module_api.inc index 6b9096c..be27f10 100644 --- a/module_api.inc +++ b/module_api.inc @@ -6,11 +6,18 @@ API_VERSION = 0x100 ; 0.1.0 -FLAG_KEEP_ALIVE = 0x01 -FLAG_ADD_DATE = 0x02 ;(not supported) -FLAG_NO_SET_CACHE = 0x04 ;(not supported) -FLAG_NO_CONTENT_ENCODING = 0x08 ;(not supported) -FLAG_TRASFER_CHUNKED = 0x10 ;(not supported) +FLAG_KEEP_ALIVE = 0x01 +FLAG_NO_CONNECTION = 0x02 +FLAG_NO_SERVER_HEADER = 0x04 +FLAG_NO_CONTENT_ENCODING = 0x08 +FLAG_NO_DATE = 0x10 ;(not supported) + +FLAG_NO_CONTENT_LENGTH = 0x20 +FLAG_NO_CONTENT_TYPE = 0x40 +FLAG_NO_CACHE_CONTROL = 0x80 + +FLAG_TRANSFER_CHUNKED = 0x100 +FLAG_RAW_STREAM = 0x200 struct CONNECT_DATA ; 16*4 = 64 bytes socket dd 0 ; номер сокета подключения @@ -64,14 +71,17 @@ struct IMPORT_DATA ; no del std header set_http_ver rd 1 ; void set_http_ver(RESPD* ptr, char* version, uint32_t length); - ; example: 'RTSP/1.1 ' + ; example: 'RTSP/1.1' find_uri_arg rd 1 ;char* find_uri_arg(CONNECT_DATA* session, char* key); find_header rd 1 ;char* find_header(CONNECT_DATA* session, char* key); close_server rd 1 ;void close_server(); - + begin_send_resp rd 1 + ;uint32_t begin_send_resp(RESPD* ptr, uint64_t content_length); + finish_send_resp rd 1 + ;uint32_t finish_send_resp(RESPD* ptr); base_response rd 1 GLOBAL_DATA rd 1 diff --git a/readme.md b/readme.md index 022eaba..d70b254 100644 --- a/readme.md +++ b/readme.md @@ -43,9 +43,9 @@ - void stdcall httpd_close(uint32_t pdata) Эта функция вызывается сервером при завершении работы или в процессе управления сервером. Данная функция предназначена для корректного завершения работы модуля и освобождением связанных с ним ресурсов. + ## Bugs - Сервер не поддерживает работу с файлами, имеющими не ascii символы, так как не производит преобразование uri пути; - - Сервер не имеет интерфейса для управления, что может вызвать трудности в сохранении временных данных модулей при завершении работы; - В ходе тестов был обнаружена ошибка отправки "больших" файлов. Это баг сетевого стека; - При длительной работе сервер может начать "подзависать" или перестать отвечать на сообщения. Это баг сетевого стека. diff --git a/settings.inc b/settings.inc index 626d6b7..22f6a25 100644 --- a/settings.inc +++ b/settings.inc @@ -38,6 +38,9 @@ ends load_settings: mov ebp, ecx + mov dword[srv_stop], 0 + mov dword[srv_shutdown], 0 + sub esp, 16 mov esi, esp invoke ini.get_str, ebp, ini_section_main, ini_key_ip, esi, 16, 0 ; ip diff --git a/sys_func.inc b/sys_func.inc index 34a51e0..5070cdc 100644 --- a/sys_func.inc +++ b/sys_func.inc @@ -246,7 +246,7 @@ destruct_resp: set_http_status: mov eax, [esp + 4] mov ecx, [esp + 8] - and ecx, 0x00ffffff ; clear 3 byte register + and ecx, 0x00ffffff ; clear 3 byte of register add ecx, 0x20 shl 24 ; set 3 byte in ' ' mov [eax + RESPD.http_status], ecx ret 8 @@ -309,7 +309,7 @@ del_http_header: jmp @b .exit: mov ecx, [esp + 4] - inc dword[ecx + RESPD.count_header] + dec dword[ecx + RESPD.count_header] ret 8 .err: mov eax, -1 @@ -319,108 +319,80 @@ del_http_header: ;uint32_t send_resp(RESPD* ptr, char* content, uint32_t length) send_resp: push esi edi ebp - ; get full size mov ebp, [esp + 4*3 + 4] - mov ecx, [ebp + RESPD.count_header] - shl ecx, 1 ; *2 - add ecx, 2 ; finish 0x0d 0x0a - add ecx, [ebp + RESPD.http_ver_len] - ; add size all headers - xor edx, edx -@@: - cmp edx, [ebp + RESPD.count_header] - je @f - add ecx, [ebp + edx*8 + RESPD.header.len] - inc edx - jmp @b -@@: - add ecx, response.end_headers - response.code - ; add size content - ;add ecx, [esp + 4*3 + 12] - ; alloc buffer + test [ebp + RESPD.flags], FLAG_TRANSFER_CHUNKED + jnz .chunked + + test [ebp + RESPD.flags], FLAG_RAW_STREAM + jnz .send_content + + mov edx, [esp + 4*3 + 12] + xor ecx, ecx + push ecx - stdcall Alloc, ecx - pop ecx - test eax, eax - jz .error_alloc - - mov [ebp + RESPD.buffer], eax - mov [ebp + RESPD.buffer_size], ecx - mov edi, eax - ; copy data - mov ecx, [ebp + RESPD.http_ver_len] - mov esi, [ebp + RESPD.http_ver_ptr] - rep movsb ; copy http ver - - mov esi, base_response + response.code - mov ecx, response.end_headers - response.code - mov edx, edi - rep movsb ; copy default status code + headers - - mov eax, [ebp + RESPD.http_status] - mov [edx], eax - - test [ebp + RESPD.flags], FLAG_KEEP_ALIVE - jz @f - push edx - add edx, response.connection - response.code - mov dword[edx], 'keep' - mov dword[edx + 4], '-ali' - mov word[edx + 8], 've' - pop edx -@@: - add edx, response.content_len + 21 - response.code - mov ecx, edx - ; set content length - mov eax, [esp + 4*3 + 12] -@@: - xor edx, edx - test eax, eax - jz @f - div dword[_DIV_10_] - add byte[ecx], dl - dec ecx - jmp @b -@@: - ; copy addition headers - lea eax, [ebp + RESPD.header.ptr] - xor edx, edx -@@: - cmp edx, [ebp + RESPD.count_header] - je @f - - mov esi, [eax] - mov ecx, [eax + 4] - rep movsb - - mov word[edi], 0x0a0d - add edi, 2 - - add eax, 8 - inc edx - jmp @b -@@: - mov ax, 0x0A0D - stosw - - ; send response status line and headers - mov eax, [ebp + RESPD.session] - - push dword 0 - push dword[ebp + RESPD.buffer_size] - push dword[ebp + RESPD.buffer] - push dword[eax + CONNECT_DATA.socket] - call netfunc_send + push ebp + call begin_send_resp cmp eax, -1 jz .exit ; send content - +.send_content: mov ecx, [esp + 4*3 + 8] ; ptr test ecx, ecx - jz .free + jz .exit + + mov eax, [ebp + RESPD.session] + push dword 0 + push dword[esp + 4*4 + 12] ; size + push ecx + push dword[eax + CONNECT_DATA.socket] + call netfunc_send +.exit: + pop ebp edi esi + ret 12 + + +.chunked: + ; TODO + mov eax, -1 + mov ecx, [esp + 4*3 + 8] ; ptr + test ecx, ecx + jz .exit + mov ecx, [esp + 4*3 + 12] ; size + test ecx, ecx + jz .exit + + ; send db , 13, 10 + mov eax, [esp + 4*3 + 12] + push word 0x0a0d + sub esp, 8 + lea esi, [esp + 7] + mov ecx, 8 +@@: + mov edx, eax + and edx, 1111b + mov dl, byte[hex_chars + edx] + mov [esi], dl + shr eax, 4 + dec esi + loop @b + + mov ecx, esp + mov eax, [ebp + RESPD.session] + push dword 0 + push 10 ; size + push ecx + push dword[eax + CONNECT_DATA.socket] + call netfunc_send + add esp, 2+8 + + cmp eax, -1 + jz .exit + + ; send content + mov ecx, [esp + 4*3 + 8] ; ptr mov eax, [ebp + RESPD.session] push dword 0 @@ -431,22 +403,21 @@ send_resp: cmp eax, -1 jz .exit -.free: - xor eax, eax - ; free buffer - push eax - stdcall Free, [ebp + RESPD.buffer] - pop eax -.exit: + + ; send db 13, 10 + push word 0x0a0d + mov ecx, esp ; ptr + + mov eax, [ebp + RESPD.session] + push dword 0 + push 2 ; size + push ecx + push dword[eax + CONNECT_DATA.socket] + call netfunc_send + pop ebp edi esi ret 12 -.error_alloc: - mov eax, -1 - jmp .exit - - - ;char* find_uri_arg(CONNECT_DATA* session, char* key) find_uri_arg: push esi edi @@ -509,7 +480,260 @@ find_header: pop edi esi ret 8 -;void close_server() -close_server: +;uint32_t begin_send_resp(RESPD* ptr, uint64_t content_length); +begin_send_resp: + ; send status line, headers and \n + push esi edi ebp + ; get full size + mov ebp, [esp + 4*3 + 4] + mov ecx, [ebp + RESPD.count_header] + shl ecx, 1 ; *2 + add ecx, 2 + 5 + 2 ; finish 0x0d 0x0a + status(5 byte) + 0x0d 0x0a + add ecx, [ebp + RESPD.http_ver_len] + ; add size all headers + xor edx, edx +@@: + cmp edx, [ebp + RESPD.count_header] + je @f + add ecx, [ebp + edx*8 + RESPD.header.len] + inc edx + jmp @b +@@: + ; add size default headers + ;add ecx, response.end_headers - response.code + test [ebp + RESPD.flags], FLAG_NO_CONNECTION + jnz @f + add ecx, default_http_connection.length +@@: + test [ebp + RESPD.flags], FLAG_NO_SERVER_HEADER + jnz @f + add ecx, default_http_header_server.length +@@: + test [ebp + RESPD.flags], FLAG_NO_CONTENT_ENCODING + jnz @f + add ecx, default_http_cont_encod.length +@@: + test [ebp + RESPD.flags], FLAG_TRANSFER_CHUNKED + jz @f + add ecx, http_header_transfer_chunked.length +@@: + test [ebp + RESPD.flags], FLAG_NO_CONTENT_LENGTH + jnz @f + add ecx, default_http_cont_len.length +@@: + test [ebp + RESPD.flags], FLAG_NO_CONTENT_TYPE + jnz @f + add ecx, default_http_cont_type.length +@@: + test [ebp + RESPD.flags], FLAG_NO_CACHE_CONTROL + jnz @f + add ecx, default_http_cache_ctl.length +@@: + mov [ebp + RESPD.buffer_size], ecx + ; alloc buffer + stdcall Alloc, ecx + test eax, eax + jz .error + mov [ebp + RESPD.buffer], eax + mov edi, eax + ; copy data - version, status code, default header + mov ecx, [ebp + RESPD.http_ver_len] + mov esi, [ebp + RESPD.http_ver_ptr] + rep movsb ; copy http ver + + mov al, ' ' + stosb + mov eax, [ebp + RESPD.http_status] + stosd + mov eax, 0x0a0d + stosw + + ; copy and creating default headers + test [ebp + RESPD.flags], FLAG_NO_SERVER_HEADER + jnz @f + mov esi, default_http_header_server + mov ecx, default_http_header_server.length + rep movsb +@@: + test [ebp + RESPD.flags], FLAG_NO_CACHE_CONTROL + jnz @f + mov esi, default_http_cache_ctl + mov ecx, default_http_cache_ctl.length + rep movsb +@@: + test [ebp + RESPD.flags], FLAG_NO_CONTENT_ENCODING + jnz @f + mov esi, default_http_cont_encod + mov ecx, default_http_cont_encod.length + rep movsb +@@: + test [ebp + RESPD.flags], FLAG_TRANSFER_CHUNKED + jz @f + + mov esi, http_header_transfer_chunked + mov ecx, http_header_transfer_chunked.length + rep movsb +@@: + test [ebp + RESPD.flags], FLAG_NO_CONTENT_LENGTH + jnz .no_content_length + + mov esi, default_http_cont_len + mov ecx, default_http_cont_len.length + rep movsb + ; set content length + mov eax, [esp + 4*3 + 8] + mov edx, [esp + 4*3 + 12] + + test eax, eax + jne @f + test edx, edx + jz .no_content_length +@@: + cmp edx, 1000 ; 999*4 - max length of file + jae .error_free + + lea ecx, [edi - 1 - 2] ; skip 13, 10 and set on finish char number + +.div1000: + div dword[_DIV_1000_] + push eax + + mov eax, edx + xor edx, edx + + div dword[_DIV_100_] + push eax + + mov eax, edx + xor edx, edx + div dword[_DIV_10_] + add byte[ecx], dl + add byte[ecx - 1], al + sub ecx, 3 + + pop eax + add byte[ecx + 1], al + + pop eax + xor edx, edx + test eax, eax + jne .div1000 + +.no_content_length: + test [ebp + RESPD.flags], FLAG_NO_CONTENT_TYPE + jnz @f + + mov esi, default_http_cont_type + mov ecx, default_http_cont_type.length + rep movsb +@@: + test [ebp + RESPD.flags], FLAG_NO_CONNECTION + jnz @f + + mov esi, default_http_connection + mov ecx, default_http_connection.length + rep movsb + + test [ebp + RESPD.flags], FLAG_KEEP_ALIVE + jz @f + + lea ecx, [edi - default_http_connection.length \ + + default_http_connection.value] + mov dword[ecx], 'keep' + mov dword[ecx + 4], '-ali' + mov word[ecx + 8], 've' +@@: + ; copy addition headers + lea eax, [ebp + RESPD.header.ptr] + xor edx, edx +@@: + cmp edx, [ebp + RESPD.count_header] + je @f + + mov esi, [eax] + mov ecx, [eax + 4] + rep movsb + + mov word[edi], 0x0a0d + add edi, 2 + + add eax, 8 + inc edx + jmp @b +@@: + mov ax, 0x0A0D + stosw + + ; send response status line and headers + mov eax, [ebp + RESPD.session] + + push dword 0 + push dword[ebp + RESPD.buffer_size] + push dword[ebp + RESPD.buffer] + push dword[eax + CONNECT_DATA.socket] + call netfunc_send + + push eax + stdcall Free, [ebp + RESPD.buffer] + pop eax + pop ebp edi esi + ret 12 + +.error_free: + stdcall Free, [ebp + RESPD.buffer] +.error: + mov eax, -1 + pop ebp edi esi + ret 12 + + +;uint32_t finish_send_resp(RESPD* ptr); +finish_send_resp: + ; send finish block for chunked encoding + mov edx, [esp + 4] + test dword[edx + RESPD.flags], FLAG_TRANSFER_CHUNKED + jz .exit + ; send finish block - zero length + sub esp, 5 + mov dword[esp + 1], 0x0a0d0a0d + mov byte[esp], '0' + + mov ecx, esp + mov eax, [ebp + RESPD.session] + + push dword 0 + push dword 5 ; size buffer + push ecx + push dword[eax + CONNECT_DATA.socket] + call netfunc_send + + add esp, 5 +.exit: + ret 4 + + +;void close_server() +; TODO: added free HTTPD_MODULE structures +close_server: + ; call function httpd_close() for all modules + ; terminate main thread server + mov dword[srv_stop], 1 + + cmp dword[GLOBAL_DATA.modules], 0 + jz .no_modules + + mov eax, [GLOBAL_DATA.modules] +.next_module: + push eax + push dword[eax + HTTPD_MODULE.pdata] ; context of module + call dword[eax + HTTPD_MODULE.httpd_close] + pop eax + + mov eax, [eax] ; HTTPD_MODULE.next + test eax, eax ; terminate list + jne .next_module + +.no_modules: + mov dword[srv_shutdown], 1 ret \ No newline at end of file