Created
October 30, 2012 23:51
-
-
Save kohgpat/3983888 to your computer and use it in GitHub Desktop.
My Own HTTP Daemon by Neill Corlett
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; | |
; My Own HTTP Daemon | |
; A web server for i386 Linux because I was bored | |
; Copyright (C) 2012 Neill Corlett | |
; | |
; This program is free software: you can redistribute it and/or modify it under | |
; the terms of the GNU General Public License as published by the Free Software | |
; Foundation, either version 3 of the License, or (at your option) any later | |
; version. | |
; | |
; This program is distributed in the hope that it will be useful, but WITHOUT | |
; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
; FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |
; details. | |
; | |
; You should have received a copy of the GNU General Public License along with | |
; this program. If not, see <http://www.gnu.org/licenses/>. | |
; | |
; | |
; Caveat: This code is PROBABLY NOT SECURE. | |
; | |
; | |
; To build: | |
; nasm -f elf mohttpd.asm | |
; ld -melf_i386 -s -o mohttpd mohttpd.o | |
; | |
; To start: | |
; ./mohttpd | |
; Serves pages from the current working directory. | |
; | |
; To stop: Ctrl-C | |
; | |
; | |
; Port to listen on | |
; | |
listenport equ 8888 | |
section .bss | |
buf: resb 16384 | |
bufend: | |
buflen equ bufend-buf | |
section .data | |
; | |
; File descriptors | |
; | |
listenfd: dd -1 | |
clientfd: dd -1 | |
filefd: dd -1 | |
section .rodata | |
; | |
; Error messages and other strings | |
; | |
socketerror: db 'socket error',10 | |
socketerrorlen equ $-socketerror | |
binderror: db 'bind error',10 | |
binderrorlen equ $-binderror | |
listenerror: db 'listen error',10 | |
listenerrorlen equ $-listenerror | |
http200: db 'HTTP/1.1 200 OK',13,10,'Content-Type: text/html',13,10,13,10 | |
http200len equ $-http200 | |
http400: db 'HTTP/1.1 400 Bad Request',13,10,'Content-Type: text/html',13,10,13,10,'Bad Request' | |
http400len equ $-http400 | |
http404: db 'HTTP/1.1 404 Not Found',13,10,'Content-Type: text/html',13,10,13,10,'Not Found' | |
http404len equ $-http404 | |
section .text | |
; | |
; Entry point here | |
; | |
global _start | |
_start: | |
; | |
; Create socket | |
; | |
push byte 0 | |
push byte 1 ; SOCK_STREAM | |
push byte 2 ; AF_INET | |
mov eax,102 ; NR_socketcall | |
mov ebx,1 ; SYS_SOCKET | |
mov ecx,esp | |
int 80h | |
add esp,byte 12 | |
mov ecx,socketerror | |
mov edx,socketerrorlen | |
test eax,eax | |
js fatalerror | |
mov [listenfd],eax | |
; | |
; Bind to the listen port | |
; first two bytes: 2 (AF_INET) | |
; next two bytes: listen port in network order | |
; | |
mov word[buf],2 ; AF_INET | |
mov ax,listenport | |
xchg ah,al ; htons | |
mov [buf+2],ax | |
push byte 16 ; sizeof sockaddr | |
push buf | |
push dword[listenfd] | |
mov eax,102 ; NR_socketcall | |
mov ebx,2 ; SYS_BIND | |
mov ecx,esp | |
int 80h | |
add esp,byte 12 | |
mov ecx,binderror | |
mov edx,binderrorlen | |
test eax,eax | |
js fatalerror | |
; | |
; Listen on the listen fd | |
; | |
push byte 5 | |
push dword[listenfd] | |
mov eax,102 ; NR_socketcall | |
mov ebx,4 ; SYS_LISTEN | |
mov ecx,esp | |
int 80h | |
add esp,byte 8 | |
mov ecx,listenerror | |
mov edx,listenerrorlen | |
test eax,eax | |
js fatalerror | |
serverloop: | |
; | |
; Close old fds | |
; | |
mov eax,6 ; close | |
mov ebx,[filefd] | |
int 80h | |
mov dword[filefd],-1 | |
mov eax,6 ; close | |
mov ebx,[clientfd] | |
int 80h | |
mov dword[clientfd],-1 | |
; | |
; Accept a connection | |
; | |
push byte 0 ; space for length | |
mov eax,esp | |
push eax ; points to length | |
push buf ; points to buffer for peer address | |
push dword[listenfd] | |
mov eax,102 ; NR_socketcall | |
mov ebx,5 ; SYS_ACCEPT | |
mov ecx,esp | |
int 80h | |
add esp,byte 16 | |
cmp eax,byte -1 | |
je short serverloop | |
mov [clientfd],eax | |
; | |
; Read the request header into buf | |
; | |
mov ecx,buf | |
readreq_reset: | |
xor edi,edi ; number of consecutive linefeeds | |
readreq: | |
mov eax,3 ; read | |
mov ebx,[clientfd] | |
mov edx,1 | |
int 80h | |
; end on read failure | |
cmp eax,byte 1 | |
jne short readreq_done | |
; end if buffer is full | |
cmp ecx,bufend-1 | |
je short readreq_done | |
inc ecx | |
; end if two consecutive linefeeds | |
mov al,[ecx-1] | |
cmp al,21h | |
jae short readreq_reset | |
cmp al,0ah | |
jne short readreq | |
inc edi | |
cmp edi,byte 2 | |
jb short readreq | |
readreq_done: | |
; | |
; Ensure the request header is terminated | |
; | |
mov byte[ecx],0 | |
; | |
; Only recognize requests starting with 'GET ' | |
; | |
mov esi,buf | |
lodsd | |
cmp eax,'GET ' | |
jne badreq | |
; | |
; Get the URI as a relative path | |
; | |
geturi: | |
; ignore leading slashes | |
lodsb | |
cmp al,'/' | |
je short geturi | |
dec esi | |
; ebx points to URI start | |
mov ebx,esi | |
; | |
; Null terminate the URI | |
; | |
termuri: | |
lodsb | |
cmp al,21h | |
jae short termuri | |
dec esi | |
mov byte[esi],0 ; null terminate it | |
; | |
; As a really simple security measure, disallow '..' in the URI | |
; | |
mov eax,ebx | |
dec esi | |
uricheck: | |
cmp word[eax],'..' | |
je badreq | |
inc eax | |
cmp eax,esi | |
jb short uricheck | |
; | |
; Attempt to open the URI as a relative path | |
; | |
mov eax,5 ; open | |
xor ecx,ecx ; flags: O_RDONLY | |
xor edx,edx ; mode: 0 | |
int 80h | |
; Treat any open error as a 404 | |
test eax,eax | |
js short notfound | |
mov [filefd],eax | |
; | |
; Serve HTTP 200 header | |
; | |
mov eax,4 ; write | |
mov ebx,[clientfd] | |
mov ecx,http200 | |
mov edx,http200len | |
int 80h | |
; | |
; Serve the file contents | |
; | |
servefile: | |
mov eax,3 | |
mov ebx,[filefd] | |
mov ecx,buf | |
mov edx,buflen | |
int 80h | |
cmp eax,byte 0 | |
jle serverloop | |
mov edx,eax ; length | |
mov eax,4 ; write | |
mov ebx,[clientfd] | |
int 80h | |
jmp short servefile | |
; | |
; Bad request: Serve a HTTP 400 page | |
; | |
badreq: | |
mov eax,4 ; write | |
mov ebx,[clientfd] | |
mov ecx,http400 | |
mov edx,http400len | |
int 80h | |
jmp serverloop | |
; | |
; Not found: Serve a HTTP 404 page | |
; | |
notfound: | |
mov eax,4 ; write | |
mov ebx,[clientfd] | |
mov ecx,http404 | |
mov edx,http404len | |
int 80h | |
jmp serverloop | |
; | |
; Fatal error: Print the error string and exit | |
; | |
fatalerror: | |
mov eax,4 ; write | |
mov ebx,2 ; stderr | |
int 80h | |
mov eax,1 ; exit | |
mov ebx,eax | |
int 80h |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment