Fixed a memory leak when specifying a proxy with a file: URL and added

test case 288 to verify it.
This commit is contained in:
Dan Fandrich 2007-03-24 02:15:20 +00:00
parent b7131009fb
commit 0dd1219668
4 changed files with 114 additions and 61 deletions

View File

@ -16,6 +16,8 @@ Dan F (23 March 2007)
- Added test harness infrastructure to support scp/sftp tests, using - Added test harness infrastructure to support scp/sftp tests, using
OpenSSH as the server. OpenSSH as the server.
- Fixed a memory leak when specifying a proxy with a file: URL.
Yang Tse (20 March 2007) Yang Tse (20 March 2007)
- Fixed: When a signal was caught awaiting for an event using Curl_select() - Fixed: When a signal was caught awaiting for an event using Curl_select()
or Curl_poll() with a non-zero timeout both functions would restart the or Curl_poll() with a non-zero timeout both functions would restart the

129
lib/url.c
View File

@ -2767,8 +2767,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
char passwd[MAX_CURL_PASSWORD_LENGTH]; char passwd[MAX_CURL_PASSWORD_LENGTH];
int rc; int rc;
bool reuse; bool reuse;
char *proxy; char *proxy = NULL;
bool proxy_alloc = FALSE;
#ifndef USE_ARES #ifndef USE_ARES
#ifdef SIGALRM #ifdef SIGALRM
@ -2821,7 +2820,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
conn->bits.proxy = (bool)(data->set.proxy && *data->set.proxy); conn->bits.proxy = (bool)(data->set.proxy && *data->set.proxy);
conn->bits.httpproxy = (bool)(conn->bits.proxy conn->bits.httpproxy = (bool)(conn->bits.proxy
&& (conn->proxytype == CURLPROXY_HTTP)); && (conn->proxytype == CURLPROXY_HTTP));
proxy = data->set.proxy; /* if global proxy is set, this is it */
/* Default protocol-independent behavior doesn't support persistent /* Default protocol-independent behavior doesn't support persistent
connections, so we set this to force-close. Protocols that support connections, so we set this to force-close. Protocols that support
@ -2917,6 +2916,15 @@ static CURLcode CreateConnection(struct SessionHandle *data,
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
if (data->set.proxy) {
proxy = strdup(data->set.proxy); /* if global proxy is set, this is it */
if(NULL == proxy) {
failf(data, "memory shortage");
return CURLE_OUT_OF_MEMORY;
}
}
/* proxy must be freed later unless NULL */
#ifndef CURL_DISABLE_HTTP #ifndef CURL_DISABLE_HTTP
/************************************************************* /*************************************************************
* Detect what (if any) proxy to use. Remember that this selects a host * Detect what (if any) proxy to use. Remember that this selects a host
@ -3018,8 +3026,6 @@ static CURLcode CreateConnection(struct SessionHandle *data,
if(proxy && *proxy) { if(proxy && *proxy) {
long bits = conn->protocol & (PROT_HTTPS|PROT_SSL|PROT_MISSING); long bits = conn->protocol & (PROT_HTTPS|PROT_SSL|PROT_MISSING);
proxy_alloc=TRUE; /* this needs to be freed later */
if(conn->proxytype == CURLPROXY_HTTP) { if(conn->proxytype == CURLPROXY_HTTP) {
/* force this connection's protocol to become HTTP */ /* force this connection's protocol to become HTTP */
conn->protocol = PROT_HTTP | bits; conn->protocol = PROT_HTTP | bits;
@ -3044,35 +3050,16 @@ static CURLcode CreateConnection(struct SessionHandle *data,
reurl = aprintf("%s://%s", conn->protostr, data->change.url); reurl = aprintf("%s://%s", conn->protostr, data->change.url);
if(!reurl) if(!reurl) {
Curl_safefree(proxy);
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
}
data->change.url = reurl; data->change.url = reurl;
data->change.url_alloc = TRUE; /* free this later */ data->change.url_alloc = TRUE; /* free this later */
conn->protocol &= ~PROT_MISSING; /* switch that one off again */ conn->protocol &= ~PROT_MISSING; /* switch that one off again */
} }
#ifndef CURL_DISABLE_HTTP
/************************************************************
* RESUME on a HTTP page is a tricky business. First, let's just check that
* 'range' isn't used, then set the range parameter and leave the resume as
* it is to inform about this situation for later use. We will then
* "attempt" to resume, and if we're talking to a HTTP/1.1 (or later)
* server, we will get the document resumed. If we talk to a HTTP/1.0
* server, we just fail since we can't rewind the file writing from within
* this function.
***********************************************************/
if(data->reqdata.resume_from) {
if(!data->reqdata.use_range) {
/* if it already was in use, we just skip this */
data->reqdata.range = aprintf("%" FORMAT_OFF_T "-", data->reqdata.resume_from);
if(!data->reqdata.range)
return CURLE_OUT_OF_MEMORY;
data->reqdata.rangestringalloc = TRUE; /* mark as allocated */
data->reqdata.use_range = 1; /* switch on range usage */
}
}
#endif
/************************************************************* /*************************************************************
* Setup internals depending on protocol * Setup internals depending on protocol
*************************************************************/ *************************************************************/
@ -3206,6 +3193,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
#else #else
failf(data, LIBCURL_NAME failf(data, LIBCURL_NAME
" was built with TELNET disabled!"); " was built with TELNET disabled!");
return CURLE_UNSUPPORTED_PROTOCOL;
#endif #endif
} }
else if (strequal(conn->protostr, "DICT")) { else if (strequal(conn->protostr, "DICT")) {
@ -3219,6 +3207,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
#else #else
failf(data, LIBCURL_NAME failf(data, LIBCURL_NAME
" was built with DICT disabled!"); " was built with DICT disabled!");
return CURLE_UNSUPPORTED_PROTOCOL;
#endif #endif
} }
else if (strequal(conn->protostr, "LDAP")) { else if (strequal(conn->protostr, "LDAP")) {
@ -3232,6 +3221,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
#else #else
failf(data, LIBCURL_NAME failf(data, LIBCURL_NAME
" was built with LDAP disabled!"); " was built with LDAP disabled!");
return CURLE_UNSUPPORTED_PROTOCOL;
#endif #endif
} }
else if (strequal(conn->protostr, "FILE")) { else if (strequal(conn->protostr, "FILE")) {
@ -3240,25 +3230,10 @@ static CURLcode CreateConnection(struct SessionHandle *data,
conn->curl_do = Curl_file; conn->curl_do = Curl_file;
conn->curl_done = Curl_file_done; conn->curl_done = Curl_file_done;
/* anyway, this is supposed to be the connect function so we better
at least check that the file is present here! */
result = Curl_file_connect(conn);
/* Setup a "faked" transfer that'll do nothing */
if(CURLE_OK == result) {
conn->data = data;
conn->bits.tcpconnect = TRUE; /* we are "connected */
ConnectionStore(data, conn);
result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
-1, NULL); /* no upload */
}
return result;
#else #else
failf(data, LIBCURL_NAME failf(data, LIBCURL_NAME
" was built with FILE disabled!"); " was built with FILE disabled!");
return CURLE_UNSUPPORTED_PROTOCOL;
#endif #endif
} }
else if (strequal(conn->protostr, "TFTP")) { else if (strequal(conn->protostr, "TFTP")) {
@ -3297,6 +3272,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
#else #else
failf(data, LIBCURL_NAME failf(data, LIBCURL_NAME
" was built with TFTP disabled!"); " was built with TFTP disabled!");
return CURLE_UNSUPPORTED_PROTOCOL;
#endif #endif
} }
else if (strequal(conn->protostr, "SCP")) { else if (strequal(conn->protostr, "SCP")) {
@ -3344,21 +3320,11 @@ else {
char *prox_portno; char *prox_portno;
char *endofprot; char *endofprot;
/* We need to make a duplicate of the proxy so that we can modify the
string safely. If 'proxy_alloc' is TRUE, the string is already
allocated and we can treat it as duplicated. */
char *proxydup=proxy_alloc?proxy:strdup(proxy);
/* We use 'proxyptr' to point to the proxy name from now on... */ /* We use 'proxyptr' to point to the proxy name from now on... */
char *proxyptr=proxydup; char *proxyptr=proxy;
char *portptr; char *portptr;
char *atsign; char *atsign;
if(NULL == proxydup) {
failf(data, "memory shortage");
return CURLE_OUT_OF_MEMORY;
}
/* We do the proxy host string parsing here. We want the host name and the /* We do the proxy host string parsing here. We want the host name and the
* port name. Accept a protocol:// prefix, even though it should just be * port name. Accept a protocol:// prefix, even though it should just be
* ignored. * ignored.
@ -3404,15 +3370,15 @@ else {
atsign = strdup(atsign+1); /* the right side of the @-letter */ atsign = strdup(atsign+1); /* the right side of the @-letter */
if(atsign) { if(atsign) {
free(proxydup); /* free the former proxy string */ free(proxy); /* free the former proxy string */
proxydup = proxyptr = atsign; /* now use this instead */ proxy = proxyptr = atsign; /* now use this instead */
} }
else else
res = CURLE_OUT_OF_MEMORY; res = CURLE_OUT_OF_MEMORY;
} }
if(res) { if(res) {
free(proxydup); /* free the allocated proxy string */ free(proxy); /* free the allocated proxy string */
return res; return res;
} }
} }
@ -3455,12 +3421,33 @@ else {
conn->proxy.rawalloc = strdup(proxyptr); conn->proxy.rawalloc = strdup(proxyptr);
conn->proxy.name = conn->proxy.rawalloc; conn->proxy.name = conn->proxy.rawalloc;
free(proxydup); /* free the duplicate pointer and not the modified */ free(proxy);
proxy = NULL; /* this may have just been freed */ proxy = NULL;
if(!conn->proxy.rawalloc) if(!conn->proxy.rawalloc)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
/***********************************************************************
* file: is a special case in that it doesn't need a network connection
***********************************************************************/
if (strequal(conn->protostr, "FILE")) {
/* anyway, this is supposed to be the connect function so we better
at least check that the file is present here! */
result = Curl_file_connect(conn);
/* Setup a "faked" transfer that'll do nothing */
if(CURLE_OK == result) {
conn->data = data;
conn->bits.tcpconnect = TRUE; /* we are "connected */
ConnectionStore(data, conn);
result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
-1, NULL); /* no upload */
}
return result;
}
/************************************************************* /*************************************************************
* If the protocol is using SSL and HTTP proxy is used, we set * If the protocol is using SSL and HTTP proxy is used, we set
* the tunnel_proxy bit. * the tunnel_proxy bit.
@ -3678,6 +3665,28 @@ else {
if(!conn->user || !conn->passwd) if(!conn->user || !conn->passwd)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
#ifndef CURL_DISABLE_HTTP
/************************************************************
* RESUME on a HTTP page is a tricky business. First, let's just check that
* 'range' isn't used, then set the range parameter and leave the resume as
* it is to inform about this situation for later use. We will then
* "attempt" to resume, and if we're talking to a HTTP/1.1 (or later)
* server, we will get the document resumed. If we talk to a HTTP/1.0
* server, we just fail since we can't rewind the file writing from within
* this function.
***********************************************************/
if(data->reqdata.resume_from) {
if(!data->reqdata.use_range) {
/* if it already was in use, we just skip this */
data->reqdata.range = aprintf("%" FORMAT_OFF_T "-", data->reqdata.resume_from);
if(!data->reqdata.range)
return CURLE_OUT_OF_MEMORY;
data->reqdata.rangestringalloc = TRUE; /* mark as allocated */
data->reqdata.use_range = 1; /* switch on range usage */
}
}
#endif
/************************************************************* /*************************************************************
* Check the current list of connections to see if we can * Check the current list of connections to see if we can
* re-use an already existing one or if we have to create a * re-use an already existing one or if we have to create a
@ -3797,7 +3806,7 @@ else {
infof(data, "Re-using existing connection! (#%ld) with host %s\n", infof(data, "Re-using existing connection! (#%ld) with host %s\n",
conn->connectindex, conn->connectindex,
proxy?conn->proxy.dispname:conn->host.dispname); conn->proxy.name?conn->proxy.dispname:conn->host.dispname);
} }
else { else {
/* /*

View File

@ -37,4 +37,4 @@ EXTRA_DIST = test1 test108 test117 test127 test20 test27 test34 test46 \
test274 test275 test524 test525 test276 test277 test526 test527 test528 \ test274 test275 test524 test525 test276 test277 test526 test527 test528 \
test530 DISABLED test278 test279 test531 test280 test529 test532 test533 \ test530 DISABLED test278 test279 test531 test280 test529 test532 test533 \
test534 test535 test281 test537 test282 test283 test284 test538 test285 \ test534 test535 test281 test537 test282 test283 test284 test538 test285 \
test286 test307 test308 test287 test400 test286 test307 test308 test287 test400 test288

42
tests/data/test288 Normal file
View File

@ -0,0 +1,42 @@
<testcase>
# Server-side
<reply>
<data>
foo
bar
bar
foo
moo
</data>
</reply>
# Client-side
<client>
<server>
none
</server>
<features>
file
</features>
<name>
file:// with (unsupported) proxy, authentication and range
</name>
<setenv>
all_proxy=http://fake:user@%HOSTIP:%HTTPPORT/
</setenv>
<command>
file://localhost/%PWD/log/test288.txt
</command>
<file name="log/test288.txt">
foo
bar
bar
foo
moo
</file>
</client>
# Verify data after the test has been "shot"
<verify>
</verify>
</testcase>