- Craig A West brought CURLOPT_NOPROXY and the corresponding --noproxy option.

They basically offer the same thing the NO_PROXY environment variable only
  offered previously: list a set of host names that shall not use the proxy
  even if one is specified.
This commit is contained in:
Daniel Stenberg 2009-01-25 23:26:25 +00:00
parent ddd3fe5948
commit 5aeef9c1c8
11 changed files with 221 additions and 92 deletions

236
lib/url.c
View file

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -1677,6 +1677,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
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:
@ -3368,6 +3375,80 @@ static CURLcode setup_connection_internals(struct SessionHandle *data,
}
#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)
*/
size_t tok_start;
size_t tok_end;
const char* separator = ", ";
size_t no_proxy_len;
size_t namelen;
char *endptr;
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 */
no_proxy_len = strlen(no_proxy);
endptr = strchr(name, ':');
if(endptr)
namelen = endptr - name;
else
namelen = strlen(name);
tok_start = 0;
for (tok_start = 0; tok_start < no_proxy_len; tok_start = tok_end + 1) {
while (tok_start < no_proxy_len &&
strchr(separator, no_proxy[tok_start]) != NULL) {
/* Look for the beginning of the token. */
++tok_start;
}
if(tok_start == no_proxy_len)
break; /* It was all trailing separator chars, no more tokens. */
for (tok_end = tok_start; tok_end < no_proxy_len &&
strchr(separator, no_proxy[tok_end]) == NULL; ++tok_end) {
/* Look for the end of the token. */
}
/* To match previous behaviour, where it was necessary to specify
* ".local.com" to prevent matching "notlocal.com", we will leave
* the '.' off.
*/
if(no_proxy[tok_start] == '.')
++tok_start;
if((tok_end - tok_start) <= namelen) {
/* Match the last part of the name to the domain we are checking. */
const char *checkn = name + namelen - (tok_end - tok_start);
if(Curl_raw_nequal(no_proxy + tok_start, checkn, tok_end - tok_start)) {
if((tok_end - tok_start) == 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.
*/
return TRUE;
}
}
} /* if((tok_end - tok_start) <= namelen) */
} /* for (tok_start = 0; tok_start < no_proxy_len;
tok_start = tok_end + 1) */
} /* NO_PROXY was specified and it wasn't just an asterisk */
return FALSE;
}
/****************************************************************
* Detect what (if any) proxy to use. Remember that this selects a host
* name and is not limited to HTTP proxies only.
@ -3396,90 +3477,56 @@ static char *detect_proxy(struct connectdata *conn)
* 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;
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;
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);
/* Now, build <protocol>_proxy and check for such a one to use */
while(*protop)
*envp++ = (char)tolower((int)*protop++);
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;
/* append _proxy */
strcpy(envp, "_proxy");
/* Now, build <protocol>_proxy and check for such a one to use */
while(*protop)
*envp++ = (char)tolower((int)*protop++);
/* read the protocol proxy: */
prox=curl_getenv(proxy_env);
/* append _proxy */
strcpy(envp, "_proxy");
/* read the protocol proxy: */
/*
* 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: */
Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env));
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: */
Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env));
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);
@ -3629,7 +3676,8 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data,
char proxypasswd[MAX_CURL_PASSWORD_LENGTH]="";
if(data->set.str[STRING_PROXYUSERNAME] != NULL) {
strncpy(proxyuser, data->set.str[STRING_PROXYUSERNAME], MAX_CURL_USER_LENGTH);
strncpy(proxyuser, data->set.str[STRING_PROXYUSERNAME],
MAX_CURL_USER_LENGTH);
proxyuser[MAX_CURL_USER_LENGTH-1] = '\0'; /*To be on safe side*/
}
if(data->set.str[STRING_PROXYPASSWORD] != NULL) {
@ -4117,15 +4165,26 @@ static CURLcode create_conn(struct SessionHandle *data,
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.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;
#endif /* CURL_DISABLE_PROXY */
conn->bits.user_passwd = (bool)(NULL != data->set.str[STRING_USERNAME]);
conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
@ -4205,11 +4264,34 @@ static CURLcode create_conn(struct SessionHandle *data,
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 */
/*************************************************************

View file

@ -1363,6 +1363,8 @@ enum dupstring {
STRING_PASSWORD, /* <password>, if used */
STRING_PROXYUSERNAME, /* Proxy <username>, if used */
STRING_PROXYPASSWORD, /* Proxy <password>, if used */
STRING_NOPROXY, /* List of hosts which should not use the proxy, if
used */
/* -- end of strings -- */
STRING_LAST /* not used, just an end-of-list marker */