Вы не можете выбрать более 25 тем
			Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
		
		
		
		
		
			
		
			
				
	
	
		
			219 строки
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
			
		
		
	
	
			219 строки
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
/***************************************************************************
 | 
						|
 *                                  _   _ ____  _
 | 
						|
 *  Project                     ___| | | |  _ \| |
 | 
						|
 *                             / __| | | | |_) | |
 | 
						|
 *                            | (__| |_| |  _ <| |___
 | 
						|
 *                             \___|\___/|_| \_\_____|
 | 
						|
 *
 | 
						|
 * Copyright (C) 1998 - 2021, 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
 | 
						|
 * are also available at https://curl.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 void unit_stop(void)
 | 
						|
{
 | 
						|
  curl_global_cleanup();
 | 
						|
}
 | 
						|
 | 
						|
static CURLcode unit_setup(void)
 | 
						|
{
 | 
						|
  int res = CURLE_OK;
 | 
						|
 | 
						|
  global_init(CURL_GLOBAL_ALL);
 | 
						|
 | 
						|
  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);
 | 
						|
  struct Curl_multi *multi = NULL;
 | 
						|
  struct Curl_easy *easy = NULL;
 | 
						|
  struct curl_slist *list = NULL;
 | 
						|
 | 
						|
/* 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. */
 | 
						|
 | 
						|
  for(i = 0; i < testnum; ++i) {
 | 
						|
    int j;
 | 
						|
    int addressnum = sizeof (tests[i].address) / sizeof (*tests[i].address);
 | 
						|
    struct Curl_addrinfo *addr;
 | 
						|
    struct Curl_dns_entry *dns;
 | 
						|
    void *entry_id;
 | 
						|
    bool problem = false;
 | 
						|
    easy = curl_easy_init();
 | 
						|
    if(!easy) {
 | 
						|
      curl_global_cleanup();
 | 
						|
      return CURLE_OUT_OF_MEMORY;
 | 
						|
    }
 | 
						|
    /* create a multi handle and add the easy handle to it so that the
 | 
						|
       hostcache is setup */
 | 
						|
    multi = curl_multi_init();
 | 
						|
    if(!multi)
 | 
						|
      goto error;
 | 
						|
    curl_multi_add_handle(multi, easy);
 | 
						|
 | 
						|
    list = curl_slist_append(NULL, tests[i].optval);
 | 
						|
    if(!list)
 | 
						|
      goto error;
 | 
						|
 | 
						|
    curl_easy_setopt(easy, CURLOPT_RESOLVE, list);
 | 
						|
 | 
						|
    if(Curl_loadhostpairs(easy))
 | 
						|
      goto error;
 | 
						|
 | 
						|
    entry_id = (void *)aprintf("%s:%d", tests[i].host, tests[i].port);
 | 
						|
    if(!entry_id)
 | 
						|
      goto error;
 | 
						|
 | 
						|
    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) {
 | 
						|
      int port = 0;
 | 
						|
      char ipaddress[MAX_IPADR_LEN] = {0};
 | 
						|
 | 
						|
      if(!addr && !tests[i].address[j])
 | 
						|
        break;
 | 
						|
 | 
						|
      if(addr && !Curl_addr2string(addr->ai_addr, addr->ai_addrlen,
 | 
						|
                                   ipaddress, &port)) {
 | 
						|
        fprintf(stderr, "%s:%d tests[%d] failed. Curl_addr2string 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_easy_cleanup(easy);
 | 
						|
    easy = NULL;
 | 
						|
    Curl_hash_destroy(&multi->hostcache);
 | 
						|
    curl_multi_cleanup(multi);
 | 
						|
    multi = NULL;
 | 
						|
    curl_slist_free_all(list);
 | 
						|
    list = NULL;
 | 
						|
 | 
						|
    if(problem) {
 | 
						|
      unitfail++;
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  goto unit_test_abort;
 | 
						|
  error:
 | 
						|
  curl_easy_cleanup(easy);
 | 
						|
  curl_multi_cleanup(multi);
 | 
						|
  curl_slist_free_all(list);
 | 
						|
}
 | 
						|
UNITTEST_STOP
 |