Merge branch 'master' into sunshine
Conflicts: indra/llimage/llimage.cpp indra/llui/llui.cpp indra/newview/llvoavatar.cpp
This commit is contained in:
@@ -545,6 +545,9 @@ void CurlEasyHandle::handle_easy_error(CURLcode code)
|
||||
|
||||
// Throws AICurlNoEasyHandle.
|
||||
CurlEasyHandle::CurlEasyHandle(void) : mActiveMultiHandle(NULL), mErrorBuffer(NULL), mQueuedForRemoval(false)
|
||||
#ifdef DEBUG_CURLIO
|
||||
, mDebug(false)
|
||||
#endif
|
||||
#ifdef SHOW_ASSERT
|
||||
, mRemovedPerCommand(true)
|
||||
#endif
|
||||
@@ -588,6 +591,12 @@ CurlEasyHandle::~CurlEasyHandle()
|
||||
llassert(!mActiveMultiHandle);
|
||||
curl_easy_cleanup(mEasyHandle);
|
||||
Stats::easy_cleanup_calls++;
|
||||
#ifdef DEBUG_CURLIO
|
||||
if (mDebug)
|
||||
{
|
||||
debug_curl_remove_easy(mEasyHandle);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//static
|
||||
@@ -760,17 +769,17 @@ void CurlEasyRequest::setoptString(CURLoption option, std::string const& value)
|
||||
setopt(option, value.c_str());
|
||||
}
|
||||
|
||||
void CurlEasyRequest::setPost(AIPostFieldPtr const& postdata, U32 size)
|
||||
void CurlEasyRequest::setPost(AIPostFieldPtr const& postdata, U32 size, bool keepalive)
|
||||
{
|
||||
llassert_always(postdata->data());
|
||||
|
||||
DoutCurl("POST size is " << size << " bytes: \"" << libcwd::buf2str(postdata->data(), size) << "\".");
|
||||
setPostField(postdata); // Make sure the data stays around until we don't need it anymore.
|
||||
|
||||
setPost_raw(size, postdata->data());
|
||||
setPost_raw(size, postdata->data(), keepalive);
|
||||
}
|
||||
|
||||
void CurlEasyRequest::setPost_raw(U32 size, char const* data)
|
||||
void CurlEasyRequest::setPost_raw(U32 size, char const* data, bool keepalive)
|
||||
{
|
||||
if (!data)
|
||||
{
|
||||
@@ -780,7 +789,7 @@ void CurlEasyRequest::setPost_raw(U32 size, char const* data)
|
||||
|
||||
// The server never replies with 100-continue, so suppress the "Expect: 100-continue" header that libcurl adds by default.
|
||||
addHeader("Expect:");
|
||||
if (size > 0)
|
||||
if (size > 0 && keepalive)
|
||||
{
|
||||
addHeader("Connection: keep-alive");
|
||||
addHeader("Keep-alive: 300");
|
||||
@@ -1005,6 +1014,8 @@ CURLcode CurlEasyRequest::curlCtxCallback(CURL* curl, void* sslctx, void* parm)
|
||||
options |= SSL_OP_NO_TLSv1_1;
|
||||
}
|
||||
#else
|
||||
// This is expected when you compile against the headers of a version < 1.0.1 and then link at runtime with version >= 1.0.1.
|
||||
// Don't do that.
|
||||
llassert_always(!need_renegotiation_hack);
|
||||
#endif
|
||||
SSL_CTX_set_options(ctx, options);
|
||||
@@ -1225,6 +1236,20 @@ void CurlEasyRequest::removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy
|
||||
mHandleEventsTarget->removed_from_multi_handle(curl_easy_request_w);
|
||||
}
|
||||
|
||||
void CurlEasyRequest::bad_file_descriptor(AICurlEasyRequest_wat& curl_easy_request_w)
|
||||
{
|
||||
if (mHandleEventsTarget)
|
||||
mHandleEventsTarget->bad_file_descriptor(curl_easy_request_w);
|
||||
}
|
||||
|
||||
#ifdef SHOW_ASSERT
|
||||
void CurlEasyRequest::queued_for_removal(AICurlEasyRequest_wat& curl_easy_request_w)
|
||||
{
|
||||
if (mHandleEventsTarget)
|
||||
mHandleEventsTarget->queued_for_removal(curl_easy_request_w);
|
||||
}
|
||||
#endif
|
||||
|
||||
PerHostRequestQueuePtr CurlEasyRequest::getPerHostPtr(void)
|
||||
{
|
||||
if (!mPerHostPtr)
|
||||
@@ -1288,7 +1313,17 @@ void BufferedCurlEasyRequest::timed_out(void)
|
||||
mResponder->finished(CURLE_OK, HTTP_INTERNAL_ERROR, "Request timeout, aborted.", sChannels, mOutput);
|
||||
if (mResponder->needsHeaders())
|
||||
{
|
||||
send_buffer_events_to(NULL); // Revoke buffer events: we sent them to the responder.
|
||||
send_buffer_events_to(NULL); // Revoke buffer events: we send them to the responder.
|
||||
}
|
||||
mResponder = NULL;
|
||||
}
|
||||
|
||||
void BufferedCurlEasyRequest::bad_socket(void)
|
||||
{
|
||||
mResponder->finished(CURLE_OK, HTTP_INTERNAL_ERROR, "File descriptor went bad! Aborted.", sChannels, mOutput);
|
||||
if (mResponder->needsHeaders())
|
||||
{
|
||||
send_buffer_events_to(NULL); // Revoke buffer events: we send them to the responder.
|
||||
}
|
||||
mResponder = NULL;
|
||||
}
|
||||
@@ -1408,3 +1443,18 @@ CurlMultiHandle::~CurlMultiHandle()
|
||||
}
|
||||
|
||||
} // namespace AICurlPrivate
|
||||
|
||||
#if LL_LINUX
|
||||
extern "C" {
|
||||
|
||||
// Keep linker happy.
|
||||
const SSL_METHOD *SSLv2_client_method(void)
|
||||
{
|
||||
// Never used.
|
||||
llassert_always(false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -208,6 +208,10 @@ struct AICurlEasyHandleEvents {
|
||||
virtual void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
|
||||
virtual void finished(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
|
||||
virtual void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
|
||||
virtual void bad_file_descriptor(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
|
||||
#ifdef SHOW_ASSERT
|
||||
virtual void queued_for_removal(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
|
||||
#endif
|
||||
// Avoid compiler warning.
|
||||
virtual ~AICurlEasyHandleEvents() { }
|
||||
};
|
||||
@@ -271,6 +275,11 @@ class AICurlEasyRequest {
|
||||
// Queue a command to remove this request from the multi session (or cancel a queued command to add it).
|
||||
void removeRequest(void);
|
||||
|
||||
#ifdef DEBUG_CURLIO
|
||||
// Turn on/off debug output.
|
||||
void debug(bool debug) { AICurlEasyRequest_wat(*mBufferedCurlEasyRequest)->debug(debug); }
|
||||
#endif
|
||||
|
||||
private:
|
||||
// The actual pointer to the ThreadSafeBufferedCurlEasyRequest instance.
|
||||
AICurlPrivate::BufferedCurlEasyRequestPtr mBufferedCurlEasyRequest;
|
||||
|
||||
@@ -40,7 +40,8 @@ enum curleasyrequeststatemachine_state_type {
|
||||
AICurlEasyRequestStateMachine_timedOut, // This must be smaller than the rest, so they always overrule.
|
||||
AICurlEasyRequestStateMachine_finished,
|
||||
AICurlEasyRequestStateMachine_removed, // The removed states must be largest two, so they are never ignored.
|
||||
AICurlEasyRequestStateMachine_removed_after_finished
|
||||
AICurlEasyRequestStateMachine_removed_after_finished,
|
||||
AICurlEasyRequestStateMachine_bad_file_descriptor
|
||||
};
|
||||
|
||||
char const* AICurlEasyRequestStateMachine::state_str_impl(state_type run_state) const
|
||||
@@ -54,6 +55,7 @@ char const* AICurlEasyRequestStateMachine::state_str_impl(state_type run_state)
|
||||
AI_CASE_RETURN(AICurlEasyRequestStateMachine_finished);
|
||||
AI_CASE_RETURN(AICurlEasyRequestStateMachine_removed);
|
||||
AI_CASE_RETURN(AICurlEasyRequestStateMachine_removed_after_finished);
|
||||
AI_CASE_RETURN(AICurlEasyRequestStateMachine_bad_file_descriptor);
|
||||
}
|
||||
return "UNKNOWN STATE";
|
||||
}
|
||||
@@ -94,6 +96,24 @@ void AICurlEasyRequestStateMachine::removed_from_multi_handle(AICurlEasyRequest_
|
||||
set_state(mFinished ? AICurlEasyRequestStateMachine_removed_after_finished : AICurlEasyRequestStateMachine_removed);
|
||||
}
|
||||
|
||||
// CURL-THREAD
|
||||
void AICurlEasyRequestStateMachine::bad_file_descriptor(AICurlEasyRequest_wat&)
|
||||
{
|
||||
if (!mFinished)
|
||||
{
|
||||
mFinished = true;
|
||||
set_state(AICurlEasyRequestStateMachine_bad_file_descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SHOW_ASSERT
|
||||
// CURL-THREAD
|
||||
void AICurlEasyRequestStateMachine::queued_for_removal(AICurlEasyRequest_wat&)
|
||||
{
|
||||
llassert(mFinished || mTimedOut); // See AICurlEasyRequestStateMachine::removed_from_multi_handle
|
||||
}
|
||||
#endif
|
||||
|
||||
void AICurlEasyRequestStateMachine::multiplex_impl(void)
|
||||
{
|
||||
mSetStateLock.lock();
|
||||
@@ -207,6 +227,11 @@ void AICurlEasyRequestStateMachine::multiplex_impl(void)
|
||||
|
||||
break;
|
||||
}
|
||||
case AICurlEasyRequestStateMachine_bad_file_descriptor:
|
||||
{
|
||||
AICurlEasyRequest_wat(*mCurlEasyRequest)->bad_socket();
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -81,6 +81,14 @@ class AICurlEasyRequestStateMachine : public AIStateMachine, public AICurlEasyHa
|
||||
// Called after this curl easy handle was removed from a multi handle.
|
||||
/*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat&);
|
||||
|
||||
// Called when the curl thread detected that the socket of this handle has become unusable.
|
||||
/*virtual*/ void bad_file_descriptor(AICurlEasyRequest_wat&);
|
||||
|
||||
#ifdef SHOW_ASSERT
|
||||
// Called when a command was added to remove this easy handle.
|
||||
/*virtual*/ void queued_for_removal(AICurlEasyRequest_wat&);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// AIStateMachine implementations.
|
||||
|
||||
|
||||
@@ -201,12 +201,19 @@ class CurlEasyHandle : public boost::noncopyable, protected AICurlEasyHandleEven
|
||||
// In case it's added after being removed.
|
||||
void add_queued(void) { mQueuedForRemoval = false; }
|
||||
|
||||
#ifdef DEBUG_CURLIO
|
||||
void debug(bool debug) { if (mDebug) debug_curl_remove_easy(mEasyHandle); if (debug) debug_curl_add_easy(mEasyHandle); mDebug = debug; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
CURL* mEasyHandle;
|
||||
CURLM* mActiveMultiHandle;
|
||||
mutable char* mErrorBuffer;
|
||||
AIPostFieldPtr mPostField; // This keeps the POSTFIELD data alive for as long as the easy handle exists.
|
||||
bool mQueuedForRemoval; // Set if the easy handle is (probably) added to the multi handle, but is queued for removal.
|
||||
#ifdef DEBUG_CURLIO
|
||||
bool mDebug;
|
||||
#endif
|
||||
#ifdef SHOW_ASSERT
|
||||
public:
|
||||
bool mRemovedPerCommand; // Set if mActiveMultiHandle was reset as per command from the main thread.
|
||||
@@ -270,11 +277,11 @@ class CurlEasyHandle : public boost::noncopyable, protected AICurlEasyHandleEven
|
||||
// and the CurlEasyRequest destructed.
|
||||
class CurlEasyRequest : public CurlEasyHandle {
|
||||
private:
|
||||
void setPost_raw(U32 size, char const* data);
|
||||
void setPost_raw(U32 size, char const* data, bool keepalive);
|
||||
public:
|
||||
void setPost(U32 size) { setPost_raw(size, NULL); }
|
||||
void setPost(AIPostFieldPtr const& postdata, U32 size);
|
||||
void setPost(char const* data, U32 size) { setPost(new AIPostField(data), size); }
|
||||
void setPost(U32 size, bool keepalive = true) { setPost_raw(size, NULL, keepalive); }
|
||||
void setPost(AIPostFieldPtr const& postdata, U32 size, bool keepalive = true);
|
||||
void setPost(char const* data, U32 size, bool keepalive = true) { setPost(new AIPostField(data), size, keepalive); }
|
||||
void setoptString(CURLoption option, std::string const& value);
|
||||
void addHeader(char const* str);
|
||||
void addHeaders(AIHTTPHeaders const& headers);
|
||||
@@ -413,6 +420,11 @@ class CurlEasyRequest : public CurlEasyHandle {
|
||||
/*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w);
|
||||
/*virtual*/ void finished(AICurlEasyRequest_wat& curl_easy_request_w);
|
||||
/*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w);
|
||||
public:
|
||||
/*virtual*/ void bad_file_descriptor(AICurlEasyRequest_wat& curl_easy_request_w);
|
||||
#ifdef SHOW_ASSERT
|
||||
/*virtual*/ void queued_for_removal(AICurlEasyRequest_wat& curl_easy_request_w);
|
||||
#endif
|
||||
};
|
||||
|
||||
// This class adds input/output buffers to the request and hooks up the libcurl callbacks to use those buffers.
|
||||
@@ -431,6 +443,9 @@ class BufferedCurlEasyRequest : public CurlEasyRequest {
|
||||
// Called if libcurl doesn't deliver within AIHTTPTimeoutPolicy::mMaximumTotalDelay seconds.
|
||||
void timed_out(void);
|
||||
|
||||
// Called if the underlaying socket went bad (ie, when accidently closed by a buggy library).
|
||||
void bad_socket(void);
|
||||
|
||||
// Called after removed_from_multi_handle was called.
|
||||
void processOutput(void);
|
||||
|
||||
|
||||
@@ -286,14 +286,36 @@ enum refresh_t {
|
||||
empty_and_complete = complete|empty
|
||||
};
|
||||
|
||||
// A class with info for each socket that is in use by curl.
|
||||
class CurlSocketInfo
|
||||
{
|
||||
public:
|
||||
CurlSocketInfo(MultiHandle& multi_handle, CURL* easy, curl_socket_t s, int action, ThreadSafeBufferedCurlEasyRequest* lockobj);
|
||||
~CurlSocketInfo();
|
||||
|
||||
void set_action(int action);
|
||||
void mark_dead(void) { set_action(CURL_POLL_NONE); mDead = true; }
|
||||
curl_socket_t getSocketFd(void) const { return mSocketFd; }
|
||||
AICurlEasyRequest& getEasyRequest(void) { return mEasyRequest; }
|
||||
|
||||
private:
|
||||
MultiHandle& mMultiHandle;
|
||||
CURL const* mEasy;
|
||||
curl_socket_t mSocketFd;
|
||||
int mAction;
|
||||
bool mDead;
|
||||
AICurlEasyRequest mEasyRequest;
|
||||
LLPointer<HTTPTimeout> mTimeout;
|
||||
};
|
||||
|
||||
class PollSet
|
||||
{
|
||||
public:
|
||||
PollSet(void);
|
||||
|
||||
// Add/remove a filedescriptor to/from mFileDescriptors.
|
||||
void add(curl_socket_t s);
|
||||
void remove(curl_socket_t s);
|
||||
void add(CurlSocketInfo* sp);
|
||||
void remove(CurlSocketInfo* sp);
|
||||
|
||||
// Copy mFileDescriptors to an internal fd_set that is returned by access().
|
||||
// Returns if all fds could be copied (complete) and/or if the resulting fd_set is empty.
|
||||
@@ -307,8 +329,8 @@ class PollSet
|
||||
curl_socket_t get_max_fd(void) const { return mMaxFdSet; }
|
||||
#endif
|
||||
|
||||
// Return true if a filedescriptor is set in mFileDescriptors (used for debugging).
|
||||
bool contains(curl_socket_t s) const;
|
||||
// Return a pointer to the corresponding CurlSocketInfo if a filedescriptor is set in mFileDescriptors, or NULL if s is not set.
|
||||
CurlSocketInfo* contains(curl_socket_t s) const;
|
||||
|
||||
// Return true if a filedescriptor is set in mFdSet.
|
||||
bool is_set(curl_socket_t s) const;
|
||||
@@ -323,7 +345,7 @@ class PollSet
|
||||
void next(void); // Advance to next filedescriptor.
|
||||
|
||||
private:
|
||||
curl_socket_t* mFileDescriptors;
|
||||
CurlSocketInfo** mFileDescriptors;
|
||||
int mNrFds; // The number of filedescriptors in the array.
|
||||
int mNext; // The index of the first file descriptor to start copying, the next call to refresh().
|
||||
|
||||
@@ -332,8 +354,8 @@ class PollSet
|
||||
#if !WINDOWS_CODE
|
||||
curl_socket_t mMaxFd; // The largest filedescriptor in the array, or CURL_SOCKET_BAD when it is empty.
|
||||
curl_socket_t mMaxFdSet; // The largest filedescriptor set in mFdSet by refresh(), or CURL_SOCKET_BAD when it was empty.
|
||||
std::vector<curl_socket_t> mCopiedFileDescriptors; // Filedescriptors copied by refresh to mFdSet.
|
||||
std::vector<curl_socket_t>::iterator mIter; // Index into mCopiedFileDescriptors for next(); loop variable.
|
||||
std::vector<CurlSocketInfo*> mCopiedFileDescriptors; // Filedescriptors copied by refresh to mFdSet.
|
||||
std::vector<CurlSocketInfo*>::iterator mIter; // Index into mCopiedFileDescriptors for next(); loop variable.
|
||||
#else
|
||||
unsigned int mIter; // Index into fd_set::fd_array.
|
||||
#endif
|
||||
@@ -359,7 +381,7 @@ class PollSet
|
||||
static size_t const MAXSIZE = llmax(1024, FD_SETSIZE);
|
||||
|
||||
// Create an empty PollSet.
|
||||
PollSet::PollSet(void) : mFileDescriptors(new curl_socket_t [MAXSIZE]),
|
||||
PollSet::PollSet(void) : mFileDescriptors(new CurlSocketInfo* [MAXSIZE]),
|
||||
mNrFds(0), mNext(0)
|
||||
#if !WINDOWS_CODE
|
||||
, mMaxFd(-1), mMaxFdSet(-1)
|
||||
@@ -369,17 +391,17 @@ PollSet::PollSet(void) : mFileDescriptors(new curl_socket_t [MAXSIZE]),
|
||||
}
|
||||
|
||||
// Add filedescriptor s to the PollSet.
|
||||
void PollSet::add(curl_socket_t s)
|
||||
void PollSet::add(CurlSocketInfo* sp)
|
||||
{
|
||||
llassert_always(mNrFds < (int)MAXSIZE);
|
||||
mFileDescriptors[mNrFds++] = s;
|
||||
mFileDescriptors[mNrFds++] = sp;
|
||||
#if !WINDOWS_CODE
|
||||
mMaxFd = llmax(mMaxFd, s);
|
||||
mMaxFd = llmax(mMaxFd, sp->getSocketFd());
|
||||
#endif
|
||||
}
|
||||
|
||||
// Remove filedescriptor s from the PollSet.
|
||||
void PollSet::remove(curl_socket_t s)
|
||||
void PollSet::remove(CurlSocketInfo* sp)
|
||||
{
|
||||
// The number of open filedescriptors is relatively small,
|
||||
// and on top of that we rather do something CPU intensive
|
||||
@@ -391,15 +413,15 @@ void PollSet::remove(curl_socket_t s)
|
||||
// back, keeping it compact and keeping the filedescriptors
|
||||
// in the same order (which is supposedly their priority).
|
||||
//
|
||||
// The general case is where mFileDescriptors contains s at an index
|
||||
// The general case is where mFileDescriptors contains sp at an index
|
||||
// between 0 and mNrFds:
|
||||
// mNrFds = 6
|
||||
// v
|
||||
// index: 0 1 2 3 4 5
|
||||
// a b c s d e
|
||||
|
||||
// This function should never be called unless s is actually in mFileDescriptors,
|
||||
// as a result of a previous call to PollSet::add().
|
||||
// This function should never be called unless sp is actually in mFileDescriptors,
|
||||
// as a result of a previous call to PollSet::add(sp).
|
||||
llassert(mNrFds > 0);
|
||||
|
||||
// Correct mNrFds for when the descriptor is removed.
|
||||
@@ -409,17 +431,18 @@ void PollSet::remove(curl_socket_t s)
|
||||
// v
|
||||
// index: 0 1 2 3 4 5
|
||||
// a b c s d e
|
||||
curl_socket_t cur = mFileDescriptors[i]; // cur = 'e'
|
||||
curl_socket_t const s = sp->getSocketFd();
|
||||
CurlSocketInfo* cur = mFileDescriptors[i]; // cur = 'e'
|
||||
#if !WINDOWS_CODE
|
||||
curl_socket_t max = -1;
|
||||
#endif
|
||||
while (cur != s)
|
||||
while (cur != sp)
|
||||
{
|
||||
llassert(i > 0);
|
||||
curl_socket_t next = mFileDescriptors[--i]; // next = 'd'
|
||||
CurlSocketInfo* next = mFileDescriptors[--i]; // next = 'd'
|
||||
mFileDescriptors[i] = cur; // Overwrite 'd' with 'e'.
|
||||
#if !WINDOWS_CODE
|
||||
max = llmax(max, cur); // max is the maximum value in 'i' or higher.
|
||||
max = llmax(max, cur->getSocketFd()); // max is the maximum value in 'i' or higher.
|
||||
#endif
|
||||
cur = next; // cur = 'd'
|
||||
// i NrFds = 5
|
||||
@@ -427,21 +450,21 @@ void PollSet::remove(curl_socket_t s)
|
||||
// index: 0 1 2 3 4
|
||||
// a b c s e // cur = 'd'
|
||||
//
|
||||
// Next loop iteration: next = 's', overwrite 's' with 'd', cur = 's'; loop terminates.
|
||||
// Next loop iteration: next = 'sp', overwrite 'sp' with 'd', cur = 'sp'; loop terminates.
|
||||
// i NrFds = 5
|
||||
// v v
|
||||
// index: 0 1 2 3 4
|
||||
// a b c d e // cur = 's'
|
||||
// a b c d e // cur = 'sp'
|
||||
}
|
||||
llassert(cur == s);
|
||||
llassert(cur == sp);
|
||||
// At this point i was decremented once more and points to the element before the old s.
|
||||
// i NrFds = 5
|
||||
// v v
|
||||
// index: 0 1 2 3 4
|
||||
// a b c d e // max = llmax('d', 'e')
|
||||
|
||||
// If mNext pointed to an element before s, it should be left alone. Otherwise, if mNext pointed
|
||||
// to s it must now point to 'd', or if it pointed beyond 's' it must be decremented by 1.
|
||||
// If mNext pointed to an element before sp, it should be left alone. Otherwise, if mNext pointed
|
||||
// to sp it must now point to 'd', or if it pointed beyond 'sp' it must be decremented by 1.
|
||||
if (mNext > i) // i is where s was.
|
||||
--mNext;
|
||||
|
||||
@@ -451,8 +474,8 @@ void PollSet::remove(curl_socket_t s)
|
||||
{
|
||||
while (i > 0)
|
||||
{
|
||||
curl_socket_t next = mFileDescriptors[--i];
|
||||
max = llmax(max, next);
|
||||
CurlSocketInfo* next = mFileDescriptors[--i];
|
||||
max = llmax(max, next->getSocketFd());
|
||||
}
|
||||
mMaxFd = max;
|
||||
llassert(mMaxFd < s);
|
||||
@@ -487,12 +510,12 @@ void PollSet::remove(curl_socket_t s)
|
||||
#endif
|
||||
}
|
||||
|
||||
bool PollSet::contains(curl_socket_t fd) const
|
||||
CurlSocketInfo* PollSet::contains(curl_socket_t fd) const
|
||||
{
|
||||
for (int i = 0; i < mNrFds; ++i)
|
||||
if (mFileDescriptors[i] == fd)
|
||||
return true;
|
||||
return false;
|
||||
if (mFileDescriptors[i]->getSocketFd() == fd)
|
||||
return mFileDescriptors[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline bool PollSet::is_set(curl_socket_t fd) const
|
||||
@@ -536,7 +559,7 @@ refresh_t PollSet::refresh(void)
|
||||
// Calculate mMaxFdSet.
|
||||
// Run over FD_SETSIZE - 1 elements, starting at mNext, wrapping to 0 when we reach the end.
|
||||
int max = -1, i = mNext, count = 0;
|
||||
while (++count < FD_SETSIZE) { max = llmax(max, mFileDescriptors[i]); if (++i == mNrFds) i = 0; }
|
||||
while (++count < FD_SETSIZE) { max = llmax(max, mFileDescriptors[i]->getSocketFd()); if (++i == mNrFds) i = 0; }
|
||||
mMaxFdSet = max;
|
||||
#endif
|
||||
}
|
||||
@@ -556,7 +579,7 @@ refresh_t PollSet::refresh(void)
|
||||
mNext = i;
|
||||
return not_complete_not_empty;
|
||||
}
|
||||
FD_SET(mFileDescriptors[i], &mFdSet);
|
||||
FD_SET(mFileDescriptors[i]->getSocketFd(), &mFdSet);
|
||||
#if !WINDOWS_CODE
|
||||
mCopiedFileDescriptors.push_back(mFileDescriptors[i]);
|
||||
#endif
|
||||
@@ -603,7 +626,7 @@ void PollSet::reset(void)
|
||||
else
|
||||
{
|
||||
mIter = mCopiedFileDescriptors.begin();
|
||||
if (!FD_ISSET(*mIter, &mFdSet))
|
||||
if (!FD_ISSET((*mIter)->getSocketFd(), &mFdSet))
|
||||
next();
|
||||
}
|
||||
#endif
|
||||
@@ -614,7 +637,7 @@ inline curl_socket_t PollSet::get(void) const
|
||||
#if WINDOWS_CODE
|
||||
return (mIter >= mFdSet.fd_count) ? CURL_SOCKET_BAD : mFdSet.fd_array[mIter];
|
||||
#else
|
||||
return (mIter == mCopiedFileDescriptors.end()) ? CURL_SOCKET_BAD : *mIter;
|
||||
return (mIter == mCopiedFileDescriptors.end()) ? CURL_SOCKET_BAD : (*mIter)->getSocketFd();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -625,7 +648,7 @@ void PollSet::next(void)
|
||||
++mIter;
|
||||
#else
|
||||
llassert(mIter != mCopiedFileDescriptors.end()); // Only call next() if the last call to get() didn't return -1.
|
||||
while (++mIter != mCopiedFileDescriptors.end() && !FD_ISSET(*mIter, &mFdSet));
|
||||
while (++mIter != mCopiedFileDescriptors.end() && !FD_ISSET((*mIter)->getSocketFd(), &mFdSet));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -743,26 +766,8 @@ std::ostream& operator<<(std::ostream& os, DebugFdSet const& s)
|
||||
}
|
||||
#endif
|
||||
|
||||
// A class with info for each socket that is in use by curl.
|
||||
class CurlSocketInfo
|
||||
{
|
||||
public:
|
||||
CurlSocketInfo(MultiHandle& multi_handle, CURL* easy, curl_socket_t s, int action, ThreadSafeBufferedCurlEasyRequest* lockobj);
|
||||
~CurlSocketInfo();
|
||||
|
||||
void set_action(int action);
|
||||
|
||||
private:
|
||||
MultiHandle& mMultiHandle;
|
||||
CURL const* mEasy;
|
||||
curl_socket_t mSocketFd;
|
||||
int mAction;
|
||||
AICurlEasyRequest mEasyRequest;
|
||||
LLPointer<HTTPTimeout> mTimeout;
|
||||
};
|
||||
|
||||
CurlSocketInfo::CurlSocketInfo(MultiHandle& multi_handle, CURL* easy, curl_socket_t s, int action, ThreadSafeBufferedCurlEasyRequest* lockobj) :
|
||||
mMultiHandle(multi_handle), mEasy(easy), mSocketFd(s), mAction(CURL_POLL_NONE), mEasyRequest(lockobj)
|
||||
mMultiHandle(multi_handle), mEasy(easy), mSocketFd(s), mAction(CURL_POLL_NONE), mDead(false), mEasyRequest(lockobj)
|
||||
{
|
||||
llassert(*AICurlEasyRequest_wat(*mEasyRequest) == easy);
|
||||
mMultiHandle.assign(s, this);
|
||||
@@ -785,23 +790,28 @@ CurlSocketInfo::~CurlSocketInfo()
|
||||
|
||||
void CurlSocketInfo::set_action(int action)
|
||||
{
|
||||
if (mDead)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Dout(dc::curl, "CurlSocketInfo::set_action(" << action_str(mAction) << " --> " << action_str(action) << ") [" << (void*)mEasyRequest.get_ptr().get() << "]");
|
||||
int toggle_action = mAction ^ action;
|
||||
mAction = action;
|
||||
if ((toggle_action & CURL_POLL_IN))
|
||||
{
|
||||
if ((action & CURL_POLL_IN))
|
||||
mMultiHandle.mReadPollSet->add(mSocketFd);
|
||||
mMultiHandle.mReadPollSet->add(this);
|
||||
else
|
||||
mMultiHandle.mReadPollSet->remove(mSocketFd);
|
||||
mMultiHandle.mReadPollSet->remove(this);
|
||||
}
|
||||
if ((toggle_action & CURL_POLL_OUT))
|
||||
{
|
||||
if ((action & CURL_POLL_OUT))
|
||||
mMultiHandle.mWritePollSet->add(mSocketFd);
|
||||
mMultiHandle.mWritePollSet->add(this);
|
||||
else
|
||||
{
|
||||
mMultiHandle.mWritePollSet->remove(mSocketFd);
|
||||
mMultiHandle.mWritePollSet->remove(this);
|
||||
|
||||
// The following is a bit of a hack, needed because of the lack of proper timeout callbacks in libcurl.
|
||||
// The removal of CURL_POLL_OUT could be part of the SSL handshake, therefore check if we're already connected:
|
||||
@@ -838,6 +848,9 @@ class AICurlThread : public LLThread
|
||||
// MAIN-THREAD
|
||||
void stop_thread(void) { mRunning = false; wakeup_thread(); }
|
||||
|
||||
// MAIN-THREAD
|
||||
apr_status_t join_thread(void);
|
||||
|
||||
protected:
|
||||
virtual void run(void);
|
||||
void wakeup(AICurlMultiHandle_wat const& multi_handle_w);
|
||||
@@ -1110,6 +1123,17 @@ void AICurlThread::wakeup_thread(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
apr_status_t AICurlThread::join_thread(void)
|
||||
{
|
||||
apr_status_t retval = APR_SUCCESS;
|
||||
if (sInstance)
|
||||
{
|
||||
apr_thread_join(&retval, sInstance->mAPRThreadp);
|
||||
delete sInstance;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void AICurlThread::wakeup(AICurlMultiHandle_wat const& multi_handle_w)
|
||||
{
|
||||
DoutEntering(dc::curl, "AICurlThread::wakeup");
|
||||
@@ -1255,6 +1279,26 @@ void AICurlThread::process_commands(AICurlMultiHandle_wat const& multi_handle_w)
|
||||
}
|
||||
}
|
||||
|
||||
// Return true if fd is a 'bad' socket.
|
||||
static bool is_bad(curl_socket_t fd, bool for_writing)
|
||||
{
|
||||
fd_set tmp;
|
||||
FD_ZERO(&tmp);
|
||||
FD_SET(fd, &tmp);
|
||||
fd_set* readfds = for_writing ? NULL : &tmp;
|
||||
fd_set* writefds = for_writing ? &tmp : NULL;
|
||||
#if !WINDOWS_CODE
|
||||
int nfds = fd + 1;
|
||||
#else
|
||||
int nfds = 64;
|
||||
#endif
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 10;
|
||||
int ret = select(nfds, readfds, writefds, NULL, &timeout);
|
||||
return ret == -1;
|
||||
}
|
||||
|
||||
// The main loop of the curl thread.
|
||||
void AICurlThread::run(void)
|
||||
{
|
||||
@@ -1266,7 +1310,7 @@ void AICurlThread::run(void)
|
||||
{
|
||||
// If mRunning is true then we can only get here if mWakeUpFd != CURL_SOCKET_BAD.
|
||||
llassert(mWakeUpFd != CURL_SOCKET_BAD);
|
||||
// Copy the next batch of file descriptors from the PollSets mFiledescriptors into their mFdSet.
|
||||
// Copy the next batch of file descriptors from the PollSets mFileDescriptors into their mFdSet.
|
||||
multi_handle_w->mReadPollSet->refresh();
|
||||
refresh_t wres = multi_handle_w->mWritePollSet->refresh();
|
||||
// Add wake up fd if any, and pass NULL to select() if a set is empty.
|
||||
@@ -1383,6 +1427,51 @@ void AICurlThread::run(void)
|
||||
if (ready == -1)
|
||||
{
|
||||
llwarns << "select() failed: " << errno << ", " << strerror(errno) << llendl;
|
||||
if (errno == EBADF)
|
||||
{
|
||||
// Somewhere (fmodex?) one of our file descriptors was closed. Try to recover by finding out which.
|
||||
llassert_always(!is_bad(mWakeUpFd, false)); // We can't recover from this.
|
||||
PollSet* found = NULL;
|
||||
// Run over all read file descriptors.
|
||||
multi_handle_w->mReadPollSet->refresh();
|
||||
multi_handle_w->mReadPollSet->reset();
|
||||
curl_socket_t fd;
|
||||
while ((fd = multi_handle_w->mReadPollSet->get()) != CURL_SOCKET_BAD)
|
||||
{
|
||||
if (is_bad(fd, false))
|
||||
{
|
||||
found = multi_handle_w->mReadPollSet;
|
||||
break;
|
||||
}
|
||||
multi_handle_w->mReadPollSet->next();
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
// Try all write file descriptors.
|
||||
refresh_t wres = multi_handle_w->mWritePollSet->refresh();
|
||||
if (!(wres & empty))
|
||||
{
|
||||
multi_handle_w->mWritePollSet->reset();
|
||||
while ((fd = multi_handle_w->mWritePollSet->get()) != CURL_SOCKET_BAD)
|
||||
{
|
||||
if (is_bad(fd, true))
|
||||
{
|
||||
found = multi_handle_w->mWritePollSet;
|
||||
break;
|
||||
}
|
||||
multi_handle_w->mWritePollSet->next();
|
||||
}
|
||||
}
|
||||
}
|
||||
llassert_always(found); // It makes no sense to continue if we can't recover.
|
||||
// Find the corresponding CurlSocketInfo
|
||||
CurlSocketInfo* sp = found->contains(fd);
|
||||
llassert_always(sp); // fd was just *read* from this sp.
|
||||
sp->mark_dead(); // Make sure it's never used again.
|
||||
AICurlEasyRequest_wat curl_easy_request_w(*sp->getEasyRequest());
|
||||
curl_easy_request_w->pause(CURLPAUSE_ALL); // Keep libcurl at bay.
|
||||
curl_easy_request_w->bad_file_descriptor(curl_easy_request_w); // Make the main thread cleanly terminate this transaction.
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// Clock count used for timeouts.
|
||||
@@ -1822,7 +1911,7 @@ bool HTTPTimeout::data_received(size_t n)
|
||||
// | | | | | | | | | | | | | |
|
||||
bool HTTPTimeout::lowspeed(size_t bytes)
|
||||
{
|
||||
DoutCurlEntering("HTTPTimeout::lowspeed(" << bytes << ")");
|
||||
//DoutCurlEntering("HTTPTimeout::lowspeed(" << bytes << ")"); commented out... too spammy for normal use.
|
||||
|
||||
// The algorithm to determine if we timed out if different from how libcurls CURLOPT_LOW_SPEED_TIME works.
|
||||
//
|
||||
@@ -2000,12 +2089,11 @@ void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, ch
|
||||
#if LOWRESTIMER
|
||||
llinfos << "Hostname seems to have been still in the DNS cache." << llendl;
|
||||
#else
|
||||
llwarns << "Huh? Curl returned CURLE_OPERATION_TIMEDOUT, but DNS lookup did not occur according to timings. Expected CURLE_COULDNT_RESOLVE_PROXY or CURLE_COULDNT_RESOLVE_HOST!" << llendl;
|
||||
llwarns << "Curl returned CURLE_OPERATION_TIMEDOUT and DNS lookup did not occur according to timings. Apparently the resolve attempt timed out (bad network?)" << llendl;
|
||||
llassert(connect_time == 0);
|
||||
llassert(appconnect_time == 0);
|
||||
llassert(pretransfer_time == 0);
|
||||
llassert(starttransfer_time == 0);
|
||||
// Fatal error for diagnostics.
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
@@ -2028,11 +2116,10 @@ void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, ch
|
||||
#endif
|
||||
)
|
||||
{
|
||||
llwarns << "Huh? Curl returned CURLE_OPERATION_TIMEDOUT, but connection did not occur according to timings. Expected CURLE_COULDNT_CONNECT!" << llendl;
|
||||
llwarns << "Curl returned CURLE_OPERATION_TIMEDOUT and connection did not occur according to timings: apparently the connect attempt timed out (bad network?)" << llendl;
|
||||
llassert(appconnect_time == 0);
|
||||
llassert(pretransfer_time == 0);
|
||||
llassert(starttransfer_time == 0);
|
||||
// Fatal error for diagnostics.
|
||||
return;
|
||||
}
|
||||
// If connect_time is almost equal to namelookup_time, then it was just set because it was already connected.
|
||||
@@ -2148,12 +2235,22 @@ void stopCurlThread(void)
|
||||
if (AICurlThread::sInstance)
|
||||
{
|
||||
AICurlThread::sInstance->stop_thread();
|
||||
int count = 101;
|
||||
int count = 401;
|
||||
while(--count && !AICurlThread::sInstance->isStopped())
|
||||
{
|
||||
ms_sleep(10);
|
||||
}
|
||||
Dout(dc::curl, "Curl thread" << (curlThreadIsRunning() ? " not" : "") << " stopped after " << ((100 - count) * 10) << "ms.");
|
||||
if (AICurlThread::sInstance->isStopped())
|
||||
{
|
||||
// isStopped() returns true somewhere at the end of run(),
|
||||
// but that doesn't mean the thread really stopped: it still
|
||||
// needs to destroy it's static variables.
|
||||
// If we don't join here, then there is a chance that the
|
||||
// curl thread will crash when using globals that we (the
|
||||
// main thread) will have destroyed before it REALLY finished.
|
||||
AICurlThread::sInstance->join_thread(); // Wait till it is REALLY done.
|
||||
}
|
||||
llinfos << "Curl thread" << (curlThreadIsRunning() ? " not" : "") << " stopped after " << ((400 - count) * 10) << "ms." << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2174,7 +2271,7 @@ void BufferedCurlEasyRequest::setStatusAndReason(U32 status, std::string const&
|
||||
AICurlInterface::Stats::status_count[AICurlInterface::Stats::status2index(mStatus)]++;
|
||||
|
||||
// Sanity check. If the server replies with a redirect status then we better have that option turned on!
|
||||
if ((status >= 300 && status < 400) && mResponder && !mResponder->followRedir())
|
||||
if ((status >= 300 && status < 400) && mResponder && !mResponder->redirect_status_ok())
|
||||
{
|
||||
llerrs << "Received " << status << " (" << reason << ") for responder \"" << mTimeoutPolicy->name() << "\" which has no followRedir()!" << llendl;
|
||||
}
|
||||
@@ -2188,7 +2285,7 @@ void BufferedCurlEasyRequest::processOutput(void)
|
||||
CURLcode code;
|
||||
AITransferInfo info;
|
||||
getResult(&code, &info);
|
||||
if (code == CURLE_OK)
|
||||
if (code == CURLE_OK && mStatus != HTTP_INTERNAL_ERROR)
|
||||
{
|
||||
getinfo(CURLINFO_RESPONSE_CODE, &responseCode);
|
||||
// If getResult code is CURLE_OK then we should have decoded the first header line ourselves.
|
||||
@@ -2201,7 +2298,7 @@ void BufferedCurlEasyRequest::processOutput(void)
|
||||
else
|
||||
{
|
||||
responseCode = HTTP_INTERNAL_ERROR;
|
||||
responseReason = curl_easy_strerror(code);
|
||||
responseReason = (code == CURLE_OK) ? mReason : std::string(curl_easy_strerror(code));
|
||||
setopt(CURLOPT_FRESH_CONNECT, TRUE);
|
||||
}
|
||||
|
||||
@@ -2367,14 +2464,25 @@ size_t BufferedCurlEasyRequest::curlHeaderCallback(char* data, size_t size, size
|
||||
}
|
||||
|
||||
#if defined(CWDEBUG) || defined(DEBUG_CURLIO)
|
||||
int debug_callback(CURL*, curl_infotype infotype, char* buf, size_t size, void* user_ptr)
|
||||
int debug_callback(CURL* handle, curl_infotype infotype, char* buf, size_t size, void* user_ptr)
|
||||
{
|
||||
BufferedCurlEasyRequest* request = (BufferedCurlEasyRequest*)user_ptr;
|
||||
if (infotype == CURLINFO_HEADER_OUT && size >= 5 && (strncmp(buf, "GET ", 4) == 0 || strncmp(buf, "HEAD ", 5) == 0))
|
||||
{
|
||||
request->mDebugIsHeadOrGetMethod = true;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CURLIO
|
||||
if (!debug_curl_print_debug(handle))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CWDEBUG
|
||||
using namespace ::libcwd;
|
||||
std::ostringstream marker;
|
||||
marker << (void*)request->get_lockobj();
|
||||
marker << (void*)request->get_lockobj() << ' ';
|
||||
libcw_do.push_marker();
|
||||
libcw_do.marker().assign(marker.str().data(), marker.str().size());
|
||||
if (!debug::channels::dc::curlio.is_on())
|
||||
@@ -2398,8 +2506,6 @@ int debug_callback(CURL*, curl_infotype infotype, char* buf, size_t size, void*
|
||||
break;
|
||||
case CURLINFO_HEADER_OUT:
|
||||
LibcwDoutStream << "H< ";
|
||||
if (size >= 5 && (strncmp(buf, "GET ", 4) == 0 || strncmp(buf, "HEAD ", 5) == 0))
|
||||
request->mDebugIsHeadOrGetMethod = true;
|
||||
break;
|
||||
case CURLINFO_DATA_IN:
|
||||
LibcwDoutStream << "D> ";
|
||||
@@ -2573,6 +2679,14 @@ void AICurlEasyRequest::removeRequest(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
AICurlEasyRequest_wat curl_easy_request_w(*get());
|
||||
// As soon as the lock on the command queue is released, it could be picked up by
|
||||
// the curl thread and executed. At that point it (already) demands that the easy
|
||||
// request either timed out or is finished. So, to avoid race conditions that already
|
||||
// has to be true right now. The call to queued_for_removal() checks this.
|
||||
curl_easy_request_w->queued_for_removal(curl_easy_request_w);
|
||||
}
|
||||
#endif
|
||||
// Add a command to remove this request from the multi session to the command queue.
|
||||
command_queue_w->push_back(Command(*this, cmd_remove));
|
||||
|
||||
@@ -107,6 +107,20 @@ void AIHTTPReceivedHeaders::addHeader(std::string const& key, std::string const&
|
||||
{
|
||||
mContainer = new Container;
|
||||
}
|
||||
else if (equal(key, "set-cookie"))
|
||||
{
|
||||
// If a cookie with this name already exists, replace it.
|
||||
std::string const name = value.substr(0, value.find('='));
|
||||
container_t::iterator const end = mContainer->mKeyValuePairs.end();
|
||||
for (container_t::iterator header = mContainer->mKeyValuePairs.begin(); header != end; ++header)
|
||||
{
|
||||
if (equal(header->first, "set-cookie") && header->second.substr(0, header->second.find('=')) == name)
|
||||
{
|
||||
header->second = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
mContainer->mKeyValuePairs.insert(container_t::value_type(key, value));
|
||||
}
|
||||
|
||||
@@ -151,3 +165,20 @@ std::ostream& operator<<(std::ostream& os, AIHTTPReceivedHeaders const& headers)
|
||||
return os;
|
||||
}
|
||||
|
||||
//static
|
||||
bool AIHTTPReceivedHeaders::equal(std::string const& key1, std::string const& key2)
|
||||
{
|
||||
if (key1.length() != key2.length())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (std::string::const_iterator i1 = key1.begin(), i2 = key2.begin(); i1 != key1.end(); ++i1, ++i2)
|
||||
{
|
||||
if ((*i1 ^ *i2) & 0xdf != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -132,6 +132,9 @@ class AIHTTPReceivedHeaders {
|
||||
// Add a header.
|
||||
void addHeader(std::string const& key, std::string const& value);
|
||||
|
||||
// Swap headers with another container.
|
||||
void swap(AIHTTPReceivedHeaders& headers) { LLPointer<Container>::swap(mContainer, headers.mContainer); }
|
||||
|
||||
// Return true if there are no headers associated with this object.
|
||||
bool empty(void) const { return !mContainer || mContainer->mKeyValuePairs.empty(); }
|
||||
|
||||
@@ -147,6 +150,9 @@ class AIHTTPReceivedHeaders {
|
||||
// For debug purposes.
|
||||
friend std::ostream& operator<<(std::ostream& os, AIHTTPReceivedHeaders const& headers);
|
||||
|
||||
// Returns true if the two keys compare equal (ie, "Set-Cookie" == "set-cookie").
|
||||
static bool equal(std::string const& key1, std::string const& key2);
|
||||
|
||||
private:
|
||||
struct Container : public LLThreadSafeRefCount {
|
||||
container_t mKeyValuePairs;
|
||||
|
||||
@@ -646,6 +646,12 @@ AIHTTPTimeoutPolicyBase transfer_18s(AIHTTPTimeoutPolicyBase::getDebugSettingsCu
|
||||
transactionOp18s
|
||||
);
|
||||
|
||||
// This used to be '30 seconds'.
|
||||
Transaction transactionOp30s(30);
|
||||
AIHTTPTimeoutPolicyBase transfer_30s(AIHTTPTimeoutPolicyBase::getDebugSettingsCurlTimeout(),
|
||||
transactionOp30s
|
||||
);
|
||||
|
||||
// This used to be '300 seconds'. We derive this from the hardcoded result so users can't mess with it.
|
||||
Transaction transactionOp300s(300);
|
||||
AIHTTPTimeoutPolicyBase transfer_300s(HTTPTimeoutPolicy_default,
|
||||
@@ -852,6 +858,7 @@ P(lcl_responder);
|
||||
P(MPImportGetResponder);
|
||||
P(MPImportPostResponder);
|
||||
P(mapLayerResponder);
|
||||
P2(maturityPreferences, transfer_30s);
|
||||
P(mediaTypeResponder);
|
||||
P(meshDecompositionResponder);
|
||||
P(meshHeaderResponder);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <cstdlib>
|
||||
#include <stdarg.h>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include "llpreprocessor.h"
|
||||
#include <curl/curl.h>
|
||||
#define COMPILING_DEBUG_LIBCURL_CC
|
||||
@@ -528,19 +529,66 @@ std::ostream& operator<<(std::ostream& os, EvBitmask const& bitmask)
|
||||
return os;
|
||||
}
|
||||
|
||||
// Set this to limit the curl debug output to specific easy handles.
|
||||
bool gDebugCurlTerse = false;
|
||||
|
||||
namespace {
|
||||
|
||||
std::vector<CURL*> handles;
|
||||
|
||||
inline bool print_debug(CURL* handle)
|
||||
{
|
||||
if (!gDebugCurlTerse)
|
||||
return true;
|
||||
return std::find(handles.begin(), handles.end(), handle) != handles.end();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void debug_curl_add_easy(CURL* handle)
|
||||
{
|
||||
std::vector<CURL*>::iterator iter = std::find(handles.begin(), handles.end(), handle);
|
||||
if (iter == handles.end())
|
||||
{
|
||||
handles.push_back(handle);
|
||||
Dout(dc::warning, "debug_curl_add_easy(" << (void*)handle << "): added");
|
||||
}
|
||||
llassert(print_debug(handle));
|
||||
}
|
||||
|
||||
void debug_curl_remove_easy(CURL* handle)
|
||||
{
|
||||
std::vector<CURL*>::iterator iter = std::find(handles.begin(), handles.end(), handle);
|
||||
if (iter != handles.end())
|
||||
{
|
||||
handles.erase(iter);
|
||||
Dout(dc::warning, "debug_curl_remove_easy(" << (void*)handle << "): removed");
|
||||
}
|
||||
llassert(!print_debug(handle));
|
||||
}
|
||||
|
||||
bool debug_curl_print_debug(CURL* handle)
|
||||
{
|
||||
return print_debug(handle);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
void debug_curl_easy_cleanup(CURL* handle)
|
||||
{
|
||||
curl_easy_cleanup(handle);
|
||||
Dout(dc::curl, "curl_easy_cleanup(" << (AICURL*)handle << ")");
|
||||
if (print_debug(handle))
|
||||
{
|
||||
Dout(dc::curltr, "curl_easy_cleanup(" << (AICURL*)handle << ")");
|
||||
}
|
||||
}
|
||||
|
||||
CURL* debug_curl_easy_duphandle(CURL* handle)
|
||||
{
|
||||
CURL* ret;
|
||||
ret = curl_easy_duphandle(handle);
|
||||
Dout(dc::curl, "curl_easy_duphandle(" << (AICURL*)handle << ") = " << (AICURL*)ret);
|
||||
if (!print_debug(handle)) return ret;
|
||||
Dout(dc::curltr, "curl_easy_duphandle(" << (AICURL*)handle << ") = " << (AICURL*)ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -548,11 +596,12 @@ char* debug_curl_easy_escape(CURL* curl, char* url, int length)
|
||||
{
|
||||
char* ret;
|
||||
ret = curl_easy_escape(curl, url, length);
|
||||
Dout(dc::curl, "curl_easy_escape(" << (AICURL*)curl << ", \"" << url << "\", " << length << ") = \"" << ret << '"');
|
||||
if (!print_debug(curl)) return ret;
|
||||
Dout(dc::curltr, "curl_easy_escape(" << (AICURL*)curl << ", \"" << url << "\", " << length << ") = \"" << ret << '"');
|
||||
return ret;
|
||||
}
|
||||
|
||||
CURLcode debug_curl_easy_getinfo(CURL* curl, CURLINFO info, ...)
|
||||
CURLcode debug_curl_easy_getinfo(CURL* handle, CURLINFO info, ...)
|
||||
{
|
||||
CURLcode ret;
|
||||
va_list ap;
|
||||
@@ -566,26 +615,27 @@ CURLcode debug_curl_easy_getinfo(CURL* curl, CURLINFO info, ...)
|
||||
va_start(ap, info);
|
||||
param.some_ptr = va_arg(ap, void*);
|
||||
va_end(ap);
|
||||
ret = curl_easy_getinfo(curl, info, param.some_ptr);
|
||||
ret = curl_easy_getinfo(handle, info, param.some_ptr);
|
||||
if (!print_debug(handle)) return ret;
|
||||
if (info == CURLINFO_PRIVATE)
|
||||
{
|
||||
Dout(dc::curl, "curl_easy_getinfo(" << (AICURL*)curl << ", " << info << ", 0x" << std::hex << (size_t)param.some_ptr << std::dec << ") = " << ret);
|
||||
Dout(dc::curltr, "curl_easy_getinfo(" << (AICURL*)handle << ", " << info << ", 0x" << std::hex << (size_t)param.some_ptr << std::dec << ") = " << ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch((info & CURLINFO_TYPEMASK))
|
||||
{
|
||||
case CURLINFO_STRING:
|
||||
Dout(dc::curl, "curl_easy_getinfo(" << (AICURL*)curl << ", " << info << ", (char**){ \"" << (ret == CURLE_OK ? *param.char_ptr : " <unchanged> ") << "\" }) = " << ret);
|
||||
Dout(dc::curltr, "curl_easy_getinfo(" << (AICURL*)handle << ", " << info << ", (char**){ \"" << (ret == CURLE_OK ? *param.char_ptr : " <unchanged> ") << "\" }) = " << ret);
|
||||
break;
|
||||
case CURLINFO_LONG:
|
||||
Dout(dc::curl, "curl_easy_getinfo(" << (AICURL*)curl << ", " << info << ", (long*){ " << (ret == CURLE_OK ? *param.long_ptr : 0L) << "L }) = " << ret);
|
||||
Dout(dc::curltr, "curl_easy_getinfo(" << (AICURL*)handle << ", " << info << ", (long*){ " << (ret == CURLE_OK ? *param.long_ptr : 0L) << "L }) = " << ret);
|
||||
break;
|
||||
case CURLINFO_DOUBLE:
|
||||
Dout(dc::curl, "curl_easy_getinfo(" << (AICURL*)curl << ", " << info << ", (double*){" << (ret == CURLE_OK ? *param.double_ptr : 0.) << "}) = " << ret);
|
||||
Dout(dc::curltr, "curl_easy_getinfo(" << (AICURL*)handle << ", " << info << ", (double*){" << (ret == CURLE_OK ? *param.double_ptr : 0.) << "}) = " << ret);
|
||||
break;
|
||||
case CURLINFO_SLIST:
|
||||
Dout(dc::curl, "curl_easy_getinfo(" << (AICURL*)curl << ", " << info << ", (curl_slist**){ " << (ret == CURLE_OK ? **param.curl_slist_ptr : unchanged_slist) << " }) = " << ret);
|
||||
Dout(dc::curltr, "curl_easy_getinfo(" << (AICURL*)handle << ", " << info << ", (curl_slist**){ " << (ret == CURLE_OK ? **param.curl_slist_ptr : unchanged_slist) << " }) = " << ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -596,7 +646,8 @@ CURL* debug_curl_easy_init(void)
|
||||
{
|
||||
CURL* ret;
|
||||
ret = curl_easy_init();
|
||||
Dout(dc::curl, "curl_easy_init() = " << (AICURL*)ret);
|
||||
if (gDebugCurlTerse) return ret;
|
||||
Dout(dc::curltr, "curl_easy_init() = " << (AICURL*)ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -604,7 +655,8 @@ CURLcode debug_curl_easy_pause(CURL* handle, int bitmask)
|
||||
{
|
||||
CURLcode ret;
|
||||
ret = curl_easy_pause(handle, bitmask);
|
||||
Dout(dc::curl, "curl_easy_pause(" << (AICURL*)handle << ", 0x" << std::hex << bitmask << std::dec << ") = " << ret);
|
||||
if (!print_debug(handle)) return ret;
|
||||
Dout(dc::curltr, "curl_easy_pause(" << (AICURL*)handle << ", 0x" << std::hex << bitmask << std::dec << ") = " << ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -612,19 +664,21 @@ CURLcode debug_curl_easy_perform(CURL* handle)
|
||||
{
|
||||
CURLcode ret;
|
||||
ret = curl_easy_perform(handle);
|
||||
Dout(dc::curl, "curl_easy_perform(" << (AICURL*)handle << ") = " << ret);
|
||||
if (!print_debug(handle)) return ret;
|
||||
Dout(dc::curltr, "curl_easy_perform(" << (AICURL*)handle << ") = " << ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void debug_curl_easy_reset(CURL* handle)
|
||||
{
|
||||
curl_easy_reset(handle);
|
||||
Dout(dc::curl, "curl_easy_reset(" << (AICURL*)handle << ")");
|
||||
if (!print_debug(handle)) return;
|
||||
Dout(dc::curltr, "curl_easy_reset(" << (AICURL*)handle << ")");
|
||||
}
|
||||
|
||||
CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...)
|
||||
{
|
||||
CURLcode ret = CURLE_UNKNOWN_OPTION; // Suppress compiler warning.
|
||||
CURLcode ret = CURLE_OBSOLETE50; // Suppress compiler warning.
|
||||
va_list ap;
|
||||
union param_type {
|
||||
long along;
|
||||
@@ -656,7 +710,10 @@ CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...)
|
||||
case CURLOPTTYPE_LONG:
|
||||
{
|
||||
ret = curl_easy_setopt(handle, option, param.along);
|
||||
Dout(dc::curl, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", " << param.along << "L) = " << ret);
|
||||
if (print_debug(handle))
|
||||
{
|
||||
Dout(dc::curltr, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", " << param.along << "L) = " << ret);
|
||||
}
|
||||
if (option == CURLOPT_POSTFIELDSIZE)
|
||||
{
|
||||
postfieldsize = param.along;
|
||||
@@ -666,7 +723,8 @@ CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...)
|
||||
case CURLOPTTYPE_OBJECTPOINT:
|
||||
{
|
||||
ret = curl_easy_setopt(handle, option, param.ptr);
|
||||
LibcwDoutScopeBegin(LIBCWD_DEBUGCHANNELS, libcwd::libcw_do, dc::curl)
|
||||
if (!print_debug(handle)) break;
|
||||
LibcwDoutScopeBegin(LIBCWD_DEBUGCHANNELS, libcwd::libcw_do, dc::curltr)
|
||||
LibcwDoutStream << "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", ";
|
||||
// For a subset of all options that take a char*, print the string passed.
|
||||
if (option == CURLOPT_PROXY || // Set HTTP proxy to use. The parameter should be a char* to a zero terminated string holding the host name or dotted IP address.
|
||||
@@ -717,11 +775,11 @@ CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...)
|
||||
if (option == CURLOPT_HTTPHEADER && param.ptr)
|
||||
{
|
||||
debug::Indent indent(2);
|
||||
Dout(dc::curl, "HTTP Headers:");
|
||||
Dout(dc::curltr, "HTTP Headers:");
|
||||
struct curl_slist* list = (struct curl_slist*)param.ptr;
|
||||
while (list)
|
||||
{
|
||||
Dout(dc::curl, '"' << list->data << '"');
|
||||
Dout(dc::curltr, '"' << list->data << '"');
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
@@ -729,12 +787,18 @@ CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...)
|
||||
}
|
||||
case CURLOPTTYPE_FUNCTIONPOINT:
|
||||
ret = curl_easy_setopt(handle, option, param.ptr);
|
||||
Dout(dc::curl, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", (function*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = " << ret);
|
||||
if (print_debug(handle))
|
||||
{
|
||||
Dout(dc::curltr, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", (function*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = " << ret);
|
||||
}
|
||||
break;
|
||||
case CURLOPTTYPE_OFF_T:
|
||||
{
|
||||
ret = curl_easy_setopt(handle, option, param.offset);
|
||||
Dout(dc::curl, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", (curl_off_t)" << param.offset << ") = " << ret);
|
||||
if (print_debug(handle))
|
||||
{
|
||||
Dout(dc::curltr, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", (curl_off_t)" << param.offset << ") = " << ret);
|
||||
}
|
||||
if (option == CURLOPT_POSTFIELDSIZE_LARGE)
|
||||
{
|
||||
postfieldsize = (long)param.offset;
|
||||
@@ -751,7 +815,8 @@ char const* debug_curl_easy_strerror(CURLcode errornum)
|
||||
{
|
||||
char const* ret;
|
||||
ret = curl_easy_strerror(errornum);
|
||||
Dout(dc::curl, "curl_easy_strerror(" << errornum << ") = \"" << ret << '"');
|
||||
if (gDebugCurlTerse) return ret;
|
||||
Dout(dc::curltr, "curl_easy_strerror(" << errornum << ") = \"" << ret << '"');
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -759,35 +824,38 @@ char* debug_curl_easy_unescape(CURL* curl, char* url, int inlength, int* outleng
|
||||
{
|
||||
char* ret;
|
||||
ret = curl_easy_unescape(curl, url, inlength, outlength);
|
||||
Dout(dc::curl, "curl_easy_unescape(" << (AICURL*)curl << ", \"" << url << "\", " << inlength << ", " << ((ret && outlength) ? *outlength : 1) << ") = \"" << ret << '"');
|
||||
if (!print_debug(curl)) return ret;
|
||||
Dout(dc::curltr, "curl_easy_unescape(" << (AICURL*)curl << ", \"" << url << "\", " << inlength << ", " << ((ret && outlength) ? *outlength : 1) << ") = \"" << ret << '"');
|
||||
return ret;
|
||||
}
|
||||
|
||||
void debug_curl_free(char* ptr)
|
||||
{
|
||||
curl_free(ptr);
|
||||
Dout(dc::curl, "curl_free(0x" << std::hex << (size_t)ptr << std::dec << ")");
|
||||
if (gDebugCurlTerse) return;
|
||||
Dout(dc::curltr, "curl_free(0x" << std::hex << (size_t)ptr << std::dec << ")");
|
||||
}
|
||||
|
||||
time_t debug_curl_getdate(char const* datestring, time_t* now)
|
||||
{
|
||||
time_t ret;
|
||||
ret = curl_getdate(datestring, now);
|
||||
Dout(dc::curl, "curl_getdate(\"" << datestring << "\", " << (now == NULL ? "NULL" : "<erroneous non-NULL value for 'now'>") << ") = " << ret);
|
||||
if (gDebugCurlTerse) return ret;
|
||||
Dout(dc::curltr, "curl_getdate(\"" << datestring << "\", " << (now == NULL ? "NULL" : "<erroneous non-NULL value for 'now'>") << ") = " << ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void debug_curl_global_cleanup(void)
|
||||
{
|
||||
curl_global_cleanup();
|
||||
Dout(dc::curl, "curl_global_cleanup()");
|
||||
Dout(dc::curltr, "curl_global_cleanup()");
|
||||
}
|
||||
|
||||
CURLcode debug_curl_global_init(long flags)
|
||||
{
|
||||
CURLcode ret;
|
||||
ret = curl_global_init(flags);
|
||||
Dout(dc::curl, "curl_global_init(0x" << std::hex << flags << std::dec << ") = " << ret);
|
||||
Dout(dc::curltr, "curl_global_init(0x" << std::hex << flags << std::dec << ") = " << ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -795,7 +863,8 @@ CURLMcode debug_curl_multi_add_handle(CURLM* multi_handle, CURL* easy_handle)
|
||||
{
|
||||
CURLMcode ret;
|
||||
ret = curl_multi_add_handle(multi_handle, easy_handle);
|
||||
Dout(dc::curl, "curl_multi_add_handle(" << (AICURLM*)multi_handle << ", " << (AICURL*)easy_handle << ") = " << ret);
|
||||
if (gDebugCurlTerse) return ret;
|
||||
Dout(dc::curltr, "curl_multi_add_handle(" << (AICURLM*)multi_handle << ", " << (AICURL*)easy_handle << ") = " << ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -803,7 +872,8 @@ CURLMcode debug_curl_multi_assign(CURLM* multi_handle, curl_socket_t sockfd, voi
|
||||
{
|
||||
CURLMcode ret;
|
||||
ret = curl_multi_assign(multi_handle, sockfd, sockptr);
|
||||
Dout(dc::curl, "curl_multi_assign(" << (AICURLM*)multi_handle << ", " << Socket(sockfd) << ", " << sockptr << ") = " << ret);
|
||||
if (gDebugCurlTerse) return ret;
|
||||
Dout(dc::curltr, "curl_multi_assign(" << (AICURLM*)multi_handle << ", " << Socket(sockfd) << ", " << sockptr << ") = " << ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -811,7 +881,8 @@ CURLMcode debug_curl_multi_cleanup(CURLM* multi_handle)
|
||||
{
|
||||
CURLMcode ret;
|
||||
ret = curl_multi_cleanup(multi_handle);
|
||||
Dout(dc::curl, "curl_multi_cleanup(" << (AICURLM*)multi_handle << ") = " << ret);
|
||||
if (gDebugCurlTerse) return ret;
|
||||
Dout(dc::curltr, "curl_multi_cleanup(" << (AICURLM*)multi_handle << ") = " << ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -819,7 +890,8 @@ CURLMsg* debug_curl_multi_info_read(CURLM* multi_handle, int* msgs_in_queue)
|
||||
{
|
||||
CURLMsg* ret;
|
||||
ret = curl_multi_info_read(multi_handle, msgs_in_queue);
|
||||
Dout(dc::curl, "curl_multi_info_read(" << (AICURLM*)multi_handle << ", {" << *msgs_in_queue << "}) = " << ret);
|
||||
if (gDebugCurlTerse) return ret;
|
||||
Dout(dc::curltr, "curl_multi_info_read(" << (AICURLM*)multi_handle << ", {" << *msgs_in_queue << "}) = " << ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -827,7 +899,8 @@ CURLM* debug_curl_multi_init(void)
|
||||
{
|
||||
CURLM* ret;
|
||||
ret = curl_multi_init();
|
||||
Dout(dc::curl, "curl_multi_init() = " << (AICURLM*)ret);
|
||||
if (gDebugCurlTerse) return ret;
|
||||
Dout(dc::curltr, "curl_multi_init() = " << (AICURLM*)ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -835,7 +908,8 @@ CURLMcode debug_curl_multi_remove_handle(CURLM* multi_handle, CURL* easy_handle)
|
||||
{
|
||||
CURLMcode ret;
|
||||
ret = curl_multi_remove_handle(multi_handle, easy_handle);
|
||||
Dout(dc::curl, "curl_multi_remove_handle(" << (AICURLM*)multi_handle << ", " << (AICURL*)easy_handle << ") = " << ret);
|
||||
if (!print_debug(easy_handle)) return ret;
|
||||
Dout(dc::curltr, "curl_multi_remove_handle(" << (AICURLM*)multi_handle << ", " << (AICURL*)easy_handle << ") = " << ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -871,19 +945,23 @@ CURLMcode debug_curl_multi_setopt(CURLM* multi_handle, CURLMoption option, ...)
|
||||
{
|
||||
case CURLOPTTYPE_LONG:
|
||||
ret = curl_multi_setopt(multi_handle, option, param.along);
|
||||
Dout(dc::curl, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", " << param.along << "L) = " << ret);
|
||||
if (gDebugCurlTerse) break;
|
||||
Dout(dc::curltr, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", " << param.along << "L) = " << ret);
|
||||
break;
|
||||
case CURLOPTTYPE_OBJECTPOINT:
|
||||
ret = curl_multi_setopt(multi_handle, option, param.ptr);
|
||||
Dout(dc::curl, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (object*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = " << ret);
|
||||
if (gDebugCurlTerse) break;
|
||||
Dout(dc::curltr, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (object*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = " << ret);
|
||||
break;
|
||||
case CURLOPTTYPE_FUNCTIONPOINT:
|
||||
ret = curl_multi_setopt(multi_handle, option, param.ptr);
|
||||
Dout(dc::curl, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (function*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = " << ret);
|
||||
if (gDebugCurlTerse) break;
|
||||
Dout(dc::curltr, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (function*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = " << ret);
|
||||
break;
|
||||
case CURLOPTTYPE_OFF_T:
|
||||
ret = curl_multi_setopt(multi_handle, option, param.offset);
|
||||
Dout(dc::curl, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (curl_off_t)" << param.offset << ") = " << ret);
|
||||
if (gDebugCurlTerse) break;
|
||||
Dout(dc::curltr, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (curl_off_t)" << param.offset << ") = " << ret);
|
||||
break;
|
||||
default: // Stop compiler complaining about no default.
|
||||
break;
|
||||
@@ -895,7 +973,8 @@ CURLMcode debug_curl_multi_socket_action(CURLM* multi_handle, curl_socket_t sock
|
||||
{
|
||||
CURLMcode ret;
|
||||
ret = curl_multi_socket_action(multi_handle, sockfd, ev_bitmask, running_handles);
|
||||
Dout(dc::curl, "curl_multi_socket_action(" << (AICURLM*)multi_handle << ", " << Socket(sockfd) <<
|
||||
if (gDebugCurlTerse) return ret;
|
||||
Dout(dc::curltr, "curl_multi_socket_action(" << (AICURLM*)multi_handle << ", " << Socket(sockfd) <<
|
||||
", " << EvBitmask(ev_bitmask) << ", {" << (ret == CURLM_OK ? *running_handles : 0) << "}) = " << ret);
|
||||
return ret;
|
||||
}
|
||||
@@ -904,7 +983,8 @@ char const* debug_curl_multi_strerror(CURLMcode errornum)
|
||||
{
|
||||
char const* ret;
|
||||
ret = curl_multi_strerror(errornum);
|
||||
Dout(dc::curl, "curl_multi_strerror(" << errornum << ") = \"" << ret << '"');
|
||||
if (gDebugCurlTerse) return ret;
|
||||
Dout(dc::curltr, "curl_multi_strerror(" << errornum << ") = \"" << ret << '"');
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -912,21 +992,24 @@ struct curl_slist* debug_curl_slist_append(struct curl_slist* list, char const*
|
||||
{
|
||||
struct curl_slist* ret;
|
||||
ret = curl_slist_append(list, string);
|
||||
Dout(dc::curl, "curl_slist_append((curl_slist)@0x" << std::hex << (size_t)list << std::dec << ", \"" << string << "\") = " << *ret);
|
||||
if (gDebugCurlTerse) return ret;
|
||||
Dout(dc::curltr, "curl_slist_append((curl_slist)@0x" << std::hex << (size_t)list << std::dec << ", \"" << string << "\") = " << *ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void debug_curl_slist_free_all(struct curl_slist* list)
|
||||
{
|
||||
curl_slist_free_all(list);
|
||||
Dout(dc::curl, "curl_slist_free_all((curl_slist)@0x" << std::hex << (size_t)list << std::dec << ")");
|
||||
if (gDebugCurlTerse) return;
|
||||
Dout(dc::curltr, "curl_slist_free_all((curl_slist)@0x" << std::hex << (size_t)list << std::dec << ")");
|
||||
}
|
||||
|
||||
char* debug_curl_unescape(char const* url, int length)
|
||||
{
|
||||
char* ret;
|
||||
ret = curl_unescape(url, length);
|
||||
Dout(dc::curl, "curl_unescape(\"" << url << "\", " << length << ") = \"" << ret << '"');
|
||||
if (gDebugCurlTerse) return ret;
|
||||
Dout(dc::curltr, "curl_unescape(\"" << url << "\", " << length << ") = \"" << ret << '"');
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -934,7 +1017,8 @@ char* debug_curl_version(void)
|
||||
{
|
||||
char* ret;
|
||||
ret = curl_version();
|
||||
Dout(dc::curl, "curl_version() = \"" << ret << '"');
|
||||
if (gDebugCurlTerse) return ret;
|
||||
Dout(dc::curltr, "curl_version() = \"" << ret << '"');
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -86,4 +86,9 @@ extern char* debug_curl_version(void);
|
||||
|
||||
#endif // !COMPILING_DEBUG_LIBCURL_CC
|
||||
|
||||
extern bool gDebugCurlTerse; // With this set,
|
||||
void debug_curl_add_easy(CURL* handle); // only output debug output for easy handles added with this function.
|
||||
void debug_curl_remove_easy(CURL* handle);
|
||||
bool debug_curl_print_debug(CURL* handle);
|
||||
|
||||
#endif // DEBUG_LIBCURL
|
||||
|
||||
@@ -200,7 +200,9 @@ static void request(
|
||||
LLURLRequest::ERequestAction method,
|
||||
Injector* body_injector,
|
||||
LLHTTPClient::ResponderPtr responder,
|
||||
AIHTTPHeaders& headers,
|
||||
AIHTTPHeaders& headers/*,*/
|
||||
DEBUG_CURLIO_PARAM(EDebugCurl debug),
|
||||
EKeepAlive keepalive = keep_alive,
|
||||
bool is_auth = false,
|
||||
bool no_compression = false)
|
||||
{
|
||||
@@ -213,7 +215,10 @@ static void request(
|
||||
LLURLRequest* req;
|
||||
try
|
||||
{
|
||||
req = new LLURLRequest(method, url, body_injector, responder, headers, is_auth, no_compression);
|
||||
req = new LLURLRequest(method, url, body_injector, responder, headers, keepalive, is_auth, no_compression);
|
||||
#ifdef DEBUG_CURLIO
|
||||
req->mCurlEasyRequest.debug(debug);
|
||||
#endif
|
||||
}
|
||||
catch(AICurlNoEasyHandle& error)
|
||||
{
|
||||
@@ -225,36 +230,36 @@ static void request(
|
||||
req->run();
|
||||
}
|
||||
|
||||
void LLHTTPClient::getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers)
|
||||
void LLHTTPClient::getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
|
||||
{
|
||||
if(offset > 0 || bytes > 0)
|
||||
{
|
||||
headers.addHeader("Range", llformat("bytes=%d-%d", offset, offset + bytes - 1));
|
||||
}
|
||||
request(url, LLURLRequest::HTTP_GET, NULL, responder, headers);
|
||||
request(url, LLURLRequest::HTTP_GET, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
|
||||
}
|
||||
|
||||
void LLHTTPClient::head(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers)
|
||||
void LLHTTPClient::head(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
|
||||
{
|
||||
request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers);
|
||||
request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
|
||||
}
|
||||
|
||||
void LLHTTPClient::get(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers)
|
||||
void LLHTTPClient::get(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
|
||||
{
|
||||
request(url, LLURLRequest::HTTP_GET, NULL, responder, headers);
|
||||
request(url, LLURLRequest::HTTP_GET, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
|
||||
}
|
||||
|
||||
void LLHTTPClient::getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers)
|
||||
void LLHTTPClient::getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
|
||||
{
|
||||
request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers);
|
||||
request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
|
||||
}
|
||||
|
||||
void LLHTTPClient::get(std::string const& url, LLSD const& query, ResponderPtr responder, AIHTTPHeaders& headers)
|
||||
void LLHTTPClient::get(std::string const& url, LLSD const& query, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
|
||||
{
|
||||
LLURI uri;
|
||||
|
||||
uri = LLURI::buildHTTP(url, LLSD::emptyArray(), query);
|
||||
get(uri.asString(), responder, headers);
|
||||
get(uri.asString(), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
@@ -362,6 +367,22 @@ void LLHTTPClient::ResponderBase::decode_raw_body(U32 status, std::string const&
|
||||
}
|
||||
}
|
||||
|
||||
std::string const& LLHTTPClient::ResponderBase::get_cookie(std::string const& key)
|
||||
{
|
||||
AIHTTPReceivedHeaders::range_type cookies;
|
||||
mReceivedHeaders.getValues("set-cookie", cookies);
|
||||
for (AIHTTPReceivedHeaders::iterator_type cookie = cookies.first; cookie != cookies.second; ++cookie)
|
||||
{
|
||||
if (key == cookie->second.substr(0, cookie->second.find('=')))
|
||||
{
|
||||
return cookie->second;
|
||||
}
|
||||
}
|
||||
// Not found.
|
||||
static std::string empty_dummy;
|
||||
return empty_dummy;
|
||||
}
|
||||
|
||||
// Called with HTML body.
|
||||
// virtual
|
||||
void LLHTTPClient::ResponderWithCompleted::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer)
|
||||
@@ -554,7 +575,8 @@ enum EBlockingRequestAction {
|
||||
static LLSD blocking_request(
|
||||
std::string const& url,
|
||||
EBlockingRequestAction method,
|
||||
LLSD const& body) // Only used for HTTP_LLSD_POST
|
||||
LLSD const& body/*,*/ // Only used for HTTP_LLSD_POST
|
||||
DEBUG_CURLIO_PARAM(EDebugCurl debug))
|
||||
{
|
||||
lldebugs << "blockingRequest of " << url << llendl;
|
||||
|
||||
@@ -563,17 +585,17 @@ static LLSD blocking_request(
|
||||
if (method == HTTP_LLSD_POST)
|
||||
{
|
||||
responder = new BlockingLLSDPostResponder;
|
||||
LLHTTPClient::post(url, body, responder, headers);
|
||||
LLHTTPClient::post(url, body, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
|
||||
}
|
||||
else if (method == HTTP_LLSD_GET)
|
||||
{
|
||||
responder = new BlockingLLSDGetResponder;
|
||||
LLHTTPClient::get(url, responder, headers);
|
||||
LLHTTPClient::get(url, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
|
||||
}
|
||||
else // method == HTTP_RAW_GET
|
||||
{
|
||||
responder = new BlockingRawGetResponder;
|
||||
LLHTTPClient::get(url, responder, headers);
|
||||
LLHTTPClient::get(url, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
|
||||
}
|
||||
|
||||
responder->wait();
|
||||
@@ -635,39 +657,39 @@ static LLSD blocking_request(
|
||||
return response;
|
||||
}
|
||||
|
||||
LLSD LLHTTPClient::blockingPost(const std::string& url, const LLSD& body)
|
||||
LLSD LLHTTPClient::blockingPost(const std::string& url, const LLSD& body/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
|
||||
{
|
||||
return blocking_request(url, HTTP_LLSD_POST, body);
|
||||
return blocking_request(url, HTTP_LLSD_POST, body/*,*/ DEBUG_CURLIO_PARAM(debug));
|
||||
}
|
||||
|
||||
LLSD LLHTTPClient::blockingGet(const std::string& url)
|
||||
LLSD LLHTTPClient::blockingGet(const std::string& url/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
|
||||
{
|
||||
return blocking_request(url, HTTP_LLSD_GET, LLSD());
|
||||
return blocking_request(url, HTTP_LLSD_GET, LLSD()/*,*/ DEBUG_CURLIO_PARAM(debug));
|
||||
}
|
||||
|
||||
U32 LLHTTPClient::blockingGetRaw(const std::string& url, std::string& body)
|
||||
U32 LLHTTPClient::blockingGetRaw(const std::string& url, std::string& body/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
|
||||
{
|
||||
LLSD result = blocking_request(url, HTTP_RAW_GET, LLSD());
|
||||
LLSD result = blocking_request(url, HTTP_RAW_GET, LLSD()/*,*/ DEBUG_CURLIO_PARAM(debug));
|
||||
body = result["body"].asString();
|
||||
return result["status"].asInteger();
|
||||
}
|
||||
|
||||
void LLHTTPClient::put(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers)
|
||||
void LLHTTPClient::put(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
|
||||
{
|
||||
request(url, LLURLRequest::HTTP_PUT, new LLSDInjector(body), responder, headers);
|
||||
request(url, LLURLRequest::HTTP_PUT, new LLSDInjector(body), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
|
||||
}
|
||||
|
||||
void LLHTTPClient::post(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers)
|
||||
void LLHTTPClient::post(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive)
|
||||
{
|
||||
request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, headers);
|
||||
request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive);
|
||||
}
|
||||
|
||||
void LLHTTPClient::postXMLRPC(std::string const& url, XMLRPC_REQUEST xmlrpc_request, ResponderPtr responder, AIHTTPHeaders& headers)
|
||||
void LLHTTPClient::postXMLRPC(std::string const& url, XMLRPC_REQUEST xmlrpc_request, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive)
|
||||
{
|
||||
request(url, LLURLRequest::HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers, true, false); // Does use compression.
|
||||
request(url, LLURLRequest::HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, true, false); // Does use compression.
|
||||
}
|
||||
|
||||
void LLHTTPClient::postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder, AIHTTPHeaders& headers)
|
||||
void LLHTTPClient::postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive)
|
||||
{
|
||||
XMLRPC_REQUEST xmlrpc_request = XMLRPC_RequestNew();
|
||||
XMLRPC_RequestSetMethodName(xmlrpc_request, method);
|
||||
@@ -675,33 +697,33 @@ void LLHTTPClient::postXMLRPC(std::string const& url, char const* method, XMLRPC
|
||||
XMLRPC_RequestSetData(xmlrpc_request, value);
|
||||
// XMLRPCInjector takes ownership of xmlrpc_request and will free it when done.
|
||||
// LLURLRequest takes ownership of the XMLRPCInjector object and will free it when done.
|
||||
request(url, LLURLRequest::HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers, true, true); // Does not use compression.
|
||||
request(url, LLURLRequest::HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, true, true); // Does not use compression.
|
||||
}
|
||||
|
||||
void LLHTTPClient::postRaw(std::string const& url, char const* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers)
|
||||
void LLHTTPClient::postRaw(std::string const& url, char const* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive)
|
||||
{
|
||||
request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, headers);
|
||||
request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive);
|
||||
}
|
||||
|
||||
void LLHTTPClient::postFile(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers)
|
||||
void LLHTTPClient::postFile(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive)
|
||||
{
|
||||
request(url, LLURLRequest::HTTP_POST, new FileInjector(filename), responder, headers);
|
||||
request(url, LLURLRequest::HTTP_POST, new FileInjector(filename), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive);
|
||||
}
|
||||
|
||||
void LLHTTPClient::postFile(std::string const& url, LLUUID const& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers)
|
||||
void LLHTTPClient::postFile(std::string const& url, LLUUID const& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive)
|
||||
{
|
||||
request(url, LLURLRequest::HTTP_POST, new VFileInjector(uuid, asset_type), responder, headers);
|
||||
request(url, LLURLRequest::HTTP_POST, new VFileInjector(uuid, asset_type), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive);
|
||||
}
|
||||
|
||||
// static
|
||||
void LLHTTPClient::del(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers)
|
||||
void LLHTTPClient::del(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
|
||||
{
|
||||
request(url, LLURLRequest::HTTP_DELETE, NULL, responder, headers);
|
||||
request(url, LLURLRequest::HTTP_DELETE, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
|
||||
}
|
||||
|
||||
// static
|
||||
void LLHTTPClient::move(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers)
|
||||
void LLHTTPClient::move(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
|
||||
{
|
||||
headers.addHeader("Destination", destination);
|
||||
request(url, LLURLRequest::HTTP_MOVE, NULL, responder, headers);
|
||||
request(url, LLURLRequest::HTTP_MOVE, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
|
||||
}
|
||||
|
||||
@@ -66,6 +66,21 @@ struct AIBufferedCurlEasyRequestEvents {
|
||||
virtual void completed_headers(U32 status, std::string const& reason, AITransferInfo* info) = 0; // Transaction completed.
|
||||
};
|
||||
|
||||
enum EKeepAlive {
|
||||
no_keep_alive = 0,
|
||||
keep_alive
|
||||
};
|
||||
|
||||
#ifdef DEBUG_CURLIO
|
||||
enum EDebugCurl {
|
||||
debug_off = 0,
|
||||
debug_on
|
||||
};
|
||||
#define DEBUG_CURLIO_PARAM(p) ,p
|
||||
#else
|
||||
#define DEBUG_CURLIO_PARAM(p)
|
||||
#endif
|
||||
|
||||
class LLHTTPClient {
|
||||
public:
|
||||
|
||||
@@ -140,7 +155,16 @@ public:
|
||||
{
|
||||
// It's possible that this page was moved (302), so we already saw headers
|
||||
// from the 302 page and are starting over on the new page now.
|
||||
mReceivedHeaders.clear();
|
||||
// Erase all headers EXCEPT the cookies.
|
||||
AIHTTPReceivedHeaders set_cookie_headers;
|
||||
AIHTTPReceivedHeaders::range_type cookies;
|
||||
mReceivedHeaders.getValues("set-cookie", cookies);
|
||||
for (AIHTTPReceivedHeaders::iterator_type cookie = cookies.first; cookie != cookies.second; ++cookie)
|
||||
{
|
||||
set_cookie_headers.addHeader(cookie->first, cookie->second);
|
||||
}
|
||||
// Replace headers with just the cookie headers.
|
||||
mReceivedHeaders.swap(set_cookie_headers);
|
||||
}
|
||||
|
||||
// Called for all remaining headers.
|
||||
@@ -155,6 +179,9 @@ public:
|
||||
completedHeaders(status, reason, mReceivedHeaders);
|
||||
}
|
||||
|
||||
// Extract cookie 'key' from mReceivedHeaders and return the string 'key=value', or an empty string if key does not exists.
|
||||
std::string const& get_cookie(std::string const& key);
|
||||
|
||||
public:
|
||||
// Derived classes that implement completed_headers()/completedHeaders() should return true here.
|
||||
virtual bool needsHeaders(void) const { return false; }
|
||||
@@ -163,6 +190,9 @@ public:
|
||||
// The default is not to follow redirections.
|
||||
virtual bool followRedir(void) const { return false; }
|
||||
|
||||
// If this function returns false then we generate an error when a redirect status (300..399) is received.
|
||||
virtual bool redirect_status_ok(void) const { return followRedir(); }
|
||||
|
||||
// Timeout policy to use.
|
||||
virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const = 0;
|
||||
|
||||
@@ -358,59 +388,59 @@ public:
|
||||
|
||||
/** @name non-blocking API */
|
||||
//@{
|
||||
static void head(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers);
|
||||
static void head(std::string const& url, ResponderHeadersOnly* responder)
|
||||
{ AIHTTPHeaders headers; head(url, responder, headers); }
|
||||
static void head(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
|
||||
static void head(std::string const& url, ResponderHeadersOnly* responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
|
||||
{ AIHTTPHeaders headers; head(url, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
|
||||
|
||||
static void getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers);
|
||||
static void getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder)
|
||||
{ AIHTTPHeaders headers; getByteRange(url, offset, bytes, responder, headers); }
|
||||
static void getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
|
||||
static void getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
|
||||
{ AIHTTPHeaders headers; getByteRange(url, offset, bytes, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
|
||||
|
||||
static void get(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers);
|
||||
static void get(std::string const& url, ResponderPtr responder)
|
||||
{ AIHTTPHeaders headers; get(url, responder, headers); }
|
||||
static void get(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
|
||||
static void get(std::string const& url, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
|
||||
{ AIHTTPHeaders headers; get(url, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
|
||||
|
||||
static void get(std::string const& url, LLSD const& query, ResponderPtr responder, AIHTTPHeaders& headers);
|
||||
static void get(std::string const& url, LLSD const& query, ResponderPtr responder)
|
||||
{ AIHTTPHeaders headers; get(url, query, responder, headers); }
|
||||
static void get(std::string const& url, LLSD const& query, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
|
||||
static void get(std::string const& url, LLSD const& query, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
|
||||
{ AIHTTPHeaders headers; get(url, query, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
|
||||
|
||||
static void put(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers);
|
||||
static void put(std::string const& url, LLSD const& body, ResponderPtr responder)
|
||||
{ AIHTTPHeaders headers; put(url, body, responder, headers); }
|
||||
static void put(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
|
||||
static void put(std::string const& url, LLSD const& body, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
|
||||
{ AIHTTPHeaders headers; put(url, body, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
|
||||
|
||||
static void getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers);
|
||||
static void getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder)
|
||||
{ AIHTTPHeaders headers; getHeaderOnly(url, responder, headers); }
|
||||
static void getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
|
||||
static void getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
|
||||
{ AIHTTPHeaders headers; getHeaderOnly(url, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
|
||||
|
||||
static void post(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers);
|
||||
static void post(std::string const& url, LLSD const& body, ResponderPtr responder)
|
||||
{ AIHTTPHeaders headers; post(url, body, responder, headers); }
|
||||
static void post(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive);
|
||||
static void post(std::string const& url, LLSD const& body, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive)
|
||||
{ AIHTTPHeaders headers; post(url, body, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); }
|
||||
|
||||
/** Takes ownership of request and deletes it when sent */
|
||||
static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder, AIHTTPHeaders& headers);
|
||||
static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder)
|
||||
{ AIHTTPHeaders headers; postXMLRPC(url, request, responder, headers); }
|
||||
static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive);
|
||||
static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive)
|
||||
{ AIHTTPHeaders headers; postXMLRPC(url, request, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); }
|
||||
|
||||
static void postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder, AIHTTPHeaders& headers);
|
||||
static void postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder)
|
||||
{ AIHTTPHeaders headers; postXMLRPC(url, method, value, responder, headers); }
|
||||
static void postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive);
|
||||
static void postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive)
|
||||
{ AIHTTPHeaders headers; postXMLRPC(url, method, value, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); }
|
||||
|
||||
/** Takes ownership of data and deletes it when sent */
|
||||
static void postRaw(std::string const& url, const char* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers);
|
||||
static void postRaw(std::string const& url, const char* data, S32 size, ResponderPtr responder)
|
||||
{ AIHTTPHeaders headers; postRaw(url, data, size, responder, headers); }
|
||||
static void postRaw(std::string const& url, const char* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive);
|
||||
static void postRaw(std::string const& url, const char* data, S32 size, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive)
|
||||
{ AIHTTPHeaders headers; postRaw(url, data, size, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); }
|
||||
|
||||
static void postFile(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers);
|
||||
static void postFile(std::string const& url, std::string const& filename, ResponderPtr responder)
|
||||
{ AIHTTPHeaders headers; postFile(url, filename, responder, headers); }
|
||||
static void postFile(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive);
|
||||
static void postFile(std::string const& url, std::string const& filename, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive)
|
||||
{ AIHTTPHeaders headers; postFile(url, filename, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); }
|
||||
|
||||
static void postFile(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers);
|
||||
static void postFile(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder)
|
||||
{ AIHTTPHeaders headers; postFile(url, uuid, asset_type, responder, headers); }
|
||||
static void postFile(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive);
|
||||
static void postFile(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive)
|
||||
{ AIHTTPHeaders headers; postFile(url, uuid, asset_type, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); }
|
||||
|
||||
static void del(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers);
|
||||
static void del(std::string const& url, ResponderPtr responder)
|
||||
{ AIHTTPHeaders headers; del(url, responder, headers); }
|
||||
static void del(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
|
||||
static void del(std::string const& url, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
|
||||
{ AIHTTPHeaders headers; del(url, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
|
||||
|
||||
///< sends a DELETE method, but we can't call it delete in c++
|
||||
|
||||
@@ -423,9 +453,9 @@ public:
|
||||
* @param headers A map of key:value headers to pass to the request
|
||||
* @param timeout The number of seconds to give the server to respond.
|
||||
*/
|
||||
static void move(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers);
|
||||
static void move(std::string const& url, std::string const& destination, ResponderPtr responder)
|
||||
{ AIHTTPHeaders headers; move(url, destination, responder, headers); }
|
||||
static void move(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
|
||||
static void move(std::string const& url, std::string const& destination, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
|
||||
{ AIHTTPHeaders headers; move(url, destination, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
|
||||
|
||||
//@}
|
||||
|
||||
@@ -435,7 +465,7 @@ public:
|
||||
* @param url the complete serialized (and escaped) url to get
|
||||
* @return An LLSD of { 'status':status, 'body':payload }
|
||||
*/
|
||||
static LLSD blockingGet(std::string const& url);
|
||||
static LLSD blockingGet(std::string const& url/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
|
||||
|
||||
/**
|
||||
* @brief Blocking HTTP GET that returns the raw body.
|
||||
@@ -444,7 +474,7 @@ public:
|
||||
* @param result the target string to write the body to
|
||||
* @return HTTP status
|
||||
*/
|
||||
static U32 blockingGetRaw(const std::string& url, std::string& result);
|
||||
static U32 blockingGetRaw(const std::string& url, std::string& result/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
|
||||
|
||||
/**
|
||||
* @brief Blocking HTTP POST that returns an LLSD map of status and body.
|
||||
@@ -453,7 +483,7 @@ public:
|
||||
* @param body the LLSD post body
|
||||
* @return An LLSD of { 'status':status (an int), 'body':payload (an LLSD) }
|
||||
*/
|
||||
static LLSD blockingPost(std::string const& url, LLSD const& body);
|
||||
static LLSD blockingPost(std::string const& url, LLSD const& body/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
|
||||
};
|
||||
|
||||
#endif // LL_LLHTTPCLIENT_H
|
||||
|
||||
@@ -77,8 +77,8 @@ std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action)
|
||||
|
||||
// This might throw AICurlNoEasyHandle.
|
||||
LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, std::string const& url, Injector* body,
|
||||
LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, bool is_auth, bool no_compression) :
|
||||
mAction(action), mURL(url), mIsAuth(is_auth), mNoCompression(no_compression),
|
||||
LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, bool keepalive, bool is_auth, bool no_compression) :
|
||||
mAction(action), mURL(url), mKeepAlive(keepalive), mIsAuth(is_auth), mNoCompression(no_compression),
|
||||
mBody(body), mResponder(responder), mHeaders(headers)
|
||||
{
|
||||
}
|
||||
@@ -226,7 +226,7 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w)
|
||||
case HTTP_POST:
|
||||
{
|
||||
// Set the handle for an http post
|
||||
curlEasyRequest_w->setPost(mBodySize);
|
||||
curlEasyRequest_w->setPost(mBodySize, mKeepAlive);
|
||||
|
||||
// Set Accept-Encoding to allow response compression
|
||||
curlEasyRequest_w->setoptString(CURLOPT_ENCODING, mNoCompression ? "identity" : "");
|
||||
|
||||
@@ -77,7 +77,7 @@ class LLURLRequest : public AICurlEasyRequestStateMachine {
|
||||
* @param action One of the ERequestAction enumerations.
|
||||
* @param url The url of the request. It should already be encoded.
|
||||
*/
|
||||
LLURLRequest(ERequestAction action, std::string const& url, Injector* body, LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, bool is_auth, bool no_compression);
|
||||
LLURLRequest(ERequestAction action, std::string const& url, Injector* body, LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, bool keepalive, bool is_auth, bool no_compression);
|
||||
|
||||
protected:
|
||||
// Call abort(), not delete.
|
||||
@@ -111,6 +111,7 @@ class LLURLRequest : public AICurlEasyRequestStateMachine {
|
||||
private:
|
||||
ERequestAction mAction;
|
||||
std::string mURL;
|
||||
bool mKeepAlive; // Set to false only when explicitely requested.
|
||||
bool mIsAuth; // Set for authentication messages (login, buy land, buy currency).
|
||||
bool mNoCompression; // Set to disable using gzip.
|
||||
Injector* mBody; // Non-zero iff the action is HTTP_POST and HTTP_PUT.
|
||||
|
||||
Reference in New Issue
Block a user