1
0
mirror of https://github.com/moparisthebest/curl synced 2024-12-21 23:58:49 -05:00

global dns cache: didn't work [regression]

CURLOPT_DNS_USE_GLOBAL_CACHE broke in commit c43127414d (been
broken since the libcurl 7.29.0 release). While this option has been
documented as deprecated for almost a decade and nobody even reported
this bug, it should remain functional.

Added test case 1512 to verify
This commit is contained in:
Daniel Stenberg 2013-08-08 13:01:16 +02:00
parent 27f8c93daf
commit d2b36e466a
7 changed files with 224 additions and 40 deletions

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
* *
* This software is licensed as described in the file COPYING, which * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * you should have received as part of this distribution. The terms
@ -681,12 +681,14 @@ clean_up:
* Curl_resolv_unlock() unlocks the given cached DNS entry. When this has been * Curl_resolv_unlock() unlocks the given cached DNS entry. When this has been
* made, the struct may be destroyed due to pruning. It is important that only * made, the struct may be destroyed due to pruning. It is important that only
* one unlock is made for each Curl_resolv() call. * one unlock is made for each Curl_resolv() call.
*
* May be called with 'data' == NULL for global cache.
*/ */
void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns) void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns)
{ {
DEBUGASSERT(dns && (dns->inuse>0)); DEBUGASSERT(dns && (dns->inuse>0));
if(data->share) if(data && data->share)
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
dns->inuse--; dns->inuse--;
@ -697,7 +699,7 @@ void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns)
free(dns); free(dns);
} }
if(data->share) if(data && data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS); Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
} }
@ -734,22 +736,23 @@ static int hostcache_inuse(void *data, void *hc)
return 1; /* free all entries */ return 1; /* free all entries */
} }
void Curl_hostcache_clean(struct SessionHandle *data) /*
* Curl_hostcache_clean()
*
* This _can_ be called with 'data' == NULL but then of course no locking
* can be done!
*/
void Curl_hostcache_clean(struct SessionHandle *data,
struct curl_hash *hash)
{ {
/* Entries added to the hostcache with the CURLOPT_RESOLVE function are /* Entries added to the hostcache with the CURLOPT_RESOLVE function are
* still present in the cache with the inuse counter set to 1. Detect them * still present in the cache with the inuse counter set to 1. Detect them
* and cleanup! * and cleanup!
*/ */
Curl_hash_clean_with_criterium(data->dns.hostcache, data, hostcache_inuse); Curl_hash_clean_with_criterium(hash, data, hostcache_inuse);
} }
void Curl_hostcache_destroy(struct SessionHandle *data)
{
Curl_hostcache_clean(data);
Curl_hash_destroy(data->dns.hostcache);
data->dns.hostcachetype = HCACHE_NONE;
data->dns.hostcache = NULL;
}
CURLcode Curl_loadhostpairs(struct SessionHandle *data) CURLcode Curl_loadhostpairs(struct SessionHandle *data)
{ {

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
* *
* This software is licensed as described in the file COPYING, which * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * you should have received as part of this distribution. The terms
@ -203,7 +203,7 @@ CURLcode Curl_set_dns_servers(struct SessionHandle *data, char *servers);
/* /*
* Clean off entries from the cache * Clean off entries from the cache
*/ */
void Curl_hostcache_clean(struct SessionHandle *data); void Curl_hostcache_clean(struct SessionHandle *data, struct curl_hash *hash);
/* /*
* Destroy the hostcache of this handle. * Destroy the hostcache of this handle.

View File

@ -334,7 +334,6 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
CURL *easy_handle) CURL *easy_handle)
{ {
struct curl_llist *timeoutlist; struct curl_llist *timeoutlist;
struct SessionHandle *easy;
struct Curl_multi *multi = (struct Curl_multi *)multi_handle; struct Curl_multi *multi = (struct Curl_multi *)multi_handle;
struct SessionHandle *data = (struct SessionHandle *)easy_handle; struct SessionHandle *data = (struct SessionHandle *)easy_handle;
struct SessionHandle *new_closure = NULL; struct SessionHandle *new_closure = NULL;
@ -348,8 +347,8 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
if(!GOOD_EASY_HANDLE(easy_handle)) if(!GOOD_EASY_HANDLE(easy_handle))
return CURLM_BAD_EASY_HANDLE; return CURLM_BAD_EASY_HANDLE;
/* Prevent users from adding same easy handle more than /* Prevent users from adding same easy handle more than once and prevent
once and prevent adding to more than one multi stack */ adding to more than one multi stack */
if(data->multi) if(data->multi)
/* possibly we should create a new unique error code for this condition */ /* possibly we should create a new unique error code for this condition */
return CURLM_BAD_EASY_HANDLE; return CURLM_BAD_EASY_HANDLE;
@ -359,13 +358,11 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
if(!timeoutlist) if(!timeoutlist)
return CURLM_OUT_OF_MEMORY; return CURLM_OUT_OF_MEMORY;
easy = data;
/* In case multi handle has no hostcache yet, allocate one */ /* In case multi handle has no hostcache yet, allocate one */
if(!multi->hostcache) { if(!multi->hostcache) {
hostcache = Curl_mk_dnscache(); hostcache = Curl_mk_dnscache();
if(!hostcache) { if(!hostcache) {
free(easy); free(data);
Curl_llist_destroy(timeoutlist, NULL); Curl_llist_destroy(timeoutlist, NULL);
return CURLM_OUT_OF_MEMORY; return CURLM_OUT_OF_MEMORY;
} }
@ -377,7 +374,7 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
new_closure = (struct SessionHandle *)curl_easy_init(); new_closure = (struct SessionHandle *)curl_easy_init();
if(!new_closure) { if(!new_closure) {
Curl_hash_destroy(hostcache); Curl_hash_destroy(hostcache);
free(easy); free(data);
Curl_llist_destroy(timeoutlist, NULL); Curl_llist_destroy(timeoutlist, NULL);
return CURLM_OUT_OF_MEMORY; return CURLM_OUT_OF_MEMORY;
} }
@ -408,18 +405,28 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
timeoutlist = NULL; timeoutlist = NULL;
/* set the easy handle */ /* set the easy handle */
multistate(easy, CURLM_STATE_INIT); multistate(data, CURLM_STATE_INIT);
if((data->set.global_dns_cache) &&
(data->dns.hostcachetype != HCACHE_GLOBAL)) {
/* global dns cache was requested but still isn't */
struct curl_hash *global = Curl_global_host_cache_init();
if(global) {
/* only do this if the global cache init works */
data->dns.hostcache = global;
data->dns.hostcachetype = HCACHE_GLOBAL;
}
}
/* for multi interface connections, we share DNS cache automatically if the /* for multi interface connections, we share DNS cache automatically if the
easy handle's one is currently not set. */ easy handle's one is currently not set. */
if(!easy->dns.hostcache || else if(!data->dns.hostcache ||
(easy->dns.hostcachetype == HCACHE_NONE)) { (data->dns.hostcachetype == HCACHE_NONE)) {
easy->dns.hostcache = multi->hostcache; data->dns.hostcache = multi->hostcache;
easy->dns.hostcachetype = HCACHE_MULTI; data->dns.hostcachetype = HCACHE_MULTI;
} }
/* Point to the multi's connection cache */ /* Point to the multi's connection cache */
easy->state.conn_cache = multi->conn_cache; data->state.conn_cache = multi->conn_cache;
/* This adds the new entry at the 'end' of the doubly-linked circular /* This adds the new entry at the 'end' of the doubly-linked circular
list of SessionHandle structs to try and maintain a FIFO queue so list of SessionHandle structs to try and maintain a FIFO queue so
@ -427,22 +434,22 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
/* We add this new entry last in the list. */ /* We add this new entry last in the list. */
easy->next = NULL; /* end of the line */ data->next = NULL; /* end of the line */
if(multi->easyp) { if(multi->easyp) {
struct SessionHandle *last = multi->easylp; struct SessionHandle *last = multi->easylp;
last->next = easy; last->next = data;
easy->prev = last; data->prev = last;
multi->easylp = easy; /* the new last node */ multi->easylp = data; /* the new last node */
} }
else { else {
/* first node, make both prev and next be NULL! */ /* first node, make both prev and next be NULL! */
easy->next = NULL; data->next = NULL;
easy->prev = NULL; data->prev = NULL;
multi->easylp = multi->easyp = easy; /* both first and last */ multi->easylp = multi->easyp = data; /* both first and last */
} }
/* make the SessionHandle refer back to this multi handle */ /* make the SessionHandle refer back to this multi handle */
Curl_easy_addmulti(easy_handle, multi_handle); Curl_easy_addmulti(data, multi_handle);
/* Set the timeout for this handle to expire really soon so that it will /* Set the timeout for this handle to expire really soon so that it will
be taken care of even when this handle is added in the midst of operation be taken care of even when this handle is added in the midst of operation
@ -450,7 +457,7 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
sockets that time-out or have actions will be dealt with. Since this sockets that time-out or have actions will be dealt with. Since this
handle has no action yet, we make sure it times out to get things to handle has no action yet, we make sure it times out to get things to
happen. */ happen. */
Curl_expire(easy, 1); Curl_expire(data, 1);
/* increase the node-counter */ /* increase the node-counter */
multi->num_easy++; multi->num_easy++;
@ -1811,7 +1818,8 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle)
if(multi->closure_handle) { if(multi->closure_handle) {
multi->closure_handle->dns.hostcache = multi->hostcache; multi->closure_handle->dns.hostcache = multi->hostcache;
Curl_hostcache_clean(multi->closure_handle); Curl_hostcache_clean(multi->closure_handle,
multi->closure_handle->dns.hostcache);
Curl_close(multi->closure_handle); Curl_close(multi->closure_handle);
multi->closure_handle = NULL; multi->closure_handle = NULL;
@ -1833,7 +1841,7 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle)
nexteasy=easy->next; nexteasy=easy->next;
if(easy->dns.hostcachetype == HCACHE_MULTI) { if(easy->dns.hostcachetype == HCACHE_MULTI) {
/* clear out the usage of the shared DNS cache */ /* clear out the usage of the shared DNS cache */
Curl_hostcache_clean(easy); Curl_hostcache_clean(easy, easy->dns.hostcache);
easy->dns.hostcache = NULL; easy->dns.hostcache = NULL;
easy->dns.hostcachetype = HCACHE_NONE; easy->dns.hostcachetype = HCACHE_NONE;
} }

View File

@ -113,7 +113,7 @@ test1400 test1401 test1402 test1403 test1404 test1405 test1406 test1407 \
test1408 test1409 test1410 test1412 test1413 test1414 \ test1408 test1409 test1410 test1412 test1413 test1414 \
\ \
test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \ test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \
test1508 test1509 test1510 test1511 \ test1508 test1509 test1510 test1511 test1512 \
\ \
test1900 test1901 test1902 test1903 \ test1900 test1901 test1902 test1903 \
\ \

80
tests/data/test1512 Normal file
View File

@ -0,0 +1,80 @@
<testcase>
<info>
<keywords>
HTTP
GLOBAL DNS CACHE
</keywords>
</info>
# Server-side
<reply>
<data1>
HTTP/1.1 200 OK
Date: Thu, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Content-Length: 47
file contents should appear once for each file
</data1>
<data2>
HTTP/1.1 200 OK
Date: Thu, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Content-Length: 47
file contents should appear once for each file
</data2>
<data3>
HTTP/1.1 200 OK
Date: Thu, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Content-Length: 47
file contents should appear once for each file
</data3>
<data4>
HTTP/1.1 200 OK
Date: Thu, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Content-Length: 47
file contents should appear once for each file
</data4>
</reply>
# Client-side
<client>
<server>
http
</server>
<tool>
lib1512
</tool>
<name>
GLOBAL CACHE test over two easy performs
</name>
<command>
http://%HOSTIP:%HTTPPORT/path/1512 %HOSTIP %HTTPPORT
</command>
</client>
# Verify data after the test has been "shot"
<verify>
<protocol>
GET /path/15120001 HTTP/1.1
Host: %HOSTIP:%HTTPPORT
Accept: */*
GET /path/15120002 HTTP/1.1
Host: %HOSTIP:%HTTPPORT
Accept: */*
</protocol>
<strip>
^Host:.*
</strip>
<stripfile>
$_ = '' if (($_ !~ /left intact/) && ($_ !~ /Closing connection/))
</stripfile>
</verify>
</testcase>

View File

@ -21,7 +21,7 @@ noinst_PROGRAMS = chkhostname libauthretry libntlmconnect \
lib571 lib572 lib573 lib574 lib575 lib576 lib578 lib579 lib582 \ lib571 lib572 lib573 lib574 lib575 lib576 lib578 lib579 lib582 \
lib583 lib585 lib586 lib587 lib590 lib591 lib597 lib598 lib599 \ lib583 lib585 lib586 lib587 lib590 lib591 lib597 lib598 lib599 \
lib1500 lib1501 lib1502 lib1503 lib1504 lib1505 lib1506 lib1507 lib1508 \ lib1500 lib1501 lib1502 lib1503 lib1504 lib1505 lib1506 lib1507 lib1508 \
lib1509 lib1510 lib1511 \ lib1509 lib1510 lib1511 lib1512 \
lib1900 \ lib1900 \
lib2033 lib2033
@ -339,6 +339,10 @@ lib1511_SOURCES = lib1511.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1511_LDADD = $(TESTUTIL_LIBS) lib1511_LDADD = $(TESTUTIL_LIBS)
lib1511_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1511 lib1511_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1511
lib1512_SOURCES = lib1512.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1512_LDADD = $(TESTUTIL_LIBS)
lib1512_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1512
lib1900_SOURCES = lib1900.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) lib1900_SOURCES = lib1900.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1900_LDADD = $(TESTUTIL_LIBS) lib1900_LDADD = $(TESTUTIL_LIBS)
lib1900_CPPFLAGS = $(AM_CPPFLAGS) lib1900_CPPFLAGS = $(AM_CPPFLAGS)

89
tests/libtest/lib1512.c Normal file
View File

@ -0,0 +1,89 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2013, Linus Nielsen Feltzing <linus@haxx.se>
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
***************************************************************************/
/*
* Use global DNS cache (while deprecated it should still work), populate it
* with CURLOPT_RESOLVE in the first request and then make sure a subsequent
* easy transfer finds and uses the populated stuff.
*/
#include "test.h"
#include "memdebug.h"
#define NUM_HANDLES 2
int test(char *URL)
{
CURLcode res;
CURL *curl[NUM_HANDLES] = {NULL, NULL};
char *port = libtest_arg3;
char *address = libtest_arg2;
char dnsentry[256];
struct curl_slist *slist = NULL;
int i;
char target_url[256];
(void)URL; /* URL is setup in the code */
if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
fprintf(stderr, "curl_global_init() failed\n");
return TEST_ERR_MAJOR_BAD;
}
sprintf(dnsentry, "server.example.curl:%s:%s", port, address);
printf("%s\n", dnsentry);
slist = curl_slist_append(slist, dnsentry);
/* get NUM_HANDLES easy handles */
for(i=0; i < NUM_HANDLES; i++) {
/* get an easy handle */
easy_init(curl[i]);
/* specify target */
sprintf(target_url, "http://server.example.curl:%s/path/1512%04i",
port, i + 1);
target_url[sizeof(target_url) - 1] = '\0';
easy_setopt(curl[i], CURLOPT_URL, target_url);
/* go verbose */
easy_setopt(curl[i], CURLOPT_VERBOSE, 1L);
/* include headers */
easy_setopt(curl[i], CURLOPT_HEADER, 1L);
easy_setopt(curl[i], CURLOPT_DNS_USE_GLOBAL_CACHE, 1L);
}
/* make the first one populate the GLOBAL cache */
easy_setopt(curl[0], CURLOPT_RESOLVE, slist);
/* run NUM_HANDLES transfers */
for(i=0; (i < NUM_HANDLES) && !res; i++)
res = curl_easy_perform(curl[i]);
test_cleanup:
curl_easy_cleanup(curl[0]);
curl_easy_cleanup(curl[1]);
curl_slist_free_all(slist);
curl_global_cleanup();
return (int)res;
}