diff --git a/src/DownloadContext.cc b/src/DownloadContext.cc index 46375e81..56e2e7e2 100644 --- a/src/DownloadContext.cc +++ b/src/DownloadContext.cc @@ -53,7 +53,8 @@ DownloadContext::DownloadContext(): knowsTotalLength_(true), ownerRequestGroup_(0), downloadStartTime_(0), - downloadStopTime_(downloadStartTime_) {} + downloadStopTime_(downloadStartTime_), + metalinkServerContacted_(false) {} DownloadContext::DownloadContext(size_t pieceLength, uint64_t totalLength, @@ -63,7 +64,8 @@ DownloadContext::DownloadContext(size_t pieceLength, knowsTotalLength_(true), ownerRequestGroup_(0), downloadStartTime_(0), - downloadStopTime_(0) + downloadStopTime_(0), + metalinkServerContacted_(false) { SharedHandle fileEntry(new FileEntry(path, totalLength, 0)); fileEntries_.push_back(fileEntry); diff --git a/src/DownloadContext.h b/src/DownloadContext.h index 4977d8f5..868ef621 100644 --- a/src/DownloadContext.h +++ b/src/DownloadContext.h @@ -84,6 +84,9 @@ private: Timer downloadStopTime_; SharedHandle signature_; + // This member variable is required to avoid to parse Metalink/HTTP + // Link header fields multiple times. + bool metalinkServerContacted_; public: DownloadContext(); @@ -224,6 +227,15 @@ public: SharedHandle findFileEntryByOffset(off_t offset) const; void releaseRuntimeResource(); + + void setMetalinkServerContacted(bool f) + { + metalinkServerContacted_ = f; + } + bool getMetalinkServerContacted() const + { + return metalinkServerContacted_; + } }; } // namespace aria2 diff --git a/src/HttpHeader.cc b/src/HttpHeader.cc index a4158dff..f3b90eb0 100644 --- a/src/HttpHeader.cc +++ b/src/HttpHeader.cc @@ -66,6 +66,10 @@ const std::string HttpHeader::LAST_MODIFIED("Last-Modified"); 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::CLOSE[] = "close"; const char HttpHeader::CHUNKED[] = "chunked"; @@ -110,6 +114,14 @@ std::vector HttpHeader::get(const std::string& name) const return v; } +std::pair::const_iterator, + std::multimap::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 { return getFirstAsULLInt(name); } diff --git a/src/HttpHeader.h b/src/HttpHeader.h index d0d60c93..df2e9216 100644 --- a/src/HttpHeader.h +++ b/src/HttpHeader.h @@ -71,6 +71,9 @@ public: bool defined(const std::string& name) const; const std::string& getFirst(const std::string& name) const; std::vector get(const std::string& name) const; + std::pair::const_iterator, + std::multimap::const_iterator> + getIterator(const std::string& name) const; unsigned int getFirstAsUInt(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 LINK; + + static const std::string DIGEST; + static const char HTTP_1_1[]; static const char CLOSE[]; diff --git a/src/HttpResponse.cc b/src/HttpResponse.cc index a916f3a6..17313732 100644 --- a/src/HttpResponse.cc +++ b/src/HttpResponse.cc @@ -51,6 +51,15 @@ #include "AuthConfig.h" #include "ChunkedDecodingStreamFilter.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 # include "GZipDecodingStreamFilter.h" #endif // HAVE_ZLIB @@ -286,4 +295,134 @@ bool HttpResponse::supportsPersistentConnection() const != 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 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& result, + const SharedHandle