Files
SingularityViewer/indra/llmessage/aihttptimeout.h
Aleric Inglewood b20886a481 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).
2013-03-25 04:41:07 +01:00

154 lines
5.4 KiB
C++

/**
* @file aihttptimeout.h
* @brief HTTP timeout control class.
*
* Copyright (c) 2012, Aleric Inglewood.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution.
*
* CHANGELOG
* and additional copyright holders.
*
* 28/04/2012
* Initial version, written by Aleric Inglewood @ SL
*/
#ifndef AIHTTPTIMEOUT_H
#define AIHTTPTIMEOUT_H
#include <vector>
#ifndef HTTPTIMEOUT_TESTSUITE
#include "llrefcount.h"
#include "aithreadsafe.h" // AIAccess
#include <curl/curl.h> // Needed for files that include this header (also for aicurlprivate.h).
#ifdef DEBUG_CURLIO
#include "debug_libcurl.h"
#endif
#else
#include <sys/types.h>
class LLRefCount { };
template<typename T> struct AIAccess;
typedef int CURLcode;
#define ASSERT_ONLY_COMMA(...) , __VA_ARGS__
#endif
class AIHTTPTimeoutPolicy;
// Forward declaration (see aicurlprivate.h).
namespace AICurlPrivate {
class BufferedCurlEasyRequest;
} // namespace AICurlPrivate
typedef AIAccess<AICurlPrivate::BufferedCurlEasyRequest> AICurlEasyRequest_wat;
namespace AICurlPrivate {
class CurlEasyRequest;
class ThreadSafeBufferedCurlEasyRequest;
namespace curlthread {
// A class that keeps track of timeout administration per connection.
class HTTPTimeout : public LLRefCount {
private:
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 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.
U32 mTotalBytes; // The sum of all bytes in mBuckets.
U64 mLowSpeedClock; // Clock count at which low speed detection (re)started.
U64 mStalled; // The clock count at which this transaction is considered to be stalling if nothing is transfered anymore.
public:
static F64 const sClockWidth; // Time between two clock ticks in seconds.
static U64 sClockCount; // Clock count used as 'now' during one loop of the main loop.
#if defined(CWDEBUG) || defined(DEBUG_CURLIO)
ThreadSafeBufferedCurlEasyRequest* mLockObj;
#endif
public:
HTTPTimeout(AIHTTPTimeoutPolicy const* policy, ThreadSafeBufferedCurlEasyRequest* lock_obj) :
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);
// Called when data is sent. Returns true if transfer timed out.
bool data_sent(size_t n, bool finished);
// Called when data is received. Returns true if transfer timed out.
bool data_received(size_t n/*,*/ ASSERT_ONLY_COMMA(bool upload_error_status = false));
// Called immediately before done() after curl finished, with code.
void done(AICurlEasyRequest_wat const& curlEasyRequest_w, CURLcode code);
// Returns true when we REALLY timed out. Might call upload_finished heuristically.
bool has_stalled(void) { return mStalled < sClockCount && !maybe_upload_finished(); }
// Called from BufferedCurlEasyRequest::processOutput if a timeout occurred.
void print_diagnostics(CurlEasyRequest const* curl_easy_request, char const* eff_url);
#if defined(CWDEBUG) || defined(DEBUG_CURLIO)
void* get_lockobj(void) const { return mLockObj; }
#endif
private:
// (Re)start low speed transer rate detection.
void reset_lowspeed(void);
// Common low speed detection, Called from data_sent or data_received.
bool lowspeed(size_t bytes, bool finished = false);
// Return false when we timed out on reply delay, or didn't sent all bytes yet.
// Otherwise calls upload_finished() and return true;
bool maybe_upload_finished(void);
};
} // namespace curlthread
} // namespace AICurlPrivate
#if defined(CWDEBUG) || defined(DEBUG_CURLIO)
extern bool gCurlIo;
#endif
#endif