OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / user / httpd / httpd.c
1 /* httpd.c:  A very simple http server
2  * Copyright (C) 2000      Lineo, Inc.  (www.lineo.com)
3  * Copyright (c) 1997-1999 D. Jeff Dionne <jeff@lineo.ca>
4  * Copyright (c) 1998      Kenneth Albanowski <kjahds@kjahds.com>
5  * Copyright (c) 1999      Nick Brok <nick@nbrok.iaehv.nl>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <fcntl.h>
17 #include <string.h>
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <errno.h>
22 #include <sys/stat.h>
23 #include <dirent.h>
24 #include <signal.h>
25 #include <unistd.h>
26 #include <ctype.h>
27
28 #undef DEBUG
29
30 int TIMEOUT=30;
31
32 #ifndef O_BINARY
33 #define O_BINARY 0
34 #endif
35
36 char referrer[128];
37 int content_length;
38
39 #define SERVER_PORT 80
40
41 int PrintHeader(FILE *f, int content_type)
42
43 {
44   alarm(TIMEOUT);
45   fprintf(f,"HTTP/1.0 200 OK\n");
46   switch (content_type)
47   { 
48    case 't':
49     fprintf(f,"Content-type: text/plain\n");
50     break;
51    case 'g':
52     fprintf(f,"Content-type: image/gif\n");
53     break;
54    case 'j':
55     fprintf(f,"Content-type: image/jpeg\n");
56     break;
57    case 'h':
58     fprintf(f,"Content-type: text/html\n");
59     break;
60   }
61   fprintf(f,"Server: uClinux-httpd 0.2.2\n");
62   fprintf(f,"Expires: 0\n");
63   fprintf(f,"\n");
64   alarm(0);
65   return(0);
66 }
67
68 int
69 DoJpeg(FILE *f, char *name)
70 {
71   char *buf;
72   FILE * infile;
73   int count;
74  
75   if (!(infile = fopen(name, "r"))) {
76     alarm(TIMEOUT);
77     fprintf(stderr, "Unable to open JPEG file %s, %d\n", name, errno);
78     fflush(f);
79     alarm(0);
80     return -1;
81   }
82  
83   PrintHeader(f,'j');
84  
85   copy(infile,f); /* prints the page */
86  
87   alarm(TIMEOUT);
88   fclose(infile);
89   alarm(0);
90  
91   return 0;
92 }
93
94 int
95 DoGif(FILE *f, char *name)
96 {
97   char *buf;
98   FILE * infile;
99   int count;
100
101   if (!(infile = fopen(name, "r"))) {
102     alarm(TIMEOUT);
103     fprintf(stderr, "Unable to open GIF file %s, %d\n", name, errno);
104     fflush(f);
105     alarm(0);
106     return -1;
107   }
108   
109   PrintHeader(f,'g');
110
111   copy(infile,f); /* prints the page */  
112
113   alarm(TIMEOUT);
114   fclose(infile);
115   alarm(0);
116   
117   return 0;
118 }
119
120 int
121 DoDir(FILE *f, char *name)
122 {
123   char *buf;
124   DIR * dir;
125   struct dirent * dirent;
126
127   if ((dir = opendir(name))== 0) {
128     fprintf(stderr, "Unable to open directory %s, %d\n", name, errno);
129     fflush(f);
130     return -1;
131   }
132   
133   PrintHeader(f,'h');
134   
135   alarm(TIMEOUT);
136   fprintf(f, "<H1>Index of %s</H1>\n\n",name);
137   alarm(0);
138
139   if (name[strlen(name)-1] != '/') {
140         strcat(name, "/");
141   }
142   
143   while(dirent = readdir(dir)) {
144         alarm(TIMEOUT);
145   
146         fprintf(f, "<p><a href=\"/%s%s\">%s</a></p>\n", name, dirent->d_name, dirent->d_name);
147         alarm(0);
148   }
149   
150   closedir(dir);
151   return 0;
152 }
153
154 int
155 DoHTML(FILE *f, char *name)
156 {
157   char *buf;
158   FILE *infile;
159   int count;
160   char * dir = 0;
161
162   if (!(infile = fopen(name,"r"))) {
163     alarm(TIMEOUT);
164     fprintf(stderr, "Unable to open HTML file %s, %d\n", name, errno);
165     fflush(f);
166     alarm(0);
167     return -1;
168   }
169
170   PrintHeader(f,'h');
171   copy(infile,f); /* prints the page */  
172
173   alarm(TIMEOUT);
174   fclose(infile);
175   alarm(0);
176
177   return 0;
178 }
179
180 int
181 DoText(FILE *f, char *name)
182 {
183   char *buf;
184   FILE *infile;
185   int count;
186
187   if (!(infile = fopen(name,"r"))) {
188     alarm(TIMEOUT);
189     fprintf(stderr, "Unable to open text file %s, %d\n", name, errno);
190     fflush(f);
191     alarm(0);
192     return -1;
193   }
194
195   PrintHeader(f,'t');
196   copy(infile,f); /* prints the page */  
197
198   alarm(TIMEOUT);
199   fclose(infile);
200   alarm(0);
201
202   return 0;
203 }
204
205 int
206 ParseReq(FILE *f, char *r)
207 {
208   char *bp;
209   struct stat stbuf;
210   char * arg;
211   char * c;
212   int e;
213   int raw;
214
215 #ifdef DEBUG
216   printf("req is '%s'\n", r);
217 #endif
218   
219   while(*(++r) != ' ');  /*skip non-white space*/
220   while(isspace(*r))
221         r++;
222   
223   while (*r == '/')
224         r++;
225
226   bp = r;
227   /**r = '.';*/
228   
229   while(*r && (*(r) != ' ') && (*(r) != '?'))
230         r++;
231         
232 #ifdef DEBUG
233   printf("bp='%s', r='%s'\n", bp, r);
234 #endif
235         
236   if (*r == '?')
237   {
238         char * e;
239         *r = 0;
240         arg = r+1;
241         if (e = strchr(arg,' ')) 
242         {
243                 *e = '\0';
244         }
245   } else 
246     {
247         arg = 0;
248         *r = 0;
249     }
250   
251   c = bp;
252
253   if (c[0] == '\0') strcat(c,".");
254
255   if (c && !stat(c, &stbuf)) 
256   {
257     if (S_ISDIR(stbuf.st_mode)) 
258     { 
259         char * end = c + strlen(c);
260         strcat(c, "/index.html");
261         if (!stat(c, &stbuf)) 
262         {
263                 DoHTML(f, c);
264         } 
265         else 
266         {
267                 *end = '\0';
268                 DoDir(f,c);
269         }
270     }
271     else if (!strcmp(r - 4, ".gif"))
272       DoGif(f,c);
273         else if (!strcmp(r - 4, ".jpg") || !strcmp(r - 5, ".jpeg"))
274           DoJpeg(f,c);
275             else if (!strcmp(r - 4, ".htm") || !strcmp(r - 5, ".html"))
276               DoHTML(f,c);
277                 else
278                   DoText(f,c);
279   } else
280     {
281         PrintHeader(f,'h');
282         alarm(TIMEOUT);
283         fprintf(f, "<html><head><title>404 File Not Found</title></head>\n");
284         fprintf(f, "<body>The requested URL was not found on this server</body></html>\n");
285         alarm(0);
286     }
287   return 0;
288 }
289
290 void sigalrm(int signo)
291 {
292         /* got an alarm, exit & recycle */
293         exit(0);
294 }
295
296 int
297 HandleConnect(int fd)
298 {
299   FILE *f;
300
301   char buf[160];
302   char buf1[160];
303
304   f = fdopen(fd,"a+");
305   if (!f) {
306     fprintf(stderr, "httpd: Unable to open httpd input fd, error %d\n", errno);
307     alarm(TIMEOUT);
308     close(fd);
309     alarm(0);
310     return 0;
311   }
312   setbuf(f, 0);
313
314   alarm(TIMEOUT);
315
316   if (!fgets(buf, 150, f)) {
317     fprintf(stderr, "httpd: Error reading connection, error %d\n", errno);
318     fclose(f);
319     alarm(0);
320     return 0;
321   }
322 #ifdef DEBUG
323   printf("buf = '%s'\n", buf);
324 #endif
325     
326   alarm(0);
327
328   referrer[0] = '\0';
329   content_length = -1;
330     
331   alarm(TIMEOUT);
332   while (fgets(buf1, 150, f) && (strlen(buf1) > 2)) {
333     alarm(TIMEOUT);
334 #ifdef DEBUG
335     printf("Got buf1 '%s'\n", buf1);
336 #endif
337     if (!strncasecmp(buf1, "Referer:", 8)) {
338       char * c = buf1+8;
339       while (isspace(*c))
340         c++;
341       strcpy(referrer, c);
342     } else if (!strncasecmp(buf1, "Referrer:", 9)) {
343       char * c = buf1+9;
344       while (isspace(*c))
345         c++;
346       strcpy(referrer, c);
347     } else if (!strncasecmp(buf1, "Content-length:", 15)) {
348       content_length = atoi(buf1+15);
349     } 
350   }
351   alarm(0);
352   
353   
354   if (ferror(f)) {
355     fprintf(stderr, "http: Error continuing reading connection, error %d\n", errno);
356     fclose(f);
357     return 0;
358   }
359     
360   ParseReq(f, buf);
361
362   alarm(TIMEOUT);
363   fflush(f);
364   fclose(f);
365   alarm(0);
366
367   return 1;
368 }
369
370 int
371 main(int argc, char *argv[])
372 {
373   int fd, s;
374   int len;
375   volatile int true = 1;
376   struct sockaddr_in ec;
377   struct sockaddr_in server_sockaddr;
378
379   signal(SIGCHLD, SIG_IGN);
380   signal(SIGPIPE, SIG_IGN);
381   signal(SIGALRM, sigalrm);
382
383   chroot(HTTPD_DOCUMENT_ROOT);
384   chdir("/");
385
386   if (argc > 1 && !strcmp(argv[1], "-i")) {
387     /* I'm running from inetd, handle the request on stdin */
388     fclose(stderr);
389     HandleConnect(0);
390     exit(0);
391   }
392
393   if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
394     perror("Unable to obtain network");
395     exit(1);
396   }
397   
398   if((setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&true, 
399                  sizeof(true))) == -1) {
400     perror("setsockopt failed");
401     exit(1);
402   }
403
404   server_sockaddr.sin_family = AF_INET;
405   server_sockaddr.sin_port = htons(SERVER_PORT);
406   server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
407   
408   if(bind(s, (struct sockaddr *)&server_sockaddr, 
409           sizeof(server_sockaddr)) == -1)  {
410     perror("Unable to bind socket");
411     exit(1);
412   }
413
414   if(listen(s, 8*3) == -1) { /* Arbitrary, 8 files/page, 3 clients */
415     perror("Unable to listen");
416     exit(4);
417   }
418
419   while (1) {
420     len = sizeof(ec);
421     
422     if((fd = accept(s, (void *)&ec, &len)) == -1) {
423       exit(5);
424       close(s);
425     }
426     HandleConnect(fd);
427   }
428 }