# picohttpd/Linux # (c) copyright 2001 by wojtek kaniewski # released under terms of GNU GPL version 2 # # this is pretty useless http daemon. it doesn't support vhosts, userdirs, # listing directory contents, cgi, php. it handles only one client at a # time. it lacks of full HTTP/1.0 support. it's insecure. it isn't # portable. it's stupid. # # $ as ph.s -o ph.o # $ ld -s ph.o -o ph # $ ./ph & .data port = 8182 root: .asciz "/home/httpd/html/" # has to be followed by slash e404.t: .ascii "HTTP/1.0 404 Not Found\r\n\r\n

404 Not Found

\r\n" e403.t: .ascii "HTTP/1.0 403 Forbidden\r\n\r\n

403 Forbidden

\r\n" e500.t: .ascii "HTTP/1.0 500 Server Error\r\n\r\n

500 Server Error

\r\n" head.t: .ascii "HTTP/1.0 200 OK\r\nServer: picohttpd/Linux\r\nContent-type: " html.t: .ascii "text/html\r\n\r\n" txt.t: .ascii "text/plain\r\n\r\n" gif.t: .ascii "image/gif\r\n\r\n" jpg.t: .ascii "image/jpeg\r\n\r\n" png.t: .ascii "image/png\r\n\r\n" def.t: .ascii "application/octet-stream\r\n\r\n" e404.l = e403.t-e404.t e403.l = e500.t-e403.t e500.l = head.t-e500.t head.l = html.t-head.t html.l = txt.t-html.t txt.l = gif.t-txt.t gif.l = jpg.t-gif.t jpg.l = png.t-jpg.t png.l = def.t-png.t def.l = .-def.t .bss buf: .space 1024, 0 # char buf[1024]; buf.l = .-buf len: .long 0 # int len; buf2: .space buf.l+256, 0 # char buf2[sizeof(buf)+256]; buf2.l = .-buf2 s_args: # int s_args[4]; s_arg0: .long 0 s_arg1: .long 0 s_arg2: .long 0 s_arg3: .long 0 s_fd: .long 0 # int s_fd; c_fd: .long 0 # int c_fd; sa: .space 128, 0 # struct sockaddr_in sa; sa.l = .-sa salen: .long 0 # int salen; stat: .space 64, 0 # struct stat stat; fd: .long 0 # int fd; off: .long 0 # int off; O_RDONLY = 0 # valid for linux 2.2.x SOCK_STREAM = 1 IPPROTO_TCP = 6 AF_INET = 2 AF_INET6 = 10 SYS_SOCKET = 1 SYS_BIND = 2 SYS_CONNECT = 3 SYS_LISTEN = 4 SYS_ACCEPT = 5 INADDR_ANY = 0 NR_open = 5 NR_close = 6 NR_write = 4 NR_read = 3 NR_fstat = 108 NR_sendfile = 187 st_size = 20 .macro __socketcall call # all socket calls are made movl $102, %eax # by the same syscall. movl \call, %ebx movl $s_args, %ecx int $0x80 .endm .text .global _start _start: movl $AF_INET, s_arg0 # s_fd = socket(AF_INET, ...); movl $SOCK_STREAM, s_arg1 movl $0, s_arg2 __socketcall $SYS_SOCKET movl %eax, s_fd movw $AF_INET, sa # sa.sin_family = AF_INET; movw $((port & 0xff00) >> 8 | (port & 0xff) << 8), sa+2 # sa.sin_port = htons(port); movl $INADDR_ANY, sa+4 # sa.sin_addr = INADDR_ANY; movl s_fd, %eax # bind(s_fd, &sa, sizeof(sa)); movl %eax, s_arg0 movl $sa, s_arg1 movl $sa.l, s_arg2 __socketcall $SYS_BIND movl s_fd, %eax # listen(s_fd, 64); movl %eax, s_arg0 movl $64, s_arg1 __socketcall $SYS_LISTEN loop: movl s_fd, %eax # c_fd = accept(s_fd, ...); movl %eax, s_arg0 movl $sa, s_arg1 movl $sa.l, salen movl $salen, s_arg2 __socketcall $SYS_ACCEPT mov %eax, c_fd cmpl $-1, %eax # if (c_fd == -1) goto fail; je fail movl %eax, %ebx # len = read(c_fd, buf, ...); movl $NR_read, %eax movl $buf, %ecx movl $buf.l, %edx int $0x80 movl %eax, len cmpl $5, %eax # if (len < 6) goto e500; jng e500 cmpl $('G'|'E'<<8|'T'<<16|' '<<24), buf jnz e500 # if (buf[0..3] != "GET ") goto e500; movl len, %ecx # for (i = 0; i < len; i++) { movl $buf+4, %esi # p = buf + 4; url: lodsb # q = *p++; cmpb $' ', %al # if (q == ' ') break; jz last cmpb $'\r', %al # if (q == '\r') break; jz last cmpb $'\n', %al # if (q == '\n') break; jz last loop url # } last: decl %esi # p--; movl %esi, %edi xor %eax, %eax stosb # *p = 0; fetch: movl $buf+4, %esi # p = buf + 4; xorl %eax, %eax # for (r = 0;;) { trav: lodsb # q = *p++; cmpb $0, %al # if (!p) goto done; jz done cmpb $'.', %al # if (q == '.' && r == '.') jnz next2 # goto e403; cmpb $'.', %ah jnz next2 jmp e403 next2: movb %al, %ah # r = q; jmp trav # } done: cld # strcpy(buf2, root); movl $buf2, %edi movl $root, %esi xorl %eax, %eax cpy1: lodsb stosb orl %eax, %eax jnz cpy1 decl %edi movl $buf+4, %esi # strcat(buf2, buf + 4); xorl %eax, %eax cpy2: lodsb stosb orl %eax, %eax jnz cpy2 subl $2, %esi # if (buf2[strlen(buf2)-1] != '/') lodsb # goto notind; cmp $'/', %al jnz notind movl $('i'|'n'<<8|'d'<<16|'e'<<24), -1(%edi) movl $('x'|'.'<<8|'h'<<16|'t'<<24), 3(%edi) movl $('m'|'l'<<8), 7(%edi) addl $10, %edi # strcat(buf2, "index.html"); notind: push %edi movl $NR_open, %eax # fd = open(buf2, O_RDONLY); movl $buf2, %ebx movl $O_RDONLY, %ecx int $0x80 movl %eax, fd pop %edi andl $0x8000000, %eax # if (fd < 0) goto e404; jnz e404 push %edi movl $NR_write, %eax # write(c_fd, head, sizeof(head)); movl c_fd, %ebx movl $head.t, %ecx movl $head.l, %edx int $0x80 pop %edi mov %edi, %esi subl $5, %esi lodsl cmpl $('.'|'h'<<8|'t'<<16|'m'<<24), %eax jnz ext1 # if (buf2[-3..0] == ".htm") { html: movl $html.t, %ecx # x = html; movl $html.l, %edx # y = strlen(html); jmp gotext # } else ... ext1: cmpl $('h'|'t'<<8|'m'<<16|'l'<<24), %eax jnz ext2 # ... jmp html ext2: cmpl $('.'|'g'<<8|'i'<<16|'f'<<24), %eax jnz ext3 # ... movl $gif.t, %ecx movl $gif.l, %edx jmp gotext ext3: cmpl $('.'|'p'<<8|'n'<<16|'g'<<24), %eax jnz ext4 # ... movl $png.t, %ecx movl $png.l, %edx jmp gotext ext4: cmpl $('.'|'j'<<8|'p'<<16|'g'<<24), %eax jnz ext5 # ... movl $jpg.t, %ecx movl $jpg.l, %edx jmp gotext ext5: cmpl $('.'|'t'<<8|'x'<<16|'t'<<24), %eax jnz ext6 # } else if (buf2[-3..0] == ".txt") { movl $txt.t, %ecx # x = txt; movl $txt.l, %edx # y = strlen(txt); jmp gotext # } else { ext6: movl $def.t, %ecx # x = def; movl $def.l, %edx # y = strlen(def); gotext: movl $NR_write, %eax # } movl c_fd, %ebx int $0x80 # write(c_fd, x, y); movl $NR_fstat, %eax # fstat(fd, &stat); movl fd, %ebx movl $stat, %ecx int $0x80 movl $0, off # sendfile(..., &off, stat.st_size); movl $NR_sendfile, %eax movl c_fd, %ebx movl fd, %ecx movl $off, %edx movl stat+st_size, %esi int $0x80 exit: movl c_fd, %ebx # close(c_fd); movl $NR_close, %eax int $0x80 jmp loop # goto loop; e404: movl c_fd, %ebx # write(c_fd, e404, strlen(e404)); movl $4, %eax movl $e404.t, %ecx movl $e404.l, %edx int $0x80 jmp exit e403: movl c_fd, %ebx # write(c_fd, e403, strlen(e403)); movl $4, %eax movl $e403.t, %ecx movl $e403.l, %edx int $0x80 jmp exit e500: movl c_fd, %ebx # write(c_fd, e500, strlen(e500)); movl $4, %eax movl $e500.t, %ecx movl $e500.l, %edx int $0x80 jmp exit fail: movl $1, %eax # exit(0); xor %ebx, %ebx int $0x80