diff --git a/ChangeLog b/ChangeLog index 7da797fc..bfd09471 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2008-04-21 Tatsuhiro Tsujikawa + + Now HTTP status and version are a member variable of HttpHeader. + HTTP status is processed as a string, not integer. + * src/AbstractProxyResponseCommand.cc + * src/HttpConnection.cc + * src/HttpHeader.cc + * src/HttpHeader.h + * src/HttpHeaderProcessor.cc + * src/HttpHeaderProcessor.h + * src/HttpResponse.cc + * src/HttpResponse.h + * test/HttpHeaderProcessorTest.cc + * test/HttpResponseTest.cc + 2008-04-20 Tatsuhiro Tsujikawa Added --header option. You can specify any number of additional HTTP headers diff --git a/src/AbstractProxyResponseCommand.cc b/src/AbstractProxyResponseCommand.cc index e27ff382..e7a620be 100644 --- a/src/AbstractProxyResponseCommand.cc +++ b/src/AbstractProxyResponseCommand.cc @@ -65,7 +65,7 @@ bool AbstractProxyResponseCommand::executeInternal() { e->commands.push_back(this); return false; } - if(httpResponse->getStatus() != 200) { + if(httpResponse->getResponseStatus() != "200") { throw new DlRetryEx(EX_PROXY_CONNECTION_FAILED); } e->commands.push_back(getNextCommand()); diff --git a/src/HttpConnection.cc b/src/HttpConnection.cc index e624a040..02a9e600 100644 --- a/src/HttpConnection.cc +++ b/src/HttpConnection.cc @@ -134,15 +134,14 @@ HttpResponseHandle HttpConnection::receiveResponse() // OK, we got all headers. logger->info(MSG_RECEIVE_RESPONSE, cuid, proc->getHeaderString().c_str()); - std::pair httpStatusHeader = proc->getHttpStatusHeader(); - if(Util::toLower(httpStatusHeader.second->getFirst("Connection")).find("close") != std::string::npos) { + SharedHandle httpHeader = proc->getHttpResponseHeader(); + if(Util::toLower(httpHeader->getFirst("Connection")).find("close") != std::string::npos) { entry->getHttpRequest()->getRequest()->setKeepAlive(false); } HttpResponseHandle httpResponse(new HttpResponse()); httpResponse->setCuid(cuid); - httpResponse->setStatus(Util::parseInt(httpStatusHeader.first)); - httpResponse->setHttpHeader(httpStatusHeader.second); + httpResponse->setHttpHeader(httpHeader); httpResponse->setHttpRequest(entry->getHttpRequest()); outstandingHttpRequests.pop_front(); diff --git a/src/HttpHeader.cc b/src/HttpHeader.cc index 9a9ad225..5a80665e 100644 --- a/src/HttpHeader.cc +++ b/src/HttpHeader.cc @@ -35,6 +35,7 @@ #include "HttpHeader.h" #include "Range.h" #include "Util.h" +#include namespace aria2 { @@ -120,4 +121,38 @@ RangeHandle HttpHeader::getRange() const return SharedHandle(new Range(startByte, endByte, entityLength)); } +const std::string& HttpHeader::getResponseStatus() const +{ + return _responseStatus; +} + +void HttpHeader::setResponseStatus(const std::string& responseStatus) +{ + _responseStatus = responseStatus; +} + +const std::string& HttpHeader::getVersion() const +{ + return _version; +} + +void HttpHeader::setVersion(const std::string& version) +{ + _version = version; +} + +void HttpHeader::fill(std::istream& in) +{ + std::string line; + while(std::getline(in, line)) { + line = Util::trim(line); + if(line.empty()) { + break; + } + std::pair hp; + Util::split(hp, line, ':'); + put(hp.first, hp.second); + } +} + } // namespace aria2 diff --git a/src/HttpHeader.h b/src/HttpHeader.h index 6349a9b7..87c7c82c 100644 --- a/src/HttpHeader.h +++ b/src/HttpHeader.h @@ -40,6 +40,7 @@ #include #include #include +#include namespace aria2 { @@ -48,6 +49,13 @@ class Range; class HttpHeader { private: std::multimap table; + + // for HTTP response header only + // response status, e.g. "200" + std::string _responseStatus; + + // HTTP version, e.g. HTTP/1.1 + std::string _version; public: HttpHeader() {} ~HttpHeader() {} @@ -60,6 +68,16 @@ public: uint64_t getFirstAsULLInt(const std::string& name) const; SharedHandle getRange() const; + + const std::string& getResponseStatus() const; + + void setResponseStatus(const std::string& responseStatus); + + const std::string& getVersion() const; + + void setVersion(const std::string& version); + + void fill(std::istream& in); }; typedef SharedHandle HttpHeaderHandle; diff --git a/src/HttpHeaderProcessor.cc b/src/HttpHeaderProcessor.cc index 254bb737..b16d7f90 100644 --- a/src/HttpHeaderProcessor.cc +++ b/src/HttpHeaderProcessor.cc @@ -77,7 +77,7 @@ bool HttpHeaderProcessor::eoh() const size_t HttpHeaderProcessor::getPutBackDataLength() const { - std::string str = strm.str(); + const std::string& str = strm.str(); std::string::size_type delimpos = std::string::npos; if((delimpos = str.find("\r\n\r\n")) != std::string::npos) { return str.size()-(delimpos+4); @@ -93,7 +93,7 @@ void HttpHeaderProcessor::clear() strm.str(""); } -std::pair HttpHeaderProcessor::getHttpStatusHeader() +SharedHandle HttpHeaderProcessor::getHttpResponseHeader() { strm.seekg(0, std::ios::beg); std::string line; @@ -102,19 +102,11 @@ std::pair HttpHeaderProcessor::getHttpStatusHeade if(line.size() <= 12) { throw new DlRetryEx(EX_NO_STATUS_HEADER); } - std::string status = line.substr(9, 3); HttpHeaderHandle httpHeader(new HttpHeader()); - while(getline(strm, line)) { - line = Util::trim(line); - if(line.empty()) { - break; - } - std::pair hp; - Util::split(hp, line, ':'); - httpHeader->put(hp.first, hp.second); - } - - return std::pair(status, httpHeader); + httpHeader->setResponseStatus(line.substr(9, 3)); + httpHeader->setVersion(line.substr(0, 8)); + httpHeader->fill(strm); + return httpHeader; } std::string HttpHeaderProcessor::getHeaderString() const diff --git a/src/HttpHeaderProcessor.h b/src/HttpHeaderProcessor.h index fc6814d3..e4bdc9f1 100644 --- a/src/HttpHeaderProcessor.h +++ b/src/HttpHeaderProcessor.h @@ -70,7 +70,11 @@ public: */ size_t getPutBackDataLength() const; - std::pair > getHttpStatusHeader(); + /** + * Processes the recieved header as a http response header and returns + * HttpHeader object. + */ + SharedHandle getHttpResponseHeader(); std::string getHeaderString() const; diff --git a/src/HttpResponse.cc b/src/HttpResponse.cc index 05946e27..90cc528c 100644 --- a/src/HttpResponse.cc +++ b/src/HttpResponse.cc @@ -50,7 +50,6 @@ namespace aria2 { HttpResponse::HttpResponse():cuid(0), - status(0), logger(LogFactory::getInstance()) {} @@ -58,19 +57,19 @@ HttpResponse::~HttpResponse() {} void HttpResponse::validateResponse() const { - if(status == 401) { + const std::string& status = getResponseStatus(); + if(status == "401") { throw new DlAbortEx(EX_AUTH_FAILED); } - if(status == 404) { + if(status == "404") { throw new DlAbortEx(MSG_RESOURCE_NOT_FOUND); } - if(status >= 400) { - throw new DlAbortEx(EX_BAD_STATUS, status); + if(status >= "400") { + throw new DlAbortEx(EX_BAD_STATUS, Util::parseUInt(status)); } - if(status >= 300) { + if(status >= "300") { if(!httpHeader->defined("Location")) { - throw new DlAbortEx(EX_LOCATION_HEADER_REQUIRED, - status); + throw new DlAbortEx(EX_LOCATION_HEADER_REQUIRED, Util::parseUInt(status)); } } else { if(!httpHeader->defined("Transfer-Encoding")) { @@ -114,7 +113,8 @@ void HttpResponse::retrieveCookie() bool HttpResponse::isRedirect() const { - return 300 <= status && status < 400 && httpHeader->defined("Location"); + const std::string& status = getResponseStatus(); + return "300" <= status && status < "400" && httpHeader->defined("Location"); } void HttpResponse::processRedirect() @@ -195,4 +195,10 @@ SharedHandle HttpResponse::getHttpRequest() const return httpRequest; } +// TODO return std::string +const std::string& HttpResponse::getResponseStatus() const +{ + return httpHeader->getResponseStatus(); +} + } // namespace aria2 diff --git a/src/HttpResponse.h b/src/HttpResponse.h index 57cfdd83..7ec54db9 100644 --- a/src/HttpResponse.h +++ b/src/HttpResponse.h @@ -49,7 +49,6 @@ class Logger; class HttpResponse { private: int32_t cuid; - unsigned int status; SharedHandle httpRequest; SharedHandle httpHeader; const Logger* logger; @@ -95,15 +94,7 @@ public: SharedHandle getHttpHeader() const; - void setStatus(unsigned int status) - { - this->status = status; - } - - unsigned int getStatus() const - { - return status; - } + const std::string& getResponseStatus() const; void setHttpRequest(const SharedHandle& httpRequest); diff --git a/test/HttpHeaderProcessorTest.cc b/test/HttpHeaderProcessorTest.cc index 4f359e44..38e9f0fc 100644 --- a/test/HttpHeaderProcessorTest.cc +++ b/test/HttpHeaderProcessorTest.cc @@ -14,10 +14,10 @@ class HttpHeaderProcessorTest:public CppUnit::TestFixture { CPPUNIT_TEST(testUpdate2); CPPUNIT_TEST(testGetPutBackDataLength); CPPUNIT_TEST(testGetPutBackDataLength_nullChar); - CPPUNIT_TEST(testGetHttpStatusHeader); - CPPUNIT_TEST(testGetHttpStatusHeader_empty); - CPPUNIT_TEST(testGetHttpStatusHeader_statusOnly); - CPPUNIT_TEST(testGetHttpStatusHeader_insufficientStatusLength); + CPPUNIT_TEST(testGetHttpResponseHeader); + CPPUNIT_TEST(testGetHttpResponseHeader_empty); + CPPUNIT_TEST(testGetHttpResponseHeader_statusOnly); + CPPUNIT_TEST(testGetHttpResponseHeader_insufficientStatusLength); CPPUNIT_TEST(testBeyondLimit); CPPUNIT_TEST(testGetHeaderString); CPPUNIT_TEST_SUITE_END(); @@ -27,12 +27,13 @@ public: void testUpdate2(); void testGetPutBackDataLength(); void testGetPutBackDataLength_nullChar(); - void testGetHttpStatusHeader(); - void testGetHttpStatusHeader_empty(); - void testGetHttpStatusHeader_statusOnly(); - void testGetHttpStatusHeader_insufficientStatusLength(); + void testGetHttpResponseHeader(); + void testGetHttpResponseHeader_empty(); + void testGetHttpResponseHeader_statusOnly(); + void testGetHttpResponseHeader_insufficientStatusLength(); void testBeyondLimit(); void testGetHeaderString(); + void testGetHttpRequestHeader(); }; @@ -88,7 +89,7 @@ void HttpHeaderProcessorTest::testGetPutBackDataLength_nullChar() CPPUNIT_ASSERT_EQUAL((size_t)9, proc.getPutBackDataLength()); } -void HttpHeaderProcessorTest::testGetHttpStatusHeader() +void HttpHeaderProcessorTest::testGetHttpResponseHeader() { HttpHeaderProcessor proc; std::string hd = "HTTP/1.1 200 OK\r\n" @@ -104,22 +105,24 @@ void HttpHeaderProcessorTest::testGetHttpStatusHeader() proc.update(hd); - std::pair > statusHeader = proc.getHttpStatusHeader(); - std::string status = statusHeader.first; - SharedHandle header = statusHeader.second; - CPPUNIT_ASSERT_EQUAL(std::string("200"), status); - CPPUNIT_ASSERT_EQUAL(std::string("Mon, 25 Jun 2007 16:04:59 GMT"), header->getFirst("Date")); - CPPUNIT_ASSERT_EQUAL(std::string("Apache/2.2.3 (Debian)"), header->getFirst("Server")); + SharedHandle header = proc.getHttpResponseHeader(); + CPPUNIT_ASSERT_EQUAL(std::string("200"), header->getResponseStatus()); + CPPUNIT_ASSERT_EQUAL(std::string("HTTP/1.1"), header->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string("Mon, 25 Jun 2007 16:04:59 GMT"), + header->getFirst("Date")); + CPPUNIT_ASSERT_EQUAL(std::string("Apache/2.2.3 (Debian)"), + header->getFirst("Server")); CPPUNIT_ASSERT_EQUAL(9187ULL, header->getFirstAsULLInt("Content-Length")); - CPPUNIT_ASSERT_EQUAL(std::string("text/html; charset=UTF-8"), header->getFirst("Content-Type")); + CPPUNIT_ASSERT_EQUAL(std::string("text/html; charset=UTF-8"), + header->getFirst("Content-Type")); } -void HttpHeaderProcessorTest::testGetHttpStatusHeader_empty() +void HttpHeaderProcessorTest::testGetHttpResponseHeader_empty() { HttpHeaderProcessor proc; try { - std::pair > statusHeader = proc.getHttpStatusHeader(); + proc.getHttpResponseHeader(); CPPUNIT_FAIL("Exception must be thrown."); } catch(DlRetryEx* ex) { std::cout << ex->getMsg() << std::endl; @@ -128,25 +131,24 @@ void HttpHeaderProcessorTest::testGetHttpStatusHeader_empty() } -void HttpHeaderProcessorTest::testGetHttpStatusHeader_statusOnly() +void HttpHeaderProcessorTest::testGetHttpResponseHeader_statusOnly() { HttpHeaderProcessor proc; std::string hd = "HTTP/1.1 200\r\n\r\n"; proc.update(hd); - std::pair > statusHeader = proc.getHttpStatusHeader(); - CPPUNIT_ASSERT_EQUAL(std::string("200"), statusHeader.first); - CPPUNIT_ASSERT(!statusHeader.second.isNull()); + SharedHandle header = proc.getHttpResponseHeader(); + CPPUNIT_ASSERT_EQUAL(std::string("200"), header->getResponseStatus()); } -void HttpHeaderProcessorTest::testGetHttpStatusHeader_insufficientStatusLength() +void HttpHeaderProcessorTest::testGetHttpResponseHeader_insufficientStatusLength() { HttpHeaderProcessor proc; std::string hd = "HTTP/1.1 20\r\n\r\n"; proc.update(hd); try { - std::pair > statusHeader = proc.getHttpStatusHeader(); + proc.getHttpResponseHeader(); CPPUNIT_FAIL("Exception must be thrown."); } catch(DlRetryEx* ex) { std::cout << ex->getMsg() << std::endl; diff --git a/test/HttpResponseTest.cc b/test/HttpResponseTest.cc index 44fe44b5..df01b590 100644 --- a/test/HttpResponseTest.cc +++ b/test/HttpResponseTest.cc @@ -184,14 +184,14 @@ void HttpResponseTest::testIsRedirect() { HttpResponse httpResponse; SharedHandle httpHeader(new HttpHeader()); + httpHeader->setResponseStatus("200"); httpHeader->put("Location", "http://localhost/download/aria2-1.0.0.tar.bz2"); httpResponse.setHttpHeader(httpHeader); - httpResponse.setStatus(200); CPPUNIT_ASSERT(!httpResponse.isRedirect()); - httpResponse.setStatus(304); + httpHeader->setResponseStatus("304"); CPPUNIT_ASSERT(httpResponse.isRedirect()); } @@ -242,27 +242,28 @@ void HttpResponseTest::testValidateResponse() { HttpResponse httpResponse; - httpResponse.setStatus(401); - - try { - httpResponse.validateResponse(); - CPPUNIT_FAIL("exception must be thrown."); - } catch(Exception* e) { - delete e; - } - - httpResponse.setStatus(505); - - try { - httpResponse.validateResponse(); - CPPUNIT_FAIL("exception must be thrown."); - } catch(Exception* e) { - delete e; - } - - httpResponse.setStatus(304); SharedHandle httpHeader(new HttpHeader()); + httpHeader->setResponseStatus("401"); httpResponse.setHttpHeader(httpHeader); + + try { + httpResponse.validateResponse(); + CPPUNIT_FAIL("exception must be thrown."); + } catch(Exception* e) { + delete e; + } + + httpHeader->setResponseStatus("505"); + + try { + httpResponse.validateResponse(); + CPPUNIT_FAIL("exception must be thrown."); + } catch(Exception* e) { + delete e; + } + + httpHeader->setResponseStatus("304"); + try { httpResponse.validateResponse(); CPPUNIT_FAIL("exception must be thrown."); @@ -295,7 +296,7 @@ void HttpResponseTest::testValidateResponse_good_range() request->setKeepAlive(false); httpRequest->setRequest(request); httpResponse.setHttpRequest(httpRequest); - httpResponse.setStatus(206); + httpHeader->setResponseStatus("206"); httpHeader->put("Content-Range", "bytes 1048576-10485760/10485761"); try { @@ -322,7 +323,7 @@ void HttpResponseTest::testValidateResponse_bad_range() request->setKeepAlive(false); httpRequest->setRequest(request); httpResponse.setHttpRequest(httpRequest); - httpResponse.setStatus(206); + httpHeader->setResponseStatus("206"); httpHeader->put("Content-Range", "bytes 0-10485760/10485761"); try { @@ -348,7 +349,7 @@ void HttpResponseTest::testValidateResponse_chunked() request->setKeepAlive(false); httpRequest->setRequest(request); httpResponse.setHttpRequest(httpRequest); - httpResponse.setStatus(206); + httpHeader->setResponseStatus("206"); httpHeader->put("Content-Range", "bytes 0-10485760/10485761"); httpHeader->put("Transfer-Encoding", "chunked");