From f66d97b677d114733f6b938d54ce7502d6aff214 Mon Sep 17 00:00:00 2001 From: "Alibek.Jorajev" Date: Wed, 30 May 2018 15:23:35 +0100 Subject: CURLOPT_RESOLVE: always purge old entry first If there's an existing entry using the selected name. Closes #2622 --- tests/unit/unit1609.c | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 tests/unit/unit1609.c (limited to 'tests/unit/unit1609.c') diff --git a/tests/unit/unit1609.c b/tests/unit/unit1609.c new file mode 100644 index 000000000..2b99bee9b --- /dev/null +++ b/tests/unit/unit1609.c @@ -0,0 +1,214 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. + * + * 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 https://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. + * + ***************************************************************************/ +#include "curlcheck.h" + +#include "urldata.h" +#include "connect.h" +#include "share.h" + +#include "memdebug.h" /* LAST include file */ + +static struct Curl_easy *easy; +static struct curl_hash *hostcache; + +static void unit_stop(void) +{ + curl_easy_cleanup(easy); + curl_global_cleanup(); +} + +static CURLcode unit_setup(void) +{ + int res = CURLE_OK; + + global_init(CURL_GLOBAL_ALL); + + easy = curl_easy_init(); + if(!easy) { + curl_global_cleanup(); + return CURLE_OUT_OF_MEMORY; + } + + hostcache = Curl_global_host_cache_init(); + if(!hostcache) { + unit_stop(); + return CURLE_OUT_OF_MEMORY; + } + + return res; +} + +struct testcase { + /* host:port:address[,address]... */ + const char *optval; + + /* lowercase host and port to retrieve the addresses from hostcache */ + const char *host; + int port; + + /* 0 to 9 addresses expected from hostcache */ + const char *address[10]; +}; + + +/* CURLOPT_RESOLVE address parsing test - to test the following defect fix: + + 1) if there is already existing host:port pair in the DNS cache and + we call CURLOPT_RESOLVE, it should also replace addresses. + for example, if there is "test.com:80" with address "1.1.1.1" + and we called CURLOPT_RESOLVE with address "2.2.2.2", then DNS entry needs to + reflect that. + + 2) when cached address is already there and close to expire, then by the + time request is made, it can get expired. This happens because, when + we set address using CURLOPT_RESOLVE, + it usually marks as permanent (by setting timestamp to zero). However, + if address already exists +in the cache, then it does not mark it, but just leaves it as it is. + So we fixing this by timestamp to zero if address already exists too. + +Test: + + - insert new entry + - verify that timestamp is not zero + - call set options with CURLOPT_RESOLVE + - then, call Curl_loadhostpairs + + expected result: cached address has zero timestamp. + + - call set options with CURLOPT_RESOLVE with same host:port pair, + different address. + - then, call Curl_loadhostpairs + + expected result: cached address has zero timestamp and new address +*/ + +static const struct testcase tests[] = { + /* spaces aren't allowed, for now */ + { "test.com:80:127.0.0.1", + "test.com", 80, { "127.0.0.1", } + }, + { "test.com:80:127.0.0.2", + "test.com", 80, { "127.0.0.2", } + }, +}; + +UNITTEST_START + int i; + int testnum = sizeof(tests) / sizeof(struct testcase); + +/* important: we setup cache outside of the loop + and also clean cache after the loop. In contrast,for example, + test 1607 sets up and cleans cache on each iteration. */ + Curl_hostcache_clean(easy, hostcache); + easy->dns.hostcache = hostcache; + easy->dns.hostcachetype = HCACHE_GLOBAL; + + for(i = 0; i < testnum; ++i, curl_easy_reset(easy)) { + int j; + int addressnum = sizeof (tests[i].address) / sizeof (*tests[i].address); + struct Curl_addrinfo *addr; + struct Curl_dns_entry *dns; + struct curl_slist *list; + void *entry_id; + bool problem = false; + + list = curl_slist_append(NULL, tests[i].optval); + if(!list) + goto unit_test_abort; + + curl_easy_setopt(easy, CURLOPT_RESOLVE, list); + + Curl_loadhostpairs(easy); + + entry_id = (void *)aprintf("%s:%d", tests[i].host, tests[i].port); + if(!entry_id) { + curl_slist_free_all(list); + goto unit_test_abort; + } + dns = Curl_hash_pick(easy->dns.hostcache, entry_id, strlen(entry_id) + 1); + free(entry_id); + entry_id = NULL; + + addr = dns ? dns->addr : NULL; + + for(j = 0; j < addressnum; ++j) { + long port = 0; + char ipaddress[MAX_IPADR_LEN] = {0}; + + if(!addr && !tests[i].address[j]) + break; + + if(addr && !Curl_getaddressinfo(addr->ai_addr, + ipaddress, &port)) { + fprintf(stderr, "%s:%d tests[%d] failed. getaddressinfo failed.\n", + __FILE__, __LINE__, i); + problem = true; + break; + } + + if(addr && !tests[i].address[j]) { + fprintf(stderr, "%s:%d tests[%d] failed. the retrieved addr " + "is %s but tests[%d].address[%d] is NULL.\n", + __FILE__, __LINE__, i, ipaddress, i, j); + problem = true; + break; + } + + if(!addr && tests[i].address[j]) { + fprintf(stderr, "%s:%d tests[%d] failed. the retrieved addr " + "is NULL but tests[%d].address[%d] is %s.\n", + __FILE__, __LINE__, i, i, j, tests[i].address[j]); + problem = true; + break; + } + + if(!curl_strequal(ipaddress, tests[i].address[j])) { + fprintf(stderr, "%s:%d tests[%d] failed. the retrieved addr " + "%s is not equal to tests[%d].address[%d] %s.\n", + __FILE__, __LINE__, i, ipaddress, i, j, tests[i].address[j]); + problem = true; + break; + } + + if(port != tests[i].port) { + fprintf(stderr, "%s:%d tests[%d] failed. the retrieved port " + "for tests[%d].address[%d] is %ld but tests[%d].port is %d.\n", + __FILE__, __LINE__, i, i, j, port, i, tests[i].port); + problem = true; + break; + } + + addr = addr->ai_next; + } + + curl_slist_free_all(list); + + if(problem) { + unitfail++; + continue; + } + } + + Curl_hostcache_clean(easy, easy->dns.hostcache); + +UNITTEST_STOP -- cgit v1.2.3