/* */ #include "HttpHeader.h" #include #include "Range.h" #include "util.h" #include "A2STR.h" namespace aria2 { const std::string HttpHeader::LOCATION("Location"); const std::string HttpHeader::TRANSFER_ENCODING("Transfer-Encoding"); const std::string HttpHeader::CONTENT_ENCODING("Content-Encoding"); const std::string HttpHeader::CONTENT_DISPOSITION("Content-Disposition"); const std::string HttpHeader::SET_COOKIE("Set-Cookie"); const std::string HttpHeader::CONTENT_TYPE("Content-Type"); const std::string HttpHeader::RETRY_AFTER("Retry-After"); const std::string HttpHeader::CONNECTION("Connection"); const std::string HttpHeader::CONTENT_LENGTH("Content-Length"); const std::string HttpHeader::CONTENT_RANGE("Content-Range"); 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"; const char HttpHeader::GZIP[] = "gzip"; const char HttpHeader::DEFLATE[] = "deflate"; HttpHeader::HttpHeader() {} HttpHeader::~HttpHeader() {} void HttpHeader::put(const std::string& name, const std::string& value) { std::multimap::value_type vt (util::toLower(name), value); table_.insert(vt); } bool HttpHeader::defined(const std::string& name) const { return table_.count(util::toLower(name)) >= 1; } const std::string& HttpHeader::getFirst(const std::string& name) const { std::multimap::const_iterator itr = table_.find(util::toLower(name)); if(itr == table_.end()) { return A2STR::NIL; } else { return (*itr).second; } } std::vector HttpHeader::get(const std::string& name) const { std::vector v; std::string n(util::toLower(name)); std::pair::const_iterator, std::multimap::const_iterator> itrpair = table_.equal_range(n); std::multimap::const_iterator first = itrpair.first; while(first != itrpair.second) { v.push_back((*first).second); ++first; } 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); } uint64_t HttpHeader::getFirstAsULLInt(const std::string& name) const { const std::string& value = getFirst(name); if(value.empty()) { return 0; } else { return util::parseULLInt(value); } } RangeHandle HttpHeader::getRange() const { const std::string& rangeStr = getFirst(CONTENT_RANGE); if(rangeStr.empty()) { const std::string& contentLengthStr = getFirst(CONTENT_LENGTH); if(contentLengthStr.empty()) { return SharedHandle(new Range()); } else { uint64_t contentLength = util::parseULLInt(contentLengthStr); if(contentLength == 0) { return SharedHandle(new Range()); } else { return SharedHandle (new Range(0, contentLength-1, contentLength)); } } } std::string byteRangeSpec; { // we expect that rangeStr looks like 'bytes 100-199/100' // but some server returns '100-199/100', omitting bytes-unit sepcifier // 'bytes'. std::pair splist; util::divide(splist, rangeStr, ' '); if(splist.second.empty()) { // we assume bytes-unit specifier omitted. byteRangeSpec = splist.first; } else { byteRangeSpec = splist.second; } } std::pair byteRangeSpecPair; util::divide(byteRangeSpecPair, byteRangeSpec, '/'); if(util::strip(byteRangeSpecPair.first) == "*" || util::strip(byteRangeSpecPair.second) == "*") { // If byte-range-resp-spec or instance-length is "*", we returns // empty Range. The former is usually sent with 416 (Request range // not satisfiable) status. return SharedHandle(new Range()); } std::pair byteRangeRespSpecPair; util::divide(byteRangeRespSpecPair, byteRangeSpecPair.first, '-'); off_t startByte = util::parseLLInt(byteRangeRespSpecPair.first); off_t endByte = util::parseLLInt(byteRangeRespSpecPair.second); uint64_t entityLength = util::parseULLInt(byteRangeSpecPair.second); return SharedHandle(new Range(startByte, endByte, entityLength)); } void HttpHeader::setVersion(const std::string& version) { version_ = version; } void HttpHeader::setMethod(const std::string& method) { method_ = method; } void HttpHeader::setRequestPath(const std::string& requestPath) { requestPath_ = requestPath; } void HttpHeader::fill(std::istream& in) { std::string line; std::getline(in, line); while(in) { line = util::strip(line); if(line.empty()) { std::getline(in, line); } else { std::pair hp; util::divide(hp, line, ':'); while(std::getline(in, line)) { if(!line.empty() && (line[0] == ' ' || line[0] == '\t')) { line = util::strip(line); hp.second += " "; hp.second += line; } else { break; } } put(hp.first, hp.second); } } } void HttpHeader::clearField() { table_.clear(); } } // namespace aria2