diff --git a/.hgtags b/.hgtags index 8248f3dfeb..61934b7a64 100755 --- a/.hgtags +++ b/.hgtags @@ -519,3 +519,4 @@ fc066b82343fca51f9c1b8eda0abc6bee9bb4503 3.7.5-release d029faf69f20a23007f32420a1ac6a3b89a6d441 3.7.6-release 83959480cb986522d07b151a0c778ab7f920d41b 3.7.7-release bba9b3722eea08949e4ff69591f736bf0f808434 3.7.8-release +a9f2d0cb11f73b06858e6083bb50083becc3f9cd 3.7.9-release diff --git a/autobuild.xml b/autobuild.xml index 87a03c8de7..63b94f26c2 100755 --- a/autobuild.xml +++ b/autobuild.xml @@ -1024,7 +1024,7 @@ hash 52257e5eb166a0b69c9c0c38f6e1920e url - 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 + 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 name linux @@ -1094,9 +1094,9 @@ archive hash - d2542614df9dd99cbb5ff67e76d4a6c1 + 98994d5b0b4b3d43be22aa6a5c36e6fa url - 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 + 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 name windows @@ -1742,9 +1742,9 @@ archive hash - b6d29de20de5c8f31925697b30e8f727 + 54e46715e72b7805d9d3f84d45b6b1b7 url - 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 + 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 name linux diff --git a/indra/cmake/BuildVersion.cmake b/indra/cmake/BuildVersion.cmake index 7c83fedbbd..14bf97efac 100755 --- a/indra/cmake/BuildVersion.cmake +++ b/indra/cmake/BuildVersion.cmake @@ -49,6 +49,11 @@ if (NOT DEFINED VIEWER_SHORT_VERSION) # will be true in indra/, false in indra/n message(SEND_ERROR "Cannot get viewer version from '${VIEWER_VERSION_BASE_FILE}'") endif ( EXISTS ${VIEWER_VERSION_BASE_FILE} ) + if ("${VIEWER_VERSION_REVISION}" STREQUAL "") + message("Ultimate fallback, revision was blank or not set: will use 0") + set(VIEWER_VERSION_REVISION 0) + endif ("${VIEWER_VERSION_REVISION}" STREQUAL "") + set(VIEWER_CHANNEL_VERSION_DEFINES "LL_VIEWER_CHANNEL=\"${VIEWER_CHANNEL}\"" "LL_VIEWER_VERSION_MAJOR=${VIEWER_VERSION_MAJOR}" diff --git a/indra/edit-me-to-trigger-new-build.txt b/indra/edit-me-to-trigger-new-build.txt index beeb570496..c63ad74682 100755 --- a/indra/edit-me-to-trigger-new-build.txt +++ b/indra/edit-me-to-trigger-new-build.txt @@ -1,7 +1 @@ -Wed Nov 7 00:25:19 UTC 2012 - - - - - - +2014-02-25 10:34 diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp old mode 100644 new mode 100755 index 3622a24591..92fa541422 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -510,33 +510,9 @@ void LLAvatarAppearance::computeBodySize() mAvatarOffset.mV[VX] = 0.0f; mAvatarOffset.mV[VY] = 0.0f; - - // Certain configurations of avatars can force the overall height (with offset) to go negative. - // Enforce a constraint to make sure we don't go below 0.1 meters. - // Camera positioning and other things start to break down when your avatar is "walking" while being fully underground -// [FS:CR] This is a bad check and will force your head in the ground if the following is true. -#if 0 - if (new_body_size.mV[VZ] + mAvatarOffset.mV[VZ] < 0.1f) - { - mAvatarOffset.mV[VZ] = -(new_body_size.mV[VZ] - 0.11f); // avoid floating point rounding making the above check continue to fail. - - llassert(new_body_size.mV[VZ] + mAvatarOffset.mV[VZ] >= 0.1f); - - if (mWearableData && isSelf()) - { - LLWearable* shape = mWearableData->getWearable(LLWearableType::WT_SHAPE, 0); - if (shape) - { - shape->setVisualParamWeight(AVATAR_HOVER, mAvatarOffset.mV[VZ], false); - } - } - } -#endif // [/FS:CR] - if (new_body_size != mBodySize || old_offset != mAvatarOffset.mV[VZ]) { mBodySize = new_body_size; - bodySizeChanged(); } } @@ -1413,14 +1389,14 @@ BOOL LLAvatarAppearance::teToColorParams( ETextureIndex te, U32 *param_name ) return TRUE; } -void LLAvatarAppearance::setClothesColor( ETextureIndex te, const LLColor4& new_color, BOOL upload_bake ) +void LLAvatarAppearance::setClothesColor( ETextureIndex te, const LLColor4& new_color) { U32 param_name[3]; if( teToColorParams( te, param_name ) ) { - setVisualParamWeight( param_name[0], new_color.mV[VX], upload_bake ); - setVisualParamWeight( param_name[1], new_color.mV[VY], upload_bake ); - setVisualParamWeight( param_name[2], new_color.mV[VZ], upload_bake ); + setVisualParamWeight( param_name[0], new_color.mV[VX]); + setVisualParamWeight( param_name[1], new_color.mV[VY]); + setVisualParamWeight( param_name[2], new_color.mV[VZ]); } } diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h old mode 100644 new mode 100755 index 8ff0c45e91..d81741da4a --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -107,7 +107,6 @@ public: public: virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent virtual BOOL isValid() const; - virtual BOOL isUsingServerBakes() const = 0; virtual BOOL isUsingLocalAppearance() const = 0; virtual BOOL isEditingAppearance() const = 0; @@ -141,14 +140,13 @@ public: joint_map_t mJointMap; - void computeBodySize(); + void computeBodySize(); protected: static BOOL parseSkeletonFile(const std::string& filename); virtual void buildCharacter(); virtual BOOL loadAvatar(); - virtual void bodySizeChanged() = 0; // [RLVa:KB] - Checked: 2013-03-03 (RLVa-1.4.8) virtual F32 getAvatarOffset() /*const*/; // [/RLVa:KB] @@ -232,7 +230,7 @@ public: // Composites //-------------------------------------------------------------------- public: - virtual void invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result) = 0; + virtual void invalidateComposite(LLTexLayerSet* layerset) = 0; /******************************************************************************** ** ** @@ -263,7 +261,7 @@ protected: // Clothing colors (convenience functions to access visual parameters) //-------------------------------------------------------------------- public: - void setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color, BOOL upload_bake); + void setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color); LLColor4 getClothesColor(LLAvatarAppearanceDefines::ETextureIndex te); static BOOL teToColorParams(LLAvatarAppearanceDefines::ETextureIndex te, U32 *param_name); @@ -272,7 +270,7 @@ public: //-------------------------------------------------------------------- public: LLColor4 getGlobalColor(const std::string& color_name ) const; - virtual void onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake) = 0; + virtual void onGlobalColorChanged(const LLTexGlobalColor* global_color) = 0; protected: LLTexGlobalColor* mTexSkinColor; LLTexGlobalColor* mTexHairColor; diff --git a/indra/llappearance/lldriverparam.cpp b/indra/llappearance/lldriverparam.cpp old mode 100644 new mode 100755 index c66a428374..e630c1118b --- a/indra/llappearance/lldriverparam.cpp +++ b/indra/llappearance/lldriverparam.cpp @@ -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); } } diff --git a/indra/llappearance/lldriverparam.h b/indra/llappearance/lldriverparam.h old mode 100644 new mode 100755 index 2420db76e7..f71c930e5e --- a/indra/llappearance/lldriverparam.h +++ b/indra/llappearance/lldriverparam.h @@ -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 diff --git a/indra/llappearance/llpolymorph.cpp b/indra/llappearance/llpolymorph.cpp index ce8a0b0b76..e3992a080e 100644 --- a/indra/llappearance/llpolymorph.cpp +++ b/indra/llappearance/llpolymorph.cpp @@ -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; } //----------------------------------------------------------------------------- diff --git a/indra/llappearance/llpolymorph.h b/indra/llappearance/llpolymorph.h index ee380ae7c3..7e712f9e94 100644 --- a/indra/llappearance/llpolymorph.h +++ b/indra/llappearance/llpolymorph.h @@ -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; diff --git a/indra/llappearance/llpolyskeletaldistortion.cpp b/indra/llappearance/llpolyskeletaldistortion.cpp index a72b446ace..ea29cbd451 100644 --- a/indra/llappearance/llpolyskeletaldistortion.cpp +++ b/indra/llappearance/llpolyskeletaldistortion.cpp @@ -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); } diff --git a/indra/llappearance/llpolyskeletaldistortion.h b/indra/llappearance/llpolyskeletaldistortion.h index 24c9e9ae48..ea2adb8a87 100644 --- a/indra/llappearance/llpolyskeletaldistortion.h +++ b/indra/llappearance/llpolyskeletaldistortion.h @@ -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 joint_vec_map_t; joint_vec_map_t mJointScales; diff --git a/indra/llappearance/lltexglobalcolor.cpp b/indra/llappearance/lltexglobalcolor.cpp old mode 100644 new mode 100755 index 186c537659..3df2254b14 --- a/indra/llappearance/lltexglobalcolor.cpp +++ b/indra/llappearance/lltexglobalcolor.cpp @@ -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); } //----------------------------------------------------------------------------- diff --git a/indra/llappearance/lltexglobalcolor.h b/indra/llappearance/lltexglobalcolor.h old mode 100644 new mode 100755 index 2867479876..3b426053de --- a/indra/llappearance/lltexglobalcolor.h +++ b/indra/llappearance/lltexglobalcolor.h @@ -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; }; diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index 80e3df19bc..f3626fea62 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -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); } } diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp old mode 100644 new mode 100755 index f1f7d07fa9..ff682d6906 --- a/indra/llappearance/lltexlayerparams.cpp +++ b/indra/llappearance/lltexlayerparams.cpp @@ -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); } } diff --git a/indra/llappearance/lltexlayerparams.h b/indra/llappearance/lltexlayerparams.h old mode 100644 new mode 100755 index b38d28d3eb..0cb2dedbff --- a/indra/llappearance/lltexlayerparams.h +++ b/indra/llappearance/lltexlayerparams.h @@ -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 mCachedProcessedTexture; LLPointer mStaticImageTGA; LLPointer 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); diff --git a/indra/llappearance/llviewervisualparam.cpp b/indra/llappearance/llviewervisualparam.cpp index cc81bcf118..af8394b60c 100644 --- a/indra/llappearance/llviewervisualparam.cpp +++ b/indra/llappearance/llviewervisualparam.cpp @@ -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; } diff --git a/indra/llappearance/llviewervisualparam.h b/indra/llappearance/llviewervisualparam.h index 2826e6c316..1a710c0ca6 100644 --- a/indra/llappearance/llviewervisualparam.h +++ b/indra/llappearance/llviewervisualparam.h @@ -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 diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp old mode 100644 new mode 100755 index 389505fa34..4bce3f99ed --- a/indra/llappearance/llwearable.cpp +++ b/indra/llappearance/llwearable.cpp @@ -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(param) ) { - setVisualParamWeight(id, value, TRUE); + setVisualParamWeight(id, value); } } @@ -537,7 +560,7 @@ void LLWearable::revertValues() LLVisualParam *param = getVisualParam(id); if(param && dynamic_cast(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); } } } diff --git a/indra/llappearance/llwearable.h b/indra/llappearance/llwearable.h old mode 100644 new mode 100755 index 87ea6010bf..bb0775c56c --- a/indra/llappearance/llwearable.h +++ b/indra/llappearance/llwearable.h @@ -46,6 +46,7 @@ class LLWearable // Constructors and destructors //-------------------------------------------------------------------- public: + LLWearable(); virtual ~LLWearable(); //-------------------------------------------------------------------- @@ -94,14 +95,14 @@ public: void setLocalTextureObject(S32 index, LLLocalTextureObject <o); void addVisualParam(LLVisualParam *param); - void setVisualParamWeight(S32 index, F32 value, BOOL upload_bake); + void setVisualParamWeight(S32 index, F32 value); F32 getVisualParamWeight(S32 index) const; LLVisualParam* getVisualParam(S32 index) const; void getVisualParams(visual_param_vec_t &list); - void animateParams(F32 delta, BOOL upload_bake); + void animateParams(F32 delta); LLColor4 getClothesColor(S32 te) const; - void setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake ); + void setClothesColor( S32 te, const LLColor4& new_color); virtual void revertValues(); virtual void saveValues(); diff --git a/indra/llappearance/llwearabledata.cpp b/indra/llappearance/llwearabledata.cpp old mode 100644 new mode 100755 index 169608e168..1f665e1702 --- a/indra/llappearance/llwearabledata.cpp +++ b/indra/llappearance/llwearabledata.cpp @@ -139,13 +139,6 @@ U32 LLWearableData::pushWearable(const LLWearableType::EType type, void LLWearableData::wearableUpdated(LLWearable *wearable, BOOL removed) { wearable->setUpdated(); - // FIXME DRANO avoid updating params via wearables when rendering server-baked appearance. -#if 0 - if (mAvatarAppearance->isUsingServerBakes() && !mAvatarAppearance->isUsingLocalAppearance()) - { - return; - } -#endif if (!removed) { pullCrossWearableValues(wearable->getType()); diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp index b173abdc40..54cc2f1027 100755 --- a/indra/llcharacter/llcharacter.cpp +++ b/indra/llcharacter/llcharacter.cpp @@ -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()); } } } diff --git a/indra/llcharacter/llcharacter.h b/indra/llcharacter/llcharacter.h index b10a8a5f34..d4e3b76386 100755 --- a/indra/llcharacter/llcharacter.h +++ b/indra/llcharacter/llcharacter.h @@ -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); diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp index 1492cc172c..dbd6d48a95 100755 --- a/indra/llcharacter/lljoint.cpp +++ b/indra/llcharacter/lljoint.cpp @@ -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(); } diff --git a/indra/llcharacter/lljoint.h b/indra/llcharacter/lljoint.h index 6efa13aeb5..b65d6979d4 100755 --- a/indra/llcharacter/lljoint.h +++ b/indra/llcharacter/lljoint.h @@ -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 diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp index 3216cd6082..e02b139608 100755 --- a/indra/llcharacter/llmotioncontroller.cpp +++ b/indra/llcharacter/llmotioncontroller.cpp @@ -173,10 +173,12 @@ void LLMotionController::deleteAllMotions() for_each(mAllMotions.begin(), mAllMotions.end(), DeletePairedPointer()); mAllMotions.clear(); - // There might still be motions in mDeprecatedMotions. Don't leak those. - for_each(mDeprecatedMotions.begin(), mDeprecatedMotions.end(), DeletePointer() ); + // stinson 05/12/20014 : Ownership of the LLMotion pointers is transferred from + // mAllMotions to mDeprecatedMotions in method + // LLMotionController::deprecateMotionInstance(). Thus, we should also clean + // up the mDeprecatedMotions list as well. + for_each(mDeprecatedMotions.begin(), mDeprecatedMotions.end(), DeletePointer()); mDeprecatedMotions.clear(); - // } //----------------------------------------------------------------------------- diff --git a/indra/llcharacter/llvisualparam.cpp b/indra/llcharacter/llvisualparam.cpp index 0df7fb2bc3..2235496ac5 100755 --- a/indra/llcharacter/llvisualparam.cpp +++ b/indra/llcharacter/llvisualparam.cpp @@ -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); } } diff --git a/indra/llcharacter/llvisualparam.h b/indra/llcharacter/llvisualparam.h index a4d9f93e56..c6b97d7e8b 100755 --- a/indra/llcharacter/llvisualparam.h +++ b/indra/llcharacter/llvisualparam.h @@ -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 diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 6a69669c4d..c1f22f0076 100755 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -158,7 +158,6 @@ set(llcommon_HEADER_FILES llhandle.h llhash.h llheartbeat.h - llhttpstatuscodes.h llindexedvector.h llinitparam.h llinstancetracker.h diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 8da553ca33..70b78e57df 100755 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -47,6 +47,7 @@ #include "lllivefile.h" #include "llsd.h" #include "llsdserialize.h" +#include "llsingleton.h" #include "llstl.h" #include "lltimer.h" @@ -363,30 +364,31 @@ namespace typedef std::map LevelMap; - typedef std::vector Recorders; + typedef std::vector Recorders; typedef std::vector CallSiteVector; - class Globals + class Globals : public LLSingleton { public: + Globals(); + std::ostringstream messageStream; bool messageStreamInUse; void addCallSite(LLError::CallSite&); void invalidateCallSites(); - - static Globals& get(); - // return the one instance of the globals private: CallSiteVector callSites; - - Globals() - : messageStreamInUse(false) - { } - }; + Globals::Globals() + : messageStream(), + messageStreamInUse(false), + callSites() + { + } + void Globals::addCallSite(LLError::CallSite& site) { callSites.push_back(&site); @@ -403,25 +405,17 @@ namespace callSites.clear(); } - - Globals& Globals::get() - { - /* This pattern, of returning a reference to a static function - variable, is to ensure that this global is constructed before - it is used, no matter what the global initialization sequence - is. - See C++ FAQ Lite, sections 10.12 through 10.14 - */ - static Globals* globals = new Globals; - return *globals; - } } namespace LLError { - class Settings + class SettingsConfig : public LLRefCount { + friend class Settings; + public: + virtual ~SettingsConfig(); + bool mPrintLocation; LLError::ELevel mDefaultLevel; @@ -436,81 +430,86 @@ namespace LLError LLError::TimeFunction mTimeFunction; Recorders mRecorders; - Recorder* mFileRecorder; - Recorder* mFixedBufferRecorder; + RecorderPtr mFileRecorder; + RecorderPtr mFixedBufferRecorder; std::string mFileRecorderFileName; int mShouldLogCallCounter; - static Settings& get(); + private: + SettingsConfig(); + }; + + typedef LLPointer SettingsConfigPtr; + + class Settings : public LLSingleton + { + 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(), + 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(pSettingsStorage.get())); + mSettingsConfig = newSettingsConfig; } } @@ -646,7 +645,7 @@ namespace void commonInit(const std::string& dir, bool log_to_stderr = true) { - LLError::Settings::reset(); + LLError::Settings::getInstance()->reset(); LLError::setDefaultLevel(LLError::LEVEL_INFO); LLError::setFatalFunction(LLError::crashAndLoop); @@ -655,11 +654,13 @@ namespace // log_to_stderr is only false in the unit and integration tests to keep builds quieter if (log_to_stderr && shouldLogToStderr()) { - LLError::addRecorder(new RecordToStderr(stderrLogWantsTime())); + LLError::RecorderPtr recordToStdErr(new RecordToStderr(stderrLogWantsTime())); + LLError::addRecorder(recordToStdErr); } #if LL_WINDOWS - LLError::addRecorder(new RecordToWinDebug); + LLError::RecorderPtr recordToWinDebug(new RecordToWinDebug()); + LLError::addRecorder(recordToWinDebug); #endif LogControlFile& e = LogControlFile::fromDirectory(dir); @@ -687,7 +688,8 @@ namespace LLError } commonInit(dir); #if !LL_WINDOWS - addRecorder(new RecordToSyslog(identity)); + LLError::RecorderPtr recordToSyslog(new RecordToSyslog(identity)); + addRecorder(recordToSyslog); #endif } @@ -698,72 +700,67 @@ namespace LLError void setPrintLocation(bool print) { - Settings& s = Settings::get(); - s.mPrintLocation = print; + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + s->mPrintLocation = print; } void setFatalFunction(const FatalFunction& f) { - Settings& s = Settings::get(); - s.mCrashFunction = f; + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + s->mCrashFunction = f; } FatalFunction getFatalFunction() { - Settings& s = Settings::get(); - return s.mCrashFunction; + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + return s->mCrashFunction; } void setTimeFunction(TimeFunction f) { - Settings& s = Settings::get(); - s.mTimeFunction = f; + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + s->mTimeFunction = f; } void setDefaultLevel(ELevel level) { - Globals& g = Globals::get(); - Settings& s = Settings::get(); - g.invalidateCallSites(); - s.mDefaultLevel = level; + Globals::getInstance()->invalidateCallSites(); + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + s->mDefaultLevel = level; } ELevel getDefaultLevel() { - Settings& s = Settings::get(); - return s.mDefaultLevel; + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + return s->mDefaultLevel; } void setFunctionLevel(const std::string& function_name, ELevel level) { - Globals& g = Globals::get(); - Settings& s = Settings::get(); - g.invalidateCallSites(); - s.mFunctionLevelMap[function_name] = level; + Globals::getInstance()->invalidateCallSites(); + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + s->mFunctionLevelMap[function_name] = level; } void setClassLevel(const std::string& class_name, ELevel level) { - Globals& g = Globals::get(); - Settings& s = Settings::get(); - g.invalidateCallSites(); - s.mClassLevelMap[class_name] = level; + Globals::getInstance()->invalidateCallSites(); + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + s->mClassLevelMap[class_name] = level; } void setFileLevel(const std::string& file_name, ELevel level) { - Globals& g = Globals::get(); - Settings& s = Settings::get(); - g.invalidateCallSites(); - s.mFileLevelMap[file_name] = level; + Globals::getInstance()->invalidateCallSites(); + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + s->mFileLevelMap[file_name] = level; } void setTagLevel(const std::string& tag_name, ELevel level) { - Globals& g = Globals::get(); - Settings& s = Settings::get(); - g.invalidateCallSites(); - s.mTagLevelMap[tag_name] = level; + Globals::getInstance()->invalidateCallSites(); + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + s->mTagLevelMap[tag_name] = level; } LLError::ELevel decodeLevel(std::string name) @@ -807,15 +804,14 @@ namespace LLError { void configure(const LLSD& config) { - Globals& g = Globals::get(); - Settings& s = Settings::get(); + Globals::getInstance()->invalidateCallSites(); + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); - g.invalidateCallSites(); - s.mFunctionLevelMap.clear(); - s.mClassLevelMap.clear(); - s.mFileLevelMap.clear(); - s.mTagLevelMap.clear(); - s.mUniqueLogMessages.clear(); + s->mFunctionLevelMap.clear(); + s->mClassLevelMap.clear(); + s->mFileLevelMap.clear(); + s->mTagLevelMap.clear(); + s->mUniqueLogMessages.clear(); setPrintLocation(config["print-location"]); setDefaultLevel(decodeLevel(config["default-level"])); @@ -828,10 +824,10 @@ namespace LLError ELevel level = decodeLevel(entry["level"]); - setLevels(s.mFunctionLevelMap, entry["functions"], level); - setLevels(s.mClassLevelMap, entry["classes"], level); - setLevels(s.mFileLevelMap, entry["files"], level); - setLevels(s.mTagLevelMap, entry["tags"], level); + setLevels(s->mFunctionLevelMap, entry["functions"], level); + setLevels(s->mClassLevelMap, entry["classes"], level); + setLevels(s->mFileLevelMap, entry["files"], level); + setLevels(s->mTagLevelMap, entry["tags"], level); } } } @@ -845,10 +841,12 @@ namespace LLError mWantsLevel(true), mWantsLocation(false), mWantsFunctionName(true) - {} + { + } Recorder::~Recorder() - { } + { + } bool Recorder::wantsTime() { @@ -879,25 +877,25 @@ namespace LLError return mWantsFunctionName; } - void addRecorder(Recorder* recorder) + void addRecorder(RecorderPtr recorder) { - if (recorder == NULL) + if (!recorder) { return; } - Settings& s = Settings::get(); - s.mRecorders.push_back(recorder); + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + s->mRecorders.push_back(recorder); } - void removeRecorder(Recorder* recorder) + void removeRecorder(RecorderPtr recorder) { - if (recorder == NULL) + if (!recorder) { return; } - Settings& s = Settings::get(); - s.mRecorders.erase(std::remove(s.mRecorders.begin(), s.mRecorders.end(), recorder), - s.mRecorders.end()); + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + s->mRecorders.erase(std::remove(s->mRecorders.begin(), s->mRecorders.end(), recorder), + s->mRecorders.end()); } } @@ -905,51 +903,47 @@ namespace LLError { void logToFile(const std::string& file_name) { - LLError::Settings& s = LLError::Settings::get(); + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); - removeRecorder(s.mFileRecorder); - delete s.mFileRecorder; - s.mFileRecorder = NULL; - s.mFileRecorderFileName.clear(); + removeRecorder(s->mFileRecorder); + s->mFileRecorder.reset(); + s->mFileRecorderFileName.clear(); if (file_name.empty()) { return; } - RecordToFile* f = new RecordToFile(file_name); - if (!f->okay()) + RecorderPtr recordToFile(new RecordToFile(file_name)); + if (boost::dynamic_pointer_cast(recordToFile)->okay()) { - delete f; - return; + s->mFileRecorderFileName = file_name; + s->mFileRecorder = recordToFile; + addRecorder(recordToFile); } - - s.mFileRecorderFileName = file_name; - s.mFileRecorder = f; - addRecorder(f); } void logToFixedBuffer(LLLineBuffer* fixedBuffer) { - LLError::Settings& s = LLError::Settings::get(); + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); - removeRecorder(s.mFixedBufferRecorder); - delete s.mFixedBufferRecorder; - s.mFixedBufferRecorder = NULL; + removeRecorder(s->mFixedBufferRecorder); + s->mFixedBufferRecorder.reset(); if (!fixedBuffer) { return; } - s.mFixedBufferRecorder = new RecordToFixedBuffer(fixedBuffer); - addRecorder(s.mFixedBufferRecorder); + RecorderPtr recordToFixedBuffer(new RecordToFixedBuffer(fixedBuffer)); + s->mFixedBufferRecorder = recordToFixedBuffer; + addRecorder(recordToFixedBuffer); } std::string logFileName() { - LLError::Settings& s = LLError::Settings::get(); - return s.mFileRecorderFileName; + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + return s->mFileRecorderFileName; } } @@ -958,24 +952,24 @@ namespace void writeToRecorders(const LLError::CallSite& site, const std::string& message, bool show_location = true, bool show_time = true, bool show_tags = true, bool show_level = true, bool show_function = true) { LLError::ELevel level = site.mLevel; - LLError::Settings& s = LLError::Settings::get(); + LLError::SettingsConfigPtr s = LLError::Settings::getInstance()->getSettingsConfig(); - for (Recorders::const_iterator i = s.mRecorders.begin(); - i != s.mRecorders.end(); + for (Recorders::const_iterator i = s->mRecorders.begin(); + i != s->mRecorders.end(); ++i) { - LLError::Recorder* r = *i; + LLError::RecorderPtr r = *i; std::ostringstream message_stream; - if (show_location && (r->wantsLocation() || level == LLError::LEVEL_ERROR || s.mPrintLocation)) + if (show_location && (r->wantsLocation() || level == LLError::LEVEL_ERROR || s->mPrintLocation)) { message_stream << site.mLocationString << " "; } - if (show_time && r->wantsTime() && s.mTimeFunction != NULL) + if (show_time && r->wantsTime() && s->mTimeFunction != NULL) { - message_stream << s.mTimeFunction() << " "; + message_stream << s->mTimeFunction() << " "; } if (show_level && r->wantsLevel()) @@ -1107,10 +1101,9 @@ namespace LLError return false; } - Globals& g = Globals::get(); - Settings& s = Settings::get(); + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); - s.mShouldLogCallCounter++; + s->mShouldLogCallCounter++; const std::string& class_name = className(site.mClassInfo); std::string function_name = functionName(site.mFunction); @@ -1124,21 +1117,21 @@ namespace LLError function_name = class_name + "::" + function_name; } - ELevel compareLevel = s.mDefaultLevel; + ELevel compareLevel = s->mDefaultLevel; // The most specific match found will be used as the log level, // since the computation short circuits. // So, in increasing order of importance: // Default < Tags < File < Class < Function - checkLevelMap(s.mFunctionLevelMap, function_name, compareLevel) - || checkLevelMap(s.mClassLevelMap, class_name, compareLevel) - || checkLevelMap(s.mFileLevelMap, abbreviateFile(site.mFile), compareLevel) + checkLevelMap(s->mFunctionLevelMap, function_name, compareLevel) + || checkLevelMap(s->mClassLevelMap, class_name, compareLevel) + || checkLevelMap(s->mFileLevelMap, abbreviateFile(site.mFile), compareLevel) || (site.mTagCount > 0 - ? checkLevelMap(s.mTagLevelMap, site.mTags, site.mTagCount, compareLevel) + ? checkLevelMap(s->mTagLevelMap, site.mTags, site.mTagCount, compareLevel) : false); site.mCached = true; - g.addCallSite(site); + Globals::getInstance()->addCallSite(site); return site.mShouldLog = site.mLevel >= compareLevel; } @@ -1148,12 +1141,12 @@ namespace LLError LogLock lock; if (lock.ok()) { - Globals& g = Globals::get(); + Globals* g = Globals::getInstance(); - if (!g.messageStreamInUse) + if (!g->messageStreamInUse) { - g.messageStreamInUse = true; - return &g.messageStream; + g->messageStreamInUse = true; + return &g->messageStream; } } @@ -1178,13 +1171,12 @@ namespace LLError message[127] = '\0' ; } - Globals& g = Globals::get(); - - if (out == &g.messageStream) + Globals* g = Globals::getInstance(); + if (out == &g->messageStream) { - g.messageStream.clear(); - g.messageStream.str(""); - g.messageStreamInUse = false; + g->messageStream.clear(); + g->messageStream.str(""); + g->messageStreamInUse = false; } else { @@ -1201,15 +1193,15 @@ namespace LLError return; } - Globals& g = Globals::get(); - Settings& s = Settings::get(); + Globals* g = Globals::getInstance(); + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); std::string message = out->str(); - if (out == &g.messageStream) + if (out == &g->messageStream) { - g.messageStream.clear(); - g.messageStream.str(""); - g.messageStreamInUse = false; + g->messageStream.clear(); + g->messageStream.str(""); + g->messageStreamInUse = false; } else { @@ -1229,8 +1221,8 @@ namespace LLError if (site.mPrintOnce) { - std::map::iterator messageIter = s.mUniqueLogMessages.find(message); - if (messageIter != s.mUniqueLogMessages.end()) + std::map::iterator messageIter = s->mUniqueLogMessages.find(message); + if (messageIter != s->mUniqueLogMessages.end()) { messageIter->second++; unsigned int num_messages = messageIter->second; @@ -1246,7 +1238,7 @@ namespace LLError else { message_stream << "ONCE: "; - s.mUniqueLogMessages[message] = 1; + s->mUniqueLogMessages[message] = 1; } } @@ -1254,23 +1246,23 @@ namespace LLError writeToRecorders(site, message_stream.str()); - if (site.mLevel == LEVEL_ERROR && s.mCrashFunction) + if (site.mLevel == LEVEL_ERROR && s->mCrashFunction) { - s.mCrashFunction(message_stream.str()); + s->mCrashFunction(message_stream.str()); } } } namespace LLError { - Settings* saveAndResetSettings() + SettingsStoragePtr saveAndResetSettings() { - return Settings::saveAndReset(); + return Settings::getInstance()->saveAndReset(); } - void restoreSettings(Settings* s) + void restoreSettings(SettingsStoragePtr pSettingsStorage) { - return Settings::restore(s); + return Settings::getInstance()->restore(pSettingsStorage); } std::string removePrefix(std::string& s, const std::string& p) @@ -1316,8 +1308,8 @@ namespace LLError int shouldLogCallCount() { - Settings& s = Settings::get(); - return s.mShouldLogCallCounter; + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + return s->mShouldLogCallCounter; } #if LL_WINDOWS @@ -1426,15 +1418,9 @@ namespace LLError #endif //static - void LLCallStacks::push(const char* function, const int line) + void LLCallStacks::allocateStackBuffer() { - CallStacksLogLock lock; - if (!lock.ok()) - { - return; - } - - if(!sBuffer) + if(sBuffer == NULL) { sBuffer = new char*[512] ; sBuffer[0] = new char[512 * 128] ; @@ -1444,6 +1430,31 @@ namespace LLError } sIndex = 0 ; } + } + + void LLCallStacks::freeStackBuffer() + { + if(sBuffer != NULL) + { + delete [] sBuffer[0] ; + delete [] sBuffer ; + sBuffer = NULL ; + } + } + + //static + void LLCallStacks::push(const char* function, const int line) + { + CallStacksLogLock lock; + if (!lock.ok()) + { + return; + } + + if(sBuffer == NULL) + { + allocateStackBuffer(); + } if(sIndex > 511) { @@ -1475,15 +1486,9 @@ namespace LLError return; } - if(!sBuffer) + if(sBuffer == NULL) { - sBuffer = new char*[512] ; - sBuffer[0] = new char[512 * 128] ; - for(S32 i = 1 ; i < 512 ; i++) - { - sBuffer[i] = sBuffer[i-1] + 128 ; - } - sIndex = 0 ; + allocateStackBuffer(); } if(sIndex > 511) @@ -1514,11 +1519,9 @@ namespace LLError LL_INFOS() << " *************** END OF LL CALL STACKS *************** " << LL_ENDL; } - if(sBuffer) + if(sBuffer != NULL) { - delete[] sBuffer[0] ; - delete[] sBuffer ; - sBuffer = NULL ; + freeStackBuffer(); } } @@ -1528,5 +1531,10 @@ namespace LLError sIndex = 0 ; } + //static + void LLCallStacks::cleanup() + { + freeStackBuffer(); + } } diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index 6d2a757107..057c5a958b 100755 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -274,6 +274,9 @@ namespace LLError private: static char** sBuffer ; static S32 sIndex ; + + static void allocateStackBuffer(); + static void freeStackBuffer(); public: static void push(const char* function, const int line) ; @@ -281,6 +284,7 @@ namespace LLError static void print() ; static void clear() ; static void end(std::ostringstream* _out) ; + static void cleanup(); }; } diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h index aab695094c..56ac52e5de 100755 --- a/indra/llcommon/llerrorcontrol.h +++ b/indra/llcommon/llerrorcontrol.h @@ -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 class LLSD; @@ -156,16 +159,14 @@ namespace LLError mWantsFunctionName; }; + typedef boost::shared_ptr 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 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(); diff --git a/indra/llcommon/llhttpstatuscodes.h b/indra/llcommon/llhttpstatuscodes.h deleted file mode 100755 index 0173461dad..0000000000 --- a/indra/llcommon/llhttpstatuscodes.h +++ /dev/null @@ -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 diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h index 0cd4fef99e..6d9b935690 100755 --- a/indra/llcommon/llinitparam.h +++ b/indra/llcommon/llinitparam.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -630,7 +631,7 @@ namespace LLInitParam UserData* mUserData; }; - typedef ParamDescriptor* ParamDescriptorPtr; + typedef boost::shared_ptr ParamDescriptorPtr; // each derived Block class keeps a static data structure maintaining offsets to various params class LL_COMMON_API BlockDescriptor diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index c9ebc70d19..9a6453ea48 100755 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -166,6 +166,132 @@ protected: Type* mPointer; }; +template class LLConstPointer +{ +public: + LLConstPointer() : + mPointer(NULL) + { + } + + LLConstPointer(const Type* ptr) : + mPointer(ptr) + { + ref(); + } + + LLConstPointer(const LLConstPointer& ptr) : + mPointer(ptr.mPointer) + { + ref(); + } + + // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. + template + LLConstPointer(const LLConstPointer& 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& ptr) const { return (mPointer == ptr.mPointer); } + bool operator < (const LLConstPointer& ptr) const { return (mPointer < ptr.mPointer); } + bool operator > (const LLConstPointer& ptr) const { return (mPointer > ptr.mPointer); } + + LLConstPointer& operator =(const Type* ptr) + { + if( mPointer != ptr ) + { + unref(); + mPointer = ptr; + ref(); + } + + return *this; + } + + LLConstPointer& operator =(const LLConstPointer& 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 + LLConstPointer& operator =(const LLConstPointer& 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& a, LLConstPointer& 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 class LLCopyOnWritePointer : public LLPointer { diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp index f962485284..d8bbb3a74f 100755 --- a/indra/llcommon/llsd.cpp +++ b/indra/llcommon/llsd.cpp @@ -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(); } + virtual const Binary& asBinary() const { static const std::vector 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); } diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h index deb87d7497..7b9b1285f5 100755 --- a/indra/llcommon/llsd.h +++ b/indra/llcommon/llsd.h @@ -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(); } diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index 980564eea7..9ce9c53001 100755 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -873,7 +873,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const { /** * Undefined: '!'
- * Boolean: 't' for true 'f' for false
+ * Boolean: '1' for true '0' for false
* Integer: 'i' + 4 bytes network byte order
* Real: 'r' + 8 bytes IEEE double
* UUID: 'u' + 16 byte unsigned integer
@@ -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 buffer = data.asBinary(); + const std::vector& 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 buffer = data.asBinary(); + const std::vector& 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()); diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h index e7a5507385..23a0c8cfb1 100755 --- a/indra/llcommon/llsdserialize.h +++ b/indra/llcommon/llsdserialize.h @@ -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: * * * *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 f = new LLSDNotationFormatter; return f->format(sd, str, LLSDFormatter::OPTIONS_NONE); } + static S32 toPrettyNotation(const LLSD& sd, std::ostream& str) + { + LLPointer f = new LLSDNotationFormatter; + return f->format(sd, str, LLSDFormatter::OPTIONS_PRETTY); + } + static S32 toPrettyBinaryNotation(const LLSD& sd, std::ostream& str) + { + LLPointer 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 p = new LLSDNotationParser; diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp index 7402dd500c..4c255c08b8 100755 --- a/indra/llcommon/llsdserialize_xml.cpp +++ b/indra/llcommon/llsdserialize_xml.cpp @@ -169,8 +169,8 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 opti break; case LLSD::TypeString: - if(data.asString().empty()) ostr << pre << "" << post; - else ostr << pre << "" << escapeString(data.asString()) <<"" << post; + if(data.asStringRef().empty()) ostr << pre << "" << post; + else ostr << pre << "" << escapeString(data.asStringRef()) <<"" << post; break; case LLSD::TypeDate: @@ -183,7 +183,7 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 opti case LLSD::TypeBinary: { - LLSD::Binary buffer = data.asBinary(); + const LLSD::Binary& buffer = data.asBinary(); if(buffer.empty()) { ostr << pre << "" << post; @@ -377,13 +377,10 @@ S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data) { break; } + count = get_till_eol(input, (char *)buffer, BUFFER_SIZE); + if (!count) { - - count = get_till_eol(input, (char *)buffer, BUFFER_SIZE); - if (!count) - { - break; - } + break; } status = XML_ParseBuffer(mParser, count, false); diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp index 803417d368..562fd26658 100755 --- a/indra/llcommon/llsdutil.cpp +++ b/indra/llcommon/llsdutil.cpp @@ -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); diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h index f7de0fb0c8..062d6bac13 100755 --- a/indra/llcommon/lluuid.h +++ b/indra/llcommon/lluuid.h @@ -132,10 +132,14 @@ public: }; typedef std::vector uuid_vec_t; +typedef std::set uuid_set_t; - -// Helper structure for ordering lluuids in stl containers. -// eg: std::map widget_map; +// Helper structure for ordering lluuids in stl containers. eg: +// std::map 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 uuid_list_t; - /* * Sub-classes for keeping transaction IDs and asset IDs * straight. diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp index b28c5ba4b3..a5aaff10c5 100755 --- a/indra/llcommon/tests/llerror_test.cpp +++ b/indra/llcommon/tests/llerror_test.cpp @@ -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(mRecorder)->countMessages(); + } + + void clearMessages() + { + boost::dynamic_pointer_cast(mRecorder)->clearMessages(); + } + + void setWantsTime(bool t) + { + boost::dynamic_pointer_cast(mRecorder)->setWantsTime(t); + } + + std::string message(int n) + { + return boost::dynamic_pointer_cast(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(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(recorder)->message(0); + std::string messageWithName = boost::dynamic_pointer_cast(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(altRecorder)->countMessages(), 1); + ensure_contains("alt recorder message 0", boost::dynamic_pointer_cast(altRecorder)->message(0), "boo"); LLError::setTimeFunction(roswell); - TestRecorder* anotherRecorder(new TestRecorder); - anotherRecorder->setWantsTime(true); + LLError::RecorderPtr anotherRecorder(new TestRecorder()); + boost::dynamic_pointer_cast(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(altRecorder)->countMessages(), 2); + ensure_does_not_contain("alt recorder message 1", boost::dynamic_pointer_cast(altRecorder)->message(1), when); + ensure_equals("another recorder count", boost::dynamic_pointer_cast(anotherRecorder)->countMessages(), 1); + ensure_contains("another recorder message 0", boost::dynamic_pointer_cast(anotherRecorder)->message(0), when); + + LLError::removeRecorder(altRecorder); + LLError::removeRecorder(anotherRecorder); } } diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h index 3137bd8fea..785197ba11 100755 --- a/indra/llcommon/tests/wrapllerrs.h +++ b/indra/llcommon/tests/wrapllerrs.h @@ -38,6 +38,7 @@ #include "stringize.h" #include #include +#include #include #include #include @@ -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 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(mRecorder)->messageWith(search, required); + } + + std::ostream& streamto(std::ostream& out) const + { + return boost::dynamic_pointer_cast(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); } diff --git a/indra/llcorehttp/_httplibcurl.cpp b/indra/llcorehttp/_httplibcurl.cpp index fc257fb0c1..e56bc84174 100755 --- a/indra/llcorehttp/_httplibcurl.cpp +++ b/indra/llcorehttp/_httplibcurl.cpp @@ -31,7 +31,7 @@ #include "_httpoprequest.h" #include "_httppolicy.h" -#include "llhttpstatuscodes.h" +#include "llhttpconstants.h" namespace LLCore diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp index 926031501e..43dd069bc6 100755 --- a/indra/llcorehttp/_httpoprequest.cpp +++ b/indra/llcorehttp/_httpoprequest.cpp @@ -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"); } diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index 790b4c16f5..166ca5c078 100755 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -64,17 +64,20 @@ std::string getStartupStateFromLog(std::string& sllog); class LLCrashLoggerResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLCrashLoggerResponder); public: LLCrashLoggerResponder() { } - virtual void error(U32 status, const std::string& reason) +protected: + virtual void httpFailure() { + LL_WARNS() << dumpResponse() << LL_ENDL; gBreak = true; } - virtual void result(const LLSD& content) + virtual void httpSuccess() { gBreak = true; gSent = true; diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 5957bfcf3f..9e2b4b88c0 100755 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -51,6 +51,7 @@ static const std::string INV_DESC_LABEL("desc"); static const std::string INV_PERMISSIONS_LABEL("permissions"); static const std::string INV_SHADOW_ID_LABEL("shadow_id"); static const std::string INV_ASSET_ID_LABEL("asset_id"); +static const std::string INV_LINKED_ID_LABEL("linked_id"); static const std::string INV_SALE_INFO_LABEL("sale_info"); static const std::string INV_FLAGS_LABEL("flags"); static const std::string INV_CREATION_DATE_LABEL("created_at"); @@ -257,13 +258,6 @@ BOOL LLInventoryObject::exportLegacyStream(std::ostream& output_stream, BOOL) co return TRUE; } - -void LLInventoryObject::removeFromServer() -{ - // don't do nothin' - LL_WARNS() << "LLInventoryObject::removeFromServer() called. Doesn't do anything." << LL_ENDL; -} - void LLInventoryObject::updateParentOnServer(BOOL) const { // don't do nothin' @@ -276,7 +270,7 @@ void LLInventoryObject::updateServer(BOOL) const LL_WARNS() << "LLInventoryObject::updateServer() called. Doesn't do anything." << LL_ENDL; } -//inline +// static void LLInventoryObject::correctInventoryName(std::string& name) { LLStringUtil::replaceNonstandardASCII(name, ' '); @@ -435,12 +429,17 @@ U32 LLInventoryItem::getCRC32() const return crc; } +// static +void LLInventoryItem::correctInventoryDescription(std::string& desc) +{ + LLStringUtil::replaceNonstandardASCII(desc, ' '); + LLStringUtil::replaceChar(desc, '|', ' '); +} void LLInventoryItem::setDescription(const std::string& d) { std::string new_desc(d); - LLStringUtil::replaceNonstandardASCII(new_desc, ' '); - LLStringUtil::replaceChar(new_desc, '|', ' '); + LLInventoryItem::correctInventoryDescription(new_desc); if( new_desc != mDescription ) { disclaimMem(mDescription); @@ -1174,11 +1173,16 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const LLTrace::BlockTimerStatHandle FTM_INVENTORY_SD_DESERIALIZE("Inventory SD Deserialize"); -bool LLInventoryItem::fromLLSD(const LLSD& sd) +bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) { LL_RECORD_BLOCK_TIME(FTM_INVENTORY_SD_DESERIALIZE); - mInventoryType = LLInventoryType::IT_NONE; - mAssetUUID.setNull(); + if (is_new) + { + // If we're adding LLSD to an existing object, need avoid + // clobbering these fields. + mInventoryType = LLInventoryType::IT_NONE; + mAssetUUID.setNull(); + } std::string w; w = INV_ITEM_ID_LABEL; @@ -1235,6 +1239,11 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd) { mAssetUUID = sd[w]; } + w = INV_LINKED_ID_LABEL; + if (sd.has(w)) + { + mAssetUUID = sd[w]; + } w = INV_ASSET_TYPE_LABEL; if (sd.has(w)) { diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h index 2c503177be..70b200e139 100755 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -48,6 +48,7 @@ class LLInventoryObject : public LLRefCount, public LLTrace::MemTrackable > object_list_t; + typedef std::list > const_object_list_t; //-------------------------------------------------------------------- // Initialization @@ -86,26 +87,19 @@ public: void setType(LLAssetType::EType type); virtual void setCreationDate(time_t creation_date_utc); // only stored for items -// [RLVa:KB] - Checked: 2014-01-07 (RLVa-1.4.10) // in place correction for inventory name string static void correctInventoryName(std::string& name); -// [/RLVa:KB] -private: -// // in place correction for inventory name string -// void correctInventoryName(std::string& name); //-------------------------------------------------------------------- // File Support // Implemented here so that a minimal information set can be transmitted // between simulator and viewer. //-------------------------------------------------------------------- -public: // virtual BOOL importFile(LLFILE* fp); virtual BOOL exportFile(LLFILE* fp, BOOL include_asset_key = TRUE) const; virtual BOOL importLegacyStream(std::istream& input_stream); virtual BOOL exportLegacyStream(std::ostream& output_stream, BOOL include_asset_key = TRUE) const; - virtual void removeFromServer(); virtual void updateParentOnServer(BOOL) const; virtual void updateServer(BOOL) const; @@ -178,6 +172,7 @@ public: //-------------------------------------------------------------------- public: void setAssetUUID(const LLUUID& asset_id); + static void correctInventoryDescription(std::string& name); void setDescription(const std::string& new_desc); void setSaleInfo(const LLSaleInfo& sale_info); void setPermissions(const LLPermissions& perm); @@ -216,7 +211,7 @@ public: void unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size); LLSD asLLSD() const; void asLLSD( LLSD& sd ) const; - bool fromLLSD(const LLSD& sd); + bool fromLLSD(const LLSD& sd, bool is_new = true); //-------------------------------------------------------------------- // Member Variables diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 46e1a95724..ee23d80eff 100755 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -48,6 +48,7 @@ set(llmessage_SOURCE_FILES llhttpassetstorage.cpp llhttpclient.cpp llhttpclientadapter.cpp + llhttpconstants.cpp llhttpnode.cpp llhttpsender.cpp llinstantmessage.cpp @@ -63,7 +64,6 @@ set(llmessage_SOURCE_FILES llmessagetemplate.cpp llmessagetemplateparser.cpp llmessagethrottle.cpp - llmime.cpp llnamevalue.cpp llnullcipher.cpp llpacketack.cpp @@ -72,7 +72,6 @@ set(llmessage_SOURCE_FILES llpartdata.cpp llproxy.cpp llpumpio.cpp - llregionpresenceverifier.cpp llsdappservices.cpp llsdhttpserver.cpp llsdmessage.cpp @@ -142,6 +141,7 @@ set(llmessage_HEADER_FILES llhttpclient.h llhttpclientinterface.h llhttpclientadapter.h + llhttpconstants.h llhttpnode.h llhttpnodeadapter.h llhttpsender.h @@ -160,7 +160,6 @@ set(llmessage_HEADER_FILES llmessagetemplate.h llmessagetemplateparser.h llmessagethrottle.h - llmime.h llmsgvariabletype.h llnamevalue.h llnullcipher.h @@ -173,7 +172,6 @@ set(llmessage_HEADER_FILES llqueryflags.h llregionflags.h llregionhandle.h - llregionpresenceverifier.h llsdappservices.h llsdhttpserver.h llsdmessage.h @@ -237,17 +235,15 @@ target_link_libraries( # tests if (LL_TESTS) SET(llmessage_TEST_SOURCE_FILES - # llhttpclientadapter.cpp - llmime.cpp llnamevalue.cpp lltrustedmessageservice.cpp lltemplatemessagedispatcher.cpp - llregionpresenceverifier.cpp ) LL_ADD_PROJECT_UNIT_TESTS(llmessage "${llmessage_TEST_SOURCE_FILES}") # set(TEST_DEBUG on) set(test_libs + ${CURL_LIBRARIES} ${LLMESSAGE_LIBRARIES} ${WINDOWS_LIBRARIES} ${LLVFS_LIBRARIES} @@ -274,6 +270,7 @@ if (LL_TESTS) LL_ADD_INTEGRATION_TEST(llavatarnamecache "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llhost "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(llhttpclientadapter "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llpartdata "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llxfer_file "" "${test_libs}") endif (LL_TESTS) diff --git a/indra/llmessage/llares.cpp b/indra/llmessage/llares.cpp index 25701e8ee9..5020aca132 100755 --- a/indra/llmessage/llares.cpp +++ b/indra/llmessage/llares.cpp @@ -647,6 +647,15 @@ LLAres *ll_init_ares() return gAres; } +void ll_cleanup_ares() +{ + if (gAres != NULL) + { + delete gAres; + gAres = NULL; + } +} + LLDnsRecord::LLDnsRecord(LLResType type, const std::string &name, unsigned ttl) : LLRefCount(), diff --git a/indra/llmessage/llares.h b/indra/llmessage/llares.h index 800781ee88..0b5d49e322 100755 --- a/indra/llmessage/llares.h +++ b/indra/llmessage/llares.h @@ -578,5 +578,6 @@ extern LLAres *gAres; * thread safe. */ extern LLAres *ll_init_ares(); +extern void ll_cleanup_ares(); #endif // LL_LLARES_H diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index 650719ff9e..b9aa795f56 100755 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -127,7 +127,7 @@ namespace LLAvatarNameCache // Erase expired names from cache void eraseUnrefreshed(); - bool expirationFromCacheControl(LLSD headers, F64 *expires); + bool expirationFromCacheControl(const LLSD& headers, F64 *expires); } /* Sample response: @@ -171,33 +171,31 @@ namespace LLAvatarNameCache class LLAvatarNameResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLAvatarNameResponder); private: // need to store agent ids that are part of this request in case of // an error, so we can flag them as unavailable std::vector mAgentIDs; - // Need the headers to look up Expires: and Retry-After: - LLSD mHeaders; - public: LLAvatarNameResponder(const std::vector& agent_ids) - : mAgentIDs(agent_ids), - mHeaders() + : mAgentIDs(agent_ids) { } - /*virtual*/ void completedHeader(U32 status, const std::string& reason, - const LLSD& headers) - { - mHeaders = headers; - } - - /*virtual*/ void result(const LLSD& content) +protected: + /*virtual*/ void httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } // Pull expiration out of headers if available - F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(mHeaders); + F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(getResponseHeaders()); F64 now = LLFrameTimer::getTotalSeconds(); - LLSD agents = content["agents"]; + const LLSD& agents = content["agents"]; LLSD::array_const_iterator it = agents.beginArray(); for ( ; it != agents.endArray(); ++it) { @@ -218,7 +216,7 @@ public: } // Same logic as error response case - LLSD unresolved_agents = content["bad_ids"]; + const LLSD& unresolved_agents = content["bad_ids"]; S32 num_unresolved = unresolved_agents.size(); if (num_unresolved > 0) { @@ -242,14 +240,13 @@ public: << LL_ENDL; } - /*virtual*/ void error(U32 status, const std::string& reason) + /*virtual*/ void httpFailure() { // If there's an error, it might be caused by PeopleApi, // or when loading textures on startup and using a very slow // network, this query may time out. // What we should do depends on whether or not we have a cached name - LL_WARNS("AvNameCache") << "LLAvatarNameResponder::error " << status << " " << reason - << LL_ENDL; + LL_WARNS("AvNameCache") << dumpResponse() << LL_ENDL; // Add dummy records for any agent IDs in this request that we do not have cached already std::vector::const_iterator it = mAgentIDs.begin(); @@ -762,7 +759,7 @@ void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_na sCache[agent_id] = av_name; } -F64 LLAvatarNameCache::nameExpirationFromHeaders(LLSD headers) +F64 LLAvatarNameCache::nameExpirationFromHeaders(const LLSD& headers) { const F64 DEFAULT_EXPIRES = 60.0 * 60.0 + LLFrameTimer::getTotalSeconds(); @@ -782,17 +779,21 @@ F64 LLAvatarNameCache::nameExpirationFromHeaders(LLSD headers) } } -bool LLAvatarNameCache::expirationFromCacheControl(LLSD headers, F64 *expires) +bool LLAvatarNameCache::expirationFromCacheControl(const LLSD& headers, F64 *expires) { bool fromCacheControl = false; F64 now = LLFrameTimer::getTotalSeconds(); // Allow the header to override the default - LLSD cache_control_header = headers["cache-control"]; - if (cache_control_header.isDefined()) + std::string cache_control; + if (headers.has(HTTP_IN_HEADER_CACHE_CONTROL)) + { + cache_control = headers[HTTP_IN_HEADER_CACHE_CONTROL].asString(); + } + + if (!cache_control.empty()) { S32 max_age = 0; - std::string cache_control = cache_control_header.asString(); if (max_age_from_cache_control(cache_control, &max_age)) { *expires = now + (F64)max_age; diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h index 9145459643..b406e24fd3 100755 --- a/indra/llmessage/llavatarnamecache.h +++ b/indra/llmessage/llavatarnamecache.h @@ -105,7 +105,7 @@ namespace LLAvatarNameCache // Compute name expiration time from HTTP Cache-Control header, // or return default value, in seconds from epoch. - F64 nameExpirationFromHeaders(LLSD headers); + F64 nameExpirationFromHeaders(const LLSD& headers); void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb); } diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index c1164a7b98..39b1b200a0 100755 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -49,6 +49,7 @@ #include "llproxy.h" #include "llsdserialize.h" #include "llstl.h" +#include "llstring.h" #include "llthread.h" #include "lltimer.h" @@ -100,7 +101,7 @@ void check_curl_code(CURLcode code) { // linux appears to throw a curl error once per session for a bad initialization // at a pretty random time (when enabling cookies). - LL_INFOS() << "curl error detected: " << curl_easy_strerror(code) << LL_ENDL; + LL_WARNS("curl") << "curl error detected: " << curl_easy_strerror(code) << LL_ENDL; } } @@ -110,7 +111,7 @@ void check_curl_multi_code(CURLMcode code) { // linux appears to throw a curl error once per session for a bad initialization // at a pretty random time (when enabling cookies). - LL_INFOS() << "curl multi error detected: " << curl_multi_strerror(code) << LL_ENDL; + LL_WARNS("curl") << "curl multi error detected: " << curl_multi_strerror(code) << LL_ENDL; } } @@ -135,6 +136,7 @@ std::string LLCurl::getVersionString() ////////////////////////////////////////////////////////////////////////////// LLCurl::Responder::Responder() + : mHTTPMethod(HTTP_INVALID), mStatus(HTTP_INTERNAL_ERROR) { } @@ -144,22 +146,30 @@ LLCurl::Responder::~Responder() } // virtual -void LLCurl::Responder::errorWithContent( - U32 status, - const std::string& reason, - const LLSD&) +void LLCurl::Responder::httpFailure() { - error(status, reason); + LL_WARNS("curl") << dumpResponse() << LL_ENDL; +} + +std::string LLCurl::Responder::dumpResponse() const +{ + std::ostringstream s; + s << "[" << httpMethodAsVerb(mHTTPMethod) << ":" << mURL << "] " + << "[status:" << mStatus << "] " + << "[reason:" << mReason << "] "; + + if (mResponseHeaders.has(HTTP_IN_HEADER_CONTENT_TYPE)) + { + s << "[content-type:" << mResponseHeaders[HTTP_IN_HEADER_CONTENT_TYPE] << "] "; + } + + s << "[content:" << mContent << "]"; + + return s.str(); } // virtual -void LLCurl::Responder::error(U32 status, const std::string& reason) -{ - LL_INFOS() << mURL << " [" << status << "]: " << reason << LL_ENDL; -} - -// virtual -void LLCurl::Responder::result(const LLSD& content) +void LLCurl::Responder::httpSuccess() { } @@ -168,51 +178,114 @@ void LLCurl::Responder::setURL(const std::string& url) mURL = url; } +void LLCurl::Responder::successResult(const LLSD& content) +{ + setResult(HTTP_OK, "", content); + httpSuccess(); +} + +void LLCurl::Responder::failureResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */) +{ + setResult(status, reason, content); + httpFailure(); +} + +void LLCurl::Responder::completeResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */) +{ + setResult(status, reason, content); + httpCompleted(); +} + +void LLCurl::Responder::setResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */) +{ + mStatus = status; + mReason = reason; + mContent = content; +} + +void LLCurl::Responder::setHTTPMethod(EHTTPMethod method) +{ + mHTTPMethod = method; +} + +void LLCurl::Responder::setResponseHeader(const std::string& header, const std::string& value) +{ + mResponseHeaders[header] = value; +} + +const std::string& LLCurl::Responder::getResponseHeader(const std::string& header) const +{ + if (mResponseHeaders.has(header)) + { + return mResponseHeaders[header].asStringRef(); + } + static const std::string empty; + return empty; +} + +bool LLCurl::Responder::hasResponseHeader(const std::string& header) const +{ + if (mResponseHeaders.has(header)) return true; + return false; +} + // virtual void LLCurl::Responder::completedRaw( - U32 status, - const std::string& reason, const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { - LLSD content; LLBufferStream istr(channels, buffer.get()); - const bool emit_errors = false; - if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(content, istr, emit_errors)) - { - LL_INFOS() << "Failed to deserialize LLSD. " << mURL << " [" << status << "]: " << reason << LL_ENDL; - content["reason"] = reason; + const bool emit_parse_errors = false; + // pass parse error down code path + mDeserializeError = false; + + std::string debug_body("(empty)"); + bool parsed=true; + if (EOF == istr.peek()) + { + parsed=false; + } + // Try to parse body as llsd, no matter what 'content-type' says. + else if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(mContent, istr, emit_parse_errors)) + { + parsed=false; + char body[1025]; + body[1024] = '\0'; + istr.seekg(0, std::ios::beg); + istr.get(body,1024); + if (strlen(body) > 0) + { + mContent = body; + debug_body = body; + } + // pass parse error down code path mDeserializeError = true; } - else - { - mDeserializeError = false; - } - // - 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 LLCurl::Easy::sFreeHandles; @@ -292,6 +365,36 @@ void LLCurl::Easy::releaseEasyHandle(CURL* handle) } } +//static +void LLCurl::Easy::deleteAllActiveHandles() +{ + LLMutexLock lock(sHandleMutexp) ; + LL_CHECK_MEMORY + for (std::set::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::iterator freeHandle = sFreeHandles.begin(); freeHandle != sFreeHandles.end(); ++freeHandle) + { + CURL* curlHandle = *freeHandle; + LLCurl::deleteEasyHandle(curlHandle); + LL_CHECK_MEMORY + } + + sFreeHandles.clear(); +} + LLCurl::Easy::Easy() : mHeaders(NULL), mCurlEasyHandle(NULL) @@ -307,7 +410,8 @@ LLCurl::Easy* LLCurl::Easy::getEasy() if (!easy->mCurlEasyHandle) { // this can happen if we have too many open files (fails in c-ares/ares_init.c) - LL_WARNS() << "allocEasyHandle() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << LL_ENDL; + LL_WARNS("curl") << "allocEasyHandle() returned NULL! Easy handles: " + << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << LL_ENDL; delete easy; return NULL; } @@ -344,10 +448,14 @@ LLCurl::Easy::~Easy() for_each(mStrings.begin(), mStrings.end(), DeletePointerArray()); LL_CHECK_MEMORY if (mResponder && LLCurl::sNotQuitting) //aborted - { - std::string reason("Request timeout, aborted.") ; - mResponder->completedRaw(408, //HTTP_REQUEST_TIME_OUT, timeout, abort - reason, mChannels, mOutput); + { + // HTTP_REQUEST_TIME_OUT, timeout, abort + // *TODO: This looks like improper use of the 408 status code. + // See: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.9 + // This status code should be returned by the *server* when: + // "The client did not produce a request within the time that the server was prepared to wait." + mResponder->setResult(HTTP_REQUEST_TIME_OUT, "Request timeout, aborted."); + mResponder->completedRaw(mChannels, mOutput); LL_CHECK_MEMORY } mResponder = NULL; @@ -411,10 +519,10 @@ void LLCurl::Easy::getTransferInfo(LLCurl::TransferInfo* info) check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SPEED_DOWNLOAD, &info->mSpeedDownload)); } -U32 LLCurl::Easy::report(CURLcode code) +S32 LLCurl::Easy::report(CURLcode code) { - // Curl wants a long, not a U32. This can be a difference. - // U32 responseCode = 0; + // Curl wants a long, not a S32. This can be a difference. + // S32 responseCode = 0; long responseCode = 0; // @@ -427,14 +535,15 @@ U32 LLCurl::Easy::report(CURLcode code) } else { - responseCode = 499; + responseCode = HTTP_INTERNAL_ERROR; responseReason = strerror(code) + " : " + mErrorBuffer; setopt(CURLOPT_FRESH_CONNECT, TRUE); } if (mResponder) { - mResponder->completedRaw(responseCode, responseReason, mChannels, mOutput); + mResponder->setResult(responseCode, responseReason); + mResponder->completedRaw(mChannels, mOutput); mResponder = NULL; } @@ -471,9 +580,31 @@ void LLCurl::Easy::setoptString(CURLoption option, const std::string& value) check_curl_code(result); } +void LLCurl::Easy::slist_append(const std::string& header, const std::string& value) +{ + std::string pair(header); + if (value.empty()) + { + pair += ":"; + } + else + { + pair += ": "; + pair += value; + } + slist_append(pair.c_str()); +} + void LLCurl::Easy::slist_append(const char* str) { - mHeaders = curl_slist_append(mHeaders, str); + if (str) + { + mHeaders = curl_slist_append(mHeaders, str); + if (!mHeaders) + { + LL_WARNS() << "curl_slist_append() call returned NULL appending " << str << LL_ENDL; + } + } } size_t curlReadCallback(char* data, size_t size, size_t nmemb, void* user_data) @@ -561,8 +692,9 @@ void LLCurl::Easy::prepRequest(const std::string& url, if (!post) { - slist_append("Connection: keep-alive"); - slist_append("Keep-alive: 300"); + // *TODO: Should this be set to 'Keep-Alive' ? + slist_append(HTTP_OUT_HEADER_CONNECTION, "keep-alive"); + slist_append(HTTP_OUT_HEADER_KEEP_ALIVE, "300"); // Accept and other headers for (std::vector::const_iterator iter = headers.begin(); iter != headers.end(); ++iter) @@ -845,7 +977,7 @@ S32 LLCurl::Multi::process() ++processed; if (msg->msg == CURLMSG_DONE) { - U32 response = 0; + S32 response = 0; Easy* easy = NULL ; { @@ -864,7 +996,7 @@ S32 LLCurl::Multi::process() } else { - response = 499; + response = HTTP_INTERNAL_ERROR; //*TODO: change to LL_WARNS() LL_ERRS() << "cleaned up curl request completed!" << LL_ENDL; } @@ -1170,13 +1302,13 @@ bool LLCurlRequest::getByteRange(const std::string& url, easy->setopt(CURLOPT_HTTPGET, 1); if (length > 0) { - std::string range = llformat("Range: bytes=%d-%d", offset,offset+length-1); - easy->slist_append(range.c_str()); + std::string range = llformat("bytes=%d-%d", offset,offset+length-1); + easy->slist_append(HTTP_OUT_HEADER_RANGE, range); } else if (offset > 0) { - std::string range = llformat("Range: bytes=%d-", offset); - easy->slist_append(range.c_str()); + std::string range = llformat("bytes=%d-", offset); + easy->slist_append(HTTP_OUT_HEADER_RANGE, range); } easy->setHeaders(); bool res = addEasy(easy); @@ -1203,7 +1335,7 @@ bool LLCurlRequest::post(const std::string& url, easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL); easy->setopt(CURLOPT_POSTFIELDSIZE, bytes); - easy->slist_append("Content-Type: application/llsd+xml"); + easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); easy->setHeaders(); LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL; @@ -1231,7 +1363,7 @@ bool LLCurlRequest::post(const std::string& url, easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL); easy->setopt(CURLOPT_POSTFIELDSIZE, bytes); - easy->slist_append("Content-Type: application/octet-stream"); + easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_OCTET_STREAM); easy->setHeaders(); LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL; @@ -1603,6 +1735,14 @@ void LLCurlEasyRequest::setSSLCtxCallback(curl_ssl_ctx_callback callback, void* } } +void LLCurlEasyRequest::slist_append(const std::string& header, const std::string& value) +{ + if (isValid() && mEasy) + { + mEasy->slist_append(header, value); + } +} + void LLCurlEasyRequest::slist_append(const char* str) { if (isValid() && mEasy) @@ -1787,17 +1927,14 @@ void LLCurl::cleanupClass() #endif LL_CHECK_MEMORY - - for (std::set::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 ; diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h index 13f4cf076b..aeed98c243 100755 --- a/indra/llmessage/llcurl.h +++ b/indra/llmessage/llcurl.h @@ -39,6 +39,7 @@ #include // TODO: remove dependency #include "llbuffer.h" +#include "llhttpconstants.h" #include "lliopipe.h" #include "llsd.h" #include "llqueuedthread.h" @@ -76,63 +77,96 @@ public: Responder(); virtual ~Responder(); + virtual bool followRedir() + { + return false; + } + /** * @brief return true if the status code indicates success. */ - static bool isGoodStatus(U32 status) - { - return((200 <= status) && (status < 300)); - } - - virtual void errorWithContent( - U32 status, - const std::string& reason, - const LLSD& content); - //< called by completed() on bad status + bool isGoodStatus() const { return isHttpGoodStatus(mStatus); } - virtual void error(U32 status, const std::string& reason); - //< called by default error(status, reason, content) - - virtual void result(const LLSD& content); - //< called by completed for good status codes. + S32 getStatus() const { return mStatus; } + const std::string& getReason() const { return mReason; } + const LLSD& getContent() const { return mContent; } + bool hasResponseHeader(const std::string& header) const; + const std::string& getResponseHeader(const std::string& header) const; + const LLSD& getResponseHeaders() const { return mResponseHeaders; } + const std::string& getURL() const { return mURL; } + EHTTPMethod getHTTPMethod() const { return mHTTPMethod; } + // This formats response information for use in log spam. Includes content spam. + std::string dumpResponse() const; + + // Allows direct triggering of success/error with different results. + void completeResult(S32 status, const std::string& reason, const LLSD& content = LLSD()); + void successResult(const LLSD& content); + void failureResult(S32 status, const std::string& reason, const LLSD& content = LLSD()); + + // The default implementation will try to parse body content as an LLSD, however + // it should not spam about parsing failures unless the server sent a + // Content-Type: application/llsd+xml header. virtual void completedRaw( - U32 status, - const std::string& reason, const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer); /**< Override point for clients that may want to use this class when the response is some other format besides LLSD */ - - virtual void completed( - U32 status, - const std::string& reason, - const LLSD& content); - /**< The default implemetnation calls - either: - * result(), or - * error() - */ - // Override to handle parsing of the header only. Note: this is the only place where the contents - // of the header can be parsed. In the ::completed call above only the body is contained in the LLSD. - virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content); - // Used internally to set the url for debugging later. - void setURL(const std::string& url); + // The http* methods are not public since these should be triggered internally + // after status, reason, content, etc have been set. + // If you need to trigger a completion method, use the *Result methods, above. + protected: + // These methods are the preferred way to process final results. + // By default, when one of these is called the following information will be resolved: + // * HTTP status code - getStatus() + // * Reason string - getReason() + // * Content - getContent() + // * Response Headers - getResponseHeaders() - virtual bool followRedir() - { - return false; - } + // By default, httpSuccess is triggered whenever httpCompleted is called with a 2xx status code. + virtual void httpSuccess(); + //< called by completed for good status codes. + + // By default, httpFailure is triggered whenever httpCompleted is called with a non-2xx status code. + virtual void httpFailure(); + //< called by httpCompleted() on bad status + + // httpCompleted does not generally need to be overridden, unless + // you don't care about the status code (which determine httpFailure or httpSuccess) + // or if you want to re-interpret what a 'good' vs' bad' status code is. + virtual void httpCompleted(); + /**< The default implementation calls + either: + * httpSuccess(), or + * httpFailure() + */ + + public: + void setHTTPMethod(EHTTPMethod method); + void setURL(const std::string& url); + void setResult(S32 status, const std::string& reason, const LLSD& content = LLSD()); + void setResponseHeader(const std::string& header, const std::string& value); // pass parse error down code path bool mDeserializeError; // 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 ResponderPtr; @@ -231,10 +265,11 @@ public: // Copies the string so that it is guaranteed to stick around void setoptString(CURLoption option, const std::string& value); + void slist_append(const std::string& header, const std::string& value); void slist_append(const char* str); void setHeaders(); - U32 report(CURLcode); + S32 report(CURLcode); void getTransferInfo(LLCurl::TransferInfo* info); void prepRequest(const std::string& url, const std::vector& headers, LLCurl::ResponderPtr, S32 time_out = 0, bool post = false); @@ -273,6 +308,9 @@ private: static std::set sFreeHandles; static std::set sActiveHandles; static LLMutex* sHandleMutexp ; + + static void deleteAllActiveHandles(); + static void deleteAllFreeHandles(); }; class LLCurl::Multi @@ -498,6 +536,7 @@ public: void setWriteCallback(curl_write_callback callback, void* userdata); void setReadCallback(curl_read_callback callback, void* userdata); void setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata); + void slist_append(const std::string& header, const std::string& value); void slist_append(const char* str); void sendRequest(const std::string& url); void requestComplete(); diff --git a/indra/llmessage/llhttpassetstorage.cpp b/indra/llmessage/llhttpassetstorage.cpp index 095da6f0f9..f168ac4ec6 100755 --- a/indra/llmessage/llhttpassetstorage.cpp +++ b/indra/llmessage/llhttpassetstorage.cpp @@ -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; } diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 8b97ac4189..87a2572c9e 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -54,7 +54,7 @@ namespace { public: LLHTTPClientURLAdaptor(LLCurl::ResponderPtr responder) - : LLURLRequestComplete(), mResponder(responder), mStatus(499), + : LLURLRequestComplete(), mResponder(responder), mStatus(HTTP_INTERNAL_ERROR), mReason("LLURLRequest complete w/no status") { } @@ -63,7 +63,7 @@ namespace { } - virtual void httpStatus(U32 status, const std::string& reason) + virtual void httpStatus(S32 status, const std::string& reason) { LLURLRequestComplete::httpStatus(status,reason); @@ -74,30 +74,33 @@ namespace virtual void complete(const LLChannelDescriptors& channels, const buffer_ptr_t& buffer) { + // *TODO: Re-interpret mRequestStatus codes? + // Would like to detect curl errors, such as + // connection errors, write erros, etc. if (mResponder.get()) { - // Allow clients to parse headers before we attempt to parse - // the body and provide completed/result/error calls. - mResponder->completedHeader(mStatus, mReason, mHeaderOutput); - mResponder->completedRaw(mStatus, mReason, channels, buffer); + mResponder->setResult(mStatus, mReason); + mResponder->completedRaw(channels, buffer); } } virtual void header(const std::string& header, const std::string& value) { - mHeaderOutput[header] = value; + if (mResponder.get()) + { + mResponder->setResponseHeader(header, value); + } } private: LLCurl::ResponderPtr mResponder; - U32 mStatus; + S32 mStatus; std::string mReason; - LLSD mHeaderOutput; }; class Injector : public LLIOPipe { public: - virtual const char* contentType() = 0; + virtual const std::string& contentType() = 0; }; class LLSDInjector : public Injector @@ -106,7 +109,7 @@ namespace LLSDInjector(const LLSD& sd) : mSD(sd) {} virtual ~LLSDInjector() {} - const char* contentType() { return "application/llsd+xml"; } + const std::string& contentType() { return HTTP_CONTENT_LLSD_XML; } virtual EStatus process_impl(const LLChannelDescriptors& channels, buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) @@ -124,12 +127,9 @@ namespace { public: RawInjector(const U8* data, S32 size) : mData(data), mSize(size) {} - // Memleak fix by Sovereign Engineer - //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) @@ -150,7 +150,7 @@ namespace FileInjector(const std::string& filename) : mFilename(filename) {} virtual ~FileInjector() {} - const char* contentType() { return "application/octet-stream"; } + const std::string& contentType() { return HTTP_CONTENT_OCTET_STREAM; } virtual EStatus process_impl(const LLChannelDescriptors& channels, buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) @@ -183,7 +183,7 @@ namespace VFileInjector(const LLUUID& uuid, LLAssetType::EType asset_type) : mUUID(uuid), mAssetType(asset_type) {} virtual ~VFileInjector() {} - const char* contentType() { return "application/octet-stream"; } + const std::string& contentType() { return HTTP_CONTENT_OCTET_STREAM; } virtual EStatus process_impl(const LLChannelDescriptors& channels, buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) @@ -216,7 +216,7 @@ void LLHTTPClient::setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback cal static void request( const std::string& url, - LLURLRequest::ERequestAction method, + EHTTPMethod method, Injector* body_injector, LLCurl::ResponderPtr responder, const F32 timeout = HTTP_REQUEST_EXPIRY_SECS, @@ -229,7 +229,7 @@ static void request( { if (responder) { - responder->completed(U32_MAX, "No pump", LLSD()); + responder->completeResult(HTTP_INTERNAL_ERROR, "No pump"); } delete body_injector; return; @@ -241,48 +241,44 @@ static void request( { if (responder) { - responder->completed(498, "Internal Error - curl failure", LLSD()); + responder->completeResult(HTTP_INTERNAL_CURL_ERROR, "Internal Error - curl failure"); } - delete req ; + delete req; delete body_injector; - return ; + return; } req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req); - - LL_DEBUGS() << LLURLRequest::actionAsVerb(method) << " " << url << " " - << headers << LL_ENDL; + LL_DEBUGS("LLHTTPClient") << httpMethodAsVerb(method) << " " << url << " " << headers << LL_ENDL; // Insert custom headers if the caller sent any if (headers.isMap()) { - if (headers.has("Cookie")) + if (headers.has(HTTP_OUT_HEADER_COOKIE)) { req->allowCookies(); } - LLSD::map_const_iterator iter = headers.beginMap(); - LLSD::map_const_iterator end = headers.endMap(); + LLSD::map_const_iterator iter = headers.beginMap(); + LLSD::map_const_iterator end = headers.endMap(); - for (; iter != end; ++iter) - { - std::ostringstream header; - //if the header is "Pragma" with no value - //the caller intends to force libcurl to drop - //the Pragma header it so gratuitously inserts - //Before inserting the header, force libcurl - //to not use the proxy (read: llurlrequest.cpp) - static const std::string PRAGMA("Pragma"); - if ((iter->first == PRAGMA) && (iter->second.asString().empty())) - { - req->useProxy(false); - } - header << iter->first << ": " << iter->second.asString() ; - LL_DEBUGS() << "header = " << header.str() << LL_ENDL; - req->addHeader(header.str().c_str()); - } - } + for (; iter != end; ++iter) + { + //if the header is "Pragma" with no value + //the caller intends to force libcurl to drop + //the Pragma header it so gratuitously inserts + //Before inserting the header, force libcurl + //to not use the proxy (read: llurlrequest.cpp) + if ((iter->first == HTTP_OUT_HEADER_PRAGMA) && (iter->second.asString().empty())) + { + req->useProxy(false); + } + LL_DEBUGS("LLHTTPClient") << "header = " << iter->first + << ": " << iter->second.asString() << LL_ENDL; + req->addHeader(iter->first, iter->second.asString()); + } + } if(if_modified_since) { @@ -292,44 +288,40 @@ static void request( // Check to see if we have already set Accept or not. If no one // set it, set it to application/llsd+xml since that's what we // almost always want. - if( method != LLURLRequest::HTTP_PUT && method != LLURLRequest::HTTP_POST ) + if( method != HTTP_PUT && method != HTTP_POST ) { - static const std::string ACCEPT("Accept"); - if(!headers.has(ACCEPT)) + if(!headers.has(HTTP_OUT_HEADER_ACCEPT)) { - req->addHeader("Accept: application/llsd+xml"); + req->addHeader(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_LLSD_XML); } } if (responder) { responder->setURL(url); + responder->setHTTPMethod(method); } req->setCallback(new LLHTTPClientURLAdaptor(responder)); - if (method == LLURLRequest::HTTP_POST && gMessageSystem) + if (method == HTTP_POST && gMessageSystem) { - req->addHeader(llformat("X-SecondLife-UDP-Listen-Port: %d", - gMessageSystem->mPort).c_str()); - } + req->addHeader("X-SecondLife-UDP-Listen-Port", llformat("%d", + gMessageSystem->mPort)); + } - if (method == LLURLRequest::HTTP_PUT || method == LLURLRequest::HTTP_POST) + if (method == HTTP_PUT || method == HTTP_POST || method == HTTP_PATCH) { - static const std::string CONTENT_TYPE("Content-Type"); - if(!headers.has(CONTENT_TYPE)) + if(!headers.has(HTTP_OUT_HEADER_CONTENT_TYPE)) { // If the Content-Type header was passed in, it has // already been added as a header through req->addHeader // in the loop above. We defer to the caller's wisdom, but // if they did not specify a Content-Type, then ask the // injector. - req->addHeader( - llformat( - "Content-Type: %s", - body_injector->contentType()).c_str()); + req->addHeader(HTTP_OUT_HEADER_CONTENT_TYPE, body_injector->contentType()); } - chain.push_back(LLIOPipe::ptr_t(body_injector)); + chain.push_back(LLIOPipe::ptr_t(body_injector)); } chain.push_back(LLIOPipe::ptr_t(req)); @@ -351,9 +343,9 @@ void LLHTTPClient::getByteRange( if(offset > 0 || bytes > 0) { std::string range = llformat("bytes=%d-%d", offset, offset+bytes-1); - headers["Range"] = range; + headers[HTTP_OUT_HEADER_RANGE] = range; } - request(url,LLURLRequest::HTTP_GET, NULL, responder, timeout, headers, follow_redirects); + request(url,HTTP_GET, NULL, responder, timeout, headers, follow_redirects); } void LLHTTPClient::head( @@ -363,25 +355,25 @@ void LLHTTPClient::head( const F32 timeout, bool follow_redirects /* = true */) { - request(url, LLURLRequest::HTTP_HEAD, NULL, responder, timeout, headers, follow_redirects); + request(url, HTTP_HEAD, NULL, responder, timeout, headers, follow_redirects); } void LLHTTPClient::get(const std::string& url, ResponderPtr responder, const LLSD& headers, const F32 timeout, bool follow_redirects /* = true */) { - request(url, LLURLRequest::HTTP_GET, NULL, responder, timeout, headers, follow_redirects); + request(url, HTTP_GET, NULL, responder, timeout, headers, follow_redirects); } // opensim void LLHTTPClient::getIfModified(const std::string& url, ResponderPtr responder, const time_t &if_modified_since, const LLSD& headers, const F32 timeout) { - request(url, LLURLRequest::HTTP_GET, NULL, responder, timeout, headers, true, if_modified_since); + request(url, HTTP_GET, NULL, responder, timeout, headers, true, if_modified_since); } // opensim void LLHTTPClient::getHeaderOnly(const std::string& url, ResponderPtr responder, const LLSD& headers, const F32 timeout, bool follow_redirects /* = true */) { - request(url, LLURLRequest::HTTP_HEAD, NULL, responder, timeout, headers, follow_redirects); + request(url, HTTP_HEAD, NULL, responder, timeout, headers, follow_redirects); } void LLHTTPClient::getHeaderOnly(const std::string& url, ResponderPtr responder, const F32 timeout, bool follow_redirects /* = true */) @@ -424,7 +416,7 @@ public: return content; } - std::string asString() + const std::string& asString() { return mBuffer; } @@ -453,7 +445,7 @@ private: */ static LLSD blocking_request( const std::string& url, - LLURLRequest::ERequestAction method, + EHTTPMethod method, const LLSD& body, const LLSD& headers = LLSD(), const F32 timeout = 5 @@ -496,11 +488,11 @@ static LLSD blocking_request( } // * Setup specific method / "verb" for the URI (currently only GET and POST supported + poppy) - if (method == LLURLRequest::HTTP_GET) + if (method == HTTP_GET) { curl_easy_setopt(curlp, CURLOPT_HTTPGET, 1); } - else if (method == LLURLRequest::HTTP_POST) + else if (method == HTTP_POST) { curl_easy_setopt(curlp, CURLOPT_POST, 1); //serialize to ostr then copy to str - need to because ostr ptr is unstable :( @@ -509,18 +501,20 @@ static LLSD blocking_request( body_str = ostr.str(); curl_easy_setopt(curlp, CURLOPT_POSTFIELDS, body_str.c_str()); //copied from PHP libs, correct? - headers_list = curl_slist_append(headers_list, "Content-Type: application/llsd+xml"); + headers_list = curl_slist_append(headers_list, + llformat("%s: %s", HTTP_OUT_HEADER_CONTENT_TYPE.c_str(), HTTP_CONTENT_LLSD_XML.c_str()).c_str()); // copied from llurlrequest.cpp // it appears that apache2.2.3 or django in etch is busted. If // we do not clear the expect header, we get a 500. May be // limited to django/mod_wsgi. - headers_list = curl_slist_append(headers_list, "Expect:"); + headers_list = curl_slist_append(headers_list, llformat("%s:", HTTP_OUT_HEADER_EXPECT.c_str()).c_str()); } // * Do the action using curl, handle results LL_DEBUGS() << "HTTP body: " << body_str << LL_ENDL; - headers_list = curl_slist_append(headers_list, "Accept: application/llsd+xml"); + headers_list = curl_slist_append(headers_list, + llformat("%s: %s", HTTP_OUT_HEADER_ACCEPT.c_str(), HTTP_CONTENT_LLSD_XML.c_str()).c_str()); CURLcode curl_result = curl_easy_setopt(curlp, CURLOPT_HTTPHEADER, headers_list); if ( curl_result != CURLE_OK ) { @@ -529,11 +523,11 @@ static LLSD blocking_request( LLSD response = LLSD::emptyMap(); S32 curl_success = curl_easy_perform(curlp); - S32 http_status = 499; + S32 http_status = HTTP_INTERNAL_ERROR; curl_easy_getinfo(curlp, CURLINFO_RESPONSE_CODE, &http_status); response["status"] = http_status; // if we get a non-404 and it's not a 200 OR maybe it is but you have error bits, - if ( http_status != 404 && (http_status != 200 || curl_success != 0) ) + if ( http_status != HTTP_NOT_FOUND && (http_status != HTTP_OK || curl_success != 0) ) { // We expect 404s, don't spam for them. LL_WARNS() << "CURL REQ URL: " << url << LL_ENDL; @@ -563,12 +557,12 @@ static LLSD blocking_request( LLSD LLHTTPClient::blockingGet(const std::string& url) { - return blocking_request(url, LLURLRequest::HTTP_GET, LLSD()); + return blocking_request(url, HTTP_GET, LLSD()); } LLSD LLHTTPClient::blockingPost(const std::string& url, const LLSD& body) { - return blocking_request(url, LLURLRequest::HTTP_POST, body); + return blocking_request(url, HTTP_POST, body); } void LLHTTPClient::put( @@ -578,7 +572,17 @@ void LLHTTPClient::put( const LLSD& headers, const F32 timeout) { - request(url, LLURLRequest::HTTP_PUT, new LLSDInjector(body), responder, timeout, headers); + request(url, HTTP_PUT, new LLSDInjector(body), responder, timeout, headers); +} + +void LLHTTPClient::patch( + const std::string& url, + const LLSD& body, + ResponderPtr responder, + const LLSD& headers, + const F32 timeout) +{ + request(url, HTTP_PATCH, new LLSDInjector(body), responder, timeout, headers); } void LLHTTPClient::post( @@ -588,7 +592,7 @@ void LLHTTPClient::post( const LLSD& headers, const F32 timeout) { - request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, timeout, headers); + request(url, HTTP_POST, new LLSDInjector(body), responder, timeout, headers); } void LLHTTPClient::postRaw( @@ -599,7 +603,7 @@ void LLHTTPClient::postRaw( const LLSD& headers, const F32 timeout) { - request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, timeout, headers); + request(url, HTTP_POST, new RawInjector(data, size), responder, timeout, headers); } void LLHTTPClient::postFile( @@ -609,7 +613,7 @@ void LLHTTPClient::postFile( const LLSD& headers, const F32 timeout) { - request(url, LLURLRequest::HTTP_POST, new FileInjector(filename), responder, timeout, headers); + request(url, HTTP_POST, new FileInjector(filename), responder, timeout, headers); } void LLHTTPClient::postFile( @@ -620,7 +624,7 @@ void LLHTTPClient::postFile( const LLSD& headers, const F32 timeout) { - request(url, LLURLRequest::HTTP_POST, new VFileInjector(uuid, asset_type), responder, timeout, headers); + request(url, HTTP_POST, new VFileInjector(uuid, asset_type), responder, timeout, headers); } // static @@ -630,7 +634,7 @@ void LLHTTPClient::del( const LLSD& headers, const F32 timeout) { - request(url, LLURLRequest::HTTP_DELETE, NULL, responder, timeout, headers); + request(url, HTTP_DELETE, NULL, responder, timeout, headers); } // static @@ -642,8 +646,21 @@ void LLHTTPClient::move( const F32 timeout) { LLSD headers = hdrs; - headers["Destination"] = destination; - request(url, LLURLRequest::HTTP_MOVE, NULL, responder, timeout, headers); + headers[HTTP_OUT_HEADER_DESTINATION] = destination; + request(url, HTTP_MOVE, NULL, responder, timeout, headers); +} + +// static +void LLHTTPClient::copy( + const std::string& url, + const std::string& destination, + ResponderPtr responder, + const LLSD& hdrs, + const F32 timeout) +{ + LLSD headers = hdrs; + headers[HTTP_OUT_HEADER_DESTINATION] = destination; + request(url, HTTP_COPY, NULL, responder, timeout, headers); } diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index 82ad7dabac..0c255af734 100755 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -80,6 +80,14 @@ public: ResponderPtr, const LLSD& headers = LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); + + static void patch( + const std::string& url, + const LLSD& body, + ResponderPtr, + const LLSD& headers = LLSD(), + const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); + static void getHeaderOnly(const std::string& url, ResponderPtr, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS, bool follow_redirects = true); static void getHeaderOnly(const std::string& url, ResponderPtr, const LLSD& headers, @@ -119,7 +127,7 @@ public: const LLSD& headers = LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); ///< sends a DELETE method, but we can't call it delete in c++ - + /** * @brief Send a MOVE webdav method * @@ -136,6 +144,22 @@ public: const LLSD& headers = LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); + /** + * @brief Send a COPY webdav method + * + * @param url The complete serialized (and escaped) url to get. + * @param destination The complete serialized destination url. + * @param responder The responder that will handle the result. + * @param headers A map of key:value headers to pass to the request + * @param timeout The number of seconds to give the server to respond. + */ + static void copy( + const std::string& url, + const std::string& destination, + ResponderPtr responder, + const LLSD& headers = LLSD(), + const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); + //@} /** diff --git a/indra/llmessage/llhttpclientadapter.cpp b/indra/llmessage/llhttpclientadapter.cpp index dcd2d79d67..b56a804f94 100755 --- a/indra/llmessage/llhttpclientadapter.cpp +++ b/indra/llmessage/llhttpclientadapter.cpp @@ -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); +} diff --git a/indra/llmessage/llhttpclientadapter.h b/indra/llmessage/llhttpclientadapter.h index aae6426a59..270282c66f 100755 --- a/indra/llmessage/llhttpclientadapter.h +++ b/indra/llmessage/llhttpclientadapter.h @@ -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 diff --git a/indra/llmessage/llhttpconstants.cpp b/indra/llmessage/llhttpconstants.cpp new file mode 100755 index 0000000000..01f4a080b0 --- /dev/null +++ b/indra/llmessage/llhttpconstants.cpp @@ -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 + +// 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; +} + diff --git a/indra/llmessage/llhttpconstants.h b/indra/llmessage/llhttpconstants.h new file mode 100755 index 0000000000..4aa3cc6394 --- /dev/null +++ b/indra/llmessage/llhttpconstants.h @@ -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 diff --git a/indra/llmessage/llhttpnode.cpp b/indra/llmessage/llhttpnode.cpp index f1f4a95005..f235965879 100755 --- a/indra/llmessage/llhttpnode.cpp +++ b/indra/llmessage/llhttpnode.cpp @@ -30,9 +30,15 @@ #include #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; diff --git a/indra/llmessage/llhttpnode.h b/indra/llmessage/llhttpnode.h index 148647ddde..1144d88be1 100755 --- a/indra/llmessage/llhttpnode.h +++ b/indra/llmessage/llhttpnode.h @@ -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 getChild() 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//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; diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp index 23813c6edb..d9042fa8b0 100755 --- a/indra/llmessage/lliohttpserver.cpp +++ b/indra/llmessage/lliohttpserver.cpp @@ -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 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 diff --git a/indra/llmessage/lliohttpserver.h b/indra/llmessage/lliohttpserver.h index 5c1b0531ff..a23eafe58a 100755 --- a/indra/llmessage/lliohttpserver.h +++ b/indra/llmessage/lliohttpserver.h @@ -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: diff --git a/indra/llmessage/lliosocket.cpp b/indra/llmessage/lliosocket.cpp index 8647d9d5de..5cdaec0f6c 100755 --- a/indra/llmessage/lliosocket.cpp +++ b/indra/llmessage/lliosocket.cpp @@ -40,6 +40,9 @@ // constants // +const std::string CONTEXT_REMOTE_HOST("remote-host"); +const std::string CONTEXT_REMOTE_PORT("remote-port"); + static const S32 LL_DEFAULT_LISTEN_BACKLOG = 10; static const S32 LL_SEND_BUFFER_SIZE = 40000; static const S32 LL_RECV_BUFFER_SIZE = 40000; @@ -626,8 +629,8 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl( apr_sockaddr_ip_get(&remote_host_string, remote_addr); LLSD context; - context["remote-host"] = remote_host_string; - context["remote-port"] = remote_addr->port; + context[CONTEXT_REMOTE_HOST] = remote_host_string; + context[CONTEXT_REMOTE_PORT] = remote_addr->port; LLPumpIO::chain_t chain; chain.push_back(LLIOPipe::ptr_t(new LLIOSocketReader(llsocket))); diff --git a/indra/llmessage/lliosocket.h b/indra/llmessage/lliosocket.h index ec998552d0..f840f0275c 100755 --- a/indra/llmessage/lliosocket.h +++ b/indra/llmessage/lliosocket.h @@ -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; /** diff --git a/indra/llmessage/llmime.cpp b/indra/llmessage/llmime.cpp deleted file mode 100755 index 9d9c4ebd68..0000000000 --- a/indra/llmessage/llmime.cpp +++ /dev/null @@ -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 - -#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 - - - ---segment -Content-Type: text/xml; charset=UTF-8 - - -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 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& 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); -} -*/ diff --git a/indra/llmessage/llmime.h b/indra/llmessage/llmime.h deleted file mode 100755 index e6617fb503..0000000000 --- a/indra/llmessage/llmime.h +++ /dev/null @@ -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 -#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:
- * LLMimeIndex mime_index;
- * std::ifstream fstr("package.mime", ios::binary);
- * LLMimeParser parser;
- * if(parser.parseIndex(fstr, mime_index))
- * {
- * std::vector content;
- * content.resize(mime_index.contentLength());
- * fstr.seekg(mime_index.offset(), ios::beg);
- * // ...do work on fstr and content
- * }
- */ -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& 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 diff --git a/indra/llmessage/llregionpresenceverifier.cpp b/indra/llmessage/llregionpresenceverifier.cpp deleted file mode 100755 index 3267988e40..0000000000 --- a/indra/llmessage/llregionpresenceverifier.cpp +++ /dev/null @@ -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 -#include "net.h" -#include "message.h" - -//namespace boost -//{ - void intrusive_ptr_add_ref(LLRegionPresenceVerifier::Response* p) - { - nd::intrin::FAA( &p->mReferenceCount ); - } - - void intrusive_ptr_release(LLRegionPresenceVerifier::Response* p) - { - if(p && 0 == nd::intrin::FAD( &p->mReferenceCount )) - { - delete p; - } - } -//}; - -LLRegionPresenceVerifier::Response::~Response() -{ -} - -LLRegionPresenceVerifier::RegionResponder::RegionResponder(const std::string& - uri, - ResponsePtr data, - S32 retry_count) : - mUri(uri), - mSharedData(data), - mRetryCount(retry_count) -{ -} - -//virtual -LLRegionPresenceVerifier::RegionResponder::~RegionResponder() -{ -} - -void LLRegionPresenceVerifier::RegionResponder::result(const LLSD& content) -{ - std::string host = content["private_host"].asString(); - U32 port = content["private_port"].asInteger(); - LLHost destination(host, port); - LLUUID id = content["region_id"]; - - LL_DEBUGS() << "Verifying " << destination.getString() << " is region " << id << LL_ENDL; - - std::stringstream uri; - uri << "http://" << destination.getString() << "/state/basic/"; - mSharedData->getHttpClient().get( - uri.str(), - new VerifiedDestinationResponder(mUri, mSharedData, content, mRetryCount)); -} - -void LLRegionPresenceVerifier::RegionResponder::error(U32 status, - const std::string& reason) -{ - // TODO: babbage: distinguish between region presence service and - // region verification errors? - mSharedData->onRegionVerificationFailed(); -} - -LLRegionPresenceVerifier::VerifiedDestinationResponder::VerifiedDestinationResponder(const std::string& uri, ResponsePtr data, const LLSD& content, - S32 retry_count): - mUri(uri), - mSharedData(data), - mContent(content), - mRetryCount(retry_count) -{ -} - -//virtual -LLRegionPresenceVerifier::VerifiedDestinationResponder::~VerifiedDestinationResponder() -{ -} - -void LLRegionPresenceVerifier::VerifiedDestinationResponder::result(const LLSD& content) -{ - LLUUID actual_region_id = content["region_id"]; - LLUUID expected_region_id = mContent["region_id"]; - - LL_DEBUGS() << "Actual region: " << content << LL_ENDL; - LL_DEBUGS() << "Expected region: " << mContent << LL_ENDL; - - if (mSharedData->checkValidity(content) && - (actual_region_id == expected_region_id)) - { - mSharedData->onRegionVerified(mContent); - } - else if (mRetryCount > 0) - { - retry(); - } - else - { - LL_WARNS() << "Simulator verification failed. Region: " << mUri << LL_ENDL; - mSharedData->onRegionVerificationFailed(); - } -} - -void LLRegionPresenceVerifier::VerifiedDestinationResponder::retry() -{ - LLSD headers; - headers["Cache-Control"] = "no-cache, max-age=0"; - LL_INFOS() << "Requesting region information, get uncached for region " - << mUri << LL_ENDL; - --mRetryCount; - mSharedData->getHttpClient().get(mUri, new RegionResponder(mUri, mSharedData, mRetryCount), headers); -} - -void LLRegionPresenceVerifier::VerifiedDestinationResponder::error(U32 status, const std::string& reason) -{ - if(mRetryCount > 0) - { - retry(); - } - else - { - LL_WARNS() << "Failed to contact simulator for verification. Region: " << mUri << LL_ENDL; - mSharedData->onRegionVerificationFailed(); - } -} diff --git a/indra/llmessage/llregionpresenceverifier.h b/indra/llmessage/llregionpresenceverifier.h deleted file mode 100755 index a9d447cccb..0000000000 --- a/indra/llmessage/llregionpresenceverifier.h +++ /dev/null @@ -1,99 +0,0 @@ -/** - * @file llregionpresenceverifier.cpp - * @brief - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -/* Macro Definitions */ -#ifndef LL_LLREGIONPRESENCEVERIFIER_H -#define LL_LLREGIONPRESENCEVERIFIER_H - -#include "llhttpclient.h" -#include -#include "llsd.h" -#include - -class LLHTTPClientInterface; - -class LLRegionPresenceVerifier -{ -public: - class Response - { - public: - virtual ~Response() = 0; - - virtual bool checkValidity(const LLSD& content) const = 0; - virtual void onRegionVerified(const LLSD& region_details) = 0; - virtual void onRegionVerificationFailed() = 0; - - virtual LLHTTPClientInterface& getHttpClient() = 0; - - public: /* but not really -- don't touch this */ -// U32 mReferenceCount; - volatile U32 mReferenceCount; - }; - - typedef boost::intrusive_ptr 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 diff --git a/indra/llmessage/llsdappservices.cpp b/indra/llmessage/llsdappservices.cpp index 4103ece33a..4ca45267bd 100755 --- a/indra/llmessage/llsdappservices.cpp +++ b/indra/llmessage/llsdappservices.cpp @@ -121,7 +121,7 @@ public: { //LL_INFOS() << "validate: " << name << ", " // << LLSDOStreamer(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)); } }; diff --git a/indra/llmessage/llsdhttpserver.cpp b/indra/llmessage/llsdhttpserver.cpp index 5c8fc7b2bb..8ac6b3cb12 100755 --- a/indra/llmessage/llsdhttpserver.cpp +++ b/indra/llmessage/llsdhttpserver.cpp @@ -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) { diff --git a/indra/llmessage/llsdmessage.cpp b/indra/llmessage/llsdmessage.cpp index 1d0904e3f1..61fcc5dd2f 100755 --- a/indra/llmessage/llsdmessage.cpp +++ b/indra/llmessage/llsdmessage.cpp @@ -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 ----------------*/ diff --git a/indra/llmessage/llsdmessage.h b/indra/llmessage/llsdmessage.h index 0d34847ff2..e5d532d6a4 100755 --- a/indra/llmessage/llsdmessage.h +++ b/indra/llmessage/llsdmessage.h @@ -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; diff --git a/indra/llmessage/llsdrpcclient.h b/indra/llmessage/llsdrpcclient.h index 8eb7a08620..c4e0333ca3 100755 --- a/indra/llmessage/llsdrpcclient.h +++ b/indra/llmessage/llsdrpcclient.h @@ -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))); diff --git a/indra/llmessage/lltrustedmessageservice.cpp b/indra/llmessage/lltrustedmessageservice.cpp index 151d02a156..5bd1112cfe 100755 --- a/indra/llmessage/lltrustedmessageservice.cpp +++ b/indra/llmessage/lltrustedmessageservice.cpp @@ -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 { diff --git a/indra/llmessage/lltrustedmessageservice.h b/indra/llmessage/lltrustedmessageservice.h index 688937ac2c..12a37bb535 100755 --- a/indra/llmessage/lltrustedmessageservice.h +++ b/indra/llmessage/lltrustedmessageservice.h @@ -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 diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index 8511cbb0bc..75b6ab4aca 100755 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -41,7 +41,6 @@ #include "llstring.h" #include "apr_env.h" #include "llapr.h" -static const U32 HTTP_STATUS_PIPE_ERROR = 499; /** * String constants @@ -49,11 +48,12 @@ static const U32 HTTP_STATUS_PIPE_ERROR = 499; const std::string CONTEXT_DEST_URI_SD_LABEL("dest_uri"); const std::string CONTEXT_TRANSFERED_BYTES("transfered_bytes"); +// These are defined in llhttpnode.h/llhttpnode.cpp +extern const std::string CONTEXT_REQUEST; +extern const std::string CONTEXT_RESPONSE; static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user); - - /** * class LLURLRequestDetail */ @@ -150,27 +150,8 @@ CURLcode LLURLRequest::_sslCtxCallback(CURL * curl, void *sslctx, void *param) * class LLURLRequest */ -// static -std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action) -{ - static const std::string VERBS[] = - { - "(invalid)", - "HEAD", - "GET", - "PUT", - "POST", - "DELETE", - "MOVE" - }; - if(((S32)action <=0) || ((S32)action >= REQUEST_ACTION_COUNT)) - { - return VERBS[0]; - } - return VERBS[action]; -} -LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, bool follow_redirects /* = true */) : +LLURLRequest::LLURLRequest(EHTTPMethod action, bool follow_redirects /* = true */) : mAction(action), mFollowRedirects(follow_redirects) { @@ -178,7 +159,7 @@ LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, bool follow_redi } LLURLRequest::LLURLRequest( - LLURLRequest::ERequestAction action, + EHTTPMethod action, const std::string& url, bool follow_redirects /* = true */) : mAction(action), @@ -203,12 +184,17 @@ void LLURLRequest::setURL(const std::string& url) } } -std::string LLURLRequest::getURL() const +const std::string& LLURLRequest::getURL() const { return mDetail->mURL; } -void LLURLRequest::addHeader(const char* header) +void LLURLRequest::addHeader(const std::string& header, const std::string& value /* = "" */) +{ + mDetail->mCurlRequest->slist_append(header, value); +} + +void LLURLRequest::addHeaderRaw(const char* header) { mDetail->mCurlRequest->slist_append(header); } @@ -305,7 +291,7 @@ LLIOPipe::EStatus LLURLRequest::handleError( LLURLRequestComplete* complete = NULL; complete = (LLURLRequestComplete*)mCompletionCallback.get(); complete->httpStatus( - HTTP_STATUS_PIPE_ERROR, + HTTP_INTERNAL_ERROR, LLIOPipe::lookupStatusString(status)); complete->responseStatus(status); pump->respond(complete); @@ -533,21 +519,32 @@ bool LLURLRequest::configure() case HTTP_PUT: // Disable the expect http 1.1 extension. POST and PUT default // to turning this on, and I am not too sure what it means. - addHeader("Expect:"); + addHeader(HTTP_OUT_HEADER_EXPECT); mDetail->mCurlRequest->setopt(CURLOPT_UPLOAD, 1); mDetail->mCurlRequest->setopt(CURLOPT_INFILESIZE, bytes); rv = true; break; + case HTTP_PATCH: + // Disable the expect http 1.1 extension. POST and PUT default + // to turning this on, and I am not too sure what it means. + addHeader(HTTP_OUT_HEADER_EXPECT); + + mDetail->mCurlRequest->setopt(CURLOPT_UPLOAD, 1); + mDetail->mCurlRequest->setopt(CURLOPT_INFILESIZE, bytes); + mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "PATCH"); + rv = true; + break; + case HTTP_POST: // Disable the expect http 1.1 extension. POST and PUT default // to turning this on, and I am not too sure what it means. - addHeader("Expect:"); + addHeader(HTTP_OUT_HEADER_EXPECT); // Disable the content type http header. // *FIX: what should it be? - addHeader("Content-Type:"); + addHeader(HTTP_OUT_HEADER_CONTENT_TYPE); // Set the handle for an http post mDetail->mCurlRequest->setPost(NULL, bytes); @@ -558,13 +555,19 @@ bool LLURLRequest::configure() break; case HTTP_DELETE: - // Set the handle for an http post + // Set the handle for an http delete mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "DELETE"); rv = true; break; + case HTTP_COPY: + // Set the handle for an http copy + mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "COPY"); + rv = true; + break; + case HTTP_MOVE: - // Set the handle for an http post + // Set the handle for an http move mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "MOVE"); // *NOTE: should we check for the Destination header? rv = true; @@ -677,7 +680,7 @@ static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user) S32 status_code = atoi(status.c_str()); if (status_code > 0) { - complete->httpStatus((U32)status_code, reason); + complete->httpStatus(status_code, reason); return header_len; } } diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h index 1575cff01b..1ccb5d6cbd 100755 --- a/indra/llmessage/llurlrequest.h +++ b/indra/llmessage/llurlrequest.h @@ -42,9 +42,10 @@ #include "llcurl.h" -extern const std::string CONTEXT_REQUEST; +/** + * External constants + */ extern const std::string CONTEXT_DEST_URI_SD_LABEL; -extern const std::string CONTEXT_RESPONSE; extern const std::string CONTEXT_TRANSFERED_BYTES; class LLURLRequestDetail; @@ -68,42 +69,22 @@ class LLURLRequest : public LLIOPipe { LOG_CLASS(LLURLRequest); public: - typedef int (* SSLCertVerifyCallback)(X509_STORE_CTX *ctx, void *param); - /** - * @brief This enumeration is for specifying the type of request. - */ - enum ERequestAction - { - INVALID, - HTTP_HEAD, - HTTP_GET, - HTTP_PUT, - HTTP_POST, - HTTP_DELETE, - HTTP_MOVE, // Caller will need to set 'Destination' header - REQUEST_ACTION_COUNT - }; - - /** - * @brief Turn the requst action into an http verb. - */ - static std::string actionAsVerb(ERequestAction action); /** * @brief Constructor. * - * @param action One of the ERequestAction enumerations. + * @param action One of the EHTTPMethod enumerations. */ - LLURLRequest(ERequestAction action, bool follow_redirects = true); + LLURLRequest(EHTTPMethod action, bool follow_redirects = true); /** * @brief Constructor. * - * @param action One of the ERequestAction enumerations. + * @param action One of the EHTTPMethod enumerations. * @param url The url of the request. It should already be encoded. */ - LLURLRequest(ERequestAction action, const std::string& url, bool follow_redirects = true); + LLURLRequest(EHTTPMethod action, const std::string& url, bool follow_redirects = true); /** * @brief Destructor. @@ -123,7 +104,7 @@ public: * */ void setURL(const std::string& url); - std::string getURL() const; + const std::string& getURL() const; /** * @brief Set If-Modified-Since Attribute @@ -137,13 +118,13 @@ public: /** * @brief Add a header to the http post. * - * The header must be correctly formatted for HTTP requests. This - * provides a raw interface if you know what kind of request you + * This provides a raw interface if you know what kind of request you * will be making during construction of this instance. All * required headers will be automatically constructed, so this is * usually useful for encoding parameters. */ - void addHeader(const char* header); + void addHeader(const std::string& header, const std::string& value = ""); + void addHeaderRaw(const char* header); /** * @brief Check remote server certificate signed by a known root CA. @@ -228,7 +209,7 @@ protected: STATE_HAVE_RESPONSE, }; EState mState; - ERequestAction mAction; + EHTTPMethod mAction; bool mFollowRedirects; LLURLRequestDetail* mDetail; LLIOPipe::ptr_t mCompletionCallback; @@ -326,7 +307,7 @@ public: // May be called more than once, particularly for redirects and proxy madness. // Ex. a 200 for a connection to https through a proxy, followed by the "real" status // a 3xx for a redirect followed by a "real" status, or more redirects. - virtual void httpStatus(U32 status, const std::string& reason) { } + virtual void httpStatus(S32 status, const std::string& reason) { } virtual void complete( const LLChannelDescriptors& channels, @@ -379,15 +360,8 @@ protected: //@} // value to note if we actually got the response. This value - // depends on correct useage from the LLURLRequest instance. + // depends on correct usage from the LLURLRequest instance. EStatus mRequestStatus; }; - - -/** - * External constants - */ -extern const std::string CONTEXT_DEST_URI_SD_LABEL; - #endif // LL_LLURLREQUEST_H diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index fc7fb608f3..d43dd1fd38 100755 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -112,20 +112,20 @@ namespace { } - virtual void error(U32 status, const std::string& reason) + protected: + virtual void httpFailure() { // don't spam when agent communication disconnected already - if (status != 410) + if (HTTP_GONE != getStatus()) { - LL_WARNS("Messaging") << "error status " << status - << " for message " << mMessageName - << " reason " << reason << LL_ENDL; + LL_WARNS("Messaging") << "error for message " << mMessageName + << " " << dumpResponse() << LL_ENDL; } // TODO: Map status in to useful error code. if(NULL != mCallback) mCallback(mCallbackData, LL_ERR_TCP_TIMEOUT); } - virtual void result(const LLSD& content) + virtual void httpSuccess() { if(NULL != mCallback) mCallback(mCallbackData, LL_ERR_NOERR); } @@ -151,7 +151,7 @@ class LLMessageHandlerBridge : public LLHTTPNode void LLMessageHandlerBridge::post(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const { - std::string name = context["request"]["wildcard"]["message-name"]; + std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["message-name"]; char* namePtr = LLMessageStringTable::getInstance()->getString(name.c_str()); LL_DEBUGS() << "Setting mLastSender " << input["sender"].asString() << LL_ENDL; diff --git a/indra/llmessage/tests/llcurl_stub.cpp b/indra/llmessage/tests/llcurl_stub.cpp index 9b298d0c04..b7fdf4f437 100755 --- a/indra/llmessage/tests/llcurl_stub.cpp +++ b/indra/llmessage/tests/llcurl_stub.cpp @@ -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, std::allocator > 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, std::allocator > const&, - LLSD const&) -{ -} - -void LLCurl::Responder::completedRaw(unsigned, - std::basic_string, std::allocator > const&, - LLChannelDescriptors const&, +void LLCurl::Responder::completedRaw(LLChannelDescriptors const&, boost::shared_ptr const&) { } -void LLCurl::Responder::errorWithContent(unsigned, - std::basic_string, std::allocator > const&, - LLSD const&) +void LLCurl::Responder::httpFailure() { } @@ -67,12 +61,39 @@ LLCurl::Responder::~Responder () { } -void LLCurl::Responder::error(unsigned, - std::basic_string, std::allocator > 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 diff --git a/indra/llmessage/tests/llhttpclient_test.cpp b/indra/llmessage/tests/llhttpclient_test.cpp index 559001d079..a32bfa59ce 100755 --- a/indra/llmessage/tests/llhttpclient_test.cpp +++ b/indra/llmessage/tests/llhttpclient_test.cpp @@ -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: diff --git a/indra/llmessage/tests/llhttpclientadapter_test.cpp b/indra/llmessage/tests/llhttpclientadapter_test.cpp index 13ce0a0edd..e9ce116bb3 100755 --- a/indra/llmessage/tests/llhttpclientadapter_test.cpp +++ b/indra/llmessage/tests/llhttpclientadapter_test.cpp @@ -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 get_urls; -std::vector > get_responders; -void LLHTTPClient::get(const std::string& url, boost::intrusive_ptr 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 put_urls; std::vector put_body; -std::vector > put_responders; +std::vector put_headers; +std::vector put_responders; -void LLHTTPClient::put(const std::string& url, const LLSD& body, boost::intrusive_ptr 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 delete_urls; +std::vector 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 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 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 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 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 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); + } } diff --git a/indra/llmessage/tests/llhttpnode_stub.cpp b/indra/llmessage/tests/llhttpnode_stub.cpp new file mode 100755 index 0000000000..479a256bdd --- /dev/null +++ b/indra/llmessage/tests/llhttpnode_stub.cpp @@ -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) {} + + diff --git a/indra/llmessage/tests/llmime_test.cpp b/indra/llmessage/tests/llmime_test.cpp deleted file mode 100755 index ea48561ae9..0000000000 --- a/indra/llmessage/tests/llmime_test.cpp +++ /dev/null @@ -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_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(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_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: 22rnrnrnrn - */ - 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\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: 22rnrnrnrn */ - 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\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\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: 22rnrnrnrn -*/ - 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\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<>() - { - } -*/ -} diff --git a/indra/llmessage/tests/llregionpresenceverifier_test.cpp b/indra/llmessage/tests/llregionpresenceverifier_test.cpp deleted file mode 100755 index 5b89f2a8c6..0000000000 --- a/indra/llmessage/tests/llregionpresenceverifier_test.cpp +++ /dev/null @@ -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 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); - } -} - diff --git a/indra/llmessage/tests/lltrustedmessageservice_test.cpp b/indra/llmessage/tests/lltrustedmessageservice_test.cpp index b287a29841..55748ad27e 100755 --- a/indra/llmessage/tests/lltrustedmessageservice_test.cpp +++ b/indra/llmessage/tests/lltrustedmessageservice_test.cpp @@ -32,6 +32,7 @@ #include "message.h" #include "llmessageconfig.h" +#include "llhttpnode_stub.cpp" LLMessageSystem* gMessageSystem = NULL; diff --git a/indra/llplugin/llplugincookiestore.cpp b/indra/llplugin/llplugincookiestore.cpp index f64b264222..a5d717389d 100755 --- a/indra/llplugin/llplugincookiestore.cpp +++ b/indra/llplugin/llplugincookiestore.cpp @@ -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) diff --git a/indra/llplugin/llpluginprocesschild.cpp b/indra/llplugin/llpluginprocesschild.cpp index 19b814bc35..f8a282184e 100755 --- a/indra/llplugin/llpluginprocesschild.cpp +++ b/indra/llplugin/llpluginprocesschild.cpp @@ -364,12 +364,7 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message) else { // This is a new region - - // use smartptr - // LLPluginSharedMemory *region = new LLPluginSharedMemory; - LLPluginSharedMemoryPtr region( new LLPluginSharedMemory ); - // - + LLPluginSharedMemory *region = new LLPluginSharedMemory; if(region->attach(name, size)) { mSharedMemoryRegions.insert(sharedMemoryRegionsType::value_type(name, region)); @@ -392,7 +387,7 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message) else { LL_WARNS("Plugin") << "Couldn't create a shared memory segment!" << LL_ENDL; - // delete region; // smartptr will delete automatically. + delete region; } } diff --git a/indra/llplugin/llpluginprocesschild.h b/indra/llplugin/llpluginprocesschild.h index 52f71e3b5b..531422e792 100755 --- a/indra/llplugin/llpluginprocesschild.h +++ b/indra/llplugin/llpluginprocesschild.h @@ -97,11 +97,7 @@ private: LLPluginInstance *mInstance; - // Use boost::shred_ptr so LLPluginSharedMemory gets properly destroyed - // typedef std::map sharedMemoryRegionsType; - typedef std::map sharedMemoryRegionsType; - // - + typedef std::map sharedMemoryRegionsType; sharedMemoryRegionsType mSharedMemoryRegions; LLTimer mHeartbeat; diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index 6fbe994e6a..083d66b863 100755 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -133,6 +133,8 @@ LLPluginProcessParent::~LLPluginProcessParent() { // destroy the shared memory region iter->second->destroy(); + delete iter->second; + iter->second = NULL; // and remove it from our map mSharedMemoryRegions.erase(iter); @@ -979,6 +981,8 @@ void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message) { // destroy the shared memory region iter->second->destroy(); + delete iter->second; + iter->second = NULL; // and remove it from our map mSharedMemoryRegions.erase(iter); @@ -1002,10 +1006,7 @@ std::string LLPluginProcessParent::addSharedMemory(size_t size) { std::string name; - // Use smartptr - // LLPluginSharedMemory *region = new LLPluginSharedMemory; - LLPluginSharedMemoryPtr region( new LLPluginSharedMemory ); - // + LLPluginSharedMemory *region = new LLPluginSharedMemory; // This is a new region if(region->create(size)) @@ -1024,7 +1025,7 @@ std::string LLPluginProcessParent::addSharedMemory(size_t size) LL_WARNS("Plugin") << "Couldn't create a shared memory segment!" << LL_ENDL; // Don't leak - // delete region; // Smartptr will autodelete. + delete region; } return name; diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h index 4be4843f39..10e941c63e 100755 --- a/indra/llplugin/llpluginprocessparent.h +++ b/indra/llplugin/llpluginprocessparent.h @@ -160,11 +160,7 @@ private: LLPluginProcessParentOwner *mOwner; - // Use boost::shred_ptr so LLPluginSharedMemory gets properly destroyed - // typedef std::map sharedMemoryRegionsType; - typedef std::map sharedMemoryRegionsType; - // - + typedef std::map sharedMemoryRegionsType; sharedMemoryRegionsType mSharedMemoryRegions; LLSD mMessageClassVersions; diff --git a/indra/llplugin/llpluginsharedmemory.h b/indra/llplugin/llpluginsharedmemory.h index b20d755e47..c6cd49cabb 100755 --- a/indra/llplugin/llpluginsharedmemory.h +++ b/indra/llplugin/llpluginsharedmemory.h @@ -28,8 +28,6 @@ #ifndef LL_LLPLUGINSHAREDMEMORY_H #define LL_LLPLUGINSHAREDMEMORY_H -#include - class LLPluginSharedMemoryPlatformImpl; /** @@ -122,7 +120,6 @@ private: }; -typedef boost::shared_ptr< LLPluginSharedMemory > LLPluginSharedMemoryPtr; #endif // LL_LLPLUGINSHAREDMEMORY_H diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index b3bdaa0e93..e6c9880953 100755 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -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 diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 3d778da174..b58b6a5570 100755 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -390,9 +390,7 @@ LLImageGL::~LLImageGL() { LLImageGL::cleanup(); sImageList.erase(this); - disclaimMem((mPickMaskWidth * mPickMaskHeight + 7) / 8); - delete [] mPickMask; - mPickMask = NULL; + freePickMask(); sCount--; } @@ -461,6 +459,8 @@ void LLImageGL::cleanup() { destroyGLTexture(); } + freePickMask(); + mSaveData = NULL; // deletes data } @@ -507,10 +507,7 @@ void LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_leve } // pickmask validity depends on old image size, delete it - disclaimMem((mPickMaskWidth * mPickMaskHeight + 7) / 8); - delete [] mPickMask; - mPickMask = NULL; - mPickMaskWidth = mPickMaskHeight = 0; + freePickMask(); mWidth = width; mHeight = height; @@ -1889,27 +1886,10 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) } //---------------------------------------------------------------------------- -void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) +U32 LLImageGL::createPickMask(S32 pWidth, S32 pHeight) { - if(!mNeedsAlphaAndPickMask) - { - return ; - } - - disclaimMem((mPickMaskWidth * mPickMaskHeight + 7) / 8); - delete [] mPickMask; - mPickMask = NULL; - mPickMaskWidth = mPickMaskHeight = 0; - - if (mFormatType != GL_UNSIGNED_BYTE || - mFormatPrimary != GL_RGBA) - { - //cannot generate a pick mask for this texture - return; - } - - U32 pick_width = width/2 + 1; - U32 pick_height = height/2 + 1; + U32 pick_width = pWidth/2 + 1; + U32 pick_height = pHeight/2 + 1; U32 size = pick_width * pick_height; size = (size + 7) / 8; // pixelcount-to-bits @@ -1920,6 +1900,45 @@ void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) memset(mPickMask, 0, sizeof(U8) * size); + return size; +} + +//---------------------------------------------------------------------------- +void LLImageGL::freePickMask() +{ + // pickmask validity depends on old image size, delete it + if (mPickMask != NULL) + { + disclaimMem((mPickMaskWidth * mPickMaskHeight + 7) / 8); + delete [] mPickMask; + } + mPickMask = NULL; + mPickMaskWidth = mPickMaskHeight = 0; +} + +//---------------------------------------------------------------------------- +void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) +{ + if(!mNeedsAlphaAndPickMask) + { + return ; + } + + freePickMask(); + + if (mFormatType != GL_UNSIGNED_BYTE || + mFormatPrimary != GL_RGBA) + { + //cannot generate a pick mask for this texture + return; + } + +#ifdef SHOW_ASSERT + const U32 pickSize = createPickMask(width, height); +#else // SHOW_ASSERT + createPickMask(width, height); +#endif // SHOW_ASSERT + U32 pick_bit = 0; for (S32 y = 0; y < height; y += 2) @@ -1932,7 +1951,7 @@ void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) { U32 pick_idx = pick_bit/8; U32 pick_offset = pick_bit%8; - llassert(pick_idx < size); + llassert(pick_idx < pickSize); mPickMask[pick_idx] |= 1 << pick_offset; } diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index 6ca814af6f..21982eab1d 100755 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -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 mSaveData; // used for destroyGL/restoreGL U8* mPickMask; //downsampled bitmap approximation of alpha channel. NULL if no alpha channel U16 mPickMaskWidth; diff --git a/indra/llui/llbadgeowner.cpp b/indra/llui/llbadgeowner.cpp index 1860a05edd..18412e60f7 100755 --- a/indra/llui/llbadgeowner.cpp +++ b/indra/llui/llbadgeowner.cpp @@ -35,8 +35,9 @@ // LLBadgeOwner::LLBadgeOwner(LLHandle< LLView > viewHandle) - : mBadge(NULL) - , mBadgeOwnerView(viewHandle) + : mHasBadgeHolderParent(false), + mBadge(NULL), + mBadgeOwnerView(viewHandle) { } @@ -45,16 +46,24 @@ void LLBadgeOwner::initBadgeParams(const LLBadge::Params& p) if (!p.equals(LLUICtrlFactory::getDefaultParams())) { mBadge = createBadge(p); + mHasBadgeHolderParent = false; + + LLView * owner_view = mBadgeOwnerView.get(); + if (owner_view) + { + mBadge->addToView(owner_view); + } } } +// Re-add setBadgeLabel void LLBadgeOwner::setBadgeLabel(const LLStringExplicit& label) { if (mBadge == NULL) { mBadge = createBadge(LLUICtrlFactory::getDefaultParams()); - addBadgeToParentPanel(); + addBadgeToParentHolder(); } if (mBadge) @@ -73,6 +82,7 @@ void LLBadgeOwner::setBadgeLabel(const LLStringExplicit& label) } } } +// void LLBadgeOwner::setBadgeVisibility(bool visible) { @@ -82,10 +92,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 +118,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) diff --git a/indra/llui/llbadgeowner.h b/indra/llui/llbadgeowner.h index 8d03e30645..82f636b5b1 100755 --- a/indra/llui/llbadgeowner.h +++ b/indra/llui/llbadgeowner.h @@ -41,11 +41,12 @@ public: LLBadgeOwner(LLHandle< LLView > viewHandle); void initBadgeParams(const LLBadge::Params& p); - bool addBadgeToParentPanel(); + void addBadgeToParentHolder(); - bool badgeHasParent() const { return (mBadge && mBadge->getParent()); } - + bool hasBadgeHolderParent() const { return mHasBadgeHolderParent; }; + // Re-add setBadgeLabel void setBadgeLabel(const LLStringExplicit& label); + // void setBadgeVisibility(bool visible); private: @@ -53,7 +54,7 @@ private: LLBadge* createBadge(const LLBadge::Params& p); private: - + bool mHasBadgeHolderParent; LLBadge* mBadge; LLHandle< LLView > mBadgeOwnerView; }; diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 6bff27532a..f405fbffe4 100755 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -420,7 +420,7 @@ BOOL LLButton::postBuild() } // - addBadgeToParentPanel(); + addBadgeToParentHolder(); return LLUICtrl::postBuild(); } diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 10e26b08a2..da7b830aec 100755 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -1707,7 +1707,7 @@ void LLFloater::bringToFront( S32 x, S32 y ) // virtual -void LLFloater::setVisibleAndFrontmost(BOOL take_focus, const LLSD& key) +void LLFloater::setVisibleAndFrontmost(BOOL take_focus,const LLSD& key) { LLMultiFloater* hostp = getHost(); if (hostp) diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index ec13b5569b..e6475c1285 100755 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -313,7 +313,7 @@ public: /*virtual*/ void onVisibilityChange ( BOOL new_visibility ); // do not override void setFrontmost(BOOL take_focus = TRUE); - virtual void setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD()); + virtual void setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD()); // Defaults to false. virtual BOOL canSaveAs() const { return FALSE; } diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 2d5ea60a55..8e5aede4d7 100755 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -231,10 +231,11 @@ LLFolderView::LLFolderView(const Params& p) mStatusTextBox = LLUICtrlFactory::create (text_p); mStatusTextBox->setFollowsLeft(); mStatusTextBox->setFollowsTop(); - //addChild(mStatusTextBox); + addChild(mStatusTextBox); // make the popup menu available + llassert(LLMenuGL::sMenuContainer != NULL); LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile(p.options_menu, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); if (!menu) { @@ -734,8 +735,9 @@ void LLFolderView::finishRenamingItem( void ) closeRenamer(); + // This is moved to an inventory observer in llinventorybridge.cpp, to handle updating after operation completed in AISv3 (SH-4611). // List is re-sorted alphabetically, so scroll to make sure the selected item is visible. - scrollToShowSelection(); + //scrollToShowSelection(); } void LLFolderView::closeRenamer( void ) diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index eb35f767c0..421cdbbf2f 100755 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -193,6 +193,7 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p) setPrevalidateInput(p.prevalidate_input_callback()); setPrevalidate(p.prevalidate_callback()); + llassert(LLMenuGL::sMenuContainer != NULL); // Only allocate a menu when it's called for the first time // LLContextMenu* menu = LLUICtrlFactory::instance().createFromFile // ("menu_text_editor.xml", diff --git a/indra/llui/llmenubutton.cpp b/indra/llui/llmenubutton.cpp index 0609cd8b42..303afcda15 100755 --- a/indra/llui/llmenubutton.cpp +++ b/indra/llui/llmenubutton.cpp @@ -93,6 +93,7 @@ void LLMenuButton::setMenu(const std::string& menu_filename, EMenuPosition posit return; } + llassert(LLMenuGL::sMenuContainer != NULL); LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile(menu_filename, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); if (!menu) { diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 0df600df14..39b968ba02 100755 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -63,6 +63,7 @@ // static LLMenuHolderGL *LLMenuGL::sMenuContainer = NULL; +view_listener_t::listener_map_t view_listener_t::sListeners; S32 MENU_BAR_HEIGHT = 0; S32 MENU_BAR_WIDTH = 0; diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 09b05a16f4..e1c8a0a2d2 100755 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -903,7 +903,8 @@ class view_listener_t : public boost::signals2::trackable { public: virtual bool handleEvent(const LLSD& userdata) = 0; - virtual ~view_listener_t() {} + view_listener_t() { sListeners.insert(this); } + virtual ~view_listener_t() { sListeners.erase(this); } static void addEnable(view_listener_t* listener, const std::string& name) { @@ -921,6 +922,20 @@ public: addEnable(listener, name); addCommit(listener, name); } + + static void cleanup() + { + listener_vector_t listeners(sListeners.begin(), sListeners.end()); + sListeners.clear(); + + std::for_each(listeners.begin(), listeners.end(), DeletePointer()); + listeners.clear(); + } + +private: + typedef std::set listener_map_t; + typedef std::vector listener_vector_t; + static listener_map_t sListeners; }; #endif // LL_LLMENUGL_H diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index c352368bed..353c30996c 100755 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -1954,6 +1954,7 @@ BOOL LLScrollListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) // create the context menu from the XUI file and display it std::string menu_name = is_group ? "menu_url_group.xml" : "menu_url_agent.xml"; delete mPopupMenu; + llassert(LLMenuGL::sMenuContainer != NULL); mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile( menu_name, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); if (mPopupMenu) diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index e605dae171..890f3b1ca4 100755 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -1243,6 +1243,17 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel) addChild( btn, 0 ); } } + else + { + if (textbox) + { + LLUICtrl::addChild(textbox, 0); + } + if (btn) + { + LLUICtrl::addChild(btn, 0); + } + } if (child) { @@ -1763,16 +1774,26 @@ void LLTabContainer::setTabImage(LLPanel* child, LLIconCtrl* icon) { LLTabTuple* tuple = getTabByPanel(child); LLCustomButtonIconCtrl* button; + bool hasButton = false; if(tuple) { button = dynamic_cast(tuple->mButton); if(button) { + hasButton = true; button->setIcon(icon); reshapeTuple(tuple); } } + + if (!hasButton && (icon != NULL)) + { + // It was assumed that the tab's button would take ownership of the icon pointer. + // But since the tab did not have a button, kill the icon to prevent the memory + // leak. + icon->die(); + } } void LLTabContainer::reshapeTuple(LLTabTuple* tuple) diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 33d9fb53e9..2fb3a0601e 100755 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -2160,6 +2160,7 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url) // create and return the context menu from the XUI file delete mPopupMenu; + llassert(LLMenuGL::sMenuContainer != NULL); mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile(xui_file, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); if (mIsFriendSignal) @@ -2242,7 +2243,7 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para LLUrlMatch match; std::string text = new_text; while ( LLUrlRegistry::instance().findUrl(text, match, - boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3)) ) + boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3),isContentTrusted())) { start = match.getStart(); end = match.getEnd()+1; @@ -2271,7 +2272,7 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para // Optional icon position if (mIconPositioning == LLTextBaseEnums::LEFT) { - LLTextUtil::processUrlMatch(&match,this); + LLTextUtil::processUrlMatch(&match,this,isContentTrusted()); } // Optional icon position @@ -2294,10 +2295,10 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para } // Optional icon position - //LLTextUtil::processUrlMatch(&match,this); + //LLTextUtil::processUrlMatch(&match,this,isContentTrusted()); if (mIconPositioning == LLTextBaseEnums::RIGHT) { - LLTextUtil::processUrlMatch(&match,this); + LLTextUtil::processUrlMatch(&match,this,isContentTrusted()); } // Optional icon position diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 2bebfe7fe7..44121f53c8 100755 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -401,7 +401,9 @@ public: bool getWordWrap() { return mWordWrap; } bool getUseEllipses() { return mUseEllipses; } bool truncate(); // returns true of truncation occurred + bool isContentTrusted() {return mTrustedContent;} + void setContentTrusted(bool trusted_content) { mTrustedContent = trusted_content; } // TODO: move into LLTextSegment? void createUrlContextMenu(S32 x, S32 y, const std::string &url); // create a popup context menu for the given Url diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 119c92081e..5c3b0fe383 100755 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -2096,6 +2096,7 @@ void LLTextEditor::showContextMenu(S32 x, S32 y) { if (!mContextMenu) { + llassert(LLMenuGL::sMenuContainer != NULL); mContextMenu = LLUICtrlFactory::instance().createFromFile("menu_text_editor.xml", LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); diff --git a/indra/llui/lltextutil.cpp b/indra/llui/lltextutil.cpp index 4df2c3363f..fff04b34f2 100755 --- a/indra/llui/lltextutil.cpp +++ b/indra/llui/lltextutil.cpp @@ -72,7 +72,7 @@ const std::string& LLTextUtil::formatPhoneNumber(const std::string& phone_str) return formatted_phone_str; } -bool LLTextUtil::processUrlMatch(LLUrlMatch* match,LLTextBase* text_base) +bool LLTextUtil::processUrlMatch(LLUrlMatch* match,LLTextBase* text_base, bool is_content_trusted) { if (match == 0 || text_base == 0) return false; @@ -85,7 +85,7 @@ bool LLTextUtil::processUrlMatch(LLUrlMatch* match,LLTextBase* text_base) } // output an optional icon before the Url - if (!match->getIcon().empty() ) + if (is_content_trusted && !match->getIcon().empty() ) { LLUIImagePtr image = LLUI::getUIImage(match->getIcon()); if (image) diff --git a/indra/llui/lltextutil.h b/indra/llui/lltextutil.h index bf7dbb58ce..798f14d086 100755 --- a/indra/llui/lltextutil.h +++ b/indra/llui/lltextutil.h @@ -64,7 +64,7 @@ namespace LLTextUtil */ const std::string& formatPhoneNumber(const std::string& phone_str); - bool processUrlMatch(LLUrlMatch* match,LLTextBase* text_base); + bool processUrlMatch(LLUrlMatch* match,LLTextBase* text_base, bool is_content_trusted); class TextHelpers { diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp index 2a62c3dcf9..dbbdb228a6 100755 --- a/indra/llui/lltoolbar.cpp +++ b/indra/llui/lltoolbar.cpp @@ -198,6 +198,7 @@ void LLToolBar::createContextMenu() // // Create the context menu + llassert(LLMenuGL::sMenuContainer != NULL); // Load the context menu, using the previously defined XML file name // LLContextMenu* menu = LLUICtrlFactory::instance().createFromFile("menu_toolbars.xml", LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); LLContextMenu* menu = LLUICtrlFactory::instance().createFromFile(menu_xml_name, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index 4eb4432b12..0e12a4f7b0 100755 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -45,7 +45,8 @@ LLUrlRegistry::LLUrlRegistry() // Urls are matched in the order that they were registered registerUrl(new LLUrlEntryNoLink()); - registerUrl(new LLUrlEntryIcon()); + mUrlEntryIcon = new LLUrlEntryIcon(); + registerUrl(mUrlEntryIcon); registerUrl(new LLUrlEntrySLURL()); registerUrl(new LLUrlEntryHTTP()); registerUrl(new LLUrlEntryHTTPLabel()); @@ -197,7 +198,7 @@ static bool stringHasJira(const std::string &text) text.find("WEB") != std::string::npos); } -bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb) +bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb, bool is_content_trusted) { // avoid costly regexes if there is clearly no URL in the text if (! (stringHasUrl(text) || stringHasJira(text))) @@ -212,6 +213,12 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL std::vector::iterator it; for (it = mUrlEntry.begin(); it != mUrlEntry.end(); ++it) { + //Skip for url entry icon if content is not trusted + if(!is_content_trusted && (mUrlEntryIcon == *it)) + { + continue; + } + LLUrlEntryBase *url_entry = *it; U32 start = 0, end = 0; diff --git a/indra/llui/llurlregistry.h b/indra/llui/llurlregistry.h index da16171a97..6270df1bbb 100755 --- a/indra/llui/llurlregistry.h +++ b/indra/llui/llurlregistry.h @@ -73,7 +73,8 @@ public: /// get the next Url in an input string, starting at a given character offset /// your callback is invoked if the matched Url's label changes in the future bool findUrl(const std::string &text, LLUrlMatch &match, - const LLUrlLabelCallback &cb = &LLUrlRegistryNullCallback); + const LLUrlLabelCallback &cb = &LLUrlRegistryNullCallback, + bool is_content_trusted = false); /// a slightly less efficient version of findUrl for wide strings bool findUrl(const LLWString &text, LLUrlMatch &match, @@ -92,6 +93,7 @@ private: friend class LLSingleton; std::vector mUrlEntry; + LLUrlEntryBase* mUrlEntryIcon; }; #endif diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 0761907fab..08af58d5a6 100755 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -660,7 +660,7 @@ LLWindowWin32::~LLWindowWin32() delete [] mSupportedResolutions; mSupportedResolutions = NULL; - delete mWindowClassName; + delete [] mWindowClassName; mWindowClassName = NULL; } diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 9271ef6f74..3a2241dd73 100755 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -210,6 +210,7 @@ set(viewer_SOURCE_FILES llpanelopenregionsettings.cpp llaccountingcostmanager.cpp + llaisapi.cpp llagent.cpp llagentaccess.cpp llagentcamera.cpp @@ -220,7 +221,6 @@ set(viewer_SOURCE_FILES llagentpilot.cpp llagentui.cpp llagentwearables.cpp - llagentwearablesfetch.cpp llanimstatelabels.cpp llappcorehttp.cpp llappearancemgr.cpp @@ -425,6 +425,7 @@ set(viewer_SOURCE_FILES llhasheduniqueid.cpp llhints.cpp llhomelocationresponder.cpp + llhttpretrypolicy.cpp llhudeffect.cpp llhudeffectbeam.cpp llhudeffectlookat.cpp @@ -925,6 +926,7 @@ set(viewer_HEADER_FILES lfsimfeaturehandler.h llaccountingcostmanager.h + llaisapi.h llagent.h llagentaccess.h llagentcamera.h @@ -935,7 +937,6 @@ set(viewer_HEADER_FILES llagentpilot.h llagentui.h llagentwearables.h - llagentwearablesfetch.h llanimstatelabels.h llappcorehttp.h llappearance.h @@ -1142,6 +1143,7 @@ set(viewer_HEADER_FILES llgroupmgr.h llhasheduniqueid.h llhints.h + llhttpretrypolicy.h llhomelocationresponder.h llhudeffect.h llhudeffectbeam.h @@ -2555,6 +2557,11 @@ if (LL_TESTS) #llviewertexturelist.cpp ) + set(test_libs + ${JSONCPP_LIBRARIES} + ${CURL_LIBRARIES} + ) + set_source_files_properties( llworldmap.cpp llworldmipmap.cpp @@ -2567,7 +2574,13 @@ if (LL_TESTS) set_source_files_properties( lltranslate.cpp PROPERTIES - LL_TEST_ADDITIONAL_LIBRARIES "${JSONCPP_LIBRARIES}" + LL_TEST_ADDITIONAL_LIBRARIES "${test_libs}" + ) + + set_source_files_properties( + llmediadataclient.cpp + PROPERTIES + LL_TEST_ADDITIONAL_LIBRARIES "${CURL_LIBRARIES}" ) set_source_files_properties( @@ -2648,6 +2661,7 @@ if (LL_TESTS) set(test_libs ${LLMESSAGE_LIBRARIES} + ${LLCOREHTTP_LIBRARIES} ${WINDOWS_LIBRARIES} ${LLVFS_LIBRARIES} ${LLMATH_LIBRARIES} @@ -2689,6 +2703,8 @@ if (LL_TESTS) "${test_libs}" ) + LL_ADD_INTEGRATION_TEST(llhttpretrypolicy "llhttpretrypolicy.cpp" "${test_libs}") + #ADD_VIEWER_BUILD_TEST(llmemoryview viewer) #ADD_VIEWER_BUILD_TEST(llagentaccess viewer) #ADD_VIEWER_BUILD_TEST(lltextureinfo viewer) diff --git a/indra/newview/aoengine.cpp b/indra/newview/aoengine.cpp index 032916c6ca..aac34ca400 100644 --- a/indra/newview/aoengine.cpp +++ b/indra/newview/aoengine.cpp @@ -736,14 +736,11 @@ BOOL AOEngine::createAnimationLink(const AOSet* set,AOSet::AOState* state,const return FALSE; } - link_inventory_item( - gAgent.getID(), - item->getUUID(), - state->mInventoryUUID, - item->getName(), - item->getDescription(), - LLAssetType::AT_LINK, - NULL); + LLInventoryObject::const_object_list_t obj_array; + obj_array.push_back(LLConstPointer(item)); + link_inventory_array(state->mInventoryUUID, + obj_array, + LLPointer(NULL)); return TRUE; } @@ -840,11 +837,11 @@ void AOEngine::purgeFolder(const LLUUID& uuid) const gInventory.removeCategory(uuid); // clean it - gInventory.purgeDescendentsOf(uuid); + purge_descendents_of(uuid, NULL); gInventory.notifyObservers(); // purge it - gInventory.purgeObject(uuid); + remove_inventory_object(uuid, NULL); gInventory.notifyObservers(); // protect it @@ -890,7 +887,7 @@ BOOL AOEngine::removeAnimation(const AOSet* set,AOSet::AOState* state,S32 index) // purge the item from inventory LL_DEBUGS("AOEngine") << __LINE__ << " purging: " << state->mAnimations[index].mInventoryUUID << LL_ENDL; - gInventory.purgeObject(state->mAnimations[index].mInventoryUUID); // item->getUUID()); + remove_inventory_object(state->mAnimations[index].mInventoryUUID, NULL); // item->getUUID()); gInventory.notifyObservers(); state->mAnimations.erase(state->mAnimations.begin()+index); diff --git a/indra/newview/app_settings/logcontrol.xml b/indra/newview/app_settings/logcontrol.xml index 9bb144a599..58720eaa68 100644 --- a/indra/newview/app_settings/logcontrol.xml +++ b/indra/newview/app_settings/logcontrol.xml @@ -44,6 +44,7 @@