SH-4257 Preparation for a new cap grant: GetMesh2

Mesh repo is using three policy classes now:  one for
large objects, one for GetMesh2 regions, one for
GetMesh regions.  It's also detecting the presence
of the cap and using the correct class.  Class
initialization cleaned up significantly in llappcorehttp
using data-directed code.  Pulled in the changes to
HttpHeader done for sunshine-internal then did a
refactoring pass on the header callback which now
uses a unified approach to clean up and deliver
header information to all interested parties.  Added
support for using Retry-After header information on
503 retries.
master
Monty Brandenberg 2013-06-20 19:18:39 -04:00
parent d6741a4fc0
commit d6cbcd591a
13 changed files with 276 additions and 95 deletions

View File

@ -98,7 +98,7 @@ 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 = 4;
const int HTTP_POLICY_CLASS_LIMIT = 8;
// Debug/informational tracing. Used both
// as a global option and in per-request traces.
@ -138,6 +138,10 @@ const int HTTP_CONNECTION_LIMIT_DEFAULT = 8;
const int HTTP_CONNECTION_LIMIT_MIN = 1;
const int HTTP_CONNECTION_LIMIT_MAX = 256;
// Miscellaneous defaults
const long HTTP_PIPELINING_DEFAULT = 0L;
const bool HTTP_USE_RETRY_AFTER_DEFAULT = true;
// Tuning parameters
// Time worker thread sleeps after a pass through the

View File

@ -4,7 +4,7 @@
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, Linden Research, Inc.
* Copyright (C) 2012-2013, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -53,7 +53,7 @@ HttpOperation::HttpOperation()
mUserHandler(NULL),
mReqPolicy(HttpRequest::DEFAULT_POLICY_ID),
mReqPriority(0U),
mTracing(0)
mTracing(HTTP_TRACE_OFF)
{
mMetricCreated = totalTime();
}

View File

@ -64,6 +64,15 @@ int parse_content_range_header(char * buffer,
unsigned int * last,
unsigned int * length);
// Similar for Retry-After headers. Only parses the delta form
// of the header, HTTP time formats aren't interesting for client
// purposes.
//
// @return 0 if successfully parsed and seconds time delta
// returned in time argument.
//
int parse_retry_after_header(char * buffer, int * time);
// Take data from libcurl's CURLOPT_DEBUGFUNCTION callback and
// escape and format it for a tracing line in logging. Absolutely
@ -74,14 +83,12 @@ void escape_libcurl_debug_data(char * buffer, size_t len, bool scrub,
std::string & safe_line);
// OS-neutral string comparisons of various types
int os_strncasecmp(const char *s1, const char *s2, size_t n);
int os_strcasecmp(const char *s1, const char *s2);
char * os_strtok_r(char *str, const char *delim, char **saveptr);
static const char * const hdr_whitespace(" \t");
static const char * const hdr_separator(": \t");
// OS-neutral string comparisons of various types.
int os_strcasecmp(const char * s1, const char * s2);
char * os_strtok_r(char * str, const char * delim, char ** saveptr);
char * os_strtrim(char * str);
char * os_strltrim(char * str);
void os_strlower(char * str);
} // end anonymous namespace
@ -104,6 +111,8 @@ HttpOpRequest::HttpOpRequest()
mCurlService(NULL),
mCurlHeaders(NULL),
mCurlBodyPos(0),
mCurlTemp(NULL),
mCurlTempLen(0),
mReplyBody(NULL),
mReplyOffset(0),
mReplyLength(0),
@ -154,6 +163,10 @@ HttpOpRequest::~HttpOpRequest()
mCurlHeaders = NULL;
}
delete [] mCurlTemp;
mCurlTemp = NULL;
mCurlTempLen = 0;
if (mReplyBody)
{
mReplyBody->release();
@ -207,6 +220,11 @@ void HttpOpRequest::stageFromActive(HttpService * service)
mCurlHeaders = NULL;
}
// Also not needed on the other side
delete [] mCurlTemp;
mCurlTemp = NULL;
mCurlTempLen = 0;
addAsReply();
}
@ -335,6 +353,10 @@ void HttpOpRequest::setupCommon(HttpRequest::policy_t policy_id,
{
mProcFlags |= PF_SAVE_HEADERS;
}
if (options->getUseRetryAfter())
{
mProcFlags |= PF_USE_RETRY_AFTER;
}
mPolicyRetryLimit = options->getRetries();
mPolicyRetryLimit = llclamp(mPolicyRetryLimit, HTTP_RETRY_COUNT_MIN, HTTP_RETRY_COUNT_MAX);
mTracing = (std::max)(mTracing, llclamp(options->getTrace(), HTTP_TRACE_MIN, HTTP_TRACE_MAX));
@ -549,7 +571,7 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
}
curl_easy_setopt(mCurlHandle, CURLOPT_HTTPHEADER, mCurlHeaders);
if (mProcFlags & (PF_SCAN_RANGE_HEADER | PF_SAVE_HEADERS))
if (mProcFlags & (PF_SCAN_RANGE_HEADER | PF_SAVE_HEADERS | PF_USE_RETRY_AFTER))
{
curl_easy_setopt(mCurlHandle, CURLOPT_HEADERFUNCTION, headerCallback);
curl_easy_setopt(mCurlHandle, CURLOPT_HEADERDATA, this);
@ -610,10 +632,9 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi
{
static const char status_line[] = "HTTP/";
static const size_t status_line_len = sizeof(status_line) - 1;
static const char con_ran_line[] = "content-range:";
static const size_t con_ran_line_len = sizeof(con_ran_line) - 1;
static const char con_ran_line[] = "content-range";
static const char con_retry_line[] = "retry-after";
HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata));
const size_t hdr_size(size * nmemb);
@ -627,6 +648,7 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi
op->mReplyOffset = 0;
op->mReplyLength = 0;
op->mReplyFullLength = 0;
op->mReplyRetryAfter = 0;
op->mStatus = HttpStatus();
if (op->mReplyHeaders)
{
@ -645,6 +667,53 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi
--wanted_hdr_size;
}
}
// Copy and normalize header fragments for the following
// stages. Would like to modify the data in-place but that
// may not be allowed and we need one byte extra for NUL.
// At the end of this we will have:
//
// If ':' present in header:
// 1. name points to text to left of colon which
// will be ascii lower-cased and left and right
// trimmed of whitespace.
// 2. value points to text to right of colon which
// will be left trimmed of whitespace.
// Otherwise:
// 1. name points to header which will be left
// trimmed of whitespace.
// 2. value is NULL
// Any non-NULL pointer may point to a zero-length string.
//
if (wanted_hdr_size >= op->mCurlTempLen)
{
delete [] op->mCurlTemp;
op->mCurlTempLen = 2 * wanted_hdr_size + 1;
op->mCurlTemp = new char [op->mCurlTempLen];
}
memcpy(op->mCurlTemp, hdr_data, wanted_hdr_size);
op->mCurlTemp[wanted_hdr_size] = '\0';
char * name(op->mCurlTemp);
char * value(strchr(name, ':'));
if (value)
{
*value++ = '\0';
os_strlower(name);
name = os_strtrim(name);
value = os_strltrim(value);
}
else
{
// Doesn't look well-formed, do minimal normalization on it
name = os_strltrim(name);
}
// Normalized, now reject headers with empty names.
if (! *name)
{
// No use continuing
return hdr_size;
}
// Save header if caller wants them in the response
if (is_header && op->mProcFlags & PF_SAVE_HEADERS)
@ -654,43 +723,53 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi
{
op->mReplyHeaders = new HttpHeaders;
}
op->mReplyHeaders->appendNormal(hdr_data, wanted_hdr_size);
op->mReplyHeaders->append(name, value ? value : "");
}
// From this point, header-specific processors are free to
// modify the header value.
// Detect and parse 'Content-Range' headers
if (is_header && op->mProcFlags & PF_SCAN_RANGE_HEADER)
if (is_header
&& op->mProcFlags & PF_SCAN_RANGE_HEADER
&& value && *value
&& ! strcmp(name, con_ran_line))
{
char hdr_buffer[128]; // Enough for a reasonable header
size_t frag_size((std::min)(wanted_hdr_size, sizeof(hdr_buffer) - 1));
memcpy(hdr_buffer, hdr_data, frag_size);
hdr_buffer[frag_size] = '\0';
if (frag_size > con_ran_line_len &&
! os_strncasecmp(hdr_buffer, con_ran_line, con_ran_line_len))
{
unsigned int first(0), last(0), length(0);
int status;
unsigned int first(0), last(0), length(0);
int status;
if (! (status = parse_content_range_header(hdr_buffer, &first, &last, &length)))
{
// Success, record the fragment position
op->mReplyOffset = first;
op->mReplyLength = last - first + 1;
op->mReplyFullLength = length;
}
else if (-1 == status)
{
// Response is badly formed and shouldn't be accepted
op->mStatus = HttpStatus(HttpStatus::LLCORE, HE_INV_CONTENT_RANGE_HDR);
}
else
{
// Ignore the unparsable.
LL_INFOS_ONCE("CoreHttp") << "Problem parsing odd Content-Range header: '"
<< std::string(hdr_data, frag_size)
<< "'. Ignoring."
<< LL_ENDL;
}
if (! (status = parse_content_range_header(value, &first, &last, &length)))
{
// Success, record the fragment position
op->mReplyOffset = first;
op->mReplyLength = last - first + 1;
op->mReplyFullLength = length;
}
else if (-1 == status)
{
// Response is badly formed and shouldn't be accepted
op->mStatus = HttpStatus(HttpStatus::LLCORE, HE_INV_CONTENT_RANGE_HDR);
}
else
{
// Ignore the unparsable.
LL_INFOS_ONCE("CoreHttp") << "Problem parsing odd Content-Range header: '"
<< std::string(hdr_data, wanted_hdr_size)
<< "'. Ignoring."
<< LL_ENDL;
}
}
// Detect and parse 'Retry-After' headers
if (is_header
&& op->mProcFlags & PF_USE_RETRY_AFTER
&& value && *value
&& ! strcmp(name, con_retry_line))
{
int time(0);
if (! parse_retry_after_header(value, &time))
{
op->mReplyRetryAfter = time;
}
}
@ -805,14 +884,16 @@ int parse_content_range_header(char * buffer,
unsigned int * last,
unsigned int * length)
{
static const char * const hdr_whitespace(" \t");
char * tok_state(NULL), * tok(NULL);
bool match(true);
if (! os_strtok_r(buffer, hdr_separator, &tok_state))
if (! (tok = os_strtok_r(buffer, hdr_whitespace, &tok_state)))
match = false;
if (match && (tok = os_strtok_r(NULL, hdr_whitespace, &tok_state)))
match = 0 == os_strcasecmp("bytes", tok);
if (match && ! (tok = os_strtok_r(NULL, " \t", &tok_state)))
else
match = (0 == os_strcasecmp("bytes", tok));
if (match && ! (tok = os_strtok_r(NULL, hdr_whitespace, &tok_state)))
match = false;
if (match)
{
@ -851,6 +932,25 @@ int parse_content_range_header(char * buffer,
}
int parse_retry_after_header(char * buffer, int * time)
{
char * endptr(buffer);
long lcl_time(strtol(buffer, &endptr, 10));
if (*endptr == '\0' && endptr != buffer && lcl_time > 0)
{
*time = lcl_time;
return 0;
}
// Could attempt to parse HTTP time here but we're not really
// interested in it. Scheduling based on wallclock time on
// user hardware will lead to tears.
// Header is there but badly/unexpectedly formed, try to ignore it.
return 1;
}
void escape_libcurl_debug_data(char * buffer, size_t len, bool scrub, std::string & safe_line)
{
std::string out;
@ -887,15 +987,6 @@ void escape_libcurl_debug_data(char * buffer, size_t len, bool scrub, std::strin
}
int os_strncasecmp(const char *s1, const char *s2, size_t n)
{
#if LL_WINDOWS
return _strnicmp(s1, s2, n);
#else
return strncasecmp(s1, s2, n);
#endif // LL_WINDOWS
}
int os_strcasecmp(const char *s1, const char *s2)
{
@ -917,6 +1008,45 @@ char * os_strtok_r(char *str, const char *delim, char ** savestate)
}
void os_strlower(char * str)
{
for (char c(0); (c = *str); ++str)
{
*str = tolower(c);
}
}
char * os_strtrim(char * lstr)
{
while (' ' == *lstr || '\t' == *lstr)
{
++lstr;
}
if (*lstr)
{
for (char * rstr(lstr + strlen(lstr)); *--rstr;)
{
if (' ' == *rstr || '\t' == *rstr)
{
*rstr = '\0';
}
}
}
return lstr;
}
char * os_strltrim(char * lstr)
{
while (' ' == *lstr || '\t' == *lstr)
{
++lstr;
}
return lstr;
}
} // end anonymous namespace

View File

@ -158,6 +158,7 @@ protected:
unsigned int mProcFlags;
static const unsigned int PF_SCAN_RANGE_HEADER = 0x00000001U;
static const unsigned int PF_SAVE_HEADERS = 0x00000002U;
static const unsigned int PF_USE_RETRY_AFTER = 0x00000004U;
public:
// Request data
@ -175,6 +176,8 @@ public:
HttpService * mCurlService;
curl_slist * mCurlHeaders;
size_t mCurlBodyPos;
char * mCurlTemp; // Scratch buffer for header processing
size_t mCurlTempLen;
// Result data
HttpStatus mStatus;
@ -184,6 +187,7 @@ public:
size_t mReplyFullLength;
HttpHeaders * mReplyHeaders;
std::string mReplyConType;
int mReplyRetryAfter;
// Policy data
int mPolicyRetries;

View File

@ -160,8 +160,12 @@ void HttpPolicy::retryOp(HttpOpRequest * op)
const HttpTime now(totalTime());
const int policy_class(op->mReqPolicy);
const HttpTime delta(retry_deltas[llclamp(op->mPolicyRetries, 0, delta_max)]);
HttpTime delta(retry_deltas[llclamp(op->mPolicyRetries, 0, delta_max)]);
if (op->mReplyRetryAfter > 0 && op->mReplyRetryAfter < 30)
{
delta = op->mReplyRetryAfter * U64L(1000000);
}
op->mPolicyRetryAt = now + delta;
++op->mPolicyRetries;
if (error_503 == op->mStatus)
@ -170,10 +174,10 @@ void HttpPolicy::retryOp(HttpOpRequest * op)
}
LL_WARNS("CoreHttp") << "HTTP request " << static_cast<HttpHandle>(op)
<< " retry " << op->mPolicyRetries
<< " scheduled for +" << (delta / HttpTime(1000))
<< " scheduled in " << (delta / HttpTime(1000))
<< " mS. Status: " << op->mStatus.toHex()
<< LL_ENDL;
if (op->mTracing > 0)
if (op->mTracing > HTTP_TRACE_OFF)
{
LL_INFOS("CoreHttp") << "TRACE, ToRetryQueue, Handle: "
<< static_cast<HttpHandle>(op)

View File

@ -4,7 +4,7 @@
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, Linden Research, Inc.
* Copyright (C) 2012-2013, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -37,7 +37,7 @@ HttpPolicyClass::HttpPolicyClass()
: mSetMask(0UL),
mConnectionLimit(HTTP_CONNECTION_LIMIT_DEFAULT),
mPerHostConnectionLimit(HTTP_CONNECTION_LIMIT_DEFAULT),
mPipelining(0)
mPipelining(HTTP_PIPELINING_DEFAULT)
{}

View File

@ -55,9 +55,6 @@ HttpService::HttpService()
{
// Create the default policy class
HttpPolicyClass pol_class;
pol_class.set(HttpRequest::CP_CONNECTION_LIMIT, HTTP_CONNECTION_LIMIT_DEFAULT);
pol_class.set(HttpRequest::CP_PER_HOST_CONNECTION_LIMIT, HTTP_CONNECTION_LIMIT_DEFAULT);
pol_class.set(HttpRequest::CP_ENABLE_PIPELINING, 0L);
mPolicyClasses.push_back(pol_class);
}

View File

@ -39,7 +39,8 @@ HttpOptions::HttpOptions()
mTracing(HTTP_TRACE_OFF),
mTimeout(HTTP_REQUEST_TIMEOUT_DEFAULT),
mTransferTimeout(HTTP_REQUEST_XFER_TIMEOUT_DEFAULT),
mRetries(HTTP_RETRY_COUNT_DEFAULT)
mRetries(HTTP_RETRY_COUNT_DEFAULT),
mUseRetryAfter(HTTP_USE_RETRY_AFTER_DEFAULT)
{}
@ -76,5 +77,10 @@ void HttpOptions::setRetries(unsigned int retries)
mRetries = retries;
}
void HttpOptions::setUseRetryAfter(bool use_retry)
{
mUseRetryAfter = use_retry;
}
} // end namespace LLCore

View File

@ -98,13 +98,19 @@ public:
return mRetries;
}
void setUseRetryAfter(bool use_retry);
bool getUseRetryAfter() const
{
return mUseRetryAfter;
}
protected:
bool mWantHeaders;
int mTracing;
unsigned int mTimeout;
unsigned int mTransferTimeout;
unsigned int mRetries;
bool mUseRetryAfter;
}; // end class HttpOptions

View File

@ -72,10 +72,16 @@ void LLAppCoreHttp::init()
"texture fetch"
},
{
AP_MESH, 8, 1, 32, 4,
// *FIXME: Should become 32, 1, 32, 1 before release
AP_MESH1, 8, 1, 32, 4,
"MeshMaxConcurrentRequests",
"mesh fetch"
},
{
AP_MESH2, 8, 1, 32, 4,
"MeshMaxConcurrentRequests",
"mesh2 fetch"
},
{
AP_LARGE_MESH, 2, 1, 8, 1,
"",
@ -171,6 +177,8 @@ void LLAppCoreHttp::init()
}
// Set it and report
// *TODO: These are intended to be per-host limits when we can
// support that in llcorehttp/libcurl.
LLCore::HttpStatus status;
status = LLCore::HttpRequest::setPolicyClassOption(mPolicies[policy],
LLCore::HttpRequest::CP_CONNECTION_LIMIT,

View File

@ -47,7 +47,8 @@ public:
{
AP_DEFAULT,
AP_TEXTURE,
AP_MESH,
AP_MESH1,
AP_MESH2,
AP_LARGE_MESH,
AP_UPLOADS,
AP_COUNT // Must be last

View File

@ -560,6 +560,7 @@ LLMeshRepoThread::LLMeshRepoThread()
mHttpLargeOptions(NULL),
mHttpHeaders(NULL),
mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),
mHttpLegacyPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),
mHttpLargePolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),
mHttpPriority(0),
mHttpGetCount(0U),
@ -574,8 +575,9 @@ LLMeshRepoThread::LLMeshRepoThread()
mHttpLargeOptions->setTransferTimeout(LARGE_MESH_XFER_TIMEOUT);
mHttpHeaders = new LLCore::HttpHeaders;
mHttpHeaders->append("Accept", "application/vnd.ll.mesh");
mHttpPolicyClass = LLAppViewer::instance()->getAppCoreHttp().getPolicy(LLAppCoreHttp::AP_MESH);
mHttpPolicyClass = LLAppViewer::instance()->getAppCoreHttp().getPolicy(LLAppCoreHttp::AP_LARGE_MESH);
mHttpPolicyClass = LLAppViewer::instance()->getAppCoreHttp().getPolicy(LLAppCoreHttp::AP_MESH2);
mHttpLegacyPolicyClass = LLAppViewer::instance()->getAppCoreHttp().getPolicy(LLAppCoreHttp::AP_MESH1);
mHttpLargePolicyClass = LLAppViewer::instance()->getAppCoreHttp().getPolicy(LLAppCoreHttp::AP_LARGE_MESH);
}
@ -795,13 +797,22 @@ void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
}
//static
std::string LLMeshRepoThread::constructUrl(LLUUID mesh_id)
std::string LLMeshRepoThread::constructUrl(LLUUID mesh_id, int * cap_version)
{
int version(1);
std::string http_url;
if (gAgent.getRegion())
{
http_url = gMeshRepo.mGetMeshCapability;
if (! gMeshRepo.mGetMesh2Capability.empty())
{
version = 2;
http_url = gMeshRepo.mGetMesh2Capability;
}
else
{
http_url = gMeshRepo.mGetMeshCapability;
}
}
if (!http_url.empty())
@ -814,20 +825,22 @@ std::string LLMeshRepoThread::constructUrl(LLUUID mesh_id)
llwarns << "Current region does not have GetMesh capability! Cannot load " << mesh_id << ".mesh" << llendl;
}
*cap_version = version;
return http_url;
}
// May only be called by repo thread
LLCore::HttpHandle LLMeshRepoThread::getByteRange(const std::string & url,
size_t offset,
size_t len,
LLCore::HttpHandle LLMeshRepoThread::getByteRange(const std::string & url, int cap_version,
size_t offset, size_t len,
LLCore::HttpHandler * handler)
{
LLCore::HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
if (len < LARGE_MESH_FETCH_THRESHOLD)
{
handle = mHttpRequest->requestGetByteRange(mHttpPolicyClass,
handle = mHttpRequest->requestGetByteRange((2 == cap_version
? mHttpPolicyClass
: mHttpLegacyPolicyClass),
mHttpPriority,
url,
offset,
@ -911,12 +924,13 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
}
//reading from VFS failed for whatever reason, fetch from sim
std::string http_url = constructUrl(mesh_id);
int cap_version(1);
std::string http_url = constructUrl(mesh_id, &cap_version);
if (!http_url.empty())
{
LLMeshSkinInfoHandler * handler = new LLMeshSkinInfoHandler(mesh_id, offset, size);
// LL_WARNS("Mesh") << "MESH: Issuing Skin Info Request" << LL_ENDL;
LLCore::HttpHandle handle = getByteRange(http_url, offset, size, handler);
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
if (LLCORE_HTTP_HANDLE_INVALID == handle)
{
// *TODO: Better error message
@ -1000,12 +1014,13 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
}
//reading from VFS failed for whatever reason, fetch from sim
std::string http_url = constructUrl(mesh_id);
int cap_version(1);
std::string http_url = constructUrl(mesh_id, &cap_version);
if (!http_url.empty())
{
LLMeshDecompositionHandler * handler = new LLMeshDecompositionHandler(mesh_id, offset, size);
// LL_WARNS("Mesh") << "MESH: Issuing Decomp Request" << LL_ENDL;
LLCore::HttpHandle handle = getByteRange(http_url, offset, size, handler);
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
if (LLCORE_HTTP_HANDLE_INVALID == handle)
{
// *TODO: Better error message
@ -1088,12 +1103,13 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
}
//reading from VFS failed for whatever reason, fetch from sim
std::string http_url = constructUrl(mesh_id);
int cap_version(1);
std::string http_url = constructUrl(mesh_id, &cap_version);
if (!http_url.empty())
{
LLMeshPhysicsShapeHandler * handler = new LLMeshPhysicsShapeHandler(mesh_id, offset, size);
// LL_WARNS("Mesh") << "MESH: Issuing Physics Shape Request" << LL_ENDL;
LLCore::HttpHandle handle = getByteRange(http_url, offset, size, handler);
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
if (LLCORE_HTTP_HANDLE_INVALID == handle)
{
// *TODO: Better error message
@ -1177,7 +1193,8 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, U32& c
//either cache entry doesn't exist or is corrupt, request header from simulator
bool retval = true ;
std::string http_url = constructUrl(mesh_params.getSculptID());
int cap_version(1);
std::string http_url = constructUrl(mesh_params.getSculptID(), &cap_version);
if (!http_url.empty())
{
//grab first 4KB if we're going to bother with a fetch. Cache will prevent future fetches if a full mesh fits
@ -1186,7 +1203,7 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, U32& c
LLMeshHeaderHandler * handler = new LLMeshHeaderHandler(mesh_params);
// LL_WARNS("Mesh") << "MESH: Issuing Request" << LL_ENDL;
LLCore::HttpHandle handle = getByteRange(http_url, 0, MESH_HEADER_SIZE, handler);
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, 0, MESH_HEADER_SIZE, handler);
if (LLCORE_HTTP_HANDLE_INVALID == handle)
{
// *TODO: Better error message
@ -1261,12 +1278,13 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod,
}
//reading from VFS failed for whatever reason, fetch from sim
std::string http_url = constructUrl(mesh_id);
int cap_version(1);
std::string http_url = constructUrl(mesh_id, &cap_version);
if (!http_url.empty())
{
LLMeshLODHandler * handler = new LLMeshLODHandler(mesh_params, lod, offset, size);
// LL_WARNS("Mesh") << "MESH: Issuing LOD Request" << LL_ENDL;
LLCore::HttpHandle handle = getByteRange(http_url, offset, size, handler);
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
if (LLCORE_HTTP_HANDLE_INVALID == handle)
{
// *TODO: Better error message
@ -2653,6 +2671,7 @@ void LLMeshRepository::notifyLoadedMeshes()
{
region_name = gAgent.getRegion()->getName();
mGetMeshCapability = gAgent.getRegion()->getCapability("GetMesh");
mGetMesh2Capability = gAgent.getRegion()->getCapability("GetMesh2");
}
}

View File

@ -328,13 +328,14 @@ public:
LLCore::HttpOptions * mHttpLargeOptions;
LLCore::HttpHeaders * mHttpHeaders;
LLCore::HttpRequest::policy_t mHttpPolicyClass;
LLCore::HttpRequest::policy_t mHttpLegacyPolicyClass;
LLCore::HttpRequest::policy_t mHttpLargePolicyClass;
LLCore::HttpRequest::priority_t mHttpPriority;
typedef std::set<LLCore::HttpHandler *> http_request_set;
http_request_set mHttpRequestSet; // Outstanding HTTP requests
static std::string constructUrl(LLUUID mesh_id);
static std::string constructUrl(LLUUID mesh_id, int * cap_version);
LLMeshRepoThread();
~LLMeshRepoThread();
@ -384,7 +385,8 @@ private:
// or dispose of handler.
//
// Threads: Repo thread only
LLCore::HttpHandle getByteRange(const std::string & url, size_t offset, size_t len,
LLCore::HttpHandle getByteRange(const std::string & url, int cap_version,
size_t offset, size_t len,
LLCore::HttpHandler * handler);
private:
@ -595,7 +597,7 @@ public:
void updateInventory(inventory_data data);
std::string mGetMeshCapability;
std::string mGetMesh2Capability;
};
extern LLMeshRepository gMeshRepo;