SH-4312 Configuration data between viewer and llcorehttp is clumsy.

Fri, 12 Jul 2013 15:00:24 -0400

author
Monty Brandenberg <monty@lindenlab.com>
date
Fri, 12 Jul 2013 15:00:24 -0400
changeset 40694
4291c258ebc4
parent 40693
206b5cdfe4d5
child 40695
916573da16a0

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.

indra/llcorehttp/_httpinternal.h file | annotate | diff | revisions
indra/llcorehttp/_httplibcurl.h file | annotate | diff | revisions
indra/llcorehttp/_httpoperation.h file | annotate | diff | revisions
indra/llcorehttp/_httpoprequest.cpp file | annotate | diff | revisions
indra/llcorehttp/_httpopsetget.cpp file | annotate | diff | revisions
indra/llcorehttp/_httpopsetget.h file | annotate | diff | revisions
indra/llcorehttp/_httppolicy.cpp file | annotate | diff | revisions
indra/llcorehttp/_httppolicy.h file | annotate | diff | revisions
indra/llcorehttp/_httppolicyclass.cpp file | annotate | diff | revisions
indra/llcorehttp/_httppolicyclass.h file | annotate | diff | revisions
indra/llcorehttp/_httppolicyglobal.cpp file | annotate | diff | revisions
indra/llcorehttp/_httppolicyglobal.h file | annotate | diff | revisions
indra/llcorehttp/_httpservice.cpp file | annotate | diff | revisions
indra/llcorehttp/_httpservice.h file | annotate | diff | revisions
indra/llcorehttp/examples/http_texture_load.cpp file | annotate | diff | revisions
indra/llcorehttp/httpcommon.h file | annotate | diff | revisions
indra/llcorehttp/httprequest.cpp file | annotate | diff | revisions
indra/llcorehttp/httprequest.h file | annotate | diff | revisions
indra/llcorehttp/tests/test_httprequest.hpp file | annotate | diff | revisions
indra/llcorehttp/tests/test_llcorehttp_peer.py file | annotate | diff | revisions
indra/newview/llappcorehttp.cpp file | annotate | diff | revisions
     1.1 --- a/indra/llcorehttp/_httpinternal.h	Mon Jul 08 20:31:09 2013 +0000
     1.2 +++ b/indra/llcorehttp/_httpinternal.h	Fri Jul 12 15:00:24 2013 -0400
     1.3 @@ -36,7 +36,8 @@
     1.4  // General library to-do list
     1.5  //
     1.6  // - Implement policy classes.  Structure is mostly there just didn't
     1.7 -//   need it for the first consumer.
     1.8 +//   need it for the first consumer.  [Classes are there.  More
     1.9 +//   advanced features, like borrowing, aren't there yet.]
    1.10  // - Consider Removing 'priority' from the request interface.  Its use
    1.11  //   in an always active class can lead to starvation of low-priority
    1.12  //   requests.  Requires coodination of priority values across all
    1.13 @@ -46,6 +47,7 @@
    1.14  //   may not really need it.
    1.15  // - Set/get for global policy and policy classes is clumsy.  Rework
    1.16  //   it heading in a direction that allows for more dynamic behavior.
    1.17 +//   [Mostly fixed]
    1.18  // - Move HttpOpRequest::prepareRequest() to HttpLibcurl for the
    1.19  //   pedantic.
    1.20  // - Update downloader and other long-duration services are going to
    1.21 @@ -73,7 +75,7 @@
    1.22  //   the main source file.
    1.23  // - Expand areas of usage eventually leading to the removal of LLCurl.
    1.24  //   Rough order of expansion:
    1.25 -//   .  Mesh fetch
    1.26 +//   .  Mesh fetch [Underway]
    1.27  //   .  Avatar names
    1.28  //   .  Group membership lists
    1.29  //   .  Caps access in general
     2.1 --- a/indra/llcorehttp/_httplibcurl.h	Mon Jul 08 20:31:09 2013 +0000
     2.2 +++ b/indra/llcorehttp/_httplibcurl.h	Fri Jul 12 15:00:24 2013 -0400
     2.3 @@ -4,7 +4,7 @@
     2.4   *
     2.5   * $LicenseInfo:firstyear=2012&license=viewerlgpl$
     2.6   * Second Life Viewer Source Code
     2.7 - * Copyright (C) 2012, Linden Research, Inc.
     2.8 + * Copyright (C) 2012-2013, Linden Research, Inc.
     2.9   *
    2.10   * This library is free software; you can redistribute it and/or
    2.11   * modify it under the terms of the GNU Lesser General Public
    2.12 @@ -71,16 +71,22 @@
    2.13  	///
    2.14  	/// @return			Indication of how long this method is
    2.15  	///					willing to wait for next service call.
    2.16 +	///
    2.17 +	/// Threading:  called by worker thread.
    2.18  	HttpService::ELoopSpeed processTransport();
    2.19  
    2.20  	/// Add request to the active list.  Caller is expected to have
    2.21  	/// provided us with a reference count on the op to hold the
    2.22  	/// request.  (No additional references will be added.)
    2.23 +	///
    2.24 +	/// Threading:  called by worker thread.
    2.25  	void addOp(HttpOpRequest * op);
    2.26  
    2.27  	/// One-time call to set the number of policy classes to be
    2.28  	/// serviced and to create the resources for each.  Value
    2.29  	/// must agree with HttpPolicy::setPolicies() call.
    2.30 +	///
    2.31 +	/// Threading:  called by init thread.
    2.32  	void start(int policy_count);
    2.33  
    2.34  	/// Synchronously stop libcurl operations.  All active requests
    2.35 @@ -91,9 +97,13 @@
    2.36  	/// respective reply queues.
    2.37  	///
    2.38  	/// Can be restarted with a start() call.
    2.39 +	///
    2.40 +	/// Threading:  called by worker thread.
    2.41  	void shutdown();
    2.42  
    2.43  	/// Return global and per-class counts of active requests.
    2.44 +	///
    2.45 +	/// Threading:  called by worker thread.
    2.46  	int getActiveCount() const;
    2.47  	int getActiveCountInClass(int policy_class) const;
    2.48  
    2.49 @@ -103,6 +113,7 @@
    2.50  	///
    2.51  	/// @return			True if handle was found and operation canceled.
    2.52  	///
    2.53 +	/// Threading:  called by worker thread.
    2.54  	bool cancel(HttpHandle handle);
    2.55  
    2.56  protected:
    2.57 @@ -121,7 +132,7 @@
    2.58  	HttpService *		mService;				// Simple reference, not owner
    2.59  	active_set_t		mActiveOps;
    2.60  	int					mPolicyCount;
    2.61 -	CURLM **			mMultiHandles;
    2.62 +	CURLM **			mMultiHandles;			// One handle per policy class
    2.63  }; // end class HttpLibcurl
    2.64  
    2.65  }  // end namespace LLCore
     3.1 --- a/indra/llcorehttp/_httpoperation.h	Mon Jul 08 20:31:09 2013 +0000
     3.2 +++ b/indra/llcorehttp/_httpoperation.h	Fri Jul 12 15:00:24 2013 -0400
     3.3 @@ -4,7 +4,7 @@
     3.4   *
     3.5   * $LicenseInfo:firstyear=2012&license=viewerlgpl$
     3.6   * Second Life Viewer Source Code
     3.7 - * Copyright (C) 2012, Linden Research, Inc.
     3.8 + * Copyright (C) 2012-2013, Linden Research, Inc.
     3.9   *
    3.10   * This library is free software; you can redistribute it and/or
    3.11   * modify it under the terms of the GNU Lesser General Public
    3.12 @@ -72,7 +72,7 @@
    3.13  class HttpOperation : public LLCoreInt::RefCounted
    3.14  {
    3.15  public:
    3.16 -	/// Threading:  called by a consumer/application thread.
    3.17 +	/// Threading:  called by consumer thread.
    3.18  	HttpOperation();
    3.19  
    3.20  protected:
    3.21 @@ -108,7 +108,7 @@
    3.22  	///							by the worker thread.  This is passible data
    3.23  	///							until notification is performed.
    3.24  	///
    3.25 -	/// Threading:  called by application thread.
    3.26 +	/// Threading:  called by consumer thread.
    3.27  	///
    3.28  	void setReplyPath(HttpReplyQueue * reply_queue,
    3.29  					  HttpHandler * handler);
    3.30 @@ -141,7 +141,7 @@
    3.31  	/// call to HttpRequest::update().  This method does the necessary
    3.32  	/// dispatching.
    3.33  	///
    3.34 -	/// Threading:  called by application thread.
    3.35 +	/// Threading:  called by consumer thread.
    3.36  	///
    3.37  	virtual void visitNotifier(HttpRequest *);
    3.38  
     4.1 --- a/indra/llcorehttp/_httpoprequest.cpp	Mon Jul 08 20:31:09 2013 +0000
     4.2 +++ b/indra/llcorehttp/_httpoprequest.cpp	Fri Jul 12 15:00:24 2013 -0400
     4.3 @@ -402,7 +402,7 @@
     4.4  	// *FIXME:  better error handling later
     4.5  	HttpStatus status;
     4.6  
     4.7 -	// Get policy options
     4.8 +	// Get global policy options
     4.9  	HttpPolicyGlobal & policy(service->getPolicy().getGlobalOptions());
    4.10  	
    4.11  	mCurlHandle = curl_easy_init();
    4.12 @@ -441,30 +441,27 @@
    4.13  	curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYPEER, 1);
    4.14  	curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYHOST, 0);
    4.15  
    4.16 -	const std::string * opt_value(NULL);
    4.17 -	long opt_long(0L);
    4.18 -	policy.get(HttpRequest::GP_LLPROXY, &opt_long);
    4.19 -	if (opt_long)
    4.20 +	if (policy.mUseLLProxy)
    4.21  	{
    4.22  		// Use the viewer-based thread-safe API which has a
    4.23  		// fast/safe check for proxy enable.  Would like to
    4.24  		// encapsulate this someway...
    4.25  		LLProxy::getInstance()->applyProxySettings(mCurlHandle);
    4.26  	}
    4.27 -	else if (policy.get(HttpRequest::GP_HTTP_PROXY, &opt_value))
    4.28 +	else if (policy.mHttpProxy.size())
    4.29  	{
    4.30  		// *TODO:  This is fine for now but get fuller socks5/
    4.31  		// authentication thing going later....
    4.32 -		curl_easy_setopt(mCurlHandle, CURLOPT_PROXY, opt_value->c_str());
    4.33 +		curl_easy_setopt(mCurlHandle, CURLOPT_PROXY, policy.mHttpProxy.c_str());
    4.34  		curl_easy_setopt(mCurlHandle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
    4.35  	}
    4.36 -	if (policy.get(HttpRequest::GP_CA_PATH, &opt_value))
    4.37 +	if (policy.mCAPath.size())
    4.38  	{
    4.39 -		curl_easy_setopt(mCurlHandle, CURLOPT_CAPATH, opt_value->c_str());
    4.40 +		curl_easy_setopt(mCurlHandle, CURLOPT_CAPATH, policy.mCAPath.c_str());
    4.41  	}
    4.42 -	if (policy.get(HttpRequest::GP_CA_FILE, &opt_value))
    4.43 +	if (policy.mCAFile.size())
    4.44  	{
    4.45 -		curl_easy_setopt(mCurlHandle, CURLOPT_CAINFO, opt_value->c_str());
    4.46 +		curl_easy_setopt(mCurlHandle, CURLOPT_CAINFO, policy.mCAFile.c_str());
    4.47  	}
    4.48  	
    4.49  	switch (mReqMethod)
     5.1 --- a/indra/llcorehttp/_httpopsetget.cpp	Mon Jul 08 20:31:09 2013 +0000
     5.2 +++ b/indra/llcorehttp/_httpopsetget.cpp	Fri Jul 12 15:00:24 2013 -0400
     5.3 @@ -4,7 +4,7 @@
     5.4   *
     5.5   * $LicenseInfo:firstyear=2012&license=viewerlgpl$
     5.6   * Second Life Viewer Source Code
     5.7 - * Copyright (C) 2012, Linden Research, Inc.
     5.8 + * Copyright (C) 2012-2013, Linden Research, Inc.
     5.9   *
    5.10   * This library is free software; you can redistribute it and/or
    5.11   * modify it under the terms of the GNU Lesser General Public
    5.12 @@ -27,6 +27,7 @@
    5.13  #include "_httpopsetget.h"
    5.14  
    5.15  #include "httpcommon.h"
    5.16 +#include "httprequest.h"
    5.17  
    5.18  #include "_httpservice.h"
    5.19  #include "_httppolicy.h"
    5.20 @@ -43,10 +44,11 @@
    5.21  
    5.22  HttpOpSetGet::HttpOpSetGet()
    5.23  	: HttpOperation(),
    5.24 -	  mIsGlobal(false),
    5.25 -	  mDoSet(false),
    5.26 -	  mSetting(-1),				// Nothing requested
    5.27 -	  mLongValue(0L)
    5.28 +	  mReqOption(HttpRequest::PO_CONNECTION_LIMIT),
    5.29 +	  mReqClass(HttpRequest::INVALID_POLICY_ID),
    5.30 +	  mReqDoSet(false),
    5.31 +	  mReqLongValue(0L),
    5.32 +	  mReplyLongValue(0L)
    5.33  {}
    5.34  
    5.35  
    5.36 @@ -54,37 +56,84 @@
    5.37  {}
    5.38  
    5.39  
    5.40 -void HttpOpSetGet::setupGet(HttpRequest::EGlobalPolicy setting)
    5.41 +HttpStatus HttpOpSetGet::setupGet(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass)
    5.42  {
    5.43 -	mIsGlobal = true;
    5.44 -	mSetting = setting;
    5.45 +	HttpStatus status;
    5.46 +	
    5.47 +	mReqOption = opt;
    5.48 +	mReqClass = pclass;
    5.49 +	return status;
    5.50  }
    5.51  
    5.52  
    5.53 -void HttpOpSetGet::setupSet(HttpRequest::EGlobalPolicy setting, const std::string & value)
    5.54 +HttpStatus HttpOpSetGet::setupSet(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass, long value)
    5.55  {
    5.56 -	mIsGlobal = true;
    5.57 -	mDoSet = true;
    5.58 -	mSetting = setting;
    5.59 -	mStrValue = value;
    5.60 +	HttpStatus status;
    5.61 +
    5.62 +	if (! HttpService::sOptionDesc[opt].mIsLong)
    5.63 +	{
    5.64 +		return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
    5.65 +	}
    5.66 +	if (! HttpService::sOptionDesc[opt].mIsDynamic)
    5.67 +	{
    5.68 +		return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC);
    5.69 +	}
    5.70 +	
    5.71 +	mReqOption = opt;
    5.72 +	mReqClass = pclass;
    5.73 +	mReqDoSet = true;
    5.74 +	mReqLongValue = value;
    5.75 +	
    5.76 +	return status;
    5.77 +}
    5.78 +
    5.79 +
    5.80 +HttpStatus HttpOpSetGet::setupSet(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass, const std::string & value)
    5.81 +{
    5.82 +	HttpStatus status;
    5.83 +
    5.84 +	if (HttpService::sOptionDesc[opt].mIsLong)
    5.85 +	{
    5.86 +		return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
    5.87 +	}
    5.88 +	if (! HttpService::sOptionDesc[opt].mIsDynamic)
    5.89 +	{
    5.90 +		return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC);
    5.91 +	}
    5.92 +
    5.93 +	mReqOption = opt;
    5.94 +	mReqClass = pclass;
    5.95 +	mReqDoSet = true;
    5.96 +	mReqStrValue = value;
    5.97 +	
    5.98 +	return status;
    5.99  }
   5.100  
   5.101  
   5.102  void HttpOpSetGet::stageFromRequest(HttpService * service)
   5.103  {
   5.104 -	HttpPolicyGlobal & pol_opt(service->getPolicy().getGlobalOptions());
   5.105 -	HttpRequest::EGlobalPolicy setting(static_cast<HttpRequest::EGlobalPolicy>(mSetting));
   5.106 -	
   5.107 -	if (mDoSet)
   5.108 +	if (mReqDoSet)
   5.109  	{
   5.110 -		mStatus = pol_opt.set(setting, mStrValue);
   5.111 +		if (HttpService::sOptionDesc[mReqOption].mIsLong)
   5.112 +		{
   5.113 +			mStatus = service->setPolicyOption(mReqOption, mReqClass,
   5.114 +											   mReqLongValue, &mReplyLongValue);
   5.115 +		}
   5.116 +		else
   5.117 +		{
   5.118 +			mStatus = service->setPolicyOption(mReqOption, mReqClass,
   5.119 +											   mReqStrValue, &mReplyStrValue);
   5.120 +		}
   5.121  	}
   5.122 -	if (mStatus)
   5.123 +	else
   5.124  	{
   5.125 -		const std::string * value(NULL);
   5.126 -		if ((mStatus = pol_opt.get(setting, &value)))
   5.127 +		if (HttpService::sOptionDesc[mReqOption].mIsLong)
   5.128  		{
   5.129 -			mStrValue = *value;
   5.130 +			mStatus = service->getPolicyOption(mReqOption, mReqClass, &mReplyLongValue);
   5.131 +		}
   5.132 +		else
   5.133 +		{
   5.134 +			mStatus = service->getPolicyOption(mReqOption, mReqClass, &mReplyStrValue);
   5.135  		}
   5.136  	}
   5.137  	
     6.1 --- a/indra/llcorehttp/_httpopsetget.h	Mon Jul 08 20:31:09 2013 +0000
     6.2 +++ b/indra/llcorehttp/_httpopsetget.h	Fri Jul 12 15:00:24 2013 -0400
     6.3 @@ -4,7 +4,7 @@
     6.4   *
     6.5   * $LicenseInfo:firstyear=2012&license=viewerlgpl$
     6.6   * Second Life Viewer Source Code
     6.7 - * Copyright (C) 2012, Linden Research, Inc.
     6.8 + * Copyright (C) 2012-2013, Linden Research, Inc.
     6.9   *
    6.10   * This library is free software; you can redistribute it and/or
    6.11   * modify it under the terms of the GNU Lesser General Public
    6.12 @@ -46,7 +46,10 @@
    6.13  /// configuration settings.
    6.14  ///
    6.15  /// *NOTE:  Expect this to change.  Don't really like it yet.
    6.16 -
    6.17 +///
    6.18 +/// *TODO:  Can't return values to caller yet.  Need to do
    6.19 +/// something better with HttpResponse and visitNotifier().
    6.20 +///
    6.21  class HttpOpSetGet : public HttpOperation
    6.22  {
    6.23  public:
    6.24 @@ -61,19 +64,23 @@
    6.25  
    6.26  public:
    6.27  	/// Threading:  called by application thread
    6.28 -	void setupGet(HttpRequest::EGlobalPolicy setting);
    6.29 -	void setupSet(HttpRequest::EGlobalPolicy setting, const std::string & value);
    6.30 +	HttpStatus setupGet(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass);
    6.31 +	HttpStatus setupSet(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass, long value);
    6.32 +	HttpStatus setupSet(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass, const std::string & value);
    6.33  
    6.34  	virtual void stageFromRequest(HttpService *);
    6.35  
    6.36  public:
    6.37  	// Request data
    6.38 -	bool				mIsGlobal;
    6.39 -	bool				mDoSet;
    6.40 -	int					mSetting;
    6.41 -	long				mLongValue;
    6.42 -	std::string			mStrValue;
    6.43 +	HttpRequest::EPolicyOption	mReqOption;
    6.44 +	HttpRequest::policy_t		mReqClass;
    6.45 +	bool						mReqDoSet;
    6.46 +	long						mReqLongValue;
    6.47 +	std::string					mReqStrValue;
    6.48  
    6.49 +	// Reply Data
    6.50 +	long						mReplyLongValue;
    6.51 +	std::string					mReplyStrValue;
    6.52  };  // end class HttpOpSetGet
    6.53  
    6.54  
     7.1 --- a/indra/llcorehttp/_httppolicy.cpp	Mon Jul 08 20:31:09 2013 +0000
     7.2 +++ b/indra/llcorehttp/_httppolicy.cpp	Fri Jul 12 15:00:24 2013 -0400
     7.3 @@ -4,7 +4,7 @@
     7.4   *
     7.5   * $LicenseInfo:firstyear=2012&license=viewerlgpl$
     7.6   * Second Life Viewer Source Code
     7.7 - * Copyright (C) 2012, Linden Research, Inc.
     7.8 + * Copyright (C) 2012-2013, Linden Research, Inc.
     7.9   *
    7.10   * This library is free software; you can redistribute it and/or
    7.11   * modify it under the terms of the GNU Lesser General Public
    7.12 @@ -41,57 +41,64 @@
    7.13  
    7.14  
    7.15  // Per-policy-class data for a running system.
    7.16 -// Collection of queues, parameters, history, metrics, etc.
    7.17 +// Collection of queues, options and other data
    7.18  // for a single policy class.
    7.19  //
    7.20  // Threading:  accessed only by worker thread
    7.21 -struct HttpPolicy::State
    7.22 +struct HttpPolicy::ClassState
    7.23  {
    7.24  public:
    7.25 -	State()
    7.26 -		: mConnMax(HTTP_CONNECTION_LIMIT_DEFAULT),
    7.27 -		  mConnAt(HTTP_CONNECTION_LIMIT_DEFAULT),
    7.28 -		  mConnMin(1),
    7.29 -		  mNextSample(0),
    7.30 -		  mErrorCount(0),
    7.31 -		  mErrorFactor(0)
    7.32 +	ClassState()
    7.33  		{}
    7.34  	
    7.35  	HttpReadyQueue		mReadyQueue;
    7.36  	HttpRetryQueue		mRetryQueue;
    7.37  
    7.38  	HttpPolicyClass		mOptions;
    7.39 -
    7.40 -	long				mConnMax;
    7.41 -	long				mConnAt;
    7.42 -	long				mConnMin;
    7.43 -
    7.44 -	HttpTime			mNextSample;
    7.45 -	unsigned long		mErrorCount;
    7.46 -	unsigned long		mErrorFactor;
    7.47  };
    7.48  
    7.49  
    7.50  HttpPolicy::HttpPolicy(HttpService * service)
    7.51 -	: mActiveClasses(0),
    7.52 -	  mState(NULL),
    7.53 -	  mService(service)
    7.54 -{}
    7.55 +	: mService(service)
    7.56 +{
    7.57 +	// Create default class
    7.58 +	mClasses.push_back(new ClassState());
    7.59 +}
    7.60  
    7.61  
    7.62  HttpPolicy::~HttpPolicy()
    7.63  {
    7.64  	shutdown();
    7.65 +
    7.66 +	for (class_list_t::iterator it(mClasses.begin()); it != mClasses.end(); ++it)
    7.67 +	{
    7.68 +		delete (*it);
    7.69 +	}
    7.70 +	mClasses.clear();
    7.71  	
    7.72  	mService = NULL;
    7.73  }
    7.74  
    7.75  
    7.76 +HttpRequest::policy_t HttpPolicy::createPolicyClass()
    7.77 +{
    7.78 +	const HttpRequest::policy_t policy_class(mClasses.size());
    7.79 +	if (policy_class >= HTTP_POLICY_CLASS_LIMIT)
    7.80 +	{
    7.81 +		return HttpRequest::INVALID_POLICY_ID;
    7.82 +	}
    7.83 +	mClasses.push_back(new ClassState());
    7.84 +	return policy_class;
    7.85 +}
    7.86 +
    7.87 +
    7.88  void HttpPolicy::shutdown()
    7.89  {
    7.90 -	for (int policy_class(0); policy_class < mActiveClasses; ++policy_class)
    7.91 +	for (int policy_class(0); policy_class < mClasses.size(); ++policy_class)
    7.92  	{
    7.93 -		HttpRetryQueue & retryq(mState[policy_class].mRetryQueue);
    7.94 +		ClassState & state(*mClasses[policy_class]);
    7.95 +		
    7.96 +		HttpRetryQueue & retryq(state.mRetryQueue);
    7.97  		while (! retryq.empty())
    7.98  		{
    7.99  			HttpOpRequest * op(retryq.top());
   7.100 @@ -101,7 +108,7 @@
   7.101  			op->release();
   7.102  		}
   7.103  
   7.104 -		HttpReadyQueue & readyq(mState[policy_class].mReadyQueue);
   7.105 +		HttpReadyQueue & readyq(state.mReadyQueue);
   7.106  		while (! readyq.empty())
   7.107  		{
   7.108  			HttpOpRequest * op(readyq.top());
   7.109 @@ -111,28 +118,11 @@
   7.110  			op->release();
   7.111  		}
   7.112  	}
   7.113 -	delete [] mState;
   7.114 -	mState = NULL;
   7.115 -	mActiveClasses = 0;
   7.116  }
   7.117  
   7.118  
   7.119 -void HttpPolicy::start(const HttpPolicyGlobal & global,
   7.120 -					   const std::vector<HttpPolicyClass> & classes)
   7.121 -{
   7.122 -	llassert_always(! mState);
   7.123 -
   7.124 -	mGlobalOptions = global;
   7.125 -	mActiveClasses = classes.size();
   7.126 -	mState = new State [mActiveClasses];
   7.127 -	for (int i(0); i < mActiveClasses; ++i)
   7.128 -	{
   7.129 -		mState[i].mOptions = classes[i];
   7.130 -		mState[i].mConnMax = classes[i].mConnectionLimit;
   7.131 -		mState[i].mConnAt = mState[i].mConnMax;
   7.132 -		mState[i].mConnMin = 2;
   7.133 -	}
   7.134 -}
   7.135 +void HttpPolicy::start()
   7.136 +{}
   7.137  
   7.138  
   7.139  void HttpPolicy::addOp(HttpOpRequest * op)
   7.140 @@ -141,7 +131,7 @@
   7.141  	
   7.142  	op->mPolicyRetries = 0;
   7.143  	op->mPolicy503Retries = 0;
   7.144 -	mState[policy_class].mReadyQueue.push(op);
   7.145 +	mClasses[policy_class]->mReadyQueue.push(op);
   7.146  }
   7.147  
   7.148  
   7.149 @@ -183,7 +173,7 @@
   7.150  							 << static_cast<HttpHandle>(op)
   7.151  							 << LL_ENDL;
   7.152  	}
   7.153 -	mState[policy_class].mRetryQueue.push(op);
   7.154 +	mClasses[policy_class]->mRetryQueue.push(op);
   7.155  }
   7.156  
   7.157  
   7.158 @@ -204,11 +194,11 @@
   7.159  	HttpService::ELoopSpeed result(HttpService::REQUEST_SLEEP);
   7.160  	HttpLibcurl & transport(mService->getTransport());
   7.161  	
   7.162 -	for (int policy_class(0); policy_class < mActiveClasses; ++policy_class)
   7.163 +	for (int policy_class(0); policy_class < mClasses.size(); ++policy_class)
   7.164  	{
   7.165 -		State & state(mState[policy_class]);
   7.166 +		ClassState & state(*mClasses[policy_class]);
   7.167  		int active(transport.getActiveCountInClass(policy_class));
   7.168 -		int needed(state.mConnAt - active);		// Expect negatives here
   7.169 +		int needed(state.mOptions.mConnectionLimit - active);		// Expect negatives here
   7.170  
   7.171  		HttpRetryQueue & retryq(state.mRetryQueue);
   7.172  		HttpReadyQueue & readyq(state.mReadyQueue);
   7.173 @@ -256,9 +246,9 @@
   7.174  
   7.175  bool HttpPolicy::changePriority(HttpHandle handle, HttpRequest::priority_t priority)
   7.176  {
   7.177 -	for (int policy_class(0); policy_class < mActiveClasses; ++policy_class)
   7.178 +	for (int policy_class(0); policy_class < mClasses.size(); ++policy_class)
   7.179  	{
   7.180 -		State & state(mState[policy_class]);
   7.181 +		ClassState & state(*mClasses[policy_class]);
   7.182  		// We don't scan retry queue because a priority change there
   7.183  		// is meaningless.  The request will be issued based on retry
   7.184  		// intervals not priority value, which is now moot.
   7.185 @@ -286,9 +276,9 @@
   7.186  
   7.187  bool HttpPolicy::cancel(HttpHandle handle)
   7.188  {
   7.189 -	for (int policy_class(0); policy_class < mActiveClasses; ++policy_class)
   7.190 +	for (int policy_class(0); policy_class < mClasses.size(); ++policy_class)
   7.191  	{
   7.192 -		State & state(mState[policy_class]);
   7.193 +		ClassState & state(*mClasses[policy_class]);
   7.194  
   7.195  		// Scan retry queue
   7.196  		HttpRetryQueue::container_type & c1(state.mRetryQueue.get_container());
   7.197 @@ -382,13 +372,21 @@
   7.198  	return false;						// not active
   7.199  }
   7.200  
   7.201 +	
   7.202 +HttpPolicyClass & HttpPolicy::getClassOptions(HttpRequest::policy_t pclass)
   7.203 +{
   7.204 +	llassert_always(pclass >= 0 && pclass < mClasses.size());
   7.205 +	
   7.206 +	return mClasses[pclass]->mOptions;
   7.207 +}
   7.208 +
   7.209  
   7.210  int HttpPolicy::getReadyCount(HttpRequest::policy_t policy_class) const
   7.211  {
   7.212 -	if (policy_class < mActiveClasses)
   7.213 +	if (policy_class < mClasses.size())
   7.214  	{
   7.215 -		return (mState[policy_class].mReadyQueue.size()
   7.216 -				+ mState[policy_class].mRetryQueue.size());
   7.217 +		return (mClasses[policy_class]->mReadyQueue.size()
   7.218 +				+ mClasses[policy_class]->mRetryQueue.size());
   7.219  	}
   7.220  	return 0;
   7.221  }
     8.1 --- a/indra/llcorehttp/_httppolicy.h	Mon Jul 08 20:31:09 2013 +0000
     8.2 +++ b/indra/llcorehttp/_httppolicy.h	Fri Jul 12 15:00:24 2013 -0400
     8.3 @@ -4,7 +4,7 @@
     8.4   *
     8.5   * $LicenseInfo:firstyear=2012&license=viewerlgpl$
     8.6   * Second Life Viewer Source Code
     8.7 - * Copyright (C) 2012, Linden Research, Inc.
     8.8 + * Copyright (C) 2012-2013, Linden Research, Inc.
     8.9   *
    8.10   * This library is free software; you can redistribute it and/or
    8.11   * modify it under the terms of the GNU Lesser General Public
    8.12 @@ -60,6 +60,9 @@
    8.13  	void operator=(const HttpPolicy &);			// Not defined
    8.14  
    8.15  public:
    8.16 +	/// Threading:  called by init thread.
    8.17 +	HttpRequest::policy_t createPolicyClass();
    8.18 +	
    8.19  	/// Cancel all ready and retry requests sending them to
    8.20  	/// their notification queues.  Release state resources
    8.21  	/// making further request handling impossible.
    8.22 @@ -71,9 +74,8 @@
    8.23  	/// requests.  One-time call invoked before starting
    8.24  	/// the worker thread.
    8.25  	///
    8.26 -	/// Threading:  called by application thread
    8.27 -	void start(const HttpPolicyGlobal & global,
    8.28 -			   const std::vector<HttpPolicyClass> & classes);
    8.29 +	/// Threading:  called by init thread
    8.30 +	void start();
    8.31  
    8.32  	/// Give the policy layer some cycles to scan the ready
    8.33  	/// queue promoting higher-priority requests to active
    8.34 @@ -93,7 +95,7 @@
    8.35  	/// and should not be modified by anyone until retrieved
    8.36  	/// from queue.
    8.37  	///
    8.38 -	/// Threading:  called by any thread
    8.39 +	/// Threading:  called by worker thread
    8.40  	void addOp(HttpOpRequest *);
    8.41  
    8.42  	/// Similar to addOp, used when a caller wants to retry a
    8.43 @@ -130,30 +132,39 @@
    8.44  	/// Threading:  called by worker thread
    8.45  	bool stageAfterCompletion(HttpOpRequest * op);
    8.46  	
    8.47 -	// Get pointer to global policy options.  Caller is expected
    8.48 -	// to do context checks like no setting once running.
    8.49 +	/// Get a reference to global policy options.  Caller is expected
    8.50 +	/// to do context checks like no setting once running.  These
    8.51 +	/// are done, for example, in @see HttpService interfaces.
    8.52  	///
    8.53  	/// Threading:  called by any thread *but* the object may
    8.54  	/// only be modified by the worker thread once running.
    8.55 -	///
    8.56  	HttpPolicyGlobal & getGlobalOptions()
    8.57  		{
    8.58  			return mGlobalOptions;
    8.59  		}
    8.60  
    8.61 +	/// Get a reference to class policy options.  Caller is expected
    8.62 +	/// to do context checks like no setting once running.  These
    8.63 +	/// are done, for example, in @see HttpService interfaces.
    8.64 +	///
    8.65 +	/// Threading:  called by any thread *but* the object may
    8.66 +	/// only be modified by the worker thread once running and
    8.67 +	/// read accesses by other threads are exposed to races at
    8.68 +	/// that point.
    8.69 +	HttpPolicyClass & getClassOptions(HttpRequest::policy_t pclass);
    8.70 +	
    8.71  	/// Get ready counts for a particular policy class
    8.72  	///
    8.73  	/// Threading:  called by worker thread
    8.74  	int getReadyCount(HttpRequest::policy_t policy_class) const;
    8.75  	
    8.76  protected:
    8.77 -	struct State;
    8.78 -
    8.79 -	int									mActiveClasses;
    8.80 -	State *								mState;
    8.81 +	struct ClassState;
    8.82 +	typedef std::vector<ClassState *>	class_list_t;
    8.83 +	
    8.84 +	HttpPolicyGlobal					mGlobalOptions;
    8.85 +	class_list_t						mClasses;
    8.86  	HttpService *						mService;				// Naked pointer, not refcounted, not owner
    8.87 -	HttpPolicyGlobal					mGlobalOptions;
    8.88 -	
    8.89  };  // end class HttpPolicy
    8.90  
    8.91  }  // end namespace LLCore
     9.1 --- a/indra/llcorehttp/_httppolicyclass.cpp	Mon Jul 08 20:31:09 2013 +0000
     9.2 +++ b/indra/llcorehttp/_httppolicyclass.cpp	Fri Jul 12 15:00:24 2013 -0400
     9.3 @@ -34,8 +34,7 @@
     9.4  
     9.5  
     9.6  HttpPolicyClass::HttpPolicyClass()
     9.7 -	: mSetMask(0UL),
     9.8 -	  mConnectionLimit(HTTP_CONNECTION_LIMIT_DEFAULT),
     9.9 +	: mConnectionLimit(HTTP_CONNECTION_LIMIT_DEFAULT),
    9.10  	  mPerHostConnectionLimit(HTTP_CONNECTION_LIMIT_DEFAULT),
    9.11  	  mPipelining(HTTP_PIPELINING_DEFAULT)
    9.12  {}
    9.13 @@ -49,7 +48,6 @@
    9.14  {
    9.15  	if (this != &other)
    9.16  	{
    9.17 -		mSetMask = other.mSetMask;
    9.18  		mConnectionLimit = other.mConnectionLimit;
    9.19  		mPerHostConnectionLimit = other.mPerHostConnectionLimit;
    9.20  		mPipelining = other.mPipelining;
    9.21 @@ -59,26 +57,25 @@
    9.22  
    9.23  
    9.24  HttpPolicyClass::HttpPolicyClass(const HttpPolicyClass & other)
    9.25 -	: mSetMask(other.mSetMask),
    9.26 -	  mConnectionLimit(other.mConnectionLimit),
    9.27 +	: mConnectionLimit(other.mConnectionLimit),
    9.28  	  mPerHostConnectionLimit(other.mPerHostConnectionLimit),
    9.29  	  mPipelining(other.mPipelining)
    9.30  {}
    9.31  
    9.32  
    9.33 -HttpStatus HttpPolicyClass::set(HttpRequest::EClassPolicy opt, long value)
    9.34 +HttpStatus HttpPolicyClass::set(HttpRequest::EPolicyOption opt, long value)
    9.35  {
    9.36  	switch (opt)
    9.37  	{
    9.38 -	case HttpRequest::CP_CONNECTION_LIMIT:
    9.39 +	case HttpRequest::PO_CONNECTION_LIMIT:
    9.40  		mConnectionLimit = llclamp(value, long(HTTP_CONNECTION_LIMIT_MIN), long(HTTP_CONNECTION_LIMIT_MAX));
    9.41  		break;
    9.42  
    9.43 -	case HttpRequest::CP_PER_HOST_CONNECTION_LIMIT:
    9.44 +	case HttpRequest::PO_PER_HOST_CONNECTION_LIMIT:
    9.45  		mPerHostConnectionLimit = llclamp(value, long(HTTP_CONNECTION_LIMIT_MIN), mConnectionLimit);
    9.46  		break;
    9.47  
    9.48 -	case HttpRequest::CP_ENABLE_PIPELINING:
    9.49 +	case HttpRequest::PO_ENABLE_PIPELINING:
    9.50  		mPipelining = llclamp(value, 0L, 1L);
    9.51  		break;
    9.52  
    9.53 @@ -86,38 +83,30 @@
    9.54  		return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
    9.55  	}
    9.56  
    9.57 -	mSetMask |= 1UL << int(opt);
    9.58  	return HttpStatus();
    9.59  }
    9.60  
    9.61  
    9.62 -HttpStatus HttpPolicyClass::get(HttpRequest::EClassPolicy opt, long * value)
    9.63 +HttpStatus HttpPolicyClass::get(HttpRequest::EPolicyOption opt, long * value) const
    9.64  {
    9.65 -	static const HttpStatus not_set(HttpStatus::LLCORE, HE_OPT_NOT_SET);
    9.66 -	long * src(NULL);
    9.67 -	
    9.68  	switch (opt)
    9.69  	{
    9.70 -	case HttpRequest::CP_CONNECTION_LIMIT:
    9.71 -		src = &mConnectionLimit;
    9.72 +	case HttpRequest::PO_CONNECTION_LIMIT:
    9.73 +		*value = mConnectionLimit;
    9.74  		break;
    9.75  
    9.76 -	case HttpRequest::CP_PER_HOST_CONNECTION_LIMIT:
    9.77 -		src = &mPerHostConnectionLimit;
    9.78 +	case HttpRequest::PO_PER_HOST_CONNECTION_LIMIT:
    9.79 +		*value = mPerHostConnectionLimit;
    9.80  		break;
    9.81  
    9.82 -	case HttpRequest::CP_ENABLE_PIPELINING:
    9.83 -		src = &mPipelining;
    9.84 +	case HttpRequest::PO_ENABLE_PIPELINING:
    9.85 +		*value = mPipelining;
    9.86  		break;
    9.87  
    9.88  	default:
    9.89  		return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
    9.90  	}
    9.91  
    9.92 -	if (! (mSetMask & (1UL << int(opt))))
    9.93 -		return not_set;
    9.94 -
    9.95 -	*value = *src;
    9.96  	return HttpStatus();
    9.97  }
    9.98  
    10.1 --- a/indra/llcorehttp/_httppolicyclass.h	Mon Jul 08 20:31:09 2013 +0000
    10.2 +++ b/indra/llcorehttp/_httppolicyclass.h	Fri Jul 12 15:00:24 2013 -0400
    10.3 @@ -4,7 +4,7 @@
    10.4   *
    10.5   * $LicenseInfo:firstyear=2012&license=viewerlgpl$
    10.6   * Second Life Viewer Source Code
    10.7 - * Copyright (C) 2012, Linden Research, Inc.
    10.8 + * Copyright (C) 2012-2013, Linden Research, Inc.
    10.9   *
   10.10   * This library is free software; you can redistribute it and/or
   10.11   * modify it under the terms of the GNU Lesser General Public
   10.12 @@ -34,6 +34,18 @@
   10.13  namespace LLCore
   10.14  {
   10.15  
   10.16 +/// Options struct for per-class policy options.
   10.17 +///
   10.18 +/// Combines both raw blob data access with semantics-enforcing
   10.19 +/// set/get interfaces.  For internal operations by the worker
   10.20 +/// thread, just grab the setting directly from instance and test/use
   10.21 +/// as needed.  When attached to external APIs (the public API
   10.22 +/// options interfaces) the set/get methods are available to
   10.23 +/// enforce correct ranges, data types, contexts, etc. and suitable
   10.24 +/// status values are returned.
   10.25 +///
   10.26 +/// Threading:  Single-threaded.  In practice, init thread before
   10.27 +/// worker starts, worker thread after.
   10.28  class HttpPolicyClass
   10.29  {
   10.30  public:
   10.31 @@ -44,11 +56,10 @@
   10.32  	HttpPolicyClass(const HttpPolicyClass &);			// Not defined
   10.33  
   10.34  public:
   10.35 -	HttpStatus set(HttpRequest::EClassPolicy opt, long value);
   10.36 -	HttpStatus get(HttpRequest::EClassPolicy opt, long * value);
   10.37 +	HttpStatus set(HttpRequest::EPolicyOption opt, long value);
   10.38 +	HttpStatus get(HttpRequest::EPolicyOption opt, long * value) const;
   10.39  	
   10.40  public:
   10.41 -	unsigned long				mSetMask;
   10.42  	long						mConnectionLimit;
   10.43  	long						mPerHostConnectionLimit;
   10.44  	long						mPipelining;
    11.1 --- a/indra/llcorehttp/_httppolicyglobal.cpp	Mon Jul 08 20:31:09 2013 +0000
    11.2 +++ b/indra/llcorehttp/_httppolicyglobal.cpp	Fri Jul 12 15:00:24 2013 -0400
    11.3 @@ -4,7 +4,7 @@
    11.4   *
    11.5   * $LicenseInfo:firstyear=2012&license=viewerlgpl$
    11.6   * Second Life Viewer Source Code
    11.7 - * Copyright (C) 2012, Linden Research, Inc.
    11.8 + * Copyright (C) 2012-2013, Linden Research, Inc.
    11.9   *
   11.10   * This library is free software; you can redistribute it and/or
   11.11   * modify it under the terms of the GNU Lesser General Public
   11.12 @@ -34,8 +34,7 @@
   11.13  
   11.14  
   11.15  HttpPolicyGlobal::HttpPolicyGlobal()
   11.16 -	: mSetMask(0UL),
   11.17 -	  mConnectionLimit(HTTP_CONNECTION_LIMIT_DEFAULT),
   11.18 +	: mConnectionLimit(HTTP_CONNECTION_LIMIT_DEFAULT),
   11.19  	  mTrace(HTTP_TRACE_OFF),
   11.20  	  mUseLLProxy(0)
   11.21  {}
   11.22 @@ -49,7 +48,6 @@
   11.23  {
   11.24  	if (this != &other)
   11.25  	{
   11.26 -		mSetMask = other.mSetMask;
   11.27  		mConnectionLimit = other.mConnectionLimit;
   11.28  		mCAPath = other.mCAPath;
   11.29  		mCAFile = other.mCAFile;
   11.30 @@ -61,19 +59,19 @@
   11.31  }
   11.32  
   11.33  
   11.34 -HttpStatus HttpPolicyGlobal::set(HttpRequest::EGlobalPolicy opt, long value)
   11.35 +HttpStatus HttpPolicyGlobal::set(HttpRequest::EPolicyOption opt, long value)
   11.36  {
   11.37  	switch (opt)
   11.38  	{
   11.39 -	case HttpRequest::GP_CONNECTION_LIMIT:
   11.40 +	case HttpRequest::PO_CONNECTION_LIMIT:
   11.41  		mConnectionLimit = llclamp(value, long(HTTP_CONNECTION_LIMIT_MIN), long(HTTP_CONNECTION_LIMIT_MAX));
   11.42  		break;
   11.43  
   11.44 -	case HttpRequest::GP_TRACE:
   11.45 +	case HttpRequest::PO_TRACE:
   11.46  		mTrace = llclamp(value, long(HTTP_TRACE_MIN), long(HTTP_TRACE_MAX));
   11.47  		break;
   11.48  
   11.49 -	case HttpRequest::GP_LLPROXY:
   11.50 +	case HttpRequest::PO_LLPROXY:
   11.51  		mUseLLProxy = llclamp(value, 0L, 1L);
   11.52  		break;
   11.53  
   11.54 @@ -81,24 +79,23 @@
   11.55  		return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
   11.56  	}
   11.57  
   11.58 -	mSetMask |= 1UL << int(opt);
   11.59  	return HttpStatus();
   11.60  }
   11.61  
   11.62  
   11.63 -HttpStatus HttpPolicyGlobal::set(HttpRequest::EGlobalPolicy opt, const std::string & value)
   11.64 +HttpStatus HttpPolicyGlobal::set(HttpRequest::EPolicyOption opt, const std::string & value)
   11.65  {
   11.66  	switch (opt)
   11.67  	{
   11.68 -	case HttpRequest::GP_CA_PATH:
   11.69 +	case HttpRequest::PO_CA_PATH:
   11.70  		mCAPath = value;
   11.71  		break;
   11.72  
   11.73 -	case HttpRequest::GP_CA_FILE:
   11.74 +	case HttpRequest::PO_CA_FILE:
   11.75  		mCAFile = value;
   11.76  		break;
   11.77  
   11.78 -	case HttpRequest::GP_HTTP_PROXY:
   11.79 +	case HttpRequest::PO_HTTP_PROXY:
   11.80  		mCAFile = value;
   11.81  		break;
   11.82  
   11.83 @@ -106,69 +103,54 @@
   11.84  		return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
   11.85  	}
   11.86  	
   11.87 -	mSetMask |= 1UL << int(opt);
   11.88  	return HttpStatus();
   11.89  }
   11.90  
   11.91  
   11.92 -HttpStatus HttpPolicyGlobal::get(HttpRequest::EGlobalPolicy opt, long * value)
   11.93 +HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, long * value) const
   11.94  {
   11.95 -	static const HttpStatus not_set(HttpStatus::LLCORE, HE_OPT_NOT_SET);
   11.96 -	long * src(NULL);
   11.97 -	
   11.98  	switch (opt)
   11.99  	{
  11.100 -	case HttpRequest::GP_CONNECTION_LIMIT:
  11.101 -		src = &mConnectionLimit;
  11.102 +	case HttpRequest::PO_CONNECTION_LIMIT:
  11.103 +		*value = mConnectionLimit;
  11.104  		break;
  11.105  
  11.106 -	case HttpRequest::GP_TRACE:
  11.107 -		src = &mTrace;
  11.108 +	case HttpRequest::PO_TRACE:
  11.109 +		*value = mTrace;
  11.110  		break;
  11.111  
  11.112 -	case HttpRequest::GP_LLPROXY:
  11.113 -		src = &mUseLLProxy;
  11.114 +	case HttpRequest::PO_LLPROXY:
  11.115 +		*value = mUseLLProxy;
  11.116  		break;
  11.117  
  11.118  	default:
  11.119  		return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
  11.120  	}
  11.121  
  11.122 -	if (! (mSetMask & (1UL << int(opt))))
  11.123 -		return not_set;
  11.124 -
  11.125 -	*value = *src;
  11.126  	return HttpStatus();
  11.127  }
  11.128  
  11.129  
  11.130 -HttpStatus HttpPolicyGlobal::get(HttpRequest::EGlobalPolicy opt, const std::string ** value)
  11.131 +HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, std::string * value) const
  11.132  {
  11.133 -	static const HttpStatus not_set(HttpStatus::LLCORE, HE_OPT_NOT_SET);
  11.134 -	const std::string * src(NULL);
  11.135 -
  11.136  	switch (opt)
  11.137  	{
  11.138 -	case HttpRequest::GP_CA_PATH:
  11.139 -		src = &mCAPath;
  11.140 +	case HttpRequest::PO_CA_PATH:
  11.141 +		*value = mCAPath;
  11.142  		break;
  11.143  
  11.144 -	case HttpRequest::GP_CA_FILE:
  11.145 -		src = &mCAFile;
  11.146 +	case HttpRequest::PO_CA_FILE:
  11.147 +		*value = mCAFile;
  11.148  		break;
  11.149  
  11.150 -	case HttpRequest::GP_HTTP_PROXY:
  11.151 -		src = &mHttpProxy;
  11.152 +	case HttpRequest::PO_HTTP_PROXY:
  11.153 +		*value = mHttpProxy;
  11.154  		break;
  11.155  
  11.156  	default:
  11.157  		return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
  11.158  	}
  11.159  	
  11.160 -	if (! (mSetMask & (1UL << int(opt))))
  11.161 -		return not_set;
  11.162 -
  11.163 -	*value = src;
  11.164  	return HttpStatus();
  11.165  }
  11.166  
    12.1 --- a/indra/llcorehttp/_httppolicyglobal.h	Mon Jul 08 20:31:09 2013 +0000
    12.2 +++ b/indra/llcorehttp/_httppolicyglobal.h	Fri Jul 12 15:00:24 2013 -0400
    12.3 @@ -4,7 +4,7 @@
    12.4   *
    12.5   * $LicenseInfo:firstyear=2012&license=viewerlgpl$
    12.6   * Second Life Viewer Source Code
    12.7 - * Copyright (C) 2012, Linden Research, Inc.
    12.8 + * Copyright (C) 2012-2013, Linden Research, Inc.
    12.9   *
   12.10   * This library is free software; you can redistribute it and/or
   12.11   * modify it under the terms of the GNU Lesser General Public
   12.12 @@ -34,6 +34,18 @@
   12.13  namespace LLCore
   12.14  {
   12.15  
   12.16 +/// Options struct for global policy options.
   12.17 +///
   12.18 +/// Combines both raw blob data access with semantics-enforcing
   12.19 +/// set/get interfaces.  For internal operations by the worker
   12.20 +/// thread, just grab the setting directly from instance and test/use
   12.21 +/// as needed.  When attached to external APIs (the public API
   12.22 +/// options interfaces) the set/get methods are available to
   12.23 +/// enforce correct ranges, data types, contexts, etc. and suitable
   12.24 +/// status values are returned.
   12.25 +///
   12.26 +/// Threading:  Single-threaded.  In practice, init thread before
   12.27 +/// worker starts, worker thread after.
   12.28  class HttpPolicyGlobal
   12.29  {
   12.30  public:
   12.31 @@ -46,13 +58,12 @@
   12.32  	HttpPolicyGlobal(const HttpPolicyGlobal &);			// Not defined
   12.33  
   12.34  public:
   12.35 -	HttpStatus set(HttpRequest::EGlobalPolicy opt, long value);
   12.36 -	HttpStatus set(HttpRequest::EGlobalPolicy opt, const std::string & value);
   12.37 -	HttpStatus get(HttpRequest::EGlobalPolicy opt, long * value);
   12.38 -	HttpStatus get(HttpRequest::EGlobalPolicy opt, const std::string ** value);
   12.39 +	HttpStatus set(HttpRequest::EPolicyOption opt, long value);
   12.40 +	HttpStatus set(HttpRequest::EPolicyOption opt, const std::string & value);
   12.41 +	HttpStatus get(HttpRequest::EPolicyOption opt, long * value) const;
   12.42 +	HttpStatus get(HttpRequest::EPolicyOption opt, std::string * value) const;
   12.43  	
   12.44  public:
   12.45 -	unsigned long		mSetMask;
   12.46  	long				mConnectionLimit;
   12.47  	std::string			mCAPath;
   12.48  	std::string			mCAFile;
    13.1 --- a/indra/llcorehttp/_httpservice.cpp	Mon Jul 08 20:31:09 2013 +0000
    13.2 +++ b/indra/llcorehttp/_httpservice.cpp	Fri Jul 12 15:00:24 2013 -0400
    13.3 @@ -4,7 +4,7 @@
    13.4   *
    13.5   * $LicenseInfo:firstyear=2012&license=viewerlgpl$
    13.6   * Second Life Viewer Source Code
    13.7 - * Copyright (C) 2012, Linden Research, Inc.
    13.8 + * Copyright (C) 2012-2013, Linden Research, Inc.
    13.9   *
   13.10   * This library is free software; you can redistribute it and/or
   13.11   * modify it under the terms of the GNU Lesser General Public
   13.12 @@ -43,6 +43,17 @@
   13.13  namespace LLCore
   13.14  {
   13.15  
   13.16 +const HttpService::OptionDescriptor HttpService::sOptionDesc[] =
   13.17 +{ //    isLong     isDynamic  isGlobal    isClass
   13.18 +	{	true,		true,		true,		true	},		// PO_CONNECTION_LIMIT
   13.19 +	{	true,		true,		false,		true	},		// PO_PER_HOST_CONNECTION_LIMIT
   13.20 +	{	false,		false,		true,		false	},		// PO_CA_PATH
   13.21 +	{	false,		false,		true,		false	},		// PO_CA_FILE
   13.22 +	{	false,		true,		true,		false	},		// PO_HTTP_PROXY
   13.23 +	{	true,		true,		true,		false	},		// PO_LLPROXY
   13.24 +	{	true,		true,		true,		false	},		// PO_TRACE
   13.25 +	{	true,		true,		false,		true	}		// PO_ENABLE_PIPELINING
   13.26 +};
   13.27  HttpService * HttpService::sInstance(NULL);
   13.28  volatile HttpService::EState HttpService::sState(NOT_INITIALIZED);
   13.29  
   13.30 @@ -51,12 +62,9 @@
   13.31  	  mExitRequested(0U),
   13.32  	  mThread(NULL),
   13.33  	  mPolicy(NULL),
   13.34 -	  mTransport(NULL)
   13.35 -{
   13.36 -	// Create the default policy class
   13.37 -	HttpPolicyClass pol_class;
   13.38 -	mPolicyClasses.push_back(pol_class);
   13.39 -}
   13.40 +	  mTransport(NULL),
   13.41 +	  mLastPolicy(0)
   13.42 +{}
   13.43  
   13.44  
   13.45  HttpService::~HttpService()
   13.46 @@ -146,13 +154,8 @@
   13.47  
   13.48  HttpRequest::policy_t HttpService::createPolicyClass()
   13.49  {
   13.50 -	const HttpRequest::policy_t policy_class(mPolicyClasses.size());
   13.51 -	if (policy_class >= HTTP_POLICY_CLASS_LIMIT)
   13.52 -	{
   13.53 -		return 0;
   13.54 -	}
   13.55 -	mPolicyClasses.push_back(HttpPolicyClass());
   13.56 -	return policy_class;
   13.57 +	mLastPolicy = mPolicy->createPolicyClass();
   13.58 +	return mLastPolicy;
   13.59  }
   13.60  
   13.61  
   13.62 @@ -185,8 +188,8 @@
   13.63  	}
   13.64  
   13.65  	// Push current policy definitions, enable policy & transport components
   13.66 -	mPolicy->start(mPolicyGlobal, mPolicyClasses);
   13.67 -	mTransport->start(mPolicyClasses.size());
   13.68 +	mPolicy->start();
   13.69 +	mTransport->start(mLastPolicy + 1);
   13.70  
   13.71  	mThread = new LLCoreInt::HttpThread(boost::bind(&HttpService::threadRun, this, _1));
   13.72  	sState = RUNNING;
   13.73 @@ -319,7 +322,7 @@
   13.74  		{
   13.75  			// Setup for subsequent tracing
   13.76  			long tracing(HTTP_TRACE_OFF);
   13.77 -			mPolicy->getGlobalOptions().get(HttpRequest::GP_TRACE, &tracing);
   13.78 +			mPolicy->getGlobalOptions().get(HttpRequest::PO_TRACE, &tracing);
   13.79  			op->mTracing = (std::max)(op->mTracing, int(tracing));
   13.80  
   13.81  			if (op->mTracing > HTTP_TRACE_OFF)
   13.82 @@ -342,4 +345,137 @@
   13.83  }
   13.84  
   13.85  
   13.86 +HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
   13.87 +										long * ret_value)
   13.88 +{
   13.89 +	if (opt < HttpRequest::PO_CONNECTION_LIMIT											// option must be in range
   13.90 +		|| opt >= HttpRequest::PO_LAST													// ditto
   13.91 +		|| (! sOptionDesc[opt].mIsLong)													// datatype is long
   13.92 +		|| (pclass != HttpRequest::GLOBAL_POLICY_ID && pclass > mLastPolicy)			// pclass in valid range
   13.93 +		|| (pclass == HttpRequest::GLOBAL_POLICY_ID && ! sOptionDesc[opt].mIsGlobal)	// global setting permitted
   13.94 +		|| (pclass != HttpRequest::GLOBAL_POLICY_ID && ! sOptionDesc[opt].mIsClass))	// class setting permitted
   13.95 +																						// can always get, no dynamic check
   13.96 +	{
   13.97 +		return HttpStatus(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
   13.98 +	}
   13.99 +
  13.100 +	HttpStatus status;
  13.101 +	if (pclass == HttpRequest::GLOBAL_POLICY_ID)
  13.102 +	{
  13.103 +		HttpPolicyGlobal & opts(mPolicy->getGlobalOptions());
  13.104 +		
  13.105 +		status = opts.get(opt, ret_value);
  13.106 +	}
  13.107 +	else
  13.108 +	{
  13.109 +		HttpPolicyClass & opts(mPolicy->getClassOptions(pclass));
  13.110 +
  13.111 +		status = opts.get(opt, ret_value);
  13.112 +	}
  13.113 +
  13.114 +	return status;
  13.115 +}
  13.116 +
  13.117 +
  13.118 +HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
  13.119 +										std::string * ret_value)
  13.120 +{
  13.121 +	HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
  13.122 +
  13.123 +	if (opt < HttpRequest::PO_CONNECTION_LIMIT											// option must be in range
  13.124 +		|| opt >= HttpRequest::PO_LAST													// ditto
  13.125 +		|| (sOptionDesc[opt].mIsLong)													// datatype is string
  13.126 +		|| (pclass != HttpRequest::GLOBAL_POLICY_ID && pclass > mLastPolicy)			// pclass in valid range
  13.127 +		|| (pclass == HttpRequest::GLOBAL_POLICY_ID && ! sOptionDesc[opt].mIsGlobal)	// global setting permitted
  13.128 +		|| (pclass != HttpRequest::GLOBAL_POLICY_ID && ! sOptionDesc[opt].mIsClass))	// class setting permitted
  13.129 +																						// can always get, no dynamic check
  13.130 +	{
  13.131 +		return status;
  13.132 +	}
  13.133 +
  13.134 +	// Only global has string values
  13.135 +	if (pclass == HttpRequest::GLOBAL_POLICY_ID)
  13.136 +	{
  13.137 +		HttpPolicyGlobal & opts(mPolicy->getGlobalOptions());
  13.138 +
  13.139 +		status = opts.get(opt, ret_value);
  13.140 +	}
  13.141 +
  13.142 +	return status;
  13.143 +}
  13.144 +
  13.145 +
  13.146 +HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
  13.147 +										long value, long * ret_value)
  13.148 +{
  13.149 +	HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
  13.150 +	
  13.151 +	if (opt < HttpRequest::PO_CONNECTION_LIMIT											// option must be in range
  13.152 +		|| opt >= HttpRequest::PO_LAST													// ditto
  13.153 +		|| (! sOptionDesc[opt].mIsLong)													// datatype is long
  13.154 +		|| (pclass != HttpRequest::GLOBAL_POLICY_ID && pclass > mLastPolicy)			// pclass in valid range
  13.155 +		|| (pclass == HttpRequest::GLOBAL_POLICY_ID && ! sOptionDesc[opt].mIsGlobal)	// global setting permitted
  13.156 +		|| (pclass != HttpRequest::GLOBAL_POLICY_ID && ! sOptionDesc[opt].mIsClass)		// class setting permitted
  13.157 +		|| (RUNNING == sState && ! sOptionDesc[opt].mIsDynamic))						// dynamic setting permitted
  13.158 +	{
  13.159 +		return status;
  13.160 +	}
  13.161 +
  13.162 +	if (pclass == HttpRequest::GLOBAL_POLICY_ID)
  13.163 +	{
  13.164 +		HttpPolicyGlobal & opts(mPolicy->getGlobalOptions());
  13.165 +		
  13.166 +		status = opts.set(opt, value);
  13.167 +		if (status && ret_value)
  13.168 +		{
  13.169 +			status = opts.get(opt, ret_value);
  13.170 +		}
  13.171 +	}
  13.172 +	else
  13.173 +	{
  13.174 +		HttpPolicyClass & opts(mPolicy->getClassOptions(pclass));
  13.175 +
  13.176 +		status = opts.set(opt, value);
  13.177 +		if (status && ret_value)
  13.178 +		{
  13.179 +			status = opts.get(opt, ret_value);
  13.180 +		}
  13.181 +	}
  13.182 +
  13.183 +	return status;
  13.184 +}
  13.185 +
  13.186 +
  13.187 +HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
  13.188 +										const std::string & value, std::string * ret_value)
  13.189 +{
  13.190 +	HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
  13.191 +	
  13.192 +	if (opt < HttpRequest::PO_CONNECTION_LIMIT											// option must be in range
  13.193 +		|| opt >= HttpRequest::PO_LAST													// ditto
  13.194 +		|| (sOptionDesc[opt].mIsLong)													// datatype is string
  13.195 +		|| (pclass != HttpRequest::GLOBAL_POLICY_ID && pclass > mLastPolicy)			// pclass in valid range
  13.196 +		|| (pclass == HttpRequest::GLOBAL_POLICY_ID && ! sOptionDesc[opt].mIsGlobal)	// global setting permitted
  13.197 +		|| (pclass != HttpRequest::GLOBAL_POLICY_ID && ! sOptionDesc[opt].mIsClass)		// class setting permitted
  13.198 +		|| (RUNNING == sState && ! sOptionDesc[opt].mIsDynamic))						// dynamic setting permitted
  13.199 +	{
  13.200 +		return status;
  13.201 +	}
  13.202 +
  13.203 +	// Only string values are global at this time
  13.204 +	if (pclass == HttpRequest::GLOBAL_POLICY_ID)
  13.205 +	{
  13.206 +		HttpPolicyGlobal & opts(mPolicy->getGlobalOptions());
  13.207 +		
  13.208 +		status = opts.set(opt, value);
  13.209 +		if (status && ret_value)
  13.210 +		{
  13.211 +			status = opts.get(opt, ret_value);
  13.212 +		}
  13.213 +	}
  13.214 +
  13.215 +	return status;
  13.216 +}
  13.217 +	
  13.218 +
  13.219  }  // end namespace LLCore
    14.1 --- a/indra/llcorehttp/_httpservice.h	Mon Jul 08 20:31:09 2013 +0000
    14.2 +++ b/indra/llcorehttp/_httpservice.h	Fri Jul 12 15:00:24 2013 -0400
    14.3 @@ -4,7 +4,7 @@
    14.4   *
    14.5   * $LicenseInfo:firstyear=2012&license=viewerlgpl$
    14.6   * Second Life Viewer Source Code
    14.7 - * Copyright (C) 2012, Linden Research, Inc.
    14.8 + * Copyright (C) 2012-2013, Linden Research, Inc.
    14.9   *
   14.10   * This library is free software; you can redistribute it and/or
   14.11   * modify it under the terms of the GNU Lesser General Public
   14.12 @@ -53,6 +53,7 @@
   14.13  class HttpRequestQueue;
   14.14  class HttpPolicy;
   14.15  class HttpLibcurl;
   14.16 +class HttpOpSetGet;
   14.17  
   14.18  
   14.19  /// The HttpService class does the work behind the request queue.  It
   14.20 @@ -106,7 +107,7 @@
   14.21  		NORMAL,					///< continuous polling of request, ready, active queues
   14.22  		REQUEST_SLEEP			///< can sleep indefinitely waiting for request queue write
   14.23  	};
   14.24 -		
   14.25 +
   14.26  	static void init(HttpRequestQueue *);
   14.27  	static void term();
   14.28  
   14.29 @@ -136,7 +137,7 @@
   14.30  	/// acquires its weaknesses.
   14.31  	static bool isStopped();
   14.32  
   14.33 -	/// Threading:  callable by consumer thread *once*.
   14.34 +	/// Threading:  callable by init thread *once*.
   14.35  	void startThread();
   14.36  
   14.37  	/// Threading:  callable by worker thread.
   14.38 @@ -181,27 +182,38 @@
   14.39  		}
   14.40  
   14.41  	/// Threading:  callable by consumer thread.
   14.42 -	HttpPolicyGlobal & getGlobalOptions()
   14.43 -		{
   14.44 -			return mPolicyGlobal;
   14.45 -		}
   14.46 -
   14.47 -	/// Threading:  callable by consumer thread.
   14.48  	HttpRequest::policy_t createPolicyClass();
   14.49  	
   14.50 -	/// Threading:  callable by consumer thread.
   14.51 -	HttpPolicyClass & getClassOptions(HttpRequest::policy_t policy_class)
   14.52 -		{
   14.53 -			llassert(policy_class >= 0 && policy_class < mPolicyClasses.size());
   14.54 -			return mPolicyClasses[policy_class];
   14.55 -		}
   14.56 -	
   14.57  protected:
   14.58  	void threadRun(LLCoreInt::HttpThread * thread);
   14.59  	
   14.60  	ELoopSpeed processRequestQueue(ELoopSpeed loop);
   14.61 +
   14.62 +protected:
   14.63 +	friend class HttpOpSetGet;
   14.64 +	friend class HttpRequest;
   14.65 +	
   14.66 +	// Used internally to describe what operations are allowed
   14.67 +	// on each policy option.
   14.68 +	struct OptionDescriptor
   14.69 +	{
   14.70 +		bool		mIsLong;
   14.71 +		bool		mIsDynamic;
   14.72 +		bool		mIsGlobal;
   14.73 +		bool		mIsClass;
   14.74 +	};
   14.75 +		
   14.76 +	HttpStatus getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
   14.77 +							   long * ret_value);
   14.78 +	HttpStatus getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
   14.79 +							   std::string * ret_value);
   14.80 +	HttpStatus setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
   14.81 +							   long value, long * ret_value);
   14.82 +	HttpStatus setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
   14.83 +							   const std::string & value, std::string * ret_value);
   14.84  	
   14.85  protected:
   14.86 +	static const OptionDescriptor		sOptionDesc[HttpRequest::PO_LAST];
   14.87  	static HttpService *				sInstance;
   14.88  	
   14.89  	// === shared data ===
   14.90 @@ -210,13 +222,13 @@
   14.91  	LLAtomicU32							mExitRequested;
   14.92  	LLCoreInt::HttpThread *				mThread;
   14.93  	
   14.94 -	// === consumer-thread-only data ===
   14.95 -	HttpPolicyGlobal					mPolicyGlobal;
   14.96 -	std::vector<HttpPolicyClass>		mPolicyClasses;
   14.97 -	
   14.98  	// === working-thread-only data ===
   14.99  	HttpPolicy *						mPolicy;		// Simple pointer, has ownership
  14.100  	HttpLibcurl *						mTransport;		// Simple pointer, has ownership
  14.101 +	
  14.102 +	// === main-thread-only data ===
  14.103 +	HttpRequest::policy_t				mLastPolicy;
  14.104 +	
  14.105  };  // end class HttpService
  14.106  
  14.107  }  // end namespace LLCore
    15.1 --- a/indra/llcorehttp/examples/http_texture_load.cpp	Mon Jul 08 20:31:09 2013 +0000
    15.2 +++ b/indra/llcorehttp/examples/http_texture_load.cpp	Fri Jul 12 15:00:24 2013 -0400
    15.3 @@ -236,9 +236,10 @@
    15.4  	// Initialization
    15.5  	init_curl();
    15.6  	LLCore::HttpRequest::createService();
    15.7 -	LLCore::HttpRequest::setPolicyClassOption(LLCore::HttpRequest::DEFAULT_POLICY_ID,
    15.8 -											  LLCore::HttpRequest::CP_CONNECTION_LIMIT,
    15.9 -											  concurrency_limit);
   15.10 +	LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_CONNECTION_LIMIT,
   15.11 +											   LLCore::HttpRequest::DEFAULT_POLICY_ID,
   15.12 +											   concurrency_limit,
   15.13 +											   NULL);
   15.14  	LLCore::HttpRequest::startThread();
   15.15  	
   15.16  	// Get service point
    16.1 --- a/indra/llcorehttp/httpcommon.h	Mon Jul 08 20:31:09 2013 +0000
    16.2 +++ b/indra/llcorehttp/httpcommon.h	Fri Jul 12 15:00:24 2013 -0400
    16.3 @@ -4,7 +4,7 @@
    16.4   *
    16.5   * $LicenseInfo:firstyear=2012&license=viewerlgpl$
    16.6   * Second Life Viewer Source Code
    16.7 - * Copyright (C) 2012, Linden Research, Inc.
    16.8 + * Copyright (C) 2012-2013, Linden Research, Inc.
    16.9   *
   16.10   * This library is free software; you can redistribute it and/or
   16.11   * modify it under the terms of the GNU Lesser General Public
   16.12 @@ -29,9 +29,9 @@
   16.13  
   16.14  /// @package LLCore::HTTP
   16.15  ///
   16.16 -/// This library implements a high-level, Indra-code-free client interface to
   16.17 -/// HTTP services based on actual patterns found in the viewer and simulator.
   16.18 -/// Interfaces are similar to those supplied by the legacy classes
   16.19 +/// This library implements a high-level, Indra-code-free (somewhat) client
   16.20 +/// interface to HTTP services based on actual patterns found in the viewer
   16.21 +/// and simulator.  Interfaces are similar to those supplied by the legacy classes
   16.22  /// LLCurlRequest and LLHTTPClient.  To that is added a policy scheme that
   16.23  /// allows an application to specify connection behaviors:  limits on
   16.24  /// connections, HTTP keepalive, HTTP pipelining, retry-on-error limits, etc.
   16.25 @@ -52,7 +52,7 @@
   16.26  /// - "llcorehttp/httprequest.h"
   16.27  /// - "llcorehttp/httpresponse.h"
   16.28  ///
   16.29 -/// The library is still under early development and particular users
   16.30 +/// The library is still under development and particular users
   16.31  /// may need access to internal implementation details that are found
   16.32  /// in the _*.h header files.  But this is a crutch to be avoided if at
   16.33  /// all possible and probably indicates some interface work is neeeded.
   16.34 @@ -66,6 +66,8 @@
   16.35  ///   .  CRYPTO_set_id_callback(...)
   16.36  /// - HttpRequest::createService() called to instantiate singletons
   16.37  ///   and support objects.
   16.38 +/// - HttpRequest::startThread() to kick off the worker thread and
   16.39 +///   begin servicing requests.
   16.40  ///
   16.41  /// An HTTP consumer in an application, and an application may have many
   16.42  /// consumers, does a few things:
   16.43 @@ -91,10 +93,12 @@
   16.44  ///   objects.
   16.45  /// - Do completion processing in your onCompletion() method.
   16.46  ///
   16.47 -/// Code fragments:
   16.48 -/// Rather than a poorly-maintained example in comments, look in the
   16.49 -/// example subdirectory which is a minimal yet functional tool to do
   16.50 -/// GET request performance testing.  With four calls:
   16.51 +/// Code fragments.
   16.52 +///
   16.53 +/// Initialization.  Rather than a poorly-maintained example in
   16.54 +/// comments, look in the example subdirectory which is a minimal
   16.55 +/// yet functional tool to do GET request performance testing.
   16.56 +/// With four calls:
   16.57  ///
   16.58  ///   	init_curl();
   16.59  ///     LLCore::HttpRequest::createService();
   16.60 @@ -103,7 +107,85 @@
   16.61  ///
   16.62  /// the program is basically ready to issue requests.
   16.63  ///
   16.64 -
   16.65 +/// HttpHandler.  Having started life as a non-indra library,
   16.66 +/// this code broke away from the classic Responder model and
   16.67 +/// introduced a handler class to represent an interface for
   16.68 +/// request responses.  This is a non-reference-counted entity
   16.69 +/// which can be used as a base class or a mixin.  An instance
   16.70 +/// of a handler can be used for each request or can be shared
   16.71 +/// among any number of requests.  Your choice but expect to
   16.72 +/// code something like the following:
   16.73 +///
   16.74 +///     class AppHandler : public LLCore::HttpHandler
   16.75 +///     {
   16.76 +///     public:
   16.77 +///         virtual void onCompleted(HttpHandle handle,
   16.78 +///                                  HttpResponse * response)
   16.79 +///         {
   16.80 +///             ...
   16.81 +///         }
   16.82 +///         ...
   16.83 +///     };
   16.84 +///     ...
   16.85 +///     handler = new handler(...);
   16.86 +///
   16.87 +///
   16.88 +/// Issuing requests.  Using 'hr' above,
   16.89 +///
   16.90 +///     hr->requestGet(HttpRequest::DEFAULT_POLICY_ID,
   16.91 +///                    0,				// Priority, not used yet
   16.92 +///                    url,
   16.93 +///                    NULL,			// options
   16.94 +///                    NULL,            // additional headers
   16.95 +///                    handler);
   16.96 +///
   16.97 +/// If that returns a value other than LLCORE_HTTP_HANDLE_INVALID,
   16.98 +/// the request was successfully issued and there will eventally
   16.99 +/// be a status delivered to the handler.  If invalid is returnedd,
  16.100 +/// the actual status can be retrieved by calling hr->getStatus().
  16.101 +///
  16.102 +/// Completing requests and delivering notifications.  Operations
  16.103 +/// are all performed by the worker thread and will be driven to
  16.104 +/// completion regardless of caller actions.  Notification of
  16.105 +/// completion (success or failure) is done by calls to
  16.106 +/// HttpRequest::update() which will invoke handlers for completed
  16.107 +/// requests:
  16.108 +///
  16.109 +///     hr->update(0);
  16.110 +///       // Callbacks into handler->onCompleted()
  16.111 +///
  16.112 +///
  16.113 +/// Threads.
  16.114 +///
  16.115 +/// Threads are supported and used by this library.  The various
  16.116 +/// classes, methods and members are documented with thread
  16.117 +/// constraints which programmers must follow and which are
  16.118 +/// defined as follows:
  16.119 +///
  16.120 +/// consumer	Any thread that has instanced HttpRequest and is
  16.121 +///             issuing requests.  A particular instance can only
  16.122 +///             be used by one consumer thread but a consumer may
  16.123 +///             have many instances available to it.
  16.124 +/// init		Special consumer thread, usually the main thread,
  16.125 +///             involved in setting up the library at startup.
  16.126 +/// worker      Thread used internally by the library to perform
  16.127 +///             HTTP operations.  Consumers will not have to deal
  16.128 +///             with this thread directly but some APIs are reserved
  16.129 +///             to it.
  16.130 +/// any         Consumer or worker thread.
  16.131 +///
  16.132 +/// For the most part, API users will not have to do much in the
  16.133 +/// way of ensuring thread safely.  However, there is a tremendous
  16.134 +/// amount of sharing between threads of read-only data.  So when
  16.135 +/// documentation declares that an option or header instance
  16.136 +/// becomes shared between consumer and worker, the consumer must
  16.137 +/// not modify the shared object.
  16.138 +///
  16.139 +/// Internally, there is almost no thread synchronization.  During
  16.140 +/// normal operations (non-init, non-term), only the request queue
  16.141 +/// and the multiple reply queues are shared between threads and
  16.142 +/// only here are mutexes used.
  16.143 +///
  16.144  
  16.145  #include "linden_common.h"		// Modifies curl/curl.h interfaces
  16.146  
  16.147 @@ -239,9 +321,10 @@
  16.148  			return *this;
  16.149  		}
  16.150  	
  16.151 -	static const type_enum_t EXT_CURL_EASY = 0;
  16.152 -	static const type_enum_t EXT_CURL_MULTI = 1;
  16.153 -	static const type_enum_t LLCORE = 2;
  16.154 +	static const type_enum_t EXT_CURL_EASY = 0;			///< mStatus is an error from a curl_easy_*() call
  16.155 +	static const type_enum_t EXT_CURL_MULTI = 1;		///< mStatus is an error from a curl_multi_*() call
  16.156 +	static const type_enum_t LLCORE = 2;				///< mStatus is an HE_* error code
  16.157 +														///< 100-999 directly represent HTTP status codes
  16.158  	
  16.159  	type_enum_t			mType;
  16.160  	short				mStatus;
    17.1 --- a/indra/llcorehttp/httprequest.cpp	Mon Jul 08 20:31:09 2013 +0000
    17.2 +++ b/indra/llcorehttp/httprequest.cpp	Fri Jul 12 15:00:24 2013 -0400
    17.3 @@ -4,7 +4,7 @@
    17.4   *
    17.5   * $LicenseInfo:firstyear=2012&license=viewerlgpl$
    17.6   * Second Life Viewer Source Code
    17.7 - * Copyright (C) 2012, Linden Research, Inc.
    17.8 + * Copyright (C) 2012-2013, Linden Research, Inc.
    17.9   *
   17.10   * This library is free software; you can redistribute it and/or
   17.11   * modify it under the terms of the GNU Lesser General Public
   17.12 @@ -54,12 +54,8 @@
   17.13  // ====================================
   17.14  
   17.15  
   17.16 -HttpRequest::policy_t HttpRequest::sNextPolicyID(1);
   17.17 -
   17.18 -
   17.19  HttpRequest::HttpRequest()
   17.20 -	: //HttpHandler(),
   17.21 -	  mReplyQueue(NULL),
   17.22 +	: mReplyQueue(NULL),
   17.23  	  mRequestQueue(NULL)
   17.24  {
   17.25  	mRequestQueue = HttpRequestQueue::instanceOf();
   17.26 @@ -90,26 +86,6 @@
   17.27  // ====================================
   17.28  
   17.29  
   17.30 -HttpStatus HttpRequest::setPolicyGlobalOption(EGlobalPolicy opt, long value)
   17.31 -{
   17.32 -	if (HttpService::RUNNING == HttpService::instanceOf()->getState())
   17.33 -	{
   17.34 -		return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC);
   17.35 -	}
   17.36 -	return HttpService::instanceOf()->getGlobalOptions().set(opt, value);
   17.37 -}
   17.38 -
   17.39 -
   17.40 -HttpStatus HttpRequest::setPolicyGlobalOption(EGlobalPolicy opt, const std::string & value)
   17.41 -{
   17.42 -	if (HttpService::RUNNING == HttpService::instanceOf()->getState())
   17.43 -	{
   17.44 -		return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC);
   17.45 -	}
   17.46 -	return HttpService::instanceOf()->getGlobalOptions().set(opt, value);
   17.47 -}
   17.48 -
   17.49 -
   17.50  HttpRequest::policy_t HttpRequest::createPolicyClass()
   17.51  {
   17.52  	if (HttpService::RUNNING == HttpService::instanceOf()->getState())
   17.53 @@ -120,15 +96,81 @@
   17.54  }
   17.55  
   17.56  
   17.57 -HttpStatus HttpRequest::setPolicyClassOption(policy_t policy_id,
   17.58 -											 EClassPolicy opt,
   17.59 -											 long value)
   17.60 +HttpStatus HttpRequest::setStaticPolicyOption(EPolicyOption opt, policy_t pclass,
   17.61 +											  long value, long * ret_value)
   17.62  {
   17.63  	if (HttpService::RUNNING == HttpService::instanceOf()->getState())
   17.64  	{
   17.65  		return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC);
   17.66  	}
   17.67 -	return HttpService::instanceOf()->getClassOptions(policy_id).set(opt, value);
   17.68 +	return HttpService::instanceOf()->setPolicyOption(opt, pclass, value, ret_value);
   17.69 +}
   17.70 +
   17.71 +
   17.72 +HttpStatus HttpRequest::setStaticPolicyOption(EPolicyOption opt, policy_t pclass,
   17.73 +											  const std::string & value, std::string * ret_value)
   17.74 +{
   17.75 +	if (HttpService::RUNNING == HttpService::instanceOf()->getState())
   17.76 +	{
   17.77 +		return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC);
   17.78 +	}
   17.79 +	return HttpService::instanceOf()->setPolicyOption(opt, pclass, value, ret_value);
   17.80 +}
   17.81 +
   17.82 +
   17.83 +HttpHandle HttpRequest::setPolicyOption(EPolicyOption opt, policy_t pclass,
   17.84 +										long value, HttpHandler * handler)
   17.85 +{
   17.86 +	HttpStatus status;
   17.87 +	HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
   17.88 +
   17.89 +	HttpOpSetGet * op = new HttpOpSetGet();
   17.90 +	if (! (status = op->setupSet(opt, pclass, value)))
   17.91 +	{
   17.92 +		op->release();
   17.93 +		mLastReqStatus = status;
   17.94 +		return handle;
   17.95 +	}
   17.96 +	op->setReplyPath(mReplyQueue, handler);
   17.97 +	if (! (status = mRequestQueue->addOp(op)))			// transfers refcount
   17.98 +	{
   17.99 +		op->release();
  17.100 +		mLastReqStatus = status;
  17.101 +		return handle;
  17.102 +	}
  17.103 +	
  17.104 +	mLastReqStatus = status;
  17.105 +	handle = static_cast<HttpHandle>(op);
  17.106 +	
  17.107 +	return handle;
  17.108 +}
  17.109 +
  17.110 +
  17.111 +HttpHandle HttpRequest::setPolicyOption(EPolicyOption opt, policy_t pclass,
  17.112 +										const std::string & value, HttpHandler * handler)
  17.113 +{
  17.114 +	HttpStatus status;
  17.115 +	HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
  17.116 +
  17.117 +	HttpOpSetGet * op = new HttpOpSetGet();
  17.118 +	if (! (status = op->setupSet(opt, pclass, value)))
  17.119 +	{
  17.120 +		op->release();
  17.121 +		mLastReqStatus = status;
  17.122 +		return handle;
  17.123 +	}
  17.124 +	op->setReplyPath(mReplyQueue, handler);
  17.125 +	if (! (status = mRequestQueue->addOp(op)))			// transfers refcount
  17.126 +	{
  17.127 +		op->release();
  17.128 +		mLastReqStatus = status;
  17.129 +		return handle;
  17.130 +	}
  17.131 +	
  17.132 +	mLastReqStatus = status;
  17.133 +	handle = static_cast<HttpHandle>(op);
  17.134 +	
  17.135 +	return handle;
  17.136  }
  17.137  
  17.138  
  17.139 @@ -474,31 +516,6 @@
  17.140  	return handle;
  17.141  }
  17.142  
  17.143 -// ====================================
  17.144 -// Dynamic Policy Methods
  17.145 -// ====================================
  17.146 -
  17.147 -HttpHandle HttpRequest::requestSetHttpProxy(const std::string & proxy, HttpHandler * handler)
  17.148 -{
  17.149 -	HttpStatus status;
  17.150 -	HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
  17.151 -
  17.152 -	HttpOpSetGet * op = new HttpOpSetGet();
  17.153 -	op->setupSet(GP_HTTP_PROXY, proxy);
  17.154 -	op->setReplyPath(mReplyQueue, handler);
  17.155 -	if (! (status = mRequestQueue->addOp(op)))			// transfers refcount
  17.156 -	{
  17.157 -		op->release();
  17.158 -		mLastReqStatus = status;
  17.159 -		return handle;
  17.160 -	}
  17.161 -
  17.162 -	mLastReqStatus = status;
  17.163 -	handle = static_cast<HttpHandle>(op);
  17.164 -
  17.165 -	return handle;
  17.166 -}
  17.167 -
  17.168  
  17.169  }   // end namespace LLCore
  17.170  
    18.1 --- a/indra/llcorehttp/httprequest.h	Mon Jul 08 20:31:09 2013 +0000
    18.2 +++ b/indra/llcorehttp/httprequest.h	Fri Jul 12 15:00:24 2013 -0400
    18.3 @@ -56,6 +56,9 @@
    18.4  /// The class supports the current HTTP request operations:
    18.5  ///
    18.6  /// - requestGetByteRange:  GET with Range header for a single range of bytes
    18.7 +/// - requestGet:
    18.8 +/// - requestPost:
    18.9 +/// - requestPut:
   18.10  ///
   18.11  /// Policy Classes
   18.12  ///
   18.13 @@ -100,61 +103,9 @@
   18.14  
   18.15  	/// Represents a default, catch-all policy class that guarantees
   18.16  	/// eventual service for any HTTP request.
   18.17 -	static const int DEFAULT_POLICY_ID = 0;
   18.18 -
   18.19 -	enum EGlobalPolicy
   18.20 -	{
   18.21 -		/// Maximum number of connections the library will use to
   18.22 -		/// perform operations.  This is somewhat soft as the underlying
   18.23 -		/// transport will cache some connections (up to 5).
   18.24 -
   18.25 -		/// A long value setting the maximum number of connections
   18.26 -		/// allowed over all policy classes.  Note that this will be
   18.27 -		/// a somewhat soft value.  There may be an additional five
   18.28 -		/// connections per policy class depending upon runtime
   18.29 -		/// behavior.
   18.30 -		GP_CONNECTION_LIMIT,
   18.31 -
   18.32 -		/// String containing a system-appropriate directory name
   18.33 -		/// where SSL certs are stored.
   18.34 -		GP_CA_PATH,
   18.35 -
   18.36 -		/// String giving a full path to a file containing SSL certs.
   18.37 -		GP_CA_FILE,
   18.38 -
   18.39 -		/// String of host/port to use as simple HTTP proxy.  This is
   18.40 -		/// going to change in the future into something more elaborate
   18.41 -		/// that may support richer schemes.
   18.42 -		GP_HTTP_PROXY,
   18.43 -
   18.44 -		/// Long value that if non-zero enables the use of the
   18.45 -		/// traditional LLProxy code for http/socks5 support.  If
   18.46 -		/// enabled, has priority over GP_HTTP_PROXY.
   18.47 -		GP_LLPROXY,
   18.48 -
   18.49 -		/// Long value setting the logging trace level for the
   18.50 -		/// library.  Possible values are:
   18.51 -		/// 0 - No tracing (default)
   18.52 -		/// 1 - Basic tracing of request start, stop and major events.
   18.53 -		/// 2 - Connection, header and payload size information from
   18.54 -		///     HTTP transactions.
   18.55 -		/// 3 - Partial logging of payload itself.
   18.56 -		///
   18.57 -		/// These values are also used in the trace modes for
   18.58 -		/// individual requests in HttpOptions.  Also be aware that
   18.59 -		/// tracing tends to impact performance of the viewer.
   18.60 -		GP_TRACE
   18.61 -	};
   18.62 -
   18.63 -	/// Set a parameter on a global policy option.  Calls
   18.64 -	/// made after the start of the servicing thread are
   18.65 -	/// not honored and return an error status.
   18.66 -	///
   18.67 -	/// @param opt		Enum of option to be set.
   18.68 -	/// @param value	Desired value of option.
   18.69 -	/// @return			Standard status code.
   18.70 -	static HttpStatus setPolicyGlobalOption(EGlobalPolicy opt, long value);
   18.71 -	static HttpStatus setPolicyGlobalOption(EGlobalPolicy opt, const std::string & value);
   18.72 +	static const policy_t DEFAULT_POLICY_ID = 0;
   18.73 +	static const policy_t INVALID_POLICY_ID = 0xFFFFFFFFU;
   18.74 +	static const policy_t GLOBAL_POLICY_ID = 0xFFFFFFFEU;
   18.75  
   18.76  	/// Create a new policy class into which requests can be made.
   18.77  	///
   18.78 @@ -171,29 +122,93 @@
   18.79  	///
   18.80  	static policy_t createPolicyClass();
   18.81  
   18.82 -	enum EClassPolicy
   18.83 +	enum EPolicyOption
   18.84  	{
   18.85 -		/// Limits the number of connections used for the class.
   18.86 -		CP_CONNECTION_LIMIT,
   18.87 +		/// Maximum number of connections the library will use to
   18.88 +		/// perform operations.  This is somewhat soft as the underlying
   18.89 +		/// transport will cache some connections (up to 5).
   18.90 +
   18.91 +		/// A long value setting the maximum number of connections
   18.92 +		/// allowed over all policy classes.  Note that this will be
   18.93 +		/// a somewhat soft value.  There may be an additional five
   18.94 +		/// connections per policy class depending upon runtime
   18.95 +		/// behavior.
   18.96 +		///
   18.97 +		/// Both global and per-class
   18.98 +		PO_CONNECTION_LIMIT,
   18.99  
  18.100  		/// Limits the number of connections used for a single
  18.101  		/// literal address/port pair within the class.
  18.102 -		CP_PER_HOST_CONNECTION_LIMIT,
  18.103 +		PO_PER_HOST_CONNECTION_LIMIT,
  18.104 +
  18.105 +		/// String containing a system-appropriate directory name
  18.106 +		/// where SSL certs are stored.
  18.107 +		PO_CA_PATH,
  18.108 +
  18.109 +		/// String giving a full path to a file containing SSL certs.
  18.110 +		PO_CA_FILE,
  18.111 +
  18.112 +		/// String of host/port to use as simple HTTP proxy.  This is
  18.113 +		/// going to change in the future into something more elaborate
  18.114 +		/// that may support richer schemes.
  18.115 +		PO_HTTP_PROXY,
  18.116 +
  18.117 +		/// Long value that if non-zero enables the use of the
  18.118 +		/// traditional LLProxy code for http/socks5 support.  If
  18.119 +		// enabled, has priority over GP_HTTP_PROXY.
  18.120 +		PO_LLPROXY,
  18.121 +
  18.122 +		/// Long value setting the logging trace level for the
  18.123 +		/// library.  Possible values are:
  18.124 +		/// 0 - No tracing (default)
  18.125 +		/// 1 - Basic tracing of request start, stop and major events.
  18.126 +		/// 2 - Connection, header and payload size information from
  18.127 +		///     HTTP transactions.
  18.128 +		/// 3 - Partial logging of payload itself.
  18.129 +		///
  18.130 +		/// These values are also used in the trace modes for
  18.131 +		/// individual requests in HttpOptions.  Also be aware that
  18.132 +		/// tracing tends to impact performance of the viewer.
  18.133 +		PO_TRACE,
  18.134  
  18.135  		/// Suitable requests are allowed to pipeline on their
  18.136  		/// connections when they ask for it.
  18.137 -		CP_ENABLE_PIPELINING
  18.138 +		PO_ENABLE_PIPELINING,
  18.139 +
  18.140 +		PO_LAST  // Always at end
  18.141  	};
  18.142 -	
  18.143 +
  18.144 +	/// Set a policy option for a global or class parameter at
  18.145 +	/// startup time (prior to thread start).
  18.146 +	///
  18.147 +	/// @param opt			Enum of option to be set.
  18.148 +	/// @param pclass		For class-based options, the policy class ID to
  18.149 +	///					    be changed.  For globals, specify GLOBAL_POLICY_ID.
  18.150 +	/// @param value		Desired value of option.
  18.151 +	/// @param ret_value	Pointer to receive effective set value
  18.152 +	///						if successful.  May be NULL if effective
  18.153 +	///						value not wanted.
  18.154 +	/// @return				Standard status code.
  18.155 +	static HttpStatus setStaticPolicyOption(EPolicyOption opt, policy_t pclass,
  18.156 +											long value, long * ret_value);
  18.157 +	static HttpStatus setStaticPolicyOption(EPolicyOption opt, policy_t pclass,
  18.158 +											const std::string & value, std::string * ret_value);
  18.159 +
  18.160  	/// Set a parameter on a class-based policy option.  Calls
  18.161  	/// made after the start of the servicing thread are
  18.162  	/// not honored and return an error status.
  18.163  	///
  18.164 -	/// @param policy_id		ID of class as returned by @see createPolicyClass().
  18.165 -	/// @param opt				Enum of option to be set.
  18.166 -	/// @param value			Desired value of option.
  18.167 -	/// @return					Standard status code.
  18.168 -	static HttpStatus setPolicyClassOption(policy_t policy_id, EClassPolicy opt, long value);
  18.169 +	/// @param opt			Enum of option to be set.
  18.170 +	/// @param pclass		For class-based options, the policy class ID to
  18.171 +	///					    be changed.  Ignored for globals but recommend
  18.172 +	///					    using INVALID_POLICY_ID in this case.
  18.173 +	/// @param value		Desired value of option.
  18.174 +	/// @return				Handle of dynamic request.  Use @see getStatus() if
  18.175 +	///						the returned handle is invalid.
  18.176 +	HttpHandle setPolicyOption(EPolicyOption opt, policy_t pclass, long value,
  18.177 +							   HttpHandler * handler);
  18.178 +	HttpHandle setPolicyOption(EPolicyOption opt, policy_t pclass, const std::string & value,
  18.179 +							   HttpHandler * handler);
  18.180  
  18.181  	/// @}
  18.182  
  18.183 @@ -495,16 +510,6 @@
  18.184  
  18.185  	/// @}
  18.186  	
  18.187 -	/// @name DynamicPolicyMethods
  18.188 -	///
  18.189 -	/// @{
  18.190 -
  18.191 -	/// Request that a running transport pick up a new proxy setting.
  18.192 -	/// An empty string will indicate no proxy is to be used.
  18.193 -	HttpHandle requestSetHttpProxy(const std::string & proxy, HttpHandler * handler);
  18.194 -
  18.195 -    /// @}
  18.196 -
  18.197  protected:
  18.198  	void generateNotification(HttpOperation * op);
  18.199  
  18.200 @@ -526,7 +531,6 @@
  18.201  	/// Must be established before any threading is allowed to
  18.202  	/// start.
  18.203  	///
  18.204 -	static policy_t		sNextPolicyID;
  18.205  	
  18.206  	/// @}
  18.207  	// End Global State
    19.1 --- a/indra/llcorehttp/tests/test_httprequest.hpp	Mon Jul 08 20:31:09 2013 +0000
    19.2 +++ b/indra/llcorehttp/tests/test_httprequest.hpp	Fri Jul 12 15:00:24 2013 -0400
    19.3 @@ -1213,7 +1213,7 @@
    19.4  		HttpRequest::createService();
    19.5  
    19.6  		// Enable tracing
    19.7 -		HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_TRACE, 2);
    19.8 +		HttpRequest::setStaticPolicyOption(HttpRequest::PO_TRACE, HttpRequest::DEFAULT_POLICY_ID, 2, NULL);
    19.9  
   19.10  		// Start threading early so that thread memory is invariant
   19.11  		// over the test.
   19.12 @@ -1331,7 +1331,7 @@
   19.13  		HttpRequest::createService();
   19.14  
   19.15  		// Enable tracing
   19.16 -		HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_TRACE, 2);
   19.17 +		HttpRequest::setStaticPolicyOption(HttpRequest::PO_TRACE, HttpRequest::DEFAULT_POLICY_ID, 2, NULL);
   19.18  
   19.19  		// Start threading early so that thread memory is invariant
   19.20  		// over the test.
   19.21 @@ -2972,6 +2972,142 @@
   19.22  }
   19.23  
   19.24  
   19.25 +template <> template <>
   19.26 +void HttpRequestTestObjectType::test<22>()
   19.27 +{
   19.28 +	ScopedCurlInit ready;
   19.29 +
   19.30 +	set_test_name("HttpRequest GET 503s with 'Retry-After'");
   19.31 +
   19.32 +	// This tests mainly that the code doesn't fall over if
   19.33 +	// various well- and mis-formed Retry-After headers are
   19.34 +	// sent along with the response.  Direct inspection of
   19.35 +	// the parsing result isn't supported.
   19.36 +	
   19.37 +	// Handler can be stack-allocated *if* there are no dangling
   19.38 +	// references to it after completion of this method.
   19.39 +	// Create before memory record as the string copy will bump numbers.
   19.40 +	TestHandler2 handler(this, "handler");
   19.41 +	std::string url_base(get_base_url() + "/503/");	// path to 503 generators
   19.42 +		
   19.43 +	// record the total amount of dynamically allocated memory
   19.44 +	mMemTotal = GetMemTotal();
   19.45 +	mHandlerCalls = 0;
   19.46 +
   19.47 +	HttpRequest * req = NULL;
   19.48 +	HttpOptions * opts = NULL;
   19.49 +	
   19.50 +	try
   19.51 +	{
   19.52 +		// Get singletons created
   19.53 +		HttpRequest::createService();
   19.54 +		
   19.55 +		// Start threading early so that thread memory is invariant
   19.56 +		// over the test.
   19.57 +		HttpRequest::startThread();
   19.58 +
   19.59 +		// create a new ref counted object with an implicit reference
   19.60 +		req = new HttpRequest();
   19.61 +		ensure("Memory allocated on construction", mMemTotal < GetMemTotal());
   19.62 +
   19.63 +		opts = new HttpOptions();
   19.64 +		opts->setRetries(1);			// Retry once only
   19.65 +		opts->setUseRetryAfter(true);	// Try to parse the retry-after header
   19.66 +		
   19.67 +		// Issue a GET that 503s with valid retry-after
   19.68 +		mStatus = HttpStatus(503);
   19.69 +		int url_limit(6);
   19.70 +		for (int i(0); i < url_limit; ++i)
   19.71 +		{
   19.72 +			std::ostringstream url;
   19.73 +			url << url_base << i << "/";
   19.74 +			HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
   19.75 +														 0U,
   19.76 +														 url.str(),
   19.77 +														 0,
   19.78 +														 0,
   19.79 +														 opts,
   19.80 +														 NULL,
   19.81 +														 &handler);
   19.82 +
   19.83 +			std::ostringstream testtag;
   19.84 +			testtag << "Valid handle returned for 503 request #" << i;
   19.85 +			ensure(testtag.str(), handle != LLCORE_HTTP_HANDLE_INVALID);
   19.86 +		}
   19.87 +		
   19.88 +
   19.89 +		// Run the notification pump.
   19.90 +		int count(0);
   19.91 +		int limit(300);				// One retry but several seconds needed
   19.92 +		while (count++ < limit && mHandlerCalls < url_limit)
   19.93 +		{
   19.94 +			req->update(0);
   19.95 +			usleep(100000);
   19.96 +		}
   19.97 +		ensure("Request executed in reasonable time", count < limit);
   19.98 +		ensure("One handler invocation for request", mHandlerCalls == url_limit);
   19.99 +
  19.100 +		// Okay, request a shutdown of the servicing thread
  19.101 +		mStatus = HttpStatus();
  19.102 +		mHandlerCalls = 0;
  19.103 +		HttpHandle handle = req->requestStopThread(&handler);
  19.104 +		ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
  19.105 +	
  19.106 +		// Run the notification pump again
  19.107 +		count = 0;
  19.108 +		limit = 100;
  19.109 +		while (count++ < limit && mHandlerCalls < 1)
  19.110 +		{
  19.111 +			req->update(1000000);
  19.112 +			usleep(100000);
  19.113 +		}
  19.114 +		ensure("Second request executed in reasonable time", count < limit);
  19.115 +		ensure("Second handler invocation", mHandlerCalls == 1);
  19.116 +
  19.117 +		// See that we actually shutdown the thread
  19.118 +		count = 0;
  19.119 +		limit = 10;
  19.120 +		while (count++ < limit && ! HttpService::isStopped())
  19.121 +		{
  19.122 +			usleep(100000);
  19.123 +		}
  19.124 +		ensure("Thread actually stopped running", HttpService::isStopped());
  19.125 +
  19.126 +		// release options
  19.127 +		opts->release();
  19.128 +		opts = NULL;
  19.129 +		
  19.130 +		// release the request object
  19.131 +		delete req;
  19.132 +		req = NULL;
  19.133 +
  19.134 +		// Shut down service
  19.135 +		HttpRequest::destroyService();
  19.136 +	
  19.137 +#if defined(WIN32)
  19.138 +		// Can only do this memory test on Windows.  On other platforms,
  19.139 +		// the LL logging system holds on to memory and produces what looks
  19.140 +		// like memory leaks...
  19.141 +	
  19.142 +		// printf("Old mem:  %d, New mem:  %d\n", mMemTotal, GetMemTotal());
  19.143 +		ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal());
  19.144 +#endif
  19.145 +	}
  19.146 +	catch (...)
  19.147 +	{
  19.148 +		stop_thread(req);
  19.149 +		if (opts)
  19.150 +		{
  19.151 +			opts->release();
  19.152 +			opts = NULL;
  19.153 +		}
  19.154 +		delete req;
  19.155 +		HttpRequest::destroyService();
  19.156 +		throw;
  19.157 +	}
  19.158 +}
  19.159 +
  19.160 +
  19.161  }  // end namespace tut
  19.162  
  19.163  namespace
    20.1 --- a/indra/llcorehttp/tests/test_llcorehttp_peer.py	Mon Jul 08 20:31:09 2013 +0000
    20.2 +++ b/indra/llcorehttp/tests/test_llcorehttp_peer.py	Fri Jul 12 15:00:24 2013 -0400
    20.3 @@ -9,7 +9,7 @@
    20.4  
    20.5  $LicenseInfo:firstyear=2008&license=viewerlgpl$
    20.6  Second Life Viewer Source Code
    20.7 -Copyright (C) 2012, Linden Research, Inc.
    20.8 +Copyright (C) 2012-2013, Linden Research, Inc.
    20.9  
   20.10  This library is free software; you can redistribute it and/or
   20.11  modify it under the terms of the GNU Lesser General Public
   20.12 @@ -47,6 +47,17 @@
   20.13  class TestHTTPRequestHandler(BaseHTTPRequestHandler):
   20.14      """This subclass of BaseHTTPRequestHandler is to receive and echo
   20.15      LLSD-flavored messages sent by the C++ LLHTTPClient.
   20.16 +
   20.17 +    [Merge with viewer-cat later]
   20.18 +    - '/503/'           Generate 503 responses with various kinds
   20.19 +                        of 'retry-after' headers
   20.20 +    -- '/503/0/'            "Retry-After: 2"   
   20.21 +    -- '/503/1/'            "Retry-After: Thu, 31 Dec 2043 23:59:59 GMT"
   20.22 +    -- '/503/2/'            "Retry-After: Fri, 31 Dec 1999 23:59:59 GMT"
   20.23 +    -- '/503/3/'            "Retry-After: "
   20.24 +    -- '/503/4/'            "Retry-After: (*#*(@*(@(")"
   20.25 +    -- '/503/5/'            "Retry-After: aklsjflajfaklsfaklfasfklasdfklasdgahsdhgasdiogaioshdgo"
   20.26 +    -- '/503/6/'            "Retry-After: 1 2 3 4 5 6 7 8 9 10"
   20.27      """
   20.28      def read(self):
   20.29          # The following logic is adapted from the library module
   20.30 @@ -107,7 +118,41 @@
   20.31          if "/sleep/" in self.path:
   20.32              time.sleep(30)
   20.33  
   20.34 -        if "fail" not in self.path:
   20.35 +        if "/503/" in self.path:
   20.36 +            # Tests for various kinds of 'Retry-After' header parsing
   20.37 +            body = None
   20.38 +            if "/503/0/" in self.path:
   20.39 +                self.send_response(503)
   20.40 +                self.send_header("retry-after", "2")
   20.41 +            elif "/503/1/" in self.path:
   20.42 +                self.send_response(503)
   20.43 +                self.send_header("retry-after", "Thu, 31 Dec 2043 23:59:59 GMT")
   20.44 +            elif "/503/2/" in self.path:
   20.45 +                self.send_response(503)
   20.46 +                self.send_header("retry-after", "Fri, 31 Dec 1999 23:59:59 GMT")
   20.47 +            elif "/503/3/" in self.path:
   20.48 +                self.send_response(503)
   20.49 +                self.send_header("retry-after", "")
   20.50 +            elif "/503/4/" in self.path:
   20.51 +                self.send_response(503)
   20.52 +                self.send_header("retry-after", "(*#*(@*(@(")
   20.53 +            elif "/503/5/" in self.path:
   20.54 +                self.send_response(503)
   20.55 +                self.send_header("retry-after", "aklsjflajfaklsfaklfasfklasdfklasdgahsdhgasdiogaioshdgo")
   20.56 +            elif "/503/6/" in self.path:
   20.57 +                self.send_response(503)
   20.58 +                self.send_header("retry-after", "1 2 3 4 5 6 7 8 9 10")
   20.59 +            else:
   20.60 +                # Unknown request
   20.61 +                self.send_response(400)
   20.62 +                body = "Unknown /503/ path in server"
   20.63 +            if "/reflect/" in self.path:
   20.64 +                self.reflect_headers()
   20.65 +            self.send_header("Content-type", "text/plain")
   20.66 +            self.end_headers()
   20.67 +            if body:
   20.68 +                self.wfile.write(body)
   20.69 +        elif "fail" not in self.path:
   20.70              data = data.copy()          # we're going to modify
   20.71              # Ensure there's a "reply" key in data, even if there wasn't before
   20.72              data["reply"] = data.get("reply", llsd.LLSD("success"))
    21.1 --- a/indra/newview/llappcorehttp.cpp	Mon Jul 08 20:31:09 2013 +0000
    21.2 +++ b/indra/newview/llappcorehttp.cpp	Fri Jul 12 15:00:24 2013 -0400
    21.3 @@ -105,8 +105,9 @@
    21.4  	}
    21.5  
    21.6  	// Point to our certs or SSH/https: will fail on connect
    21.7 -	status = LLCore::HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_CA_FILE,
    21.8 -														gDirUtilp->getCAFile());
    21.9 +	status = LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_CA_FILE,
   21.10 +														LLCore::HttpRequest::GLOBAL_POLICY_ID,
   21.11 +														gDirUtilp->getCAFile(), NULL);
   21.12  	if (! status)
   21.13  	{
   21.14  		LL_ERRS("Init") << "Failed to set CA File for HTTP services.  Reason:  " << status.toString()
   21.15 @@ -114,7 +115,9 @@
   21.16  	}
   21.17  
   21.18  	// Establish HTTP Proxy, if desired.
   21.19 -	status = LLCore::HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_LLPROXY, 1);
   21.20 +	status = LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_LLPROXY,
   21.21 +														LLCore::HttpRequest::GLOBAL_POLICY_ID,
   21.22 +														1, NULL);
   21.23  	if (! status)
   21.24  	{
   21.25  		LL_WARNS("Init") << "Failed to set HTTP proxy for HTTP services.  Reason:  " << status.toString()
   21.26 @@ -131,7 +134,9 @@
   21.27  	{
   21.28  		long trace_level(0L);
   21.29  		trace_level = long(gSavedSettings.getU32(http_trace));
   21.30 -		status = LLCore::HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_TRACE, trace_level);
   21.31 +		status = LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_TRACE,
   21.32 +															LLCore::HttpRequest::GLOBAL_POLICY_ID,
   21.33 +															trace_level, NULL);
   21.34  	}
   21.35  	
   21.36  	// Setup default policy and constrain if directed to
   21.37 @@ -164,6 +169,9 @@
   21.38  		}
   21.39  	}
   21.40  
   21.41 +	// Need a request object to handle dynamic options before setting them
   21.42 +	mRequest = new LLCore::HttpRequest;
   21.43 +
   21.44  	// Apply initial settings
   21.45  	refreshSettings(true);
   21.46  	
   21.47 @@ -175,8 +183,6 @@
   21.48  						<< LL_ENDL;
   21.49  	}
   21.50  
   21.51 -	mRequest = new LLCore::HttpRequest;
   21.52 -
   21.53  	// Register signals for settings and state changes
   21.54  	for (int i(0); i < LL_ARRAY_SIZE(init_data); ++i)
   21.55  	{
   21.56 @@ -287,12 +293,13 @@
   21.57  		// Set it and report
   21.58  		// *TODO:  These are intended to be per-host limits when we can
   21.59  		// support that in llcorehttp/libcurl.
   21.60 -		LLCore::HttpStatus status;
   21.61 -		status = LLCore::HttpRequest::setPolicyClassOption(mPolicies[policy],
   21.62 -														   LLCore::HttpRequest::CP_CONNECTION_LIMIT,
   21.63 -														   setting);
   21.64 -		if (! status)
   21.65 +		LLCore::HttpHandle handle;
   21.66 +		handle = mRequest->setPolicyOption(LLCore::HttpRequest::PO_CONNECTION_LIMIT,
   21.67 +										   mPolicies[policy],
   21.68 +										   setting, NULL);
   21.69 +		if (LLCORE_HTTP_HANDLE_INVALID == handle)
   21.70  		{
   21.71 +			LLCore::HttpStatus status(mRequest->getStatus());
   21.72  			LL_WARNS("Init") << "Unable to set " << init_data[i].mUsage
   21.73  							 << " concurrency.  Reason:  " << status.toString()
   21.74  							 << LL_ENDL;

mercurial