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

Annotation of /hydra/src/util.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.8 - (hide annotations)
Sat Sep 28 17:49:13 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
CVS Tags: hydra_0_0_3
Changes since 1.7: +19 -9 lines
File MIME type: text/plain
*** empty log message ***

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     *
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 nmav 1.8 /* $Id: util.c,v 1.7 2002/09/28 16:32:37 nmav Exp $ */
25 nmav 1.1
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 nmav 1.2 void get_commonlog_time(char buf[30])
91 nmav 1.1 {
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 nmav 1.2 return; /* should be same as returning buf */
146 nmav 1.1 }
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 nmav 1.3 void simple_itoa(unsigned long int i, char buf[22])
389 nmav 1.1 {
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 nmav 1.2 char *p = &buf[21];
397 nmav 1.3 int digits = 1; /* include null char */
398    
399 nmav 1.1 *p-- = '\0';
400     do {
401 nmav 1.3 digits++;
402 nmav 1.1 *p-- = '0' + i % 10;
403     i /= 10;
404     } while (i > 0);
405 nmav 1.2
406 nmav 1.3 p++;
407     if (p!=buf) memmove( buf, p, digits);
408    
409 nmav 1.2 return;
410 nmav 1.1 }
411    
412     /* I don't "do" negative conversions
413     * Therefore, -1 indicates error
414     */
415    
416 nmav 1.3 int boa_atoi(const char *s)
417 nmav 1.1 {
418     int retval;
419 nmav 1.2 char reconv[22];
420 nmav 1.1
421     if (!isdigit(*s))
422     return -1;
423    
424 nmav 1.3 retval = atoi( s);
425 nmav 1.6 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     long boa_atol(const char *s)
436     {
437     long int retval;
438     char reconv[22];
439    
440     if (!isdigit(*s))
441     return -1;
442    
443     retval = atol( s);
444 nmav 1.1 if (retval < 0)
445     return -1;
446    
447 nmav 1.2 simple_itoa(retval, reconv);
448 nmav 1.1 if (memcmp(s,reconv,strlen(s)) != 0) {
449     return -1;
450     }
451     return retval;
452     }
453    
454 nmav 1.8 #define TEMP_FILE_TEMPLATE "/hydra.temp.XXXXXX"
455     #define TEMP_FILE_TEMPLATE_LEN sizeof(TEMP_FILE_TEMPLATE)-1
456    
457 nmav 1.5 /* returns -1 on error */
458 nmav 1.1 int create_temporary_file(short want_unlink, char *storage, int size)
459     {
460 nmav 1.2 char boa_tempfile[MAX_PATH_LENGTH + 1];
461 nmav 1.8 int fd, total_len;
462 nmav 1.1
463 nmav 1.8 total_len = tempdir_len + TEMP_FILE_TEMPLATE_LEN;
464     if (total_len > MAX_PATH_LENGTH) {
465     log_error_time();
466     fprintf(stderr, "Temporary file length (%d) is too long\n", total_len);
467     return -1;
468     }
469 nmav 1.1
470 nmav 1.8 memcpy( boa_tempfile, tempdir, tempdir_len);
471     memcpy( &boa_tempfile[tempdir_len], TEMP_FILE_TEMPLATE, TEMP_FILE_TEMPLATE_LEN);
472     boa_tempfile[total_len] = 0; /* null terminated */
473    
474     /* open temp file
475     */
476 nmav 1.1 fd = mkstemp(boa_tempfile);
477     if (fd == -1) {
478     log_error_time();
479     perror("mkstemp");
480 nmav 1.5 return -1;
481 nmav 1.1 }
482    
483     if (storage != NULL) {
484 nmav 1.8 if (total_len < size) {
485     memcpy(storage, boa_tempfile, total_len + 1);
486 nmav 1.1 } else {
487     close(fd);
488 nmav 1.5 fd = -1;
489 nmav 1.1 log_error_time();
490     fprintf(stderr, "not enough memory for memcpy in storage\n");
491     want_unlink = 1;
492     }
493     }
494    
495     if (want_unlink) {
496     if (unlink(boa_tempfile) == -1) {
497     close(fd);
498 nmav 1.5 fd = -1;
499 nmav 1.1 log_error_time();
500     fprintf(stderr, "unlink temp file\n");
501     }
502     }
503    
504     return (fd);
505     }
506    
507     /*
508     * Name: normalize_path
509     *
510     * Description: Makes sure relative paths are made absolute
511     *
512     */
513    
514     #define DIRBUF_SIZE MAX_PATH_LENGTH * 2 + 1
515     char * normalize_path(char *path)
516     {
517     char dirbuf[DIRBUF_SIZE];
518     int len1, len2;
519     char *endpath;
520    
521     if (path[0] == '/') {
522     endpath = strdup(path);
523     } else {
524    
525     #ifndef HAVE_GETCWD
526 nmav 1.4 perror("%s: getcwd() not defined. Aborting.", SERVER_NAME);
527 nmav 1.1 exit(1);
528     #endif
529     if (getcwd(dirbuf, DIRBUF_SIZE) == NULL) {
530     if (errno == ERANGE)
531     perror
532 nmav 1.4 (SERVER_NAME": getcwd() failed - unable to get working directory. "
533 nmav 1.1 "Aborting.");
534     else if (errno == EACCES)
535 nmav 1.4 perror(SERVER_NAME": getcwd() failed - No read access in current "
536 nmav 1.1 "directory. Aborting.");
537     else
538 nmav 1.4 perror(SERVER_NAME": getcwd() failed - unknown error. Aborting.");
539 nmav 1.1 exit(1);
540     }
541    
542     /* OK, now the hard part. */
543     len1 = strlen(dirbuf);
544     len2 = strlen(path);
545     if (len1 + len2 > MAX_PATH_LENGTH * 2) {
546 nmav 1.4 perror(SERVER_NAME": eek. unable to normalize pathname");
547 nmav 1.1 exit(1);
548     }
549     if (strcmp(path,".") != 0) {
550     memcpy(dirbuf + len1, "/", 1);
551     memcpy(dirbuf + len1 + 1, path, len2 + 1);
552     }
553 nmav 1.4 /* fprintf(stderr, "%s: normalize gets \"%s\"\n", SERVER_NAME, dirbuf); */
554 nmav 1.1
555     endpath = strdup(dirbuf);
556     }
557    
558     if (endpath == NULL) {
559     fprintf(stderr,
560 nmav 1.4 "%s: Cannot strdup path. Aborting.\n", SERVER_NAME);
561 nmav 1.1 exit(1);
562     }
563     return endpath;
564     }
565    
566     int real_set_block_fd(int fd)
567     {
568     int flags;
569    
570     flags = fcntl(fd, F_GETFL);
571     if (flags == -1)
572     return -1;
573    
574     flags &= ~O_NONBLOCK;
575     flags = fcntl(fd, F_SETFL, flags);
576     return flags;
577     }
578    
579     int real_set_nonblock_fd(int fd)
580     {
581     int flags;
582    
583     flags = fcntl(fd, F_GETFL);
584     if (flags == -1)
585     return -1;
586    
587     flags |= O_NONBLOCK;
588     flags = fcntl(fd, F_SETFL, flags);
589     return flags;
590     }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26