higgs

httpd experiment
git clone git://git.2f30.org/higgs
Log | Files | Refs

higgs.c (4092B)


      1 #include <errno.h>
      2 #include <limits.h>
      3 #include <netdb.h>
      4 #include <poll.h>
      5 #include <signal.h>
      6 #include <stdio.h>
      7 #include <stdlib.h>
      8 #include <string.h>
      9 #include <time.h>
     10 #include <arpa/inet.h>
     11 #include <netinet/in.h>
     12 #include <sys/resource.h>
     13 #include <sys/socket.h>
     14 #include <sys/time.h>
     15 #include <sys/types.h>
     16 
     17 #include "config.h"
     18 
     19 static char *
     20 strdupcond(char *s, char *skip, char *delim)
     21 {
     22 	char *p;
     23 
     24 	for (; !*s || strchr(skip, *s); s++)
     25 		;
     26 	for (p = s; !strchr(delim, *p); p++)
     27 		;
     28 
     29 	return strndup(s, p - s);
     30 }
     31 
     32 static void
     33 handle(int fd)
     34 {
     35 	FILE *fp;
     36 	size_t buflen = 0;
     37 	off_t range[2] = { -1, -1 };
     38 	char *buf = NULL, *p, *url, *host;
     39 
     40 readline:
     41 	/* check first line of HTTP request (use strtok?) */
     42 	if (!(fp = fdopen(fd, "r")) || getline(&buf, &buflen, fp) < 0)
     43 		goto servererr;
     44 	if (strncmp(buf, "GET", strlen("GET")))
     45 		goto clienterr;
     46 	if (!(url = strdupcond(buf + strlen("GET"), " ", " ")))
     47 		goto servererr;
     48 	for (p = buf + strlen("GET"); *p == ' '; p++);
     49 	for (; *p && *p != ' '; p++);
     50 	for (; *p == ' '; p++);
     51 	if (strncmp(p, "HTTP/", strlen("HTTP/")))
     52 		goto clienterr;
     53 
     54 	/* read upcoming fields (use strtok? first \r -> \0) */
     55 	while (getline(&buf, &buflen, fp) >= 0 && strcmp(buf, "\r\n")) {
     56 		/* host */
     57 		if (!strncmp(buf, "Host:", strlen("Host:"))) {
     58 			if (!(host = strdupcond(buf + strlen("Host:"),
     59 			                        " ", "\r\n")))
     60 				goto servererr;
     61 			printf("FIELD HOST: %s\n", host);
     62 		/* range */
     63 		} else if (!strncmp(buf, "Range:", strlen("Range:"))) {
     64 			if (!(p = strdupcond(buf + strlen("Range:"),
     65 			                     " ", "\r\n")))
     66 				goto servererr;
     67 			printf("FIELD RANGE: %s\n", p);
     68 			free(p);
     69 		/* if-modified-since */
     70 		} else if (!strncmp(buf, "If-Modified-Since:",
     71 		                    strlen("If-Modified-Since:"))) {
     72 			if (!(p = strdupcond(buf + strlen("If-Modified-Since:"),
     73 			                     " ", "\r\n")))
     74 				goto servererr;
     75 			printf("FIELD MOD-SINCE: %s\n", p);
     76 			free(p);
     77 		}
     78 	}
     79 	/* Response: Allow, Connection, Content-Range, Content-Type,
     80 	 * Date, Server */
     81 	return;
     82 servererr:
     83 	/* 500 internal server error */
     84 	printf("500 |%s|\n", url);
     85 	return;
     86 clienterr:
     87 	/* 400 Bad Request */
     88 	printf("400 |%s|\n", url);
     89 	return;
     90 }
     91 
     92 int
     93 main()
     94 {
     95 	struct addrinfo hints, *ai = NULL;
     96 	struct rlimit rlim;
     97 	struct sockaddr sa;
     98 	pid_t pid;
     99 	socklen_t salen;
    100 	int i, listenfd, reqfd, running = 1;
    101 
    102 	if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) {
    103 		fprintf(stderr, "signal: Failed to set SIG_IGN on SIGCHLD\n");
    104 		return 1;
    105 	}
    106 
    107 	setbuf(stdout, NULL); /* unbuffered stdout */
    108 
    109 	hints.ai_family = AF_INET;
    110 	hints.ai_socktype = SOCK_STREAM;
    111 	hints.ai_flags = AI_PASSIVE;
    112 
    113 	if ((i = getaddrinfo(servername, serverport, &hints, &ai))) {
    114 		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(i));
    115 		return 1;
    116 	}
    117 	if ((listenfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0) {
    118 		fprintf(stderr, "tsocket: %s\n", strerror(errno));
    119 		return 1;
    120 	}
    121 	if (bind(listenfd, ai->ai_addr, ai->ai_addrlen) == -1) {
    122 		fprintf(stderr, "bind: %s\n", strerror(errno));
    123 		return 1;
    124 	}
    125 	if (listen(listenfd, SOMAXCONN) == -1) {
    126 		fprintf(stderr, "listen: %s\n", strerror(errno));
    127 		return 1;
    128 	}
    129 
    130 	rlim.rlim_cur = rlim.rlim_max = maxnprocs;
    131 	if (setrlimit(RLIMIT_NPROC, &rlim) < 0) {
    132 		fprintf(stderr, "setrlimit RLIMIT_NPROC: %s\n", strerror(errno));
    133 		return 1;
    134 	}
    135 
    136 	while (running) {
    137 		salen = sizeof(sa);
    138 		if ((reqfd = accept(listenfd, &sa, &salen)) < 0) {
    139 			fprintf(stderr, "accept: %s\n", strerror(errno));
    140 			continue;
    141 		}
    142 
    143 		pid = fork();
    144 
    145 		if (pid < 0) {
    146 			fprintf(stderr, "fork: %s\n", strerror(errno));
    147 			/* error-message? */
    148 			continue;
    149 		} else if (pid == 0) {
    150 			close(listenfd);
    151 
    152 			/* close socket after timeout */
    153 			if (setsockopt(reqfd, SOL_SOCKET, SO_RCVTIMEO,
    154 			               &timeout, sizeof(timeout)) < 0) {
    155 				fprintf(stderr, "error\tsetsockopt SO_RCVTIMEO"
    156 				        "failed: %s\n", strerror(errno));
    157 			}
    158 
    159 			handle(reqfd);
    160 
    161 			shutdown(reqfd, SHUT_RD);
    162 			shutdown(reqfd, SHUT_WR);
    163 			close(reqfd);
    164 			exit(0);
    165 		} else {
    166 			close(reqfd);
    167 		}
    168 	}
    169 
    170 	close(listenfd);
    171 	freeaddrinfo(ai);
    172 
    173 	return 0;
    174 }