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

Annotation of /hydra/src/util.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.14 - (hide annotations)
Sat Oct 5 16:42:53 2002 UTC (21 years, 5 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 nmav 1.1 /*
2 nmav 1.7 * Hydra, an http server
3 nmav 1.1 * 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 nmav 1.9 * Portions Copyright (C) 2002 Nikos Mavroyanopoulos <nmav@gnutls.org>
8 nmav 1.1 *
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 nmav 1.14 /* $Id: util.c,v 1.13 2002/10/04 09:11:43 nmav Exp $ */
26 nmav 1.1
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 nmav 1.2 void get_commonlog_time(char buf[30])
92 nmav 1.1 {
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 nmav 1.2 return; /* should be same as returning buf */
147 nmav 1.1 }
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 nmav 1.10 int modified_since(time_t mtime, char *if_modified_since)
201 nmav 1.1 {
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 nmav 1.10 file_gmt = gmtime(&mtime);
236 nmav 1.1 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 nmav 1.11 /* Returns the number of digits */
390 nmav 1.13 int simple_itoa(off64_t i, char buf[22])
391 nmav 1.1 {
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 nmav 1.2 char *p = &buf[21];
399 nmav 1.3 int digits = 1; /* include null char */
400    
401 nmav 1.1 *p-- = '\0';
402     do {
403 nmav 1.3 digits++;
404 nmav 1.1 *p-- = '0' + i % 10;
405     i /= 10;
406     } while (i > 0);
407 nmav 1.2
408 nmav 1.3 p++;
409     if (p!=buf) memmove( buf, p, digits);
410    
411 nmav 1.11 return digits - 1;
412 nmav 1.1 }
413 nmav 1.11
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 nmav 1.12 len2 = simple_itoa( size % 100000, buf); /* up to 5 digits */
426 nmav 1.11 memcpy( &etag[len], buf, len2);
427     len += len2;
428    
429     etag[len++] = '-';
430 nmav 1.12 len2 = simple_itoa( mod_time % 100000, buf); /* also 5 digits */
431 nmav 1.11 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 nmav 1.1
441     /* I don't "do" negative conversions
442     * Therefore, -1 indicates error
443     */
444    
445 nmav 1.3 int boa_atoi(const char *s)
446 nmav 1.1 {
447     int retval;
448 nmav 1.2 char reconv[22];
449 nmav 1.1
450     if (!isdigit(*s))
451     return -1;
452    
453 nmav 1.3 retval = atoi( s);
454 nmav 1.6 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 nmav 1.13 off64_t boa_atoll(const char *s)
465 nmav 1.6 {
466     long int retval;
467     char reconv[22];
468    
469     if (!isdigit(*s))
470     return -1;
471    
472 nmav 1.13 #ifdef HAVE_ATOLL
473     retval = atoll( s);
474     #else
475 nmav 1.6 retval = atol( s);
476 nmav 1.13 #endif
477 nmav 1.1 if (retval < 0)
478     return -1;
479    
480 nmav 1.2 simple_itoa(retval, reconv);
481 nmav 1.1 if (memcmp(s,reconv,strlen(s)) != 0) {
482     return -1;
483     }
484     return retval;
485     }
486    
487 nmav 1.8 #define TEMP_FILE_TEMPLATE "/hydra.temp.XXXXXX"
488     #define TEMP_FILE_TEMPLATE_LEN sizeof(TEMP_FILE_TEMPLATE)-1
489    
490 nmav 1.5 /* returns -1 on error */
491 nmav 1.1 int create_temporary_file(short want_unlink, char *storage, int size)
492     {
493 nmav 1.2 char boa_tempfile[MAX_PATH_LENGTH + 1];
494 nmav 1.8 int fd, total_len;
495 nmav 1.1
496 nmav 1.8 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 nmav 1.1
503 nmav 1.8 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 nmav 1.1 fd = mkstemp(boa_tempfile);
510     if (fd == -1) {
511     log_error_time();
512     perror("mkstemp");
513 nmav 1.5 return -1;
514 nmav 1.1 }
515    
516     if (storage != NULL) {
517 nmav 1.8 if (total_len < size) {
518     memcpy(storage, boa_tempfile, total_len + 1);
519 nmav 1.1 } else {
520     close(fd);
521 nmav 1.5 fd = -1;
522 nmav 1.1 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 nmav 1.5 fd = -1;
532 nmav 1.1 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 nmav 1.4 perror("%s: getcwd() not defined. Aborting.", SERVER_NAME);
560 nmav 1.1 exit(1);
561     #endif
562     if (getcwd(dirbuf, DIRBUF_SIZE) == NULL) {
563     if (errno == ERANGE)
564     perror
565 nmav 1.4 (SERVER_NAME": getcwd() failed - unable to get working directory. "
566 nmav 1.1 "Aborting.");
567     else if (errno == EACCES)
568 nmav 1.4 perror(SERVER_NAME": getcwd() failed - No read access in current "
569 nmav 1.1 "directory. Aborting.");
570     else
571 nmav 1.4 perror(SERVER_NAME": getcwd() failed - unknown error. Aborting.");
572 nmav 1.1 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 nmav 1.4 perror(SERVER_NAME": eek. unable to normalize pathname");
580 nmav 1.1 exit(1);
581     }
582     if (strcmp(path,".") != 0) {
583     memcpy(dirbuf + len1, "/", 1);
584     memcpy(dirbuf + len1 + 1, path, len2 + 1);
585     }
586 nmav 1.4 /* fprintf(stderr, "%s: normalize gets \"%s\"\n", SERVER_NAME, dirbuf); */
587 nmav 1.1
588     endpath = strdup(dirbuf);
589     }
590    
591     if (endpath == NULL) {
592     fprintf(stderr,
593 nmav 1.4 "%s: Cannot strdup path. Aborting.\n", SERVER_NAME);
594 nmav 1.1 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 nmav 1.9 }
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 nmav 1.14 }
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 nmav 1.1 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26