SH-4312 Configuration data between viewer and llcorehttp is clumsy.
Much improved. Unified the global and class options into a single option list. Implemented static and dynamic setting paths as much as possible. Dynamic path does require packet/RPC but otherwise there's near unification. Dynamic modes can't get values back yet due to the response/notifier scheme but this doesn't bother me. Flatten global and class options into simpler struct-like entities. Setter/getter available on these when needed (external APIs) but code can otherwise fiddle directly when it knows what to do. Much duplicated options/state removed from HttpPolicy. Comments cleaned up. Threads better described and consistently mentioned in API docs. Integration test extended for 503 responses with Reply-After headers.master
parent
fb734d621e
commit
eff651cffc
|
|
@ -36,7 +36,8 @@
|
|||
// General library to-do list
|
||||
//
|
||||
// - Implement policy classes. Structure is mostly there just didn't
|
||||
// need it for the first consumer.
|
||||
// need it for the first consumer. [Classes are there. More
|
||||
// advanced features, like borrowing, aren't there yet.]
|
||||
// - Consider Removing 'priority' from the request interface. Its use
|
||||
// in an always active class can lead to starvation of low-priority
|
||||
// requests. Requires coodination of priority values across all
|
||||
|
|
@ -46,6 +47,7 @@
|
|||
// may not really need it.
|
||||
// - Set/get for global policy and policy classes is clumsy. Rework
|
||||
// it heading in a direction that allows for more dynamic behavior.
|
||||
// [Mostly fixed]
|
||||
// - Move HttpOpRequest::prepareRequest() to HttpLibcurl for the
|
||||
// pedantic.
|
||||
// - Update downloader and other long-duration services are going to
|
||||
|
|
@ -73,7 +75,7 @@
|
|||
// the main source file.
|
||||
// - Expand areas of usage eventually leading to the removal of LLCurl.
|
||||
// Rough order of expansion:
|
||||
// . Mesh fetch
|
||||
// . Mesh fetch [Underway]
|
||||
// . Avatar names
|
||||
// . Group membership lists
|
||||
// . Caps access in general
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
* Copyright (C) 2012-2013, 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
|
||||
|
|
@ -71,16 +71,22 @@ public:
|
|||
///
|
||||
/// @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(HttpOpRequest * 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
|
||||
|
|
@ -91,9 +97,13 @@ public:
|
|||
/// 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;
|
||||
|
||||
|
|
@ -103,6 +113,7 @@ public:
|
|||
///
|
||||
/// @return True if handle was found and operation canceled.
|
||||
///
|
||||
/// Threading: called by worker thread.
|
||||
bool cancel(HttpHandle handle);
|
||||
|
||||
protected:
|
||||
|
|
@ -121,7 +132,7 @@ protected:
|
|||
HttpService * mService; // Simple reference, not owner
|
||||
active_set_t mActiveOps;
|
||||
int mPolicyCount;
|
||||
CURLM ** mMultiHandles;
|
||||
CURLM ** mMultiHandles; // One handle per policy class
|
||||
}; // end class HttpLibcurl
|
||||
|
||||
} // end namespace LLCore
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
* Copyright (C) 2012-2013, 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
|
||||
|
|
@ -72,7 +72,7 @@ class HttpService;
|
|||
class HttpOperation : public LLCoreInt::RefCounted
|
||||
{
|
||||
public:
|
||||
/// Threading: called by a consumer/application thread.
|
||||
/// Threading: called by consumer thread.
|
||||
HttpOperation();
|
||||
|
||||
protected:
|
||||
|
|
@ -108,7 +108,7 @@ public:
|
|||
/// by the worker thread. This is passible data
|
||||
/// until notification is performed.
|
||||
///
|
||||
/// Threading: called by application thread.
|
||||
/// Threading: called by consumer thread.
|
||||
///
|
||||
void setReplyPath(HttpReplyQueue * reply_queue,
|
||||
HttpHandler * handler);
|
||||
|
|
@ -141,7 +141,7 @@ public:
|
|||
/// call to HttpRequest::update(). This method does the necessary
|
||||
/// dispatching.
|
||||
///
|
||||
/// Threading: called by application thread.
|
||||
/// Threading: called by consumer thread.
|
||||
///
|
||||
virtual void visitNotifier(HttpRequest *);
|
||||
|
||||
|
|
|
|||
|
|
@ -402,7 +402,7 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
|
|||
// *FIXME: better error handling later
|
||||
HttpStatus status;
|
||||
|
||||
// Get policy options
|
||||
// Get global policy options
|
||||
HttpPolicyGlobal & policy(service->getPolicy().getGlobalOptions());
|
||||
|
||||
mCurlHandle = curl_easy_init();
|
||||
|
|
@ -441,30 +441,27 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
|
|||
curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYPEER, 1);
|
||||
curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYHOST, 0);
|
||||
|
||||
const std::string * opt_value(NULL);
|
||||
long opt_long(0L);
|
||||
policy.get(HttpRequest::GP_LLPROXY, &opt_long);
|
||||
if (opt_long)
|
||||
if (policy.mUseLLProxy)
|
||||
{
|
||||
// Use the viewer-based thread-safe API which has a
|
||||
// fast/safe check for proxy enable. Would like to
|
||||
// encapsulate this someway...
|
||||
LLProxy::getInstance()->applyProxySettings(mCurlHandle);
|
||||
}
|
||||
else if (policy.get(HttpRequest::GP_HTTP_PROXY, &opt_value))
|
||||
else if (policy.mHttpProxy.size())
|
||||
{
|
||||
// *TODO: This is fine for now but get fuller socks5/
|
||||
// authentication thing going later....
|
||||
curl_easy_setopt(mCurlHandle, CURLOPT_PROXY, opt_value->c_str());
|
||||
curl_easy_setopt(mCurlHandle, CURLOPT_PROXY, policy.mHttpProxy.c_str());
|
||||
curl_easy_setopt(mCurlHandle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
|
||||
}
|
||||
if (policy.get(HttpRequest::GP_CA_PATH, &opt_value))
|
||||
if (policy.mCAPath.size())
|
||||
{
|
||||
curl_easy_setopt(mCurlHandle, CURLOPT_CAPATH, opt_value->c_str());
|
||||
curl_easy_setopt(mCurlHandle, CURLOPT_CAPATH, policy.mCAPath.c_str());
|
||||
}
|
||||
if (policy.get(HttpRequest::GP_CA_FILE, &opt_value))
|
||||
if (policy.mCAFile.size())
|
||||
{
|
||||
curl_easy_setopt(mCurlHandle, CURLOPT_CAINFO, opt_value->c_str());
|
||||
curl_easy_setopt(mCurlHandle, CURLOPT_CAINFO, policy.mCAFile.c_str());
|
||||
}
|
||||
|
||||
switch (mReqMethod)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
* Copyright (C) 2012-2013, 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
|
||||
|
|
@ -27,6 +27,7 @@
|
|||
#include "_httpopsetget.h"
|
||||
|
||||
#include "httpcommon.h"
|
||||
#include "httprequest.h"
|
||||
|
||||
#include "_httpservice.h"
|
||||
#include "_httppolicy.h"
|
||||
|
|
@ -43,10 +44,11 @@ namespace LLCore
|
|||
|
||||
HttpOpSetGet::HttpOpSetGet()
|
||||
: HttpOperation(),
|
||||
mIsGlobal(false),
|
||||
mDoSet(false),
|
||||
mSetting(-1), // Nothing requested
|
||||
mLongValue(0L)
|
||||
mReqOption(HttpRequest::PO_CONNECTION_LIMIT),
|
||||
mReqClass(HttpRequest::INVALID_POLICY_ID),
|
||||
mReqDoSet(false),
|
||||
mReqLongValue(0L),
|
||||
mReplyLongValue(0L)
|
||||
{}
|
||||
|
||||
|
||||
|
|
@ -54,37 +56,84 @@ HttpOpSetGet::~HttpOpSetGet()
|
|||
{}
|
||||
|
||||
|
||||
void HttpOpSetGet::setupGet(HttpRequest::EGlobalPolicy setting)
|
||||
HttpStatus HttpOpSetGet::setupGet(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass)
|
||||
{
|
||||
mIsGlobal = true;
|
||||
mSetting = setting;
|
||||
HttpStatus status;
|
||||
|
||||
mReqOption = opt;
|
||||
mReqClass = pclass;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void HttpOpSetGet::setupSet(HttpRequest::EGlobalPolicy setting, const std::string & value)
|
||||
HttpStatus HttpOpSetGet::setupSet(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass, long value)
|
||||
{
|
||||
mIsGlobal = true;
|
||||
mDoSet = true;
|
||||
mSetting = setting;
|
||||
mStrValue = 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 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;
|
||||
}
|
||||
|
||||
|
||||
void HttpOpSetGet::stageFromRequest(HttpService * service)
|
||||
{
|
||||
HttpPolicyGlobal & pol_opt(service->getPolicy().getGlobalOptions());
|
||||
HttpRequest::EGlobalPolicy setting(static_cast<HttpRequest::EGlobalPolicy>(mSetting));
|
||||
|
||||
if (mDoSet)
|
||||
if (mReqDoSet)
|
||||
{
|
||||
mStatus = pol_opt.set(setting, mStrValue);
|
||||
}
|
||||
if (mStatus)
|
||||
{
|
||||
const std::string * value(NULL);
|
||||
if ((mStatus = pol_opt.get(setting, &value)))
|
||||
if (HttpService::sOptionDesc[mReqOption].mIsLong)
|
||||
{
|
||||
mStrValue = *value;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
* Copyright (C) 2012-2013, 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
|
||||
|
|
@ -46,7 +46,10 @@ namespace LLCore
|
|||
/// configuration settings.
|
||||
///
|
||||
/// *NOTE: Expect this to change. Don't really like it yet.
|
||||
|
||||
///
|
||||
/// *TODO: Can't return values to caller yet. Need to do
|
||||
/// something better with HttpResponse and visitNotifier().
|
||||
///
|
||||
class HttpOpSetGet : public HttpOperation
|
||||
{
|
||||
public:
|
||||
|
|
@ -61,19 +64,23 @@ private:
|
|||
|
||||
public:
|
||||
/// Threading: called by application thread
|
||||
void setupGet(HttpRequest::EGlobalPolicy setting);
|
||||
void setupSet(HttpRequest::EGlobalPolicy setting, const std::string & value);
|
||||
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 *);
|
||||
|
||||
public:
|
||||
// Request data
|
||||
bool mIsGlobal;
|
||||
bool mDoSet;
|
||||
int mSetting;
|
||||
long mLongValue;
|
||||
std::string mStrValue;
|
||||
HttpRequest::EPolicyOption mReqOption;
|
||||
HttpRequest::policy_t mReqClass;
|
||||
bool mReqDoSet;
|
||||
long mReqLongValue;
|
||||
std::string mReqStrValue;
|
||||
|
||||
// Reply Data
|
||||
long mReplyLongValue;
|
||||
std::string mReplyStrValue;
|
||||
}; // end class HttpOpSetGet
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
* Copyright (C) 2012-2013, 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
|
||||
|
|
@ -41,57 +41,64 @@ namespace LLCore
|
|||
|
||||
|
||||
// Per-policy-class data for a running system.
|
||||
// Collection of queues, parameters, history, metrics, etc.
|
||||
// Collection of queues, options and other data
|
||||
// for a single policy class.
|
||||
//
|
||||
// Threading: accessed only by worker thread
|
||||
struct HttpPolicy::State
|
||||
struct HttpPolicy::ClassState
|
||||
{
|
||||
public:
|
||||
State()
|
||||
: mConnMax(HTTP_CONNECTION_LIMIT_DEFAULT),
|
||||
mConnAt(HTTP_CONNECTION_LIMIT_DEFAULT),
|
||||
mConnMin(1),
|
||||
mNextSample(0),
|
||||
mErrorCount(0),
|
||||
mErrorFactor(0)
|
||||
ClassState()
|
||||
{}
|
||||
|
||||
HttpReadyQueue mReadyQueue;
|
||||
HttpRetryQueue mRetryQueue;
|
||||
|
||||
HttpPolicyClass mOptions;
|
||||
|
||||
long mConnMax;
|
||||
long mConnAt;
|
||||
long mConnMin;
|
||||
|
||||
HttpTime mNextSample;
|
||||
unsigned long mErrorCount;
|
||||
unsigned long mErrorFactor;
|
||||
};
|
||||
|
||||
|
||||
HttpPolicy::HttpPolicy(HttpService * service)
|
||||
: mActiveClasses(0),
|
||||
mState(NULL),
|
||||
mService(service)
|
||||
{}
|
||||
: mService(service)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
void HttpPolicy::shutdown()
|
||||
{
|
||||
for (int policy_class(0); policy_class < mActiveClasses; ++policy_class)
|
||||
for (int policy_class(0); policy_class < mClasses.size(); ++policy_class)
|
||||
{
|
||||
HttpRetryQueue & retryq(mState[policy_class].mRetryQueue);
|
||||
ClassState & state(*mClasses[policy_class]);
|
||||
|
||||
HttpRetryQueue & retryq(state.mRetryQueue);
|
||||
while (! retryq.empty())
|
||||
{
|
||||
HttpOpRequest * op(retryq.top());
|
||||
|
|
@ -101,7 +108,7 @@ void HttpPolicy::shutdown()
|
|||
op->release();
|
||||
}
|
||||
|
||||
HttpReadyQueue & readyq(mState[policy_class].mReadyQueue);
|
||||
HttpReadyQueue & readyq(state.mReadyQueue);
|
||||
while (! readyq.empty())
|
||||
{
|
||||
HttpOpRequest * op(readyq.top());
|
||||
|
|
@ -111,28 +118,11 @@ void HttpPolicy::shutdown()
|
|||
op->release();
|
||||
}
|
||||
}
|
||||
delete [] mState;
|
||||
mState = NULL;
|
||||
mActiveClasses = 0;
|
||||
}
|
||||
|
||||
|
||||
void HttpPolicy::start(const HttpPolicyGlobal & global,
|
||||
const std::vector<HttpPolicyClass> & classes)
|
||||
{
|
||||
llassert_always(! mState);
|
||||
|
||||
mGlobalOptions = global;
|
||||
mActiveClasses = classes.size();
|
||||
mState = new State [mActiveClasses];
|
||||
for (int i(0); i < mActiveClasses; ++i)
|
||||
{
|
||||
mState[i].mOptions = classes[i];
|
||||
mState[i].mConnMax = classes[i].mConnectionLimit;
|
||||
mState[i].mConnAt = mState[i].mConnMax;
|
||||
mState[i].mConnMin = 2;
|
||||
}
|
||||
}
|
||||
void HttpPolicy::start()
|
||||
{}
|
||||
|
||||
|
||||
void HttpPolicy::addOp(HttpOpRequest * op)
|
||||
|
|
@ -141,7 +131,7 @@ void HttpPolicy::addOp(HttpOpRequest * op)
|
|||
|
||||
op->mPolicyRetries = 0;
|
||||
op->mPolicy503Retries = 0;
|
||||
mState[policy_class].mReadyQueue.push(op);
|
||||
mClasses[policy_class]->mReadyQueue.push(op);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -183,7 +173,7 @@ void HttpPolicy::retryOp(HttpOpRequest * op)
|
|||
<< static_cast<HttpHandle>(op)
|
||||
<< LL_ENDL;
|
||||
}
|
||||
mState[policy_class].mRetryQueue.push(op);
|
||||
mClasses[policy_class]->mRetryQueue.push(op);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -204,11 +194,11 @@ HttpService::ELoopSpeed HttpPolicy::processReadyQueue()
|
|||
HttpService::ELoopSpeed result(HttpService::REQUEST_SLEEP);
|
||||
HttpLibcurl & transport(mService->getTransport());
|
||||
|
||||
for (int policy_class(0); policy_class < mActiveClasses; ++policy_class)
|
||||
for (int policy_class(0); policy_class < mClasses.size(); ++policy_class)
|
||||
{
|
||||
State & state(mState[policy_class]);
|
||||
ClassState & state(*mClasses[policy_class]);
|
||||
int active(transport.getActiveCountInClass(policy_class));
|
||||
int needed(state.mConnAt - active); // Expect negatives here
|
||||
int needed(state.mOptions.mConnectionLimit - active); // Expect negatives here
|
||||
|
||||
HttpRetryQueue & retryq(state.mRetryQueue);
|
||||
HttpReadyQueue & readyq(state.mReadyQueue);
|
||||
|
|
@ -256,9 +246,9 @@ HttpService::ELoopSpeed HttpPolicy::processReadyQueue()
|
|||
|
||||
bool HttpPolicy::changePriority(HttpHandle handle, HttpRequest::priority_t priority)
|
||||
{
|
||||
for (int policy_class(0); policy_class < mActiveClasses; ++policy_class)
|
||||
for (int policy_class(0); policy_class < mClasses.size(); ++policy_class)
|
||||
{
|
||||
State & state(mState[policy_class]);
|
||||
ClassState & state(*mClasses[policy_class]);
|
||||
// We don't scan retry queue because a priority change there
|
||||
// is meaningless. The request will be issued based on retry
|
||||
// intervals not priority value, which is now moot.
|
||||
|
|
@ -286,9 +276,9 @@ bool HttpPolicy::changePriority(HttpHandle handle, HttpRequest::priority_t prior
|
|||
|
||||
bool HttpPolicy::cancel(HttpHandle handle)
|
||||
{
|
||||
for (int policy_class(0); policy_class < mActiveClasses; ++policy_class)
|
||||
for (int policy_class(0); policy_class < mClasses.size(); ++policy_class)
|
||||
{
|
||||
State & state(mState[policy_class]);
|
||||
ClassState & state(*mClasses[policy_class]);
|
||||
|
||||
// Scan retry queue
|
||||
HttpRetryQueue::container_type & c1(state.mRetryQueue.get_container());
|
||||
|
|
@ -382,13 +372,21 @@ bool HttpPolicy::stageAfterCompletion(HttpOpRequest * op)
|
|||
return false; // not active
|
||||
}
|
||||
|
||||
|
||||
HttpPolicyClass & HttpPolicy::getClassOptions(HttpRequest::policy_t pclass)
|
||||
{
|
||||
llassert_always(pclass >= 0 && pclass < mClasses.size());
|
||||
|
||||
return mClasses[pclass]->mOptions;
|
||||
}
|
||||
|
||||
|
||||
int HttpPolicy::getReadyCount(HttpRequest::policy_t policy_class) const
|
||||
{
|
||||
if (policy_class < mActiveClasses)
|
||||
if (policy_class < mClasses.size())
|
||||
{
|
||||
return (mState[policy_class].mReadyQueue.size()
|
||||
+ mState[policy_class].mRetryQueue.size());
|
||||
return (mClasses[policy_class]->mReadyQueue.size()
|
||||
+ mClasses[policy_class]->mRetryQueue.size());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
* Copyright (C) 2012-2013, 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
|
||||
|
|
@ -60,6 +60,9 @@ private:
|
|||
void operator=(const HttpPolicy &); // Not defined
|
||||
|
||||
public:
|
||||
/// 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.
|
||||
|
|
@ -71,9 +74,8 @@ public:
|
|||
/// requests. One-time call invoked before starting
|
||||
/// the worker thread.
|
||||
///
|
||||
/// Threading: called by application thread
|
||||
void start(const HttpPolicyGlobal & global,
|
||||
const std::vector<HttpPolicyClass> & classes);
|
||||
/// Threading: called by init thread
|
||||
void start();
|
||||
|
||||
/// Give the policy layer some cycles to scan the ready
|
||||
/// queue promoting higher-priority requests to active
|
||||
|
|
@ -93,7 +95,7 @@ public:
|
|||
/// and should not be modified by anyone until retrieved
|
||||
/// from queue.
|
||||
///
|
||||
/// Threading: called by any thread
|
||||
/// Threading: called by worker thread
|
||||
void addOp(HttpOpRequest *);
|
||||
|
||||
/// Similar to addOp, used when a caller wants to retry a
|
||||
|
|
@ -130,30 +132,39 @@ public:
|
|||
/// Threading: called by worker thread
|
||||
bool stageAfterCompletion(HttpOpRequest * op);
|
||||
|
||||
// Get pointer to global policy options. Caller is expected
|
||||
// to do context checks like no setting once running.
|
||||
/// 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;
|
||||
|
||||
protected:
|
||||
struct State;
|
||||
|
||||
int mActiveClasses;
|
||||
State * mState;
|
||||
HttpService * mService; // Naked pointer, not refcounted, not owner
|
||||
HttpPolicyGlobal mGlobalOptions;
|
||||
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
|
||||
|
|
|
|||
|
|
@ -34,8 +34,7 @@ namespace LLCore
|
|||
|
||||
|
||||
HttpPolicyClass::HttpPolicyClass()
|
||||
: mSetMask(0UL),
|
||||
mConnectionLimit(HTTP_CONNECTION_LIMIT_DEFAULT),
|
||||
: mConnectionLimit(HTTP_CONNECTION_LIMIT_DEFAULT),
|
||||
mPerHostConnectionLimit(HTTP_CONNECTION_LIMIT_DEFAULT),
|
||||
mPipelining(HTTP_PIPELINING_DEFAULT)
|
||||
{}
|
||||
|
|
@ -49,7 +48,6 @@ HttpPolicyClass & HttpPolicyClass::operator=(const HttpPolicyClass & other)
|
|||
{
|
||||
if (this != &other)
|
||||
{
|
||||
mSetMask = other.mSetMask;
|
||||
mConnectionLimit = other.mConnectionLimit;
|
||||
mPerHostConnectionLimit = other.mPerHostConnectionLimit;
|
||||
mPipelining = other.mPipelining;
|
||||
|
|
@ -59,26 +57,25 @@ HttpPolicyClass & HttpPolicyClass::operator=(const HttpPolicyClass & other)
|
|||
|
||||
|
||||
HttpPolicyClass::HttpPolicyClass(const HttpPolicyClass & other)
|
||||
: mSetMask(other.mSetMask),
|
||||
mConnectionLimit(other.mConnectionLimit),
|
||||
: mConnectionLimit(other.mConnectionLimit),
|
||||
mPerHostConnectionLimit(other.mPerHostConnectionLimit),
|
||||
mPipelining(other.mPipelining)
|
||||
{}
|
||||
|
||||
|
||||
HttpStatus HttpPolicyClass::set(HttpRequest::EClassPolicy opt, long value)
|
||||
HttpStatus HttpPolicyClass::set(HttpRequest::EPolicyOption opt, long value)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case HttpRequest::CP_CONNECTION_LIMIT:
|
||||
case HttpRequest::PO_CONNECTION_LIMIT:
|
||||
mConnectionLimit = llclamp(value, long(HTTP_CONNECTION_LIMIT_MIN), long(HTTP_CONNECTION_LIMIT_MAX));
|
||||
break;
|
||||
|
||||
case HttpRequest::CP_PER_HOST_CONNECTION_LIMIT:
|
||||
case HttpRequest::PO_PER_HOST_CONNECTION_LIMIT:
|
||||
mPerHostConnectionLimit = llclamp(value, long(HTTP_CONNECTION_LIMIT_MIN), mConnectionLimit);
|
||||
break;
|
||||
|
||||
case HttpRequest::CP_ENABLE_PIPELINING:
|
||||
case HttpRequest::PO_ENABLE_PIPELINING:
|
||||
mPipelining = llclamp(value, 0L, 1L);
|
||||
break;
|
||||
|
||||
|
|
@ -86,38 +83,30 @@ HttpStatus HttpPolicyClass::set(HttpRequest::EClassPolicy opt, long value)
|
|||
return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
|
||||
}
|
||||
|
||||
mSetMask |= 1UL << int(opt);
|
||||
return HttpStatus();
|
||||
}
|
||||
|
||||
|
||||
HttpStatus HttpPolicyClass::get(HttpRequest::EClassPolicy opt, long * value)
|
||||
HttpStatus HttpPolicyClass::get(HttpRequest::EPolicyOption opt, long * value) const
|
||||
{
|
||||
static const HttpStatus not_set(HttpStatus::LLCORE, HE_OPT_NOT_SET);
|
||||
long * src(NULL);
|
||||
|
||||
switch (opt)
|
||||
{
|
||||
case HttpRequest::CP_CONNECTION_LIMIT:
|
||||
src = &mConnectionLimit;
|
||||
case HttpRequest::PO_CONNECTION_LIMIT:
|
||||
*value = mConnectionLimit;
|
||||
break;
|
||||
|
||||
case HttpRequest::CP_PER_HOST_CONNECTION_LIMIT:
|
||||
src = &mPerHostConnectionLimit;
|
||||
case HttpRequest::PO_PER_HOST_CONNECTION_LIMIT:
|
||||
*value = mPerHostConnectionLimit;
|
||||
break;
|
||||
|
||||
case HttpRequest::CP_ENABLE_PIPELINING:
|
||||
src = &mPipelining;
|
||||
case HttpRequest::PO_ENABLE_PIPELINING:
|
||||
*value = mPipelining;
|
||||
break;
|
||||
|
||||
default:
|
||||
return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
|
||||
}
|
||||
|
||||
if (! (mSetMask & (1UL << int(opt))))
|
||||
return not_set;
|
||||
|
||||
*value = *src;
|
||||
return HttpStatus();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
* Copyright (C) 2012-2013, 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
|
||||
|
|
@ -34,6 +34,18 @@
|
|||
namespace LLCore
|
||||
{
|
||||
|
||||
/// Options struct for per-class policy options.
|
||||
///
|
||||
/// Combines both raw blob data access with semantics-enforcing
|
||||
/// set/get interfaces. For internal operations by the worker
|
||||
/// thread, just grab the setting directly from instance and test/use
|
||||
/// as needed. When attached to external APIs (the public API
|
||||
/// options interfaces) the set/get methods are available to
|
||||
/// enforce correct ranges, data types, contexts, etc. and suitable
|
||||
/// status values are returned.
|
||||
///
|
||||
/// Threading: Single-threaded. In practice, init thread before
|
||||
/// worker starts, worker thread after.
|
||||
class HttpPolicyClass
|
||||
{
|
||||
public:
|
||||
|
|
@ -44,11 +56,10 @@ public:
|
|||
HttpPolicyClass(const HttpPolicyClass &); // Not defined
|
||||
|
||||
public:
|
||||
HttpStatus set(HttpRequest::EClassPolicy opt, long value);
|
||||
HttpStatus get(HttpRequest::EClassPolicy opt, long * value);
|
||||
HttpStatus set(HttpRequest::EPolicyOption opt, long value);
|
||||
HttpStatus get(HttpRequest::EPolicyOption opt, long * value) const;
|
||||
|
||||
public:
|
||||
unsigned long mSetMask;
|
||||
long mConnectionLimit;
|
||||
long mPerHostConnectionLimit;
|
||||
long mPipelining;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
* Copyright (C) 2012-2013, 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
|
||||
|
|
@ -34,8 +34,7 @@ namespace LLCore
|
|||
|
||||
|
||||
HttpPolicyGlobal::HttpPolicyGlobal()
|
||||
: mSetMask(0UL),
|
||||
mConnectionLimit(HTTP_CONNECTION_LIMIT_DEFAULT),
|
||||
: mConnectionLimit(HTTP_CONNECTION_LIMIT_DEFAULT),
|
||||
mTrace(HTTP_TRACE_OFF),
|
||||
mUseLLProxy(0)
|
||||
{}
|
||||
|
|
@ -49,7 +48,6 @@ HttpPolicyGlobal & HttpPolicyGlobal::operator=(const HttpPolicyGlobal & other)
|
|||
{
|
||||
if (this != &other)
|
||||
{
|
||||
mSetMask = other.mSetMask;
|
||||
mConnectionLimit = other.mConnectionLimit;
|
||||
mCAPath = other.mCAPath;
|
||||
mCAFile = other.mCAFile;
|
||||
|
|
@ -61,19 +59,19 @@ HttpPolicyGlobal & HttpPolicyGlobal::operator=(const HttpPolicyGlobal & other)
|
|||
}
|
||||
|
||||
|
||||
HttpStatus HttpPolicyGlobal::set(HttpRequest::EGlobalPolicy opt, long value)
|
||||
HttpStatus HttpPolicyGlobal::set(HttpRequest::EPolicyOption opt, long value)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case HttpRequest::GP_CONNECTION_LIMIT:
|
||||
case HttpRequest::PO_CONNECTION_LIMIT:
|
||||
mConnectionLimit = llclamp(value, long(HTTP_CONNECTION_LIMIT_MIN), long(HTTP_CONNECTION_LIMIT_MAX));
|
||||
break;
|
||||
|
||||
case HttpRequest::GP_TRACE:
|
||||
case HttpRequest::PO_TRACE:
|
||||
mTrace = llclamp(value, long(HTTP_TRACE_MIN), long(HTTP_TRACE_MAX));
|
||||
break;
|
||||
|
||||
case HttpRequest::GP_LLPROXY:
|
||||
case HttpRequest::PO_LLPROXY:
|
||||
mUseLLProxy = llclamp(value, 0L, 1L);
|
||||
break;
|
||||
|
||||
|
|
@ -81,24 +79,23 @@ HttpStatus HttpPolicyGlobal::set(HttpRequest::EGlobalPolicy opt, long value)
|
|||
return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
|
||||
}
|
||||
|
||||
mSetMask |= 1UL << int(opt);
|
||||
return HttpStatus();
|
||||
}
|
||||
|
||||
|
||||
HttpStatus HttpPolicyGlobal::set(HttpRequest::EGlobalPolicy opt, const std::string & value)
|
||||
HttpStatus HttpPolicyGlobal::set(HttpRequest::EPolicyOption opt, const std::string & value)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case HttpRequest::GP_CA_PATH:
|
||||
case HttpRequest::PO_CA_PATH:
|
||||
mCAPath = value;
|
||||
break;
|
||||
|
||||
case HttpRequest::GP_CA_FILE:
|
||||
case HttpRequest::PO_CA_FILE:
|
||||
mCAFile = value;
|
||||
break;
|
||||
|
||||
case HttpRequest::GP_HTTP_PROXY:
|
||||
case HttpRequest::PO_HTTP_PROXY:
|
||||
mCAFile = value;
|
||||
break;
|
||||
|
||||
|
|
@ -106,69 +103,54 @@ HttpStatus HttpPolicyGlobal::set(HttpRequest::EGlobalPolicy opt, const std::stri
|
|||
return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
|
||||
}
|
||||
|
||||
mSetMask |= 1UL << int(opt);
|
||||
return HttpStatus();
|
||||
}
|
||||
|
||||
|
||||
HttpStatus HttpPolicyGlobal::get(HttpRequest::EGlobalPolicy opt, long * value)
|
||||
HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, long * value) const
|
||||
{
|
||||
static const HttpStatus not_set(HttpStatus::LLCORE, HE_OPT_NOT_SET);
|
||||
long * src(NULL);
|
||||
|
||||
switch (opt)
|
||||
{
|
||||
case HttpRequest::GP_CONNECTION_LIMIT:
|
||||
src = &mConnectionLimit;
|
||||
case HttpRequest::PO_CONNECTION_LIMIT:
|
||||
*value = mConnectionLimit;
|
||||
break;
|
||||
|
||||
case HttpRequest::GP_TRACE:
|
||||
src = &mTrace;
|
||||
case HttpRequest::PO_TRACE:
|
||||
*value = mTrace;
|
||||
break;
|
||||
|
||||
case HttpRequest::GP_LLPROXY:
|
||||
src = &mUseLLProxy;
|
||||
case HttpRequest::PO_LLPROXY:
|
||||
*value = mUseLLProxy;
|
||||
break;
|
||||
|
||||
default:
|
||||
return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
|
||||
}
|
||||
|
||||
if (! (mSetMask & (1UL << int(opt))))
|
||||
return not_set;
|
||||
|
||||
*value = *src;
|
||||
return HttpStatus();
|
||||
}
|
||||
|
||||
|
||||
HttpStatus HttpPolicyGlobal::get(HttpRequest::EGlobalPolicy opt, const std::string ** value)
|
||||
HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, std::string * value) const
|
||||
{
|
||||
static const HttpStatus not_set(HttpStatus::LLCORE, HE_OPT_NOT_SET);
|
||||
const std::string * src(NULL);
|
||||
|
||||
switch (opt)
|
||||
{
|
||||
case HttpRequest::GP_CA_PATH:
|
||||
src = &mCAPath;
|
||||
case HttpRequest::PO_CA_PATH:
|
||||
*value = mCAPath;
|
||||
break;
|
||||
|
||||
case HttpRequest::GP_CA_FILE:
|
||||
src = &mCAFile;
|
||||
case HttpRequest::PO_CA_FILE:
|
||||
*value = mCAFile;
|
||||
break;
|
||||
|
||||
case HttpRequest::GP_HTTP_PROXY:
|
||||
src = &mHttpProxy;
|
||||
case HttpRequest::PO_HTTP_PROXY:
|
||||
*value = mHttpProxy;
|
||||
break;
|
||||
|
||||
default:
|
||||
return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
|
||||
}
|
||||
|
||||
if (! (mSetMask & (1UL << int(opt))))
|
||||
return not_set;
|
||||
|
||||
*value = src;
|
||||
return HttpStatus();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
* Copyright (C) 2012-2013, 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
|
||||
|
|
@ -34,6 +34,18 @@
|
|||
namespace LLCore
|
||||
{
|
||||
|
||||
/// Options struct for global policy options.
|
||||
///
|
||||
/// Combines both raw blob data access with semantics-enforcing
|
||||
/// set/get interfaces. For internal operations by the worker
|
||||
/// thread, just grab the setting directly from instance and test/use
|
||||
/// as needed. When attached to external APIs (the public API
|
||||
/// options interfaces) the set/get methods are available to
|
||||
/// enforce correct ranges, data types, contexts, etc. and suitable
|
||||
/// status values are returned.
|
||||
///
|
||||
/// Threading: Single-threaded. In practice, init thread before
|
||||
/// worker starts, worker thread after.
|
||||
class HttpPolicyGlobal
|
||||
{
|
||||
public:
|
||||
|
|
@ -46,13 +58,12 @@ private:
|
|||
HttpPolicyGlobal(const HttpPolicyGlobal &); // Not defined
|
||||
|
||||
public:
|
||||
HttpStatus set(HttpRequest::EGlobalPolicy opt, long value);
|
||||
HttpStatus set(HttpRequest::EGlobalPolicy opt, const std::string & value);
|
||||
HttpStatus get(HttpRequest::EGlobalPolicy opt, long * value);
|
||||
HttpStatus get(HttpRequest::EGlobalPolicy opt, const std::string ** value);
|
||||
HttpStatus set(HttpRequest::EPolicyOption opt, long value);
|
||||
HttpStatus set(HttpRequest::EPolicyOption opt, const std::string & value);
|
||||
HttpStatus get(HttpRequest::EPolicyOption opt, long * value) const;
|
||||
HttpStatus get(HttpRequest::EPolicyOption opt, std::string * value) const;
|
||||
|
||||
public:
|
||||
unsigned long mSetMask;
|
||||
long mConnectionLimit;
|
||||
std::string mCAPath;
|
||||
std::string mCAFile;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
* Copyright (C) 2012-2013, 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
|
||||
|
|
@ -43,6 +43,17 @@
|
|||
namespace LLCore
|
||||
{
|
||||
|
||||
const HttpService::OptionDescriptor HttpService::sOptionDesc[] =
|
||||
{ // isLong isDynamic isGlobal isClass
|
||||
{ true, true, true, true }, // PO_CONNECTION_LIMIT
|
||||
{ true, true, false, true }, // PO_PER_HOST_CONNECTION_LIMIT
|
||||
{ false, false, true, false }, // PO_CA_PATH
|
||||
{ false, false, true, false }, // PO_CA_FILE
|
||||
{ false, true, true, false }, // PO_HTTP_PROXY
|
||||
{ true, true, true, false }, // PO_LLPROXY
|
||||
{ true, true, true, false }, // PO_TRACE
|
||||
{ true, true, false, true } // PO_ENABLE_PIPELINING
|
||||
};
|
||||
HttpService * HttpService::sInstance(NULL);
|
||||
volatile HttpService::EState HttpService::sState(NOT_INITIALIZED);
|
||||
|
||||
|
|
@ -51,12 +62,9 @@ HttpService::HttpService()
|
|||
mExitRequested(0U),
|
||||
mThread(NULL),
|
||||
mPolicy(NULL),
|
||||
mTransport(NULL)
|
||||
{
|
||||
// Create the default policy class
|
||||
HttpPolicyClass pol_class;
|
||||
mPolicyClasses.push_back(pol_class);
|
||||
}
|
||||
mTransport(NULL),
|
||||
mLastPolicy(0)
|
||||
{}
|
||||
|
||||
|
||||
HttpService::~HttpService()
|
||||
|
|
@ -146,13 +154,8 @@ void HttpService::term()
|
|||
|
||||
HttpRequest::policy_t HttpService::createPolicyClass()
|
||||
{
|
||||
const HttpRequest::policy_t policy_class(mPolicyClasses.size());
|
||||
if (policy_class >= HTTP_POLICY_CLASS_LIMIT)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
mPolicyClasses.push_back(HttpPolicyClass());
|
||||
return policy_class;
|
||||
mLastPolicy = mPolicy->createPolicyClass();
|
||||
return mLastPolicy;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -185,8 +188,8 @@ void HttpService::startThread()
|
|||
}
|
||||
|
||||
// Push current policy definitions, enable policy & transport components
|
||||
mPolicy->start(mPolicyGlobal, mPolicyClasses);
|
||||
mTransport->start(mPolicyClasses.size());
|
||||
mPolicy->start();
|
||||
mTransport->start(mLastPolicy + 1);
|
||||
|
||||
mThread = new LLCoreInt::HttpThread(boost::bind(&HttpService::threadRun, this, _1));
|
||||
sState = RUNNING;
|
||||
|
|
@ -319,7 +322,7 @@ HttpService::ELoopSpeed HttpService::processRequestQueue(ELoopSpeed loop)
|
|||
{
|
||||
// Setup for subsequent tracing
|
||||
long tracing(HTTP_TRACE_OFF);
|
||||
mPolicy->getGlobalOptions().get(HttpRequest::GP_TRACE, &tracing);
|
||||
mPolicy->getGlobalOptions().get(HttpRequest::PO_TRACE, &tracing);
|
||||
op->mTracing = (std::max)(op->mTracing, int(tracing));
|
||||
|
||||
if (op->mTracing > HTTP_TRACE_OFF)
|
||||
|
|
@ -342,4 +345,137 @@ HttpService::ELoopSpeed HttpService::processRequestQueue(ELoopSpeed loop)
|
|||
}
|
||||
|
||||
|
||||
HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
|
||||
long * ret_value)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
|
||||
long value, long * ret_value)
|
||||
{
|
||||
HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
|
||||
|
||||
if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range
|
||||
|| opt >= HttpRequest::PO_LAST // ditto
|
||||
|| (! sOptionDesc[opt].mIsLong) // datatype is 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 && 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// Only string values are global at this time
|
||||
if (pclass == HttpRequest::GLOBAL_POLICY_ID)
|
||||
{
|
||||
HttpPolicyGlobal & opts(mPolicy->getGlobalOptions());
|
||||
|
||||
status = opts.set(opt, value);
|
||||
if (status && ret_value)
|
||||
{
|
||||
status = opts.get(opt, ret_value);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace LLCore
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
* Copyright (C) 2012-2013, 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
|
||||
|
|
@ -53,6 +53,7 @@ namespace LLCore
|
|||
class HttpRequestQueue;
|
||||
class HttpPolicy;
|
||||
class HttpLibcurl;
|
||||
class HttpOpSetGet;
|
||||
|
||||
|
||||
/// The HttpService class does the work behind the request queue. It
|
||||
|
|
@ -106,7 +107,7 @@ public:
|
|||
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();
|
||||
|
||||
|
|
@ -136,7 +137,7 @@ public:
|
|||
/// acquires its weaknesses.
|
||||
static bool isStopped();
|
||||
|
||||
/// Threading: callable by consumer thread *once*.
|
||||
/// Threading: callable by init thread *once*.
|
||||
void startThread();
|
||||
|
||||
/// Threading: callable by worker thread.
|
||||
|
|
@ -180,28 +181,39 @@ public:
|
|||
return *mRequestQueue;
|
||||
}
|
||||
|
||||
/// Threading: callable by consumer thread.
|
||||
HttpPolicyGlobal & getGlobalOptions()
|
||||
{
|
||||
return mPolicyGlobal;
|
||||
}
|
||||
|
||||
/// Threading: callable by consumer thread.
|
||||
HttpRequest::policy_t createPolicyClass();
|
||||
|
||||
/// Threading: callable by consumer thread.
|
||||
HttpPolicyClass & getClassOptions(HttpRequest::policy_t policy_class)
|
||||
{
|
||||
llassert(policy_class >= 0 && policy_class < mPolicyClasses.size());
|
||||
return mPolicyClasses[policy_class];
|
||||
}
|
||||
|
||||
protected:
|
||||
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;
|
||||
};
|
||||
|
||||
HttpStatus getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
|
||||
long * ret_value);
|
||||
HttpStatus getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
|
||||
std::string * 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);
|
||||
|
||||
protected:
|
||||
static const OptionDescriptor sOptionDesc[HttpRequest::PO_LAST];
|
||||
static HttpService * sInstance;
|
||||
|
||||
// === shared data ===
|
||||
|
|
@ -210,13 +222,13 @@ protected:
|
|||
LLAtomicU32 mExitRequested;
|
||||
LLCoreInt::HttpThread * mThread;
|
||||
|
||||
// === consumer-thread-only data ===
|
||||
HttpPolicyGlobal mPolicyGlobal;
|
||||
std::vector<HttpPolicyClass> mPolicyClasses;
|
||||
|
||||
// === 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
|
||||
|
|
|
|||
|
|
@ -236,9 +236,10 @@ int main(int argc, char** argv)
|
|||
// Initialization
|
||||
init_curl();
|
||||
LLCore::HttpRequest::createService();
|
||||
LLCore::HttpRequest::setPolicyClassOption(LLCore::HttpRequest::DEFAULT_POLICY_ID,
|
||||
LLCore::HttpRequest::CP_CONNECTION_LIMIT,
|
||||
concurrency_limit);
|
||||
LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_CONNECTION_LIMIT,
|
||||
LLCore::HttpRequest::DEFAULT_POLICY_ID,
|
||||
concurrency_limit,
|
||||
NULL);
|
||||
LLCore::HttpRequest::startThread();
|
||||
|
||||
// Get service point
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
* Copyright (C) 2012-2013, 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
|
||||
|
|
@ -29,9 +29,9 @@
|
|||
|
||||
/// @package LLCore::HTTP
|
||||
///
|
||||
/// This library implements a high-level, Indra-code-free client interface to
|
||||
/// HTTP services based on actual patterns found in the viewer and simulator.
|
||||
/// Interfaces are similar to those supplied by the legacy classes
|
||||
/// This library implements a high-level, Indra-code-free (somewhat) client
|
||||
/// interface to HTTP services based on actual patterns found in the viewer
|
||||
/// and simulator. Interfaces are similar to those supplied by the legacy classes
|
||||
/// LLCurlRequest and LLHTTPClient. To that is added a policy scheme that
|
||||
/// allows an application to specify connection behaviors: limits on
|
||||
/// connections, HTTP keepalive, HTTP pipelining, retry-on-error limits, etc.
|
||||
|
|
@ -52,7 +52,7 @@
|
|||
/// - "llcorehttp/httprequest.h"
|
||||
/// - "llcorehttp/httpresponse.h"
|
||||
///
|
||||
/// The library is still under early development and particular users
|
||||
/// The library is still under development and particular users
|
||||
/// may need access to internal implementation details that are found
|
||||
/// in the _*.h header files. But this is a crutch to be avoided if at
|
||||
/// all possible and probably indicates some interface work is neeeded.
|
||||
|
|
@ -66,6 +66,8 @@
|
|||
/// . CRYPTO_set_id_callback(...)
|
||||
/// - HttpRequest::createService() called to instantiate singletons
|
||||
/// and support objects.
|
||||
/// - HttpRequest::startThread() to kick off the worker thread and
|
||||
/// begin servicing requests.
|
||||
///
|
||||
/// An HTTP consumer in an application, and an application may have many
|
||||
/// consumers, does a few things:
|
||||
|
|
@ -91,10 +93,12 @@
|
|||
/// objects.
|
||||
/// - Do completion processing in your onCompletion() method.
|
||||
///
|
||||
/// Code fragments:
|
||||
/// Rather than a poorly-maintained example in comments, look in the
|
||||
/// example subdirectory which is a minimal yet functional tool to do
|
||||
/// GET request performance testing. With four calls:
|
||||
/// Code fragments.
|
||||
///
|
||||
/// Initialization. Rather than a poorly-maintained example in
|
||||
/// comments, look in the example subdirectory which is a minimal
|
||||
/// yet functional tool to do GET request performance testing.
|
||||
/// With four calls:
|
||||
///
|
||||
/// init_curl();
|
||||
/// LLCore::HttpRequest::createService();
|
||||
|
|
@ -103,7 +107,85 @@
|
|||
///
|
||||
/// the program is basically ready to issue requests.
|
||||
///
|
||||
|
||||
/// HttpHandler. Having started life as a non-indra library,
|
||||
/// this code broke away from the classic Responder model and
|
||||
/// introduced a handler class to represent an interface for
|
||||
/// request responses. This is a non-reference-counted entity
|
||||
/// which can be used as a base class or a mixin. An instance
|
||||
/// of a handler can be used for each request or can be shared
|
||||
/// among any number of requests. Your choice but expect to
|
||||
/// code something like the following:
|
||||
///
|
||||
/// class AppHandler : public LLCore::HttpHandler
|
||||
/// {
|
||||
/// public:
|
||||
/// virtual void onCompleted(HttpHandle handle,
|
||||
/// HttpResponse * response)
|
||||
/// {
|
||||
/// ...
|
||||
/// }
|
||||
/// ...
|
||||
/// };
|
||||
/// ...
|
||||
/// handler = new handler(...);
|
||||
///
|
||||
///
|
||||
/// Issuing requests. Using 'hr' above,
|
||||
///
|
||||
/// hr->requestGet(HttpRequest::DEFAULT_POLICY_ID,
|
||||
/// 0, // Priority, not used yet
|
||||
/// url,
|
||||
/// NULL, // options
|
||||
/// NULL, // additional headers
|
||||
/// handler);
|
||||
///
|
||||
/// If that returns a value other than LLCORE_HTTP_HANDLE_INVALID,
|
||||
/// the request was successfully issued and there will eventally
|
||||
/// be a status delivered to the handler. If invalid is returnedd,
|
||||
/// the actual status can be retrieved by calling hr->getStatus().
|
||||
///
|
||||
/// Completing requests and delivering notifications. Operations
|
||||
/// are all performed by the worker thread and will be driven to
|
||||
/// completion regardless of caller actions. Notification of
|
||||
/// completion (success or failure) is done by calls to
|
||||
/// HttpRequest::update() which will invoke handlers for completed
|
||||
/// requests:
|
||||
///
|
||||
/// hr->update(0);
|
||||
/// // Callbacks into handler->onCompleted()
|
||||
///
|
||||
///
|
||||
/// Threads.
|
||||
///
|
||||
/// Threads are supported and used by this library. The various
|
||||
/// classes, methods and members are documented with thread
|
||||
/// constraints which programmers must follow and which are
|
||||
/// defined as follows:
|
||||
///
|
||||
/// 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,
|
||||
/// 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
|
||||
/// with this thread directly but some APIs are reserved
|
||||
/// to it.
|
||||
/// any Consumer or worker thread.
|
||||
///
|
||||
/// For the most part, API users will not have to do much in the
|
||||
/// way of ensuring thread safely. However, there is a tremendous
|
||||
/// amount of sharing between threads of read-only data. So when
|
||||
/// documentation declares that an option or header instance
|
||||
/// becomes shared between consumer and worker, the consumer must
|
||||
/// not modify the shared object.
|
||||
///
|
||||
/// Internally, there is almost no thread synchronization. During
|
||||
/// normal operations (non-init, non-term), only the request queue
|
||||
/// and the multiple reply queues are shared between threads and
|
||||
/// only here are mutexes used.
|
||||
///
|
||||
|
||||
#include "linden_common.h" // Modifies curl/curl.h interfaces
|
||||
|
||||
|
|
@ -239,9 +321,10 @@ struct HttpStatus
|
|||
return *this;
|
||||
}
|
||||
|
||||
static const type_enum_t EXT_CURL_EASY = 0;
|
||||
static const type_enum_t EXT_CURL_MULTI = 1;
|
||||
static const type_enum_t LLCORE = 2;
|
||||
static const type_enum_t EXT_CURL_EASY = 0; ///< mStatus is an error from a curl_easy_*() call
|
||||
static const type_enum_t EXT_CURL_MULTI = 1; ///< mStatus is an error from a curl_multi_*() call
|
||||
static const type_enum_t LLCORE = 2; ///< mStatus is an HE_* error code
|
||||
///< 100-999 directly represent HTTP status codes
|
||||
|
||||
type_enum_t mType;
|
||||
short mStatus;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
* Copyright (C) 2012-2013, 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
|
||||
|
|
@ -54,12 +54,8 @@ namespace LLCore
|
|||
// ====================================
|
||||
|
||||
|
||||
HttpRequest::policy_t HttpRequest::sNextPolicyID(1);
|
||||
|
||||
|
||||
HttpRequest::HttpRequest()
|
||||
: //HttpHandler(),
|
||||
mReplyQueue(NULL),
|
||||
: mReplyQueue(NULL),
|
||||
mRequestQueue(NULL)
|
||||
{
|
||||
mRequestQueue = HttpRequestQueue::instanceOf();
|
||||
|
|
@ -90,26 +86,6 @@ HttpRequest::~HttpRequest()
|
|||
// ====================================
|
||||
|
||||
|
||||
HttpStatus HttpRequest::setPolicyGlobalOption(EGlobalPolicy opt, long value)
|
||||
{
|
||||
if (HttpService::RUNNING == HttpService::instanceOf()->getState())
|
||||
{
|
||||
return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC);
|
||||
}
|
||||
return HttpService::instanceOf()->getGlobalOptions().set(opt, value);
|
||||
}
|
||||
|
||||
|
||||
HttpStatus HttpRequest::setPolicyGlobalOption(EGlobalPolicy opt, const std::string & value)
|
||||
{
|
||||
if (HttpService::RUNNING == HttpService::instanceOf()->getState())
|
||||
{
|
||||
return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC);
|
||||
}
|
||||
return HttpService::instanceOf()->getGlobalOptions().set(opt, value);
|
||||
}
|
||||
|
||||
|
||||
HttpRequest::policy_t HttpRequest::createPolicyClass()
|
||||
{
|
||||
if (HttpService::RUNNING == HttpService::instanceOf()->getState())
|
||||
|
|
@ -120,15 +96,81 @@ HttpRequest::policy_t HttpRequest::createPolicyClass()
|
|||
}
|
||||
|
||||
|
||||
HttpStatus HttpRequest::setPolicyClassOption(policy_t policy_id,
|
||||
EClassPolicy opt,
|
||||
long value)
|
||||
HttpStatus HttpRequest::setStaticPolicyOption(EPolicyOption opt, policy_t pclass,
|
||||
long value, long * ret_value)
|
||||
{
|
||||
if (HttpService::RUNNING == HttpService::instanceOf()->getState())
|
||||
{
|
||||
return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC);
|
||||
}
|
||||
return HttpService::instanceOf()->getClassOptions(policy_id).set(opt, value);
|
||||
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)
|
||||
{
|
||||
if (HttpService::RUNNING == HttpService::instanceOf()->getState())
|
||||
{
|
||||
return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC);
|
||||
}
|
||||
return HttpService::instanceOf()->setPolicyOption(opt, pclass, value, ret_value);
|
||||
}
|
||||
|
||||
|
||||
HttpHandle HttpRequest::setPolicyOption(EPolicyOption opt, policy_t pclass,
|
||||
long value, HttpHandler * handler)
|
||||
{
|
||||
HttpStatus status;
|
||||
HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
|
||||
|
||||
HttpOpSetGet * op = new HttpOpSetGet();
|
||||
if (! (status = op->setupSet(opt, pclass, value)))
|
||||
{
|
||||
op->release();
|
||||
mLastReqStatus = status;
|
||||
return handle;
|
||||
}
|
||||
op->setReplyPath(mReplyQueue, handler);
|
||||
if (! (status = mRequestQueue->addOp(op))) // transfers refcount
|
||||
{
|
||||
op->release();
|
||||
mLastReqStatus = status;
|
||||
return handle;
|
||||
}
|
||||
|
||||
mLastReqStatus = status;
|
||||
handle = static_cast<HttpHandle>(op);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
HttpHandle HttpRequest::setPolicyOption(EPolicyOption opt, policy_t pclass,
|
||||
const std::string & value, HttpHandler * handler)
|
||||
{
|
||||
HttpStatus status;
|
||||
HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
|
||||
|
||||
HttpOpSetGet * op = new HttpOpSetGet();
|
||||
if (! (status = op->setupSet(opt, pclass, value)))
|
||||
{
|
||||
op->release();
|
||||
mLastReqStatus = status;
|
||||
return handle;
|
||||
}
|
||||
op->setReplyPath(mReplyQueue, handler);
|
||||
if (! (status = mRequestQueue->addOp(op))) // transfers refcount
|
||||
{
|
||||
op->release();
|
||||
mLastReqStatus = status;
|
||||
return handle;
|
||||
}
|
||||
|
||||
mLastReqStatus = status;
|
||||
handle = static_cast<HttpHandle>(op);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -474,31 +516,6 @@ HttpHandle HttpRequest::requestSpin(int mode)
|
|||
return handle;
|
||||
}
|
||||
|
||||
// ====================================
|
||||
// Dynamic Policy Methods
|
||||
// ====================================
|
||||
|
||||
HttpHandle HttpRequest::requestSetHttpProxy(const std::string & proxy, HttpHandler * handler)
|
||||
{
|
||||
HttpStatus status;
|
||||
HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
|
||||
|
||||
HttpOpSetGet * op = new HttpOpSetGet();
|
||||
op->setupSet(GP_HTTP_PROXY, proxy);
|
||||
op->setReplyPath(mReplyQueue, handler);
|
||||
if (! (status = mRequestQueue->addOp(op))) // transfers refcount
|
||||
{
|
||||
op->release();
|
||||
mLastReqStatus = status;
|
||||
return handle;
|
||||
}
|
||||
|
||||
mLastReqStatus = status;
|
||||
handle = static_cast<HttpHandle>(op);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace LLCore
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@ class BufferArray;
|
|||
/// The class supports the current HTTP request operations:
|
||||
///
|
||||
/// - requestGetByteRange: GET with Range header for a single range of bytes
|
||||
/// - requestGet:
|
||||
/// - requestPost:
|
||||
/// - requestPut:
|
||||
///
|
||||
/// Policy Classes
|
||||
///
|
||||
|
|
@ -100,61 +103,9 @@ public:
|
|||
|
||||
/// Represents a default, catch-all policy class that guarantees
|
||||
/// eventual service for any HTTP request.
|
||||
static const int DEFAULT_POLICY_ID = 0;
|
||||
|
||||
enum EGlobalPolicy
|
||||
{
|
||||
/// 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.
|
||||
GP_CONNECTION_LIMIT,
|
||||
|
||||
/// String containing a system-appropriate directory name
|
||||
/// where SSL certs are stored.
|
||||
GP_CA_PATH,
|
||||
|
||||
/// String giving a full path to a file containing SSL certs.
|
||||
GP_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.
|
||||
GP_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.
|
||||
GP_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.
|
||||
GP_TRACE
|
||||
};
|
||||
|
||||
/// Set a parameter on a global 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 value Desired value of option.
|
||||
/// @return Standard status code.
|
||||
static HttpStatus setPolicyGlobalOption(EGlobalPolicy opt, long value);
|
||||
static HttpStatus setPolicyGlobalOption(EGlobalPolicy opt, const std::string & value);
|
||||
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.
|
||||
///
|
||||
|
|
@ -171,29 +122,93 @@ public:
|
|||
///
|
||||
static policy_t createPolicyClass();
|
||||
|
||||
enum EClassPolicy
|
||||
enum EPolicyOption
|
||||
{
|
||||
/// Limits the number of connections used for the class.
|
||||
CP_CONNECTION_LIMIT,
|
||||
/// 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.
|
||||
CP_PER_HOST_CONNECTION_LIMIT,
|
||||
PO_PER_HOST_CONNECTION_LIMIT,
|
||||
|
||||
/// String containing a system-appropriate directory name
|
||||
/// where SSL certs are stored.
|
||||
PO_CA_PATH,
|
||||
|
||||
/// String giving a full path to a file containing SSL certs.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
PO_TRACE,
|
||||
|
||||
/// Suitable requests are allowed to pipeline on their
|
||||
/// connections when they ask for it.
|
||||
CP_ENABLE_PIPELINING
|
||||
PO_ENABLE_PIPELINING,
|
||||
|
||||
PO_LAST // Always at end
|
||||
};
|
||||
|
||||
|
||||
/// 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);
|
||||
|
||||
/// 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 policy_id ID of class as returned by @see createPolicyClass().
|
||||
/// @param opt Enum of option to be set.
|
||||
/// @param value Desired value of option.
|
||||
/// @return Standard status code.
|
||||
static HttpStatus setPolicyClassOption(policy_t policy_id, EClassPolicy opt, long value);
|
||||
/// @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 * handler);
|
||||
HttpHandle setPolicyOption(EPolicyOption opt, policy_t pclass, const std::string & value,
|
||||
HttpHandler * handler);
|
||||
|
||||
/// @}
|
||||
|
||||
|
|
@ -495,16 +510,6 @@ public:
|
|||
|
||||
/// @}
|
||||
|
||||
/// @name DynamicPolicyMethods
|
||||
///
|
||||
/// @{
|
||||
|
||||
/// Request that a running transport pick up a new proxy setting.
|
||||
/// An empty string will indicate no proxy is to be used.
|
||||
HttpHandle requestSetHttpProxy(const std::string & proxy, HttpHandler * handler);
|
||||
|
||||
/// @}
|
||||
|
||||
protected:
|
||||
void generateNotification(HttpOperation * op);
|
||||
|
||||
|
|
@ -526,7 +531,6 @@ private:
|
|||
/// Must be established before any threading is allowed to
|
||||
/// start.
|
||||
///
|
||||
static policy_t sNextPolicyID;
|
||||
|
||||
/// @}
|
||||
// End Global State
|
||||
|
|
|
|||
|
|
@ -1213,7 +1213,7 @@ void HttpRequestTestObjectType::test<12>()
|
|||
HttpRequest::createService();
|
||||
|
||||
// Enable tracing
|
||||
HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_TRACE, 2);
|
||||
HttpRequest::setStaticPolicyOption(HttpRequest::PO_TRACE, HttpRequest::DEFAULT_POLICY_ID, 2, NULL);
|
||||
|
||||
// Start threading early so that thread memory is invariant
|
||||
// over the test.
|
||||
|
|
@ -1331,7 +1331,7 @@ void HttpRequestTestObjectType::test<13>()
|
|||
HttpRequest::createService();
|
||||
|
||||
// Enable tracing
|
||||
HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_TRACE, 2);
|
||||
HttpRequest::setStaticPolicyOption(HttpRequest::PO_TRACE, HttpRequest::DEFAULT_POLICY_ID, 2, NULL);
|
||||
|
||||
// Start threading early so that thread memory is invariant
|
||||
// over the test.
|
||||
|
|
@ -2972,6 +2972,142 @@ void HttpRequestTestObjectType::test<21>()
|
|||
}
|
||||
|
||||
|
||||
template <> template <>
|
||||
void HttpRequestTestObjectType::test<22>()
|
||||
{
|
||||
ScopedCurlInit ready;
|
||||
|
||||
set_test_name("HttpRequest GET 503s with 'Retry-After'");
|
||||
|
||||
// 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");
|
||||
std::string url_base(get_base_url() + "/503/"); // path to 503 generators
|
||||
|
||||
// record the total amount of dynamically allocated memory
|
||||
mMemTotal = GetMemTotal();
|
||||
mHandlerCalls = 0;
|
||||
|
||||
HttpRequest * req = NULL;
|
||||
HttpOptions * opts = NULL;
|
||||
|
||||
try
|
||||
{
|
||||
// Get singletons created
|
||||
HttpRequest::createService();
|
||||
|
||||
// Start threading early so that thread memory is invariant
|
||||
// over the test.
|
||||
HttpRequest::startThread();
|
||||
|
||||
// create a new ref counted object with an implicit reference
|
||||
req = new HttpRequest();
|
||||
ensure("Memory allocated on construction", mMemTotal < GetMemTotal());
|
||||
|
||||
opts = new HttpOptions();
|
||||
opts->setRetries(1); // 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,
|
||||
0U,
|
||||
url.str(),
|
||||
0,
|
||||
0,
|
||||
opts,
|
||||
NULL,
|
||||
&handler);
|
||||
|
||||
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(300); // One retry but several seconds needed
|
||||
while (count++ < limit && mHandlerCalls < url_limit)
|
||||
{
|
||||
req->update(0);
|
||||
usleep(100000);
|
||||
}
|
||||
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(&handler);
|
||||
ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
|
||||
|
||||
// Run the notification pump again
|
||||
count = 0;
|
||||
limit = 100;
|
||||
while (count++ < limit && mHandlerCalls < 1)
|
||||
{
|
||||
req->update(1000000);
|
||||
usleep(100000);
|
||||
}
|
||||
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 = 10;
|
||||
while (count++ < limit && ! HttpService::isStopped())
|
||||
{
|
||||
usleep(100000);
|
||||
}
|
||||
ensure("Thread actually stopped running", HttpService::isStopped());
|
||||
|
||||
// release options
|
||||
opts->release();
|
||||
opts = NULL;
|
||||
|
||||
// release the request object
|
||||
delete req;
|
||||
req = NULL;
|
||||
|
||||
// Shut down service
|
||||
HttpRequest::destroyService();
|
||||
|
||||
#if defined(WIN32)
|
||||
// Can only do this memory test on Windows. On other platforms,
|
||||
// the LL logging system holds on to memory and produces what looks
|
||||
// like memory leaks...
|
||||
|
||||
// printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal());
|
||||
ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal());
|
||||
#endif
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
stop_thread(req);
|
||||
if (opts)
|
||||
{
|
||||
opts->release();
|
||||
opts = NULL;
|
||||
}
|
||||
delete req;
|
||||
HttpRequest::destroyService();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // end namespace tut
|
||||
|
||||
namespace
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
$LicenseInfo:firstyear=2008&license=viewerlgpl$
|
||||
Second Life Viewer Source Code
|
||||
Copyright (C) 2012, Linden Research, Inc.
|
||||
Copyright (C) 2012-2013, 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
|
||||
|
|
@ -47,6 +47,17 @@ from testrunner import freeport, run, debug, VERBOSE
|
|||
class TestHTTPRequestHandler(BaseHTTPRequestHandler):
|
||||
"""This subclass of BaseHTTPRequestHandler is to receive and echo
|
||||
LLSD-flavored messages sent by the C++ LLHTTPClient.
|
||||
|
||||
[Merge with viewer-cat later]
|
||||
- '/503/' Generate 503 responses with various kinds
|
||||
of 'retry-after' headers
|
||||
-- '/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: "
|
||||
-- '/503/4/' "Retry-After: (*#*(@*(@(")"
|
||||
-- '/503/5/' "Retry-After: aklsjflajfaklsfaklfasfklasdfklasdgahsdhgasdiogaioshdgo"
|
||||
-- '/503/6/' "Retry-After: 1 2 3 4 5 6 7 8 9 10"
|
||||
"""
|
||||
def read(self):
|
||||
# The following logic is adapted from the library module
|
||||
|
|
@ -107,7 +118,41 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler):
|
|||
if "/sleep/" in self.path:
|
||||
time.sleep(30)
|
||||
|
||||
if "fail" not in self.path:
|
||||
if "/503/" in self.path:
|
||||
# Tests for various kinds of 'Retry-After' header parsing
|
||||
body = None
|
||||
if "/503/0/" in self.path:
|
||||
self.send_response(503)
|
||||
self.send_header("retry-after", "2")
|
||||
elif "/503/1/" in self.path:
|
||||
self.send_response(503)
|
||||
self.send_header("retry-after", "Thu, 31 Dec 2043 23:59:59 GMT")
|
||||
elif "/503/2/" in self.path:
|
||||
self.send_response(503)
|
||||
self.send_header("retry-after", "Fri, 31 Dec 1999 23:59:59 GMT")
|
||||
elif "/503/3/" in self.path:
|
||||
self.send_response(503)
|
||||
self.send_header("retry-after", "")
|
||||
elif "/503/4/" in self.path:
|
||||
self.send_response(503)
|
||||
self.send_header("retry-after", "(*#*(@*(@(")
|
||||
elif "/503/5/" in self.path:
|
||||
self.send_response(503)
|
||||
self.send_header("retry-after", "aklsjflajfaklsfaklfasfklasdfklasdgahsdhgasdiogaioshdgo")
|
||||
elif "/503/6/" in self.path:
|
||||
self.send_response(503)
|
||||
self.send_header("retry-after", "1 2 3 4 5 6 7 8 9 10")
|
||||
else:
|
||||
# Unknown request
|
||||
self.send_response(400)
|
||||
body = "Unknown /503/ path in server"
|
||||
if "/reflect/" in self.path:
|
||||
self.reflect_headers()
|
||||
self.send_header("Content-type", "text/plain")
|
||||
self.end_headers()
|
||||
if body:
|
||||
self.wfile.write(body)
|
||||
elif "fail" not in self.path:
|
||||
data = data.copy() # we're going to modify
|
||||
# Ensure there's a "reply" key in data, even if there wasn't before
|
||||
data["reply"] = data.get("reply", llsd.LLSD("success"))
|
||||
|
|
|
|||
|
|
@ -105,8 +105,9 @@ void LLAppCoreHttp::init()
|
|||
}
|
||||
|
||||
// Point to our certs or SSH/https: will fail on connect
|
||||
status = LLCore::HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_CA_FILE,
|
||||
gDirUtilp->getCAFile());
|
||||
status = LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_CA_FILE,
|
||||
LLCore::HttpRequest::GLOBAL_POLICY_ID,
|
||||
gDirUtilp->getCAFile(), NULL);
|
||||
if (! status)
|
||||
{
|
||||
LL_ERRS("Init") << "Failed to set CA File for HTTP services. Reason: " << status.toString()
|
||||
|
|
@ -114,7 +115,9 @@ void LLAppCoreHttp::init()
|
|||
}
|
||||
|
||||
// Establish HTTP Proxy, if desired.
|
||||
status = LLCore::HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_LLPROXY, 1);
|
||||
status = LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_LLPROXY,
|
||||
LLCore::HttpRequest::GLOBAL_POLICY_ID,
|
||||
1, NULL);
|
||||
if (! status)
|
||||
{
|
||||
LL_WARNS("Init") << "Failed to set HTTP proxy for HTTP services. Reason: " << status.toString()
|
||||
|
|
@ -131,7 +134,9 @@ void LLAppCoreHttp::init()
|
|||
{
|
||||
long trace_level(0L);
|
||||
trace_level = long(gSavedSettings.getU32(http_trace));
|
||||
status = LLCore::HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_TRACE, trace_level);
|
||||
status = LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_TRACE,
|
||||
LLCore::HttpRequest::GLOBAL_POLICY_ID,
|
||||
trace_level, NULL);
|
||||
}
|
||||
|
||||
// Setup default policy and constrain if directed to
|
||||
|
|
@ -164,6 +169,9 @@ void LLAppCoreHttp::init()
|
|||
}
|
||||
}
|
||||
|
||||
// Need a request object to handle dynamic options before setting them
|
||||
mRequest = new LLCore::HttpRequest;
|
||||
|
||||
// Apply initial settings
|
||||
refreshSettings(true);
|
||||
|
||||
|
|
@ -175,8 +183,6 @@ void LLAppCoreHttp::init()
|
|||
<< LL_ENDL;
|
||||
}
|
||||
|
||||
mRequest = new LLCore::HttpRequest;
|
||||
|
||||
// Register signals for settings and state changes
|
||||
for (int i(0); i < LL_ARRAY_SIZE(init_data); ++i)
|
||||
{
|
||||
|
|
@ -287,12 +293,13 @@ void LLAppCoreHttp::refreshSettings(bool initial)
|
|||
// Set it and report
|
||||
// *TODO: These are intended to be per-host limits when we can
|
||||
// support that in llcorehttp/libcurl.
|
||||
LLCore::HttpStatus status;
|
||||
status = LLCore::HttpRequest::setPolicyClassOption(mPolicies[policy],
|
||||
LLCore::HttpRequest::CP_CONNECTION_LIMIT,
|
||||
setting);
|
||||
if (! status)
|
||||
LLCore::HttpHandle handle;
|
||||
handle = mRequest->setPolicyOption(LLCore::HttpRequest::PO_CONNECTION_LIMIT,
|
||||
mPolicies[policy],
|
||||
setting, NULL);
|
||||
if (LLCORE_HTTP_HANDLE_INVALID == handle)
|
||||
{
|
||||
LLCore::HttpStatus status(mRequest->getStatus());
|
||||
LL_WARNS("Init") << "Unable to set " << init_data[i].mUsage
|
||||
<< " concurrency. Reason: " << status.toString()
|
||||
<< LL_ENDL;
|
||||
|
|
|
|||
Loading…
Reference in New Issue