/[hydra]/hydra/src/util.c
ViewVC logotype

Contents of /hydra/src/util.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.5 - (show annotations)
Fri Sep 27 21:09:11 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
Changes since 1.4: +5 -4 lines
File MIME type: text/plain
Added some preliminary support for fast CGI support (Hydra Internally handled CGI) or HIC. Currently it can be used with php.

1 /*
2 * Boa, an http server
3 * Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
4 * Some changes Copyright (C) 1996,97 Larry Doolittle <ldoolitt@boa.org>
5 * Some changes Copyright (C) 1996 Charles F. Randall <crandall@goldsys.com>
6 * Some changes Copyright (C) 1996-99 Jon Nelson <jnelson@boa.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 1, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 */
23
24 /* $Id: util.c,v 1.4 2002/09/25 19:55:53 nmav Exp $ */
25
26 #include "boa.h"
27
28 #define HEX_TO_DECIMAL(char1, char2) \
29 (((char1 >= 'A') ? (((char1 & 0xdf) - 'A') + 10) : (char1 - '0')) * 16) + \
30 (((char2 >= 'A') ? (((char2 & 0xdf) - 'A') + 10) : (char2 - '0')))
31
32 const char month_tab[48] =
33 "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ";
34 const char day_tab[] = "Sun,Mon,Tue,Wed,Thu,Fri,Sat,";
35
36 /*
37 * Name: clean_pathname
38 *
39 * Description: Replaces unsafe/incorrect instances of:
40 * //[...] with /
41 * /./ with /
42 * /../ with / (technically not what we want, but browsers should deal
43 * with this, not servers)
44 */
45
46 void clean_pathname(char *pathname)
47 {
48 char *cleanpath, c;
49
50 cleanpath = pathname;
51 while ((c = *pathname++)) {
52 if (c == '/') {
53 while (1) {
54 if (*pathname == '/')
55 pathname++;
56 else if (*pathname == '.' && *(pathname + 1) == '/')
57 pathname += 2;
58 else if (*pathname == '.' && *(pathname + 1) == '.' &&
59 *(pathname + 2) == '/') {
60 pathname += 3;
61 } else
62 break;
63 }
64 c = '/';
65 }
66 *cleanpath++ = c;
67 }
68
69 *cleanpath = '\0';
70 }
71
72 /*
73 * Name: get_commonlog_time
74 *
75 * Description: Returns the current time in common log format in a static
76 * char buffer.
77 *
78 * commonlog time is exactly 25 characters long
79 * because this is only used in logging, we add " [" before and "] " after
80 * making 29 characters
81 * "[27/Feb/1998:20:20:04 +0000] "
82 *
83 * Constrast with rfc822 time:
84 * "Sun, 06 Nov 1994 08:49:37 GMT"
85 *
86 * Altered 10 Jan 2000 by Jon Nelson ala Drew Streib for non UTC logging
87 *
88 */
89
90 void get_commonlog_time(char buf[30])
91 {
92 struct tm *t;
93 char *p;
94 unsigned int a;
95 int time_offset;
96
97 if (use_localtime) {
98 t = localtime(&current_time);
99 time_offset = TIMEZONE_OFFSET(t);
100 } else {
101 t = gmtime(&current_time);
102 time_offset = 0;
103 }
104
105 p = buf + 29;
106 *p-- = '\0';
107 *p-- = ' ';
108 *p-- = ']';
109 a = abs(time_offset / 60);
110 *p-- = '0' + a % 10;
111 a /= 10;
112 *p-- = '0' + a % 6;
113 a /= 6;
114 *p-- = '0' + a % 10;
115 *p-- = '0' + a / 10;
116 *p-- = (time_offset >= 0) ? '+' : '-';
117 *p-- = ' ';
118
119 a = t->tm_sec;
120 *p-- = '0' + a % 10;
121 *p-- = '0' + a / 10;
122 *p-- = ':';
123 a = t->tm_min;
124 *p-- = '0' + a % 10;
125 *p-- = '0' + a / 10;
126 *p-- = ':';
127 a = t->tm_hour;
128 *p-- = '0' + a % 10;
129 *p-- = '0' + a / 10;
130 *p-- = ':';
131 a = 1900 + t->tm_year;
132 while (a) {
133 *p-- = '0' + a % 10;
134 a /= 10;
135 }
136 /* p points to an unused spot */
137 *p-- = '/';
138 p -= 2;
139 memcpy(p--, month_tab + 4 * (t->tm_mon), 3);
140 *p-- = '/';
141 a = t->tm_mday;
142 *p-- = '0' + a % 10;
143 *p-- = '0' + a / 10;
144 *p = '[';
145 return; /* should be same as returning buf */
146 }
147
148 /*
149 * Name: month2int
150 *
151 * Description: Turns a three letter month into a 0-11 int
152 *
153 * Note: This function is from wn-v1.07 -- it's clever and fast
154 */
155
156 int month2int(char *monthname)
157 {
158 switch (*monthname) {
159 case 'A':
160 return (*++monthname == 'p' ? 3 : 7);
161 case 'D':
162 return (11);
163 case 'F':
164 return (1);
165 case 'J':
166 if (*++monthname == 'a')
167 return (0);
168 return (*++monthname == 'n' ? 5 : 6);
169 case 'M':
170 return (*(monthname + 2) == 'r' ? 2 : 4);
171 case 'N':
172 return (10);
173 case 'O':
174 return (9);
175 case 'S':
176 return (8);
177 default:
178 return (-1);
179 }
180 }
181
182 /*
183 * Name: modified_since
184 * Description: Decides whether a file's mtime is newer than the
185 * If-Modified-Since header of a request.
186 *
187
188 Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
189 Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
190 Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
191 31 September 2000 23:59:59 GMT ; non-standard
192
193 * RETURN VALUES:
194 * 0: File has not been modified since specified time.
195 * 1: File has been.
196 * -1: Error!
197 */
198
199 int modified_since(time_t * mtime, char *if_modified_since)
200 {
201 struct tm *file_gmt;
202 char *ims_info;
203 char monthname[10 + 1];
204 int day, month, year, hour, minute, second;
205 int comp;
206
207 ims_info = if_modified_since;
208 while (*ims_info != ' ' && *ims_info != '\0')
209 ++ims_info;
210 if (*ims_info != ' ')
211 return -1;
212
213 /* the pre-space in the third scanf skips whitespace for the string */
214 if (sscanf(ims_info, "%d %3s %d %d:%d:%d GMT", /* RFC 1123 */
215 &day, monthname, &year, &hour, &minute, &second) == 6);
216 else if (sscanf(ims_info, "%d-%3s-%d %d:%d:%d GMT", /* RFC 1036 */
217 &day, monthname, &year, &hour, &minute, &second) == 6)
218 year += 1900;
219 else if (sscanf(ims_info, " %3s %d %d:%d:%d %d", /* asctime() format */
220 monthname, &day, &hour, &minute, &second, &year) == 6);
221 /* allow this non-standard date format: 31 September 2000 23:59:59 GMT */
222 /* NOTE: Use if_modified_since here, because the date *starts*
223 * with the day, versus a throwaway item
224 */
225 else if (sscanf(if_modified_since, "%d %10s %d %d:%d:%d GMT",
226 &day, monthname, &year, &hour, &minute, &second) == 6);
227 else {
228 log_error_time();
229 fprintf(stderr, "Error in %s, line %d: Unable to sscanf \"%s\"\n",
230 __FILE__, __LINE__, ims_info);
231 return -1; /* error */
232 }
233
234 file_gmt = gmtime(mtime);
235 month = month2int(monthname);
236
237 /* Go through from years to seconds -- if they are ever unequal,
238 we know which one is newer and can return */
239
240 if ((comp = 1900 + file_gmt->tm_year - year))
241 return (comp > 0);
242 if ((comp = file_gmt->tm_mon - month))
243 return (comp > 0);
244 if ((comp = file_gmt->tm_mday - day))
245 return (comp > 0);
246 if ((comp = file_gmt->tm_hour - hour))
247 return (comp > 0);
248 if ((comp = file_gmt->tm_min - minute))
249 return (comp > 0);
250 if ((comp = file_gmt->tm_sec - second))
251 return (comp > 0);
252
253 return 0; /* this person must really be into the latest/greatest */
254 }
255
256
257 /*
258 * Name: to_upper
259 *
260 * Description: Turns a string into all upper case (for HTTP_ header forming)
261 * AND changes - into _
262 */
263
264 char *to_upper(char *str)
265 {
266 char *start = str;
267
268 while (*str) {
269 if (*str == '-')
270 *str = '_';
271 else
272 *str = toupper(*str);
273
274 str++;
275 }
276
277 return start;
278 }
279
280 /*
281 * Name: unescape_uri
282 *
283 * Description: Decodes a uri, changing %xx encodings with the actual
284 * character. The query_string should already be gone.
285 *
286 * Return values:
287 * 1: success
288 * 0: illegal string
289 */
290
291 int unescape_uri(char *uri, char ** query_string)
292 {
293 char c, d;
294 char *uri_old;
295
296 uri_old = uri;
297
298 while ((c = *uri_old)) {
299 if (c == '%') {
300 uri_old++;
301 if ((c = *uri_old++) && (d = *uri_old++))
302 *uri++ = HEX_TO_DECIMAL(c, d);
303 else
304 return 0; /* NULL in chars to be decoded */
305 } else if (c == '?') { /* query string */
306 if (query_string)
307 *query_string = ++uri_old;
308 /* stop here */
309 *uri = '\0';
310 return(1);
311 break;
312 } else if (c == '#') { /* fragment */
313 /* legal part of URL, but we do *not* care.
314 * However, we still have to look for the query string */
315 if (query_string) {
316 ++uri_old;
317 while((c = *uri_old)) {
318 if (c == '?') {
319 *query_string = ++uri_old;
320 break;
321 }
322 ++uri_old;
323 }
324 }
325 break;
326 } else {
327 *uri++ = c;
328 uri_old++;
329 }
330 }
331
332 *uri = '\0';
333 return 1;
334 }
335
336 /* rfc822 (1123) time is exactly 29 characters long
337 * "Sun, 06 Nov 1994 08:49:37 GMT"
338 */
339
340 void rfc822_time_buf(char *buf, time_t s)
341 {
342 struct tm *t;
343 char *p;
344 unsigned int a;
345
346 if (!s) {
347 t = gmtime(&current_time);
348 } else
349 t = gmtime(&s);
350
351 p = buf + 28;
352 /* p points to the last char in the buf */
353
354 p -= 3;
355 /* p points to where the ' ' will go */
356 memcpy(p--, " GMT", 4);
357
358 a = t->tm_sec;
359 *p-- = '0' + a % 10;
360 *p-- = '0' + a / 10;
361 *p-- = ':';
362 a = t->tm_min;
363 *p-- = '0' + a % 10;
364 *p-- = '0' + a / 10;
365 *p-- = ':';
366 a = t->tm_hour;
367 *p-- = '0' + a % 10;
368 *p-- = '0' + a / 10;
369 *p-- = ' ';
370 a = 1900 + t->tm_year;
371 while (a) {
372 *p-- = '0' + a % 10;
373 a /= 10;
374 }
375 /* p points to an unused spot to where the space will go */
376 p -= 3;
377 /* p points to where the first char of the month will go */
378 memcpy(p--, month_tab + 4 * (t->tm_mon), 4);
379 *p-- = ' ';
380 a = t->tm_mday;
381 *p-- = '0' + a % 10;
382 *p-- = '0' + a / 10;
383 *p-- = ' ';
384 p -= 3;
385 memcpy(p, day_tab + t->tm_wday * 4, 4);
386 }
387
388 void simple_itoa(unsigned long int i, char buf[22])
389 {
390 /* 21 digits plus null terminator, good for 64-bit or smaller ints
391 * for bigger ints, use a bigger buffer!
392 *
393 * 4294967295 is, incidentally, MAX_UINT (on 32bit systems at this time)
394 * and is 10 bytes long
395 */
396 char *p = &buf[21];
397 int digits = 1; /* include null char */
398
399 *p-- = '\0';
400 do {
401 digits++;
402 *p-- = '0' + i % 10;
403 i /= 10;
404 } while (i > 0);
405
406 p++;
407 if (p!=buf) memmove( buf, p, digits);
408
409 return;
410 }
411
412 /* I don't "do" negative conversions
413 * Therefore, -1 indicates error
414 */
415
416 int boa_atoi(const char *s)
417 {
418 int retval;
419 char reconv[22];
420
421 if (!isdigit(*s))
422 return -1;
423
424 retval = atoi( s);
425 if (retval < 0)
426 return -1;
427
428 simple_itoa(retval, reconv);
429 if (memcmp(s,reconv,strlen(s)) != 0) {
430 return -1;
431 }
432 return retval;
433 }
434
435 /* returns -1 on error */
436 int create_temporary_file(short want_unlink, char *storage, int size)
437 {
438 char boa_tempfile[MAX_PATH_LENGTH + 1];
439 int fd;
440
441 snprintf(boa_tempfile, MAX_PATH_LENGTH,
442 "%s/boa-temp.XXXXXX", tempdir);
443
444 /* open temp file */
445 fd = mkstemp(boa_tempfile);
446 if (fd == -1) {
447 log_error_time();
448 perror("mkstemp");
449 return -1;
450 }
451
452 if (storage != NULL) {
453 int len = strlen(boa_tempfile);
454
455 if (len < size) {
456 memcpy(storage, boa_tempfile, len + 1);
457 } else {
458 close(fd);
459 fd = -1;
460 log_error_time();
461 fprintf(stderr, "not enough memory for memcpy in storage\n");
462 want_unlink = 1;
463 }
464 }
465
466 if (want_unlink) {
467 if (unlink(boa_tempfile) == -1) {
468 close(fd);
469 fd = -1;
470 log_error_time();
471 fprintf(stderr, "unlink temp file\n");
472 }
473 }
474
475 return (fd);
476 }
477
478 /*
479 * Name: normalize_path
480 *
481 * Description: Makes sure relative paths are made absolute
482 *
483 */
484
485 #define DIRBUF_SIZE MAX_PATH_LENGTH * 2 + 1
486 char * normalize_path(char *path)
487 {
488 char dirbuf[DIRBUF_SIZE];
489 int len1, len2;
490 char *endpath;
491
492 if (path[0] == '/') {
493 endpath = strdup(path);
494 } else {
495
496 #ifndef HAVE_GETCWD
497 perror("%s: getcwd() not defined. Aborting.", SERVER_NAME);
498 exit(1);
499 #endif
500 if (getcwd(dirbuf, DIRBUF_SIZE) == NULL) {
501 if (errno == ERANGE)
502 perror
503 (SERVER_NAME": getcwd() failed - unable to get working directory. "
504 "Aborting.");
505 else if (errno == EACCES)
506 perror(SERVER_NAME": getcwd() failed - No read access in current "
507 "directory. Aborting.");
508 else
509 perror(SERVER_NAME": getcwd() failed - unknown error. Aborting.");
510 exit(1);
511 }
512
513 /* OK, now the hard part. */
514 len1 = strlen(dirbuf);
515 len2 = strlen(path);
516 if (len1 + len2 > MAX_PATH_LENGTH * 2) {
517 perror(SERVER_NAME": eek. unable to normalize pathname");
518 exit(1);
519 }
520 if (strcmp(path,".") != 0) {
521 memcpy(dirbuf + len1, "/", 1);
522 memcpy(dirbuf + len1 + 1, path, len2 + 1);
523 }
524 /* fprintf(stderr, "%s: normalize gets \"%s\"\n", SERVER_NAME, dirbuf); */
525
526 endpath = strdup(dirbuf);
527 }
528
529 if (endpath == NULL) {
530 fprintf(stderr,
531 "%s: Cannot strdup path. Aborting.\n", SERVER_NAME);
532 exit(1);
533 }
534 return endpath;
535 }
536
537 int real_set_block_fd(int fd)
538 {
539 int flags;
540
541 flags = fcntl(fd, F_GETFL);
542 if (flags == -1)
543 return -1;
544
545 flags &= ~O_NONBLOCK;
546 flags = fcntl(fd, F_SETFL, flags);
547 return flags;
548 }
549
550 int real_set_nonblock_fd(int fd)
551 {
552 int flags;
553
554 flags = fcntl(fd, F_GETFL);
555 if (flags == -1)
556 return -1;
557
558 flags |= O_NONBLOCK;
559 flags = fcntl(fd, F_SETFL, flags);
560 return flags;
561 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26