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
This commit is contained in:
2024-03-10 00:59:52 +05:00
parent 853ed0f5b5
commit 00abdb31f0
17 changed files with 658 additions and 134 deletions

BIN
bin/httpd

Binary file not shown.

View File

@@ -23,5 +23,7 @@ mime_file=/usbhd0/3/mime_types.bin
; not uning ' ' in unit_name;cmdline : "path = unit_name ; cmdline" is bad name ; not uning ' ' in unit_name;cmdline : "path = unit_name ; cmdline" is bad name
test=test_unit.obj test=test_unit.obj
rasp=test_unit_2.obj rasp=test_unit_2.obj
test5=test_unit5.obj
admin=srv_control.obj;123456
;database/sqlite3=sqlite3_serv.obj ;database/sqlite3=sqlite3_serv.obj
;database/cvs=cvs_table_server.obj ;database/cvs=cvs_table_server.obj

BIN
bin/modules/srv_control.obj Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
bin/modules/test_unit5.obj Normal file

Binary file not shown.

Binary file not shown.

148
example/srv_control.asm Normal file
View File

@@ -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 '<body> <h1> Control panel of simple-httpd</h1> <a href="?cmd=S&token='
.token:
db ' ">Stop Server</a></body>'
.size = $ - text_board
@EXPORT:
export \
unit_init, 'httpd_init', \
server_entry, 'httpd_serv',\
server_close, 'httpd_close'
IMPORT IMPORT_DATA

View File

@@ -88,7 +88,7 @@ section '.data' data readable writable align 16
text_no_cmd: text_no_cmd:
db 'For this unit in config not set arguments' db 'For this unit in config not set arguments'
.size = $ - $$ .size = $ - text_no_cmd
@EXPORT: @EXPORT:
export \ export \

84
example/test_unit5.asm Normal file
View File

@@ -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<br>'
.size = $ - text_no_cmd
text_no_cmd2:
db 'chunk 2 - new size chunk<br>'
.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

View File

@@ -138,7 +138,7 @@ server_entry:
.send_data: ; eax - ptr to buffer .send_data: ; eax - ptr to buffer
mov edi, eax mov edi, eax
board_input 'create_resp' board_input 'create_resp'
invoke IMPORT.create_resp, esi, 0 invoke IMPORT.create_resp, esi, FLAG_KEEP_ALIVE
test eax, eax test eax, eax
jz .exit jz .exit
@@ -153,7 +153,8 @@ server_entry:
.err_404: .err_404:
; send resp 404 ; send resp 404
board_input 'err404' 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 test eax, eax
jz .exit jz .exit

View File

@@ -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. ; ; Distributed under terms of the 3-Clause BSD License. ;
; ; ; ;
; httpd - Simple http server for Kolibri OS. ; ; 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 test eax, eax
jnz .err_settings jnz .err_settings
mov ecx, PATH
cmp byte[ecx],0
jnz @f
mov ecx, default_ini_path mov ecx, default_ini_path
cmp byte[PATH],0
jz @f
mov ecx, PATH
@@: @@:
; get settings ; get settings
call load_settings ; ecx -> string to config file call load_settings ; ecx -> string to config file
@@ -70,14 +72,21 @@ START:
jz .listen_err jz .listen_err
.mainloop: .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 test eax, eax
jz .mainloop jz .mainloop
cmp dword[srv_stop], 1
jz .mainloop
push dword thread_connect push dword thread_connect
call CreateThread ; not save PID call CreateThread ; not save PID
jmp .mainloop jmp .mainloop
.shutdown:
.listen_err: .listen_err:
.bind_err: .bind_err:
push dword[srv_socket] push dword[srv_socket]
@@ -237,6 +246,7 @@ default_ini_path: db 'httpd.ini',0
ini_section_units: db 'MODULES',0 ini_section_units: db 'MODULES',0
ini_section_main: db 'MAIN', 0 ini_section_main: db 'MAIN', 0
ini_section_tls db 'TLS',0
ini_key_ip db 'ip',0 ini_key_ip db 'ip',0
ini_key_port db 'port',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_uri_arg
dd find_header dd find_header
dd close_server dd close_server
dd begin_send_resp
dd finish_send_resp
dd base_response dd base_response
dd GLOBAL_DATA dd GLOBAL_DATA
@@ -293,7 +305,8 @@ EXPORT_DATA: ; in modules for this table using struct IMPORT_DATA
; DATA ; DATA
;UDATA ;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_backlog: rd 1 ; maximum number of simultaneous open connections
srv_socket: rd 1 srv_socket: rd 1

View File

@@ -82,16 +82,52 @@
; db 13, 10 ; db 13, 10
;.size = $ - http_err_response ;.size = $ - http_err_response
default_http_version: db 'HTTP/1.1 ' default_http_version:
db 'HTTP/1.1 '
.length = $ - default_http_version .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: http_response_err_501:
db 'HTTP/1.1 ' db 'HTTP/1.1 '
db '501 ',13, 10 db '501 ',13, 10
db 'Error parsing your request message. The version is not supported or another error.' db 'Error parsing your request message. The version is not supported or another error.'
db 'Server: simple-httpd/0.0.1', 13, 10 db 'Server: simple-httpd/0.3.0', 13, 10
;db 'Content-length: 91', 13, 10
;db 'Content-type: text/plain', 13, 10;
db 'Connection: close', 13, 10 db 'Connection: close', 13, 10
db 13, 10 db 13, 10
.size = $ - http_response_err_501 .size = $ - http_response_err_501
@@ -99,7 +135,7 @@ http_response_err_501:
http_response_err_404: http_response_err_404:
db 'HTTP/1.1 ' db 'HTTP/1.1 '
db '404 ',13, 10 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-length: 45', 13, 10
db 'Content-type: text/plain', 13, 10; db 'Content-type: text/plain', 13, 10;
db 'Connection: close', 13, 10 db 'Connection: close', 13, 10
@@ -110,7 +146,7 @@ http_response_err_404:
http_response_options: http_response_options:
db 'HTTP/1.1 ' db 'HTTP/1.1 '
db '204 ',13, 10 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 'Allow: OPTIONS, GET, POST', 13, 10
db 'Connection: close', 13, 10 db 'Connection: close', 13, 10
db 13, 10 db 13, 10
@@ -124,7 +160,7 @@ response:
db 'HTTP/1.1 ' db 'HTTP/1.1 '
.code = $ - response .code = $ - response
db '000 ',13, 10 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 'Cache-Control: no-cache', 13, 10
db 'Content-Encoding: ' db 'Content-Encoding: '
.content_encod = $ - response .content_encod = $ - response
@@ -179,3 +215,6 @@ STD_MIME_TYPE_ARR:
_DIV_10_: dd 10 _DIV_10_: dd 10
_DIV_100_: dd 100 _DIV_100_: dd 100
_DIV_1000_: dd 1000 _DIV_1000_: dd 1000
hex_chars:
db '0123456789ABCDEF'

View File

@@ -6,11 +6,18 @@
API_VERSION = 0x100 ; 0.1.0 API_VERSION = 0x100 ; 0.1.0
FLAG_KEEP_ALIVE = 0x01 FLAG_KEEP_ALIVE = 0x01
FLAG_ADD_DATE = 0x02 ;(not supported) FLAG_NO_CONNECTION = 0x02
FLAG_NO_SET_CACHE = 0x04 ;(not supported) FLAG_NO_SERVER_HEADER = 0x04
FLAG_NO_CONTENT_ENCODING = 0x08 ;(not supported) FLAG_NO_CONTENT_ENCODING = 0x08
FLAG_TRASFER_CHUNKED = 0x10 ;(not supported) 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 struct CONNECT_DATA ; 16*4 = 64 bytes
socket dd 0 ; номер сокета подключения socket dd 0 ; номер сокета подключения
@@ -64,14 +71,17 @@ struct IMPORT_DATA
; no del std header ; no del std header
set_http_ver rd 1 set_http_ver rd 1
; void set_http_ver(RESPD* ptr, char* version, uint32_t length); ; void set_http_ver(RESPD* ptr, char* version, uint32_t length);
; example: 'RTSP/1.1 ' ; example: 'RTSP/1.1'
find_uri_arg rd 1 find_uri_arg rd 1
;char* find_uri_arg(CONNECT_DATA* session, char* key); ;char* find_uri_arg(CONNECT_DATA* session, char* key);
find_header rd 1 find_header rd 1
;char* find_header(CONNECT_DATA* session, char* key); ;char* find_header(CONNECT_DATA* session, char* key);
close_server rd 1 close_server rd 1
;void close_server(); ;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 base_response rd 1
GLOBAL_DATA rd 1 GLOBAL_DATA rd 1

View File

@@ -43,9 +43,9 @@
- <CODE>void stdcall httpd_close(uint32_t pdata) </CODE> - <CODE>void stdcall httpd_close(uint32_t pdata) </CODE>
Эта функция вызывается сервером при завершении работы или в процессе управления сервером. Данная функция предназначена для корректного завершения работы модуля и освобождением связанных с ним ресурсов. Эта функция вызывается сервером при завершении работы или в процессе управления сервером. Данная функция предназначена для корректного завершения работы модуля и освобождением связанных с ним ресурсов.
## Bugs ## Bugs
- Сервер не поддерживает работу с файлами, имеющими не ascii символы, так как не производит преобразование uri пути; - Сервер не поддерживает работу с файлами, имеющими не ascii символы, так как не производит преобразование uri пути;
- Сервер не имеет интерфейса для управления, что может вызвать трудности в сохранении временных данных модулей при завершении работы;
- В ходе тестов был обнаружена ошибка отправки "больших" файлов. Это баг сетевого стека; - В ходе тестов был обнаружена ошибка отправки "больших" файлов. Это баг сетевого стека;
- При длительной работе сервер может начать "подзависать" или перестать отвечать на сообщения. Это баг сетевого стека. - При длительной работе сервер может начать "подзависать" или перестать отвечать на сообщения. Это баг сетевого стека.

View File

@@ -38,6 +38,9 @@ ends
load_settings: load_settings:
mov ebp, ecx mov ebp, ecx
mov dword[srv_stop], 0
mov dword[srv_shutdown], 0
sub esp, 16 sub esp, 16
mov esi, esp mov esi, esp
invoke ini.get_str, ebp, ini_section_main, ini_key_ip, esi, 16, 0 ; ip invoke ini.get_str, ebp, ini_section_main, ini_key_ip, esi, 16, 0 ; ip

View File

@@ -246,7 +246,7 @@ destruct_resp:
set_http_status: set_http_status:
mov eax, [esp + 4] mov eax, [esp + 4]
mov ecx, [esp + 8] 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 ' ' add ecx, 0x20 shl 24 ; set 3 byte in ' '
mov [eax + RESPD.http_status], ecx mov [eax + RESPD.http_status], ecx
ret 8 ret 8
@@ -309,7 +309,7 @@ del_http_header:
jmp @b jmp @b
.exit: .exit:
mov ecx, [esp + 4] mov ecx, [esp + 4]
inc dword[ecx + RESPD.count_header] dec dword[ecx + RESPD.count_header]
ret 8 ret 8
.err: .err:
mov eax, -1 mov eax, -1
@@ -319,108 +319,80 @@ del_http_header:
;uint32_t send_resp(RESPD* ptr, char* content, uint32_t length) ;uint32_t send_resp(RESPD* ptr, char* content, uint32_t length)
send_resp: send_resp:
push esi edi ebp push esi edi ebp
; get full size
mov ebp, [esp + 4*3 + 4] 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 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 push edx
add edx, response.connection - response.code push ebp
mov dword[edx], 'keep' call begin_send_resp
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
cmp eax, -1 cmp eax, -1
jz .exit jz .exit
; send content ; send content
.send_content:
mov ecx, [esp + 4*3 + 8] ; ptr mov ecx, [esp + 4*3 + 8] ; ptr
test ecx, ecx 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 <HEX size>, 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] mov eax, [ebp + RESPD.session]
push dword 0 push dword 0
@@ -431,22 +403,21 @@ send_resp:
cmp eax, -1 cmp eax, -1
jz .exit jz .exit
.free:
xor eax, eax ; send db 13, 10
; free buffer push word 0x0a0d
push eax mov ecx, esp ; ptr
stdcall Free, [ebp + RESPD.buffer]
pop eax mov eax, [ebp + RESPD.session]
.exit: push dword 0
push 2 ; size
push ecx
push dword[eax + CONNECT_DATA.socket]
call netfunc_send
pop ebp edi esi pop ebp edi esi
ret 12 ret 12
.error_alloc:
mov eax, -1
jmp .exit
;char* find_uri_arg(CONNECT_DATA* session, char* key) ;char* find_uri_arg(CONNECT_DATA* session, char* key)
find_uri_arg: find_uri_arg:
push esi edi push esi edi
@@ -509,7 +480,260 @@ find_header:
pop edi esi pop edi esi
ret 8 ret 8
;void close_server() ;uint32_t begin_send_resp(RESPD* ptr, uint64_t content_length);
close_server: 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 ret