diff --git a/bin/httpd b/bin/httpd
index b1b9943..cb5d053 100644
Binary files a/bin/httpd and b/bin/httpd differ
diff --git a/bin/httpd.ini b/bin/httpd.ini
index f7ef16e..c43bb95 100644
--- a/bin/httpd.ini
+++ b/bin/httpd.ini
@@ -23,5 +23,7 @@ mime_file=/usbhd0/3/mime_types.bin
; not uning ' ' in unit_name;cmdline : "path = unit_name ; cmdline" is bad name
test=test_unit.obj
rasp=test_unit_2.obj
+test5=test_unit5.obj
+admin=srv_control.obj;123456
;database/sqlite3=sqlite3_serv.obj
;database/cvs=cvs_table_server.obj
\ No newline at end of file
diff --git a/bin/modules/srv_control.obj b/bin/modules/srv_control.obj
new file mode 100644
index 0000000..e853cda
Binary files /dev/null and b/bin/modules/srv_control.obj differ
diff --git a/bin/modules/test_unit.obj b/bin/modules/test_unit.obj
index 44922db..ba5b189 100644
Binary files a/bin/modules/test_unit.obj and b/bin/modules/test_unit.obj differ
diff --git a/bin/modules/test_unit4.obj b/bin/modules/test_unit4.obj
index 190a0e3..7773ac7 100644
Binary files a/bin/modules/test_unit4.obj and b/bin/modules/test_unit4.obj differ
diff --git a/bin/modules/test_unit5.obj b/bin/modules/test_unit5.obj
new file mode 100644
index 0000000..5367c5d
Binary files /dev/null and b/bin/modules/test_unit5.obj differ
diff --git a/bin/modules/test_unit_2.obj b/bin/modules/test_unit_2.obj
index 3bb0572..3c73304 100644
Binary files a/bin/modules/test_unit_2.obj and b/bin/modules/test_unit_2.obj differ
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