bitreich-httpd.c (4201B)
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/cache/shorturl" 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", 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, request[512], *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 197 if (!getpeername(0, (struct sockaddr *)&clt, &cltlen)) { 198 if (getnameinfo((struct sockaddr *)&clt, cltlen, clienth, 199 sizeof(clienth), clientp, sizeof(clientp), 200 NI_NUMERICHOST|NI_NUMERICSERV)) { 201 clienth[0] = clientp[0] = '\0'; 202 } 203 if (!strncmp(clienth, "::ffff:", 7)) 204 memmove(clienth, clienth+7, strlen(clienth)-6); 205 } else { 206 clienth[0] = clientp[0] = '\0'; 207 } 208 209 rlen = read(0, request, sizeof(request)-1); 210 if (rlen < 0) 211 return 1; 212 213 request[rlen] = '\0'; 214 215 if (!strncmp(request, "PUT ", 4)) { 216 url = strstr(request, "\r\n\r\n") + 4; 217 if (!url || !strlen(url) || saveurl(wwwbase, url)) { 218 perror(url); 219 print500(); 220 return 1; 221 } 222 return 0; 223 } else if (!strncmp(request, "GET ", 4)) { 224 if (!strncmp(request + 4, "/ ", 2) || strstr(request, "/../")) { 225 print404(); 226 return 1; 227 } else { 228 char *p = strstr(request + 4, " "); 229 *p = '\0'; 230 asprintf(&path, "%s%s", wwwbase, request + 4); 231 rlen = redirect(path); 232 free(path); 233 return rlen; 234 } 235 } 236 237 return -1; 238 }