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

Contents of /hydra/src/util.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.8 - (show 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 /*
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 *
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.7 2002/09/28 16:32:37 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 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 if (retval < 0)
445 return -1;
446
447 simple_itoa(retval, reconv);
448 if (memcmp(s,reconv,strlen(s)) != 0) {
449 return -1;
450 }
451 return retval;
452 }
453
454 #define TEMP_FILE_TEMPLATE "/hydra.temp.XXXXXX"
455 #define TEMP_FILE_TEMPLATE_LEN sizeof(TEMP_FILE_TEMPLATE)-1
456
457 /* returns -1 on error */
458 int create_temporary_file(short want_unlink, char *storage, int size)
459 {
460 char boa_tempfile[MAX_PATH_LENGTH + 1];
461 int fd, total_len;
462
463 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
470 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 fd = mkstemp(boa_tempfile);
477 if (fd == -1) {
478 log_error_time();
479 perror("mkstemp");
480 return -1;
481 }
482
483 if (storage != NULL) {
484 if (total_len < size) {
485 memcpy(storage, boa_tempfile, total_len + 1);
486 } else {
487 close(fd);
488 fd = -1;
489 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 fd = -1;
499 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 perror("%s: getcwd() not defined. Aborting.", SERVER_NAME);
527 exit(1);
528 #endif
529 if (getcwd(dirbuf, DIRBUF_SIZE) == NULL) {
530 if (errno == ERANGE)
531 perror
532 (SERVER_NAME": getcwd() failed - unable to get working directory. "
533 "Aborting.");
534 else if (errno == EACCES)
535 perror(SERVER_NAME": getcwd() failed - No read access in current "
536 "directory. Aborting.");
537 else
538 perror(SERVER_NAME": getcwd() failed - unknown error. Aborting.");
539 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 perror(SERVER_NAME": eek. unable to normalize pathname");
547 exit(1);
548 }
549 if (strcmp(path,".") != 0) {
550 memcpy(dirbuf + len1, "/", 1);
551 memcpy(dirbuf + len1 + 1, path, len2 + 1);
552 }
553 /* fprintf(stderr, "%s: normalize gets \"%s\"\n", SERVER_NAME, dirbuf); */
554
555 endpath = strdup(dirbuf);
556 }
557
558 if (endpath == NULL) {
559 fprintf(stderr,
560 "%s: Cannot strdup path. Aborting.\n", SERVER_NAME);
561 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