Commits

Scott Lawrence committed 5cba5f3 Merge

merge release tag

  • Participants
  • Parent commits 9505109, f6353f0

Comments (0)

Files changed (396)

 e9a5886052433d5db9e504ffaca10890f9932979 DRTVWR-243
 73b84b9864dc650fe7c8fc9f52361450f0849004 3.4.2-beta4
 16310aabccf315870f7cc9bf966926c0ad6954fa 3.4.2-release
+d799593b53ed733862e9a13871e318e886469377 DRTVWR-208
+e497dcde7a3653e384eb223a8a460030e89c294c DRTVWR-223
+93ab02d83f51e30a3cabad98aff89601befd9413 DRTVWR-240
+2aa72e3372a83dece4df9cf72fb1e7c34f90b5e3 DRTVWR-209
+f7bedce18ad52283e6072814db23318907261487 DRTVWR-238
+7b64c96fbcadf360bd2feaae19d330166b70877c DRTVWR-210
+5e4e4128b256525bafc07a62e35ae8527aaa9c9d DRTVWR-241
+f1d3b3fcab28ed9ea532bf50db0ba96f5c8cc8e9 DRTVWR-232
+4918b150e75df6b516fb6c2616d32043fa6b4cac DRTVWR-245
+94ab2b49458ab372a95d2d6949fdf574f413068d 3.4.3-beta1
+965b9a35e260c0f53be1a25f0db7abc8a67eaf47 DRTVWR-252
+bb10adc4f76cf0067fca7075146f00cdc0740e9d DRTVWR-251
+ab0aa2f6ba22b52fed30a2337197f589156edc75 DRTVWR-253
+48382ec79741671d19ce4cc3e8cd59e9a521e4a7 DRTVWR-254
+937ec902bb9a1cbceff17bd89e3923352b0a5fbc DRTVWR-256
+44e764a6ac9e672a4f3bce821a4b6a218590c374 DRTVWR-258
+c23d734065ed593b2413385aecd8366d8e0ee96b DRTVWR-257
+452ce96d4046dc05a3ecaecc203e2cc8ddd72e76 DRTVWR-259

File autobuild.xml

             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>d98078791ce345bf6168ce9ba53ca2d7</string>
+              <string>36aa500e13cdde61607b6e93065206ec</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-boost/rev/222752/arch/Darwin/installer/boost-1.45.0-darwin-20110304.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-boost/rev/261457/arch/Darwin/installer/boost-1.48.0-darwin-20120710.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>a34e7fffdb94a6a4d8a2966b1f216da3</string>
+              <string>18602d44bd435eb0d7189f436ff2cb0f</string>
               <key>url</key>
-              <string>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.45.0-linux-20110310.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-boost/rev/261457/arch/Linux/installer/boost-1.48.0-linux-20120710.tar.bz2</string>
             </map>
             <key>name</key>
             <string>linux</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>98be22c8833aa2bca184b9fa09fbb82b</string>
+              <string>dc8f5dc6be04c64bf3460b4932b18457</string>
               <key>url</key>
-              <string>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.45.0-windows-20110124.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-boost/rev/261457/arch/CYGWIN/installer/boost-1.48.0-windows-20120710.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>

File doc/contributions.txt

 	VWR-2682
 	VWR-2684
 Nick Rhodes
+Nicky Dasmijn
+	VWR-29228
 Nicky Perian
 	OPEN-1
 	STORM-1087
 	STORM-1602
 	STORM-1868
     VWR-26622
+	VWR-29224
 Talamasca
 Tali Rosca
 Tayra Dagostino
 Winter Ventura
 Wilton Lundquist
 	VWR-7682
+Wolf Loonie
+	STORM-1868
 WolfPup Lowenhar
 	OPEN-1
 	OPEN-37

File indra/CMakeLists.txt

 add_subdirectory(${LIBS_OPEN_PREFIX}llaudio)
 add_subdirectory(${LIBS_OPEN_PREFIX}llcharacter)
 add_subdirectory(${LIBS_OPEN_PREFIX}llcommon)
+add_subdirectory(${LIBS_OPEN_PREFIX}llcorehttp)
 add_subdirectory(${LIBS_OPEN_PREFIX}llimage)
 add_subdirectory(${LIBS_OPEN_PREFIX}llkdu)
 add_subdirectory(${LIBS_OPEN_PREFIX}llimagej2coj)

File indra/cmake/00-Common.cmake

File contents unchanged.

File indra/cmake/Boost.cmake

   set(BOOST_SIGNALS_LIBRARY boost_signals-mt)
   set(BOOST_SYSTEM_LIBRARY boost_system-mt)
   set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-mt)
+  set(BOOST_THREAD_LIBRARY boost_thread-mt)
 else (STANDALONE)
   use_prebuilt_binary(boost)
   set(Boost_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
 
   if (WINDOWS)
-    set(BOOST_VERSION 1_45)
+    set(BOOST_VERSION 1_48)
     if(MSVC80)
       set(BOOST_PROGRAM_OPTIONS_LIBRARY 
           optimized libboost_program_options-vc80-mt-${BOOST_VERSION}
     else(MSVC80)
       # MSVC 10.0 config
       set(BOOST_PROGRAM_OPTIONS_LIBRARY 
-          optimized libboost_program_options-vc100-mt-${BOOST_VERSION}
-          debug libboost_program_options-vc100-mt-gd-${BOOST_VERSION})
+          optimized libboost_program_options-mt
+          debug libboost_program_options-mt-gd)
       set(BOOST_REGEX_LIBRARY
-          optimized libboost_regex-vc100-mt-${BOOST_VERSION}
-          debug libboost_regex-vc100-mt-gd-${BOOST_VERSION})
+          optimized libboost_regex-mt
+          debug libboost_regex-mt-gd)
       set(BOOST_SYSTEM_LIBRARY 
-          optimized libboost_system-vc100-mt-${BOOST_VERSION}
-          debug libboost_system-vc100-mt-gd-${BOOST_VERSION})
+          optimized libboost_system-mt
+          debug libboost_system-mt-gd)
       set(BOOST_FILESYSTEM_LIBRARY 
-          optimized libboost_filesystem-vc100-mt-${BOOST_VERSION}
-          debug libboost_filesystem-vc100-mt-gd-${BOOST_VERSION})    
+          optimized libboost_filesystem-mt
+          debug libboost_filesystem-mt-gd)
+      set(BOOST_THREAD_LIBRARY 
+          optimized libboost_thread-mt
+          debug libboost_thread-mt-gd)
     endif (MSVC80)
-  elseif (DARWIN OR LINUX)
-    set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options)
-    set(BOOST_REGEX_LIBRARY boost_regex)
-    set(BOOST_SYSTEM_LIBRARY boost_system)
-    set(BOOST_FILESYSTEM_LIBRARY boost_filesystem)
+  elseif (LINUX)
+    set(BOOST_PROGRAM_OPTIONS_LIBRARY
+        optimized boost_program_options-mt
+        debug boost_program_options-mt-d)
+    set(BOOST_REGEX_LIBRARY
+        optimized boost_regex-mt
+        debug boost_regex-mt-d)
+    set(BOOST_SYSTEM_LIBRARY
+        optimized boost_system-mt
+        debug boost_system-mt-d)
+    set(BOOST_FILESYSTEM_LIBRARY
+        optimized boost_filesystem-mt
+        debug boost_filesystem-mt-d)
+    set(BOOST_THREAD_LIBRARY
+        optimized boost_thread-mt
+        debug boost_thread-mt-d)
+  elseif (DARWIN)
+    set(BOOST_PROGRAM_OPTIONS_LIBRARY
+        optimized boost_program_options-mt
+        debug boost_program_options-mt-d)
+    set(BOOST_PROGRAM_OPTIONS_LIBRARY
+        optimized boost_program_options-mt
+        debug boost_program_options-mt-d)
+    set(BOOST_REGEX_LIBRARY
+        optimized boost_regex-mt
+        debug boost_regex-mt-d)
+    set(BOOST_SYSTEM_LIBRARY
+        optimized boost_system-mt
+        debug boost_system-mt-d)
+    set(BOOST_FILESYSTEM_LIBRARY
+        optimized boost_filesystem-mt
+        debug boost_filesystem-mt-d)
+    set(BOOST_THREAD_LIBRARY
+        optimized boost_thread-mt
+        debug boost_thread-mt-d)
   endif (WINDOWS)
 endif (STANDALONE)

File indra/cmake/Copy3rdPartyLibs.cmake

         libapr-1.so.0
         libaprutil-1.so.0
         libatk-1.0.so
+        libboost_program_options-mt.so.1.48.0
+        libboost_regex-mt.so.1.48.0
+        libboost_thread-mt.so.1.48.0
+        libboost_filesystem-mt.so.1.48.0
+        libboost_signals-mt.so.1.48.0
+        libboost_system-mt.so.1.48.0
         libbreakpad_client.so.0
         libcollada14dom.so
         libcrypto.so.1.0.0

File indra/cmake/LLCommon.cmake

 
 add_definitions(${TCMALLOC_FLAG})
 
-set(LLCOMMON_LINK_SHARED OFF CACHE BOOL "Build the llcommon target as a shared library.")
+set(LLCOMMON_LINK_SHARED OFF CACHE BOOL "Build the llcommon target as a static library.")
 if(LLCOMMON_LINK_SHARED)
   add_definitions(-DLL_COMMON_LINK_SHARED=1)
 endif(LLCOMMON_LINK_SHARED)

File indra/cmake/LLCoreHttp.cmake

+# -*- cmake -*-
+
+include(CARes)
+include(CURL)
+include(OpenSSL)
+include(Boost)
+
+set(LLCOREHTTP_INCLUDE_DIRS
+    ${LIBS_OPEN_DIR}/llcorehttp
+    ${CARES_INCLUDE_DIRS}
+    ${CURL_INCLUDE_DIRS}
+    ${OPENSSL_INCLUDE_DIRS}
+    ${BOOST_INCLUDE_DIRS}
+    )
+
+set(LLCOREHTTP_LIBRARIES llcorehttp)

File indra/cmake/LLPrimitive.cmake

         optimized llprimitive
         debug libcollada14dom22-d
         optimized libcollada14dom22
-        debug libboost_filesystem-vc100-mt-gd-1_45
-        optimized libboost_filesystem-vc100-mt-1_45
-        debug libboost_system-vc100-mt-gd-1_45
-        optimized libboost_system-vc100-mt-1_45
+        debug libboost_filesystem-mt-gd
+        optimized libboost_filesystem-mt
+        debug libboost_system-mt-gd
+        optimized libboost_system-mt
         )
 else (WINDOWS)
     set(LLPRIMITIVE_LIBRARIES 

File indra/cmake/Variables.cmake

File contents unchanged.

File indra/integration_tests/llimage_libtest/llimage_libtest.cpp

 		LLDirIterator iter(dir, name);
 		while (iter.next(next_name))
 		{
-			std::string file_name = dir + gDirUtilp->getDirDelimiter() + next_name;
+			std::string file_name = gDirUtilp->add(dir, next_name);
 			input_filenames.push_back(file_name);
 		}
 	}

File indra/integration_tests/llui_libtest/llui_libtest.cpp

 };
 TestImageProvider gTestImageProvider;
 
-static std::string get_xui_dir()
-{
-	std::string delim = gDirUtilp->getDirDelimiter();
-	return gDirUtilp->getSkinBaseDir() + delim + "default" + delim + "xui" + delim;
-}
-
 void init_llui()
 {
 	// Font lookup needs directory support
 	const char* newview_path = "../../../newview";
 #endif
 	gDirUtilp->initAppDirs("SecondLife", newview_path);
-	gDirUtilp->setSkinFolder("default");
+	gDirUtilp->setSkinFolder("default", "en");
 	
 	// colors are no longer stored in a LLControlGroup file
 	LLUIColorTable::instance().loadFromSettings();
 
-	std::string config_filename = gDirUtilp->getExpandedFilename(
-																 LL_PATH_APP_SETTINGS, "settings.xml");
+	std::string config_filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "settings.xml");
 	gSavedSettings.loadFromFile(config_filename);
 	
 	// See LLAppViewer::init()
 	
 	const bool no_register_widgets = false;
 	LLWidgetReg::initClass( no_register_widgets );
-	
-	// Unclear if this is needed
-	LLUI::setupPaths();
+
 	// Otherwise we get translation warnings when setting up floaters
 	// (tooltips for buttons)
 	std::set<std::string> default_args;
 	// otherwise it crashes.
 	LLFontGL::initClass(96.f, 1.f, 1.f,
 						gDirUtilp->getAppRODataDir(),
-						LLUI::getXUIPaths(),
 						false );	// don't create gl textures
 	
 	LLFloaterView::Params fvparams;
 	gFloaterView = LLUICtrlFactory::create<LLFloaterView> (fvparams);
 }
 
+/*==========================================================================*|
+static std::string get_xui_dir()
+{
+	std::string delim = gDirUtilp->getDirDelimiter();
+	return gDirUtilp->getSkinBaseDir() + delim + "default" + delim + "xui" + delim;
+}
+
+// buildFromFile() no longer supports generate-output-LLXMLNode
 void export_test_floaters()
 {
 	// Convert all test floaters to new XML format
 		floater->buildFromFile(	filename,
 								//	 FALSE,	// don't open floater
 								output_node);
-		std::string out_filename = xui_dir + filename;
+		std::string out_filename = gDirUtilp->add(xui_dir, filename);
 		std::string::size_type extension_pos = out_filename.rfind(".xml");
 		out_filename.resize(extension_pos);
 		out_filename += "_new.xml";
 		fclose(floater_file);
 	}
 }
+|*==========================================================================*/
 
 int main(int argc, char** argv)
 {
 
 	init_llui();
 	
-	export_test_floaters();
+//	export_test_floaters();
 	
 	return 0;
 }

File indra/lib/python/indra/util/llmanifest.py

             d = src_re.sub(d_template, s.replace('\\', '/'))
             yield os.path.normpath(s), os.path.normpath(d)
 
+    def path2basename(self, path, file):
+        """
+        It is a common idiom to write:
+        self.path(os.path.join(somedir, somefile), somefile)
+
+        So instead you can write:
+        self.path2basename(somedir, somefile)
+
+        Note that this is NOT the same as:
+        self.path(os.path.join(somedir, somefile))
+
+        which is the same as:
+        temppath = os.path.join(somedir, somefile)
+        self.path(temppath, temppath)
+        """
+        return self.path(os.path.join(path, file), file)
+
     def path(self, src, dst=None):
         sys.stdout.write("Processing %s => %s ... " % (src, dst))
         sys.stdout.flush()
 
         print "%d files" % count
 
+        # Let caller check whether we processed as many files as expected. In
+        # particular, let caller notice 0.
+        return count
+
     def do(self, *actions):
         self.actions = actions
         self.construct()

File indra/linux_updater/linux_updater.cpp

 {
 	std::string image_filename;
 	iter.next(image_filename);
-	return image_path + "/" + image_filename;
+	return gDirUtilp->add(image_path, image_filename);
 }
 
 void on_window_closed(GtkWidget *sender, GdkEvent* event, gpointer data)

File indra/llaudio/llaudioengine.cpp

 	mBufferp->mAudioDatap = this;
 	return true;
 }
-
-

File indra/llcharacter/lleditingmotion.cpp

 	target = target * target_dist;
 	if (!target.isFinite())
 	{
-		llerrs << "Non finite target in editing motion with target distance of " << target_dist << 
+		// Don't error out here, set a fail-safe target vector
+		llwarns << "Non finite target in editing motion with target distance of " << target_dist << 
 			" and focus point " << focus_pt << llendl;
+		target.setVec(1.f, 1.f, 1.f);
 	}
 	
 	mTarget.setPosition( target + mParentJoint.getPosition());

File indra/llcommon/linden_common.h

 #include "llerror.h"
 #include "llfile.h"
 
+// Boost 1.45 had version 2 as the default for the filesystem library,
+// 1.48 has version 3 as the default.  Keep compatibility for now.
+#define BOOST_FILESYSTEM_VERSION		2
+
 #endif

File indra/llcommon/llapr.h

 	void operator -=(Type x) { apr_atomic_sub32(&mData, apr_uint32_t(x)); }
 	void operator +=(Type x) { apr_atomic_add32(&mData, apr_uint32_t(x)); }
 	Type operator ++(int) { return apr_atomic_inc32(&mData); } // Type++
-	Type operator --(int) { return apr_atomic_dec32(&mData); } // Type--
+	Type operator --(int) { return apr_atomic_dec32(&mData); } // approximately --Type (0 if final is 0, non-zero otherwise)
 	
 private:
 	apr_uint32_t mData;

File indra/llcommon/llsdserialize.cpp

 	}
 
 	case LLSD::TypeUUID:
+	{
 		ostr.put('u');
-		ostr.write((const char*)(&(data.asUUID().mData)), UUID_BYTES);
+		LLSD::UUID value = data.asUUID();
+		ostr.write((const char*)(&value.mData), UUID_BYTES);
 		break;
+	}
 
 	case LLSD::TypeString:
 		ostr.put('s');

File indra/llcommon/llstring.cpp

 
 std::string ll_safe_string(const char* in, S32 maxlen)
 {
-	if(in) return std::string(in, maxlen);
+	if(in && maxlen > 0 ) return std::string(in, maxlen);
+
 	return std::string();
 }
 

File indra/llcommon/llthread.cpp

 	}
 }
 
+void LLThread::registerThreadID()
+{
+#if !LL_DARWIN
+	sThreadID = ++sIDIter;
+#endif
+}
+
 //
 // Handed to the APR thread creation function
 //

File indra/llcommon/llthread.h

 
 	U32 getID() const { return mID; }
 
+	// Called by threads *not* created via LLThread to register some
+	// internal state used by LLMutex.  You must call this once early
+	// in the running thread to prevent collisions with the main thread.
+	static void registerThreadID();
+	
 private:
 	BOOL				mPaused;
 	

File indra/llcommon/lluri.cpp

 
 // system includes
 #include <boost/tokenizer.hpp>
+#include <boost/algorithm/string/find_iterator.hpp>
+#include <boost/algorithm/string/finder.hpp>
 
 void encode_character(std::ostream& ostr, std::string::value_type val)
 {
 					   const LLSD& path)
 {
 	LLURI result;
-	
+
 	// TODO: deal with '/' '?' '#' in host_port
 	if (prefix.find("://") != prefix.npos)
 	{
 			result.mEscapedPath += "/" + escapePathComponent(it->asString());
 		}
 	}
-	else if(path.isString())
+	else if (path.isString())
 	{
-		result.mEscapedPath += "/" + escapePathComponent(path.asString());
+		std::string pathstr(path);
+		// Trailing slash is significant in HTTP land. If caller specified,
+		// make a point of preserving.
+		std::string last_slash;
+		std::string::size_type len(pathstr.length());
+		if (len && pathstr[len-1] == '/')
+		{
+			last_slash = "/";
+		}
+
+		// Escape every individual path component, recombining with slashes.
+		for (boost::split_iterator<std::string::const_iterator>
+				 ti(pathstr, boost::first_finder("/")), tend;
+			 ti != tend; ++ti)
+		{
+			// Eliminate a leading slash or duplicate slashes anywhere. (Extra
+			// slashes show up here as empty components.) This test also
+			// eliminates a trailing slash, hence last_slash above.
+			if (! ti->empty())
+			{
+				result.mEscapedPath
+					+= "/" + escapePathComponent(std::string(ti->begin(), ti->end()));
+			}
+		}
+
+		// Reinstate trailing slash, if any.
+		result.mEscapedPath += last_slash;
 	} 
 	else if(path.isUndefined())
 	{
 	  // do nothing
 	}
-    else
+	else
 	{
 	  llwarns << "Valid path arguments to buildHTTP are array, string, or undef, you passed type" 
 			  << path.type() << llendl;

File indra/llcommon/llversionviewer.h

 
 const S32 LL_VERSION_MAJOR = 3;
 const S32 LL_VERSION_MINOR = 4;
-const S32 LL_VERSION_PATCH = 2;
+const S32 LL_VERSION_PATCH = 3;
 const S32 LL_VERSION_BUILD = 0;
 
 const char * const LL_CHANNEL = "Second Life Developer";

File indra/llcommon/tests/bitpack_test.cpp

 		ensure("bitPack: individual unpack: 5", unpackbuffer[0] == (U8) str[5]);
 		unpack_bufsize = bitunpack.bitUnpack(unpackbuffer, 8*4); // Life
 		ensure_memory_matches("bitPack: 4 bytes unpack:", unpackbuffer, 4, str+6, 4);
+		ensure("keep compiler quiet", unpack_bufsize == unpack_bufsize);
 	}
 
 	// U32 packing

File indra/llcommon/tests/lluri_test.cpp

 			ensure_equals("escape/unescape escaped", uri_esc_2, uri_esc_1);
 		}
 	};
-	
+
 	typedef test_group<URITestData>	URITestGroup;
 	typedef URITestGroup::object	URITestObject;
 
 	URITestGroup uriTestGroup("LLURI");
-	
+
 	template<> template<>
 	void URITestObject::test<1>()
 	{
 	template<> template<>
 	void URITestObject::test<2>()
 	{
-		// empty string
+		set_test_name("empty string");
 		checkParts(LLURI(""), "", "", "", "");
 	}
-	
+
 	template<> template<>
 	void URITestObject::test<3>()
 	{
-		// no scheme
+		set_test_name("no scheme");
 		checkParts(LLURI("foo"), "", "foo", "", "");
 		checkParts(LLURI("foo%3A"), "", "foo:", "", "");
 	}
 	template<> template<>
 	void URITestObject::test<4>()
 	{
-		// scheme w/o paths
+		set_test_name("scheme w/o paths");
 		checkParts(LLURI("mailto:zero@ll.com"),
 			"mailto", "zero@ll.com", "", "");
 		checkParts(LLURI("silly://abc/def?foo"),
 	template<> template<>
 	void URITestObject::test<5>()
 	{
-		// authority section
+		set_test_name("authority section");
 		checkParts(LLURI("http:///"),
 			"http", "///", "", "/");
-			
+
 		checkParts(LLURI("http://abc"),
 			"http", "//abc", "abc", "");
-			
+
 		checkParts(LLURI("http://a%2Fb/cd"),
 			"http", "//a/b/cd", "a/b", "/cd");
-			
+
 		checkParts(LLURI("http://host?"),
 			"http", "//host?", "host", "");
 	}
 	template<> template<>
 	void URITestObject::test<6>()
 	{		
-		// path section
+		set_test_name("path section");
 		checkParts(LLURI("http://host/a/b/"),
 				"http", "//host/a/b/", "host", "/a/b/");
-				
+
 		checkParts(LLURI("http://host/a%3Fb/"),
 				"http", "//host/a?b/", "host", "/a?b/");
-				
+
 		checkParts(LLURI("http://host/a:b/"),
 				"http", "//host/a:b/", "host", "/a:b/");
 	}
 	template<> template<>
 	void URITestObject::test<7>()
 	{		
-		// query string
+		set_test_name("query string");
 		checkParts(LLURI("http://host/?"),
 				"http", "//host/?", "host", "/", "");
-				
+
 		checkParts(LLURI("http://host/?x"),
 				"http", "//host/?x", "host", "/", "x");
-				
+
 		checkParts(LLURI("http://host/??"),
 				"http", "//host/??", "host", "/", "?");
-				
+
 		checkParts(LLURI("http://host/?%3F"),
 				"http", "//host/??", "host", "/", "?");
 	}
 		path.append("123");
 		checkParts(LLURI::buildHTTP("host", path),
 			"http", "//host/x/123", "host", "/x/123");
-		
+
 		LLSD query;
 		query["123"] = "12";
 		query["abcd"] = "abc";
 		checkParts(LLURI::buildHTTP("host", path, query),
 			"http", "//host/x/123?123=12&abcd=abc",
 			"host", "/x/123", "123=12&abcd=abc");
+
+		ensure_equals(LLURI::buildHTTP("host", "").asString(),
+					  "http://host");
+		ensure_equals(LLURI::buildHTTP("host", "/").asString(),
+					  "http://host/");
+		ensure_equals(LLURI::buildHTTP("host", "//").asString(),
+					  "http://host/");
+		ensure_equals(LLURI::buildHTTP("host", "dir name").asString(),
+					  "http://host/dir%20name");
+		ensure_equals(LLURI::buildHTTP("host", "dir name/").asString(),
+					  "http://host/dir%20name/");
+		ensure_equals(LLURI::buildHTTP("host", "/dir name").asString(),
+					  "http://host/dir%20name");
+		ensure_equals(LLURI::buildHTTP("host", "/dir name/").asString(),
+					  "http://host/dir%20name/");
+		ensure_equals(LLURI::buildHTTP("host", "dir name/subdir name").asString(),
+					  "http://host/dir%20name/subdir%20name");
+		ensure_equals(LLURI::buildHTTP("host", "dir name/subdir name/").asString(),
+					  "http://host/dir%20name/subdir%20name/");
+		ensure_equals(LLURI::buildHTTP("host", "/dir name/subdir name").asString(),
+					  "http://host/dir%20name/subdir%20name");
+		ensure_equals(LLURI::buildHTTP("host", "/dir name/subdir name/").asString(),
+					  "http://host/dir%20name/subdir%20name/");
+		ensure_equals(LLURI::buildHTTP("host", "//dir name//subdir name//").asString(),
+					  "http://host/dir%20name/subdir%20name/");
 	}
 
 	template<> template<>
 	void URITestObject::test<9>()
 	{
-		// test unescaped path components
+		set_test_name("test unescaped path components");
 		LLSD path;
 		path.append("x@*//*$&^");
 		path.append("123");
 	template<> template<>
 	void URITestObject::test<10>()
 	{
-		// test unescaped query components
+		set_test_name("test unescaped query components");
 		LLSD path;
 		path.append("x");
 		path.append("123");
 	template<> template<>
 	void URITestObject::test<11>()
 	{
-		// test unescaped host components
+		set_test_name("test unescaped host components");
 		LLSD path;
 		path.append("x");
 		path.append("123");
 			"http", "//hi123*33--}{:portstuffs/x/123?123=12&abcd=abc",
 			"hi123*33--}{:portstuffs", "/x/123", "123=12&abcd=abc");
 	}
-	
+
 	template<> template<>
 	void URITestObject::test<12>()
 	{
-		// test funky host_port values that are actually prefixes
-		
+		set_test_name("test funky host_port values that are actually prefixes");
+
 		checkParts(LLURI::buildHTTP("http://example.com:8080", LLSD()),
 			"http", "//example.com:8080",
 			"example.com:8080", "");
-			
+
 		checkParts(LLURI::buildHTTP("http://example.com:8080/", LLSD()),
 			"http", "//example.com:8080/",
 			"example.com:8080", "/");
 			"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
 			"0123456789"
 			"-._~";
-		// test escape
+		set_test_name("test escape");
 		ensure_equals("escaping", LLURI::escape("abcdefg", "abcdef"), "abcdef%67");
 		ensure_equals("escaping", LLURI::escape("|/&\\+-_!@", ""), "%7C%2F%26%5C%2B%2D%5F%21%40");
 		ensure_equals("escaping as query variable", 
 		cedilla.push_back( (char)0xA7 );
 		ensure_equals("escape UTF8", LLURI::escape( cedilla, unreserved), "%C3%A7");
 	}
-	
+
 
 	template<> template<>
 	void URITestObject::test<14>()
 	{
-		// make sure escape and unescape of empty strings return empty
-		// strings.
+		set_test_name("make sure escape and unescape of empty strings return empty strings.");
 		std::string uri_esc(LLURI::escape(""));
 		ensure("escape string empty", uri_esc.empty());
 		std::string uri_raw(LLURI::unescape(""));
 	template<> template<>
 	void URITestObject::test<15>()
 	{
-		// do some round-trip tests
+		set_test_name("do some round-trip tests");
 		escapeRoundTrip("http://secondlife.com");
 		escapeRoundTrip("http://secondlife.com/url with spaces");
 		escapeRoundTrip("http://bad[domain]name.com/");
 	template<> template<>
 	void URITestObject::test<16>()
 	{
-		// Test the default escaping
+		set_test_name("Test the default escaping");
 		// yes -- this mangles the url. This is expected behavior
 		std::string simple("http://secondlife.com");
 		ensure_equals(
 	template<> template<>
 	void URITestObject::test<17>()
 	{
-		// do some round-trip tests with very long strings.
+		set_test_name("do some round-trip tests with very long strings.");
 		escapeRoundTrip("Welcome to Second Life.We hope you'll have a richly rewarding experience, filled with creativity, self expression and fun.The goals of the Community Standards are simple: treat each other with respect and without harassment, adhere to local standards as indicated by simulator ratings, and refrain from any hate activity which slurs a real-world individual or real-world community. Behavioral Guidelines - The Big Six");
 		escapeRoundTrip(
 			"'asset_data':b(12100){'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444921\n\ttotal_crc\t323\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.368634403\t0.00781063363\t-0.569040775\n\toldpos\t150.117996\t25.8658009\t8.19664001\n\trotation\t-0.06293071806430816650390625\t-0.6995697021484375\t-0.7002241611480712890625\t0.1277817934751510620117188\n\tchildpos\t-0.00499999989\t-0.0359999985\t0.307999998\n\tchildrot\t-0.515492737293243408203125\t-0.46601200103759765625\t0.529055416584014892578125\t0.4870323240756988525390625\n\tscale"
 			"D STRING RW SV 20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\torig_asset_id\t8747acbc-d391-1e59-69f1-41d06830e6c0\n\torig_item_id\t20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tfrom_task_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tlinked\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n");
 	}
 
-	 
+
 	template<> template<>
 	void URITestObject::test<18>()
 	{
 		ensure_equals("pathmap",	u.pathArray()[1].asString(),	"login");
 		ensure_equals("query",		u.query(),		"first_name=Testert4&last_name=Tester&web_login_key=test");
 		ensure_equals("query map element", u.queryMap()["last_name"].asString(), "Tester");
-		
+
 		u = LLURI("secondlife://Da Boom/128/128/128");
 		// if secondlife is the scheme, LLURI should parse /128/128/128 as path, with Da Boom as authority
 		ensure_equals("scheme",		u.scheme(),		"secondlife");
 	template<> template<>
 	void URITestObject::test<19>()
 	{
-		// Parse about: schemes
+		set_test_name("Parse about: schemes");
 		LLURI u("about:blank?redirect-http-hack=secondlife%3A%2F%2F%2Fapp%2Flogin%3Ffirst_name%3DCallum%26last_name%3DLinden%26location%3Dspecify%26grid%3Dvaak%26region%3D%2FMorris%2F128%2F128%26web_login_key%3Defaa4795-c2aa-4c58-8966-763c27931e78");
 		ensure_equals("scheme",		u.scheme(),		"about");
 		ensure_equals("authority",	u.authority(),	"");

File indra/llcommon/tests/reflection_test.cpp

 			const LLReflective* reflective = property->get(aggregated_data); // Wrong reflective type, should throw exception.
 
 			// useless op to get rid of compiler warning.
-			reflective = NULL;
+			reflective = reflective;
 		}
 		catch(...)
 		{

File indra/llcorehttp/CMakeLists.txt

+# -*- cmake -*-
+
+project(llcorehttp)
+
+include(00-Common)
+include(GoogleMock)
+include(CURL)
+include(CARes)
+include(OpenSSL)
+include(ZLIB)
+include(LLCoreHttp)
+include(LLAddBuildTest)
+include(LLMessage)
+include(LLCommon)
+include(Tut)
+
+include_directories (${CMAKE_CURRENT_SOURCE_DIR})
+
+include_directories(
+    ${LLMESSAGE_INCLUDE_DIRS}
+    ${LLCOMMON_INCLUDE_DIRS}
+    ${LLCOREHTTP_INCLUDE_DIRS}
+    )
+
+set(llcorehttp_SOURCE_FILES
+    bufferarray.cpp
+    bufferstream.cpp
+    httpcommon.cpp
+    httpheaders.cpp
+    httpoptions.cpp
+    httprequest.cpp
+    httpresponse.cpp
+    _httplibcurl.cpp
+    _httpopcancel.cpp
+    _httpoperation.cpp
+    _httpoprequest.cpp
+    _httpopsetget.cpp
+    _httpopsetpriority.cpp
+    _httppolicy.cpp
+    _httppolicyclass.cpp
+    _httppolicyglobal.cpp
+    _httpreplyqueue.cpp
+    _httprequestqueue.cpp
+    _httpservice.cpp
+    _refcounted.cpp
+    )
+
+set(llcorehttp_HEADER_FILES
+    CMakeLists.txt
+
+    bufferarray.h
+    bufferstream.h
+    httpcommon.h
+    httphandler.h
+    httpheaders.h
+    httpoptions.h
+    httprequest.h
+    httpresponse.h
+    _httpinternal.h
+    _httplibcurl.h
+    _httpopcancel.h
+    _httpoperation.h
+    _httpoprequest.h
+    _httpopsetget.h
+    _httpopsetpriority.h
+    _httppolicy.h
+    _httppolicyclass.h
+    _httppolicyglobal.h
+    _httpreadyqueue.h
+    _httpreplyqueue.h
+    _httprequestqueue.h
+    _httpservice.h
+    _mutex.h
+    _refcounted.h
+    _thread.h
+    )
+
+set_source_files_properties(${llcorehttp_HEADER_FILES}
+                            PROPERTIES HEADER_FILE_ONLY TRUE)
+if (DARWIN OR LINUX)
+  # Boost headers define unused members in condition_variable so...
+  set_source_files_properties(${llcorehttp_SOURCE_FILES}
+                              PROPERTIES COMPILE_FLAGS -Wno-unused-variable)
+endif (DARWIN OR LINUX)
+
+list(APPEND llcorehttp_SOURCE_FILES ${llcorehttp_HEADER_FILES})
+
+add_library (llcorehttp ${llcorehttp_SOURCE_FILES})
+target_link_libraries(
+  llcorehttp
+  ${CURL_LIBRARIES}
+  ${CARES_LIBRARIES}
+  ${OPENSSL_LIBRARIES}
+  ${CRYPTO_LIBRARIES}
+  ${BOOST_THREAD_LIBRARY}
+  )
+
+# tests
+if (LL_TESTS)
+  SET(llcorehttp_TEST_SOURCE_FILES
+      tests/test_allocator.cpp
+      )
+
+  set(llcorehttp_TEST_HEADER_FILS
+      tests/test_httpstatus.hpp
+      tests/test_refcounted.hpp
+      tests/test_httpoperation.hpp
+      tests/test_httprequest.hpp
+      tests/test_httprequestqueue.hpp
+      tests/test_httpheaders.hpp
+      tests/test_bufferarray.hpp
+      tests/test_bufferstream.hpp
+      )
+
+  set_source_files_properties(${llcorehttp_TEST_HEADER_FILES}
+                              PROPERTIES HEADER_FILE_ONLY TRUE)
+
+  list(APPEND llcorehttp_TEST_SOURCE_FILES ${llcorehttp_TEST_HEADER_FILES})
+
+  # LL_ADD_PROJECT_UNIT_TESTS(llcorehttp "${llcorehttp_TEST_SOURCE_FILES}")
+
+  #    set(TEST_DEBUG on)
+  set(test_libs
+      ${LLCOREHTTP_LIBRARIES}
+      ${WINDOWS_LIBRARIES}
+      ${LLMESSAGE_LIBRARIES}
+      ${LLCOMMON_LIBRARIES}
+      ${GOOGLEMOCK_LIBRARIES}
+      ${CURL_LIBRARIES}
+      ${CARES_LIBRARIES}
+      ${OPENSSL_LIBRARIES}
+      ${CRYPTO_LIBRARIES}
+      ${BOOST_THREAD_LIBRARY}
+      )
+
+  LL_ADD_INTEGRATION_TEST(llcorehttp
+                          "${llcorehttp_TEST_SOURCE_FILES}"
+                          "${test_libs}"
+                          ${PYTHON_EXECUTABLE}
+                          "${CMAKE_CURRENT_SOURCE_DIR}/tests/test_llcorehttp_peer.py"
+                          )
+
+  #
+  # Example Programs
+  #
+  SET(llcorehttp_EXAMPLE_SOURCE_FILES
+      examples/http_texture_load.cpp
+      )
+
+  set(example_libs
+      ${LLCOREHTTP_LIBRARIES}
+      ${WINDOWS_LIBRARIES}
+      ${LLMESSAGE_LIBRARIES}
+      ${LLCOMMON_LIBRARIES}
+      ${GOOGLEMOCK_LIBRARIES}
+      ${CURL_LIBRARIES}
+      ${CARES_LIBRARIES}
+      ${OPENSSL_LIBRARIES}
+      ${CRYPTO_LIBRARIES}
+      ${BOOST_THREAD_LIBRARY}
+      )
+
+  add_executable(http_texture_load
+                 ${llcorehttp_EXAMPLE_SOURCE_FILES}
+                 )
+  set_target_properties(http_texture_load
+                        PROPERTIES
+                        RUNTIME_OUTPUT_DIRECTORY "${EXE_STAGING_DIR}"
+                        )
+
+  if (WINDOWS)
+    # The following come from LLAddBuildTest.cmake's INTEGRATION_TEST_xxxx target.
+    set_target_properties(http_texture_load
+                          PROPERTIES
+                          LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS /INCLUDE:__tcmalloc"
+                          LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\" /INCREMENTAL:NO"
+                          LINK_FLAGS_RELEASE ""
+                          )
+  endif (WINDOWS)
+
+  target_link_libraries(http_texture_load ${example_libs})
+
+endif (LL_TESTS)
+

File indra/llcorehttp/_httpinternal.h

+/**
+ * @file _httpinternal.h
+ * @brief Implementation constants and magic numbers
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef	_LLCORE_HTTP_INTERNAL_H_
+#define	_LLCORE_HTTP_INTERNAL_H_
+
+
+// If you find this included in a public interface header,
+// something wrong is probably happening.
+
+
+// --------------------------------------------------------------------
+// General library to-do list
+//
+// - Implement policy classes.  Structure is mostly there just didn't
+//   need it for the first consumer.
+// - Consider Removing 'priority' from the request interface.  Its use
+//   in an always active class can lead to starvation of low-priority
+//   requests.  Requires coodination of priority values across all
+//   components that share a class.  Changing priority across threads
+//   is slightly expensive (relative to gain) and hasn't been completely
+//   implemented.  And the major user of priority, texture fetches,
+//   may not really need it.
+// - Set/get for global policy and policy classes is clumsy.  Rework
+//   it heading in a direction that allows for more dynamic behavior.
+// - Move HttpOpRequest::prepareRequest() to HttpLibcurl for the
+//   pedantic.
+// - Update downloader and other long-duration services are going to
+//   need a progress notification.  Initial idea is to introduce a
+//   'repeating request' which can piggyback on another request and
+//   persist until canceled or carrier completes.  Current queue
+//   structures allow an HttpOperation object to be enqueued
+//   repeatedly, so...
+// - Investigate making c-ares' re-implementation of a resolver library
+//   more resilient or more intelligent on Mac.  Part of the DNS failure
+//   lies in here.  The mechanism also looks a little less dynamic
+//   than needed in an environments where networking is changing.
+// - Global optimizations:  'borrowing' connections from other classes,
+//   HTTP pipelining.
+// - Dynamic/control system stuff:  detect problems and self-adjust.
+//   This won't help in the face of the router problems we've looked
+//   at, however.  Detect starvation due to UDP activity and provide
+//   feedback to it.
+//
+// Integration to-do list
+// - LLTextureFetch still needs a major refactor.  The use of
+//   LLQueuedThread makes it hard to inspect workers and do the
+//   resource waiting we're now doing.  Rebuild along simpler lines
+//   some of which are suggested in new commentary at the top of
+//   the main source file.
+// - Expand areas of usage eventually leading to the removal of LLCurl.
+//   Rough order of expansion:
+//   .  Mesh fetch
+//   .  Avatar names
+//   .  Group membership lists
+//   .  Caps access in general
+//   .  'The rest'
+// - Adapt texture cache, image decode and other image consumers to
+//   the BufferArray model to reduce data copying.  Alternatively,
+//   adapt this library to something else.
+//
+// --------------------------------------------------------------------
+
+
+// If '1', internal ready queues will not order ready
+// requests by priority, instead it's first-come-first-served.
+// Reprioritization requests have the side-effect of then
+// putting the modified request at the back of the ready queue.
+
+#define	LLCORE_HTTP_READY_QUEUE_IGNORES_PRIORITY		1
+
+
+namespace LLCore
+{
+
+// Maxium number of policy classes that can be defined.
+// *TODO:  Currently limited to the default class, extend.
+const int HTTP_POLICY_CLASS_LIMIT = 1;
+
+// Debug/informational tracing.  Used both
+// as a global option and in per-request traces.
+const int HTTP_TRACE_OFF = 0;
+const int HTTP_TRACE_LOW = 1;
+const int HTTP_TRACE_CURL_HEADERS = 2;
+const int HTTP_TRACE_CURL_BODIES = 3;
+
+const int HTTP_TRACE_MIN = HTTP_TRACE_OFF;
+const int HTTP_TRACE_MAX = HTTP_TRACE_CURL_BODIES;
+
+// Request retry limits
+//
+// At a minimum, retries need to extend past any throttling
+// window we're expecting from central services.  In the case
+// of Linden services running through the caps routers, there's
+// a five-second or so window for throttling with some spillover.
+// We want to span a few windows to allow transport to slow
+// after onset of the throttles and then recover without a final
+// failure.  Other systems may need other constants.
+const int HTTP_RETRY_COUNT_DEFAULT = 8;
+const int HTTP_RETRY_COUNT_MIN = 0;
+const int HTTP_RETRY_COUNT_MAX = 100;
+
+const int HTTP_REDIRECTS_DEFAULT = 10;
+
+// Timeout value used for both connect and protocol exchange.
+// Retries and time-on-queue are not included and aren't
+// accounted for.
+const long HTTP_REQUEST_TIMEOUT_DEFAULT = 30L;
+const long HTTP_REQUEST_TIMEOUT_MIN = 0L;
+const long HTTP_REQUEST_TIMEOUT_MAX = 3600L;
+
+// Limits on connection counts
+const int HTTP_CONNECTION_LIMIT_DEFAULT = 8;
+const int HTTP_CONNECTION_LIMIT_MIN = 1;
+const int HTTP_CONNECTION_LIMIT_MAX = 256;
+
+// Tuning parameters
+
+// Time worker thread sleeps after a pass through the
+// request, ready and active queues.
+const int HTTP_SERVICE_LOOP_SLEEP_NORMAL_MS = 2;
+
+// Block allocation size (a tuning parameter) is found
+// in bufferarray.h.
+
+// Compatibility controls
+const bool HTTP_ENABLE_LINKSYS_WRT54G_V5_DNS_FIX = true;
+
+}  // end namespace LLCore
+
+#endif	// _LLCORE_HTTP_INTERNAL_H_

File indra/llcorehttp/_httplibcurl.cpp

+/**
+ * @file _httplibcurl.cpp
+ * @brief Internal definitions of the Http libcurl thread
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "_httplibcurl.h"
+
+#include "httpheaders.h"
+#include "bufferarray.h"
+#include "_httpoprequest.h"
+#include "_httppolicy.h"
+
+#include "llhttpstatuscodes.h"
+
+
+namespace LLCore
+{
+
+
+HttpLibcurl::HttpLibcurl(HttpService * service)
+	: mService(service),
+	  mPolicyCount(0),
+	  mMultiHandles(NULL)
+{}
+
+
+HttpLibcurl::~HttpLibcurl()
+{
+	shutdown();
+	
+	mService = NULL;
+}
+
+
+void HttpLibcurl::shutdown()
+{
+	while (! mActiveOps.empty())
+	{
+		HttpOpRequest * op(* mActiveOps.begin());
+		mActiveOps.erase(mActiveOps.begin());
+
+		cancelRequest(op);
+		op->release();
+	}
+
+	if (mMultiHandles)
+	{
+		for (int policy_class(0); policy_class < mPolicyCount; ++policy_class)
+		{
+			if (mMultiHandles[policy_class])
+			{
+				curl_multi_cleanup(mMultiHandles[policy_class]);
+				mMultiHandles[policy_class] = 0;
+			}
+		}
+
+		delete [] mMultiHandles;
+		mMultiHandles = NULL;
+	}
+
+	mPolicyCount = 0;
+}
+
+
+void HttpLibcurl::start(int policy_count)
+{
+	llassert_always(policy_count <= HTTP_POLICY_CLASS_LIMIT);
+	llassert_always(! mMultiHandles);					// One-time call only
+	
+	mPolicyCount = policy_count;
+	mMultiHandles = new CURLM * [mPolicyCount];
+	for (int policy_class(0); policy_class < mPolicyCount; ++policy_class)
+	{
+		mMultiHandles[policy_class] = curl_multi_init();
+	}
+}
+
+
+// Give libcurl some cycles, invoke it's callbacks, process
+// completed requests finalizing or issuing retries as needed.
+//
+// If active list goes empty *and* we didn't queue any
+// requests for retry, we return a request for a hard
+// sleep otherwise ask for a normal polling interval.
+HttpService::ELoopSpeed HttpLibcurl::processTransport()
+{
+	HttpService::ELoopSpeed	ret(HttpService::REQUEST_SLEEP);
+
+	// Give libcurl some cycles to do I/O & callbacks
+	for (int policy_class(0); policy_class < mPolicyCount; ++policy_class)
+	{
+		if (! mMultiHandles[policy_class])
+			continue;
+		
+		int running(0);
+		CURLMcode status(CURLM_CALL_MULTI_PERFORM);
+		do
+		{
+			running = 0;
+			status = curl_multi_perform(mMultiHandles[policy_class], &running);
+		}
+		while (0 != running && CURLM_CALL_MULTI_PERFORM == status);
+
+		// Run completion on anything done
+		CURLMsg * msg(NULL);
+		int msgs_in_queue(0);
+		while ((msg = curl_multi_info_read(mMultiHandles[policy_class], &msgs_in_queue)))
+		{
+			if (CURLMSG_DONE == msg->msg)
+			{
+				CURL * handle(msg->easy_handle);
+				CURLcode result(msg->data.result);
+
+				if (completeRequest(mMultiHandles[policy_class], handle, result))
+				{
+					// Request is still active, don't get too sleepy
+					ret = HttpService::NORMAL;
+				}
+				handle = NULL;			// No longer valid on return
+			}
+			else if (CURLMSG_NONE == msg->msg)
+			{
+				// Ignore this... it shouldn't mean anything.
+				;
+			}
+			else
+			{
+				LL_WARNS_ONCE("CoreHttp") << "Unexpected message from libcurl.  Msg code:  "
+										  << msg->msg
+										  << LL_ENDL;
+			}
+			msgs_in_queue = 0;
+		}
+	}
+
+	if (! mActiveOps.empty())
+	{
+		ret = HttpService::NORMAL;
+	}
+	return ret;
+}
+
+
+// Caller has provided us with a ref count on op.
+void HttpLibcurl::addOp(HttpOpRequest * op)
+{
+	llassert_always(op->mReqPolicy < mPolicyCount);
+	llassert_always(mMultiHandles[op->mReqPolicy] != NULL);
+	
+	// Create standard handle
+	if (! op->prepareRequest(mService))
+	{
+		// Couldn't issue request, fail with notification
+		// *TODO:  Need failure path
+		return;
+	}
+
+	// Make the request live
+	curl_multi_add_handle(mMultiHandles[op->mReqPolicy], op->mCurlHandle);
+	op->mCurlActive = true;
+	
+	if (op->mTracing > HTTP_TRACE_OFF)
+	{
+		HttpPolicy & policy(mService->getPolicy());
+		
+		LL_INFOS("CoreHttp") << "TRACE, ToActiveQueue, Handle:  "
+							 << static_cast<HttpHandle>(op)
+							 << ", Actives:  " << mActiveOps.size()
+							 << ", Readies:  " << policy.getReadyCount(op->mReqPolicy)
+							 << LL_ENDL;
+	}
+	
+	// On success, make operation active
+	mActiveOps.insert(op);
+}
+
+
+// Implements the transport part of any cancel operation.
+// See if the handle is an active operation and if so,
+// use the more complicated transport-based cancelation
+// method to kill the request.
+bool HttpLibcurl::cancel(HttpHandle handle)
+{
+	HttpOpRequest * op(static_cast<HttpOpRequest *>(handle));
+	active_set_t::iterator it(mActiveOps.find(op));
+	if (mActiveOps.end() == it)
+	{
+		return false;
+	}
+
+	// Cancel request
+	cancelRequest(op);
+
+	// Drop references
+	mActiveOps.erase(it);
+	op->release();
+
+	return true;
+}
+
+
+// *NOTE:  cancelRequest logic parallels completeRequest logic.
+// Keep them synchronized as necessary.  Caller is expected to
+// remove the op from the active list and release the op *after*
+// calling this method.  It must be called first to deliver the
+// op to the reply queue with refcount intact.
+void HttpLibcurl::cancelRequest(HttpOpRequest * op)
+{
+	// Deactivate request
+	op->mCurlActive = false;
+
+	// Detach from multi and recycle handle
+	curl_multi_remove_handle(mMultiHandles[op->mReqPolicy], op->mCurlHandle);
+	curl_easy_cleanup(op->mCurlHandle);
+	op->mCurlHandle = NULL;