This commit is contained in:
Shyotl
2015-01-26 15:26:02 -06:00
163 changed files with 3529 additions and 3264 deletions

View File

@@ -35,6 +35,7 @@ set(llmessage_SOURCE_FILES
llares.cpp
llareslistener.cpp
llassetstorage.cpp
llavatarname.cpp
llavatarnamecache.cpp
llblowfishcipher.cpp
llbuffer.cpp
@@ -125,6 +126,7 @@ set(llmessage_HEADER_FILES
llares.h
llareslistener.h
llassetstorage.h
llavatarname.h
llavatarnamecache.h
llblowfishcipher.h
llbuffer.h

View File

@@ -907,7 +907,6 @@ AIHTTPTimeoutPolicy const* AIHTTPTimeoutPolicy::getTimeoutPolicyByName(std::stri
// Policy name Policy
P(assetReportHandler);
P(authHandler);
P(avatarNameResponder);
P2(baseCapabilitiesComplete, transfer_18s_connect_5s);
P(blockingLLSDPost);
P(blockingLLSDGet);
@@ -926,8 +925,6 @@ P(fetchScriptLimitsRegionSummaryResponder);
P(fnPtrResponder);
P(floaterPermsResponder);
P2(gamingDataReceived, transfer_22s_connect_10s);
P(groupBanDataResponder);
P2(groupMemberDataResponder, transfer_300s);
P2(groupProposalBallotResponder, transfer_300s);
P(homeLocationResponder);
P2(HTTPGetResponder, reply_15s);
@@ -936,8 +933,6 @@ P(iamHereVoice);
P2(inventoryModelFetchDescendentsResponder, transfer_300s);
P(inventoryModelFetchItemResponder);
P(lcl_responder);
P(MPImportGetResponder);
P(MPImportPostResponder);
P(mapLayerResponder);
P(materialsResponder);
P2(maturityPreferences, transfer_30s_connect_10s);
@@ -957,21 +952,16 @@ P(regionResponder);
P(remoteParcelRequestResponder);
P(requestAgentUpdateAppearance);
P(responderIgnore);
P(sessionInviteResponder);
P(setDisplayNameResponder);
P2(simulatorFeaturesReceived, transfer_22s_connect_10s);
P(startConferenceChatResponder);
P2(startGroupVoteResponder, transfer_300s);
P(translationReceiver);
P(uploadModelPremissionsResponder);
P(userReportResponder);
P(verifiedDestinationResponder);
P(viewerChatterBoxInvitationAcceptResponder);
P(viewerMediaOpenIDResponder);
P(viewerMediaWebProfileResponder);
P(viewerStatsResponder);
P(vivoxVoiceAccountProvisionResponder);
P(vivoxVoiceClientCapResponder);
P(voiceCallCapResponder);
P(webProfileResponders);
P(wholeModelFeeResponder);

View File

@@ -0,0 +1,254 @@
/**
* @file llavatarname.cpp
* @brief Represents name-related data for an avatar, such as the
* username/SLID ("bobsmith123" or "james.linden") and the display
* name ("James Cook")
*
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "llavatarname.h"
#include "llcontrol.h" // For LLCachedControl
#include "lldate.h"
#include "llframetimer.h"
#include "llsd.h"
// Store these in pre-built std::strings to avoid memory allocations in
// LLSD map lookups
static const std::string USERNAME("username");
static const std::string DISPLAY_NAME("display_name");
static const std::string LEGACY_FIRST_NAME("legacy_first_name");
static const std::string LEGACY_LAST_NAME("legacy_last_name");
static const std::string IS_DISPLAY_NAME_DEFAULT("is_display_name_default");
static const std::string DISPLAY_NAME_EXPIRES("display_name_expires");
static const std::string DISPLAY_NAME_NEXT_UPDATE("display_name_next_update");
bool LLAvatarName::sUseDisplayNames = true;
bool LLAvatarName::sUseUsernames = true;
// Minimum time-to-live (in seconds) for a name entry.
// Avatar name should always guarantee to expire reasonably soon by default
// so if the failure to get a valid expiration time was due to something temporary
// we will eventually request and get the right data.
const F64 MIN_ENTRY_LIFETIME = 60.0;
LLAvatarName::LLAvatarName()
: mUsername(),
mDisplayName(),
mLegacyFirstName(),
mLegacyLastName(),
mIsDisplayNameDefault(false),
mIsTemporaryName(false),
mExpires(F64_MAX),
mNextUpdate(0.0)
{ }
bool LLAvatarName::operator<(const LLAvatarName& rhs) const
{
if (mUsername == rhs.mUsername)
return mDisplayName < rhs.mDisplayName;
else
return mUsername < rhs.mUsername;
}
//static
void LLAvatarName::setUseDisplayNames(bool use)
{
sUseDisplayNames = use;
}
//static
bool LLAvatarName::useDisplayNames()
{
return sUseDisplayNames;
}
void LLAvatarName::setUseUsernames(bool use)
{
sUseUsernames = use;
}
bool LLAvatarName::useUsernames()
{
return sUseUsernames;
}
LLSD LLAvatarName::asLLSD() const
{
LLSD sd;
sd[USERNAME] = mUsername;
sd[DISPLAY_NAME] = mDisplayName;
sd[LEGACY_FIRST_NAME] = mLegacyFirstName;
sd[LEGACY_LAST_NAME] = mLegacyLastName;
sd[IS_DISPLAY_NAME_DEFAULT] = mIsDisplayNameDefault;
sd[DISPLAY_NAME_EXPIRES] = LLDate(mExpires);
sd[DISPLAY_NAME_NEXT_UPDATE] = LLDate(mNextUpdate);
return sd;
}
void LLAvatarName::fromLLSD(const LLSD& sd)
{
mUsername = sd[USERNAME].asString();
mDisplayName = sd[DISPLAY_NAME].asString();
mLegacyFirstName = sd[LEGACY_FIRST_NAME].asString();
mLegacyLastName = sd[LEGACY_LAST_NAME].asString();
mIsDisplayNameDefault = sd[IS_DISPLAY_NAME_DEFAULT].asBoolean() || mUsername == mDisplayName;
LLDate expires = sd[DISPLAY_NAME_EXPIRES];
mExpires = expires.secondsSinceEpoch();
LLDate next_update = sd[DISPLAY_NAME_NEXT_UPDATE];
mNextUpdate = next_update.secondsSinceEpoch();
// Some avatars don't have explicit display names set. Force a legible display name here.
if (mDisplayName.empty())
{
mDisplayName = mUsername;
mIsDisplayNameDefault = true;
}
}
// Transform a string (typically provided by the legacy service) into a decent
// avatar name instance.
void LLAvatarName::fromString(const std::string& full_name)
{
mDisplayName = full_name;
std::string::size_type index = full_name.find(' ');
if (index != std::string::npos)
{
// The name is in 2 parts (first last)
mLegacyFirstName = full_name.substr(0, index);
mLegacyLastName = full_name.substr(index+1);
if (mLegacyLastName != "Resident")
{
mUsername = mLegacyFirstName + "." + mLegacyLastName;
mDisplayName = full_name;
LLStringUtil::toLower(mUsername);
}
else
{
// Very old names do have a dummy "Resident" last name
// that we choose to hide from users.
mUsername = mLegacyFirstName;
mDisplayName = mLegacyFirstName;
}
}
else
{
mLegacyFirstName = full_name;
mLegacyLastName = "";
mUsername = full_name;
mDisplayName = full_name;
}
mIsDisplayNameDefault = true;
mIsTemporaryName = true;
setExpires(MIN_ENTRY_LIFETIME);
}
void LLAvatarName::setExpires(F64 expires)
{
mExpires = LLFrameTimer::getTotalSeconds() + expires;
}
std::string LLAvatarName::getCompleteName(bool linefeed) const
{
std::string name;
if (sUseDisplayNames)
{
if (mUsername.empty() || mIsDisplayNameDefault)
{
// If this particular display name is defaulted (i.e. based on user name),
// then display only the easier to read instance of the person's name.
name = mDisplayName;
}
else
{
name = mDisplayName;
if (sUseUsernames)
{
name += (linefeed ? "\n(" : " (") + mUsername + ")";
}
}
}
else
{
name = getUserName();
}
return name;
}
std::string LLAvatarName::getLegacyName() const
{
if (mLegacyFirstName.empty() && mLegacyLastName.empty()) // display names disabled?
{
return mDisplayName;
}
static const LLCachedControl<bool> show_resident("LiruShowLastNameResident", false);
if (show_resident || mLegacyLastName != "Resident")
return mLegacyFirstName + ' ' + mLegacyLastName;
return mLegacyFirstName;
}
std::string LLAvatarName::getDisplayName() const
{
if (sUseDisplayNames)
{
return mDisplayName;
}
else
{
return getUserName();
}
}
std::string LLAvatarName::getUserName() const
{
std::string name;
if (mLegacyLastName.empty() /*|| (mLegacyLastName == "Resident")*/) // <alchemy/>
{
if (mLegacyFirstName.empty())
{
// If we cannot create a user name from the legacy strings, use the display name
name = mDisplayName;
}
else
{
// The last name might be empty if it defaulted to "Resident"
name = mLegacyFirstName;
}
}
else
{
name = mLegacyFirstName + " " + mLegacyLastName;
}
return name;
}
void LLAvatarName::dump() const
{
LL_DEBUGS("AvNameCache") << "LLAvatarName: "
<< "user '" << mUsername << "' "
<< "display '" << mDisplayName << "' "
<< "expires in " << mExpires - LLFrameTimer::getTotalSeconds() << " seconds"
<< LL_ENDL;
}

View File

@@ -0,0 +1,153 @@
/**
* @file llavatarname.h
* @brief Represents name-related data for an avatar, such as the
* username/SLID ("bobsmith123" or "james.linden") and the display
* name ("James Cook")
*
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 LLAVATARNAME_H
#define LLAVATARNAME_H
#include <string>
const S32& main_name_system();
class LLSD;
class LLAvatarName
{
public:
LLAvatarName();
bool operator<(const LLAvatarName& rhs) const;
// Conversion to and from LLSD (cache file or server response)
LLSD asLLSD() const;
void fromLLSD(const LLSD& sd);
// Used only in legacy mode when the display name capability is not provided server side
// or to otherwise create a temporary valid item.
void fromString(const std::string& full_name);
// Set the name object to become invalid in "expires" seconds from now
void setExpires(F64 expires);
// Set and get the display name flag set by the user in preferences.
static void setUseDisplayNames(bool use);
static bool useDisplayNames();
static void setUseUsernames(bool use);
static bool useUsernames();
// A name object is valid if not temporary and not yet expired (default is expiration not checked)
bool isValidName(F64 max_unrefreshed = 0.0f) const { return !mIsTemporaryName && (mExpires >= max_unrefreshed); }
// Return true if the name is made up from legacy or temporary data
bool isDisplayNameDefault() const { return mIsDisplayNameDefault; }
// For normal names, returns "James Linden (james.linden)"
// When display names are disabled returns just "James Linden"
std::string getCompleteName(bool linefeed = false) const;
// Returns "James Linden" or "bobsmith123 Resident" for backwards
// compatibility with systems like voice and muting
// *TODO: Eliminate this in favor of username only
std::string getLegacyName() const;
// "Jos<6F> Sanchez" or "James Linden", UTF-8 encoded Unicode
// Takes the display name preference into account. This is truly the name that should
// be used for all UI where an avatar name has to be used unless we truly want something else (rare)
std::string getDisplayName() const;
// Returns "James Linden" or "bobsmith123 Resident"
// Used where we explicitely prefer or need a non UTF-8 legacy (ASCII) name
// Also used for backwards compatibility with systems like voice and muting
std::string getUserName() const;
// Returns "james.linden" or the legacy name for very old names
std::string getAccountName() const { return mUsername; }
// Returns name in the format desired according to name_system
std::string getNSName(const S32& name_system = main_name_system()) const
{
switch (name_system)
{
case 1 : return getCompleteName();
case 2 : return getDisplayName();
case 3 : return getLegacyName() + (mIsDisplayNameDefault ? "" : " (" + mDisplayName + ")"); break;
default : return getLegacyName();
}
}
// Debug print of the object
void dump() const;
// Names can change, so need to keep track of when name was
// last checked.
// Unix time-from-epoch seconds for efficiency
F64 mExpires;
// You can only change your name every N hours, so record
// when the next update is allowed
// Unix time-from-epoch seconds
F64 mNextUpdate;
private:
// "bobsmith123" or "james.linden", US-ASCII only
std::string mUsername;
// "Jos<6F> Sanchez" or "James Linden", UTF-8 encoded Unicode
// Contains data whether or not user has explicitly set
// a display name; may duplicate their username.
std::string mDisplayName;
// For "James Linden", "James"
// For "bobsmith123", "bobsmith123"
// Used to communicate with legacy systems like voice and muting which
// rely on old-style names.
// *TODO: Eliminate this in favor of username only
std::string mLegacyFirstName;
// For "James Linden", "Linden"
// For "bobsmith123", "Resident"
// see above for rationale
std::string mLegacyLastName;
// If true, both display name and SLID were generated from
// a legacy first and last name, like "James Linden (james.linden)"
bool mIsDisplayNameDefault;
// Under error conditions, we may insert "dummy" records with
// names like "???" into caches as placeholders. These can be
// shown in UI, but are not serialized.
bool mIsTemporaryName;
// Global flag indicating if display name should be used or not
// This will affect the output of the high level "get" methods
static bool sUseDisplayNames;
// Flag indicating if username should be shown after display name or not
static bool sUseUsernames;
};
#endif

View File

@@ -44,10 +44,6 @@ namespace LLAvatarNameCache
{
use_display_name_signal_t mUseDisplayNamesSignal;
// Manual override for display names - can disable even if the region
// supports it.
bool sUseDisplayNames = true;
// [RLVa:KB] - Checked: 2010-12-08 (RLVa-1.4.0a) | Added: RLVa-1.2.2c
// RLVa override for display names
bool sForceDisplayNames = false;
@@ -57,18 +53,22 @@ namespace LLAvatarNameCache
// current region supports display names.
bool sRunning = false;
// Use the People API (modern) for fetching name if true. Use the old legacy protocol if false.
// For testing, there's a UsePeopleAPI setting that can be flipped (must restart viewer).
bool sUsePeopleAPI = true;
// Base lookup URL for name service.
// On simulator, loaded from indra.xml
// On viewer, usually a simulator capability (at People API team's request)
// Includes the trailing slash, like "http://pdp60.lindenlab.com:8000/agents/"
std::string sNameLookupURL;
// accumulated agent IDs for next query against service
// Accumulated agent IDs for next query against service
typedef std::set<LLUUID> ask_queue_t;
ask_queue_t sAskQueue;
// agent IDs that have been requested, but with no reply
// maps agent ID to frame time request was made
// Agent IDs that have been requested, but with no reply.
// Maps agent ID to frame time request was made.
typedef std::map<LLUUID, F64> pending_queue_t;
pending_queue_t sPendingQueue;
@@ -79,21 +79,21 @@ namespace LLAvatarNameCache
typedef std::map<LLUUID, callback_signal_t*> signal_map_t;
signal_map_t sSignalMap;
// names we know about
// The cache at last, i.e. avatar names we know about.
typedef std::map<LLUUID, LLAvatarName> cache_t;
cache_t sCache;
// Send bulk lookup requests a few times a second at most
// only need per-frame timing resolution
// Send bulk lookup requests a few times a second at most.
// Only need per-frame timing resolution.
LLFrameTimer sRequestTimer;
/// Maximum time an unrefreshed cache entry is allowed
// Maximum time an unrefreshed cache entry is allowed.
const F64 MAX_UNREFRESHED_TIME = 20.0 * 60.0;
/// Time when unrefreshed cached names were checked last
// Time when unrefreshed cached names were checked last.
static F64 sLastExpireCheck;
/// Time-to-live for a temp cache entry.
// Time-to-live for a temp cache entry.
const F64 TEMP_CACHE_ENTRY_LIFETIME = 60.0;
//-----------------------------------------------------------------------
@@ -101,26 +101,21 @@ namespace LLAvatarNameCache
//-----------------------------------------------------------------------
// Handle name response off network.
// Optionally skip adding to cache, used when this is a fallback to the
// legacy name system.
void processName(const LLUUID& agent_id,
const LLAvatarName& av_name,
bool add_to_cache);
const LLAvatarName& av_name);
void requestNamesViaCapability();
// Legacy name system callback
// Legacy name system callbacks
void legacyNameCallback(const LLUUID& agent_id,
const std::string& full_name,
bool is_group
);
bool is_group);
void legacyNameFetch(const LLUUID& agent_id,
const std::string& full_name,
bool is_group);
void requestNamesViaLegacy();
// Fill in an LLAvatarName with the legacy name data
void buildLegacyName(const std::string& full_name,
LLAvatarName* av_name);
// Do a single callback to a given slot
void fireSignal(const LLUUID& agent_id,
const callback_slot_t& slot,
@@ -174,31 +169,37 @@ namespace LLAvatarNameCache
</llsd>
*/
class AIHTTPTimeoutPolicy;
extern AIHTTPTimeoutPolicy avatarNameResponder_timeout;
class LLAvatarNameResponder : public LLHTTPClient::ResponderWithResult
{
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;
// Need the headers to look up Expires: and Retry-After:
virtual bool needsHeaders(void) const { return true; }
/*virtual*/ bool needsHeaders() const { return true; }
/*virtual*/ char const* getName() const { return "LLAvatarNameResponder"; }
public:
LLAvatarNameResponder(const std::vector<LLUUID>& agent_ids)
: mAgentIDs(agent_ids)
{ }
/*virtual*/ void httpSuccess(void)
protected:
/*virtual*/ void httpSuccess()
{
const LLSD& content = getContent();
if (!content.isMap())
{
failureResult(HTTP_INTERNAL_ERROR_OTHER, "Malformed response contents", content);
return;
}
// Pull expiration out of headers if available
F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(mReceivedHeaders);
F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(getResponseHeaders());
F64 now = LLFrameTimer::getTotalSeconds();
LLSD agents = mContent["agents"];
const LLSD& agents = content["agents"];
LLSD::array_const_iterator it = agents.beginArray();
for ( ; it != agents.endArray(); ++it)
{
@@ -211,24 +212,15 @@ public:
// Use expiration time from header
av_name.mExpires = expires;
// Some avatars don't have explicit display names set
if (av_name.mDisplayName.empty())
{
av_name.mDisplayName = av_name.mUsername;
}
LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result for " << agent_id << " "
<< "user '" << av_name.mUsername << "' "
<< "display '" << av_name.mDisplayName << "' "
<< "expires in " << expires - now << " seconds"
<< 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, true);
LLAvatarNameCache::processName(agent_id, av_name);
}
// Same logic as error response case
LLSD unresolved_agents = mContent["bad_ids"];
const LLSD& unresolved_agents = content["bad_ids"];
S32 num_unresolved = unresolved_agents.size();
if (num_unresolved > 0)
{
@@ -252,14 +244,13 @@ public:
<< LL_ENDL;
}
/*virtual*/ void httpFailure(void)
/*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") << "LLAvatarNameResponder::httpFailure " << mStatus << " " << mReason
<< LL_ENDL;
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();
@@ -269,9 +260,6 @@ public:
LLAvatarNameCache::handleAgentError(agent_id);
}
}
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return avatarNameResponder_timeout; }
/*virtual*/ char const* getName(void) const { return "LLAvatarNameResponder"; }
};
// Provide some fallback for agents that return errors
@@ -284,48 +272,34 @@ void LLAvatarNameCache::handleAgentError(const LLUUID& agent_id)
LL_WARNS("AvNameCache") << "LLAvatarNameCache get legacy for agent "
<< agent_id << LL_ENDL;
gCacheName->get(agent_id, false, // legacy compatibility
boost::bind(&LLAvatarNameCache::legacyNameCallback,
_1, _2, _3));
boost::bind(&LLAvatarNameCache::legacyNameFetch, _1, _2, _3));
}
else
{
// we have a chached (but probably expired) entry - since that would have
// we have a cached (but probably expired) entry - since that would have
// been returned by the get method, there is no need to signal anyone
// Clear this agent from the pending list
LLAvatarNameCache::sPendingQueue.erase(agent_id);
LLAvatarName& av_name = existing->second;
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache use cache for agent "
<< agent_id
<< "user '" << av_name.mUsername << "' "
<< "display '" << av_name.mDisplayName << "' "
<< "expires in " << av_name.mExpires - LLFrameTimer::getTotalSeconds() << " seconds"
<< LL_ENDL;
av_name.mExpires = LLFrameTimer::getTotalSeconds() + TEMP_CACHE_ENTRY_LIFETIME; // reset expiry time so we don't constantly rerequest.
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache use cache for agent " << agent_id << LL_ENDL;
av_name.dump();
// Reset expiry time so we don't constantly rerequest.
av_name.setExpires(TEMP_CACHE_ENTRY_LIFETIME);
}
}
void LLAvatarNameCache::processName(const LLUUID& agent_id,
const LLAvatarName& av_name,
bool add_to_cache)
void LLAvatarNameCache::processName(const LLUUID& agent_id, const LLAvatarName& av_name)
{
if (add_to_cache)
{
// sCache[agent_id] = av_name;
// [SL:KB] - Patch: Agent-DisplayNames | Checked: 2010-12-28 (Catznip-2.4.0h) | Added: Catznip-2.4.0h
// Don't replace existing entries with dummies
cache_t::iterator itName = (av_name.mIsTemporaryName) ? sCache.find(agent_id) : sCache.end();
if (sCache.end() != itName)
itName->second.mExpires = av_name.mExpires;
else
sCache[agent_id] = av_name;
// [/SL:KB]
}
// Add to the cache
sCache[agent_id] = av_name;
// Suppress request from the queue
sPendingQueue.erase(agent_id);
// signal everyone waiting on this name
// Signal everyone waiting on this name
signal_map_t::iterator sig_it = sSignalMap.find(agent_id);
if (sig_it != sSignalMap.end())
{
@@ -356,7 +330,6 @@ void LLAvatarNameCache::requestNamesViaCapability()
std::vector<LLUUID> agent_ids;
agent_ids.reserve(128);
U32 id_total = sAskQueue.size();
U32 ids = 0;
ask_queue_t::const_iterator it;
while(!sAskQueue.empty())
@@ -393,7 +366,7 @@ void LLAvatarNameCache::requestNamesViaCapability()
if (!url.empty())
{
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability requested "
<< ids << "/" << id_total << "ids "
<< ids << " ids"
<< LL_ENDL;
LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids));
}
@@ -403,22 +376,33 @@ void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id,
const std::string& full_name,
bool is_group)
{
// Construct a dummy record for this name. By convention, SLID is blank
// Never expires, but not written to disk, so lasts until end of session.
LLAvatarName av_name;
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::legacyNameCallback "
// Put the received data in the cache
legacyNameFetch(agent_id, full_name, is_group);
// Retrieve the name and set it to never (or almost never...) expire: when we are using the legacy
// protocol, we do not get an expiration date for each name and there's no reason to ask the
// data again and again so we set the expiration time to the largest value admissible.
std::map<LLUUID,LLAvatarName>::iterator av_record = sCache.find(agent_id);
LLAvatarName& av_name = av_record->second;
av_name.setExpires(MAX_UNREFRESHED_TIME);
}
void LLAvatarNameCache::legacyNameFetch(const LLUUID& agent_id,
const std::string& full_name,
bool is_group)
{
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::legacyNameFetch "
<< "agent " << agent_id << " "
<< "full name '" << full_name << "'"
<< ( is_group ? " [group]" : "" )
<< LL_ENDL;
buildLegacyName(full_name, &av_name);
// Add to cache, because if we don't we'll keep rerequesting the
// same record forever. buildLegacyName should always guarantee
// that these records expire reasonably soon
// (in TEMP_CACHE_ENTRY_LIFETIME seconds), so if the failure was due
// to something temporary we will eventually request and get the right data.
processName(agent_id, av_name, true);
// Construct an av_name record from this name.
LLAvatarName av_name;
av_name.fromString(full_name);
// Add to cache: we're still using the new cache even if we're using the old (legacy) protocol.
processName(agent_id, av_name);
}
void LLAvatarNameCache::requestNamesViaLegacy()
@@ -440,25 +424,28 @@ void LLAvatarNameCache::requestNamesViaLegacy()
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaLegacy agent " << agent_id << LL_ENDL;
gCacheName->get(agent_id, false, // legacy compatibility
boost::bind(&LLAvatarNameCache::legacyNameCallback,
_1, _2, _3));
boost::bind(&LLAvatarNameCache::legacyNameCallback, _1, _2, _3));
}
}
void LLAvatarNameCache::initClass(bool running)
void LLAvatarNameCache::initClass(bool running, bool usePeopleAPI)
{
sRunning = running;
sUsePeopleAPI = usePeopleAPI;
}
void LLAvatarNameCache::cleanupClass()
{
sCache.clear();
}
void LLAvatarNameCache::importFile(std::istream& istr)
{
LLSD data;
S32 parse_count = LLSDSerialize::fromXMLDocument(data, istr);
if (parse_count < 1) return;
if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXMLDocument(data, istr))
{
return;
}
// by convention LLSD storage is a map
// we only store one entry in the map
@@ -490,7 +477,7 @@ void LLAvatarNameCache::exportFile(std::ostream& ostr)
const LLUUID& agent_id = it->first;
const LLAvatarName& av_name = it->second;
// Do not write temporary or expired entries to the stored cache
if (!av_name.mIsTemporaryName && av_name.mExpires >= max_unrefreshed)
if (av_name.isValidName(max_unrefreshed))
{
// key must be a string
agents[agent_id.asString()] = av_name.asLLSD();
@@ -511,6 +498,11 @@ bool LLAvatarNameCache::hasNameLookupURL()
return !sNameLookupURL.empty();
}
bool LLAvatarNameCache::usePeopleAPI()
{
return hasNameLookupURL() && sUsePeopleAPI;
}
void LLAvatarNameCache::idle()
{
// By convention, start running at first idle() call
@@ -527,13 +519,12 @@ void LLAvatarNameCache::idle()
if (!sAskQueue.empty())
{
if (useDisplayNames())
if (usePeopleAPI())
{
requestNamesViaCapability();
}
else
{
// ...fall back to legacy name cache system
requestNamesViaLegacy();
}
}
@@ -541,7 +532,7 @@ void LLAvatarNameCache::idle()
if (sAskQueue.empty())
{
// cleared the list, reset the request timer.
sRequestTimer.reset(SECS_BETWEEN_REQUESTS);
sRequestTimer.resetWithExpiry(SECS_BETWEEN_REQUESTS);
}
// erase anything that has not been refreshed for more than MAX_UNREFRESHED_TIME
@@ -577,9 +568,8 @@ void LLAvatarNameCache::eraseUnrefreshed()
const LLAvatarName& av_name = it->second;
if (av_name.mExpires < max_unrefreshed)
{
const LLUUID& agent_id = it->first;
LL_DEBUGS("AvNameCache") << agent_id
<< " user '" << av_name.mUsername << "' "
LL_DEBUGS("AvNameCache") << it->first
<< " user '" << av_name.getAccountName() << "' "
<< "expired " << now - av_name.mExpires << " secs ago"
<< LL_ENDL;
sCache.erase(it++);
@@ -593,29 +583,6 @@ void LLAvatarNameCache::eraseUnrefreshed()
}
}
void LLAvatarNameCache::buildLegacyName(const std::string& full_name,
LLAvatarName* av_name)
{
llassert(av_name);
av_name->mUsername = "";
av_name->mDisplayName = full_name;
av_name->mIsDisplayNameDefault = true;
av_name->mIsTemporaryName = true;
av_name->mExpires = LLFrameTimer::getTotalSeconds() + TEMP_CACHE_ENTRY_LIFETIME;
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::buildLegacyName "
<< full_name
<< LL_ENDL;
// [Ansariel/Henri]
// Why ain't those set? In case of disabled display names
// we would have to parse LLAvatarName::mDisplayName to get
// first and lastname if we need them. So do it already here
// for convenience.
std::istringstream fname(full_name);
fname >> av_name->mLegacyFirstName >> av_name->mLegacyLastName;
// [/Ansariel/Henri]
}
// fills in av_name if it has it in the cache, even if expired (can check expiry time)
// returns bool specifying if av_name was filled, false otherwise
bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name)
@@ -623,36 +590,32 @@ bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name)
if (sRunning)
{
// ...only do immediate lookups when cache is running
if (useDisplayNames())
std::map<LLUUID,LLAvatarName>::iterator it = sCache.find(agent_id);
if (it != sCache.end())
{
// ...use display names cache
std::map<LLUUID,LLAvatarName>::iterator it = sCache.find(agent_id);
if (it != sCache.end())
{
*av_name = it->second;
*av_name = it->second;
// re-request name if entry is expired
if (av_name->mExpires < LLFrameTimer::getTotalSeconds())
// re-request name if entry is expired
if (av_name->mExpires < LLFrameTimer::getTotalSeconds())
{
if (!isRequestPending(agent_id))
{
if (!isRequestPending(agent_id))
{
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::get "
<< "refresh agent " << agent_id
<< LL_ENDL;
sAskQueue.insert(agent_id);
}
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::get "
<< "refresh agent " << agent_id
<< LL_ENDL;
sAskQueue.insert(agent_id);
}
return true;
}
return true;
}
else
else if (!usePeopleAPI())
{
// ...use legacy names cache
std::string full_name;
if (gCacheName->getFullName(agent_id, full_name))
{
buildLegacyName(full_name, av_name);
av_name->fromString(full_name);
sCache[agent_id] = *av_name;
return true;
}
}
@@ -669,35 +632,22 @@ bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name)
return false;
}
const S32& LLAvatarNameCache::phoenix_name_system()
const S32& main_name_system()
{
static const LLCachedControl<S32> name_system("PhoenixNameSystem", 0);
return name_system;
}
// Return true when name has been set to Phoenix Name System Name, if not return false.
bool LLAvatarNameCache::getPNSName(const LLUUID& agent_id, std::string& name, const S32& name_system)
// Return true when name has been set to Name System Name, if not return false.
bool LLAvatarNameCache::getNSName(const LLUUID& agent_id, std::string& name, const S32& name_system)
{
LLAvatarName avatar_name;
if (get(agent_id, &avatar_name))
getPNSName(avatar_name, name, name_system);
name = avatar_name.getNSName(name_system);
else return false;
return true;
}
// get() with callback compatible version of getPNSName
void LLAvatarNameCache::getPNSName(const LLAvatarName& avatar_name, std::string& name, const S32& name_system)
{
switch (name_system)
{
case 0 : name = avatar_name.getLegacyName(); break;
case 1 : name = avatar_name.getCompleteName(); break;
case 2 : name = avatar_name.mDisplayName; break;
case 3 : name = avatar_name.getLegacyName() + (avatar_name.mIsDisplayNameDefault ? "" : " (" + avatar_name.mDisplayName + ")"); break;
default : name = avatar_name.getLegacyName(); break;
}
}
void LLAvatarNameCache::fireSignal(const LLUUID& agent_id,
const callback_slot_t& slot,
const LLAvatarName& av_name)
@@ -714,30 +664,14 @@ LLAvatarNameCache::callback_connection_t LLAvatarNameCache::get(const LLUUID& ag
if (sRunning)
{
// ...only do immediate lookups when cache is running
if (useDisplayNames())
std::map<LLUUID,LLAvatarName>::iterator it = sCache.find(agent_id);
if (it != sCache.end())
{
// ...use new cache
std::map<LLUUID,LLAvatarName>::iterator it = sCache.find(agent_id);
if (it != sCache.end())
const LLAvatarName& av_name = it->second;
if (av_name.mExpires > LLFrameTimer::getTotalSeconds())
{
const LLAvatarName& av_name = it->second;
if (av_name.mExpires > LLFrameTimer::getTotalSeconds())
{
// ...name already exists in cache, fire callback now
fireSignal(agent_id, slot, av_name);
return connection;
}
}
}
else
{
// ...use old name system
std::string full_name;
if (gCacheName->getFullName(agent_id, full_name))
{
LLAvatarName av_name;
buildLegacyName(full_name, &av_name);
// ...name already exists in cache, fire callback now
fireSignal(agent_id, slot, av_name);
return connection;
}
@@ -778,7 +712,7 @@ bool LLAvatarNameCache::getForceDisplayNames()
void LLAvatarNameCache::setForceDisplayNames(bool force)
{
sForceDisplayNames = force;
if ( (!sUseDisplayNames) && (force) )
if ( (!LLAvatarName::useDisplayNames()) && (force) )
{
setUseDisplayNames(true);
}
@@ -791,21 +725,20 @@ void LLAvatarNameCache::setUseDisplayNames(bool use)
// We need to force the use of the "display names" cache when @shownames=n restricted (and disallow toggling it)
use |= getForceDisplayNames();
// [/RLVa:KB]
if (use != sUseDisplayNames)
if (use != LLAvatarName::useDisplayNames())
{
sUseDisplayNames = use;
LL_DEBUGS("AvNameCache") << "Display names are now: " << (use ? "on" : "off") << LL_ENDL;
// flush our cache
sCache.clear();
LLAvatarName::setUseDisplayNames(use);
mUseDisplayNamesSignal();
}
}
bool LLAvatarNameCache::useDisplayNames()
void LLAvatarNameCache::setUseUsernames(bool use)
{
// Must be both manually set on and able to look up names.
return sUseDisplayNames && !sNameLookupURL.empty();
if (use != LLAvatarName::useUsernames())
{
LLAvatarName::setUseUsernames(use);
mUseDisplayNamesSignal();
}
}
void LLAvatarNameCache::erase(const LLUUID& agent_id)
@@ -839,6 +772,7 @@ bool LLAvatarNameCache::expirationFromCacheControl(AIHTTPReceivedHeaders const&
{
bool fromCacheControl = false;
F64 now = LLFrameTimer::getTotalSeconds();
// Allow the header to override the default
std::string cache_control;
if (headers.getFirstValue("cache-control", cache_control))

View File

@@ -32,46 +32,41 @@
#include <boost/signals2.hpp>
class LLUUID;
class AIHTTPReceivedHeaders;
class LLUUID;
namespace LLAvatarNameCache
{
typedef boost::signals2::signal<void (void)> use_display_name_signal_t;
// Until the cache is set running, immediate lookups will fail and
// async lookups will be queued. This allows us to block requests
// until we know if the first region supports display names.
void initClass(bool running);
void initClass(bool running, bool usePeopleAPI);
void cleanupClass();
// Import/export the name cache to file.
void importFile(std::istream& istr);
void exportFile(std::ostream& ostr);
// On the viewer, usually a simulator capabilitity
// If empty, name cache will fall back to using legacy name
// lookup system
// On the viewer, usually a simulator capabilitity.
// If empty, name cache will fall back to using legacy name lookup system.
void setNameLookupURL(const std::string& name_lookup_url);
// Do we have a valid lookup URL, hence are we trying to use the
// new display name lookup system?
// Do we have a valid lookup URL, i.e. are we trying to use the
// more recent display name lookup system?
bool hasNameLookupURL();
bool usePeopleAPI();
// Periodically makes a batch request for display names not already in
// cache. Call once per frame.
// cache. Called once per frame.
void idle();
// If name is in cache, returns true and fills in provided LLAvatarName
// otherwise returns false
// otherwise returns false.
bool get(const LLUUID& agent_id, LLAvatarName *av_name);
const S32& phoenix_name_system();
// If get() succeeds, returns true and fills in name string
// via void function below, otherwise returns false
bool getPNSName(const LLUUID& agent_id, std::string& name, const S32& name_system = phoenix_name_system());
// Perform a filling of name string according to Phoenix Name System,
// when we have an LLAvatarName already.
void getPNSName(const LLAvatarName& avatar_name, std::string& name, const S32& name_system = phoenix_name_system());
// If get() succeeds, returns true and fills in name string via void function below, otherwise returns false
bool getNSName(const LLUUID& agent_id, std::string& name, const S32& name_system = main_name_system());
// Callback types for get() below
typedef boost::signals2::signal<
@@ -80,29 +75,29 @@ namespace LLAvatarNameCache
typedef callback_signal_t::slot_type callback_slot_t;
typedef boost::signals2::connection callback_connection_t;
// Fetches name information and calls callback.
// If name information is in cache, callback will be called immediately.
// Fetches name information and calls callbacks.
// If name information is in cache, callbacks will be called immediately.
callback_connection_t get(const LLUUID& agent_id, callback_slot_t slot);
// Allow display names to be explicitly disabled for testing.
// Set display name: flips the switch and triggers the callbacks.
void setUseDisplayNames(bool use);
bool useDisplayNames();
// [RLVa:KB] - Checked: 2010-12-08 (RLVa-1.4.0a) | Added: RLVa-1.2.2c
bool getForceDisplayNames();
void setForceDisplayNames(bool force);
// [/RLVa:KB]
void erase(const LLUUID& agent_id);
/// Provide some fallback for agents that return errors
void handleAgentError(const LLUUID& agent_id);
void setUseUsernames(bool use);
void insert(const LLUUID& agent_id, const LLAvatarName& av_name);
void erase(const LLUUID& agent_id);
/// Provide some fallback for agents that return errors.
void handleAgentError(const LLUUID& agent_id);
// Compute name expiration time from HTTP Cache-Control header,
// or return default value, in seconds from epoch.
F64 nameExpirationFromHeaders(AIHTTPReceivedHeaders const& headers);
F64 nameExpirationFromHeaders(const AIHTTPReceivedHeaders& headers);
void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb);
}

View File

@@ -279,7 +279,9 @@ LLCacheName::Impl::Impl(LLMessageSystem* msg)
LLCacheName::Impl::~Impl()
{
for_each(mCache.begin(), mCache.end(), DeletePairedPointer());
mCache.clear();
for_each(mReplyQueue.begin(), mReplyQueue.end(), DeletePointer());
mReplyQueue.clear();
}
boost::signals2::connection LLCacheName::Impl::addPending(const LLUUID& id, const LLCacheNameCallback& callback)
@@ -309,8 +311,10 @@ boost::signals2::connection LLCacheName::addObserver(const LLCacheNameCallback&
bool LLCacheName::importFile(std::istream& istr)
{
LLSD data;
if(LLSDSerialize::fromXMLDocument(data, istr) < 1)
if(LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXMLDocument(data, istr))
{
return false;
}
// We'll expire entries more than a week old
U32 now = (U32)time(NULL);
@@ -527,6 +531,7 @@ std::string LLCacheName::cleanFullName(const std::string& full_name)
}
//static
// Transform hard-coded name provided by server to a more legible username
std::string LLCacheName::buildUsername(const std::string& full_name)
{
// rare, but handle hard-coded error names returned from server
@@ -553,8 +558,9 @@ std::string LLCacheName::buildUsername(const std::string& full_name)
return username;
}
// if the input wasn't a correctly formatted legacy name just return it unchanged
return full_name;
// if the input wasn't a correctly formatted legacy name, just return it
// cleaned up from a potential terminal "Resident"
return cleanFullName(full_name);
}
//static
@@ -562,13 +568,13 @@ std::string LLCacheName::buildLegacyName(const std::string& complete_name)
{
//boost::regexp was showing up in the crashreporter, so doing
//painfully manual parsing using substr. LF
S32 open_paren = complete_name.rfind(" (");
S32 close_paren = complete_name.rfind(')');
size_t open_paren = complete_name.rfind(" (");
size_t close_paren = complete_name.rfind(')');
if (open_paren != std::string::npos &&
close_paren == complete_name.length()-1)
{
S32 length = close_paren - open_paren - 2;
size_t length = llmax(close_paren - open_paren - 2, (size_t)0);
std::string legacy_name = complete_name.substr(open_paren+2, length);
if (legacy_name.length() > 0)
@@ -577,7 +583,7 @@ std::string LLCacheName::buildLegacyName(const std::string& complete_name)
LLStringUtil::toUpper(cap_letter);
legacy_name = cap_letter + legacy_name.substr(1);
S32 separator = legacy_name.find('.');
size_t separator = legacy_name.find('.');
if (separator != std::string::npos)
{
@@ -668,32 +674,18 @@ boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, ol
// <edit>
bool LLCacheName::getIfThere(const LLUUID& id, std::string& fullname, BOOL& is_group)
{
if(id.isNull())
if (id.notNull())
if (LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id))
{
fullname = "";
return false;
}
LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id );
if (entry)
{
if (entry->mIsGroup)
{
fullname = entry->mGroupName;
}
else
{
fullname = entry->mFirstName + " " + entry->mLastName;
}
is_group = entry->mIsGroup;
fullname = (is_group = entry->mIsGroup) ? entry->mGroupName : entry->mFirstName + " " + entry->mLastName;
return true;
}
fullname = "";
return false;
}
// </edit>
void LLCacheName::processPending()
{
const F32 SECS_BETWEEN_PROCESS = 0.1f;
@@ -705,7 +697,7 @@ void LLCacheName::processPending()
if(!impl.mUpstreamHost.isOk())
{
lldebugs << "LLCacheName::processPending() - bad upstream host."
<< llendl;
<< LL_ENDL;
return;
}
@@ -756,7 +748,7 @@ void LLCacheName::dump()
<< iter->first << " = (group) "
<< entry->mGroupName
<< " @ " << entry->mCreateTime
<< llendl;
<< LL_ENDL;
}
else
{
@@ -764,7 +756,7 @@ void LLCacheName::dump()
<< iter->first << " = "
<< buildFullName(entry->mFirstName, entry->mLastName)
<< " @ " << entry->mCreateTime
<< llendl;
<< LL_ENDL;
}
}
}
@@ -778,7 +770,7 @@ void LLCacheName::dumpStats()
<< " Pending=" << impl.mPendingQueue.size()
<< " Reply=" << impl.mReplyQueue.size()
// << " Observers=" << impl.mSignal.size()
<< llendl;
<< LL_ENDL;
}
void LLCacheName::clear()
@@ -935,7 +927,7 @@ void LLCacheName::Impl::processUUIDRequest(LLMessageSystem* msg, bool isGroup)
<< (isGroup ? "group" : "user") << " name, "
<< "but found "
<< (entry->mIsGroup ? "group" : "user")
<< ": " << id << llendl;
<< ": " << id << LL_ENDL;
}
else
{

View File

@@ -40,7 +40,7 @@ typedef boost::signals2::signal<void (const LLUUID& id,
bool is_group)> LLCacheNameSignal;
typedef LLCacheNameSignal::slot_type LLCacheNameCallback;
// Old callback with user data for compatability
// Old callback with user data for compatibility
typedef void (*old_callback_t)(const LLUUID&, const std::string&, bool, void*);
// Here's the theory:
@@ -107,7 +107,7 @@ public:
// otherwise, will request the data, and will call the callback when
// available. There is no garuntee the callback will ever be called.
boost::signals2::connection get(const LLUUID& id, bool is_group, const LLCacheNameCallback& callback);
//<edit>
bool getIfThere(const LLUUID& id, std::string& fullname, BOOL& is_group);
//</edit>

View File

@@ -722,6 +722,11 @@ void LLHTTPClient::put(std::string const& url, LLSD const& body, ResponderPtr re
request(url, HTTP_PUT, new LLSDInjector(body), responder, headers, NULL/*,*/ DEBUG_CURLIO_PARAM(debug), no_keep_alive, no_does_authentication, no_allow_compressed_reply);
}
void LLHTTPClient::putRaw(const std::string& url, const char* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
{
request(url, HTTP_PUT, new RawInjector(data, size), responder, headers, NULL/*,*/ DEBUG_CURLIO_PARAM(debug), no_keep_alive, no_does_authentication, no_allow_compressed_reply);
}
void LLHTTPClient::post(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive, AIStateMachine* parent, AIStateMachine::state_type new_parent_state)
{
request(url, HTTP_POST, new LLSDInjector(body), responder, headers, NULL/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, no_does_authentication, allow_compressed_reply, parent, new_parent_state);

View File

@@ -491,6 +491,10 @@ public:
static void put(std::string const& url, LLSD const& body, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
{ AIHTTPHeaders headers; put(url, body, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
static void putRaw(const std::string& url, const char* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
static void putRaw(const std::string& url, const char* data, S32 size, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
{ AIHTTPHeaders headers; putRaw(url, data, size, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
static void getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
static void getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
{ AIHTTPHeaders headers; getHeaderOnly(url, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }