Skip to content

Instantly share code, notes, and snippets.

@kohgpat
Created October 30, 2012 23:51
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kohgpat/3983888 to your computer and use it in GitHub Desktop.
Save kohgpat/3983888 to your computer and use it in GitHub Desktop.
My Own HTTP Daemon by Neill Corlett
;
; 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