diff options
author | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2024-06-10 17:06:06 +0300 |
---|---|---|
committer | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2024-06-10 19:25:02 +0300 |
commit | 0dcc912cecdfb365c1f4246545ece40ccb7bc18e (patch) | |
tree | ccf664c765d1adbbf4985069321df65c85ca36e2 /indra/llcorehttp | |
parent | bd8438f7083643ae5812b14e35e69e69ef1616c6 (diff) | |
parent | d317454c82e016a02c8a708a0118f3ff29aa8e82 (diff) |
Merge main into inventory_favorites
# Conflicts:
# indra/llui/llfolderviewmodel.h
# indra/newview/llpanelwearing.cpp
# indra/newview/llwearableitemslist.cpp
Diffstat (limited to 'indra/llcorehttp')
64 files changed, 10079 insertions, 10079 deletions
diff --git a/indra/llcorehttp/_httpinternal.h b/indra/llcorehttp/_httpinternal.h index 690ebbecd8..768ef98330 100644 --- a/indra/llcorehttp/_httpinternal.h +++ b/indra/llcorehttp/_httpinternal.h @@ -24,8 +24,8 @@ * $/LicenseInfo$ */ -#ifndef _LLCORE_HTTP_INTERNAL_H_ -#define _LLCORE_HTTP_INTERNAL_H_ +#ifndef _LLCORE_HTTP_INTERNAL_H_ +#define _LLCORE_HTTP_INTERNAL_H_ // If you find this included in a public interface header, @@ -97,14 +97,14 @@ // Reprioritization requests have the side-effect of then // putting the modified request at the back of the ready queue. -#define LLCORE_HTTP_READY_QUEUE_IGNORES_PRIORITY 1 +#define LLCORE_HTTP_READY_QUEUE_IGNORES_PRIORITY 1 namespace LLCore { // Maxium number of policy classes that can be defined. -// *TODO: Currently limited to the default class + 1, extend. +// *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; @@ -168,4 +168,4 @@ const int HTTP_SERVICE_LOOP_SLEEP_NORMAL_MS = 2; } // end namespace LLCore -#endif // _LLCORE_HTTP_INTERNAL_H_ +#endif // _LLCORE_HTTP_INTERNAL_H_ diff --git a/indra/llcorehttp/_httplibcurl.cpp b/indra/llcorehttp/_httplibcurl.cpp index bd0ac740db..e646271c84 100644 --- a/indra/llcorehttp/_httplibcurl.cpp +++ b/indra/llcorehttp/_httplibcurl.cpp @@ -59,80 +59,80 @@ namespace LLCore HttpLibcurl::HttpLibcurl(HttpService * service) - : mService(service), - mHandleCache(), - mPolicyCount(0), - mMultiHandles(NULL), - mActiveHandles(NULL), - mDirtyPolicy(NULL) + : mService(service), + mHandleCache(), + mPolicyCount(0), + mMultiHandles(NULL), + mActiveHandles(NULL), + mDirtyPolicy(NULL) {} HttpLibcurl::~HttpLibcurl() { - shutdown(); + shutdown(); - mService = NULL; + mService = NULL; } void HttpLibcurl::shutdown() { - while (! mActiveOps.empty()) - { - HttpOpRequest::ptr_t op(* mActiveOps.begin()); - mActiveOps.erase(mActiveOps.begin()); - - cancelRequest(op); - } - - if (mMultiHandles) - { - for (int policy_class(0); policy_class < mPolicyCount; ++policy_class) - { - if (mMultiHandles[policy_class]) - { - curl_multi_cleanup(mMultiHandles[policy_class]); - mMultiHandles[policy_class] = 0; - } - } - - delete [] mMultiHandles; - mMultiHandles = NULL; - - delete [] mActiveHandles; - mActiveHandles = NULL; - - delete [] mDirtyPolicy; - mDirtyPolicy = NULL; - } - - mPolicyCount = 0; + while (! mActiveOps.empty()) + { + HttpOpRequest::ptr_t op(* mActiveOps.begin()); + mActiveOps.erase(mActiveOps.begin()); + + cancelRequest(op); + } + + if (mMultiHandles) + { + for (int policy_class(0); policy_class < mPolicyCount; ++policy_class) + { + if (mMultiHandles[policy_class]) + { + curl_multi_cleanup(mMultiHandles[policy_class]); + mMultiHandles[policy_class] = 0; + } + } + + delete [] mMultiHandles; + mMultiHandles = NULL; + + delete [] mActiveHandles; + mActiveHandles = NULL; + + delete [] mDirtyPolicy; + mDirtyPolicy = NULL; + } + + mPolicyCount = 0; } void HttpLibcurl::start(int policy_count) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - llassert_always(policy_count <= HTTP_POLICY_CLASS_LIMIT); - llassert_always(! mMultiHandles); // One-time call only - - mPolicyCount = policy_count; - mMultiHandles = new CURLM * [mPolicyCount]; - mActiveHandles = new int [mPolicyCount]; - mDirtyPolicy = new bool [mPolicyCount]; - - for (int policy_class(0); policy_class < mPolicyCount; ++policy_class) - { - if (NULL == (mMultiHandles[policy_class] = curl_multi_init())) - { - LL_ERRS(LOG_CORE) << "Failed to allocate multi handle in libcurl." - << LL_ENDL; - } - mActiveHandles[policy_class] = 0; - mDirtyPolicy[policy_class] = false; - policyUpdated(policy_class); - } + llassert_always(policy_count <= HTTP_POLICY_CLASS_LIMIT); + llassert_always(! mMultiHandles); // One-time call only + + mPolicyCount = policy_count; + mMultiHandles = new CURLM * [mPolicyCount]; + mActiveHandles = new int [mPolicyCount]; + mDirtyPolicy = new bool [mPolicyCount]; + + for (int policy_class(0); policy_class < mPolicyCount; ++policy_class) + { + if (NULL == (mMultiHandles[policy_class] = curl_multi_init())) + { + LL_ERRS(LOG_CORE) << "Failed to allocate multi handle in libcurl." + << LL_ENDL; + } + mActiveHandles[policy_class] = 0; + mDirtyPolicy[policy_class] = false; + policyUpdated(policy_class); + } } @@ -145,40 +145,40 @@ void HttpLibcurl::start(int policy_count) HttpService::ELoopSpeed HttpLibcurl::processTransport() { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - HttpService::ELoopSpeed ret(HttpService::REQUEST_SLEEP); - - // Give libcurl some cycles to do I/O & callbacks - for (int policy_class(0); policy_class < mPolicyCount; ++policy_class) - { - if (! mMultiHandles[policy_class]) - { - // No handle, nothing to do. - continue; - } - if (! mActiveHandles[policy_class]) - { - // If we've gone quiet and there's a dirty update, apply it, - // otherwise we're done. - if (mDirtyPolicy[policy_class]) - { - policyUpdated(policy_class); - } - continue; - } - - int running(0); - CURLMcode status(CURLM_CALL_MULTI_PERFORM); - do - { + HttpService::ELoopSpeed ret(HttpService::REQUEST_SLEEP); + + // Give libcurl some cycles to do I/O & callbacks + for (int policy_class(0); policy_class < mPolicyCount; ++policy_class) + { + if (! mMultiHandles[policy_class]) + { + // No handle, nothing to do. + continue; + } + if (! mActiveHandles[policy_class]) + { + // If we've gone quiet and there's a dirty update, apply it, + // otherwise we're done. + if (mDirtyPolicy[policy_class]) + { + policyUpdated(policy_class); + } + continue; + } + + int running(0); + CURLMcode status(CURLM_CALL_MULTI_PERFORM); + do + { LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("httppt - curl_multi_perform"); - running = 0; - status = curl_multi_perform(mMultiHandles[policy_class], &running); - } - while (0 != running && CURLM_CALL_MULTI_PERFORM == status); - - // Run completion on anything done - CURLMsg * msg(NULL); - int msgs_in_queue(0); + running = 0; + status = curl_multi_perform(mMultiHandles[policy_class], &running); + } + while (0 != running && CURLM_CALL_MULTI_PERFORM == status); + + // Run completion on anything done + CURLMsg * msg(NULL); + int msgs_in_queue(0); { LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("httppt - curl_multi_info_read"); while ((msg = curl_multi_info_read(mMultiHandles[policy_class], &msgs_in_queue))) @@ -189,8 +189,8 @@ HttpService::ELoopSpeed HttpLibcurl::processTransport() CURLcode result(msg->data.result); completeRequest(mMultiHandles[policy_class], handle, result); - handle = NULL; // No longer valid on return - ret = HttpService::NORMAL; // If anything completes, we may have a free slot. + handle = NULL; // No longer valid on return + ret = HttpService::NORMAL; // If anything completes, we may have a free slot. // Turning around quickly reduces connection gap by 7-10mS. } else if (CURLMSG_NONE == msg->msg) @@ -207,13 +207,13 @@ HttpService::ELoopSpeed HttpLibcurl::processTransport() msgs_in_queue = 0; } } - } + } - if (! mActiveOps.empty()) - { - ret = HttpService::NORMAL; - } - return ret; + if (! mActiveOps.empty()) + { + ret = HttpService::NORMAL; + } + return ret; } @@ -221,40 +221,40 @@ HttpService::ELoopSpeed HttpLibcurl::processTransport() void HttpLibcurl::addOp(const HttpOpRequest::ptr_t &op) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - llassert_always(op->mReqPolicy < mPolicyCount); - llassert_always(mMultiHandles[op->mReqPolicy] != NULL); - - // Create standard handle - if (! op->prepareRequest(mService)) - { - // Couldn't issue request, fail with notification - // *TODO: Need failure path - return; - } - - // Make the request live - CURLMcode code; - code = curl_multi_add_handle(mMultiHandles[op->mReqPolicy], op->mCurlHandle); - if (CURLM_OK != code) - { - // *TODO: Better cleanup and recovery but not much we can do here. - check_curl_multi_code(code); - return; - } - op->mCurlActive = true; - mActiveOps.insert(op); - ++mActiveHandles[op->mReqPolicy]; - - if (op->mTracing > HTTP_TRACE_OFF) - { - HttpPolicy & policy(mService->getPolicy()); - - LL_INFOS(LOG_CORE) << "TRACE, ToActiveQueue, Handle: " + llassert_always(op->mReqPolicy < mPolicyCount); + llassert_always(mMultiHandles[op->mReqPolicy] != NULL); + + // Create standard handle + if (! op->prepareRequest(mService)) + { + // Couldn't issue request, fail with notification + // *TODO: Need failure path + return; + } + + // Make the request live + CURLMcode code; + code = curl_multi_add_handle(mMultiHandles[op->mReqPolicy], op->mCurlHandle); + if (CURLM_OK != code) + { + // *TODO: Better cleanup and recovery but not much we can do here. + check_curl_multi_code(code); + return; + } + op->mCurlActive = true; + mActiveOps.insert(op); + ++mActiveHandles[op->mReqPolicy]; + + if (op->mTracing > HTTP_TRACE_OFF) + { + HttpPolicy & policy(mService->getPolicy()); + + LL_INFOS(LOG_CORE) << "TRACE, ToActiveQueue, Handle: " << op->getHandle() - << ", Actives: " << mActiveOps.size() - << ", Readies: " << policy.getReadyCount(op->mReqPolicy) - << LL_ENDL; - } + << ", Actives: " << mActiveOps.size() + << ", Readies: " << policy.getReadyCount(op->mReqPolicy) + << LL_ENDL; + } } @@ -266,20 +266,20 @@ bool HttpLibcurl::cancel(HttpHandle handle) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; HttpOpRequest::ptr_t op = HttpOpRequest::fromHandle<HttpOpRequest>(handle); - active_set_t::iterator it(mActiveOps.find(op)); - if (mActiveOps.end() == it) - { - return false; - } + active_set_t::iterator it(mActiveOps.find(op)); + if (mActiveOps.end() == it) + { + return false; + } - // Cancel request - cancelRequest(op); + // Cancel request + cancelRequest(op); - // Drop references - mActiveOps.erase(it); - --mActiveHandles[op->mReqPolicy]; + // Drop references + mActiveOps.erase(it); + --mActiveHandles[op->mReqPolicy]; - return true; + return true; } @@ -291,25 +291,25 @@ bool HttpLibcurl::cancel(HttpHandle handle) void HttpLibcurl::cancelRequest(const HttpOpRequest::ptr_t &op) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - // Deactivate request - op->mCurlActive = false; - - // Detach from multi and recycle handle - curl_multi_remove_handle(mMultiHandles[op->mReqPolicy], op->mCurlHandle); - mHandleCache.freeHandle(op->mCurlHandle); - op->mCurlHandle = NULL; - - // Tracing - if (op->mTracing > HTTP_TRACE_OFF) - { - LL_INFOS(LOG_CORE) << "TRACE, RequestCanceled, Handle: " - << op->getHandle() - << ", Status: " << op->mStatus.toTerseString() - << LL_ENDL; - } - - // Cancel op and deliver for notification - op->cancel(); + // Deactivate request + op->mCurlActive = false; + + // Detach from multi and recycle handle + curl_multi_remove_handle(mMultiHandles[op->mReqPolicy], op->mCurlHandle); + mHandleCache.freeHandle(op->mCurlHandle); + op->mCurlHandle = NULL; + + // Tracing + if (op->mTracing > HTTP_TRACE_OFF) + { + LL_INFOS(LOG_CORE) << "TRACE, RequestCanceled, Handle: " + << op->getHandle() + << ", Status: " << op->mStatus.toTerseString() + << LL_ENDL; + } + + // Cancel op and deliver for notification + op->cancel(); } @@ -322,47 +322,47 @@ bool HttpLibcurl::completeRequest(CURLM * multi_handle, CURL * handle, CURLcode CURLcode ccode(CURLE_OK); - ccode = curl_easy_getinfo(handle, CURLINFO_PRIVATE, &ophandle); + 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) - { - LL_WARNS(LOG_CORE) << "libcurl handle and HttpOpRequest handle in disagreement or inactive request." - << " Handle: " << static_cast<HttpHandle>(handle) - << LL_ENDL; - return false; - } - - active_set_t::iterator it(mActiveOps.find(op)); - if (mActiveOps.end() == it) - { - LL_WARNS(LOG_CORE) << "libcurl completion for request not on active list. Continuing." - << " Handle: " << static_cast<HttpHandle>(handle) - << LL_ENDL; - return false; - } - - // Deactivate request - mActiveOps.erase(it); - --mActiveHandles[op->mReqPolicy]; - op->mCurlActive = false; - - // Set final status of request if it hasn't failed by other mechanisms yet - if (op->mStatus) - { - op->mStatus = HttpStatus(HttpStatus::EXT_CURL_EASY, status); - } + if (handle != op->mCurlHandle || ! op->mCurlActive) + { + LL_WARNS(LOG_CORE) << "libcurl handle and HttpOpRequest handle in disagreement or inactive request." + << " Handle: " << static_cast<HttpHandle>(handle) + << LL_ENDL; + return false; + } + + active_set_t::iterator it(mActiveOps.find(op)); + if (mActiveOps.end() == it) + { + LL_WARNS(LOG_CORE) << "libcurl completion for request not on active list. Continuing." + << " Handle: " << static_cast<HttpHandle>(handle) + << LL_ENDL; + return false; + } + + // Deactivate request + mActiveOps.erase(it); + --mActiveHandles[op->mReqPolicy]; + op->mCurlActive = false; + + // Set final status of request if it hasn't failed by other mechanisms yet + if (op->mStatus) + { + op->mStatus = HttpStatus(HttpStatus::EXT_CURL_EASY, status); + } if (op->mStatus) { // note: CURLINFO_RESPONSE_CODE requires a long - https://curl.haxx.se/libcurl/c/CURLINFO_RESPONSE_CODE.html @@ -407,7 +407,7 @@ bool HttpLibcurl::completeRequest(CURLM * multi_handle, CURL * handle, CURLcode { LL_WARNS(LOG_CORE) << "Attempt to retrieve status from NULL handle!" << LL_ENDL; } - } + } if (multi_handle && handle) { @@ -417,115 +417,115 @@ bool HttpLibcurl::completeRequest(CURLM * multi_handle, CURL * handle, CURLcode } else { - LL_WARNS(LOG_CORE) << "Curl multi_handle or handle is NULL on remove! multi:" + 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: " + // Tracing + if (op->mTracing > HTTP_TRACE_OFF) + { + LL_INFOS(LOG_CORE) << "TRACE, RequestComplete, Handle: " << op->getHandle() - << ", Status: " << op->mStatus.toTerseString() - << LL_ENDL; - } + << ", Status: " << op->mStatus.toTerseString() + << LL_ENDL; + } - // Dispatch to next stage - HttpPolicy & policy(mService->getPolicy()); - bool still_active(policy.stageAfterCompletion(op)); + // Dispatch to next stage + HttpPolicy & policy(mService->getPolicy()); + bool still_active(policy.stageAfterCompletion(op)); - return still_active; + return still_active; } int HttpLibcurl::getActiveCount() const { - return mActiveOps.size(); + return mActiveOps.size(); } int HttpLibcurl::getActiveCountInClass(int policy_class) const { - llassert_always(policy_class < mPolicyCount); + llassert_always(policy_class < mPolicyCount); - return mActiveHandles ? mActiveHandles[policy_class] : 0; + return mActiveHandles ? mActiveHandles[policy_class] : 0; } void HttpLibcurl::policyUpdated(int policy_class) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - if (policy_class < 0 || policy_class >= mPolicyCount || ! mMultiHandles) - { - return; - } - - HttpPolicy & policy(mService->getPolicy()); - - if (! mActiveHandles[policy_class]) - { - // Clear to set options. As of libcurl 7.37.0, if a pipelining - // multi handle has active requests and you try to set the - // multi handle to non-pipelining, the library gets very angry - // and goes off the rails corrupting memory. A clue that you're - // about to crash is that you'll get a missing server response - // error (curl code 9). So, if options are to be set, we let - // the multi handle run out of requests, then set options, and - // re-enable request processing. - // - // All of this stall mechanism exists for this reason. If - // libcurl becomes more resilient later, it should be possible - // to remove all of this. The connection limit settings are fine, - // it's just that pipelined-to-non-pipelined transition that - // is fatal at the moment. - - HttpPolicyClass & options(policy.getClassOptions(policy_class)); - CURLM * multi_handle(mMultiHandles[policy_class]); - - // Enable policy if stalled - policy.stallPolicy(policy_class, false); - mDirtyPolicy[policy_class] = false; - - if (options.mPipelining > 1) - { - // We'll try to do pipelining on this multihandle - check_curl_multi_setopt(multi_handle, - CURLMOPT_PIPELINING, - 1L); - check_curl_multi_setopt(multi_handle, - CURLMOPT_MAX_PIPELINE_LENGTH, - long(options.mPipelining)); - check_curl_multi_setopt(multi_handle, - CURLMOPT_MAX_HOST_CONNECTIONS, - long(options.mPerHostConnectionLimit)); - check_curl_multi_setopt(multi_handle, - CURLMOPT_MAX_TOTAL_CONNECTIONS, - long(options.mConnectionLimit)); - } - else - { - check_curl_multi_setopt(multi_handle, - CURLMOPT_PIPELINING, - 0L); - check_curl_multi_setopt(multi_handle, - CURLMOPT_MAX_HOST_CONNECTIONS, - 0L); - check_curl_multi_setopt(multi_handle, - CURLMOPT_MAX_TOTAL_CONNECTIONS, - long(options.mConnectionLimit)); - } - } - else if (! mDirtyPolicy[policy_class]) - { - // Mark policy dirty and request a stall in the policy. - // When policy goes idle, we'll re-invoke this method - // and perform the change. Don't allow this thread to - // sleep while we're waiting for quiescence, we'll just - // stop processing. - mDirtyPolicy[policy_class] = true; - policy.stallPolicy(policy_class, true); - } + if (policy_class < 0 || policy_class >= mPolicyCount || ! mMultiHandles) + { + return; + } + + HttpPolicy & policy(mService->getPolicy()); + + if (! mActiveHandles[policy_class]) + { + // Clear to set options. As of libcurl 7.37.0, if a pipelining + // multi handle has active requests and you try to set the + // multi handle to non-pipelining, the library gets very angry + // and goes off the rails corrupting memory. A clue that you're + // about to crash is that you'll get a missing server response + // error (curl code 9). So, if options are to be set, we let + // the multi handle run out of requests, then set options, and + // re-enable request processing. + // + // All of this stall mechanism exists for this reason. If + // libcurl becomes more resilient later, it should be possible + // to remove all of this. The connection limit settings are fine, + // it's just that pipelined-to-non-pipelined transition that + // is fatal at the moment. + + HttpPolicyClass & options(policy.getClassOptions(policy_class)); + CURLM * multi_handle(mMultiHandles[policy_class]); + + // Enable policy if stalled + policy.stallPolicy(policy_class, false); + mDirtyPolicy[policy_class] = false; + + if (options.mPipelining > 1) + { + // We'll try to do pipelining on this multihandle + check_curl_multi_setopt(multi_handle, + CURLMOPT_PIPELINING, + 1L); + check_curl_multi_setopt(multi_handle, + CURLMOPT_MAX_PIPELINE_LENGTH, + long(options.mPipelining)); + check_curl_multi_setopt(multi_handle, + CURLMOPT_MAX_HOST_CONNECTIONS, + long(options.mPerHostConnectionLimit)); + check_curl_multi_setopt(multi_handle, + CURLMOPT_MAX_TOTAL_CONNECTIONS, + long(options.mConnectionLimit)); + } + else + { + check_curl_multi_setopt(multi_handle, + CURLMOPT_PIPELINING, + 0L); + check_curl_multi_setopt(multi_handle, + CURLMOPT_MAX_HOST_CONNECTIONS, + 0L); + check_curl_multi_setopt(multi_handle, + CURLMOPT_MAX_TOTAL_CONNECTIONS, + long(options.mConnectionLimit)); + } + } + else if (! mDirtyPolicy[policy_class]) + { + // Mark policy dirty and request a stall in the policy. + // When policy goes idle, we'll re-invoke this method + // and perform the change. Don't allow this thread to + // sleep while we're waiting for quiescence, we'll just + // stop processing. + mDirtyPolicy[policy_class] = true; + policy.stallPolicy(policy_class, true); + } } // --------------------------------------- @@ -533,75 +533,75 @@ void HttpLibcurl::policyUpdated(int policy_class) // --------------------------------------- HttpLibcurl::HandleCache::HandleCache() - : mHandleTemplate(NULL) + : mHandleTemplate(NULL) { - mCache.reserve(50); + mCache.reserve(50); } HttpLibcurl::HandleCache::~HandleCache() { - if (mHandleTemplate) - { - curl_easy_cleanup(mHandleTemplate); - mHandleTemplate = NULL; - } - - for (handle_cache_t::iterator it(mCache.begin()); mCache.end() != it; ++it) - { - curl_easy_cleanup(*it); - } - mCache.clear(); + if (mHandleTemplate) + { + curl_easy_cleanup(mHandleTemplate); + mHandleTemplate = NULL; + } + + for (handle_cache_t::iterator it(mCache.begin()); mCache.end() != it; ++it) + { + curl_easy_cleanup(*it); + } + mCache.clear(); } CURL * HttpLibcurl::HandleCache::getHandle() { - CURL * ret(NULL); - - if (! mCache.empty()) - { - // Fastest path to handle - ret = mCache.back(); - mCache.pop_back(); - } - else if (mHandleTemplate) - { - // Still fast path - ret = curl_easy_duphandle(mHandleTemplate); - } - else - { - // When all else fails - ret = curl_easy_init(); - } - - return ret; + CURL * ret(NULL); + + if (! mCache.empty()) + { + // Fastest path to handle + ret = mCache.back(); + mCache.pop_back(); + } + else if (mHandleTemplate) + { + // Still fast path + ret = curl_easy_duphandle(mHandleTemplate); + } + else + { + // When all else fails + ret = curl_easy_init(); + } + + return ret; } void HttpLibcurl::HandleCache::freeHandle(CURL * handle) { - if (! handle) - { - return; - } - - curl_easy_reset(handle); - if (! mHandleTemplate) - { - // Save the first freed handle as a template. - mHandleTemplate = handle; - } - else - { - // Otherwise add it to the cache - if (mCache.size() >= mCache.capacity()) - { - mCache.reserve(mCache.capacity() + 50); - } - mCache.push_back(handle); - } + if (! handle) + { + return; + } + + curl_easy_reset(handle); + if (! mHandleTemplate) + { + // Save the first freed handle as a template. + mHandleTemplate = handle; + } + else + { + // Otherwise add it to the cache + if (mCache.size() >= mCache.capacity()) + { + mCache.reserve(mCache.capacity() + 50); + } + mCache.push_back(handle); + } } @@ -612,46 +612,46 @@ void HttpLibcurl::HandleCache::freeHandle(CURL * handle) 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) - { - static const char sep[] = ": "; - std::string header; - header.reserve((*it).first.size() + (*it).second.size() + sizeof(sep)); - header.append((*it).first); - header.append(sep); - header.append((*it).second); - - slist = curl_slist_append(slist, header.c_str()); - } - return slist; + const HttpHeaders::const_iterator end(headers->end()); + for (HttpHeaders::const_iterator it(headers->begin()); end != it; ++it) + { + static const char sep[] = ": "; + std::string header; + header.reserve((*it).first.size() + (*it).second.size() + sizeof(sep)); + header.append((*it).first); + header.append(sep); + header.append((*it).second); + + slist = curl_slist_append(slist, header.c_str()); + } + return slist; } } // end namespace LLCore -namespace +namespace { - + void check_curl_multi_code(CURLMcode code, int curl_setopt_option) { - if (CURLM_OK != code) - { - LL_WARNS(LOG_CORE) << "libcurl multi error detected: " << curl_multi_strerror(code) - << ", curl_multi_setopt option: " << curl_setopt_option - << LL_ENDL; - } + if (CURLM_OK != code) + { + LL_WARNS(LOG_CORE) << "libcurl multi error detected: " << curl_multi_strerror(code) + << ", curl_multi_setopt option: " << curl_setopt_option + << LL_ENDL; + } } void check_curl_multi_code(CURLMcode code) { - if (CURLM_OK != code) - { - LL_WARNS(LOG_CORE) << "libcurl multi error detected: " << curl_multi_strerror(code) - << LL_ENDL; - } + if (CURLM_OK != code) + { + LL_WARNS(LOG_CORE) << "libcurl multi error detected: " << curl_multi_strerror(code) + << LL_ENDL; + } } } // end anonymous namespace diff --git a/indra/llcorehttp/_httplibcurl.h b/indra/llcorehttp/_httplibcurl.h index 61ecc492af..a1b537d354 100644 --- a/indra/llcorehttp/_httplibcurl.h +++ b/indra/llcorehttp/_httplibcurl.h @@ -24,10 +24,10 @@ * $/LicenseInfo$ */ -#ifndef _LLCORE_HTTP_LIBCURL_H_ -#define _LLCORE_HTTP_LIBCURL_H_ +#ifndef _LLCORE_HTTP_LIBCURL_H_ +#define _LLCORE_HTTP_LIBCURL_H_ -#include "linden_common.h" // Modifies curl/curl.h interfaces +#include "linden_common.h" // Modifies curl/curl.h interfaces #include <curl/curl.h> #include <curl/multi.h> @@ -57,165 +57,165 @@ class HttpHeaders; class HttpLibcurl { public: - HttpLibcurl(HttpService * service); - virtual ~HttpLibcurl(); + HttpLibcurl(HttpService * service); + virtual ~HttpLibcurl(); private: - HttpLibcurl(const HttpLibcurl &); // Not defined - void operator=(const HttpLibcurl &); // Not defined + HttpLibcurl(const HttpLibcurl &); // Not defined + void operator=(const HttpLibcurl &); // Not defined public: typedef std::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. - /// - /// @return Indication of how long this method is - /// willing to wait for next service call. - /// - /// Threading: called by worker thread. - HttpService::ELoopSpeed processTransport(); - - /// Add request to the active list. Caller is expected to have - /// provided us with a reference count on the op to hold the - /// request. (No additional references will be added.) - /// - /// Threading: called by worker thread. + /// 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. + /// + /// @return Indication of how long this method is + /// willing to wait for next service call. + /// + /// Threading: called by worker thread. + HttpService::ELoopSpeed processTransport(); + + /// Add request to the active list. Caller is expected to have + /// provided us with a reference count on the op to hold the + /// request. (No additional references will be added.) + /// + /// Threading: called by worker thread. 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 - /// must agree with HttpPolicy::setPolicies() call. - /// - /// Threading: called by init thread. - void start(int policy_count); - - /// Synchronously stop libcurl operations. All active requests - /// are canceled and removed from libcurl's handling. Easy - /// handles are detached from their multi handles and released. - /// Multi handles are also released. Canceled requests are - /// completed with canceled status and made available on their - /// respective reply queues. - /// - /// Can be restarted with a start() call. - /// - /// Threading: called by worker thread. - void shutdown(); - - /// Return global and per-class counts of active requests. - /// - /// Threading: called by worker thread. - int getActiveCount() const; - int getActiveCountInClass(int policy_class) const; - - /// Attempt to cancel a request identified by handle. - /// - /// Interface shadows HttpService's method. - /// - /// @return True if handle was found and operation canceled. - /// - /// Threading: called by worker thread. - bool cancel(HttpHandle handle); - - /// Informs transport that a particular policy class has had - /// options changed and so should effect any transport state - /// change necessary to effect those changes. Used mainly for - /// initialization and dynamic option setting. - /// - /// Threading: called by worker thread. - void policyUpdated(int policy_class); - - /// Allocate a curl handle for caller. May be freed using - /// either the freeHandle() method or calling curl_easy_cleanup() - /// directly. - /// - /// @return Libcurl handle (CURL *) or NULL on allocation - /// problem. Handle will be in curl_easy_reset() - /// condition. - /// - /// Threading: callable by worker thread. - /// - /// Deprecation: Expect this to go away after _httpoprequest is - /// refactored bringing code into this class. - CURL * getHandle() - { - return mHandleCache.getHandle(); - } + /// One-time call to set the number of policy classes to be + /// serviced and to create the resources for each. Value + /// must agree with HttpPolicy::setPolicies() call. + /// + /// Threading: called by init thread. + void start(int policy_count); + + /// Synchronously stop libcurl operations. All active requests + /// are canceled and removed from libcurl's handling. Easy + /// handles are detached from their multi handles and released. + /// Multi handles are also released. Canceled requests are + /// completed with canceled status and made available on their + /// respective reply queues. + /// + /// Can be restarted with a start() call. + /// + /// Threading: called by worker thread. + void shutdown(); + + /// Return global and per-class counts of active requests. + /// + /// Threading: called by worker thread. + int getActiveCount() const; + int getActiveCountInClass(int policy_class) const; + + /// Attempt to cancel a request identified by handle. + /// + /// Interface shadows HttpService's method. + /// + /// @return True if handle was found and operation canceled. + /// + /// Threading: called by worker thread. + bool cancel(HttpHandle handle); + + /// Informs transport that a particular policy class has had + /// options changed and so should effect any transport state + /// change necessary to effect those changes. Used mainly for + /// initialization and dynamic option setting. + /// + /// Threading: called by worker thread. + void policyUpdated(int policy_class); + + /// Allocate a curl handle for caller. May be freed using + /// either the freeHandle() method or calling curl_easy_cleanup() + /// directly. + /// + /// @return Libcurl handle (CURL *) or NULL on allocation + /// problem. Handle will be in curl_easy_reset() + /// condition. + /// + /// Threading: callable by worker thread. + /// + /// Deprecation: Expect this to go away after _httpoprequest is + /// refactored bringing code into this class. + CURL * getHandle() + { + return mHandleCache.getHandle(); + } protected: - /// Invoked when libcurl has indicated a request has been processed - /// to completion and we need to move the request to a new state. - bool completeRequest(CURLM * multi_handle, CURL * handle, CURLcode status); + /// Invoked when libcurl has indicated a request has been processed + /// to completion and we need to move the request to a new state. + bool completeRequest(CURLM * multi_handle, CURL * handle, CURLcode status); - /// Invoked to cancel an active request, mainly during shutdown - /// and destroy. + /// Invoked to cancel an active request, mainly during shutdown + /// and destroy. void cancelRequest(const opReqPtr_t &op); - + protected: typedef std::set<opReqPtr_t> active_set_t; - /// Simple request handle cache for libcurl. - /// - /// Handle creation is somewhat slow and chunky in libcurl and there's - /// a pretty good speedup to be had from handle re-use. So, a simple - /// vector is kept of 'freed' handles to be reused as needed. When - /// that is empty, the first freed handle is kept as a template for - /// handle duplication. This is still faster than creation from nothing. - /// And when that fails, we init fresh from curl_easy_init(). - /// - /// Handles allocated with getHandle() may be freed with either - /// freeHandle() or curl_easy_cleanup(). Choice may be dictated - /// by thread constraints. - /// - /// Threading: Single-threaded. May only be used by a single thread, - /// typically the worker thread. If freeing requests' handles in an - /// unknown threading context, use curl_easy_cleanup() for safety. - - class HandleCache - { - public: - HandleCache(); - ~HandleCache(); - - private: - HandleCache(const HandleCache &); // Not defined - void operator=(const HandleCache &); // Not defined - - public: - /// Allocate a curl handle for caller. May be freed using - /// either the freeHandle() method or calling curl_easy_cleanup() - /// directly. - /// - /// @return Libcurl handle (CURL *) or NULL on allocation - /// problem. - /// - /// Threading: Single-thread (worker) only. - CURL * getHandle(); - - /// Free a libcurl handle acquired by whatever means. Thread - /// safety is left to the caller. - /// - /// Threading: Single-thread (worker) only. - void freeHandle(CURL * handle); - - protected: - typedef std::vector<CURL *> handle_cache_t; - - protected: - CURL * mHandleTemplate; // Template for duplicating new handles - handle_cache_t mCache; // Cache of old handles - }; // end class HandleCache - + /// Simple request handle cache for libcurl. + /// + /// Handle creation is somewhat slow and chunky in libcurl and there's + /// a pretty good speedup to be had from handle re-use. So, a simple + /// vector is kept of 'freed' handles to be reused as needed. When + /// that is empty, the first freed handle is kept as a template for + /// handle duplication. This is still faster than creation from nothing. + /// And when that fails, we init fresh from curl_easy_init(). + /// + /// Handles allocated with getHandle() may be freed with either + /// freeHandle() or curl_easy_cleanup(). Choice may be dictated + /// by thread constraints. + /// + /// Threading: Single-threaded. May only be used by a single thread, + /// typically the worker thread. If freeing requests' handles in an + /// unknown threading context, use curl_easy_cleanup() for safety. + + class HandleCache + { + public: + HandleCache(); + ~HandleCache(); + + private: + HandleCache(const HandleCache &); // Not defined + void operator=(const HandleCache &); // Not defined + + public: + /// Allocate a curl handle for caller. May be freed using + /// either the freeHandle() method or calling curl_easy_cleanup() + /// directly. + /// + /// @return Libcurl handle (CURL *) or NULL on allocation + /// problem. + /// + /// Threading: Single-thread (worker) only. + CURL * getHandle(); + + /// Free a libcurl handle acquired by whatever means. Thread + /// safety is left to the caller. + /// + /// Threading: Single-thread (worker) only. + void freeHandle(CURL * handle); + + protected: + typedef std::vector<CURL *> handle_cache_t; + + protected: + CURL * mHandleTemplate; // Template for duplicating new handles + handle_cache_t mCache; // Cache of old handles + }; // end class HandleCache + protected: - HttpService * mService; // Simple reference, not owner - HandleCache mHandleCache; // Handle allocator, owner - active_set_t mActiveOps; - int mPolicyCount; - CURLM ** mMultiHandles; // One handle per policy class - int * mActiveHandles; // Active count per policy class - bool * mDirtyPolicy; // Dirty policy update waiting for stall (per pc) - + HttpService * mService; // Simple reference, not owner + HandleCache mHandleCache; // Handle allocator, owner + active_set_t mActiveOps; + int mPolicyCount; + CURLM ** mMultiHandles; // One handle per policy class + int * mActiveHandles; // Active count per policy class + bool * mDirtyPolicy; // Dirty policy update waiting for stall (per pc) + }; // end class HttpLibcurl } // end namespace LLCore diff --git a/indra/llcorehttp/_httpopcancel.cpp b/indra/llcorehttp/_httpopcancel.cpp index c1912eb3db..3b6cd3caa9 100644 --- a/indra/llcorehttp/_httpopcancel.cpp +++ b/indra/llcorehttp/_httpopcancel.cpp @@ -43,8 +43,8 @@ namespace LLCore HttpOpCancel::HttpOpCancel(HttpHandle handle) - : HttpOperation(), - mHandle(handle) + : HttpOperation(), + mHandle(handle) {} @@ -59,15 +59,15 @@ HttpOpCancel::~HttpOpCancel() // its handler. void HttpOpCancel::stageFromRequest(HttpService * service) { - if (! service->cancel(mHandle)) - { - mStatus = HttpStatus(HttpStatus::LLCORE, HE_HANDLE_NOT_FOUND); - } - - addAsReply(); + if (! service->cancel(mHandle)) + { + mStatus = HttpStatus(HttpStatus::LLCORE, HE_HANDLE_NOT_FOUND); + } + + addAsReply(); } } // end namespace LLCore - + diff --git a/indra/llcorehttp/_httpopcancel.h b/indra/llcorehttp/_httpopcancel.h index 86944eb159..ac71a55f4e 100644 --- a/indra/llcorehttp/_httpopcancel.h +++ b/indra/llcorehttp/_httpopcancel.h @@ -24,11 +24,11 @@ * $/LicenseInfo$ */ -#ifndef _LLCORE_HTTP_OPCANCEL_H_ -#define _LLCORE_HTTP_OPCANCEL_H_ +#ifndef _LLCORE_HTTP_OPCANCEL_H_ +#define _LLCORE_HTTP_OPCANCEL_H_ -#include "linden_common.h" // Modifies curl/curl.h interfaces +#include "linden_common.h" // Modifies curl/curl.h interfaces #include "httpcommon.h" @@ -52,22 +52,22 @@ namespace LLCore class HttpOpCancel : public HttpOperation { public: - /// @param handle Handle of previously-issued request to - /// be canceled. - HttpOpCancel(HttpHandle handle); + /// @param handle Handle of previously-issued request to + /// be canceled. + HttpOpCancel(HttpHandle handle); + + virtual ~HttpOpCancel(); // Use release() - virtual ~HttpOpCancel(); // Use release() - public: - virtual void stageFromRequest(HttpService *); - + virtual void stageFromRequest(HttpService *); + public: - // Request data - HttpHandle mHandle; + // Request data + HttpHandle mHandle; }; // end class HttpOpCancel } // end namespace LLCore -#endif // _LLCORE_HTTP_OPCANCEL_H_ +#endif // _LLCORE_HTTP_OPCANCEL_H_ diff --git a/indra/llcorehttp/_httpoperation.cpp b/indra/llcorehttp/_httpoperation.cpp index c3a9bcaf54..2f6c3fce56 100644 --- a/indra/llcorehttp/_httpoperation.cpp +++ b/indra/llcorehttp/_httpoperation.cpp @@ -53,9 +53,9 @@ namespace LLCore // ================================== // HttpOperation // ================================== -/*static*/ +/*static*/ HttpOperation::handleMap_t HttpOperation::mHandleMap; -LLCoreInt::HttpMutex HttpOperation::mOpMutex; +LLCoreInt::HttpMutex HttpOperation::mOpMutex; HttpOperation::HttpOperation(): std::enable_shared_from_this<HttpOperation>(), @@ -65,7 +65,7 @@ HttpOperation::HttpOperation(): mTracing(HTTP_TRACE_OFF), mMyHandle(LLCORE_HTTP_HANDLE_INVALID) { - mMetricCreated = totalTime(); + mMetricCreated = totalTime(); } @@ -78,63 +78,63 @@ HttpOperation::~HttpOperation() void HttpOperation::setReplyPath(HttpReplyQueue::ptr_t reply_queue, - HttpHandler::ptr_t user_handler) + HttpHandler::ptr_t user_handler) { mReplyQueue.swap(reply_queue); - mUserHandler.swap(user_handler); + mUserHandler.swap(user_handler); } void HttpOperation::stageFromRequest(HttpService *) { - // Default implementation should never be called. This - // indicates an operation making a transition that isn't - // defined. - LL_ERRS(LOG_CORE) << "Default stageFromRequest method may not be called." - << LL_ENDL; + // Default implementation should never be called. This + // indicates an operation making a transition that isn't + // defined. + LL_ERRS(LOG_CORE) << "Default stageFromRequest method may not be called." + << LL_ENDL; } void HttpOperation::stageFromReady(HttpService *) { - // Default implementation should never be called. This - // indicates an operation making a transition that isn't - // defined. - LL_ERRS(LOG_CORE) << "Default stageFromReady method may not be called." - << LL_ENDL; + // Default implementation should never be called. This + // indicates an operation making a transition that isn't + // defined. + LL_ERRS(LOG_CORE) << "Default stageFromReady method may not be called." + << LL_ENDL; } void HttpOperation::stageFromActive(HttpService *) { - // Default implementation should never be called. This - // indicates an operation making a transition that isn't - // defined. - LL_ERRS(LOG_CORE) << "Default stageFromActive method may not be called." - << LL_ENDL; + // Default implementation should never be called. This + // indicates an operation making a transition that isn't + // defined. + LL_ERRS(LOG_CORE) << "Default stageFromActive method may not be called." + << LL_ENDL; } void HttpOperation::visitNotifier(HttpRequest *) { - if (mUserHandler) - { - HttpResponse * response = new HttpResponse(); + if (mUserHandler) + { + HttpResponse * response = new HttpResponse(); - response->setStatus(mStatus); - mUserHandler->onCompleted(getHandle(), response); + response->setStatus(mStatus); + mUserHandler->onCompleted(getHandle(), response); - response->release(); - } + response->release(); + } } HttpStatus HttpOperation::cancel() { - HttpStatus status; + HttpStatus status; - return status; + return status; } // Handle methods @@ -196,25 +196,25 @@ HttpOperation::ptr_t HttpOperation::findByHandle(HttpHandle handle) if (!weak.expired()) return weak.lock(); - + return ptr_t(); } void HttpOperation::addAsReply() { - if (mTracing > HTTP_TRACE_OFF) - { - LL_INFOS(LOG_CORE) << "TRACE, ToReplyQueue, Handle: " - << getHandle() - << LL_ENDL; - } - - if (mReplyQueue) - { + if (mTracing > HTTP_TRACE_OFF) + { + LL_INFOS(LOG_CORE) << "TRACE, ToReplyQueue, Handle: " + << getHandle() + << LL_ENDL; + } + + if (mReplyQueue) + { HttpOperation::ptr_t op = shared_from_this(); - mReplyQueue->addOp(op); - } + mReplyQueue->addOp(op); + } } @@ -224,7 +224,7 @@ void HttpOperation::addAsReply() HttpOpStop::HttpOpStop() - : HttpOperation() + : HttpOperation() {} @@ -234,11 +234,11 @@ HttpOpStop::~HttpOpStop() void HttpOpStop::stageFromRequest(HttpService * service) { - // Do operations - service->stopRequested(); - - // Prepare response if needed - addAsReply(); + // Do operations + service->stopRequested(); + + // Prepare response if needed + addAsReply(); } @@ -248,7 +248,7 @@ void HttpOpStop::stageFromRequest(HttpService * service) HttpOpNull::HttpOpNull() - : HttpOperation() + : HttpOperation() {} @@ -258,13 +258,13 @@ HttpOpNull::~HttpOpNull() void HttpOpNull::stageFromRequest(HttpService * service) { - // Perform op - // Nothing to perform. This doesn't fall into the libcurl - // ready/active queues, it just bounces over to the reply - // queue directly. - - // Prepare response if needed - addAsReply(); + // Perform op + // Nothing to perform. This doesn't fall into the libcurl + // ready/active queues, it just bounces over to the reply + // queue directly. + + // Prepare response if needed + addAsReply(); } @@ -274,8 +274,8 @@ void HttpOpNull::stageFromRequest(HttpService * service) HttpOpSpin::HttpOpSpin(int mode) - : HttpOperation(), - mMode(mode) + : HttpOperation(), + mMode(mode) {} @@ -285,20 +285,20 @@ HttpOpSpin::~HttpOpSpin() void HttpOpSpin::stageFromRequest(HttpService * service) { - if (0 == mMode) - { - // Spin forever - while (true) - { - ms_sleep(100); - } - } - else - { - ms_sleep(1); // backoff interlock plumbing a bit + if (0 == mMode) + { + // Spin forever + while (true) + { + ms_sleep(100); + } + } + else + { + ms_sleep(1); // backoff interlock plumbing a bit HttpOperation::ptr_t opptr = shared_from_this(); service->getRequestQueue().addOp(opptr); - } + } } diff --git a/indra/llcorehttp/_httpoperation.h b/indra/llcorehttp/_httpoperation.h index b07ef76d49..ff7efe60e9 100644 --- a/indra/llcorehttp/_httpoperation.h +++ b/indra/llcorehttp/_httpoperation.h @@ -24,8 +24,8 @@ * $/LicenseInfo$ */ -#ifndef _LLCORE_HTTP_OPERATION_H_ -#define _LLCORE_HTTP_OPERATION_H_ +#ifndef _LLCORE_HTTP_OPERATION_H_ +#define _LLCORE_HTTP_OPERATION_H_ #include "httpcommon.h" @@ -76,82 +76,82 @@ public: typedef std::weak_ptr<HttpOperation> wptr_t; typedef std::shared_ptr<HttpReplyQueue> HttpReplyQueuePtr_t; - /// Threading: called by consumer thread. - HttpOperation(); + /// Threading: called by consumer thread. + HttpOperation(); - /// Threading: called by any thread. - virtual ~HttpOperation(); // Use release() + /// Threading: called by any thread. + virtual ~HttpOperation(); // Use release() public: - /// Register a reply queue and a handler for completion notifications. - /// - /// Invokers of operations that want to receive notification that an - /// operation has been completed do so by binding a reply queue and - /// a handler object to the request. - /// - /// @param reply_queue Pointer to the reply queue where completion - /// notifications are to be queued (typically - /// by addAsReply()). This will typically be - /// the reply queue referenced by the request - /// object. This method will increment the - /// refcount on the queue holding the queue - /// until delivery is complete. Using a reply_queue - /// even if the handler is NULL has some benefits - /// for memory deallocation by keeping it in the - /// originating thread. - /// - /// @param handler Possibly NULL pointer to a non-refcounted - //// handler object to be invoked (onCompleted) - /// when the operation is finished. Note that - /// the handler object is never dereferenced - /// by the worker thread. This is passible data - /// until notification is performed. - /// - /// Threading: called by consumer thread. - /// - 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 - /// request queue to the ready queue via stageFromRequest. Then - /// from the ready queue to the active queue by stageFromReady. And - /// when complete, to the reply queue via stageFromActive and the - /// addAsReply utility. - /// - /// Immediate mode operations (everything else) move from the - /// request queue to the reply queue directly via stageFromRequest - /// and addAsReply with no existence on the ready or active queues. - /// - /// These methods will take out a reference count on the request, - /// caller only needs to dispose of its reference when done with - /// the request. - /// - /// Threading: called by worker thread. - /// - virtual void stageFromRequest(HttpService *); - virtual void stageFromReady(HttpService *); - virtual void stageFromActive(HttpService *); - - /// Delivers a notification to a handler object on completion. - /// - /// Once a request is complete and it has been removed from its - /// reply queue, a handler notification may be delivered by a - /// call to HttpRequest::update(). This method does the necessary - /// dispatching. - /// - /// Threading: called by consumer thread. - /// - virtual void visitNotifier(HttpRequest *); - - /// Cancels the operation whether queued or active. - /// Final status of the request becomes canceled (an error) and - /// that will be delivered to caller via notification scheme. - /// - /// Threading: called by worker thread. - /// - virtual HttpStatus cancel(); + /// Register a reply queue and a handler for completion notifications. + /// + /// Invokers of operations that want to receive notification that an + /// operation has been completed do so by binding a reply queue and + /// a handler object to the request. + /// + /// @param reply_queue Pointer to the reply queue where completion + /// notifications are to be queued (typically + /// by addAsReply()). This will typically be + /// the reply queue referenced by the request + /// object. This method will increment the + /// refcount on the queue holding the queue + /// until delivery is complete. Using a reply_queue + /// even if the handler is NULL has some benefits + /// for memory deallocation by keeping it in the + /// originating thread. + /// + /// @param handler Possibly NULL pointer to a non-refcounted + //// handler object to be invoked (onCompleted) + /// when the operation is finished. Note that + /// the handler object is never dereferenced + /// by the worker thread. This is passible data + /// until notification is performed. + /// + /// Threading: called by consumer thread. + /// + 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 + /// request queue to the ready queue via stageFromRequest. Then + /// from the ready queue to the active queue by stageFromReady. And + /// when complete, to the reply queue via stageFromActive and the + /// addAsReply utility. + /// + /// Immediate mode operations (everything else) move from the + /// request queue to the reply queue directly via stageFromRequest + /// and addAsReply with no existence on the ready or active queues. + /// + /// These methods will take out a reference count on the request, + /// caller only needs to dispose of its reference when done with + /// the request. + /// + /// Threading: called by worker thread. + /// + virtual void stageFromRequest(HttpService *); + virtual void stageFromReady(HttpService *); + virtual void stageFromActive(HttpService *); + + /// Delivers a notification to a handler object on completion. + /// + /// Once a request is complete and it has been removed from its + /// reply queue, a handler notification may be delivered by a + /// call to HttpRequest::update(). This method does the necessary + /// dispatching. + /// + /// Threading: called by consumer thread. + /// + virtual void visitNotifier(HttpRequest *); + + /// Cancels the operation whether queued or active. + /// Final status of the request becomes canceled (an error) and + /// that will be delivered to caller via notification scheme. + /// + /// Threading: called by worker thread. + /// + virtual HttpStatus cancel(); /// Retrieves a unique handle for this operation. HttpHandle getHandle(); @@ -164,30 +164,30 @@ public: return std::shared_ptr< OPT >(); return std::dynamic_pointer_cast< OPT >(ptr); } - + protected: - /// Delivers request to reply queue on completion. After this - /// call, worker thread no longer accesses the object and it - /// is owned by the reply queue. - /// - /// Threading: called by worker thread. - /// - void addAsReply(); - + /// Delivers request to reply queue on completion. After this + /// call, worker thread no longer accesses the object and it + /// is owned by the reply queue. + /// + /// Threading: called by worker thread. + /// + void addAsReply(); + protected: HttpReplyQueuePtr_t mReplyQueue; - HttpHandler::ptr_t mUserHandler; + HttpHandler::ptr_t mUserHandler; public: - // Request Data - HttpRequest::policy_t mReqPolicy; + // Request Data + HttpRequest::policy_t mReqPolicy; - // Reply Data - HttpStatus mStatus; + // Reply Data + HttpStatus mStatus; - // Tracing, debug and metrics - HttpTime mMetricCreated; - int mTracing; + // Tracing, debug and metrics + HttpTime mMetricCreated; + int mTracing; private: typedef std::map<HttpHandle, wptr_t> handleMap_t; @@ -197,7 +197,7 @@ private: HttpHandle mMyHandle; static handleMap_t mHandleMap; - static LLCoreInt::HttpMutex mOpMutex; + static LLCoreInt::HttpMutex mOpMutex; protected: static ptr_t findByHandle(HttpHandle handle); @@ -219,16 +219,16 @@ protected: class HttpOpStop : public HttpOperation { public: - HttpOpStop(); + HttpOpStop(); - virtual ~HttpOpStop(); + virtual ~HttpOpStop(); private: - HttpOpStop(const HttpOpStop &); // Not defined - void operator=(const HttpOpStop &); // Not defined + HttpOpStop(const HttpOpStop &); // Not defined + void operator=(const HttpOpStop &); // Not defined public: - virtual void stageFromRequest(HttpService *); + virtual void stageFromRequest(HttpService *); }; // end class HttpOpStop @@ -241,16 +241,16 @@ public: class HttpOpNull : public HttpOperation { public: - HttpOpNull(); + HttpOpNull(); - virtual ~HttpOpNull(); + virtual ~HttpOpNull(); private: - HttpOpNull(const HttpOpNull &); // Not defined - void operator=(const HttpOpNull &); // Not defined + HttpOpNull(const HttpOpNull &); // Not defined + void operator=(const HttpOpNull &); // Not defined public: - virtual void stageFromRequest(HttpService *); + virtual void stageFromRequest(HttpService *); }; // end class HttpOpNull @@ -261,25 +261,25 @@ public: class HttpOpSpin : public HttpOperation { public: - // 0 does a hard spin in the operation - // 1 does a soft spin continuously requeuing itself - HttpOpSpin(int mode); + // 0 does a hard spin in the operation + // 1 does a soft spin continuously requeuing itself + HttpOpSpin(int mode); - virtual ~HttpOpSpin(); + virtual ~HttpOpSpin(); private: - HttpOpSpin(const HttpOpSpin &); // Not defined - void operator=(const HttpOpSpin &); // Not defined + HttpOpSpin(const HttpOpSpin &); // Not defined + void operator=(const HttpOpSpin &); // Not defined public: - virtual void stageFromRequest(HttpService *); + virtual void stageFromRequest(HttpService *); protected: - int mMode; + int mMode; }; // end class HttpOpSpin } // end namespace LLCore -#endif // _LLCORE_HTTP_OPERATION_H_ +#endif // _LLCORE_HTTP_OPERATION_H_ diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp index 3247146212..5165a6eb62 100644 --- a/indra/llcorehttp/_httpoprequest.cpp +++ b/indra/llcorehttp/_httpoprequest.cpp @@ -69,22 +69,22 @@ namespace // have verified that the header tag is present. The 'buffer' argument // will be processed by strtok_r calls which will modify the buffer. // -// @return -1 if invalid and response should be dropped, 0 if valid an -// correct, 1 if couldn't be parsed. If 0, the first, last, -// and length arguments are also written. 'length' may be -// 0 if the length wasn't available to the server. +// @return -1 if invalid and response should be dropped, 0 if valid an +// correct, 1 if couldn't be parsed. If 0, the first, last, +// and length arguments are also written. 'length' may be +// 0 if the length wasn't available to the server. // int parse_content_range_header(char * buffer, - unsigned int * first, - unsigned int * last, - unsigned int * length); + unsigned int * first, + unsigned int * last, + unsigned int * length); // Similar for Retry-After headers. Only parses the delta form // of the header, HTTP time formats aren't interesting for client // purposes. // -// @return 0 if successfully parsed and seconds time delta -// returned in time argument. +// @return 0 if successfully parsed and seconds time delta +// returned in time argument. // int parse_retry_after_header(char * buffer, int * time); @@ -95,7 +95,7 @@ int parse_retry_after_header(char * buffer, int * time); // non-printing or non-ascii characters are replaced with spaces // otherwise a %XX form of escaping is used. void escape_libcurl_debug_data(char * buffer, size_t len, bool scrub, - std::string & safe_line); + std::string & safe_line); // OS-neutral string comparisons of various types. @@ -127,73 +127,73 @@ namespace LLCore HttpOpRequest::HttpOpRequest() - : HttpOperation(), - mProcFlags(0U), - mReqMethod(HOR_GET), - mReqBody(NULL), - mReqOffset(0), - mReqLength(0), - mReqHeaders(), - mReqOptions(), - mCurlActive(false), - mCurlHandle(NULL), - mCurlService(NULL), - mCurlHeaders(NULL), - mCurlBodyPos(0), - mCurlTemp(NULL), - mCurlTempLen(0), - mReplyBody(NULL), - mReplyOffset(0), - mReplyLength(0), - mReplyFullLength(0), - mReplyHeaders(), - mPolicyRetries(0), - mPolicy503Retries(0), - mPolicyRetryAt(HttpTime(0)), - mPolicyRetryLimit(HTTP_RETRY_COUNT_DEFAULT), - mPolicyMinRetryBackoff(HttpTime(HTTP_RETRY_BACKOFF_MIN_DEFAULT)), - mPolicyMaxRetryBackoff(HttpTime(HTTP_RETRY_BACKOFF_MAX_DEFAULT)), - mCallbackSSLVerify(NULL) + : HttpOperation(), + mProcFlags(0U), + mReqMethod(HOR_GET), + mReqBody(NULL), + mReqOffset(0), + mReqLength(0), + mReqHeaders(), + mReqOptions(), + mCurlActive(false), + mCurlHandle(NULL), + mCurlService(NULL), + mCurlHeaders(NULL), + mCurlBodyPos(0), + mCurlTemp(NULL), + mCurlTempLen(0), + mReplyBody(NULL), + mReplyOffset(0), + mReplyLength(0), + mReplyFullLength(0), + mReplyHeaders(), + mPolicyRetries(0), + mPolicy503Retries(0), + mPolicyRetryAt(HttpTime(0)), + mPolicyRetryLimit(HTTP_RETRY_COUNT_DEFAULT), + mPolicyMinRetryBackoff(HttpTime(HTTP_RETRY_BACKOFF_MIN_DEFAULT)), + mPolicyMaxRetryBackoff(HttpTime(HTTP_RETRY_BACKOFF_MAX_DEFAULT)), + mCallbackSSLVerify(NULL) { - // *NOTE: As members are added, retry initialization/cleanup - // may need to be extended in @see prepareRequest(). + // *NOTE: As members are added, retry initialization/cleanup + // may need to be extended in @see prepareRequest(). } HttpOpRequest::~HttpOpRequest() { - if (mReqBody) - { - mReqBody->release(); - mReqBody = NULL; - } - - if (mCurlHandle) - { - // Uncertain of thread context so free using - // safest method. - curl_easy_cleanup(mCurlHandle); - mCurlHandle = NULL; - } - - mCurlService = NULL; - - if (mCurlHeaders) - { - curl_slist_free_all(mCurlHeaders); - mCurlHeaders = NULL; - } - - delete [] mCurlTemp; - mCurlTemp = NULL; - mCurlTempLen = 0; - - if (mReplyBody) - { - mReplyBody->release(); - mReplyBody = NULL; - } + if (mReqBody) + { + mReqBody->release(); + mReqBody = NULL; + } + + if (mCurlHandle) + { + // Uncertain of thread context so free using + // safest method. + curl_easy_cleanup(mCurlHandle); + mCurlHandle = NULL; + } + + mCurlService = NULL; + + if (mCurlHeaders) + { + curl_slist_free_all(mCurlHeaders); + mCurlHeaders = NULL; + } + + delete [] mCurlTemp; + mCurlTemp = NULL; + mCurlTempLen = 0; + + if (mReplyBody) + { + mReplyBody->release(); + mReplyBody = NULL; + } } @@ -202,7 +202,7 @@ void HttpOpRequest::stageFromRequest(HttpService * service) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; HttpOpRequest::ptr_t self(std::dynamic_pointer_cast<HttpOpRequest>(shared_from_this())); - service->getPolicy().addOp(self); // transfers refcount + service->getPolicy().addOp(self); // transfers refcount } @@ -210,86 +210,86 @@ void HttpOpRequest::stageFromReady(HttpService * service) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; HttpOpRequest::ptr_t self(std::dynamic_pointer_cast<HttpOpRequest>(shared_from_this())); - service->getTransport().addOp(self); // transfers refcount + service->getTransport().addOp(self); // transfers refcount } void HttpOpRequest::stageFromActive(HttpService * service) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - if (mReplyLength) - { - // If non-zero, we received and processed a Content-Range - // header with the response. If there is received data - // (and there may not be due to protocol violations, - // HEAD requests, etc., see BUG-2295) Verify that what it - // says is consistent with the received data. - if (mReplyBody && mReplyBody->size() && mReplyLength != mReplyBody->size()) - { - // Not as expected, fail the request - mStatus = HttpStatus(HttpStatus::LLCORE, HE_INV_CONTENT_RANGE_HDR); - } - } - - if (mCurlHeaders) - { - // We take these headers out of the request now as they were - // allocated originally in this thread and the notifier doesn't - // need them. This eliminates one source of heap moving across - // threads. - - curl_slist_free_all(mCurlHeaders); - mCurlHeaders = NULL; - } - - // Also not needed on the other side - delete [] mCurlTemp; - mCurlTemp = NULL; - mCurlTempLen = 0; - - addAsReply(); + if (mReplyLength) + { + // If non-zero, we received and processed a Content-Range + // header with the response. If there is received data + // (and there may not be due to protocol violations, + // HEAD requests, etc., see BUG-2295) Verify that what it + // says is consistent with the received data. + if (mReplyBody && mReplyBody->size() && mReplyLength != mReplyBody->size()) + { + // Not as expected, fail the request + mStatus = HttpStatus(HttpStatus::LLCORE, HE_INV_CONTENT_RANGE_HDR); + } + } + + if (mCurlHeaders) + { + // We take these headers out of the request now as they were + // allocated originally in this thread and the notifier doesn't + // need them. This eliminates one source of heap moving across + // threads. + + curl_slist_free_all(mCurlHeaders); + mCurlHeaders = NULL; + } + + // Also not needed on the other side + delete [] mCurlTemp; + mCurlTemp = NULL; + mCurlTempLen = 0; + + addAsReply(); } void HttpOpRequest::visitNotifier(HttpRequest * request) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - if (mUserHandler) - { - HttpResponse * response = new HttpResponse(); - response->setStatus(mStatus); - response->setBody(mReplyBody); - response->setHeaders(mReplyHeaders); + if (mUserHandler) + { + HttpResponse * response = new HttpResponse(); + response->setStatus(mStatus); + response->setBody(mReplyBody); + response->setHeaders(mReplyHeaders); response->setRequestURL(mReqURL); response->setRequestMethod(methodToString(mReqMethod)); if (mReplyOffset || mReplyLength) - { - // Got an explicit offset/length in response - response->setRange(mReplyOffset, mReplyLength, mReplyFullLength); - } - response->setContentType(mReplyConType); - response->setRetries(mPolicyRetries, mPolicy503Retries); - - HttpResponse::TransferStats::ptr_t stats = HttpResponse::TransferStats::ptr_t(new HttpResponse::TransferStats); + { + // Got an explicit offset/length in response + response->setRange(mReplyOffset, mReplyLength, mReplyFullLength); + } + response->setContentType(mReplyConType); + response->setRetries(mPolicyRetries, mPolicy503Retries); - 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); + HttpResponse::TransferStats::ptr_t stats = HttpResponse::TransferStats::ptr_t(new HttpResponse::TransferStats); - response->setTransferStats(stats); + 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); - mUserHandler->onCompleted(this->getHandle(), response); + response->setTransferStats(stats); - response->release(); - } + mUserHandler->onCompleted(this->getHandle(), response); + + response->release(); + } } // /*static*/ // HttpOpRequest::ptr_t HttpOpRequest::fromHandle(HttpHandle handle) // { -// +// // return std::dynamic_pointer_cast<HttpOpRequest>((static_cast<HttpOpRequest *>(handle))->shared_from_this()); // } @@ -297,73 +297,73 @@ void HttpOpRequest::visitNotifier(HttpRequest * request) HttpStatus HttpOpRequest::cancel() { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - mStatus = HttpStatus(HttpStatus::LLCORE, HE_OP_CANCELED); + mStatus = HttpStatus(HttpStatus::LLCORE, HE_OP_CANCELED); - addAsReply(); + addAsReply(); - return HttpStatus(); + return HttpStatus(); } HttpStatus HttpOpRequest::setupGet(HttpRequest::policy_t policy_id, - const std::string & url, + const std::string & url, const HttpOptions::ptr_t & options, - const HttpHeaders::ptr_t & headers) + const HttpHeaders::ptr_t & headers) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - setupCommon(policy_id, url, NULL, options, headers); - mReqMethod = HOR_GET; - - return HttpStatus(); + setupCommon(policy_id, url, NULL, options, headers); + mReqMethod = HOR_GET; + + return HttpStatus(); } HttpStatus HttpOpRequest::setupGetByteRange(HttpRequest::policy_t policy_id, - const std::string & url, - size_t offset, - size_t len, + const std::string & url, + size_t offset, + size_t len, const HttpOptions::ptr_t & options, const HttpHeaders::ptr_t & headers) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - setupCommon(policy_id, url, NULL, options, headers); - mReqMethod = HOR_GET; - mReqOffset = offset; - mReqLength = len; - if (offset || len) - { - mProcFlags |= PF_SCAN_RANGE_HEADER; - } - - return HttpStatus(); + setupCommon(policy_id, url, NULL, options, headers); + mReqMethod = HOR_GET; + mReqOffset = offset; + mReqLength = len; + if (offset || len) + { + mProcFlags |= PF_SCAN_RANGE_HEADER; + } + + return HttpStatus(); } HttpStatus HttpOpRequest::setupPost(HttpRequest::policy_t policy_id, - const std::string & url, - BufferArray * body, + const std::string & url, + BufferArray * body, const HttpOptions::ptr_t & options, const HttpHeaders::ptr_t & headers) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - setupCommon(policy_id, url, body, options, headers); - mReqMethod = HOR_POST; - - return HttpStatus(); + setupCommon(policy_id, url, body, options, headers); + mReqMethod = HOR_POST; + + return HttpStatus(); } HttpStatus HttpOpRequest::setupPut(HttpRequest::policy_t policy_id, - const std::string & url, - BufferArray * body, + const std::string & url, + BufferArray * body, const HttpOptions::ptr_t & options, - const HttpHeaders::ptr_t & headers) + const HttpHeaders::ptr_t & headers) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - setupCommon(policy_id, url, body, options, headers); - mReqMethod = HOR_PUT; - - return HttpStatus(); + setupCommon(policy_id, url, body, options, headers); + mReqMethod = HOR_PUT; + + return HttpStatus(); } @@ -421,42 +421,42 @@ HttpStatus HttpOpRequest::setupMove(HttpRequest::policy_t policy_id, void HttpOpRequest::setupCommon(HttpRequest::policy_t policy_id, - const std::string & url, - BufferArray * body, + const std::string & url, + BufferArray * body, const HttpOptions::ptr_t & options, - const HttpHeaders::ptr_t & headers) + const HttpHeaders::ptr_t & headers) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - mProcFlags = 0U; - mReqPolicy = policy_id; - mReqURL = url; - if (body) - { - body->addRef(); - mReqBody = body; - } - if (headers && ! mReqHeaders) - { - mReqHeaders = headers; - } - if (options && !mReqOptions) - { - mReqOptions = options; - if (options->getWantHeaders()) - { - mProcFlags |= PF_SAVE_HEADERS; - } - if (options->getUseRetryAfter()) - { - mProcFlags |= PF_USE_RETRY_AFTER; - } - mPolicyRetryLimit = options->getRetries(); - mPolicyRetryLimit = llclamp(mPolicyRetryLimit, HTTP_RETRY_COUNT_MIN, HTTP_RETRY_COUNT_MAX); - mTracing = (std::max)(mTracing, llclamp(options->getTrace(), HTTP_TRACE_MIN, HTTP_TRACE_MAX)); - - mPolicyMinRetryBackoff = llclamp(options->getMinBackoff(), HttpTime(0), HTTP_RETRY_BACKOFF_MAX); - mPolicyMaxRetryBackoff = llclamp(options->getMaxBackoff(), mPolicyMinRetryBackoff, HTTP_RETRY_BACKOFF_MAX); - } + mProcFlags = 0U; + mReqPolicy = policy_id; + mReqURL = url; + if (body) + { + body->addRef(); + mReqBody = body; + } + if (headers && ! mReqHeaders) + { + mReqHeaders = headers; + } + if (options && !mReqOptions) + { + mReqOptions = options; + if (options->getWantHeaders()) + { + mProcFlags |= PF_SAVE_HEADERS; + } + if (options->getUseRetryAfter()) + { + mProcFlags |= PF_USE_RETRY_AFTER; + } + mPolicyRetryLimit = options->getRetries(); + mPolicyRetryLimit = llclamp(mPolicyRetryLimit, HTTP_RETRY_COUNT_MIN, HTTP_RETRY_COUNT_MAX); + mTracing = (std::max)(mTracing, llclamp(options->getTrace(), HTTP_TRACE_MIN, HTTP_TRACE_MAX)); + + mPolicyMinRetryBackoff = llclamp(options->getMinBackoff(), HttpTime(0), HTTP_RETRY_BACKOFF_MAX); + mPolicyMaxRetryBackoff = llclamp(options->getMaxBackoff(), mPolicyMinRetryBackoff, HTTP_RETRY_BACKOFF_MAX); + } } // Sets all libcurl options and data for a request. @@ -470,167 +470,167 @@ void HttpOpRequest::setupCommon(HttpRequest::policy_t policy_id, HttpStatus HttpOpRequest::prepareRequest(HttpService * service) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - // Scrub transport and result data for retried op case - mCurlActive = false; - mCurlHandle = NULL; - mCurlService = NULL; - if (mCurlHeaders) - { - curl_slist_free_all(mCurlHeaders); - mCurlHeaders = NULL; - } - mCurlBodyPos = 0; - - if (mReplyBody) - { - mReplyBody->release(); - mReplyBody = NULL; - } - mReplyOffset = 0; - mReplyLength = 0; - mReplyFullLength = 0; + // Scrub transport and result data for retried op case + mCurlActive = false; + mCurlHandle = NULL; + mCurlService = NULL; + if (mCurlHeaders) + { + curl_slist_free_all(mCurlHeaders); + mCurlHeaders = NULL; + } + mCurlBodyPos = 0; + + if (mReplyBody) + { + mReplyBody->release(); + mReplyBody = NULL; + } + mReplyOffset = 0; + mReplyLength = 0; + mReplyFullLength = 0; mReplyHeaders.reset(); - mReplyConType.clear(); - - // *FIXME: better error handling later - HttpStatus status; - - // Get global and class policy options - HttpPolicyGlobal & gpolicy(service->getPolicy().getGlobalOptions()); - HttpPolicyClass & cpolicy(service->getPolicy().getClassOptions(mReqPolicy)); - - mCurlHandle = service->getTransport().getHandle(); - if (! mCurlHandle) - { - // We're in trouble. We'll continue but it won't go well. - LL_WARNS(LOG_CORE) << "Failed to allocate libcurl easy handle. Continuing." - << LL_ENDL; - return HttpStatus(HttpStatus::LLCORE, HE_BAD_ALLOC); - } - - check_curl_easy_setopt(mCurlHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); - check_curl_easy_setopt(mCurlHandle, CURLOPT_NOSIGNAL, 1); - check_curl_easy_setopt(mCurlHandle, CURLOPT_NOPROGRESS, 1); - check_curl_easy_setopt(mCurlHandle, CURLOPT_URL, mReqURL.c_str()); - check_curl_easy_setopt(mCurlHandle, CURLOPT_PRIVATE, getHandle()); - check_curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, ""); - - check_curl_easy_setopt(mCurlHandle, CURLOPT_AUTOREFERER, 1); - check_curl_easy_setopt(mCurlHandle, CURLOPT_MAXREDIRS, HTTP_REDIRECTS_DEFAULT); - check_curl_easy_setopt(mCurlHandle, CURLOPT_WRITEFUNCTION, writeCallback); + mReplyConType.clear(); + + // *FIXME: better error handling later + HttpStatus status; + + // Get global and class policy options + HttpPolicyGlobal & gpolicy(service->getPolicy().getGlobalOptions()); + HttpPolicyClass & cpolicy(service->getPolicy().getClassOptions(mReqPolicy)); + + mCurlHandle = service->getTransport().getHandle(); + if (! mCurlHandle) + { + // We're in trouble. We'll continue but it won't go well. + LL_WARNS(LOG_CORE) << "Failed to allocate libcurl easy handle. Continuing." + << LL_ENDL; + return HttpStatus(HttpStatus::LLCORE, HE_BAD_ALLOC); + } + + check_curl_easy_setopt(mCurlHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); + check_curl_easy_setopt(mCurlHandle, CURLOPT_NOSIGNAL, 1); + check_curl_easy_setopt(mCurlHandle, CURLOPT_NOPROGRESS, 1); + check_curl_easy_setopt(mCurlHandle, CURLOPT_URL, mReqURL.c_str()); + check_curl_easy_setopt(mCurlHandle, CURLOPT_PRIVATE, getHandle()); + check_curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, ""); + + check_curl_easy_setopt(mCurlHandle, CURLOPT_AUTOREFERER, 1); + check_curl_easy_setopt(mCurlHandle, CURLOPT_MAXREDIRS, HTTP_REDIRECTS_DEFAULT); + check_curl_easy_setopt(mCurlHandle, CURLOPT_WRITEFUNCTION, writeCallback); check_curl_easy_setopt(mCurlHandle, CURLOPT_WRITEDATA, getHandle()); - check_curl_easy_setopt(mCurlHandle, CURLOPT_READFUNCTION, readCallback); + check_curl_easy_setopt(mCurlHandle, CURLOPT_READFUNCTION, readCallback); check_curl_easy_setopt(mCurlHandle, CURLOPT_READDATA, getHandle()); check_curl_easy_setopt(mCurlHandle, CURLOPT_SEEKFUNCTION, seekCallback); check_curl_easy_setopt(mCurlHandle, CURLOPT_SEEKDATA, getHandle()); - check_curl_easy_setopt(mCurlHandle, CURLOPT_COOKIEFILE, ""); + check_curl_easy_setopt(mCurlHandle, CURLOPT_COOKIEFILE, ""); - if (gpolicy.mSslCtxCallback) - { - check_curl_easy_setopt(mCurlHandle, CURLOPT_SSL_CTX_FUNCTION, curlSslCtxCallback); + if (gpolicy.mSslCtxCallback) + { + check_curl_easy_setopt(mCurlHandle, CURLOPT_SSL_CTX_FUNCTION, curlSslCtxCallback); check_curl_easy_setopt(mCurlHandle, CURLOPT_SSL_CTX_DATA, getHandle()); - mCallbackSSLVerify = gpolicy.mSslCtxCallback; - } + mCallbackSSLVerify = gpolicy.mSslCtxCallback; + } - long follow_redirect(1L); - long sslPeerV(0L); - long sslHostV(0L); + 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(); + 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; - } - check_curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, follow_redirect); + } + check_curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, follow_redirect); - check_curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYPEER, sslPeerV); - check_curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYHOST, sslHostV); + check_curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYPEER, sslPeerV); + check_curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYHOST, sslHostV); check_curl_easy_setopt(mCurlHandle, CURLOPT_NOBODY, 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. - // - // -1 stores forever - // 0 never stores - // any other positive number specifies seconds - // supposedly curl 7.62.0 can use TTL by default, otherwise default is 60 seconds - check_curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, dnsCacheTimeout); - - if (gpolicy.mUseLLProxy) - { - // Use the viewer-based thread-safe API which has a - // fast/safe check for proxy enable. Would like to - // encapsulate this someway... - // Make sure proxy won't be getInstance() from here, - // it is not thread safe - LLProxy::applyProxySettings(mCurlHandle); - - } - else if (gpolicy.mHttpProxy.size()) - { - // *TODO: This is fine for now but get fuller socks5/ - // authentication thing going later.... - check_curl_easy_setopt(mCurlHandle, CURLOPT_PROXY, gpolicy.mHttpProxy.c_str()); - check_curl_easy_setopt(mCurlHandle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); - } - if (gpolicy.mCAPath.size()) - { - check_curl_easy_setopt(mCurlHandle, CURLOPT_CAPATH, gpolicy.mCAPath.c_str()); - } - if (gpolicy.mCAFile.size()) - { - check_curl_easy_setopt(mCurlHandle, CURLOPT_CAINFO, gpolicy.mCAFile.c_str()); - } - - switch (mReqMethod) - { - case HOR_GET: + // 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. + // + // -1 stores forever + // 0 never stores + // any other positive number specifies seconds + // supposedly curl 7.62.0 can use TTL by default, otherwise default is 60 seconds + check_curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, dnsCacheTimeout); + + if (gpolicy.mUseLLProxy) + { + // Use the viewer-based thread-safe API which has a + // fast/safe check for proxy enable. Would like to + // encapsulate this someway... + // Make sure proxy won't be getInstance() from here, + // it is not thread safe + LLProxy::applyProxySettings(mCurlHandle); + + } + else if (gpolicy.mHttpProxy.size()) + { + // *TODO: This is fine for now but get fuller socks5/ + // authentication thing going later.... + check_curl_easy_setopt(mCurlHandle, CURLOPT_PROXY, gpolicy.mHttpProxy.c_str()); + check_curl_easy_setopt(mCurlHandle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); + } + if (gpolicy.mCAPath.size()) + { + check_curl_easy_setopt(mCurlHandle, CURLOPT_CAPATH, gpolicy.mCAPath.c_str()); + } + if (gpolicy.mCAFile.size()) + { + check_curl_easy_setopt(mCurlHandle, CURLOPT_CAINFO, gpolicy.mCAFile.c_str()); + } + + switch (mReqMethod) + { + case HOR_GET: if (nobody == 0) check_curl_easy_setopt(mCurlHandle, CURLOPT_HTTPGET, 1); - break; - - case HOR_POST: - { - check_curl_easy_setopt(mCurlHandle, CURLOPT_POST, 1); - check_curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, ""); - long data_size(0); - if (mReqBody) - { - data_size = mReqBody->size(); - } - check_curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDS, static_cast<void *>(NULL)); - check_curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDSIZE, data_size); - mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:"); - } - break; - + break; + + case HOR_POST: + { + check_curl_easy_setopt(mCurlHandle, CURLOPT_POST, 1); + check_curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, ""); + long data_size(0); + if (mReqBody) + { + data_size = mReqBody->size(); + } + check_curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDS, static_cast<void *>(NULL)); + check_curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDSIZE, data_size); + mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:"); + } + break; + case HOR_PATCH: check_curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "PATCH"); // fall through. The rest is the same as PUT case HOR_PUT: - { - check_curl_easy_setopt(mCurlHandle, CURLOPT_UPLOAD, 1); - long data_size(0); - if (mReqBody) - { - data_size = mReqBody->size(); - } - check_curl_easy_setopt(mCurlHandle, CURLOPT_INFILESIZE, data_size); - mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:"); - } - break; - + { + check_curl_easy_setopt(mCurlHandle, CURLOPT_UPLOAD, 1); + long data_size(0); + if (mReqBody) + { + data_size = mReqBody->size(); + } + check_curl_easy_setopt(mCurlHandle, CURLOPT_INFILESIZE, data_size); + mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:"); + } + break; + case HOR_DELETE: check_curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "DELETE"); break; @@ -643,136 +643,136 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service) check_curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "MOVE"); break; - default: - LL_ERRS(LOG_CORE) << "Invalid HTTP method in request: " - << int(mReqMethod) << ". Can't recover." - << LL_ENDL; - break; - } + default: + LL_ERRS(LOG_CORE) << "Invalid HTTP method in request: " + << int(mReqMethod) << ". Can't recover." + << LL_ENDL; + 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) - { - check_curl_easy_setopt(mCurlHandle, CURLOPT_VERBOSE, 1); - check_curl_easy_setopt(mCurlHandle, CURLOPT_DEBUGDATA, this); - check_curl_easy_setopt(mCurlHandle, CURLOPT_DEBUGFUNCTION, debugCallback); - } - - // There's a CURLOPT for this now... - if ((mReqOffset || mReqLength) && HOR_GET == mReqMethod) - { - static const char * const fmt1("Range: bytes=%lu-%lu"); - static const char * const fmt2("Range: bytes=%lu-"); - - char range_line[64]; + // Tracing + if (mTracing >= HTTP_TRACE_CURL_HEADERS) + { + check_curl_easy_setopt(mCurlHandle, CURLOPT_VERBOSE, 1); + check_curl_easy_setopt(mCurlHandle, CURLOPT_DEBUGDATA, this); + check_curl_easy_setopt(mCurlHandle, CURLOPT_DEBUGFUNCTION, debugCallback); + } + + // There's a CURLOPT for this now... + if ((mReqOffset || mReqLength) && HOR_GET == mReqMethod) + { + static const char * const fmt1("Range: bytes=%lu-%lu"); + static const char * const fmt2("Range: bytes=%lu-"); + + char range_line[64]; #if LL_WINDOWS - _snprintf_s(range_line, sizeof(range_line), sizeof(range_line) - 1, - (mReqLength ? fmt1 : fmt2), - (unsigned long) mReqOffset, (unsigned long) (mReqOffset + mReqLength - 1)); + _snprintf_s(range_line, sizeof(range_line), sizeof(range_line) - 1, + (mReqLength ? fmt1 : fmt2), + (unsigned long) mReqOffset, (unsigned long) (mReqOffset + mReqLength - 1)); #else - if ( mReqLength ) - { - snprintf(range_line, sizeof(range_line), - fmt1, - (unsigned long) mReqOffset, (unsigned long) (mReqOffset + mReqLength - 1)); - } - else - { - snprintf(range_line, sizeof(range_line), - fmt2, - (unsigned long) mReqOffset); - } + if ( mReqLength ) + { + snprintf(range_line, sizeof(range_line), + fmt1, + (unsigned long) mReqOffset, (unsigned long) (mReqOffset + mReqLength - 1)); + } + else + { + snprintf(range_line, sizeof(range_line), + fmt2, + (unsigned long) mReqOffset); + } #endif // LL_WINDOWS - range_line[sizeof(range_line) - 1] = '\0'; - mCurlHeaders = curl_slist_append(mCurlHeaders, range_line); - } - - mCurlHeaders = curl_slist_append(mCurlHeaders, "Pragma:"); - - // Request options - long timeout(HTTP_REQUEST_TIMEOUT_DEFAULT); - long xfer_timeout(HTTP_REQUEST_XFER_TIMEOUT_DEFAULT); - if (mReqOptions) - { - timeout = mReqOptions->getTimeout(); - timeout = llclamp(timeout, HTTP_REQUEST_TIMEOUT_MIN, HTTP_REQUEST_TIMEOUT_MAX); - xfer_timeout = mReqOptions->getTransferTimeout(); - xfer_timeout = llclamp(xfer_timeout, HTTP_REQUEST_TIMEOUT_MIN, HTTP_REQUEST_TIMEOUT_MAX); - } - if (xfer_timeout == 0L) - { - xfer_timeout = timeout; - } - if (cpolicy.mPipelining > 1L) - { - // Pipelining affects both connection and transfer timeout values. - // Requests that are added to a pipeling immediately have completed - // their connection so the connection delay tends to be less than - // the non-pipelined value. Transfers are the opposite. Transfer - // timeout starts once the connection is established and completion - // can be delayed due to the pipelined requests ahead. So, it's - // a handwave but bump the transfer timeout up by the pipelining - // depth to give some room. - // - // BUG-7698, BUG-7688, BUG-7694 (others). Scylla and Charybdis - // situation. Operating against a CDN having service issues may - // lead to requests stalling for an arbitrarily long time with only - // the CURLOPT_TIMEOUT value leading to a closed connection. Sadly - // for pipelining, libcurl (7.39.0 and earlier, at minimum) starts - // the clock on this value as soon as a request is started down - // the wire. We want a short value to recover and retry from the - // CDN. We need a long value to safely deal with a succession of - // piled-up pipelined requests. - // - // *TODO: Find a better scheme than timeouts to guarantee liveness. - // Progress on the connection is what we really want, not timeouts. - // But we don't have access to that and the request progress indicators - // (various libcurl callbacks) have the same problem TIMEOUT does. - // - // xfer_timeout *= cpolicy.mPipelining; - xfer_timeout *= 2L; - - // Also try requesting HTTP/2. + range_line[sizeof(range_line) - 1] = '\0'; + mCurlHeaders = curl_slist_append(mCurlHeaders, range_line); + } + + mCurlHeaders = curl_slist_append(mCurlHeaders, "Pragma:"); + + // Request options + long timeout(HTTP_REQUEST_TIMEOUT_DEFAULT); + long xfer_timeout(HTTP_REQUEST_XFER_TIMEOUT_DEFAULT); + if (mReqOptions) + { + timeout = mReqOptions->getTimeout(); + timeout = llclamp(timeout, HTTP_REQUEST_TIMEOUT_MIN, HTTP_REQUEST_TIMEOUT_MAX); + xfer_timeout = mReqOptions->getTransferTimeout(); + xfer_timeout = llclamp(xfer_timeout, HTTP_REQUEST_TIMEOUT_MIN, HTTP_REQUEST_TIMEOUT_MAX); + } + if (xfer_timeout == 0L) + { + xfer_timeout = timeout; + } + if (cpolicy.mPipelining > 1L) + { + // Pipelining affects both connection and transfer timeout values. + // Requests that are added to a pipeling immediately have completed + // their connection so the connection delay tends to be less than + // the non-pipelined value. Transfers are the opposite. Transfer + // timeout starts once the connection is established and completion + // can be delayed due to the pipelined requests ahead. So, it's + // a handwave but bump the transfer timeout up by the pipelining + // depth to give some room. + // + // BUG-7698, BUG-7688, BUG-7694 (others). Scylla and Charybdis + // situation. Operating against a CDN having service issues may + // lead to requests stalling for an arbitrarily long time with only + // the CURLOPT_TIMEOUT value leading to a closed connection. Sadly + // for pipelining, libcurl (7.39.0 and earlier, at minimum) starts + // the clock on this value as soon as a request is started down + // the wire. We want a short value to recover and retry from the + // CDN. We need a long value to safely deal with a succession of + // piled-up pipelined requests. + // + // *TODO: Find a better scheme than timeouts to guarantee liveness. + // Progress on the connection is what we really want, not timeouts. + // But we don't have access to that and the request progress indicators + // (various libcurl callbacks) have the same problem TIMEOUT does. + // + // xfer_timeout *= cpolicy.mPipelining; + xfer_timeout *= 2L; + + // Also try requesting HTTP/2. /******************************/ - // but for test purposes, only if overriding VIEWERASSET - if (getenv("VIEWERASSET")) + // but for test purposes, only if overriding VIEWERASSET + if (getenv("VIEWERASSET")) /******************************/ - check_curl_easy_setopt(mCurlHandle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); - } - // *DEBUG: Enable following override for timeout handling and "[curl:bugs] #1420" tests + check_curl_easy_setopt(mCurlHandle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); + } + // *DEBUG: Enable following override for timeout handling and "[curl:bugs] #1420" tests //if (cpolicy.mPipelining) //{ // xfer_timeout = 1L; // timeout = 1L; //} - check_curl_easy_setopt(mCurlHandle, CURLOPT_TIMEOUT, xfer_timeout); - check_curl_easy_setopt(mCurlHandle, CURLOPT_CONNECTTIMEOUT, timeout); - - // Request headers - if (mReqHeaders) - { - // Caller's headers last to override - mCurlHeaders = append_headers_to_slist(mReqHeaders, mCurlHeaders); - } - check_curl_easy_setopt(mCurlHandle, CURLOPT_HTTPHEADER, mCurlHeaders); - - if (mProcFlags & (PF_SCAN_RANGE_HEADER | PF_SAVE_HEADERS | PF_USE_RETRY_AFTER)) - { - check_curl_easy_setopt(mCurlHandle, CURLOPT_HEADERFUNCTION, headerCallback); - check_curl_easy_setopt(mCurlHandle, CURLOPT_HEADERDATA, this); - } - - if (status) - { - mCurlService = service; - } - return status; + check_curl_easy_setopt(mCurlHandle, CURLOPT_TIMEOUT, xfer_timeout); + check_curl_easy_setopt(mCurlHandle, CURLOPT_CONNECTTIMEOUT, timeout); + + // Request headers + if (mReqHeaders) + { + // Caller's headers last to override + mCurlHeaders = append_headers_to_slist(mReqHeaders, mCurlHeaders); + } + check_curl_easy_setopt(mCurlHandle, CURLOPT_HTTPHEADER, mCurlHeaders); + + if (mProcFlags & (PF_SCAN_RANGE_HEADER | PF_SAVE_HEADERS | PF_USE_RETRY_AFTER)) + { + check_curl_easy_setopt(mCurlHandle, CURLOPT_HEADERFUNCTION, headerCallback); + check_curl_easy_setopt(mCurlHandle, CURLOPT_HEADERDATA, this); + } + + if (status) + { + mCurlService = service; + } + return status; } @@ -781,46 +781,46 @@ size_t HttpOpRequest::writeCallback(void * data, size_t size, size_t nmemb, void LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata)); - if (! op->mReplyBody) - { - op->mReplyBody = new BufferArray(); - } - const size_t req_size(size * nmemb); - const size_t write_size(op->mReplyBody->append(static_cast<char *>(data), req_size)); + if (! op->mReplyBody) + { + op->mReplyBody = new BufferArray(); + } + const size_t req_size(size * nmemb); + const size_t write_size(op->mReplyBody->append(static_cast<char *>(data), req_size)); HTTPStats::instance().recordDataDown(write_size); - return write_size; + return write_size; } - + size_t HttpOpRequest::readCallback(void * data, size_t size, size_t nmemb, void * userdata) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata)); - if (! op->mReqBody) - { - return 0; - } - const size_t req_size(size * nmemb); - const size_t body_size(op->mReqBody->size()); - if (body_size <= op->mCurlBodyPos) - { - if (body_size < op->mCurlBodyPos) - { - // Warn but continue if the read position moves beyond end-of-body - // for some reason. - LL_WARNS(LOG_CORE) << "Request body position beyond body size. Truncating request body." - << LL_ENDL; - } - return 0; - } - - const size_t do_size((std::min)(req_size, body_size - op->mCurlBodyPos)); - const size_t read_size(op->mReqBody->read(op->mCurlBodyPos, static_cast<char *>(data), do_size)); + if (! op->mReqBody) + { + return 0; + } + const size_t req_size(size * nmemb); + const size_t body_size(op->mReqBody->size()); + if (body_size <= op->mCurlBodyPos) + { + if (body_size < op->mCurlBodyPos) + { + // Warn but continue if the read position moves beyond end-of-body + // for some reason. + LL_WARNS(LOG_CORE) << "Request body position beyond body size. Truncating request body." + << LL_ENDL; + } + return 0; + } + + const size_t do_size((std::min)(req_size, body_size - op->mCurlBodyPos)); + const size_t read_size(op->mReqBody->read(op->mCurlBodyPos, static_cast<char *>(data), do_size)); // FIXME: singleton's instance() is Thread unsafe! Even if stats accumulators inside are. HTTPStats::instance().recordDataUp(read_size); op->mCurlBodyPos += read_size; - return read_size; + return read_size; } @@ -855,154 +855,154 @@ int HttpOpRequest::seekCallback(void *userdata, curl_off_t offset, int origin) return 0; } - + size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, void * userdata) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - static const char status_line[] = "HTTP/"; - static const size_t status_line_len = sizeof(status_line) - 1; - static const char con_ran_line[] = "content-range"; - static const char con_retry_line[] = "retry-after"; - + static const char status_line[] = "HTTP/"; + static const size_t status_line_len = sizeof(status_line) - 1; + static const char con_ran_line[] = "content-range"; + static const char con_retry_line[] = "retry-after"; + 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 - bool is_header(true); - - if (hdr_size >= status_line_len && ! strncmp(status_line, hdr_data, status_line_len)) - { - // One of possibly several status lines. Reset what we know and start over - // taking results from the last header stanza we receive. - op->mReplyOffset = 0; - op->mReplyLength = 0; - op->mReplyFullLength = 0; - op->mReplyRetryAfter = 0; - op->mStatus = HttpStatus(); - if (op->mReplyHeaders) - { - op->mReplyHeaders->clear(); - } - is_header = false; - } - - // Nothing in here wants a final CR/LF combination. Remove - // it as much as possible. - size_t wanted_hdr_size(hdr_size); - if (wanted_hdr_size && '\n' == hdr_data[wanted_hdr_size - 1]) - { - if (--wanted_hdr_size && '\r' == hdr_data[wanted_hdr_size - 1]) - { - --wanted_hdr_size; - } - } - - // Copy and normalize header fragments for the following - // stages. Would like to modify the data in-place but that - // may not be allowed and we need one byte extra for NUL. - // At the end of this we will have: - // - // If ':' present in header: - // 1. name points to text to left of colon which - // will be ascii lower-cased and left and right - // trimmed of whitespace. - // 2. value points to text to right of colon which - // will be left trimmed of whitespace. - // Otherwise: - // 1. name points to header which will be left - // trimmed of whitespace. - // 2. value is NULL - // Any non-NULL pointer may point to a zero-length string. - // - if (wanted_hdr_size >= op->mCurlTempLen) - { - delete [] op->mCurlTemp; - op->mCurlTempLen = 2 * wanted_hdr_size + 1; - op->mCurlTemp = new char [op->mCurlTempLen]; - } - memcpy(op->mCurlTemp, hdr_data, wanted_hdr_size); - op->mCurlTemp[wanted_hdr_size] = '\0'; - char * name(op->mCurlTemp); - char * value(strchr(name, ':')); - if (value) - { - *value++ = '\0'; - os_strlower(name); - name = os_strtrim(name); - value = os_strltrim(value); - } - else - { - // Doesn't look well-formed, do minimal normalization on it - name = os_strltrim(name); - } - - // Normalized, now reject headers with empty names. - if (! *name) - { - // No use continuing - return hdr_size; - } - - // Save header if caller wants them in the response - if (is_header && op->mProcFlags & PF_SAVE_HEADERS) - { - // Save headers in response - if (! op->mReplyHeaders) - { - op->mReplyHeaders = HttpHeaders::ptr_t(new HttpHeaders); - } - op->mReplyHeaders->append(name, value ? value : ""); - } - - // From this point, header-specific processors are free to - // modify the header value. - - // Detect and parse 'Content-Range' headers - if (is_header - && op->mProcFlags & PF_SCAN_RANGE_HEADER - && value && *value - && ! strcmp(name, con_ran_line)) - { - unsigned int first(0), last(0), length(0); - int status; - - if (! (status = parse_content_range_header(value, &first, &last, &length))) - { - // Success, record the fragment position - op->mReplyOffset = first; - op->mReplyLength = last - first + 1; - op->mReplyFullLength = length; - } - else if (-1 == status) - { - // Response is badly formed and shouldn't be accepted - op->mStatus = HttpStatus(HttpStatus::LLCORE, HE_INV_CONTENT_RANGE_HDR); - } - else - { - // Ignore the unparsable. - LL_INFOS_ONCE(LOG_CORE) << "Problem parsing odd Content-Range header: '" - << std::string(hdr_data, wanted_hdr_size) - << "'. Ignoring." - << LL_ENDL; - } - } - - // Detect and parse 'Retry-After' headers - if (is_header - && op->mProcFlags & PF_USE_RETRY_AFTER - && value && *value - && ! strcmp(name, con_retry_line)) - { - int time(0); - if (! parse_retry_after_header(value, &time)) - { - op->mReplyRetryAfter = time; - } - } - - return hdr_size; + const size_t hdr_size(size * nmemb); + const char * hdr_data(static_cast<const char *>(data)); // Not null terminated + bool is_header(true); + + if (hdr_size >= status_line_len && ! strncmp(status_line, hdr_data, status_line_len)) + { + // One of possibly several status lines. Reset what we know and start over + // taking results from the last header stanza we receive. + op->mReplyOffset = 0; + op->mReplyLength = 0; + op->mReplyFullLength = 0; + op->mReplyRetryAfter = 0; + op->mStatus = HttpStatus(); + if (op->mReplyHeaders) + { + op->mReplyHeaders->clear(); + } + is_header = false; + } + + // Nothing in here wants a final CR/LF combination. Remove + // it as much as possible. + size_t wanted_hdr_size(hdr_size); + if (wanted_hdr_size && '\n' == hdr_data[wanted_hdr_size - 1]) + { + if (--wanted_hdr_size && '\r' == hdr_data[wanted_hdr_size - 1]) + { + --wanted_hdr_size; + } + } + + // Copy and normalize header fragments for the following + // stages. Would like to modify the data in-place but that + // may not be allowed and we need one byte extra for NUL. + // At the end of this we will have: + // + // If ':' present in header: + // 1. name points to text to left of colon which + // will be ascii lower-cased and left and right + // trimmed of whitespace. + // 2. value points to text to right of colon which + // will be left trimmed of whitespace. + // Otherwise: + // 1. name points to header which will be left + // trimmed of whitespace. + // 2. value is NULL + // Any non-NULL pointer may point to a zero-length string. + // + if (wanted_hdr_size >= op->mCurlTempLen) + { + delete [] op->mCurlTemp; + op->mCurlTempLen = 2 * wanted_hdr_size + 1; + op->mCurlTemp = new char [op->mCurlTempLen]; + } + memcpy(op->mCurlTemp, hdr_data, wanted_hdr_size); + op->mCurlTemp[wanted_hdr_size] = '\0'; + char * name(op->mCurlTemp); + char * value(strchr(name, ':')); + if (value) + { + *value++ = '\0'; + os_strlower(name); + name = os_strtrim(name); + value = os_strltrim(value); + } + else + { + // Doesn't look well-formed, do minimal normalization on it + name = os_strltrim(name); + } + + // Normalized, now reject headers with empty names. + if (! *name) + { + // No use continuing + return hdr_size; + } + + // Save header if caller wants them in the response + if (is_header && op->mProcFlags & PF_SAVE_HEADERS) + { + // Save headers in response + if (! op->mReplyHeaders) + { + op->mReplyHeaders = HttpHeaders::ptr_t(new HttpHeaders); + } + op->mReplyHeaders->append(name, value ? value : ""); + } + + // From this point, header-specific processors are free to + // modify the header value. + + // Detect and parse 'Content-Range' headers + if (is_header + && op->mProcFlags & PF_SCAN_RANGE_HEADER + && value && *value + && ! strcmp(name, con_ran_line)) + { + unsigned int first(0), last(0), length(0); + int status; + + if (! (status = parse_content_range_header(value, &first, &last, &length))) + { + // Success, record the fragment position + op->mReplyOffset = first; + op->mReplyLength = last - first + 1; + op->mReplyFullLength = length; + } + else if (-1 == status) + { + // Response is badly formed and shouldn't be accepted + op->mStatus = HttpStatus(HttpStatus::LLCORE, HE_INV_CONTENT_RANGE_HDR); + } + else + { + // Ignore the unparsable. + LL_INFOS_ONCE(LOG_CORE) << "Problem parsing odd Content-Range header: '" + << std::string(hdr_data, wanted_hdr_size) + << "'. Ignoring." + << LL_ENDL; + } + } + + // Detect and parse 'Retry-After' headers + if (is_header + && op->mProcFlags & PF_USE_RETRY_AFTER + && value && *value + && ! strcmp(name, con_retry_line)) + { + int time(0); + if (! parse_retry_after_header(value, &time)) + { + op->mReplyRetryAfter = time; + } + } + + return hdr_size; } @@ -1025,12 +1025,12 @@ CURLcode HttpOpRequest::curlSslCtxCallback(CURL *curl, void *sslctx, void *userd // Ex: setting urls (assume non-SL) for parcel media in LLFloaterURLEntry 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 - } + // set the verification callback. + SSL_CTX_set_cert_verify_callback(ctx, sslCertVerifyCallback, userdata); + // the calls are void + } - return CURLE_OK; + return CURLE_OK; } int HttpOpRequest::sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param) @@ -1038,12 +1038,12 @@ int HttpOpRequest::sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param) LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(param)); - if (op->mCallbackSSLVerify) - { - op->mStatus = op->mCallbackSSLVerify(op->mReqURL, op->mUserHandler, ctx); - } + if (op->mCallbackSSLVerify) + { + op->mStatus = op->mCallbackSSLVerify(op->mReqURL, op->mUserHandler, ctx); + } - return (op->mStatus) ? 1 : 0; + return (op->mStatus) ? 1 : 0; } int HttpOpRequest::debugCallback(CURL * handle, curl_infotype info, char * buffer, size_t len, void * userdata) @@ -1051,91 +1051,91 @@ int HttpOpRequest::debugCallback(CURL * handle, curl_infotype info, char * buffe LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata)); - std::string safe_line; - std::string tag; - bool logit(false); - const size_t log_len((std::min)(len, size_t(256))); // Keep things reasonable in all cases - - switch (info) - { - case CURLINFO_TEXT: - if (op->mTracing >= HTTP_TRACE_CURL_HEADERS) - { - tag = "TEXT"; - escape_libcurl_debug_data(buffer, log_len, true, safe_line); - logit = true; - } - break; - - case CURLINFO_HEADER_IN: - if (op->mTracing >= HTTP_TRACE_CURL_HEADERS) - { - tag = "HEADERIN"; - escape_libcurl_debug_data(buffer, log_len, true, safe_line); - logit = true; - } - break; - - case CURLINFO_HEADER_OUT: - if (op->mTracing >= HTTP_TRACE_CURL_HEADERS) - { - tag = "HEADEROUT"; - escape_libcurl_debug_data(buffer, log_len, true, safe_line); // Goes out as one line unlike header_in - logit = true; - } - break; - - case CURLINFO_DATA_IN: - if (op->mTracing >= HTTP_TRACE_CURL_HEADERS) - { - tag = "DATAIN"; - logit = true; - if (op->mTracing >= HTTP_TRACE_CURL_BODIES) - { - escape_libcurl_debug_data(buffer, log_len, false, safe_line); - } - else - { - std::ostringstream out; - out << len << " Bytes"; - safe_line = out.str(); - } - } - break; - - case CURLINFO_DATA_OUT: - if (op->mTracing >= HTTP_TRACE_CURL_HEADERS) - { - tag = "DATAOUT"; - logit = true; - if (op->mTracing >= HTTP_TRACE_CURL_BODIES) - { - escape_libcurl_debug_data(buffer, log_len, false, safe_line); - } - else - { - std::ostringstream out; - out << len << " Bytes"; - safe_line = out.str(); - } - } - break; - - default: - logit = false; - break; - } - - if (logit) - { - LL_INFOS(LOG_CORE) << "TRACE, LibcurlDebug, Handle: " - << op->getHandle() - << ", Type: " << tag - << ", Data: " << safe_line - << LL_ENDL; - } - - return 0; + std::string safe_line; + std::string tag; + bool logit(false); + const size_t log_len((std::min)(len, size_t(256))); // Keep things reasonable in all cases + + switch (info) + { + case CURLINFO_TEXT: + if (op->mTracing >= HTTP_TRACE_CURL_HEADERS) + { + tag = "TEXT"; + escape_libcurl_debug_data(buffer, log_len, true, safe_line); + logit = true; + } + break; + + case CURLINFO_HEADER_IN: + if (op->mTracing >= HTTP_TRACE_CURL_HEADERS) + { + tag = "HEADERIN"; + escape_libcurl_debug_data(buffer, log_len, true, safe_line); + logit = true; + } + break; + + case CURLINFO_HEADER_OUT: + if (op->mTracing >= HTTP_TRACE_CURL_HEADERS) + { + tag = "HEADEROUT"; + escape_libcurl_debug_data(buffer, log_len, true, safe_line); // Goes out as one line unlike header_in + logit = true; + } + break; + + case CURLINFO_DATA_IN: + if (op->mTracing >= HTTP_TRACE_CURL_HEADERS) + { + tag = "DATAIN"; + logit = true; + if (op->mTracing >= HTTP_TRACE_CURL_BODIES) + { + escape_libcurl_debug_data(buffer, log_len, false, safe_line); + } + else + { + std::ostringstream out; + out << len << " Bytes"; + safe_line = out.str(); + } + } + break; + + case CURLINFO_DATA_OUT: + if (op->mTracing >= HTTP_TRACE_CURL_HEADERS) + { + tag = "DATAOUT"; + logit = true; + if (op->mTracing >= HTTP_TRACE_CURL_BODIES) + { + escape_libcurl_debug_data(buffer, log_len, false, safe_line); + } + else + { + std::ostringstream out; + out << len << " Bytes"; + safe_line = out.str(); + } + } + break; + + default: + logit = false; + break; + } + + if (logit) + { + LL_INFOS(LOG_CORE) << "TRACE, LibcurlDebug, Handle: " + << op->getHandle() + << ", Type: " << tag + << ", Data: " << safe_line + << LL_ENDL; + } + + return 0; } std::string HttpOpRequest::methodToString(const HttpOpRequest::EMethod &e) @@ -1169,110 +1169,110 @@ namespace { int parse_content_range_header(char * buffer, - unsigned int * first, - unsigned int * last, - unsigned int * length) + unsigned int * first, + unsigned int * last, + unsigned int * length) { - static const char * const hdr_whitespace(" \t"); - - char * tok_state(NULL), * tok(NULL); - bool match(true); - - if (! (tok = os_strtok_r(buffer, hdr_whitespace, &tok_state))) - match = false; - else - match = (0 == os_strcasecmp("bytes", tok)); - if (match && ! (tok = os_strtok_r(NULL, hdr_whitespace, &tok_state))) - match = false; - if (match) - { - unsigned int lcl_first(0), lcl_last(0), lcl_len(0); + static const char * const hdr_whitespace(" \t"); + + char * tok_state(NULL), * tok(NULL); + bool match(true); + + if (! (tok = os_strtok_r(buffer, hdr_whitespace, &tok_state))) + match = false; + else + match = (0 == os_strcasecmp("bytes", tok)); + if (match && ! (tok = os_strtok_r(NULL, hdr_whitespace, &tok_state))) + match = false; + if (match) + { + unsigned int lcl_first(0), lcl_last(0), lcl_len(0); #if LL_WINDOWS - if (3 == sscanf_s(tok, "%u-%u/%u", &lcl_first, &lcl_last, &lcl_len)) + if (3 == sscanf_s(tok, "%u-%u/%u", &lcl_first, &lcl_last, &lcl_len)) #else - if (3 == sscanf(tok, "%u-%u/%u", &lcl_first, &lcl_last, &lcl_len)) + if (3 == sscanf(tok, "%u-%u/%u", &lcl_first, &lcl_last, &lcl_len)) #endif // LL_WINDOWS - { - if (lcl_first > lcl_last || lcl_last >= lcl_len) - return -1; - *first = lcl_first; - *last = lcl_last; - *length = lcl_len; - return 0; - } + { + if (lcl_first > lcl_last || lcl_last >= lcl_len) + return -1; + *first = lcl_first; + *last = lcl_last; + *length = lcl_len; + return 0; + } #if LL_WINDOWS - if (2 == sscanf_s(tok, "%u-%u/*", &lcl_first, &lcl_last)) + if (2 == sscanf_s(tok, "%u-%u/*", &lcl_first, &lcl_last)) #else - if (2 == sscanf(tok, "%u-%u/*", &lcl_first, &lcl_last)) -#endif // LL_WINDOWS - { - if (lcl_first > lcl_last) - return -1; - *first = lcl_first; - *last = lcl_last; - *length = 0; - return 0; - } - } - - // Header is there but badly/unexpectedly formed, try to ignore it. - return 1; + if (2 == sscanf(tok, "%u-%u/*", &lcl_first, &lcl_last)) +#endif // LL_WINDOWS + { + if (lcl_first > lcl_last) + return -1; + *first = lcl_first; + *last = lcl_last; + *length = 0; + return 0; + } + } + + // Header is there but badly/unexpectedly formed, try to ignore it. + return 1; } int parse_retry_after_header(char * buffer, int * time) { - char * endptr(buffer); - long lcl_time(strtol(buffer, &endptr, 10)); - if (*endptr == '\0' && endptr != buffer && lcl_time > 0) - { - *time = lcl_time; - return 0; - } - - // Could attempt to parse HTTP time here but we're not really - // interested in it. Scheduling based on wallclock time on - // user hardware will lead to tears. - - // Header is there but badly/unexpectedly formed, try to ignore it. - return 1; + char * endptr(buffer); + long lcl_time(strtol(buffer, &endptr, 10)); + if (*endptr == '\0' && endptr != buffer && lcl_time > 0) + { + *time = lcl_time; + return 0; + } + + // Could attempt to parse HTTP time here but we're not really + // interested in it. Scheduling based on wallclock time on + // user hardware will lead to tears. + + // Header is there but badly/unexpectedly formed, try to ignore it. + return 1; } void escape_libcurl_debug_data(char * buffer, size_t len, bool scrub, std::string & safe_line) { - std::string out; - len = (std::min)(len, size_t(200)); - out.reserve(3 * len); - for (int i(0); i < len; ++i) - { - unsigned char uc(static_cast<unsigned char>(buffer[i])); - - if (uc < 32 || uc > 126) - { - if (scrub) - { - out.append(1, ' '); - } - else - { - static const char hex[] = "0123456789ABCDEF"; - char convert[4]; - - convert[0] = '%'; - convert[1] = hex[(uc >> 4) % 16]; - convert[2] = hex[uc % 16]; - convert[3] = '\0'; - out.append(convert); - } - } - else - { - out.append(1, buffer[i]); - } - } - safe_line.swap(out); + std::string out; + len = (std::min)(len, size_t(200)); + out.reserve(3 * len); + for (int i(0); i < len; ++i) + { + unsigned char uc(static_cast<unsigned char>(buffer[i])); + + if (uc < 32 || uc > 126) + { + if (scrub) + { + out.append(1, ' '); + } + else + { + static const char hex[] = "0123456789ABCDEF"; + char convert[4]; + + convert[0] = '%'; + convert[1] = hex[(uc >> 4) % 16]; + convert[2] = hex[uc % 16]; + convert[3] = '\0'; + out.append(convert); + } + } + else + { + out.append(1, buffer[i]); + } + } + safe_line.swap(out); } @@ -1280,9 +1280,9 @@ void escape_libcurl_debug_data(char * buffer, size_t len, bool scrub, std::strin int os_strcasecmp(const char *s1, const char *s2) { #if LL_WINDOWS - return _stricmp(s1, s2); + return _stricmp(s1, s2); #else - return strcasecmp(s1, s2); + return strcasecmp(s1, s2); #endif // LL_WINDOWS } @@ -1290,66 +1290,66 @@ int os_strcasecmp(const char *s1, const char *s2) char * os_strtok_r(char *str, const char *delim, char ** savestate) { #if LL_WINDOWS - return strtok_s(str, delim, savestate); + return strtok_s(str, delim, savestate); #else - return strtok_r(str, delim, savestate); + return strtok_r(str, delim, savestate); #endif } void os_strlower(char * str) { - for (char c(0); (c = *str); ++str) - { - *str = tolower(c); - } + for (char c(0); (c = *str); ++str) + { + *str = tolower(c); + } } char * os_strtrim(char * lstr) { - while (' ' == *lstr || '\t' == *lstr) - { - ++lstr; - } - if (*lstr) - { - char * rstr(lstr + strlen(lstr)); - while (lstr < rstr && *--rstr) - { - if (' ' == *rstr || '\t' == *rstr) - { - *rstr = '\0'; - } - } - llassert(lstr <= rstr); - } - return lstr; + while (' ' == *lstr || '\t' == *lstr) + { + ++lstr; + } + if (*lstr) + { + char * rstr(lstr + strlen(lstr)); + while (lstr < rstr && *--rstr) + { + if (' ' == *rstr || '\t' == *rstr) + { + *rstr = '\0'; + } + } + llassert(lstr <= rstr); + } + return lstr; } char * os_strltrim(char * lstr) { - while (' ' == *lstr || '\t' == *lstr) - { - ++lstr; - } - return lstr; + while (' ' == *lstr || '\t' == *lstr) + { + ++lstr; + } + return lstr; } void check_curl_easy_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(LOG_CORE) << "libcurl error detected: " << curl_easy_strerror(code) - << ", curl_easy_setopt option: " << curl_setopt_option - << LL_ENDL; - } + 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(LOG_CORE) << "libcurl error detected: " << curl_easy_strerror(code) + << ", curl_easy_setopt option: " << curl_setopt_option + << LL_ENDL; + } } } // end anonymous namespace diff --git a/indra/llcorehttp/_httpoprequest.h b/indra/llcorehttp/_httpoprequest.h index 626064329d..b029bc740c 100644 --- a/indra/llcorehttp/_httpoprequest.h +++ b/indra/llcorehttp/_httpoprequest.h @@ -24,11 +24,11 @@ * $/LicenseInfo$ */ -#ifndef _LLCORE_HTTP_OPREQUEST_H_ -#define _LLCORE_HTTP_OPREQUEST_H_ +#ifndef _LLCORE_HTTP_OPREQUEST_H_ +#define _LLCORE_HTTP_OPREQUEST_H_ -#include "linden_common.h" // Modifies curl/curl.h interfaces +#include "linden_common.h" // Modifies curl/curl.h interfaces #include <string> #include <curl/curl.h> @@ -68,65 +68,65 @@ class HttpOpRequest : public HttpOperation public: typedef std::shared_ptr<HttpOpRequest> ptr_t; - HttpOpRequest(); + HttpOpRequest(); - virtual ~HttpOpRequest(); // Use release() + virtual ~HttpOpRequest(); // Use release() private: - HttpOpRequest(const HttpOpRequest &); // Not defined - void operator=(const HttpOpRequest &); // Not defined + HttpOpRequest(const HttpOpRequest &); // Not defined + void operator=(const HttpOpRequest &); // Not defined public: - enum EMethod - { - HOR_GET, - HOR_POST, - HOR_PUT, + enum EMethod + { + HOR_GET, + HOR_POST, + HOR_PUT, HOR_DELETE, HOR_PATCH, HOR_COPY, HOR_MOVE - }; + }; static std::string methodToString(const EMethod &); - virtual void stageFromRequest(HttpService *); - virtual void stageFromReady(HttpService *); - virtual void stageFromActive(HttpService *); + virtual void stageFromRequest(HttpService *); + virtual void stageFromReady(HttpService *); + virtual void stageFromActive(HttpService *); + + virtual void visitNotifier(HttpRequest * request); - virtual void visitNotifier(HttpRequest * request); - public: - /// Setup Methods - /// - /// Basically an RPC setup for each type of HTTP method - /// invocation with one per method type. These are - /// generally invoked right after construction. - /// - /// Threading: called by application thread - /// - HttpStatus setupGet(HttpRequest::policy_t policy_id, - const std::string & url, - const HttpOptions::ptr_t & options, - const HttpHeaders::ptr_t & headers); - - HttpStatus setupGetByteRange(HttpRequest::policy_t policy_id, - const std::string & url, - size_t offset, - size_t len, + /// Setup Methods + /// + /// Basically an RPC setup for each type of HTTP method + /// invocation with one per method type. These are + /// generally invoked right after construction. + /// + /// Threading: called by application thread + /// + HttpStatus setupGet(HttpRequest::policy_t policy_id, + const std::string & url, + const HttpOptions::ptr_t & options, + const HttpHeaders::ptr_t & headers); + + HttpStatus setupGetByteRange(HttpRequest::policy_t policy_id, + const std::string & url, + size_t offset, + size_t len, const HttpOptions::ptr_t & options, - const HttpHeaders::ptr_t & headers); - - HttpStatus setupPost(HttpRequest::policy_t policy_id, - const std::string & url, - BufferArray * body, + const HttpHeaders::ptr_t & headers); + + HttpStatus setupPost(HttpRequest::policy_t policy_id, + const std::string & url, + BufferArray * body, const HttpOptions::ptr_t & options, - const HttpHeaders::ptr_t & headers); - - HttpStatus setupPut(HttpRequest::policy_t policy_id, - const std::string & url, - BufferArray * body, + const HttpHeaders::ptr_t & headers); + + HttpStatus setupPut(HttpRequest::policy_t policy_id, + const std::string & url, + BufferArray * body, const HttpOptions::ptr_t & options, - const HttpHeaders::ptr_t & headers); + const HttpHeaders::ptr_t & headers); HttpStatus setupDelete(HttpRequest::policy_t policy_id, const std::string & url, @@ -150,82 +150,82 @@ public: 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 - // - HttpStatus prepareRequest(HttpService * service); - - virtual HttpStatus cancel(); + // Does all the libcurl handle setup in one place. + // + // Threading: called by worker thread + // + HttpStatus prepareRequest(HttpService * service); + + virtual HttpStatus cancel(); protected: - // Common setup for all the request methods. - // - // Threading: called by application thread - // - void setupCommon(HttpRequest::policy_t policy_id, - const std::string & url, - BufferArray * body, + // Common setup for all the request methods. + // + // Threading: called by application thread + // + void setupCommon(HttpRequest::policy_t policy_id, + const std::string & url, + BufferArray * body, const HttpOptions::ptr_t & options, - const HttpHeaders::ptr_t & headers); - - // libcurl operational callbacks - // - // Threading: called by worker thread - // - 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); + const HttpHeaders::ptr_t & headers); + + // libcurl operational callbacks + // + // Threading: called by worker thread + // + 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 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); + static int debugCallback(CURL *, curl_infotype info, char * buffer, size_t len, void * userdata); protected: - unsigned int mProcFlags; - static const unsigned int PF_SCAN_RANGE_HEADER = 0x00000001U; - static const unsigned int PF_SAVE_HEADERS = 0x00000002U; - static const unsigned int PF_USE_RETRY_AFTER = 0x00000004U; + unsigned int mProcFlags; + static const unsigned int PF_SCAN_RANGE_HEADER = 0x00000001U; + static const unsigned int PF_SAVE_HEADERS = 0x00000002U; + static const unsigned int PF_USE_RETRY_AFTER = 0x00000004U; - HttpRequest::policyCallback_t mCallbackSSLVerify; + HttpRequest::policyCallback_t mCallbackSSLVerify; public: - // Request data - EMethod mReqMethod; - std::string mReqURL; - BufferArray * mReqBody; - off_t mReqOffset; - size_t mReqLength; - HttpHeaders::ptr_t mReqHeaders; + // Request data + EMethod mReqMethod; + std::string mReqURL; + BufferArray * mReqBody; + off_t mReqOffset; + size_t mReqLength; + HttpHeaders::ptr_t mReqHeaders; HttpOptions::ptr_t mReqOptions; - // Transport data - bool mCurlActive; - CURL * mCurlHandle; - HttpService * mCurlService; - curl_slist * mCurlHeaders; - size_t mCurlBodyPos; - char * mCurlTemp; // Scratch buffer for header processing - size_t mCurlTempLen; - - // Result data - HttpStatus mStatus; - BufferArray * mReplyBody; - off_t mReplyOffset; - size_t mReplyLength; - size_t mReplyFullLength; - HttpHeaders::ptr_t mReplyHeaders; - std::string mReplyConType; - int mReplyRetryAfter; - - // Policy data - int mPolicyRetries; - int mPolicy503Retries; - HttpTime mPolicyRetryAt; - int mPolicyRetryLimit; - HttpTime mPolicyMinRetryBackoff; // initial delay between retries (mcs) - HttpTime mPolicyMaxRetryBackoff; + // Transport data + bool mCurlActive; + CURL * mCurlHandle; + HttpService * mCurlService; + curl_slist * mCurlHeaders; + size_t mCurlBodyPos; + char * mCurlTemp; // Scratch buffer for header processing + size_t mCurlTempLen; + + // Result data + HttpStatus mStatus; + BufferArray * mReplyBody; + off_t mReplyOffset; + size_t mReplyLength; + size_t mReplyFullLength; + HttpHeaders::ptr_t mReplyHeaders; + std::string mReplyConType; + int mReplyRetryAfter; + + // Policy data + int mPolicyRetries; + int mPolicy503Retries; + HttpTime mPolicyRetryAt; + int mPolicyRetryLimit; + HttpTime mPolicyMinRetryBackoff; // initial delay between retries (mcs) + HttpTime mPolicyMaxRetryBackoff; }; // end class HttpOpRequest @@ -240,5 +240,5 @@ curl_slist * append_headers_to_slist(const HttpHeaders::ptr_t &, curl_slist * sl } // end namespace LLCore -#endif // _LLCORE_HTTP_OPREQUEST_H_ +#endif // _LLCORE_HTTP_OPREQUEST_H_ diff --git a/indra/llcorehttp/_httpopsetget.cpp b/indra/llcorehttp/_httpopsetget.cpp index a5363f9170..8caecd3e76 100644 --- a/indra/llcorehttp/_httpopsetget.cpp +++ b/indra/llcorehttp/_httpopsetget.cpp @@ -43,12 +43,12 @@ namespace LLCore HttpOpSetGet::HttpOpSetGet() - : HttpOperation(), - mReqOption(HttpRequest::PO_CONNECTION_LIMIT), - mReqClass(HttpRequest::INVALID_POLICY_ID), - mReqDoSet(false), - mReqLongValue(0L), - mReplyLongValue(0L) + : HttpOperation(), + mReqOption(HttpRequest::PO_CONNECTION_LIMIT), + mReqClass(HttpRequest::INVALID_POLICY_ID), + mReqDoSet(false), + mReqLongValue(0L), + mReplyLongValue(0L) {} @@ -58,89 +58,89 @@ HttpOpSetGet::~HttpOpSetGet() HttpStatus HttpOpSetGet::setupGet(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass) { - HttpStatus status; - - mReqOption = opt; - mReqClass = pclass; - return status; + HttpStatus status; + + mReqOption = opt; + mReqClass = pclass; + return status; } HttpStatus HttpOpSetGet::setupSet(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass, long value) { - HttpStatus status; - - if (! HttpService::sOptionDesc[opt].mIsLong) - { - return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); - } - if (! HttpService::sOptionDesc[opt].mIsDynamic) - { - return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC); - } - - mReqOption = opt; - mReqClass = pclass; - mReqDoSet = true; - mReqLongValue = value; - - return status; + HttpStatus status; + + if (! HttpService::sOptionDesc[opt].mIsLong) + { + return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); + } + if (! HttpService::sOptionDesc[opt].mIsDynamic) + { + return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC); + } + + mReqOption = opt; + mReqClass = pclass; + mReqDoSet = true; + mReqLongValue = value; + + return status; } HttpStatus HttpOpSetGet::setupSet(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass, const std::string & value) { - HttpStatus status; - - if (HttpService::sOptionDesc[opt].mIsLong) - { - return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); - } - if (! HttpService::sOptionDesc[opt].mIsDynamic) - { - return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC); - } - - mReqOption = opt; - mReqClass = pclass; - mReqDoSet = true; - mReqStrValue = value; - - return status; + HttpStatus status; + + if (HttpService::sOptionDesc[opt].mIsLong) + { + return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); + } + if (! HttpService::sOptionDesc[opt].mIsDynamic) + { + return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC); + } + + mReqOption = opt; + mReqClass = pclass; + mReqDoSet = true; + mReqStrValue = value; + + return status; } void HttpOpSetGet::stageFromRequest(HttpService * service) { - if (mReqDoSet) - { - if (HttpService::sOptionDesc[mReqOption].mIsLong) - { - mStatus = service->setPolicyOption(mReqOption, mReqClass, - mReqLongValue, &mReplyLongValue); - } - else - { - mStatus = service->setPolicyOption(mReqOption, mReqClass, - mReqStrValue, &mReplyStrValue); - } - } - else - { - if (HttpService::sOptionDesc[mReqOption].mIsLong) - { - mStatus = service->getPolicyOption(mReqOption, mReqClass, &mReplyLongValue); - } - else - { - mStatus = service->getPolicyOption(mReqOption, mReqClass, &mReplyStrValue); - } - } - - addAsReply(); + if (mReqDoSet) + { + if (HttpService::sOptionDesc[mReqOption].mIsLong) + { + mStatus = service->setPolicyOption(mReqOption, mReqClass, + mReqLongValue, &mReplyLongValue); + } + else + { + mStatus = service->setPolicyOption(mReqOption, mReqClass, + mReqStrValue, &mReplyStrValue); + } + } + else + { + if (HttpService::sOptionDesc[mReqOption].mIsLong) + { + mStatus = service->getPolicyOption(mReqOption, mReqClass, &mReplyLongValue); + } + else + { + mStatus = service->getPolicyOption(mReqOption, mReqClass, &mReplyStrValue); + } + } + + addAsReply(); } } // end namespace LLCore - + diff --git a/indra/llcorehttp/_httpopsetget.h b/indra/llcorehttp/_httpopsetget.h index 04ab2446ef..0b927a6b71 100644 --- a/indra/llcorehttp/_httpopsetget.h +++ b/indra/llcorehttp/_httpopsetget.h @@ -24,11 +24,11 @@ * $/LicenseInfo$ */ -#ifndef _LLCORE_HTTP_OPSETGET_H_ -#define _LLCORE_HTTP_OPSETGET_H_ +#ifndef _LLCORE_HTTP_OPSETGET_H_ +#define _LLCORE_HTTP_OPSETGET_H_ -#include "linden_common.h" // Modifies curl/curl.h interfaces +#include "linden_common.h" // Modifies curl/curl.h interfaces #include "httpcommon.h" @@ -55,37 +55,37 @@ class HttpOpSetGet : public HttpOperation public: typedef std::shared_ptr<HttpOpSetGet> ptr_t; - HttpOpSetGet(); + HttpOpSetGet(); - virtual ~HttpOpSetGet(); // Use release() + virtual ~HttpOpSetGet(); // Use release() private: - HttpOpSetGet(const HttpOpSetGet &); // Not defined - void operator=(const HttpOpSetGet &); // Not defined + HttpOpSetGet(const HttpOpSetGet &); // Not defined + void operator=(const HttpOpSetGet &); // Not defined public: - /// Threading: called by application thread - HttpStatus setupGet(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass); - HttpStatus setupSet(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass, long value); - HttpStatus setupSet(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass, const std::string & value); + /// Threading: called by application thread + HttpStatus setupGet(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass); + HttpStatus setupSet(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass, long value); + HttpStatus setupSet(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass, const std::string & value); - virtual void stageFromRequest(HttpService *); + virtual void stageFromRequest(HttpService *); public: - // Request data - HttpRequest::EPolicyOption mReqOption; - HttpRequest::policy_t mReqClass; - bool mReqDoSet; - long mReqLongValue; - std::string mReqStrValue; - - // Reply Data - long mReplyLongValue; - std::string mReplyStrValue; + // Request data + HttpRequest::EPolicyOption mReqOption; + HttpRequest::policy_t mReqClass; + bool mReqDoSet; + long mReqLongValue; + std::string mReqStrValue; + + // Reply Data + long mReplyLongValue; + std::string mReplyStrValue; }; // end class HttpOpSetGet } // end namespace LLCore -#endif // _LLCORE_HTTP_OPSETGET_H_ +#endif // _LLCORE_HTTP_OPSETGET_H_ diff --git a/indra/llcorehttp/_httpopsetpriority.cpp b/indra/llcorehttp/_httpopsetpriority.cpp index b99b4e9e4a..b62770e45a 100644 --- a/indra/llcorehttp/_httpopsetpriority.cpp +++ b/indra/llcorehttp/_httpopsetpriority.cpp @@ -37,9 +37,9 @@ namespace LLCore HttpOpSetPriority::HttpOpSetPriority(HttpHandle handle, HttpRequest::priority_t priority) - : HttpOperation(), - mHandle(handle), - mPriority(priority) + : HttpOperation(), + mHandle(handle), + mPriority(priority) {} @@ -49,15 +49,15 @@ HttpOpSetPriority::~HttpOpSetPriority() void HttpOpSetPriority::stageFromRequest(HttpService * service) { - // Do operations - if (! service->changePriority(mHandle, mPriority)) - { - // Request not found, fail the final status - mStatus = HttpStatus(HttpStatus::LLCORE, HE_HANDLE_NOT_FOUND); - } - - // Move directly to response queue - addAsReply(); + // Do operations + if (! service->changePriority(mHandle, mPriority)) + { + // Request not found, fail the final status + mStatus = HttpStatus(HttpStatus::LLCORE, HE_HANDLE_NOT_FOUND); + } + + // Move directly to response queue + addAsReply(); } diff --git a/indra/llcorehttp/_httpopsetpriority.h b/indra/llcorehttp/_httpopsetpriority.h index fd543f37cc..b77a220c1b 100644 --- a/indra/llcorehttp/_httpopsetpriority.h +++ b/indra/llcorehttp/_httpopsetpriority.h @@ -24,8 +24,8 @@ * $/LicenseInfo$ */ -#ifndef _LLCORE_HTTP_SETPRIORITY_H_ -#define _LLCORE_HTTP_SETPRIORITY_H_ +#ifndef _LLCORE_HTTP_SETPRIORITY_H_ +#define _LLCORE_HTTP_SETPRIORITY_H_ #if 0 // DEPRECATED #include "httpcommon.h" @@ -49,24 +49,24 @@ namespace LLCore class HttpOpSetPriority : public HttpOperation { public: - HttpOpSetPriority(HttpHandle handle); + HttpOpSetPriority(HttpHandle handle); - virtual ~HttpOpSetPriority(); + virtual ~HttpOpSetPriority(); private: - HttpOpSetPriority(const HttpOpSetPriority &); // Not defined - void operator=(const HttpOpSetPriority &); // Not defined + HttpOpSetPriority(const HttpOpSetPriority &); // Not defined + void operator=(const HttpOpSetPriority &); // Not defined public: - virtual void stageFromRequest(HttpService *); + virtual void stageFromRequest(HttpService *); protected: - // Request Data - HttpHandle mHandle; + // Request Data + HttpHandle mHandle; }; // end class HttpOpSetPriority } // end namespace LLCore #endif -#endif // _LLCORE_HTTP_SETPRIORITY_H_ +#endif // _LLCORE_HTTP_SETPRIORITY_H_ diff --git a/indra/llcorehttp/_httppolicy.cpp b/indra/llcorehttp/_httppolicy.cpp index 29f50c1693..704c8abb93 100644 --- a/indra/llcorehttp/_httppolicy.cpp +++ b/indra/llcorehttp/_httppolicy.cpp @@ -56,82 +56,82 @@ namespace LLCore struct HttpPolicy::ClassState { public: - ClassState() - : mThrottleEnd(0), - mThrottleLeft(0L), - mRequestCount(0L), - mStallStaging(false) - {} - - HttpReadyQueue mReadyQueue; - HttpRetryQueue mRetryQueue; - - HttpPolicyClass mOptions; - HttpTime mThrottleEnd; - long mThrottleLeft; - long mRequestCount; - bool mStallStaging; + ClassState() + : mThrottleEnd(0), + mThrottleLeft(0L), + mRequestCount(0L), + mStallStaging(false) + {} + + HttpReadyQueue mReadyQueue; + HttpRetryQueue mRetryQueue; + + HttpPolicyClass mOptions; + HttpTime mThrottleEnd; + long mThrottleLeft; + long mRequestCount; + bool mStallStaging; }; HttpPolicy::HttpPolicy(HttpService * service) - : mService(service) + : mService(service) { - // Create default class - mClasses.push_back(new ClassState()); + // Create default class + mClasses.push_back(new ClassState()); } HttpPolicy::~HttpPolicy() { - shutdown(); - - for (class_list_t::iterator it(mClasses.begin()); it != mClasses.end(); ++it) - { - delete (*it); - } - mClasses.clear(); - - mService = NULL; + shutdown(); + + for (class_list_t::iterator it(mClasses.begin()); it != mClasses.end(); ++it) + { + delete (*it); + } + mClasses.clear(); + + mService = NULL; } HttpRequest::policy_t HttpPolicy::createPolicyClass() { - const HttpRequest::policy_t policy_class(mClasses.size()); - if (policy_class >= HTTP_POLICY_CLASS_LIMIT) - { - return HttpRequest::INVALID_POLICY_ID; - } - mClasses.push_back(new ClassState()); - return policy_class; + const HttpRequest::policy_t policy_class(mClasses.size()); + if (policy_class >= HTTP_POLICY_CLASS_LIMIT) + { + return HttpRequest::INVALID_POLICY_ID; + } + mClasses.push_back(new ClassState()); + return policy_class; } void HttpPolicy::shutdown() { - for (int policy_class(0); policy_class < mClasses.size(); ++policy_class) - { - ClassState & state(*mClasses[policy_class]); - - HttpRetryQueue & retryq(state.mRetryQueue); - while (! retryq.empty()) - { - HttpOpRequest::ptr_t op(retryq.top()); - retryq.pop(); - - op->cancel(); - } - - HttpReadyQueue & readyq(state.mReadyQueue); - while (! readyq.empty()) - { - HttpOpRequest::ptr_t op(readyq.top()); - readyq.pop(); - - op->cancel(); - } - } + for (int policy_class(0); policy_class < mClasses.size(); ++policy_class) + { + ClassState & state(*mClasses[policy_class]); + + HttpRetryQueue & retryq(state.mRetryQueue); + while (! retryq.empty()) + { + HttpOpRequest::ptr_t op(retryq.top()); + retryq.pop(); + + op->cancel(); + } + + HttpReadyQueue & readyq(state.mReadyQueue); + while (! readyq.empty()) + { + HttpOpRequest::ptr_t op(readyq.top()); + readyq.pop(); + + op->cancel(); + } + } } @@ -142,54 +142,54 @@ void HttpPolicy::start() void HttpPolicy::addOp(const HttpOpRequest::ptr_t &op) { - const int policy_class(op->mReqPolicy); - - op->mPolicyRetries = 0; - op->mPolicy503Retries = 0; - mClasses[policy_class]->mReadyQueue.push(op); + const int policy_class(op->mReqPolicy); + + op->mPolicyRetries = 0; + op->mPolicy503Retries = 0; + mClasses[policy_class]->mReadyQueue.push(op); } void HttpPolicy::retryOp(const HttpOpRequest::ptr_t &op) { - static const HttpStatus error_503(503); - - const HttpTime now(totalTime()); - const int policy_class(op->mReqPolicy); - - HttpTime delta_min = op->mPolicyMinRetryBackoff; - HttpTime delta_max = op->mPolicyMaxRetryBackoff; - // mPolicyRetries limited to 100 - U32 delta_factor = op->mPolicyRetries <= 10 ? 1 << op->mPolicyRetries : 1024; - HttpTime delta = llmin(delta_min * delta_factor, delta_max); - bool external_delta(false); - - if (op->mReplyRetryAfter > 0 && op->mReplyRetryAfter < 30) - { - delta = op->mReplyRetryAfter * U64L(1000000); - external_delta = true; - } - op->mPolicyRetryAt = now + delta; - ++op->mPolicyRetries; - if (error_503 == op->mStatus) - { - ++op->mPolicy503Retries; - } - LL_DEBUGS(LOG_CORE) << "HTTP request " << op->getHandle() - << " retry " << op->mPolicyRetries - << " scheduled in " << (delta / HttpTime(1000)) - << " mS (" << (external_delta ? "external" : "internal") - << "). Status: " << op->mStatus.toTerseString() - << LL_ENDL; - if (op->mTracing > HTTP_TRACE_OFF) - { - LL_INFOS(LOG_CORE) << "TRACE, ToRetryQueue, Handle: " + static const HttpStatus error_503(503); + + const HttpTime now(totalTime()); + const int policy_class(op->mReqPolicy); + + HttpTime delta_min = op->mPolicyMinRetryBackoff; + HttpTime delta_max = op->mPolicyMaxRetryBackoff; + // mPolicyRetries limited to 100 + U32 delta_factor = op->mPolicyRetries <= 10 ? 1 << op->mPolicyRetries : 1024; + HttpTime delta = llmin(delta_min * delta_factor, delta_max); + bool external_delta(false); + + if (op->mReplyRetryAfter > 0 && op->mReplyRetryAfter < 30) + { + delta = op->mReplyRetryAfter * U64L(1000000); + external_delta = true; + } + op->mPolicyRetryAt = now + delta; + ++op->mPolicyRetries; + if (error_503 == op->mStatus) + { + ++op->mPolicy503Retries; + } + LL_DEBUGS(LOG_CORE) << "HTTP request " << op->getHandle() + << " retry " << op->mPolicyRetries + << " scheduled in " << (delta / HttpTime(1000)) + << " mS (" << (external_delta ? "external" : "internal") + << "). Status: " << op->mStatus.toTerseString() + << LL_ENDL; + if (op->mTracing > HTTP_TRACE_OFF) + { + LL_INFOS(LOG_CORE) << "TRACE, ToRetryQueue, Handle: " << op->getHandle() - << ", Delta: " << (delta / HttpTime(1000)) - << ", Retries: " << op->mPolicyRetries - << LL_ENDL; - } - mClasses[policy_class]->mRetryQueue.push(op); + << ", Delta: " << (delta / HttpTime(1000)) + << ", Retries: " << op->mPolicyRetries + << LL_ENDL; + } + mClasses[policy_class]->mRetryQueue.push(op); } @@ -213,242 +213,242 @@ void HttpPolicy::retryOp(const HttpOpRequest::ptr_t &op) // HttpService::ELoopSpeed HttpPolicy::processReadyQueue() { - const HttpTime now(totalTime()); - HttpService::ELoopSpeed result(HttpService::REQUEST_SLEEP); - HttpLibcurl & transport(mService->getTransport()); - - for (int policy_class(0); policy_class < mClasses.size(); ++policy_class) - { - ClassState & state(*mClasses[policy_class]); - HttpRetryQueue & retryq(state.mRetryQueue); - HttpReadyQueue & readyq(state.mReadyQueue); - - if (state.mStallStaging) - { - // Stalling but don't sleep. Need to complete operations - // and get back to servicing queues. Do this test before - // the retryq/readyq test or you'll get stalls until you - // click a setting or an asset request comes in. - result = HttpService::NORMAL; - continue; - } - if (retryq.empty() && readyq.empty()) - { - continue; - } - - const bool throttle_enabled(state.mOptions.mThrottleRate > 0L); - const bool throttle_current(throttle_enabled && now < state.mThrottleEnd); - - if (throttle_current && state.mThrottleLeft <= 0) - { - // Throttled condition, don't serve this class but don't sleep hard. - result = HttpService::NORMAL; - continue; - } - - int active(transport.getActiveCountInClass(policy_class)); - int active_limit(state.mOptions.mPipelining > 1L - ? (state.mOptions.mPerHostConnectionLimit - * state.mOptions.mPipelining) - : state.mOptions.mConnectionLimit); - int needed(active_limit - active); // Expect negatives here - - if (needed > 0) - { - // First see if we have any retries... - while (needed > 0 && ! retryq.empty()) - { - HttpOpRequest::ptr_t op(retryq.top()); - if (op->mPolicyRetryAt > now) - break; - - retryq.pop(); - - op->stageFromReady(mService); + const HttpTime now(totalTime()); + HttpService::ELoopSpeed result(HttpService::REQUEST_SLEEP); + HttpLibcurl & transport(mService->getTransport()); + + for (int policy_class(0); policy_class < mClasses.size(); ++policy_class) + { + ClassState & state(*mClasses[policy_class]); + HttpRetryQueue & retryq(state.mRetryQueue); + HttpReadyQueue & readyq(state.mReadyQueue); + + if (state.mStallStaging) + { + // Stalling but don't sleep. Need to complete operations + // and get back to servicing queues. Do this test before + // the retryq/readyq test or you'll get stalls until you + // click a setting or an asset request comes in. + result = HttpService::NORMAL; + continue; + } + if (retryq.empty() && readyq.empty()) + { + continue; + } + + const bool throttle_enabled(state.mOptions.mThrottleRate > 0L); + const bool throttle_current(throttle_enabled && now < state.mThrottleEnd); + + if (throttle_current && state.mThrottleLeft <= 0) + { + // Throttled condition, don't serve this class but don't sleep hard. + result = HttpService::NORMAL; + continue; + } + + int active(transport.getActiveCountInClass(policy_class)); + int active_limit(state.mOptions.mPipelining > 1L + ? (state.mOptions.mPerHostConnectionLimit + * state.mOptions.mPipelining) + : state.mOptions.mConnectionLimit); + int needed(active_limit - active); // Expect negatives here + + if (needed > 0) + { + // First see if we have any retries... + while (needed > 0 && ! retryq.empty()) + { + HttpOpRequest::ptr_t op(retryq.top()); + if (op->mPolicyRetryAt > now) + break; + + retryq.pop(); + + op->stageFromReady(mService); + op.reset(); + + ++state.mRequestCount; + --needed; + if (throttle_enabled) + { + if (now >= state.mThrottleEnd) + { + // Throttle expired, move to next window + LL_DEBUGS(LOG_CORE) << "Throttle expired with " << state.mThrottleLeft + << " requests to go and " << state.mRequestCount + << " requests issued." << LL_ENDL; + state.mThrottleLeft = state.mOptions.mThrottleRate; + state.mThrottleEnd = now + HttpTime(1000000); + } + if (--state.mThrottleLeft <= 0) + { + goto throttle_on; + } + } + } + + // Now go on to the new requests... + while (needed > 0 && ! readyq.empty()) + { + HttpOpRequest::ptr_t op(readyq.top()); + readyq.pop(); + + op->stageFromReady(mService); op.reset(); - ++state.mRequestCount; - --needed; - if (throttle_enabled) - { - if (now >= state.mThrottleEnd) - { - // Throttle expired, move to next window - LL_DEBUGS(LOG_CORE) << "Throttle expired with " << state.mThrottleLeft - << " requests to go and " << state.mRequestCount - << " requests issued." << LL_ENDL; - state.mThrottleLeft = state.mOptions.mThrottleRate; - state.mThrottleEnd = now + HttpTime(1000000); - } - if (--state.mThrottleLeft <= 0) - { - goto throttle_on; - } - } - } - - // Now go on to the new requests... - while (needed > 0 && ! readyq.empty()) - { - HttpOpRequest::ptr_t op(readyq.top()); - readyq.pop(); - - op->stageFromReady(mService); - op.reset(); - - ++state.mRequestCount; - --needed; - if (throttle_enabled) - { - if (now >= state.mThrottleEnd) - { - // Throttle expired, move to next window - LL_DEBUGS(LOG_CORE) << "Throttle expired with " << state.mThrottleLeft - << " requests to go and " << state.mRequestCount - << " requests issued." << LL_ENDL; - state.mThrottleLeft = state.mOptions.mThrottleRate; - state.mThrottleEnd = now + HttpTime(1000000); - } - if (--state.mThrottleLeft <= 0) - { - goto throttle_on; - } - } - } - } - - throttle_on: - - if (! readyq.empty() || ! retryq.empty()) - { - // If anything is ready, continue looping... - result = HttpService::NORMAL; - } - } // end foreach policy_class - - return result; + ++state.mRequestCount; + --needed; + if (throttle_enabled) + { + if (now >= state.mThrottleEnd) + { + // Throttle expired, move to next window + LL_DEBUGS(LOG_CORE) << "Throttle expired with " << state.mThrottleLeft + << " requests to go and " << state.mRequestCount + << " requests issued." << LL_ENDL; + state.mThrottleLeft = state.mOptions.mThrottleRate; + state.mThrottleEnd = now + HttpTime(1000000); + } + if (--state.mThrottleLeft <= 0) + { + goto throttle_on; + } + } + } + } + + throttle_on: + + if (! readyq.empty() || ! retryq.empty()) + { + // If anything is ready, continue looping... + result = HttpService::NORMAL; + } + } // end foreach policy_class + + return result; } bool HttpPolicy::cancel(HttpHandle handle) { - for (int policy_class(0); policy_class < mClasses.size(); ++policy_class) - { - ClassState & state(*mClasses[policy_class]); - - // Scan retry queue - HttpRetryQueue::container_type & c1(state.mRetryQueue.get_container()); - for (HttpRetryQueue::container_type::iterator iter(c1.begin()); c1.end() != iter;) - { - HttpRetryQueue::container_type::iterator cur(iter++); - - if ((*cur)->getHandle() == handle) - { - HttpOpRequest::ptr_t op(*cur); - c1.erase(cur); // All iterators are now invalidated - op->cancel(); - return true; - } - } - - // Scan ready queue - HttpReadyQueue::container_type & c2(state.mReadyQueue.get_container()); - for (HttpReadyQueue::container_type::iterator iter(c2.begin()); c2.end() != iter;) - { - HttpReadyQueue::container_type::iterator cur(iter++); - - if ((*cur)->getHandle() == handle) - { - HttpOpRequest::ptr_t op(*cur); - c2.erase(cur); // All iterators are now invalidated - op->cancel(); - return true; - } - } - } - - return false; + for (int policy_class(0); policy_class < mClasses.size(); ++policy_class) + { + ClassState & state(*mClasses[policy_class]); + + // Scan retry queue + HttpRetryQueue::container_type & c1(state.mRetryQueue.get_container()); + for (HttpRetryQueue::container_type::iterator iter(c1.begin()); c1.end() != iter;) + { + HttpRetryQueue::container_type::iterator cur(iter++); + + if ((*cur)->getHandle() == handle) + { + HttpOpRequest::ptr_t op(*cur); + c1.erase(cur); // All iterators are now invalidated + op->cancel(); + return true; + } + } + + // Scan ready queue + HttpReadyQueue::container_type & c2(state.mReadyQueue.get_container()); + for (HttpReadyQueue::container_type::iterator iter(c2.begin()); c2.end() != iter;) + { + HttpReadyQueue::container_type::iterator cur(iter++); + + if ((*cur)->getHandle() == handle) + { + HttpOpRequest::ptr_t op(*cur); + c2.erase(cur); // All iterators are now invalidated + op->cancel(); + return true; + } + } + } + + return false; } bool HttpPolicy::stageAfterCompletion(const HttpOpRequest::ptr_t &op) { - // Retry or finalize - if (! op->mStatus) - { - // *DEBUG: For "[curl:bugs] #1420" tests. This will interfere - // with unit tests due to allocation retention by logging code. - // But you won't be checking this in enabled. + // Retry or finalize + if (! op->mStatus) + { + // *DEBUG: For "[curl:bugs] #1420" tests. This will interfere + // with unit tests due to allocation retention by logging code. + // But you won't be checking this in enabled. #if 0 - if (op->mStatus == HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_OPERATION_TIMEDOUT)) - { - LL_WARNS(LOG_CORE) << "HTTP request " << op->getHandle() - << " timed out." - << LL_ENDL; - } + if (op->mStatus == HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_OPERATION_TIMEDOUT)) + { + LL_WARNS(LOG_CORE) << "HTTP request " << op->getHandle() + << " timed out." + << LL_ENDL; + } #endif - - // If this failed, we might want to retry. - if (op->mPolicyRetries < op->mPolicyRetryLimit && op->mStatus.isRetryable()) - { - // Okay, worth a retry. - retryOp(op); - return true; // still active/ready - } - } - - // This op is done, finalize it delivering it to the reply queue... - if (! op->mStatus) - { - LL_WARNS(LOG_CORE) << "HTTP request " << op->getHandle() - << " failed after " << op->mPolicyRetries - << " retries. Reason: " << op->mStatus.toString() - << " (" << op->mStatus.toTerseString() << ")" - << LL_ENDL; - } - else if (op->mPolicyRetries) - { + + // If this failed, we might want to retry. + if (op->mPolicyRetries < op->mPolicyRetryLimit && op->mStatus.isRetryable()) + { + // Okay, worth a retry. + retryOp(op); + return true; // still active/ready + } + } + + // This op is done, finalize it delivering it to the reply queue... + if (! op->mStatus) + { + LL_WARNS(LOG_CORE) << "HTTP request " << op->getHandle() + << " failed after " << op->mPolicyRetries + << " retries. Reason: " << op->mStatus.toString() + << " (" << op->mStatus.toTerseString() << ")" + << LL_ENDL; + } + else if (op->mPolicyRetries) + { LL_DEBUGS(LOG_CORE) << "HTTP request " << op->getHandle() - << " succeeded on retry " << op->mPolicyRetries << "." - << LL_ENDL; - } + << " succeeded on retry " << op->mPolicyRetries << "." + << LL_ENDL; + } - op->stageFromActive(mService); + op->stageFromActive(mService); HTTPStats::instance().recordResultCode(op->mStatus.getType()); - return false; // not active + return false; // not active } - + HttpPolicyClass & HttpPolicy::getClassOptions(HttpRequest::policy_t pclass) { - llassert_always(pclass >= 0 && pclass < mClasses.size()); - - return mClasses[pclass]->mOptions; + llassert_always(pclass >= 0 && pclass < mClasses.size()); + + return mClasses[pclass]->mOptions; } int HttpPolicy::getReadyCount(HttpRequest::policy_t policy_class) const { - if (policy_class < mClasses.size()) - { - return (mClasses[policy_class]->mReadyQueue.size() - + mClasses[policy_class]->mRetryQueue.size()); - } - return 0; + if (policy_class < mClasses.size()) + { + return (mClasses[policy_class]->mReadyQueue.size() + + mClasses[policy_class]->mRetryQueue.size()); + } + return 0; } bool HttpPolicy::stallPolicy(HttpRequest::policy_t policy_class, bool stall) { - bool ret(false); - - if (policy_class < mClasses.size()) - { - ret = mClasses[policy_class]->mStallStaging; - mClasses[policy_class]->mStallStaging = stall; - } - return ret; + bool ret(false); + + if (policy_class < mClasses.size()) + { + ret = mClasses[policy_class]->mStallStaging; + mClasses[policy_class]->mStallStaging = stall; + } + return ret; } diff --git a/indra/llcorehttp/_httppolicy.h b/indra/llcorehttp/_httppolicy.h index 955f757c93..a074949f20 100644 --- a/indra/llcorehttp/_httppolicy.h +++ b/indra/llcorehttp/_httppolicy.h @@ -24,8 +24,8 @@ * $/LicenseInfo$ */ -#ifndef _LLCORE_HTTP_POLICY_H_ -#define _LLCORE_HTTP_POLICY_H_ +#ifndef _LLCORE_HTTP_POLICY_H_ +#define _LLCORE_HTTP_POLICY_H_ #include "httprequest.h" @@ -52,123 +52,123 @@ class HttpOpRequest; class HttpPolicy { public: - HttpPolicy(HttpService *); - virtual ~HttpPolicy(); + HttpPolicy(HttpService *); + virtual ~HttpPolicy(); private: - HttpPolicy(const HttpPolicy &); // Not defined - void operator=(const HttpPolicy &); // Not defined + HttpPolicy(const HttpPolicy &); // Not defined + void operator=(const HttpPolicy &); // Not defined public: typedef std::shared_ptr<HttpOpRequest> opReqPtr_t; - /// Threading: called by init thread. - HttpRequest::policy_t createPolicyClass(); - - /// Cancel all ready and retry requests sending them to - /// their notification queues. Release state resources - /// making further request handling impossible. - /// - /// Threading: called by worker thread - void shutdown(); - - /// Deliver policy definitions and enable handling of - /// requests. One-time call invoked before starting - /// the worker thread. - /// - /// Threading: called by init thread - void start(); - - /// Give the policy layer some cycles to scan the ready - /// queue promoting higher-priority requests to active - /// as permited. - /// - /// @return Indication of how soon this method - /// should be called again. - /// - /// Threading: called by worker thread - HttpService::ELoopSpeed processReadyQueue(); - - /// Add request to a ready queue. Caller is expected to have - /// provided us with a reference count to hold the request. (No - /// additional references will be added.) - /// - /// OpRequest is owned by the request queue after this call - /// and should not be modified by anyone until retrieved - /// from queue. - /// - /// Threading: called by worker thread + /// Threading: called by init thread. + HttpRequest::policy_t createPolicyClass(); + + /// Cancel all ready and retry requests sending them to + /// their notification queues. Release state resources + /// making further request handling impossible. + /// + /// Threading: called by worker thread + void shutdown(); + + /// Deliver policy definitions and enable handling of + /// requests. One-time call invoked before starting + /// the worker thread. + /// + /// Threading: called by init thread + void start(); + + /// Give the policy layer some cycles to scan the ready + /// queue promoting higher-priority requests to active + /// as permited. + /// + /// @return Indication of how soon this method + /// should be called again. + /// + /// Threading: called by worker thread + HttpService::ELoopSpeed processReadyQueue(); + + /// Add request to a ready queue. Caller is expected to have + /// provided us with a reference count to hold the request. (No + /// additional references will be added.) + /// + /// OpRequest is owned by the request queue after this call + /// and should not be modified by anyone until retrieved + /// from queue. + /// + /// Threading: called by worker thread 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 - /// queue but ordered by retry time not priority. Otherwise, - /// handling is the same and retried operations are considered - /// before new ones but that doesn't guarantee completion - /// order. - /// - /// Threading: called by worker thread + /// Similar to addOp, used when a caller wants to retry a + /// request that has failed. It's placed on a special retry + /// queue but ordered by retry time not priority. Otherwise, + /// handling is the same and retried operations are considered + /// before new ones but that doesn't guarantee completion + /// order. + /// + /// Threading: called by worker thread void retryOp(const opReqPtr_t &); - /// Attempt to cancel a previous request. - /// Shadows HttpService's method as well - /// - /// Threading: called by worker thread - bool cancel(HttpHandle handle); - - /// When transport is finished with an op and takes it off the - /// active queue, it is delivered here for dispatch. Policy - /// may send it back to the ready/retry queues if it needs another - /// go or we may finalize it and send it on to the reply queue. - /// - /// @return Returns true of the request is still active - /// or ready after staging, false if has been - /// sent on to the reply queue. - /// - /// Threading: called by worker thread + /// Attempt to cancel a previous request. + /// Shadows HttpService's method as well + /// + /// Threading: called by worker thread + bool cancel(HttpHandle handle); + + /// When transport is finished with an op and takes it off the + /// active queue, it is delivered here for dispatch. Policy + /// may send it back to the ready/retry queues if it needs another + /// go or we may finalize it and send it on to the reply queue. + /// + /// @return Returns true of the request is still active + /// or ready after staging, false if has been + /// sent on to the reply queue. + /// + /// Threading: called by worker thread 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 - /// are done, for example, in @see HttpService interfaces. - /// - /// Threading: called by any thread *but* the object may - /// only be modified by the worker thread once running. - HttpPolicyGlobal & getGlobalOptions() - { - return mGlobalOptions; - } - - /// Get a reference to class policy options. Caller is expected - /// to do context checks like no setting once running. These - /// are done, for example, in @see HttpService interfaces. - /// - /// Threading: called by any thread *but* the object may - /// only be modified by the worker thread once running and - /// read accesses by other threads are exposed to races at - /// that point. - HttpPolicyClass & getClassOptions(HttpRequest::policy_t pclass); - - /// Get ready counts for a particular policy class - /// - /// Threading: called by worker thread - int getReadyCount(HttpRequest::policy_t policy_class) const; - - /// Stall (or unstall) a policy class preventing requests from - /// transitioning to an active state. Used to allow an HTTP - /// request policy to empty prior to changing settings or state - /// that isn't tolerant of changes when work is outstanding. - /// - /// Threading: called by worker thread - bool stallPolicy(HttpRequest::policy_t policy_class, bool stall); - + + /// Get a reference to global policy options. Caller is expected + /// to do context checks like no setting once running. These + /// are done, for example, in @see HttpService interfaces. + /// + /// Threading: called by any thread *but* the object may + /// only be modified by the worker thread once running. + HttpPolicyGlobal & getGlobalOptions() + { + return mGlobalOptions; + } + + /// Get a reference to class policy options. Caller is expected + /// to do context checks like no setting once running. These + /// are done, for example, in @see HttpService interfaces. + /// + /// Threading: called by any thread *but* the object may + /// only be modified by the worker thread once running and + /// read accesses by other threads are exposed to races at + /// that point. + HttpPolicyClass & getClassOptions(HttpRequest::policy_t pclass); + + /// Get ready counts for a particular policy class + /// + /// Threading: called by worker thread + int getReadyCount(HttpRequest::policy_t policy_class) const; + + /// Stall (or unstall) a policy class preventing requests from + /// transitioning to an active state. Used to allow an HTTP + /// request policy to empty prior to changing settings or state + /// that isn't tolerant of changes when work is outstanding. + /// + /// Threading: called by worker thread + bool stallPolicy(HttpRequest::policy_t policy_class, bool stall); + protected: - struct ClassState; - typedef std::vector<ClassState *> class_list_t; - - HttpPolicyGlobal mGlobalOptions; - class_list_t mClasses; - HttpService * mService; // Naked pointer, not refcounted, not owner + struct ClassState; + typedef std::vector<ClassState *> class_list_t; + + HttpPolicyGlobal mGlobalOptions; + class_list_t mClasses; + HttpService * mService; // Naked pointer, not refcounted, not owner }; // end class HttpPolicy } // end namespace LLCore diff --git a/indra/llcorehttp/_httppolicyclass.cpp b/indra/llcorehttp/_httppolicyclass.cpp index 2c0f650155..811b004032 100644 --- a/indra/llcorehttp/_httppolicyclass.cpp +++ b/indra/llcorehttp/_httppolicyclass.cpp @@ -34,10 +34,10 @@ namespace LLCore HttpPolicyClass::HttpPolicyClass() - : mConnectionLimit(HTTP_CONNECTION_LIMIT_DEFAULT), - mPerHostConnectionLimit(HTTP_CONNECTION_LIMIT_DEFAULT), - mPipelining(HTTP_PIPELINING_DEFAULT), - mThrottleRate(HTTP_THROTTLE_RATE_DEFAULT) + : mConnectionLimit(HTTP_CONNECTION_LIMIT_DEFAULT), + mPerHostConnectionLimit(HTTP_CONNECTION_LIMIT_DEFAULT), + mPipelining(HTTP_PIPELINING_DEFAULT), + mThrottleRate(HTTP_THROTTLE_RATE_DEFAULT) {} @@ -47,78 +47,78 @@ HttpPolicyClass::~HttpPolicyClass() HttpPolicyClass & HttpPolicyClass::operator=(const HttpPolicyClass & other) { - if (this != &other) - { - mConnectionLimit = other.mConnectionLimit; - mPerHostConnectionLimit = other.mPerHostConnectionLimit; - mPipelining = other.mPipelining; - mThrottleRate = other.mThrottleRate; - } - return *this; + if (this != &other) + { + mConnectionLimit = other.mConnectionLimit; + mPerHostConnectionLimit = other.mPerHostConnectionLimit; + mPipelining = other.mPipelining; + mThrottleRate = other.mThrottleRate; + } + return *this; } HttpPolicyClass::HttpPolicyClass(const HttpPolicyClass & other) - : mConnectionLimit(other.mConnectionLimit), - mPerHostConnectionLimit(other.mPerHostConnectionLimit), - mPipelining(other.mPipelining), - mThrottleRate(other.mThrottleRate) + : mConnectionLimit(other.mConnectionLimit), + mPerHostConnectionLimit(other.mPerHostConnectionLimit), + mPipelining(other.mPipelining), + mThrottleRate(other.mThrottleRate) {} HttpStatus HttpPolicyClass::set(HttpRequest::EPolicyOption opt, long value) { - switch (opt) - { - case HttpRequest::PO_CONNECTION_LIMIT: - mConnectionLimit = llclamp(value, long(HTTP_CONNECTION_LIMIT_MIN), long(HTTP_CONNECTION_LIMIT_MAX)); - break; + switch (opt) + { + case HttpRequest::PO_CONNECTION_LIMIT: + mConnectionLimit = llclamp(value, long(HTTP_CONNECTION_LIMIT_MIN), long(HTTP_CONNECTION_LIMIT_MAX)); + break; - case HttpRequest::PO_PER_HOST_CONNECTION_LIMIT: - mPerHostConnectionLimit = llclamp(value, long(HTTP_CONNECTION_LIMIT_MIN), mConnectionLimit); - break; + case HttpRequest::PO_PER_HOST_CONNECTION_LIMIT: + mPerHostConnectionLimit = llclamp(value, long(HTTP_CONNECTION_LIMIT_MIN), mConnectionLimit); + break; - case HttpRequest::PO_PIPELINING_DEPTH: - mPipelining = llclamp(value, 0L, HTTP_PIPELINING_MAX); - break; + case HttpRequest::PO_PIPELINING_DEPTH: + mPipelining = llclamp(value, 0L, HTTP_PIPELINING_MAX); + break; - case HttpRequest::PO_THROTTLE_RATE: - mThrottleRate = llclamp(value, 0L, 1000000L); - break; + case HttpRequest::PO_THROTTLE_RATE: + mThrottleRate = llclamp(value, 0L, 1000000L); + break; - default: - return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); - } + default: + return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); + } - return HttpStatus(); + return HttpStatus(); } HttpStatus HttpPolicyClass::get(HttpRequest::EPolicyOption opt, long * value) const { - switch (opt) - { - case HttpRequest::PO_CONNECTION_LIMIT: - *value = mConnectionLimit; - break; + switch (opt) + { + case HttpRequest::PO_CONNECTION_LIMIT: + *value = mConnectionLimit; + break; - case HttpRequest::PO_PER_HOST_CONNECTION_LIMIT: - *value = mPerHostConnectionLimit; - break; + case HttpRequest::PO_PER_HOST_CONNECTION_LIMIT: + *value = mPerHostConnectionLimit; + break; - case HttpRequest::PO_PIPELINING_DEPTH: - *value = mPipelining; - break; + case HttpRequest::PO_PIPELINING_DEPTH: + *value = mPipelining; + break; - case HttpRequest::PO_THROTTLE_RATE: - *value = mThrottleRate; - break; + case HttpRequest::PO_THROTTLE_RATE: + *value = mThrottleRate; + break; - default: - return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); - } + default: + return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); + } - return HttpStatus(); + return HttpStatus(); } diff --git a/indra/llcorehttp/_httppolicyclass.h b/indra/llcorehttp/_httppolicyclass.h index 38f1194ded..32bcad4f9c 100644 --- a/indra/llcorehttp/_httppolicyclass.h +++ b/indra/llcorehttp/_httppolicyclass.h @@ -24,8 +24,8 @@ * $/LicenseInfo$ */ -#ifndef _LLCORE_HTTP_POLICY_CLASS_H_ -#define _LLCORE_HTTP_POLICY_CLASS_H_ +#ifndef _LLCORE_HTTP_POLICY_CLASS_H_ +#define _LLCORE_HTTP_POLICY_CLASS_H_ #include "httprequest.h" @@ -49,21 +49,21 @@ namespace LLCore class HttpPolicyClass { public: - HttpPolicyClass(); - ~HttpPolicyClass(); + HttpPolicyClass(); + ~HttpPolicyClass(); - HttpPolicyClass & operator=(const HttpPolicyClass &); - HttpPolicyClass(const HttpPolicyClass &); // Not defined + HttpPolicyClass & operator=(const HttpPolicyClass &); + HttpPolicyClass(const HttpPolicyClass &); // Not defined public: - HttpStatus set(HttpRequest::EPolicyOption opt, long value); - HttpStatus get(HttpRequest::EPolicyOption opt, long * value) const; - + HttpStatus set(HttpRequest::EPolicyOption opt, long value); + HttpStatus get(HttpRequest::EPolicyOption opt, long * value) const; + public: - long mConnectionLimit; - long mPerHostConnectionLimit; - long mPipelining; - long mThrottleRate; + long mConnectionLimit; + long mPerHostConnectionLimit; + long mPipelining; + long mThrottleRate; }; // end class HttpPolicyClass } // end namespace LLCore diff --git a/indra/llcorehttp/_httppolicyglobal.cpp b/indra/llcorehttp/_httppolicyglobal.cpp index 8da6cba6d0..431df6ba64 100644 --- a/indra/llcorehttp/_httppolicyglobal.cpp +++ b/indra/llcorehttp/_httppolicyglobal.cpp @@ -34,9 +34,9 @@ namespace LLCore HttpPolicyGlobal::HttpPolicyGlobal() - : mConnectionLimit(HTTP_CONNECTION_LIMIT_DEFAULT), - mTrace(HTTP_TRACE_OFF), - mUseLLProxy(0) + : mConnectionLimit(HTTP_CONNECTION_LIMIT_DEFAULT), + mTrace(HTTP_TRACE_OFF), + mUseLLProxy(0) {} @@ -46,145 +46,145 @@ HttpPolicyGlobal::~HttpPolicyGlobal() HttpPolicyGlobal & HttpPolicyGlobal::operator=(const HttpPolicyGlobal & other) { - if (this != &other) - { - mConnectionLimit = other.mConnectionLimit; - mCAPath = other.mCAPath; - mCAFile = other.mCAFile; - mHttpProxy = other.mHttpProxy; - mTrace = other.mTrace; - mUseLLProxy = other.mUseLLProxy; - } - return *this; + if (this != &other) + { + mConnectionLimit = other.mConnectionLimit; + mCAPath = other.mCAPath; + mCAFile = other.mCAFile; + mHttpProxy = other.mHttpProxy; + mTrace = other.mTrace; + mUseLLProxy = other.mUseLLProxy; + } + return *this; } HttpStatus HttpPolicyGlobal::set(HttpRequest::EPolicyOption opt, long value) { - switch (opt) - { - case HttpRequest::PO_CONNECTION_LIMIT: - mConnectionLimit = llclamp(value, long(HTTP_CONNECTION_LIMIT_MIN), long(HTTP_CONNECTION_LIMIT_MAX)); - break; + switch (opt) + { + case HttpRequest::PO_CONNECTION_LIMIT: + mConnectionLimit = llclamp(value, long(HTTP_CONNECTION_LIMIT_MIN), long(HTTP_CONNECTION_LIMIT_MAX)); + break; - case HttpRequest::PO_TRACE: - mTrace = llclamp(value, long(HTTP_TRACE_MIN), long(HTTP_TRACE_MAX)); - break; + case HttpRequest::PO_TRACE: + mTrace = llclamp(value, long(HTTP_TRACE_MIN), long(HTTP_TRACE_MAX)); + break; - case HttpRequest::PO_LLPROXY: - mUseLLProxy = llclamp(value, 0L, 1L); - break; + case HttpRequest::PO_LLPROXY: + mUseLLProxy = llclamp(value, 0L, 1L); + break; - default: - return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); - } + default: + return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); + } - return HttpStatus(); + return HttpStatus(); } HttpStatus HttpPolicyGlobal::set(HttpRequest::EPolicyOption opt, const std::string & value) { - switch (opt) - { - case HttpRequest::PO_CA_PATH: + switch (opt) + { + case HttpRequest::PO_CA_PATH: LL_DEBUGS("CoreHttp") << "Setting global CA Path to " << value << LL_ENDL; - mCAPath = value; - break; + mCAPath = value; + break; - case HttpRequest::PO_CA_FILE: + case HttpRequest::PO_CA_FILE: LL_DEBUGS("CoreHttp") << "Setting global CA File to " << value << LL_ENDL; - mCAFile = value; - break; + mCAFile = value; + break; - case HttpRequest::PO_HTTP_PROXY: + case HttpRequest::PO_HTTP_PROXY: LL_DEBUGS("CoreHttp") << "Setting global Proxy to " << value << LL_ENDL; - mHttpProxy = value; - break; - - default: - return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); - } - - return HttpStatus(); + mHttpProxy = value; + break; + + default: + return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); + } + + return HttpStatus(); } HttpStatus HttpPolicyGlobal::set(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback_t value) { - switch (opt) - { - case HttpRequest::PO_SSL_VERIFY_CALLBACK: - mSslCtxCallback = value; - break; + switch (opt) + { + case HttpRequest::PO_SSL_VERIFY_CALLBACK: + mSslCtxCallback = value; + break; - default: - return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); - } + default: + return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); + } - return HttpStatus(); + return HttpStatus(); } HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, long * value) const { - switch (opt) - { - case HttpRequest::PO_CONNECTION_LIMIT: - *value = mConnectionLimit; - break; + switch (opt) + { + case HttpRequest::PO_CONNECTION_LIMIT: + *value = mConnectionLimit; + break; - case HttpRequest::PO_TRACE: - *value = mTrace; - break; + case HttpRequest::PO_TRACE: + *value = mTrace; + break; - case HttpRequest::PO_LLPROXY: - *value = mUseLLProxy; - break; + case HttpRequest::PO_LLPROXY: + *value = mUseLLProxy; + break; - default: - return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); - } + default: + return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); + } - return HttpStatus(); + return HttpStatus(); } HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, std::string * value) const { - switch (opt) - { - case HttpRequest::PO_CA_PATH: - *value = mCAPath; - break; - - case HttpRequest::PO_CA_FILE: - *value = mCAFile; - break; - - case HttpRequest::PO_HTTP_PROXY: - *value = mHttpProxy; - break; - - default: - return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); - } - - return HttpStatus(); + switch (opt) + { + case HttpRequest::PO_CA_PATH: + *value = mCAPath; + break; + + case HttpRequest::PO_CA_FILE: + *value = mCAFile; + break; + + case HttpRequest::PO_HTTP_PROXY: + *value = mHttpProxy; + break; + + default: + return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); + } + + return HttpStatus(); } HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback_t * value) const { - switch (opt) - { - case HttpRequest::PO_SSL_VERIFY_CALLBACK: - *value = mSslCtxCallback; - break; + switch (opt) + { + case HttpRequest::PO_SSL_VERIFY_CALLBACK: + *value = mSslCtxCallback; + break; - default: - return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); - } + default: + return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); + } - return HttpStatus(); + return HttpStatus(); } } // end namespace LLCore diff --git a/indra/llcorehttp/_httppolicyglobal.h b/indra/llcorehttp/_httppolicyglobal.h index e02da4386a..d9114d167f 100644 --- a/indra/llcorehttp/_httppolicyglobal.h +++ b/indra/llcorehttp/_httppolicyglobal.h @@ -24,8 +24,8 @@ * $/LicenseInfo$ */ -#ifndef _LLCORE_HTTP_POLICY_GLOBAL_H_ -#define _LLCORE_HTTP_POLICY_GLOBAL_H_ +#ifndef _LLCORE_HTTP_POLICY_GLOBAL_H_ +#define _LLCORE_HTTP_POLICY_GLOBAL_H_ #include "httprequest.h" @@ -49,30 +49,30 @@ namespace LLCore class HttpPolicyGlobal { public: - HttpPolicyGlobal(); - ~HttpPolicyGlobal(); + HttpPolicyGlobal(); + ~HttpPolicyGlobal(); + + HttpPolicyGlobal & operator=(const HttpPolicyGlobal &); - HttpPolicyGlobal & operator=(const HttpPolicyGlobal &); - private: - HttpPolicyGlobal(const HttpPolicyGlobal &); // Not defined + HttpPolicyGlobal(const HttpPolicyGlobal &); // Not defined 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; - + 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; - std::string mCAPath; - std::string mCAFile; - std::string mHttpProxy; - long mTrace; - long mUseLLProxy; - HttpRequest::policyCallback_t mSslCtxCallback; + long mConnectionLimit; + std::string mCAPath; + std::string mCAFile; + 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 7418988ec1..0bc0723511 100644 --- a/indra/llcorehttp/_httpreadyqueue.h +++ b/indra/llcorehttp/_httpreadyqueue.h @@ -24,8 +24,8 @@ * $/LicenseInfo$ */ -#ifndef _LLCORE_HTTP_READY_QUEUE_H_ -#define _LLCORE_HTTP_READY_QUEUE_H_ +#ifndef _LLCORE_HTTP_READY_QUEUE_H_ +#define _LLCORE_HTTP_READY_QUEUE_H_ #include <queue> @@ -61,64 +61,64 @@ typedef std::deque<HttpOpRequest::ptr_t> HttpReadyQueueBase; #else typedef std::priority_queue<HttpOpRequest::ptr_t, - std::deque<HttpOpRequest::ptr_t>, - LLCore::HttpOpRequestCompare> HttpReadyQueueBase; + std::deque<HttpOpRequest::ptr_t>, + LLCore::HttpOpRequestCompare> HttpReadyQueueBase; #endif // LLCORE_HTTP_READY_QUEUE_IGNORES_PRIORITY class HttpReadyQueue : public HttpReadyQueueBase { public: - HttpReadyQueue() - : HttpReadyQueueBase() - {} - - ~HttpReadyQueue() - {} - + HttpReadyQueue() + : HttpReadyQueueBase() + {} + + ~HttpReadyQueue() + {} + protected: - HttpReadyQueue(const HttpReadyQueue &); // Not defined - void operator=(const HttpReadyQueue &); // Not defined + HttpReadyQueue(const HttpReadyQueue &); // Not defined + void operator=(const HttpReadyQueue &); // Not defined public: #if LLCORE_HTTP_READY_QUEUE_IGNORES_PRIORITY - // Types and methods needed to make a std::deque look - // more like a std::priority_queue, at least for our - // purposes. - typedef HttpReadyQueueBase container_type; - - const_reference top() const - { - return front(); - } - - void pop() - { - pop_front(); - } - - void push(const value_type & v) - { - push_back(v); - } - + // Types and methods needed to make a std::deque look + // more like a std::priority_queue, at least for our + // purposes. + typedef HttpReadyQueueBase container_type; + + const_reference top() const + { + return front(); + } + + void pop() + { + pop_front(); + } + + void push(const value_type & v) + { + push_back(v); + } + #endif // LLCORE_HTTP_READY_QUEUE_IGNORES_PRIORITY - - const container_type & get_container() const - { - return *this; - } - - container_type & get_container() - { - return *this; - } - + + const container_type & get_container() const + { + return *this; + } + + container_type & get_container() + { + return *this; + } + }; // end class HttpReadyQueue } // end namespace LLCore -#endif // _LLCORE_HTTP_READY_QUEUE_H_ +#endif // _LLCORE_HTTP_READY_QUEUE_H_ diff --git a/indra/llcorehttp/_httpreplyqueue.cpp b/indra/llcorehttp/_httpreplyqueue.cpp index 229bfdbe07..6124bb6186 100644 --- a/indra/llcorehttp/_httpreplyqueue.cpp +++ b/indra/llcorehttp/_httpreplyqueue.cpp @@ -51,46 +51,46 @@ HttpReplyQueue::~HttpReplyQueue() void HttpReplyQueue::addOp(const HttpReplyQueue::opPtr_t &op) { - { - HttpScopedLock lock(mQueueMutex); + { + HttpScopedLock lock(mQueueMutex); - mQueue.push_back(op); - } + mQueue.push_back(op); + } } HttpReplyQueue::opPtr_t HttpReplyQueue::fetchOp() { - HttpOperation::ptr_t result; + HttpOperation::ptr_t result; - { - HttpScopedLock lock(mQueueMutex); + { + HttpScopedLock lock(mQueueMutex); - if (mQueue.empty()) + if (mQueue.empty()) return opPtr_t(); - result = mQueue.front(); - mQueue.erase(mQueue.begin()); - } + result = mQueue.front(); + mQueue.erase(mQueue.begin()); + } - // Caller also acquires the reference count - return result; + // Caller also acquires the reference count + return result; } void HttpReplyQueue::fetchAll(OpContainer & ops) { - // Not valid putting something back on the queue... - llassert_always(ops.empty()); + // Not valid putting something back on the queue... + llassert_always(ops.empty()); - { - HttpScopedLock lock(mQueueMutex); + { + HttpScopedLock lock(mQueueMutex); - if (! mQueue.empty()) - { - mQueue.swap(ops); - } - } + if (! mQueue.empty()) + { + mQueue.swap(ops); + } + } } diff --git a/indra/llcorehttp/_httpreplyqueue.h b/indra/llcorehttp/_httpreplyqueue.h index 2de26249ef..d8847fafb5 100644 --- a/indra/llcorehttp/_httpreplyqueue.h +++ b/indra/llcorehttp/_httpreplyqueue.h @@ -24,8 +24,8 @@ * $/LicenseInfo$ */ -#ifndef _LLCORE_HTTP_REPLY_QUEUE_H_ -#define _LLCORE_HTTP_REPLY_QUEUE_H_ +#ifndef _LLCORE_HTTP_REPLY_QUEUE_H_ +#define _LLCORE_HTTP_REPLY_QUEUE_H_ #include "_refcounted.h" @@ -66,42 +66,42 @@ public: typedef std::shared_ptr<HttpOperation> opPtr_t; typedef std::shared_ptr<HttpReplyQueue> ptr_t; - HttpReplyQueue(); - virtual ~HttpReplyQueue(); + HttpReplyQueue(); + virtual ~HttpReplyQueue(); public: typedef std::vector< opPtr_t > OpContainer; - /// Insert an object at the back of the reply queue. - /// - /// Library also takes possession of one reference count to pass - /// through the queue. - /// - /// Threading: callable by any thread. + /// Insert an object at the back of the reply queue. + /// + /// Library also takes possession of one reference count to pass + /// through the queue. + /// + /// Threading: callable by any thread. void addOp(const opPtr_t &op); - /// Fetch an operation from the head of the queue. Returns - /// NULL if none exists. - /// - /// Caller acquires reference count on returned operation. - /// - /// Threading: callable by any thread. + /// Fetch an operation from the head of the queue. Returns + /// NULL if none exists. + /// + /// Caller acquires reference count on returned operation. + /// + /// Threading: callable by any thread. opPtr_t fetchOp(); - /// Caller acquires reference count on each returned operation - /// - /// Threading: callable by any thread. - void fetchAll(OpContainer & ops); - + /// Caller acquires reference count on each returned operation + /// + /// Threading: callable by any thread. + void fetchAll(OpContainer & ops); + protected: - OpContainer mQueue; - LLCoreInt::HttpMutex mQueueMutex; - + OpContainer mQueue; + LLCoreInt::HttpMutex mQueueMutex; + }; // end class HttpReplyQueue } // end namespace LLCore -#endif // _LLCORE_HTTP_REPLY_QUEUE_H_ +#endif // _LLCORE_HTTP_REPLY_QUEUE_H_ diff --git a/indra/llcorehttp/_httprequestqueue.cpp b/indra/llcorehttp/_httprequestqueue.cpp index ad72bdcce6..df89fb85ec 100644 --- a/indra/llcorehttp/_httprequestqueue.cpp +++ b/indra/llcorehttp/_httprequestqueue.cpp @@ -1,6 +1,6 @@ /** * @file _httprequestqueue.cpp - * @brief + * @brief * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Second Life Viewer Source Code @@ -39,8 +39,8 @@ HttpRequestQueue * HttpRequestQueue::sInstance(NULL); HttpRequestQueue::HttpRequestQueue() - : RefCounted(true), - mQueueStopped(false) + : RefCounted(true), + mQueueStopped(false) { } @@ -53,99 +53,99 @@ HttpRequestQueue::~HttpRequestQueue() void HttpRequestQueue::init() { - llassert_always(! sInstance); - sInstance = new HttpRequestQueue(); + llassert_always(! sInstance); + sInstance = new HttpRequestQueue(); } void HttpRequestQueue::term() { - if (sInstance) - { - sInstance->release(); - sInstance = NULL; - } + if (sInstance) + { + sInstance->release(); + sInstance = NULL; + } } HttpStatus HttpRequestQueue::addOp(const HttpRequestQueue::opPtr_t &op) { - bool wake(false); - { - HttpScopedLock lock(mQueueMutex); - - if (mQueueStopped) - { - // Return op and error to caller - return HttpStatus(HttpStatus::LLCORE, HE_SHUTTING_DOWN); - } - wake = mQueue.empty(); - mQueue.push_back(op); - } - if (wake) - { - mQueueCV.notify_all(); - } - return HttpStatus(); + bool wake(false); + { + HttpScopedLock lock(mQueueMutex); + + if (mQueueStopped) + { + // Return op and error to caller + return HttpStatus(HttpStatus::LLCORE, HE_SHUTTING_DOWN); + } + wake = mQueue.empty(); + mQueue.push_back(op); + } + if (wake) + { + mQueueCV.notify_all(); + } + return HttpStatus(); } HttpRequestQueue::opPtr_t HttpRequestQueue::fetchOp(bool wait) { - HttpOperation::ptr_t result; + HttpOperation::ptr_t result; - { - HttpScopedLock lock(mQueueMutex); + { + HttpScopedLock lock(mQueueMutex); - while (mQueue.empty()) - { - if (! wait || mQueueStopped) + while (mQueue.empty()) + { + if (! wait || mQueueStopped) return HttpOperation::ptr_t(); - mQueueCV.wait(lock); - } + mQueueCV.wait(lock); + } - result = mQueue.front(); - mQueue.erase(mQueue.begin()); - } + result = mQueue.front(); + mQueue.erase(mQueue.begin()); + } - // Caller also acquires the reference count - return result; + // Caller also acquires the reference count + return result; } void HttpRequestQueue::fetchAll(bool wait, OpContainer & ops) { - // Not valid putting something back on the queue... - llassert_always(ops.empty()); + // Not valid putting something back on the queue... + llassert_always(ops.empty()); - { - HttpScopedLock lock(mQueueMutex); + { + HttpScopedLock lock(mQueueMutex); - while (mQueue.empty()) - { - if (! wait || mQueueStopped) - return; - mQueueCV.wait(lock); - } + while (mQueue.empty()) + { + if (! wait || mQueueStopped) + return; + mQueueCV.wait(lock); + } - mQueue.swap(ops); - } + mQueue.swap(ops); + } - // Caller also acquires the reference counts on each op. - return; + // Caller also acquires the reference counts on each op. + return; } void HttpRequestQueue::wakeAll() { - mQueueCV.notify_all(); + mQueueCV.notify_all(); } bool HttpRequestQueue::stopQueue() { - { - HttpScopedLock lock(mQueueMutex); + { + HttpScopedLock lock(mQueueMutex); if (!mQueueStopped) { @@ -155,7 +155,7 @@ bool HttpRequestQueue::stopQueue() } wakeAll(); return false; - } + } } diff --git a/indra/llcorehttp/_httprequestqueue.h b/indra/llcorehttp/_httprequestqueue.h index 52369df174..0823126f78 100644 --- a/indra/llcorehttp/_httprequestqueue.h +++ b/indra/llcorehttp/_httprequestqueue.h @@ -24,8 +24,8 @@ * $/LicenseInfo$ */ -#ifndef _LLCORE_HTTP_REQUEST_QUEUE_H_ -#define _LLCORE_HTTP_REQUEST_QUEUE_H_ +#ifndef _LLCORE_HTTP_REQUEST_QUEUE_H_ +#define _LLCORE_HTTP_REQUEST_QUEUE_H_ #include <vector> @@ -50,94 +50,94 @@ class HttpOperation; class HttpRequestQueue : public LLCoreInt::RefCounted { protected: - /// Caller acquires a Refcount on construction - HttpRequestQueue(); + /// Caller acquires a Refcount on construction + HttpRequestQueue(); protected: - virtual ~HttpRequestQueue(); // Use release() + virtual ~HttpRequestQueue(); // Use release() private: - HttpRequestQueue(const HttpRequestQueue &); // Not defined - void operator=(const HttpRequestQueue &); // Not defined + HttpRequestQueue(const HttpRequestQueue &); // Not defined + void operator=(const HttpRequestQueue &); // Not defined public: typedef std::shared_ptr<HttpOperation> opPtr_t; - static void init(); - static void term(); - - /// Threading: callable by any thread once inited. - inline static HttpRequestQueue * instanceOf() - { - return sInstance; - } - + static void init(); + static void term(); + + /// Threading: callable by any thread once inited. + inline static HttpRequestQueue * instanceOf() + { + return sInstance; + } + public: typedef std::vector<opPtr_t> OpContainer; - /// Insert an object at the back of the request queue. - /// - /// Caller must provide one refcount to the queue which takes - /// possession of the count on success. - /// - /// @return Standard status. On failure, caller - /// must dispose of the operation with - /// an explicit release() call. - /// - /// Threading: callable by any thread. + /// Insert an object at the back of the request queue. + /// + /// Caller must provide one refcount to the queue which takes + /// possession of the count on success. + /// + /// @return Standard status. On failure, caller + /// must dispose of the operation with + /// an explicit release() call. + /// + /// Threading: callable by any thread. 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 - /// immediately and a NULL pointer is returned. If true, - /// caller will sleep until explicitly woken. Wakeups - /// can be spurious and callers must expect NULL pointers - /// even if waiting is indicated. - /// - /// Caller acquires reference count any returned operation - /// - /// Threading: callable by any thread. + /// Return the operation on the front of the queue. If + /// the queue is empty and @wait is false, call returns + /// immediately and a NULL pointer is returned. If true, + /// caller will sleep until explicitly woken. Wakeups + /// can be spurious and callers must expect NULL pointers + /// even if waiting is indicated. + /// + /// Caller acquires reference count any returned operation + /// + /// Threading: callable by any thread. 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 - /// current contents. Handling of the @wait argument is - /// identical to @fetchOp. - /// - /// Caller acquires reference count on each returned operation - /// - /// Threading: callable by any thread. - void fetchAll(bool wait, OpContainer & ops); - - /// Wake any sleeping threads. Normal queuing operations - /// won't require this but it may be necessary for termination - /// requests. - /// - /// Threading: callable by any thread. - void wakeAll(); - - /// Disallow further request queuing. Callers to @addOp will - /// get a failure status (LLCORE, HE_SHUTTING_DOWN). Callers - /// to @fetchAll or @fetchOp will get requests that are on the - /// queue but the calls will no longer wait. Instead they'll - /// return immediately. Also wakes up all sleepers to send - /// them on their way. - /// - /// Threading: callable by any thread. - bool stopQueue(); - + /// Return all queued requests to caller. The @ops argument + /// should be empty when called and will be swap()'d with + /// current contents. Handling of the @wait argument is + /// identical to @fetchOp. + /// + /// Caller acquires reference count on each returned operation + /// + /// Threading: callable by any thread. + void fetchAll(bool wait, OpContainer & ops); + + /// Wake any sleeping threads. Normal queuing operations + /// won't require this but it may be necessary for termination + /// requests. + /// + /// Threading: callable by any thread. + void wakeAll(); + + /// Disallow further request queuing. Callers to @addOp will + /// get a failure status (LLCORE, HE_SHUTTING_DOWN). Callers + /// to @fetchAll or @fetchOp will get requests that are on the + /// queue but the calls will no longer wait. Instead they'll + /// return immediately. Also wakes up all sleepers to send + /// them on their way. + /// + /// Threading: callable by any thread. + bool stopQueue(); + protected: - static HttpRequestQueue * sInstance; - + static HttpRequestQueue * sInstance; + protected: - OpContainer mQueue; - LLCoreInt::HttpMutex mQueueMutex; - LLCoreInt::HttpConditionVariable mQueueCV; - bool mQueueStopped; - + OpContainer mQueue; + LLCoreInt::HttpMutex mQueueMutex; + LLCoreInt::HttpConditionVariable mQueueCV; + bool mQueueStopped; + }; // end class HttpRequestQueue } // end namespace LLCore -#endif // _LLCORE_HTTP_REQUEST_QUEUE_H_ +#endif // _LLCORE_HTTP_REQUEST_QUEUE_H_ diff --git a/indra/llcorehttp/_httpretryqueue.h b/indra/llcorehttp/_httpretryqueue.h index 5d8c529cff..8545368d9e 100644 --- a/indra/llcorehttp/_httpretryqueue.h +++ b/indra/llcorehttp/_httpretryqueue.h @@ -24,8 +24,8 @@ * $/LicenseInfo$ */ -#ifndef _LLCORE_HTTP_RETRY_QUEUE_H_ -#define _LLCORE_HTTP_RETRY_QUEUE_H_ +#ifndef _LLCORE_HTTP_RETRY_QUEUE_H_ +#define _LLCORE_HTTP_RETRY_QUEUE_H_ #include <queue> @@ -49,41 +49,41 @@ namespace LLCore struct HttpOpRetryCompare { - bool operator()(const HttpOpRequest::ptr_t &lhs, const HttpOpRequest::ptr_t &rhs) - { - return lhs->mPolicyRetryAt < rhs->mPolicyRetryAt; - } + bool operator()(const HttpOpRequest::ptr_t &lhs, const HttpOpRequest::ptr_t &rhs) + { + return lhs->mPolicyRetryAt < rhs->mPolicyRetryAt; + } }; - + typedef std::priority_queue<HttpOpRequest::ptr_t, - std::deque<HttpOpRequest::ptr_t>, - LLCore::HttpOpRetryCompare> HttpRetryQueueBase; + std::deque<HttpOpRequest::ptr_t>, + LLCore::HttpOpRetryCompare> HttpRetryQueueBase; class HttpRetryQueue : public HttpRetryQueueBase { public: - HttpRetryQueue() - : HttpRetryQueueBase() - {} - - ~HttpRetryQueue() - {} - + HttpRetryQueue() + : HttpRetryQueueBase() + {} + + ~HttpRetryQueue() + {} + protected: - HttpRetryQueue(const HttpRetryQueue &); // Not defined - void operator=(const HttpRetryQueue &); // Not defined + HttpRetryQueue(const HttpRetryQueue &); // Not defined + void operator=(const HttpRetryQueue &); // Not defined public: - const container_type & get_container() const - { - return c; - } + const container_type & get_container() const + { + return c; + } - container_type & get_container() - { - return c; - } + container_type & get_container() + { + return c; + } }; // end class HttpRetryQueue @@ -91,4 +91,4 @@ public: } // end namespace LLCore -#endif // _LLCORE_HTTP_RETRY_QUEUE_H_ +#endif // _LLCORE_HTTP_RETRY_QUEUE_H_ diff --git a/indra/llcorehttp/_httpservice.cpp b/indra/llcorehttp/_httpservice.cpp index 517076804d..d543512ec4 100644 --- a/indra/llcorehttp/_httpservice.cpp +++ b/indra/llcorehttp/_httpservice.cpp @@ -54,145 +54,145 @@ namespace LLCore const HttpService::OptionDescriptor HttpService::sOptionDesc[] = { // isLong isDynamic isGlobal isClass - { 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 + { 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); HttpService::HttpService() - : mRequestQueue(NULL), - mExitRequested(0U), - mThread(NULL), - mPolicy(NULL), - mTransport(NULL), - mLastPolicy(0) + : mRequestQueue(NULL), + mExitRequested(0U), + mThread(NULL), + mPolicy(NULL), + mTransport(NULL), + mLastPolicy(0) {} HttpService::~HttpService() { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - mExitRequested = 1U; - if (RUNNING == sState) - { - // Trying to kill the service object with a running thread - // is a bit tricky. - if (mRequestQueue) - { + mExitRequested = 1U; + if (RUNNING == sState) + { + // Trying to kill the service object with a running thread + // is a bit tricky. + if (mRequestQueue) + { if (mRequestQueue->stopQueue()) { // Give mRequestQueue a chance to finish ms_sleep(10); } - } - - if (mThread) - { - if (! mThread->timedJoin(250)) - { - // Failed to join, expect problems ahead so do a hard termination. - LL_WARNS(LOG_CORE) << "Destroying HttpService with running thread. Expect problems." << LL_NEWLINE - << "State: " << S32(sState) - << " Last policy: " << U32(mLastPolicy) - << LL_ENDL; - - mThread->cancel(); - } - } - } - - if (mRequestQueue) - { - mRequestQueue->release(); - mRequestQueue = NULL; - } - - delete mTransport; - mTransport = NULL; - - delete mPolicy; - mPolicy = NULL; - - if (mThread) - { - mThread->release(); - mThread = NULL; - } + } + + if (mThread) + { + if (! mThread->timedJoin(250)) + { + // Failed to join, expect problems ahead so do a hard termination. + LL_WARNS(LOG_CORE) << "Destroying HttpService with running thread. Expect problems." << LL_NEWLINE + << "State: " << S32(sState) + << " Last policy: " << U32(mLastPolicy) + << LL_ENDL; + + mThread->cancel(); + } + } + } + + if (mRequestQueue) + { + mRequestQueue->release(); + mRequestQueue = NULL; + } + + delete mTransport; + mTransport = NULL; + + delete mPolicy; + mPolicy = NULL; + + if (mThread) + { + mThread->release(); + mThread = NULL; + } } - + void HttpService::init(HttpRequestQueue * queue) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - llassert_always(! sInstance); - llassert_always(NOT_INITIALIZED == sState); - sInstance = new HttpService(); - - queue->addRef(); - sInstance->mRequestQueue = queue; - sInstance->mPolicy = new HttpPolicy(sInstance); - sInstance->mTransport = new HttpLibcurl(sInstance); - sState = INITIALIZED; + llassert_always(! sInstance); + llassert_always(NOT_INITIALIZED == sState); + sInstance = new HttpService(); + + queue->addRef(); + sInstance->mRequestQueue = queue; + sInstance->mPolicy = new HttpPolicy(sInstance); + sInstance->mTransport = new HttpLibcurl(sInstance); + sState = INITIALIZED; } void HttpService::term() { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - if (sInstance) - { - if (RUNNING == sState && sInstance->mThread) - { - // Unclean termination. Thread appears to be running. We'll - // try to give the worker thread a chance to cancel using the - // exit flag... - sInstance->mExitRequested = 1U; - sInstance->mRequestQueue->stopQueue(); - - // And a little sleep - for (int i(0); i < 10 && RUNNING == sState; ++i) - { - ms_sleep(100); - } - } - - delete sInstance; - sInstance = NULL; - } - sState = NOT_INITIALIZED; + if (sInstance) + { + if (RUNNING == sState && sInstance->mThread) + { + // Unclean termination. Thread appears to be running. We'll + // try to give the worker thread a chance to cancel using the + // exit flag... + sInstance->mExitRequested = 1U; + sInstance->mRequestQueue->stopQueue(); + + // And a little sleep + for (int i(0); i < 10 && RUNNING == sState; ++i) + { + ms_sleep(100); + } + } + + delete sInstance; + sInstance = NULL; + } + sState = NOT_INITIALIZED; } HttpRequest::policy_t HttpService::createPolicyClass() { - mLastPolicy = mPolicy->createPolicyClass(); - return mLastPolicy; + mLastPolicy = mPolicy->createPolicyClass(); + return mLastPolicy; } bool HttpService::isStopped() { - // What is really wanted here is something like: - // - // HttpService * service = instanceOf(); - // return STOPPED == sState && (! service || ! service->mThread || ! service->mThread->joinable()); - // - // But boost::thread is not giving me a consistent story on joinability - // of a thread after it returns. Debug and non-debug builds are showing - // different behavior on Linux/Etch so we do a weaker test that may - // not be globally correct (i.e. thread *is* stopping, may not have - // stopped but will very soon): - - return STOPPED == sState; + // What is really wanted here is something like: + // + // HttpService * service = instanceOf(); + // return STOPPED == sState && (! service || ! service->mThread || ! service->mThread->joinable()); + // + // But boost::thread is not giving me a consistent story on joinability + // of a thread after it returns. Debug and non-debug builds are showing + // different behavior on Linux/Etch so we do a weaker test that may + // not be globally correct (i.e. thread *is* stopping, may not have + // stopped but will very soon): + + return STOPPED == sState; } @@ -200,66 +200,66 @@ bool HttpService::isStopped() void HttpService::startThread() { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - llassert_always(! mThread || STOPPED == sState); - llassert_always(INITIALIZED == sState || STOPPED == sState); + llassert_always(! mThread || STOPPED == sState); + llassert_always(INITIALIZED == sState || STOPPED == sState); - if (mThread) - { - mThread->release(); - } + if (mThread) + { + mThread->release(); + } - // Push current policy definitions, enable policy & transport components - mPolicy->start(); - mTransport->start(mLastPolicy + 1); + // Push current policy definitions, enable policy & transport components + mPolicy->start(); + mTransport->start(mLastPolicy + 1); - mThread = new LLCoreInt::HttpThread(boost::bind(&HttpService::threadRun, this, _1)); - sState = RUNNING; + mThread = new LLCoreInt::HttpThread(boost::bind(&HttpService::threadRun, this, _1)); + sState = RUNNING; } /// Threading: callable by worker thread. void HttpService::stopRequested() { - mExitRequested = 1U; + mExitRequested = 1U; } /// Try to find the given request handle on any of the request /// queues and cancel the operation. /// -/// @return True if the request was canceled. +/// @return True if the request was canceled. /// /// Threading: callable by worker thread. bool HttpService::cancel(HttpHandle handle) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - bool canceled(false); + bool canceled(false); + + // Request can't be on request queue so skip that. - // Request can't be on request queue so skip that. + // Check the policy component's queues first + canceled = mPolicy->cancel(handle); - // Check the policy component's queues first - canceled = mPolicy->cancel(handle); + if (! canceled) + { + // If that didn't work, check transport's. + canceled = mTransport->cancel(handle); + } - if (! canceled) - { - // If that didn't work, check transport's. - canceled = mTransport->cancel(handle); - } - - return canceled; + return canceled; } - + /// Threading: callable by worker thread. void HttpService::shutdown() { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - // Disallow future enqueue of requests - mRequestQueue->stopQueue(); + // Disallow future enqueue of requests + mRequestQueue->stopQueue(); - // Cancel requests already on the request queue - HttpRequestQueue::OpContainer ops; - mRequestQueue->fetchAll(false, ops); + // Cancel requests already on the request queue + HttpRequestQueue::OpContainer ops; + mRequestQueue->fetchAll(false, ops); for (HttpRequestQueue::OpContainer::iterator it = ops.begin(); it != ops.end(); ++it) @@ -268,11 +268,11 @@ void HttpService::shutdown() } ops.clear(); - // Shutdown transport canceling requests, freeing resources - mTransport->shutdown(); + // Shutdown transport canceling requests, freeing resources + mTransport->shutdown(); - // And now policy - mPolicy->shutdown(); + // And now policy + mPolicy->shutdown(); } @@ -285,31 +285,31 @@ void HttpService::threadRun(LLCoreInt::HttpThread * thread) { LL_PROFILER_SET_THREAD_NAME("HttpService"); - boost::this_thread::disable_interruption di; + boost::this_thread::disable_interruption di; + + LLThread::registerThreadID(); - LLThread::registerThreadID(); - - ELoopSpeed loop(REQUEST_SLEEP); - while (! mExitRequested) - { + ELoopSpeed loop(REQUEST_SLEEP); + while (! mExitRequested) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; try { - loop = processRequestQueue(loop); - - // Process ready queue issuing new requests as needed - ELoopSpeed new_loop = mPolicy->processReadyQueue(); - loop = (std::min)(loop, new_loop); - - // Give libcurl some cycles - new_loop = mTransport->processTransport(); - loop = (std::min)(loop, new_loop); - - // Determine whether to spin, sleep briefly or sleep for next request - if (REQUEST_SLEEP != loop) - { - ms_sleep(HTTP_SERVICE_LOOP_SLEEP_NORMAL_MS); - } + loop = processRequestQueue(loop); + + // Process ready queue issuing new requests as needed + ELoopSpeed new_loop = mPolicy->processReadyQueue(); + loop = (std::min)(loop, new_loop); + + // Give libcurl some cycles + new_loop = mTransport->processTransport(); + loop = (std::min)(loop, new_loop); + + // Determine whether to spin, sleep briefly or sleep for next request + if (REQUEST_SLEEP != loop) + { + ms_sleep(HTTP_SERVICE_LOOP_SLEEP_NORMAL_MS); + } } catch (const LLContinueError&) { @@ -331,250 +331,250 @@ void HttpService::threadRun(LLCoreInt::HttpThread * thread) } } - shutdown(); - sState = STOPPED; + shutdown(); + sState = STOPPED; } HttpService::ELoopSpeed HttpService::processRequestQueue(ELoopSpeed loop) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - HttpRequestQueue::OpContainer ops; - const bool wait_for_req(REQUEST_SLEEP == loop); - - mRequestQueue->fetchAll(wait_for_req, ops); - while (! ops.empty()) - { - HttpOperation::ptr_t op(ops.front()); - ops.erase(ops.begin()); - - // Process operation - if (! mExitRequested) - { - // Setup for subsequent tracing - long tracing(HTTP_TRACE_OFF); - mPolicy->getGlobalOptions().get(HttpRequest::PO_TRACE, &tracing); - op->mTracing = (std::max)(op->mTracing, int(tracing)); - - if (op->mTracing > HTTP_TRACE_OFF) - { - LL_INFOS(LOG_CORE) << "TRACE, FromRequestQueue, Handle: " - << op->getHandle() - << LL_ENDL; - } - - // Stage - op->stageFromRequest(this); - } - - // Done with operation + HttpRequestQueue::OpContainer ops; + const bool wait_for_req(REQUEST_SLEEP == loop); + + mRequestQueue->fetchAll(wait_for_req, ops); + while (! ops.empty()) + { + HttpOperation::ptr_t op(ops.front()); + ops.erase(ops.begin()); + + // Process operation + if (! mExitRequested) + { + // Setup for subsequent tracing + long tracing(HTTP_TRACE_OFF); + mPolicy->getGlobalOptions().get(HttpRequest::PO_TRACE, &tracing); + op->mTracing = (std::max)(op->mTracing, int(tracing)); + + if (op->mTracing > HTTP_TRACE_OFF) + { + LL_INFOS(LOG_CORE) << "TRACE, FromRequestQueue, Handle: " + << op->getHandle() + << LL_ENDL; + } + + // Stage + op->stageFromRequest(this); + } + + // Done with operation op.reset(); - } + } - // Queue emptied, allow polling loop to sleep - return REQUEST_SLEEP; + // Queue emptied, allow polling loop to sleep + return REQUEST_SLEEP; } HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass, - long * ret_value) + long * ret_value) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range - || opt >= HttpRequest::PO_LAST // ditto - || (! sOptionDesc[opt].mIsLong) // datatype is long - || (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 HttpStatus(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG); - } - - HttpStatus status; - if (pclass == HttpRequest::GLOBAL_POLICY_ID) - { - HttpPolicyGlobal & opts(mPolicy->getGlobalOptions()); - - status = opts.get(opt, ret_value); - } - else - { - HttpPolicyClass & opts(mPolicy->getClassOptions(pclass)); - - status = opts.get(opt, ret_value); - } - - return status; + if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range + || opt >= HttpRequest::PO_LAST // ditto + || (! sOptionDesc[opt].mIsLong) // datatype is long + || (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 HttpStatus(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG); + } + + HttpStatus status; + if (pclass == HttpRequest::GLOBAL_POLICY_ID) + { + HttpPolicyGlobal & opts(mPolicy->getGlobalOptions()); + + status = opts.get(opt, ret_value); + } + else + { + HttpPolicyClass & opts(mPolicy->getClassOptions(pclass)); + + status = opts.get(opt, ret_value); + } + + return status; } HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass, - std::string * ret_value) + std::string * ret_value) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - 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 string values - if (pclass == HttpRequest::GLOBAL_POLICY_ID) - { - HttpPolicyGlobal & opts(mPolicy->getGlobalOptions()); - - status = opts.get(opt, ret_value); - } - - return status; + 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 string values + if (pclass == HttpRequest::GLOBAL_POLICY_ID) + { + HttpPolicyGlobal & opts(mPolicy->getGlobalOptions()); + + status = opts.get(opt, ret_value); + } + + return status; } HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass, - HttpRequest::policyCallback_t * ret_value) + HttpRequest::policyCallback_t * ret_value) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - 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 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) + long value, long * ret_value) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - 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 long - || (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; - } - - 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); - } - } - else - { - HttpPolicyClass & opts(mPolicy->getClassOptions(pclass)); - - status = opts.set(opt, value); - if (status) - { - mTransport->policyUpdated(pclass); - if (ret_value) - { - status = opts.get(opt, ret_value); - } - } - } - - return status; + 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 long + || (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; + } + + 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); + } + } + else + { + HttpPolicyClass & opts(mPolicy->getClassOptions(pclass)); + + status = opts.set(opt, value); + if (status) + { + mTransport->policyUpdated(pclass); + if (ret_value) + { + status = opts.get(opt, ret_value); + } + } + } + + return status; } HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass, - const std::string & value, std::string * ret_value) + const std::string & value, std::string * ret_value) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - 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; - } - - // String 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; + 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; + } + + // String 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; } HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass, - HttpRequest::policyCallback_t value, HttpRequest::policyCallback_t * ret_value) + HttpRequest::policyCallback_t value, HttpRequest::policyCallback_t * ret_value) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - 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; + 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; } diff --git a/indra/llcorehttp/_httpservice.h b/indra/llcorehttp/_httpservice.h index 551a718f20..13eb034f0e 100644 --- a/indra/llcorehttp/_httpservice.h +++ b/indra/llcorehttp/_httpservice.h @@ -24,8 +24,8 @@ * $/LicenseInfo$ */ -#ifndef _LLCORE_HTTP_SERVICE_H_ -#define _LLCORE_HTTP_SERVICE_H_ +#ifndef _LLCORE_HTTP_SERVICE_H_ +#define _LLCORE_HTTP_SERVICE_H_ #include <vector> @@ -82,151 +82,151 @@ class HttpOpSetGet; class HttpService { protected: - HttpService(); - virtual ~HttpService(); + HttpService(); + virtual ~HttpService(); private: - HttpService(const HttpService &); // Not defined - void operator=(const HttpService &); // Not defined + HttpService(const HttpService &); // Not defined + void operator=(const HttpService &); // Not defined public: - enum EState - { - NOT_INITIALIZED = -1, - INITIALIZED, ///< init() has been called - RUNNING, ///< thread created and running - STOPPED ///< thread has committed to exiting - }; - - // Ordered enumeration of idling strategies available to - // threadRun's loop. Ordered so that std::min on values - // produces the most conservative result of multiple - // requests. - enum ELoopSpeed - { - NORMAL, ///< continuous polling of request, ready, active queues - REQUEST_SLEEP ///< can sleep indefinitely waiting for request queue write - }; - - static void init(HttpRequestQueue *); - static void term(); - - /// Threading: callable by any thread once inited. - inline static HttpService * instanceOf() - { - return sInstance; - } - - /// Return the state of the worker thread. Note that the - /// transition from RUNNING to STOPPED is performed by the - /// worker thread itself. This has two weaknesses: - /// - race where the thread hasn't really stopped but will - /// - data ordering between threads where a non-worker thread - /// may see a stale RUNNING status. - /// - /// This transition is generally of interest only to unit tests - /// and these weaknesses shouldn't be any real burden. - /// - /// Threading: callable by any thread with above exceptions. - static EState getState() - { - return sState; - } - - /// Threading: callable by any thread but uses @see getState() and - /// acquires its weaknesses. - static bool isStopped(); - - /// Threading: callable by init thread *once*. - void startThread(); - - /// Threading: callable by worker thread. - void stopRequested(); - - /// Threading: callable by worker thread. - void shutdown(); - - /// Try to find the given request handle on any of the request - /// queues and cancel the operation. - /// - /// @return True if the request was found and canceled. - /// - /// Threading: callable by worker thread. - bool cancel(HttpHandle handle); - - /// Threading: callable by worker thread. - HttpPolicy & getPolicy() - { - return *mPolicy; - } - - /// Threading: callable by worker thread. - HttpLibcurl & getTransport() - { - return *mTransport; - } - - /// Threading: callable by worker thread. - HttpRequestQueue & getRequestQueue() - { - return *mRequestQueue; - } - - /// Threading: callable by consumer thread. - HttpRequest::policy_t createPolicyClass(); - + enum EState + { + NOT_INITIALIZED = -1, + INITIALIZED, ///< init() has been called + RUNNING, ///< thread created and running + STOPPED ///< thread has committed to exiting + }; + + // Ordered enumeration of idling strategies available to + // threadRun's loop. Ordered so that std::min on values + // produces the most conservative result of multiple + // requests. + enum ELoopSpeed + { + NORMAL, ///< continuous polling of request, ready, active queues + REQUEST_SLEEP ///< can sleep indefinitely waiting for request queue write + }; + + static void init(HttpRequestQueue *); + static void term(); + + /// Threading: callable by any thread once inited. + inline static HttpService * instanceOf() + { + return sInstance; + } + + /// Return the state of the worker thread. Note that the + /// transition from RUNNING to STOPPED is performed by the + /// worker thread itself. This has two weaknesses: + /// - race where the thread hasn't really stopped but will + /// - data ordering between threads where a non-worker thread + /// may see a stale RUNNING status. + /// + /// This transition is generally of interest only to unit tests + /// and these weaknesses shouldn't be any real burden. + /// + /// Threading: callable by any thread with above exceptions. + static EState getState() + { + return sState; + } + + /// Threading: callable by any thread but uses @see getState() and + /// acquires its weaknesses. + static bool isStopped(); + + /// Threading: callable by init thread *once*. + void startThread(); + + /// Threading: callable by worker thread. + void stopRequested(); + + /// Threading: callable by worker thread. + void shutdown(); + + /// Try to find the given request handle on any of the request + /// queues and cancel the operation. + /// + /// @return True if the request was found and canceled. + /// + /// Threading: callable by worker thread. + bool cancel(HttpHandle handle); + + /// Threading: callable by worker thread. + HttpPolicy & getPolicy() + { + return *mPolicy; + } + + /// Threading: callable by worker thread. + HttpLibcurl & getTransport() + { + return *mTransport; + } + + /// Threading: callable by worker thread. + HttpRequestQueue & getRequestQueue() + { + return *mRequestQueue; + } + + /// Threading: callable by consumer thread. + HttpRequest::policy_t createPolicyClass(); + protected: - void threadRun(LLCoreInt::HttpThread * thread); - - ELoopSpeed processRequestQueue(ELoopSpeed loop); + void threadRun(LLCoreInt::HttpThread * thread); + + ELoopSpeed processRequestQueue(ELoopSpeed loop); protected: - friend class HttpOpSetGet; - friend class HttpRequest; - - // Used internally to describe what operations are allowed - // on each policy option. - struct OptionDescriptor - { - bool mIsLong; - 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); + friend class HttpOpSetGet; + friend class HttpRequest; + + // Used internally to describe what operations are allowed + // on each policy option. + struct OptionDescriptor + { + bool mIsLong; + 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; - - // === shared data === - static volatile EState sState; - HttpRequestQueue * mRequestQueue; // Refcounted - LLAtomicU32 mExitRequested; - LLCoreInt::HttpThread * mThread; - - // === working-thread-only data === - HttpPolicy * mPolicy; // Simple pointer, has ownership - HttpLibcurl * mTransport; // Simple pointer, has ownership - - // === main-thread-only data === - HttpRequest::policy_t mLastPolicy; - + static const OptionDescriptor sOptionDesc[HttpRequest::PO_LAST]; + static HttpService * sInstance; + + // === shared data === + static volatile EState sState; + HttpRequestQueue * mRequestQueue; // Refcounted + LLAtomicU32 mExitRequested; + LLCoreInt::HttpThread * mThread; + + // === working-thread-only data === + HttpPolicy * mPolicy; // Simple pointer, has ownership + HttpLibcurl * mTransport; // Simple pointer, has ownership + + // === main-thread-only data === + HttpRequest::policy_t mLastPolicy; + }; // end class HttpService } // end namespace LLCore diff --git a/indra/llcorehttp/_mutex.h b/indra/llcorehttp/_mutex.h index 4be4d016d4..5e0164eb51 100644 --- a/indra/llcorehttp/_mutex.h +++ b/indra/llcorehttp/_mutex.h @@ -1,4 +1,4 @@ -/** +/** * @file _mutex.hpp * @brief mutex type abstraction * @@ -51,5 +51,5 @@ typedef boost::unique_lock<HttpMutex> HttpScopedLock; } -#endif // LLCOREINT_MUTEX_H +#endif // LLCOREINT_MUTEX_H diff --git a/indra/llcorehttp/_refcounted.cpp b/indra/llcorehttp/_refcounted.cpp index e7d0b72741..94b28102f3 100644 --- a/indra/llcorehttp/_refcounted.cpp +++ b/indra/llcorehttp/_refcounted.cpp @@ -1,4 +1,4 @@ -/** +/** * @file _refcounted.cpp * @brief Atomic, thread-safe ref counting and destruction mixin class * @@ -30,11 +30,11 @@ namespace LLCoreInt { -#if ! LL_WINDOWS +#if ! LL_WINDOWS const S32 RefCounted::NOT_REF_COUNTED; -#endif // ! LL_WINDOWS +#endif // ! LL_WINDOWS RefCounted::~RefCounted() {} diff --git a/indra/llcorehttp/_refcounted.h b/indra/llcorehttp/_refcounted.h index 5cc8914395..7470965a7f 100644 --- a/indra/llcorehttp/_refcounted.h +++ b/indra/llcorehttp/_refcounted.h @@ -1,4 +1,4 @@ -/** +/** * @file _refcounted.h * @brief Atomic, thread-safe ref counting and destruction mixin class * @@ -44,81 +44,81 @@ namespace LLCoreInt class RefCounted { private: - RefCounted(); // Not defined - may not be default constructed - void operator=(const RefCounted &); // Not defined - + RefCounted(); // Not defined - may not be default constructed + void operator=(const RefCounted &); // Not defined + public: - explicit RefCounted(bool const implicit) - : mRefCount(implicit) - {} - - // ref-count interface - void addRef() const; - void release() const; - bool isLastRef() const; - S32 getRefCount() const; - void noRef() const; - - static const S32 NOT_REF_COUNTED = -1; - + explicit RefCounted(bool const implicit) + : mRefCount(implicit) + {} + + // ref-count interface + void addRef() const; + void release() const; + bool isLastRef() const; + S32 getRefCount() const; + void noRef() const; + + static const S32 NOT_REF_COUNTED = -1; + protected: - virtual ~RefCounted(); - virtual void destroySelf(); + virtual ~RefCounted(); + virtual void destroySelf(); private: - mutable LLAtomicS32 mRefCount; + mutable LLAtomicS32 mRefCount; }; // end class RefCounted inline void RefCounted::addRef() const { - S32 count(++mRefCount); - llassert_always(count >= 0); + S32 count(++mRefCount); + llassert_always(count >= 0); } inline void RefCounted::release() const { - S32 count(mRefCount); - llassert_always(count != NOT_REF_COUNTED); - llassert_always(count > 0); - count = --mRefCount; - - // clean ourselves up if that was the last reference - if (0 == count) - { - const_cast<RefCounted *>(this)->destroySelf(); - } + S32 count(mRefCount); + llassert_always(count != NOT_REF_COUNTED); + llassert_always(count > 0); + count = --mRefCount; + + // clean ourselves up if that was the last reference + if (0 == count) + { + const_cast<RefCounted *>(this)->destroySelf(); + } } inline bool RefCounted::isLastRef() const { - const S32 count(mRefCount); - llassert_always(count != NOT_REF_COUNTED); - llassert_always(count >= 1); - return (1 == count); + const S32 count(mRefCount); + llassert_always(count != NOT_REF_COUNTED); + llassert_always(count >= 1); + return (1 == count); } inline S32 RefCounted::getRefCount() const { - const S32 result(mRefCount); - return result; + const S32 result(mRefCount); + return result; } inline void RefCounted::noRef() const { - llassert_always(mRefCount <= 1); - mRefCount = NOT_REF_COUNTED; + llassert_always(mRefCount <= 1); + mRefCount = NOT_REF_COUNTED; } inline void RefCounted::destroySelf() { - delete this; + delete this; } /** @@ -131,26 +131,26 @@ inline void RefCounted::destroySelf() template <typename T> struct IntrusivePtr: public boost::intrusive_ptr<T> { - IntrusivePtr(): - boost::intrusive_ptr<T>() - {} - IntrusivePtr(T* p): - boost::intrusive_ptr<T>(p, false) - {} + IntrusivePtr(): + boost::intrusive_ptr<T>() + {} + IntrusivePtr(T* p): + boost::intrusive_ptr<T>(p, false) + {} }; inline void intrusive_ptr_add_ref(RefCounted* p) { - p->addRef(); + p->addRef(); } inline void intrusive_ptr_release(RefCounted* p) { - p->release(); + p->release(); } } // end namespace LLCoreInt -#endif // LLCOREINT__REFCOUNTED_H_ +#endif // LLCOREINT__REFCOUNTED_H_ diff --git a/indra/llcorehttp/_thread.h b/indra/llcorehttp/_thread.h index 22b7750bad..6c0e39cf92 100644 --- a/indra/llcorehttp/_thread.h +++ b/indra/llcorehttp/_thread.h @@ -1,4 +1,4 @@ -/** +/** * @file _thread.h * @brief thread type abstraction * @@ -42,79 +42,79 @@ namespace LLCoreInt class HttpThread : public RefCounted { private: - HttpThread(); // Not defined - void operator=(const HttpThread &); // Not defined + HttpThread(); // Not defined + void operator=(const HttpThread &); // Not defined - void at_exit() - { - // the thread function has exited so we need to release our reference - // to ourself so that we will be automagically cleaned up. - release(); - } + void at_exit() + { + // the thread function has exited so we need to release our reference + // to ourself so that we will be automagically cleaned up. + release(); + } - void run() - { // THREAD CONTEXT + void run() + { // THREAD CONTEXT - // Take out additional reference for the at_exit handler - addRef(); - boost::this_thread::at_thread_exit(boost::bind(&HttpThread::at_exit, this)); + // Take out additional reference for the at_exit handler + addRef(); + boost::this_thread::at_thread_exit(boost::bind(&HttpThread::at_exit, this)); - // run the thread function - mThreadFunc(this); + // run the thread function + mThreadFunc(this); - } // THREAD CONTEXT + } // THREAD CONTEXT protected: - virtual ~HttpThread() - { - delete mThread; - } + virtual ~HttpThread() + { + delete mThread; + } public: - /// Constructs a thread object for concurrent execution but does - /// not start running. Caller receives on refcount on the thread - /// instance. If the thread is started, another will be taken - /// out for the exit handler. - explicit HttpThread(boost::function<void (HttpThread *)> threadFunc) - : RefCounted(true), // implicit reference - mThreadFunc(threadFunc) - { - // this creates a boost thread that will call HttpThread::run on this instance - // and pass it the threadfunc callable... - boost::function<void()> f = boost::bind(&HttpThread::run, this); - - mThread = new boost::thread(f); - } - - inline void join() - { - mThread->join(); - } - - inline bool timedJoin(S32 millis) - { - return mThread->timed_join(boost::posix_time::milliseconds(millis)); - } - - inline bool joinable() const - { - return mThread->joinable(); - } - - // A very hostile method to force a thread to quit - inline void cancel() - { - boost::thread::native_handle_type thread(mThread->native_handle()); -#if LL_WINDOWS - TerminateThread(thread, 0); + /// Constructs a thread object for concurrent execution but does + /// not start running. Caller receives on refcount on the thread + /// instance. If the thread is started, another will be taken + /// out for the exit handler. + explicit HttpThread(boost::function<void (HttpThread *)> threadFunc) + : RefCounted(true), // implicit reference + mThreadFunc(threadFunc) + { + // this creates a boost thread that will call HttpThread::run on this instance + // and pass it the threadfunc callable... + boost::function<void()> f = boost::bind(&HttpThread::run, this); + + mThread = new boost::thread(f); + } + + inline void join() + { + mThread->join(); + } + + inline bool timedJoin(S32 millis) + { + return mThread->timed_join(boost::posix_time::milliseconds(millis)); + } + + inline bool joinable() const + { + return mThread->joinable(); + } + + // A very hostile method to force a thread to quit + inline void cancel() + { + boost::thread::native_handle_type thread(mThread->native_handle()); +#if LL_WINDOWS + TerminateThread(thread, 0); #else - pthread_cancel(thread); + pthread_cancel(thread); #endif - } - + } + private: - boost::function<void(HttpThread *)> mThreadFunc; - boost::thread * mThread; + boost::function<void(HttpThread *)> mThreadFunc; + boost::thread * mThread; }; // end class HttpThread } // end namespace LLCoreInt diff --git a/indra/llcorehttp/bufferarray.cpp b/indra/llcorehttp/bufferarray.cpp index c780c06b4e..50a8d461a7 100644 --- a/indra/llcorehttp/bufferarray.cpp +++ b/indra/llcorehttp/bufferarray.cpp @@ -52,33 +52,33 @@ namespace LLCore class BufferArray::Block { public: - ~Block(); + ~Block(); - void operator delete(void *); - void operator delete(void *, size_t len); + void operator delete(void *); + void operator delete(void *, size_t len); protected: - Block(size_t len); + Block(size_t len); - Block(const Block &); // Not defined - void operator=(const Block &); // Not defined + Block(const Block &); // Not defined + void operator=(const Block &); // Not defined + + // Allocate the block with the additional space for the + // buffered data at the end of the object. + void * operator new(size_t len, size_t addl_len); - // Allocate the block with the additional space for the - // buffered data at the end of the object. - void * operator new(size_t len, size_t addl_len); - public: - // Only public entry to get a block. - static Block * alloc(size_t len); + // Only public entry to get a block. + static Block * alloc(size_t len); public: - size_t mUsed; - size_t mAlloced; + size_t mUsed; + size_t mAlloced; - // *NOTE: Must be last member of the object. We'll - // overallocate as requested via operator new and index - // into the array at will. - char mData[1]; + // *NOTE: Must be last member of the object. We'll + // overallocate as requested via operator new and index + // into the array at will. + char mData[1]; }; @@ -87,61 +87,61 @@ public: // ================================== -#if ! LL_WINDOWS +#if ! LL_WINDOWS const size_t BufferArray::BLOCK_ALLOC_SIZE; -#endif // ! LL_WINDOWS +#endif // ! LL_WINDOWS BufferArray::BufferArray() - : LLCoreInt::RefCounted(true), - mLen(0) + : LLCoreInt::RefCounted(true), + mLen(0) {} BufferArray::~BufferArray() { - for (container_t::iterator it(mBlocks.begin()); - it != mBlocks.end(); - ++it) - { - delete *it; - *it = NULL; - } - mBlocks.clear(); + for (container_t::iterator it(mBlocks.begin()); + it != mBlocks.end(); + ++it) + { + delete *it; + *it = NULL; + } + mBlocks.clear(); } size_t BufferArray::append(const void * src, size_t len) { - const size_t ret(len); - const char * c_src(static_cast<const char *>(src)); - - // First, try to copy into the last block - if (len && ! mBlocks.empty()) - { - Block & last(*mBlocks.back()); - if (last.mUsed < last.mAlloced) - { - // Some will fit... - const size_t copy_len((std::min)(len, (last.mAlloced - last.mUsed))); - - memcpy(&last.mData[last.mUsed], c_src, copy_len); - last.mUsed += copy_len; - llassert_always(last.mUsed <= last.mAlloced); - mLen += copy_len; - c_src += copy_len; - len -= copy_len; - } - } - - // Then get new blocks as needed - while (len) - { - const size_t copy_len((std::min)(len, BLOCK_ALLOC_SIZE)); - - if (mBlocks.size() >= mBlocks.capacity()) - { - mBlocks.reserve(mBlocks.size() + 5); - } + const size_t ret(len); + const char * c_src(static_cast<const char *>(src)); + + // First, try to copy into the last block + if (len && ! mBlocks.empty()) + { + Block & last(*mBlocks.back()); + if (last.mUsed < last.mAlloced) + { + // Some will fit... + const size_t copy_len((std::min)(len, (last.mAlloced - last.mUsed))); + + memcpy(&last.mData[last.mUsed], c_src, copy_len); + last.mUsed += copy_len; + llassert_always(last.mUsed <= last.mAlloced); + mLen += copy_len; + c_src += copy_len; + len -= copy_len; + } + } + + // Then get new blocks as needed + while (len) + { + const size_t copy_len((std::min)(len, BLOCK_ALLOC_SIZE)); + + if (mBlocks.size() >= mBlocks.capacity()) + { + mBlocks.reserve(mBlocks.size() + 5); + } Block * block; try { @@ -158,163 +158,163 @@ size_t BufferArray::append(const void * src, size_t len) break; } memcpy(block->mData, c_src, copy_len); - block->mUsed = copy_len; - llassert_always(block->mUsed <= block->mAlloced); - mBlocks.push_back(block); - mLen += copy_len; - c_src += copy_len; - len -= copy_len; - } - return ret - len; + block->mUsed = copy_len; + llassert_always(block->mUsed <= block->mAlloced); + mBlocks.push_back(block); + mLen += copy_len; + c_src += copy_len; + len -= copy_len; + } + return ret - len; } void * BufferArray::appendBufferAlloc(size_t len) { - // If someone asks for zero-length, we give them a valid pointer. - if (mBlocks.size() >= mBlocks.capacity()) - { - mBlocks.reserve(mBlocks.size() + 5); - } - Block * block = Block::alloc((std::max)(BLOCK_ALLOC_SIZE, len)); - block->mUsed = len; - mBlocks.push_back(block); - mLen += len; - return block->mData; + // If someone asks for zero-length, we give them a valid pointer. + if (mBlocks.size() >= mBlocks.capacity()) + { + mBlocks.reserve(mBlocks.size() + 5); + } + Block * block = Block::alloc((std::max)(BLOCK_ALLOC_SIZE, len)); + block->mUsed = len; + mBlocks.push_back(block); + mLen += len; + return block->mData; } size_t BufferArray::read(size_t pos, void * dst, size_t len) { - char * c_dst(static_cast<char *>(dst)); - - if (pos >= mLen) - return 0; - size_t len_limit(mLen - pos); - len = (std::min)(len, len_limit); - if (0 == len) - return 0; - - size_t result(0), offset(0); - const auto block_limit(mBlocks.size()); - int block_start(findBlock(pos, &offset)); - if (block_start < 0) - return 0; - - do - { - Block & block(*mBlocks[block_start]); - size_t block_limit(block.mUsed - offset); - size_t block_len((std::min)(block_limit, len)); - - memcpy(c_dst, &block.mData[offset], block_len); - result += block_len; - len -= block_len; - c_dst += block_len; - offset = 0; - ++block_start; - } - while (len && block_start < block_limit); - - return result; + char * c_dst(static_cast<char *>(dst)); + + if (pos >= mLen) + return 0; + size_t len_limit(mLen - pos); + len = (std::min)(len, len_limit); + if (0 == len) + return 0; + + size_t result(0), offset(0); + const auto block_limit(mBlocks.size()); + int block_start(findBlock(pos, &offset)); + if (block_start < 0) + return 0; + + do + { + Block & block(*mBlocks[block_start]); + size_t block_limit(block.mUsed - offset); + size_t block_len((std::min)(block_limit, len)); + + memcpy(c_dst, &block.mData[offset], block_len); + result += block_len; + len -= block_len; + c_dst += block_len; + offset = 0; + ++block_start; + } + while (len && block_start < block_limit); + + return result; } size_t BufferArray::write(size_t pos, const void * src, size_t len) { - const char * c_src(static_cast<const char *>(src)); - - if (pos > mLen || 0 == len) - return 0; - - size_t result(0), offset(0); - const auto block_limit(mBlocks.size()); - int block_start(findBlock(pos, &offset)); - - if (block_start >= 0) - { - // Some or all of the write will be on top of - // existing data. - do - { - Block & block(*mBlocks[block_start]); - size_t block_limit(block.mUsed - offset); - size_t block_len((std::min)(block_limit, len)); - - memcpy(&block.mData[offset], c_src, block_len); - result += block_len; - c_src += block_len; - len -= block_len; - offset = 0; - ++block_start; - } - while (len && block_start < block_limit); - } - - // Something left, see if it will fit in the free - // space of the last block. - if (len && ! mBlocks.empty()) - { - Block & last(*mBlocks.back()); - if (last.mUsed < last.mAlloced) - { - // Some will fit... - const size_t copy_len((std::min)(len, (last.mAlloced - last.mUsed))); - - memcpy(&last.mData[last.mUsed], c_src, copy_len); - last.mUsed += copy_len; - result += copy_len; - llassert_always(last.mUsed <= last.mAlloced); - mLen += copy_len; - c_src += copy_len; - len -= copy_len; - } - } - - if (len) - { - // Some or all of the remaining write data will - // be an append. - result += append(c_src, len); - } - - return result; + const char * c_src(static_cast<const char *>(src)); + + if (pos > mLen || 0 == len) + return 0; + + size_t result(0), offset(0); + const auto block_limit(mBlocks.size()); + int block_start(findBlock(pos, &offset)); + + if (block_start >= 0) + { + // Some or all of the write will be on top of + // existing data. + do + { + Block & block(*mBlocks[block_start]); + size_t block_limit(block.mUsed - offset); + size_t block_len((std::min)(block_limit, len)); + + memcpy(&block.mData[offset], c_src, block_len); + result += block_len; + c_src += block_len; + len -= block_len; + offset = 0; + ++block_start; + } + while (len && block_start < block_limit); + } + + // Something left, see if it will fit in the free + // space of the last block. + if (len && ! mBlocks.empty()) + { + Block & last(*mBlocks.back()); + if (last.mUsed < last.mAlloced) + { + // Some will fit... + const size_t copy_len((std::min)(len, (last.mAlloced - last.mUsed))); + + memcpy(&last.mData[last.mUsed], c_src, copy_len); + last.mUsed += copy_len; + result += copy_len; + llassert_always(last.mUsed <= last.mAlloced); + mLen += copy_len; + c_src += copy_len; + len -= copy_len; + } + } + + if (len) + { + // Some or all of the remaining write data will + // be an append. + result += append(c_src, len); + } + + return result; } - + int BufferArray::findBlock(size_t pos, size_t * ret_offset) { - *ret_offset = 0; - if (pos >= mLen) - return -1; // Doesn't exist - - const int block_limit(narrow<size_t>(mBlocks.size())); - for (int i(0); i < block_limit; ++i) - { - if (pos < mBlocks[i]->mUsed) - { - *ret_offset = pos; - return i; - } - pos -= mBlocks[i]->mUsed; - } - - // Shouldn't get here but... - return -1; + *ret_offset = 0; + if (pos >= mLen) + return -1; // Doesn't exist + + const int block_limit(narrow<size_t>(mBlocks.size())); + for (int i(0); i < block_limit; ++i) + { + if (pos < mBlocks[i]->mUsed) + { + *ret_offset = pos; + return i; + } + pos -= mBlocks[i]->mUsed; + } + + // Shouldn't get here but... + return -1; } bool BufferArray::getBlockStartEnd(int block, const char ** start, const char ** end) { - if (block < 0 || block >= mBlocks.size()) - { - return false; - } - - const Block & b(*mBlocks[block]); - *start = &b.mData[0]; - *end = &b.mData[b.mUsed]; - return true; + if (block < 0 || block >= mBlocks.size()) + { + return false; + } + + const Block & b(*mBlocks[block]); + *start = &b.mData[0]; + *end = &b.mData[b.mUsed]; + return true; } @@ -324,45 +324,45 @@ bool BufferArray::getBlockStartEnd(int block, const char ** start, const char ** BufferArray::Block::Block(size_t len) - : mUsed(0), - mAlloced(len) + : mUsed(0), + mAlloced(len) { - memset(mData, 0, len); + memset(mData, 0, len); } - + BufferArray::Block::~Block() { - mUsed = 0; - mAlloced = 0; + mUsed = 0; + mAlloced = 0; } void * BufferArray::Block::operator new(size_t len, size_t addl_len) { - void * mem = new char[len + addl_len + sizeof(void *)]; - return mem; + void * mem = new char[len + addl_len + sizeof(void *)]; + return mem; } void BufferArray::Block::operator delete(void * mem) { - char * cmem = static_cast<char *>(mem); - delete [] cmem; + char * cmem = static_cast<char *>(mem); + delete [] cmem; } void BufferArray::Block::operator delete(void * mem, size_t) { - operator delete(mem); + operator delete(mem); } BufferArray::Block * BufferArray::Block::alloc(size_t len) { - Block * block = new (len) Block(len); - return block; + Block * block = new (len) Block(len); + return block; } - + } // end namespace LLCore diff --git a/indra/llcorehttp/bufferarray.h b/indra/llcorehttp/bufferarray.h index 320adf2b8b..0269d1785e 100644 --- a/indra/llcorehttp/bufferarray.h +++ b/indra/llcorehttp/bufferarray.h @@ -24,8 +24,8 @@ * $/LicenseInfo$ */ -#ifndef _LLCORE_BUFFER_ARRAY_H_ -#define _LLCORE_BUFFER_ARRAY_H_ +#ifndef _LLCORE_BUFFER_ARRAY_H_ +#define _LLCORE_BUFFER_ARRAY_H_ #include <cstdlib> @@ -67,75 +67,75 @@ class BufferArrayStreamBuf; class BufferArray : public LLCoreInt::RefCounted { public: - // BufferArrayStreamBuf has intimate knowledge of this - // implementation to implement a buffer-free adapter. - // Changes here will likely need to be reflected there. - friend class BufferArrayStreamBuf; - - BufferArray(); + // BufferArrayStreamBuf has intimate knowledge of this + // implementation to implement a buffer-free adapter. + // Changes here will likely need to be reflected there. + friend class BufferArrayStreamBuf; - typedef LLCoreInt::IntrusivePtr<BufferArray> ptr_t; + BufferArray(); + + typedef LLCoreInt::IntrusivePtr<BufferArray> ptr_t; protected: - virtual ~BufferArray(); // Use release() + virtual ~BufferArray(); // Use release() private: - BufferArray(const BufferArray &); // Not defined - void operator=(const BufferArray &); // Not defined + BufferArray(const BufferArray &); // Not defined + void operator=(const BufferArray &); // Not defined public: - // Internal magic number, may be used by unit tests. - static const size_t BLOCK_ALLOC_SIZE = 65540; - - /// Appends the indicated data to the BufferArray - /// modifying current position and total size. New - /// position is one beyond the final byte of the buffer. - /// - /// @return Count of bytes copied to BufferArray - size_t append(const void * src, size_t len); - - /// Similar to @see append(), this call guarantees a - /// contiguous block of memory of requested size placed - /// at the current end of the BufferArray. On return, - /// the data in the memory is considered valid whether - /// the caller writes to it or not. - /// - /// @return Pointer to contiguous region at end - /// of BufferArray of 'len' size. - void * appendBufferAlloc(size_t len); - - /// Current count of bytes in BufferArray instance. - size_t size() const - { - return mLen; - } - - /// Copies data from the given position in the instance - /// to the caller's buffer. Will return a short count of - /// bytes copied if the 'len' extends beyond the data. - size_t read(size_t pos, void * dst, size_t len); - - /// Copies data from the caller's buffer to the instance - /// at the current position. May overwrite existing data, - /// append data when current position is equal to the - /// size of the instance or do a mix of both. - size_t write(size_t pos, const void * src, size_t len); - + // Internal magic number, may be used by unit tests. + static const size_t BLOCK_ALLOC_SIZE = 65540; + + /// Appends the indicated data to the BufferArray + /// modifying current position and total size. New + /// position is one beyond the final byte of the buffer. + /// + /// @return Count of bytes copied to BufferArray + size_t append(const void * src, size_t len); + + /// Similar to @see append(), this call guarantees a + /// contiguous block of memory of requested size placed + /// at the current end of the BufferArray. On return, + /// the data in the memory is considered valid whether + /// the caller writes to it or not. + /// + /// @return Pointer to contiguous region at end + /// of BufferArray of 'len' size. + void * appendBufferAlloc(size_t len); + + /// Current count of bytes in BufferArray instance. + size_t size() const + { + return mLen; + } + + /// Copies data from the given position in the instance + /// to the caller's buffer. Will return a short count of + /// bytes copied if the 'len' extends beyond the data. + size_t read(size_t pos, void * dst, size_t len); + + /// Copies data from the caller's buffer to the instance + /// at the current position. May overwrite existing data, + /// append data when current position is equal to the + /// size of the instance or do a mix of both. + size_t write(size_t pos, const void * src, size_t len); + protected: - int findBlock(size_t pos, size_t * ret_offset); + int findBlock(size_t pos, size_t * ret_offset); + + bool getBlockStartEnd(int block, const char ** start, const char ** end); - bool getBlockStartEnd(int block, const char ** start, const char ** end); - protected: - class Block; - typedef std::vector<Block *> container_t; + class Block; + typedef std::vector<Block *> container_t; - container_t mBlocks; - size_t mLen; + container_t mBlocks; + size_t mLen; }; // end class BufferArray } // end namespace LLCore -#endif // _LLCORE_BUFFER_ARRAY_H_ +#endif // _LLCORE_BUFFER_ARRAY_H_ diff --git a/indra/llcorehttp/bufferstream.cpp b/indra/llcorehttp/bufferstream.cpp index 678bf5ea9f..ea92f2f71d 100644 --- a/indra/llcorehttp/bufferstream.cpp +++ b/indra/llcorehttp/bufferstream.cpp @@ -33,250 +33,250 @@ namespace LLCore { BufferArrayStreamBuf::BufferArrayStreamBuf(BufferArray * array) - : mBufferArray(array), - mReadCurPos(0), - mReadCurBlock(-1), - mReadBegin(NULL), - mReadCur(NULL), - mReadEnd(NULL), - mWriteCurPos(0) + : mBufferArray(array), + mReadCurPos(0), + mReadCurBlock(-1), + mReadBegin(NULL), + mReadCur(NULL), + mReadEnd(NULL), + mWriteCurPos(0) { - if (array) - { - array->addRef(); - mWriteCurPos = array->mLen; - } + if (array) + { + array->addRef(); + mWriteCurPos = array->mLen; + } } BufferArrayStreamBuf::~BufferArrayStreamBuf() { - if (mBufferArray) - { - mBufferArray->release(); - mBufferArray = NULL; - } + if (mBufferArray) + { + mBufferArray->release(); + mBufferArray = NULL; + } } - + BufferArrayStreamBuf::int_type BufferArrayStreamBuf::underflow() { - if (! mBufferArray) - { - return traits_type::eof(); - } - - if (mReadCur == mReadEnd) - { - // Find the next block with actual data or leave - // mCurBlock/mCur/mEnd unchanged if we're at the end - // of any block chain. - const char * new_begin(NULL), * new_end(NULL); - int new_cur_block(mReadCurBlock + 1); - - while (mBufferArray->getBlockStartEnd(new_cur_block, &new_begin, &new_end)) - { - if (new_begin != new_end) - { - break; - } - ++new_cur_block; - } - if (new_begin == new_end) - { - return traits_type::eof(); - } - - mReadCurBlock = new_cur_block; - mReadBegin = mReadCur = new_begin; - mReadEnd = new_end; - } - - return traits_type::to_int_type(*mReadCur); + if (! mBufferArray) + { + return traits_type::eof(); + } + + if (mReadCur == mReadEnd) + { + // Find the next block with actual data or leave + // mCurBlock/mCur/mEnd unchanged if we're at the end + // of any block chain. + const char * new_begin(NULL), * new_end(NULL); + int new_cur_block(mReadCurBlock + 1); + + while (mBufferArray->getBlockStartEnd(new_cur_block, &new_begin, &new_end)) + { + if (new_begin != new_end) + { + break; + } + ++new_cur_block; + } + if (new_begin == new_end) + { + return traits_type::eof(); + } + + mReadCurBlock = new_cur_block; + mReadBegin = mReadCur = new_begin; + mReadEnd = new_end; + } + + return traits_type::to_int_type(*mReadCur); } BufferArrayStreamBuf::int_type BufferArrayStreamBuf::uflow() { - const int_type ret(underflow()); - - if (traits_type::eof() != ret) - { - ++mReadCur; - ++mReadCurPos; - } - return ret; + const int_type ret(underflow()); + + if (traits_type::eof() != ret) + { + ++mReadCur; + ++mReadCurPos; + } + return ret; } BufferArrayStreamBuf::int_type BufferArrayStreamBuf::pbackfail(int_type ch) { - if (! mBufferArray) - { - return traits_type::eof(); - } - - if (mReadCur == mReadBegin) - { - // Find the previous block with actual data or leave - // mCurBlock/mBegin/mCur/mEnd unchanged if we're at the - // beginning of any block chain. - const char * new_begin(NULL), * new_end(NULL); - int new_cur_block(mReadCurBlock - 1); - - while (mBufferArray->getBlockStartEnd(new_cur_block, &new_begin, &new_end)) - { - if (new_begin != new_end) - { - break; - } - --new_cur_block; - } - if (new_begin == new_end) - { - return traits_type::eof(); - } - - mReadCurBlock = new_cur_block; - mReadBegin = new_begin; - mReadEnd = mReadCur = new_end; - } - - if (traits_type::eof() != ch && mReadCur[-1] != ch) - { - return traits_type::eof(); - } - --mReadCurPos; - return traits_type::to_int_type(*--mReadCur); + if (! mBufferArray) + { + return traits_type::eof(); + } + + if (mReadCur == mReadBegin) + { + // Find the previous block with actual data or leave + // mCurBlock/mBegin/mCur/mEnd unchanged if we're at the + // beginning of any block chain. + const char * new_begin(NULL), * new_end(NULL); + int new_cur_block(mReadCurBlock - 1); + + while (mBufferArray->getBlockStartEnd(new_cur_block, &new_begin, &new_end)) + { + if (new_begin != new_end) + { + break; + } + --new_cur_block; + } + if (new_begin == new_end) + { + return traits_type::eof(); + } + + mReadCurBlock = new_cur_block; + mReadBegin = new_begin; + mReadEnd = mReadCur = new_end; + } + + if (traits_type::eof() != ch && mReadCur[-1] != ch) + { + return traits_type::eof(); + } + --mReadCurPos; + return traits_type::to_int_type(*--mReadCur); } std::streamsize BufferArrayStreamBuf::showmanyc() { - if (! mBufferArray) - { - return -1; - } - return mBufferArray->mLen - mReadCurPos; + if (! mBufferArray) + { + return -1; + } + return mBufferArray->mLen - mReadCurPos; } BufferArrayStreamBuf::int_type BufferArrayStreamBuf::overflow(int c) { - if (! mBufferArray || mWriteCurPos > mBufferArray->mLen) - { - return traits_type::eof(); - } - const size_t wrote(mBufferArray->write(mWriteCurPos, &c, 1)); - mWriteCurPos += wrote; - return wrote ? c : traits_type::eof(); + if (! mBufferArray || mWriteCurPos > mBufferArray->mLen) + { + return traits_type::eof(); + } + const size_t wrote(mBufferArray->write(mWriteCurPos, &c, 1)); + mWriteCurPos += wrote; + return wrote ? c : traits_type::eof(); } std::streamsize BufferArrayStreamBuf::xsputn(const char * src, std::streamsize count) { - if (! mBufferArray || mWriteCurPos > mBufferArray->mLen) - { - return 0; - } - const size_t wrote(mBufferArray->write(mWriteCurPos, src, count)); - mWriteCurPos += wrote; - return wrote; + if (! mBufferArray || mWriteCurPos > mBufferArray->mLen) + { + return 0; + } + const size_t wrote(mBufferArray->write(mWriteCurPos, src, count)); + mWriteCurPos += wrote; + return wrote; } std::streampos BufferArrayStreamBuf::seekoff(std::streamoff off, - std::ios_base::seekdir way, - std::ios_base::openmode which) + std::ios_base::seekdir way, + std::ios_base::openmode which) { - std::streampos ret(-1); - - if (! mBufferArray) - { - return ret; - } - - if (std::ios_base::in == which) - { - size_t pos(0); - - switch (way) - { - case std::ios_base::beg: - pos = off; - break; - - case std::ios_base::cur: - pos = mReadCurPos += off; - break; - - case std::ios_base::end: - pos = mBufferArray->mLen - off; - break; - - default: - return ret; - } - - if (pos >= mBufferArray->size()) - { - pos = (std::max)(size_t(0), mBufferArray->size() - 1); - } - size_t ba_offset(0); - int block(mBufferArray->findBlock(pos, &ba_offset)); - if (block < 0) - return ret; - const char * start(NULL), * end(NULL); - if (! mBufferArray->getBlockStartEnd(block, &start, &end)) - return ret; - mReadCurBlock = block; - mReadBegin = start; - mReadCur = start + ba_offset; - mReadEnd = end; - ret = mReadCurPos = pos; - } - else if (std::ios_base::out == which) - { - size_t pos(0); - - switch (way) - { - case std::ios_base::beg: - pos = off; - break; - - case std::ios_base::cur: - pos = mWriteCurPos += off; - break; - - case std::ios_base::end: - pos = mBufferArray->mLen - off; - break; - - default: - return ret; - } - - if (pos > mBufferArray->size()) - { - pos = mBufferArray->size(); - } - ret = mWriteCurPos = pos; - } - - return ret; + std::streampos ret(-1); + + if (! mBufferArray) + { + return ret; + } + + if (std::ios_base::in == which) + { + size_t pos(0); + + switch (way) + { + case std::ios_base::beg: + pos = off; + break; + + case std::ios_base::cur: + pos = mReadCurPos += off; + break; + + case std::ios_base::end: + pos = mBufferArray->mLen - off; + break; + + default: + return ret; + } + + if (pos >= mBufferArray->size()) + { + pos = (std::max)(size_t(0), mBufferArray->size() - 1); + } + size_t ba_offset(0); + int block(mBufferArray->findBlock(pos, &ba_offset)); + if (block < 0) + return ret; + const char * start(NULL), * end(NULL); + if (! mBufferArray->getBlockStartEnd(block, &start, &end)) + return ret; + mReadCurBlock = block; + mReadBegin = start; + mReadCur = start + ba_offset; + mReadEnd = end; + ret = mReadCurPos = pos; + } + else if (std::ios_base::out == which) + { + size_t pos(0); + + switch (way) + { + case std::ios_base::beg: + pos = off; + break; + + case std::ios_base::cur: + pos = mWriteCurPos += off; + break; + + case std::ios_base::end: + pos = mBufferArray->mLen - off; + break; + + default: + return ret; + } + + if (pos > mBufferArray->size()) + { + pos = mBufferArray->size(); + } + ret = mWriteCurPos = pos; + } + + return ret; } BufferArrayStream::BufferArrayStream(BufferArray * ba) - : std::iostream(&mStreamBuf), - mStreamBuf(ba) + : std::iostream(&mStreamBuf), + mStreamBuf(ba) {} - - + + BufferArrayStream::~BufferArrayStream() {} - + } // end namespace LLCore diff --git a/indra/llcorehttp/bufferstream.h b/indra/llcorehttp/bufferstream.h index 9327a798aa..93891810aa 100644 --- a/indra/llcorehttp/bufferstream.h +++ b/indra/llcorehttp/bufferstream.h @@ -24,8 +24,8 @@ * $/LicenseInfo$ */ -#ifndef _LLCORE_BUFFER_STREAM_H_ -#define _LLCORE_BUFFER_STREAM_H_ +#ifndef _LLCORE_BUFFER_STREAM_H_ +#define _LLCORE_BUFFER_STREAM_H_ #include <sstream> @@ -85,38 +85,38 @@ namespace LLCore class BufferArrayStreamBuf : public std::streambuf { public: - /// Constructor increments the reference count on the - /// BufferArray argument and calls release() on destruction. - BufferArrayStreamBuf(BufferArray * array); - virtual ~BufferArrayStreamBuf(); + /// Constructor increments the reference count on the + /// BufferArray argument and calls release() on destruction. + BufferArrayStreamBuf(BufferArray * array); + virtual ~BufferArrayStreamBuf(); private: - BufferArrayStreamBuf(const BufferArrayStreamBuf &); // Not defined - void operator=(const BufferArrayStreamBuf &); // Not defined + BufferArrayStreamBuf(const BufferArrayStreamBuf &); // Not defined + void operator=(const BufferArrayStreamBuf &); // Not defined public: - // Input interfaces from std::streambuf - int_type underflow(); - int_type uflow(); - int_type pbackfail(int_type ch); - std::streamsize showmanyc(); - - // Output interfaces from std::streambuf - int_type overflow(int c); - std::streamsize xsputn(const char * src, std::streamsize count); - - // Common/misc interfaces from std::streambuf - std::streampos seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode which); - + // Input interfaces from std::streambuf + int_type underflow(); + int_type uflow(); + int_type pbackfail(int_type ch); + std::streamsize showmanyc(); + + // Output interfaces from std::streambuf + int_type overflow(int c); + std::streamsize xsputn(const char * src, std::streamsize count); + + // Common/misc interfaces from std::streambuf + std::streampos seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode which); + protected: - BufferArray * mBufferArray; // Ref counted - size_t mReadCurPos; - int mReadCurBlock; - const char * mReadBegin; - const char * mReadCur; - const char * mReadEnd; - size_t mWriteCurPos; - + BufferArray * mBufferArray; // Ref counted + size_t mReadCurPos; + int mReadCurBlock; + const char * mReadBegin; + const char * mReadCur; + const char * mReadEnd; + size_t mWriteCurPos; + }; // end class BufferArrayStreamBuf @@ -134,20 +134,20 @@ protected: class BufferArrayStream : public std::iostream { public: - /// Constructor increments the reference count on the - /// BufferArray argument and calls release() on destruction. - BufferArrayStream(BufferArray * ba); - ~BufferArrayStream(); + /// Constructor increments the reference count on the + /// BufferArray argument and calls release() on destruction. + BufferArrayStream(BufferArray * ba); + ~BufferArrayStream(); protected: - BufferArrayStream(const BufferArrayStream &); - void operator=(const BufferArrayStream &); + BufferArrayStream(const BufferArrayStream &); + void operator=(const BufferArrayStream &); protected: - BufferArrayStreamBuf mStreamBuf; + BufferArrayStreamBuf mStreamBuf; }; // end class BufferArrayStream } // end namespace LLCore -#endif // _LLCORE_BUFFER_STREAM_H_ +#endif // _LLCORE_BUFFER_STREAM_H_ diff --git a/indra/llcorehttp/examples/http_texture_load.cpp b/indra/llcorehttp/examples/http_texture_load.cpp index cc53b20add..4d1e52b766 100644 --- a/indra/llcorehttp/examples/http_texture_load.cpp +++ b/indra/llcorehttp/examples/http_texture_load.cpp @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012-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$ */ @@ -65,8 +65,8 @@ static char url_format[1024] = "http://example.com/some/path?texture_id=%s.textu #if defined(WIN32) -#define strncpy(_a, _b, _c) strncpy_s(_a, _b, _c) -#define strtok_r(_a, _b, _c) strtok_s(_a, _b, _c) +#define strncpy(_a, _b, _c) strncpy_s(_a, _b, _c) +#define strtok_r(_a, _b, _c) strtok_s(_a, _b, _c) int getopt(int argc, char * const argv[], const char *optstring); char *optarg(NULL); @@ -80,48 +80,48 @@ int optind(1); class WorkingSet : public LLCore::HttpHandler { public: - WorkingSet(); - ~WorkingSet(); + WorkingSet(); + ~WorkingSet(); + + bool reload(LLCore::HttpRequest *, LLCore::HttpOptions::ptr_t &); + + virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response); - bool reload(LLCore::HttpRequest *, LLCore::HttpOptions::ptr_t &); - - virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response); + void loadAssetUuids(FILE * in); - void loadAssetUuids(FILE * in); - public: - struct Spec - { - std::string mUuid; - int mOffset; - int mLength; - }; - typedef std::set<LLCore::HttpHandle> handle_set_t; - typedef std::vector<Spec> asset_list_t; - + struct Spec + { + std::string mUuid; + int mOffset; + int mLength; + }; + typedef std::set<LLCore::HttpHandle> handle_set_t; + typedef std::vector<Spec> asset_list_t; + public: - bool mVerbose; - bool mRandomRange; - bool mNoRange; - int mRequestLowWater; - int mRequestHighWater; - handle_set_t mHandles; - int mRemaining; - int mLimit; - int mAt; - std::string mUrl; - asset_list_t mAssets; - int mErrorsApi; - int mErrorsHttp; - int mErrorsHttp404; - int mErrorsHttp416; - int mErrorsHttp500; - int mErrorsHttp503; - int mRetries; - int mRetriesHttp503; - int mSuccesses; - long mByteCount; - LLCore::HttpHeaders::ptr_t mHeaders; + bool mVerbose; + bool mRandomRange; + bool mNoRange; + int mRequestLowWater; + int mRequestHighWater; + handle_set_t mHandles; + int mRemaining; + int mLimit; + int mAt; + std::string mUrl; + asset_list_t mAssets; + int mErrorsApi; + int mErrorsHttp; + int mErrorsHttp404; + int mErrorsHttp416; + int mErrorsHttp500; + int mErrorsHttp503; + int mRetries; + int mRetriesHttp503; + int mSuccesses; + long mByteCount; + LLCore::HttpHeaders::ptr_t mHeaders; }; @@ -131,28 +131,28 @@ public: class Metrics { public: - class MetricsImpl; - + class MetricsImpl; + public: - Metrics(); - ~Metrics(); + Metrics(); + ~Metrics(); - void init(); - void sample(); - void term(); + void init(); + void sample(); + void term(); protected: - MetricsImpl * mImpl; + MetricsImpl * mImpl; public: - U64 mMaxVSZ; - U64 mMinVSZ; - U64 mStartWallTime; - U64 mEndWallTime; - U64 mStartUTime; - U64 mEndUTime; - U64 mStartSTime; - U64 mEndSTime; + U64 mMaxVSZ; + U64 mMinVSZ; + U64 mStartWallTime; + U64 mEndWallTime; + U64 mStartUTime; + U64 mEndUTime; + U64 mStartSTime; + U64 mEndSTime; }; @@ -161,273 +161,273 @@ public: // int main(int argc, char** argv) { - LLCore::HttpStatus status; - bool do_random(false); - bool do_whole(false); - bool do_verbose(false); - - int option(-1); - while (-1 != (option = getopt(argc, argv, "u:c:h?RwvH:p:t:"))) - { - switch (option) - { - case 'u': - strncpy(url_format, optarg, sizeof(url_format)); - url_format[sizeof(url_format) - 1] = '\0'; - break; - - case 'c': - { - unsigned long value; - char * end; - - value = strtoul(optarg, &end, 10); - if (value < 1 || value > 100 || *end != '\0') - { - usage(std::cerr); - return 1; - } - concurrency_limit = value; - } - break; - - case 'H': - { - unsigned long value; - char * end; - - value = strtoul(optarg, &end, 10); - if (value < 1 || value > 200 || *end != '\0') - { - usage(std::cerr); - return 1; - } - highwater = value; - } - break; - - case 'p': - { - unsigned long value; - char * end; - - value = strtoul(optarg, &end, 10); - if (value > 100 || *end != '\0') - { - usage(std::cerr); - return 1; - } - pipeline_depth = value; - } - break; - - case '5': - { - unsigned long value; - char * end; - - value = strtoul(optarg, &end, 10); - if (value > 3 || *end != '\0') - { - usage(std::cerr); - return 1; - } - tracing = value; - } - break; - - case 'R': - do_random = true; - do_whole = false; - break; - - case 'w': - do_whole = true; - do_random = false; - break; - - case 'v': - do_verbose = true; - break; - - case 'h': - case '?': - usage(std::cout); - return 0; - } - } - - if ((optind + 1) != argc) - { - usage(std::cerr); - return 1; - } - - FILE * uuids(fopen(argv[optind], "r")); - if (! uuids) - { - const char * errstr(strerror(errno)); - - std::cerr << "Couldn't open UUID file '" << argv[optind] << "'. Reason: " - << errstr << std::endl; - return 1; - } - - // Initialization - init_curl(); - LLCore::HttpRequest::createService(); - LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_CONNECTION_LIMIT, - LLCore::HttpRequest::DEFAULT_POLICY_ID, - concurrency_limit, - NULL); - LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_PER_HOST_CONNECTION_LIMIT, - LLCore::HttpRequest::DEFAULT_POLICY_ID, - concurrency_limit, - NULL); - if (pipeline_depth) - { - LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_PIPELINING_DEPTH, - LLCore::HttpRequest::DEFAULT_POLICY_ID, - pipeline_depth, - NULL); - } - if (tracing) - { - LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_TRACE, - LLCore::HttpRequest::DEFAULT_POLICY_ID, - tracing, - NULL); - } - LLCore::HttpRequest::startThread(); - - // Get service point - LLCore::HttpRequest * hr = new LLCore::HttpRequest(); - - // Get request options - LLCore::HttpOptions::ptr_t opt = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()); - opt->setRetries(12); - opt->setUseRetryAfter(true); - - // Get a handler/working set - WorkingSet ws; - - // Fill the working set with work - ws.mUrl = url_format; - ws.loadAssetUuids(uuids); - ws.mRandomRange = do_random; - ws.mNoRange = do_whole; - ws.mVerbose = do_verbose; - ws.mRequestHighWater = highwater; - ws.mRequestLowWater = ws.mRequestHighWater / 2; - - if (! ws.mAssets.size()) - { - std::cerr << "No UUIDs found in file '" << argv[optind] << "'." << std::endl; - return 1; - } - - // Setup metrics - Metrics metrics; - metrics.init(); - - // Run it - int passes(0); - while (! ws.reload(hr, opt)) - { - hr->update(0); - ms_sleep(2); - if (0 == (++passes % 200)) - { - metrics.sample(); - } - } - metrics.sample(); - metrics.term(); - - // Report - std::cout << "HTTP errors: " << ws.mErrorsHttp << " API errors: " << ws.mErrorsApi - << " Successes: " << ws.mSuccesses << " Byte count: " << ws.mByteCount - << std::endl; - std::cout << "HTTP 404 errors: " << ws.mErrorsHttp404 << " HTTP 416 errors: " << ws.mErrorsHttp416 - << " HTTP 500 errors: " << ws.mErrorsHttp500 << " HTTP 503 errors: " << ws.mErrorsHttp503 - << std::endl; - std::cout << "Retries: " << ws.mRetries << " Retries on 503: " << ws.mRetriesHttp503 - << std::endl; - std::cout << "User CPU: " << (metrics.mEndUTime - metrics.mStartUTime) - << " uS System CPU: " << (metrics.mEndSTime - metrics.mStartSTime) - << " uS Wall Time: " << (metrics.mEndWallTime - metrics.mStartWallTime) - << " uS Maximum VSZ: " << metrics.mMaxVSZ - << " Bytes Minimum VSZ: " << metrics.mMinVSZ << " Bytes" - << std::endl; - - // Clean up - hr->requestStopThread(LLCore::HttpHandler::ptr_t()); - ms_sleep(1000); + LLCore::HttpStatus status; + bool do_random(false); + bool do_whole(false); + bool do_verbose(false); + + int option(-1); + while (-1 != (option = getopt(argc, argv, "u:c:h?RwvH:p:t:"))) + { + switch (option) + { + case 'u': + strncpy(url_format, optarg, sizeof(url_format)); + url_format[sizeof(url_format) - 1] = '\0'; + break; + + case 'c': + { + unsigned long value; + char * end; + + value = strtoul(optarg, &end, 10); + if (value < 1 || value > 100 || *end != '\0') + { + usage(std::cerr); + return 1; + } + concurrency_limit = value; + } + break; + + case 'H': + { + unsigned long value; + char * end; + + value = strtoul(optarg, &end, 10); + if (value < 1 || value > 200 || *end != '\0') + { + usage(std::cerr); + return 1; + } + highwater = value; + } + break; + + case 'p': + { + unsigned long value; + char * end; + + value = strtoul(optarg, &end, 10); + if (value > 100 || *end != '\0') + { + usage(std::cerr); + return 1; + } + pipeline_depth = value; + } + break; + + case '5': + { + unsigned long value; + char * end; + + value = strtoul(optarg, &end, 10); + if (value > 3 || *end != '\0') + { + usage(std::cerr); + return 1; + } + tracing = value; + } + break; + + case 'R': + do_random = true; + do_whole = false; + break; + + case 'w': + do_whole = true; + do_random = false; + break; + + case 'v': + do_verbose = true; + break; + + case 'h': + case '?': + usage(std::cout); + return 0; + } + } + + if ((optind + 1) != argc) + { + usage(std::cerr); + return 1; + } + + FILE * uuids(fopen(argv[optind], "r")); + if (! uuids) + { + const char * errstr(strerror(errno)); + + std::cerr << "Couldn't open UUID file '" << argv[optind] << "'. Reason: " + << errstr << std::endl; + return 1; + } + + // Initialization + init_curl(); + LLCore::HttpRequest::createService(); + LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_CONNECTION_LIMIT, + LLCore::HttpRequest::DEFAULT_POLICY_ID, + concurrency_limit, + NULL); + LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_PER_HOST_CONNECTION_LIMIT, + LLCore::HttpRequest::DEFAULT_POLICY_ID, + concurrency_limit, + NULL); + if (pipeline_depth) + { + LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_PIPELINING_DEPTH, + LLCore::HttpRequest::DEFAULT_POLICY_ID, + pipeline_depth, + NULL); + } + if (tracing) + { + LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_TRACE, + LLCore::HttpRequest::DEFAULT_POLICY_ID, + tracing, + NULL); + } + LLCore::HttpRequest::startThread(); + + // Get service point + LLCore::HttpRequest * hr = new LLCore::HttpRequest(); + + // Get request options + LLCore::HttpOptions::ptr_t opt = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()); + opt->setRetries(12); + opt->setUseRetryAfter(true); + + // Get a handler/working set + WorkingSet ws; + + // Fill the working set with work + ws.mUrl = url_format; + ws.loadAssetUuids(uuids); + ws.mRandomRange = do_random; + ws.mNoRange = do_whole; + ws.mVerbose = do_verbose; + ws.mRequestHighWater = highwater; + ws.mRequestLowWater = ws.mRequestHighWater / 2; + + if (! ws.mAssets.size()) + { + std::cerr << "No UUIDs found in file '" << argv[optind] << "'." << std::endl; + return 1; + } + + // Setup metrics + Metrics metrics; + metrics.init(); + + // Run it + int passes(0); + while (! ws.reload(hr, opt)) + { + hr->update(0); + ms_sleep(2); + if (0 == (++passes % 200)) + { + metrics.sample(); + } + } + metrics.sample(); + metrics.term(); + + // Report + std::cout << "HTTP errors: " << ws.mErrorsHttp << " API errors: " << ws.mErrorsApi + << " Successes: " << ws.mSuccesses << " Byte count: " << ws.mByteCount + << std::endl; + std::cout << "HTTP 404 errors: " << ws.mErrorsHttp404 << " HTTP 416 errors: " << ws.mErrorsHttp416 + << " HTTP 500 errors: " << ws.mErrorsHttp500 << " HTTP 503 errors: " << ws.mErrorsHttp503 + << std::endl; + std::cout << "Retries: " << ws.mRetries << " Retries on 503: " << ws.mRetriesHttp503 + << std::endl; + std::cout << "User CPU: " << (metrics.mEndUTime - metrics.mStartUTime) + << " uS System CPU: " << (metrics.mEndSTime - metrics.mStartSTime) + << " uS Wall Time: " << (metrics.mEndWallTime - metrics.mStartWallTime) + << " uS Maximum VSZ: " << metrics.mMaxVSZ + << " Bytes Minimum VSZ: " << metrics.mMinVSZ << " Bytes" + << std::endl; + + // Clean up + hr->requestStopThread(LLCore::HttpHandler::ptr_t()); + ms_sleep(1000); opt.reset(); - delete hr; - LLCore::HttpRequest::destroyService(); - term_curl(); - + delete hr; + LLCore::HttpRequest::destroyService(); + term_curl(); + return 0; } void usage(std::ostream & out) { - out << "\n" - "usage:\thttp_texture_load [options] uuid_file\n" - "\n" - "This is a standalone program to drive the New Platform HTTP Library.\n" - "The program is supplied with a file of texture UUIDs, one per line\n" - "These are fetched sequentially using a pool of concurrent connection\n" - "until all are fetched. The default URL format is only useful from\n" - "within Linden Lab but this can be overriden with a printf-style\n" - "URL formatting string on the command line.\n" - "\n" - "Options:\n" - "\n" - " -u <url_format> printf-style format string for URL generation\n" - " Default: " << url_format << "\n" - " -R Issue GETs with random Range: headers\n" - " -w Issue GETs without Range: headers to get whole object\n" - " -c <limit> Maximum connection concurrency. Range: [1..100]\n" - " Default: " << concurrency_limit << "\n" - " -H <limit> HTTP request highwater (requests fed to llcorehttp).\n" - " Range: [1..200] Default: " << highwater << "\n" - " -p <depth> If <depth> is positive, enables and sets pipelineing\n" - " depth on HTTP requests. Default: " << pipeline_depth << "\n" - " -t <level> If <level> is positive ([1..3]), enables and sets HTTP\n" - " tracing on HTTP requests. Default: " << tracing << "\n" - " -v Verbose mode. Issue some chatter while running\n" - " -h print this help\n" - "\n" - << std::endl; + out << "\n" + "usage:\thttp_texture_load [options] uuid_file\n" + "\n" + "This is a standalone program to drive the New Platform HTTP Library.\n" + "The program is supplied with a file of texture UUIDs, one per line\n" + "These are fetched sequentially using a pool of concurrent connection\n" + "until all are fetched. The default URL format is only useful from\n" + "within Linden Lab but this can be overriden with a printf-style\n" + "URL formatting string on the command line.\n" + "\n" + "Options:\n" + "\n" + " -u <url_format> printf-style format string for URL generation\n" + " Default: " << url_format << "\n" + " -R Issue GETs with random Range: headers\n" + " -w Issue GETs without Range: headers to get whole object\n" + " -c <limit> Maximum connection concurrency. Range: [1..100]\n" + " Default: " << concurrency_limit << "\n" + " -H <limit> HTTP request highwater (requests fed to llcorehttp).\n" + " Range: [1..200] Default: " << highwater << "\n" + " -p <depth> If <depth> is positive, enables and sets pipelineing\n" + " depth on HTTP requests. Default: " << pipeline_depth << "\n" + " -t <level> If <level> is positive ([1..3]), enables and sets HTTP\n" + " tracing on HTTP requests. Default: " << tracing << "\n" + " -v Verbose mode. Issue some chatter while running\n" + " -h print this help\n" + "\n" + << std::endl; } WorkingSet::WorkingSet() - : LLCore::HttpHandler(), - mVerbose(false), - mRandomRange(false), - mNoRange(false), - mRemaining(200), - mLimit(200), - mAt(0), - mErrorsApi(0), - mErrorsHttp(0), - mErrorsHttp404(0), - mErrorsHttp416(0), - mErrorsHttp500(0), - mErrorsHttp503(0), - mRetries(0), - mRetriesHttp503(0), - mSuccesses(0), - mByteCount(0L) + : LLCore::HttpHandler(), + mVerbose(false), + mRandomRange(false), + mNoRange(false), + mRemaining(200), + mLimit(200), + mAt(0), + mErrorsApi(0), + mErrorsHttp(0), + mErrorsHttp404(0), + mErrorsHttp416(0), + mErrorsHttp500(0), + mErrorsHttp503(0), + mRetries(0), + mRetriesHttp503(0), + mSuccesses(0), + mByteCount(0L) { - mAssets.reserve(30000); + mAssets.reserve(30000); - mHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders); - mHeaders->append("Accept", "image/x-j2c"); + mHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders); + mHeaders->append("Accept", "image/x-j2c"); } @@ -443,166 +443,166 @@ namespace bool WorkingSet::reload(LLCore::HttpRequest * hr, LLCore::HttpOptions::ptr_t & opt) { - if (mRequestLowWater <= mHandles.size()) - { - // Haven't fallen below low-water level yet. - return false; - } - - int to_do((std::min)(mRemaining, mRequestHighWater - int(mHandles.size()))); - - for (int i(0); i < to_do; ++i) - { - char buffer[1024]; -#if defined(WIN32) - _snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, mUrl.c_str(), mAssets[mAt].mUuid.c_str()); + if (mRequestLowWater <= mHandles.size()) + { + // Haven't fallen below low-water level yet. + return false; + } + + int to_do((std::min)(mRemaining, mRequestHighWater - int(mHandles.size()))); + + for (int i(0); i < to_do; ++i) + { + char buffer[1024]; +#if defined(WIN32) + _snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, mUrl.c_str(), mAssets[mAt].mUuid.c_str()); #else - snprintf(buffer, sizeof(buffer), mUrl.c_str(), mAssets[mAt].mUuid.c_str()); + snprintf(buffer, sizeof(buffer), mUrl.c_str(), mAssets[mAt].mUuid.c_str()); #endif - int offset(mNoRange - ? 0 - : (mRandomRange ? ((unsigned long) rand()) % 1000000UL : mAssets[mAt].mOffset)); - int length(mNoRange - ? 0 - : (mRandomRange ? ((unsigned long) rand()) % 1000000UL : mAssets[mAt].mLength)); - - LLCore::HttpHandle handle; - if (offset || length) - { - handle = hr->requestGetByteRange(0, buffer, offset, length, opt, mHeaders, LLCore::HttpHandler::ptr_t(this, NoOpDeletor)); - } - else - { + int offset(mNoRange + ? 0 + : (mRandomRange ? ((unsigned long) rand()) % 1000000UL : mAssets[mAt].mOffset)); + int length(mNoRange + ? 0 + : (mRandomRange ? ((unsigned long) rand()) % 1000000UL : mAssets[mAt].mLength)); + + LLCore::HttpHandle handle; + if (offset || length) + { + handle = hr->requestGetByteRange(0, buffer, offset, length, opt, mHeaders, LLCore::HttpHandler::ptr_t(this, NoOpDeletor)); + } + else + { handle = hr->requestGet(0, buffer, opt, mHeaders, LLCore::HttpHandler::ptr_t(this, NoOpDeletor)); - } - if (! handle) - { - // Fatal. Couldn't queue up something. - std::cerr << "Failed to queue work to HTTP Service. Reason: " - << hr->getStatus().toString() << std::endl; - exit(1); - } - else - { - mHandles.insert(handle); - } - mAt++; - mRemaining--; - - if (mVerbose) - { - static int count(0); - ++count; - if (0 == (count %5)) - std::cout << "Queued " << count << std::endl; - } - } - - // Are we done? - return (! mRemaining) && mHandles.empty(); + } + if (! handle) + { + // Fatal. Couldn't queue up something. + std::cerr << "Failed to queue work to HTTP Service. Reason: " + << hr->getStatus().toString() << std::endl; + exit(1); + } + else + { + mHandles.insert(handle); + } + mAt++; + mRemaining--; + + if (mVerbose) + { + static int count(0); + ++count; + if (0 == (count %5)) + std::cout << "Queued " << count << std::endl; + } + } + + // Are we done? + return (! mRemaining) && mHandles.empty(); } - + void WorkingSet::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response) { - handle_set_t::iterator it(mHandles.find(handle)); - if (mHandles.end() == it) - { - // Wha? - std::cerr << "Failed to find handle in request list. Fatal." << std::endl; - exit(1); - } - else - { - LLCore::HttpStatus status(response->getStatus()); - if (status) - { - // More success - LLCore::BufferArray * data(response->getBody()); - mByteCount += data ? data->size() : 0; - ++mSuccesses; - } - else - { - // Something in this library or libcurl - if (status.isHttpStatus()) - { - static const LLCore::HttpStatus hs404(404); - static const LLCore::HttpStatus hs416(416); - static const LLCore::HttpStatus hs500(500); - static const LLCore::HttpStatus hs503(503); - - ++mErrorsHttp; - if (hs404 == status) - { - ++mErrorsHttp404; - } - else if (hs416 == status) - { - ++mErrorsHttp416; - } - else if (hs500 == status) - { - ++mErrorsHttp500; - } - else if (hs503 == status) - { - ++mErrorsHttp503; - } - } - else - { - ++mErrorsApi; - } - } - unsigned int retry(0U), retry_503(0U); - response->getRetries(&retry, &retry_503); - mRetries += int(retry); - mRetriesHttp503 += int(retry_503); - mHandles.erase(it); - } - - if (mVerbose) - { - static int count(0); - ++count; - if (0 == (count %5)) - std::cout << "Handled " << count << std::endl; - } + handle_set_t::iterator it(mHandles.find(handle)); + if (mHandles.end() == it) + { + // Wha? + std::cerr << "Failed to find handle in request list. Fatal." << std::endl; + exit(1); + } + else + { + LLCore::HttpStatus status(response->getStatus()); + if (status) + { + // More success + LLCore::BufferArray * data(response->getBody()); + mByteCount += data ? data->size() : 0; + ++mSuccesses; + } + else + { + // Something in this library or libcurl + if (status.isHttpStatus()) + { + static const LLCore::HttpStatus hs404(404); + static const LLCore::HttpStatus hs416(416); + static const LLCore::HttpStatus hs500(500); + static const LLCore::HttpStatus hs503(503); + + ++mErrorsHttp; + if (hs404 == status) + { + ++mErrorsHttp404; + } + else if (hs416 == status) + { + ++mErrorsHttp416; + } + else if (hs500 == status) + { + ++mErrorsHttp500; + } + else if (hs503 == status) + { + ++mErrorsHttp503; + } + } + else + { + ++mErrorsApi; + } + } + unsigned int retry(0U), retry_503(0U); + response->getRetries(&retry, &retry_503); + mRetries += int(retry); + mRetriesHttp503 += int(retry_503); + mHandles.erase(it); + } + + if (mVerbose) + { + static int count(0); + ++count; + if (0 == (count %5)) + std::cout << "Handled " << count << std::endl; + } } void WorkingSet::loadAssetUuids(FILE * in) { - char buffer[1024]; - - while (fgets(buffer, sizeof(buffer), in)) - { - WorkingSet::Spec asset; - char * state(NULL); - char * token = strtok_r(buffer, " \t\n,", &state); - if (token && 36 == strlen(token)) - { - // Close enough for this function - asset.mUuid = token; - asset.mOffset = 0; - asset.mLength = 0; - token = strtok_r(buffer, " \t\n,", &state); - if (token) - { - int offset(atoi(token)); - token = strtok_r(buffer, " \t\n,", &state); - if (token) - { - int length(atoi(token)); - asset.mOffset = offset; - asset.mLength = length; - } - } - mAssets.push_back(asset); - } - } - mRemaining = mLimit = mAssets.size(); + char buffer[1024]; + + while (fgets(buffer, sizeof(buffer), in)) + { + WorkingSet::Spec asset; + char * state(NULL); + char * token = strtok_r(buffer, " \t\n,", &state); + if (token && 36 == strlen(token)) + { + // Close enough for this function + asset.mUuid = token; + asset.mOffset = 0; + asset.mLength = 0; + token = strtok_r(buffer, " \t\n,", &state); + if (token) + { + int offset(atoi(token)); + token = strtok_r(buffer, " \t\n,", &state); + if (token) + { + int length(atoi(token)); + asset.mOffset = offset; + asset.mLength = length; + } + } + mAssets.push_back(asset); + } + } + mRemaining = mLimit = mAssets.size(); } @@ -611,58 +611,58 @@ LLCoreInt::HttpMutex ** ssl_mutex_list = NULL; void init_curl() { - curl_global_init(CURL_GLOBAL_ALL); - - ssl_mutex_count = CRYPTO_num_locks(); - if (ssl_mutex_count > 0) - { - ssl_mutex_list = new LLCoreInt::HttpMutex * [ssl_mutex_count]; - - for (int i(0); i < ssl_mutex_count; ++i) - { - ssl_mutex_list[i] = new LLCoreInt::HttpMutex; - } - - CRYPTO_set_locking_callback(ssl_locking_callback); - CRYPTO_THREADID_set_callback(ssl_thread_id_callback); - } + curl_global_init(CURL_GLOBAL_ALL); + + ssl_mutex_count = CRYPTO_num_locks(); + if (ssl_mutex_count > 0) + { + ssl_mutex_list = new LLCoreInt::HttpMutex * [ssl_mutex_count]; + + for (int i(0); i < ssl_mutex_count; ++i) + { + ssl_mutex_list[i] = new LLCoreInt::HttpMutex; + } + + CRYPTO_set_locking_callback(ssl_locking_callback); + CRYPTO_THREADID_set_callback(ssl_thread_id_callback); + } } void term_curl() { - CRYPTO_set_locking_callback(NULL); - for (int i(0); i < ssl_mutex_count; ++i) - { - delete ssl_mutex_list[i]; - } - delete [] ssl_mutex_list; + CRYPTO_set_locking_callback(NULL); + for (int i(0); i < ssl_mutex_count; ++i) + { + delete ssl_mutex_list[i]; + } + delete [] ssl_mutex_list; } void ssl_thread_id_callback(CRYPTO_THREADID* pthreadid) { #if defined(WIN32) - CRYPTO_THREADID_set_pointer(pthreadid, GetCurrentThread()); + CRYPTO_THREADID_set_pointer(pthreadid, GetCurrentThread()); #else - CRYPTO_THREADID_set_pointer(pthreadid, pthread_self()); + CRYPTO_THREADID_set_pointer(pthreadid, pthread_self()); #endif } void ssl_locking_callback(int mode, int type, const char * /* file */, int /* line */) { - if (type >= 0 && type < ssl_mutex_count) - { - if (mode & CRYPTO_LOCK) - { - ssl_mutex_list[type]->lock(); - } - else - { - ssl_mutex_list[type]->unlock(); - } - } + if (type >= 0 && type < ssl_mutex_count) + { + if (mode & CRYPTO_LOCK) + { + ssl_mutex_list[type]->lock(); + } + else + { + ssl_mutex_list[type]->unlock(); + } + } } @@ -672,41 +672,41 @@ void ssl_locking_callback(int mode, int type, const char * /* file */, int /* li // it too hard... int getopt(int argc, char * const argv[], const char *optstring) { - static int pos(0); - while (optind < argc) - { - if (pos == 0) - { - if (argv[optind][0] != '-') - return -1; - pos = 1; - } - if (! argv[optind][pos]) - { - ++optind; - pos = 0; - continue; - } - const char * thing(strchr(optstring, argv[optind][pos])); - if (! thing) - { - ++optind; - return -1; - } - if (thing[1] == ':') - { - optarg = argv[++optind]; - ++optind; - pos = 0; - } - else - { - optarg = NULL; - ++pos; - } - return *thing; - } - return -1; + static int pos(0); + while (optind < argc) + { + if (pos == 0) + { + if (argv[optind][0] != '-') + return -1; + pos = 1; + } + if (! argv[optind][pos]) + { + ++optind; + pos = 0; + continue; + } + const char * thing(strchr(optstring, argv[optind][pos])); + if (! thing) + { + ++optind; + return -1; + } + if (thing[1] == ':') + { + optarg = argv[++optind]; + ++optind; + pos = 0; + } + else + { + optarg = NULL; + ++pos; + } + return *thing; + } + return -1; } #endif @@ -715,63 +715,63 @@ int getopt(int argc, char * const argv[], const char *optstring) #if LL_WINDOWS -#define PSAPI_VERSION 1 +#define PSAPI_VERSION 1 #include "windows.h" #include "psapi.h" class Metrics::MetricsImpl { public: - MetricsImpl() - {} - - ~MetricsImpl() - {} - - void init(Metrics * metrics) - { - HANDLE self(GetCurrentProcess()); // Does not have to be closed - FILETIME ft_dummy, ft_system, ft_user; - GetProcessTimes(self, &ft_dummy, &ft_dummy, &ft_system, &ft_user); - ULARGE_INTEGER uli; - uli.u.LowPart = ft_system.dwLowDateTime; - uli.u.HighPart = ft_system.dwHighDateTime; - metrics->mStartSTime = uli.QuadPart / U64L(10); // Convert to uS - uli.u.LowPart = ft_user.dwLowDateTime; - uli.u.HighPart = ft_user.dwHighDateTime; - metrics->mStartUTime = uli.QuadPart / U64L(10); - metrics->mStartWallTime = totalTime(); - } - - void sample(Metrics * metrics) - { - PROCESS_MEMORY_COUNTERS_EX counters; - - GetProcessMemoryInfo(GetCurrentProcess(), - (PROCESS_MEMORY_COUNTERS *) &counters, - sizeof(counters)); - // Okay, PrivateUsage isn't truly VSZ but it will be - // a good tracker for leaks and fragmentation. Work on - // a better estimator later... - SIZE_T vsz(counters.PrivateUsage); - metrics->mMaxVSZ = (std::max)(metrics->mMaxVSZ, U64(vsz)); - metrics->mMinVSZ = (std::min)(metrics->mMinVSZ, U64(vsz)); - } - - void term(Metrics * metrics) - { - HANDLE self(GetCurrentProcess()); // Does not have to be closed - FILETIME ft_dummy, ft_system, ft_user; - GetProcessTimes(self, &ft_dummy, &ft_dummy, &ft_system, &ft_user); - ULARGE_INTEGER uli; - uli.u.LowPart = ft_system.dwLowDateTime; - uli.u.HighPart = ft_system.dwHighDateTime; - metrics->mEndSTime = uli.QuadPart / U64L(10); - uli.u.LowPart = ft_user.dwLowDateTime; - uli.u.HighPart = ft_user.dwHighDateTime; - metrics->mEndUTime = uli.QuadPart / U64L(10); - metrics->mEndWallTime = totalTime(); - } + MetricsImpl() + {} + + ~MetricsImpl() + {} + + void init(Metrics * metrics) + { + HANDLE self(GetCurrentProcess()); // Does not have to be closed + FILETIME ft_dummy, ft_system, ft_user; + GetProcessTimes(self, &ft_dummy, &ft_dummy, &ft_system, &ft_user); + ULARGE_INTEGER uli; + uli.u.LowPart = ft_system.dwLowDateTime; + uli.u.HighPart = ft_system.dwHighDateTime; + metrics->mStartSTime = uli.QuadPart / U64L(10); // Convert to uS + uli.u.LowPart = ft_user.dwLowDateTime; + uli.u.HighPart = ft_user.dwHighDateTime; + metrics->mStartUTime = uli.QuadPart / U64L(10); + metrics->mStartWallTime = totalTime(); + } + + void sample(Metrics * metrics) + { + PROCESS_MEMORY_COUNTERS_EX counters; + + GetProcessMemoryInfo(GetCurrentProcess(), + (PROCESS_MEMORY_COUNTERS *) &counters, + sizeof(counters)); + // Okay, PrivateUsage isn't truly VSZ but it will be + // a good tracker for leaks and fragmentation. Work on + // a better estimator later... + SIZE_T vsz(counters.PrivateUsage); + metrics->mMaxVSZ = (std::max)(metrics->mMaxVSZ, U64(vsz)); + metrics->mMinVSZ = (std::min)(metrics->mMinVSZ, U64(vsz)); + } + + void term(Metrics * metrics) + { + HANDLE self(GetCurrentProcess()); // Does not have to be closed + FILETIME ft_dummy, ft_system, ft_user; + GetProcessTimes(self, &ft_dummy, &ft_dummy, &ft_system, &ft_user); + ULARGE_INTEGER uli; + uli.u.LowPart = ft_system.dwLowDateTime; + uli.u.HighPart = ft_system.dwHighDateTime; + metrics->mEndSTime = uli.QuadPart / U64L(10); + uli.u.LowPart = ft_user.dwLowDateTime; + uli.u.HighPart = ft_user.dwHighDateTime; + metrics->mEndUTime = uli.QuadPart / U64L(10); + metrics->mEndWallTime = totalTime(); + } protected: }; @@ -780,82 +780,82 @@ protected: #include <sys/resource.h> #include <mach/mach.h> - + class Metrics::MetricsImpl { public: - MetricsImpl() - {} - - ~MetricsImpl() - {} - - void init(Metrics * metrics) - { - U64 utime, stime; - - if (getTimes(&utime, &stime)) - { - metrics->mStartSTime = stime; - metrics->mStartUTime = utime; - } - metrics->mStartWallTime = totalTime(); - sample(metrics); - } - - void sample(Metrics * metrics) - { - U64 vsz; - - if (getVM(&vsz)) - { - metrics->mMaxVSZ = (std::max)(metrics->mMaxVSZ, vsz); - metrics->mMinVSZ = (std::min)(metrics->mMinVSZ, vsz); - } - } - - void term(Metrics * metrics) - { - U64 utime, stime; - - if (getTimes(&utime, &stime)) - { - metrics->mEndSTime = stime; - metrics->mEndUTime = utime; - } - metrics->mEndWallTime = totalTime(); - } + MetricsImpl() + {} + + ~MetricsImpl() + {} + + void init(Metrics * metrics) + { + U64 utime, stime; + + if (getTimes(&utime, &stime)) + { + metrics->mStartSTime = stime; + metrics->mStartUTime = utime; + } + metrics->mStartWallTime = totalTime(); + sample(metrics); + } + + void sample(Metrics * metrics) + { + U64 vsz; + + if (getVM(&vsz)) + { + metrics->mMaxVSZ = (std::max)(metrics->mMaxVSZ, vsz); + metrics->mMinVSZ = (std::min)(metrics->mMinVSZ, vsz); + } + } + + void term(Metrics * metrics) + { + U64 utime, stime; + + if (getTimes(&utime, &stime)) + { + metrics->mEndSTime = stime; + metrics->mEndUTime = utime; + } + metrics->mEndWallTime = totalTime(); + } protected: - bool getVM(U64 * vsz) - { - task_basic_info task_info_block; - mach_msg_type_number_t task_info_count(TASK_BASIC_INFO_COUNT); - - if (KERN_SUCCESS != task_info(mach_task_self(), - TASK_BASIC_INFO, - (task_info_t) &task_info_block, - &task_info_count)) - { - return false; - } - * vsz = task_info_block.virtual_size; - return true; - } - - bool getTimes(U64 * utime, U64 * stime) - { - struct rusage usage; - - if (getrusage(RUSAGE_SELF, &usage)) - { - return false; - } - * utime = U64(usage.ru_utime.tv_sec) * U64L(1000000) + usage.ru_utime.tv_usec; - * stime = U64(usage.ru_stime.tv_sec) * U64L(1000000) + usage.ru_stime.tv_usec; - return true; - } - + bool getVM(U64 * vsz) + { + task_basic_info task_info_block; + mach_msg_type_number_t task_info_count(TASK_BASIC_INFO_COUNT); + + if (KERN_SUCCESS != task_info(mach_task_self(), + TASK_BASIC_INFO, + (task_info_t) &task_info_block, + &task_info_count)) + { + return false; + } + * vsz = task_info_block.virtual_size; + return true; + } + + bool getTimes(U64 * utime, U64 * stime) + { + struct rusage usage; + + if (getrusage(RUSAGE_SELF, &usage)) + { + return false; + } + * utime = U64(usage.ru_utime.tv_sec) * U64L(1000000) + usage.ru_utime.tv_usec; + * stime = U64(usage.ru_stime.tv_sec) * U64L(1000000) + usage.ru_stime.tv_usec; + return true; + } + }; #else @@ -863,198 +863,198 @@ protected: class Metrics::MetricsImpl { public: - MetricsImpl() - : mProcFS(NULL), - mUsecsPerTick(U64L(0)) - {} - - - ~MetricsImpl() - { - if (mProcFS) - { - fclose(mProcFS); - mProcFS = NULL; - } - } - - void init(Metrics * metrics) - { - if (! mProcFS) - { - mProcFS = fopen("/proc/self/stat", "r"); - if (! mProcFS) - { - const int errnum(errno); - LL_ERRS("Main") << "Error opening proc fs: " << strerror(errnum) << LL_ENDL; - } - } - - long ticks_per_sec(sysconf(_SC_CLK_TCK)); - mUsecsPerTick = U64L(1000000) / ticks_per_sec; - U64 usecs_per_sec(mUsecsPerTick * ticks_per_sec); - if (900000 > usecs_per_sec || 1100000 < usecs_per_sec) - { - LL_ERRS("Main") << "Resolution problems using uSecs for ticks" << LL_ENDL; - } - - U64 utime, stime; - if (scanProcFS(&utime, &stime, NULL)) - { - metrics->mStartSTime = stime; - metrics->mStartUTime = utime; - } - metrics->mStartWallTime = totalTime(); - - sample(metrics); - } - - - void sample(Metrics * metrics) - { - U64 vsz; - if (scanProcFS(NULL, NULL, &vsz)) - { - metrics->mMaxVSZ = (std::max)(metrics->mMaxVSZ, vsz); - metrics->mMinVSZ = (std::min)(metrics->mMinVSZ, vsz); - } - } - - - void term(Metrics * metrics) - { - U64 utime, stime; - if (scanProcFS(&utime, &stime, NULL)) - { - metrics->mEndSTime = stime; - metrics->mEndUTime = utime; - } - metrics->mEndWallTime = totalTime(); - - sample(metrics); - - if (mProcFS) - { - fclose(mProcFS); - mProcFS = NULL; - } - } - + MetricsImpl() + : mProcFS(NULL), + mUsecsPerTick(U64L(0)) + {} + + + ~MetricsImpl() + { + if (mProcFS) + { + fclose(mProcFS); + mProcFS = NULL; + } + } + + void init(Metrics * metrics) + { + if (! mProcFS) + { + mProcFS = fopen("/proc/self/stat", "r"); + if (! mProcFS) + { + const int errnum(errno); + LL_ERRS("Main") << "Error opening proc fs: " << strerror(errnum) << LL_ENDL; + } + } + + long ticks_per_sec(sysconf(_SC_CLK_TCK)); + mUsecsPerTick = U64L(1000000) / ticks_per_sec; + U64 usecs_per_sec(mUsecsPerTick * ticks_per_sec); + if (900000 > usecs_per_sec || 1100000 < usecs_per_sec) + { + LL_ERRS("Main") << "Resolution problems using uSecs for ticks" << LL_ENDL; + } + + U64 utime, stime; + if (scanProcFS(&utime, &stime, NULL)) + { + metrics->mStartSTime = stime; + metrics->mStartUTime = utime; + } + metrics->mStartWallTime = totalTime(); + + sample(metrics); + } + + + void sample(Metrics * metrics) + { + U64 vsz; + if (scanProcFS(NULL, NULL, &vsz)) + { + metrics->mMaxVSZ = (std::max)(metrics->mMaxVSZ, vsz); + metrics->mMinVSZ = (std::min)(metrics->mMinVSZ, vsz); + } + } + + + void term(Metrics * metrics) + { + U64 utime, stime; + if (scanProcFS(&utime, &stime, NULL)) + { + metrics->mEndSTime = stime; + metrics->mEndUTime = utime; + } + metrics->mEndWallTime = totalTime(); + + sample(metrics); + + if (mProcFS) + { + fclose(mProcFS); + mProcFS = NULL; + } + } + protected: - bool scanProcFS(U64 * utime, U64 * stime, U64 * vsz) - { - if (mProcFS) - { - int i_dummy; - unsigned int ui_dummy; - unsigned long ul_dummy, user_ticks, sys_ticks, vsize; - long l_dummy, rss; - unsigned long long ull_dummy; - char c_dummy; - - char buffer[256]; - - static const char * format("%d %*s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %llu %lu %ld"); - - fseek(mProcFS, 0L, SEEK_SET); - size_t len = fread(buffer, 1, sizeof(buffer) - 1, mProcFS); - if (! len) - { - return false; - } - buffer[len] = '\0'; - if (23 == sscanf(buffer, format, - &i_dummy, // pid - // &s_dummy, // command name - &c_dummy, // state - &i_dummy, // ppid - &i_dummy, // pgrp - &i_dummy, // session - &i_dummy, // terminal - &i_dummy, // terminal group id - &ui_dummy, // flags - &ul_dummy, // minor faults - &ul_dummy, // minor faults in children - &ul_dummy, // major faults - &ul_dummy, // major faults in children - &user_ticks, - &sys_ticks, - &l_dummy, // cutime - &l_dummy, // cstime - &l_dummy, // process priority - &l_dummy, // nice value - &l_dummy, // thread count - &l_dummy, // time to SIGALRM - &ull_dummy, // start time - &vsize, - &rss)) - { - // Looks like we understand the line - if (utime) - { - *utime = user_ticks * mUsecsPerTick; - } - - if (stime) - { - *stime = sys_ticks * mUsecsPerTick; - } - - if (vsz) - { - *vsz = vsize; - } - return true; - } - } - return false; - } - + bool scanProcFS(U64 * utime, U64 * stime, U64 * vsz) + { + if (mProcFS) + { + int i_dummy; + unsigned int ui_dummy; + unsigned long ul_dummy, user_ticks, sys_ticks, vsize; + long l_dummy, rss; + unsigned long long ull_dummy; + char c_dummy; + + char buffer[256]; + + static const char * format("%d %*s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %llu %lu %ld"); + + fseek(mProcFS, 0L, SEEK_SET); + size_t len = fread(buffer, 1, sizeof(buffer) - 1, mProcFS); + if (! len) + { + return false; + } + buffer[len] = '\0'; + if (23 == sscanf(buffer, format, + &i_dummy, // pid + // &s_dummy, // command name + &c_dummy, // state + &i_dummy, // ppid + &i_dummy, // pgrp + &i_dummy, // session + &i_dummy, // terminal + &i_dummy, // terminal group id + &ui_dummy, // flags + &ul_dummy, // minor faults + &ul_dummy, // minor faults in children + &ul_dummy, // major faults + &ul_dummy, // major faults in children + &user_ticks, + &sys_ticks, + &l_dummy, // cutime + &l_dummy, // cstime + &l_dummy, // process priority + &l_dummy, // nice value + &l_dummy, // thread count + &l_dummy, // time to SIGALRM + &ull_dummy, // start time + &vsize, + &rss)) + { + // Looks like we understand the line + if (utime) + { + *utime = user_ticks * mUsecsPerTick; + } + + if (stime) + { + *stime = sys_ticks * mUsecsPerTick; + } + + if (vsz) + { + *vsz = vsize; + } + return true; + } + } + return false; + } + protected: - FILE * mProcFS; - U64 mUsecsPerTick; - + FILE * mProcFS; + U64 mUsecsPerTick; + }; #endif // LL_WINDOWS Metrics::Metrics() - : mMaxVSZ(U64(0)), - mMinVSZ(U64L(0xffffffffffffffff)), - mStartWallTime(U64(0)), - mEndWallTime(U64(0)), - mStartUTime(U64(0)), - mEndUTime(U64(0)), - mStartSTime(U64(0)), - mEndSTime(U64(0)) + : mMaxVSZ(U64(0)), + mMinVSZ(U64L(0xffffffffffffffff)), + mStartWallTime(U64(0)), + mEndWallTime(U64(0)), + mStartUTime(U64(0)), + mEndUTime(U64(0)), + mStartSTime(U64(0)), + mEndSTime(U64(0)) { - mImpl = new MetricsImpl(); + mImpl = new MetricsImpl(); } Metrics::~Metrics() { - delete mImpl; - mImpl = NULL; + delete mImpl; + mImpl = NULL; } void Metrics::init() { - mImpl->init(this); + mImpl->init(this); } void Metrics::sample() { - mImpl->sample(this); + mImpl->sample(this); } void Metrics::term() { - mImpl->term(this); + mImpl->term(this); } - + diff --git a/indra/llcorehttp/httpcommon.cpp b/indra/llcorehttp/httpcommon.cpp index 61ba83594e..315ff15ebb 100644 --- a/indra/llcorehttp/httpcommon.cpp +++ b/indra/llcorehttp/httpcommon.cpp @@ -1,6 +1,6 @@ /** * @file httpcommon.cpp - * @brief + * @brief * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Second Life Viewer Source Code @@ -24,7 +24,7 @@ * $/LicenseInfo$ */ -#include "linden_common.h" // Modifies curl/curl.h interfaces +#include "linden_common.h" // Modifies curl/curl.h interfaces #include "httpcommon.h" #include "llmutex.h" #include "llthread.h" @@ -42,184 +42,184 @@ HttpStatus::type_enum_t LLCORE; HttpStatus::operator U32() const { - // Effectively, concatenate mType (high) with mStatus (low). - static const int shift(sizeof(mDetails->mStatus) * 8); + // Effectively, concatenate mType (high) with mStatus (low). + static const int shift(sizeof(mDetails->mStatus) * 8); - U32 result(U32(mDetails->mType) << shift | U32((int)mDetails->mStatus)); - return result; + U32 result(U32(mDetails->mType) << shift | U32((int)mDetails->mStatus)); + return result; } std::string HttpStatus::toHex() const { - std::ostringstream result; - result.width(8); - result.fill('0'); - result << std::hex << operator U32(); - return result.str(); + std::ostringstream result; + result.width(8); + result.fill('0'); + result << std::hex << operator U32(); + return result.str(); } std::string HttpStatus::toString() const { - static const char * llcore_errors[] = - { - "", - "HTTP error reply status", - "Services shutting down", - "Operation canceled", - "Invalid Content-Range header encountered", - "Request handle not found", - "Invalid datatype for argument or option", - "Option has not been explicitly set", - "Option is not dynamic and must be set early", - "Invalid HTTP status code received from server", - "Could not allocate required resource" - }; - static const int llcore_errors_count(sizeof(llcore_errors) / sizeof(llcore_errors[0])); - - static const struct - { - type_enum_t mCode; - const char * mText; - } - http_errors[] = - { - // Keep sorted by mCode, we binary search this list. - { 100, "Continue" }, - { 101, "Switching Protocols" }, - { 200, "OK" }, - { 201, "Created" }, - { 202, "Accepted" }, - { 203, "Non-Authoritative Information" }, - { 204, "No Content" }, - { 205, "Reset Content" }, - { 206, "Partial Content" }, - { 300, "Multiple Choices" }, - { 301, "Moved Permanently" }, - { 302, "Found" }, - { 303, "See Other" }, - { 304, "Not Modified" }, - { 305, "Use Proxy" }, - { 307, "Temporary Redirect" }, - { 400, "Bad Request" }, - { 401, "Unauthorized" }, - { 402, "Payment Required" }, - { 403, "Forbidden" }, - { 404, "Not Found" }, - { 405, "Method Not Allowed" }, - { 406, "Not Acceptable" }, - { 407, "Proxy Authentication Required" }, - { 408, "Request Time-out" }, - { 409, "Conflict" }, - { 410, "Gone" }, - { 411, "Length Required" }, - { 412, "Precondition Failed" }, - { 413, "Request Entity Too Large" }, - { 414, "Request-URI Too Large" }, - { 415, "Unsupported Media Type" }, - { 416, "Requested range not satisfiable" }, - { 417, "Expectation Failed" }, - { 499, "Linden Catch-All" }, - { 500, "Internal Server Error" }, - { 501, "Not Implemented" }, - { 502, "Bad Gateway" }, - { 503, "Service Unavailable" }, - { 504, "Gateway Time-out" }, - { 505, "HTTP Version not supported" } - }; - static const int http_errors_count(sizeof(http_errors) / sizeof(http_errors[0])); - - if (*this) - { - return std::string(""); - } - switch (getType()) - { - case EXT_CURL_EASY: - return std::string(curl_easy_strerror(CURLcode(getStatus()))); - - case EXT_CURL_MULTI: - return std::string(curl_multi_strerror(CURLMcode(getStatus()))); - - case LLCORE: - if (getStatus() >= 0 && getStatus() < llcore_errors_count) - { - 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 (getType() == http_errors[at].mCode) - { - return std::string(http_errors[at].mText); - } - if (at == bottom) - { - break; - } - else if (getType() < http_errors[at].mCode) - { - top = at; - } - else - { - bottom = at; - } - } - } - break; - } - return std::string("Unknown error"); + static const char * llcore_errors[] = + { + "", + "HTTP error reply status", + "Services shutting down", + "Operation canceled", + "Invalid Content-Range header encountered", + "Request handle not found", + "Invalid datatype for argument or option", + "Option has not been explicitly set", + "Option is not dynamic and must be set early", + "Invalid HTTP status code received from server", + "Could not allocate required resource" + }; + static const int llcore_errors_count(sizeof(llcore_errors) / sizeof(llcore_errors[0])); + + static const struct + { + type_enum_t mCode; + const char * mText; + } + http_errors[] = + { + // Keep sorted by mCode, we binary search this list. + { 100, "Continue" }, + { 101, "Switching Protocols" }, + { 200, "OK" }, + { 201, "Created" }, + { 202, "Accepted" }, + { 203, "Non-Authoritative Information" }, + { 204, "No Content" }, + { 205, "Reset Content" }, + { 206, "Partial Content" }, + { 300, "Multiple Choices" }, + { 301, "Moved Permanently" }, + { 302, "Found" }, + { 303, "See Other" }, + { 304, "Not Modified" }, + { 305, "Use Proxy" }, + { 307, "Temporary Redirect" }, + { 400, "Bad Request" }, + { 401, "Unauthorized" }, + { 402, "Payment Required" }, + { 403, "Forbidden" }, + { 404, "Not Found" }, + { 405, "Method Not Allowed" }, + { 406, "Not Acceptable" }, + { 407, "Proxy Authentication Required" }, + { 408, "Request Time-out" }, + { 409, "Conflict" }, + { 410, "Gone" }, + { 411, "Length Required" }, + { 412, "Precondition Failed" }, + { 413, "Request Entity Too Large" }, + { 414, "Request-URI Too Large" }, + { 415, "Unsupported Media Type" }, + { 416, "Requested range not satisfiable" }, + { 417, "Expectation Failed" }, + { 499, "Linden Catch-All" }, + { 500, "Internal Server Error" }, + { 501, "Not Implemented" }, + { 502, "Bad Gateway" }, + { 503, "Service Unavailable" }, + { 504, "Gateway Time-out" }, + { 505, "HTTP Version not supported" } + }; + static const int http_errors_count(sizeof(http_errors) / sizeof(http_errors[0])); + + if (*this) + { + return std::string(""); + } + switch (getType()) + { + case EXT_CURL_EASY: + return std::string(curl_easy_strerror(CURLcode(getStatus()))); + + case EXT_CURL_MULTI: + return std::string(curl_multi_strerror(CURLMcode(getStatus()))); + + case LLCORE: + if (getStatus() >= 0 && getStatus() < llcore_errors_count) + { + 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 (getType() == http_errors[at].mCode) + { + return std::string(http_errors[at].mText); + } + if (at == bottom) + { + break; + } + else if (getType() < http_errors[at].mCode) + { + top = at; + } + else + { + bottom = at; + } + } + } + break; + } + return std::string("Unknown error"); } std::string HttpStatus::toTerseString() const { - std::ostringstream result; - - unsigned int error_value((unsigned short)getStatus()); - - switch (getType()) - { - case EXT_CURL_EASY: - result << "Easy_"; - break; - - case EXT_CURL_MULTI: - result << "Multi_"; - break; - - case LLCORE: - result << "Core_"; - break; - - default: - if (isHttpStatus()) - { - result << "Http_"; - error_value = getType(); - } - else - { - result << "Unknown_"; - } - break; - } - - result << error_value; - return result.str(); + std::ostringstream result; + + unsigned int error_value((unsigned short)getStatus()); + + switch (getType()) + { + case EXT_CURL_EASY: + result << "Easy_"; + break; + + case EXT_CURL_MULTI: + result << "Multi_"; + break; + + case LLCORE: + result << "Core_"; + break; + + default: + if (isHttpStatus()) + { + result << "Http_"; + error_value = getType(); + } + else + { + result << "Unknown_"; + } + break; + } + + result << error_value; + return result.str(); } @@ -235,35 +235,35 @@ std::string HttpStatus::toTerseString() const // for details. bool HttpStatus::isRetryable() const { - static const HttpStatus cant_connect(HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_CONNECT); - static const HttpStatus cant_res_proxy(HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_RESOLVE_PROXY); - static const HttpStatus cant_res_host(HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_RESOLVE_HOST); - static const HttpStatus send_error(HttpStatus::EXT_CURL_EASY, CURLE_SEND_ERROR); - static const HttpStatus recv_error(HttpStatus::EXT_CURL_EASY, CURLE_RECV_ERROR); - static const HttpStatus upload_failed(HttpStatus::EXT_CURL_EASY, CURLE_UPLOAD_FAILED); - static const HttpStatus op_timedout(HttpStatus::EXT_CURL_EASY, CURLE_OPERATION_TIMEDOUT); - static const HttpStatus post_error(HttpStatus::EXT_CURL_EASY, CURLE_HTTP_POST_ERROR); - static const HttpStatus partial_file(HttpStatus::EXT_CURL_EASY, CURLE_PARTIAL_FILE); - static const HttpStatus inv_cont_range(HttpStatus::LLCORE, HE_INV_CONTENT_RANGE_HDR); - static const HttpStatus inv_status(HttpStatus::LLCORE, HE_INVALID_HTTP_STATUS); - - // *DEBUG: For "[curl:bugs] #1420" tests. - // Disable the '*this == inv_status' test and look for 'Core_9' - // failures in log files. - - 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 - *this == send_error || // General socket problems - *this == recv_error || // General socket problems - *this == upload_failed || // Transport problem - *this == op_timedout || // Timer expired - *this == post_error || // Transport problem - *this == partial_file || // Data inconsistency in response - // *DEBUG: Comment out 'inv_status' test for [curl:bugs] #1420 testing. - *this == inv_status || // Inv status can reflect internal state problem in libcurl - *this == inv_cont_range); // Short data read disagrees with content-range + static const HttpStatus cant_connect(HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_CONNECT); + static const HttpStatus cant_res_proxy(HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_RESOLVE_PROXY); + static const HttpStatus cant_res_host(HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_RESOLVE_HOST); + static const HttpStatus send_error(HttpStatus::EXT_CURL_EASY, CURLE_SEND_ERROR); + static const HttpStatus recv_error(HttpStatus::EXT_CURL_EASY, CURLE_RECV_ERROR); + static const HttpStatus upload_failed(HttpStatus::EXT_CURL_EASY, CURLE_UPLOAD_FAILED); + static const HttpStatus op_timedout(HttpStatus::EXT_CURL_EASY, CURLE_OPERATION_TIMEDOUT); + static const HttpStatus post_error(HttpStatus::EXT_CURL_EASY, CURLE_HTTP_POST_ERROR); + static const HttpStatus partial_file(HttpStatus::EXT_CURL_EASY, CURLE_PARTIAL_FILE); + static const HttpStatus inv_cont_range(HttpStatus::LLCORE, HE_INV_CONTENT_RANGE_HDR); + static const HttpStatus inv_status(HttpStatus::LLCORE, HE_INVALID_HTTP_STATUS); + + // *DEBUG: For "[curl:bugs] #1420" tests. + // Disable the '*this == inv_status' test and look for 'Core_9' + // failures in log files. + + 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 + *this == send_error || // General socket problems + *this == recv_error || // General socket problems + *this == upload_failed || // Transport problem + *this == op_timedout || // Timer expired + *this == post_error || // Transport problem + *this == partial_file || // Data inconsistency in response + // *DEBUG: Comment out 'inv_status' test for [curl:bugs] #1420 testing. + *this == inv_status || // Inv status can reflect internal state problem in libcurl + *this == inv_cont_range); // Short data read disagrees with content-range } namespace LLHttp @@ -275,7 +275,7 @@ CURL *getCurlTemplateHandle() static CURL *curlpTemplateHandle = NULL; if (curlpTemplateHandle == NULL) - { // Late creation of the template curl handle + { // Late creation of the template curl handle curlpTemplateHandle = curl_easy_init(); if (curlpTemplateHandle == NULL) { @@ -313,7 +313,7 @@ CURL *getCurlTemplateHandle() return curlpTemplateHandle; } - + LLMutex *getCurlMutex() { static LLMutex* sHandleMutexp = NULL; @@ -338,7 +338,7 @@ void deallocateEasyCurl(CURL *curlp) void initialize() { - // Do not change this "unless you are familiar with and mean to control + // 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); diff --git a/indra/llcorehttp/httpcommon.h b/indra/llcorehttp/httpcommon.h index 7fe5c48edf..0a1c5ed101 100644 --- a/indra/llcorehttp/httpcommon.h +++ b/indra/llcorehttp/httpcommon.h @@ -24,8 +24,8 @@ * $/LicenseInfo$ */ -#ifndef _LLCORE_HTTP_COMMON_H_ -#define _LLCORE_HTTP_COMMON_H_ +#ifndef _LLCORE_HTTP_COMMON_H_ +#define _LLCORE_HTTP_COMMON_H_ /// @package LLCore::HTTP /// @@ -42,7 +42,7 @@ /// - Scatter/gather (a.k.a. buffer array) model for bulk data movement. /// - Reference counting used for many object instance lifetimes. /// - Minimal data sharing across threads for correctness and low latency. -/// +/// /// The public interface is declared in a few key header files: /// - "llcorehttp/bufferarray.h" /// - "llcorehttp/httpcommon.h" @@ -100,7 +100,7 @@ /// yet functional tool to do GET request performance testing. /// With four calls: /// -/// init_curl(); +/// init_curl(); /// LLCore::HttpRequest::createService(); /// LLCore::HttpRequest::startThread(); /// LLCore::HttpRequest * hr = new LLCore::HttpRequest(); @@ -133,9 +133,9 @@ /// Issuing requests. Using 'hr' above, /// /// hr->requestGet(HttpRequest::DEFAULT_POLICY_ID, -/// 0, // Priority, not used yet +/// 0, // Priority, not used yet /// url, -/// NULL, // options +/// NULL, // options /// NULL, // additional headers /// handler); /// @@ -162,11 +162,11 @@ /// constraints which programmers must follow and which are /// defined as follows: /// -/// consumer Any thread that has instanced HttpRequest and is +/// consumer Any thread that has instanced HttpRequest and is /// issuing requests. A particular instance can only /// be used by one consumer thread but a consumer may /// have many instances available to it. -/// init Special consumer thread, usually the main thread, +/// init Special consumer thread, usually the main thread, /// involved in setting up the library at startup. /// worker Thread used internally by the library to perform /// HTTP operations. Consumers will not have to deal @@ -187,7 +187,7 @@ /// only here are mutexes used. /// -#include "linden_common.h" // Modifies curl/curl.h interfaces +#include "linden_common.h" // Modifies curl/curl.h interfaces #include "llsd.h" #include "boost/intrusive_ptr.hpp" #include "boost/shared_ptr.hpp" @@ -212,7 +212,7 @@ namespace LLCore typedef void * HttpHandle; -#define LLCORE_HTTP_HANDLE_INVALID (NULL) +#define LLCORE_HTTP_HANDLE_INVALID (NULL) /// For internal scheduling and metrics, we use a microsecond /// timebase compatible with the environment. @@ -222,41 +222,41 @@ typedef U64 HttpTime; /// libcurl (or any other transport provider). enum HttpError { - // Successful value compatible with the libcurl codes. - HE_SUCCESS = 0, - - // Intended for HTTP reply codes 100-999, indicates that - // the reply should be considered an error by the application. - HE_REPLY_ERROR = 1, - - // Service is shutting down and requested operation will - // not be queued or performed. - HE_SHUTTING_DOWN = 2, - - // Operation was canceled by request. - HE_OP_CANCELED = 3, - - // Invalid content range header received. - HE_INV_CONTENT_RANGE_HDR = 4, - - // Request handle not found - HE_HANDLE_NOT_FOUND = 5, - - // Invalid datatype for option/setting - HE_INVALID_ARG = 6, - - // Option hasn't been explicitly set - HE_OPT_NOT_SET = 7, - - // Option not dynamic, must be set during init phase - HE_OPT_NOT_DYNAMIC = 8, - - // Invalid HTTP status code returned by server - HE_INVALID_HTTP_STATUS = 9, - - // Couldn't allocate resource, typically libcurl handle - HE_BAD_ALLOC = 10 - + // Successful value compatible with the libcurl codes. + HE_SUCCESS = 0, + + // Intended for HTTP reply codes 100-999, indicates that + // the reply should be considered an error by the application. + HE_REPLY_ERROR = 1, + + // Service is shutting down and requested operation will + // not be queued or performed. + HE_SHUTTING_DOWN = 2, + + // Operation was canceled by request. + HE_OP_CANCELED = 3, + + // Invalid content range header received. + HE_INV_CONTENT_RANGE_HDR = 4, + + // Request handle not found + HE_HANDLE_NOT_FOUND = 5, + + // Invalid datatype for option/setting + HE_INVALID_ARG = 6, + + // Option hasn't been explicitly set + HE_OPT_NOT_SET = 7, + + // Option not dynamic, must be set during init phase + HE_OPT_NOT_DYNAMIC = 8, + + // Invalid HTTP status code returned by server + HE_INVALID_HTTP_STATUS = 9, + + // Couldn't allocate resource, typically libcurl handle + HE_BAD_ALLOC = 10 + }; // end enum HttpError @@ -278,223 +278,223 @@ enum HttpError /// Examples: /// /// 1. Construct a default, successful status code: -/// HttpStatus(); +/// HttpStatus(); /// /// 2. Construct a successful, HTTP 200 status code: -/// HttpStatus(200); +/// HttpStatus(200); /// /// 3. Construct a failed, HTTP 404 not-found status code: -/// HttpStatus(404); +/// HttpStatus(404); /// /// 4. Construct a failed libcurl couldn't connect status code: -/// HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_CONNECT); +/// HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_CONNECT); /// /// 5. Construct an HTTP 301 status code to be treated as success: -/// HttpStatus(301, HE_SUCCESS); +/// HttpStatus(301, HE_SUCCESS); /// -/// 6. Construct a failed status of HTTP Status 499 with a custom error message -/// HttpStatus(499, "Failed LLSD Response"); +/// 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() - { - mDetails = std::shared_ptr<Details>(new Details(LLCORE, HE_SUCCESS)); + typedef unsigned short type_enum_t; + + HttpStatus() + { + mDetails = std::shared_ptr<Details>(new Details(LLCORE, HE_SUCCESS)); } - HttpStatus(type_enum_t type, short status) - { + HttpStatus(type_enum_t type, short status) + { mDetails = std::shared_ptr<Details>(new Details(type, status)); - } - - HttpStatus(int http_status) - { - mDetails = std::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) - { + } + + HttpStatus(int http_status) + { mDetails = std::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) - { - mDetails = rhs.mDetails; - } - - ~HttpStatus() - { - } - - HttpStatus & operator=(const HttpStatus & rhs) - { + (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 = std::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) + { + mDetails = rhs.mDetails; + } + + ~HttpStatus() + { + } + + HttpStatus & operator=(const HttpStatus & rhs) + { mDetails = rhs.mDetails; - return *this; - } + return *this; + } HttpStatus & clone(const HttpStatus &rhs) { mDetails = std::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 - /// Test for successful status in the code regardless - /// of error source (internal, libcurl). - /// - /// @return 'true' when status is successful. - /// - operator bool() const - { - return 0 == mDetails->mStatus; - } - - /// Inverse of previous operator. - /// - /// @return 'true' on any error condition - bool operator !() const - { - 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 (*mDetails == *rhs.mDetails); - } - - bool operator!=(const HttpStatus & rhs) const - { - return ! operator==(rhs); - } - - /// Convert to single numeric representation. Mainly - /// for logging or other informal purposes. Also - /// creates an ambiguous second path to integer conversion - /// which tends to find programming errors such as formatting - /// the status to a stream (operator<<). - operator U32() const; - U32 toULong() const - { - return operator U32(); - } - - /// And to convert to a hex string. - std::string toHex() const; - - /// Convert status to a string representation. For - /// success, returns an empty string. For failure - /// statuses, a string as appropriate for the source of - /// the error code (libcurl easy, libcurl multi, or - /// LLCore itself). - std::string toString() const; - - /// Convert status to a compact string representation - /// of the form: "<type>_<value>". The <type> will be - /// one of: Core, Http, Easy, Multi, Unknown. And - /// <value> will be an unsigned integer. More easily - /// interpreted than the hex representation, it's still - /// compact and easily searched. - std::string toTerseString() const; - - /// Returns true if the status value represents an - /// HTTP response status (100 - 999). - bool isHttpStatus() const - { - return mDetails->mType >= type_enum_t(100) && mDetails->mType <= type_enum_t(999); - } - - /// Returns true if the status is one that will be retried - /// internally. Provided for external consumption for cases - /// 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 data about an optionally recorded SSL certificate. - LLSD getErrorData() const - { - return mDetails->mErrorData; - } - - /// Optionally sets an SSL certificate on this status. - void setErrorData(LLSD data) - { - mDetails->mErrorData = data; - } + + 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 + /// Test for successful status in the code regardless + /// of error source (internal, libcurl). + /// + /// @return 'true' when status is successful. + /// + operator bool() const + { + return 0 == mDetails->mStatus; + } + + /// Inverse of previous operator. + /// + /// @return 'true' on any error condition + bool operator !() const + { + 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 (*mDetails == *rhs.mDetails); + } + + bool operator!=(const HttpStatus & rhs) const + { + return ! operator==(rhs); + } + + /// Convert to single numeric representation. Mainly + /// for logging or other informal purposes. Also + /// creates an ambiguous second path to integer conversion + /// which tends to find programming errors such as formatting + /// the status to a stream (operator<<). + operator U32() const; + U32 toULong() const + { + return operator U32(); + } + + /// And to convert to a hex string. + std::string toHex() const; + + /// Convert status to a string representation. For + /// success, returns an empty string. For failure + /// statuses, a string as appropriate for the source of + /// the error code (libcurl easy, libcurl multi, or + /// LLCore itself). + std::string toString() const; + + /// Convert status to a compact string representation + /// of the form: "<type>_<value>". The <type> will be + /// one of: Core, Http, Easy, Multi, Unknown. And + /// <value> will be an unsigned integer. More easily + /// interpreted than the hex representation, it's still + /// compact and easily searched. + std::string toTerseString() const; + + /// Returns true if the status value represents an + /// HTTP response status (100 - 999). + bool isHttpStatus() const + { + return mDetails->mType >= type_enum_t(100) && mDetails->mType <= type_enum_t(999); + } + + /// Returns true if the status is one that will be retried + /// internally. Provided for external consumption for cases + /// 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 data about an optionally recorded SSL certificate. + LLSD getErrorData() const + { + return mDetails->mErrorData; + } + + /// Optionally sets an SSL certificate on this status. + void setErrorData(LLSD data) + { + mDetails->mErrorData = data; + } private: - struct Details - { - Details(type_enum_t type, short status): - mType(type), - mStatus(status), - mMessage(), - mErrorData() - {} - - Details(const Details &rhs) : - mType(rhs.mType), - mStatus(rhs.mStatus), - mMessage(rhs.mMessage), - mErrorData(rhs.mErrorData) - {} + struct Details + { + Details(type_enum_t type, short status): + mType(type), + mStatus(status), + mMessage(), + mErrorData() + {} + + 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; - LLSD mErrorData; - }; + type_enum_t mType; + short mStatus; + std::string mMessage; + LLSD mErrorData; + }; std::shared_ptr<Details> mDetails; }; // end struct HttpStatus -/// A namespace for several free methods and low level utilities. +/// A namespace for several free methods and low level utilities. namespace LLHttp { typedef std::shared_ptr<CURL> CURL_ptr; @@ -510,4 +510,4 @@ namespace LLHttp } // end namespace LLCore -#endif // _LLCORE_HTTP_COMMON_H_ +#endif // _LLCORE_HTTP_COMMON_H_ diff --git a/indra/llcorehttp/httphandler.h b/indra/llcorehttp/httphandler.h index 4cfb2598c7..1bc1e9cfac 100644 --- a/indra/llcorehttp/httphandler.h +++ b/indra/llcorehttp/httphandler.h @@ -24,8 +24,8 @@ * $/LicenseInfo$ */ -#ifndef _LLCORE_HTTP_HANDLER_H_ -#define _LLCORE_HTTP_HANDLER_H_ +#ifndef _LLCORE_HTTP_HANDLER_H_ +#define _LLCORE_HTTP_HANDLER_H_ #include "httpcommon.h" @@ -55,38 +55,38 @@ class HttpResponse; /// dangling pointer if lifetimes aren't managed correctly. /// /// *TODO: public std::enable_shared_from_this<HttpHandler> -class HttpHandler +class HttpHandler { public: typedef std::shared_ptr<HttpHandler> ptr_t; typedef std::weak_ptr<HttpHandler> wptr_t; - virtual ~HttpHandler() - { } + virtual ~HttpHandler() + { } - /// Method invoked during calls to @see update(). Each invocation - /// represents the completion of some requested operation. Caller - /// can identify the request from the handle and interrogate the - /// response argument for success/failure, data and other information. - /// - /// @param handle Identifier of the request generating - /// the notification. - /// @param response Supplies detailed information about - /// the request including status codes - /// (both programming and HTTP), HTTP body - /// data and encodings, headers, etc. - /// The response object is refcounted and - /// the called code may retain the object - /// by invoking @see addRef() on it. The - /// library itself drops all references to - /// to object on return and never touches - /// it again. - /// - virtual void onCompleted(HttpHandle handle, HttpResponse * response) = 0; + /// Method invoked during calls to @see update(). Each invocation + /// represents the completion of some requested operation. Caller + /// can identify the request from the handle and interrogate the + /// response argument for success/failure, data and other information. + /// + /// @param handle Identifier of the request generating + /// the notification. + /// @param response Supplies detailed information about + /// the request including status codes + /// (both programming and HTTP), HTTP body + /// data and encodings, headers, etc. + /// The response object is refcounted and + /// the called code may retain the object + /// by invoking @see addRef() on it. The + /// library itself drops all references to + /// to object on return and never touches + /// it again. + /// + virtual void onCompleted(HttpHandle handle, HttpResponse * response) = 0; }; // end class HttpHandler } // end namespace LLCore -#endif // _LLCORE_HTTP_HANDLER_H_ +#endif // _LLCORE_HTTP_HANDLER_H_ diff --git a/indra/llcorehttp/httpheaders.cpp b/indra/llcorehttp/httpheaders.cpp index f586191a7c..6f1d0db370 100644 --- a/indra/llcorehttp/httpheaders.cpp +++ b/indra/llcorehttp/httpheaders.cpp @@ -44,61 +44,61 @@ HttpHeaders::~HttpHeaders() void HttpHeaders::clear() { - mHeaders.clear(); + mHeaders.clear(); } void HttpHeaders::append(const std::string & name, const std::string & value) { - mHeaders.push_back(value_type(name, value)); + mHeaders.push_back(value_type(name, value)); } void HttpHeaders::append(const char * name, const char * value) { - mHeaders.push_back(value_type(name, value)); + mHeaders.push_back(value_type(name, value)); } void HttpHeaders::appendNormal(const char * header, size_t size) { - std::string name; - std::string value; - - int col_pos(0); - for (; col_pos < size; ++col_pos) - { - if (':' == header[col_pos]) - break; - } - - if (col_pos < size) - { - // Looks like a header, split it and normalize. - // Name is everything before the colon, may be zero-length. - name.assign(header, col_pos); - - // Value is everything after the colon, may also be zero-length. - const size_t val_len(size - col_pos - 1); - if (val_len) - { - value.assign(header + col_pos + 1, val_len); - } - - // Clean the strings - LLStringUtil::toLower(name); - LLStringUtil::trim(name); - LLStringUtil::trimHead(value); - } - else - { - // Uncertain what this is, we'll pack it as - // a name without a value. Won't clean as we don't - // know what it is... - name.assign(header, size); - } - - mHeaders.push_back(value_type(name, value)); + std::string name; + std::string value; + + int col_pos(0); + for (; col_pos < size; ++col_pos) + { + if (':' == header[col_pos]) + break; + } + + if (col_pos < size) + { + // Looks like a header, split it and normalize. + // Name is everything before the colon, may be zero-length. + name.assign(header, col_pos); + + // Value is everything after the colon, may also be zero-length. + const size_t val_len(size - col_pos - 1); + if (val_len) + { + value.assign(header + col_pos + 1, val_len); + } + + // Clean the strings + LLStringUtil::toLower(name); + LLStringUtil::trim(name); + LLStringUtil::trimHead(value); + } + else + { + // Uncertain what this is, we'll pack it as + // a name without a value. Won't clean as we don't + // know what it is... + name.assign(header, size); + } + + mHeaders.push_back(value_type(name, value)); } @@ -106,15 +106,15 @@ void HttpHeaders::appendNormal(const char * header, size_t size) // std::map for this in the past. const std::string * HttpHeaders::find(const std::string &name) const { - const_reverse_iterator iend(rend()); - for (const_reverse_iterator iter(rbegin()); iend != iter; ++iter) - { - if ((*iter).first == name) - { - return &(*iter).second; - } - } - return NULL; + const_reverse_iterator iend(rend()); + for (const_reverse_iterator iter(rbegin()); iend != iter; ++iter) + { + if ((*iter).first == name) + { + return &(*iter).second; + } + } + return NULL; } void HttpHeaders::remove(const char *name) @@ -139,50 +139,50 @@ void HttpHeaders::remove(const std::string &name) // Standard Iterators HttpHeaders::iterator HttpHeaders::begin() { - return mHeaders.begin(); + return mHeaders.begin(); } HttpHeaders::const_iterator HttpHeaders::begin() const { - return mHeaders.begin(); + return mHeaders.begin(); } HttpHeaders::iterator HttpHeaders::end() { - return mHeaders.end(); + return mHeaders.end(); } HttpHeaders::const_iterator HttpHeaders::end() const { - return mHeaders.end(); + return mHeaders.end(); } // Standard Reverse Iterators HttpHeaders::reverse_iterator HttpHeaders::rbegin() { - return mHeaders.rbegin(); + return mHeaders.rbegin(); } HttpHeaders::const_reverse_iterator HttpHeaders::rbegin() const { - return mHeaders.rbegin(); + return mHeaders.rbegin(); } HttpHeaders::reverse_iterator HttpHeaders::rend() { - return mHeaders.rend(); + return mHeaders.rend(); } HttpHeaders::const_reverse_iterator HttpHeaders::rend() const { - return mHeaders.rend(); + return mHeaders.rend(); } @@ -192,7 +192,7 @@ HttpHeaders::const_reverse_iterator HttpHeaders::rend() const // HttpHeaders::container_t & HttpHeaders::getContainerTESTONLY() { - return mHeaders; + return mHeaders; } diff --git a/indra/llcorehttp/httpheaders.h b/indra/llcorehttp/httpheaders.h index e7cf4037bf..a5ca7749b0 100644 --- a/indra/llcorehttp/httpheaders.h +++ b/indra/llcorehttp/httpheaders.h @@ -24,8 +24,8 @@ * $/LicenseInfo$ */ -#ifndef _LLCORE_HTTP_HEADERS_H_ -#define _LLCORE_HTTP_HEADERS_H_ +#ifndef _LLCORE_HTTP_HEADERS_H_ +#define _LLCORE_HTTP_HEADERS_H_ #include "httpcommon.h" @@ -77,115 +77,115 @@ namespace LLCore class HttpHeaders: private boost::noncopyable { public: - typedef std::pair<std::string, std::string> header_t; - typedef std::vector<header_t> container_t; - typedef container_t::iterator iterator; - typedef container_t::const_iterator const_iterator; - typedef container_t::reverse_iterator reverse_iterator; - typedef container_t::const_reverse_iterator const_reverse_iterator; - typedef container_t::value_type value_type; - typedef container_t::size_type size_type; + typedef std::pair<std::string, std::string> header_t; + typedef std::vector<header_t> container_t; + typedef container_t::iterator iterator; + typedef container_t::const_iterator const_iterator; + typedef container_t::reverse_iterator reverse_iterator; + typedef container_t::const_reverse_iterator const_reverse_iterator; + typedef container_t::value_type value_type; + typedef container_t::size_type size_type; typedef std::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() + /// @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; + //typedef LLCoreInt::IntrusivePtr<HttpHeaders> ptr_t; protected: - HttpHeaders(const HttpHeaders &); // Not defined - void operator=(const HttpHeaders &); // Not defined + HttpHeaders(const HttpHeaders &); // Not defined + void operator=(const HttpHeaders &); // Not defined public: - // Empty the list of headers. - void clear(); - - // Append a name/value pair supplied as either std::strings - // or NUL-terminated char * to the header list. No normalization - // is performed on the strings. No conformance test is - // performed (names may contain spaces, colons, etc.). - // - void append(const std::string & name, const std::string & value); - void append(const char * name, const char * value); - - // Extract a name/value pair from a raw byte array using - // the first colon character as a separator. Input string - // does not need to be NUL-terminated. Resulting name/value - // pair is appended to the header list. - // - // Normalization is performed on the name/value pair as - // follows: - // - name is lower-cased according to mostly ASCII rules - // - name is left- and right-trimmed of spaces and tabs - // - value is left-trimmed of spaces and tabs - // - either or both of name and value may be zero-length - // - // By convention, headers read from the wire will be normalized - // in this fashion prior to delivery to any HttpHandler code. - // Headers to be written to the wire are left as appended to - // the list. - void appendNormal(const char * header, size_t size); - - // Perform a simple, case-sensitive search of the header list - // returning a pointer to the value of the last matching header - // in the header list. If none is found, a NULL pointer is returned. - // - // Any pointer returned references objects in the container itself - // and will have the same lifetime as this class. If you want - // the value beyond the lifetime of this instance, make a copy. - // - // @arg name C-style string giving the name of a header - // to search. The comparison is case-sensitive - // though list entries may have been normalized - // to lower-case. - // - // @return NULL if the header wasn't found otherwise - // 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 std::string &name) const; - const std::string * find(const char * name) const - { - return find(std::string(name)); - } + // Empty the list of headers. + void clear(); + + // Append a name/value pair supplied as either std::strings + // or NUL-terminated char * to the header list. No normalization + // is performed on the strings. No conformance test is + // performed (names may contain spaces, colons, etc.). + // + void append(const std::string & name, const std::string & value); + void append(const char * name, const char * value); + + // Extract a name/value pair from a raw byte array using + // the first colon character as a separator. Input string + // does not need to be NUL-terminated. Resulting name/value + // pair is appended to the header list. + // + // Normalization is performed on the name/value pair as + // follows: + // - name is lower-cased according to mostly ASCII rules + // - name is left- and right-trimmed of spaces and tabs + // - value is left-trimmed of spaces and tabs + // - either or both of name and value may be zero-length + // + // By convention, headers read from the wire will be normalized + // in this fashion prior to delivery to any HttpHandler code. + // Headers to be written to the wire are left as appended to + // the list. + void appendNormal(const char * header, size_t size); + + // Perform a simple, case-sensitive search of the header list + // returning a pointer to the value of the last matching header + // in the header list. If none is found, a NULL pointer is returned. + // + // Any pointer returned references objects in the container itself + // and will have the same lifetime as this class. If you want + // the value beyond the lifetime of this instance, make a copy. + // + // @arg name C-style string giving the name of a header + // to search. The comparison is case-sensitive + // though list entries may have been normalized + // to lower-case. + // + // @return NULL if the header wasn't found otherwise + // 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 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 - { - return mHeaders.size(); - } + // Count of headers currently in the list. + size_type size() const + { + return mHeaders.size(); + } - // Standard std::vector-based forward iterators. - iterator begin(); - const_iterator begin() const; - iterator end(); - const_iterator end() const; + // Standard std::vector-based forward iterators. + iterator begin(); + const_iterator begin() const; + iterator end(); + const_iterator end() const; - // Standard std::vector-based reverse iterators. - reverse_iterator rbegin(); - const_reverse_iterator rbegin() const; - reverse_iterator rend(); - const_reverse_iterator rend() const; + // Standard std::vector-based reverse iterators. + reverse_iterator rbegin(); + const_reverse_iterator rbegin() const; + reverse_iterator rend(); + const_reverse_iterator rend() const; public: - // For unit tests only - not a public API - container_t & getContainerTESTONLY(); - + // For unit tests only - not a public API + container_t & getContainerTESTONLY(); + protected: - container_t mHeaders; - + container_t mHeaders; + }; // end class HttpHeaders } // end namespace LLCore -#endif // _LLCORE_HTTP_HEADERS_H_ +#endif // _LLCORE_HTTP_HEADERS_H_ diff --git a/indra/llcorehttp/httpoptions.cpp b/indra/llcorehttp/httpoptions.cpp index c6365e5091..d85f6039b1 100644 --- a/indra/llcorehttp/httpoptions.cpp +++ b/indra/llcorehttp/httpoptions.cpp @@ -57,66 +57,66 @@ HttpOptions::~HttpOptions() void HttpOptions::setWantHeaders(bool wanted) { - mWantHeaders = wanted; + mWantHeaders = wanted; } void HttpOptions::setTrace(long level) { - mTracing = int(level); + mTracing = int(level); } void HttpOptions::setTimeout(unsigned int timeout) { - mTimeout = timeout; + mTimeout = timeout; } void HttpOptions::setTransferTimeout(unsigned int timeout) { - mTransferTimeout = timeout; + mTransferTimeout = timeout; } void HttpOptions::setRetries(unsigned int retries) { - mRetries = retries; + mRetries = retries; } void HttpOptions::setMinBackoff(HttpTime delay) { - mMinRetryBackoff = delay; + mMinRetryBackoff = delay; } void HttpOptions::setMaxBackoff(HttpTime delay) { - mMaxRetryBackoff = delay; + mMaxRetryBackoff = delay; } void HttpOptions::setUseRetryAfter(bool use_retry) { - mUseRetryAfter = use_retry; + mUseRetryAfter = use_retry; } void HttpOptions::setFollowRedirects(bool follow_redirect) { - mFollowRedirects = follow_redirect; + mFollowRedirects = follow_redirect; } void HttpOptions::setSSLVerifyPeer(bool verify) { - mVerifyPeer = verify; + mVerifyPeer = verify; } void HttpOptions::setSSLVerifyHost(bool verify) { - mVerifyHost = verify; + mVerifyHost = verify; } void HttpOptions::setDNSCacheTimeout(int timeout) { - mDNSCacheTimeout = timeout; + mDNSCacheTimeout = timeout; } void HttpOptions::setHeadersOnly(bool nobody) diff --git a/indra/llcorehttp/httpoptions.h b/indra/llcorehttp/httpoptions.h index fa993c857b..56a28013cb 100644 --- a/indra/llcorehttp/httpoptions.h +++ b/indra/llcorehttp/httpoptions.h @@ -24,8 +24,8 @@ * $/LicenseInfo$ */ -#ifndef _LLCORE_HTTP_OPTIONS_H_ -#define _LLCORE_HTTP_OPTIONS_H_ +#ifndef _LLCORE_HTTP_OPTIONS_H_ +#define _LLCORE_HTTP_OPTIONS_H_ #include "httpcommon.h" @@ -58,118 +58,118 @@ namespace LLCore class HttpOptions : private boost::noncopyable { public: - HttpOptions(); + HttpOptions(); - typedef std::shared_ptr<HttpOptions> ptr_t; + typedef std::shared_ptr<HttpOptions> ptr_t; - virtual ~HttpOptions(); // Use release() + virtual ~HttpOptions(); // Use release() protected: - - HttpOptions(const HttpOptions &); // Not defined - void operator=(const HttpOptions &); // Not defined + + HttpOptions(const HttpOptions &); // Not defined + void operator=(const HttpOptions &); // Not defined public: - // Default: false - void setWantHeaders(bool wanted); - bool getWantHeaders() const - { - return mWantHeaders; - } - - // Default: 0 - void setTrace(int long); - int getTrace() const - { - return mTracing; - } - - // Default: 30 - void setTimeout(unsigned int timeout); - unsigned int getTimeout() const - { - return mTimeout; - } - - // Default: 0 - void setTransferTimeout(unsigned int timeout); - unsigned int getTransferTimeout() const - { - return mTransferTimeout; - } - - /// Sets the number of retries on an LLCore::HTTPRequest before the + // Default: false + void setWantHeaders(bool wanted); + bool getWantHeaders() const + { + return mWantHeaders; + } + + // Default: 0 + void setTrace(int long); + int getTrace() const + { + return mTracing; + } + + // Default: 30 + void setTimeout(unsigned int timeout); + unsigned int getTimeout() const + { + return mTimeout; + } + + // Default: 0 + void setTransferTimeout(unsigned int timeout); + unsigned int getTransferTimeout() const + { + return mTransferTimeout; + } + + /// Sets the number of retries on an LLCore::HTTPRequest before the /// request fails. - // Default: 5 - void setRetries(unsigned int retries); - unsigned int getRetries() const - { - return mRetries; - } - - /// Sets minimal delay before request retries. In microseconds. - /// HttpPolicy will increase delay from min to max with each retry - // Default: 1 000 000 mcs - void setMinBackoff(HttpTime delay); - HttpTime getMinBackoff() const - { - return mMinRetryBackoff; - } - - /// Sets maximum delay before request retries. In microseconds. - /// HttpPolicy will increase delay from min to max with each retry - // Default: 5 000 000 mcs - void setMaxBackoff(HttpTime delay); - HttpTime getMaxBackoff() const - { - return mMaxRetryBackoff; - } - - // Default: true - void setUseRetryAfter(bool use_retry); - bool getUseRetryAfter() const - { - return mUseRetryAfter; - } - - /// Instructs the LLCore::HTTPRequest to follow redirects - /// Default: false - void setFollowRedirects(bool follow_redirect); - bool getFollowRedirects() const - { - return mFollowRedirects; - } + // Default: 5 + void setRetries(unsigned int retries); + unsigned int getRetries() const + { + return mRetries; + } + + /// Sets minimal delay before request retries. In microseconds. + /// HttpPolicy will increase delay from min to max with each retry + // Default: 1 000 000 mcs + void setMinBackoff(HttpTime delay); + HttpTime getMinBackoff() const + { + return mMinRetryBackoff; + } + + /// Sets maximum delay before request retries. In microseconds. + /// HttpPolicy will increase delay from min to max with each retry + // Default: 5 000 000 mcs + void setMaxBackoff(HttpTime delay); + HttpTime getMaxBackoff() const + { + return mMaxRetryBackoff; + } + + // Default: true + void setUseRetryAfter(bool use_retry); + bool getUseRetryAfter() const + { + 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. + /// certificate is authentic. /// Default: sDefaultVerifyPeer - void setSSLVerifyPeer(bool verify); - bool getSSLVerifyPeer() const - { - return mVerifyPeer; - } + void setSSLVerifyPeer(bool verify); + bool getSSLVerifyPeer() const + { + return mVerifyPeer; + } - /// Instructs the LLCore::HTTPRequest to verify that the name in the + /// 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; - } + 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 + /// 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; - } + void setDNSCacheTimeout(int timeout); + int getDNSCacheTimeout() const + { + return mDNSCacheTimeout; + } - /// Retrieve only the headers and status from the request. Setting this + /// Retrieve only the headers and status from the request. Setting this /// to true implies setWantHeaders(true) as well. /// Default: false void setHeadersOnly(bool nobody); @@ -178,26 +178,26 @@ public: return mNoBody; } - /// Sets default behavior for verifying that the name in the + /// Sets default behavior for verifying that the name in the /// security certificate matches the name of the host contacted. /// Defaults false if not set, but should be set according to /// viewer's initialization options and command argunments, see /// NoVerifySSLCert static void setDefaultSSLVerifyPeer(bool verify); - + protected: - bool mWantHeaders; - int mTracing; - unsigned int mTimeout; - unsigned int mTransferTimeout; - unsigned int mRetries; - HttpTime mMinRetryBackoff; - HttpTime mMaxRetryBackoff; - bool mUseRetryAfter; - bool mFollowRedirects; - bool mVerifyPeer; - bool mVerifyHost; - int mDNSCacheTimeout; + bool mWantHeaders; + int mTracing; + unsigned int mTimeout; + unsigned int mTransferTimeout; + unsigned int mRetries; + HttpTime mMinRetryBackoff; + HttpTime mMaxRetryBackoff; + bool mUseRetryAfter; + bool mFollowRedirects; + bool mVerifyPeer; + bool mVerifyHost; + int mDNSCacheTimeout; bool mNoBody; static bool sDefaultVerifyPeer; @@ -206,4 +206,4 @@ protected: } // end namespace HttpOptions -#endif // _LLCORE_HTTP_OPTIONS_H_ +#endif // _LLCORE_HTTP_OPTIONS_H_ diff --git a/indra/llcorehttp/httprequest.cpp b/indra/llcorehttp/httprequest.cpp index de3854a101..216d407deb 100644 --- a/indra/llcorehttp/httprequest.cpp +++ b/indra/llcorehttp/httprequest.cpp @@ -54,13 +54,13 @@ namespace LLCore HttpRequest::HttpRequest() - : mReplyQueue(), - mRequestQueue(NULL) + : mReplyQueue(), + mRequestQueue(NULL) { - mRequestQueue = HttpRequestQueue::instanceOf(); - mRequestQueue->addRef(); + mRequestQueue = HttpRequestQueue::instanceOf(); + mRequestQueue->addRef(); - mReplyQueue.reset( new HttpReplyQueue() ); + mReplyQueue.reset( new HttpReplyQueue() ); HTTPStats::instance().recordHTTPRequest(); } @@ -68,11 +68,11 @@ HttpRequest::HttpRequest() HttpRequest::~HttpRequest() { - if (mRequestQueue) - { - mRequestQueue->release(); - mRequestQueue = NULL; - } + if (mRequestQueue) + { + mRequestQueue->release(); + mRequestQueue = NULL; + } mReplyQueue.reset(); } @@ -85,88 +85,88 @@ HttpRequest::~HttpRequest() HttpRequest::policy_t HttpRequest::createPolicyClass() { - if (HttpService::RUNNING == HttpService::instanceOf()->getState()) - { - return 0; - } - return HttpService::instanceOf()->createPolicyClass(); + if (HttpService::RUNNING == HttpService::instanceOf()->getState()) + { + return 0; + } + return HttpService::instanceOf()->createPolicyClass(); } HttpStatus HttpRequest::setStaticPolicyOption(EPolicyOption opt, policy_t pclass, - long value, long * ret_value) + long value, long * 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); + if (HttpService::RUNNING == HttpService::instanceOf()->getState()) + { + return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC); + } + return HttpService::instanceOf()->setPolicyOption(opt, pclass, value, ret_value); } HttpStatus HttpRequest::setStaticPolicyOption(EPolicyOption opt, policy_t pclass, - const std::string & value, std::string * ret_value) + const std::string & value, std::string * 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); + if (HttpService::RUNNING == HttpService::instanceOf()->getState()) + { + return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC); + } + 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); - } + if (HttpService::RUNNING == HttpService::instanceOf()->getState()) + { + return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC); + } - return HttpService::instanceOf()->setPolicyOption(opt, pclass, value, ret_value); + return HttpService::instanceOf()->setPolicyOption(opt, pclass, value, ret_value); } HttpHandle HttpRequest::setPolicyOption(EPolicyOption opt, policy_t pclass, - long value, HttpHandler::ptr_t handler) + long value, HttpHandler::ptr_t handler) { - HttpStatus status; + HttpStatus status; HttpOpSetGet::ptr_t op(new HttpOpSetGet()); - if (! (status = op->setupSet(opt, pclass, value))) - { - mLastReqStatus = status; + if (! (status = op->setupSet(opt, pclass, value))) + { + mLastReqStatus = status; return LLCORE_HTTP_HANDLE_INVALID; - } - op->setReplyPath(mReplyQueue, handler); - if (! (status = mRequestQueue->addOp(op))) // transfers refcount - { - mLastReqStatus = status; + } + op->setReplyPath(mReplyQueue, handler); + if (! (status = mRequestQueue->addOp(op))) // transfers refcount + { + mLastReqStatus = status; return LLCORE_HTTP_HANDLE_INVALID; - } - - mLastReqStatus = status; - return op->getHandle(); + } + + mLastReqStatus = status; + return op->getHandle(); } HttpHandle HttpRequest::setPolicyOption(EPolicyOption opt, policy_t pclass, - const std::string & value, HttpHandler::ptr_t handler) + const std::string & value, HttpHandler::ptr_t handler) { - HttpStatus status; + HttpStatus status; - HttpOpSetGet::ptr_t op (new HttpOpSetGet()); - if (! (status = op->setupSet(opt, pclass, value))) - { - mLastReqStatus = status; + HttpOpSetGet::ptr_t op (new HttpOpSetGet()); + if (! (status = op->setupSet(opt, pclass, value))) + { + mLastReqStatus = status; return LLCORE_HTTP_HANDLE_INVALID; - } - op->setReplyPath(mReplyQueue, handler); - if (! (status = mRequestQueue->addOp(op))) // transfers refcount - { - mLastReqStatus = status; + } + op->setReplyPath(mReplyQueue, handler); + if (! (status = mRequestQueue->addOp(op))) // transfers refcount + { + mLastReqStatus = status; return LLCORE_HTTP_HANDLE_INVALID; - } - - mLastReqStatus = status; - return op->getHandle(); + } + + mLastReqStatus = status; + return op->getHandle(); } @@ -177,116 +177,116 @@ HttpHandle HttpRequest::setPolicyOption(EPolicyOption opt, policy_t pclass, HttpStatus HttpRequest::getStatus() const { - return mLastReqStatus; + return mLastReqStatus; } HttpHandle HttpRequest::requestGet(policy_t policy_id, - const std::string & url, + const std::string & url, const HttpOptions::ptr_t & options, - const HttpHeaders::ptr_t & headers, - HttpHandler::ptr_t user_handler) + const HttpHeaders::ptr_t & headers, + HttpHandler::ptr_t user_handler) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - HttpStatus status; + HttpStatus status; - HttpOpRequest::ptr_t op(new HttpOpRequest()); - if (! (status = op->setupGet(policy_id, url, options, headers))) - { - mLastReqStatus = status; + HttpOpRequest::ptr_t op(new HttpOpRequest()); + if (! (status = op->setupGet(policy_id, url, options, headers))) + { + mLastReqStatus = status; return LLCORE_HTTP_HANDLE_INVALID; - } - op->setReplyPath(mReplyQueue, user_handler); - if (! (status = mRequestQueue->addOp(op))) // transfers refcount - { - mLastReqStatus = status; + } + op->setReplyPath(mReplyQueue, user_handler); + if (! (status = mRequestQueue->addOp(op))) // transfers refcount + { + mLastReqStatus = status; return LLCORE_HTTP_HANDLE_INVALID; - } - - mLastReqStatus = status; + } + + mLastReqStatus = status; return op->getHandle(); } HttpHandle HttpRequest::requestGetByteRange(policy_t policy_id, - const std::string & url, - size_t offset, - size_t len, + const std::string & url, + size_t offset, + size_t len, const HttpOptions::ptr_t & options, - const HttpHeaders::ptr_t & headers, - HttpHandler::ptr_t user_handler) + const HttpHeaders::ptr_t & headers, + HttpHandler::ptr_t user_handler) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - HttpStatus status; + HttpStatus status; - HttpOpRequest::ptr_t op(new HttpOpRequest()); - if (! (status = op->setupGetByteRange(policy_id, url, offset, len, options, headers))) - { - mLastReqStatus = status; + HttpOpRequest::ptr_t op(new HttpOpRequest()); + if (! (status = op->setupGetByteRange(policy_id, url, offset, len, options, headers))) + { + mLastReqStatus = status; return LLCORE_HTTP_HANDLE_INVALID; - } - op->setReplyPath(mReplyQueue, user_handler); - if (! (status = mRequestQueue->addOp(op))) // transfers refcount - { - mLastReqStatus = status; + } + op->setReplyPath(mReplyQueue, user_handler); + if (! (status = mRequestQueue->addOp(op))) // transfers refcount + { + mLastReqStatus = status; return LLCORE_HTTP_HANDLE_INVALID; - } - - mLastReqStatus = status; - return op->getHandle(); + } + + mLastReqStatus = status; + return op->getHandle(); } HttpHandle HttpRequest::requestPost(policy_t policy_id, - const std::string & url, - BufferArray * body, + const std::string & url, + BufferArray * body, const HttpOptions::ptr_t & options, - const HttpHeaders::ptr_t & headers, - HttpHandler::ptr_t user_handler) + const HttpHeaders::ptr_t & headers, + HttpHandler::ptr_t user_handler) { - HttpStatus status; + HttpStatus status; - HttpOpRequest::ptr_t op(new HttpOpRequest()); - if (! (status = op->setupPost(policy_id, url, body, options, headers))) - { - mLastReqStatus = status; + HttpOpRequest::ptr_t op(new HttpOpRequest()); + if (! (status = op->setupPost(policy_id, 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; + } + op->setReplyPath(mReplyQueue, user_handler); + if (! (status = mRequestQueue->addOp(op))) // transfers refcount + { + mLastReqStatus = status; return LLCORE_HTTP_HANDLE_INVALID; - } - - mLastReqStatus = status; - return op->getHandle(); + } + + mLastReqStatus = status; + return op->getHandle(); } HttpHandle HttpRequest::requestPut(policy_t policy_id, - const std::string & url, - BufferArray * body, + const std::string & url, + BufferArray * body, const HttpOptions::ptr_t & options, - const HttpHeaders::ptr_t & headers, - HttpHandler::ptr_t user_handler) + const HttpHeaders::ptr_t & headers, + HttpHandler::ptr_t user_handler) { - HttpStatus status; + HttpStatus status; - HttpOpRequest::ptr_t op (new HttpOpRequest()); - if (! (status = op->setupPut(policy_id, url, body, options, headers))) - { - mLastReqStatus = status; + HttpOpRequest::ptr_t op (new HttpOpRequest()); + if (! (status = op->setupPut(policy_id, 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; + } + op->setReplyPath(mReplyQueue, user_handler); + if (! (status = mRequestQueue->addOp(op))) // transfers refcount + { + mLastReqStatus = status; return LLCORE_HTTP_HANDLE_INVALID; - } - - mLastReqStatus = status; + } + + mLastReqStatus = status; return op->getHandle(); } @@ -305,7 +305,7 @@ HttpHandle HttpRequest::requestDelete(policy_t policy_id, return LLCORE_HTTP_HANDLE_INVALID; } op->setReplyPath(mReplyQueue, user_handler); - if (!(status = mRequestQueue->addOp(op))) // transfers refcount + if (!(status = mRequestQueue->addOp(op))) // transfers refcount { mLastReqStatus = status; return LLCORE_HTTP_HANDLE_INVALID; @@ -331,7 +331,7 @@ HttpHandle HttpRequest::requestPatch(policy_t policy_id, return LLCORE_HTTP_HANDLE_INVALID; } op->setReplyPath(mReplyQueue, user_handler); - if (!(status = mRequestQueue->addOp(op))) // transfers refcount + if (!(status = mRequestQueue->addOp(op))) // transfers refcount { mLastReqStatus = status; return LLCORE_HTTP_HANDLE_INVALID; @@ -356,7 +356,7 @@ HttpHandle HttpRequest::requestCopy(policy_t policy_id, return LLCORE_HTTP_HANDLE_INVALID; } op->setReplyPath(mReplyQueue, user_handler); - if (!(status = mRequestQueue->addOp(op))) // transfers refcount + if (!(status = mRequestQueue->addOp(op))) // transfers refcount { mLastReqStatus = status; return LLCORE_HTTP_HANDLE_INVALID; @@ -382,7 +382,7 @@ HttpHandle HttpRequest::requestMove(policy_t policy_id, return LLCORE_HTTP_HANDLE_INVALID; } op->setReplyPath(mReplyQueue, user_handler); - if (!(status = mRequestQueue->addOp(op))) // transfers refcount + if (!(status = mRequestQueue->addOp(op))) // transfers refcount { mLastReqStatus = status; return LLCORE_HTTP_HANDLE_INVALID; @@ -395,61 +395,61 @@ HttpHandle HttpRequest::requestMove(policy_t policy_id, HttpHandle HttpRequest::requestNoOp(HttpHandler::ptr_t user_handler) { - HttpStatus status; + HttpStatus status; - HttpOperation::ptr_t op (new HttpOpNull()); - op->setReplyPath(mReplyQueue, user_handler); - if (! (status = mRequestQueue->addOp(op))) // transfers refcount - { - mLastReqStatus = status; + HttpOperation::ptr_t op (new HttpOpNull()); + op->setReplyPath(mReplyQueue, user_handler); + if (! (status = mRequestQueue->addOp(op))) // transfers refcount + { + mLastReqStatus = status; return LLCORE_HTTP_HANDLE_INVALID; - } + } - mLastReqStatus = status; - return op->getHandle(); + mLastReqStatus = status; + return op->getHandle(); } HttpStatus HttpRequest::update(long usecs) { - HttpOperation::ptr_t op; - - if (usecs) - { - const HttpTime limit(totalTime() + HttpTime(usecs)); - while (limit >= totalTime() && (op = mReplyQueue->fetchOp())) - { - // Process operation - op->visitNotifier(this); - - // We're done with the operation + HttpOperation::ptr_t op; + + if (usecs) + { + const HttpTime limit(totalTime() + HttpTime(usecs)); + while (limit >= totalTime() && (op = mReplyQueue->fetchOp())) + { + // Process operation + op->visitNotifier(this); + + // We're done with the operation op.reset(); - } - } - else - { - // Same as above, just no time limit - HttpReplyQueue::OpContainer replies; - mReplyQueue->fetchAll(replies); - if (! replies.empty()) - { - for (HttpReplyQueue::OpContainer::iterator iter(replies.begin()); - replies.end() != iter; - ++iter) - { - // Swap op pointer for NULL; + } + } + else + { + // Same as above, just no time limit + HttpReplyQueue::OpContainer replies; + mReplyQueue->fetchAll(replies); + if (! replies.empty()) + { + for (HttpReplyQueue::OpContainer::iterator iter(replies.begin()); + replies.end() != iter; + ++iter) + { + // Swap op pointer for NULL; op.reset(); op.swap(*iter); - - // Process operation - op->visitNotifier(this); - - // We're done with the operation - } - } - } - - return HttpStatus(); + + // Process operation + op->visitNotifier(this); + + // We're done with the operation + } + } + } + + return HttpStatus(); } @@ -461,18 +461,18 @@ HttpStatus HttpRequest::update(long usecs) HttpHandle HttpRequest::requestCancel(HttpHandle request, HttpHandler::ptr_t user_handler) { - HttpStatus status; + HttpStatus status; - HttpOperation::ptr_t op(new HttpOpCancel(request)); - op->setReplyPath(mReplyQueue, user_handler); - if (! (status = mRequestQueue->addOp(op))) // transfers refcount - { - mLastReqStatus = status; + HttpOperation::ptr_t op(new HttpOpCancel(request)); + op->setReplyPath(mReplyQueue, user_handler); + if (! (status = mRequestQueue->addOp(op))) // transfers refcount + { + mLastReqStatus = status; return LLCORE_HTTP_HANDLE_INVALID; - } + } - mLastReqStatus = status; - return op->getHandle(); + mLastReqStatus = status; + return op->getHandle(); } @@ -482,82 +482,82 @@ HttpHandle HttpRequest::requestCancel(HttpHandle request, HttpHandler::ptr_t use HttpStatus HttpRequest::createService() { - HttpStatus status; - - if (! has_inited) - { - HttpRequestQueue::init(); - HttpRequestQueue * rq = HttpRequestQueue::instanceOf(); - HttpService::init(rq); - has_inited = true; - } - - return status; + HttpStatus status; + + if (! has_inited) + { + HttpRequestQueue::init(); + HttpRequestQueue * rq = HttpRequestQueue::instanceOf(); + HttpService::init(rq); + has_inited = true; + } + + return status; } HttpStatus HttpRequest::destroyService() { - HttpStatus status; - - if (has_inited) - { - HttpService::term(); - HttpRequestQueue::term(); - has_inited = false; - } - - return status; + HttpStatus status; + + if (has_inited) + { + HttpService::term(); + HttpRequestQueue::term(); + has_inited = false; + } + + return status; } HttpStatus HttpRequest::startThread() { - HttpStatus status; + HttpStatus status; + + HttpService::instanceOf()->startThread(); - HttpService::instanceOf()->startThread(); - - return status; + return status; } HttpHandle HttpRequest::requestStopThread(HttpHandler::ptr_t user_handler) { - HttpStatus status; - HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); + HttpStatus status; + HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); - HttpOperation::ptr_t op(new HttpOpStop()); - op->setReplyPath(mReplyQueue, user_handler); - if (! (status = mRequestQueue->addOp(op))) // transfers refcount - { - mLastReqStatus = status; - return handle; - } + HttpOperation::ptr_t op(new HttpOpStop()); + op->setReplyPath(mReplyQueue, user_handler); + if (! (status = mRequestQueue->addOp(op))) // transfers refcount + { + mLastReqStatus = status; + return handle; + } - mLastReqStatus = status; - handle = op->getHandle(); + mLastReqStatus = status; + handle = op->getHandle(); - return handle; + return handle; } HttpHandle HttpRequest::requestSpin(int mode) { - HttpStatus status; - HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); + HttpStatus status; + HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); - HttpOperation::ptr_t op(new HttpOpSpin(mode)); + HttpOperation::ptr_t op(new HttpOpSpin(mode)); op->setReplyPath(mReplyQueue, HttpHandler::ptr_t()); - if (! (status = mRequestQueue->addOp(op))) // transfers refcount - { - mLastReqStatus = status; - return handle; - } + if (! (status = mRequestQueue->addOp(op))) // transfers refcount + { + mLastReqStatus = status; + return handle; + } - mLastReqStatus = status; - handle = op->getHandle(); + mLastReqStatus = status; + handle = op->getHandle(); - return handle; + return handle; } diff --git a/indra/llcorehttp/httprequest.h b/indra/llcorehttp/httprequest.h index 857a034a7b..e6e051410e 100644 --- a/indra/llcorehttp/httprequest.h +++ b/indra/llcorehttp/httprequest.h @@ -24,8 +24,8 @@ * $/LicenseInfo$ */ -#ifndef _LLCORE_HTTP_REQUEST_H_ -#define _LLCORE_HTTP_REQUEST_H_ +#ifndef _LLCORE_HTTP_REQUEST_H_ +#define _LLCORE_HTTP_REQUEST_H_ #include "httpcommon.h" @@ -86,398 +86,398 @@ class BufferArray; class HttpRequest { public: - HttpRequest(); - virtual ~HttpRequest(); + HttpRequest(); + virtual ~HttpRequest(); private: - HttpRequest(const HttpRequest &); // Disallowed - void operator=(const HttpRequest &); // Disallowed + HttpRequest(const HttpRequest &); // Disallowed + void operator=(const HttpRequest &); // Disallowed public: - typedef unsigned int policy_t; - - typedef std::shared_ptr<HttpRequest> ptr_t; + typedef unsigned int policy_t; + + typedef std::shared_ptr<HttpRequest> ptr_t; typedef std::weak_ptr<HttpRequest> wptr_t; public: - /// @name PolicyMethods - /// @{ - - /// Represents a default, catch-all policy class that guarantees - /// eventual service for any HTTP request. - static const policy_t DEFAULT_POLICY_ID = 0; - static const policy_t INVALID_POLICY_ID = 0xFFFFFFFFU; - static const policy_t GLOBAL_POLICY_ID = 0xFFFFFFFEU; - - /// Create a new policy class into which requests can be made. - /// - /// All class creation must occur before threads are started and - /// transport begins. Policy classes are limited to a small value. - /// Currently that limit is the default class + 1. - /// - /// @return If positive, the policy_id used to reference - /// the class in other methods. If 0, requests - /// for classes have exceeded internal limits - /// or caller has tried to create a class after - /// threads have been started. Caller must fallback - /// and recover. - /// - static policy_t createPolicyClass(); - - enum EPolicyOption - { - /// Maximum number of connections the library will use to - /// perform operations. This is somewhat soft as the underlying - /// transport will cache some connections (up to 5). - - /// A long value setting the maximum number of connections - /// allowed over all policy classes. Note that this will be - /// a somewhat soft value. There may be an additional five - /// connections per policy class depending upon runtime - /// behavior. - /// - /// Both global and per-class - PO_CONNECTION_LIMIT, - - /// Limits the number of connections used for a single - /// literal address/port pair within the class. - /// - /// Per-class only - PO_PER_HOST_CONNECTION_LIMIT, - - /// String containing a system-appropriate directory name - /// where SSL certs are stored. - /// - /// Global only - PO_CA_PATH, - - /// String giving a full path to a file containing SSL certs. - /// - /// Global only - PO_CA_FILE, - - /// String of host/port to use as simple HTTP proxy. This is - /// going to change in the future into something more elaborate - /// that may support richer schemes. - /// - /// Global only - PO_HTTP_PROXY, - - /// 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. - /// - /// Global only - PO_LLPROXY, - - /// Long value setting the logging trace level for the - /// library. Possible values are: - /// 0 - No tracing (default) - /// 1 - Basic tracing of request start, stop and major events. - /// 2 - Connection, header and payload size information from - /// HTTP transactions. - /// 3 - Partial logging of payload itself. - /// - /// These values are also used in the trace modes for - /// individual requests in HttpOptions. Also be aware that - /// tracing tends to impact performance of the viewer. - /// - /// Global only - PO_TRACE, - - /// If greater than 1, suitable requests are allowed to - /// pipeline on their connections when they ask for it. - /// Value gives the maximum number of outstanding requests - /// on a connection. - /// - /// There is some interaction between PO_CONNECTION_LIMIT, - /// PO_PER_HOST_CONNECTION_LIMIT, and PO_PIPELINING_DEPTH. - /// When PIPELINING_DEPTH is 0 or 1 (no pipelining), this - /// library manages connection lifecycle and honors the - /// PO_CONNECTION_LIMIT setting as the maximum in-flight - /// request limit. Libcurl itself may be caching additional - /// connections under its connection cache policy. - /// - /// When PIPELINING_DEPTH is 2 or more, libcurl performs - /// connection management and both PO_CONNECTION_LIMIT and - /// PO_PER_HOST_CONNECTION_LIMIT should be set and non-zero. - /// In this case (as of libcurl 7.37.0), libcurl will - /// open new connections in preference to pipelining, up - /// to the above limits at which time pipelining begins. - /// And as usual, an additional cache of open but inactive - /// connections may still be maintained within libcurl. - /// For SL, a good rule-of-thumb is to set - /// PO_PER_HOST_CONNECTION_LIMIT to the user-visible - /// concurrency value and PO_CONNECTION_LIMIT to twice - /// that for baked texture loads and region crossings where - /// additional connection load will be tolerated. If - /// either limit is 0, libcurl will prefer pipelining - /// over connection creation, which is still interesting, - /// but won't be pursued at this time. - /// - /// Per-class only - PO_PIPELINING_DEPTH, - - /// 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 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. + /// @name PolicyMethods + /// @{ + + /// Represents a default, catch-all policy class that guarantees + /// eventual service for any HTTP request. + static const policy_t DEFAULT_POLICY_ID = 0; + static const policy_t INVALID_POLICY_ID = 0xFFFFFFFFU; + static const policy_t GLOBAL_POLICY_ID = 0xFFFFFFFEU; + + /// Create a new policy class into which requests can be made. + /// + /// All class creation must occur before threads are started and + /// transport begins. Policy classes are limited to a small value. + /// Currently that limit is the default class + 1. + /// + /// @return If positive, the policy_id used to reference + /// the class in other methods. If 0, requests + /// for classes have exceeded internal limits + /// or caller has tried to create a class after + /// threads have been started. Caller must fallback + /// and recover. + /// + static policy_t createPolicyClass(); + + enum EPolicyOption + { + /// Maximum number of connections the library will use to + /// perform operations. This is somewhat soft as the underlying + /// transport will cache some connections (up to 5). + + /// A long value setting the maximum number of connections + /// allowed over all policy classes. Note that this will be + /// a somewhat soft value. There may be an additional five + /// connections per policy class depending upon runtime + /// behavior. + /// + /// Both global and per-class + PO_CONNECTION_LIMIT, + + /// Limits the number of connections used for a single + /// literal address/port pair within the class. + /// + /// Per-class only + PO_PER_HOST_CONNECTION_LIMIT, + + /// String containing a system-appropriate directory name + /// where SSL certs are stored. + /// + /// Global only + PO_CA_PATH, + + /// String giving a full path to a file containing SSL certs. + /// + /// Global only + PO_CA_FILE, + + /// String of host/port to use as simple HTTP proxy. This is + /// going to change in the future into something more elaborate + /// that may support richer schemes. + /// + /// Global only + PO_HTTP_PROXY, + + /// 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. + /// + /// Global only + PO_LLPROXY, + + /// Long value setting the logging trace level for the + /// library. Possible values are: + /// 0 - No tracing (default) + /// 1 - Basic tracing of request start, stop and major events. + /// 2 - Connection, header and payload size information from + /// HTTP transactions. + /// 3 - Partial logging of payload itself. + /// + /// These values are also used in the trace modes for + /// individual requests in HttpOptions. Also be aware that + /// tracing tends to impact performance of the viewer. + /// + /// Global only + PO_TRACE, + + /// If greater than 1, suitable requests are allowed to + /// pipeline on their connections when they ask for it. + /// Value gives the maximum number of outstanding requests + /// on a connection. + /// + /// There is some interaction between PO_CONNECTION_LIMIT, + /// PO_PER_HOST_CONNECTION_LIMIT, and PO_PIPELINING_DEPTH. + /// When PIPELINING_DEPTH is 0 or 1 (no pipelining), this + /// library manages connection lifecycle and honors the + /// PO_CONNECTION_LIMIT setting as the maximum in-flight + /// request limit. Libcurl itself may be caching additional + /// connections under its connection cache policy. + /// + /// When PIPELINING_DEPTH is 2 or more, libcurl performs + /// connection management and both PO_CONNECTION_LIMIT and + /// PO_PER_HOST_CONNECTION_LIMIT should be set and non-zero. + /// In this case (as of libcurl 7.37.0), libcurl will + /// open new connections in preference to pipelining, up + /// to the above limits at which time pipelining begins. + /// And as usual, an additional cache of open but inactive + /// connections may still be maintained within libcurl. + /// For SL, a good rule-of-thumb is to set + /// PO_PER_HOST_CONNECTION_LIMIT to the user-visible + /// concurrency value and PO_CONNECTION_LIMIT to twice + /// that for baked texture loads and region crossings where + /// additional connection load will be tolerated. If + /// either limit is 0, libcurl will prefer pipelining + /// over connection creation, which is still interesting, + /// but won't be pursued at this time. + /// + /// Per-class only + PO_PIPELINING_DEPTH, + + /// 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 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). - /// - /// @param opt Enum of option to be set. - /// @param pclass For class-based options, the policy class ID to - /// be changed. For globals, specify GLOBAL_POLICY_ID. - /// @param value Desired value of option. - /// @param ret_value Pointer to receive effective set value - /// if successful. May be NULL if effective - /// value not wanted. - /// @return Standard status code. - static HttpStatus setStaticPolicyOption(EPolicyOption opt, policy_t pclass, - 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 - /// not honored and return an error status. - /// - /// @param opt Enum of option to be set. - /// @param pclass For class-based options, the policy class ID to - /// be changed. Ignored for globals but recommend - /// using INVALID_POLICY_ID in this case. - /// @param value Desired value of option. - /// @return Handle of dynamic request. Use @see getStatus() if - /// the returned handle is invalid. - HttpHandle setPolicyOption(EPolicyOption opt, policy_t pclass, long value, - HttpHandler::ptr_t handler); - HttpHandle setPolicyOption(EPolicyOption opt, policy_t pclass, const std::string & value, - HttpHandler::ptr_t handler); - - /// @} - - /// @name RequestMethods - /// - /// @{ - - /// Some calls expect to succeed as the normal part of operation and so - /// return a useful value rather than a status. When they do fail, the - /// status is saved and can be fetched with this method. - /// - /// @return Status of the failing method invocation. If the - /// preceding call succeeded or other HttpStatus - /// returning calls immediately preceded this method, - /// the returned value may not be reliable. - /// - HttpStatus getStatus() const; - - /// Queue a full HTTP GET request to be issued for entire entity. - /// The request is queued and serviced by the working thread and - /// notification of completion delivered to the optional HttpHandler - /// argument during @see update() calls. - /// - /// With a valid handle returned, it can be used to reference the - /// request in other requests (like cancellation) and will be an - /// argument when any HttpHandler object is invoked. - /// - /// Headers supplied by default: - /// - Connection: keep-alive - /// - Accept: */* - /// - Accept-Encoding: deflate, gzip - /// - Keep-alive: 300 - /// - Host: <stuff> - /// - /// Some headers excluded by default: - /// - Pragma: - /// - Cache-control: - /// - Range: - /// - Transfer-Encoding: - /// - Referer: - /// - /// @param policy_id Default or user-defined policy class under - /// which this request is to be serviced. - /// @param url URL with any encoded query parameters to - /// be accessed. - /// @param options Optional instance of an HttpOptions object - /// to provide additional controls over the request - /// function for this request only. Any such - /// object then becomes shared-read across threads - /// and no code should modify the HttpOptions - /// instance. - /// @param headers Optional instance of an HttpHeaders object - /// to provide additional and/or overridden - /// headers for the request. As with options, - /// the instance becomes shared-read across threads - /// and no code should modify the HttpHeaders - /// instance. - /// @param handler Optional pointer to an HttpHandler instance - /// whose onCompleted() method will be invoked - /// during calls to update(). This is a non- - /// reference-counted object which would be a - /// problem for shutdown and other edge cases but - /// the pointer is only dereferenced during - /// calls to update(). - /// - /// @return The handle of the request if successfully - /// queued or LLCORE_HTTP_HANDLE_INVALID if the - /// request could not be queued. In the latter - /// case, @see getStatus() will return more info. - /// - HttpHandle requestGet(policy_t policy_id, - const std::string & url, + /// Set a policy option for a global or class parameter at + /// startup time (prior to thread start). + /// + /// @param opt Enum of option to be set. + /// @param pclass For class-based options, the policy class ID to + /// be changed. For globals, specify GLOBAL_POLICY_ID. + /// @param value Desired value of option. + /// @param ret_value Pointer to receive effective set value + /// if successful. May be NULL if effective + /// value not wanted. + /// @return Standard status code. + static HttpStatus setStaticPolicyOption(EPolicyOption opt, policy_t pclass, + 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 + /// not honored and return an error status. + /// + /// @param opt Enum of option to be set. + /// @param pclass For class-based options, the policy class ID to + /// be changed. Ignored for globals but recommend + /// using INVALID_POLICY_ID in this case. + /// @param value Desired value of option. + /// @return Handle of dynamic request. Use @see getStatus() if + /// the returned handle is invalid. + HttpHandle setPolicyOption(EPolicyOption opt, policy_t pclass, long value, + HttpHandler::ptr_t handler); + HttpHandle setPolicyOption(EPolicyOption opt, policy_t pclass, const std::string & value, + HttpHandler::ptr_t handler); + + /// @} + + /// @name RequestMethods + /// + /// @{ + + /// Some calls expect to succeed as the normal part of operation and so + /// return a useful value rather than a status. When they do fail, the + /// status is saved and can be fetched with this method. + /// + /// @return Status of the failing method invocation. If the + /// preceding call succeeded or other HttpStatus + /// returning calls immediately preceded this method, + /// the returned value may not be reliable. + /// + HttpStatus getStatus() const; + + /// Queue a full HTTP GET request to be issued for entire entity. + /// The request is queued and serviced by the working thread and + /// notification of completion delivered to the optional HttpHandler + /// argument during @see update() calls. + /// + /// With a valid handle returned, it can be used to reference the + /// request in other requests (like cancellation) and will be an + /// argument when any HttpHandler object is invoked. + /// + /// Headers supplied by default: + /// - Connection: keep-alive + /// - Accept: */* + /// - Accept-Encoding: deflate, gzip + /// - Keep-alive: 300 + /// - Host: <stuff> + /// + /// Some headers excluded by default: + /// - Pragma: + /// - Cache-control: + /// - Range: + /// - Transfer-Encoding: + /// - Referer: + /// + /// @param policy_id Default or user-defined policy class under + /// which this request is to be serviced. + /// @param url URL with any encoded query parameters to + /// be accessed. + /// @param options Optional instance of an HttpOptions object + /// to provide additional controls over the request + /// function for this request only. Any such + /// object then becomes shared-read across threads + /// and no code should modify the HttpOptions + /// instance. + /// @param headers Optional instance of an HttpHeaders object + /// to provide additional and/or overridden + /// headers for the request. As with options, + /// the instance becomes shared-read across threads + /// and no code should modify the HttpHeaders + /// instance. + /// @param handler Optional pointer to an HttpHandler instance + /// whose onCompleted() method will be invoked + /// during calls to update(). This is a non- + /// reference-counted object which would be a + /// problem for shutdown and other edge cases but + /// the pointer is only dereferenced during + /// calls to update(). + /// + /// @return The handle of the request if successfully + /// queued or LLCORE_HTTP_HANDLE_INVALID if the + /// request could not be queued. In the latter + /// case, @see getStatus() will return more info. + /// + HttpHandle requestGet(policy_t policy_id, + const std::string & url, 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. - /// The request is queued and serviced by the working thread and - /// notification of completion delivered to the optional HttpHandler - /// argument during @see update() calls. - /// - /// With a valid handle returned, it can be used to reference the - /// request in other requests (like cancellation) and will be an - /// argument when any HttpHandler object is invoked. - /// - /// Headers supplied by default: - /// - Connection: keep-alive - /// - Accept: */* - /// - Accept-Encoding: deflate, gzip - /// - Keep-alive: 300 - /// - Host: <stuff> - /// - Range: <stuff> (will be omitted if offset == 0 and len == 0) - /// - /// Some headers excluded by default: - /// - Pragma: - /// - Cache-control: - /// - Transfer-Encoding: - /// - Referer: - /// - /// @param policy_id @see requestGet() - /// @param url " - /// @param offset Offset of first byte into resource to be returned. - /// @param len Count of bytes to be returned - /// @param options @see requestGet() - /// @param headers " - /// @param handler " - /// @return " - /// - HttpHandle requestGetByteRange(policy_t policy_id, - const std::string & url, - size_t offset, - size_t len, + const HttpHeaders::ptr_t & headers, + HttpHandler::ptr_t handler); + + + /// Queue a full HTTP GET request to be issued with a 'Range' header. + /// The request is queued and serviced by the working thread and + /// notification of completion delivered to the optional HttpHandler + /// argument during @see update() calls. + /// + /// With a valid handle returned, it can be used to reference the + /// request in other requests (like cancellation) and will be an + /// argument when any HttpHandler object is invoked. + /// + /// Headers supplied by default: + /// - Connection: keep-alive + /// - Accept: */* + /// - Accept-Encoding: deflate, gzip + /// - Keep-alive: 300 + /// - Host: <stuff> + /// - Range: <stuff> (will be omitted if offset == 0 and len == 0) + /// + /// Some headers excluded by default: + /// - Pragma: + /// - Cache-control: + /// - Transfer-Encoding: + /// - Referer: + /// + /// @param policy_id @see requestGet() + /// @param url " + /// @param offset Offset of first byte into resource to be returned. + /// @param len Count of bytes to be returned + /// @param options @see requestGet() + /// @param headers " + /// @param handler " + /// @return " + /// + HttpHandle requestGetByteRange(policy_t policy_id, + const std::string & url, + size_t offset, + size_t len, const HttpOptions::ptr_t & options, - const HttpHeaders::ptr_t & headers, - HttpHandler::ptr_t handler); - - - /// Queue a full HTTP POST. Query arguments and body may - /// be provided. Caller is responsible for escaping and - /// encoding and communicating the content types. - /// - /// Headers supplied by default: - /// - Connection: keep-alive - /// - Accept: */* - /// - Accept-Encoding: deflate, gzip - /// - Keep-Alive: 300 - /// - Host: <stuff> - /// - Content-Length: <digits> - /// - Content-Type: application/x-www-form-urlencoded - /// - /// Some headers excluded by default: - /// - Pragma: - /// - Cache-Control: - /// - Transfer-Encoding: ... chunked ... - /// - Referer: - /// - Content-Encoding: - /// - Expect: - /// - /// @param policy_id @see requestGet() - /// @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 requestPost(policy_t policy_id, - const std::string & url, - BufferArray * body, + const HttpHeaders::ptr_t & headers, + HttpHandler::ptr_t handler); + + + /// Queue a full HTTP POST. Query arguments and body may + /// be provided. Caller is responsible for escaping and + /// encoding and communicating the content types. + /// + /// Headers supplied by default: + /// - Connection: keep-alive + /// - Accept: */* + /// - Accept-Encoding: deflate, gzip + /// - Keep-Alive: 300 + /// - Host: <stuff> + /// - Content-Length: <digits> + /// - Content-Type: application/x-www-form-urlencoded + /// + /// Some headers excluded by default: + /// - Pragma: + /// - Cache-Control: + /// - Transfer-Encoding: ... chunked ... + /// - Referer: + /// - Content-Encoding: + /// - Expect: + /// + /// @param policy_id @see requestGet() + /// @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 requestPost(policy_t policy_id, + const std::string & url, + BufferArray * body, const HttpOptions::ptr_t & options, - const HttpHeaders::ptr_t & headers, - HttpHandler::ptr_t handler); - - - /// Queue a full HTTP PUT. Query arguments and body may - /// be provided. Caller is responsible for escaping and - /// encoding and communicating the content types. - /// - /// Headers supplied by default: - /// - Connection: keep-alive - /// - Accept: */* - /// - Accept-Encoding: deflate, gzip - /// - Keep-Alive: 300 - /// - Host: <stuff> - /// - Content-Length: <digits> - /// - /// Some headers excluded by default: - /// - Pragma: - /// - Cache-Control: - /// - Transfer-Encoding: ... chunked ... - /// - Referer: - /// - Content-Encoding: - /// - Expect: - /// - Content-Type: - /// - /// @param policy_id @see requestGet() - /// @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 requestPut(policy_t policy_id, - const std::string & url, - BufferArray * body, + const HttpHeaders::ptr_t & headers, + HttpHandler::ptr_t handler); + + + /// Queue a full HTTP PUT. Query arguments and body may + /// be provided. Caller is responsible for escaping and + /// encoding and communicating the content types. + /// + /// Headers supplied by default: + /// - Connection: keep-alive + /// - Accept: */* + /// - Accept-Encoding: deflate, gzip + /// - Keep-Alive: 300 + /// - Host: <stuff> + /// - Content-Length: <digits> + /// + /// Some headers excluded by default: + /// - Pragma: + /// - Cache-Control: + /// - Transfer-Encoding: ... chunked ... + /// - Referer: + /// - Content-Encoding: + /// - Expect: + /// - Content-Type: + /// + /// @param policy_id @see requestGet() + /// @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 requestPut(policy_t policy_id, + const std::string & url, + BufferArray * body, const HttpOptions::ptr_t & options, - const HttpHeaders::ptr_t & headers, - HttpHandler::ptr_t handler); + 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 url " - /// @param options @see requestGet()K(optional) - /// @param headers " - /// @param handler " - /// @return " + /// @param policy_id @see requestGet() + /// @param url " + /// @param options @see requestGet()K(optional) + /// @param headers " + /// @param handler " + /// @return " /// HttpHandle requestDelete(policy_t policy_id, const std::string & url, @@ -489,15 +489,15 @@ public: /// be provided. Caller is responsible for escaping and /// encoding and communicating the content types. /// - /// @param policy_id @see requestGet() - /// @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 " + /// @param policy_id @see requestGet() + /// @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, const std::string & url, @@ -510,12 +510,12 @@ public: /// be provided. Caller is responsible for escaping and /// encoding and communicating the content types. /// - /// @param policy_id @see requestGet() - /// @param url " - /// @param options @see requestGet()K(optional) - /// @param headers " - /// @param handler " - /// @return " + /// @param policy_id @see requestGet() + /// @param url " + /// @param options @see requestGet()K(optional) + /// @param headers " + /// @param handler " + /// @return " /// HttpHandle requestCopy(policy_t policy_id, const std::string & url, @@ -527,12 +527,12 @@ public: /// be provided. Caller is responsible for escaping and /// encoding and communicating the content types. /// - /// @param policy_id @see requestGet() - /// @param url " - /// @param options @see requestGet()K(optional) - /// @param headers " - /// @param handler " - /// @return " + /// @param policy_id @see requestGet() + /// @param url " + /// @param options @see requestGet()K(optional) + /// @param headers " + /// @param handler " + /// @return " /// HttpHandle requestMove(policy_t policy_id, const std::string & url, @@ -541,115 +541,115 @@ public: 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. - /// - /// @param handler @see requestGet() - /// @return " - /// - 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 - /// are done synchronously during calls to this method which gives the - /// library control so notification can be performed. Application handlers - /// are expected to return 'quickly' and do any significant processing - /// outside of the notification callback to onCompleted(). - /// - /// @param usecs Maximum number of wallclock microseconds to - /// spend in the call. As hinted at above, this - /// is partly a function of application code so it's - /// a soft limit. A '0' value will run without - /// time limit until everything queued has been - /// delivered. - /// - /// @return Standard status code. - HttpStatus update(long usecs); - - /// @} - - /// @name RequestMgmtMethods - /// - /// @{ - - HttpHandle requestCancel(HttpHandle request, HttpHandler::ptr_t); - - /// @} - - /// @name UtilityMethods - /// - /// @{ - - /// Initialization method that needs to be called before queueing any - /// requests. Doesn't start the worker thread and may be called befoer - /// or after policy setup. - static HttpStatus createService(); - - /// Mostly clean shutdown of services prior to exit. Caller is expected - /// to have stopped a running worker thread before calling this. - static HttpStatus destroyService(); - - /// Called once after @see createService() to start the worker thread. - /// Stopping the thread is achieved by requesting it via @see requestStopThread(). - /// May be called before or after requests are issued. - static HttpStatus startThread(); - - /// Queues a request to the worker thread to have it stop processing - /// and exit (without exiting the program). When the operation is - /// picked up by the worker thread, it immediately processes it and - /// begins detaching from refcounted resources like request and - /// reply queues and then returns to the host OS. It *does* queue a - /// reply to give the calling application thread a notification that - /// the operation has been performed. - /// - /// @param handler (optional) - /// @return The handle of the request if successfully - /// queued or LLCORE_HTTP_HANDLE_INVALID if the - /// request could not be queued. In the latter - /// case, @see getStatus() will return more info. - /// As the request cannot be cancelled, the handle - /// is generally not useful. - /// - HttpHandle requestStopThread(HttpHandler::ptr_t handler); - - /// Queue a Spin request. - /// DEBUG/TESTING ONLY. This puts the worker into a CPU spin for - /// test purposes. - /// - /// @param mode 0 for hard spin, 1 for soft spin - /// @return Standard handle return cases. - /// - HttpHandle requestSpin(int mode); - - /// @} - + /// The request is queued and serviced by the working thread which + /// immediately processes it and returns the request to the reply + /// queue. + /// + /// @param handler @see requestGet() + /// @return " + /// + 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 + /// are done synchronously during calls to this method which gives the + /// library control so notification can be performed. Application handlers + /// are expected to return 'quickly' and do any significant processing + /// outside of the notification callback to onCompleted(). + /// + /// @param usecs Maximum number of wallclock microseconds to + /// spend in the call. As hinted at above, this + /// is partly a function of application code so it's + /// a soft limit. A '0' value will run without + /// time limit until everything queued has been + /// delivered. + /// + /// @return Standard status code. + HttpStatus update(long usecs); + + /// @} + + /// @name RequestMgmtMethods + /// + /// @{ + + HttpHandle requestCancel(HttpHandle request, HttpHandler::ptr_t); + + /// @} + + /// @name UtilityMethods + /// + /// @{ + + /// Initialization method that needs to be called before queueing any + /// requests. Doesn't start the worker thread and may be called befoer + /// or after policy setup. + static HttpStatus createService(); + + /// Mostly clean shutdown of services prior to exit. Caller is expected + /// to have stopped a running worker thread before calling this. + static HttpStatus destroyService(); + + /// Called once after @see createService() to start the worker thread. + /// Stopping the thread is achieved by requesting it via @see requestStopThread(). + /// May be called before or after requests are issued. + static HttpStatus startThread(); + + /// Queues a request to the worker thread to have it stop processing + /// and exit (without exiting the program). When the operation is + /// picked up by the worker thread, it immediately processes it and + /// begins detaching from refcounted resources like request and + /// reply queues and then returns to the host OS. It *does* queue a + /// reply to give the calling application thread a notification that + /// the operation has been performed. + /// + /// @param handler (optional) + /// @return The handle of the request if successfully + /// queued or LLCORE_HTTP_HANDLE_INVALID if the + /// request could not be queued. In the latter + /// case, @see getStatus() will return more info. + /// As the request cannot be cancelled, the handle + /// is generally not useful. + /// + HttpHandle requestStopThread(HttpHandler::ptr_t handler); + + /// Queue a Spin request. + /// DEBUG/TESTING ONLY. This puts the worker into a CPU spin for + /// test purposes. + /// + /// @param mode 0 for hard spin, 1 for soft spin + /// @return Standard handle return cases. + /// + HttpHandle requestSpin(int mode); + + /// @} + protected: private: typedef std::shared_ptr<HttpReplyQueue> HttpReplyQueuePtr_t; - /// @name InstanceData - /// - /// @{ - HttpStatus mLastReqStatus; - HttpReplyQueuePtr_t mReplyQueue; - HttpRequestQueue * mRequestQueue; - - /// @} - - // ==================================== - /// @name GlobalState - /// - /// @{ - /// - /// Must be established before any threading is allowed to - /// start. - /// - - /// @} - // End Global State - // ==================================== + /// @name InstanceData + /// + /// @{ + HttpStatus mLastReqStatus; + HttpReplyQueuePtr_t mReplyQueue; + HttpRequestQueue * mRequestQueue; + + /// @} + + // ==================================== + /// @name GlobalState + /// + /// @{ + /// + /// Must be established before any threading is allowed to + /// start. + /// + + /// @} + // End Global State + // ==================================== }; // end class HttpRequest @@ -658,4 +658,4 @@ private: -#endif // _LLCORE_HTTP_REQUEST_H_ +#endif // _LLCORE_HTTP_REQUEST_H_ diff --git a/indra/llcorehttp/httpresponse.cpp b/indra/llcorehttp/httpresponse.cpp index f5ad2ebd47..1436054c0b 100644 --- a/indra/llcorehttp/httpresponse.cpp +++ b/indra/llcorehttp/httpresponse.cpp @@ -1,6 +1,6 @@ /** * @file httpresponse.cpp - * @brief + * @brief * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Second Life Viewer Source Code @@ -34,41 +34,41 @@ namespace LLCore HttpResponse::HttpResponse() - : LLCoreInt::RefCounted(true), - mReplyOffset(0U), - mReplyLength(0U), - mReplyFullLength(0U), - mBufferArray(NULL), - mHeaders(), - mRetries(0U), - m503Retries(0U), + : LLCoreInt::RefCounted(true), + mReplyOffset(0U), + mReplyLength(0U), + mReplyFullLength(0U), + mBufferArray(NULL), + mHeaders(), + mRetries(0U), + m503Retries(0U), mRequestUrl() {} HttpResponse::~HttpResponse() { - setBody(NULL); - //setHeaders(); + setBody(NULL); + //setHeaders(); } void HttpResponse::setBody(BufferArray * ba) { - if (mBufferArray == ba) - return; - - if (mBufferArray) - { - mBufferArray->release(); - } - - if (ba) - { - ba->addRef(); - } - - mBufferArray = ba; + if (mBufferArray == ba) + return; + + if (mBufferArray) + { + mBufferArray->release(); + } + + if (ba) + { + ba->addRef(); + } + + mBufferArray = ba; } @@ -79,7 +79,7 @@ void HttpResponse::setHeaders(HttpHeaders::ptr_t &headers) size_t HttpResponse::getBodySize() const { - return (mBufferArray) ? mBufferArray->size() : 0; + return (mBufferArray) ? mBufferArray->size() : 0; } } // end namespace LLCore diff --git a/indra/llcorehttp/httpresponse.h b/indra/llcorehttp/httpresponse.h index ef98fbef2b..99c8f1d2f9 100644 --- a/indra/llcorehttp/httpresponse.h +++ b/indra/llcorehttp/httpresponse.h @@ -24,8 +24,8 @@ * $/LicenseInfo$ */ -#ifndef _LLCORE_HTTP_RESPONSE_H_ -#define _LLCORE_HTTP_RESPONSE_H_ +#ifndef _LLCORE_HTTP_RESPONSE_H_ +#define _LLCORE_HTTP_RESPONSE_H_ #include <string> @@ -60,139 +60,139 @@ class HttpHeaders; class HttpResponse : public LLCoreInt::RefCounted { public: - HttpResponse(); + HttpResponse(); protected: - virtual ~HttpResponse(); // Use release() - - HttpResponse(const HttpResponse &); // Not defined - void operator=(const HttpResponse &); // Not defined - + virtual ~HttpResponse(); // Use release() + + HttpResponse(const HttpResponse &); // Not defined + void operator=(const HttpResponse &); // Not defined + public: - /// Statistics for the HTTP - struct TransferStats - { - typedef std::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 - { - return mStatus; - } - - void setStatus(const HttpStatus & status) - { - mStatus = status; - } - - /// Simple getter for the response body returned as a scatter/gather - /// buffer. If the operation doesn't produce data (such as the Null - /// or StopThread operations), this may be NULL. - /// - /// Caller can hold onto the response by incrementing the reference - /// count of the returned object. - BufferArray * getBody() const - { - 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. - void setBody(BufferArray * ba); - - /// And a getter for the headers. And as with @see getResponse(), - /// if headers aren't available because the operation doesn't produce - /// any or delivery of headers wasn't requested in the options, this - /// will be NULL. - /// - /// Caller can hold onto the headers by incrementing the reference - /// count of the returned object. - HttpHeaders::ptr_t getHeaders() const - { - return mHeaders; - } - - /// Behaves like @see setResponse() but for header data. - 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. - /// If both @offset and @length are returned as 0, we probably - /// didn't get a Content-Range header in the response. This - /// occurs with various Capabilities-based services and the - /// caller is going to have to make assumptions on receipt of - /// a 206 status. The @full value may also be zero in cases of - /// parsing problems or a wild-carded length response. - /// - /// These values will not necessarily agree with the data in - /// the body itself (if present). The BufferArray object - /// is authoritative for actual data length. - void getRange(unsigned int * offset, unsigned int * length, unsigned int * full) const - { - *offset = mReplyOffset; - *length = mReplyLength; - *full = mReplyFullLength; - } - - void setRange(unsigned int offset, unsigned int length, unsigned int full_length) - { - mReplyOffset = offset; - mReplyLength = length; - mReplyFullLength = full_length; - } - - /// - const std::string & getContentType() const - { - return mContentType; - } - - void setContentType(const std::string & con_type) - { - mContentType = con_type; - } - - /// Get and set retry attempt information on the request. - void getRetries(unsigned int * retries, unsigned int * retries_503) const - { - if (retries) - { - *retries = mRetries; - } - if (retries_503) - { - *retries_503 = m503Retries; - } - } - - void setRetries(unsigned int retries, unsigned int retries_503) - { - mRetries = retries; - m503Retries = retries_503; - } - - void setTransferStats(TransferStats::ptr_t &stats) - { - mStats = stats; - } - - TransferStats::ptr_t getTransferStats() - { - return mStats; - } + /// Statistics for the HTTP + struct TransferStats + { + typedef std::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 + { + return mStatus; + } + + void setStatus(const HttpStatus & status) + { + mStatus = status; + } + + /// Simple getter for the response body returned as a scatter/gather + /// buffer. If the operation doesn't produce data (such as the Null + /// or StopThread operations), this may be NULL. + /// + /// Caller can hold onto the response by incrementing the reference + /// count of the returned object. + BufferArray * getBody() const + { + 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. + void setBody(BufferArray * ba); + + /// And a getter for the headers. And as with @see getResponse(), + /// if headers aren't available because the operation doesn't produce + /// any or delivery of headers wasn't requested in the options, this + /// will be NULL. + /// + /// Caller can hold onto the headers by incrementing the reference + /// count of the returned object. + HttpHeaders::ptr_t getHeaders() const + { + return mHeaders; + } + + /// Behaves like @see setResponse() but for header data. + 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. + /// If both @offset and @length are returned as 0, we probably + /// didn't get a Content-Range header in the response. This + /// occurs with various Capabilities-based services and the + /// caller is going to have to make assumptions on receipt of + /// a 206 status. The @full value may also be zero in cases of + /// parsing problems or a wild-carded length response. + /// + /// These values will not necessarily agree with the data in + /// the body itself (if present). The BufferArray object + /// is authoritative for actual data length. + void getRange(unsigned int * offset, unsigned int * length, unsigned int * full) const + { + *offset = mReplyOffset; + *length = mReplyLength; + *full = mReplyFullLength; + } + + void setRange(unsigned int offset, unsigned int length, unsigned int full_length) + { + mReplyOffset = offset; + mReplyLength = length; + mReplyFullLength = full_length; + } + + /// + const std::string & getContentType() const + { + return mContentType; + } + + void setContentType(const std::string & con_type) + { + mContentType = con_type; + } + + /// Get and set retry attempt information on the request. + void getRetries(unsigned int * retries, unsigned int * retries_503) const + { + if (retries) + { + *retries = mRetries; + } + if (retries_503) + { + *retries_503 = m503Retries; + } + } + + void setRetries(unsigned int retries, unsigned int retries_503) + { + mRetries = retries; + m503Retries = retries_503; + } + + void setTransferStats(TransferStats::ptr_t &stats) + { + mStats = stats; + } + + TransferStats::ptr_t getTransferStats() + { + return mStats; + } void setRequestURL(const std::string &url) { @@ -215,23 +215,23 @@ public: } protected: - // Response data here - HttpStatus mStatus; - unsigned int mReplyOffset; - unsigned int mReplyLength; - unsigned int mReplyFullLength; - BufferArray * mBufferArray; - HttpHeaders::ptr_t mHeaders; - std::string mContentType; - unsigned int mRetries; - unsigned int m503Retries; + // Response data here + HttpStatus mStatus; + unsigned int mReplyOffset; + unsigned int mReplyLength; + unsigned int mReplyFullLength; + BufferArray * mBufferArray; + HttpHeaders::ptr_t mHeaders; + std::string mContentType; + unsigned int mRetries; + unsigned int m503Retries; std::string mRequestUrl; std::string mRequestMethod; - TransferStats::ptr_t mStats; + TransferStats::ptr_t mStats; }; } // end namespace LLCore -#endif // _LLCORE_HTTP_RESPONSE_H_ +#endif // _LLCORE_HTTP_RESPONSE_H_ diff --git a/indra/llcorehttp/httpstats.cpp b/indra/llcorehttp/httpstats.cpp index 19eceae5ef..dc2ac35c71 100644 --- a/indra/llcorehttp/httpstats.cpp +++ b/indra/llcorehttp/httpstats.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llviewerstats.cpp * @brief LLViewerStats class implementation * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, 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$ */ @@ -97,7 +97,7 @@ void HTTPStats::dumpStats() out << "Result Codes:" << std::endl << "--- -----" << std::endl; for (std::map<S32, S32>::iterator it = mResutCodes.begin(); it != mResutCodes.end(); ++it) - { + { out << (*it).first << " " << (*it).second << std::endl; } diff --git a/indra/llcorehttp/httpstats.h b/indra/llcorehttp/httpstats.h index 2c713cb548..e1387d9df5 100644 --- a/indra/llcorehttp/httpstats.h +++ b/indra/llcorehttp/httpstats.h @@ -1,25 +1,25 @@ -/** +/** * @file llviewerim_peningtats.h * @brief LLViewerStats class header file * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, 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$ */ diff --git a/indra/llcorehttp/llhttpconstants.cpp b/indra/llcorehttp/llhttpconstants.cpp index 71d4f19408..40d6c7506c 100755 --- a/indra/llcorehttp/llhttpconstants.cpp +++ b/indra/llcorehttp/llhttpconstants.cpp @@ -1,25 +1,25 @@ -/** +/** * @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$ */ diff --git a/indra/llcorehttp/llhttpconstants.h b/indra/llcorehttp/llhttpconstants.h index 121448854e..583f9fbcb7 100755 --- a/indra/llcorehttp/llhttpconstants.h +++ b/indra/llcorehttp/llhttpconstants.h @@ -1,25 +1,25 @@ -/** +/** * @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$ */ @@ -103,17 +103,17 @@ 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 + 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. diff --git a/indra/llcorehttp/tests/llcorehttp_test.cpp b/indra/llcorehttp/tests/llcorehttp_test.cpp index 362b2309ee..c0cc2c8030 100755 --- a/indra/llcorehttp/tests/llcorehttp_test.cpp +++ b/indra/llcorehttp/tests/llcorehttp_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llcorehttp_test * @brief Main test runner * @@ -56,26 +56,26 @@ void ssl_thread_id_callback(CRYPTO_THREADID*); void ssl_locking_callback(int mode, int type, const char * file, int line); -#if 0 // lltut provides main and runner +#if 0 // lltut provides main and runner namespace tut { - test_runner_singleton runner; + test_runner_singleton runner; } int main() { - curl_global_init(CURL_GLOBAL_ALL); + curl_global_init(CURL_GLOBAL_ALL); - // *FIXME: Need threaded/SSL curl setup here. - - tut::reporter reporter; + // *FIXME: Need threaded/SSL curl setup here. - tut::runner.get().set_callback(&reporter); - tut::runner.get().run_tests(); - return !reporter.all_ok(); + tut::reporter reporter; - curl_global_cleanup(); + tut::runner.get().set_callback(&reporter); + tut::runner.get().run_tests(); + return !reporter.all_ok(); + + curl_global_cleanup(); } #endif // 0 @@ -85,95 +85,95 @@ LLCoreInt::HttpMutex ** ssl_mutex_list = NULL; void init_curl() { - curl_global_init(CURL_GLOBAL_ALL); - - ssl_mutex_count = CRYPTO_num_locks(); - if (ssl_mutex_count > 0) - { - ssl_mutex_list = new LLCoreInt::HttpMutex * [ssl_mutex_count]; - - for (int i(0); i < ssl_mutex_count; ++i) - { - ssl_mutex_list[i] = new LLCoreInt::HttpMutex; - } - - CRYPTO_set_locking_callback(ssl_locking_callback); - CRYPTO_THREADID_set_callback(ssl_thread_id_callback); - } - - LLProxy::getInstance(); + curl_global_init(CURL_GLOBAL_ALL); + + ssl_mutex_count = CRYPTO_num_locks(); + if (ssl_mutex_count > 0) + { + ssl_mutex_list = new LLCoreInt::HttpMutex * [ssl_mutex_count]; + + for (int i(0); i < ssl_mutex_count; ++i) + { + ssl_mutex_list[i] = new LLCoreInt::HttpMutex; + } + + CRYPTO_set_locking_callback(ssl_locking_callback); + CRYPTO_THREADID_set_callback(ssl_thread_id_callback); + } + + LLProxy::getInstance(); } void term_curl() { - SUBSYSTEM_CLEANUP(LLProxy); - - CRYPTO_set_locking_callback(NULL); - for (int i(0); i < ssl_mutex_count; ++i) - { - delete ssl_mutex_list[i]; - } - delete [] ssl_mutex_list; + SUBSYSTEM_CLEANUP(LLProxy); + + CRYPTO_set_locking_callback(NULL); + for (int i(0); i < ssl_mutex_count; ++i) + { + delete ssl_mutex_list[i]; + } + delete [] ssl_mutex_list; } void ssl_thread_id_callback(CRYPTO_THREADID* pthreadid) { #if defined(WIN32) - CRYPTO_THREADID_set_pointer(pthreadid, GetCurrentThread()); + CRYPTO_THREADID_set_pointer(pthreadid, GetCurrentThread()); #else - CRYPTO_THREADID_set_pointer(pthreadid, pthread_self()); + CRYPTO_THREADID_set_pointer(pthreadid, pthread_self()); #endif } void ssl_locking_callback(int mode, int type, const char * /* file */, int /* line */) { - if (type >= 0 && type < ssl_mutex_count) - { - if (mode & CRYPTO_LOCK) - { - ssl_mutex_list[type]->lock(); - } - else - { - ssl_mutex_list[type]->unlock(); - } - } + if (type >= 0 && type < ssl_mutex_count) + { + if (mode & CRYPTO_LOCK) + { + ssl_mutex_list[type]->lock(); + } + else + { + ssl_mutex_list[type]->unlock(); + } + } } std::string get_base_url() { - const char * env(getenv("LL_TEST_PORT")); - - if (! env) - { - std::cerr << "LL_TEST_PORT environment variable missing." << std::endl; - std::cerr << "Test expects to run in test_llcorehttp_peer.py script." << std::endl; - tut::ensure("LL_TEST_PORT set in environment", NULL != env); - } - - int port(atoi(env)); - std::ostringstream out; - out << "http://localhost:" << port << "/"; - return out.str(); + const char * env(getenv("LL_TEST_PORT")); + + if (! env) + { + std::cerr << "LL_TEST_PORT environment variable missing." << std::endl; + std::cerr << "Test expects to run in test_llcorehttp_peer.py script." << std::endl; + tut::ensure("LL_TEST_PORT set in environment", NULL != env); + } + + int port(atoi(env)); + std::ostringstream out; + out << "http://localhost:" << port << "/"; + return out.str(); } void stop_thread(LLCore::HttpRequest * req) { - if (req) - { - req->requestStopThread(LLCore::HttpHandler::ptr_t()); - - int count = 0; - int limit = 10; - while (count++ < limit && ! HttpService::isStopped()) - { - req->update(1000); - usleep(100000); - } - } + if (req) + { + req->requestStopThread(LLCore::HttpHandler::ptr_t()); + + int count = 0; + int limit = 10; + while (count++ < limit && ! HttpService::isStopped()) + { + req->update(1000); + usleep(100000); + } + } } diff --git a/indra/llcorehttp/tests/llcorehttp_test.h b/indra/llcorehttp/tests/llcorehttp_test.h index a9567435ce..133cb3121a 100644 --- a/indra/llcorehttp/tests/llcorehttp_test.h +++ b/indra/llcorehttp/tests/llcorehttp_test.h @@ -1,4 +1,4 @@ -/** +/** * @file llcorehttp_test.h * @brief Main test runner * @@ -26,9 +26,9 @@ #ifndef _LLCOREHTTP_TEST_H_ -#define _LLCOREHTTP_TEST_H_ +#define _LLCOREHTTP_TEST_H_ -#include "linden_common.h" // Modifies curl interfaces +#include "linden_common.h" // Modifies curl interfaces #include <curl/curl.h> #include <openssl/crypto.h> @@ -49,16 +49,16 @@ extern void stop_thread(LLCore::HttpRequest * req); class ScopedCurlInit { public: - ScopedCurlInit() - { - init_curl(); - } + ScopedCurlInit() + { + init_curl(); + } - ~ScopedCurlInit() - { - term_curl(); - } + ~ScopedCurlInit() + { + term_curl(); + } }; - -#endif // _LLCOREHTTP_TEST_H_ + +#endif // _LLCOREHTTP_TEST_H_ diff --git a/indra/llcorehttp/tests/test_allocator.cpp b/indra/llcorehttp/tests/test_allocator.cpp index 597e0d2fc9..757736acbb 100644 --- a/indra/llcorehttp/tests/test_allocator.cpp +++ b/indra/llcorehttp/tests/test_allocator.cpp @@ -1,4 +1,4 @@ -/** +/** * @file test_allocator.cpp * @brief quick and dirty allocator for tracking memory allocations * @@ -45,15 +45,15 @@ struct BlockHeader { - struct Block * next; - std::size_t size; - bool in_use; + struct Block * next; + std::size_t size; + bool in_use; }; struct Block { - BlockHeader hdr; - unsigned char data[1]; + BlockHeader hdr; + unsigned char data[1]; }; #define TRACE_MSG(val) std::cout << __FUNCTION__ << "(" << val << ") [" << __FILE__ << ":" << __LINE__ << "]" << std::endl; @@ -66,109 +66,109 @@ volatile std::size_t MemTotal = 0; static bool CAS(void * volatile * ptr, void * expected, void * new_value) { #if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050 - return OSAtomicCompareAndSwapPtr( expected, new_value, ptr ); + return OSAtomicCompareAndSwapPtr( expected, new_value, ptr ); #elif defined(_MSC_VER) - return expected == InterlockedCompareExchangePointer( ptr, new_value, expected ); + return expected == InterlockedCompareExchangePointer( ptr, new_value, expected ); #elif (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ ) > 40100 - return __sync_bool_compare_and_swap( ptr, expected, new_value ); + return __sync_bool_compare_and_swap( ptr, expected, new_value ); #endif } static void * GetMem(std::size_t size) { - // TRACE_MSG(size); - volatile Block * pBlock = NULL; - volatile Block * pNewNext = NULL; - - // do a lock-free update of the global next pointer - do - { - pBlock = pNext; - pNewNext = (volatile Block *)(pBlock->data + size); - - } while(! CAS((void * volatile *) &pNext, (void *) pBlock, (void *) pNewNext)); - - // if we get here, we safely carved out a block of memory in the - // memory pool... - - // initialize our block - pBlock->hdr.next = (Block *)(pBlock->data + size); - pBlock->hdr.size = size; - pBlock->hdr.in_use = true; - memset((void *) pBlock->data, 0, pBlock->hdr.size); - - // do a lock-free update of the global memory total - volatile size_t total = 0; - volatile size_t new_total = 0; - do - { - total = MemTotal; - new_total = total + size; - - } while (! CAS((void * volatile *) &MemTotal, (void *) total, (void *) new_total)); - - return (void *) pBlock->data; + // TRACE_MSG(size); + volatile Block * pBlock = NULL; + volatile Block * pNewNext = NULL; + + // do a lock-free update of the global next pointer + do + { + pBlock = pNext; + pNewNext = (volatile Block *)(pBlock->data + size); + + } while(! CAS((void * volatile *) &pNext, (void *) pBlock, (void *) pNewNext)); + + // if we get here, we safely carved out a block of memory in the + // memory pool... + + // initialize our block + pBlock->hdr.next = (Block *)(pBlock->data + size); + pBlock->hdr.size = size; + pBlock->hdr.in_use = true; + memset((void *) pBlock->data, 0, pBlock->hdr.size); + + // do a lock-free update of the global memory total + volatile size_t total = 0; + volatile size_t new_total = 0; + do + { + total = MemTotal; + new_total = total + size; + + } while (! CAS((void * volatile *) &MemTotal, (void *) total, (void *) new_total)); + + return (void *) pBlock->data; } static void FreeMem(void * p) { - // get the pointer to the block record - Block * pBlock = (Block *)((unsigned char *) p - sizeof(BlockHeader)); - - // TRACE_MSG(pBlock->hdr.size); - bool * cur_in_use = &(pBlock->hdr.in_use); - volatile bool in_use = false; - bool new_in_use = false; - do - { - in_use = pBlock->hdr.in_use; - } while (! CAS((void * volatile *) cur_in_use, (void *) in_use, (void *) new_in_use)); - - // do a lock-free update of the global memory total - volatile size_t total = 0; - volatile size_t new_total = 0; - do - { - total = MemTotal; - new_total = total - pBlock->hdr.size; - } while (! CAS((void * volatile *)&MemTotal, (void *) total, (void *) new_total)); + // get the pointer to the block record + Block * pBlock = (Block *)((unsigned char *) p - sizeof(BlockHeader)); + + // TRACE_MSG(pBlock->hdr.size); + bool * cur_in_use = &(pBlock->hdr.in_use); + volatile bool in_use = false; + bool new_in_use = false; + do + { + in_use = pBlock->hdr.in_use; + } while (! CAS((void * volatile *) cur_in_use, (void *) in_use, (void *) new_in_use)); + + // do a lock-free update of the global memory total + volatile size_t total = 0; + volatile size_t new_total = 0; + do + { + total = MemTotal; + new_total = total - pBlock->hdr.size; + } while (! CAS((void * volatile *)&MemTotal, (void *) total, (void *) new_total)); } std::size_t GetMemTotal() { - return MemTotal; + return MemTotal; } void * operator new(std::size_t size) //throw(std::bad_alloc) { - return GetMem( size ); + return GetMem( size ); } void * operator new[](std::size_t size) //throw(std::bad_alloc) { - return GetMem( size ); + return GetMem( size ); } void operator delete(void * p) throw() { - if (p) - { - FreeMem( p ); - } + if (p) + { + FreeMem( p ); + } } void operator delete[](void * p) throw() { - if (p) - { - FreeMem( p ); - } + if (p) + { + FreeMem( p ); + } } diff --git a/indra/llcorehttp/tests/test_allocator.h b/indra/llcorehttp/tests/test_allocator.h index abd88f4c98..2a06431d1b 100644 --- a/indra/llcorehttp/tests/test_allocator.h +++ b/indra/llcorehttp/tests/test_allocator.h @@ -1,4 +1,4 @@ -/** +/** * @file test_allocator.h * @brief quick and dirty allocator for tracking memory allocations * diff --git a/indra/llcorehttp/tests/test_bufferarray.hpp b/indra/llcorehttp/tests/test_bufferarray.hpp index cc4ad2a906..2a272e73d7 100644 --- a/indra/llcorehttp/tests/test_bufferarray.hpp +++ b/indra/llcorehttp/tests/test_bufferarray.hpp @@ -1,4 +1,4 @@ -/** +/** * @file test_bufferarray.hpp * @brief unit tests for the LLCore::BufferArray class * @@ -40,8 +40,8 @@ namespace tut struct BufferArrayTestData { - // the test objects inherit from this so the member functions and variables - // can be referenced directly inside of the test functions. + // the test objects inherit from this so the member functions and variables + // can be referenced directly inside of the test functions. }; typedef test_group<BufferArrayTestData> BufferArrayTestGroupType; @@ -51,327 +51,327 @@ BufferArrayTestGroupType BufferArrayTestGroup("BufferArray Tests"); template <> template <> void BufferArrayTestObjectType::test<1>() { - set_test_name("BufferArray construction"); - - // create a new ref counted object with an implicit reference - BufferArray * ba = new BufferArray(); - ensure("One ref on construction of BufferArray", ba->getRefCount() == 1); - ensure("Nothing in BA", 0 == ba->size()); - - // Try to read - char buffer[20]; - size_t read_len(ba->read(0, buffer, sizeof(buffer))); - ensure("Read returns empty", 0 == read_len); - - // release the implicit reference, causing the object to be released - ba->release(); + set_test_name("BufferArray construction"); + + // create a new ref counted object with an implicit reference + BufferArray * ba = new BufferArray(); + ensure("One ref on construction of BufferArray", ba->getRefCount() == 1); + ensure("Nothing in BA", 0 == ba->size()); + + // Try to read + char buffer[20]; + size_t read_len(ba->read(0, buffer, sizeof(buffer))); + ensure("Read returns empty", 0 == read_len); + + // release the implicit reference, causing the object to be released + ba->release(); } template <> template <> void BufferArrayTestObjectType::test<2>() { - set_test_name("BufferArray single write"); - - // create a new ref counted object with an implicit reference - BufferArray * ba = new BufferArray(); - - // write some data to the buffer - char str1[] = "abcdefghij"; - char buffer[256]; - - size_t len = ba->write(0, str1, strlen(str1)); - ensure("Wrote length correct", strlen(str1) == len); - ensure("Recorded size correct", strlen(str1) == ba->size()); - - // read some data back - memset(buffer, 'X', sizeof(buffer)); - len = ba->read(2, buffer, 2); - ensure("Read length correct", 2 == len); - ensure("Read content correct", 'c' == buffer[0] && 'd' == buffer[1]); - ensure("Read didn't overwrite", 'X' == buffer[2]); - - // release the implicit reference, causing the object to be released - ba->release(); + set_test_name("BufferArray single write"); + + // create a new ref counted object with an implicit reference + BufferArray * ba = new BufferArray(); + + // write some data to the buffer + char str1[] = "abcdefghij"; + char buffer[256]; + + size_t len = ba->write(0, str1, strlen(str1)); + ensure("Wrote length correct", strlen(str1) == len); + ensure("Recorded size correct", strlen(str1) == ba->size()); + + // read some data back + memset(buffer, 'X', sizeof(buffer)); + len = ba->read(2, buffer, 2); + ensure("Read length correct", 2 == len); + ensure("Read content correct", 'c' == buffer[0] && 'd' == buffer[1]); + ensure("Read didn't overwrite", 'X' == buffer[2]); + + // release the implicit reference, causing the object to be released + ba->release(); } template <> template <> void BufferArrayTestObjectType::test<3>() { - set_test_name("BufferArray multiple writes"); - - // create a new ref counted object with an implicit reference - BufferArray * ba = new BufferArray(); - - // write some data to the buffer - char str1[] = "abcdefghij"; - size_t str1_len(strlen(str1)); - char buffer[256]; - - size_t len = ba->write(0, str1, str1_len); - ensure("Wrote length correct", str1_len == len); - ensure("Recorded size correct", str1_len == ba->size()); - - // again... - len = ba->write(str1_len, str1, strlen(str1)); - ensure("Wrote length correct", str1_len == len); - ensure("Recorded size correct", (2 * str1_len) == ba->size()); - - // read some data back - memset(buffer, 'X', sizeof(buffer)); - len = ba->read(8, buffer, 4); - ensure("Read length correct", 4 == len); - ensure("Read content correct", 'i' == buffer[0] && 'j' == buffer[1]); - ensure("Read content correct", 'a' == buffer[2] && 'b' == buffer[3]); - ensure("Read didn't overwrite", 'X' == buffer[4]); - - // Read whole thing - memset(buffer, 'X', sizeof(buffer)); - len = ba->read(0, buffer, sizeof(buffer)); - ensure("Read length correct", (2 * str1_len) == len); - ensure("Read content correct (3)", 0 == strncmp(buffer, str1, str1_len)); - ensure("Read content correct (4)", 0 == strncmp(&buffer[str1_len], str1, str1_len)); - ensure("Read didn't overwrite (5)", 'X' == buffer[2 * str1_len]); - - // release the implicit reference, causing the object to be released - ba->release(); + set_test_name("BufferArray multiple writes"); + + // create a new ref counted object with an implicit reference + BufferArray * ba = new BufferArray(); + + // write some data to the buffer + char str1[] = "abcdefghij"; + size_t str1_len(strlen(str1)); + char buffer[256]; + + size_t len = ba->write(0, str1, str1_len); + ensure("Wrote length correct", str1_len == len); + ensure("Recorded size correct", str1_len == ba->size()); + + // again... + len = ba->write(str1_len, str1, strlen(str1)); + ensure("Wrote length correct", str1_len == len); + ensure("Recorded size correct", (2 * str1_len) == ba->size()); + + // read some data back + memset(buffer, 'X', sizeof(buffer)); + len = ba->read(8, buffer, 4); + ensure("Read length correct", 4 == len); + ensure("Read content correct", 'i' == buffer[0] && 'j' == buffer[1]); + ensure("Read content correct", 'a' == buffer[2] && 'b' == buffer[3]); + ensure("Read didn't overwrite", 'X' == buffer[4]); + + // Read whole thing + memset(buffer, 'X', sizeof(buffer)); + len = ba->read(0, buffer, sizeof(buffer)); + ensure("Read length correct", (2 * str1_len) == len); + ensure("Read content correct (3)", 0 == strncmp(buffer, str1, str1_len)); + ensure("Read content correct (4)", 0 == strncmp(&buffer[str1_len], str1, str1_len)); + ensure("Read didn't overwrite (5)", 'X' == buffer[2 * str1_len]); + + // release the implicit reference, causing the object to be released + ba->release(); } template <> template <> void BufferArrayTestObjectType::test<4>() { - set_test_name("BufferArray overwriting"); - - // create a new ref counted object with an implicit reference - BufferArray * ba = new BufferArray(); - - // write some data to the buffer - char str1[] = "abcdefghij"; - size_t str1_len(strlen(str1)); - char str2[] = "ABCDEFGHIJ"; - char buffer[256]; - - size_t len = ba->write(0, str1, str1_len); - ensure("Wrote length correct", str1_len == len); - ensure("Recorded size correct", str1_len == ba->size()); - - // again... - len = ba->write(str1_len, str1, strlen(str1)); - ensure("Wrote length correct", str1_len == len); - ensure("Recorded size correct", (2 * str1_len) == ba->size()); - - // reposition and overwrite - len = ba->write(8, str2, 4); - ensure("Overwrite length correct", 4 == len); - - // Leave position and read verifying content (stale really from seek() days) - memset(buffer, 'X', sizeof(buffer)); - len = ba->read(12, buffer, 4); - ensure("Read length correct", 4 == len); - ensure("Read content correct", 'c' == buffer[0] && 'd' == buffer[1]); - ensure("Read content correct.2", 'e' == buffer[2] && 'f' == buffer[3]); - ensure("Read didn't overwrite", 'X' == buffer[4]); - - // reposition and check - len = ba->read(6, buffer, 8); - ensure("Read length correct.2", 8 == len); - ensure("Read content correct.3", 'g' == buffer[0] && 'h' == buffer[1]); - ensure("Read content correct.4", 'A' == buffer[2] && 'B' == buffer[3]); - ensure("Read content correct.5", 'C' == buffer[4] && 'D' == buffer[5]); - ensure("Read content correct.6", 'c' == buffer[6] && 'd' == buffer[7]); - ensure("Read didn't overwrite.7", 'X' == buffer[8]); - - // release the implicit reference, causing the object to be released - ba->release(); + set_test_name("BufferArray overwriting"); + + // create a new ref counted object with an implicit reference + BufferArray * ba = new BufferArray(); + + // write some data to the buffer + char str1[] = "abcdefghij"; + size_t str1_len(strlen(str1)); + char str2[] = "ABCDEFGHIJ"; + char buffer[256]; + + size_t len = ba->write(0, str1, str1_len); + ensure("Wrote length correct", str1_len == len); + ensure("Recorded size correct", str1_len == ba->size()); + + // again... + len = ba->write(str1_len, str1, strlen(str1)); + ensure("Wrote length correct", str1_len == len); + ensure("Recorded size correct", (2 * str1_len) == ba->size()); + + // reposition and overwrite + len = ba->write(8, str2, 4); + ensure("Overwrite length correct", 4 == len); + + // Leave position and read verifying content (stale really from seek() days) + memset(buffer, 'X', sizeof(buffer)); + len = ba->read(12, buffer, 4); + ensure("Read length correct", 4 == len); + ensure("Read content correct", 'c' == buffer[0] && 'd' == buffer[1]); + ensure("Read content correct.2", 'e' == buffer[2] && 'f' == buffer[3]); + ensure("Read didn't overwrite", 'X' == buffer[4]); + + // reposition and check + len = ba->read(6, buffer, 8); + ensure("Read length correct.2", 8 == len); + ensure("Read content correct.3", 'g' == buffer[0] && 'h' == buffer[1]); + ensure("Read content correct.4", 'A' == buffer[2] && 'B' == buffer[3]); + ensure("Read content correct.5", 'C' == buffer[4] && 'D' == buffer[5]); + ensure("Read content correct.6", 'c' == buffer[6] && 'd' == buffer[7]); + ensure("Read didn't overwrite.7", 'X' == buffer[8]); + + // release the implicit reference, causing the object to be released + ba->release(); } template <> template <> void BufferArrayTestObjectType::test<5>() { - set_test_name("BufferArray multiple writes - sequential reads"); - - // create a new ref counted object with an implicit reference - BufferArray * ba = new BufferArray(); - - // write some data to the buffer - char str1[] = "abcdefghij"; - size_t str1_len(strlen(str1)); - char buffer[256]; - - size_t len = ba->write(0, str1, str1_len); - ensure("Wrote length correct", str1_len == len); - ensure("Recorded size correct", str1_len == ba->size()); - - // again... - len = ba->write(str1_len, str1, str1_len); - ensure("Wrote length correct", str1_len == len); - ensure("Recorded size correct", (2 * str1_len) == ba->size()); - - // read some data back - memset(buffer, 'X', sizeof(buffer)); - len = ba->read(8, buffer, 4); - ensure("Read length correct", 4 == len); - ensure("Read content correct", 'i' == buffer[0] && 'j' == buffer[1]); - ensure("Read content correct.2", 'a' == buffer[2] && 'b' == buffer[3]); - ensure("Read didn't overwrite", 'X' == buffer[4]); - - // Read some more without repositioning - memset(buffer, 'X', sizeof(buffer)); - len = ba->read(12, buffer, sizeof(buffer)); - ensure("Read length correct", (str1_len - 2) == len); - ensure("Read content correct.3", 0 == strncmp(buffer, str1+2, str1_len-2)); - ensure("Read didn't overwrite.2", 'X' == buffer[str1_len-1]); - - // release the implicit reference, causing the object to be released - ba->release(); + set_test_name("BufferArray multiple writes - sequential reads"); + + // create a new ref counted object with an implicit reference + BufferArray * ba = new BufferArray(); + + // write some data to the buffer + char str1[] = "abcdefghij"; + size_t str1_len(strlen(str1)); + char buffer[256]; + + size_t len = ba->write(0, str1, str1_len); + ensure("Wrote length correct", str1_len == len); + ensure("Recorded size correct", str1_len == ba->size()); + + // again... + len = ba->write(str1_len, str1, str1_len); + ensure("Wrote length correct", str1_len == len); + ensure("Recorded size correct", (2 * str1_len) == ba->size()); + + // read some data back + memset(buffer, 'X', sizeof(buffer)); + len = ba->read(8, buffer, 4); + ensure("Read length correct", 4 == len); + ensure("Read content correct", 'i' == buffer[0] && 'j' == buffer[1]); + ensure("Read content correct.2", 'a' == buffer[2] && 'b' == buffer[3]); + ensure("Read didn't overwrite", 'X' == buffer[4]); + + // Read some more without repositioning + memset(buffer, 'X', sizeof(buffer)); + len = ba->read(12, buffer, sizeof(buffer)); + ensure("Read length correct", (str1_len - 2) == len); + ensure("Read content correct.3", 0 == strncmp(buffer, str1+2, str1_len-2)); + ensure("Read didn't overwrite.2", 'X' == buffer[str1_len-1]); + + // release the implicit reference, causing the object to be released + ba->release(); } template <> template <> void BufferArrayTestObjectType::test<6>() { - set_test_name("BufferArray overwrite spanning blocks and appending"); - - // create a new ref counted object with an implicit reference - BufferArray * ba = new BufferArray(); - - // write some data to the buffer - char str1[] = "abcdefghij"; - size_t str1_len(strlen(str1)); - char str2[] = "ABCDEFGHIJKLMNOPQRST"; - size_t str2_len(strlen(str2)); - char buffer[256]; - - size_t len = ba->write(0, str1, str1_len); - ensure("Wrote length correct", str1_len == len); - ensure("Recorded size correct", str1_len == ba->size()); - - // again... - len = ba->write(str1_len, str1, strlen(str1)); - ensure("Wrote length correct", str1_len == len); - ensure("Recorded size correct", (2 * str1_len) == ba->size()); - - // reposition and overwrite - len = ba->write(8, str2, str2_len); - ensure("Overwrite length correct", str2_len == len); - - // Leave position and read verifying content - memset(buffer, 'X', sizeof(buffer)); - len = ba->read(8 + str2_len, buffer, 0); - ensure("Read length correct", 0 == len); - ensure("Read didn't overwrite", 'X' == buffer[0]); - - // reposition and check - len = ba->read(0, buffer, sizeof(buffer)); - ensure("Read length correct.2", (str1_len + str2_len - 2) == len); - ensure("Read content correct", 0 == strncmp(buffer, str1, str1_len-2)); - ensure("Read content correct.2", 0 == strncmp(buffer+str1_len-2, str2, str2_len)); - ensure("Read didn't overwrite.2", 'X' == buffer[str1_len + str2_len - 2]); - - // release the implicit reference, causing the object to be released - ba->release(); + set_test_name("BufferArray overwrite spanning blocks and appending"); + + // create a new ref counted object with an implicit reference + BufferArray * ba = new BufferArray(); + + // write some data to the buffer + char str1[] = "abcdefghij"; + size_t str1_len(strlen(str1)); + char str2[] = "ABCDEFGHIJKLMNOPQRST"; + size_t str2_len(strlen(str2)); + char buffer[256]; + + size_t len = ba->write(0, str1, str1_len); + ensure("Wrote length correct", str1_len == len); + ensure("Recorded size correct", str1_len == ba->size()); + + // again... + len = ba->write(str1_len, str1, strlen(str1)); + ensure("Wrote length correct", str1_len == len); + ensure("Recorded size correct", (2 * str1_len) == ba->size()); + + // reposition and overwrite + len = ba->write(8, str2, str2_len); + ensure("Overwrite length correct", str2_len == len); + + // Leave position and read verifying content + memset(buffer, 'X', sizeof(buffer)); + len = ba->read(8 + str2_len, buffer, 0); + ensure("Read length correct", 0 == len); + ensure("Read didn't overwrite", 'X' == buffer[0]); + + // reposition and check + len = ba->read(0, buffer, sizeof(buffer)); + ensure("Read length correct.2", (str1_len + str2_len - 2) == len); + ensure("Read content correct", 0 == strncmp(buffer, str1, str1_len-2)); + ensure("Read content correct.2", 0 == strncmp(buffer+str1_len-2, str2, str2_len)); + ensure("Read didn't overwrite.2", 'X' == buffer[str1_len + str2_len - 2]); + + // release the implicit reference, causing the object to be released + ba->release(); } template <> template <> void BufferArrayTestObjectType::test<7>() { - set_test_name("BufferArray overwrite spanning blocks and sequential writes"); - - // create a new ref counted object with an implicit reference - BufferArray * ba = new BufferArray(); - - // write some data to the buffer - char str1[] = "abcdefghij"; - size_t str1_len(strlen(str1)); - char str2[] = "ABCDEFGHIJKLMNOPQRST"; - size_t str2_len(strlen(str2)); - char buffer[256]; - - // 2x str1 - size_t len = ba->write(0, str1, str1_len); - len = ba->write(str1_len, str1, str1_len); - - // reposition and overwrite - len = ba->write(6, str2, 2); - ensure("Overwrite length correct", 2 == len); - - len = ba->write(8, str2, 2); - ensure("Overwrite length correct.2", 2 == len); - - len = ba->write(10, str2, 2); - ensure("Overwrite length correct.3", 2 == len); - - // append some data - len = ba->append(str2, str2_len); - ensure("Append length correct", str2_len == len); - - // append some more - void * out_buf(ba->appendBufferAlloc(str1_len)); - memcpy(out_buf, str1, str1_len); - - // And some final writes - len = ba->write(3 * str1_len + str2_len, str2, 2); - ensure("Write length correct.2", 2 == len); - - // Check contents - memset(buffer, 'X', sizeof(buffer)); - len = ba->read(0, buffer, sizeof(buffer)); - ensure("Final buffer length correct", (3 * str1_len + str2_len + 2) == len); - ensure("Read content correct", 0 == strncmp(buffer, str1, 6)); - ensure("Read content correct.2", 0 == strncmp(buffer + 6, str2, 2)); - ensure("Read content correct.3", 0 == strncmp(buffer + 8, str2, 2)); - ensure("Read content correct.4", 0 == strncmp(buffer + 10, str2, 2)); - ensure("Read content correct.5", 0 == strncmp(buffer + str1_len + 2, str1 + 2, str1_len - 2)); - ensure("Read content correct.6", 0 == strncmp(buffer + str1_len + str1_len, str2, str2_len)); - ensure("Read content correct.7", 0 == strncmp(buffer + str1_len + str1_len + str2_len, str1, str1_len)); - ensure("Read content correct.8", 0 == strncmp(buffer + str1_len + str1_len + str2_len + str1_len, str2, 2)); - ensure("Read didn't overwrite", 'X' == buffer[str1_len + str1_len + str2_len + str1_len + 2]); - - // release the implicit reference, causing the object to be released - ba->release(); + set_test_name("BufferArray overwrite spanning blocks and sequential writes"); + + // create a new ref counted object with an implicit reference + BufferArray * ba = new BufferArray(); + + // write some data to the buffer + char str1[] = "abcdefghij"; + size_t str1_len(strlen(str1)); + char str2[] = "ABCDEFGHIJKLMNOPQRST"; + size_t str2_len(strlen(str2)); + char buffer[256]; + + // 2x str1 + size_t len = ba->write(0, str1, str1_len); + len = ba->write(str1_len, str1, str1_len); + + // reposition and overwrite + len = ba->write(6, str2, 2); + ensure("Overwrite length correct", 2 == len); + + len = ba->write(8, str2, 2); + ensure("Overwrite length correct.2", 2 == len); + + len = ba->write(10, str2, 2); + ensure("Overwrite length correct.3", 2 == len); + + // append some data + len = ba->append(str2, str2_len); + ensure("Append length correct", str2_len == len); + + // append some more + void * out_buf(ba->appendBufferAlloc(str1_len)); + memcpy(out_buf, str1, str1_len); + + // And some final writes + len = ba->write(3 * str1_len + str2_len, str2, 2); + ensure("Write length correct.2", 2 == len); + + // Check contents + memset(buffer, 'X', sizeof(buffer)); + len = ba->read(0, buffer, sizeof(buffer)); + ensure("Final buffer length correct", (3 * str1_len + str2_len + 2) == len); + ensure("Read content correct", 0 == strncmp(buffer, str1, 6)); + ensure("Read content correct.2", 0 == strncmp(buffer + 6, str2, 2)); + ensure("Read content correct.3", 0 == strncmp(buffer + 8, str2, 2)); + ensure("Read content correct.4", 0 == strncmp(buffer + 10, str2, 2)); + ensure("Read content correct.5", 0 == strncmp(buffer + str1_len + 2, str1 + 2, str1_len - 2)); + ensure("Read content correct.6", 0 == strncmp(buffer + str1_len + str1_len, str2, str2_len)); + ensure("Read content correct.7", 0 == strncmp(buffer + str1_len + str1_len + str2_len, str1, str1_len)); + ensure("Read content correct.8", 0 == strncmp(buffer + str1_len + str1_len + str2_len + str1_len, str2, 2)); + ensure("Read didn't overwrite", 'X' == buffer[str1_len + str1_len + str2_len + str1_len + 2]); + + // release the implicit reference, causing the object to be released + ba->release(); } template <> template <> void BufferArrayTestObjectType::test<8>() { - set_test_name("BufferArray zero-length appendBufferAlloc"); - - // create a new ref counted object with an implicit reference - BufferArray * ba = new BufferArray(); - - // write some data to the buffer - char str1[] = "abcdefghij"; - size_t str1_len(strlen(str1)); - char str2[] = "ABCDEFGHIJKLMNOPQRST"; - size_t str2_len(strlen(str2)); - char buffer[256]; - - // 2x str1 - size_t len = ba->write(0, str1, str1_len); - len = ba->write(str1_len, str1, str1_len); - - // zero-length allocate (we allow this with a valid pointer returned) - void * out_buf(ba->appendBufferAlloc(0)); - ensure("Buffer from zero-length appendBufferAlloc non-NULL", NULL != out_buf); - - // Do it again - void * out_buf2(ba->appendBufferAlloc(0)); - ensure("Buffer from zero-length appendBufferAlloc non-NULL.2", NULL != out_buf2); - ensure("Two zero-length appendBufferAlloc buffers distinct", out_buf != out_buf2); - - // And some final writes - len = ba->write(2 * str1_len, str2, str2_len); - - // Check contents - memset(buffer, 'X', sizeof(buffer)); - len = ba->read(0, buffer, sizeof(buffer)); - ensure("Final buffer length correct", (2 * str1_len + str2_len) == len); - ensure("Read content correct.1", 0 == strncmp(buffer, str1, str1_len)); - ensure("Read content correct.2", 0 == strncmp(buffer + str1_len, str1, str1_len)); - ensure("Read content correct.3", 0 == strncmp(buffer + str1_len + str1_len, str2, str2_len)); - ensure("Read didn't overwrite", 'X' == buffer[str1_len + str1_len + str2_len]); - - // release the implicit reference, causing the object to be released - ba->release(); + set_test_name("BufferArray zero-length appendBufferAlloc"); + + // create a new ref counted object with an implicit reference + BufferArray * ba = new BufferArray(); + + // write some data to the buffer + char str1[] = "abcdefghij"; + size_t str1_len(strlen(str1)); + char str2[] = "ABCDEFGHIJKLMNOPQRST"; + size_t str2_len(strlen(str2)); + char buffer[256]; + + // 2x str1 + size_t len = ba->write(0, str1, str1_len); + len = ba->write(str1_len, str1, str1_len); + + // zero-length allocate (we allow this with a valid pointer returned) + void * out_buf(ba->appendBufferAlloc(0)); + ensure("Buffer from zero-length appendBufferAlloc non-NULL", NULL != out_buf); + + // Do it again + void * out_buf2(ba->appendBufferAlloc(0)); + ensure("Buffer from zero-length appendBufferAlloc non-NULL.2", NULL != out_buf2); + ensure("Two zero-length appendBufferAlloc buffers distinct", out_buf != out_buf2); + + // And some final writes + len = ba->write(2 * str1_len, str2, str2_len); + + // Check contents + memset(buffer, 'X', sizeof(buffer)); + len = ba->read(0, buffer, sizeof(buffer)); + ensure("Final buffer length correct", (2 * str1_len + str2_len) == len); + ensure("Read content correct.1", 0 == strncmp(buffer, str1, str1_len)); + ensure("Read content correct.2", 0 == strncmp(buffer + str1_len, str1, str1_len)); + ensure("Read content correct.3", 0 == strncmp(buffer + str1_len + str1_len, str2, str2_len)); + ensure("Read didn't overwrite", 'X' == buffer[str1_len + str1_len + str2_len]); + + // release the implicit reference, causing the object to be released + ba->release(); } } // end namespace tut diff --git a/indra/llcorehttp/tests/test_bufferstream.hpp b/indra/llcorehttp/tests/test_bufferstream.hpp index 2739a6e38e..556abf45a2 100644 --- a/indra/llcorehttp/tests/test_bufferstream.hpp +++ b/indra/llcorehttp/tests/test_bufferstream.hpp @@ -1,4 +1,4 @@ -/** +/** * @file test_bufferstream.hpp * @brief unit tests for the LLCore::BufferArrayStreamBuf/BufferArrayStream classes * @@ -42,8 +42,8 @@ namespace tut struct BufferStreamTestData { - // the test objects inherit from this so the member functions and variables - // can be referenced directly inside of the test functions. + // the test objects inherit from this so the member functions and variables + // can be referenced directly inside of the test functions. }; typedef test_group<BufferStreamTestData> BufferStreamTestGroupType; @@ -55,194 +55,194 @@ typedef BufferArrayStreamBuf::traits_type tst_traits_t; template <> template <> void BufferStreamTestObjectType::test<1>() { - set_test_name("BufferArrayStreamBuf construction with NULL BufferArray"); - - // create a new ref counted object with an implicit reference - BufferArrayStreamBuf * bsb = new BufferArrayStreamBuf(NULL); - - // Not much will work with a NULL - ensure("underflow() on NULL fails", tst_traits_t::eof() == bsb->underflow()); - ensure("uflow() on NULL fails", tst_traits_t::eof() == bsb->uflow()); - ensure("pbackfail() on NULL fails", tst_traits_t::eof() == bsb->pbackfail('c')); - ensure("showmanyc() on NULL fails", bsb->showmanyc() == -1); - ensure("overflow() on NULL fails", tst_traits_t::eof() == bsb->overflow('c')); - ensure("xsputn() on NULL fails", bsb->xsputn("blah", 4) == 0); - ensure("seekoff() on NULL fails", bsb->seekoff(0, std::ios_base::beg, std::ios_base::in) == std::streampos(-1)); - - // release the implicit reference, causing the object to be released - delete bsb; - bsb = NULL; + set_test_name("BufferArrayStreamBuf construction with NULL BufferArray"); + + // create a new ref counted object with an implicit reference + BufferArrayStreamBuf * bsb = new BufferArrayStreamBuf(NULL); + + // Not much will work with a NULL + ensure("underflow() on NULL fails", tst_traits_t::eof() == bsb->underflow()); + ensure("uflow() on NULL fails", tst_traits_t::eof() == bsb->uflow()); + ensure("pbackfail() on NULL fails", tst_traits_t::eof() == bsb->pbackfail('c')); + ensure("showmanyc() on NULL fails", bsb->showmanyc() == -1); + ensure("overflow() on NULL fails", tst_traits_t::eof() == bsb->overflow('c')); + ensure("xsputn() on NULL fails", bsb->xsputn("blah", 4) == 0); + ensure("seekoff() on NULL fails", bsb->seekoff(0, std::ios_base::beg, std::ios_base::in) == std::streampos(-1)); + + // release the implicit reference, causing the object to be released + delete bsb; + bsb = NULL; } template <> template <> void BufferStreamTestObjectType::test<2>() { - set_test_name("BufferArrayStream construction with NULL BufferArray"); - - // create a new ref counted object with an implicit reference - BufferArrayStream * bas = new BufferArrayStream(NULL); - - // Not much will work with a NULL here - ensure("eof() is false on NULL", ! bas->eof()); - ensure("fail() is false on NULL", ! bas->fail()); - ensure("good() on NULL", bas->good()); - - // release the implicit reference, causing the object to be released - delete bas; - bas = NULL; + set_test_name("BufferArrayStream construction with NULL BufferArray"); + + // create a new ref counted object with an implicit reference + BufferArrayStream * bas = new BufferArrayStream(NULL); + + // Not much will work with a NULL here + ensure("eof() is false on NULL", ! bas->eof()); + ensure("fail() is false on NULL", ! bas->fail()); + ensure("good() on NULL", bas->good()); + + // release the implicit reference, causing the object to be released + delete bas; + bas = NULL; } template <> template <> void BufferStreamTestObjectType::test<3>() { - set_test_name("BufferArrayStreamBuf construction with empty BufferArray"); - - // create a new ref counted BufferArray with implicit reference - BufferArray * ba = new BufferArray; - BufferArrayStreamBuf * bsb = new BufferArrayStreamBuf(ba); - - // I can release my ref on the BA - ba->release(); - ba = NULL; - - // release the implicit reference, causing the object to be released - delete bsb; - bsb = NULL; + set_test_name("BufferArrayStreamBuf construction with empty BufferArray"); + + // create a new ref counted BufferArray with implicit reference + BufferArray * ba = new BufferArray; + BufferArrayStreamBuf * bsb = new BufferArrayStreamBuf(ba); + + // I can release my ref on the BA + ba->release(); + ba = NULL; + + // release the implicit reference, causing the object to be released + delete bsb; + bsb = NULL; } template <> template <> void BufferStreamTestObjectType::test<4>() { - set_test_name("BufferArrayStream construction with empty BufferArray"); + set_test_name("BufferArrayStream construction with empty BufferArray"); - // create a new ref counted BufferArray with implicit reference - BufferArray * ba = new BufferArray; + // create a new ref counted BufferArray with implicit reference + BufferArray * ba = new BufferArray; - { - // create a new ref counted object with an implicit reference - BufferArrayStream bas(ba); - } + { + // create a new ref counted object with an implicit reference + BufferArrayStream bas(ba); + } - // release the implicit reference, causing the object to be released - ba->release(); - ba = NULL; + // release the implicit reference, causing the object to be released + ba->release(); + ba = NULL; } template <> template <> void BufferStreamTestObjectType::test<5>() { - set_test_name("BufferArrayStreamBuf construction with real BufferArray"); - - // create a new ref counted BufferArray with implicit reference - BufferArray * ba = new BufferArray; - const char * content("This is a string. A fragment."); - const size_t c_len(strlen(content)); - ba->append(content, c_len); - - // Creat an adapter for the BufferArray - BufferArrayStreamBuf * bsb = new BufferArrayStreamBuf(ba); - - // I can release my ref on the BA - ba->release(); - ba = NULL; - - // Various static state - ensure("underflow() returns 'T'", bsb->underflow() == 'T'); - ensure("underflow() returns 'T' again", bsb->underflow() == 'T'); - ensure("uflow() returns 'T'", bsb->uflow() == 'T'); - ensure("uflow() returns 'h'", bsb->uflow() == 'h'); - ensure("pbackfail('i') fails", tst_traits_t::eof() == bsb->pbackfail('i')); - ensure("pbackfail('T') fails", tst_traits_t::eof() == bsb->pbackfail('T')); - ensure("pbackfail('h') succeeds", bsb->pbackfail('h') == 'h'); - ensure("showmanyc() is everything but the 'T'", bsb->showmanyc() == (c_len - 1)); - ensure("overflow() appends", bsb->overflow('c') == 'c'); - ensure("showmanyc() reflects append", bsb->showmanyc() == (c_len - 1 + 1)); - ensure("xsputn() appends some more", bsb->xsputn("bla!", 4) == 4); - ensure("showmanyc() reflects 2nd append", bsb->showmanyc() == (c_len - 1 + 5)); - ensure("seekoff() succeeds", bsb->seekoff(0, std::ios_base::beg, std::ios_base::in) == std::streampos(0)); - ensure("seekoff() succeeds 2", bsb->seekoff(4, std::ios_base::cur, std::ios_base::in) == std::streampos(4)); - ensure("showmanyc() picks up seekoff", bsb->showmanyc() == (c_len + 5 - 4)); - ensure("seekoff() succeeds 3", bsb->seekoff(0, std::ios_base::end, std::ios_base::in) == std::streampos(c_len + 4)); - ensure("pbackfail('!') succeeds", tst_traits_t::eof() == bsb->pbackfail('!')); - - // release the implicit reference, causing the object to be released - delete bsb; - bsb = NULL; + set_test_name("BufferArrayStreamBuf construction with real BufferArray"); + + // create a new ref counted BufferArray with implicit reference + BufferArray * ba = new BufferArray; + const char * content("This is a string. A fragment."); + const size_t c_len(strlen(content)); + ba->append(content, c_len); + + // Creat an adapter for the BufferArray + BufferArrayStreamBuf * bsb = new BufferArrayStreamBuf(ba); + + // I can release my ref on the BA + ba->release(); + ba = NULL; + + // Various static state + ensure("underflow() returns 'T'", bsb->underflow() == 'T'); + ensure("underflow() returns 'T' again", bsb->underflow() == 'T'); + ensure("uflow() returns 'T'", bsb->uflow() == 'T'); + ensure("uflow() returns 'h'", bsb->uflow() == 'h'); + ensure("pbackfail('i') fails", tst_traits_t::eof() == bsb->pbackfail('i')); + ensure("pbackfail('T') fails", tst_traits_t::eof() == bsb->pbackfail('T')); + ensure("pbackfail('h') succeeds", bsb->pbackfail('h') == 'h'); + ensure("showmanyc() is everything but the 'T'", bsb->showmanyc() == (c_len - 1)); + ensure("overflow() appends", bsb->overflow('c') == 'c'); + ensure("showmanyc() reflects append", bsb->showmanyc() == (c_len - 1 + 1)); + ensure("xsputn() appends some more", bsb->xsputn("bla!", 4) == 4); + ensure("showmanyc() reflects 2nd append", bsb->showmanyc() == (c_len - 1 + 5)); + ensure("seekoff() succeeds", bsb->seekoff(0, std::ios_base::beg, std::ios_base::in) == std::streampos(0)); + ensure("seekoff() succeeds 2", bsb->seekoff(4, std::ios_base::cur, std::ios_base::in) == std::streampos(4)); + ensure("showmanyc() picks up seekoff", bsb->showmanyc() == (c_len + 5 - 4)); + ensure("seekoff() succeeds 3", bsb->seekoff(0, std::ios_base::end, std::ios_base::in) == std::streampos(c_len + 4)); + ensure("pbackfail('!') succeeds", tst_traits_t::eof() == bsb->pbackfail('!')); + + // release the implicit reference, causing the object to be released + delete bsb; + bsb = NULL; } template <> template <> void BufferStreamTestObjectType::test<6>() { - set_test_name("BufferArrayStream construction with real BufferArray"); - - // create a new ref counted BufferArray with implicit reference - BufferArray * ba = new BufferArray; - //const char * content("This is a string. A fragment."); - //const size_t c_len(strlen(content)); - //ba->append(content, strlen(content)); - - { - // Creat an adapter for the BufferArray - BufferArrayStream bas(ba); - - // Basic operations - bas << "Hello" << 27 << "."; - ensure("BA length 8", ba->size() == 8); - - std::string str; - bas >> str; - ensure("reads correctly", str == "Hello27."); - } - - // release the implicit reference, causing the object to be released - ba->release(); - ba = NULL; + set_test_name("BufferArrayStream construction with real BufferArray"); + + // create a new ref counted BufferArray with implicit reference + BufferArray * ba = new BufferArray; + //const char * content("This is a string. A fragment."); + //const size_t c_len(strlen(content)); + //ba->append(content, strlen(content)); + + { + // Creat an adapter for the BufferArray + BufferArrayStream bas(ba); + + // Basic operations + bas << "Hello" << 27 << "."; + ensure("BA length 8", ba->size() == 8); + + std::string str; + bas >> str; + ensure("reads correctly", str == "Hello27."); + } + + // release the implicit reference, causing the object to be released + ba->release(); + ba = NULL; } template <> template <> void BufferStreamTestObjectType::test<7>() { - set_test_name("BufferArrayStream with LLSD serialization"); + set_test_name("BufferArrayStream with LLSD serialization"); + + // create a new ref counted BufferArray with implicit reference + BufferArray * ba = new BufferArray; - // create a new ref counted BufferArray with implicit reference - BufferArray * ba = new BufferArray; + { + // Creat an adapter for the BufferArray + BufferArrayStream bas(ba); - { - // Creat an adapter for the BufferArray - BufferArrayStream bas(ba); + // LLSD + LLSD llsd = LLSD::emptyMap(); - // LLSD - LLSD llsd = LLSD::emptyMap(); + llsd["int"] = LLSD::Integer(3); + llsd["float"] = LLSD::Real(923289.28992); + llsd["string"] = LLSD::String("aksjdl;ajsdgfjgfal;sdgjakl;sdfjkl;ajsdfkl;ajsdfkl;jaskl;dfj"); - llsd["int"] = LLSD::Integer(3); - llsd["float"] = LLSD::Real(923289.28992); - llsd["string"] = LLSD::String("aksjdl;ajsdgfjgfal;sdgjakl;sdfjkl;ajsdfkl;ajsdfkl;jaskl;dfj"); + LLSD llsd_map = LLSD::emptyMap(); + llsd_map["int"] = LLSD::Integer(-2889); + llsd_map["float"] = LLSD::Real(2.37829e32); + llsd_map["string"] = LLSD::String("OHIGODHSPDGHOSDHGOPSHDGP"); - LLSD llsd_map = LLSD::emptyMap(); - llsd_map["int"] = LLSD::Integer(-2889); - llsd_map["float"] = LLSD::Real(2.37829e32); - llsd_map["string"] = LLSD::String("OHIGODHSPDGHOSDHGOPSHDGP"); + llsd["map"] = llsd_map; - llsd["map"] = llsd_map; - - // Serialize it - LLSDSerialize::toXML(llsd, bas); + // Serialize it + LLSDSerialize::toXML(llsd, bas); - std::string str; - bas >> str; - // std::cout << "SERIALIZED LLSD: " << str << std::endl; - ensure("Extracted string has reasonable length", str.size() > 60); - } + std::string str; + bas >> str; + // std::cout << "SERIALIZED LLSD: " << str << std::endl; + ensure("Extracted string has reasonable length", str.size() > 60); + } - // release the implicit reference, causing the object to be released - ba->release(); - ba = NULL; + // release the implicit reference, causing the object to be released + ba->release(); + ba = NULL; } diff --git a/indra/llcorehttp/tests/test_httpheaders.hpp b/indra/llcorehttp/tests/test_httpheaders.hpp index 6aefb5054b..d8eff78ca5 100644 --- a/indra/llcorehttp/tests/test_httpheaders.hpp +++ b/indra/llcorehttp/tests/test_httpheaders.hpp @@ -1,4 +1,4 @@ -/** +/** * @file test_httpheaders.hpp * @brief unit tests for the LLCore::HttpHeaders class * @@ -39,8 +39,8 @@ namespace tut struct HttpHeadersTestData { - // the test objects inherit from this so the member functions and variables - // can be referenced directly inside of the test functions. + // the test objects inherit from this so the member functions and variables + // can be referenced directly inside of the test functions. }; typedef test_group<HttpHeadersTestData> HttpHeadersTestGroupType; @@ -50,181 +50,181 @@ HttpHeadersTestGroupType HttpHeadersTestGroup("HttpHeaders Tests"); template <> template <> void HttpHeadersTestObjectType::test<1>() { - set_test_name("HttpHeaders construction"); + set_test_name("HttpHeaders construction"); - // create a new ref counted object with an implicit reference - HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders()); - ensure("Nothing in headers", 0 == headers->size()); + // create a new ref counted object with an implicit reference + HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders()); + ensure("Nothing in headers", 0 == headers->size()); - // release the implicit reference, causing the object to be released + // release the implicit reference, causing the object to be released headers.reset(); } template <> template <> void HttpHeadersTestObjectType::test<2>() { - set_test_name("HttpHeaders construction"); - - // create a new ref counted object with an implicit reference - HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders()); - - { - // Append a few strings - std::string str1n("Pragma"); - std::string str1v(""); - headers->append(str1n, str1v); - std::string str2n("Accept"); - std::string str2v("application/json"); - headers->append(str2n, str2v); - - ensure("Headers retained", 2 == headers->size()); - HttpHeaders::container_t & c(headers->getContainerTESTONLY()); - - ensure("First name is first name", c[0].first == str1n); - ensure("First value is first value", c[0].second == str1v); - ensure("Second name is second name", c[1].first == str2n); - ensure("Second value is second value", c[1].second == str2v); - } - - // release the implicit reference, causing the object to be released + set_test_name("HttpHeaders construction"); + + // create a new ref counted object with an implicit reference + HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders()); + + { + // Append a few strings + std::string str1n("Pragma"); + std::string str1v(""); + headers->append(str1n, str1v); + std::string str2n("Accept"); + std::string str2v("application/json"); + headers->append(str2n, str2v); + + ensure("Headers retained", 2 == headers->size()); + HttpHeaders::container_t & c(headers->getContainerTESTONLY()); + + ensure("First name is first name", c[0].first == str1n); + ensure("First value is first value", c[0].second == str1v); + ensure("Second name is second name", c[1].first == str2n); + ensure("Second value is second value", c[1].second == str2v); + } + + // release the implicit reference, causing the object to be released headers.reset(); } template <> template <> void HttpHeadersTestObjectType::test<3>() { - set_test_name("HttpHeaders basic find"); - - // create a new ref counted object with an implicit reference - HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders()); - - { - // Append a few strings - std::string str1n("Uno"); - std::string str1v("1"); - headers->append(str1n, str1v); - std::string str2n("doS"); - std::string str2v("2-2-2-2"); - headers->append(str2n, str2v); - std::string str3n("TRES"); - std::string str3v("trois gymnopedie"); - headers->append(str3n, str3v); - - ensure("Headers retained", 3 == headers->size()); - - const std::string * result(NULL); - - // Find a header - result = headers->find("TRES"); - ensure("Found the last item", result != NULL); - ensure("Last item is a nice", result != NULL && str3v == *result); - - // appends above are raw and find is case sensitive - result = headers->find("TReS"); - ensure("Last item not found due to case", result == NULL); - - result = headers->find("TRE"); - ensure("Last item not found due to prefixing (1)", result == NULL); - - result = headers->find("TRESS"); - ensure("Last item not found due to prefixing (2)", result == NULL); - } - - // release the implicit reference, causing the object to be released + set_test_name("HttpHeaders basic find"); + + // create a new ref counted object with an implicit reference + HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders()); + + { + // Append a few strings + std::string str1n("Uno"); + std::string str1v("1"); + headers->append(str1n, str1v); + std::string str2n("doS"); + std::string str2v("2-2-2-2"); + headers->append(str2n, str2v); + std::string str3n("TRES"); + std::string str3v("trois gymnopedie"); + headers->append(str3n, str3v); + + ensure("Headers retained", 3 == headers->size()); + + const std::string * result(NULL); + + // Find a header + result = headers->find("TRES"); + ensure("Found the last item", result != NULL); + ensure("Last item is a nice", result != NULL && str3v == *result); + + // appends above are raw and find is case sensitive + result = headers->find("TReS"); + ensure("Last item not found due to case", result == NULL); + + result = headers->find("TRE"); + ensure("Last item not found due to prefixing (1)", result == NULL); + + result = headers->find("TRESS"); + ensure("Last item not found due to prefixing (2)", result == NULL); + } + + // release the implicit reference, causing the object to be released headers.reset(); } template <> template <> void HttpHeadersTestObjectType::test<4>() { - set_test_name("HttpHeaders normalized header entry"); + set_test_name("HttpHeaders normalized header entry"); - // create a new ref counted object with an implicit reference + // create a new ref counted object with an implicit reference HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders()); - { - static char line1[] = " AcCePT : image/yourfacehere"; - static char line1v[] = "image/yourfacehere"; - headers->appendNormal(line1, sizeof(line1) - 1); - - ensure("First append worked in some fashion", 1 == headers->size()); - - const std::string * result(NULL); - - // Find a header - result = headers->find("accept"); - ensure("Found 'accept'", result != NULL); - ensure("accept value has face", result != NULL && *result == line1v); - - // Left-clean on value - static char line2[] = " next : \t\tlinejunk \t"; - headers->appendNormal(line2, sizeof(line2) - 1); - ensure("Second append worked", 2 == headers->size()); - result = headers->find("next"); - ensure("Found 'next'", result != NULL); - ensure("next value is left-clean", result != NULL && - *result == "linejunk \t"); - - // First value unmolested - result = headers->find("accept"); - ensure("Found 'accept' again", result != NULL); - ensure("accept value has face", result != NULL && *result == line1v); - - // Colons in value are okay - static char line3[] = "FancY-PANTs::plop:-neuf-=vleem="; - static char line3v[] = ":plop:-neuf-=vleem="; - headers->appendNormal(line3, sizeof(line3) - 1); - ensure("Third append worked", 3 == headers->size()); - result = headers->find("fancy-pants"); - ensure("Found 'fancy-pants'", result != NULL); - ensure("fancy-pants value has colons", result != NULL && *result == line3v); - - // Zero-length value - static char line4[] = "all-talk-no-walk:"; - headers->appendNormal(line4, sizeof(line4) - 1); - ensure("Fourth append worked", 4 == headers->size()); - result = headers->find("all-talk-no-walk"); - ensure("Found 'all-talk'", result != NULL); - ensure("al-talk value is zero-length", result != NULL && result->size() == 0); - - // Zero-length name - static char line5[] = ":all-talk-no-walk"; - static char line5v[] = "all-talk-no-walk"; - headers->appendNormal(line5, sizeof(line5) - 1); - ensure("Fifth append worked", 5 == headers->size()); - result = headers->find(""); - ensure("Found no-name", result != NULL); - ensure("no-name value is something", result != NULL && *result == line5v); - - // Lone colon is still something - headers->clear(); - static char line6[] = " :"; - headers->appendNormal(line6, sizeof(line6) - 1); - ensure("Sixth append worked", 1 == headers->size()); - result = headers->find(""); - ensure("Found 2nd no-name", result != NULL); - ensure("2nd no-name value is nothing", result != NULL && result->size() == 0); - - // Line without colons is taken as-is and unstripped in name - static char line7[] = " \toskdgioasdghaosdghoowg28342908tg8902hg0hwedfhqew890v7qh0wdebv78q0wdevbhq>?M>BNM<ZV>?NZ? \t"; - headers->appendNormal(line7, sizeof(line7) - 1); - ensure("Seventh append worked", 2 == headers->size()); - result = headers->find(line7); - ensure("Found whatsit line", result != NULL); - ensure("Whatsit line has no value", result != NULL && result->size() == 0); - - // Normaling interface heeds the byte count, doesn't look for NUL-terminator - static char line8[] = "binary:ignorestuffontheendofthis"; - headers->appendNormal(line8, 13); - ensure("Eighth append worked", 3 == headers->size()); - result = headers->find("binary"); - ensure("Found 'binary'", result != NULL); - ensure("binary value was limited to 'ignore'", result != NULL && - *result == "ignore"); - - } - - // release the implicit reference, causing the object to be released + { + static char line1[] = " AcCePT : image/yourfacehere"; + static char line1v[] = "image/yourfacehere"; + headers->appendNormal(line1, sizeof(line1) - 1); + + ensure("First append worked in some fashion", 1 == headers->size()); + + const std::string * result(NULL); + + // Find a header + result = headers->find("accept"); + ensure("Found 'accept'", result != NULL); + ensure("accept value has face", result != NULL && *result == line1v); + + // Left-clean on value + static char line2[] = " next : \t\tlinejunk \t"; + headers->appendNormal(line2, sizeof(line2) - 1); + ensure("Second append worked", 2 == headers->size()); + result = headers->find("next"); + ensure("Found 'next'", result != NULL); + ensure("next value is left-clean", result != NULL && + *result == "linejunk \t"); + + // First value unmolested + result = headers->find("accept"); + ensure("Found 'accept' again", result != NULL); + ensure("accept value has face", result != NULL && *result == line1v); + + // Colons in value are okay + static char line3[] = "FancY-PANTs::plop:-neuf-=vleem="; + static char line3v[] = ":plop:-neuf-=vleem="; + headers->appendNormal(line3, sizeof(line3) - 1); + ensure("Third append worked", 3 == headers->size()); + result = headers->find("fancy-pants"); + ensure("Found 'fancy-pants'", result != NULL); + ensure("fancy-pants value has colons", result != NULL && *result == line3v); + + // Zero-length value + static char line4[] = "all-talk-no-walk:"; + headers->appendNormal(line4, sizeof(line4) - 1); + ensure("Fourth append worked", 4 == headers->size()); + result = headers->find("all-talk-no-walk"); + ensure("Found 'all-talk'", result != NULL); + ensure("al-talk value is zero-length", result != NULL && result->size() == 0); + + // Zero-length name + static char line5[] = ":all-talk-no-walk"; + static char line5v[] = "all-talk-no-walk"; + headers->appendNormal(line5, sizeof(line5) - 1); + ensure("Fifth append worked", 5 == headers->size()); + result = headers->find(""); + ensure("Found no-name", result != NULL); + ensure("no-name value is something", result != NULL && *result == line5v); + + // Lone colon is still something + headers->clear(); + static char line6[] = " :"; + headers->appendNormal(line6, sizeof(line6) - 1); + ensure("Sixth append worked", 1 == headers->size()); + result = headers->find(""); + ensure("Found 2nd no-name", result != NULL); + ensure("2nd no-name value is nothing", result != NULL && result->size() == 0); + + // Line without colons is taken as-is and unstripped in name + static char line7[] = " \toskdgioasdghaosdghoowg28342908tg8902hg0hwedfhqew890v7qh0wdebv78q0wdevbhq>?M>BNM<ZV>?NZ? \t"; + headers->appendNormal(line7, sizeof(line7) - 1); + ensure("Seventh append worked", 2 == headers->size()); + result = headers->find(line7); + ensure("Found whatsit line", result != NULL); + ensure("Whatsit line has no value", result != NULL && result->size() == 0); + + // Normaling interface heeds the byte count, doesn't look for NUL-terminator + static char line8[] = "binary:ignorestuffontheendofthis"; + headers->appendNormal(line8, 13); + ensure("Eighth append worked", 3 == headers->size()); + result = headers->find("binary"); + ensure("Found 'binary'", result != NULL); + ensure("binary value was limited to 'ignore'", result != NULL && + *result == "ignore"); + + } + + // release the implicit reference, causing the object to be released headers.reset(); } @@ -232,79 +232,79 @@ void HttpHeadersTestObjectType::test<4>() template <> template <> void HttpHeadersTestObjectType::test<5>() { - set_test_name("HttpHeaders iterator tests"); + set_test_name("HttpHeaders iterator tests"); - // create a new ref counted object with an implicit reference + // create a new ref counted object with an implicit reference 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); - HttpHeaders::const_iterator cend(headers->end()), cbegin(headers->begin()); - ensure("Empty container has equal rbegin/rend const iterators", cend == cbegin); - - ensure("Empty container has equal begin/end iterators", headers->end() == headers->begin()); - - { - static char line1[] = " AcCePT : image/yourfacehere"; - static char line1v[] = "image/yourfacehere"; - headers->appendNormal(line1, sizeof(line1) - 1); - - static char line2[] = " next : \t\tlinejunk \t"; - static char line2v[] = "linejunk \t"; - headers->appendNormal(line2, sizeof(line2) - 1); - - static char line3[] = "FancY-PANTs::plop:-neuf-=vleem="; - static char line3v[] = ":plop:-neuf-=vleem="; - headers->appendNormal(line3, sizeof(line3) - 1); - - static char line4[] = "all-talk-no-walk:"; - static char line4v[] = ""; - headers->appendNormal(line4, sizeof(line4) - 1); - - static char line5[] = ":all-talk-no-walk"; - static char line5v[] = "all-talk-no-walk"; - headers->appendNormal(line5, sizeof(line5) - 1); - - static char line6[] = " :"; - static char line6v[] = ""; - headers->appendNormal(line6, sizeof(line6) - 1); - - ensure("All entries accounted for", 6 == headers->size()); - - static char * values[] = { - line1v, - line2v, - line3v, - line4v, - line5v, - line6v - }; - - int i(0); - HttpHeaders::const_iterator cend(headers->end()); - for (HttpHeaders::const_iterator it(headers->begin()); - cend != it; - ++it, ++i) - { - std::ostringstream str; - str << "Const Iterator value # " << i << " was " << values[i]; - ensure(str.str(), (*it).second == values[i]); - } - - // Rewind, do non-consts - i = 0; - HttpHeaders::iterator end(headers->end()); - for (HttpHeaders::iterator it(headers->begin()); - end != it; - ++it, ++i) - { - std::ostringstream str; - str << "Const Iterator value # " << i << " was " << values[i]; - ensure(str.str(), (*it).second == values[i]); - } - } - - // release the implicit reference, causing the object to be released + HttpHeaders::iterator end(headers->end()), begin(headers->begin()); + ensure("Empty container has equal begin/end const iterators", end == begin); + HttpHeaders::const_iterator cend(headers->end()), cbegin(headers->begin()); + ensure("Empty container has equal rbegin/rend const iterators", cend == cbegin); + + ensure("Empty container has equal begin/end iterators", headers->end() == headers->begin()); + + { + static char line1[] = " AcCePT : image/yourfacehere"; + static char line1v[] = "image/yourfacehere"; + headers->appendNormal(line1, sizeof(line1) - 1); + + static char line2[] = " next : \t\tlinejunk \t"; + static char line2v[] = "linejunk \t"; + headers->appendNormal(line2, sizeof(line2) - 1); + + static char line3[] = "FancY-PANTs::plop:-neuf-=vleem="; + static char line3v[] = ":plop:-neuf-=vleem="; + headers->appendNormal(line3, sizeof(line3) - 1); + + static char line4[] = "all-talk-no-walk:"; + static char line4v[] = ""; + headers->appendNormal(line4, sizeof(line4) - 1); + + static char line5[] = ":all-talk-no-walk"; + static char line5v[] = "all-talk-no-walk"; + headers->appendNormal(line5, sizeof(line5) - 1); + + static char line6[] = " :"; + static char line6v[] = ""; + headers->appendNormal(line6, sizeof(line6) - 1); + + ensure("All entries accounted for", 6 == headers->size()); + + static char * values[] = { + line1v, + line2v, + line3v, + line4v, + line5v, + line6v + }; + + int i(0); + HttpHeaders::const_iterator cend(headers->end()); + for (HttpHeaders::const_iterator it(headers->begin()); + cend != it; + ++it, ++i) + { + std::ostringstream str; + str << "Const Iterator value # " << i << " was " << values[i]; + ensure(str.str(), (*it).second == values[i]); + } + + // Rewind, do non-consts + i = 0; + HttpHeaders::iterator end(headers->end()); + for (HttpHeaders::iterator it(headers->begin()); + end != it; + ++it, ++i) + { + std::ostringstream str; + str << "Const Iterator value # " << i << " was " << values[i]; + ensure(str.str(), (*it).second == values[i]); + } + } + + // release the implicit reference, causing the object to be released headers.reset(); } @@ -312,77 +312,77 @@ void HttpHeadersTestObjectType::test<5>() template <> template <> void HttpHeadersTestObjectType::test<6>() { - set_test_name("HttpHeaders reverse iterator tests"); + set_test_name("HttpHeaders reverse iterator tests"); - // create a new ref counted object with an implicit reference + // create a new ref counted object with an implicit reference 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); - HttpHeaders::const_reverse_iterator crend(headers->rend()), crbegin(headers->rbegin()); - ensure("Empty container has equal rbegin/rend const iterators", crend == crbegin); - - { - static char line1[] = " AcCePT : image/yourfacehere"; - static char line1v[] = "image/yourfacehere"; - headers->appendNormal(line1, sizeof(line1) - 1); - - static char line2[] = " next : \t\tlinejunk \t"; - static char line2v[] = "linejunk \t"; - headers->appendNormal(line2, sizeof(line2) - 1); - - static char line3[] = "FancY-PANTs::plop:-neuf-=vleem="; - static char line3v[] = ":plop:-neuf-=vleem="; - headers->appendNormal(line3, sizeof(line3) - 1); - - static char line4[] = "all-talk-no-walk:"; - static char line4v[] = ""; - headers->appendNormal(line4, sizeof(line4) - 1); - - static char line5[] = ":all-talk-no-walk"; - static char line5v[] = "all-talk-no-walk"; - headers->appendNormal(line5, sizeof(line5) - 1); - - static char line6[] = " :"; - static char line6v[] = ""; - headers->appendNormal(line6, sizeof(line6) - 1); - - ensure("All entries accounted for", 6 == headers->size()); - - static char * values[] = { - line6v, - line5v, - line4v, - line3v, - line2v, - line1v - }; - - int i(0); - HttpHeaders::const_reverse_iterator cend(headers->rend()); - for (HttpHeaders::const_reverse_iterator it(headers->rbegin()); - cend != it; - ++it, ++i) - { - std::ostringstream str; - str << "Const Iterator value # " << i << " was " << values[i]; - ensure(str.str(), (*it).second == values[i]); - } - - // Rewind, do non-consts - i = 0; - HttpHeaders::reverse_iterator end(headers->rend()); - for (HttpHeaders::reverse_iterator it(headers->rbegin()); - end != it; - ++it, ++i) - { - std::ostringstream str; - str << "Iterator value # " << i << " was " << values[i]; - ensure(str.str(), (*it).second == values[i]); - } - } - - // release the implicit reference, causing the object to be released + HttpHeaders::reverse_iterator rend(headers->rend()), rbegin(headers->rbegin()); + ensure("Empty container has equal rbegin/rend const iterators", rend == rbegin); + HttpHeaders::const_reverse_iterator crend(headers->rend()), crbegin(headers->rbegin()); + ensure("Empty container has equal rbegin/rend const iterators", crend == crbegin); + + { + static char line1[] = " AcCePT : image/yourfacehere"; + static char line1v[] = "image/yourfacehere"; + headers->appendNormal(line1, sizeof(line1) - 1); + + static char line2[] = " next : \t\tlinejunk \t"; + static char line2v[] = "linejunk \t"; + headers->appendNormal(line2, sizeof(line2) - 1); + + static char line3[] = "FancY-PANTs::plop:-neuf-=vleem="; + static char line3v[] = ":plop:-neuf-=vleem="; + headers->appendNormal(line3, sizeof(line3) - 1); + + static char line4[] = "all-talk-no-walk:"; + static char line4v[] = ""; + headers->appendNormal(line4, sizeof(line4) - 1); + + static char line5[] = ":all-talk-no-walk"; + static char line5v[] = "all-talk-no-walk"; + headers->appendNormal(line5, sizeof(line5) - 1); + + static char line6[] = " :"; + static char line6v[] = ""; + headers->appendNormal(line6, sizeof(line6) - 1); + + ensure("All entries accounted for", 6 == headers->size()); + + static char * values[] = { + line6v, + line5v, + line4v, + line3v, + line2v, + line1v + }; + + int i(0); + HttpHeaders::const_reverse_iterator cend(headers->rend()); + for (HttpHeaders::const_reverse_iterator it(headers->rbegin()); + cend != it; + ++it, ++i) + { + std::ostringstream str; + str << "Const Iterator value # " << i << " was " << values[i]; + ensure(str.str(), (*it).second == values[i]); + } + + // Rewind, do non-consts + i = 0; + HttpHeaders::reverse_iterator end(headers->rend()); + for (HttpHeaders::reverse_iterator it(headers->rbegin()); + end != it; + ++it, ++i) + { + std::ostringstream str; + str << "Iterator value # " << i << " was " << values[i]; + ensure(str.str(), (*it).second == values[i]); + } + } + + // release the implicit reference, causing the object to be released headers.reset(); } diff --git a/indra/llcorehttp/tests/test_httpoperation.hpp b/indra/llcorehttp/tests/test_httpoperation.hpp index c6407e8d04..6778c3440b 100644 --- a/indra/llcorehttp/tests/test_httpoperation.hpp +++ b/indra/llcorehttp/tests/test_httpoperation.hpp @@ -1,4 +1,4 @@ -/** +/** * @file test_httpoperation.hpp * @brief unit tests for the LLCore::HttpOperation-derived classes * @@ -41,11 +41,11 @@ namespace class TestHandler : public LLCore::HttpHandler { public: - virtual void onCompleted(HttpHandle, HttpResponse *) - { - std::cout << "TestHandler::onCompleted() invoked" << std::endl; - } - + virtual void onCompleted(HttpHandle, HttpResponse *) + { + std::cout << "TestHandler::onCompleted() invoked" << std::endl; + } + }; @@ -54,53 +54,53 @@ public: namespace tut { - struct HttpOperationTestData - { - // the test objects inherit from this so the member functions and variables - // can be referenced directly inside of the test functions. - }; - - typedef test_group<HttpOperationTestData> HttpOperationTestGroupType; - typedef HttpOperationTestGroupType::object HttpOperationTestObjectType; - HttpOperationTestGroupType HttpOperationTestGroup("HttpOperation Tests"); - - template <> template <> - void HttpOperationTestObjectType::test<1>() - { - set_test_name("HttpOpNull construction"); - - // create a new ref counted object with an implicit reference - HttpOperation::ptr_t op (new HttpOpNull()); - ensure(op.use_count() == 1); - - // release the implicit reference, causing the object to be released - op.reset(); - } - - template <> template <> - void HttpOperationTestObjectType::test<2>() - { - set_test_name("HttpOpNull construction with handlers"); - - // Get some handlers - LLCore::HttpHandler::ptr_t h1 (new TestHandler()); - - // create a new ref counted object with an implicit reference - HttpOperation::ptr_t op (new HttpOpNull()); - - // Add the handlers - op->setReplyPath(LLCore::HttpOperation::HttpReplyQueuePtr_t(), h1); - - // Check ref count - ensure(op.unique() == 1); - - // release the reference, releasing the operation but - // not the handlers. - op.reset(); - - // release the handlers - h1.reset(); - } + struct HttpOperationTestData + { + // the test objects inherit from this so the member functions and variables + // can be referenced directly inside of the test functions. + }; + + typedef test_group<HttpOperationTestData> HttpOperationTestGroupType; + typedef HttpOperationTestGroupType::object HttpOperationTestObjectType; + HttpOperationTestGroupType HttpOperationTestGroup("HttpOperation Tests"); + + template <> template <> + void HttpOperationTestObjectType::test<1>() + { + set_test_name("HttpOpNull construction"); + + // create a new ref counted object with an implicit reference + HttpOperation::ptr_t op (new HttpOpNull()); + ensure(op.use_count() == 1); + + // release the implicit reference, causing the object to be released + op.reset(); + } + + template <> template <> + void HttpOperationTestObjectType::test<2>() + { + set_test_name("HttpOpNull construction with handlers"); + + // Get some handlers + LLCore::HttpHandler::ptr_t h1 (new TestHandler()); + + // create a new ref counted object with an implicit reference + HttpOperation::ptr_t op (new HttpOpNull()); + + // Add the handlers + op->setReplyPath(LLCore::HttpOperation::HttpReplyQueuePtr_t(), h1); + + // Check ref count + ensure(op.unique() == 1); + + // release the reference, releasing the operation but + // not the handlers. + op.reset(); + + // release the handlers + h1.reset(); + } } diff --git a/indra/llcorehttp/tests/test_httprequest.hpp b/indra/llcorehttp/tests/test_httprequest.hpp index 3eaac10aeb..aed906bb8f 100644 --- a/indra/llcorehttp/tests/test_httprequest.hpp +++ b/indra/llcorehttp/tests/test_httprequest.hpp @@ -1,4 +1,4 @@ -/** +/** * @file test_httprequest.hpp * @brief unit tests for the LLCore::HttpRequest class * @@ -51,8 +51,8 @@ using namespace LLCoreInt; // loaded system where the unit test is in competition with // other programs. static const int LOOP_SLEEP_INTERVAL(10000); -static const int LOOP_COUNT_SHORT(500); // 5-second dwell time -static const int LOOP_COUNT_LONG(3000); // 30-second dwell time +static const int LOOP_COUNT_SHORT(500); // 5-second dwell time +static const int LOOP_COUNT_LONG(3000); // 30-second dwell time namespace { @@ -72,117 +72,117 @@ typedef std::vector<std::pair<boost::regex, boost::regex> > regex_container_t; struct HttpRequestTestData { - // the test objects inherit from this so the member functions and variables - // can be referenced directly inside of the test functions. - int mHandlerCalls; - HttpStatus mStatus; + // the test objects inherit from this so the member functions and variables + // can be referenced directly inside of the test functions. + int mHandlerCalls; + HttpStatus mStatus; }; class TestHandler2 : public LLCore::HttpHandler { public: - TestHandler2(HttpRequestTestData * state, - const std::string & name) - : mState(state), - mName(name), - mExpectHandle(LLCORE_HTTP_HANDLE_INVALID) - {} - - virtual void onCompleted(HttpHandle handle, HttpResponse * response) - { - if (LLCORE_HTTP_HANDLE_INVALID != mExpectHandle) - { - ensure("Expected handle received in handler", mExpectHandle == handle); - } - ensure("Handler got a response", NULL != response); - if (response && mState) - { - const HttpStatus actual_status(response->getStatus()); - std::ostringstream test; - test << "Expected HttpStatus received in response. Wanted: " - << mState->mStatus.toHex() << " Received: " << actual_status.toHex(); - ensure(test.str().c_str(), actual_status == mState->mStatus); - } - if (mState) - { - mState->mHandlerCalls++; - } - if (! mHeadersRequired.empty() || ! mHeadersDisallowed.empty()) - { - ensure("Response required with header check", response != NULL); - HttpHeaders::ptr_t header(response->getHeaders()); // Will not hold onto this - ensure("Some quantity of headers returned", header != NULL); - - if (! mHeadersRequired.empty()) - { - for (int i(0); i < mHeadersRequired.size(); ++i) - { - bool found = false; - for (HttpHeaders::const_iterator iter(header->begin()); - header->end() != iter; - ++iter) - { - // std::cerr << "Header: " << (*iter).first - // << ": " << (*iter).second << std::endl; - - if (boost::regex_match((*iter).first, - mHeadersRequired[i].first) && - boost::regex_match((*iter).second, - mHeadersRequired[i].second)) - { - found = true; - break; - } - } - std::ostringstream str; - str << "Required header #" << i << " " - << mHeadersRequired[i].first << "=" << mHeadersRequired[i].second - << " not found in response"; - ensure(str.str(), found); - } - } - - if (! mHeadersDisallowed.empty()) - { - for (int i(0); i < mHeadersDisallowed.size(); ++i) - { - for (HttpHeaders::const_iterator iter(header->begin()); - header->end() != iter; - ++iter) - { - if (boost::regex_match((*iter).first, - mHeadersDisallowed[i].first) && - boost::regex_match((*iter).second, - mHeadersDisallowed[i].second)) - { - std::ostringstream str; - str << "Disallowed header #" << i << " " - << mHeadersDisallowed[i].first << "=" << mHeadersDisallowed[i].second - << " found in response"; - ensure(str.str(), false); - } - } - } - } - } - - if (! mCheckContentType.empty()) - { - ensure("Response required with content type check", response != NULL); - std::string con_type(response->getContentType()); - ensure("Content-Type as expected (" + mCheckContentType + ")", - mCheckContentType == con_type); - } - - // std::cout << "TestHandler2::onCompleted() invoked" << std::endl; - } - - HttpRequestTestData * mState; - std::string mName; - HttpHandle mExpectHandle; - std::string mCheckContentType; - regex_container_t mHeadersRequired; - regex_container_t mHeadersDisallowed; + TestHandler2(HttpRequestTestData * state, + const std::string & name) + : mState(state), + mName(name), + mExpectHandle(LLCORE_HTTP_HANDLE_INVALID) + {} + + virtual void onCompleted(HttpHandle handle, HttpResponse * response) + { + if (LLCORE_HTTP_HANDLE_INVALID != mExpectHandle) + { + ensure("Expected handle received in handler", mExpectHandle == handle); + } + ensure("Handler got a response", NULL != response); + if (response && mState) + { + const HttpStatus actual_status(response->getStatus()); + std::ostringstream test; + test << "Expected HttpStatus received in response. Wanted: " + << mState->mStatus.toHex() << " Received: " << actual_status.toHex(); + ensure(test.str().c_str(), actual_status == mState->mStatus); + } + if (mState) + { + mState->mHandlerCalls++; + } + if (! mHeadersRequired.empty() || ! mHeadersDisallowed.empty()) + { + ensure("Response required with header check", response != NULL); + HttpHeaders::ptr_t header(response->getHeaders()); // Will not hold onto this + ensure("Some quantity of headers returned", header != NULL); + + if (! mHeadersRequired.empty()) + { + for (int i(0); i < mHeadersRequired.size(); ++i) + { + bool found = false; + for (HttpHeaders::const_iterator iter(header->begin()); + header->end() != iter; + ++iter) + { + // std::cerr << "Header: " << (*iter).first + // << ": " << (*iter).second << std::endl; + + if (boost::regex_match((*iter).first, + mHeadersRequired[i].first) && + boost::regex_match((*iter).second, + mHeadersRequired[i].second)) + { + found = true; + break; + } + } + std::ostringstream str; + str << "Required header #" << i << " " + << mHeadersRequired[i].first << "=" << mHeadersRequired[i].second + << " not found in response"; + ensure(str.str(), found); + } + } + + if (! mHeadersDisallowed.empty()) + { + for (int i(0); i < mHeadersDisallowed.size(); ++i) + { + for (HttpHeaders::const_iterator iter(header->begin()); + header->end() != iter; + ++iter) + { + if (boost::regex_match((*iter).first, + mHeadersDisallowed[i].first) && + boost::regex_match((*iter).second, + mHeadersDisallowed[i].second)) + { + std::ostringstream str; + str << "Disallowed header #" << i << " " + << mHeadersDisallowed[i].first << "=" << mHeadersDisallowed[i].second + << " found in response"; + ensure(str.str(), false); + } + } + } + } + } + + if (! mCheckContentType.empty()) + { + ensure("Response required with content type check", response != NULL); + std::string con_type(response->getContentType()); + ensure("Content-Type as expected (" + mCheckContentType + ")", + mCheckContentType == con_type); + } + + // std::cout << "TestHandler2::onCompleted() invoked" << std::endl; + } + + HttpRequestTestData * mState; + std::string mName; + HttpHandle mExpectHandle; + std::string mCheckContentType; + regex_container_t mHeadersRequired; + regex_container_t mHeadersDisallowed; }; typedef test_group<HttpRequestTestData> HttpRequestTestGroupType; @@ -192,72 +192,72 @@ HttpRequestTestGroupType HttpRequestTestGroup("HttpRequest Tests"); template <> template <> void HttpRequestTestObjectType::test<1>() { - ScopedCurlInit ready; - - set_test_name("HttpRequest construction"); - - HttpRequest * req = NULL; - - try - { - // Get singletons created - HttpRequest::createService(); - - // create a new ref counted object with an implicit reference - req = new HttpRequest(); - - // release the request object - delete req; - req = NULL; - - HttpRequest::destroyService(); - } - catch (...) - { - delete req; - HttpRequest::destroyService(); - throw; - } + ScopedCurlInit ready; + + set_test_name("HttpRequest construction"); + + HttpRequest * req = NULL; + + try + { + // Get singletons created + HttpRequest::createService(); + + // create a new ref counted object with an implicit reference + req = new HttpRequest(); + + // release the request object + delete req; + req = NULL; + + HttpRequest::destroyService(); + } + catch (...) + { + delete req; + HttpRequest::destroyService(); + throw; + } } template <> template <> void HttpRequestTestObjectType::test<2>() { - ScopedCurlInit ready; - - set_test_name("HttpRequest and Null Op queued"); - - HttpRequest * req = NULL; - - try - { - // Get singletons created - HttpRequest::createService(); - - // create a new ref counted object with an implicit reference - req = new HttpRequest(); - - // Issue a NoOp - HttpHandle handle = req->requestNoOp(LLCore::HttpHandler::ptr_t()); - ensure("Request issued", handle != LLCORE_HTTP_HANDLE_INVALID); - - // release the request object - delete req; - req = NULL; - - // Request queue should have two references: global singleton & service object - ensure("Two references to request queue", 2 == HttpRequestQueue::instanceOf()->getRefCount()); - - // Okay, tear it down - HttpRequest::destroyService(); - } - catch (...) - { - stop_thread(req); - delete req; - HttpRequest::destroyService(); - throw; - } + ScopedCurlInit ready; + + set_test_name("HttpRequest and Null Op queued"); + + HttpRequest * req = NULL; + + try + { + // Get singletons created + HttpRequest::createService(); + + // create a new ref counted object with an implicit reference + req = new HttpRequest(); + + // Issue a NoOp + HttpHandle handle = req->requestNoOp(LLCore::HttpHandler::ptr_t()); + ensure("Request issued", handle != LLCORE_HTTP_HANDLE_INVALID); + + // release the request object + delete req; + req = NULL; + + // Request queue should have two references: global singleton & service object + ensure("Two references to request queue", 2 == HttpRequestQueue::instanceOf()->getRefCount()); + + // Okay, tear it down + HttpRequest::destroyService(); + } + catch (...) + { + stop_thread(req); + delete req; + HttpRequest::destroyService(); + throw; + } } namespace @@ -268,1243 +268,1243 @@ namespace template <> template <> void HttpRequestTestObjectType::test<3>() { - ScopedCurlInit ready; - - set_test_name("HttpRequest NoOp + Stop execution"); - - // Handler can be stack-allocated *if* there are no dangling - // references to it after completion of this method. - // Create before memory record as the string copy will bump numbers. - TestHandler2 handler(this, "handler"); + ScopedCurlInit ready; + + set_test_name("HttpRequest NoOp + Stop execution"); + + // Handler can be stack-allocated *if* there are no dangling + // references to it after completion of this method. + // Create before memory record as the string copy will bump numbers. + TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - mHandlerCalls = 0; + mHandlerCalls = 0; - HttpRequest * req = NULL; - - try - { - // Get singletons created + HttpRequest * req = NULL; + + try + { + // Get singletons created HttpRequest::createService(); - - // Start threading early so that thread memory is invariant - // over the test. - HttpRequest::startThread(); - - // create a new ref counted object with an implicit reference - req = new HttpRequest(); - - // Issue a NoOp - HttpHandle handle = req->requestNoOp(handlerp); - ensure("Valid handle returned for first request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump. - int count(0); - int limit(LOOP_COUNT_SHORT); - while (count++ < limit && mHandlerCalls < 1) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Request executed in reasonable time", count < limit); - ensure("One handler invocation for request", mHandlerCalls == 1); - - // Okay, request a shutdown of the servicing thread - handle = req->requestStopThread(handlerp); - ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump again - count = 0; - limit = LOOP_COUNT_LONG; - while (count++ < limit && mHandlerCalls < 2) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Second request executed in reasonable time", count < limit); - ensure("Second handler invocation", mHandlerCalls == 2); - - // See that we actually shutdown the thread - count = 0; - limit = LOOP_COUNT_SHORT; - while (count++ < limit && ! HttpService::isStopped()) - { - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Thread actually stopped running", HttpService::isStopped()); - - // release the request object - delete req; - req = NULL; - - // Shut down service - HttpRequest::destroyService(); - - ensure("Two handler calls on the way out", 2 == mHandlerCalls); - } - catch (...) - { - stop_thread(req); - delete req; - HttpRequest::destroyService(); - throw; - } + + // Start threading early so that thread memory is invariant + // over the test. + HttpRequest::startThread(); + + // create a new ref counted object with an implicit reference + req = new HttpRequest(); + + // Issue a NoOp + HttpHandle handle = req->requestNoOp(handlerp); + ensure("Valid handle returned for first request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump. + int count(0); + int limit(LOOP_COUNT_SHORT); + while (count++ < limit && mHandlerCalls < 1) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Request executed in reasonable time", count < limit); + ensure("One handler invocation for request", mHandlerCalls == 1); + + // Okay, request a shutdown of the servicing thread + handle = req->requestStopThread(handlerp); + ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump again + count = 0; + limit = LOOP_COUNT_LONG; + while (count++ < limit && mHandlerCalls < 2) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Second request executed in reasonable time", count < limit); + ensure("Second handler invocation", mHandlerCalls == 2); + + // See that we actually shutdown the thread + count = 0; + limit = LOOP_COUNT_SHORT; + while (count++ < limit && ! HttpService::isStopped()) + { + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Thread actually stopped running", HttpService::isStopped()); + + // release the request object + delete req; + req = NULL; + + // Shut down service + HttpRequest::destroyService(); + + ensure("Two handler calls on the way out", 2 == mHandlerCalls); + } + catch (...) + { + stop_thread(req); + delete req; + HttpRequest::destroyService(); + throw; + } } template <> template <> void HttpRequestTestObjectType::test<4>() { - ScopedCurlInit ready; + ScopedCurlInit ready; - set_test_name("2 HttpRequest instances, one thread"); + set_test_name("2 HttpRequest instances, one thread"); - // Handler can be stack-allocated *if* there are no dangling - // references to it after completion of this method. - TestHandler2 handler1(this, "handler1"); - TestHandler2 handler2(this, "handler2"); + // Handler can be stack-allocated *if* there are no dangling + // references to it after completion of this method. + TestHandler2 handler1(this, "handler1"); + TestHandler2 handler2(this, "handler2"); LLCore::HttpHandler::ptr_t handler1p(&handler1, NoOpDeletor); LLCore::HttpHandler::ptr_t handler2p(&handler2, NoOpDeletor); - mHandlerCalls = 0; - - HttpRequest * req1 = NULL; - HttpRequest * req2 = NULL; - - try - { - - // Get singletons created - HttpRequest::createService(); - - // Start threading early so that thread memory is invariant - // over the test. - HttpRequest::startThread(); - - // create a new ref counted object with an implicit reference - req1 = new HttpRequest(); - req2 = new HttpRequest(); - - // Issue some NoOps - HttpHandle handle = req1->requestNoOp(handler1p); - ensure("Valid handle returned for first request", handle != LLCORE_HTTP_HANDLE_INVALID); - handler1.mExpectHandle = handle; - - handle = req2->requestNoOp(handler2p); - ensure("Valid handle returned for first request", handle != LLCORE_HTTP_HANDLE_INVALID); - handler2.mExpectHandle = handle; - - // Run the notification pump. - int count(0); - int limit(LOOP_COUNT_LONG); - while (count++ < limit && mHandlerCalls < 2) - { - req1->update(1000000); - req2->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Request executed in reasonable time", count < limit); - ensure("One handler invocation for request", mHandlerCalls == 2); - - // Okay, request a shutdown of the servicing thread - handle = req2->requestStopThread(handler2p); - ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); - handler2.mExpectHandle = handle; - - // Run the notification pump again - count = 0; - limit = LOOP_COUNT_LONG; - while (count++ < limit && mHandlerCalls < 3) - { - req1->update(1000000); - req2->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Second request executed in reasonable time", count < limit); - ensure("Second handler invocation", mHandlerCalls == 3); - - // See that we actually shutdown the thread - count = 0; - limit = LOOP_COUNT_SHORT; - while (count++ < limit && ! HttpService::isStopped()) - { - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Thread actually stopped running", HttpService::isStopped()); - - // release the request object - delete req1; - req1 = NULL; - delete req2; - req2 = NULL; - - // Shut down service - HttpRequest::destroyService(); - - ensure("Two handler calls on the way out", 3 == mHandlerCalls); - } - catch (...) - { - stop_thread(req1); - delete req1; - delete req2; - HttpRequest::destroyService(); - throw; - } + mHandlerCalls = 0; + + HttpRequest * req1 = NULL; + HttpRequest * req2 = NULL; + + try + { + + // Get singletons created + HttpRequest::createService(); + + // Start threading early so that thread memory is invariant + // over the test. + HttpRequest::startThread(); + + // create a new ref counted object with an implicit reference + req1 = new HttpRequest(); + req2 = new HttpRequest(); + + // Issue some NoOps + HttpHandle handle = req1->requestNoOp(handler1p); + ensure("Valid handle returned for first request", handle != LLCORE_HTTP_HANDLE_INVALID); + handler1.mExpectHandle = handle; + + handle = req2->requestNoOp(handler2p); + ensure("Valid handle returned for first request", handle != LLCORE_HTTP_HANDLE_INVALID); + handler2.mExpectHandle = handle; + + // Run the notification pump. + int count(0); + int limit(LOOP_COUNT_LONG); + while (count++ < limit && mHandlerCalls < 2) + { + req1->update(1000000); + req2->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Request executed in reasonable time", count < limit); + ensure("One handler invocation for request", mHandlerCalls == 2); + + // Okay, request a shutdown of the servicing thread + handle = req2->requestStopThread(handler2p); + ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); + handler2.mExpectHandle = handle; + + // Run the notification pump again + count = 0; + limit = LOOP_COUNT_LONG; + while (count++ < limit && mHandlerCalls < 3) + { + req1->update(1000000); + req2->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Second request executed in reasonable time", count < limit); + ensure("Second handler invocation", mHandlerCalls == 3); + + // See that we actually shutdown the thread + count = 0; + limit = LOOP_COUNT_SHORT; + while (count++ < limit && ! HttpService::isStopped()) + { + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Thread actually stopped running", HttpService::isStopped()); + + // release the request object + delete req1; + req1 = NULL; + delete req2; + req2 = NULL; + + // Shut down service + HttpRequest::destroyService(); + + ensure("Two handler calls on the way out", 3 == mHandlerCalls); + } + catch (...) + { + stop_thread(req1); + delete req1; + delete req2; + HttpRequest::destroyService(); + throw; + } } template <> template <> void HttpRequestTestObjectType::test<5>() { - ScopedCurlInit ready; - - set_test_name("HttpRequest Spin (soft) + NoOp + hard termination"); - - // Handler can be stack-allocated *if* there are no dangling - // references to it after completion of this method. - // Create before memory record as the string copy will bump numbers. - TestHandler2 handler(this, "handler"); + ScopedCurlInit ready; + + set_test_name("HttpRequest Spin (soft) + NoOp + hard termination"); + + // Handler can be stack-allocated *if* there are no dangling + // references to it after completion of this method. + // Create before memory record as the string copy will bump numbers. + TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - mHandlerCalls = 0; - - HttpRequest * req = NULL; - - try - { - // Get singletons created - HttpRequest::createService(); - - // Start threading early so that thread memory is invariant - // over the test. - HttpRequest::startThread(); - - // create a new ref counted object with an implicit reference - req = new HttpRequest(); - - // Issue a Spin - HttpHandle handle = req->requestSpin(1); - ensure("Valid handle returned for spin request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Issue a NoOp - handle = req->requestNoOp(handlerp); - ensure("Valid handle returned for no-op request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump. - int count(0); - int limit(LOOP_COUNT_SHORT); - while (count++ < limit && mHandlerCalls < 1) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("NoOp notification received", mHandlerCalls == 1); - - // release the request object - delete req; - req = NULL; - - // Shut down service - HttpRequest::destroyService(); - } - catch (...) - { - stop_thread(req); - delete req; - HttpRequest::destroyService(); - throw; - } + mHandlerCalls = 0; + + HttpRequest * req = NULL; + + try + { + // Get singletons created + HttpRequest::createService(); + + // Start threading early so that thread memory is invariant + // over the test. + HttpRequest::startThread(); + + // create a new ref counted object with an implicit reference + req = new HttpRequest(); + + // Issue a Spin + HttpHandle handle = req->requestSpin(1); + ensure("Valid handle returned for spin request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Issue a NoOp + handle = req->requestNoOp(handlerp); + ensure("Valid handle returned for no-op request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump. + int count(0); + int limit(LOOP_COUNT_SHORT); + while (count++ < limit && mHandlerCalls < 1) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("NoOp notification received", mHandlerCalls == 1); + + // release the request object + delete req; + req = NULL; + + // Shut down service + HttpRequest::destroyService(); + } + catch (...) + { + stop_thread(req); + delete req; + HttpRequest::destroyService(); + throw; + } } template <> template <> void HttpRequestTestObjectType::test<6>() { - ScopedCurlInit ready; - - set_test_name("HttpRequest Spin + NoOp + hard termination"); - - // Handler can be stack-allocated *if* there are no dangling - // references to it after completion of this method. - // Create before memory record as the string copy will bump numbers. - TestHandler2 handler(this, "handler"); - mHandlerCalls = 0; - - HttpRequest * req = NULL; - - try - { + ScopedCurlInit ready; + + set_test_name("HttpRequest Spin + NoOp + hard termination"); + + // Handler can be stack-allocated *if* there are no dangling + // references to it after completion of this method. + // Create before memory record as the string copy will bump numbers. + TestHandler2 handler(this, "handler"); + mHandlerCalls = 0; + + HttpRequest * req = NULL; + + try + { LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - // Get singletons created - HttpRequest::createService(); - - // Start threading early so that thread memory is invariant - // over the test. - HttpRequest::startThread(); - - // create a new ref counted object with an implicit reference - req = new HttpRequest(); - - // Issue a Spin - HttpHandle handle = req->requestSpin(0); // Hard spin - ensure("Valid handle returned for spin request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Issue a NoOp - handle = req->requestNoOp(handlerp); - ensure("Valid handle returned for no-op request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump. - int count(0); - int limit(LOOP_COUNT_SHORT); - while (count++ < limit && mHandlerCalls < 1) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("No notifications received", mHandlerCalls == 0); - - // release the request object - delete req; - req = NULL; - - // Shut down service - HttpRequest::destroyService(); - } - catch (...) - { - stop_thread(req); - delete req; - HttpRequest::destroyService(); - throw; - } + // Get singletons created + HttpRequest::createService(); + + // Start threading early so that thread memory is invariant + // over the test. + HttpRequest::startThread(); + + // create a new ref counted object with an implicit reference + req = new HttpRequest(); + + // Issue a Spin + HttpHandle handle = req->requestSpin(0); // Hard spin + ensure("Valid handle returned for spin request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Issue a NoOp + handle = req->requestNoOp(handlerp); + ensure("Valid handle returned for no-op request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump. + int count(0); + int limit(LOOP_COUNT_SHORT); + while (count++ < limit && mHandlerCalls < 1) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("No notifications received", mHandlerCalls == 0); + + // release the request object + delete req; + req = NULL; + + // Shut down service + HttpRequest::destroyService(); + } + catch (...) + { + stop_thread(req); + delete req; + HttpRequest::destroyService(); + throw; + } } template <> template <> void HttpRequestTestObjectType::test<7>() { - ScopedCurlInit ready; + ScopedCurlInit ready; - set_test_name("HttpRequest GET to dead port + Stop execution"); + set_test_name("HttpRequest GET to dead port + Stop execution"); - // Handler can be stack-allocated *if* there are no dangling - // references to it after completion of this method. - // Create before memory record as the string copy will bump numbers. - TestHandler2 handler(this, "handler"); + // Handler can be stack-allocated *if* there are no dangling + // references to it after completion of this method. + // Create before memory record as the string copy will bump numbers. + TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - mHandlerCalls = 0; + mHandlerCalls = 0; + + HttpRequest * req = NULL; + HttpOptions::ptr_t opts; - HttpRequest * req = NULL; - HttpOptions::ptr_t opts; - - try - { + try + { // Get singletons created - HttpRequest::createService(); - - // Start threading early so that thread memory is invariant - // over the test. - HttpRequest::startThread(); + HttpRequest::createService(); + + // Start threading early so that thread memory is invariant + // over the test. + HttpRequest::startThread(); - // create a new ref counted object with an implicit reference - req = new HttpRequest(); + // create a new ref counted object with an implicit reference + req = new HttpRequest(); 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 - mStatus = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_CONNECT); - HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, - "http://127.0.0.1:2/nothing/here", - 0, - 0, - opts, - HttpHeaders::ptr_t(), - handlerp); - ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump. - int count(0); - int limit(LOOP_COUNT_LONG); - while (count++ < limit && mHandlerCalls < 1) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Request executed in reasonable time", count < limit); - ensure("One handler invocation for request", mHandlerCalls == 1); - - // Okay, request a shutdown of the servicing thread - mStatus = HttpStatus(); - handle = req->requestStopThread(handlerp); - ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump again - count = 0; - limit = LOOP_COUNT_LONG; - while (count++ < limit && mHandlerCalls < 2) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Second request executed in reasonable time", count < limit); - ensure("Second handler invocation", mHandlerCalls == 2); - - // See that we actually shutdown the thread - count = 0; - limit = LOOP_COUNT_SHORT; - while (count++ < limit && ! HttpService::isStopped()) - { - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Thread actually stopped running", HttpService::isStopped()); - - // release options + opts->setRetries(1); // Don't try for too long - default retries take about 18S + + // Issue a GET that can't connect + mStatus = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_CONNECT); + HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, + "http://127.0.0.1:2/nothing/here", + 0, + 0, + opts, + HttpHeaders::ptr_t(), + handlerp); + ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump. + int count(0); + int limit(LOOP_COUNT_LONG); + while (count++ < limit && mHandlerCalls < 1) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Request executed in reasonable time", count < limit); + ensure("One handler invocation for request", mHandlerCalls == 1); + + // Okay, request a shutdown of the servicing thread + mStatus = HttpStatus(); + handle = req->requestStopThread(handlerp); + ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump again + count = 0; + limit = LOOP_COUNT_LONG; + while (count++ < limit && mHandlerCalls < 2) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Second request executed in reasonable time", count < limit); + ensure("Second handler invocation", mHandlerCalls == 2); + + // See that we actually shutdown the thread + count = 0; + limit = LOOP_COUNT_SHORT; + while (count++ < limit && ! HttpService::isStopped()) + { + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Thread actually stopped running", HttpService::isStopped()); + + // release options opts.reset(); - - // release the request object - delete req; - req = NULL; - - // Shut down service - HttpRequest::destroyService(); - - ensure("Two handler calls on the way out", 2 == mHandlerCalls); - } - catch (...) - { - stop_thread(req); + + // release the request object + delete req; + req = NULL; + + // Shut down service + HttpRequest::destroyService(); + + ensure("Two handler calls on the way out", 2 == mHandlerCalls); + } + catch (...) + { + stop_thread(req); opts.reset(); - delete req; - HttpRequest::destroyService(); - throw; - } + delete req; + HttpRequest::destroyService(); + throw; + } } template <> template <> void HttpRequestTestObjectType::test<8>() { - ScopedCurlInit ready; + ScopedCurlInit ready; - std::string url_base(get_base_url()); - // std::cerr << "Base: " << url_base << std::endl; - - set_test_name("HttpRequest GET to real service"); + std::string url_base(get_base_url()); + // std::cerr << "Base: " << url_base << std::endl; - // Handler can be stack-allocated *if* there are no dangling - // references to it after completion of this method. - // Create before memory record as the string copy will bump numbers. - TestHandler2 handler(this, "handler"); + set_test_name("HttpRequest GET to real service"); + + // Handler can be stack-allocated *if* there are no dangling + // references to it after completion of this method. + // Create before memory record as the string copy will bump numbers. + TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - mHandlerCalls = 0; + mHandlerCalls = 0; - HttpRequest * req = NULL; + HttpRequest * req = NULL; - try - { + try + { // Get singletons created - HttpRequest::createService(); - - // Start threading early so that thread memory is invariant - // over the test. - HttpRequest::startThread(); - - // create a new ref counted object with an implicit reference - req = new HttpRequest(); - - // Issue a GET that *can* connect - mStatus = HttpStatus(200); - HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID, - url_base, - HttpOptions::ptr_t(), + HttpRequest::createService(); + + // Start threading early so that thread memory is invariant + // over the test. + HttpRequest::startThread(); + + // create a new ref counted object with an implicit reference + req = new HttpRequest(); + + // Issue a GET that *can* connect + mStatus = HttpStatus(200); + HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID, + url_base, + HttpOptions::ptr_t(), HttpHeaders::ptr_t(), - handlerp); - ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump. - int count(0); - int limit(LOOP_COUNT_LONG); - while (count++ < limit && mHandlerCalls < 1) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Request executed in reasonable time", count < limit); - ensure("One handler invocation for request", mHandlerCalls == 1); - - // Okay, request a shutdown of the servicing thread - mStatus = HttpStatus(); - handle = req->requestStopThread(handlerp); - ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump again - count = 0; - limit = LOOP_COUNT_LONG; - while (count++ < limit && mHandlerCalls < 2) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Second request executed in reasonable time", count < limit); - ensure("Second handler invocation", mHandlerCalls == 2); - - // See that we actually shutdown the thread - count = 0; - limit = LOOP_COUNT_SHORT; - while (count++ < limit && ! HttpService::isStopped()) - { - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Thread actually stopped running", HttpService::isStopped()); - - // release the request object - delete req; - req = NULL; - - // Shut down service - HttpRequest::destroyService(); - - ensure("Two handler calls on the way out", 2 == mHandlerCalls); - } - catch (...) - { - stop_thread(req); - delete req; - HttpRequest::destroyService(); - throw; - } + handlerp); + ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump. + int count(0); + int limit(LOOP_COUNT_LONG); + while (count++ < limit && mHandlerCalls < 1) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Request executed in reasonable time", count < limit); + ensure("One handler invocation for request", mHandlerCalls == 1); + + // Okay, request a shutdown of the servicing thread + mStatus = HttpStatus(); + handle = req->requestStopThread(handlerp); + ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump again + count = 0; + limit = LOOP_COUNT_LONG; + while (count++ < limit && mHandlerCalls < 2) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Second request executed in reasonable time", count < limit); + ensure("Second handler invocation", mHandlerCalls == 2); + + // See that we actually shutdown the thread + count = 0; + limit = LOOP_COUNT_SHORT; + while (count++ < limit && ! HttpService::isStopped()) + { + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Thread actually stopped running", HttpService::isStopped()); + + // release the request object + delete req; + req = NULL; + + // Shut down service + HttpRequest::destroyService(); + + ensure("Two handler calls on the way out", 2 == mHandlerCalls); + } + catch (...) + { + stop_thread(req); + delete req; + HttpRequest::destroyService(); + throw; + } } template <> template <> void HttpRequestTestObjectType::test<9>() { - ScopedCurlInit ready; + ScopedCurlInit ready; + + std::string url_base(get_base_url()); + // std::cerr << "Base: " << url_base << std::endl; - std::string url_base(get_base_url()); - // std::cerr << "Base: " << url_base << std::endl; - - set_test_name("HttpRequest GET with Range: header to real service"); + set_test_name("HttpRequest GET with Range: header to real service"); - // Handler can be stack-allocated *if* there are no dangling - // references to it after completion of this method. - // Create before memory record as the string copy will bump numbers. - TestHandler2 handler(this, "handler"); + // Handler can be stack-allocated *if* there are no dangling + // references to it after completion of this method. + // Create before memory record as the string copy will bump numbers. + TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - mHandlerCalls = 0; + mHandlerCalls = 0; - HttpRequest * req = NULL; + HttpRequest * req = NULL; - try - { + try + { // Get singletons created - HttpRequest::createService(); - - // Start threading early so that thread memory is invariant - // over the test. - HttpRequest::startThread(); - - // create a new ref counted object with an implicit reference - req = new HttpRequest(); - - // Issue a GET that *can* connect - mStatus = HttpStatus(200); - HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, - url_base, - 0, - 0, - HttpOptions::ptr_t(), + HttpRequest::createService(); + + // Start threading early so that thread memory is invariant + // over the test. + HttpRequest::startThread(); + + // create a new ref counted object with an implicit reference + req = new HttpRequest(); + + // Issue a GET that *can* connect + mStatus = HttpStatus(200); + HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, + url_base, + 0, + 0, + HttpOptions::ptr_t(), HttpHeaders::ptr_t(), - handlerp); - ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump. - int count(0); - int limit(LOOP_COUNT_LONG); - while (count++ < limit && mHandlerCalls < 1) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Request executed in reasonable time", count < limit); - ensure("One handler invocation for request", mHandlerCalls == 1); - - // Okay, request a shutdown of the servicing thread - mStatus = HttpStatus(); - handle = req->requestStopThread(handlerp); - ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump again - count = 0; - limit = LOOP_COUNT_LONG; - while (count++ < limit && mHandlerCalls < 2) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Second request executed in reasonable time", count < limit); - ensure("Second handler invocation", mHandlerCalls == 2); - - // See that we actually shutdown the thread - count = 0; - limit = LOOP_COUNT_SHORT; - while (count++ < limit && ! HttpService::isStopped()) - { - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Thread actually stopped running", HttpService::isStopped()); - - // release the request object - delete req; - req = NULL; - - // Shut down service - HttpRequest::destroyService(); - - ensure("Two handler calls on the way out", 2 == mHandlerCalls); - } - catch (...) - { - stop_thread(req); - delete req; - HttpRequest::destroyService(); - throw; - } + handlerp); + ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump. + int count(0); + int limit(LOOP_COUNT_LONG); + while (count++ < limit && mHandlerCalls < 1) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Request executed in reasonable time", count < limit); + ensure("One handler invocation for request", mHandlerCalls == 1); + + // Okay, request a shutdown of the servicing thread + mStatus = HttpStatus(); + handle = req->requestStopThread(handlerp); + ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump again + count = 0; + limit = LOOP_COUNT_LONG; + while (count++ < limit && mHandlerCalls < 2) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Second request executed in reasonable time", count < limit); + ensure("Second handler invocation", mHandlerCalls == 2); + + // See that we actually shutdown the thread + count = 0; + limit = LOOP_COUNT_SHORT; + while (count++ < limit && ! HttpService::isStopped()) + { + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Thread actually stopped running", HttpService::isStopped()); + + // release the request object + delete req; + req = NULL; + + // Shut down service + HttpRequest::destroyService(); + + ensure("Two handler calls on the way out", 2 == mHandlerCalls); + } + catch (...) + { + stop_thread(req); + delete req; + HttpRequest::destroyService(); + throw; + } } template <> template <> void HttpRequestTestObjectType::test<10>() { - ScopedCurlInit ready; + ScopedCurlInit ready; - std::string url_base(get_base_url()); - // std::cerr << "Base: " << url_base << std::endl; - - set_test_name("HttpRequest PUT to real service"); + std::string url_base(get_base_url()); + // std::cerr << "Base: " << url_base << std::endl; - // Handler can be stack-allocated *if* there are no dangling - // references to it after completion of this method. - // Create before memory record as the string copy will bump numbers. - TestHandler2 handler(this, "handler"); + set_test_name("HttpRequest PUT to real service"); + + // Handler can be stack-allocated *if* there are no dangling + // references to it after completion of this method. + // Create before memory record as the string copy will bump numbers. + TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - mHandlerCalls = 0; + mHandlerCalls = 0; + + HttpRequest * req = NULL; + BufferArray * body = new BufferArray; - HttpRequest * req = NULL; - BufferArray * body = new BufferArray; - - try - { + try + { // Get singletons created - HttpRequest::createService(); - - // Start threading early so that thread memory is invariant - // over the test. - HttpRequest::startThread(); - - // create a new ref counted object with an implicit reference - req = new HttpRequest(); - - // Issue a GET that *can* connect - static const char * body_text("Now is the time for all good men..."); - body->append(body_text, strlen(body_text)); - mStatus = HttpStatus(200); - HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID, - url_base, - body, + HttpRequest::createService(); + + // Start threading early so that thread memory is invariant + // over the test. + HttpRequest::startThread(); + + // create a new ref counted object with an implicit reference + req = new HttpRequest(); + + // Issue a GET that *can* connect + static const char * body_text("Now is the time for all good men..."); + body->append(body_text, strlen(body_text)); + mStatus = HttpStatus(200); + HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID, + url_base, + body, HttpOptions::ptr_t(), HttpHeaders::ptr_t(), handlerp); - ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump. - int count(0); - int limit(LOOP_COUNT_LONG); - while (count++ < limit && mHandlerCalls < 1) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Request executed in reasonable time", count < limit); - ensure("One handler invocation for request", mHandlerCalls == 1); - - // Okay, request a shutdown of the servicing thread - mStatus = HttpStatus(); - handle = req->requestStopThread(handlerp); - ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump again - count = 0; - limit = LOOP_COUNT_LONG; - while (count++ < limit && mHandlerCalls < 2) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Second request executed in reasonable time", count < limit); - ensure("Second handler invocation", mHandlerCalls == 2); - - // See that we actually shutdown the thread - count = 0; - limit = LOOP_COUNT_SHORT; - while (count++ < limit && ! HttpService::isStopped()) - { - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Thread actually stopped running", HttpService::isStopped()); - - // Lose the request body - body->release(); - body = NULL; - - // release the request object - delete req; - req = NULL; - - // Shut down service - HttpRequest::destroyService(); - - ensure("Two handler calls on the way out", 2 == mHandlerCalls); - } - catch (...) - { - if (body) - { - body->release(); - } - stop_thread(req); - delete req; - HttpRequest::destroyService(); - throw; - } + ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump. + int count(0); + int limit(LOOP_COUNT_LONG); + while (count++ < limit && mHandlerCalls < 1) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Request executed in reasonable time", count < limit); + ensure("One handler invocation for request", mHandlerCalls == 1); + + // Okay, request a shutdown of the servicing thread + mStatus = HttpStatus(); + handle = req->requestStopThread(handlerp); + ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump again + count = 0; + limit = LOOP_COUNT_LONG; + while (count++ < limit && mHandlerCalls < 2) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Second request executed in reasonable time", count < limit); + ensure("Second handler invocation", mHandlerCalls == 2); + + // See that we actually shutdown the thread + count = 0; + limit = LOOP_COUNT_SHORT; + while (count++ < limit && ! HttpService::isStopped()) + { + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Thread actually stopped running", HttpService::isStopped()); + + // Lose the request body + body->release(); + body = NULL; + + // release the request object + delete req; + req = NULL; + + // Shut down service + HttpRequest::destroyService(); + + ensure("Two handler calls on the way out", 2 == mHandlerCalls); + } + catch (...) + { + if (body) + { + body->release(); + } + stop_thread(req); + delete req; + HttpRequest::destroyService(); + throw; + } } template <> template <> void HttpRequestTestObjectType::test<11>() { - ScopedCurlInit ready; + ScopedCurlInit ready; + + std::string url_base(get_base_url()); + // std::cerr << "Base: " << url_base << std::endl; - std::string url_base(get_base_url()); - // std::cerr << "Base: " << url_base << std::endl; - - set_test_name("HttpRequest POST to real service"); + set_test_name("HttpRequest POST to real service"); - // Handler can be stack-allocated *if* there are no dangling - // references to it after completion of this method. - // Create before memory record as the string copy will bump numbers. - TestHandler2 handler(this, "handler"); + // Handler can be stack-allocated *if* there are no dangling + // references to it after completion of this method. + // Create before memory record as the string copy will bump numbers. + TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - mHandlerCalls = 0; + mHandlerCalls = 0; - HttpRequest * req = NULL; - BufferArray * body = new BufferArray; - - try - { + HttpRequest * req = NULL; + BufferArray * body = new BufferArray; + + try + { // Get singletons created - HttpRequest::createService(); - - // Start threading early so that thread memory is invariant - // over the test. - HttpRequest::startThread(); - - // create a new ref counted object with an implicit reference - req = new HttpRequest(); - - // Issue a GET that *can* connect - static const char * body_text("Now is the time for all good men..."); - body->append(body_text, strlen(body_text)); - mStatus = HttpStatus(200); - HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID, - url_base, - body, + HttpRequest::createService(); + + // Start threading early so that thread memory is invariant + // over the test. + HttpRequest::startThread(); + + // create a new ref counted object with an implicit reference + req = new HttpRequest(); + + // Issue a GET that *can* connect + static const char * body_text("Now is the time for all good men..."); + body->append(body_text, strlen(body_text)); + mStatus = HttpStatus(200); + HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID, + url_base, + body, HttpOptions::ptr_t(), HttpHeaders::ptr_t(), handlerp); - ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump. - int count(0); - int limit(LOOP_COUNT_LONG); - while (count++ < limit && mHandlerCalls < 1) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Request executed in reasonable time", count < limit); - ensure("One handler invocation for request", mHandlerCalls == 1); - - // Okay, request a shutdown of the servicing thread - mStatus = HttpStatus(); - handle = req->requestStopThread(handlerp); - ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump again - count = 0; - limit = LOOP_COUNT_LONG; - while (count++ < limit && mHandlerCalls < 2) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Second request executed in reasonable time", count < limit); - ensure("Second handler invocation", mHandlerCalls == 2); - - // See that we actually shutdown the thread - count = 0; - limit = LOOP_COUNT_SHORT; - while (count++ < limit && ! HttpService::isStopped()) - { - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Thread actually stopped running", HttpService::isStopped()); - - // Lose the request body - body->release(); - body = NULL; - - // release the request object - delete req; - req = NULL; - - // Shut down service - HttpRequest::destroyService(); - - ensure("Two handler calls on the way out", 2 == mHandlerCalls); - } - catch (...) - { - if (body) - { - body->release(); - } - stop_thread(req); - delete req; - HttpRequest::destroyService(); - throw; - } + ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump. + int count(0); + int limit(LOOP_COUNT_LONG); + while (count++ < limit && mHandlerCalls < 1) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Request executed in reasonable time", count < limit); + ensure("One handler invocation for request", mHandlerCalls == 1); + + // Okay, request a shutdown of the servicing thread + mStatus = HttpStatus(); + handle = req->requestStopThread(handlerp); + ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump again + count = 0; + limit = LOOP_COUNT_LONG; + while (count++ < limit && mHandlerCalls < 2) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Second request executed in reasonable time", count < limit); + ensure("Second handler invocation", mHandlerCalls == 2); + + // See that we actually shutdown the thread + count = 0; + limit = LOOP_COUNT_SHORT; + while (count++ < limit && ! HttpService::isStopped()) + { + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Thread actually stopped running", HttpService::isStopped()); + + // Lose the request body + body->release(); + body = NULL; + + // release the request object + delete req; + req = NULL; + + // Shut down service + HttpRequest::destroyService(); + + ensure("Two handler calls on the way out", 2 == mHandlerCalls); + } + catch (...) + { + if (body) + { + body->release(); + } + stop_thread(req); + delete req; + HttpRequest::destroyService(); + throw; + } } template <> template <> void HttpRequestTestObjectType::test<12>() { - ScopedCurlInit ready; + ScopedCurlInit ready; - std::string url_base(get_base_url()); - // std::cerr << "Base: " << url_base << std::endl; - - set_test_name("HttpRequest GET with some tracing"); + std::string url_base(get_base_url()); + // std::cerr << "Base: " << url_base << std::endl; - // Handler can be stack-allocated *if* there are no dangling - // references to it after completion of this method. - // Create before memory record as the string copy will bump numbers. - TestHandler2 handler(this, "handler"); + set_test_name("HttpRequest GET with some tracing"); + + // Handler can be stack-allocated *if* there are no dangling + // references to it after completion of this method. + // Create before memory record as the string copy will bump numbers. + TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - mHandlerCalls = 0; + mHandlerCalls = 0; - HttpRequest * req = NULL; + HttpRequest * req = NULL; - try - { + try + { // Get singletons created - HttpRequest::createService(); + HttpRequest::createService(); - // Enable tracing - HttpRequest::setStaticPolicyOption(HttpRequest::PO_TRACE, HttpRequest::DEFAULT_POLICY_ID, 2, NULL); + // Enable tracing + HttpRequest::setStaticPolicyOption(HttpRequest::PO_TRACE, HttpRequest::DEFAULT_POLICY_ID, 2, NULL); - // Start threading early so that thread memory is invariant - // over the test. - HttpRequest::startThread(); + // Start threading early so that thread memory is invariant + // over the test. + HttpRequest::startThread(); - // create a new ref counted object with an implicit reference - req = new HttpRequest(); + // create a new ref counted object with an implicit reference + req = new HttpRequest(); - // Issue a GET that *can* connect - mStatus = HttpStatus(200); - HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, - url_base, - 0, - 0, + // Issue a GET that *can* connect + mStatus = HttpStatus(200); + HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, + url_base, + 0, + 0, HttpOptions::ptr_t(), HttpHeaders::ptr_t(), handlerp); - ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump. - int count(0); - int limit(LOOP_COUNT_LONG); - while (count++ < limit && mHandlerCalls < 1) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Request executed in reasonable time", count < limit); - ensure("One handler invocation for request", mHandlerCalls == 1); - - // Okay, request a shutdown of the servicing thread - mStatus = HttpStatus(); - handle = req->requestStopThread(handlerp); - ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump again - count = 0; - limit = LOOP_COUNT_LONG; - while (count++ < limit && mHandlerCalls < 2) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Second request executed in reasonable time", count < limit); - ensure("Second handler invocation", mHandlerCalls == 2); - - // See that we actually shutdown the thread - count = 0; - limit = LOOP_COUNT_SHORT; - while (count++ < limit && ! HttpService::isStopped()) - { - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Thread actually stopped running", HttpService::isStopped()); - - // release the request object - delete req; - req = NULL; - - // Shut down service - HttpRequest::destroyService(); - - ensure("Two handler calls on the way out", 2 == mHandlerCalls); - } - catch (...) - { - stop_thread(req); - delete req; - HttpRequest::destroyService(); - throw; - } + ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump. + int count(0); + int limit(LOOP_COUNT_LONG); + while (count++ < limit && mHandlerCalls < 1) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Request executed in reasonable time", count < limit); + ensure("One handler invocation for request", mHandlerCalls == 1); + + // Okay, request a shutdown of the servicing thread + mStatus = HttpStatus(); + handle = req->requestStopThread(handlerp); + ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump again + count = 0; + limit = LOOP_COUNT_LONG; + while (count++ < limit && mHandlerCalls < 2) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Second request executed in reasonable time", count < limit); + ensure("Second handler invocation", mHandlerCalls == 2); + + // See that we actually shutdown the thread + count = 0; + limit = LOOP_COUNT_SHORT; + while (count++ < limit && ! HttpService::isStopped()) + { + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Thread actually stopped running", HttpService::isStopped()); + + // release the request object + delete req; + req = NULL; + + // Shut down service + HttpRequest::destroyService(); + + ensure("Two handler calls on the way out", 2 == mHandlerCalls); + } + catch (...) + { + stop_thread(req); + delete req; + HttpRequest::destroyService(); + throw; + } } template <> template <> void HttpRequestTestObjectType::test<13>() { - ScopedCurlInit ready; - - // Warmup boost::regex to pre-alloc memory for memory size tests - boost::regex warmup("askldjflasdj;f", boost::regex::icase); - boost::regex_match("akl;sjflajfk;ajsk", warmup); - - std::string url_base(get_base_url()); - // std::cerr << "Base: " << url_base << std::endl; - - set_test_name("HttpRequest GET with returned headers"); - - // Handler can be stack-allocated *if* there are no dangling - // references to it after completion of this method. - // Create before memory record as the string copy will bump numbers. - TestHandler2 handler(this, "handler"); - handler.mHeadersRequired.reserve(20); // Avoid memory leak test failure + ScopedCurlInit ready; + + // Warmup boost::regex to pre-alloc memory for memory size tests + boost::regex warmup("askldjflasdj;f", boost::regex::icase); + boost::regex_match("akl;sjflajfk;ajsk", warmup); + + std::string url_base(get_base_url()); + // std::cerr << "Base: " << url_base << std::endl; + + set_test_name("HttpRequest GET with returned headers"); + + // Handler can be stack-allocated *if* there are no dangling + // references to it after completion of this method. + // Create before memory record as the string copy will bump numbers. + TestHandler2 handler(this, "handler"); + handler.mHeadersRequired.reserve(20); // Avoid memory leak test failure LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - mHandlerCalls = 0; + mHandlerCalls = 0; - HttpRequest * req = NULL; - HttpOptions::ptr_t opts; + HttpRequest * req = NULL; + HttpOptions::ptr_t opts; - try - { + try + { // Get singletons created - HttpRequest::createService(); + HttpRequest::createService(); - // Enable tracing - HttpRequest::setStaticPolicyOption(HttpRequest::PO_TRACE, HttpRequest::DEFAULT_POLICY_ID, 2, NULL); + // Enable tracing + HttpRequest::setStaticPolicyOption(HttpRequest::PO_TRACE, HttpRequest::DEFAULT_POLICY_ID, 2, NULL); - // Start threading early so that thread memory is invariant - // over the test. - HttpRequest::startThread(); + // Start threading early so that thread memory is invariant + // over the test. + HttpRequest::startThread(); - // create a new ref counted object with an implicit reference - req = new HttpRequest(); + // create a new ref counted object with an implicit reference + req = new HttpRequest(); opts = HttpOptions::ptr_t(new HttpOptions()); - opts->setWantHeaders(true); - - // Issue a GET that succeeds - mStatus = HttpStatus(200); - handler.mHeadersRequired.push_back( - regex_container_t::value_type(boost::regex("X-LL-Special", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, - url_base, - 0, - 0, - opts, + opts->setWantHeaders(true); + + // Issue a GET that succeeds + mStatus = HttpStatus(200); + handler.mHeadersRequired.push_back( + regex_container_t::value_type(boost::regex("X-LL-Special", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, + url_base, + 0, + 0, + opts, HttpHeaders::ptr_t(), handlerp); - ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); + ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); - // release options + // release options opts.reset(); - // Run the notification pump. - int count(0); - int limit(LOOP_COUNT_LONG); - while (count++ < limit && mHandlerCalls < 1) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Request executed in reasonable time", count < limit); - ensure("One handler invocation for request", mHandlerCalls == 1); - - // Okay, request a shutdown of the servicing thread - mStatus = HttpStatus(); - handler.mHeadersRequired.clear(); - handle = req->requestStopThread(handlerp); - ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump again - count = 0; - limit = LOOP_COUNT_LONG; - while (count++ < limit && mHandlerCalls < 2) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Second request executed in reasonable time", count < limit); - ensure("Second handler invocation", mHandlerCalls == 2); - - // See that we actually shutdown the thread - count = 0; - limit = LOOP_COUNT_SHORT; - while (count++ < limit && ! HttpService::isStopped()) - { - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Thread actually stopped running", HttpService::isStopped()); - - // release the request object - delete req; - req = NULL; - - // Shut down service - HttpRequest::destroyService(); - - ensure("Two handler calls on the way out", 2 == mHandlerCalls); - } - catch (...) - { - stop_thread(req); + // Run the notification pump. + int count(0); + int limit(LOOP_COUNT_LONG); + while (count++ < limit && mHandlerCalls < 1) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Request executed in reasonable time", count < limit); + ensure("One handler invocation for request", mHandlerCalls == 1); + + // Okay, request a shutdown of the servicing thread + mStatus = HttpStatus(); + handler.mHeadersRequired.clear(); + handle = req->requestStopThread(handlerp); + ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump again + count = 0; + limit = LOOP_COUNT_LONG; + while (count++ < limit && mHandlerCalls < 2) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Second request executed in reasonable time", count < limit); + ensure("Second handler invocation", mHandlerCalls == 2); + + // See that we actually shutdown the thread + count = 0; + limit = LOOP_COUNT_SHORT; + while (count++ < limit && ! HttpService::isStopped()) + { + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Thread actually stopped running", HttpService::isStopped()); + + // release the request object + delete req; + req = NULL; + + // Shut down service + HttpRequest::destroyService(); + + ensure("Two handler calls on the way out", 2 == mHandlerCalls); + } + catch (...) + { + stop_thread(req); opts.reset(); - delete req; - HttpRequest::destroyService(); - throw; - } + delete req; + HttpRequest::destroyService(); + throw; + } } template <> template <> void HttpRequestTestObjectType::test<14>() { - ScopedCurlInit ready; - - set_test_name("HttpRequest GET timeout"); - - // Handler can be stack-allocated *if* there are no dangling - // references to it after completion of this method. - // Create before memory record as the string copy will bump numbers. - TestHandler2 handler(this, "handler"); - LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - std::string url_base(get_base_url() + "/sleep/"); // path to a 30-second sleep - mHandlerCalls = 0; - - HttpRequest * req = NULL; - HttpOptions::ptr_t opts; - - try - { - // Get singletons created - HttpRequest::createService(); - - // Start threading early so that thread memory is invariant - // over the test. - HttpRequest::startThread(); - - // create a new ref counted object with an implicit reference - req = new HttpRequest(); - - opts = HttpOptions::ptr_t(new HttpOptions); - opts->setRetries(0); // Don't retry - opts->setTimeout(2); - - // Issue a GET that sleeps - mStatus = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_OPERATION_TIMEDOUT); - HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, - url_base, - 0, - 0, - opts, - HttpHeaders::ptr_t(), - handlerp); - ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump. - int count(0); - int limit(LOOP_COUNT_LONG); - while (count++ < limit && mHandlerCalls < 1) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Request executed in reasonable time", count < limit); - ensure("One handler invocation for request", mHandlerCalls == 1); - - // Okay, request a shutdown of the servicing thread - mStatus = HttpStatus(); - handle = req->requestStopThread(handlerp); - ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump again - count = 0; - limit = LOOP_COUNT_LONG; - while (count++ < limit && mHandlerCalls < 2) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Second request executed in reasonable time", count < limit); - ensure("Second handler invocation", mHandlerCalls == 2); - - // See that we actually shutdown the thread - count = 0; - limit = LOOP_COUNT_SHORT; - while (count++ < limit && ! HttpService::isStopped()) - { - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Thread actually stopped running", HttpService::isStopped()); - - // release options - opts.reset(); - - // release the request object - delete req; - req = NULL; - - // Shut down service - HttpRequest::destroyService(); - - ensure("Two handler calls on the way out", 2 == mHandlerCalls); - } - catch (...) - { - stop_thread(req); - opts.reset(); - delete req; - HttpRequest::destroyService(); - throw; - } + ScopedCurlInit ready; + + set_test_name("HttpRequest GET timeout"); + + // Handler can be stack-allocated *if* there are no dangling + // references to it after completion of this method. + // Create before memory record as the string copy will bump numbers. + TestHandler2 handler(this, "handler"); + LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); + std::string url_base(get_base_url() + "/sleep/"); // path to a 30-second sleep + mHandlerCalls = 0; + + HttpRequest * req = NULL; + HttpOptions::ptr_t opts; + + try + { + // Get singletons created + HttpRequest::createService(); + + // Start threading early so that thread memory is invariant + // over the test. + HttpRequest::startThread(); + + // create a new ref counted object with an implicit reference + req = new HttpRequest(); + + opts = HttpOptions::ptr_t(new HttpOptions); + opts->setRetries(0); // Don't retry + opts->setTimeout(2); + + // Issue a GET that sleeps + mStatus = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_OPERATION_TIMEDOUT); + HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, + url_base, + 0, + 0, + opts, + HttpHeaders::ptr_t(), + handlerp); + ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump. + int count(0); + int limit(LOOP_COUNT_LONG); + while (count++ < limit && mHandlerCalls < 1) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Request executed in reasonable time", count < limit); + ensure("One handler invocation for request", mHandlerCalls == 1); + + // Okay, request a shutdown of the servicing thread + mStatus = HttpStatus(); + handle = req->requestStopThread(handlerp); + ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump again + count = 0; + limit = LOOP_COUNT_LONG; + while (count++ < limit && mHandlerCalls < 2) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Second request executed in reasonable time", count < limit); + ensure("Second handler invocation", mHandlerCalls == 2); + + // See that we actually shutdown the thread + count = 0; + limit = LOOP_COUNT_SHORT; + while (count++ < limit && ! HttpService::isStopped()) + { + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Thread actually stopped running", HttpService::isStopped()); + + // release options + opts.reset(); + + // release the request object + delete req; + req = NULL; + + // Shut down service + HttpRequest::destroyService(); + + ensure("Two handler calls on the way out", 2 == mHandlerCalls); + } + catch (...) + { + stop_thread(req); + opts.reset(); + delete req; + HttpRequest::destroyService(); + throw; + } } // Test retrieval of Content-Type/Content-Encoding headers template <> template <> void HttpRequestTestObjectType::test<15>() { - ScopedCurlInit ready; + ScopedCurlInit ready; + + std::string url_base(get_base_url()); + // std::cerr << "Base: " << url_base << std::endl; - std::string url_base(get_base_url()); - // std::cerr << "Base: " << url_base << std::endl; - - set_test_name("HttpRequest GET with Content-Type"); + set_test_name("HttpRequest GET with Content-Type"); - // Handler can be stack-allocated *if* there are no dangling - // references to it after completion of this method. - // Create before memory record as the string copy will bump numbers. - TestHandler2 handler(this, "handler"); + // Handler can be stack-allocated *if* there are no dangling + // references to it after completion of this method. + // Create before memory record as the string copy will bump numbers. + TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - // Load and clear the string setting to preload std::string object - // for memory return tests. - handler.mCheckContentType = "application/llsd+xml"; - handler.mCheckContentType.clear(); - mHandlerCalls = 0; + // Load and clear the string setting to preload std::string object + // for memory return tests. + handler.mCheckContentType = "application/llsd+xml"; + handler.mCheckContentType.clear(); + mHandlerCalls = 0; - HttpRequest * req = NULL; + HttpRequest * req = NULL; - try - { + try + { // Get singletons created - HttpRequest::createService(); - - // Start threading early so that thread memory is invariant - // over the test. - HttpRequest::startThread(); - - // create a new ref counted object with an implicit reference - req = new HttpRequest(); - - // Issue a GET that *can* connect - mStatus = HttpStatus(200); - handler.mCheckContentType = "application/llsd+xml"; - HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID, - url_base, + HttpRequest::createService(); + + // Start threading early so that thread memory is invariant + // over the test. + HttpRequest::startThread(); + + // create a new ref counted object with an implicit reference + req = new HttpRequest(); + + // Issue a GET that *can* connect + mStatus = HttpStatus(200); + handler.mCheckContentType = "application/llsd+xml"; + HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID, + url_base, HttpOptions::ptr_t(), HttpHeaders::ptr_t(), handlerp); - ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump. - int count(0); - int limit(LOOP_COUNT_LONG); - while (count++ < limit && mHandlerCalls < 1) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Request executed in reasonable time", count < limit); - ensure("One handler invocation for request", mHandlerCalls == 1); - - // Okay, request a shutdown of the servicing thread - mStatus = HttpStatus(); - handler.mCheckContentType.clear(); - handle = req->requestStopThread(handlerp); - ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump again - count = 0; - limit = LOOP_COUNT_LONG; - while (count++ < limit && mHandlerCalls < 2) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Second request executed in reasonable time", count < limit); - ensure("Second handler invocation", mHandlerCalls == 2); - - // See that we actually shutdown the thread - count = 0; - limit = LOOP_COUNT_SHORT; - while (count++ < limit && ! HttpService::isStopped()) - { - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Thread actually stopped running", HttpService::isStopped()); - - // release the request object - delete req; - req = NULL; - - // Shut down service - HttpRequest::destroyService(); - - ensure("Two handler calls on the way out", 2 == mHandlerCalls); - } - catch (...) - { - stop_thread(req); - delete req; - HttpRequest::destroyService(); - throw; - } + ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump. + int count(0); + int limit(LOOP_COUNT_LONG); + while (count++ < limit && mHandlerCalls < 1) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Request executed in reasonable time", count < limit); + ensure("One handler invocation for request", mHandlerCalls == 1); + + // Okay, request a shutdown of the servicing thread + mStatus = HttpStatus(); + handler.mCheckContentType.clear(); + handle = req->requestStopThread(handlerp); + ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump again + count = 0; + limit = LOOP_COUNT_LONG; + while (count++ < limit && mHandlerCalls < 2) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Second request executed in reasonable time", count < limit); + ensure("Second handler invocation", mHandlerCalls == 2); + + // See that we actually shutdown the thread + count = 0; + limit = LOOP_COUNT_SHORT; + while (count++ < limit && ! HttpService::isStopped()) + { + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Thread actually stopped running", HttpService::isStopped()); + + // release the request object + delete req; + req = NULL; + + // Shut down service + HttpRequest::destroyService(); + + ensure("Two handler calls on the way out", 2 == mHandlerCalls); + } + catch (...) + { + stop_thread(req); + delete req; + HttpRequest::destroyService(); + throw; + } } @@ -1512,236 +1512,236 @@ void HttpRequestTestObjectType::test<15>() template <> template <> void HttpRequestTestObjectType::test<16>() { - ScopedCurlInit ready; + ScopedCurlInit ready; - // Warmup boost::regex to pre-alloc memory for memory size tests - boost::regex warmup("askldjflasdj;f", boost::regex::icase); - boost::regex_match("akl;sjflajfk;ajsk", warmup); + // Warmup boost::regex to pre-alloc memory for memory size tests + boost::regex warmup("askldjflasdj;f", boost::regex::icase); + boost::regex_match("akl;sjflajfk;ajsk", warmup); - std::string url_base(get_base_url()); - - set_test_name("Header generation for HttpRequest GET"); + std::string url_base(get_base_url()); - // Handler can be stack-allocated *if* there are no dangling - // references to it after completion of this method. - // Create before memory record as the string copy will bump numbers. - TestHandler2 handler(this, "handler"); + set_test_name("Header generation for HttpRequest GET"); + + // Handler can be stack-allocated *if* there are no dangling + // references to it after completion of this method. + // Create before memory record as the string copy will bump numbers. + TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - mHandlerCalls = 0; + mHandlerCalls = 0; - HttpRequest * req = NULL; - HttpOptions::ptr_t options; - HttpHeaders::ptr_t headers; + HttpRequest * req = NULL; + HttpOptions::ptr_t options; + HttpHeaders::ptr_t headers; - try - { + try + { // Get singletons created - HttpRequest::createService(); - - // Start threading early so that thread memory is invariant - // over the test. - HttpRequest::startThread(); + HttpRequest::createService(); + + // Start threading early so that thread memory is invariant + // over the test. + HttpRequest::startThread(); - // create a new ref counted object with an implicit reference - req = new HttpRequest(); + // create a new ref counted object with an implicit reference + req = new HttpRequest(); - // options set + // options set options = HttpOptions::ptr_t(new HttpOptions()); - options->setWantHeaders(true); - - // Issue a GET that *can* connect - mStatus = HttpStatus(200); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-connection", boost::regex::icase), - boost::regex("keep-alive", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-accept", boost::regex::icase), - boost::regex("\\*/\\*", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-accept-encoding", boost::regex::icase), - boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-keep-alive", boost::regex::icase), - boost::regex("\\d+", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-host", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-cache-control", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-pragma", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-range", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-referer", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-content-type", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-content-encoding", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID, - url_base + "reflect/", - options, - HttpHeaders::ptr_t(), - handlerp); - ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump. - int count(0); - int limit(LOOP_COUNT_LONG); - while (count++ < limit && mHandlerCalls < 1) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Request executed in reasonable time", count < limit); - ensure("One handler invocation for request", mHandlerCalls == 1); - - // Do a texture-style fetch - headers = HttpHeaders::ptr_t(new HttpHeaders); - headers->append("Accept", "image/x-j2c"); - - mStatus = HttpStatus(200); - handler.mHeadersRequired.clear(); - handler.mHeadersDisallowed.clear(); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-connection", boost::regex::icase), - boost::regex("keep-alive", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-accept", boost::regex::icase), - boost::regex("image/x-j2c", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-accept-encoding", boost::regex::icase), - boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-keep-alive", boost::regex::icase), - boost::regex("\\d+", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-host", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("\\W*X-Reflect-range", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-cache-control", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-pragma", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-referer", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-content-type", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-content-encoding", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, - url_base + "reflect/", - 0, - 47, - options, - headers, - handlerp); - ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump. - count = 0; - limit = LOOP_COUNT_LONG; - while (count++ < limit && mHandlerCalls < 2) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Request executed in reasonable time", count < limit); - ensure("One handler invocation for request", mHandlerCalls == 2); - - - // Okay, request a shutdown of the servicing thread - mStatus = HttpStatus(); - handler.mHeadersRequired.clear(); - handler.mHeadersDisallowed.clear(); - handle = req->requestStopThread(handlerp); - ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump again - count = 0; - limit = LOOP_COUNT_LONG; - while (count++ < limit && mHandlerCalls < 3) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Second request executed in reasonable time", count < limit); - ensure("Second handler invocation", mHandlerCalls == 3); - - // See that we actually shutdown the thread - count = 0; - limit = LOOP_COUNT_SHORT; - while (count++ < limit && ! HttpService::isStopped()) - { - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Thread actually stopped running", HttpService::isStopped()); - - // release options & headers + options->setWantHeaders(true); + + // Issue a GET that *can* connect + mStatus = HttpStatus(200); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-connection", boost::regex::icase), + boost::regex("keep-alive", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-accept", boost::regex::icase), + boost::regex("\\*/\\*", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-accept-encoding", boost::regex::icase), + boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-keep-alive", boost::regex::icase), + boost::regex("\\d+", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-host", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-cache-control", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-pragma", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-range", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-referer", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-content-type", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-content-encoding", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID, + url_base + "reflect/", + options, + HttpHeaders::ptr_t(), + handlerp); + ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump. + int count(0); + int limit(LOOP_COUNT_LONG); + while (count++ < limit && mHandlerCalls < 1) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Request executed in reasonable time", count < limit); + ensure("One handler invocation for request", mHandlerCalls == 1); + + // Do a texture-style fetch + headers = HttpHeaders::ptr_t(new HttpHeaders); + headers->append("Accept", "image/x-j2c"); + + mStatus = HttpStatus(200); + handler.mHeadersRequired.clear(); + handler.mHeadersDisallowed.clear(); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-connection", boost::regex::icase), + boost::regex("keep-alive", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-accept", boost::regex::icase), + boost::regex("image/x-j2c", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-accept-encoding", boost::regex::icase), + boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-keep-alive", boost::regex::icase), + boost::regex("\\d+", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-host", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("\\W*X-Reflect-range", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-cache-control", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-pragma", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-referer", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-content-type", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-content-encoding", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, + url_base + "reflect/", + 0, + 47, + options, + headers, + handlerp); + ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump. + count = 0; + limit = LOOP_COUNT_LONG; + while (count++ < limit && mHandlerCalls < 2) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Request executed in reasonable time", count < limit); + ensure("One handler invocation for request", mHandlerCalls == 2); + + + // Okay, request a shutdown of the servicing thread + mStatus = HttpStatus(); + handler.mHeadersRequired.clear(); + handler.mHeadersDisallowed.clear(); + handle = req->requestStopThread(handlerp); + ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump again + count = 0; + limit = LOOP_COUNT_LONG; + while (count++ < limit && mHandlerCalls < 3) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Second request executed in reasonable time", count < limit); + ensure("Second handler invocation", mHandlerCalls == 3); + + // See that we actually shutdown the thread + count = 0; + limit = LOOP_COUNT_SHORT; + while (count++ < limit && ! HttpService::isStopped()) + { + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Thread actually stopped running", HttpService::isStopped()); + + // release options & headers options.reset(); headers.reset(); - - // release the request object - delete req; - req = NULL; - - // Shut down service - HttpRequest::destroyService(); - } - catch (...) - { - stop_thread(req); + + // release the request object + delete req; + req = NULL; + + // Shut down service + HttpRequest::destroyService(); + } + catch (...) + { + stop_thread(req); options.reset(); headers.reset(); - delete req; - HttpRequest::destroyService(); - throw; - } + delete req; + HttpRequest::destroyService(); + throw; + } } @@ -1749,183 +1749,183 @@ void HttpRequestTestObjectType::test<16>() template <> template <> void HttpRequestTestObjectType::test<17>() { - ScopedCurlInit ready; + ScopedCurlInit ready; + + // Warmup boost::regex to pre-alloc memory for memory size tests + boost::regex warmup("askldjflasdj;f", boost::regex::icase); + boost::regex_match("akl;sjflajfk;ajsk", warmup); - // Warmup boost::regex to pre-alloc memory for memory size tests - boost::regex warmup("askldjflasdj;f", boost::regex::icase); - boost::regex_match("akl;sjflajfk;ajsk", warmup); + std::string url_base(get_base_url()); - std::string url_base(get_base_url()); - - set_test_name("Header generation for HttpRequest POST"); + set_test_name("Header generation for HttpRequest POST"); - // Handler can be stack-allocated *if* there are no dangling - // references to it after completion of this method. - // Create before memory record as the string copy will bump numbers. - TestHandler2 handler(this, "handler"); + // Handler can be stack-allocated *if* there are no dangling + // references to it after completion of this method. + // Create before memory record as the string copy will bump numbers. + TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - mHandlerCalls = 0; - - HttpRequest * req = NULL; - HttpOptions::ptr_t options; - HttpHeaders::ptr_t headers; - BufferArray * ba = NULL; - - try - { + mHandlerCalls = 0; + + HttpRequest * req = NULL; + HttpOptions::ptr_t options; + HttpHeaders::ptr_t headers; + BufferArray * ba = NULL; + + try + { // Get singletons created - HttpRequest::createService(); - - // Start threading early so that thread memory is invariant - // over the test. - HttpRequest::startThread(); + HttpRequest::createService(); + + // Start threading early so that thread memory is invariant + // over the test. + HttpRequest::startThread(); - // create a new ref counted object with an implicit reference - req = new HttpRequest(); + // create a new ref counted object with an implicit reference + req = new HttpRequest(); - // options set + // options set options = HttpOptions::ptr_t(new HttpOptions()); - options->setWantHeaders(true); - - // And a buffer array - const char * msg("It was the best of times, it was the worst of times."); - ba = new BufferArray; - ba->append(msg, strlen(msg)); - - // Issue a default POST - mStatus = HttpStatus(200); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-connection", boost::regex::icase), - boost::regex("keep-alive", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-accept", boost::regex::icase), - boost::regex("\\*/\\*", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-accept-encoding", boost::regex::icase), - boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-keep-alive", boost::regex::icase), - boost::regex("\\d+", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-host", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-content-length", boost::regex::icase), - boost::regex("\\d+", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-content-type", boost::regex::icase), - boost::regex("application/x-www-form-urlencoded", boost::regex::icase))); - - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-cache-control", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-pragma", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-range", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-referer", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-content-encoding", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-expect", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-transfer_encoding", boost::regex::icase), - boost::regex(".*chunked.*", boost::regex::icase))); - HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID, - url_base + "reflect/", - ba, - options, - HttpHeaders::ptr_t(), - handlerp); - ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); - ba->release(); - ba = NULL; - - // Run the notification pump. - int count(0); - int limit(LOOP_COUNT_LONG); - while (count++ < limit && mHandlerCalls < 1) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Request executed in reasonable time", count < limit); - ensure("One handler invocation for request", mHandlerCalls == 1); - - - // Okay, request a shutdown of the servicing thread - mStatus = HttpStatus(); - handler.mHeadersRequired.clear(); - handler.mHeadersDisallowed.clear(); - handle = req->requestStopThread(handlerp); - ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump again - count = 0; - limit = LOOP_COUNT_LONG; - while (count++ < limit && mHandlerCalls < 2) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Second request executed in reasonable time", count < limit); - ensure("Second handler invocation", mHandlerCalls == 2); - - // See that we actually shutdown the thread - count = 0; - limit = LOOP_COUNT_SHORT; - while (count++ < limit && ! HttpService::isStopped()) - { - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Thread actually stopped running", HttpService::isStopped()); - - // release options & headers + options->setWantHeaders(true); + + // And a buffer array + const char * msg("It was the best of times, it was the worst of times."); + ba = new BufferArray; + ba->append(msg, strlen(msg)); + + // Issue a default POST + mStatus = HttpStatus(200); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-connection", boost::regex::icase), + boost::regex("keep-alive", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-accept", boost::regex::icase), + boost::regex("\\*/\\*", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-accept-encoding", boost::regex::icase), + boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-keep-alive", boost::regex::icase), + boost::regex("\\d+", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-host", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-content-length", boost::regex::icase), + boost::regex("\\d+", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-content-type", boost::regex::icase), + boost::regex("application/x-www-form-urlencoded", boost::regex::icase))); + + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-cache-control", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-pragma", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-range", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-referer", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-content-encoding", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-expect", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-transfer_encoding", boost::regex::icase), + boost::regex(".*chunked.*", boost::regex::icase))); + HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID, + url_base + "reflect/", + ba, + options, + HttpHeaders::ptr_t(), + handlerp); + ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); + ba->release(); + ba = NULL; + + // Run the notification pump. + int count(0); + int limit(LOOP_COUNT_LONG); + while (count++ < limit && mHandlerCalls < 1) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Request executed in reasonable time", count < limit); + ensure("One handler invocation for request", mHandlerCalls == 1); + + + // Okay, request a shutdown of the servicing thread + mStatus = HttpStatus(); + handler.mHeadersRequired.clear(); + handler.mHeadersDisallowed.clear(); + handle = req->requestStopThread(handlerp); + ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump again + count = 0; + limit = LOOP_COUNT_LONG; + while (count++ < limit && mHandlerCalls < 2) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Second request executed in reasonable time", count < limit); + ensure("Second handler invocation", mHandlerCalls == 2); + + // See that we actually shutdown the thread + count = 0; + limit = LOOP_COUNT_SHORT; + while (count++ < limit && ! HttpService::isStopped()) + { + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Thread actually stopped running", HttpService::isStopped()); + + // release options & headers options.reset(); headers.reset(); - - // release the request object - delete req; - req = NULL; - - // Shut down service - HttpRequest::destroyService(); - } - catch (...) - { - stop_thread(req); - if (ba) - { - ba->release(); - ba = NULL; - } + + // release the request object + delete req; + req = NULL; + + // Shut down service + HttpRequest::destroyService(); + } + catch (...) + { + stop_thread(req); + if (ba) + { + ba->release(); + ba = NULL; + } options.reset(); headers.reset(); delete req; - HttpRequest::destroyService(); - throw; - } + HttpRequest::destroyService(); + throw; + } } @@ -1933,184 +1933,184 @@ void HttpRequestTestObjectType::test<17>() template <> template <> void HttpRequestTestObjectType::test<18>() { - ScopedCurlInit ready; + ScopedCurlInit ready; - // Warmup boost::regex to pre-alloc memory for memory size tests - boost::regex warmup("askldjflasdj;f", boost::regex::icase); - boost::regex_match("akl;sjflajfk;ajsk", warmup); + // Warmup boost::regex to pre-alloc memory for memory size tests + boost::regex warmup("askldjflasdj;f", boost::regex::icase); + boost::regex_match("akl;sjflajfk;ajsk", warmup); - std::string url_base(get_base_url()); - - set_test_name("Header generation for HttpRequest PUT"); + std::string url_base(get_base_url()); - // Handler can be stack-allocated *if* there are no dangling - // references to it after completion of this method. - // Create before memory record as the string copy will bump numbers. - TestHandler2 handler(this, "handler"); + set_test_name("Header generation for HttpRequest PUT"); + + // Handler can be stack-allocated *if* there are no dangling + // references to it after completion of this method. + // Create before memory record as the string copy will bump numbers. + TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - mHandlerCalls = 0; - - HttpRequest * req = NULL; - HttpOptions::ptr_t options; - HttpHeaders::ptr_t headers; - BufferArray * ba = NULL; - - try - { + mHandlerCalls = 0; + + HttpRequest * req = NULL; + HttpOptions::ptr_t options; + HttpHeaders::ptr_t headers; + BufferArray * ba = NULL; + + try + { // Get singletons created - HttpRequest::createService(); - - // Start threading early so that thread memory is invariant - // over the test. - HttpRequest::startThread(); - - // create a new ref counted object with an implicit reference - req = new HttpRequest(); - - // options set - options = HttpOptions::ptr_t(new HttpOptions()); - options->setWantHeaders(true); - - // And a buffer array - const char * msg("It was the best of times, it was the worst of times."); - ba = new BufferArray; - ba->append(msg, strlen(msg)); - - // Issue a default PUT - mStatus = HttpStatus(200); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-connection", boost::regex::icase), - boost::regex("keep-alive", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-accept", boost::regex::icase), - boost::regex("\\*/\\*", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-accept-encoding", boost::regex::icase), - boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-keep-alive", boost::regex::icase), - boost::regex("\\d+", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-host", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-content-length", boost::regex::icase), - boost::regex("\\d+", boost::regex::icase))); - - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-cache-control", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-pragma", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-range", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-referer", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-content-encoding", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-expect", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), - boost::regex(".*chunked.*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-content-type", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - - HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID, - url_base + "reflect/", - ba, - options, - HttpHeaders::ptr_t(), - handlerp); - ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); - ba->release(); - ba = NULL; - - // Run the notification pump. - int count(0); - int limit(LOOP_COUNT_LONG); - while (count++ < limit && mHandlerCalls < 1) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Request executed in reasonable time", count < limit); - ensure("One handler invocation for request", mHandlerCalls == 1); - - - // Okay, request a shutdown of the servicing thread - mStatus = HttpStatus(); - handler.mHeadersRequired.clear(); - handler.mHeadersDisallowed.clear(); - handle = req->requestStopThread(handlerp); - ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump again - count = 0; - limit = LOOP_COUNT_LONG; - while (count++ < limit && mHandlerCalls < 2) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Second request executed in reasonable time", count < limit); - ensure("Second handler invocation", mHandlerCalls == 2); - - // See that we actually shutdown the thread - count = 0; - limit = LOOP_COUNT_SHORT; - while (count++ < limit && ! HttpService::isStopped()) - { - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Thread actually stopped running", HttpService::isStopped()); - - // release options & headers + HttpRequest::createService(); + + // Start threading early so that thread memory is invariant + // over the test. + HttpRequest::startThread(); + + // create a new ref counted object with an implicit reference + req = new HttpRequest(); + + // options set + options = HttpOptions::ptr_t(new HttpOptions()); + options->setWantHeaders(true); + + // And a buffer array + const char * msg("It was the best of times, it was the worst of times."); + ba = new BufferArray; + ba->append(msg, strlen(msg)); + + // Issue a default PUT + mStatus = HttpStatus(200); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-connection", boost::regex::icase), + boost::regex("keep-alive", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-accept", boost::regex::icase), + boost::regex("\\*/\\*", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-accept-encoding", boost::regex::icase), + boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-keep-alive", boost::regex::icase), + boost::regex("\\d+", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-host", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-content-length", boost::regex::icase), + boost::regex("\\d+", boost::regex::icase))); + + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-cache-control", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-pragma", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-range", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-referer", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-content-encoding", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-expect", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), + boost::regex(".*chunked.*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-content-type", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + + HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID, + url_base + "reflect/", + ba, + options, + HttpHeaders::ptr_t(), + handlerp); + ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); + ba->release(); + ba = NULL; + + // Run the notification pump. + int count(0); + int limit(LOOP_COUNT_LONG); + while (count++ < limit && mHandlerCalls < 1) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Request executed in reasonable time", count < limit); + ensure("One handler invocation for request", mHandlerCalls == 1); + + + // Okay, request a shutdown of the servicing thread + mStatus = HttpStatus(); + handler.mHeadersRequired.clear(); + handler.mHeadersDisallowed.clear(); + handle = req->requestStopThread(handlerp); + ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump again + count = 0; + limit = LOOP_COUNT_LONG; + while (count++ < limit && mHandlerCalls < 2) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Second request executed in reasonable time", count < limit); + ensure("Second handler invocation", mHandlerCalls == 2); + + // See that we actually shutdown the thread + count = 0; + limit = LOOP_COUNT_SHORT; + while (count++ < limit && ! HttpService::isStopped()) + { + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Thread actually stopped running", HttpService::isStopped()); + + // release options & headers options.reset(); headers.reset(); - - // release the request object - delete req; - req = NULL; - - // Shut down service - HttpRequest::destroyService(); - } - catch (...) - { - stop_thread(req); - if (ba) - { - ba->release(); - ba = NULL; - } + + // release the request object + delete req; + req = NULL; + + // Shut down service + HttpRequest::destroyService(); + } + catch (...) + { + stop_thread(req); + if (ba) + { + ba->release(); + ba = NULL; + } options.reset(); headers.reset(); delete req; - HttpRequest::destroyService(); - throw; - } + HttpRequest::destroyService(); + throw; + } } @@ -2118,189 +2118,189 @@ void HttpRequestTestObjectType::test<18>() template <> template <> void HttpRequestTestObjectType::test<19>() { - // It appears that HttpRequest is fully capable of sending duplicate header values in violation of - // this test's expectations. Something needs to budge: is sending duplicate header values desired? - // - // Test server /reflect/ response headers (mirrored from request) - // - // X-Reflect-content-type: text/plain - // X-Reflect-content-type: text/html - // X-Reflect-content-type: application/llsd+xml - // - skip("FIXME: Bad assertions or broken functionality."); - - ScopedCurlInit ready; - - // Warmup boost::regex to pre-alloc memory for memory size tests - boost::regex warmup("askldjflasdj;f", boost::regex::icase); - boost::regex_match("akl;sjflajfk;ajsk", warmup); - - std::string url_base(get_base_url()); - - set_test_name("Header generation for HttpRequest GET with header overrides"); - - // Handler can be stack-allocated *if* there are no dangling - // references to it after completion of this method. - // Create before memory record as the string copy will bump numbers. - TestHandler2 handler(this, "handler"); + // It appears that HttpRequest is fully capable of sending duplicate header values in violation of + // this test's expectations. Something needs to budge: is sending duplicate header values desired? + // + // Test server /reflect/ response headers (mirrored from request) + // + // X-Reflect-content-type: text/plain + // X-Reflect-content-type: text/html + // X-Reflect-content-type: application/llsd+xml + // + skip("FIXME: Bad assertions or broken functionality."); + + ScopedCurlInit ready; + + // Warmup boost::regex to pre-alloc memory for memory size tests + boost::regex warmup("askldjflasdj;f", boost::regex::icase); + boost::regex_match("akl;sjflajfk;ajsk", warmup); + + std::string url_base(get_base_url()); + + set_test_name("Header generation for HttpRequest GET with header overrides"); + + // Handler can be stack-allocated *if* there are no dangling + // references to it after completion of this method. + // Create before memory record as the string copy will bump numbers. + TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - mHandlerCalls = 0; + mHandlerCalls = 0; - HttpRequest * req = NULL; - HttpOptions::ptr_t options; - HttpHeaders::ptr_t headers; + HttpRequest * req = NULL; + HttpOptions::ptr_t options; + HttpHeaders::ptr_t headers; - try - { + try + { // Get singletons created - HttpRequest::createService(); - - // Start threading early so that thread memory is invariant - // over the test. - HttpRequest::startThread(); + HttpRequest::createService(); + + // Start threading early so that thread memory is invariant + // over the test. + HttpRequest::startThread(); - // create a new ref counted object with an implicit reference - req = new HttpRequest(); + // create a new ref counted object with an implicit reference + req = new HttpRequest(); - // options set + // options set options = HttpOptions::ptr_t(new HttpOptions()); - options->setWantHeaders(true); - - // headers - headers = HttpHeaders::ptr_t(new HttpHeaders); - headers->append("Keep-Alive", "120"); - headers->append("Accept-encoding", "deflate"); - headers->append("Accept", "text/plain"); - - // Issue a GET with modified headers - mStatus = HttpStatus(200); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-connection", boost::regex::icase), - boost::regex("keep-alive", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-accept", boost::regex::icase), - boost::regex("text/plain", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-accept-encoding", boost::regex::icase), - boost::regex("deflate", boost::regex::icase))); // close enough - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-keep-alive", boost::regex::icase), - boost::regex("120", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-host", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-accept-encoding", boost::regex::icase), - boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-keep-alive", boost::regex::icase), - boost::regex("300", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-accept", boost::regex::icase), - boost::regex("\\*/\\*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-cache-control", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-pragma", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-range", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-referer", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-content-type", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-content-encoding", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID, - url_base + "reflect/", - options, - headers, - handlerp); - ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump. - int count(0); - int limit(LOOP_COUNT_LONG); - while (count++ < limit && mHandlerCalls < 1) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Request executed in reasonable time", count < limit); - ensure("One handler invocation for request", mHandlerCalls == 1); - - // Okay, request a shutdown of the servicing thread - mStatus = HttpStatus(); - handler.mHeadersRequired.clear(); - handler.mHeadersDisallowed.clear(); - handle = req->requestStopThread(handlerp); - ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump again - count = 0; - limit = LOOP_COUNT_LONG; - while (count++ < limit && mHandlerCalls < 2) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Second request executed in reasonable time", count < limit); - ensure("Second handler invocation", mHandlerCalls == 2); - - // See that we actually shutdown the thread - count = 0; - limit = LOOP_COUNT_SHORT; - while (count++ < limit && ! HttpService::isStopped()) - { - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Thread actually stopped running", HttpService::isStopped()); - - // release options & headers + options->setWantHeaders(true); + + // headers + headers = HttpHeaders::ptr_t(new HttpHeaders); + headers->append("Keep-Alive", "120"); + headers->append("Accept-encoding", "deflate"); + headers->append("Accept", "text/plain"); + + // Issue a GET with modified headers + mStatus = HttpStatus(200); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-connection", boost::regex::icase), + boost::regex("keep-alive", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-accept", boost::regex::icase), + boost::regex("text/plain", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-accept-encoding", boost::regex::icase), + boost::regex("deflate", boost::regex::icase))); // close enough + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-keep-alive", boost::regex::icase), + boost::regex("120", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-host", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-accept-encoding", boost::regex::icase), + boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-keep-alive", boost::regex::icase), + boost::regex("300", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-accept", boost::regex::icase), + boost::regex("\\*/\\*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-cache-control", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-pragma", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-range", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-referer", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-content-type", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-content-encoding", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID, + url_base + "reflect/", + options, + headers, + handlerp); + ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump. + int count(0); + int limit(LOOP_COUNT_LONG); + while (count++ < limit && mHandlerCalls < 1) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Request executed in reasonable time", count < limit); + ensure("One handler invocation for request", mHandlerCalls == 1); + + // Okay, request a shutdown of the servicing thread + mStatus = HttpStatus(); + handler.mHeadersRequired.clear(); + handler.mHeadersDisallowed.clear(); + handle = req->requestStopThread(handlerp); + ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump again + count = 0; + limit = LOOP_COUNT_LONG; + while (count++ < limit && mHandlerCalls < 2) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Second request executed in reasonable time", count < limit); + ensure("Second handler invocation", mHandlerCalls == 2); + + // See that we actually shutdown the thread + count = 0; + limit = LOOP_COUNT_SHORT; + while (count++ < limit && ! HttpService::isStopped()) + { + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Thread actually stopped running", HttpService::isStopped()); + + // release options & headers options.reset(); headers.reset(); - - // release the request object - delete req; - req = NULL; - - // Shut down service - HttpRequest::destroyService(); - } - catch (...) - { - stop_thread(req); + + // release the request object + delete req; + req = NULL; + + // Shut down service + HttpRequest::destroyService(); + } + catch (...) + { + stop_thread(req); options.reset(); headers.reset(); - delete req; - HttpRequest::destroyService(); - throw; - } + delete req; + HttpRequest::destroyService(); + throw; + } } @@ -2308,214 +2308,214 @@ void HttpRequestTestObjectType::test<19>() template <> template <> void HttpRequestTestObjectType::test<20>() { - // It appears that HttpRequest is fully capable of sending duplicate header values in violation of - // this test's expectations. Something needs to budge: is sending duplicate header values desired? - // - // Test server /reflect/ response headers (mirrored from request) - // - // X-Reflect-content-type: text/plain - // X-Reflect-content-type: text/html - // X-Reflect-content-type: application/llsd+xml - // - skip("FIXME: Bad assertions or broken functionality."); - - ScopedCurlInit ready; - - // Warmup boost::regex to pre-alloc memory for memory size tests - boost::regex warmup("askldjflasdj;f", boost::regex::icase); - boost::regex_match("akl;sjflajfk;ajsk", warmup); - - std::string url_base(get_base_url()); - - set_test_name("Header generation for HttpRequest POST with header overrides"); - - // Handler can be stack-allocated *if* there are no dangling - // references to it after completion of this method. - // Create before memory record as the string copy will bump numbers. - TestHandler2 handler(this, "handler"); + // It appears that HttpRequest is fully capable of sending duplicate header values in violation of + // this test's expectations. Something needs to budge: is sending duplicate header values desired? + // + // Test server /reflect/ response headers (mirrored from request) + // + // X-Reflect-content-type: text/plain + // X-Reflect-content-type: text/html + // X-Reflect-content-type: application/llsd+xml + // + skip("FIXME: Bad assertions or broken functionality."); + + ScopedCurlInit ready; + + // Warmup boost::regex to pre-alloc memory for memory size tests + boost::regex warmup("askldjflasdj;f", boost::regex::icase); + boost::regex_match("akl;sjflajfk;ajsk", warmup); + + std::string url_base(get_base_url()); + + set_test_name("Header generation for HttpRequest POST with header overrides"); + + // Handler can be stack-allocated *if* there are no dangling + // references to it after completion of this method. + // Create before memory record as the string copy will bump numbers. + TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - mHandlerCalls = 0; + mHandlerCalls = 0; - HttpRequest * req = NULL; - HttpOptions::ptr_t options; - HttpHeaders::ptr_t headers; - BufferArray * ba = NULL; - - try - { + HttpRequest * req = NULL; + HttpOptions::ptr_t options; + HttpHeaders::ptr_t headers; + BufferArray * ba = NULL; + + try + { // Get singletons created - HttpRequest::createService(); - - // Start threading early so that thread memory is invariant - // over the test. - HttpRequest::startThread(); + HttpRequest::createService(); - // create a new ref counted object with an implicit reference - req = new HttpRequest(); + // Start threading early so that thread memory is invariant + // over the test. + HttpRequest::startThread(); - // options set + // create a new ref counted object with an implicit reference + req = new HttpRequest(); + + // options set options = HttpOptions::ptr_t(new HttpOptions()); - options->setWantHeaders(true); - - // headers - headers = HttpHeaders::ptr_t(new HttpHeaders()); - headers->append("keep-Alive", "120"); - headers->append("Accept", "text/html"); - headers->append("content-type", "application/llsd+xml"); - headers->append("cache-control", "no-store"); - - // And a buffer array - const char * msg("<xml><llsd><string>It was the best of times, it was the worst of times.</string></llsd></xml>"); - ba = new BufferArray; - ba->append(msg, strlen(msg)); - - // Issue a default POST - mStatus = HttpStatus(200); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-connection", boost::regex::icase), - boost::regex("keep-alive", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-accept", boost::regex::icase), - boost::regex("text/html", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-accept-encoding", boost::regex::icase), - boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-keep-alive", boost::regex::icase), - boost::regex("120", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-host", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-content-length", boost::regex::icase), - boost::regex("\\d+", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-content-type", boost::regex::icase), - boost::regex("application/llsd\\+xml", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-cache-control", boost::regex::icase), - boost::regex("no-store", boost::regex::icase))); - - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-content-type", boost::regex::icase), - boost::regex("application/x-www-form-urlencoded", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-accept", boost::regex::icase), - boost::regex("\\*/\\*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-keep-alive", boost::regex::icase), - boost::regex("300", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-pragma", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-range", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-referer", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-content-encoding", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-expect", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - - HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID, - url_base + "reflect/", - ba, - options, - headers, - handlerp); - ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); - ba->release(); - ba = NULL; - - // Run the notification pump. - int count(0); - int limit(LOOP_COUNT_LONG); - while (count++ < limit && mHandlerCalls < 1) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Request executed in reasonable time", count < limit); - ensure("One handler invocation for request", mHandlerCalls == 1); - - - // Okay, request a shutdown of the servicing thread - mStatus = HttpStatus(); - handler.mHeadersRequired.clear(); - handler.mHeadersDisallowed.clear(); - handle = req->requestStopThread(handlerp); - ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump again - count = 0; - limit = LOOP_COUNT_LONG; - while (count++ < limit && mHandlerCalls < 2) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Second request executed in reasonable time", count < limit); - ensure("Second handler invocation", mHandlerCalls == 2); - - // See that we actually shutdown the thread - count = 0; - limit = LOOP_COUNT_SHORT; - while (count++ < limit && ! HttpService::isStopped()) - { - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Thread actually stopped running", HttpService::isStopped()); - - // release options & headers + options->setWantHeaders(true); + + // headers + headers = HttpHeaders::ptr_t(new HttpHeaders()); + headers->append("keep-Alive", "120"); + headers->append("Accept", "text/html"); + headers->append("content-type", "application/llsd+xml"); + headers->append("cache-control", "no-store"); + + // And a buffer array + const char * msg("<xml><llsd><string>It was the best of times, it was the worst of times.</string></llsd></xml>"); + ba = new BufferArray; + ba->append(msg, strlen(msg)); + + // Issue a default POST + mStatus = HttpStatus(200); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-connection", boost::regex::icase), + boost::regex("keep-alive", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-accept", boost::regex::icase), + boost::regex("text/html", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-accept-encoding", boost::regex::icase), + boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-keep-alive", boost::regex::icase), + boost::regex("120", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-host", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-content-length", boost::regex::icase), + boost::regex("\\d+", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-content-type", boost::regex::icase), + boost::regex("application/llsd\\+xml", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-cache-control", boost::regex::icase), + boost::regex("no-store", boost::regex::icase))); + + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-content-type", boost::regex::icase), + boost::regex("application/x-www-form-urlencoded", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-accept", boost::regex::icase), + boost::regex("\\*/\\*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-keep-alive", boost::regex::icase), + boost::regex("300", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-pragma", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-range", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-referer", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-content-encoding", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-expect", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + + HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID, + url_base + "reflect/", + ba, + options, + headers, + handlerp); + ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); + ba->release(); + ba = NULL; + + // Run the notification pump. + int count(0); + int limit(LOOP_COUNT_LONG); + while (count++ < limit && mHandlerCalls < 1) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Request executed in reasonable time", count < limit); + ensure("One handler invocation for request", mHandlerCalls == 1); + + + // Okay, request a shutdown of the servicing thread + mStatus = HttpStatus(); + handler.mHeadersRequired.clear(); + handler.mHeadersDisallowed.clear(); + handle = req->requestStopThread(handlerp); + ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump again + count = 0; + limit = LOOP_COUNT_LONG; + while (count++ < limit && mHandlerCalls < 2) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Second request executed in reasonable time", count < limit); + ensure("Second handler invocation", mHandlerCalls == 2); + + // See that we actually shutdown the thread + count = 0; + limit = LOOP_COUNT_SHORT; + while (count++ < limit && ! HttpService::isStopped()) + { + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Thread actually stopped running", HttpService::isStopped()); + + // release options & headers options.reset(); headers.reset(); - - // release the request object - delete req; - req = NULL; - - // Shut down service - HttpRequest::destroyService(); - } - catch (...) - { - stop_thread(req); - if (ba) - { - ba->release(); - ba = NULL; - } + + // release the request object + delete req; + req = NULL; + + // Shut down service + HttpRequest::destroyService(); + } + catch (...) + { + stop_thread(req); + if (ba) + { + ba->release(); + ba = NULL; + } options.reset(); headers.reset(); - delete req; - HttpRequest::destroyService(); - throw; - } + delete req; + HttpRequest::destroyService(); + throw; + } } @@ -2523,516 +2523,516 @@ void HttpRequestTestObjectType::test<20>() template <> template <> void HttpRequestTestObjectType::test<21>() { - // It appears that HttpRequest is fully capable of sending duplicate header values in violation of - // this test's expectations. Something needs to budge: is sending duplicate header values desired? - // - // Test server /reflect/ response headers (mirrored from request) - // - // X-Reflect-content-type: text/plain - // X-Reflect-content-type: text/html - // X-Reflect-content-type: application/llsd+xml - // - skip("FIXME: Bad assertions or broken functionality."); - - ScopedCurlInit ready; - - // Warmup boost::regex to pre-alloc memory for memory size tests - boost::regex warmup("askldjflasdj;f", boost::regex::icase); - boost::regex_match("akl;sjflajfk;ajsk", warmup); - - std::string url_base(get_base_url()); - - set_test_name("Header generation for HttpRequest PUT with header overrides"); - - // Handler can be stack-allocated *if* there are no dangling - // references to it after completion of this method. - // Create before memory record as the string copy will bump numbers. - TestHandler2 handler(this, "handler"); + // It appears that HttpRequest is fully capable of sending duplicate header values in violation of + // this test's expectations. Something needs to budge: is sending duplicate header values desired? + // + // Test server /reflect/ response headers (mirrored from request) + // + // X-Reflect-content-type: text/plain + // X-Reflect-content-type: text/html + // X-Reflect-content-type: application/llsd+xml + // + skip("FIXME: Bad assertions or broken functionality."); + + ScopedCurlInit ready; + + // Warmup boost::regex to pre-alloc memory for memory size tests + boost::regex warmup("askldjflasdj;f", boost::regex::icase); + boost::regex_match("akl;sjflajfk;ajsk", warmup); + + std::string url_base(get_base_url()); + + set_test_name("Header generation for HttpRequest PUT with header overrides"); + + // Handler can be stack-allocated *if* there are no dangling + // references to it after completion of this method. + // Create before memory record as the string copy will bump numbers. + TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - mHandlerCalls = 0; - - HttpRequest * req = NULL; - HttpOptions::ptr_t options; - HttpHeaders::ptr_t headers; - BufferArray * ba = NULL; - - try - { + mHandlerCalls = 0; + + HttpRequest * req = NULL; + HttpOptions::ptr_t options; + HttpHeaders::ptr_t headers; + BufferArray * ba = NULL; + + try + { // Get singletons created - HttpRequest::createService(); - - // Start threading early so that thread memory is invariant - // over the test. - HttpRequest::startThread(); + HttpRequest::createService(); - // create a new ref counted object with an implicit reference - req = new HttpRequest(); + // Start threading early so that thread memory is invariant + // over the test. + HttpRequest::startThread(); - // options set + // create a new ref counted object with an implicit reference + req = new HttpRequest(); + + // options set options = HttpOptions::ptr_t(new HttpOptions()); - options->setWantHeaders(true); - - // headers - 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"); - - // And a buffer array - const char * msg("<xml><llsd><string>It was the best of times, it was the worst of times.</string></llsd></xml>"); - ba = new BufferArray; - ba->append(msg, strlen(msg)); - - // Issue a default PUT - mStatus = HttpStatus(200); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-connection", boost::regex::icase), - boost::regex("keep-alive", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-accept", boost::regex::icase), - boost::regex("\\*/\\*", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-accept-encoding", boost::regex::icase), - boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-keep-alive", boost::regex::icase), - boost::regex("\\d+", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-host", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-content-length", boost::regex::icase), - boost::regex("\\d+", boost::regex::icase))); - handler.mHeadersRequired.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-content-type", boost::regex::icase), - boost::regex("application/llsd\\+xml", boost::regex::icase))); - - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-cache-control", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-pragma", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-range", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-referer", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-content-encoding", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-expect", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), - boost::regex(".*", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-content-type", boost::regex::icase), - boost::regex("text/plain", boost::regex::icase))); - handler.mHeadersDisallowed.push_back( - regex_container_t::value_type( - boost::regex("X-Reflect-content-type", boost::regex::icase), - boost::regex("text/html", boost::regex::icase))); - HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID, - url_base + "reflect/", - ba, - options, - headers, - handlerp); - ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); - ba->release(); - ba = NULL; - - // Run the notification pump. - int count(0); - int limit(LOOP_COUNT_LONG); - while (count++ < limit && mHandlerCalls < 1) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Request executed in reasonable time", count < limit); - ensure("One handler invocation for request", mHandlerCalls == 1); - - - // Okay, request a shutdown of the servicing thread - mStatus = HttpStatus(); - handler.mHeadersRequired.clear(); - handler.mHeadersDisallowed.clear(); - handle = req->requestStopThread(handlerp); - ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump again - count = 0; - limit = LOOP_COUNT_LONG; - while (count++ < limit && mHandlerCalls < 2) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Second request executed in reasonable time", count < limit); - ensure("Second handler invocation", mHandlerCalls == 2); - - // See that we actually shutdown the thread - count = 0; - limit = LOOP_COUNT_SHORT; - while (count++ < limit && ! HttpService::isStopped()) - { - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Thread actually stopped running", HttpService::isStopped()); - - // release options & headers + options->setWantHeaders(true); + + // headers + 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"); + + // And a buffer array + const char * msg("<xml><llsd><string>It was the best of times, it was the worst of times.</string></llsd></xml>"); + ba = new BufferArray; + ba->append(msg, strlen(msg)); + + // Issue a default PUT + mStatus = HttpStatus(200); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-connection", boost::regex::icase), + boost::regex("keep-alive", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-accept", boost::regex::icase), + boost::regex("\\*/\\*", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-accept-encoding", boost::regex::icase), + boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-keep-alive", boost::regex::icase), + boost::regex("\\d+", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-host", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-content-length", boost::regex::icase), + boost::regex("\\d+", boost::regex::icase))); + handler.mHeadersRequired.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-content-type", boost::regex::icase), + boost::regex("application/llsd\\+xml", boost::regex::icase))); + + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-cache-control", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-pragma", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-range", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-referer", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-content-encoding", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-expect", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), + boost::regex(".*", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-content-type", boost::regex::icase), + boost::regex("text/plain", boost::regex::icase))); + handler.mHeadersDisallowed.push_back( + regex_container_t::value_type( + boost::regex("X-Reflect-content-type", boost::regex::icase), + boost::regex("text/html", boost::regex::icase))); + HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID, + url_base + "reflect/", + ba, + options, + headers, + handlerp); + ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); + ba->release(); + ba = NULL; + + // Run the notification pump. + int count(0); + int limit(LOOP_COUNT_LONG); + while (count++ < limit && mHandlerCalls < 1) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Request executed in reasonable time", count < limit); + ensure("One handler invocation for request", mHandlerCalls == 1); + + + // Okay, request a shutdown of the servicing thread + mStatus = HttpStatus(); + handler.mHeadersRequired.clear(); + handler.mHeadersDisallowed.clear(); + handle = req->requestStopThread(handlerp); + ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump again + count = 0; + limit = LOOP_COUNT_LONG; + while (count++ < limit && mHandlerCalls < 2) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Second request executed in reasonable time", count < limit); + ensure("Second handler invocation", mHandlerCalls == 2); + + // See that we actually shutdown the thread + count = 0; + limit = LOOP_COUNT_SHORT; + while (count++ < limit && ! HttpService::isStopped()) + { + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Thread actually stopped running", HttpService::isStopped()); + + // release options & headers options.reset(); headers.reset(); - - // release the request object - delete req; - req = NULL; - - // Shut down service - HttpRequest::destroyService(); - } - catch (...) - { - stop_thread(req); - if (ba) - { - ba->release(); - ba = NULL; - } + + // release the request object + delete req; + req = NULL; + + // Shut down service + HttpRequest::destroyService(); + } + catch (...) + { + stop_thread(req); + if (ba) + { + ba->release(); + ba = NULL; + } options.reset(); headers.reset(); - delete req; - HttpRequest::destroyService(); - throw; - } + delete req; + HttpRequest::destroyService(); + throw; + } } // BUG-2295 Tests - Content-Range header received but no body template <> template <> void HttpRequestTestObjectType::test<22>() { - ScopedCurlInit ready; + ScopedCurlInit ready; + + std::string url_base(get_base_url()); + // std::cerr << "Base: " << url_base << std::endl; - std::string url_base(get_base_url()); - // std::cerr << "Base: " << url_base << std::endl; - - set_test_name("BUG-2295"); + set_test_name("BUG-2295"); #if LL_WINDOWS && ADDRESS_SIZE == 64 - // teamcity win64 builds freeze on this test, if you figure out the cause, please fix it - if (getenv("TEAMCITY_PROJECT_NAME")) - { - skip("BUG-2295 - partial load on W64 causes freeze"); - } + // teamcity win64 builds freeze on this test, if you figure out the cause, please fix it + if (getenv("TEAMCITY_PROJECT_NAME")) + { + skip("BUG-2295 - partial load on W64 causes freeze"); + } #endif - // Handler can be stack-allocated *if* there are no dangling - // references to it after completion of this method. - // Create before memory record as the string copy will bump numbers. - TestHandler2 handler(this, "handler"); + // Handler can be stack-allocated *if* there are no dangling + // references to it after completion of this method. + // Create before memory record as the string copy will bump numbers. + TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - mHandlerCalls = 0; + mHandlerCalls = 0; - HttpOptions::ptr_t options; - HttpRequest * req = NULL; + HttpOptions::ptr_t options; + HttpRequest * req = NULL; - try - { + try + { // options set options = HttpOptions::ptr_t(new HttpOptions()); - options->setRetries(1); // Partial_File is retryable and can timeout in here - options->setDNSCacheTimeout(30); - - // Get singletons created - HttpRequest::createService(); - - // Start threading early so that thread memory is invariant - // over the test. - HttpRequest::startThread(); - - // create a new ref counted object with an implicit reference - req = new HttpRequest(); - - // ====================================== - // Issue bug2295 GETs that will get a 206 - // ====================================== - mStatus = HttpStatus(206); - static const int test_count(3); - for (int i(0); i < test_count; ++i) - { - char buffer[128]; - sprintf(buffer, "/bug2295/%d/", i); - HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, - url_base + buffer, - 0, - 25, - options, + options->setRetries(1); // Partial_File is retryable and can timeout in here + options->setDNSCacheTimeout(30); + + // Get singletons created + HttpRequest::createService(); + + // Start threading early so that thread memory is invariant + // over the test. + HttpRequest::startThread(); + + // create a new ref counted object with an implicit reference + req = new HttpRequest(); + + // ====================================== + // Issue bug2295 GETs that will get a 206 + // ====================================== + mStatus = HttpStatus(206); + static const int test_count(3); + for (int i(0); i < test_count; ++i) + { + char buffer[128]; + sprintf(buffer, "/bug2295/%d/", i); + HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, + url_base + buffer, + 0, + 25, + options, + HttpHeaders::ptr_t(), + handlerp); + ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); + } + + // Run the notification pump. + int count(0); + int limit(LOOP_COUNT_LONG); + while (count++ < limit && mHandlerCalls < test_count) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Request executed in reasonable time - ms1", count < limit); + ensure("One handler invocation for each request - ms1", mHandlerCalls == test_count); + + // ====================================== + // Issue bug2295 GETs that will get a libcurl 18 (PARTIAL_FILE) + // ====================================== + mHandlerCalls = 0; + mStatus = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_PARTIAL_FILE); + static const int test2_count(1); + for (int i(0); i < test2_count; ++i) + { + char buffer[128]; + sprintf(buffer, "/bug2295/00000012/%d/", i); + HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, + url_base + buffer, + 0, + 25, + options, HttpHeaders::ptr_t(), handlerp); - ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); - } - - // Run the notification pump. - int count(0); - int limit(LOOP_COUNT_LONG); - while (count++ < limit && mHandlerCalls < test_count) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Request executed in reasonable time - ms1", count < limit); - ensure("One handler invocation for each request - ms1", mHandlerCalls == test_count); - - // ====================================== - // Issue bug2295 GETs that will get a libcurl 18 (PARTIAL_FILE) - // ====================================== - mHandlerCalls = 0; - mStatus = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_PARTIAL_FILE); - static const int test2_count(1); - for (int i(0); i < test2_count; ++i) - { - char buffer[128]; - sprintf(buffer, "/bug2295/00000012/%d/", i); - HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, - url_base + buffer, - 0, - 25, - options, - HttpHeaders::ptr_t(), - handlerp); - ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); - } - - // Run the notification pump. - count = 0; - limit = LOOP_COUNT_LONG; - while (count++ < limit && mHandlerCalls < test2_count) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Request executed in reasonable time - ms2", count < limit); - ensure("One handler invocation for each request - ms2", mHandlerCalls == test2_count); - - // ====================================== - // Issue bug2295 GETs that will get an llcorehttp HE_INV_CONTENT_RANGE_HDR status - // ====================================== - mHandlerCalls = 0; - mStatus = HttpStatus(HttpStatus::LLCORE, HE_INV_CONTENT_RANGE_HDR); - static const int test3_count(1); - for (int i(0); i < test3_count; ++i) - { - char buffer[128]; - sprintf(buffer, "/bug2295/inv_cont_range/%d/", i); - HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, - url_base + buffer, - 0, - 25, - options, + ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); + } + + // Run the notification pump. + count = 0; + limit = LOOP_COUNT_LONG; + while (count++ < limit && mHandlerCalls < test2_count) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Request executed in reasonable time - ms2", count < limit); + ensure("One handler invocation for each request - ms2", mHandlerCalls == test2_count); + + // ====================================== + // Issue bug2295 GETs that will get an llcorehttp HE_INV_CONTENT_RANGE_HDR status + // ====================================== + mHandlerCalls = 0; + mStatus = HttpStatus(HttpStatus::LLCORE, HE_INV_CONTENT_RANGE_HDR); + static const int test3_count(1); + for (int i(0); i < test3_count; ++i) + { + char buffer[128]; + sprintf(buffer, "/bug2295/inv_cont_range/%d/", i); + HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, + url_base + buffer, + 0, + 25, + options, HttpHeaders::ptr_t(), handlerp); - ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); - } - - // Run the notification pump. - count = 0; - limit = LOOP_COUNT_LONG; - while (count++ < limit && mHandlerCalls < test3_count) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Request executed in reasonable time - ms3", count < limit); - ensure("One handler invocation for each request - ms3", mHandlerCalls == test3_count); - - // ====================================== - // Okay, request a shutdown of the servicing thread - // ====================================== - mStatus = HttpStatus(); - mHandlerCalls = 0; - HttpHandle handle = req->requestStopThread(handlerp); - ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump again - count = 0; - limit = LOOP_COUNT_LONG; - while (count++ < limit && mHandlerCalls < 1) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Shutdown request executed in reasonable time", count < limit); - ensure("Shutdown handler invocation", mHandlerCalls == 1); - - // See that we actually shutdown the thread - count = 0; - limit = LOOP_COUNT_SHORT; - while (count++ < limit && ! HttpService::isStopped()) - { - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Thread actually stopped running", HttpService::isStopped()); - - // release options + ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID); + } + + // Run the notification pump. + count = 0; + limit = LOOP_COUNT_LONG; + while (count++ < limit && mHandlerCalls < test3_count) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Request executed in reasonable time - ms3", count < limit); + ensure("One handler invocation for each request - ms3", mHandlerCalls == test3_count); + + // ====================================== + // Okay, request a shutdown of the servicing thread + // ====================================== + mStatus = HttpStatus(); + mHandlerCalls = 0; + HttpHandle handle = req->requestStopThread(handlerp); + ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump again + count = 0; + limit = LOOP_COUNT_LONG; + while (count++ < limit && mHandlerCalls < 1) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Shutdown request executed in reasonable time", count < limit); + ensure("Shutdown handler invocation", mHandlerCalls == 1); + + // See that we actually shutdown the thread + count = 0; + limit = LOOP_COUNT_SHORT; + while (count++ < limit && ! HttpService::isStopped()) + { + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Thread actually stopped running", HttpService::isStopped()); + + // release options options.reset(); - - // release the request object - delete req; - req = NULL; - - // Shut down service - HttpRequest::destroyService(); - } - catch (...) - { - stop_thread(req); - delete req; - HttpRequest::destroyService(); - throw; - } + + // release the request object + delete req; + req = NULL; + + // Shut down service + HttpRequest::destroyService(); + } + catch (...) + { + stop_thread(req); + delete req; + HttpRequest::destroyService(); + throw; + } } template <> template <> void HttpRequestTestObjectType::test<23>() { - ScopedCurlInit ready; + ScopedCurlInit ready; - set_test_name("HttpRequest GET 503s with 'Retry-After'"); + set_test_name("HttpRequest GET 503s with 'Retry-After'"); #if LL_WINDOWS && ADDRESS_SIZE == 64 - // teamcity win64 builds freeze on this test, if you figure out the cause, please fix it - if (getenv("TEAMCITY_PROJECT_NAME")) - { - skip("llcorehttp 503-with-retry test hangs on Windows 64"); - } + // teamcity win64 builds freeze on this test, if you figure out the cause, please fix it + if (getenv("TEAMCITY_PROJECT_NAME")) + { + skip("llcorehttp 503-with-retry test hangs on Windows 64"); + } #endif - // This tests mainly that the code doesn't fall over if - // various well- and mis-formed Retry-After headers are - // sent along with the response. Direct inspection of - // the parsing result isn't supported. - - // Handler can be stack-allocated *if* there are no dangling - // references to it after completion of this method. - // Create before memory record as the string copy will bump numbers. - TestHandler2 handler(this, "handler"); + // This tests mainly that the code doesn't fall over if + // various well- and mis-formed Retry-After headers are + // sent along with the response. Direct inspection of + // the parsing result isn't supported. + + // Handler can be stack-allocated *if* there are no dangling + // references to it after completion of this method. + // Create before memory record as the string copy will bump numbers. + TestHandler2 handler(this, "handler"); LLCore::HttpHandler::ptr_t handlerp(&handler, NoOpDeletor); - std::string url_base(get_base_url() + "/503/"); // path to 503 generators - mHandlerCalls = 0; - - HttpRequest * req = NULL; - HttpOptions::ptr_t opts; - - try - { + std::string url_base(get_base_url() + "/503/"); // path to 503 generators + mHandlerCalls = 0; + + HttpRequest * req = NULL; + HttpOptions::ptr_t opts; + + try + { // Get singletons created - HttpRequest::createService(); - - // Start threading early so that thread memory is invariant - // over the test. - HttpRequest::startThread(); + HttpRequest::createService(); + + // Start threading early so that thread memory is invariant + // over the test. + HttpRequest::startThread(); - // create a new ref counted object with an implicit reference - req = new HttpRequest(); + // create a new ref counted object with an implicit reference + req = new HttpRequest(); opts = HttpOptions::ptr_t(new HttpOptions()); - opts->setRetries(1); // Retry once only - opts->setUseRetryAfter(true); // Try to parse the retry-after header - - // Issue a GET that 503s with valid retry-after - mStatus = HttpStatus(503); - int url_limit(6); - for (int i(0); i < url_limit; ++i) - { - std::ostringstream url; - url << url_base << i << "/"; - HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, - url.str(), - 0, - 0, - opts, + opts->setRetries(1); // Retry once only + opts->setUseRetryAfter(true); // Try to parse the retry-after header + + // Issue a GET that 503s with valid retry-after + mStatus = HttpStatus(503); + int url_limit(6); + for (int i(0); i < url_limit; ++i) + { + std::ostringstream url; + url << url_base << i << "/"; + HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, + url.str(), + 0, + 0, + opts, HttpHeaders::ptr_t(), handlerp); - std::ostringstream testtag; - testtag << "Valid handle returned for 503 request #" << i; - ensure(testtag.str(), handle != LLCORE_HTTP_HANDLE_INVALID); - } - - - // Run the notification pump. - int count(0); - int limit(LOOP_COUNT_LONG); - while (count++ < limit && mHandlerCalls < url_limit) - { - req->update(0); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Request executed in reasonable time", count < limit); - ensure("One handler invocation for request", mHandlerCalls == url_limit); - - // Okay, request a shutdown of the servicing thread - mStatus = HttpStatus(); - mHandlerCalls = 0; - HttpHandle handle = req->requestStopThread(handlerp); - ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); - - // Run the notification pump again - count = 0; - limit = LOOP_COUNT_LONG; - while (count++ < limit && mHandlerCalls < 1) - { - req->update(1000000); - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Second request executed in reasonable time", count < limit); - ensure("Second handler invocation", mHandlerCalls == 1); - - // See that we actually shutdown the thread - count = 0; - limit = LOOP_COUNT_SHORT; - while (count++ < limit && ! HttpService::isStopped()) - { - usleep(LOOP_SLEEP_INTERVAL); - } - ensure("Thread actually stopped running", HttpService::isStopped()); - - // release options + std::ostringstream testtag; + testtag << "Valid handle returned for 503 request #" << i; + ensure(testtag.str(), handle != LLCORE_HTTP_HANDLE_INVALID); + } + + + // Run the notification pump. + int count(0); + int limit(LOOP_COUNT_LONG); + while (count++ < limit && mHandlerCalls < url_limit) + { + req->update(0); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Request executed in reasonable time", count < limit); + ensure("One handler invocation for request", mHandlerCalls == url_limit); + + // Okay, request a shutdown of the servicing thread + mStatus = HttpStatus(); + mHandlerCalls = 0; + HttpHandle handle = req->requestStopThread(handlerp); + ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); + + // Run the notification pump again + count = 0; + limit = LOOP_COUNT_LONG; + while (count++ < limit && mHandlerCalls < 1) + { + req->update(1000000); + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Second request executed in reasonable time", count < limit); + ensure("Second handler invocation", mHandlerCalls == 1); + + // See that we actually shutdown the thread + count = 0; + limit = LOOP_COUNT_SHORT; + while (count++ < limit && ! HttpService::isStopped()) + { + usleep(LOOP_SLEEP_INTERVAL); + } + ensure("Thread actually stopped running", HttpService::isStopped()); + + // release options opts.reset(); - - // release the request object - delete req; - req = NULL; - - // Shut down service - HttpRequest::destroyService(); - } - catch (...) - { - stop_thread(req); + + // release the request object + delete req; + req = NULL; + + // Shut down service + HttpRequest::destroyService(); + } + catch (...) + { + stop_thread(req); opts.reset(); - delete req; - HttpRequest::destroyService(); - throw; - } + delete req; + HttpRequest::destroyService(); + throw; + } } @@ -3045,7 +3045,7 @@ namespace void usleep(unsigned long usec) { - Sleep((DWORD) (usec / 1000UL)); + Sleep((DWORD) (usec / 1000UL)); } #endif diff --git a/indra/llcorehttp/tests/test_httprequestqueue.hpp b/indra/llcorehttp/tests/test_httprequestqueue.hpp index dba9e0b250..c6fa1b7534 100644 --- a/indra/llcorehttp/tests/test_httprequestqueue.hpp +++ b/indra/llcorehttp/tests/test_httprequestqueue.hpp @@ -1,4 +1,4 @@ -/** +/** * @file test_httprequestqueue.hpp * @brief unit tests for the LLCore::HttpRequestQueue class * @@ -42,8 +42,8 @@ namespace tut struct HttpRequestqueueTestData { - // the test objects inherit from this so the member functions and variables - // can be referenced directly inside of the test functions. + // the test objects inherit from this so the member functions and variables + // can be referenced directly inside of the test functions. }; typedef test_group<HttpRequestqueueTestData> HttpRequestqueueTestGroupType; @@ -53,102 +53,102 @@ HttpRequestqueueTestGroupType HttpRequestqueueTestGroup("HttpRequestqueue Tests" template <> template <> void HttpRequestqueueTestObjectType::test<1>() { - set_test_name("HttpRequestQueue construction"); + set_test_name("HttpRequestQueue construction"); - // create a new ref counted object with an implicit reference - HttpRequestQueue::init(); - - ensure("One ref on construction of HttpRequestQueue", HttpRequestQueue::instanceOf()->getRefCount() == 1); + // create a new ref counted object with an implicit reference + HttpRequestQueue::init(); - // release the implicit reference, causing the object to be released - HttpRequestQueue::term(); + ensure("One ref on construction of HttpRequestQueue", HttpRequestQueue::instanceOf()->getRefCount() == 1); + + // release the implicit reference, causing the object to be released + HttpRequestQueue::term(); } template <> template <> void HttpRequestqueueTestObjectType::test<2>() { - set_test_name("HttpRequestQueue refcount works"); + set_test_name("HttpRequestQueue refcount works"); + + // create a new ref counted object with an implicit reference + HttpRequestQueue::init(); + + HttpRequestQueue * rq = HttpRequestQueue::instanceOf(); + rq->addRef(); - // create a new ref counted object with an implicit reference - HttpRequestQueue::init(); + // release the singleton, hold on to the object + HttpRequestQueue::term(); - HttpRequestQueue * rq = HttpRequestQueue::instanceOf(); - rq->addRef(); - - // release the singleton, hold on to the object - HttpRequestQueue::term(); - - ensure("One ref after term() called", rq->getRefCount() == 1); + ensure("One ref after term() called", rq->getRefCount() == 1); - // Drop ref - rq->release(); + // Drop ref + rq->release(); } template <> template <> void HttpRequestqueueTestObjectType::test<3>() { - set_test_name("HttpRequestQueue addOp/fetchOp work"); + set_test_name("HttpRequestQueue addOp/fetchOp work"); - // create a new ref counted object with an implicit reference - HttpRequestQueue::init(); + // create a new ref counted object with an implicit reference + HttpRequestQueue::init(); - HttpRequestQueue * rq = HttpRequestQueue::instanceOf(); + HttpRequestQueue * rq = HttpRequestQueue::instanceOf(); - HttpOperation::ptr_t op(new HttpOpNull()); + HttpOperation::ptr_t op(new HttpOpNull()); - rq->addOp(op); // transfer my refcount + rq->addOp(op); // transfer my refcount - op = rq->fetchOp(true); // Potentially hangs the test on failure - ensure("One goes in, one comes out", static_cast<bool>(op)); + op = rq->fetchOp(true); // Potentially hangs the test on failure + ensure("One goes in, one comes out", static_cast<bool>(op)); op.reset(); - op = rq->fetchOp(false); - ensure("Better not be two of them", !op); - - // release the singleton, hold on to the object - HttpRequestQueue::term(); + op = rq->fetchOp(false); + ensure("Better not be two of them", !op); + + // release the singleton, hold on to the object + HttpRequestQueue::term(); } template <> template <> void HttpRequestqueueTestObjectType::test<4>() { - set_test_name("HttpRequestQueue addOp/fetchAll work"); + set_test_name("HttpRequestQueue addOp/fetchAll work"); + + // create a new ref counted object with an implicit reference + HttpRequestQueue::init(); - // create a new ref counted object with an implicit reference - HttpRequestQueue::init(); + HttpRequestQueue * rq = HttpRequestQueue::instanceOf(); - HttpRequestQueue * rq = HttpRequestQueue::instanceOf(); + HttpOperation::ptr_t op (new HttpOpNull()); + rq->addOp(op); // transfer my refcount - HttpOperation::ptr_t op (new HttpOpNull()); - rq->addOp(op); // transfer my refcount + op.reset(new HttpOpNull()); + rq->addOp(op); // transfer my refcount - op.reset(new HttpOpNull()); - rq->addOp(op); // transfer my refcount + op.reset(new HttpOpNull()); + rq->addOp(op); // transfer my refcount - op.reset(new HttpOpNull()); - rq->addOp(op); // transfer my refcount - - { - HttpRequestQueue::OpContainer ops; - rq->fetchAll(true, ops); // Potentially hangs the test on failure - ensure("Three go in, three come out", 3 == ops.size()); + { + HttpRequestQueue::OpContainer ops; + rq->fetchAll(true, ops); // Potentially hangs the test on failure + ensure("Three go in, three come out", 3 == ops.size()); - op = rq->fetchOp(false); - ensure("Better not be any more of them", !op); + op = rq->fetchOp(false); + ensure("Better not be any more of them", !op); op.reset(); - // release the singleton, hold on to the object - HttpRequestQueue::term(); + // release the singleton, hold on to the object + HttpRequestQueue::term(); - // Release them + // Release them ops.clear(); -// while (! ops.empty()) -// { -// HttpOperation * op = ops.front(); -// ops.erase(ops.begin()); -// op->release(); -// } - } +// while (! ops.empty()) +// { +// HttpOperation * op = ops.front(); +// ops.erase(ops.begin()); +// op->release(); +// } + } } } // end namespace tut diff --git a/indra/llcorehttp/tests/test_httpstatus.hpp b/indra/llcorehttp/tests/test_httpstatus.hpp index cbe3f574d4..eac7ba8557 100644 --- a/indra/llcorehttp/tests/test_httpstatus.hpp +++ b/indra/llcorehttp/tests/test_httpstatus.hpp @@ -1,4 +1,4 @@ -/** +/** * @file test_llrefcounted * @brief unit tests for HttpStatus struct * @@ -39,8 +39,8 @@ namespace tut struct HttpStatusTestData { - HttpStatusTestData() - {} + HttpStatusTestData() + {} }; typedef test_group<HttpStatusTestData> HttpStatusTestGroupType; @@ -51,250 +51,250 @@ HttpStatusTestGroupType HttpStatusTestGroup("HttpStatus Tests"); template <> template <> void HttpStatusTestObjectType::test<1>() { - set_test_name("HttpStatus construction"); - - // auto allocation fine for this - HttpStatus status; + set_test_name("HttpStatus construction"); - status = HttpStatus(HttpStatus::EXT_CURL_EASY, 0); - - ensure(bool(status)); - ensure(false == !(status)); + // auto allocation fine for this + HttpStatus status; - status = HttpStatus(HttpStatus::EXT_CURL_MULTI, 0); + status = HttpStatus(HttpStatus::EXT_CURL_EASY, 0); - ensure(bool(status)); - ensure(false == !(status)); + ensure(bool(status)); + ensure(false == !(status)); - status = HttpStatus(HttpStatus::LLCORE, HE_SUCCESS); - - ensure(bool(status)); - ensure(false == !(status)); + status = HttpStatus(HttpStatus::EXT_CURL_MULTI, 0); - status = HttpStatus(HttpStatus::EXT_CURL_MULTI, -1); + ensure(bool(status)); + ensure(false == !(status)); - ensure(false == bool(status)); - ensure(!(status)); + status = HttpStatus(HttpStatus::LLCORE, HE_SUCCESS); - status = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_BAD_DOWNLOAD_RESUME); + ensure(bool(status)); + ensure(false == !(status)); - ensure(false == bool(status)); - ensure(!(status)); + status = HttpStatus(HttpStatus::EXT_CURL_MULTI, -1); + + ensure(false == bool(status)); + ensure(!(status)); + + 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)); +// 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 valid status string conversion"); - - HttpStatus status = HttpStatus(HttpStatus::EXT_CURL_EASY, 0); - std::string msg = status.toString(); - // std::cout << "Result: " << msg << std::endl; - ensure(msg.empty()); - - status = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_BAD_FUNCTION_ARGUMENT); - msg = status.toString(); - // std::cout << "Result: " << msg << std::endl; - ensure(! msg.empty()); - - status = HttpStatus(HttpStatus::EXT_CURL_MULTI, CURLM_OUT_OF_MEMORY); - msg = status.toString(); - // std::cout << "Result: " << msg << std::endl; - ensure(! msg.empty()); - - status = HttpStatus(HttpStatus::LLCORE, HE_SHUTTING_DOWN); - msg = status.toString(); - // std::cout << "Result: " << msg << std::endl; - ensure(! msg.empty()); + set_test_name("HttpStatus valid status string conversion"); + + HttpStatus status = HttpStatus(HttpStatus::EXT_CURL_EASY, 0); + std::string msg = status.toString(); + // std::cout << "Result: " << msg << std::endl; + ensure(msg.empty()); + + status = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_BAD_FUNCTION_ARGUMENT); + msg = status.toString(); + // std::cout << "Result: " << msg << std::endl; + ensure(! msg.empty()); + + status = HttpStatus(HttpStatus::EXT_CURL_MULTI, CURLM_OUT_OF_MEMORY); + msg = status.toString(); + // std::cout << "Result: " << msg << std::endl; + ensure(! msg.empty()); + + status = HttpStatus(HttpStatus::LLCORE, HE_SHUTTING_DOWN); + msg = status.toString(); + // std::cout << "Result: " << msg << std::endl; + ensure(! msg.empty()); } template <> template <> void HttpStatusTestObjectType::test<3>() { - set_test_name("HttpStatus invalid status string conversion"); - - HttpStatus status = HttpStatus(HttpStatus::EXT_CURL_EASY, 32726); - std::string msg = status.toString(); - // std::cout << "Result: " << msg << std::endl; - ensure(! msg.empty()); - - status = HttpStatus(HttpStatus::EXT_CURL_MULTI, -470); - msg = status.toString(); - // std::cout << "Result: " << msg << std::endl; - ensure(! msg.empty()); - - status = HttpStatus(HttpStatus::LLCORE, 923); - msg = status.toString(); - // std::cout << "Result: " << msg << std::endl; - ensure(! msg.empty()); + set_test_name("HttpStatus invalid status string conversion"); + + HttpStatus status = HttpStatus(HttpStatus::EXT_CURL_EASY, 32726); + std::string msg = status.toString(); + // std::cout << "Result: " << msg << std::endl; + ensure(! msg.empty()); + + status = HttpStatus(HttpStatus::EXT_CURL_MULTI, -470); + msg = status.toString(); + // std::cout << "Result: " << msg << std::endl; + ensure(! msg.empty()); + + status = HttpStatus(HttpStatus::LLCORE, 923); + msg = status.toString(); + // std::cout << "Result: " << msg << std::endl; + ensure(! msg.empty()); } template <> template <> void HttpStatusTestObjectType::test<4>() { - set_test_name("HttpStatus equality/inequality testing"); + set_test_name("HttpStatus equality/inequality testing"); - // Make certain equality/inequality tests do not pass - // through the bool conversion. Distinct successful - // and error statuses should compare unequal. + // Make certain equality/inequality tests do not pass + // through the bool conversion. Distinct successful + // and error statuses should compare unequal. - HttpStatus status1(HttpStatus::LLCORE, HE_SUCCESS); - HttpStatus status2(HttpStatus::EXT_CURL_EASY, HE_SUCCESS); - ensure(status1 != status2); + HttpStatus status1(HttpStatus::LLCORE, HE_SUCCESS); + HttpStatus status2(HttpStatus::EXT_CURL_EASY, HE_SUCCESS); + ensure(status1 != status2); - status1 = HttpStatus(HttpStatus::LLCORE, HE_REPLY_ERROR); - status1 = HttpStatus(HttpStatus::LLCORE, HE_SHUTTING_DOWN); + status1 = HttpStatus(HttpStatus::LLCORE, HE_REPLY_ERROR); + status1 = HttpStatus(HttpStatus::LLCORE, HE_SHUTTING_DOWN); - ensure(status1 != status2); + ensure(status1 != status2); } template <> template <> void HttpStatusTestObjectType::test<5>() { - set_test_name("HttpStatus basic HTTP status encoding"); - - HttpStatus status; - - status = HttpStatus(200, HE_SUCCESS); - std::string msg = status.toString(); - ensure(msg.empty()); - ensure(bool(status)); - - // Normally a success but application says 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 = HttpStatus(200, HE_SUCCESS); - HttpStatus status2(200, HE_REPLY_ERROR); - ensure(status != status2); - - // Normally an error but application says okay - status = HttpStatus(406, HE_SUCCESS); - msg = status.toString(); - ensure(msg.empty()); - ensure(bool(status)); - - // Different statuses but both successful are distinct - status = HttpStatus(200, HE_SUCCESS); - status2 = HttpStatus(201, HE_SUCCESS); - ensure(status != status2); - - // Different statuses but both failed are distinct - status = HttpStatus(200, HE_REPLY_ERROR); - status2 = HttpStatus(201, HE_REPLY_ERROR); - ensure(status != status2); + set_test_name("HttpStatus basic HTTP status encoding"); + + HttpStatus status; + + status = HttpStatus(200, HE_SUCCESS); + std::string msg = status.toString(); + ensure(msg.empty()); + ensure(bool(status)); + + // Normally a success but application says 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 = HttpStatus(200, HE_SUCCESS); + HttpStatus status2(200, HE_REPLY_ERROR); + ensure(status != status2); + + // Normally an error but application says okay + status = HttpStatus(406, HE_SUCCESS); + msg = status.toString(); + ensure(msg.empty()); + ensure(bool(status)); + + // Different statuses but both successful are distinct + status = HttpStatus(200, HE_SUCCESS); + status2 = HttpStatus(201, HE_SUCCESS); + ensure(status != status2); + + // Different statuses but both failed are distinct + status = HttpStatus(200, HE_REPLY_ERROR); + status2 = HttpStatus(201, HE_REPLY_ERROR); + ensure(status != status2); } template <> template <> void HttpStatusTestObjectType::test<6>() { - set_test_name("HttpStatus HTTP status text strings"); + set_test_name("HttpStatus HTTP status text strings"); - HttpStatus status(100, HE_REPLY_ERROR); - std::string msg(status.toString()); - ensure(! msg.empty()); // Should be something - ensure(msg == "Continue"); + HttpStatus status(100, HE_REPLY_ERROR); + std::string msg(status.toString()); + ensure(! msg.empty()); // Should be something + ensure(msg == "Continue"); - status = HttpStatus(200, HE_SUCCESS); - msg = status.toString(); - ensure(msg.empty()); // Success is empty + status = HttpStatus(200, HE_SUCCESS); + msg = status.toString(); + ensure(msg.empty()); // Success is empty - status = HttpStatus(199, HE_REPLY_ERROR); - msg = status.toString(); - ensure(msg == "Unknown error"); + status = HttpStatus(199, HE_REPLY_ERROR); + msg = status.toString(); + ensure(msg == "Unknown error"); - status = HttpStatus(505, HE_REPLY_ERROR); - msg = status.toString(); - ensure(msg == "HTTP Version not supported"); + status = HttpStatus(505, HE_REPLY_ERROR); + msg = status.toString(); + ensure(msg == "HTTP Version not supported"); - status = HttpStatus(506, HE_REPLY_ERROR); - msg = status.toString(); - ensure(msg == "Unknown error"); + status = HttpStatus(506, HE_REPLY_ERROR); + msg = status.toString(); + ensure(msg == "Unknown error"); - status = HttpStatus(999, HE_REPLY_ERROR); - msg = status.toString(); - ensure(msg == "Unknown error"); + status = HttpStatus(999, HE_REPLY_ERROR); + msg = status.toString(); + ensure(msg == "Unknown error"); } template <> template <> void HttpStatusTestObjectType::test<7>() { - set_test_name("HttpStatus toHex() nominal function"); - - HttpStatus status(404); - std::string msg = status.toHex(); - // std::cout << "Result: " << msg << std::endl; - ensure_equals(msg, "01940001"); + set_test_name("HttpStatus toHex() nominal function"); + + HttpStatus status(404); + std::string msg = status.toHex(); + // std::cout << "Result: " << msg << std::endl; + ensure_equals(msg, "01940001"); } template <> template <> void HttpStatusTestObjectType::test<8>() { - set_test_name("HttpStatus toTerseString() nominal function"); - - HttpStatus status(404); - std::string msg = status.toTerseString(); - // std::cout << "Result: " << msg << std::endl; - ensure("Normal HTTP 404", msg == "Http_404"); - - status = HttpStatus(200); - msg = status.toTerseString(); - // std::cout << "Result: " << msg << std::endl; - ensure("Normal HTTP 200", msg == "Http_200"); - - status = HttpStatus(200, HE_REPLY_ERROR); - msg = status.toTerseString(); - // std::cout << "Result: " << msg << std::endl; - ensure("Unsuccessful HTTP 200", msg == "Http_200"); // No distinction for error - - status = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_CONNECT); - msg = status.toTerseString(); - // std::cout << "Result: " << msg << std::endl; - ensure("Easy couldn't connect error", msg == "Easy_7"); - - status = HttpStatus(HttpStatus::EXT_CURL_MULTI, CURLM_OUT_OF_MEMORY); - msg = status.toTerseString(); - // std::cout << "Result: " << msg << std::endl; - ensure("Multi out-of-memory error", msg == "Multi_3"); - - status = HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_SET); - msg = status.toTerseString(); - // std::cout << "Result: " << msg << std::endl; - ensure("Core option not set error", msg == "Core_7"); - - status = HttpStatus(22000, 1); - msg = status.toTerseString(); - // std::cout << "Result: " << msg << std::endl; - ensure("Undecodable error", msg == "Unknown_1"); - - status = HttpStatus(22000, -1); - msg = status.toTerseString(); - // std::cout << "Result: " << msg << std::endl; - ensure("Undecodable error 65535", msg == "Unknown_65535"); + set_test_name("HttpStatus toTerseString() nominal function"); + + HttpStatus status(404); + std::string msg = status.toTerseString(); + // std::cout << "Result: " << msg << std::endl; + ensure("Normal HTTP 404", msg == "Http_404"); + + status = HttpStatus(200); + msg = status.toTerseString(); + // std::cout << "Result: " << msg << std::endl; + ensure("Normal HTTP 200", msg == "Http_200"); + + status = HttpStatus(200, HE_REPLY_ERROR); + msg = status.toTerseString(); + // std::cout << "Result: " << msg << std::endl; + ensure("Unsuccessful HTTP 200", msg == "Http_200"); // No distinction for error + + status = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_CONNECT); + msg = status.toTerseString(); + // std::cout << "Result: " << msg << std::endl; + ensure("Easy couldn't connect error", msg == "Easy_7"); + + status = HttpStatus(HttpStatus::EXT_CURL_MULTI, CURLM_OUT_OF_MEMORY); + msg = status.toTerseString(); + // std::cout << "Result: " << msg << std::endl; + ensure("Multi out-of-memory error", msg == "Multi_3"); + + status = HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_SET); + msg = status.toTerseString(); + // std::cout << "Result: " << msg << std::endl; + ensure("Core option not set error", msg == "Core_7"); + + status = HttpStatus(22000, 1); + msg = status.toTerseString(); + // std::cout << "Result: " << msg << std::endl; + ensure("Undecodable error", msg == "Unknown_1"); + + status = HttpStatus(22000, -1); + msg = status.toTerseString(); + // std::cout << "Result: " << msg << std::endl; + ensure("Undecodable error 65535", msg == "Unknown_65535"); } } // end namespace tut -#endif // TEST_HTTP_STATUS_H +#endif // TEST_HTTP_STATUS_H diff --git a/indra/llcorehttp/tests/test_llcorehttp_peer.py b/indra/llcorehttp/tests/test_llcorehttp_peer.py index b9992538ba..b2805fda11 100755 --- a/indra/llcorehttp/tests/test_llcorehttp_peer.py +++ b/indra/llcorehttp/tests/test_llcorehttp_peer.py @@ -50,12 +50,12 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler): """This subclass of BaseHTTPRequestHandler is to receive and echo LLSD-flavored messages sent by the C++ LLHTTPClient. - Target URLs are fairly free-form and are assembled by + Target URLs are fairly free-form and are assembled by concatinating fragments. Currently defined fragments are: - '/reflect/' Request headers are bounced back to caller after prefixing with 'X-Reflect-' - - '/fail/' Body of request can contain LLSD with + - '/fail/' Body of request can contain LLSD with 'reason' string and 'status' integer which will become response header. - '/bug2295/' 206 response, no data in body: @@ -69,7 +69,7 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler): -- '/bug2295/inv_cont_range/0/' Generates HE_INVALID_CONTENT_RANGE error in llcorehttp. - '/503/' Generate 503 responses with various kinds of 'retry-after' headers - -- '/503/0/' "Retry-After: 2" + -- '/503/0/' "Retry-After: 2" -- '/503/1/' "Retry-After: Thu, 31 Dec 2043 23:59:59 GMT" -- '/503/2/' "Retry-After: Fri, 31 Dec 1999 23:59:59 GMT" -- '/503/3/' "Retry-After: " diff --git a/indra/llcorehttp/tests/test_refcounted.hpp b/indra/llcorehttp/tests/test_refcounted.hpp index 2310812d5a..c0c8e78413 100644 --- a/indra/llcorehttp/tests/test_refcounted.hpp +++ b/indra/llcorehttp/tests/test_refcounted.hpp @@ -1,4 +1,4 @@ -/** +/** * @file test_refcounted.hpp * @brief unit tests for the LLCoreInt::RefCounted class * @@ -34,93 +34,93 @@ using namespace LLCoreInt; namespace tut { - struct RefCountedTestData - { - // the test objects inherit from this so the member functions and variables - // can be referenced directly inside of the test functions. - }; + struct RefCountedTestData + { + // the test objects inherit from this so the member functions and variables + // can be referenced directly inside of the test functions. + }; - typedef test_group<RefCountedTestData> RefCountedTestGroupType; - typedef RefCountedTestGroupType::object RefCountedTestObjectType; - RefCountedTestGroupType RefCountedTestGroup("RefCounted Tests"); + typedef test_group<RefCountedTestData> RefCountedTestGroupType; + typedef RefCountedTestGroupType::object RefCountedTestObjectType; + RefCountedTestGroupType RefCountedTestGroup("RefCounted Tests"); - template <> template <> - void RefCountedTestObjectType::test<1>() - { - set_test_name("RefCounted construction with implicit count"); + template <> template <> + void RefCountedTestObjectType::test<1>() + { + set_test_name("RefCounted construction with implicit count"); - // create a new ref counted object with an implicit reference - RefCounted * rc = new RefCounted(true); - ensure(rc->getRefCount() == 1); + // create a new ref counted object with an implicit reference + RefCounted * rc = new RefCounted(true); + ensure(rc->getRefCount() == 1); - // release the implicit reference, causing the object to be released - rc->release(); - } + // release the implicit reference, causing the object to be released + rc->release(); + } - template <> template <> - void RefCountedTestObjectType::test<2>() - { - set_test_name("RefCounted construction without implicit count"); + template <> template <> + void RefCountedTestObjectType::test<2>() + { + set_test_name("RefCounted construction without implicit count"); - // create a new ref counted object with an implicit reference - RefCounted * rc = new RefCounted(false); - ensure(rc->getRefCount() == 0); + // create a new ref counted object with an implicit reference + RefCounted * rc = new RefCounted(false); + ensure(rc->getRefCount() == 0); - // add a reference - rc->addRef(); - ensure(rc->getRefCount() == 1); + // add a reference + rc->addRef(); + ensure(rc->getRefCount() == 1); - // release the implicit reference, causing the object to be released - rc->release(); - } + // release the implicit reference, causing the object to be released + rc->release(); + } - template <> template <> - void RefCountedTestObjectType::test<3>() - { - set_test_name("RefCounted addRef and release"); + template <> template <> + void RefCountedTestObjectType::test<3>() + { + set_test_name("RefCounted addRef and release"); - RefCounted * rc = new RefCounted(false); + RefCounted * rc = new RefCounted(false); - for (int i = 0; i < 1024; ++i) - { - rc->addRef(); - } + for (int i = 0; i < 1024; ++i) + { + rc->addRef(); + } - ensure(rc->getRefCount() == 1024); + ensure(rc->getRefCount() == 1024); - for (int i = 0; i < 1024; ++i) - { - rc->release(); - } - } + for (int i = 0; i < 1024; ++i) + { + rc->release(); + } + } - template <> template <> - void RefCountedTestObjectType::test<4>() - { - set_test_name("RefCounted isLastRef check"); + template <> template <> + void RefCountedTestObjectType::test<4>() + { + set_test_name("RefCounted isLastRef check"); - RefCounted * rc = new RefCounted(true); + RefCounted * rc = new RefCounted(true); - // with only one reference, isLastRef should be true - ensure(rc->isLastRef()); + // with only one reference, isLastRef should be true + ensure(rc->isLastRef()); - // release it to clean up memory - rc->release(); - } + // release it to clean up memory + rc->release(); + } - template <> template <> - void RefCountedTestObjectType::test<5>() - { - set_test_name("RefCounted noRef check"); + template <> template <> + void RefCountedTestObjectType::test<5>() + { + set_test_name("RefCounted noRef check"); - RefCounted * rc = new RefCounted(false); + RefCounted * rc = new RefCounted(false); - // set the noRef - rc->noRef(); + // set the noRef + rc->noRef(); - // with only one reference, isLastRef should be true - ensure(rc->getRefCount() == RefCounted::NOT_REF_COUNTED); - } + // with only one reference, isLastRef should be true + ensure(rc->getRefCount() == RefCounted::NOT_REF_COUNTED); + } } #endif // disabling on Win64 -#endif // TEST_LLCOREINT_REF_COUNTED_H_ +#endif // TEST_LLCOREINT_REF_COUNTED_H_ |