Allow TOS redirect. Fix upload finished detection when redirecting.

This fixes https://code.google.com/p/singularity-viewer/issues/detail?id=705

Adds 'bool redirect_status_ok(void) const { return true; }' to LLIamHere,
because it's ok to receive a 302 status there. Likewise added to LLIamHereVoice,
because that has the same comment in its error() method.

Also fixes the problem that if two redirects occur on a row, then the
upload_finished detection asserted because it would detect the third
time that libcurl turned off writing to the socket as a failure (the
second time wasn't a problem because mUploadFinished was reset upon
receiving the first 302 header, but not upon receiving the second
header).
This commit is contained in:
Aleric Inglewood
2013-03-25 04:41:07 +01:00
parent 2916d9353e
commit b20886a481
5 changed files with 41 additions and 8 deletions

View File

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

View File

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

View File

@@ -77,9 +77,10 @@ class HTTPTimeout : public LLRefCount {
AIHTTPTimeoutPolicy const* mPolicy; // A pointer to the used timeout policy.
std::vector<U32> 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);

View File

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

View File

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