logo
Go to the homepage of the Vrije Universiteit. Go to the homepage of the department of computer science. Go to the homepage of the faculty of sciences.

How not to write a http daemon


Below you can see the source code of a http daemon, based on the ioccc entry "Hibachi". Though it is a robust and toughout program, it would not do well, at all, as a CN lab solution. Actually, it breaks almost every rule (both implicit and explicit) in the book of propper C writing, as well as all the directives given in the handout and the CN lab website.

Do not, I repeat, do not submit a solution even remotly like this, and expect to pass.

It is smaller than 160 lines of code. It's list of features, however, is impressive, and it takes a lot of experience to write something like this. In fact, it takes a lot of experience to read something like this.

Features

  • Implements HTTP/1.1
  • Supports virtual hosts.
  • Supports all MIME types.
  • Supports Common Gateway Interface (CGI) scripts and programs.
  • Supports multiple index.* file types: index.htm, index.html, index.php, index.pl, index.sh, index.rb, index.py
  • Supports subset of RFC 2616 HTTP/1.1 methods: GET, HEAD, and POST
  • Simple & straight forward configuration using environment variables.
  • Portability across Unix-like environments, such as: Cygwin, FreeBSD, Linux, SunOS.
  • Known to work with Lynx, Mozilla, Opera, and Internet Explorer web browsers.
  • Is a dedicated process-forking server that does not use inetd.
  • Is secure against relative path file snooping.
  • Is secure against directory searches.
  • CGI script execution managed through Unix file permissions.

C Source Code

This code is way past the category "Don't try this at home!" Study this code at your own risk! #include <fcntl.h> #include <dirent.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/stat.h> #include <sys/wait.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define bufsize 8192 char r[bufsize], q[bufsize], l[bufsize], w[bufsize], *o, *m = "404 Not Found", *e = "500 Error"; void X(int t, char *u, long j) { j = snprintf(q, bufsize, "HTTP/1.0 %s\r\nContent-Length: %ld\r\n\r\n%s", u, j ? j : strcspn(u, ""), j ? "" : u); send(t, q, j, 0); } void A(char *i, char *j) { char *u; if ((u = strstr(o, i + 5))) sscanf(u + strcspn(u, ":") + 1, j, getenv(i)); } int main(int c, char **p) { int f, t, i; struct stat g; struct sockaddr_in a; char *v, *u; if ((v = getenv("SERVER_PORT")) == 0) { return 4; } i = (int)strtol(v, 0, 10); a.sin_addr.s_addr = htonl(INADDR_ANY); a.sin_port = htons((unsigned short)i); a.sin_family = AF_INET; if ((f = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { return 5; } if (bind(f, (void *)&a, sizeof a)) { return 6; } if (listen(f, 10)) { return 7; } for (;; close(t)) { for (; waitpid(0, 0, WNOHANG) > 0;); i = sizeof a; if ((t = accept(f, (void *)&a, &i)) < 0) continue; if (fork()) continue; for (f = i = 0; f < 2 && i < bufsize; i++) { if (recv(t, r + i, 1, 0) <= 0) return 1; if (r[i] == '\n') f++; if (r[i] == ':') f = 0; if (f) r[i] = r[i] == '-' ? '_' : toupper(r[i]); } if (bufsize <= i) break; r[i] = 0; if (*r != 'G' && *r != 'H' && r[2] != 'S') { X(t, "501 Unsupported", 0); break; } *l = 0; if ((v = strstr(r, "HOST:"))) sscanf(v + 5, " %255[^:\r\n]", l); snprintf(w, bufsize, "DOCUMENT_ROOT=%s/%s", getenv("DOCUMENT_ROOT"), l); putenv(w); u = r + 4 + (*r != 'G'); if (*u != '/' || strstr(u, "../")) { X(t, m, 0); break; } u[i = strcspn(u, " ")] = 0; o = u + i + 1; i = strcspn(u, "?"); if (u[i]) { snprintf(q, bufsize, "QUERY_STRING=%s", u + i + 1); putenv(q); u[i] = 0; } snprintf(l, bufsize, "SCRIPT_FILENAME=%s%s", w + 14, u); v = l + 16; if (stat(v, &g) < 0) { X(t, m, 0); break; } if (S_ISDIR(g.st_mode)) { struct dirent *d; DIR *D = opendir(v); for (; (d = readdir(D));) { if (!strncmp(d->d_name, "index.", 6)) { strncat(v, d->d_name, bufsize - 16); stat(v, &g); break; } } closedir(D); if (d == 0) { X(t, m, 0); break; } } if (*r != 'H') { if (g.st_mode & 0111) { putenv(l); sscanf(r, "%4s", getenv("REQUEST_METHOD")); sscanf(inet_ntoa(a.sin_addr), "%15s", getenv("REMOTE_ADDR")); A("HTTP_COOKIE", "%*[ \t]%80[^\r\n]"); A("CONTENT_LENGTH", "%20s"); A("CONTENT_TYPE", "%60s"); dup2(t, 0); dup2(t, 1); if (system(v)) X(t, e, 0); break; } if ((f = open(v, O_RDONLY)) < 0) { X(t, e, 0); break; } } X(t, "200 OK", g.st_size); if (*r != 'H') { for (; 0 < (i = read(f, r, bufsize));) send(t, r, i, 0); } break; } shutdown(t, SHUT_WR); return 0; }

If you have any comments, please e-mail the maintainer of this page.
Your browser does not fully support CSS. This may result in visual artifacts.