X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=urlmatch.c;h=4670f310aea5c4e2fd3b7d1addf879ed56c0f766;hp=2886f27b933a9c9d0e7d56701c34347411683e8f;hb=873efe14859c0fb3f53a905eb346c36cf5fe7eda;hpb=7ec8373d06e66e3ddb543b80b50dd9ead1f3874b diff --git a/urlmatch.c b/urlmatch.c index 2886f27b..4670f310 100644 --- a/urlmatch.c +++ b/urlmatch.c @@ -1,4 +1,3 @@ -const char urlmatch_rcs[] = "$Id: urlmatch.c,v 1.73 2012/11/29 09:57:39 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/urlmatch.c,v $ @@ -6,8 +5,8 @@ const char urlmatch_rcs[] = "$Id: urlmatch.c,v 1.73 2012/11/29 09:57:39 fabianke * Purpose : Declares functions to match URLs against URL * patterns. * - * Copyright : Written by and Copyright (C) 2001-2011 - * the Privoxy team. http://www.privoxy.org/ + * Copyright : Written by and Copyright (C) 2001-2020 + * the Privoxy team. https://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and @@ -46,7 +45,7 @@ const char urlmatch_rcs[] = "$Id: urlmatch.c,v 1.73 2012/11/29 09:57:39 fabianke #include #include -#if !defined(_WIN32) && !defined(__OS2__) +#if !defined(_WIN32) #include #endif @@ -56,8 +55,6 @@ const char urlmatch_rcs[] = "$Id: urlmatch.c,v 1.73 2012/11/29 09:57:39 fabianke #include "miscutil.h" #include "errlog.h" -const char urlmatch_h_rcs[] = URLMATCH_H_VERSION; - enum regex_anchoring { NO_ANCHORING, @@ -65,7 +62,10 @@ enum regex_anchoring RIGHT_ANCHORED, RIGHT_ANCHORED_HOST }; -static jb_err compile_host_pattern(struct url_spec *url, const char *host_pattern); +static jb_err compile_vanilla_host_pattern(struct pattern_spec *url, const char *host_pattern); +#ifdef FEATURE_PCRE_HOST_PATTERNS +static jb_err compile_pcre_host_pattern(struct pattern_spec *url, const char *host_pattern); +#endif /********************************************************************* * @@ -90,17 +90,14 @@ void free_http_request(struct http_request *http) freez(http->url); freez(http->hostport); freez(http->path); - freez(http->ver); + freez(http->version); freez(http->host_ip_addr_str); -#ifndef FEATURE_EXTENDED_HOST_PATTERNS freez(http->dbuffer); freez(http->dvec); http->dcount = 0; -#endif } -#ifndef FEATURE_EXTENDED_HOST_PATTERNS /********************************************************************* * * Function : init_domain_components @@ -155,7 +152,6 @@ jb_err init_domain_components(struct http_request *http) return JB_ERR_OK; } -#endif /* ndef FEATURE_EXTENDED_HOST_PATTERNS */ /********************************************************************* @@ -267,7 +263,9 @@ jb_err parse_http_url(const char *url, struct http_request *http, int require_pr else if (strncmpic(url_noproto, "https://", 8) == 0) { /* - * Should only happen when called from cgi_show_url_info(). + * Should only happen when called from cgi_show_url_info() + * or when the request was https-inspected and the request + * line got rewritten. */ url_noproto += 8; http->ssl = 1; @@ -294,14 +292,19 @@ jb_err parse_http_url(const char *url, struct http_request *http, int require_pr /* * Got a path. * - * NOTE: The following line ignores the path for HTTPS URLS. - * This means that you get consistent behaviour if you type a - * https URL in and it's parsed by the function. (When the - * URL is actually retrieved, SSL hides the path part). + * If FEATURE_HTTPS_INSPECTION isn't available, ignore the + * path for https URLs so that we get consistent behaviour + * if a https URL is parsed. When the URL is actually + * retrieved, https hides the path part. */ - http->path = strdup_or_die(http->ssl ? "/" : url_path); + http->path = strdup_or_die( +#ifndef FEATURE_HTTPS_INSPECTION + http->ssl ? "/" : +#endif + url_path + ); *url_path = '\0'; - http->hostport = strdup_or_die(url_noproto); + http->hostport = string_tolower(url_noproto); } else { @@ -310,10 +313,15 @@ jb_err parse_http_url(const char *url, struct http_request *http, int require_pr * or CONNECT requests */ http->path = strdup_or_die("/"); - http->hostport = strdup_or_die(url_noproto); + http->hostport = string_tolower(url_noproto); } freez(buf); + + if (http->hostport == NULL) + { + return JB_ERR_PARSE; + } } if (!host_available) @@ -406,12 +414,8 @@ jb_err parse_http_url(const char *url, struct http_request *http, int require_pr freez(buf); } -#ifdef FEATURE_EXTENDED_HOST_PATTERNS - return JB_ERR_OK; -#else /* Split domain name so we can compare it against wildcards */ return init_domain_components(http); -#endif /* def FEATURE_EXTENDED_HOST_PATTERNS */ } @@ -454,6 +458,12 @@ static int unknown_method(const char *method) */ "VERSION-CONTROL", "REPORT", "CHECKOUT", "CHECKIN", "UNCHECKOUT", "MKWORKSPACE", "UPDATE", "LABEL", "MERGE", "BASELINE-CONTROL", "MKACTIVITY", + /* + * The PATCH method is defined by RFC5789, the format of the + * actual patch in the body depends on the application, but from + * Privoxy's point of view it doesn't matter. + */ + "PATCH", }; int i; @@ -470,6 +480,50 @@ static int unknown_method(const char *method) } +/********************************************************************* + * + * Function : normalize_http_version + * + * Description : Take a supported HTTP version string and remove + * leading zeroes etc., reject unsupported versions. + * + * This is an explicit RFC 2616 (3.1) MUST and + * RFC 7230 mandates that intermediaries send their + * own HTTP-version in forwarded messages. + * + * Parameters : + * 1 : http_version = HTTP version string + * + * Returns : JB_ERR_OK on success + * JB_ERR_PARSE if the HTTP version is unsupported + * + *********************************************************************/ +static jb_err normalize_http_version(char *http_version) +{ + unsigned int major_version; + unsigned int minor_version; + + if (2 != sscanf(http_version, "HTTP/%u.%u", &major_version, &minor_version)) + { + log_error(LOG_LEVEL_ERROR, "Unsupported HTTP version: %s", http_version); + return JB_ERR_PARSE; + } + + if (major_version != 1 || (minor_version != 0 && minor_version != 1)) + { + log_error(LOG_LEVEL_ERROR, "The only supported HTTP " + "versions are 1.0 and 1.1. This rules out: %s", http_version); + return JB_ERR_PARSE; + } + + assert(strlen(http_version) >= 8); + snprintf(http_version, 9, "HTTP/%u.%u", major_version, minor_version); + + return JB_ERR_OK; + +} + + /********************************************************************* * * Function : parse_http_request @@ -489,7 +543,7 @@ static int unknown_method(const char *method) jb_err parse_http_request(const char *req, struct http_request *http) { char *buf; - char *v[10]; /* XXX: Why 10? We should only need three. */ + char *v[3]; int n; jb_err err; @@ -520,10 +574,8 @@ jb_err parse_http_request(const char *req, struct http_request *http) return JB_ERR_PARSE; } - if (strcmpic(v[2], "HTTP/1.1") && strcmpic(v[2], "HTTP/1.0")) + if (JB_ERR_OK != normalize_http_version(v[2])) { - log_error(LOG_LEVEL_ERROR, "The only supported HTTP " - "versions are 1.0 and 1.1. This rules out: %s", v[2]); freez(buf); return JB_ERR_PARSE; } @@ -542,7 +594,8 @@ jb_err parse_http_request(const char *req, struct http_request *http) */ http->cmd = strdup_or_die(req); http->gpc = strdup_or_die(v[0]); - http->ver = strdup_or_die(v[2]); + http->version = strdup_or_die(v[2]); + http->ocmd = strdup_or_die(http->cmd); freez(buf); @@ -568,19 +621,18 @@ jb_err parse_http_request(const char *req, struct http_request *http) * 4 : regex = Where the compiled regex should be stored. * * Returns : JB_ERR_OK - Success - * JB_ERR_MEMORY - Out of memory * JB_ERR_PARSE - Cannot parse regex * *********************************************************************/ static jb_err compile_pattern(const char *pattern, enum regex_anchoring anchoring, - struct url_spec *url, regex_t **regex) + struct pattern_spec *url, regex_t **regex) { int errcode; - char rebuf[BUFFER_SIZE]; const char *fmt = NULL; + char *rebuf; + size_t rebuf_size; assert(pattern); - assert(strlen(pattern) < sizeof(rebuf) - 2); if (pattern[0] == '\0') { @@ -606,32 +658,30 @@ static jb_err compile_pattern(const char *pattern, enum regex_anchoring anchorin log_error(LOG_LEVEL_FATAL, "Invalid anchoring in compile_pattern %d", anchoring); } + rebuf_size = strlen(pattern) + strlen(fmt); + rebuf = malloc_or_die(rebuf_size); + *regex = zalloc_or_die(sizeof(**regex)); - *regex = zalloc(sizeof(**regex)); - if (NULL == *regex) - { - free_url_spec(url); - return JB_ERR_MEMORY; - } - - snprintf(rebuf, sizeof(rebuf), fmt, pattern); + snprintf(rebuf, rebuf_size, fmt, pattern); errcode = regcomp(*regex, rebuf, (REG_EXTENDED|REG_NOSUB|REG_ICASE)); if (errcode) { - size_t errlen = regerror(errcode, *regex, rebuf, sizeof(rebuf)); - if (errlen > (sizeof(rebuf) - (size_t)1)) + size_t errlen = regerror(errcode, *regex, rebuf, rebuf_size); + if (errlen > (rebuf_size - (size_t)1)) { - errlen = sizeof(rebuf) - (size_t)1; + errlen = rebuf_size - (size_t)1; } rebuf[errlen] = '\0'; log_error(LOG_LEVEL_ERROR, "error compiling %s from %s: %s", pattern, url->spec, rebuf); - free_url_spec(url); + free_pattern_spec(url); + freez(rebuf); return JB_ERR_PARSE; } + freez(rebuf); return JB_ERR_OK; @@ -645,7 +695,7 @@ static jb_err compile_pattern(const char *pattern, enum regex_anchoring anchorin * Description : Compiles the three parts of an URL pattern. * * Parameters : - * 1 : url = Target url_spec to be filled in. + * 1 : url = Target pattern_spec to be filled in. * 2 : buf = The url pattern to compile. Will be messed up. * * Returns : JB_ERR_OK - Success @@ -653,9 +703,39 @@ static jb_err compile_pattern(const char *pattern, enum regex_anchoring anchorin * JB_ERR_PARSE - Cannot parse regex * *********************************************************************/ -static jb_err compile_url_pattern(struct url_spec *url, char *buf) +static jb_err compile_url_pattern(struct pattern_spec *url, char *buf) { char *p; + const size_t prefix_length = 18; + +#ifdef FEATURE_PCRE_HOST_PATTERNS + if (strncmpic(buf, "PCRE-HOST-PATTERN:", prefix_length) == 0) + { + url->pattern.url_spec.host_regex_type = PCRE_HOST_PATTERN; + /* Overwrite the "PCRE-HOST-PATTERN:" prefix */ + memmove(buf, buf+prefix_length, strlen(buf+prefix_length)+1); + } + else + { + url->pattern.url_spec.host_regex_type = VANILLA_HOST_PATTERN; + } +#else + if (strncmpic(buf, "PCRE-HOST-PATTERN:", prefix_length) == 0) + { + log_error(LOG_LEVEL_ERROR, + "PCRE-HOST-PATTERN detected while Privoxy has been compiled " + "without FEATURE_PCRE_HOST_PATTERNS: %s", + buf); + /* Overwrite the "PCRE-HOST-PATTERN:" prefix */ + memmove(buf, buf+prefix_length, strlen(buf+prefix_length)+1); + /* + * The pattern will probably not work as expected. + * We don't simply return JB_ERR_PARSE here so the + * regression tests can be loaded with and without + * FEATURE_PCRE_HOST_PATTERNS. + */ + } +#endif p = strchr(buf, '/'); if (NULL != p) @@ -669,7 +749,7 @@ static jb_err compile_url_pattern(struct url_spec *url, char *buf) /* * XXX: does it make sense to compile the slash at the beginning? */ - jb_err err = compile_pattern(p, LEFT_ANCHORED, url, &url->preg); + jb_err err = compile_pattern(p, LEFT_ANCHORED, url, &url->pattern.url_spec.preg); if (JB_ERR_OK != err) { @@ -709,16 +789,25 @@ static jb_err compile_url_pattern(struct url_spec *url, char *buf) if (NULL != p) { *p++ = '\0'; - url->port_list = strdup_or_die(p); + url->pattern.url_spec.port_list = strdup_or_die(p); } else { - url->port_list = NULL; + url->pattern.url_spec.port_list = NULL; } if (buf[0] != '\0') { - return compile_host_pattern(url, buf); +#ifdef FEATURE_PCRE_HOST_PATTERNS + if (url->pattern.url_spec.host_regex_type == PCRE_HOST_PATTERN) + { + return compile_pcre_host_pattern(url, buf); + } + else +#endif + { + return compile_vanilla_host_pattern(url, buf); + } } return JB_ERR_OK; @@ -726,15 +815,15 @@ static jb_err compile_url_pattern(struct url_spec *url, char *buf) } -#ifdef FEATURE_EXTENDED_HOST_PATTERNS +#ifdef FEATURE_PCRE_HOST_PATTERNS /********************************************************************* * - * Function : compile_host_pattern + * Function : compile_pcre_host_pattern * - * Description : Parses and compiles a host pattern. + * Description : Parses and compiles a pcre host pattern. * * Parameters : - * 1 : url = Target url_spec to be filled in. + * 1 : url = Target pattern_spec to be filled in. * 2 : host_pattern = Host pattern to compile. * * Returns : JB_ERR_OK - Success @@ -742,28 +831,28 @@ static jb_err compile_url_pattern(struct url_spec *url, char *buf) * JB_ERR_PARSE - Cannot parse regex * *********************************************************************/ -static jb_err compile_host_pattern(struct url_spec *url, const char *host_pattern) +static jb_err compile_pcre_host_pattern(struct pattern_spec *url, const char *host_pattern) { - return compile_pattern(host_pattern, RIGHT_ANCHORED_HOST, url, &url->host_regex); + return compile_pattern(host_pattern, RIGHT_ANCHORED_HOST, url, &url->pattern.url_spec.host_regex); } +#endif /* def FEATURE_PCRE_HOST_PATTERNS */ -#else /********************************************************************* * - * Function : compile_host_pattern + * Function : compile_vanilla_host_pattern * * Description : Parses and "compiles" an old-school host pattern. * * Parameters : - * 1 : url = Target url_spec to be filled in. + * 1 : url = Target pattern_spec to be filled in. * 2 : host_pattern = Host pattern to parse. * * Returns : JB_ERR_OK - Success * JB_ERR_PARSE - Cannot parse regex * *********************************************************************/ -static jb_err compile_host_pattern(struct url_spec *url, const char *host_pattern) +static jb_err compile_vanilla_host_pattern(struct pattern_spec *url, const char *host_pattern) { char *v[150]; size_t size; @@ -774,22 +863,22 @@ static jb_err compile_host_pattern(struct url_spec *url, const char *host_patter */ if (host_pattern[strlen(host_pattern) - 1] == '.') { - url->unanchored |= ANCHOR_RIGHT; + url->pattern.url_spec.unanchored |= ANCHOR_RIGHT; } if (host_pattern[0] == '.') { - url->unanchored |= ANCHOR_LEFT; + url->pattern.url_spec.unanchored |= ANCHOR_LEFT; } /* * Split domain into components */ - url->dbuffer = strdup_or_die(host_pattern); + url->pattern.url_spec.dbuffer = strdup_or_die(host_pattern); /* * Map to lower case */ - for (p = url->dbuffer; *p ; p++) + for (p = url->pattern.url_spec.dbuffer; *p ; p++) { *p = (char)privoxy_tolower(*p); } @@ -797,23 +886,23 @@ static jb_err compile_host_pattern(struct url_spec *url, const char *host_patter /* * Split the domain name into components */ - url->dcount = ssplit(url->dbuffer, ".", v, SZ(v)); + url->pattern.url_spec.dcount = ssplit(url->pattern.url_spec.dbuffer, ".", v, SZ(v)); - if (url->dcount < 0) + if (url->pattern.url_spec.dcount < 0) { - free_url_spec(url); - return JB_ERR_MEMORY; + free_pattern_spec(url); + return JB_ERR_PARSE; } - else if (url->dcount != 0) + else if (url->pattern.url_spec.dcount != 0) { /* * Save a copy of the pointers in dvec */ - size = (size_t)url->dcount * sizeof(*url->dvec); + size = (size_t)url->pattern.url_spec.dcount * sizeof(*url->pattern.url_spec.dvec); - url->dvec = malloc_or_die(size); + url->pattern.url_spec.dvec = malloc_or_die(size); - memcpy(url->dvec, v, size); + memcpy(url->pattern.url_spec.dvec, v, size); } /* * else dcount == 0 in which case we needn't do anything, @@ -1003,25 +1092,25 @@ static int simple_domaincmp(char **pv, char **fv, int len) * Function : domain_match * * Description : Domain-wise Compare fqdn's. Governed by the bimap in - * pattern->unachored, the comparison is un-, left-, + * p.pattern->unachored, the comparison is un-, left-, * right-anchored, or both. * The individual domain names are compared with * simplematch(). * * Parameters : - * 1 : pattern = a domain that may contain a '*' as a wildcard. + * 1 : p = a domain that may contain a '*' as a wildcard. * 2 : fqdn = domain name against which the patterns are compared. * * Returns : 0 => domains are equivalent, else no match. * *********************************************************************/ -static int domain_match(const struct url_spec *pattern, const struct http_request *fqdn) +static int domain_match(const struct pattern_spec *p, const struct http_request *fqdn) { char **pv, **fv; /* vectors */ int plen, flen; - int unanchored = pattern->unanchored & (ANCHOR_RIGHT | ANCHOR_LEFT); + int unanchored = p->pattern.url_spec.unanchored & (ANCHOR_RIGHT | ANCHOR_LEFT); - plen = pattern->dcount; + plen = p->pattern.url_spec.dcount; flen = fqdn->dcount; if (flen < plen) @@ -1030,7 +1119,7 @@ static int domain_match(const struct url_spec *pattern, const struct http_reques return 1; } - pv = pattern->dvec; + pv = p->pattern.url_spec.dvec; fv = fqdn->dvec; if (unanchored == ANCHOR_LEFT) @@ -1079,23 +1168,22 @@ static int domain_match(const struct url_spec *pattern, const struct http_reques } } -#endif /* def FEATURE_EXTENDED_HOST_PATTERNS */ /********************************************************************* * - * Function : create_url_spec + * Function : create_pattern_spec * - * Description : Creates a "url_spec" structure from a string. - * When finished, free with free_url_spec(). + * Description : Creates a "pattern_spec" structure from a string. + * When finished, free with free_pattern_spec(). * * Parameters : - * 1 : url = Target url_spec to be filled in. Will be - * zeroed before use. + * 1 : pattern = Target pattern_spec to be filled in. + * Will be zeroed before use. * 2 : buf = Source pattern, null terminated. NOTE: The * contents of this buffer are destroyed by this * function. If this function succeeds, the - * buffer is copied to url->spec. If this + * buffer is copied to pattern->spec. If this * function fails, the contents of the buffer * are lost forever. * @@ -1104,68 +1192,97 @@ static int domain_match(const struct url_spec *pattern, const struct http_reques * written to system log) * *********************************************************************/ -jb_err create_url_spec(struct url_spec *url, char *buf) +jb_err create_pattern_spec(struct pattern_spec *pattern, char *buf) { - assert(url); + static const struct + { + /** The tag pattern prefix to match */ + const char *prefix; + + /** The length of the prefix to match */ + const size_t prefix_length; + + /** The pattern flag */ + const unsigned flag; + } tag_pattern[] = { + { "TAG:", 4, PATTERN_SPEC_TAG_PATTERN}, + #ifdef FEATURE_CLIENT_TAGS + { "CLIENT-TAG:", 11, PATTERN_SPEC_CLIENT_TAG_PATTERN}, + #endif + { "NO-REQUEST-TAG:", 15, PATTERN_SPEC_NO_REQUEST_TAG_PATTERN}, + { "NO-RESPONSE-TAG:", 16, PATTERN_SPEC_NO_RESPONSE_TAG_PATTERN} + }; + int i; + + assert(pattern); assert(buf); - memset(url, '\0', sizeof(*url)); + memset(pattern, '\0', sizeof(*pattern)); /* Remember the original specification for the CGI pages. */ - url->spec = strdup_or_die(buf); + pattern->spec = strdup_or_die(buf); - /* Is it a tag pattern? */ - if (0 == strncmpic(url->spec, "TAG:", 4)) + /* Check if it's a tag pattern */ + for (i = 0; i < SZ(tag_pattern); i++) { - /* The pattern starts with the first character after "TAG:" */ - const char *tag_pattern = buf + 4; - return compile_pattern(tag_pattern, NO_ANCHORING, url, &url->tag_regex); + if (0 == strncmpic(pattern->spec, tag_pattern[i].prefix, tag_pattern[i].prefix_length)) + { + /* The regex starts after the prefix */ + const char *tag_regex = buf + tag_pattern[i].prefix_length; + + pattern->flags |= tag_pattern[i].flag; + + return compile_pattern(tag_regex, NO_ANCHORING, pattern, + &pattern->pattern.tag_regex); + } } /* If it isn't a tag pattern it must be an URL pattern. */ - return compile_url_pattern(url, buf); + pattern->flags |= PATTERN_SPEC_URL_PATTERN; + + return compile_url_pattern(pattern, buf); + } /********************************************************************* * - * Function : free_url_spec + * Function : free_pattern_spec * - * Description : Called from the "unloaders". Freez the url + * Description : Called from the "unloaders". Freez the pattern * structure elements. * * Parameters : - * 1 : url = pointer to a url_spec structure. + * 1 : pattern = pointer to a pattern_spec structure. * * Returns : N/A * *********************************************************************/ -void free_url_spec(struct url_spec *url) +void free_pattern_spec(struct pattern_spec *pattern) { - if (url == NULL) return; + if (pattern == NULL) return; - freez(url->spec); -#ifdef FEATURE_EXTENDED_HOST_PATTERNS - if (url->host_regex) + freez(pattern->spec); +#ifdef FEATURE_PCRE_HOST_PATTERNS + if (pattern->pattern.url_spec.host_regex) { - regfree(url->host_regex); - freez(url->host_regex); + regfree(pattern->pattern.url_spec.host_regex); + freez(pattern->pattern.url_spec.host_regex); } -#else - freez(url->dbuffer); - freez(url->dvec); - url->dcount = 0; -#endif /* ndef FEATURE_EXTENDED_HOST_PATTERNS */ - freez(url->port_list); - if (url->preg) +#endif /* def FEATURE_PCRE_HOST_PATTERNS */ + freez(pattern->pattern.url_spec.dbuffer); + freez(pattern->pattern.url_spec.dvec); + pattern->pattern.url_spec.dcount = 0; + freez(pattern->pattern.url_spec.port_list); + if (pattern->pattern.url_spec.preg) { - regfree(url->preg); - freez(url->preg); + regfree(pattern->pattern.url_spec.preg); + freez(pattern->pattern.url_spec.preg); } - if (url->tag_regex) + if (pattern->pattern.tag_regex) { - regfree(url->tag_regex); - freez(url->tag_regex); + regfree(pattern->pattern.tag_regex); + freez(pattern->pattern.tag_regex); } } @@ -1203,14 +1320,18 @@ static int port_matches(const int port, const char *port_list) * *********************************************************************/ static int host_matches(const struct http_request *http, - const struct url_spec *pattern) + const struct pattern_spec *pattern) { -#ifdef FEATURE_EXTENDED_HOST_PATTERNS - return ((NULL == pattern->host_regex) - || (0 == regexec(pattern->host_regex, http->host, 0, NULL, 0))); -#else - return ((NULL == pattern->dbuffer) || (0 == domain_match(pattern, http))); + assert(http->host != NULL); +#ifdef FEATURE_PCRE_HOST_PATTERNS + if (pattern->pattern.url_spec.host_regex_type == PCRE_HOST_PATTERN) + { + return ((NULL == pattern->pattern.url_spec.host_regex) + || (0 == regexec(pattern->pattern.url_spec.host_regex, + http->host, 0, NULL, 0))); + } #endif + return ((NULL == pattern->pattern.url_spec.dbuffer) || (0 == domain_match(pattern, http))); } @@ -1227,10 +1348,10 @@ static int host_matches(const struct http_request *http, * Returns : TRUE for yes, FALSE otherwise. * *********************************************************************/ -static int path_matches(const char *path, const struct url_spec *pattern) +static int path_matches(const char *path, const struct pattern_spec *pattern) { - return ((NULL == pattern->preg) - || (0 == regexec(pattern->preg, path, 0, NULL, 0))); + return ((NULL == pattern->pattern.url_spec.preg) + || (0 == regexec(pattern->pattern.url_spec.preg, path, 0, NULL, 0))); } @@ -1247,16 +1368,16 @@ static int path_matches(const char *path, const struct url_spec *pattern) * Returns : Nonzero if the URL matches the pattern, else 0. * *********************************************************************/ -int url_match(const struct url_spec *pattern, +int url_match(const struct pattern_spec *pattern, const struct http_request *http) { - if (pattern->tag_regex != NULL) + if (!(pattern->flags & PATTERN_SPEC_URL_PATTERN)) { - /* It's a tag pattern and shouldn't be matched against URLs */ + /* It's not an URL pattern and thus shouldn't be matched against URLs */ return 0; } - return (port_matches(http->port, pattern->port_list) + return (port_matches(http->port, pattern->pattern.url_spec.port_list) && host_matches(http, pattern) && path_matches(http->path, pattern)); } @@ -1346,31 +1467,53 @@ int match_portlist(const char *portlist, int port) * * Function : parse_forwarder_address * - * Description : Parse out the host and port from a forwarder address. + * Description : Parse out the username, password, host and port from + * a forwarder address. * * Parameters : * 1 : address = The forwarder address to parse. * 2 : hostname = Used to return the hostname. NULL on error. * 3 : port = Used to return the port. Untouched if no port * is specified. + * 4 : username = Used to return the username if any. + * 5 : password = Used to return the password if any. * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out of memory * JB_ERR_PARSE on malformed address. * *********************************************************************/ -jb_err parse_forwarder_address(char *address, char **hostname, int *port) +jb_err parse_forwarder_address(char *address, char **hostname, int *port, + char **username, char **password) { - char *p = address; + char *p; + char *tmp; + + tmp = *hostname = strdup_or_die(address); - if ((*address == '[') && (NULL == strchr(address, ']'))) + /* Parse username and password */ + if (username && password && (NULL != (p = strchr(*hostname, '@')))) + { + *p++ = '\0'; + *username = strdup_or_die(*hostname); + *hostname = strdup_or_die(p); + + if (NULL != (p = strchr(*username, ':'))) + { + *p++ = '\0'; + *password = strdup_or_die(p); + } + freez(tmp); + } + + /* Parse hostname and port */ + p = *hostname; + if ((*p == '[') && (NULL == strchr(p, ']'))) { /* XXX: Should do some more validity checks here. */ return JB_ERR_PARSE; } - *hostname = strdup_or_die(address); - if ((**hostname == '[') && (NULL != (p = strchr(*hostname, ']')))) { *p++ = '\0';