;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Tiny HTTP Server v 0.4 for MenuetOS ; ; ; ; License GPL / See file COPYING for details. ; ; Copyright 2003 Ville Turjanmaa ; ; ; ; Compile with FASM for Menuet ; ; ; ; Request /TinyStat for server statistics ; ; Request /TinyBoard for server message board ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; version equ '0.4' use32 org 0x0 db 'MENUET01' ; 8 byte id dd 0x01 ; required os dd START ; program start dd I_END ; program image size dd 0x400000 ; required amount of memory dd 0x20000 dd 0,0 ; reserved=no extended header include 'lang.inc' include "macros.inc" ; 0x0+ - program image ; 0x1ffff - stack ; 0x20000+ - message board ; 0x100000+ - requested file filel: dd 0x0,0x0,50000/512,0x20000,0x70000 db '/rd/1/board.htm',0 files: dd 0x1,0x0,0x0,0x20000,0x70000 db '/rd/1/board.htm',0 START: ; start of execution mov eax,58 mov ebx,filel int 0x40 mov [board_size],ebx cmp eax,0 je board_found mov [board_size],board_end-board mov esi,board mov edi,0x20000 mov ecx,[board_size] cld rep movsb board_found: mov eax,58 mov ebx,files mov ecx,[board_size] mov [files+8],ecx int 0x40 mov [status],-1 mov [last_status],-2 call clear_input call draw_window ; at first, draw the window ; call ops still: call check_status cmp [status],4 je start_transmission cmp [status],0 jne nnn cmp [server_active],1 jne nnn call ops nnn: mov eax,5 mov ebx,1 int 0x40 mov eax,11 int 0x40 call check_events jmp still reb: ; boot mov eax,18 mov ebx,1 int 0x40 jmp $ last_status dd 0x0 check_events: cmp eax,1 ; redraw request ? jz red cmp eax,2 ; key in buffer ? jz key cmp eax,3 ; button in buffer ? jz button ret red: ; redraw call draw_window ret key: ; Keys are not valid at this part of the mov eax,2 ; loop. Just read it and ignore int 0x40 ret button: ; button mov eax,17 ; get id int 0x40 cmp ah,1 ; close jnz tst2 mov eax,53 mov ebx,8 mov ecx,[socket] int 0x40 mov eax,-1 int 0x40 tst2: cmp ah,2 ; button id=2 ? jnz tst3 ; open socket ops: mov eax,53 mov ebx,5 mov ecx,80 ; local port # - http mov edx,0 ; no remote port specified mov esi,0 ; no remote ip specified mov edi,0 ; PASSIVE open int 0x40 mov [socket], eax mov [posy],1 mov [posx],0 call check_for_incoming_data call clear_input call draw_data mov [server_active],1 call check_status ; cmp [status],0 ; je reb ret tst3: cmp ah,4 ; button id=4 ? jnz no4 mov [server_active],0 close_socket: mov eax,53 mov ebx,8 mov ecx,[socket] int 0x40 mov eax,5 mov ebx,2 int 0x40 mov eax,53 mov ebx,8 mov ecx,[socket] int 0x40 cmp [server_active],1 jne no_re_open mov eax,53 mov ebx,5 mov ecx,80 ; local port # - http mov edx,0 ; no remote port specified mov esi,0 ; no remote ip specified mov edi,0 ; PASSIVE open int 0x40 mov [socket], eax no_re_open: mov edi,input_text+256*15+1 mov [edi+2],dword ': :' call set_time mov edi,input_text+256*16+1 mov [edi+2],dword '. .' call set_date mov eax,[documents_served] mov ecx,9 mov edi,input_text+256*15+12 call set_value mov eax,[bytes_transferred] mov ecx,9 mov edi,input_text+256*16+12 call set_value call draw_data mov esp,0x1ffff jmp still no4: cmp ah,6 ; read directory je read_string ret clear_input: mov edi,input_text mov eax,0 mov ecx,256*30 cld rep stosb ret retries dd 50 start_transmission: mov [posy],1 mov [posx],0 call clear_input mov [retries],50 wait_for_data: call check_for_incoming_data cmp [input_text+256+1],dword 'GET ' je data_received cmp [input_text+256+1],dword 'POST' je data_received mov eax,5 mov ebx,1 int 0x40 dec [retries] jnz wait_for_data jmp no_http_request data_received: mov eax,0x100000 mov ebx,0x2f0000 / 512 call read_file call wait_for_empty_slot call send_header mov [filepos],0x100000 mov [fileadd],700 call check_status call draw_data newblock: call wait_for_empty_slot mov edx,[fileadd] cmp edx,[file_left] jbe file_size_ok mov edx,[file_left] file_size_ok: sub [file_left],edx ; write to socket mov eax,53 mov ebx,7 mov ecx,[socket] mov esi,[filepos] int 0x40 mov eax,esi add eax,edx sub eax,0x100000 call display_progress mov edx,[fileadd] add [filepos],edx cmp [file_left],0 jg newblock no_http_request: jmp close_socket filepos dd 0x100000 fileadd dd 0x1 filesize dd 0x0 file_left dd 0x0 wait_for_empty_slot: pusha wait_more: ; rdtsc ; mov ecx,eax ; add ecx,1000000 ; wr: ; rdtsc ; cmp eax,ecx ; jb wr mov eax,5 mov ebx,1 int 0x40 mov eax,11 int 0x40 call check_events mov eax,53 mov ebx,255 mov ecx,103 int 0x40 cmp eax,0 je no_wait_more jmp wait_more no_wait_more: popa ret display_progress: pusha mov edi,eax mov eax,13 mov ebx,115*65536+8*6 mov ecx,178*65536+10 mov edx,0xffffff int 0x40 mov eax,47 mov ebx,8*65536 mov ecx,edi mov edx,115*65536+178 mov esi,0x000000 int 0x40 popa ret send_header: pusha mov eax,53 ; send response and file length mov ebx,7 mov ecx,[socket] mov edx,h_len-html_header mov esi,html_header int 0x40 mov eax,53 ; send file type mov ebx,7 mov ecx,[socket] mov edx,[type_len] mov esi,[file_type] int 0x40 popa ret fileinfo dd 0,0,1,0x100000,0xf0000 getf db '/RD/1/' times 50 db 0 wanted_file: times 100 db 0 getflen dd 6 make_room: pusha mov edx,ecx mov esi,0x20000 add esi,[board_size] mov edi,esi add edi,edx mov ecx,[board_size] sub ecx,board1-board inc ecx std rep movsb cld popa ret from_i dd 0x0 from_len dd 0x0 message dd 0x0 message_len dd 0x0 read_file: ; start of execution mov [fileinfo+12],eax mov [fileinfo+8],ebx mov [file_type],unk mov [type_len],unkl-unk mov [filename+40*2+6],dword 'UNK ' cmp [input_text+256+1],dword 'POST' je yes_new_message cmp [input_text+256+11],dword 'oard' ; server board message jne no_server_message_2 yes_new_message: mov eax,58 mov ebx,filel int 0x40 mov [board_size],ebx cmp [input_text+256+1],dword 'POST' jne no_new_message mov edi,bsmt call set_time mov edi,bsmd call set_date call check_for_incoming_data mov esi,input_text+256 ; from newfroms: inc esi cmp esi,input_text+256*20 je no_server_message_2 cmp [esi],dword 'from' jne newfroms add esi,5 mov [from_i],esi mov edx,0 name_new_len: cmp [esi+edx],byte 13 je name_found_len cmp [esi+edx],byte '&' je name_found_len cmp edx,1000 je name_found_len inc edx jmp name_new_len name_found_len: mov [from_len],edx mov esi,input_text+256 newmessages: inc esi cmp esi,input_text+256*20 je no_server_message_2 cmp [esi],dword 'sage' jne newmessages add esi,5 mov [message],esi mov edx,0 new_len: inc edx cmp [esi+edx],byte ' ' je found_len cmp [esi+edx],byte 13 jbe found_len cmp edx,input_text+5000 je found_len jmp new_len found_len: mov [message_len],edx mov edx,0 change_letters: cmp [esi+edx],byte '+' jne no_space mov [esi+edx],byte ' ' no_space: cmp [esi+edx+1],word '0D' jne no_br mov [esi+edx],dword '
' mov [esi+edx+4],word ' ' no_br: cmp [esi+edx],byte '%' jne no_ascii movzx eax,byte [esi+edx+2] sub eax,48 cmp eax,9 jbe eax_ok sub eax,7 eax_ok: movzx ebx,byte [esi+edx+1] sub ebx,48 cmp ebx,9 jbe ebx_ok sub ebx,7 ebx_ok: imul ebx,16 add ebx,eax mov [esi+edx],bl mov [esi+edx+1],word ' ' add edx,2 no_ascii: inc edx cmp edx,[message_len] jbe change_letters mov edx,board1e-board1 + board2e-board2 + board3e-board3 add edx,[from_len] add edx,[message_len] add [board_size],edx mov ecx,edx call make_room mov esi,board1 ; first part mov edi,0x20000 add edi,board1-board mov ecx,edx cld rep movsb mov esi,[from_i] ; name mov edi,0x20000 add edi,board1-board + board1e-board1 mov ecx,[from_len] cld rep movsb mov esi,board2 ; middle part mov edi,0x20000 add edi,board1-board + board1e-board1 add edi,[from_len] mov ecx,board2e-board2 cld rep movsb mov esi,[message] ; message mov edi,0x20000 add edi,board1-board + board1e-board1 +board2e-board2 add edi,[from_len] mov ecx,[message_len] cld rep movsb mov esi,board3 ; end part mov edi,0x20000 add edi,board1-board + board1e-board1 +board2e-board2 add edi,[from_len] add edi,[message_len] mov ecx,board3e-board3 cld rep movsb inc [board_messages] mov eax,[board_size] mov [files+8],eax mov eax,58 mov ebx,files int 0x40 no_new_message: mov esi,0x20000 mov edi,0x100000 mov ecx,[board_size] cld rep movsb mov ebx,[board_size] mov [file_type],htm mov [type_len],html-htm mov [filename+40*2+6],dword 'HTM ' jmp file_loaded no_server_message_2: cmp [input_text+256+9],dword 'ySta' ; server message jne no_server_message_1 mov edi,smt call set_time mov edi,smd call set_date mov eax,[documents_served] mov ecx,9 mov edi,sms+21 call set_value mov eax,[bytes_transferred] mov ecx,9 mov edi,smb+21 call set_value mov eax,[board_messages] mov ecx,9 mov edi,smm+21 call set_value mov eax,[board_size] mov ecx,9 mov edi,smz+21 call set_value mov esi,sm mov edi,0x100000 mov ecx,sme-sm cld rep movsb mov ebx,sme-sm mov [file_type],htm mov [type_len],html-htm mov [filename+40*2+6],dword 'HTM ' jmp file_loaded no_server_message_1: mov esi,input_text+256+6 cmp [input_text+256+1],dword 'GET ' jne no_new_let mov edi,wanted_file cld new_let: cmp [esi],byte ' ' je no_new_let cmp edi,wanted_file+30 jge no_new_let movsb jmp new_let no_new_let: mov [edi+0],dword 0 mov [edi+4],dword 0 mov [edi+8],dword 0 cmp esi,input_text+256+6 jne no_index mov edi,wanted_file mov [edi+0],dword 'inde' mov [edi+4],dword 'x.ht' mov [edi+8],byte 'm' mov [edi+9],byte 0 add edi,9 mov [file_type],htm mov [type_len],html-htm mov [filename+40*2+6],dword 'HTM ' jmp html_file no_index: cmp [edi-3],dword 'htm'+0 je htm_header cmp [edi-3],dword 'HTM'+0 je htm_header jmp no_htm_header htm_header: mov [file_type],htm mov [type_len],html-htm mov [filename+40*2+6],dword 'HTM ' jmp found_file_type no_htm_header: cmp [edi-3],dword 'png'+0 je png_header cmp [edi-3],dword 'PNG'+0 je png_header jmp no_png_header png_header: mov [file_type],png mov [type_len],pngl-png mov [filename+40*2+6],dword 'PNG ' jmp found_file_type no_png_header: cmp [edi-3],dword 'gif'+0 je gif_header cmp [edi-3],dword 'GIF'+0 je gif_header jmp no_gif_header gif_header: mov [file_type],gif mov [type_len],gifl-gif mov [filename+40*2+6],dword 'GIF ' jmp found_file_type no_gif_header: cmp [edi-3],dword 'jpg'+0 je jpg_header cmp [edi-3],dword 'JPG'+0 je jpg_header jmp no_jpg_header jpg_header: mov [file_type],jpg mov [type_len],jpgl-jpg mov [filename+40*2+6],dword 'JPG ' jmp found_file_type no_jpg_header: cmp [edi-3],dword 'asm'+0 je txt_header cmp [edi-3],dword 'ASM'+0 je txt_header cmp [edi-3],dword 'txt'+0 je txt_header cmp [edi-3],dword 'TXT'+0 je txt_header jmp no_txt_header txt_header: mov [file_type],txt mov [type_len],txtl-txt mov [filename+40*2+6],dword 'TXT ' jmp found_file_type no_txt_header: html_file: found_file_type: mov edi,getf add edi,[getflen] mov esi,wanted_file mov ecx,40 cld rep movsb mov esi,getf mov edi,filename mov ecx,35 cld rep movsb mov [fileinfo+8],dword 1 ; file exists ? mov eax,58 mov ebx,fileinfo int 0x40 cmp eax,0 ; file not found - message je file_found mov edi,et call set_time mov edi,ed call set_date mov esi,fnf mov edi,0x100000 mov ecx,fnfe-fnf cld rep movsb mov ebx,fnfe-fnf mov [file_type],htm mov [type_len],html-htm mov [filename+40*2+6],dword 'HTM ' jmp file_not_found file_found: mov [fileinfo+8],dword 0x2f0000 / 512 ; read all of file mov eax,58 mov ebx,fileinfo int 0x40 file_not_found: file_loaded: and ebx,0x3fffff mov [filesize],ebx mov [file_left],ebx mov eax,ebx mov edi,c_l+5 mov ebx,10 newl: xor edx,edx div ebx mov ecx,edx add cl,48 mov [edi],cl dec edi cmp edi,c_l jge newl mov esi,c_l mov edi,filename+46 mov ecx,7 cld rep movsb inc [documents_served] mov eax,[filesize] add [bytes_transferred],eax call draw_data ret set_value: pusha add edi,ecx mov ebx,10 new_value: xor edx,edx div ebx add dl,48 mov [edi],dl dec edi loop new_value popa ret set_time: pusha mov eax,3 int 0x40 mov ecx,3 new_time_digit: mov ebx,eax and ebx,0xff shl ebx,4 shr bl,4 add bx,48*256+48 mov [edi],bh mov [edi+1],bl add edi,3 shr eax,8 loop new_time_digit popa ret set_date: pusha mov eax,29 int 0x40 mov ecx,3 add edi,6 new_date_digit: mov ebx,eax and ebx,0xff shl ebx,4 shr bl,4 add bx,48*256+48 mov [edi],bh mov [edi+1],bl sub edi,3 shr eax,8 loop new_date_digit popa ret check_for_incoming_data: pusha check: mov eax, 53 mov ebx, 2 mov ecx, [socket] int 0x40 cmp eax,0 je _ret_now new_data: mov eax,53 mov ebx,2 mov ecx,[socket] int 0x40 cmp eax,0 je _ret mov eax,53 mov ebx,3 mov ecx,[socket] int 0x40 cmp bl,10 jne no_lf inc [posy] mov [posx],0 jmp new_data no_lf: cmp bl,20 jb new_data inc [posx] cmp [posy],20 jbe yok mov [posy],1 yok: mov eax,[posy] imul eax,256 add eax,[posx] mov [input_text+eax],bl jmp new_data _ret: call draw_data mov eax,5 mov ebx,1 cmp [input_text+256+1],dword 'POST' jne no_ld mov ebx,50 no_ld: int 0x40 jmp check _ret_now: popa ret posy dd 1 posx dd 0 check_status: pusha mov eax,53 mov ebx,6 mov ecx,[socket] int 0x40 cmp eax,[status] je c_ret mov [status],eax add al,48 mov [text+12],al call draw_data c_ret: popa ret addr dd 0x0 ya dd 0x0 filename2: times 100 db 32 read_string: mov [addr],dword getf mov [ya],dword 139 mov edi,[addr] mov eax,0 mov ecx,30 cld rep stosb call print_text mov edi,[addr] f11: mov eax,10 int 0x40 cmp eax,2 jne read_done mov eax,2 int 0x40 shr eax,8 cmp eax,13 je read_done cmp eax,8 jnz nobsl cmp edi,[addr] jz f11 sub edi,1 mov [edi],byte 32 call print_text jmp f11 nobsl: mov [edi],al call print_text add edi,1 mov esi,[addr] add esi,30 cmp esi,edi jnz f11 read_done: push edi mov ecx,40 mov eax,32 cld rep stosb call print_text pop edi sub edi,[addr] mov [getflen],edi mov esi,getf mov edi,dirp+12 mov ecx,28 cld rep movsb jmp still print_text: pusha mov eax,13 mov ebx,97*65536+23*6 mov ecx,[ya] shl ecx,16 mov cx,9 mov edx,0xffffff int 0x40 mov eax,4 mov edx,[addr] mov ebx,97*65536 add ebx,[ya] mov ecx,0x000000 mov esi,23 int 0x40 popa ret ; ********************************************* ; ******* WINDOW DEFINITIONS AND DRAW ******** ; ********************************************* draw_window: mov eax,12 ; function 12:tell os about windowdraw mov ebx,1 ; 1, start of draw int 0x40 ; DRAW WINDOW mov eax,0 ; function 0 : define and draw window mov ebx,100*65536+480 ; [x start] *65536 + [x size] mov ecx,100*65536+215 ; [y start] *65536 + [y size] mov edx,0x03ffffff ; color of work area RRGGBB mov esi,0x8050a0b0 ; color of grab bar RRGGBB,8->color gl mov edi,0x0050a0b0 ; color of frames RRGGBB int 0x40 ; WINDOW LABEL mov eax,4 ; function 4 : write text to window mov ebx,8*65536+8 ; [x start] *65536 + [y start] mov ecx,0x10ffffff ; color of text RRGGBB mov edx,labelt ; pointer to text beginning mov esi,labellen-labelt ; text length int 0x40 mov eax,8 ; function 8 : define and draw button mov ebx,(40)*65536+20 ; [x start] *65536 + [x size] mov ecx,59*65536+9 ; [y start] *65536 + [y size] mov edx,2 ; button id mov esi,0x66aa66 ; button color RRGGBB int 0x40 mov eax,8 ; function 8 : define and draw button mov ebx,(40)*65536+20 ; [x start] *65536 + [x size] mov ecx,72*65536+9 ; [y start] *65536 + [y size] mov edx,4 ; button id mov esi,0xaa6666 ; button color RRGGBB int 0x40 mov eax,8 ; Enter directory mov ebx,(25)*65536+66 mov ecx,135*65536+15 mov edx,6 mov esi,0x3388dd int 0x40 mov eax,38 mov ebx,240*65536+240 mov ecx,22*65536+210 mov edx,0x6699cc ; 002288 int 0x40 mov eax,38 mov ebx,241*65536+241 mov ecx,22*65536+210 mov edx,0x336699 ; 002288 int 0x40 call draw_data mov eax,12 ; function 12:tell os about windowdraw mov ebx,2 ; 2, end of draw int 0x40 ret draw_data: pusha mov ebx,25*65536+35 ; draw info text with function 4 mov ecx,0x000000 mov edx,text mov esi,35 newline: pusha cmp ebx,25*65536+61 je now cmp ebx,25*65536+74 je now cmp ebx,25*65536+74+13*5 je now mov ecx,ebx mov bx,35*6 shl ecx,16 mov cx,9 mov eax,13 mov edx,0xffffff int 0x40 now: popa mov eax,4 int 0x40 add ebx,13 add edx,40 cmp [edx],byte 'x' jnz newline mov [input_text+0],dword 'RECE' mov [input_text+4],dword 'IVED' mov [input_text+8],dword ': ' mov ebx,255*65536+35 ; draw info text with function 4 mov ecx,0x000000 mov edx,input_text mov esi,35 mov edi,17 newline2: pusha mov ecx,ebx mov bx,35*6 shl ecx,16 mov cx,9 mov eax,13 mov edx,0xffffff int 0x40 popa mov eax,4 int 0x40 add ebx,10 add edx,256 dec edi jnz newline2 popa ret ; DATA AREA status dd 0x0 text: db 'TCB status: x ' db ' ' db ' Activate server ' db ' Stop server ' db ' ' db 'Requests: /TinyStat -statistics ' db ' /TinyBoard -message board ' db ' ' dirp: db ' Files: /RD/1/ ' db ' ' filename: db ' ' db 'Size: ------- ' db 'Type: --- ' db 'x' ; <- END MARKER, DONT DELETE html_header: db 'HTTP/1.0 200 OK',13,10 db 'Server: MenuetOS HTTP Server',13,10 db 'Content-Length: ' c_l: db '000000',13,10 h_len: fnf: db '' db '
'
     db  "TinyServer v ",version," for MenuetOS",13,10,13,10
     db  "Error 404 - File not found.",13,10,13,10
     db  "For more info about server: request /TinyStat",13,10,13,10
et:  db  "xx:xx:xx",13,10
ed:  db  "xx.xx.xx",13,10
     db  "
" fnfe: sm: db '' db '
'
     db  "TinyServer v ",version," for MenuetOS",13,10,13,10
     db  "Statistics: (before current request)",13,10,13,10
sms: db  "- Documents served  : xxxxxxxxx",13,10
smb: db  "- Bytes transferred : xxxxxxxxx",13,10
     db  "- Location          : /TinyStat",13,10,13,10
     db  "TinyBoard:",13,10,13,10
smm: db  "- Messages          : xxxxxxxxx",13,10
smz: db  "- Size in bytes     : xxxxxxxxx",13,10
     db  "- Location          : /TinyBoard",13,10,13,10
smt: db  "xx:xx:xx",13,10
smd: db  "xx.xx.xx",13,10
     db  '
' sme: documents_served dd 0x0 bytes_transferred dd 0x0 file_type dd 0 type_len dd 0 htm: db 'Content-Type: text/html',13,10,13,10 html: txt: db 'Content-Type: text/plain',13,10,13,10 txtl: png: db 'Content-Type: image/png',13,10,13,10 pngl: gif: db 'Content-Type: image/gif',13,10,13,10 gifl: jpg: db 'Content-Type: image/jpeg',13,10,13,10 jpgl: unk: db 'Content-Type: unknown/unknown',13,10,13,10 unkl: labelt: db 'Tiny http server ',version labellen: socket dd 0x0 server_active db 0x0 board: db "
",13,10 db "
",13,10 db "" db 13,10 db "
",13,10 db "Tinyserver Messageboard

",13,10 db "" db 13,10,13,10 board1: db "",13,10 db "",13,10 db "",13,10,13,10 board3e: boardadd: db "

",13,10 db "",13,10 board1e: db "WebMaster",13,10 board2: db "",13,10 db "


",13,10 db "



",13,10 bsmt: db "12.23.45
",13,10 bsmd: db "02.05.03",13,10 db "

",13,10 board2e: db "Assembly written messageboard from assembly written MenuetOS.
" db 13,10 board3: db "

",13,10 db "
",13,10 db "" db 13,10 db "",13,10 db "",13,10 db "

",13,10 db "

",13,10 db "Name:

",13,10 db "Message:

",13,10 db "
",13,10 db "
",13,10 db "",13,10 db "",13,10 board_end: board_size dd 0x0 board_messages dd 0x0 input_text: I_END: