| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878 | /* <!-- copyright *//* * aria2 - The high speed download utility * * Copyright (C) 2006 Tatsuhiro Tsujikawa * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL.  If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so.  If you * do not wish to do so, delete this exception statement from your * version.  If you delete this exception statement from all source * files in the program, then also delete it here. *//* copyright --> */#ifndef D_UTIL_H#define D_UTIL_H#include "common.h"#include <sys/time.h>#include <limits.h>#include <stdint.h>#include <cstdio>#include <cstring>#include <string>#include <utility>#include <iosfwd>#include <ostream>#include <numeric>#include <map>#include <iomanip>#include <algorithm>#include <vector>#include <memory>#include "a2time.h"#include "a2netcompat.h"#include "a2functional.h"#include "SegList.h"#include "a2iterator.h"#include "message.h"#include "DlAbortEx.h"#include "fmt.h"#include "prefs.h"#ifdef ENABLE_SSL#include "TLSContext.h"#endif // ENABLE_SSL#ifndef HAVE_SIGACTION#define sigset_t int#endif // HAVE_SIGACTIONnamespace aria2 {class Randomizer;class BitfieldMan;class BinaryStream;class FileEntry;class RequestGroup;class Option;#ifdef WORDS_BIGENDIANinline uint64_t ntoh64(uint64_t x) { return x; }inline uint64_t hton64(uint64_t x) { return x; }#else  // !WORDS_BIGENDIANinline uint64_t byteswap64(uint64_t x){  uint64_t v1 = ntohl(x & 0x00000000ffffffffllu);  uint64_t v2 = ntohl(x >> 32);  return (v1 << 32) | v2;}inline uint64_t ntoh64(uint64_t x) { return byteswap64(x); }inline uint64_t hton64(uint64_t x) { return byteswap64(x); }#endif // !WORDS_BIGENDIAN#ifdef __MINGW32__std::wstring utf8ToWChar(const std::string& src);std::wstring utf8ToWChar(const char* str);std::string wCharToUtf8(const std::wstring& wsrc);// replace any backslash '\' in |src| with '/' and returns it.std::string toForwardSlash(const std::string& src);#else // !__MINGW32__#define utf8ToWChar(src) src#define utf8ToNative(src) src#endif // !__MINGW32__namespace util {extern const char DEFAULT_STRIP_CHARSET[];template <typename InputIterator>std::pair<InputIterator, InputIterator>stripIter(InputIterator first, InputIterator last,          const char* chars = DEFAULT_STRIP_CHARSET){  for (; first != last && strchr(chars, *first) != 0; ++first)    ;  if (first == last) {    return std::make_pair(first, last);  }  InputIterator left = last - 1;  for (; left != first && strchr(chars, *left) != 0; --left)    ;  return std::make_pair(first, left + 1);}template <typename InputIterator>InputIterator lstripIter(InputIterator first, InputIterator last, char ch){  for (; first != last && *first == ch; ++first)    ;  return first;}template <typename InputIterator>InputIterator lstripIter(InputIterator first, InputIterator last,                         const char* chars){  for (; first != last && strchr(chars, *first) != 0; ++first)    ;  return first;}template <typename InputIterator>InputIterator lstripIter(InputIterator first, InputIterator last){  return lstripIter(first, last, DEFAULT_STRIP_CHARSET);}std::string strip(const std::string& str,                  const char* chars = DEFAULT_STRIP_CHARSET);template <typename InputIterator>std::pair<std::pair<InputIterator, InputIterator>,          std::pair<InputIterator, InputIterator>>divide(InputIterator first, InputIterator last, char delim, bool strip = true){  auto dpos = std::find(first, last, delim);  if (dpos == last) {    if (strip) {      return {stripIter(first, last), {last, last}};    }    return {{first, last}, {last, last}};  }  if (strip) {    return {stripIter(first, dpos), stripIter(dpos + 1, last)};  }  return {{first, dpos}, {dpos + 1, last}};}template <typename T> std::string uitos(T n, bool comma = false){  std::string res;  if (n == 0) {    res = "0";    return res;  }  int i = 0;  T t = n;  for (; t; t /= 10, ++i)    ;  if (comma) {    i += (i - 1) / 3;  }  res.resize(i);  --i;  for (int j = 0; n; --i, ++j, n /= 10) {    res[i] = (n % 10) + '0';    if (comma && i > 1 && (j + 1) % 3 == 0) {      res[--i] = ',';    }  }  return res;}std::string itos(int64_t value, bool comma = false);/** * Computes difference in micro-seconds between tv1 and tv2, * assuming tv1 is newer than tv2. * If tv1 is older than tv2, then this method returns 0. */int64_t difftv(struct timeval tv1, struct timeval tv2);int32_t difftvsec(struct timeval tv1, struct timeval tv2);std::string replace(const std::string& target, const std::string& oldstr,                    const std::string& newstr);std::string percentEncode(const unsigned char* target, size_t len);std::string percentEncode(const std::string& target);std::string percentEncodeMini(const std::string& target);bool inRFC3986ReservedChars(const char c);bool inRFC3986UnreservedChars(const char c);bool inRFC2978MIMECharset(const char c);bool inRFC2616HttpToken(const char c);bool inRFC5987AttrChar(const char c);// Returns true if |c| is in ISO/IEC 8859-1 character set.bool isIso8859p1(unsigned char c);bool isUtf8(const std::string& str);std::string percentDecode(std::string::const_iterator first,                          std::string::const_iterator last);std::string torrentPercentEncode(const unsigned char* target, size_t len);std::string torrentPercentEncode(const std::string& target);std::string toHex(const unsigned char* src, size_t len);std::string toHex(const char* src, size_t len);std::string toHex(const std::string& src);unsigned int hexCharToUInt(unsigned char ch);// Converts hexadecimal ascii characters in [first, last) into packed// binary form and return the result. If characters in given range is// not well formed, then empty string is returned.template <typename InputIterator>std::string fromHex(InputIterator first, InputIterator last){  std::string dest;  size_t len = last - first;  if (len % 2) {    return dest;  }  for (; first != last; first += 2) {    unsigned char high = hexCharToUInt(*first);    unsigned char low = hexCharToUInt(*(first + 1));    if (high == 255 || low == 255) {      dest.clear();      return dest;    }    dest += (high * 16 + low);  }  return dest;}std::string secfmt(time_t sec);bool parseIntNoThrow(int32_t& res, const std::string& s, int base = 10);// Valid range: [0, INT32_MAX]bool parseUIntNoThrow(uint32_t& res, const std::string& s, int base = 10);bool parseLLIntNoThrow(int64_t& res, const std::string& s, int base = 10);SegList<int> parseIntSegments(const std::string& src);// Parses string which specifies the range of piece index for higher// priority and appends those indexes into result.  The input string// src can contain 2 keywords "head" and "tail".  To include both// keywords, they must be separated by comma.  "head" means the pieces// where the first byte of each file sits.  "tail" means the pieces// where the last byte of each file sits.  These keywords can take one// parameter, SIZE. For example, if "head=SIZE" is specified, pieces// in the range of first SIZE bytes of each file get higher// priority. SIZE can include K or M(1K = 1024, 1M = 1024K).// If SIZE is omitted, SIZE=defaultSize is used.//// sample: head=512K,tail=512Kvoid parsePrioritizePieceRange(    std::vector<size_t>& result, const std::string& src,    const std::vector<std::shared_ptr<FileEntry>>& fileEntries,    size_t pieceLength, int64_t defaultSize = 1048576 /* 1MiB */);// Converts ISO/IEC 8859-1 string src to utf-8.std::string iso8859p1ToUtf8(const char* src, size_t len);std::string iso8859p1ToUtf8(const std::string& src);// Parses Content-Disposition header field value |in| with its length// |len| in a manner conforming to RFC 6266 and extracts filename// value and copies it to the region pointed by |dest|. The |destlen|// specifies the capacity of the |dest|. This function does not store// NUL character after filename in |dest|. This function does not// support RFC 2231 Continuation. If the function sees RFC 2231/5987// encoding and charset, it stores its first pointer to |*charsetp|// and its length in |*charsetlenp|. Otherwise, they are NULL and 0// respectively.  In RFC 2231/5987 encoding, percent-encoded string// will be decoded to original form and stored in |dest|.//// This function returns the number of written bytes in |dest| if it// succeeds, or -1. If there is enough room to store filename in// |dest|, this function returns -1. If this function returns -1, the// |dest|, |*charsetp| and |*charsetlenp| are undefined.ssize_t parse_content_disposition(char* dest, size_t destlen,                                  const char** charsetp, size_t* charsetlenp,                                  const char* in, size_t len);std::string getContentDispositionFilename(const std::string& header);std::string toUpper(std::string src);std::string toLower(std::string src);void uppercase(std::string& s);void lowercase(std::string& s);char toUpperChar(char c);char toLowerChar(char c);bool isNumericHost(const std::string& name);typedef void (*signal_handler_t)(int);void setGlobalSignalHandler(int signal, sigset_t* mask,                            signal_handler_t handler, int flags);std::string getHomeDir();std::string getXDGDir(const std::string& environmentVariable,                      const std::string& fallbackDirectory);std::string getConfigFile();std::string getDHTFile(bool ipv6);int64_t getRealSize(const std::string& sizeWithUnit);std::string abbrevSize(int64_t size);template <typename InputIterator, typename Output>void toStream(InputIterator first, InputIterator last, Output& os){  os.printf("%s\n"            "idx|path/length\n"            "===+=============================================================="            "=============\n",            _("Files:"));  int32_t count = 1;  for (; first != last; ++first, ++count) {    os.printf("%3d|%s\n"              "   |%sB (%s)\n"              "---+------------------------------------------------------------"              "---------------\n",              count, (*first)->getPath().c_str(),              util::abbrevSize((*first)->getLength()).c_str(),              util::uitos((*first)->getLength(), true).c_str());  }}void sleep(long seconds);void usleep(long microseconds);template <typename InputIterator>bool isNumber(InputIterator first, InputIterator last){  if (first == last) {    return false;  }  for (; first != last; ++first) {    if ('0' > *first || *first > '9') {      return false;    }  }  return true;}bool isAlpha(const char c);bool isDigit(const char c);bool isHexDigit(const char c);bool isHexDigit(const std::string& s);bool isLws(const char c);bool isCRLF(const char c);template <typename InputIterator>bool isLowercase(InputIterator first, InputIterator last){  if (first == last) {    return false;  }  for (; first != last; ++first) {    if ('a' > *first || *first > 'z') {      return false;    }  }  return true;}template <typename InputIterator>bool isUppercase(InputIterator first, InputIterator last){  if (first == last) {    return false;  }  for (; first != last; ++first) {    if ('A' > *first || *first > 'Z') {      return false;    }  }  return true;}void mkdirs(const std::string& dirpath);void convertBitfield(BitfieldMan* dest, const BitfieldMan* src);// binaryStream has to be opened before calling this function.std::string toString(const std::shared_ptr<BinaryStream>& binaryStream);#ifdef HAVE_POSIX_MEMALIGNvoid* allocateAlignedMemory(size_t alignment, size_t size);#endif // HAVE_POSIX_MEMALIGNEndpoint getNumericNameInfo(const struct sockaddr* sockaddr, socklen_t len);std::string htmlEscape(const std::string& src);// Joins path element specified in [first, last).  If ".." is found,// it eats the previous element if it exists.  If "." is found, it// is just ignored and it is not appeared in the result.template <typename InputIterator>std::string joinPath(InputIterator first, InputIterator last){  std::vector<std::string> elements;  for (; first != last; ++first) {    if (*first == "..") {      if (!elements.empty()) {        elements.pop_back();      }    }    else if (*first == ".") {      // do nothing    }    else {      elements.push_back(*first);    }  }  return strjoin(elements.begin(), elements.end(), "/");}// Parses INDEX=PATH format string. INDEX must be an unsigned// integer.std::pair<size_t, std::string> parseIndexPath(const std::string& line);std::vector<std::pair<size_t, std::string>> createIndexPaths(std::istream& i);/** * Take a string [first, last) which is a delimited list and add its * elements into result as iterator pair. result is stored in out. */template <typename InputIterator, typename OutputIterator>OutputIterator splitIter(InputIterator first, InputIterator last,                         OutputIterator out, char delim, bool doStrip = false,                         bool allowEmpty = false){  for (InputIterator i = first; i != last;) {    InputIterator j = std::find(i, last, delim);    std::pair<InputIterator, InputIterator> p(i, j);    if (doStrip) {      p = stripIter(i, j);    }    if (allowEmpty || p.first != p.second) {      *out++ = p;    }    i = j;    if (j != last) {      ++i;    }  }  if (allowEmpty && (first == last || *(last - 1) == delim)) {    *out++ = std::make_pair(last, last);  }  return out;}template <typename InputIterator, typename OutputIterator>OutputIterator splitIterM(InputIterator first, InputIterator last,                          OutputIterator out, const char* delims,                          bool doStrip = false, bool allowEmpty = false){  size_t numDelims = strlen(delims);  const char* dlast = delims + numDelims;  for (InputIterator i = first; i != last;) {    InputIterator j = i;    for (; j != last && std::find(delims, dlast, *j) == dlast; ++j)      ;    std::pair<InputIterator, InputIterator> p(i, j);    if (doStrip) {      p = stripIter(i, j);    }    if (allowEmpty || p.first != p.second) {      *out++ = p;    }    i = j;    if (j != last) {      ++i;    }  }  if (allowEmpty &&      (first == last || std::find(delims, dlast, *(last - 1)) != dlast)) {    *out++ = std::make_pair(last, last);  }  return out;}template <typename InputIterator, typename OutputIterator>OutputIterator split(InputIterator first, InputIterator last,                     OutputIterator out, char delim, bool doStrip = false,                     bool allowEmpty = false){  for (InputIterator i = first; i != last;) {    InputIterator j = std::find(i, last, delim);    std::pair<InputIterator, InputIterator> p(i, j);    if (doStrip) {      p = stripIter(i, j);    }    if (allowEmpty || p.first != p.second) {      *out++ = std::string(p.first, p.second);    }    i = j;    if (j != last) {      ++i;    }  }  if (allowEmpty && (first == last || *(last - 1) == delim)) {    *out++ = std::string(last, last);  }  return out;}template <typename InputIterator1, typename InputIterator2>bool streq(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2,           InputIterator2 last2){  if (last1 - first1 != last2 - first2) {    return false;  }  return std::equal(first1, last1, first2);}template <typename InputIterator>bool streq(InputIterator first, InputIterator last, const char* b){  for (; first != last && *b != '\0'; ++first, ++b) {    if (*first != *b) {      return false;    }  }  return first == last && *b == '\0';}struct CaseCmp {  bool operator()(char lhs, char rhs) const  {    if ('A' <= lhs && lhs <= 'Z') {      lhs += 'a' - 'A';    }    if ('A' <= rhs && rhs <= 'Z') {      rhs += 'a' - 'A';    }    return lhs == rhs;  }};template <typename InputIterator1, typename InputIterator2>InputIterator1 strifind(InputIterator1 first1, InputIterator1 last1,                        InputIterator2 first2, InputIterator2 last2){  return std::search(first1, last1, first2, last2, CaseCmp());}template <typename InputIterator1, typename InputIterator2>bool strieq(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2,            InputIterator2 last2){  if (last1 - first1 != last2 - first2) {    return false;  }  return std::equal(first1, last1, first2, CaseCmp());}template <typename InputIterator>bool strieq(InputIterator first, InputIterator last, const char* b){  CaseCmp cmp;  for (; first != last && *b != '\0'; ++first, ++b) {    if (!cmp(*first, *b)) {      return false;    }  }  return first == last && *b == '\0';}bool strieq(const std::string& a, const char* b);bool strieq(const std::string& a, const std::string& b);template <typename InputIterator1, typename InputIterator2>bool startsWith(InputIterator1 first1, InputIterator1 last1,                InputIterator2 first2, InputIterator2 last2){  if (last1 - first1 < last2 - first2) {    return false;  }  return std::equal(first2, last2, first1);}template <typename InputIterator>bool startsWith(InputIterator first, InputIterator last, const char* b){  for (; first != last && *b != '\0'; ++first, ++b) {    if (*first != *b) {      return false;    }  }  return *b == '\0';}bool startsWith(const std::string& a, const char* b);bool startsWith(const std::string& a, const std::string& b);template <typename InputIterator1, typename InputIterator2>bool istartsWith(InputIterator1 first1, InputIterator1 last1,                 InputIterator2 first2, InputIterator2 last2){  if (last1 - first1 < last2 - first2) {    return false;  }  return std::equal(first2, last2, first1, CaseCmp());}template <typename InputIterator>bool istartsWith(InputIterator first, InputIterator last, const char* b){  CaseCmp cmp;  for (; first != last && *b != '\0'; ++first, ++b) {    if (!cmp(*first, *b)) {      return false;    }  }  return *b == '\0';}bool istartsWith(const std::string& a, const char* b);bool istartsWith(const std::string& a, const std::string& b);template <typename InputIterator1, typename InputIterator2>bool endsWith(InputIterator1 first1, InputIterator1 last1,              InputIterator2 first2, InputIterator2 last2){  if (last1 - first1 < last2 - first2) {    return false;  }  return std::equal(first2, last2, last1 - (last2 - first2));}bool endsWith(const std::string& a, const char* b);bool endsWith(const std::string& a, const std::string& b);template <typename InputIterator1, typename InputIterator2>bool iendsWith(InputIterator1 first1, InputIterator1 last1,               InputIterator2 first2, InputIterator2 last2){  if (last1 - first1 < last2 - first2) {    return false;  }  return std::equal(first2, last2, last1 - (last2 - first2), CaseCmp());}bool iendsWith(const std::string& a, const char* b);bool iendsWith(const std::string& a, const std::string& b);// Returns true if strcmp(a, b) < 0bool strless(const char* a, const char* b);void generateRandomData(unsigned char* data, size_t length);// Saves data to file whose name is filename. If overwrite is true,// existing file is overwritten. Otherwise, this function doesn't do// nothing.  If data is saved successfully, return true. Otherwise// returns false.bool saveAs(const std::string& filename, const std::string& data,            bool overwrite = false);// Prepend dir to relPath. If dir is empty, it prepends "." to relPath.//// dir = "/dir", relPath = "foo" => "/dir/foo"// dir = "",     relPath = "foo" => "./foo"// dir = "/",    relPath = "foo" => "/foo"std::string applyDir(const std::string& dir, const std::string& relPath);// In HTTP/FTP, file name is file component in URI. In HTTP, filename// may be a value of Content-Disposition header.  They are likely// percent encoded. If they contains, for example, %2F, when decoded,// basename contains dir component. This should be avoided.  This// function is created to fix these issues.  This function expects src// should be non-percent-encoded basename.  Currently, this function// replaces '/' with '_' and result string is passed to escapePath()// function and its result is returned.std::string fixTaintedBasename(const std::string& src);// Generates 20 bytes random key and store it to the address pointed// by key.  Caller must allocate at least 20 bytes for generated key.void generateRandomKey(unsigned char* key);// Returns true is given numeric ipv4addr is in Private Address Space.bool inPrivateAddress(const std::string& ipv4addr);// Returns true if s contains directory traversal path component such// as '..' or it contains null or control character which may fool// user.bool detectDirTraversal(const std::string& s);// Replaces null(0x00) and control character(0x01-0x1f) with '_'. If// __MINGW32__ is defined, following characters are also replaced with// '_': '"', '*', ':', '<', '>', '?', '\', '|'.std::string escapePath(const std::string& s);// Returns true if ip1 and ip2 are in the same CIDR block.  ip1 and// ip2 must be numeric IPv4 or IPv6 address. If either of them or both// of them is not valid numeric address, then returns false. bits is// prefix bits. If bits is out of range, then bits is set to the// length of binary representation of the address*8.bool inSameCidrBlock(const std::string& ip1, const std::string& ip2,                     size_t bits);// No throwvoid executeHookByOptName(const std::shared_ptr<RequestGroup>& group,                          const Option* option, PrefPtr pref);// No throwvoid executeHookByOptName(const RequestGroup* group, const Option* option,                          PrefPtr pref);std::string createSafePath(const std::string& dir, const std::string& filename);std::string createSafePath(const std::string& filename);std::string encodeNonUtf8(const std::string& s);// Create string safely. If str is NULL, returns empty string.// Otherwise, returns std::string(str).std::string makeString(const char* str);// This function is basically the same with strerror(errNum) but when// strerror returns NULL, this function returns empty string.std::string safeStrerror(int errNum);// Parses sequence [first, last) and find name=value pair delimited by// delim character. If name(and optionally value) is found, returns// pair of iterator which can use as first parameter of next call of// this function, and true. If no name is found, returns the pair of// last and false.template <typename Iterator>std::pair<Iterator, bool> nextParam(std::string& name, std::string& value,                                    Iterator first, Iterator last, char delim){  Iterator end = last;  while (first != end) {    last = first;    Iterator parmnameFirst = first;    Iterator parmnameLast = first;    bool eqFound = false;    for (; last != end; ++last) {      if (*last == delim) {        break;      }      else if (!eqFound && *last == '=') {        eqFound = true;        parmnameFirst = first;        parmnameLast = last;      }    }    std::pair<std::string::const_iterator, std::string::const_iterator> namep =        std::make_pair(last, last);    std::pair<std::string::const_iterator, std::string::const_iterator> valuep =        std::make_pair(last, last);    if (parmnameFirst == parmnameLast) {      if (!eqFound) {        parmnameFirst = first;        parmnameLast = last;        namep = stripIter(parmnameFirst, parmnameLast);      }    }    else {      first = parmnameLast + 1;      namep = stripIter(parmnameFirst, parmnameLast);      valuep = stripIter(first, last);    }    if (last != end) {      ++last;    }    if (namep.first != namep.second) {      name.assign(namep.first, namep.second);      value.assign(valuep.first, valuep.second);      return std::make_pair(last, true);    }    first = last;  }  return std::make_pair(end, false);}template <typename T> std::shared_ptr<T> copy(const std::shared_ptr<T>& a){  return std::make_shared<T>(*a.get());}// This is a bit different from cookie_helper::domainMatch().  If// hostname is numeric host, then returns true if domain == hostname.// That is if domain starts with ".", then returns true if domain is a// suffix of hostname.  If domain does not start with ".", then// returns true if domain == hostname.  Otherwise returns true.// For example,//// * noProxyDomainMatch("aria2.sf.net", ".sf.net") returns true.// * noProxyDomainMatch("sf.net", ".sf.net") returns false.bool noProxyDomainMatch(const std::string& hostname, const std::string& domain);// Checks hostname matches pattern as described in RFC 6125.bool tlsHostnameMatch(const std::string& pattern, const std::string& hostname);#ifdef ENABLE_SSLTLSVersion toTLSVersion(const std::string& ver);#endif // ENABLE_SSL#ifdef __MINGW32__// Formats error message for error code errNum, which is the return// value of GetLastError().  On error, this function returns empty// string.std::string formatLastError(int errNum);#endif // __MINGW32__// Sets file descriptor file FD_CLOEXEC to |fd|.  This function is// noop for Mingw32 build, since we disable inheritance in// CreateProcess call.void make_fd_cloexec(int fd);#ifdef __MINGW32__bool gainPrivilege(LPCTSTR privName);#endif // __MINGW32__} // namespace util} // namespace aria2#endif // D_UTIL_H
 |