bitreich-short

fork of git.z3bra.org/bitreich-short
git clone git://git.pyratebeard.net/bitreich-short.git
Log | Files | Refs | README | LICENSE

bitreich-httpd.c (4356B)


      1 /*
      2  * Copy me if you can.
      3  * by 20h
      4  */
      5 
      6 #include <errno.h>
      7 #include <unistd.h>
      8 #include <stdio.h>
      9 #include <stdlib.h>
     10 #include <time.h>
     11 #include <sys/types.h>
     12 #include <sys/stat.h>
     13 #include <fcntl.h>
     14 #include <string.h>
     15 #include <sys/socket.h>
     16 #include <netdb.h>
     17 
     18 #define WWWBASE "/var/www/html"
     19 #define CHARSET "abcdefghijklmnopqrstuvwxyz"
     20 #define NAMELEN 3
     21 
     22 char *host = "url.short";
     23 
     24 void *
     25 xmalloc(size_t size)
     26 {
     27 	void *p;
     28 
     29 	if (!(p = malloc(size))) {
     30 		perror("malloc");
     31 		exit(1);
     32 	}
     33 
     34 	return p;
     35 }
     36 
     37 char *
     38 randomname(int len)
     39 {
     40 	int i;
     41 	static char out[NAMELEN + 1];
     42 	static char charset[] = CHARSET;
     43 
     44 	srand((unsigned long)&i);
     45 	for (i = 0; i < len; i++)
     46 		out[i] = charset[rand() % (int)(sizeof(charset) -1)];
     47 
     48 	return out;
     49 }
     50 
     51 void
     52 print404(void)
     53 {
     54 	printf("HTTP/1.1 404 Google Broke The Web\r\n");
     55 	printf("\r\n");
     56 }
     57 
     58 void
     59 print500(void)
     60 {
     61 	printf("HTTP/1.1 500 You Broke The Web\r\n");
     62 	printf("\r\n");
     63 }
     64 
     65 void
     66 printheaders(char *ctype)
     67 {
     68 	time_t t;
     69 
     70 	t = time(NULL);
     71 	if (t > 0)
     72 		printf("Date: %s", asctime(gmtime(&t)));
     73 	printf("Content-Type: %s\r\n", ctype);
     74 	printf("Server: bitreich-httpd/2.0\r\n");
     75 	printf("Host: bitreich.org\r\n");
     76 	printf("Connection: close\r\n");
     77 }
     78 
     79 int
     80 servefile(char *path, char *ctype, int sock)
     81 {
     82 	struct stat st;
     83 	char *sendb, *sendi;
     84 	size_t bufsiz = BUFSIZ;
     85 	int len, sent, fd;
     86 
     87 	fd = open(path, O_RDONLY);
     88 	if (fd < 0) {
     89 		print404();
     90 		return 1;
     91 	}
     92 
     93 	printf("HTTP/1.1 200 OK\r\n");
     94 	printheaders(ctype);
     95 
     96 	if (fstat(fd, &st) >= 0)
     97 		if ((bufsiz = st.st_blksize) < BUFSIZ)
     98 			bufsiz = BUFSIZ;
     99 
    100 	printf("Content-Length: %ld\r\n", st.st_size);
    101 	printf("\r\n");
    102 	fflush(stdout);
    103 
    104 	sendb = xmalloc(bufsiz);
    105 	while ((len = read(fd, sendb, bufsiz)) > 0) {
    106 		sendi = sendb;
    107 		while (len > 0) {
    108 			if ((sent = write(sock, sendi, len)) < 0) {
    109 				free(sendb);
    110 				return 1;
    111 			}
    112 			len -= sent;
    113 			sendi += sent;
    114 		}
    115 	}
    116 	free(sendb);
    117 
    118 	return 0;
    119 }
    120 
    121 int
    122 redirect(char *path)
    123 {
    124 	struct stat st;
    125 	char *location;
    126 	size_t bufsiz = BUFSIZ;
    127 	int len, fd;
    128 
    129 	fd = open(path, O_RDONLY);
    130 	if (fd < 0) {
    131 		print404();
    132 		return 1;
    133 	}
    134 
    135 	if (fstat(fd, &st) >= 0)
    136 		if ((bufsiz = st.st_blksize) < BUFSIZ)
    137 			bufsiz = BUFSIZ;
    138 
    139 	location = xmalloc(bufsiz);
    140 	len = read(fd, location, bufsiz);
    141 
    142 	location[len - 1] = '\0';
    143 
    144 	printf("HTTP/1.1 307 Moved Temporarily\r\n");
    145 	printheaders("text/html");
    146 	printf("Location: %s\r\n", location);
    147 	printf("\r\n");
    148 
    149 	free(location);
    150 
    151 	return 0;
    152 }
    153 
    154 int
    155 saveurl(char *wwwbase, char *location)
    156 {
    157 	int fd;
    158 	char *path, *name, *url;
    159 
    160 	if (!(name = randomname(NAMELEN)))
    161 		return 1;
    162 
    163 	asprintf(&path, "%s/%s", wwwbase, name);
    164 	asprintf(&url, "http://%s/%s\r\n", host, name);
    165 
    166 	if ((fd = open(path, O_WRONLY|O_CREAT, 0644)) < 0)
    167 		return 1;
    168 
    169 	write(fd, location, strlen(location));
    170 	write(fd, "\n", 1);
    171 	close(fd);
    172 
    173 	printf("HTTP/1.1 200 OK\r\n");
    174 	printheaders("text/plain");
    175 	printf("Content-Length: %ld\r\n", strlen(url));
    176 	printf("\r\n");
    177 	fflush(stdout);
    178 	printf("%s", url);
    179 
    180 	free(path);
    181 	free(url);
    182 
    183 	return 0;
    184 }
    185 
    186 int
    187 main(int argc, char *argv[])
    188 {
    189 	char *wwwbase, *wwwindex, request[512], *ctype, *path, *url,
    190 	     clienth[NI_MAXHOST], clientp[NI_MAXSERV];
    191 	int rlen;
    192 	struct sockaddr_storage clt;
    193 	socklen_t cltlen = sizeof(clt);
    194 
    195 	wwwbase = WWWBASE;
    196 	wwwindex = "index.html";
    197 
    198 	if (!getpeername(0, (struct sockaddr *)&clt, &cltlen)) {
    199 		if (getnameinfo((struct sockaddr *)&clt, cltlen, clienth,
    200 					sizeof(clienth), clientp, sizeof(clientp),
    201 					NI_NUMERICHOST|NI_NUMERICSERV)) {
    202 			clienth[0] = clientp[0] = '\0';
    203 		}
    204 		if (!strncmp(clienth, "::ffff:", 7))
    205 			memmove(clienth, clienth+7, strlen(clienth)-6);
    206 	} else {
    207 			clienth[0] = clientp[0] = '\0';
    208 	}
    209 
    210 	rlen = read(0, request, sizeof(request)-1);
    211 	if (rlen < 0)
    212 		return 1;
    213 
    214 	request[rlen] = '\0';
    215 
    216 	if (!strncmp(request, "PUT ", 4)) {
    217 		url = strstr(request, "\r\n\r\n") + 4;
    218 		if (!url || !strlen(url) || saveurl(wwwbase, url)) {
    219 			perror(url);
    220 			print500();
    221 			return 1;
    222 		}
    223 		return 0;
    224 	} else if (!strncmp(request, "GET ", 4)) {
    225 		if (!strncmp(request + 4, "/ ", 2) || strstr(request, "/../")) {
    226 			asprintf(&path, "%s/%s", wwwbase, wwwindex);
    227 			ctype = "text/html";
    228 			rlen = servefile(path, ctype, 1);
    229 			free(path);
    230 			return rlen;
    231 		} else {
    232 			char *p = strstr(request + 4, " ");
    233 			*p = '\0';
    234 			asprintf(&path, "%s%s", wwwbase, request + 4);
    235 			rlen = redirect(path);
    236 			free(path);
    237 			return rlen;
    238 		}
    239 	}
    240 
    241 	return -1;
    242 }