📄 util.c
字号:
/* * Boa, an http server * Copyright (C) 1995 Paul Phillips <paulp@go2net.com> * Some changes Copyright (C) 1996 Charles F. Randall <crandall@goldsys.com> * Copyright (C) 1996-1999 Larry Doolittle <ldoolitt@boa.org> * Copyright (C) 1996-2005 Jon Nelson <jnelson@boa.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 1, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * *//* $Id: util.c,v 1.61.2.22 2005/02/22 14:11:29 jnelson Exp $ */#include "boa.h"static int date_to_tm(struct tm *file_gmt, const char *cmtime);/* Don't need or want the trailing nul for these character arrays */static const char month_tab[48] = "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ";static const char day_tab[28] = "Sun,Mon,Tue,Wed,Thu,Fri,Sat,";/* * Name: clean_pathname * * Description: Replaces unsafe/incorrect instances of: * //[...] with / * /./ with / * /../ with / (technically not what we want, but browsers should deal * with this, not servers) */void clean_pathname(char *pathname){ char *cleanpath, c; cleanpath = pathname; while ((c = *pathname++)) { if (c == '/') { while (1) { if (*pathname == '/') pathname++; else if (*pathname == '.' && *(pathname + 1) == '/') pathname += 2; else if (*pathname == '.' && *(pathname + 1) == '.' && *(pathname + 2) == '/') { pathname += 3; } else break; } c = '/'; } *cleanpath++ = c; } *cleanpath = '\0';}#if 0char *new_clean_pathname(char *pathname){ static char *segment[50]; int seg_count = 0; char *a, *cleanpath, c; a = pathname; segment[seg_count] = pathname; cleanpath = pathname; while ((c = *pathname++)) { if (c == '/') { /* /?? */ while (1) { /* everything in this loop gets eliminated */ if (*pathname == '/') /* // */ pathname++; else if (*pathname == '.') { /* /. */ if (*(pathname + 1) == '/') /* /./ */ pathname += 2; else if (*(pathname + 1) == '\0') /* /.$ */ pathname += 1; else if (*(pathname + 1) == '.') { /* /.. */ if (*(pathname + 2) == '/') /* /../ */ pathname += 3; else if (*(pathname + 1) == '\0') /* /..$ */ pathname += 2; /* cleanpath goes *back* one */ if (seg_count) cleanpath = segment[--seg_count]; else { *a = '\0'; return a; } } else { /* /.blah */ break; } } else { /* we have /something */ break; } } if (seg_count > 49) { /* we can store in spots 0...49 */ *a = '\0'; return a; } *cleanpath = '/'; segment[seg_count++] = cleanpath++; } else *cleanpath++ = c; } *cleanpath = '\0'; return a;}#endif/* * Name: get_commonlog_time * * Description: Returns the current time in common log format in a static * char buffer. * * commonlog time is exactly 25 characters long * because this is only used in logging, we add " [" before and "] " after * making 29 characters * "[27/Feb/1998:20:20:04 +0000] " * * Contrast with rfc822 time: * "Sun, 06 Nov 1994 08:49:37 GMT" * * Altered 10 Jan 2000 by Jon Nelson ala Drew Streib for non UTC logging * */char *get_commonlog_time(void){ struct tm *t; char *p; unsigned int a; static char buf[30]; int time_offset; if (use_localtime) { t = localtime(¤t_time); time_offset = TIMEZONE_OFFSET(t); } else { t = gmtime(¤t_time); time_offset = 0; } p = buf + 29; *p-- = '\0'; *p-- = ' '; *p-- = ']'; a = abs(time_offset / 60); *p-- = '0' + a % 10; a /= 10; *p-- = '0' + a % 6; a /= 6; *p-- = '0' + a % 10; *p-- = '0' + a / 10; *p-- = (time_offset >= 0) ? '+' : '-'; *p-- = ' '; a = t->tm_sec; *p-- = '0' + a % 10; *p-- = '0' + a / 10; *p-- = ':'; a = t->tm_min; *p-- = '0' + a % 10; *p-- = '0' + a / 10; *p-- = ':'; a = t->tm_hour; *p-- = '0' + a % 10; *p-- = '0' + a / 10; *p-- = ':'; a = 1900 + t->tm_year; while (a) { *p-- = '0' + a % 10; a /= 10; } /* p points to an unused spot */ *p-- = '/'; p -= 2; memcpy(p--, month_tab + 4 * (t->tm_mon), 3); *p-- = '/'; a = t->tm_mday; *p-- = '0' + a % 10; *p-- = '0' + a / 10; *p = '['; return p; /* should be same as returning buf */}/* * Name: month2int * * Description: Turns a three letter month into a 0-11 int * * Note: This function is from wn-v1.07 -- it's clever and fast */int month2int(const char *monthname){ switch (*monthname) { case 'A': return (*++monthname == 'p' ? 3 : 7); case 'D': return (11); case 'F': return (1); case 'J': if (*++monthname == 'a') return 0; return (*++monthname == 'n' ? 5 : 6); case 'M': return (*(monthname + 2) == 'r' ? 2 : 4); case 'N': return (10); case 'O': return (9); case 'S': return (8); default: return (-1); }}/* * Name: date_to_seconds * Description: * Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format 31 September 2000 23:59:59 GMT ; non-standard * RETURN VALUES: * -1 for error, 0 for success */static int date_to_tm(struct tm *parsed_gmt, const char *cmtime){ char monthname[10 + 1]; const char *cmtime_start = cmtime; int day, year, hour, minute, second; /* we don't use the weekday portion, so skip over it */ while (*cmtime != ' ' && *cmtime != '\0') ++cmtime; if (*cmtime != ' ') return -1; /* the pre-space in the third scanf skips whitespace for the string */ if (sscanf(cmtime, "%d %3s %d %d:%d:%d GMT", /* RFC 1123 */ &day, monthname, &year, &hour, &minute, &second) == 6) { } else if (sscanf(cmtime, "%d-%3s-%d %d:%d:%d GMT", /* RFC 1036 */ &day, monthname, &year, &hour, &minute, &second) == 6) { } else if (sscanf(cmtime, "%3s %d %d:%d:%d %d", /* asctime() format */ monthname, &day, &hour, &minute, &second, &year) == 6) { /* * allow this non-standard date format: 31 September 2000 23:59:59 GMT * NOTE: Use 'cmtime_start' instead of 'cmtime' here, because the date *starts* * with the day, versus a throwaway item */ } else if (sscanf(cmtime_start, "%d %10s %d %d:%d:%d GMT", &day, monthname, &year, &hour, &minute, &second) == 6) { } else { log_error_time(); fprintf(stderr, "Error in %s, line %d: Unable to sscanf \"%s\"\n", __FILE__, __LINE__, cmtime); return -1; /* error */ } if (year < 70) year += 100; if (year > 1900) year -= 1900; parsed_gmt->tm_sec = second; parsed_gmt->tm_min = minute; parsed_gmt->tm_hour = hour; parsed_gmt->tm_mday = day; parsed_gmt->tm_mon = month2int(monthname); parsed_gmt->tm_year = year; parsed_gmt->tm_wday = 0; parsed_gmt->tm_yday = 0; parsed_gmt->tm_isdst = 0; if (parsed_gmt->tm_mon == -1) { log_error_time(); fprintf(stderr, "Invalid month name: \"%s\"\n", monthname); return -1; } /* adapted from Squid 2.5 */ if (parsed_gmt->tm_sec < 0 || parsed_gmt->tm_sec > 59) return -1; if (parsed_gmt->tm_min < 0 || parsed_gmt->tm_min > 59) return -1; if (parsed_gmt->tm_hour < 0 || parsed_gmt->tm_hour > 23) return -1; if (parsed_gmt->tm_mday < 1 || parsed_gmt->tm_mday > 31) return -1; if (parsed_gmt->tm_mon < 0 || parsed_gmt->tm_mon > 11) return -1; if (parsed_gmt->tm_year < 70 || parsed_gmt->tm_year > 120) return -1; return 0;}/* * Name: modified_since * Description: Decides whether a file's mtime is newer than the * If-Modified-Since header of a request. * * RETURN VALUES: * 0: File has not been modified since specified time. * >0: File has been (and value is the converted_time) * -1: Error! */int modified_since(time_t * mtime, const char *if_modified_since){ struct tm *file_gmt; struct tm parsed_gmt; int comp; if (date_to_tm(&parsed_gmt, if_modified_since) != 0) { return -1; } file_gmt = gmtime(mtime); /* Go through from years to seconds -- if they are ever unequal, we know which one is newer and can return */ if ((comp = file_gmt->tm_year - parsed_gmt.tm_year)) return (comp > 0); if ((comp = file_gmt->tm_mon - parsed_gmt.tm_mon)) return (comp > 0); if ((comp = file_gmt->tm_mday - parsed_gmt.tm_mday)) return (comp > 0); if ((comp = file_gmt->tm_hour - parsed_gmt.tm_hour)) return (comp > 0); if ((comp = file_gmt->tm_min - parsed_gmt.tm_min)) return (comp > 0); if ((comp = file_gmt->tm_sec - parsed_gmt.tm_sec)) return (comp > 0); /* this person must really be into the latest/greatest */ return 0;}/* * Name: to_upper * * Description: Turns a string into all upper case (for HTTP_ header forming) * AND changes - into _ */char *to_upper(char *str){ char *start = str; while (*str) { if (*str == '-') *str = '_'; else *str = toupper(*str); str++; } return start;}/* * Name: unescape_uri * * Description: Decodes a uri, changing %xx encodings with the actual * character. The query_string should already be gone. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -