/** * @file test_httprequest.hpp * @brief unit tests for the LLCore::HttpRequest class * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #ifndef TEST_LLCORE_HTTP_REQUEST_H_ #define TEST_LLCORE_HTTP_REQUEST_H_ #include "httprequest.h" #include "bufferarray.h" #include "httphandler.h" #include "httpheaders.h" #include "httpresponse.h" #include "httpoptions.h" #include "_httpservice.h" #include "_httprequestqueue.h" #include #include #include #include "test_allocator.h" #include "llcorehttp_test.h" using namespace LLCoreInt; namespace { #if defined(WIN32) void usleep(unsigned long usec); #endif } namespace tut { struct HttpRequestTestData { // the test objects inherit from this so the member functions and variables // can be referenced directly inside of the test functions. size_t mMemTotal; int mHandlerCalls; HttpStatus mStatus; }; class TestHandler2 : public LLCore::HttpHandler { public: TestHandler2(HttpRequestTestData * state, const std::string & name) : mState(state), mName(name), mExpectHandle(LLCORE_HTTP_HANDLE_INVALID) {} virtual void onCompleted(HttpHandle handle, HttpResponse * response) { if (LLCORE_HTTP_HANDLE_INVALID != mExpectHandle) { ensure("Expected handle received in handler", mExpectHandle == handle); } ensure("Handler got a response", NULL != response); if (response && mState) { const HttpStatus actual_status(response->getStatus()); std::ostringstream test; test << "Expected HttpStatus received in response. Wanted: " << mState->mStatus.toHex() << " Received: " << actual_status.toHex(); ensure(test.str().c_str(), actual_status == mState->mStatus); } if (mState) { mState->mHandlerCalls++; } if (! mHeadersRequired.empty() || ! mHeadersDisallowed.empty()) { ensure("Response required with header check", response != NULL); HttpHeaders * header(response->getHeaders()); // Will not hold onto this ensure("Some quantity of headers returned", header != NULL); if (! mHeadersRequired.empty()) { for (int i(0); i < mHeadersRequired.size(); ++i) { bool found = false; for (HttpHeaders::container_t::const_iterator iter(header->mHeaders.begin()); header->mHeaders.end() != iter; ++iter) { if (boost::regex_match(*iter, mHeadersRequired[i])) { found = true; break; } } std::ostringstream str; str << "Required header # " << i << " found in response"; ensure(str.str(), found); } } if (! mHeadersDisallowed.empty()) { for (int i(0); i < mHeadersDisallowed.size(); ++i) { for (HttpHeaders::container_t::const_iterator iter(header->mHeaders.begin()); header->mHeaders.end() != iter; ++iter) { if (boost::regex_match(*iter, mHeadersDisallowed[i])) { std::ostringstream str; str << "Disallowed header # " << i << " not found in response"; ensure(str.str(), false); } } } } } if (! mCheckContentType.empty()) { ensure("Response required with content type check", response != NULL); std::string con_type(response->getContentType()); ensure("Content-Type as expected (" + mCheckContentType + ")", mCheckContentType == con_type); } // std::cout << "TestHandler2::onCompleted() invoked" << std::endl; } HttpRequestTestData * mState; std::string mName; HttpHandle mExpectHandle; std::string mCheckContentType; std::vector mHeadersRequired; std::vector mHeadersDisallowed; }; typedef test_group HttpRequestTestGroupType; typedef HttpRequestTestGroupType::object HttpRequestTestObjectType; HttpRequestTestGroupType HttpRequestTestGroup("HttpRequest Tests"); template <> template <> void HttpRequestTestObjectType::test<1>() { ScopedCurlInit ready; set_test_name("HttpRequest construction"); HttpRequest * req = NULL; // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); try { // Get singletons created HttpRequest::createService(); // create a new ref counted object with an implicit reference req = new HttpRequest(); ensure("Memory being used", mMemTotal < GetMemTotal()); // release the request object delete req; req = NULL; HttpRequest::destroyService(); // make sure we didn't leak any memory ensure("Memory returned", mMemTotal == GetMemTotal()); } catch (...) { delete req; HttpRequest::destroyService(); throw; } } template <> template <> void HttpRequestTestObjectType::test<2>() { ScopedCurlInit ready; set_test_name("HttpRequest and Null Op queued"); HttpRequest * req = NULL; // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); try { // Get singletons created HttpRequest::createService(); // create a new ref counted object with an implicit reference req = new HttpRequest(); ensure("Memory being used", mMemTotal < GetMemTotal()); // Issue a NoOp HttpHandle handle = req->requestNoOp(NULL); ensure("Request issued", handle != LLCORE_HTTP_HANDLE_INVALID); // release the request object delete req; req = NULL; // We're still holding onto the operation which is // sitting, unserviced, on the request queue so... ensure("Memory being used 2", mMemTotal < GetMemTotal()); // Request queue should have two references: global singleton & service object ensure("Two references to request queue", 2 == HttpRequestQueue::instanceOf()->getRefCount()); // Okay, tear it down HttpRequest::destroyService(); // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); ensure("Memory returned", mMemTotal == GetMemTotal()); } catch (...) { stop_thread(req); delete req; HttpRequest::destroyService(); throw; } } template <> template <> void HttpRequestTestObjectType::test<3>() { ScopedCurlInit ready; set_test_name("HttpRequest NoOp + Stop execution"); // Handler can be stack-allocated *if* there are no dangling // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; try { // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant // over the test. HttpRequest::startThread(); // create a new ref counted object with an implicit reference req = new HttpRequest(); ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); // Issue a NoOp HttpHandle handle = req->requestNoOp(&handler); ensure("Valid handle returned for first request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. int count(0); int limit(20); while (count++ < limit && mHandlerCalls < 1) { req->update(1000000); usleep(100000); } ensure("Request executed in reasonable time", count < limit); ensure("One handler invocation for request", mHandlerCalls == 1); // Okay, request a shutdown of the servicing thread handle = req->requestStopThread(&handler); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again count = 0; limit = 100; while (count++ < limit && mHandlerCalls < 2) { req->update(1000000); usleep(100000); } ensure("Second request executed in reasonable time", count < limit); ensure("Second handler invocation", mHandlerCalls == 2); // See that we actually shutdown the thread count = 0; limit = 10; while (count++ < limit && ! HttpService::isStopped()) { usleep(100000); } ensure("Thread actually stopped running", HttpService::isStopped()); // release the request object delete req; req = NULL; // Shut down service HttpRequest::destroyService(); ensure("Two handler calls on the way out", 2 == mHandlerCalls); // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); } catch (...) { stop_thread(req); delete req; HttpRequest::destroyService(); throw; } } template <> template <> void HttpRequestTestObjectType::test<4>() { ScopedCurlInit ready; set_test_name("2 HttpRequest instances, one thread"); // Handler can be stack-allocated *if* there are no dangling // references to it after completion of this method. TestHandler2 handler1(this, "handler1"); TestHandler2 handler2(this, "handler2"); // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req1 = NULL; HttpRequest * req2 = NULL; try { // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant // over the test. HttpRequest::startThread(); // create a new ref counted object with an implicit reference req1 = new HttpRequest(); req2 = new HttpRequest(); ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); // Issue some NoOps HttpHandle handle = req1->requestNoOp(&handler1); ensure("Valid handle returned for first request", handle != LLCORE_HTTP_HANDLE_INVALID); handler1.mExpectHandle = handle; handle = req2->requestNoOp(&handler2); ensure("Valid handle returned for first request", handle != LLCORE_HTTP_HANDLE_INVALID); handler2.mExpectHandle = handle; // Run the notification pump. int count(0); int limit(20); while (count++ < limit && mHandlerCalls < 2) { req1->update(1000000); req2->update(1000000); usleep(100000); } ensure("Request executed in reasonable time", count < limit); ensure("One handler invocation for request", mHandlerCalls == 2); // Okay, request a shutdown of the servicing thread handle = req2->requestStopThread(&handler2); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); handler2.mExpectHandle = handle; // Run the notification pump again count = 0; limit = 100; while (count++ < limit && mHandlerCalls < 3) { req1->update(1000000); req2->update(1000000); usleep(100000); } ensure("Second request executed in reasonable time", count < limit); ensure("Second handler invocation", mHandlerCalls == 3); // See that we actually shutdown the thread count = 0; limit = 10; while (count++ < limit && ! HttpService::isStopped()) { usleep(100000); } ensure("Thread actually stopped running", HttpService::isStopped()); // release the request object delete req1; req1 = NULL; delete req2; req2 = NULL; // Shut down service HttpRequest::destroyService(); ensure("Two handler calls on the way out", 3 == mHandlerCalls); // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); } catch (...) { stop_thread(req1); delete req1; delete req2; HttpRequest::destroyService(); throw; } } template <> template <> void HttpRequestTestObjectType::test<5>() { ScopedCurlInit ready; set_test_name("HttpRequest Spin (soft) + NoOp + hard termination"); // Handler can be stack-allocated *if* there are no dangling // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; try { // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant // over the test. HttpRequest::startThread(); // create a new ref counted object with an implicit reference req = new HttpRequest(); ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); // Issue a Spin HttpHandle handle = req->requestSpin(1); ensure("Valid handle returned for spin request", handle != LLCORE_HTTP_HANDLE_INVALID); // Issue a NoOp handle = req->requestNoOp(&handler); ensure("Valid handle returned for no-op request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. int count(0); int limit(10); while (count++ < limit && mHandlerCalls < 1) { req->update(1000000); usleep(100000); } ensure("NoOp notification received", mHandlerCalls == 1); // release the request object delete req; req = NULL; // Shut down service HttpRequest::destroyService(); // Check memory usage // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); // This memory test should work but could give problems as it // relies on the worker thread picking up a friendly request // to shutdown. Doing so, it drops references to things and // we should go back to where we started. If it gives you // problems, look into the code before commenting things out. } catch (...) { stop_thread(req); delete req; HttpRequest::destroyService(); throw; } } template <> template <> void HttpRequestTestObjectType::test<6>() { ScopedCurlInit ready; set_test_name("HttpRequest Spin + NoOp + hard termination"); // Handler can be stack-allocated *if* there are no dangling // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; try { // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant // over the test. HttpRequest::startThread(); // create a new ref counted object with an implicit reference req = new HttpRequest(); ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); // Issue a Spin HttpHandle handle = req->requestSpin(0); // Hard spin ensure("Valid handle returned for spin request", handle != LLCORE_HTTP_HANDLE_INVALID); // Issue a NoOp handle = req->requestNoOp(&handler); ensure("Valid handle returned for no-op request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. int count(0); int limit(10); while (count++ < limit && mHandlerCalls < 1) { req->update(1000000); usleep(100000); } ensure("No notifications received", mHandlerCalls == 0); // release the request object delete req; req = NULL; // Shut down service HttpRequest::destroyService(); // Check memory usage // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); // ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); // This memory test won't work because we're killing the thread // hard with the hard spinner. There's no opportunity to join // nicely so many things leak or get destroyed unilaterally. } catch (...) { stop_thread(req); delete req; HttpRequest::destroyService(); throw; } } template <> template <> void HttpRequestTestObjectType::test<7>() { ScopedCurlInit ready; set_test_name("HttpRequest GET to dead port + Stop execution"); // Handler can be stack-allocated *if* there are no dangling // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; HttpOptions * opts = NULL; try { // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant // over the test. HttpRequest::startThread(); // create a new ref counted object with an implicit reference req = new HttpRequest(); ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); opts = new HttpOptions(); opts->setRetries(1); // Don't try for too long - default retries take about 18S // Issue a GET that can't connect mStatus = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_CONNECT); HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, 0U, "http://127.0.0.1:2/nothing/here", 0, 0, opts, NULL, &handler); ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. int count(0); int limit(50); // With one retry, should fail quickish while (count++ < limit && mHandlerCalls < 1) { req->update(1000000); usleep(100000); } ensure("Request executed in reasonable time", count < limit); ensure("One handler invocation for request", mHandlerCalls == 1); // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); handle = req->requestStopThread(&handler); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again count = 0; limit = 100; while (count++ < limit && mHandlerCalls < 2) { req->update(1000000); usleep(100000); } ensure("Second request executed in reasonable time", count < limit); ensure("Second handler invocation", mHandlerCalls == 2); // See that we actually shutdown the thread count = 0; limit = 10; while (count++ < limit && ! HttpService::isStopped()) { usleep(100000); } ensure("Thread actually stopped running", HttpService::isStopped()); // release options opts->release(); opts = NULL; // release the request object delete req; req = NULL; // Shut down service HttpRequest::destroyService(); ensure("Two handler calls on the way out", 2 == mHandlerCalls); #if 0 // defined(WIN32) // Can't do this on any platform anymore, the LL logging system holds // on to memory and produces what looks like memory leaks... // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); #endif } catch (...) { stop_thread(req); if (opts) { opts->release(); opts = NULL; } delete req; HttpRequest::destroyService(); throw; } } template <> template <> void HttpRequestTestObjectType::test<8>() { ScopedCurlInit ready; std::string url_base(get_base_url()); // std::cerr << "Base: " << url_base << std::endl; set_test_name("HttpRequest GET to real service"); // Handler can be stack-allocated *if* there are no dangling // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; try { // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant // over the test. HttpRequest::startThread(); // create a new ref counted object with an implicit reference req = new HttpRequest(); ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); // Issue a GET that *can* connect mStatus = HttpStatus(200); HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID, 0U, url_base, NULL, NULL, &handler); ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. int count(0); int limit(10); while (count++ < limit && mHandlerCalls < 1) { req->update(1000000); usleep(100000); } ensure("Request executed in reasonable time", count < limit); ensure("One handler invocation for request", mHandlerCalls == 1); // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); handle = req->requestStopThread(&handler); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again count = 0; limit = 10; while (count++ < limit && mHandlerCalls < 2) { req->update(1000000); usleep(100000); } ensure("Second request executed in reasonable time", count < limit); ensure("Second handler invocation", mHandlerCalls == 2); // See that we actually shutdown the thread count = 0; limit = 10; while (count++ < limit && ! HttpService::isStopped()) { usleep(100000); } ensure("Thread actually stopped running", HttpService::isStopped()); // release the request object delete req; req = NULL; // Shut down service HttpRequest::destroyService(); ensure("Two handler calls on the way out", 2 == mHandlerCalls); #if defined(WIN32) // Can only do this memory test on Windows. On other platforms, // the LL logging system holds on to memory and produces what looks // like memory leaks... // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); #endif } catch (...) { stop_thread(req); delete req; HttpRequest::destroyService(); throw; } } template <> template <> void HttpRequestTestObjectType::test<9>() { ScopedCurlInit ready; std::string url_base(get_base_url()); // std::cerr << "Base: " << url_base << std::endl; set_test_name("HttpRequest GET with Range: header to real service"); // Handler can be stack-allocated *if* there are no dangling // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; try { // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant // over the test. HttpRequest::startThread(); // create a new ref counted object with an implicit reference req = new HttpRequest(); ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); // Issue a GET that *can* connect mStatus = HttpStatus(200); HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, 0U, url_base, 0, 0, NULL, NULL, &handler); ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. int count(0); int limit(10); while (count++ < limit && mHandlerCalls < 1) { req->update(1000000); usleep(100000); } ensure("Request executed in reasonable time", count < limit); ensure("One handler invocation for request", mHandlerCalls == 1); // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); handle = req->requestStopThread(&handler); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again count = 0; limit = 10; while (count++ < limit && mHandlerCalls < 2) { req->update(1000000); usleep(100000); } ensure("Second request executed in reasonable time", count < limit); ensure("Second handler invocation", mHandlerCalls == 2); // See that we actually shutdown the thread count = 0; limit = 10; while (count++ < limit && ! HttpService::isStopped()) { usleep(100000); } ensure("Thread actually stopped running", HttpService::isStopped()); // release the request object delete req; req = NULL; // Shut down service HttpRequest::destroyService(); ensure("Two handler calls on the way out", 2 == mHandlerCalls); #if defined(WIN32) // Can only do this memory test on Windows. On other platforms, // the LL logging system holds on to memory and produces what looks // like memory leaks... // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); #endif } catch (...) { stop_thread(req); delete req; HttpRequest::destroyService(); throw; } } template <> template <> void HttpRequestTestObjectType::test<10>() { ScopedCurlInit ready; std::string url_base(get_base_url()); // std::cerr << "Base: " << url_base << std::endl; set_test_name("HttpRequest PUT to real service"); // Handler can be stack-allocated *if* there are no dangling // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; BufferArray * body = new BufferArray; try { // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant // over the test. HttpRequest::startThread(); // create a new ref counted object with an implicit reference req = new HttpRequest(); ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); // Issue a GET that *can* connect static const char * body_text("Now is the time for all good men..."); body->append(body_text, strlen(body_text)); mStatus = HttpStatus(200); HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID, 0U, url_base, body, NULL, NULL, &handler); ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. int count(0); int limit(10); while (count++ < limit && mHandlerCalls < 1) { req->update(1000000); usleep(100000); } ensure("Request executed in reasonable time", count < limit); ensure("One handler invocation for request", mHandlerCalls == 1); // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); handle = req->requestStopThread(&handler); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again count = 0; limit = 10; while (count++ < limit && mHandlerCalls < 2) { req->update(1000000); usleep(100000); } ensure("Second request executed in reasonable time", count < limit); ensure("Second handler invocation", mHandlerCalls == 2); // See that we actually shutdown the thread count = 0; limit = 10; while (count++ < limit && ! HttpService::isStopped()) { usleep(100000); } ensure("Thread actually stopped running", HttpService::isStopped()); // Lose the request body body->release(); body = NULL; // release the request object delete req; req = NULL; // Shut down service HttpRequest::destroyService(); ensure("Two handler calls on the way out", 2 == mHandlerCalls); #if 0 // defined(WIN32) // Can't do this on any platform anymore, the LL logging system holds // on to memory and produces what looks like memory leaks... // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); #endif } catch (...) { if (body) { body->release(); } stop_thread(req); delete req; HttpRequest::destroyService(); throw; } } template <> template <> void HttpRequestTestObjectType::test<11>() { ScopedCurlInit ready; std::string url_base(get_base_url()); // std::cerr << "Base: " << url_base << std::endl; set_test_name("HttpRequest POST to real service"); // Handler can be stack-allocated *if* there are no dangling // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; BufferArray * body = new BufferArray; try { // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant // over the test. HttpRequest::startThread(); // create a new ref counted object with an implicit reference req = new HttpRequest(); ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); // Issue a GET that *can* connect static const char * body_text("Now is the time for all good men..."); body->append(body_text, strlen(body_text)); mStatus = HttpStatus(200); HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID, 0U, url_base, body, NULL, NULL, &handler); ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. int count(0); int limit(10); while (count++ < limit && mHandlerCalls < 1) { req->update(1000000); usleep(100000); } ensure("Request executed in reasonable time", count < limit); ensure("One handler invocation for request", mHandlerCalls == 1); // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); handle = req->requestStopThread(&handler); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again count = 0; limit = 10; while (count++ < limit && mHandlerCalls < 2) { req->update(1000000); usleep(100000); } ensure("Second request executed in reasonable time", count < limit); ensure("Second handler invocation", mHandlerCalls == 2); // See that we actually shutdown the thread count = 0; limit = 10; while (count++ < limit && ! HttpService::isStopped()) { usleep(100000); } ensure("Thread actually stopped running", HttpService::isStopped()); // Lose the request body body->release(); body = NULL; // release the request object delete req; req = NULL; // Shut down service HttpRequest::destroyService(); ensure("Two handler calls on the way out", 2 == mHandlerCalls); #if defined(WIN32) // Can only do this memory test on Windows. On other platforms, // the LL logging system holds on to memory and produces what looks // like memory leaks... // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); #endif } catch (...) { if (body) { body->release(); } stop_thread(req); delete req; HttpRequest::destroyService(); throw; } } template <> template <> void HttpRequestTestObjectType::test<12>() { ScopedCurlInit ready; std::string url_base(get_base_url()); // std::cerr << "Base: " << url_base << std::endl; set_test_name("HttpRequest GET with some tracing"); // Handler can be stack-allocated *if* there are no dangling // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; try { // Get singletons created HttpRequest::createService(); // Enable tracing HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_TRACE, 2); // Start threading early so that thread memory is invariant // over the test. HttpRequest::startThread(); // create a new ref counted object with an implicit reference req = new HttpRequest(); ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); // Issue a GET that *can* connect mStatus = HttpStatus(200); HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, 0U, url_base, 0, 0, NULL, NULL, &handler); ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. int count(0); int limit(10); while (count++ < limit && mHandlerCalls < 1) { req->update(1000000); usleep(100000); } ensure("Request executed in reasonable time", count < limit); ensure("One handler invocation for request", mHandlerCalls == 1); // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); handle = req->requestStopThread(&handler); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again count = 0; limit = 10; while (count++ < limit && mHandlerCalls < 2) { req->update(1000000); usleep(100000); } ensure("Second request executed in reasonable time", count < limit); ensure("Second handler invocation", mHandlerCalls == 2); // See that we actually shutdown the thread count = 0; limit = 10; while (count++ < limit && ! HttpService::isStopped()) { usleep(100000); } ensure("Thread actually stopped running", HttpService::isStopped()); // release the request object delete req; req = NULL; // Shut down service HttpRequest::destroyService(); ensure("Two handler calls on the way out", 2 == mHandlerCalls); #if 0 // defined(WIN32) // Can't do this on any platform anymore, the LL logging system holds // on to memory and produces what looks like memory leaks... // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); #endif } catch (...) { stop_thread(req); delete req; HttpRequest::destroyService(); throw; } } template <> template <> void HttpRequestTestObjectType::test<13>() { ScopedCurlInit ready; // Warmup boost::regex to pre-alloc memory for memory size tests boost::regex warmup("askldjflasdj;f", boost::regex::icase); boost::regex_match("akl;sjflajfk;ajsk", warmup); std::string url_base(get_base_url()); // std::cerr << "Base: " << url_base << std::endl; set_test_name("HttpRequest GET with returned headers"); // Handler can be stack-allocated *if* there are no dangling // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); handler.mHeadersRequired.reserve(20); // Avoid memory leak test failure // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; HttpOptions * opts = NULL; try { // Get singletons created HttpRequest::createService(); // Enable tracing HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_TRACE, 2); // Start threading early so that thread memory is invariant // over the test. HttpRequest::startThread(); // create a new ref counted object with an implicit reference req = new HttpRequest(); ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); opts = new HttpOptions(); opts->setWantHeaders(true); // Issue a GET that succeeds mStatus = HttpStatus(200); handler.mHeadersRequired.push_back(boost::regex("\\W*X-LL-Special:.*", boost::regex::icase)); HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, 0U, url_base, 0, 0, opts, NULL, &handler); ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); // release options opts->release(); opts = NULL; // Run the notification pump. int count(0); int limit(10); while (count++ < limit && mHandlerCalls < 1) { req->update(1000000); usleep(100000); } ensure("Request executed in reasonable time", count < limit); ensure("One handler invocation for request", mHandlerCalls == 1); // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); handler.mHeadersRequired.clear(); handle = req->requestStopThread(&handler); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again count = 0; limit = 10; while (count++ < limit && mHandlerCalls < 2) { req->update(1000000); usleep(100000); } ensure("Second request executed in reasonable time", count < limit); ensure("Second handler invocation", mHandlerCalls == 2); // See that we actually shutdown the thread count = 0; limit = 10; while (count++ < limit && ! HttpService::isStopped()) { usleep(100000); } ensure("Thread actually stopped running", HttpService::isStopped()); // release the request object delete req; req = NULL; // Shut down service HttpRequest::destroyService(); ensure("Two handler calls on the way out", 2 == mHandlerCalls); #if defined(WIN32) // Can only do this memory test on Windows. On other platforms, // the LL logging system holds on to memory and produces what looks // like memory leaks... // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); #endif } catch (...) { stop_thread(req); if (opts) { opts->release(); opts = NULL; } delete req; HttpRequest::destroyService(); throw; } } template <> template <> void HttpRequestTestObjectType::test<14>() { ScopedCurlInit ready; set_test_name("HttpRequest GET timeout"); // Handler can be stack-allocated *if* there are no dangling // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); std::string url_base(get_base_url() + "/sleep/"); // path to a 30-second sleep // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; HttpOptions * opts = NULL; try { // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant // over the test. HttpRequest::startThread(); // create a new ref counted object with an implicit reference req = new HttpRequest(); ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); opts = new HttpOptions(); opts->setRetries(0); // Don't retry opts->setTimeout(2); // Issue a GET that sleeps mStatus = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_OPERATION_TIMEDOUT); HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, 0U, url_base, 0, 0, opts, NULL, &handler); ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. int count(0); int limit(50); // With one retry, should fail quickish while (count++ < limit && mHandlerCalls < 1) { req->update(1000000); usleep(100000); } ensure("Request executed in reasonable time", count < limit); ensure("One handler invocation for request", mHandlerCalls == 1); // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); handle = req->requestStopThread(&handler); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again count = 0; limit = 100; while (count++ < limit && mHandlerCalls < 2) { req->update(1000000); usleep(100000); } ensure("Second request executed in reasonable time", count < limit); ensure("Second handler invocation", mHandlerCalls == 2); // See that we actually shutdown the thread count = 0; limit = 10; while (count++ < limit && ! HttpService::isStopped()) { usleep(100000); } ensure("Thread actually stopped running", HttpService::isStopped()); // release options opts->release(); opts = NULL; // release the request object delete req; req = NULL; // Shut down service HttpRequest::destroyService(); ensure("Two handler calls on the way out", 2 == mHandlerCalls); #if defined(WIN32) // Can only do this memory test on Windows. On other platforms, // the LL logging system holds on to memory and produces what looks // like memory leaks... // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); #endif } catch (...) { stop_thread(req); if (opts) { opts->release(); opts = NULL; } delete req; HttpRequest::destroyService(); throw; } } // Test retrieval of Content-Type/Content-Encoding headers template <> template <> void HttpRequestTestObjectType::test<15>() { ScopedCurlInit ready; std::string url_base(get_base_url()); // std::cerr << "Base: " << url_base << std::endl; set_test_name("HttpRequest GET with Content-Type"); // Handler can be stack-allocated *if* there are no dangling // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); // Load and clear the string setting to preload std::string object // for memory return tests. handler.mCheckContentType = "application/llsd+xml"; handler.mCheckContentType.clear(); // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; try { // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant // over the test. HttpRequest::startThread(); // create a new ref counted object with an implicit reference req = new HttpRequest(); ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); // Issue a GET that *can* connect mStatus = HttpStatus(200); handler.mCheckContentType = "application/llsd+xml"; HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID, 0U, url_base, NULL, NULL, &handler); ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. int count(0); int limit(10); while (count++ < limit && mHandlerCalls < 1) { req->update(1000000); usleep(100000); } ensure("Request executed in reasonable time", count < limit); ensure("One handler invocation for request", mHandlerCalls == 1); // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); handler.mCheckContentType.clear(); handle = req->requestStopThread(&handler); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again count = 0; limit = 10; while (count++ < limit && mHandlerCalls < 2) { req->update(1000000); usleep(100000); } ensure("Second request executed in reasonable time", count < limit); ensure("Second handler invocation", mHandlerCalls == 2); // See that we actually shutdown the thread count = 0; limit = 10; while (count++ < limit && ! HttpService::isStopped()) { usleep(100000); } ensure("Thread actually stopped running", HttpService::isStopped()); // release the request object delete req; req = NULL; // Shut down service HttpRequest::destroyService(); ensure("Two handler calls on the way out", 2 == mHandlerCalls); #if defined(WIN32) // Can only do this memory test on Windows. On other platforms, // the LL logging system holds on to memory and produces what looks // like memory leaks... // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal()); ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); #endif } catch (...) { stop_thread(req); delete req; HttpRequest::destroyService(); throw; } } // Test header generation on GET requests template <> template <> void HttpRequestTestObjectType::test<16>() { ScopedCurlInit ready; // Warmup boost::regex to pre-alloc memory for memory size tests boost::regex warmup("askldjflasdj;f", boost::regex::icase); boost::regex_match("akl;sjflajfk;ajsk", warmup); std::string url_base(get_base_url()); set_test_name("Header generation for HttpRequest GET"); // Handler can be stack-allocated *if* there are no dangling // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; HttpOptions * options = NULL; HttpHeaders * headers = NULL; try { // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant // over the test. HttpRequest::startThread(); // create a new ref counted object with an implicit reference req = new HttpRequest(); // options set options = new HttpOptions(); options->setWantHeaders(true); // Issue a GET that *can* connect mStatus = HttpStatus(200); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*\\d+", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-type:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase)); HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID, 0U, url_base + "reflect/", options, NULL, &handler); ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. int count(0); int limit(10); while (count++ < limit && mHandlerCalls < 1) { req->update(1000000); usleep(100000); } ensure("Request executed in reasonable time", count < limit); ensure("One handler invocation for request", mHandlerCalls == 1); // Do a texture-style fetch headers = new HttpHeaders; headers->mHeaders.push_back("Accept: image/x-j2c"); mStatus = HttpStatus(200); handler.mHeadersRequired.clear(); handler.mHeadersDisallowed.clear(); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*image/x-j2c", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*\\d+", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("\\W*X-Reflect-range:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-type:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase)); handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, 0U, url_base + "reflect/", 0, 47, options, headers, &handler); ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. count = 0; limit = 10; while (count++ < limit && mHandlerCalls < 2) { req->update(1000000); usleep(100000); } ensure("Request executed in reasonable time", count < limit); ensure("One handler invocation for request", mHandlerCalls == 2); // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); handler.mHeadersRequired.clear(); handler.mHeadersDisallowed.clear(); handle = req->requestStopThread(&handler); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again count = 0; limit = 10; while (count++ < limit && mHandlerCalls < 3) { req->update(1000000); usleep(100000); } ensure("Second request executed in reasonable time", count < limit); ensure("Second handler invocation", mHandlerCalls == 3); // See that we actually shutdown the thread count = 0; limit = 10; while (count++ < limit && ! HttpService::isStopped()) { usleep(100000); } ensure("Thread actually stopped running", HttpService::isStopped()); // release options & headers if (options) { options->release(); } options = NULL; if (headers) { headers->release(); } headers = NULL; // release the request object delete req; req = NULL; // Shut down service HttpRequest::destroyService(); } catch (...) { stop_thread(req); if (options) { options->release(); options = NULL; } if (headers) { headers->release(); headers = NULL; } delete req; HttpRequest::destroyService(); throw; } } // Test header generation on POST requests template <> template <> void HttpRequestTestObjectType::test<17>() { ScopedCurlInit ready; // Warmup boost::regex to pre-alloc memory for memory size tests boost::regex warmup("askldjflasdj;f", boost::regex::icase); boost::regex_match("akl;sjflajfk;ajsk", warmup); std::string url_base(get_base_url()); set_test_name("Header generation for HttpRequest POST"); // Handler can be stack-allocated *if* there are no dangling // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; HttpOptions * options = NULL; HttpHeaders * headers = NULL; BufferArray * ba = NULL; try { // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant // over the test. HttpRequest::startThread(); // create a new ref counted object with an implicit reference req = new HttpRequest(); // options set options = new HttpOptions(); options->setWantHeaders(true); // And a buffer array const char * msg("It was the best of times, it was the worst of times."); ba = new BufferArray; ba->append(msg, strlen(msg)); // Issue a default POST mStatus = HttpStatus(200); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*\\d+", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-length:\\s*\\d+", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-type:\\s*application/x-www-form-urlencoded", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-expect:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:\\s*.*chunked.*", boost::regex::icase)); HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID, 0U, url_base + "reflect/", ba, options, NULL, &handler); ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); ba->release(); ba = NULL; // Run the notification pump. int count(0); int limit(10); while (count++ < limit && mHandlerCalls < 1) { req->update(1000000); usleep(100000); } ensure("Request executed in reasonable time", count < limit); ensure("One handler invocation for request", mHandlerCalls == 1); // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); handler.mHeadersRequired.clear(); handler.mHeadersDisallowed.clear(); handle = req->requestStopThread(&handler); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again count = 0; limit = 10; while (count++ < limit && mHandlerCalls < 2) { req->update(1000000); usleep(100000); } ensure("Second request executed in reasonable time", count < limit); ensure("Second handler invocation", mHandlerCalls == 2); // See that we actually shutdown the thread count = 0; limit = 10; while (count++ < limit && ! HttpService::isStopped()) { usleep(100000); } ensure("Thread actually stopped running", HttpService::isStopped()); // release options & headers if (options) { options->release(); } options = NULL; if (headers) { headers->release(); } headers = NULL; // release the request object delete req; req = NULL; // Shut down service HttpRequest::destroyService(); } catch (...) { stop_thread(req); if (ba) { ba->release(); ba = NULL; } if (options) { options->release(); options = NULL; } if (headers) { headers->release(); headers = NULL; } delete req; HttpRequest::destroyService(); throw; } } // Test header generation on PUT requests template <> template <> void HttpRequestTestObjectType::test<18>() { ScopedCurlInit ready; // Warmup boost::regex to pre-alloc memory for memory size tests boost::regex warmup("askldjflasdj;f", boost::regex::icase); boost::regex_match("akl;sjflajfk;ajsk", warmup); std::string url_base(get_base_url()); set_test_name("Header generation for HttpRequest PUT"); // Handler can be stack-allocated *if* there are no dangling // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; HttpOptions * options = NULL; HttpHeaders * headers = NULL; BufferArray * ba = NULL; try { // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant // over the test. HttpRequest::startThread(); // create a new ref counted object with an implicit reference req = new HttpRequest(); // options set options = new HttpOptions(); options->setWantHeaders(true); // And a buffer array const char * msg("It was the best of times, it was the worst of times."); ba = new BufferArray; ba->append(msg, strlen(msg)); // Issue a default PUT mStatus = HttpStatus(200); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*\\d+", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-length:\\s*\\d+", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-expect:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:\\s*.*chunked.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-content-type:.*", boost::regex::icase)); HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID, 0U, url_base + "reflect/", ba, options, NULL, &handler); ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); ba->release(); ba = NULL; // Run the notification pump. int count(0); int limit(10); while (count++ < limit && mHandlerCalls < 1) { req->update(1000000); usleep(100000); } ensure("Request executed in reasonable time", count < limit); ensure("One handler invocation for request", mHandlerCalls == 1); // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); handler.mHeadersRequired.clear(); handler.mHeadersDisallowed.clear(); handle = req->requestStopThread(&handler); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again count = 0; limit = 10; while (count++ < limit && mHandlerCalls < 2) { req->update(1000000); usleep(100000); } ensure("Second request executed in reasonable time", count < limit); ensure("Second handler invocation", mHandlerCalls == 2); // See that we actually shutdown the thread count = 0; limit = 10; while (count++ < limit && ! HttpService::isStopped()) { usleep(100000); } ensure("Thread actually stopped running", HttpService::isStopped()); // release options & headers if (options) { options->release(); } options = NULL; if (headers) { headers->release(); } headers = NULL; // release the request object delete req; req = NULL; // Shut down service HttpRequest::destroyService(); } catch (...) { stop_thread(req); if (ba) { ba->release(); ba = NULL; } if (options) { options->release(); options = NULL; } if (headers) { headers->release(); headers = NULL; } delete req; HttpRequest::destroyService(); throw; } } // Test header generation on GET requests with overrides template <> template <> void HttpRequestTestObjectType::test<19>() { ScopedCurlInit ready; // Warmup boost::regex to pre-alloc memory for memory size tests boost::regex warmup("askldjflasdj;f", boost::regex::icase); boost::regex_match("akl;sjflajfk;ajsk", warmup); std::string url_base(get_base_url()); set_test_name("Header generation for HttpRequest GET with header overrides"); // Handler can be stack-allocated *if* there are no dangling // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; HttpOptions * options = NULL; HttpHeaders * headers = NULL; try { // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant // over the test. HttpRequest::startThread(); // create a new ref counted object with an implicit reference req = new HttpRequest(); // options set options = new HttpOptions(); options->setWantHeaders(true); // headers headers = new HttpHeaders; headers->mHeaders.push_back("Keep-Alive: 120"); headers->mHeaders.push_back("Accept-encoding: deflate"); headers->mHeaders.push_back("Accept: text/plain"); // Issue a GET with modified headers mStatus = HttpStatus(200); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*text/plain", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*deflate", boost::regex::icase)); // close enough handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*120", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-keep-alive:\\s*300", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-type:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase)); HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID, 0U, url_base + "reflect/", options, headers, &handler); ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. int count(0); int limit(10); while (count++ < limit && mHandlerCalls < 1) { req->update(1000000); usleep(100000); } ensure("Request executed in reasonable time", count < limit); ensure("One handler invocation for request", mHandlerCalls == 1); // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); handler.mHeadersRequired.clear(); handler.mHeadersDisallowed.clear(); handle = req->requestStopThread(&handler); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again count = 0; limit = 10; while (count++ < limit && mHandlerCalls < 2) { req->update(1000000); usleep(100000); } ensure("Second request executed in reasonable time", count < limit); ensure("Second handler invocation", mHandlerCalls == 2); // See that we actually shutdown the thread count = 0; limit = 10; while (count++ < limit && ! HttpService::isStopped()) { usleep(100000); } ensure("Thread actually stopped running", HttpService::isStopped()); // release options & headers if (options) { options->release(); } options = NULL; if (headers) { headers->release(); } headers = NULL; // release the request object delete req; req = NULL; // Shut down service HttpRequest::destroyService(); } catch (...) { stop_thread(req); if (options) { options->release(); options = NULL; } if (headers) { headers->release(); headers = NULL; } delete req; HttpRequest::destroyService(); throw; } } // Test header generation on POST requests with overrides template <> template <> void HttpRequestTestObjectType::test<20>() { ScopedCurlInit ready; // Warmup boost::regex to pre-alloc memory for memory size tests boost::regex warmup("askldjflasdj;f", boost::regex::icase); boost::regex_match("akl;sjflajfk;ajsk", warmup); std::string url_base(get_base_url()); set_test_name("Header generation for HttpRequest POST with header overrides"); // Handler can be stack-allocated *if* there are no dangling // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; HttpOptions * options = NULL; HttpHeaders * headers = NULL; BufferArray * ba = NULL; try { // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant // over the test. HttpRequest::startThread(); // create a new ref counted object with an implicit reference req = new HttpRequest(); // options set options = new HttpOptions(); options->setWantHeaders(true); // headers headers = new HttpHeaders(); headers->mHeaders.push_back("keep-Alive: 120"); headers->mHeaders.push_back("Accept: text/html"); headers->mHeaders.push_back("content-type: application/llsd+xml"); headers->mHeaders.push_back("cache-control: no-store"); // And a buffer array const char * msg("It was the best of times, it was the worst of times."); ba = new BufferArray; ba->append(msg, strlen(msg)); // Issue a default POST mStatus = HttpStatus(200); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*text/html", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*120", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-length:\\s*\\d+", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-type:\\s*application/llsd\\+xml", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("\\s*X-Reflect-cache-control:\\s*no-store", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-content-type:\\s*application/x-www-form-urlencoded", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-keep-alive:\\s*300", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-expect:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:\\s*.*chunked.*", boost::regex::icase)); HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID, 0U, url_base + "reflect/", ba, options, headers, &handler); ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); ba->release(); ba = NULL; // Run the notification pump. int count(0); int limit(10); while (count++ < limit && mHandlerCalls < 1) { req->update(1000000); usleep(100000); } ensure("Request executed in reasonable time", count < limit); ensure("One handler invocation for request", mHandlerCalls == 1); // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); handler.mHeadersRequired.clear(); handler.mHeadersDisallowed.clear(); handle = req->requestStopThread(&handler); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again count = 0; limit = 10; while (count++ < limit && mHandlerCalls < 2) { req->update(1000000); usleep(100000); } ensure("Second request executed in reasonable time", count < limit); ensure("Second handler invocation", mHandlerCalls == 2); // See that we actually shutdown the thread count = 0; limit = 10; while (count++ < limit && ! HttpService::isStopped()) { usleep(100000); } ensure("Thread actually stopped running", HttpService::isStopped()); // release options & headers if (options) { options->release(); } options = NULL; if (headers) { headers->release(); } headers = NULL; // release the request object delete req; req = NULL; // Shut down service HttpRequest::destroyService(); } catch (...) { stop_thread(req); if (ba) { ba->release(); ba = NULL; } if (options) { options->release(); options = NULL; } if (headers) { headers->release(); headers = NULL; } delete req; HttpRequest::destroyService(); throw; } } // Test header generation on PUT requests with overrides template <> template <> void HttpRequestTestObjectType::test<21>() { ScopedCurlInit ready; // Warmup boost::regex to pre-alloc memory for memory size tests boost::regex warmup("askldjflasdj;f", boost::regex::icase); boost::regex_match("akl;sjflajfk;ajsk", warmup); std::string url_base(get_base_url()); set_test_name("Header generation for HttpRequest PUT with header overrides"); // Handler can be stack-allocated *if* there are no dangling // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; HttpOptions * options = NULL; HttpHeaders * headers = NULL; BufferArray * ba = NULL; try { // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant // over the test. HttpRequest::startThread(); // create a new ref counted object with an implicit reference req = new HttpRequest(); // options set options = new HttpOptions(); options->setWantHeaders(true); // headers headers = new HttpHeaders; headers->mHeaders.push_back("content-type: text/plain"); headers->mHeaders.push_back("content-type: text/html"); headers->mHeaders.push_back("content-type: application/llsd+xml"); // And a buffer array const char * msg("It was the best of times, it was the worst of times."); ba = new BufferArray; ba->append(msg, strlen(msg)); // Issue a default PUT mStatus = HttpStatus(200); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*\\d+", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-length:\\s*\\d+", boost::regex::icase)); handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-type:\\s*application/llsd\\+xml", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-expect:.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:\\s*.*chunked.*", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-content-type:\\s*text/plain", boost::regex::icase)); handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-content-type:\\s*text/html", boost::regex::icase)); HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID, 0U, url_base + "reflect/", ba, options, headers, &handler); ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); ba->release(); ba = NULL; // Run the notification pump. int count(0); int limit(10); while (count++ < limit && mHandlerCalls < 1) { req->update(1000000); usleep(100000); } ensure("Request executed in reasonable time", count < limit); ensure("One handler invocation for request", mHandlerCalls == 1); // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); handler.mHeadersRequired.clear(); handler.mHeadersDisallowed.clear(); handle = req->requestStopThread(&handler); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again count = 0; limit = 10; while (count++ < limit && mHandlerCalls < 2) { req->update(1000000); usleep(100000); } ensure("Second request executed in reasonable time", count < limit); ensure("Second handler invocation", mHandlerCalls == 2); // See that we actually shutdown the thread count = 0; limit = 10; while (count++ < limit && ! HttpService::isStopped()) { usleep(100000); } ensure("Thread actually stopped running", HttpService::isStopped()); // release options & headers if (options) { options->release(); } options = NULL; if (headers) { headers->release(); } headers = NULL; // release the request object delete req; req = NULL; // Shut down service HttpRequest::destroyService(); } catch (...) { stop_thread(req); if (ba) { ba->release(); ba = NULL; } if (options) { options->release(); options = NULL; } if (headers) { headers->release(); headers = NULL; } delete req; HttpRequest::destroyService(); throw; } } } // end namespace tut namespace { #if defined(WIN32) void usleep(unsigned long usec) { Sleep((DWORD) (usec / 1000UL)); } #endif } #endif // TEST_LLCORE_HTTP_REQUEST_H_