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 }