--- ../curl-7.19.2/include/curl/curl.h 2008-10-17 01:58:26.000000000 -0400 +++ Win32/curl-7.19.2/build/include/curl/curl.h 2009-01-08 11:39:27.000000000 -0500 @@ -1149,6 +1149,14 @@ CINIT(PROXYUSERNAME, OBJECTPOINT, 175), CINIT(PROXYPASSWORD, OBJECTPOINT, 176), + /* Comma separated list of hostnames defining no-proxy zones. These should + match both hostnames directly, and hostnames within a domain. For example, + local.com will match local.com and www.local.com, but NOT notlocal.com or + www.notlocal.com. For compatibility with other implementations of this, + .local.com will be considered to be the same as local.com. A single * is + the only valid wildcard, and effectively disables the use of proxy. */ + CINIT(NOPROXY, OBJECTPOINT, 177), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; --- ../curl-7.19.2/include/curl/typecheck-gcc.h 2008-10-17 01:58:26.000000000 -0400 +++ Win32/curl-7.19.2/build/include/curl/typecheck-gcc.h 2009-01-05 17:12:38.000000000 -0500 @@ -201,6 +201,7 @@ (option) == CURLOPT_PROXYUSERPWD || \ (option) == CURLOPT_PROXYUSERNAME || \ (option) == CURLOPT_PROXYPASSWORD || \ + (option) == CURLOPT_NOPROXY || \ (option) == CURLOPT_ENCODING || \ (option) == CURLOPT_REFERER || \ (option) == CURLOPT_USERAGENT || \ --- ../curl-7.19.2/lib/url.c 2008-11-11 08:20:02.000000000 -0500 +++ Win32/curl-7.19.2/build/lib/url.c 2009-01-08 11:50:42.000000000 -0500 @@ -1629,6 +1629,13 @@ result = setstropt(&data->set.str[STRING_PROXYPASSWORD], va_arg(param, char *)); break; + case CURLOPT_NOPROXY: + /* + * proxy exception list + */ + result = setstropt(&data->set.str[STRING_NOPROXY], + va_arg(param, char *)); + break; #endif case CURLOPT_RANGE: @@ -3298,6 +3305,66 @@ #ifndef CURL_DISABLE_PROXY /**************************************************************** +* Checks if the host is in the noproxy list. returns true if it matches +* and therefore the proxy should NOT be used. +****************************************************************/ +static bool check_noproxy(const char* name, const char* no_proxy) +{ + /* no_proxy=domain1.dom,host.domain2.dom + * (a comma-separated list of hosts which should + * not be proxied, or an asterisk to override + * all proxy variables) + */ + char *tmp_no_proxy = NULL; + + if(no_proxy && no_proxy[0]) { + if(Curl_raw_equal("*", no_proxy)) { + return TRUE; + } + /* NO_PROXY was specified and it wasn't just an asterisk */ + tmp_no_proxy = strdup(no_proxy); + } + if (tmp_no_proxy) { + char *nope; + char *no_proxy_tok_buf; + + nope=strtok_r(tmp_no_proxy, ", ", &no_proxy_tok_buf); + while(nope) { + size_t namelen; + char *endptr = strchr(name, ':'); + if(endptr) + namelen=endptr-name; + else + namelen=strlen(name); + + /* To match previous behaviour, where it was necessary to specify + * .local.com to prevent matching notlocal.com, we will leave the . off + */ + if (nope[0] == '.') + ++nope; + if(strlen(nope) <= namelen) { + const char *checkn= + name + namelen - strlen(nope); + if(checkprefix(nope, checkn)) { + if(strlen(nope) == namelen || *(checkn - 1) == '.') { + /* We either have an exact match, or the previous character is a . + * so it is within the same domain, so no proxy for this host. + */ + break; + } + } + } + nope=strtok_r(NULL, ", ", &no_proxy_tok_buf); + } + free(tmp_no_proxy); + if (nope) + return TRUE; + } /* NO_PROXY was specified and it wasn't just an asterisk, or strdup failed */ + + return FALSE; +} + +/**************************************************************** * Detect what (if any) proxy to use. Remember that this selects a host * name and is not limited to HTTP proxies only. * The returned pointer must be freed by the caller (unless NULL) @@ -3325,91 +3392,56 @@ * checked if the lowercase versions don't exist. */ char *no_proxy=NULL; - char *no_proxy_tok_buf; char proxy_env[128]; no_proxy=curl_getenv("no_proxy"); if(!no_proxy) no_proxy=curl_getenv("NO_PROXY"); - if(!no_proxy || !Curl_raw_equal("*", no_proxy)) { - /* NO_PROXY wasn't specified or it wasn't just an asterisk */ - char *nope; - - nope=no_proxy?strtok_r(no_proxy, ", ", &no_proxy_tok_buf):NULL; - while(nope) { - size_t namelen; - char *endptr = strchr(conn->host.name, ':'); - if(endptr) - namelen=endptr-conn->host.name; - else - namelen=strlen(conn->host.name); - - if(strlen(nope) <= namelen) { - char *checkn= - conn->host.name + namelen - strlen(nope); - if(checkprefix(nope, checkn)) { - /* no proxy for this host! */ - break; - } - } - nope=strtok_r(NULL, ", ", &no_proxy_tok_buf); - } - if(!nope) { - /* It was not listed as without proxy */ - char *protop = conn->protostr; - char *envp = proxy_env; - char *prox; - - /* Now, build _proxy and check for such a one to use */ - while(*protop) - *envp++ = (char)tolower((int)*protop++); - - /* append _proxy */ - strcpy(envp, "_proxy"); - - /* read the protocol proxy: */ + if (!check_noproxy(conn->host.name, no_proxy)) { + /* It was not listed as without proxy */ + char *protop = conn->protostr; + char *envp = proxy_env; + char *prox; + + /* Now, build _proxy and check for such a one to use */ + while(*protop) + *envp++ = (char)tolower((int)*protop++); + + /* append _proxy */ + strcpy(envp, "_proxy"); + + /* read the protocol proxy: */ + prox=curl_getenv(proxy_env); + + /* + * We don't try the uppercase version of HTTP_PROXY because of + * security reasons: + * + * When curl is used in a webserver application + * environment (cgi or php), this environment variable can + * be controlled by the web server user by setting the + * http header 'Proxy:' to some value. + * + * This can cause 'internal' http/ftp requests to be + * arbitrarily redirected by any external attacker. + */ + if(!prox && !Curl_raw_equal("http_proxy", proxy_env)) { + /* There was no lowercase variable, try the uppercase version: */ + for(envp = proxy_env; *envp; envp++) + *envp = (char)toupper((int)*envp); prox=curl_getenv(proxy_env); + } - /* - * We don't try the uppercase version of HTTP_PROXY because of - * security reasons: - * - * When curl is used in a webserver application - * environment (cgi or php), this environment variable can - * be controlled by the web server user by setting the - * http header 'Proxy:' to some value. - * - * This can cause 'internal' http/ftp requests to be - * arbitrarily redirected by any external attacker. - */ - if(!prox && !Curl_raw_equal("http_proxy", proxy_env)) { - /* There was no lowercase variable, try the uppercase version: */ - for(envp = proxy_env; *envp; envp++) - *envp = (char)toupper((int)*envp); - prox=curl_getenv(proxy_env); - } - - if(prox && *prox) { /* don't count "" strings */ - proxy = prox; /* use this */ - } - else { - proxy = curl_getenv("all_proxy"); /* default proxy to use */ - if(!proxy) - proxy=curl_getenv("ALL_PROXY"); - } - - if(proxy && *proxy) { - long bits = conn->protocol & (PROT_HTTPS|PROT_SSL|PROT_MISSING); - - if(conn->proxytype == CURLPROXY_HTTP) { - /* force this connection's protocol to become HTTP */ - conn->protocol = PROT_HTTP | bits; - conn->bits.proxy = conn->bits.httpproxy = TRUE; - } - } - } /* if(!nope) - it wasn't specified non-proxy */ - } /* NO_PROXY wasn't specified or '*' */ + if(prox && *prox) { /* don't count "" strings */ + proxy = prox; /* use this */ + } + else { + proxy = curl_getenv("all_proxy"); /* default proxy to use */ + if(!proxy) + proxy=curl_getenv("ALL_PROXY"); + } + } /* if (!check_noproxy(conn->host.name, no_proxy)) - it wasn't specified non-proxy */ if(no_proxy) free(no_proxy); @@ -4043,15 +4075,26 @@ and the SessionHandle */ conn->proxytype = data->set.proxytype; /* type */ + +#ifdef CURL_DISABLE_PROXY + + conn->bits.proxy = FALSE; + conn->bits.httpproxy = FALSE; + conn->bits.proxy_user_passwd = FALSE; + conn->bits.tunnel_proxy = FALSE; + +#else /* CURL_DISABLE_PROXY */ + conn->bits.proxy = (bool)(data->set.str[STRING_PROXY] && *data->set.str[STRING_PROXY]); conn->bits.httpproxy = (bool)(conn->bits.proxy && (conn->proxytype == CURLPROXY_HTTP)); + conn->bits.proxy_user_passwd = (bool)(NULL != data->set.str[STRING_PROXYUSERNAME]); + conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy; +#endif /* CURL_DISABLE_PROXY */ conn->bits.user_passwd = (bool)(NULL != data->set.str[STRING_USERNAME]); - conn->bits.proxy_user_passwd = (bool)(NULL != data->set.str[STRING_PROXYUSERNAME]); - conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy; conn->bits.ftp_use_epsv = data->set.ftp_use_epsv; conn->bits.ftp_use_eprt = data->set.ftp_use_eprt; @@ -4131,11 +4174,34 @@ if(!proxy) proxy = detect_proxy(conn); + else if(data->set.str[STRING_NOPROXY]) { + if (check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY])) { + free(proxy); /* proxy is in exception list */ + proxy = NULL; + } + } if(proxy && !*proxy) { free(proxy); /* Don't bother with an empty proxy string */ proxy = NULL; } /* proxy must be freed later unless NULL */ + if(proxy && *proxy) { + long bits = conn->protocol & (PROT_HTTPS|PROT_SSL|PROT_MISSING); + + if(conn->proxytype == CURLPROXY_HTTP) { + /* force this connection's protocol to become HTTP */ + conn->protocol = PROT_HTTP | bits; + conn->bits.httpproxy = TRUE; + } + conn->bits.proxy = TRUE; + } + else { + /* we aren't using the proxy after all... */ + conn->bits.proxy = FALSE; + conn->bits.httpproxy = FALSE; + conn->bits.proxy_user_passwd = FALSE; + conn->bits.tunnel_proxy = FALSE; + } #endif /* CURL_DISABLE_PROXY */ /************************************************************* --- ../curl-7.19.2/lib/urldata.h 2008-11-11 14:19:56.000000000 -0500 +++ Win32/curl-7.19.2/build/lib/urldata.h 2009-01-05 17:12:38.000000000 -0500 @@ -1344,6 +1344,7 @@ STRING_PASSWORD, /* , if used */ STRING_PROXYUSERNAME, /* Proxy , if used */ STRING_PROXYPASSWORD, /* Proxy , if used */ + STRING_NOPROXY, /* List of urls which should not use the proxy, if used */ /* -- end of strings -- */ STRING_LAST /* not used, just an end-of-list marker */