Pull merge from lindenlab/viewer-release

master
Merov Linden 2014-06-17 11:12:27 -07:00
commit c4c8debfc2
302 changed files with 9711 additions and 9197 deletions

View File

@ -481,3 +481,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

View File

@ -764,7 +764,7 @@
<key>hash</key>
<string>aff5566e04003de0383941981198e04e</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273073/arch/Darwin/installer/google_breakpad-0.0.0-rev1099-darwin-20130329.tar.bz2</string>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273073/arch/Darwin/installer/google_breakpad-0.0.0-rev1099-darwin-20130329.tar.bz2</string>
</map>
<key>name</key>
<string>darwin</string>
@ -776,7 +776,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>
@ -834,9 +834,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>
@ -1290,9 +1290,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>

View File

@ -42,6 +42,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}"

View File

@ -1,7 +1 @@
Wed Nov 7 00:25:19 UTC 2012
2014-02-25 10:34

28
indra/llappearance/llavatarappearance.cpp Normal file → Executable file
View File

@ -498,29 +498,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
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);
}
}
}
if (new_body_size != mBodySize || old_offset != mAvatarOffset.mV[VZ])
{
mBodySize = new_body_size;
bodySizeChanged();
}
}
@ -1390,14 +1370,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]);
}
}

10
indra/llappearance/llavatarappearance.h Normal file → Executable file
View File

@ -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;
@ -137,14 +136,13 @@ public:
typedef std::map<std::string, LLJoint*> joint_map_t;
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;
BOOL setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 &current_volume_num, S32 &current_joint_num);
BOOL allocateCharacterJoints(U32 num);
@ -225,7 +223,7 @@ public:
// Composites
//--------------------------------------------------------------------
public:
virtual void invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result) = 0;
virtual void invalidateComposite(LLTexLayerSet* layerset) = 0;
/********************************************************************************
** **
@ -256,7 +254,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);
@ -265,7 +263,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;

58
indra/llappearance/lldriverparam.cpp Normal file → Executable file
View File

@ -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);
}
}

9
indra/llappearance/lldriverparam.h Normal file → Executable file
View File

@ -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

View File

@ -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;
}
//-----------------------------------------------------------------------------

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

28
indra/llappearance/lltexglobalcolor.cpp Normal file → Executable file
View File

@ -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);
}
//-----------------------------------------------------------------------------

4
indra/llappearance/lltexglobalcolor.h Normal file → Executable file
View File

@ -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;
};

View File

@ -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);
}
}

94
indra/llappearance/lltexlayerparams.cpp Normal file → Executable file
View File

@ -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);
}
}

20
indra/llappearance/lltexlayerparams.h Normal file → Executable file
View File

@ -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);

View File

@ -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;
}

View File

@ -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

54
indra/llappearance/llwearable.cpp Normal file → Executable file
View File

@ -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);
}
}
}

7
indra/llappearance/llwearable.h Normal file → Executable file
View File

@ -46,6 +46,7 @@ class LLWearable
// Constructors and destructors
//--------------------------------------------------------------------
public:
LLWearable();
virtual ~LLWearable();
//--------------------------------------------------------------------
@ -94,14 +95,14 @@ public:
void setLocalTextureObject(S32 index, LLLocalTextureObject &lto);
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();

7
indra/llappearance/llwearabledata.cpp Normal file → Executable file
View File

@ -119,13 +119,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());

View File

@ -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());
}
}
}

View File

@ -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);

View File

@ -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();
}

View File

@ -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

View File

@ -172,6 +172,13 @@ void LLMotionController::deleteAllMotions()
for_each(mAllMotions.begin(), mAllMotions.end(), DeletePairedPointer());
mAllMotions.clear();
// 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();
}
//-----------------------------------------------------------------------------

View File

@ -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);
}
}

View File

@ -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

View File

@ -158,7 +158,6 @@ set(llcommon_HEADER_FILES
llhandle.h
llhash.h
llheartbeat.h
llhttpstatuscodes.h
llindexedvector.h
llinitparam.h
llinstancetracker.h

View File

@ -47,6 +47,7 @@
#include "lllivefile.h"
#include "llsd.h"
#include "llsdserialize.h"
#include "llsingleton.h"
#include "llstl.h"
#include "lltimer.h"
@ -356,30 +357,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);
@ -396,25 +398,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;
@ -429,81 +423,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;
}
}
@ -604,7 +603,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);
@ -613,11 +612,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);
@ -645,7 +646,8 @@ namespace LLError
}
commonInit(dir);
#if !LL_WINDOWS
addRecorder(new RecordToSyslog(identity));
LLError::RecorderPtr recordToSyslog(new RecordToSyslog(identity));
addRecorder(recordToSyslog);
#endif
}
@ -656,72 +658,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)
@ -765,15 +762,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"]));
@ -786,10 +782,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);
}
}
}
@ -803,10 +799,12 @@ namespace LLError
mWantsLevel(true),
mWantsLocation(false),
mWantsFunctionName(true)
{}
{
}
Recorder::~Recorder()
{ }
{
}
bool Recorder::wantsTime()
{
@ -837,25 +835,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());
}
}
@ -863,51 +861,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;
}
}
@ -916,24 +910,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())
@ -1060,10 +1054,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);
@ -1077,21 +1070,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;
}
@ -1101,12 +1094,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;
}
}
@ -1131,13 +1124,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
{
@ -1154,15 +1146,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
{
@ -1178,8 +1170,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;
@ -1195,7 +1187,7 @@ namespace LLError
else
{
message_stream << "ONCE: ";
s.mUniqueLogMessages[message] = 1;
s->mUniqueLogMessages[message] = 1;
}
}
@ -1203,23 +1195,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)
@ -1265,8 +1257,8 @@ namespace LLError
int shouldLogCallCount()
{
Settings& s = Settings::get();
return s.mShouldLogCallCounter;
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
return s->mShouldLogCallCounter;
}
#if LL_WINDOWS
@ -1375,15 +1367,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] ;
@ -1393,6 +1379,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)
{
@ -1424,15 +1435,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)
@ -1463,11 +1468,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();
}
}
@ -1477,5 +1480,10 @@ namespace LLError
sIndex = 0 ;
}
//static
void LLCallStacks::cleanup()
{
freeStackBuffer();
}
}

View File

@ -261,6 +261,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) ;
@ -268,6 +271,7 @@ namespace LLError
static void print() ;
static void clear() ;
static void end(std::ostringstream* _out) ;
static void cleanup();
};
}

View File

@ -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();

View File

@ -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

View File

@ -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>
@ -629,7 +630,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

View File

@ -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>
{

View File

@ -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); }

View File

@ -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(); }

View File

@ -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());

View File

@ -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;

View File

@ -168,8 +168,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:
@ -182,7 +182,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;
@ -375,13 +375,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);

View File

@ -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);

View File

@ -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.

View File

@ -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);
}
}

View File

@ -95,7 +95,7 @@ namespace tut
ensure_equals(stringize(f), "3.14159");
ensure_equals(stringize(d), "3.14159");
ensure_equals(stringize(abc), "abc def");
ensure_equals(stringize(def), "def ghi"); //Will generate llwarns due to narrowing.
ensure_equals(stringize(def), "def ghi"); //Will generate LL_WARNS() due to narrowing.
ensure_equals(stringize(llsd), "{'abc':'abc def','d':r3.14159,'i':i34}");
}

View File

@ -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);
}

View File

@ -31,7 +31,7 @@
#include "_httpoprequest.h"
#include "_httppolicy.h"
#include "llhttpstatuscodes.h"
#include "llhttpconstants.h"
namespace LLCore

View File

@ -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");
}

View File

@ -52,17 +52,20 @@ BOOL gSent = false;
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;

View File

@ -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);
@ -1068,11 +1067,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;
@ -1129,6 +1133,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))
{

View File

@ -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,22 +87,19 @@ public:
void setType(LLAssetType::EType type);
virtual void setCreationDate(time_t creation_date_utc); // only stored for items
private:
// in place correction for inventory name string
void correctInventoryName(std::string& name);
static 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;
@ -174,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);
@ -212,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

View File

@ -44,6 +44,7 @@ set(llmessage_SOURCE_FILES
llhttpassetstorage.cpp
llhttpclient.cpp
llhttpclientadapter.cpp
llhttpconstants.cpp
llhttpnode.cpp
llhttpsender.cpp
llinstantmessage.cpp
@ -59,7 +60,6 @@ set(llmessage_SOURCE_FILES
llmessagetemplate.cpp
llmessagetemplateparser.cpp
llmessagethrottle.cpp
llmime.cpp
llnamevalue.cpp
llnullcipher.cpp
llpacketack.cpp
@ -68,7 +68,6 @@ set(llmessage_SOURCE_FILES
llpartdata.cpp
llproxy.cpp
llpumpio.cpp
llregionpresenceverifier.cpp
llsdappservices.cpp
llsdhttpserver.cpp
llsdmessage.cpp
@ -138,6 +137,7 @@ set(llmessage_HEADER_FILES
llhttpclient.h
llhttpclientinterface.h
llhttpclientadapter.h
llhttpconstants.h
llhttpnode.h
llhttpnodeadapter.h
llhttpsender.h
@ -156,7 +156,6 @@ set(llmessage_HEADER_FILES
llmessagetemplate.h
llmessagetemplateparser.h
llmessagethrottle.h
llmime.h
llmsgvariabletype.h
llnamevalue.h
llnullcipher.h
@ -169,7 +168,6 @@ set(llmessage_HEADER_FILES
llqueryflags.h
llregionflags.h
llregionhandle.h
llregionpresenceverifier.h
llsdappservices.h
llsdhttpserver.h
llsdmessage.h
@ -233,17 +231,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}
@ -270,6 +266,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)

View File

@ -610,6 +610,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(),

View File

@ -578,5 +578,6 @@ extern LLAres *gAres;
* thread safe.
*/
extern LLAres *ll_init_ares();
extern void ll_cleanup_ares();
#endif // LL_LLARES_H

View File

@ -121,7 +121,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:
@ -165,33 +165,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)
{
@ -212,7 +210,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)
{
@ -236,14 +234,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();
@ -700,7 +697,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)
{
F64 expires = 0.0;
if (expirationFromCacheControl(headers, &expires))
@ -716,17 +713,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;

View File

@ -90,7 +90,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);
}

View File

@ -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,44 +178,109 @@ 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))
const bool emit_parse_errors = false;
std::string debug_body("(empty)");
bool parsed=true;
if (EOF == istr.peek())
{
LL_INFOS() << "Failed to deserialize LLSD. " << mURL << " [" << status << "]: " << reason << LL_ENDL;
content["reason"] = reason;
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;
}
}
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;
@ -274,6 +349,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)
@ -289,7 +394,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;
}
@ -317,10 +423,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;
@ -384,9 +494,9 @@ 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)
{
U32 responseCode = 0;
S32 responseCode = 0;
std::string responseReason;
if (code == CURLE_OK)
@ -396,14 +506,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;
}
@ -440,9 +551,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)
@ -530,8 +663,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)
@ -810,7 +944,7 @@ S32 LLCurl::Multi::process()
++processed;
if (msg->msg == CURLMSG_DONE)
{
U32 response = 0;
S32 response = 0;
Easy* easy = NULL ;
{
@ -829,7 +963,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;
}
@ -1128,13 +1262,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);
@ -1161,7 +1295,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;
@ -1189,7 +1323,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;
@ -1561,6 +1695,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)
@ -1745,17 +1887,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 ;

View File

@ -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,59 +77,92 @@ 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);
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;
@ -227,10 +261,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);
@ -269,6 +304,9 @@ private:
static std::set<CURL*> sFreeHandles;
static std::set<CURL*> sActiveHandles;
static LLMutex* sHandleMutexp ;
static void deleteAllActiveHandles();
static void deleteAllFreeHandles();
};
class LLCurl::Multi
@ -486,6 +524,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();

View File

@ -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;
}

View File

@ -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,9 +127,9 @@ namespace
{
public:
RawInjector(const U8* data, S32 size) : mData(data), mSize(size) {}
virtual ~RawInjector() {delete mData;}
virtual ~RawInjector() {delete [] mData;}
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)
@ -147,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)
@ -180,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)
@ -213,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,
@ -225,7 +228,7 @@ static void request(
{
if (responder)
{
responder->completed(U32_MAX, "No pump", LLSD());
responder->completeResult(HTTP_INTERNAL_ERROR, "No pump");
}
delete body_injector;
return;
@ -237,90 +240,82 @@ 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());
}
}
// 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));
@ -342,9 +337,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(
@ -354,18 +349,18 @@ 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);
}
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 */)
@ -408,7 +403,7 @@ public:
return content;
}
std::string asString()
const std::string& asString()
{
return mBuffer;
}
@ -437,7 +432,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
@ -480,11 +475,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 :(
@ -493,18 +488,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 )
{
@ -513,11 +510,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;
@ -547,12 +544,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(
@ -562,7 +559,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(
@ -572,7 +579,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(
@ -583,7 +590,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(
@ -593,7 +600,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(
@ -604,7 +611,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
@ -614,7 +621,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
@ -626,8 +633,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);
}

View File

@ -79,6 +79,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,
@ -118,7 +126,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
*
@ -135,6 +143,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);
//@}
/**

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

225
indra/llmessage/llhttpconstants.h Executable file
View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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:

View File

@ -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;
@ -620,8 +623,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)));

View File

@ -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;
/**

View File

@ -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);
}
*/

View File

@ -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

View File

@ -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)
{
++p->mReferenceCount;
}
void intrusive_ptr_release(LLRegionPresenceVerifier::Response* p)
{
if(p && 0 == --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();
}
}

View File

@ -1,98 +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;
};
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

View File

@ -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));
}
};

View File

@ -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)
{

View File

@ -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 ----------------*/

View File

@ -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;

View File

@ -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)));

View File

@ -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
{

View File

@ -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

View File

@ -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
*/
@ -131,27 +131,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)
{
@ -159,7 +140,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),
@ -184,12 +165,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);
}
@ -276,7 +262,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);
@ -504,21 +490,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);
@ -529,13 +526,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;
@ -648,7 +651,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;
}
}

View File

@ -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,17 +104,17 @@ public:
*
*/
void setURL(const std::string& url);
std::string getURL() const;
const std::string& getURL() const;
/**
* @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.
@ -218,7 +199,7 @@ protected:
STATE_HAVE_RESPONSE,
};
EState mState;
ERequestAction mAction;
EHTTPMethod mAction;
bool mFollowRedirects;
LLURLRequestDetail* mDetail;
LLIOPipe::ptr_t mCompletionCallback;
@ -316,7 +297,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,
@ -369,15 +350,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

View File

@ -110,20 +110,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);
}
@ -149,7 +149,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;

View File

@ -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

View File

@ -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:

View File

@ -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);
}
}

View File

@ -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) {}

View File

@ -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<>()
{
}
*/
}

View File

@ -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);
}
}

View File

@ -32,6 +32,7 @@
#include "message.h"
#include "llmessageconfig.h"
#include "llhttpnode_stub.cpp"
LLMessageSystem* gMessageSystem = NULL;

View File

@ -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)

View File

@ -131,6 +131,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);
@ -960,6 +962,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);

View File

@ -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

View File

@ -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
}
@ -504,10 +504,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;
@ -1886,27 +1883,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
@ -1917,6 +1897,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)
@ -1929,7 +1948,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;
}

View File

@ -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;

View File

@ -35,8 +35,9 @@
//
LLBadgeOwner::LLBadgeOwner(LLHandle< LLView > viewHandle)
: mBadge(NULL)
, mBadgeOwnerView(viewHandle)
: mHasBadgeHolderParent(false),
mBadge(NULL),
mBadgeOwnerView(viewHandle)
{
}
@ -45,31 +46,12 @@ void LLBadgeOwner::initBadgeParams(const LLBadge::Params& p)
if (!p.equals(LLUICtrlFactory::getDefaultParams<LLBadge>()))
{
mBadge = createBadge(p);
}
}
mHasBadgeHolderParent = false;
void LLBadgeOwner::setBadgeLabel(const LLStringExplicit& label)
{
if (mBadge == NULL)
{
mBadge = createBadge(LLUICtrlFactory::getDefaultParams<LLBadge>());
addBadgeToParentPanel();
}
if (mBadge)
{
mBadge->setLabel(label);
//
// Push the badge to the front so it renders on top
//
LLView * parent = mBadge->getParent();
if (parent)
LLView * owner_view = mBadgeOwnerView.get();
if (owner_view)
{
parent->sendChildToFront(mBadge);
mBadge->addToView(owner_view);
}
}
}
@ -82,10 +64,8 @@ void LLBadgeOwner::setBadgeVisibility(bool visible)
}
}
bool LLBadgeOwner::addBadgeToParentPanel()
void LLBadgeOwner::addBadgeToParentHolder()
{
bool badge_added = false;
LLView * owner_view = mBadgeOwnerView.get();
if (mBadge && owner_view)
@ -110,16 +90,9 @@ bool LLBadgeOwner::addBadgeToParentPanel()
if (badge_holder)
{
badge_added = badge_holder->addBadge(mBadge);
}
else
{
// Badge parent is fallback badge owner if no valid holder exists in the hierarchy
badge_added = mBadge->addToView(owner_view);
mHasBadgeHolderParent = badge_holder->addBadge(mBadge);
}
}
return badge_added;
}
LLBadge* LLBadgeOwner::createBadge(const LLBadge::Params& p)

View File

@ -41,11 +41,9 @@ public:
LLBadgeOwner(LLHandle< LLView > viewHandle);
void initBadgeParams(const LLBadge::Params& p);
bool addBadgeToParentPanel();
void addBadgeToParentHolder();
bool badgeHasParent() const { return (mBadge && mBadge->getParent()); }
void setBadgeLabel(const LLStringExplicit& label);
bool hasBadgeHolderParent() const { return mHasBadgeHolderParent; };
void setBadgeVisibility(bool visible);
private:
@ -53,7 +51,7 @@ private:
LLBadge* createBadge(const LLBadge::Params& p);
private:
bool mHasBadgeHolderParent;
LLBadge* mBadge;
LLHandle< LLView > mBadgeOwnerView;
};

View File

@ -384,7 +384,7 @@ BOOL LLButton::postBuild()
{
autoResize();
addBadgeToParentPanel();
addBadgeToParentHolder();
return LLUICtrl::postBuild();
}

Some files were not shown because too many files have changed in this diff Show More