diff --git a/indra/llmessage/aicurlthread.cpp b/indra/llmessage/aicurlthread.cpp index 6234e9425..64b35c683 100644 --- a/indra/llmessage/aicurlthread.cpp +++ b/indra/llmessage/aicurlthread.cpp @@ -806,7 +806,15 @@ void CurlSocketInfo::set_action(int action) if ((toggle_action & CURL_POLL_OUT)) { if ((action & CURL_POLL_OUT)) + { mMultiHandle.mWritePollSet->add(this); + if (mTimeout) + { + // Note that this detection normally doesn't work because mTimeout will be zero. + // However, it works in the case of a redirect - and then we need it. + mTimeout->upload_starting(); // Update timeout administration. + } + } else { mMultiHandle.mWritePollSet->remove(this); @@ -2140,6 +2148,11 @@ size_t BufferedCurlEasyRequest::curlHeaderCallback(char* data, size_t size, size self_w->received_HTTP_header(); self_w->setStatusAndReason(status, reason); done = true; + if (status >= 300 && status < 400) + { + // Timeout administration needs to know if we're being redirected. + self_w->httptimeout()->being_redirected(); + } } // Update timeout administration. This must be done after the status is already known. if (self_w->httptimeout()->data_received(header_len/*,*/ ASSERT_ONLY_COMMA(self_w->upload_error_status()))) diff --git a/indra/llmessage/aihttptimeout.cpp b/indra/llmessage/aihttptimeout.cpp index 352862ca1..0f99e23d2 100644 --- a/indra/llmessage/aihttptimeout.cpp +++ b/indra/llmessage/aihttptimeout.cpp @@ -133,6 +133,20 @@ void HTTPTimeout::reset_lowspeed(void) DoutCurl("reset_lowspeed: mLowSpeedClock = " << mLowSpeedClock << "; mStalled = -1"); } +void HTTPTimeout::being_redirected(void) +{ + mBeingRedirected = true; +} + +void HTTPTimeout::upload_starting(void) +{ + // We're not supposed start with an upload when it already finished, unless we're being redirected. + llassert(!mUploadFinished || mBeingRedirected); + mUploadFinished = false; + // Apparently there is something to upload. Start detecting low speed timeouts. + reset_lowspeed(); +} + // CURL-THREAD // This is called when everything we had to send to the server has been sent. // <-----mLowSpeedOn------> @@ -143,7 +157,9 @@ void HTTPTimeout::upload_finished(void) { llassert(!mUploadFinished); // If we get here twice, then the 'upload finished' detection failed. mUploadFinished = true; - // We finished uploading (if there was a body to upload at all), so not more transfer rate timeouts. + // Only accept a call to upload_starting() if being_redirected() is called after this point. + mBeingRedirected = false; + // We finished uploading (if there was a body to upload at all), so no more transfer rate timeouts. mLowSpeedOn = false; // Timeout if the server doesn't reply quick enough. mStalled = sClockCount + mPolicy->getReplyDelay() / sClockWidth; @@ -179,11 +195,6 @@ bool HTTPTimeout::data_received(size_t n/*,*/ // 'Upload finished' detection failed, generate it now. upload_finished(); } - // Turn this flag off again now that we received data, so that if 'upload_finished()' is called again - // for a future upload on the same descriptor, then that won't trigger an assert. - // Note that because we also set mNothingReceivedYet here, we won't enter this code block anymore, - // so it's safe to do this. - mUploadFinished = false; // Mark that something was received. mNothingReceivedYet = false; // We received something; switch to getLowSpeedLimit()/getLowSpeedTime(). diff --git a/indra/llmessage/aihttptimeout.h b/indra/llmessage/aihttptimeout.h index aa5e6feef..2c5442075 100644 --- a/indra/llmessage/aihttptimeout.h +++ b/indra/llmessage/aihttptimeout.h @@ -77,9 +77,10 @@ class HTTPTimeout : public LLRefCount { AIHTTPTimeoutPolicy const* mPolicy; // A pointer to the used timeout policy. std::vector mBuckets; // An array with the number of bytes transfered in each second. U16 mBucket; // The bucket corresponding to mLastSecond. - bool mNothingReceivedYet; // Set when created, reset when the HTML reply header from the server is received. + bool mNothingReceivedYet; // Set when created, reset when the first HTML reply header from the server is received. bool mLowSpeedOn; // Set while uploading or downloading data. bool mLastBytesSent; // Set when the last bytes were sent to libcurl to be uploaded. + bool mBeingRedirected; // Set when a 302 header is received, reset when upload finished is detected. bool mUploadFinished; // Used to keep track of whether upload_finished was called yet. S32 mLastSecond; // The time at which lowspeed() was last called, in seconds since mLowSpeedClock. S32 mOverwriteSecond; // The second at which the first bucket of this transfer will be overwritten. @@ -95,12 +96,18 @@ class HTTPTimeout : public LLRefCount { public: HTTPTimeout(AIHTTPTimeoutPolicy const* policy, ThreadSafeBufferedCurlEasyRequest* lock_obj) : - mPolicy(policy), mNothingReceivedYet(true), mLowSpeedOn(false), mLastBytesSent(false), mUploadFinished(false), mStalled((U64)-1) + mPolicy(policy), mNothingReceivedYet(true), mLowSpeedOn(false), mLastBytesSent(false), mBeingRedirected(false), mUploadFinished(false), mStalled((U64)-1) #if defined(CWDEBUG) || defined(DEBUG_CURLIO) , mLockObj(lock_obj) #endif { } + // Called when a redirect header is received. + void being_redirected(void); + + // Called when curl makes the socket writable (again). + void upload_starting(void); + // Called when everything we had to send to the server has been sent. void upload_finished(void); diff --git a/indra/newview/floatervoicelicense.cpp b/indra/newview/floatervoicelicense.cpp index 17dff4a5e..93d403744 100644 --- a/indra/newview/floatervoicelicense.cpp +++ b/indra/newview/floatervoicelicense.cpp @@ -104,6 +104,7 @@ class LLIamHereVoice : public LLHTTPClient::ResponderWithResult }; /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return iamHereVoice_timeout; } + /*virtual*/ bool redirect_status_ok(void) const { return true; } /*virtual*/ char const* getName(void) const { return "LLIamHereVoice"; } }; diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp index e58b1783e..700479406 100644 --- a/indra/newview/llfloatertos.cpp +++ b/indra/newview/llfloatertos.cpp @@ -132,6 +132,7 @@ class LLIamHere : public LLHTTPClient::ResponderWithResult }; /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return iamHere_timeout; } + /*virtual*/ bool redirect_status_ok(void) const { return true; } /*virtual*/ char const* getName(void) const { return "LLIamHere"; } };