summaryrefslogtreecommitdiff
path: root/indra/llcorehttp
diff options
context:
space:
mode:
authorMonty Brandenberg <monty@lindenlab.com>2012-06-12 17:42:33 -0400
committerMonty Brandenberg <monty@lindenlab.com>2012-06-12 17:42:33 -0400
commit7adeb3923728ca84a309a6af141c148ce38066fc (patch)
tree1d2395b61eaa90b670fdd356bb8010b75b49f99a /indra/llcorehttp
parent24e16e1632974057013b86300bb60954ea6f5684 (diff)
HTTP Proxy, PUT & POST, unit tests and refactoring.
Implemented/modified PUT & POST to not used chunked encoding for the request. Made the unit test much happier and probably a better thing for the pipeline. Have a cheesy static & dynamic proxy capability using both local options and a way to wire into LLProxy in llmessages. Not a clean thing but it will get the proxy path working with both socks5 & http proxies. Refactoring to get rid of unneeded library handler and unified an HttpStatus return for all requests. Big batch of code removed as a result of that and more is possible as well as some syscall avoidance with a bit more work. Boosted the unit tests for simple PUT & POST test which revealed the test harness does *not* like chunked encoding so we'll avoid it for now (and don't really need it in any of our schemes).
Diffstat (limited to 'indra/llcorehttp')
-rw-r--r--indra/llcorehttp/CMakeLists.txt5
-rw-r--r--indra/llcorehttp/_httpopcancel.cpp11
-rw-r--r--indra/llcorehttp/_httpopcancel.h3
-rw-r--r--indra/llcorehttp/_httpoperation.cpp18
-rw-r--r--indra/llcorehttp/_httpoperation.h13
-rw-r--r--indra/llcorehttp/_httpoprequest.cpp63
-rw-r--r--indra/llcorehttp/_httpoprequest.h7
-rw-r--r--indra/llcorehttp/_httpopsetget.cpp105
-rw-r--r--indra/llcorehttp/_httpopsetget.h78
-rw-r--r--indra/llcorehttp/_httpopsetpriority.cpp14
-rw-r--r--indra/llcorehttp/_httpopsetpriority.h4
-rw-r--r--indra/llcorehttp/_httppolicy.cpp6
-rw-r--r--indra/llcorehttp/_httppolicy.h4
-rw-r--r--indra/llcorehttp/_httppolicyglobal.cpp38
-rw-r--r--indra/llcorehttp/_httppolicyglobal.h7
-rw-r--r--indra/llcorehttp/_httpservice.cpp11
-rw-r--r--indra/llcorehttp/_httpservice.h10
-rw-r--r--indra/llcorehttp/httprequest.cpp151
-rw-r--r--indra/llcorehttp/httprequest.h44
-rw-r--r--indra/llcorehttp/tests/llcorehttp_test.cpp6
-rw-r--r--indra/llcorehttp/tests/test_httpoperation.hpp5
-rw-r--r--indra/llcorehttp/tests/test_httprequest.hpp239
-rw-r--r--indra/llcorehttp/tests/test_llcorehttp_peer.py10
23 files changed, 689 insertions, 163 deletions
diff --git a/indra/llcorehttp/CMakeLists.txt b/indra/llcorehttp/CMakeLists.txt
index a0827286e3..4273b32fe3 100644
--- a/indra/llcorehttp/CMakeLists.txt
+++ b/indra/llcorehttp/CMakeLists.txt
@@ -10,12 +10,14 @@ 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}
)
@@ -31,6 +33,7 @@ set(llcorehttp_SOURCE_FILES
_httpopcancel.cpp
_httpoperation.cpp
_httpoprequest.cpp
+ _httpopsetget.cpp
_httpopsetpriority.cpp
_httppolicy.cpp
_httppolicyglobal.cpp
@@ -54,6 +57,7 @@ set(llcorehttp_HEADER_FILES
_httpopcancel.h
_httpoperation.h
_httpoprequest.h
+ _httpopsetget.h
_httpopsetpriority.h
_httppolicy.h
_httppolicyglobal.h
@@ -113,6 +117,7 @@ if (LL_TESTS)
set(test_libs
${LLCOREHTTP_LIBRARIES}
${WINDOWS_LIBRARIES}
+ ${LLMESSAGE_LIBRARIES}
${LLCOMMON_LIBRARIES}
${GOOGLEMOCK_LIBRARIES}
${CURL_LIBRARIES}
diff --git a/indra/llcorehttp/_httpopcancel.cpp b/indra/llcorehttp/_httpopcancel.cpp
index 69dbff4bb4..ad624d2e57 100644
--- a/indra/llcorehttp/_httpopcancel.cpp
+++ b/indra/llcorehttp/_httpopcancel.cpp
@@ -66,17 +66,6 @@ void HttpOpCancel::stageFromRequest(HttpService * service)
}
-void HttpOpCancel::visitNotifier(HttpRequest * request)
-{
- if (mLibraryHandler)
- {
- HttpResponse * response = new HttpResponse();
- mLibraryHandler->onCompleted(static_cast<HttpHandle>(this), response);
- response->release();
- }
-}
-
-
} // end namespace LLCore
diff --git a/indra/llcorehttp/_httpopcancel.h b/indra/llcorehttp/_httpopcancel.h
index fab6f1f362..6d1e0f8774 100644
--- a/indra/llcorehttp/_httpopcancel.h
+++ b/indra/llcorehttp/_httpopcancel.h
@@ -59,13 +59,10 @@ private:
public:
virtual void stageFromRequest(HttpService *);
-
- virtual void visitNotifier(HttpRequest * request);
public:
// Request data
HttpHandle mHandle;
-
}; // end class HttpOpCancel
diff --git a/indra/llcorehttp/_httpoperation.cpp b/indra/llcorehttp/_httpoperation.cpp
index d966efd12b..b5c58013d4 100644
--- a/indra/llcorehttp/_httpoperation.cpp
+++ b/indra/llcorehttp/_httpoperation.cpp
@@ -47,7 +47,6 @@ namespace LLCore
HttpOperation::HttpOperation()
: LLCoreInt::RefCounted(true),
mReplyQueue(NULL),
- mLibraryHandler(NULL),
mUserHandler(NULL),
mReqPolicy(HttpRequest::DEFAULT_POLICY_ID),
mReqPriority(0U)
@@ -57,13 +56,12 @@ HttpOperation::HttpOperation()
HttpOperation::~HttpOperation()
{
- setHandlers(NULL, NULL, NULL);
+ setReplyPath(NULL, NULL);
}
-void HttpOperation::setHandlers(HttpReplyQueue * reply_queue,
- HttpHandler * lib_handler,
- HttpHandler * user_handler)
+void HttpOperation::setReplyPath(HttpReplyQueue * reply_queue,
+ HttpHandler * user_handler)
{
if (reply_queue != mReplyQueue)
{
@@ -81,9 +79,6 @@ void HttpOperation::setHandlers(HttpReplyQueue * reply_queue,
}
// Not refcounted
- mLibraryHandler = lib_handler;
-
- // Not refcounted
mUserHandler = user_handler;
}
@@ -121,11 +116,12 @@ void HttpOperation::stageFromActive(HttpService *)
void HttpOperation::visitNotifier(HttpRequest *)
{
- if (mLibraryHandler)
+ if (mUserHandler)
{
HttpResponse * response = new HttpResponse();
- mLibraryHandler->onCompleted(static_cast<HttpHandle>(this), response);
+ response->setStatus(mStatus);
+ mUserHandler->onCompleted(static_cast<HttpHandle>(this), response);
response->release();
}
@@ -142,7 +138,7 @@ HttpStatus HttpOperation::cancel()
void HttpOperation::addAsReply()
{
- if (mReplyQueue && mLibraryHandler)
+ if (mReplyQueue)
{
addRef();
mReplyQueue->addOp(this);
diff --git a/indra/llcorehttp/_httpoperation.h b/indra/llcorehttp/_httpoperation.h
index 01e26029d2..c93aa2def9 100644
--- a/indra/llcorehttp/_httpoperation.h
+++ b/indra/llcorehttp/_httpoperation.h
@@ -80,9 +80,8 @@ private:
void operator=(const HttpOperation &); // Not defined
public:
- void setHandlers(HttpReplyQueue * reply_queue,
- HttpHandler * lib_handler,
- HttpHandler * user_handler);
+ void setReplyPath(HttpReplyQueue * reply_queue,
+ HttpHandler * handler);
HttpHandler * getUserHandler() const
{
@@ -102,13 +101,15 @@ protected:
protected:
HttpReplyQueue * mReplyQueue; // Have refcount
- HttpHandler * mLibraryHandler; // Have refcount
- HttpHandler * mUserHandler; // Have refcount
+ HttpHandler * mUserHandler;
public:
+ // Request Data
HttpRequest::policy_t mReqPolicy;
HttpRequest::priority_t mReqPriority;
-
+
+ // Reply Data
+ HttpStatus mStatus;
}; // end class HttpOperation
diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp
index ea0b99303e..e2550d057e 100644
--- a/indra/llcorehttp/_httpoprequest.cpp
+++ b/indra/llcorehttp/_httpoprequest.cpp
@@ -44,6 +44,7 @@
#include "_httplibcurl.h"
#include "llhttpstatuscodes.h"
+#include "llproxy.h"
namespace
{
@@ -207,7 +208,7 @@ void HttpOpRequest::visitNotifier(HttpRequest * request)
{
static const HttpStatus partial_content(HTTP_PARTIAL_CONTENT, HE_SUCCESS);
- if (mLibraryHandler)
+ if (mUserHandler)
{
HttpResponse * response = new HttpResponse();
response->setStatus(mStatus);
@@ -219,7 +220,7 @@ void HttpOpRequest::visitNotifier(HttpRequest * request)
response->setRange(mReplyOffset, mReplyLength);
}
- mLibraryHandler->onCompleted(static_cast<HttpHandle>(this), response);
+ mUserHandler->onCompleted(static_cast<HttpHandle>(this), response);
response->release();
}
@@ -304,6 +305,39 @@ HttpStatus HttpOpRequest::setupPost(HttpRequest::policy_t policy_id,
}
+HttpStatus HttpOpRequest::setupPut(HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ BufferArray * body,
+ HttpOptions * options,
+ HttpHeaders * headers)
+{
+ HttpStatus status;
+
+ mProcFlags = 0;
+ mReqPolicy = policy_id;
+ mReqPriority = priority;
+ mReqMethod = HOR_PUT;
+ mReqURL = url;
+ if (body)
+ {
+ body->addRef();
+ mReqBody = body;
+ }
+ if (headers && ! mReqHeaders)
+ {
+ headers->addRef();
+ mReqHeaders = headers;
+ }
+ if (options && ! mReqOptions)
+ {
+ mReqOptions = new HttpOptions(*options);
+ }
+
+ return status;
+}
+
+
HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
{
// Scrub transport and result data for retried op case
@@ -346,8 +380,6 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
curl_easy_setopt(mCurlHandle, CURLOPT_URL, mReqURL.c_str());
curl_easy_setopt(mCurlHandle, CURLOPT_PRIVATE, this);
curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, "");
- // *FIXME: Need to deal with proxy setup...
- // curl_easy_setopt(handle, CURLOPT_PROXY, "");
// *FIXME: Revisit this old DNS timeout setting - may no longer be valid
curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0);
@@ -361,18 +393,31 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYPEER, 1);
curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYHOST, 0);
- std::string opt_value;
+ const std::string * opt_value(NULL);
if (policy.get(HttpRequest::GP_CA_PATH, opt_value))
{
- curl_easy_setopt(mCurlHandle, CURLOPT_CAPATH, opt_value.c_str());
+ curl_easy_setopt(mCurlHandle, CURLOPT_CAPATH, opt_value->c_str());
}
if (policy.get(HttpRequest::GP_CA_FILE, opt_value))
{
- curl_easy_setopt(mCurlHandle, CURLOPT_CAINFO, opt_value.c_str());
+ curl_easy_setopt(mCurlHandle, CURLOPT_CAINFO, opt_value->c_str());
}
if (policy.get(HttpRequest::GP_HTTP_PROXY, opt_value))
{
- curl_easy_setopt(mCurlHandle, CURLOPT_PROXY, opt_value.c_str());
+ if (*opt_value == "LLProxy")
+ {
+ // Use the viewer-based thread-safe API which has a
+ // fast/safe check for proxy enable. Would like to
+ // encapsulate this someway...
+ LLProxy::getInstance()->applyProxySettings(mCurlHandle);
+ }
+ else
+ {
+ // *TODO: This is fine for now but get fuller socks/
+ // authentication thing going later....
+ curl_easy_setopt(mCurlHandle, CURLOPT_PROXY, opt_value->c_str());
+ curl_easy_setopt(mCurlHandle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
+ }
}
switch (mReqMethod)
@@ -394,7 +439,6 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
}
curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDS, static_cast<void *>(NULL));
curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDSIZE, data_size);
- mCurlHeaders = curl_slist_append(mCurlHeaders, "Transfer-Encoding: chunked");
mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:");
}
break;
@@ -409,7 +453,6 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
}
curl_easy_setopt(mCurlHandle, CURLOPT_INFILESIZE, data_size);
curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDS, (void *) NULL);
- mCurlHeaders = curl_slist_append(mCurlHeaders, "Transfer-Encoding: chunked");
mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:");
mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive");
mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300");
diff --git a/indra/llcorehttp/_httpoprequest.h b/indra/llcorehttp/_httpoprequest.h
index 6dcf30ca0c..80893beb40 100644
--- a/indra/llcorehttp/_httpoprequest.h
+++ b/indra/llcorehttp/_httpoprequest.h
@@ -91,6 +91,13 @@ public:
HttpOptions * options,
HttpHeaders * headers);
+ HttpStatus setupPut(HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ BufferArray * body,
+ HttpOptions * options,
+ HttpHeaders * headers);
+
HttpStatus prepareRequest(HttpService * service);
virtual HttpStatus cancel();
diff --git a/indra/llcorehttp/_httpopsetget.cpp b/indra/llcorehttp/_httpopsetget.cpp
new file mode 100644
index 0000000000..21e058b2be
--- /dev/null
+++ b/indra/llcorehttp/_httpopsetget.cpp
@@ -0,0 +1,105 @@
+/**
+ * @file _httpopsetget.cpp
+ * @brief Definitions for internal class HttpOpSetGet
+ *
+ * $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 "_httpopsetget.h"
+
+#include <cstdio>
+#include <algorithm>
+
+#include "httpcommon.h"
+#include "httphandler.h"
+#include "httpresponse.h"
+
+#include "_httprequestqueue.h"
+#include "_httpreplyqueue.h"
+#include "_httpservice.h"
+#include "_httppolicy.h"
+#include "_httplibcurl.h"
+
+
+namespace LLCore
+{
+
+
+// ==================================
+// HttpOpSetget
+// ==================================
+
+
+HttpOpSetGet::HttpOpSetGet()
+ : HttpOperation(),
+ mIsGlobal(false),
+ mDoSet(false),
+ mSetting(-1), // Nothing requested
+ mLongValue(0L)
+{}
+
+
+HttpOpSetGet::~HttpOpSetGet()
+{}
+
+
+void HttpOpSetGet::setupGet(HttpRequest::EGlobalPolicy setting)
+{
+ mIsGlobal = true;
+ mSetting = setting;
+}
+
+
+void HttpOpSetGet::setupSet(HttpRequest::EGlobalPolicy setting, const std::string & value)
+{
+ mIsGlobal = true;
+ mDoSet = true;
+ mSetting = setting;
+ mStrValue = value;
+}
+
+
+void HttpOpSetGet::stageFromRequest(HttpService * service)
+{
+ HttpPolicyGlobal & pol_opt(service->getPolicy().getGlobalOptions());
+ HttpRequest::EGlobalPolicy setting(static_cast<HttpRequest::EGlobalPolicy>(mSetting));
+
+ if (mDoSet)
+ {
+ mStatus = pol_opt.set(setting, mStrValue);
+ }
+ if (mStatus)
+ {
+ const std::string * value;
+ if ((mStatus = pol_opt.get(setting, value)))
+ {
+ mStrValue = *value;
+ }
+ }
+
+ addAsReply();
+}
+
+
+} // end namespace LLCore
+
+
diff --git a/indra/llcorehttp/_httpopsetget.h b/indra/llcorehttp/_httpopsetget.h
new file mode 100644
index 0000000000..e065eb4c30
--- /dev/null
+++ b/indra/llcorehttp/_httpopsetget.h
@@ -0,0 +1,78 @@
+/**
+ * @file _httpopsetget.h
+ * @brief Internal declarations for the HttpOpSetGet subclass
+ *
+ * $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_OPSETGET_H_
+#define _LLCORE_HTTP_OPSETGET_H_
+
+
+#include "linden_common.h" // Modifies curl/curl.h interfaces
+
+#include "httpcommon.h"
+
+#include <curl/curl.h>
+
+#include "_httpoperation.h"
+#include "_refcounted.h"
+
+
+namespace LLCore
+{
+
+
+/// HttpOpSetGet requests dynamic changes to policy and
+/// configuration settings.
+
+class HttpOpSetGet : public HttpOperation
+{
+public:
+ HttpOpSetGet();
+ virtual ~HttpOpSetGet();
+
+private:
+ HttpOpSetGet(const HttpOpSetGet &); // Not defined
+ void operator=(const HttpOpSetGet &); // Not defined
+
+public:
+ void setupGet(HttpRequest::EGlobalPolicy setting);
+ void setupSet(HttpRequest::EGlobalPolicy setting, const std::string & value);
+
+ virtual void stageFromRequest(HttpService *);
+
+public:
+ // Request data
+ bool mIsGlobal;
+ bool mDoSet;
+ int mSetting;
+ long mLongValue;
+ std::string mStrValue;
+
+}; // end class HttpOpSetGet
+
+
+} // end namespace LLCore
+
+#endif // _LLCORE_HTTP_OPSETGET_H_
+
diff --git a/indra/llcorehttp/_httpopsetpriority.cpp b/indra/llcorehttp/_httpopsetpriority.cpp
index b0ee577087..d48c7a0b7d 100644
--- a/indra/llcorehttp/_httpopsetpriority.cpp
+++ b/indra/llcorehttp/_httpopsetpriority.cpp
@@ -60,18 +60,4 @@ void HttpOpSetPriority::stageFromRequest(HttpService * service)
}
-void HttpOpSetPriority::visitNotifier(HttpRequest * request)
-{
- if (mLibraryHandler)
- {
- HttpResponse * response = new HttpResponse();
-
- response->setStatus(mStatus);
- mLibraryHandler->onCompleted(static_cast<HttpHandle>(this), response);
-
- response->release();
- }
-}
-
-
} // end namespace LLCore
diff --git a/indra/llcorehttp/_httpopsetpriority.h b/indra/llcorehttp/_httpopsetpriority.h
index b972f50fff..f1e94b6e43 100644
--- a/indra/llcorehttp/_httpopsetpriority.h
+++ b/indra/llcorehttp/_httpopsetpriority.h
@@ -56,10 +56,8 @@ private:
public:
virtual void stageFromRequest(HttpService *);
- virtual void visitNotifier(HttpRequest * request);
-
protected:
- HttpStatus mStatus;
+ // Request Data
HttpHandle mHandle;
HttpRequest::priority_t mPriority;
}; // end class HttpOpSetPriority
diff --git a/indra/llcorehttp/_httppolicy.cpp b/indra/llcorehttp/_httppolicy.cpp
index 72bb6f14e4..8ee3f88658 100644
--- a/indra/llcorehttp/_httppolicy.cpp
+++ b/indra/llcorehttp/_httppolicy.cpp
@@ -71,6 +71,12 @@ HttpPolicy::~HttpPolicy()
}
+void HttpPolicy::setPolicies(const HttpPolicyGlobal & global)
+{
+ mGlobalOptions = global;
+}
+
+
void HttpPolicy::addOp(HttpOpRequest * op)
{
const int policy_class(op->mReqPolicy);
diff --git a/indra/llcorehttp/_httppolicy.h b/indra/llcorehttp/_httppolicy.h
index 14f6a9a676..73c22bab78 100644
--- a/indra/llcorehttp/_httppolicy.h
+++ b/indra/llcorehttp/_httppolicy.h
@@ -95,7 +95,9 @@ public:
{
return mGlobalOptions;
}
-
+
+ void setPolicies(const HttpPolicyGlobal & global);
+
protected:
struct State
{
diff --git a/indra/llcorehttp/_httppolicyglobal.cpp b/indra/llcorehttp/_httppolicyglobal.cpp
index 877b85896f..d95d73cfba 100644
--- a/indra/llcorehttp/_httppolicyglobal.cpp
+++ b/indra/llcorehttp/_httppolicyglobal.cpp
@@ -32,7 +32,7 @@ namespace LLCore
HttpPolicyGlobal::HttpPolicyGlobal()
- : mValidMask(0UL),
+ : mSetMask(0UL),
mConnectionLimit(32L)
{}
@@ -41,6 +41,20 @@ HttpPolicyGlobal::~HttpPolicyGlobal()
{}
+HttpPolicyGlobal & HttpPolicyGlobal::operator=(const HttpPolicyGlobal & other)
+{
+ if (this != &other)
+ {
+ mSetMask = other.mSetMask;
+ mConnectionLimit = other.mConnectionLimit;
+ mCAPath = other.mCAPath;
+ mCAFile = other.mCAFile;
+ mHttpProxy = other.mHttpProxy;
+ }
+ return *this;
+}
+
+
HttpStatus HttpPolicyGlobal::set(HttpRequest::EGlobalPolicy opt, long value)
{
switch (opt)
@@ -53,7 +67,7 @@ HttpStatus HttpPolicyGlobal::set(HttpRequest::EGlobalPolicy opt, long value)
return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
}
- mValidMask |= 1UL << int(opt);
+ mSetMask |= 1UL << int(opt);
return HttpStatus();
}
@@ -78,7 +92,7 @@ HttpStatus HttpPolicyGlobal::set(HttpRequest::EGlobalPolicy opt, const std::stri
return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
}
- mValidMask |= 1UL << int(opt);
+ mSetMask |= 1UL << int(opt);
return HttpStatus();
}
@@ -90,7 +104,7 @@ HttpStatus HttpPolicyGlobal::get(HttpRequest::EGlobalPolicy opt, long & value)
switch (opt)
{
case HttpRequest::GP_CONNECTION_LIMIT:
- if (! (mValidMask & (1UL << int(opt))))
+ if (! (mSetMask & (1UL << int(opt))))
return not_set;
value = mConnectionLimit;
break;
@@ -103,28 +117,28 @@ HttpStatus HttpPolicyGlobal::get(HttpRequest::EGlobalPolicy opt, long & value)
}
-HttpStatus HttpPolicyGlobal::get(HttpRequest::EGlobalPolicy opt, std::string & value)
+HttpStatus HttpPolicyGlobal::get(HttpRequest::EGlobalPolicy opt, const std::string *& value)
{
static const HttpStatus not_set(HttpStatus::LLCORE, HE_OPT_NOT_SET);
-
+
switch (opt)
{
case HttpRequest::GP_CA_PATH:
- if (! (mValidMask & (1UL << int(opt))))
+ if (! (mSetMask & (1UL << int(opt))))
return not_set;
- value = mCAPath;
+ value = &mCAPath;
break;
case HttpRequest::GP_CA_FILE:
- if (! (mValidMask & (1UL << int(opt))))
+ if (! (mSetMask & (1UL << int(opt))))
return not_set;
- value = mCAFile;
+ value = &mCAFile;
break;
case HttpRequest::GP_HTTP_PROXY:
- if (! (mValidMask & (1UL << int(opt))))
+ if (! (mSetMask & (1UL << int(opt))))
return not_set;
- value = mHttpProxy;
+ value = &mHttpProxy;
break;
default:
diff --git a/indra/llcorehttp/_httppolicyglobal.h b/indra/llcorehttp/_httppolicyglobal.h
index 39ffbcb9bb..f4bb4d4b25 100644
--- a/indra/llcorehttp/_httppolicyglobal.h
+++ b/indra/llcorehttp/_httppolicyglobal.h
@@ -40,18 +40,19 @@ public:
HttpPolicyGlobal();
~HttpPolicyGlobal();
+ HttpPolicyGlobal & operator=(const HttpPolicyGlobal &);
+
private:
HttpPolicyGlobal(const HttpPolicyGlobal &); // Not defined
- void operator=(const HttpPolicyGlobal &); // Not defined
public:
HttpStatus set(HttpRequest::EGlobalPolicy opt, long value);
HttpStatus set(HttpRequest::EGlobalPolicy opt, const std::string & value);
HttpStatus get(HttpRequest::EGlobalPolicy opt, long & value);
- HttpStatus get(HttpRequest::EGlobalPolicy opt, std::string & value);
+ HttpStatus get(HttpRequest::EGlobalPolicy opt, const std::string *& value);
public:
- unsigned long mValidMask;
+ unsigned long mSetMask;
long mConnectionLimit;
std::string mCAPath;
std::string mCAFile;
diff --git a/indra/llcorehttp/_httpservice.cpp b/indra/llcorehttp/_httpservice.cpp
index b038bdb720..920a3f3b6d 100644
--- a/indra/llcorehttp/_httpservice.cpp
+++ b/indra/llcorehttp/_httpservice.cpp
@@ -79,11 +79,8 @@ HttpService::~HttpService()
mTransport = NULL;
}
- if (mPolicy)
- {
- delete mPolicy;
- mPolicy = NULL;
- }
+ delete mPolicy;
+ mPolicy = NULL;
if (mThread)
{
@@ -145,6 +142,10 @@ void HttpService::startThread()
{
mThread->release();
}
+
+ // Push current policy definitions
+ mPolicy->setPolicies(mPolicyGlobal);
+
mThread = new LLCoreInt::HttpThread(boost::bind(&HttpService::threadRun, this, _1));
mThread->addRef(); // Need an explicit reference, implicit one is used internally
sState = RUNNING;
diff --git a/indra/llcorehttp/_httpservice.h b/indra/llcorehttp/_httpservice.h
index 748354a8e4..3f953ec1a7 100644
--- a/indra/llcorehttp/_httpservice.h
+++ b/indra/llcorehttp/_httpservice.h
@@ -30,6 +30,7 @@
#include "httpcommon.h"
#include "httprequest.h"
+#include "_httppolicyglobal.h"
namespace LLCoreInt
@@ -157,6 +158,11 @@ public:
{
return *mTransport;
}
+
+ HttpPolicyGlobal & getGlobalOptions()
+ {
+ return mPolicyGlobal;
+ }
protected:
void threadRun(LLCoreInt::HttpThread * thread);
@@ -173,11 +179,11 @@ protected:
// === calling-thread-only data ===
LLCoreInt::HttpThread * mThread;
-
+ HttpPolicyGlobal mPolicyGlobal;
+
// === working-thread-only data ===
HttpPolicy * mPolicy; // Simple pointer, has ownership
HttpLibcurl * mTransport; // Simple pointer, has ownership
-
}; // end class HttpService
} // end namespace LLCore
diff --git a/indra/llcorehttp/httprequest.cpp b/indra/llcorehttp/httprequest.cpp
index 2f36168f8b..089eee76f3 100644
--- a/indra/llcorehttp/httprequest.cpp
+++ b/indra/llcorehttp/httprequest.cpp
@@ -34,6 +34,7 @@
#include "_httpoprequest.h"
#include "_httpopsetpriority.h"
#include "_httpopcancel.h"
+#include "_httpopsetget.h"
#include "lltimer.h"
@@ -49,39 +50,6 @@ namespace LLCore
{
// ====================================
-// InternalHandler Implementation
-// ====================================
-
-
-class HttpRequest::InternalHandler : public HttpHandler
-{
-public:
- InternalHandler(HttpRequest & request)
- : mRequest(request)
- {}
-
-protected:
- InternalHandler(const InternalHandler &); // Not defined
- void operator=(const InternalHandler &); // Not defined
-
-public:
- void onCompleted(HttpHandle handle, HttpResponse * response)
- {
- HttpOperation * op(static_cast<HttpOperation *>(handle));
- HttpHandler * user_handler(op->getUserHandler());
- if (user_handler)
- {
- user_handler->onCompleted(handle, response);
- }
- }
-
-protected:
- HttpRequest & mRequest;
-
-}; // end class HttpRequest::InternalHandler
-
-
-// ====================================
// HttpRequest Implementation
// ====================================
@@ -92,15 +60,12 @@ HttpRequest::policy_t HttpRequest::sNextPolicyID(1);
HttpRequest::HttpRequest()
: //HttpHandler(),
mReplyQueue(NULL),
- mRequestQueue(NULL),
- mSelfHandler(NULL)
+ mRequestQueue(NULL)
{
mRequestQueue = HttpRequestQueue::instanceOf();
mRequestQueue->addRef();
mReplyQueue = new HttpReplyQueue();
-
- mSelfHandler = new InternalHandler(*this);
}
@@ -117,9 +82,6 @@ HttpRequest::~HttpRequest()
mReplyQueue->release();
mReplyQueue = NULL;
}
-
- delete mSelfHandler;
- mSelfHandler = NULL;
}
@@ -132,7 +94,7 @@ HttpStatus HttpRequest::setPolicyGlobalOption(EGlobalPolicy opt, long value)
{
// *FIXME: Fail if thread is running.
- return HttpService::instanceOf()->getPolicy().getGlobalOptions().set(opt, value);
+ return HttpService::instanceOf()->getGlobalOptions().set(opt, value);
}
@@ -140,7 +102,7 @@ HttpStatus HttpRequest::setPolicyGlobalOption(EGlobalPolicy opt, const std::stri
{
// *FIXME: Fail if thread is running.
- return HttpService::instanceOf()->getPolicy().getGlobalOptions().set(opt, value);
+ return HttpService::instanceOf()->getGlobalOptions().set(opt, value);
}
@@ -192,7 +154,7 @@ HttpHandle HttpRequest::requestGetByteRange(policy_t policy_id,
mLastReqStatus = status;
return handle;
}
- op->setHandlers(mReplyQueue, mSelfHandler, user_handler);
+ op->setReplyPath(mReplyQueue, user_handler);
mRequestQueue->addOp(op); // transfers refcount
mLastReqStatus = status;
@@ -220,7 +182,7 @@ HttpHandle HttpRequest::requestPost(policy_t policy_id,
mLastReqStatus = status;
return handle;
}
- op->setHandlers(mReplyQueue, mSelfHandler, user_handler);
+ op->setReplyPath(mReplyQueue, user_handler);
mRequestQueue->addOp(op); // transfers refcount
mLastReqStatus = status;
@@ -230,19 +192,31 @@ HttpHandle HttpRequest::requestPost(policy_t policy_id,
}
-HttpHandle HttpRequest::requestCancel(HttpHandle handle, HttpHandler * user_handler)
+HttpHandle HttpRequest::requestPut(policy_t policy_id,
+ priority_t priority,
+ const std::string & url,
+ BufferArray * body,
+ HttpOptions * options,
+ HttpHeaders * headers,
+ HttpHandler * user_handler)
{
HttpStatus status;
- HttpHandle ret_handle(LLCORE_HTTP_HANDLE_INVALID);
-
- HttpOpCancel * op = new HttpOpCancel(handle);
- op->setHandlers(mReplyQueue, mSelfHandler, user_handler);
- mRequestQueue->addOp(op); // transfer refcount as well
+ HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
+ HttpOpRequest * op = new HttpOpRequest();
+ if (! (status = op->setupPut(policy_id, priority, url, body, options, headers)))
+ {
+ op->release();
+ mLastReqStatus = status;
+ return handle;
+ }
+ op->setReplyPath(mReplyQueue, user_handler);
+ mRequestQueue->addOp(op); // transfers refcount
+
mLastReqStatus = status;
- ret_handle = static_cast<HttpHandle>(op);
+ handle = static_cast<HttpHandle>(op);
- return ret_handle;
+ return handle;
}
@@ -252,7 +226,7 @@ HttpHandle HttpRequest::requestNoOp(HttpHandler * user_handler)
HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
HttpOpNull * op = new HttpOpNull();
- op->setHandlers(mReplyQueue, mSelfHandler, user_handler);
+ op->setReplyPath(mReplyQueue, user_handler);
mRequestQueue->addOp(op); // transfer refcount as well
mLastReqStatus = status;
@@ -262,23 +236,6 @@ HttpHandle HttpRequest::requestNoOp(HttpHandler * user_handler)
}
-HttpHandle HttpRequest::requestSetPriority(HttpHandle request, priority_t priority,
- HttpHandler * handler)
-{
- HttpStatus status;
- HttpHandle ret_handle(LLCORE_HTTP_HANDLE_INVALID);
-
- HttpOpSetPriority * op = new HttpOpSetPriority(request, priority);
- op->setHandlers(mReplyQueue, mSelfHandler, handler);
- mRequestQueue->addOp(op); // transfer refcount as well
-
- mLastReqStatus = status;
- ret_handle = static_cast<HttpHandle>(op);
-
- return ret_handle;
-}
-
-
HttpStatus HttpRequest::update(long millis)
{
const HttpTime limit(totalTime() + (1000 * HttpTime(millis)));
@@ -302,6 +259,38 @@ HttpStatus HttpRequest::update(long millis)
// Request Management Methods
// ====================================
+HttpHandle HttpRequest::requestCancel(HttpHandle handle, HttpHandler * user_handler)
+{
+ HttpStatus status;
+ HttpHandle ret_handle(LLCORE_HTTP_HANDLE_INVALID);
+
+ HttpOpCancel * op = new HttpOpCancel(handle);
+ op->setReplyPath(mReplyQueue, user_handler);
+ mRequestQueue->addOp(op); // transfer refcount as well
+
+ mLastReqStatus = status;
+ ret_handle = static_cast<HttpHandle>(op);
+
+ return ret_handle;
+}
+
+
+HttpHandle HttpRequest::requestSetPriority(HttpHandle request, priority_t priority,
+ HttpHandler * handler)
+{
+ HttpStatus status;
+ HttpHandle ret_handle(LLCORE_HTTP_HANDLE_INVALID);
+
+ HttpOpSetPriority * op = new HttpOpSetPriority(request, priority);
+ op->setReplyPath(mReplyQueue, handler);
+ mRequestQueue->addOp(op); // transfer refcount as well
+
+ mLastReqStatus = status;
+ ret_handle = static_cast<HttpHandle>(op);
+
+ return ret_handle;
+}
+
// ====================================
// Utility Methods
@@ -350,7 +339,27 @@ HttpHandle HttpRequest::requestStopThread(HttpHandler * user_handler)
HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
HttpOpStop * op = new HttpOpStop();
- op->setHandlers(mReplyQueue, mSelfHandler, user_handler);
+ op->setReplyPath(mReplyQueue, user_handler);
+ mRequestQueue->addOp(op); // transfer refcount as well
+
+ mLastReqStatus = status;
+ handle = static_cast<HttpHandle>(op);
+
+ return handle;
+}
+
+// ====================================
+// Dynamic Policy Methods
+// ====================================
+
+HttpHandle HttpRequest::requestSetHttpProxy(const std::string & proxy, HttpHandler * handler)
+{
+ HttpStatus status;
+ HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
+
+ HttpOpSetGet * op = new HttpOpSetGet();
+ op->setupSet(GP_HTTP_PROXY, proxy);
+ op->setReplyPath(mReplyQueue, handler);
mRequestQueue->addOp(op); // transfer refcount as well
mLastReqStatus = status;
diff --git a/indra/llcorehttp/httprequest.h b/indra/llcorehttp/httprequest.h
index 01dbfba6dd..a953aa28d0 100644
--- a/indra/llcorehttp/httprequest.h
+++ b/indra/llcorehttp/httprequest.h
@@ -124,8 +124,8 @@ public:
/// @param opt Enum of option to be set.
/// @param value Desired value of option.
/// @return Standard status code.
- HttpStatus setPolicyGlobalOption(EGlobalPolicy opt, long value);
- HttpStatus setPolicyGlobalOption(EGlobalPolicy opt, const std::string & value);
+ static HttpStatus setPolicyGlobalOption(EGlobalPolicy opt, long value);
+ static HttpStatus setPolicyGlobalOption(EGlobalPolicy opt, const std::string & value);
/// Create a new policy class into which requests can be made.
///
@@ -236,6 +236,32 @@ public:
HttpHandler * handler);
+ ///
+ /// @param policy_id Default or user-defined policy class under
+ /// which this request is to be serviced.
+ /// @param priority Standard priority scheme inherited from
+ /// Indra code base.
+ /// @param url
+ /// @param body Byte stream to be sent as the body. No
+ /// further encoding or escaping will be done
+ /// to the content.
+ /// @param options (optional)
+ /// @param headers (optional)
+ /// @param handler (optional)
+ /// @return The handle of the request if successfully
+ /// queued or LLCORE_HTTP_HANDLE_INVALID if the
+ /// request could not be queued. In the latter
+ /// case, @see getStatus() will return more info.
+ ///
+ HttpHandle requestPut(policy_t policy_id,
+ priority_t priority,
+ const std::string & url,
+ BufferArray * body,
+ HttpOptions * options,
+ HttpHeaders * headers,
+ HttpHandler * handler);
+
+
/// Queue a NoOp request.
/// The request is queued and serviced by the working thread which
/// immediately processes it and returns the request to the reply
@@ -325,13 +351,20 @@ public:
HttpHandle requestStopThread(HttpHandler * handler);
/// @}
+
+ /// @name DynamicPolicyMethods
+ ///
+ /// @{
+
+ /// Request that a running transport pick up a new proxy setting.
+ /// An empty string will indicate no proxy is to be used.
+ HttpHandle requestSetHttpProxy(const std::string & proxy, HttpHandler * handler);
+
+ /// @}
protected:
void generateNotification(HttpOperation * op);
- class InternalHandler;
- friend class InternalHandler;
-
private:
/// @name InstanceData
///
@@ -339,7 +372,6 @@ private:
HttpStatus mLastReqStatus;
HttpReplyQueue * mReplyQueue;
HttpRequestQueue * mRequestQueue;
- InternalHandler * mSelfHandler;
/// @}
diff --git a/indra/llcorehttp/tests/llcorehttp_test.cpp b/indra/llcorehttp/tests/llcorehttp_test.cpp
index f59361ab53..2b36d3a982 100644
--- a/indra/llcorehttp/tests/llcorehttp_test.cpp
+++ b/indra/llcorehttp/tests/llcorehttp_test.cpp
@@ -44,6 +44,8 @@
#include "test_bufferarray.hpp"
#include "test_httprequestqueue.hpp"
+#include "llproxy.h"
+
unsigned long ssl_thread_id_callback(void);
void ssl_locking_callback(int mode, int type, const char * file, int line);
@@ -91,11 +93,15 @@ void init_curl()
CRYPTO_set_locking_callback(ssl_locking_callback);
CRYPTO_set_id_callback(ssl_thread_id_callback);
}
+
+ LLProxy::getInstance();
}
void term_curl()
{
+ LLProxy::cleanupClass();
+
CRYPTO_set_locking_callback(NULL);
for (int i(0); i < ssl_mutex_count; ++i)
{
diff --git a/indra/llcorehttp/tests/test_httpoperation.hpp b/indra/llcorehttp/tests/test_httpoperation.hpp
index 6c3df1e9e3..17b1a96878 100644
--- a/indra/llcorehttp/tests/test_httpoperation.hpp
+++ b/indra/llcorehttp/tests/test_httpoperation.hpp
@@ -97,13 +97,12 @@ namespace tut
// Get some handlers
TestHandler * h1 = new TestHandler();
- TestHandler * h2 = new TestHandler();
// create a new ref counted object with an implicit reference
HttpOpNull * op = new HttpOpNull();
// Add the handlers
- op->setHandlers(NULL, h1, h2);
+ op->setReplyPath(NULL, h1);
// Check ref count
ensure(op->getRefCount() == 1);
@@ -117,8 +116,6 @@ namespace tut
// release the handlers
delete h1;
h1 = NULL;
- delete h2;
- h2 = NULL;
ensure(mMemTotal == GetMemTotal());
}
diff --git a/indra/llcorehttp/tests/test_httprequest.hpp b/indra/llcorehttp/tests/test_httprequest.hpp
index 81f8fe4a85..61698f34d8 100644
--- a/indra/llcorehttp/tests/test_httprequest.hpp
+++ b/indra/llcorehttp/tests/test_httprequest.hpp
@@ -27,6 +27,7 @@
#define TEST_LLCORE_HTTP_REQUEST_H_
#include "httprequest.h"
+#include "bufferarray.h"
#include "httphandler.h"
#include "httpresponse.h"
#include "_httpservice.h"
@@ -604,6 +605,244 @@ void HttpRequestTestObjectType::test<6>()
}
}
+template <> template <>
+void HttpRequestTestObjectType::test<7>()
+{
+ ScopedCurlInit ready;
+
+ std::string url_base(get_base_url());
+ std::cerr << "Base: " << url_base << std::endl;
+
+ set_test_name("HttpRequest PUT to real service");
+
+ // Handler can be stack-allocated *if* there are no dangling
+ // references to it after completion of this method.
+ // Create before memory record as the string copy will bump numbers.
+ TestHandler2 handler(this, "handler");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+ mHandlerCalls = 0;
+
+ HttpRequest * req = NULL;
+ BufferArray * body = new BufferArray;
+
+ try
+ {
+ // Get singletons created
+ HttpRequest::createService();
+
+ // Start threading early so that thread memory is invariant
+ // over the test.
+ HttpRequest::startThread();
+
+ // create a new ref counted object with an implicit reference
+ req = new HttpRequest();
+ ensure("Memory allocated on construction", mMemTotal < GetMemTotal());
+
+ // Issue a GET that *can* connect
+ static const char * body_text("Now is the time for all good men...");
+ body->append(body_text, strlen(body_text));
+ mStatus = HttpStatus(200);
+ HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID,
+ 0U,
+ url_base,
+ body,
+ NULL,
+ NULL,
+ &handler);
+ ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
+
+ // Run the notification pump.
+ int count(0);
+ int limit(10);
+ while (count++ < limit && mHandlerCalls < 1)
+ {
+ req->update(1000);
+ usleep(100000);
+ }
+ ensure("Request executed in reasonable time", count < limit);
+ ensure("One handler invocation for request", mHandlerCalls == 1);
+
+ // Okay, request a shutdown of the servicing thread
+ mStatus = HttpStatus();
+ handle = req->requestStopThread(&handler);
+ ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
+
+ // Run the notification pump again
+ count = 0;
+ limit = 10;
+ while (count++ < limit && mHandlerCalls < 2)
+ {
+ req->update(1000);
+ usleep(100000);
+ }
+ ensure("Second request executed in reasonable time", count < limit);
+ ensure("Second handler invocation", mHandlerCalls == 2);
+
+ // See that we actually shutdown the thread
+ count = 0;
+ limit = 10;
+ while (count++ < limit && ! HttpService::isStopped())
+ {
+ usleep(100000);
+ }
+ ensure("Thread actually stopped running", HttpService::isStopped());
+
+ // Lose the request body
+ body->release();
+ body = NULL;
+
+ // release the request object
+ delete req;
+ req = NULL;
+
+ // Shut down service
+ HttpRequest::destroyService();
+
+ ensure("Two handler calls on the way out", 2 == mHandlerCalls);
+
+#if defined(WIN32)
+ // Can only do this memory test on Windows. On other platforms,
+ // the LL logging system holds on to memory and produces what looks
+ // like memory leaks...
+
+ // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal());
+ ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal());
+#endif
+ }
+ catch (...)
+ {
+ if (body)
+ {
+ body->release();
+ }
+ stop_thread(req);
+ delete req;
+ HttpRequest::destroyService();
+ throw;
+ }
+}
+
+template <> template <>
+void HttpRequestTestObjectType::test<8>()
+{
+ ScopedCurlInit ready;
+
+ std::string url_base(get_base_url());
+ std::cerr << "Base: " << url_base << std::endl;
+
+ set_test_name("HttpRequest POST to real service");
+
+ // Handler can be stack-allocated *if* there are no dangling
+ // references to it after completion of this method.
+ // Create before memory record as the string copy will bump numbers.
+ TestHandler2 handler(this, "handler");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+ mHandlerCalls = 0;
+
+ HttpRequest * req = NULL;
+ BufferArray * body = new BufferArray;
+
+ try
+ {
+ // Get singletons created
+ HttpRequest::createService();
+
+ // Start threading early so that thread memory is invariant
+ // over the test.
+ HttpRequest::startThread();
+
+ // create a new ref counted object with an implicit reference
+ req = new HttpRequest();
+ ensure("Memory allocated on construction", mMemTotal < GetMemTotal());
+
+ // Issue a GET that *can* connect
+ static const char * body_text("Now is the time for all good men...");
+ body->append(body_text, strlen(body_text));
+ mStatus = HttpStatus(200);
+ HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID,
+ 0U,
+ url_base,
+ body,
+ NULL,
+ NULL,
+ &handler);
+ ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
+
+ // Run the notification pump.
+ int count(0);
+ int limit(10);
+ while (count++ < limit && mHandlerCalls < 1)
+ {
+ req->update(1000);
+ usleep(100000);
+ }
+ ensure("Request executed in reasonable time", count < limit);
+ ensure("One handler invocation for request", mHandlerCalls == 1);
+
+ // Okay, request a shutdown of the servicing thread
+ mStatus = HttpStatus();
+ handle = req->requestStopThread(&handler);
+ ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
+
+ // Run the notification pump again
+ count = 0;
+ limit = 10;
+ while (count++ < limit && mHandlerCalls < 2)
+ {
+ req->update(1000);
+ usleep(100000);
+ }
+ ensure("Second request executed in reasonable time", count < limit);
+ ensure("Second handler invocation", mHandlerCalls == 2);
+
+ // See that we actually shutdown the thread
+ count = 0;
+ limit = 10;
+ while (count++ < limit && ! HttpService::isStopped())
+ {
+ usleep(100000);
+ }
+ ensure("Thread actually stopped running", HttpService::isStopped());
+
+ // Lose the request body
+ body->release();
+ body = NULL;
+
+ // release the request object
+ delete req;
+ req = NULL;
+
+ // Shut down service
+ HttpRequest::destroyService();
+
+ ensure("Two handler calls on the way out", 2 == mHandlerCalls);
+
+#if defined(WIN32)
+ // Can only do this memory test on Windows. On other platforms,
+ // the LL logging system holds on to memory and produces what looks
+ // like memory leaks...
+
+ // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal());
+ ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal());
+#endif
+ }
+ catch (...)
+ {
+ if (body)
+ {
+ body->release();
+ }
+ stop_thread(req);
+ delete req;
+ HttpRequest::destroyService();
+ throw;
+ }
+}
+
} // end namespace tut
namespace
diff --git a/indra/llcorehttp/tests/test_llcorehttp_peer.py b/indra/llcorehttp/tests/test_llcorehttp_peer.py
index 3e200a5c19..8c3ad805b3 100644
--- a/indra/llcorehttp/tests/test_llcorehttp_peer.py
+++ b/indra/llcorehttp/tests/test_llcorehttp_peer.py
@@ -85,7 +85,15 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler):
def do_POST(self):
# Read the provided POST data.
- self.answer(self.read())
+ # self.answer(self.read())
+ self.answer(dict(reply="success", status=200,
+ reason=self.read()))
+
+ def do_PUT(self):
+ # Read the provided PUT data.
+ # self.answer(self.read())
+ self.answer(dict(reply="success", status=200,
+ reason=self.read()))
def answer(self, data):
debug("%s.answer(%s): self.path = %r", self.__class__.__name__, data, self.path)