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

Contents of /hydra/src/util.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.14 - (show annotations)
Sat Oct 5 16:42:53 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
CVS Tags: hydra_0_0_7
Changes since 1.13: +29 -1 lines
File MIME type: text/plain
Corrected behavour in SIGHUP signal handling, and now can read
the SSL related variables.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26