tbitreich-httpd.c - bitreich-short - Fork of bitreich-httpd to shorten URLs
 (HTM) git clone git://git.z3bra.org/bitreich-short.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       tbitreich-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 }