diff options
author | Glenn Glazer <coyot@lindenlab.com> | 2016-04-07 12:10:13 -0700 |
---|---|---|
committer | Glenn Glazer <coyot@lindenlab.com> | 2016-04-07 12:10:13 -0700 |
commit | 369cefd5b3f2f52ae0dd203fcd45a4618f74b0f3 (patch) | |
tree | 941d27a32099abaf71bae8a2865002e2b25a3512 /indra/llcorehttp | |
parent | 0494a502aafac73800352dc26c4eb3a27b02a8ce (diff) | |
parent | 18928ea6c6f2830a0d45ec412c915eceff1b76b0 (diff) |
pull from viewer-release
Diffstat (limited to 'indra/llcorehttp')
45 files changed, 2279 insertions, 983 deletions
diff --git a/indra/llcorehttp/CMakeLists.txt b/indra/llcorehttp/CMakeLists.txt index a0b1ea13b1..0bb0348d26 100755 --- a/indra/llcorehttp/CMakeLists.txt +++ b/indra/llcorehttp/CMakeLists.txt @@ -5,7 +5,6 @@ project(llcorehttp) include(00-Common) include(GoogleMock) include(CURL) -include(CARes) include(OpenSSL) include(ZLIB) include(LLCoreHttp) @@ -26,6 +25,7 @@ set(llcorehttp_SOURCE_FILES bufferarray.cpp bufferstream.cpp httpcommon.cpp + llhttpconstants.cpp httpheaders.cpp httpoptions.cpp httprequest.cpp @@ -51,6 +51,7 @@ set(llcorehttp_HEADER_FILES bufferarray.h bufferstream.h httpcommon.h + llhttpconstants.h httphandler.h httpheaders.h httpoptions.h @@ -89,7 +90,6 @@ add_library (llcorehttp ${llcorehttp_SOURCE_FILES}) target_link_libraries( llcorehttp ${CURL_LIBRARIES} - ${CARES_LIBRARIES} ${OPENSSL_LIBRARIES} ${CRYPTO_LIBRARIES} ${BOOST_THREAD_LIBRARY} @@ -127,20 +127,60 @@ if (LL_TESTS) ${LLCOMMON_LIBRARIES} ${GOOGLEMOCK_LIBRARIES} ${CURL_LIBRARIES} - ${CARES_LIBRARIES} ${OPENSSL_LIBRARIES} ${CRYPTO_LIBRARIES} ${BOOST_SYSTEM_LIBRARY} ${BOOST_THREAD_LIBRARY} ) + # If http_proxy is in the current environment (e.g. to fetch s3-proxy + # autobuild packages), suppress it for this integration test: it screws up + # the tests. LL_ADD_INTEGRATION_TEST(llcorehttp "${llcorehttp_TEST_SOURCE_FILES}" "${test_libs}" + "-Dhttp_proxy" ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/tests/test_llcorehttp_peer.py" ) +if (DARWIN) + # Path inside the app bundle where we'll need to copy libraries + set(LL_TEST_DESTINATION_DIR + ${CMAKE_SOURCE_DIR}/../build-darwin-i386/sharedlibs/Resources + ) + + # Create the Contents/Resources directory + add_custom_command( + TARGET INTEGRATION_TEST_llcorehttp PRE_BUILD + COMMAND ${CMAKE_COMMAND} + ARGS + -E + make_directory + ${LL_TEST_DESTINATION_DIR} + COMMENT "Creating Resources directory in app bundle." + ) + + # Copy the required libraries to the package app + add_custom_command(TARGET INTEGRATION_TEST_llcorehttp PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libapr-1.0.dylib ${LL_TEST_DESTINATION_DIR} + DEPENDS ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libapr-1.0.dylib + ) + add_custom_command(TARGET INTEGRATION_TEST_llcorehttp PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libaprutil-1.0.dylib ${LL_TEST_DESTINATION_DIR} + DEPENDS ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libaprutil-1.0.dylib + ) + add_custom_command(TARGET INTEGRATION_TEST_llcorehttp PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libexception_handler.dylib ${LL_TEST_DESTINATION_DIR} + DEPENDS ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libexception_handler.dylib + ) + add_custom_command(TARGET INTEGRATION_TEST_llcorehttp PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libexpat.1.5.2.dylib ${LL_TEST_DESTINATION_DIR} + DEPENDS ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libexpat.1.5.2.dylib + ) + +endif (DARWIN) + # # Example Programs # @@ -155,7 +195,6 @@ if (LL_TESTS) ${LLCOMMON_LIBRARIES} ${GOOGLEMOCK_LIBRARIES} ${CURL_LIBRARIES} - ${CARES_LIBRARIES} ${OPENSSL_LIBRARIES} ${CRYPTO_LIBRARIES} ${BOOST_SYSTEM_LIBRARY} diff --git a/indra/llcorehttp/_httpinternal.h b/indra/llcorehttp/_httpinternal.h index a2a60ca056..79c89d6c92 100755 --- a/indra/llcorehttp/_httpinternal.h +++ b/indra/llcorehttp/_httpinternal.h @@ -104,8 +104,9 @@ namespace LLCore { // Maxium number of policy classes that can be defined. -// *TODO: Currently limited to the default class + 1, extend. -const int HTTP_POLICY_CLASS_LIMIT = 8; +// *TODO: Currently limited to the default class + 1, extend. +// (TSN: should this be more dynamically sized. Is there a reason to hard limit the number of policies?) +const int HTTP_POLICY_CLASS_LIMIT = 32; // Debug/informational tracing. Used both // as a global option and in per-request traces. diff --git a/indra/llcorehttp/_httplibcurl.cpp b/indra/llcorehttp/_httplibcurl.cpp index 81b44ab90b..c25e01a318 100755 --- a/indra/llcorehttp/_httplibcurl.cpp +++ b/indra/llcorehttp/_httplibcurl.cpp @@ -71,11 +71,10 @@ void HttpLibcurl::shutdown() { while (! mActiveOps.empty()) { - HttpOpRequest * op(* mActiveOps.begin()); + HttpOpRequest::ptr_t op(* mActiveOps.begin()); mActiveOps.erase(mActiveOps.begin()); cancelRequest(op); - op->release(); } if (mMultiHandles) @@ -204,7 +203,7 @@ HttpService::ELoopSpeed HttpLibcurl::processTransport() // Caller has provided us with a ref count on op. -void HttpLibcurl::addOp(HttpOpRequest * op) +void HttpLibcurl::addOp(const HttpOpRequest::ptr_t &op) { llassert_always(op->mReqPolicy < mPolicyCount); llassert_always(mMultiHandles[op->mReqPolicy] != NULL); @@ -235,21 +234,21 @@ void HttpLibcurl::addOp(HttpOpRequest * op) HttpPolicy & policy(mService->getPolicy()); LL_INFOS(LOG_CORE) << "TRACE, ToActiveQueue, Handle: " - << static_cast<HttpHandle>(op) - << ", Actives: " << mActiveOps.size() - << ", Readies: " << policy.getReadyCount(op->mReqPolicy) - << LL_ENDL; + << op->getHandle() + << ", Actives: " << mActiveOps.size() + << ", Readies: " << policy.getReadyCount(op->mReqPolicy) + << LL_ENDL; } } // Implements the transport part of any cancel operation. // See if the handle is an active operation and if so, -// use the more complicated transport-based cancelation +// use the more complicated transport-based cancellation // method to kill the request. bool HttpLibcurl::cancel(HttpHandle handle) { - HttpOpRequest * op(static_cast<HttpOpRequest *>(handle)); + HttpOpRequest::ptr_t op = HttpOpRequest::fromHandle<HttpOpRequest>(handle); active_set_t::iterator it(mActiveOps.find(op)); if (mActiveOps.end() == it) { @@ -262,7 +261,6 @@ bool HttpLibcurl::cancel(HttpHandle handle) // Drop references mActiveOps.erase(it); --mActiveHandles[op->mReqPolicy]; - op->release(); return true; } @@ -273,7 +271,7 @@ bool HttpLibcurl::cancel(HttpHandle handle) // remove the op from the active list and release the op *after* // calling this method. It must be called first to deliver the // op to the reply queue with refcount intact. -void HttpLibcurl::cancelRequest(HttpOpRequest * op) +void HttpLibcurl::cancelRequest(const HttpOpRequest::ptr_t &op) { // Deactivate request op->mCurlActive = false; @@ -287,7 +285,7 @@ void HttpLibcurl::cancelRequest(HttpOpRequest * op) if (op->mTracing > HTTP_TRACE_OFF) { LL_INFOS(LOG_CORE) << "TRACE, RequestCanceled, Handle: " - << static_cast<HttpHandle>(op) + << op->getHandle() << ", Status: " << op->mStatus.toTerseString() << LL_ENDL; } @@ -301,8 +299,23 @@ void HttpLibcurl::cancelRequest(HttpOpRequest * op) // Keep them synchronized as necessary. bool HttpLibcurl::completeRequest(CURLM * multi_handle, CURL * handle, CURLcode status) { - HttpOpRequest * op(NULL); - curl_easy_getinfo(handle, CURLINFO_PRIVATE, &op); + HttpHandle ophandle(NULL); + + CURLcode ccode(CURLE_OK); + + ccode = curl_easy_getinfo(handle, CURLINFO_PRIVATE, &ophandle); + if (ccode) + { + LL_WARNS(LOG_CORE) << "libcurl error: " << ccode << " Unable to retrieve operation handle from CURL handle" << LL_ENDL; + return false; + } + HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(ophandle)); + + if (!op) + { + LL_WARNS() << "Unable to locate operation by handle. May have expired!" << LL_ENDL; + return false; + } if (handle != op->mCurlHandle || ! op->mCurlActive) { @@ -331,42 +344,72 @@ bool HttpLibcurl::completeRequest(CURLM * multi_handle, CURL * handle, CURLcode { op->mStatus = HttpStatus(HttpStatus::EXT_CURL_EASY, status); } - if (op->mStatus) - { - int http_status(HTTP_OK); - - curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_status); - if (http_status >= 100 && http_status <= 999) - { - char * cont_type(NULL); - curl_easy_getinfo(handle, CURLINFO_CONTENT_TYPE, &cont_type); - if (cont_type) - { - op->mReplyConType = cont_type; - } - op->mStatus = HttpStatus(http_status); - } - else - { - LL_WARNS(LOG_CORE) << "Invalid HTTP response code (" - << http_status << ") received from server." - << LL_ENDL; - op->mStatus = HttpStatus(HttpStatus::LLCORE, HE_INVALID_HTTP_STATUS); - } + if (op->mStatus) + { + int http_status(HTTP_OK); + + if (handle) + { + ccode = curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_status); + if (ccode == CURLE_OK) + { + if (http_status >= 100 && http_status <= 999) + { + char * cont_type(NULL); + ccode = curl_easy_getinfo(handle, CURLINFO_CONTENT_TYPE, &cont_type); + if (ccode == CURLE_OK) + { + if (cont_type) + { + op->mReplyConType = cont_type; + } + } + else + { + LL_WARNS(LOG_CORE) << "CURL error:" << ccode << " Attempting to get content type." << LL_ENDL; + } + op->mStatus = HttpStatus(http_status); + } + else + { + LL_WARNS(LOG_CORE) << "Invalid HTTP response code (" + << http_status << ") received from server." + << LL_ENDL; + op->mStatus = HttpStatus(HttpStatus::LLCORE, HE_INVALID_HTTP_STATUS); + } + } + else + { + op->mStatus = HttpStatus(HttpStatus::LLCORE, HE_INVALID_HTTP_STATUS); + } + } + else + { + LL_WARNS(LOG_CORE) << "Attempt to retrieve status from NULL handle!" << LL_ENDL; + } } - // Detach from multi and recycle handle - curl_multi_remove_handle(multi_handle, handle); - mHandleCache.freeHandle(op->mCurlHandle); - op->mCurlHandle = NULL; + if (multi_handle && handle) + { + // Detach from multi and recycle handle + curl_multi_remove_handle(multi_handle, handle); + mHandleCache.freeHandle(op->mCurlHandle); + } + else + { + LL_WARNS(LOG_CORE) << "Curl multi_handle or handle is NULL on remove! multi:" + << std::hex << multi_handle << " h:" << std::hex << handle << std::dec << LL_ENDL; + } + + op->mCurlHandle = NULL; // Tracing if (op->mTracing > HTTP_TRACE_OFF) { LL_INFOS(LOG_CORE) << "TRACE, RequestComplete, Handle: " - << static_cast<HttpHandle>(op) - << ", Status: " << op->mStatus.toTerseString() - << LL_ENDL; + << op->getHandle() + << ", Status: " << op->mStatus.toTerseString() + << LL_ENDL; } // Dispatch to next stage @@ -554,7 +597,7 @@ void HttpLibcurl::HandleCache::freeHandle(CURL * handle) // --------------------------------------- -struct curl_slist * append_headers_to_slist(const HttpHeaders * headers, struct curl_slist * slist) +struct curl_slist * append_headers_to_slist(const HttpHeaders::ptr_t &headers, struct curl_slist * slist) { const HttpHeaders::const_iterator end(headers->end()); for (HttpHeaders::const_iterator it(headers->begin()); end != it; ++it) diff --git a/indra/llcorehttp/_httplibcurl.h b/indra/llcorehttp/_httplibcurl.h index ffc24c63a8..a71eae59c0 100755 --- a/indra/llcorehttp/_httplibcurl.h +++ b/indra/llcorehttp/_httplibcurl.h @@ -65,6 +65,8 @@ private: void operator=(const HttpLibcurl &); // Not defined public: + typedef boost::shared_ptr<HttpOpRequest> opReqPtr_t; + /// Give cycles to libcurl to run active requests. Completed /// operations (successful or failed) will be retried or handed /// over to the reply queue as final responses. @@ -80,7 +82,7 @@ public: /// request. (No additional references will be added.) /// /// Threading: called by worker thread. - void addOp(HttpOpRequest * op); + void addOp(const opReqPtr_t & op); /// One-time call to set the number of policy classes to be /// serviced and to create the resources for each. Value @@ -148,10 +150,10 @@ protected: /// Invoked to cancel an active request, mainly during shutdown /// and destroy. - void cancelRequest(HttpOpRequest * op); + void cancelRequest(const opReqPtr_t &op); protected: - typedef std::set<HttpOpRequest *> active_set_t; + typedef std::set<opReqPtr_t> active_set_t; /// Simple request handle cache for libcurl. /// diff --git a/indra/llcorehttp/_httpopcancel.h b/indra/llcorehttp/_httpopcancel.h index 336dfdc573..86944eb159 100755 --- a/indra/llcorehttp/_httpopcancel.h +++ b/indra/llcorehttp/_httpopcancel.h @@ -56,13 +56,8 @@ public: /// be canceled. HttpOpCancel(HttpHandle handle); -protected: virtual ~HttpOpCancel(); // Use release() -private: - HttpOpCancel(const HttpOpCancel &); // Not defined - void operator=(const HttpOpCancel &); // Not defined - public: virtual void stageFromRequest(HttpService *); diff --git a/indra/llcorehttp/_httpoperation.cpp b/indra/llcorehttp/_httpoperation.cpp index fefe561f80..3fc4e28910 100755 --- a/indra/llcorehttp/_httpoperation.cpp +++ b/indra/llcorehttp/_httpoperation.cpp @@ -53,15 +53,18 @@ namespace LLCore // ================================== // HttpOperation // ================================== - - -HttpOperation::HttpOperation() - : LLCoreInt::RefCounted(true), - mReplyQueue(NULL), - mUserHandler(NULL), - mReqPolicy(HttpRequest::DEFAULT_POLICY_ID), - mReqPriority(0U), - mTracing(HTTP_TRACE_OFF) +/*static*/ +HttpOperation::handleMap_t HttpOperation::mHandleMap; +LLCoreInt::HttpMutex HttpOperation::mOpMutex; + +HttpOperation::HttpOperation(): + boost::enable_shared_from_this<HttpOperation>(), + mReplyQueue(), + mUserHandler(), + mReqPolicy(HttpRequest::DEFAULT_POLICY_ID), + mReqPriority(0U), + mTracing(HTTP_TRACE_OFF), + mMyHandle(LLCORE_HTTP_HANDLE_INVALID) { mMetricCreated = totalTime(); } @@ -69,30 +72,17 @@ HttpOperation::HttpOperation() HttpOperation::~HttpOperation() { - setReplyPath(NULL, NULL); + destroyHandle(); + mReplyQueue.reset(); + mUserHandler.reset(); } -void HttpOperation::setReplyPath(HttpReplyQueue * reply_queue, - HttpHandler * user_handler) +void HttpOperation::setReplyPath(HttpReplyQueue::ptr_t reply_queue, + HttpHandler::ptr_t user_handler) { - if (reply_queue != mReplyQueue) - { - if (mReplyQueue) - { - mReplyQueue->release(); - } - - if (reply_queue) - { - reply_queue->addRef(); - } - - mReplyQueue = reply_queue; - } - - // Not refcounted - mUserHandler = user_handler; + mReplyQueue.swap(reply_queue); + mUserHandler.swap(user_handler); } @@ -134,7 +124,7 @@ void HttpOperation::visitNotifier(HttpRequest *) HttpResponse * response = new HttpResponse(); response->setStatus(mStatus); - mUserHandler->onCompleted(static_cast<HttpHandle>(this), response); + mUserHandler->onCompleted(getHandle(), response); response->release(); } @@ -148,20 +138,83 @@ HttpStatus HttpOperation::cancel() return status; } +// Handle methods +HttpHandle HttpOperation::getHandle() +{ + if (mMyHandle == LLCORE_HTTP_HANDLE_INVALID) + return createHandle(); + + return mMyHandle; +} + +HttpHandle HttpOperation::createHandle() +{ + HttpHandle handle = static_cast<HttpHandle>(this); + + { + LLCoreInt::HttpScopedLock lock(mOpMutex); + + mHandleMap[handle] = shared_from_this(); + mMyHandle = handle; + } + + return mMyHandle; +} + +void HttpOperation::destroyHandle() +{ + if (mMyHandle == LLCORE_HTTP_HANDLE_INVALID) + return; + { + LLCoreInt::HttpScopedLock lock(mOpMutex); + + handleMap_t::iterator it = mHandleMap.find(mMyHandle); + if (it != mHandleMap.end()) + mHandleMap.erase(it); + } +} + +/*static*/ +HttpOperation::ptr_t HttpOperation::findByHandle(HttpHandle handle) +{ + wptr_t weak; + + if (!handle) + return ptr_t(); + + { + LLCoreInt::HttpScopedLock lock(mOpMutex); + + handleMap_t::iterator it = mHandleMap.find(handle); + if (it == mHandleMap.end()) + { + LL_WARNS("LLCore::HTTP") << "Could not find operation for handle " << handle << LL_ENDL; + return ptr_t(); + } + + weak = (*it).second; + } + + if (!weak.expired()) + return weak.lock(); + + return ptr_t(); +} + void HttpOperation::addAsReply() { if (mTracing > HTTP_TRACE_OFF) { LL_INFOS(LOG_CORE) << "TRACE, ToReplyQueue, Handle: " - << static_cast<HttpHandle>(this) + << getHandle() << LL_ENDL; } if (mReplyQueue) { - addRef(); - mReplyQueue->addOp(this); + HttpOperation::ptr_t op = shared_from_this(); + mReplyQueue->addOp(op); } } @@ -244,11 +297,8 @@ void HttpOpSpin::stageFromRequest(HttpService * service) else { ms_sleep(1); // backoff interlock plumbing a bit - this->addRef(); - if (! service->getRequestQueue().addOp(this)) - { - this->release(); - } + HttpOperation::ptr_t opptr = shared_from_this(); + service->getRequestQueue().addOp(opptr); } } diff --git a/indra/llcorehttp/_httpoperation.h b/indra/llcorehttp/_httpoperation.h index 937a61187d..1a75921c09 100755 --- a/indra/llcorehttp/_httpoperation.h +++ b/indra/llcorehttp/_httpoperation.h @@ -30,8 +30,7 @@ #include "httpcommon.h" #include "httprequest.h" -#include "_refcounted.h" - +#include "_mutex.h" namespace LLCore { @@ -69,19 +68,20 @@ class HttpService; /// via queue-like interfaces that are thread compatible /// and those interfaces establish the access rules. -class HttpOperation : public LLCoreInt::RefCounted +class HttpOperation : private boost::noncopyable, + public boost::enable_shared_from_this<HttpOperation> { public: + typedef boost::shared_ptr<HttpOperation> ptr_t; + typedef boost::weak_ptr<HttpOperation> wptr_t; + typedef boost::shared_ptr<HttpReplyQueue> HttpReplyQueuePtr_t; + /// Threading: called by consumer thread. HttpOperation(); -protected: /// Threading: called by any thread. virtual ~HttpOperation(); // Use release() -private: - HttpOperation(const HttpOperation &); // Not defined - void operator=(const HttpOperation &); // Not defined public: /// Register a reply queue and a handler for completion notifications. @@ -110,8 +110,8 @@ public: /// /// Threading: called by consumer thread. /// - void setReplyPath(HttpReplyQueue * reply_queue, - HttpHandler * handler); + void setReplyPath(HttpReplyQueuePtr_t reply_queue, + HttpHandler::ptr_t handler); /// The three possible staging steps in an operation's lifecycle. /// Asynchronous requests like HTTP operations move from the @@ -152,6 +152,18 @@ public: /// Threading: called by worker thread. /// virtual HttpStatus cancel(); + + /// Retrieves a unique handle for this operation. + HttpHandle getHandle(); + + template< class OPT > + static boost::shared_ptr< OPT > fromHandle(HttpHandle handle) + { + ptr_t ptr = findByHandle(handle); + if (!ptr) + return boost::shared_ptr< OPT >(); + return boost::dynamic_pointer_cast< OPT >(ptr); + } protected: /// Delivers request to reply queue on completion. After this @@ -163,8 +175,8 @@ protected: void addAsReply(); protected: - HttpReplyQueue * mReplyQueue; // Have refcount - HttpHandler * mUserHandler; // Naked pointer + HttpReplyQueuePtr_t mReplyQueue; + HttpHandler::ptr_t mUserHandler; public: // Request Data @@ -177,6 +189,21 @@ public: // Tracing, debug and metrics HttpTime mMetricCreated; int mTracing; + +private: + typedef std::map<HttpHandle, wptr_t> handleMap_t; + + HttpHandle createHandle(); + void destroyHandle(); + HttpHandle mMyHandle; + + static handleMap_t mHandleMap; + static LLCoreInt::HttpMutex mOpMutex; + +protected: + static ptr_t findByHandle(HttpHandle handle); + + }; // end class HttpOperation @@ -195,7 +222,6 @@ class HttpOpStop : public HttpOperation public: HttpOpStop(); -protected: virtual ~HttpOpStop(); private: @@ -218,7 +244,6 @@ class HttpOpNull : public HttpOperation public: HttpOpNull(); -protected: virtual ~HttpOpNull(); private: @@ -241,7 +266,6 @@ public: // 1 does a soft spin continuously requeuing itself HttpOpSpin(int mode); -protected: virtual ~HttpOpSpin(); private: diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp index b9632a7921..db57869a1b 100755 --- a/indra/llcorehttp/_httpoprequest.cpp +++ b/indra/llcorehttp/_httpoprequest.cpp @@ -122,8 +122,8 @@ HttpOpRequest::HttpOpRequest() mReqBody(NULL), mReqOffset(0), mReqLength(0), - mReqHeaders(NULL), - mReqOptions(NULL), + mReqHeaders(), + mReqOptions(), mCurlActive(false), mCurlHandle(NULL), mCurlService(NULL), @@ -135,11 +135,12 @@ HttpOpRequest::HttpOpRequest() mReplyOffset(0), mReplyLength(0), mReplyFullLength(0), - mReplyHeaders(NULL), + mReplyHeaders(), mPolicyRetries(0), mPolicy503Retries(0), mPolicyRetryAt(HttpTime(0)), - mPolicyRetryLimit(HTTP_RETRY_COUNT_DEFAULT) + mPolicyRetryLimit(HTTP_RETRY_COUNT_DEFAULT), + mCallbackSSLVerify(NULL) { // *NOTE: As members are added, retry initialization/cleanup // may need to be extended in @see prepareRequest(). @@ -155,18 +156,6 @@ HttpOpRequest::~HttpOpRequest() mReqBody = NULL; } - if (mReqOptions) - { - mReqOptions->release(); - mReqOptions = NULL; - } - - if (mReqHeaders) - { - mReqHeaders->release(); - mReqHeaders = NULL; - } - if (mCurlHandle) { // Uncertain of thread context so free using @@ -193,25 +182,20 @@ HttpOpRequest::~HttpOpRequest() mReplyBody = NULL; } - if (mReplyHeaders) - { - mReplyHeaders->release(); - mReplyHeaders = NULL; - } } void HttpOpRequest::stageFromRequest(HttpService * service) { - addRef(); - service->getPolicy().addOp(this); // transfers refcount + HttpOpRequest::ptr_t self(boost::dynamic_pointer_cast<HttpOpRequest>(shared_from_this())); + service->getPolicy().addOp(self); // transfers refcount } void HttpOpRequest::stageFromReady(HttpService * service) { - addRef(); - service->getTransport().addOp(this); // transfers refcount + HttpOpRequest::ptr_t self(boost::dynamic_pointer_cast<HttpOpRequest>(shared_from_this())); + service->getTransport().addOp(self); // transfers refcount } @@ -259,7 +243,9 @@ void HttpOpRequest::visitNotifier(HttpRequest * request) response->setStatus(mStatus); response->setBody(mReplyBody); response->setHeaders(mReplyHeaders); - if (mReplyOffset || mReplyLength) + response->setRequestURL(mReqURL); + + if (mReplyOffset || mReplyLength) { // Got an explicit offset/length in response response->setRange(mReplyOffset, mReplyLength, mReplyFullLength); @@ -267,12 +253,27 @@ void HttpOpRequest::visitNotifier(HttpRequest * request) response->setContentType(mReplyConType); response->setRetries(mPolicyRetries, mPolicy503Retries); - mUserHandler->onCompleted(static_cast<HttpHandle>(this), response); + HttpResponse::TransferStats::ptr_t stats = HttpResponse::TransferStats::ptr_t(new HttpResponse::TransferStats); + + curl_easy_getinfo(mCurlHandle, CURLINFO_SIZE_DOWNLOAD, &stats->mSizeDownload); + curl_easy_getinfo(mCurlHandle, CURLINFO_TOTAL_TIME, &stats->mTotalTime); + curl_easy_getinfo(mCurlHandle, CURLINFO_SPEED_DOWNLOAD, &stats->mSpeedDownload); + + response->setTransferStats(stats); + + mUserHandler->onCompleted(this->getHandle(), response); response->release(); } } +// /*static*/ +// HttpOpRequest::ptr_t HttpOpRequest::fromHandle(HttpHandle handle) +// { +// +// return boost::dynamic_pointer_cast<HttpOpRequest>((static_cast<HttpOpRequest *>(handle))->shared_from_this()); +// } + HttpStatus HttpOpRequest::cancel() { @@ -287,8 +288,8 @@ HttpStatus HttpOpRequest::cancel() HttpStatus HttpOpRequest::setupGet(HttpRequest::policy_t policy_id, HttpRequest::priority_t priority, const std::string & url, - HttpOptions * options, - HttpHeaders * headers) + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers) { setupCommon(policy_id, priority, url, NULL, options, headers); mReqMethod = HOR_GET; @@ -302,8 +303,8 @@ HttpStatus HttpOpRequest::setupGetByteRange(HttpRequest::policy_t policy_id, const std::string & url, size_t offset, size_t len, - HttpOptions * options, - HttpHeaders * headers) + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers) { setupCommon(policy_id, priority, url, NULL, options, headers); mReqMethod = HOR_GET; @@ -322,8 +323,8 @@ HttpStatus HttpOpRequest::setupPost(HttpRequest::policy_t policy_id, HttpRequest::priority_t priority, const std::string & url, BufferArray * body, - HttpOptions * options, - HttpHeaders * headers) + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers) { setupCommon(policy_id, priority, url, body, options, headers); mReqMethod = HOR_POST; @@ -336,8 +337,8 @@ HttpStatus HttpOpRequest::setupPut(HttpRequest::policy_t policy_id, HttpRequest::priority_t priority, const std::string & url, BufferArray * body, - HttpOptions * options, - HttpHeaders * headers) + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers) { setupCommon(policy_id, priority, url, body, options, headers); mReqMethod = HOR_PUT; @@ -346,12 +347,65 @@ HttpStatus HttpOpRequest::setupPut(HttpRequest::policy_t policy_id, } +HttpStatus HttpOpRequest::setupDelete(HttpRequest::policy_t policy_id, + HttpRequest::priority_t priority, + const std::string & url, + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers) +{ + setupCommon(policy_id, priority, url, NULL, options, headers); + mReqMethod = HOR_DELETE; + + return HttpStatus(); +} + + +HttpStatus HttpOpRequest::setupPatch(HttpRequest::policy_t policy_id, + HttpRequest::priority_t priority, + const std::string & url, + BufferArray * body, + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers) +{ + setupCommon(policy_id, priority, url, body, options, headers); + mReqMethod = HOR_PATCH; + + return HttpStatus(); +} + + +HttpStatus HttpOpRequest::setupCopy(HttpRequest::policy_t policy_id, + HttpRequest::priority_t priority, + const std::string & url, + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t &headers) +{ + setupCommon(policy_id, priority, url, NULL, options, headers); + mReqMethod = HOR_COPY; + + return HttpStatus(); +} + + +HttpStatus HttpOpRequest::setupMove(HttpRequest::policy_t policy_id, + HttpRequest::priority_t priority, + const std::string & url, + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t &headers) +{ + setupCommon(policy_id, priority, url, NULL, options, headers); + mReqMethod = HOR_MOVE; + + return HttpStatus(); +} + + void HttpOpRequest::setupCommon(HttpRequest::policy_t policy_id, HttpRequest::priority_t priority, const std::string & url, BufferArray * body, - HttpOptions * options, - HttpHeaders * headers) + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers) { mProcFlags = 0U; mReqPolicy = policy_id; @@ -364,12 +418,10 @@ void HttpOpRequest::setupCommon(HttpRequest::policy_t policy_id, } if (headers && ! mReqHeaders) { - headers->addRef(); mReqHeaders = headers; } - if (options && ! mReqOptions) + if (options && !mReqOptions) { - options->addRef(); mReqOptions = options; if (options->getWantHeaders()) { @@ -416,11 +468,7 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service) mReplyOffset = 0; mReplyLength = 0; mReplyFullLength = 0; - if (mReplyHeaders) - { - mReplyHeaders->release(); - mReplyHeaders = NULL; - } + mReplyHeaders.reset(); mReplyConType.clear(); // *FIXME: better error handling later @@ -447,38 +495,74 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service) check_curl_easy_code(code, CURLOPT_NOPROGRESS); code = curl_easy_setopt(mCurlHandle, CURLOPT_URL, mReqURL.c_str()); check_curl_easy_code(code, CURLOPT_URL); - code = curl_easy_setopt(mCurlHandle, CURLOPT_PRIVATE, this); + code = curl_easy_setopt(mCurlHandle, CURLOPT_PRIVATE, getHandle()); check_curl_easy_code(code, CURLOPT_PRIVATE); code = curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, ""); check_curl_easy_code(code, CURLOPT_ENCODING); - // The Linksys WRT54G V5 router has an issue with frequent - // DNS lookups from LAN machines. If they happen too often, - // like for every HTTP request, the router gets annoyed after - // about 700 or so requests and starts issuing TCP RSTs to - // new connections. Reuse the DNS lookups for even a few - // seconds and no RSTs. - code = curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, 15); - check_curl_easy_code(code, CURLOPT_DNS_CACHE_TIMEOUT); code = curl_easy_setopt(mCurlHandle, CURLOPT_AUTOREFERER, 1); check_curl_easy_code(code, CURLOPT_AUTOREFERER); - code = curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, 1); - check_curl_easy_code(code, CURLOPT_FOLLOWLOCATION); code = curl_easy_setopt(mCurlHandle, CURLOPT_MAXREDIRS, HTTP_REDIRECTS_DEFAULT); check_curl_easy_code(code, CURLOPT_MAXREDIRS); code = curl_easy_setopt(mCurlHandle, CURLOPT_WRITEFUNCTION, writeCallback); check_curl_easy_code(code, CURLOPT_WRITEFUNCTION); - code = curl_easy_setopt(mCurlHandle, CURLOPT_WRITEDATA, this); + code = curl_easy_setopt(mCurlHandle, CURLOPT_WRITEDATA, getHandle()); check_curl_easy_code(code, CURLOPT_WRITEDATA); code = curl_easy_setopt(mCurlHandle, CURLOPT_READFUNCTION, readCallback); check_curl_easy_code(code, CURLOPT_READFUNCTION); - code = curl_easy_setopt(mCurlHandle, CURLOPT_READDATA, this); + code = curl_easy_setopt(mCurlHandle, CURLOPT_READDATA, getHandle()); check_curl_easy_code(code, CURLOPT_READDATA); - code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYPEER, 1); + code = curl_easy_setopt(mCurlHandle, CURLOPT_SEEKFUNCTION, seekCallback); + check_curl_easy_code(code, CURLOPT_SEEKFUNCTION); + code = curl_easy_setopt(mCurlHandle, CURLOPT_SEEKDATA, getHandle()); + check_curl_easy_code(code, CURLOPT_SEEKDATA); + + code = curl_easy_setopt(mCurlHandle, CURLOPT_COOKIEFILE, ""); + check_curl_easy_code(code, CURLOPT_COOKIEFILE); + + if (gpolicy.mSslCtxCallback) + { + code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_CTX_FUNCTION, curlSslCtxCallback); + check_curl_easy_code(code, CURLOPT_SSL_CTX_FUNCTION); + code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_CTX_DATA, getHandle()); + check_curl_easy_code(code, CURLOPT_SSL_CTX_DATA); + mCallbackSSLVerify = gpolicy.mSslCtxCallback; + } + + long follow_redirect(1L); + long sslPeerV(0L); + long sslHostV(0L); + long dnsCacheTimeout(-1L); + long nobody(0L); + + if (mReqOptions) + { + follow_redirect = mReqOptions->getFollowRedirects() ? 1L : 0L; + sslPeerV = mReqOptions->getSSLVerifyPeer() ? 1L : 0L; + sslHostV = mReqOptions->getSSLVerifyHost() ? 2L : 0L; + dnsCacheTimeout = mReqOptions->getDNSCacheTimeout(); + nobody = mReqOptions->getHeadersOnly() ? 1L : 0L; + } + code = curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, follow_redirect); + check_curl_easy_code(code, CURLOPT_FOLLOWLOCATION); + + code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYPEER, sslPeerV); check_curl_easy_code(code, CURLOPT_SSL_VERIFYPEER); - code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYHOST, 0); + code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYHOST, sslHostV); check_curl_easy_code(code, CURLOPT_SSL_VERIFYHOST); + code = curl_easy_setopt(mCurlHandle, CURLOPT_NOBODY, nobody); + check_curl_easy_code(code, CURLOPT_NOBODY); + + // The Linksys WRT54G V5 router has an issue with frequent + // DNS lookups from LAN machines. If they happen too often, + // like for every HTTP request, the router gets annoyed after + // about 700 or so requests and starts issuing TCP RSTs to + // new connections. Reuse the DNS lookups for even a few + // seconds and no RSTs. + code = curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, dnsCacheTimeout); + check_curl_easy_code(code, CURLOPT_DNS_CACHE_TIMEOUT); + if (gpolicy.mUseLLProxy) { // Use the viewer-based thread-safe API which has a @@ -509,10 +593,9 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service) switch (mReqMethod) { case HOR_GET: - code = curl_easy_setopt(mCurlHandle, CURLOPT_HTTPGET, 1); + if (nobody == 0) + code = curl_easy_setopt(mCurlHandle, CURLOPT_HTTPGET, 1); check_curl_easy_code(code, CURLOPT_HTTPGET); - mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive"); - mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300"); break; case HOR_POST: @@ -531,12 +614,14 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service) code = curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDSIZE, data_size); check_curl_easy_code(code, CURLOPT_POSTFIELDSIZE); mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:"); - mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive"); - mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300"); } break; - case HOR_PUT: + case HOR_PATCH: + code = curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "PATCH"); + check_curl_easy_code(code, CURLOPT_CUSTOMREQUEST); + // fall through. The rest is the same as PUT + case HOR_PUT: { code = curl_easy_setopt(mCurlHandle, CURLOPT_UPLOAD, 1); check_curl_easy_code(code, CURLOPT_UPLOAD); @@ -547,15 +632,25 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service) } code = curl_easy_setopt(mCurlHandle, CURLOPT_INFILESIZE, data_size); check_curl_easy_code(code, CURLOPT_INFILESIZE); - code = curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDS, (void *) NULL); - check_curl_easy_code(code, CURLOPT_POSTFIELDS); mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:"); - // *TODO: Should this be 'Keep-Alive' ? - mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive"); - mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300"); } break; + case HOR_DELETE: + code = curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "DELETE"); + check_curl_easy_code(code, CURLOPT_CUSTOMREQUEST); + break; + + case HOR_COPY: + code = curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "COPY"); + check_curl_easy_code(code, CURLOPT_CUSTOMREQUEST); + break; + + case HOR_MOVE: + code = curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "MOVE"); + check_curl_easy_code(code, CURLOPT_CUSTOMREQUEST); + break; + default: LL_ERRS(LOG_CORE) << "Invalid HTTP method in request: " << int(mReqMethod) << ". Can't recover." @@ -563,6 +658,11 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service) break; } + + // *TODO: Should this be 'Keep-Alive' ? + mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive"); + mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300"); + // Tracing if (mTracing >= HTTP_TRACE_CURL_HEADERS) { @@ -650,7 +750,11 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service) xfer_timeout *= 2L; } // *DEBUG: Enable following override for timeout handling and "[curl:bugs] #1420" tests - // xfer_timeout = 1L; + //if (cpolicy.mPipelining) + //{ + // xfer_timeout = 1L; + // timeout = 1L; + //} code = curl_easy_setopt(mCurlHandle, CURLOPT_TIMEOUT, xfer_timeout); check_curl_easy_code(code, CURLOPT_TIMEOUT); code = curl_easy_setopt(mCurlHandle, CURLOPT_CONNECTTIMEOUT, timeout); @@ -683,7 +787,7 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service) size_t HttpOpRequest::writeCallback(void * data, size_t size, size_t nmemb, void * userdata) { - HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata)); + HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata)); if (! op->mReplyBody) { @@ -697,7 +801,7 @@ size_t HttpOpRequest::writeCallback(void * data, size_t size, size_t nmemb, void size_t HttpOpRequest::readCallback(void * data, size_t size, size_t nmemb, void * userdata) { - HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata)); + HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata)); if (! op->mReqBody) { @@ -723,6 +827,37 @@ size_t HttpOpRequest::readCallback(void * data, size_t size, size_t nmemb, void return read_size; } + +int HttpOpRequest::seekCallback(void *userdata, curl_off_t offset, int origin) +{ + HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata)); + + if (!op->mReqBody) + { + return 0; + } + + size_t newPos = 0; + if (origin == SEEK_SET) + newPos = offset; + else if (origin == SEEK_END) + newPos = static_cast<curl_off_t>(op->mReqBody->size()) + offset; + else if (origin == SEEK_CUR) + newPos = static_cast<curl_off_t>(op->mCurlBodyPos) + offset; + else + return 2; + + if (newPos >= op->mReqBody->size()) + { + LL_WARNS(LOG_CORE) << "Attempt to seek to position outside post body." << LL_ENDL; + return 2; + } + + op->mCurlBodyPos = (size_t)newPos; + + return 0; +} + size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, void * userdata) { @@ -731,7 +866,7 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi static const char con_ran_line[] = "content-range"; static const char con_retry_line[] = "retry-after"; - HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata)); + HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata)); const size_t hdr_size(size * nmemb); const char * hdr_data(static_cast<const char *>(data)); // Not null terminated @@ -817,7 +952,7 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi // Save headers in response if (! op->mReplyHeaders) { - op->mReplyHeaders = new HttpHeaders; + op->mReplyHeaders = HttpHeaders::ptr_t(new HttpHeaders); } op->mReplyHeaders->append(name, value ? value : ""); } @@ -873,9 +1008,38 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi } +CURLcode HttpOpRequest::curlSslCtxCallback(CURL *curl, void *sslctx, void *userdata) +{ + HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata)); + + if (op->mCallbackSSLVerify) + { + SSL_CTX * ctx = (SSL_CTX *)sslctx; + // disable any default verification for server certs + SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); + // set the verification callback. + SSL_CTX_set_cert_verify_callback(ctx, sslCertVerifyCallback, userdata); + // the calls are void + } + + return CURLE_OK; +} + +int HttpOpRequest::sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param) +{ + HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(param)); + + if (op->mCallbackSSLVerify) + { + op->mStatus = op->mCallbackSSLVerify(op->mReqURL, op->mUserHandler, ctx); + } + + return (op->mStatus) ? 1 : 0; +} + int HttpOpRequest::debugCallback(CURL * handle, curl_infotype info, char * buffer, size_t len, void * userdata) { - HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata)); + HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata)); std::string safe_line; std::string tag; @@ -955,7 +1119,7 @@ int HttpOpRequest::debugCallback(CURL * handle, curl_infotype info, char * buffe if (logit) { LL_INFOS(LOG_CORE) << "TRACE, LibcurlDebug, Handle: " - << static_cast<HttpHandle>(op) + << op->getHandle() << ", Type: " << tag << ", Data: " << safe_line << LL_ENDL; diff --git a/indra/llcorehttp/_httpoprequest.h b/indra/llcorehttp/_httpoprequest.h index 2f628b5aba..dbcc57d0fd 100755 --- a/indra/llcorehttp/_httpoprequest.h +++ b/indra/llcorehttp/_httpoprequest.h @@ -33,19 +33,22 @@ #include <string> #include <curl/curl.h> +#include <openssl/x509_vfy.h> +#include <openssl/ssl.h> + #include "httpcommon.h" #include "httprequest.h" #include "_httpoperation.h" #include "_refcounted.h" +#include "httpheaders.h" +#include "httpoptions.h" namespace LLCore { class BufferArray; -class HttpHeaders; -class HttpOptions; /// HttpOpRequest requests a supported HTTP method invocation with @@ -63,9 +66,10 @@ class HttpOptions; class HttpOpRequest : public HttpOperation { public: + typedef boost::shared_ptr<HttpOpRequest> ptr_t; + HttpOpRequest(); -protected: virtual ~HttpOpRequest(); // Use release() private: @@ -77,7 +81,11 @@ public: { HOR_GET, HOR_POST, - HOR_PUT + HOR_PUT, + HOR_DELETE, + HOR_PATCH, + HOR_COPY, + HOR_MOVE }; virtual void stageFromRequest(HttpService *); @@ -98,32 +106,57 @@ public: HttpStatus setupGet(HttpRequest::policy_t policy_id, HttpRequest::priority_t priority, const std::string & url, - HttpOptions * options, - HttpHeaders * headers); + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers); HttpStatus setupGetByteRange(HttpRequest::policy_t policy_id, HttpRequest::priority_t priority, const std::string & url, size_t offset, size_t len, - HttpOptions * options, - HttpHeaders * headers); + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers); HttpStatus setupPost(HttpRequest::policy_t policy_id, HttpRequest::priority_t priority, const std::string & url, BufferArray * body, - HttpOptions * options, - HttpHeaders * headers); + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers); HttpStatus setupPut(HttpRequest::policy_t policy_id, HttpRequest::priority_t priority, const std::string & url, BufferArray * body, - HttpOptions * options, - HttpHeaders * headers); + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers); + + HttpStatus setupDelete(HttpRequest::policy_t policy_id, + HttpRequest::priority_t priority, + const std::string & url, + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers); + + HttpStatus setupPatch(HttpRequest::policy_t policy_id, + HttpRequest::priority_t priority, + const std::string & url, + BufferArray * body, + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers); - // Internal method used to setup the libcurl options for a request. + HttpStatus setupCopy(HttpRequest::policy_t policy_id, + HttpRequest::priority_t priority, + const std::string & url, + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers); + + HttpStatus setupMove(HttpRequest::policy_t policy_id, + HttpRequest::priority_t priority, + const std::string & url, + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers); + + // Internal method used to setup the libcurl options for a request. // Does all the libcurl handle setup in one place. // // Threading: called by worker thread @@ -141,8 +174,8 @@ protected: HttpRequest::priority_t priority, const std::string & url, BufferArray * body, - HttpOptions * options, - HttpHeaders * headers); + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers); // libcurl operational callbacks // @@ -150,7 +183,11 @@ protected: // static size_t writeCallback(void * data, size_t size, size_t nmemb, void * userdata); static size_t readCallback(void * data, size_t size, size_t nmemb, void * userdata); + static int seekCallback(void *data, curl_off_t offset, int origin); static size_t headerCallback(void * data, size_t size, size_t nmemb, void * userdata); + static CURLcode curlSslCtxCallback(CURL *curl, void *ssl_ctx, void *userptr); + static int sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param); + static int debugCallback(CURL *, curl_infotype info, char * buffer, size_t len, void * userdata); protected: @@ -159,6 +196,8 @@ protected: static const unsigned int PF_SAVE_HEADERS = 0x00000002U; static const unsigned int PF_USE_RETRY_AFTER = 0x00000004U; + HttpRequest::policyCallback_t mCallbackSSLVerify; + public: // Request data EMethod mReqMethod; @@ -166,8 +205,8 @@ public: BufferArray * mReqBody; off_t mReqOffset; size_t mReqLength; - HttpHeaders * mReqHeaders; - HttpOptions * mReqOptions; + HttpHeaders::ptr_t mReqHeaders; + HttpOptions::ptr_t mReqOptions; // Transport data bool mCurlActive; @@ -184,7 +223,7 @@ public: off_t mReplyOffset; size_t mReplyLength; size_t mReplyFullLength; - HttpHeaders * mReplyHeaders; + HttpHeaders::ptr_t mReplyHeaders; std::string mReplyConType; int mReplyRetryAfter; @@ -215,7 +254,7 @@ public: // Internal function to append the contents of an HttpHeaders // instance to a curl_slist object. -curl_slist * append_headers_to_slist(const HttpHeaders *, curl_slist * slist); +curl_slist * append_headers_to_slist(const HttpHeaders::ptr_t &, curl_slist * slist); } // end namespace LLCore diff --git a/indra/llcorehttp/_httpopsetget.h b/indra/llcorehttp/_httpopsetget.h index a1e76dd429..eabd41e79f 100755 --- a/indra/llcorehttp/_httpopsetget.h +++ b/indra/llcorehttp/_httpopsetget.h @@ -53,9 +53,10 @@ namespace LLCore class HttpOpSetGet : public HttpOperation { public: + typedef boost::shared_ptr<HttpOpSetGet> ptr_t; + HttpOpSetGet(); -protected: virtual ~HttpOpSetGet(); // Use release() private: diff --git a/indra/llcorehttp/_httpopsetpriority.h b/indra/llcorehttp/_httpopsetpriority.h index 31706b737c..43e2aa081b 100755 --- a/indra/llcorehttp/_httpopsetpriority.h +++ b/indra/llcorehttp/_httpopsetpriority.h @@ -51,7 +51,6 @@ class HttpOpSetPriority : public HttpOperation public: HttpOpSetPriority(HttpHandle handle, HttpRequest::priority_t priority); -protected: virtual ~HttpOpSetPriority(); private: diff --git a/indra/llcorehttp/_httppolicy.cpp b/indra/llcorehttp/_httppolicy.cpp index e5d6321401..b2709b53ec 100755 --- a/indra/llcorehttp/_httppolicy.cpp +++ b/indra/llcorehttp/_httppolicy.cpp @@ -116,21 +116,19 @@ void HttpPolicy::shutdown() HttpRetryQueue & retryq(state.mRetryQueue); while (! retryq.empty()) { - HttpOpRequest * op(retryq.top()); + HttpOpRequest::ptr_t op(retryq.top()); retryq.pop(); op->cancel(); - op->release(); } HttpReadyQueue & readyq(state.mReadyQueue); while (! readyq.empty()) { - HttpOpRequest * op(readyq.top()); + HttpOpRequest::ptr_t op(readyq.top()); readyq.pop(); op->cancel(); - op->release(); } } } @@ -141,7 +139,7 @@ void HttpPolicy::start() } -void HttpPolicy::addOp(HttpOpRequest * op) +void HttpPolicy::addOp(const HttpOpRequest::ptr_t &op) { const int policy_class(op->mReqPolicy); @@ -151,7 +149,7 @@ void HttpPolicy::addOp(HttpOpRequest * op) } -void HttpPolicy::retryOp(HttpOpRequest * op) +void HttpPolicy::retryOp(const HttpOpRequest::ptr_t &op) { static const HttpTime retry_deltas[] = { @@ -180,7 +178,7 @@ void HttpPolicy::retryOp(HttpOpRequest * op) { ++op->mPolicy503Retries; } - LL_DEBUGS(LOG_CORE) << "HTTP request " << static_cast<HttpHandle>(op) + LL_DEBUGS(LOG_CORE) << "HTTP request " << op->getHandle() << " retry " << op->mPolicyRetries << " scheduled in " << (delta / HttpTime(1000)) << " mS (" << (external_delta ? "external" : "internal") @@ -189,10 +187,10 @@ void HttpPolicy::retryOp(HttpOpRequest * op) if (op->mTracing > HTTP_TRACE_OFF) { LL_INFOS(LOG_CORE) << "TRACE, ToRetryQueue, Handle: " - << static_cast<HttpHandle>(op) - << ", Delta: " << (delta / HttpTime(1000)) - << ", Retries: " << op->mPolicyRetries - << LL_ENDL; + << op->getHandle() + << ", Delta: " << (delta / HttpTime(1000)) + << ", Retries: " << op->mPolicyRetries + << LL_ENDL; } mClasses[policy_class]->mRetryQueue.push(op); } @@ -264,14 +262,14 @@ HttpService::ELoopSpeed HttpPolicy::processReadyQueue() // First see if we have any retries... while (needed > 0 && ! retryq.empty()) { - HttpOpRequest * op(retryq.top()); + HttpOpRequest::ptr_t op(retryq.top()); if (op->mPolicyRetryAt > now) break; retryq.pop(); op->stageFromReady(mService); - op->release(); + op.reset(); ++state.mRequestCount; --needed; @@ -296,11 +294,11 @@ HttpService::ELoopSpeed HttpPolicy::processReadyQueue() // Now go on to the new requests... while (needed > 0 && ! readyq.empty()) { - HttpOpRequest * op(readyq.top()); + HttpOpRequest::ptr_t op(readyq.top()); readyq.pop(); op->stageFromReady(mService); - op->release(); + op.reset(); ++state.mRequestCount; --needed; @@ -351,9 +349,9 @@ bool HttpPolicy::changePriority(HttpHandle handle, HttpRequest::priority_t prior { HttpReadyQueue::container_type::iterator cur(iter++); - if (static_cast<HttpHandle>(*cur) == handle) + if ((*cur)->getHandle() == handle) { - HttpOpRequest * op(*cur); + HttpOpRequest::ptr_t op(*cur); c.erase(cur); // All iterators are now invalidated op->mReqPriority = priority; state.mReadyQueue.push(op); // Re-insert using adapter class @@ -378,12 +376,11 @@ bool HttpPolicy::cancel(HttpHandle handle) { HttpRetryQueue::container_type::iterator cur(iter++); - if (static_cast<HttpHandle>(*cur) == handle) + if ((*cur)->getHandle() == handle) { - HttpOpRequest * op(*cur); + HttpOpRequest::ptr_t op(*cur); c1.erase(cur); // All iterators are now invalidated op->cancel(); - op->release(); return true; } } @@ -394,12 +391,11 @@ bool HttpPolicy::cancel(HttpHandle handle) { HttpReadyQueue::container_type::iterator cur(iter++); - if (static_cast<HttpHandle>(*cur) == handle) + if ((*cur)->getHandle() == handle) { - HttpOpRequest * op(*cur); + HttpOpRequest::ptr_t op(*cur); c2.erase(cur); // All iterators are now invalidated op->cancel(); - op->release(); return true; } } @@ -409,7 +405,7 @@ bool HttpPolicy::cancel(HttpHandle handle) } -bool HttpPolicy::stageAfterCompletion(HttpOpRequest * op) +bool HttpPolicy::stageAfterCompletion(const HttpOpRequest::ptr_t &op) { // Retry or finalize if (! op->mStatus) @@ -420,7 +416,7 @@ bool HttpPolicy::stageAfterCompletion(HttpOpRequest * op) #if 0 if (op->mStatus == HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_OPERATION_TIMEDOUT)) { - LL_WARNS(LOG_CORE) << "HTTP request " << static_cast<HttpHandle>(op) + LL_WARNS(LOG_CORE) << "HTTP request " << op->getHandle() << " timed out." << LL_ENDL; } @@ -438,7 +434,7 @@ bool HttpPolicy::stageAfterCompletion(HttpOpRequest * op) // This op is done, finalize it delivering it to the reply queue... if (! op->mStatus) { - LL_WARNS(LOG_CORE) << "HTTP request " << static_cast<HttpHandle>(op) + LL_WARNS(LOG_CORE) << "HTTP request " << op->getHandle() << " failed after " << op->mPolicyRetries << " retries. Reason: " << op->mStatus.toString() << " (" << op->mStatus.toTerseString() << ")" @@ -446,13 +442,12 @@ bool HttpPolicy::stageAfterCompletion(HttpOpRequest * op) } else if (op->mPolicyRetries) { - LL_DEBUGS(LOG_CORE) << "HTTP request " << static_cast<HttpHandle>(op) + LL_DEBUGS(LOG_CORE) << "HTTP request " << op->getHandle() << " succeeded on retry " << op->mPolicyRetries << "." << LL_ENDL; } op->stageFromActive(mService); - op->release(); return false; // not active } diff --git a/indra/llcorehttp/_httppolicy.h b/indra/llcorehttp/_httppolicy.h index 11cd89bbd1..3c4126e14b 100755 --- a/indra/llcorehttp/_httppolicy.h +++ b/indra/llcorehttp/_httppolicy.h @@ -60,6 +60,8 @@ private: void operator=(const HttpPolicy &); // Not defined public: + typedef boost::shared_ptr<HttpOpRequest> opReqPtr_t; + /// Threading: called by init thread. HttpRequest::policy_t createPolicyClass(); @@ -96,7 +98,7 @@ public: /// from queue. /// /// Threading: called by worker thread - void addOp(HttpOpRequest *); + void addOp(const opReqPtr_t &); /// Similar to addOp, used when a caller wants to retry a /// request that has failed. It's placed on a special retry @@ -106,7 +108,7 @@ public: /// order. /// /// Threading: called by worker thread - void retryOp(HttpOpRequest *); + void retryOp(const opReqPtr_t &); /// Attempt to change the priority of an earlier request. /// Request that Shadows HttpService's method @@ -130,7 +132,7 @@ public: /// sent on to the reply queue. /// /// Threading: called by worker thread - bool stageAfterCompletion(HttpOpRequest * op); + bool stageAfterCompletion(const opReqPtr_t &op); /// Get a reference to global policy options. Caller is expected /// to do context checks like no setting once running. These diff --git a/indra/llcorehttp/_httppolicyglobal.cpp b/indra/llcorehttp/_httppolicyglobal.cpp index 1dc95f3dce..3d0df96ade 100755 --- a/indra/llcorehttp/_httppolicyglobal.cpp +++ b/indra/llcorehttp/_httppolicyglobal.cpp @@ -106,6 +106,20 @@ HttpStatus HttpPolicyGlobal::set(HttpRequest::EPolicyOption opt, const std::stri return HttpStatus(); } +HttpStatus HttpPolicyGlobal::set(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback_t value) +{ + switch (opt) + { + case HttpRequest::PO_SSL_VERIFY_CALLBACK: + mSslCtxCallback = value; + break; + + default: + return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); + } + + return HttpStatus(); +} HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, long * value) const { @@ -154,4 +168,20 @@ HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, std::string * v return HttpStatus(); } + +HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback_t * value) const +{ + switch (opt) + { + case HttpRequest::PO_SSL_VERIFY_CALLBACK: + *value = mSslCtxCallback; + break; + + default: + return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); + } + + return HttpStatus(); +} + } // end namespace LLCore diff --git a/indra/llcorehttp/_httppolicyglobal.h b/indra/llcorehttp/_httppolicyglobal.h index 67c4ba9481..e02da4386a 100755 --- a/indra/llcorehttp/_httppolicyglobal.h +++ b/indra/llcorehttp/_httppolicyglobal.h @@ -60,8 +60,10 @@ private: public: HttpStatus set(HttpRequest::EPolicyOption opt, long value); HttpStatus set(HttpRequest::EPolicyOption opt, const std::string & value); + HttpStatus set(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback_t value); HttpStatus get(HttpRequest::EPolicyOption opt, long * value) const; HttpStatus get(HttpRequest::EPolicyOption opt, std::string * value) const; + HttpStatus get(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback_t * value) const; public: long mConnectionLimit; @@ -70,6 +72,7 @@ public: std::string mHttpProxy; long mTrace; long mUseLLProxy; + HttpRequest::policyCallback_t mSslCtxCallback; }; // end class HttpPolicyGlobal } // end namespace LLCore diff --git a/indra/llcorehttp/_httpreadyqueue.h b/indra/llcorehttp/_httpreadyqueue.h index 5f19a9c5f9..7418988ec1 100755 --- a/indra/llcorehttp/_httpreadyqueue.h +++ b/indra/llcorehttp/_httpreadyqueue.h @@ -56,12 +56,12 @@ namespace LLCore #if LLCORE_HTTP_READY_QUEUE_IGNORES_PRIORITY -typedef std::deque<HttpOpRequest *> HttpReadyQueueBase; +typedef std::deque<HttpOpRequest::ptr_t> HttpReadyQueueBase; #else -typedef std::priority_queue<HttpOpRequest *, - std::deque<HttpOpRequest *>, +typedef std::priority_queue<HttpOpRequest::ptr_t, + std::deque<HttpOpRequest::ptr_t>, LLCore::HttpOpRequestCompare> HttpReadyQueueBase; #endif // LLCORE_HTTP_READY_QUEUE_IGNORES_PRIORITY diff --git a/indra/llcorehttp/_httpreplyqueue.cpp b/indra/llcorehttp/_httpreplyqueue.cpp index 558b7bdee9..2b138f3ad5 100755 --- a/indra/llcorehttp/_httpreplyqueue.cpp +++ b/indra/llcorehttp/_httpreplyqueue.cpp @@ -39,23 +39,17 @@ namespace LLCore HttpReplyQueue::HttpReplyQueue() - : RefCounted(true) { } HttpReplyQueue::~HttpReplyQueue() { - while (! mQueue.empty()) - { - HttpOperation * op = mQueue.back(); - mQueue.pop_back(); - op->release(); - } + mQueue.clear(); } -void HttpReplyQueue::addOp(HttpOperation * op) +void HttpReplyQueue::addOp(const HttpReplyQueue::opPtr_t &op) { { HttpScopedLock lock(mQueueMutex); @@ -66,15 +60,15 @@ void HttpReplyQueue::addOp(HttpOperation * op) } -HttpOperation * HttpReplyQueue::fetchOp() +HttpReplyQueue::opPtr_t HttpReplyQueue::fetchOp() { - HttpOperation * result(NULL); + HttpOperation::ptr_t result; { HttpScopedLock lock(mQueueMutex); if (mQueue.empty()) - return NULL; + return opPtr_t(); result = mQueue.front(); mQueue.erase(mQueue.begin()); @@ -98,9 +92,6 @@ void HttpReplyQueue::fetchAll(OpContainer & ops) mQueue.swap(ops); } } - - // Caller also acquires the reference counts on each op. - return; } diff --git a/indra/llcorehttp/_httpreplyqueue.h b/indra/llcorehttp/_httpreplyqueue.h index 4220a09a3b..0e39e22dde 100755 --- a/indra/llcorehttp/_httpreplyqueue.h +++ b/indra/llcorehttp/_httpreplyqueue.h @@ -58,21 +58,19 @@ class HttpOperation; /// will be coded anyway so it shouldn't be too much of a /// burden. -class HttpReplyQueue : public LLCoreInt::RefCounted +class HttpReplyQueue : private boost::noncopyable { -public: - /// Caller acquires a Refcount on construction - HttpReplyQueue(); -protected: - virtual ~HttpReplyQueue(); // Use release() +public: + typedef boost::shared_ptr<HttpOperation> opPtr_t; + typedef boost::shared_ptr<HttpReplyQueue> ptr_t; -private: - HttpReplyQueue(const HttpReplyQueue &); // Not defined - void operator=(const HttpReplyQueue &); // Not defined + HttpReplyQueue(); + virtual ~HttpReplyQueue(); public: - typedef std::vector<HttpOperation *> OpContainer; + + typedef std::vector< opPtr_t > OpContainer; /// Insert an object at the back of the reply queue. /// @@ -80,7 +78,7 @@ public: /// through the queue. /// /// Threading: callable by any thread. - void addOp(HttpOperation * op); + void addOp(const opPtr_t &op); /// Fetch an operation from the head of the queue. Returns /// NULL if none exists. @@ -88,7 +86,7 @@ public: /// Caller acquires reference count on returned operation. /// /// Threading: callable by any thread. - HttpOperation * fetchOp(); + opPtr_t fetchOp(); /// Caller acquires reference count on each returned operation /// @@ -96,6 +94,7 @@ public: void fetchAll(OpContainer & ops); protected: + OpContainer mQueue; LLCoreInt::HttpMutex mQueueMutex; LLCoreInt::HttpConditionVariable mQueueCV; diff --git a/indra/llcorehttp/_httprequestqueue.cpp b/indra/llcorehttp/_httprequestqueue.cpp index c16966d078..c6f4ad789f 100755 --- a/indra/llcorehttp/_httprequestqueue.cpp +++ b/indra/llcorehttp/_httprequestqueue.cpp @@ -47,12 +47,7 @@ HttpRequestQueue::HttpRequestQueue() HttpRequestQueue::~HttpRequestQueue() { - while (! mQueue.empty()) - { - HttpOperation * op = mQueue.back(); - mQueue.pop_back(); - op->release(); - } + mQueue.clear(); } @@ -73,7 +68,7 @@ void HttpRequestQueue::term() } -HttpStatus HttpRequestQueue::addOp(HttpOperation * op) +HttpStatus HttpRequestQueue::addOp(const HttpRequestQueue::opPtr_t &op) { bool wake(false); { @@ -95,9 +90,9 @@ HttpStatus HttpRequestQueue::addOp(HttpOperation * op) } -HttpOperation * HttpRequestQueue::fetchOp(bool wait) +HttpRequestQueue::opPtr_t HttpRequestQueue::fetchOp(bool wait) { - HttpOperation * result(NULL); + HttpOperation::ptr_t result; { HttpScopedLock lock(mQueueMutex); @@ -105,7 +100,7 @@ HttpOperation * HttpRequestQueue::fetchOp(bool wait) while (mQueue.empty()) { if (! wait || mQueueStopped) - return NULL; + return HttpOperation::ptr_t(); mQueueCV.wait(lock); } diff --git a/indra/llcorehttp/_httprequestqueue.h b/indra/llcorehttp/_httprequestqueue.h index c9c52b7233..3c3d134b07 100755 --- a/indra/llcorehttp/_httprequestqueue.h +++ b/indra/llcorehttp/_httprequestqueue.h @@ -61,6 +61,8 @@ private: void operator=(const HttpRequestQueue &); // Not defined public: + typedef boost::shared_ptr<HttpOperation> opPtr_t; + static void init(); static void term(); @@ -71,7 +73,7 @@ public: } public: - typedef std::vector<HttpOperation *> OpContainer; + typedef std::vector<opPtr_t> OpContainer; /// Insert an object at the back of the request queue. /// @@ -83,7 +85,7 @@ public: /// an explicit release() call. /// /// Threading: callable by any thread. - HttpStatus addOp(HttpOperation * op); + HttpStatus addOp(const opPtr_t &op); /// Return the operation on the front of the queue. If /// the queue is empty and @wait is false, call returns @@ -95,7 +97,7 @@ public: /// Caller acquires reference count any returned operation /// /// Threading: callable by any thread. - HttpOperation * fetchOp(bool wait); + opPtr_t fetchOp(bool wait); /// Return all queued requests to caller. The @ops argument /// should be empty when called and will be swap()'d with diff --git a/indra/llcorehttp/_httpretryqueue.h b/indra/llcorehttp/_httpretryqueue.h index 745adec09d..5d8c529cff 100755 --- a/indra/llcorehttp/_httpretryqueue.h +++ b/indra/llcorehttp/_httpretryqueue.h @@ -49,15 +49,15 @@ namespace LLCore struct HttpOpRetryCompare { - bool operator()(const HttpOpRequest * lhs, const HttpOpRequest * rhs) + bool operator()(const HttpOpRequest::ptr_t &lhs, const HttpOpRequest::ptr_t &rhs) { return lhs->mPolicyRetryAt < rhs->mPolicyRetryAt; } }; -typedef std::priority_queue<HttpOpRequest *, - std::deque<HttpOpRequest *>, +typedef std::priority_queue<HttpOpRequest::ptr_t, + std::deque<HttpOpRequest::ptr_t>, LLCore::HttpOpRetryCompare> HttpRetryQueueBase; class HttpRetryQueue : public HttpRetryQueueBase diff --git a/indra/llcorehttp/_httpservice.cpp b/indra/llcorehttp/_httpservice.cpp index c673e1be1d..6c39fdc61b 100755 --- a/indra/llcorehttp/_httpservice.cpp +++ b/indra/llcorehttp/_httpservice.cpp @@ -53,15 +53,16 @@ namespace LLCore const HttpService::OptionDescriptor HttpService::sOptionDesc[] = { // isLong isDynamic isGlobal isClass - { true, true, true, true }, // PO_CONNECTION_LIMIT - { true, true, false, true }, // PO_PER_HOST_CONNECTION_LIMIT - { false, false, true, false }, // PO_CA_PATH - { false, false, true, false }, // PO_CA_FILE - { false, true, true, false }, // PO_HTTP_PROXY - { true, true, true, false }, // PO_LLPROXY - { true, true, true, false }, // PO_TRACE - { true, true, false, true }, // PO_ENABLE_PIPELINING - { true, true, false, true } // PO_THROTTLE_RATE + { true, true, true, true, false }, // PO_CONNECTION_LIMIT + { true, true, false, true, false }, // PO_PER_HOST_CONNECTION_LIMIT + { false, false, true, false, false }, // PO_CA_PATH + { false, false, true, false, false }, // PO_CA_FILE + { false, true, true, false, false }, // PO_HTTP_PROXY + { true, true, true, false, false }, // PO_LLPROXY + { true, true, true, false, false }, // PO_TRACE + { true, true, false, true, false }, // PO_ENABLE_PIPELINING + { true, true, false, true, false }, // PO_THROTTLE_RATE + { false, false, true, false, true } // PO_SSL_VERIFY_CALLBACK }; HttpService * HttpService::sInstance(NULL); volatile HttpService::EState HttpService::sState(NOT_INITIALIZED); @@ -262,14 +263,13 @@ void HttpService::shutdown() // Cancel requests already on the request queue HttpRequestQueue::OpContainer ops; mRequestQueue->fetchAll(false, ops); - while (! ops.empty()) - { - HttpOperation * op(ops.front()); - ops.erase(ops.begin()); - op->cancel(); - op->release(); - } + for (HttpRequestQueue::OpContainer::iterator it = ops.begin(); + it != ops.end(); ++it) + { + (*it)->cancel(); + } + ops.clear(); // Shutdown transport canceling requests, freeing resources mTransport->shutdown(); @@ -323,7 +323,7 @@ HttpService::ELoopSpeed HttpService::processRequestQueue(ELoopSpeed loop) mRequestQueue->fetchAll(wait_for_req, ops); while (! ops.empty()) { - HttpOperation * op(ops.front()); + HttpOperation::ptr_t op(ops.front()); ops.erase(ops.begin()); // Process operation @@ -337,7 +337,7 @@ HttpService::ELoopSpeed HttpService::processRequestQueue(ELoopSpeed loop) if (op->mTracing > HTTP_TRACE_OFF) { LL_INFOS(LOG_CORE) << "TRACE, FromRequestQueue, Handle: " - << static_cast<HttpHandle>(op) + << op->getHandle() << LL_ENDL; } @@ -346,7 +346,7 @@ HttpService::ELoopSpeed HttpService::processRequestQueue(ELoopSpeed loop) } // Done with operation - op->release(); + op.reset(); } // Queue emptied, allow polling loop to sleep @@ -413,6 +413,34 @@ HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequ return status; } +HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass, + HttpRequest::policyCallback_t * ret_value) +{ + HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG); + + if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range + || opt >= HttpRequest::PO_LAST // ditto + || (sOptionDesc[opt].mIsLong) // datatype is string + || (pclass != HttpRequest::GLOBAL_POLICY_ID && pclass > mLastPolicy) // pclass in valid range + || (pclass == HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsGlobal) // global setting permitted + || (pclass != HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsClass)) // class setting permitted + // can always get, no dynamic check + { + return status; + } + + // Only global has callback values + if (pclass == HttpRequest::GLOBAL_POLICY_ID) + { + HttpPolicyGlobal & opts(mPolicy->getGlobalOptions()); + + status = opts.get(opt, ret_value); + } + + return status; +} + + HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass, long value, long * ret_value) @@ -489,6 +517,37 @@ HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequ return status; } - + +HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass, + HttpRequest::policyCallback_t value, HttpRequest::policyCallback_t * ret_value) +{ + HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG); + + if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range + || opt >= HttpRequest::PO_LAST // ditto + || (sOptionDesc[opt].mIsLong) // datatype is string + || (pclass != HttpRequest::GLOBAL_POLICY_ID && pclass > mLastPolicy) // pclass in valid range + || (pclass == HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsGlobal) // global setting permitted + || (pclass != HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsClass) // class setting permitted + || (RUNNING == sState && !sOptionDesc[opt].mIsDynamic)) // dynamic setting permitted + { + return status; + } + + // Callbacks values are always global (at this time). + if (pclass == HttpRequest::GLOBAL_POLICY_ID) + { + HttpPolicyGlobal & opts(mPolicy->getGlobalOptions()); + + status = opts.set(opt, value); + if (status && ret_value) + { + status = opts.get(opt, ret_value); + } + } + + return status; +} + } // end namespace LLCore diff --git a/indra/llcorehttp/_httpservice.h b/indra/llcorehttp/_httpservice.h index cf23f3ab61..ac518a5de7 100755 --- a/indra/llcorehttp/_httpservice.h +++ b/indra/llcorehttp/_httpservice.h @@ -201,17 +201,24 @@ protected: bool mIsDynamic; bool mIsGlobal; bool mIsClass; + bool mIsCallback; }; HttpStatus getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t, long * ret_value); HttpStatus getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t, std::string * ret_value); + HttpStatus getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t, + HttpRequest::policyCallback_t * ret_value); + HttpStatus setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t, long value, long * ret_value); HttpStatus setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t, const std::string & value, std::string * ret_value); - + HttpStatus setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t, + HttpRequest::policyCallback_t value, + HttpRequest::policyCallback_t * ret_value); + protected: static const OptionDescriptor sOptionDesc[HttpRequest::PO_LAST]; static HttpService * sInstance; diff --git a/indra/llcorehttp/_refcounted.h b/indra/llcorehttp/_refcounted.h index 402e725152..7f713f2298 100755 --- a/indra/llcorehttp/_refcounted.h +++ b/indra/llcorehttp/_refcounted.h @@ -32,6 +32,7 @@ #include "fix_macros.h" #include <boost/thread.hpp> +#include <boost/intrusive_ptr.hpp> #include "llapr.h" @@ -120,7 +121,36 @@ inline void RefCounted::destroySelf() delete this; } +/** + * boost::intrusive_ptr may be used to manage RefCounted classes. + * Unfortunately RefCounted and boost::intrusive_ptr use different conventions + * for the initial refcount value. To avoid leaky (immortal) objects, you + * should really construct boost::intrusive_ptr<RefCounted*>(rawptr, false). + * IntrusivePtr<T> encapsulates that for you. + */ +template <typename T> +struct IntrusivePtr: public boost::intrusive_ptr<T> +{ + IntrusivePtr(): + boost::intrusive_ptr<T>() + {} + IntrusivePtr(T* p): + boost::intrusive_ptr<T>(p, false) + {} +}; + +inline void intrusive_ptr_add_ref(RefCounted* p) +{ + p->addRef(); +} + +inline void intrusive_ptr_release(RefCounted* p) +{ + p->release(); +} + } // end namespace LLCoreInt + #endif // LLCOREINT__REFCOUNTED_H_ diff --git a/indra/llcorehttp/bufferarray.h b/indra/llcorehttp/bufferarray.h index 1094a435b4..320adf2b8b 100755 --- a/indra/llcorehttp/bufferarray.h +++ b/indra/llcorehttp/bufferarray.h @@ -30,6 +30,7 @@ #include <cstdlib> #include <vector> +#include "boost/intrusive_ptr.hpp" #include "_refcounted.h" @@ -73,6 +74,8 @@ public: BufferArray(); + typedef LLCoreInt::IntrusivePtr<BufferArray> ptr_t; + protected: virtual ~BufferArray(); // Use release() @@ -129,6 +132,7 @@ protected: container_t mBlocks; size_t mLen; + }; // end class BufferArray diff --git a/indra/llcorehttp/examples/http_texture_load.cpp b/indra/llcorehttp/examples/http_texture_load.cpp index 9d9631b980..b91aaf0593 100755 --- a/indra/llcorehttp/examples/http_texture_load.cpp +++ b/indra/llcorehttp/examples/http_texture_load.cpp @@ -83,7 +83,7 @@ public: WorkingSet(); ~WorkingSet(); - bool reload(LLCore::HttpRequest *, LLCore::HttpOptions *); + bool reload(LLCore::HttpRequest *, LLCore::HttpOptions::ptr_t &); virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response); @@ -121,7 +121,7 @@ public: int mRetriesHttp503; int mSuccesses; long mByteCount; - LLCore::HttpHeaders * mHeaders; + LLCore::HttpHeaders::ptr_t mHeaders; }; @@ -304,7 +304,7 @@ int main(int argc, char** argv) LLCore::HttpRequest * hr = new LLCore::HttpRequest(); // Get request options - LLCore::HttpOptions * opt = new LLCore::HttpOptions(); + LLCore::HttpOptions::ptr_t opt = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()); opt->setRetries(12); opt->setUseRetryAfter(true); @@ -361,10 +361,9 @@ int main(int argc, char** argv) << std::endl; // Clean up - hr->requestStopThread(NULL); + hr->requestStopThread(LLCore::HttpHandler::ptr_t()); ms_sleep(1000); - opt->release(); - opt = NULL; + opt.reset(); delete hr; LLCore::HttpRequest::destroyService(); term_curl(); @@ -427,22 +426,22 @@ WorkingSet::WorkingSet() { mAssets.reserve(30000); - mHeaders = new LLCore::HttpHeaders; + mHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders); mHeaders->append("Accept", "image/x-j2c"); } WorkingSet::~WorkingSet() { - if (mHeaders) - { - mHeaders->release(); - mHeaders = NULL; - } } +namespace +{ + void NoOpDeletor(LLCore::HttpHandler *) + { /*NoOp*/ } +} -bool WorkingSet::reload(LLCore::HttpRequest * hr, LLCore::HttpOptions * opt) +bool WorkingSet::reload(LLCore::HttpRequest * hr, LLCore::HttpOptions::ptr_t & opt) { if (mRequestLowWater <= mHandles.size()) { @@ -470,11 +469,11 @@ bool WorkingSet::reload(LLCore::HttpRequest * hr, LLCore::HttpOptions * opt) LLCore::HttpHandle handle; if (offset || length) { - handle = hr->requestGetByteRange(0, 0, buffer, offset, length, opt, mHeaders, this); + handle = hr->requestGetByteRange(0, 0, buffer, offset, length, opt, mHeaders, LLCore::HttpHandler::ptr_t(this, NoOpDeletor)); } else { - handle = hr->requestGet(0, 0, buffer, opt, mHeaders, this); + handle = hr->requestGet(0, 0, buffer, opt, mHeaders, LLCore::HttpHandler::ptr_t(this, NoOpDeletor)); } if (! handle) { diff --git a/indra/llcorehttp/httpcommon.cpp b/indra/llcorehttp/httpcommon.cpp index 7907e958a4..c423047bb0 100755 --- a/indra/llcorehttp/httpcommon.cpp +++ b/indra/llcorehttp/httpcommon.cpp @@ -23,12 +23,24 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ +#if LL_WINDOWS +#define SAFE_SSL 1 +#elif LL_DARWIN +#define SAFE_SSL 1 +#else +#define SAFE_SSL 1 +#endif +#include "linden_common.h" // Modifies curl/curl.h interfaces #include "httpcommon.h" - +#include "llmutex.h" +#include "llthread.h" #include <curl/curl.h> #include <string> #include <sstream> +#if SAFE_SSL +#include <openssl/crypto.h> +#endif namespace LLCore @@ -42,7 +54,7 @@ HttpStatus::operator unsigned long() const { static const int shift(sizeof(unsigned long) * 4); - unsigned long result(((unsigned long) mType) << shift | (unsigned long) (int) mStatus); + unsigned long result(((unsigned long)mDetails->mType) << shift | (unsigned long)(int)mDetails->mStatus); return result; } @@ -131,30 +143,34 @@ std::string HttpStatus::toString() const { return std::string(""); } - switch (mType) + switch (getType()) { case EXT_CURL_EASY: - return std::string(curl_easy_strerror(CURLcode(mStatus))); + return std::string(curl_easy_strerror(CURLcode(getStatus()))); case EXT_CURL_MULTI: - return std::string(curl_multi_strerror(CURLMcode(mStatus))); + return std::string(curl_multi_strerror(CURLMcode(getStatus()))); case LLCORE: - if (mStatus >= 0 && mStatus < llcore_errors_count) + if (getStatus() >= 0 && getStatus() < llcore_errors_count) { - return std::string(llcore_errors[mStatus]); + return std::string(llcore_errors[getStatus()]); } break; default: if (isHttpStatus()) { + // special handling for status 499 "Linden Catchall" + if ((getType() == 499) && (!getMessage().empty())) + return getMessage(); + // Binary search for the error code and string int bottom(0), top(http_errors_count); while (true) { int at((bottom + top) / 2); - if (mType == http_errors[at].mCode) + if (getType() == http_errors[at].mCode) { return std::string(http_errors[at].mText); } @@ -162,7 +178,7 @@ std::string HttpStatus::toString() const { break; } - else if (mType < http_errors[at].mCode) + else if (getType() < http_errors[at].mCode) { top = at; } @@ -182,9 +198,9 @@ std::string HttpStatus::toTerseString() const { std::ostringstream result; - unsigned int error_value((unsigned short) mStatus); + unsigned int error_value((unsigned short)getStatus()); - switch (mType) + switch (getType()) { case EXT_CURL_EASY: result << "Easy_"; @@ -202,7 +218,7 @@ std::string HttpStatus::toTerseString() const if (isHttpStatus()) { result << "Http_"; - error_value = mType; + error_value = getType(); } else { @@ -244,7 +260,7 @@ bool HttpStatus::isRetryable() const // Disable the '*this == inv_status' test and look for 'Core_9' // failures in log files. - return ((isHttpStatus() && mType >= 499 && mType <= 599) || // Include special 499 in retryables + return ((isHttpStatus() && getType() >= 499 && getType() <= 599) || // Include special 499 in retryables *this == cant_connect || // Connection reset/endpoint problems *this == cant_res_proxy || // DNS problems *this == cant_res_host || // DNS problems @@ -259,5 +275,168 @@ bool HttpStatus::isRetryable() const *this == inv_cont_range); // Short data read disagrees with content-range } -} // end namespace LLCore +namespace LLHttp +{ +namespace +{ +typedef boost::shared_ptr<LLMutex> LLMutex_ptr; +std::vector<LLMutex_ptr> sSSLMutex; + +CURL *getCurlTemplateHandle() +{ + static CURL *curlpTemplateHandle = NULL; + + if (curlpTemplateHandle == NULL) + { // Late creation of the template curl handle + curlpTemplateHandle = curl_easy_init(); + if (curlpTemplateHandle == NULL) + { + LL_WARNS() << "curl error calling curl_easy_init()" << LL_ENDL; + } + else + { + CURLcode result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); + check_curl_code(result, CURLOPT_IPRESOLVE); + result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_NOSIGNAL, 1); + check_curl_code(result, CURLOPT_NOSIGNAL); + result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_NOPROGRESS, 1); + check_curl_code(result, CURLOPT_NOPROGRESS); + result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_ENCODING, ""); + check_curl_code(result, CURLOPT_ENCODING); + result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_AUTOREFERER, 1); + check_curl_code(result, CURLOPT_AUTOREFERER); + result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_FOLLOWLOCATION, 1); + check_curl_code(result, CURLOPT_FOLLOWLOCATION); + result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_SSL_VERIFYPEER, 1); + check_curl_code(result, CURLOPT_SSL_VERIFYPEER); + result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_SSL_VERIFYHOST, 0); + check_curl_code(result, CURLOPT_SSL_VERIFYHOST); + + // The Linksys WRT54G V5 router has an issue with frequent + // DNS lookups from LAN machines. If they happen too often, + // like for every HTTP request, the router gets annoyed after + // about 700 or so requests and starts issuing TCP RSTs to + // new connections. Reuse the DNS lookups for even a few + // seconds and no RSTs. + result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_DNS_CACHE_TIMEOUT, 15); + check_curl_code(result, CURLOPT_DNS_CACHE_TIMEOUT); + } + } + + return curlpTemplateHandle; +} + +LLMutex *getCurlMutex() +{ + static LLMutex* sHandleMutexp = NULL; + + if (!sHandleMutexp) + { + sHandleMutexp = new LLMutex(NULL); + } + + return sHandleMutexp; +} + +void deallocateEasyCurl(CURL *curlp) +{ + LLMutexLock lock(getCurlMutex()); + + curl_easy_cleanup(curlp); +} + + +#if SAFE_SSL +//static +void ssl_locking_callback(int mode, int type, const char *file, int line) +{ + if (type >= sSSLMutex.size()) + { + LL_WARNS() << "Attempt to get unknown MUTEX in SSL Lock." << LL_ENDL; + } + + if (mode & CRYPTO_LOCK) + { + sSSLMutex[type]->lock(); + } + else + { + sSSLMutex[type]->unlock(); + } +} + +//static +unsigned long ssl_thread_id(void) +{ + return LLThread::currentID(); +} +#endif + +} + +void initialize() +{ + // Do not change this "unless you are familiar with and mean to control + // internal operations of libcurl" + // - http://curl.haxx.se/libcurl/c/curl_global_init.html + CURLcode code = curl_global_init(CURL_GLOBAL_ALL); + + check_curl_code(code, CURL_GLOBAL_ALL); + +#if SAFE_SSL + S32 mutex_count = CRYPTO_num_locks(); + for (S32 i = 0; i < mutex_count; i++) + { + sSSLMutex.push_back(LLMutex_ptr(new LLMutex(NULL))); + } + CRYPTO_set_id_callback(&ssl_thread_id); + CRYPTO_set_locking_callback(&ssl_locking_callback); +#endif + +} + + +void cleanup() +{ +#if SAFE_SSL + CRYPTO_set_id_callback(NULL); + CRYPTO_set_locking_callback(NULL); + sSSLMutex.clear(); +#endif + + curl_global_cleanup(); +} + + +CURL_ptr createEasyHandle() +{ + LLMutexLock lock(getCurlMutex()); + + CURL* handle = curl_easy_duphandle(getCurlTemplateHandle()); + + return CURL_ptr(handle, &deallocateEasyCurl); +} + +std::string getCURLVersion() +{ + return std::string(curl_version()); +} + +void check_curl_code(CURLcode code, int curl_setopt_option) +{ + if (CURLE_OK != code) + { + // Comment from old llcurl code which may no longer apply: + // + // linux appears to throw a curl error once per session for a bad initialization + // at a pretty random time (when enabling cookies). + LL_WARNS() << "libcurl error detected: " << curl_easy_strerror(code) + << ", curl_easy_setopt option: " << curl_setopt_option + << LL_ENDL; + } + +} + +} +} // end namespace LLCore diff --git a/indra/llcorehttp/httpcommon.h b/indra/llcorehttp/httpcommon.h index 9601f94125..b2db01d038 100755 --- a/indra/llcorehttp/httpcommon.h +++ b/indra/llcorehttp/httpcommon.h @@ -188,9 +188,12 @@ /// #include "linden_common.h" // Modifies curl/curl.h interfaces - +#include "boost/intrusive_ptr.hpp" +#include "boost/shared_ptr.hpp" +#include "boost/weak_ptr.hpp" +#include "boost/function.hpp" #include <string> - +#include <curl/curl.h> namespace LLCore { @@ -206,6 +209,7 @@ namespace LLCore /// becomes invalid and may be recycled for other queued requests. typedef void * HttpHandle; + #define LLCORE_HTTP_HANDLE_INVALID (NULL) /// For internal scheduling and metrics, we use a microsecond @@ -286,52 +290,63 @@ enum HttpError /// 5. Construct an HTTP 301 status code to be treated as success: /// HttpStatus(301, HE_SUCCESS); /// +/// 6. Construct a failed status of HTTP Status 499 with a custom error message +/// HttpStatus(499, "Failed LLSD Response"); struct HttpStatus { typedef unsigned short type_enum_t; HttpStatus() - : mType(LLCORE), - mStatus(HE_SUCCESS) - {} + { + mDetails = boost::shared_ptr<Details>(new Details(LLCORE, HE_SUCCESS)); + } HttpStatus(type_enum_t type, short status) - : mType(type), - mStatus(status) - {} + { + mDetails = boost::shared_ptr<Details>(new Details(type, status)); + } HttpStatus(int http_status) - : mType(http_status), - mStatus(http_status >= 200 && http_status <= 299 - ? HE_SUCCESS - : HE_REPLY_ERROR) - { - llassert(http_status >= 100 && http_status <= 999); - } + { + mDetails = boost::shared_ptr<Details>(new Details(http_status, + (http_status >= 200 && http_status <= 299) ? HE_SUCCESS : HE_REPLY_ERROR)); + llassert(http_status >= 100 && http_status <= 999); + } + + HttpStatus(int http_status, const std::string &message) + { + mDetails = boost::shared_ptr<Details>(new Details(http_status, + (http_status >= 200 && http_status <= 299) ? HE_SUCCESS : HE_REPLY_ERROR)); + llassert(http_status >= 100 && http_status <= 999); + mDetails->mMessage = message; + } HttpStatus(const HttpStatus & rhs) - : mType(rhs.mType), - mStatus(rhs.mStatus) - {} + { + mDetails = rhs.mDetails; + } + + ~HttpStatus() + { + } HttpStatus & operator=(const HttpStatus & rhs) - { - // Don't care if lhs & rhs are the same object + { + mDetails = rhs.mDetails; + return *this; + } - mType = rhs.mType; - mStatus = rhs.mStatus; - return *this; - } + HttpStatus & clone(const HttpStatus &rhs) + { + mDetails = boost::shared_ptr<Details>(new Details(*rhs.mDetails)); + return *this; + } static const type_enum_t EXT_CURL_EASY = 0; ///< mStatus is an error from a curl_easy_*() call static const type_enum_t EXT_CURL_MULTI = 1; ///< mStatus is an error from a curl_multi_*() call static const type_enum_t LLCORE = 2; ///< mStatus is an HE_* error code ///< 100-999 directly represent HTTP status codes - - type_enum_t mType; - short mStatus; - /// Test for successful status in the code regardless /// of error source (internal, libcurl). /// @@ -339,7 +354,7 @@ struct HttpStatus /// operator bool() const { - return 0 == mStatus; + return 0 == mDetails->mStatus; } /// Inverse of previous operator. @@ -347,14 +362,14 @@ struct HttpStatus /// @return 'true' on any error condition bool operator !() const { - return 0 != mStatus; + return 0 != mDetails->mStatus; } /// Equality and inequality tests to bypass bool conversion /// which will do the wrong thing in conditional expressions. bool operator==(const HttpStatus & rhs) const { - return mType == rhs.mType && mStatus == rhs.mStatus; + return (*mDetails == *rhs.mDetails); } bool operator!=(const HttpStatus & rhs) const @@ -395,7 +410,7 @@ struct HttpStatus /// HTTP response status (100 - 999). bool isHttpStatus() const { - return mType >= type_enum_t(100) && mType <= type_enum_t(999); + return mDetails->mType >= type_enum_t(100) && mDetails->mType <= type_enum_t(999); } /// Returns true if the status is one that will be retried @@ -403,9 +418,94 @@ struct HttpStatus /// where that logic needs to be replicated. Only applies /// to failed statuses, successful statuses will return false. bool isRetryable() const; - + + /// Returns the currently set status code as a raw number + /// + short getStatus() const + { + return mDetails->mStatus; + } + + /// Returns the currently set status type + /// + type_enum_t getType() const + { + return mDetails->mType; + } + + /// Returns an optional error message if one has been set. + /// + std::string getMessage() const + { + return mDetails->mMessage; + } + + /// Sets an optional error message + /// + void setMessage(const std::string &message) + { + mDetails->mMessage = message; + } + + /// Retrieves an optionally recorded SSL certificate. + void * getErrorData() const + { + return mDetails->mErrorData; + } + + /// Optionally sets an SSL certificate on this status. + void setErrorData(void *data) + { + mDetails->mErrorData = data; + } + +private: + + struct Details + { + Details(type_enum_t type, short status): + mType(type), + mStatus(status), + mMessage(), + mErrorData(NULL) + {} + + Details(const Details &rhs) : + mType(rhs.mType), + mStatus(rhs.mStatus), + mMessage(rhs.mMessage), + mErrorData(rhs.mErrorData) + {} + + bool operator == (const Details &rhs) const + { + return (mType == rhs.mType) && (mStatus == rhs.mStatus); + } + + type_enum_t mType; + short mStatus; + std::string mMessage; + void * mErrorData; + }; + + boost::shared_ptr<Details> mDetails; + }; // end struct HttpStatus +/// A namespace for several free methods and low level utilities. +namespace LLHttp +{ + typedef boost::shared_ptr<CURL> CURL_ptr; + + void initialize(); + void cleanup(); + + CURL_ptr createEasyHandle(); + std::string getCURLVersion(); + + void check_curl_code(CURLcode code, int curl_setopt_option); +} + } // end namespace LLCore #endif // _LLCORE_HTTP_COMMON_H_ diff --git a/indra/llcorehttp/httphandler.h b/indra/llcorehttp/httphandler.h index 9171e4e7b9..65e043f5d3 100755 --- a/indra/llcorehttp/httphandler.h +++ b/indra/llcorehttp/httphandler.h @@ -45,7 +45,7 @@ class HttpResponse; /// be shared by any number of requests and across instances /// of HttpRequest running in the same thread. /// -/// Threading: HttpHandler itself is pure interface and is +/// Threading: HttpHandler itself is interface and is /// tread-compatible. Most derivations, however, will have /// different constraints. /// @@ -53,12 +53,16 @@ class HttpResponse; /// that is rarely a good idea. Queued requests and replies keep /// a naked pointer to the handler and this can result in a /// dangling pointer if lifetimes aren't managed correctly. - -class HttpHandler +/// +/// *TODO: public std::enable_shared_from_this<HttpHandler> +class HttpHandler { public: + typedef boost::shared_ptr<HttpHandler> ptr_t; + typedef boost::weak_ptr<HttpHandler> wptr_t; + virtual ~HttpHandler() - {} + { } /// Method invoked during calls to @see update(). Each invocation /// represents the completion of some requested operation. Caller diff --git a/indra/llcorehttp/httpheaders.cpp b/indra/llcorehttp/httpheaders.cpp index 23ebea361c..f586191a7c 100755 --- a/indra/llcorehttp/httpheaders.cpp +++ b/indra/llcorehttp/httpheaders.cpp @@ -34,7 +34,6 @@ namespace LLCore HttpHeaders::HttpHeaders() - : RefCounted(true) {} @@ -105,7 +104,7 @@ void HttpHeaders::appendNormal(const char * header, size_t size) // Find from end to simulate a tradition of using single-valued // std::map for this in the past. -const std::string * HttpHeaders::find(const char * name) const +const std::string * HttpHeaders::find(const std::string &name) const { const_reverse_iterator iend(rend()); for (const_reverse_iterator iter(rbegin()); iend != iter; ++iter) @@ -118,6 +117,24 @@ const std::string * HttpHeaders::find(const char * name) const return NULL; } +void HttpHeaders::remove(const char *name) +{ + remove(std::string(name)); +} + +void HttpHeaders::remove(const std::string &name) +{ + iterator iend(end()); + for (iterator iter(begin()); iend != iter; ++iter) + { + if ((*iter).first == name) + { + mHeaders.erase(iter); + return; + } + } +} + // Standard Iterators HttpHeaders::iterator HttpHeaders::begin() diff --git a/indra/llcorehttp/httpheaders.h b/indra/llcorehttp/httpheaders.h index f70cd898f3..b9168cb6ec 100755 --- a/indra/llcorehttp/httpheaders.h +++ b/indra/llcorehttp/httpheaders.h @@ -28,8 +28,8 @@ #define _LLCORE_HTTP_HEADERS_H_ +#include "httpcommon.h" #include <string> - #include "_refcounted.h" @@ -74,7 +74,7 @@ namespace LLCore /// constructor is given a refcount. /// -class HttpHeaders : public LLCoreInt::RefCounted +class HttpHeaders: private boost::noncopyable { public: typedef std::pair<std::string, std::string> header_t; @@ -85,15 +85,17 @@ public: typedef container_t::const_reverse_iterator const_reverse_iterator; typedef container_t::value_type value_type; typedef container_t::size_type size_type; + typedef boost::shared_ptr<HttpHeaders> ptr_t; public: /// @post In addition to the instance, caller has a refcount /// to the instance. A call to @see release() will destroy /// the instance. HttpHeaders(); + virtual ~HttpHeaders(); // Use release() + //typedef LLCoreInt::IntrusivePtr<HttpHeaders> ptr_t; protected: - virtual ~HttpHeaders(); // Use release() HttpHeaders(const HttpHeaders &); // Not defined void operator=(const HttpHeaders &); // Not defined @@ -145,8 +147,16 @@ public: // a pointer to a std::string in the container. // Pointer is valid only for the lifetime of // the container or until container is modifed. - // - const std::string * find(const char * name) const; + const std::string * find(const std::string &name) const; + const std::string * find(const char * name) const + { + return find(std::string(name)); + } + + // Remove the header from the list if found. + // + void remove(const std::string &name); + void remove(const char *name); // Count of headers currently in the list. size_type size() const diff --git a/indra/llcorehttp/httpoptions.cpp b/indra/llcorehttp/httpoptions.cpp index 5bf1ecb4a5..aab447f2dd 100755 --- a/indra/llcorehttp/httpoptions.cpp +++ b/indra/llcorehttp/httpoptions.cpp @@ -25,7 +25,7 @@ */ #include "httpoptions.h" - +#include "lldefs.h" #include "_httpinternal.h" @@ -33,14 +33,18 @@ namespace LLCore { -HttpOptions::HttpOptions() - : RefCounted(true), - mWantHeaders(false), - mTracing(HTTP_TRACE_OFF), - mTimeout(HTTP_REQUEST_TIMEOUT_DEFAULT), - mTransferTimeout(HTTP_REQUEST_XFER_TIMEOUT_DEFAULT), - mRetries(HTTP_RETRY_COUNT_DEFAULT), - mUseRetryAfter(HTTP_USE_RETRY_AFTER_DEFAULT) +HttpOptions::HttpOptions() : + mWantHeaders(false), + mTracing(HTTP_TRACE_OFF), + mTimeout(HTTP_REQUEST_TIMEOUT_DEFAULT), + mTransferTimeout(HTTP_REQUEST_XFER_TIMEOUT_DEFAULT), + mRetries(HTTP_RETRY_COUNT_DEFAULT), + mUseRetryAfter(HTTP_USE_RETRY_AFTER_DEFAULT), + mFollowRedirects(true), + mVerifyPeer(false), + mVerifyHost(false), + mDNSCacheTimeout(-1L), + mNoBody(false) {} @@ -82,5 +86,31 @@ void HttpOptions::setUseRetryAfter(bool use_retry) mUseRetryAfter = use_retry; } +void HttpOptions::setFollowRedirects(bool follow_redirect) +{ + mFollowRedirects = follow_redirect; +} + +void HttpOptions::setSSLVerifyPeer(bool verify) +{ + mVerifyPeer = verify; +} + +void HttpOptions::setSSLVerifyHost(bool verify) +{ + mVerifyHost = verify; +} + +void HttpOptions::setDNSCacheTimeout(int timeout) +{ + mDNSCacheTimeout = timeout; +} + +void HttpOptions::setHeadersOnly(bool nobody) +{ + mNoBody = nobody; + if (mNoBody) + setWantHeaders(true); +} } // end namespace LLCore diff --git a/indra/llcorehttp/httpoptions.h b/indra/llcorehttp/httpoptions.h index 4ab5ff18c4..510eaa45bb 100755 --- a/indra/llcorehttp/httpoptions.h +++ b/indra/llcorehttp/httpoptions.h @@ -29,7 +29,6 @@ #include "httpcommon.h" - #include "_refcounted.h" @@ -56,59 +55,110 @@ namespace LLCore /// Allocation: Refcounted, heap only. Caller of the constructor /// is given a refcount. /// -class HttpOptions : public LLCoreInt::RefCounted +class HttpOptions : private boost::noncopyable { public: HttpOptions(); + typedef boost::shared_ptr<HttpOptions> ptr_t; + + virtual ~HttpOptions(); // Use release() + protected: - virtual ~HttpOptions(); // Use release() HttpOptions(const HttpOptions &); // Not defined void operator=(const HttpOptions &); // Not defined public: + // Default: false void setWantHeaders(bool wanted); bool getWantHeaders() const - { - return mWantHeaders; - } + { + return mWantHeaders; + } // Default: 0 void setTrace(int long); int getTrace() const - { - return mTracing; - } + { + return mTracing; + } // Default: 30 void setTimeout(unsigned int timeout); unsigned int getTimeout() const - { - return mTimeout; - } + { + return mTimeout; + } // Default: 0 void setTransferTimeout(unsigned int timeout); unsigned int getTransferTimeout() const - { - return mTransferTimeout; - } + { + return mTransferTimeout; + } + /// Sets the number of retries on an LLCore::HTTPRequest before the + /// request fails. // Default: 8 void setRetries(unsigned int retries); unsigned int getRetries() const - { - return mRetries; - } + { + return mRetries; + } // Default: true void setUseRetryAfter(bool use_retry); bool getUseRetryAfter() const - { - return mUseRetryAfter; - } + { + return mUseRetryAfter; + } + + /// Instructs the LLCore::HTTPRequest to follow redirects + /// Default: false + void setFollowRedirects(bool follow_redirect); + bool getFollowRedirects() const + { + return mFollowRedirects; + } + + /// Instructs the LLCore::HTTPRequest to verify that the exchanged security + /// certificate is authentic. + /// Default: false + void setSSLVerifyPeer(bool verify); + bool getSSLVerifyPeer() const + { + return mVerifyPeer; + } + + /// Instructs the LLCore::HTTPRequest to verify that the name in the + /// security certificate matches the name of the host contacted. + /// Default: false + void setSSLVerifyHost(bool verify); + bool getSSLVerifyHost() const + { + return mVerifyHost; + } + + /// Sets the time for DNS name caching in seconds. Setting this value + /// to 0 will disable name caching. Setting this value to -1 causes the + /// name cache to never time out. + /// Default: -1 + void setDNSCacheTimeout(int timeout); + int getDNSCacheTimeout() const + { + return mDNSCacheTimeout; + } + + /// Retrieve only the headers and status from the request. Setting this + /// to true implies setWantHeaders(true) as well. + /// Default: false + void setHeadersOnly(bool nobody); + bool getHeadersOnly() const + { + return mNoBody; + } protected: bool mWantHeaders; @@ -117,6 +167,11 @@ protected: unsigned int mTransferTimeout; unsigned int mRetries; bool mUseRetryAfter; + bool mFollowRedirects; + bool mVerifyPeer; + bool mVerifyHost; + int mDNSCacheTimeout; + bool mNoBody; }; // end class HttpOptions diff --git a/indra/llcorehttp/httprequest.cpp b/indra/llcorehttp/httprequest.cpp index 7b1888e3eb..e09f0c3b18 100755 --- a/indra/llcorehttp/httprequest.cpp +++ b/indra/llcorehttp/httprequest.cpp @@ -55,13 +55,13 @@ namespace LLCore HttpRequest::HttpRequest() - : mReplyQueue(NULL), + : mReplyQueue(), mRequestQueue(NULL) { mRequestQueue = HttpRequestQueue::instanceOf(); mRequestQueue->addRef(); - mReplyQueue = new HttpReplyQueue(); + mReplyQueue.reset( new HttpReplyQueue() ); } @@ -73,11 +73,7 @@ HttpRequest::~HttpRequest() mRequestQueue = NULL; } - if (mReplyQueue) - { - mReplyQueue->release(); - mReplyQueue = NULL; - } + mReplyQueue.reset(); } @@ -117,60 +113,59 @@ HttpStatus HttpRequest::setStaticPolicyOption(EPolicyOption opt, policy_t pclass return HttpService::instanceOf()->setPolicyOption(opt, pclass, value, ret_value); } +HttpStatus HttpRequest::setStaticPolicyOption(EPolicyOption opt, policy_t pclass, policyCallback_t value, policyCallback_t * ret_value) +{ + if (HttpService::RUNNING == HttpService::instanceOf()->getState()) + { + return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC); + } + + return HttpService::instanceOf()->setPolicyOption(opt, pclass, value, ret_value); +} HttpHandle HttpRequest::setPolicyOption(EPolicyOption opt, policy_t pclass, - long value, HttpHandler * handler) + long value, HttpHandler::ptr_t handler) { HttpStatus status; - HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); - HttpOpSetGet * op = new HttpOpSetGet(); + HttpOpSetGet::ptr_t op(new HttpOpSetGet()); if (! (status = op->setupSet(opt, pclass, value))) { - op->release(); mLastReqStatus = status; - return handle; + return LLCORE_HTTP_HANDLE_INVALID; } op->setReplyPath(mReplyQueue, handler); if (! (status = mRequestQueue->addOp(op))) // transfers refcount { - op->release(); mLastReqStatus = status; - return handle; + return LLCORE_HTTP_HANDLE_INVALID; } mLastReqStatus = status; - handle = static_cast<HttpHandle>(op); - - return handle; + return op->getHandle(); } HttpHandle HttpRequest::setPolicyOption(EPolicyOption opt, policy_t pclass, - const std::string & value, HttpHandler * handler) + const std::string & value, HttpHandler::ptr_t handler) { HttpStatus status; - HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); - HttpOpSetGet * op = new HttpOpSetGet(); + HttpOpSetGet::ptr_t op (new HttpOpSetGet()); if (! (status = op->setupSet(opt, pclass, value))) { - op->release(); mLastReqStatus = status; - return handle; + return LLCORE_HTTP_HANDLE_INVALID; } op->setReplyPath(mReplyQueue, handler); if (! (status = mRequestQueue->addOp(op))) // transfers refcount { - op->release(); mLastReqStatus = status; - return handle; + return LLCORE_HTTP_HANDLE_INVALID; } mLastReqStatus = status; - handle = static_cast<HttpHandle>(op); - - return handle; + return op->getHandle(); } @@ -188,32 +183,27 @@ HttpStatus HttpRequest::getStatus() const HttpHandle HttpRequest::requestGet(policy_t policy_id, priority_t priority, const std::string & url, - HttpOptions * options, - HttpHeaders * headers, - HttpHandler * user_handler) + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers, + HttpHandler::ptr_t user_handler) { HttpStatus status; - HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); - HttpOpRequest * op = new HttpOpRequest(); + HttpOpRequest::ptr_t op(new HttpOpRequest()); if (! (status = op->setupGet(policy_id, priority, url, options, headers))) { - op->release(); mLastReqStatus = status; - return handle; + return LLCORE_HTTP_HANDLE_INVALID; } op->setReplyPath(mReplyQueue, user_handler); if (! (status = mRequestQueue->addOp(op))) // transfers refcount { - op->release(); mLastReqStatus = status; - return handle; + return LLCORE_HTTP_HANDLE_INVALID; } mLastReqStatus = status; - handle = static_cast<HttpHandle>(op); - - return handle; + return op->getHandle(); } @@ -222,32 +212,27 @@ HttpHandle HttpRequest::requestGetByteRange(policy_t policy_id, const std::string & url, size_t offset, size_t len, - HttpOptions * options, - HttpHeaders * headers, - HttpHandler * user_handler) + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers, + HttpHandler::ptr_t user_handler) { HttpStatus status; - HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); - HttpOpRequest * op = new HttpOpRequest(); + HttpOpRequest::ptr_t op(new HttpOpRequest()); if (! (status = op->setupGetByteRange(policy_id, priority, url, offset, len, options, headers))) { - op->release(); mLastReqStatus = status; - return handle; + return LLCORE_HTTP_HANDLE_INVALID; } op->setReplyPath(mReplyQueue, user_handler); if (! (status = mRequestQueue->addOp(op))) // transfers refcount { - op->release(); mLastReqStatus = status; - return handle; + return LLCORE_HTTP_HANDLE_INVALID; } mLastReqStatus = status; - handle = static_cast<HttpHandle>(op); - - return handle; + return op->getHandle(); } @@ -255,32 +240,27 @@ HttpHandle HttpRequest::requestPost(policy_t policy_id, priority_t priority, const std::string & url, BufferArray * body, - HttpOptions * options, - HttpHeaders * headers, - HttpHandler * user_handler) + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers, + HttpHandler::ptr_t user_handler) { HttpStatus status; - HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); - HttpOpRequest * op = new HttpOpRequest(); + HttpOpRequest::ptr_t op(new HttpOpRequest()); if (! (status = op->setupPost(policy_id, priority, url, body, options, headers))) { - op->release(); mLastReqStatus = status; - return handle; + return LLCORE_HTTP_HANDLE_INVALID; } op->setReplyPath(mReplyQueue, user_handler); if (! (status = mRequestQueue->addOp(op))) // transfers refcount { - op->release(); mLastReqStatus = status; - return handle; + return LLCORE_HTTP_HANDLE_INVALID; } mLastReqStatus = status; - handle = static_cast<HttpHandle>(op); - - return handle; + return op->getHandle(); } @@ -288,59 +268,156 @@ HttpHandle HttpRequest::requestPut(policy_t policy_id, priority_t priority, const std::string & url, BufferArray * body, - HttpOptions * options, - HttpHeaders * headers, - HttpHandler * user_handler) + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers, + HttpHandler::ptr_t user_handler) { HttpStatus status; - HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); - HttpOpRequest * op = new HttpOpRequest(); + HttpOpRequest::ptr_t op (new HttpOpRequest()); if (! (status = op->setupPut(policy_id, priority, url, body, options, headers))) { - op->release(); mLastReqStatus = status; - return handle; + return LLCORE_HTTP_HANDLE_INVALID; } op->setReplyPath(mReplyQueue, user_handler); if (! (status = mRequestQueue->addOp(op))) // transfers refcount { - op->release(); mLastReqStatus = status; - return handle; + return LLCORE_HTTP_HANDLE_INVALID; } mLastReqStatus = status; - handle = static_cast<HttpHandle>(op); - - return handle; + return op->getHandle(); } +HttpHandle HttpRequest::requestDelete(policy_t policy_id, + priority_t priority, + const std::string & url, + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers, + HttpHandler::ptr_t user_handler) +{ + HttpStatus status; + + HttpOpRequest::ptr_t op(new HttpOpRequest()); + if (!(status = op->setupDelete(policy_id, priority, url, options, headers))) + { + mLastReqStatus = status; + return LLCORE_HTTP_HANDLE_INVALID; + } + op->setReplyPath(mReplyQueue, user_handler); + if (!(status = mRequestQueue->addOp(op))) // transfers refcount + { + mLastReqStatus = status; + return LLCORE_HTTP_HANDLE_INVALID; + } + + mLastReqStatus = status; + return op->getHandle(); +} + +HttpHandle HttpRequest::requestPatch(policy_t policy_id, + priority_t priority, + const std::string & url, + BufferArray * body, + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers, + HttpHandler::ptr_t user_handler) +{ + HttpStatus status; + + HttpOpRequest::ptr_t op (new HttpOpRequest()); + if (!(status = op->setupPatch(policy_id, priority, url, body, options, headers))) + { + mLastReqStatus = status; + return LLCORE_HTTP_HANDLE_INVALID; + } + op->setReplyPath(mReplyQueue, user_handler); + if (!(status = mRequestQueue->addOp(op))) // transfers refcount + { + mLastReqStatus = status; + return LLCORE_HTTP_HANDLE_INVALID; + } + + mLastReqStatus = status; + return op->getHandle(); +} -HttpHandle HttpRequest::requestNoOp(HttpHandler * user_handler) +HttpHandle HttpRequest::requestCopy(policy_t policy_id, + priority_t priority, + const std::string & url, + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers, + HttpHandler::ptr_t user_handler) +{ + HttpStatus status; + + HttpOpRequest::ptr_t op(new HttpOpRequest()); + if (!(status = op->setupCopy(policy_id, priority, url, options, headers))) + { + mLastReqStatus = status; + return LLCORE_HTTP_HANDLE_INVALID; + } + op->setReplyPath(mReplyQueue, user_handler); + if (!(status = mRequestQueue->addOp(op))) // transfers refcount + { + mLastReqStatus = status; + return LLCORE_HTTP_HANDLE_INVALID; + } + + mLastReqStatus = status; + return op->getHandle(); + +} + +HttpHandle HttpRequest::requestMove(policy_t policy_id, + priority_t priority, + const std::string & url, + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers, + HttpHandler::ptr_t user_handler) +{ + HttpStatus status; + + HttpOpRequest::ptr_t op (new HttpOpRequest()); + if (!(status = op->setupMove(policy_id, priority, url, options, headers))) + { + mLastReqStatus = status; + return LLCORE_HTTP_HANDLE_INVALID; + } + op->setReplyPath(mReplyQueue, user_handler); + if (!(status = mRequestQueue->addOp(op))) // transfers refcount + { + mLastReqStatus = status; + return LLCORE_HTTP_HANDLE_INVALID; + } + + mLastReqStatus = status; + return op->getHandle(); +} + + +HttpHandle HttpRequest::requestNoOp(HttpHandler::ptr_t user_handler) { HttpStatus status; - HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); - HttpOpNull * op = new HttpOpNull(); + HttpOperation::ptr_t op (new HttpOpNull()); op->setReplyPath(mReplyQueue, user_handler); if (! (status = mRequestQueue->addOp(op))) // transfers refcount { - op->release(); mLastReqStatus = status; - return handle; + return LLCORE_HTTP_HANDLE_INVALID; } mLastReqStatus = status; - handle = static_cast<HttpHandle>(op); - - return handle; + return op->getHandle(); } HttpStatus HttpRequest::update(long usecs) { - HttpOperation * op(NULL); + HttpOperation::ptr_t op; if (usecs) { @@ -351,7 +428,7 @@ HttpStatus HttpRequest::update(long usecs) op->visitNotifier(this); // We're done with the operation - op->release(); + op.reset(); } } else @@ -366,13 +443,13 @@ HttpStatus HttpRequest::update(long usecs) ++iter) { // Swap op pointer for NULL; - op = *iter; *iter = NULL; + op.reset(); + op.swap(*iter); // Process operation op->visitNotifier(this); // We're done with the operation - op->release(); } } } @@ -387,46 +464,38 @@ HttpStatus HttpRequest::update(long usecs) // Request Management Methods // ==================================== -HttpHandle HttpRequest::requestCancel(HttpHandle request, HttpHandler * user_handler) +HttpHandle HttpRequest::requestCancel(HttpHandle request, HttpHandler::ptr_t user_handler) { HttpStatus status; - HttpHandle ret_handle(LLCORE_HTTP_HANDLE_INVALID); - HttpOpCancel * op = new HttpOpCancel(request); + HttpOperation::ptr_t op(new HttpOpCancel(request)); op->setReplyPath(mReplyQueue, user_handler); if (! (status = mRequestQueue->addOp(op))) // transfers refcount { - op->release(); mLastReqStatus = status; - return ret_handle; + return LLCORE_HTTP_HANDLE_INVALID; } mLastReqStatus = status; - ret_handle = static_cast<HttpHandle>(op); - - return ret_handle; + return op->getHandle(); } HttpHandle HttpRequest::requestSetPriority(HttpHandle request, priority_t priority, - HttpHandler * handler) + HttpHandler::ptr_t handler) { HttpStatus status; - HttpHandle ret_handle(LLCORE_HTTP_HANDLE_INVALID); - HttpOpSetPriority * op = new HttpOpSetPriority(request, priority); + HttpOperation::ptr_t op (new HttpOpSetPriority(request, priority)); op->setReplyPath(mReplyQueue, handler); if (! (status = mRequestQueue->addOp(op))) // transfers refcount { - op->release(); mLastReqStatus = status; - return ret_handle; + return LLCORE_HTTP_HANDLE_INVALID; } mLastReqStatus = status; - ret_handle = static_cast<HttpHandle>(op); - - return ret_handle; + return op->getHandle(); } @@ -475,22 +544,21 @@ HttpStatus HttpRequest::startThread() } -HttpHandle HttpRequest::requestStopThread(HttpHandler * user_handler) +HttpHandle HttpRequest::requestStopThread(HttpHandler::ptr_t user_handler) { HttpStatus status; HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); - HttpOpStop * op = new HttpOpStop(); + HttpOperation::ptr_t op(new HttpOpStop()); op->setReplyPath(mReplyQueue, user_handler); if (! (status = mRequestQueue->addOp(op))) // transfers refcount { - op->release(); mLastReqStatus = status; return handle; } mLastReqStatus = status; - handle = static_cast<HttpHandle>(op); + handle = op->getHandle(); return handle; } @@ -501,17 +569,16 @@ HttpHandle HttpRequest::requestSpin(int mode) HttpStatus status; HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); - HttpOpSpin * op = new HttpOpSpin(mode); - op->setReplyPath(mReplyQueue, NULL); + HttpOperation::ptr_t op(new HttpOpSpin(mode)); + op->setReplyPath(mReplyQueue, HttpHandler::ptr_t()); if (! (status = mRequestQueue->addOp(op))) // transfers refcount { - op->release(); mLastReqStatus = status; return handle; } mLastReqStatus = status; - handle = static_cast<HttpHandle>(op); + handle = op->getHandle(); return handle; } diff --git a/indra/llcorehttp/httprequest.h b/indra/llcorehttp/httprequest.h index 7f23723b0b..17cfdcd7b6 100755 --- a/indra/llcorehttp/httprequest.h +++ b/indra/llcorehttp/httprequest.h @@ -31,6 +31,8 @@ #include "httpcommon.h" #include "httphandler.h" +#include "httpheaders.h" +#include "httpoptions.h" namespace LLCore { @@ -38,8 +40,6 @@ namespace LLCore class HttpRequestQueue; class HttpReplyQueue; class HttpService; -class HttpOptions; -class HttpHeaders; class HttpOperation; class BufferArray; @@ -97,6 +97,8 @@ public: typedef unsigned int policy_t; typedef unsigned int priority_t; + typedef boost::shared_ptr<HttpRequest> ptr_t; + typedef boost::weak_ptr<HttpRequest> wptr_t; public: /// @name PolicyMethods /// @{ @@ -163,7 +165,7 @@ public: /// Long value that if non-zero enables the use of the /// traditional LLProxy code for http/socks5 support. If - // enabled, has priority over GP_HTTP_PROXY. + /// enabled, has priority over GP_HTTP_PROXY. /// /// Global only PO_LLPROXY, @@ -219,15 +221,25 @@ public: /// Controls whether client-side throttling should be /// performed on this policy class. Positive values /// enable throttling and specify the request rate - /// (requests per second) that should be targetted. + /// (requests per second) that should be targeted. /// A value of zero, the default, specifies no throttling. /// /// Per-class only PO_THROTTLE_RATE, + /// Controls the callback function used to control SSL CTX + /// certificate verification. + /// + /// Global only + PO_SSL_VERIFY_CALLBACK, + PO_LAST // Always at end }; + /// Prototype for policy based callbacks. The callback methods will be executed + /// on the worker thread so no modifications should be made to the HttpHandler object. + typedef boost::function<HttpStatus(const std::string &, const HttpHandler::ptr_t &, void *)> policyCallback_t; + /// Set a policy option for a global or class parameter at /// startup time (prior to thread start). /// @@ -243,6 +255,8 @@ public: long value, long * ret_value); static HttpStatus setStaticPolicyOption(EPolicyOption opt, policy_t pclass, const std::string & value, std::string * ret_value); + static HttpStatus setStaticPolicyOption(EPolicyOption opt, policy_t pclass, + policyCallback_t value, policyCallback_t * ret_value);; /// Set a parameter on a class-based policy option. Calls /// made after the start of the servicing thread are @@ -256,9 +270,9 @@ public: /// @return Handle of dynamic request. Use @see getStatus() if /// the returned handle is invalid. HttpHandle setPolicyOption(EPolicyOption opt, policy_t pclass, long value, - HttpHandler * handler); + HttpHandler::ptr_t handler); HttpHandle setPolicyOption(EPolicyOption opt, policy_t pclass, const std::string & value, - HttpHandler * handler); + HttpHandler::ptr_t handler); /// @} @@ -334,9 +348,9 @@ public: HttpHandle requestGet(policy_t policy_id, priority_t priority, const std::string & url, - HttpOptions * options, - HttpHeaders * headers, - HttpHandler * handler); + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers, + HttpHandler::ptr_t handler); /// Queue a full HTTP GET request to be issued with a 'Range' header. @@ -377,9 +391,9 @@ public: const std::string & url, size_t offset, size_t len, - HttpOptions * options, - HttpHeaders * headers, - HttpHandler * handler); + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers, + HttpHandler::ptr_t handler); /// Queue a full HTTP POST. Query arguments and body may @@ -418,9 +432,9 @@ public: priority_t priority, const std::string & url, BufferArray * body, - HttpOptions * options, - HttpHeaders * headers, - HttpHandler * handler); + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers, + HttpHandler::ptr_t handler); /// Queue a full HTTP PUT. Query arguments and body may @@ -459,12 +473,92 @@ public: priority_t priority, const std::string & url, BufferArray * body, - HttpOptions * options, - HttpHeaders * headers, - HttpHandler * handler); - - - /// Queue a NoOp request. + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers, + HttpHandler::ptr_t handler); + + + /// Queue a full HTTP DELETE. Query arguments and body may + /// be provided. Caller is responsible for escaping and + /// encoding and communicating the content types. + /// + /// @param policy_id @see requestGet() + /// @param priority " + /// @param url " + /// @param options @see requestGet()K(optional) + /// @param headers " + /// @param handler " + /// @return " + /// + HttpHandle requestDelete(policy_t policy_id, + priority_t priority, + const std::string & url, + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers, + HttpHandler::ptr_t user_handler); + + /// Queue a full HTTP PATCH. Query arguments and body may + /// be provided. Caller is responsible for escaping and + /// encoding and communicating the content types. + /// + /// @param policy_id @see requestGet() + /// @param priority " + /// @param url " + /// @param body Byte stream to be sent as the body. No + /// further encoding or escaping will be done + /// to the content. + /// @param options @see requestGet()K(optional) + /// @param headers " + /// @param handler " + /// @return " + /// + HttpHandle requestPatch(policy_t policy_id, + priority_t priority, + const std::string & url, + BufferArray * body, + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers, + HttpHandler::ptr_t user_handler); + + /// Queue a full HTTP COPY. Query arguments and body may + /// be provided. Caller is responsible for escaping and + /// encoding and communicating the content types. + /// + /// @param policy_id @see requestGet() + /// @param priority " + /// @param url " + /// @param options @see requestGet()K(optional) + /// @param headers " + /// @param handler " + /// @return " + /// + HttpHandle requestCopy(policy_t policy_id, + priority_t priority, + const std::string & url, + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers, + HttpHandler::ptr_t user_handler); + + /// Queue a full HTTP MOVE. Query arguments and body may + /// be provided. Caller is responsible for escaping and + /// encoding and communicating the content types. + /// + /// @param policy_id @see requestGet() + /// @param priority " + /// @param url " + /// @param options @see requestGet()K(optional) + /// @param headers " + /// @param handler " + /// @return " + /// + HttpHandle requestMove(policy_t policy_id, + priority_t priority, + const std::string & url, + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers, + HttpHandler::ptr_t user_handler); + + /// Queue a NoOp request. /// The request is queued and serviced by the working thread which /// immediately processes it and returns the request to the reply /// queue. @@ -472,7 +566,7 @@ public: /// @param handler @see requestGet() /// @return " /// - HttpHandle requestNoOp(HttpHandler * handler); + HttpHandle requestNoOp(HttpHandler::ptr_t handler); /// While all the heavy work is done by the worker thread, notifications /// must be performed in the context of the application thread. These @@ -497,7 +591,7 @@ public: /// /// @{ - HttpHandle requestCancel(HttpHandle request, HttpHandler *); + HttpHandle requestCancel(HttpHandle request, HttpHandler::ptr_t); /// Request that a previously-issued request be reprioritized. /// The status of whether the change itself succeeded arrives @@ -509,7 +603,7 @@ public: /// @param handler @see requestGet() /// @return " /// - HttpHandle requestSetPriority(HttpHandle request, priority_t priority, HttpHandler * handler); + HttpHandle requestSetPriority(HttpHandle request, priority_t priority, HttpHandler::ptr_t handler); /// @} @@ -547,7 +641,7 @@ public: /// As the request cannot be cancelled, the handle /// is generally not useful. /// - HttpHandle requestStopThread(HttpHandler * handler); + HttpHandle requestStopThread(HttpHandler::ptr_t handler); /// Queue a Spin request. /// DEBUG/TESTING ONLY. This puts the worker into a CPU spin for @@ -561,14 +655,15 @@ public: /// @} protected: - void generateNotification(HttpOperation * op); private: + typedef boost::shared_ptr<HttpReplyQueue> HttpReplyQueuePtr_t; + /// @name InstanceData /// /// @{ HttpStatus mLastReqStatus; - HttpReplyQueue * mReplyQueue; + HttpReplyQueuePtr_t mReplyQueue; HttpRequestQueue * mRequestQueue; /// @} diff --git a/indra/llcorehttp/httpresponse.cpp b/indra/llcorehttp/httpresponse.cpp index c974395b0a..f5ad2ebd47 100755 --- a/indra/llcorehttp/httpresponse.cpp +++ b/indra/llcorehttp/httpresponse.cpp @@ -39,16 +39,17 @@ HttpResponse::HttpResponse() mReplyLength(0U), mReplyFullLength(0U), mBufferArray(NULL), - mHeaders(NULL), + mHeaders(), mRetries(0U), - m503Retries(0U) + m503Retries(0U), + mRequestUrl() {} HttpResponse::~HttpResponse() { setBody(NULL); - setHeaders(NULL); + //setHeaders(); } @@ -71,23 +72,14 @@ void HttpResponse::setBody(BufferArray * ba) } -void HttpResponse::setHeaders(HttpHeaders * headers) +void HttpResponse::setHeaders(HttpHeaders::ptr_t &headers) { - if (mHeaders == headers) - return; - - if (mHeaders) - { - mHeaders->release(); - } - - if (headers) - { - headers->addRef(); - } - - mHeaders = headers; + mHeaders = headers; } +size_t HttpResponse::getBodySize() const +{ + return (mBufferArray) ? mBufferArray->size() : 0; +} } // end namespace LLCore diff --git a/indra/llcorehttp/httpresponse.h b/indra/llcorehttp/httpresponse.h index aee64e2878..0bfa4585c7 100755 --- a/indra/llcorehttp/httpresponse.h +++ b/indra/llcorehttp/httpresponse.h @@ -31,7 +31,7 @@ #include <string> #include "httpcommon.h" - +#include "httpheaders.h" #include "_refcounted.h" @@ -69,6 +69,18 @@ protected: void operator=(const HttpResponse &); // Not defined public: + /// Statistics for the HTTP + struct TransferStats + { + typedef boost::shared_ptr<TransferStats> ptr_t; + + TransferStats() : mSizeDownload(0.0), mTotalTime(0.0), mSpeedDownload(0.0) {} + F64 mSizeDownload; + F64 mTotalTime; + F64 mSpeedDownload; + }; + + /// Returns the final status of the requested operation. /// HttpStatus getStatus() const @@ -92,6 +104,10 @@ public: return mBufferArray; } + /// Safely get the size of the body buffer. If the body buffer is missing + /// return 0 as the size. + size_t getBodySize() const; + /// Set the response data in the instance. Will drop the reference /// count to any existing data and increment the count of that passed /// in. It is legal to set the data to NULL. @@ -104,13 +120,13 @@ public: /// /// Caller can hold onto the headers by incrementing the reference /// count of the returned object. - HttpHeaders * getHeaders() const - { + HttpHeaders::ptr_t getHeaders() const + { return mHeaders; - } + } /// Behaves like @see setResponse() but for header data. - void setHeaders(HttpHeaders * headers); + void setHeaders(HttpHeaders::ptr_t &headers); /// If a 'Range:' header was used, these methods are involved /// in setting and returning data about the actual response. @@ -168,6 +184,27 @@ public: m503Retries = retries_503; } + void setTransferStats(TransferStats::ptr_t &stats) + { + mStats = stats; + } + + TransferStats::ptr_t getTransferStats() + { + return mStats; + } + + void setRequestURL(const std::string &url) + { + mRequestUrl = url; + } + + const std::string &getRequestURL() const + { + return mRequestUrl; + } + + protected: // Response data here HttpStatus mStatus; @@ -175,10 +212,13 @@ protected: unsigned int mReplyLength; unsigned int mReplyFullLength; BufferArray * mBufferArray; - HttpHeaders * mHeaders; + HttpHeaders::ptr_t mHeaders; std::string mContentType; unsigned int mRetries; unsigned int m503Retries; + std::string mRequestUrl; + + TransferStats::ptr_t mStats; }; diff --git a/indra/llcorehttp/llhttpconstants.cpp b/indra/llcorehttp/llhttpconstants.cpp new file mode 100755 index 0000000000..71d4f19408 --- /dev/null +++ b/indra/llcorehttp/llhttpconstants.cpp @@ -0,0 +1,135 @@ +/** + * @file llhttpconstants.cpp + * @brief Implementation of the HTTP request / response constant lookups + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013-2014, 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$ + */ + +#include "linden_common.h" +#include "llhttpconstants.h" +#include "lltimer.h" + +// for curl_getdate() (apparently parsing RFC 1123 dates is hard) +#include <curl/curl.h> + +// Outgoing headers. Do *not* use these to check incoming headers. +// For incoming headers, use the lower-case headers, below. +const std::string HTTP_OUT_HEADER_ACCEPT("Accept"); +const std::string HTTP_OUT_HEADER_ACCEPT_CHARSET("Accept-Charset"); +const std::string HTTP_OUT_HEADER_ACCEPT_ENCODING("Accept-Encoding"); +const std::string HTTP_OUT_HEADER_ACCEPT_LANGUAGE("Accept-Language"); +const std::string HTTP_OUT_HEADER_ACCEPT_RANGES("Accept-Ranges"); +const std::string HTTP_OUT_HEADER_AGE("Age"); +const std::string HTTP_OUT_HEADER_ALLOW("Allow"); +const std::string HTTP_OUT_HEADER_AUTHORIZATION("Authorization"); +const std::string HTTP_OUT_HEADER_CACHE_CONTROL("Cache-Control"); +const std::string HTTP_OUT_HEADER_CONNECTION("Connection"); +const std::string HTTP_OUT_HEADER_CONTENT_DESCRIPTION("Content-Description"); +const std::string HTTP_OUT_HEADER_CONTENT_ENCODING("Content-Encoding"); +const std::string HTTP_OUT_HEADER_CONTENT_ID("Content-ID"); +const std::string HTTP_OUT_HEADER_CONTENT_LANGUAGE("Content-Language"); +const std::string HTTP_OUT_HEADER_CONTENT_LENGTH("Content-Length"); +const std::string HTTP_OUT_HEADER_CONTENT_LOCATION("Content-Location"); +const std::string HTTP_OUT_HEADER_CONTENT_MD5("Content-MD5"); +const std::string HTTP_OUT_HEADER_CONTENT_RANGE("Content-Range"); +const std::string HTTP_OUT_HEADER_CONTENT_TRANSFER_ENCODING("Content-Transfer-Encoding"); +const std::string HTTP_OUT_HEADER_CONTENT_TYPE("Content-Type"); +const std::string HTTP_OUT_HEADER_COOKIE("Cookie"); +const std::string HTTP_OUT_HEADER_DATE("Date"); +const std::string HTTP_OUT_HEADER_DESTINATION("Destination"); +const std::string HTTP_OUT_HEADER_ETAG("ETag"); +const std::string HTTP_OUT_HEADER_EXPECT("Expect"); +const std::string HTTP_OUT_HEADER_EXPIRES("Expires"); +const std::string HTTP_OUT_HEADER_FROM("From"); +const std::string HTTP_OUT_HEADER_HOST("Host"); +const std::string HTTP_OUT_HEADER_IF_MATCH("If-Match"); +const std::string HTTP_OUT_HEADER_IF_MODIFIED_SINCE("If-Modified-Since"); +const std::string HTTP_OUT_HEADER_IF_NONE_MATCH("If-None-Match"); +const std::string HTTP_OUT_HEADER_IF_RANGE("If-Range"); +const std::string HTTP_OUT_HEADER_IF_UNMODIFIED_SINCE("If-Unmodified-Since"); +const std::string HTTP_OUT_HEADER_KEEP_ALIVE("Keep-Alive"); +const std::string HTTP_OUT_HEADER_LAST_MODIFIED("Last-Modified"); +const std::string HTTP_OUT_HEADER_LOCATION("Location"); +const std::string HTTP_OUT_HEADER_MAX_FORWARDS("Max-Forwards"); +const std::string HTTP_OUT_HEADER_MIME_VERSION("MIME-Version"); +const std::string HTTP_OUT_HEADER_PRAGMA("Pragma"); +const std::string HTTP_OUT_HEADER_PROXY_AUTHENTICATE("Proxy-Authenticate"); +const std::string HTTP_OUT_HEADER_PROXY_AUTHORIZATION("Proxy-Authorization"); +const std::string HTTP_OUT_HEADER_RANGE("Range"); +const std::string HTTP_OUT_HEADER_REFERER("Referer"); +const std::string HTTP_OUT_HEADER_RETRY_AFTER("Retry-After"); +const std::string HTTP_OUT_HEADER_SERVER("Server"); +const std::string HTTP_OUT_HEADER_SET_COOKIE("Set-Cookie"); +const std::string HTTP_OUT_HEADER_TE("TE"); +const std::string HTTP_OUT_HEADER_TRAILER("Trailer"); +const std::string HTTP_OUT_HEADER_TRANSFER_ENCODING("Transfer-Encoding"); +const std::string HTTP_OUT_HEADER_UPGRADE("Upgrade"); +const std::string HTTP_OUT_HEADER_USER_AGENT("User-Agent"); +const std::string HTTP_OUT_HEADER_VARY("Vary"); +const std::string HTTP_OUT_HEADER_VIA("Via"); +const std::string HTTP_OUT_HEADER_WARNING("Warning"); +const std::string HTTP_OUT_HEADER_WWW_AUTHENTICATE("WWW-Authenticate"); + +// Incoming headers are normalized to lower-case. +const std::string HTTP_IN_HEADER_ACCEPT_LANGUAGE("accept-language"); +const std::string HTTP_IN_HEADER_CACHE_CONTROL("cache-control"); +const std::string HTTP_IN_HEADER_CONTENT_LENGTH("content-length"); +const std::string HTTP_IN_HEADER_CONTENT_LOCATION("content-location"); +const std::string HTTP_IN_HEADER_CONTENT_TYPE("content-type"); +const std::string HTTP_IN_HEADER_HOST("host"); +const std::string HTTP_IN_HEADER_LOCATION("location"); +const std::string HTTP_IN_HEADER_RETRY_AFTER("retry-after"); +const std::string HTTP_IN_HEADER_SET_COOKIE("set-cookie"); +const std::string HTTP_IN_HEADER_USER_AGENT("user-agent"); +const std::string HTTP_IN_HEADER_X_FORWARDED_FOR("x-forwarded-for"); + +const std::string HTTP_CONTENT_LLSD_XML("application/llsd+xml"); +const std::string HTTP_CONTENT_OCTET_STREAM("application/octet-stream"); +const std::string HTTP_CONTENT_VND_LL_MESH("application/vnd.ll.mesh"); +const std::string HTTP_CONTENT_XML("application/xml"); +const std::string HTTP_CONTENT_JSON("application/json"); +const std::string HTTP_CONTENT_TEXT_HTML("text/html"); +const std::string HTTP_CONTENT_TEXT_HTML_UTF8("text/html; charset=utf-8"); +const std::string HTTP_CONTENT_TEXT_PLAIN_UTF8("text/plain; charset=utf-8"); +const std::string HTTP_CONTENT_TEXT_LLSD("text/llsd"); +const std::string HTTP_CONTENT_TEXT_XML("text/xml"); +const std::string HTTP_CONTENT_TEXT_LSL("text/lsl"); +const std::string HTTP_CONTENT_TEXT_PLAIN("text/plain"); +const std::string HTTP_CONTENT_IMAGE_X_J2C("image/x-j2c"); +const std::string HTTP_CONTENT_IMAGE_J2C("image/j2c"); +const std::string HTTP_CONTENT_IMAGE_JPEG("image/jpeg"); +const std::string HTTP_CONTENT_IMAGE_PNG("image/png"); +const std::string HTTP_CONTENT_IMAGE_BMP("image/bmp"); + +const std::string HTTP_NO_CACHE("no-cache"); +const std::string HTTP_NO_CACHE_CONTROL("no-cache, max-age=0"); + +const std::string HTTP_VERB_INVALID("(invalid)"); +const std::string HTTP_VERB_HEAD("HEAD"); +const std::string HTTP_VERB_GET("GET"); +const std::string HTTP_VERB_PUT("PUT"); +const std::string HTTP_VERB_POST("POST"); +const std::string HTTP_VERB_DELETE("DELETE"); +const std::string HTTP_VERB_MOVE("MOVE"); +const std::string HTTP_VERB_OPTIONS("OPTIONS"); +const std::string HTTP_VERB_PATCH("PATCH"); +const std::string HTTP_VERB_COPY("COPY"); diff --git a/indra/llcorehttp/llhttpconstants.h b/indra/llcorehttp/llhttpconstants.h new file mode 100755 index 0000000000..121448854e --- /dev/null +++ b/indra/llcorehttp/llhttpconstants.h @@ -0,0 +1,219 @@ +/** + * @file llhttpconstants.h + * @brief Constants for HTTP requests and responses + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2001-2014, 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 LL_HTTP_CONSTANTS_H +#define LL_HTTP_CONSTANTS_H + +#include "stdtypes.h" + +/////// HTTP STATUS CODES /////// + +// Standard errors from HTTP spec: +// http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1 +const S32 HTTP_CONTINUE = 100; +const S32 HTTP_SWITCHING_PROTOCOLS = 101; + +// Success +const S32 HTTP_OK = 200; +const S32 HTTP_CREATED = 201; +const S32 HTTP_ACCEPTED = 202; +const S32 HTTP_NON_AUTHORITATIVE_INFORMATION = 203; +const S32 HTTP_NO_CONTENT = 204; +const S32 HTTP_RESET_CONTENT = 205; +const S32 HTTP_PARTIAL_CONTENT = 206; + +// Redirection +const S32 HTTP_MULTIPLE_CHOICES = 300; +const S32 HTTP_MOVED_PERMANENTLY = 301; +const S32 HTTP_FOUND = 302; +const S32 HTTP_SEE_OTHER = 303; +const S32 HTTP_NOT_MODIFIED = 304; +const S32 HTTP_USE_PROXY = 305; +const S32 HTTP_TEMPORARY_REDIRECT = 307; + +// Client Error +const S32 HTTP_BAD_REQUEST = 400; +const S32 HTTP_UNAUTHORIZED = 401; +const S32 HTTP_PAYMENT_REQUIRED = 402; +const S32 HTTP_FORBIDDEN = 403; +const S32 HTTP_NOT_FOUND = 404; +const S32 HTTP_METHOD_NOT_ALLOWED = 405; +const S32 HTTP_NOT_ACCEPTABLE = 406; +const S32 HTTP_PROXY_AUTHENTICATION_REQUIRED = 407; +const S32 HTTP_REQUEST_TIME_OUT = 408; +const S32 HTTP_CONFLICT = 409; +const S32 HTTP_GONE = 410; +const S32 HTTP_LENGTH_REQUIRED = 411; +const S32 HTTP_PRECONDITION_FAILED = 412; +const S32 HTTP_REQUEST_ENTITY_TOO_LARGE = 413; +const S32 HTTP_REQUEST_URI_TOO_LARGE = 414; +const S32 HTTP_UNSUPPORTED_MEDIA_TYPE = 415; +const S32 HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416; +const S32 HTTP_EXPECTATION_FAILED = 417; + +// Server Error +const S32 HTTP_INTERNAL_SERVER_ERROR = 500; +const S32 HTTP_NOT_IMPLEMENTED = 501; +const S32 HTTP_BAD_GATEWAY = 502; +const S32 HTTP_SERVICE_UNAVAILABLE = 503; +const S32 HTTP_GATEWAY_TIME_OUT = 504; +const S32 HTTP_VERSION_NOT_SUPPORTED = 505; + +// We combine internal process errors with status codes +// These status codes should not be sent over the wire +// and indicate something went wrong internally. +// If you get these they are not normal. +const S32 HTTP_INTERNAL_CURL_ERROR = 498; +const S32 HTTP_INTERNAL_ERROR = 499; + + +////// HTTP Methods ////// + +extern const std::string HTTP_VERB_INVALID; +extern const std::string HTTP_VERB_HEAD; +extern const std::string HTTP_VERB_GET; +extern const std::string HTTP_VERB_PUT; +extern const std::string HTTP_VERB_POST; +extern const std::string HTTP_VERB_DELETE; +extern const std::string HTTP_VERB_MOVE; +extern const std::string HTTP_VERB_OPTIONS; + +enum EHTTPMethod +{ + HTTP_INVALID = 0, + HTTP_HEAD, + HTTP_GET, + HTTP_PUT, + HTTP_POST, + HTTP_DELETE, + HTTP_MOVE, // Caller will need to set 'Destination' header + HTTP_OPTIONS, + HTTP_PATCH, + HTTP_COPY, + HTTP_METHOD_COUNT +}; + +// Parses 'Retry-After' header contents and returns seconds until retry should occur. +bool getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait); + +//// HTTP Headers ///// + +// Outgoing headers. Do *not* use these to check incoming headers. +// For incoming headers, use the lower-case headers, below. +extern const std::string HTTP_OUT_HEADER_ACCEPT; +extern const std::string HTTP_OUT_HEADER_ACCEPT_CHARSET; +extern const std::string HTTP_OUT_HEADER_ACCEPT_ENCODING; +extern const std::string HTTP_OUT_HEADER_ACCEPT_LANGUAGE; +extern const std::string HTTP_OUT_HEADER_ACCEPT_RANGES; +extern const std::string HTTP_OUT_HEADER_AGE; +extern const std::string HTTP_OUT_HEADER_ALLOW; +extern const std::string HTTP_OUT_HEADER_AUTHORIZATION; +extern const std::string HTTP_OUT_HEADER_CACHE_CONTROL; +extern const std::string HTTP_OUT_HEADER_CONNECTION; +extern const std::string HTTP_OUT_HEADER_CONTENT_DESCRIPTION; +extern const std::string HTTP_OUT_HEADER_CONTENT_ENCODING; +extern const std::string HTTP_OUT_HEADER_CONTENT_ID; +extern const std::string HTTP_OUT_HEADER_CONTENT_LANGUAGE; +extern const std::string HTTP_OUT_HEADER_CONTENT_LENGTH; +extern const std::string HTTP_OUT_HEADER_CONTENT_LOCATION; +extern const std::string HTTP_OUT_HEADER_CONTENT_MD5; +extern const std::string HTTP_OUT_HEADER_CONTENT_RANGE; +extern const std::string HTTP_OUT_HEADER_CONTENT_TRANSFER_ENCODING; +extern const std::string HTTP_OUT_HEADER_CONTENT_TYPE; +extern const std::string HTTP_OUT_HEADER_COOKIE; +extern const std::string HTTP_OUT_HEADER_DATE; +extern const std::string HTTP_OUT_HEADER_DESTINATION; +extern const std::string HTTP_OUT_HEADER_ETAG; +extern const std::string HTTP_OUT_HEADER_EXPECT; +extern const std::string HTTP_OUT_HEADER_EXPIRES; +extern const std::string HTTP_OUT_HEADER_FROM; +extern const std::string HTTP_OUT_HEADER_HOST; +extern const std::string HTTP_OUT_HEADER_IF_MATCH; +extern const std::string HTTP_OUT_HEADER_IF_MODIFIED_SINCE; +extern const std::string HTTP_OUT_HEADER_IF_NONE_MATCH; +extern const std::string HTTP_OUT_HEADER_IF_RANGE; +extern const std::string HTTP_OUT_HEADER_IF_UNMODIFIED_SINCE; +extern const std::string HTTP_OUT_HEADER_KEEP_ALIVE; +extern const std::string HTTP_OUT_HEADER_LAST_MODIFIED; +extern const std::string HTTP_OUT_HEADER_LOCATION; +extern const std::string HTTP_OUT_HEADER_MAX_FORWARDS; +extern const std::string HTTP_OUT_HEADER_MIME_VERSION; +extern const std::string HTTP_OUT_HEADER_PRAGMA; +extern const std::string HTTP_OUT_HEADER_PROXY_AUTHENTICATE; +extern const std::string HTTP_OUT_HEADER_PROXY_AUTHORIZATION; +extern const std::string HTTP_OUT_HEADER_RANGE; +extern const std::string HTTP_OUT_HEADER_REFERER; +extern const std::string HTTP_OUT_HEADER_RETRY_AFTER; +extern const std::string HTTP_OUT_HEADER_SERVER; +extern const std::string HTTP_OUT_HEADER_SET_COOKIE; +extern const std::string HTTP_OUT_HEADER_TE; +extern const std::string HTTP_OUT_HEADER_TRAILER; +extern const std::string HTTP_OUT_HEADER_TRANSFER_ENCODING; +extern const std::string HTTP_OUT_HEADER_UPGRADE; +extern const std::string HTTP_OUT_HEADER_USER_AGENT; +extern const std::string HTTP_OUT_HEADER_VARY; +extern const std::string HTTP_OUT_HEADER_VIA; +extern const std::string HTTP_OUT_HEADER_WARNING; +extern const std::string HTTP_OUT_HEADER_WWW_AUTHENTICATE; + +// Incoming headers are normalized to lower-case. +extern const std::string HTTP_IN_HEADER_ACCEPT_LANGUAGE; +extern const std::string HTTP_IN_HEADER_CACHE_CONTROL; +extern const std::string HTTP_IN_HEADER_CONTENT_LENGTH; +extern const std::string HTTP_IN_HEADER_CONTENT_LOCATION; +extern const std::string HTTP_IN_HEADER_CONTENT_TYPE; +extern const std::string HTTP_IN_HEADER_HOST; +extern const std::string HTTP_IN_HEADER_LOCATION; +extern const std::string HTTP_IN_HEADER_RETRY_AFTER; +extern const std::string HTTP_IN_HEADER_SET_COOKIE; +extern const std::string HTTP_IN_HEADER_USER_AGENT; +extern const std::string HTTP_IN_HEADER_X_FORWARDED_FOR; + +//// HTTP Content Types //// + +extern const std::string HTTP_CONTENT_LLSD_XML; +extern const std::string HTTP_CONTENT_OCTET_STREAM; +extern const std::string HTTP_CONTENT_VND_LL_MESH; +extern const std::string HTTP_CONTENT_XML; +extern const std::string HTTP_CONTENT_JSON; +extern const std::string HTTP_CONTENT_TEXT_HTML; +extern const std::string HTTP_CONTENT_TEXT_HTML_UTF8; +extern const std::string HTTP_CONTENT_TEXT_PLAIN_UTF8; +extern const std::string HTTP_CONTENT_TEXT_LLSD; +extern const std::string HTTP_CONTENT_TEXT_XML; +extern const std::string HTTP_CONTENT_TEXT_LSL; +extern const std::string HTTP_CONTENT_TEXT_PLAIN; +extern const std::string HTTP_CONTENT_IMAGE_X_J2C; +extern const std::string HTTP_CONTENT_IMAGE_J2C; +extern const std::string HTTP_CONTENT_IMAGE_JPEG; +extern const std::string HTTP_CONTENT_IMAGE_PNG; +extern const std::string HTTP_CONTENT_IMAGE_BMP; + +//// HTTP Cache Settings //// +extern const std::string HTTP_NO_CACHE; +extern const std::string HTTP_NO_CACHE_CONTROL; + +#endif diff --git a/indra/llcorehttp/tests/llcorehttp_test.cpp b/indra/llcorehttp/tests/llcorehttp_test.cpp index e863ddd13f..bef762f5ce 100755 --- a/indra/llcorehttp/tests/llcorehttp_test.cpp +++ b/indra/llcorehttp/tests/llcorehttp_test.cpp @@ -160,7 +160,7 @@ void stop_thread(LLCore::HttpRequest * req) { if (req) { - req->requestStopThread(NULL); + req->requestStopThread(LLCore::HttpHandler::ptr_t()); int count = 0; int limit = 10; diff --git a/indra/llcorehttp/tests/test_httpheaders.hpp b/indra/llcorehttp/tests/test_httpheaders.hpp index 668c36dc66..c05f1d9429 100755 --- a/indra/llcorehttp/tests/test_httpheaders.hpp +++ b/indra/llcorehttp/tests/test_httpheaders.hpp @@ -59,13 +59,12 @@ void HttpHeadersTestObjectType::test<1>() mMemTotal = GetMemTotal(); // create a new ref counted object with an implicit reference - HttpHeaders * headers = new HttpHeaders(); - ensure("One ref on construction of HttpHeaders", headers->getRefCount() == 1); + HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders()); ensure("Memory being used", mMemTotal < GetMemTotal()); ensure("Nothing in headers", 0 == headers->size()); // release the implicit reference, causing the object to be released - headers->release(); + headers.reset(); // make sure we didn't leak any memory ensure(mMemTotal == GetMemTotal()); @@ -80,7 +79,7 @@ void HttpHeadersTestObjectType::test<2>() mMemTotal = GetMemTotal(); // create a new ref counted object with an implicit reference - HttpHeaders * headers = new HttpHeaders(); + HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders()); { // Append a few strings @@ -101,7 +100,7 @@ void HttpHeadersTestObjectType::test<2>() } // release the implicit reference, causing the object to be released - headers->release(); + headers.reset(); // make sure we didn't leak any memory ensure(mMemTotal == GetMemTotal()); @@ -116,7 +115,7 @@ void HttpHeadersTestObjectType::test<3>() mMemTotal = GetMemTotal(); // create a new ref counted object with an implicit reference - HttpHeaders * headers = new HttpHeaders(); + HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders()); { // Append a few strings @@ -151,7 +150,7 @@ void HttpHeadersTestObjectType::test<3>() } // release the implicit reference, causing the object to be released - headers->release(); + headers.reset(); // make sure we didn't leak any memory ensure(mMemTotal == GetMemTotal()); @@ -166,8 +165,8 @@ void HttpHeadersTestObjectType::test<4>() mMemTotal = GetMemTotal(); // create a new ref counted object with an implicit reference - HttpHeaders * headers = new HttpHeaders(); - + HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders()); + { static char line1[] = " AcCePT : image/yourfacehere"; static char line1v[] = "image/yourfacehere"; @@ -251,7 +250,7 @@ void HttpHeadersTestObjectType::test<4>() } // release the implicit reference, causing the object to be released - headers->release(); + headers.reset(); // make sure we didn't leak any memory ensure(mMemTotal == GetMemTotal()); @@ -267,7 +266,7 @@ void HttpHeadersTestObjectType::test<5>() mMemTotal = GetMemTotal(); // create a new ref counted object with an implicit reference - HttpHeaders * headers = new HttpHeaders(); + HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders()); HttpHeaders::iterator end(headers->end()), begin(headers->begin()); ensure("Empty container has equal begin/end const iterators", end == begin); @@ -337,7 +336,7 @@ void HttpHeadersTestObjectType::test<5>() } // release the implicit reference, causing the object to be released - headers->release(); + headers.reset(); // make sure we didn't leak any memory ensure(mMemTotal == GetMemTotal()); @@ -353,7 +352,7 @@ void HttpHeadersTestObjectType::test<6>() mMemTotal = GetMemTotal(); // create a new ref counted object with an implicit reference - HttpHeaders * headers = new HttpHeaders(); + HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders()); HttpHeaders::reverse_iterator rend(headers->rend()), rbegin(headers->rbegin()); ensure("Empty container has equal rbegin/rend const iterators", rend == rbegin); @@ -421,7 +420,7 @@ void HttpHeadersTestObjectType::test<6>() } // release the implicit reference, causing the object to be released - headers->release(); + headers.reset(); // make sure we didn't leak any memory ensure(mMemTotal == GetMemTotal()); diff --git a/indra/llcorehttp/tests/test_httpoperation.hpp b/indra/llcorehttp/tests/test_httpoperation.hpp index 17b1a96878..e7df2337de 100755 --- a/indra/llcorehttp/tests/test_httpoperation.hpp +++ b/indra/llcorehttp/tests/test_httpoperation.hpp @@ -76,12 +76,12 @@ namespace tut mMemTotal = GetMemTotal(); // create a new ref counted object with an implicit reference - HttpOpNull * op = new HttpOpNull(); - ensure(op->getRefCount() == 1); + HttpOperation::ptr_t op (new HttpOpNull()); + ensure(op.use_count() == 1); ensure(mMemTotal < GetMemTotal()); // release the implicit reference, causing the object to be released - op->release(); + op.reset(); // make sure we didn't leak any memory ensure(mMemTotal == GetMemTotal()); @@ -96,26 +96,24 @@ namespace tut mMemTotal = GetMemTotal(); // Get some handlers - TestHandler * h1 = new TestHandler(); + LLCore::HttpHandler::ptr_t h1 (new TestHandler()); // create a new ref counted object with an implicit reference - HttpOpNull * op = new HttpOpNull(); + HttpOperation::ptr_t op (new HttpOpNull()); // Add the handlers - op->setReplyPath(NULL, h1); + op->setReplyPath(LLCore::HttpOperation::HttpReplyQueuePtr_t(), h1); // Check ref count - ensure(op->getRefCount() == 1); + ensure(op.unique() == 1); // release the reference, releasing the operation but // not the handlers. - op->release(); - op = NULL; + op.reset(); ensure(mMemTotal != GetMemTotal()); // release the handlers - delete h1; - h1 = NULL; + h1.reset(); ensure(mMemTotal == GetMemTotal()); } diff --git a/indra/llcorehttp/tests/test_httprequest.hpp b/indra/llcorehttp/tests/test_httprequest.hpp index 43f7e36da5..463e55dd7e 100755 --- a/indra/llcorehttp/tests/test_httprequest.hpp +++ b/indra/llcorehttp/tests/test_httprequest.hpp @@ -112,7 +112,7 @@ public: if (! mHeadersRequired.empty() || ! mHeadersDisallowed.empty()) { ensure("Response required with header check", response != NULL); - HttpHeaders * header(response->getHeaders()); // Will not hold onto this + HttpHeaders::ptr_t header(response->getHeaders()); // Will not hold onto this ensure("Some quantity of headers returned", header != NULL); if (! mHeadersRequired.empty()) @@ -247,7 +247,7 @@ void HttpRequestTestObjectType::test<2>() ensure("Memory being used", mMemTotal < GetMemTotal()); // Issue a NoOp - HttpHandle handle = req->requestNoOp(NULL); + HttpHandle handle = req->requestNoOp(LLCore::HttpHandler::ptr_t()); ensure("Request issued", handle != LLCORE_HTTP_HANDLE_INVALID); // release the request object @@ -275,6 +275,10 @@ void HttpRequestTestObjectType::test<2>() } } +namespace +{ + void NoOpDeletor(LLCore::HttpHandler *) { } +} template <> template <> void HttpRequestTestObjectType::test<3>() @@ -287,7 +291,8 @@ void HttpRequestTestObjectType::test<3>() // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); - + LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); + // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; @@ -296,9 +301,8 @@ void HttpRequestTestObjectType::test<3>() try { - // Get singletons created - HttpRequest::createService(); + HttpRequest::createService(); // Start threading early so that thread memory is invariant // over the test. @@ -309,7 +313,7 @@ void HttpRequestTestObjectType::test<3>() ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); // Issue a NoOp - HttpHandle handle = req->requestNoOp(&handler); + HttpHandle handle = req->requestNoOp(handlerp); ensure("Valid handle returned for first request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. @@ -324,7 +328,7 @@ void HttpRequestTestObjectType::test<3>() ensure("One handler invocation for request", mHandlerCalls == 1); // Okay, request a shutdown of the servicing thread - handle = req->requestStopThread(&handler); + handle = req->requestStopThread(handlerp); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again @@ -378,7 +382,10 @@ void HttpRequestTestObjectType::test<4>() // references to it after completion of this method. TestHandler2 handler1(this, "handler1"); TestHandler2 handler2(this, "handler2"); - + + LLCore::HttpHandler::ptr_t handler1p(&handler1, NoOpDeletor); + LLCore::HttpHandler::ptr_t handler2p(&handler2, NoOpDeletor); + // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; @@ -388,7 +395,7 @@ void HttpRequestTestObjectType::test<4>() try { - + // Get singletons created HttpRequest::createService(); @@ -402,11 +409,11 @@ void HttpRequestTestObjectType::test<4>() ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); // Issue some NoOps - HttpHandle handle = req1->requestNoOp(&handler1); + HttpHandle handle = req1->requestNoOp(handler1p); ensure("Valid handle returned for first request", handle != LLCORE_HTTP_HANDLE_INVALID); handler1.mExpectHandle = handle; - handle = req2->requestNoOp(&handler2); + handle = req2->requestNoOp(handler2p); ensure("Valid handle returned for first request", handle != LLCORE_HTTP_HANDLE_INVALID); handler2.mExpectHandle = handle; @@ -423,7 +430,7 @@ void HttpRequestTestObjectType::test<4>() ensure("One handler invocation for request", mHandlerCalls == 2); // Okay, request a shutdown of the servicing thread - handle = req2->requestStopThread(&handler2); + handle = req2->requestStopThread(handler2p); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); handler2.mExpectHandle = handle; @@ -482,7 +489,8 @@ void HttpRequestTestObjectType::test<5>() // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); - + LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); + // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; @@ -491,7 +499,6 @@ void HttpRequestTestObjectType::test<5>() try { - // Get singletons created HttpRequest::createService(); @@ -508,7 +515,7 @@ void HttpRequestTestObjectType::test<5>() ensure("Valid handle returned for spin request", handle != LLCORE_HTTP_HANDLE_INVALID); // Issue a NoOp - handle = req->requestNoOp(&handler); + handle = req->requestNoOp(handlerp); ensure("Valid handle returned for no-op request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. @@ -567,7 +574,8 @@ void HttpRequestTestObjectType::test<6>() try { - + LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); + // Get singletons created HttpRequest::createService(); @@ -584,7 +592,7 @@ void HttpRequestTestObjectType::test<6>() ensure("Valid handle returned for spin request", handle != LLCORE_HTTP_HANDLE_INVALID); // Issue a NoOp - handle = req->requestNoOp(&handler); + handle = req->requestNoOp(handlerp); ensure("Valid handle returned for no-op request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. @@ -632,17 +640,19 @@ void HttpRequestTestObjectType::test<7>() // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); - + + LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); + // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; - HttpOptions * opts = NULL; + HttpOptions::ptr_t opts; try { - // Get singletons created + // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant @@ -653,7 +663,7 @@ void HttpRequestTestObjectType::test<7>() req = new HttpRequest(); ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); - opts = new HttpOptions(); + opts = HttpOptions::ptr_t(new HttpOptions()); opts->setRetries(1); // Don't try for too long - default retries take about 18S // Issue a GET that can't connect @@ -664,8 +674,8 @@ void HttpRequestTestObjectType::test<7>() 0, 0, opts, - NULL, - &handler); + HttpHeaders::ptr_t(), + handlerp); ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. @@ -681,7 +691,7 @@ void HttpRequestTestObjectType::test<7>() // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); - handle = req->requestStopThread(&handler); + handle = req->requestStopThread(handlerp); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again @@ -705,8 +715,7 @@ void HttpRequestTestObjectType::test<7>() ensure("Thread actually stopped running", HttpService::isStopped()); // release options - opts->release(); - opts = NULL; + opts.reset(); // release the request object delete req; @@ -728,11 +737,7 @@ void HttpRequestTestObjectType::test<7>() catch (...) { stop_thread(req); - if (opts) - { - opts->release(); - opts = NULL; - } + opts.reset(); delete req; HttpRequest::destroyService(); throw; @@ -754,7 +759,8 @@ void HttpRequestTestObjectType::test<8>() // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); - + LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); + // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; @@ -763,7 +769,7 @@ void HttpRequestTestObjectType::test<8>() try { - // Get singletons created + // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant @@ -779,9 +785,9 @@ void HttpRequestTestObjectType::test<8>() HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID, 0U, url_base, - NULL, - NULL, - &handler); + HttpOptions::ptr_t(), + HttpHeaders::ptr_t(), + handlerp); ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. @@ -797,7 +803,7 @@ void HttpRequestTestObjectType::test<8>() // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); - handle = req->requestStopThread(&handler); + handle = req->requestStopThread(handlerp); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again @@ -862,7 +868,8 @@ void HttpRequestTestObjectType::test<9>() // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); - + LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); + // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; @@ -871,7 +878,7 @@ void HttpRequestTestObjectType::test<9>() try { - // Get singletons created + // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant @@ -889,9 +896,9 @@ void HttpRequestTestObjectType::test<9>() url_base, 0, 0, - NULL, - NULL, - &handler); + HttpOptions::ptr_t(), + HttpHeaders::ptr_t(), + handlerp); ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. @@ -907,7 +914,7 @@ void HttpRequestTestObjectType::test<9>() // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); - handle = req->requestStopThread(&handler); + handle = req->requestStopThread(handlerp); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again @@ -972,7 +979,8 @@ void HttpRequestTestObjectType::test<10>() // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); - + LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); + // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; @@ -982,7 +990,7 @@ void HttpRequestTestObjectType::test<10>() try { - // Get singletons created + // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant @@ -1001,9 +1009,9 @@ void HttpRequestTestObjectType::test<10>() 0U, url_base, body, - NULL, - NULL, - &handler); + HttpOptions::ptr_t(), + HttpHeaders::ptr_t(), + handlerp); ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. @@ -1019,7 +1027,7 @@ void HttpRequestTestObjectType::test<10>() // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); - handle = req->requestStopThread(&handler); + handle = req->requestStopThread(handlerp); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again @@ -1090,7 +1098,8 @@ void HttpRequestTestObjectType::test<11>() // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); - + LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); + // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; @@ -1100,7 +1109,7 @@ void HttpRequestTestObjectType::test<11>() try { - // Get singletons created + // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant @@ -1119,9 +1128,9 @@ void HttpRequestTestObjectType::test<11>() 0U, url_base, body, - NULL, - NULL, - &handler); + HttpOptions::ptr_t(), + HttpHeaders::ptr_t(), + handlerp); ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. @@ -1137,7 +1146,7 @@ void HttpRequestTestObjectType::test<11>() // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); - handle = req->requestStopThread(&handler); + handle = req->requestStopThread(handlerp); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again @@ -1209,7 +1218,8 @@ void HttpRequestTestObjectType::test<12>() // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); - + LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); + // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; @@ -1218,7 +1228,7 @@ void HttpRequestTestObjectType::test<12>() try { - // Get singletons created + // Get singletons created HttpRequest::createService(); // Enable tracing @@ -1239,9 +1249,9 @@ void HttpRequestTestObjectType::test<12>() url_base, 0, 0, - NULL, - NULL, - &handler); + HttpOptions::ptr_t(), + HttpHeaders::ptr_t(), + handlerp); ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. @@ -1257,7 +1267,7 @@ void HttpRequestTestObjectType::test<12>() // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); - handle = req->requestStopThread(&handler); + handle = req->requestStopThread(handlerp); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again @@ -1326,17 +1336,18 @@ void HttpRequestTestObjectType::test<13>() // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); handler.mHeadersRequired.reserve(20); // Avoid memory leak test failure - + LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); + // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; - HttpOptions * opts = NULL; + HttpOptions::ptr_t opts; try { - // Get singletons created + // Get singletons created HttpRequest::createService(); // Enable tracing @@ -1350,7 +1361,7 @@ void HttpRequestTestObjectType::test<13>() req = new HttpRequest(); ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); - opts = new HttpOptions(); + opts = HttpOptions::ptr_t(new HttpOptions()); opts->setWantHeaders(true); // Issue a GET that succeeds @@ -1364,13 +1375,12 @@ void HttpRequestTestObjectType::test<13>() 0, 0, opts, - NULL, - &handler); + HttpHeaders::ptr_t(), + handlerp); ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); // release options - opts->release(); - opts = NULL; + opts.reset(); // Run the notification pump. int count(0); @@ -1386,7 +1396,7 @@ void HttpRequestTestObjectType::test<13>() // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); handler.mHeadersRequired.clear(); - handle = req->requestStopThread(&handler); + handle = req->requestStopThread(handlerp); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again @@ -1430,11 +1440,7 @@ void HttpRequestTestObjectType::test<13>() catch (...) { stop_thread(req); - if (opts) - { - opts->release(); - opts = NULL; - } + opts.reset(); delete req; HttpRequest::destroyService(); throw; @@ -1453,18 +1459,19 @@ void HttpRequestTestObjectType::test<14>() // 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 + LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); + 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; + HttpOptions::ptr_t opts; try { - // Get singletons created + // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant @@ -1475,7 +1482,7 @@ void HttpRequestTestObjectType::test<14>() req = new HttpRequest(); ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); - opts = new HttpOptions(); + opts = HttpOptions::ptr_t(new HttpOptions); opts->setRetries(0); // Don't retry opts->setTimeout(2); @@ -1487,8 +1494,8 @@ void HttpRequestTestObjectType::test<14>() 0, 0, opts, - NULL, - &handler); + HttpHeaders::ptr_t(), + handlerp); ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. @@ -1504,7 +1511,7 @@ void HttpRequestTestObjectType::test<14>() // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); - handle = req->requestStopThread(&handler); + handle = req->requestStopThread(handlerp); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again @@ -1528,8 +1535,7 @@ void HttpRequestTestObjectType::test<14>() ensure("Thread actually stopped running", HttpService::isStopped()); // release options - opts->release(); - opts = NULL; + opts.reset(); // release the request object delete req; @@ -1552,11 +1558,7 @@ void HttpRequestTestObjectType::test<14>() catch (...) { stop_thread(req); - if (opts) - { - opts->release(); - opts = NULL; - } + opts.reset(); delete req; HttpRequest::destroyService(); throw; @@ -1578,6 +1580,7 @@ void HttpRequestTestObjectType::test<15>() // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); + LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); // Load and clear the string setting to preload std::string object // for memory return tests. @@ -1592,7 +1595,7 @@ void HttpRequestTestObjectType::test<15>() try { - // Get singletons created + // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant @@ -1609,9 +1612,9 @@ void HttpRequestTestObjectType::test<15>() HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID, 0U, url_base, - NULL, - NULL, - &handler); + HttpOptions::ptr_t(), + HttpHeaders::ptr_t(), + handlerp); ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. @@ -1628,7 +1631,7 @@ void HttpRequestTestObjectType::test<15>() // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); handler.mCheckContentType.clear(); - handle = req->requestStopThread(&handler); + handle = req->requestStopThread(handlerp); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again @@ -1697,18 +1700,19 @@ void HttpRequestTestObjectType::test<16>() // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); + LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; - HttpOptions * options = NULL; - HttpHeaders * headers = NULL; + HttpOptions::ptr_t options; + HttpHeaders::ptr_t headers; try { - // Get singletons created + // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant @@ -1719,7 +1723,7 @@ void HttpRequestTestObjectType::test<16>() req = new HttpRequest(); // options set - options = new HttpOptions(); + options = HttpOptions::ptr_t(new HttpOptions()); options->setWantHeaders(true); // Issue a GET that *can* connect @@ -1776,8 +1780,8 @@ void HttpRequestTestObjectType::test<16>() 0U, url_base + "reflect/", options, - NULL, - &handler); + HttpHeaders::ptr_t(), + handlerp); ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. @@ -1792,7 +1796,7 @@ void HttpRequestTestObjectType::test<16>() ensure("One handler invocation for request", mHandlerCalls == 1); // Do a texture-style fetch - headers = new HttpHeaders; + headers = HttpHeaders::ptr_t(new HttpHeaders); headers->append("Accept", "image/x-j2c"); mStatus = HttpStatus(200); @@ -1854,7 +1858,7 @@ void HttpRequestTestObjectType::test<16>() 47, options, headers, - &handler); + handlerp); ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. @@ -1873,7 +1877,7 @@ void HttpRequestTestObjectType::test<16>() mStatus = HttpStatus(); handler.mHeadersRequired.clear(); handler.mHeadersDisallowed.clear(); - handle = req->requestStopThread(&handler); + handle = req->requestStopThread(handlerp); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again @@ -1897,17 +1901,8 @@ void HttpRequestTestObjectType::test<16>() ensure("Thread actually stopped running", HttpService::isStopped()); // release options & headers - if (options) - { - options->release(); - } - options = NULL; - - if (headers) - { - headers->release(); - } - headers = NULL; + options.reset(); + headers.reset(); // release the request object delete req; @@ -1919,16 +1914,9 @@ void HttpRequestTestObjectType::test<16>() catch (...) { stop_thread(req); - if (options) - { - options->release(); - options = NULL; - } - if (headers) - { - headers->release(); - headers = NULL; - } + options.reset(); + headers.reset(); + delete req; HttpRequest::destroyService(); throw; @@ -1954,19 +1942,20 @@ void HttpRequestTestObjectType::test<17>() // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); + LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; - HttpOptions * options = NULL; - HttpHeaders * headers = NULL; + HttpOptions::ptr_t options; + HttpHeaders::ptr_t headers; BufferArray * ba = NULL; try { - // Get singletons created + // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant @@ -1977,7 +1966,7 @@ void HttpRequestTestObjectType::test<17>() req = new HttpRequest(); // options set - options = new HttpOptions(); + options = HttpOptions::ptr_t(new HttpOptions()); options->setWantHeaders(true); // And a buffer array @@ -2049,8 +2038,8 @@ void HttpRequestTestObjectType::test<17>() url_base + "reflect/", ba, options, - NULL, - &handler); + HttpHeaders::ptr_t(), + handlerp); ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); ba->release(); ba = NULL; @@ -2071,7 +2060,7 @@ void HttpRequestTestObjectType::test<17>() mStatus = HttpStatus(); handler.mHeadersRequired.clear(); handler.mHeadersDisallowed.clear(); - handle = req->requestStopThread(&handler); + handle = req->requestStopThread(handlerp); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again @@ -2095,17 +2084,8 @@ void HttpRequestTestObjectType::test<17>() ensure("Thread actually stopped running", HttpService::isStopped()); // release options & headers - if (options) - { - options->release(); - } - options = NULL; - - if (headers) - { - headers->release(); - } - headers = NULL; + options.reset(); + headers.reset(); // release the request object delete req; @@ -2122,17 +2102,10 @@ void HttpRequestTestObjectType::test<17>() ba->release(); ba = NULL; } - if (options) - { - options->release(); - options = NULL; - } - if (headers) - { - headers->release(); - headers = NULL; - } - delete req; + options.reset(); + headers.reset(); + + delete req; HttpRequest::destroyService(); throw; } @@ -2157,19 +2130,20 @@ void HttpRequestTestObjectType::test<18>() // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); + LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; - HttpOptions * options = NULL; - HttpHeaders * headers = NULL; + HttpOptions::ptr_t options; + HttpHeaders::ptr_t headers; BufferArray * ba = NULL; try { - // Get singletons created + // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant @@ -2180,7 +2154,7 @@ void HttpRequestTestObjectType::test<18>() req = new HttpRequest(); // options set - options = new HttpOptions(); + options = HttpOptions::ptr_t(new HttpOptions()); options->setWantHeaders(true); // And a buffer array @@ -2253,8 +2227,8 @@ void HttpRequestTestObjectType::test<18>() url_base + "reflect/", ba, options, - NULL, - &handler); + HttpHeaders::ptr_t(), + handlerp); ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); ba->release(); ba = NULL; @@ -2275,7 +2249,7 @@ void HttpRequestTestObjectType::test<18>() mStatus = HttpStatus(); handler.mHeadersRequired.clear(); handler.mHeadersDisallowed.clear(); - handle = req->requestStopThread(&handler); + handle = req->requestStopThread(handlerp); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again @@ -2299,17 +2273,8 @@ void HttpRequestTestObjectType::test<18>() ensure("Thread actually stopped running", HttpService::isStopped()); // release options & headers - if (options) - { - options->release(); - } - options = NULL; - - if (headers) - { - headers->release(); - } - headers = NULL; + options.reset(); + headers.reset(); // release the request object delete req; @@ -2326,17 +2291,10 @@ void HttpRequestTestObjectType::test<18>() ba->release(); ba = NULL; } - if (options) - { - options->release(); - options = NULL; - } - if (headers) - { - headers->release(); - headers = NULL; - } - delete req; + options.reset(); + headers.reset(); + + delete req; HttpRequest::destroyService(); throw; } @@ -2361,18 +2319,19 @@ void HttpRequestTestObjectType::test<19>() // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); + LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; - HttpOptions * options = NULL; - HttpHeaders * headers = NULL; + HttpOptions::ptr_t options; + HttpHeaders::ptr_t headers; try { - // Get singletons created + // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant @@ -2383,11 +2342,11 @@ void HttpRequestTestObjectType::test<19>() req = new HttpRequest(); // options set - options = new HttpOptions(); + options = HttpOptions::ptr_t(new HttpOptions()); options->setWantHeaders(true); // headers - headers = new HttpHeaders; + headers = HttpHeaders::ptr_t(new HttpHeaders); headers->append("Keep-Alive", "120"); headers->append("Accept-encoding", "deflate"); headers->append("Accept", "text/plain"); @@ -2460,7 +2419,7 @@ void HttpRequestTestObjectType::test<19>() url_base + "reflect/", options, headers, - &handler); + handlerp); ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump. @@ -2478,7 +2437,7 @@ void HttpRequestTestObjectType::test<19>() mStatus = HttpStatus(); handler.mHeadersRequired.clear(); handler.mHeadersDisallowed.clear(); - handle = req->requestStopThread(&handler); + handle = req->requestStopThread(handlerp); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again @@ -2502,17 +2461,8 @@ void HttpRequestTestObjectType::test<19>() ensure("Thread actually stopped running", HttpService::isStopped()); // release options & headers - if (options) - { - options->release(); - } - options = NULL; - - if (headers) - { - headers->release(); - } - headers = NULL; + options.reset(); + headers.reset(); // release the request object delete req; @@ -2524,16 +2474,9 @@ void HttpRequestTestObjectType::test<19>() catch (...) { stop_thread(req); - if (options) - { - options->release(); - options = NULL; - } - if (headers) - { - headers->release(); - headers = NULL; - } + options.reset(); + headers.reset(); + delete req; HttpRequest::destroyService(); throw; @@ -2559,19 +2502,21 @@ void HttpRequestTestObjectType::test<20>() // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); + LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; - HttpOptions * options = NULL; - HttpHeaders * headers = NULL; + HttpOptions::ptr_t options; + HttpHeaders::ptr_t headers; BufferArray * ba = NULL; try { - // Get singletons created + + // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant @@ -2582,11 +2527,11 @@ void HttpRequestTestObjectType::test<20>() req = new HttpRequest(); // options set - options = new HttpOptions(); + options = HttpOptions::ptr_t(new HttpOptions()); options->setWantHeaders(true); // headers - headers = new HttpHeaders(); + headers = HttpHeaders::ptr_t(new HttpHeaders()); headers->append("keep-Alive", "120"); headers->append("Accept", "text/html"); headers->append("content-type", "application/llsd+xml"); @@ -2675,7 +2620,7 @@ void HttpRequestTestObjectType::test<20>() ba, options, headers, - &handler); + handlerp); ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); ba->release(); ba = NULL; @@ -2696,7 +2641,7 @@ void HttpRequestTestObjectType::test<20>() mStatus = HttpStatus(); handler.mHeadersRequired.clear(); handler.mHeadersDisallowed.clear(); - handle = req->requestStopThread(&handler); + handle = req->requestStopThread(handlerp); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again @@ -2720,17 +2665,8 @@ void HttpRequestTestObjectType::test<20>() ensure("Thread actually stopped running", HttpService::isStopped()); // release options & headers - if (options) - { - options->release(); - } - options = NULL; - - if (headers) - { - headers->release(); - } - headers = NULL; + options.reset(); + headers.reset(); // release the request object delete req; @@ -2747,16 +2683,8 @@ void HttpRequestTestObjectType::test<20>() ba->release(); ba = NULL; } - if (options) - { - options->release(); - options = NULL; - } - if (headers) - { - headers->release(); - headers = NULL; - } + options.reset(); + headers.reset(); delete req; HttpRequest::destroyService(); throw; @@ -2782,19 +2710,20 @@ void HttpRequestTestObjectType::test<21>() // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); + LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; - HttpOptions * options = NULL; - HttpHeaders * headers = NULL; + HttpOptions::ptr_t options; + HttpHeaders::ptr_t headers; BufferArray * ba = NULL; try { - // Get singletons created + // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant @@ -2805,11 +2734,11 @@ void HttpRequestTestObjectType::test<21>() req = new HttpRequest(); // options set - options = new HttpOptions(); + options = HttpOptions::ptr_t(new HttpOptions()); options->setWantHeaders(true); // headers - headers = new HttpHeaders; + headers = HttpHeaders::ptr_t(new HttpHeaders); headers->append("content-type", "text/plain"); headers->append("content-type", "text/html"); headers->append("content-type", "application/llsd+xml"); @@ -2892,7 +2821,7 @@ void HttpRequestTestObjectType::test<21>() ba, options, headers, - &handler); + handlerp); ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); ba->release(); ba = NULL; @@ -2913,7 +2842,7 @@ void HttpRequestTestObjectType::test<21>() mStatus = HttpStatus(); handler.mHeadersRequired.clear(); handler.mHeadersDisallowed.clear(); - handle = req->requestStopThread(&handler); + handle = req->requestStopThread(handlerp); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again @@ -2937,17 +2866,8 @@ void HttpRequestTestObjectType::test<21>() ensure("Thread actually stopped running", HttpService::isStopped()); // release options & headers - if (options) - { - options->release(); - } - options = NULL; - - if (headers) - { - headers->release(); - } - headers = NULL; + options.reset(); + headers.reset(); // release the request object delete req; @@ -2964,16 +2884,8 @@ void HttpRequestTestObjectType::test<21>() ba->release(); ba = NULL; } - if (options) - { - options->release(); - options = NULL; - } - if (headers) - { - headers->release(); - headers = NULL; - } + options.reset(); + headers.reset(); delete req; HttpRequest::destroyService(); throw; @@ -2995,18 +2907,19 @@ void HttpRequestTestObjectType::test<22>() // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. TestHandler2 handler(this, "handler"); - + LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); + // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; - HttpOptions * options = NULL; + HttpOptions::ptr_t options; HttpRequest * req = NULL; try { - // options set - options = new HttpOptions(); + // options set + options = HttpOptions::ptr_t(new HttpOptions()); options->setRetries(1); // Partial_File is retryable and can timeout in here // Get singletons created @@ -3035,8 +2948,8 @@ void HttpRequestTestObjectType::test<22>() 0, 25, options, - NULL, - &handler); + HttpHeaders::ptr_t(), + handlerp); ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); } @@ -3067,8 +2980,8 @@ void HttpRequestTestObjectType::test<22>() 0, 25, options, - NULL, - &handler); + HttpHeaders::ptr_t(), + handlerp); ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); } @@ -3099,8 +3012,8 @@ void HttpRequestTestObjectType::test<22>() 0, 25, options, - NULL, - &handler); + HttpHeaders::ptr_t(), + handlerp); ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); } @@ -3120,7 +3033,7 @@ void HttpRequestTestObjectType::test<22>() // ====================================== mStatus = HttpStatus(); mHandlerCalls = 0; - HttpHandle handle = req->requestStopThread(&handler); + HttpHandle handle = req->requestStopThread(handlerp); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again @@ -3144,11 +3057,7 @@ void HttpRequestTestObjectType::test<22>() ensure("Thread actually stopped running", HttpService::isStopped()); // release options - if (options) - { - options->release(); - options = NULL; - } + options.reset(); // release the request object delete req; @@ -3191,18 +3100,19 @@ void HttpRequestTestObjectType::test<23>() // 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() + "/503/"); // path to 503 generators + LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); + std::string url_base(get_base_url() + "/503/"); // path to 503 generators // record the total amount of dynamically allocated memory mMemTotal = GetMemTotal(); mHandlerCalls = 0; HttpRequest * req = NULL; - HttpOptions * opts = NULL; + HttpOptions::ptr_t opts; try { - // Get singletons created + // Get singletons created HttpRequest::createService(); // Start threading early so that thread memory is invariant @@ -3213,7 +3123,7 @@ void HttpRequestTestObjectType::test<23>() req = new HttpRequest(); ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); - opts = new HttpOptions(); + opts = HttpOptions::ptr_t(new HttpOptions()); opts->setRetries(1); // Retry once only opts->setUseRetryAfter(true); // Try to parse the retry-after header @@ -3230,8 +3140,8 @@ void HttpRequestTestObjectType::test<23>() 0, 0, opts, - NULL, - &handler); + HttpHeaders::ptr_t(), + handlerp); std::ostringstream testtag; testtag << "Valid handle returned for 503 request #" << i; @@ -3253,7 +3163,7 @@ void HttpRequestTestObjectType::test<23>() // Okay, request a shutdown of the servicing thread mStatus = HttpStatus(); mHandlerCalls = 0; - HttpHandle handle = req->requestStopThread(&handler); + HttpHandle handle = req->requestStopThread(handlerp); ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); // Run the notification pump again @@ -3277,8 +3187,7 @@ void HttpRequestTestObjectType::test<23>() ensure("Thread actually stopped running", HttpService::isStopped()); // release options - opts->release(); - opts = NULL; + opts.reset(); // release the request object delete req; @@ -3299,11 +3208,7 @@ void HttpRequestTestObjectType::test<23>() catch (...) { stop_thread(req); - if (opts) - { - opts->release(); - opts = NULL; - } + opts.reset(); delete req; HttpRequest::destroyService(); throw; diff --git a/indra/llcorehttp/tests/test_httprequestqueue.hpp b/indra/llcorehttp/tests/test_httprequestqueue.hpp index 1de2d8f9ab..ef4ce0479b 100755 --- a/indra/llcorehttp/tests/test_httprequestqueue.hpp +++ b/indra/llcorehttp/tests/test_httprequestqueue.hpp @@ -113,16 +113,16 @@ void HttpRequestqueueTestObjectType::test<3>() HttpRequestQueue * rq = HttpRequestQueue::instanceOf(); - HttpOperation * op = new HttpOpNull(); + HttpOperation::ptr_t op(new HttpOpNull()); rq->addOp(op); // transfer my refcount op = rq->fetchOp(true); // Potentially hangs the test on failure - ensure("One goes in, one comes out", NULL != op); - op->release(); + ensure("One goes in, one comes out", static_cast<bool>(op)); + op.reset(); op = rq->fetchOp(false); - ensure("Better not be two of them", NULL == op); + ensure("Better not be two of them", !op); // release the singleton, hold on to the object HttpRequestQueue::term(); @@ -144,13 +144,13 @@ void HttpRequestqueueTestObjectType::test<4>() HttpRequestQueue * rq = HttpRequestQueue::instanceOf(); - HttpOperation * op = new HttpOpNull(); + HttpOperation::ptr_t op (new HttpOpNull()); rq->addOp(op); // transfer my refcount - op = new HttpOpNull(); + op.reset(new HttpOpNull()); rq->addOp(op); // transfer my refcount - op = new HttpOpNull(); + op.reset(new HttpOpNull()); rq->addOp(op); // transfer my refcount { @@ -159,8 +159,9 @@ void HttpRequestqueueTestObjectType::test<4>() ensure("Three go in, three come out", 3 == ops.size()); op = rq->fetchOp(false); - ensure("Better not be any more of them", NULL == op); - + ensure("Better not be any more of them", !op); + op.reset(); + // release the singleton, hold on to the object HttpRequestQueue::term(); @@ -168,12 +169,13 @@ void HttpRequestqueueTestObjectType::test<4>() ensure(mMemTotal < GetMemTotal()); // Release them - while (! ops.empty()) - { - HttpOperation * op = ops.front(); - ops.erase(ops.begin()); - op->release(); - } + ops.clear(); +// while (! ops.empty()) +// { +// HttpOperation * op = ops.front(); +// ops.erase(ops.begin()); +// op->release(); +// } } // Should be clean diff --git a/indra/llcorehttp/tests/test_httpstatus.hpp b/indra/llcorehttp/tests/test_httpstatus.hpp index 0b379836c9..4502d32fe1 100755 --- a/indra/llcorehttp/tests/test_httpstatus.hpp +++ b/indra/llcorehttp/tests/test_httpstatus.hpp @@ -55,77 +55,68 @@ void HttpStatusTestObjectType::test<1>() // auto allocation fine for this HttpStatus status; - status.mType = HttpStatus::EXT_CURL_EASY; - status.mStatus = 0; + + status = HttpStatus(HttpStatus::EXT_CURL_EASY, 0); ensure(bool(status)); ensure(false == !(status)); - status.mType = HttpStatus::EXT_CURL_MULTI; - status.mStatus = 0; + status = HttpStatus(HttpStatus::EXT_CURL_MULTI, 0); ensure(bool(status)); ensure(false == !(status)); - - status.mType = HttpStatus::LLCORE; - status.mStatus = HE_SUCCESS; + + status = HttpStatus(HttpStatus::LLCORE, HE_SUCCESS); ensure(bool(status)); ensure(false == !(status)); - status.mType = HttpStatus::EXT_CURL_MULTI; - status.mStatus = -1; + status = HttpStatus(HttpStatus::EXT_CURL_MULTI, -1); ensure(false == bool(status)); ensure(!(status)); - status.mType = HttpStatus::EXT_CURL_EASY; - status.mStatus = CURLE_BAD_DOWNLOAD_RESUME; + status = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_BAD_DOWNLOAD_RESUME); ensure(false == bool(status)); ensure(!(status)); } -template <> template <> -void HttpStatusTestObjectType::test<2>() -{ - set_test_name("HttpStatus memory structure"); - - // Require that an HttpStatus object can be trivially - // returned as a function return value in registers. - // One should fit in an int on all platforms. - - ensure(sizeof(HttpStatus) <= sizeof(int)); -} +// template <> template <> +// void HttpStatusTestObjectType::test<2>() +// { +// set_test_name("HttpStatus memory structure"); +// +// // Require that an HttpStatus object can be trivially +// // returned as a function return value in registers. +// // One should fit in an int on all platforms. +// +// //ensure(sizeof(HttpStatus) <= sizeof(int)); +// } template <> template <> -void HttpStatusTestObjectType::test<3>() +void HttpStatusTestObjectType::test<2>() { set_test_name("HttpStatus valid status string conversion"); - HttpStatus status; - status.mType = HttpStatus::EXT_CURL_EASY; - status.mStatus = 0; + HttpStatus status = HttpStatus(HttpStatus::EXT_CURL_EASY, 0); std::string msg = status.toString(); // std::cout << "Result: " << msg << std::endl; ensure(msg.empty()); - - status.mType = HttpStatus::EXT_CURL_EASY; - status.mStatus = CURLE_BAD_FUNCTION_ARGUMENT; + + status = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_BAD_FUNCTION_ARGUMENT); msg = status.toString(); // std::cout << "Result: " << msg << std::endl; ensure(! msg.empty()); - status.mType = HttpStatus::EXT_CURL_MULTI; - status.mStatus = CURLM_OUT_OF_MEMORY; + status = HttpStatus(HttpStatus::EXT_CURL_MULTI, CURLM_OUT_OF_MEMORY); msg = status.toString(); // std::cout << "Result: " << msg << std::endl; ensure(! msg.empty()); - status.mType = HttpStatus::LLCORE; - status.mStatus = HE_SHUTTING_DOWN; + status = HttpStatus(HttpStatus::LLCORE, HE_SHUTTING_DOWN); msg = status.toString(); // std::cout << "Result: " << msg << std::endl; ensure(! msg.empty()); @@ -133,32 +124,28 @@ void HttpStatusTestObjectType::test<3>() template <> template <> -void HttpStatusTestObjectType::test<4>() +void HttpStatusTestObjectType::test<3>() { set_test_name("HttpStatus invalid status string conversion"); - HttpStatus status; - status.mType = HttpStatus::EXT_CURL_EASY; - status.mStatus = 32726; + HttpStatus status = HttpStatus(HttpStatus::EXT_CURL_EASY, 32726); std::string msg = status.toString(); // std::cout << "Result: " << msg << std::endl; ensure(! msg.empty()); - - status.mType = HttpStatus::EXT_CURL_MULTI; - status.mStatus = -470; + + status = HttpStatus(HttpStatus::EXT_CURL_MULTI, -470); msg = status.toString(); // std::cout << "Result: " << msg << std::endl; ensure(! msg.empty()); - status.mType = HttpStatus::LLCORE; - status.mStatus = 923; + status = HttpStatus(HttpStatus::LLCORE, 923); msg = status.toString(); // std::cout << "Result: " << msg << std::endl; ensure(! msg.empty()); } template <> template <> -void HttpStatusTestObjectType::test<5>() +void HttpStatusTestObjectType::test<4>() { set_test_name("HttpStatus equality/inequality testing"); @@ -170,62 +157,55 @@ void HttpStatusTestObjectType::test<5>() HttpStatus status2(HttpStatus::EXT_CURL_EASY, HE_SUCCESS); ensure(status1 != status2); - status1.mType = HttpStatus::LLCORE; - status1.mStatus = HE_REPLY_ERROR; - status2.mType = HttpStatus::LLCORE; - status2.mStatus= HE_SHUTTING_DOWN; + status1 = HttpStatus(HttpStatus::LLCORE, HE_REPLY_ERROR); + status1 = HttpStatus(HttpStatus::LLCORE, HE_SHUTTING_DOWN); + ensure(status1 != status2); } template <> template <> -void HttpStatusTestObjectType::test<6>() +void HttpStatusTestObjectType::test<5>() { set_test_name("HttpStatus basic HTTP status encoding"); HttpStatus status; - status.mType = 200; - status.mStatus = HE_SUCCESS; + + status = HttpStatus(200, HE_SUCCESS); std::string msg = status.toString(); ensure(msg.empty()); ensure(bool(status)); // Normally a success but application says error - status.mStatus = HE_REPLY_ERROR; + status = HttpStatus(200, HE_REPLY_ERROR); msg = status.toString(); ensure(! msg.empty()); ensure(! bool(status)); ensure(status.toULong() > 1UL); // Biggish number, not a bool-to-ulong // Same statuses with distinct success/fail are distinct - status.mType = 200; - status.mStatus = HE_SUCCESS; + status = HttpStatus(200, HE_SUCCESS); HttpStatus status2(200, HE_REPLY_ERROR); ensure(status != status2); // Normally an error but application says okay - status.mType = 406; - status.mStatus = HE_SUCCESS; + status = HttpStatus(406, HE_SUCCESS); msg = status.toString(); ensure(msg.empty()); ensure(bool(status)); // Different statuses but both successful are distinct - status.mType = 200; - status.mStatus = HE_SUCCESS; - status2.mType = 201; - status2.mStatus = HE_SUCCESS; + status = HttpStatus(200, HE_SUCCESS); + status2 = HttpStatus(201, HE_SUCCESS); ensure(status != status2); // Different statuses but both failed are distinct - status.mType = 200; - status.mStatus = HE_REPLY_ERROR; - status2.mType = 201; - status2.mStatus = HE_REPLY_ERROR; + status = HttpStatus(200, HE_REPLY_ERROR); + status2 = HttpStatus(201, HE_REPLY_ERROR); ensure(status != status2); } template <> template <> -void HttpStatusTestObjectType::test<7>() +void HttpStatusTestObjectType::test<6>() { set_test_name("HttpStatus HTTP status text strings"); @@ -234,34 +214,30 @@ void HttpStatusTestObjectType::test<7>() ensure(! msg.empty()); // Should be something ensure(msg == "Continue"); - status.mStatus = HE_SUCCESS; + status = HttpStatus(200, HE_SUCCESS); msg = status.toString(); ensure(msg.empty()); // Success is empty - status.mType = 199; - status.mStatus = HE_REPLY_ERROR; + status = HttpStatus(199, HE_REPLY_ERROR); msg = status.toString(); ensure(msg == "Unknown error"); - status.mType = 505; // Last defined string - status.mStatus = HE_REPLY_ERROR; + status = HttpStatus(505, HE_REPLY_ERROR); msg = status.toString(); ensure(msg == "HTTP Version not supported"); - status.mType = 506; // One beyond - status.mStatus = HE_REPLY_ERROR; + status = HttpStatus(506, HE_REPLY_ERROR); msg = status.toString(); ensure(msg == "Unknown error"); - status.mType = 999; // Last HTTP status - status.mStatus = HE_REPLY_ERROR; + status = HttpStatus(999, HE_REPLY_ERROR); msg = status.toString(); ensure(msg == "Unknown error"); } template <> template <> -void HttpStatusTestObjectType::test<8>() +void HttpStatusTestObjectType::test<7>() { set_test_name("HttpStatus toHex() nominal function"); @@ -273,7 +249,7 @@ void HttpStatusTestObjectType::test<8>() template <> template <> -void HttpStatusTestObjectType::test<9>() +void HttpStatusTestObjectType::test<8>() { set_test_name("HttpStatus toTerseString() nominal function"); |