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 }