summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xindra/llcommon/linden_common.h1
-rwxr-xr-xindra/llcommon/llerror.h1
-rwxr-xr-xindra/llcorehttp/_httpinternal.h5
-rwxr-xr-xindra/llcorehttp/_httpoprequest.cpp163
-rwxr-xr-xindra/llcorehttp/_httpoprequest.h34
-rwxr-xr-xindra/llcorehttp/_httppolicyglobal.cpp30
-rwxr-xr-xindra/llcorehttp/_httppolicyglobal.h3
-rwxr-xr-xindra/llcorehttp/_httpservice.cpp80
-rwxr-xr-xindra/llcorehttp/_httpservice.h9
-rwxr-xr-xindra/llcorehttp/_refcounted.h11
-rwxr-xr-xindra/llcorehttp/bufferarray.h4
-rwxr-xr-xindra/llcorehttp/httpcommon.cpp28
-rwxr-xr-xindra/llcorehttp/httpcommon.h150
-rwxr-xr-xindra/llcorehttp/httphandler.h4
-rwxr-xr-xindra/llcorehttp/httpheaders.cpp2
-rwxr-xr-xindra/llcorehttp/httpheaders.h11
-rwxr-xr-xindra/llcorehttp/httpoptions.cpp39
-rwxr-xr-xindra/llcorehttp/httpoptions.h82
-rwxr-xr-xindra/llcorehttp/httprequest.cpp103
-rwxr-xr-xindra/llcorehttp/httprequest.h81
-rwxr-xr-xindra/llcorehttp/httpresponse.cpp7
-rwxr-xr-xindra/llcorehttp/httpresponse.h40
-rwxr-xr-xindra/llcorehttp/tests/test_httpstatus.hpp126
-rwxr-xr-xindra/llmessage/CMakeLists.txt15
-rwxr-xr-xindra/llmessage/llavatarnamecache.cpp274
-rwxr-xr-xindra/llmessage/llavatarnamecache.h5
-rw-r--r--indra/llmessage/llcorehttputil.cpp540
-rw-r--r--indra/llmessage/llcorehttputil.h200
-rwxr-xr-xindra/llmessage/llcurl.cpp858
-rwxr-xr-xindra/llmessage/llcurl.h96
-rwxr-xr-xindra/llmessage/llhttpclient.cpp4
-rwxr-xr-xindra/llmessage/llhttpclientadapter.cpp90
-rwxr-xr-xindra/llmessage/llhttpclientadapter.h2
-rwxr-xr-xindra/llmessage/llhttpclientinterface.h16
-rw-r--r--indra/llmessage/llhttpsdhandler.cpp103
-rw-r--r--indra/llmessage/llhttpsdhandler.h67
-rwxr-xr-xindra/llmessage/llsdrpcclient.h8
-rwxr-xr-xindra/llmessage/tests/llhttpclientadapter_test.cpp3
-rwxr-xr-xindra/newview/CMakeLists.txt14
-rwxr-xr-xindra/newview/llaccountingcostmanager.cpp267
-rwxr-xr-xindra/newview/llaccountingcostmanager.h14
-rwxr-xr-xindra/newview/llagent.cpp199
-rwxr-xr-xindra/newview/llagent.h31
-rwxr-xr-xindra/newview/llagentlanguage.cpp8
-rwxr-xr-xindra/newview/llappcorehttp.cpp81
-rwxr-xr-xindra/newview/llappcorehttp.h28
-rwxr-xr-xindra/newview/llappearancemgr.cpp619
-rwxr-xr-xindra/newview/llappearancemgr.h22
-rw-r--r--indra/newview/llavatarrenderinfoaccountant.cpp131
-rw-r--r--indra/newview/llavatarrenderinfoaccountant.h10
-rwxr-xr-xindra/newview/lleventpoll.cpp475
-rwxr-xr-xindra/newview/lleventpoll.h18
-rwxr-xr-xindra/newview/llhttpretrypolicy.cpp2
-rwxr-xr-xindra/newview/llmaterialmgr.cpp141
-rw-r--r--indra/newview/llmaterialmgr.h49
-rwxr-xr-xindra/newview/llviewerregion.cpp569
-rwxr-xr-xindra/newview/llviewerregion.h3
-rwxr-xr-xindra/newview/llvoavatarself.cpp1
-rwxr-xr-xindra/newview/llwlhandlers.cpp215
-rwxr-xr-xindra/newview/llwlhandlers.h45
-rwxr-xr-xindra/newview/llxmlrpctransaction.cpp500
-rwxr-xr-xindra/newview/llxmlrpctransaction.h4
62 files changed, 4249 insertions, 2492 deletions
diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h
index 5cfcdab41c..e5a913a6a9 100755
--- a/indra/llcommon/linden_common.h
+++ b/indra/llcommon/linden_common.h
@@ -51,6 +51,7 @@
#include <cstdlib>
#include <ctime>
#include <iosfwd>
+#include <memory>
// Linden only libs in alpha-order other than stdtypes.h
// *NOTE: Please keep includes here to a minimum, see above.
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index 63040e1772..b1b5e9be7d 100755
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -354,6 +354,7 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
#define LL_WARNS(...) lllog(LLError::LEVEL_WARN, false, ##__VA_ARGS__)
#define LL_ERRS(...) lllog(LLError::LEVEL_ERROR, false, ##__VA_ARGS__)
// alternative to llassert_always that prints explanatory message
+#define LL_WARNS_IF(exp, ...) if (exp) LL_WARNS(##__VA_ARGS__) << "(" #exp ")"
#define LL_ERRS_IF(exp, ...) if (exp) LL_ERRS(##__VA_ARGS__) << "(" #exp ")"
// Only print the log message once (good for warnings or infos that would otherwise
diff --git a/indra/llcorehttp/_httpinternal.h b/indra/llcorehttp/_httpinternal.h
index a2a60ca056..79c89d6c92 100755
--- a/indra/llcorehttp/_httpinternal.h
+++ b/indra/llcorehttp/_httpinternal.h
@@ -104,8 +104,9 @@ namespace LLCore
{
// Maxium number of policy classes that can be defined.
-// *TODO: Currently limited to the default class + 1, extend.
-const int HTTP_POLICY_CLASS_LIMIT = 8;
+// *TODO: Currently limited to the default class + 1, extend.
+// (TSN: should this be more dynamically sized. Is there a reason to hard limit the number of policies?)
+const int HTTP_POLICY_CLASS_LIMIT = 32;
// Debug/informational tracing. Used both
// as a global option and in per-request traces.
diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp
index b9632a7921..b1b05dc285 100755
--- a/indra/llcorehttp/_httpoprequest.cpp
+++ b/indra/llcorehttp/_httpoprequest.cpp
@@ -139,7 +139,8 @@ HttpOpRequest::HttpOpRequest()
mPolicyRetries(0),
mPolicy503Retries(0),
mPolicyRetryAt(HttpTime(0)),
- mPolicyRetryLimit(HTTP_RETRY_COUNT_DEFAULT)
+ mPolicyRetryLimit(HTTP_RETRY_COUNT_DEFAULT),
+ mCallbackSSLVerify(NULL)
{
// *NOTE: As members are added, retry initialization/cleanup
// may need to be extended in @see prepareRequest().
@@ -259,7 +260,9 @@ void HttpOpRequest::visitNotifier(HttpRequest * request)
response->setStatus(mStatus);
response->setBody(mReplyBody);
response->setHeaders(mReplyHeaders);
- if (mReplyOffset || mReplyLength)
+ response->setRequestURL(mReqURL);
+
+ if (mReplyOffset || mReplyLength)
{
// Got an explicit offset/length in response
response->setRange(mReplyOffset, mReplyLength, mReplyFullLength);
@@ -267,6 +270,14 @@ void HttpOpRequest::visitNotifier(HttpRequest * request)
response->setContentType(mReplyConType);
response->setRetries(mPolicyRetries, mPolicy503Retries);
+ HttpResponse::TransferStats::ptr_t stats = HttpResponse::TransferStats::ptr_t(new HttpResponse::TransferStats);
+
+ curl_easy_getinfo(mCurlHandle, CURLINFO_SIZE_DOWNLOAD, &stats->mSizeDownload);
+ curl_easy_getinfo(mCurlHandle, CURLINFO_TOTAL_TIME, &stats->mTotalTime);
+ curl_easy_getinfo(mCurlHandle, CURLINFO_SPEED_DOWNLOAD, &stats->mSpeedDownload);
+
+ response->setTransferStats(stats);
+
mUserHandler->onCompleted(static_cast<HttpHandle>(this), response);
response->release();
@@ -346,6 +357,46 @@ HttpStatus HttpOpRequest::setupPut(HttpRequest::policy_t policy_id,
}
+HttpStatus HttpOpRequest::setupDelete(HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ HttpOptions * options,
+ HttpHeaders * headers)
+{
+ setupCommon(policy_id, priority, url, NULL, options, headers);
+ mReqMethod = HOR_DELETE;
+
+ return HttpStatus();
+}
+
+
+HttpStatus HttpOpRequest::setupPatch(HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ BufferArray * body,
+ HttpOptions * options,
+ HttpHeaders * headers)
+{
+ setupCommon(policy_id, priority, url, body, options, headers);
+ mReqMethod = HOR_PATCH;
+
+ return HttpStatus();
+}
+
+
+HttpStatus HttpOpRequest::setupCopy(HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ HttpOptions * options,
+ HttpHeaders * headers)
+{
+ setupCommon(policy_id, priority, url, NULL, options, headers);
+ mReqMethod = HOR_COPY;
+
+ return HttpStatus();
+}
+
+
void HttpOpRequest::setupCommon(HttpRequest::policy_t policy_id,
HttpRequest::priority_t priority,
const std::string & url,
@@ -452,18 +503,8 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
code = curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, "");
check_curl_easy_code(code, CURLOPT_ENCODING);
- // The Linksys WRT54G V5 router has an issue with frequent
- // DNS lookups from LAN machines. If they happen too often,
- // like for every HTTP request, the router gets annoyed after
- // about 700 or so requests and starts issuing TCP RSTs to
- // new connections. Reuse the DNS lookups for even a few
- // seconds and no RSTs.
- code = curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, 15);
- check_curl_easy_code(code, CURLOPT_DNS_CACHE_TIMEOUT);
code = curl_easy_setopt(mCurlHandle, CURLOPT_AUTOREFERER, 1);
check_curl_easy_code(code, CURLOPT_AUTOREFERER);
- code = curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, 1);
- check_curl_easy_code(code, CURLOPT_FOLLOWLOCATION);
code = curl_easy_setopt(mCurlHandle, CURLOPT_MAXREDIRS, HTTP_REDIRECTS_DEFAULT);
check_curl_easy_code(code, CURLOPT_MAXREDIRS);
code = curl_easy_setopt(mCurlHandle, CURLOPT_WRITEFUNCTION, writeCallback);
@@ -474,11 +515,48 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
check_curl_easy_code(code, CURLOPT_READFUNCTION);
code = curl_easy_setopt(mCurlHandle, CURLOPT_READDATA, this);
check_curl_easy_code(code, CURLOPT_READDATA);
- code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYPEER, 1);
+
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_COOKIEFILE, "");
+ check_curl_easy_code(code, CURLOPT_COOKIEFILE);
+
+ if (gpolicy.mSslCtxCallback)
+ {
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_CTX_FUNCTION, curlSslCtxCallback);
+ check_curl_easy_code(code, CURLOPT_SSL_CTX_FUNCTION);
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_CTX_DATA, this);
+ check_curl_easy_code(code, CURLOPT_SSL_CTX_DATA);
+ mCallbackSSLVerify = gpolicy.mSslCtxCallback;
+ }
+
+ long follow_redirect(1L);
+ long sslPeerV(0L);
+ long sslHostV(0L);
+ long dnsCacheTimeout(-1L);
+
+ if (mReqOptions)
+ {
+ follow_redirect = mReqOptions->getFollowRedirects() ? 1L : 0L;
+ sslPeerV = mReqOptions->getSSLVerifyPeer() ? 1L : 0L;
+ sslHostV = mReqOptions->getSSLVerifyHost() ? 2L : 0L;
+ dnsCacheTimeout = mReqOptions->getDNSCacheTimeout();
+ }
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, follow_redirect);
+ check_curl_easy_code(code, CURLOPT_FOLLOWLOCATION);
+
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYPEER, sslPeerV);
check_curl_easy_code(code, CURLOPT_SSL_VERIFYPEER);
- code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYHOST, 0);
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYHOST, sslHostV);
check_curl_easy_code(code, CURLOPT_SSL_VERIFYHOST);
+ // The Linksys WRT54G V5 router has an issue with frequent
+ // DNS lookups from LAN machines. If they happen too often,
+ // like for every HTTP request, the router gets annoyed after
+ // about 700 or so requests and starts issuing TCP RSTs to
+ // new connections. Reuse the DNS lookups for even a few
+ // seconds and no RSTs.
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, dnsCacheTimeout);
+ check_curl_easy_code(code, CURLOPT_DNS_CACHE_TIMEOUT);
+
if (gpolicy.mUseLLProxy)
{
// Use the viewer-based thread-safe API which has a
@@ -511,8 +589,6 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
case HOR_GET:
code = curl_easy_setopt(mCurlHandle, CURLOPT_HTTPGET, 1);
check_curl_easy_code(code, CURLOPT_HTTPGET);
- mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive");
- mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300");
break;
case HOR_POST:
@@ -531,12 +607,14 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
code = curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDSIZE, data_size);
check_curl_easy_code(code, CURLOPT_POSTFIELDSIZE);
mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:");
- mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive");
- mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300");
}
break;
- case HOR_PUT:
+ case HOR_PATCH:
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "PATCH");
+ check_curl_easy_code(code, CURLOPT_CUSTOMREQUEST);
+ // fall through. The rest is the same as PUT
+ case HOR_PUT:
{
code = curl_easy_setopt(mCurlHandle, CURLOPT_UPLOAD, 1);
check_curl_easy_code(code, CURLOPT_UPLOAD);
@@ -550,12 +628,19 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
code = curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDS, (void *) NULL);
check_curl_easy_code(code, CURLOPT_POSTFIELDS);
mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:");
- // *TODO: Should this be 'Keep-Alive' ?
- mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive");
- mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300");
}
break;
+ case HOR_DELETE:
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "DELETE");
+ check_curl_easy_code(code, CURLOPT_CUSTOMREQUEST);
+ break;
+
+ case HOR_COPY:
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "COPY");
+ check_curl_easy_code(code, CURLOPT_CUSTOMREQUEST);
+ break;
+
default:
LL_ERRS(LOG_CORE) << "Invalid HTTP method in request: "
<< int(mReqMethod) << ". Can't recover."
@@ -563,6 +648,11 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
break;
}
+
+ // *TODO: Should this be 'Keep-Alive' ?
+ mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive");
+ mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300");
+
// Tracing
if (mTracing >= HTTP_TRACE_CURL_HEADERS)
{
@@ -873,6 +963,35 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi
}
+CURLcode HttpOpRequest::curlSslCtxCallback(CURL *curl, void *sslctx, void *userdata)
+{
+ HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata));
+
+ if (op->mCallbackSSLVerify)
+ {
+ SSL_CTX * ctx = (SSL_CTX *)sslctx;
+ // disable any default verification for server certs
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
+ // set the verification callback.
+ SSL_CTX_set_cert_verify_callback(ctx, sslCertVerifyCallback, userdata);
+ // the calls are void
+ }
+
+ return CURLE_OK;
+}
+
+int HttpOpRequest::sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param)
+{
+ HttpOpRequest * op(static_cast<HttpOpRequest *>(param));
+
+ if (op->mCallbackSSLVerify)
+ {
+ op->mStatus = op->mCallbackSSLVerify(op->mReqURL, op->mUserHandler, ctx);
+ }
+
+ return (op->mStatus) ? 1 : 0;
+}
+
int HttpOpRequest::debugCallback(CURL * handle, curl_infotype info, char * buffer, size_t len, void * userdata)
{
HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata));
diff --git a/indra/llcorehttp/_httpoprequest.h b/indra/llcorehttp/_httpoprequest.h
index 2f628b5aba..ca40898a81 100755
--- a/indra/llcorehttp/_httpoprequest.h
+++ b/indra/llcorehttp/_httpoprequest.h
@@ -33,6 +33,9 @@
#include <string>
#include <curl/curl.h>
+#include <openssl/x509_vfy.h>
+#include <openssl/ssl.h>
+
#include "httpcommon.h"
#include "httprequest.h"
#include "_httpoperation.h"
@@ -77,7 +80,10 @@ public:
{
HOR_GET,
HOR_POST,
- HOR_PUT
+ HOR_PUT,
+ HOR_DELETE,
+ HOR_PATCH,
+ HOR_COPY
};
virtual void stageFromRequest(HttpService *);
@@ -123,7 +129,26 @@ public:
HttpOptions * options,
HttpHeaders * headers);
- // Internal method used to setup the libcurl options for a request.
+ HttpStatus setupDelete(HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ HttpOptions * options,
+ HttpHeaders * headers);
+
+ HttpStatus setupPatch(HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ BufferArray * body,
+ HttpOptions * options,
+ HttpHeaders * headers);
+
+ HttpStatus setupCopy(HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ HttpOptions * options,
+ HttpHeaders * headers);
+
+ // Internal method used to setup the libcurl options for a request.
// Does all the libcurl handle setup in one place.
//
// Threading: called by worker thread
@@ -151,6 +176,9 @@ protected:
static size_t writeCallback(void * data, size_t size, size_t nmemb, void * userdata);
static size_t readCallback(void * data, size_t size, size_t nmemb, void * userdata);
static size_t headerCallback(void * data, size_t size, size_t nmemb, void * userdata);
+ static CURLcode curlSslCtxCallback(CURL *curl, void *ssl_ctx, void *userptr);
+ static int sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param);
+
static int debugCallback(CURL *, curl_infotype info, char * buffer, size_t len, void * userdata);
protected:
@@ -159,6 +187,8 @@ protected:
static const unsigned int PF_SAVE_HEADERS = 0x00000002U;
static const unsigned int PF_USE_RETRY_AFTER = 0x00000004U;
+ HttpRequest::policyCallback_t mCallbackSSLVerify;
+
public:
// Request data
EMethod mReqMethod;
diff --git a/indra/llcorehttp/_httppolicyglobal.cpp b/indra/llcorehttp/_httppolicyglobal.cpp
index 1dc95f3dce..3d0df96ade 100755
--- a/indra/llcorehttp/_httppolicyglobal.cpp
+++ b/indra/llcorehttp/_httppolicyglobal.cpp
@@ -106,6 +106,20 @@ HttpStatus HttpPolicyGlobal::set(HttpRequest::EPolicyOption opt, const std::stri
return HttpStatus();
}
+HttpStatus HttpPolicyGlobal::set(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback_t value)
+{
+ switch (opt)
+ {
+ case HttpRequest::PO_SSL_VERIFY_CALLBACK:
+ mSslCtxCallback = value;
+ break;
+
+ default:
+ return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
+ }
+
+ return HttpStatus();
+}
HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, long * value) const
{
@@ -154,4 +168,20 @@ HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, std::string * v
return HttpStatus();
}
+
+HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback_t * value) const
+{
+ switch (opt)
+ {
+ case HttpRequest::PO_SSL_VERIFY_CALLBACK:
+ *value = mSslCtxCallback;
+ break;
+
+ default:
+ return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
+ }
+
+ return HttpStatus();
+}
+
} // end namespace LLCore
diff --git a/indra/llcorehttp/_httppolicyglobal.h b/indra/llcorehttp/_httppolicyglobal.h
index 67c4ba9481..e02da4386a 100755
--- a/indra/llcorehttp/_httppolicyglobal.h
+++ b/indra/llcorehttp/_httppolicyglobal.h
@@ -60,8 +60,10 @@ private:
public:
HttpStatus set(HttpRequest::EPolicyOption opt, long value);
HttpStatus set(HttpRequest::EPolicyOption opt, const std::string & value);
+ HttpStatus set(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback_t value);
HttpStatus get(HttpRequest::EPolicyOption opt, long * value) const;
HttpStatus get(HttpRequest::EPolicyOption opt, std::string * value) const;
+ HttpStatus get(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback_t * value) const;
public:
long mConnectionLimit;
@@ -70,6 +72,7 @@ public:
std::string mHttpProxy;
long mTrace;
long mUseLLProxy;
+ HttpRequest::policyCallback_t mSslCtxCallback;
}; // end class HttpPolicyGlobal
} // end namespace LLCore
diff --git a/indra/llcorehttp/_httpservice.cpp b/indra/llcorehttp/_httpservice.cpp
index c673e1be1d..252db78c89 100755
--- a/indra/llcorehttp/_httpservice.cpp
+++ b/indra/llcorehttp/_httpservice.cpp
@@ -53,15 +53,16 @@ namespace LLCore
const HttpService::OptionDescriptor HttpService::sOptionDesc[] =
{ // isLong isDynamic isGlobal isClass
- { true, true, true, true }, // PO_CONNECTION_LIMIT
- { true, true, false, true }, // PO_PER_HOST_CONNECTION_LIMIT
- { false, false, true, false }, // PO_CA_PATH
- { false, false, true, false }, // PO_CA_FILE
- { false, true, true, false }, // PO_HTTP_PROXY
- { true, true, true, false }, // PO_LLPROXY
- { true, true, true, false }, // PO_TRACE
- { true, true, false, true }, // PO_ENABLE_PIPELINING
- { true, true, false, true } // PO_THROTTLE_RATE
+ { true, true, true, true, false }, // PO_CONNECTION_LIMIT
+ { true, true, false, true, false }, // PO_PER_HOST_CONNECTION_LIMIT
+ { false, false, true, false, false }, // PO_CA_PATH
+ { false, false, true, false, false }, // PO_CA_FILE
+ { false, true, true, false, false }, // PO_HTTP_PROXY
+ { true, true, true, false, false }, // PO_LLPROXY
+ { true, true, true, false, false }, // PO_TRACE
+ { true, true, false, true, false }, // PO_ENABLE_PIPELINING
+ { true, true, false, true, false }, // PO_THROTTLE_RATE
+ { false, false, true, false, true } // PO_SSL_VERIFY_CALLBACK
};
HttpService * HttpService::sInstance(NULL);
volatile HttpService::EState HttpService::sState(NOT_INITIALIZED);
@@ -413,6 +414,34 @@ HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequ
return status;
}
+HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
+ HttpRequest::policyCallback_t * ret_value)
+{
+ HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
+
+ if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range
+ || opt >= HttpRequest::PO_LAST // ditto
+ || (sOptionDesc[opt].mIsLong) // datatype is string
+ || (pclass != HttpRequest::GLOBAL_POLICY_ID && pclass > mLastPolicy) // pclass in valid range
+ || (pclass == HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsGlobal) // global setting permitted
+ || (pclass != HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsClass)) // class setting permitted
+ // can always get, no dynamic check
+ {
+ return status;
+ }
+
+ // Only global has callback values
+ if (pclass == HttpRequest::GLOBAL_POLICY_ID)
+ {
+ HttpPolicyGlobal & opts(mPolicy->getGlobalOptions());
+
+ status = opts.get(opt, ret_value);
+ }
+
+ return status;
+}
+
+
HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
long value, long * ret_value)
@@ -489,6 +518,37 @@ HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequ
return status;
}
-
+
+HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
+ HttpRequest::policyCallback_t value, HttpRequest::policyCallback_t * ret_value)
+{
+ HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
+
+ if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range
+ || opt >= HttpRequest::PO_LAST // ditto
+ || (sOptionDesc[opt].mIsLong) // datatype is string
+ || (pclass != HttpRequest::GLOBAL_POLICY_ID && pclass > mLastPolicy) // pclass in valid range
+ || (pclass == HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsGlobal) // global setting permitted
+ || (pclass != HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsClass) // class setting permitted
+ || (RUNNING == sState && !sOptionDesc[opt].mIsDynamic)) // dynamic setting permitted
+ {
+ return status;
+ }
+
+ // Callbacks values are always global (at this time).
+ if (pclass == HttpRequest::GLOBAL_POLICY_ID)
+ {
+ HttpPolicyGlobal & opts(mPolicy->getGlobalOptions());
+
+ status = opts.set(opt, value);
+ if (status && ret_value)
+ {
+ status = opts.get(opt, ret_value);
+ }
+ }
+
+ return status;
+}
+
} // end namespace LLCore
diff --git a/indra/llcorehttp/_httpservice.h b/indra/llcorehttp/_httpservice.h
index cf23f3ab61..ac518a5de7 100755
--- a/indra/llcorehttp/_httpservice.h
+++ b/indra/llcorehttp/_httpservice.h
@@ -201,17 +201,24 @@ protected:
bool mIsDynamic;
bool mIsGlobal;
bool mIsClass;
+ bool mIsCallback;
};
HttpStatus getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
long * ret_value);
HttpStatus getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
std::string * ret_value);
+ HttpStatus getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
+ HttpRequest::policyCallback_t * ret_value);
+
HttpStatus setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
long value, long * ret_value);
HttpStatus setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
const std::string & value, std::string * ret_value);
-
+ HttpStatus setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
+ HttpRequest::policyCallback_t value,
+ HttpRequest::policyCallback_t * ret_value);
+
protected:
static const OptionDescriptor sOptionDesc[HttpRequest::PO_LAST];
static HttpService * sInstance;
diff --git a/indra/llcorehttp/_refcounted.h b/indra/llcorehttp/_refcounted.h
index 402e725152..cd16e2e2b4 100755
--- a/indra/llcorehttp/_refcounted.h
+++ b/indra/llcorehttp/_refcounted.h
@@ -120,7 +120,18 @@ inline void RefCounted::destroySelf()
delete this;
}
+inline void intrusive_ptr_add_ref(RefCounted* p)
+{
+ p->addRef();
+}
+
+inline void intrusive_ptr_release(RefCounted* p)
+{
+ p->release();
+}
+
} // end namespace LLCoreInt
+
#endif // LLCOREINT__REFCOUNTED_H_
diff --git a/indra/llcorehttp/bufferarray.h b/indra/llcorehttp/bufferarray.h
index 1094a435b4..076f341736 100755
--- a/indra/llcorehttp/bufferarray.h
+++ b/indra/llcorehttp/bufferarray.h
@@ -30,6 +30,7 @@
#include <cstdlib>
#include <vector>
+#include "boost/intrusive_ptr.hpp"
#include "_refcounted.h"
@@ -73,6 +74,8 @@ public:
BufferArray();
+ typedef boost::intrusive_ptr<BufferArray> ptr_t;
+
protected:
virtual ~BufferArray(); // Use release()
@@ -129,6 +132,7 @@ protected:
container_t mBlocks;
size_t mLen;
+
}; // end class BufferArray
diff --git a/indra/llcorehttp/httpcommon.cpp b/indra/llcorehttp/httpcommon.cpp
index 7907e958a4..99238ea920 100755
--- a/indra/llcorehttp/httpcommon.cpp
+++ b/indra/llcorehttp/httpcommon.cpp
@@ -42,7 +42,7 @@ HttpStatus::operator unsigned long() const
{
static const int shift(sizeof(unsigned long) * 4);
- unsigned long result(((unsigned long) mType) << shift | (unsigned long) (int) mStatus);
+ unsigned long result(((unsigned long)mDetails->mType) << shift | (unsigned long)(int)mDetails->mStatus);
return result;
}
@@ -131,30 +131,34 @@ std::string HttpStatus::toString() const
{
return std::string("");
}
- switch (mType)
+ switch (getType())
{
case EXT_CURL_EASY:
- return std::string(curl_easy_strerror(CURLcode(mStatus)));
+ return std::string(curl_easy_strerror(CURLcode(getStatus())));
case EXT_CURL_MULTI:
- return std::string(curl_multi_strerror(CURLMcode(mStatus)));
+ return std::string(curl_multi_strerror(CURLMcode(getStatus())));
case LLCORE:
- if (mStatus >= 0 && mStatus < llcore_errors_count)
+ if (getStatus() >= 0 && getStatus() < llcore_errors_count)
{
- return std::string(llcore_errors[mStatus]);
+ return std::string(llcore_errors[getStatus()]);
}
break;
default:
if (isHttpStatus())
{
+ // special handling for status 499 "Linden Catchall"
+ if ((getType() == 499) && (!getMessage().empty()))
+ return getMessage();
+
// Binary search for the error code and string
int bottom(0), top(http_errors_count);
while (true)
{
int at((bottom + top) / 2);
- if (mType == http_errors[at].mCode)
+ if (getType() == http_errors[at].mCode)
{
return std::string(http_errors[at].mText);
}
@@ -162,7 +166,7 @@ std::string HttpStatus::toString() const
{
break;
}
- else if (mType < http_errors[at].mCode)
+ else if (getType() < http_errors[at].mCode)
{
top = at;
}
@@ -182,9 +186,9 @@ std::string HttpStatus::toTerseString() const
{
std::ostringstream result;
- unsigned int error_value((unsigned short) mStatus);
+ unsigned int error_value((unsigned short)getStatus());
- switch (mType)
+ switch (getType())
{
case EXT_CURL_EASY:
result << "Easy_";
@@ -202,7 +206,7 @@ std::string HttpStatus::toTerseString() const
if (isHttpStatus())
{
result << "Http_";
- error_value = mType;
+ error_value = getType();
}
else
{
@@ -244,7 +248,7 @@ bool HttpStatus::isRetryable() const
// Disable the '*this == inv_status' test and look for 'Core_9'
// failures in log files.
- return ((isHttpStatus() && mType >= 499 && mType <= 599) || // Include special 499 in retryables
+ return ((isHttpStatus() && getType() >= 499 && getType() <= 599) || // Include special 499 in retryables
*this == cant_connect || // Connection reset/endpoint problems
*this == cant_res_proxy || // DNS problems
*this == cant_res_host || // DNS problems
diff --git a/indra/llcorehttp/httpcommon.h b/indra/llcorehttp/httpcommon.h
index 9601f94125..898d3d47fa 100755
--- a/indra/llcorehttp/httpcommon.h
+++ b/indra/llcorehttp/httpcommon.h
@@ -188,10 +188,12 @@
///
#include "linden_common.h" // Modifies curl/curl.h interfaces
-
+#include "boost/intrusive_ptr.hpp"
+#include "boost/shared_ptr.hpp"
+#include "boost/weak_ptr.hpp"
+#include "boost/function.hpp"
#include <string>
-
namespace LLCore
{
@@ -286,52 +288,63 @@ enum HttpError
/// 5. Construct an HTTP 301 status code to be treated as success:
/// HttpStatus(301, HE_SUCCESS);
///
+/// 6. Construct a failed status of HTTP Status 499 with a custom error message
+/// HttpStatus(499, "Failed LLSD Response");
struct HttpStatus
{
typedef unsigned short type_enum_t;
HttpStatus()
- : mType(LLCORE),
- mStatus(HE_SUCCESS)
- {}
+ {
+ mDetails = boost::shared_ptr<Details>(new Details(LLCORE, HE_SUCCESS));
+ }
HttpStatus(type_enum_t type, short status)
- : mType(type),
- mStatus(status)
- {}
+ {
+ mDetails = boost::shared_ptr<Details>(new Details(type, status));
+ }
HttpStatus(int http_status)
- : mType(http_status),
- mStatus(http_status >= 200 && http_status <= 299
- ? HE_SUCCESS
- : HE_REPLY_ERROR)
- {
- llassert(http_status >= 100 && http_status <= 999);
- }
+ {
+ mDetails = boost::shared_ptr<Details>(new Details(http_status,
+ (http_status >= 200 && http_status <= 299) ? HE_SUCCESS : HE_REPLY_ERROR));
+ llassert(http_status >= 100 && http_status <= 999);
+ }
+
+ HttpStatus(int http_status, const std::string &message)
+ {
+ mDetails = boost::shared_ptr<Details>(new Details(http_status,
+ (http_status >= 200 && http_status <= 299) ? HE_SUCCESS : HE_REPLY_ERROR));
+ llassert(http_status >= 100 && http_status <= 999);
+ mDetails->mMessage = message;
+ }
HttpStatus(const HttpStatus & rhs)
- : mType(rhs.mType),
- mStatus(rhs.mStatus)
- {}
+ {
+ mDetails = rhs.mDetails;
+ }
+
+ ~HttpStatus()
+ {
+ }
HttpStatus & operator=(const HttpStatus & rhs)
- {
- // Don't care if lhs & rhs are the same object
+ {
+ mDetails = rhs.mDetails;
+ return *this;
+ }
- mType = rhs.mType;
- mStatus = rhs.mStatus;
- return *this;
- }
+ HttpStatus & clone(const HttpStatus &rhs)
+ {
+ mDetails = boost::shared_ptr<Details>(new Details(*rhs.mDetails));
+ return *this;
+ }
static const type_enum_t EXT_CURL_EASY = 0; ///< mStatus is an error from a curl_easy_*() call
static const type_enum_t EXT_CURL_MULTI = 1; ///< mStatus is an error from a curl_multi_*() call
static const type_enum_t LLCORE = 2; ///< mStatus is an HE_* error code
///< 100-999 directly represent HTTP status codes
-
- type_enum_t mType;
- short mStatus;
-
/// Test for successful status in the code regardless
/// of error source (internal, libcurl).
///
@@ -339,7 +352,7 @@ struct HttpStatus
///
operator bool() const
{
- return 0 == mStatus;
+ return 0 == mDetails->mStatus;
}
/// Inverse of previous operator.
@@ -347,14 +360,14 @@ struct HttpStatus
/// @return 'true' on any error condition
bool operator !() const
{
- return 0 != mStatus;
+ return 0 != mDetails->mStatus;
}
/// Equality and inequality tests to bypass bool conversion
/// which will do the wrong thing in conditional expressions.
bool operator==(const HttpStatus & rhs) const
{
- return mType == rhs.mType && mStatus == rhs.mStatus;
+ return (*mDetails == *rhs.mDetails);
}
bool operator!=(const HttpStatus & rhs) const
@@ -395,7 +408,7 @@ struct HttpStatus
/// HTTP response status (100 - 999).
bool isHttpStatus() const
{
- return mType >= type_enum_t(100) && mType <= type_enum_t(999);
+ return mDetails->mType >= type_enum_t(100) && mDetails->mType <= type_enum_t(999);
}
/// Returns true if the status is one that will be retried
@@ -403,7 +416,78 @@ struct HttpStatus
/// where that logic needs to be replicated. Only applies
/// to failed statuses, successful statuses will return false.
bool isRetryable() const;
-
+
+ /// Returns the currently set status code as a raw number
+ ///
+ short getStatus() const
+ {
+ return mDetails->mStatus;
+ }
+
+ /// Returns the currently set status type
+ ///
+ type_enum_t getType() const
+ {
+ return mDetails->mType;
+ }
+
+ /// Returns an optional error message if one has been set.
+ ///
+ std::string getMessage() const
+ {
+ return mDetails->mMessage;
+ }
+
+ /// Sets an optional error message
+ ///
+ void setMessage(const std::string &message)
+ {
+ mDetails->mMessage = message;
+ }
+
+ /// Retrieves an optionally recorded SSL certificate.
+ void * getErrorData() const
+ {
+ return mDetails->mErrorData;
+ }
+
+ /// Optionally sets an SSL certificate on this status.
+ void setErrorData(void *data)
+ {
+ mDetails->mErrorData = data;
+ }
+
+private:
+
+ struct Details
+ {
+ Details(type_enum_t type, short status):
+ mType(type),
+ mStatus(status),
+ mMessage(),
+ mErrorData(NULL)
+ {}
+
+ Details(const Details &rhs) :
+ mType(rhs.mType),
+ mStatus(rhs.mStatus),
+ mMessage(rhs.mMessage),
+ mErrorData(rhs.mErrorData)
+ {}
+
+ bool operator == (const Details &rhs) const
+ {
+ return (mType == rhs.mType) && (mStatus == rhs.mStatus);
+ }
+
+ type_enum_t mType;
+ short mStatus;
+ std::string mMessage;
+ void * mErrorData;
+ };
+
+ boost::shared_ptr<Details> mDetails;
+
}; // end struct HttpStatus
} // end namespace LLCore
diff --git a/indra/llcorehttp/httphandler.h b/indra/llcorehttp/httphandler.h
index 9171e4e7b9..740e986dec 100755
--- a/indra/llcorehttp/httphandler.h
+++ b/indra/llcorehttp/httphandler.h
@@ -45,7 +45,7 @@ class HttpResponse;
/// be shared by any number of requests and across instances
/// of HttpRequest running in the same thread.
///
-/// Threading: HttpHandler itself is pure interface and is
+/// Threading: HttpHandler itself is interface and is
/// tread-compatible. Most derivations, however, will have
/// different constraints.
///
@@ -58,7 +58,7 @@ class HttpHandler
{
public:
virtual ~HttpHandler()
- {}
+ { }
/// Method invoked during calls to @see update(). Each invocation
/// represents the completion of some requested operation. Caller
diff --git a/indra/llcorehttp/httpheaders.cpp b/indra/llcorehttp/httpheaders.cpp
index 23ebea361c..73c92c8f10 100755
--- a/indra/llcorehttp/httpheaders.cpp
+++ b/indra/llcorehttp/httpheaders.cpp
@@ -105,7 +105,7 @@ void HttpHeaders::appendNormal(const char * header, size_t size)
// Find from end to simulate a tradition of using single-valued
// std::map for this in the past.
-const std::string * HttpHeaders::find(const char * name) const
+const std::string * HttpHeaders::find(const std::string &name) const
{
const_reverse_iterator iend(rend());
for (const_reverse_iterator iter(rbegin()); iend != iter; ++iter)
diff --git a/indra/llcorehttp/httpheaders.h b/indra/llcorehttp/httpheaders.h
index f70cd898f3..940f92183c 100755
--- a/indra/llcorehttp/httpheaders.h
+++ b/indra/llcorehttp/httpheaders.h
@@ -28,8 +28,8 @@
#define _LLCORE_HTTP_HEADERS_H_
+#include "httpcommon.h"
#include <string>
-
#include "_refcounted.h"
@@ -92,6 +92,7 @@ public:
/// the instance.
HttpHeaders();
+ typedef boost::intrusive_ptr<HttpHeaders> ptr_t;
protected:
virtual ~HttpHeaders(); // Use release()
@@ -145,8 +146,12 @@ public:
// a pointer to a std::string in the container.
// Pointer is valid only for the lifetime of
// the container or until container is modifed.
- //
- const std::string * find(const char * name) const;
+
+ const std::string * find(const std::string &name) const;
+ const std::string * find(const char * name) const
+ {
+ return find(std::string(name));
+ }
// Count of headers currently in the list.
size_type size() const
diff --git a/indra/llcorehttp/httpoptions.cpp b/indra/llcorehttp/httpoptions.cpp
index 5bf1ecb4a5..a4d08a80df 100755
--- a/indra/llcorehttp/httpoptions.cpp
+++ b/indra/llcorehttp/httpoptions.cpp
@@ -25,7 +25,7 @@
*/
#include "httpoptions.h"
-
+#include "lldefs.h"
#include "_httpinternal.h"
@@ -33,14 +33,17 @@ namespace LLCore
{
-HttpOptions::HttpOptions()
- : RefCounted(true),
- mWantHeaders(false),
- mTracing(HTTP_TRACE_OFF),
- mTimeout(HTTP_REQUEST_TIMEOUT_DEFAULT),
- mTransferTimeout(HTTP_REQUEST_XFER_TIMEOUT_DEFAULT),
- mRetries(HTTP_RETRY_COUNT_DEFAULT),
- mUseRetryAfter(HTTP_USE_RETRY_AFTER_DEFAULT)
+HttpOptions::HttpOptions() : RefCounted(true),
+ mWantHeaders(false),
+ mTracing(HTTP_TRACE_OFF),
+ mTimeout(HTTP_REQUEST_TIMEOUT_DEFAULT),
+ mTransferTimeout(HTTP_REQUEST_XFER_TIMEOUT_DEFAULT),
+ mRetries(HTTP_RETRY_COUNT_DEFAULT),
+ mUseRetryAfter(HTTP_USE_RETRY_AFTER_DEFAULT),
+ mFollowRedirects(false),
+ mVerifyPeer(false),
+ mVerifyHost(false),
+ mDNSCacheTimeout(-1L)
{}
@@ -82,5 +85,23 @@ void HttpOptions::setUseRetryAfter(bool use_retry)
mUseRetryAfter = use_retry;
}
+void HttpOptions::setFollowRedirects(bool follow_redirect)
+{
+ mFollowRedirects = follow_redirect;
+}
+
+void HttpOptions::setSSLVerifyPeer(bool verify)
+{
+ mVerifyPeer = verify;
+}
+void HttpOptions::setSSLVerifyHost(bool verify)
+{
+ mVerifyHost = verify;
+}
+
+void HttpOptions::setDNSCacheTimeout(int timeout)
+{
+ mDNSCacheTimeout = timeout;
+}
} // end namespace LLCore
diff --git a/indra/llcorehttp/httpoptions.h b/indra/llcorehttp/httpoptions.h
index 4ab5ff18c4..765d2431bb 100755
--- a/indra/llcorehttp/httpoptions.h
+++ b/indra/llcorehttp/httpoptions.h
@@ -29,7 +29,6 @@
#include "httpcommon.h"
-
#include "_refcounted.h"
@@ -61,6 +60,8 @@ class HttpOptions : public LLCoreInt::RefCounted
public:
HttpOptions();
+ typedef boost::intrusive_ptr<HttpOptions> ptr_t;
+
protected:
virtual ~HttpOptions(); // Use release()
@@ -68,47 +69,86 @@ protected:
void operator=(const HttpOptions &); // Not defined
public:
+
// Default: false
void setWantHeaders(bool wanted);
bool getWantHeaders() const
- {
- return mWantHeaders;
- }
+ {
+ return mWantHeaders;
+ }
// Default: 0
void setTrace(int long);
int getTrace() const
- {
- return mTracing;
- }
+ {
+ return mTracing;
+ }
// Default: 30
void setTimeout(unsigned int timeout);
unsigned int getTimeout() const
- {
- return mTimeout;
- }
+ {
+ return mTimeout;
+ }
// Default: 0
void setTransferTimeout(unsigned int timeout);
unsigned int getTransferTimeout() const
- {
- return mTransferTimeout;
- }
+ {
+ return mTransferTimeout;
+ }
+ /// Sets the number of retries on an LLCore::HTTPRequest before the
+ /// request fails.
// Default: 8
void setRetries(unsigned int retries);
unsigned int getRetries() const
- {
- return mRetries;
- }
+ {
+ return mRetries;
+ }
// Default: true
void setUseRetryAfter(bool use_retry);
bool getUseRetryAfter() const
- {
- return mUseRetryAfter;
- }
+ {
+ return mUseRetryAfter;
+ }
+
+ /// Instructs the LLCore::HTTPRequest to follow redirects
+ /// Default: false
+ void setFollowRedirects(bool follow_redirect);
+ bool getFollowRedirects() const
+ {
+ return mFollowRedirects;
+ }
+
+ /// Instructs the LLCore::HTTPRequest to verify that the exchanged security
+ /// certificate is authentic.
+ /// Default: false
+ void setSSLVerifyPeer(bool verify);
+ bool getSSLVerifyPeer() const
+ {
+ return mVerifyPeer;
+ }
+
+ /// Instructs the LLCore::HTTPRequest to verify that the name in the
+ /// security certificate matches the name of the host contacted.
+ /// Default: false
+ void setSSLVerifyHost(bool verify);
+ bool getSSLVerifyHost() const
+ {
+ return mVerifyHost;
+ }
+
+ /// Sets the time for DNS name caching in seconds. Setting this value
+ /// to 0 will disable name caching. Setting this value to -1 causes the
+ /// name cache to never time out.
+ /// Default: -1
+ void setDNSCacheTimeout(int timeout);
+ int getDNSCacheTimeout() const
+ {
+ return mDNSCacheTimeout;
+ }
protected:
bool mWantHeaders;
@@ -117,6 +157,10 @@ protected:
unsigned int mTransferTimeout;
unsigned int mRetries;
bool mUseRetryAfter;
+ bool mFollowRedirects;
+ bool mVerifyPeer;
+ bool mVerifyHost;
+ int mDNSCacheTimeout;
}; // end class HttpOptions
diff --git a/indra/llcorehttp/httprequest.cpp b/indra/llcorehttp/httprequest.cpp
index 7b1888e3eb..d4c60a6f14 100755
--- a/indra/llcorehttp/httprequest.cpp
+++ b/indra/llcorehttp/httprequest.cpp
@@ -117,6 +117,15 @@ HttpStatus HttpRequest::setStaticPolicyOption(EPolicyOption opt, policy_t pclass
return HttpService::instanceOf()->setPolicyOption(opt, pclass, value, ret_value);
}
+HttpStatus HttpRequest::setStaticPolicyOption(EPolicyOption opt, policy_t pclass, policyCallback_t value, policyCallback_t * ret_value)
+{
+ if (HttpService::RUNNING == HttpService::instanceOf()->getState())
+ {
+ return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC);
+ }
+
+ return HttpService::instanceOf()->setPolicyOption(opt, pclass, value, ret_value);
+}
HttpHandle HttpRequest::setPolicyOption(EPolicyOption opt, policy_t pclass,
long value, HttpHandler * handler)
@@ -316,6 +325,100 @@ HttpHandle HttpRequest::requestPut(policy_t policy_id,
return handle;
}
+HttpHandle HttpRequest::requestDelete(policy_t policy_id,
+ priority_t priority,
+ const std::string & url,
+ HttpOptions * options,
+ HttpHeaders * headers,
+ HttpHandler * user_handler)
+{
+ HttpStatus status;
+ HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
+
+ HttpOpRequest * op = new HttpOpRequest();
+ if (!(status = op->setupDelete(policy_id, priority, url, options, headers)))
+ {
+ op->release();
+ mLastReqStatus = status;
+ return handle;
+ }
+ op->setReplyPath(mReplyQueue, user_handler);
+ if (!(status = mRequestQueue->addOp(op))) // transfers refcount
+ {
+ op->release();
+ mLastReqStatus = status;
+ return handle;
+ }
+
+ mLastReqStatus = status;
+ handle = static_cast<HttpHandle>(op);
+
+ return handle;
+}
+
+HttpHandle HttpRequest::requestPatch(policy_t policy_id,
+ priority_t priority,
+ const std::string & url,
+ BufferArray * body,
+ HttpOptions * options,
+ HttpHeaders * headers,
+ HttpHandler * user_handler)
+{
+ HttpStatus status;
+ HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
+
+ HttpOpRequest * op = new HttpOpRequest();
+ if (!(status = op->setupPatch(policy_id, priority, url, body, options, headers)))
+ {
+ op->release();
+ mLastReqStatus = status;
+ return handle;
+ }
+ op->setReplyPath(mReplyQueue, user_handler);
+ if (!(status = mRequestQueue->addOp(op))) // transfers refcount
+ {
+ op->release();
+ mLastReqStatus = status;
+ return handle;
+ }
+
+ mLastReqStatus = status;
+ handle = static_cast<HttpHandle>(op);
+
+ return handle;
+}
+
+HttpHandle HttpRequest::requestCopy(policy_t policy_id,
+ priority_t priority,
+ const std::string & url,
+ HttpOptions * options,
+ HttpHeaders * headers,
+ HttpHandler * user_handler)
+{
+ HttpStatus status;
+ HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
+
+ HttpOpRequest * op = new HttpOpRequest();
+ if (!(status = op->setupCopy(policy_id, priority, url, options, headers)))
+ {
+ op->release();
+ mLastReqStatus = status;
+ return handle;
+ }
+ op->setReplyPath(mReplyQueue, user_handler);
+ if (!(status = mRequestQueue->addOp(op))) // transfers refcount
+ {
+ op->release();
+ mLastReqStatus = status;
+ return handle;
+ }
+
+ mLastReqStatus = status;
+ handle = static_cast<HttpHandle>(op);
+
+ return handle;
+}
+
HttpHandle HttpRequest::requestNoOp(HttpHandler * user_handler)
{
diff --git a/indra/llcorehttp/httprequest.h b/indra/llcorehttp/httprequest.h
index 7f23723b0b..e87a8b691a 100755
--- a/indra/llcorehttp/httprequest.h
+++ b/indra/llcorehttp/httprequest.h
@@ -97,6 +97,8 @@ public:
typedef unsigned int policy_t;
typedef unsigned int priority_t;
+ typedef boost::shared_ptr<HttpRequest> ptr_t;
+ typedef boost::weak_ptr<HttpRequest> wptr_t;
public:
/// @name PolicyMethods
/// @{
@@ -163,7 +165,7 @@ public:
/// Long value that if non-zero enables the use of the
/// traditional LLProxy code for http/socks5 support. If
- // enabled, has priority over GP_HTTP_PROXY.
+ /// enabled, has priority over GP_HTTP_PROXY.
///
/// Global only
PO_LLPROXY,
@@ -219,15 +221,25 @@ public:
/// Controls whether client-side throttling should be
/// performed on this policy class. Positive values
/// enable throttling and specify the request rate
- /// (requests per second) that should be targetted.
+ /// (requests per second) that should be targeted.
/// A value of zero, the default, specifies no throttling.
///
/// Per-class only
PO_THROTTLE_RATE,
+ /// Controls the callback function used to control SSL CTX
+ /// certificate verification.
+ ///
+ /// Global only
+ PO_SSL_VERIFY_CALLBACK,
+
PO_LAST // Always at end
};
+ /// Prototype for policy based callbacks. The callback methods will be executed
+ /// on the worker thread so no modifications should be made to the HttpHandler object.
+ typedef boost::function<HttpStatus(const std::string &, HttpHandler const * const, void *)> policyCallback_t;
+
/// Set a policy option for a global or class parameter at
/// startup time (prior to thread start).
///
@@ -243,6 +255,8 @@ public:
long value, long * ret_value);
static HttpStatus setStaticPolicyOption(EPolicyOption opt, policy_t pclass,
const std::string & value, std::string * ret_value);
+ static HttpStatus setStaticPolicyOption(EPolicyOption opt, policy_t pclass,
+ policyCallback_t value, policyCallback_t * ret_value);;
/// Set a parameter on a class-based policy option. Calls
/// made after the start of the servicing thread are
@@ -464,7 +478,68 @@ public:
HttpHandler * handler);
- /// Queue a NoOp request.
+ /// Queue a full HTTP PUT. Query arguments and body may
+ /// be provided. Caller is responsible for escaping and
+ /// encoding and communicating the content types.
+ ///
+ /// @param policy_id @see requestGet()
+ /// @param priority "
+ /// @param url "
+ /// @param options @see requestGet()K(optional)
+ /// @param headers "
+ /// @param handler "
+ /// @return "
+ ///
+ HttpHandle requestDelete(policy_t policy_id,
+ priority_t priority,
+ const std::string & url,
+ HttpOptions * options,
+ HttpHeaders * headers,
+ HttpHandler * user_handler);
+
+ /// Queue a full HTTP PUT. Query arguments and body may
+ /// be provided. Caller is responsible for escaping and
+ /// encoding and communicating the content types.
+ ///
+ /// @param policy_id @see requestGet()
+ /// @param priority "
+ /// @param url "
+ /// @param body Byte stream to be sent as the body. No
+ /// further encoding or escaping will be done
+ /// to the content.
+ /// @param options @see requestGet()K(optional)
+ /// @param headers "
+ /// @param handler "
+ /// @return "
+ ///
+ HttpHandle requestPatch(policy_t policy_id,
+ priority_t priority,
+ const std::string & url,
+ BufferArray * body,
+ HttpOptions * options,
+ HttpHeaders * headers,
+ HttpHandler * user_handler);
+
+ /// Queue a full HTTP PUT. Query arguments and body may
+ /// be provided. Caller is responsible for escaping and
+ /// encoding and communicating the content types.
+ ///
+ /// @param policy_id @see requestGet()
+ /// @param priority "
+ /// @param url "
+ /// @param options @see requestGet()K(optional)
+ /// @param headers "
+ /// @param handler "
+ /// @return "
+ ///
+ HttpHandle requestCopy(policy_t policy_id,
+ priority_t priority,
+ const std::string & url,
+ HttpOptions * options,
+ HttpHeaders * headers,
+ HttpHandler * user_handler);
+
+ /// Queue a NoOp request.
/// The request is queued and serviced by the working thread which
/// immediately processes it and returns the request to the reply
/// queue.
diff --git a/indra/llcorehttp/httpresponse.cpp b/indra/llcorehttp/httpresponse.cpp
index c974395b0a..7d88f02527 100755
--- a/indra/llcorehttp/httpresponse.cpp
+++ b/indra/llcorehttp/httpresponse.cpp
@@ -41,7 +41,8 @@ HttpResponse::HttpResponse()
mBufferArray(NULL),
mHeaders(NULL),
mRetries(0U),
- m503Retries(0U)
+ m503Retries(0U),
+ mRequestUrl()
{}
@@ -89,5 +90,9 @@ void HttpResponse::setHeaders(HttpHeaders * headers)
mHeaders = headers;
}
+size_t HttpResponse::getBodySize() const
+{
+ return (mBufferArray) ? mBufferArray->size() : 0;
+}
} // end namespace LLCore
diff --git a/indra/llcorehttp/httpresponse.h b/indra/llcorehttp/httpresponse.h
index aee64e2878..6c3b4da5e6 100755
--- a/indra/llcorehttp/httpresponse.h
+++ b/indra/llcorehttp/httpresponse.h
@@ -69,6 +69,18 @@ protected:
void operator=(const HttpResponse &); // Not defined
public:
+ /// Statistics for the HTTP
+ struct TransferStats
+ {
+ typedef boost::shared_ptr<TransferStats> ptr_t;
+
+ TransferStats() : mSizeDownload(0.0), mTotalTime(0.0), mSpeedDownload(0.0) {}
+ F64 mSizeDownload;
+ F64 mTotalTime;
+ F64 mSpeedDownload;
+ };
+
+
/// Returns the final status of the requested operation.
///
HttpStatus getStatus() const
@@ -92,6 +104,10 @@ public:
return mBufferArray;
}
+ /// Safely get the size of the body buffer. If the body buffer is missing
+ /// return 0 as the size.
+ size_t getBodySize() const;
+
/// Set the response data in the instance. Will drop the reference
/// count to any existing data and increment the count of that passed
/// in. It is legal to set the data to NULL.
@@ -168,6 +184,27 @@ public:
m503Retries = retries_503;
}
+ void setTransferStats(TransferStats::ptr_t &stats)
+ {
+ mStats = stats;
+ }
+
+ TransferStats::ptr_t getTransferStats()
+ {
+ return mStats;
+ }
+
+ void setRequestURL(const std::string &url)
+ {
+ mRequestUrl = url;
+ }
+
+ const std::string &getRequestURL() const
+ {
+ return mRequestUrl;
+ }
+
+
protected:
// Response data here
HttpStatus mStatus;
@@ -179,6 +216,9 @@ protected:
std::string mContentType;
unsigned int mRetries;
unsigned int m503Retries;
+ std::string mRequestUrl;
+
+ TransferStats::ptr_t mStats;
};
diff --git a/indra/llcorehttp/tests/test_httpstatus.hpp b/indra/llcorehttp/tests/test_httpstatus.hpp
index 0b379836c9..4502d32fe1 100755
--- a/indra/llcorehttp/tests/test_httpstatus.hpp
+++ b/indra/llcorehttp/tests/test_httpstatus.hpp
@@ -55,77 +55,68 @@ void HttpStatusTestObjectType::test<1>()
// auto allocation fine for this
HttpStatus status;
- status.mType = HttpStatus::EXT_CURL_EASY;
- status.mStatus = 0;
+
+ status = HttpStatus(HttpStatus::EXT_CURL_EASY, 0);
ensure(bool(status));
ensure(false == !(status));
- status.mType = HttpStatus::EXT_CURL_MULTI;
- status.mStatus = 0;
+ status = HttpStatus(HttpStatus::EXT_CURL_MULTI, 0);
ensure(bool(status));
ensure(false == !(status));
-
- status.mType = HttpStatus::LLCORE;
- status.mStatus = HE_SUCCESS;
+
+ status = HttpStatus(HttpStatus::LLCORE, HE_SUCCESS);
ensure(bool(status));
ensure(false == !(status));
- status.mType = HttpStatus::EXT_CURL_MULTI;
- status.mStatus = -1;
+ status = HttpStatus(HttpStatus::EXT_CURL_MULTI, -1);
ensure(false == bool(status));
ensure(!(status));
- status.mType = HttpStatus::EXT_CURL_EASY;
- status.mStatus = CURLE_BAD_DOWNLOAD_RESUME;
+ status = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_BAD_DOWNLOAD_RESUME);
ensure(false == bool(status));
ensure(!(status));
}
-template <> template <>
-void HttpStatusTestObjectType::test<2>()
-{
- set_test_name("HttpStatus memory structure");
-
- // Require that an HttpStatus object can be trivially
- // returned as a function return value in registers.
- // One should fit in an int on all platforms.
-
- ensure(sizeof(HttpStatus) <= sizeof(int));
-}
+// template <> template <>
+// void HttpStatusTestObjectType::test<2>()
+// {
+// set_test_name("HttpStatus memory structure");
+//
+// // Require that an HttpStatus object can be trivially
+// // returned as a function return value in registers.
+// // One should fit in an int on all platforms.
+//
+// //ensure(sizeof(HttpStatus) <= sizeof(int));
+// }
template <> template <>
-void HttpStatusTestObjectType::test<3>()
+void HttpStatusTestObjectType::test<2>()
{
set_test_name("HttpStatus valid status string conversion");
- HttpStatus status;
- status.mType = HttpStatus::EXT_CURL_EASY;
- status.mStatus = 0;
+ HttpStatus status = HttpStatus(HttpStatus::EXT_CURL_EASY, 0);
std::string msg = status.toString();
// std::cout << "Result: " << msg << std::endl;
ensure(msg.empty());
-
- status.mType = HttpStatus::EXT_CURL_EASY;
- status.mStatus = CURLE_BAD_FUNCTION_ARGUMENT;
+
+ status = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_BAD_FUNCTION_ARGUMENT);
msg = status.toString();
// std::cout << "Result: " << msg << std::endl;
ensure(! msg.empty());
- status.mType = HttpStatus::EXT_CURL_MULTI;
- status.mStatus = CURLM_OUT_OF_MEMORY;
+ status = HttpStatus(HttpStatus::EXT_CURL_MULTI, CURLM_OUT_OF_MEMORY);
msg = status.toString();
// std::cout << "Result: " << msg << std::endl;
ensure(! msg.empty());
- status.mType = HttpStatus::LLCORE;
- status.mStatus = HE_SHUTTING_DOWN;
+ status = HttpStatus(HttpStatus::LLCORE, HE_SHUTTING_DOWN);
msg = status.toString();
// std::cout << "Result: " << msg << std::endl;
ensure(! msg.empty());
@@ -133,32 +124,28 @@ void HttpStatusTestObjectType::test<3>()
template <> template <>
-void HttpStatusTestObjectType::test<4>()
+void HttpStatusTestObjectType::test<3>()
{
set_test_name("HttpStatus invalid status string conversion");
- HttpStatus status;
- status.mType = HttpStatus::EXT_CURL_EASY;
- status.mStatus = 32726;
+ HttpStatus status = HttpStatus(HttpStatus::EXT_CURL_EASY, 32726);
std::string msg = status.toString();
// std::cout << "Result: " << msg << std::endl;
ensure(! msg.empty());
-
- status.mType = HttpStatus::EXT_CURL_MULTI;
- status.mStatus = -470;
+
+ status = HttpStatus(HttpStatus::EXT_CURL_MULTI, -470);
msg = status.toString();
// std::cout << "Result: " << msg << std::endl;
ensure(! msg.empty());
- status.mType = HttpStatus::LLCORE;
- status.mStatus = 923;
+ status = HttpStatus(HttpStatus::LLCORE, 923);
msg = status.toString();
// std::cout << "Result: " << msg << std::endl;
ensure(! msg.empty());
}
template <> template <>
-void HttpStatusTestObjectType::test<5>()
+void HttpStatusTestObjectType::test<4>()
{
set_test_name("HttpStatus equality/inequality testing");
@@ -170,62 +157,55 @@ void HttpStatusTestObjectType::test<5>()
HttpStatus status2(HttpStatus::EXT_CURL_EASY, HE_SUCCESS);
ensure(status1 != status2);
- status1.mType = HttpStatus::LLCORE;
- status1.mStatus = HE_REPLY_ERROR;
- status2.mType = HttpStatus::LLCORE;
- status2.mStatus= HE_SHUTTING_DOWN;
+ status1 = HttpStatus(HttpStatus::LLCORE, HE_REPLY_ERROR);
+ status1 = HttpStatus(HttpStatus::LLCORE, HE_SHUTTING_DOWN);
+
ensure(status1 != status2);
}
template <> template <>
-void HttpStatusTestObjectType::test<6>()
+void HttpStatusTestObjectType::test<5>()
{
set_test_name("HttpStatus basic HTTP status encoding");
HttpStatus status;
- status.mType = 200;
- status.mStatus = HE_SUCCESS;
+
+ status = HttpStatus(200, HE_SUCCESS);
std::string msg = status.toString();
ensure(msg.empty());
ensure(bool(status));
// Normally a success but application says error
- status.mStatus = HE_REPLY_ERROR;
+ status = HttpStatus(200, HE_REPLY_ERROR);
msg = status.toString();
ensure(! msg.empty());
ensure(! bool(status));
ensure(status.toULong() > 1UL); // Biggish number, not a bool-to-ulong
// Same statuses with distinct success/fail are distinct
- status.mType = 200;
- status.mStatus = HE_SUCCESS;
+ status = HttpStatus(200, HE_SUCCESS);
HttpStatus status2(200, HE_REPLY_ERROR);
ensure(status != status2);
// Normally an error but application says okay
- status.mType = 406;
- status.mStatus = HE_SUCCESS;
+ status = HttpStatus(406, HE_SUCCESS);
msg = status.toString();
ensure(msg.empty());
ensure(bool(status));
// Different statuses but both successful are distinct
- status.mType = 200;
- status.mStatus = HE_SUCCESS;
- status2.mType = 201;
- status2.mStatus = HE_SUCCESS;
+ status = HttpStatus(200, HE_SUCCESS);
+ status2 = HttpStatus(201, HE_SUCCESS);
ensure(status != status2);
// Different statuses but both failed are distinct
- status.mType = 200;
- status.mStatus = HE_REPLY_ERROR;
- status2.mType = 201;
- status2.mStatus = HE_REPLY_ERROR;
+ status = HttpStatus(200, HE_REPLY_ERROR);
+ status2 = HttpStatus(201, HE_REPLY_ERROR);
ensure(status != status2);
}
template <> template <>
-void HttpStatusTestObjectType::test<7>()
+void HttpStatusTestObjectType::test<6>()
{
set_test_name("HttpStatus HTTP status text strings");
@@ -234,34 +214,30 @@ void HttpStatusTestObjectType::test<7>()
ensure(! msg.empty()); // Should be something
ensure(msg == "Continue");
- status.mStatus = HE_SUCCESS;
+ status = HttpStatus(200, HE_SUCCESS);
msg = status.toString();
ensure(msg.empty()); // Success is empty
- status.mType = 199;
- status.mStatus = HE_REPLY_ERROR;
+ status = HttpStatus(199, HE_REPLY_ERROR);
msg = status.toString();
ensure(msg == "Unknown error");
- status.mType = 505; // Last defined string
- status.mStatus = HE_REPLY_ERROR;
+ status = HttpStatus(505, HE_REPLY_ERROR);
msg = status.toString();
ensure(msg == "HTTP Version not supported");
- status.mType = 506; // One beyond
- status.mStatus = HE_REPLY_ERROR;
+ status = HttpStatus(506, HE_REPLY_ERROR);
msg = status.toString();
ensure(msg == "Unknown error");
- status.mType = 999; // Last HTTP status
- status.mStatus = HE_REPLY_ERROR;
+ status = HttpStatus(999, HE_REPLY_ERROR);
msg = status.toString();
ensure(msg == "Unknown error");
}
template <> template <>
-void HttpStatusTestObjectType::test<8>()
+void HttpStatusTestObjectType::test<7>()
{
set_test_name("HttpStatus toHex() nominal function");
@@ -273,7 +249,7 @@ void HttpStatusTestObjectType::test<8>()
template <> template <>
-void HttpStatusTestObjectType::test<9>()
+void HttpStatusTestObjectType::test<8>()
{
set_test_name("HttpStatus toTerseString() nominal function");
diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt
index 40eddcb0ab..f6ca6a3634 100755
--- a/indra/llmessage/CMakeLists.txt
+++ b/indra/llmessage/CMakeLists.txt
@@ -49,6 +49,7 @@ set(llmessage_SOURCE_FILES
llhttpclientadapter.cpp
llhttpconstants.cpp
llhttpnode.cpp
+ llhttpsdhandler.cpp
llhttpsender.cpp
llinstantmessage.cpp
lliobuffer.cpp
@@ -144,6 +145,7 @@ set(llmessage_HEADER_FILES
llhttpconstants.h
llhttpnode.h
llhttpnodeadapter.h
+ llhttpsdhandler.h
llhttpsender.h
llinstantmessage.h
llinvite.h
@@ -224,7 +226,7 @@ target_link_libraries(
llmessage
${CURL_LIBRARIES}
${LLCOMMON_LIBRARIES}
- ${LLVFS_LIBRARES}
+ ${LLVFS_LIBRARIES}
${LLMATH_LIBRARIES}
${CARES_LIBRARIES}
${OPENSSL_LIBRARIES}
@@ -241,15 +243,20 @@ if (LL_TESTS)
)
LL_ADD_PROJECT_UNIT_TESTS(llmessage "${llmessage_TEST_SOURCE_FILES}")
+
# set(TEST_DEBUG on)
+
set(test_libs
- ${CURL_LIBRARIES}
- ${LLMESSAGE_LIBRARIES}
${WINDOWS_LIBRARIES}
${LLVFS_LIBRARIES}
${LLMATH_LIBRARIES}
+ ${CURL_LIBRARIES}
${LLCOMMON_LIBRARIES}
- ${GOOGLEMOCK_LIBRARIES}
+ ${LLMESSAGE_LIBRARIES}
+ ${LLCOREHTTP_LIBRARIES}
+ ${BOOST_CONTEXT_LIBRARY}
+ ${BOOST_COROUTINE_LIBRARY}
+ ${GOOGLEMOCK_LIBRARIES}
)
LL_ADD_INTEGRATION_TEST(
diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp
index 549708097a..88b88d0454 100755
--- a/indra/llmessage/llavatarnamecache.cpp
+++ b/indra/llmessage/llavatarnamecache.cpp
@@ -33,9 +33,18 @@
#include "llhttpclient.h"
#include "llsd.h"
#include "llsdserialize.h"
-
+#include "httpresponse.h"
+#include "llhttpsdhandler.h"
#include <boost/tokenizer.hpp>
+#include "httpcommon.h"
+#include "httprequest.h"
+#include "httpheaders.h"
+#include "httpoptions.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
+#include "llcorehttputil.h"
+
#include <map>
#include <set>
@@ -90,6 +99,12 @@ namespace LLAvatarNameCache
// Time-to-live for a temp cache entry.
const F64 TEMP_CACHE_ENTRY_LIFETIME = 60.0;
+ LLCore::HttpRequest::ptr_t sHttpRequest;
+ LLCore::HttpHeaders::ptr_t sHttpHeaders;
+ LLCore::HttpOptions::ptr_t sHttpOptions;
+ LLCore::HttpRequest::policy_t sHttpPolicy;
+ LLCore::HttpRequest::priority_t sHttpPriority;
+
//-----------------------------------------------------------------------
// Internal methods
//-----------------------------------------------------------------------
@@ -121,7 +136,13 @@ namespace LLAvatarNameCache
// Erase expired names from cache
void eraseUnrefreshed();
- bool expirationFromCacheControl(const LLSD& headers, F64 *expires);
+ //bool expirationFromCacheControl(LLCore::HttpHeaders *headers, F64 *expires);
+ bool expirationFromCacheControl(const LLSD& headers, F64 *expires);
+
+ // This is a coroutine. The only parameter that can be specified as a reference is the self
+ void requestAvatarNameCache_(LLCoros::self& self, std::string url, std::vector<LLUUID> agentIds);
+
+ void handleAvNameCacheSuccess(const LLSD &data, const LLSD &httpResult);
}
/* Sample response:
@@ -163,94 +184,117 @@ namespace LLAvatarNameCache
</llsd>
*/
-class LLAvatarNameResponder : public LLHTTPClient::Responder
+// Coroutine for sending and processing avatar name cache requests.
+// Do not call directly. See documentation in lleventcoro.h and llcoro.h for
+// further explanation.
+void LLAvatarNameCache::requestAvatarNameCache_(LLCoros::self& self, std::string url, std::vector<LLUUID> agentIds)
{
- LOG_CLASS(LLAvatarNameResponder);
-private:
- // need to store agent ids that are part of this request in case of
- // an error, so we can flag them as unavailable
- std::vector<LLUUID> mAgentIDs;
-
-public:
- LLAvatarNameResponder(const std::vector<LLUUID>& agent_ids)
- : mAgentIDs(agent_ids)
- { }
-
-protected:
- /*virtual*/ void httpSuccess()
- {
- const LLSD& content = getContent();
- if (!content.isMap())
- {
- failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
- return;
- }
- // Pull expiration out of headers if available
- F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(getResponseHeaders());
- F64 now = LLFrameTimer::getTotalSeconds();
+ LL_DEBUGS("AvNameCache") << "Entering coroutine " << LLCoros::instance().getName(self)
+ << " with url '" << url << "', requesting " << agentIds.size() << " Agent Ids" << LL_ENDL;
- const LLSD& agents = content["agents"];
- LLSD::array_const_iterator it = agents.beginArray();
- for ( ; it != agents.endArray(); ++it)
- {
- const LLSD& row = *it;
- LLUUID agent_id = row["id"].asUUID();
+ try
+ {
+ bool success = true;
- LLAvatarName av_name;
- av_name.fromLLSD(row);
+ LLCoreHttpUtil::HttpCoroutineAdapter httpAdapter("NameCache", LLAvatarNameCache::sHttpPolicy);
+ LLSD results = httpAdapter.getAndYield(self, sHttpRequest, url);
+ LLSD httpResults;
- // Use expiration time from header
- av_name.mExpires = expires;
+ LL_DEBUGS() << results << LL_ENDL;
- LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result for " << agent_id << LL_ENDL;
- av_name.dump();
-
- // cache it and fire signals
- LLAvatarNameCache::processName(agent_id, av_name);
- }
+ if (!results.isMap())
+ {
+ LL_WARNS("AvNameCache") << " Invalid result returned from LLCoreHttpUtil::HttpCoroHandler." << LL_ENDL;
+ success = false;
+ }
+ else
+ {
+ httpResults = results["http_result"];
+ success = httpResults["success"].asBoolean();
+ if (!success)
+ {
+ LL_WARNS("AvNameCache") << "Error result from LLCoreHttpUtil::HttpCoroHandler. Code "
+ << httpResults["status"] << ": '" << httpResults["message"] << "'" << LL_ENDL;
+ }
+ }
- // Same logic as error response case
- const LLSD& unresolved_agents = content["bad_ids"];
- S32 num_unresolved = unresolved_agents.size();
- if (num_unresolved > 0)
- {
- LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result " << num_unresolved << " unresolved ids; "
- << "expires in " << expires - now << " seconds"
- << LL_ENDL;
- it = unresolved_agents.beginArray();
- for ( ; it != unresolved_agents.endArray(); ++it)
- {
- const LLUUID& agent_id = *it;
+ if (!success)
+ { // on any sort of failure add dummy records for any agent IDs
+ // in this request that we do not have cached already
+ std::vector<LLUUID>::const_iterator it = agentIds.begin();
+ for ( ; it != agentIds.end(); ++it)
+ {
+ const LLUUID& agent_id = *it;
+ LLAvatarNameCache::handleAgentError(agent_id);
+ }
+ return;
+ }
- LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result "
- << "failed id " << agent_id
- << LL_ENDL;
+ LLAvatarNameCache::handleAvNameCacheSuccess(results, httpResults);
- LLAvatarNameCache::handleAgentError(agent_id);
- }
- }
- LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result "
- << LLAvatarNameCache::sCache.size() << " cached names"
- << LL_ENDL;
}
+ catch (std::exception e)
+ {
+ LL_WARNS() << "Caught exception '" << e.what() << "'" << LL_ENDL;
+ }
+ catch (...)
+ {
+ LL_WARNS() << "Caught unknown exception." << LL_ENDL;
+ }
+}
- /*virtual*/ void httpFailure()
- {
- // If there's an error, it might be caused by PeopleApi,
- // or when loading textures on startup and using a very slow
- // network, this query may time out.
- // What we should do depends on whether or not we have a cached name
- LL_WARNS("AvNameCache") << dumpResponse() << LL_ENDL;
-
- // Add dummy records for any agent IDs in this request that we do not have cached already
- std::vector<LLUUID>::const_iterator it = mAgentIDs.begin();
- for ( ; it != mAgentIDs.end(); ++it)
- {
- const LLUUID& agent_id = *it;
- LLAvatarNameCache::handleAgentError(agent_id);
- }
- }
-};
+void LLAvatarNameCache::handleAvNameCacheSuccess(const LLSD &data, const LLSD &httpResult)
+{
+
+ LLSD headers = httpResult["headers"];
+ // Pull expiration out of headers if available
+ F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(headers);
+ F64 now = LLFrameTimer::getTotalSeconds();
+
+ const LLSD& agents = data["agents"];
+ LLSD::array_const_iterator it = agents.beginArray();
+ for (; it != agents.endArray(); ++it)
+ {
+ const LLSD& row = *it;
+ LLUUID agent_id = row["id"].asUUID();
+
+ LLAvatarName av_name;
+ av_name.fromLLSD(row);
+
+ // Use expiration time from header
+ av_name.mExpires = expires;
+
+ LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result for " << agent_id << LL_ENDL;
+ av_name.dump();
+
+ // cache it and fire signals
+ LLAvatarNameCache::processName(agent_id, av_name);
+ }
+
+ // Same logic as error response case
+ const LLSD& unresolved_agents = data["bad_ids"];
+ S32 num_unresolved = unresolved_agents.size();
+ if (num_unresolved > 0)
+ {
+ LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result " << num_unresolved << " unresolved ids; "
+ << "expires in " << expires - now << " seconds"
+ << LL_ENDL;
+ it = unresolved_agents.beginArray();
+ for (; it != unresolved_agents.endArray(); ++it)
+ {
+ const LLUUID& agent_id = *it;
+
+ LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result "
+ << "failed id " << agent_id
+ << LL_ENDL;
+
+ LLAvatarNameCache::handleAgentError(agent_id);
+ }
+ }
+ LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result "
+ << LLAvatarNameCache::sCache.size() << " cached names"
+ << LL_ENDL;
+}
// Provide some fallback for agents that return errors
void LLAvatarNameCache::handleAgentError(const LLUUID& agent_id)
@@ -353,10 +397,15 @@ void LLAvatarNameCache::requestNamesViaCapability()
}
}
- if (!url.empty())
- {
- LL_INFOS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability getting " << ids << " ids" << LL_ENDL;
- LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids));
+ if (!url.empty())
+ {
+ LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability requested " << ids << " ids" << LL_ENDL;
+
+ std::string coroname =
+ LLCoros::instance().launch("LLAvatarNameCache::requestAvatarNameCache_",
+ boost::bind(&LLAvatarNameCache::requestAvatarNameCache_, _1, url, agent_ids));
+ LL_DEBUGS("AvNameCache") << coroname << " with url '" << url << "', agent_ids.size()=" << agent_ids.size() << LL_ENDL;
+
}
}
@@ -419,11 +468,20 @@ void LLAvatarNameCache::initClass(bool running, bool usePeopleAPI)
{
sRunning = running;
sUsePeopleAPI = usePeopleAPI;
+
+ sHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest());
+ sHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders(), false);
+ sHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions(), false);
+ sHttpPolicy = LLCore::HttpRequest::DEFAULT_POLICY_ID;
+ sHttpPriority = 0;
}
void LLAvatarNameCache::cleanupClass()
{
- sCache.clear();
+ sHttpRequest.reset();
+ sHttpHeaders.reset();
+ sHttpOptions.reset();
+ sCache.clear();
}
bool LLAvatarNameCache::importFile(std::istream& istr)
@@ -698,6 +756,50 @@ void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_na
sCache[agent_id] = av_name;
}
+#if 0
+F64 LLAvatarNameCache::nameExpirationFromHeaders(LLCore::HttpHeaders *headers)
+{
+ F64 expires = 0.0;
+ if (expirationFromCacheControl(headers, &expires))
+ {
+ return expires;
+ }
+ else
+ {
+ // With no expiration info, default to an hour
+ const F64 DEFAULT_EXPIRES = 60.0 * 60.0;
+ F64 now = LLFrameTimer::getTotalSeconds();
+ return now + DEFAULT_EXPIRES;
+ }
+}
+
+bool LLAvatarNameCache::expirationFromCacheControl(LLCore::HttpHeaders *headers, F64 *expires)
+{
+ bool fromCacheControl = false;
+ F64 now = LLFrameTimer::getTotalSeconds();
+
+ // Allow the header to override the default
+ const std::string *cache_control;
+
+ cache_control = headers->find(HTTP_IN_HEADER_CACHE_CONTROL);
+
+ if (cache_control && !cache_control->empty())
+ {
+ S32 max_age = 0;
+ if (max_age_from_cache_control(*cache_control, &max_age))
+ {
+ *expires = now + (F64)max_age;
+ fromCacheControl = true;
+ }
+ }
+ LL_DEBUGS("AvNameCache")
+ << ( fromCacheControl ? "expires based on cache control " : "default expiration " )
+ << "in " << *expires - now << " seconds"
+ << LL_ENDL;
+
+ return fromCacheControl;
+}
+#else
F64 LLAvatarNameCache::nameExpirationFromHeaders(const LLSD& headers)
{
F64 expires = 0.0;
@@ -742,7 +844,7 @@ bool LLAvatarNameCache::expirationFromCacheControl(const LLSD& headers, F64 *exp
return fromCacheControl;
}
-
+#endif
void LLAvatarNameCache::addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb)
{
diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h
index 5a10053a69..bd2715e956 100755
--- a/indra/llmessage/llavatarnamecache.h
+++ b/indra/llmessage/llavatarnamecache.h
@@ -29,7 +29,6 @@
#define LLAVATARNAMECACHE_H
#include "llavatarname.h" // for convenience
-
#include <boost/signals2.hpp>
class LLSD;
@@ -49,7 +48,7 @@ namespace LLAvatarNameCache
bool importFile(std::istream& istr);
void exportFile(std::ostream& ostr);
- // On the viewer, usually a simulator capabilitity.
+ // On the viewer, usually a simulator capabilities.
// If empty, name cache will fall back to using legacy name lookup system.
void setNameLookupURL(const std::string& name_lookup_url);
@@ -90,7 +89,7 @@ namespace LLAvatarNameCache
// Compute name expiration time from HTTP Cache-Control header,
// or return default value, in seconds from epoch.
- F64 nameExpirationFromHeaders(const LLSD& headers);
+ F64 nameExpirationFromHeaders(const LLSD& headers);
void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb);
}
diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp
index ee80b0fd94..2d6cca214c 100644
--- a/indra/llmessage/llcorehttputil.cpp
+++ b/indra/llmessage/llcorehttputil.cpp
@@ -30,110 +30,498 @@
#include <sstream>
#include "llcorehttputil.h"
+#include "llhttpconstants.h"
#include "llsdserialize.h"
-
using namespace LLCore;
namespace LLCoreHttpUtil
{
+
+
// *TODO: Currently converts only from XML content. A mode
// to convert using fromBinary() might be useful as well. Mesh
// headers could use it.
bool responseToLLSD(HttpResponse * response, bool log, LLSD & out_llsd)
{
- // Convert response to LLSD
- BufferArray * body(response->getBody());
- if (! body || ! body->size())
- {
- return false;
- }
+ // Convert response to LLSD
+ BufferArray * body(response->getBody());
+ if (!body || !body->size())
+ {
+ return false;
+ }
- LLCore::BufferArrayStream bas(body);
- LLSD body_llsd;
- S32 parse_status(LLSDSerialize::fromXML(body_llsd, bas, log));
- if (LLSDParser::PARSE_FAILURE == parse_status){
- return false;
- }
- out_llsd = body_llsd;
- return true;
+ LLCore::BufferArrayStream bas(body);
+ LLSD body_llsd;
+ S32 parse_status(LLSDSerialize::fromXML(body_llsd, bas, log));
+ if (LLSDParser::PARSE_FAILURE == parse_status){
+ return false;
+ }
+ out_llsd = body_llsd;
+ return true;
}
HttpHandle requestPostWithLLSD(HttpRequest * request,
- HttpRequest::policy_t policy_id,
- HttpRequest::priority_t priority,
- const std::string & url,
- const LLSD & body,
- HttpOptions * options,
- HttpHeaders * headers,
- HttpHandler * handler)
+ HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ const LLSD & body,
+ HttpOptions * options,
+ HttpHeaders * headers,
+ HttpHandler * handler)
+{
+ HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
+
+ BufferArray * ba = new BufferArray();
+ BufferArrayStream bas(ba);
+ LLSDSerialize::toXML(body, bas);
+
+ handle = request->requestPost(policy_id,
+ priority,
+ url,
+ ba,
+ options,
+ headers,
+ handler);
+ ba->release();
+ return handle;
+}
+
+HttpHandle requestPostWithLLSD(HttpRequest::ptr_t & request,
+ HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ const LLSD & body,
+ HttpOptions::ptr_t & options,
+ HttpHeaders::ptr_t & headers,
+ HttpHandler * handler)
+{
+ return requestPostWithLLSD(request.get(), policy_id, priority,
+ url, body, options.get(), headers.get(), handler);
+}
+
+HttpHandle requestPutWithLLSD(HttpRequest * request,
+ HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ const LLSD & body,
+ HttpOptions * options,
+ HttpHeaders * headers,
+ HttpHandler * handler)
+{
+ HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
+
+ BufferArray * ba = new BufferArray();
+ BufferArrayStream bas(ba);
+ LLSDSerialize::toXML(body, bas);
+
+ handle = request->requestPut(policy_id,
+ priority,
+ url,
+ ba,
+ options,
+ headers,
+ handler);
+ ba->release();
+ return handle;
+}
+
+HttpHandle requestPutWithLLSD(HttpRequest::ptr_t & request,
+ HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ const LLSD & body,
+ HttpOptions::ptr_t & options,
+ HttpHeaders::ptr_t & headers,
+ HttpHandler * handler)
{
- HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
+ return requestPutWithLLSD(request.get(), policy_id, priority,
+ url, body, options.get(), headers.get(), handler);
+}
- BufferArray * ba = new BufferArray();
- BufferArrayStream bas(ba);
- LLSDSerialize::toXML(body, bas);
+HttpHandle requestPatchWithLLSD(HttpRequest * request,
+ HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ const LLSD & body,
+ HttpOptions * options,
+ HttpHeaders * headers,
+ HttpHandler * handler)
+{
+ HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
+
+ BufferArray * ba = new BufferArray();
+ BufferArrayStream bas(ba);
+ LLSDSerialize::toXML(body, bas);
+
+ handle = request->requestPatch(policy_id,
+ priority,
+ url,
+ ba,
+ options,
+ headers,
+ handler);
+ ba->release();
+ return handle;
+}
- handle = request->requestPost(policy_id,
- priority,
- url,
- ba,
- options,
- headers,
- handler);
- ba->release();
- return handle;
+HttpHandle requestPatchWithLLSD(HttpRequest::ptr_t & request,
+ HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ const LLSD & body,
+ HttpOptions::ptr_t & options,
+ HttpHeaders::ptr_t & headers,
+ HttpHandler * handler)
+{
+ return requestPatchWithLLSD(request.get(), policy_id, priority,
+ url, body, options.get(), headers.get(), handler);
}
std::string responseToString(LLCore::HttpResponse * response)
{
- static const std::string empty("[Empty]");
-
- if (! response)
- {
- return empty;
- }
-
- BufferArray * body(response->getBody());
- if (! body || ! body->size())
- {
- return empty;
- }
-
- // Attempt to parse as LLSD regardless of content-type
- LLSD body_llsd;
- if (responseToLLSD(response, false, body_llsd))
- {
- std::ostringstream tmp;
-
- LLSDSerialize::toPrettyNotation(body_llsd, tmp);
- std::size_t temp_len(tmp.tellp());
-
- if (temp_len)
- {
- return tmp.str().substr(0, std::min(temp_len, std::size_t(1024)));
- }
- }
- else
- {
- // *TODO: More elaborate forms based on Content-Type as needed.
- char content[1024];
-
- size_t len(body->read(0, content, sizeof(content)));
- if (len)
- {
- return std::string(content, 0, len);
- }
- }
-
- // Default
- return empty;
+ static const std::string empty("[Empty]");
+
+ if (!response)
+ {
+ return empty;
+ }
+
+ BufferArray * body(response->getBody());
+ if (!body || !body->size())
+ {
+ return empty;
+ }
+
+ // Attempt to parse as LLSD regardless of content-type
+ LLSD body_llsd;
+ if (responseToLLSD(response, false, body_llsd))
+ {
+ std::ostringstream tmp;
+
+ LLSDSerialize::toPrettyNotation(body_llsd, tmp);
+ std::size_t temp_len(tmp.tellp());
+
+ if (temp_len)
+ {
+ return tmp.str().substr(0, std::min(temp_len, std::size_t(1024)));
+ }
+ }
+ else
+ {
+ // *TODO: More elaborate forms based on Content-Type as needed.
+ char content[1024];
+
+ size_t len(body->read(0, content, sizeof(content)));
+ if (len)
+ {
+ return std::string(content, 0, len);
+ }
+ }
+
+ // Default
+ return empty;
+}
+
+//========================================================================
+HttpCoroHandler::HttpCoroHandler(LLEventStream &reply) :
+ mReplyPump(reply)
+{
}
+void HttpCoroHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response)
+{
+ LLSD result;
+
+ LLCore::HttpStatus status = response->getStatus();
+
+ if (status == LLCore::HttpStatus(LLCore::HttpStatus::LLCORE, LLCore::HE_HANDLE_NOT_FOUND))
+ { // A response came in for a canceled request and we have not processed the
+ // cancel yet. Patience!
+ return;
+ }
+
+ if (!status)
+ {
+ result = LLSD::emptyMap();
+ LL_WARNS()
+ << "\n--------------------------------------------------------------------------\n"
+ << " Error[" << status.toULong() << "] cannot access url '" << response->getRequestURL()
+ << "' because " << status.toString()
+ << "\n--------------------------------------------------------------------------"
+ << LL_ENDL;
+
+ }
+ else
+ {
+ const bool emit_parse_errors = false;
+
+ bool parsed = !((response->getBodySize() == 0) ||
+ !LLCoreHttpUtil::responseToLLSD(response, emit_parse_errors, result));
+
+ if (!parsed)
+ {
+ // Only emit a warning if we failed to parse when 'content-type' == 'application/llsd+xml'
+ LLCore::HttpHeaders::ptr_t headers(response->getHeaders());
+ const std::string *contentType = (headers) ? headers->find(HTTP_IN_HEADER_CONTENT_TYPE) : NULL;
+
+ if (contentType && (HTTP_CONTENT_LLSD_XML == *contentType))
+ {
+ std::string thebody = LLCoreHttpUtil::responseToString(response);
+ LL_WARNS() << "Failed to deserialize . " << response->getRequestURL() << " [status:" << response->getStatus().toString() << "] "
+ << " body: " << thebody << LL_ENDL;
+
+ // Replace the status with a new one indicating the failure.
+ status = LLCore::HttpStatus(499, "Failed to deserialize LLSD.");
+ }
+ }
+
+ if (result.isUndefined())
+ { // If we've gotten to this point and the result LLSD is still undefined
+ // either there was an issue deserializing the body or the response was
+ // blank. Create an empty map to hold the result either way.
+ result = LLSD::emptyMap();
+ }
+ else if (!result.isMap())
+ { // The results are not themselves a map. Move them down so that
+ // this method can return a map to the caller.
+ // *TODO: Should it always do this?
+ LLSD newResult = LLSD::emptyMap();
+ newResult["content"] = result;
+ result = newResult;
+ }
+ }
+
+ buildStatusEntry(response, status, result);
+ mReplyPump.post(result);
+}
+
+void HttpCoroHandler::buildStatusEntry(LLCore::HttpResponse *response, LLCore::HttpStatus status, LLSD &result)
+{
+ LLSD httpresults = LLSD::emptyMap();
+
+ writeStatusCodes(status, response->getRequestURL(), httpresults);
+ // httpresults["success"] = static_cast<LLSD::Boolean>(status);
+ // httpresults["type"] = static_cast<LLSD::Integer>(status.getType());
+ // httpresults["status"] = static_cast<LLSD::Integer>(status.getStatus());
+ // httpresults["message"] = static_cast<LLSD::String>(status.getMessage());
+ // httpresults["url"] = static_cast<LLSD::String>(response->getRequestURL());
+
+ LLSD httpHeaders = LLSD::emptyMap();
+ LLCore::HttpHeaders * hdrs = response->getHeaders();
+
+ if (hdrs)
+ {
+ for (LLCore::HttpHeaders::iterator it = hdrs->begin(); it != hdrs->end(); ++it)
+ {
+ if (!(*it).second.empty())
+ {
+ httpHeaders[(*it).first] = (*it).second;
+ }
+ else
+ {
+ httpHeaders[(*it).first] = static_cast<LLSD::Boolean>(true);
+ }
+ }
+ }
+
+ httpresults["headers"] = httpHeaders;
+ result["http_result"] = httpresults;
+}
+
+void HttpCoroHandler::writeStatusCodes(LLCore::HttpStatus status, const std::string &url, LLSD &result)
+{
+ result["success"] = static_cast<LLSD::Boolean>(status);
+ result["type"] = static_cast<LLSD::Integer>(status.getType());
+ result["status"] = static_cast<LLSD::Integer>(status.getStatus());
+ result["message"] = static_cast<LLSD::String>(status.getMessage());
+ result["url"] = static_cast<LLSD::String>(url);
+
+}
+
+LLCore::HttpStatus HttpCoroHandler::getStatusFromLLSD(const LLSD &httpResults)
+{
+ LLCore::HttpStatus::type_enum_t type = static_cast<LLCore::HttpStatus::type_enum_t>(httpResults["type"].asInteger());
+ short code = static_cast<short>(httpResults["status"].asInteger());
+
+ return LLCore::HttpStatus(type, code);
+}
+
+//========================================================================
+HttpRequestPumper::HttpRequestPumper(const LLCore::HttpRequest::ptr_t &request) :
+ mHttpRequest(request)
+{
+ mBoundListener = LLEventPumps::instance().obtain("mainloop").
+ listen(LLEventPump::inventName(), boost::bind(&HttpRequestPumper::pollRequest, this, _1));
+}
+
+HttpRequestPumper::~HttpRequestPumper()
+{
+ if (mBoundListener.connected())
+ {
+ mBoundListener.disconnect();
+ }
+}
+
+bool HttpRequestPumper::pollRequest(const LLSD&)
+{
+ if (mHttpRequest->getStatus() != HttpStatus(HttpStatus::LLCORE, HE_OP_CANCELED))
+ {
+ mHttpRequest->update(0L);
+ }
+ return false;
+}
+
+//========================================================================
+HttpCoroutineAdapter::HttpCoroutineAdapter(const std::string &name,
+ LLCore::HttpRequest::policy_t policyId, LLCore::HttpRequest::priority_t priority) :
+ mAdapterName(name),
+ mPolicyId(policyId),
+ mPriority(priority),
+ mYieldingHandle(LLCORE_HTTP_HANDLE_INVALID),
+ mWeakRequest(),
+ mWeakHandler()
+{
+}
+
+HttpCoroutineAdapter::~HttpCoroutineAdapter()
+{
+ cancelYieldingOperation();
+}
+
+LLSD HttpCoroutineAdapter::postAndYield(LLCoros::self & self, LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+ LLEventStream replyPump(mAdapterName, true);
+ LLCoreHttpUtil::HttpCoroHandler::ptr_t httpHandler =
+ LLCoreHttpUtil::HttpCoroHandler::ptr_t(new LLCoreHttpUtil::HttpCoroHandler(replyPump));
+
+ //LL_INFOS() << "Requesting transaction " << transactionId << LL_ENDL;
+ LLCoreHttpUtil::HttpRequestPumper pumper(request);
+ // The HTTPCoroHandler does not self delete, so retrieval of a the contained
+ // pointer from the smart pointer is safe in this case.
+ LLCore::HttpHandle hhandle = requestPostWithLLSD(request,
+ mPolicyId, mPriority, url, body, options, headers,
+ httpHandler.get());
+
+ if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ return HttpCoroutineAdapter::buildImmediateErrorResult(request, url);
+ }
+
+ saveState(hhandle, request, httpHandler);
+ LLSD results = waitForEventOn(self, replyPump);
+ cleanState();
+
+ //LL_INFOS() << "Results for transaction " << transactionId << LL_ENDL;
+ return results;
+}
+
+LLSD HttpCoroutineAdapter::putAndYield(LLCoros::self & self, LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+ LLEventStream replyPump(mAdapterName, true);
+ LLCoreHttpUtil::HttpCoroHandler::ptr_t httpHandler =
+ LLCoreHttpUtil::HttpCoroHandler::ptr_t(new LLCoreHttpUtil::HttpCoroHandler(replyPump));
+
+ //LL_INFOS() << "Requesting transaction " << transactionId << LL_ENDL;
+ LLCoreHttpUtil::HttpRequestPumper pumper(request);
+ // The HTTPCoroHandler does not self delete, so retrieval of a the contained
+ // pointer from the smart pointer is safe in this case.
+ LLCore::HttpHandle hhandle = requestPutWithLLSD(request,
+ mPolicyId, mPriority, url, body, options, headers,
+ httpHandler.get());
+
+ if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ return HttpCoroutineAdapter::buildImmediateErrorResult(request, url);
+ }
+
+ saveState(hhandle, request, httpHandler);
+ LLSD results = waitForEventOn(self, replyPump);
+ cleanState();
+ //LL_INFOS() << "Results for transaction " << transactionId << LL_ENDL;
+ return results;
+}
+
+LLSD HttpCoroutineAdapter::getAndYield(LLCoros::self & self, LLCore::HttpRequest::ptr_t request,
+ const std::string & url,
+ LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+ LLEventStream replyPump(mAdapterName + "Reply", true);
+ LLCoreHttpUtil::HttpCoroHandler::ptr_t httpHandler =
+ LLCoreHttpUtil::HttpCoroHandler::ptr_t(new LLCoreHttpUtil::HttpCoroHandler(replyPump));
+
+ //LL_INFOS() << "Requesting transaction " << transactionId << LL_ENDL;
+ LLCoreHttpUtil::HttpRequestPumper pumper(request);
+ // The HTTPCoroHandler does not self delete, so retrieval of a the contained
+ // pointer from the smart pointer is safe in this case.
+ LLCore::HttpHandle hhandle = request->requestGet(mPolicyId, mPriority,
+ url, options.get(), headers.get(), httpHandler.get());
+
+ if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ return HttpCoroutineAdapter::buildImmediateErrorResult(request, url);
+ }
+
+ saveState(hhandle, request, httpHandler);
+ LLSD results = waitForEventOn(self, replyPump);
+ cleanState();
+ //LL_INFOS() << "Results for transaction " << transactionId << LL_ENDL;
+ return results;
+}
+
+void HttpCoroutineAdapter::cancelYieldingOperation()
+{
+ LLCore::HttpRequest::ptr_t request = mWeakRequest.lock();
+ HttpCoroHandler::ptr_t handler = mWeakHandler.lock();
+ if ((request) && (handler) && (mYieldingHandle != LLCORE_HTTP_HANDLE_INVALID))
+ {
+ cleanState();
+ LL_INFOS() << "Canceling yielding request!" << LL_ENDL;
+ request->requestCancel(mYieldingHandle, handler.get());
+ }
+}
+
+void HttpCoroutineAdapter::saveState(LLCore::HttpHandle yieldingHandle,
+ LLCore::HttpRequest::ptr_t &request, HttpCoroHandler::ptr_t &handler)
+{
+ mWeakRequest = request;
+ mWeakHandler = handler;
+ mYieldingHandle = yieldingHandle;
+}
+
+void HttpCoroutineAdapter::cleanState()
+{
+ mWeakRequest.reset();
+ mWeakHandler.reset();
+ mYieldingHandle = LLCORE_HTTP_HANDLE_INVALID;
+}
+
+LLSD HttpCoroutineAdapter::buildImmediateErrorResult(const LLCore::HttpRequest::ptr_t &request,
+ const std::string &url)
+{
+ LLCore::HttpStatus status = request->getStatus();
+ LL_WARNS() << "Error posting to " << url << " Status=" << status.getStatus() <<
+ " message = " << status.getMessage() << LL_ENDL;
+
+ // Mimic the status results returned from an http error that we had
+ // to wait on
+ LLSD httpresults = LLSD::emptyMap();
+
+ HttpCoroHandler::writeStatusCodes(status, url, httpresults);
+
+ LLSD errorres = LLSD::emptyMap();
+ errorres["http_result"] = httpresults;
+
+ return errorres;
+}
} // end namespace LLCoreHttpUtil
diff --git a/indra/llmessage/llcorehttputil.h b/indra/llmessage/llcorehttputil.h
index d40172bc7a..6fcf03b95c 100644
--- a/indra/llmessage/llcorehttputil.h
+++ b/indra/llmessage/llcorehttputil.h
@@ -39,6 +39,9 @@
#include "bufferarray.h"
#include "bufferstream.h"
#include "llsd.h"
+#include "llevents.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
///
/// The base llcorehttp library implements many HTTP idioms
@@ -109,7 +112,202 @@ LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest * request,
LLCore::HttpHeaders * headers,
LLCore::HttpHandler * handler);
-} // end namespace LLCoreHttpUtil
+LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest::ptr_t & request,
+ LLCore::HttpRequest::policy_t policy_id,
+ LLCore::HttpRequest::priority_t priority,
+ const std::string & url,
+ const LLSD & body,
+ LLCore::HttpOptions::ptr_t & options,
+ LLCore::HttpHeaders::ptr_t & headers,
+ LLCore::HttpHandler * handler);
+
+/// Issue a standard HttpRequest::requestPut() call but using
+/// and LLSD object as the request body. Conventions are the
+/// same as with that method. Caller is expected to provide
+/// an HttpHeaders object with a correct 'Content-Type:' header.
+/// One will not be provided by this call.
+///
+/// @return If request is successfully issued, the
+/// HttpHandle representing the request.
+/// On error, LLCORE_HTTP_HANDLE_INVALID
+/// is returned and caller can fetch detailed
+/// status with the getStatus() method on the
+/// request object. In case of error, no
+/// request is queued and caller may need to
+/// perform additional cleanup such as freeing
+/// a now-useless HttpHandler object.
+///
+LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest * request,
+ LLCore::HttpRequest::policy_t policy_id,
+ LLCore::HttpRequest::priority_t priority,
+ const std::string & url,
+ const LLSD & body,
+ LLCore::HttpOptions * options,
+ LLCore::HttpHeaders * headers,
+ LLCore::HttpHandler * handler);
+
+LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest::ptr_t & request,
+ LLCore::HttpRequest::policy_t policy_id,
+ LLCore::HttpRequest::priority_t priority,
+ const std::string & url,
+ const LLSD & body,
+ LLCore::HttpOptions::ptr_t & options,
+ LLCore::HttpHeaders::ptr_t & headers,
+ LLCore::HttpHandler * handler);
+/// Issue a standard HttpRequest::requestPatch() call but using
+/// and LLSD object as the request body. Conventions are the
+/// same as with that method. Caller is expected to provide
+/// an HttpHeaders object with a correct 'Content-Type:' header.
+/// One will not be provided by this call.
+///
+/// @return If request is successfully issued, the
+/// HttpHandle representing the request.
+/// On error, LLCORE_HTTP_HANDLE_INVALID
+/// is returned and caller can fetch detailed
+/// status with the getStatus() method on the
+/// request object. In case of error, no
+/// request is queued and caller may need to
+/// perform additional cleanup such as freeing
+/// a now-useless HttpHandler object.
+///
+LLCore::HttpHandle requestPatchWithLLSD(LLCore::HttpRequest * request,
+ LLCore::HttpRequest::policy_t policy_id,
+ LLCore::HttpRequest::priority_t priority,
+ const std::string & url,
+ const LLSD & body,
+ LLCore::HttpOptions * options,
+ LLCore::HttpHeaders * headers,
+ LLCore::HttpHandler * handler);
+
+LLCore::HttpHandle requestPatchWithLLSD(LLCore::HttpRequest::ptr_t & request,
+ LLCore::HttpRequest::policy_t policy_id,
+ LLCore::HttpRequest::priority_t priority,
+ const std::string & url,
+ const LLSD & body,
+ LLCore::HttpOptions::ptr_t & options,
+ LLCore::HttpHeaders::ptr_t & headers,
+ LLCore::HttpHandler * handler);
+
+
+/// The HttpCoroHandler is a specialization of the LLCore::HttpHandler for
+/// interacting with coroutines. When the request is completed the response
+/// will be posted onto the supplied Event Pump.
+///
+/// The LLSD posted back to the coroutine will have the following additions:
+/// llsd["http_result"] -+- ["message"] - An error message returned from the HTTP status
+/// +- ["status"] - The status code associated with the HTTP call
+/// +- ["success"] - Success of failure of the HTTP call and LLSD parsing.
+/// +- ["type"] - The LLCore::HttpStatus type associted with the HTTP call
+/// +- ["url"] - The URL used to make the call.
+/// +- ["headers"] - A map of name name value pairs with the HTTP headers.
+///
+class HttpCoroHandler : public LLCore::HttpHandler
+{
+public:
+ typedef boost::shared_ptr<HttpCoroHandler> ptr_t;
+ typedef boost::weak_ptr<HttpCoroHandler> wptr_t;
+
+ HttpCoroHandler(LLEventStream &reply);
+
+ virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
+
+ static void writeStatusCodes(LLCore::HttpStatus status, const std::string &url, LLSD &result);
+ static LLCore::HttpStatus getStatusFromLLSD(const LLSD &httpResults);
+
+private:
+ void buildStatusEntry(LLCore::HttpResponse *response, LLCore::HttpStatus status, LLSD &result);
+
+ LLEventStream &mReplyPump;
+};
+
+/// The HttpRequestPumper is a utility class. When constructed it will poll the
+/// supplied HttpRequest once per frame until it is destroyed.
+///
+class HttpRequestPumper
+{
+public:
+ HttpRequestPumper(const LLCore::HttpRequest::ptr_t &request);
+ ~HttpRequestPumper();
+
+private:
+ bool pollRequest(const LLSD&);
+
+ LLTempBoundListener mBoundListener;
+ LLCore::HttpRequest::ptr_t mHttpRequest;
+};
+
+/// An adapter to handle some of the boilerplate code surrounding HTTP and coroutine
+/// interaction.
+///
+/// Construct an HttpCoroutineAdapter giving it a name and policy Id. After
+/// any application specific setup call the post, put or get method. The request
+/// will be automatically pumped and the method will return with an LLSD describing
+/// the result of the operation. See HttpCoroHandler for a description of the
+/// decoration done to the returned LLSD.
+class HttpCoroutineAdapter
+{
+public:
+ typedef boost::shared_ptr<HttpCoroutineAdapter> ptr_t;
+ typedef boost::weak_ptr<HttpCoroutineAdapter> wptr_t;
+
+ HttpCoroutineAdapter(const std::string &name, LLCore::HttpRequest::policy_t policyId,
+ LLCore::HttpRequest::priority_t priority = 0L);
+ ~HttpCoroutineAdapter();
+
+ /// Execute a Post transaction on the supplied URL and yield execution of
+ /// the coroutine until a result is available.
+ ///
+ /// @Note: the request's smart pointer is passed by value so that it will
+ /// not be deallocated during the yield.
+ LLSD postAndYield(LLCoros::self & self, LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions(), false),
+ LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders(), false));
+
+ /// Execute a Put transaction on the supplied URL and yield execution of
+ /// the coroutine until a result is available.
+ ///
+ /// @Note: the request's smart pointer is passed by value so that it will
+ /// not be deallocated during the yield.
+ LLSD putAndYield(LLCoros::self & self, LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions(), false),
+ LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders(), false));
+
+ /// Execute a Get transaction on the supplied URL and yield execution of
+ /// the coroutine until a result is available.
+ ///
+ /// @Note: the request's smart pointer is passed by value so that it will
+ /// not be deallocated during the yield.
+ LLSD getAndYield(LLCoros::self & self, LLCore::HttpRequest::ptr_t request,
+ const std::string & url,
+ LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions(), false),
+ LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders(), false));
+
+ ///
+ void cancelYieldingOperation();
+
+private:
+ static LLSD buildImmediateErrorResult(const LLCore::HttpRequest::ptr_t &request, const std::string &url);
+
+ void saveState(LLCore::HttpHandle yieldingHandle, LLCore::HttpRequest::ptr_t &request,
+ HttpCoroHandler::ptr_t &handler);
+ void cleanState();
+
+
+ std::string mAdapterName;
+ LLCore::HttpRequest::priority_t mPriority;
+ LLCore::HttpRequest::policy_t mPolicyId;
+
+ LLCore::HttpHandle mYieldingHandle;
+ LLCore::HttpRequest::wptr_t mWeakRequest;
+ HttpCoroHandler::wptr_t mWeakHandler;
+};
+
+//-------------------------------------------------------------------------
+LLCore::HttpStatus getStatusFromLLSD(const LLSD &httpResults);
+
+} // end namespace LLCoreHttpUtil
#endif // LL_LLCOREHTTPUTIL_H
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
index 73df47b933..ef28a4d211 100755
--- a/indra/llmessage/llcurl.cpp
+++ b/indra/llmessage/llcurl.cpp
@@ -69,13 +69,15 @@
do this.
*/
+// *TODO: TSN remove the commented code from this file
//////////////////////////////////////////////////////////////////////////////
static const U32 EASY_HANDLE_POOL_SIZE = 5;
static const S32 MULTI_PERFORM_CALL_REPEAT = 5;
static const S32 CURL_REQUEST_TIMEOUT = 120; // seconds per operation
static const S32 CURL_CONNECT_TIMEOUT = 30; //seconds to wait for a connection
-static const S32 MAX_ACTIVE_REQUEST_COUNT = 100;
+
+//static const S32 MAX_ACTIVE_REQUEST_COUNT = 100;
// DEBUG //
S32 gCurlEasyCount = 0;
@@ -676,6 +678,7 @@ void LLCurl::Easy::prepRequest(const std::string& url,
}
////////////////////////////////////////////////////////////////////////////
+#if 1
LLCurl::Multi::Multi(F32 idle_time_out)
: mQueued(0),
mErrorCount(0),
@@ -1056,6 +1059,7 @@ void LLCurl::Multi::removeEasy(Easy* easy)
easyFree(easy);
}
+#endif
//------------------------------------------------------------
//LLCurlThread
LLCurlThread::CurlRequest::CurlRequest(handle_t handle, LLCurl::Multi* multi, LLCurlThread* curl_thread) :
@@ -1176,428 +1180,428 @@ std::string LLCurl::strerror(CURLcode errorcode)
// For generating a simple request for data
// using one multi and one easy per request
-LLCurlRequest::LLCurlRequest() :
- mActiveMulti(NULL),
- mActiveRequestCount(0)
-{
- mProcessing = FALSE;
-}
-
-LLCurlRequest::~LLCurlRequest()
-{
- //stop all Multi handle background threads
- for (curlmulti_set_t::iterator iter = mMultiSet.begin(); iter != mMultiSet.end(); ++iter)
- {
- LLCurl::getCurlThread()->killMulti(*iter) ;
- }
- mMultiSet.clear() ;
-}
-
-void LLCurlRequest::addMulti()
-{
- LLCurl::Multi* multi = new LLCurl::Multi();
- if(!multi->isValid())
- {
- LLCurl::getCurlThread()->killMulti(multi) ;
- mActiveMulti = NULL ;
- mActiveRequestCount = 0 ;
- return;
- }
-
- mMultiSet.insert(multi);
- mActiveMulti = multi;
- mActiveRequestCount = 0;
-}
-
-LLCurl::Easy* LLCurlRequest::allocEasy()
-{
- if (!mActiveMulti ||
- mActiveRequestCount >= MAX_ACTIVE_REQUEST_COUNT ||
- mActiveMulti->mErrorCount > 0)
- {
- addMulti();
- }
- if(!mActiveMulti)
- {
- return NULL ;
- }
-
- //llassert_always(mActiveMulti);
- ++mActiveRequestCount;
- LLCurl::Easy* easy = mActiveMulti->allocEasy();
- return easy;
-}
-
-bool LLCurlRequest::addEasy(LLCurl::Easy* easy)
-{
- llassert_always(mActiveMulti);
-
- if (mProcessing)
- {
- LL_ERRS() << "Posting to a LLCurlRequest instance from within a responder is not allowed (causes DNS timeouts)." << LL_ENDL;
- }
- bool res = mActiveMulti->addEasy(easy);
- return res;
-}
-
-void LLCurlRequest::get(const std::string& url, LLCurl::ResponderPtr responder)
-{
- getByteRange(url, headers_t(), 0, -1, responder);
-}
-
-// Note: (length==0) is interpreted as "the rest of the file", i.e. the whole file if (offset==0) or
-// the remainder of the file if not.
-bool LLCurlRequest::getByteRange(const std::string& url,
- const headers_t& headers,
- S32 offset, S32 length,
- LLCurl::ResponderPtr responder)
-{
- llassert(LLCurl::sNotQuitting);
- LLCurl::Easy* easy = allocEasy();
- if (!easy)
- {
- return false;
- }
- easy->prepRequest(url, headers, responder);
- easy->setopt(CURLOPT_HTTPGET, 1);
- if (length > 0)
- {
- std::string range = llformat("bytes=%d-%d", offset,offset+length-1);
- easy->slist_append(HTTP_OUT_HEADER_RANGE, range);
- }
- else if (offset > 0)
- {
- std::string range = llformat("bytes=%d-", offset);
- easy->slist_append(HTTP_OUT_HEADER_RANGE, range);
- }
- easy->setHeaders();
- bool res = addEasy(easy);
- return res;
-}
-
-bool LLCurlRequest::post(const std::string& url,
- const headers_t& headers,
- const LLSD& data,
- LLCurl::ResponderPtr responder, S32 time_out)
-{
- llassert(LLCurl::sNotQuitting);
- LLCurl::Easy* easy = allocEasy();
- if (!easy)
- {
- return false;
- }
- easy->prepRequest(url, headers, responder, time_out);
-
- LLSDSerialize::toXML(data, easy->getInput());
- S32 bytes = easy->getInput().str().length();
-
- easy->setopt(CURLOPT_POST, 1);
- easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
- easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
-
- easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML);
- easy->setHeaders();
-
- LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL;
- bool res = addEasy(easy);
- return res;
-}
-
-bool LLCurlRequest::post(const std::string& url,
- const headers_t& headers,
- const std::string& data,
- LLCurl::ResponderPtr responder, S32 time_out)
-{
- llassert(LLCurl::sNotQuitting);
- LLCurl::Easy* easy = allocEasy();
- if (!easy)
- {
- return false;
- }
- easy->prepRequest(url, headers, responder, time_out);
-
- easy->getInput().write(data.data(), data.size());
- S32 bytes = easy->getInput().str().length();
-
- easy->setopt(CURLOPT_POST, 1);
- easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
- easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
-
- easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_OCTET_STREAM);
- easy->setHeaders();
-
- LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL;
- bool res = addEasy(easy);
- return res;
-}
-
-// Note: call once per frame
-S32 LLCurlRequest::process()
-{
- S32 res = 0;
-
- mProcessing = TRUE;
- for (curlmulti_set_t::iterator iter = mMultiSet.begin();
- iter != mMultiSet.end(); )
- {
- curlmulti_set_t::iterator curiter = iter++;
- LLCurl::Multi* multi = *curiter;
-
- if(!multi->isValid())
- {
- if(multi == mActiveMulti)
- {
- mActiveMulti = NULL ;
- mActiveRequestCount = 0 ;
- }
- mMultiSet.erase(curiter) ;
- LLCurl::getCurlThread()->killMulti(multi) ;
- continue ;
- }
-
- S32 tres = multi->process();
- res += tres;
- if (multi != mActiveMulti && tres == 0 && multi->mQueued == 0)
- {
- mMultiSet.erase(curiter);
- LLCurl::getCurlThread()->killMulti(multi);
- }
- }
- mProcessing = FALSE;
- return res;
-}
-
-S32 LLCurlRequest::getQueued()
-{
- S32 queued = 0;
- for (curlmulti_set_t::iterator iter = mMultiSet.begin();
- iter != mMultiSet.end(); )
- {
- curlmulti_set_t::iterator curiter = iter++;
- LLCurl::Multi* multi = *curiter;
-
- if(!multi->isValid())
- {
- if(multi == mActiveMulti)
- {
- mActiveMulti = NULL ;
- mActiveRequestCount = 0 ;
- }
- LLCurl::getCurlThread()->killMulti(multi);
- mMultiSet.erase(curiter) ;
- continue ;
- }
-
- queued += multi->mQueued;
- if (multi->getState() != LLCurl::Multi::STATE_READY)
- {
- ++queued;
- }
- }
- return queued;
-}
-
-LLCurlTextureRequest::LLCurlTextureRequest(S32 concurrency) :
- LLCurlRequest(),
- mConcurrency(concurrency),
- mInQueue(0),
- mMutex(NULL),
- mHandleCounter(1),
- mTotalIssuedRequests(0),
- mTotalReceivedBits(0)
-{
- mGlobalTimer.reset();
-}
-
-LLCurlTextureRequest::~LLCurlTextureRequest()
-{
- mRequestMap.clear();
-
- for(req_queue_t::iterator iter = mCachedRequests.begin(); iter != mCachedRequests.end(); ++iter)
- {
- delete *iter;
- }
- mCachedRequests.clear();
-}
-
-//return 0: success
-// > 0: cached handle
-U32 LLCurlTextureRequest::getByteRange(const std::string& url,
- const headers_t& headers,
- S32 offset, S32 length, U32 pri,
- LLCurl::ResponderPtr responder, F32 delay_time)
-{
- U32 ret_val = 0;
- bool success = false;
-
- if(mInQueue < mConcurrency && delay_time < 0.f)
- {
- success = LLCurlRequest::getByteRange(url, headers, offset, length, responder);
- }
-
- LLMutexLock lock(&mMutex);
-
- if(success)
- {
- mInQueue++;
- mTotalIssuedRequests++;
- }
- else
- {
- request_t* request = new request_t(mHandleCounter, url, headers, offset, length, pri, responder);
- if(delay_time > 0.f)
- {
- request->mStartTime = mGlobalTimer.getElapsedTimeF32() + delay_time;
- }
-
- mCachedRequests.insert(request);
- mRequestMap[mHandleCounter] = request;
- ret_val = mHandleCounter;
- mHandleCounter++;
-
- if(!mHandleCounter)
- {
- mHandleCounter = 1;
- }
- }
-
- return ret_val;
-}
-
-void LLCurlTextureRequest::completeRequest(S32 received_bytes)
-{
- LLMutexLock lock(&mMutex);
-
- llassert_always(mInQueue > 0);
-
- mInQueue--;
- mTotalReceivedBits += received_bytes * 8;
-}
-
-void LLCurlTextureRequest::nextRequests()
-{
- if(mCachedRequests.empty() || mInQueue >= mConcurrency)
- {
- return;
- }
-
- F32 cur_time = mGlobalTimer.getElapsedTimeF32();
-
- req_queue_t::iterator iter;
- {
- LLMutexLock lock(&mMutex);
- iter = mCachedRequests.begin();
- }
- while(1)
- {
- request_t* request = *iter;
- if(request->mStartTime < cur_time)
- {
- if(!LLCurlRequest::getByteRange(request->mUrl, request->mHeaders, request->mOffset, request->mLength, request->mResponder))
- {
- break;
- }
-
- LLMutexLock lock(&mMutex);
- ++iter;
- mInQueue++;
- mTotalIssuedRequests++;
- mCachedRequests.erase(request);
- mRequestMap.erase(request->mHandle);
- delete request;
-
- if(iter == mCachedRequests.end() || mInQueue >= mConcurrency)
- {
- break;
- }
- }
- else
- {
- LLMutexLock lock(&mMutex);
- ++iter;
- if(iter == mCachedRequests.end() || mInQueue >= mConcurrency)
- {
- break;
- }
- }
- }
-
- return;
-}
-
-void LLCurlTextureRequest::updatePriority(U32 handle, U32 pri)
-{
- if(!handle)
- {
- return;
- }
-
- LLMutexLock lock(&mMutex);
-
- std::map<S32, request_t*>::iterator iter = mRequestMap.find(handle);
- if(iter != mRequestMap.end())
- {
- request_t* req = iter->second;
-
- if(req->mPriority != pri)
- {
- mCachedRequests.erase(req);
- req->mPriority = pri;
- mCachedRequests.insert(req);
- }
- }
-}
-
-void LLCurlTextureRequest::removeRequest(U32 handle)
-{
- if(!handle)
- {
- return;
- }
-
- LLMutexLock lock(&mMutex);
-
- std::map<S32, request_t*>::iterator iter = mRequestMap.find(handle);
- if(iter != mRequestMap.end())
- {
- request_t* req = iter->second;
- mRequestMap.erase(iter);
- mCachedRequests.erase(req);
- delete req;
- }
-}
-
-bool LLCurlTextureRequest::isWaiting(U32 handle)
-{
- if(!handle)
- {
- return false;
- }
-
- LLMutexLock lock(&mMutex);
- return mRequestMap.find(handle) != mRequestMap.end();
-}
-
-U32 LLCurlTextureRequest::getTotalReceivedBits()
-{
- LLMutexLock lock(&mMutex);
-
- U32 bits = mTotalReceivedBits;
- mTotalReceivedBits = 0;
- return bits;
-}
-
-U32 LLCurlTextureRequest::getTotalIssuedRequests()
-{
- LLMutexLock lock(&mMutex);
- return mTotalIssuedRequests;
-}
-
-S32 LLCurlTextureRequest::getNumRequests()
-{
- LLMutexLock lock(&mMutex);
- return mInQueue;
-}
+// LLCurlRequest::LLCurlRequest() :
+// mActiveMulti(NULL),
+// mActiveRequestCount(0)
+// {
+// mProcessing = FALSE;
+// }
+//
+// LLCurlRequest::~LLCurlRequest()
+// {
+// //stop all Multi handle background threads
+// for (curlmulti_set_t::iterator iter = mMultiSet.begin(); iter != mMultiSet.end(); ++iter)
+// {
+// LLCurl::getCurlThread()->killMulti(*iter) ;
+// }
+// mMultiSet.clear() ;
+// }
+//
+// void LLCurlRequest::addMulti()
+// {
+// LLCurl::Multi* multi = new LLCurl::Multi();
+// if(!multi->isValid())
+// {
+// LLCurl::getCurlThread()->killMulti(multi) ;
+// mActiveMulti = NULL ;
+// mActiveRequestCount = 0 ;
+// return;
+// }
+//
+// mMultiSet.insert(multi);
+// mActiveMulti = multi;
+// mActiveRequestCount = 0;
+// }
+//
+// LLCurl::Easy* LLCurlRequest::allocEasy()
+// {
+// if (!mActiveMulti ||
+// mActiveRequestCount >= MAX_ACTIVE_REQUEST_COUNT ||
+// mActiveMulti->mErrorCount > 0)
+// {
+// addMulti();
+// }
+// if(!mActiveMulti)
+// {
+// return NULL ;
+// }
+//
+// //llassert_always(mActiveMulti);
+// ++mActiveRequestCount;
+// LLCurl::Easy* easy = mActiveMulti->allocEasy();
+// return easy;
+// }
+//
+// bool LLCurlRequest::addEasy(LLCurl::Easy* easy)
+// {
+// llassert_always(mActiveMulti);
+//
+// if (mProcessing)
+// {
+// LL_ERRS() << "Posting to a LLCurlRequest instance from within a responder is not allowed (causes DNS timeouts)." << LL_ENDL;
+// }
+// bool res = mActiveMulti->addEasy(easy);
+// return res;
+// }
+//
+// void LLCurlRequest::get(const std::string& url, LLCurl::ResponderPtr responder)
+// {
+// getByteRange(url, headers_t(), 0, -1, responder);
+// }
+//
+// // Note: (length==0) is interpreted as "the rest of the file", i.e. the whole file if (offset==0) or
+// // the remainder of the file if not.
+// bool LLCurlRequest::getByteRange(const std::string& url,
+// const headers_t& headers,
+// S32 offset, S32 length,
+// LLCurl::ResponderPtr responder)
+// {
+// llassert(LLCurl::sNotQuitting);
+// LLCurl::Easy* easy = allocEasy();
+// if (!easy)
+// {
+// return false;
+// }
+// easy->prepRequest(url, headers, responder);
+// easy->setopt(CURLOPT_HTTPGET, 1);
+// if (length > 0)
+// {
+// std::string range = llformat("bytes=%d-%d", offset,offset+length-1);
+// easy->slist_append(HTTP_OUT_HEADER_RANGE, range);
+// }
+// else if (offset > 0)
+// {
+// std::string range = llformat("bytes=%d-", offset);
+// easy->slist_append(HTTP_OUT_HEADER_RANGE, range);
+// }
+// easy->setHeaders();
+// bool res = addEasy(easy);
+// return res;
+// }
+//
+// bool LLCurlRequest::post(const std::string& url,
+// const headers_t& headers,
+// const LLSD& data,
+// LLCurl::ResponderPtr responder, S32 time_out)
+// {
+// llassert(LLCurl::sNotQuitting);
+// LLCurl::Easy* easy = allocEasy();
+// if (!easy)
+// {
+// return false;
+// }
+// easy->prepRequest(url, headers, responder, time_out);
+//
+// LLSDSerialize::toXML(data, easy->getInput());
+// S32 bytes = easy->getInput().str().length();
+//
+// easy->setopt(CURLOPT_POST, 1);
+// easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
+// easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
+//
+// easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML);
+// easy->setHeaders();
+//
+// LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL;
+// bool res = addEasy(easy);
+// return res;
+// }
+//
+// bool LLCurlRequest::post(const std::string& url,
+// const headers_t& headers,
+// const std::string& data,
+// LLCurl::ResponderPtr responder, S32 time_out)
+// {
+// llassert(LLCurl::sNotQuitting);
+// LLCurl::Easy* easy = allocEasy();
+// if (!easy)
+// {
+// return false;
+// }
+// easy->prepRequest(url, headers, responder, time_out);
+//
+// easy->getInput().write(data.data(), data.size());
+// S32 bytes = easy->getInput().str().length();
+//
+// easy->setopt(CURLOPT_POST, 1);
+// easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
+// easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
+//
+// easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_OCTET_STREAM);
+// easy->setHeaders();
+//
+// LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL;
+// bool res = addEasy(easy);
+// return res;
+// }
+//
+// // Note: call once per frame
+// S32 LLCurlRequest::process()
+// {
+// S32 res = 0;
+//
+// mProcessing = TRUE;
+// for (curlmulti_set_t::iterator iter = mMultiSet.begin();
+// iter != mMultiSet.end(); )
+// {
+// curlmulti_set_t::iterator curiter = iter++;
+// LLCurl::Multi* multi = *curiter;
+//
+// if(!multi->isValid())
+// {
+// if(multi == mActiveMulti)
+// {
+// mActiveMulti = NULL ;
+// mActiveRequestCount = 0 ;
+// }
+// mMultiSet.erase(curiter) ;
+// LLCurl::getCurlThread()->killMulti(multi) ;
+// continue ;
+// }
+//
+// S32 tres = multi->process();
+// res += tres;
+// if (multi != mActiveMulti && tres == 0 && multi->mQueued == 0)
+// {
+// mMultiSet.erase(curiter);
+// LLCurl::getCurlThread()->killMulti(multi);
+// }
+// }
+// mProcessing = FALSE;
+// return res;
+// }
+//
+// S32 LLCurlRequest::getQueued()
+// {
+// S32 queued = 0;
+// for (curlmulti_set_t::iterator iter = mMultiSet.begin();
+// iter != mMultiSet.end(); )
+// {
+// curlmulti_set_t::iterator curiter = iter++;
+// LLCurl::Multi* multi = *curiter;
+//
+// if(!multi->isValid())
+// {
+// if(multi == mActiveMulti)
+// {
+// mActiveMulti = NULL ;
+// mActiveRequestCount = 0 ;
+// }
+// LLCurl::getCurlThread()->killMulti(multi);
+// mMultiSet.erase(curiter) ;
+// continue ;
+// }
+//
+// queued += multi->mQueued;
+// if (multi->getState() != LLCurl::Multi::STATE_READY)
+// {
+// ++queued;
+// }
+// }
+// return queued;
+// }
+
+// LLCurlTextureRequest::LLCurlTextureRequest(S32 concurrency) :
+// LLCurlRequest(),
+// mConcurrency(concurrency),
+// mInQueue(0),
+// mMutex(NULL),
+// mHandleCounter(1),
+// mTotalIssuedRequests(0),
+// mTotalReceivedBits(0)
+// {
+// mGlobalTimer.reset();
+// }
+//
+// LLCurlTextureRequest::~LLCurlTextureRequest()
+// {
+// mRequestMap.clear();
+//
+// for(req_queue_t::iterator iter = mCachedRequests.begin(); iter != mCachedRequests.end(); ++iter)
+// {
+// delete *iter;
+// }
+// mCachedRequests.clear();
+// }
+//
+// //return 0: success
+// // > 0: cached handle
+// U32 LLCurlTextureRequest::getByteRange(const std::string& url,
+// const headers_t& headers,
+// S32 offset, S32 length, U32 pri,
+// LLCurl::ResponderPtr responder, F32 delay_time)
+// {
+// U32 ret_val = 0;
+// bool success = false;
+//
+// if(mInQueue < mConcurrency && delay_time < 0.f)
+// {
+// success = LLCurlRequest::getByteRange(url, headers, offset, length, responder);
+// }
+//
+// LLMutexLock lock(&mMutex);
+//
+// if(success)
+// {
+// mInQueue++;
+// mTotalIssuedRequests++;
+// }
+// else
+// {
+// request_t* request = new request_t(mHandleCounter, url, headers, offset, length, pri, responder);
+// if(delay_time > 0.f)
+// {
+// request->mStartTime = mGlobalTimer.getElapsedTimeF32() + delay_time;
+// }
+//
+// mCachedRequests.insert(request);
+// mRequestMap[mHandleCounter] = request;
+// ret_val = mHandleCounter;
+// mHandleCounter++;
+//
+// if(!mHandleCounter)
+// {
+// mHandleCounter = 1;
+// }
+// }
+//
+// return ret_val;
+// }
+//
+// void LLCurlTextureRequest::completeRequest(S32 received_bytes)
+// {
+// LLMutexLock lock(&mMutex);
+//
+// llassert_always(mInQueue > 0);
+//
+// mInQueue--;
+// mTotalReceivedBits += received_bytes * 8;
+// }
+//
+// void LLCurlTextureRequest::nextRequests()
+// {
+// if(mCachedRequests.empty() || mInQueue >= mConcurrency)
+// {
+// return;
+// }
+//
+// F32 cur_time = mGlobalTimer.getElapsedTimeF32();
+//
+// req_queue_t::iterator iter;
+// {
+// LLMutexLock lock(&mMutex);
+// iter = mCachedRequests.begin();
+// }
+// while(1)
+// {
+// request_t* request = *iter;
+// if(request->mStartTime < cur_time)
+// {
+// if(!LLCurlRequest::getByteRange(request->mUrl, request->mHeaders, request->mOffset, request->mLength, request->mResponder))
+// {
+// break;
+// }
+//
+// LLMutexLock lock(&mMutex);
+// ++iter;
+// mInQueue++;
+// mTotalIssuedRequests++;
+// mCachedRequests.erase(request);
+// mRequestMap.erase(request->mHandle);
+// delete request;
+//
+// if(iter == mCachedRequests.end() || mInQueue >= mConcurrency)
+// {
+// break;
+// }
+// }
+// else
+// {
+// LLMutexLock lock(&mMutex);
+// ++iter;
+// if(iter == mCachedRequests.end() || mInQueue >= mConcurrency)
+// {
+// break;
+// }
+// }
+// }
+//
+// return;
+// }
+//
+// void LLCurlTextureRequest::updatePriority(U32 handle, U32 pri)
+// {
+// if(!handle)
+// {
+// return;
+// }
+//
+// LLMutexLock lock(&mMutex);
+//
+// std::map<S32, request_t*>::iterator iter = mRequestMap.find(handle);
+// if(iter != mRequestMap.end())
+// {
+// request_t* req = iter->second;
+//
+// if(req->mPriority != pri)
+// {
+// mCachedRequests.erase(req);
+// req->mPriority = pri;
+// mCachedRequests.insert(req);
+// }
+// }
+// }
+//
+// void LLCurlTextureRequest::removeRequest(U32 handle)
+// {
+// if(!handle)
+// {
+// return;
+// }
+//
+// LLMutexLock lock(&mMutex);
+//
+// std::map<S32, request_t*>::iterator iter = mRequestMap.find(handle);
+// if(iter != mRequestMap.end())
+// {
+// request_t* req = iter->second;
+// mRequestMap.erase(iter);
+// mCachedRequests.erase(req);
+// delete req;
+// }
+// }
+//
+// bool LLCurlTextureRequest::isWaiting(U32 handle)
+// {
+// if(!handle)
+// {
+// return false;
+// }
+//
+// LLMutexLock lock(&mMutex);
+// return mRequestMap.find(handle) != mRequestMap.end();
+// }
+//
+// U32 LLCurlTextureRequest::getTotalReceivedBits()
+// {
+// LLMutexLock lock(&mMutex);
+//
+// U32 bits = mTotalReceivedBits;
+// mTotalReceivedBits = 0;
+// return bits;
+// }
+//
+// U32 LLCurlTextureRequest::getTotalIssuedRequests()
+// {
+// LLMutexLock lock(&mMutex);
+// return mTotalIssuedRequests;
+// }
+//
+// S32 LLCurlTextureRequest::getNumRequests()
+// {
+// LLMutexLock lock(&mMutex);
+// return mInQueue;
+// }
////////////////////////////////////////////////////////////////////////////
// For generating one easy request
@@ -1988,10 +1992,10 @@ void LLCurlFF::check_easy_code(CURLcode code)
{
check_curl_code(code);
}
-void LLCurlFF::check_multi_code(CURLMcode code)
-{
- check_curl_multi_code(code);
-}
+// void LLCurlFF::check_multi_code(CURLMcode code)
+// {
+// check_curl_multi_code(code);
+// }
// Static
diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h
index 385d9fffa8..06b3ce45e1 100755
--- a/indra/llmessage/llcurl.h
+++ b/indra/llmessage/llcurl.h
@@ -418,100 +418,6 @@ private:
} ;
-class LLCurlRequest
-{
-public:
- typedef std::vector<std::string> headers_t;
-
- LLCurlRequest();
- ~LLCurlRequest();
-
- void get(const std::string& url, LLCurl::ResponderPtr responder);
- bool getByteRange(const std::string& url, const headers_t& headers, S32 offset, S32 length, LLCurl::ResponderPtr responder);
- bool post(const std::string& url, const headers_t& headers, const LLSD& data, LLCurl::ResponderPtr responder, S32 time_out = 0);
- bool post(const std::string& url, const headers_t& headers, const std::string& data, LLCurl::ResponderPtr responder, S32 time_out = 0);
-
- S32 process();
- S32 getQueued();
-
-private:
- void addMulti();
- LLCurl::Easy* allocEasy();
- bool addEasy(LLCurl::Easy* easy);
-
-private:
- typedef std::set<LLCurl::Multi*> curlmulti_set_t;
- curlmulti_set_t mMultiSet;
- LLCurl::Multi* mActiveMulti;
- S32 mActiveRequestCount;
- BOOL mProcessing;
-};
-
-//for texture fetch only
-class LLCurlTextureRequest : public LLCurlRequest
-{
-public:
- LLCurlTextureRequest(S32 concurrency);
- ~LLCurlTextureRequest();
-
- U32 getByteRange(const std::string& url, const headers_t& headers, S32 offset, S32 length, U32 pri, LLCurl::ResponderPtr responder, F32 delay_time = -1.f);
- void nextRequests();
- void completeRequest(S32 received_bytes);
-
- void updatePriority(U32 handle, U32 pri);
- void removeRequest(U32 handle);
-
- U32 getTotalReceivedBits();
- U32 getTotalIssuedRequests();
- S32 getNumRequests();
- bool isWaiting(U32 handle);
-
-private:
- LLMutex mMutex;
- S32 mConcurrency;
- S32 mInQueue; //request currently in queue.
- U32 mHandleCounter;
- U32 mTotalIssuedRequests;
- U32 mTotalReceivedBits;
-
- typedef struct _request_t
- {
- _request_t(U32 handle, const std::string& url, const headers_t& headers, S32 offset, S32 length, U32 pri, LLCurl::ResponderPtr responder) :
- mHandle(handle), mUrl(url), mHeaders(headers), mOffset(offset), mLength(length), mPriority(pri), mResponder(responder), mStartTime(0.f)
- {}
-
- U32 mHandle;
- std::string mUrl;
- LLCurlRequest::headers_t mHeaders;
- S32 mOffset;
- S32 mLength;
- LLCurl::ResponderPtr mResponder;
- U32 mPriority;
- F32 mStartTime; //start time to issue this request
- } request_t;
-
- struct request_compare
- {
- bool operator()(const request_t* lhs, const request_t* rhs) const
- {
- if(lhs->mPriority != rhs->mPriority)
- {
- return lhs->mPriority > rhs->mPriority; // higher priority in front of queue (set)
- }
- else
- {
- return (U32)lhs < (U32)rhs;
- }
- }
- };
-
- typedef std::set<request_t*, request_compare> req_queue_t;
- req_queue_t mCachedRequests;
- std::map<S32, request_t*> mRequestMap;
-
- LLFrameTimer mGlobalTimer;
-};
-
class LLCurlEasyRequest
{
public:
@@ -550,7 +456,7 @@ private:
namespace LLCurlFF
{
void check_easy_code(CURLcode code);
- void check_multi_code(CURLMcode code);
+ //void check_multi_code(CURLMcode code);
}
#endif // LL_LLCURL_H
diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp
index f8db3dded2..7f70e6a3f5 100755
--- a/indra/llmessage/llhttpclient.cpp
+++ b/indra/llmessage/llhttpclient.cpp
@@ -38,6 +38,10 @@
#include "lluri.h"
#include "message.h"
+#include "httpcommon.h"
+#include "httprequest.h"
+#include "httpoptions.h"
+
#include <curl/curl.h>
diff --git a/indra/llmessage/llhttpclientadapter.cpp b/indra/llmessage/llhttpclientadapter.cpp
index b56a804f94..8c2a0ad9cf 100755
--- a/indra/llmessage/llhttpclientadapter.cpp
+++ b/indra/llmessage/llhttpclientadapter.cpp
@@ -26,48 +26,48 @@
#include "llhttpclientadapter.h"
#include "llhttpclient.h"
-
-LLHTTPClientAdapter::~LLHTTPClientAdapter()
-{
-}
-
-void LLHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder)
-{
- LLSD empty_pragma_header;
- // Pragma is required to stop curl adding "no-cache"
- // Space is required to stop llurlrequest from turning off proxying
- empty_pragma_header[HTTP_OUT_HEADER_PRAGMA] = " ";
- LLHTTPClient::get(url, responder, empty_pragma_header);
-}
-
-void LLHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers)
-{
- LLSD empty_pragma_header = headers;
- if (!empty_pragma_header.has(HTTP_OUT_HEADER_PRAGMA))
- {
- // as above
- empty_pragma_header[HTTP_OUT_HEADER_PRAGMA] = " ";
- }
- LLHTTPClient::get(url, responder, empty_pragma_header);
-}
-
-void LLHTTPClientAdapter::put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder)
-{
- LLHTTPClient::put(url, body, responder);
-}
-
-void LLHTTPClientAdapter::put(
- const std::string& url,
- const LLSD& body,
- LLCurl::ResponderPtr responder,
- const LLSD& headers)
-{
- LLHTTPClient::put(url, body, responder, headers);
-}
-
-void LLHTTPClientAdapter::del(
- const std::string& url,
- LLCurl::ResponderPtr responder)
-{
- LLHTTPClient::del(url, responder);
-}
+//
+// LLHTTPClientAdapter::~LLHTTPClientAdapter()
+// {
+// }
+//
+// void LLHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder)
+// {
+// LLSD empty_pragma_header;
+// // Pragma is required to stop curl adding "no-cache"
+// // Space is required to stop llurlrequest from turning off proxying
+// empty_pragma_header[HTTP_OUT_HEADER_PRAGMA] = " ";
+// LLHTTPClient::get(url, responder, empty_pragma_header);
+// }
+//
+// void LLHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers)
+// {
+// LLSD empty_pragma_header = headers;
+// if (!empty_pragma_header.has(HTTP_OUT_HEADER_PRAGMA))
+// {
+// // as above
+// empty_pragma_header[HTTP_OUT_HEADER_PRAGMA] = " ";
+// }
+// LLHTTPClient::get(url, responder, empty_pragma_header);
+// }
+//
+// void LLHTTPClientAdapter::put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder)
+// {
+// LLHTTPClient::put(url, body, responder);
+// }
+//
+// void LLHTTPClientAdapter::put(
+// const std::string& url,
+// const LLSD& body,
+// LLCurl::ResponderPtr responder,
+// const LLSD& headers)
+// {
+// LLHTTPClient::put(url, body, responder, headers);
+// }
+//
+// void LLHTTPClientAdapter::del(
+// const std::string& url,
+// LLCurl::ResponderPtr responder)
+// {
+// LLHTTPClient::del(url, responder);
+// }
diff --git a/indra/llmessage/llhttpclientadapter.h b/indra/llmessage/llhttpclientadapter.h
index 270282c66f..0067703895 100755
--- a/indra/llmessage/llhttpclientadapter.h
+++ b/indra/llmessage/llhttpclientadapter.h
@@ -30,6 +30,7 @@
#include "llhttpclientinterface.h"
#include "llsingleton.h" // LLSingleton<>
+/*
class LLHTTPClientAdapter : public LLHTTPClientInterface, public LLSingleton<LLHTTPClientAdapter>
{
public:
@@ -46,6 +47,7 @@ public:
const std::string& url,
LLCurl::ResponderPtr responder);
};
+*/
#endif
diff --git a/indra/llmessage/llhttpclientinterface.h b/indra/llmessage/llhttpclientinterface.h
index 12a3857a61..9c1c8e7c11 100755
--- a/indra/llmessage/llhttpclientinterface.h
+++ b/indra/llmessage/llhttpclientinterface.h
@@ -32,14 +32,14 @@
#include <string>
-class LLHTTPClientInterface
-{
-public:
- virtual ~LLHTTPClientInterface() {}
- virtual void get(const std::string& url, LLCurl::ResponderPtr responder) = 0;
- virtual void get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers) = 0;
- virtual void put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder) = 0;
-};
+// class LLHTTPClientInterface
+// {
+// public:
+// virtual ~LLHTTPClientInterface() {}
+// virtual void get(const std::string& url, LLCurl::ResponderPtr responder) = 0;
+// virtual void get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers) = 0;
+// virtual void put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder) = 0;
+// };
#endif // LL_LLHTTPCLIENTINTERFACE_H
diff --git a/indra/llmessage/llhttpsdhandler.cpp b/indra/llmessage/llhttpsdhandler.cpp
new file mode 100644
index 0000000000..159d03b176
--- /dev/null
+++ b/indra/llmessage/llhttpsdhandler.cpp
@@ -0,0 +1,103 @@
+/**
+* @file llhttpsdhandler.h
+* @brief Public-facing declarations for the HttpHandler class
+*
+* $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 "linden_common.h"
+#include "llhttpconstants.h"
+
+#include "llhttpsdhandler.h"
+#include "httpresponse.h"
+#include "httpheaders.h"
+#include "llsd.h"
+#include "llsdserialize.h"
+#include "bufferstream.h"
+#include "llcorehttputil.h"
+
+//========================================================================
+LLHttpSDHandler::LLHttpSDHandler()
+{
+}
+
+void LLHttpSDHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response)
+{
+ LLCore::HttpStatus status = response->getStatus();
+
+ if (!status)
+ {
+ this->onFailure(response, status);
+ }
+ else
+ {
+ LLSD resplsd;
+ const bool emit_parse_errors = false;
+
+ bool parsed = !((response->getBodySize() == 0) ||
+ !LLCoreHttpUtil::responseToLLSD(response, emit_parse_errors, resplsd));
+
+ if (!parsed)
+ {
+ // Only emit a warning if we failed to parse when 'content-type' == 'application/llsd+xml'
+ LLCore::HttpHeaders::ptr_t headers(response->getHeaders());
+ const std::string *contentType = (headers) ? headers->find(HTTP_IN_HEADER_CONTENT_TYPE) : NULL;
+
+ if (contentType && (HTTP_CONTENT_LLSD_XML == *contentType))
+ {
+ std::string thebody = LLCoreHttpUtil::responseToString(response);
+
+ LL_WARNS() << "Failed to deserialize . " << response->getRequestURL() << " [status:" << response->getStatus().toString() << "] "
+ << " body: " << thebody << LL_ENDL;
+ }
+ }
+
+ this->onSuccess(response, resplsd);
+ }
+
+ // The handler must destroy itself when it is done.
+ // *TODO: I'm not fond of this pattern. A class shooting itself in the head
+ // outside of a smart pointer always makes me nervous.
+ delete this;
+}
+
+//========================================================================
+LLHttpSDGenericHandler::LLHttpSDGenericHandler(const std::string &caps) :
+ LLHttpSDHandler(),
+ mCaps(caps)
+{
+}
+
+void LLHttpSDGenericHandler::onSuccess(LLCore::HttpResponse * response, const LLSD &content)
+{
+ LL_DEBUGS() << mCaps << " Success." << LL_ENDL;
+}
+
+void LLHttpSDGenericHandler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status)
+{
+ LL_WARNS()
+ << "\n--------------------------------------------------------------------------\n"
+ << mCaps << " Error[" << status.toULong() << "] cannot access cap with url '"
+ << response->getRequestURL() << "' because " << status.toString()
+ << "\n--------------------------------------------------------------------------"
+ << LL_ENDL;
+}
diff --git a/indra/llmessage/llhttpsdhandler.h b/indra/llmessage/llhttpsdhandler.h
new file mode 100644
index 0000000000..7c28dbcab6
--- /dev/null
+++ b/indra/llmessage/llhttpsdhandler.h
@@ -0,0 +1,67 @@
+/**
+* @file llhttpsdhandler.h
+* @brief Public-facing declarations for the HttpHandler class
+*
+* $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 _LLHTTPSDHANDLER_H_
+#define _LLHTTPSDHANDLER_H_
+#include "httpcommon.h"
+#include "httphandler.h"
+#include "lluri.h"
+
+/// Handler class LLCore's HTTP library. Splitting with separate success and
+/// failure routines and parsing the result body into LLSD on success. It
+/// is intended to be subclassed for specific capability handling.
+///
+// *TODO: This class self deletes at the end of onCompleted method. This is
+// less than ideal and should be revisited.
+class LLHttpSDHandler : public LLCore::HttpHandler
+{
+public:
+ LLHttpSDHandler();
+
+ virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
+
+protected:
+ virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content) = 0;
+ virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status) = 0;
+
+};
+
+/// A trivial implementation of LLHttpSDHandler. This success and failure
+/// methods log the action taken, the URI accessed and the status code retuned
+/// in the response.
+class LLHttpSDGenericHandler : public LLHttpSDHandler
+{
+public:
+ LLHttpSDGenericHandler(const std::string &action);
+
+protected:
+ virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content);
+ virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status);
+
+private:
+ std::string mCaps;
+};
+#endif \ No newline at end of file
diff --git a/indra/llmessage/llsdrpcclient.h b/indra/llmessage/llsdrpcclient.h
index c4e0333ca3..d097ecdff7 100755
--- a/indra/llmessage/llsdrpcclient.h
+++ b/indra/llmessage/llsdrpcclient.h
@@ -37,7 +37,9 @@
#include "llchainio.h"
#include "llfiltersd2xmlrpc.h"
#include "lliopipe.h"
-#include "llurlrequest.h"
+#if 0
+//#include "llurlrequest.h"
+#endif
/**
* @class LLSDRPCClientResponse
@@ -218,6 +220,7 @@ protected:
LLIOPipe::ptr_t mResponse;
};
+#if 0
/**
* @class LLSDRPCClientFactory
* @brief Basic implementation for making an SD RPC client factory
@@ -267,7 +270,9 @@ public:
protected:
std::string mURL;
};
+#endif
+#if 0
/**
* @class LLXMLSDRPCClientFactory
* @brief Basic implementation for making an XMLRPC to SD RPC client factory
@@ -319,5 +324,6 @@ public:
protected:
std::string mURL;
};
+#endif
#endif // LL_LLSDRPCCLIENT_H
diff --git a/indra/llmessage/tests/llhttpclientadapter_test.cpp b/indra/llmessage/tests/llhttpclientadapter_test.cpp
index e9ce116bb3..e0a82e237b 100755
--- a/indra/llmessage/tests/llhttpclientadapter_test.cpp
+++ b/indra/llmessage/tests/llhttpclientadapter_test.cpp
@@ -23,7 +23,7 @@
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
-
+#if 0
#include "llhttpclientadapter.h"
#include "../test/lltut.h"
@@ -219,3 +219,4 @@ namespace tut
}
}
+#endif \ No newline at end of file
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 13040ea423..3858383e39 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -2330,16 +2330,26 @@ if (LL_TESTS)
"${CMAKE_SOURCE_DIR}/llmessage/tests/test_llsdmessage_peer.py"
)
+ if (LINUX)
+ # llcommon uses `clock_gettime' which is provided by librt on linux.
+ set(LIBRT_LIBRARY
+ rt
+ )
+ endif (LINUX)
+
set(test_libs
- ${LLMESSAGE_LIBRARIES}
- ${LLCOREHTTP_LIBRARIES}
${WINDOWS_LIBRARIES}
${LLVFS_LIBRARIES}
${LLMATH_LIBRARIES}
${LLCOMMON_LIBRARIES}
+ ${LLMESSAGE_LIBRARIES}
+ ${LLCOREHTTP_LIBRARIES}
${GOOGLEMOCK_LIBRARIES}
${OPENSSL_LIBRARIES}
${CRYPTO_LIBRARIES}
+ ${LIBRT_LIBRARY}
+ ${BOOST_CONTEXT_LIBRARY}
+ ${BOOST_COROUTINE_LIBRARY}
)
LL_ADD_INTEGRATION_TEST(llsechandler_basic
diff --git a/indra/newview/llaccountingcostmanager.cpp b/indra/newview/llaccountingcostmanager.cpp
index a42286a9e4..6337fbe444 100755
--- a/indra/newview/llaccountingcostmanager.cpp
+++ b/indra/newview/llaccountingcostmanager.cpp
@@ -27,90 +27,154 @@
#include "llviewerprecompiledheaders.h"
#include "llaccountingcostmanager.h"
#include "llagent.h"
-#include "llcurl.h"
-#include "llhttpclient.h"
+#include "httpcommon.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
+#include "llcorehttputil.h"
+
//===============================================================================
-LLAccountingCostManager::LLAccountingCostManager()
+LLAccountingCostManager::LLAccountingCostManager():
+ mHttpRequest(),
+ mHttpHeaders(),
+ mHttpOptions(),
+ mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID)
{
+ mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest());
+ mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders(), false);
+ mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions(), false);
+ //mHttpPolicy = LLCore::HttpRequest::DEFAULT_POLICY_ID;
+
}
-//===============================================================================
-class LLAccountingCostResponder : public LLCurl::Responder
+
+// Coroutine for sending and processing avatar name cache requests.
+// Do not call directly. See documentation in lleventcoro.h and llcoro.h for
+// further explanation.
+void LLAccountingCostManager::accountingCostCoro(LLCoros::self& self, std::string url,
+ eSelectionType selectionType, const LLHandle<LLAccountingCostObserver> observerHandle)
{
- LOG_CLASS(LLAccountingCostResponder);
-public:
- LLAccountingCostResponder( const LLSD& objectIDs, const LLHandle<LLAccountingCostObserver>& observer_handle )
- : mObjectIDs( objectIDs ),
- mObserverHandle( observer_handle )
- {
- LLAccountingCostObserver* observer = mObserverHandle.get();
- if (observer)
- {
- mTransactionID = observer->getTransactionID();
- }
- }
+ LL_DEBUGS("LLAccountingCostManager") << "Entering coroutine " << LLCoros::instance().getName(self)
+ << " with url '" << url << LL_ENDL;
- void clearPendingRequests ( void )
- {
- for ( LLSD::array_iterator iter = mObjectIDs.beginArray(); iter != mObjectIDs.endArray(); ++iter )
- {
- LLAccountingCostManager::getInstance()->removePendingObject( iter->asUUID() );
- }
- }
-
-protected:
- void httpFailure()
- {
- LL_WARNS() << dumpResponse() << LL_ENDL;
- clearPendingRequests();
-
- LLAccountingCostObserver* observer = mObserverHandle.get();
- if (observer && observer->getTransactionID() == mTransactionID)
- {
- observer->setErrorStatus(getStatus(), getReason());
- }
- }
-
- void httpSuccess()
- {
- const LLSD& content = getContent();
- //Check for error
- if ( !content.isMap() || content.has("error") )
- {
- failureResult(HTTP_INTERNAL_ERROR, "Error on fetched data", content);
- return;
- }
- else if (content.has("selected"))
- {
- F32 physicsCost = 0.0f;
- F32 networkCost = 0.0f;
- F32 simulationCost = 0.0f;
-
- physicsCost = content["selected"]["physics"].asReal();
- networkCost = content["selected"]["streaming"].asReal();
- simulationCost = content["selected"]["simulation"].asReal();
-
- SelectionCost selectionCost( /*transactionID,*/ physicsCost, networkCost, simulationCost );
-
- LLAccountingCostObserver* observer = mObserverHandle.get();
- if (observer && observer->getTransactionID() == mTransactionID)
- {
- observer->onWeightsUpdate(selectionCost);
- }
- }
-
- clearPendingRequests();
- }
-
-private:
- //List of posted objects
- LLSD mObjectIDs;
+ try
+ {
+ LLSD objectList;
+ U32 objectIndex = 0;
+
+ IDIt IDIter = mObjectList.begin();
+ IDIt IDIterEnd = mObjectList.end();
+
+ for (; IDIter != IDIterEnd; ++IDIter)
+ {
+ // Check to see if a request for this object has already been made.
+ if (mPendingObjectQuota.find(*IDIter) == mPendingObjectQuota.end())
+ {
+ mPendingObjectQuota.insert(*IDIter);
+ objectList[objectIndex++] = *IDIter;
+ }
+ }
+
+ mObjectList.clear();
+
+ //Post results
+ if (objectList.size() == 0)
+ return;
+
+ std::string keystr;
+ if (selectionType == Roots)
+ {
+ keystr = "selected_roots";
+ }
+ else if (selectionType == Prims)
+ {
+ keystr = "selected_prims";
+ }
+ else
+ {
+ LL_INFOS() << "Invalid selection type " << LL_ENDL;
+ mObjectList.clear();
+ mPendingObjectQuota.clear();
+ return;
+ }
- // Current request ID
- LLUUID mTransactionID;
+ LLSD dataToPost = LLSD::emptyMap();
+ dataToPost[keystr.c_str()] = objectList;
+
+ LLAccountingCostObserver* observer = observerHandle.get();
+ LLUUID transactionId = observer->getTransactionID();
+ observer = NULL;
+
+ LLCoreHttpUtil::HttpCoroutineAdapter httpAdapter("AccountingCost", mHttpPolicy);
+
+ LLSD results = httpAdapter.postAndYield(self, mHttpRequest, url, dataToPost);
+
+ LLSD httpResults;
+ httpResults = results["http_result"];
+
+ // do/while(false) allows error conditions to break out of following
+ // block while normal flow goes forward once.
+ do
+ {
+ observer = observerHandle.get();
+ if ((!observer) || (observer->getTransactionID() != transactionId))
+ { // *TODO: Rider: I've noticed that getTransactionID() does not
+ // always match transactionId (the new transaction Id does not show a
+ // corresponding request.) (ask Vir)
+ if (!observer)
+ break;
+ LL_WARNS() << "Request transaction Id(" << transactionId
+ << ") does not match observer's transaction Id("
+ << observer->getTransactionID() << ")." << LL_ENDL;
+ break;
+ }
+
+ if (!httpResults["success"].asBoolean())
+ {
+ LL_WARNS() << "Error result from LLCoreHttpUtil::HttpCoroHandler. Code "
+ << httpResults["status"] << ": '" << httpResults["message"] << "'" << LL_ENDL;
+ if (observer)
+ {
+ observer->setErrorStatus(httpResults["status"].asInteger(), httpResults["message"].asStringRef());
+ }
+ break;
+ }
+
+ if (!results.isMap() || results.has("error"))
+ {
+ LL_WARNS() << "Error on fetched data" << LL_ENDL;
+ observer->setErrorStatus(499, "Error on fetched data");
+ break;
+ }
+
+ if (results.has("selected"))
+ {
+ F32 physicsCost = 0.0f;
+ F32 networkCost = 0.0f;
+ F32 simulationCost = 0.0f;
+
+ physicsCost = results["selected"]["physics"].asReal();
+ networkCost = results["selected"]["streaming"].asReal();
+ simulationCost = results["selected"]["simulation"].asReal();
+
+ SelectionCost selectionCost( physicsCost, networkCost, simulationCost);
+
+ observer->onWeightsUpdate(selectionCost);
+ }
+
+ } while (false);
+
+ }
+ catch (std::exception e)
+ {
+ LL_WARNS() << "Caught exception '" << e.what() << "'" << LL_ENDL;
+ }
+ catch (...)
+ {
+ LL_WARNS() << "Caught unknown exception." << LL_ENDL;
+ }
+
+ mPendingObjectQuota.clear();
+}
- // Cost update observer handle
- LLHandle<LLAccountingCostObserver> mObserverHandle;
-};
//===============================================================================
void LLAccountingCostManager::fetchCosts( eSelectionType selectionType,
const std::string& url,
@@ -119,50 +183,11 @@ void LLAccountingCostManager::fetchCosts( eSelectionType selectionType,
// Invoking system must have already determined capability availability
if ( !url.empty() )
{
- LLSD objectList;
- U32 objectIndex = 0;
-
- IDIt IDIter = mObjectList.begin();
- IDIt IDIterEnd = mObjectList.end();
-
- for ( ; IDIter != IDIterEnd; ++IDIter )
- {
- // Check to see if a request for this object has already been made.
- if ( mPendingObjectQuota.find( *IDIter ) == mPendingObjectQuota.end() )
- {
- mPendingObjectQuota.insert( *IDIter );
- objectList[objectIndex++] = *IDIter;
- }
- }
-
- mObjectList.clear();
-
- //Post results
- if ( objectList.size() > 0 )
- {
- std::string keystr;
- if ( selectionType == Roots )
- {
- keystr="selected_roots";
- }
- else
- if ( selectionType == Prims )
- {
- keystr="selected_prims";
- }
- else
- {
- LL_INFOS()<<"Invalid selection type "<<LL_ENDL;
- mObjectList.clear();
- mPendingObjectQuota.clear();
- return;
- }
-
- LLSD dataToPost = LLSD::emptyMap();
- dataToPost[keystr.c_str()] = objectList;
-
- LLHTTPClient::post( url, dataToPost, new LLAccountingCostResponder( objectList, observer_handle ));
- }
+ std::string coroname =
+ LLCoros::instance().launch("LLAccountingCostManager::accountingCostCoro",
+ boost::bind(&LLAccountingCostManager::accountingCostCoro, this, _1, url, selectionType, observer_handle));
+ LL_DEBUGS() << coroname << " with url '" << url << LL_ENDL;
+
}
else
{
diff --git a/indra/newview/llaccountingcostmanager.h b/indra/newview/llaccountingcostmanager.h
index 3ade34c81d..f4d45d43cb 100755
--- a/indra/newview/llaccountingcostmanager.h
+++ b/indra/newview/llaccountingcostmanager.h
@@ -30,6 +30,13 @@
#include "llhandle.h"
#include "llaccountingcost.h"
+#include "httpcommon.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
+#include "httprequest.h"
+#include "httpheaders.h"
+#include "httpoptions.h"
+
//===============================================================================
// An interface class for panels which display the parcel accounting information.
class LLAccountingCostObserver
@@ -69,6 +76,13 @@ private:
//a fetch has been instigated.
std::set<LLUUID> mPendingObjectQuota;
typedef std::set<LLUUID>::iterator IDIt;
+
+ void accountingCostCoro(LLCoros::self& self, std::string url, eSelectionType selectionType, const LLHandle<LLAccountingCostObserver> observerHandle);
+
+ LLCore::HttpRequest::ptr_t mHttpRequest;
+ LLCore::HttpHeaders::ptr_t mHttpHeaders;
+ LLCore::HttpOptions::ptr_t mHttpOptions;
+ LLCore::HttpRequest::policy_t mHttpPolicy;
};
//===============================================================================
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 359171c5bd..b983a636b6 100755
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -95,6 +95,8 @@
#include "lscript_byteformat.h"
#include "stringize.h"
#include "boost/foreach.hpp"
+#include "llhttpsdhandler.h"
+#include "llcorehttputil.h"
using namespace LLAvatarAppearanceDefines;
@@ -361,7 +363,12 @@ LLAgent::LLAgent() :
mMaturityPreferenceNumRetries(0U),
mLastKnownRequestMaturity(SIM_ACCESS_MIN),
mLastKnownResponseMaturity(SIM_ACCESS_MIN),
- mTeleportState( TELEPORT_NONE ),
+ mHttpRequest(),
+ mHttpHeaders(),
+ mHttpOptions(),
+ mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID),
+ mHttpPriority(0),
+ mTeleportState(TELEPORT_NONE),
mRegionp(NULL),
mAgentOriginGlobal(),
@@ -461,6 +468,17 @@ void LLAgent::init()
mTeleportFailedSlot = LLViewerParcelMgr::getInstance()->setTeleportFailedCallback(boost::bind(&LLAgent::handleTeleportFailed, this));
}
+ LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp());
+
+ mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest());
+ mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders(), false);
+ mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions(), false);
+ mHttpPolicy = app_core_http.getPolicy(LLAppCoreHttp::AP_AGENT);
+
+ // Now ensure that we get regular callbacks to poll for completion.
+ mBoundListener = LLEventPumps::instance().obtain("mainloop").
+ listen(LLEventPump::inventName(), boost::bind(&LLAgent::pollHttp, this, _1));
+
mInitialized = TRUE;
}
@@ -478,6 +496,10 @@ void LLAgent::cleanup()
{
mTeleportFailedSlot.disconnect();
}
+ if (mBoundListener.connected())
+ {
+ mBoundListener.disconnect();
+ }
}
//-----------------------------------------------------------------------------
@@ -500,6 +522,17 @@ LLAgent::~LLAgent()
mTeleportSourceSLURL = NULL;
}
+//-----------------------------------------------------------------------------
+// pollHttp
+// Polling done once per frame on the "mainloop" to support HTTP processing.
+//-----------------------------------------------------------------------------
+bool LLAgent::pollHttp(const LLSD&)
+{
+ mHttpRequest->update(0L);
+ return false;
+}
+
+
// Handle any actions that need to be performed when the main app gains focus
// (such as through alt-tab).
//-----------------------------------------------------------------------------
@@ -2517,66 +2550,61 @@ int LLAgent::convertTextToMaturity(char text)
return LLAgentAccess::convertTextToMaturity(text);
}
-class LLMaturityPreferencesResponder : public LLHTTPClient::Responder
+//=========================================================================
+class LLMaturityHttpHandler : public LLHttpSDHandler
{
- LOG_CLASS(LLMaturityPreferencesResponder);
public:
- LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity);
- virtual ~LLMaturityPreferencesResponder();
+ LLMaturityHttpHandler(LLAgent *agent, U8 preferred, U8 previous):
+ LLHttpSDHandler(),
+ mAgent(agent),
+ mPreferredMaturity(preferred),
+ mPreviousMaturity(previous)
+ { }
-protected:
- virtual void httpSuccess();
- virtual void httpFailure();
+ virtual ~LLMaturityHttpHandler()
+ { }
protected:
+ virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content);
+ virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status);
private:
- U8 parseMaturityFromServerResponse(const LLSD &pContent) const;
+ U8 parseMaturityFromServerResponse(const LLSD &pContent) const;
- LLAgent *mAgent;
- U8 mPreferredMaturity;
- U8 mPreviousMaturity;
-};
-
-LLMaturityPreferencesResponder::LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity)
- : LLHTTPClient::Responder(),
- mAgent(pAgent),
- mPreferredMaturity(pPreferredMaturity),
- mPreviousMaturity(pPreviousMaturity)
-{
-}
+ LLAgent * mAgent;
+ U8 mPreferredMaturity;
+ U8 mPreviousMaturity;
-LLMaturityPreferencesResponder::~LLMaturityPreferencesResponder()
-{
-}
+};
-void LLMaturityPreferencesResponder::httpSuccess()
+//-------------------------------------------------------------------------
+void LLMaturityHttpHandler::onSuccess(LLCore::HttpResponse * response, const LLSD &content)
{
- U8 actualMaturity = parseMaturityFromServerResponse(getContent());
+ U8 actualMaturity = parseMaturityFromServerResponse(content);
if (actualMaturity != mPreferredMaturity)
{
LL_WARNS() << "while attempting to change maturity preference from '"
- << LLViewerRegion::accessToString(mPreviousMaturity)
- << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity)
- << "', the server responded with '"
- << LLViewerRegion::accessToString(actualMaturity)
- << "' [value:" << static_cast<U32>(actualMaturity)
- << "], " << dumpResponse() << LL_ENDL;
+ << LLViewerRegion::accessToString(mPreviousMaturity)
+ << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity)
+ << "', the server responded with '"
+ << LLViewerRegion::accessToString(actualMaturity)
+ << "' [value:" << static_cast<U32>(actualMaturity)
+ << "], " << LL_ENDL;
}
mAgent->handlePreferredMaturityResult(actualMaturity);
}
-void LLMaturityPreferencesResponder::httpFailure()
+void LLMaturityHttpHandler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status)
{
- LL_WARNS() << "while attempting to change maturity preference from '"
- << LLViewerRegion::accessToString(mPreviousMaturity)
- << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity)
- << "', " << dumpResponse() << LL_ENDL;
+ LL_WARNS() << "while attempting to change maturity preference from '"
+ << LLViewerRegion::accessToString(mPreviousMaturity)
+ << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity)
+ << "', " << LL_ENDL;
mAgent->handlePreferredMaturityError();
}
-U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &pContent) const
+U8 LLMaturityHttpHandler::parseMaturityFromServerResponse(const LLSD &pContent) const
{
U8 maturity = SIM_ACCESS_MIN;
@@ -2597,6 +2625,7 @@ U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &p
return maturity;
}
+//=========================================================================
void LLAgent::handlePreferredMaturityResult(U8 pServerMaturity)
{
@@ -2726,42 +2755,84 @@ void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity)
// Update the last know maturity request
mLastKnownRequestMaturity = pPreferredMaturity;
- // Create a response handler
- LLHTTPClient::ResponderPtr responderPtr = LLHTTPClient::ResponderPtr(new LLMaturityPreferencesResponder(this, pPreferredMaturity, mLastKnownResponseMaturity));
-
// If we don't have a region, report it as an error
if (getRegion() == NULL)
{
- responderPtr->failureResult(0U, "region is not defined", LLSD());
+ LL_WARNS("Agent") << "Region is not defined, can not change Maturity setting." << LL_ENDL;
+ return;
}
- else
+ std::string url = getRegion()->getCapability("UpdateAgentInformation");
+
+ // If the capability is not defined, report it as an error
+ if (url.empty())
{
- // Find the capability to send maturity preference
- std::string url = getRegion()->getCapability("UpdateAgentInformation");
+ LL_WARNS("Agent") << "'UpdateAgentInformation' is not defined for region" << LL_ENDL;
+ return;
+ }
- // If the capability is not defined, report it as an error
- if (url.empty())
- {
- responderPtr->failureResult(0U,
- "capability 'UpdateAgentInformation' is not defined for region", LLSD());
- }
- else
- {
- // Set new access preference
- LLSD access_prefs = LLSD::emptyMap();
- access_prefs["max"] = LLViewerRegion::accessToShortString(pPreferredMaturity);
-
- LLSD body = LLSD::emptyMap();
- body["access_prefs"] = access_prefs;
- LL_INFOS() << "Sending viewer preferred maturity to '" << LLViewerRegion::accessToString(pPreferredMaturity)
- << "' via capability to: " << url << LL_ENDL;
- LLSD headers;
- LLHTTPClient::post(url, body, responderPtr, headers, 30.0f);
- }
+ LLMaturityHttpHandler * handler = new LLMaturityHttpHandler(this, pPreferredMaturity, mLastKnownResponseMaturity);
+
+ LLSD access_prefs = LLSD::emptyMap();
+ access_prefs["max"] = LLViewerRegion::accessToShortString(pPreferredMaturity);
+
+ LLSD postData = LLSD::emptyMap();
+ postData["access_prefs"] = access_prefs;
+ LL_INFOS() << "Sending viewer preferred maturity to '" << LLViewerRegion::accessToString(pPreferredMaturity)
+ << "' via capability to: " << url << LL_ENDL;
+
+ LLCore::HttpHandle handle = requestPostCapability("UpdateAgentInformation", url, postData, handler);
+
+ if (handle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ delete handler;
+ LL_WARNS("Agent") << "Maturity request post failed." << LL_ENDL;
}
}
}
+// *TODO:RIDER Convert this system to using the coroutine scheme for HTTP communications
+//
+LLCore::HttpHandle LLAgent::requestPostCapability(const std::string &cap, const std::string &url, LLSD &postData, LLHttpSDHandler *usrhndlr)
+{
+ LLHttpSDHandler * handler = (usrhndlr) ? usrhndlr : new LLHttpSDGenericHandler(cap);
+ LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(mHttpRequest,
+ mHttpPolicy, mHttpPriority, url,
+ postData, mHttpOptions, mHttpHeaders, handler);
+
+ if (handle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ // If no handler was passed in we delete the handler default handler allocated
+ // at the start of this function.
+ // *TODO: Change this metaphore to use boost::shared_ptr<> for handlers. Requires change in LLCore::HTTP
+ if (!usrhndlr)
+ delete handler;
+ LLCore::HttpStatus status = mHttpRequest->getStatus();
+ LL_WARNS("Agent") << "'" << cap << "' request POST failed. Reason "
+ << status.toTerseString() << " \"" << status.toString() << "\"" << LL_ENDL;
+ }
+ return handle;
+}
+
+LLCore::HttpHandle LLAgent::requestGetCapability(const std::string &cap, const std::string &url, LLHttpSDHandler *usrhndlr)
+{
+ LLHttpSDHandler * handler = (usrhndlr) ? usrhndlr : new LLHttpSDGenericHandler(cap);
+ LLCore::HttpHandle handle = mHttpRequest->requestGet(mHttpPolicy, mHttpPriority,
+ url, mHttpOptions.get(), mHttpHeaders.get(), handler);
+
+ if (handle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ // If no handler was passed in we delete the handler default handler allocated
+ // at the start of this function.
+ // *TODO: Change this metaphore to use boost::shared_ptr<> for handlers. Requires change in LLCore::HTTP
+ if (!usrhndlr)
+ delete handler;
+ LLCore::HttpStatus status = mHttpRequest->getStatus();
+ LL_WARNS("Agent") << "'" << cap << "' request GET failed. Reason "
+ << status.toTerseString() << " \"" << status.toString() << "\"" << LL_ENDL;
+ }
+ return handle;
+}
+
BOOL LLAgent::getAdminOverride() const
{
return mAgentAccess->getAdminOverride();
diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h
index 4830cb754b..1bad35751f 100755
--- a/indra/newview/llagent.h
+++ b/indra/newview/llagent.h
@@ -34,7 +34,11 @@
#include "llcoordframe.h" // for mFrameAgent
#include "llavatarappearancedefines.h"
#include "llpermissionsflags.h"
+#include "llevents.h"
#include "v3dmath.h"
+#include "httprequest.h"
+#include "httpheaders.h"
+#include "httpoptions.h"
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
@@ -60,6 +64,7 @@ class LLSLURL;
class LLPauseRequestHandle;
class LLUIColor;
class LLTeleportRequest;
+class LLHttpSDHandler;
typedef boost::shared_ptr<LLTeleportRequest> LLTeleportRequestPtr;
@@ -112,6 +117,8 @@ public:
void init();
void cleanup();
+private:
+
//--------------------------------------------------------------------
// Login
//--------------------------------------------------------------------
@@ -758,11 +765,17 @@ private:
unsigned int mMaturityPreferenceNumRetries;
U8 mLastKnownRequestMaturity;
U8 mLastKnownResponseMaturity;
+ LLCore::HttpRequest::ptr_t mHttpRequest;
+ LLCore::HttpHeaders::ptr_t mHttpHeaders;
+ LLCore::HttpOptions::ptr_t mHttpOptions;
+ LLCore::HttpRequest::policy_t mHttpPolicy;
+ LLCore::HttpRequest::priority_t mHttpPriority;
+ LLTempBoundListener mBoundListener;
bool isMaturityPreferenceSyncedWithServer() const;
void sendMaturityPreferenceToServer(U8 pPreferredMaturity);
- friend class LLMaturityPreferencesResponder;
+ friend class LLMaturityHttpHandler;
void handlePreferredMaturityResult(U8 pServerMaturity);
void handlePreferredMaturityError();
void reportPreferredMaturitySuccess();
@@ -772,6 +785,8 @@ private:
void handleMaturity(const LLSD &pNewValue);
bool validateMaturity(const LLSD& newvalue);
+ bool pollHttp(const LLSD &);
+
/** Access
** **
@@ -911,6 +926,20 @@ public:
/********************************************************************************
** **
+ ** UTILITY
+ **/
+public:
+ /// Utilities for allowing the the agent sub managers to post and get via
+ /// HTTP using the agent's policy settings and headers.
+ LLCore::HttpHandle requestPostCapability(const std::string &cap, const std::string &url, LLSD &postData, LLHttpSDHandler *usrhndlr = NULL);
+ LLCore::HttpHandle requestGetCapability(const std::string &cap, const std::string &url, LLHttpSDHandler *usrhndlr = NULL);
+
+/** Utility
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
** DEBUGGING
**/
diff --git a/indra/newview/llagentlanguage.cpp b/indra/newview/llagentlanguage.cpp
index fe6236a32a..f2ac323578 100755
--- a/indra/newview/llagentlanguage.cpp
+++ b/indra/newview/llagentlanguage.cpp
@@ -32,6 +32,7 @@
#include "llviewerregion.h"
// library includes
#include "llui.h" // getLanguage()
+#include "httpcommon.h"
// static
void LLAgentLanguage::init()
@@ -69,7 +70,12 @@ bool LLAgentLanguage::update()
body["language"] = language;
body["language_is_public"] = gSavedSettings.getBOOL("LanguageIsPublic");
- LLHTTPClient::post(url, body, new LLHTTPClient::Responder);
+ //LLHTTPClient::post(url, body, new LLHTTPClient::Responder);
+ LLCore::HttpHandle handle = gAgent.requestPostCapability("UpdateAgentLanguage", url, body);
+ if (handle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ LL_WARNS() << "Unable to change language." << LL_ENDL;
+ }
}
return true;
}
diff --git a/indra/newview/llappcorehttp.cpp b/indra/newview/llappcorehttp.cpp
index f5f224b83e..51cca273d8 100755
--- a/indra/newview/llappcorehttp.cpp
+++ b/indra/newview/llappcorehttp.cpp
@@ -31,6 +31,10 @@
#include "llappviewer.h"
#include "llviewercontrol.h"
+#include <openssl/x509_vfy.h>
+#include <openssl/ssl.h>
+#include "llsecapi.h"
+#include <curl/curl.h>
// Here is where we begin to get our connection usage under control.
// This establishes llcorehttp policy classes that, among other
@@ -93,6 +97,16 @@ static const struct
4, 1, 4, 0, false,
"",
"inventory"
+ },
+ { // AP_MATERIALS
+ 2, 1, 8, 0, false,
+ "RenderMaterials",
+ "material manager requests"
+ },
+ { // AP_AGENT
+ 2, 1, 32, 0, true,
+ "Agent",
+ "Agent requests"
}
};
@@ -151,6 +165,15 @@ void LLAppCoreHttp::init()
<< LL_ENDL;
}
+ // Set up SSL Verification call back.
+ status = LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_SSL_VERIFY_CALLBACK,
+ LLCore::HttpRequest::GLOBAL_POLICY_ID,
+ sslVerify, NULL);
+ if (!status)
+ {
+ LL_WARNS("Init") << "Failed to set SSL Verification. Reason: " << status.toString() << LL_ENDL;
+ }
+
// Tracing levels for library & libcurl (note that 2 & 3 are beyond spammy):
// 0 - None
// 1 - Basic start, stop simple transitions
@@ -182,6 +205,8 @@ void LLAppCoreHttp::init()
}
mHttpClasses[app_policy].mPolicy = LLCore::HttpRequest::createPolicyClass();
+ // We have run out of available HTTP policies. Adjust HTTP_POLICY_CLASS_LIMIT in _httpinternal.h
+ llassert(mHttpClasses[app_policy].mPolicy != LLCore::HttpRequest::INVALID_POLICY_ID);
if (! mHttpClasses[app_policy].mPolicy)
{
// Use default policy (but don't accidentally modify default)
@@ -457,6 +482,62 @@ void LLAppCoreHttp::refreshSettings(bool initial)
}
}
+LLCore::HttpStatus LLAppCoreHttp::sslVerify(const std::string &url,
+ LLCore::HttpHandler const * const handler, void *appdata)
+{
+ X509_STORE_CTX *ctx = static_cast<X509_STORE_CTX *>(appdata);
+ LLCore::HttpStatus result;
+ LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore("");
+ LLPointer<LLCertificateChain> chain = gSecAPIHandler->getCertificateChain(ctx);
+ LLSD validation_params = LLSD::emptyMap();
+ LLURI uri(url);
+
+ validation_params[CERT_HOSTNAME] = uri.hostName();
+
+ // *TODO: In the case of an exception while validating the cert, we need a way
+ // to pass the offending(?) cert back out. *Rider*
+
+ try
+ {
+ // don't validate hostname. Let libcurl do it instead. That way, it'll handle redirects
+ store->validate(VALIDATION_POLICY_SSL & (~VALIDATION_POLICY_HOSTNAME), chain, validation_params);
+ }
+ catch (LLCertValidationTrustException &cert_exception)
+ {
+ // this exception is is handled differently than the general cert
+ // exceptions, as we allow the user to actually add the certificate
+ // for trust.
+ // therefore we pass back a different error code
+ // NOTE: We're currently 'wired' to pass around CURL error codes. This is
+ // somewhat clumsy, as we may run into errors that do not map directly to curl
+ // error codes. Should be refactored with login refactoring, perhaps.
+ result = LLCore::HttpStatus(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_SSL_CACERT);
+ result.setMessage(cert_exception.getMessage());
+ LLPointer<LLCertificate> cert = cert_exception.getCert();
+ cert->ref(); // adding an extra ref here
+ result.setErrorData(cert.get());
+ // We should probably have a more generic way of passing information
+ // back to the error handlers.
+ }
+ catch (LLCertException &cert_exception)
+ {
+ result = LLCore::HttpStatus(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_SSL_PEER_CERTIFICATE);
+ result.setMessage(cert_exception.getMessage());
+ LLPointer<LLCertificate> cert = cert_exception.getCert();
+ cert->ref(); // adding an extra ref here
+ result.setErrorData(cert.get());
+ }
+ catch (...)
+ {
+ // any other odd error, we just handle as a connect error.
+ result = LLCore::HttpStatus(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_SSL_CONNECT_ERROR);
+ }
+
+ return result;
+}
+
+
+
void LLAppCoreHttp::onCompleted(LLCore::HttpHandle, LLCore::HttpResponse *)
{
diff --git a/indra/newview/llappcorehttp.h b/indra/newview/llappcorehttp.h
index 37d7a737e7..410d7c6b07 100755
--- a/indra/newview/llappcorehttp.h
+++ b/indra/newview/llappcorehttp.h
@@ -164,7 +164,29 @@ public:
/// Pipelined: no
AP_INVENTORY,
AP_REPORTING = AP_INVENTORY, // Piggy-back on inventory
-
+
+ /// Material resource requests and puts.
+ ///
+ /// Destination: simhost:12043
+ /// Protocol: https:
+ /// Transfer size: KB
+ /// Long poll: no
+ /// Concurrency: low
+ /// Request rate: low
+ /// Pipelined: no
+ AP_MATERIALS,
+
+ /// Appearance resource requests and puts.
+ ///
+ /// Destination: simhost:12043
+ /// Protocol: https:
+ /// Transfer size: KB
+ /// Long poll: no
+ /// Concurrency: mid
+ /// Request rate: low
+ /// Pipelined: yes
+ AP_AGENT,
+
AP_COUNT // Must be last
};
@@ -233,7 +255,9 @@ private:
bool mStopped;
HttpClass mHttpClasses[AP_COUNT];
bool mPipelined; // Global setting
- boost::signals2::connection mPipelinedSignal; // Signal for 'HttpPipelining' setting
+ boost::signals2::connection mPipelinedSignal; // Signal for 'HttpPipelining' setting
+
+ static LLCore::HttpStatus sslVerify(const std::string &uri, LLCore::HttpHandler const * const handler, void *appdata);
};
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index a64d5b50b3..42c8c0fb1c 100755
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -23,7 +23,7 @@
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
-
+
#include "llviewerprecompiledheaders.h"
#include <boost/lexical_cast.hpp>
@@ -54,6 +54,9 @@
#include "llsdserialize.h"
#include "llhttpretrypolicy.h"
#include "llaisapi.h"
+#include "llhttpsdhandler.h"
+#include "llcorehttputil.h"
+#include "llappviewer.h"
#if LL_MSVC
// disable boost::lexical_cast warning
@@ -1242,6 +1245,198 @@ static void removeDuplicateItems(LLInventoryModel::item_array_t& items)
items = new_items;
}
+//=========================================================================
+#if 0
+// *TODO:
+class LLAppearanceMgrHttpHandler
+{
+public:
+
+ static void apperanceMgrRequestCoro(LLCoros::self& self, std::string url);
+
+private:
+ LLAppearanceMgrHttpHandler();
+
+ static void debugCOF(const LLSD& content);
+
+
+};
+
+void LLAppearanceMgrHttpHandler::apperanceMgrRequestCoro(LLCoros::self& self, std::string url)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("EnvironmentRequest", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+
+
+}
+
+#else
+
+// *TODO: Convert this and llavatar over to using the coroutine scheme rather
+// than the responder for communications. (see block above for start...)
+
+class LLAppearanceMgrHttpHandler : public LLHttpSDHandler
+{
+public:
+ LLAppearanceMgrHttpHandler(LLAppearanceMgr *mgr) :
+ LLHttpSDHandler(),
+ mManager(mgr)
+ { }
+
+ virtual ~LLAppearanceMgrHttpHandler()
+ { }
+
+ virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
+
+protected:
+ virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content);
+ virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status);
+
+private:
+ static void debugCOF(const LLSD& content);
+
+ LLAppearanceMgr *mManager;
+
+};
+
+//-------------------------------------------------------------------------
+void LLAppearanceMgrHttpHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response)
+{
+ mManager->decrementInFlightCounter();
+
+ LLHttpSDHandler::onCompleted(handle, response);
+}
+
+void LLAppearanceMgrHttpHandler::onSuccess(LLCore::HttpResponse * response, const LLSD &content)
+{
+ if (!content.isMap())
+ {
+ LLCore::HttpStatus status = LLCore::HttpStatus(HTTP_INTERNAL_ERROR, "Malformed response contents");
+ response->setStatus(status);
+ onFailure(response, status);
+ if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
+ {
+ debugCOF(content);
+ }
+ return;
+ }
+ if (content["success"].asBoolean())
+ {
+ LL_DEBUGS("Avatar") << "succeeded" << LL_ENDL;
+ if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
+ {
+ dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_ok", content);
+ }
+ }
+ else
+ {
+ LLCore::HttpStatus status = LLCore::HttpStatus(HTTP_INTERNAL_ERROR, "Non-success response");
+ response->setStatus(status);
+ onFailure(response, status);
+ if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
+ {
+ debugCOF(content);
+ }
+ return;
+ }
+}
+
+void LLAppearanceMgrHttpHandler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status)
+{
+ LL_WARNS("Avatar") << "Appearance Mgr request failed to " << response->getRequestURL()
+ << ". Reason code: (" << status.toTerseString() << ") "
+ << status.toString() << LL_ENDL;
+}
+
+#endif
+
+void LLAppearanceMgrHttpHandler::debugCOF(const LLSD& content)
+{
+ dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_error", content);
+
+ LL_INFOS("Avatar") << "AIS COF, version received: " << content["expected"].asInteger()
+ << " ================================= " << LL_ENDL;
+ std::set<LLUUID> ais_items, local_items;
+ const LLSD& cof_raw = content["cof_raw"];
+ for (LLSD::array_const_iterator it = cof_raw.beginArray();
+ it != cof_raw.endArray(); ++it)
+ {
+ const LLSD& item = *it;
+ if (item["parent_id"].asUUID() == LLAppearanceMgr::instance().getCOF())
+ {
+ ais_items.insert(item["item_id"].asUUID());
+ if (item["type"].asInteger() == 24) // link
+ {
+ LL_INFOS("Avatar") << "AIS Link: item_id: " << item["item_id"].asUUID()
+ << " linked_item_id: " << item["asset_id"].asUUID()
+ << " name: " << item["name"].asString()
+ << LL_ENDL;
+ }
+ else if (item["type"].asInteger() == 25) // folder link
+ {
+ LL_INFOS("Avatar") << "AIS Folder link: item_id: " << item["item_id"].asUUID()
+ << " linked_item_id: " << item["asset_id"].asUUID()
+ << " name: " << item["name"].asString()
+ << LL_ENDL;
+ }
+ else
+ {
+ LL_INFOS("Avatar") << "AIS Other: item_id: " << item["item_id"].asUUID()
+ << " linked_item_id: " << item["asset_id"].asUUID()
+ << " name: " << item["name"].asString()
+ << " type: " << item["type"].asInteger()
+ << LL_ENDL;
+ }
+ }
+ }
+ LL_INFOS("Avatar") << LL_ENDL;
+ LL_INFOS("Avatar") << "Local COF, version requested: " << content["observed"].asInteger()
+ << " ================================= " << LL_ENDL;
+ LLInventoryModel::cat_array_t cat_array;
+ LLInventoryModel::item_array_t item_array;
+ gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(),
+ cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH);
+ for (S32 i = 0; i < item_array.size(); i++)
+ {
+ const LLViewerInventoryItem* inv_item = item_array.at(i).get();
+ local_items.insert(inv_item->getUUID());
+ LL_INFOS("Avatar") << "LOCAL: item_id: " << inv_item->getUUID()
+ << " linked_item_id: " << inv_item->getLinkedUUID()
+ << " name: " << inv_item->getName()
+ << " parent: " << inv_item->getParentUUID()
+ << LL_ENDL;
+ }
+ LL_INFOS("Avatar") << " ================================= " << LL_ENDL;
+ S32 local_only = 0, ais_only = 0;
+ for (std::set<LLUUID>::iterator it = local_items.begin(); it != local_items.end(); ++it)
+ {
+ if (ais_items.find(*it) == ais_items.end())
+ {
+ LL_INFOS("Avatar") << "LOCAL ONLY: " << *it << LL_ENDL;
+ local_only++;
+ }
+ }
+ for (std::set<LLUUID>::iterator it = ais_items.begin(); it != ais_items.end(); ++it)
+ {
+ if (local_items.find(*it) == local_items.end())
+ {
+ LL_INFOS("Avatar") << "AIS ONLY: " << *it << LL_ENDL;
+ ais_only++;
+ }
+ }
+ if (local_only == 0 && ais_only == 0)
+ {
+ LL_INFOS("Avatar") << "COF contents identical, only version numbers differ (req "
+ << content["observed"].asInteger()
+ << " rcv " << content["expected"].asInteger()
+ << ")" << LL_ENDL;
+ }
+}
+//=========================================================================
+
const LLUUID LLAppearanceMgr::getCOF() const
{
return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
@@ -3154,276 +3349,6 @@ void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id,
}
-class RequestAgentUpdateAppearanceResponder: public LLHTTPClient::Responder
-{
- LOG_CLASS(RequestAgentUpdateAppearanceResponder);
-
- friend class LLAppearanceMgr;
-
-public:
- RequestAgentUpdateAppearanceResponder();
-
- virtual ~RequestAgentUpdateAppearanceResponder();
-
-private:
- // Called when sendServerAppearanceUpdate called. May or may not
- // trigger a request depending on various bits of state.
- void onRequestRequested();
-
- // Post the actual appearance request to cap.
- void sendRequest();
-
- void debugCOF(const LLSD& content);
-
-protected:
- // Successful completion.
- /* virtual */ void httpSuccess();
-
- // Error
- /*virtual*/ void httpFailure();
-
- void onFailure();
- void onSuccess();
-
- S32 mInFlightCounter;
- LLTimer mInFlightTimer;
- LLPointer<LLHTTPRetryPolicy> mRetryPolicy;
-};
-
-RequestAgentUpdateAppearanceResponder::RequestAgentUpdateAppearanceResponder()
-{
- bool retry_on_4xx = true;
- mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10, retry_on_4xx);
- mInFlightCounter = 0;
-}
-
-RequestAgentUpdateAppearanceResponder::~RequestAgentUpdateAppearanceResponder()
-{
-}
-
-void RequestAgentUpdateAppearanceResponder::onRequestRequested()
-{
- // If we have already received an update for this or higher cof version, ignore.
- S32 cof_version = LLAppearanceMgr::instance().getCOFVersion();
- S32 last_rcv = gAgentAvatarp->mLastUpdateReceivedCOFVersion;
- S32 last_req = gAgentAvatarp->mLastUpdateRequestCOFVersion;
- LL_DEBUGS("Avatar") << "cof_version " << cof_version
- << " last_rcv " << last_rcv
- << " last_req " << last_req
- << " in flight " << mInFlightCounter << LL_ENDL;
- if ((mInFlightCounter>0) && (mInFlightTimer.hasExpired()))
- {
- LL_WARNS("Avatar") << "in flight timer expired, resetting " << LL_ENDL;
- mInFlightCounter = 0;
- }
- if (cof_version < last_rcv)
- {
- LL_DEBUGS("Avatar") << "Have already received update for cof version " << last_rcv
- << " will not request for " << cof_version << LL_ENDL;
- return;
- }
- if (mInFlightCounter>0 && last_req >= cof_version)
- {
- LL_DEBUGS("Avatar") << "Request already in flight for cof version " << last_req
- << " will not request for " << cof_version << LL_ENDL;
- return;
- }
-
- // Actually send the request.
- LL_DEBUGS("Avatar") << "Will send request for cof_version " << cof_version << LL_ENDL;
- mRetryPolicy->reset();
- sendRequest();
-}
-
-void RequestAgentUpdateAppearanceResponder::sendRequest()
-{
- if (gAgentAvatarp->isEditingAppearance())
- {
- // don't send out appearance updates if in appearance editing mode
- return;
- }
-
- if (!gAgent.getRegion())
- {
- LL_WARNS() << "Region not set, cannot request server appearance update" << LL_ENDL;
- return;
- }
- if (gAgent.getRegion()->getCentralBakeVersion()==0)
- {
- LL_WARNS() << "Region does not support baking" << LL_ENDL;
- }
- std::string url = gAgent.getRegion()->getCapability("UpdateAvatarAppearance");
- if (url.empty())
- {
- LL_WARNS() << "No cap for UpdateAvatarAppearance." << LL_ENDL;
- return;
- }
-
- LLSD body;
- S32 cof_version = LLAppearanceMgr::instance().getCOFVersion();
- if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate"))
- {
- body = LLAppearanceMgr::instance().dumpCOF();
- }
- else
- {
- body["cof_version"] = cof_version;
- if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure"))
- {
- body["cof_version"] = cof_version+999;
- }
- }
- LL_DEBUGS("Avatar") << "request url " << url << " my_cof_version " << cof_version << LL_ENDL;
-
- mInFlightCounter++;
- mInFlightTimer.setTimerExpirySec(60.0);
- LLHTTPClient::post(url, body, this);
- llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion);
- gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version;
-}
-
-void RequestAgentUpdateAppearanceResponder::debugCOF(const LLSD& content)
-{
- LL_INFOS("Avatar") << "AIS COF, version received: " << content["expected"].asInteger()
- << " ================================= " << LL_ENDL;
- std::set<LLUUID> ais_items, local_items;
- const LLSD& cof_raw = content["cof_raw"];
- for (LLSD::array_const_iterator it = cof_raw.beginArray();
- it != cof_raw.endArray(); ++it)
- {
- const LLSD& item = *it;
- if (item["parent_id"].asUUID() == LLAppearanceMgr::instance().getCOF())
- {
- ais_items.insert(item["item_id"].asUUID());
- if (item["type"].asInteger() == 24) // link
- {
- LL_INFOS("Avatar") << "AIS Link: item_id: " << item["item_id"].asUUID()
- << " linked_item_id: " << item["asset_id"].asUUID()
- << " name: " << item["name"].asString()
- << LL_ENDL;
- }
- else if (item["type"].asInteger() == 25) // folder link
- {
- LL_INFOS("Avatar") << "AIS Folder link: item_id: " << item["item_id"].asUUID()
- << " linked_item_id: " << item["asset_id"].asUUID()
- << " name: " << item["name"].asString()
- << LL_ENDL;
- }
- else
- {
- LL_INFOS("Avatar") << "AIS Other: item_id: " << item["item_id"].asUUID()
- << " linked_item_id: " << item["asset_id"].asUUID()
- << " name: " << item["name"].asString()
- << " type: " << item["type"].asInteger()
- << LL_ENDL;
- }
- }
- }
- LL_INFOS("Avatar") << LL_ENDL;
- LL_INFOS("Avatar") << "Local COF, version requested: " << content["observed"].asInteger()
- << " ================================= " << LL_ENDL;
- LLInventoryModel::cat_array_t cat_array;
- LLInventoryModel::item_array_t item_array;
- gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(),
- cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH);
- for (S32 i=0; i<item_array.size(); i++)
- {
- const LLViewerInventoryItem* inv_item = item_array.at(i).get();
- local_items.insert(inv_item->getUUID());
- LL_INFOS("Avatar") << "LOCAL: item_id: " << inv_item->getUUID()
- << " linked_item_id: " << inv_item->getLinkedUUID()
- << " name: " << inv_item->getName()
- << " parent: " << inv_item->getParentUUID()
- << LL_ENDL;
- }
- LL_INFOS("Avatar") << " ================================= " << LL_ENDL;
- S32 local_only = 0, ais_only = 0;
- for (std::set<LLUUID>::iterator it = local_items.begin(); it != local_items.end(); ++it)
- {
- if (ais_items.find(*it) == ais_items.end())
- {
- LL_INFOS("Avatar") << "LOCAL ONLY: " << *it << LL_ENDL;
- local_only++;
- }
- }
- for (std::set<LLUUID>::iterator it = ais_items.begin(); it != ais_items.end(); ++it)
- {
- if (local_items.find(*it) == local_items.end())
- {
- LL_INFOS("Avatar") << "AIS ONLY: " << *it << LL_ENDL;
- ais_only++;
- }
- }
- if (local_only==0 && ais_only==0)
- {
- LL_INFOS("Avatar") << "COF contents identical, only version numbers differ (req "
- << content["observed"].asInteger()
- << " rcv " << content["expected"].asInteger()
- << ")" << LL_ENDL;
- }
-}
-
-/* virtual */ void RequestAgentUpdateAppearanceResponder::httpSuccess()
-{
- const LLSD& content = getContent();
- if (!content.isMap())
- {
- failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
- return;
- }
- if (content["success"].asBoolean())
- {
- LL_DEBUGS("Avatar") << "succeeded" << LL_ENDL;
- if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
- {
- dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_ok", content);
- }
-
- onSuccess();
- }
- else
- {
- failureResult(HTTP_INTERNAL_ERROR, "Non-success response", content);
- }
-}
-
-void RequestAgentUpdateAppearanceResponder::onSuccess()
-{
- mInFlightCounter = llmax(mInFlightCounter-1,0);
-}
-
-/*virtual*/ void RequestAgentUpdateAppearanceResponder::httpFailure()
-{
- LL_WARNS("Avatar") << "appearance update request failed, status "
- << getStatus() << " reason " << getReason() << LL_ENDL;
-
- if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
- {
- const LLSD& content = getContent();
- dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_error", content);
- debugCOF(content);
- }
- onFailure();
-}
-
-void RequestAgentUpdateAppearanceResponder::onFailure()
-{
- mInFlightCounter = llmax(mInFlightCounter-1,0);
-
- F32 seconds_to_wait;
- mRetryPolicy->onFailure(getStatus(), getResponseHeaders());
- if (mRetryPolicy->shouldRetry(seconds_to_wait))
- {
- LL_INFOS() << "retrying" << LL_ENDL;
- doAfterInterval(boost::bind(&RequestAgentUpdateAppearanceResponder::sendRequest,this),
- seconds_to_wait);
- }
- else
- {
- LL_WARNS() << "giving up after too many retries" << LL_ENDL;
- }
-}
-
LLSD LLAppearanceMgr::dumpCOF() const
{
@@ -3490,101 +3415,104 @@ LLSD LLAppearanceMgr::dumpCOF() const
void LLAppearanceMgr::requestServerAppearanceUpdate()
{
- mAppearanceResponder->onRequestRequested();
-}
-class LLIncrementCofVersionResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLIncrementCofVersionResponder);
-public:
- LLIncrementCofVersionResponder() : LLHTTPClient::Responder()
+ if (!testCOFRequestVersion())
{
- mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 16.0, 2.0, 5);
+ // *TODO: LL_LOG message here
+ return;
}
- virtual ~LLIncrementCofVersionResponder()
+ if ((mInFlightCounter > 0) && (mInFlightTimer.hasExpired()))
{
+ LL_WARNS("Avatar") << "in flight timer expired, resetting " << LL_ENDL;
+ mInFlightCounter = 0;
}
-protected:
- virtual void httpSuccess()
+ if (gAgentAvatarp->isEditingAppearance())
{
- LL_INFOS() << "Successfully incremented agent's COF." << LL_ENDL;
- const LLSD& content = getContent();
- if (!content.isMap())
- {
- failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
- return;
- }
- S32 new_version = content["category"]["version"].asInteger();
-
- // cof_version should have increased
- llassert(new_version > gAgentAvatarp->mLastUpdateRequestCOFVersion);
-
- gAgentAvatarp->mLastUpdateRequestCOFVersion = new_version;
+ LL_WARNS("Avatar") << "Avatar editing appeance, not sending request." << LL_ENDL;
+ // don't send out appearance updates if in appearance editing mode
+ return;
}
- virtual void httpFailure()
+ if (!gAgent.getRegion())
{
- LL_WARNS("Avatar") << "While attempting to increment the agent's cof we got an error "
- << dumpResponse() << LL_ENDL;
- F32 seconds_to_wait;
- mRetryPolicy->onFailure(getStatus(), getResponseHeaders());
- if (mRetryPolicy->shouldRetry(seconds_to_wait))
- {
- LL_INFOS() << "retrying" << LL_ENDL;
- doAfterInterval(boost::bind(&LLAppearanceMgr::incrementCofVersion,
- LLAppearanceMgr::getInstance(),
- LLHTTPClient::ResponderPtr(this)),
- seconds_to_wait);
- }
- else
- {
- LL_WARNS() << "giving up after too many retries" << LL_ENDL;
- }
+ LL_WARNS("Avatar") << "Region not set, cannot request server appearance update" << LL_ENDL;
+ return;
}
-
-private:
- LLPointer<LLHTTPRetryPolicy> mRetryPolicy;
-};
-
-void LLAppearanceMgr::incrementCofVersion(LLHTTPClient::ResponderPtr responder_ptr)
-{
- // If we don't have a region, report it as an error
- if (gAgent.getRegion() == NULL)
+ if (gAgent.getRegion()->getCentralBakeVersion() == 0)
{
- LL_WARNS() << "Region not set, cannot request cof_version increment" << LL_ENDL;
- return;
+ LL_WARNS("Avatar") << "Region does not support baking" << LL_ENDL;
}
-
- std::string url = gAgent.getRegion()->getCapability("IncrementCofVersion");
+ std::string url = gAgent.getRegion()->getCapability("UpdateAvatarAppearance");
if (url.empty())
{
- LL_WARNS() << "No cap for IncrementCofVersion." << LL_ENDL;
+ LL_WARNS("Avatar") << "No cap for UpdateAvatarAppearance." << LL_ENDL;
return;
}
- LL_INFOS() << "Requesting cof_version be incremented via capability to: "
- << url << LL_ENDL;
- LLSD headers;
- LLSD body = LLSD::emptyMap();
-
- if (!responder_ptr.get())
+ LLSD postData;
+ S32 cof_version = LLAppearanceMgr::instance().getCOFVersion();
+ if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate"))
+ {
+ postData = LLAppearanceMgr::instance().dumpCOF();
+ }
+ else
{
- responder_ptr = LLHTTPClient::ResponderPtr(new LLIncrementCofVersionResponder());
+ postData["cof_version"] = cof_version;
+ if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure"))
+ {
+ postData["cof_version"] = cof_version + 999;
+ }
}
+ LL_DEBUGS("Avatar") << "request url " << url << " my_cof_version " << cof_version << LL_ENDL;
+
+ LLAppearanceMgrHttpHandler * handler = new LLAppearanceMgrHttpHandler(this);
+
+ mInFlightCounter++;
+ mInFlightTimer.setTimerExpirySec(60.0);
+
+ llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion);
+ gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version;
- LLHTTPClient::get(url, body, responder_ptr, headers, 30.0f);
+
+ LLCore::HttpHandle handle = gAgent.requestPostCapability("UpdateAvatarAppearance", url, postData, handler);
+
+ if (handle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ delete handler;
+ }
}
-U32 LLAppearanceMgr::getNumAttachmentsInCOF()
+bool LLAppearanceMgr::testCOFRequestVersion() const
{
- const LLUUID cof = getCOF();
- LLInventoryModel::item_array_t obj_items;
- getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT);
- return obj_items.size();
-}
+ // If we have already received an update for this or higher cof version, ignore.
+ S32 cof_version = getCOFVersion();
+ S32 last_rcv = gAgentAvatarp->mLastUpdateReceivedCOFVersion;
+ S32 last_req = gAgentAvatarp->mLastUpdateRequestCOFVersion;
+ LL_DEBUGS("Avatar") << "cof_version " << cof_version
+ << " last_rcv " << last_rcv
+ << " last_req " << last_req
+ << " in flight " << mInFlightCounter
+ << LL_ENDL;
+ if (cof_version < last_rcv)
+ {
+ LL_DEBUGS("Avatar") << "Have already received update for cof version " << last_rcv
+ << " will not request for " << cof_version << LL_ENDL;
+ return false;
+ }
+ if (/*mInFlightCounter > 0 &&*/ last_req >= cof_version)
+ {
+ LL_DEBUGS("Avatar") << "Request already in flight for cof version " << last_req
+ << " will not request for " << cof_version << LL_ENDL;
+ return false;
+ }
+
+ // Actually send the request.
+ LL_DEBUGS("Avatar") << "Will send request for cof_version " << cof_version << LL_ENDL;
+ return true;
+}
std::string LLAppearanceMgr::getAppearanceServiceURL() const
{
@@ -3850,15 +3778,17 @@ void LLAppearanceMgr::dumpItemArray(const LLInventoryModel::item_array_t& items,
}
}
+bool LLAppearanceMgr::mActive = true;
+
LLAppearanceMgr::LLAppearanceMgr():
mAttachmentInvLinkEnabled(false),
mOutfitIsDirty(false),
mOutfitLocked(false),
- mIsInUpdateAppearanceFromCOF(false),
- mAppearanceResponder(new RequestAgentUpdateAppearanceResponder)
+ mInFlightCounter(0),
+ mInFlightTimer(),
+ mIsInUpdateAppearanceFromCOF(false)
{
LLOutfitObserver& outfit_observer = LLOutfitObserver::instance();
-
// unlock outfit on save operation completed
outfit_observer.addCOFSavedCallback(boost::bind(
&LLAppearanceMgr::setOutfitLocked, this, false));
@@ -3866,11 +3796,12 @@ LLAppearanceMgr::LLAppearanceMgr():
mUnlockOutfitTimer.reset(new LLOutfitUnLockTimer(gSavedSettings.getS32(
"OutfitOperationsTimeout")));
- gIdleCallbacks.addFunction(&LLAttachmentsMgr::onIdle,NULL);
+ gIdleCallbacks.addFunction(&LLAttachmentsMgr::onIdle, NULL);
}
LLAppearanceMgr::~LLAppearanceMgr()
{
+ mActive = false;
}
void LLAppearanceMgr::setAttachmentInvLinkEnable(bool val)
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index 7742a19c07..760a0bc6ef 100755
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -34,12 +34,10 @@
#include "llinventorymodel.h"
#include "llinventoryobserver.h"
#include "llviewerinventory.h"
-#include "llhttpclient.h"
class LLWearableHoldingPattern;
class LLInventoryCallback;
class LLOutfitUnLockTimer;
-class RequestAgentUpdateAppearanceResponder;
class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>
{
@@ -54,7 +52,6 @@ public:
void updateAppearanceFromCOF(bool enforce_item_restrictions = true,
bool enforce_ordering = true,
nullary_func_t post_update_func = no_op);
- bool needToSaveCOF();
void updateCOF(const LLUUID& category, bool append = false);
void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append);
void wearInventoryCategoryOnAvatar(LLInventoryCategory* category, bool append);
@@ -215,20 +212,20 @@ public:
void requestServerAppearanceUpdate();
- void incrementCofVersion(LLHTTPClient::ResponderPtr responder_ptr = NULL);
+ void setAppearanceServiceURL(const std::string& url) { mAppearanceServiceURL = url; }
+ std::string getAppearanceServiceURL() const;
- U32 getNumAttachmentsInCOF();
- // *HACK Remove this after server side texture baking is deployed on all sims.
- void incrementCofVersionLegacy();
+ bool testCOFRequestVersion() const;
+ void decrementInFlightCounter()
+ {
+ mInFlightCounter = llmax(mInFlightCounter - 1, 0);
+ }
- void setAppearanceServiceURL(const std::string& url) { mAppearanceServiceURL = url; }
- std::string getAppearanceServiceURL() const;
private:
std::string mAppearanceServiceURL;
-
protected:
LLAppearanceMgr();
~LLAppearanceMgr();
@@ -252,13 +249,14 @@ private:
bool mOutfitIsDirty;
bool mIsInUpdateAppearanceFromCOF; // to detect recursive calls.
- LLPointer<RequestAgentUpdateAppearanceResponder> mAppearanceResponder;
-
/**
* Lock for blocking operations on outfit until server reply or timeout exceed
* to avoid unsynchronized outfit state or performing duplicate operations.
*/
bool mOutfitLocked;
+ S32 mInFlightCounter;
+ LLTimer mInFlightTimer;
+ static bool mActive;
std::auto_ptr<LLOutfitUnLockTimer> mUnlockOutfitTimer;
diff --git a/indra/newview/llavatarrenderinfoaccountant.cpp b/indra/newview/llavatarrenderinfoaccountant.cpp
index 38e153137c..aeaa832bc7 100644
--- a/indra/newview/llavatarrenderinfoaccountant.cpp
+++ b/indra/newview/llavatarrenderinfoaccountant.cpp
@@ -43,7 +43,9 @@
#include "llviewerregion.h"
#include "llvoavatar.h"
#include "llworld.h"
-
+#include "llhttpsdhandler.h"
+#include "httpheaders.h"
+#include "httpoptions.h"
static const std::string KEY_AGENTS = "agents"; // map
static const std::string KEY_WEIGHT = "weight"; // integer
@@ -55,8 +57,113 @@ static const std::string KEY_ERROR = "error";
// Send data updates about once per minute, only need per-frame resolution
LLFrameTimer LLAvatarRenderInfoAccountant::sRenderInfoReportTimer;
+//LLCore::HttpRequest::ptr_t LLAvatarRenderInfoAccountant::sHttpRequest;
+
+#if 0
+//=========================================================================
+class LLAvatarRenderInfoHandler : public LLHttpSDHandler
+{
+public:
+ LLAvatarRenderInfoHandler(const LLURI &uri, U64 regionHandle);
+
+protected:
+ virtual void onSuccess(LLCore::HttpResponse * response, LLSD &content);
+ virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status);
+
+private:
+ U64 mRegionHandle;
+};
+
+LLAvatarRenderInfoHandler::LLAvatarRenderInfoHandler(const LLURI &uri, U64 regionHandle) :
+ LLHttpSDHandler(uri),
+ mRegionHandle(regionHandle)
+{
+}
+
+void LLAvatarRenderInfoHandler::onSuccess(LLCore::HttpResponse * response, LLSD &content)
+{
+ LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
+ if (regionp)
+ {
+ if (LLAvatarRenderInfoAccountant::logRenderInfo())
+ {
+ LL_INFOS() << "LRI: Result for avatar weights request for region " << regionp->getName() << ":" << LL_ENDL;
+ }
+
+ if (content.isMap())
+ {
+ if (content.has(KEY_AGENTS))
+ {
+ const LLSD & agents = content[KEY_AGENTS];
+ if (agents.isMap())
+ {
+ LLSD::map_const_iterator report_iter = agents.beginMap();
+ while (report_iter != agents.endMap())
+ {
+ LLUUID target_agent_id = LLUUID(report_iter->first);
+ const LLSD & agent_info_map = report_iter->second;
+ LLViewerObject* avatarp = gObjectList.findObject(target_agent_id);
+ if (avatarp &&
+ avatarp->isAvatar() &&
+ agent_info_map.isMap())
+ { // Extract the data for this avatar
+
+ if (LLAvatarRenderInfoAccountant::logRenderInfo())
+ {
+ LL_INFOS() << "LRI: Agent " << target_agent_id
+ << ": " << agent_info_map << LL_ENDL;
+ }
+
+ if (agent_info_map.has(KEY_WEIGHT))
+ {
+ ((LLVOAvatar *)avatarp)->setReportedVisualComplexity(agent_info_map[KEY_WEIGHT].asInteger());
+ }
+ }
+ report_iter++;
+ }
+ }
+ } // has "agents"
+ else if (content.has(KEY_ERROR))
+ {
+ const LLSD & error = content[KEY_ERROR];
+ LL_WARNS() << "Avatar render info GET error: "
+ << error[KEY_IDENTIFIER]
+ << ": " << error[KEY_MESSAGE]
+ << " from region " << regionp->getName()
+ << LL_ENDL;
+ }
+ }
+ }
+ else
+ {
+ LL_INFOS() << "Avatar render weight info received but region not found for "
+ << mRegionHandle << LL_ENDL;
+ }
+}
+void LLAvatarRenderInfoHandler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status)
+{
+ LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
+ if (regionp)
+ {
+ LL_WARNS() << "HTTP error result for avatar weight GET: " << status.toULong()
+ << ", " << status.toString()
+ << " returned by region " << regionp->getName()
+ << LL_ENDL;
+ }
+ else
+ {
+ LL_WARNS() << "Avatar render weight GET error received but region not found for "
+ << mRegionHandle
+ << ", error " << status.toULong()
+ << ", " << status.toString()
+ << LL_ENDL;
+ }
+}
+
+//-------------------------------------------------------------------------
+#else
// HTTP responder class for GET request for avatar render weight information
class LLAvatarRenderInfoGetResponder : public LLHTTPClient::Responder
{
@@ -142,7 +249,7 @@ public:
}
else
{
- LL_INFOS() << "Avatar render weight info recieved but region not found for "
+ LL_INFOS() << "Avatar render weight info received but region not found for "
<< mRegionHandle << LL_ENDL;
}
}
@@ -150,7 +257,7 @@ public:
private:
U64 mRegionHandle;
};
-
+#endif
// HTTP responder class for POST request for avatar render weight information
class LLAvatarRenderInfoPostResponder : public LLHTTPClient::Responder
@@ -172,7 +279,7 @@ public:
}
else
{
- LL_WARNS() << "Avatar render weight POST error recieved but region not found for "
+ LL_WARNS() << "Avatar render weight POST error received but region not found for "
<< mRegionHandle
<< ", error " << statusNum
<< ", " << reason
@@ -215,7 +322,6 @@ private:
U64 mRegionHandle;
};
-
// static
// Send request for one region, no timer checks
void LLAvatarRenderInfoAccountant::sendRenderInfoToRegion(LLViewerRegion * regionp)
@@ -292,7 +398,19 @@ void LLAvatarRenderInfoAccountant::getRenderInfoFromRegion(LLViewerRegion * regi
}
// First send a request to get the latest data
+#if 0
+ if (!LLAvatarRenderInfoAccountant::sHttpRequest)
+ sHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest());
+ LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp());
+
+ LLCore::HttpHeaders::ptr_t httpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders(), false);
+ LLCore::HttpOptions::ptr_t httpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions(), false);
+ LLCore::HttpRequest::policy_t httpPolicy = app_core_http.getPolicy(LLAppCoreHttp::AP_AGENT);
+
+ LLCore::HttpHandle handle = sHttpRequest->
+#else
LLHTTPClient::get(url, new LLAvatarRenderInfoGetResponder(regionp->getHandle()));
+#endif
}
}
@@ -301,6 +419,9 @@ void LLAvatarRenderInfoAccountant::getRenderInfoFromRegion(LLViewerRegion * regi
// Called every frame - send render weight requests to every region
void LLAvatarRenderInfoAccountant::idle()
{
+// if (!LLAvatarRenderInfoAccountant::sHttpRequest)
+// sHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest());
+
if (sRenderInfoReportTimer.hasExpired())
{
const F32 SECS_BETWEEN_REGION_SCANS = 5.f; // Scan the region list every 5 seconds
diff --git a/indra/newview/llavatarrenderinfoaccountant.h b/indra/newview/llavatarrenderinfoaccountant.h
index d68f2dccfb..13054f5e2f 100644
--- a/indra/newview/llavatarrenderinfoaccountant.h
+++ b/indra/newview/llavatarrenderinfoaccountant.h
@@ -29,6 +29,8 @@
#if ! defined(LL_llavatarrenderinfoaccountant_H)
#define LL_llavatarrenderinfoaccountant_H
+#include "httpcommon.h"
+
class LLViewerRegion;
// Class to gather avatar rendering information
@@ -36,8 +38,6 @@ class LLViewerRegion;
class LLAvatarRenderInfoAccountant
{
public:
- LLAvatarRenderInfoAccountant() {};
- ~LLAvatarRenderInfoAccountant() {};
static void sendRenderInfoToRegion(LLViewerRegion * regionp);
static void getRenderInfoFromRegion(LLViewerRegion * regionp);
@@ -49,8 +49,14 @@ public:
static bool logRenderInfo();
private:
+ LLAvatarRenderInfoAccountant() {};
+ ~LLAvatarRenderInfoAccountant() {};
+
// Send data updates about once per minute, only need per-frame resolution
static LLFrameTimer sRenderInfoReportTimer;
+
+// static LLCore::HttpRequest::ptr_t sHttpRequest;
+
};
#endif /* ! defined(LL_llavatarrenderinfoaccountant_H) */
diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp
index 4de6ad4d2f..d731428464 100755
--- a/indra/newview/lleventpoll.cpp
+++ b/indra/newview/lleventpoll.cpp
@@ -37,254 +37,243 @@
#include "llviewerregion.h"
#include "message.h"
#include "lltrans.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
+#include "llcorehttputil.h"
+#include "lleventfilter.h"
-namespace
+namespace LLEventPolling
{
- // We will wait RETRY_SECONDS + (errorCount * RETRY_SECONDS_INC) before retrying after an error.
- // This means we attempt to recover relatively quickly but back off giving more time to recover
- // until we finally give up after MAX_EVENT_POLL_HTTP_ERRORS attempts.
- const F32 EVENT_POLL_ERROR_RETRY_SECONDS = 15.f; // ~ half of a normal timeout.
- const F32 EVENT_POLL_ERROR_RETRY_SECONDS_INC = 5.f; // ~ half of a normal timeout.
- const S32 MAX_EVENT_POLL_HTTP_ERRORS = 10; // ~5 minutes, by the above rules.
-
- class LLEventPollResponder : public LLHTTPClient::Responder
- {
- LOG_CLASS(LLEventPollResponder);
- public:
-
- static LLHTTPClient::ResponderPtr start(const std::string& pollURL, const LLHost& sender);
- void stop();
-
- void makeRequest();
-
- /* virtual */ void completedRaw(const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer);
-
- private:
- LLEventPollResponder(const std::string& pollURL, const LLHost& sender);
- ~LLEventPollResponder();
-
-
- void handleMessage(const LLSD& content);
-
- /* virtual */ void httpFailure();
- /* virtual */ void httpSuccess();
-
- private:
-
- bool mDone;
-
- std::string mPollURL;
- std::string mSender;
-
- LLSD mAcknowledge;
-
- // these are only here for debugging so we can see which poller is which
- static int sCount;
- int mCount;
- S32 mErrorCount;
- };
-
- class LLEventPollEventTimer : public LLEventTimer
- {
- typedef LLPointer<LLEventPollResponder> EventPollResponderPtr;
-
- public:
- LLEventPollEventTimer(F32 period, EventPollResponderPtr responder)
- : LLEventTimer(period), mResponder(responder)
- { }
-
- virtual BOOL tick()
- {
- mResponder->makeRequest();
- return TRUE; // Causes this instance to be deleted.
- }
-
- private:
-
- EventPollResponderPtr mResponder;
- };
-
- //static
- LLHTTPClient::ResponderPtr LLEventPollResponder::start(
- const std::string& pollURL, const LLHost& sender)
- {
- LLHTTPClient::ResponderPtr result = new LLEventPollResponder(pollURL, sender);
- LL_INFOS() << "LLEventPollResponder::start <" << sCount << "> "
- << pollURL << LL_ENDL;
- return result;
- }
-
- void LLEventPollResponder::stop()
- {
- LL_INFOS() << "LLEventPollResponder::stop <" << mCount << "> "
- << mPollURL << LL_ENDL;
- // there should be a way to stop a LLHTTPClient request in progress
- mDone = true;
- }
-
- int LLEventPollResponder::sCount = 0;
-
- LLEventPollResponder::LLEventPollResponder(const std::string& pollURL, const LLHost& sender)
- : mDone(false),
- mPollURL(pollURL),
- mCount(++sCount),
- mErrorCount(0)
- {
- //extract host and port of simulator to set as sender
- LLViewerRegion *regionp = gAgent.getRegion();
- if (!regionp)
- {
- LL_ERRS() << "LLEventPoll initialized before region is added." << LL_ENDL;
- }
- mSender = sender.getIPandPort();
- LL_INFOS() << "LLEventPoll initialized with sender " << mSender << LL_ENDL;
- makeRequest();
- }
-
- LLEventPollResponder::~LLEventPollResponder()
- {
- stop();
- LL_DEBUGS() << "LLEventPollResponder::~Impl <" << mCount << "> "
- << mPollURL << LL_ENDL;
- }
-
- // virtual
- void LLEventPollResponder::completedRaw(const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
- {
- if (getStatus() == HTTP_BAD_GATEWAY)
- {
- // These errors are not parsable as LLSD,
- // which LLHTTPClient::Responder::completedRaw will try to do.
- httpCompleted();
- }
- else
- {
- LLHTTPClient::Responder::completedRaw(channels,buffer);
- }
- }
-
- void LLEventPollResponder::makeRequest()
- {
- LLSD request;
- request["ack"] = mAcknowledge;
- request["done"] = mDone;
-
- LL_DEBUGS() << "LLEventPollResponder::makeRequest <" << mCount << "> ack = "
- << LLSDXMLStreamer(mAcknowledge) << LL_ENDL;
- LLHTTPClient::post(mPollURL, request, this);
- }
-
- void LLEventPollResponder::handleMessage(const LLSD& content)
- {
- std::string msg_name = content["message"];
- LLSD message;
- message["sender"] = mSender;
- message["body"] = content["body"];
- LLMessageSystem::dispatch(msg_name, message);
- }
-
- //virtual
- void LLEventPollResponder::httpFailure()
- {
- if (mDone) return;
-
- // A HTTP_BAD_GATEWAY (502) error is our standard timeout response
- // we get this when there are no events.
- if ( getStatus() == HTTP_BAD_GATEWAY )
- {
- mErrorCount = 0;
- makeRequest();
- }
- else if (mErrorCount < MAX_EVENT_POLL_HTTP_ERRORS)
- {
- ++mErrorCount;
-
- // The 'tick' will return TRUE causing the timer to delete this.
- new LLEventPollEventTimer(EVENT_POLL_ERROR_RETRY_SECONDS
- + mErrorCount * EVENT_POLL_ERROR_RETRY_SECONDS_INC
- , this);
-
- LL_WARNS() << dumpResponse() << LL_ENDL;
- }
- else
- {
- LL_WARNS() << dumpResponse()
- << " [count:" << mCount << "] "
- << (mDone ? " -- done" : "") << LL_ENDL;
- stop();
-
- // At this point we have given up and the viewer will not receive HTTP messages from the simulator.
- // IMs, teleports, about land, selecing land, region crossing and more will all fail.
- // They are essentially disconnected from the region even though some things may still work.
- // Since things won't get better until they relog we force a disconnect now.
-
- // *NOTE:Mani - The following condition check to see if this failing event poll
- // is attached to the Agent's main region. If so we disconnect the viewer.
- // Else... its a child region and we just leave the dead event poll stopped and
- // continue running.
- if(gAgent.getRegion() && gAgent.getRegion()->getHost().getIPandPort() == mSender)
- {
- LL_WARNS() << "Forcing disconnect due to stalled main region event poll." << LL_ENDL;
- LLAppViewer::instance()->forceDisconnect(LLTrans::getString("AgentLostConnection"));
- }
- }
- }
-
- //virtual
- void LLEventPollResponder::httpSuccess()
- {
- LL_DEBUGS() << "LLEventPollResponder::result <" << mCount << ">"
- << (mDone ? " -- done" : "") << LL_ENDL;
-
- if (mDone) return;
-
- mErrorCount = 0;
-
- const LLSD& content = getContent();
- if (!content.isMap() ||
- !content.get("events") ||
- !content.get("id"))
- {
- LL_WARNS() << "received event poll with no events or id key: " << dumpResponse() << LL_ENDL;
- makeRequest();
- return;
- }
-
- mAcknowledge = content["id"];
- LLSD events = content["events"];
-
- if(mAcknowledge.isUndefined())
- {
- LL_WARNS() << "LLEventPollResponder: id undefined" << LL_ENDL;
- }
-
- // was LL_INFOS() but now that CoarseRegionUpdate is TCP @ 1/second, it'd be too verbose for viewer logs. -MG
- LL_DEBUGS() << "LLEventPollResponder::httpSuccess <" << mCount << "> " << events.size() << "events (id "
- << LLSDXMLStreamer(mAcknowledge) << ")" << LL_ENDL;
-
- LLSD::array_const_iterator i = events.beginArray();
- LLSD::array_const_iterator end = events.endArray();
- for (; i != end; ++i)
- {
- if (i->has("message"))
- {
- handleMessage(*i);
- }
- }
-
- makeRequest();
- }
+namespace Details
+{
+
+ class LLEventPollImpl
+ {
+ public:
+ LLEventPollImpl(const LLHost &sender);
+
+ void start(const std::string &url);
+ void stop();
+
+ private:
+ // We will wait RETRY_SECONDS + (errorCount * RETRY_SECONDS_INC) before retrying after an error.
+ // This means we attempt to recover relatively quickly but back off giving more time to recover
+ // until we finally give up after MAX_EVENT_POLL_HTTP_ERRORS attempts.
+ static const F32 EVENT_POLL_ERROR_RETRY_SECONDS;
+ static const F32 EVENT_POLL_ERROR_RETRY_SECONDS_INC;
+ static const S32 MAX_EVENT_POLL_HTTP_ERRORS;
+
+ void eventPollCoro(LLCoros::self& self, std::string url);
+
+ void handleMessage(const LLSD &content);
+
+ bool mDone;
+ LLCore::HttpRequest::ptr_t mHttpRequest;
+ LLCore::HttpRequest::policy_t mHttpPolicy;
+ std::string mSenderIp;
+ int mCounter;
+ LLCoreHttpUtil::HttpCoroutineAdapter::wptr_t mAdapter;
+
+ static int sNextCounter;
+ };
+
+
+ const F32 LLEventPollImpl::EVENT_POLL_ERROR_RETRY_SECONDS = 15.f; // ~ half of a normal timeout.
+ const F32 LLEventPollImpl::EVENT_POLL_ERROR_RETRY_SECONDS_INC = 5.f; // ~ half of a normal timeout.
+ const S32 LLEventPollImpl::MAX_EVENT_POLL_HTTP_ERRORS = 10; // ~5 minutes, by the above rules.
+
+ int LLEventPollImpl::sNextCounter = 1;
+
+
+ LLEventPollImpl::LLEventPollImpl(const LLHost &sender) :
+ mDone(false),
+ mHttpRequest(),
+ mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID),
+ mSenderIp(),
+ mCounter(sNextCounter++)
+
+ {
+ LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp());
+
+ mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest);
+ mHttpPolicy = app_core_http.getPolicy(LLAppCoreHttp::AP_LONG_POLL);
+ mSenderIp = sender.getIPandPort();
+ }
+
+ void LLEventPollImpl::handleMessage(const LLSD& content)
+ {
+ std::string msg_name = content["message"];
+ LLSD message;
+ message["sender"] = mSenderIp;
+ message["body"] = content["body"];
+ LLMessageSystem::dispatch(msg_name, message);
+ }
+
+ void LLEventPollImpl::start(const std::string &url)
+ {
+ if (!url.empty())
+ {
+ std::string coroname =
+ LLCoros::instance().launch("LLEventPollImpl::eventPollCoro",
+ boost::bind(&LLEventPollImpl::eventPollCoro, this, _1, url));
+ LL_INFOS("LLEventPollImpl") << coroname << " with url '" << url << LL_ENDL;
+ }
+ }
+
+ void LLEventPollImpl::stop()
+ {
+ LL_INFOS() << "requesting stop for event poll coroutine <" << mCounter << ">" << LL_ENDL;
+ mDone = true;
+
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter = mAdapter.lock();
+ if (adapter)
+ {
+ // cancel the yielding operation if any.
+ adapter->cancelYieldingOperation();
+ }
+ }
+
+ void LLEventPollImpl::eventPollCoro(LLCoros::self& self, std::string url)
+ {
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("EventPoller", mHttpPolicy));
+ LLSD acknowledge;
+ int errorCount = 0;
+ int counter = mCounter; // saved on the stack for logging.
+
+ LL_INFOS("LLEventPollImpl") << " <" << counter << "> entering coroutine." << LL_ENDL;
+
+ mAdapter = httpAdapter;
+
+ // continually poll for a server update until we've been flagged as
+ // finished
+ while (!mDone)
+ {
+ LLSD request;
+ request["ack"] = acknowledge;
+ request["done"] = mDone;
+
+// LL_DEBUGS("LLEventPollImpl::eventPollCoro") << "<" << counter << "> request = "
+// << LLSDXMLStreamer(request) << LL_ENDL;
+
+ LL_DEBUGS("LLEventPollImpl") << " <" << counter << "> posting and yielding." << LL_ENDL;
+ LLSD result = httpAdapter->postAndYield(self, mHttpRequest, url, request);
+
+// LL_DEBUGS("LLEventPollImpl::eventPollCoro") << "<" << counter << "> result = "
+// << LLSDXMLStreamer(result) << LL_ENDL;
+
+ LLSD httpResults = result["http_result"];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroHandler::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ if (status == LLCore::HttpStatus(HTTP_BAD_GATEWAY))
+ { // A HTTP_BAD_GATEWAY (502) error is our standard timeout response
+ // we get this when there are no events.
+ errorCount = 0;
+ continue;
+ }
+ else if ((status == LLCore::HttpStatus(LLCore::HttpStatus::LLCORE, LLCore::HE_OP_CANCELED)) ||
+ (status == LLCore::HttpStatus(HTTP_NOT_FOUND)))
+ { // Event polling for this server has been canceled. In
+ // some cases the server gets ahead of the viewer and will
+ // return a 404 error (Not Found) before the cancel event
+ // comes back in the queue
+ LL_WARNS() << "Canceling coroutine" << LL_ENDL;
+ break;
+ }
+ LL_WARNS("LLEventPollImpl") << "<" << counter << "> Error result from LLCoreHttpUtil::HttpCoroHandler. Code "
+ << status.toTerseString() << ": '" << httpResults["message"] << "'" << LL_ENDL;
+
+ if (errorCount < MAX_EVENT_POLL_HTTP_ERRORS)
+ { // An unanticipated error has been received from our poll
+ // request. Calculate a timeout and wait for it to expire(sleep)
+ // before trying again. The sleep time is increased by 5 seconds
+ // for each consecutive error.
+ LLEventTimeout timeout;
+ ++errorCount;
+
+ F32 waitToRetry = EVENT_POLL_ERROR_RETRY_SECONDS
+ + errorCount * EVENT_POLL_ERROR_RETRY_SECONDS_INC;
+
+ LL_WARNS("LLEventPollImpl") << "<" << counter << "> Retrying in " << waitToRetry <<
+ " seconds, error count is now " << errorCount << LL_ENDL;
+
+ timeout.eventAfter(waitToRetry, LLSD());
+ waitForEventOn(self, timeout);
+
+ if (mDone)
+ break;
+ LL_INFOS("LLEventPollImpl") << "<" << counter << "> About to retry request." << LL_ENDL;
+ continue;
+ }
+ else
+ {
+ // At this point we have given up and the viewer will not receive HTTP messages from the simulator.
+ // IMs, teleports, about land, selecting land, region crossing and more will all fail.
+ // They are essentially disconnected from the region even though some things may still work.
+ // Since things won't get better until they relog we force a disconnect now.
+ mDone = true;
+
+ // *NOTE:Mani - The following condition check to see if this failing event poll
+ // is attached to the Agent's main region. If so we disconnect the viewer.
+ // Else... its a child region and we just leave the dead event poll stopped and
+ // continue running.
+ if (gAgent.getRegion() && gAgent.getRegion()->getHost().getIPandPort() == mSenderIp)
+ {
+ LL_WARNS("LLEventPollImpl") << "< " << counter << "> Forcing disconnect due to stalled main region event poll." << LL_ENDL;
+ LLAppViewer::instance()->forceDisconnect(LLTrans::getString("AgentLostConnection"));
+ }
+ break;
+ }
+ }
+
+ errorCount = 0;
+
+ if (!result.isMap() ||
+ !result.get("events") ||
+ !result.get("id"))
+ {
+ LL_WARNS("LLEventPollImpl") << " <" << counter << "> received event poll with no events or id key: " << LLSDXMLStreamer(result) << LL_ENDL;
+ continue;
+ }
+
+ acknowledge = result["id"];
+ LLSD events = result["events"];
+
+ if (acknowledge.isUndefined())
+ {
+ LL_WARNS("LLEventPollImpl") << " id undefined" << LL_ENDL;
+ }
+
+ // was LL_INFOS() but now that CoarseRegionUpdate is TCP @ 1/second, it'd be too verbose for viewer logs. -MG
+ LL_DEBUGS("LLEventPollImpl") << " <" << counter << "> " << events.size() << "events (id " << LLSDXMLStreamer(acknowledge) << ")" << LL_ENDL;
+
+ LLSD::array_const_iterator i = events.beginArray();
+ LLSD::array_const_iterator end = events.endArray();
+ for (; i != end; ++i)
+ {
+ if (i->has("message"))
+ {
+ handleMessage(*i);
+ }
+ }
+ }
+ LL_INFOS("LLEventPollImpl") << " <" << counter << "> Leaving coroutine." << LL_ENDL;
+ }
+
+}
}
-LLEventPoll::LLEventPoll(const std::string& poll_url, const LLHost& sender)
- : mImpl(LLEventPollResponder::start(poll_url, sender))
- { }
+LLEventPoll::LLEventPoll(const std::string& poll_url, const LLHost& sender):
+ mImpl()
+{
+ mImpl = boost::unique_ptr<LLEventPolling::Details::LLEventPollImpl>
+ (new LLEventPolling::Details::LLEventPollImpl(sender));
+ mImpl->start(poll_url);
+}
LLEventPoll::~LLEventPoll()
{
- LLHTTPClient::Responder* responderp = mImpl.get();
- LLEventPollResponder* event_poll_responder = dynamic_cast<LLEventPollResponder*>(responderp);
- if (event_poll_responder) event_poll_responder->stop();
+ mImpl->stop();
+
}
diff --git a/indra/newview/lleventpoll.h b/indra/newview/lleventpoll.h
index e8d98062aa..e32b4ed322 100755
--- a/indra/newview/lleventpoll.h
+++ b/indra/newview/lleventpoll.h
@@ -28,9 +28,23 @@
#define LL_LLEVENTPOLL_H
#include "llhttpclient.h"
+#include "boost/move/unique_ptr.hpp"
+
+namespace boost
+{
+ using ::boost::movelib::unique_ptr; // move unique_ptr into the boost namespace.
+}
class LLHost;
+namespace LLEventPolling
+{
+namespace Details
+{
+ class LLEventPollImpl;
+}
+}
+
class LLEventPoll
///< implements the viewer side of server-to-viewer pushed events.
@@ -40,11 +54,11 @@ public:
///< Start polling the URL.
virtual ~LLEventPoll();
- ///< will stop polling, cancelling any poll in progress.
+ ///< will stop polling, canceling any poll in progress.
private:
- LLHTTPClient::ResponderPtr mImpl;
+ boost::unique_ptr<LLEventPolling::Details::LLEventPollImpl> mImpl;
};
diff --git a/indra/newview/llhttpretrypolicy.cpp b/indra/newview/llhttpretrypolicy.cpp
index 2d4ce6c883..530eb685fa 100755
--- a/indra/newview/llhttpretrypolicy.cpp
+++ b/indra/newview/llhttpretrypolicy.cpp
@@ -87,7 +87,7 @@ void LLAdaptiveRetryPolicy::onFailure(const LLCore::HttpResponse *response)
F32 retry_header_time;
const LLCore::HttpHeaders *headers = response->getHeaders();
bool has_retry_header_time = getRetryAfter(headers,retry_header_time);
- onFailureCommon(response->getStatus().mType, has_retry_header_time, retry_header_time);
+ onFailureCommon(response->getStatus().getType(), has_retry_header_time, retry_header_time);
}
void LLAdaptiveRetryPolicy::onFailureCommon(S32 status, bool has_retry_header_time, F32 retry_header_time)
diff --git a/indra/newview/llmaterialmgr.cpp b/indra/newview/llmaterialmgr.cpp
index a1f6a01aa0..8a726ec7c9 100755
--- a/indra/newview/llmaterialmgr.cpp
+++ b/indra/newview/llmaterialmgr.cpp
@@ -36,6 +36,9 @@
#include "llviewerobjectlist.h"
#include "llviewerregion.h"
#include "llworld.h"
+#include "llhttpsdhandler.h"
+#include "httpcommon.h"
+#include "llcorehttputil.h"
/**
* Materials cap parameters
@@ -59,56 +62,51 @@
#define MATERIALS_PUT_THROTTLE_SECS 1.f
#define MATERIALS_PUT_MAX_ENTRIES 50
-/**
- * LLMaterialsResponder helper class
- */
-class LLMaterialsResponder : public LLHTTPClient::Responder
+
+class LLMaterialHttpHandler : public LLHttpSDHandler
{
-public:
- typedef boost::function<void (bool, const LLSD&)> CallbackFunction;
+public:
+ typedef boost::function<void(bool, const LLSD&)> CallbackFunction;
+ typedef boost::shared_ptr<LLMaterialHttpHandler> ptr_t;
+
+ LLMaterialHttpHandler(const std::string& method, CallbackFunction cback);
- LLMaterialsResponder(const std::string& pMethod, const std::string& pCapabilityURL, CallbackFunction pCallback);
- virtual ~LLMaterialsResponder();
+ virtual ~LLMaterialHttpHandler();
- virtual void httpSuccess();
- virtual void httpFailure();
+protected:
+ virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content);
+ virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status);
private:
std::string mMethod;
- std::string mCapabilityURL;
CallbackFunction mCallback;
};
-LLMaterialsResponder::LLMaterialsResponder(const std::string& pMethod, const std::string& pCapabilityURL, CallbackFunction pCallback)
- : LLHTTPClient::Responder()
- , mMethod(pMethod)
- , mCapabilityURL(pCapabilityURL)
- , mCallback(pCallback)
+LLMaterialHttpHandler::LLMaterialHttpHandler(const std::string& method, CallbackFunction cback):
+ LLHttpSDHandler(),
+ mMethod(method),
+ mCallback(cback)
{
+
}
-LLMaterialsResponder::~LLMaterialsResponder()
+LLMaterialHttpHandler::~LLMaterialHttpHandler()
{
}
-void LLMaterialsResponder::httpSuccess()
+void LLMaterialHttpHandler::onSuccess(LLCore::HttpResponse * response, const LLSD &content)
{
- const LLSD& pContent = getContent();
-
LL_DEBUGS("Materials") << LL_ENDL;
- mCallback(true, pContent);
+ mCallback(true, content);
}
-void LLMaterialsResponder::httpFailure()
+void LLMaterialHttpHandler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status)
{
- U32 pStatus = (U32) getStatus();
- const std::string& pReason = getReason();
-
LL_WARNS("Materials")
<< "\n--------------------------------------------------------------------------\n"
- << mMethod << " Error[" << pStatus << "] cannot access cap '" << MATERIALS_CAPABILITY_NAME
- << "'\n with url '" << mCapabilityURL << "' because " << pReason
+ << mMethod << " Error[" << status.toULong() << "] cannot access cap '" << MATERIALS_CAPABILITY_NAME
+ << "'\n with url '" << response->getRequestURL() << "' because " << status.toString()
<< "\n--------------------------------------------------------------------------"
<< LL_ENDL;
@@ -116,12 +114,35 @@ void LLMaterialsResponder::httpFailure()
mCallback(false, emptyResult);
}
+
+
/**
* LLMaterialMgr class
*/
-
-LLMaterialMgr::LLMaterialMgr()
+LLMaterialMgr::LLMaterialMgr():
+ mGetQueue(),
+ mGetPending(),
+ mGetCallbacks(),
+ mGetTECallbacks(),
+ mGetAllQueue(),
+ mGetAllRequested(),
+ mGetAllPending(),
+ mGetAllCallbacks(),
+ mPutQueue(),
+ mMaterials(),
+ mHttpRequest(),
+ mHttpHeaders(),
+ mHttpOptions(),
+ mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID),
+ mHttpPriority(0)
{
+ LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp());
+
+ mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest());
+ mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders(), false);
+ mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions(), false);
+ mHttpPolicy = app_core_http.getPolicy(LLAppCoreHttp::AP_MATERIALS);
+
mMaterials.insert(std::pair<LLMaterialID, LLMaterialPtr>(LLMaterialID::null, LLMaterialPtr(NULL)));
gIdleCallbacks.addFunction(&LLMaterialMgr::onIdle, NULL);
LLWorld::instance().setRegionRemovedCallback(boost::bind(&LLMaterialMgr::onRegionRemoved, this, _1));
@@ -554,6 +575,8 @@ void LLMaterialMgr::onIdle(void*)
{
instancep->processPutQueue();
}
+
+ instancep->mHttpRequest->update(0L);
}
void LLMaterialMgr::processGetQueue()
@@ -629,10 +652,26 @@ void LLMaterialMgr::processGetQueue()
LLSD postData = LLSD::emptyMap();
postData[MATERIALS_CAP_ZIP_FIELD] = materialBinary;
- LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("POST", capURL, boost::bind(&LLMaterialMgr::onGetResponse, this, _1, _2, region_id));
- LL_DEBUGS("Materials") << "POSTing to region '" << regionp->getName() << "' at '"<< capURL << " for " << materialsData.size() << " materials."
+ LLMaterialHttpHandler * handler =
+ new LLMaterialHttpHandler("POST",
+ boost::bind(&LLMaterialMgr::onGetResponse, this, _1, _2, region_id)
+ );
+
+ LL_DEBUGS("Materials") << "POSTing to region '" << regionp->getName() << "' at '" << capURL << " for " << materialsData.size() << " materials."
<< "\ndata: " << ll_pretty_print_sd(materialsData) << LL_ENDL;
- LLHTTPClient::post(capURL, postData, materialsResponder);
+
+ LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(mHttpRequest,
+ mHttpPolicy, mHttpPriority, capURL,
+ postData, mHttpOptions, mHttpHeaders, handler);
+
+ if (handle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ delete handler;
+ LLCore::HttpStatus status = mHttpRequest->getStatus();
+ LL_ERRS("Meterials") << "Failed to execute material POST. Status = " <<
+ status.toULong() << "\"" << status.toString() << "\"" << LL_ENDL;
+ }
+
regionp->resetMaterialsCapThrottle();
}
}
@@ -667,8 +706,22 @@ void LLMaterialMgr::processGetAllQueue()
}
LL_DEBUGS("Materials") << "GET all for region " << region_id << "url " << capURL << LL_ENDL;
- LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("GET", capURL, boost::bind(&LLMaterialMgr::onGetAllResponse, this, _1, _2, *itRegion));
- LLHTTPClient::get(capURL, materialsResponder);
+ LLMaterialHttpHandler *handler =
+ new LLMaterialHttpHandler("GET",
+ boost::bind(&LLMaterialMgr::onGetAllResponse, this, _1, _2, *itRegion)
+ );
+
+ LLCore::HttpHandle handle = mHttpRequest->requestGet(mHttpPolicy, mHttpPriority, capURL,
+ mHttpOptions.get(), mHttpHeaders.get(), handler);
+
+ if (handle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ delete handler;
+ LLCore::HttpStatus status = mHttpRequest->getStatus();
+ LL_ERRS("Meterials") << "Failed to execute material GET. Status = " <<
+ status.toULong() << "\"" << status.toString() << "\"" << LL_ENDL;
+ }
+
regionp->resetMaterialsCapThrottle();
mGetAllPending.insert(std::pair<LLUUID, F64>(region_id, LLFrameTimer::getTotalSeconds()));
mGetAllQueue.erase(itRegion); // Invalidates region_id
@@ -755,8 +808,24 @@ void LLMaterialMgr::processPutQueue()
putData[MATERIALS_CAP_ZIP_FIELD] = materialBinary;
LL_DEBUGS("Materials") << "put for " << itRequest->second.size() << " faces to region " << itRequest->first->getName() << LL_ENDL;
- LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("PUT", capURL, boost::bind(&LLMaterialMgr::onPutResponse, this, _1, _2));
- LLHTTPClient::put(capURL, putData, materialsResponder);
+
+ LLMaterialHttpHandler * handler =
+ new LLMaterialHttpHandler("PUT",
+ boost::bind(&LLMaterialMgr::onPutResponse, this, _1, _2)
+ );
+
+ LLCore::HttpHandle handle = LLCoreHttpUtil::requestPutWithLLSD(
+ mHttpRequest, mHttpPolicy, mHttpPriority, capURL,
+ putData, mHttpOptions, mHttpHeaders, handler);
+
+ if (handle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ delete handler;
+ LLCore::HttpStatus status = mHttpRequest->getStatus();
+ LL_ERRS("Meterials") << "Failed to execute material PUT. Status = " <<
+ status.toULong() << "\"" << status.toString() << "\"" << LL_ENDL;
+ }
+
regionp->resetMaterialsCapThrottle();
}
else
diff --git a/indra/newview/llmaterialmgr.h b/indra/newview/llmaterialmgr.h
index e83f1f4e01..ef202d24ba 100644
--- a/indra/newview/llmaterialmgr.h
+++ b/indra/newview/llmaterialmgr.h
@@ -30,6 +30,9 @@
#include "llmaterial.h"
#include "llmaterialid.h"
#include "llsingleton.h"
+#include "httprequest.h"
+#include "httpheaders.h"
+#include "httpoptions.h"
class LLViewerRegion;
@@ -56,7 +59,7 @@ public:
void put(const LLUUID& object_id, const U8 te, const LLMaterial& material);
void remove(const LLUUID& object_id, const U8 te);
-protected:
+private:
void clearGetQueues(const LLUUID& region_id);
bool isGetPending(const LLUUID& region_id, const LLMaterialID& material_id) const;
bool isGetAllPending(const LLUUID& region_id) const;
@@ -72,16 +75,7 @@ protected:
void onPutResponse(bool success, const LLSD& content);
void onRegionRemoved(LLViewerRegion* regionp);
-protected:
- typedef std::set<LLMaterialID> material_queue_t;
- typedef std::map<LLUUID, material_queue_t> get_queue_t;
- get_queue_t mGetQueue;
- typedef std::pair<const LLUUID, LLMaterialID> pending_material_t;
- typedef std::map<const pending_material_t, F64> get_pending_map_t;
- get_pending_map_t mGetPending;
- typedef std::map<LLMaterialID, get_callback_t*> get_callback_map_t;
- get_callback_map_t mGetCallbacks;
-
+private:
// struct for TE-specific material ID query
class TEMaterialPair
{
@@ -108,22 +102,37 @@ protected:
bool operator()(const TEMaterialPair& left, const TEMaterialPair& right) const { return left < right; }
};
- typedef boost::unordered_map<TEMaterialPair, get_callback_te_t*, TEMaterialPairHasher> get_callback_te_map_t;
- get_callback_te_map_t mGetTECallbacks;
+ typedef std::set<LLMaterialID> material_queue_t;
+ typedef std::map<LLUUID, material_queue_t> get_queue_t;
+ typedef std::pair<const LLUUID, LLMaterialID> pending_material_t;
+ typedef std::map<const pending_material_t, F64> get_pending_map_t;
+ typedef std::map<LLMaterialID, get_callback_t*> get_callback_map_t;
+
+ typedef boost::unordered_map<TEMaterialPair, get_callback_te_t*, TEMaterialPairHasher> get_callback_te_map_t;
typedef std::set<LLUUID> getall_queue_t;
- getall_queue_t mGetAllQueue;
- getall_queue_t mGetAllRequested;
typedef std::map<LLUUID, F64> getall_pending_map_t;
- getall_pending_map_t mGetAllPending;
typedef std::map<LLUUID, getall_callback_t*> getall_callback_map_t;
- getall_callback_map_t mGetAllCallbacks;
-
typedef std::map<U8, LLMaterial> facematerial_map_t;
typedef std::map<LLUUID, facematerial_map_t> put_queue_t;
- put_queue_t mPutQueue;
- material_map_t mMaterials;
+ get_queue_t mGetQueue;
+ get_pending_map_t mGetPending;
+ get_callback_map_t mGetCallbacks;
+
+ get_callback_te_map_t mGetTECallbacks;
+ getall_queue_t mGetAllQueue;
+ getall_queue_t mGetAllRequested;
+ getall_pending_map_t mGetAllPending;
+ getall_callback_map_t mGetAllCallbacks;
+ put_queue_t mPutQueue;
+ material_map_t mMaterials;
+
+ LLCore::HttpRequest::ptr_t mHttpRequest;
+ LLCore::HttpHeaders::ptr_t mHttpHeaders;
+ LLCore::HttpOptions::ptr_t mHttpOptions;
+ LLCore::HttpRequest::policy_t mHttpPolicy;
+ LLCore::HttpRequest::priority_t mHttpPriority;
U32 getMaxEntries(const LLViewerRegion* regionp);
};
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 92e07c52a5..36dd778746 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -78,6 +78,9 @@
#include "llviewerdisplay.h"
#include "llviewerwindow.h"
#include "llprogressview.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
+#include "llcorehttputil.h"
#ifdef LL_WINDOWS
#pragma warning(disable:4355)
@@ -105,7 +108,8 @@ typedef std::map<std::string, std::string> CapabilityMap;
static void log_capabilities(const CapabilityMap &capmap);
-class LLViewerRegionImpl {
+class LLViewerRegionImpl
+{
public:
LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host)
: mHost(host),
@@ -189,212 +193,281 @@ public:
//spatial partitions for objects in this region
std::vector<LLViewerOctreePartition*> mObjectPartition;
- LLVector3 mLastCameraOrigin;
- U32 mLastCameraUpdate;
-};
-
-// support for secondlife:///app/region/{REGION} SLapps
-// N.B. this is defined to work exactly like the classic secondlife://{REGION}
-// However, the later syntax cannot support spaces in the region name because
-// spaces (and %20 chars) are illegal in the hostname of an http URL. Some
-// browsers let you get away with this, but some do not (such as Qt's Webkit).
-// Hence we introduced the newer secondlife:///app/region alternative.
-class LLRegionHandler : public LLCommandHandler
-{
-public:
- // requests will be throttled from a non-trusted browser
- LLRegionHandler() : LLCommandHandler("region", UNTRUSTED_THROTTLE) {}
-
- bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
- {
- // make sure that we at least have a region name
- int num_params = params.size();
- if (num_params < 1)
- {
- return false;
- }
+ LLVector3 mLastCameraOrigin;
+ U32 mLastCameraUpdate;
- // build a secondlife://{PLACE} SLurl from this SLapp
- std::string url = "secondlife://";
- for (int i = 0; i < num_params; i++)
- {
- if (i > 0)
- {
- url += "/";
- }
- url += params[i].asString();
- }
-
- // Process the SLapp as if it was a secondlife://{PLACE} SLurl
- LLURLDispatcher::dispatch(url, "clicked", web, true);
- return true;
- }
+ void requestBaseCapabilitiesCoro(LLCoros::self& self, U64 regionHandle);
+ void requestBaseCapabilitiesCompleteCoro(LLCoros::self& self, U64 regionHandle);
+ void requestSimulatorFeatureCoro(LLCoros::self& self, std::string url, U64 regionHandle);
};
-LLRegionHandler gRegionHandler;
-class BaseCapabilitiesComplete : public LLHTTPClient::Responder
+void LLViewerRegionImpl::requestBaseCapabilitiesCoro(LLCoros::self& self, U64 regionHandle)
{
- LOG_CLASS(BaseCapabilitiesComplete);
-public:
- BaseCapabilitiesComplete(U64 region_handle, S32 id)
- : mRegionHandle(region_handle), mID(id)
- { }
- virtual ~BaseCapabilitiesComplete()
- { }
-
- static BaseCapabilitiesComplete* build( U64 region_handle, S32 id )
- {
- return new BaseCapabilitiesComplete(region_handle, id);
- }
-
-private:
- /* virtual */void httpFailure()
- {
- LL_WARNS("AppInit", "Capabilities") << dumpResponse() << LL_ENDL;
- LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
- if (regionp)
- {
- regionp->failedSeedCapability();
- }
- }
-
- /* virtual */ void httpSuccess()
- {
- LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
- if(!regionp) //region was removed
- {
- LL_WARNS("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL;
- return ;
- }
- if( mID != regionp->getHttpResponderID() ) // region is no longer referring to this responder
- {
- LL_WARNS("AppInit", "Capabilities") << "Received results for a stale http responder!" << LL_ENDL;
- regionp->failedSeedCapability();
- return ;
- }
-
- const LLSD& content = getContent();
- if (!content.isMap())
- {
- failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
- return;
- }
- LLSD::map_const_iterator iter;
- for(iter = content.beginMap(); iter != content.endMap(); ++iter)
- {
- regionp->setCapability(iter->first, iter->second);
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("BaseCapabilitiesRequest", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
- LL_DEBUGS("AppInit", "Capabilities")
- << "Capability '" << iter->first << "' is '" << iter->second << "'" << LL_ENDL;
+ LLSD result;
+ LLViewerRegion *regionp = NULL;
- /* HACK we're waiting for the ServerReleaseNotes */
- if (iter->first == "ServerReleaseNotes" && regionp->getReleaseNotesRequested())
- {
- regionp->showReleaseNotes();
- }
- }
-
- regionp->setCapabilitiesReceived(true);
+ // This loop is used for retrying a capabilities request.
+ do
+ {
+ regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
+ if (!regionp) //region was removed
+ {
+ LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities for region that no longer exists!" << LL_ENDL;
+ return; // this error condition is not recoverable.
+ }
+
+ std::string url = regionp->getCapability("Seed");
+ if (url.empty())
+ {
+ LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url!" << LL_ENDL;
+ return; // this error condition is not recoverable.
+ }
+
+ // After a few attempts, continue login. But keep trying to get the caps:
+ if (mSeedCapAttempts >= mSeedCapMaxAttemptsBeforeLogin &&
+ STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState())
+ {
+ LLStartUp::setStartupState(STATE_SEED_CAP_GRANTED);
+ }
+
+ if (mSeedCapAttempts > mSeedCapMaxAttempts)
+ {
+ // *TODO: Give a user pop-up about this error?
+ LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities from '" << url << "' after " << mSeedCapAttempts << " attempts. Giving up!" << LL_ENDL;
+ return; // this error condition is not recoverable.
+ }
+
+ S32 id = ++mHttpResponderID;
+ ++mSeedCapAttempts;
+
+ LLSD capabilityNames = LLSD::emptyArray();
+ buildCapabilityNames(capabilityNames);
+
+ LL_INFOS("AppInit", "Capabilities") << "Requesting seed from " << url
+ << " (attempt #" << mSeedCapAttempts << ")" << LL_ENDL;
+
+ regionp = NULL;
+ result = httpAdapter->postAndYield(self, httpRequest, url, capabilityNames);
+
+ regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
+ if (!regionp) //region was removed
+ {
+ LL_WARNS("AppInit", "Capabilities") << "Received capabilities for region that no longer exists!" << LL_ENDL;
+ return; // this error condition is not recoverable.
+ }
+
+ if (id != mHttpResponderID) // region is no longer referring to this request
+ {
+ LL_WARNS("AppInit", "Capabilities") << "Received results for a stale capabilities request!" << LL_ENDL;
+ // setup for retry.
+ continue;
+ }
+
+ LLSD httpResults = result["http_result"];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroHandler::getStatusFromLLSD(httpResults);
+ if (!status)
+ {
+ LL_WARNS("AppInit", "Capabilities") << "HttpStatus error " << LL_ENDL;
+ // setup for retry.
+ continue;
+ }
+
+ // remove the http_result from the llsd
+ result.erase("http_result");
+
+ LLSD::map_const_iterator iter;
+ for (iter = result.beginMap(); iter != result.endMap(); ++iter)
+ {
+ regionp->setCapability(iter->first, iter->second);
+
+ LL_DEBUGS("AppInit", "Capabilities")
+ << "Capability '" << iter->first << "' is '" << iter->second << "'" << LL_ENDL;
+ }
+
+ regionp->setCapabilitiesReceived(true);
+
+ if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState())
+ {
+ LLStartUp::setStartupState(STATE_SEED_CAP_GRANTED);
+ }
+
+ break;
+ }
+ while (true);
+
+ if (regionp && regionp->isCapabilityAvailable("ServerReleaseNotes") &&
+ regionp->getReleaseNotesRequested())
+ { // *HACK: we're waiting for the ServerReleaseNotes
+ regionp->showReleaseNotes();
+ }
- if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState())
- {
- LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED );
- }
- }
+}
-private:
- U64 mRegionHandle;
- S32 mID;
-};
-class BaseCapabilitiesCompleteTracker : public LLHTTPClient::Responder
+void LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro(LLCoros::self& self, U64 regionHandle)
{
- LOG_CLASS(BaseCapabilitiesCompleteTracker);
-public:
- BaseCapabilitiesCompleteTracker( U64 region_handle)
- : mRegionHandle(region_handle)
- { }
-
- virtual ~BaseCapabilitiesCompleteTracker()
- { }
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("BaseCapabilitiesRequest", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
- static BaseCapabilitiesCompleteTracker* build( U64 region_handle )
- {
- return new BaseCapabilitiesCompleteTracker( region_handle );
- }
-
-private:
- /* virtual */ void httpFailure()
- {
- LL_WARNS() << dumpResponse() << LL_ENDL;
- }
-
- /* virtual */ void httpSuccess()
- {
- LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
- if( !regionp )
- {
- LL_WARNS("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL;
- return ;
- }
+ LLSD result;
+ LLViewerRegion *regionp = NULL;
- const LLSD& content = getContent();
- if (!content.isMap())
- {
- failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
- return;
- }
- LLSD::map_const_iterator iter;
- for(iter = content.beginMap(); iter != content.endMap(); ++iter)
- {
- regionp->setCapabilityDebug(iter->first, iter->second);
- //LL_INFOS()<<"BaseCapabilitiesCompleteTracker New Caps "<<iter->first<<" "<< iter->second<<LL_ENDL;
- }
-
- if ( regionp->getRegionImpl()->mCapabilities.size() != regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() )
- {
- LL_WARNS("AppInit", "Capabilities")
- << "Sim sent duplicate base caps that differ in size from what we initially received - most likely content. "
- << "mCapabilities == " << regionp->getRegionImpl()->mCapabilities.size()
- << " mSecondCapabilitiesTracker == " << regionp->getRegionImpl()->mSecondCapabilitiesTracker.size()
- << LL_ENDL;
+ // This loop is used for retrying a capabilities request.
+ do
+ {
+ regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
+ if (!regionp) //region was removed
+ {
+ LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities for region that no longer exists!" << LL_ENDL;
+ break; // this error condition is not recoverable.
+ }
+
+ std::string url = regionp->getCapabilityDebug("Seed");
+ if (url.empty())
+ {
+ LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url!" << LL_ENDL;
+ break; // this error condition is not recoverable.
+ }
+
+ LLSD capabilityNames = LLSD::emptyArray();
+ buildCapabilityNames(capabilityNames);
+
+ LL_INFOS("AppInit", "Capabilities") << "Requesting second Seed from " << url << LL_ENDL;
+
+ regionp = NULL;
+ result = httpAdapter->postAndYield(self, httpRequest, url, capabilityNames);
+
+ LLSD httpResults = result["http_result"];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroHandler::getStatusFromLLSD(httpResults);
+ if (!status)
+ {
+ LL_WARNS("AppInit", "Capabilities") << "HttpStatus error " << LL_ENDL;
+ break; // no retry
+ }
+
+ regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
+ if (!regionp) //region was removed
+ {
+ LL_WARNS("AppInit", "Capabilities") << "Received capabilities for region that no longer exists!" << LL_ENDL;
+ break; // this error condition is not recoverable.
+ }
+
+ // remove the http_result from the llsd
+ result.erase("http_result");
+
+ LLSD::map_const_iterator iter;
+ for (iter = result.beginMap(); iter != result.endMap(); ++iter)
+ {
+ regionp->setCapabilityDebug(iter->first, iter->second);
+ //LL_INFOS()<<"BaseCapabilitiesCompleteTracker New Caps "<<iter->first<<" "<< iter->second<<LL_ENDL;
+ }
+
+ if (mCapabilities.size() != mSecondCapabilitiesTracker.size())
+ {
+ LL_WARNS("AppInit", "Capabilities")
+ << "Sim sent duplicate base caps that differ in size from what we initially received - most likely content. "
+ << "mCapabilities == " << mCapabilities.size()
+ << " mSecondCapabilitiesTracker == " << mSecondCapabilitiesTracker.size()
+ << LL_ENDL;
#ifdef DEBUG_CAPS_GRANTS
- LL_WARNS("AppInit", "Capabilities")
- << "Initial Base capabilities: " << LL_ENDL;
+ LL_WARNS("AppInit", "Capabilities")
+ << "Initial Base capabilities: " << LL_ENDL;
- log_capabilities(regionp->getRegionImpl()->mCapabilities);
+ log_capabilities(mCapabilities);
- LL_WARNS("AppInit", "Capabilities")
- << "Latest base capabilities: " << LL_ENDL;
+ LL_WARNS("AppInit", "Capabilities")
+ << "Latest base capabilities: " << LL_ENDL;
- log_capabilities(regionp->getRegionImpl()->mSecondCapabilitiesTracker);
+ log_capabilities(mSecondCapabilitiesTracker);
#endif
- if (regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() > regionp->getRegionImpl()->mCapabilities.size() )
- {
- // *HACK Since we were granted more base capabilities in this grant request than the initial, replace
- // the old with the new. This shouldn't happen i.e. we should always get the same capabilities from a
- // sim. The simulator fix from SH-3895 should prevent it from happening, at least in the case of the
- // inventory api capability grants.
-
- // Need to clear a std::map before copying into it because old keys take precedence.
- regionp->getRegionImplNC()->mCapabilities.clear();
- regionp->getRegionImplNC()->mCapabilities = regionp->getRegionImpl()->mSecondCapabilitiesTracker;
- }
- }
- else
- {
- LL_DEBUGS("CrossingCaps") << "Sim sent multiple base cap grants with matching sizes." << LL_ENDL;
- }
- regionp->getRegionImplNC()->mSecondCapabilitiesTracker.clear();
- }
+ if (mSecondCapabilitiesTracker.size() > mCapabilities.size())
+ {
+ // *HACK Since we were granted more base capabilities in this grant request than the initial, replace
+ // the old with the new. This shouldn't happen i.e. we should always get the same capabilities from a
+ // sim. The simulator fix from SH-3895 should prevent it from happening, at least in the case of the
+ // inventory api capability grants.
+ // Need to clear a std::map before copying into it because old keys take precedence.
+ mCapabilities.clear();
+ mCapabilities = mSecondCapabilitiesTracker;
+ }
+ }
+ else
+ {
+ LL_DEBUGS("CrossingCaps") << "Sim sent multiple base cap grants with matching sizes." << LL_ENDL;
+ }
+ mSecondCapabilitiesTracker.clear();
+ }
+ while (false);
-private:
- U64 mRegionHandle;
-};
+}
+
+void LLViewerRegionImpl::requestSimulatorFeatureCoro(LLCoros::self& self, std::string url, U64 regionHandle)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("BaseCapabilitiesRequest", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLViewerRegion *regionp = NULL;
+ S32 attemptNumber = 0;
+ // This loop is used for retrying a capabilities request.
+ do
+ {
+ ++attemptNumber;
+
+ if (attemptNumber > MAX_CAP_REQUEST_ATTEMPTS)
+ {
+ LL_WARNS("AppInit", "SimulatorFeatures") << "Retries count exceeded attempting to get Simulator feature from "
+ << url << LL_ENDL;
+ break;
+ }
+
+ regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
+ if (!regionp) //region was removed
+ {
+ LL_WARNS("AppInit", "SimulatorFeatures") << "Attempting to request Sim Feature for region that no longer exists!" << LL_ENDL;
+ break; // this error condition is not recoverable.
+ }
+
+ regionp = NULL;
+ LLSD result = httpAdapter->getAndYield(self, httpRequest, url);
+
+ LLSD httpResults = result["http_result"];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroHandler::getStatusFromLLSD(httpResults);
+ if (!status)
+ {
+ LL_WARNS("AppInit", "SimulatorFeatures") << "HttpStatus error retrying" << LL_ENDL;
+ continue;
+ }
+
+ // remove the http_result from the llsd
+ result.erase("http_result");
+
+ regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
+ if (!regionp) //region was removed
+ {
+ LL_WARNS("AppInit", "SimulatorFeatures") << "Attempting to set Sim Feature for region that no longer exists!" << LL_ENDL;
+ break; // this error condition is not recoverable.
+ }
+
+ regionp->setSimulatorFeatures(result);
+
+ break;
+ }
+ while (true);
+
+}
LLViewerRegion::LLViewerRegion(const U64 &handle,
const LLHost &host,
@@ -2797,15 +2870,14 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
if (getCapability("Seed") == url)
{
setCapabilityDebug("Seed", url);
- LL_DEBUGS("CrossingCaps") << "Received duplicate seed capability, posting to seed " <<
+ LL_WARNS("CrossingCaps") << "Received duplicate seed capability, posting to seed " <<
url << LL_ENDL;
//Instead of just returning we build up a second set of seed caps and compare them
//to the "original" seed cap received and determine why there is problem!
- LLSD capabilityNames = LLSD::emptyArray();
- mImpl->buildCapabilityNames( capabilityNames );
- LLHTTPClient::post( url, capabilityNames, BaseCapabilitiesCompleteTracker::build(getHandle() ),
- LLSD(), CAP_REQUEST_TIMEOUT );
+ std::string coroname =
+ LLCoros::instance().launch("LLEnvironmentRequest::requestBaseCapabilitiesCompleteCoro",
+ boost::bind(&LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro, mImpl, _1, getHandle()));
return;
}
@@ -2815,15 +2887,11 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
mImpl->mCapabilities.clear();
setCapability("Seed", url);
- LLSD capabilityNames = LLSD::emptyArray();
- mImpl->buildCapabilityNames(capabilityNames);
-
- LL_INFOS() << "posting to seed " << url << LL_ENDL;
+ std::string coroname =
+ LLCoros::instance().launch("LLEnvironmentRequest::environmentRequestCoro",
+ boost::bind(&LLViewerRegionImpl::requestBaseCapabilitiesCoro, mImpl, _1, getHandle()));
- S32 id = ++mImpl->mHttpResponderID;
- LLHTTPClient::post(url, capabilityNames,
- BaseCapabilitiesComplete::build(getHandle(), id),
- LLSD(), CAP_REQUEST_TIMEOUT);
+ LL_INFOS("AppInit", "Capabilities") << "Launching " << coroname << " requesting seed capabilities from " << url << LL_ENDL;
}
S32 LLViewerRegion::getNumSeedCapRetries()
@@ -2831,94 +2899,6 @@ S32 LLViewerRegion::getNumSeedCapRetries()
return mImpl->mSeedCapAttempts;
}
-void LLViewerRegion::failedSeedCapability()
-{
- // Should we retry asking for caps?
- mImpl->mSeedCapAttempts++;
- std::string url = getCapability("Seed");
- if ( url.empty() )
- {
- LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url for retries!" << LL_ENDL;
- return;
- }
- // After a few attempts, continue login. We will keep trying once in-world:
- if ( mImpl->mSeedCapAttempts >= mImpl->mSeedCapMaxAttemptsBeforeLogin &&
- STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState() )
- {
- LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED );
- }
-
- if ( mImpl->mSeedCapAttempts < mImpl->mSeedCapMaxAttempts)
- {
- LLSD capabilityNames = LLSD::emptyArray();
- mImpl->buildCapabilityNames(capabilityNames);
-
- LL_INFOS() << "posting to seed " << url << " (retry "
- << mImpl->mSeedCapAttempts << ")" << LL_ENDL;
-
- S32 id = ++mImpl->mHttpResponderID;
- LLHTTPClient::post(url, capabilityNames,
- BaseCapabilitiesComplete::build(getHandle(), id),
- LLSD(), CAP_REQUEST_TIMEOUT);
- }
- else
- {
- // *TODO: Give a user pop-up about this error?
- LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities from '" << url << "' after " << mImpl->mSeedCapAttempts << " attempts. Giving up!" << LL_ENDL;
- }
-}
-
-class SimulatorFeaturesReceived : public LLHTTPClient::Responder
-{
- LOG_CLASS(SimulatorFeaturesReceived);
-public:
- SimulatorFeaturesReceived(const std::string& retry_url, U64 region_handle,
- S32 attempt = 0, S32 max_attempts = MAX_CAP_REQUEST_ATTEMPTS)
- : mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts)
- { }
-
- /* virtual */ void httpFailure()
- {
- LL_WARNS("AppInit", "SimulatorFeatures") << dumpResponse() << LL_ENDL;
- retry();
- }
-
- /* virtual */ void httpSuccess()
- {
- LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
- if(!regionp) //region is removed or responder is not created.
- {
- LL_WARNS("AppInit", "SimulatorFeatures")
- << "Received results for region that no longer exists!" << LL_ENDL;
- return ;
- }
-
- const LLSD& content = getContent();
- if (!content.isMap())
- {
- failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
- return;
- }
- regionp->setSimulatorFeatures(content);
- }
-
- void retry()
- {
- if (mAttempt < mMaxAttempts)
- {
- mAttempt++;
- LL_WARNS("AppInit", "SimulatorFeatures") << "Re-trying '" << mRetryURL << "'. Retry #" << mAttempt << LL_ENDL;
- LLHTTPClient::get(mRetryURL, new SimulatorFeaturesReceived(*this), LLSD(), CAP_REQUEST_TIMEOUT);
- }
- }
-
- std::string mRetryURL;
- U64 mRegionHandle;
- S32 mAttempt;
- S32 mMaxAttempts;
-};
-
-
void LLViewerRegion::setCapability(const std::string& name, const std::string& url)
{
if(name == "EventQueueGet")
@@ -2934,7 +2914,11 @@ void LLViewerRegion::setCapability(const std::string& name, const std::string& u
else if (name == "SimulatorFeatures")
{
// kick off a request for simulator features
- LLHTTPClient::get(url, new SimulatorFeaturesReceived(url, getHandle()), LLSD(), CAP_REQUEST_TIMEOUT);
+ std::string coroname =
+ LLCoros::instance().launch("LLViewerRegionImpl::requestSimulatorFeatureCoro",
+ boost::bind(&LLViewerRegionImpl::requestSimulatorFeatureCoro, mImpl, _1, url, getHandle()));
+
+ LL_INFOS("AppInit", "SimulatorFeatures") << "Launching " << coroname << " requesting simulator features from " << url << LL_ENDL;
}
else
{
@@ -2957,9 +2941,20 @@ void LLViewerRegion::setCapabilityDebug(const std::string& name, const std::stri
mHttpUrl = url ;
}
}
+}
+
+std::string LLViewerRegion::getCapabilityDebug(const std::string& name) const
+{
+ CapabilityMap::const_iterator iter = mImpl->mSecondCapabilitiesTracker.find(name);
+ if (iter == mImpl->mSecondCapabilitiesTracker.end())
+ {
+ return "";
+ }
+ return iter->second;
}
+
bool LLViewerRegion::isSpecialCapabilityName(const std::string &name)
{
return name == "EventQueueGet" || name == "UntrustedSimulatorMessage";
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index c14fa5aee8..d15f2eab20 100755
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -253,13 +253,14 @@ public:
// Get/set named capability URLs for this region.
void setSeedCapability(const std::string& url);
- void failedSeedCapability();
S32 getNumSeedCapRetries();
void setCapability(const std::string& name, const std::string& url);
void setCapabilityDebug(const std::string& name, const std::string& url);
bool isCapabilityAvailable(const std::string& name) const;
// implements LLCapabilityProvider
virtual std::string getCapability(const std::string& name) const;
+ std::string getCapabilityDebug(const std::string& name) const;
+
// has region received its final (not seed) capability list?
bool capabilitiesReceived() const;
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index 1e9945b514..f9160b6d60 100755
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -2362,7 +2362,6 @@ void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()
if (!caps_url.empty())
{
gPendingMetricsUploads++;
- LLCurlRequest::headers_t headers;
LLHTTPClient::post(caps_url,
msg,
new ViewerAppearanceChangeMetricsResponder(report_sequence,
diff --git a/indra/newview/llwlhandlers.cpp b/indra/newview/llwlhandlers.cpp
index 3bedfbe502..c05486b173 100755
--- a/indra/newview/llwlhandlers.cpp
+++ b/indra/newview/llwlhandlers.cpp
@@ -32,6 +32,7 @@
#include "llviewerregion.h"
#include "llenvmanager.h"
#include "llnotificationsutil.h"
+#include "llcorehttputil.h"
/****
* LLEnvironmentRequest
@@ -81,55 +82,62 @@ bool LLEnvironmentRequest::doRequest()
return false;
}
- LL_INFOS("WindlightCaps") << "Requesting region windlight settings via " << url << LL_ENDL;
- LLHTTPClient::get(url, new LLEnvironmentRequestResponder());
- return true;
-}
-
-/****
- * LLEnvironmentRequestResponder
- ****/
-int LLEnvironmentRequestResponder::sCount = 0; // init to 0
+ std::string coroname =
+ LLCoros::instance().launch("LLEnvironmentRequest::environmentRequestCoro",
+ boost::bind(&LLEnvironmentRequest::environmentRequestCoro, _1, url));
-LLEnvironmentRequestResponder::LLEnvironmentRequestResponder()
-{
- mID = ++sCount;
+ LL_INFOS("WindlightCaps") << "Requesting region windlight settings via " << url << LL_ENDL;
+ return true;
}
-/*virtual*/ void LLEnvironmentRequestResponder::httpSuccess()
-{
- const LLSD& unvalidated_content = getContent();
- LL_INFOS("WindlightCaps") << "Received region windlight settings" << LL_ENDL;
- if (mID != sCount)
- {
- LL_INFOS("WindlightCaps") << "Got superseded by another responder; ignoring..." << LL_ENDL;
- return;
- }
-
- LLUUID regionId;
- if( gAgent.getRegion() )
- {
- regionId = gAgent.getRegion()->getRegionID();
- }
-
- if (unvalidated_content[0]["regionID"].asUUID() != regionId )
- {
- LL_WARNS("WindlightCaps") << "Not in the region from where this data was received (wanting "
- << regionId << " but got " << unvalidated_content[0]["regionID"].asUUID()
- << ") - ignoring..." << LL_ENDL;
- return;
- }
+S32 LLEnvironmentRequest::sLastRequest = 0;
- LLEnvManagerNew::getInstance()->onRegionSettingsResponse(unvalidated_content);
-}
-/*virtual*/
-void LLEnvironmentRequestResponder::httpFailure()
+//static
+void LLEnvironmentRequest::environmentRequestCoro(LLCoros::self& self, std::string url)
{
- LL_WARNS("WindlightCaps") << "Got an error, not using region windlight... "
- << dumpResponse() << LL_ENDL;
- LLEnvManagerNew::getInstance()->onRegionSettingsResponse(LLSD());
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ S32 requestId = ++LLEnvironmentRequest::sLastRequest;
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("EnvironmentRequest", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD result = httpAdapter->getAndYield(self, httpRequest, url);
+
+ if (requestId != LLEnvironmentRequest::sLastRequest)
+ {
+ LL_INFOS("WindlightCaps") << "Got superseded by another responder; ignoring..." << LL_ENDL;
+ return;
+ }
+
+ LLSD httpResults = result["http_result"];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroHandler::getStatusFromLLSD(httpResults);
+ if (!status)
+ {
+ LL_WARNS("WindlightCaps") << "Got an error, not using region windlight... " << LL_ENDL;
+ LLEnvManagerNew::getInstance()->onRegionSettingsResponse(LLSD());
+ return;
+ }
+ result = result["content"];
+ LL_INFOS("WindlightCaps") << "Received region windlight settings" << LL_ENDL;
+
+ LLUUID regionId;
+ if (gAgent.getRegion())
+ {
+ regionId = gAgent.getRegion()->getRegionID();
+ }
+
+ if (result[0]["regionID"].asUUID() != regionId)
+ {
+ LL_WARNS("WindlightCaps") << "Not in the region from where this data was received (wanting "
+ << regionId << " but got " << result[0]["regionID"].asUUID()
+ << ") - ignoring..." << LL_ENDL;
+ return;
+ }
+
+ LLEnvManagerNew::getInstance()->onRegionSettingsResponse(result);
}
+
/****
* LLEnvironmentApply
****/
@@ -161,53 +169,86 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content)
return false;
}
- LL_INFOS("WindlightCaps") << "Sending windlight settings to " << url << LL_ENDL;
- LL_DEBUGS("WindlightCaps") << "content: " << content << LL_ENDL;
- LLHTTPClient::post(url, content, new LLEnvironmentApplyResponder());
+ LL_INFOS("WindlightCaps") << "Sending windlight settings to " << url << LL_ENDL;
+ LL_DEBUGS("WindlightCaps") << "content: " << content << LL_ENDL;
+
+ std::string coroname =
+ LLCoros::instance().launch("LLEnvironmentApply::environmentApplyCoro",
+ boost::bind(&LLEnvironmentApply::environmentApplyCoro, _1, url, content));
return true;
}
-/****
- * LLEnvironmentApplyResponder
- ****/
-/*virtual*/ void LLEnvironmentApplyResponder::httpSuccess()
-{
- const LLSD& content = getContent();
- if (!content.isMap() || !content.has("regionID"))
- {
- failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
- return;
- }
- if (content["regionID"].asUUID() != gAgent.getRegion()->getRegionID())
- {
- LL_WARNS("WindlightCaps") << "No longer in the region where data was sent (currently "
- << gAgent.getRegion()->getRegionID() << ", reply is from " << content["regionID"].asUUID()
- << "); ignoring..." << LL_ENDL;
- return;
- }
- else if (content["success"].asBoolean())
- {
- LL_DEBUGS("WindlightCaps") << "Success in applying windlight settings to region " << content["regionID"].asUUID() << LL_ENDL;
- LLEnvManagerNew::instance().onRegionSettingsApplyResponse(true);
- }
- else
- {
- LL_WARNS("WindlightCaps") << "Region couldn't apply windlight settings! " << dumpResponse() << LL_ENDL;
- LLSD args(LLSD::emptyMap());
- args["FAIL_REASON"] = content["fail_reason"].asString();
- LLNotificationsUtil::add("WLRegionApplyFail", args);
- LLEnvManagerNew::instance().onRegionSettingsApplyResponse(false);
- }
-}
-/*virtual*/
-void LLEnvironmentApplyResponder::httpFailure()
+void LLEnvironmentApply::environmentApplyCoro(LLCoros::self& self, std::string url, LLSD content)
{
- LL_WARNS("WindlightCaps") << "Couldn't apply windlight settings to region! "
- << dumpResponse() << LL_ENDL;
-
- LLSD args(LLSD::emptyMap());
- std::stringstream msg;
- msg << getReason() << " (Code " << getStatus() << ")";
- args["FAIL_REASON"] = msg.str();
- LLNotificationsUtil::add("WLRegionApplyFail", args);
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("EnvironmentApply", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD result = httpAdapter->postAndYield(self, httpRequest, url, content);
+
+ LLSD notify; // for error reporting. If there is something to report to user this will be defined.
+ /*
+ * Expecting reply from sim in form of:
+ * {
+ * regionID : uuid,
+ * messageID: uuid,
+ * success : true
+ * }
+ * or
+ * {
+ * regionID : uuid,
+ * success : false,
+ * fail_reason : string
+ * }
+ */
+
+ do // while false.
+ { // Breaks from loop in the case of an error.
+
+ LLSD httpResults = result["http_result"];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroHandler::getStatusFromLLSD(httpResults);
+ if (!status)
+ {
+ LL_WARNS("WindlightCaps") << "Couldn't apply windlight settings to region! " << LL_ENDL;
+
+ std::stringstream msg;
+ msg << status.toString() << " (Code " << status.toTerseString() << ")";
+ notify = LLSD::emptyMap();
+ notify["FAIL_REASON"] = msg.str();
+ break;
+ }
+
+ if (!result.has("regionID"))
+ {
+ notify = LLSD::emptyMap();
+ notify["FAIL_REASON"] = "Missing regionID, malformed response";
+ break;
+ }
+ else if (result["regionID"].asUUID() != gAgent.getRegion()->getRegionID())
+ {
+ // note that there is no report to the user in this failure case.
+ LL_WARNS("WindlightCaps") << "No longer in the region where data was sent (currently "
+ << gAgent.getRegion()->getRegionID() << ", reply is from " << result["regionID"].asUUID()
+ << "); ignoring..." << LL_ENDL;
+ break;
+ }
+ else if (!result["success"].asBoolean())
+ {
+ LL_WARNS("WindlightCaps") << "Region couldn't apply windlight settings! " << LL_ENDL;
+ notify = LLSD::emptyMap();
+ notify["FAIL_REASON"] = result["fail_reason"].asString();
+ break;
+ }
+
+ LL_DEBUGS("WindlightCaps") << "Success in applying windlight settings to region " << result["regionID"].asUUID() << LL_ENDL;
+ LLEnvManagerNew::instance().onRegionSettingsApplyResponse(true);
+
+ } while (false);
+
+ if (!notify.isUndefined())
+ {
+ LLNotificationsUtil::add("WLRegionApplyFail", notify);
+ LLEnvManagerNew::instance().onRegionSettingsApplyResponse(false);
+ }
}
diff --git a/indra/newview/llwlhandlers.h b/indra/newview/llwlhandlers.h
index 089c799da7..e8908410d9 100755
--- a/indra/newview/llwlhandlers.h
+++ b/indra/newview/llwlhandlers.h
@@ -29,6 +29,7 @@
#include "llviewerprecompiledheaders.h"
#include "llhttpclient.h"
+#include "llcoros.h"
class LLEnvironmentRequest
{
@@ -40,21 +41,10 @@ public:
private:
static void onRegionCapsReceived(const LLUUID& region_id);
static bool doRequest();
-};
-
-class LLEnvironmentRequestResponder: public LLHTTPClient::Responder
-{
- LOG_CLASS(LLEnvironmentRequestResponder);
-private:
- /* virtual */ void httpSuccess();
- /* virtual */ void httpFailure();
-private:
- friend class LLEnvironmentRequest;
+ static void environmentRequestCoro(LLCoros::self& self, std::string url);
- LLEnvironmentRequestResponder();
- static int sCount;
- int mID;
+ static S32 sLastRequest;
};
class LLEnvironmentApply
@@ -67,35 +57,8 @@ public:
private:
static clock_t sLastUpdate;
static clock_t UPDATE_WAIT_SECONDS;
-};
-class LLEnvironmentApplyResponder: public LLHTTPClient::Responder
-{
- LOG_CLASS(LLEnvironmentApplyResponder);
-private:
- /*
- * Expecting reply from sim in form of:
- * {
- * regionID : uuid,
- * messageID: uuid,
- * success : true
- * }
- * or
- * {
- * regionID : uuid,
- * success : false,
- * fail_reason : string
- * }
- */
- /* virtual */ void httpSuccess();
-
- // non-2xx errors only
- /* virtual */ void httpFailure();
-
-private:
- friend class LLEnvironmentApply;
-
- LLEnvironmentApplyResponder() {}
+ static void environmentApplyCoro(LLCoros::self& self, std::string url, LLSD content);
};
#endif // LL_LLWLHANDLERS_H
diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp
index c12c2cc24c..702d0c3a29 100755
--- a/indra/newview/llxmlrpctransaction.cpp
+++ b/indra/newview/llxmlrpctransaction.cpp
@@ -35,6 +35,11 @@
#include "llxmlrpclistener.h"
#include "llcurl.h"
+#include "httpcommon.h"
+#include "httprequest.h"
+#include "httpoptions.h"
+#include "httpheaders.h"
+#include "bufferarray.h"
#include "llviewercontrol.h"
// Have to include these last to avoid queue redefinition!
@@ -43,6 +48,13 @@
#include "llappviewer.h"
#include "lltrans.h"
+#include "boost/move/unique_ptr.hpp"
+
+namespace boost
+{
+ using ::boost::movelib::unique_ptr; // move unique_ptr into the boost namespace.
+}
+
// Static instance of LLXMLRPCListener declared here so that every time we
// bring in this code, we instantiate a listener. If we put the static
// instance of LLXMLRPCListener into llxmlrpclistener.cpp, the linker would
@@ -155,55 +167,158 @@ XMLRPC_VALUE LLXMLRPCValue::getValue() const
}
+class LLXMLRPCTransaction::Handler : public LLCore::HttpHandler
+{
+public:
+ Handler(LLCore::HttpRequest::ptr_t &request, LLXMLRPCTransaction::Impl *impl);
+ virtual ~Handler();
+
+ virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
+
+ typedef boost::unique_ptr<LLXMLRPCTransaction::Handler> ptr_t;
+
+private:
+
+ LLXMLRPCTransaction::Impl *mImpl;
+ LLCore::HttpRequest::ptr_t mRequest;
+};
+
class LLXMLRPCTransaction::Impl
{
public:
typedef LLXMLRPCTransaction::EStatus EStatus;
- LLCurlEasyRequest* mCurlRequest;
+ LLCore::HttpRequest::ptr_t mHttpRequest;
+
+
+ EStatus mStatus;
+ CURLcode mCurlCode;
+ std::string mStatusMessage;
+ std::string mStatusURI;
+ LLCore::HttpResponse::TransferStats::ptr_t mTransferStats;
+ Handler::ptr_t mHandler;
+ LLCore::HttpHandle mPostH;
- EStatus mStatus;
- CURLcode mCurlCode;
- std::string mStatusMessage;
- std::string mStatusURI;
- LLCurl::TransferInfo mTransferInfo;
-
std::string mURI;
- char* mRequestText;
- int mRequestTextSize;
-
+
std::string mProxyAddress;
std::string mResponseText;
XMLRPC_REQUEST mResponse;
std::string mCertStore;
LLPointer<LLCertificate> mErrorCert;
-
+
Impl(const std::string& uri, XMLRPC_REQUEST request, bool useGzip);
Impl(const std::string& uri,
- const std::string& method, LLXMLRPCValue params, bool useGzip);
+ const std::string& method, LLXMLRPCValue params, bool useGzip);
~Impl();
-
+
bool process();
-
- void setStatus(EStatus code,
- const std::string& message = "", const std::string& uri = "");
- void setCurlStatus(CURLcode);
+
+ void setStatus(EStatus code, const std::string& message = "", const std::string& uri = "");
+ void setHttpStatus(const LLCore::HttpStatus &status);
private:
void init(XMLRPC_REQUEST request, bool useGzip);
- static int _sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param);
- static CURLcode _sslCtxFunction(CURL * curl, void *sslctx, void *param);
- static size_t curlDownloadCallback(
- char* data, size_t size, size_t nmemb, void* user_data);
};
+LLXMLRPCTransaction::Handler::Handler(LLCore::HttpRequest::ptr_t &request,
+ LLXMLRPCTransaction::Impl *impl) :
+ mImpl(impl),
+ mRequest(request)
+{
+}
+
+LLXMLRPCTransaction::Handler::~Handler()
+{
+}
+
+void LLXMLRPCTransaction::Handler::onCompleted(LLCore::HttpHandle handle,
+ LLCore::HttpResponse * response)
+{
+ LLCore::HttpStatus status = response->getStatus();
+
+ if (!status)
+ {
+ if ((status.toULong() != CURLE_SSL_PEER_CERTIFICATE) &&
+ (status.toULong() != CURLE_SSL_CACERT))
+ {
+ // if we have a curl error that's not already been handled
+ // (a non cert error), then generate the error message as
+ // appropriate
+ mImpl->setHttpStatus(status);
+ LLCertificate *errordata = static_cast<LLCertificate *>(status.getErrorData());
+
+ if (errordata)
+ {
+ mImpl->mErrorCert = LLPointer<LLCertificate>(errordata);
+ status.setErrorData(NULL);
+ errordata->unref();
+ }
+
+ LL_WARNS() << "LLXMLRPCTransaction error "
+ << status.toHex() << ": " << status.toString() << LL_ENDL;
+ LL_WARNS() << "LLXMLRPCTransaction request URI: "
+ << mImpl->mURI << LL_ENDL;
+ }
+
+ return;
+ }
+
+ mImpl->setStatus(LLXMLRPCTransaction::StatusComplete);
+ mImpl->mTransferStats = response->getTransferStats();
+
+ // the contents of a buffer array are potentially noncontiguous, so we
+ // will need to copy them into an contiguous block of memory for XMLRPC.
+ LLCore::BufferArray *body = response->getBody();
+ char * bodydata = new char[body->size()];
+
+ body->read(0, bodydata, body->size());
+
+ mImpl->mResponse = XMLRPC_REQUEST_FromXML(bodydata, body->size(), 0);
+
+ delete[] bodydata;
+
+ bool hasError = false;
+ bool hasFault = false;
+ int faultCode = 0;
+ std::string faultString;
+
+ LLXMLRPCValue error(XMLRPC_RequestGetError(mImpl->mResponse));
+ if (error.isValid())
+ {
+ hasError = true;
+ faultCode = error["faultCode"].asInt();
+ faultString = error["faultString"].asString();
+ }
+ else if (XMLRPC_ResponseIsFault(mImpl->mResponse))
+ {
+ hasFault = true;
+ faultCode = XMLRPC_GetResponseFaultCode(mImpl->mResponse);
+ faultString = XMLRPC_GetResponseFaultString(mImpl->mResponse);
+ }
+
+ if (hasError || hasFault)
+ {
+ mImpl->setStatus(LLXMLRPCTransaction::StatusXMLRPCError);
+
+ LL_WARNS() << "LLXMLRPCTransaction XMLRPC "
+ << (hasError ? "error " : "fault ")
+ << faultCode << ": "
+ << faultString << LL_ENDL;
+ LL_WARNS() << "LLXMLRPCTransaction request URI: "
+ << mImpl->mURI << LL_ENDL;
+ }
+
+}
+
+//=========================================================================
+
LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
XMLRPC_REQUEST request, bool useGzip)
- : mCurlRequest(0),
+ : mHttpRequest(),
mStatus(LLXMLRPCTransaction::StatusNotStarted),
mURI(uri),
- mRequestText(0),
mResponse(0)
{
init(request, useGzip);
@@ -212,10 +327,9 @@ LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
const std::string& method, LLXMLRPCValue params, bool useGzip)
- : mCurlRequest(0),
+ : mHttpRequest(),
mStatus(LLXMLRPCTransaction::StatusNotStarted),
mURI(uri),
- mRequestText(0),
mResponse(0)
{
XMLRPC_REQUEST request = XMLRPC_RequestNew();
@@ -231,127 +345,53 @@ LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
XMLRPC_RequestFree(request, 1);
}
-// _sslCertVerifyCallback
-// callback called when a cert verification is requested.
-// calls SECAPI to validate the context
-int LLXMLRPCTransaction::Impl::_sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param)
+void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)
{
- LLXMLRPCTransaction::Impl *transaction = (LLXMLRPCTransaction::Impl *)param;
- LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(transaction->mCertStore);
- LLPointer<LLCertificateChain> chain = gSecAPIHandler->getCertificateChain(ctx);
- LLSD validation_params = LLSD::emptyMap();
- LLURI uri(transaction->mURI);
- validation_params[CERT_HOSTNAME] = uri.hostName();
- try
- {
- // don't validate hostname. Let libcurl do it instead. That way, it'll handle redirects
- store->validate(VALIDATION_POLICY_SSL & (~VALIDATION_POLICY_HOSTNAME), chain, validation_params);
- }
- catch (LLCertValidationTrustException& cert_exception)
- {
- // this exception is is handled differently than the general cert
- // exceptions, as we allow the user to actually add the certificate
- // for trust.
- // therefore we pass back a different error code
- // NOTE: We're currently 'wired' to pass around CURL error codes. This is
- // somewhat clumsy, as we may run into errors that do not map directly to curl
- // error codes. Should be refactored with login refactoring, perhaps.
- transaction->mCurlCode = CURLE_SSL_CACERT;
- // set the status directly. set curl status generates error messages and we want
- // to use the fixed ones from the exceptions
- transaction->setStatus(StatusCURLError, cert_exception.getMessage(), std::string());
- // We should probably have a more generic way of passing information
- // back to the error handlers.
- transaction->mErrorCert = cert_exception.getCert();
- return 0;
- }
- catch (LLCertException& cert_exception)
- {
- transaction->mCurlCode = CURLE_SSL_PEER_CERTIFICATE;
- // set the status directly. set curl status generates error messages and we want
- // to use the fixed ones from the exceptions
- transaction->setStatus(StatusCURLError, cert_exception.getMessage(), std::string());
- transaction->mErrorCert = cert_exception.getCert();
- return 0;
- }
- catch (...)
- {
- // any other odd error, we just handle as a connect error.
- transaction->mCurlCode = CURLE_SSL_CONNECT_ERROR;
- transaction->setCurlStatus(CURLE_SSL_CONNECT_ERROR);
- return 0;
- }
- return 1;
-}
+ LLCore::HttpOptions::ptr_t httpOpts;
+ LLCore::HttpHeaders::ptr_t httpHeaders;
-// _sslCtxFunction
-// Callback function called when an SSL Context is created via CURL
-// used to configure the context for custom cert validate(<, <#const & xs#>, <#T * #>, <#long #>)tion
-// based on SECAPI
-
-CURLcode LLXMLRPCTransaction::Impl::_sslCtxFunction(CURL * curl, void *sslctx, void *param)
-{
- SSL_CTX * ctx = (SSL_CTX *) sslctx;
- // disable any default verification for server certs
- SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
- // set the verification callback.
- SSL_CTX_set_cert_verify_callback(ctx, _sslCertVerifyCallback, param);
- // the calls are void
- return CURLE_OK;
-
-}
-void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)
-{
- if (!mCurlRequest)
+ if (!mHttpRequest)
{
- mCurlRequest = new LLCurlEasyRequest();
+ mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest);
}
- if(!mCurlRequest->isValid())
- {
- LL_WARNS() << "mCurlRequest is invalid." << LL_ENDL ;
- delete mCurlRequest ;
- mCurlRequest = NULL ;
- return ;
- }
+ // LLRefCounted starts with a 1 ref, so don't add a ref in the smart pointer
+ httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions(), false);
- mErrorCert = NULL;
+ httpOpts->setTimeout(40L);
-// mCurlRequest->setopt(CURLOPT_VERBOSE, 1); // useful for debugging
- mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1);
- mCurlRequest->setWriteCallback(&curlDownloadCallback, (void*)this);
- BOOL vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert");
+ bool vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert");
mCertStore = gSavedSettings.getString("CertStore");
- mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, vefifySSLCert);
- mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, vefifySSLCert ? 2 : 0);
- // Be a little impatient about establishing connections.
- mCurlRequest->setopt(CURLOPT_CONNECTTIMEOUT, 40L);
- mCurlRequest->setSSLCtxCallback(_sslCtxFunction, (void *)this);
- /* Setting the DNS cache timeout to -1 disables it completely.
- This might help with bug #503 */
- mCurlRequest->setopt(CURLOPT_DNS_CACHE_TIMEOUT, -1);
+ httpOpts->setSSLVerifyPeer( vefifySSLCert );
+ httpOpts->setSSLVerifyHost( vefifySSLCert ? 2 : 0);
- mCurlRequest->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML);
+ // LLRefCounted starts with a 1 ref, so don't add a ref in the smart pointer
+ httpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders(), false);
- if (useGzip)
- {
- mCurlRequest->setoptString(CURLOPT_ENCODING, "");
- }
+ httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML);
+
+ ///* Setting the DNS cache timeout to -1 disables it completely.
+ //This might help with bug #503 */
+ //httpOpts->setDNSCacheTimeout(-1);
+
+ LLCore::BufferArray::ptr_t body = LLCore::BufferArray::ptr_t(new LLCore::BufferArray(), false);
+
+ // TODO: See if there is a way to serialize to a preallocated buffer I'm
+ // not fond of the copy here.
+ int requestSize(0);
+ char * requestText = XMLRPC_REQUEST_ToXML(request, &requestSize);
+
+ body->append(requestText, requestSize);
- mRequestText = XMLRPC_REQUEST_ToXML(request, &mRequestTextSize);
- if (mRequestText)
- {
- mCurlRequest->setoptString(CURLOPT_POSTFIELDS, mRequestText);
- mCurlRequest->setopt(CURLOPT_POSTFIELDSIZE, mRequestTextSize);
- }
- else
- {
- setStatus(StatusOtherError);
- }
+ XMLRPC_Free(requestText);
+
+ mHandler = LLXMLRPCTransaction::Handler::ptr_t(new Handler( mHttpRequest, this ));
+
+ mPostH = mHttpRequest->requestPost(LLCore::HttpRequest::DEFAULT_POLICY_ID, 0,
+ mURI, body.get(), httpOpts.get(), httpHeaders.get(), mHandler.get());
- mCurlRequest->sendRequest(mURI);
}
@@ -361,28 +401,17 @@ LLXMLRPCTransaction::Impl::~Impl()
{
XMLRPC_RequestFree(mResponse, 1);
}
-
- if (mRequestText)
- {
- XMLRPC_Free(mRequestText);
- }
-
- delete mCurlRequest;
- mCurlRequest = NULL ;
}
bool LLXMLRPCTransaction::Impl::process()
{
- if(!mCurlRequest || !mCurlRequest->isValid())
+ if (!mPostH || !mHttpRequest)
{
- LL_WARNS() << "transaction failed." << LL_ENDL ;
-
- delete mCurlRequest ;
- mCurlRequest = NULL ;
- return true ; //failed, quit.
+ LL_WARNS() << "transaction failed." << LL_ENDL;
+ return true; //failed, quit.
}
- switch(mStatus)
+ switch (mStatus)
{
case LLXMLRPCTransaction::StatusComplete:
case LLXMLRPCTransaction::StatusCURLError:
@@ -391,93 +420,25 @@ bool LLXMLRPCTransaction::Impl::process()
{
return true;
}
-
+
case LLXMLRPCTransaction::StatusNotStarted:
{
setStatus(LLXMLRPCTransaction::StatusStarted);
break;
}
-
+
default:
- {
- // continue onward
- }
- }
-
- if(!mCurlRequest->wait())
- {
- return false ;
+ break;
}
- while(1)
- {
- CURLcode result;
- bool newmsg = mCurlRequest->getResult(&result, &mTransferInfo);
- if (newmsg)
- {
- if (result != CURLE_OK)
- {
- if ((result != CURLE_SSL_PEER_CERTIFICATE) &&
- (result != CURLE_SSL_CACERT))
- {
- // if we have a curl error that's not already been handled
- // (a non cert error), then generate the error message as
- // appropriate
- setCurlStatus(result);
-
- LL_WARNS() << "LLXMLRPCTransaction CURL error "
- << mCurlCode << ": " << mCurlRequest->getErrorString() << LL_ENDL;
- LL_WARNS() << "LLXMLRPCTransaction request URI: "
- << mURI << LL_ENDL;
- }
-
- return true;
- }
-
- setStatus(LLXMLRPCTransaction::StatusComplete);
+ LLCore::HttpStatus status = mHttpRequest->update(0);
- mResponse = XMLRPC_REQUEST_FromXML(
- mResponseText.data(), mResponseText.size(), NULL);
-
- bool hasError = false;
- bool hasFault = false;
- int faultCode = 0;
- std::string faultString;
-
- LLXMLRPCValue error(XMLRPC_RequestGetError(mResponse));
- if (error.isValid())
- {
- hasError = true;
- faultCode = error["faultCode"].asInt();
- faultString = error["faultString"].asString();
- }
- else if (XMLRPC_ResponseIsFault(mResponse))
- {
- hasFault = true;
- faultCode = XMLRPC_GetResponseFaultCode(mResponse);
- faultString = XMLRPC_GetResponseFaultString(mResponse);
- }
-
- if (hasError || hasFault)
- {
- setStatus(LLXMLRPCTransaction::StatusXMLRPCError);
-
- LL_WARNS() << "LLXMLRPCTransaction XMLRPC "
- << (hasError ? "error " : "fault ")
- << faultCode << ": "
- << faultString << LL_ENDL;
- LL_WARNS() << "LLXMLRPCTransaction request URI: "
- << mURI << LL_ENDL;
- }
-
- return true;
- }
- else
- {
- break; // done
- }
+ status = mHttpRequest->getStatus();
+ if (!status)
+ {
+ return false;
}
-
+
return false;
}
@@ -516,64 +477,51 @@ void LLXMLRPCTransaction::Impl::setStatus(EStatus status,
}
}
-void LLXMLRPCTransaction::Impl::setCurlStatus(CURLcode code)
+void LLXMLRPCTransaction::Impl::setHttpStatus(const LLCore::HttpStatus &status)
{
+ CURLcode code = static_cast<CURLcode>(status.toULong());
std::string message;
std::string uri = "http://secondlife.com/community/support.php";
-
+ LLURI failuri(mURI);
+
+
switch (code)
{
- case CURLE_COULDNT_RESOLVE_HOST:
- message =
- "DNS could not resolve the host name.\n"
- "Please verify that you can connect to the www.secondlife.com\n"
- "web site. If you can, but continue to receive this error,\n"
- "please go to the support section and report this problem.";
- break;
-
- case CURLE_SSL_PEER_CERTIFICATE:
- message =
- "The login server couldn't verify itself via SSL.\n"
- "If you continue to receive this error, please go\n"
- "to the Support section of the SecondLife.com web site\n"
- "and report the problem.";
- break;
-
- case CURLE_SSL_CACERT:
- case CURLE_SSL_CONNECT_ERROR:
- message =
- "Often this means that your computer\'s clock is set incorrectly.\n"
- "Please go to Control Panels and make sure the time and date\n"
- "are set correctly.\n"
- "Also check that your network and firewall are set up correctly.\n"
- "If you continue to receive this error, please go\n"
- "to the Support section of the SecondLife.com web site\n"
- "and report the problem.";
- break;
-
- default:
- break;
+ case CURLE_COULDNT_RESOLVE_HOST:
+ message =
+ std::string("DNS could not resolve the host name(") + failuri.hostName() + ").\n"
+ "Please verify that you can connect to the www.secondlife.com\n"
+ "web site. If you can, but continue to receive this error,\n"
+ "please go to the support section and report this problem.";
+ break;
+
+ case CURLE_SSL_PEER_CERTIFICATE:
+ message =
+ "The login server couldn't verify itself via SSL.\n"
+ "If you continue to receive this error, please go\n"
+ "to the Support section of the SecondLife.com web site\n"
+ "and report the problem.";
+ break;
+
+ case CURLE_SSL_CACERT:
+ case CURLE_SSL_CONNECT_ERROR:
+ message =
+ "Often this means that your computer\'s clock is set incorrectly.\n"
+ "Please go to Control Panels and make sure the time and date\n"
+ "are set correctly.\n"
+ "Also check that your network and firewall are set up correctly.\n"
+ "If you continue to receive this error, please go\n"
+ "to the Support section of the SecondLife.com web site\n"
+ "and report the problem.";
+ break;
+
+ default:
+ break;
}
-
+
mCurlCode = code;
setStatus(StatusCURLError, message, uri);
-}
-
-size_t LLXMLRPCTransaction::Impl::curlDownloadCallback(
- char* data, size_t size, size_t nmemb, void* user_data)
-{
- Impl& impl(*(Impl*)user_data);
-
- size_t n = size * nmemb;
- impl.mResponseText.append(data, n);
-
- if (impl.mStatus == LLXMLRPCTransaction::StatusStarted)
- {
- impl.setStatus(LLXMLRPCTransaction::StatusDownloading);
- }
-
- return n;
}
@@ -645,11 +593,11 @@ F64 LLXMLRPCTransaction::transferRate()
return 0.0L;
}
- double rate_bits_per_sec = impl.mTransferInfo.mSpeedDownload * 8.0;
+ double rate_bits_per_sec = impl.mTransferStats->mSpeedDownload * 8.0;
LL_INFOS("AppInit") << "Buffer size: " << impl.mResponseText.size() << " B" << LL_ENDL;
- LL_DEBUGS("AppInit") << "Transfer size: " << impl.mTransferInfo.mSizeDownload << " B" << LL_ENDL;
- LL_DEBUGS("AppInit") << "Transfer time: " << impl.mTransferInfo.mTotalTime << " s" << LL_ENDL;
+ LL_DEBUGS("AppInit") << "Transfer size: " << impl.mTransferStats->mSizeDownload << " B" << LL_ENDL;
+ LL_DEBUGS("AppInit") << "Transfer time: " << impl.mTransferStats->mTotalTime << " s" << LL_ENDL;
LL_INFOS("AppInit") << "Transfer rate: " << rate_bits_per_sec / 1000.0 << " Kb/s" << LL_ENDL;
return rate_bits_per_sec;
diff --git a/indra/newview/llxmlrpctransaction.h b/indra/newview/llxmlrpctransaction.h
index f2589c7f41..3a1c9c82b7 100755
--- a/indra/newview/llxmlrpctransaction.h
+++ b/indra/newview/llxmlrpctransaction.h
@@ -81,7 +81,7 @@ private:
class LLXMLRPCTransaction
- // an asynchronous request and respones via XML-RPC
+ // an asynchronous request and responses via XML-RPC
{
public:
LLXMLRPCTransaction(const std::string& uri,
@@ -127,7 +127,9 @@ public:
// only valid if StsatusComplete, otherwise 0.0
private:
+ class Handler;
class Impl;
+
Impl& impl;
};