mirror of https://github.com/aria2/aria2
Added Metalink/HTTP Link and Digest header field parser.
parent
9ff60ac477
commit
7c317de4e7
|
@ -53,7 +53,8 @@ DownloadContext::DownloadContext():
|
||||||
knowsTotalLength_(true),
|
knowsTotalLength_(true),
|
||||||
ownerRequestGroup_(0),
|
ownerRequestGroup_(0),
|
||||||
downloadStartTime_(0),
|
downloadStartTime_(0),
|
||||||
downloadStopTime_(downloadStartTime_) {}
|
downloadStopTime_(downloadStartTime_),
|
||||||
|
metalinkServerContacted_(false) {}
|
||||||
|
|
||||||
DownloadContext::DownloadContext(size_t pieceLength,
|
DownloadContext::DownloadContext(size_t pieceLength,
|
||||||
uint64_t totalLength,
|
uint64_t totalLength,
|
||||||
|
@ -63,7 +64,8 @@ DownloadContext::DownloadContext(size_t pieceLength,
|
||||||
knowsTotalLength_(true),
|
knowsTotalLength_(true),
|
||||||
ownerRequestGroup_(0),
|
ownerRequestGroup_(0),
|
||||||
downloadStartTime_(0),
|
downloadStartTime_(0),
|
||||||
downloadStopTime_(0)
|
downloadStopTime_(0),
|
||||||
|
metalinkServerContacted_(false)
|
||||||
{
|
{
|
||||||
SharedHandle<FileEntry> fileEntry(new FileEntry(path, totalLength, 0));
|
SharedHandle<FileEntry> fileEntry(new FileEntry(path, totalLength, 0));
|
||||||
fileEntries_.push_back(fileEntry);
|
fileEntries_.push_back(fileEntry);
|
||||||
|
|
|
@ -84,6 +84,9 @@ private:
|
||||||
Timer downloadStopTime_;
|
Timer downloadStopTime_;
|
||||||
|
|
||||||
SharedHandle<Signature> signature_;
|
SharedHandle<Signature> signature_;
|
||||||
|
// This member variable is required to avoid to parse Metalink/HTTP
|
||||||
|
// Link header fields multiple times.
|
||||||
|
bool metalinkServerContacted_;
|
||||||
public:
|
public:
|
||||||
DownloadContext();
|
DownloadContext();
|
||||||
|
|
||||||
|
@ -224,6 +227,15 @@ public:
|
||||||
SharedHandle<FileEntry> findFileEntryByOffset(off_t offset) const;
|
SharedHandle<FileEntry> findFileEntryByOffset(off_t offset) const;
|
||||||
|
|
||||||
void releaseRuntimeResource();
|
void releaseRuntimeResource();
|
||||||
|
|
||||||
|
void setMetalinkServerContacted(bool f)
|
||||||
|
{
|
||||||
|
metalinkServerContacted_ = f;
|
||||||
|
}
|
||||||
|
bool getMetalinkServerContacted() const
|
||||||
|
{
|
||||||
|
return metalinkServerContacted_;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace aria2
|
} // namespace aria2
|
||||||
|
|
|
@ -66,6 +66,10 @@ const std::string HttpHeader::LAST_MODIFIED("Last-Modified");
|
||||||
|
|
||||||
const std::string HttpHeader::ACCEPT_ENCODING("Accept-Encoding");
|
const std::string HttpHeader::ACCEPT_ENCODING("Accept-Encoding");
|
||||||
|
|
||||||
|
const std::string HttpHeader::LINK("Link");
|
||||||
|
|
||||||
|
const std::string HttpHeader::DIGEST("Digest");
|
||||||
|
|
||||||
const char HttpHeader::HTTP_1_1[] = "HTTP/1.1";
|
const char HttpHeader::HTTP_1_1[] = "HTTP/1.1";
|
||||||
const char HttpHeader::CLOSE[] = "close";
|
const char HttpHeader::CLOSE[] = "close";
|
||||||
const char HttpHeader::CHUNKED[] = "chunked";
|
const char HttpHeader::CHUNKED[] = "chunked";
|
||||||
|
@ -110,6 +114,14 @@ std::vector<std::string> HttpHeader::get(const std::string& name) const
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<std::multimap<std::string, std::string>::const_iterator,
|
||||||
|
std::multimap<std::string, std::string>::const_iterator>
|
||||||
|
HttpHeader::getIterator(const std::string& name) const
|
||||||
|
{
|
||||||
|
std::string n(util::toLower(name));
|
||||||
|
return table_.equal_range(n);
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int HttpHeader::getFirstAsUInt(const std::string& name) const {
|
unsigned int HttpHeader::getFirstAsUInt(const std::string& name) const {
|
||||||
return getFirstAsULLInt(name);
|
return getFirstAsULLInt(name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,9 @@ public:
|
||||||
bool defined(const std::string& name) const;
|
bool defined(const std::string& name) const;
|
||||||
const std::string& getFirst(const std::string& name) const;
|
const std::string& getFirst(const std::string& name) const;
|
||||||
std::vector<std::string> get(const std::string& name) const;
|
std::vector<std::string> get(const std::string& name) const;
|
||||||
|
std::pair<std::multimap<std::string, std::string>::const_iterator,
|
||||||
|
std::multimap<std::string, std::string>::const_iterator>
|
||||||
|
getIterator(const std::string& name) const;
|
||||||
unsigned int getFirstAsUInt(const std::string& name) const;
|
unsigned int getFirstAsUInt(const std::string& name) const;
|
||||||
uint64_t getFirstAsULLInt(const std::string& name) const;
|
uint64_t getFirstAsULLInt(const std::string& name) const;
|
||||||
|
|
||||||
|
@ -136,6 +139,10 @@ public:
|
||||||
|
|
||||||
static const std::string ACCEPT_ENCODING;
|
static const std::string ACCEPT_ENCODING;
|
||||||
|
|
||||||
|
static const std::string LINK;
|
||||||
|
|
||||||
|
static const std::string DIGEST;
|
||||||
|
|
||||||
static const char HTTP_1_1[];
|
static const char HTTP_1_1[];
|
||||||
|
|
||||||
static const char CLOSE[];
|
static const char CLOSE[];
|
||||||
|
|
|
@ -51,6 +51,15 @@
|
||||||
#include "AuthConfig.h"
|
#include "AuthConfig.h"
|
||||||
#include "ChunkedDecodingStreamFilter.h"
|
#include "ChunkedDecodingStreamFilter.h"
|
||||||
#include "error_code.h"
|
#include "error_code.h"
|
||||||
|
#include "prefs.h"
|
||||||
|
#include "Option.h"
|
||||||
|
#include "Checksum.h"
|
||||||
|
#include "uri.h"
|
||||||
|
#include "MetalinkHttpEntry.h"
|
||||||
|
#include "Base64.h"
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
#include "MessageDigest.h"
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
#ifdef HAVE_ZLIB
|
#ifdef HAVE_ZLIB
|
||||||
# include "GZipDecodingStreamFilter.h"
|
# include "GZipDecodingStreamFilter.h"
|
||||||
#endif // HAVE_ZLIB
|
#endif // HAVE_ZLIB
|
||||||
|
@ -286,4 +295,134 @@ bool HttpResponse::supportsPersistentConnection() const
|
||||||
!= std::string::npos);
|
!= std::string::npos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
bool parseMetalinkHttpLink(MetalinkHttpEntry& result, const std::string& s)
|
||||||
|
{
|
||||||
|
std::string::const_iterator first = std::find(s.begin(), s.end(), '<');
|
||||||
|
if(first == s.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::string::const_iterator last = std::find(first, s.end(), '>');
|
||||||
|
if(last == s.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::string uri(first+1, last);
|
||||||
|
uri::UriStruct us;
|
||||||
|
if(uri::parse(us, uri)) {
|
||||||
|
result.uri = uri;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
last = std::find(last, s.end(), ';');
|
||||||
|
if(last != s.end()) {
|
||||||
|
++last;
|
||||||
|
}
|
||||||
|
bool ok = false;
|
||||||
|
while(1) {
|
||||||
|
std::string name, value;
|
||||||
|
std::pair<std::string::const_iterator, bool> r =
|
||||||
|
util::nextParam(name, value, last, s.end(), ';');
|
||||||
|
last = r.first;
|
||||||
|
if(!r.second) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(value.empty()) {
|
||||||
|
if(name == "pref") {
|
||||||
|
result.pref = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(name == "rel") {
|
||||||
|
if(value == "duplicate") {
|
||||||
|
ok = true;
|
||||||
|
} else {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
} else if(name == "pri") {
|
||||||
|
int32_t priValue;
|
||||||
|
if(util::parseIntNoThrow(priValue, value)) {
|
||||||
|
if(1 <= priValue && priValue <= 999999) {
|
||||||
|
result.pri = priValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(name == "geo") {
|
||||||
|
util::lowercase(value);
|
||||||
|
result.geo = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// Metalink/HTTP is defined by http://tools.ietf.org/html/rfc6249.
|
||||||
|
// Link header field is defined by http://tools.ietf.org/html/rfc5988.
|
||||||
|
void HttpResponse::getMetalinKHttpEntries
|
||||||
|
(std::vector<MetalinkHttpEntry>& result,
|
||||||
|
const SharedHandle<Option>& option) const
|
||||||
|
{
|
||||||
|
std::pair<std::multimap<std::string, std::string>::const_iterator,
|
||||||
|
std::multimap<std::string, std::string>::const_iterator> p =
|
||||||
|
httpHeader_->getIterator(HttpHeader::LINK);
|
||||||
|
for(; p.first != p.second; ++p.first) {
|
||||||
|
MetalinkHttpEntry e;
|
||||||
|
if(parseMetalinkHttpLink(e, (*p.first).second)) {
|
||||||
|
result.push_back(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!result.empty()) {
|
||||||
|
std::vector<std::string> locs;
|
||||||
|
if(option->defined(PREF_METALINK_LOCATION)) {
|
||||||
|
util::split(util::toLower(option->get(PREF_METALINK_LOCATION)),
|
||||||
|
std::back_inserter(locs), ",", true);
|
||||||
|
}
|
||||||
|
for(std::vector<MetalinkHttpEntry>::iterator i = result.begin(),
|
||||||
|
eoi = result.end(); i != eoi; ++i) {
|
||||||
|
if(std::find(locs.begin(), locs.end(), (*i).geo) != locs.end()) {
|
||||||
|
(*i).pri -= 999999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::sort(result.begin(), result.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
// Digest header field is defined by
|
||||||
|
// http://tools.ietf.org/html/rfc3230.
|
||||||
|
SharedHandle<Checksum> HttpResponse::getDigest() const
|
||||||
|
{
|
||||||
|
SharedHandle<Checksum> res;
|
||||||
|
std::pair<std::multimap<std::string, std::string>::const_iterator,
|
||||||
|
std::multimap<std::string, std::string>::const_iterator> p =
|
||||||
|
httpHeader_->getIterator(HttpHeader::DIGEST);
|
||||||
|
for(; p.first != p.second; ++p.first) {
|
||||||
|
const std::string& s = (*p.first).second;
|
||||||
|
std::string::const_iterator itr = s.begin();
|
||||||
|
while(1) {
|
||||||
|
std::string hashType, digest;
|
||||||
|
std::pair<std::string::const_iterator, bool> r =
|
||||||
|
util::nextParam(hashType, digest, itr, s.end(), ',');
|
||||||
|
itr = r.first;
|
||||||
|
if(!r.second) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
util::lowercase(hashType);
|
||||||
|
if(!MessageDigest::supports(hashType)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::string hexDigest = util::toHex(Base64::decode(digest));
|
||||||
|
if(!MessageDigest::isValidHash(hashType, hexDigest)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(!res) {
|
||||||
|
res.reset(new Checksum(hashType, hexDigest));
|
||||||
|
} else if(MessageDigest::isStronger(hashType, res->getAlgo())) {
|
||||||
|
res->setAlgo(hashType);
|
||||||
|
res->setMessageDigest(hexDigest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
} // namespace aria2
|
} // namespace aria2
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "SharedHandle.h"
|
#include "SharedHandle.h"
|
||||||
#include "TimeA2.h"
|
#include "TimeA2.h"
|
||||||
|
@ -48,6 +49,9 @@ namespace aria2 {
|
||||||
class HttpRequest;
|
class HttpRequest;
|
||||||
class HttpHeader;
|
class HttpHeader;
|
||||||
class StreamFilter;
|
class StreamFilter;
|
||||||
|
class MetalinkHttpEntry;
|
||||||
|
class Option;
|
||||||
|
class Checksum;
|
||||||
|
|
||||||
class HttpResponse {
|
class HttpResponse {
|
||||||
private:
|
private:
|
||||||
|
@ -127,6 +131,17 @@ public:
|
||||||
Time getLastModifiedTime() const;
|
Time getLastModifiedTime() const;
|
||||||
|
|
||||||
bool supportsPersistentConnection() const;
|
bool supportsPersistentConnection() const;
|
||||||
|
|
||||||
|
void getMetalinKHttpEntries
|
||||||
|
(std::vector<MetalinkHttpEntry>& result,
|
||||||
|
const SharedHandle<Option>& option) const;
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
// Returns digest specified in Digest header field. If multiple
|
||||||
|
// digest algorithm is available, use strongest one defined in
|
||||||
|
// MessageDigest. If several same digest algorithms are available,
|
||||||
|
// but they have different value, they are all ignored.
|
||||||
|
SharedHandle<Checksum> getDigest() const;
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace aria2
|
} // namespace aria2
|
||||||
|
|
54
src/util.h
54
src/util.h
|
@ -438,6 +438,60 @@ std::string makeString(const char* str);
|
||||||
// strerror returns NULL, this function returns empty string.
|
// strerror returns NULL, this function returns empty string.
|
||||||
std::string safeStrerror(int errNum);
|
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::string tname, tvalue;
|
||||||
|
if(parmnameFirst == parmnameLast) {
|
||||||
|
if(!eqFound) {
|
||||||
|
parmnameFirst = first;
|
||||||
|
parmnameLast = last;
|
||||||
|
tname = util::stripIter(parmnameFirst, parmnameLast);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
first = parmnameLast+1;
|
||||||
|
tname = util::stripIter(parmnameFirst, parmnameLast);
|
||||||
|
tvalue = util::stripIter(first, last);
|
||||||
|
}
|
||||||
|
if(last != end) {
|
||||||
|
++last;
|
||||||
|
}
|
||||||
|
if(!tname.empty()) {
|
||||||
|
name.swap(tname);
|
||||||
|
value.swap(tvalue);
|
||||||
|
return std::make_pair(last, true);
|
||||||
|
}
|
||||||
|
first = last;
|
||||||
|
}
|
||||||
|
return std::make_pair(end, false);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace util
|
} // namespace util
|
||||||
|
|
||||||
} // namespace aria2
|
} // namespace aria2
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
#include "AuthConfigFactory.h"
|
#include "AuthConfigFactory.h"
|
||||||
#include "AuthConfig.h"
|
#include "AuthConfig.h"
|
||||||
#include "StreamFilter.h"
|
#include "StreamFilter.h"
|
||||||
|
#include "MetalinkHttpEntry.h"
|
||||||
|
#include "Option.h"
|
||||||
|
#include "Checksum.h"
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
@ -49,6 +52,10 @@ class HttpResponseTest : public CppUnit::TestFixture {
|
||||||
CPPUNIT_TEST(testProcessRedirect);
|
CPPUNIT_TEST(testProcessRedirect);
|
||||||
CPPUNIT_TEST(testRetrieveCookie);
|
CPPUNIT_TEST(testRetrieveCookie);
|
||||||
CPPUNIT_TEST(testSupportsPersistentConnection);
|
CPPUNIT_TEST(testSupportsPersistentConnection);
|
||||||
|
CPPUNIT_TEST(testGetMetalinKHttpEntries);
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
CPPUNIT_TEST(testGetDigest);
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
CPPUNIT_TEST_SUITE_END();
|
CPPUNIT_TEST_SUITE_END();
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -81,6 +88,10 @@ public:
|
||||||
void testProcessRedirect();
|
void testProcessRedirect();
|
||||||
void testRetrieveCookie();
|
void testRetrieveCookie();
|
||||||
void testSupportsPersistentConnection();
|
void testSupportsPersistentConnection();
|
||||||
|
void testGetMetalinKHttpEntries();
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
void testGetDigest();
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -590,4 +601,73 @@ void HttpResponseTest::testSupportsPersistentConnection()
|
||||||
httpHeader->clearField();
|
httpHeader->clearField();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HttpResponseTest::testGetMetalinKHttpEntries()
|
||||||
|
{
|
||||||
|
HttpResponse httpResponse;
|
||||||
|
SharedHandle<HttpHeader> httpHeader(new HttpHeader());
|
||||||
|
httpResponse.setHttpHeader(httpHeader);
|
||||||
|
SharedHandle<Option> option(new Option());
|
||||||
|
|
||||||
|
httpHeader->put("Link", "<http://uri1/>; rel=duplicate; pri=1; pref; geo=JP");
|
||||||
|
httpHeader->put("Link", "<http://uri2/>; rel=duplicate");
|
||||||
|
httpHeader->put("Link", "<http://uri3/>;;;;;;;;rel=duplicate;;;;;pri=2;;;;;");
|
||||||
|
httpHeader->put("Link", "<http://uri4/>;rel=duplicate;=pri=1;pref");
|
||||||
|
httpHeader->put("Link", "<http://describedby>; rel=describedby");
|
||||||
|
httpHeader->put("Link", "<baduri>; rel=duplicate");
|
||||||
|
httpHeader->put("Link", "<http://norel/>");
|
||||||
|
httpHeader->put("Link", "<http://badpri/>; rel=duplicate; pri=-1;");
|
||||||
|
std::vector<MetalinkHttpEntry> result;
|
||||||
|
httpResponse.getMetalinKHttpEntries(result, option);
|
||||||
|
CPPUNIT_ASSERT_EQUAL((size_t)5, result.size());
|
||||||
|
|
||||||
|
MetalinkHttpEntry e = result[0];
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("http://uri1/"), e.uri);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(1, e.pri);
|
||||||
|
CPPUNIT_ASSERT(e.pref);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("jp"), e.geo);
|
||||||
|
|
||||||
|
e = result[1];
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("http://uri4/"), e.uri);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(999999, e.pri);
|
||||||
|
CPPUNIT_ASSERT(e.pref);
|
||||||
|
CPPUNIT_ASSERT(e.geo.empty());
|
||||||
|
|
||||||
|
e = result[2];
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("http://uri3/"), e.uri);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(2, e.pri);
|
||||||
|
CPPUNIT_ASSERT(!e.pref);
|
||||||
|
CPPUNIT_ASSERT(e.geo.empty());
|
||||||
|
|
||||||
|
e = result[3];
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("http://uri2/"), e.uri);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(999999, e.pri);
|
||||||
|
CPPUNIT_ASSERT(!e.pref);
|
||||||
|
CPPUNIT_ASSERT(e.geo.empty());
|
||||||
|
|
||||||
|
e = result[4];
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("http://badpri/"), e.uri);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(999999, e.pri);
|
||||||
|
CPPUNIT_ASSERT(!e.pref);
|
||||||
|
CPPUNIT_ASSERT(e.geo.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
void HttpResponseTest::testGetDigest()
|
||||||
|
{
|
||||||
|
HttpResponse httpResponse;
|
||||||
|
SharedHandle<HttpHeader> httpHeader(new HttpHeader());
|
||||||
|
httpResponse.setHttpHeader(httpHeader);
|
||||||
|
SharedHandle<Option> option(new Option());
|
||||||
|
|
||||||
|
httpHeader->put("Digest", "SHA-1=82AD8itGL/oYQ5BTPFANiYnp9oE=");
|
||||||
|
httpHeader->put("Digest", "NOT_SUPPORTED");
|
||||||
|
httpHeader->put("Digest",
|
||||||
|
"SHA-256=+D8nGudz3G/kpkVKQeDrI3xD57v0UeQmzGCZOk03nsU=,"
|
||||||
|
"MD5=LJDK2+9ClF8Nz/K5WZd/+A==");
|
||||||
|
SharedHandle<Checksum> c = httpResponse.getDigest();
|
||||||
|
CPPUNIT_ASSERT(c);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("sha-256"), c->getAlgo());
|
||||||
|
}
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
} // namespace aria2
|
} // namespace aria2
|
||||||
|
|
|
@ -71,6 +71,7 @@ class UtilTest:public CppUnit::TestFixture {
|
||||||
CPPUNIT_TEST(testGetCidrPrefix);
|
CPPUNIT_TEST(testGetCidrPrefix);
|
||||||
CPPUNIT_TEST(testInSameCidrBlock);
|
CPPUNIT_TEST(testInSameCidrBlock);
|
||||||
CPPUNIT_TEST(testIsUtf8String);
|
CPPUNIT_TEST(testIsUtf8String);
|
||||||
|
CPPUNIT_TEST(testNextParam);
|
||||||
CPPUNIT_TEST_SUITE_END();
|
CPPUNIT_TEST_SUITE_END();
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -130,6 +131,7 @@ public:
|
||||||
void testGetCidrPrefix();
|
void testGetCidrPrefix();
|
||||||
void testInSameCidrBlock();
|
void testInSameCidrBlock();
|
||||||
void testIsUtf8String();
|
void testIsUtf8String();
|
||||||
|
void testNextParam();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1247,4 +1249,42 @@ void UtilTest::testIsUtf8String()
|
||||||
CPPUNIT_ASSERT(!util::isUtf8(util::fromHex("00")));
|
CPPUNIT_ASSERT(!util::isUtf8(util::fromHex("00")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UtilTest::testNextParam()
|
||||||
|
{
|
||||||
|
std::string s1 = " :a : b=c :d=b::::g::";
|
||||||
|
std::pair<std::string::iterator, bool> r;
|
||||||
|
std::string name, value;
|
||||||
|
r = util::nextParam(name, value, s1.begin(), s1.end(), ':');
|
||||||
|
CPPUNIT_ASSERT(r.second);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("a"), name);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string(), value);
|
||||||
|
|
||||||
|
r = util::nextParam(name, value, r.first, s1.end(), ':');
|
||||||
|
CPPUNIT_ASSERT(r.second);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("b"), name);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("c"), value);
|
||||||
|
|
||||||
|
r = util::nextParam(name, value, r.first, s1.end(), ':');
|
||||||
|
CPPUNIT_ASSERT(r.second);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("d"), name);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("b"), value);
|
||||||
|
|
||||||
|
r = util::nextParam(name, value, r.first, s1.end(), ':');
|
||||||
|
CPPUNIT_ASSERT(r.second);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("g"), name);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string(), value);
|
||||||
|
|
||||||
|
std::string s2 = "";
|
||||||
|
r = util::nextParam(name, value, s2.begin(), s2.end(), ':');
|
||||||
|
CPPUNIT_ASSERT(!r.second);
|
||||||
|
|
||||||
|
std::string s3 = " ";
|
||||||
|
r = util::nextParam(name, value, s3.begin(), s3.end(), ':');
|
||||||
|
CPPUNIT_ASSERT(!r.second);
|
||||||
|
|
||||||
|
std::string s4 = ":::";
|
||||||
|
r = util::nextParam(name, value, s4.begin(), s4.end(), ':');
|
||||||
|
CPPUNIT_ASSERT(!r.second);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace aria2
|
} // namespace aria2
|
||||||
|
|
Loading…
Reference in New Issue