}
#ifdef ENABLE_IPV6
-/* return a static IPv6 resolve for 'localhost' */
-static struct Curl_addrinfo *get_localhost6(int port)
+/* return a static IPv6 ::1 for the name */
+static struct Curl_addrinfo *get_localhost6(int port, const char *name)
{
struct Curl_addrinfo *ca;
const size_t ss_size = sizeof(struct sockaddr_in6);
- const size_t hostlen = strlen("localhost");
+ const size_t hostlen = strlen(name);
struct sockaddr_in6 sa6;
unsigned char ipv6[16];
unsigned short port16 = (unsigned short)(port & 0xffff);
ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
memcpy(ca->ai_addr, &sa6, ss_size);
ca->ai_canonname = (char *)ca->ai_addr + ss_size;
- strcpy(ca->ai_canonname, "localhost");
+ strcpy(ca->ai_canonname, name);
return ca;
}
#else
-#define get_localhost6(x) NULL
+#define get_localhost6(x,y) NULL
#endif
-/* return a static IPv4 resolve for 'localhost' */
-static struct Curl_addrinfo *get_localhost(int port)
+/* return a static IPv4 127.0.0.1 for the given name */
+static struct Curl_addrinfo *get_localhost(int port, const char *name)
{
struct Curl_addrinfo *ca;
const size_t ss_size = sizeof(struct sockaddr_in);
- const size_t hostlen = strlen("localhost");
+ const size_t hostlen = strlen(name);
struct sockaddr_in sa;
unsigned int ipv4;
unsigned short port16 = (unsigned short)(port & 0xffff);
ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
memcpy(ca->ai_addr, &sa, ss_size);
ca->ai_canonname = (char *)ca->ai_addr + ss_size;
- strcpy(ca->ai_canonname, "localhost");
- ca->ai_next = get_localhost6(port);
+ strcpy(ca->ai_canonname, name);
+ ca->ai_next = get_localhost6(port, name);
return ca;
}
return FALSE;
}
+
+/* return TRUE if 'part' is a case insentive tail of 'full' */
+static bool tailmatch(const char *full, const char *part)
+{
+ size_t plen = strlen(part);
+ size_t flen = strlen(full);
+ if(plen > flen)
+ return FALSE;
+ return strncasecompare(part, &full[flen - plen], plen);
+}
+
/*
* Curl_resolv() is the main name resolve function within libcurl. It resolves
* a name and returns a pointer to the entry in the 'entry' argument (if one
if(conn->ip_version == CURL_IPRESOLVE_V6 && !Curl_ipv6works(data))
return CURLRESOLV_ERROR;
- if(strcasecompare(hostname, "localhost"))
- addr = get_localhost(port);
+ if(strcasecompare(hostname, "localhost") ||
+ tailmatch(hostname, ".localhost"))
+ addr = get_localhost(port, hostname);
#ifndef CURL_DISABLE_DOH
else if(allowDOH && data->set.doh && !ipnum)
addr = Curl_doh(data, hostname, port, &respwait);
--- /dev/null
+<testcase>
+<info>
+<keywords>
+HTTP
+.localhost
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<data>
+HTTP/1.1 200 OK
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+Accept-Ranges: bytes
+Content-Length: 6
+Connection: close
+Content-Type: text/html
+Funny-head: yesyes
+
+-foo-
+</data>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+http
+</server>
+ <name>
+*.localhost is a local host
+ </name>
+ <command>
+http://curlmachine.localhost:%HTTPPORT/%TESTNUMBER
+</command>
+# Ensure that we're running on localhost
+<precheck>
+perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );"
+</precheck>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<protocol>
+GET /%TESTNUMBER HTTP/1.1\r
+Host: curlmachine.localhost:%HTTPPORT\r
+User-Agent: curl/%VERSION\r
+Accept: */*\r
+\r
+</protocol>
+</verify>
+</testcase>