mirror of
https://github.com/Doczom/simple-httpd.git
synced 2025-09-21 02:50:09 +02:00
Release first beta version server
Version 0.1.0 has been released: - Added a feature for easily sending an http response - Minor bugs have been fixed - Updated API for server modules - Added a readme file
This commit is contained in:
@@ -21,6 +21,7 @@ mime_file=/usbhd0/3/mime_types.bin
|
|||||||
; list units
|
; list units
|
||||||
; path = path to lib in units_dir
|
; path = path to lib in units_dir
|
||||||
test=test_unit.obj
|
test=test_unit.obj
|
||||||
|
rasp=test_unit_2.obj
|
||||||
;database/sqlite3=sqlite3_serv.obj
|
;database/sqlite3=sqlite3_serv.obj
|
||||||
;database/cvs=cvs_table_server.obj
|
;database/cvs=cvs_table_server.obj
|
||||||
|
|
||||||
|
@@ -1,10 +1,15 @@
|
|||||||
format MS COFF
|
format MS COFF
|
||||||
public @EXPORT as 'EXPORTS'
|
public @EXPORT as 'EXPORTS'
|
||||||
|
|
||||||
NO_DEBUG_INPUT = 1
|
API_VERSION = 0x05
|
||||||
|
FLAG_KEEP_ALIVE = 0x01
|
||||||
|
|
||||||
|
NO_DEBUG_INPUT = 0
|
||||||
include 'D:\kos\programs\macros.inc'
|
include 'D:\kos\programs\macros.inc'
|
||||||
|
|
||||||
struct EXPORT_DATA
|
struct IMPORT_DATA
|
||||||
|
version rd 1 ; dword for check api
|
||||||
|
sizeof rd 1 ; size struct
|
||||||
netfunc_socket rd 1
|
netfunc_socket rd 1
|
||||||
netfunc_close rd 1
|
netfunc_close rd 1
|
||||||
netfunc_bind rd 1
|
netfunc_bind rd 1
|
||||||
@@ -16,6 +21,26 @@ struct EXPORT_DATA
|
|||||||
FileRead rd 1
|
FileRead rd 1
|
||||||
Alloc rd 1
|
Alloc rd 1
|
||||||
Free rd 1
|
Free rd 1
|
||||||
|
parse_http_query rd 1
|
||||||
|
;send_resp(RESPD* ptr, char* content, uint32_t length)
|
||||||
|
;create_resp(CONNECT_DATA* session, uint32_t flags)
|
||||||
|
; FLAG_KEEP_ALIVE = 0x01
|
||||||
|
; FLAG_ADD_DATE = 0x02 ;(not supported)
|
||||||
|
; FLAG_NO_SET_CACHE = 0x04 ;(not supported)
|
||||||
|
; FLAG_NO_CONTENT_ENCODING = 0x08 ;(not supported)
|
||||||
|
;
|
||||||
|
;destruct_resp(RESPD* ptr)
|
||||||
|
;set_http_status(RESPD* ptr, uint32_t status) ; status in '200' format,
|
||||||
|
;add_http_header(RESPD* ptr, char* ptr_header)
|
||||||
|
;del_http_header(RESPD* ptr, char* ptr_header) ; no del std header
|
||||||
|
;set_http_ver(RESPD* ptr, char* version) ; example: RTSP/1.1
|
||||||
|
send_resp rd 1
|
||||||
|
create_resp rd 1
|
||||||
|
destruct_resp rd 1
|
||||||
|
set_http_status rd 1
|
||||||
|
add_http_header rd 1
|
||||||
|
del_http_header rd 1
|
||||||
|
set_http_ver rd 1
|
||||||
|
|
||||||
base_response rd 1
|
base_response rd 1
|
||||||
GLOBAL_DATA rd 1
|
GLOBAL_DATA rd 1
|
||||||
@@ -64,13 +89,25 @@ end if
|
|||||||
section '.flat' code readable align 16
|
section '.flat' code readable align 16
|
||||||
|
|
||||||
unit_init:
|
unit_init:
|
||||||
|
mov eax, -1
|
||||||
|
push esi edi
|
||||||
|
mov esi, [esp + 4*2 + 4]
|
||||||
|
mov [import_httpd], esi
|
||||||
|
|
||||||
mov eax, [esp + 4]
|
cmp dword[esi + IMPORT_DATA.version], API_VERSION
|
||||||
mov [import_httpd], eax
|
jne .exit
|
||||||
|
|
||||||
|
mov edi, IMPORT
|
||||||
|
mov ecx, [esi + IMPORT_DATA.sizeof]
|
||||||
|
shr ecx, 2 ; div 4
|
||||||
|
rep movsd
|
||||||
|
|
||||||
xor eax, eax
|
xor eax, eax
|
||||||
|
.exit:
|
||||||
|
pop edi esi
|
||||||
ret 4
|
ret 4
|
||||||
|
|
||||||
|
|
||||||
server_entry:
|
server_entry:
|
||||||
push esi edi
|
push esi edi
|
||||||
mov esi, [esp + 4*2 + 4]
|
mov esi, [esp + 4*2 + 4]
|
||||||
@@ -106,6 +143,11 @@ server_entry:
|
|||||||
cmp dword[ecx], 'txt'
|
cmp dword[ecx], 'txt'
|
||||||
jne .no_args
|
jne .no_args
|
||||||
|
|
||||||
|
mov dword[text_message], ' '
|
||||||
|
mov dword[text_message + 4], ' '
|
||||||
|
mov dword[text_message + 8], ' '
|
||||||
|
mov dword[text_message + 12], ' '
|
||||||
|
|
||||||
push esi edi
|
push esi edi
|
||||||
mov esi, [eax + 12]
|
mov esi, [eax + 12]
|
||||||
mov edi, text_message
|
mov edi, text_message
|
||||||
@@ -123,8 +165,7 @@ server_entry:
|
|||||||
board_input 'create message'
|
board_input 'create message'
|
||||||
; create http message
|
; create http message
|
||||||
push dword 8*1024
|
push dword 8*1024
|
||||||
mov eax, [import_httpd]
|
call [IMPORT + IMPORT_DATA.Alloc]
|
||||||
call [eax + EXPORT_DATA.Alloc]
|
|
||||||
test eax, eax
|
test eax, eax
|
||||||
jz .exit
|
jz .exit
|
||||||
|
|
||||||
@@ -168,13 +209,12 @@ server_entry:
|
|||||||
; set httpcode
|
; set httpcode
|
||||||
mov dword[edi + sceleton_resp.code], '200 '
|
mov dword[edi + sceleton_resp.code], '200 '
|
||||||
; send http message
|
; send http message
|
||||||
mov ecx, [import_httpd]
|
|
||||||
|
|
||||||
push dword 0 ; flags
|
push dword 0 ; flags
|
||||||
push sceleton_resp.size
|
push sceleton_resp.size
|
||||||
push edi
|
push edi
|
||||||
push dword[esi + CONNECT_DATA.socket]
|
push dword[esi + CONNECT_DATA.socket]
|
||||||
call [ecx + EXPORT_DATA.netfunc_send]
|
call [IMPORT + IMPORT_DATA.netfunc_send]
|
||||||
|
|
||||||
board_input 'send'
|
board_input 'send'
|
||||||
.exit:
|
.exit:
|
||||||
@@ -224,3 +264,6 @@ text_message:
|
|||||||
export \
|
export \
|
||||||
unit_init, 'httpd_init', \
|
unit_init, 'httpd_init', \
|
||||||
server_entry, 'httpd_serv'
|
server_entry, 'httpd_serv'
|
||||||
|
|
||||||
|
|
||||||
|
IMPORT IMPORT_DATA ;
|
Binary file not shown.
264
example/test_unit_2.asm
Normal file
264
example/test_unit_2.asm
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
format MS COFF
|
||||||
|
public @EXPORT as 'EXPORTS'
|
||||||
|
|
||||||
|
API_VERSION = 0x05
|
||||||
|
FLAG_KEEP_ALIVE = 0x01
|
||||||
|
|
||||||
|
NO_DEBUG_INPUT = 0
|
||||||
|
include 'D:\kos\programs\macros.inc'
|
||||||
|
purge mov,add,sub
|
||||||
|
include 'D:\kos\programs\proc32.inc'
|
||||||
|
|
||||||
|
struct IMPORT_DATA
|
||||||
|
version rd 1 ; dword for check api
|
||||||
|
sizeof rd 1 ; size struct
|
||||||
|
netfunc_socket rd 1
|
||||||
|
netfunc_close rd 1
|
||||||
|
netfunc_bind rd 1
|
||||||
|
netfunc_accept rd 1
|
||||||
|
netfunc_listen rd 1
|
||||||
|
netfunc_recv rd 1
|
||||||
|
netfunc_send rd 1
|
||||||
|
FileInfo rd 1
|
||||||
|
FileRead rd 1
|
||||||
|
Alloc rd 1
|
||||||
|
Free rd 1
|
||||||
|
parse_http_query rd 1
|
||||||
|
;send_resp(RESPD* ptr, char* content, uint32_t length)
|
||||||
|
;create_resp(CONNECT_DATA* session, uint32_t flags)
|
||||||
|
; FLAG_KEEP_ALIVE = 0x01
|
||||||
|
; FLAG_ADD_DATE = 0x02 ;(not supported)
|
||||||
|
; FLAG_NO_SET_CACHE = 0x04 ;(not supported)
|
||||||
|
; FLAG_NO_CONTENT_ENCODING = 0x08 ;(not supported)
|
||||||
|
;
|
||||||
|
;destruct_resp(RESPD* ptr)
|
||||||
|
;set_http_status(RESPD* ptr, uint32_t status) ; status in '200' format,
|
||||||
|
;add_http_header(RESPD* ptr, char* ptr_header)
|
||||||
|
;del_http_header(RESPD* ptr, char* ptr_header) ; no del std header
|
||||||
|
;set_http_ver(RESPD* ptr, char* version) ; example: RTSP/1.1
|
||||||
|
send_resp rd 1
|
||||||
|
create_resp rd 1
|
||||||
|
destruct_resp rd 1
|
||||||
|
set_http_status rd 1
|
||||||
|
add_http_header rd 1
|
||||||
|
del_http_header rd 1
|
||||||
|
set_http_ver rd 1
|
||||||
|
|
||||||
|
base_response rd 1
|
||||||
|
GLOBAL_DATA rd 1
|
||||||
|
ends
|
||||||
|
|
||||||
|
struct CONNECT_DATA ; 16*4 = 64 bytes
|
||||||
|
socket dd 0 ; номер сокета подключения
|
||||||
|
sockaddr dd 16/4 ; socaddr connection
|
||||||
|
buffer_request dd 0 ; pointer to buffer for geting message socket
|
||||||
|
request_size dd 0 ; size geted data from client
|
||||||
|
end_buffer_request dd 0 ; для парсера
|
||||||
|
buffer_response dd 0 ; pointer to buffwr for resp message
|
||||||
|
http_method dd 0 ; указатель на строку
|
||||||
|
http_verion dd 0 ; указатель на строку
|
||||||
|
num_headers dd 0 ; number items in REQUEST_DATA
|
||||||
|
http_headers dd 0 ; указатель на массив REQUEST_DATA
|
||||||
|
uri_scheme dd 0 ; указатель на схему
|
||||||
|
uri_authority dd 0 ; pointer to struct ?
|
||||||
|
uri_path dd 0 ; указатель на декодированный путь к ресурсу(без параметров)
|
||||||
|
num_uri_args dd 0 ;
|
||||||
|
uri_arg dd 0 ; pointer to array REQUEST_DATA аргументов uri строк
|
||||||
|
uri_fragment dd 0 ; указатель на строку
|
||||||
|
message_body dd 0 ; указатель на тело http запроса
|
||||||
|
ends
|
||||||
|
|
||||||
|
macro board_input message {
|
||||||
|
if NO_DEBUG_INPUT = 0
|
||||||
|
local ..str, ..end
|
||||||
|
push eax ebx ecx esi
|
||||||
|
mov esi, ..str
|
||||||
|
@@:
|
||||||
|
mov cl, [esi]
|
||||||
|
mcall 63, 1
|
||||||
|
inc esi
|
||||||
|
|
||||||
|
cmp cl, 10
|
||||||
|
jne @b
|
||||||
|
jmp ..end
|
||||||
|
..str:
|
||||||
|
db message,13, 10
|
||||||
|
..end:
|
||||||
|
pop esi ecx ebx eax
|
||||||
|
end if
|
||||||
|
}
|
||||||
|
|
||||||
|
section '.flat' code readable align 16
|
||||||
|
|
||||||
|
unit_init:
|
||||||
|
mov eax, -1
|
||||||
|
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
|
||||||
|
|
||||||
|
xor eax, eax
|
||||||
|
.exit:
|
||||||
|
pop edi esi
|
||||||
|
ret 4
|
||||||
|
|
||||||
|
|
||||||
|
server_entry:
|
||||||
|
push esi edi
|
||||||
|
mov esi, [esp + 4*2 + 4]
|
||||||
|
; work
|
||||||
|
board_input 'first'
|
||||||
|
|
||||||
|
cmp [esi + CONNECT_DATA.num_uri_args], 1
|
||||||
|
jb .no_args
|
||||||
|
|
||||||
|
mov eax, [esi + CONNECT_DATA.uri_arg]
|
||||||
|
|
||||||
|
mov ecx, [eax]
|
||||||
|
cmp word[ecx], 'gr'
|
||||||
|
jne .no_args
|
||||||
|
|
||||||
|
cmp byte[ecx + 2], 0
|
||||||
|
jne .no_args
|
||||||
|
|
||||||
|
|
||||||
|
mov ecx, [eax + 4]
|
||||||
|
cmp dword[ecx], 'bpo'
|
||||||
|
jne .no_bpo
|
||||||
|
|
||||||
|
board_input 'bpo'
|
||||||
|
invoke IMPORT.Alloc, sceleton_resp.size
|
||||||
|
test eax, eax
|
||||||
|
jz .exit
|
||||||
|
|
||||||
|
push esi
|
||||||
|
mov edi, eax
|
||||||
|
mov esi, sceleton_resp
|
||||||
|
mov ecx, sceleton_resp.size
|
||||||
|
rep movsb
|
||||||
|
|
||||||
|
lea edi, [eax + sceleton_resp.name]
|
||||||
|
mov esi, bpo_name
|
||||||
|
mov ecx, bpo_name.size
|
||||||
|
rep movsb
|
||||||
|
|
||||||
|
lea edi, [eax + sceleton_resp.data]
|
||||||
|
mov esi, bpo_data
|
||||||
|
mov ecx, bpo_data.size
|
||||||
|
rep movsb
|
||||||
|
pop esi
|
||||||
|
|
||||||
|
jmp .send_data
|
||||||
|
.no_bpo:
|
||||||
|
cmp dword[ecx], 'btp'
|
||||||
|
jne .err_404
|
||||||
|
|
||||||
|
board_input 'btp'
|
||||||
|
invoke IMPORT.Alloc, sceleton_resp.size
|
||||||
|
test eax, eax
|
||||||
|
jz .exit
|
||||||
|
|
||||||
|
push esi
|
||||||
|
mov edi, eax
|
||||||
|
mov esi, sceleton_resp
|
||||||
|
mov ecx, sceleton_resp.size
|
||||||
|
rep movsb
|
||||||
|
|
||||||
|
lea edi, [eax + sceleton_resp.name]
|
||||||
|
mov esi, btp_name
|
||||||
|
mov ecx, btp_name.size
|
||||||
|
rep movsb
|
||||||
|
|
||||||
|
lea edi, [eax + sceleton_resp.data]
|
||||||
|
mov esi, btp_data
|
||||||
|
mov ecx, btp_data.size
|
||||||
|
rep movsb
|
||||||
|
pop esi
|
||||||
|
|
||||||
|
jmp .send_data
|
||||||
|
.no_args:
|
||||||
|
board_input 'no_arg'
|
||||||
|
invoke IMPORT.create_resp, esi, 0
|
||||||
|
test eax, eax
|
||||||
|
jz .exit
|
||||||
|
|
||||||
|
push eax
|
||||||
|
invoke IMPORT.send_resp, eax, sceleton_resp, sceleton_resp.size
|
||||||
|
invoke IMPORT.destruct_resp ; arg in stack
|
||||||
|
.exit:
|
||||||
|
pop edi esi
|
||||||
|
ret 4
|
||||||
|
|
||||||
|
.send_data: ; eax - ptr to buffer
|
||||||
|
mov edi, eax
|
||||||
|
board_input 'create_resp'
|
||||||
|
invoke IMPORT.create_resp, esi, 0
|
||||||
|
test eax, eax
|
||||||
|
jz .exit
|
||||||
|
|
||||||
|
board_input 'send_data'
|
||||||
|
push eax
|
||||||
|
invoke IMPORT.send_resp, eax, edi, sceleton_resp.size
|
||||||
|
invoke IMPORT.destruct_resp ; arg in stack
|
||||||
|
|
||||||
|
invoke IMPORT.Free, edi
|
||||||
|
jmp .exit
|
||||||
|
|
||||||
|
.err_404:
|
||||||
|
; send resp 404
|
||||||
|
board_input 'err404'
|
||||||
|
invoke IMPORT.create_resp, esi, 0
|
||||||
|
test eax, eax
|
||||||
|
jz .exit
|
||||||
|
|
||||||
|
mov edi, eax
|
||||||
|
invoke IMPORT.set_http_status, edi, dword '404'
|
||||||
|
invoke IMPORT.send_resp, edi, 0, 0
|
||||||
|
invoke IMPORT.destruct_resp, edi
|
||||||
|
jmp .exit
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
section '.data' data readable writable align 16
|
||||||
|
|
||||||
|
_10: dd 10
|
||||||
|
|
||||||
|
sceleton_resp:
|
||||||
|
db '<!DOCTYPE html>'
|
||||||
|
db '<html><head><meta charset="utf-8"><title>Test Server 2</title></head>'
|
||||||
|
db '<body><ul><il><a href="?gr=bpo">bpo</a></il><br><il><a href="?gr=btp">btp</a></il></ul>'
|
||||||
|
db '<b>Название группы: </b>'
|
||||||
|
.name = $ - sceleton_resp
|
||||||
|
db ' <br><b>Экзамены:</b>'
|
||||||
|
.data = $ - sceleton_resp
|
||||||
|
db ' <br></body></html>'
|
||||||
|
.size = $ - sceleton_resp
|
||||||
|
|
||||||
|
|
||||||
|
bpo_data:
|
||||||
|
db 'Дискретка'
|
||||||
|
.size = $ - bpo_data
|
||||||
|
bpo_name:
|
||||||
|
db 'БПО09-23-21'
|
||||||
|
.size = $ - bpo_name
|
||||||
|
|
||||||
|
btp_data:
|
||||||
|
db 'Эти лохи химию сдают'
|
||||||
|
.size = $ - btp_data
|
||||||
|
btp_name:
|
||||||
|
db 'БТП-23-21'
|
||||||
|
.size = $ - btp_name
|
||||||
|
|
||||||
|
@EXPORT:
|
||||||
|
export \
|
||||||
|
unit_init, 'httpd_init', \
|
||||||
|
server_entry, 'httpd_serv'
|
||||||
|
|
||||||
|
|
||||||
|
IMPORT IMPORT_DATA ;
|
BIN
example/test_unit_2.obj
Normal file
BIN
example/test_unit_2.obj
Normal file
Binary file not shown.
@@ -1,6 +1,7 @@
|
|||||||
; This is a module for processing standard requests to get a file along
|
; This is a module for processing standard requests to get a file along
|
||||||
; a path that does not belong to another module.
|
; a path that does not belong to another module.
|
||||||
|
|
||||||
|
SIZE_FILE_BUFFER = 64*1024
|
||||||
|
|
||||||
file_server:
|
file_server:
|
||||||
|
|
||||||
@@ -90,7 +91,7 @@ file_server:
|
|||||||
.send_file:
|
.send_file:
|
||||||
; create http response (set 200 code, MINE type and length of body)
|
; create http response (set 200 code, MINE type and length of body)
|
||||||
;; alloc 33 kib
|
;; alloc 33 kib
|
||||||
push dword 33*1024
|
push dword SIZE_FILE_BUFFER
|
||||||
call Alloc
|
call Alloc
|
||||||
test eax, eax
|
test eax, eax
|
||||||
jz .err_http_501 ; error memory
|
jz .err_http_501 ; error memory
|
||||||
@@ -107,6 +108,11 @@ file_server:
|
|||||||
mov edi, [esp]
|
mov edi, [esp]
|
||||||
mov dword[edi + response.code], '200 '
|
mov dword[edi + response.code], '200 '
|
||||||
|
|
||||||
|
mov dword[edi + response.connection], 'keep'
|
||||||
|
mov dword[edi + response.connection + 4], '-ali'
|
||||||
|
mov word[edi + response.connection + 8], 've'
|
||||||
|
|
||||||
|
|
||||||
push dword[esp + 4] ; <-FILED
|
push dword[esp + 4] ; <-FILED
|
||||||
call Get_MIME_Type
|
call Get_MIME_Type
|
||||||
|
|
||||||
@@ -173,7 +179,7 @@ file_server:
|
|||||||
mov dword[ebx + FILED.offset], 0
|
mov dword[ebx + FILED.offset], 0
|
||||||
mov dword[ebx + FILED.offset + 4], 0
|
mov dword[ebx + FILED.offset + 4], 0
|
||||||
mov [ebx + FILED.buffer], edi
|
mov [ebx + FILED.buffer], edi
|
||||||
mov [ebx + FILED.size], 32*1024
|
mov [ebx + FILED.size], SIZE_FILE_BUFFER
|
||||||
.send_response_body:
|
.send_response_body:
|
||||||
; read 32 kib to file
|
; read 32 kib to file
|
||||||
push ebx
|
push ebx
|
||||||
@@ -181,11 +187,13 @@ file_server:
|
|||||||
test eax, eax
|
test eax, eax
|
||||||
jz @f
|
jz @f
|
||||||
cmp eax, 6
|
cmp eax, 6
|
||||||
|
|
||||||
|
mov [0], eax
|
||||||
jne .exit_free
|
jne .exit_free
|
||||||
@@:
|
@@:
|
||||||
; send this block data
|
; send this block data
|
||||||
push dword 0 ; flags
|
push dword 0 ; flags
|
||||||
push 32*1024
|
push SIZE_FILE_BUFFER
|
||||||
push edi
|
push edi
|
||||||
push dword[esi + CONNECT_DATA.socket]
|
push dword[esi + CONNECT_DATA.socket]
|
||||||
call netfunc_send
|
call netfunc_send
|
||||||
@@ -202,7 +210,7 @@ file_server:
|
|||||||
jbe .exit_free
|
jbe .exit_free
|
||||||
|
|
||||||
.add_offset:
|
.add_offset:
|
||||||
add [ebx + FILED.offset], 32*1024
|
add [ebx + FILED.offset], SIZE_FILE_BUFFER
|
||||||
adc [ebx + FILED.offset + 4], 0
|
adc [ebx + FILED.offset + 4], 0
|
||||||
|
|
||||||
jmp @b
|
jmp @b
|
||||||
|
24
httpd.asm
24
httpd.asm
@@ -4,9 +4,11 @@
|
|||||||
; ;
|
; ;
|
||||||
; httpd - Simple http server for Kolibri OS. ;
|
; httpd - Simple http server for Kolibri OS. ;
|
||||||
; ;
|
; ;
|
||||||
; Version 0.0.4, 12 November 2023 ;
|
; Version 0.1.0, 10 December 2023 ;
|
||||||
; ;
|
; ;
|
||||||
;*****************************************************************************;
|
;*****************************************************************************;
|
||||||
|
|
||||||
|
API_VERSION = 0x05 ; 0.0.5
|
||||||
;include "macros.inc"
|
;include "macros.inc"
|
||||||
use32
|
use32
|
||||||
org 0
|
org 0
|
||||||
@@ -43,7 +45,7 @@ START:
|
|||||||
jnz .err_settings
|
jnz .err_settings
|
||||||
|
|
||||||
;init server socket
|
;init server socket
|
||||||
push dword SO_NONBLOCK ; IPPROTO_TCP ?
|
push dword SO_NONBLOCK ;IPPROTO_TCP
|
||||||
push dword SOCK_STREAM
|
push dword SOCK_STREAM
|
||||||
push dword AF_INET4
|
push dword AF_INET4
|
||||||
call netfunc_socket; AF_INET4, SOCK_STREAM, SO_NONBLOCK ; we dont want to block on accept
|
call netfunc_socket; AF_INET4, SOCK_STREAM, SO_NONBLOCK ; we dont want to block on accept
|
||||||
@@ -253,6 +255,8 @@ httpd_import:
|
|||||||
dd 0
|
dd 0
|
||||||
|
|
||||||
EXPORT_DATA:
|
EXPORT_DATA:
|
||||||
|
dd API_VERSION
|
||||||
|
dd .size
|
||||||
dd netfunc_socket
|
dd netfunc_socket
|
||||||
dd netfunc_close
|
dd netfunc_close
|
||||||
dd netfunc_bind
|
dd netfunc_bind
|
||||||
@@ -264,15 +268,25 @@ EXPORT_DATA:
|
|||||||
dd FileRead
|
dd FileRead
|
||||||
dd Alloc
|
dd Alloc
|
||||||
dd Free
|
dd Free
|
||||||
|
dd parse_http_query ; no stdcall
|
||||||
|
|
||||||
|
dd send_resp
|
||||||
|
dd create_resp
|
||||||
|
dd destruct_resp
|
||||||
|
dd set_http_status
|
||||||
|
dd add_http_header
|
||||||
|
dd del_http_header
|
||||||
|
dd set_http_ver
|
||||||
|
|
||||||
dd base_response
|
dd base_response
|
||||||
dd GLOBAL_DATA
|
dd GLOBAL_DATA
|
||||||
|
.size = $ - EXPORT_DATA ; (count func)*4 + size(api ver) + 4
|
||||||
dd 0
|
dd 0
|
||||||
; DATA
|
; DATA
|
||||||
|
|
||||||
;UDATA
|
;UDATA
|
||||||
|
|
||||||
srv_backlog: rd 1 ; максимум одновременных подключений подключений
|
srv_backlog: rd 1 ; maximum number of simultaneous open connections
|
||||||
|
|
||||||
srv_socket: rd 1
|
srv_socket: rd 1
|
||||||
|
|
||||||
@@ -284,7 +298,7 @@ srv_sockaddr:
|
|||||||
.length = $ - srv_sockaddr
|
.length = $ - srv_sockaddr
|
||||||
|
|
||||||
GLOBAL_DATA:
|
GLOBAL_DATA:
|
||||||
.units rd 1 ; указатель на двусвязный не кольцевой(null terminator) список
|
.units rd 1 ; pointer to a doubly connected non-cyclic list (null terminator)
|
||||||
; next, prev, ptr of httpd_serv(), uri path
|
; next, prev, ptr of httpd_serv(), uri path
|
||||||
.work_dir rb 1024 ; max size path to work directory
|
.work_dir rb 1024 ; max size path to work directory
|
||||||
.work_dir.size rd 1 ; length string
|
.work_dir.size rd 1 ; length string
|
||||||
|
@@ -1,30 +1,30 @@
|
|||||||
|
|
||||||
align 4
|
;align 4
|
||||||
day:
|
;day:
|
||||||
dd 'Mon,'
|
; dd 'Mon,'
|
||||||
dd 'Tue,'
|
; dd 'Tue,'
|
||||||
dd 'Wed,'
|
; dd 'Wed,'
|
||||||
dd 'Thu,'
|
; dd 'Thu,'
|
||||||
dd 'Fri,'
|
; dd 'Fri,'
|
||||||
dd 'Sat,'
|
; dd 'Sat,'
|
||||||
dd 'Sun,'
|
; dd 'Sun,'
|
||||||
.count = ($ - day) / 4
|
;.count = ($ - day) / 4
|
||||||
|
;
|
||||||
align 4
|
;align 4
|
||||||
months:
|
;months:
|
||||||
dd 'Jan '
|
; dd 'Jan '
|
||||||
dd 'Feb '
|
; dd 'Feb '
|
||||||
dd 'Mar '
|
; dd 'Mar '
|
||||||
dd 'Apr '
|
; dd 'Apr '
|
||||||
dd 'May '
|
; dd 'May '
|
||||||
dd 'Jun '
|
; dd 'Jun '
|
||||||
dd 'Jul '
|
; dd 'Jul '
|
||||||
dd 'Aug '
|
; dd 'Aug '
|
||||||
dd 'Sep '
|
; dd 'Sep '
|
||||||
dd 'Oct '
|
; dd 'Oct '
|
||||||
dd 'Nov '
|
; dd 'Nov '
|
||||||
dd 'Dec '
|
; dd 'Dec '
|
||||||
.count = ($ - months) / 4 ; count item in this array
|
;.count = ($ - months) / 4 ; count item in this array
|
||||||
|
|
||||||
; HTTP-date = rfc1123-date | rfc850-date | asctime-date
|
; HTTP-date = rfc1123-date | rfc850-date | asctime-date
|
||||||
; rfc1123-date = wkday "," SP date1 SP time SP "GMT"
|
; rfc1123-date = wkday "," SP date1 SP time SP "GMT"
|
||||||
@@ -49,16 +49,16 @@ months:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
serv_header:
|
;serv_header:
|
||||||
.Accept_Ranges db 'Accept-Ranges: bytes',13,10
|
; .Accept_Ranges db 'Accept-Ranges: bytes',13,10
|
||||||
.connection db 'Connection: close',0
|
; .connection db 'Connection: close',0
|
||||||
|
|
||||||
http_method:
|
;http_method:
|
||||||
.get: db 'GET '
|
; .get: db 'GET '
|
||||||
.head: db 'HEAD'
|
; .head: db 'HEAD'
|
||||||
.post: db 'POST'
|
; .post: db 'POST'
|
||||||
.put: db 'PUT '
|
; .put: db 'PUT '
|
||||||
.patch db 'PATCH'
|
; .patch db 'PATCH'
|
||||||
|
|
||||||
;error_404:
|
;error_404:
|
||||||
; db '<html>'
|
; db '<html>'
|
||||||
@@ -83,6 +83,9 @@ http_method:
|
|||||||
; db 13, 10
|
; db 13, 10
|
||||||
;.size = $ - http_err_response
|
;.size = $ - http_err_response
|
||||||
|
|
||||||
|
default_http_version: db 'HTTP/1.1 '
|
||||||
|
.length = $ - default_http_version
|
||||||
|
|
||||||
http_response_err_501:
|
http_response_err_501:
|
||||||
db 'HTTP/1.1 '
|
db 'HTTP/1.1 '
|
||||||
db '501 ',13, 10
|
db '501 ',13, 10
|
||||||
@@ -119,7 +122,7 @@ http_response_options:
|
|||||||
|
|
||||||
base_response:
|
base_response:
|
||||||
response:
|
response:
|
||||||
db 'HTTP/1.0 '
|
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.0.1', 13, 10
|
||||||
@@ -134,11 +137,13 @@ response:
|
|||||||
db '0000000000000000000000', 13, 10
|
db '0000000000000000000000', 13, 10
|
||||||
db 'Content-type: '
|
db 'Content-type: '
|
||||||
.content_type = $ - response
|
.content_type = $ - response
|
||||||
db ' ', 13, 10;
|
db 'text/html ', 13, 10;
|
||||||
;'text/html; charset=utf-8'
|
;'text/html; charset=utf-8'
|
||||||
.end_headers: ; for adding new headers, and save connection(keep-alive)
|
db 'Connection: '
|
||||||
.connection = $ - response
|
.connection = $ - response
|
||||||
db 'Connection: close', 13, 10
|
db 'close ', 13, 10
|
||||||
|
; 'keep-alive'
|
||||||
|
.end_headers = $ - response ; for adding new headers
|
||||||
db 13, 10
|
db 13, 10
|
||||||
.body = $ - response ; offset for add http body in simple response
|
.body = $ - response ; offset for add http body in simple response
|
||||||
|
|
||||||
@@ -148,15 +153,15 @@ min_http_size = 18
|
|||||||
|
|
||||||
MIME_FILE_FORMAT:
|
MIME_FILE_FORMAT:
|
||||||
.html: db 5,'.html', 'text/html',0
|
.html: db 5,'.html', 'text/html',0
|
||||||
.css: db 4,'.css', 'text/css',0
|
.css: db 4,'.css', 'text/css ',0
|
||||||
.js: db 3,'.js', 'text/javascript',0
|
.js: db 3,'.js', 'text/javascript',0
|
||||||
.txt: db 4,'.txt', 'text/plain',0
|
.txt: db 4,'.txt', 'text/plain',0
|
||||||
.pdf: db 4,'.pdf', 'application/pdf',0
|
.pdf: db 4,'.pdf', 'application/pdf',0
|
||||||
.json: db 5,'.json', 'application/json',0
|
.json: db 5,'.json', 'application/json',0
|
||||||
|
|
||||||
.png: db 4,'.png', 'image/png',0
|
.png: db 4,'.png', 'image/png',0
|
||||||
.mp3: db 4,'.mp3', 'audio/mpeg',0
|
.mp3: db 4,'.mp3', 'audio/mpeg',0
|
||||||
.mp4: db 4,'.mp4', 'video/mp4',0
|
.mp4: db 4,'.mp4', 'video/mp4',0
|
||||||
.other: dd 0
|
.other: dd 0
|
||||||
db 'application/octet-stream',0 ; for unknow file - all file :)
|
db 'application/octet-stream',0 ; for unknow file - all file :)
|
||||||
|
|
||||||
|
93
parser.inc
93
parser.inc
@@ -2,23 +2,24 @@
|
|||||||
BASE_ARRAY_ARGS equ (esi - 1024)
|
BASE_ARRAY_ARGS equ (esi - 1024)
|
||||||
BASE_ARRAY_HEADERS equ (esi - 2048)
|
BASE_ARRAY_HEADERS equ (esi - 2048)
|
||||||
|
|
||||||
|
MAX_COUNT_ARG = 1024/(4+4)
|
||||||
|
MAX_COUNT_HEADER = 1024/(4+4)
|
||||||
|
|
||||||
;TODO: fix checking end http packed
|
;TODO: fix checking end http packed
|
||||||
|
|
||||||
; IN:
|
; IN:
|
||||||
; esi - struct
|
; esi - struct
|
||||||
; ecx = ptr to str URI
|
; ecx - ptr to str URI
|
||||||
; OUT:
|
; OUT:
|
||||||
; ecx - new base for reading data ('HTTP/1.1 ...')
|
; ecx = new base for reading data ('HTTP/1.1 ...')
|
||||||
; eax -
|
; eax = -1 - error
|
||||||
; NOTE: this function don`t check buffer size
|
; 0 - good
|
||||||
parse_url:
|
parse_url:
|
||||||
; URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
|
; URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
|
||||||
;
|
|
||||||
; hier-part = "//" authority path-abempty
|
; hier-part = "//" authority path-abempty
|
||||||
; / path-absolute
|
; / path-absolute
|
||||||
; / path-rootless
|
; / path-rootless
|
||||||
; / path-empty
|
; / path-empty
|
||||||
;
|
|
||||||
; foo://example.com:8042/over/there?name=ferret#nose
|
; foo://example.com:8042/over/there?name=ferret#nose
|
||||||
; \_/ \______________/\_________/ \_________/ \__/
|
; \_/ \______________/\_________/ \_________/ \__/
|
||||||
; | | | | |
|
; | | | | |
|
||||||
@@ -33,6 +34,9 @@ parse_url:
|
|||||||
;get scheme
|
;get scheme
|
||||||
mov [esi + CONNECT_DATA.uri_scheme], ecx
|
mov [esi + CONNECT_DATA.uri_scheme], ecx
|
||||||
@@:
|
@@:
|
||||||
|
cmp ecx, [esi + CONNECT_DATA.end_buffer_request]
|
||||||
|
ja .error_exit
|
||||||
|
|
||||||
inc ecx
|
inc ecx
|
||||||
cmp byte[ecx - 1], ':'
|
cmp byte[ecx - 1], ':'
|
||||||
jne @b
|
jne @b
|
||||||
@@ -44,7 +48,10 @@ parse_url:
|
|||||||
add ecx, 2
|
add ecx, 2
|
||||||
mov [esi + CONNECT_DATA.uri_authority], ecx
|
mov [esi + CONNECT_DATA.uri_authority], ecx
|
||||||
;get authority
|
;get authority
|
||||||
@@:
|
@@:
|
||||||
|
cmp ecx, [esi + CONNECT_DATA.end_buffer_request]
|
||||||
|
ja .error_exit
|
||||||
|
|
||||||
inc ecx
|
inc ecx
|
||||||
;cmp byte[ecx - 1], ' ' ;check end, не нужно, так как в http всегда / абс путь
|
;cmp byte[ecx - 1], ' ' ;check end, не нужно, так как в http всегда / абс путь
|
||||||
|
|
||||||
@@ -52,10 +59,14 @@ parse_url:
|
|||||||
jne @b
|
jne @b
|
||||||
dec ecx
|
dec ecx
|
||||||
.get_path:
|
.get_path:
|
||||||
;path-absolute
|
;ecx = path-absolute
|
||||||
mov [esi + CONNECT_DATA.uri_path], ecx
|
mov [esi + CONNECT_DATA.uri_path], ecx
|
||||||
@@:
|
@@:
|
||||||
inc ecx
|
inc ecx
|
||||||
|
|
||||||
|
cmp ecx, [esi + CONNECT_DATA.end_buffer_request]
|
||||||
|
ja .error_exit
|
||||||
|
|
||||||
cmp byte[ecx], '?'
|
cmp byte[ecx], '?'
|
||||||
je .get_query
|
je .get_query
|
||||||
|
|
||||||
@@ -77,11 +88,19 @@ parse_url:
|
|||||||
; add new item
|
; add new item
|
||||||
.get_query_new_arg:
|
.get_query_new_arg:
|
||||||
inc edx
|
inc edx
|
||||||
|
|
||||||
|
cmp edx, MAX_COUNT_HEADER
|
||||||
|
jae .error_exit
|
||||||
|
|
||||||
mov dword[BASE_ARRAY_ARGS + (edx-1)*8], ecx
|
mov dword[BASE_ARRAY_ARGS + (edx-1)*8], ecx
|
||||||
mov [esi + CONNECT_DATA.num_uri_args], edx
|
mov [esi + CONNECT_DATA.num_uri_args], edx
|
||||||
dec ecx
|
dec ecx
|
||||||
@@:
|
@@:
|
||||||
inc ecx
|
inc ecx
|
||||||
|
|
||||||
|
cmp ecx, [esi + CONNECT_DATA.end_buffer_request]
|
||||||
|
ja .error_exit
|
||||||
|
|
||||||
cmp byte[ecx], '='
|
cmp byte[ecx], '='
|
||||||
je .get_args
|
je .get_args
|
||||||
|
|
||||||
@@ -102,6 +121,10 @@ parse_url:
|
|||||||
dec ecx
|
dec ecx
|
||||||
@@:
|
@@:
|
||||||
inc ecx
|
inc ecx
|
||||||
|
|
||||||
|
cmp ecx, [esi + CONNECT_DATA.end_buffer_request]
|
||||||
|
ja .error_exit
|
||||||
|
|
||||||
cmp byte[ecx], '#'
|
cmp byte[ecx], '#'
|
||||||
je .get_fragment
|
je .get_fragment
|
||||||
|
|
||||||
@@ -124,22 +147,29 @@ parse_url:
|
|||||||
inc ecx
|
inc ecx
|
||||||
mov [esi + CONNECT_DATA.uri_fragment], ecx
|
mov [esi + CONNECT_DATA.uri_fragment], ecx
|
||||||
@@:
|
@@:
|
||||||
|
cmp ecx, [esi + CONNECT_DATA.end_buffer_request]
|
||||||
|
ja .error_exit
|
||||||
|
|
||||||
inc ecx
|
inc ecx
|
||||||
cmp byte[ecx - 1], ' '
|
cmp byte[ecx - 1], ' '
|
||||||
jne @b
|
jne @b
|
||||||
mov byte[ecx - 1], 0
|
mov byte[ecx - 1], 0
|
||||||
.exit:
|
.exit:
|
||||||
|
xor eax, eax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
.error_exit:
|
||||||
|
; set return value
|
||||||
|
mov eax, -1
|
||||||
|
ret
|
||||||
|
|
||||||
; IN:
|
; IN:
|
||||||
; esi - struct
|
; esi - struct
|
||||||
; ecx - ptr to begin headers block
|
; ecx - ptr to begin headers block
|
||||||
; edx - free mem ptr
|
|
||||||
; OUT:
|
; OUT:
|
||||||
; ecx - new base for reading body message HTTP query
|
; ecx = new base for reading body message HTTP query
|
||||||
; eax -
|
; eax = -1 - error
|
||||||
; NOTE: this function don`t check buffer size
|
; 0 - good
|
||||||
parse_headers:
|
parse_headers:
|
||||||
; init array
|
; init array
|
||||||
mov [esi + CONNECT_DATA.num_headers], 0
|
mov [esi + CONNECT_DATA.num_headers], 0
|
||||||
@@ -148,12 +178,10 @@ parse_headers:
|
|||||||
xor edx, edx
|
xor edx, edx
|
||||||
|
|
||||||
; for check size
|
; for check size
|
||||||
mov eax, [esi + CONNECT_DATA.request_size]
|
mov eax, [esi + CONNECT_DATA.end_buffer_request]
|
||||||
add eax, [esi + CONNECT_DATA.buffer_request]
|
|
||||||
|
|
||||||
.new_str:
|
.new_str:
|
||||||
cmp ecx, eax
|
cmp ecx, eax
|
||||||
jae .exit
|
jae .error_exit
|
||||||
|
|
||||||
cmp word[ecx], 0x0A0D ; \n
|
cmp word[ecx], 0x0A0D ; \n
|
||||||
jnz .find_header
|
jnz .find_header
|
||||||
@@ -161,12 +189,16 @@ parse_headers:
|
|||||||
; end find heeaders
|
; end find heeaders
|
||||||
mov byte[ecx], 0
|
mov byte[ecx], 0
|
||||||
add ecx, 2 ; ecx = base for body message
|
add ecx, 2 ; ecx = base for body message
|
||||||
|
xor eax, eax
|
||||||
ret
|
ret
|
||||||
|
.error_exit:
|
||||||
|
mov eax, -1
|
||||||
|
ret
|
||||||
|
|
||||||
.find_header:
|
.find_header:
|
||||||
; add new item in array headers
|
; add new item in array headers
|
||||||
cmp edx, 512 ; max count headers
|
cmp edx, MAX_COUNT_HEADER
|
||||||
jae .exit
|
jae .error_exit
|
||||||
|
|
||||||
inc edx
|
inc edx
|
||||||
mov dword[esi + CONNECT_DATA.num_headers], edx
|
mov dword[esi + CONNECT_DATA.num_headers], edx
|
||||||
@@ -175,9 +207,9 @@ parse_headers:
|
|||||||
dec ecx
|
dec ecx
|
||||||
@@:
|
@@:
|
||||||
inc ecx
|
inc ecx
|
||||||
|
; check size
|
||||||
cmp ecx, eax
|
cmp ecx, eax
|
||||||
jae .exit
|
jae .error_exit
|
||||||
|
|
||||||
cmp byte[ecx], ':'
|
cmp byte[ecx], ':'
|
||||||
jnz @b
|
jnz @b
|
||||||
@@ -187,12 +219,14 @@ parse_headers:
|
|||||||
; save pointer to value
|
; save pointer to value
|
||||||
mov dword[BASE_ARRAY_HEADERS + (edx-1)*8 + 4], ecx
|
mov dword[BASE_ARRAY_HEADERS + (edx-1)*8 + 4], ecx
|
||||||
@@:
|
@@:
|
||||||
|
; check size
|
||||||
cmp ecx, eax
|
cmp ecx, eax
|
||||||
jae .exit
|
jae .error_exit
|
||||||
|
|
||||||
inc ecx
|
inc ecx
|
||||||
cmp word[ecx - 1], 0x0A0D
|
cmp word[ecx - 1], 0x0A0D
|
||||||
jnz @b
|
jnz @b
|
||||||
|
|
||||||
mov byte[ecx - 1], 0
|
mov byte[ecx - 1], 0
|
||||||
inc ecx ; set offset on new string
|
inc ecx ; set offset on new string
|
||||||
jmp .new_str
|
jmp .new_str
|
||||||
@@ -201,7 +235,7 @@ parse_headers:
|
|||||||
; ecx - raw data query
|
; ecx - raw data query
|
||||||
; esi - ptr to CONNECT_DATA
|
; esi - ptr to CONNECT_DATA
|
||||||
; OUT: eax = 0 error
|
; OUT: eax = 0 error
|
||||||
; eax = prt to struct CONNECT_DATA
|
; eax = prt to struct CONNECT_DATA
|
||||||
parse_http_query:
|
parse_http_query:
|
||||||
;method scheme://host:port/abs_path HTTP/1.1 0x0d 0x0a
|
;method scheme://host:port/abs_path HTTP/1.1 0x0d 0x0a
|
||||||
;header_1:value 0x0d 0x0a
|
;header_1:value 0x0d 0x0a
|
||||||
@@ -230,15 +264,15 @@ parse_http_query:
|
|||||||
mov byte[ecx - 1], 0
|
mov byte[ecx - 1], 0
|
||||||
|
|
||||||
; check size
|
; check size
|
||||||
mov edx, ecx
|
cmp ecx, [esi + CONNECT_DATA.end_buffer_request]
|
||||||
sub edx, [esi + CONNECT_DATA.buffer_request]
|
ja .error_exit
|
||||||
sub edx, 2 ; / 0x20
|
|
||||||
cmp dword[esi + CONNECT_DATA.request_size], edx
|
|
||||||
jle .error_exit
|
|
||||||
|
|
||||||
; ecx <- uri string
|
; ecx <- uri string
|
||||||
; парсинг uri строки в заголовке запроса(получение схемы, пути аргументов, фрагмента и тд)
|
; parsing the URI string in the start line of the query
|
||||||
|
; (getting the schema, path, arguments, fragment, etc.)
|
||||||
call parse_url
|
call parse_url
|
||||||
|
test eax, eax
|
||||||
|
jnz .error_exit
|
||||||
|
|
||||||
; get http version(HTTP/1.1)
|
; get http version(HTTP/1.1)
|
||||||
mov [esi + CONNECT_DATA.http_verion], ecx
|
mov [esi + CONNECT_DATA.http_verion], ecx
|
||||||
@@ -261,7 +295,8 @@ parse_http_query:
|
|||||||
|
|
||||||
; get headers request (key + value string)
|
; get headers request (key + value string)
|
||||||
call parse_headers
|
call parse_headers
|
||||||
|
test eax, eax
|
||||||
|
jnz .error_exit
|
||||||
|
|
||||||
; check size
|
; check size
|
||||||
cmp ecx, [esi + CONNECT_DATA.end_buffer_request]
|
cmp ecx, [esi + CONNECT_DATA.end_buffer_request]
|
||||||
|
42
readme.md
Normal file
42
readme.md
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
|
||||||
|
# simple_http
|
||||||
|
Это небольшой http-сервер для Колибри ОС позволяющий хостить статичные сайты и создавать модули, для динамической генерации отправляемых клиенту данных.
|
||||||
|
|
||||||
|
Сервер отправляет содержимое файлов без сжатия в соответствии с заданной таблицей ассоциации MIME типа и расширения файла.
|
||||||
|
Если запрос от клиента имеет uri путь который соответствует модулю сервера, то сервер передаёт управление коду в этом модуле с передачей всех необходимых для функционирования данных.
|
||||||
|
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
Для настройки сервера применяется файл конфигурации в формате ini, где указываются следующие параметры:
|
||||||
|
|
||||||
|
В секции <CODE>MAIN</CODE>
|
||||||
|
- <CODE>ip</CODE> - ip адрес сервера
|
||||||
|
- <CODE>port</CODE> - порт для подключения (по умолчанию 80)
|
||||||
|
- <CODE>conn</CODE> - максимальное количество открытых соединений(по умолчанию 10)
|
||||||
|
- <CODE>work_dir</CODE> - директория для размещения файлов, отправляемых сервером
|
||||||
|
- <CODE>mime_file</CODE> - путь к файлу с таблицей сопоставлениея mime типов и расширений файлов (если не указан, то используется встроенная в сервер таблица сопоставления)
|
||||||
|
- <CODE>unit_dir</CODE> - директория расположения модулей сервера
|
||||||
|
|
||||||
|
В секции <CODE>UNITS</CODE> может находиться множество параметров, имеющих вид <CODE>uri_path=file_name</CODE> где:
|
||||||
|
- <CODE>uri_path</CODE> - путь указываемый клиентом во время запроса
|
||||||
|
- <CODE>file_name</CODE> - название/путь до файла модуля относительно <CODE>work_dir</CODE>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## API for units
|
||||||
|
|
||||||
|
К серверу можно подключить дополнительные модули в виде библиотек со специальными экспортируемыми функциями:
|
||||||
|
|
||||||
|
- <CODE>uint32_t stdcall httpd_init(IMPORT_DATA* import)</CODE>
|
||||||
|
|
||||||
|
Эта функция необходима для передачи модулю необходимых данных, таких как функции работы с сетью, рабочие директории и тд.
|
||||||
|
Если инициализация модуля прошла успешно, функция возвращает 0.
|
||||||
|
|
||||||
|
- <CODE>void stdcall httpd_server(CONNECT_DATA* request_data)</CODE>
|
||||||
|
Эта функция вызывается при получении запроса с uri путём указанном в файле конфигурации для этого модуля. Сервер передаёт в функцию структуру соединения, в которой находятся данные запроса(заголовки, параметры, http метод и версия). На основе этих данных функция может генерировать необходимый ответ.
|
||||||
|
|
||||||
|
|
||||||
|
## Bugs
|
||||||
|
|
||||||
|
- В ходе тестов был обнаружена ошибка отправки "больших" файлов. Это баг сетевого стека.
|
||||||
|
- При длительной работе сервер может начать "подзависать" или перестать отвечать на сообщения. Это баг сетевого стека.
|
36
settings.inc
36
settings.inc
@@ -27,6 +27,22 @@ struct HTTPD_UNIT
|
|||||||
uri_path rb 4096-3*4
|
uri_path rb 4096-3*4
|
||||||
ends
|
ends
|
||||||
|
|
||||||
|
struct RESPD
|
||||||
|
session rd 1
|
||||||
|
flags rd 1
|
||||||
|
http_status rd 1
|
||||||
|
http_ver_ptr rd 1
|
||||||
|
http_ver_len rd 1
|
||||||
|
buffer rd 1
|
||||||
|
buffer_size rd 1
|
||||||
|
http_body rd 1
|
||||||
|
count_header rd 1
|
||||||
|
header.ptr rd 1
|
||||||
|
header.len rd 1
|
||||||
|
rd 2*(64 - 1)
|
||||||
|
ends
|
||||||
|
|
||||||
|
|
||||||
struct REQUEST_DATA
|
struct REQUEST_DATA
|
||||||
ptr_name dd 0 ;
|
ptr_name dd 0 ;
|
||||||
ptr_data dd 0 ;
|
ptr_data dd 0 ;
|
||||||
@@ -41,6 +57,8 @@ load_settings:
|
|||||||
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
|
||||||
|
test eax, eax
|
||||||
|
jnz .error_exit2
|
||||||
; xxx.xxx.xxx.xxx\n - 16 byte max
|
; xxx.xxx.xxx.xxx\n - 16 byte max
|
||||||
xor edx, edx
|
xor edx, edx
|
||||||
xor eax, eax
|
xor eax, eax
|
||||||
@@ -76,7 +94,10 @@ load_settings:
|
|||||||
; flags
|
; flags
|
||||||
|
|
||||||
; work_dir
|
; work_dir
|
||||||
invoke ini.get_str, ebp, ini_section_main, ini_key_work_dir, GLOBAL_DATA.work_dir, 1024, 0
|
invoke ini.get_str, ebp, ini_section_main, ini_key_work_dir, GLOBAL_DATA.work_dir, 1024, 0
|
||||||
|
test eax, eax
|
||||||
|
jnz .error_exit
|
||||||
|
|
||||||
push edi
|
push edi
|
||||||
mov ecx, 1024
|
mov ecx, 1024
|
||||||
mov edi, GLOBAL_DATA.work_dir
|
mov edi, GLOBAL_DATA.work_dir
|
||||||
@@ -87,12 +108,14 @@ load_settings:
|
|||||||
mov [GLOBAL_DATA.work_dir.size], edi
|
mov [GLOBAL_DATA.work_dir.size], edi
|
||||||
pop edi
|
pop edi
|
||||||
|
|
||||||
; TODO: get mime file
|
; get mime file
|
||||||
;mov dword[GLOBAL_DATA.MIME_types_arr], STD_MIME_TYPE_ARR
|
|
||||||
call load_mime_file
|
call load_mime_file
|
||||||
|
|
||||||
; units_dir
|
; units_dir
|
||||||
invoke ini.get_str, ebp, ini_section_main, ini_key_units_dir, GLOBAL_DATA.unit_dir, 1024, 0
|
invoke ini.get_str, ebp, ini_section_main, ini_key_units_dir, GLOBAL_DATA.unit_dir, 1024, 0
|
||||||
|
test eax, eax
|
||||||
|
jnz .no_units
|
||||||
|
|
||||||
push edi
|
push edi
|
||||||
mov ecx, 1024
|
mov ecx, 1024
|
||||||
mov edi, GLOBAL_DATA.unit_dir
|
mov edi, GLOBAL_DATA.unit_dir
|
||||||
@@ -104,7 +127,7 @@ load_settings:
|
|||||||
|
|
||||||
; get all units
|
; get all units
|
||||||
invoke ini.enum_keys, ebp, ini_section_units, .add_unit
|
invoke ini.enum_keys, ebp, ini_section_units, .add_unit
|
||||||
|
.no_units:
|
||||||
xor eax, eax
|
xor eax, eax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
@@ -176,7 +199,10 @@ load_settings:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
.err:
|
.error_exit2:
|
||||||
|
add esp, 16
|
||||||
|
.error_exit:
|
||||||
|
mov eax, -1
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
239
sys_func.inc
239
sys_func.inc
@@ -214,4 +214,241 @@ FileRead:
|
|||||||
mov dword[ebx], 0 ; read file
|
mov dword[ebx], 0 ; read file
|
||||||
mcall 70
|
mcall 70
|
||||||
pop ebx
|
pop ebx
|
||||||
ret 4
|
ret 4
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
FLAG_KEEP_ALIVE = 0x01
|
||||||
|
FLAG_ADD_DATE = 0x02 ;(not supported)
|
||||||
|
FLAG_NO_SET_CACHE = 0x04 ;(not supported)
|
||||||
|
FLAG_NO_CONTENT_ENCODING = 0x08 ;(not supported)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;RESPD* stdcall create_resp(CONNECT_DATA* session, uint32_t flags)
|
||||||
|
create_resp:
|
||||||
|
stdcall Alloc, sizeof.RESPD
|
||||||
|
test eax, eax
|
||||||
|
jz .exit
|
||||||
|
|
||||||
|
mov edx, [esp + 4]
|
||||||
|
mov ecx, [esp + 8]
|
||||||
|
mov [eax + RESPD.flags], ecx
|
||||||
|
mov [eax + RESPD.session], edx
|
||||||
|
; set default values
|
||||||
|
mov [eax + RESPD.http_status], '200 '
|
||||||
|
mov [eax + RESPD.http_ver_ptr], default_http_version
|
||||||
|
mov [eax + RESPD.http_ver_len], default_http_version.length
|
||||||
|
mov [eax + RESPD.count_header], 0
|
||||||
|
.exit:
|
||||||
|
ret 8
|
||||||
|
|
||||||
|
;void destruct_resp(RESPD* ptr)
|
||||||
|
destruct_resp:
|
||||||
|
stdcall Free, [esp + 4]
|
||||||
|
ret 4
|
||||||
|
|
||||||
|
;void set_http_status(RESPD* ptr, uint32_t status) // status in '200' format
|
||||||
|
set_http_status:
|
||||||
|
mov eax, [esp + 4]
|
||||||
|
mov ecx, [esp + 8]
|
||||||
|
and ecx, 0x00ffffff ; clear 3 byte register
|
||||||
|
add ecx, 0x20 shl 24 ; set 3 byte in ' '
|
||||||
|
mov [eax + RESPD.http_status], ecx
|
||||||
|
ret 8
|
||||||
|
;void set_http_ver(RESPD* ptr, char* version, uint32_t length) // example: 'RTSP/1.1 '
|
||||||
|
set_http_ver:
|
||||||
|
mov eax, [esp + 4]
|
||||||
|
mov ecx, [esp + 8]
|
||||||
|
mov edx, [esp + 12]
|
||||||
|
mov [eax + RESPD.http_ver_ptr], ecx
|
||||||
|
mov [eax + RESPD.http_ver_len], edx
|
||||||
|
|
||||||
|
ret 12
|
||||||
|
|
||||||
|
;uint32_t add_http_header(RESPD* ptr, char* ptr_header, uint32_t length)
|
||||||
|
add_http_header:
|
||||||
|
mov eax, [esp + 4]
|
||||||
|
mov ecx, [eax + RESPD.count_header]
|
||||||
|
cmp ecx, 64
|
||||||
|
jz .err
|
||||||
|
|
||||||
|
inc dword[eax + RESPD.count_header]
|
||||||
|
mov edx, [esp + 8]
|
||||||
|
mov [eax + ecx*8 + RESPD.header.ptr], edx
|
||||||
|
mov edx, [esp + 12]
|
||||||
|
mov [eax + ecx*8 + RESPD.header.len], edx
|
||||||
|
mov eax, ecx
|
||||||
|
ret 12
|
||||||
|
.err:
|
||||||
|
mov eax, -1
|
||||||
|
ret 12
|
||||||
|
|
||||||
|
|
||||||
|
;uint32_t del_http_header(RESPD* ptr, char* ptr_header) // no del std header
|
||||||
|
del_http_header:
|
||||||
|
mov eax, [esp + 4]
|
||||||
|
mov edx, [esp + 8]
|
||||||
|
mov ecx, [eax + RESPD.count_header]
|
||||||
|
add eax, RESPD.header.ptr
|
||||||
|
@@:
|
||||||
|
test ecx, ecx
|
||||||
|
jz .err
|
||||||
|
|
||||||
|
cmp [eax], edx
|
||||||
|
je .found
|
||||||
|
|
||||||
|
add eax, 8
|
||||||
|
dec ecx
|
||||||
|
jmp @b
|
||||||
|
.found:
|
||||||
|
dec ecx ; skiip one item
|
||||||
|
@@:
|
||||||
|
test ecx, ecx
|
||||||
|
jz .exit
|
||||||
|
mov edx, [eax + 8]
|
||||||
|
mov [eax], edx
|
||||||
|
mov edx, [eax + 8 + 4]
|
||||||
|
mov [eax + 4], edx
|
||||||
|
|
||||||
|
add eax, 8
|
||||||
|
jmp @b
|
||||||
|
.exit:
|
||||||
|
mov ecx, [esp + 4]
|
||||||
|
inc dword[ecx + RESPD.count_header]
|
||||||
|
ret 8
|
||||||
|
.err:
|
||||||
|
mov eax, -1
|
||||||
|
ret 8
|
||||||
|
|
||||||
|
|
||||||
|
;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
|
||||||
|
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
|
||||||
|
|
||||||
|
cmp eax, -1
|
||||||
|
jz .exit
|
||||||
|
; send content
|
||||||
|
|
||||||
|
mov ecx, [esp + 4*3 + 8] ; ptr
|
||||||
|
test ecx, ecx
|
||||||
|
jz .free
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
cmp eax, -1
|
||||||
|
jz .exit
|
||||||
|
.free:
|
||||||
|
xor eax, eax
|
||||||
|
; free buffer
|
||||||
|
push eax
|
||||||
|
stdcall Free, [ebp + RESPD.buffer]
|
||||||
|
pop eax
|
||||||
|
.exit:
|
||||||
|
pop ebp edi esi
|
||||||
|
ret 12
|
||||||
|
|
||||||
|
.error_alloc:
|
||||||
|
mov eax, -1
|
||||||
|
jmp .exit
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user