📄 util.c
字号:
/* Copyright 1999-2005 The Apache Software Foundation or its licensors, as * applicable. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//* * util.c: string utility things * * 3/21/93 Rob McCool * 1995-96 Many changes by the Apache Software Foundation * *//* Debugging aid: * #define DEBUG to trace all cfg_open*()/cfg_closefile() calls * #define DEBUG_CFG_LINES to trace every line read from the config files */#include "apr.h"#include "apr_strings.h"#include "apr_lib.h"#define APR_WANT_STDIO#define APR_WANT_STRFUNC#include "apr_want.h"#if APR_HAVE_UNISTD_H#include <unistd.h>#endif#if APR_HAVE_NETDB_H#include <netdb.h> /* for gethostbyname() */#endif#define CORE_PRIVATE#include "ap_config.h"#include "apr_base64.h"#include "httpd.h"#include "http_main.h"#include "http_log.h"#include "http_protocol.h"#include "http_config.h"#include "util_ebcdic.h"#ifdef HAVE_PWD_H#include <pwd.h>#endif#ifdef HAVE_GRP_H#include <grp.h>#endif/* A bunch of functions in util.c scan strings looking for certain characters. * To make that more efficient we encode a lookup table. The test_char_table * is generated automatically by gen_test_char.c. */#include "test_char.h"/* we assume the folks using this ensure 0 <= c < 256... which means * you need a cast to (unsigned char) first, you can't just plug a * char in here and get it to work, because if char is signed then it * will first be sign extended. */#define TEST_CHAR(c, f) (test_char_table[(unsigned)(c)] & (f))/* Win32/NetWare/OS2 need to check for both forward and back slashes * in ap_getparents() and ap_escape_url. */#ifdef CASE_BLIND_FILESYSTEM#define IS_SLASH(s) ((s == '/') || (s == '\\'))#else#define IS_SLASH(s) (s == '/')#endif/* * Examine a field value (such as a media-/content-type) string and return * it sans any parameters; e.g., strip off any ';charset=foo' and the like. */AP_DECLARE(char *) ap_field_noparam(apr_pool_t *p, const char *intype){ const char *semi; if (intype == NULL) return NULL; semi = ap_strchr_c(intype, ';'); if (semi == NULL) { return apr_pstrdup(p, intype); } else { while ((semi > intype) && apr_isspace(semi[-1])) { semi--; } return apr_pstrndup(p, intype, semi - intype); }}AP_DECLARE(char *) ap_ht_time(apr_pool_t *p, apr_time_t t, const char *fmt, int gmt){ apr_size_t retcode; char ts[MAX_STRING_LEN]; char tf[MAX_STRING_LEN]; apr_time_exp_t xt; if (gmt) { const char *f; char *strp; apr_time_exp_gmt(&xt, t); /* Convert %Z to "GMT" and %z to "+0000"; * on hosts that do not have a time zone string in struct tm, * strftime must assume its argument is local time. */ for(strp = tf, f = fmt; strp < tf + sizeof(tf) - 6 && (*strp = *f) ; f++, strp++) { if (*f != '%') continue; switch (f[1]) { case '%': *++strp = *++f; break; case 'Z': *strp++ = 'G'; *strp++ = 'M'; *strp = 'T'; f++; break; case 'z': /* common extension */ *strp++ = '+'; *strp++ = '0'; *strp++ = '0'; *strp++ = '0'; *strp = '0'; f++; break; } } *strp = '\0'; fmt = tf; } else { apr_time_exp_lt(&xt, t); } /* check return code? */ apr_strftime(ts, &retcode, MAX_STRING_LEN, fmt, &xt); ts[MAX_STRING_LEN - 1] = '\0'; return apr_pstrdup(p, ts);}/* Roy owes Rob beer. *//* Rob owes Roy dinner. *//* These legacy comments would make a lot more sense if Roy hadn't * replaced the old later_than() routine with util_date.c. * * Well, okay, they still wouldn't make any sense. *//* Match = 0, NoMatch = 1, Abort = -1 * Based loosely on sections of wildmat.c by Rich Salz * Hmmm... shouldn't this really go component by component? */AP_DECLARE(int) ap_strcmp_match(const char *str, const char *expected){ int x, y; for (x = 0, y = 0; expected[y]; ++y, ++x) { if ((!str[x]) && (expected[y] != '*')) return -1; if (expected[y] == '*') { while (expected[++y] == '*'); if (!expected[y]) return 0; while (str[x]) { int ret; if ((ret = ap_strcmp_match(&str[x++], &expected[y])) != 1) return ret; } return -1; } else if ((expected[y] != '?') && (str[x] != expected[y])) return 1; } return (str[x] != '\0');}AP_DECLARE(int) ap_strcasecmp_match(const char *str, const char *expected){ int x, y; for (x = 0, y = 0; expected[y]; ++y, ++x) { if (!str[x] && expected[y] != '*') return -1; if (expected[y] == '*') { while (expected[++y] == '*'); if (!expected[y]) return 0; while (str[x]) { int ret; if ((ret = ap_strcasecmp_match(&str[x++], &expected[y])) != 1) return ret; } return -1; } else if (expected[y] != '?' && apr_tolower(str[x]) != apr_tolower(expected[y])) return 1; } return (str[x] != '\0');}/* We actually compare the canonical root to this root, (but we don't * waste time checking the case), since every use of this function in * httpd-2.0 tests if the path is 'proper', meaning we've already passed * it through apr_filepath_merge, or we haven't. */AP_DECLARE(int) ap_os_is_path_absolute(apr_pool_t *p, const char *dir) { const char *newpath; const char *ourdir = dir; if (apr_filepath_root(&newpath, &dir, 0, p) != APR_SUCCESS || strncmp(newpath, ourdir, strlen(newpath)) != 0) { return 0; } return 1;}AP_DECLARE(int) ap_is_matchexp(const char *str){ register int x; for (x = 0; str[x]; x++) if ((str[x] == '*') || (str[x] == '?')) return 1; return 0;}/* * Here's a pool-based interface to POSIX regex's regcomp(). * Note that we return regex_t instead of being passed one. * The reason is that if you use an already-used regex_t structure, * the memory that you've already allocated gets forgotten, and * regfree() doesn't clear it. So we don't allow it. */static apr_status_t regex_cleanup(void *preg){ regfree((regex_t *) preg); return APR_SUCCESS;}AP_DECLARE(regex_t *) ap_pregcomp(apr_pool_t *p, const char *pattern, int cflags){ regex_t *preg = apr_palloc(p, sizeof(regex_t)); if (regcomp(preg, pattern, cflags)) { return NULL; } apr_pool_cleanup_register(p, (void *) preg, regex_cleanup, apr_pool_cleanup_null); return preg;}AP_DECLARE(void) ap_pregfree(apr_pool_t *p, regex_t * reg){ regfree(reg); apr_pool_cleanup_kill(p, (void *) reg, regex_cleanup);}/* * Similar to standard strstr() but we ignore case in this version. * Based on the strstr() implementation further below. */AP_DECLARE(char *) ap_strcasestr(const char *s1, const char *s2){ char *p1, *p2; if (*s2 == '\0') { /* an empty s2 */ return((char *)s1); } while(1) { for ( ; (*s1 != '\0') && (apr_tolower(*s1) != apr_tolower(*s2)); s1++); if (*s1 == '\0') { return(NULL); } /* found first character of s2, see if the rest matches */ p1 = (char *)s1; p2 = (char *)s2; for (++p1, ++p2; apr_tolower(*p1) == apr_tolower(*p2); ++p1, ++p2) { if (*p1 == '\0') { /* both strings ended together */ return((char *)s1); } } if (*p2 == '\0') { /* second string ended, a match */ break; } /* didn't find a match here, try starting at next character in s1 */ s1++; } return((char *)s1);}/* * Returns an offsetted pointer in bigstring immediately after * prefix. Returns bigstring if bigstring doesn't start with * prefix or if prefix is longer than bigstring while still matching. * NOTE: pointer returned is relative to bigstring, so we * can use standard pointer comparisons in the calling function * (eg: test if ap_stripprefix(a,b) == a) */AP_DECLARE(const char *) ap_stripprefix(const char *bigstring, const char *prefix){ const char *p1; if (*prefix == '\0') return bigstring; p1 = bigstring; while (*p1 && *prefix) { if (*p1++ != *prefix++) return bigstring; } if (*prefix == '\0') return p1; /* hit the end of bigstring! */ return bigstring;}/* * Apache stub function for the regex libraries regexec() to make sure the * whole regex(3) API is available through the Apache (exported) namespace. * This is especially important for the DSO situations of modules. * DO NOT MAKE A MACRO OUT OF THIS FUNCTION! */AP_DECLARE(int) ap_regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags){ return regexec(preg, string, nmatch, pmatch, eflags);}AP_DECLARE(size_t) ap_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size){ return regerror(errcode, preg, errbuf, errbuf_size);}/* This function substitutes for $0-$9, filling in regular expression * submatches. Pass it the same nmatch and pmatch arguments that you * passed ap_regexec(). pmatch should not be greater than the maximum number * of subexpressions - i.e. one more than the re_nsub member of regex_t. * * input should be the string with the $-expressions, source should be the * string that was matched against. * * It returns the substituted string, or NULL on error. * * Parts of this code are based on Henry Spencer's regsub(), from his * AT&T V8 regexp package. */AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input, const char *source, size_t nmatch, regmatch_t pmatch[]){ const char *src = input; char *dest, *dst; char c; size_t no; int len; if (!source) return NULL; if (!nmatch) return apr_pstrdup(p, src); /* First pass, find the size */ len = 0; while ((c = *src++) != '\0') { if (c == '&') no = 0; else if (c == '$' && apr_isdigit(*src)) no = *src++ - '0'; else no = 10; if (no > 9) { /* Ordinary character. */ if (c == '\\' && (*src == '$' || *src == '&')) c = *src++; len++; } else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) { len += pmatch[no].rm_eo - pmatch[no].rm_so; } } dest = dst = apr_pcalloc(p, len + 1); /* Now actually fill in the string */ src = input; while ((c = *src++) != '\0') { if (c == '&') no = 0; else if (c == '$' && apr_isdigit(*src)) no = *src++ - '0'; else no = 10; if (no > 9) { /* Ordinary character. */ if (c == '\\' && (*src == '$' || *src == '&')) c = *src++; *dst++ = c; } else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) { len = pmatch[no].rm_eo - pmatch[no].rm_so; memcpy(dst, source + pmatch[no].rm_so, len); dst += len; } } *dst = '\0'; return dest;}/* * Parse .. so we don't compromise security */AP_DECLARE(void) ap_getparents(char *name){ char *next; int l, w, first_dot; /* Four paseses, as per RFC 1808 */ /* a) remove ./ path segments */ for (next = name; *next && (*next != '.'); next++) { } l = w = first_dot = next - name; while (name[l] != '\0') { if (name[l] == '.' && IS_SLASH(name[l + 1]) && (l == 0 || IS_SLASH(name[l - 1]))) l += 2; else name[w++] = name[l++]; } /* b) remove trailing . path, segment */ if (w == 1 && name[0] == '.') w--; else if (w > 1 && name[w - 1] == '.' && IS_SLASH(name[w - 2])) w--; name[w] = '\0'; /* c) remove all xx/../ segments. (including leading ../ and /../) */ l = first_dot; while (name[l] != '\0') { if (name[l] == '.' && name[l + 1] == '.' && IS_SLASH(name[l + 2]) && (l == 0 || IS_SLASH(name[l - 1]))) { register int m = l + 3, n; l = l - 2; if (l >= 0) { while (l >= 0 && !IS_SLASH(name[l])) l--; l++; } else l = 0; n = l; while ((name[n] = name[m])) (++n, ++m); } else ++l; } /* d) remove trailing xx/.. segment. */ if (l == 2 && name[0] == '.' && name[1] == '.') name[0] = '\0'; else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.' && IS_SLASH(name[l - 3])) { l = l - 4; if (l >= 0) { while (l >= 0 && !IS_SLASH(name[l])) l--; l++; } else l = 0; name[l] = '\0'; }}AP_DECLARE(void) ap_no2slash(char *name){ char *d, *s; s = d = name;#ifdef HAVE_UNC_PATHS /* Check for UNC names. Leave leading two slashes. */ if (s[0] == '/' && s[1] == '/') *d++ = *s++;#endif while (*s) { if ((*d++ = *s) == '/') { do { ++s; } while (*s == '/'); } else { ++s; } } *d = '\0';}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -