Deleted Added
full compact
simple_httpd.c (42714) simple_httpd.c (43939)
1/* simpleHTTPd (C) 1998 netSTOR Technologies, Inc. ("netSTOR")
2 FreeBSD port and additional work by Marc Nicholas <marc@netstor.com>
3 Based on work by:-
4 Thierry Leconte & Yury Shimanovsky
5 My Russian webserver writing friends :-)
6
7 This is an HTTP daemon that will serve up HTML, text files, JPEGs,
8 GIFs and do simple CGI work.
9
10 You may use this code for non-commercial distribution only. Commercial
11 distribution requires the express, written permission of netSTOR. No
12 warranty is implied or given -- use at your own risk!
13*/
14
15/*
16 * $Id: simple_httpd.c,v 1.1.1.1 1998/08/27 17:38:45 abial Exp $
1/*-
2 * SimpleHTTPd v1.0 - a very small, barebones HTTP server
3 *
4 * Copyright (c) 1998-1999 Marc Nicholas <marc@netstor.com>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $Id: simple_httpd.c,v 1.2.2.1 1999/02/05 12:21:41 abial Exp $
17 */
18
19#include <stdio.h>
20#include <unistd.h>
21#include <stdlib.h>
22#include <sys/stat.h>
23#include <sys/time.h>
24#include <sys/types.h>
25#include <time.h>
26#include <sys/socket.h>
27#include <netinet/in.h>
28#include <arpa/inet.h>
29#include <netdb.h>
30#include <fcntl.h>
31#include <string.h>
32#include <signal.h>
33#include <sys/wait.h>
29 */
30
31#include <stdio.h>
32#include <unistd.h>
33#include <stdlib.h>
34#include <sys/stat.h>
35#include <sys/time.h>
36#include <sys/types.h>
37#include <time.h>
38#include <sys/socket.h>
39#include <netinet/in.h>
40#include <arpa/inet.h>
41#include <netdb.h>
42#include <fcntl.h>
43#include <string.h>
44#include <signal.h>
45#include <sys/wait.h>
34#define LOGDIR "/var/log"
35
36int http_sock, con_sock;
37int http_port = 80;
38struct sockaddr_in source;
39char homedir[100];
40char *adate();
41struct hostent *hst;
42
43void
44init_servconnection(void)
45{
46 struct sockaddr_in server;
47
48 /* Create a socket */
49 http_sock = socket(AF_INET, SOCK_STREAM, 0);
50 if (http_sock < 0) {
51 perror("socket");
52 exit(1);
53 }
54 server.sin_family = AF_INET;
55 server.sin_port = htons(http_port);
56 server.sin_addr.s_addr = INADDR_ANY;
57 if (bind(http_sock, (struct sockaddr *) & server, sizeof(server)) < 0) {
58 perror("bind socket");
59 exit(1);
60 }
61 printf("simpleHTTPd running on %d port\n",http_port);
62}
63
64attenteconnection(void)
65{
66 int lg;
67
68 lg = sizeof(struct sockaddr_in);
69
70 con_sock = accept(http_sock, (struct sockaddr *) & source, &lg);
71 if (con_sock <= 0) {
72 perror("accept");
73 exit(1);
74 }
75}
76
77outdate()
78{
79 time_t tl;
80 char buff[50];
81
82 tl = time(NULL);
83 strftime(buff, 50, "Date: %a, %d %h %Y %H:%M:%S %Z\r\n", gmtime(&tl));
84 write(con_sock, buff, strlen(buff));
85}
86
87char *rep_err_nget[2] = {"<HTML><HEAD><TITLE>Error</TITLE></HEAD><BODY><H1>Error 405</H1>\
88This server is supports only GET and HEAD requests\n</BODY></HTML>\r\n",
89"HTTP/1.0 405 Method Not allowed\r\nAllow: GET,HEAD\r\nServer: jhttpd\r\n"};
90
91char *rep_err_acc[2] = {"<HTML><HEAD><TITLE>Error</TITLE></HEAD><BODY><H1>Error 404</H1>\
92Not found - file doesn't exist or is read protected\n</BODY></HTML>\r\n",
93"HTTP/1.0 404 Not found\r\nServer: jhttpd\r\n"};
94
95outerror(char **rep, int http1) /* ������ ������ ������� � html- ���� */
96{
97
98 if (http1) {
99 write(con_sock, rep[1], strlen(rep[1]));
100 outdate();
101 write(con_sock, "\r\n", 2);
102 }
103 write(con_sock, rep[0], strlen(rep[0]));
104}
105
106char rep_head[] = "HTTP/1.0 200 OK\r\nServer: simpleHTTPD\r\n";
107
108traite_req()
109{
110 char buff[8192];
111 int fd, lg, cmd, http1, i;
112 char *filename, *c;
113 struct stat statres;
114 char req[1024];
115 char logfile[80];
116 char msg[1024];
117 char *p,
118 *par;
119 long addr;
120 FILE *log;
121
122 lg = read(con_sock, req, 1024);
123
124 if (p=strstr(req,"\n")) *p=0;
125 if (p=strstr(req,"\r")) *p=0;
126
127 if (geteuid())
128 {
129 strcpy(logfile,getenv("HOME"));
130 strcat(logfile,"/");
131 strcat(logfile,"jhttp.log");
132 }
46
47int http_sock, con_sock;
48int http_port = 80;
49struct sockaddr_in source;
50char homedir[100];
51char *adate();
52struct hostent *hst;
53
54void
55init_servconnection(void)
56{
57 struct sockaddr_in server;
58
59 /* Create a socket */
60 http_sock = socket(AF_INET, SOCK_STREAM, 0);
61 if (http_sock < 0) {
62 perror("socket");
63 exit(1);
64 }
65 server.sin_family = AF_INET;
66 server.sin_port = htons(http_port);
67 server.sin_addr.s_addr = INADDR_ANY;
68 if (bind(http_sock, (struct sockaddr *) & server, sizeof(server)) < 0) {
69 perror("bind socket");
70 exit(1);
71 }
72 printf("simpleHTTPd running on %d port\n",http_port);
73}
74
75attenteconnection(void)
76{
77 int lg;
78
79 lg = sizeof(struct sockaddr_in);
80
81 con_sock = accept(http_sock, (struct sockaddr *) & source, &lg);
82 if (con_sock <= 0) {
83 perror("accept");
84 exit(1);
85 }
86}
87
88outdate()
89{
90 time_t tl;
91 char buff[50];
92
93 tl = time(NULL);
94 strftime(buff, 50, "Date: %a, %d %h %Y %H:%M:%S %Z\r\n", gmtime(&tl));
95 write(con_sock, buff, strlen(buff));
96}
97
98char *rep_err_nget[2] = {"<HTML><HEAD><TITLE>Error</TITLE></HEAD><BODY><H1>Error 405</H1>\
99This server is supports only GET and HEAD requests\n</BODY></HTML>\r\n",
100"HTTP/1.0 405 Method Not allowed\r\nAllow: GET,HEAD\r\nServer: jhttpd\r\n"};
101
102char *rep_err_acc[2] = {"<HTML><HEAD><TITLE>Error</TITLE></HEAD><BODY><H1>Error 404</H1>\
103Not found - file doesn't exist or is read protected\n</BODY></HTML>\r\n",
104"HTTP/1.0 404 Not found\r\nServer: jhttpd\r\n"};
105
106outerror(char **rep, int http1) /* ������ ������ ������� � html- ���� */
107{
108
109 if (http1) {
110 write(con_sock, rep[1], strlen(rep[1]));
111 outdate();
112 write(con_sock, "\r\n", 2);
113 }
114 write(con_sock, rep[0], strlen(rep[0]));
115}
116
117char rep_head[] = "HTTP/1.0 200 OK\r\nServer: simpleHTTPD\r\n";
118
119traite_req()
120{
121 char buff[8192];
122 int fd, lg, cmd, http1, i;
123 char *filename, *c;
124 struct stat statres;
125 char req[1024];
126 char logfile[80];
127 char msg[1024];
128 char *p,
129 *par;
130 long addr;
131 FILE *log;
132
133 lg = read(con_sock, req, 1024);
134
135 if (p=strstr(req,"\n")) *p=0;
136 if (p=strstr(req,"\r")) *p=0;
137
138 if (geteuid())
139 {
140 strcpy(logfile,getenv("HOME"));
141 strcat(logfile,"/");
142 strcat(logfile,"jhttp.log");
143 }
133 else strcpy(logfile, LOGDIR "/jhttpd.log");
144 else strcpy(logfile,"/var/log/jhttpd.log");
134
135 if ( access(logfile,W_OK))
136 {
137 lg=creat (logfile,O_WRONLY);
138 chmod (logfile,00600);
139 close(lg);
140 }
141
142 strcpy(buff,inet_ntoa(source.sin_addr));
143
144 addr=inet_addr(buff);
145
146 strcpy(msg,adate());
147 strcat(msg," ");
148 hst=gethostbyaddr((char*) &addr, 4, AF_INET);
149 if (hst) strcat(msg,hst->h_name);
150 strcat(msg," (");
151 strcat(msg,buff);
152 strcat(msg,") ");
153 strcat(msg,req);
154
155 log=fopen(logfile,"a");
156 fprintf(log,"%s\n",msg);
157 fclose(log);
158
159 c = strtok(req, " ");
160 if (c == NULL) {
161 outerror(rep_err_nget, 0);
162 goto error;
163 }
164 cmd = 0;
165 if (strncmp(c, "GET", 3) == 0)
166 cmd = 1;
167 if (strncmp(c, "HEAD", 4) == 0) {
168 cmd = 2;
169 }
170
171 filename = strtok(NULL, " ");
172
173 http1 = 0;
174 c = strtok(NULL, " ");
175 if (c != NULL && strncmp(c, "HTTP", 4) == 0)
176 http1 = 1;
177
178 if (cmd == 0) {
179 outerror(rep_err_nget, http1);
180 goto error;
181 }
182
183 if (filename == NULL ||
184 strlen(filename)==1) filename="/index.html";
185
186 while (filename[0]== '/') filename++;
187
188 /**/
189 if (!strncmp(filename,"cgi-bin/",8))
190 {
191 par=0;
192 if (par=strstr(filename,"?"))
193 {
194 *par=0;
195 par++;
196 }
197 if (access(filename,X_OK)) goto conti;
198 stat (filename,&statres);
199 if (setuid(statres.st_uid)) return(0);
200 if (seteuid(statres.st_uid)) return(0);
201 if (!fork())
202 {
203 close(1);
204 dup(con_sock);
205 printf("HTTP/1.0 200 OK\nContent-type: text/html\n\n\n");
206 execlp (filename,filename,par,0);
207 }
208 wait(&i);
209 return(0);
210 }
211 conti:
212 if (filename == NULL) {
213 outerror(rep_err_acc, http1);
214 goto error;
215 }
216 /* interdit les .. dans le path */
217 c = filename;
218 while (*c != '\0')
219 if (c[0] == '.' && c[1] == '.') {
220 outerror(rep_err_acc, http1);
221 goto error;
222 } else
223 c++;
224
225 fd = open(filename, O_RDONLY);
226 if (fd < 0) {
227 outerror(rep_err_acc, http1);
228 goto error;
229 }
230 if (fstat(fd, &statres) < 0) {
231 outerror(rep_err_acc, http1);
232 goto error;
233 }
234 if (!S_ISREG(statres.st_mode))
235 {
236 outerror(rep_err_acc, http1);
237 goto error;
238 }
239 if (http1) {
240 char buff[50];
241 time_t tl;
242
243 write(con_sock, rep_head, strlen(rep_head));
244 sprintf(buff, "Content-length: %d\r\n", statres.st_size);
245 write(con_sock, buff, strlen(buff));
246 outdate();
247
248 if (strstr(filename,"."))
249 {
250 strcpy(buff,"Content-type: ");
251 strcat(buff,strstr(filename,".")+1);
252 strcat(buff,"\r\n");
253 write(con_sock,buff,strlen(buff));
254 }
255
256 if (strstr(filename,".txt"))
257 {
258 strcpy(buff,"Content-type: text/plain\r\n");
259 write(con_sock, buff, strlen(buff));
260 }
261
262 if (strstr(filename,".html") ||
263 strstr(filename,".htm"))
264 {
265 strcpy(buff,"Content-type: text/html\r\n");
266 write(con_sock, buff, strlen(buff));
267 }
268
269 if (strstr(filename,".gif"))
270 {
271 strcpy(buff,"Content-type: image/gif\r\n");
272 write(con_sock, buff, strlen(buff));
273 }
274
275 if (strstr(filename,".jpg"))
276 {
277 strcpy(buff,"Content-type: image/jpeg\r\n");
278 write(con_sock, buff, strlen(buff));
279 }
280
281 strftime(buff, 50, "Last-Modified: %a, %d %h %Y %H:%M:%S %Z\r\n\r\n", gmtime(&statres.st_mtime));
282 write(con_sock, buff, strlen(buff));
283 }
284 if (cmd == 1) {
285 while (lg = read(fd, buff, 8192))
286 write(con_sock, buff, lg);
287 }
288
289error:
290 close(fd);
291 close(con_sock);
292
293}
294
295
296main(int argc, char **argv)
297{
298 int lg;
299 char hello[100];
300
301 if (argc<2 && geteuid())
302 {
303 printf("Usage: simple_htppd <port>\n");
304 exit(1);
305 }
306
307 if (argc>=2) http_port = atoi(argv[1]);
308
309 strcpy (homedir,getenv("HOME"));
310 if (!geteuid()) strcpy (homedir,"/httphome");
311 else strcat (homedir,"/httphome");
312
313 strcpy(hello,homedir);
314 strcat(hello,"/0hello.html");
315
316 if (chdir(homedir))
317 {
318 perror("chdir");
319 puts(homedir);
320 exit(1);
321 }
322 init_servconnection();
323
324 if (fork()) exit(0);
325
326 setpgrp(0,65534);
327 signal(SIGQUIT, SIG_IGN);
328 signal(SIGHUP, SIG_IGN);
329
330 if (listen(http_sock,100) < 0) exit(1);
331
332 label:
333 attenteconnection();
334 if (fork())
335 {
336 close(con_sock);
337 goto label;
338 }
339 alarm(1800);
340 traite_req();
341 exit(0);
342}
343
344
345
346char *adate()
347{
348 static char out[50];
349 long now;
350 struct tm *t;
351 time(&now);
352 t = localtime(&now);
145
146 if ( access(logfile,W_OK))
147 {
148 lg=creat (logfile,O_WRONLY);
149 chmod (logfile,00600);
150 close(lg);
151 }
152
153 strcpy(buff,inet_ntoa(source.sin_addr));
154
155 addr=inet_addr(buff);
156
157 strcpy(msg,adate());
158 strcat(msg," ");
159 hst=gethostbyaddr((char*) &addr, 4, AF_INET);
160 if (hst) strcat(msg,hst->h_name);
161 strcat(msg," (");
162 strcat(msg,buff);
163 strcat(msg,") ");
164 strcat(msg,req);
165
166 log=fopen(logfile,"a");
167 fprintf(log,"%s\n",msg);
168 fclose(log);
169
170 c = strtok(req, " ");
171 if (c == NULL) {
172 outerror(rep_err_nget, 0);
173 goto error;
174 }
175 cmd = 0;
176 if (strncmp(c, "GET", 3) == 0)
177 cmd = 1;
178 if (strncmp(c, "HEAD", 4) == 0) {
179 cmd = 2;
180 }
181
182 filename = strtok(NULL, " ");
183
184 http1 = 0;
185 c = strtok(NULL, " ");
186 if (c != NULL && strncmp(c, "HTTP", 4) == 0)
187 http1 = 1;
188
189 if (cmd == 0) {
190 outerror(rep_err_nget, http1);
191 goto error;
192 }
193
194 if (filename == NULL ||
195 strlen(filename)==1) filename="/index.html";
196
197 while (filename[0]== '/') filename++;
198
199 /**/
200 if (!strncmp(filename,"cgi-bin/",8))
201 {
202 par=0;
203 if (par=strstr(filename,"?"))
204 {
205 *par=0;
206 par++;
207 }
208 if (access(filename,X_OK)) goto conti;
209 stat (filename,&statres);
210 if (setuid(statres.st_uid)) return(0);
211 if (seteuid(statres.st_uid)) return(0);
212 if (!fork())
213 {
214 close(1);
215 dup(con_sock);
216 printf("HTTP/1.0 200 OK\nContent-type: text/html\n\n\n");
217 execlp (filename,filename,par,0);
218 }
219 wait(&i);
220 return(0);
221 }
222 conti:
223 if (filename == NULL) {
224 outerror(rep_err_acc, http1);
225 goto error;
226 }
227 /* interdit les .. dans le path */
228 c = filename;
229 while (*c != '\0')
230 if (c[0] == '.' && c[1] == '.') {
231 outerror(rep_err_acc, http1);
232 goto error;
233 } else
234 c++;
235
236 fd = open(filename, O_RDONLY);
237 if (fd < 0) {
238 outerror(rep_err_acc, http1);
239 goto error;
240 }
241 if (fstat(fd, &statres) < 0) {
242 outerror(rep_err_acc, http1);
243 goto error;
244 }
245 if (!S_ISREG(statres.st_mode))
246 {
247 outerror(rep_err_acc, http1);
248 goto error;
249 }
250 if (http1) {
251 char buff[50];
252 time_t tl;
253
254 write(con_sock, rep_head, strlen(rep_head));
255 sprintf(buff, "Content-length: %d\r\n", statres.st_size);
256 write(con_sock, buff, strlen(buff));
257 outdate();
258
259 if (strstr(filename,"."))
260 {
261 strcpy(buff,"Content-type: ");
262 strcat(buff,strstr(filename,".")+1);
263 strcat(buff,"\r\n");
264 write(con_sock,buff,strlen(buff));
265 }
266
267 if (strstr(filename,".txt"))
268 {
269 strcpy(buff,"Content-type: text/plain\r\n");
270 write(con_sock, buff, strlen(buff));
271 }
272
273 if (strstr(filename,".html") ||
274 strstr(filename,".htm"))
275 {
276 strcpy(buff,"Content-type: text/html\r\n");
277 write(con_sock, buff, strlen(buff));
278 }
279
280 if (strstr(filename,".gif"))
281 {
282 strcpy(buff,"Content-type: image/gif\r\n");
283 write(con_sock, buff, strlen(buff));
284 }
285
286 if (strstr(filename,".jpg"))
287 {
288 strcpy(buff,"Content-type: image/jpeg\r\n");
289 write(con_sock, buff, strlen(buff));
290 }
291
292 strftime(buff, 50, "Last-Modified: %a, %d %h %Y %H:%M:%S %Z\r\n\r\n", gmtime(&statres.st_mtime));
293 write(con_sock, buff, strlen(buff));
294 }
295 if (cmd == 1) {
296 while (lg = read(fd, buff, 8192))
297 write(con_sock, buff, lg);
298 }
299
300error:
301 close(fd);
302 close(con_sock);
303
304}
305
306
307main(int argc, char **argv)
308{
309 int lg;
310 char hello[100];
311
312 if (argc<2 && geteuid())
313 {
314 printf("Usage: simple_htppd <port>\n");
315 exit(1);
316 }
317
318 if (argc>=2) http_port = atoi(argv[1]);
319
320 strcpy (homedir,getenv("HOME"));
321 if (!geteuid()) strcpy (homedir,"/httphome");
322 else strcat (homedir,"/httphome");
323
324 strcpy(hello,homedir);
325 strcat(hello,"/0hello.html");
326
327 if (chdir(homedir))
328 {
329 perror("chdir");
330 puts(homedir);
331 exit(1);
332 }
333 init_servconnection();
334
335 if (fork()) exit(0);
336
337 setpgrp(0,65534);
338 signal(SIGQUIT, SIG_IGN);
339 signal(SIGHUP, SIG_IGN);
340
341 if (listen(http_sock,100) < 0) exit(1);
342
343 label:
344 attenteconnection();
345 if (fork())
346 {
347 close(con_sock);
348 goto label;
349 }
350 alarm(1800);
351 traite_req();
352 exit(0);
353}
354
355
356
357char *adate()
358{
359 static char out[50];
360 long now;
361 struct tm *t;
362 time(&now);
363 t = localtime(&now);
353
354 sprintf(out, "%4d/%02d/%02d %02d:%02d:%02d",
355 t->tm_year+1900, t->tm_mon+1, t->tm_mday,
356 t->tm_hour, t->tm_min, t->tm_sec );
364 sprintf(out, "%02d:%02d:%02d %02d/%02d/%02d",
365 t->tm_hour, t->tm_min, t->tm_sec,
366 t->tm_mday, t->tm_mon+1, t->tm_year );
357 return out;
358}
367 return out;
368}