unit1609.c (6587B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 #include "unitcheck.h" 25 26 #include "urldata.h" 27 #include "connect.h" 28 #include "share.h" 29 30 #include "memdebug.h" /* LAST include file */ 31 32 static CURLcode t1609_setup(void) 33 { 34 CURLcode res = CURLE_OK; 35 global_init(CURL_GLOBAL_ALL); 36 return res; 37 } 38 39 /* CURLOPT_RESOLVE address parsing test - to test the following defect fix: 40 41 1) if there is already existing host:port pair in the DNS cache and 42 we call CURLOPT_RESOLVE, it should also replace addresses. 43 for example, if there is "test.com:80" with address "1.1.1.1" 44 and we called CURLOPT_RESOLVE with address "2.2.2.2", then DNS entry needs to 45 reflect that. 46 47 2) when cached address is already there and close to expire, then by the 48 time request is made, it can get expired. This happens because, when 49 we set address using CURLOPT_RESOLVE, 50 it usually marks as permanent (by setting timestamp to zero). However, 51 if address already exists 52 in the cache, then it does not mark it, but just leaves it as it is. 53 So we fixing this by timestamp to zero if address already exists too. 54 55 Test: 56 57 - insert new entry 58 - verify that timestamp is not zero 59 - call set options with CURLOPT_RESOLVE 60 - then, call Curl_loadhostpairs 61 62 expected result: cached address has zero timestamp. 63 64 - call set options with CURLOPT_RESOLVE with same host:port pair, 65 different address. 66 - then, call Curl_loadhostpairs 67 68 expected result: cached address has zero timestamp and new address 69 */ 70 71 static CURLcode test_unit1609(char *arg) 72 { 73 UNITTEST_BEGIN(t1609_setup()) 74 75 struct testcase { 76 /* host:port:address[,address]... */ 77 const char *optval; 78 79 /* lowercase host and port to retrieve the addresses from hostcache */ 80 const char *host; 81 int port; 82 83 /* 0 to 9 addresses expected from hostcache */ 84 const char *address[10]; 85 }; 86 87 static const struct testcase tests[] = { 88 /* spaces aren't allowed, for now */ 89 { "test.com:80:127.0.0.1", 90 "test.com", 80, { "127.0.0.1", } 91 }, 92 { "test.com:80:127.0.0.2", 93 "test.com", 80, { "127.0.0.2", } 94 }, 95 }; 96 97 int i; 98 struct Curl_multi *multi = NULL; 99 struct Curl_easy *easy = NULL; 100 struct curl_slist *list = NULL; 101 102 /* important: we setup cache outside of the loop 103 and also clean cache after the loop. In contrast,for example, 104 test 1607 sets up and cleans cache on each iteration. */ 105 106 for(i = 0; i < (int)CURL_ARRAYSIZE(tests); ++i) { 107 int j; 108 int addressnum = CURL_ARRAYSIZE(tests[i].address); 109 struct Curl_addrinfo *addr; 110 struct Curl_dns_entry *dns; 111 void *entry_id; 112 bool problem = false; 113 easy = curl_easy_init(); 114 if(!easy) { 115 curl_global_cleanup(); 116 return CURLE_OUT_OF_MEMORY; 117 } 118 /* create a multi handle and add the easy handle to it so that the 119 hostcache is setup */ 120 multi = curl_multi_init(); 121 if(!multi) 122 goto error; 123 curl_multi_add_handle(multi, easy); 124 125 list = curl_slist_append(NULL, tests[i].optval); 126 if(!list) 127 goto error; 128 129 curl_easy_setopt(easy, CURLOPT_RESOLVE, list); 130 131 if(Curl_loadhostpairs(easy)) 132 goto error; 133 134 entry_id = (void *)curl_maprintf("%s:%d", tests[i].host, tests[i].port); 135 if(!entry_id) 136 goto error; 137 138 dns = Curl_hash_pick(&multi->dnscache.entries, 139 entry_id, strlen(entry_id) + 1); 140 free(entry_id); 141 entry_id = NULL; 142 143 addr = dns ? dns->addr : NULL; 144 145 for(j = 0; j < addressnum; ++j) { 146 int port = 0; 147 char ipaddress[MAX_IPADR_LEN] = {0}; 148 149 if(!addr && !tests[i].address[j]) 150 break; 151 152 if(addr && !Curl_addr2string(addr->ai_addr, addr->ai_addrlen, 153 ipaddress, &port)) { 154 curl_mfprintf(stderr, 155 "%s:%d tests[%d] failed. Curl_addr2string failed.\n", 156 __FILE__, __LINE__, i); 157 problem = true; 158 break; 159 } 160 161 if(addr && !tests[i].address[j]) { 162 curl_mfprintf(stderr, "%s:%d tests[%d] failed. the retrieved addr " 163 "is %s but tests[%d].address[%d] is NULL.\n", 164 __FILE__, __LINE__, i, ipaddress, i, j); 165 problem = true; 166 break; 167 } 168 169 if(!addr && tests[i].address[j]) { 170 curl_mfprintf(stderr, "%s:%d tests[%d] failed. the retrieved addr " 171 "is NULL but tests[%d].address[%d] is %s.\n", 172 __FILE__, __LINE__, i, i, j, tests[i].address[j]); 173 problem = true; 174 break; 175 } 176 177 if(!curl_strequal(ipaddress, tests[i].address[j])) { 178 curl_mfprintf(stderr, "%s:%d tests[%d] failed. the retrieved addr " 179 "%s is not equal to tests[%d].address[%d] %s.\n", 180 __FILE__, __LINE__, i, ipaddress, i, j, 181 tests[i].address[j]); 182 problem = true; 183 break; 184 } 185 186 if(port != tests[i].port) { 187 curl_mfprintf(stderr, "%s:%d tests[%d] failed. the retrieved port " 188 "for tests[%d].address[%d] is %d " 189 "but tests[%d].port is %d.\n", 190 __FILE__, __LINE__, i, i, j, port, i, tests[i].port); 191 problem = true; 192 break; 193 } 194 195 addr = addr->ai_next; 196 } 197 198 curl_easy_cleanup(easy); 199 easy = NULL; 200 curl_multi_cleanup(multi); 201 multi = NULL; 202 curl_slist_free_all(list); 203 list = NULL; 204 205 if(problem) { 206 unitfail++; 207 continue; 208 } 209 } 210 goto unit_test_abort; 211 error: 212 curl_easy_cleanup(easy); 213 curl_multi_cleanup(multi); 214 curl_slist_free_all(list); 215 216 UNITTEST_END(curl_global_cleanup()) 217 }