diff options
Diffstat (limited to 'indra/newview')
116 files changed, 3013 insertions, 1831 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 4f7ce88165..27dbe15005 100644..100755 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -299,6 +299,7 @@ set(viewer_SOURCE_FILES llgroupmgr.cpp llhints.cpp llhomelocationresponder.cpp + llhttpretrypolicy.cpp llhudeffect.cpp llhudeffectbeam.cpp llhudeffectlookat.cpp @@ -877,6 +878,7 @@ set(viewer_HEADER_FILES llgrouplist.h llgroupmgr.h llhints.h + llhttpretrypolicy.h llhomelocationresponder.h llhudeffect.h llhudeffectbeam.h @@ -2091,10 +2093,21 @@ if (LL_TESTS) #llviewertexturelist.cpp ) + set(test_libs + ${JSONCPP_LIBRARIES} + ${CURL_LIBRARIES} + ) + 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( @@ -2141,6 +2154,7 @@ if (LL_TESTS) set(test_libs ${LLMESSAGE_LIBRARIES} + ${LLCOREHTTP_LIBRARIES} ${WINDOWS_LIBRARIES} ${LLVFS_LIBRARIES} ${LLMATH_LIBRARIES} @@ -2186,6 +2200,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/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index f66d8fca5b..1262089b3d 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -11130,6 +11130,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>TextureFetchFakeFailureRate</key> + <map> + <key>Comment</key> + <string>Simulate HTTP fetch failures for some server bake textures.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <integer>0.0</integer> + </map> <key>TextureFetchSource</key> <map> <key>Comment</key> @@ -14022,6 +14033,17 @@ <key>Value</key> <integer>1</integer> </map> + <key>UseAISv3Inventory</key> + <map> + <key>Comment</key> + <string>Allow use of AISv3 inventory - this setting should only be needed during development.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>ClickToWalk</key> <map> <key>Comment</key> diff --git a/indra/newview/llaccountingcostmanager.cpp b/indra/newview/llaccountingcostmanager.cpp index 7662a9689d..55d453cdcc 100644 --- a/indra/newview/llaccountingcostmanager.cpp +++ b/indra/newview/llaccountingcostmanager.cpp @@ -36,6 +36,7 @@ LLAccountingCostManager::LLAccountingCostManager() //=============================================================================== class LLAccountingCostResponder : public LLCurl::Responder { + LOG_CLASS(LLAccountingCostResponder); public: LLAccountingCostResponder( const LLSD& objectIDs, const LLHandle<LLAccountingCostObserver>& observer_handle ) : mObjectIDs( objectIDs ), @@ -56,24 +57,27 @@ public: } } - void errorWithContent( U32 statusNum, const std::string& reason, const LLSD& content ) +protected: + void httpFailure() { - llwarns << "Transport error [status:" << statusNum << "]: " << content <<llendl; + llwarns << dumpResponse() << llendl; clearPendingRequests(); LLAccountingCostObserver* observer = mObserverHandle.get(); if (observer && observer->getTransactionID() == mTransactionID) { - observer->setErrorStatus(statusNum, reason); + observer->setErrorStatus(getStatus(), getReason()); } } - void result( const LLSD& content ) + void httpSuccess() { + const LLSD& content = getContent(); //Check for error if ( !content.isMap() || content.has("error") ) { - llwarns << "Error on fetched data"<< llendl; + failureResult(HTTP_INTERNAL_ERROR, "Error on fetched data", content); + return; } else if (content.has("selected")) { diff --git a/indra/newview/llaccountingcostmanager.h b/indra/newview/llaccountingcostmanager.h index 0bca1f54ef..3ade34c81d 100644 --- a/indra/newview/llaccountingcostmanager.h +++ b/indra/newview/llaccountingcostmanager.h @@ -38,7 +38,7 @@ public: LLAccountingCostObserver() { mObserverHandle.bind(this); } virtual ~LLAccountingCostObserver() {} virtual void onWeightsUpdate(const SelectionCost& selection_cost) = 0; - virtual void setErrorStatus(U32 status, const std::string& reason) = 0; + virtual void setErrorStatus(S32 status, const std::string& reason) = 0; const LLHandle<LLAccountingCostObserver>& getObserverHandle() const { return mObserverHandle; } const LLUUID& getTransactionID() { return mTransactionID; } diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 8c42defa73..939d9398b2 100755 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -2526,17 +2526,19 @@ int LLAgent::convertTextToMaturity(char text) class LLMaturityPreferencesResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLMaturityPreferencesResponder); public: LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity); virtual ~LLMaturityPreferencesResponder(); - virtual void result(const LLSD &pContent); - virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); +protected: + virtual void httpSuccess(); + virtual void httpFailure(); protected: private: - U8 parseMaturityFromServerResponse(const LLSD &pContent); + U8 parseMaturityFromServerResponse(const LLSD &pContent) const; LLAgent *mAgent; U8 mPreferredMaturity; @@ -2555,39 +2557,43 @@ LLMaturityPreferencesResponder::~LLMaturityPreferencesResponder() { } -void LLMaturityPreferencesResponder::result(const LLSD &pContent) +void LLMaturityPreferencesResponder::httpSuccess() { - U8 actualMaturity = parseMaturityFromServerResponse(pContent); + U8 actualMaturity = parseMaturityFromServerResponse(getContent()); if (actualMaturity != mPreferredMaturity) { - llwarns << "while attempting to change maturity preference from '" << LLViewerRegion::accessToString(mPreviousMaturity) - << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) << "', the server responded with '" - << LLViewerRegion::accessToString(actualMaturity) << "' [value:" << static_cast<U32>(actualMaturity) << ", llsd:" - << pContent << "]" << llendl; + llwarns << "while attempting to change maturity preference from '" + << LLViewerRegion::accessToString(mPreviousMaturity) + << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) + << "', the server responded with '" + << LLViewerRegion::accessToString(actualMaturity) + << "' [value:" << static_cast<U32>(actualMaturity) + << "], " << dumpResponse() << llendl; } mAgent->handlePreferredMaturityResult(actualMaturity); } -void LLMaturityPreferencesResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent) +void LLMaturityPreferencesResponder::httpFailure() { - llwarns << "while attempting to change maturity preference from '" << LLViewerRegion::accessToString(mPreviousMaturity) - << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) << "', we got an error with [status:" - << pStatus << "]: " << (pContent.isDefined() ? pContent : LLSD(pReason)) << llendl; + llwarns << "while attempting to change maturity preference from '" + << LLViewerRegion::accessToString(mPreviousMaturity) + << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) + << "', " << dumpResponse() << llendl; mAgent->handlePreferredMaturityError(); } -U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &pContent) +U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &pContent) const { U8 maturity = SIM_ACCESS_MIN; - llassert(!pContent.isUndefined()); + llassert(pContent.isDefined()); llassert(pContent.isMap()); llassert(pContent.has("access_prefs")); llassert(pContent.get("access_prefs").isMap()); llassert(pContent.get("access_prefs").has("max")); llassert(pContent.get("access_prefs").get("max").isString()); - if (!pContent.isUndefined() && pContent.isMap() && pContent.has("access_prefs") + if (pContent.isDefined() && pContent.isMap() && pContent.has("access_prefs") && pContent.get("access_prefs").isMap() && pContent.get("access_prefs").has("max") && pContent.get("access_prefs").get("max").isString()) { @@ -2733,7 +2739,7 @@ void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity) // If we don't have a region, report it as an error if (getRegion() == NULL) { - responderPtr->errorWithContent(0U, "region is not defined", LLSD()); + responderPtr->failureResult(0U, "region is not defined", LLSD()); } else { @@ -2743,7 +2749,7 @@ void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity) // If the capability is not defined, report it as an error if (url.empty()) { - responderPtr->errorWithContent(0U, + responderPtr->failureResult(0U, "capability 'UpdateAgentInformation' is not defined for region", LLSD()); } else @@ -3242,8 +3248,7 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode !input.has("body") ) { //what to do with badly formed message? - response->statusUnknownError(400); - response->result(LLSD("Invalid message parameters")); + response->extendedResult(HTTP_BAD_REQUEST, LLSD("Invalid message parameters")); } LLSD body = input["body"]; @@ -3312,8 +3317,7 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode else { //what to do with badly formed message? - response->statusUnknownError(400); - response->result(LLSD("Invalid message parameters")); + response->extendedResult(HTTP_BAD_REQUEST, LLSD("Invalid message parameters")); } } }; diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index c88694ef76..b4c3e33e0e 100755..100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -69,7 +69,7 @@ void wear_and_edit_cb(const LLUUID& inv_item) gAgentWearables.requestEditingWearable(inv_item); // Wear it. - LLAppearanceMgr::instance().wearItemOnAvatar(inv_item); + LLAppearanceMgr::instance().wearItemOnAvatar(inv_item,true); } /////////////////////////////////////////////////////////////////////////////// @@ -239,7 +239,7 @@ void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& i } if (mTodo & CALL_RECOVERDONE) { - LLAppearanceMgr::instance().addCOFItemLink(inv_item,false); + LLAppearanceMgr::instance().addCOFItemLink(inv_item); gAgentWearables.recoverMissingWearableDone(); } /* @@ -247,7 +247,7 @@ void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& i */ if (mTodo & CALL_CREATESTANDARDDONE) { - LLAppearanceMgr::instance().addCOFItemLink(inv_item,false); + LLAppearanceMgr::instance().addCOFItemLink(inv_item); gAgentWearables.createStandardWearablesDone(mType, mIndex); } if (mTodo & CALL_MAKENEWOUTFITDONE) @@ -256,7 +256,8 @@ void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& i } if (mTodo & CALL_WEARITEM) { - LLAppearanceMgr::instance().addCOFItemLink(inv_item, true, NULL, mDescription); + LLAppearanceMgr::instance().addCOFItemLink(inv_item, + new LLUpdateAppearanceAndEditWearableOnDestroy(inv_item), mDescription); } } diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 652f199e28..40ec88f1be 100755 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -52,6 +52,7 @@ #include "llwearablelist.h" #include "llsdutil.h" #include "llsdserialize.h" +#include "llhttpretrypolicy.h" #if LL_MSVC // disable boost::lexical_cast warning @@ -420,93 +421,25 @@ public: } }; -class LLCallAfterInventoryLinkMgr: public LLCallAfterInventoryBatchMgr -{ -public: - LLCallAfterInventoryLinkMgr(LLInventoryModel::item_array_t& src_items, - const LLUUID& dst_cat_id, - const std::string& phase_name, - nullary_func_t on_completion_func, - nullary_func_t on_failure_func = no_op, - F32 retry_after = DEFAULT_RETRY_AFTER_INTERVAL, - S32 max_retries = DEFAULT_MAX_RETRIES - ): - LLCallAfterInventoryBatchMgr(dst_cat_id, phase_name, on_completion_func, on_failure_func, retry_after, max_retries) - { - addItems(src_items); - } - - virtual bool requestOperation(const LLUUID& item_id) - { - bool request_sent = false; - LLViewerInventoryItem *item = gInventory.getItem(item_id); - if (item) - { - if (item->getParentUUID() == mDstCatID) - { - LL_DEBUGS("Avatar") << "item " << item_id << " name " << item->getName() << " is already a child of " << mDstCatID << llendl; - return false; - } - LL_DEBUGS("Avatar") << "linking item " << item_id << " name " << item->getName() << " to " << mDstCatID << llendl; - // create an inventory item link. - if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate")) - { - LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << llendl; - return true; - } - link_inventory_item(gAgent.getID(), - item->getLinkedUUID(), - mDstCatID, - item->getName(), - item->getActualDescription(), - LLAssetType::AT_LINK, - new LLBoostFuncInventoryCallback( - boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,item_id,_1,LLTimer()))); - return true; - } - else - { - // create a base outfit link if appropriate. - LLViewerInventoryCategory *catp = gInventory.getCategory(item_id); - if (!catp) - { - llwarns << "link request failed, id not found as inventory item or category " << item_id << llendl; - return false; - } - const LLUUID cof = LLAppearanceMgr::instance().getCOF(); - std::string new_outfit_name = ""; - - LLAppearanceMgr::instance().purgeBaseOutfitLink(cof); - - if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) - { - if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate")) - { - LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << llendl; - return true; - } - LL_DEBUGS("Avatar") << "linking folder " << item_id << " name " << catp->getName() << " to cof " << cof << llendl; - link_inventory_item(gAgent.getID(), item_id, cof, catp->getName(), "", - LLAssetType::AT_LINK_FOLDER, - new LLBoostFuncInventoryCallback( - boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,item_id,_1,LLTimer()))); - new_outfit_name = catp->getName(); - request_sent = true; - } - - LLAppearanceMgr::instance().updatePanelOutfitName(new_outfit_name); - } - return request_sent; - } -}; - -LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering): +LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering, + bool enforce_item_restrictions): mFireCount(0), - mUpdateBaseOrder(update_base_outfit_ordering) + mUpdateBaseOrder(update_base_outfit_ordering), + mEnforceItemRestrictions(enforce_item_restrictions) { selfStartPhase("update_appearance_on_destroy"); } +void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item) +{ + LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(inv_item); + const std::string item_name = item ? item->getName() : "ITEM NOT FOUND"; +#ifndef LL_RELEASE_FOR_DOWNLOAD + LL_DEBUGS("Avatar") << self_av_string() << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << LL_ENDL; +#endif + mFireCount++; +} + LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy() { if (!LLApp::isExiting()) @@ -516,20 +449,39 @@ LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy() selfStopPhase("update_appearance_on_destroy"); - LLAppearanceMgr::instance().updateAppearanceFromCOF(mUpdateBaseOrder); + LLAppearanceMgr::instance().updateAppearanceFromCOF(mUpdateBaseOrder, mEnforceItemRestrictions); } } -void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item) +LLUpdateAppearanceAndEditWearableOnDestroy::LLUpdateAppearanceAndEditWearableOnDestroy(const LLUUID& item_id): + mItemID(item_id) { - LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(inv_item); - const std::string item_name = item ? item->getName() : "ITEM NOT FOUND"; -#ifndef LL_RELEASE_FOR_DOWNLOAD - LL_DEBUGS("Avatar") << self_av_string() << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << LL_ENDL; -#endif - mFireCount++; } +LLUpdateAppearanceAndEditWearableOnDestroy::~LLUpdateAppearanceAndEditWearableOnDestroy() +{ + if (!LLApp::isExiting()) + { + LLAppearanceMgr::instance().updateAppearanceFromCOF(); + + // Start editing the item if previously requested. + gAgentWearables.editWearableIfRequested(mItemID); + + // TODO: camera mode may not be changed if a debug setting is tweaked + if( gAgentCamera.cameraCustomizeAvatar() ) + { + // If we're in appearance editing mode, the current tab may need to be refreshed + LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>( + LLFloaterSidePanelContainer::getPanel("appearance")); + if (panel) + { + panel->showDefaultSubpart(); + } + } + } +} + + struct LLFoundData { LLFoundData() : @@ -1203,8 +1155,7 @@ const LLViewerInventoryItem* LLAppearanceMgr::getBaseOutfitLink() cat_array, item_array, false, - is_category, - false); + is_category); for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); iter != item_array.end(); iter++) @@ -1270,8 +1221,12 @@ void wear_on_avatar_cb(const LLUUID& inv_item, bool do_replace = false) } } -bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_update, bool replace, LLPointer<LLInventoryCallback> cb) +bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, + bool do_update, + bool replace, + LLPointer<LLInventoryCallback> cb) { + if (item_id_to_wear.isNull()) return false; // *TODO: issue with multi-wearable should be fixed: @@ -1310,15 +1265,22 @@ bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_up switch (item_to_wear->getType()) { case LLAssetType::AT_CLOTHING: - if (gAgentWearables.areWearablesLoaded()) + if (gAgentWearables.areWearablesLoaded()) { + if (!cb && do_update) + { + cb = new LLUpdateAppearanceAndEditWearableOnDestroy(item_id_to_wear); + } S32 wearable_count = gAgentWearables.getWearableCount(item_to_wear->getWearableType()); if ((replace && wearable_count != 0) || (wearable_count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) ) { - removeCOFItemLinks(gAgentWearables.getWearableItemID(item_to_wear->getWearableType(), wearable_count-1)); + LLUUID item_id = gAgentWearables.getWearableItemID(item_to_wear->getWearableType(), + wearable_count-1); + removeCOFItemLinks(item_id, cb); } - addCOFItemLink(item_to_wear, do_update, cb); + + addCOFItemLink(item_to_wear, cb); } break; case LLAssetType::AT_BODYPART: @@ -1327,8 +1289,11 @@ bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_up // Remove the existing wearables of the same type. // Remove existing body parts anyway because we must not be able to wear e.g. two skins. removeCOFLinksOfType(item_to_wear->getWearableType()); - - addCOFItemLink(item_to_wear, do_update, cb); + if (!cb && do_update) + { + cb = new LLUpdateAppearanceAndEditWearableOnDestroy(item_id_to_wear); + } + addCOFItemLink(item_to_wear, cb); break; case LLAssetType::AT_OBJECT: rez_attachment(item_to_wear, NULL, replace); @@ -1582,15 +1547,8 @@ bool LLAppearanceMgr::getCanRemoveOutfit(const LLUUID& outfit_cat_id) // static bool LLAppearanceMgr::getCanRemoveFromCOF(const LLUUID& outfit_cat_id) { - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; LLFindWearablesEx is_worn(/*is_worn=*/ true, /*include_body_parts=*/ false); - gInventory.collectDescendentsIf(outfit_cat_id, - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - is_worn); - return items.size() > 0; + return gInventory.hasMatchingDirectDescendent(outfit_cat_id, is_worn); } // static @@ -1601,15 +1559,8 @@ bool LLAppearanceMgr::getCanAddToCOF(const LLUUID& outfit_cat_id) return false; } - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false); - gInventory.collectDescendentsIf(outfit_cat_id, - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - not_worn); - return items.size() > 0; + return gInventory.hasMatchingDirectDescendent(outfit_cat_id, not_worn); } bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id) @@ -1627,18 +1578,11 @@ bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id) } // Check whether the outfit contains any wearables we aren't wearing already (STORM-702). - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; LLFindWearablesEx is_worn(/*is_worn=*/ false, /*include_body_parts=*/ true); - gInventory.collectDescendentsIf(outfit_cat_id, - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - is_worn); - return items.size() > 0; + return gInventory.hasMatchingDirectDescendent(outfit_cat_id, is_worn); } -void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category) +void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> cb) { LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; @@ -1649,18 +1593,16 @@ void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category) LLViewerInventoryItem *item = items.get(i); if (item->getActualType() != LLAssetType::AT_LINK_FOLDER) continue; - if (item->getIsLinkType()) + LLViewerInventoryCategory* catp = item->getLinkedCategory(); + if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) { - LLViewerInventoryCategory* catp = item->getLinkedCategory(); - if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) - { - gInventory.purgeObject(item->getUUID()); - } + remove_inventory_item(item->getUUID(), cb); } } } -void LLAppearanceMgr::purgeCategory(const LLUUID& category, bool keep_outfit_links, LLInventoryModel::item_array_t* keep_items) +void LLAppearanceMgr::removeCategoryContents(const LLUUID& category, bool keep_outfit_links, + LLPointer<LLInventoryCallback> cb) { LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; @@ -1673,19 +1615,8 @@ void LLAppearanceMgr::purgeCategory(const LLUUID& category, bool keep_outfit_lin continue; if (item->getIsLinkType()) { -#if 0 - if (keep_items && keep_items->find(item) != LLInventoryModel::item_array_t::FAIL) - { - llinfos << "preserved item" << llendl; - } - else - { - gInventory.purgeObject(item->getUUID()); - } -#else - gInventory.purgeObject(item->getUUID()); + remove_inventory_item(item->getUUID(), cb); } -#endif } } @@ -1737,6 +1668,18 @@ void LLAppearanceMgr::linkAll(const LLUUID& cat_uuid, } } +void LLAppearanceMgr::removeAll(LLInventoryModel::item_array_t& items_to_kill, + LLPointer<LLInventoryCallback> cb) +{ + for (LLInventoryModel::item_array_t::iterator it = items_to_kill.begin(); + it != items_to_kill.end(); + ++it) + { + LLViewerInventoryItem *item = *it; + remove_inventory_item(item->getUUID(), cb); + } +} + void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) { LLViewerInventoryCategory *pcat = gInventory.getCategory(category); @@ -1748,7 +1691,7 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) if (!append) { LLInventoryModel::item_array_t gest_items; - getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE, false); + getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE); for(S32 i = 0; i < gest_items.count(); ++i) { LLViewerInventoryItem *gest_item = gest_items.get(i); @@ -1765,8 +1708,8 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) // required parts are missing. // Preserve body parts from COF if appending. LLInventoryModel::item_array_t body_items; - getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART, false); - getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART, false); + getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART); + getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART); if (append) reverse(body_items.begin(), body_items.end()); // Reduce body items to max of one per type. @@ -1776,8 +1719,8 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) // - Wearables: include COF contents only if appending. LLInventoryModel::item_array_t wear_items; if (append) - getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING, false); - getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING, false); + getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING); + getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING); // Reduce wearables to max of one per type. removeDuplicateItems(wear_items); filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_PER_TYPE); @@ -1785,15 +1728,15 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) // - Attachments: include COF contents only if appending. LLInventoryModel::item_array_t obj_items; if (append) - getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT, false); - getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT, false); + getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT); + getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT); removeDuplicateItems(obj_items); // - Gestures: include COF contents only if appending. LLInventoryModel::item_array_t gest_items; if (append) - getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE, false); - getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE, false); + getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE); + getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE); removeDuplicateItems(gest_items); // Create links to new COF contents. @@ -1818,8 +1761,7 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) // carried over (e.g. keeping old shape if the new outfit does not // contain one) bool keep_outfit_links = append; - purgeCategory(cof, keep_outfit_links, &all_items); - gInventory.notifyObservers(); + removeCategoryContents(cof, keep_outfit_links, link_waiter); LL_DEBUGS("Avatar") << self_av_string() << "waiting for LLUpdateAppearanceOnDestroy" << LL_ENDL; } @@ -1840,7 +1782,7 @@ void LLAppearanceMgr::createBaseOutfitLink(const LLUUID& category, LLPointer<LLI LLViewerInventoryCategory* catp = gInventory.getCategory(category); std::string new_outfit_name = ""; - purgeBaseOutfitLink(cof); + purgeBaseOutfitLink(cof, link_waiter); if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) { @@ -1937,7 +1879,7 @@ S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id, S32 to_kill_count = 0; LLInventoryModel::item_array_t items; - getDescendentsOfAssetType(cat_id, items, type, false); + getDescendentsOfAssetType(cat_id, items, type); LLInventoryModel::item_array_t curr_items = items; removeDuplicateItems(items); if (max_items > 0) @@ -1956,34 +1898,20 @@ S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id, return to_kill_count; } - -void LLAppearanceMgr::enforceItemRestrictions() -{ - S32 purge_count = 0; - LLInventoryModel::item_array_t items_to_kill; - - purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_BODYPART, - 1, items_to_kill); - purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_CLOTHING, - LLAgentWearables::MAX_CLOTHING_PER_TYPE, items_to_kill); - purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_OBJECT, - -1, items_to_kill); - if (items_to_kill.size()>0) - { - for (LLInventoryModel::item_array_t::iterator it = items_to_kill.begin(); - it != items_to_kill.end(); - ++it) - { - LLViewerInventoryItem *item = *it; - LL_DEBUGS("Avatar") << self_av_string() << "purging duplicate or excess item " << item->getName() << LL_ENDL; - gInventory.purgeObject(item->getUUID()); - } - gInventory.notifyObservers(); - } +void LLAppearanceMgr::findAllExcessOrDuplicateItems(const LLUUID& cat_id, + LLInventoryModel::item_array_t& items_to_kill) +{ + findExcessOrDuplicateItems(cat_id,LLAssetType::AT_BODYPART, + 1, items_to_kill); + findExcessOrDuplicateItems(cat_id,LLAssetType::AT_CLOTHING, + LLAgentWearables::MAX_CLOTHING_PER_TYPE, items_to_kill); + findExcessOrDuplicateItems(cat_id,LLAssetType::AT_OBJECT, + -1, items_to_kill); } -void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) +void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering, + bool enforce_item_restrictions) { if (mIsInUpdateAppearanceFromCOF) { @@ -1996,14 +1924,31 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) LL_DEBUGS("Avatar") << self_av_string() << "starting" << LL_ENDL; + if (enforce_item_restrictions) + { + LLInventoryModel::item_array_t items_to_kill; + findAllExcessOrDuplicateItems(getCOF(), items_to_kill); + if (items_to_kill.size()>0) + { + // The point here is just to call + // updateAppearanceFromCOF() again after excess items + // have been removed. That time we will set + // enforce_item_restrictions to false so we don't get + // caught in a perpetual loop. + LLPointer<LLInventoryCallback> cb( + new LLUpdateAppearanceOnDestroy(update_base_outfit_ordering, false)); + + // Remove duplicate or excess wearables. Should normally be enforced at the UI level, but + // this should catch anything that gets through. + removeAll(items_to_kill, cb); + return; + } + } + //checking integrity of the COF in terms of ordering of wearables, //checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state) updateClothingOrderingInfo(LLUUID::null, update_base_outfit_ordering); - // Remove duplicate or excess wearables. Should normally be enforced at the UI level, but - // this should catch anything that gets through. - enforceItemRestrictions(); - // update dirty flag to see if the state of the COF matches // the saved outfit stored as a folder link updateIsDirty(); @@ -2019,7 +1964,6 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) //dumpCat(getCOF(),"COF, start"); - bool follow_folder_links = false; LLUUID current_outfit_id = getCOF(); // Find all the wearables that are in the COF's subtree. @@ -2027,7 +1971,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) LLInventoryModel::item_array_t wear_items; LLInventoryModel::item_array_t obj_items; LLInventoryModel::item_array_t gest_items; - getUserDescendents(current_outfit_id, wear_items, obj_items, gest_items, follow_folder_links); + getUserDescendents(current_outfit_id, wear_items, obj_items, gest_items); // Get rid of non-links in case somehow the COF was corrupted. remove_non_link_items(wear_items); remove_non_link_items(obj_items); @@ -2123,8 +2067,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) void LLAppearanceMgr::getDescendentsOfAssetType(const LLUUID& category, LLInventoryModel::item_array_t& items, - LLAssetType::EType type, - bool follow_folder_links) + LLAssetType::EType type) { LLInventoryModel::cat_array_t cats; LLIsType is_of_type(type); @@ -2132,15 +2075,13 @@ void LLAppearanceMgr::getDescendentsOfAssetType(const LLUUID& category, cats, items, LLInventoryModel::EXCLUDE_TRASH, - is_of_type, - follow_folder_links); + is_of_type); } void LLAppearanceMgr::getUserDescendents(const LLUUID& category, LLInventoryModel::item_array_t& wear_items, LLInventoryModel::item_array_t& obj_items, - LLInventoryModel::item_array_t& gest_items, - bool follow_folder_links) + LLInventoryModel::item_array_t& gest_items) { LLInventoryModel::cat_array_t wear_cats; LLFindWearables is_wearable; @@ -2148,8 +2089,7 @@ void LLAppearanceMgr::getUserDescendents(const LLUUID& category, wear_cats, wear_items, LLInventoryModel::EXCLUDE_TRASH, - is_wearable, - follow_folder_links); + is_wearable); LLInventoryModel::cat_array_t obj_cats; LLIsType is_object( LLAssetType::AT_OBJECT ); @@ -2157,8 +2097,7 @@ void LLAppearanceMgr::getUserDescendents(const LLUUID& category, obj_cats, obj_items, LLInventoryModel::EXCLUDE_TRASH, - is_object, - follow_folder_links); + is_object); // Find all gestures in this folder LLInventoryModel::cat_array_t gest_cats; @@ -2167,8 +2106,7 @@ void LLAppearanceMgr::getUserDescendents(const LLUUID& category, gest_cats, gest_items, LLInventoryModel::EXCLUDE_TRASH, - is_gesture, - follow_folder_links); + is_gesture); } void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append) @@ -2287,6 +2225,7 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append); } +// FIXME do we really want to search entire inventory for matching name? void LLAppearanceMgr::wearOutfitByName(const std::string& name) { LL_INFOS("Avatar") << self_av_string() << "Wearing category " << name << LL_ENDL; @@ -2340,9 +2279,8 @@ bool areMatchingWearables(const LLViewerInventoryItem *a, const LLViewerInventor class LLDeferredCOFLinkObserver: public LLInventoryObserver { public: - LLDeferredCOFLinkObserver(const LLUUID& item_id, bool do_update, LLPointer<LLInventoryCallback> cb = NULL, std::string description = ""): + LLDeferredCOFLinkObserver(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb, const std::string& description): mItemID(item_id), - mDoUpdate(do_update), mCallback(cb), mDescription(description) { @@ -2358,14 +2296,13 @@ public: if (item) { gInventory.removeObserver(this); - LLAppearanceMgr::instance().addCOFItemLink(item,mDoUpdate,mCallback); + LLAppearanceMgr::instance().addCOFItemLink(item, mCallback, mDescription); delete this; } } private: const LLUUID mItemID; - bool mDoUpdate; std::string mDescription; LLPointer<LLInventoryCallback> mCallback; }; @@ -2373,42 +2310,26 @@ private: // BAP - note that this runs asynchronously if the item is not already loaded from inventory. // Dangerous if caller assumes link will exist after calling the function. -void LLAppearanceMgr::addCOFItemLink(const LLUUID &item_id, bool do_update, LLPointer<LLInventoryCallback> cb, const std::string description) +void LLAppearanceMgr::addCOFItemLink(const LLUUID &item_id, + LLPointer<LLInventoryCallback> cb, + const std::string description) { const LLInventoryItem *item = gInventory.getItem(item_id); if (!item) { - LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, do_update, cb, description); + LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, cb, description); gInventory.addObserver(observer); } else { - addCOFItemLink(item, do_update, cb, description); - } -} - -void modified_cof_cb(const LLUUID& inv_item) -{ - LLAppearanceMgr::instance().updateAppearanceFromCOF(); - - // Start editing the item if previously requested. - gAgentWearables.editWearableIfRequested(inv_item); - - // TODO: camera mode may not be changed if a debug setting is tweaked - if( gAgentCamera.cameraCustomizeAvatar() ) - { - // If we're in appearance editing mode, the current tab may need to be refreshed - LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(LLFloaterSidePanelContainer::getPanel("appearance")); - if (panel) - { - panel->showDefaultSubpart(); - } + addCOFItemLink(item, cb, description); } } -void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update, LLPointer<LLInventoryCallback> cb, const std::string description) +void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, + LLPointer<LLInventoryCallback> cb, + const std::string description) { - std::string link_description = description; const LLViewerInventoryItem *vitem = dynamic_cast<const LLViewerInventoryItem*>(item); if (!vitem) { @@ -2448,30 +2369,19 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update ++count; if (is_body_part && inv_item->getIsLinkType() && (vitem->getWearableType() == wearable_type)) { - gInventory.purgeObject(inv_item->getUUID()); + remove_inventory_item(inv_item->getUUID(), cb); } else if (count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) { // MULTI-WEARABLES: make sure we don't go over MAX_CLOTHING_PER_TYPE - gInventory.purgeObject(inv_item->getUUID()); + remove_inventory_item(inv_item->getUUID(), cb); } } } - if (linked_already) + if (!linked_already) { - if (do_update) - { - LLAppearanceMgr::updateAppearanceFromCOF(); - } - return; - } - else - { - if(do_update && cb.isNull()) - { - cb = new LLBoostFuncInventoryCallback(modified_cof_cb); - } + std::string link_description = description; if (vitem->getIsLinkType()) { link_description = vitem->getActualDescription(); @@ -2484,7 +2394,6 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update LLAssetType::AT_LINK, cb); } - return; } LLInventoryModel::item_array_t LLAppearanceMgr::findCOFItemLinks(const LLUUID& item_id) @@ -2524,8 +2433,7 @@ void LLAppearanceMgr::removeAllClothesFromAvatar() dummy, clothing_items, LLInventoryModel::EXCLUDE_TRASH, - is_clothing, - false); + is_clothing); uuid_vec_t item_ids; for (LLInventoryModel::item_array_t::iterator it = clothing_items.begin(); it != clothing_items.end(); ++it) @@ -2569,7 +2477,7 @@ void LLAppearanceMgr::removeAllAttachmentsFromAvatar() removeItemsFromAvatar(ids_to_remove); } -void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id) +void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb) { gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); @@ -2584,12 +2492,12 @@ void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id) const LLInventoryItem* item = item_array.get(i).get(); if (item->getIsLinkType() && item->getLinkedUUID() == item_id) { - gInventory.purgeObject(item->getUUID()); + remove_inventory_item(item->getUUID(), cb); } } } -void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type) +void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type, LLPointer<LLInventoryCallback> cb) { LLFindWearablesOfType filter_wearables_of_type(type); LLInventoryModel::cat_array_t cats; @@ -2602,7 +2510,7 @@ void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type) const LLViewerInventoryItem* item = *it; if (item->getIsLinkType()) // we must operate on links only { - gInventory.purgeObject(item->getUUID()); + remove_inventory_item(item->getUUID(), cb); } } } @@ -2823,7 +2731,7 @@ bool LLAppearanceMgr::updateBaseOutfit() updateClothingOrderingInfo(); // in a Base Outfit we do not remove items, only links - purgeCategory(base_outfit_id, false); + removeCategoryContents(base_outfit_id, false, NULL); LLPointer<LLInventoryCallback> dirty_state_updater = new LLBoostFuncInventoryCallback(no_op_inventory_func, appearance_mgr_update_dirty_state); @@ -2920,7 +2828,7 @@ void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, bool update_base // COF is processed if cat_id is not specified LLInventoryModel::item_array_t wear_items; - getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING, false); + getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING); wearables_by_type_t items_by_type(LLWearableType::WT_COUNT); divvyWearablesByType(wear_items, items_by_type); @@ -2957,62 +2865,9 @@ void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, bool update_base if (inventory_changed) gInventory.notifyObservers(); } -// This is intended for use with HTTP Clients/Responders, but is not -// specifically coupled with those classes. -class LLHTTPRetryPolicy: public LLThreadSafeRefCount -{ -public: - LLHTTPRetryPolicy() {} - virtual ~LLHTTPRetryPolicy() {} - virtual bool shouldRetry(U32 status, F32& seconds_to_wait) = 0; -}; - -// Example of simplest possible policy, not necessarily recommended. -class LLAlwaysRetryImmediatelyPolicy: public LLHTTPRetryPolicy -{ -public: - LLAlwaysRetryImmediatelyPolicy() {} - bool shouldRetry(U32 status, F32& seconds_to_wait) - { - seconds_to_wait = 0.0; - return true; - } -}; - -// Very general policy with geometric back-off after failures, -// up to a maximum delay, and maximum number of retries. -class LLAdaptiveRetryPolicy: public LLHTTPRetryPolicy -{ -public: - LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries): - mMinDelay(min_delay), - mMaxDelay(max_delay), - mBackoffFactor(backoff_factor), - mMaxRetries(max_retries), - mDelay(min_delay), - mRetryCount(0) - { - } - - bool shouldRetry(U32 status, F32& seconds_to_wait) - { - seconds_to_wait = mDelay; - mDelay = llclamp(mDelay*mBackoffFactor,mMinDelay,mMaxDelay); - mRetryCount++; - return (mRetryCount<=mMaxRetries); - } - -private: - F32 mMinDelay; // delay never less than this value - F32 mMaxDelay; // delay never exceeds this value - F32 mBackoffFactor; // delay increases by this factor after each retry, up to mMaxDelay. - U32 mMaxRetries; // maximum number of times shouldRetry will return true. - F32 mDelay; // current delay. - U32 mRetryCount; // number of times shouldRetry has been called. -}; - class RequestAgentUpdateAppearanceResponder: public LLHTTPClient::Responder { + LOG_CLASS(RequestAgentUpdateAppearanceResponder); public: RequestAgentUpdateAppearanceResponder() { @@ -3023,13 +2878,19 @@ public: { } +protected: // Successful completion. - /* virtual */ void result(const LLSD& content) + /* virtual */ void httpSuccess() { - LL_DEBUGS("Avatar") << "content: " << ll_pretty_print_sd(content) << LL_ENDL; + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } if (content["success"].asBoolean()) { - LL_DEBUGS("Avatar") << "OK" << LL_ENDL; + //LL_DEBUGS("Avatar") << dumpResponse() << LL_ENDL; if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) { dumpContents(gAgentAvatarp->getFullname() + "_appearance_request_ok", content); @@ -3037,33 +2898,37 @@ public: } else { - onFailure(200); + failureResult(HTTP_INTERNAL_ERROR, "Non-success response", content); } } // Error - /*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content) + /*virtual*/ void httpFailure() { - llwarns << "appearance update request failed, status: " << status << " reason: " << reason << " code: " << content["code"].asInteger() << " error: \"" << content["error"].asString() << "\"" << llendl; + const LLSD& content = getContent(); + LL_WARNS("Avatar") << "appearance update request failed " + << dumpResponse() << LL_ENDL; + if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) { dumpContents(gAgentAvatarp->getFullname() + "_appearance_request_error", content); debugCOF(content); } - onFailure(status); - } + onFailure(); + } - void onFailure(U32 status) + void onFailure() { F32 seconds_to_wait; - if (mRetryPolicy->shouldRetry(status,seconds_to_wait)) + mRetryPolicy->onFailure(getStatus(), getResponseHeaders()); + if (mRetryPolicy->shouldRetry(seconds_to_wait)) { llinfos << "retrying" << llendl; doAfterInterval(boost::bind(&LLAppearanceMgr::requestServerAppearanceUpdate, LLAppearanceMgr::getInstance(), - LLCurl::ResponderPtr(this)), - seconds_to_wait); + LLHTTPClient::ResponderPtr(this)), + seconds_to_wait); } else { @@ -3254,7 +3119,6 @@ void LLAppearanceMgr::requestServerAppearanceUpdate(LLCurl::ResponderPtr respond } LL_DEBUGS("Avatar") << "request url " << url << " my_cof_version " << cof_version << llendl; - //LLCurl::ResponderPtr responder_ptr; if (!responder_ptr.get()) { responder_ptr = new RequestAgentUpdateAppearanceResponder; @@ -3266,6 +3130,7 @@ void LLAppearanceMgr::requestServerAppearanceUpdate(LLCurl::ResponderPtr respond class LLIncrementCofVersionResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLIncrementCofVersionResponder); public: LLIncrementCofVersionResponder() : LLHTTPClient::Responder() { @@ -3276,22 +3141,31 @@ public: { } - virtual void result(const LLSD &pContent) +protected: + virtual void httpSuccess() { llinfos << "Successfully incremented agent's COF." << llendl; - S32 new_version = pContent["category"]["version"].asInteger(); + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } + S32 new_version = content["category"]["version"].asInteger(); // cof_version should have increased llassert(new_version > gAgentAvatarp->mLastUpdateRequestCOFVersion); gAgentAvatarp->mLastUpdateRequestCOFVersion = new_version; } - virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& content) + + virtual void httpFailure() { - llwarns << "While attempting to increment the agent's cof we got an error with [status:" - << pStatus << "]: " << content << llendl; + LL_WARNS("Avatar") << "While attempting to increment the agent's cof we got an error " + << dumpResponse() << LL_ENDL; F32 seconds_to_wait; - if (mRetryPolicy->shouldRetry(pStatus,seconds_to_wait)) + mRetryPolicy->onFailure(getStatus(), getResponseHeaders()); + if (mRetryPolicy->shouldRetry(seconds_to_wait)) { llinfos << "retrying" << llendl; doAfterInterval(boost::bind(&LLAppearanceMgr::incrementCofVersion, @@ -3305,6 +3179,7 @@ public: } } +private: LLPointer<LLHTTPRetryPolicy> mRetryPolicy; }; @@ -3373,6 +3248,13 @@ void show_created_outfit(LLUUID& folder_id, bool show_panel = true) LLAppearanceMgr::getInstance()->updateIsDirty(); gAgentWearables.notifyLoadingFinished(); // New outfit is saved. LLAppearanceMgr::getInstance()->updatePanelOutfitName(""); + + // For SSB, need to update appearance after we add a base outfit + // link, since, the COF version has changed. There is a race + // condition in initial outfit setup which can lead to rez + // failures - SH-3860. + LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; + LLAppearanceMgr::getInstance()->createBaseOutfitLink(folder_id, cb); } LLUUID LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, bool show_panel) @@ -3393,7 +3275,6 @@ LLUUID LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, b LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(no_op_inventory_func, boost::bind(show_created_outfit,folder_id,show_panel)); shallowCopyCategoryContents(getCOF(),folder_id, cb); - createBaseOutfitLink(folder_id, cb); dumpCat(folder_id,"COF, new outfit"); @@ -3413,21 +3294,22 @@ void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove) if (ids_to_remove.empty()) { llwarns << "called with empty list, nothing to do" << llendl; + return; } + LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it) { const LLUUID& id_to_remove = *it; const LLUUID& linked_item_id = gInventory.getLinkedItemID(id_to_remove); - removeCOFItemLinks(linked_item_id); + removeCOFItemLinks(linked_item_id, cb); } - updateAppearanceFromCOF(); } void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove) { LLUUID linked_item_id = gInventory.getLinkedItemID(id_to_remove); - removeCOFItemLinks(linked_item_id); - updateAppearanceFromCOF(); + LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; + removeCOFItemLinks(linked_item_id, cb); } bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_body) @@ -3586,7 +3468,7 @@ void LLAppearanceMgr::registerAttachment(const LLUUID& item_id) // we have to pass do_update = true to call LLAppearanceMgr::updateAppearanceFromCOF. // it will trigger gAgentWariables.notifyLoadingFinished() // But it is not acceptable solution. See EXT-7777 - LLAppearanceMgr::addCOFItemLink(item_id, false); // Add COF link for item. + LLAppearanceMgr::addCOFItemLink(item_id); // Add COF link for item. } else { @@ -3610,22 +3492,21 @@ void LLAppearanceMgr::unregisterAttachment(const LLUUID& item_id) BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const { - return gInventory.isObjectDescendentOf(obj_id, getCOF()); + const LLUUID& cof = getCOF(); + if (obj_id == cof) + return TRUE; + const LLInventoryObject* obj = gInventory.getObject(obj_id); + if (obj && obj->getParentUUID() == cof) + return TRUE; + return FALSE; } // static bool LLAppearanceMgr::isLinkInCOF(const LLUUID& obj_id) { - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLLinkedItemIDMatches find_links(gInventory.getLinkedItemID(obj_id)); - gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - find_links); - - return !items.empty(); + const LLUUID& target_id = gInventory.getLinkedItemID(obj_id); + LLLinkedItemIDMatches find_links(target_id); + return gInventory.hasMatchingDirectDescendent(LLAppearanceMgr::instance().getCOF(), find_links); } BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const @@ -3642,18 +3523,6 @@ BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const // For now, don't allow direct deletion from the COF. Instead, force users // to choose "Detach" or "Take Off". return TRUE; - /* - const LLInventoryObject *obj = gInventory.getObject(obj_id); - if (!obj) return FALSE; - - // Can't delete bodyparts, since this would be equivalent to removing the item. - if (obj->getType() == LLAssetType::AT_BODYPART) return TRUE; - - // Can't delete the folder link, since this is saved for bookkeeping. - if (obj->getActualType() == LLAssetType::AT_LINK_FOLDER) return TRUE; - - return FALSE; - */ } class CallAfterCategoryFetchStage2: public LLInventoryFetchItemsObserver diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index 46252afbde..2cc76c4b4c 100755 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -49,7 +49,8 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr> public: typedef std::vector<LLInventoryModel::item_array_t> wearables_by_type_t; - void updateAppearanceFromCOF(bool update_base_outfit_ordering = false); + void updateAppearanceFromCOF(bool update_base_outfit_ordering = false, + bool enforce_item_restrictions = true); bool needToSaveCOF(); void updateCOF(const LLUUID& category, bool append = false); void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append); @@ -65,7 +66,8 @@ public: LLAssetType::EType type, S32 max_items, LLInventoryModel::item_array_t& items_to_kill); - void enforceItemRestrictions(); + void findAllExcessOrDuplicateItems(const LLUUID& cat_id, + LLInventoryModel::item_array_t& items_to_kill); // Copy all items and the src category itself. void shallowCopyCategory(const LLUUID& src_id, const LLUUID& dst_id, @@ -105,12 +107,13 @@ public: const LLUUID getBaseOutfitUUID(); // Wear/attach an item (from a user's inventory) on the agent - bool wearItemOnAvatar(const LLUUID& item_to_wear, bool do_update = true, bool replace = false, LLPointer<LLInventoryCallback> cb = NULL); + bool wearItemOnAvatar(const LLUUID& item_to_wear, bool do_update, bool replace = false, + LLPointer<LLInventoryCallback> cb = NULL); // Update the displayed outfit name in UI. void updatePanelOutfitName(const std::string& name); - void purgeBaseOutfitLink(const LLUUID& category); + void purgeBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> cb = NULL); void createBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> link_waiter); void updateAgentWearables(LLWearableHoldingPattern* holder, bool append); @@ -129,16 +132,20 @@ public: LLInventoryModel::item_array_t& items, LLPointer<LLInventoryCallback> cb); + // And bulk removal. + void removeAll(LLInventoryModel::item_array_t& items, + LLPointer<LLInventoryCallback> cb); + // Add COF link to individual item. - void addCOFItemLink(const LLUUID& item_id, bool do_update = true, LLPointer<LLInventoryCallback> cb = NULL, const std::string description = ""); - void addCOFItemLink(const LLInventoryItem *item, bool do_update = true, LLPointer<LLInventoryCallback> cb = NULL, const std::string description = ""); + void addCOFItemLink(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb = NULL, const std::string description = ""); + void addCOFItemLink(const LLInventoryItem *item, LLPointer<LLInventoryCallback> cb = NULL, const std::string description = ""); // Find COF entries referencing the given item. LLInventoryModel::item_array_t findCOFItemLinks(const LLUUID& item_id); // Remove COF entries - void removeCOFItemLinks(const LLUUID& item_id); - void removeCOFLinksOfType(LLWearableType::EType type); + void removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb = NULL); + void removeCOFLinksOfType(LLWearableType::EType type, LLPointer<LLInventoryCallback> cb = NULL); void removeAllClothesFromAvatar(); void removeAllAttachmentsFromAvatar(); @@ -213,16 +220,15 @@ private: void getDescendentsOfAssetType(const LLUUID& category, LLInventoryModel::item_array_t& items, - LLAssetType::EType type, - bool follow_folder_links); + LLAssetType::EType type); void getUserDescendents(const LLUUID& category, LLInventoryModel::item_array_t& wear_items, LLInventoryModel::item_array_t& obj_items, - LLInventoryModel::item_array_t& gest_items, - bool follow_folder_links); + LLInventoryModel::item_array_t& gest_items); - void purgeCategory(const LLUUID& category, bool keep_outfit_links, LLInventoryModel::item_array_t* keep_items = NULL); + void removeCategoryContents(const LLUUID& category, bool keep_outfit_links, + LLPointer<LLInventoryCallback> cb); static void onOutfitRename(const LLSD& notification, const LLSD& response); void setOutfitLocked(bool locked); @@ -256,15 +262,31 @@ public: class LLUpdateAppearanceOnDestroy: public LLInventoryCallback { public: - LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering = false); + LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering = false, + bool enforce_item_restrictions = true); virtual ~LLUpdateAppearanceOnDestroy(); /* virtual */ void fire(const LLUUID& inv_item); private: U32 mFireCount; bool mUpdateBaseOrder; + bool mEnforceItemRestrictions; +}; + +class LLUpdateAppearanceAndEditWearableOnDestroy: public LLInventoryCallback +{ +public: + LLUpdateAppearanceAndEditWearableOnDestroy(const LLUUID& item_id); + + /* virtual */ void fire(const LLUUID& item_id) {} + + ~LLUpdateAppearanceAndEditWearableOnDestroy(); + +private: + LLUUID mItemID; }; +class #define SUPPORT_ENSEMBLES 0 diff --git a/indra/newview/llassetuploadqueue.cpp b/indra/newview/llassetuploadqueue.cpp index 4bdb690225..cde9bc9dc0 100644 --- a/indra/newview/llassetuploadqueue.cpp +++ b/indra/newview/llassetuploadqueue.cpp @@ -36,6 +36,7 @@ class LLAssetUploadChainResponder : public LLUpdateTaskInventoryResponder { + LOG_CLASS(LLAssetUploadChainResponder); public: LLAssetUploadChainResponder(const LLSD& post_data, @@ -51,52 +52,54 @@ public: mDataSize(data_size), mScriptName(script_name) { - } + } virtual ~LLAssetUploadChainResponder() - { - if(mSupplier) - { - LLAssetUploadQueue *queue = mSupplier->get(); - if (queue) - { - // Give ownership of supplier back to queue. - queue->mSupplier = mSupplier; - mSupplier = NULL; - } - } - delete mSupplier; + { + if(mSupplier) + { + LLAssetUploadQueue *queue = mSupplier->get(); + if (queue) + { + // Give ownership of supplier back to queue. + queue->mSupplier = mSupplier; + mSupplier = NULL; + } + } + delete mSupplier; delete mData; - } + } - virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) - { - llwarns << "LLAssetUploadChainResponder Error [status:" - << statusNum << "]: " << content << llendl; - LLUpdateTaskInventoryResponder::errorWithContent(statusNum, reason, content); - LLAssetUploadQueue *queue = mSupplier->get(); - if (queue) +protected: + virtual void httpFailure() + { + // Parent class will spam the failure. + //llwarns << dumpResponse() << llendl; + LLUpdateTaskInventoryResponder::httpFailure(); + LLAssetUploadQueue *queue = mSupplier->get(); + if (queue) + { + queue->request(&mSupplier); + } + } + + virtual void httpSuccess() + { + LLUpdateTaskInventoryResponder::httpSuccess(); + LLAssetUploadQueue *queue = mSupplier->get(); + if (queue) { - queue->request(&mSupplier); - } - } - - virtual void result(const LLSD& content) - { - LLUpdateTaskInventoryResponder::result(content); - LLAssetUploadQueue *queue = mSupplier->get(); - if (queue) - { - // Responder is reused across 2 phase upload, - // so only start next upload after 2nd phase complete. - std::string state = content["state"]; - if(state == "complete") - { - queue->request(&mSupplier); - } - } - } + // Responder is reused across 2 phase upload, + // so only start next upload after 2nd phase complete. + const std::string& state = getContent()["state"].asStringRef(); + if(state == "complete") + { + queue->request(&mSupplier); + } + } + } +public: virtual void uploadUpload(const LLSD& content) { std::string uploader = content["uploader"]; diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index 2564802387..ea511b18e2 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -225,37 +225,41 @@ LLAssetUploadResponder::~LLAssetUploadResponder() } // virtual -void LLAssetUploadResponder::errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +void LLAssetUploadResponder::httpFailure() { - llinfos << "LLAssetUploadResponder::error [status:" - << statusNum << "]: " << content << llendl; + // *TODO: Add adaptive retry policy? + llwarns << dumpResponse() << llendl; LLSD args; - switch(statusNum) + if (isHttpClientErrorStatus(getStatus())) { - case 400: - args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); - args["REASON"] = "Error in upload request. Please visit " - "http://secondlife.com/support for help fixing this problem."; - LLNotificationsUtil::add("CannotUploadReason", args); - break; - case 500: - default: - args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); - args["REASON"] = "The server is experiencing unexpected " - "difficulties."; - LLNotificationsUtil::add("CannotUploadReason", args); - break; + args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); + args["REASON"] = "Error in upload request. Please visit " + "http://secondlife.com/support for help fixing this problem."; + LLNotificationsUtil::add("CannotUploadReason", args); + } + else + { + args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); + args["REASON"] = "The server is experiencing unexpected " + "difficulties."; + LLNotificationsUtil::add("CannotUploadReason", args); } LLUploadDialog::modalUploadFinished(); LLFilePicker::instance().reset(); // unlock file picker when bulk upload fails } //virtual -void LLAssetUploadResponder::result(const LLSD& content) +void LLAssetUploadResponder::httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } lldebugs << "LLAssetUploadResponder::result from capabilities" << llendl; - std::string state = content["state"]; + const std::string& state = content["state"].asStringRef(); if (state == "upload") { @@ -280,7 +284,7 @@ void LLAssetUploadResponder::result(const LLSD& content) void LLAssetUploadResponder::uploadUpload(const LLSD& content) { - std::string uploader = content["uploader"]; + const std::string& uploader = content["uploader"].asStringRef(); if (mFileName.empty()) { LLHTTPClient::postFile(uploader, mVFileID, mAssetType, this); @@ -293,6 +297,7 @@ void LLAssetUploadResponder::uploadUpload(const LLSD& content) void LLAssetUploadResponder::uploadFailure(const LLSD& content) { + llwarns << dumpResponse() << llendl; // remove the "Uploading..." message LLUploadDialog::modalUploadFinished(); LLFloater* floater_snapshot = LLFloaterReg::findInstance("snapshot"); @@ -301,7 +306,7 @@ void LLAssetUploadResponder::uploadFailure(const LLSD& content) floater_snapshot->notify(LLSD().with("set-finished", LLSD().with("ok", false).with("msg", "inventory"))); } - std::string reason = content["state"]; + const std::string& reason = content["state"].asStringRef(); // deal with L$ errors if (reason == "insufficient funds") { @@ -340,9 +345,9 @@ LLNewAgentInventoryResponder::LLNewAgentInventoryResponder( } // virtual -void LLNewAgentInventoryResponder::errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +void LLNewAgentInventoryResponder::httpFailure() { - LLAssetUploadResponder::errorWithContent(statusNum, reason, content); + LLAssetUploadResponder::httpFailure(); //LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, LLUUID(), FALSE); } @@ -487,10 +492,9 @@ void LLSendTexLayerResponder::uploadComplete(const LLSD& content) } } -void LLSendTexLayerResponder::errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +void LLSendTexLayerResponder::httpFailure() { - llinfos << "LLSendTexLayerResponder error [status:" - << statusNum << "]: " << content << llendl; + llwarns << dumpResponse() << llendl; // Invoke the original callback with an error result LLViewerTexLayerSetBuffer::onTextureUploadComplete(LLUUID(), (void*) mBakedUploadData, -1, LL_EXSTAT_NONE); @@ -1009,19 +1013,14 @@ LLNewAgentInventoryVariablePriceResponder::~LLNewAgentInventoryVariablePriceResp delete mImpl; } -void LLNewAgentInventoryVariablePriceResponder::errorWithContent( - U32 statusNum, - const std::string& reason, - const LLSD& content) +void LLNewAgentInventoryVariablePriceResponder::httpFailure() { - lldebugs - << "LLNewAgentInventoryVariablePrice::error " << statusNum - << " reason: " << reason << llendl; + const LLSD& content = getContent(); + LL_WARNS("Upload") << dumpResponse() << LL_ENDL; - if ( content.has("error") ) + static const std::string _ERROR = "error"; + if ( content.has(_ERROR) ) { - static const std::string _ERROR = "error"; - mImpl->onTransportError(content[_ERROR]); } else @@ -1030,8 +1029,14 @@ void LLNewAgentInventoryVariablePriceResponder::errorWithContent( } } -void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content) +void LLNewAgentInventoryVariablePriceResponder::httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } // Parse out application level errors and the appropriate // responses for them static const std::string _ERROR = "error"; @@ -1047,6 +1052,7 @@ void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content) // Check for application level errors if ( content.has(_ERROR) ) { + LL_WARNS("Upload") << dumpResponse() << LL_ENDL; onApplicationLevelError(content[_ERROR]); return; } @@ -1090,6 +1096,7 @@ void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content) } else { + LL_WARNS("Upload") << dumpResponse() << LL_ENDL; onApplicationLevelError(""); } } diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h index a6d1016136..abfdc4ca77 100644 --- a/indra/newview/llassetuploadresponders.h +++ b/indra/newview/llassetuploadresponders.h @@ -33,6 +33,8 @@ // via capabilities class LLAssetUploadResponder : public LLHTTPClient::Responder { +protected: + LOG_CLASS(LLAssetUploadResponder); public: LLAssetUploadResponder(const LLSD& post_data, const LLUUID& vfile_id, @@ -42,8 +44,11 @@ public: LLAssetType::EType asset_type); ~LLAssetUploadResponder(); - virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content); - virtual void result(const LLSD& content); +protected: + virtual void httpFailure(); + virtual void httpSuccess(); + +public: virtual void uploadUpload(const LLSD& content); virtual void uploadComplete(const LLSD& content); virtual void uploadFailure(const LLSD& content); @@ -58,6 +63,7 @@ protected: // TODO*: Remove this once deprecated class LLNewAgentInventoryResponder : public LLAssetUploadResponder { + LOG_CLASS(LLNewAgentInventoryResponder); public: LLNewAgentInventoryResponder( const LLSD& post_data, @@ -67,9 +73,10 @@ public: const LLSD& post_data, const std::string& file_name, LLAssetType::EType asset_type); - virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content); virtual void uploadComplete(const LLSD& content); virtual void uploadFailure(const LLSD& content); +protected: + virtual void httpFailure(); }; // A base class which goes through and performs some default @@ -79,6 +86,7 @@ public: class LLNewAgentInventoryVariablePriceResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLNewAgentInventoryVariablePriceResponder); public: LLNewAgentInventoryVariablePriceResponder( const LLUUID& vfile_id, @@ -91,12 +99,11 @@ public: const LLSD& inventory_info); virtual ~LLNewAgentInventoryVariablePriceResponder(); - void errorWithContent( - U32 statusNum, - const std::string& reason, - const LLSD& content); - void result(const LLSD& content); +private: + /* virtual */ void httpFailure(); + /* virtual */ void httpSuccess(); +public: virtual void onApplicationLevelError( const LLSD& error); virtual void showConfirmationDialog( @@ -122,8 +129,11 @@ public: ~LLSendTexLayerResponder(); virtual void uploadComplete(const LLSD& content); - virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content); +protected: + virtual void httpFailure(); + +private: LLBakedUploadData * mBakedUploadData; }; diff --git a/indra/newview/llclassifiedstatsresponder.cpp b/indra/newview/llclassifiedstatsresponder.cpp index e3cd83e174..923662e887 100644 --- a/indra/newview/llclassifiedstatsresponder.cpp +++ b/indra/newview/llclassifiedstatsresponder.cpp @@ -44,8 +44,14 @@ mClassifiedID(classified_id) } /*virtual*/ -void LLClassifiedStatsResponder::result(const LLSD& content) +void LLClassifiedStatsResponder::httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } S32 teleport = content["teleport_clicks"].asInteger(); S32 map = content["map_clicks"].asInteger(); S32 profile = content["profile_clicks"].asInteger(); @@ -62,7 +68,8 @@ void LLClassifiedStatsResponder::result(const LLSD& content) } /*virtual*/ -void LLClassifiedStatsResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLClassifiedStatsResponder::httpFailure() { - llinfos << "LLClassifiedStatsResponder::error [status:" << status << "]: " << content << llendl; + llwarns << dumpResponse() << llendl; } + diff --git a/indra/newview/llclassifiedstatsresponder.h b/indra/newview/llclassifiedstatsresponder.h index 06dcb62fd0..efa4d82411 100644 --- a/indra/newview/llclassifiedstatsresponder.h +++ b/indra/newview/llclassifiedstatsresponder.h @@ -33,13 +33,15 @@ class LLClassifiedStatsResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLClassifiedStatsResponder); public: LLClassifiedStatsResponder(LLUUID classified_id); + +protected: //If we get back a normal response, handle it here - virtual void result(const LLSD& content); + virtual void httpSuccess(); //If we get back an error (not found, etc...), handle it here - - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); + virtual void httpFailure(); protected: LLUUID mClassifiedID; diff --git a/indra/newview/llestateinfomodel.cpp b/indra/newview/llestateinfomodel.cpp index 2669b0340f..db2c15a444 100644 --- a/indra/newview/llestateinfomodel.cpp +++ b/indra/newview/llestateinfomodel.cpp @@ -112,19 +112,19 @@ void LLEstateInfoModel::notifyCommit() class LLEstateChangeInfoResponder : public LLHTTPClient::Responder { -public: - + LOG_CLASS(LLEstateChangeInfoResponder); +protected: // if we get a normal response, handle it here - virtual void result(const LLSD& content) + virtual void httpSuccesss() { llinfos << "Committed estate info" << llendl; LLEstateInfoModel::instance().notifyCommit(); } // if we get an error response - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) + virtual void httpFailure() { - llwarns << "Failed to commit estate info [status:" << status << "]: " << content << llendl; + llwarns << "Failed to commit estate info " << dumpResponse() << llendl; } }; diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index e0f7223a8c..c3b53d5e4a 100644 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -31,7 +31,7 @@ #include "llagent.h" #include "llhttpclient.h" -#include "llhttpstatuscodes.h" +#include "llhttpconstants.h" #include "llsdserialize.h" #include "lleventtimer.h" #include "llviewerregion.h" @@ -49,6 +49,7 @@ namespace class LLEventPollResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLEventPollResponder); public: static LLHTTPClient::ResponderPtr start(const std::string& pollURL, const LLHost& sender); @@ -56,19 +57,19 @@ namespace void makeRequest(); + /* virtual */ void completedRaw(const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer); + private: LLEventPollResponder(const std::string& pollURL, const LLHost& sender); ~LLEventPollResponder(); void handleMessage(const LLSD& content); - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); - virtual void result(const LLSD& content); - virtual void completedRaw(U32 status, - const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer); + /* virtual */ void httpFailure(); + /* virtual */ void httpSuccess(); + private: bool mDone; @@ -149,20 +150,18 @@ namespace } // virtual - void LLEventPollResponder::completedRaw(U32 status, - const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) + void LLEventPollResponder::completedRaw(const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) { - if (status == HTTP_BAD_GATEWAY) + if (getStatus() == HTTP_BAD_GATEWAY) { // These errors are not parsable as LLSD, // which LLHTTPClient::Responder::completedRaw will try to do. - completed(status, reason, LLSD()); + httpCompleted(); } else { - LLHTTPClient::Responder::completedRaw(status,reason,channels,buffer); + LLHTTPClient::Responder::completedRaw(channels,buffer); } } @@ -187,13 +186,13 @@ namespace } //virtual - void LLEventPollResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) + void LLEventPollResponder::httpFailure() { if (mDone) return; // A HTTP_BAD_GATEWAY (502) error is our standard timeout response // we get this when there are no events. - if ( status == HTTP_BAD_GATEWAY ) + if ( getStatus() == HTTP_BAD_GATEWAY ) { mErrorCount = 0; makeRequest(); @@ -207,12 +206,12 @@ namespace + mErrorCount * EVENT_POLL_ERROR_RETRY_SECONDS_INC , this); - llwarns << "LLEventPollResponder error [status:" << status << "]: " << content << llendl; + llwarns << dumpResponse() << llendl; } else { - llwarns << "LLEventPollResponder error <" << mCount - << "> [status:" << status << "]: " << content + llwarns << dumpResponse() + << " [count:" << mCount << "] " << (mDone ? " -- done" : "") << llendl; stop(); @@ -234,7 +233,7 @@ namespace } //virtual - void LLEventPollResponder::result(const LLSD& content) + void LLEventPollResponder::httpSuccess() { lldebugs << "LLEventPollResponder::result <" << mCount << ">" << (mDone ? " -- done" : "") << llendl; @@ -243,10 +242,12 @@ namespace mErrorCount = 0; - if (!content.get("events") || + const LLSD& content = getContent(); + if (!content.isMap() || + !content.get("events") || !content.get("id")) { - llwarns << "received event poll with no events or id key" << llendl; + llwarns << "received event poll with no events or id key: " << dumpResponse() << llendl; makeRequest(); return; } diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index a4cadcd5dc..c4ae718082 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -39,6 +39,7 @@ #include "llsecondlifeurls.h" #include "llappviewer.h" +#include "llbufferstream.h" #include "llhttpclient.h" #include "llnotificationsutil.h" #include "llviewercontrol.h" @@ -509,6 +510,7 @@ void LLFeatureManager::parseGPUTable(std::string filename) // responder saves table into file class LLHTTPFeatureTableResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLHTTPFeatureTableResponder); public: LLHTTPFeatureTableResponder(std::string filename) : @@ -517,11 +519,10 @@ public: } - virtual void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, + virtual void completedRaw(const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { - if (isGoodStatus(status)) + if (isGoodStatus()) { // write to file @@ -540,7 +541,18 @@ public: out.close(); } } - + else + { + char body[1025]; + body[1024] = '\0'; + LLBufferStream istr(channels, buffer.get()); + istr.get(body,1024); + if (strlen(body) > 0) + { + mContent["body"] = body; + } + llwarns << dumpResponse() << llendl; + } } private: diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index d13f85baa2..89d74666f7 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -1240,9 +1240,9 @@ static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker) { GtkFileFilter *gfilter = gtk_file_filter_new(); gtk_file_filter_add_pattern(gfilter, "*.tga"); - gtk_file_filter_add_mime_type(gfilter, "image/jpeg"); - gtk_file_filter_add_mime_type(gfilter, "image/png"); - gtk_file_filter_add_mime_type(gfilter, "image/bmp"); + gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_JPEG.c_str()); + gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_PNG.c_str()); + gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_BMP.c_str()); std::string filtername = LLTrans::getString("image_files") + " (*.tga; *.bmp; *.jpg; *.png)"; add_common_filters_to_gtkchooser(gfilter, picker, filtername); return filtername; @@ -1250,13 +1250,13 @@ static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker) static std::string add_script_filter_to_gtkchooser(GtkWindow *picker) { - return add_simple_mime_filter_to_gtkchooser(picker, "text/plain", + return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN, LLTrans::getString("script_files") + " (*.lsl)"); } static std::string add_dictionary_filter_to_gtkchooser(GtkWindow *picker) { - return add_simple_mime_filter_to_gtkchooser(picker, "text/plain", + return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN, LLTrans::getString("dictionary_files") + " (*.dic; *.xcu)"); } @@ -1294,7 +1294,7 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename break; case FFSAVE_BMP: caption += add_simple_mime_filter_to_gtkchooser - (picker, "image/bmp", LLTrans::getString("bitmap_image_files") + " (*.bmp)"); + (picker, HTTP_CONTENT_IMAGE_BMP, LLTrans::getString("bitmap_image_files") + " (*.bmp)"); suggest_ext = ".bmp"; break; case FFSAVE_AVI: @@ -1319,6 +1319,7 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename suggest_ext = ".raw"; break; case FFSAVE_J2C: + // *TODO: Should this be 'image/j2c' ? caption += add_simple_mime_filter_to_gtkchooser (picker, "images/jp2", LLTrans::getString("compressed_image_files") + " (*.j2c)"); diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index 83fb887d81..801a24f472 100644 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -77,14 +77,9 @@ class LLServerReleaseNotesURLFetcher : public LLHTTPClient::Responder { LOG_CLASS(LLServerReleaseNotesURLFetcher); public: - static void startFetch(); - /*virtual*/ void completedHeader(U32 status, const std::string& reason, const LLSD& content); - /*virtual*/ void completedRaw( - U32 status, - const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer); +private: + /* virtual */ void httpCompleted(); }; ///---------------------------------------------------------------------------- @@ -471,32 +466,26 @@ void LLServerReleaseNotesURLFetcher::startFetch() } // virtual -void LLServerReleaseNotesURLFetcher::completedHeader(U32 status, const std::string& reason, const LLSD& content) +void LLServerReleaseNotesURLFetcher::httpCompleted() { - lldebugs << "Status: " << status << llendl; - lldebugs << "Reason: " << reason << llendl; - lldebugs << "Headers: " << content << llendl; + LL_DEBUGS("ServerReleaseNotes") << dumpResponse() + << " [headers:" << getResponseHeaders() << "]" << LL_ENDL; LLFloaterAbout* floater_about = LLFloaterReg::getTypedInstance<LLFloaterAbout>("sl_about"); if (floater_about) { - std::string location = content["location"].asString(); + const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); if (location.empty()) { - location = floater_about->getString("ErrorFetchingServerReleaseNotesURL"); + LL_WARNS("ServerReleaseNotes") << "Missing Location header " + << dumpResponse() << " [headers:" << getResponseHeaders() << "]" << LL_ENDL; + floater_about->updateServerReleaseNotesURL( + floater_about->getString("ErrorFetchingServerReleaseNotesURL")); + } + else + { + floater_about->updateServerReleaseNotesURL(location); } - floater_about->updateServerReleaseNotesURL(location); } } -// virtual -void LLServerReleaseNotesURLFetcher::completedRaw( - U32 status, - const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) -{ - // Do nothing. - // We're overriding just because the base implementation tries to - // deserialize LLSD which triggers warnings. -} diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index 113aa9a8f2..0844a70e25 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -458,13 +458,15 @@ BOOL LLFloaterAvatarPicker::visibleItemsSelected() const class LLAvatarPickerResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLAvatarPickerResponder); public: LLUUID mQueryID; std::string mName; LLAvatarPickerResponder(const LLUUID& id, const std::string& name) : mQueryID(id), mName(name) { } - /*virtual*/ void completed(U32 status, const std::string& reason, const LLSD& content) +protected: + /*virtual*/ void httpCompleted() { //std::ostringstream ss; //LLSDSerialize::toPrettyXML(content, ss); @@ -472,19 +474,18 @@ public: // in case of invalid characters, the avatar picker returns a 400 // just set it to process so it displays 'not found' - if (isGoodStatus(status) || status == 400) + if (isGoodStatus() || getStatus() == HTTP_BAD_REQUEST) { LLFloaterAvatarPicker* floater = LLFloaterReg::findTypedInstance<LLFloaterAvatarPicker>("avatar_picker", mName); if (floater) { - floater->processResponse(mQueryID, content); + floater->processResponse(mQueryID, getContent()); } } else { - llwarns << "avatar picker failed [status:" << status << "]: " << content << llendl; - + llwarns << "avatar picker failed " << dumpResponse() << llendl; } } }; diff --git a/indra/newview/llfloaterbuycurrencyhtml.cpp b/indra/newview/llfloaterbuycurrencyhtml.cpp index 013cf74c7b..6e641e7d40 100644 --- a/indra/newview/llfloaterbuycurrencyhtml.cpp +++ b/indra/newview/llfloaterbuycurrencyhtml.cpp @@ -27,6 +27,7 @@ #include "llviewerprecompiledheaders.h" #include "llfloaterbuycurrencyhtml.h" +#include "llhttpconstants.h" #include "llstatusbar.h" //////////////////////////////////////////////////////////////////////////////// @@ -85,7 +86,7 @@ void LLFloaterBuyCurrencyHTML::navigateToFinalURL() llinfos << "Buy currency HTML parsed URL is " << buy_currency_url << llendl; // kick off the navigation - mBrowser->navigateTo( buy_currency_url, "text/html" ); + mBrowser->navigateTo( buy_currency_url, HTTP_CONTENT_TEXT_HTML ); } //////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp index 56051ff684..af5c11e12c 100644 --- a/indra/newview/llfloatergesture.cpp +++ b/indra/newview/llfloatergesture.cpp @@ -617,9 +617,10 @@ void LLFloaterGesture::addToCurrentOutFit() uuid_vec_t ids; getSelectedIds(ids); LLAppearanceMgr* am = LLAppearanceMgr::getInstance(); + LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; for(uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); it++) { - am->addCOFItemLink(*it); + am->addCOFItemLink(*it, cb); } } diff --git a/indra/newview/llfloaterhelpbrowser.cpp b/indra/newview/llfloaterhelpbrowser.cpp index 4cb632bd6a..c0bb213540 100644 --- a/indra/newview/llfloaterhelpbrowser.cpp +++ b/indra/newview/llfloaterhelpbrowser.cpp @@ -29,6 +29,7 @@ #include "llfloaterhelpbrowser.h" #include "llfloaterreg.h" +#include "llhttpconstants.h" #include "llpluginclassmedia.h" #include "llmediactrl.h" #include "llviewerwindow.h" @@ -37,7 +38,6 @@ #include "llui.h" #include "llurlhistory.h" -#include "llmediactrl.h" #include "llviewermedia.h" #include "llviewerhelp.h" @@ -148,7 +148,7 @@ void LLFloaterHelpBrowser::openMedia(const std::string& media_url) { // explicitly make the media mime type for this floater since it will // only ever display one type of content (Web). - mBrowser->setHomePageUrl(media_url, "text/html"); - mBrowser->navigateTo(media_url, "text/html"); + mBrowser->setHomePageUrl(media_url, HTTP_CONTENT_TEXT_HTML); + mBrowser->navigateTo(media_url, HTTP_CONTENT_TEXT_HTML); setCurrentURL(media_url); } diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp index 8ec85e1160..7b72c1e930 100644 --- a/indra/newview/llfloaterimsession.cpp +++ b/indra/newview/llfloaterimsession.cpp @@ -1149,16 +1149,17 @@ BOOL LLFloaterIMSession::isInviteAllowed() const class LLSessionInviteResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLSessionInviteResponder); public: LLSessionInviteResponder(const LLUUID& session_id) { mSessionID = session_id; } - void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +protected: + void httpFailure() { - llwarns << "Error inviting all agents to session [status:" - << statusNum << "]: " << content << llendl; + llwarns << "Error inviting all agents to session " << dumpResponse() << llendl; //throw something back to the viewer here? } diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 100f1d580b..5830156fdd 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -5839,7 +5839,7 @@ void LLFloaterModelPreview::handleModelPhysicsFeeReceived() mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty()); } -void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason) +void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) { llwarns << "LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(" << status << " : " << reason << ")" << llendl; doOnIdleOneTime(boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this, true)); @@ -5915,7 +5915,7 @@ void LLFloaterModelPreview::onPermissionsReceived(const LLSD& result) getChild<LLTextBox>("warning_message")->setVisible(!mHasUploadPerm); } -void LLFloaterModelPreview::setPermissonsErrorStatus(U32 status, const std::string& reason) +void LLFloaterModelPreview::setPermissonsErrorStatus(S32 status, const std::string& reason) { llwarns << "LLFloaterModelPreview::setPermissonsErrorStatus(" << status << " : " << reason << ")" << llendl; diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index e588418f7b..6c0c60b87f 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -200,11 +200,11 @@ public: /*virtual*/ void onPermissionsReceived(const LLSD& result); // called when error occurs during permissions request - /*virtual*/ void setPermissonsErrorStatus(U32 status, const std::string& reason); + /*virtual*/ void setPermissonsErrorStatus(S32 status, const std::string& reason); /*virtual*/ void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url); void handleModelPhysicsFeeReceived(); - /*virtual*/ void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason); + /*virtual*/ void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason); /*virtual*/ void onModelUploadSuccess(); diff --git a/indra/newview/llfloatermodeluploadbase.cpp b/indra/newview/llfloatermodeluploadbase.cpp index 6d3800bfa4..9f1fc06e14 100644 --- a/indra/newview/llfloatermodeluploadbase.cpp +++ b/indra/newview/llfloatermodeluploadbase.cpp @@ -45,7 +45,7 @@ void LLFloaterModelUploadBase::requestAgentUploadPermissions() if (!url.empty()) { llinfos<< typeid(*this).name() <<"::requestAgentUploadPermissions() requesting for upload model permissions from: "<< url <<llendl; - LLHTTPClient::get(url, new LLUploadModelPremissionsResponder(getPermObserverHandle())); + LLHTTPClient::get(url, new LLUploadModelPermissionsResponder(getPermObserverHandle())); } else { diff --git a/indra/newview/llfloatermodeluploadbase.h b/indra/newview/llfloatermodeluploadbase.h index a52bc28687..d9a8879687 100644 --- a/indra/newview/llfloatermodeluploadbase.h +++ b/indra/newview/llfloatermodeluploadbase.h @@ -37,13 +37,13 @@ public: virtual ~LLFloaterModelUploadBase(){}; - virtual void setPermissonsErrorStatus(U32 status, const std::string& reason) = 0; + virtual void setPermissonsErrorStatus(S32 status, const std::string& reason) = 0; virtual void onPermissionsReceived(const LLSD& result) = 0; virtual void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) = 0; - virtual void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason) = 0; + virtual void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) = 0; virtual void onModelUploadSuccess() {}; diff --git a/indra/newview/llfloaterobjectweights.cpp b/indra/newview/llfloaterobjectweights.cpp index 0862cd2897..c11a0568a6 100644 --- a/indra/newview/llfloaterobjectweights.cpp +++ b/indra/newview/llfloaterobjectweights.cpp @@ -123,7 +123,7 @@ void LLFloaterObjectWeights::onWeightsUpdate(const SelectionCost& selection_cost } //virtual -void LLFloaterObjectWeights::setErrorStatus(U32 status, const std::string& reason) +void LLFloaterObjectWeights::setErrorStatus(S32 status, const std::string& reason) { const std::string text = getString("nothing_selected"); diff --git a/indra/newview/llfloaterobjectweights.h b/indra/newview/llfloaterobjectweights.h index 9a244573be..1a2c317bad 100644 --- a/indra/newview/llfloaterobjectweights.h +++ b/indra/newview/llfloaterobjectweights.h @@ -63,7 +63,7 @@ public: /*virtual*/ void onOpen(const LLSD& key); /*virtual*/ void onWeightsUpdate(const SelectionCost& selection_cost); - /*virtual*/ void setErrorStatus(U32 status, const std::string& reason); + /*virtual*/ void setErrorStatus(S32 status, const std::string& reason); void updateLandImpacts(const LLParcel* parcel); void refresh(); diff --git a/indra/newview/llfloaterregiondebugconsole.cpp b/indra/newview/llfloaterregiondebugconsole.cpp index 3a7ca17b73..efc04ac358 100644 --- a/indra/newview/llfloaterregiondebugconsole.cpp +++ b/indra/newview/llfloaterregiondebugconsole.cpp @@ -73,24 +73,29 @@ namespace // called if this request times out. class AsyncConsoleResponder : public LLHTTPClient::Responder { - public: + LOG_CLASS(AsyncConsoleResponder); + protected: /* virtual */ - void errorWithContent(U32 status, const std::string& reason, const LLSD& content) + void httpFailure() { + LL_WARNS("Console") << dumpResponse() << LL_ENDL; sConsoleReplySignal(UNABLE_TO_SEND_COMMAND); } }; class ConsoleResponder : public LLHTTPClient::Responder { + LOG_CLASS(ConsoleResponder); public: ConsoleResponder(LLTextEditor *output) : mOutput(output) { } + protected: /*virtual*/ - void error(U32 status, const std::string& reason) + void httpFailure() { + LL_WARNS("Console") << dumpResponse() << LL_ENDL; if (mOutput) { mOutput->appendText( @@ -100,8 +105,10 @@ namespace } /*virtual*/ - void result(const LLSD& content) + void httpSuccess() { + const LLSD& content = getContent(); + LL_DEBUGS("Console") << content << LL_ENDL; if (mOutput) { mOutput->appendText( @@ -109,6 +116,7 @@ namespace } } + public: LLTextEditor * mOutput; }; diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 50c013a49d..ddfae005bb 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -756,12 +756,12 @@ bool LLPanelRegionGeneralInfo::onMessageCommit(const LLSD& notification, const L class ConsoleRequestResponder : public LLHTTPClient::Responder { -public: + LOG_CLASS(ConsoleRequestResponder); +protected: /*virtual*/ - void errorWithContent(U32 status, const std::string& reason, const LLSD& content) + void httpFailure() { - llwarns << "ConsoleRequestResponder error requesting mesh_rez_enabled [status:" - << status << "]: " << content << llendl; + llwarns << "error requesting mesh_rez_enabled " << dumpResponse() << llendl; } }; @@ -769,12 +769,12 @@ public: // called if this request times out. class ConsoleUpdateResponder : public LLHTTPClient::Responder { -public: + LOG_CLASS(ConsoleUpdateResponder); +protected: /* virtual */ - void errorWithContent(U32 status, const std::string& reason, const LLSD& content) + void httpFailure() { - llwarns << "ConsoleRequestResponder error updating mesh enabled region setting [status:" - << status << "]: " << content << llendl; + llwarns << "error updating mesh enabled region setting " << dumpResponse() << llendl; } }; @@ -2233,14 +2233,16 @@ void LLPanelEstateInfo::getEstateOwner() class LLEstateChangeInfoResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLEstateChangeInfoResponder); public: LLEstateChangeInfoResponder(LLPanelEstateInfo* panel) { mpPanel = panel->getHandle(); } +protected: // if we get a normal response, handle it here - virtual void result(const LLSD& content) + virtual void httpSuccess() { LL_INFOS("Windlight") << "Successfully committed estate info" << llendl; @@ -2251,10 +2253,9 @@ public: } // if we get an error response - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) + virtual void httpFailure() { - llinfos << "LLEstateChangeInfoResponder::error [status:" - << status << "]: " << content << llendl; + LL_WARNS("Windlight") << dumpResponse() << LL_ENDL; } private: LLHandle<LLPanel> mpPanel; diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 35b63c5480..cc4199a758 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -707,16 +707,18 @@ public: class LLUserReportResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLUserReportResponder); public: LLUserReportResponder(): LLHTTPClient::Responder() {} - void errorWithContent(U32 status, const std::string& reason, const LLSD& content) - { - // *TODO do some user messaging here - LLUploadDialog::modalUploadFinished(); - } - void result(const LLSD& content) +private: + void httpCompleted() { + if (!isGoodStatus()) + { + // *TODO do some user messaging here + LL_WARNS("UserReport") << dumpResponse() << LL_ENDL; + } // we don't care about what the server returns LLUploadDialog::modalUploadFinished(); } diff --git a/indra/newview/llfloaterscriptlimits.cpp b/indra/newview/llfloaterscriptlimits.cpp index 13cb3c2eb0..11a0d3ebe4 100644 --- a/indra/newview/llfloaterscriptlimits.cpp +++ b/indra/newview/llfloaterscriptlimits.cpp @@ -183,8 +183,14 @@ void LLPanelScriptLimitsInfo::updateChild(LLUICtrl* child_ctr) // Responders ///---------------------------------------------------------------------------- -void fetchScriptLimitsRegionInfoResponder::result(const LLSD& content) +void fetchScriptLimitsRegionInfoResponder::httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } //we don't need to test with a fake respose here (shouldn't anyway) #ifdef DUMP_REPLIES_TO_LLINFOS @@ -221,13 +227,14 @@ void fetchScriptLimitsRegionInfoResponder::result(const LLSD& content) } } -void fetchScriptLimitsRegionInfoResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void fetchScriptLimitsRegionInfoResponder::httpFailure() { - llwarns << "fetchScriptLimitsRegionInfoResponder error [status:" << status << "]: " << content << llendl; + llwarns << dumpResponse() << llendl; } -void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref) +void fetchScriptLimitsRegionSummaryResponder::httpSuccess() { + const LLSD& content_ref = getContent(); #ifdef USE_FAKE_RESPONSES LLSD fake_content; @@ -268,6 +275,12 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref) #endif + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } + #ifdef DUMP_REPLIES_TO_LLINFOS @@ -291,7 +304,7 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref) LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels"); if(tab) { - LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel"); + LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel"); if(panel_memory) { panel_memory->getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string(""))); @@ -301,20 +314,21 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref) { btn->setEnabled(true); } - - panel_memory->setRegionSummary(content); - } -} + + panel_memory->setRegionSummary(content); + } + } } } -void fetchScriptLimitsRegionSummaryResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void fetchScriptLimitsRegionSummaryResponder::httpFailure() { - llwarns << "fetchScriptLimitsRegionSummaryResponder error [status:" << status << "]: " << content << llendl; + llwarns << dumpResponse() << llendl; } -void fetchScriptLimitsRegionDetailsResponder::result(const LLSD& content_ref) +void fetchScriptLimitsRegionDetailsResponder::httpSuccess() { + const LLSD& content_ref = getContent(); #ifdef USE_FAKE_RESPONSES /* Updated detail service, ** denotes field added: @@ -377,6 +391,12 @@ result (map) #endif + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } + #ifdef DUMP_REPLIES_TO_LLINFOS LLSDNotationStreamer notation_streamer(content); @@ -417,13 +437,14 @@ result (map) } } -void fetchScriptLimitsRegionDetailsResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void fetchScriptLimitsRegionDetailsResponder::httpFailure() { - llwarns << "fetchScriptLimitsRegionDetailsResponder error [status:" << status << "]: " << content << llendl; + llwarns << dumpResponse() << llendl; } -void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref) +void fetchScriptLimitsAttachmentInfoResponder::httpSuccess() { + const LLSD& content_ref = getContent(); #ifdef USE_FAKE_RESPONSES @@ -465,6 +486,12 @@ void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref) #endif + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } + #ifdef DUMP_REPLIES_TO_LLINFOS LLSDNotationStreamer notation_streamer(content); @@ -513,9 +540,9 @@ void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref) } } -void fetchScriptLimitsAttachmentInfoResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void fetchScriptLimitsAttachmentInfoResponder::httpFailure() { - llwarns << "fetchScriptLimitsAttachmentInfoResponder error [status:" << status << "]: " << content << llendl; + llwarns << dumpResponse() << llendl; } ///---------------------------------------------------------------------------- @@ -586,7 +613,7 @@ void LLPanelScriptLimitsRegionMemory::setParcelID(const LLUUID& parcel_id) } // virtual -void LLPanelScriptLimitsRegionMemory::setErrorStatus(U32 status, const std::string& reason) +void LLPanelScriptLimitsRegionMemory::setErrorStatus(S32 status, const std::string& reason) { llwarns << "Can't handle remote parcel request."<< " Http Status: "<< status << ". Reason : "<< reason<<llendl; } diff --git a/indra/newview/llfloaterscriptlimits.h b/indra/newview/llfloaterscriptlimits.h index f8732ef94b..a5cb1b6184 100644 --- a/indra/newview/llfloaterscriptlimits.h +++ b/indra/newview/llfloaterscriptlimits.h @@ -85,49 +85,49 @@ protected: class fetchScriptLimitsRegionInfoResponder: public LLHTTPClient::Responder { - public: - fetchScriptLimitsRegionInfoResponder(const LLSD& info) : mInfo(info) {}; - - void result(const LLSD& content); - void errorWithContent(U32 status, const std::string& reason, const LLSD& content); - public: - protected: - LLSD mInfo; + LOG_CLASS(fetchScriptLimitsRegionInfoResponder); +public: + fetchScriptLimitsRegionInfoResponder(const LLSD& info) : mInfo(info) {}; + +private: + /* virtual */ void httpSuccess(); + /* virtual */ void httpFailure(); + LLSD mInfo; }; class fetchScriptLimitsRegionSummaryResponder: public LLHTTPClient::Responder { - public: - fetchScriptLimitsRegionSummaryResponder(const LLSD& info) : mInfo(info) {}; - - void result(const LLSD& content); - void errorWithContent(U32 status, const std::string& reason, const LLSD& content); - public: - protected: - LLSD mInfo; + LOG_CLASS(fetchScriptLimitsRegionSummaryResponder); +public: + fetchScriptLimitsRegionSummaryResponder(const LLSD& info) : mInfo(info) {}; + +private: + /* virtual */ void httpSuccess(); + /* virtual */ void httpFailure(); + LLSD mInfo; }; class fetchScriptLimitsRegionDetailsResponder: public LLHTTPClient::Responder { - public: - fetchScriptLimitsRegionDetailsResponder(const LLSD& info) : mInfo(info) {}; - - void result(const LLSD& content); - void errorWithContent(U32 status, const std::string& reason, const LLSD& content); - public: - protected: - LLSD mInfo; + LOG_CLASS(fetchScriptLimitsRegionDetailsResponder); +public: + fetchScriptLimitsRegionDetailsResponder(const LLSD& info) : mInfo(info) {}; + +private: + /* virtual */ void httpSuccess(); + /* virtual */ void httpFailure(); + LLSD mInfo; }; class fetchScriptLimitsAttachmentInfoResponder: public LLHTTPClient::Responder { - public: - fetchScriptLimitsAttachmentInfoResponder() {}; + LOG_CLASS(fetchScriptLimitsAttachmentInfoResponder); +public: + fetchScriptLimitsAttachmentInfoResponder() {}; - void result(const LLSD& content); - void errorWithContent(U32 status, const std::string& reason, const LLSD& content); - public: - protected: +private: + /* virtual */ void httpSuccess(); + /* virtual */ void httpFailure(); }; ///////////////////////////////////////////////////////////////////////////// @@ -190,7 +190,7 @@ protected: // LLRemoteParcelInfoObserver interface: /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); /*virtual*/ void setParcelID(const LLUUID& parcel_id); -/*virtual*/ void setErrorStatus(U32 status, const std::string& reason); +/*virtual*/ void setErrorStatus(S32 status, const std::string& reason); static void onClickRefresh(void* userdata); static void onClickHighlight(void* userdata); diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp index 2a946b1edf..a446b767ac 100644 --- a/indra/newview/llfloatersearch.cpp +++ b/indra/newview/llfloatersearch.cpp @@ -30,6 +30,7 @@ #include "llcommandhandler.h" #include "llfloaterreg.h" #include "llfloatersearch.h" +#include "llhttpconstants.h" #include "llmediactrl.h" #include "llnotificationsutil.h" #include "lllogininstance.h" @@ -200,5 +201,5 @@ void LLFloaterSearch::search(const SearchQuery &p) url = LLWeb::expandURLSubstitutions(url, subs); // and load the URL in the web view - mWebBrowser->navigateTo(url, "text/html"); + mWebBrowser->navigateTo(url, HTTP_CONTENT_TEXT_HTML); } diff --git a/indra/newview/llfloatersidepanelcontainer.cpp b/indra/newview/llfloatersidepanelcontainer.cpp index 5f9556a870..4dd558c9c0 100644 --- a/indra/newview/llfloatersidepanelcontainer.cpp +++ b/indra/newview/llfloatersidepanelcontainer.cpp @@ -67,15 +67,21 @@ void LLFloaterSidePanelContainer::onClickCloseBtn() if (parent == this ) { LLSidepanelAppearance* panel_appearance = dynamic_cast<LLSidepanelAppearance*>(getPanel("appearance")); - if ( panel_appearance ) - { - panel_appearance->getWearable()->onClose(); - panel_appearance->showOutfitsInventoryPanel(); - } + panel_appearance->onClose(this); } + else + { + LLFloater::onClickCloseBtn(); + } + } + else + { + LLFloater::onClickCloseBtn(); } - - LLFloater::onClickCloseBtn(); +} +void LLFloaterSidePanelContainer::close() +{ + LLFloater::onClickCloseBtn(); } LLPanel* LLFloaterSidePanelContainer::openChildPanel(const std::string& panel_name, const LLSD& params) diff --git a/indra/newview/llfloatersidepanelcontainer.h b/indra/newview/llfloatersidepanelcontainer.h index 491723471f..940673b643 100644 --- a/indra/newview/llfloatersidepanelcontainer.h +++ b/indra/newview/llfloatersidepanelcontainer.h @@ -55,6 +55,8 @@ public: LLPanel* openChildPanel(const std::string& panel_name, const LLSD& params); + void close(); + static void showPanel(const std::string& floater_name, const LLSD& key); static void showPanel(const std::string& floater_name, const std::string& panel_name, const LLSD& key); diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp index a242b224cd..0613ffc94d 100644 --- a/indra/newview/llfloatertos.cpp +++ b/indra/newview/llfloatertos.cpp @@ -36,7 +36,7 @@ #include "llbutton.h" #include "llevents.h" #include "llhttpclient.h" -#include "llhttpstatuscodes.h" // for HTTP_FOUND +#include "llhttpconstants.h" #include "llnotificationsutil.h" #include "llradiogroup.h" #include "lltextbox.h" @@ -62,42 +62,46 @@ LLFloaterTOS::LLFloaterTOS(const LLSD& data) // on parent class indicating if the web server is working or not class LLIamHere : public LLHTTPClient::Responder { - private: - LLIamHere( LLFloaterTOS* parent ) : - mParent( parent ) - {} + LOG_CLASS(LLIamHere); +private: + LLIamHere( LLFloaterTOS* parent ) : + mParent( parent ) + {} - LLFloaterTOS* mParent; + LLFloaterTOS* mParent; - public: - - static LLIamHere* build( LLFloaterTOS* parent ) - { - return new LLIamHere( parent ); - }; - - virtual void setParent( LLFloaterTOS* parentIn ) - { - mParent = parentIn; - }; - - virtual void result( const LLSD& content ) +public: + static LLIamHere* build( LLFloaterTOS* parent ) + { + return new LLIamHere( parent ); + } + + virtual void setParent( LLFloaterTOS* parentIn ) + { + mParent = parentIn; + } + +protected: + virtual void httpSuccess() + { + if ( mParent ) { - if ( mParent ) - mParent->setSiteIsAlive( true ); - }; + mParent->setSiteIsAlive( true ); + } + } - virtual void error( U32 status, const std::string& reason ) + virtual void httpFailure() + { + LL_DEBUGS("LLIamHere") << dumpResponse() << LL_ENDL; + if ( mParent ) { - if ( mParent ) - { - // *HACK: For purposes of this alive check, 302 Found - // (aka Moved Temporarily) is considered alive. The web site - // redirects this link to a "cache busting" temporary URL. JC - bool alive = (status == HTTP_FOUND); - mParent->setSiteIsAlive( alive ); - } - }; + // *HACK: For purposes of this alive check, 302 Found + // (aka Moved Temporarily) is considered alive. The web site + // redirects this link to a "cache busting" temporary URL. JC + bool alive = (getStatus() == HTTP_FOUND); + mParent->setSiteIsAlive( alive ); + } + } }; // this is global and not a class member to keep crud out of the header file diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp index e85d849c9a..e26f1e9ea5 100644 --- a/indra/newview/llfloaterurlentry.cpp +++ b/indra/newview/llfloaterurlentry.cpp @@ -48,31 +48,30 @@ static LLFloaterURLEntry* sInstance = NULL; // on the Panel Land Media and to discover the MIME type class LLMediaTypeResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLMediaTypeResponder); public: LLMediaTypeResponder( const LLHandle<LLFloater> parent ) : - mParent( parent ) - {} - - LLHandle<LLFloater> mParent; - - - virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content) - { - std::string media_type = content["content-type"].asString(); - std::string::size_type idx1 = media_type.find_first_of(";"); - std::string mime_type = media_type.substr(0, idx1); - completeAny(status, mime_type); - } - - void completeAny(U32 status, const std::string& mime_type) - { - // Set empty type to none/none. Empty string is reserved for legacy parcels - // which have no mime type set. - std::string resolved_mime_type = ! mime_type.empty() ? mime_type : LLMIMETypes::getDefaultMimeType(); - LLFloaterURLEntry* floater_url_entry = (LLFloaterURLEntry*)mParent.get(); - if ( floater_url_entry ) - floater_url_entry->headerFetchComplete( status, resolved_mime_type ); - } + mParent( parent ) + {} + + LLHandle<LLFloater> mParent; + +private: + /* virtual */ void httpCompleted() + { + const std::string& media_type = getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE); + std::string::size_type idx1 = media_type.find_first_of(";"); + std::string mime_type = media_type.substr(0, idx1); + + // Set empty type to none/none. Empty string is reserved for legacy parcels + // which have no mime type set. + std::string resolved_mime_type = ! mime_type.empty() ? mime_type : LLMIMETypes::getDefaultMimeType(); + LLFloaterURLEntry* floater_url_entry = (LLFloaterURLEntry*)mParent.get(); + if ( floater_url_entry ) + { + floater_url_entry->headerFetchComplete( getStatus(), resolved_mime_type ); + } + } }; //----------------------------------------------------------------------------- @@ -136,7 +135,7 @@ void LLFloaterURLEntry::buildURLHistory() } } -void LLFloaterURLEntry::headerFetchComplete(U32 status, const std::string& mime_type) +void LLFloaterURLEntry::headerFetchComplete(S32 status, const std::string& mime_type) { LLPanelLandMedia* panel_media = dynamic_cast<LLPanelLandMedia*>(mPanelLandMediaHandle.get()); if (panel_media) diff --git a/indra/newview/llfloaterurlentry.h b/indra/newview/llfloaterurlentry.h index dfb49fe5ac..bdd1ebe592 100644 --- a/indra/newview/llfloaterurlentry.h +++ b/indra/newview/llfloaterurlentry.h @@ -40,7 +40,7 @@ public: // that panel via the handle. static LLHandle<LLFloater> show(LLHandle<LLPanel> panel_land_media_handle, const std::string media_url); /*virtual*/ BOOL postBuild(); - void headerFetchComplete(U32 status, const std::string& mime_type); + void headerFetchComplete(S32 status, const std::string& mime_type); bool addURLToCombobox(const std::string& media_url); diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp index 3fe2518de6..21b171446f 100644 --- a/indra/newview/llfloaterwebcontent.cpp +++ b/indra/newview/llfloaterwebcontent.cpp @@ -29,6 +29,7 @@ #include "llcombobox.h" #include "lliconctrl.h" #include "llfloaterreg.h" +#include "llhttpconstants.h" #include "lllayoutstack.h" #include "llpluginclassmedia.h" #include "llprogressbar.h" @@ -234,9 +235,9 @@ void LLFloaterWebContent::open_media(const Params& p) { // Specifying a mime type of text/html here causes the plugin system to skip the MIME type probe and just open a browser plugin. LLViewerMedia::proxyWindowOpened(p.target(), p.id()); - mWebBrowser->setHomePageUrl(p.url, "text/html"); + mWebBrowser->setHomePageUrl(p.url, HTTP_CONTENT_TEXT_HTML); mWebBrowser->setTarget(p.target); - mWebBrowser->navigateTo(p.url, "text/html"); + mWebBrowser->navigateTo(p.url, HTTP_CONTENT_TEXT_HTML); set_current_url(p.url); @@ -451,7 +452,7 @@ void LLFloaterWebContent::onEnterAddress() std::string url = mAddressCombo->getValue().asString(); if ( url.length() > 0 ) { - mWebBrowser->navigateTo( url, "text/html"); + mWebBrowser->navigateTo(url, HTTP_CONTENT_TEXT_HTML); }; } diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index 9aa86297fc..5eaa83d872 100644..100755 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -299,6 +299,12 @@ void LLGestureMgr::activateGestureWithAsset(const LLUUID& item_id, } +void notify_update_label(const LLUUID& base_item_id) +{ + gInventory.addChangedMask(LLInventoryObserver::LABEL, base_item_id); + LLGestureMgr::instance().notifyObservers(); +} + void LLGestureMgr::deactivateGesture(const LLUUID& item_id) { const LLUUID& base_item_id = get_linked_uuid(item_id); @@ -322,7 +328,6 @@ void LLGestureMgr::deactivateGesture(const LLUUID& item_id) } mActive.erase(it); - gInventory.addChangedMask(LLInventoryObserver::LABEL, base_item_id); // Inform the database of this change LLMessageSystem* msg = gMessageSystem; @@ -338,9 +343,11 @@ void LLGestureMgr::deactivateGesture(const LLUUID& item_id) gAgent.sendReliableMessage(); - LLAppearanceMgr::instance().removeCOFItemLinks(base_item_id); + LLPointer<LLInventoryCallback> cb = + new LLBoostFuncInventoryCallback(no_op_inventory_func, + boost::bind(notify_update_label,base_item_id)); - notifyObservers(); + LLAppearanceMgr::instance().removeCOFItemLinks(base_item_id, cb); } diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp index cbd844cdac..472e3862ea 100644 --- a/indra/newview/llgroupmgr.cpp +++ b/indra/newview/llgroupmgr.cpp @@ -1843,23 +1843,31 @@ void LLGroupMgr::sendGroupMemberEjects(const LLUUID& group_id, // Responder class for capability group management class GroupMemberDataResponder : public LLHTTPClient::Responder { + LOG_CLASS(GroupMemberDataResponder); public: - GroupMemberDataResponder() {} - virtual ~GroupMemberDataResponder() {} - virtual void result(const LLSD& pContent); - virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); + GroupMemberDataResponder() {} + virtual ~GroupMemberDataResponder() {} + private: - LLSD mMemberData; + /* virtual */ void httpSuccess(); + /* virtual */ void httpFailure(); + LLSD mMemberData; }; -void GroupMemberDataResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent) +void GroupMemberDataResponder::httpFailure() { - LL_WARNS("GrpMgr") << "Error receiving group member data [status:" - << pStatus << "]: " << pContent << LL_ENDL; + LL_WARNS("GrpMgr") << "Error receiving group member data " + << dumpResponse() << LL_ENDL; } -void GroupMemberDataResponder::result(const LLSD& content) +void GroupMemberDataResponder::httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } LLGroupMgr::processCapGroupMembersRequest(content); } diff --git a/indra/newview/llhomelocationresponder.cpp b/indra/newview/llhomelocationresponder.cpp index 37428c4a44..b1286cccf2 100644 --- a/indra/newview/llhomelocationresponder.cpp +++ b/indra/newview/llhomelocationresponder.cpp @@ -33,71 +33,76 @@ #include "llagent.h" #include "llviewerregion.h" -void LLHomeLocationResponder::result( const LLSD& content ) +void LLHomeLocationResponder::httpSuccess() { + const LLSD& content = getContent(); LLVector3 agent_pos; bool error = true; - + do { - + // was the call to /agent/<agent-id>/home-location successful? // If not, we keep error set to true if( ! content.has("success") ) { break; } - + if( 0 != strncmp("true", content["success"].asString().c_str(), 4 ) ) { break; } - + // did the simulator return a "justified" home location? // If no, we keep error set to true if( ! content.has( "HomeLocation" ) ) { break; } - + if( ! content["HomeLocation"].has("LocationPos") ) { break; } - + if( ! content["HomeLocation"]["LocationPos"].has("X") ) { break; } agent_pos.mV[VX] = content["HomeLocation"]["LocationPos"]["X"].asInteger(); - + if( ! content["HomeLocation"]["LocationPos"].has("Y") ) { break; } agent_pos.mV[VY] = content["HomeLocation"]["LocationPos"]["Y"].asInteger(); - + if( ! content["HomeLocation"]["LocationPos"].has("Z") ) { break; } agent_pos.mV[VZ] = content["HomeLocation"]["LocationPos"]["Z"].asInteger(); - + error = false; } while( 0 ); - - if( ! error ) + + if( error ) + { + failureResult(HTTP_INTERNAL_ERROR, "Invalid server response content", content); + } + else { llinfos << "setting home position" << llendl; - + LLViewerRegion *viewer_region = gAgent.getRegion(); gAgent.setHomePosRegion( viewer_region->getHandle(), agent_pos ); } } -void LLHomeLocationResponder::errorWithContent( U32 status, const std::string& reason, const LLSD& content ) +void LLHomeLocationResponder::httpFailure() { - llwarns << "LLHomeLocationResponder error [status:" << status << "]: " << content << llendl; + llwarns << dumpResponse() << llendl; } diff --git a/indra/newview/llhomelocationresponder.h b/indra/newview/llhomelocationresponder.h index 9bf4b12c4e..adc6c8cb58 100644 --- a/indra/newview/llhomelocationresponder.h +++ b/indra/newview/llhomelocationresponder.h @@ -35,8 +35,10 @@ /* Typedef, Enum, Class, Struct, etc. */ class LLHomeLocationResponder : public LLHTTPClient::Responder { - virtual void result( const LLSD& content ); - virtual void errorWithContent( U32 status, const std::string& reason, const LLSD& content ); + LOG_CLASS(LLHomeLocationResponder); +private: + /* virtual */ void httpSuccess(); + /* virtual */ void httpFailure(); }; #endif diff --git a/indra/newview/llhttpretrypolicy.cpp b/indra/newview/llhttpretrypolicy.cpp new file mode 100755 index 0000000000..80d97e4362 --- /dev/null +++ b/indra/newview/llhttpretrypolicy.cpp @@ -0,0 +1,136 @@ +/** + * @file llhttpretrypolicy.h + * @brief Header for a retry policy class intended for use with http responders. + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * 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 "llviewerprecompiledheaders.h" + +#include "llhttpretrypolicy.h" + +LLAdaptiveRetryPolicy::LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries): + mMinDelay(min_delay), + mMaxDelay(max_delay), + mBackoffFactor(backoff_factor), + mMaxRetries(max_retries) +{ + init(); +} + +void LLAdaptiveRetryPolicy::init() +{ + mDelay = mMinDelay; + mRetryCount = 0; + mShouldRetry = true; +} + +bool LLAdaptiveRetryPolicy::getRetryAfter(const LLSD& headers, F32& retry_header_time) +{ + return (headers.has(HTTP_IN_HEADER_RETRY_AFTER) + && getSecondsUntilRetryAfter(headers[HTTP_IN_HEADER_RETRY_AFTER].asStringRef(), retry_header_time)); +} + +bool LLAdaptiveRetryPolicy::getRetryAfter(const LLCore::HttpHeaders *headers, F32& retry_header_time) +{ + if (headers) + { + const std::string *retry_value = headers->find(HTTP_IN_HEADER_RETRY_AFTER.c_str()); + if (retry_value && + getSecondsUntilRetryAfter(*retry_value, retry_header_time)) + { + return true; + } + } + return false; +} + +void LLAdaptiveRetryPolicy::onSuccess() +{ + init(); +} + +void LLAdaptiveRetryPolicy::onFailure(S32 status, const LLSD& headers) +{ + F32 retry_header_time; + bool has_retry_header_time = getRetryAfter(headers,retry_header_time); + onFailureCommon(status, has_retry_header_time, retry_header_time); +} + +void LLAdaptiveRetryPolicy::onFailure(const LLCore::HttpResponse *response) +{ + F32 retry_header_time; + const LLCore::HttpHeaders *headers = response->getHeaders(); + bool has_retry_header_time = getRetryAfter(headers,retry_header_time); + onFailureCommon(response->getStatus().mType, has_retry_header_time, retry_header_time); +} + +void LLAdaptiveRetryPolicy::onFailureCommon(S32 status, bool has_retry_header_time, F32 retry_header_time) +{ + if (!mShouldRetry) + { + llinfos << "keep on failing" << llendl; + return; + } + if (mRetryCount > 0) + { + mDelay = llclamp(mDelay*mBackoffFactor,mMinDelay,mMaxDelay); + } + // Honor server Retry-After header. + // Status 503 may ask us to wait for a certain amount of time before retrying. + F32 wait_time = mDelay; + if (has_retry_header_time) + { + wait_time = retry_header_time; + } + + if (mRetryCount>=mMaxRetries) + { + llinfos << "Too many retries " << mRetryCount << ", will not retry" << llendl; + mShouldRetry = false; + } + if (!isHttpServerErrorStatus(status)) + { + llinfos << "Non-server error " << status << ", will not retry" << llendl; + mShouldRetry = false; + } + if (mShouldRetry) + { + llinfos << "Retry count " << mRetryCount << " should retry after " << wait_time << llendl; + mRetryTimer.reset(); + mRetryTimer.setTimerExpirySec(wait_time); + } + mRetryCount++; +} + + +bool LLAdaptiveRetryPolicy::shouldRetry(F32& seconds_to_wait) const +{ + if (mRetryCount == 0) + { + // Called shouldRetry before any failure. + seconds_to_wait = F32_MAX; + return false; + } + seconds_to_wait = mShouldRetry ? mRetryTimer.getRemainingTimeF32() : F32_MAX; + return mShouldRetry; +} diff --git a/indra/newview/llhttpretrypolicy.h b/indra/newview/llhttpretrypolicy.h new file mode 100755 index 0000000000..1fb0cac03f --- /dev/null +++ b/indra/newview/llhttpretrypolicy.h @@ -0,0 +1,93 @@ +/** + * @file file llhttpretrypolicy.h + * @brief declarations for http retry policy class. + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * 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$ + */ + +#ifndef LL_RETRYPOLICY_H +#define LL_RETRYPOLICY_H + +#include "lltimer.h" +#include "llthread.h" + +#include "llhttpconstants.h" + +// For compatibility with new core http lib. +#include "httpresponse.h" +#include "httpheaders.h" + +// This is intended for use with HTTP Clients/Responders, but is not +// specifically coupled with those classes. +class LLHTTPRetryPolicy: public LLThreadSafeRefCount +{ +public: + LLHTTPRetryPolicy() {} + + virtual ~LLHTTPRetryPolicy() {} + // Call after a sucess to reset retry state. + + virtual void onSuccess() = 0; + // Call once after an HTTP failure to update state. + virtual void onFailure(S32 status, const LLSD& headers) = 0; + + virtual void onFailure(const LLCore::HttpResponse *response) = 0; + + virtual bool shouldRetry(F32& seconds_to_wait) const = 0; +}; + +// Very general policy with geometric back-off after failures, +// up to a maximum delay, and maximum number of retries. +class LLAdaptiveRetryPolicy: public LLHTTPRetryPolicy +{ +public: + LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries); + + // virtual + void onSuccess(); + + // virtual + void onFailure(S32 status, const LLSD& headers); + // virtual + void onFailure(const LLCore::HttpResponse *response); + // virtual + bool shouldRetry(F32& seconds_to_wait) const; + +protected: + void init(); + bool getRetryAfter(const LLSD& headers, F32& retry_header_time); + bool getRetryAfter(const LLCore::HttpHeaders *headers, F32& retry_header_time); + void onFailureCommon(S32 status, bool has_retry_header_time, F32 retry_header_time); + +private: + + const F32 mMinDelay; // delay never less than this value + const F32 mMaxDelay; // delay never exceeds this value + const F32 mBackoffFactor; // delay increases by this factor after each retry, up to mMaxDelay. + const U32 mMaxRetries; // maximum number of times shouldRetry will return true. + F32 mDelay; // current default delay. + U32 mRetryCount; // number of times shouldRetry has been called. + LLTimer mRetryTimer; // time until next retry. + bool mShouldRetry; // Becomes false after too many retries, or the wrong sort of status received, etc. +}; + +#endif diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 59272d721f..8a02dde88c 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -388,16 +388,17 @@ void LLFloaterIMPanel::draw() class LLSessionInviteResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLSessionInviteResponder); public: LLSessionInviteResponder(const LLUUID& session_id) { mSessionID = session_id; } - void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +protected: + void httpFailure() { - llwarns << "Error inviting all agents to session [status:" - << statusNum << "]: " << content << llendl; + llwarns << "Error inviting all agents to session " << dumpResponse() << llendl; //throw something back to the viewer here? } diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 2c20409381..9c0af79923 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -1387,6 +1387,7 @@ void start_deprecated_conference_chat( class LLStartConferenceChatResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLStartConferenceChatResponder); public: LLStartConferenceChatResponder( const LLUUID& temp_session_id, @@ -1400,10 +1401,12 @@ public: mAgents = agents_to_invite; } - virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +protected: + virtual void httpFailure() { //try an "old school" way. - if ( statusNum == 400 ) + // *TODO: What about other error status codes? 4xx 5xx? + if ( getStatus() == HTTP_BAD_REQUEST ) { start_deprecated_conference_chat( mTempSessionID, @@ -1412,8 +1415,7 @@ public: mAgents); } - llwarns << "LLStartConferenceChatResponder error [status:" - << statusNum << "]: " << content << llendl; + llwarns << dumpResponse() << llendl; //else throw an error back to the client? //in theory we should have just have these error strings @@ -1505,6 +1507,7 @@ bool LLIMModel::sendStartSession( class LLViewerChatterBoxInvitationAcceptResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLViewerChatterBoxInvitationAcceptResponder); public: LLViewerChatterBoxInvitationAcceptResponder( const LLUUID& session_id, @@ -1514,8 +1517,15 @@ public: mInvitiationType = invitation_type; } - void result(const LLSD& content) +private: + void httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } if ( gIMMgr) { LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); @@ -1560,19 +1570,17 @@ public: } } - void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) + void httpFailure() { - llwarns << "LLViewerChatterBoxInvitationAcceptResponder error [status:" - << statusNum << "]: " << content << llendl; + llwarns << dumpResponse() << llendl; //throw something back to the viewer here? if ( gIMMgr ) { gIMMgr->clearPendingAgentListUpdates(mSessionID); gIMMgr->clearPendingInvitation(mSessionID); - if ( 404 == statusNum ) + if ( HTTP_NOT_FOUND == getStatus() ) { - std::string error_string; - error_string = "session_does_not_exist_error"; + static const std::string error_string("session_does_not_exist_error"); gIMMgr->showSessionStartError(error_string, mSessionID); } } diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp index 9c6db3676f..6ff16742dd 100644 --- a/indra/newview/llinspectavatar.cpp +++ b/indra/newview/llinspectavatar.cpp @@ -292,11 +292,7 @@ void LLInspectAvatar::processAvatarData(LLAvatarData* data) delete mPropertiesRequest; mPropertiesRequest = NULL; } -/* -prep# - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) - llwarns << "MuteVoiceResponder error [status:" << status << "]: " << content << llendl; - */ + void LLInspectAvatar::updateVolumeSlider() { diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index a5043a30ac..27f35c5946 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -1159,17 +1159,10 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid) { - LLInventoryCategory* cat = model->getCategory(uuid); - if (cat) - { - model->purgeDescendentsOf(uuid); - model->notifyObservers(); - } LLInventoryObject* obj = model->getObject(uuid); if (obj) { - model->purgeObject(uuid); - model->notifyObservers(); + remove_inventory_object(uuid, NULL); } } diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 935fe2b4d0..ae8efeecda 100755 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -450,6 +450,7 @@ const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::ETyp class LLCreateInventoryCategoryResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLCreateInventoryCategoryResponder); public: LLCreateInventoryCategoryResponder(LLInventoryModel* model, void (*callback)(const LLSD&, void*), @@ -460,16 +461,21 @@ public: { } - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +protected: + virtual void httpFailure() { - LL_WARNS("InvAPI") << "CreateInventoryCategory failed [status:" - << status << "]: " << content << LL_ENDL; + LL_WARNS("InvAPI") << dumpResponse() << LL_ENDL; } - virtual void result(const LLSD& content) + virtual void httpSuccess() { //Server has created folder. - + const LLSD& content = getContent(); + if (!content.isMap() || !content.has("folder_id")) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } LLUUID category_id = content["folder_id"].asUUID(); @@ -587,6 +593,40 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, return id; } +// This is optimized for the case that we just want to know whether a +// category has any immediate children meeting a condition, without +// needing to recurse or build up any lists. +bool LLInventoryModel::hasMatchingDirectDescendent(const LLUUID& cat_id, + LLInventoryCollectFunctor& filter) +{ + LLInventoryModel::cat_array_t *cats; + LLInventoryModel::item_array_t *items; + getDirectDescendentsOf(cat_id, cats, items); + if (cats) + { + for (LLInventoryModel::cat_array_t::const_iterator it = cats->begin(); + it != cats->end(); ++it) + { + if (filter(*it,NULL)) + { + return true; + } + } + } + if (items) + { + for (LLInventoryModel::item_array_t::const_iterator it = items->begin(); + it != items->end(); ++it) + { + if (filter(NULL,*it)) + { + return true; + } + } + } + return false; +} + // Starting with the object specified, add it's descendents to the // array provided, but do not add the inventory object specified by // id. There is no guaranteed order. Neither array will be erased @@ -618,8 +658,7 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, cat_array_t& cats, item_array_t& items, BOOL include_trash, - LLInventoryCollectFunctor& add, - BOOL follow_folder_links) + LLInventoryCollectFunctor& add) { // Start with categories if(!include_trash) @@ -646,36 +685,6 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, LLViewerInventoryItem* item = NULL; item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id); - // Follow folder links recursively. Currently never goes more - // than one level deep (for current outfit support) - // Note: if making it fully recursive, need more checking against infinite loops. - if (follow_folder_links && item_array) - { - S32 count = item_array->count(); - for(S32 i = 0; i < count; ++i) - { - item = item_array->get(i); - if (item && item->getActualType() == LLAssetType::AT_LINK_FOLDER) - { - LLViewerInventoryCategory *linked_cat = item->getLinkedCategory(); - if (linked_cat && linked_cat->getPreferredType() != LLFolderType::FT_OUTFIT) - // BAP - was - // LLAssetType::lookupIsEnsembleCategoryType(linked_cat->getPreferredType())) - // Change back once ensemble typing is in place. - { - if(add(linked_cat,NULL)) - { - // BAP should this be added here? May not - // matter if it's only being used in current - // outfit traversal. - cats.put(LLPointer<LLViewerInventoryCategory>(linked_cat)); - } - collectDescendentsIf(linked_cat->getUUID(), cats, items, include_trash, add, FALSE); - } - } - } - } - // Move onto items if(item_array) { @@ -748,6 +757,10 @@ LLInventoryModel::item_array_t LLInventoryModel::collectLinkedItems(const LLUUID const LLUUID& start_folder_id) { item_array_t items; + const LLInventoryObject *obj = getObject(id); + if (!obj || obj->getIsLinkType()) + return items; + LLInventoryModel::cat_array_t cat_array; LLLinkedItemIDMatches is_linked_item_match(id); collectDescendentsIf((start_folder_id == LLUUID::null ? gInventory.getRootFolderID() : start_folder_id), @@ -1123,6 +1136,79 @@ void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* cat, notifyObservers(); } +// Update model after descendents have been purged. +void LLInventoryModel::onDescendentsPurgedFromServer(const LLUUID& object_id) +{ + LLPointer<LLViewerInventoryCategory> cat = getCategory(object_id); + if (cat.notNull()) + { + // do the cache accounting + S32 descendents = cat->getDescendentCount(); + if(descendents > 0) + { + LLInventoryModel::LLCategoryUpdate up(object_id, -descendents); + accountForUpdate(up); + } + + // we know that descendent count is 0, however since the + // accounting may actually not do an update, we should force + // it here. + cat->setDescendentCount(0); + + // unceremoniously remove anything we have locally stored. + LLInventoryModel::cat_array_t categories; + LLInventoryModel::item_array_t items; + collectDescendents(object_id, + categories, + items, + LLInventoryModel::INCLUDE_TRASH); + S32 count = items.count(); + + LLUUID uu_id; + for(S32 i = 0; i < count; ++i) + { + uu_id = items.get(i)->getUUID(); + + // This check prevents the deletion of a previously deleted item. + // This is necessary because deletion is not done in a hierarchical + // order. The current item may have been already deleted as a child + // of its deleted parent. + if (getItem(uu_id)) + { + deleteObject(uu_id); + } + } + + count = categories.count(); + for(S32 i = 0; i < count; ++i) + { + uu_id = categories.get(i)->getUUID(); + if (getCategory(uu_id)) + { + deleteObject(uu_id); + } + } + } +} + +// Update model after an item is confirmed as removed from +// server. Works for categories or items. +void LLInventoryModel::onObjectDeletedFromServer(const LLUUID& object_id) +{ + LLPointer<LLInventoryObject> obj = getObject(object_id); + if(obj) + { + // From item/cat removeFromServer() + LLInventoryModel::LLCategoryUpdate up(obj->getParentUUID(), -1); + accountForUpdate(up); + + // From purgeObject() + LLPreview::hide(object_id); + deleteObject(object_id); + } +} + + // Delete a particular inventory object by ID. void LLInventoryModel::deleteObject(const LLUUID& id) { @@ -1165,22 +1251,16 @@ void LLInventoryModel::deleteObject(const LLUUID& id) mParentChildCategoryTree.erase(id); } addChangedMask(LLInventoryObserver::REMOVE, id); + + // Can't have links to links, so there's no need for this update + // if the item removed is a link. + bool is_link_type = obj->getIsLinkType(); obj = NULL; // delete obj - updateLinkedObjectsFromPurge(id); - gInventory.notifyObservers(); -} - -// Delete a particular inventory item by ID, and remove it from the server. -void LLInventoryModel::purgeObject(const LLUUID &id) -{ - lldebugs << "LLInventoryModel::purgeObject() [ id: " << id << " ] " << llendl; - LLPointer<LLInventoryObject> obj = getObject(id); - if(obj) + if (!is_link_type) { - obj->removeFromServer(); - LLPreview::hide(id); - deleteObject(id); + updateLinkedObjectsFromPurge(id); } + notifyObservers(); } void LLInventoryModel::updateLinkedObjectsFromPurge(const LLUUID &baseobj_id) @@ -1189,129 +1269,19 @@ void LLInventoryModel::updateLinkedObjectsFromPurge(const LLUUID &baseobj_id) // REBUILD is expensive, so clear the current change list first else // everything else on the changelist will also get rebuilt. - gInventory.notifyObservers(); - for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); - iter != item_array.end(); - iter++) + if (item_array.size() > 0) { - const LLViewerInventoryItem *linked_item = (*iter); - const LLUUID &item_id = linked_item->getUUID(); - if (item_id == baseobj_id) continue; - addChangedMask(LLInventoryObserver::REBUILD, item_id); - } - gInventory.notifyObservers(); -} - -// This is a method which collects the descendents of the id -// provided. If the category is not found, no action is -// taken. This method goes through the long winded process of -// cancelling any calling cards, removing server representation of -// folders, items, etc in a fairly efficient manner. -void LLInventoryModel::purgeDescendentsOf(const LLUUID& id) -{ - EHasChildren children = categoryHasChildren(id); - if(children == CHILDREN_NO) - { - llinfos << "Not purging descendents of " << id << llendl; - return; - } - LLPointer<LLViewerInventoryCategory> cat = getCategory(id); - if (cat.notNull()) - { - if (LLClipboard::instance().hasContents() && LLClipboard::instance().isCutMode()) - { - // Something on the clipboard is in "cut mode" and needs to be preserved - llinfos << "LLInventoryModel::purgeDescendentsOf " << cat->getName() - << " iterate and purge non hidden items" << llendl; - cat_array_t* categories; - item_array_t* items; - // Get the list of direct descendants in tha categoy passed as argument - getDirectDescendentsOf(id, categories, items); - std::vector<LLUUID> list_uuids; - // Make a unique list with all the UUIDs of the direct descendants (items and categories are not treated differently) - // Note: we need to do that shallow copy as purging things will invalidate the categories or items lists - for (cat_array_t::const_iterator it = categories->begin(); it != categories->end(); ++it) - { - list_uuids.push_back((*it)->getUUID()); - } - for (item_array_t::const_iterator it = items->begin(); it != items->end(); ++it) - { - list_uuids.push_back((*it)->getUUID()); - } - // Iterate through the list and only purge the UUIDs that are not on the clipboard - for (std::vector<LLUUID>::const_iterator it = list_uuids.begin(); it != list_uuids.end(); ++it) - { - if (!LLClipboard::instance().isOnClipboard(*it)) - { - purgeObject(*it); - } - } - } - else + gInventory.notifyObservers(); + for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); + iter != item_array.end(); + iter++) { - // Fast purge - // do the cache accounting - llinfos << "LLInventoryModel::purgeDescendentsOf " << cat->getName() - << llendl; - S32 descendents = cat->getDescendentCount(); - if(descendents > 0) - { - LLCategoryUpdate up(id, -descendents); - accountForUpdate(up); - } - - // we know that descendent count is 0, however since the - // accounting may actually not do an update, we should force - // it here. - cat->setDescendentCount(0); - - // send it upstream - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("PurgeInventoryDescendents"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("InventoryData"); - msg->addUUID("FolderID", id); - gAgent.sendReliableMessage(); - - // unceremoniously remove anything we have locally stored. - cat_array_t categories; - item_array_t items; - collectDescendents(id, - categories, - items, - INCLUDE_TRASH); - S32 count = items.count(); - - item_map_t::iterator item_map_end = mItemMap.end(); - cat_map_t::iterator cat_map_end = mCategoryMap.end(); - LLUUID uu_id; - - for(S32 i = 0; i < count; ++i) - { - uu_id = items.get(i)->getUUID(); - - // This check prevents the deletion of a previously deleted item. - // This is necessary because deletion is not done in a hierarchical - // order. The current item may have been already deleted as a child - // of its deleted parent. - if (mItemMap.find(uu_id) != item_map_end) - { - deleteObject(uu_id); - } - } - - count = categories.count(); - for(S32 i = 0; i < count; ++i) - { - uu_id = categories.get(i)->getUUID(); - if (mCategoryMap.find(uu_id) != cat_map_end) - { - deleteObject(uu_id); - } - } + const LLViewerInventoryItem *linked_item = (*iter); + const LLUUID &item_id = linked_item->getUUID(); + if (item_id == baseobj_id) continue; + addChangedMask(LLInventoryObserver::REBUILD, item_id); } + gInventory.notifyObservers(); } } @@ -1396,8 +1366,14 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) } // If we get back a normal response, handle it here -void LLInventoryModel::fetchInventoryResponder::result(const LLSD& content) -{ +void LLInventoryModel::fetchInventoryResponder::httpSuccess() +{ + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } start_new_inventory_observer(); /*LLUUID agent_id; @@ -1456,9 +1432,9 @@ void LLInventoryModel::fetchInventoryResponder::result(const LLSD& content) } //If we get back an error (not found, etc...), handle it here -void LLInventoryModel::fetchInventoryResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLInventoryModel::fetchInventoryResponder::httpFailure() { - llwarns << "fetchInventory error [status:" << status << "]: " << content << llendl; + llwarns << dumpResponse() << llendl; gInventory.notifyObservers(); } @@ -3085,8 +3061,7 @@ bool LLInventoryModel::callbackEmptyFolderType(const LLSD& notification, const L if (option == 0) // YES { const LLUUID folder_id = findCategoryUUIDForType(preferred_type); - purgeDescendentsOf(folder_id); - notifyObservers(); + purge_descendents_of(folder_id, NULL); } return false; } @@ -3101,8 +3076,7 @@ void LLInventoryModel::emptyFolderType(const std::string notification, LLFolderT else { const LLUUID folder_id = findCategoryUUIDForType(preferred_type); - purgeDescendentsOf(folder_id); - notifyObservers(); + purge_descendents_of(folder_id, NULL); } } diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 8aac879a93..b7e1888f20 100644..100755 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -81,11 +81,12 @@ public: class fetchInventoryResponder : public LLHTTPClient::Responder { + LOG_CLASS(fetchInventoryResponder); public: fetchInventoryResponder(const LLSD& request_sd) : mRequestSD(request_sd) {}; - void result(const LLSD& content); - void errorWithContent(U32 status, const std::string& reason, const LLSD& content); protected: + virtual void httpSuccess(); + virtual void httpFailure(); LLSD mRequestSD; }; @@ -204,6 +205,9 @@ public: EXCLUDE_TRASH = FALSE, INCLUDE_TRASH = TRUE }; + // Simpler existence test if matches don't actually need to be collected. + bool hasMatchingDirectDescendent(const LLUUID& cat_id, + LLInventoryCollectFunctor& filter); void collectDescendents(const LLUUID& id, cat_array_t& categories, item_array_t& items, @@ -212,8 +216,7 @@ public: cat_array_t& categories, item_array_t& items, BOOL include_trash, - LLInventoryCollectFunctor& add, - BOOL follow_folder_links = FALSE); + LLInventoryCollectFunctor& add); // Collect all items in inventory that are linked to item_id. // Assumes item_id is itself not a linked item. @@ -322,6 +325,14 @@ public: // Delete //-------------------------------------------------------------------- public: + + // Update model after an item is confirmed as removed from + // server. Works for categories or items. + void onObjectDeletedFromServer(const LLUUID& item_id); + + // Update model after all descendents removed from server. + void onDescendentsPurgedFromServer(const LLUUID& object_id); + // Delete a particular inventory object by ID. Will purge one // object from the internal data structures, maintaining a // consistent internal state. No cache accounting, observer @@ -334,17 +345,6 @@ public: /// removeItem() or removeCategory(), whichever is appropriate void removeObject(const LLUUID& object_id); - // Delete a particular inventory object by ID, and delete it from - // the server. Also updates linked items. - void purgeObject(const LLUUID& id); - - // Collects and purges the descendants of the id - // provided. If the category is not found, no action is - // taken. This method goes through the long winded process of - // removing server representation of folders and items while doing - // cache accounting in a fairly efficient manner. This method does - // not notify observers (though maybe it should...) - void purgeDescendentsOf(const LLUUID& id); protected: void updateLinkedObjectsFromPurge(const LLUUID& baseobj_id); diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index f2b39e7186..01b0e647a9 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -1,6 +1,6 @@ /** - * @file llinventorymodel.cpp - * @brief Implementation of the inventory model used to track agent inventory. + * @file llinventorymodelbackgroundfetch.cpp + * @brief Implementation of background fetching of inventory. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code @@ -363,35 +363,40 @@ void LLInventoryModelBackgroundFetch::incrFetchCount(S16 fetching) class LLInventoryModelFetchItemResponder : public LLInventoryModel::fetchInventoryResponder { + LOG_CLASS(LLInventoryModelFetchItemResponder); public: - LLInventoryModelFetchItemResponder(const LLSD& request_sd) : LLInventoryModel::fetchInventoryResponder(request_sd) {}; - void result(const LLSD& content); - void errorWithContent(U32 status, const std::string& reason, const LLSD& content); + LLInventoryModelFetchItemResponder(const LLSD& request_sd) : + LLInventoryModel::fetchInventoryResponder(request_sd) + { + LLInventoryModelBackgroundFetch::instance().incrFetchCount(1); + } +private: + /* virtual */ void httpCompleted() + { + LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); + LLInventoryModel::fetchInventoryResponder::httpCompleted(); + } }; -void LLInventoryModelFetchItemResponder::result( const LLSD& content ) -{ - LLInventoryModel::fetchInventoryResponder::result(content); - LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); -} - -void LLInventoryModelFetchItemResponder::errorWithContent( U32 status, const std::string& reason, const LLSD& content ) -{ - LLInventoryModel::fetchInventoryResponder::errorWithContent(status, reason, content); - LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); -} - - class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::Responder { + LOG_CLASS(LLInventoryModelFetchDescendentsResponder); public: LLInventoryModelFetchDescendentsResponder(const LLSD& request_sd, uuid_vec_t recursive_cats) : mRequestSD(request_sd), mRecursiveCatUUIDs(recursive_cats) - {}; + { + LLInventoryModelBackgroundFetch::instance().incrFetchCount(1); + } //LLInventoryModelFetchDescendentsResponder() {}; - void result(const LLSD& content); - void errorWithContent(U32 status, const std::string& reason, const LLSD& content); +private: + /* virtual */ void httpCompleted() + { + LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); + LLHTTPClient::Responder::httpCompleted(); + } + /* virtual */ void httpSuccess(); + /* virtual */ void httpFailure(); protected: BOOL getIsRecursive(const LLUUID& cat_id) const; private: @@ -400,8 +405,14 @@ private: }; // If we get back a normal response, handle it here. -void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) +void LLInventoryModelFetchDescendentsResponder::httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance(); if (content.has("folders")) { @@ -508,16 +519,15 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) for(LLSD::array_const_iterator folder_it = content["bad_folders"].beginArray(); folder_it != content["bad_folders"].endArray(); ++folder_it) - { + { + // *TODO: Stop copying data LLSD folder_sd = *folder_it; // These folders failed on the dataserver. We probably don't want to retry them. - llinfos << "Folder " << folder_sd["folder_id"].asString() + llwarns << "Folder " << folder_sd["folder_id"].asString() << "Error: " << folder_sd["error"].asString() << llendl; } } - - fetcher->incrFetchCount(-1); if (fetcher->isBulkFetchProcessingComplete()) { @@ -529,21 +539,17 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) } // If we get back an error (not found, etc...), handle it here. -void LLInventoryModelFetchDescendentsResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLInventoryModelFetchDescendentsResponder::httpFailure() { + llwarns << dumpResponse() << llendl; LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance(); - llinfos << "LLInventoryModelFetchDescendentsResponder::error [status:" - << status << "]: " << content << llendl; - - fetcher->incrFetchCount(-1); - - if (status==499) // timed out + if (getStatus()==HTTP_INTERNAL_ERROR) // timed out or curl failure { for(LLSD::array_const_iterator folder_it = mRequestSD["folders"].beginArray(); folder_it != mRequestSD["folders"].endArray(); ++folder_it) - { + { LLSD folder_sd = *folder_it; LLUUID folder_id = folder_sd["folder_id"]; const BOOL recursive = getIsRecursive(folder_id); @@ -586,7 +592,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch() (mFetchTimer.getElapsedTimeF32() < mMinTimeBetweenFetches)) { return; // just bail if we are disconnected - } + } U32 item_count=0; U32 folder_count=0; @@ -689,7 +695,6 @@ void LLInventoryModelBackgroundFetch::bulkFetch() std::string url = region->getCapability("FetchInventoryDescendents2"); if ( !url.empty() ) { - mFetchCount++; if (folder_request_body["folders"].size()) { LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body, recursive_cats); @@ -702,7 +707,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch() LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body_lib, recursive_cats); LLHTTPClient::post(url_lib, folder_request_body_lib, fetcher, 300.0); } - } + } } if (item_count) { @@ -710,39 +715,23 @@ void LLInventoryModelBackgroundFetch::bulkFetch() if (item_request_body.size()) { - mFetchCount++; url = region->getCapability("FetchInventory2"); if (!url.empty()) { LLSD body; - body["agent_id"] = gAgent.getID(); body["items"] = item_request_body; LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body)); } - //else - //{ - // LLMessageSystem* msg = gMessageSystem; - // msg->newMessage("FetchInventory"); - // msg->nextBlock("AgentData"); - // msg->addUUID("AgentID", gAgent.getID()); - // msg->addUUID("SessionID", gAgent.getSessionID()); - // msg->nextBlock("InventoryData"); - // msg->addUUID("OwnerID", mPermissions.getOwner()); - // msg->addUUID("ItemID", mUUID); - // gAgent.sendReliableMessage(); - //} } if (item_request_body_lib.size()) { - mFetchCount++; url = region->getCapability("FetchLib2"); if (!url.empty()) { LLSD body; - body["agent_id"] = gAgent.getID(); body["items"] = item_request_body_lib; LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body)); diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index 0b009b68f7..28e1df725a 100644 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -99,7 +99,7 @@ namespace LLMarketplaceImport bool hasSessionCookie(); bool inProgress(); bool resultPending(); - U32 getResultStatus(); + S32 getResultStatus(); const LLSD& getResults(); bool establishMarketplaceSessionCookie(); @@ -113,7 +113,7 @@ namespace LLMarketplaceImport static bool sImportInProgress = false; static bool sImportPostPending = false; static bool sImportGetPending = false; - static U32 sImportResultStatus = 0; + static S32 sImportResultStatus = 0; static LLSD sImportResults = LLSD::emptyMap(); static LLTimer slmGetTimer; @@ -123,22 +123,22 @@ namespace LLMarketplaceImport class LLImportPostResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLImportPostResponder); public: LLImportPostResponder() : LLCurl::Responder() {} - - void completed(U32 status, const std::string& reason, const LLSD& content) + + protected: + /* virtual */ void httpCompleted() { slmPostTimer.stop(); if (gSavedSettings.getBOOL("InventoryOutboxLogging")) { - llinfos << " SLM POST status: " << status << llendl; - llinfos << " SLM POST reason: " << reason << llendl; - llinfos << " SLM POST content: " << content.asString() << llendl; - - llinfos << " SLM POST timer: " << slmPostTimer.getElapsedTimeF32() << llendl; + llinfos << " SLM [timer:" << slmPostTimer.getElapsedTimeF32() << "] " + << dumpResponse() << llendl; } + S32 status = getStatus(); if ((status == MarketplaceErrorCodes::IMPORT_REDIRECT) || (status == MarketplaceErrorCodes::IMPORT_AUTHENTICATION_ERROR) || (status == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT)) @@ -154,38 +154,35 @@ namespace LLMarketplaceImport sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_DONE); sImportPostPending = false; sImportResultStatus = status; - sImportId = content; + sImportId = getContent(); } }; class LLImportGetResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLImportGetResponder); public: LLImportGetResponder() : LLCurl::Responder() {} - void completedHeader(U32 status, const std::string& reason, const LLSD& content) + protected: + /* virtual */ void httpCompleted() { - const std::string& set_cookie_string = content["set-cookie"].asString(); + const std::string& set_cookie_string = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE); if (!set_cookie_string.empty()) { sMarketplaceCookie = set_cookie_string; } - } - - void completed(U32 status, const std::string& reason, const LLSD& content) - { + slmGetTimer.stop(); if (gSavedSettings.getBOOL("InventoryOutboxLogging")) { - llinfos << " SLM GET status: " << status << llendl; - llinfos << " SLM GET reason: " << reason << llendl; - llinfos << " SLM GET content: " << content.asString() << llendl; - - llinfos << " SLM GET timer: " << slmGetTimer.getElapsedTimeF32() << llendl; + llinfos << " SLM [timer:" << slmGetTimer.getElapsedTimeF32() << "] " + << dumpResponse() << llendl; } + S32 status = getStatus(); if ((status == MarketplaceErrorCodes::IMPORT_AUTHENTICATION_ERROR) || (status == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT)) { @@ -200,7 +197,7 @@ namespace LLMarketplaceImport sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_PROCESSING); sImportGetPending = false; sImportResultStatus = status; - sImportResults = content; + sImportResults = getContent(); } }; @@ -221,7 +218,7 @@ namespace LLMarketplaceImport return (sImportPostPending || sImportGetPending); } - U32 getResultStatus() + S32 getResultStatus() { return sImportResultStatus; } @@ -280,10 +277,11 @@ namespace LLMarketplaceImport // Make the headers for the post LLSD headers = LLSD::emptyMap(); - headers["Accept"] = "*/*"; - headers["Cookie"] = sMarketplaceCookie; - headers["Content-Type"] = "application/llsd+xml"; - headers["User-Agent"] = LLViewerMedia::getCurrentUserAgent(); + headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; + headers[HTTP_OUT_HEADER_COOKIE] = sMarketplaceCookie; + // *TODO: Why are we setting Content-Type for a GET request? + headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_LLSD_XML; + headers[HTTP_OUT_HEADER_USER_AGENT] = LLViewerMedia::getCurrentUserAgent(); if (gSavedSettings.getBOOL("InventoryOutboxLogging")) { @@ -313,11 +311,11 @@ namespace LLMarketplaceImport // Make the headers for the post LLSD headers = LLSD::emptyMap(); - headers["Accept"] = "*/*"; - headers["Connection"] = "Keep-Alive"; - headers["Cookie"] = sMarketplaceCookie; - headers["Content-Type"] = "application/xml"; - headers["User-Agent"] = LLViewerMedia::getCurrentUserAgent(); + headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; + headers[HTTP_OUT_HEADER_CONNECTION] = "Keep-Alive"; + headers[HTTP_OUT_HEADER_COOKIE] = sMarketplaceCookie; + headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_XML; + headers[HTTP_OUT_HEADER_USER_AGENT] = LLViewerMedia::getCurrentUserAgent(); if (gSavedSettings.getBOOL("InventoryOutboxLogging")) { diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 2075aeed63..cb5640b4da 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -52,6 +52,7 @@ #include "llsdutil.h" #include "lllayoutstack.h" #include "lliconctrl.h" +#include "llhttpconstants.h" #include "lltextbox.h" #include "llbutton.h" #include "llcheckboxctrl.h" @@ -576,7 +577,7 @@ void LLMediaCtrl::navigateToLocalPage( const std::string& subdir, const std::str { mCurrentNavUrl = expanded_filename; mMediaSource->setSize(mTextureWidth, mTextureHeight); - mMediaSource->navigateTo(expanded_filename, "text/html", false); + mMediaSource->navigateTo(expanded_filename, HTTP_CONTENT_TEXT_HTML, false); } } @@ -948,7 +949,7 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_ERROR_PAGE" << LL_ENDL; if ( mErrorPageURL.length() > 0 ) { - navigateTo(mErrorPageURL, "text/html"); + navigateTo(mErrorPageURL, HTTP_CONTENT_TEXT_HTML); }; }; break; diff --git a/indra/newview/llmediadataclient.cpp b/indra/newview/llmediadataclient.cpp index e3b46d5d2f..691be13610 100644 --- a/indra/newview/llmediadataclient.cpp +++ b/indra/newview/llmediadataclient.cpp @@ -35,7 +35,7 @@ #include <boost/lexical_cast.hpp> -#include "llhttpstatuscodes.h" +#include "llhttpconstants.h" #include "llsdutil.h" #include "llmediaentry.h" #include "lltextureentry.h" @@ -564,7 +564,7 @@ LLMediaDataClient::Responder::Responder(const request_ptr_t &request) } /*virtual*/ -void LLMediaDataClient::Responder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLMediaDataClient::Responder::httpFailure() { mRequest->stopTracking(); @@ -574,9 +574,17 @@ void LLMediaDataClient::Responder::errorWithContent(U32 status, const std::strin return; } - if (status == HTTP_SERVICE_UNAVAILABLE) + if (getStatus() == HTTP_SERVICE_UNAVAILABLE) { - F32 retry_timeout = mRequest->getRetryTimerDelay(); + F32 retry_timeout; +#if 0 + // *TODO: Honor server Retry-After header. + if (!hasResponseHeader(HTTP_IN_HEADER_RETRY_AFTER) + || !getSecondsUntilRetryAfter(getResponseHeader(HTTP_IN_HEADER_RETRY_AFTER), retry_timeout)) +#endif + { + retry_timeout = mRequest->getRetryTimerDelay(); + } mRequest->incRetryCount(); @@ -594,15 +602,16 @@ void LLMediaDataClient::Responder::errorWithContent(U32 status, const std::strin << mRequest->getRetryCount() << " exceeds " << mRequest->getMaxNumRetries() << ", not retrying" << LL_ENDL; } } + // *TODO: Redirect on 3xx status codes. else { - LL_WARNS("LLMediaDataClient") << *mRequest << " http error [status:" - << status << "]:" << content << ")" << LL_ENDL; + LL_WARNS("LLMediaDataClient") << *mRequest << " http failure " + << dumpResponse() << LL_ENDL; } } /*virtual*/ -void LLMediaDataClient::Responder::result(const LLSD& content) +void LLMediaDataClient::Responder::httpSuccess() { mRequest->stopTracking(); @@ -612,7 +621,7 @@ void LLMediaDataClient::Responder::result(const LLSD& content) return; } - LL_DEBUGS("LLMediaDataClientResponse") << *mRequest << " result : " << ll_print_sd(content) << LL_ENDL; + LL_DEBUGS("LLMediaDataClientResponse") << *mRequest << " " << dumpResponse() << LL_ENDL; } ////////////////////////////////////////////////////////////////////////////////////// @@ -876,7 +885,7 @@ LLMediaDataClient::Responder *LLObjectMediaDataClient::RequestUpdate::createResp /*virtual*/ -void LLObjectMediaDataClient::Responder::result(const LLSD& content) +void LLObjectMediaDataClient::Responder::httpSuccess() { getRequest()->stopTracking(); @@ -886,10 +895,16 @@ void LLObjectMediaDataClient::Responder::result(const LLSD& content) return; } + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } + // This responder is only used for GET requests, not UPDATE. + LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " " << dumpResponse() << LL_ENDL; - LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " GET returned: " << ll_print_sd(content) << LL_ENDL; - // Look for an error if (content.has("error")) { @@ -1003,7 +1018,7 @@ LLMediaDataClient::Responder *LLObjectMediaNavigateClient::RequestNavigate::crea } /*virtual*/ -void LLObjectMediaNavigateClient::Responder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLObjectMediaNavigateClient::Responder::httpFailure() { getRequest()->stopTracking(); @@ -1015,14 +1030,14 @@ void LLObjectMediaNavigateClient::Responder::errorWithContent(U32 status, const // Bounce back (unless HTTP_SERVICE_UNAVAILABLE, in which case call base // class - if (status == HTTP_SERVICE_UNAVAILABLE) + if (getStatus() == HTTP_SERVICE_UNAVAILABLE) { - LLMediaDataClient::Responder::errorWithContent(status, reason, content); + LLMediaDataClient::Responder::httpFailure(); } else { // bounce the face back - LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: http code=" << status << LL_ENDL; + LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: " << dumpResponse() << LL_ENDL; const LLSD &payload = getRequest()->getPayload(); // bounce the face back getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]); @@ -1030,7 +1045,7 @@ void LLObjectMediaNavigateClient::Responder::errorWithContent(U32 status, const } /*virtual*/ -void LLObjectMediaNavigateClient::Responder::result(const LLSD& content) +void LLObjectMediaNavigateClient::Responder::httpSuccess() { getRequest()->stopTracking(); @@ -1040,8 +1055,9 @@ void LLObjectMediaNavigateClient::Responder::result(const LLSD& content) return; } - LL_INFOS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned " << ll_print_sd(content) << LL_ENDL; + LL_INFOS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned " << dumpResponse() << LL_ENDL; + const LLSD& content = getContent(); if (content.has("error")) { const LLSD &error = content["error"]; @@ -1065,6 +1081,6 @@ void LLObjectMediaNavigateClient::Responder::result(const LLSD& content) else { // No action required. - LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " result : " << ll_print_sd(content) << LL_ENDL; + LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " " << dumpResponse() << LL_ENDL; } } diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h index 89e20a28d0..231b883c32 100644 --- a/indra/newview/llmediadataclient.h +++ b/indra/newview/llmediadataclient.h @@ -74,8 +74,9 @@ public: // Abstracts the Cap URL, the request, and the responder class LLMediaDataClient : public LLRefCount { -public: +protected: LOG_CLASS(LLMediaDataClient); +public: const static F32 QUEUE_TIMER_DELAY;// = 1.0; // seconds(s) const static F32 UNAVAILABLE_RETRY_TIMER_DELAY;// = 5.0; // secs @@ -192,14 +193,16 @@ protected: // Responder class Responder : public LLHTTPClient::Responder { + LOG_CLASS(Responder); public: Responder(const request_ptr_t &request); + request_ptr_t &getRequest() { return mRequest; } + + protected: //If we get back an error (not found, etc...), handle it here - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); + virtual void httpFailure(); //If we get back a normal response, handle it here. Default just logs it. - virtual void result(const LLSD& content); - - request_ptr_t &getRequest() { return mRequest; } + virtual void httpSuccess(); private: request_ptr_t mRequest; @@ -287,8 +290,9 @@ private: // MediaDataClient specific for the ObjectMedia cap class LLObjectMediaDataClient : public LLMediaDataClient { -public: +protected: LOG_CLASS(LLObjectMediaDataClient); +public: LLObjectMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY, F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY, U32 max_retries = MAX_RETRIES, @@ -341,10 +345,12 @@ protected: class Responder : public LLMediaDataClient::Responder { + LOG_CLASS(Responder); public: Responder(const request_ptr_t &request) : LLMediaDataClient::Responder(request) {} - virtual void result(const LLSD &content); + protected: + virtual void httpSuccess(); }; private: // The Get/Update data client needs a second queue to avoid object updates starving load-ins. @@ -362,8 +368,9 @@ private: // MediaDataClient specific for the ObjectMediaNavigate cap class LLObjectMediaNavigateClient : public LLMediaDataClient { -public: +protected: LOG_CLASS(LLObjectMediaNavigateClient); +public: // NOTE: from llmediaservice.h static const int ERROR_PERMISSION_DENIED_CODE = 8002; @@ -397,11 +404,13 @@ protected: class Responder : public LLMediaDataClient::Responder { + LOG_CLASS(Responder); public: Responder(const request_ptr_t &request) : LLMediaDataClient::Responder(request) {} - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); - virtual void result(const LLSD &content); + protected: + virtual void httpFailure(); + virtual void httpSuccess(); private: void mediaNavigateBounceBack(); }; diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 17311dd75e..524467a37e 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -28,7 +28,7 @@ #include "apr_pools.h" #include "apr_dso.h" -#include "llhttpstatuscodes.h" +#include "llhttpconstants.h" #include "llmeshrepository.h" #include "llagent.h" @@ -202,6 +202,7 @@ U32 LLMeshRepoThread::sMaxConcurrentRequests = 1; class LLMeshHeaderResponder : public LLCurl::Responder { + LOG_CLASS(LLMeshHeaderResponder); public: LLVolumeParams mMeshParams; bool mProcessed; @@ -230,14 +231,14 @@ public: } } - virtual void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, + virtual void completedRaw(const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer); }; class LLMeshLODResponder : public LLCurl::Responder { + LOG_CLASS(LLMeshLODResponder); public: LLVolumeParams mMeshParams; S32 mLOD; @@ -266,14 +267,14 @@ public: } } - virtual void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, + virtual void completedRaw(const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer); }; class LLMeshSkinInfoResponder : public LLCurl::Responder { + LOG_CLASS(LLMeshSkinInfoResponder); public: LLUUID mMeshID; U32 mRequestedBytes; @@ -291,14 +292,14 @@ public: llassert(mProcessed); } - virtual void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, + virtual void completedRaw(const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer); }; class LLMeshDecompositionResponder : public LLCurl::Responder { + LOG_CLASS(LLMeshDecompositionResponder); public: LLUUID mMeshID; U32 mRequestedBytes; @@ -316,14 +317,14 @@ public: llassert(mProcessed); } - virtual void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, + virtual void completedRaw(const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer); }; class LLMeshPhysicsShapeResponder : public LLCurl::Responder { + LOG_CLASS(LLMeshPhysicsShapeResponder); public: LLUUID mMeshID; U32 mRequestedBytes; @@ -341,8 +342,7 @@ public: llassert(mProcessed); } - virtual void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, + virtual void completedRaw(const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer); }; @@ -398,6 +398,7 @@ void log_upload_error(S32 status, const LLSD& content, std::string stage, std::s class LLWholeModelFeeResponder: public LLCurl::Responder { + LOG_CLASS(LLWholeModelFeeResponder); LLMeshUploadThread* mThread; LLSD mModelData; LLHandle<LLWholeModelFeeObserver> mObserverHandle; @@ -421,21 +422,20 @@ public: } } - virtual void completed(U32 status, - const std::string& reason, - const LLSD& content) +protected: + virtual void httpCompleted() { - LLSD cc = content; + LLSD cc = getContent(); if (gSavedSettings.getS32("MeshUploadFakeErrors")&1) { cc = llsd_from_file("fake_upload_error.xml"); } - + dump_llsd_to_file(cc,make_dump_name("whole_model_fee_response_",dump_num)); LLWholeModelFeeObserver* observer = mObserverHandle.get(); - if (isGoodStatus(status) && + if (isGoodStatus() && cc["state"].asString() == "upload") { mThread->mWholeModelUploadURL = cc["uploader"].asString(); @@ -448,13 +448,14 @@ public: } else { - llwarns << "fee request failed" << llendl; + llwarns << "fee request failed " << dumpResponse() << llendl; + S32 status = getStatus(); log_upload_error(status,cc,"fee",mModelData["name"]); mThread->mWholeModelUploadURL = ""; if (observer) { - observer->setModelPhysicsFeeErrorStatus(status, reason); + observer->setModelPhysicsFeeErrorStatus(status, getReason()); } } } @@ -463,6 +464,7 @@ public: class LLWholeModelUploadResponder: public LLCurl::Responder { + LOG_CLASS(LLWholeModelUploadResponder); LLMeshUploadThread* mThread; LLSD mModelData; LLHandle<LLWholeModelUploadObserver> mObserverHandle; @@ -487,11 +489,10 @@ public: } } - virtual void completed(U32 status, - const std::string& reason, - const LLSD& content) +protected: + virtual void httpCompleted() { - LLSD cc = content; + LLSD cc = getContent(); if (gSavedSettings.getS32("MeshUploadFakeErrors")&2) { cc = llsd_from_file("fake_upload_error.xml"); @@ -503,7 +504,7 @@ public: // requested "mesh" asset type isn't actually the type // of the resultant object, fix it up here. - if (isGoodStatus(status) && + if (isGoodStatus() && cc["state"].asString() == "complete") { mModelData["asset_type"] = "object"; @@ -516,9 +517,9 @@ public: } else { - llwarns << "upload failed" << llendl; + llwarns << "upload failed " << dumpResponse() << llendl; std::string model_name = mModelData["name"].asString(); - log_upload_error(status,cc,"upload",model_name); + log_upload_error(getStatus(),cc,"upload",model_name); if (observer) { @@ -807,7 +808,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) //reading from VFS failed for whatever reason, fetch from sim std::vector<std::string> headers; - headers.push_back("Accept: application/octet-stream"); + headers.push_back(HTTP_OUT_HEADER_ACCEPT + ": " + HTTP_CONTENT_OCTET_STREAM); std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) @@ -889,7 +890,7 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) //reading from VFS failed for whatever reason, fetch from sim std::vector<std::string> headers; - headers.push_back("Accept: application/octet-stream"); + headers.push_back(HTTP_OUT_HEADER_ACCEPT + ": " + HTTP_CONTENT_OCTET_STREAM); std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) @@ -970,7 +971,7 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) //reading from VFS failed for whatever reason, fetch from sim std::vector<std::string> headers; - headers.push_back("Accept: application/octet-stream"); + headers.push_back(HTTP_OUT_HEADER_ACCEPT + ": " + HTTP_CONTENT_OCTET_STREAM); std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) @@ -1051,7 +1052,7 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, U32& c //either cache entry doesn't exist or is corrupt, request header from simulator bool retval = true ; std::vector<std::string> headers; - headers.push_back("Accept: application/octet-stream"); + headers.push_back(HTTP_OUT_HEADER_ACCEPT + ": " + HTTP_CONTENT_OCTET_STREAM); std::string http_url = constructUrl(mesh_params.getSculptID()); if (!http_url.empty()) @@ -1126,7 +1127,7 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, //reading from VFS failed for whatever reason, fetch from sim std::vector<std::string> headers; - headers.push_back("Accept: application/octet-stream"); + headers.push_back(HTTP_OUT_HEADER_ACCEPT + ": " + HTTP_CONTENT_OCTET_STREAM); std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) @@ -1898,10 +1899,10 @@ void LLMeshRepository::cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header) } -void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) +void LLMeshLODResponder::completedRaw(const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) { + S32 status = getStatus(); mProcessed = true; // thread could have already be destroyed during logout @@ -1912,14 +1913,15 @@ void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason, S32 data_size = buffer->countAfter(channels.in(), NULL); + // *TODO: What about 3xx redirect codes? What about status 400 (Bad Request)? if (status < 200 || status > 400) { - llwarns << status << ": " << reason << llendl; + llwarns << dumpResponse() << llendl; } if (data_size < mRequestedBytes) { - if (status == 499 || status == 503) + if (status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE) { //timeout or service unavailable, try again llwarns << "Timeout or service unavailable, retrying." << llendl; LLMeshRepository::sHTTPRetryCount++; @@ -1927,8 +1929,8 @@ void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason, } else { - llassert(status == 499 || status == 503); //intentionally trigger a breakpoint - llwarns << "Unhandled status " << status << llendl; + llassert(status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint + llwarns << "Unhandled status " << dumpResponse() << llendl; } return; } @@ -1962,10 +1964,10 @@ void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason, delete [] data; } -void LLMeshSkinInfoResponder::completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) +void LLMeshSkinInfoResponder::completedRaw(const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) { + S32 status = getStatus(); mProcessed = true; // thread could have already be destroyed during logout @@ -1976,14 +1978,15 @@ void LLMeshSkinInfoResponder::completedRaw(U32 status, const std::string& reason S32 data_size = buffer->countAfter(channels.in(), NULL); + // *TODO: What about 3xx redirect codes? What about status 400 (Bad Request)? if (status < 200 || status > 400) { - llwarns << status << ": " << reason << llendl; + llwarns << dumpResponse() << llendl; } if (data_size < mRequestedBytes) { - if (status == 499 || status == 503) + if (status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE) { //timeout or service unavailable, try again llwarns << "Timeout or service unavailable, retrying." << llendl; LLMeshRepository::sHTTPRetryCount++; @@ -1991,8 +1994,8 @@ void LLMeshSkinInfoResponder::completedRaw(U32 status, const std::string& reason } else { - llassert(status == 499 || status == 503); //intentionally trigger a breakpoint - llwarns << "Unhandled status " << status << llendl; + llassert(status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint + llwarns << "Unhandled status " << dumpResponse() << llendl; } return; } @@ -2026,10 +2029,10 @@ void LLMeshSkinInfoResponder::completedRaw(U32 status, const std::string& reason delete [] data; } -void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) +void LLMeshDecompositionResponder::completedRaw(const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) { + S32 status = getStatus(); mProcessed = true; if( !gMeshRepo.mThread ) @@ -2039,14 +2042,15 @@ void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& r S32 data_size = buffer->countAfter(channels.in(), NULL); + // *TODO: What about 3xx redirect codes? What about status 400 (Bad Request)? if (status < 200 || status > 400) { - llwarns << status << ": " << reason << llendl; + llwarns << dumpResponse() << llendl; } if (data_size < mRequestedBytes) { - if (status == 499 || status == 503) + if (status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE) { //timeout or service unavailable, try again llwarns << "Timeout or service unavailable, retrying." << llendl; LLMeshRepository::sHTTPRetryCount++; @@ -2054,8 +2058,8 @@ void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& r } else { - llassert(status == 499 || status == 503); //intentionally trigger a breakpoint - llwarns << "Unhandled status " << status << llendl; + llassert(status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint + llwarns << "Unhandled status " << dumpResponse() << llendl; } return; } @@ -2089,10 +2093,10 @@ void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& r delete [] data; } -void LLMeshPhysicsShapeResponder::completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) +void LLMeshPhysicsShapeResponder::completedRaw(const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) { + S32 status = getStatus(); mProcessed = true; // thread could have already be destroyed during logout @@ -2103,14 +2107,15 @@ void LLMeshPhysicsShapeResponder::completedRaw(U32 status, const std::string& re S32 data_size = buffer->countAfter(channels.in(), NULL); + // *TODO: What about 3xx redirect codes? What about status 400 (Bad Request)? if (status < 200 || status > 400) { - llwarns << status << ": " << reason << llendl; + llwarns << dumpResponse() << llendl; } if (data_size < mRequestedBytes) { - if (status == 499 || status == 503) + if (status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE) { //timeout or service unavailable, try again llwarns << "Timeout or service unavailable, retrying." << llendl; LLMeshRepository::sHTTPRetryCount++; @@ -2118,8 +2123,8 @@ void LLMeshPhysicsShapeResponder::completedRaw(U32 status, const std::string& re } else { - llassert(status == 499 || status == 503); //intentionally trigger a breakpoint - llwarns << "Unhandled status " << status << llendl; + llassert(status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint + llwarns << "Unhandled status " << dumpResponse() << llendl; } return; } @@ -2153,10 +2158,10 @@ void LLMeshPhysicsShapeResponder::completedRaw(U32 status, const std::string& re delete [] data; } -void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) +void LLMeshHeaderResponder::completedRaw(const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) { + S32 status = getStatus(); mProcessed = true; // thread could have already be destroyed during logout @@ -2165,6 +2170,7 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason, return; } + // *TODO: What about 3xx redirect codes? What about status 400 (Bad Request)? if (status < 200 || status > 400) { //llwarns @@ -2178,9 +2184,9 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason, // and (somewhat more optional than the others) retries // again after some set period of time - llassert(status == 503 || status == 499); + llassert(status == HTTP_SERVICE_UNAVAILABLE || status == HTTP_INTERNAL_ERROR); - if (status == 503 || status == 499) + if (status == HTTP_SERVICE_UNAVAILABLE || status == HTTP_INTERNAL_ERROR) { //retry llwarns << "Timeout or service unavailable, retrying." << llendl; LLMeshRepository::sHTTPRetryCount++; @@ -2192,7 +2198,7 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason, } else { - llwarns << "Unhandled status." << llendl; + llwarns << "Unhandled status " << dumpResponse() << llendl; } } @@ -2214,9 +2220,7 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason, if (!success) { - llwarns - << "Unable to parse mesh header: " - << status << ": " << reason << llendl; + llwarns << "Unable to parse mesh header: " << dumpResponse() << llendl; } else if (data && data_size > 0) { diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index 862e4be203..4f5e07c566 100644 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -95,15 +95,11 @@ class LLClassifiedClickMessageResponder : public LLHTTPClient::Responder { LOG_CLASS(LLClassifiedClickMessageResponder); -public: +protected: // If we get back an error (not found, etc...), handle it here - virtual void errorWithContent( - U32 status, - const std::string& reason, - const LLSD& content) + virtual void httpFailure() { - llwarns << "Sending click message failed (" << status << "): [" << reason << "]" << llendl; - llwarns << "Content: [" << content << "]" << llendl; + llwarns << "Sending click message failed " << dumpResponse() << llendl; } }; diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index e71dba5cae..580e31591c 100644..100755 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -1079,10 +1079,15 @@ void LLPanelEditWearable::saveChanges(bool force_save_as) if (force_save_as) { - // the name of the wearable has changed, re-save wearable with new name - LLAppearanceMgr::instance().removeCOFItemLinks(mWearablePtr->getItemID()); + // FIXME race condition if removeCOFItemLinks does not + // complete immediately. Looks like we're counting on the + // fact that updateAppearanceFromCOF will get called after + // we exit customize mode. + + // the name of the wearable has changed, re-save wearable with new name + LLAppearanceMgr::instance().removeCOFItemLinks(mWearablePtr->getItemID()); gAgentWearables.saveWearableAs(mWearablePtr->getType(), index, new_name, description, FALSE); - mNameEditor->setText(mWearableItem->getName()); + mNameEditor->setText(mWearableItem->getName()); } else { @@ -1091,6 +1096,14 @@ void LLPanelEditWearable::saveChanges(bool force_save_as) // version so texture baking service knows appearance has changed. if (link_item) { + // FIXME - two link-modifying calls here plus one + // inventory change request, none of which use a + // callback. When does a new appearance request go out + // and how is it synced with these changes? As above, + // we seem to be implicitly depending on + // updateAppearanceFromCOF() to be called when we + // exit customize mode. + // Create new link link_inventory_item( gAgent.getID(), link_item->getLinkedUUID(), @@ -1100,9 +1113,9 @@ void LLPanelEditWearable::saveChanges(bool force_save_as) LLAssetType::AT_LINK, NULL); // Remove old link - gInventory.purgeObject(link_item->getUUID()); + remove_inventory_item(link_item->getUUID(), NULL); } - gAgentWearables.saveWearable(mWearablePtr->getType(), index, TRUE, new_name); + gAgentWearables.saveWearable(mWearablePtr->getType(), index, TRUE, new_name); } diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index 88400e4ef2..d1a18fdc8c 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -527,7 +527,7 @@ void LLLandmarksPanel::setParcelID(const LLUUID& parcel_id) } // virtual -void LLLandmarksPanel::setErrorStatus(U32 status, const std::string& reason) +void LLLandmarksPanel::setErrorStatus(S32 status, const std::string& reason) { llwarns << "Can't handle remote parcel request."<< " Http Status: "<< status << ". Reason : "<< reason<<llendl; } diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h index 8fae0f0b67..a39338304c 100644 --- a/indra/newview/llpanellandmarks.h +++ b/indra/newview/llpanellandmarks.h @@ -106,7 +106,7 @@ protected: //LLRemoteParcelInfoObserver interface /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); /*virtual*/ void setParcelID(const LLUUID& parcel_id); - /*virtual*/ void setErrorStatus(U32 status, const std::string& reason); + /*virtual*/ void setErrorStatus(S32 status, const std::string& reason); private: void initFavoritesInventoryPanel(); diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index bcb90bcb56..c4ba097914 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -437,7 +437,7 @@ void LLPanelLogin::showLoginWidgets() sInstance->reshapeBrowser(); // *TODO: Append all the usual login parameters, like first_login=Y etc. std::string splash_screen_url = LLGridManager::getInstance()->getLoginPage(); - web_browser->navigateTo( splash_screen_url, "text/html" ); + web_browser->navigateTo( splash_screen_url, HTTP_CONTENT_TEXT_HTML ); LLUICtrl* username_combo = sInstance->getChild<LLUICtrl>("username_combo"); username_combo->setFocus(TRUE); } @@ -791,7 +791,7 @@ void LLPanelLogin::loadLoginPage() if (web_browser->getCurrentNavUrl() != login_uri.asString()) { LL_DEBUGS("AppInit") << "loading: " << login_uri << LL_ENDL; - web_browser->navigateTo( login_uri.asString(), "text/html" ); + web_browser->navigateTo( login_uri.asString(), HTTP_CONTENT_TEXT_HTML ); } } diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index c09d4393c8..0e3057dcad 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -1184,12 +1184,12 @@ BOOL LLPanelOutfitEdit::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, * second argument is used to delay the appearance update until all dragged items * are added to optimize user experience. */ - LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID(), false); + LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID()); } else { // if asset id is not available for the item we must wear it immediately (attachments only) - LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID(), true); + LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID(), new LLUpdateAppearanceAndEditWearableOnDestroy(item->getUUID())); } } diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp index f90236f6f2..d6c927ab58 100644..100755 --- a/indra/newview/llpaneloutfitsinventory.cpp +++ b/indra/newview/llpaneloutfitsinventory.cpp @@ -76,7 +76,8 @@ BOOL LLPanelOutfitsInventory::postBuild() // Fetch your outfits folder so that the links are in memory. // ( This is only necessary if we want to show a warning if a user deletes an item that has a // a link in an outfit, see "ConfirmItemDeleteHasLinks". ) - const LLUUID &outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTFIT, false); + + const LLUUID &outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); if (outfits_cat.notNull()) { LLInventoryModelBackgroundFetch::instance().start(outfits_cat); diff --git a/indra/newview/llpanelpick.h b/indra/newview/llpanelpick.h index 3c1f14759c..7a8bd66fcf 100644 --- a/indra/newview/llpanelpick.h +++ b/indra/newview/llpanelpick.h @@ -86,7 +86,7 @@ public: //This stuff we got from LLRemoteParcelObserver, in the last one we intentionally do nothing /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); /*virtual*/ void setParcelID(const LLUUID& parcel_id) { mParcelId = parcel_id; } - /*virtual*/ void setErrorStatus(U32 status, const std::string& reason) {}; + /*virtual*/ void setErrorStatus(S32 status, const std::string& reason) {}; protected: diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp index 4ae0c0eb12..4e7c5f6ed2 100644 --- a/indra/newview/llpanelplaceinfo.cpp +++ b/indra/newview/llpanelplaceinfo.cpp @@ -169,15 +169,15 @@ void LLPanelPlaceInfo::displayParcelInfo(const LLUUID& region_id, } // virtual -void LLPanelPlaceInfo::setErrorStatus(U32 status, const std::string& reason) +void LLPanelPlaceInfo::setErrorStatus(S32 status, const std::string& reason) { // We only really handle 404 and 499 errors std::string error_text; - if(status == 404) + if(status == HTTP_NOT_FOUND) { error_text = getString("server_error_text"); } - else if(status == 499) + else if(status == HTTP_INTERNAL_ERROR) { error_text = getString("server_forbidden_text"); } diff --git a/indra/newview/llpanelplaceinfo.h b/indra/newview/llpanelplaceinfo.h index 64f0b6b550..30327378ef 100644 --- a/indra/newview/llpanelplaceinfo.h +++ b/indra/newview/llpanelplaceinfo.h @@ -86,7 +86,7 @@ public: void displayParcelInfo(const LLUUID& region_id, const LLVector3d& pos_global); - /*virtual*/ void setErrorStatus(U32 status, const std::string& reason); + /*virtual*/ void setErrorStatus(S32 status, const std::string& reason); /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 6c2a01fc82..730df2ea23 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -217,7 +217,7 @@ public: LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(parcel_id); } } - /*virtual*/ void setErrorStatus(U32 status, const std::string& reason) + /*virtual*/ void setErrorStatus(S32 status, const std::string& reason) { llerrs << "Can't complete remote parcel request. Http Status: " << status << ". Reason : " << reason << llendl; diff --git a/indra/newview/llpathfindingmanager.cpp b/indra/newview/llpathfindingmanager.cpp index c277359133..a9c755de35 100644 --- a/indra/newview/llpathfindingmanager.cpp +++ b/indra/newview/llpathfindingmanager.cpp @@ -103,17 +103,16 @@ LLHTTPRegistration<LLAgentStateChangeNode> gHTTPRegistrationAgentStateChangeNode class NavMeshStatusResponder : public LLHTTPClient::Responder { + LOG_CLASS(NavMeshStatusResponder); public: - NavMeshStatusResponder(const std::string &pCapabilityURL, LLViewerRegion *pRegion, bool pIsGetStatusOnly); + NavMeshStatusResponder(LLViewerRegion *pRegion, bool pIsGetStatusOnly); virtual ~NavMeshStatusResponder(); - virtual void result(const LLSD &pContent); - virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); - protected: + virtual void httpSuccess(); + virtual void httpFailure(); private: - std::string mCapabilityURL; LLViewerRegion *mRegion; LLUUID mRegionUUID; bool mIsGetStatusOnly; @@ -125,17 +124,16 @@ private: class NavMeshResponder : public LLHTTPClient::Responder { + LOG_CLASS(NavMeshResponder); public: - NavMeshResponder(const std::string &pCapabilityURL, U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr); + NavMeshResponder(U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr); virtual ~NavMeshResponder(); - virtual void result(const LLSD &pContent); - virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); - protected: + virtual void httpSuccess(); + virtual void httpFailure(); private: - std::string mCapabilityURL; U32 mNavMeshVersion; LLPathfindingNavMeshPtr mNavMeshPtr; }; @@ -146,17 +144,14 @@ private: class AgentStateResponder : public LLHTTPClient::Responder { + LOG_CLASS(AgentStateResponder); public: - AgentStateResponder(const std::string &pCapabilityURL); + AgentStateResponder(); virtual ~AgentStateResponder(); - virtual void result(const LLSD &pContent); - virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); - protected: - -private: - std::string mCapabilityURL; + virtual void httpSuccess(); + virtual void httpFailure(); }; @@ -165,17 +160,16 @@ private: //--------------------------------------------------------------------------- class NavMeshRebakeResponder : public LLHTTPClient::Responder { + LOG_CLASS(NavMeshRebakeResponder); public: - NavMeshRebakeResponder(const std::string &pCapabilityURL, LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback); + NavMeshRebakeResponder(LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback); virtual ~NavMeshRebakeResponder(); - virtual void result(const LLSD &pContent); - virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); - protected: + virtual void httpSuccess(); + virtual void httpFailure(); private: - std::string mCapabilityURL; LLPathfindingManager::rebake_navmesh_callback_t mRebakeNavMeshCallback; }; @@ -190,11 +184,9 @@ public: virtual ~LinksetsResponder(); void handleObjectLinksetsResult(const LLSD &pContent); - void handleObjectLinksetsError(U32 pStatus, const std::string &pReason, - const LLSD& pContent, const std::string &pURL); + void handleObjectLinksetsError(); void handleTerrainLinksetsResult(const LLSD &pContent); - void handleTerrainLinksetsError(U32 pStatus, const std::string &pReason, - const LLSD& pContent, const std::string &pURL); + void handleTerrainLinksetsError(); protected: @@ -227,17 +219,16 @@ typedef boost::shared_ptr<LinksetsResponder> LinksetsResponderPtr; class ObjectLinksetsResponder : public LLHTTPClient::Responder { + LOG_CLASS(ObjectLinksetsResponder); public: - ObjectLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr); + ObjectLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr); virtual ~ObjectLinksetsResponder(); - virtual void result(const LLSD &pContent); - virtual void errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent); - protected: + virtual void httpSuccess(); + virtual void httpFailure(); private: - std::string mCapabilityURL; LinksetsResponderPtr mLinksetsResponsderPtr; }; @@ -247,17 +238,16 @@ private: class TerrainLinksetsResponder : public LLHTTPClient::Responder { + LOG_CLASS(TerrainLinksetsResponder); public: - TerrainLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr); + TerrainLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr); virtual ~TerrainLinksetsResponder(); - virtual void result(const LLSD &pContent); - virtual void errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent); - protected: + virtual void httpSuccess(); + virtual void httpFailure(); private: - std::string mCapabilityURL; LinksetsResponderPtr mLinksetsResponsderPtr; }; @@ -267,17 +257,16 @@ private: class CharactersResponder : public LLHTTPClient::Responder { + LOG_CLASS(TerrainLinksetsResponder); public: - CharactersResponder(const std::string &pCapabilityURL, LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback); + CharactersResponder(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback); virtual ~CharactersResponder(); - virtual void result(const LLSD &pContent); - virtual void errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent); - protected: + virtual void httpSuccess(); + virtual void httpFailure(); private: - std::string mCapabilityURL; LLPathfindingManager::request_id_t mRequestId; LLPathfindingManager::object_request_callback_t mCharactersCallback; }; @@ -364,7 +353,7 @@ void LLPathfindingManager::requestGetNavMeshForRegion(LLViewerRegion *pRegion, b std::string navMeshStatusURL = getNavMeshStatusURLForRegion(pRegion); llassert(!navMeshStatusURL.empty()); navMeshPtr->handleNavMeshCheckVersion(); - LLHTTPClient::ResponderPtr navMeshStatusResponder = new NavMeshStatusResponder(navMeshStatusURL, pRegion, pIsGetStatusOnly); + LLHTTPClient::ResponderPtr navMeshStatusResponder = new NavMeshStatusResponder(pRegion, pIsGetStatusOnly); LLHTTPClient::get(navMeshStatusURL, navMeshStatusResponder); } } @@ -398,12 +387,12 @@ void LLPathfindingManager::requestGetLinksets(request_id_t pRequestId, object_re bool doRequestTerrain = isAllowViewTerrainProperties(); LinksetsResponderPtr linksetsResponderPtr(new LinksetsResponder(pRequestId, pLinksetsCallback, true, doRequestTerrain)); - LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(objectLinksetsURL, linksetsResponderPtr); + LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(linksetsResponderPtr); LLHTTPClient::get(objectLinksetsURL, objectLinksetsResponder); if (doRequestTerrain) { - LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(terrainLinksetsURL, linksetsResponderPtr); + LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(linksetsResponderPtr); LLHTTPClient::get(terrainLinksetsURL, terrainLinksetsResponder); } } @@ -447,13 +436,13 @@ void LLPathfindingManager::requestSetLinksets(request_id_t pRequestId, const LLP if (!objectPostData.isUndefined()) { - LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(objectLinksetsURL, linksetsResponderPtr); + LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(linksetsResponderPtr); LLHTTPClient::put(objectLinksetsURL, objectPostData, objectLinksetsResponder); } if (!terrainPostData.isUndefined()) { - LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(terrainLinksetsURL, linksetsResponderPtr); + LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(linksetsResponderPtr); LLHTTPClient::put(terrainLinksetsURL, terrainPostData, terrainLinksetsResponder); } } @@ -486,7 +475,7 @@ void LLPathfindingManager::requestGetCharacters(request_id_t pRequestId, object_ { pCharactersCallback(pRequestId, kRequestStarted, emptyCharacterListPtr); - LLHTTPClient::ResponderPtr charactersResponder = new CharactersResponder(charactersURL, pRequestId, pCharactersCallback); + LLHTTPClient::ResponderPtr charactersResponder = new CharactersResponder(pRequestId, pCharactersCallback); LLHTTPClient::get(charactersURL, charactersResponder); } } @@ -519,7 +508,7 @@ void LLPathfindingManager::requestGetAgentState() { std::string agentStateURL = getAgentStateURLForRegion(currentRegion); llassert(!agentStateURL.empty()); - LLHTTPClient::ResponderPtr responder = new AgentStateResponder(agentStateURL); + LLHTTPClient::ResponderPtr responder = new AgentStateResponder(); LLHTTPClient::get(agentStateURL, responder); } } @@ -543,7 +532,7 @@ void LLPathfindingManager::requestRebakeNavMesh(rebake_navmesh_callback_t pRebak llassert(!navMeshStatusURL.empty()); LLSD postData; postData["command"] = "rebuild"; - LLHTTPClient::ResponderPtr responder = new NavMeshRebakeResponder(navMeshStatusURL, pRebakeNavMeshCallback); + LLHTTPClient::ResponderPtr responder = new NavMeshRebakeResponder(pRebakeNavMeshCallback); LLHTTPClient::post(navMeshStatusURL, postData, responder); } } @@ -565,7 +554,7 @@ void LLPathfindingManager::sendRequestGetNavMeshForRegion(LLPathfindingNavMeshPt else { navMeshPtr->handleNavMeshStart(pNavMeshStatus); - LLHTTPClient::ResponderPtr responder = new NavMeshResponder(navMeshURL, pNavMeshStatus.getVersion(), navMeshPtr); + LLHTTPClient::ResponderPtr responder = new NavMeshResponder(pNavMeshStatus.getVersion(), navMeshPtr); LLSD postData; LLHTTPClient::post(navMeshURL, postData, responder); @@ -779,9 +768,8 @@ void LLAgentStateChangeNode::post(ResponsePtr pResponse, const LLSD &pContext, c // NavMeshStatusResponder //--------------------------------------------------------------------------- -NavMeshStatusResponder::NavMeshStatusResponder(const std::string &pCapabilityURL, LLViewerRegion *pRegion, bool pIsGetStatusOnly) +NavMeshStatusResponder::NavMeshStatusResponder(LLViewerRegion *pRegion, bool pIsGetStatusOnly) : LLHTTPClient::Responder(), - mCapabilityURL(pCapabilityURL), mRegion(pRegion), mRegionUUID(), mIsGetStatusOnly(pIsGetStatusOnly) @@ -796,15 +784,15 @@ NavMeshStatusResponder::~NavMeshStatusResponder() { } -void NavMeshStatusResponder::result(const LLSD &pContent) +void NavMeshStatusResponder::httpSuccess() { - LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID, pContent); + LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID, getContent()); LLPathfindingManager::getInstance()->handleNavMeshStatusRequest(navMeshStatus, mRegion, mIsGetStatusOnly); } -void NavMeshStatusResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent) +void NavMeshStatusResponder::httpFailure() { - llwarns << "NavMeshStatusResponder error [status:" << pStatus << "]: " << pContent << llendl; + llwarns << dumpResponse() << llendl; LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID); LLPathfindingManager::getInstance()->handleNavMeshStatusRequest(navMeshStatus, mRegion, mIsGetStatusOnly); } @@ -813,9 +801,8 @@ void NavMeshStatusResponder::errorWithContent(U32 pStatus, const std::string& pR // NavMeshResponder //--------------------------------------------------------------------------- -NavMeshResponder::NavMeshResponder(const std::string &pCapabilityURL, U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr) +NavMeshResponder::NavMeshResponder(U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr) : LLHTTPClient::Responder(), - mCapabilityURL(pCapabilityURL), mNavMeshVersion(pNavMeshVersion), mNavMeshPtr(pNavMeshPtr) { @@ -825,23 +812,23 @@ NavMeshResponder::~NavMeshResponder() { } -void NavMeshResponder::result(const LLSD &pContent) +void NavMeshResponder::httpSuccess() { - mNavMeshPtr->handleNavMeshResult(pContent, mNavMeshVersion); + mNavMeshPtr->handleNavMeshResult(getContent(), mNavMeshVersion); } -void NavMeshResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent) +void NavMeshResponder::httpFailure() { - mNavMeshPtr->handleNavMeshError(pStatus, pReason, pContent, mCapabilityURL, mNavMeshVersion); + llwarns << dumpResponse() << llendl; + mNavMeshPtr->handleNavMeshError(mNavMeshVersion); } //--------------------------------------------------------------------------- // AgentStateResponder //--------------------------------------------------------------------------- -AgentStateResponder::AgentStateResponder(const std::string &pCapabilityURL) +AgentStateResponder::AgentStateResponder() : LLHTTPClient::Responder() -, mCapabilityURL(pCapabilityURL) { } @@ -849,17 +836,18 @@ AgentStateResponder::~AgentStateResponder() { } -void AgentStateResponder::result(const LLSD &pContent) +void AgentStateResponder::httpSuccess() { + const LLSD& pContent = getContent(); llassert(pContent.has(AGENT_STATE_CAN_REBAKE_REGION_FIELD)); llassert(pContent.get(AGENT_STATE_CAN_REBAKE_REGION_FIELD).isBoolean()); BOOL canRebakeRegion = pContent.get(AGENT_STATE_CAN_REBAKE_REGION_FIELD).asBoolean(); LLPathfindingManager::getInstance()->handleAgentState(canRebakeRegion); } -void AgentStateResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent) +void AgentStateResponder::httpFailure() { - llwarns << "AgentStateResponder error [status:" << pStatus << "]: " << pContent << llendl; + llwarns << dumpResponse() << llendl; LLPathfindingManager::getInstance()->handleAgentState(FALSE); } @@ -867,9 +855,8 @@ void AgentStateResponder::errorWithContent(U32 pStatus, const std::string &pReas //--------------------------------------------------------------------------- // navmesh rebake responder //--------------------------------------------------------------------------- -NavMeshRebakeResponder::NavMeshRebakeResponder(const std::string &pCapabilityURL, LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback) +NavMeshRebakeResponder::NavMeshRebakeResponder(LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback) : LLHTTPClient::Responder(), - mCapabilityURL(pCapabilityURL), mRebakeNavMeshCallback(pRebakeNavMeshCallback) { } @@ -878,14 +865,14 @@ NavMeshRebakeResponder::~NavMeshRebakeResponder() { } -void NavMeshRebakeResponder::result(const LLSD &pContent) +void NavMeshRebakeResponder::httpSuccess() { mRebakeNavMeshCallback(true); } -void NavMeshRebakeResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent) +void NavMeshRebakeResponder::httpFailure() { - llwarns << "NavMeshRebakeResponder error [status:" << pStatus << "]: " << pContent << llendl; + llwarns << dumpResponse() << llendl; mRebakeNavMeshCallback(false); } @@ -918,11 +905,8 @@ void LinksetsResponder::handleObjectLinksetsResult(const LLSD &pContent) } } -void LinksetsResponder::handleObjectLinksetsError(U32 pStatus, const std::string &pReason, - const LLSD& pContent, const std::string &pURL) +void LinksetsResponder::handleObjectLinksetsError() { - llwarns << "LinksetsResponder object linksets error with request to URL '" << pURL << "' [status:" - << pStatus << "]: " << pContent << llendl; mObjectMessagingState = kReceivedError; if (mTerrainMessagingState != kWaiting) { @@ -941,11 +925,8 @@ void LinksetsResponder::handleTerrainLinksetsResult(const LLSD &pContent) } } -void LinksetsResponder::handleTerrainLinksetsError(U32 pStatus, const std::string &pReason, - const LLSD& pContent, const std::string &pURL) +void LinksetsResponder::handleTerrainLinksetsError() { - llwarns << "LinksetsResponder terrain linksets error with request to URL '" << pURL << "' [status:" - << pStatus << "]: " << pContent << llendl; mTerrainMessagingState = kReceivedError; if (mObjectMessagingState != kWaiting) { @@ -979,9 +960,8 @@ void LinksetsResponder::sendCallback() // ObjectLinksetsResponder //--------------------------------------------------------------------------- -ObjectLinksetsResponder::ObjectLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr) +ObjectLinksetsResponder::ObjectLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr) : LLHTTPClient::Responder(), - mCapabilityURL(pCapabilityURL), mLinksetsResponsderPtr(pLinksetsResponsderPtr) { } @@ -990,23 +970,23 @@ ObjectLinksetsResponder::~ObjectLinksetsResponder() { } -void ObjectLinksetsResponder::result(const LLSD &pContent) +void ObjectLinksetsResponder::httpSuccess() { - mLinksetsResponsderPtr->handleObjectLinksetsResult(pContent); + mLinksetsResponsderPtr->handleObjectLinksetsResult(getContent()); } -void ObjectLinksetsResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent) +void ObjectLinksetsResponder::httpFailure() { - mLinksetsResponsderPtr->handleObjectLinksetsError(pStatus, pReason, pContent, mCapabilityURL); + llwarns << dumpResponse() << llendl; + mLinksetsResponsderPtr->handleObjectLinksetsError(); } //--------------------------------------------------------------------------- // TerrainLinksetsResponder //--------------------------------------------------------------------------- -TerrainLinksetsResponder::TerrainLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr) +TerrainLinksetsResponder::TerrainLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr) : LLHTTPClient::Responder(), - mCapabilityURL(pCapabilityURL), mLinksetsResponsderPtr(pLinksetsResponsderPtr) { } @@ -1015,23 +995,23 @@ TerrainLinksetsResponder::~TerrainLinksetsResponder() { } -void TerrainLinksetsResponder::result(const LLSD &pContent) +void TerrainLinksetsResponder::httpSuccess() { - mLinksetsResponsderPtr->handleTerrainLinksetsResult(pContent); + mLinksetsResponsderPtr->handleTerrainLinksetsResult(getContent()); } -void TerrainLinksetsResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent) +void TerrainLinksetsResponder::httpFailure() { - mLinksetsResponsderPtr->handleTerrainLinksetsError(pStatus, pReason, pContent, mCapabilityURL); + llwarns << dumpResponse() << llendl; + mLinksetsResponsderPtr->handleTerrainLinksetsError(); } //--------------------------------------------------------------------------- // CharactersResponder //--------------------------------------------------------------------------- -CharactersResponder::CharactersResponder(const std::string &pCapabilityURL, LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback) +CharactersResponder::CharactersResponder(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback) : LLHTTPClient::Responder(), - mCapabilityURL(pCapabilityURL), mRequestId(pRequestId), mCharactersCallback(pCharactersCallback) { @@ -1041,15 +1021,15 @@ CharactersResponder::~CharactersResponder() { } -void CharactersResponder::result(const LLSD &pContent) +void CharactersResponder::httpSuccess() { - LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList(pContent)); + LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList(getContent())); mCharactersCallback(mRequestId, LLPathfindingManager::kRequestCompleted, characterListPtr); } -void CharactersResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent) +void CharactersResponder::httpFailure() { - llwarns << "CharactersResponder error [status:" << pStatus << "]: " << pContent << llendl; + llwarns << dumpResponse() << llendl; LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList()); mCharactersCallback(mRequestId, LLPathfindingManager::kRequestError, characterListPtr); diff --git a/indra/newview/llpathfindingnavmesh.cpp b/indra/newview/llpathfindingnavmesh.cpp index 0c23e5ac92..555105cf40 100644 --- a/indra/newview/llpathfindingnavmesh.cpp +++ b/indra/newview/llpathfindingnavmesh.cpp @@ -184,10 +184,8 @@ void LLPathfindingNavMesh::handleNavMeshError() setRequestStatus(kNavMeshRequestError); } -void LLPathfindingNavMesh::handleNavMeshError(U32 pStatus, const std::string &pReason, const LLSD& pContent, const std::string &pURL, U32 pNavMeshVersion) +void LLPathfindingNavMesh::handleNavMeshError(U32 pNavMeshVersion) { - llwarns << "LLPathfindingNavMesh error with request to URL '" << pURL << "' [status:" - << pStatus << "]: " << pContent << llendl; if (mNavMeshStatus.getVersion() == pNavMeshVersion) { handleNavMeshError(); diff --git a/indra/newview/llpathfindingnavmesh.h b/indra/newview/llpathfindingnavmesh.h index b872ccad7c..87f32b8d56 100644 --- a/indra/newview/llpathfindingnavmesh.h +++ b/indra/newview/llpathfindingnavmesh.h @@ -74,7 +74,7 @@ public: void handleNavMeshResult(const LLSD &pContent, U32 pNavMeshVersion); void handleNavMeshNotEnabled(); void handleNavMeshError(); - void handleNavMeshError(U32 pStatus, const std::string &pReason, const LLSD& pContent, const std::string &pURL, U32 pNavMeshVersion); + void handleNavMeshError(U32 pNavMeshVersion); protected: diff --git a/indra/newview/llpreview.cpp b/indra/newview/llpreview.cpp index 04934b13f1..452efad291 100644 --- a/indra/newview/llpreview.cpp +++ b/indra/newview/llpreview.cpp @@ -401,13 +401,6 @@ void LLPreview::onDiscardBtn(void* data) self->mForceClose = TRUE; self->closeFloater(); - // Delete the item entirely - /* - item->removeFromServer(); - gInventory.deleteObject(item->getUUID()); - gInventory.notifyObservers(); - */ - // Move the item to the trash const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); if (item->getParentUUID() != trash_id) diff --git a/indra/newview/llproductinforequest.cpp b/indra/newview/llproductinforequest.cpp index 1390000fc5..94a6389f8a 100644 --- a/indra/newview/llproductinforequest.cpp +++ b/indra/newview/llproductinforequest.cpp @@ -35,18 +35,24 @@ class LLProductInfoRequestResponder : public LLHTTPClient::Responder { -public: + LOG_CLASS(LLProductInfoRequestResponder); +private: //If we get back a normal response, handle it here - virtual void result(const LLSD& content) + /* virtual */ void httpSuccess() { - LLProductInfoRequestManager::instance().setSkuDescriptions(content); + const LLSD& content = getContent(); + if (!content.isArray()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } + LLProductInfoRequestManager::instance().setSkuDescriptions(getContent()); } //If we get back an error (not found, etc...), handle it here - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) + /* virtual */ void httpFailure() { - llwarns << "LLProductInfoRequest error [status:" - << status << ":] " << content << llendl; + llwarns << dumpResponse() << llendl; } }; diff --git a/indra/newview/llremoteparcelrequest.cpp b/indra/newview/llremoteparcelrequest.cpp index 500dec7ee5..7418bbf615 100644 --- a/indra/newview/llremoteparcelrequest.cpp +++ b/indra/newview/llremoteparcelrequest.cpp @@ -47,9 +47,15 @@ LLRemoteParcelRequestResponder::LLRemoteParcelRequestResponder(LLHandle<LLRemote //If we get back a normal response, handle it here //virtual -void LLRemoteParcelRequestResponder::result(const LLSD& content) +void LLRemoteParcelRequestResponder::httpSuccess() { - LLUUID parcel_id = content["parcel_id"]; + const LLSD& content = getContent(); + if (!content.isMap() || !content.has("parcel_id")) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } + LLUUID parcel_id = getContent()["parcel_id"]; // Panel inspecting the information may be closed and destroyed // before this response is received. @@ -62,17 +68,16 @@ void LLRemoteParcelRequestResponder::result(const LLSD& content) //If we get back an error (not found, etc...), handle it here //virtual -void LLRemoteParcelRequestResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLRemoteParcelRequestResponder::httpFailure() { - llwarns << "LLRemoteParcelRequest error [status:" - << status << "]: " << content << llendl; + llwarns << dumpResponse() << llendl; // Panel inspecting the information may be closed and destroyed // before this response is received. LLRemoteParcelInfoObserver* observer = mObserverHandle.get(); if (observer) { - observer->setErrorStatus(status, reason); + observer->setErrorStatus(getStatus(), getReason()); } } diff --git a/indra/newview/llremoteparcelrequest.h b/indra/newview/llremoteparcelrequest.h index b87056573b..0f8ae41d76 100644 --- a/indra/newview/llremoteparcelrequest.h +++ b/indra/newview/llremoteparcelrequest.h @@ -37,16 +37,17 @@ class LLRemoteParcelInfoObserver; class LLRemoteParcelRequestResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLRemoteParcelRequestResponder); public: LLRemoteParcelRequestResponder(LLHandle<LLRemoteParcelInfoObserver> observer_handle); +private: //If we get back a normal response, handle it here - /*virtual*/ void result(const LLSD& content); + /*virtual*/ void httpSuccess(); //If we get back an error (not found, etc...), handle it here - /*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content); + /*virtual*/ void httpFailure(); -protected: LLHandle<LLRemoteParcelInfoObserver> mObserverHandle; }; @@ -78,7 +79,7 @@ public: virtual ~LLRemoteParcelInfoObserver() {} virtual void processParcelInfo(const LLParcelData& parcel_data) = 0; virtual void setParcelID(const LLUUID& parcel_id) = 0; - virtual void setErrorStatus(U32 status, const std::string& reason) = 0; + virtual void setErrorStatus(S32 status, const std::string& reason) = 0; LLHandle<LLRemoteParcelInfoObserver> getObserverHandle() const { return mObserverHandle; } protected: diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index 74fa5a87bb..77e9604460 100644 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -48,6 +48,8 @@ #include "llviewerregion.h" #include "llvoavatarself.h" #include "llviewerwearable.h" +#include "llnotificationsutil.h" +#include "llfloatersidepanelcontainer.h" static LLRegisterPanelClassWrapper<LLSidepanelAppearance> t_appearance("sidepanel_appearance"); @@ -70,13 +72,86 @@ private: LLSidepanelAppearance *mPanel; }; +bool LLSidepanelAppearance::callBackExitWithoutSaveViaBack(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if ( option == 0 ) + { + LLAppearanceMgr::instance().setOutfitDirty( true ); + showOutfitsInventoryPanel(); + LLAppearanceMgr::getInstance()->wearBaseOutfit(); + return true; + } + return false; +} + +bool LLSidepanelAppearance::callBackExitWithoutSaveViaClose(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if ( option == 0 ) + { + //revert curernt edits + mEditWearable->revertChanges(); + toggleWearableEditPanel(FALSE); + LLVOAvatarSelf::onCustomizeEnd(FALSE); + mLLFloaterSidePanelContainer->close(); + return true; + } + return false; +} + +void LLSidepanelAppearance::onClickConfirmExitWithoutSaveViaClose() +{ + if ( LLAppearanceMgr::getInstance()->isOutfitDirty() && !LLAppearanceMgr::getInstance()->isOutfitLocked() ) + { + LLSidepanelAppearance* pSelf = (LLSidepanelAppearance *)this; + LLNotificationsUtil::add("ConfirmExitWithoutSave", LLSD(), LLSD(), boost::bind(&LLSidepanelAppearance::callBackExitWithoutSaveViaClose,pSelf,_1,_2) ); + } + else + { + showOutfitsInventoryPanel(); + } +} + +void LLSidepanelAppearance::onClickConfirmExitWithoutSaveViaBack() +{ + if ( LLAppearanceMgr::getInstance()->isOutfitDirty() && !mSidePanelJustOpened && !LLAppearanceMgr::getInstance()->isOutfitLocked() ) + { + LLSidepanelAppearance* pSelf = (LLSidepanelAppearance *)this; + LLNotificationsUtil::add("ConfirmExitWithoutSave", LLSD(), LLSD(), boost::bind(&LLSidepanelAppearance::callBackExitWithoutSaveViaBack,pSelf,_1,_2) ); + } + else + { + showOutfitsInventoryPanel(); + } +} + +void LLSidepanelAppearance::onClose(LLFloaterSidePanelContainer* obj) +{ + mLLFloaterSidePanelContainer = obj; + if ( LLAppearanceMgr::getInstance()->isOutfitDirty() && + !LLAppearanceMgr::getInstance()->isOutfitLocked() || + ( mEditWearable->isAvailable() && mEditWearable->isDirty() ) ) + { + LLSidepanelAppearance* pSelf = (LLSidepanelAppearance *)this; + LLNotificationsUtil::add("ConfirmExitWithoutSave", LLSD(), LLSD(), boost::bind(&LLSidepanelAppearance::callBackExitWithoutSaveViaClose,pSelf,_1,_2) ); + } + else + { + LLVOAvatarSelf::onCustomizeEnd(FALSE); + toggleWearableEditPanel(FALSE); + mLLFloaterSidePanelContainer->close(); + } +} + LLSidepanelAppearance::LLSidepanelAppearance() : LLPanel(), mFilterSubString(LLStringUtil::null), mFilterEditor(NULL), mOutfitEdit(NULL), mCurrOutfitPanel(NULL), - mOpened(false) + mOpened(false), + mSidePanelJustOpened(true) { LLOutfitObserver& outfit_observer = LLOutfitObserver::instance(); outfit_observer.addBOFReplacedCallback(boost::bind(&LLSidepanelAppearance::refreshCurrentOutfitName, this, "")); @@ -85,6 +160,8 @@ LLSidepanelAppearance::LLSidepanelAppearance() : gAgentWearables.addLoadingStartedCallback(boost::bind(&LLSidepanelAppearance::setWearablesLoading, this, true)); gAgentWearables.addLoadedCallback(boost::bind(&LLSidepanelAppearance::setWearablesLoading, this, false)); + + } LLSidepanelAppearance::~LLSidepanelAppearance() @@ -119,8 +196,8 @@ BOOL LLSidepanelAppearance::postBuild() { LLButton* back_btn = mOutfitEdit->getChild<LLButton>("back_btn"); if (back_btn) - { - back_btn->setClickedCallback(boost::bind(&LLSidepanelAppearance::showOutfitsInventoryPanel, this)); + { + back_btn->setClickedCallback(boost::bind(&LLSidepanelAppearance::onClickConfirmExitWithoutSaveViaBack, this)); } } @@ -144,6 +221,7 @@ BOOL LLSidepanelAppearance::postBuild() setVisibleCallback(boost::bind(&LLSidepanelAppearance::onVisibilityChange,this,_2)); + return TRUE; } @@ -183,6 +261,12 @@ void LLSidepanelAppearance::onOpen(const LLSD& key) void LLSidepanelAppearance::onVisibilityChange(const LLSD &new_visibility) { + //handle leaving and subsequent user verification of discarding any unsaved data + if ( mSidePanelJustOpened ) + { + mSidePanelJustOpened = false; + } + LLSD visibility; visibility["visible"] = new_visibility.asBoolean(); visibility["reset_accordion"] = false; diff --git a/indra/newview/llsidepanelappearance.h b/indra/newview/llsidepanelappearance.h index 762f557a80..85e7734567 100644 --- a/indra/newview/llsidepanelappearance.h +++ b/indra/newview/llsidepanelappearance.h @@ -38,9 +38,11 @@ class LLCurrentlyWornFetchObserver; class LLPanelEditWearable; class LLViewerWearable; class LLPanelOutfitsInventory; +class LLFloaterSidePanelContainer; class LLSidepanelAppearance : public LLPanel -{ +{ + LOG_CLASS(LLSidepanelAppearance); public: LLSidepanelAppearance(); @@ -48,6 +50,8 @@ public: /*virtual*/ BOOL postBuild(); /*virtual*/ void onOpen(const LLSD& key); + void onClose(LLFloaterSidePanelContainer* obj); + void onClickCloseBtn(); void refreshCurrentOutfitName(const std::string& name = ""); @@ -65,6 +69,11 @@ public: void updateScrollingPanelList(); void updateToVisibility( const LLSD& new_visibility ); LLPanelEditWearable* getWearable(){ return mEditWearable; } + bool callBackExitWithoutSaveViaBack(const LLSD& notification, const LLSD& response); + void onClickConfirmExitWithoutSaveViaBack(); + bool callBackExitWithoutSaveViaClose(const LLSD& notification, const LLSD& response); + void onClickConfirmExitWithoutSaveViaClose(); + private: void onFilterEdit(const std::string& search_string); @@ -85,6 +94,7 @@ private: LLButton* mOpenOutfitBtn; LLButton* mEditAppearanceBtn; LLButton* mNewOutfitBtn; + LLPanel* mCurrOutfitPanel; LLTextBox* mCurrentLookName; @@ -99,6 +109,10 @@ private: // Gets set to true when we're opened for the first time. bool mOpened; + // Set to true if sidepanel has just been opened + bool mSidePanelJustOpened; + LLFloaterSidePanelContainer* mLLFloaterSidePanelContainer; + }; #endif //LL_LLSIDEPANELAPPEARANCE_H diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index a4582071e8..bf209df863 100644 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -268,21 +268,23 @@ bool LLSpeakersDelayActionsStorage::isTimerStarted(const LLUUID& speaker_id) class ModerationResponder : public LLHTTPClient::Responder { + LOG_CLASS(ModerationResponder); public: ModerationResponder(const LLUUID& session_id) { mSessionID = session_id; } - virtual void error(U32 status, const std::string& reason) +protected: + virtual void httpFailure() { - llwarns << status << ": " << reason << llendl; + llwarns << dumpResponse() << llendl;; if ( gIMMgr ) { //403 == you're not a mod //should be disabled if you're not a moderator - if ( 403 == status ) + if ( HTTP_FORBIDDEN == getStatus() ) { gIMMgr->showSessionEventError( "mute", @@ -853,10 +855,7 @@ void LLIMSpeakerMgr::updateSpeakers(const LLSD& update) } } } -/*prep# - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) - llwarns << "ModerationResponder error [status:" << status << "]: " << content << llendl; - */ + void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id) { LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 8b71f1067f..e4627b132f 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1279,6 +1279,8 @@ bool idle_startup() LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle); LL_INFOS("AppInit") << "Adding initial simulator " << regionp->getOriginGlobal() << LL_ENDL; + LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from init_idle(). Seed cap == " + << gFirstSimSeedCap << LL_ENDL; regionp->setSeedCapability(gFirstSimSeedCap); LL_DEBUGS("AppInit") << "Waiting for seed grant ...." << LL_ENDL; display_startup(); diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index be5fde9e2b..f7fbb19bdc 100755 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2012, Linden Research, Inc. + * Copyright (C) 2012-2013, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -36,7 +36,7 @@ #include "lldir.h" #include "llhttpclient.h" -#include "llhttpstatuscodes.h" +#include "llhttpconstants.h" #include "llimage.h" #include "llimagej2c.h" #include "llimageworker.h" @@ -63,6 +63,8 @@ #include "bufferarray.h" #include "bufferstream.h" +#include "llhttpretrypolicy.h" + bool LLTextureFetchDebugger::sDebuggerEnabled = false ; LLStat LLTextureFetch::sCacheHitRate("texture_cache_hits", 128); LLStat LLTextureFetch::sCacheReadLatency("texture_cache_read_latency", 128); @@ -244,6 +246,25 @@ static const S32 HTTP_REQUESTS_IN_QUEUE_LOW_WATER = 20; // Active level at whi ////////////////////////////////////////////////////////////////////////////// +static const char* e_state_name[] = +{ + "INVALID", + "INIT", + "LOAD_FROM_TEXTURE_CACHE", + "CACHE_POST", + "LOAD_FROM_NETWORK", + "LOAD_FROM_SIMULATOR", + "WAIT_HTTP_RESOURCE", + "WAIT_HTTP_RESOURCE2", + "SEND_HTTP_REQ", + "WAIT_HTTP_REQ", + "DECODE_IMAGE", + "DECODE_IMAGE_UPDATE", + "WRITE_TO_CACHE", + "WAIT_ON_WRITE", + "DONE" +}; + class LLTextureFetchWorker : public LLWorkerClass, public LLCore::HttpHandler { @@ -382,12 +403,14 @@ public: void setCanUseHTTP(bool can_use_http) { mCanUseHTTP = can_use_http; } bool getCanUseHTTP() const { return mCanUseHTTP; } + void setUrl(const std::string& url) { mUrl = url; } + LLTextureFetch & getFetcher() { return *mFetcher; } // Inherited from LLCore::HttpHandler // Threads: Ttf virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response); - + protected: LLTextureFetchWorker(LLTextureFetch* fetcher, FTType f_type, const std::string& url, const LLUUID& id, const LLHost& host, @@ -547,6 +570,8 @@ private: S32 mActiveCount; LLCore::HttpStatus mGetStatus; std::string mGetReason; + LLAdaptiveRetryPolicy mFetchRetryPolicy; + // Work Data LLMutex mWorkMutex; @@ -889,7 +914,8 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher, mHttpHasResource(false), mCacheReadCount(0U), mCacheWriteCount(0U), - mResourceWaitCount(0U) + mResourceWaitCount(0U), + mFetchRetryPolicy(10.0,3600.0,2.0,10) { mCanUseNET = mUrl.empty() ; @@ -1148,6 +1174,7 @@ bool LLTextureFetchWorker::doWork(S32 param) mDesiredSize = llmax(mDesiredSize, TEXTURE_CACHE_ENTRY_SIZE); // min desired size is TEXTURE_CACHE_ENTRY_SIZE LL_DEBUGS("Texture") << mID << ": Priority: " << llformat("%8.0f",mImagePriority) << " Desired Discard: " << mDesiredDiscard << " Desired Size: " << mDesiredSize << LL_ENDL; + // fall through } @@ -1270,6 +1297,21 @@ bool LLTextureFetchWorker::doWork(S32 param) if (mState == LOAD_FROM_NETWORK) { + // Check for retries to previous server failures. + F32 wait_seconds; + if (mFetchRetryPolicy.shouldRetry(wait_seconds)) + { + if (wait_seconds <= 0.0) + { + llinfos << mID << " retrying now" << llendl; + } + else + { + //llinfos << mID << " waiting to retry for " << wait_seconds << " seconds" << llendl; + return false; + } + } + static LLCachedControl<bool> use_http(gSavedSettings,"ImagePipelineUseHTTP"); // if (mHost != LLHost::invalid) get_url = false; @@ -1286,7 +1328,7 @@ bool LLTextureFetchWorker::doWork(S32 param) std::string http_url = region->getHttpUrl() ; if (!http_url.empty()) { - mUrl = http_url + "/?texture_id=" + mID.asString().c_str(); + setUrl(http_url + "/?texture_id=" + mID.asString().c_str()); mWriteToCacheState = CAN_WRITE ; //because this texture has a fixed texture id. } else @@ -1482,12 +1524,14 @@ bool LLTextureFetchWorker::doWork(S32 param) << LL_ENDL; // Will call callbackHttpGet when curl request completes + // Only server bake images use the returned headers currently, for getting retry-after field. + LLCore::HttpOptions *options = (mFTType == FTT_SERVER_BAKE) ? mFetcher->mHttpOptionsWithHeaders: mFetcher->mHttpOptions; mHttpHandle = mFetcher->mHttpRequest->requestGetByteRange(mHttpPolicyClass, mWorkPriority, mUrl, mRequestedOffset, mRequestedSize, - mFetcher->mHttpOptions, + options, mFetcher->mHttpHeaders, this); } @@ -1519,15 +1563,22 @@ bool LLTextureFetchWorker::doWork(S32 param) { if (http_not_found == mGetStatus) { - if(mWriteToCacheState == NOT_WRITE) //map tiles + if (mFTType != FTT_MAP_TILE) + { + llwarns << "Texture missing from server (404): " << mUrl << llendl; + } + + if(mWriteToCacheState == NOT_WRITE) //map tiles or server bakes { setState(DONE); releaseHttpSemaphore(); - LL_DEBUGS("Texture") << mID << " abort: WAIT_HTTP_REQ not found" << llendl; - return true; // failed, means no map tile on the empty region. + if (mFTType != FTT_MAP_TILE) + { + LL_WARNS("Texture") << mID << " abort: WAIT_HTTP_REQ not found" << llendl; + } + return true; } - llwarns << "Texture missing from server (404): " << mUrl << llendl; // roll back to try UDP if (mCanUseNET) @@ -1543,6 +1594,10 @@ bool LLTextureFetchWorker::doWork(S32 param) else if (http_service_unavail == mGetStatus) { LL_INFOS_ONCE("Texture") << "Texture server busy (503): " << mUrl << LL_ENDL; + llinfos << "503: HTTP GET failed for: " << mUrl + << " Status: " << mGetStatus.toHex() + << " Reason: '" << mGetReason << "'" + << llendl; } else if (http_not_sat == mGetStatus) { @@ -1551,7 +1606,7 @@ bool LLTextureFetchWorker::doWork(S32 param) } else { - llinfos << "HTTP GET failed for: " << mUrl + llinfos << "other: HTTP GET failed for: " << mUrl << " Status: " << mGetStatus.toHex() << " Reason: '" << mGetReason << "'" << llendl; @@ -1891,14 +1946,48 @@ void LLTextureFetchWorker::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRe mFetcher->mTextureInfo.setRequestCompleteTimeAndLog(mID, timeNow); } + static LLCachedControl<F32> fake_failure_rate(gSavedSettings, "TextureFetchFakeFailureRate"); + F32 rand_val = ll_frand(); + F32 rate = fake_failure_rate; + if (mFTType == FTT_SERVER_BAKE && (fake_failure_rate > 0.0) && (rand_val < fake_failure_rate)) + { + llwarns << mID << " for debugging, setting fake failure status for texture " << mID + << " (rand was " << rand_val << "/" << rate << ")" << llendl; + response->setStatus(LLCore::HttpStatus(503)); + } bool success = true; bool partial = false; LLCore::HttpStatus status(response->getStatus()); + if (!status && (mFTType == FTT_SERVER_BAKE)) + { + llinfos << mID << " state " << e_state_name[mState] << llendl; + mFetchRetryPolicy.onFailure(response); + F32 retry_after; + if (mFetchRetryPolicy.shouldRetry(retry_after)) + { + llinfos << mID << " will retry after " << retry_after << " seconds, resetting state to LOAD_FROM_NETWORK" << llendl; + mFetcher->removeFromHTTPQueue(mID, 0); + std::string reason(status.toString()); + setGetStatus(status, reason); + releaseHttpSemaphore(); + setState(LOAD_FROM_NETWORK); + return; + } + else + { + llinfos << mID << " will not retry" << llendl; + } + } + else + { + mFetchRetryPolicy.onSuccess(); + } LL_DEBUGS("Texture") << "HTTP COMPLETE: " << mID << " status: " << status.toHex() << " '" << status.toString() << "'" << llendl; + // unsigned int offset(0), length(0), full_length(0); // response->getRange(&offset, &length, &full_length); // llwarns << "HTTP COMPLETE: " << mID << " handle: " << handle @@ -1907,13 +1996,16 @@ void LLTextureFetchWorker::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRe // << " offset: " << offset << " length: " << length // << llendl; + std::string reason(status.toString()); + setGetStatus(status, reason); if (! status) { success = false; - std::string reason(status.toString()); - setGetStatus(status, reason); - llwarns << "CURL GET FAILED, status: " << status.toHex() - << " reason: " << reason << llendl; + if (mFTType != FTT_MAP_TILE) // missing map tiles are normal, don't complain about them. + { + llwarns << mID << " CURL GET FAILED, status: " << status.toHex() + << " reason: " << reason << llendl; + } } else { @@ -2376,6 +2468,7 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image mQAMode(qa_mode), mHttpRequest(NULL), mHttpOptions(NULL), + mHttpOptionsWithHeaders(NULL), mHttpHeaders(NULL), mHttpMetricsHeaders(NULL), mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID), @@ -2406,10 +2499,13 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image mHttpRequest = new LLCore::HttpRequest; mHttpOptions = new LLCore::HttpOptions; + mHttpOptionsWithHeaders = new LLCore::HttpOptions; + mHttpOptionsWithHeaders->setWantHeaders(true); mHttpHeaders = new LLCore::HttpHeaders; - mHttpHeaders->mHeaders.push_back("Accept: image/x-j2c"); + // *TODO: Should this be 'image/j2c' instead of 'image/x-j2c' ? + mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_IMAGE_X_J2C); mHttpMetricsHeaders = new LLCore::HttpHeaders; - mHttpMetricsHeaders->mHeaders.push_back("Content-Type: application/llsd+xml"); + mHttpMetricsHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); mHttpPolicyClass = LLAppViewer::instance()->getAppCoreHttp().getPolicyDefault(); } @@ -2430,6 +2526,12 @@ LLTextureFetch::~LLTextureFetch() mHttpOptions = NULL; } + if (mHttpOptionsWithHeaders) + { + mHttpOptionsWithHeaders->release(); + mHttpOptionsWithHeaders = NULL; + } + if (mHttpHeaders) { mHttpHeaders->release(); @@ -2464,7 +2566,11 @@ bool LLTextureFetch::createRequest(FTType f_type, const std::string& url, const { return false; } - + + if (f_type == FTT_SERVER_BAKE) + { + LL_DEBUGS("Avatar") << " requesting " << id << " " << w << "x" << h << " discard " << desired_discard << llendl; + } LLTextureFetchWorker* worker = getWorker(id) ; if (worker) { @@ -2522,7 +2628,8 @@ bool LLTextureFetch::createRequest(FTType f_type, const std::string& url, const worker->mNeedsAux = needs_aux; worker->setImagePriority(priority); worker->setDesiredDiscard(desired_discard, desired_size); - worker->setCanUseHTTP(can_use_http) ; + worker->setCanUseHTTP(can_use_http); + worker->setUrl(url); if (!worker->haveWork()) { worker->setState(LLTextureFetchWorker::INIT); @@ -2728,7 +2835,8 @@ LLTextureFetchWorker* LLTextureFetch::getWorker(const LLUUID& id) // Threads: T* bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level, - LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux) + LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux, + LLCore::HttpStatus& last_http_get_status) { bool res = false; LLTextureFetchWorker* worker = getWorker(id); @@ -2750,6 +2858,7 @@ bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level, else if (worker->checkWork()) { worker->lockWorkMutex(); // +Mw + last_http_get_status = worker->mGetStatus; discard_level = worker->mDecodedDiscard; raw = worker->mRawImage; aux = worker->mAuxImage; @@ -3220,25 +3329,14 @@ bool LLTextureFetchWorker::insertPacket(S32 index, U8* data, S32 size) void LLTextureFetchWorker::setState(e_state new_state) { - static const char* e_state_name[] = - { - "INVALID", - "INIT", - "LOAD_FROM_TEXTURE_CACHE", - "CACHE_POST", - "LOAD_FROM_NETWORK", - "LOAD_FROM_SIMULATOR", - "WAIT_HTTP_RESOURCE", - "WAIT_HTTP_RESOURCE2", - "SEND_HTTP_REQ", - "WAIT_HTTP_REQ", - "DECODE_IMAGE", - "DECODE_IMAGE_UPDATE", - "WRITE_TO_CACHE", - "WAIT_ON_WRITE", - "DONE" - }; - LL_DEBUGS("Texture") << "id: " << mID << " FTType: " << mFTType << " disc: " << mDesiredDiscard << " sz: " << mDesiredSize << " state: " << e_state_name[mState] << " => " << e_state_name[new_state] << llendl; + if (mFTType == FTT_SERVER_BAKE) + { + // NOTE: turning on these log statements is a reliable way to get + // blurry images fairly frequently. Presumably this is an + // indication of some subtle timing or locking issue. + +// LL_INFOS("Texture") << "id: " << mID << " FTType: " << mFTType << " disc: " << mDesiredDiscard << " sz: " << mDesiredSize << " state: " << e_state_name[mState] << " => " << e_state_name[new_state] << llendl; + } mState = new_state; } @@ -4041,7 +4139,8 @@ void LLTextureFetchDebugger::init() if (! mHttpHeaders) { mHttpHeaders = new LLCore::HttpHeaders; - mHttpHeaders->mHeaders.push_back("Accept: image/x-j2c"); + // *TODO: Should this be 'image/j2c' instead of 'image/x-j2c' ? + mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_IMAGE_X_J2C); } } diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index 902a3d7a25..237912cde7 100644..100755 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2012, Linden Research, Inc. + * Copyright (C) 2012-2013, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -95,7 +95,8 @@ public: // Threads: T* bool getRequestFinished(const LLUUID& id, S32& discard_level, - LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux); + LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux, + LLCore::HttpStatus& last_http_get_status); // Threads: T* bool updateRequestPriority(const LLUUID& id, F32 priority); @@ -351,6 +352,7 @@ private: // LLCurl interfaces used in the past. LLCore::HttpRequest * mHttpRequest; // Ttf LLCore::HttpOptions * mHttpOptions; // Ttf + LLCore::HttpOptions * mHttpOptionsWithHeaders; // Ttf LLCore::HttpHeaders * mHttpHeaders; // Ttf LLCore::HttpHeaders * mHttpMetricsHeaders; // Ttf LLCore::HttpRequest::policy_t mHttpPolicyClass; // T* @@ -395,6 +397,9 @@ private: e_tex_source mFetchSource; e_tex_source mOriginFetchSource; + // Retry logic + //LLAdaptiveRetryPolicy mFetchRetryPolicy; + public: //debug use LLTextureFetchDebugger* getFetchDebugger() { return mFetchDebugger;} diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp index f3d8de1904..ae934d9f5a 100755 --- a/indra/newview/lltranslate.cpp +++ b/indra/newview/lltranslate.cpp @@ -84,7 +84,7 @@ bool LLGoogleTranslationHandler::parseResponse( return false; } - if (status != STATUS_OK) + if (status != HTTP_OK) { // Request failed. Extract error message from the response. parseErrorResponse(root, status, err_msg); @@ -186,7 +186,7 @@ bool LLBingTranslationHandler::parseResponse( std::string& detected_lang, std::string& err_msg) const { - if (status != STATUS_OK) + if (status != HTTP_OK) { static const std::string MSG_BEGIN_MARKER = "Message: "; size_t begin = body.find(MSG_BEGIN_MARKER); @@ -251,8 +251,6 @@ LLTranslate::TranslationReceiver::TranslationReceiver(const std::string& from_la // virtual void LLTranslate::TranslationReceiver::completedRaw( - U32 http_status, - const std::string& reason, const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { @@ -262,8 +260,8 @@ void LLTranslate::TranslationReceiver::completedRaw( const std::string body = strstrm.str(); std::string translation, detected_lang, err_msg; - int status = http_status; - LL_DEBUGS("Translate") << "HTTP status: " << status << " " << reason << LL_ENDL; + int status = getStatus(); + LL_DEBUGS("Translate") << "HTTP status: " << status << " " << getReason() << LL_ENDL; LL_DEBUGS("Translate") << "Response body: " << body << LL_ENDL; if (mHandler.parseResponse(status, body, translation, detected_lang, err_msg)) { @@ -301,12 +299,10 @@ LLTranslate::EService LLTranslate::KeyVerificationReceiver::getService() const // virtual void LLTranslate::KeyVerificationReceiver::completedRaw( - U32 http_status, - const std::string& reason, const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { - bool ok = (http_status == 200); + bool ok = (getStatus() == HTTP_OK); setVerificationStatus(ok); } @@ -398,8 +394,8 @@ void LLTranslate::sendRequest(const std::string& url, LLHTTPClient::ResponderPtr LLVersionInfo::getPatch(), LLVersionInfo::getBuild()); - sHeader.insert("Accept", "text/plain"); - sHeader.insert("User-Agent", user_agent); + sHeader.insert(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN); + sHeader.insert(HTTP_OUT_HEADER_USER_AGENT, user_agent); } LLHTTPClient::get(url, responder, sHeader, REQUEST_TIMEOUT); diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h index db5ad9479c..972274714a 100755 --- a/indra/newview/lltranslate.h +++ b/indra/newview/lltranslate.h @@ -95,9 +95,6 @@ public: virtual bool isConfigured() const = 0; virtual ~LLTranslationAPIHandler() {} - -protected: - static const int STATUS_OK = 200; }; /// Google Translate v2 API handler. @@ -201,8 +198,6 @@ public : * @see mHandler */ /*virtual*/ void completedRaw( - U32 http_status, - const std::string& reason, const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer); @@ -250,8 +245,6 @@ public : * @see setVerificationStatus() */ /*virtual*/ void completedRaw( - U32 http_status, - const std::string& reason, const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer); diff --git a/indra/newview/lluploadfloaterobservers.cpp b/indra/newview/lluploadfloaterobservers.cpp index 1d777b3f7f..88c48ba0a3 100644 --- a/indra/newview/lluploadfloaterobservers.cpp +++ b/indra/newview/lluploadfloaterobservers.cpp @@ -1,6 +1,6 @@ /** * @file lluploadfloaterobservers.cpp - * @brief LLUploadModelPremissionsResponder definition + * @brief LLUploadModelPermissionsResponder definition * * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code @@ -28,26 +28,31 @@ #include "lluploadfloaterobservers.h" -LLUploadModelPremissionsResponder::LLUploadModelPremissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer) +LLUploadModelPermissionsResponder::LLUploadModelPermissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer) :mObserverHandle(observer) { } -void LLUploadModelPremissionsResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLUploadModelPermissionsResponder::httpFailure() { - llwarns << "LLUploadModelPremissionsResponder error [status:" - << status << "]: " << content << llendl; + llwarns << dumpResponse() << llendl; LLUploadPermissionsObserver* observer = mObserverHandle.get(); if (observer) { - observer->setPermissonsErrorStatus(status, reason); + observer->setPermissonsErrorStatus(getStatus(), getReason()); } } -void LLUploadModelPremissionsResponder::result(const LLSD& content) +void LLUploadModelPermissionsResponder::httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } LLUploadPermissionsObserver* observer = mObserverHandle.get(); if (observer) @@ -55,3 +60,4 @@ void LLUploadModelPremissionsResponder::result(const LLSD& content) observer->onPermissionsReceived(content); } } + diff --git a/indra/newview/lluploadfloaterobservers.h b/indra/newview/lluploadfloaterobservers.h index b43ddb44d9..4ff4a827a5 100644 --- a/indra/newview/lluploadfloaterobservers.h +++ b/indra/newview/lluploadfloaterobservers.h @@ -1,6 +1,6 @@ /** * @file lluploadfloaterobservers.h - * @brief LLUploadModelPremissionsResponder declaration + * @brief LLUploadModelPermissionsResponder declaration * * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code @@ -39,7 +39,7 @@ public: virtual ~LLUploadPermissionsObserver() {} virtual void onPermissionsReceived(const LLSD& result) = 0; - virtual void setPermissonsErrorStatus(U32 status, const std::string& reason) = 0; + virtual void setPermissonsErrorStatus(S32 status, const std::string& reason) = 0; LLHandle<LLUploadPermissionsObserver> getPermObserverHandle() const {return mUploadPermObserverHandle;} @@ -54,7 +54,7 @@ public: virtual ~LLWholeModelFeeObserver() {} virtual void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) = 0; - virtual void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason) = 0; + virtual void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) = 0; LLHandle<LLWholeModelFeeObserver> getWholeModelFeeObserverHandle() const { return mWholeModelFeeObserverHandle; } @@ -80,17 +80,16 @@ protected: }; -class LLUploadModelPremissionsResponder : public LLHTTPClient::Responder +class LLUploadModelPermissionsResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLUploadModelPermissionsResponder); public: - - LLUploadModelPremissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer); - - void errorWithContent(U32 status, const std::string& reason, const LLSD& content); - - void result(const LLSD& content); + LLUploadModelPermissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer); private: + /* virtual */ void httpSuccess(); + /* virtual */ void httpFailure(); + LLHandle<LLUploadPermissionsObserver> mObserverHandle; }; diff --git a/indra/newview/llviewerdisplayname.cpp b/indra/newview/llviewerdisplayname.cpp index f81206ffec..3f836efdd3 100644 --- a/indra/newview/llviewerdisplayname.cpp +++ b/indra/newview/llviewerdisplayname.cpp @@ -58,12 +58,12 @@ namespace LLViewerDisplayName class LLSetDisplayNameResponder : public LLHTTPClient::Responder { -public: + LOG_CLASS(LLSetDisplayNameResponder); +private: // only care about errors - /*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content) + /*virtual*/ void httpFailure() { - llwarns << "LLSetDisplayNameResponder error [status:" - << status << "]: " << content << llendl; + llwarns << dumpResponse() << llendl; LLViewerDisplayName::sSetDisplayNameSignal(false, "", LLSD()); LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots(); } @@ -86,7 +86,7 @@ void LLViewerDisplayName::set(const std::string& display_name, const set_name_sl // People API can return localized error messages. Indicate our // language preference via header. LLSD headers; - headers["Accept-Language"] = LLUI::getLanguage(); + headers[HTTP_OUT_HEADER_ACCEPT_LANGUAGE] = LLUI::getLanguage(); // People API requires both the old and new value to change a variable. // Our display name will be in cache before the viewer's UI is available @@ -128,7 +128,7 @@ public: LLSD body = input["body"]; S32 status = body["status"].asInteger(); - bool success = (status == 200); + bool success = (status == HTTP_OK); std::string reason = body["reason"].asString(); LLSD content = body["content"]; @@ -137,7 +137,7 @@ public: // If viewer's concept of display name is out-of-date, the set request // will fail with 409 Conflict. If that happens, fetch up-to-date // name information. - if (status == 409) + if (status == HTTP_CONFLICT) { LLUUID agent_id = gAgent.getID(); // Flush stale data diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index fff9821e86..f9afdee4f9 100644..100755 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -65,6 +65,7 @@ #include "llavataractions.h" #include "lllogininstance.h" #include "llfavoritesbar.h" +#include "llclipboard.h" // Two do-nothing ops for use in callbacks. void no_op_inventory_func(const LLUUID&) {} @@ -345,24 +346,6 @@ void LLViewerInventoryItem::cloneViewerItem(LLPointer<LLViewerInventoryItem>& ne } } -void LLViewerInventoryItem::removeFromServer() -{ - lldebugs << "Removing inventory item " << mUUID << " from server." - << llendl; - - LLInventoryModel::LLCategoryUpdate up(mParentUUID, -1); - gInventory.accountForUpdate(up); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_RemoveInventoryItem); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_InventoryData); - msg->addUUIDFast(_PREHASH_ItemID, mUUID); - gAgent.sendReliableMessage(); -} - void LLViewerInventoryItem::updateServer(BOOL is_new) const { if(!mIsComplete) @@ -637,30 +620,6 @@ void LLViewerInventoryCategory::updateServer(BOOL is_new) const gAgent.sendReliableMessage(); } -void LLViewerInventoryCategory::removeFromServer( void ) -{ - llinfos << "Removing inventory category " << mUUID << " from server." - << llendl; - // communicate that change with the server. - if(LLFolderType::lookupIsProtectedType(mPreferredType)) - { - LLNotificationsUtil::add("CannotRemoveProtectedCategories"); - return; - } - - LLInventoryModel::LLCategoryUpdate up(mParentUUID, -1); - gInventory.accountForUpdate(up); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_RemoveInventoryFolder); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_FolderData); - msg->addUUIDFast(_PREHASH_FolderID, mUUID); - gAgent.sendReliableMessage(); -} - S32 LLViewerInventoryCategory::getVersion() const { return mVersion; @@ -1179,6 +1138,314 @@ void move_inventory_item( gAgent.sendReliableMessage(); } +class RemoveObjectResponder: public LLHTTPClient::Responder +{ +public: + RemoveObjectResponder(const LLUUID& item_id, LLPointer<LLInventoryCallback> callback): + mItemUUID(item_id), + mCallback(callback) + { + } + /* virtual */ void httpSuccess() + { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } + llinfos << "succeeded: " << ll_pretty_print_sd(content) << llendl; + + gInventory.onObjectDeletedFromServer(mItemUUID); + + if (mCallback) + { + mCallback->fire(mItemUUID); + } + } + /*virtual*/ void httpFailure() + { + const LLSD& content = getContent(); + S32 status = getStatus(); + const std::string& reason = getReason(); + if (!content.isMap()) + { + llwarns << "Malformed response contents " << content << " id " << mItemUUID << " status " << status << " reason " << reason << llendl; + return; + } + llwarns << "failed for " << mItemUUID << " content: " << ll_pretty_print_sd(content) << " status " << status << " reason " << reason << llendl; + } +private: + LLPointer<LLInventoryCallback> mCallback; + const LLUUID mItemUUID; +}; + +void remove_inventory_item( + const LLUUID& item_id, + LLPointer<LLInventoryCallback> cb) +{ + llinfos << "item_id: [" << item_id << "] " << llendl; + LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id); + if(obj) + { + std::string cap; + if (gAgent.getRegion() && gSavedSettings.getBOOL("UseAISv3Inventory")) + { + cap = gAgent.getRegion()->getCapability("InventoryAPIv3"); + } + if (!cap.empty()) + { + std::string url = cap + std::string("/item/") + item_id.asString(); + llinfos << "url: " << url << llendl; + LLCurl::ResponderPtr responder_ptr = new RemoveObjectResponder(item_id,cb); + LLHTTPClient::del(url,responder_ptr); + } + else // no cap + { + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RemoveInventoryItem); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addUUIDFast(_PREHASH_ItemID, item_id); + gAgent.sendReliableMessage(); + + // Update inventory and call callback immediately since + // message-based system has no callback mechanism (!) + gInventory.onObjectDeletedFromServer(item_id); + if (cb) + { + cb->fire(item_id); + } + } + } + else + { + llwarns << "remove_inventory_item called for invalid or nonexistent item " << item_id << llendl; + } +} + +class LLRemoveObjectOnDestroy: public LLInventoryCallback +{ +public: + LLRemoveObjectOnDestroy(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb): + mID(item_id), + mCB(cb) + { + } + /* virtual */ void fire(const LLUUID& item_id) {} + ~LLRemoveObjectOnDestroy() + { + remove_inventory_object(mID, mCB); + } +private: + LLUUID mID; + LLPointer<LLInventoryCallback> mCB; +}; + +void remove_inventory_category( + const LLUUID& cat_id, + LLPointer<LLInventoryCallback> cb) +{ + llinfos << "cat_id: [" << cat_id << "] " << llendl; + LLPointer<LLViewerInventoryCategory> obj = gInventory.getCategory(cat_id); + if(obj) + { + if(LLFolderType::lookupIsProtectedType(obj->getPreferredType())) + { + LLNotificationsUtil::add("CannotRemoveProtectedCategories"); + return; + } + LLInventoryModel::EHasChildren children = gInventory.categoryHasChildren(cat_id); + if(children != LLInventoryModel::CHILDREN_NO) + { + llinfos << "Will purge descendents first before deleting category " << cat_id << llendl; + LLPointer<LLInventoryCallback> wrap_cb = new LLRemoveObjectOnDestroy(cat_id,cb); + purge_descendents_of(cat_id, wrap_cb); + return; + } + + std::string cap; + if (gAgent.getRegion() && gSavedSettings.getBOOL("UseAISv3Inventory")) + { + cap = gAgent.getRegion()->getCapability("InventoryAPIv3"); + } + if (!cap.empty()) + { + std::string url = cap + std::string("/category/") + cat_id.asString(); + llinfos << "url: " << url << llendl; + LLCurl::ResponderPtr responder_ptr = new RemoveObjectResponder(cat_id,cb); + LLHTTPClient::del(url,responder_ptr); + } + else // no cap + { + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RemoveInventoryFolder); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_FolderData); + msg->addUUIDFast(_PREHASH_FolderID, cat_id); + gAgent.sendReliableMessage(); + + // Update inventory and call callback immediately since + // message-based system has no callback mechanism (!) + gInventory.onObjectDeletedFromServer(cat_id); + if (cb) + { + cb->fire(cat_id); + } + } + } + else + { + llwarns << "remove_inventory_category called for invalid or nonexistent item " << cat_id << llendl; + } +} + +void remove_inventory_object( + const LLUUID& object_id, + LLPointer<LLInventoryCallback> cb) +{ + if (gInventory.getCategory(object_id)) + { + remove_inventory_category(object_id, cb); + } + else + { + remove_inventory_item(object_id, cb); + } +} + +class PurgeDescendentsResponder: public LLHTTPClient::Responder +{ +public: + PurgeDescendentsResponder(const LLUUID& item_id, LLPointer<LLInventoryCallback> callback): + mItemUUID(item_id), + mCallback(callback) + { + } + /* virtual */ void httpSuccess() + { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } + llinfos << "succeeded: " << ll_pretty_print_sd(content) << llendl; + + gInventory.onDescendentsPurgedFromServer(mItemUUID); + + if (mCallback) + { + mCallback->fire(mItemUUID); + } + } + /*virtual*/ void httpFailure() + { + const LLSD& content = getContent(); + S32 status = getStatus(); + const std::string& reason = getReason(); + if (!content.isMap()) + { + llwarns << "Malformed response contents " << content << " id " << mItemUUID << " status " << status << " reason " << reason << llendl; + return; + } + llwarns << "failed for " << mItemUUID << " content: " << ll_pretty_print_sd(content) << " status " << status << " reason " << reason << llendl; + } +private: + LLPointer<LLInventoryCallback> mCallback; + const LLUUID mItemUUID; +}; + +// This is a method which collects the descendents of the id +// provided. If the category is not found, no action is +// taken. This method goes through the long winded process of +// cancelling any calling cards, removing server representation of +// folders, items, etc in a fairly efficient manner. +void purge_descendents_of(const LLUUID& id, LLPointer<LLInventoryCallback> cb) +{ + LLInventoryModel::EHasChildren children = gInventory.categoryHasChildren(id); + if(children == LLInventoryModel::CHILDREN_NO) + { + llinfos << "No descendents to purge for " << id << llendl; + return; + } + LLPointer<LLViewerInventoryCategory> cat = gInventory.getCategory(id); + if (cat.notNull()) + { + if (LLClipboard::instance().hasContents() && LLClipboard::instance().isCutMode()) + { + // Something on the clipboard is in "cut mode" and needs to be preserved + llinfos << "purge_descendents_of clipboard case " << cat->getName() + << " iterate and purge non hidden items" << llendl; + LLInventoryModel::cat_array_t* categories; + LLInventoryModel::item_array_t* items; + // Get the list of direct descendants in tha categoy passed as argument + gInventory.getDirectDescendentsOf(id, categories, items); + std::vector<LLUUID> list_uuids; + // Make a unique list with all the UUIDs of the direct descendants (items and categories are not treated differently) + // Note: we need to do that shallow copy as purging things will invalidate the categories or items lists + for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); it != categories->end(); ++it) + { + list_uuids.push_back((*it)->getUUID()); + } + for (LLInventoryModel::item_array_t::const_iterator it = items->begin(); it != items->end(); ++it) + { + list_uuids.push_back((*it)->getUUID()); + } + // Iterate through the list and only purge the UUIDs that are not on the clipboard + for (std::vector<LLUUID>::const_iterator it = list_uuids.begin(); it != list_uuids.end(); ++it) + { + if (!LLClipboard::instance().isOnClipboard(*it)) + { + remove_inventory_object(*it, NULL); + } + } + } + else + { + std::string cap; + if (gAgent.getRegion() && gSavedSettings.getBOOL("UseAISv3Inventory")) + { + cap = gAgent.getRegion()->getCapability("InventoryAPIv3"); + } + if (!cap.empty()) + { + std::string url = cap + std::string("/category/") + id.asString() + "/children"; + llinfos << "url: " << url << llendl; + LLCurl::ResponderPtr responder_ptr = new PurgeDescendentsResponder(id,cb); + LLHTTPClient::del(url,responder_ptr); + } + else // no cap + { + // Fast purge + llinfos << "purge_descendents_of fast case " << cat->getName() << llendl; + + // send it upstream + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("PurgeInventoryDescendents"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->nextBlock("InventoryData"); + msg->addUUID("FolderID", id); + gAgent.sendReliableMessage(); + + // Update model immediately because there is no callback mechanism. + gInventory.onDescendentsPurgedFromServer(id); + if (cb) + { + cb->fire(id); + } + } + } + } +} + const LLUUID get_folder_by_itemtype(const LLInventoryItem *src) { LLUUID retval = LLUUID::null; diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index 61b1b8d846..4e24dc87d1 100644..100755 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -118,7 +118,6 @@ public: void cloneViewerItem(LLPointer<LLViewerInventoryItem>& newitem) const; // virtual methods - virtual void removeFromServer( void ); virtual void updateParentOnServer(BOOL restamp) const; virtual void updateServer(BOOL is_new) const; void fetchFromServer(void) const; @@ -198,7 +197,6 @@ public: LLViewerInventoryCategory(const LLViewerInventoryCategory* other); void copyViewerCategory(const LLViewerInventoryCategory* other); - virtual void removeFromServer(); virtual void updateParentOnServer(BOOL restamp_children) const; virtual void updateServer(BOOL is_new) const; @@ -274,7 +272,7 @@ class LLBoostFuncInventoryCallback: public LLInventoryCallback { public: - LLBoostFuncInventoryCallback(inventory_func_type fire_func, + LLBoostFuncInventoryCallback(inventory_func_type fire_func = no_op_inventory_func, nullary_func_type destroy_func = no_op): mFireFunc(fire_func), mDestroyFunc(destroy_func) @@ -365,6 +363,22 @@ void move_inventory_item( const std::string& new_name, LLPointer<LLInventoryCallback> cb); +void remove_inventory_item( + const LLUUID& item_id, + LLPointer<LLInventoryCallback> cb); + +void remove_inventory_category( + const LLUUID& cat_id, + LLPointer<LLInventoryCallback> cb); + +void remove_inventory_object( + const LLUUID& object_id, + LLPointer<LLInventoryCallback> cb); + +void purge_descendents_of( + const LLUUID& cat_id, + LLPointer<LLInventoryCallback> cb); + const LLUUID get_folder_by_itemtype(const LLInventoryItem *src); void copy_inventory_from_notecard(const LLUUID& destination_id, diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 2df028de69..2cec808f19 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -158,7 +158,7 @@ LLViewerMediaObserver::~LLViewerMediaObserver() // on the Panel Land Media and to discover the MIME type class LLMimeDiscoveryResponder : public LLHTTPClient::Responder { -LOG_CLASS(LLMimeDiscoveryResponder); + LOG_CLASS(LLMimeDiscoveryResponder); public: LLMimeDiscoveryResponder( viewer_media_t media_impl) : mMediaImpl(media_impl), @@ -177,13 +177,19 @@ public: disconnectOwner(); } - virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content) +private: + /* virtual */ void httpCompleted() { - std::string media_type = content["content-type"].asString(); + if (!isGoodStatus()) + { + llwarns << dumpResponse() + << " [headers:" << getResponseHeaders() << "]" << llendl; + } + const std::string& media_type = getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE); std::string::size_type idx1 = media_type.find_first_of(";"); std::string mime_type = media_type.substr(0, idx1); - lldebugs << "status is " << status << ", media type \"" << media_type << "\"" << llendl; + lldebugs << "status is " << getStatus() << ", media type \"" << media_type << "\"" << llendl; // 2xx status codes indicate success. // Most 4xx status codes are successful enough for our purposes. @@ -200,32 +206,27 @@ public: // ) // We now no longer check the error code returned from the probe. // If we have a mime type, use it. If not, default to the web plugin and let it handle error reporting. - if(1) + //if(1) { // The probe was successful. if(mime_type.empty()) { // Some sites don't return any content-type header at all. // Treat an empty mime type as text/html. - mime_type = "text/html"; + mime_type = HTTP_CONTENT_TEXT_HTML; } - - completeAny(status, mime_type); } - else - { - llwarns << "responder failed with status " << status << ", reason " << reason << llendl; - - if(mMediaImpl) - { - mMediaImpl->mMediaSourceFailed = true; - } - } - - } + //else + //{ + // llwarns << "responder failed with status " << dumpResponse() << llendl; + // + // if(mMediaImpl) + // { + // mMediaImpl->mMediaSourceFailed = true; + // } + // return; + //} - void completeAny(U32 status, const std::string& mime_type) - { // the call to initializeMedia may disconnect the responder, which will clear mMediaImpl. // Make a local copy so we can call loadURI() afterwards. LLViewerMediaImpl *impl = mMediaImpl; @@ -241,6 +242,7 @@ public: } } +public: void cancelRequest() { disconnectOwner(); @@ -269,7 +271,7 @@ public: class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder { -LOG_CLASS(LLViewerMediaOpenIDResponder); + LOG_CLASS(LLViewerMediaOpenIDResponder); public: LLViewerMediaOpenIDResponder( ) { @@ -279,23 +281,17 @@ public: { } - /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) - { - LL_DEBUGS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; - LL_DEBUGS("MediaAuth") << content << LL_ENDL; - std::string cookie = content["set-cookie"].asString(); - - LLViewerMedia::openIDCookieResponse(cookie); - } - /* virtual */ void completedRaw( - U32 status, - const std::string& reason, const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { - // This is just here to disable the default behavior (attempting to parse the response as llsd). - // We don't care about the content of the response, only the set-cookie header. + // We don't care about the content of the response, only the Set-Cookie header. + LL_DEBUGS("MediaAuth") << dumpResponse() + << " [headers:" << getResponseHeaders() << "]" << LL_ENDL; + const std::string& cookie = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE); + + // *TODO: What about bad status codes? Does this destroy previous cookies? + LLViewerMedia::openIDCookieResponse(cookie); } }; @@ -313,17 +309,23 @@ public: { } - /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) + void completedRaw( + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) { - LL_WARNS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; + // We don't care about the content of the response, only the set-cookie header. + LL_WARNS("MediaAuth") << dumpResponse() + << " [headers:" << getResponseHeaders() << "]" << LL_ENDL; - LLSD stripped_content = content; - stripped_content.erase("set-cookie"); + LLSD stripped_content = getResponseHeaders(); + // *TODO: Check that this works. + stripped_content.erase(HTTP_IN_HEADER_SET_COOKIE); LL_WARNS("MediaAuth") << stripped_content << LL_ENDL; - std::string cookie = content["set-cookie"].asString(); + const std::string& cookie = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE); LL_DEBUGS("MediaAuth") << "cookie = " << cookie << LL_ENDL; + // *TODO: What about bad status codes? Does this destroy previous cookies? LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost); // Set cookie for snapshot publishing. @@ -331,16 +333,6 @@ public: LLWebProfile::setAuthCookie(auth_cookie); } - void completedRaw( - U32 status, - const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - // This is just here to disable the default behavior (attempting to parse the response as llsd). - // We don't care about the content of the response, only the set-cookie header. - } - std::string mHost; }; @@ -1387,10 +1379,12 @@ void LLViewerMedia::removeCookie(const std::string &name, const std::string &dom LLSD LLViewerMedia::getHeaders() { LLSD headers = LLSD::emptyMap(); - headers["Accept"] = "*/*"; - headers["Content-Type"] = "application/xml"; - headers["Cookie"] = sOpenIDCookie; - headers["User-Agent"] = getCurrentUserAgent(); + headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; + // *TODO: Should this be 'application/llsd+xml' ? + // *TODO: Should this even be set at all? This header is only not overridden in 'GET' methods. + headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_XML; + headers[HTTP_OUT_HEADER_COOKIE] = sOpenIDCookie; + headers[HTTP_OUT_HEADER_USER_AGENT] = getCurrentUserAgent(); return headers; } @@ -1431,9 +1425,9 @@ void LLViewerMedia::setOpenIDCookie() // Do a web profile get so we can store the cookie LLSD headers = LLSD::emptyMap(); - headers["Accept"] = "*/*"; - headers["Cookie"] = sOpenIDCookie; - headers["User-Agent"] = getCurrentUserAgent(); + headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; + headers[HTTP_OUT_HEADER_COOKIE] = sOpenIDCookie; + headers[HTTP_OUT_HEADER_USER_AGENT] = getCurrentUserAgent(); std::string profile_url = getProfileURL(""); LLURL raw_profile_url( profile_url.c_str() ); @@ -1463,9 +1457,9 @@ void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string LLSD headers = LLSD::emptyMap(); // Keep LLHTTPClient from adding an "Accept: application/llsd+xml" header - headers["Accept"] = "*/*"; + headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; // and use the expected content-type for a post, instead of the LLHTTPClient::postRaw() default of "application/octet-stream" - headers["Content-Type"] = "application/x-www-form-urlencoded"; + headers[HTTP_OUT_HEADER_CONTENT_TYPE] = "application/x-www-form-urlencoded"; // postRaw() takes ownership of the buffer and releases it later, so we need to allocate a new buffer here. size_t size = openid_token.size(); @@ -1537,7 +1531,7 @@ void LLViewerMedia::createSpareBrowserMediaSource() // The null owner will keep the browser plugin from fully initializing // (specifically, it keeps LLPluginClassMedia from negotiating a size change, // which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color) - sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType("text/html", NULL, 0, 0); + sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType(HTTP_CONTENT_TEXT_HTML, NULL, 0, 0); } } @@ -2633,16 +2627,16 @@ void LLViewerMediaImpl::navigateInternal() // Accept: application/llsd+xml // which is really not what we want. LLSD headers = LLSD::emptyMap(); - headers["Accept"] = "*/*"; + headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; // Allow cookies in the response, to prevent a redirect loop when accessing join.secondlife.com - headers["Cookie"] = ""; + headers[HTTP_OUT_HEADER_COOKIE] = ""; LLHTTPClient::getHeaderOnly( mMediaURL, new LLMimeDiscoveryResponder(this), headers, 10.0f); } else if("data" == scheme || "file" == scheme || "about" == scheme) { // FIXME: figure out how to really discover the type for these schemes // We use "data" internally for a text/html url for loading the login screen - if(initializeMedia("text/html")) + if(initializeMedia(HTTP_CONTENT_TEXT_HTML)) { loadURI(); } diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 3c0d6189ac..40e6b0d09e 100755 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -3956,6 +3956,8 @@ void process_teleport_finish(LLMessageSystem* msg, void**) gAgent.setTeleportState( LLAgent::TELEPORT_MOVING ); gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages["contacting"]); + LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from process_teleport_finish(). Seed cap == " + << seedCap << LL_ENDL; regionp->setSeedCapability(seedCap); // Don't send camera updates to the new region until we're @@ -4210,6 +4212,9 @@ void process_crossed_region(LLMessageSystem* msg, void**) send_complete_agent_movement(sim_host); LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host); + + LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from process_crossed_region(). Seed cap == " + << seedCap << LL_ENDL; regionp->setSeedCapability(seedCap); } diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 11d34ad084..2d5f7768d5 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -671,6 +671,7 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent) class LLObjectCostResponder : public LLCurl::Responder { + LOG_CLASS(LLObjectCostResponder); public: LLObjectCostResponder(const LLSD& object_ids) : mObjectIDs(object_ids) @@ -691,20 +692,19 @@ public: } } - void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +private: + /* virtual */ void httpFailure() { - llwarns - << "Transport error requesting object cost " - << "[status: " << statusNum << "]: " - << content << llendl; + llwarns << dumpResponse() << llendl; // TODO*: Error message to user // For now just clear the request from the pending list clear_object_list_pending_requests(); } - void result(const LLSD& content) + /* virtual */ void httpSuccess() { + const LLSD& content = getContent(); if ( !content.isMap() || content.has("error") ) { // Improper response or the request had an error, @@ -760,6 +760,7 @@ private: class LLPhysicsFlagsResponder : public LLCurl::Responder { + LOG_CLASS(LLPhysicsFlagsResponder); public: LLPhysicsFlagsResponder(const LLSD& object_ids) : mObjectIDs(object_ids) @@ -780,20 +781,19 @@ public: } } - void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +private: + /* virtual */ void httpFailure() { - llwarns - << "Transport error requesting object physics flags " - << "[status: " << statusNum << "]: " - << content << llendl; + llwarns << dumpResponse() << llendl; // TODO*: Error message to user // For now just clear the request from the pending list clear_object_list_pending_requests(); } - void result(const LLSD& content) + /* virtual void */ void httpSuccess() { + const LLSD& content = getContent(); if ( !content.isMap() || content.has("error") ) { // Improper response or the request had an error, diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index 386b2fd400..d7e14ac6f5 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -99,7 +99,7 @@ void LLViewerParcelMedia::update(LLParcel* parcel) std::string mediaCurrentUrl = std::string( parcel->getMediaCurrentURL()); // if we have a current (link sharing) url, use it instead - if (mediaCurrentUrl != "" && parcel->getMediaType() == "text/html") + if (mediaCurrentUrl != "" && parcel->getMediaType() == HTTP_CONTENT_TEXT_HTML) { mediaUrl = mediaCurrentUrl; } diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index b8b53aa6e4..e77b29aca4 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -87,6 +87,8 @@ const S32 MAX_CAP_REQUEST_ATTEMPTS = 30; typedef std::map<std::string, std::string> CapabilityMap; +static void log_capabilities(const CapabilityMap &capmap); + class LLViewerRegionImpl { public: LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host) @@ -204,24 +206,30 @@ class BaseCapabilitiesComplete : public LLHTTPClient::Responder { LOG_CLASS(BaseCapabilitiesComplete); public: - BaseCapabilitiesComplete(U64 region_handle, S32 id) + BaseCapabilitiesComplete(U64 region_handle, S32 id) : mRegionHandle(region_handle), mID(id) - { } + { } virtual ~BaseCapabilitiesComplete() { } - void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) - { - LL_WARNS2("AppInit", "Capabilities") << "[status:" << statusNum << ":] " << content << LL_ENDL; + static BaseCapabilitiesComplete* build( U64 region_handle, S32 id ) + { + return new BaseCapabilitiesComplete(region_handle, id); + } + +private: + /* virtual */void httpFailure() + { + LL_WARNS2("AppInit", "Capabilities") << dumpResponse() << LL_ENDL; LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); if (regionp) { regionp->failedSeedCapability(); } - } + } - void result(const LLSD& content) - { + /* virtual */ void httpSuccess() + { LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); if(!regionp) //region was removed { @@ -234,11 +242,17 @@ public: return ; } + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } LLSD::map_const_iterator iter; for(iter = content.beginMap(); iter != content.endMap(); ++iter) { regionp->setCapability(iter->first, iter->second); - + LL_DEBUGS2("AppInit", "Capabilities") << "got capability for " << iter->first << LL_ENDL; @@ -257,11 +271,6 @@ public: } } - static BaseCapabilitiesComplete* build( U64 region_handle, S32 id ) - { - return new BaseCapabilitiesComplete(region_handle, id); - } - private: U64 mRegionHandle; S32 mID; @@ -278,19 +287,32 @@ public: virtual ~BaseCapabilitiesCompleteTracker() { } - void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) + static BaseCapabilitiesCompleteTracker* build( U64 region_handle ) { - llwarns << "BaseCapabilitiesCompleteTracker error [status:" - << statusNum << "]: " << content << llendl; + return new BaseCapabilitiesCompleteTracker( region_handle ); } - void result(const LLSD& content) +private: + /* virtual */ void httpFailure() + { + llwarns << dumpResponse() << llendl; + } + + /* virtual */ void httpSuccess() { LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); if( !regionp ) { + LL_WARNS2("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL; return ; - } + } + + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } LLSD::map_const_iterator iter; for(iter = content.beginMap(); iter != content.endMap(); ++iter) { @@ -300,27 +322,53 @@ public: if ( regionp->getRegionImpl()->mCapabilities.size() != regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() ) { - llinfos<<"BaseCapabilitiesCompleteTracker "<<"Sim sent duplicate seed caps that differs in size - most likely content."<<llendl; - //todo#add cap debug versus original check? - /*CapabilityMap::const_iterator iter = regionp->getRegionImpl()->mCapabilities.begin(); - while (iter!=regionp->getRegionImpl()->mCapabilities.end() ) + LL_WARNS2("AppInit", "Capabilities") + << "Sim sent duplicate base caps that differ in size from what we initially received - most likely content. " + << "mCapabilities == " << regionp->getRegionImpl()->mCapabilities.size() + << " mSecondCapabilitiesTracker == " << regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() + << LL_ENDL; + + //LL_WARNS2("AppInit", "Capabilities") + // << "Initial Base capabilities: " << LL_ENDL; + + //log_capabilities(regionp->getRegionImpl()->mCapabilities); + + //LL_WARNS2("AppInit", "Capabilities") + // << "Latest base capabilities: " << LL_ENDL; + + //log_capabilities(regionp->getRegionImpl()->mSecondCapabilitiesTracker); + + // *TODO + //add cap debug versus original check? + //CapabilityMap::const_iterator iter = regionp->getRegionImpl()->mCapabilities.begin(); + //while (iter!=regionp->getRegionImpl()->mCapabilities.end() ) + //{ + // llinfos<<"BaseCapabilitiesCompleteTracker Original "<<iter->first<<" "<< iter->second<<llendl; + // ++iter; + //} + + if (regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() > regionp->getRegionImpl()->mCapabilities.size() ) { - llinfos<<"BaseCapabilitiesCompleteTracker Original "<<iter->first<<" "<< iter->second<<llendl; - ++iter; + // *HACK Since we were granted more base capabilities in this grant request than the initial, replace + // the old with the new. This shouldn't happen i.e. we should always get the same capabilities from a + // sim. The simulator fix from SH-3895 should prevent it from happening, at least in the case of the + // inventory api capability grants. + + // Need to clear a std::map before copying into it because old keys take precedence. + regionp->getRegionImplNC()->mCapabilities.clear(); + regionp->getRegionImplNC()->mCapabilities = regionp->getRegionImpl()->mSecondCapabilitiesTracker; } - */ - regionp->getRegionImplNC()->mSecondCapabilitiesTracker.clear(); } - + else + { + LL_DEBUGS("CrossingCaps") << "Sim sent multiple base cap grants with matching sizes." << LL_ENDL; + } + regionp->getRegionImplNC()->mSecondCapabilitiesTracker.clear(); } - static BaseCapabilitiesCompleteTracker* build( U64 region_handle ) - { - return new BaseCapabilitiesCompleteTracker( region_handle ); - } private: - U64 mRegionHandle; + U64 mRegionHandle; }; @@ -1593,6 +1641,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("FetchInventory2"); capabilityNames.append("FetchInventoryDescendents2"); capabilityNames.append("IncrementCOFVersion"); + capabilityNames.append("InventoryAPIv3"); } capabilityNames.append("GetDisplayNames"); @@ -1655,7 +1704,9 @@ void LLViewerRegion::setSeedCapability(const std::string& url) { if (getCapability("Seed") == url) { - //llwarns << "Ignoring duplicate seed capability" << llendl; + setCapabilityDebug("Seed", url); + LL_DEBUGS("CrossingCaps") << "Received duplicate seed capability, posting to seed " << + url << llendl; //Instead of just returning we build up a second set of seed caps and compare them //to the "original" seed cap received and determine why there is problem! LLSD capabilityNames = LLSD::emptyArray(); @@ -1728,31 +1779,37 @@ class SimulatorFeaturesReceived : public LLHTTPClient::Responder { LOG_CLASS(SimulatorFeaturesReceived); public: - SimulatorFeaturesReceived(const std::string& retry_url, U64 region_handle, + SimulatorFeaturesReceived(const std::string& retry_url, U64 region_handle, S32 attempt = 0, S32 max_attempts = MAX_CAP_REQUEST_ATTEMPTS) - : mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts) - { } - - - void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) - { - LL_WARNS2("AppInit", "SimulatorFeatures") << "[status:" << statusNum << "]: " << content << LL_ENDL; + : mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts) + { } + +private: + /* virtual */ void httpFailure() + { + LL_WARNS2("AppInit", "SimulatorFeatures") << dumpResponse() << LL_ENDL; retry(); - } + } - void result(const LLSD& content) - { + /* virtual */ void httpSuccess() + { LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); if(!regionp) //region is removed or responder is not created. { - LL_WARNS2("AppInit", "SimulatorFeatures") << "Received results for region that no longer exists!" << LL_ENDL; + LL_WARNS2("AppInit", "SimulatorFeatures") + << "Received results for region that no longer exists!" << LL_ENDL; return ; } - + + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } regionp->setSimulatorFeatures(content); } -private: void retry() { if (mAttempt < mMaxAttempts) @@ -1762,7 +1819,7 @@ private: LLHTTPClient::get(mRetryURL, new SimulatorFeaturesReceived(*this), LLSD(), CAP_REQUEST_TIMEOUT); } } - + std::string mRetryURL; U64 mRegionHandle; S32 mAttempt; @@ -1799,7 +1856,16 @@ void LLViewerRegion::setCapability(const std::string& name, const std::string& u void LLViewerRegion::setCapabilityDebug(const std::string& name, const std::string& url) { - mImpl->mSecondCapabilitiesTracker[name] = url; + // Continue to not add certain caps, as we do in setCapability. This is so they match up when we check them later. + if ( ! ( name == "EventQueueGet" || name == "UntrustedSimulatorMessage" || name == "SimulatorFeatures" ) ) + { + mImpl->mSecondCapabilitiesTracker[name] = url; + if(name == "GetTexture") + { + mHttpUrl = url ; + } + } + } bool LLViewerRegion::isSpecialCapabilityName(const std::string &name) @@ -1850,16 +1916,7 @@ boost::signals2::connection LLViewerRegion::setCapabilitiesReceivedCallback(cons void LLViewerRegion::logActiveCapabilities() const { - int count = 0; - CapabilityMap::const_iterator iter; - for (iter = mImpl->mCapabilities.begin(); iter != mImpl->mCapabilities.end(); ++iter, ++count) - { - if (!iter->second.empty()) - { - llinfos << iter->first << " URL is " << iter->second << llendl; - } - } - llinfos << "Dumped " << count << " entries." << llendl; + log_capabilities(mImpl->mCapabilities); } LLSpatialPartition* LLViewerRegion::getSpatialPartition(U32 type) @@ -1943,3 +2000,19 @@ bool LLViewerRegion::dynamicPathfindingEnabled() const mSimulatorFeatures["DynamicPathfindingEnabled"].asBoolean()); } +/* Static Functions */ + +void log_capabilities(const CapabilityMap &capmap) +{ + S32 count = 0; + CapabilityMap::const_iterator iter; + for (iter = capmap.begin(); iter != capmap.end(); ++iter, ++count) + { + if (!iter->second.empty()) + { + llinfos << "log_capabilities: " << iter->first << " URL is " << iter->second << llendl; + } + } + llinfos << "log_capabilities: Dumped " << count << " entries." << llendl; +} + diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 35bba4184e..b73411080a 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -527,18 +527,19 @@ void update_statistics() class ViewerStatsResponder : public LLHTTPClient::Responder { + LOG_CLASS(ViewerStatsResponder); public: - ViewerStatsResponder() { } + ViewerStatsResponder() { } - void error(U32 statusNum, const std::string& reason) - { - llinfos << "ViewerStatsResponder::error " << statusNum << " " - << reason << llendl; - } +private: + /* virtual */ void httpFailure() + { + llwarns << dumpResponse() << llendl; + } - void result(const LLSD& content) - { - llinfos << "ViewerStatsResponder::result" << llendl; + /* virtual */ void httpSuccess() + { + llinfos << "OK" << llendl; } }; diff --git a/indra/newview/llviewertexlayer.cpp b/indra/newview/llviewertexlayer.cpp index 777e1f9c76..777e1f9c76 100755..100644 --- a/indra/newview/llviewertexlayer.cpp +++ b/indra/newview/llviewertexlayer.cpp diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index eb6c453e76..45b402f0f6 100644..100755 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1758,7 +1758,8 @@ bool LLViewerFetchedTexture::updateFetch() if (mRawImage.notNull()) sRawCount--; if (mAuxRawImage.notNull()) sAuxCount--; - bool finished = LLAppViewer::getTextureFetch()->getRequestFinished(getID(), fetch_discard, mRawImage, mAuxRawImage); + bool finished = LLAppViewer::getTextureFetch()->getRequestFinished(getID(), fetch_discard, mRawImage, mAuxRawImage, + mLastHttpGetStatus); if (mRawImage.notNull()) sRawCount++; if (mAuxRawImage.notNull()) sAuxCount++; if (finished) @@ -1823,10 +1824,15 @@ bool LLViewerFetchedTexture::updateFetch() // We finished but received no data if (current_discard < 0) { - llwarns << "!mIsFetching, setting as missing, decode_priority " << decode_priority - << " mRawDiscardLevel " << mRawDiscardLevel - << " current_discard " << current_discard - << llendl; + if (getFTType() != FTT_MAP_TILE) + { + llwarns << mID + << " Fetch failure, setting as missing, decode_priority " << decode_priority + << " mRawDiscardLevel " << mRawDiscardLevel + << " current_discard " << current_discard + << " stats " << mLastHttpGetStatus.toHex() + << llendl; + } setIsMissingAsset(); desired_discard = -1; } @@ -2005,29 +2011,43 @@ void LLViewerFetchedTexture::forceToDeleteRequest() mDesiredDiscardLevel = getMaxDiscardLevel() + 1; } -void LLViewerFetchedTexture::setIsMissingAsset() +void LLViewerFetchedTexture::setIsMissingAsset(BOOL is_missing) { - if (mUrl.empty()) + if (is_missing == mIsMissingAsset) { - llwarns << mID << ": Marking image as missing" << llendl; + return; } - else + if (is_missing) { - // This may or may not be an error - it is normal to have no - // map tile on an empty region, but bad if we're failing on a - // server bake texture. - llwarns << mUrl << ": Marking image as missing" << llendl; + if (mUrl.empty()) + { + llwarns << mID << ": Marking image as missing" << llendl; + } + else + { + // This may or may not be an error - it is normal to have no + // map tile on an empty region, but bad if we're failing on a + // server bake texture. + if (getFTType() != FTT_MAP_TILE) + { + llwarns << mUrl << ": Marking image as missing" << llendl; + } + } + if (mHasFetcher) + { + LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); + mHasFetcher = FALSE; + mIsFetching = FALSE; + mLastPacketTimer.reset(); + mFetchState = 0; + mFetchPriority = 0; + } } - if (mHasFetcher) + else { - LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); - mHasFetcher = FALSE; - mIsFetching = FALSE; - mLastPacketTimer.reset(); - mFetchState = 0; - mFetchPriority = 0; + llinfos << mID << ": un-flagging missing asset" << llendl; } - mIsMissingAsset = TRUE; + mIsMissingAsset = is_missing; } void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_callback, diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index f2e1a90713..bf6aadd218 100644..100755 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -34,6 +34,7 @@ #include "llgltypes.h" #include "llrender.h" #include "llmetricperformancetester.h" +#include "httpcommon.h" #include <map> #include <list> @@ -120,7 +121,7 @@ public: LLViewerTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) ; virtual S8 getType() const; - virtual BOOL isMissingAsset()const ; + virtual BOOL isMissingAsset() const ; virtual void dump(); // debug info to llinfos /*virtual*/ bool bindDefaultImage(const S32 stage = 0) ; @@ -338,8 +339,8 @@ public: // more data. /*virtual*/ void setKnownDrawSize(S32 width, S32 height); - void setIsMissingAsset(); - /*virtual*/ BOOL isMissingAsset() const { return mIsMissingAsset; } + void setIsMissingAsset(BOOL is_missing = true); + /*virtual*/ BOOL isMissingAsset() const { return mIsMissingAsset; } // returns dimensions of original image for local files (before power of two scaling) // and returns 0 for all asset system images @@ -446,10 +447,11 @@ protected: S8 mIsRawImageValid; S8 mHasFetcher; // We've made a fecth request S8 mIsFetching; // Fetch request is active - bool mCanUseHTTP ; //This texture can be fetched through http if true. + bool mCanUseHTTP; //This texture can be fetched through http if true. + LLCore::HttpStatus mLastHttpGetStatus; // Result of the most recently completed http request for this texture. FTType mFTType; // What category of image is this - map tile, server bake, etc? - mutable S8 mIsMissingAsset; // True if we know that there is no image asset with this image id in the database. + mutable BOOL mIsMissingAsset; // True if we know that there is no image asset with this image id in the database. typedef std::list<LLLoadedCallbackEntry*> callback_list_t; S8 mLoadedCallbackDesiredDiscardLevel; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 0910b7536d..8a52a8f334 100755 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1964,7 +1964,7 @@ void LLViewerWindow::initWorldUI() destinations->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL")); std::string url = gSavedSettings.getString("DestinationGuideURL"); url = LLWeb::expandURLSubstitutions(url, LLSD()); - destinations->navigateTo(url, "text/html"); + destinations->navigateTo(url, HTTP_CONTENT_TEXT_HTML); } LLMediaCtrl* avatar_picker = LLFloaterReg::getInstance("avatar")->findChild<LLMediaCtrl>("avatar_picker_contents"); if (avatar_picker) @@ -1972,7 +1972,7 @@ void LLViewerWindow::initWorldUI() avatar_picker->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL")); std::string url = gSavedSettings.getString("AvatarPickerURL"); url = LLWeb::expandURLSubstitutions(url, LLSD()); - avatar_picker->navigateTo(url, "text/html"); + avatar_picker->navigateTo(url, HTTP_CONTENT_TEXT_HTML); } } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 06fb23b84b..969106cceb 100755 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1884,6 +1884,10 @@ LLViewerFetchedTexture *LLVOAvatar::getBakedTextureImage(const U8 te, const LLUU LL_DEBUGS("Avatar") << avString() << "from URL " << url << llendl; result = LLViewerTextureManager::getFetchedTextureFromUrl( url, FTT_SERVER_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, uuid); + if (result->isMissingAsset()) + { + result->setIsMissingAsset(false); + } } else { @@ -2144,7 +2148,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) { LLVector3 tagPos = mRoot->getWorldPosition(); tagPos[VZ] -= mPelvisToFoot; - tagPos[VZ] += ( mBodySize[VZ] + 0.125f ); + tagPos[VZ] += ( mBodySize[VZ] + 0.125f ); // does not need mAvatarOffset -Nyx mVoiceVisualizer->setVoiceSourceWorldPosition( tagPos ); } }//if ( voiceEnabled ) @@ -2885,6 +2889,8 @@ void LLVOAvatar::idleUpdateNameTagPosition(const LLVector3& root_pos_last) local_camera_up.normalize(); local_camera_up = local_camera_up * inv_root_rot; + + // position is based on head position, does not require mAvatarOffset here. - Nyx LLVector3 avatar_ellipsoid(mBodySize.mV[VX] * 0.4f, mBodySize.mV[VY] * 0.4f, mBodySize.mV[VZ] * NAMETAG_VERT_OFFSET_WEIGHT); @@ -4408,7 +4414,7 @@ void LLVOAvatar::addLocalTextureStats( ETextureIndex idx, LLViewerFetchedTexture } const S32 MAX_TEXTURE_UPDATE_INTERVAL = 64 ; //need to call updateTextures() at least every 32 frames. -const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL = S32_MAX ; //frames +const S32 MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL = S32_MAX ; //frames void LLVOAvatar::checkTextureLoading() { static const F32 MAX_INVISIBLE_WAITING_TIME = 15.f ; //seconds @@ -4471,11 +4477,11 @@ const F32 ADDITIONAL_PRI = 0.5f; void LLVOAvatar::addBakedTextureStats( LLViewerFetchedTexture* imagep, F32 pixel_area, F32 texel_area_ratio, S32 boost_level) { //Note: - //if this function is not called for the last MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL frames, + //if this function is not called for the last MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL frames, //the texture pipeline will stop fetching this texture. imagep->resetTextureStats(); - imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL); + imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL); imagep->resetMaxVirtualSizeResetCounter() ; mMaxPixelArea = llmax(pixel_area, mMaxPixelArea); @@ -7301,7 +7307,7 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id ) LLViewerTexture* image_baked = getImage( mBakedTextureDatas[i].mTextureIndex, 0 ); if (id == image_baked->getID()) { - LL_DEBUGS("Avatar") << avString() << " i " << i << " id " << id << LL_ENDL; + //LL_DEBUGS("Avatar") << avString() << " i " << i << " id " << id << LL_ENDL; mBakedTextureDatas[i].mIsLoaded = true; mBakedTextureDatas[i].mLastTextureID = id; mBakedTextureDatas[i].mIsUsed = true; diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 85f6f25009..98e8491cb1 100755 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -991,7 +991,7 @@ protected: // Shared with LLVOAvatarSelf }; // LLVOAvatar extern const F32 SELF_ADDITIONAL_PRI; -extern const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL; +extern const S32 MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL; std::string get_sequential_numbered_file_name(const std::string& prefix, const std::string& suffix); diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index d54eb5f040..52c44e6e1b 100755 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -2241,6 +2241,7 @@ LLSD LLVOAvatarSelf::metricsData() class ViewerAppearanceChangeMetricsResponder: public LLCurl::Responder { + LOG_CLASS(ViewerAppearanceChangeMetricsResponder); public: ViewerAppearanceChangeMetricsResponder( S32 expected_sequence, volatile const S32 & live_sequence, @@ -2251,32 +2252,25 @@ public: { } - virtual void completed(U32 status, - const std::string& reason, - const LLSD& content) +private: + /* virtual */ void httpSuccess() { - gPendingMetricsUploads--; // if we add retry, this should be moved to the isGoodStatus case. - if (isGoodStatus(status)) - { - LL_DEBUGS("Avatar") << "OK" << LL_ENDL; - result(content); - } - else - { - LL_WARNS("Avatar") << "Failed " << status << " reason " << reason << LL_ENDL; - errorWithContent(status,reason,content); - } - } + LL_DEBUGS("Avatar") << "OK" << LL_ENDL; - // virtual - void result(const LLSD & content) - { + gPendingMetricsUploads--; if (mLiveSequence == mExpectedSequence) { mReportingStarted = true; } } + /* virtual */ void httpFailure() + { + // if we add retry, this should be removed from the httpFailure case + LL_WARNS("Avatar") << dumpResponse() << LL_ENDL; + gPendingMetricsUploads--; + } + private: S32 mExpectedSequence; volatile const S32 & mLiveSequence; @@ -2425,6 +2419,7 @@ void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics() class CheckAgentAppearanceServiceResponder: public LLHTTPClient::Responder { + LOG_CLASS(CheckAgentAppearanceServiceResponder); public: CheckAgentAppearanceServiceResponder() { @@ -2434,22 +2429,24 @@ public: { } - /* virtual */ void result(const LLSD& content) +private: + /* virtual */ void httpSuccess() { - LL_DEBUGS("Avatar") << "status OK" << llendl; + LL_DEBUGS("Avatar") << "OK" << llendl; } // Error - /*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content) + /*virtual*/ void httpFailure() { if (isAgentAvatarValid()) { - LL_DEBUGS("Avatar") << "failed, will rebake [status:" - << status << "]: " << content << llendl; + LL_DEBUGS("Avatar") << "failed, will rebake " + << dumpResponse() << LL_ENDL; forceAppearanceUpdate(); } - } + } +public: static void forceAppearanceUpdate() { // Trying to rebake immediately after crossing region boundary @@ -2590,7 +2587,7 @@ void LLVOAvatarSelf::addLocalTextureStats( ETextureIndex type, LLViewerFetchedTe imagep->setBoostLevel(getAvatarBoostLevel()); imagep->setAdditionalDecodePriority(SELF_ADDITIONAL_PRI) ; imagep->resetTextureStats(); - imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL); + imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL); imagep->addTextureStats( desired_pixels / texel_area_ratio ); imagep->forceUpdateBindStats() ; if (imagep->getDiscardLevel() < 0) diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp index ac2a34ba1e..397c5cd81f 100644 --- a/indra/newview/llvoicechannel.cpp +++ b/indra/newview/llvoicechannel.cpp @@ -53,26 +53,27 @@ const U32 DEFAULT_RETRIES_COUNT = 3; class LLVoiceCallCapResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLVoiceCallCapResponder); public: LLVoiceCallCapResponder(const LLUUID& session_id) : mSessionID(session_id) {}; +protected: // called with bad status codes - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); - virtual void result(const LLSD& content); + virtual void httpFailure(); + virtual void httpSuccess(); private: LLUUID mSessionID; }; -void LLVoiceCallCapResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLVoiceCallCapResponder::httpFailure() { - LL_WARNS("Voice") << "LLVoiceCallCapResponder error [status:" - << status << "]: " << content << LL_ENDL; + LL_WARNS("Voice") << dumpResponse() << LL_ENDL; LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); if ( channelp ) { - if ( 403 == status ) + if ( HTTP_FORBIDDEN == getStatus() ) { //403 == no ability LLNotificationsUtil::add( @@ -89,12 +90,18 @@ void LLVoiceCallCapResponder::errorWithContent(U32 status, const std::string& re } } -void LLVoiceCallCapResponder::result(const LLSD& content) +void LLVoiceCallCapResponder::httpSuccess() { LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); if (channelp) { //*TODO: DEBUG SPAM + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } LLSD::map_const_iterator iter; for(iter = content.beginMap(); iter != content.endMap(); ++iter) { diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 9b5d981aa5..838845df80 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -124,17 +124,19 @@ static int scale_speaker_volume(float volume) class LLVivoxVoiceAccountProvisionResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLVivoxVoiceAccountProvisionResponder); public: LLVivoxVoiceAccountProvisionResponder(int retries) { mRetries = retries; } - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +private: + /* virtual */ void httpFailure() { LL_WARNS("Voice") << "ProvisionVoiceAccountRequest returned an error, " << ( (mRetries > 0) ? "retrying" : "too many retries (giving up)" ) - << status << "]: " << content << LL_ENDL; + << " " << dumpResponse() << LL_ENDL; if ( mRetries > 0 ) { @@ -146,14 +148,19 @@ public: } } - virtual void result(const LLSD& content) + /* virtual */ void httpSuccess() { - std::string voice_sip_uri_hostname; std::string voice_account_server_uri; - LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response:" << ll_pretty_print_sd(content) << LL_ENDL; + LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response:" << dumpResponse() << LL_ENDL; + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } if(content.has("voice_sip_uri_hostname")) voice_sip_uri_hostname = content["voice_sip_uri_hostname"].asString(); @@ -166,7 +173,6 @@ public: content["password"].asString(), voice_sip_uri_hostname, voice_account_server_uri); - } private: @@ -197,33 +203,34 @@ static LLVivoxVoiceClientFriendsObserver *friendslist_listener = NULL; class LLVivoxVoiceClientCapResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLVivoxVoiceClientCapResponder); public: LLVivoxVoiceClientCapResponder(LLVivoxVoiceClient::state requesting_state) : mRequestingState(requesting_state) {}; +private: // called with bad status codes - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); - virtual void result(const LLSD& content); + /* virtual */ void httpFailure(); + /* virtual */ void httpSuccess(); -private: LLVivoxVoiceClient::state mRequestingState; // state }; -void LLVivoxVoiceClientCapResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLVivoxVoiceClientCapResponder::httpFailure() { - LL_WARNS("Voice") << "LLVivoxVoiceClientCapResponder error [status:" - << status << "]: " << content << LL_ENDL; + LL_WARNS("Voice") << dumpResponse() << LL_ENDL; LLVivoxVoiceClient::getInstance()->sessionTerminate(); } -void LLVivoxVoiceClientCapResponder::result(const LLSD& content) +void LLVivoxVoiceClientCapResponder::httpSuccess() { LLSD::map_const_iterator iter; - LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest response:" << ll_pretty_print_sd(content) << LL_ENDL; + LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest response:" << dumpResponse() << LL_ENDL; std::string uri; std::string credentials; + const LLSD& content = getContent(); if ( content.has("voice_credentials") ) { LLSD voice_credentials = content["voice_credentials"]; @@ -2979,7 +2986,7 @@ void LLVivoxVoiceClient::loginResponse(int statusCode, std::string &statusString // Status code of 20200 means "bad password". We may want to special-case that at some point. - if ( statusCode == 401 ) + if ( statusCode == HTTP_UNAUTHORIZED ) { // Login failure which is probably caused by the delay after a user's password being updated. LL_INFOS("Voice") << "Account.Login response failure (" << statusCode << "): " << statusString << LL_ENDL; @@ -3481,7 +3488,7 @@ void LLVivoxVoiceClient::mediaStreamUpdatedEvent( switch(statusCode) { case 0: - case 200: + case HTTP_OK: // generic success // Don't change the saved error code (it may have been set elsewhere) break; @@ -3831,7 +3838,7 @@ void LLVivoxVoiceClient::messageEvent( LL_DEBUGS("Voice") << "Message event, session " << sessionHandle << " from " << uriString << LL_ENDL; // LL_DEBUGS("Voice") << " header " << messageHeader << ", body: \n" << messageBody << LL_ENDL; - if(messageHeader.find("text/html") != std::string::npos) + if(messageHeader.find(HTTP_CONTENT_TEXT_HTML) != std::string::npos) { std::string message; @@ -6111,9 +6118,10 @@ void LLVivoxVoiceClient::notifyStatusObservers(LLVoiceClientStatusObserver::ESta { switch(mAudioSession->mErrorStatusCode) { - case 404: // NOT_FOUND + case HTTP_NOT_FOUND: // NOT_FOUND + // *TODO: Should this be 503? case 480: // TEMPORARILY_UNAVAILABLE - case 408: // REQUEST_TIMEOUT + case HTTP_REQUEST_TIME_OUT: // REQUEST_TIMEOUT // call failed because other user was not available // treat this as an error case status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE; diff --git a/indra/newview/llwebprofile.cpp b/indra/newview/llwebprofile.cpp index 641f338f2c..567138e160 100644 --- a/indra/newview/llwebprofile.cpp +++ b/indra/newview/llwebprofile.cpp @@ -67,9 +67,8 @@ public: { } + // *TODO: Check for 'application/json' content type, and parse json at the base class. /*virtual*/ void completedRaw( - U32 status, - const std::string& reason, const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { @@ -78,9 +77,9 @@ public: strstrm << istr.rdbuf(); const std::string body = strstrm.str(); - if (status != 200) + if (getStatus() != HTTP_OK) { - llwarns << "Failed to get upload config (" << status << ")" << llendl; + llwarns << "Failed to get upload config " << dumpResponse() << llendl; LLWebProfile::reportImageUploadStatus(false); return; } @@ -128,14 +127,12 @@ class LLWebProfileResponders::PostImageRedirectResponder : public LLHTTPClient:: public: /*virtual*/ void completedRaw( - U32 status, - const std::string& reason, const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { - if (status != 200) + if (getStatus() != HTTP_OK) { - llwarns << "Failed to upload image: " << status << " " << reason << llendl; + llwarns << "Failed to upload image " << dumpResponse() << llendl; LLWebProfile::reportImageUploadStatus(false); return; } @@ -161,33 +158,36 @@ class LLWebProfileResponders::PostImageResponder : public LLHTTPClient::Responde LOG_CLASS(LLWebProfileResponders::PostImageResponder); public: - /*virtual*/ void completedHeader(U32 status, const std::string& reason, const LLSD& content) + /*virtual*/ void completedRaw(const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) { // Viewer seems to fail to follow a 303 redirect on POST request // (URLRequest Error: 65, Send failed since rewinding of the data stream failed). // Handle it manually. - if (status == 303) + if (getStatus() == HTTP_SEE_OTHER) { LLSD headers = LLViewerMedia::getHeaders(); - headers["Cookie"] = LLWebProfile::getAuthCookie(); - const std::string& redir_url = content["location"]; - LL_DEBUGS("Snapshots") << "Got redirection URL: " << redir_url << llendl; - LLHTTPClient::get(redir_url, new LLWebProfileResponders::PostImageRedirectResponder, headers); + headers[HTTP_OUT_HEADER_COOKIE] = LLWebProfile::getAuthCookie(); + const std::string& redir_url = getResponseHeader(HTTP_IN_HEADER_LOCATION); + if (redir_url.empty()) + { + llwarns << "Received empty redirection URL " << dumpResponse() << llendl; + LL_DEBUGS("Snapshots") << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; + LLWebProfile::reportImageUploadStatus(false); + } + else + { + LL_DEBUGS("Snapshots") << "Got redirection URL: " << redir_url << llendl; + LLHTTPClient::get(redir_url, new LLWebProfileResponders::PostImageRedirectResponder, headers); + } } else { - llwarns << "Unexpected POST status: " << status << " " << reason << llendl; - LL_DEBUGS("Snapshots") << "headers: [" << content << "]" << llendl; + llwarns << "Unexpected POST response " << dumpResponse() << llendl; + LL_DEBUGS("Snapshots") << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; LLWebProfile::reportImageUploadStatus(false); } } - - // Override just to suppress warnings. - /*virtual*/ void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - } }; /////////////////////////////////////////////////////////////////////////////// @@ -206,7 +206,7 @@ void LLWebProfile::uploadImage(LLPointer<LLImageFormatted> image, const std::str LL_DEBUGS("Snapshots") << "Requesting " << config_url << llendl; LLSD headers = LLViewerMedia::getHeaders(); - headers["Cookie"] = getAuthCookie(); + headers[HTTP_OUT_HEADER_COOKIE] = getAuthCookie(); LLHTTPClient::get(config_url, new LLWebProfileResponders::ConfigResponder(image), headers); } @@ -230,8 +230,8 @@ void LLWebProfile::post(LLPointer<LLImageFormatted> image, const LLSD& config, c const std::string boundary = "----------------------------0123abcdefab"; LLSD headers = LLViewerMedia::getHeaders(); - headers["Cookie"] = getAuthCookie(); - headers["Content-Type"] = "multipart/form-data; boundary=" + boundary; + headers[HTTP_OUT_HEADER_COOKIE] = getAuthCookie(); + headers[HTTP_OUT_HEADER_CONTENT_TYPE] = "multipart/form-data; boundary=" + boundary; std::ostringstream body; diff --git a/indra/newview/llwebsharing.cpp b/indra/newview/llwebsharing.cpp index 3a80051b9b..7036162014 100644 --- a/indra/newview/llwebsharing.cpp +++ b/indra/newview/llwebsharing.cpp @@ -32,7 +32,7 @@ #include "llagentui.h" #include "llbufferstream.h" #include "llhttpclient.h" -#include "llhttpstatuscodes.h" +#include "llhttpconstants.h" #include "llsdserialize.h" #include "llsdutil.h" #include "llurl.h" @@ -45,36 +45,79 @@ /////////////////////////////////////////////////////////////////////////////// // -class LLWebSharingConfigResponder : public LLHTTPClient::Responder + +class LLWebSharingJSONResponder : public LLHTTPClient::Responder { - LOG_CLASS(LLWebSharingConfigResponder); + LOG_CLASS(LLWebSharingJSONResponder); public: /// Overrides the default LLSD parsing behaviour, to allow parsing a JSON response. - virtual void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, + virtual void completedRaw(const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { - LLSD content; LLBufferStream istr(channels, buffer.get()); + // *TODO: LLSD notation is not actually JSON. LLPointer<LLSDParser> parser = new LLSDNotationParser(); - if (parser->parse(istr, content, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE) + std::string debug_body("(empty)"); + bool parsed=true; + if (EOF == istr.peek()) { - LL_WARNS("WebSharing") << "Failed to deserialize LLSD from JSON response. " << " [" << status << "]: " << reason << LL_ENDL; + parsed=false; } - else + // Try to parse body as llsd, no matter what 'content-type' says. + else if (parser->parse(istr, mContent, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE) { - completed(status, reason, content); + 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; + } } + + // Only emit a warning if we failed to parse when 'content-type' == 'application/json' + if (!parsed && (HTTP_CONTENT_JSON == getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE))) + { + llwarns << "Failed to deserialize LLSD from JSON response. " << getURL() + << " [status:" << mStatus << "] " + << "(" << mReason << ") body: " << debug_body << llendl; + } + + if (!parsed) + { + // *TODO: This isn't necessarily the server's fault. Using a 5xx code + // isn't really appropriate here. + // Also, this hides the actual status returned by the server.... + mStatus = HTTP_INTERNAL_ERROR; + mReason = "Failed to deserialize LLSD from JSON response."; + } + + httpCompleted(); } +}; - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +class LLWebSharingConfigResponder : public LLWebSharingJSONResponder +{ + LOG_CLASS(LLWebSharingConfigResponder); +private: + + virtual void httpFailure() { - LL_WARNS("WebSharing") << "Error [status:" << status << "]: " << content << LL_ENDL; + LL_WARNS("WebSharing") << dumpResponse() << LL_ENDL; } - virtual void result(const LLSD& content) + virtual void httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } LLWebSharing::instance().receiveConfig(content); } }; @@ -87,39 +130,34 @@ class LLWebSharingOpenIDAuthResponder : public LLHTTPClient::Responder { LOG_CLASS(LLWebSharingOpenIDAuthResponder); public: - /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) - { - completed(status, reason, content); - } - - /* virtual */ void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, + /* virtual */ void completedRaw(const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { /// Left empty to override the default LLSD parsing behaviour. + httpCompleted(); } - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +private: + virtual void httpFailure() { - if (HTTP_UNAUTHORIZED == status) + if (HTTP_UNAUTHORIZED == getStatus()) { LL_WARNS("WebSharing") << "AU account not authenticated." << LL_ENDL; // *TODO: No account found on AU, so start the account creation process here. } else { - LL_WARNS("WebSharing") << "Error [status:" << status << "]: " << content << LL_ENDL; + LL_WARNS("WebSharing") << dumpResponse() << LL_ENDL; LLWebSharing::instance().retryOpenIDAuth(); } - } - virtual void result(const LLSD& content) + virtual void httpSuccess() { - if (content.has("set-cookie")) + if (hasResponseHeader(HTTP_IN_HEADER_SET_COOKIE)) { // OpenID request succeeded and returned a session cookie. - LLWebSharing::instance().receiveSessionCookie(content["set-cookie"].asString()); + LLWebSharing::instance().receiveSessionCookie(getResponseHeader(HTTP_IN_HEADER_SET_COOKIE)); } } }; @@ -128,38 +166,19 @@ public: /////////////////////////////////////////////////////////////////////////////// // -class LLWebSharingSecurityTokenResponder : public LLHTTPClient::Responder +class LLWebSharingSecurityTokenResponder : public LLWebSharingJSONResponder { LOG_CLASS(LLWebSharingSecurityTokenResponder); -public: - /// Overrides the default LLSD parsing behaviour, to allow parsing a JSON response. - virtual void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) +private: + virtual void httpFailure() { - LLSD content; - LLBufferStream istr(channels, buffer.get()); - LLPointer<LLSDParser> parser = new LLSDNotationParser(); - - if (parser->parse(istr, content, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE) - { - LL_WARNS("WebSharing") << "Failed to deserialize LLSD from JSON response. " << " [" << status << "]: " << reason << LL_ENDL; - LLWebSharing::instance().retryOpenIDAuth(); - } - else - { - completed(status, reason, content); - } - } - - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) - { - LL_WARNS("WebSharing") << "Error [status:" << status << "]: " << content << LL_ENDL; + LL_WARNS("WebSharing") << dumpResponse() << LL_ENDL; LLWebSharing::instance().retryOpenIDAuth(); } - virtual void result(const LLSD& content) + virtual void httpSuccess() { + const LLSD& content = getContent(); if (content[0].has("st") && content[0].has("expires")) { const std::string& token = content[0]["st"].asString(); @@ -172,7 +191,8 @@ public: } else { - LL_WARNS("WebSharing") << "No security token received." << LL_ENDL; + failureResult(HTTP_INTERNAL_ERROR, "No security token received.", content); + return; } LLWebSharing::instance().retryOpenIDAuth(); @@ -183,51 +203,18 @@ public: /////////////////////////////////////////////////////////////////////////////// // -class LLWebSharingUploadResponder : public LLHTTPClient::Responder +class LLWebSharingUploadResponder : public LLWebSharingJSONResponder { LOG_CLASS(LLWebSharingUploadResponder); -public: - /// Overrides the default LLSD parsing behaviour, to allow parsing a JSON response. - virtual void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { -/* - // Dump the body, for debugging. - - LLBufferStream istr1(channels, buffer.get()); - std::ostringstream ostr; - std::string body; - - while (istr1.good()) - { - char buf[1024]; - istr1.read(buf, sizeof(buf)); - body.append(buf, istr1.gcount()); - } - LL_DEBUGS("WebSharing") << body << LL_ENDL; -*/ - LLSD content; - LLBufferStream istr(channels, buffer.get()); - LLPointer<LLSDParser> parser = new LLSDNotationParser(); - - if (parser->parse(istr, content, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE) - { - LL_WARNS("WebSharing") << "Failed to deserialize LLSD from JSON response. " << " [" << status << "]: " << reason << LL_ENDL; - } - else - { - completed(status, reason, content); - } - } - - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +private: + virtual void httpFailure() { - LL_WARNS("WebSharing") << "Error [status:" << status << "]: " << content << LL_ENDL; + LL_WARNS("WebSharing") << dumpResponse() << LL_ENDL; } - virtual void result(const LLSD& content) + virtual void httpSuccess() { + const LLSD& content = getContent(); if (content[0].has("result") && content[0].has("id") && content[0]["id"].asString() == "newMediaItem") { @@ -235,8 +222,8 @@ public: } else { - LL_WARNS("WebSharing") << "Error [" << content[0]["code"].asString() - << "]: " << content[0]["message"].asString() << LL_ENDL; + failureResult(HTTP_INTERNAL_ERROR, "Invalid response content", content); + return; } } }; @@ -333,7 +320,7 @@ void LLWebSharing::sendConfigRequest() LL_DEBUGS("WebSharing") << "Requesting Snapshot Sharing config data from: " << config_url << LL_ENDL; LLSD headers = LLSD::emptyMap(); - headers["Accept"] = "application/json"; + headers[HTTP_OUT_HEADER_ACCEPT] = HTTP_CONTENT_JSON; LLHTTPClient::get(config_url, new LLWebSharingConfigResponder(), headers); } @@ -344,8 +331,8 @@ void LLWebSharing::sendOpenIDAuthRequest() LL_DEBUGS("WebSharing") << "Starting OpenID Auth: " << auth_url << LL_ENDL; LLSD headers = LLSD::emptyMap(); - headers["Cookie"] = mOpenIDCookie; - headers["Accept"] = "*/*"; + headers[HTTP_OUT_HEADER_COOKIE] = mOpenIDCookie; + headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; // Send request, successful login will trigger fetching a security token. LLHTTPClient::get(auth_url, new LLWebSharingOpenIDAuthResponder(), headers); @@ -371,10 +358,10 @@ void LLWebSharing::sendSecurityTokenRequest() LL_DEBUGS("WebSharing") << "Fetching security token from: " << token_url << LL_ENDL; LLSD headers = LLSD::emptyMap(); - headers["Cookie"] = mSessionCookie; + headers[HTTP_OUT_HEADER_COOKIE] = mSessionCookie; - headers["Accept"] = "application/json"; - headers["Content-Type"] = "application/json"; + headers[HTTP_OUT_HEADER_ACCEPT] = HTTP_CONTENT_JSON; + headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_JSON; std::ostringstream body; body << "{ \"gadgets\": [{ \"url\":\"" @@ -400,10 +387,10 @@ void LLWebSharing::sendUploadRequest() static const std::string BOUNDARY("------------abcdef012345xyZ"); LLSD headers = LLSD::emptyMap(); - headers["Cookie"] = mSessionCookie; + headers[HTTP_OUT_HEADER_COOKIE] = mSessionCookie; - headers["Accept"] = "application/json"; - headers["Content-Type"] = "multipart/form-data; boundary=" + BOUNDARY; + headers[HTTP_OUT_HEADER_ACCEPT] = HTTP_CONTENT_JSON; + headers[HTTP_OUT_HEADER_CONTENT_TYPE] = "multipart/form-data; boundary=" + BOUNDARY; std::ostringstream body; body << "--" << BOUNDARY << "\r\n" diff --git a/indra/newview/llwlhandlers.cpp b/indra/newview/llwlhandlers.cpp index 93eba5b604..3bedfbe502 100644 --- a/indra/newview/llwlhandlers.cpp +++ b/indra/newview/llwlhandlers.cpp @@ -95,8 +95,9 @@ LLEnvironmentRequestResponder::LLEnvironmentRequestResponder() { mID = ++sCount; } -/*virtual*/ void LLEnvironmentRequestResponder::result(const LLSD& unvalidated_content) +/*virtual*/ void LLEnvironmentRequestResponder::httpSuccess() { + const LLSD& unvalidated_content = getContent(); LL_INFOS("WindlightCaps") << "Received region windlight settings" << LL_ENDL; if (mID != sCount) @@ -122,10 +123,10 @@ LLEnvironmentRequestResponder::LLEnvironmentRequestResponder() LLEnvManagerNew::getInstance()->onRegionSettingsResponse(unvalidated_content); } /*virtual*/ -void LLEnvironmentRequestResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLEnvironmentRequestResponder::httpFailure() { - LL_INFOS("WindlightCaps") << "Got an error, not using region windlight... [status:" - << status << "]: " << content << LL_ENDL; + LL_WARNS("WindlightCaps") << "Got an error, not using region windlight... " + << dumpResponse() << LL_ENDL; LLEnvManagerNew::getInstance()->onRegionSettingsResponse(LLSD()); } @@ -169,8 +170,14 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content) /**** * LLEnvironmentApplyResponder ****/ -/*virtual*/ void LLEnvironmentApplyResponder::result(const LLSD& content) +/*virtual*/ void LLEnvironmentApplyResponder::httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap() || !content.has("regionID")) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } if (content["regionID"].asUUID() != gAgent.getRegion()->getRegionID()) { LL_WARNS("WindlightCaps") << "No longer in the region where data was sent (currently " @@ -185,7 +192,7 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content) } else { - LL_WARNS("WindlightCaps") << "Region couldn't apply windlight settings! Reason from sim: " << content["fail_reason"].asString() << LL_ENDL; + LL_WARNS("WindlightCaps") << "Region couldn't apply windlight settings! " << dumpResponse() << LL_ENDL; LLSD args(LLSD::emptyMap()); args["FAIL_REASON"] = content["fail_reason"].asString(); LLNotificationsUtil::add("WLRegionApplyFail", args); @@ -193,14 +200,14 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content) } } /*virtual*/ -void LLEnvironmentApplyResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLEnvironmentApplyResponder::httpFailure() { - LL_WARNS("WindlightCaps") << "Couldn't apply windlight settings to region! [status:" - << status << "]: " << content << LL_ENDL; + LL_WARNS("WindlightCaps") << "Couldn't apply windlight settings to region! " + << dumpResponse() << LL_ENDL; LLSD args(LLSD::emptyMap()); std::stringstream msg; - msg << reason << " (Code " << status << ")"; + msg << getReason() << " (Code " << getStatus() << ")"; args["FAIL_REASON"] = msg.str(); LLNotificationsUtil::add("WLRegionApplyFail", args); } diff --git a/indra/newview/llwlhandlers.h b/indra/newview/llwlhandlers.h index 598ce6d52a..089c799da7 100644 --- a/indra/newview/llwlhandlers.h +++ b/indra/newview/llwlhandlers.h @@ -45,9 +45,9 @@ private: class LLEnvironmentRequestResponder: public LLHTTPClient::Responder { LOG_CLASS(LLEnvironmentRequestResponder); -public: - virtual void result(const LLSD& content); - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); +private: + /* virtual */ void httpSuccess(); + /* virtual */ void httpFailure(); private: friend class LLEnvironmentRequest; @@ -72,7 +72,7 @@ private: class LLEnvironmentApplyResponder: public LLHTTPClient::Responder { LOG_CLASS(LLEnvironmentApplyResponder); -public: +private: /* * Expecting reply from sim in form of: * { @@ -87,10 +87,10 @@ public: * fail_reason : string * } */ - virtual void result(const LLSD& content); + /* virtual */ void httpSuccess(); - // non-200 errors only - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); + // non-2xx errors only + /* virtual */ void httpFailure(); private: friend class LLEnvironmentApply; diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 793becf0c8..d9da639af9 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -1065,6 +1065,8 @@ public: << sim << llendl; return; } + LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from LLEstablishAgentCommunication::post. Seed cap == " + << input["body"]["seed-capability"] << LL_ENDL; regionp->setSeedCapability(input["body"]["seed-capability"]); } }; diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index 0da70d398b..7c5f8be1b5 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -331,7 +331,7 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip) This might help with bug #503 */ mCurlRequest->setopt(CURLOPT_DNS_CACHE_TIMEOUT, -1); - mCurlRequest->slist_append("Content-Type: text/xml"); + mCurlRequest->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML); if (useGzip) { diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 105bef7321..1ff63c6def 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -10030,5 +10030,19 @@ Cannot create large prims that intersect other players. Please re-try when othe name="okignore" yestext="OK"/> </notification> - + + + <notification + icon="alertmodal.tga" + name="ConfirmExitWithoutSave" + type="alertmodal"> + Closing this window will discard any changes you have made. + <tag>confirm</tag> + <usetemplate + name="okcancelignore" + notext="Cancel" + yestext="OK" + ignoretext="Don't show me this again."/> + </notification> + </notifications> diff --git a/indra/newview/tests/llhttpretrypolicy_test.cpp b/indra/newview/tests/llhttpretrypolicy_test.cpp new file mode 100755 index 0000000000..ed7f3ba326 --- /dev/null +++ b/indra/newview/tests/llhttpretrypolicy_test.cpp @@ -0,0 +1,321 @@ +/** + * @file llhttpretrypolicy_test.cpp + * @brief Header tests to exercise the LLHTTPRetryPolicy classes. + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * 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 "../llviewerprecompiledheaders.h" +#include "../llhttpretrypolicy.h" +#include "lltut.h" + +namespace tut +{ +struct TestData +{ +}; + +typedef test_group<TestData> RetryPolicyTestGroup; +typedef RetryPolicyTestGroup::object RetryPolicyTestObject; +RetryPolicyTestGroup retryPolicyTestGroup("retry_policy"); + +template<> template<> +void RetryPolicyTestObject::test<1>() +{ + LLAdaptiveRetryPolicy never_retry(1.0,1.0,1.0,0); + LLSD headers; + F32 wait_seconds; + + // No retry until we've failed a try. + ensure("never retry 0", !never_retry.shouldRetry(wait_seconds)); + + // 0 retries max. + never_retry.onFailure(500,headers); + ensure("never retry 1", !never_retry.shouldRetry(wait_seconds)); +} + +template<> template<> +void RetryPolicyTestObject::test<2>() +{ + LLAdaptiveRetryPolicy retry404(1.0,2.0,3.0,10); + LLSD headers; + F32 wait_seconds; + + retry404.onFailure(404,headers); + ensure("no retry on 404", !retry404.shouldRetry(wait_seconds)); +} + +template<> template<> +void RetryPolicyTestObject::test<3>() +{ + // Should retry after 1.0, 2.0, 3.0, 3.0 seconds. + LLAdaptiveRetryPolicy basic_retry(1.0,3.0,2.0,4); + LLSD headers; + F32 wait_seconds; + bool should_retry; + U32 frac_bits = 6; + + // No retry until we've failed a try. + ensure("basic_retry 0", !basic_retry.shouldRetry(wait_seconds)); + + // Starting wait 1.0 + basic_retry.onFailure(500,headers); + should_retry = basic_retry.shouldRetry(wait_seconds); + ensure("basic_retry 1", should_retry); + ensure_approximately_equals("basic_retry 1", wait_seconds, 1.0F, frac_bits); + + // Double wait to 2.0 + basic_retry.onFailure(500,headers); + should_retry = basic_retry.shouldRetry(wait_seconds); + ensure("basic_retry 2", should_retry); + ensure_approximately_equals("basic_retry 2", wait_seconds, 2.0F, frac_bits); + + // Hit max wait of 3.0 (4.0 clamped to max 3) + basic_retry.onFailure(500,headers); + should_retry = basic_retry.shouldRetry(wait_seconds); + ensure("basic_retry 3", should_retry); + ensure_approximately_equals("basic_retry 3", wait_seconds, 3.0F, frac_bits); + + // At max wait, should stay at 3.0 + basic_retry.onFailure(500,headers); + should_retry = basic_retry.shouldRetry(wait_seconds); + ensure("basic_retry 4", should_retry); + ensure_approximately_equals("basic_retry 4", wait_seconds, 3.0F, frac_bits); + + // Max retries, should fail now. + basic_retry.onFailure(500,headers); + should_retry = basic_retry.shouldRetry(wait_seconds); + ensure("basic_retry 5", !should_retry); + + // Max retries, should fail now. + basic_retry.onFailure(500,headers); + should_retry = basic_retry.shouldRetry(wait_seconds); + ensure("basic_retry 5", !should_retry); + + // After a success, should reset to the starting state. + basic_retry.onSuccess(); + + // No retry until we've failed a try. + ensure("basic_retry 6", !basic_retry.shouldRetry(wait_seconds)); + + // Starting wait 1.0 + basic_retry.onFailure(500,headers); + should_retry = basic_retry.shouldRetry(wait_seconds); + ensure("basic_retry 7", should_retry); + ensure_approximately_equals("basic_retry 7", wait_seconds, 1.0F, frac_bits); + + // Double wait to 2.0 + basic_retry.onFailure(500,headers); + should_retry = basic_retry.shouldRetry(wait_seconds); + ensure("basic_retry 8", should_retry); + ensure_approximately_equals("basic_retry 8", wait_seconds, 2.0F, frac_bits); +} + +// Retries should stop as soon as a non-5xx error is received. +template<> template<> +void RetryPolicyTestObject::test<4>() +{ + // Should retry after 1.0, 2.0, 3.0, 3.0 seconds. + LLAdaptiveRetryPolicy killer404(1.0,3.0,2.0,4); + LLSD headers; + F32 wait_seconds; + bool should_retry; + U32 frac_bits = 6; + + // Starting wait 1.0 + killer404.onFailure(500,headers); + should_retry = killer404.shouldRetry(wait_seconds); + ensure("killer404 1", should_retry); + ensure_approximately_equals("killer404 1", wait_seconds, 1.0F, frac_bits); + + // Double wait to 2.0 + killer404.onFailure(500,headers); + should_retry = killer404.shouldRetry(wait_seconds); + ensure("killer404 2", should_retry); + ensure_approximately_equals("killer404 2", wait_seconds, 2.0F, frac_bits); + + // Should fail on non-5xx + killer404.onFailure(404,headers); + should_retry = killer404.shouldRetry(wait_seconds); + ensure("killer404 3", !should_retry); + + // After a non-5xx, should keep failing. + killer404.onFailure(500,headers); + should_retry = killer404.shouldRetry(wait_seconds); + ensure("killer404 4", !should_retry); +} + +// Test handling of "retry-after" header. If present, this header +// value overrides the computed delay, but does not affect the +// progression of delay values. For example, if the normal +// progression of delays would be 1,2,4,8..., but the 2nd and 3rd calls +// get a retry header of 33, the pattern would become 1,33,33,8... +template<> template<> +void RetryPolicyTestObject::test<5>() +{ + LLAdaptiveRetryPolicy policy(1.0,25.0,2.0,6); + LLSD headers_with_retry; + headers_with_retry[HTTP_IN_HEADER_RETRY_AFTER] = "666"; + LLSD headers_without_retry; + F32 wait_seconds; + bool should_retry; + U32 frac_bits = 6; + + policy.onFailure(500,headers_without_retry); + should_retry = policy.shouldRetry(wait_seconds); + ensure("retry header 1", should_retry); + ensure_approximately_equals("retry header 1", wait_seconds, 1.0F, frac_bits); + + policy.onFailure(500,headers_without_retry); + should_retry = policy.shouldRetry(wait_seconds); + ensure("retry header 2", should_retry); + ensure_approximately_equals("retry header 2", wait_seconds, 2.0F, frac_bits); + + policy.onFailure(500,headers_with_retry); + should_retry = policy.shouldRetry(wait_seconds); + ensure("retry header 3", should_retry); + // 4.0 overrides by header -> 666.0 + ensure_approximately_equals("retry header 3", wait_seconds, 666.0F, frac_bits); + + policy.onFailure(500,headers_with_retry); + should_retry = policy.shouldRetry(wait_seconds); + ensure("retry header 4", should_retry); + // 8.0 overrides by header -> 666.0 + ensure_approximately_equals("retry header 4", wait_seconds, 666.0F, frac_bits); + + policy.onFailure(500,headers_without_retry); + should_retry = policy.shouldRetry(wait_seconds); + ensure("retry header 5", should_retry); + ensure_approximately_equals("retry header 5", wait_seconds, 16.0F, frac_bits); + + policy.onFailure(500,headers_without_retry); + should_retry = policy.shouldRetry(wait_seconds); + ensure("retry header 6", should_retry); + ensure_approximately_equals("retry header 6", wait_seconds, 25.0F, frac_bits); + + policy.onFailure(500,headers_with_retry); + should_retry = policy.shouldRetry(wait_seconds); + ensure("retry header 7", !should_retry); +} + +// Test getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait), +// used by header parsing of the retry policy. +template<> template<> +void RetryPolicyTestObject::test<6>() +{ + F32 seconds_to_wait; + bool success; + + std::string str1("0"); + seconds_to_wait = F32_MAX; + success = getSecondsUntilRetryAfter(str1, seconds_to_wait); + ensure("parse 1", success); + ensure_equals("parse 1", seconds_to_wait, 0.0); + + std::string str2("999.9"); + seconds_to_wait = F32_MAX; + success = getSecondsUntilRetryAfter(str2, seconds_to_wait); + ensure("parse 2", success); + ensure_approximately_equals("parse 2", seconds_to_wait, 999.9F, 8); + + time_t nowseconds; + time(&nowseconds); + std::string str3 = LLDate((F64)(nowseconds+44)).asRFC1123(); + seconds_to_wait = F32_MAX; + success = getSecondsUntilRetryAfter(str3, seconds_to_wait); + std::cerr << " str3 [" << str3 << "]" << std::endl; + ensure("parse 3", success); + ensure_approximately_equals_range("parse 3", seconds_to_wait, 44.0F, 2.0F); +} + +// Test retry-after field in both llmessage and CoreHttp headers. +template<> template<> +void RetryPolicyTestObject::test<7>() +{ + std::cerr << "7 starts" << std::endl; + + LLSD sd_headers; + time_t nowseconds; + time(&nowseconds); + LLAdaptiveRetryPolicy policy(17.0,644.0,3.0,5); + F32 seconds_to_wait; + bool should_retry; + + // No retry until we've failed a try. + ensure("header 0", !policy.shouldRetry(seconds_to_wait)); + + // no retry header, use default. + policy.onFailure(500,LLSD()); + should_retry = policy.shouldRetry(seconds_to_wait); + ensure("header 1", should_retry); + ensure_approximately_equals("header 1", seconds_to_wait, 17.0F, 6); + + // retry header should override, give delay of 0 + std::string date_string = LLDate((F64)(nowseconds+7)).asRFC1123(); + sd_headers[HTTP_IN_HEADER_RETRY_AFTER] = date_string; + policy.onFailure(503,sd_headers); + should_retry = policy.shouldRetry(seconds_to_wait); + ensure("header 2", should_retry); + ensure_approximately_equals_range("header 2", seconds_to_wait, 7.0F, 2.0F); + + LLCore::HttpResponse *response; + LLCore::HttpHeaders *headers; + + response = new LLCore::HttpResponse(); + headers = new LLCore::HttpHeaders(); + response->setStatus(503); + response->setHeaders(headers); + headers->append(HTTP_IN_HEADER_RETRY_AFTER, std::string("600")); + policy.onFailure(response); + should_retry = policy.shouldRetry(seconds_to_wait); + ensure("header 3",should_retry); + ensure_approximately_equals("header 3", seconds_to_wait, 600.0F, 6); + response->release(); + + response = new LLCore::HttpResponse(); + headers = new LLCore::HttpHeaders(); + response->setStatus(503); + response->setHeaders(headers); + time(&nowseconds); + date_string = LLDate((F64)(nowseconds+77)).asRFC1123(); + std::cerr << "date_string [" << date_string << "]" << std::endl; + headers->append(HTTP_IN_HEADER_RETRY_AFTER,date_string); + policy.onFailure(response); + should_retry = policy.shouldRetry(seconds_to_wait); + ensure("header 4",should_retry); + ensure_approximately_equals_range("header 4", seconds_to_wait, 77.0F, 2.0F); + response->release(); + + // Timeout should be clamped at max. + policy.onFailure(500,LLSD()); + should_retry = policy.shouldRetry(seconds_to_wait); + ensure("header 5", should_retry); + ensure_approximately_equals("header 5", seconds_to_wait, 644.0F, 6); + + // No more retries. + policy.onFailure(500,LLSD()); + should_retry = policy.shouldRetry(seconds_to_wait); + ensure("header 6", !should_retry); +} + +} + diff --git a/indra/newview/tests/llmediadataclient_test.cpp b/indra/newview/tests/llmediadataclient_test.cpp index 41cb344808..01195d1269 100644 --- a/indra/newview/tests/llmediadataclient_test.cpp +++ b/indra/newview/tests/llmediadataclient_test.cpp @@ -33,7 +33,7 @@ #include "llsdserialize.h" #include "llsdutil.h" #include "llerrorcontrol.h" -#include "llhttpstatuscodes.h" +#include "llhttpconstants.h" #include "../llmediadataclient.h" #include "../llvovolume.h" @@ -128,7 +128,7 @@ void LLHTTPClient::post( { LLSD content; content["reason"] = "fake reason"; - responder->errorWithContent(HTTP_SERVICE_UNAVAILABLE, "fake reason", content); + responder->failureResult(HTTP_SERVICE_UNAVAILABLE, "fake reason", content); return; } else if (url == FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR) @@ -136,8 +136,8 @@ void LLHTTPClient::post( LLSD error; error["code"] = LLObjectMediaNavigateClient::ERROR_PERMISSION_DENIED_CODE; result["error"] = error; - } - responder->result(result); + } + responder->successResult(result); } const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f; diff --git a/indra/newview/tests/llremoteparcelrequest_test.cpp b/indra/newview/tests/llremoteparcelrequest_test.cpp index ed66066b0a..c49b0350e9 100644 --- a/indra/newview/tests/llremoteparcelrequest_test.cpp +++ b/indra/newview/tests/llremoteparcelrequest_test.cpp @@ -40,12 +40,14 @@ namespace { LLCurl::Responder::Responder() { } LLCurl::Responder::~Responder() { } -void LLCurl::Responder::error(U32,std::string const &) { } -void LLCurl::Responder::result(LLSD const &) { } -void LLCurl::Responder::errorWithContent(U32 status,std::string const &,LLSD const &) { } -void LLCurl::Responder::completedRaw(U32 status, std::string const &, LLChannelDescriptors const &,boost::shared_ptr<LLBufferArray> const &) { } -void LLCurl::Responder::completed(U32 status, std::string const &, LLSD const &) { } -void LLCurl::Responder::completedHeader(U32 status, std::string const &, LLSD const &) { } +void LLCurl::Responder::httpFailure() { } +void LLCurl::Responder::httpSuccess() { } +void LLCurl::Responder::httpCompleted() { } +void LLCurl::Responder::failureResult(S32 status, const std::string& reason, const LLSD& content) { } +void LLCurl::Responder::successResult(const LLSD& content) { } +void LLCurl::Responder::completeResult(S32 status, const std::string& reason, const LLSD& content) { } +std::string LLCurl::Responder::dumpResponse() const { return "(failure)"; } +void LLCurl::Responder::completedRaw(LLChannelDescriptors const &,boost::shared_ptr<LLBufferArray> const &) { } void LLMessageSystem::getF32(char const *,char const *,F32 &,S32) { } void LLMessageSystem::getU8(char const *,char const *,U8 &,S32) { } void LLMessageSystem::getS32(char const *,char const *,S32 &,S32) { } @@ -85,7 +87,7 @@ namespace tut virtual void setParcelID(const LLUUID& parcel_id) { } - virtual void setErrorStatus(U32 status, const std::string& reason) { } + virtual void setErrorStatus(S32 status, const std::string& reason) { } bool mProcessed; }; diff --git a/indra/newview/tests/lltranslate_test.cpp b/indra/newview/tests/lltranslate_test.cpp index fd9527d631..b28eb5db43 100644 --- a/indra/newview/tests/lltranslate_test.cpp +++ b/indra/newview/tests/lltranslate_test.cpp @@ -34,6 +34,8 @@ #include "lltrans.h" #include "llui.h" +#include "../../llmessage/llhttpconstants.cpp" + static const std::string GOOGLE_VALID_RESPONSE1 = "{\ \"data\": {\ @@ -300,12 +302,10 @@ std::string LLControlGroup::getString(const std::string& name) { return "dummy"; LLControlGroup::~LLControlGroup() {} LLCurl::Responder::Responder() {} -void LLCurl::Responder::completedHeader(U32, std::string const&, LLSD const&) {} -void LLCurl::Responder::completedRaw(U32, const std::string&, const LLChannelDescriptors&, const LLIOPipe::buffer_ptr_t& buffer) {} -void LLCurl::Responder::completed(U32, std::string const&, LLSD const&) {} -void LLCurl::Responder::error(U32, std::string const&) {} -void LLCurl::Responder::errorWithContent(U32, std::string const&, LLSD const&) {} -void LLCurl::Responder::result(LLSD const&) {} +void LLCurl::Responder::httpFailure() { } +void LLCurl::Responder::httpSuccess() { } +void LLCurl::Responder::httpCompleted() { } +void LLCurl::Responder::completedRaw(LLChannelDescriptors const &,boost::shared_ptr<LLBufferArray> const &) { } LLCurl::Responder::~Responder() {} void LLHTTPClient::get(const std::string&, const LLSD&, ResponderPtr, const LLSD&, const F32) {} |