#include #include #include #include #include #include #include char *htmsg_404 = "HTTP/1.0 404 not found\n"; char *htmsg_200 = "HTTP/1.0 200 OK\n"; char *htmsg_htm = "Content-Type: text/html\n"; char *htmsg_jpg = "Content-Type: image/jpeg\n"; char *htmsg_gif = "Content-Type: image/gif\n"; char *htmsg_cls = "Connection: close\n"; char *htmsg_len = "Content-Length: %zu\n\n"; char *htmsg_err = "Error 404

Error 404

page not found\n"; int mklistener(int addr, int port){ struct sockaddr_in *address = malloc(sizeof(struct sockaddr_in)); int listener = socket(AF_INET, SOCK_STREAM, 0); address->sin_family = AF_INET; address->sin_port = htons(port); address->sin_addr.s_addr = addr; if (bind(listener, (struct sockaddr *) address, sizeof(struct sockaddr_in)) == -1) return -1; listen(listener, 1); return listener; } char *parse_request(char *request){ char *key = "GET ", delim = ' '; int cnt = 0; while( request[cnt] != '\0' && request[cnt] == key[cnt] ) cnt++; if (cnt != 4) return NULL; while ( request[cnt] != '\0' && request[cnt] != delim ) cnt++; request[cnt] = '\0'; return (request + 5); //return only relative filepath, skip "GET /" } int recv_line(int con, char *buf, int len){ int cnt = 0; char inc; while (cnt < len && recv(con, &inc, sizeof(char), 0) && inc != '\n'){ buf[cnt] = inc; cnt++; } if (cnt == len) return 0; buf[cnt] = '\0'; return ++cnt; } int send_error(int con){ char cont_len[strlen(htmsg_len) + 10]; sprintf(cont_len, htmsg_len, strlen(htmsg_err)); send(con, htmsg_404, strlen(htmsg_404), 0); send(con, htmsg_htm, strlen(htmsg_htm), 0); send(con, htmsg_cls, strlen(htmsg_cls), 0); send(con, cont_len, strlen(cont_len), 0); send(con, htmsg_err, strlen(htmsg_err), 0); return 2; } int send_header(int con, char *fname){ struct stat fstat; char cont_len[strlen(htmsg_len) + 10]; send(con, htmsg_200, strlen(htmsg_200), 0); if (!strcasecmp(fname + strlen(fname) - 5, ".jpeg")) send(con, htmsg_jpg, strlen(htmsg_jpg), 0); if (!strcasecmp(fname + strlen(fname) - 5, ".html")) send(con, htmsg_htm, strlen(htmsg_htm), 0); if (!strcasecmp(fname + strlen(fname) - 4, ".gif")) send(con, htmsg_gif, strlen(htmsg_gif), 0); send(con, htmsg_cls, strlen(htmsg_cls), 0); if (stat(fname, &fstat)){ printf("Could not stat file: %s\n", fname); return 0; } sprintf(cont_len, htmsg_len, fstat.st_size); send(con, cont_len, strlen(cont_len), 0); return 1; } int serve_file(int con, char *fname){ printf("Serving file: %s\n", fname); FILE *file = fopen(fname, "r"); char buf; if (!file) return send_error(con); if (send_header(con, fname)) while (!feof(file)) send(con, &buf, fread(&buf, 1, 1, file), 0); fclose(file); shutdown(con, SHUT_RDWR); return 0; } int serve_http(int connection){ char *file, *linebuf = malloc(256 * sizeof(char)); linebuf[0] = '\n'; while (!(file = parse_request(linebuf))) if (!recv_line(connection, linebuf, 256)){ shutdown(connection, SHUT_RDWR); return 1; } return serve_file(connection, file); } int listener; void closesock(){ shutdown(listener, SHUT_RDWR); } int main(int argc, char *argv[]){ int unforked = 1, connection; listener = mklistener(INADDR_ANY, 80); printf("accepting connections... "); //atexit(closesock); //bad idea, every forked server would close the main socket while (unforked){ connection = accept(listener, NULL, NULL); if (connection > 0) unforked = fork(); } printf("got connection: %i\n", connection); return serve_http(connection); }