#include "HttpResponse.h" #include #include #include "TestUtil.h" #include "prefs.h" #include "PiecedSegment.h" #include "Piece.h" #include "Request.h" #include "HttpHeader.h" #include "HttpRequest.h" #include "Exception.h" #include "A2STR.h" #include "DlRetryEx.h" #include "CookieStorage.h" #include "AuthConfigFactory.h" #include "AuthConfig.h" #include "StreamFilter.h" #include "MetalinkHttpEntry.h" #include "Option.h" #include "Checksum.h" namespace aria2 { class HttpResponseTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(HttpResponseTest); CPPUNIT_TEST(testGetContentLength_null); CPPUNIT_TEST(testGetContentLength_contentLength); //CPPUNIT_TEST(testGetContentLength_range); CPPUNIT_TEST(testGetEntityLength); CPPUNIT_TEST(testGetContentType); CPPUNIT_TEST(testDetermineFilename_without_ContentDisposition); CPPUNIT_TEST(testDetermineFilename_with_ContentDisposition_zero_length); CPPUNIT_TEST(testDetermineFilename_with_ContentDisposition); CPPUNIT_TEST(testGetRedirectURI_without_Location); CPPUNIT_TEST(testGetRedirectURI_with_Location); CPPUNIT_TEST(testIsRedirect); CPPUNIT_TEST(testIsTransferEncodingSpecified); CPPUNIT_TEST(testGetTransferEncoding); CPPUNIT_TEST(testGetTransferEncodingStreamFilter); CPPUNIT_TEST(testIsContentEncodingSpecified); CPPUNIT_TEST(testGetContentEncoding); CPPUNIT_TEST(testGetContentEncodingStreamFilter); CPPUNIT_TEST(testValidateResponse); CPPUNIT_TEST(testValidateResponse_good_range); CPPUNIT_TEST(testValidateResponse_bad_range); CPPUNIT_TEST(testValidateResponse_chunked); CPPUNIT_TEST(testValidateResponse_withIfModifiedSince); CPPUNIT_TEST(testProcessRedirect); CPPUNIT_TEST(testRetrieveCookie); CPPUNIT_TEST(testSupportsPersistentConnection); CPPUNIT_TEST(testGetMetalinKHttpEntries); #ifdef ENABLE_MESSAGE_DIGEST CPPUNIT_TEST(testGetDigest); #endif // ENABLE_MESSAGE_DIGEST CPPUNIT_TEST_SUITE_END(); private: public: void setUp() { } void testGetContentLength_null(); void testGetContentLength_contentLength(); void testGetEntityLength(); void testGetContentType(); void testDetermineFilename_without_ContentDisposition(); void testDetermineFilename_with_ContentDisposition_zero_length(); void testDetermineFilename_with_ContentDisposition(); void testGetRedirectURI_without_Location(); void testGetRedirectURI_with_Location(); void testIsRedirect(); void testIsTransferEncodingSpecified(); void testGetTransferEncoding(); void testGetTransferEncodingStreamFilter(); void testIsContentEncodingSpecified(); void testGetContentEncoding(); void testGetContentEncodingStreamFilter(); void testValidateResponse(); void testValidateResponse_good_range(); void testValidateResponse_bad_range(); void testValidateResponse_chunked(); void testValidateResponse_withIfModifiedSince(); void testProcessRedirect(); void testRetrieveCookie(); void testSupportsPersistentConnection(); void testGetMetalinKHttpEntries(); #ifdef ENABLE_MESSAGE_DIGEST void testGetDigest(); #endif // ENABLE_MESSAGE_DIGEST }; CPPUNIT_TEST_SUITE_REGISTRATION( HttpResponseTest ); void HttpResponseTest::testGetContentLength_null() { HttpResponse httpResponse; CPPUNIT_ASSERT_EQUAL((int64_t)0LL, httpResponse.getContentLength()); } void HttpResponseTest::testGetContentLength_contentLength() { HttpResponse httpResponse; auto httpHeader = make_unique(); httpHeader->put(HttpHeader::CONTENT_LENGTH, "4294967296"); httpResponse.setHttpHeader(std::move(httpHeader)); CPPUNIT_ASSERT_EQUAL((int64_t)4294967296LL, httpResponse.getContentLength()); } void HttpResponseTest::testGetEntityLength() { HttpResponse httpResponse; auto httpHeader = make_unique(); httpHeader->put(HttpHeader::CONTENT_LENGTH, "4294967296"); httpResponse.setHttpHeader(std::move(httpHeader)); CPPUNIT_ASSERT_EQUAL((int64_t)4294967296LL, httpResponse.getEntityLength()); httpResponse.getHttpHeader()->put(HttpHeader::CONTENT_RANGE, "bytes 1-4294967296/4294967297"); CPPUNIT_ASSERT_EQUAL((int64_t)4294967297LL, httpResponse.getEntityLength()); } void HttpResponseTest::testGetContentType() { HttpResponse httpResponse; auto httpHeader = make_unique(); httpHeader->put(HttpHeader::CONTENT_TYPE, "application/metalink+xml; charset=UTF-8"); httpResponse.setHttpHeader(std::move(httpHeader)); // See paramter is ignored. CPPUNIT_ASSERT_EQUAL(std::string("application/metalink+xml"), httpResponse.getContentType()); } void HttpResponseTest::testDetermineFilename_without_ContentDisposition() { HttpResponse httpResponse; auto httpRequest = make_unique(); auto request = std::make_shared(); request->setUri("http://localhost/archives/aria2-1.0.0.tar.bz2"); httpRequest->setRequest(request); httpResponse.setHttpHeader(make_unique()); httpResponse.setHttpRequest(std::move(httpRequest)); CPPUNIT_ASSERT_EQUAL(std::string("aria2-1.0.0.tar.bz2"), httpResponse.determineFilename()); } void HttpResponseTest::testDetermineFilename_with_ContentDisposition_zero_length () { HttpResponse httpResponse; auto httpHeader = make_unique(); httpHeader->put(HttpHeader::CONTENT_DISPOSITION, "attachment; filename=\"\""); auto httpRequest = make_unique(); auto request = std::make_shared(); request->setUri("http://localhost/archives/aria2-1.0.0.tar.bz2"); httpRequest->setRequest(request); httpResponse.setHttpHeader(std::move(httpHeader)); httpResponse.setHttpRequest(std::move(httpRequest)); CPPUNIT_ASSERT_EQUAL(std::string("aria2-1.0.0.tar.bz2"), httpResponse.determineFilename()); } void HttpResponseTest::testDetermineFilename_with_ContentDisposition() { HttpResponse httpResponse; auto httpHeader = make_unique(); httpHeader->put(HttpHeader::CONTENT_DISPOSITION, "attachment; filename=\"aria2-current.tar.bz2\""); auto httpRequest = make_unique(); auto request = std::make_shared(); request->setUri("http://localhost/archives/aria2-1.0.0.tar.bz2"); httpRequest->setRequest(request); httpResponse.setHttpHeader(std::move(httpHeader)); httpResponse.setHttpRequest(std::move(httpRequest)); CPPUNIT_ASSERT_EQUAL(std::string("aria2-current.tar.bz2"), httpResponse.determineFilename()); } void HttpResponseTest::testGetRedirectURI_without_Location() { HttpResponse httpResponse; httpResponse.setHttpHeader(make_unique()); CPPUNIT_ASSERT_EQUAL(std::string(""), httpResponse.getRedirectURI()); } void HttpResponseTest::testGetRedirectURI_with_Location() { HttpResponse httpResponse; auto httpHeader = make_unique(); httpHeader->put(HttpHeader::LOCATION, "http://localhost/download/aria2-1.0.0.tar.bz2"); httpResponse.setHttpHeader(std::move(httpHeader)); CPPUNIT_ASSERT_EQUAL (std::string("http://localhost/download/aria2-1.0.0.tar.bz2"), httpResponse.getRedirectURI()); } void HttpResponseTest::testIsRedirect() { HttpResponse httpResponse; httpResponse.setHttpHeader(make_unique()); httpResponse.getHttpHeader()->setStatusCode(301); CPPUNIT_ASSERT(!httpResponse.isRedirect()); httpResponse.getHttpHeader()->setStatusCode(200); CPPUNIT_ASSERT(!httpResponse.isRedirect()); httpResponse.getHttpHeader()->put (HttpHeader::LOCATION, "http://localhost/download/aria2-1.0.0.tar.bz2"); CPPUNIT_ASSERT(!httpResponse.isRedirect()); httpResponse.getHttpHeader()->setStatusCode(300); CPPUNIT_ASSERT(httpResponse.isRedirect()); httpResponse.getHttpHeader()->setStatusCode(301); CPPUNIT_ASSERT(httpResponse.isRedirect()); httpResponse.getHttpHeader()->setStatusCode(302); CPPUNIT_ASSERT(httpResponse.isRedirect()); httpResponse.getHttpHeader()->setStatusCode(303); CPPUNIT_ASSERT(httpResponse.isRedirect()); httpResponse.getHttpHeader()->setStatusCode(304); CPPUNIT_ASSERT(!httpResponse.isRedirect()); httpResponse.getHttpHeader()->setStatusCode(305); CPPUNIT_ASSERT(!httpResponse.isRedirect()); httpResponse.getHttpHeader()->setStatusCode(306); CPPUNIT_ASSERT(!httpResponse.isRedirect()); httpResponse.getHttpHeader()->setStatusCode(307); CPPUNIT_ASSERT(httpResponse.isRedirect()); httpResponse.getHttpHeader()->setStatusCode(308); CPPUNIT_ASSERT(httpResponse.isRedirect()); httpResponse.getHttpHeader()->setStatusCode(309); CPPUNIT_ASSERT(!httpResponse.isRedirect()); } void HttpResponseTest::testIsTransferEncodingSpecified() { HttpResponse httpResponse; httpResponse.setHttpHeader(make_unique()); CPPUNIT_ASSERT(!httpResponse.isTransferEncodingSpecified()); httpResponse.getHttpHeader()->put(HttpHeader::TRANSFER_ENCODING, "chunked"); CPPUNIT_ASSERT(httpResponse.isTransferEncodingSpecified()); } void HttpResponseTest::testGetTransferEncoding() { HttpResponse httpResponse; httpResponse.setHttpHeader(make_unique()); CPPUNIT_ASSERT_EQUAL(std::string(""), httpResponse.getTransferEncoding()); httpResponse.getHttpHeader()->put(HttpHeader::TRANSFER_ENCODING, "chunked"); CPPUNIT_ASSERT_EQUAL(std::string("chunked"), httpResponse.getTransferEncoding()); } void HttpResponseTest::testGetTransferEncodingStreamFilter() { HttpResponse httpResponse; httpResponse.setHttpHeader(make_unique()); CPPUNIT_ASSERT(!httpResponse.getTransferEncodingStreamFilter()); httpResponse.getHttpHeader()->put(HttpHeader::TRANSFER_ENCODING, "chunked"); CPPUNIT_ASSERT(httpResponse.getTransferEncodingStreamFilter()); } void HttpResponseTest::testIsContentEncodingSpecified() { HttpResponse httpResponse; httpResponse.setHttpHeader(make_unique()); CPPUNIT_ASSERT(!httpResponse.isContentEncodingSpecified()); httpResponse.getHttpHeader()->put(HttpHeader::CONTENT_ENCODING, "gzip"); CPPUNIT_ASSERT(httpResponse.isContentEncodingSpecified()); } void HttpResponseTest::testGetContentEncoding() { HttpResponse httpResponse; httpResponse.setHttpHeader(make_unique()); CPPUNIT_ASSERT_EQUAL(A2STR::NIL, httpResponse.getContentEncoding()); httpResponse.getHttpHeader()->put(HttpHeader::CONTENT_ENCODING, "gzip"); CPPUNIT_ASSERT_EQUAL(std::string("gzip"), httpResponse.getContentEncoding()); } void HttpResponseTest::testGetContentEncodingStreamFilter() { HttpResponse httpResponse; httpResponse.setHttpHeader(make_unique()); CPPUNIT_ASSERT(!httpResponse.getContentEncodingStreamFilter()); #ifdef HAVE_ZLIB httpResponse.getHttpHeader()->put(HttpHeader::CONTENT_ENCODING, "gzip"); { std::shared_ptr filter = httpResponse.getContentEncodingStreamFilter(); CPPUNIT_ASSERT(filter); CPPUNIT_ASSERT_EQUAL(std::string("GZipDecodingStreamFilter"), filter->getName()); } httpResponse.setHttpHeader(make_unique()); httpResponse.getHttpHeader()->put(HttpHeader::CONTENT_ENCODING, "deflate"); { std::shared_ptr filter = httpResponse.getContentEncodingStreamFilter(); CPPUNIT_ASSERT(filter); CPPUNIT_ASSERT_EQUAL(std::string("GZipDecodingStreamFilter"), filter->getName()); } #endif // HAVE_ZLIB httpResponse.setHttpHeader(make_unique()); httpResponse.getHttpHeader()->put(HttpHeader::CONTENT_ENCODING, "bzip2"); { std::shared_ptr filter = httpResponse.getContentEncodingStreamFilter(); CPPUNIT_ASSERT(!filter); } } void HttpResponseTest::testValidateResponse() { HttpResponse httpResponse; httpResponse.setHttpHeader(make_unique()); httpResponse.getHttpHeader()->setStatusCode(301); try { httpResponse.validateResponse(); CPPUNIT_FAIL("exception must be thrown."); } catch(Exception& e) { // success } httpResponse.getHttpHeader()->put(HttpHeader::LOCATION, "http://a/b"); httpResponse.validateResponse(); httpResponse.getHttpHeader()->setStatusCode(201); try{ httpResponse.validateResponse(); CPPUNIT_FAIL("exception must be thrown."); } catch(Exception& e) { // success } } void HttpResponseTest::testValidateResponse_good_range() { HttpResponse httpResponse; httpResponse.setHttpHeader(make_unique()); auto httpRequest = make_unique(); auto p = std::make_shared(1, 1024*1024); auto segment = std::make_shared(1024*1024, p); httpRequest->setSegment(segment); auto fileEntry = std::make_shared("file", 1024*1024*10, 0); httpRequest->setFileEntry(fileEntry); auto request = std::make_shared(); request->setUri("http://localhost/archives/aria2-1.0.0.tar.bz2"); httpRequest->setRequest(request); httpResponse.setHttpRequest(std::move(httpRequest)); httpResponse.getHttpHeader()->setStatusCode(206); httpResponse.getHttpHeader()->put(HttpHeader::CONTENT_RANGE, "bytes 1048576-10485760/10485760"); try { httpResponse.validateResponse(); } catch(Exception& e) { std::cerr << e.stackTrace() << std::endl; CPPUNIT_FAIL("exception must not be thrown."); } } void HttpResponseTest::testValidateResponse_bad_range() { HttpResponse httpResponse; httpResponse.setHttpHeader(make_unique()); auto httpRequest = make_unique(); auto p = std::make_shared(1, 1024*1024); auto segment = std::make_shared(1024*1024, p); httpRequest->setSegment(segment); auto fileEntry = std::make_shared("file", 1024*1024*10, 0); httpRequest->setFileEntry(fileEntry); auto request = std::make_shared(); request->setUri("http://localhost/archives/aria2-1.0.0.tar.bz2"); httpRequest->setRequest(request); httpResponse.setHttpRequest(std::move(httpRequest)); httpResponse.getHttpHeader()->setStatusCode(206); httpResponse.getHttpHeader()->put(HttpHeader::CONTENT_RANGE, "bytes 0-10485760/10485761"); try { httpResponse.validateResponse(); CPPUNIT_FAIL("exception must be thrown."); } catch(Exception& e) { } } void HttpResponseTest::testValidateResponse_chunked() { HttpResponse httpResponse; httpResponse.setHttpHeader(make_unique()); auto httpRequest = make_unique(); auto p = std::make_shared(1, 1024*1024); auto segment = std::make_shared(1024*1024, p); httpRequest->setSegment(segment); auto fileEntry = std::make_shared("file", 1024*1024*10, 0); httpRequest->setFileEntry(fileEntry); auto request = std::make_shared(); request->setUri("http://localhost/archives/aria2-1.0.0.tar.bz2"); httpRequest->setRequest(request); httpResponse.setHttpRequest(std::move(httpRequest)); httpResponse.getHttpHeader()->setStatusCode(206); httpResponse.getHttpHeader()->put(HttpHeader::CONTENT_RANGE, "bytes 0-10485760/10485761"); httpResponse.getHttpHeader()->put(HttpHeader::TRANSFER_ENCODING, "chunked"); // if transfer-encoding is specified, then range validation is skipped. try { httpResponse.validateResponse(); } catch(Exception& e) { CPPUNIT_FAIL("exception must not be thrown."); } } void HttpResponseTest::testValidateResponse_withIfModifiedSince() { HttpResponse httpResponse; httpResponse.setHttpHeader(make_unique()); httpResponse.getHttpHeader()->setStatusCode(304); auto httpRequest = make_unique(); httpResponse.setHttpRequest(std::move(httpRequest)); try { httpResponse.validateResponse(); CPPUNIT_FAIL("exception must be thrown."); } catch(Exception& e) { } httpRequest = make_unique(); httpRequest->setIfModifiedSinceHeader("Fri, 16 Jul 2010 12:56:59 GMT"); httpResponse.setHttpRequest(std::move(httpRequest)); httpResponse.validateResponse(); } void HttpResponseTest::testProcessRedirect() { HttpResponse httpResponse; httpResponse.setHttpHeader(make_unique()); auto httpRequest = make_unique(); auto request = std::make_shared(); request->setUri("http://localhost/archives/aria2-1.0.0.tar.bz2"); httpRequest->setRequest(request); httpResponse.setHttpRequest(std::move(httpRequest)); httpResponse.getHttpHeader()->put(HttpHeader::LOCATION, "http://mirror/aria2-1.0.0.tar.bz2"); httpResponse.processRedirect(); httpResponse.getHttpHeader()->clearField(); // Test for percent-encode httpResponse.getHttpHeader()->put(HttpHeader::LOCATION, "http://example.org/white space#aria2"); httpResponse.processRedirect(); CPPUNIT_ASSERT_EQUAL(std::string("http://example.org/white%20space"), request->getCurrentUri()); httpResponse.getHttpHeader()->clearField(); // Give unsupported scheme httpResponse.getHttpHeader()->put (HttpHeader::LOCATION, "unsupported://mirror/aria2-1.0.0.tar.bz2"); try { httpResponse.processRedirect(); CPPUNIT_FAIL("DlRetryEx exception must be thrown."); } catch(DlRetryEx& e) { // Success } catch(...) { CPPUNIT_FAIL("DlRetryEx exception must be thrown."); } } void HttpResponseTest::testRetrieveCookie() { HttpResponse httpResponse; httpResponse.setHttpHeader(make_unique()); auto httpRequest = make_unique(); auto request = std::make_shared(); request->setUri("http://www.aria2.org/archives/aria2-1.0.0.tar.bz2"); httpRequest->setRequest(request); CookieStorage st; httpRequest->setCookieStorage(&st); httpResponse.setHttpRequest(std::move(httpRequest)); httpResponse.getHttpHeader()->put (HttpHeader::SET_COOKIE, "k1=v1; expires=Sun, 10-Jun-2007 11:00:00 GMT;" "path=/; domain=.aria2.org;"); httpResponse.getHttpHeader()->put (HttpHeader::SET_COOKIE, "k2=v2; expires=Sun, 01-Jan-38 00:00:00 GMT;" "path=/; domain=.aria2.org;"); httpResponse.getHttpHeader()->put(HttpHeader::SET_COOKIE, "k3=v3;"); httpResponse.retrieveCookie(); CPPUNIT_ASSERT_EQUAL((size_t)2, st.size()); auto cookies = std::vector{}; st.dumpCookie(std::back_inserter(cookies)); std::sort(std::begin(cookies), std::end(cookies), CookieSorter()); CPPUNIT_ASSERT_EQUAL(std::string("k2=v2"), cookies[0]->toString()); CPPUNIT_ASSERT_EQUAL(std::string("k3=v3"), cookies[1]->toString()); } void HttpResponseTest::testSupportsPersistentConnection() { HttpResponse httpResponse; httpResponse.setHttpHeader(make_unique()); httpResponse.setHttpRequest(make_unique()); httpResponse.getHttpHeader()->setVersion("HTTP/1.1"); CPPUNIT_ASSERT(httpResponse.supportsPersistentConnection()); httpResponse.getHttpHeader()->put(HttpHeader::CONNECTION, "close"); CPPUNIT_ASSERT(!httpResponse.supportsPersistentConnection()); httpResponse.getHttpHeader()->clearField(); httpResponse.getHttpHeader()->put(HttpHeader::CONNECTION, "keep-alive"); CPPUNIT_ASSERT(httpResponse.supportsPersistentConnection()); httpResponse.getHttpHeader()->clearField(); httpResponse.getHttpHeader()->setVersion("HTTP/1.0"); CPPUNIT_ASSERT(!httpResponse.supportsPersistentConnection()); httpResponse.getHttpHeader()->put(HttpHeader::CONNECTION, "close"); CPPUNIT_ASSERT(!httpResponse.supportsPersistentConnection()); httpResponse.getHttpHeader()->clearField(); httpResponse.getHttpHeader()->put(HttpHeader::CONNECTION, "keep-alive"); CPPUNIT_ASSERT(httpResponse.supportsPersistentConnection()); httpResponse.getHttpHeader()->clearField(); // test proxy connection auto httpRequest = make_unique(); httpRequest->setProxyRequest(std::make_shared()); httpResponse.setHttpRequest(std::move(httpRequest)); httpResponse.getHttpHeader()->setVersion("HTTP/1.1"); CPPUNIT_ASSERT(httpResponse.supportsPersistentConnection()); httpResponse.getHttpHeader()->put(HttpHeader::CONNECTION, "close"); CPPUNIT_ASSERT(!httpResponse.supportsPersistentConnection()); httpResponse.getHttpHeader()->clearField(); httpResponse.getHttpHeader()->put(HttpHeader::CONNECTION, "keep-alive"); CPPUNIT_ASSERT(httpResponse.supportsPersistentConnection()); httpResponse.getHttpHeader()->clearField(); httpResponse.getHttpHeader()->setVersion("HTTP/1.0"); CPPUNIT_ASSERT(!httpResponse.supportsPersistentConnection()); httpResponse.getHttpHeader()->put(HttpHeader::CONNECTION, "close"); CPPUNIT_ASSERT(!httpResponse.supportsPersistentConnection()); httpResponse.getHttpHeader()->clearField(); httpResponse.getHttpHeader()->put(HttpHeader::CONNECTION, "keep-alive"); CPPUNIT_ASSERT(httpResponse.supportsPersistentConnection()); httpResponse.getHttpHeader()->clearField(); } void HttpResponseTest::testGetMetalinKHttpEntries() { HttpResponse httpResponse; httpResponse.setHttpHeader(make_unique()); std::shared_ptr