Merge LL V3.7.9 (AIS3 + SSA)
commit
f4bfb1aadf
1
.hgtags
1
.hgtags
|
|
@ -519,3 +519,4 @@ fc066b82343fca51f9c1b8eda0abc6bee9bb4503 3.7.5-release
|
|||
d029faf69f20a23007f32420a1ac6a3b89a6d441 3.7.6-release
|
||||
83959480cb986522d07b151a0c778ab7f920d41b 3.7.7-release
|
||||
bba9b3722eea08949e4ff69591f736bf0f808434 3.7.8-release
|
||||
a9f2d0cb11f73b06858e6083bb50083becc3f9cd 3.7.9-release
|
||||
|
|
|
|||
|
|
@ -1024,7 +1024,7 @@
|
|||
<key>hash</key>
|
||||
<string>52257e5eb166a0b69c9c0c38f6e1920e</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273079/arch/Linux/installer/google_breakpad-0.0.0-rev1099-linux-20130329.tar.bz2</string>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273079/arch/Linux/installer/google_breakpad-0.0.0-rev1099-linux-20130329.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>linux</string>
|
||||
|
|
@ -1094,9 +1094,9 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>d2542614df9dd99cbb5ff67e76d4a6c1</string>
|
||||
<string>98994d5b0b4b3d43be22aa6a5c36e6fa</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-mock/rev/274899/arch/CYGWIN/installer/gmock-1.6.0-windows-20130426.tar.bz2</string>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-mock-graham/rev/272961/arch/CYGWIN/installer/gmock-1.6.0-windows-20130327.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
|
|
@ -1742,9 +1742,9 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>b6d29de20de5c8f31925697b30e8f727</string>
|
||||
<string>54e46715e72b7805d9d3f84d45b6b1b7</string>
|
||||
<key>url</key>
|
||||
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/llappearanceutility-source/rev/283723/arch/Linux/installer/llappearanceutility_source-0.1-linux-20131109.tar.bz2</string>
|
||||
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/llappearanceutility-source/rev/290120/arch/Linux/installer/llappearanceutility_source-0.1-linux-20140519.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>linux</string>
|
||||
|
|
|
|||
|
|
@ -49,6 +49,11 @@ if (NOT DEFINED VIEWER_SHORT_VERSION) # will be true in indra/, false in indra/n
|
|||
message(SEND_ERROR "Cannot get viewer version from '${VIEWER_VERSION_BASE_FILE}'")
|
||||
endif ( EXISTS ${VIEWER_VERSION_BASE_FILE} )
|
||||
|
||||
if ("${VIEWER_VERSION_REVISION}" STREQUAL "")
|
||||
message("Ultimate fallback, revision was blank or not set: will use 0")
|
||||
set(VIEWER_VERSION_REVISION 0)
|
||||
endif ("${VIEWER_VERSION_REVISION}" STREQUAL "")
|
||||
|
||||
set(VIEWER_CHANNEL_VERSION_DEFINES
|
||||
"LL_VIEWER_CHANNEL=\"${VIEWER_CHANNEL}\""
|
||||
"LL_VIEWER_VERSION_MAJOR=${VIEWER_VERSION_MAJOR}"
|
||||
|
|
|
|||
|
|
@ -1,7 +1 @@
|
|||
Wed Nov 7 00:25:19 UTC 2012
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
2014-02-25 10:34
|
||||
|
|
|
|||
|
|
@ -510,33 +510,9 @@ void LLAvatarAppearance::computeBodySize()
|
|||
|
||||
mAvatarOffset.mV[VX] = 0.0f;
|
||||
mAvatarOffset.mV[VY] = 0.0f;
|
||||
|
||||
// Certain configurations of avatars can force the overall height (with offset) to go negative.
|
||||
// Enforce a constraint to make sure we don't go below 0.1 meters.
|
||||
// Camera positioning and other things start to break down when your avatar is "walking" while being fully underground
|
||||
// [FS:CR] This is a bad check and will force your head in the ground if the following is true.
|
||||
#if 0
|
||||
if (new_body_size.mV[VZ] + mAvatarOffset.mV[VZ] < 0.1f)
|
||||
{
|
||||
mAvatarOffset.mV[VZ] = -(new_body_size.mV[VZ] - 0.11f); // avoid floating point rounding making the above check continue to fail.
|
||||
|
||||
llassert(new_body_size.mV[VZ] + mAvatarOffset.mV[VZ] >= 0.1f);
|
||||
|
||||
if (mWearableData && isSelf())
|
||||
{
|
||||
LLWearable* shape = mWearableData->getWearable(LLWearableType::WT_SHAPE, 0);
|
||||
if (shape)
|
||||
{
|
||||
shape->setVisualParamWeight(AVATAR_HOVER, mAvatarOffset.mV[VZ], false);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // [/FS:CR]
|
||||
|
||||
if (new_body_size != mBodySize || old_offset != mAvatarOffset.mV[VZ])
|
||||
{
|
||||
mBodySize = new_body_size;
|
||||
bodySizeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1413,14 +1389,14 @@ BOOL LLAvatarAppearance::teToColorParams( ETextureIndex te, U32 *param_name )
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
void LLAvatarAppearance::setClothesColor( ETextureIndex te, const LLColor4& new_color, BOOL upload_bake )
|
||||
void LLAvatarAppearance::setClothesColor( ETextureIndex te, const LLColor4& new_color)
|
||||
{
|
||||
U32 param_name[3];
|
||||
if( teToColorParams( te, param_name ) )
|
||||
{
|
||||
setVisualParamWeight( param_name[0], new_color.mV[VX], upload_bake );
|
||||
setVisualParamWeight( param_name[1], new_color.mV[VY], upload_bake );
|
||||
setVisualParamWeight( param_name[2], new_color.mV[VZ], upload_bake );
|
||||
setVisualParamWeight( param_name[0], new_color.mV[VX]);
|
||||
setVisualParamWeight( param_name[1], new_color.mV[VY]);
|
||||
setVisualParamWeight( param_name[2], new_color.mV[VZ]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -107,7 +107,6 @@ public:
|
|||
public:
|
||||
virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent
|
||||
virtual BOOL isValid() const;
|
||||
virtual BOOL isUsingServerBakes() const = 0;
|
||||
virtual BOOL isUsingLocalAppearance() const = 0;
|
||||
virtual BOOL isEditingAppearance() const = 0;
|
||||
|
||||
|
|
@ -141,14 +140,13 @@ public:
|
|||
|
||||
joint_map_t mJointMap;
|
||||
|
||||
void computeBodySize();
|
||||
void computeBodySize();
|
||||
|
||||
|
||||
protected:
|
||||
static BOOL parseSkeletonFile(const std::string& filename);
|
||||
virtual void buildCharacter();
|
||||
virtual BOOL loadAvatar();
|
||||
virtual void bodySizeChanged() = 0;
|
||||
// [RLVa:KB] - Checked: 2013-03-03 (RLVa-1.4.8)
|
||||
virtual F32 getAvatarOffset() /*const*/;
|
||||
// [/RLVa:KB]
|
||||
|
|
@ -232,7 +230,7 @@ public:
|
|||
// Composites
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
virtual void invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result) = 0;
|
||||
virtual void invalidateComposite(LLTexLayerSet* layerset) = 0;
|
||||
|
||||
/********************************************************************************
|
||||
** **
|
||||
|
|
@ -263,7 +261,7 @@ protected:
|
|||
// Clothing colors (convenience functions to access visual parameters)
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
void setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color, BOOL upload_bake);
|
||||
void setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color);
|
||||
LLColor4 getClothesColor(LLAvatarAppearanceDefines::ETextureIndex te);
|
||||
static BOOL teToColorParams(LLAvatarAppearanceDefines::ETextureIndex te, U32 *param_name);
|
||||
|
||||
|
|
@ -272,7 +270,7 @@ public:
|
|||
//--------------------------------------------------------------------
|
||||
public:
|
||||
LLColor4 getGlobalColor(const std::string& color_name ) const;
|
||||
virtual void onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake) = 0;
|
||||
virtual void onGlobalColorChanged(const LLTexGlobalColor* global_color) = 0;
|
||||
protected:
|
||||
LLTexGlobalColor* mTexSkinColor;
|
||||
LLTexGlobalColor* mTexHairColor;
|
||||
|
|
|
|||
|
|
@ -152,19 +152,31 @@ void LLDriverParamInfo::toStream(std::ostream &out)
|
|||
// LLDriverParam
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
LLDriverParam::LLDriverParam(LLAvatarAppearance *appearance, LLWearable* wearable /* = NULL */) :
|
||||
LLDriverParam::LLDriverParam(LLAvatarAppearance *appearance, LLWearable* wearable /* = NULL */)
|
||||
: LLViewerVisualParam(),
|
||||
mDefaultVec(),
|
||||
mDriven(),
|
||||
mCurrentDistortionParam( NULL ),
|
||||
mAvatarAppearance(appearance),
|
||||
mWearablep(wearable)
|
||||
{
|
||||
llassert(mAvatarAppearance);
|
||||
if (mWearablep)
|
||||
{
|
||||
llassert(mAvatarAppearance->isSelf());
|
||||
}
|
||||
llassert((mWearablep == NULL) || mAvatarAppearance->isSelf());
|
||||
mDefaultVec.clear();
|
||||
}
|
||||
|
||||
LLDriverParam::LLDriverParam(const LLDriverParam& pOther)
|
||||
: LLViewerVisualParam(pOther),
|
||||
mDefaultVec(pOther.mDefaultVec),
|
||||
mDriven(pOther.mDriven),
|
||||
mCurrentDistortionParam(pOther.mCurrentDistortionParam),
|
||||
mAvatarAppearance(pOther.mAvatarAppearance),
|
||||
mWearablep(pOther.mWearablep)
|
||||
{
|
||||
llassert(mAvatarAppearance);
|
||||
llassert((mWearablep == NULL) || mAvatarAppearance->isSelf());
|
||||
}
|
||||
|
||||
LLDriverParam::~LLDriverParam()
|
||||
{
|
||||
}
|
||||
|
|
@ -178,7 +190,7 @@ BOOL LLDriverParam::setInfo(LLDriverParamInfo *info)
|
|||
mID = info->mID;
|
||||
info->mDriverParam = this;
|
||||
|
||||
setWeight(getDefaultWeight(), FALSE );
|
||||
setWeight(getDefaultWeight());
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -186,16 +198,10 @@ BOOL LLDriverParam::setInfo(LLDriverParamInfo *info)
|
|||
/*virtual*/ LLViewerVisualParam* LLDriverParam::cloneParam(LLWearable* wearable) const
|
||||
{
|
||||
llassert(wearable);
|
||||
LLDriverParam *new_param = new LLDriverParam(mAvatarAppearance, wearable);
|
||||
// FIXME DRANO this clobbers mWearablep, which means any code
|
||||
// currently using mWearablep is wrong, or at least untested.
|
||||
*new_param = *this;
|
||||
//new_param->mWearablep = wearable;
|
||||
// new_param->mDriven.clear(); // clear driven list to avoid overwriting avatar driven params from wearables.
|
||||
return new_param;
|
||||
return new LLDriverParam(*this);
|
||||
}
|
||||
|
||||
void LLDriverParam::setWeight(F32 weight, BOOL upload_bake)
|
||||
void LLDriverParam::setWeight(F32 weight)
|
||||
{
|
||||
F32 min_weight = getMinWeight();
|
||||
F32 max_weight = getMaxWeight();
|
||||
|
|
@ -254,7 +260,7 @@ void LLDriverParam::setWeight(F32 weight, BOOL upload_bake)
|
|||
driven_weight = driven_min;
|
||||
}
|
||||
|
||||
setDrivenWeight(driven,driven_weight,upload_bake);
|
||||
setDrivenWeight(driven,driven_weight);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
|
@ -278,13 +284,13 @@ void LLDriverParam::setWeight(F32 weight, BOOL upload_bake)
|
|||
driven_weight = driven_min;
|
||||
}
|
||||
|
||||
setDrivenWeight(driven,driven_weight,upload_bake);
|
||||
setDrivenWeight(driven,driven_weight);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
driven_weight = getDrivenWeight(driven, mCurWeight);
|
||||
setDrivenWeight(driven,driven_weight,upload_bake);
|
||||
setDrivenWeight(driven,driven_weight);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -430,9 +436,9 @@ const LLViewerVisualParam* LLDriverParam::getDrivenParam(S32 index) const
|
|||
//-----------------------------------------------------------------------------
|
||||
// setAnimationTarget()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLDriverParam::setAnimationTarget( F32 target_value, BOOL upload_bake )
|
||||
void LLDriverParam::setAnimationTarget( F32 target_value)
|
||||
{
|
||||
LLVisualParam::setAnimationTarget(target_value, upload_bake);
|
||||
LLVisualParam::setAnimationTarget(target_value);
|
||||
|
||||
for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
|
||||
{
|
||||
|
|
@ -441,16 +447,16 @@ void LLDriverParam::setAnimationTarget( F32 target_value, BOOL upload_bake )
|
|||
|
||||
// this isn't normally necessary, as driver params handle interpolation of their driven params
|
||||
// but texture params need to know to assume their final value at beginning of interpolation
|
||||
driven->mParam->setAnimationTarget(driven_weight, upload_bake);
|
||||
driven->mParam->setAnimationTarget(driven_weight);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// stopAnimating()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLDriverParam::stopAnimating(BOOL upload_bake)
|
||||
void LLDriverParam::stopAnimating()
|
||||
{
|
||||
LLVisualParam::stopAnimating(upload_bake);
|
||||
LLVisualParam::stopAnimating();
|
||||
|
||||
for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
|
||||
{
|
||||
|
|
@ -530,7 +536,7 @@ void LLDriverParam::updateCrossDrivenParams(LLWearableType::EType driven_type)
|
|||
LLWearable *wearable = mAvatarAppearance->getWearableData()->getTopWearable(driver_type);
|
||||
if (wearable)
|
||||
{
|
||||
wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID), false);
|
||||
wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -593,7 +599,7 @@ F32 LLDriverParam::getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight
|
|||
return driven_weight;
|
||||
}
|
||||
|
||||
void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake)
|
||||
void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight)
|
||||
{
|
||||
bool use_self = false;
|
||||
if(mWearablep &&
|
||||
|
|
@ -610,10 +616,10 @@ void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bo
|
|||
if (use_self)
|
||||
{
|
||||
// call setWeight through LLVOAvatarSelf so other wearables can be updated with the correct values
|
||||
mAvatarAppearance->setVisualParamWeight( (LLVisualParam*)driven->mParam, driven_weight, upload_bake );
|
||||
mAvatarAppearance->setVisualParamWeight( (LLVisualParam*)driven->mParam, driven_weight);
|
||||
}
|
||||
else
|
||||
{
|
||||
driven->mParam->setWeight( driven_weight, upload_bake );
|
||||
driven->mParam->setWeight( driven_weight);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,9 +111,9 @@ public:
|
|||
|
||||
// LLVisualParam Virtual functions
|
||||
/*virtual*/ void apply( ESex sex ) {} // apply is called separately for each driven param.
|
||||
/*virtual*/ void setWeight(F32 weight, BOOL upload_bake);
|
||||
/*virtual*/ void setAnimationTarget( F32 target_value, BOOL upload_bake );
|
||||
/*virtual*/ void stopAnimating(BOOL upload_bake);
|
||||
/*virtual*/ void setWeight(F32 weight);
|
||||
/*virtual*/ void setAnimationTarget( F32 target_value);
|
||||
/*virtual*/ void stopAnimating();
|
||||
/*virtual*/ BOOL linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params);
|
||||
/*virtual*/ void resetDrivenParams();
|
||||
|
||||
|
|
@ -129,8 +129,9 @@ public:
|
|||
const LLViewerVisualParam* getDrivenParam(S32 index) const;
|
||||
|
||||
protected:
|
||||
LLDriverParam(const LLDriverParam& pOther);
|
||||
F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight);
|
||||
void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake);
|
||||
void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight);
|
||||
|
||||
|
||||
LL_ALIGN_16(LLVector4a mDefaultVec); // temp holder
|
||||
|
|
|
|||
|
|
@ -315,10 +315,27 @@ BOOL LLPolyMorphTargetInfo::parseXml(LLXmlTreeNode* node)
|
|||
// LLPolyMorphTarget()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLPolyMorphTarget::LLPolyMorphTarget(LLPolyMesh *poly_mesh)
|
||||
: mMorphData(NULL), mMesh(poly_mesh),
|
||||
mVertMask(NULL),
|
||||
mLastSex(SEX_FEMALE),
|
||||
mNumMorphMasksPending(0)
|
||||
: LLViewerVisualParam(),
|
||||
mMorphData(NULL),
|
||||
mMesh(poly_mesh),
|
||||
mVertMask(NULL),
|
||||
mLastSex(SEX_FEMALE),
|
||||
mNumMorphMasksPending(0),
|
||||
mVolumeMorphs()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLPolyMorphTarget()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLPolyMorphTarget::LLPolyMorphTarget(const LLPolyMorphTarget& pOther)
|
||||
: LLViewerVisualParam(pOther),
|
||||
mMorphData(pOther.mMorphData),
|
||||
mMesh(pOther.mMesh),
|
||||
mVertMask(pOther.mVertMask == NULL ? NULL : new LLPolyVertexMask(*pOther.mVertMask)),
|
||||
mLastSex(pOther.mLastSex),
|
||||
mNumMorphMasksPending(pOther.mNumMorphMasksPending),
|
||||
mVolumeMorphs(pOther.mVolumeMorphs)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -327,10 +344,8 @@ LLPolyMorphTarget::LLPolyMorphTarget(LLPolyMesh *poly_mesh)
|
|||
//-----------------------------------------------------------------------------
|
||||
LLPolyMorphTarget::~LLPolyMorphTarget()
|
||||
{
|
||||
if (mVertMask)
|
||||
{
|
||||
delete mVertMask;
|
||||
}
|
||||
delete mVertMask;
|
||||
mVertMask = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -343,7 +358,7 @@ BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info)
|
|||
return FALSE;
|
||||
mInfo = info;
|
||||
mID = info->mID;
|
||||
setWeight(getDefaultWeight(), FALSE );
|
||||
setWeight(getDefaultWeight());
|
||||
|
||||
LLAvatarAppearance* avatarp = mMesh->getAvatar();
|
||||
LLPolyMorphTargetInfo::volume_info_list_t::iterator iter;
|
||||
|
|
@ -385,9 +400,7 @@ BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info)
|
|||
|
||||
/*virtual*/ LLViewerVisualParam* LLPolyMorphTarget::cloneParam(LLWearable* wearable) const
|
||||
{
|
||||
LLPolyMorphTarget *new_param = new LLPolyMorphTarget(mMesh);
|
||||
*new_param = *this;
|
||||
return new_param;
|
||||
return new LLPolyMorphTarget(*this);
|
||||
}
|
||||
|
||||
#if 0 // obsolete
|
||||
|
|
@ -722,10 +735,25 @@ void LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S3
|
|||
// LLPolyVertexMask()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLPolyVertexMask::LLPolyVertexMask(LLPolyMorphData* morph_data)
|
||||
: mWeights(new F32[morph_data->mNumIndices]),
|
||||
mMorphData(morph_data),
|
||||
mWeightsGenerated(FALSE)
|
||||
{
|
||||
mWeights = new F32[morph_data->mNumIndices];
|
||||
mMorphData = morph_data;
|
||||
mWeightsGenerated = FALSE;
|
||||
llassert(mMorphData != NULL);
|
||||
llassert(mMorphData->mNumIndices > 0);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLPolyVertexMask()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLPolyVertexMask::LLPolyVertexMask(const LLPolyVertexMask& pOther)
|
||||
: mWeights(new F32[pOther.mMorphData->mNumIndices]),
|
||||
mMorphData(pOther.mMorphData),
|
||||
mWeightsGenerated(pOther.mWeightsGenerated)
|
||||
{
|
||||
llassert(mMorphData != NULL);
|
||||
llassert(mMorphData->mNumIndices > 0);
|
||||
memcpy(mWeights, pOther.mWeights, sizeof(F32) * mMorphData->mNumIndices);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -733,7 +761,8 @@ LLPolyVertexMask::LLPolyVertexMask(LLPolyMorphData* morph_data)
|
|||
//-----------------------------------------------------------------------------
|
||||
LLPolyVertexMask::~LLPolyVertexMask()
|
||||
{
|
||||
delete[] mWeights;
|
||||
delete [] mWeights;
|
||||
mWeights = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ class LLPolyVertexMask
|
|||
{
|
||||
public:
|
||||
LLPolyVertexMask(LLPolyMorphData* morph_data);
|
||||
LLPolyVertexMask(const LLPolyVertexMask& pOther);
|
||||
~LLPolyVertexMask();
|
||||
|
||||
void generateMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4a *clothing_weights);
|
||||
|
|
@ -182,6 +183,8 @@ public:
|
|||
void addPendingMorphMask() { mNumMorphMasksPending++; }
|
||||
|
||||
protected:
|
||||
LLPolyMorphTarget(const LLPolyMorphTarget& pOther);
|
||||
|
||||
LLPolyMorphData* mMorphData;
|
||||
LLPolyMesh* mMesh;
|
||||
LLPolyVertexMask * mVertMask;
|
||||
|
|
|
|||
|
|
@ -104,9 +104,25 @@ BOOL LLPolySkeletalDistortionInfo::parseXml(LLXmlTreeNode* node)
|
|||
// LLPolySkeletalDistortion()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLPolySkeletalDistortion::LLPolySkeletalDistortion(LLAvatarAppearance *avatarp)
|
||||
: LLViewerVisualParam(),
|
||||
mDefaultVec(),
|
||||
mJointScales(),
|
||||
mJointOffsets(),
|
||||
mAvatar(avatarp)
|
||||
{
|
||||
mDefaultVec.splat(0.001f);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLPolySkeletalDistortion()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLPolySkeletalDistortion::LLPolySkeletalDistortion(const LLPolySkeletalDistortion &pOther)
|
||||
: LLViewerVisualParam(pOther),
|
||||
mDefaultVec(pOther.mDefaultVec),
|
||||
mJointScales(pOther.mJointScales),
|
||||
mJointOffsets(pOther.mJointOffsets),
|
||||
mAvatar(pOther.mAvatar)
|
||||
{
|
||||
mAvatar = avatarp;
|
||||
mDefaultVec.splat(0.001f);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -123,7 +139,7 @@ BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)
|
|||
return FALSE;
|
||||
mInfo = info;
|
||||
mID = info->mID;
|
||||
setWeight(getDefaultWeight(), FALSE );
|
||||
setWeight(getDefaultWeight());
|
||||
|
||||
LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter;
|
||||
for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); iter++)
|
||||
|
|
@ -171,9 +187,7 @@ BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)
|
|||
|
||||
/*virtual*/ LLViewerVisualParam* LLPolySkeletalDistortion::cloneParam(LLWearable* wearable) const
|
||||
{
|
||||
LLPolySkeletalDistortion *new_param = new LLPolySkeletalDistortion(mAvatar);
|
||||
*new_param = *this;
|
||||
return new_param;
|
||||
return new LLPolySkeletalDistortion(*this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -185,7 +199,7 @@ void LLPolySkeletalDistortion::apply( ESex avatar_sex )
|
|||
{
|
||||
LL_RECORD_BLOCK_TIME(FTM_POLYSKELETAL_DISTORTION_APPLY);
|
||||
|
||||
F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight();
|
||||
F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight();
|
||||
|
||||
LLJoint* joint;
|
||||
joint_vec_map_t::iterator iter;
|
||||
|
|
@ -197,8 +211,10 @@ void LLPolySkeletalDistortion::apply( ESex avatar_sex )
|
|||
joint = iter->first;
|
||||
LLVector3 newScale = joint->getScale();
|
||||
LLVector3 scaleDelta = iter->second;
|
||||
newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta);
|
||||
joint->setScale(newScale);
|
||||
newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta);
|
||||
//An aspect of attached mesh objects (which contain joint offsets) that need to be cleaned up when detached
|
||||
joint->storeScaleForReset( newScale );
|
||||
joint->setScale(newScale);
|
||||
}
|
||||
|
||||
for (iter = mJointOffsets.begin();
|
||||
|
|
@ -207,8 +223,8 @@ void LLPolySkeletalDistortion::apply( ESex avatar_sex )
|
|||
{
|
||||
joint = iter->first;
|
||||
LLVector3 newPosition = joint->getPosition();
|
||||
LLVector3 positionDelta = iter->second;
|
||||
newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta);
|
||||
LLVector3 positionDelta = iter->second;
|
||||
newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta);
|
||||
joint->setPosition(newPosition);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -118,6 +118,8 @@ public:
|
|||
/*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return NULL;};
|
||||
|
||||
protected:
|
||||
LLPolySkeletalDistortion(const LLPolySkeletalDistortion& pOther);
|
||||
|
||||
LL_ALIGN_16(LLVector4a mDefaultVec);
|
||||
typedef std::map<LLJoint*, LLVector3> joint_vec_map_t;
|
||||
joint_vec_map_t mJointScales;
|
||||
|
|
|
|||
|
|
@ -90,22 +90,36 @@ const std::string& LLTexGlobalColor::getName() const
|
|||
//-----------------------------------------------------------------------------
|
||||
// LLTexParamGlobalColor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLTexParamGlobalColor::LLTexParamGlobalColor(LLTexGlobalColor* tex_global_color) :
|
||||
LLTexLayerParamColor(tex_global_color->getAvatarAppearance()),
|
||||
LLTexParamGlobalColor::LLTexParamGlobalColor(LLTexGlobalColor* tex_global_color)
|
||||
: LLTexLayerParamColor(tex_global_color->getAvatarAppearance()),
|
||||
mTexGlobalColor(tex_global_color)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLTexParamGlobalColor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLTexParamGlobalColor::LLTexParamGlobalColor(const LLTexParamGlobalColor& pOther)
|
||||
: LLTexLayerParamColor(pOther),
|
||||
mTexGlobalColor(pOther.mTexGlobalColor)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ~LLTexParamGlobalColor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLTexParamGlobalColor::~LLTexParamGlobalColor()
|
||||
{
|
||||
}
|
||||
|
||||
/*virtual*/ LLViewerVisualParam* LLTexParamGlobalColor::cloneParam(LLWearable* wearable) const
|
||||
{
|
||||
LLTexParamGlobalColor *new_param = new LLTexParamGlobalColor(mTexGlobalColor);
|
||||
*new_param = *this;
|
||||
return new_param;
|
||||
return new LLTexParamGlobalColor(*this);
|
||||
}
|
||||
|
||||
void LLTexParamGlobalColor::onGlobalColorChanged(bool upload_bake)
|
||||
void LLTexParamGlobalColor::onGlobalColorChanged()
|
||||
{
|
||||
mAvatarAppearance->onGlobalColorChanged(mTexGlobalColor, upload_bake);
|
||||
mAvatarAppearance->onGlobalColorChanged(mTexGlobalColor);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -73,9 +73,11 @@ class LLTexParamGlobalColor : public LLTexLayerParamColor
|
|||
{
|
||||
public:
|
||||
LLTexParamGlobalColor(LLTexGlobalColor *tex_color);
|
||||
virtual ~LLTexParamGlobalColor();
|
||||
/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
|
||||
protected:
|
||||
/*virtual*/ void onGlobalColorChanged(bool upload_bake);
|
||||
LLTexParamGlobalColor(const LLTexParamGlobalColor& pOther);
|
||||
/*virtual*/ void onGlobalColorChanged();
|
||||
private:
|
||||
LLTexGlobalColor* mTexGlobalColor;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1560,10 +1560,13 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
|
|||
}
|
||||
|
||||
U32 cache_index = alpha_mask_crc.getCRC();
|
||||
U8* alpha_data = get_if_there(mAlphaCache,cache_index,(U8*)NULL);
|
||||
if (!alpha_data)
|
||||
U8* alpha_data = NULL;
|
||||
// We believe we need to generate morph masks, do not assume that the cached version is accurate.
|
||||
// We can get bad morph masks during login, on minimize, and occasional gl errors.
|
||||
// We should only be doing this when we believe something has changed with respect to the user's appearance.
|
||||
{
|
||||
// clear out a slot if we have filled our cache
|
||||
LL_DEBUGS("Avatar") << "gl alpha cache of morph mask not found, doing readback: " << getName() << LL_ENDL;
|
||||
// clear out a slot if we have filled our cache
|
||||
S32 max_cache_entries = getTexLayerSet()->getAvatarAppearance()->isSelf() ? 4 : 1;
|
||||
while ((S32)mAlphaCache.size() >= max_cache_entries)
|
||||
{
|
||||
|
|
@ -1783,13 +1786,11 @@ LLTexLayer* LLTexLayerTemplate::getLayer(U32 i) const
|
|||
/*virtual*/ void LLTexLayerTemplate::gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height)
|
||||
{
|
||||
U32 num_wearables = updateWearableCache();
|
||||
for (U32 i = 0; i < num_wearables; i++)
|
||||
U32 i = num_wearables - 1; // For rendering morph masks, we only want to use the top wearable
|
||||
LLTexLayer *layer = getLayer(i);
|
||||
if (layer)
|
||||
{
|
||||
LLTexLayer *layer = getLayer(i);
|
||||
if (layer)
|
||||
{
|
||||
layer->addAlphaMask(data, originX, originY, width, height);
|
||||
}
|
||||
layer->addAlphaMask(data, originX, originY, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// LLTexLayerParam
|
||||
//-----------------------------------------------------------------------------
|
||||
LLTexLayerParam::LLTexLayerParam(LLTexLayerInterface *layer) :
|
||||
LLTexLayerParam::LLTexLayerParam(LLTexLayerInterface *layer)
|
||||
: LLViewerVisualParam(),
|
||||
mTexLayer(layer),
|
||||
mAvatarAppearance(NULL)
|
||||
{
|
||||
|
|
@ -54,12 +55,19 @@ LLTexLayerParam::LLTexLayerParam(LLTexLayerInterface *layer) :
|
|||
}
|
||||
}
|
||||
|
||||
LLTexLayerParam::LLTexLayerParam(LLAvatarAppearance *appearance) :
|
||||
LLTexLayerParam::LLTexLayerParam(LLAvatarAppearance *appearance)
|
||||
: LLViewerVisualParam(),
|
||||
mTexLayer(NULL),
|
||||
mAvatarAppearance(appearance)
|
||||
{
|
||||
}
|
||||
|
||||
LLTexLayerParam::LLTexLayerParam(const LLTexLayerParam& pOther)
|
||||
: LLViewerVisualParam(pOther),
|
||||
mTexLayer(pOther.mTexLayer),
|
||||
mAvatarAppearance(pOther.mAvatarAppearance)
|
||||
{
|
||||
}
|
||||
|
||||
BOOL LLTexLayerParam::setInfo(LLViewerVisualParamInfo *info, BOOL add_to_appearance)
|
||||
{
|
||||
|
|
@ -112,9 +120,11 @@ void LLTexLayerParamAlpha::getCacheByteCount(S32* gl_bytes)
|
|||
}
|
||||
}
|
||||
|
||||
LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLTexLayerInterface* layer) :
|
||||
LLTexLayerParam(layer),
|
||||
LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLTexLayerInterface* layer)
|
||||
: LLTexLayerParam(layer),
|
||||
mCachedProcessedTexture(NULL),
|
||||
mStaticImageTGA(),
|
||||
mStaticImageRaw(),
|
||||
mNeedsCreateTexture(FALSE),
|
||||
mStaticImageInvalid(FALSE),
|
||||
mAvgDistortionVec(1.f, 1.f, 1.f),
|
||||
|
|
@ -123,9 +133,11 @@ LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLTexLayerInterface* layer) :
|
|||
sInstances.push_front(this);
|
||||
}
|
||||
|
||||
LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLAvatarAppearance* appearance) :
|
||||
LLTexLayerParam(appearance),
|
||||
LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLAvatarAppearance* appearance)
|
||||
: LLTexLayerParam(appearance),
|
||||
mCachedProcessedTexture(NULL),
|
||||
mStaticImageTGA(),
|
||||
mStaticImageRaw(),
|
||||
mNeedsCreateTexture(FALSE),
|
||||
mStaticImageInvalid(FALSE),
|
||||
mAvgDistortionVec(1.f, 1.f, 1.f),
|
||||
|
|
@ -134,6 +146,18 @@ LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLAvatarAppearance* appearance) :
|
|||
sInstances.push_front(this);
|
||||
}
|
||||
|
||||
LLTexLayerParamAlpha::LLTexLayerParamAlpha(const LLTexLayerParamAlpha& pOther)
|
||||
: LLTexLayerParam(pOther),
|
||||
mCachedProcessedTexture(pOther.mCachedProcessedTexture),
|
||||
mStaticImageTGA(pOther.mStaticImageTGA),
|
||||
mStaticImageRaw(pOther.mStaticImageRaw),
|
||||
mNeedsCreateTexture(pOther.mNeedsCreateTexture),
|
||||
mStaticImageInvalid(pOther.mStaticImageInvalid),
|
||||
mAvgDistortionVec(pOther.mAvgDistortionVec),
|
||||
mCachedEffectiveWeight(pOther.mCachedEffectiveWeight)
|
||||
{
|
||||
sInstances.push_front(this);
|
||||
}
|
||||
|
||||
LLTexLayerParamAlpha::~LLTexLayerParamAlpha()
|
||||
{
|
||||
|
|
@ -143,9 +167,7 @@ LLTexLayerParamAlpha::~LLTexLayerParamAlpha()
|
|||
|
||||
/*virtual*/ LLViewerVisualParam* LLTexLayerParamAlpha::cloneParam(LLWearable* wearable) const
|
||||
{
|
||||
LLTexLayerParamAlpha *new_param = new LLTexLayerParamAlpha(mTexLayer);
|
||||
*new_param = *this;
|
||||
return new_param;
|
||||
return new LLTexLayerParamAlpha(*this);
|
||||
}
|
||||
|
||||
void LLTexLayerParamAlpha::deleteCaches()
|
||||
|
|
@ -161,7 +183,7 @@ BOOL LLTexLayerParamAlpha::getMultiplyBlend() const
|
|||
return ((LLTexLayerParamAlphaInfo *)getInfo())->mMultiplyBlend;
|
||||
}
|
||||
|
||||
void LLTexLayerParamAlpha::setWeight(F32 weight, BOOL upload_bake)
|
||||
void LLTexLayerParamAlpha::setWeight(F32 weight)
|
||||
{
|
||||
if (mIsAnimating || mTexLayer == NULL)
|
||||
{
|
||||
|
|
@ -179,35 +201,35 @@ void LLTexLayerParamAlpha::setWeight(F32 weight, BOOL upload_bake)
|
|||
if ((mAvatarAppearance->getSex() & getSex()) &&
|
||||
(mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param.
|
||||
{
|
||||
mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet(), upload_bake);
|
||||
mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet());
|
||||
mTexLayer->invalidateMorphMasks();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value, BOOL upload_bake)
|
||||
void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value)
|
||||
{
|
||||
// do not animate dummy parameters
|
||||
if (mIsDummy)
|
||||
{
|
||||
setWeight(target_value, upload_bake);
|
||||
setWeight(target_value);
|
||||
return;
|
||||
}
|
||||
|
||||
mTargetWeight = target_value;
|
||||
setWeight(target_value, upload_bake);
|
||||
setWeight(target_value);
|
||||
mIsAnimating = TRUE;
|
||||
if (mNext)
|
||||
{
|
||||
mNext->setAnimationTarget(target_value, upload_bake);
|
||||
mNext->setAnimationTarget(target_value);
|
||||
}
|
||||
}
|
||||
|
||||
void LLTexLayerParamAlpha::animate(F32 delta, BOOL upload_bake)
|
||||
void LLTexLayerParamAlpha::animate(F32 delta)
|
||||
{
|
||||
if (mNext)
|
||||
{
|
||||
mNext->animate(delta, upload_bake);
|
||||
mNext->animate(delta);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -399,27 +421,31 @@ BOOL LLTexLayerParamAlphaInfo::parseXml(LLXmlTreeNode* node)
|
|||
|
||||
|
||||
|
||||
LLTexLayerParamColor::LLTexLayerParamColor(LLTexLayerInterface* layer) :
|
||||
LLTexLayerParam(layer),
|
||||
LLTexLayerParamColor::LLTexLayerParamColor(LLTexLayerInterface* layer)
|
||||
: LLTexLayerParam(layer),
|
||||
mAvgDistortionVec(1.f, 1.f, 1.f)
|
||||
{
|
||||
}
|
||||
|
||||
LLTexLayerParamColor::LLTexLayerParamColor(LLAvatarAppearance *appearance) :
|
||||
LLTexLayerParam(appearance),
|
||||
LLTexLayerParamColor::LLTexLayerParamColor(LLAvatarAppearance *appearance)
|
||||
: LLTexLayerParam(appearance),
|
||||
mAvgDistortionVec(1.f, 1.f, 1.f)
|
||||
{
|
||||
}
|
||||
|
||||
LLTexLayerParamColor::LLTexLayerParamColor(const LLTexLayerParamColor& pOther)
|
||||
: LLTexLayerParam(pOther),
|
||||
mAvgDistortionVec(pOther.mAvgDistortionVec)
|
||||
{
|
||||
}
|
||||
|
||||
LLTexLayerParamColor::~LLTexLayerParamColor()
|
||||
{
|
||||
}
|
||||
|
||||
/*virtual*/ LLViewerVisualParam* LLTexLayerParamColor::cloneParam(LLWearable* wearable) const
|
||||
{
|
||||
LLTexLayerParamColor *new_param = new LLTexLayerParamColor(mTexLayer);
|
||||
*new_param = *this;
|
||||
return new_param;
|
||||
return new LLTexLayerParamColor(*this);
|
||||
}
|
||||
|
||||
LLColor4 LLTexLayerParamColor::getNetColor() const
|
||||
|
|
@ -450,14 +476,14 @@ LLColor4 LLTexLayerParamColor::getNetColor() const
|
|||
}
|
||||
}
|
||||
|
||||
void LLTexLayerParamColor::setWeight(F32 weight, BOOL upload_bake)
|
||||
|
||||
void LLTexLayerParamColor::setWeight(F32 weight)
|
||||
{
|
||||
if (mIsAnimating)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo();
|
||||
F32 min_weight = getMinWeight();
|
||||
F32 max_weight = getMaxWeight();
|
||||
F32 new_weight = llclamp(weight, min_weight, max_weight);
|
||||
|
|
@ -467,6 +493,8 @@ void LLTexLayerParamColor::setWeight(F32 weight, BOOL upload_bake)
|
|||
{
|
||||
mCurWeight = new_weight;
|
||||
|
||||
const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo();
|
||||
|
||||
if (info->mNumColors <= 0)
|
||||
{
|
||||
// This will happen when we set the default weight the first time.
|
||||
|
|
@ -475,10 +503,10 @@ void LLTexLayerParamColor::setWeight(F32 weight, BOOL upload_bake)
|
|||
|
||||
if ((mAvatarAppearance->getSex() & getSex()) && (mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param.
|
||||
{
|
||||
onGlobalColorChanged(upload_bake);
|
||||
onGlobalColorChanged();
|
||||
if (mTexLayer)
|
||||
{
|
||||
mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet(), upload_bake);
|
||||
mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -486,23 +514,23 @@ void LLTexLayerParamColor::setWeight(F32 weight, BOOL upload_bake)
|
|||
}
|
||||
}
|
||||
|
||||
void LLTexLayerParamColor::setAnimationTarget(F32 target_value, BOOL upload_bake)
|
||||
void LLTexLayerParamColor::setAnimationTarget(F32 target_value)
|
||||
{
|
||||
// set value first then set interpolating flag to ignore further updates
|
||||
mTargetWeight = target_value;
|
||||
setWeight(target_value, upload_bake);
|
||||
setWeight(target_value);
|
||||
mIsAnimating = TRUE;
|
||||
if (mNext)
|
||||
{
|
||||
mNext->setAnimationTarget(target_value, upload_bake);
|
||||
mNext->setAnimationTarget(target_value);
|
||||
}
|
||||
}
|
||||
|
||||
void LLTexLayerParamColor::animate(F32 delta, BOOL upload_bake)
|
||||
void LLTexLayerParamColor::animate(F32 delta)
|
||||
{
|
||||
if (mNext)
|
||||
{
|
||||
mNext->animate(delta, upload_bake);
|
||||
mNext->animate(delta);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@ public:
|
|||
/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const = 0;
|
||||
|
||||
protected:
|
||||
LLTexLayerParam(const LLTexLayerParam& pOther);
|
||||
|
||||
LLTexLayerInterface* mTexLayer;
|
||||
LLAvatarAppearance* mAvatarAppearance;
|
||||
};
|
||||
|
|
@ -83,9 +85,9 @@ public:
|
|||
// LLVisualParam Virtual functions
|
||||
///*virtual*/ BOOL parseData(LLXmlTreeNode* node);
|
||||
/*virtual*/ void apply( ESex avatar_sex ) {}
|
||||
/*virtual*/ void setWeight(F32 weight, BOOL upload_bake);
|
||||
/*virtual*/ void setAnimationTarget(F32 target_value, BOOL upload_bake);
|
||||
/*virtual*/ void animate(F32 delta, BOOL upload_bake);
|
||||
/*virtual*/ void setWeight(F32 weight);
|
||||
/*virtual*/ void setAnimationTarget(F32 target_value);
|
||||
/*virtual*/ void animate(F32 delta);
|
||||
|
||||
// LLViewerVisualParam Virtual functions
|
||||
/*virtual*/ F32 getTotalDistortion() { return 1.f; }
|
||||
|
|
@ -102,6 +104,8 @@ public:
|
|||
BOOL getMultiplyBlend() const;
|
||||
|
||||
private:
|
||||
LLTexLayerParamAlpha(const LLTexLayerParamAlpha& pOther);
|
||||
|
||||
LLPointer<LLGLTexture> mCachedProcessedTexture;
|
||||
LLPointer<LLImageTGA> mStaticImageTGA;
|
||||
LLPointer<LLImageRaw> mStaticImageRaw;
|
||||
|
|
@ -174,9 +178,9 @@ public:
|
|||
// LLVisualParam Virtual functions
|
||||
///*virtual*/ BOOL parseData(LLXmlTreeNode* node);
|
||||
/*virtual*/ void apply( ESex avatar_sex ) {}
|
||||
/*virtual*/ void setWeight(F32 weight, BOOL upload_bake);
|
||||
/*virtual*/ void setAnimationTarget(F32 target_value, BOOL upload_bake);
|
||||
/*virtual*/ void animate(F32 delta, BOOL upload_bake);
|
||||
/*virtual*/ void setWeight(F32 weight);
|
||||
/*virtual*/ void setAnimationTarget(F32 target_value);
|
||||
/*virtual*/ void animate(F32 delta);
|
||||
|
||||
|
||||
// LLViewerVisualParam Virtual functions
|
||||
|
|
@ -190,7 +194,9 @@ public:
|
|||
// New functions
|
||||
LLColor4 getNetColor() const;
|
||||
protected:
|
||||
virtual void onGlobalColorChanged(bool upload_bake) {}
|
||||
LLTexLayerParamColor(const LLTexLayerParamColor& pOther);
|
||||
|
||||
virtual void onGlobalColorChanged() {}
|
||||
private:
|
||||
LL_ALIGN_16(LLVector4a mAvgDistortionVec);
|
||||
} LL_ALIGN_POSTFIX(16);
|
||||
|
|
|
|||
|
|
@ -123,6 +123,22 @@ BOOL LLViewerVisualParamInfo::parseXml(LLXmlTreeNode *node)
|
|||
// LLViewerVisualParam()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLViewerVisualParam::LLViewerVisualParam()
|
||||
: LLVisualParam()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLViewerVisualParam()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLViewerVisualParam::LLViewerVisualParam(const LLViewerVisualParam& pOther)
|
||||
: LLVisualParam(pOther)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ~LLViewerVisualParam()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLViewerVisualParam::~LLViewerVisualParam()
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -137,7 +153,7 @@ BOOL LLViewerVisualParam::setInfo(LLViewerVisualParamInfo *info)
|
|||
return FALSE;
|
||||
mInfo = info;
|
||||
mID = info->mID;
|
||||
setWeight(getDefaultWeight(), FALSE );
|
||||
setWeight(getDefaultWeight());
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ class LLViewerVisualParam : public LLVisualParam
|
|||
{
|
||||
public:
|
||||
LLViewerVisualParam();
|
||||
/*virtual*/ ~LLViewerVisualParam(){};
|
||||
virtual ~LLViewerVisualParam();
|
||||
|
||||
// Special: These functions are overridden by child classes
|
||||
LLViewerVisualParamInfo *getInfo() const { return (LLViewerVisualParamInfo*)mInfo; };
|
||||
|
|
@ -105,6 +105,8 @@ public:
|
|||
|
||||
BOOL getCrossWearable() const { return getInfo()->mCrossWearable; }
|
||||
|
||||
protected:
|
||||
LLViewerVisualParam(const LLViewerVisualParam& pOther);
|
||||
} LL_ALIGN_POSTFIX(16);
|
||||
|
||||
#endif // LL_LLViewerVisualParam_H
|
||||
|
|
|
|||
|
|
@ -43,9 +43,32 @@ S32 LLWearable::sCurrentDefinitionVersion = 1;
|
|||
// Private local functions
|
||||
static std::string terse_F32_to_string(F32 f);
|
||||
|
||||
LLWearable::LLWearable()
|
||||
: mDefinitionVersion(-1),
|
||||
mName(),
|
||||
mDescription(),
|
||||
mPermissions(),
|
||||
mSaleInfo(),
|
||||
mType(LLWearableType::WT_NONE),
|
||||
mSavedVisualParamMap(),
|
||||
mVisualParamIndexMap(),
|
||||
mTEMap(),
|
||||
mSavedTEMap()
|
||||
{
|
||||
}
|
||||
|
||||
// virtual
|
||||
LLWearable::~LLWearable()
|
||||
{
|
||||
for (visual_param_index_map_t::iterator vpIter = mVisualParamIndexMap.begin(); vpIter != mVisualParamIndexMap.end(); ++vpIter)
|
||||
{
|
||||
LLVisualParam* vp = vpIter->second;
|
||||
vp->clearNextParam();
|
||||
delete vp;
|
||||
vpIter->second = NULL;
|
||||
}
|
||||
|
||||
destroyTextures();
|
||||
}
|
||||
|
||||
const std::string& LLWearable::getTypeLabel() const
|
||||
|
|
@ -525,7 +548,7 @@ void LLWearable::revertValues()
|
|||
LLVisualParam *param = getVisualParam(id);
|
||||
if(param && !dynamic_cast<LLDriverParam*>(param) )
|
||||
{
|
||||
setVisualParamWeight(id, value, TRUE);
|
||||
setVisualParamWeight(id, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -537,7 +560,7 @@ void LLWearable::revertValues()
|
|||
LLVisualParam *param = getVisualParam(id);
|
||||
if(param && dynamic_cast<LLDriverParam*>(param) )
|
||||
{
|
||||
setVisualParamWeight(id, value, TRUE);
|
||||
setVisualParamWeight(id, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -620,17 +643,10 @@ void LLWearable::syncImages(te_map_t &src, te_map_t &dst)
|
|||
|
||||
void LLWearable::destroyTextures()
|
||||
{
|
||||
for( te_map_t::iterator iter = mTEMap.begin(); iter != mTEMap.end(); ++iter )
|
||||
{
|
||||
LLLocalTextureObject *lto = iter->second;
|
||||
delete lto;
|
||||
}
|
||||
std::for_each(mTEMap.begin(), mTEMap.end(), DeletePairedPointer());
|
||||
mTEMap.clear();
|
||||
for( te_map_t::iterator iter = mSavedTEMap.begin(); iter != mSavedTEMap.end(); ++iter )
|
||||
{
|
||||
LLLocalTextureObject *lto = iter->second;
|
||||
delete lto;
|
||||
}
|
||||
|
||||
std::for_each(mSavedTEMap.begin(), mSavedTEMap.end(), DeletePairedPointer());
|
||||
mSavedTEMap.clear();
|
||||
}
|
||||
|
||||
|
|
@ -647,12 +663,12 @@ void LLWearable::addVisualParam(LLVisualParam *param)
|
|||
}
|
||||
|
||||
|
||||
void LLWearable::setVisualParamWeight(S32 param_index, F32 value, BOOL upload_bake)
|
||||
void LLWearable::setVisualParamWeight(S32 param_index, F32 value)
|
||||
{
|
||||
if( is_in_map(mVisualParamIndexMap, param_index ) )
|
||||
{
|
||||
LLVisualParam *wearable_param = mVisualParamIndexMap[param_index];
|
||||
wearable_param->setWeight(value, upload_bake);
|
||||
wearable_param->setWeight(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -693,14 +709,14 @@ void LLWearable::getVisualParams(visual_param_vec_t &list)
|
|||
}
|
||||
}
|
||||
|
||||
void LLWearable::animateParams(F32 delta, BOOL upload_bake)
|
||||
void LLWearable::animateParams(F32 delta)
|
||||
{
|
||||
for(visual_param_index_map_t::iterator iter = mVisualParamIndexMap.begin();
|
||||
iter != mVisualParamIndexMap.end();
|
||||
++iter)
|
||||
{
|
||||
LLVisualParam *param = (LLVisualParam*) iter->second;
|
||||
param->animate(delta, upload_bake);
|
||||
param->animate(delta);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -718,14 +734,14 @@ LLColor4 LLWearable::getClothesColor(S32 te) const
|
|||
return color;
|
||||
}
|
||||
|
||||
void LLWearable::setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake )
|
||||
void LLWearable::setClothesColor( S32 te, const LLColor4& new_color)
|
||||
{
|
||||
U32 param_name[3];
|
||||
if( LLAvatarAppearance::teToColorParams( (LLAvatarAppearanceDefines::ETextureIndex)te, param_name ) )
|
||||
{
|
||||
for( U8 index = 0; index < 3; index++ )
|
||||
{
|
||||
setVisualParamWeight(param_name[index], new_color.mV[index], upload_bake);
|
||||
setVisualParamWeight(param_name[index], new_color.mV[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -744,7 +760,7 @@ void LLWearable::writeToAvatar(LLAvatarAppearance* avatarp)
|
|||
S32 param_id = param->getID();
|
||||
F32 weight = getVisualParamWeight(param_id);
|
||||
|
||||
avatarp->setVisualParamWeight( param_id, weight, FALSE );
|
||||
avatarp->setVisualParamWeight( param_id, weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ class LLWearable
|
|||
// Constructors and destructors
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
LLWearable();
|
||||
virtual ~LLWearable();
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
|
@ -94,14 +95,14 @@ public:
|
|||
|
||||
void setLocalTextureObject(S32 index, LLLocalTextureObject <o);
|
||||
void addVisualParam(LLVisualParam *param);
|
||||
void setVisualParamWeight(S32 index, F32 value, BOOL upload_bake);
|
||||
void setVisualParamWeight(S32 index, F32 value);
|
||||
F32 getVisualParamWeight(S32 index) const;
|
||||
LLVisualParam* getVisualParam(S32 index) const;
|
||||
void getVisualParams(visual_param_vec_t &list);
|
||||
void animateParams(F32 delta, BOOL upload_bake);
|
||||
void animateParams(F32 delta);
|
||||
|
||||
LLColor4 getClothesColor(S32 te) const;
|
||||
void setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake );
|
||||
void setClothesColor( S32 te, const LLColor4& new_color);
|
||||
|
||||
virtual void revertValues();
|
||||
virtual void saveValues();
|
||||
|
|
|
|||
|
|
@ -139,13 +139,6 @@ U32 LLWearableData::pushWearable(const LLWearableType::EType type,
|
|||
void LLWearableData::wearableUpdated(LLWearable *wearable, BOOL removed)
|
||||
{
|
||||
wearable->setUpdated();
|
||||
// FIXME DRANO avoid updating params via wearables when rendering server-baked appearance.
|
||||
#if 0
|
||||
if (mAvatarAppearance->isUsingServerBakes() && !mAvatarAppearance->isUsingLocalAppearance())
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (!removed)
|
||||
{
|
||||
pullCrossWearableValues(wearable->getType());
|
||||
|
|
|
|||
|
|
@ -287,13 +287,13 @@ void LLCharacter::removeAnimationData(std::string name)
|
|||
//-----------------------------------------------------------------------------
|
||||
// setVisualParamWeight()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLCharacter::setVisualParamWeight(const LLVisualParam* which_param, F32 weight, BOOL upload_bake)
|
||||
BOOL LLCharacter::setVisualParamWeight(const LLVisualParam* which_param, F32 weight)
|
||||
{
|
||||
S32 index = which_param->getID();
|
||||
visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index);
|
||||
if (index_iter != mVisualParamIndexMap.end())
|
||||
{
|
||||
index_iter->second->setWeight(weight, upload_bake);
|
||||
index_iter->second->setWeight(weight);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
|
|
@ -302,7 +302,7 @@ BOOL LLCharacter::setVisualParamWeight(const LLVisualParam* which_param, F32 wei
|
|||
//-----------------------------------------------------------------------------
|
||||
// setVisualParamWeight()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake)
|
||||
BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight)
|
||||
{
|
||||
std::string tname(param_name);
|
||||
LLStringUtil::toLower(tname);
|
||||
|
|
@ -310,7 +310,7 @@ BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight, BOOL
|
|||
visual_param_name_map_t::iterator name_iter = mVisualParamNameMap.find(tableptr);
|
||||
if (name_iter != mVisualParamNameMap.end())
|
||||
{
|
||||
name_iter->second->setWeight(weight, upload_bake);
|
||||
name_iter->second->setWeight(weight);
|
||||
return TRUE;
|
||||
}
|
||||
LL_WARNS() << "LLCharacter::setVisualParamWeight() Invalid visual parameter: " << param_name << LL_ENDL;
|
||||
|
|
@ -320,12 +320,12 @@ BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight, BOOL
|
|||
//-----------------------------------------------------------------------------
|
||||
// setVisualParamWeight()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLCharacter::setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake)
|
||||
BOOL LLCharacter::setVisualParamWeight(S32 index, F32 weight)
|
||||
{
|
||||
visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index);
|
||||
if (index_iter != mVisualParamIndexMap.end())
|
||||
{
|
||||
index_iter->second->setWeight(weight, upload_bake);
|
||||
index_iter->second->setWeight(weight);
|
||||
return TRUE;
|
||||
}
|
||||
LL_WARNS() << "LLCharacter::setVisualParamWeight() Invalid visual parameter index: " << index << LL_ENDL;
|
||||
|
|
@ -395,7 +395,7 @@ void LLCharacter::clearVisualParamWeights()
|
|||
{
|
||||
if (param->isTweakable())
|
||||
{
|
||||
param->setWeight( param->getDefaultWeight(), FALSE );
|
||||
param->setWeight( param->getDefaultWeight());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -190,9 +190,9 @@ public:
|
|||
void addVisualParam(LLVisualParam *param);
|
||||
void addSharedVisualParam(LLVisualParam *param);
|
||||
|
||||
virtual BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight, BOOL upload_bake = FALSE );
|
||||
virtual BOOL setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake = FALSE );
|
||||
virtual BOOL setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake = FALSE );
|
||||
virtual BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight);
|
||||
virtual BOOL setVisualParamWeight(const char* param_name, F32 weight);
|
||||
virtual BOOL setVisualParamWeight(S32 index, F32 weight);
|
||||
|
||||
// get visual param weight by param or name
|
||||
F32 getVisualParamWeight(LLVisualParam *distortion);
|
||||
|
|
|
|||
|
|
@ -48,8 +48,11 @@ void LLJoint::init()
|
|||
mParent = NULL;
|
||||
mXform.setScaleChildOffset(TRUE);
|
||||
mXform.setScale(LLVector3(1.0f, 1.0f, 1.0f));
|
||||
mOldXform.setScaleChildOffset(TRUE);
|
||||
mOldXform.setScale(LLVector3(1.0f, 1.0f, 1.0f));
|
||||
mDirtyFlags = MATRIX_DIRTY | ROTATION_DIRTY | POSITION_DIRTY;
|
||||
mUpdateXform = TRUE;
|
||||
mResetAfterRestoreOldXform = false;
|
||||
}
|
||||
|
||||
LLJoint::LLJoint() :
|
||||
|
|
@ -57,7 +60,6 @@ LLJoint::LLJoint() :
|
|||
{
|
||||
init();
|
||||
touch();
|
||||
mResetAfterRestoreOldXform = false;
|
||||
}
|
||||
|
||||
LLJoint::LLJoint(S32 joint_num) :
|
||||
|
|
@ -65,7 +67,6 @@ LLJoint::LLJoint(S32 joint_num) :
|
|||
{
|
||||
init();
|
||||
touch();
|
||||
mResetAfterRestoreOldXform = false;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -78,7 +79,6 @@ LLJoint::LLJoint(const std::string &name, LLJoint *parent) :
|
|||
{
|
||||
init();
|
||||
mUpdateXform = FALSE;
|
||||
// *TODO: mResetAfterRestoreOldXform is not initialized!!!
|
||||
|
||||
setName(name);
|
||||
if (parent)
|
||||
|
|
@ -239,11 +239,8 @@ const LLVector3& LLJoint::getPosition()
|
|||
//--------------------------------------------------------------------
|
||||
void LLJoint::setPosition( const LLVector3& pos )
|
||||
{
|
||||
// if (mXform.getPosition() != pos)
|
||||
{
|
||||
mXform.setPosition(pos);
|
||||
touch(MATRIX_DIRTY | POSITION_DIRTY);
|
||||
}
|
||||
mXform.setPosition(pos);
|
||||
touch(MATRIX_DIRTY | POSITION_DIRTY);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -251,38 +248,37 @@ void LLJoint::setPosition( const LLVector3& pos )
|
|||
// setPosition()
|
||||
//--------------------------------------------------------------------
|
||||
void LLJoint::setDefaultFromCurrentXform( void )
|
||||
{
|
||||
{
|
||||
mDefaultXform = mXform;
|
||||
touch(MATRIX_DIRTY | POSITION_DIRTY);
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// storeCurrentXform()
|
||||
//--------------------------------------------------------------------
|
||||
void LLJoint::storeCurrentXform( const LLVector3& pos )
|
||||
{
|
||||
{
|
||||
mOldXform = mXform;
|
||||
mResetAfterRestoreOldXform = true;
|
||||
mResetAfterRestoreOldXform = true;
|
||||
setPosition( pos );
|
||||
touch(ALL_DIRTY);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// storeScaleForReset()
|
||||
//--------------------------------------------------------------------
|
||||
void LLJoint::storeScaleForReset( const LLVector3& scale )
|
||||
{
|
||||
mOldXform.setScale( scale );
|
||||
}
|
||||
//--------------------------------------------------------------------
|
||||
// restoreOldXform()
|
||||
//--------------------------------------------------------------------
|
||||
void LLJoint::restoreOldXform( void )
|
||||
{
|
||||
mResetAfterRestoreOldXform = false;
|
||||
mXform = mOldXform;
|
||||
}
|
||||
//--------------------------------------------------------------------
|
||||
// restoreOldXform()
|
||||
//--------------------------------------------------------------------
|
||||
void LLJoint::restoreToDefaultXform( void )
|
||||
{
|
||||
mXform = mDefaultXform;
|
||||
setPosition( mXform.getPosition() );
|
||||
mResetAfterRestoreOldXform = false;
|
||||
mDirtyFlags = ALL_DIRTY;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// getWorldPosition()
|
||||
//--------------------------------------------------------------------
|
||||
|
|
@ -299,8 +295,6 @@ LLVector3 LLJoint::getLastWorldPosition()
|
|||
{
|
||||
return mXform.getWorldPosition();
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// setWorldPosition()
|
||||
//--------------------------------------------------------------------
|
||||
|
|
@ -404,7 +398,7 @@ void LLJoint::setWorldRotation( const LLQuaternion& rot )
|
|||
//--------------------------------------------------------------------
|
||||
const LLVector3& LLJoint::getScale()
|
||||
{
|
||||
return mXform.getScale();
|
||||
return mXform.getScale();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
|
@ -413,7 +407,7 @@ const LLVector3& LLJoint::getScale()
|
|||
void LLJoint::setScale( const LLVector3& scale )
|
||||
{
|
||||
// if (mXform.getScale() != scale)
|
||||
{
|
||||
{
|
||||
mXform.setScale(scale);
|
||||
touch();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ protected:
|
|||
LLXformMatrix mDefaultXform;
|
||||
|
||||
LLUUID mId;
|
||||
|
||||
public:
|
||||
U32 mDirtyFlags;
|
||||
BOOL mUpdateXform;
|
||||
|
|
@ -159,7 +160,7 @@ public:
|
|||
// get/set local scale
|
||||
const LLVector3& getScale();
|
||||
void setScale( const LLVector3& scale );
|
||||
|
||||
void storeScaleForReset( const LLVector3& scale );
|
||||
// get/set world matrix
|
||||
const LLMatrix4 &getWorldMatrix();
|
||||
void setWorldMatrix( const LLMatrix4& mat );
|
||||
|
|
@ -184,7 +185,6 @@ public:
|
|||
S32 getJointNum() const { return mJointNum; }
|
||||
|
||||
void restoreOldXform( void );
|
||||
void restoreToDefaultXform( void );
|
||||
void setDefaultFromCurrentXform( void );
|
||||
void storeCurrentXform( const LLVector3& pos );
|
||||
|
||||
|
|
@ -195,8 +195,8 @@ public:
|
|||
|
||||
//If the old transform flag has been set, then the reset logic in avatar needs to be aware(test) of it
|
||||
const BOOL doesJointNeedToBeReset( void ) const { return mResetAfterRestoreOldXform; }
|
||||
//Setter for joint reset flag
|
||||
void setJointToBeReset( BOOL val ) { mResetAfterRestoreOldXform = val; }
|
||||
void setJointResetFlag( bool val ) { mResetAfterRestoreOldXform = val; }
|
||||
|
||||
};
|
||||
#endif // LL_LLJOINT_H
|
||||
|
||||
|
|
|
|||
|
|
@ -173,10 +173,12 @@ void LLMotionController::deleteAllMotions()
|
|||
for_each(mAllMotions.begin(), mAllMotions.end(), DeletePairedPointer());
|
||||
mAllMotions.clear();
|
||||
|
||||
// <FS:ND> There might still be motions in mDeprecatedMotions. Don't leak those.
|
||||
for_each(mDeprecatedMotions.begin(), mDeprecatedMotions.end(), DeletePointer() );
|
||||
// stinson 05/12/20014 : Ownership of the LLMotion pointers is transferred from
|
||||
// mAllMotions to mDeprecatedMotions in method
|
||||
// LLMotionController::deprecateMotionInstance(). Thus, we should also clean
|
||||
// up the mDeprecatedMotions list as well.
|
||||
for_each(mDeprecatedMotions.begin(), mDeprecatedMotions.end(), DeletePointer());
|
||||
mDeprecatedMotions.clear();
|
||||
// </FS:ND>
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -159,26 +159,42 @@ void LLVisualParamInfo::toStream(std::ostream &out)
|
|||
//-----------------------------------------------------------------------------
|
||||
// LLVisualParam()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLVisualParam::LLVisualParam()
|
||||
:
|
||||
mCurWeight( 0.f ),
|
||||
LLVisualParam::LLVisualParam()
|
||||
: mCurWeight( 0.f ),
|
||||
mLastWeight( 0.f ),
|
||||
mNext( NULL ),
|
||||
mTargetWeight( 0.f ),
|
||||
mIsAnimating( FALSE ),
|
||||
mIsDummy(FALSE),
|
||||
mID( -1 ),
|
||||
mInfo( 0 ),
|
||||
mIsDummy(FALSE),
|
||||
mParamLocation(LOC_UNKNOWN)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLVisualParam()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLVisualParam::LLVisualParam(const LLVisualParam& pOther)
|
||||
: mCurWeight(pOther.mCurWeight),
|
||||
mLastWeight(pOther.mLastWeight),
|
||||
mNext(pOther.mNext),
|
||||
mTargetWeight(pOther.mTargetWeight),
|
||||
mIsAnimating(pOther.mIsAnimating),
|
||||
mIsDummy(pOther.mIsDummy),
|
||||
mID(pOther.mID),
|
||||
mInfo(pOther.mInfo),
|
||||
mParamLocation(pOther.mParamLocation)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ~LLVisualParam()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLVisualParam::~LLVisualParam()
|
||||
{
|
||||
delete mNext;
|
||||
mNext = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -220,7 +236,7 @@ BOOL LLVisualParam::parseData(LLXmlTreeNode *node)
|
|||
//-----------------------------------------------------------------------------
|
||||
// setWeight()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLVisualParam::setWeight(F32 weight, BOOL upload_bake)
|
||||
void LLVisualParam::setWeight(F32 weight)
|
||||
{
|
||||
if (mIsAnimating)
|
||||
{
|
||||
|
|
@ -238,19 +254,19 @@ void LLVisualParam::setWeight(F32 weight, BOOL upload_bake)
|
|||
|
||||
if (mNext)
|
||||
{
|
||||
mNext->setWeight(weight, upload_bake);
|
||||
mNext->setWeight(weight);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// setAnimationTarget()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLVisualParam::setAnimationTarget(F32 target_value, BOOL upload_bake)
|
||||
void LLVisualParam::setAnimationTarget(F32 target_value)
|
||||
{
|
||||
// don't animate dummy parameters
|
||||
if (mIsDummy)
|
||||
{
|
||||
setWeight(target_value, upload_bake);
|
||||
setWeight(target_value);
|
||||
mTargetWeight = mCurWeight;
|
||||
return;
|
||||
}
|
||||
|
|
@ -270,7 +286,7 @@ void LLVisualParam::setAnimationTarget(F32 target_value, BOOL upload_bake)
|
|||
|
||||
if (mNext)
|
||||
{
|
||||
mNext->setAnimationTarget(target_value, upload_bake);
|
||||
mNext->setAnimationTarget(target_value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -284,27 +300,35 @@ void LLVisualParam::setNextParam( LLVisualParam *next )
|
|||
mNext = next;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// clearNextParam()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLVisualParam::clearNextParam()
|
||||
{
|
||||
mNext = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// animate()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLVisualParam::animate( F32 delta, BOOL upload_bake )
|
||||
void LLVisualParam::animate( F32 delta)
|
||||
{
|
||||
if (mIsAnimating)
|
||||
{
|
||||
F32 new_weight = ((mTargetWeight - mCurWeight) * delta) + mCurWeight;
|
||||
setWeight(new_weight, upload_bake);
|
||||
setWeight(new_weight);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// stopAnimating()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLVisualParam::stopAnimating(BOOL upload_bake)
|
||||
void LLVisualParam::stopAnimating()
|
||||
{
|
||||
if (mIsAnimating && isTweakable())
|
||||
{
|
||||
mIsAnimating = FALSE;
|
||||
setWeight(mTargetWeight, upload_bake);
|
||||
setWeight(mTargetWeight);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -120,10 +120,10 @@ public:
|
|||
//virtual BOOL parseData( LLXmlTreeNode *node ) = 0;
|
||||
virtual void apply( ESex avatar_sex ) = 0;
|
||||
// Default functions
|
||||
virtual void setWeight(F32 weight, BOOL upload_bake);
|
||||
virtual void setAnimationTarget( F32 target_value, BOOL upload_bake );
|
||||
virtual void animate(F32 delta, BOOL upload_bake);
|
||||
virtual void stopAnimating(BOOL upload_bake);
|
||||
virtual void setWeight(F32 weight);
|
||||
virtual void setAnimationTarget( F32 target_value);
|
||||
virtual void animate(F32 delta);
|
||||
virtual void stopAnimating();
|
||||
|
||||
virtual BOOL linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params);
|
||||
virtual void resetDrivenParams();
|
||||
|
|
@ -155,6 +155,7 @@ public:
|
|||
|
||||
LLVisualParam* getNextParam() { return mNext; }
|
||||
void setNextParam( LLVisualParam *next );
|
||||
void clearNextParam();
|
||||
|
||||
virtual void setAnimating(BOOL is_animating) { mIsAnimating = is_animating && !mIsDummy; }
|
||||
BOOL getAnimating() const { return mIsAnimating; }
|
||||
|
|
@ -165,6 +166,8 @@ public:
|
|||
EParamLocation getParamLocation() const { return mParamLocation; }
|
||||
|
||||
protected:
|
||||
LLVisualParam(const LLVisualParam& pOther);
|
||||
|
||||
F32 mCurWeight; // current weight
|
||||
F32 mLastWeight; // last weight
|
||||
LLVisualParam* mNext; // next param in a shared chain
|
||||
|
|
|
|||
|
|
@ -158,7 +158,6 @@ set(llcommon_HEADER_FILES
|
|||
llhandle.h
|
||||
llhash.h
|
||||
llheartbeat.h
|
||||
llhttpstatuscodes.h
|
||||
llindexedvector.h
|
||||
llinitparam.h
|
||||
llinstancetracker.h
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
#include "lllivefile.h"
|
||||
#include "llsd.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llsingleton.h"
|
||||
#include "llstl.h"
|
||||
#include "lltimer.h"
|
||||
|
||||
|
|
@ -363,30 +364,31 @@ namespace
|
|||
|
||||
|
||||
typedef std::map<std::string, LLError::ELevel> LevelMap;
|
||||
typedef std::vector<LLError::Recorder*> Recorders;
|
||||
typedef std::vector<LLError::RecorderPtr> Recorders;
|
||||
typedef std::vector<LLError::CallSite*> CallSiteVector;
|
||||
|
||||
class Globals
|
||||
class Globals : public LLSingleton<Globals>
|
||||
{
|
||||
public:
|
||||
Globals();
|
||||
|
||||
std::ostringstream messageStream;
|
||||
bool messageStreamInUse;
|
||||
|
||||
void addCallSite(LLError::CallSite&);
|
||||
void invalidateCallSites();
|
||||
|
||||
static Globals& get();
|
||||
// return the one instance of the globals
|
||||
|
||||
private:
|
||||
CallSiteVector callSites;
|
||||
|
||||
Globals()
|
||||
: messageStreamInUse(false)
|
||||
{ }
|
||||
|
||||
};
|
||||
|
||||
Globals::Globals()
|
||||
: messageStream(),
|
||||
messageStreamInUse(false),
|
||||
callSites()
|
||||
{
|
||||
}
|
||||
|
||||
void Globals::addCallSite(LLError::CallSite& site)
|
||||
{
|
||||
callSites.push_back(&site);
|
||||
|
|
@ -403,25 +405,17 @@ namespace
|
|||
|
||||
callSites.clear();
|
||||
}
|
||||
|
||||
Globals& Globals::get()
|
||||
{
|
||||
/* This pattern, of returning a reference to a static function
|
||||
variable, is to ensure that this global is constructed before
|
||||
it is used, no matter what the global initialization sequence
|
||||
is.
|
||||
See C++ FAQ Lite, sections 10.12 through 10.14
|
||||
*/
|
||||
static Globals* globals = new Globals;
|
||||
return *globals;
|
||||
}
|
||||
}
|
||||
|
||||
namespace LLError
|
||||
{
|
||||
class Settings
|
||||
class SettingsConfig : public LLRefCount
|
||||
{
|
||||
friend class Settings;
|
||||
|
||||
public:
|
||||
virtual ~SettingsConfig();
|
||||
|
||||
bool mPrintLocation;
|
||||
|
||||
LLError::ELevel mDefaultLevel;
|
||||
|
|
@ -436,81 +430,86 @@ namespace LLError
|
|||
LLError::TimeFunction mTimeFunction;
|
||||
|
||||
Recorders mRecorders;
|
||||
Recorder* mFileRecorder;
|
||||
Recorder* mFixedBufferRecorder;
|
||||
RecorderPtr mFileRecorder;
|
||||
RecorderPtr mFixedBufferRecorder;
|
||||
std::string mFileRecorderFileName;
|
||||
|
||||
int mShouldLogCallCounter;
|
||||
|
||||
static Settings& get();
|
||||
private:
|
||||
SettingsConfig();
|
||||
};
|
||||
|
||||
typedef LLPointer<SettingsConfig> SettingsConfigPtr;
|
||||
|
||||
class Settings : public LLSingleton<Settings>
|
||||
{
|
||||
public:
|
||||
Settings();
|
||||
|
||||
SettingsConfigPtr getSettingsConfig();
|
||||
|
||||
static void reset();
|
||||
static Settings* saveAndReset();
|
||||
static void restore(Settings*);
|
||||
void reset();
|
||||
SettingsStoragePtr saveAndReset();
|
||||
void restore(SettingsStoragePtr pSettingsStorage);
|
||||
|
||||
private:
|
||||
Settings()
|
||||
: mPrintLocation(false),
|
||||
mDefaultLevel(LLError::LEVEL_DEBUG),
|
||||
mCrashFunction(),
|
||||
mTimeFunction(NULL),
|
||||
mFileRecorder(NULL),
|
||||
mFixedBufferRecorder(NULL),
|
||||
mShouldLogCallCounter(0)
|
||||
{ }
|
||||
|
||||
~Settings()
|
||||
{
|
||||
for_each(mRecorders.begin(), mRecorders.end(), DeletePointer());
|
||||
mRecorders.clear();
|
||||
}
|
||||
|
||||
static Settings*& getPtr();
|
||||
SettingsConfigPtr mSettingsConfig;
|
||||
};
|
||||
|
||||
Settings& Settings::get()
|
||||
SettingsConfig::SettingsConfig()
|
||||
: LLRefCount(),
|
||||
mPrintLocation(false),
|
||||
mDefaultLevel(LLError::LEVEL_DEBUG),
|
||||
mFunctionLevelMap(),
|
||||
mClassLevelMap(),
|
||||
mFileLevelMap(),
|
||||
mTagLevelMap(),
|
||||
mUniqueLogMessages(),
|
||||
mCrashFunction(NULL),
|
||||
mTimeFunction(NULL),
|
||||
mRecorders(),
|
||||
mFileRecorder(),
|
||||
mFixedBufferRecorder(),
|
||||
mFileRecorderFileName(),
|
||||
mShouldLogCallCounter(0)
|
||||
{
|
||||
Settings* p = getPtr();
|
||||
if (!p)
|
||||
{
|
||||
reset();
|
||||
p = getPtr();
|
||||
}
|
||||
return *p;
|
||||
}
|
||||
|
||||
SettingsConfig::~SettingsConfig()
|
||||
{
|
||||
mRecorders.clear();
|
||||
}
|
||||
|
||||
Settings::Settings()
|
||||
: LLSingleton<Settings>(),
|
||||
mSettingsConfig(new SettingsConfig())
|
||||
{
|
||||
}
|
||||
|
||||
SettingsConfigPtr Settings::getSettingsConfig()
|
||||
{
|
||||
return mSettingsConfig;
|
||||
}
|
||||
|
||||
void Settings::reset()
|
||||
{
|
||||
Globals::get().invalidateCallSites();
|
||||
|
||||
Settings*& p = getPtr();
|
||||
delete p;
|
||||
p = new Settings();
|
||||
Globals::getInstance()->invalidateCallSites();
|
||||
mSettingsConfig = new SettingsConfig();
|
||||
}
|
||||
|
||||
Settings* Settings::saveAndReset()
|
||||
SettingsStoragePtr Settings::saveAndReset()
|
||||
{
|
||||
Globals::get().invalidateCallSites();
|
||||
|
||||
Settings*& p = getPtr();
|
||||
Settings* originalSettings = p;
|
||||
p = new Settings();
|
||||
return originalSettings;
|
||||
SettingsStoragePtr oldSettingsConfig(mSettingsConfig.get());
|
||||
reset();
|
||||
return oldSettingsConfig;
|
||||
}
|
||||
|
||||
void Settings::restore(Settings* originalSettings)
|
||||
void Settings::restore(SettingsStoragePtr pSettingsStorage)
|
||||
{
|
||||
Globals::get().invalidateCallSites();
|
||||
|
||||
Settings*& p = getPtr();
|
||||
delete p;
|
||||
p = originalSettings;
|
||||
}
|
||||
|
||||
Settings*& Settings::getPtr()
|
||||
{
|
||||
static Settings* currentSettings = NULL;
|
||||
return currentSettings;
|
||||
Globals::getInstance()->invalidateCallSites();
|
||||
SettingsConfigPtr newSettingsConfig(dynamic_cast<SettingsConfig *>(pSettingsStorage.get()));
|
||||
mSettingsConfig = newSettingsConfig;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -646,7 +645,7 @@ namespace
|
|||
|
||||
void commonInit(const std::string& dir, bool log_to_stderr = true)
|
||||
{
|
||||
LLError::Settings::reset();
|
||||
LLError::Settings::getInstance()->reset();
|
||||
|
||||
LLError::setDefaultLevel(LLError::LEVEL_INFO);
|
||||
LLError::setFatalFunction(LLError::crashAndLoop);
|
||||
|
|
@ -655,11 +654,13 @@ namespace
|
|||
// log_to_stderr is only false in the unit and integration tests to keep builds quieter
|
||||
if (log_to_stderr && shouldLogToStderr())
|
||||
{
|
||||
LLError::addRecorder(new RecordToStderr(stderrLogWantsTime()));
|
||||
LLError::RecorderPtr recordToStdErr(new RecordToStderr(stderrLogWantsTime()));
|
||||
LLError::addRecorder(recordToStdErr);
|
||||
}
|
||||
|
||||
#if LL_WINDOWS
|
||||
LLError::addRecorder(new RecordToWinDebug);
|
||||
LLError::RecorderPtr recordToWinDebug(new RecordToWinDebug());
|
||||
LLError::addRecorder(recordToWinDebug);
|
||||
#endif
|
||||
|
||||
LogControlFile& e = LogControlFile::fromDirectory(dir);
|
||||
|
|
@ -687,7 +688,8 @@ namespace LLError
|
|||
}
|
||||
commonInit(dir);
|
||||
#if !LL_WINDOWS
|
||||
addRecorder(new RecordToSyslog(identity));
|
||||
LLError::RecorderPtr recordToSyslog(new RecordToSyslog(identity));
|
||||
addRecorder(recordToSyslog);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -698,72 +700,67 @@ namespace LLError
|
|||
|
||||
void setPrintLocation(bool print)
|
||||
{
|
||||
Settings& s = Settings::get();
|
||||
s.mPrintLocation = print;
|
||||
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
|
||||
s->mPrintLocation = print;
|
||||
}
|
||||
|
||||
void setFatalFunction(const FatalFunction& f)
|
||||
{
|
||||
Settings& s = Settings::get();
|
||||
s.mCrashFunction = f;
|
||||
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
|
||||
s->mCrashFunction = f;
|
||||
}
|
||||
|
||||
FatalFunction getFatalFunction()
|
||||
{
|
||||
Settings& s = Settings::get();
|
||||
return s.mCrashFunction;
|
||||
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
|
||||
return s->mCrashFunction;
|
||||
}
|
||||
|
||||
void setTimeFunction(TimeFunction f)
|
||||
{
|
||||
Settings& s = Settings::get();
|
||||
s.mTimeFunction = f;
|
||||
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
|
||||
s->mTimeFunction = f;
|
||||
}
|
||||
|
||||
void setDefaultLevel(ELevel level)
|
||||
{
|
||||
Globals& g = Globals::get();
|
||||
Settings& s = Settings::get();
|
||||
g.invalidateCallSites();
|
||||
s.mDefaultLevel = level;
|
||||
Globals::getInstance()->invalidateCallSites();
|
||||
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
|
||||
s->mDefaultLevel = level;
|
||||
}
|
||||
|
||||
ELevel getDefaultLevel()
|
||||
{
|
||||
Settings& s = Settings::get();
|
||||
return s.mDefaultLevel;
|
||||
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
|
||||
return s->mDefaultLevel;
|
||||
}
|
||||
|
||||
void setFunctionLevel(const std::string& function_name, ELevel level)
|
||||
{
|
||||
Globals& g = Globals::get();
|
||||
Settings& s = Settings::get();
|
||||
g.invalidateCallSites();
|
||||
s.mFunctionLevelMap[function_name] = level;
|
||||
Globals::getInstance()->invalidateCallSites();
|
||||
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
|
||||
s->mFunctionLevelMap[function_name] = level;
|
||||
}
|
||||
|
||||
void setClassLevel(const std::string& class_name, ELevel level)
|
||||
{
|
||||
Globals& g = Globals::get();
|
||||
Settings& s = Settings::get();
|
||||
g.invalidateCallSites();
|
||||
s.mClassLevelMap[class_name] = level;
|
||||
Globals::getInstance()->invalidateCallSites();
|
||||
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
|
||||
s->mClassLevelMap[class_name] = level;
|
||||
}
|
||||
|
||||
void setFileLevel(const std::string& file_name, ELevel level)
|
||||
{
|
||||
Globals& g = Globals::get();
|
||||
Settings& s = Settings::get();
|
||||
g.invalidateCallSites();
|
||||
s.mFileLevelMap[file_name] = level;
|
||||
Globals::getInstance()->invalidateCallSites();
|
||||
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
|
||||
s->mFileLevelMap[file_name] = level;
|
||||
}
|
||||
|
||||
void setTagLevel(const std::string& tag_name, ELevel level)
|
||||
{
|
||||
Globals& g = Globals::get();
|
||||
Settings& s = Settings::get();
|
||||
g.invalidateCallSites();
|
||||
s.mTagLevelMap[tag_name] = level;
|
||||
Globals::getInstance()->invalidateCallSites();
|
||||
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
|
||||
s->mTagLevelMap[tag_name] = level;
|
||||
}
|
||||
|
||||
LLError::ELevel decodeLevel(std::string name)
|
||||
|
|
@ -807,15 +804,14 @@ namespace LLError
|
|||
{
|
||||
void configure(const LLSD& config)
|
||||
{
|
||||
Globals& g = Globals::get();
|
||||
Settings& s = Settings::get();
|
||||
Globals::getInstance()->invalidateCallSites();
|
||||
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
|
||||
|
||||
g.invalidateCallSites();
|
||||
s.mFunctionLevelMap.clear();
|
||||
s.mClassLevelMap.clear();
|
||||
s.mFileLevelMap.clear();
|
||||
s.mTagLevelMap.clear();
|
||||
s.mUniqueLogMessages.clear();
|
||||
s->mFunctionLevelMap.clear();
|
||||
s->mClassLevelMap.clear();
|
||||
s->mFileLevelMap.clear();
|
||||
s->mTagLevelMap.clear();
|
||||
s->mUniqueLogMessages.clear();
|
||||
|
||||
setPrintLocation(config["print-location"]);
|
||||
setDefaultLevel(decodeLevel(config["default-level"]));
|
||||
|
|
@ -828,10 +824,10 @@ namespace LLError
|
|||
|
||||
ELevel level = decodeLevel(entry["level"]);
|
||||
|
||||
setLevels(s.mFunctionLevelMap, entry["functions"], level);
|
||||
setLevels(s.mClassLevelMap, entry["classes"], level);
|
||||
setLevels(s.mFileLevelMap, entry["files"], level);
|
||||
setLevels(s.mTagLevelMap, entry["tags"], level);
|
||||
setLevels(s->mFunctionLevelMap, entry["functions"], level);
|
||||
setLevels(s->mClassLevelMap, entry["classes"], level);
|
||||
setLevels(s->mFileLevelMap, entry["files"], level);
|
||||
setLevels(s->mTagLevelMap, entry["tags"], level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -845,10 +841,12 @@ namespace LLError
|
|||
mWantsLevel(true),
|
||||
mWantsLocation(false),
|
||||
mWantsFunctionName(true)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
Recorder::~Recorder()
|
||||
{ }
|
||||
{
|
||||
}
|
||||
|
||||
bool Recorder::wantsTime()
|
||||
{
|
||||
|
|
@ -879,25 +877,25 @@ namespace LLError
|
|||
return mWantsFunctionName;
|
||||
}
|
||||
|
||||
void addRecorder(Recorder* recorder)
|
||||
void addRecorder(RecorderPtr recorder)
|
||||
{
|
||||
if (recorder == NULL)
|
||||
if (!recorder)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Settings& s = Settings::get();
|
||||
s.mRecorders.push_back(recorder);
|
||||
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
|
||||
s->mRecorders.push_back(recorder);
|
||||
}
|
||||
|
||||
void removeRecorder(Recorder* recorder)
|
||||
void removeRecorder(RecorderPtr recorder)
|
||||
{
|
||||
if (recorder == NULL)
|
||||
if (!recorder)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Settings& s = Settings::get();
|
||||
s.mRecorders.erase(std::remove(s.mRecorders.begin(), s.mRecorders.end(), recorder),
|
||||
s.mRecorders.end());
|
||||
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
|
||||
s->mRecorders.erase(std::remove(s->mRecorders.begin(), s->mRecorders.end(), recorder),
|
||||
s->mRecorders.end());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -905,51 +903,47 @@ namespace LLError
|
|||
{
|
||||
void logToFile(const std::string& file_name)
|
||||
{
|
||||
LLError::Settings& s = LLError::Settings::get();
|
||||
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
|
||||
|
||||
removeRecorder(s.mFileRecorder);
|
||||
delete s.mFileRecorder;
|
||||
s.mFileRecorder = NULL;
|
||||
s.mFileRecorderFileName.clear();
|
||||
removeRecorder(s->mFileRecorder);
|
||||
s->mFileRecorder.reset();
|
||||
s->mFileRecorderFileName.clear();
|
||||
|
||||
if (file_name.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RecordToFile* f = new RecordToFile(file_name);
|
||||
if (!f->okay())
|
||||
RecorderPtr recordToFile(new RecordToFile(file_name));
|
||||
if (boost::dynamic_pointer_cast<RecordToFile>(recordToFile)->okay())
|
||||
{
|
||||
delete f;
|
||||
return;
|
||||
s->mFileRecorderFileName = file_name;
|
||||
s->mFileRecorder = recordToFile;
|
||||
addRecorder(recordToFile);
|
||||
}
|
||||
|
||||
s.mFileRecorderFileName = file_name;
|
||||
s.mFileRecorder = f;
|
||||
addRecorder(f);
|
||||
}
|
||||
|
||||
void logToFixedBuffer(LLLineBuffer* fixedBuffer)
|
||||
{
|
||||
LLError::Settings& s = LLError::Settings::get();
|
||||
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
|
||||
|
||||
removeRecorder(s.mFixedBufferRecorder);
|
||||
delete s.mFixedBufferRecorder;
|
||||
s.mFixedBufferRecorder = NULL;
|
||||
removeRecorder(s->mFixedBufferRecorder);
|
||||
s->mFixedBufferRecorder.reset();
|
||||
|
||||
if (!fixedBuffer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
s.mFixedBufferRecorder = new RecordToFixedBuffer(fixedBuffer);
|
||||
addRecorder(s.mFixedBufferRecorder);
|
||||
RecorderPtr recordToFixedBuffer(new RecordToFixedBuffer(fixedBuffer));
|
||||
s->mFixedBufferRecorder = recordToFixedBuffer;
|
||||
addRecorder(recordToFixedBuffer);
|
||||
}
|
||||
|
||||
std::string logFileName()
|
||||
{
|
||||
LLError::Settings& s = LLError::Settings::get();
|
||||
return s.mFileRecorderFileName;
|
||||
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
|
||||
return s->mFileRecorderFileName;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -958,24 +952,24 @@ namespace
|
|||
void writeToRecorders(const LLError::CallSite& site, const std::string& message, bool show_location = true, bool show_time = true, bool show_tags = true, bool show_level = true, bool show_function = true)
|
||||
{
|
||||
LLError::ELevel level = site.mLevel;
|
||||
LLError::Settings& s = LLError::Settings::get();
|
||||
LLError::SettingsConfigPtr s = LLError::Settings::getInstance()->getSettingsConfig();
|
||||
|
||||
for (Recorders::const_iterator i = s.mRecorders.begin();
|
||||
i != s.mRecorders.end();
|
||||
for (Recorders::const_iterator i = s->mRecorders.begin();
|
||||
i != s->mRecorders.end();
|
||||
++i)
|
||||
{
|
||||
LLError::Recorder* r = *i;
|
||||
LLError::RecorderPtr r = *i;
|
||||
|
||||
std::ostringstream message_stream;
|
||||
|
||||
if (show_location && (r->wantsLocation() || level == LLError::LEVEL_ERROR || s.mPrintLocation))
|
||||
if (show_location && (r->wantsLocation() || level == LLError::LEVEL_ERROR || s->mPrintLocation))
|
||||
{
|
||||
message_stream << site.mLocationString << " ";
|
||||
}
|
||||
|
||||
if (show_time && r->wantsTime() && s.mTimeFunction != NULL)
|
||||
if (show_time && r->wantsTime() && s->mTimeFunction != NULL)
|
||||
{
|
||||
message_stream << s.mTimeFunction() << " ";
|
||||
message_stream << s->mTimeFunction() << " ";
|
||||
}
|
||||
|
||||
if (show_level && r->wantsLevel())
|
||||
|
|
@ -1107,10 +1101,9 @@ namespace LLError
|
|||
return false;
|
||||
}
|
||||
|
||||
Globals& g = Globals::get();
|
||||
Settings& s = Settings::get();
|
||||
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
|
||||
|
||||
s.mShouldLogCallCounter++;
|
||||
s->mShouldLogCallCounter++;
|
||||
|
||||
const std::string& class_name = className(site.mClassInfo);
|
||||
std::string function_name = functionName(site.mFunction);
|
||||
|
|
@ -1124,21 +1117,21 @@ namespace LLError
|
|||
function_name = class_name + "::" + function_name;
|
||||
}
|
||||
|
||||
ELevel compareLevel = s.mDefaultLevel;
|
||||
ELevel compareLevel = s->mDefaultLevel;
|
||||
|
||||
// The most specific match found will be used as the log level,
|
||||
// since the computation short circuits.
|
||||
// So, in increasing order of importance:
|
||||
// Default < Tags < File < Class < Function
|
||||
checkLevelMap(s.mFunctionLevelMap, function_name, compareLevel)
|
||||
|| checkLevelMap(s.mClassLevelMap, class_name, compareLevel)
|
||||
|| checkLevelMap(s.mFileLevelMap, abbreviateFile(site.mFile), compareLevel)
|
||||
checkLevelMap(s->mFunctionLevelMap, function_name, compareLevel)
|
||||
|| checkLevelMap(s->mClassLevelMap, class_name, compareLevel)
|
||||
|| checkLevelMap(s->mFileLevelMap, abbreviateFile(site.mFile), compareLevel)
|
||||
|| (site.mTagCount > 0
|
||||
? checkLevelMap(s.mTagLevelMap, site.mTags, site.mTagCount, compareLevel)
|
||||
? checkLevelMap(s->mTagLevelMap, site.mTags, site.mTagCount, compareLevel)
|
||||
: false);
|
||||
|
||||
site.mCached = true;
|
||||
g.addCallSite(site);
|
||||
Globals::getInstance()->addCallSite(site);
|
||||
return site.mShouldLog = site.mLevel >= compareLevel;
|
||||
}
|
||||
|
||||
|
|
@ -1148,12 +1141,12 @@ namespace LLError
|
|||
LogLock lock;
|
||||
if (lock.ok())
|
||||
{
|
||||
Globals& g = Globals::get();
|
||||
Globals* g = Globals::getInstance();
|
||||
|
||||
if (!g.messageStreamInUse)
|
||||
if (!g->messageStreamInUse)
|
||||
{
|
||||
g.messageStreamInUse = true;
|
||||
return &g.messageStream;
|
||||
g->messageStreamInUse = true;
|
||||
return &g->messageStream;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1178,13 +1171,12 @@ namespace LLError
|
|||
message[127] = '\0' ;
|
||||
}
|
||||
|
||||
Globals& g = Globals::get();
|
||||
|
||||
if (out == &g.messageStream)
|
||||
Globals* g = Globals::getInstance();
|
||||
if (out == &g->messageStream)
|
||||
{
|
||||
g.messageStream.clear();
|
||||
g.messageStream.str("");
|
||||
g.messageStreamInUse = false;
|
||||
g->messageStream.clear();
|
||||
g->messageStream.str("");
|
||||
g->messageStreamInUse = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1201,15 +1193,15 @@ namespace LLError
|
|||
return;
|
||||
}
|
||||
|
||||
Globals& g = Globals::get();
|
||||
Settings& s = Settings::get();
|
||||
Globals* g = Globals::getInstance();
|
||||
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
|
||||
|
||||
std::string message = out->str();
|
||||
if (out == &g.messageStream)
|
||||
if (out == &g->messageStream)
|
||||
{
|
||||
g.messageStream.clear();
|
||||
g.messageStream.str("");
|
||||
g.messageStreamInUse = false;
|
||||
g->messageStream.clear();
|
||||
g->messageStream.str("");
|
||||
g->messageStreamInUse = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1229,8 +1221,8 @@ namespace LLError
|
|||
|
||||
if (site.mPrintOnce)
|
||||
{
|
||||
std::map<std::string, unsigned int>::iterator messageIter = s.mUniqueLogMessages.find(message);
|
||||
if (messageIter != s.mUniqueLogMessages.end())
|
||||
std::map<std::string, unsigned int>::iterator messageIter = s->mUniqueLogMessages.find(message);
|
||||
if (messageIter != s->mUniqueLogMessages.end())
|
||||
{
|
||||
messageIter->second++;
|
||||
unsigned int num_messages = messageIter->second;
|
||||
|
|
@ -1246,7 +1238,7 @@ namespace LLError
|
|||
else
|
||||
{
|
||||
message_stream << "ONCE: ";
|
||||
s.mUniqueLogMessages[message] = 1;
|
||||
s->mUniqueLogMessages[message] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1254,23 +1246,23 @@ namespace LLError
|
|||
|
||||
writeToRecorders(site, message_stream.str());
|
||||
|
||||
if (site.mLevel == LEVEL_ERROR && s.mCrashFunction)
|
||||
if (site.mLevel == LEVEL_ERROR && s->mCrashFunction)
|
||||
{
|
||||
s.mCrashFunction(message_stream.str());
|
||||
s->mCrashFunction(message_stream.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace LLError
|
||||
{
|
||||
Settings* saveAndResetSettings()
|
||||
SettingsStoragePtr saveAndResetSettings()
|
||||
{
|
||||
return Settings::saveAndReset();
|
||||
return Settings::getInstance()->saveAndReset();
|
||||
}
|
||||
|
||||
void restoreSettings(Settings* s)
|
||||
void restoreSettings(SettingsStoragePtr pSettingsStorage)
|
||||
{
|
||||
return Settings::restore(s);
|
||||
return Settings::getInstance()->restore(pSettingsStorage);
|
||||
}
|
||||
|
||||
std::string removePrefix(std::string& s, const std::string& p)
|
||||
|
|
@ -1316,8 +1308,8 @@ namespace LLError
|
|||
|
||||
int shouldLogCallCount()
|
||||
{
|
||||
Settings& s = Settings::get();
|
||||
return s.mShouldLogCallCounter;
|
||||
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
|
||||
return s->mShouldLogCallCounter;
|
||||
}
|
||||
|
||||
#if LL_WINDOWS
|
||||
|
|
@ -1426,15 +1418,9 @@ namespace LLError
|
|||
#endif
|
||||
|
||||
//static
|
||||
void LLCallStacks::push(const char* function, const int line)
|
||||
void LLCallStacks::allocateStackBuffer()
|
||||
{
|
||||
CallStacksLogLock lock;
|
||||
if (!lock.ok())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(!sBuffer)
|
||||
if(sBuffer == NULL)
|
||||
{
|
||||
sBuffer = new char*[512] ;
|
||||
sBuffer[0] = new char[512 * 128] ;
|
||||
|
|
@ -1444,6 +1430,31 @@ namespace LLError
|
|||
}
|
||||
sIndex = 0 ;
|
||||
}
|
||||
}
|
||||
|
||||
void LLCallStacks::freeStackBuffer()
|
||||
{
|
||||
if(sBuffer != NULL)
|
||||
{
|
||||
delete [] sBuffer[0] ;
|
||||
delete [] sBuffer ;
|
||||
sBuffer = NULL ;
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLCallStacks::push(const char* function, const int line)
|
||||
{
|
||||
CallStacksLogLock lock;
|
||||
if (!lock.ok())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(sBuffer == NULL)
|
||||
{
|
||||
allocateStackBuffer();
|
||||
}
|
||||
|
||||
if(sIndex > 511)
|
||||
{
|
||||
|
|
@ -1475,15 +1486,9 @@ namespace LLError
|
|||
return;
|
||||
}
|
||||
|
||||
if(!sBuffer)
|
||||
if(sBuffer == NULL)
|
||||
{
|
||||
sBuffer = new char*[512] ;
|
||||
sBuffer[0] = new char[512 * 128] ;
|
||||
for(S32 i = 1 ; i < 512 ; i++)
|
||||
{
|
||||
sBuffer[i] = sBuffer[i-1] + 128 ;
|
||||
}
|
||||
sIndex = 0 ;
|
||||
allocateStackBuffer();
|
||||
}
|
||||
|
||||
if(sIndex > 511)
|
||||
|
|
@ -1514,11 +1519,9 @@ namespace LLError
|
|||
LL_INFOS() << " *************** END OF LL CALL STACKS *************** " << LL_ENDL;
|
||||
}
|
||||
|
||||
if(sBuffer)
|
||||
if(sBuffer != NULL)
|
||||
{
|
||||
delete[] sBuffer[0] ;
|
||||
delete[] sBuffer ;
|
||||
sBuffer = NULL ;
|
||||
freeStackBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1528,5 +1531,10 @@ namespace LLError
|
|||
sIndex = 0 ;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLCallStacks::cleanup()
|
||||
{
|
||||
freeStackBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -274,6 +274,9 @@ namespace LLError
|
|||
private:
|
||||
static char** sBuffer ;
|
||||
static S32 sIndex ;
|
||||
|
||||
static void allocateStackBuffer();
|
||||
static void freeStackBuffer();
|
||||
|
||||
public:
|
||||
static void push(const char* function, const int line) ;
|
||||
|
|
@ -281,6 +284,7 @@ namespace LLError
|
|||
static void print() ;
|
||||
static void clear() ;
|
||||
static void end(std::ostringstream* _out) ;
|
||||
static void cleanup();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,10 @@
|
|||
#define LL_LLERRORCONTROL_H
|
||||
|
||||
#include "llerror.h"
|
||||
#include "llpointer.h"
|
||||
#include "llrefcount.h"
|
||||
#include "boost/function.hpp"
|
||||
#include "boost/shared_ptr.hpp"
|
||||
#include <string>
|
||||
|
||||
class LLSD;
|
||||
|
|
@ -156,16 +159,14 @@ namespace LLError
|
|||
mWantsFunctionName;
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<Recorder> RecorderPtr;
|
||||
|
||||
/**
|
||||
* @NOTE: addRecorder() conveys ownership to the underlying Settings
|
||||
* object -- when destroyed, it will @em delete the passed Recorder*!
|
||||
* @NOTE: addRecorder() and removeRecorder() uses the boost::shared_ptr to allow for shared ownership
|
||||
* while still ensuring that the allocated memory is eventually freed
|
||||
*/
|
||||
LL_COMMON_API void addRecorder(Recorder*);
|
||||
/**
|
||||
* @NOTE: removeRecorder() reclaims ownership of the Recorder*: its
|
||||
* lifespan becomes the caller's problem.
|
||||
*/
|
||||
LL_COMMON_API void removeRecorder(Recorder*);
|
||||
LL_COMMON_API void addRecorder(RecorderPtr);
|
||||
LL_COMMON_API void removeRecorder(RecorderPtr);
|
||||
// each error message is passed to each recorder via recordMessage()
|
||||
|
||||
LL_COMMON_API void logToFile(const std::string& filename);
|
||||
|
|
@ -182,9 +183,9 @@ namespace LLError
|
|||
Utilities for use by the unit tests of LLError itself.
|
||||
*/
|
||||
|
||||
class Settings;
|
||||
LL_COMMON_API Settings* saveAndResetSettings();
|
||||
LL_COMMON_API void restoreSettings(Settings *);
|
||||
typedef LLPointer<LLRefCount> SettingsStoragePtr;
|
||||
LL_COMMON_API SettingsStoragePtr saveAndResetSettings();
|
||||
LL_COMMON_API void restoreSettings(SettingsStoragePtr pSettingsStorage);
|
||||
|
||||
LL_COMMON_API std::string abbreviateFile(const std::string& filePath);
|
||||
LL_COMMON_API int shouldLogCallCount();
|
||||
|
|
|
|||
|
|
@ -1,89 +0,0 @@
|
|||
/**
|
||||
* @file llhttpstatuscodes.h
|
||||
* @brief Constants for HTTP status codes
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&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 LL_HTTP_STATUS_CODES_H
|
||||
#define LL_HTTP_STATUS_CODES_H
|
||||
|
||||
#include "stdtypes.h"
|
||||
|
||||
// Standard errors from HTTP spec:
|
||||
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1
|
||||
const S32 HTTP_CONTINUE = 100;
|
||||
const S32 HTTP_SWITCHING_PROTOCOLS = 101;
|
||||
|
||||
// Success
|
||||
const S32 HTTP_OK = 200;
|
||||
const S32 HTTP_CREATED = 201;
|
||||
const S32 HTTP_ACCEPTED = 202;
|
||||
const S32 HTTP_NON_AUTHORITATIVE_INFORMATION = 203;
|
||||
const S32 HTTP_NO_CONTENT = 204;
|
||||
const S32 HTTP_RESET_CONTENT = 205;
|
||||
const S32 HTTP_PARTIAL_CONTENT = 206;
|
||||
|
||||
// Redirection
|
||||
const S32 HTTP_MULTIPLE_CHOICES = 300;
|
||||
const S32 HTTP_MOVED_PERMANENTLY = 301;
|
||||
const S32 HTTP_FOUND = 302;
|
||||
const S32 HTTP_SEE_OTHER = 303;
|
||||
const S32 HTTP_NOT_MODIFIED = 304;
|
||||
const S32 HTTP_USE_PROXY = 305;
|
||||
const S32 HTTP_TEMPORARY_REDIRECT = 307;
|
||||
|
||||
// Client Error
|
||||
const S32 HTTP_BAD_REQUEST = 400;
|
||||
const S32 HTTP_UNAUTHORIZED = 401;
|
||||
const S32 HTTP_PAYMENT_REQUIRED = 402;
|
||||
const S32 HTTP_FORBIDDEN = 403;
|
||||
const S32 HTTP_NOT_FOUND = 404;
|
||||
const S32 HTTP_METHOD_NOT_ALLOWED = 405;
|
||||
const S32 HTTP_NOT_ACCEPTABLE = 406;
|
||||
const S32 HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;
|
||||
const S32 HTTP_REQUEST_TIME_OUT = 408;
|
||||
const S32 HTTP_CONFLICT = 409;
|
||||
const S32 HTTP_GONE = 410;
|
||||
const S32 HTTP_LENGTH_REQUIRED = 411;
|
||||
const S32 HTTP_PRECONDITION_FAILED = 412;
|
||||
const S32 HTTP_REQUEST_ENTITY_TOO_LARGE = 413;
|
||||
const S32 HTTP_REQUEST_URI_TOO_LARGE = 414;
|
||||
const S32 HTTP_UNSUPPORTED_MEDIA_TYPE = 415;
|
||||
const S32 HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
|
||||
const S32 HTTP_EXPECTATION_FAILED = 417;
|
||||
|
||||
// Server Error
|
||||
const S32 HTTP_INTERNAL_SERVER_ERROR = 500;
|
||||
const S32 HTTP_NOT_IMPLEMENTED = 501;
|
||||
const S32 HTTP_BAD_GATEWAY = 502;
|
||||
const S32 HTTP_SERVICE_UNAVAILABLE = 503;
|
||||
const S32 HTTP_GATEWAY_TIME_OUT = 504;
|
||||
const S32 HTTP_VERSION_NOT_SUPPORTED = 505;
|
||||
|
||||
// We combine internal process errors with status codes
|
||||
// These status codes should not be sent over the wire
|
||||
// and indicate something went wrong internally.
|
||||
// If you get these they are not normal.
|
||||
const S32 HTTP_INTERNAL_ERROR = 499;
|
||||
|
||||
#endif
|
||||
|
|
@ -31,6 +31,7 @@
|
|||
#include <vector>
|
||||
#include <list>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/is_enum.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
|
@ -630,7 +631,7 @@ namespace LLInitParam
|
|||
UserData* mUserData;
|
||||
};
|
||||
|
||||
typedef ParamDescriptor* ParamDescriptorPtr;
|
||||
typedef boost::shared_ptr<ParamDescriptor> ParamDescriptorPtr;
|
||||
|
||||
// each derived Block class keeps a static data structure maintaining offsets to various params
|
||||
class LL_COMMON_API BlockDescriptor
|
||||
|
|
|
|||
|
|
@ -166,6 +166,132 @@ protected:
|
|||
Type* mPointer;
|
||||
};
|
||||
|
||||
template <class Type> class LLConstPointer
|
||||
{
|
||||
public:
|
||||
LLConstPointer() :
|
||||
mPointer(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
LLConstPointer(const Type* ptr) :
|
||||
mPointer(ptr)
|
||||
{
|
||||
ref();
|
||||
}
|
||||
|
||||
LLConstPointer(const LLConstPointer<Type>& ptr) :
|
||||
mPointer(ptr.mPointer)
|
||||
{
|
||||
ref();
|
||||
}
|
||||
|
||||
// support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
|
||||
template<typename Subclass>
|
||||
LLConstPointer(const LLConstPointer<Subclass>& ptr) :
|
||||
mPointer(ptr.get())
|
||||
{
|
||||
ref();
|
||||
}
|
||||
|
||||
~LLConstPointer()
|
||||
{
|
||||
unref();
|
||||
}
|
||||
|
||||
const Type* get() const { return mPointer; }
|
||||
const Type* operator->() const { return mPointer; }
|
||||
const Type& operator*() const { return *mPointer; }
|
||||
|
||||
operator BOOL() const { return (mPointer != NULL); }
|
||||
operator bool() const { return (mPointer != NULL); }
|
||||
bool operator!() const { return (mPointer == NULL); }
|
||||
bool isNull() const { return (mPointer == NULL); }
|
||||
bool notNull() const { return (mPointer != NULL); }
|
||||
|
||||
operator const Type*() const { return mPointer; }
|
||||
bool operator !=(const Type* ptr) const { return (mPointer != ptr); }
|
||||
bool operator ==(const Type* ptr) const { return (mPointer == ptr); }
|
||||
bool operator ==(const LLConstPointer<Type>& ptr) const { return (mPointer == ptr.mPointer); }
|
||||
bool operator < (const LLConstPointer<Type>& ptr) const { return (mPointer < ptr.mPointer); }
|
||||
bool operator > (const LLConstPointer<Type>& ptr) const { return (mPointer > ptr.mPointer); }
|
||||
|
||||
LLConstPointer<Type>& operator =(const Type* ptr)
|
||||
{
|
||||
if( mPointer != ptr )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr;
|
||||
ref();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
LLConstPointer<Type>& operator =(const LLConstPointer<Type>& ptr)
|
||||
{
|
||||
if( mPointer != ptr.mPointer )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr.mPointer;
|
||||
ref();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
|
||||
template<typename Subclass>
|
||||
LLConstPointer<Type>& operator =(const LLConstPointer<Subclass>& ptr)
|
||||
{
|
||||
if( mPointer != ptr.get() )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr.get();
|
||||
ref();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Just exchange the pointers, which will not change the reference counts.
|
||||
static void swap(LLConstPointer<Type>& a, LLConstPointer<Type>& b)
|
||||
{
|
||||
const Type* temp = a.mPointer;
|
||||
a.mPointer = b.mPointer;
|
||||
b.mPointer = temp;
|
||||
}
|
||||
|
||||
protected:
|
||||
#ifdef LL_LIBRARY_INCLUDE
|
||||
void ref();
|
||||
void unref();
|
||||
#else
|
||||
void ref()
|
||||
{
|
||||
if (mPointer)
|
||||
{
|
||||
mPointer->ref();
|
||||
}
|
||||
}
|
||||
|
||||
void unref()
|
||||
{
|
||||
if (mPointer)
|
||||
{
|
||||
const Type *tempp = mPointer;
|
||||
mPointer = NULL;
|
||||
tempp->unref();
|
||||
if (mPointer != NULL)
|
||||
{
|
||||
LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL;
|
||||
unref();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
protected:
|
||||
const Type* mPointer;
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
class LLCopyOnWritePointer : public LLPointer<Type>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -126,7 +126,9 @@ public:
|
|||
virtual UUID asUUID() const { return LLUUID(); }
|
||||
virtual Date asDate() const { return LLDate(); }
|
||||
virtual URI asURI() const { return LLURI(); }
|
||||
virtual Binary asBinary() const { return std::vector<U8>(); }
|
||||
virtual const Binary& asBinary() const { static const std::vector<U8> empty; return empty; }
|
||||
|
||||
virtual const String& asStringRef() const { static const std::string empty; return empty; }
|
||||
|
||||
virtual bool has(const String&) const { return false; }
|
||||
virtual LLSD get(const String&) const { return LLSD(); }
|
||||
|
|
@ -270,6 +272,7 @@ namespace
|
|||
virtual LLSD::Date asDate() const { return LLDate(mValue); }
|
||||
virtual LLSD::URI asURI() const { return LLURI(mValue); }
|
||||
virtual int size() const { return mValue.size(); }
|
||||
virtual const LLSD::String& asStringRef() const { return mValue; }
|
||||
};
|
||||
|
||||
LLSD::Integer ImplString::asInteger() const
|
||||
|
|
@ -348,7 +351,7 @@ namespace
|
|||
public:
|
||||
ImplBinary(const LLSD::Binary& v) : Base(v) { }
|
||||
|
||||
virtual LLSD::Binary asBinary() const{ return mValue; }
|
||||
virtual const LLSD::Binary& asBinary() const{ return mValue; }
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -840,7 +843,9 @@ LLSD::String LLSD::asString() const { return safe(impl).asString(); }
|
|||
LLSD::UUID LLSD::asUUID() const { return safe(impl).asUUID(); }
|
||||
LLSD::Date LLSD::asDate() const { return safe(impl).asDate(); }
|
||||
LLSD::URI LLSD::asURI() const { return safe(impl).asURI(); }
|
||||
LLSD::Binary LLSD::asBinary() const { return safe(impl).asBinary(); }
|
||||
const LLSD::Binary& LLSD::asBinary() const { return safe(impl).asBinary(); }
|
||||
|
||||
const LLSD::String& LLSD::asStringRef() const { return safe(impl).asStringRef(); }
|
||||
|
||||
// const char * helpers
|
||||
LLSD::LLSD(const char* v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
|
||||
|
|
|
|||
|
|
@ -249,7 +249,10 @@ public:
|
|||
UUID asUUID() const;
|
||||
Date asDate() const;
|
||||
URI asURI() const;
|
||||
Binary asBinary() const;
|
||||
const Binary& asBinary() const;
|
||||
|
||||
// asStringRef on any non-string type will return a ref to an empty string.
|
||||
const String& asStringRef() const;
|
||||
|
||||
operator Boolean() const { return asBoolean(); }
|
||||
operator Integer() const { return asInteger(); }
|
||||
|
|
|
|||
|
|
@ -873,7 +873,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const
|
|||
{
|
||||
/**
|
||||
* Undefined: '!'<br>
|
||||
* Boolean: 't' for true 'f' for false<br>
|
||||
* Boolean: '1' for true '0' for false<br>
|
||||
* Integer: 'i' + 4 bytes network byte order<br>
|
||||
* Real: 'r' + 8 bytes IEEE double<br>
|
||||
* UUID: 'u' + 16 byte unsigned integer<br>
|
||||
|
|
@ -1260,13 +1260,38 @@ std::string LLSDNotationFormatter::escapeString(const std::string& in)
|
|||
|
||||
// virtual
|
||||
S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const
|
||||
{
|
||||
S32 rv = format_impl(data, ostr, options, 0);
|
||||
return rv;
|
||||
}
|
||||
|
||||
S32 LLSDNotationFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 options, U32 level) const
|
||||
{
|
||||
S32 format_count = 1;
|
||||
std::string pre;
|
||||
std::string post;
|
||||
|
||||
if (options & LLSDFormatter::OPTIONS_PRETTY)
|
||||
{
|
||||
for (U32 i = 0; i < level; i++)
|
||||
{
|
||||
pre += " ";
|
||||
}
|
||||
post = "\n";
|
||||
}
|
||||
|
||||
switch(data.type())
|
||||
{
|
||||
case LLSD::TypeMap:
|
||||
{
|
||||
if (0 != level) ostr << post << pre;
|
||||
ostr << "{";
|
||||
std::string inner_pre;
|
||||
if (options & LLSDFormatter::OPTIONS_PRETTY)
|
||||
{
|
||||
inner_pre = pre + " ";
|
||||
}
|
||||
|
||||
bool need_comma = false;
|
||||
LLSD::map_const_iterator iter = data.beginMap();
|
||||
LLSD::map_const_iterator end = data.endMap();
|
||||
|
|
@ -1274,18 +1299,18 @@ S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 opti
|
|||
{
|
||||
if(need_comma) ostr << ",";
|
||||
need_comma = true;
|
||||
ostr << '\'';
|
||||
ostr << post << inner_pre << '\'';
|
||||
serialize_string((*iter).first, ostr);
|
||||
ostr << "':";
|
||||
format_count += format((*iter).second, ostr);
|
||||
format_count += format_impl((*iter).second, ostr, options, level + 2);
|
||||
}
|
||||
ostr << "}";
|
||||
ostr << post << pre << "}";
|
||||
break;
|
||||
}
|
||||
|
||||
case LLSD::TypeArray:
|
||||
{
|
||||
ostr << "[";
|
||||
ostr << post << pre << "[";
|
||||
bool need_comma = false;
|
||||
LLSD::array_const_iterator iter = data.beginArray();
|
||||
LLSD::array_const_iterator end = data.endArray();
|
||||
|
|
@ -1293,7 +1318,7 @@ S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 opti
|
|||
{
|
||||
if(need_comma) ostr << ",";
|
||||
need_comma = true;
|
||||
format_count += format(*iter, ostr);
|
||||
format_count += format_impl(*iter, ostr, options, level + 1);
|
||||
}
|
||||
ostr << "]";
|
||||
break;
|
||||
|
|
@ -1343,7 +1368,7 @@ S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 opti
|
|||
|
||||
case LLSD::TypeString:
|
||||
ostr << '\'';
|
||||
serialize_string(data.asString(), ostr);
|
||||
serialize_string(data.asStringRef(), ostr);
|
||||
ostr << '\'';
|
||||
break;
|
||||
|
||||
|
|
@ -1360,9 +1385,26 @@ S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 opti
|
|||
case LLSD::TypeBinary:
|
||||
{
|
||||
// *FIX: memory inefficient.
|
||||
std::vector<U8> buffer = data.asBinary();
|
||||
const std::vector<U8>& buffer = data.asBinary();
|
||||
ostr << "b(" << buffer.size() << ")\"";
|
||||
if(buffer.size()) ostr.write((const char*)&buffer[0], buffer.size());
|
||||
if(buffer.size())
|
||||
{
|
||||
if (options & LLSDFormatter::OPTIONS_PRETTY_BINARY)
|
||||
{
|
||||
std::ios_base::fmtflags old_flags = ostr.flags();
|
||||
ostr.setf( std::ios::hex, std::ios::basefield );
|
||||
ostr << "0x";
|
||||
for (int i = 0; i < buffer.size(); i++)
|
||||
{
|
||||
ostr << (int) buffer[i];
|
||||
}
|
||||
ostr.flags(old_flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
ostr.write((const char*)&buffer[0], buffer.size());
|
||||
}
|
||||
}
|
||||
ostr << "\"";
|
||||
break;
|
||||
}
|
||||
|
|
@ -1460,7 +1502,7 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option
|
|||
|
||||
case LLSD::TypeString:
|
||||
ostr.put('s');
|
||||
formatString(data.asString(), ostr);
|
||||
formatString(data.asStringRef(), ostr);
|
||||
break;
|
||||
|
||||
case LLSD::TypeDate:
|
||||
|
|
@ -1478,9 +1520,8 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option
|
|||
|
||||
case LLSD::TypeBinary:
|
||||
{
|
||||
// *FIX: memory inefficient.
|
||||
ostr.put('b');
|
||||
std::vector<U8> buffer = data.asBinary();
|
||||
const std::vector<U8>& buffer = data.asBinary();
|
||||
U32 size_nbo = htonl(buffer.size());
|
||||
ostr.write((const char*)(&size_nbo), sizeof(U32));
|
||||
if(buffer.size()) ostr.write((const char*)&buffer[0], buffer.size());
|
||||
|
|
|
|||
|
|
@ -416,7 +416,8 @@ public:
|
|||
typedef enum e_formatter_options_type
|
||||
{
|
||||
OPTIONS_NONE = 0,
|
||||
OPTIONS_PRETTY = 1
|
||||
OPTIONS_PRETTY = 1,
|
||||
OPTIONS_PRETTY_BINARY = 2
|
||||
} EFormatterOptions;
|
||||
|
||||
/**
|
||||
|
|
@ -507,6 +508,17 @@ public:
|
|||
* @return Returns The number of LLSD objects fomatted out
|
||||
*/
|
||||
virtual S32 format(const LLSD& data, std::ostream& ostr, U32 options = LLSDFormatter::OPTIONS_NONE) const;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* @brief Implementation to format the data. This is called recursively.
|
||||
*
|
||||
* @param data The data to write.
|
||||
* @param ostr The destination stream for the data.
|
||||
* @return Returns The number of LLSD objects fomatted out
|
||||
*/
|
||||
S32 format_impl(const LLSD& data, std::ostream& ostr, U32 options, U32 level) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -634,7 +646,7 @@ protected:
|
|||
* </code>
|
||||
*
|
||||
* *NOTE - formerly this class inherited from its template parameter Formatter,
|
||||
* but all insnatiations passed in LLRefCount subclasses. This conflicted with
|
||||
* but all instantiations passed in LLRefCount subclasses. This conflicted with
|
||||
* the auto allocation intended for this class template (demonstrated in the
|
||||
* example above). -brad
|
||||
*/
|
||||
|
|
@ -720,6 +732,18 @@ public:
|
|||
LLPointer<LLSDNotationFormatter> f = new LLSDNotationFormatter;
|
||||
return f->format(sd, str, LLSDFormatter::OPTIONS_NONE);
|
||||
}
|
||||
static S32 toPrettyNotation(const LLSD& sd, std::ostream& str)
|
||||
{
|
||||
LLPointer<LLSDNotationFormatter> f = new LLSDNotationFormatter;
|
||||
return f->format(sd, str, LLSDFormatter::OPTIONS_PRETTY);
|
||||
}
|
||||
static S32 toPrettyBinaryNotation(const LLSD& sd, std::ostream& str)
|
||||
{
|
||||
LLPointer<LLSDNotationFormatter> f = new LLSDNotationFormatter;
|
||||
return f->format(sd, str,
|
||||
LLSDFormatter::OPTIONS_PRETTY |
|
||||
LLSDFormatter::OPTIONS_PRETTY_BINARY);
|
||||
}
|
||||
static S32 fromNotation(LLSD& sd, std::istream& str, S32 max_bytes)
|
||||
{
|
||||
LLPointer<LLSDNotationParser> p = new LLSDNotationParser;
|
||||
|
|
|
|||
|
|
@ -169,8 +169,8 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 opti
|
|||
break;
|
||||
|
||||
case LLSD::TypeString:
|
||||
if(data.asString().empty()) ostr << pre << "<string />" << post;
|
||||
else ostr << pre << "<string>" << escapeString(data.asString()) <<"</string>" << post;
|
||||
if(data.asStringRef().empty()) ostr << pre << "<string />" << post;
|
||||
else ostr << pre << "<string>" << escapeString(data.asStringRef()) <<"</string>" << post;
|
||||
break;
|
||||
|
||||
case LLSD::TypeDate:
|
||||
|
|
@ -183,7 +183,7 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 opti
|
|||
|
||||
case LLSD::TypeBinary:
|
||||
{
|
||||
LLSD::Binary buffer = data.asBinary();
|
||||
const LLSD::Binary& buffer = data.asBinary();
|
||||
if(buffer.empty())
|
||||
{
|
||||
ostr << pre << "<binary />" << post;
|
||||
|
|
@ -377,13 +377,10 @@ S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data)
|
|||
{
|
||||
break;
|
||||
}
|
||||
count = get_till_eol(input, (char *)buffer, BUFFER_SIZE);
|
||||
if (!count)
|
||||
{
|
||||
|
||||
count = get_till_eol(input, (char *)buffer, BUFFER_SIZE);
|
||||
if (!count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
status = XML_ParseBuffer(mParser, count, false);
|
||||
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ char* ll_pretty_print_sd_ptr(const LLSD* sd)
|
|||
|
||||
char* ll_pretty_print_sd(const LLSD& sd)
|
||||
{
|
||||
const U32 bufferSize = 10 * 1024;
|
||||
const U32 bufferSize = 100 * 1024;
|
||||
static char buffer[bufferSize];
|
||||
std::ostringstream stream;
|
||||
//stream.rdbuf()->pubsetbuf(buffer, bufferSize);
|
||||
|
|
|
|||
|
|
@ -132,10 +132,14 @@ public:
|
|||
};
|
||||
|
||||
typedef std::vector<LLUUID> uuid_vec_t;
|
||||
typedef std::set<LLUUID> uuid_set_t;
|
||||
|
||||
|
||||
// Helper structure for ordering lluuids in stl containers.
|
||||
// eg: std::map<LLUUID, LLWidget*, lluuid_less> widget_map;
|
||||
// Helper structure for ordering lluuids in stl containers. eg:
|
||||
// std::map<LLUUID, LLWidget*, lluuid_less> widget_map;
|
||||
//
|
||||
// (isn't this the default behavior anyway? I think we could
|
||||
// everywhere replace these with uuid_set_t, but someone should
|
||||
// verify.)
|
||||
struct lluuid_less
|
||||
{
|
||||
bool operator()(const LLUUID& lhs, const LLUUID& rhs) const
|
||||
|
|
@ -145,7 +149,6 @@ struct lluuid_less
|
|||
};
|
||||
|
||||
typedef std::set<LLUUID, lluuid_less> uuid_list_t;
|
||||
|
||||
/*
|
||||
* Sub-classes for keeping transaction IDs and asset IDs
|
||||
* straight.
|
||||
|
|
|
|||
|
|
@ -56,9 +56,9 @@ namespace tut
|
|||
{
|
||||
public:
|
||||
TestRecorder() { mWantsTime = false; }
|
||||
~TestRecorder() { LLError::removeRecorder(this); }
|
||||
virtual ~TestRecorder() { }
|
||||
|
||||
void recordMessage(LLError::ELevel level,
|
||||
virtual void recordMessage(LLError::ELevel level,
|
||||
const std::string& message)
|
||||
{
|
||||
mMessages.push_back(message);
|
||||
|
|
@ -85,15 +85,11 @@ namespace tut
|
|||
|
||||
struct ErrorTestData
|
||||
{
|
||||
// addRecorder() expects to be able to later delete the passed
|
||||
// Recorder*. Even though removeRecorder() reclaims ownership, passing
|
||||
// a pointer to a data member rather than a heap Recorder subclass
|
||||
// instance would just be Wrong.
|
||||
TestRecorder* mRecorder;
|
||||
LLError::Settings* mPriorErrorSettings;
|
||||
LLError::RecorderPtr mRecorder;
|
||||
LLError::SettingsStoragePtr mPriorErrorSettings;
|
||||
|
||||
ErrorTestData():
|
||||
mRecorder(new TestRecorder)
|
||||
mRecorder(new TestRecorder())
|
||||
{
|
||||
fatalWasCalled = false;
|
||||
|
||||
|
|
@ -106,13 +102,32 @@ namespace tut
|
|||
~ErrorTestData()
|
||||
{
|
||||
LLError::removeRecorder(mRecorder);
|
||||
delete mRecorder;
|
||||
LLError::restoreSettings(mPriorErrorSettings);
|
||||
}
|
||||
|
||||
int countMessages()
|
||||
{
|
||||
return boost::dynamic_pointer_cast<TestRecorder>(mRecorder)->countMessages();
|
||||
}
|
||||
|
||||
void clearMessages()
|
||||
{
|
||||
boost::dynamic_pointer_cast<TestRecorder>(mRecorder)->clearMessages();
|
||||
}
|
||||
|
||||
void setWantsTime(bool t)
|
||||
{
|
||||
boost::dynamic_pointer_cast<TestRecorder>(mRecorder)->setWantsTime(t);
|
||||
}
|
||||
|
||||
std::string message(int n)
|
||||
{
|
||||
return boost::dynamic_pointer_cast<TestRecorder>(mRecorder)->message(n);
|
||||
}
|
||||
|
||||
void ensure_message_count(int expectedCount)
|
||||
{
|
||||
ensure_equals("message count", mRecorder->countMessages(), expectedCount);
|
||||
ensure_equals("message count", countMessages(), expectedCount);
|
||||
}
|
||||
|
||||
void ensure_message_contains(int n, const std::string& expectedText)
|
||||
|
|
@ -120,7 +135,7 @@ namespace tut
|
|||
std::ostringstream test_name;
|
||||
test_name << "testing message " << n;
|
||||
|
||||
ensure_contains(test_name.str(), mRecorder->message(n), expectedText);
|
||||
ensure_contains(test_name.str(), message(n), expectedText);
|
||||
}
|
||||
|
||||
void ensure_message_does_not_contain(int n, const std::string& expectedText)
|
||||
|
|
@ -128,7 +143,7 @@ namespace tut
|
|||
std::ostringstream test_name;
|
||||
test_name << "testing message " << n;
|
||||
|
||||
ensure_does_not_contain(test_name.str(), mRecorder->message(n), expectedText);
|
||||
ensure_does_not_contain(test_name.str(), message(n), expectedText);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -385,15 +400,15 @@ namespace
|
|||
}
|
||||
|
||||
typedef std::string (*LogFromFunction)(bool);
|
||||
void testLogName(tut::TestRecorder* recorder, LogFromFunction f,
|
||||
void testLogName(LLError::RecorderPtr recorder, LogFromFunction f,
|
||||
const std::string& class_name = "")
|
||||
{
|
||||
recorder->clearMessages();
|
||||
boost::dynamic_pointer_cast<tut::TestRecorder>(recorder)->clearMessages();
|
||||
std::string name = f(false);
|
||||
f(true);
|
||||
|
||||
std::string messageWithoutName = recorder->message(0);
|
||||
std::string messageWithName = recorder->message(1);
|
||||
std::string messageWithoutName = boost::dynamic_pointer_cast<tut::TestRecorder>(recorder)->message(0);
|
||||
std::string messageWithName = boost::dynamic_pointer_cast<tut::TestRecorder>(recorder)->message(1);
|
||||
|
||||
ensure_has(name + " logged without name",
|
||||
messageWithoutName, name);
|
||||
|
|
@ -528,12 +543,12 @@ namespace tut
|
|||
{
|
||||
LLError::setTimeFunction(roswell);
|
||||
|
||||
mRecorder->setWantsTime(false);
|
||||
setWantsTime(false);
|
||||
ufoSighting();
|
||||
ensure_message_contains(0, "ufo");
|
||||
ensure_message_does_not_contain(0, roswell());
|
||||
|
||||
mRecorder->setWantsTime(true);
|
||||
setWantsTime(true);
|
||||
ufoSighting();
|
||||
ensure_message_contains(1, "ufo");
|
||||
ensure_message_contains(1, roswell());
|
||||
|
|
@ -545,13 +560,13 @@ namespace tut
|
|||
{
|
||||
LLError::setPrintLocation(true);
|
||||
LLError::setTimeFunction(roswell);
|
||||
mRecorder->setWantsTime(true);
|
||||
setWantsTime(true);
|
||||
std::string location,
|
||||
function;
|
||||
writeReturningLocationAndFunction(location, function);
|
||||
|
||||
ensure_equals("order is location time type function message",
|
||||
mRecorder->message(0),
|
||||
message(0),
|
||||
location + roswell() + " INFO: " + function + ": apple");
|
||||
}
|
||||
|
||||
|
|
@ -559,19 +574,19 @@ namespace tut
|
|||
// multiple recorders
|
||||
void ErrorTestObject::test<11>()
|
||||
{
|
||||
TestRecorder* altRecorder(new TestRecorder);
|
||||
LLError::RecorderPtr altRecorder(new TestRecorder());
|
||||
LLError::addRecorder(altRecorder);
|
||||
|
||||
LL_INFOS() << "boo" << LL_ENDL;
|
||||
|
||||
ensure_message_contains(0, "boo");
|
||||
ensure_equals("alt recorder count", altRecorder->countMessages(), 1);
|
||||
ensure_contains("alt recorder message 0", altRecorder->message(0), "boo");
|
||||
ensure_equals("alt recorder count", boost::dynamic_pointer_cast<TestRecorder>(altRecorder)->countMessages(), 1);
|
||||
ensure_contains("alt recorder message 0", boost::dynamic_pointer_cast<TestRecorder>(altRecorder)->message(0), "boo");
|
||||
|
||||
LLError::setTimeFunction(roswell);
|
||||
|
||||
TestRecorder* anotherRecorder(new TestRecorder);
|
||||
anotherRecorder->setWantsTime(true);
|
||||
LLError::RecorderPtr anotherRecorder(new TestRecorder());
|
||||
boost::dynamic_pointer_cast<TestRecorder>(anotherRecorder)->setWantsTime(true);
|
||||
LLError::addRecorder(anotherRecorder);
|
||||
|
||||
LL_INFOS() << "baz" << LL_ENDL;
|
||||
|
|
@ -579,10 +594,13 @@ namespace tut
|
|||
std::string when = roswell();
|
||||
|
||||
ensure_message_does_not_contain(1, when);
|
||||
ensure_equals("alt recorder count", altRecorder->countMessages(), 2);
|
||||
ensure_does_not_contain("alt recorder message 1", altRecorder->message(1), when);
|
||||
ensure_equals("another recorder count", anotherRecorder->countMessages(), 1);
|
||||
ensure_contains("another recorder message 0", anotherRecorder->message(0), when);
|
||||
ensure_equals("alt recorder count", boost::dynamic_pointer_cast<TestRecorder>(altRecorder)->countMessages(), 2);
|
||||
ensure_does_not_contain("alt recorder message 1", boost::dynamic_pointer_cast<TestRecorder>(altRecorder)->message(1), when);
|
||||
ensure_equals("another recorder count", boost::dynamic_pointer_cast<TestRecorder>(anotherRecorder)->countMessages(), 1);
|
||||
ensure_contains("another recorder message 0", boost::dynamic_pointer_cast<TestRecorder>(anotherRecorder)->message(0), when);
|
||||
|
||||
LLError::removeRecorder(altRecorder);
|
||||
LLError::removeRecorder(anotherRecorder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include "stringize.h"
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
|
@ -81,72 +82,29 @@ struct WrapLLErrs
|
|||
}
|
||||
|
||||
std::string error;
|
||||
LLError::Settings* mPriorErrorSettings;
|
||||
LLError::SettingsStoragePtr mPriorErrorSettings;
|
||||
LLError::FatalFunction mPriorFatal;
|
||||
};
|
||||
|
||||
/**
|
||||
* LLError::addRecorder() accepts ownership of the passed Recorder* -- it
|
||||
* expects to be able to delete it later. CaptureLog isa Recorder whose
|
||||
* pointer we want to be able to pass without any ownership implications.
|
||||
* For such cases, instantiate a new RecorderProxy(yourRecorder) and pass
|
||||
* that. Your heap RecorderProxy might later be deleted, but not yourRecorder.
|
||||
*/
|
||||
class RecorderProxy: public LLError::Recorder
|
||||
{
|
||||
public:
|
||||
RecorderProxy(LLError::Recorder* recorder):
|
||||
mRecorder(recorder)
|
||||
{}
|
||||
|
||||
virtual void recordMessage(LLError::ELevel level, const std::string& message)
|
||||
{
|
||||
mRecorder->recordMessage(level, message);
|
||||
}
|
||||
|
||||
virtual bool wantsTime()
|
||||
{
|
||||
return mRecorder->wantsTime();
|
||||
}
|
||||
|
||||
private:
|
||||
LLError::Recorder* mRecorder;
|
||||
};
|
||||
|
||||
/**
|
||||
* Capture log messages. This is adapted (simplified) from the one in
|
||||
* llerror_test.cpp.
|
||||
*/
|
||||
class CaptureLog : public LLError::Recorder, public boost::noncopyable
|
||||
class CaptureLogRecorder : public LLError::Recorder, public boost::noncopyable
|
||||
{
|
||||
public:
|
||||
CaptureLog(LLError::ELevel level=LLError::LEVEL_DEBUG):
|
||||
// Mostly what we're trying to accomplish by saving and resetting
|
||||
// LLError::Settings is to bypass the default RecordToStderr and
|
||||
// RecordToWinDebug Recorders. As these are visible only inside
|
||||
// llerror.cpp, we can't just call LLError::removeRecorder() with
|
||||
// each. For certain tests we need to produce, capture and examine
|
||||
// DEBUG log messages -- but we don't want to spam the user's console
|
||||
// with that output. If it turns out that saveAndResetSettings() has
|
||||
// some bad effect, give up and just let the DEBUG level log messages
|
||||
// display.
|
||||
mOldSettings(LLError::saveAndResetSettings()),
|
||||
mProxy(new RecorderProxy(this))
|
||||
CaptureLogRecorder()
|
||||
: LLError::Recorder(),
|
||||
boost::noncopyable(),
|
||||
mMessages()
|
||||
{
|
||||
LLError::setFatalFunction(wouldHaveCrashed);
|
||||
LLError::setDefaultLevel(level);
|
||||
LLError::addRecorder(mProxy);
|
||||
}
|
||||
|
||||
~CaptureLog()
|
||||
virtual ~CaptureLogRecorder()
|
||||
{
|
||||
LLError::removeRecorder(mProxy);
|
||||
delete mProxy;
|
||||
LLError::restoreSettings(mOldSettings);
|
||||
}
|
||||
|
||||
void recordMessage(LLError::ELevel level,
|
||||
const std::string& message)
|
||||
virtual void recordMessage(LLError::ELevel level, const std::string& message)
|
||||
{
|
||||
mMessages.push_back(message);
|
||||
}
|
||||
|
|
@ -154,7 +112,7 @@ public:
|
|||
/// Don't assume the message we want is necessarily the LAST log message
|
||||
/// emitted by the underlying code; search backwards through all messages
|
||||
/// for the sought string.
|
||||
std::string messageWith(const std::string& search, bool required=true)
|
||||
std::string messageWith(const std::string& search, bool required)
|
||||
{
|
||||
for (MessageList::const_reverse_iterator rmi(mMessages.rbegin()), rmend(mMessages.rend());
|
||||
rmi != rmend; ++rmi)
|
||||
|
|
@ -187,14 +145,63 @@ public:
|
|||
return out;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::list<std::string> MessageList;
|
||||
MessageList mMessages;
|
||||
LLError::Settings* mOldSettings;
|
||||
LLError::Recorder* mProxy;
|
||||
};
|
||||
|
||||
/**
|
||||
* Capture log messages. This is adapted (simplified) from the one in
|
||||
* llerror_test.cpp.
|
||||
*/
|
||||
class CaptureLog : public boost::noncopyable
|
||||
{
|
||||
public:
|
||||
CaptureLog(LLError::ELevel level=LLError::LEVEL_DEBUG)
|
||||
// Mostly what we're trying to accomplish by saving and resetting
|
||||
// LLError::Settings is to bypass the default RecordToStderr and
|
||||
// RecordToWinDebug Recorders. As these are visible only inside
|
||||
// llerror.cpp, we can't just call LLError::removeRecorder() with
|
||||
// each. For certain tests we need to produce, capture and examine
|
||||
// DEBUG log messages -- but we don't want to spam the user's console
|
||||
// with that output. If it turns out that saveAndResetSettings() has
|
||||
// some bad effect, give up and just let the DEBUG level log messages
|
||||
// display.
|
||||
: boost::noncopyable(),
|
||||
mOldSettings(LLError::saveAndResetSettings()),
|
||||
mRecorder(new CaptureLogRecorder())
|
||||
{
|
||||
LLError::setFatalFunction(wouldHaveCrashed);
|
||||
LLError::setDefaultLevel(level);
|
||||
LLError::addRecorder(mRecorder);
|
||||
}
|
||||
|
||||
~CaptureLog()
|
||||
{
|
||||
LLError::removeRecorder(mRecorder);
|
||||
LLError::restoreSettings(mOldSettings);
|
||||
}
|
||||
|
||||
/// Don't assume the message we want is necessarily the LAST log message
|
||||
/// emitted by the underlying code; search backwards through all messages
|
||||
/// for the sought string.
|
||||
std::string messageWith(const std::string& search, bool required=true)
|
||||
{
|
||||
return boost::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->messageWith(search, required);
|
||||
}
|
||||
|
||||
std::ostream& streamto(std::ostream& out) const
|
||||
{
|
||||
return boost::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->streamto(out);
|
||||
}
|
||||
|
||||
private:
|
||||
LLError::SettingsStoragePtr mOldSettings;
|
||||
LLError::RecorderPtr mRecorder;
|
||||
};
|
||||
|
||||
inline
|
||||
std::ostream& operator<<(std::ostream& out, const CaptureLog& log)
|
||||
std::ostream& operator<<(std::ostream& out, const CaptureLogRecorder& log)
|
||||
{
|
||||
return log.streamto(out);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
#include "_httpoprequest.h"
|
||||
#include "_httppolicy.h"
|
||||
|
||||
#include "llhttpstatuscodes.h"
|
||||
#include "llhttpconstants.h"
|
||||
|
||||
|
||||
namespace LLCore
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
#include "_httplibcurl.h"
|
||||
#include "_httpinternal.h"
|
||||
|
||||
#include "llhttpstatuscodes.h"
|
||||
#include "llhttpconstants.h"
|
||||
#include "llproxy.h"
|
||||
|
||||
namespace
|
||||
|
|
@ -531,6 +531,7 @@ 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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,17 +64,20 @@ std::string getStartupStateFromLog(std::string& sllog);
|
|||
|
||||
class LLCrashLoggerResponder : public LLHTTPClient::Responder
|
||||
{
|
||||
LOG_CLASS(LLCrashLoggerResponder);
|
||||
public:
|
||||
LLCrashLoggerResponder()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void error(U32 status, const std::string& reason)
|
||||
protected:
|
||||
virtual void httpFailure()
|
||||
{
|
||||
LL_WARNS() << dumpResponse() << LL_ENDL;
|
||||
gBreak = true;
|
||||
}
|
||||
|
||||
virtual void result(const LLSD& content)
|
||||
virtual void httpSuccess()
|
||||
{
|
||||
gBreak = true;
|
||||
gSent = true;
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ static const std::string INV_DESC_LABEL("desc");
|
|||
static const std::string INV_PERMISSIONS_LABEL("permissions");
|
||||
static const std::string INV_SHADOW_ID_LABEL("shadow_id");
|
||||
static const std::string INV_ASSET_ID_LABEL("asset_id");
|
||||
static const std::string INV_LINKED_ID_LABEL("linked_id");
|
||||
static const std::string INV_SALE_INFO_LABEL("sale_info");
|
||||
static const std::string INV_FLAGS_LABEL("flags");
|
||||
static const std::string INV_CREATION_DATE_LABEL("created_at");
|
||||
|
|
@ -257,13 +258,6 @@ BOOL LLInventoryObject::exportLegacyStream(std::ostream& output_stream, BOOL) co
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
void LLInventoryObject::removeFromServer()
|
||||
{
|
||||
// don't do nothin'
|
||||
LL_WARNS() << "LLInventoryObject::removeFromServer() called. Doesn't do anything." << LL_ENDL;
|
||||
}
|
||||
|
||||
void LLInventoryObject::updateParentOnServer(BOOL) const
|
||||
{
|
||||
// don't do nothin'
|
||||
|
|
@ -276,7 +270,7 @@ void LLInventoryObject::updateServer(BOOL) const
|
|||
LL_WARNS() << "LLInventoryObject::updateServer() called. Doesn't do anything." << LL_ENDL;
|
||||
}
|
||||
|
||||
//inline
|
||||
// static
|
||||
void LLInventoryObject::correctInventoryName(std::string& name)
|
||||
{
|
||||
LLStringUtil::replaceNonstandardASCII(name, ' ');
|
||||
|
|
@ -435,12 +429,17 @@ U32 LLInventoryItem::getCRC32() const
|
|||
return crc;
|
||||
}
|
||||
|
||||
// static
|
||||
void LLInventoryItem::correctInventoryDescription(std::string& desc)
|
||||
{
|
||||
LLStringUtil::replaceNonstandardASCII(desc, ' ');
|
||||
LLStringUtil::replaceChar(desc, '|', ' ');
|
||||
}
|
||||
|
||||
void LLInventoryItem::setDescription(const std::string& d)
|
||||
{
|
||||
std::string new_desc(d);
|
||||
LLStringUtil::replaceNonstandardASCII(new_desc, ' ');
|
||||
LLStringUtil::replaceChar(new_desc, '|', ' ');
|
||||
LLInventoryItem::correctInventoryDescription(new_desc);
|
||||
if( new_desc != mDescription )
|
||||
{
|
||||
disclaimMem(mDescription);
|
||||
|
|
@ -1174,11 +1173,16 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const
|
|||
|
||||
LLTrace::BlockTimerStatHandle FTM_INVENTORY_SD_DESERIALIZE("Inventory SD Deserialize");
|
||||
|
||||
bool LLInventoryItem::fromLLSD(const LLSD& sd)
|
||||
bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
|
||||
{
|
||||
LL_RECORD_BLOCK_TIME(FTM_INVENTORY_SD_DESERIALIZE);
|
||||
mInventoryType = LLInventoryType::IT_NONE;
|
||||
mAssetUUID.setNull();
|
||||
if (is_new)
|
||||
{
|
||||
// If we're adding LLSD to an existing object, need avoid
|
||||
// clobbering these fields.
|
||||
mInventoryType = LLInventoryType::IT_NONE;
|
||||
mAssetUUID.setNull();
|
||||
}
|
||||
std::string w;
|
||||
|
||||
w = INV_ITEM_ID_LABEL;
|
||||
|
|
@ -1235,6 +1239,11 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd)
|
|||
{
|
||||
mAssetUUID = sd[w];
|
||||
}
|
||||
w = INV_LINKED_ID_LABEL;
|
||||
if (sd.has(w))
|
||||
{
|
||||
mAssetUUID = sd[w];
|
||||
}
|
||||
w = INV_ASSET_TYPE_LABEL;
|
||||
if (sd.has(w))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ class LLInventoryObject : public LLRefCount, public LLTrace::MemTrackable<LLInve
|
|||
{
|
||||
public:
|
||||
typedef std::list<LLPointer<LLInventoryObject> > object_list_t;
|
||||
typedef std::list<LLConstPointer<LLInventoryObject> > const_object_list_t;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Initialization
|
||||
|
|
@ -86,26 +87,19 @@ public:
|
|||
void setType(LLAssetType::EType type);
|
||||
virtual void setCreationDate(time_t creation_date_utc); // only stored for items
|
||||
|
||||
// [RLVa:KB] - Checked: 2014-01-07 (RLVa-1.4.10)
|
||||
// in place correction for inventory name string
|
||||
static void correctInventoryName(std::string& name);
|
||||
// [/RLVa:KB]
|
||||
private:
|
||||
// // in place correction for inventory name string
|
||||
// void correctInventoryName(std::string& name);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// File Support
|
||||
// Implemented here so that a minimal information set can be transmitted
|
||||
// between simulator and viewer.
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
// virtual BOOL importFile(LLFILE* fp);
|
||||
virtual BOOL exportFile(LLFILE* fp, BOOL include_asset_key = TRUE) const;
|
||||
virtual BOOL importLegacyStream(std::istream& input_stream);
|
||||
virtual BOOL exportLegacyStream(std::ostream& output_stream, BOOL include_asset_key = TRUE) const;
|
||||
|
||||
virtual void removeFromServer();
|
||||
virtual void updateParentOnServer(BOOL) const;
|
||||
virtual void updateServer(BOOL) const;
|
||||
|
||||
|
|
@ -178,6 +172,7 @@ public:
|
|||
//--------------------------------------------------------------------
|
||||
public:
|
||||
void setAssetUUID(const LLUUID& asset_id);
|
||||
static void correctInventoryDescription(std::string& name);
|
||||
void setDescription(const std::string& new_desc);
|
||||
void setSaleInfo(const LLSaleInfo& sale_info);
|
||||
void setPermissions(const LLPermissions& perm);
|
||||
|
|
@ -216,7 +211,7 @@ public:
|
|||
void unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size);
|
||||
LLSD asLLSD() const;
|
||||
void asLLSD( LLSD& sd ) const;
|
||||
bool fromLLSD(const LLSD& sd);
|
||||
bool fromLLSD(const LLSD& sd, bool is_new = true);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Member Variables
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ set(llmessage_SOURCE_FILES
|
|||
llhttpassetstorage.cpp
|
||||
llhttpclient.cpp
|
||||
llhttpclientadapter.cpp
|
||||
llhttpconstants.cpp
|
||||
llhttpnode.cpp
|
||||
llhttpsender.cpp
|
||||
llinstantmessage.cpp
|
||||
|
|
@ -63,7 +64,6 @@ set(llmessage_SOURCE_FILES
|
|||
llmessagetemplate.cpp
|
||||
llmessagetemplateparser.cpp
|
||||
llmessagethrottle.cpp
|
||||
llmime.cpp
|
||||
llnamevalue.cpp
|
||||
llnullcipher.cpp
|
||||
llpacketack.cpp
|
||||
|
|
@ -72,7 +72,6 @@ set(llmessage_SOURCE_FILES
|
|||
llpartdata.cpp
|
||||
llproxy.cpp
|
||||
llpumpio.cpp
|
||||
llregionpresenceverifier.cpp
|
||||
llsdappservices.cpp
|
||||
llsdhttpserver.cpp
|
||||
llsdmessage.cpp
|
||||
|
|
@ -142,6 +141,7 @@ set(llmessage_HEADER_FILES
|
|||
llhttpclient.h
|
||||
llhttpclientinterface.h
|
||||
llhttpclientadapter.h
|
||||
llhttpconstants.h
|
||||
llhttpnode.h
|
||||
llhttpnodeadapter.h
|
||||
llhttpsender.h
|
||||
|
|
@ -160,7 +160,6 @@ set(llmessage_HEADER_FILES
|
|||
llmessagetemplate.h
|
||||
llmessagetemplateparser.h
|
||||
llmessagethrottle.h
|
||||
llmime.h
|
||||
llmsgvariabletype.h
|
||||
llnamevalue.h
|
||||
llnullcipher.h
|
||||
|
|
@ -173,7 +172,6 @@ set(llmessage_HEADER_FILES
|
|||
llqueryflags.h
|
||||
llregionflags.h
|
||||
llregionhandle.h
|
||||
llregionpresenceverifier.h
|
||||
llsdappservices.h
|
||||
llsdhttpserver.h
|
||||
llsdmessage.h
|
||||
|
|
@ -237,17 +235,15 @@ target_link_libraries(
|
|||
# tests
|
||||
if (LL_TESTS)
|
||||
SET(llmessage_TEST_SOURCE_FILES
|
||||
# llhttpclientadapter.cpp
|
||||
llmime.cpp
|
||||
llnamevalue.cpp
|
||||
lltrustedmessageservice.cpp
|
||||
lltemplatemessagedispatcher.cpp
|
||||
llregionpresenceverifier.cpp
|
||||
)
|
||||
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}
|
||||
|
|
@ -274,6 +270,7 @@ if (LL_TESTS)
|
|||
|
||||
LL_ADD_INTEGRATION_TEST(llavatarnamecache "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(llhost "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(llhttpclientadapter "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(llpartdata "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(llxfer_file "" "${test_libs}")
|
||||
endif (LL_TESTS)
|
||||
|
|
|
|||
|
|
@ -647,6 +647,15 @@ LLAres *ll_init_ares()
|
|||
return gAres;
|
||||
}
|
||||
|
||||
void ll_cleanup_ares()
|
||||
{
|
||||
if (gAres != NULL)
|
||||
{
|
||||
delete gAres;
|
||||
gAres = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
LLDnsRecord::LLDnsRecord(LLResType type, const std::string &name,
|
||||
unsigned ttl)
|
||||
: LLRefCount(),
|
||||
|
|
|
|||
|
|
@ -578,5 +578,6 @@ extern LLAres *gAres;
|
|||
* thread safe.
|
||||
*/
|
||||
extern LLAres *ll_init_ares();
|
||||
extern void ll_cleanup_ares();
|
||||
|
||||
#endif // LL_LLARES_H
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ namespace LLAvatarNameCache
|
|||
// Erase expired names from cache
|
||||
void eraseUnrefreshed();
|
||||
|
||||
bool expirationFromCacheControl(LLSD headers, F64 *expires);
|
||||
bool expirationFromCacheControl(const LLSD& headers, F64 *expires);
|
||||
}
|
||||
|
||||
/* Sample response:
|
||||
|
|
@ -171,33 +171,31 @@ namespace LLAvatarNameCache
|
|||
|
||||
class LLAvatarNameResponder : public LLHTTPClient::Responder
|
||||
{
|
||||
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:
|
||||
LLSD mHeaders;
|
||||
|
||||
public:
|
||||
LLAvatarNameResponder(const std::vector<LLUUID>& agent_ids)
|
||||
: mAgentIDs(agent_ids),
|
||||
mHeaders()
|
||||
: mAgentIDs(agent_ids)
|
||||
{ }
|
||||
|
||||
/*virtual*/ void completedHeader(U32 status, const std::string& reason,
|
||||
const LLSD& headers)
|
||||
{
|
||||
mHeaders = headers;
|
||||
}
|
||||
|
||||
/*virtual*/ void result(const LLSD& content)
|
||||
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(mHeaders);
|
||||
F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(getResponseHeaders());
|
||||
F64 now = LLFrameTimer::getTotalSeconds();
|
||||
|
||||
LLSD agents = content["agents"];
|
||||
const LLSD& agents = content["agents"];
|
||||
LLSD::array_const_iterator it = agents.beginArray();
|
||||
for ( ; it != agents.endArray(); ++it)
|
||||
{
|
||||
|
|
@ -218,7 +216,7 @@ public:
|
|||
}
|
||||
|
||||
// Same logic as error response case
|
||||
LLSD unresolved_agents = content["bad_ids"];
|
||||
const LLSD& unresolved_agents = content["bad_ids"];
|
||||
S32 num_unresolved = unresolved_agents.size();
|
||||
if (num_unresolved > 0)
|
||||
{
|
||||
|
|
@ -242,14 +240,13 @@ public:
|
|||
<< LL_ENDL;
|
||||
}
|
||||
|
||||
/*virtual*/ void error(U32 status, const std::string& reason)
|
||||
/*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::error " << status << " " << reason
|
||||
<< 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();
|
||||
|
|
@ -762,7 +759,7 @@ void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_na
|
|||
sCache[agent_id] = av_name;
|
||||
}
|
||||
|
||||
F64 LLAvatarNameCache::nameExpirationFromHeaders(LLSD headers)
|
||||
F64 LLAvatarNameCache::nameExpirationFromHeaders(const LLSD& headers)
|
||||
{
|
||||
const F64 DEFAULT_EXPIRES = 60.0 * 60.0 + LLFrameTimer::getTotalSeconds();
|
||||
|
||||
|
|
@ -782,17 +779,21 @@ F64 LLAvatarNameCache::nameExpirationFromHeaders(LLSD headers)
|
|||
}
|
||||
}
|
||||
|
||||
bool LLAvatarNameCache::expirationFromCacheControl(LLSD headers, F64 *expires)
|
||||
bool LLAvatarNameCache::expirationFromCacheControl(const LLSD& headers, F64 *expires)
|
||||
{
|
||||
bool fromCacheControl = false;
|
||||
F64 now = LLFrameTimer::getTotalSeconds();
|
||||
|
||||
// Allow the header to override the default
|
||||
LLSD cache_control_header = headers["cache-control"];
|
||||
if (cache_control_header.isDefined())
|
||||
std::string cache_control;
|
||||
if (headers.has(HTTP_IN_HEADER_CACHE_CONTROL))
|
||||
{
|
||||
cache_control = headers[HTTP_IN_HEADER_CACHE_CONTROL].asString();
|
||||
}
|
||||
|
||||
if (!cache_control.empty())
|
||||
{
|
||||
S32 max_age = 0;
|
||||
std::string cache_control = cache_control_header.asString();
|
||||
if (max_age_from_cache_control(cache_control, &max_age))
|
||||
{
|
||||
*expires = now + (F64)max_age;
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ namespace LLAvatarNameCache
|
|||
|
||||
// Compute name expiration time from HTTP Cache-Control header,
|
||||
// or return default value, in seconds from epoch.
|
||||
F64 nameExpirationFromHeaders(LLSD headers);
|
||||
F64 nameExpirationFromHeaders(const LLSD& headers);
|
||||
|
||||
void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@
|
|||
#include "llproxy.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llstl.h"
|
||||
#include "llstring.h"
|
||||
#include "llthread.h"
|
||||
#include "lltimer.h"
|
||||
|
||||
|
|
@ -100,7 +101,7 @@ void check_curl_code(CURLcode code)
|
|||
{
|
||||
// linux appears to throw a curl error once per session for a bad initialization
|
||||
// at a pretty random time (when enabling cookies).
|
||||
LL_INFOS() << "curl error detected: " << curl_easy_strerror(code) << LL_ENDL;
|
||||
LL_WARNS("curl") << "curl error detected: " << curl_easy_strerror(code) << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -110,7 +111,7 @@ void check_curl_multi_code(CURLMcode code)
|
|||
{
|
||||
// linux appears to throw a curl error once per session for a bad initialization
|
||||
// at a pretty random time (when enabling cookies).
|
||||
LL_INFOS() << "curl multi error detected: " << curl_multi_strerror(code) << LL_ENDL;
|
||||
LL_WARNS("curl") << "curl multi error detected: " << curl_multi_strerror(code) << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -135,6 +136,7 @@ std::string LLCurl::getVersionString()
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LLCurl::Responder::Responder()
|
||||
: mHTTPMethod(HTTP_INVALID), mStatus(HTTP_INTERNAL_ERROR)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -144,22 +146,30 @@ LLCurl::Responder::~Responder()
|
|||
}
|
||||
|
||||
// virtual
|
||||
void LLCurl::Responder::errorWithContent(
|
||||
U32 status,
|
||||
const std::string& reason,
|
||||
const LLSD&)
|
||||
void LLCurl::Responder::httpFailure()
|
||||
{
|
||||
error(status, reason);
|
||||
LL_WARNS("curl") << dumpResponse() << LL_ENDL;
|
||||
}
|
||||
|
||||
std::string LLCurl::Responder::dumpResponse() const
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << "[" << httpMethodAsVerb(mHTTPMethod) << ":" << mURL << "] "
|
||||
<< "[status:" << mStatus << "] "
|
||||
<< "[reason:" << mReason << "] ";
|
||||
|
||||
if (mResponseHeaders.has(HTTP_IN_HEADER_CONTENT_TYPE))
|
||||
{
|
||||
s << "[content-type:" << mResponseHeaders[HTTP_IN_HEADER_CONTENT_TYPE] << "] ";
|
||||
}
|
||||
|
||||
s << "[content:" << mContent << "]";
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLCurl::Responder::error(U32 status, const std::string& reason)
|
||||
{
|
||||
LL_INFOS() << mURL << " [" << status << "]: " << reason << LL_ENDL;
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLCurl::Responder::result(const LLSD& content)
|
||||
void LLCurl::Responder::httpSuccess()
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -168,51 +178,114 @@ void LLCurl::Responder::setURL(const std::string& url)
|
|||
mURL = url;
|
||||
}
|
||||
|
||||
void LLCurl::Responder::successResult(const LLSD& content)
|
||||
{
|
||||
setResult(HTTP_OK, "", content);
|
||||
httpSuccess();
|
||||
}
|
||||
|
||||
void LLCurl::Responder::failureResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */)
|
||||
{
|
||||
setResult(status, reason, content);
|
||||
httpFailure();
|
||||
}
|
||||
|
||||
void LLCurl::Responder::completeResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */)
|
||||
{
|
||||
setResult(status, reason, content);
|
||||
httpCompleted();
|
||||
}
|
||||
|
||||
void LLCurl::Responder::setResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */)
|
||||
{
|
||||
mStatus = status;
|
||||
mReason = reason;
|
||||
mContent = content;
|
||||
}
|
||||
|
||||
void LLCurl::Responder::setHTTPMethod(EHTTPMethod method)
|
||||
{
|
||||
mHTTPMethod = method;
|
||||
}
|
||||
|
||||
void LLCurl::Responder::setResponseHeader(const std::string& header, const std::string& value)
|
||||
{
|
||||
mResponseHeaders[header] = value;
|
||||
}
|
||||
|
||||
const std::string& LLCurl::Responder::getResponseHeader(const std::string& header) const
|
||||
{
|
||||
if (mResponseHeaders.has(header))
|
||||
{
|
||||
return mResponseHeaders[header].asStringRef();
|
||||
}
|
||||
static const std::string empty;
|
||||
return empty;
|
||||
}
|
||||
|
||||
bool LLCurl::Responder::hasResponseHeader(const std::string& header) const
|
||||
{
|
||||
if (mResponseHeaders.has(header)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLCurl::Responder::completedRaw(
|
||||
U32 status,
|
||||
const std::string& reason,
|
||||
const LLChannelDescriptors& channels,
|
||||
const LLIOPipe::buffer_ptr_t& buffer)
|
||||
{
|
||||
LLSD content;
|
||||
LLBufferStream istr(channels, buffer.get());
|
||||
const bool emit_errors = false;
|
||||
if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(content, istr, emit_errors))
|
||||
{
|
||||
LL_INFOS() << "Failed to deserialize LLSD. " << mURL << " [" << status << "]: " << reason << LL_ENDL;
|
||||
content["reason"] = reason;
|
||||
const bool emit_parse_errors = false;
|
||||
|
||||
// <Techwolf Lupindo> pass parse error down code path
|
||||
mDeserializeError = false;
|
||||
|
||||
std::string debug_body("(empty)");
|
||||
bool parsed=true;
|
||||
if (EOF == istr.peek())
|
||||
{
|
||||
parsed=false;
|
||||
}
|
||||
// Try to parse body as llsd, no matter what 'content-type' says.
|
||||
else if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(mContent, istr, emit_parse_errors))
|
||||
{
|
||||
parsed=false;
|
||||
char body[1025];
|
||||
body[1024] = '\0';
|
||||
istr.seekg(0, std::ios::beg);
|
||||
istr.get(body,1024);
|
||||
if (strlen(body) > 0)
|
||||
{
|
||||
mContent = body;
|
||||
debug_body = body;
|
||||
}
|
||||
// <Techwolf Lupindo> pass parse error down code path
|
||||
mDeserializeError = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mDeserializeError = false;
|
||||
}
|
||||
// </Techwolf Lupindo>
|
||||
|
||||
completed(status, reason, content);
|
||||
// Only emit a warning if we failed to parse when 'content-type' == 'application/llsd+xml'
|
||||
if (!parsed && (HTTP_CONTENT_LLSD_XML == getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE)))
|
||||
{
|
||||
LL_WARNS() << "Failed to deserialize . " << mURL << " [status:" << mStatus << "] "
|
||||
<< "(" << mReason << ") body: " << debug_body << LL_ENDL;
|
||||
}
|
||||
|
||||
httpCompleted();
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLCurl::Responder::completed(U32 status, const std::string& reason, const LLSD& content)
|
||||
void LLCurl::Responder::httpCompleted()
|
||||
{
|
||||
if (isGoodStatus(status))
|
||||
if (isGoodStatus())
|
||||
{
|
||||
result(content);
|
||||
httpSuccess();
|
||||
}
|
||||
else
|
||||
{
|
||||
errorWithContent(status, reason, content);
|
||||
httpFailure();
|
||||
}
|
||||
}
|
||||
|
||||
//virtual
|
||||
void LLCurl::Responder::completedHeader(U32 status, const std::string& reason, const LLSD& content)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::set<CURL*> LLCurl::Easy::sFreeHandles;
|
||||
|
|
@ -292,6 +365,36 @@ void LLCurl::Easy::releaseEasyHandle(CURL* handle)
|
|||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLCurl::Easy::deleteAllActiveHandles()
|
||||
{
|
||||
LLMutexLock lock(sHandleMutexp) ;
|
||||
LL_CHECK_MEMORY
|
||||
for (std::set<CURL*>::iterator activeHandle = sActiveHandles.begin(); activeHandle != sActiveHandles.end(); ++activeHandle)
|
||||
{
|
||||
CURL* curlHandle = *activeHandle;
|
||||
LLCurl::deleteEasyHandle(curlHandle);
|
||||
LL_CHECK_MEMORY
|
||||
}
|
||||
|
||||
sFreeHandles.clear();
|
||||
}
|
||||
|
||||
//static
|
||||
void LLCurl::Easy::deleteAllFreeHandles()
|
||||
{
|
||||
LLMutexLock lock(sHandleMutexp) ;
|
||||
LL_CHECK_MEMORY
|
||||
for (std::set<CURL*>::iterator freeHandle = sFreeHandles.begin(); freeHandle != sFreeHandles.end(); ++freeHandle)
|
||||
{
|
||||
CURL* curlHandle = *freeHandle;
|
||||
LLCurl::deleteEasyHandle(curlHandle);
|
||||
LL_CHECK_MEMORY
|
||||
}
|
||||
|
||||
sFreeHandles.clear();
|
||||
}
|
||||
|
||||
LLCurl::Easy::Easy()
|
||||
: mHeaders(NULL),
|
||||
mCurlEasyHandle(NULL)
|
||||
|
|
@ -307,7 +410,8 @@ LLCurl::Easy* LLCurl::Easy::getEasy()
|
|||
if (!easy->mCurlEasyHandle)
|
||||
{
|
||||
// this can happen if we have too many open files (fails in c-ares/ares_init.c)
|
||||
LL_WARNS() << "allocEasyHandle() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << LL_ENDL;
|
||||
LL_WARNS("curl") << "allocEasyHandle() returned NULL! Easy handles: "
|
||||
<< gCurlEasyCount << " Multi handles: " << gCurlMultiCount << LL_ENDL;
|
||||
delete easy;
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -344,10 +448,14 @@ LLCurl::Easy::~Easy()
|
|||
for_each(mStrings.begin(), mStrings.end(), DeletePointerArray());
|
||||
LL_CHECK_MEMORY
|
||||
if (mResponder && LLCurl::sNotQuitting) //aborted
|
||||
{
|
||||
std::string reason("Request timeout, aborted.") ;
|
||||
mResponder->completedRaw(408, //HTTP_REQUEST_TIME_OUT, timeout, abort
|
||||
reason, mChannels, mOutput);
|
||||
{
|
||||
// HTTP_REQUEST_TIME_OUT, timeout, abort
|
||||
// *TODO: This looks like improper use of the 408 status code.
|
||||
// See: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.9
|
||||
// This status code should be returned by the *server* when:
|
||||
// "The client did not produce a request within the time that the server was prepared to wait."
|
||||
mResponder->setResult(HTTP_REQUEST_TIME_OUT, "Request timeout, aborted.");
|
||||
mResponder->completedRaw(mChannels, mOutput);
|
||||
LL_CHECK_MEMORY
|
||||
}
|
||||
mResponder = NULL;
|
||||
|
|
@ -411,10 +519,10 @@ void LLCurl::Easy::getTransferInfo(LLCurl::TransferInfo* info)
|
|||
check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SPEED_DOWNLOAD, &info->mSpeedDownload));
|
||||
}
|
||||
|
||||
U32 LLCurl::Easy::report(CURLcode code)
|
||||
S32 LLCurl::Easy::report(CURLcode code)
|
||||
{
|
||||
// <FS:ND> Curl wants a long, not a U32. This can be a difference.
|
||||
// U32 responseCode = 0;
|
||||
// <FS:ND> Curl wants a long, not a S32. This can be a difference.
|
||||
// S32 responseCode = 0;
|
||||
long responseCode = 0;
|
||||
// <FS:ND>
|
||||
|
||||
|
|
@ -427,14 +535,15 @@ U32 LLCurl::Easy::report(CURLcode code)
|
|||
}
|
||||
else
|
||||
{
|
||||
responseCode = 499;
|
||||
responseCode = HTTP_INTERNAL_ERROR;
|
||||
responseReason = strerror(code) + " : " + mErrorBuffer;
|
||||
setopt(CURLOPT_FRESH_CONNECT, TRUE);
|
||||
}
|
||||
|
||||
if (mResponder)
|
||||
{
|
||||
mResponder->completedRaw(responseCode, responseReason, mChannels, mOutput);
|
||||
mResponder->setResult(responseCode, responseReason);
|
||||
mResponder->completedRaw(mChannels, mOutput);
|
||||
mResponder = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -471,9 +580,31 @@ void LLCurl::Easy::setoptString(CURLoption option, const std::string& value)
|
|||
check_curl_code(result);
|
||||
}
|
||||
|
||||
void LLCurl::Easy::slist_append(const std::string& header, const std::string& value)
|
||||
{
|
||||
std::string pair(header);
|
||||
if (value.empty())
|
||||
{
|
||||
pair += ":";
|
||||
}
|
||||
else
|
||||
{
|
||||
pair += ": ";
|
||||
pair += value;
|
||||
}
|
||||
slist_append(pair.c_str());
|
||||
}
|
||||
|
||||
void LLCurl::Easy::slist_append(const char* str)
|
||||
{
|
||||
mHeaders = curl_slist_append(mHeaders, str);
|
||||
if (str)
|
||||
{
|
||||
mHeaders = curl_slist_append(mHeaders, str);
|
||||
if (!mHeaders)
|
||||
{
|
||||
LL_WARNS() << "curl_slist_append() call returned NULL appending " << str << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t curlReadCallback(char* data, size_t size, size_t nmemb, void* user_data)
|
||||
|
|
@ -561,8 +692,9 @@ void LLCurl::Easy::prepRequest(const std::string& url,
|
|||
|
||||
if (!post)
|
||||
{
|
||||
slist_append("Connection: keep-alive");
|
||||
slist_append("Keep-alive: 300");
|
||||
// *TODO: Should this be set to 'Keep-Alive' ?
|
||||
slist_append(HTTP_OUT_HEADER_CONNECTION, "keep-alive");
|
||||
slist_append(HTTP_OUT_HEADER_KEEP_ALIVE, "300");
|
||||
// Accept and other headers
|
||||
for (std::vector<std::string>::const_iterator iter = headers.begin();
|
||||
iter != headers.end(); ++iter)
|
||||
|
|
@ -845,7 +977,7 @@ S32 LLCurl::Multi::process()
|
|||
++processed;
|
||||
if (msg->msg == CURLMSG_DONE)
|
||||
{
|
||||
U32 response = 0;
|
||||
S32 response = 0;
|
||||
Easy* easy = NULL ;
|
||||
|
||||
{
|
||||
|
|
@ -864,7 +996,7 @@ S32 LLCurl::Multi::process()
|
|||
}
|
||||
else
|
||||
{
|
||||
response = 499;
|
||||
response = HTTP_INTERNAL_ERROR;
|
||||
//*TODO: change to LL_WARNS()
|
||||
LL_ERRS() << "cleaned up curl request completed!" << LL_ENDL;
|
||||
}
|
||||
|
|
@ -1170,13 +1302,13 @@ bool LLCurlRequest::getByteRange(const std::string& url,
|
|||
easy->setopt(CURLOPT_HTTPGET, 1);
|
||||
if (length > 0)
|
||||
{
|
||||
std::string range = llformat("Range: bytes=%d-%d", offset,offset+length-1);
|
||||
easy->slist_append(range.c_str());
|
||||
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("Range: bytes=%d-", offset);
|
||||
easy->slist_append(range.c_str());
|
||||
std::string range = llformat("bytes=%d-", offset);
|
||||
easy->slist_append(HTTP_OUT_HEADER_RANGE, range);
|
||||
}
|
||||
easy->setHeaders();
|
||||
bool res = addEasy(easy);
|
||||
|
|
@ -1203,7 +1335,7 @@ bool LLCurlRequest::post(const std::string& url,
|
|||
easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
|
||||
easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
|
||||
|
||||
easy->slist_append("Content-Type: application/llsd+xml");
|
||||
easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML);
|
||||
easy->setHeaders();
|
||||
|
||||
LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL;
|
||||
|
|
@ -1231,7 +1363,7 @@ bool LLCurlRequest::post(const std::string& url,
|
|||
easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
|
||||
easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
|
||||
|
||||
easy->slist_append("Content-Type: application/octet-stream");
|
||||
easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_OCTET_STREAM);
|
||||
easy->setHeaders();
|
||||
|
||||
LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL;
|
||||
|
|
@ -1603,6 +1735,14 @@ void LLCurlEasyRequest::setSSLCtxCallback(curl_ssl_ctx_callback callback, void*
|
|||
}
|
||||
}
|
||||
|
||||
void LLCurlEasyRequest::slist_append(const std::string& header, const std::string& value)
|
||||
{
|
||||
if (isValid() && mEasy)
|
||||
{
|
||||
mEasy->slist_append(header, value);
|
||||
}
|
||||
}
|
||||
|
||||
void LLCurlEasyRequest::slist_append(const char* str)
|
||||
{
|
||||
if (isValid() && mEasy)
|
||||
|
|
@ -1787,17 +1927,14 @@ void LLCurl::cleanupClass()
|
|||
#endif
|
||||
|
||||
LL_CHECK_MEMORY
|
||||
|
||||
for (std::set<CURL*>::iterator iter = Easy::sFreeHandles.begin(); iter != Easy::sFreeHandles.end(); ++iter)
|
||||
{
|
||||
CURL* curl = *iter;
|
||||
LLCurl::deleteEasyHandle(curl);
|
||||
}
|
||||
|
||||
Easy::deleteAllFreeHandles();
|
||||
LL_CHECK_MEMORY
|
||||
Easy::deleteAllActiveHandles();
|
||||
LL_CHECK_MEMORY
|
||||
|
||||
Easy::sFreeHandles.clear();
|
||||
|
||||
// Free the template easy handle
|
||||
curl_easy_cleanup(sCurlTemplateStandardHandle);
|
||||
sCurlTemplateStandardHandle = NULL;
|
||||
LL_CHECK_MEMORY
|
||||
|
||||
delete Easy::sHandleMutexp ;
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include <curl/curl.h> // TODO: remove dependency
|
||||
|
||||
#include "llbuffer.h"
|
||||
#include "llhttpconstants.h"
|
||||
#include "lliopipe.h"
|
||||
#include "llsd.h"
|
||||
#include "llqueuedthread.h"
|
||||
|
|
@ -76,63 +77,96 @@ public:
|
|||
Responder();
|
||||
virtual ~Responder();
|
||||
|
||||
virtual bool followRedir()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief return true if the status code indicates success.
|
||||
*/
|
||||
static bool isGoodStatus(U32 status)
|
||||
{
|
||||
return((200 <= status) && (status < 300));
|
||||
}
|
||||
|
||||
virtual void errorWithContent(
|
||||
U32 status,
|
||||
const std::string& reason,
|
||||
const LLSD& content);
|
||||
//< called by completed() on bad status
|
||||
bool isGoodStatus() const { return isHttpGoodStatus(mStatus); }
|
||||
|
||||
virtual void error(U32 status, const std::string& reason);
|
||||
//< called by default error(status, reason, content)
|
||||
|
||||
virtual void result(const LLSD& content);
|
||||
//< called by completed for good status codes.
|
||||
S32 getStatus() const { return mStatus; }
|
||||
const std::string& getReason() const { return mReason; }
|
||||
const LLSD& getContent() const { return mContent; }
|
||||
bool hasResponseHeader(const std::string& header) const;
|
||||
const std::string& getResponseHeader(const std::string& header) const;
|
||||
const LLSD& getResponseHeaders() const { return mResponseHeaders; }
|
||||
const std::string& getURL() const { return mURL; }
|
||||
EHTTPMethod getHTTPMethod() const { return mHTTPMethod; }
|
||||
|
||||
// This formats response information for use in log spam. Includes content spam.
|
||||
std::string dumpResponse() const;
|
||||
|
||||
// Allows direct triggering of success/error with different results.
|
||||
void completeResult(S32 status, const std::string& reason, const LLSD& content = LLSD());
|
||||
void successResult(const LLSD& content);
|
||||
void failureResult(S32 status, const std::string& reason, const LLSD& content = LLSD());
|
||||
|
||||
// The default implementation will try to parse body content as an LLSD, however
|
||||
// it should not spam about parsing failures unless the server sent a
|
||||
// Content-Type: application/llsd+xml header.
|
||||
virtual void completedRaw(
|
||||
U32 status,
|
||||
const std::string& reason,
|
||||
const LLChannelDescriptors& channels,
|
||||
const LLIOPipe::buffer_ptr_t& buffer);
|
||||
/**< Override point for clients that may want to use this
|
||||
class when the response is some other format besides LLSD
|
||||
*/
|
||||
|
||||
virtual void completed(
|
||||
U32 status,
|
||||
const std::string& reason,
|
||||
const LLSD& content);
|
||||
/**< The default implemetnation calls
|
||||
either:
|
||||
* result(), or
|
||||
* error()
|
||||
*/
|
||||
|
||||
// Override to handle parsing of the header only. Note: this is the only place where the contents
|
||||
// of the header can be parsed. In the ::completed call above only the body is contained in the LLSD.
|
||||
virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content);
|
||||
|
||||
// Used internally to set the url for debugging later.
|
||||
void setURL(const std::string& url);
|
||||
// The http* methods are not public since these should be triggered internally
|
||||
// after status, reason, content, etc have been set.
|
||||
// If you need to trigger a completion method, use the *Result methods, above.
|
||||
protected:
|
||||
// These methods are the preferred way to process final results.
|
||||
// By default, when one of these is called the following information will be resolved:
|
||||
// * HTTP status code - getStatus()
|
||||
// * Reason string - getReason()
|
||||
// * Content - getContent()
|
||||
// * Response Headers - getResponseHeaders()
|
||||
|
||||
virtual bool followRedir()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// By default, httpSuccess is triggered whenever httpCompleted is called with a 2xx status code.
|
||||
virtual void httpSuccess();
|
||||
//< called by completed for good status codes.
|
||||
|
||||
// By default, httpFailure is triggered whenever httpCompleted is called with a non-2xx status code.
|
||||
virtual void httpFailure();
|
||||
//< called by httpCompleted() on bad status
|
||||
|
||||
// httpCompleted does not generally need to be overridden, unless
|
||||
// you don't care about the status code (which determine httpFailure or httpSuccess)
|
||||
// or if you want to re-interpret what a 'good' vs' bad' status code is.
|
||||
virtual void httpCompleted();
|
||||
/**< The default implementation calls
|
||||
either:
|
||||
* httpSuccess(), or
|
||||
* httpFailure()
|
||||
*/
|
||||
|
||||
public:
|
||||
void setHTTPMethod(EHTTPMethod method);
|
||||
void setURL(const std::string& url);
|
||||
void setResult(S32 status, const std::string& reason, const LLSD& content = LLSD());
|
||||
void setResponseHeader(const std::string& header, const std::string& value);
|
||||
|
||||
// <Techwolf Lupindo> pass parse error down code path
|
||||
bool mDeserializeError;
|
||||
// </Techwolf Lupindo>
|
||||
|
||||
private:
|
||||
// These can be accessed by the get* methods. Treated as 'read-only' during completion handlers.
|
||||
EHTTPMethod mHTTPMethod;
|
||||
std::string mURL;
|
||||
LLSD mResponseHeaders;
|
||||
|
||||
protected:
|
||||
// These should also generally be treated as 'read-only' during completion handlers
|
||||
// and should be accessed by the get* methods. The exception to this rule would
|
||||
// be when overriding the completedRaw method in preparation for calling httpCompleted().
|
||||
S32 mStatus;
|
||||
std::string mReason;
|
||||
LLSD mContent;
|
||||
};
|
||||
typedef LLPointer<Responder> ResponderPtr;
|
||||
|
||||
|
|
@ -231,10 +265,11 @@ public:
|
|||
// Copies the string so that it is guaranteed to stick around
|
||||
void setoptString(CURLoption option, const std::string& value);
|
||||
|
||||
void slist_append(const std::string& header, const std::string& value);
|
||||
void slist_append(const char* str);
|
||||
void setHeaders();
|
||||
|
||||
U32 report(CURLcode);
|
||||
S32 report(CURLcode);
|
||||
void getTransferInfo(LLCurl::TransferInfo* info);
|
||||
|
||||
void prepRequest(const std::string& url, const std::vector<std::string>& headers, LLCurl::ResponderPtr, S32 time_out = 0, bool post = false);
|
||||
|
|
@ -273,6 +308,9 @@ private:
|
|||
static std::set<CURL*> sFreeHandles;
|
||||
static std::set<CURL*> sActiveHandles;
|
||||
static LLMutex* sHandleMutexp ;
|
||||
|
||||
static void deleteAllActiveHandles();
|
||||
static void deleteAllFreeHandles();
|
||||
};
|
||||
|
||||
class LLCurl::Multi
|
||||
|
|
@ -498,6 +536,7 @@ public:
|
|||
void setWriteCallback(curl_write_callback callback, void* userdata);
|
||||
void setReadCallback(curl_read_callback callback, void* userdata);
|
||||
void setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata);
|
||||
void slist_append(const std::string& header, const std::string& value);
|
||||
void slist_append(const char* str);
|
||||
void sendRequest(const std::string& url);
|
||||
void requestComplete();
|
||||
|
|
|
|||
|
|
@ -54,13 +54,6 @@ const F32 GET_URL_TO_FILE_TIMEOUT = 1800.0f;
|
|||
|
||||
const S32 COMPRESSED_INPUT_BUFFER_SIZE = 4096;
|
||||
|
||||
const S32 HTTP_OK = 200;
|
||||
const S32 HTTP_PUT_OK = 201;
|
||||
const S32 HTTP_NO_CONTENT = 204;
|
||||
const S32 HTTP_MISSING = 404;
|
||||
const S32 HTTP_SERVER_BAD_GATEWAY = 502;
|
||||
const S32 HTTP_SERVER_TEMP_UNAVAILABLE = 503;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// LLTempAssetData
|
||||
// An asset not stored on central asset store, but on a simulator node somewhere.
|
||||
|
|
@ -955,7 +948,7 @@ void LLHTTPAssetStorage::checkForTimeouts()
|
|||
{
|
||||
if (curl_msg->data.result == CURLE_OK &&
|
||||
( curl_result == HTTP_OK
|
||||
|| curl_result == HTTP_PUT_OK
|
||||
|| curl_result == HTTP_CREATED
|
||||
|| curl_result == HTTP_NO_CONTENT))
|
||||
{
|
||||
LL_INFOS() << "Success uploading " << req->getUUID() << " to " << req->mURLBuffer << LL_ENDL;
|
||||
|
|
@ -966,8 +959,8 @@ void LLHTTPAssetStorage::checkForTimeouts()
|
|||
}
|
||||
else if (curl_msg->data.result == CURLE_COULDNT_CONNECT ||
|
||||
curl_msg->data.result == CURLE_OPERATION_TIMEOUTED ||
|
||||
curl_result == HTTP_SERVER_BAD_GATEWAY ||
|
||||
curl_result == HTTP_SERVER_TEMP_UNAVAILABLE)
|
||||
curl_result == HTTP_BAD_GATEWAY ||
|
||||
curl_result == HTTP_SERVICE_UNAVAILABLE)
|
||||
{
|
||||
LL_WARNS() << "Re-requesting upload for " << req->getUUID() << ". Received upload error to " << req->mURLBuffer <<
|
||||
" with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << LL_ENDL;
|
||||
|
|
@ -988,8 +981,8 @@ void LLHTTPAssetStorage::checkForTimeouts()
|
|||
|
||||
if (!(curl_msg->data.result == CURLE_COULDNT_CONNECT ||
|
||||
curl_msg->data.result == CURLE_OPERATION_TIMEOUTED ||
|
||||
curl_result == HTTP_SERVER_BAD_GATEWAY ||
|
||||
curl_result == HTTP_SERVER_TEMP_UNAVAILABLE))
|
||||
curl_result == HTTP_BAD_GATEWAY ||
|
||||
curl_result == HTTP_SERVICE_UNAVAILABLE))
|
||||
{
|
||||
// shared upload finished callback
|
||||
// in the base class, this is called from processUploadComplete
|
||||
|
|
@ -1021,7 +1014,7 @@ void LLHTTPAssetStorage::checkForTimeouts()
|
|||
LL_WARNS() << "Failure downloading " << req->mURLBuffer <<
|
||||
" with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << LL_ENDL;
|
||||
|
||||
xfer_result = (curl_result == HTTP_MISSING) ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED;
|
||||
xfer_result = (curl_result == HTTP_NOT_FOUND) ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED;
|
||||
|
||||
if (req->mVFile)
|
||||
{
|
||||
|
|
@ -1243,7 +1236,7 @@ S32 LLHTTPAssetStorage::getURLToFile(const LLUUID& uuid, LLAssetType::EType asse
|
|||
}
|
||||
else
|
||||
{
|
||||
xfer_result = curl_result == HTTP_MISSING ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED;
|
||||
xfer_result = curl_result == HTTP_NOT_FOUND ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED;
|
||||
LL_INFOS() << "Failure downloading " << req.mURLBuffer <<
|
||||
" with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << LL_ENDL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ namespace
|
|||
{
|
||||
public:
|
||||
LLHTTPClientURLAdaptor(LLCurl::ResponderPtr responder)
|
||||
: LLURLRequestComplete(), mResponder(responder), mStatus(499),
|
||||
: LLURLRequestComplete(), mResponder(responder), mStatus(HTTP_INTERNAL_ERROR),
|
||||
mReason("LLURLRequest complete w/no status")
|
||||
{
|
||||
}
|
||||
|
|
@ -63,7 +63,7 @@ namespace
|
|||
{
|
||||
}
|
||||
|
||||
virtual void httpStatus(U32 status, const std::string& reason)
|
||||
virtual void httpStatus(S32 status, const std::string& reason)
|
||||
{
|
||||
LLURLRequestComplete::httpStatus(status,reason);
|
||||
|
||||
|
|
@ -74,30 +74,33 @@ namespace
|
|||
virtual void complete(const LLChannelDescriptors& channels,
|
||||
const buffer_ptr_t& buffer)
|
||||
{
|
||||
// *TODO: Re-interpret mRequestStatus codes?
|
||||
// Would like to detect curl errors, such as
|
||||
// connection errors, write erros, etc.
|
||||
if (mResponder.get())
|
||||
{
|
||||
// Allow clients to parse headers before we attempt to parse
|
||||
// the body and provide completed/result/error calls.
|
||||
mResponder->completedHeader(mStatus, mReason, mHeaderOutput);
|
||||
mResponder->completedRaw(mStatus, mReason, channels, buffer);
|
||||
mResponder->setResult(mStatus, mReason);
|
||||
mResponder->completedRaw(channels, buffer);
|
||||
}
|
||||
}
|
||||
virtual void header(const std::string& header, const std::string& value)
|
||||
{
|
||||
mHeaderOutput[header] = value;
|
||||
if (mResponder.get())
|
||||
{
|
||||
mResponder->setResponseHeader(header, value);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
LLCurl::ResponderPtr mResponder;
|
||||
U32 mStatus;
|
||||
S32 mStatus;
|
||||
std::string mReason;
|
||||
LLSD mHeaderOutput;
|
||||
};
|
||||
|
||||
class Injector : public LLIOPipe
|
||||
{
|
||||
public:
|
||||
virtual const char* contentType() = 0;
|
||||
virtual const std::string& contentType() = 0;
|
||||
};
|
||||
|
||||
class LLSDInjector : public Injector
|
||||
|
|
@ -106,7 +109,7 @@ namespace
|
|||
LLSDInjector(const LLSD& sd) : mSD(sd) {}
|
||||
virtual ~LLSDInjector() {}
|
||||
|
||||
const char* contentType() { return "application/llsd+xml"; }
|
||||
const std::string& contentType() { return HTTP_CONTENT_LLSD_XML; }
|
||||
|
||||
virtual EStatus process_impl(const LLChannelDescriptors& channels,
|
||||
buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump)
|
||||
|
|
@ -124,12 +127,9 @@ namespace
|
|||
{
|
||||
public:
|
||||
RawInjector(const U8* data, S32 size) : mData(data), mSize(size) {}
|
||||
// <FS> Memleak fix by Sovereign Engineer
|
||||
//virtual ~RawInjector() {delete mData;}
|
||||
virtual ~RawInjector() {delete [] mData;}
|
||||
// </FS>
|
||||
|
||||
const char* contentType() { return "application/octet-stream"; }
|
||||
const std::string& contentType() { return HTTP_CONTENT_OCTET_STREAM; }
|
||||
|
||||
virtual EStatus process_impl(const LLChannelDescriptors& channels,
|
||||
buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump)
|
||||
|
|
@ -150,7 +150,7 @@ namespace
|
|||
FileInjector(const std::string& filename) : mFilename(filename) {}
|
||||
virtual ~FileInjector() {}
|
||||
|
||||
const char* contentType() { return "application/octet-stream"; }
|
||||
const std::string& contentType() { return HTTP_CONTENT_OCTET_STREAM; }
|
||||
|
||||
virtual EStatus process_impl(const LLChannelDescriptors& channels,
|
||||
buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump)
|
||||
|
|
@ -183,7 +183,7 @@ namespace
|
|||
VFileInjector(const LLUUID& uuid, LLAssetType::EType asset_type) : mUUID(uuid), mAssetType(asset_type) {}
|
||||
virtual ~VFileInjector() {}
|
||||
|
||||
const char* contentType() { return "application/octet-stream"; }
|
||||
const std::string& contentType() { return HTTP_CONTENT_OCTET_STREAM; }
|
||||
|
||||
virtual EStatus process_impl(const LLChannelDescriptors& channels,
|
||||
buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump)
|
||||
|
|
@ -216,7 +216,7 @@ void LLHTTPClient::setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback cal
|
|||
|
||||
static void request(
|
||||
const std::string& url,
|
||||
LLURLRequest::ERequestAction method,
|
||||
EHTTPMethod method,
|
||||
Injector* body_injector,
|
||||
LLCurl::ResponderPtr responder,
|
||||
const F32 timeout = HTTP_REQUEST_EXPIRY_SECS,
|
||||
|
|
@ -229,7 +229,7 @@ static void request(
|
|||
{
|
||||
if (responder)
|
||||
{
|
||||
responder->completed(U32_MAX, "No pump", LLSD());
|
||||
responder->completeResult(HTTP_INTERNAL_ERROR, "No pump");
|
||||
}
|
||||
delete body_injector;
|
||||
return;
|
||||
|
|
@ -241,48 +241,44 @@ static void request(
|
|||
{
|
||||
if (responder)
|
||||
{
|
||||
responder->completed(498, "Internal Error - curl failure", LLSD());
|
||||
responder->completeResult(HTTP_INTERNAL_CURL_ERROR, "Internal Error - curl failure");
|
||||
}
|
||||
delete req ;
|
||||
delete req;
|
||||
delete body_injector;
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
|
||||
req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req);
|
||||
|
||||
|
||||
LL_DEBUGS() << LLURLRequest::actionAsVerb(method) << " " << url << " "
|
||||
<< headers << LL_ENDL;
|
||||
LL_DEBUGS("LLHTTPClient") << httpMethodAsVerb(method) << " " << url << " " << headers << LL_ENDL;
|
||||
|
||||
// Insert custom headers if the caller sent any
|
||||
if (headers.isMap())
|
||||
{
|
||||
if (headers.has("Cookie"))
|
||||
if (headers.has(HTTP_OUT_HEADER_COOKIE))
|
||||
{
|
||||
req->allowCookies();
|
||||
}
|
||||
|
||||
LLSD::map_const_iterator iter = headers.beginMap();
|
||||
LLSD::map_const_iterator end = headers.endMap();
|
||||
LLSD::map_const_iterator iter = headers.beginMap();
|
||||
LLSD::map_const_iterator end = headers.endMap();
|
||||
|
||||
for (; iter != end; ++iter)
|
||||
{
|
||||
std::ostringstream header;
|
||||
//if the header is "Pragma" with no value
|
||||
//the caller intends to force libcurl to drop
|
||||
//the Pragma header it so gratuitously inserts
|
||||
//Before inserting the header, force libcurl
|
||||
//to not use the proxy (read: llurlrequest.cpp)
|
||||
static const std::string PRAGMA("Pragma");
|
||||
if ((iter->first == PRAGMA) && (iter->second.asString().empty()))
|
||||
{
|
||||
req->useProxy(false);
|
||||
}
|
||||
header << iter->first << ": " << iter->second.asString() ;
|
||||
LL_DEBUGS() << "header = " << header.str() << LL_ENDL;
|
||||
req->addHeader(header.str().c_str());
|
||||
}
|
||||
}
|
||||
for (; iter != end; ++iter)
|
||||
{
|
||||
//if the header is "Pragma" with no value
|
||||
//the caller intends to force libcurl to drop
|
||||
//the Pragma header it so gratuitously inserts
|
||||
//Before inserting the header, force libcurl
|
||||
//to not use the proxy (read: llurlrequest.cpp)
|
||||
if ((iter->first == HTTP_OUT_HEADER_PRAGMA) && (iter->second.asString().empty()))
|
||||
{
|
||||
req->useProxy(false);
|
||||
}
|
||||
LL_DEBUGS("LLHTTPClient") << "header = " << iter->first
|
||||
<< ": " << iter->second.asString() << LL_ENDL;
|
||||
req->addHeader(iter->first, iter->second.asString());
|
||||
}
|
||||
}
|
||||
|
||||
if(if_modified_since)
|
||||
{
|
||||
|
|
@ -292,44 +288,40 @@ static void request(
|
|||
// Check to see if we have already set Accept or not. If no one
|
||||
// set it, set it to application/llsd+xml since that's what we
|
||||
// almost always want.
|
||||
if( method != LLURLRequest::HTTP_PUT && method != LLURLRequest::HTTP_POST )
|
||||
if( method != HTTP_PUT && method != HTTP_POST )
|
||||
{
|
||||
static const std::string ACCEPT("Accept");
|
||||
if(!headers.has(ACCEPT))
|
||||
if(!headers.has(HTTP_OUT_HEADER_ACCEPT))
|
||||
{
|
||||
req->addHeader("Accept: application/llsd+xml");
|
||||
req->addHeader(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_LLSD_XML);
|
||||
}
|
||||
}
|
||||
|
||||
if (responder)
|
||||
{
|
||||
responder->setURL(url);
|
||||
responder->setHTTPMethod(method);
|
||||
}
|
||||
|
||||
req->setCallback(new LLHTTPClientURLAdaptor(responder));
|
||||
|
||||
if (method == LLURLRequest::HTTP_POST && gMessageSystem)
|
||||
if (method == HTTP_POST && gMessageSystem)
|
||||
{
|
||||
req->addHeader(llformat("X-SecondLife-UDP-Listen-Port: %d",
|
||||
gMessageSystem->mPort).c_str());
|
||||
}
|
||||
req->addHeader("X-SecondLife-UDP-Listen-Port", llformat("%d",
|
||||
gMessageSystem->mPort));
|
||||
}
|
||||
|
||||
if (method == LLURLRequest::HTTP_PUT || method == LLURLRequest::HTTP_POST)
|
||||
if (method == HTTP_PUT || method == HTTP_POST || method == HTTP_PATCH)
|
||||
{
|
||||
static const std::string CONTENT_TYPE("Content-Type");
|
||||
if(!headers.has(CONTENT_TYPE))
|
||||
if(!headers.has(HTTP_OUT_HEADER_CONTENT_TYPE))
|
||||
{
|
||||
// If the Content-Type header was passed in, it has
|
||||
// already been added as a header through req->addHeader
|
||||
// in the loop above. We defer to the caller's wisdom, but
|
||||
// if they did not specify a Content-Type, then ask the
|
||||
// injector.
|
||||
req->addHeader(
|
||||
llformat(
|
||||
"Content-Type: %s",
|
||||
body_injector->contentType()).c_str());
|
||||
req->addHeader(HTTP_OUT_HEADER_CONTENT_TYPE, body_injector->contentType());
|
||||
}
|
||||
chain.push_back(LLIOPipe::ptr_t(body_injector));
|
||||
chain.push_back(LLIOPipe::ptr_t(body_injector));
|
||||
}
|
||||
|
||||
chain.push_back(LLIOPipe::ptr_t(req));
|
||||
|
|
@ -351,9 +343,9 @@ void LLHTTPClient::getByteRange(
|
|||
if(offset > 0 || bytes > 0)
|
||||
{
|
||||
std::string range = llformat("bytes=%d-%d", offset, offset+bytes-1);
|
||||
headers["Range"] = range;
|
||||
headers[HTTP_OUT_HEADER_RANGE] = range;
|
||||
}
|
||||
request(url,LLURLRequest::HTTP_GET, NULL, responder, timeout, headers, follow_redirects);
|
||||
request(url,HTTP_GET, NULL, responder, timeout, headers, follow_redirects);
|
||||
}
|
||||
|
||||
void LLHTTPClient::head(
|
||||
|
|
@ -363,25 +355,25 @@ void LLHTTPClient::head(
|
|||
const F32 timeout,
|
||||
bool follow_redirects /* = true */)
|
||||
{
|
||||
request(url, LLURLRequest::HTTP_HEAD, NULL, responder, timeout, headers, follow_redirects);
|
||||
request(url, HTTP_HEAD, NULL, responder, timeout, headers, follow_redirects);
|
||||
}
|
||||
|
||||
void LLHTTPClient::get(const std::string& url, ResponderPtr responder, const LLSD& headers, const F32 timeout,
|
||||
bool follow_redirects /* = true */)
|
||||
{
|
||||
request(url, LLURLRequest::HTTP_GET, NULL, responder, timeout, headers, follow_redirects);
|
||||
request(url, HTTP_GET, NULL, responder, timeout, headers, follow_redirects);
|
||||
}
|
||||
// <FS:AW> opensim
|
||||
void LLHTTPClient::getIfModified(const std::string& url, ResponderPtr responder, const time_t &if_modified_since, const LLSD& headers, const F32 timeout)
|
||||
{
|
||||
request(url, LLURLRequest::HTTP_GET, NULL, responder, timeout, headers, true, if_modified_since);
|
||||
request(url, HTTP_GET, NULL, responder, timeout, headers, true, if_modified_since);
|
||||
}
|
||||
// <FS:AW> opensim
|
||||
|
||||
void LLHTTPClient::getHeaderOnly(const std::string& url, ResponderPtr responder, const LLSD& headers,
|
||||
const F32 timeout, bool follow_redirects /* = true */)
|
||||
{
|
||||
request(url, LLURLRequest::HTTP_HEAD, NULL, responder, timeout, headers, follow_redirects);
|
||||
request(url, HTTP_HEAD, NULL, responder, timeout, headers, follow_redirects);
|
||||
}
|
||||
void LLHTTPClient::getHeaderOnly(const std::string& url, ResponderPtr responder, const F32 timeout,
|
||||
bool follow_redirects /* = true */)
|
||||
|
|
@ -424,7 +416,7 @@ public:
|
|||
return content;
|
||||
}
|
||||
|
||||
std::string asString()
|
||||
const std::string& asString()
|
||||
{
|
||||
return mBuffer;
|
||||
}
|
||||
|
|
@ -453,7 +445,7 @@ private:
|
|||
*/
|
||||
static LLSD blocking_request(
|
||||
const std::string& url,
|
||||
LLURLRequest::ERequestAction method,
|
||||
EHTTPMethod method,
|
||||
const LLSD& body,
|
||||
const LLSD& headers = LLSD(),
|
||||
const F32 timeout = 5
|
||||
|
|
@ -496,11 +488,11 @@ static LLSD blocking_request(
|
|||
}
|
||||
|
||||
// * Setup specific method / "verb" for the URI (currently only GET and POST supported + poppy)
|
||||
if (method == LLURLRequest::HTTP_GET)
|
||||
if (method == HTTP_GET)
|
||||
{
|
||||
curl_easy_setopt(curlp, CURLOPT_HTTPGET, 1);
|
||||
}
|
||||
else if (method == LLURLRequest::HTTP_POST)
|
||||
else if (method == HTTP_POST)
|
||||
{
|
||||
curl_easy_setopt(curlp, CURLOPT_POST, 1);
|
||||
//serialize to ostr then copy to str - need to because ostr ptr is unstable :(
|
||||
|
|
@ -509,18 +501,20 @@ static LLSD blocking_request(
|
|||
body_str = ostr.str();
|
||||
curl_easy_setopt(curlp, CURLOPT_POSTFIELDS, body_str.c_str());
|
||||
//copied from PHP libs, correct?
|
||||
headers_list = curl_slist_append(headers_list, "Content-Type: application/llsd+xml");
|
||||
headers_list = curl_slist_append(headers_list,
|
||||
llformat("%s: %s", HTTP_OUT_HEADER_CONTENT_TYPE.c_str(), HTTP_CONTENT_LLSD_XML.c_str()).c_str());
|
||||
|
||||
// copied from llurlrequest.cpp
|
||||
// it appears that apache2.2.3 or django in etch is busted. If
|
||||
// we do not clear the expect header, we get a 500. May be
|
||||
// limited to django/mod_wsgi.
|
||||
headers_list = curl_slist_append(headers_list, "Expect:");
|
||||
headers_list = curl_slist_append(headers_list, llformat("%s:", HTTP_OUT_HEADER_EXPECT.c_str()).c_str());
|
||||
}
|
||||
|
||||
// * Do the action using curl, handle results
|
||||
LL_DEBUGS() << "HTTP body: " << body_str << LL_ENDL;
|
||||
headers_list = curl_slist_append(headers_list, "Accept: application/llsd+xml");
|
||||
headers_list = curl_slist_append(headers_list,
|
||||
llformat("%s: %s", HTTP_OUT_HEADER_ACCEPT.c_str(), HTTP_CONTENT_LLSD_XML.c_str()).c_str());
|
||||
CURLcode curl_result = curl_easy_setopt(curlp, CURLOPT_HTTPHEADER, headers_list);
|
||||
if ( curl_result != CURLE_OK )
|
||||
{
|
||||
|
|
@ -529,11 +523,11 @@ static LLSD blocking_request(
|
|||
|
||||
LLSD response = LLSD::emptyMap();
|
||||
S32 curl_success = curl_easy_perform(curlp);
|
||||
S32 http_status = 499;
|
||||
S32 http_status = HTTP_INTERNAL_ERROR;
|
||||
curl_easy_getinfo(curlp, CURLINFO_RESPONSE_CODE, &http_status);
|
||||
response["status"] = http_status;
|
||||
// if we get a non-404 and it's not a 200 OR maybe it is but you have error bits,
|
||||
if ( http_status != 404 && (http_status != 200 || curl_success != 0) )
|
||||
if ( http_status != HTTP_NOT_FOUND && (http_status != HTTP_OK || curl_success != 0) )
|
||||
{
|
||||
// We expect 404s, don't spam for them.
|
||||
LL_WARNS() << "CURL REQ URL: " << url << LL_ENDL;
|
||||
|
|
@ -563,12 +557,12 @@ static LLSD blocking_request(
|
|||
|
||||
LLSD LLHTTPClient::blockingGet(const std::string& url)
|
||||
{
|
||||
return blocking_request(url, LLURLRequest::HTTP_GET, LLSD());
|
||||
return blocking_request(url, HTTP_GET, LLSD());
|
||||
}
|
||||
|
||||
LLSD LLHTTPClient::blockingPost(const std::string& url, const LLSD& body)
|
||||
{
|
||||
return blocking_request(url, LLURLRequest::HTTP_POST, body);
|
||||
return blocking_request(url, HTTP_POST, body);
|
||||
}
|
||||
|
||||
void LLHTTPClient::put(
|
||||
|
|
@ -578,7 +572,17 @@ void LLHTTPClient::put(
|
|||
const LLSD& headers,
|
||||
const F32 timeout)
|
||||
{
|
||||
request(url, LLURLRequest::HTTP_PUT, new LLSDInjector(body), responder, timeout, headers);
|
||||
request(url, HTTP_PUT, new LLSDInjector(body), responder, timeout, headers);
|
||||
}
|
||||
|
||||
void LLHTTPClient::patch(
|
||||
const std::string& url,
|
||||
const LLSD& body,
|
||||
ResponderPtr responder,
|
||||
const LLSD& headers,
|
||||
const F32 timeout)
|
||||
{
|
||||
request(url, HTTP_PATCH, new LLSDInjector(body), responder, timeout, headers);
|
||||
}
|
||||
|
||||
void LLHTTPClient::post(
|
||||
|
|
@ -588,7 +592,7 @@ void LLHTTPClient::post(
|
|||
const LLSD& headers,
|
||||
const F32 timeout)
|
||||
{
|
||||
request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, timeout, headers);
|
||||
request(url, HTTP_POST, new LLSDInjector(body), responder, timeout, headers);
|
||||
}
|
||||
|
||||
void LLHTTPClient::postRaw(
|
||||
|
|
@ -599,7 +603,7 @@ void LLHTTPClient::postRaw(
|
|||
const LLSD& headers,
|
||||
const F32 timeout)
|
||||
{
|
||||
request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, timeout, headers);
|
||||
request(url, HTTP_POST, new RawInjector(data, size), responder, timeout, headers);
|
||||
}
|
||||
|
||||
void LLHTTPClient::postFile(
|
||||
|
|
@ -609,7 +613,7 @@ void LLHTTPClient::postFile(
|
|||
const LLSD& headers,
|
||||
const F32 timeout)
|
||||
{
|
||||
request(url, LLURLRequest::HTTP_POST, new FileInjector(filename), responder, timeout, headers);
|
||||
request(url, HTTP_POST, new FileInjector(filename), responder, timeout, headers);
|
||||
}
|
||||
|
||||
void LLHTTPClient::postFile(
|
||||
|
|
@ -620,7 +624,7 @@ void LLHTTPClient::postFile(
|
|||
const LLSD& headers,
|
||||
const F32 timeout)
|
||||
{
|
||||
request(url, LLURLRequest::HTTP_POST, new VFileInjector(uuid, asset_type), responder, timeout, headers);
|
||||
request(url, HTTP_POST, new VFileInjector(uuid, asset_type), responder, timeout, headers);
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
@ -630,7 +634,7 @@ void LLHTTPClient::del(
|
|||
const LLSD& headers,
|
||||
const F32 timeout)
|
||||
{
|
||||
request(url, LLURLRequest::HTTP_DELETE, NULL, responder, timeout, headers);
|
||||
request(url, HTTP_DELETE, NULL, responder, timeout, headers);
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
@ -642,8 +646,21 @@ void LLHTTPClient::move(
|
|||
const F32 timeout)
|
||||
{
|
||||
LLSD headers = hdrs;
|
||||
headers["Destination"] = destination;
|
||||
request(url, LLURLRequest::HTTP_MOVE, NULL, responder, timeout, headers);
|
||||
headers[HTTP_OUT_HEADER_DESTINATION] = destination;
|
||||
request(url, HTTP_MOVE, NULL, responder, timeout, headers);
|
||||
}
|
||||
|
||||
// static
|
||||
void LLHTTPClient::copy(
|
||||
const std::string& url,
|
||||
const std::string& destination,
|
||||
ResponderPtr responder,
|
||||
const LLSD& hdrs,
|
||||
const F32 timeout)
|
||||
{
|
||||
LLSD headers = hdrs;
|
||||
headers[HTTP_OUT_HEADER_DESTINATION] = destination;
|
||||
request(url, HTTP_COPY, NULL, responder, timeout, headers);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -80,6 +80,14 @@ public:
|
|||
ResponderPtr,
|
||||
const LLSD& headers = LLSD(),
|
||||
const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
|
||||
|
||||
static void patch(
|
||||
const std::string& url,
|
||||
const LLSD& body,
|
||||
ResponderPtr,
|
||||
const LLSD& headers = LLSD(),
|
||||
const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
|
||||
|
||||
static void getHeaderOnly(const std::string& url, ResponderPtr, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS,
|
||||
bool follow_redirects = true);
|
||||
static void getHeaderOnly(const std::string& url, ResponderPtr, const LLSD& headers,
|
||||
|
|
@ -119,7 +127,7 @@ public:
|
|||
const LLSD& headers = LLSD(),
|
||||
const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
|
||||
///< sends a DELETE method, but we can't call it delete in c++
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send a MOVE webdav method
|
||||
*
|
||||
|
|
@ -136,6 +144,22 @@ public:
|
|||
const LLSD& headers = LLSD(),
|
||||
const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
|
||||
|
||||
/**
|
||||
* @brief Send a COPY webdav method
|
||||
*
|
||||
* @param url The complete serialized (and escaped) url to get.
|
||||
* @param destination The complete serialized destination url.
|
||||
* @param responder The responder that will handle the result.
|
||||
* @param headers A map of key:value headers to pass to the request
|
||||
* @param timeout The number of seconds to give the server to respond.
|
||||
*/
|
||||
static void copy(
|
||||
const std::string& url,
|
||||
const std::string& destination,
|
||||
ResponderPtr responder,
|
||||
const LLSD& headers = LLSD(),
|
||||
const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
|
||||
|
||||
//@}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -35,18 +35,18 @@ void LLHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr respo
|
|||
{
|
||||
LLSD empty_pragma_header;
|
||||
// Pragma is required to stop curl adding "no-cache"
|
||||
// Space is required to stop llurlrequest from turnning off proxying
|
||||
empty_pragma_header["Pragma"] = " ";
|
||||
// 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("Pragma"))
|
||||
if (!empty_pragma_header.has(HTTP_OUT_HEADER_PRAGMA))
|
||||
{
|
||||
// as above
|
||||
empty_pragma_header["Pragma"] = " ";
|
||||
// as above
|
||||
empty_pragma_header[HTTP_OUT_HEADER_PRAGMA] = " ";
|
||||
}
|
||||
LLHTTPClient::get(url, responder, empty_pragma_header);
|
||||
}
|
||||
|
|
@ -56,3 +56,18 @@ void LLHTTPClientAdapter::put(const std::string& url, const LLSD& body, LLCurl::
|
|||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,14 @@ public:
|
|||
virtual void get(const std::string& url, LLCurl::ResponderPtr responder);
|
||||
virtual void get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers);
|
||||
virtual void put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder);
|
||||
virtual void put(
|
||||
const std::string& url,
|
||||
const LLSD& body,
|
||||
LLCurl::ResponderPtr responder,
|
||||
const LLSD& headers);
|
||||
virtual void del(
|
||||
const std::string& url,
|
||||
LLCurl::ResponderPtr responder);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,228 @@
|
|||
/**
|
||||
* @file llhttpconstants.cpp
|
||||
* @brief Implementation of the HTTP request / response constant lookups
|
||||
*
|
||||
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
|
||||
*
|
||||
* Copyright (c) 2013, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 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
|
||||
* 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 "lltimer.h"
|
||||
|
||||
// for curl_getdate() (apparently parsing RFC 1123 dates is hard)
|
||||
#include <curl/curl.h>
|
||||
|
||||
// Outgoing headers. Do *not* use these to check incoming headers.
|
||||
// For incoming headers, use the lower-case headers, below.
|
||||
const std::string HTTP_OUT_HEADER_ACCEPT("Accept");
|
||||
const std::string HTTP_OUT_HEADER_ACCEPT_CHARSET("Accept-Charset");
|
||||
const std::string HTTP_OUT_HEADER_ACCEPT_ENCODING("Accept-Encoding");
|
||||
const std::string HTTP_OUT_HEADER_ACCEPT_LANGUAGE("Accept-Language");
|
||||
const std::string HTTP_OUT_HEADER_ACCEPT_RANGES("Accept-Ranges");
|
||||
const std::string HTTP_OUT_HEADER_AGE("Age");
|
||||
const std::string HTTP_OUT_HEADER_ALLOW("Allow");
|
||||
const std::string HTTP_OUT_HEADER_AUTHORIZATION("Authorization");
|
||||
const std::string HTTP_OUT_HEADER_CACHE_CONTROL("Cache-Control");
|
||||
const std::string HTTP_OUT_HEADER_CONNECTION("Connection");
|
||||
const std::string HTTP_OUT_HEADER_CONTENT_DESCRIPTION("Content-Description");
|
||||
const std::string HTTP_OUT_HEADER_CONTENT_ENCODING("Content-Encoding");
|
||||
const std::string HTTP_OUT_HEADER_CONTENT_ID("Content-ID");
|
||||
const std::string HTTP_OUT_HEADER_CONTENT_LANGUAGE("Content-Language");
|
||||
const std::string HTTP_OUT_HEADER_CONTENT_LENGTH("Content-Length");
|
||||
const std::string HTTP_OUT_HEADER_CONTENT_LOCATION("Content-Location");
|
||||
const std::string HTTP_OUT_HEADER_CONTENT_MD5("Content-MD5");
|
||||
const std::string HTTP_OUT_HEADER_CONTENT_RANGE("Content-Range");
|
||||
const std::string HTTP_OUT_HEADER_CONTENT_TRANSFER_ENCODING("Content-Transfer-Encoding");
|
||||
const std::string HTTP_OUT_HEADER_CONTENT_TYPE("Content-Type");
|
||||
const std::string HTTP_OUT_HEADER_COOKIE("Cookie");
|
||||
const std::string HTTP_OUT_HEADER_DATE("Date");
|
||||
const std::string HTTP_OUT_HEADER_DESTINATION("Destination");
|
||||
const std::string HTTP_OUT_HEADER_ETAG("ETag");
|
||||
const std::string HTTP_OUT_HEADER_EXPECT("Expect");
|
||||
const std::string HTTP_OUT_HEADER_EXPIRES("Expires");
|
||||
const std::string HTTP_OUT_HEADER_FROM("From");
|
||||
const std::string HTTP_OUT_HEADER_HOST("Host");
|
||||
const std::string HTTP_OUT_HEADER_IF_MATCH("If-Match");
|
||||
const std::string HTTP_OUT_HEADER_IF_MODIFIED_SINCE("If-Modified-Since");
|
||||
const std::string HTTP_OUT_HEADER_IF_NONE_MATCH("If-None-Match");
|
||||
const std::string HTTP_OUT_HEADER_IF_RANGE("If-Range");
|
||||
const std::string HTTP_OUT_HEADER_IF_UNMODIFIED_SINCE("If-Unmodified-Since");
|
||||
const std::string HTTP_OUT_HEADER_KEEP_ALIVE("Keep-Alive");
|
||||
const std::string HTTP_OUT_HEADER_LAST_MODIFIED("Last-Modified");
|
||||
const std::string HTTP_OUT_HEADER_LOCATION("Location");
|
||||
const std::string HTTP_OUT_HEADER_MAX_FORWARDS("Max-Forwards");
|
||||
const std::string HTTP_OUT_HEADER_MIME_VERSION("MIME-Version");
|
||||
const std::string HTTP_OUT_HEADER_PRAGMA("Pragma");
|
||||
const std::string HTTP_OUT_HEADER_PROXY_AUTHENTICATE("Proxy-Authenticate");
|
||||
const std::string HTTP_OUT_HEADER_PROXY_AUTHORIZATION("Proxy-Authorization");
|
||||
const std::string HTTP_OUT_HEADER_RANGE("Range");
|
||||
const std::string HTTP_OUT_HEADER_REFERER("Referer");
|
||||
const std::string HTTP_OUT_HEADER_RETRY_AFTER("Retry-After");
|
||||
const std::string HTTP_OUT_HEADER_SERVER("Server");
|
||||
const std::string HTTP_OUT_HEADER_SET_COOKIE("Set-Cookie");
|
||||
const std::string HTTP_OUT_HEADER_TE("TE");
|
||||
const std::string HTTP_OUT_HEADER_TRAILER("Trailer");
|
||||
const std::string HTTP_OUT_HEADER_TRANSFER_ENCODING("Transfer-Encoding");
|
||||
const std::string HTTP_OUT_HEADER_UPGRADE("Upgrade");
|
||||
const std::string HTTP_OUT_HEADER_USER_AGENT("User-Agent");
|
||||
const std::string HTTP_OUT_HEADER_VARY("Vary");
|
||||
const std::string HTTP_OUT_HEADER_VIA("Via");
|
||||
const std::string HTTP_OUT_HEADER_WARNING("Warning");
|
||||
const std::string HTTP_OUT_HEADER_WWW_AUTHENTICATE("WWW-Authenticate");
|
||||
|
||||
// Incoming headers are normalized to lower-case.
|
||||
const std::string HTTP_IN_HEADER_ACCEPT_LANGUAGE("accept-language");
|
||||
const std::string HTTP_IN_HEADER_CACHE_CONTROL("cache-control");
|
||||
const std::string HTTP_IN_HEADER_CONTENT_LENGTH("content-length");
|
||||
const std::string HTTP_IN_HEADER_CONTENT_LOCATION("content-location");
|
||||
const std::string HTTP_IN_HEADER_CONTENT_TYPE("content-type");
|
||||
const std::string HTTP_IN_HEADER_HOST("host");
|
||||
const std::string HTTP_IN_HEADER_LOCATION("location");
|
||||
const std::string HTTP_IN_HEADER_RETRY_AFTER("retry-after");
|
||||
const std::string HTTP_IN_HEADER_SET_COOKIE("set-cookie");
|
||||
const std::string HTTP_IN_HEADER_USER_AGENT("user-agent");
|
||||
const std::string HTTP_IN_HEADER_X_FORWARDED_FOR("x-forwarded-for");
|
||||
|
||||
const std::string HTTP_CONTENT_LLSD_XML("application/llsd+xml");
|
||||
const std::string HTTP_CONTENT_OCTET_STREAM("application/octet-stream");
|
||||
const std::string HTTP_CONTENT_XML("application/xml");
|
||||
const std::string HTTP_CONTENT_JSON("application/json");
|
||||
const std::string HTTP_CONTENT_TEXT_HTML("text/html");
|
||||
const std::string HTTP_CONTENT_TEXT_HTML_UTF8("text/html; charset=utf-8");
|
||||
const std::string HTTP_CONTENT_TEXT_PLAIN_UTF8("text/plain; charset=utf-8");
|
||||
const std::string HTTP_CONTENT_TEXT_LLSD("text/llsd");
|
||||
const std::string HTTP_CONTENT_TEXT_XML("text/xml");
|
||||
const std::string HTTP_CONTENT_TEXT_LSL("text/lsl");
|
||||
const std::string HTTP_CONTENT_TEXT_PLAIN("text/plain");
|
||||
const std::string HTTP_CONTENT_IMAGE_X_J2C("image/x-j2c");
|
||||
const std::string HTTP_CONTENT_IMAGE_J2C("image/j2c");
|
||||
const std::string HTTP_CONTENT_IMAGE_JPEG("image/jpeg");
|
||||
const std::string HTTP_CONTENT_IMAGE_PNG("image/png");
|
||||
const std::string HTTP_CONTENT_IMAGE_BMP("image/bmp");
|
||||
|
||||
const std::string HTTP_NO_CACHE("no-cache");
|
||||
const std::string HTTP_NO_CACHE_CONTROL("no-cache, max-age=0");
|
||||
|
||||
const std::string HTTP_VERB_INVALID("(invalid)");
|
||||
const std::string HTTP_VERB_HEAD("HEAD");
|
||||
const std::string HTTP_VERB_GET("GET");
|
||||
const std::string HTTP_VERB_PUT("PUT");
|
||||
const std::string HTTP_VERB_POST("POST");
|
||||
const std::string HTTP_VERB_DELETE("DELETE");
|
||||
const std::string HTTP_VERB_MOVE("MOVE");
|
||||
const std::string HTTP_VERB_OPTIONS("OPTIONS");
|
||||
const std::string HTTP_VERB_PATCH("PATCH");
|
||||
const std::string HTTP_VERB_COPY("COPY");
|
||||
|
||||
const std::string& httpMethodAsVerb(EHTTPMethod method)
|
||||
{
|
||||
static const std::string VERBS[] =
|
||||
{
|
||||
HTTP_VERB_INVALID,
|
||||
HTTP_VERB_HEAD,
|
||||
HTTP_VERB_GET,
|
||||
HTTP_VERB_PUT,
|
||||
HTTP_VERB_POST,
|
||||
HTTP_VERB_DELETE,
|
||||
HTTP_VERB_MOVE,
|
||||
HTTP_VERB_OPTIONS,
|
||||
HTTP_VERB_PATCH,
|
||||
HTTP_VERB_COPY
|
||||
};
|
||||
if(((S32)method <=0) || ((S32)method >= HTTP_METHOD_COUNT))
|
||||
{
|
||||
return VERBS[0];
|
||||
}
|
||||
return VERBS[method];
|
||||
}
|
||||
|
||||
bool isHttpInformationalStatus(S32 status)
|
||||
{
|
||||
// Check for status 1xx.
|
||||
return((100 <= status) && (status < 200));
|
||||
}
|
||||
|
||||
bool isHttpGoodStatus(S32 status)
|
||||
{
|
||||
// Check for status 2xx.
|
||||
return((200 <= status) && (status < 300));
|
||||
}
|
||||
|
||||
bool isHttpRedirectStatus(S32 status)
|
||||
{
|
||||
// Check for status 3xx.
|
||||
return((300 <= status) && (status < 400));
|
||||
}
|
||||
|
||||
bool isHttpClientErrorStatus(S32 status)
|
||||
{
|
||||
// Status 499 is sometimes used for re-interpreted status 2xx errors
|
||||
// based on body content. Treat these as potentially retryable 'server' status errors,
|
||||
// since we do not have enough context to know if this will always fail.
|
||||
if (HTTP_INTERNAL_ERROR == status) return false;
|
||||
|
||||
// Check for status 5xx.
|
||||
return((400 <= status) && (status < 500));
|
||||
}
|
||||
|
||||
bool isHttpServerErrorStatus(S32 status)
|
||||
{
|
||||
// Status 499 is sometimes used for re-interpreted status 2xx errors.
|
||||
// Allow retry of these, since we don't have enough information in this
|
||||
// context to know if this will always fail.
|
||||
if (HTTP_INTERNAL_ERROR == status) return true;
|
||||
|
||||
// Check for status 5xx.
|
||||
return((500 <= status) && (status < 600));
|
||||
}
|
||||
|
||||
// Parses 'Retry-After' header contents and returns seconds until retry should occur.
|
||||
bool getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait)
|
||||
{
|
||||
// *TODO: This needs testing! Not in use yet.
|
||||
// Examples of Retry-After headers:
|
||||
// Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
|
||||
// Retry-After: 120
|
||||
|
||||
// Check for number of seconds version, first:
|
||||
char* end = 0;
|
||||
// Parse as double
|
||||
double seconds = std::strtod(retry_after.c_str(), &end);
|
||||
if ( end != 0 && *end == 0 )
|
||||
{
|
||||
// Successful parse
|
||||
seconds_to_wait = (F32) seconds;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parse rfc1123 date.
|
||||
time_t date = curl_getdate(retry_after.c_str(), NULL );
|
||||
if (-1 == date) return false;
|
||||
|
||||
seconds_to_wait = (F64)date - LLTimer::getTotalSeconds();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,225 @@
|
|||
/**
|
||||
* @file llhttpconstants.h
|
||||
* @brief Constants for HTTP requests and responses
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2001-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
|
||||
* 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 LL_HTTP_CONSTANTS_H
|
||||
#define LL_HTTP_CONSTANTS_H
|
||||
|
||||
#include "stdtypes.h"
|
||||
|
||||
/////// HTTP STATUS CODES ///////
|
||||
|
||||
// Standard errors from HTTP spec:
|
||||
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1
|
||||
const S32 HTTP_CONTINUE = 100;
|
||||
const S32 HTTP_SWITCHING_PROTOCOLS = 101;
|
||||
|
||||
// Success
|
||||
const S32 HTTP_OK = 200;
|
||||
const S32 HTTP_CREATED = 201;
|
||||
const S32 HTTP_ACCEPTED = 202;
|
||||
const S32 HTTP_NON_AUTHORITATIVE_INFORMATION = 203;
|
||||
const S32 HTTP_NO_CONTENT = 204;
|
||||
const S32 HTTP_RESET_CONTENT = 205;
|
||||
const S32 HTTP_PARTIAL_CONTENT = 206;
|
||||
|
||||
// Redirection
|
||||
const S32 HTTP_MULTIPLE_CHOICES = 300;
|
||||
const S32 HTTP_MOVED_PERMANENTLY = 301;
|
||||
const S32 HTTP_FOUND = 302;
|
||||
const S32 HTTP_SEE_OTHER = 303;
|
||||
const S32 HTTP_NOT_MODIFIED = 304;
|
||||
const S32 HTTP_USE_PROXY = 305;
|
||||
const S32 HTTP_TEMPORARY_REDIRECT = 307;
|
||||
|
||||
// Client Error
|
||||
const S32 HTTP_BAD_REQUEST = 400;
|
||||
const S32 HTTP_UNAUTHORIZED = 401;
|
||||
const S32 HTTP_PAYMENT_REQUIRED = 402;
|
||||
const S32 HTTP_FORBIDDEN = 403;
|
||||
const S32 HTTP_NOT_FOUND = 404;
|
||||
const S32 HTTP_METHOD_NOT_ALLOWED = 405;
|
||||
const S32 HTTP_NOT_ACCEPTABLE = 406;
|
||||
const S32 HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;
|
||||
const S32 HTTP_REQUEST_TIME_OUT = 408;
|
||||
const S32 HTTP_CONFLICT = 409;
|
||||
const S32 HTTP_GONE = 410;
|
||||
const S32 HTTP_LENGTH_REQUIRED = 411;
|
||||
const S32 HTTP_PRECONDITION_FAILED = 412;
|
||||
const S32 HTTP_REQUEST_ENTITY_TOO_LARGE = 413;
|
||||
const S32 HTTP_REQUEST_URI_TOO_LARGE = 414;
|
||||
const S32 HTTP_UNSUPPORTED_MEDIA_TYPE = 415;
|
||||
const S32 HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
|
||||
const S32 HTTP_EXPECTATION_FAILED = 417;
|
||||
|
||||
// Server Error
|
||||
const S32 HTTP_INTERNAL_SERVER_ERROR = 500;
|
||||
const S32 HTTP_NOT_IMPLEMENTED = 501;
|
||||
const S32 HTTP_BAD_GATEWAY = 502;
|
||||
const S32 HTTP_SERVICE_UNAVAILABLE = 503;
|
||||
const S32 HTTP_GATEWAY_TIME_OUT = 504;
|
||||
const S32 HTTP_VERSION_NOT_SUPPORTED = 505;
|
||||
|
||||
// We combine internal process errors with status codes
|
||||
// These status codes should not be sent over the wire
|
||||
// and indicate something went wrong internally.
|
||||
// If you get these they are not normal.
|
||||
const S32 HTTP_INTERNAL_CURL_ERROR = 498;
|
||||
const S32 HTTP_INTERNAL_ERROR = 499;
|
||||
|
||||
|
||||
////// HTTP Methods //////
|
||||
|
||||
extern const std::string HTTP_VERB_INVALID;
|
||||
extern const std::string HTTP_VERB_HEAD;
|
||||
extern const std::string HTTP_VERB_GET;
|
||||
extern const std::string HTTP_VERB_PUT;
|
||||
extern const std::string HTTP_VERB_POST;
|
||||
extern const std::string HTTP_VERB_DELETE;
|
||||
extern const std::string HTTP_VERB_MOVE;
|
||||
extern const std::string HTTP_VERB_OPTIONS;
|
||||
|
||||
enum EHTTPMethod
|
||||
{
|
||||
HTTP_INVALID = 0,
|
||||
HTTP_HEAD,
|
||||
HTTP_GET,
|
||||
HTTP_PUT,
|
||||
HTTP_POST,
|
||||
HTTP_DELETE,
|
||||
HTTP_MOVE, // Caller will need to set 'Destination' header
|
||||
HTTP_OPTIONS,
|
||||
HTTP_PATCH,
|
||||
HTTP_COPY,
|
||||
HTTP_METHOD_COUNT
|
||||
};
|
||||
|
||||
const std::string& httpMethodAsVerb(EHTTPMethod method);
|
||||
bool isHttpInformationalStatus(S32 status);
|
||||
bool isHttpGoodStatus(S32 status);
|
||||
bool isHttpRedirectStatus(S32 status);
|
||||
bool isHttpClientErrorStatus(S32 status);
|
||||
bool isHttpServerErrorStatus(S32 status);
|
||||
|
||||
// Parses 'Retry-After' header contents and returns seconds until retry should occur.
|
||||
bool getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait);
|
||||
|
||||
//// HTTP Headers /////
|
||||
|
||||
// Outgoing headers. Do *not* use these to check incoming headers.
|
||||
// For incoming headers, use the lower-case headers, below.
|
||||
extern const std::string HTTP_OUT_HEADER_ACCEPT;
|
||||
extern const std::string HTTP_OUT_HEADER_ACCEPT_CHARSET;
|
||||
extern const std::string HTTP_OUT_HEADER_ACCEPT_ENCODING;
|
||||
extern const std::string HTTP_OUT_HEADER_ACCEPT_LANGUAGE;
|
||||
extern const std::string HTTP_OUT_HEADER_ACCEPT_RANGES;
|
||||
extern const std::string HTTP_OUT_HEADER_AGE;
|
||||
extern const std::string HTTP_OUT_HEADER_ALLOW;
|
||||
extern const std::string HTTP_OUT_HEADER_AUTHORIZATION;
|
||||
extern const std::string HTTP_OUT_HEADER_CACHE_CONTROL;
|
||||
extern const std::string HTTP_OUT_HEADER_CONNECTION;
|
||||
extern const std::string HTTP_OUT_HEADER_CONTENT_DESCRIPTION;
|
||||
extern const std::string HTTP_OUT_HEADER_CONTENT_ENCODING;
|
||||
extern const std::string HTTP_OUT_HEADER_CONTENT_ID;
|
||||
extern const std::string HTTP_OUT_HEADER_CONTENT_LANGUAGE;
|
||||
extern const std::string HTTP_OUT_HEADER_CONTENT_LENGTH;
|
||||
extern const std::string HTTP_OUT_HEADER_CONTENT_LOCATION;
|
||||
extern const std::string HTTP_OUT_HEADER_CONTENT_MD5;
|
||||
extern const std::string HTTP_OUT_HEADER_CONTENT_RANGE;
|
||||
extern const std::string HTTP_OUT_HEADER_CONTENT_TRANSFER_ENCODING;
|
||||
extern const std::string HTTP_OUT_HEADER_CONTENT_TYPE;
|
||||
extern const std::string HTTP_OUT_HEADER_COOKIE;
|
||||
extern const std::string HTTP_OUT_HEADER_DATE;
|
||||
extern const std::string HTTP_OUT_HEADER_DESTINATION;
|
||||
extern const std::string HTTP_OUT_HEADER_ETAG;
|
||||
extern const std::string HTTP_OUT_HEADER_EXPECT;
|
||||
extern const std::string HTTP_OUT_HEADER_EXPIRES;
|
||||
extern const std::string HTTP_OUT_HEADER_FROM;
|
||||
extern const std::string HTTP_OUT_HEADER_HOST;
|
||||
extern const std::string HTTP_OUT_HEADER_IF_MATCH;
|
||||
extern const std::string HTTP_OUT_HEADER_IF_MODIFIED_SINCE;
|
||||
extern const std::string HTTP_OUT_HEADER_IF_NONE_MATCH;
|
||||
extern const std::string HTTP_OUT_HEADER_IF_RANGE;
|
||||
extern const std::string HTTP_OUT_HEADER_IF_UNMODIFIED_SINCE;
|
||||
extern const std::string HTTP_OUT_HEADER_KEEP_ALIVE;
|
||||
extern const std::string HTTP_OUT_HEADER_LAST_MODIFIED;
|
||||
extern const std::string HTTP_OUT_HEADER_LOCATION;
|
||||
extern const std::string HTTP_OUT_HEADER_MAX_FORWARDS;
|
||||
extern const std::string HTTP_OUT_HEADER_MIME_VERSION;
|
||||
extern const std::string HTTP_OUT_HEADER_PRAGMA;
|
||||
extern const std::string HTTP_OUT_HEADER_PROXY_AUTHENTICATE;
|
||||
extern const std::string HTTP_OUT_HEADER_PROXY_AUTHORIZATION;
|
||||
extern const std::string HTTP_OUT_HEADER_RANGE;
|
||||
extern const std::string HTTP_OUT_HEADER_REFERER;
|
||||
extern const std::string HTTP_OUT_HEADER_RETRY_AFTER;
|
||||
extern const std::string HTTP_OUT_HEADER_SERVER;
|
||||
extern const std::string HTTP_OUT_HEADER_SET_COOKIE;
|
||||
extern const std::string HTTP_OUT_HEADER_TE;
|
||||
extern const std::string HTTP_OUT_HEADER_TRAILER;
|
||||
extern const std::string HTTP_OUT_HEADER_TRANSFER_ENCODING;
|
||||
extern const std::string HTTP_OUT_HEADER_UPGRADE;
|
||||
extern const std::string HTTP_OUT_HEADER_USER_AGENT;
|
||||
extern const std::string HTTP_OUT_HEADER_VARY;
|
||||
extern const std::string HTTP_OUT_HEADER_VIA;
|
||||
extern const std::string HTTP_OUT_HEADER_WARNING;
|
||||
extern const std::string HTTP_OUT_HEADER_WWW_AUTHENTICATE;
|
||||
|
||||
// Incoming headers are normalized to lower-case.
|
||||
extern const std::string HTTP_IN_HEADER_ACCEPT_LANGUAGE;
|
||||
extern const std::string HTTP_IN_HEADER_CACHE_CONTROL;
|
||||
extern const std::string HTTP_IN_HEADER_CONTENT_LENGTH;
|
||||
extern const std::string HTTP_IN_HEADER_CONTENT_LOCATION;
|
||||
extern const std::string HTTP_IN_HEADER_CONTENT_TYPE;
|
||||
extern const std::string HTTP_IN_HEADER_HOST;
|
||||
extern const std::string HTTP_IN_HEADER_LOCATION;
|
||||
extern const std::string HTTP_IN_HEADER_RETRY_AFTER;
|
||||
extern const std::string HTTP_IN_HEADER_SET_COOKIE;
|
||||
extern const std::string HTTP_IN_HEADER_USER_AGENT;
|
||||
extern const std::string HTTP_IN_HEADER_X_FORWARDED_FOR;
|
||||
|
||||
//// HTTP Content Types ////
|
||||
|
||||
extern const std::string HTTP_CONTENT_LLSD_XML;
|
||||
extern const std::string HTTP_CONTENT_OCTET_STREAM;
|
||||
extern const std::string HTTP_CONTENT_XML;
|
||||
extern const std::string HTTP_CONTENT_JSON;
|
||||
extern const std::string HTTP_CONTENT_TEXT_HTML;
|
||||
extern const std::string HTTP_CONTENT_TEXT_HTML_UTF8;
|
||||
extern const std::string HTTP_CONTENT_TEXT_PLAIN_UTF8;
|
||||
extern const std::string HTTP_CONTENT_TEXT_LLSD;
|
||||
extern const std::string HTTP_CONTENT_TEXT_XML;
|
||||
extern const std::string HTTP_CONTENT_TEXT_LSL;
|
||||
extern const std::string HTTP_CONTENT_TEXT_PLAIN;
|
||||
extern const std::string HTTP_CONTENT_IMAGE_X_J2C;
|
||||
extern const std::string HTTP_CONTENT_IMAGE_J2C;
|
||||
extern const std::string HTTP_CONTENT_IMAGE_JPEG;
|
||||
extern const std::string HTTP_CONTENT_IMAGE_PNG;
|
||||
extern const std::string HTTP_CONTENT_IMAGE_BMP;
|
||||
|
||||
//// HTTP Cache Settings ////
|
||||
extern const std::string HTTP_NO_CACHE;
|
||||
extern const std::string HTTP_NO_CACHE_CONTROL;
|
||||
|
||||
#endif
|
||||
|
|
@ -30,9 +30,15 @@
|
|||
#include <boost/tokenizer.hpp>
|
||||
|
||||
#include "llstl.h"
|
||||
#include "lliohttpserver.h" // for string constants
|
||||
#include "llhttpconstants.h"
|
||||
|
||||
static const std::string CONTEXT_WILDCARD("wildcard");
|
||||
const std::string CONTEXT_HEADERS("headers");
|
||||
const std::string CONTEXT_PATH("path");
|
||||
const std::string CONTEXT_QUERY_STRING("query-string");
|
||||
const std::string CONTEXT_REQUEST("request");
|
||||
const std::string CONTEXT_RESPONSE("response");
|
||||
const std::string CONTEXT_VERB("verb");
|
||||
const std::string CONTEXT_WILDCARD("wildcard");
|
||||
|
||||
/**
|
||||
* LLHTTPNode
|
||||
|
|
@ -173,21 +179,23 @@ LLSD LLHTTPNode::simpleDel(const LLSD&) const
|
|||
void LLHTTPNode::options(ResponsePtr response, const LLSD& context) const
|
||||
{
|
||||
//LL_INFOS() << "options context: " << context << LL_ENDL;
|
||||
LL_DEBUGS("LLHTTPNode") << "context: " << context << LL_ENDL;
|
||||
|
||||
// default implementation constructs an url to the documentation.
|
||||
// *TODO: Check for 'Host' header instead of 'host' header?
|
||||
std::string host(
|
||||
context[CONTEXT_REQUEST][CONTEXT_HEADERS]["host"].asString());
|
||||
context[CONTEXT_REQUEST][CONTEXT_HEADERS][HTTP_IN_HEADER_HOST].asString());
|
||||
if(host.empty())
|
||||
{
|
||||
response->status(400, "Bad Request -- need Host header");
|
||||
response->status(HTTP_BAD_REQUEST, "Bad Request -- need Host header");
|
||||
return;
|
||||
}
|
||||
std::ostringstream ostr;
|
||||
ostr << "http://" << host << "/web/server/api";
|
||||
ostr << context[CONTEXT_REQUEST]["path"].asString();
|
||||
ostr << context[CONTEXT_REQUEST][CONTEXT_PATH].asString();
|
||||
static const std::string DOC_HEADER("X-Documentation-URL");
|
||||
response->addHeader(DOC_HEADER, ostr.str());
|
||||
response->status(200, "OK");
|
||||
response->status(HTTP_OK, "OK");
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -389,17 +397,17 @@ void LLHTTPNode::Response::statusUnknownError(S32 code)
|
|||
|
||||
void LLHTTPNode::Response::notFound(const std::string& message)
|
||||
{
|
||||
status(404, message);
|
||||
status(HTTP_NOT_FOUND, message);
|
||||
}
|
||||
|
||||
void LLHTTPNode::Response::notFound()
|
||||
{
|
||||
status(404, "Not Found");
|
||||
status(HTTP_NOT_FOUND, "Not Found");
|
||||
}
|
||||
|
||||
void LLHTTPNode::Response::methodNotAllowed()
|
||||
{
|
||||
status(405, "Method Not Allowed");
|
||||
status(HTTP_METHOD_NOT_ALLOWED, "Method Not Allowed");
|
||||
}
|
||||
|
||||
void LLHTTPNode::Response::addHeader(
|
||||
|
|
@ -467,7 +475,7 @@ LLSimpleResponse::~LLSimpleResponse()
|
|||
|
||||
void LLSimpleResponse::result(const LLSD& result)
|
||||
{
|
||||
status(200, "OK");
|
||||
status(HTTP_OK, "OK");
|
||||
}
|
||||
|
||||
void LLSimpleResponse::extendedResult(S32 code, const std::string& body, const LLSD& headers)
|
||||
|
|
@ -475,6 +483,11 @@ void LLSimpleResponse::extendedResult(S32 code, const std::string& body, const L
|
|||
status(code,body);
|
||||
}
|
||||
|
||||
void LLSimpleResponse::extendedResult(S32 code, const LLSD& r, const LLSD& headers)
|
||||
{
|
||||
status(code,"(LLSD)");
|
||||
}
|
||||
|
||||
void LLSimpleResponse::status(S32 code, const std::string& message)
|
||||
{
|
||||
mCode = code;
|
||||
|
|
|
|||
|
|
@ -31,6 +31,17 @@
|
|||
#include "llrefcount.h"
|
||||
#include "llsd.h"
|
||||
|
||||
// common strings use for populating the context. basically 'request',
|
||||
// 'wildcard', and 'headers'.
|
||||
extern const std::string CONTEXT_HEADERS;
|
||||
extern const std::string CONTEXT_PATH;
|
||||
extern const std::string CONTEXT_QUERY_STRING;
|
||||
extern const std::string CONTEXT_REQUEST;
|
||||
extern const std::string CONTEXT_RESPONSE;
|
||||
extern const std::string CONTEXT_VERB;
|
||||
extern const std::string CONTEXT_WILDCARD;
|
||||
|
||||
|
||||
class LLChainIOFactory;
|
||||
|
||||
/**
|
||||
|
|
@ -60,6 +71,8 @@ class LLChainIOFactory;
|
|||
*/
|
||||
class LLHTTPNode
|
||||
{
|
||||
protected:
|
||||
LOG_CLASS(LLHTTPNode);
|
||||
public:
|
||||
LLHTTPNode();
|
||||
virtual ~LLHTTPNode();
|
||||
|
|
@ -100,7 +113,12 @@ public:
|
|||
/**
|
||||
* @brief return status code and message with headers.
|
||||
*/
|
||||
virtual void extendedResult(S32 code, const std::string& message, const LLSD& headers) = 0;
|
||||
virtual void extendedResult(S32 code, const std::string& message, const LLSD& headers = LLSD()) = 0;
|
||||
|
||||
/**
|
||||
* @brief return status code and LLSD result with headers.
|
||||
*/
|
||||
virtual void extendedResult(S32 code, const LLSD& result, const LLSD& headers = LLSD()) = 0;
|
||||
|
||||
/**
|
||||
* @brief return status code and reason string on http header,
|
||||
|
|
@ -118,7 +136,7 @@ public:
|
|||
virtual void methodNotAllowed();
|
||||
|
||||
/**
|
||||
* @breif Add a name: value http header.
|
||||
* @brief Add a name: value http header.
|
||||
*
|
||||
* No effort is made to ensure the response is a valid http
|
||||
* header.
|
||||
|
|
@ -187,15 +205,15 @@ public:
|
|||
name, and return true if the name will construct to a valid url.
|
||||
For convenience, the <code>getChild()</code> method above will
|
||||
automatically insert the name in
|
||||
context["request"]["wildcard"][key] if this method returns true.
|
||||
context[CONTEXT_REQUEST][CONTEXT_WILDCARD][key] if this method returns true.
|
||||
For example, the node "agent/<agent_id>/detail" will set
|
||||
context["request"]["wildcard"]["agent_id"] eqaul to the value
|
||||
context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["agent_id"] eqaul to the value
|
||||
found during traversal.
|
||||
*/
|
||||
|
||||
const LLHTTPNode* traverse(const std::string& path, LLSD& context) const;
|
||||
/**< find a node, if any, that can service this path
|
||||
set up context["request"] information
|
||||
set up context[CONTEXT_REQUEST] information
|
||||
*/
|
||||
//@}
|
||||
|
||||
|
|
@ -287,7 +305,7 @@ public:
|
|||
|
||||
void result(const LLSD& result);
|
||||
void extendedResult(S32 code, const std::string& body, const LLSD& headers);
|
||||
|
||||
void extendedResult(S32 code, const LLSD& result, const LLSD& headers);
|
||||
void status(S32 code, const std::string& message);
|
||||
|
||||
void print(std::ostream& out) const;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "llapr.h"
|
||||
#include "llbuffer.h"
|
||||
#include "llbufferstream.h"
|
||||
#include "llhttpconstants.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "llhttpnode.h"
|
||||
#include "lliopipe.h"
|
||||
|
|
@ -50,15 +51,6 @@
|
|||
#include <boost/tokenizer.hpp>
|
||||
|
||||
static const char HTTP_VERSION_STR[] = "HTTP/1.0";
|
||||
const std::string CONTEXT_REQUEST("request");
|
||||
const std::string CONTEXT_RESPONSE("response");
|
||||
const std::string CONTEXT_VERB("verb");
|
||||
const std::string CONTEXT_HEADERS("headers");
|
||||
const std::string HTTP_VERB_GET("GET");
|
||||
const std::string HTTP_VERB_PUT("PUT");
|
||||
const std::string HTTP_VERB_POST("POST");
|
||||
const std::string HTTP_VERB_DELETE("DELETE");
|
||||
const std::string HTTP_VERB_OPTIONS("OPTIONS");
|
||||
|
||||
static LLIOHTTPServer::timing_callback_t sTimingCallback = NULL;
|
||||
static void* sTimingCallbackData = NULL;
|
||||
|
|
@ -103,7 +95,7 @@ private:
|
|||
// from LLHTTPNode::Response
|
||||
virtual void result(const LLSD&);
|
||||
virtual void extendedResult(S32 code, const std::string& body, const LLSD& headers);
|
||||
|
||||
virtual void extendedResult(S32 code, const LLSD& body, const LLSD& headers);
|
||||
virtual void status(S32 code, const std::string& message);
|
||||
|
||||
void nullPipe();
|
||||
|
|
@ -123,7 +115,8 @@ private:
|
|||
STATE_LOCKED,
|
||||
STATE_GOOD_RESULT,
|
||||
STATE_STATUS_RESULT,
|
||||
STATE_EXTENDED_RESULT
|
||||
STATE_EXTENDED_RESULT,
|
||||
STATE_EXTENDED_LLSD_RESULT
|
||||
};
|
||||
State mState;
|
||||
|
||||
|
|
@ -133,7 +126,7 @@ private:
|
|||
void lockChain(LLPumpIO*);
|
||||
void unlockChain();
|
||||
|
||||
LLSD mGoodResult;
|
||||
LLSD mResult;
|
||||
S32 mStatusCode;
|
||||
std::string mStatusMessage;
|
||||
LLSD mHeaders;
|
||||
|
|
@ -194,7 +187,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
|
|||
}
|
||||
else if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_TEXT)
|
||||
{
|
||||
std::stringstream strstrm;
|
||||
std::ostringstream strstrm;
|
||||
strstrm << istr.rdbuf();
|
||||
input = strstrm.str();
|
||||
}
|
||||
|
|
@ -210,7 +203,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
|
|||
}
|
||||
else if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_TEXT)
|
||||
{
|
||||
std::stringstream strstrm;
|
||||
std::ostringstream strstrm;
|
||||
strstrm << istr.rdbuf();
|
||||
input = strstrm.str();
|
||||
}
|
||||
|
|
@ -245,12 +238,12 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
|
|||
// Log all HTTP transactions.
|
||||
// TODO: Add a way to log these to their own file instead of indra.log
|
||||
// It is just too spammy to be in indra.log.
|
||||
LL_DEBUGS() << verb << " " << context[CONTEXT_REQUEST]["path"].asString()
|
||||
LL_DEBUGS() << verb << " " << context[CONTEXT_REQUEST][CONTEXT_PATH].asString()
|
||||
<< " " << mStatusCode << " " << mStatusMessage << " " << delta
|
||||
<< "s" << LL_ENDL;
|
||||
|
||||
// Log Internal Server Errors
|
||||
//if(mStatusCode == 500)
|
||||
//if(mStatusCode == HTTP_INTERNAL_SERVER_ERROR)
|
||||
//{
|
||||
// LL_WARNS() << "LLHTTPPipe::process_impl:500:Internal Server Error"
|
||||
// << LL_ENDL;
|
||||
|
|
@ -272,10 +265,10 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
|
|||
case STATE_GOOD_RESULT:
|
||||
{
|
||||
LLSD headers = mHeaders;
|
||||
headers["Content-Type"] = "application/llsd+xml";
|
||||
headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_LLSD_XML;
|
||||
context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers;
|
||||
LLBufferStream ostr(channels, buffer.get());
|
||||
LLSDSerialize::toXML(mGoodResult, ostr);
|
||||
LLSDSerialize::toXML(mResult, ostr);
|
||||
|
||||
return STATUS_DONE;
|
||||
}
|
||||
|
|
@ -283,7 +276,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
|
|||
case STATE_STATUS_RESULT:
|
||||
{
|
||||
LLSD headers = mHeaders;
|
||||
headers["Content-Type"] = "text/plain";
|
||||
headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_TEXT_PLAIN;
|
||||
context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers;
|
||||
context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode;
|
||||
context[CONTEXT_RESPONSE]["statusMessage"] = mStatusMessage;
|
||||
|
|
@ -301,6 +294,17 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
|
|||
|
||||
return STATUS_DONE;
|
||||
}
|
||||
case STATE_EXTENDED_LLSD_RESULT:
|
||||
{
|
||||
LLSD headers = mHeaders;
|
||||
headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_LLSD_XML;
|
||||
context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers;
|
||||
context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode;
|
||||
LLBufferStream ostr(channels, buffer.get());
|
||||
LLSDSerialize::toXML(mResult, ostr);
|
||||
|
||||
return STATUS_DONE;
|
||||
}
|
||||
default:
|
||||
LL_WARNS() << "LLHTTPPipe::process_impl: unexpected state "
|
||||
<< mState << LL_ENDL;
|
||||
|
|
@ -336,12 +340,28 @@ void LLHTTPPipe::Response::result(const LLSD& r)
|
|||
return;
|
||||
}
|
||||
|
||||
mPipe->mStatusCode = 200;
|
||||
mPipe->mStatusCode = HTTP_OK;
|
||||
mPipe->mStatusMessage = "OK";
|
||||
mPipe->mGoodResult = r;
|
||||
mPipe->mResult = r;
|
||||
mPipe->mState = STATE_GOOD_RESULT;
|
||||
mPipe->mHeaders = mHeaders;
|
||||
mPipe->unlockChain();
|
||||
mPipe->unlockChain();
|
||||
}
|
||||
|
||||
void LLHTTPPipe::Response::extendedResult(S32 code, const LLSD& r, const LLSD& headers)
|
||||
{
|
||||
if(! mPipe)
|
||||
{
|
||||
LL_WARNS() << "LLHTTPPipe::Response::extendedResult: NULL pipe" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
mPipe->mStatusCode = code;
|
||||
mPipe->mStatusMessage = "(LLSD)";
|
||||
mPipe->mResult = r;
|
||||
mPipe->mHeaders = headers;
|
||||
mPipe->mState = STATE_EXTENDED_LLSD_RESULT;
|
||||
mPipe->unlockChain();
|
||||
}
|
||||
|
||||
void LLHTTPPipe::Response::extendedResult(S32 code, const std::string& body, const LLSD& headers)
|
||||
|
|
@ -455,9 +475,9 @@ LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(
|
|||
std::string message = context[CONTEXT_RESPONSE]["statusMessage"];
|
||||
|
||||
int code = context[CONTEXT_RESPONSE]["statusCode"];
|
||||
if (code < 200)
|
||||
if (code < HTTP_OK)
|
||||
{
|
||||
code = 200;
|
||||
code = HTTP_OK;
|
||||
message = "OK";
|
||||
}
|
||||
|
||||
|
|
@ -466,7 +486,7 @@ LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(
|
|||
S32 content_length = buffer->countAfter(channels.in(), NULL);
|
||||
if(0 < content_length)
|
||||
{
|
||||
ostr << "Content-Length: " << content_length << "\r\n";
|
||||
ostr << HTTP_OUT_HEADER_CONTENT_LENGTH << ": " << content_length << "\r\n";
|
||||
}
|
||||
// *NOTE: This guard can go away once the LLSD static map
|
||||
// iterator is available. Phoenix. 2008-05-09
|
||||
|
|
@ -772,7 +792,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(
|
|||
std::string name(buf, pos_colon - buf);
|
||||
std::string value(pos_colon + 2);
|
||||
LLStringUtil::toLower(name);
|
||||
if("content-length" == name)
|
||||
if(HTTP_IN_HEADER_CONTENT_LENGTH == name)
|
||||
{
|
||||
LL_DEBUGS() << "Content-Length: " << value << LL_ENDL;
|
||||
mContentLength = atoi(value.c_str());
|
||||
|
|
@ -847,12 +867,12 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(
|
|||
// HTTP headers.
|
||||
LLPumpIO::chain_t chain;
|
||||
chain.push_back(LLIOPipe::ptr_t(new LLIOFlush));
|
||||
context[CONTEXT_REQUEST]["path"] = mPath;
|
||||
context[CONTEXT_REQUEST]["query-string"] = mQuery;
|
||||
context[CONTEXT_REQUEST]["remote-host"]
|
||||
= mBuildContext["remote-host"];
|
||||
context[CONTEXT_REQUEST]["remote-port"]
|
||||
= mBuildContext["remote-port"];
|
||||
context[CONTEXT_REQUEST][CONTEXT_PATH] = mPath;
|
||||
context[CONTEXT_REQUEST][CONTEXT_QUERY_STRING] = mQuery;
|
||||
context[CONTEXT_REQUEST][CONTEXT_REMOTE_HOST]
|
||||
= mBuildContext[CONTEXT_REMOTE_HOST];
|
||||
context[CONTEXT_REQUEST][CONTEXT_REMOTE_PORT]
|
||||
= mBuildContext[CONTEXT_REMOTE_PORT];
|
||||
context[CONTEXT_REQUEST][CONTEXT_HEADERS] = mHeaders;
|
||||
|
||||
const LLChainIOFactory* protocolHandler
|
||||
|
|
|
|||
|
|
@ -33,18 +33,6 @@
|
|||
|
||||
class LLPumpIO;
|
||||
|
||||
// common strings use for populating the context. bascally 'request',
|
||||
// 'wildcard', and 'headers'.
|
||||
extern const std::string CONTEXT_REQUEST;
|
||||
extern const std::string CONTEXT_RESPONSE;
|
||||
extern const std::string CONTEXT_VERB;
|
||||
extern const std::string CONTEXT_HEADERS;
|
||||
extern const std::string HTTP_VERB_GET;
|
||||
extern const std::string HTTP_VERB_PUT;
|
||||
extern const std::string HTTP_VERB_POST;
|
||||
extern const std::string HTTP_VERB_DELETE;
|
||||
extern const std::string HTTP_VERB_OPTIONS;
|
||||
|
||||
class LLIOHTTPServer
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -40,6 +40,9 @@
|
|||
// constants
|
||||
//
|
||||
|
||||
const std::string CONTEXT_REMOTE_HOST("remote-host");
|
||||
const std::string CONTEXT_REMOTE_PORT("remote-port");
|
||||
|
||||
static const S32 LL_DEFAULT_LISTEN_BACKLOG = 10;
|
||||
static const S32 LL_SEND_BUFFER_SIZE = 40000;
|
||||
static const S32 LL_RECV_BUFFER_SIZE = 40000;
|
||||
|
|
@ -626,8 +629,8 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
|
|||
apr_sockaddr_ip_get(&remote_host_string, remote_addr);
|
||||
|
||||
LLSD context;
|
||||
context["remote-host"] = remote_host_string;
|
||||
context["remote-port"] = remote_addr->port;
|
||||
context[CONTEXT_REMOTE_HOST] = remote_host_string;
|
||||
context[CONTEXT_REMOTE_PORT] = remote_addr->port;
|
||||
|
||||
LLPumpIO::chain_t chain;
|
||||
chain.push_back(LLIOPipe::ptr_t(new LLIOSocketReader(llsocket)));
|
||||
|
|
|
|||
|
|
@ -43,6 +43,9 @@
|
|||
#include "apr_network_io.h"
|
||||
#include "llchainio.h"
|
||||
|
||||
extern const std::string CONTEXT_REMOTE_HOST;
|
||||
extern const std::string CONTEXT_REMOTE_PORT;
|
||||
|
||||
class LLHost;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,629 +0,0 @@
|
|||
/**
|
||||
* @file llmime.cpp
|
||||
* @author Phoenix
|
||||
* @date 2006-12-20
|
||||
* @brief Implementation of mime tools.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2006&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 "llmime.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "llmemorystream.h"
|
||||
|
||||
/**
|
||||
* Useful constants.
|
||||
*/
|
||||
// Headers specified in rfc-2045 will be canonicalized below.
|
||||
static const std::string CONTENT_LENGTH("Content-Length");
|
||||
static const std::string CONTENT_TYPE("Content-Type");
|
||||
static const S32 KNOWN_HEADER_COUNT = 6;
|
||||
static const std::string KNOWN_HEADER[KNOWN_HEADER_COUNT] =
|
||||
{
|
||||
CONTENT_LENGTH,
|
||||
CONTENT_TYPE,
|
||||
std::string("MIME-Version"),
|
||||
std::string("Content-Transfer-Encoding"),
|
||||
std::string("Content-ID"),
|
||||
std::string("Content-Description"),
|
||||
};
|
||||
|
||||
// parser helpers
|
||||
static const std::string MULTIPART("multipart");
|
||||
static const std::string BOUNDARY("boundary");
|
||||
static const std::string END_OF_CONTENT_PARAMETER("\r\n ;\t");
|
||||
static const std::string SEPARATOR_PREFIX("--");
|
||||
//static const std::string SEPARATOR_SUFFIX("\r\n");
|
||||
|
||||
/*
|
||||
Content-Type: multipart/mixed; boundary="segment"
|
||||
Content-Length: 24832
|
||||
|
||||
--segment
|
||||
Content-Type: image/j2c
|
||||
Content-Length: 23715
|
||||
|
||||
<data>
|
||||
|
||||
--segment
|
||||
Content-Type: text/xml; charset=UTF-8
|
||||
|
||||
<meta data>
|
||||
EOF
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* LLMimeIndex
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class LLMimeIndex::Impl
|
||||
* @brief Implementation details of the mime index class.
|
||||
* @see LLMimeIndex
|
||||
*/
|
||||
class LLMimeIndex::Impl
|
||||
{
|
||||
public:
|
||||
Impl() : mOffset(-1), mUseCount(1)
|
||||
{}
|
||||
Impl(LLSD headers, S32 offset) :
|
||||
mHeaders(headers), mOffset(offset), mUseCount(1)
|
||||
{}
|
||||
public:
|
||||
LLSD mHeaders;
|
||||
S32 mOffset;
|
||||
S32 mUseCount;
|
||||
|
||||
typedef std::vector<LLMimeIndex> sub_part_t;
|
||||
sub_part_t mAttachments;
|
||||
};
|
||||
|
||||
LLSD LLMimeIndex::headers() const
|
||||
{
|
||||
return mImpl->mHeaders;
|
||||
}
|
||||
|
||||
S32 LLMimeIndex::offset() const
|
||||
{
|
||||
return mImpl->mOffset;
|
||||
}
|
||||
|
||||
S32 LLMimeIndex::contentLength() const
|
||||
{
|
||||
// Find the content length in the headers.
|
||||
S32 length = -1;
|
||||
LLSD content_length = mImpl->mHeaders[CONTENT_LENGTH];
|
||||
if(content_length.isDefined())
|
||||
{
|
||||
length = content_length.asInteger();
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
std::string LLMimeIndex::contentType() const
|
||||
{
|
||||
std::string type;
|
||||
LLSD content_type = mImpl->mHeaders[CONTENT_TYPE];
|
||||
if(content_type.isDefined())
|
||||
{
|
||||
type = content_type.asString();
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
bool LLMimeIndex::isMultipart() const
|
||||
{
|
||||
bool multipart = false;
|
||||
LLSD content_type = mImpl->mHeaders[CONTENT_TYPE];
|
||||
if(content_type.isDefined())
|
||||
{
|
||||
std::string type = content_type.asString();
|
||||
int comp = type.compare(0, MULTIPART.size(), MULTIPART);
|
||||
if(0 == comp)
|
||||
{
|
||||
multipart = true;
|
||||
}
|
||||
}
|
||||
return multipart;
|
||||
}
|
||||
|
||||
S32 LLMimeIndex::subPartCount() const
|
||||
{
|
||||
return mImpl->mAttachments.size();
|
||||
}
|
||||
|
||||
LLMimeIndex LLMimeIndex::subPart(S32 index) const
|
||||
{
|
||||
LLMimeIndex part;
|
||||
if((index >= 0) && (index < (S32)mImpl->mAttachments.size()))
|
||||
{
|
||||
part = mImpl->mAttachments[index];
|
||||
}
|
||||
return part;
|
||||
}
|
||||
|
||||
LLMimeIndex::LLMimeIndex() : mImpl(new LLMimeIndex::Impl)
|
||||
{
|
||||
}
|
||||
|
||||
LLMimeIndex::LLMimeIndex(LLSD headers, S32 content_offset) :
|
||||
mImpl(new LLMimeIndex::Impl(headers, content_offset))
|
||||
{
|
||||
}
|
||||
|
||||
LLMimeIndex::LLMimeIndex(const LLMimeIndex& mime) :
|
||||
mImpl(mime.mImpl)
|
||||
{
|
||||
++mImpl->mUseCount;
|
||||
}
|
||||
|
||||
LLMimeIndex::~LLMimeIndex()
|
||||
{
|
||||
if(0 == --mImpl->mUseCount)
|
||||
{
|
||||
delete mImpl;
|
||||
}
|
||||
}
|
||||
|
||||
LLMimeIndex& LLMimeIndex::operator=(const LLMimeIndex& mime)
|
||||
{
|
||||
// Increment use count first so that we handle self assignment
|
||||
// automatically.
|
||||
++mime.mImpl->mUseCount;
|
||||
if(0 == --mImpl->mUseCount)
|
||||
{
|
||||
delete mImpl;
|
||||
}
|
||||
mImpl = mime.mImpl;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool LLMimeIndex::attachSubPart(LLMimeIndex sub_part)
|
||||
{
|
||||
// *FIX: Should we check for multi-part?
|
||||
if(mImpl->mAttachments.size() < S32_MAX)
|
||||
{
|
||||
mImpl->mAttachments.push_back(sub_part);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* LLMimeParser
|
||||
*/
|
||||
/**
|
||||
* @class LLMimeParser::Impl
|
||||
* @brief Implementation details of the mime parser class.
|
||||
* @see LLMimeParser
|
||||
*/
|
||||
class LLMimeParser::Impl
|
||||
{
|
||||
public:
|
||||
// @brief Constructor.
|
||||
Impl();
|
||||
|
||||
// @brief Reset this for a new parse.
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* @brief Parse a mime entity to find the index information.
|
||||
*
|
||||
* This method will scan the istr until a single complete mime
|
||||
* entity is read, an EOF, or limit bytes have been scanned. The
|
||||
* istr will be modified by this parsing, so pass in a temporary
|
||||
* stream or rewind/reset the stream after this call.
|
||||
* @param istr An istream which contains a mime entity.
|
||||
* @param limit The maximum number of bytes to scan.
|
||||
* @param separator The multipart separator if it is known.
|
||||
* @param is_subpart Set true if parsing a multipart sub part.
|
||||
* @param index[out] The parsed output.
|
||||
* @return Returns true if an index was parsed and no errors occurred.
|
||||
*/
|
||||
bool parseIndex(
|
||||
std::istream& istr,
|
||||
S32 limit,
|
||||
const std::string& separator,
|
||||
bool is_subpart,
|
||||
LLMimeIndex& index);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief parse the headers.
|
||||
*
|
||||
* At the end of a successful parse, mScanCount will be at the
|
||||
* start of the content.
|
||||
* @param istr The input stream.
|
||||
* @param limit maximum number of bytes to process
|
||||
* @param headers[out] A map of the headers found.
|
||||
* @return Returns true if the parse was successful.
|
||||
*/
|
||||
bool parseHeaders(std::istream& istr, S32 limit, LLSD& headers);
|
||||
|
||||
/**
|
||||
* @brief Figure out the separator string from a content type header.
|
||||
*
|
||||
* @param multipart_content_type The content type value from the headers.
|
||||
* @return Returns the separator string.
|
||||
*/
|
||||
std::string findSeparator(std::string multipart_content_type);
|
||||
|
||||
/**
|
||||
* @brief Scan through istr past the separator.
|
||||
*
|
||||
* @param istr The input stream.
|
||||
* @param limit Maximum number of bytes to scan.
|
||||
* @param separator The multipart separator.
|
||||
*/
|
||||
void scanPastSeparator(
|
||||
std::istream& istr,
|
||||
S32 limit,
|
||||
const std::string& separator);
|
||||
|
||||
/**
|
||||
* @brief Scan through istr past the content of the current mime part.
|
||||
*
|
||||
* @param istr The input stream.
|
||||
* @param limit Maximum number of bytes to scan.
|
||||
* @param headers The headers for this mime part.
|
||||
* @param separator The multipart separator if known.
|
||||
*/
|
||||
void scanPastContent(
|
||||
std::istream& istr,
|
||||
S32 limit,
|
||||
LLSD headers,
|
||||
const std::string separator);
|
||||
|
||||
/**
|
||||
* @brief Eat CRLF.
|
||||
*
|
||||
* This method has no concept of the limit, so ensure you have at
|
||||
* least 2 characters left to eat before hitting the limit. This
|
||||
* method will increment mScanCount as it goes.
|
||||
* @param istr The input stream.
|
||||
* @return Returns true if CRLF was found and consumed off of istr.
|
||||
*/
|
||||
bool eatCRLF(std::istream& istr);
|
||||
|
||||
// @brief Returns true if parsing should continue.
|
||||
bool continueParse() const { return (!mError && mContinue); }
|
||||
|
||||
// @brief anonymous enumeration for parse buffer size.
|
||||
enum
|
||||
{
|
||||
LINE_BUFFER_LENGTH = 1024
|
||||
};
|
||||
|
||||
protected:
|
||||
S32 mScanCount;
|
||||
bool mContinue;
|
||||
bool mError;
|
||||
char mBuffer[LINE_BUFFER_LENGTH];
|
||||
};
|
||||
|
||||
LLMimeParser::Impl::Impl()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void LLMimeParser::Impl::reset()
|
||||
{
|
||||
mScanCount = 0;
|
||||
mContinue = true;
|
||||
mError = false;
|
||||
mBuffer[0] = '\0';
|
||||
}
|
||||
|
||||
bool LLMimeParser::Impl::parseIndex(
|
||||
std::istream& istr,
|
||||
S32 limit,
|
||||
const std::string& separator,
|
||||
bool is_subpart,
|
||||
LLMimeIndex& index)
|
||||
{
|
||||
LLSD headers;
|
||||
bool parsed_something = false;
|
||||
if(parseHeaders(istr, limit, headers))
|
||||
{
|
||||
parsed_something = true;
|
||||
LLMimeIndex mime(headers, mScanCount);
|
||||
index = mime;
|
||||
if(index.isMultipart())
|
||||
{
|
||||
// Figure out the separator, scan past it, and recurse.
|
||||
std::string ct = headers[CONTENT_TYPE].asString();
|
||||
std::string sep = findSeparator(ct);
|
||||
scanPastSeparator(istr, limit, sep);
|
||||
while(continueParse() && parseIndex(istr, limit, sep, true, mime))
|
||||
{
|
||||
index.attachSubPart(mime);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Scan to the end of content.
|
||||
scanPastContent(istr, limit, headers, separator);
|
||||
if(is_subpart)
|
||||
{
|
||||
scanPastSeparator(istr, limit, separator);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(mError) return false;
|
||||
return parsed_something;
|
||||
}
|
||||
|
||||
bool LLMimeParser::Impl::parseHeaders(
|
||||
std::istream& istr,
|
||||
S32 limit,
|
||||
LLSD& headers)
|
||||
{
|
||||
while(continueParse())
|
||||
{
|
||||
// Get the next line.
|
||||
// We subtract 1 from the limit so that we make sure
|
||||
// not to read past limit when we get() the newline.
|
||||
S32 max_get = llmin((S32)LINE_BUFFER_LENGTH, limit - mScanCount - 1);
|
||||
istr.getline(mBuffer, max_get, '\r');
|
||||
mScanCount += (S32)istr.gcount();
|
||||
int c = istr.get();
|
||||
if(EOF == c)
|
||||
{
|
||||
mContinue = false;
|
||||
return false;
|
||||
}
|
||||
++mScanCount;
|
||||
if(c != '\n')
|
||||
{
|
||||
mError = true;
|
||||
return false;
|
||||
}
|
||||
if(mScanCount >= limit)
|
||||
{
|
||||
mContinue = false;
|
||||
}
|
||||
|
||||
// Check if that's the end of headers.
|
||||
if('\0' == mBuffer[0])
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Split out the name and value.
|
||||
// *NOTE: The use of strchr() here is safe since mBuffer is
|
||||
// guaranteed to be NULL terminated from the call to getline()
|
||||
// above.
|
||||
char* colon = strchr(mBuffer, ':');
|
||||
if(!colon)
|
||||
{
|
||||
mError = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Cononicalize the name part, and store the name: value in
|
||||
// the headers structure. We do this by iterating through
|
||||
// 'known' headers and replacing the value found with the
|
||||
// correct one.
|
||||
// *NOTE: Not so efficient, but iterating through a small
|
||||
// subset should not be too much of an issue.
|
||||
std::string name(mBuffer, colon++ - mBuffer);
|
||||
while(isspace(*colon)) ++colon;
|
||||
std::string value(colon);
|
||||
for(S32 ii = 0; ii < KNOWN_HEADER_COUNT; ++ii)
|
||||
{
|
||||
if(0 == LLStringUtil::compareInsensitive(name, KNOWN_HEADER[ii]))
|
||||
{
|
||||
name = KNOWN_HEADER[ii];
|
||||
break;
|
||||
}
|
||||
}
|
||||
headers[name] = value;
|
||||
}
|
||||
if(headers.isUndefined()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string LLMimeParser::Impl::findSeparator(std::string header)
|
||||
{
|
||||
// 01234567890
|
||||
//Content-Type: multipart/mixed; boundary="segment"
|
||||
std::string separator;
|
||||
std::string::size_type pos = header.find(BOUNDARY);
|
||||
if(std::string::npos == pos) return separator;
|
||||
pos += BOUNDARY.size() + 1;
|
||||
std::string::size_type end;
|
||||
if(header[pos] == '"')
|
||||
{
|
||||
// the boundary is quoted, find the end from pos, and take the
|
||||
// substring.
|
||||
end = header.find('"', ++pos);
|
||||
if(std::string::npos == end)
|
||||
{
|
||||
// poorly formed boundary.
|
||||
mError = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise, it's every character until a whitespace, end of
|
||||
// line, or another parameter begins.
|
||||
end = header.find_first_of(END_OF_CONTENT_PARAMETER, pos);
|
||||
if(std::string::npos == end)
|
||||
{
|
||||
// it goes to the end of the string.
|
||||
end = header.size();
|
||||
}
|
||||
}
|
||||
if(!mError) separator = header.substr(pos, end - pos);
|
||||
return separator;
|
||||
}
|
||||
|
||||
void LLMimeParser::Impl::scanPastSeparator(
|
||||
std::istream& istr,
|
||||
S32 limit,
|
||||
const std::string& sep)
|
||||
{
|
||||
std::ostringstream ostr;
|
||||
ostr << SEPARATOR_PREFIX << sep;
|
||||
std::string separator = ostr.str();
|
||||
bool found_separator = false;
|
||||
while(!found_separator && continueParse())
|
||||
{
|
||||
// Subtract 1 from the limit so that we make sure not to read
|
||||
// past limit when we get() the newline.
|
||||
S32 max_get = llmin((S32)LINE_BUFFER_LENGTH, limit - mScanCount - 1);
|
||||
istr.getline(mBuffer, max_get, '\r');
|
||||
mScanCount += (S32)istr.gcount();
|
||||
if(istr.gcount() >= LINE_BUFFER_LENGTH - 1)
|
||||
{
|
||||
// that's way too long to be a separator, so ignore it.
|
||||
continue;
|
||||
}
|
||||
int c = istr.get();
|
||||
if(EOF == c)
|
||||
{
|
||||
mContinue = false;
|
||||
return;
|
||||
}
|
||||
++mScanCount;
|
||||
if(c != '\n')
|
||||
{
|
||||
mError = true;
|
||||
return;
|
||||
}
|
||||
if(mScanCount >= limit)
|
||||
{
|
||||
mContinue = false;
|
||||
}
|
||||
if(0 == LLStringUtil::compareStrings(std::string(mBuffer), separator))
|
||||
{
|
||||
found_separator = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLMimeParser::Impl::scanPastContent(
|
||||
std::istream& istr,
|
||||
S32 limit,
|
||||
LLSD headers,
|
||||
const std::string separator)
|
||||
{
|
||||
if(headers.has(CONTENT_LENGTH))
|
||||
{
|
||||
S32 content_length = headers[CONTENT_LENGTH].asInteger();
|
||||
// Subtract 2 here for the \r\n after the content.
|
||||
S32 max_skip = llmin(content_length, limit - mScanCount - 2);
|
||||
istr.ignore(max_skip);
|
||||
mScanCount += max_skip;
|
||||
|
||||
// *NOTE: Check for hitting the limit and eof here before
|
||||
// checking for the trailing EOF, because our mime parser has
|
||||
// to gracefully handle incomplete mime entites.
|
||||
if((mScanCount >= limit) || istr.eof())
|
||||
{
|
||||
mContinue = false;
|
||||
}
|
||||
else if(!eatCRLF(istr))
|
||||
{
|
||||
mError = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LLMimeParser::Impl::eatCRLF(std::istream& istr)
|
||||
{
|
||||
int c = istr.get();
|
||||
++mScanCount;
|
||||
if(c != '\r')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
c = istr.get();
|
||||
++mScanCount;
|
||||
if(c != '\n')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
LLMimeParser::LLMimeParser() : mImpl(* new LLMimeParser::Impl)
|
||||
{
|
||||
}
|
||||
|
||||
LLMimeParser::~LLMimeParser()
|
||||
{
|
||||
delete & mImpl;
|
||||
}
|
||||
|
||||
void LLMimeParser::reset()
|
||||
{
|
||||
mImpl.reset();
|
||||
}
|
||||
|
||||
bool LLMimeParser::parseIndex(std::istream& istr, LLMimeIndex& index)
|
||||
{
|
||||
std::string separator;
|
||||
return mImpl.parseIndex(istr, S32_MAX, separator, false, index);
|
||||
}
|
||||
|
||||
bool LLMimeParser::parseIndex(
|
||||
const std::vector<U8>& buffer,
|
||||
LLMimeIndex& index)
|
||||
{
|
||||
LLMemoryStream mstr(&buffer[0], buffer.size());
|
||||
return parseIndex(mstr, buffer.size() + 1, index);
|
||||
}
|
||||
|
||||
bool LLMimeParser::parseIndex(
|
||||
std::istream& istr,
|
||||
S32 limit,
|
||||
LLMimeIndex& index)
|
||||
{
|
||||
std::string separator;
|
||||
return mImpl.parseIndex(istr, limit, separator, false, index);
|
||||
}
|
||||
|
||||
bool LLMimeParser::parseIndex(const U8* buffer, S32 length, LLMimeIndex& index)
|
||||
{
|
||||
LLMemoryStream mstr(buffer, length);
|
||||
return parseIndex(mstr, length + 1, index);
|
||||
}
|
||||
|
||||
/*
|
||||
bool LLMimeParser::verify(std::istream& isr, LLMimeIndex& index) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LLMimeParser::verify(U8* buffer, S32 length, LLMimeIndex& index) const
|
||||
{
|
||||
LLMemoryStream mstr(buffer, length);
|
||||
return verify(mstr, index);
|
||||
}
|
||||
*/
|
||||
|
|
@ -1,292 +0,0 @@
|
|||
/**
|
||||
* @file llmime.h
|
||||
* @author Phoenix
|
||||
* @date 2006-12-20
|
||||
* @brief Declaration of mime tools.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2006&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 LL_LLMIME_H
|
||||
#define LL_LLMIME_H
|
||||
|
||||
#include <string>
|
||||
#include "llsd.h"
|
||||
|
||||
/**
|
||||
* This file declares various tools for parsing and creating MIME
|
||||
* objects as described in RFCs 2045, 2046, 2047, 2048, and 2049.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class LLMimeIndex
|
||||
* @brief Skeletal information useful for handling mime packages.
|
||||
* @see LLMimeParser
|
||||
*
|
||||
* An instance of this class is the parsed output from a LLMimeParser
|
||||
* which then allows for easy access into a data stream to find and
|
||||
* get what you want out of it.
|
||||
*
|
||||
* This class meant as a tool to quickly find what you seek in a
|
||||
* parsed mime entity. As such, it does not have useful support for
|
||||
* modification of a mime entity and specializes the interface toward
|
||||
* querying data from a fixed mime entity. Modifying an instance of
|
||||
* LLMimeIndx does not alter a mime entity and changes to a mime
|
||||
* entity itself are not propogated into an instance of a LLMimeIndex.
|
||||
*
|
||||
* Usage:<br>
|
||||
* LLMimeIndex mime_index;<br>
|
||||
* std::ifstream fstr("package.mime", ios::binary);<br>
|
||||
* LLMimeParser parser;<br>
|
||||
* if(parser.parseIndex(fstr, mime_index))<br>
|
||||
* {<br>
|
||||
* std::vector<U8> content;<br>
|
||||
* content.resize(mime_index.contentLength());<br>
|
||||
* fstr.seekg(mime_index.offset(), ios::beg);<br>
|
||||
* // ...do work on fstr and content<br>
|
||||
* }<br>
|
||||
*/
|
||||
class LLMimeIndex
|
||||
{
|
||||
public:
|
||||
/* @name Client interface.
|
||||
*/
|
||||
//@{
|
||||
/**
|
||||
* @brief Get the full parsed headers for this.
|
||||
*
|
||||
* If there are any headers, it will be a map of header name to
|
||||
* the value found on the line. The name is everything before the
|
||||
* colon, and the value is the string found after the colon to the
|
||||
* end of the line after trimming leading whitespace. So, for
|
||||
* example:
|
||||
* Content-Type: text/plain
|
||||
* would become an entry in the headers of:
|
||||
* headers["Content-Type"] == "text/plain"
|
||||
*
|
||||
* If this instance of an index was generated by the
|
||||
* LLMimeParser::parseIndex() call, all header names in rfc2045
|
||||
* will be capitalized as in rfc, eg Content-Length and
|
||||
* MIME-Version, not content-length and mime-version.
|
||||
* @return Returns an LLSD map of header name to value. Returns
|
||||
* undef if there are no headers.
|
||||
*/
|
||||
LLSD headers() const;
|
||||
|
||||
/**
|
||||
* @brief Get the content offset.
|
||||
*
|
||||
* @return Returns the number of bytes to the start of the data
|
||||
* segment from the start of serialized mime entity. Returns -1 if
|
||||
* offset is not known.
|
||||
*/
|
||||
S32 offset() const;
|
||||
|
||||
/**
|
||||
* @brief Get the length of the data segment for this mime part.
|
||||
*
|
||||
* @return Returns the content length in bytes. Returns -1 if
|
||||
* length is not known.
|
||||
*/
|
||||
S32 contentLength() const;
|
||||
|
||||
/**
|
||||
* @brief Get the mime type associated with this node.
|
||||
*
|
||||
* @return Returns the mimetype.
|
||||
*/
|
||||
std::string contentType() const;
|
||||
|
||||
/**
|
||||
* @brief Helper method which simplifies parsing the return from type()
|
||||
*
|
||||
* @return Returns true if this is a multipart mime, and therefore
|
||||
* getting subparts will succeed.
|
||||
*/
|
||||
bool isMultipart() const;
|
||||
|
||||
/**
|
||||
* @brief Get the number of atachments.
|
||||
*
|
||||
* @return Returns the number of sub-parts for this.
|
||||
*/
|
||||
S32 subPartCount() const;
|
||||
|
||||
/**
|
||||
* @brief Get the indicated attachment.
|
||||
*
|
||||
* @param index Value from 0 to (subPartCount() - 1).
|
||||
* @return Returns the indicated sub-part, or an invalid mime
|
||||
* index on failure.
|
||||
*/
|
||||
LLMimeIndex subPart(S32 index) const;
|
||||
//@}
|
||||
|
||||
/* @name Interface for building, testing, and helpers for typical use.
|
||||
*/
|
||||
//@{
|
||||
/**
|
||||
* @brief Default constructor - creates a useless LLMimeIndex.
|
||||
*/
|
||||
LLMimeIndex();
|
||||
|
||||
/**
|
||||
* @brief Full constructor.
|
||||
*
|
||||
* @param headers The complete headers.
|
||||
* @param content_offset The number of bytes to the start of the
|
||||
* data segment of this mime entity from the start of the stream
|
||||
* or buffer.
|
||||
*/
|
||||
LLMimeIndex(LLSD headers, S32 content_offset);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
*
|
||||
* @param mime The other mime object.
|
||||
*/
|
||||
LLMimeIndex(const LLMimeIndex& mime);
|
||||
|
||||
// @brief Destructor.
|
||||
~LLMimeIndex();
|
||||
|
||||
/*
|
||||
* @breif Assignment operator.
|
||||
*
|
||||
* @param mime The other mime object.
|
||||
* @return Returns this after assignment.
|
||||
*/
|
||||
LLMimeIndex& operator=(const LLMimeIndex& mime);
|
||||
|
||||
/**
|
||||
* @brief Add attachment information as a sub-part to a multipart mime.
|
||||
*
|
||||
* @param sub_part the part to attach.
|
||||
* @return Returns true on success, false on failure.
|
||||
*/
|
||||
bool attachSubPart(LLMimeIndex sub_part);
|
||||
//@}
|
||||
|
||||
protected:
|
||||
// Implementation.
|
||||
class Impl;
|
||||
Impl* mImpl;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @class LLMimeParser
|
||||
* @brief This class implements a MIME parser and verifier.
|
||||
*
|
||||
* THOROUGH_DESCRIPTION
|
||||
*/
|
||||
class LLMimeParser
|
||||
{
|
||||
public:
|
||||
// @brief Make a new mime parser.
|
||||
LLMimeParser();
|
||||
|
||||
// @brief Mime parser Destructor.
|
||||
~LLMimeParser();
|
||||
|
||||
// @brief Reset internal state of this parser.
|
||||
void reset();
|
||||
|
||||
|
||||
/* @name Index generation interface.
|
||||
*/
|
||||
//@{
|
||||
/**
|
||||
* @brief Parse a stream to find the mime index information.
|
||||
*
|
||||
* This method will scan the istr until a single complete mime
|
||||
* entity is read or EOF. The istr will be modified by this
|
||||
* parsing, so pass in a temporary stream or rewind/reset the
|
||||
* stream after this call.
|
||||
* @param istr An istream which contains a mime entity.
|
||||
* @param index[out] The parsed output.
|
||||
* @return Returns true if an index was parsed and no errors occurred.
|
||||
*/
|
||||
bool parseIndex(std::istream& istr, LLMimeIndex& index);
|
||||
|
||||
/**
|
||||
* @brief Parse a vector to find the mime index information.
|
||||
*
|
||||
* @param buffer A vector with data to parse.
|
||||
* @param index[out] The parsed output.
|
||||
* @return Returns true if an index was parsed and no errors occurred.
|
||||
*/
|
||||
bool parseIndex(const std::vector<U8>& buffer, LLMimeIndex& index);
|
||||
|
||||
/**
|
||||
* @brief Parse a stream to find the mime index information.
|
||||
*
|
||||
* This method will scan the istr until a single complete mime
|
||||
* entity is read, an EOF, or limit bytes have been scanned. The
|
||||
* istr will be modified by this parsing, so pass in a temporary
|
||||
* stream or rewind/reset the stream after this call.
|
||||
* @param istr An istream which contains a mime entity.
|
||||
* @param limit The maximum number of bytes to scan.
|
||||
* @param index[out] The parsed output.
|
||||
* @return Returns true if an index was parsed and no errors occurred.
|
||||
*/
|
||||
bool parseIndex(std::istream& istr, S32 limit, LLMimeIndex& index);
|
||||
|
||||
/**
|
||||
* @brief Parse a memory bufffer to find the mime index information.
|
||||
*
|
||||
* @param buffer The start of the buffer to parse.
|
||||
* @param buffer_length The length of the buffer.
|
||||
* @param index[out] The parsed output.
|
||||
* @return Returns true if an index was parsed and no errors occurred.
|
||||
*/
|
||||
bool parseIndex(const U8* buffer, S32 buffer_length, LLMimeIndex& index);
|
||||
//@}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
//bool verify(std::istream& istr, LLMimeIndex& index) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
//bool verify(U8* buffer, S32 buffer_length, LLMimeIndex& index) const;
|
||||
|
||||
protected:
|
||||
// Implementation.
|
||||
class Impl;
|
||||
Impl& mImpl;
|
||||
|
||||
private:
|
||||
// @brief Not implemneted to prevent copy consturction.
|
||||
LLMimeParser(const LLMimeParser& parser);
|
||||
|
||||
// @brief Not implemneted to prevent assignment.
|
||||
LLMimeParser& operator=(const LLMimeParser& mime);
|
||||
};
|
||||
|
||||
#endif // LL_LLMIME_H
|
||||
|
|
@ -1,153 +0,0 @@
|
|||
/**
|
||||
* @file llregionpresenceverifier.cpp
|
||||
* @brief
|
||||
*
|
||||
* $LicenseInfo:firstyear=2008&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 "llregionpresenceverifier.h"
|
||||
#include "llhttpclientinterface.h"
|
||||
#include <sstream>
|
||||
#include "net.h"
|
||||
#include "message.h"
|
||||
|
||||
//namespace boost
|
||||
//{
|
||||
void intrusive_ptr_add_ref(LLRegionPresenceVerifier::Response* p)
|
||||
{
|
||||
nd::intrin::FAA( &p->mReferenceCount );
|
||||
}
|
||||
|
||||
void intrusive_ptr_release(LLRegionPresenceVerifier::Response* p)
|
||||
{
|
||||
if(p && 0 == nd::intrin::FAD( &p->mReferenceCount ))
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
//};
|
||||
|
||||
LLRegionPresenceVerifier::Response::~Response()
|
||||
{
|
||||
}
|
||||
|
||||
LLRegionPresenceVerifier::RegionResponder::RegionResponder(const std::string&
|
||||
uri,
|
||||
ResponsePtr data,
|
||||
S32 retry_count) :
|
||||
mUri(uri),
|
||||
mSharedData(data),
|
||||
mRetryCount(retry_count)
|
||||
{
|
||||
}
|
||||
|
||||
//virtual
|
||||
LLRegionPresenceVerifier::RegionResponder::~RegionResponder()
|
||||
{
|
||||
}
|
||||
|
||||
void LLRegionPresenceVerifier::RegionResponder::result(const LLSD& content)
|
||||
{
|
||||
std::string host = content["private_host"].asString();
|
||||
U32 port = content["private_port"].asInteger();
|
||||
LLHost destination(host, port);
|
||||
LLUUID id = content["region_id"];
|
||||
|
||||
LL_DEBUGS() << "Verifying " << destination.getString() << " is region " << id << LL_ENDL;
|
||||
|
||||
std::stringstream uri;
|
||||
uri << "http://" << destination.getString() << "/state/basic/";
|
||||
mSharedData->getHttpClient().get(
|
||||
uri.str(),
|
||||
new VerifiedDestinationResponder(mUri, mSharedData, content, mRetryCount));
|
||||
}
|
||||
|
||||
void LLRegionPresenceVerifier::RegionResponder::error(U32 status,
|
||||
const std::string& reason)
|
||||
{
|
||||
// TODO: babbage: distinguish between region presence service and
|
||||
// region verification errors?
|
||||
mSharedData->onRegionVerificationFailed();
|
||||
}
|
||||
|
||||
LLRegionPresenceVerifier::VerifiedDestinationResponder::VerifiedDestinationResponder(const std::string& uri, ResponsePtr data, const LLSD& content,
|
||||
S32 retry_count):
|
||||
mUri(uri),
|
||||
mSharedData(data),
|
||||
mContent(content),
|
||||
mRetryCount(retry_count)
|
||||
{
|
||||
}
|
||||
|
||||
//virtual
|
||||
LLRegionPresenceVerifier::VerifiedDestinationResponder::~VerifiedDestinationResponder()
|
||||
{
|
||||
}
|
||||
|
||||
void LLRegionPresenceVerifier::VerifiedDestinationResponder::result(const LLSD& content)
|
||||
{
|
||||
LLUUID actual_region_id = content["region_id"];
|
||||
LLUUID expected_region_id = mContent["region_id"];
|
||||
|
||||
LL_DEBUGS() << "Actual region: " << content << LL_ENDL;
|
||||
LL_DEBUGS() << "Expected region: " << mContent << LL_ENDL;
|
||||
|
||||
if (mSharedData->checkValidity(content) &&
|
||||
(actual_region_id == expected_region_id))
|
||||
{
|
||||
mSharedData->onRegionVerified(mContent);
|
||||
}
|
||||
else if (mRetryCount > 0)
|
||||
{
|
||||
retry();
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS() << "Simulator verification failed. Region: " << mUri << LL_ENDL;
|
||||
mSharedData->onRegionVerificationFailed();
|
||||
}
|
||||
}
|
||||
|
||||
void LLRegionPresenceVerifier::VerifiedDestinationResponder::retry()
|
||||
{
|
||||
LLSD headers;
|
||||
headers["Cache-Control"] = "no-cache, max-age=0";
|
||||
LL_INFOS() << "Requesting region information, get uncached for region "
|
||||
<< mUri << LL_ENDL;
|
||||
--mRetryCount;
|
||||
mSharedData->getHttpClient().get(mUri, new RegionResponder(mUri, mSharedData, mRetryCount), headers);
|
||||
}
|
||||
|
||||
void LLRegionPresenceVerifier::VerifiedDestinationResponder::error(U32 status, const std::string& reason)
|
||||
{
|
||||
if(mRetryCount > 0)
|
||||
{
|
||||
retry();
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS() << "Failed to contact simulator for verification. Region: " << mUri << LL_ENDL;
|
||||
mSharedData->onRegionVerificationFailed();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
/**
|
||||
* @file llregionpresenceverifier.cpp
|
||||
* @brief
|
||||
*
|
||||
* $LicenseInfo:firstyear=2008&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$
|
||||
*/
|
||||
|
||||
/* Macro Definitions */
|
||||
#ifndef LL_LLREGIONPRESENCEVERIFIER_H
|
||||
#define LL_LLREGIONPRESENCEVERIFIER_H
|
||||
|
||||
#include "llhttpclient.h"
|
||||
#include <string>
|
||||
#include "llsd.h"
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
|
||||
class LLHTTPClientInterface;
|
||||
|
||||
class LLRegionPresenceVerifier
|
||||
{
|
||||
public:
|
||||
class Response
|
||||
{
|
||||
public:
|
||||
virtual ~Response() = 0;
|
||||
|
||||
virtual bool checkValidity(const LLSD& content) const = 0;
|
||||
virtual void onRegionVerified(const LLSD& region_details) = 0;
|
||||
virtual void onRegionVerificationFailed() = 0;
|
||||
|
||||
virtual LLHTTPClientInterface& getHttpClient() = 0;
|
||||
|
||||
public: /* but not really -- don't touch this */
|
||||
// U32 mReferenceCount;
|
||||
volatile U32 mReferenceCount;
|
||||
};
|
||||
|
||||
typedef boost::intrusive_ptr<Response> ResponsePtr;
|
||||
|
||||
class RegionResponder : public LLHTTPClient::Responder
|
||||
{
|
||||
public:
|
||||
RegionResponder(const std::string& uri, ResponsePtr data,
|
||||
S32 retry_count);
|
||||
virtual ~RegionResponder();
|
||||
virtual void result(const LLSD& content);
|
||||
virtual void error(U32 status, const std::string& reason);
|
||||
|
||||
private:
|
||||
ResponsePtr mSharedData;
|
||||
std::string mUri;
|
||||
S32 mRetryCount;
|
||||
};
|
||||
|
||||
class VerifiedDestinationResponder : public LLHTTPClient::Responder
|
||||
{
|
||||
public:
|
||||
VerifiedDestinationResponder(const std::string& uri, ResponsePtr data,
|
||||
const LLSD& content, S32 retry_count);
|
||||
virtual ~VerifiedDestinationResponder();
|
||||
virtual void result(const LLSD& content);
|
||||
|
||||
virtual void error(U32 status, const std::string& reason);
|
||||
|
||||
private:
|
||||
void retry();
|
||||
ResponsePtr mSharedData;
|
||||
LLSD mContent;
|
||||
std::string mUri;
|
||||
S32 mRetryCount;
|
||||
};
|
||||
};
|
||||
|
||||
//namespace boost
|
||||
//{
|
||||
void intrusive_ptr_add_ref(LLRegionPresenceVerifier::Response* p);
|
||||
void intrusive_ptr_release(LLRegionPresenceVerifier::Response* p);
|
||||
//};
|
||||
|
||||
#endif //LL_LLREGIONPRESENCEVERIFIER_H
|
||||
|
|
@ -121,7 +121,7 @@ public:
|
|||
{
|
||||
//LL_INFOS() << "validate: " << name << ", "
|
||||
// << LLSDOStreamer<LLSDNotationFormatter>(context) << LL_ENDL;
|
||||
if((std::string("PUT") == context["request"]["verb"].asString()) && !name.empty())
|
||||
if((std::string("PUT") == context[CONTEXT_REQUEST][CONTEXT_VERB].asString()) && !name.empty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -139,7 +139,7 @@ public:
|
|||
LLHTTPNode::ResponsePtr response,
|
||||
const LLSD& context) const
|
||||
{
|
||||
std::string name = context["request"]["wildcard"]["option-name"];
|
||||
std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"];
|
||||
LLSD options = LLApp::instance()->getOptionData(
|
||||
LLApp::PRIORITY_RUNTIME_OVERRIDE);
|
||||
response->result(options[name]);
|
||||
|
|
@ -150,7 +150,7 @@ public:
|
|||
const LLSD& context,
|
||||
const LLSD& input) const
|
||||
{
|
||||
std::string name = context["request"]["wildcard"]["option-name"];
|
||||
std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"];
|
||||
LLSD options = LLApp::instance()->getOptionData(
|
||||
LLApp::PRIORITY_RUNTIME_OVERRIDE);
|
||||
options[name] = input;
|
||||
|
|
@ -164,7 +164,7 @@ public:
|
|||
LLHTTPNode::ResponsePtr response,
|
||||
const LLSD& context) const
|
||||
{
|
||||
std::string name = context["request"]["wildcard"]["option-name"];
|
||||
std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"];
|
||||
LLSD options = LLApp::instance()->getOptionData(
|
||||
LLApp::PRIORITY_RUNTIME_OVERRIDE);
|
||||
options.erase(name);
|
||||
|
|
@ -268,7 +268,7 @@ public:
|
|||
LLHTTPNode::ResponsePtr response,
|
||||
const LLSD& context) const
|
||||
{
|
||||
std::string name = context["request"]["wildcard"]["option-name"];
|
||||
std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"];
|
||||
response->result(LLApp::instance()->getOption(name));
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ public:
|
|||
|
||||
virtual void get(ResponsePtr response, const LLSD& context) const
|
||||
{
|
||||
const LLSD& remainder = context["request"]["remainder"];
|
||||
const LLSD& remainder = context[CONTEXT_REQUEST]["remainder"];
|
||||
|
||||
if (remainder.size() > 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -92,14 +92,14 @@ bool LLSDMessage::httpListener(const LLSD& request)
|
|||
return false;
|
||||
}
|
||||
|
||||
void LLSDMessage::EventResponder::result(const LLSD& data)
|
||||
void LLSDMessage::EventResponder::httpSuccess()
|
||||
{
|
||||
// If our caller passed an empty replyPump name, they're not
|
||||
// listening: this is a fire-and-forget message. Don't bother posting
|
||||
// to the pump whose name is "".
|
||||
if (! mReplyPump.empty())
|
||||
{
|
||||
LLSD response(data);
|
||||
LLSD response(getContent());
|
||||
mReqID.stamp(response);
|
||||
mPumps.obtain(mReplyPump).post(response);
|
||||
}
|
||||
|
|
@ -111,7 +111,7 @@ void LLSDMessage::EventResponder::result(const LLSD& data)
|
|||
}
|
||||
}
|
||||
|
||||
void LLSDMessage::EventResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content)
|
||||
void LLSDMessage::EventResponder::httpFailure()
|
||||
{
|
||||
// If our caller passed an empty errorPump name, they're not
|
||||
// listening: "default error handling is acceptable." Only post to an
|
||||
|
|
@ -121,9 +121,9 @@ void LLSDMessage::EventResponder::errorWithContent(U32 status, const std::string
|
|||
LLSD info(mReqID.makeResponse());
|
||||
info["target"] = mTarget;
|
||||
info["message"] = mMessage;
|
||||
info["status"] = LLSD::Integer(status);
|
||||
info["reason"] = reason;
|
||||
info["content"] = content;
|
||||
info["status"] = getStatus();
|
||||
info["reason"] = getReason();
|
||||
info["content"] = getContent();
|
||||
mPumps.obtain(mErrorPump).post(info);
|
||||
}
|
||||
else // default error handling
|
||||
|
|
@ -131,9 +131,7 @@ void LLSDMessage::EventResponder::errorWithContent(U32 status, const std::string
|
|||
// convention seems to be to use LL_INFOS(), but that seems a bit casual?
|
||||
LL_WARNS("LLSDMessage::EventResponder")
|
||||
<< "'" << mMessage << "' to '" << mTarget
|
||||
<< "' failed with code " << status << ": " << reason << '\n'
|
||||
<< ll_pretty_print_sd(content)
|
||||
<< LL_ENDL;
|
||||
<< "' failed " << dumpResponse() << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -151,11 +149,11 @@ bool LLSDMessage::ResponderAdapter::listener(const LLSD& payload, bool success)
|
|||
{
|
||||
if (success)
|
||||
{
|
||||
mResponder->result(payload);
|
||||
mResponder->successResult(payload);
|
||||
}
|
||||
else
|
||||
{
|
||||
mResponder->errorWithContent(payload["status"].asInteger(), payload["reason"], payload["content"]);
|
||||
mResponder->failureResult(payload["status"].asInteger(), payload["reason"], payload["content"]);
|
||||
}
|
||||
|
||||
/*---------------- MUST BE LAST STATEMENT BEFORE RETURN ----------------*/
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@ private:
|
|||
/// LLCapabilityListener. Others should use higher-level APIs.
|
||||
class EventResponder: public LLHTTPClient::Responder
|
||||
{
|
||||
LOG_CLASS(EventResponder);
|
||||
public:
|
||||
/**
|
||||
* LLHTTPClient::Responder that dispatches via named LLEventPump instances.
|
||||
|
|
@ -149,8 +150,9 @@ private:
|
|||
mErrorPump(errorPump)
|
||||
{}
|
||||
|
||||
virtual void result(const LLSD& data);
|
||||
virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
|
||||
protected:
|
||||
virtual void httpSuccess();
|
||||
virtual void httpFailure();
|
||||
|
||||
private:
|
||||
LLEventPumps& mPumps;
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ public:
|
|||
virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
|
||||
{
|
||||
LL_DEBUGS() << "LLSDRPCClientFactory::build" << LL_ENDL;
|
||||
LLURLRequest* http(new LLURLRequest(LLURLRequest::HTTP_POST));
|
||||
LLURLRequest* http(new LLURLRequest(HTTP_POST));
|
||||
if(!http->isValid())
|
||||
{
|
||||
LL_WARNS() << "Creating LLURLRequest failed." << LL_ENDL ;
|
||||
|
|
@ -251,7 +251,7 @@ public:
|
|||
LLIOPipe::ptr_t service(new Client);
|
||||
chain.push_back(service);
|
||||
LLIOPipe::ptr_t http_pipe(http);
|
||||
http->addHeader("Content-Type: text/llsd");
|
||||
http->addHeader(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_LLSD);
|
||||
if(mURL.empty())
|
||||
{
|
||||
chain.push_back(LLIOPipe::ptr_t(new LLContextURLExtractor(http)));
|
||||
|
|
@ -291,7 +291,7 @@ public:
|
|||
{
|
||||
LL_DEBUGS() << "LLXMLSDRPCClientFactory::build" << LL_ENDL;
|
||||
|
||||
LLURLRequest* http(new LLURLRequest(LLURLRequest::HTTP_POST));
|
||||
LLURLRequest* http(new LLURLRequest(HTTP_POST));
|
||||
if(!http->isValid())
|
||||
{
|
||||
LL_WARNS() << "Creating LLURLRequest failed." << LL_ENDL ;
|
||||
|
|
@ -301,7 +301,7 @@ public:
|
|||
LLIOPipe::ptr_t service(new Client);
|
||||
chain.push_back(service);
|
||||
LLIOPipe::ptr_t http_pipe(http);
|
||||
http->addHeader("Content-Type: text/xml");
|
||||
http->addHeader(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML);
|
||||
if(mURL.empty())
|
||||
{
|
||||
chain.push_back(LLIOPipe::ptr_t(new LLContextURLExtractor(http)));
|
||||
|
|
|
|||
|
|
@ -42,9 +42,9 @@ void LLTrustedMessageService::post(LLHTTPNode::ResponsePtr response,
|
|||
const LLSD& context,
|
||||
const LLSD& input) const
|
||||
{
|
||||
std::string name = context["request"]["wildcard"]["message-name"];
|
||||
std::string senderIP = context["request"]["remote-host"];
|
||||
std::string senderPort = context["request"]["headers"]
|
||||
std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["message-name"];
|
||||
std::string senderIP = context[CONTEXT_REQUEST][CONTEXT_REMOTE_HOST];
|
||||
std::string senderPort = context[CONTEXT_REQUEST][CONTEXT_HEADERS]
|
||||
["x-secondlife-udp-listen-port"];
|
||||
|
||||
LLSD message_data;
|
||||
|
|
@ -64,7 +64,7 @@ void LLTrustedMessageService::post(LLHTTPNode::ResponsePtr response,
|
|||
LL_WARNS("Messaging") << "trusted message POST to /trusted-message/"
|
||||
<< name << " from unknown or untrusted sender "
|
||||
<< sender << LL_ENDL;
|
||||
response->status(403, "Unknown or untrusted sender");
|
||||
response->status(HTTP_FORBIDDEN, "Unknown or untrusted sender");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -30,6 +30,10 @@
|
|||
#include "linden_common.h"
|
||||
#include "llhttpnode.h"
|
||||
|
||||
// These are defined in lliosocket.h/lliosocket.cpp
|
||||
extern const std::string CONTEXT_REMOTE_HOST;
|
||||
extern const std::string CONTEXT_REMOTE_PORT;
|
||||
|
||||
class LLSD;
|
||||
|
||||
class LLTrustedMessageService
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@
|
|||
#include "llstring.h"
|
||||
#include "apr_env.h"
|
||||
#include "llapr.h"
|
||||
static const U32 HTTP_STATUS_PIPE_ERROR = 499;
|
||||
|
||||
/**
|
||||
* String constants
|
||||
|
|
@ -49,11 +48,12 @@ static const U32 HTTP_STATUS_PIPE_ERROR = 499;
|
|||
const std::string CONTEXT_DEST_URI_SD_LABEL("dest_uri");
|
||||
const std::string CONTEXT_TRANSFERED_BYTES("transfered_bytes");
|
||||
|
||||
// These are defined in llhttpnode.h/llhttpnode.cpp
|
||||
extern const std::string CONTEXT_REQUEST;
|
||||
extern const std::string CONTEXT_RESPONSE;
|
||||
|
||||
static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* class LLURLRequestDetail
|
||||
*/
|
||||
|
|
@ -150,27 +150,8 @@ CURLcode LLURLRequest::_sslCtxCallback(CURL * curl, void *sslctx, void *param)
|
|||
* class LLURLRequest
|
||||
*/
|
||||
|
||||
// static
|
||||
std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action)
|
||||
{
|
||||
static const std::string VERBS[] =
|
||||
{
|
||||
"(invalid)",
|
||||
"HEAD",
|
||||
"GET",
|
||||
"PUT",
|
||||
"POST",
|
||||
"DELETE",
|
||||
"MOVE"
|
||||
};
|
||||
if(((S32)action <=0) || ((S32)action >= REQUEST_ACTION_COUNT))
|
||||
{
|
||||
return VERBS[0];
|
||||
}
|
||||
return VERBS[action];
|
||||
}
|
||||
|
||||
LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, bool follow_redirects /* = true */) :
|
||||
LLURLRequest::LLURLRequest(EHTTPMethod action, bool follow_redirects /* = true */) :
|
||||
mAction(action),
|
||||
mFollowRedirects(follow_redirects)
|
||||
{
|
||||
|
|
@ -178,7 +159,7 @@ LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, bool follow_redi
|
|||
}
|
||||
|
||||
LLURLRequest::LLURLRequest(
|
||||
LLURLRequest::ERequestAction action,
|
||||
EHTTPMethod action,
|
||||
const std::string& url,
|
||||
bool follow_redirects /* = true */) :
|
||||
mAction(action),
|
||||
|
|
@ -203,12 +184,17 @@ void LLURLRequest::setURL(const std::string& url)
|
|||
}
|
||||
}
|
||||
|
||||
std::string LLURLRequest::getURL() const
|
||||
const std::string& LLURLRequest::getURL() const
|
||||
{
|
||||
return mDetail->mURL;
|
||||
}
|
||||
|
||||
void LLURLRequest::addHeader(const char* header)
|
||||
void LLURLRequest::addHeader(const std::string& header, const std::string& value /* = "" */)
|
||||
{
|
||||
mDetail->mCurlRequest->slist_append(header, value);
|
||||
}
|
||||
|
||||
void LLURLRequest::addHeaderRaw(const char* header)
|
||||
{
|
||||
mDetail->mCurlRequest->slist_append(header);
|
||||
}
|
||||
|
|
@ -305,7 +291,7 @@ LLIOPipe::EStatus LLURLRequest::handleError(
|
|||
LLURLRequestComplete* complete = NULL;
|
||||
complete = (LLURLRequestComplete*)mCompletionCallback.get();
|
||||
complete->httpStatus(
|
||||
HTTP_STATUS_PIPE_ERROR,
|
||||
HTTP_INTERNAL_ERROR,
|
||||
LLIOPipe::lookupStatusString(status));
|
||||
complete->responseStatus(status);
|
||||
pump->respond(complete);
|
||||
|
|
@ -533,21 +519,32 @@ bool LLURLRequest::configure()
|
|||
case HTTP_PUT:
|
||||
// Disable the expect http 1.1 extension. POST and PUT default
|
||||
// to turning this on, and I am not too sure what it means.
|
||||
addHeader("Expect:");
|
||||
addHeader(HTTP_OUT_HEADER_EXPECT);
|
||||
|
||||
mDetail->mCurlRequest->setopt(CURLOPT_UPLOAD, 1);
|
||||
mDetail->mCurlRequest->setopt(CURLOPT_INFILESIZE, bytes);
|
||||
rv = true;
|
||||
break;
|
||||
|
||||
case HTTP_PATCH:
|
||||
// Disable the expect http 1.1 extension. POST and PUT default
|
||||
// to turning this on, and I am not too sure what it means.
|
||||
addHeader(HTTP_OUT_HEADER_EXPECT);
|
||||
|
||||
mDetail->mCurlRequest->setopt(CURLOPT_UPLOAD, 1);
|
||||
mDetail->mCurlRequest->setopt(CURLOPT_INFILESIZE, bytes);
|
||||
mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "PATCH");
|
||||
rv = true;
|
||||
break;
|
||||
|
||||
case HTTP_POST:
|
||||
// Disable the expect http 1.1 extension. POST and PUT default
|
||||
// to turning this on, and I am not too sure what it means.
|
||||
addHeader("Expect:");
|
||||
addHeader(HTTP_OUT_HEADER_EXPECT);
|
||||
|
||||
// Disable the content type http header.
|
||||
// *FIX: what should it be?
|
||||
addHeader("Content-Type:");
|
||||
addHeader(HTTP_OUT_HEADER_CONTENT_TYPE);
|
||||
|
||||
// Set the handle for an http post
|
||||
mDetail->mCurlRequest->setPost(NULL, bytes);
|
||||
|
|
@ -558,13 +555,19 @@ bool LLURLRequest::configure()
|
|||
break;
|
||||
|
||||
case HTTP_DELETE:
|
||||
// Set the handle for an http post
|
||||
// Set the handle for an http delete
|
||||
mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "DELETE");
|
||||
rv = true;
|
||||
break;
|
||||
|
||||
case HTTP_COPY:
|
||||
// Set the handle for an http copy
|
||||
mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "COPY");
|
||||
rv = true;
|
||||
break;
|
||||
|
||||
case HTTP_MOVE:
|
||||
// Set the handle for an http post
|
||||
// Set the handle for an http move
|
||||
mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "MOVE");
|
||||
// *NOTE: should we check for the Destination header?
|
||||
rv = true;
|
||||
|
|
@ -677,7 +680,7 @@ static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user)
|
|||
S32 status_code = atoi(status.c_str());
|
||||
if (status_code > 0)
|
||||
{
|
||||
complete->httpStatus((U32)status_code, reason);
|
||||
complete->httpStatus(status_code, reason);
|
||||
return header_len;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,9 +42,10 @@
|
|||
#include "llcurl.h"
|
||||
|
||||
|
||||
extern const std::string CONTEXT_REQUEST;
|
||||
/**
|
||||
* External constants
|
||||
*/
|
||||
extern const std::string CONTEXT_DEST_URI_SD_LABEL;
|
||||
extern const std::string CONTEXT_RESPONSE;
|
||||
extern const std::string CONTEXT_TRANSFERED_BYTES;
|
||||
|
||||
class LLURLRequestDetail;
|
||||
|
|
@ -68,42 +69,22 @@ class LLURLRequest : public LLIOPipe
|
|||
{
|
||||
LOG_CLASS(LLURLRequest);
|
||||
public:
|
||||
|
||||
typedef int (* SSLCertVerifyCallback)(X509_STORE_CTX *ctx, void *param);
|
||||
/**
|
||||
* @brief This enumeration is for specifying the type of request.
|
||||
*/
|
||||
enum ERequestAction
|
||||
{
|
||||
INVALID,
|
||||
HTTP_HEAD,
|
||||
HTTP_GET,
|
||||
HTTP_PUT,
|
||||
HTTP_POST,
|
||||
HTTP_DELETE,
|
||||
HTTP_MOVE, // Caller will need to set 'Destination' header
|
||||
REQUEST_ACTION_COUNT
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Turn the requst action into an http verb.
|
||||
*/
|
||||
static std::string actionAsVerb(ERequestAction action);
|
||||
|
||||
/**
|
||||
* @brief Constructor.
|
||||
*
|
||||
* @param action One of the ERequestAction enumerations.
|
||||
* @param action One of the EHTTPMethod enumerations.
|
||||
*/
|
||||
LLURLRequest(ERequestAction action, bool follow_redirects = true);
|
||||
LLURLRequest(EHTTPMethod action, bool follow_redirects = true);
|
||||
|
||||
/**
|
||||
* @brief Constructor.
|
||||
*
|
||||
* @param action One of the ERequestAction enumerations.
|
||||
* @param action One of the EHTTPMethod enumerations.
|
||||
* @param url The url of the request. It should already be encoded.
|
||||
*/
|
||||
LLURLRequest(ERequestAction action, const std::string& url, bool follow_redirects = true);
|
||||
LLURLRequest(EHTTPMethod action, const std::string& url, bool follow_redirects = true);
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
|
|
@ -123,7 +104,7 @@ public:
|
|||
*
|
||||
*/
|
||||
void setURL(const std::string& url);
|
||||
std::string getURL() const;
|
||||
const std::string& getURL() const;
|
||||
|
||||
/**
|
||||
* @brief Set If-Modified-Since Attribute
|
||||
|
|
@ -137,13 +118,13 @@ public:
|
|||
/**
|
||||
* @brief Add a header to the http post.
|
||||
*
|
||||
* The header must be correctly formatted for HTTP requests. This
|
||||
* provides a raw interface if you know what kind of request you
|
||||
* This provides a raw interface if you know what kind of request you
|
||||
* will be making during construction of this instance. All
|
||||
* required headers will be automatically constructed, so this is
|
||||
* usually useful for encoding parameters.
|
||||
*/
|
||||
void addHeader(const char* header);
|
||||
void addHeader(const std::string& header, const std::string& value = "");
|
||||
void addHeaderRaw(const char* header);
|
||||
|
||||
/**
|
||||
* @brief Check remote server certificate signed by a known root CA.
|
||||
|
|
@ -228,7 +209,7 @@ protected:
|
|||
STATE_HAVE_RESPONSE,
|
||||
};
|
||||
EState mState;
|
||||
ERequestAction mAction;
|
||||
EHTTPMethod mAction;
|
||||
bool mFollowRedirects;
|
||||
LLURLRequestDetail* mDetail;
|
||||
LLIOPipe::ptr_t mCompletionCallback;
|
||||
|
|
@ -326,7 +307,7 @@ public:
|
|||
// May be called more than once, particularly for redirects and proxy madness.
|
||||
// Ex. a 200 for a connection to https through a proxy, followed by the "real" status
|
||||
// a 3xx for a redirect followed by a "real" status, or more redirects.
|
||||
virtual void httpStatus(U32 status, const std::string& reason) { }
|
||||
virtual void httpStatus(S32 status, const std::string& reason) { }
|
||||
|
||||
virtual void complete(
|
||||
const LLChannelDescriptors& channels,
|
||||
|
|
@ -379,15 +360,8 @@ protected:
|
|||
//@}
|
||||
|
||||
// value to note if we actually got the response. This value
|
||||
// depends on correct useage from the LLURLRequest instance.
|
||||
// depends on correct usage from the LLURLRequest instance.
|
||||
EStatus mRequestStatus;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* External constants
|
||||
*/
|
||||
extern const std::string CONTEXT_DEST_URI_SD_LABEL;
|
||||
|
||||
#endif // LL_LLURLREQUEST_H
|
||||
|
|
|
|||
|
|
@ -112,20 +112,20 @@ namespace
|
|||
{
|
||||
}
|
||||
|
||||
virtual void error(U32 status, const std::string& reason)
|
||||
protected:
|
||||
virtual void httpFailure()
|
||||
{
|
||||
// don't spam when agent communication disconnected already
|
||||
if (status != 410)
|
||||
if (HTTP_GONE != getStatus())
|
||||
{
|
||||
LL_WARNS("Messaging") << "error status " << status
|
||||
<< " for message " << mMessageName
|
||||
<< " reason " << reason << LL_ENDL;
|
||||
LL_WARNS("Messaging") << "error for message " << mMessageName
|
||||
<< " " << dumpResponse() << LL_ENDL;
|
||||
}
|
||||
// TODO: Map status in to useful error code.
|
||||
if(NULL != mCallback) mCallback(mCallbackData, LL_ERR_TCP_TIMEOUT);
|
||||
}
|
||||
|
||||
virtual void result(const LLSD& content)
|
||||
virtual void httpSuccess()
|
||||
{
|
||||
if(NULL != mCallback) mCallback(mCallbackData, LL_ERR_NOERR);
|
||||
}
|
||||
|
|
@ -151,7 +151,7 @@ class LLMessageHandlerBridge : public LLHTTPNode
|
|||
void LLMessageHandlerBridge::post(LLHTTPNode::ResponsePtr response,
|
||||
const LLSD& context, const LLSD& input) const
|
||||
{
|
||||
std::string name = context["request"]["wildcard"]["message-name"];
|
||||
std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["message-name"];
|
||||
char* namePtr = LLMessageStringTable::getInstance()->getString(name.c_str());
|
||||
|
||||
LL_DEBUGS() << "Setting mLastSender " << input["sender"].asString() << LL_ENDL;
|
||||
|
|
|
|||
|
|
@ -24,42 +24,36 @@
|
|||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_CURL_STUB_CPP
|
||||
#define LL_CURL_STUB_CPP
|
||||
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llcurl.h"
|
||||
#include "llhttpconstants.cpp"
|
||||
|
||||
LLCurl::Responder::Responder()
|
||||
{
|
||||
}
|
||||
|
||||
void LLCurl::Responder::completed(U32 status, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const &reason,
|
||||
LLSD const& mContent)
|
||||
void LLCurl::Responder::httpCompleted()
|
||||
{
|
||||
if (isGoodStatus(status))
|
||||
if (isGoodStatus())
|
||||
{
|
||||
result(mContent);
|
||||
httpSuccess();
|
||||
}
|
||||
else
|
||||
{
|
||||
errorWithContent(status, reason, mContent);
|
||||
httpFailure();
|
||||
}
|
||||
}
|
||||
|
||||
void LLCurl::Responder::completedHeader(unsigned,
|
||||
std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&,
|
||||
LLSD const&)
|
||||
{
|
||||
}
|
||||
|
||||
void LLCurl::Responder::completedRaw(unsigned,
|
||||
std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&,
|
||||
LLChannelDescriptors const&,
|
||||
void LLCurl::Responder::completedRaw(LLChannelDescriptors const&,
|
||||
boost::shared_ptr<LLBufferArray> const&)
|
||||
{
|
||||
}
|
||||
|
||||
void LLCurl::Responder::errorWithContent(unsigned,
|
||||
std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&,
|
||||
LLSD const&)
|
||||
void LLCurl::Responder::httpFailure()
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -67,12 +61,39 @@ LLCurl::Responder::~Responder ()
|
|||
{
|
||||
}
|
||||
|
||||
void LLCurl::Responder::error(unsigned,
|
||||
std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
|
||||
void LLCurl::Responder::httpSuccess()
|
||||
{
|
||||
}
|
||||
|
||||
void LLCurl::Responder::result(LLSD const&)
|
||||
std::string LLCurl::Responder::dumpResponse() const
|
||||
{
|
||||
return "dumpResponse()";
|
||||
}
|
||||
|
||||
void LLCurl::Responder::successResult(const LLSD& content)
|
||||
{
|
||||
setResult(HTTP_OK, "", content);
|
||||
httpSuccess();
|
||||
}
|
||||
|
||||
void LLCurl::Responder::failureResult(S32 status, const std::string& reason, const LLSD& content)
|
||||
{
|
||||
setResult(status, reason, content);
|
||||
httpFailure();
|
||||
}
|
||||
|
||||
|
||||
void LLCurl::Responder::completeResult(S32 status, const std::string& reason, const LLSD& content)
|
||||
{
|
||||
setResult(status, reason, content);
|
||||
httpCompleted();
|
||||
}
|
||||
|
||||
void LLCurl::Responder::setResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */)
|
||||
{
|
||||
mStatus = status;
|
||||
mReason = reason;
|
||||
mContent = content;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -40,8 +40,6 @@
|
|||
#include "llproxy.h"
|
||||
#include "llpumpio.h"
|
||||
|
||||
#include "llsdhttpserver.h"
|
||||
#include "lliohttpserver.h"
|
||||
#include "lliosocket.h"
|
||||
#include "stringize.h"
|
||||
|
||||
|
|
@ -101,7 +99,7 @@ namespace tut
|
|||
if (mSawError)
|
||||
{
|
||||
std::string msg =
|
||||
llformat("error() called when not expected, status %d",
|
||||
llformat("httpFailure() called when not expected, status %d",
|
||||
mStatus);
|
||||
fail(msg);
|
||||
}
|
||||
|
|
@ -111,7 +109,7 @@ namespace tut
|
|||
{
|
||||
if (!mSawError)
|
||||
{
|
||||
fail("error() wasn't called");
|
||||
fail("httpFailure() wasn't called");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -153,33 +151,26 @@ namespace tut
|
|||
mClient.mResultDeleted = true;
|
||||
}
|
||||
|
||||
virtual void error(U32 status, const std::string& reason)
|
||||
protected:
|
||||
virtual void httpFailure()
|
||||
{
|
||||
mClient.mSawError = true;
|
||||
mClient.mStatus = status;
|
||||
mClient.mReason = reason;
|
||||
mClient.mStatus = getStatus();
|
||||
mClient.mReason = getReason();
|
||||
}
|
||||
|
||||
virtual void result(const LLSD& content)
|
||||
virtual void httpSuccess()
|
||||
{
|
||||
mClient.mResult = content;
|
||||
mClient.mResult = getContent();
|
||||
}
|
||||
|
||||
virtual void completed(
|
||||
U32 status, const std::string& reason,
|
||||
const LLSD& content)
|
||||
virtual void httpCompleted()
|
||||
{
|
||||
LLHTTPClient::Responder::completed(status, reason, content);
|
||||
|
||||
LLHTTPClient::Responder::httpCompleted();
|
||||
|
||||
mClient.mSawCompleted = true;
|
||||
}
|
||||
|
||||
virtual void completedHeader(
|
||||
U32 status, const std::string& reason,
|
||||
const LLSD& content)
|
||||
{
|
||||
mClient.mHeader = content;
|
||||
mClient.mSawCompletedHeader = true;
|
||||
mClient.mHeader = getResponseHeaders();
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @file
|
||||
* @brief
|
||||
* @file llhttpclientadapter_test.cpp
|
||||
* @brief Tests for LLHTTPClientAdapter
|
||||
*
|
||||
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
|
|
@ -33,8 +33,8 @@
|
|||
float const HTTP_REQUEST_EXPIRY_SECS = 1.0F;
|
||||
|
||||
std::vector<std::string> get_urls;
|
||||
std::vector<boost::intrusive_ptr<LLCurl::Responder> > get_responders;
|
||||
void LLHTTPClient::get(const std::string& url, boost::intrusive_ptr<LLCurl::Responder> responder, const LLSD& headers, const F32 timeout)
|
||||
std::vector< LLCurl::ResponderPtr > get_responders;
|
||||
void LLHTTPClient::get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers, const F32 timeout, bool follow_redirects)
|
||||
{
|
||||
get_urls.push_back(url);
|
||||
get_responders.push_back(responder);
|
||||
|
|
@ -42,16 +42,30 @@ void LLHTTPClient::get(const std::string& url, boost::intrusive_ptr<LLCurl::Resp
|
|||
|
||||
std::vector<std::string> put_urls;
|
||||
std::vector<LLSD> put_body;
|
||||
std::vector<boost::intrusive_ptr<LLCurl::Responder> > put_responders;
|
||||
std::vector<LLSD> put_headers;
|
||||
std::vector<LLCurl::ResponderPtr> put_responders;
|
||||
|
||||
void LLHTTPClient::put(const std::string& url, const LLSD& body, boost::intrusive_ptr<LLCurl::Responder> responder, const LLSD& headers, const F32 timeout)
|
||||
void LLHTTPClient::put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder, const LLSD& headers, const F32 timeout)
|
||||
{
|
||||
put_urls.push_back(url);
|
||||
put_responders.push_back(responder);
|
||||
put_body.push_back(body);
|
||||
put_headers.push_back(headers);
|
||||
|
||||
}
|
||||
|
||||
std::vector<std::string> delete_urls;
|
||||
std::vector<LLCurl::ResponderPtr> delete_responders;
|
||||
|
||||
void LLHTTPClient::del(
|
||||
const std::string& url,
|
||||
LLCurl::ResponderPtr responder,
|
||||
const LLSD& headers,
|
||||
const F32 timeout)
|
||||
{
|
||||
delete_urls.push_back(url);
|
||||
delete_responders.push_back(responder);
|
||||
}
|
||||
|
||||
namespace tut
|
||||
{
|
||||
|
|
@ -64,6 +78,9 @@ namespace tut
|
|||
put_urls.clear();
|
||||
put_responders.clear();
|
||||
put_body.clear();
|
||||
put_headers.clear();
|
||||
delete_urls.clear();
|
||||
delete_responders.clear();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -73,7 +90,7 @@ namespace tut
|
|||
|
||||
namespace
|
||||
{
|
||||
tut::factory tf("LLHTTPClientAdapterData test");
|
||||
tut::factory tf("LLHTTPClientAdapterData");
|
||||
}
|
||||
|
||||
namespace tut
|
||||
|
|
@ -91,7 +108,7 @@ namespace tut
|
|||
{
|
||||
LLHTTPClientAdapter adapter;
|
||||
|
||||
boost::intrusive_ptr<LLCurl::Responder> responder = new LLCurl::Responder();
|
||||
LLCurl::ResponderPtr responder = new LLCurl::Responder();
|
||||
|
||||
adapter.get("Made up URL", responder);
|
||||
ensure_equals(get_urls.size(), 1);
|
||||
|
|
@ -103,7 +120,7 @@ namespace tut
|
|||
void object::test<3>()
|
||||
{
|
||||
LLHTTPClientAdapter adapter;
|
||||
boost::intrusive_ptr<LLCurl::Responder> responder = new LLCurl::Responder();
|
||||
LLCurl::ResponderPtr responder = new LLCurl::Responder();
|
||||
|
||||
adapter.get("Made up URL", responder);
|
||||
|
||||
|
|
@ -117,7 +134,7 @@ namespace tut
|
|||
{
|
||||
LLHTTPClientAdapter adapter;
|
||||
|
||||
boost::intrusive_ptr<LLCurl::Responder> responder = new LLCurl::Responder();
|
||||
LLCurl::ResponderPtr responder = new LLCurl::Responder();
|
||||
|
||||
LLSD body;
|
||||
body["TestBody"] = "Foobar";
|
||||
|
|
@ -133,7 +150,7 @@ namespace tut
|
|||
{
|
||||
LLHTTPClientAdapter adapter;
|
||||
|
||||
boost::intrusive_ptr<LLCurl::Responder> responder = new LLCurl::Responder();
|
||||
LLCurl::ResponderPtr responder = new LLCurl::Responder();
|
||||
|
||||
LLSD body;
|
||||
body["TestBody"] = "Foobar";
|
||||
|
|
@ -150,7 +167,7 @@ namespace tut
|
|||
{
|
||||
LLHTTPClientAdapter adapter;
|
||||
|
||||
boost::intrusive_ptr<LLCurl::Responder> responder = new LLCurl::Responder();
|
||||
LLCurl::ResponderPtr responder = new LLCurl::Responder();
|
||||
|
||||
LLSD body;
|
||||
body["TestBody"] = "Foobar";
|
||||
|
|
@ -160,5 +177,45 @@ namespace tut
|
|||
ensure_equals(put_body.size(), 1);
|
||||
ensure_equals(put_body[0]["TestBody"].asString(), "Foobar");
|
||||
}
|
||||
|
||||
// Ensure that headers are passed through put properly
|
||||
template<> template<>
|
||||
void object::test<7>()
|
||||
{
|
||||
LLHTTPClientAdapter adapter;
|
||||
|
||||
LLCurl::ResponderPtr responder = new LLCurl::Responder();
|
||||
|
||||
LLSD body = LLSD::emptyMap();
|
||||
body["TestBody"] = "Foobar";
|
||||
|
||||
LLSD headers = LLSD::emptyMap();
|
||||
headers["booger"] = "omg";
|
||||
|
||||
adapter.put("Made up URL", body, responder, headers);
|
||||
|
||||
ensure_equals("Header count", put_headers.size(), 1);
|
||||
ensure_equals(
|
||||
"First header",
|
||||
put_headers[0]["booger"].asString(),
|
||||
"omg");
|
||||
}
|
||||
|
||||
// Ensure that del() passes appropriate arguments to the LLHTTPClient
|
||||
template<> template<>
|
||||
void object::test<8>()
|
||||
{
|
||||
LLHTTPClientAdapter adapter;
|
||||
|
||||
LLCurl::ResponderPtr responder = new LLCurl::Responder();
|
||||
|
||||
adapter.del("Made up URL", responder);
|
||||
|
||||
ensure_equals("URL count", delete_urls.size(), 1);
|
||||
ensure_equals("Received URL", delete_urls[0], "Made up URL");
|
||||
|
||||
ensure_equals("Responder count", delete_responders.size(), 1);
|
||||
//ensure_equals("Responder", delete_responders[0], responder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,107 @@
|
|||
/**
|
||||
* @file llhttpnode_stub.cpp
|
||||
* @brief STUB Implementation of classes for generic HTTP/LSL/REST handling.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (c) 2006-2009, 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 "llhttpnode.h"
|
||||
|
||||
const std::string CONTEXT_VERB("verb");
|
||||
const std::string CONTEXT_REQUEST("request");
|
||||
const std::string CONTEXT_WILDCARD("wildcard");
|
||||
const std::string CONTEXT_PATH("path");
|
||||
const std::string CONTEXT_QUERY_STRING("query-string");
|
||||
const std::string CONTEXT_REMOTE_HOST("remote-host");
|
||||
const std::string CONTEXT_REMOTE_PORT("remote-port");
|
||||
const std::string CONTEXT_HEADERS("headers");
|
||||
const std::string CONTEXT_RESPONSE("response");
|
||||
|
||||
/**
|
||||
* LLHTTPNode
|
||||
*/
|
||||
class LLHTTPNode::Impl
|
||||
{
|
||||
// dummy
|
||||
};
|
||||
|
||||
LLHTTPNode::LLHTTPNode(): impl(*new Impl) {}
|
||||
LLHTTPNode::~LLHTTPNode() {}
|
||||
LLSD LLHTTPNode::simpleGet() const { return LLSD(); }
|
||||
LLSD LLHTTPNode::simplePut(const LLSD& input) const { return LLSD(); }
|
||||
LLSD LLHTTPNode::simplePost(const LLSD& input) const { return LLSD(); }
|
||||
LLSD LLHTTPNode::simpleDel(const LLSD&) const { return LLSD(); }
|
||||
void LLHTTPNode::get(LLHTTPNode::ResponsePtr response, const LLSD& context) const {}
|
||||
void LLHTTPNode::put(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const {}
|
||||
void LLHTTPNode::post(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const {}
|
||||
void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) const {}
|
||||
void LLHTTPNode::options(ResponsePtr response, const LLSD& context) const {}
|
||||
LLHTTPNode* LLHTTPNode::getChild(const std::string& name, LLSD& context) const { return NULL; }
|
||||
bool LLHTTPNode::handles(const LLSD& remainder, LLSD& context) const { return false; }
|
||||
bool LLHTTPNode::validate(const std::string& name, LLSD& context) const { return false; }
|
||||
const LLHTTPNode* LLHTTPNode::traverse(const std::string& path, LLSD& context) const { return NULL; }
|
||||
void LLHTTPNode::addNode(const std::string& path, LLHTTPNode* nodeToAdd) { }
|
||||
LLSD LLHTTPNode::allNodePaths() const { return LLSD(); }
|
||||
const LLHTTPNode* LLHTTPNode::rootNode() const { return NULL; }
|
||||
const LLHTTPNode* LLHTTPNode::findNode(const std::string& name) const { return NULL; }
|
||||
|
||||
LLHTTPNode::Response::~Response(){}
|
||||
void LLHTTPNode::Response::notFound(const std::string& message)
|
||||
{
|
||||
status(404, message);
|
||||
}
|
||||
void LLHTTPNode::Response::notFound()
|
||||
{
|
||||
status(404, "Not Found");
|
||||
}
|
||||
void LLHTTPNode::Response::methodNotAllowed()
|
||||
{
|
||||
status(405, "Method Not Allowed");
|
||||
}
|
||||
void LLHTTPNode::Response::statusUnknownError(S32 code)
|
||||
{
|
||||
status(code, "Unknown Error");
|
||||
}
|
||||
|
||||
void LLHTTPNode::Response::status(S32 code, const std::string& message)
|
||||
{
|
||||
}
|
||||
|
||||
void LLHTTPNode::Response::addHeader(const std::string& name,const std::string& value)
|
||||
{
|
||||
mHeaders[name] = value;
|
||||
}
|
||||
void LLHTTPNode::describe(Description& desc) const { }
|
||||
|
||||
|
||||
const LLChainIOFactory* LLHTTPNode::getProtocolHandler() const { return NULL; }
|
||||
|
||||
|
||||
LLHTTPRegistrar::NodeFactory::~NodeFactory() { }
|
||||
|
||||
void LLHTTPRegistrar::registerFactory(
|
||||
const std::string& path, NodeFactory& factory) {}
|
||||
void LLHTTPRegistrar::buildAllServices(LLHTTPNode& root) {}
|
||||
|
||||
|
||||
|
|
@ -1,445 +0,0 @@
|
|||
/**
|
||||
* @file llmime_test.cpp
|
||||
* @author Phoenix
|
||||
* @date 2006-12-24
|
||||
* @brief BRIEF_DESC of llmime_test.cpp
|
||||
*
|
||||
* $LicenseInfo:firstyear=2006&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 "llsdserialize.h"
|
||||
|
||||
#include "../llmime.h"
|
||||
|
||||
#include "../test/lltut.h"
|
||||
|
||||
namespace tut
|
||||
{
|
||||
struct mime_index
|
||||
{
|
||||
};
|
||||
typedef test_group<mime_index> mime_index_t;
|
||||
typedef mime_index_t::object mime_index_object_t;
|
||||
tut::mime_index_t tut_mime_index("LLMime");
|
||||
|
||||
template<> template<>
|
||||
void mime_index_object_t::test<1>()
|
||||
{
|
||||
LLMimeIndex mime;
|
||||
ensure("no headers", mime.headers().isUndefined());
|
||||
ensure_equals("invalid offset", mime.offset(), -1);
|
||||
ensure_equals("invalid content length", mime.contentLength(), -1);
|
||||
ensure("no content type", mime.contentType().empty());
|
||||
ensure("not multipart", !mime.isMultipart());
|
||||
ensure_equals("no attachments", mime.subPartCount(), 0);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void mime_index_object_t::test<2>()
|
||||
{
|
||||
const S32 CONTENT_LENGTH = 6000;
|
||||
const S32 CONTENT_OFFSET = 100;
|
||||
const std::string CONTENT_TYPE = std::string("image/j2c");
|
||||
LLSD headers;
|
||||
headers["Content-Length"] = CONTENT_LENGTH;
|
||||
headers["Content-Type"] = CONTENT_TYPE;
|
||||
LLMimeIndex mime(headers, CONTENT_OFFSET);
|
||||
ensure("headers are map", mime.headers().isMap());
|
||||
ensure_equals("offset", mime.offset(), CONTENT_OFFSET);
|
||||
ensure_equals("content length", mime.contentLength(), CONTENT_LENGTH);
|
||||
ensure_equals("type is image/j2c", mime.contentType(), CONTENT_TYPE);
|
||||
ensure("not multipart", !mime.isMultipart());
|
||||
ensure_equals("no attachments", mime.subPartCount(), 0);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void mime_index_object_t::test<3>()
|
||||
{
|
||||
const S32 MULTI_CONTENT_LENGTH = 8000;
|
||||
const S32 MULTI_CONTENT_OFFSET = 100;
|
||||
const std::string MULTI_CONTENT_TYPE = std::string("multipart/mixed");
|
||||
LLSD headers;
|
||||
headers["Content-Length"] = MULTI_CONTENT_LENGTH;
|
||||
headers["Content-Type"] = MULTI_CONTENT_TYPE;
|
||||
LLMimeIndex mime(headers, MULTI_CONTENT_OFFSET);
|
||||
LL_INFOS() << "headers: " << LLSDOStreamer<LLSDNotationFormatter>(headers)
|
||||
<< LL_ENDL;
|
||||
|
||||
|
||||
const S32 META_CONTENT_LENGTH = 700;
|
||||
const S32 META_CONTENT_OFFSET = 69;
|
||||
const std::string META_CONTENT_TYPE = std::string(
|
||||
"text/llsd+xml");
|
||||
headers = LLSD::emptyMap();
|
||||
headers["Content-Length"] = META_CONTENT_LENGTH;
|
||||
headers["Content-Type"] = META_CONTENT_TYPE;
|
||||
LLMimeIndex meta(headers, META_CONTENT_OFFSET);
|
||||
mime.attachSubPart(meta);
|
||||
|
||||
const S32 IMAGE_CONTENT_LENGTH = 6000;
|
||||
const S32 IMAGE_CONTENT_OFFSET = 200;
|
||||
const std::string IMAGE_CONTENT_TYPE = std::string("image/j2c");
|
||||
headers = LLSD::emptyMap();
|
||||
headers["Content-Length"] = IMAGE_CONTENT_LENGTH;
|
||||
headers["Content-Type"] = IMAGE_CONTENT_TYPE;
|
||||
LLMimeIndex image(headers, IMAGE_CONTENT_OFFSET);
|
||||
mime.attachSubPart(image);
|
||||
|
||||
// make sure we have a valid multi-part
|
||||
ensure("is multipart", mime.isMultipart());
|
||||
ensure_equals("multi offset", mime.offset(), MULTI_CONTENT_OFFSET);
|
||||
ensure_equals(
|
||||
"multi content length",
|
||||
mime.contentLength(),
|
||||
MULTI_CONTENT_LENGTH);
|
||||
ensure_equals("two attachments", mime.subPartCount(), 2);
|
||||
|
||||
// make sure ranged gets do the right thing with out of bounds
|
||||
// sub-parts.
|
||||
LLMimeIndex invalid_child(mime.subPart(-1));
|
||||
ensure("no headers", invalid_child.headers().isUndefined());
|
||||
ensure_equals("invalid offset", invalid_child.offset(), -1);
|
||||
ensure_equals(
|
||||
"invalid content length", invalid_child.contentLength(), -1);
|
||||
ensure("no content type", invalid_child.contentType().empty());
|
||||
ensure("not multipart", !invalid_child.isMultipart());
|
||||
ensure_equals("no attachments", invalid_child.subPartCount(), 0);
|
||||
|
||||
invalid_child = mime.subPart(2);
|
||||
ensure("no headers", invalid_child.headers().isUndefined());
|
||||
ensure_equals("invalid offset", invalid_child.offset(), -1);
|
||||
ensure_equals(
|
||||
"invalid content length", invalid_child.contentLength(), -1);
|
||||
ensure("no content type", invalid_child.contentType().empty());
|
||||
ensure("not multipart", !invalid_child.isMultipart());
|
||||
ensure_equals("no attachments", invalid_child.subPartCount(), 0);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void mime_index_object_t::test<4>()
|
||||
{
|
||||
const S32 MULTI_CONTENT_LENGTH = 8000;
|
||||
const S32 MULTI_CONTENT_OFFSET = 100;
|
||||
const std::string MULTI_CONTENT_TYPE = std::string("multipart/mixed");
|
||||
LLSD headers;
|
||||
headers["Content-Length"] = MULTI_CONTENT_LENGTH;
|
||||
headers["Content-Type"] = MULTI_CONTENT_TYPE;
|
||||
LLMimeIndex mime(headers, MULTI_CONTENT_OFFSET);
|
||||
|
||||
const S32 META_CONTENT_LENGTH = 700;
|
||||
const S32 META_CONTENT_OFFSET = 69;
|
||||
const std::string META_CONTENT_TYPE = std::string(
|
||||
"application/llsd+xml");
|
||||
headers = LLSD::emptyMap();
|
||||
headers["Content-Length"] = META_CONTENT_LENGTH;
|
||||
headers["Content-Type"] = META_CONTENT_TYPE;
|
||||
LLMimeIndex meta(headers, META_CONTENT_OFFSET);
|
||||
mime.attachSubPart(meta);
|
||||
|
||||
const S32 IMAGE_CONTENT_LENGTH = 6000;
|
||||
const S32 IMAGE_CONTENT_OFFSET = 200;
|
||||
const std::string IMAGE_CONTENT_TYPE = std::string("image/j2c");
|
||||
headers = LLSD::emptyMap();
|
||||
headers["Content-Length"] = IMAGE_CONTENT_LENGTH;
|
||||
headers["Content-Type"] = IMAGE_CONTENT_TYPE;
|
||||
LLMimeIndex image(headers, IMAGE_CONTENT_OFFSET);
|
||||
mime.attachSubPart(image);
|
||||
|
||||
// check what we have
|
||||
ensure("is multipart", mime.isMultipart());
|
||||
ensure_equals("multi offset", mime.offset(), MULTI_CONTENT_OFFSET);
|
||||
ensure_equals(
|
||||
"multi content length",
|
||||
mime.contentLength(),
|
||||
MULTI_CONTENT_LENGTH);
|
||||
ensure_equals("two attachments", mime.subPartCount(), 2);
|
||||
|
||||
LLMimeIndex actual_meta = mime.subPart(0);
|
||||
ensure_equals(
|
||||
"meta type", actual_meta.contentType(), META_CONTENT_TYPE);
|
||||
ensure_equals(
|
||||
"meta offset", actual_meta.offset(), META_CONTENT_OFFSET);
|
||||
ensure_equals(
|
||||
"meta content length",
|
||||
actual_meta.contentLength(),
|
||||
META_CONTENT_LENGTH);
|
||||
|
||||
LLMimeIndex actual_image = mime.subPart(1);
|
||||
ensure_equals(
|
||||
"image type", actual_image.contentType(), IMAGE_CONTENT_TYPE);
|
||||
ensure_equals(
|
||||
"image offset", actual_image.offset(), IMAGE_CONTENT_OFFSET);
|
||||
ensure_equals(
|
||||
"image content length",
|
||||
actual_image.contentLength(),
|
||||
IMAGE_CONTENT_LENGTH);
|
||||
}
|
||||
|
||||
/*
|
||||
template<> template<>
|
||||
void mime_index_object_t::test<5>()
|
||||
{
|
||||
}
|
||||
template<> template<>
|
||||
void mime_index_object_t::test<6>()
|
||||
{
|
||||
}
|
||||
template<> template<>
|
||||
void mime_index_object_t::test<7>()
|
||||
{
|
||||
}
|
||||
template<> template<>
|
||||
void mime_index_object_t::test<8>()
|
||||
{
|
||||
}
|
||||
template<> template<>
|
||||
void mime_index_object_t::test<>()
|
||||
{
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
namespace tut
|
||||
{
|
||||
struct mime_parse
|
||||
{
|
||||
};
|
||||
typedef test_group<mime_parse> mime_parse_t;
|
||||
typedef mime_parse_t::object mime_parse_object_t;
|
||||
tut::mime_parse_t tut_mime_parse("LLMimeParse");
|
||||
|
||||
template<> template<>
|
||||
void mime_parse_object_t::test<1>()
|
||||
{
|
||||
// parse one mime object
|
||||
const std::string SERIALIZED_MIME("Content-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n");
|
||||
std::stringstream istr;
|
||||
istr.str(SERIALIZED_MIME);
|
||||
LLMimeIndex mime;
|
||||
LLMimeParser parser;
|
||||
bool ok = parser.parseIndex(istr, mime);
|
||||
ensure("Parse successful.", ok);
|
||||
ensure_equals("content type", mime.contentType(), "text/plain");
|
||||
ensure_equals("content length", mime.contentLength(), 200);
|
||||
ensure_equals("offset", mime.offset(), 49);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void mime_parse_object_t::test<2>()
|
||||
{
|
||||
// make sure we only parse one.
|
||||
const std::string SERIALIZED_MIME("Content-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n\r\nContent-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n\r\n");
|
||||
std::stringstream istr;
|
||||
istr.str(SERIALIZED_MIME);
|
||||
LLMimeIndex mime;
|
||||
LLMimeParser parser;
|
||||
bool ok = parser.parseIndex(istr, mime);
|
||||
ensure("Parse successful.", ok);
|
||||
ensure("not multipart.", !mime.isMultipart());
|
||||
ensure_equals("content type", mime.contentType(), "text/plain");
|
||||
ensure_equals("content length", mime.contentLength(), 200);
|
||||
ensure_equals("offset", mime.offset(), 49);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void mime_parse_object_t::test<3>()
|
||||
{
|
||||
// test multi-part and lack of content length for some of it.
|
||||
/*
|
||||
Content-Type: multipart/mixed; boundary="segment"rnContent-Length: 148rnrn--segmentrnContent-Type: text/plainrnrnsome datarnrn--segmentrnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrn<llsd><undef /></llsd>rnrn
|
||||
*/
|
||||
const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=\"segment\"\r\nContent-Length: 150\r\n\r\n--segment\r\nContent-Type: text/plain\r\n\r\nsome data\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
|
||||
std::stringstream istr;
|
||||
istr.str(SERIALIZED_MIME);
|
||||
LLMimeIndex mime;
|
||||
LLMimeParser parser;
|
||||
bool ok = parser.parseIndex(istr, mime);
|
||||
ensure("Parse successful.", ok);
|
||||
ensure("is multipart.", mime.isMultipart());
|
||||
ensure_equals("sub-part count", mime.subPartCount(), 2);
|
||||
ensure_equals("content length", mime.contentLength(), 150);
|
||||
ensure_equals("data offset for multipart", mime.offset(), 74);
|
||||
|
||||
LLMimeIndex mime_plain(mime.subPart(0));
|
||||
ensure_equals(
|
||||
"first part type",
|
||||
mime_plain.contentType(),
|
||||
"text/plain");
|
||||
ensure_equals(
|
||||
"first part content length not known.",
|
||||
mime_plain.contentLength(),
|
||||
-1);
|
||||
ensure_equals("first part offset", mime_plain.offset(), 113);
|
||||
|
||||
LLMimeIndex mime_xml(mime.subPart(1));
|
||||
ensure_equals(
|
||||
"second part type",
|
||||
mime_xml.contentType(),
|
||||
"text/xml; charset=UTF-8");
|
||||
ensure_equals(
|
||||
"second part content length",
|
||||
mime_xml.contentLength(),
|
||||
22);
|
||||
ensure_equals("second part offset", mime_xml.offset(), 198);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void mime_parse_object_t::test<4>()
|
||||
{
|
||||
// test multi-part, unquoted separator, and premature eof conditions
|
||||
/*
|
||||
Content-Type: multipart/mixed; boundary=segmentrnContent-Length: 220rnrn--segmentrnContent-Type: text/plainrnContent-Length: 55rnrnhow are you today?rnI do not know. I guess I am:n'fine'rnrn--segmentrnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrn<llsd><undef /></llsd>rnrn */
|
||||
const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=segment\r\nContent-Length: 220\r\n\r\n--segment\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
|
||||
std::stringstream istr;
|
||||
istr.str(SERIALIZED_MIME);
|
||||
LLMimeIndex mime;
|
||||
LLMimeParser parser;
|
||||
bool ok = parser.parseIndex(istr, mime);
|
||||
ensure("Parse successful.", ok);
|
||||
ensure("is multipart.", mime.isMultipart());
|
||||
ensure_equals("sub-part count", mime.subPartCount(), 2);
|
||||
ensure_equals("content length", mime.contentLength(), 220);
|
||||
ensure_equals("data offset for multipart", mime.offset(), 72);
|
||||
|
||||
LLMimeIndex mime_plain(mime.subPart(0));
|
||||
ensure_equals(
|
||||
"first part type",
|
||||
mime_plain.contentType(),
|
||||
"text/plain");
|
||||
ensure_equals(
|
||||
"first part content length",
|
||||
mime_plain.contentLength(),
|
||||
55);
|
||||
ensure_equals("first part offset", mime_plain.offset(), 131);
|
||||
|
||||
LLMimeIndex mime_xml(mime.subPart(1));
|
||||
ensure_equals(
|
||||
"second part type",
|
||||
mime_xml.contentType(),
|
||||
"text/xml; charset=UTF-8");
|
||||
ensure_equals(
|
||||
"second part content length",
|
||||
mime_xml.contentLength(),
|
||||
22);
|
||||
ensure_equals("second part offset", mime_xml.offset(), 262);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void mime_parse_object_t::test<5>()
|
||||
{
|
||||
// test multi-part with multiple params
|
||||
const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=segment; comment=\"testing multiple params.\"\r\nContent-Length: 220\r\n\r\n--segment\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
|
||||
std::stringstream istr;
|
||||
istr.str(SERIALIZED_MIME);
|
||||
LLMimeIndex mime;
|
||||
LLMimeParser parser;
|
||||
bool ok = parser.parseIndex(istr, mime);
|
||||
ensure("Parse successful.", ok);
|
||||
ensure("is multipart.", mime.isMultipart());
|
||||
ensure_equals("sub-part count", mime.subPartCount(), 2);
|
||||
ensure_equals("content length", mime.contentLength(), 220);
|
||||
|
||||
LLMimeIndex mime_plain(mime.subPart(0));
|
||||
ensure_equals(
|
||||
"first part type",
|
||||
mime_plain.contentType(),
|
||||
"text/plain");
|
||||
ensure_equals(
|
||||
"first part content length",
|
||||
mime_plain.contentLength(),
|
||||
55);
|
||||
|
||||
LLMimeIndex mime_xml(mime.subPart(1));
|
||||
ensure_equals(
|
||||
"second part type",
|
||||
mime_xml.contentType(),
|
||||
"text/xml; charset=UTF-8");
|
||||
ensure_equals(
|
||||
"second part content length",
|
||||
mime_xml.contentLength(),
|
||||
22);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void mime_parse_object_t::test<6>()
|
||||
{
|
||||
// test multi-part with no specified boundary and eof
|
||||
/*
|
||||
Content-Type: multipart/relatedrnContent-Length: 220rnrn--rnContent-Type: text/plainrnContent-Length: 55rnrnhow are you today?rnI do not know. I guess I am:n'fine'rnrn--rnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrn<llsd><undef /></llsd>rnrn
|
||||
*/
|
||||
const std::string SERIALIZED_MIME("Content-Type: multipart/related\r\nContent-Length: 500\r\n\r\n--\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
|
||||
std::stringstream istr;
|
||||
istr.str(SERIALIZED_MIME);
|
||||
LLMimeIndex mime;
|
||||
LLMimeParser parser;
|
||||
bool ok = parser.parseIndex(istr, mime);
|
||||
ensure("Parse successful.", ok);
|
||||
ensure("is multipart.", mime.isMultipart());
|
||||
ensure_equals("sub-part count", mime.subPartCount(), 2);
|
||||
ensure_equals("content length", mime.contentLength(), 500);
|
||||
ensure_equals("data offset for multipart", mime.offset(), 56);
|
||||
|
||||
LLMimeIndex mime_plain(mime.subPart(0));
|
||||
ensure_equals(
|
||||
"first part type",
|
||||
mime_plain.contentType(),
|
||||
"text/plain");
|
||||
ensure_equals(
|
||||
"first part content length",
|
||||
mime_plain.contentLength(),
|
||||
55);
|
||||
ensure_equals("first part offset", mime_plain.offset(), 108);
|
||||
|
||||
LLMimeIndex mime_xml(mime.subPart(1));
|
||||
ensure_equals(
|
||||
"second part type",
|
||||
mime_xml.contentType(),
|
||||
"text/xml; charset=UTF-8");
|
||||
ensure_equals(
|
||||
"second part content length",
|
||||
mime_xml.contentLength(),
|
||||
22);
|
||||
ensure_equals("second part offset", mime_xml.offset(), 232);
|
||||
}
|
||||
|
||||
/*
|
||||
template<> template<>
|
||||
void mime_parse_object_t::test<>()
|
||||
{
|
||||
}
|
||||
template<> template<>
|
||||
void mime_parse_object_t::test<>()
|
||||
{
|
||||
}
|
||||
template<> template<>
|
||||
void mime_parse_object_t::test<>()
|
||||
{
|
||||
}
|
||||
template<> template<>
|
||||
void mime_parse_object_t::test<>()
|
||||
{
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
/**
|
||||
* @file
|
||||
* @brief
|
||||
*
|
||||
* $LicenseInfo:firstyear=2008&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 "../test/lltut.h"
|
||||
#include "llregionpresenceverifier.h"
|
||||
#include "llcurl_stub.cpp"
|
||||
#include "llhost.cpp"
|
||||
#include "net.cpp"
|
||||
#include "lltesthttpclientadapter.cpp"
|
||||
|
||||
class LLTestResponse : public LLRegionPresenceVerifier::Response
|
||||
{
|
||||
public:
|
||||
|
||||
virtual bool checkValidity(const LLSD& content) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void onRegionVerified(const LLSD& region_details)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void onRegionVerificationFailed()
|
||||
{
|
||||
}
|
||||
|
||||
virtual LLHTTPClientInterface& getHttpClient()
|
||||
{
|
||||
return mHttpInterface;
|
||||
}
|
||||
|
||||
LLTestHTTPClientAdapter mHttpInterface;
|
||||
};
|
||||
|
||||
namespace tut
|
||||
{
|
||||
struct LLRegionPresenceVerifierData
|
||||
{
|
||||
LLRegionPresenceVerifierData() :
|
||||
mResponse(new LLTestResponse()),
|
||||
mResponder("", LLRegionPresenceVerifier::ResponsePtr(mResponse),
|
||||
LLSD(), 3)
|
||||
{
|
||||
}
|
||||
|
||||
LLTestResponse* mResponse;
|
||||
LLRegionPresenceVerifier::VerifiedDestinationResponder mResponder;
|
||||
};
|
||||
|
||||
typedef test_group<LLRegionPresenceVerifierData> factory;
|
||||
typedef factory::object object;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
tut::factory tf("LLRegionPresenceVerifier");
|
||||
}
|
||||
|
||||
namespace tut
|
||||
{
|
||||
// Test that VerifiedDestinationResponder does retry
|
||||
// on error when shouldRetry returns true.
|
||||
template<> template<>
|
||||
void object::test<1>()
|
||||
{
|
||||
mResponder.error(500, "Internal server error");
|
||||
ensure_equals(mResponse->mHttpInterface.mGetUrl.size(), 1);
|
||||
}
|
||||
|
||||
// Test that VerifiedDestinationResponder only retries
|
||||
// on error until shouldRetry returns false.
|
||||
template<> template<>
|
||||
void object::test<2>()
|
||||
{
|
||||
mResponder.error(500, "Internal server error");
|
||||
mResponder.error(500, "Internal server error");
|
||||
mResponder.error(500, "Internal server error");
|
||||
mResponder.error(500, "Internal server error");
|
||||
ensure_equals(mResponse->mHttpInterface.mGetUrl.size(), 3);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "message.h"
|
||||
#include "llmessageconfig.h"
|
||||
#include "llhttpnode_stub.cpp"
|
||||
|
||||
LLMessageSystem* gMessageSystem = NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llstl.h"
|
||||
#include "indra_constants.h"
|
||||
|
||||
#include "llplugincookiestore.h"
|
||||
|
|
@ -654,12 +655,8 @@ void LLPluginCookieStore::setOneCookie(const std::string &s, std::string::size_t
|
|||
|
||||
void LLPluginCookieStore::clearCookies()
|
||||
{
|
||||
while(!mCookies.empty())
|
||||
{
|
||||
cookie_map_t::iterator iter = mCookies.begin();
|
||||
delete iter->second;
|
||||
mCookies.erase(iter);
|
||||
}
|
||||
std::for_each(mCookies.begin(), mCookies.end(), DeletePairedPointer());
|
||||
mCookies.clear();
|
||||
}
|
||||
|
||||
void LLPluginCookieStore::removeCookie(const std::string &key)
|
||||
|
|
|
|||
|
|
@ -364,12 +364,7 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message)
|
|||
else
|
||||
{
|
||||
// This is a new region
|
||||
|
||||
// <FS:ND> use smartptr
|
||||
// LLPluginSharedMemory *region = new LLPluginSharedMemory;
|
||||
LLPluginSharedMemoryPtr region( new LLPluginSharedMemory );
|
||||
// </FS:ND>
|
||||
|
||||
LLPluginSharedMemory *region = new LLPluginSharedMemory;
|
||||
if(region->attach(name, size))
|
||||
{
|
||||
mSharedMemoryRegions.insert(sharedMemoryRegionsType::value_type(name, region));
|
||||
|
|
@ -392,7 +387,7 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message)
|
|||
else
|
||||
{
|
||||
LL_WARNS("Plugin") << "Couldn't create a shared memory segment!" << LL_ENDL;
|
||||
// delete region; // <FS:ND/> smartptr will delete automatically.
|
||||
delete region;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -97,11 +97,7 @@ private:
|
|||
|
||||
LLPluginInstance *mInstance;
|
||||
|
||||
// <FS:ND> Use boost::shred_ptr so LLPluginSharedMemory gets properly destroyed
|
||||
// typedef std::map<std::string, LLPluginSharedMemory*> sharedMemoryRegionsType;
|
||||
typedef std::map<std::string, LLPluginSharedMemoryPtr > sharedMemoryRegionsType;
|
||||
// </FS:ND>
|
||||
|
||||
typedef std::map<std::string, LLPluginSharedMemory*> sharedMemoryRegionsType;
|
||||
sharedMemoryRegionsType mSharedMemoryRegions;
|
||||
|
||||
LLTimer mHeartbeat;
|
||||
|
|
|
|||
|
|
@ -133,6 +133,8 @@ LLPluginProcessParent::~LLPluginProcessParent()
|
|||
{
|
||||
// destroy the shared memory region
|
||||
iter->second->destroy();
|
||||
delete iter->second;
|
||||
iter->second = NULL;
|
||||
|
||||
// and remove it from our map
|
||||
mSharedMemoryRegions.erase(iter);
|
||||
|
|
@ -979,6 +981,8 @@ void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message)
|
|||
{
|
||||
// destroy the shared memory region
|
||||
iter->second->destroy();
|
||||
delete iter->second;
|
||||
iter->second = NULL;
|
||||
|
||||
// and remove it from our map
|
||||
mSharedMemoryRegions.erase(iter);
|
||||
|
|
@ -1002,10 +1006,7 @@ std::string LLPluginProcessParent::addSharedMemory(size_t size)
|
|||
{
|
||||
std::string name;
|
||||
|
||||
// <FS:ND> Use smartptr
|
||||
// LLPluginSharedMemory *region = new LLPluginSharedMemory;
|
||||
LLPluginSharedMemoryPtr region( new LLPluginSharedMemory );
|
||||
// </FS:ND>
|
||||
LLPluginSharedMemory *region = new LLPluginSharedMemory;
|
||||
|
||||
// This is a new region
|
||||
if(region->create(size))
|
||||
|
|
@ -1024,7 +1025,7 @@ std::string LLPluginProcessParent::addSharedMemory(size_t size)
|
|||
LL_WARNS("Plugin") << "Couldn't create a shared memory segment!" << LL_ENDL;
|
||||
|
||||
// Don't leak
|
||||
// delete region; // <FS:ND/> Smartptr will autodelete.
|
||||
delete region;
|
||||
}
|
||||
|
||||
return name;
|
||||
|
|
|
|||
|
|
@ -160,11 +160,7 @@ private:
|
|||
|
||||
LLPluginProcessParentOwner *mOwner;
|
||||
|
||||
// <FS:ND> Use boost::shred_ptr so LLPluginSharedMemory gets properly destroyed
|
||||
// typedef std::map<std::string, LLPluginSharedMemory*> sharedMemoryRegionsType;
|
||||
typedef std::map<std::string, LLPluginSharedMemoryPtr > sharedMemoryRegionsType;
|
||||
// </FS:ND>
|
||||
|
||||
typedef std::map<std::string, LLPluginSharedMemory*> sharedMemoryRegionsType;
|
||||
sharedMemoryRegionsType mSharedMemoryRegions;
|
||||
|
||||
LLSD mMessageClassVersions;
|
||||
|
|
|
|||
|
|
@ -28,8 +28,6 @@
|
|||
#ifndef LL_LLPLUGINSHAREDMEMORY_H
|
||||
#define LL_LLPLUGINSHAREDMEMORY_H
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
class LLPluginSharedMemoryPlatformImpl;
|
||||
|
||||
/**
|
||||
|
|
@ -122,7 +120,6 @@ private:
|
|||
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr< LLPluginSharedMemory > LLPluginSharedMemoryPtr;
|
||||
|
||||
|
||||
#endif // LL_LLPLUGINSHAREDMEMORY_H
|
||||
|
|
|
|||
|
|
@ -610,6 +610,7 @@ bool LLGLManager::initGL()
|
|||
if (mGLVendor.substr(0,4) == "ATI ")
|
||||
{
|
||||
mGLVendorShort = "ATI";
|
||||
// *TODO: Fix this?
|
||||
mIsATI = TRUE;
|
||||
|
||||
#if LL_WINDOWS && !LL_MESA_HEADLESS
|
||||
|
|
|
|||
|
|
@ -390,9 +390,7 @@ LLImageGL::~LLImageGL()
|
|||
{
|
||||
LLImageGL::cleanup();
|
||||
sImageList.erase(this);
|
||||
disclaimMem((mPickMaskWidth * mPickMaskHeight + 7) / 8);
|
||||
delete [] mPickMask;
|
||||
mPickMask = NULL;
|
||||
freePickMask();
|
||||
sCount--;
|
||||
}
|
||||
|
||||
|
|
@ -461,6 +459,8 @@ void LLImageGL::cleanup()
|
|||
{
|
||||
destroyGLTexture();
|
||||
}
|
||||
freePickMask();
|
||||
|
||||
mSaveData = NULL; // deletes data
|
||||
}
|
||||
|
||||
|
|
@ -507,10 +507,7 @@ void LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_leve
|
|||
}
|
||||
|
||||
// pickmask validity depends on old image size, delete it
|
||||
disclaimMem((mPickMaskWidth * mPickMaskHeight + 7) / 8);
|
||||
delete [] mPickMask;
|
||||
mPickMask = NULL;
|
||||
mPickMaskWidth = mPickMaskHeight = 0;
|
||||
freePickMask();
|
||||
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
|
|
@ -1889,27 +1886,10 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
|
|||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in)
|
||||
U32 LLImageGL::createPickMask(S32 pWidth, S32 pHeight)
|
||||
{
|
||||
if(!mNeedsAlphaAndPickMask)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
disclaimMem((mPickMaskWidth * mPickMaskHeight + 7) / 8);
|
||||
delete [] mPickMask;
|
||||
mPickMask = NULL;
|
||||
mPickMaskWidth = mPickMaskHeight = 0;
|
||||
|
||||
if (mFormatType != GL_UNSIGNED_BYTE ||
|
||||
mFormatPrimary != GL_RGBA)
|
||||
{
|
||||
//cannot generate a pick mask for this texture
|
||||
return;
|
||||
}
|
||||
|
||||
U32 pick_width = width/2 + 1;
|
||||
U32 pick_height = height/2 + 1;
|
||||
U32 pick_width = pWidth/2 + 1;
|
||||
U32 pick_height = pHeight/2 + 1;
|
||||
|
||||
U32 size = pick_width * pick_height;
|
||||
size = (size + 7) / 8; // pixelcount-to-bits
|
||||
|
|
@ -1920,6 +1900,45 @@ void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in)
|
|||
|
||||
memset(mPickMask, 0, sizeof(U8) * size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void LLImageGL::freePickMask()
|
||||
{
|
||||
// pickmask validity depends on old image size, delete it
|
||||
if (mPickMask != NULL)
|
||||
{
|
||||
disclaimMem((mPickMaskWidth * mPickMaskHeight + 7) / 8);
|
||||
delete [] mPickMask;
|
||||
}
|
||||
mPickMask = NULL;
|
||||
mPickMaskWidth = mPickMaskHeight = 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in)
|
||||
{
|
||||
if(!mNeedsAlphaAndPickMask)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
freePickMask();
|
||||
|
||||
if (mFormatType != GL_UNSIGNED_BYTE ||
|
||||
mFormatPrimary != GL_RGBA)
|
||||
{
|
||||
//cannot generate a pick mask for this texture
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef SHOW_ASSERT
|
||||
const U32 pickSize = createPickMask(width, height);
|
||||
#else // SHOW_ASSERT
|
||||
createPickMask(width, height);
|
||||
#endif // SHOW_ASSERT
|
||||
|
||||
U32 pick_bit = 0;
|
||||
|
||||
for (S32 y = 0; y < height; y += 2)
|
||||
|
|
@ -1932,7 +1951,7 @@ void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in)
|
|||
{
|
||||
U32 pick_idx = pick_bit/8;
|
||||
U32 pick_offset = pick_bit%8;
|
||||
llassert(pick_idx < size);
|
||||
llassert(pick_idx < pickSize);
|
||||
|
||||
mPickMask[pick_idx] |= 1 << pick_offset;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -186,6 +186,9 @@ public:
|
|||
mutable F32 mLastBindTime; // last time this was bound, by discard level
|
||||
|
||||
private:
|
||||
U32 createPickMask(S32 pWidth, S32 pHeight);
|
||||
void freePickMask();
|
||||
|
||||
LLPointer<LLImageRaw> mSaveData; // used for destroyGL/restoreGL
|
||||
U8* mPickMask; //downsampled bitmap approximation of alpha channel. NULL if no alpha channel
|
||||
U16 mPickMaskWidth;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue