mirror of
https://github.com/pocoproject/poco.git
synced 2024-12-12 18:20:26 +01:00
added IDN support to Poco::Net::DNS
This commit is contained in:
parent
cb54071c4a
commit
c74af100b5
@ -45,7 +45,7 @@ public:
|
||||
DNS_HINT_AI_NUMERICSERV = AI_NUMERICSERV, /// Servicename must be a numeric port number
|
||||
DNS_HINT_AI_ALL = AI_ALL, /// Query both IP6 and IP4 with AI_V4MAPPED
|
||||
DNS_HINT_AI_ADDRCONFIG = AI_ADDRCONFIG, /// Resolution only if global address configured
|
||||
DNS_HINT_AI_V4MAPPED = AI_V4MAPPED /// On v6 failure, query v4 and convert to V4MAPPED format
|
||||
DNS_HINT_AI_V4MAPPED = AI_V4MAPPED /// On v6 failure, query v4 and convert to V4MAPPED format
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -54,7 +54,7 @@ public:
|
||||
DNS_HINT_AI_CANONNAME | DNS_HINT_AI_ADDRCONFIG
|
||||
#else
|
||||
DNS_HINT_NONE
|
||||
#endif
|
||||
#endif
|
||||
);
|
||||
/// Returns a HostEntry object containing the DNS information
|
||||
/// for the host with the given name. HintFlag argument is only
|
||||
@ -69,13 +69,13 @@ public:
|
||||
/// Throws a DNSException in case of a general DNS error.
|
||||
///
|
||||
/// Throws an IOException in case of any other error.
|
||||
|
||||
|
||||
static HostEntry hostByAddress(const IPAddress& address, unsigned hintFlags =
|
||||
#ifdef POCO_HAVE_ADDRINFO
|
||||
DNS_HINT_AI_CANONNAME | DNS_HINT_AI_ADDRCONFIG
|
||||
#else
|
||||
DNS_HINT_NONE
|
||||
#endif
|
||||
#endif
|
||||
);
|
||||
/// Returns a HostEntry object containing the DNS information
|
||||
/// for the host with the given IP address. HintFlag argument is only
|
||||
@ -92,6 +92,10 @@ public:
|
||||
/// Returns a HostEntry object containing the DNS information
|
||||
/// for the host with the given IP address or host name.
|
||||
///
|
||||
/// If address contains a UTF-8 encoded IDN (internationalized
|
||||
/// domain name), the domain name will be encoded first according
|
||||
/// to Punycode.
|
||||
///
|
||||
/// Throws a HostNotFoundException if a host with the given
|
||||
/// name cannot be found.
|
||||
///
|
||||
@ -101,16 +105,16 @@ public:
|
||||
/// Throws a DNSException in case of a general DNS error.
|
||||
///
|
||||
/// Throws an IOException in case of any other error.
|
||||
|
||||
|
||||
static IPAddress resolveOne(const std::string& address);
|
||||
/// Convenience method that calls resolve(address) and returns
|
||||
/// Convenience method that calls resolve(address) and returns
|
||||
/// the first address from the HostInfo.
|
||||
|
||||
static HostEntry thisHost();
|
||||
/// Returns a HostEntry object containing the DNS information
|
||||
/// for this host.
|
||||
///
|
||||
/// Throws a HostNotFoundException if DNS information
|
||||
/// Throws a HostNotFoundException if DNS information
|
||||
/// for this host cannot be found.
|
||||
///
|
||||
/// Throws a NoAddressFoundException if no address can be
|
||||
@ -133,19 +137,53 @@ public:
|
||||
///
|
||||
/// As of 1.4.2, the DNS cache is no longer used
|
||||
/// and this method does not do anything.
|
||||
|
||||
|
||||
static std::string hostName();
|
||||
/// Returns the host name of this host.
|
||||
|
||||
static bool isIDN(const std::string& hostname);
|
||||
/// Returns true if the given hostname is an internationalized
|
||||
/// domain name (IDN) containing non-ASCII characters, otherwise false.
|
||||
///
|
||||
/// The IDN must be UTF-8 encoded.
|
||||
|
||||
static bool isEncodedIDN(const std::string& hostname);
|
||||
/// Returns true if the given hostname is an Punycode-encoded
|
||||
/// internationalized domain name (IDN), otherwise false.
|
||||
///
|
||||
/// An encoded IDN starts with the character sequence "xn--".
|
||||
|
||||
static std::string encodeIDN(const std::string& idn);
|
||||
/// Encodes the given IDN (internationalized domain name), which must
|
||||
/// be in UTF-8 encoding.
|
||||
///
|
||||
/// The resulting string will be encoded according to Punycode.
|
||||
|
||||
static std::string decodeIDN(const std::string& encodedIDN);
|
||||
/// Decodes the given Punycode-encoded IDN (internationalized domain name).
|
||||
///
|
||||
/// The resulting string will be UTF-8 encoded.
|
||||
|
||||
protected:
|
||||
static int lastError();
|
||||
/// Returns the code of the last error.
|
||||
|
||||
|
||||
static void error(int code, const std::string& arg);
|
||||
/// Throws an exception according to the error code.
|
||||
|
||||
static void aierror(int code, const std::string& arg);
|
||||
/// Throws an exception according to the getaddrinfo() error code.
|
||||
|
||||
static std::string encodeIDNLabel(const std::string& idn);
|
||||
/// Encodes the given IDN (internationalized domain name) label, which must
|
||||
/// be in UTF-8 encoding.
|
||||
///
|
||||
/// The resulting string will be encoded according to Punycode.
|
||||
|
||||
static std::string decodeIDNLabel(const std::string& encodedIDN);
|
||||
/// Decodes the given Punycode-encoded IDN (internationalized domain name) label.
|
||||
///
|
||||
/// The resulting string will be UTF-8 encoded.
|
||||
};
|
||||
|
||||
|
||||
|
431
Net/src/DNS.cpp
431
Net/src/DNS.cpp
@ -18,6 +18,11 @@
|
||||
#include "Poco/Environment.h"
|
||||
#include "Poco/NumberFormatter.h"
|
||||
#include "Poco/RWLock.h"
|
||||
#include "Poco/TextIterator.h"
|
||||
#include "Poco/TextConverter.h"
|
||||
#include "Poco/UTF8Encoding.h"
|
||||
#include "Poco/UTF32Encoding.h"
|
||||
#include "Poco/Unicode.h"
|
||||
#include <cstring>
|
||||
|
||||
|
||||
@ -35,12 +40,28 @@ namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
typedef Poco::UInt32 punycode_uint;
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
punycode_success = 0,
|
||||
punycode_overflow = -1,
|
||||
punycode_big_output = -2,
|
||||
punycode_bad_input = -3
|
||||
};
|
||||
|
||||
|
||||
static int punycode_encode(size_t input_length, const punycode_uint input[], size_t* output_length, char output[]);
|
||||
static int punycode_decode(size_t input_length, const char input[], size_t* output_length, punycode_uint output[]);
|
||||
|
||||
|
||||
#if defined(POCO_HAVE_LIBRESOLV)
|
||||
static Poco::RWLock resolverLock;
|
||||
#endif
|
||||
|
||||
|
||||
HostEntry DNS::hostByName(const std::string& hostname, unsigned
|
||||
HostEntry DNS::hostByName(const std::string& hostname, unsigned
|
||||
#ifdef POCO_HAVE_ADDRINFO
|
||||
hintFlags
|
||||
#endif
|
||||
@ -55,7 +76,7 @@ HostEntry DNS::hostByName(const std::string& hostname, unsigned
|
||||
struct addrinfo hints;
|
||||
std::memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_flags = hintFlags;
|
||||
int rc = getaddrinfo(hostname.c_str(), NULL, &hints, &pAI);
|
||||
int rc = getaddrinfo(hostname.c_str(), NULL, &hints, &pAI);
|
||||
if (rc == 0)
|
||||
{
|
||||
HostEntry result(pAI);
|
||||
@ -84,7 +105,7 @@ HostEntry DNS::hostByName(const std::string& hostname, unsigned
|
||||
}
|
||||
|
||||
|
||||
HostEntry DNS::hostByAddress(const IPAddress& address, unsigned
|
||||
HostEntry DNS::hostByAddress(const IPAddress& address, unsigned
|
||||
#ifdef POCO_HAVE_ADDRINFO
|
||||
hintFlags
|
||||
#endif
|
||||
@ -97,7 +118,7 @@ HostEntry DNS::hostByAddress(const IPAddress& address, unsigned
|
||||
#if defined(POCO_HAVE_ADDRINFO)
|
||||
SocketAddress sa(address, 0);
|
||||
static char fqname[1024];
|
||||
int rc = getnameinfo(sa.addr(), sa.length(), fqname, sizeof(fqname), NULL, 0, NI_NAMEREQD);
|
||||
int rc = getnameinfo(sa.addr(), sa.length(), fqname, sizeof(fqname), NULL, 0, NI_NAMEREQD);
|
||||
if (rc == 0)
|
||||
{
|
||||
struct addrinfo* pAI;
|
||||
@ -190,6 +211,117 @@ std::string DNS::hostName()
|
||||
}
|
||||
|
||||
|
||||
bool DNS::isIDN(const std::string& hostname)
|
||||
{
|
||||
for (std::string::const_iterator it = hostname.begin(); it != hostname.end(); ++it)
|
||||
{
|
||||
if (static_cast<unsigned char>(*it) >= 0x80) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool DNS::isEncodedIDN(const std::string& hostname)
|
||||
{
|
||||
return hostname.compare(0, 4, "xn--") == 0 || hostname.find(".xn--") != std::string::npos;
|
||||
}
|
||||
|
||||
|
||||
std::string DNS::encodeIDN(const std::string& idn)
|
||||
{
|
||||
std::string encoded;
|
||||
std::string::const_iterator it = idn.begin();
|
||||
std::string::const_iterator end = idn.end();
|
||||
while (it != end)
|
||||
{
|
||||
std::string label;
|
||||
while (it != end && *it != '.')
|
||||
{
|
||||
label += *it++;
|
||||
}
|
||||
encoded += encodeIDNLabel(label);
|
||||
if (it != end) encoded += *it++;
|
||||
}
|
||||
return encoded;
|
||||
}
|
||||
|
||||
|
||||
std::string DNS::decodeIDN(const std::string& encodedIDN)
|
||||
{
|
||||
std::string decoded;
|
||||
std::string::const_iterator it = encodedIDN.begin();
|
||||
std::string::const_iterator end = encodedIDN.end();
|
||||
while (it != end)
|
||||
{
|
||||
std::string label;
|
||||
while (it != end && *it != '.')
|
||||
{
|
||||
label += *it++;
|
||||
}
|
||||
if (label.compare(0, 4, "xn--") == 0)
|
||||
decoded += decodeIDNLabel(label);
|
||||
else
|
||||
decoded += label;
|
||||
if (it != end) decoded += *it++;
|
||||
}
|
||||
return decoded;
|
||||
}
|
||||
|
||||
|
||||
std::string DNS::encodeIDNLabel(const std::string& label)
|
||||
{
|
||||
std::string encoded = "xn--";
|
||||
std::vector<Poco::UInt32> uniLabel;
|
||||
Poco::UTF8Encoding utf8;
|
||||
Poco::TextIterator it(label, utf8);
|
||||
Poco::TextIterator end(label);
|
||||
while (it != end)
|
||||
{
|
||||
int ch = *it;
|
||||
if (ch < 0) throw DNSException("Invalid UTF-8 character in IDN label", label);
|
||||
if (Poco::Unicode::isUpper(ch))
|
||||
{
|
||||
ch = Poco::Unicode::toLower(ch);
|
||||
}
|
||||
uniLabel.push_back(static_cast<Poco::UInt32>(ch));
|
||||
++it;
|
||||
}
|
||||
char buffer[64];
|
||||
std::size_t size = 64;
|
||||
int rc = punycode_encode(uniLabel.size(), &uniLabel[0], &size, buffer);
|
||||
if (rc > 0)
|
||||
return encoded.append(buffer, size);
|
||||
else
|
||||
throw DNSException("Failed to encode IDN label", label);
|
||||
return encoded;
|
||||
}
|
||||
|
||||
|
||||
std::string DNS::decodeIDNLabel(const std::string& encodedIDN)
|
||||
{
|
||||
std::string decoded;
|
||||
if (encodedIDN.compare(0, 4, "xn--") == 0)
|
||||
{
|
||||
std::size_t size = 64;
|
||||
punycode_uint buffer[64];
|
||||
int rc = punycode_decode(encodedIDN.size() - 4, encodedIDN.data() + 4, &size, buffer);
|
||||
if (rc > 0)
|
||||
{
|
||||
Poco::UTF32Encoding utf32;
|
||||
Poco::UTF8Encoding utf8;
|
||||
Poco::TextConverter converter(utf32, utf8);
|
||||
converter.convert(buffer, size*rc, decoded);
|
||||
}
|
||||
else throw DNSException("Failed to decode IDN label: ", encodedIDN);
|
||||
}
|
||||
else
|
||||
{
|
||||
decoded = encodedIDN;
|
||||
}
|
||||
return decoded;
|
||||
}
|
||||
|
||||
|
||||
int DNS::lastError()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
@ -201,7 +333,7 @@ int DNS::lastError()
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DNS::error(int code, const std::string& arg)
|
||||
{
|
||||
switch (code)
|
||||
@ -257,4 +389,293 @@ void DNS::aierror(int code, const std::string& arg)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Code copied from http://www.nicemice.net/idn/punycode-spec.gz on
|
||||
2018-02-17 with SHA-1 a966a8017f6be579d74a50a226accc7607c40133
|
||||
labeled punycode-spec 1.0.3 (2006-Mar-23-Thu).
|
||||
|
||||
Modified for POCO C++ Libraries by Günter Obiltschnig.
|
||||
|
||||
License on the original code:
|
||||
|
||||
punycode-spec 1.0.3 (2006-Mar-23-Thu)
|
||||
http://www.nicemice.net/idn/
|
||||
Adam M. Costello
|
||||
http://www.nicemice.net/amc/
|
||||
|
||||
B. Disclaimer and license
|
||||
|
||||
Regarding this entire document or any portion of it (including
|
||||
the pseudocode and C code), the author makes no guarantees and
|
||||
is not responsible for any damage resulting from its use. The
|
||||
author grants irrevocable permission to anyone to use, modify,
|
||||
and distribute it in any way that does not diminish the rights
|
||||
of anyone else to use, modify, and distribute it, provided that
|
||||
redistributed derivative works do not contain misleading author or
|
||||
version information. Derivative works need not be licensed under
|
||||
similar terms.
|
||||
|
||||
C. Punycode sample implementation
|
||||
|
||||
punycode-sample.c 2.0.0 (2004-Mar-21-Sun)
|
||||
http://www.nicemice.net/idn/
|
||||
Adam M. Costello
|
||||
http://www.nicemice.net/amc/
|
||||
|
||||
This is ANSI C code (C89) implementing Punycode 1.0.x.
|
||||
*/
|
||||
|
||||
|
||||
/*** Bootstring parameters for Punycode ***/
|
||||
|
||||
enum
|
||||
{
|
||||
base = 36,
|
||||
tmin = 1,
|
||||
tmax = 26,
|
||||
skew = 38,
|
||||
damp = 700,
|
||||
initial_bias = 72,
|
||||
initial_n = 0x80,
|
||||
delimiter = 0x2D
|
||||
};
|
||||
|
||||
/* basic(cp) tests whether cp is a basic code point: */
|
||||
#define basic(cp) ((punycode_uint)(cp) < 0x80)
|
||||
|
||||
/* delim(cp) tests whether cp is a delimiter: */
|
||||
#define delim(cp) ((cp) == delimiter)
|
||||
|
||||
/* encode_digit(d,flag) returns the basic code point whose value */
|
||||
/* (when used for representing integers) is d, which needs to be in */
|
||||
/* the range 0 to base-1. The lowercase form is used unless flag is */
|
||||
/* nonzero, in which case the uppercase form is used. The behavior */
|
||||
/* is undefined if flag is nonzero and digit d has no uppercase form. */
|
||||
|
||||
static char encode_digit(punycode_uint d, int flag)
|
||||
{
|
||||
return d + 22 + 75 * (d < 26) - ((flag != 0) << 5);
|
||||
/* 0..25 map to ASCII a..z or A..Z */
|
||||
/* 26..35 map to ASCII 0..9 */
|
||||
}
|
||||
|
||||
/* decode_digit(cp) returns the numeric value of a basic code */
|
||||
/* point (for use in representing integers) in the range 0 to */
|
||||
/* base-1, or base if cp does not represent a value. */
|
||||
|
||||
static unsigned decode_digit(int cp)
|
||||
{
|
||||
return (unsigned) (cp - 48 < 10 ? cp - 22 : cp - 65 < 26 ? cp - 65 :
|
||||
cp - 97 < 26 ? cp - 97 : base);
|
||||
}
|
||||
|
||||
/*** Platform-specific constants ***/
|
||||
|
||||
/* maxint is the maximum value of a punycode_uint variable: */
|
||||
static const punycode_uint maxint = -1;
|
||||
/* Because maxint is unsigned, -1 becomes the maximum value. */
|
||||
|
||||
/*** Bias adaptation function ***/
|
||||
|
||||
static punycode_uint adapt(punycode_uint delta, punycode_uint numpoints, int firsttime);
|
||||
|
||||
static punycode_uint adapt(punycode_uint delta, punycode_uint numpoints, int firsttime)
|
||||
{
|
||||
punycode_uint k;
|
||||
|
||||
delta = firsttime ? delta / damp : delta >> 1;
|
||||
/* delta >> 1 is a faster way of doing delta / 2 */
|
||||
delta += delta / numpoints;
|
||||
|
||||
for (k = 0; delta > ((base - tmin) * tmax) / 2; k += base)
|
||||
{
|
||||
delta /= base - tmin;
|
||||
}
|
||||
|
||||
return k + (base - tmin + 1) * delta / (delta + skew);
|
||||
}
|
||||
|
||||
/*** Main encode function ***/
|
||||
|
||||
int punycode_encode(size_t input_length_orig, const punycode_uint input[], size_t *output_length, char output[])
|
||||
{
|
||||
punycode_uint input_length, n, delta, h, b, bias, j, m, q, k, t;
|
||||
size_t out, max_out;
|
||||
|
||||
/* The Punycode spec assumes that the input length is the same type */
|
||||
/* of integer as a code point, so we need to convert the size_t to */
|
||||
/* a punycode_uint, which could overflow. */
|
||||
|
||||
if (input_length_orig > maxint) return punycode_overflow;
|
||||
input_length = (punycode_uint) input_length_orig;
|
||||
|
||||
/* Initialize the state: */
|
||||
|
||||
n = initial_n;
|
||||
delta = 0;
|
||||
out = 0;
|
||||
max_out = *output_length;
|
||||
bias = initial_bias;
|
||||
|
||||
/* Handle the basic code points: */
|
||||
|
||||
for (j = 0; j < input_length; ++j)
|
||||
{
|
||||
if (basic(input[j]))
|
||||
{
|
||||
if (max_out - out < 2) return punycode_big_output;
|
||||
output[out++] = (char) input[j];
|
||||
}
|
||||
/* else if (input[j] < n) return punycode_bad_input; */
|
||||
/* (not needed for Punycode with unsigned code points) */
|
||||
}
|
||||
|
||||
h = b = (punycode_uint) out;
|
||||
/* cannot overflow because out <= input_length <= maxint */
|
||||
|
||||
/* h is the number of code points that have been handled, b is the */
|
||||
/* number of basic code points, and out is the number of ASCII code */
|
||||
/* points that have been output. */
|
||||
|
||||
if (b > 0) output[out++] = delimiter;
|
||||
|
||||
/* Main encoding loop: */
|
||||
|
||||
while (h < input_length)
|
||||
{
|
||||
/* All non-basic code points < n have been */
|
||||
/* handled already. Find the next larger one: */
|
||||
|
||||
for (m = maxint, j = 0; j < input_length; ++j)
|
||||
{
|
||||
/* if (basic(input[j])) continue; */
|
||||
/* (not needed for Punycode) */
|
||||
if (input[j] >= n && input[j] < m) m = input[j];
|
||||
}
|
||||
|
||||
/* Increase delta enough to advance the decoder's */
|
||||
/* <n,i> state to <m,0>, but guard against overflow: */
|
||||
|
||||
if (m - n > (maxint - delta) / (h + 1)) return punycode_overflow;
|
||||
delta += (m - n) * (h + 1);
|
||||
n = m;
|
||||
|
||||
for (j = 0; j < input_length; ++j)
|
||||
{
|
||||
/* Punycode does not need to check whether input[j] is basic: */
|
||||
if (input[j] < n /* || basic(input[j]) */ )
|
||||
{
|
||||
if (++delta == 0) return punycode_overflow;
|
||||
}
|
||||
|
||||
if (input[j] == n)
|
||||
{
|
||||
/* Represent delta as a generalized variable-length integer: */
|
||||
|
||||
for (q = delta, k = base; ; k += base)
|
||||
{
|
||||
if (out >= max_out) return punycode_big_output;
|
||||
t = k <= bias /* + tmin */ ? tmin : /* +tmin not needed */
|
||||
k >= bias + tmax ? tmax : k - bias;
|
||||
if (q < t) break;
|
||||
output[out++] = encode_digit(t + (q - t) % (base - t), 0);
|
||||
q = (q - t) / (base - t);
|
||||
}
|
||||
|
||||
output[out++] = encode_digit(q, 0);
|
||||
bias = adapt(delta, h + 1, h == b);
|
||||
delta = 0;
|
||||
++h;
|
||||
}
|
||||
}
|
||||
|
||||
++delta, ++n;
|
||||
}
|
||||
|
||||
*output_length = out;
|
||||
return punycode_success;
|
||||
}
|
||||
|
||||
/*** Main decode function ***/
|
||||
|
||||
int punycode_decode(size_t input_length, const char input[], size_t *output_length, punycode_uint output[])
|
||||
{
|
||||
punycode_uint n, out, i, max_out, bias, oldi, w, k, digit, t;
|
||||
size_t b, j, in;
|
||||
|
||||
/* Initialize the state: */
|
||||
|
||||
n = initial_n;
|
||||
out = i = 0;
|
||||
max_out = *output_length > maxint ? maxint : (punycode_uint) *output_length;
|
||||
bias = initial_bias;
|
||||
|
||||
/* Handle the basic code points: Let b be the number of input code */
|
||||
/* points before the last delimiter, or 0 if there is none, then */
|
||||
/* copy the first b code points to the output. */
|
||||
|
||||
for (b = j = 0; j < input_length; ++j)
|
||||
{
|
||||
if (delim(input[j])) b = j;
|
||||
}
|
||||
if (b > max_out) return punycode_big_output;
|
||||
|
||||
for (j = 0; j < b; ++j)
|
||||
{
|
||||
if (!basic(input[j])) return punycode_bad_input;
|
||||
output[out++] = input[j];
|
||||
}
|
||||
|
||||
/* Main decoding loop: Start just after the last delimiter if any */
|
||||
/* basic code points were copied; start at the beginning otherwise. */
|
||||
|
||||
for (in = b > 0 ? b + 1 : 0; in < input_length; ++out)
|
||||
{
|
||||
/* in is the index of the next ASCII code point to be consumed, */
|
||||
/* and out is the number of code points in the output array. */
|
||||
|
||||
/* Decode a generalized variable-length integer into delta, */
|
||||
/* which gets added to i. The overflow checking is easier */
|
||||
/* if we increase i as we go, then subtract off its starting */
|
||||
/* value at the end to obtain delta. */
|
||||
|
||||
for (oldi = i, w = 1, k = base; ; k += base)
|
||||
{
|
||||
if (in >= input_length) return punycode_bad_input;
|
||||
digit = decode_digit(input[in++]);
|
||||
if (digit >= base) return punycode_bad_input;
|
||||
if (digit > (maxint - i) / w) return punycode_overflow;
|
||||
i += digit * w;
|
||||
t = k <= bias /* + tmin */ ? tmin : /* +tmin not needed */
|
||||
k >= bias + tmax ? tmax : k - bias;
|
||||
if (digit < t) break;
|
||||
if (w > maxint / (base - t)) return punycode_overflow;
|
||||
w *= (base - t);
|
||||
}
|
||||
|
||||
bias = adapt(i - oldi, out + 1, oldi == 0);
|
||||
|
||||
/* i was supposed to wrap around from out+1 to 0, */
|
||||
/* incrementing n each time, so we'll fix that now: */
|
||||
|
||||
if (i / (out + 1) > maxint - n) return punycode_overflow;
|
||||
n += i / (out + 1);
|
||||
i %= (out + 1);
|
||||
|
||||
/* Insert n at position i of the output: */
|
||||
|
||||
/* not needed for Punycode: */
|
||||
/* if (basic(n)) return punycode_bad_input; */
|
||||
if (out >= max_out) return punycode_big_output;
|
||||
|
||||
std::memmove(output + i + 1, output + i, (out - i) * sizeof *output);
|
||||
output[i++] = n;
|
||||
}
|
||||
|
||||
*output_length = (size_t) out;
|
||||
/* cannot overflow because out <= old value of *output_length */
|
||||
return punycode_success;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
|
@ -47,7 +47,7 @@ void DNSTest::testHostByName()
|
||||
#endif
|
||||
assert (he1.addresses().size() >= 1);
|
||||
assert (he1.addresses()[0].toString() == "1.2.3.4");
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
HostEntry he1 = DNS::hostByName("nohost.pocoproject.org");
|
||||
@ -70,7 +70,7 @@ void DNSTest::testHostByAddress()
|
||||
assert (he1.aliases().empty());
|
||||
assert (he1.addresses().size() >= 1);
|
||||
assert (he1.addresses()[0].toString() == "80.122.195.86");
|
||||
|
||||
|
||||
IPAddress ip2("10.0.244.253");
|
||||
try
|
||||
{
|
||||
@ -91,6 +91,19 @@ void DNSTest::testResolve()
|
||||
}
|
||||
|
||||
|
||||
void DNSTest::testEncodeIDN()
|
||||
{
|
||||
std::string idn("d\xc3\xb6m\xc3\xa4in.example"); // domain.example with umlauts
|
||||
assert (DNS::isIDN(idn));
|
||||
assert (DNS::encodeIDN(idn) == "xn--dmin-moa0i.example");
|
||||
}
|
||||
|
||||
|
||||
void DNSTest::testDecodeIDN()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void DNSTest::setUp()
|
||||
{
|
||||
}
|
||||
@ -108,6 +121,8 @@ CppUnit::Test* DNSTest::suite()
|
||||
CppUnit_addTest(pSuite, DNSTest, testHostByName);
|
||||
CppUnit_addTest(pSuite, DNSTest, testHostByAddress);
|
||||
CppUnit_addTest(pSuite, DNSTest, testResolve);
|
||||
CppUnit_addTest(pSuite, DNSTest, testEncodeIDN);
|
||||
CppUnit_addTest(pSuite, DNSTest, testDecodeIDN);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -27,6 +27,8 @@ public:
|
||||
void testHostByName();
|
||||
void testHostByAddress();
|
||||
void testResolve();
|
||||
void testEncodeIDN();
|
||||
void testDecodeIDN();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
Loading…
Reference in New Issue
Block a user