WIP: make everything use AICurlEasyRequestStateMachine

This commit is contained in:
Aleric Inglewood
2012-08-20 17:29:15 +02:00
parent 05c32c7a62
commit 83b13f6a3f
83 changed files with 766 additions and 752 deletions

View File

@@ -51,6 +51,7 @@
#include "lltimer.h" // ms_sleep
#include "llproxy.h"
#include "llhttpstatuscodes.h"
#include "aihttpheaders.h"
#ifdef CWDEBUG
#include <libcwd/buf2str.h>
#endif
@@ -797,7 +798,7 @@ void CurlEasyRequest::setoptString(CURLoption option, std::string const& value)
setopt(option, value.c_str());
}
void CurlEasyRequest::setPost(AIPostFieldPtr const& postdata, S32 size)
void CurlEasyRequest::setPost(AIPostFieldPtr const& postdata, U32 size)
{
llassert_always(postdata->data());
@@ -807,7 +808,7 @@ void CurlEasyRequest::setPost(AIPostFieldPtr const& postdata, S32 size)
setPost_raw(size, postdata->data());
}
void CurlEasyRequest::setPost_raw(S32 size, char const* data)
void CurlEasyRequest::setPost_raw(U32 size, char const* data)
{
if (!data)
{
@@ -815,6 +816,9 @@ void CurlEasyRequest::setPost_raw(S32 size, char const* data)
Dout(dc::curl, "POST size is " << size << " bytes.");
}
// Accept everything (send an Accept-Encoding header containing all encodings we support (zlib and gzip)).
setoptString(CURLOPT_ENCODING, ""); // CURLOPT_ACCEPT_ENCODING
// The server never replies with 100-continue, so suppress the "Expect: 100-continue" header that libcurl adds by default.
addHeader("Expect:");
if (size > 0)
@@ -823,7 +827,7 @@ void CurlEasyRequest::setPost_raw(S32 size, char const* data)
addHeader("Keep-alive: 300");
}
setopt(CURLOPT_POSTFIELDSIZE, size);
setopt(CURLOPT_POSTFIELDS, data);
setopt(CURLOPT_POSTFIELDS, data); // Implies CURLOPT_POST
}
ThreadSafeCurlEasyRequest* CurlEasyRequest::get_lockobj(void)
@@ -979,6 +983,12 @@ void CurlEasyRequest::addHeader(char const* header)
mHeaders = curl_slist_append(mHeaders, header);
}
void CurlEasyRequest::addHeaders(AIHTTPHeaders const& headers)
{
llassert(!mRequestFinalized);
headers.append_to(mHeaders);
}
#if defined(CWDEBUG) || defined(DEBUG_CURLIO)
static int curl_debug_cb(CURL*, curl_infotype infotype, char* buf, size_t size, void* user_ptr)
@@ -1307,14 +1317,8 @@ ThreadSafeBufferedCurlEasyRequest* CurlResponderBuffer::get_lockobj(void)
return static_cast<ThreadSafeBufferedCurlEasyRequest*>(AIThreadSafeSimple<CurlResponderBuffer>::wrapper_cast(this));
}
void CurlResponderBuffer::prepRequest(AICurlEasyRequest_wat& curl_easy_request_w, std::vector<std::string> const& headers, AICurlInterface::ResponderPtr responder, S32 time_out, bool post)
void CurlResponderBuffer::prepRequest(AICurlEasyRequest_wat& curl_easy_request_w, AIHTTPHeaders const& headers, AICurlInterface::ResponderPtr responder, S32 time_out)
{
if (post)
{
// Accept everything (send an Accept-Encoding header containing all encodings we support (zlib and gzip)).
curl_easy_request_w->setoptString(CURLOPT_ENCODING, ""); // CURLOPT_ACCEPT_ENCODING
}
mInput.reset(new LLBufferArray);
mInput->setThreaded(true);
mLastRead = NULL;
@@ -1343,14 +1347,8 @@ void CurlResponderBuffer::prepRequest(AICurlEasyRequest_wat& curl_easy_request_w
// Keep responder alive.
mResponder = responder;
if (!post)
{
// Add extra headers.
for (std::vector<std::string>::const_iterator iter = headers.begin(); iter != headers.end(); ++iter)
{
curl_easy_request_w->addHeader((*iter).c_str());
}
}
// Add extra headers.
curl_easy_request_w->addHeaders(headers);
}
//static
@@ -1500,7 +1498,12 @@ void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request
if (code == CURLE_OK)
{
curl_easy_request_w->getinfo(CURLINFO_RESPONSE_CODE, &responseCode);
//AIFIXME: fill responseReason if (responseCode < 200 || responseCode >= 300).
// If getResult code is CURLE_OK then we should have decoded the first header line ourselves.
llassert(responseCode == mStatus);
if (responseCode == mStatus)
responseReason = mReason;
else
responseReason = "Unknown reason.";
}
else
{

View File

@@ -36,6 +36,7 @@
#include <set>
#include <stdexcept>
#include <boost/intrusive_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
#include "llpreprocessor.h"
@@ -49,11 +50,12 @@
#define CURLOPT_DNS_USE_GLOBAL_CACHE do_not_use_CURLOPT_DNS_USE_GLOBAL_CACHE
#include "stdtypes.h" // U32
#include "lliopipe.h" // LLIOPipe::buffer_ptr_t
#include "llatomic.h" // LLAtomicU32
#include "aithreadsafe.h"
class LLSD;
class LLBufferArray;
class LLChannelDescriptors;
//-----------------------------------------------------------------------------
// Exceptions.
@@ -76,6 +78,11 @@ class AICurlNoMultiHandle : public AICurlError {
AICurlNoMultiHandle(std::string const& message) : AICurlError(message) { }
};
class AICurlNoBody : public AICurlError {
public:
AICurlNoBody(std::string const& message) : AICurlError(message) { }
};
// End Exceptions.
//-----------------------------------------------------------------------------
@@ -147,6 +154,9 @@ void setCAPath(std::string const& file);
// destructed too.
//
class Responder {
public:
typedef boost::shared_ptr<LLBufferArray> buffer_ptr_t;
protected:
Responder(void);
virtual ~Responder();
@@ -169,7 +179,7 @@ class Responder {
// Derived classes can override this to get the raw data of the body of the HTML message that was received.
// The default is to interpret the content as LLSD and call completed().
virtual void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, LLIOPipe::buffer_ptr_t const& buffer);
virtual void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer);
// Called from LLHTTPClient request calls, if an error occurs even before we can call one of the above.
// It calls completed() with a fake status U32_MAX, as that is what some derived clients expect (bad design).
@@ -272,13 +282,19 @@ typedef LLPointer<AIPostField> AIPostFieldPtr;
// AICurlEasyRequest: a thread safe, reference counting, auto-cleaning curl easy handle.
class AICurlEasyRequest {
public:
private:
// Use AICurlEasyRequestStateMachine, not AICurlEasyRequest.
friend class AICurlEasyRequestStateMachine;
// Initial construction is allowed (thread-safe).
// Note: If ThreadSafeCurlEasyRequest() throws then the memory allocated is still freed.
// 'new' never returned however and neither the constructor nor destructor of mCurlEasyRequest is called in this case.
// This might throw AICurlNoEasyHandle.
AICurlEasyRequest(bool buffered) :
mCurlEasyRequest(buffered ? new AICurlPrivate::ThreadSafeBufferedCurlEasyRequest : new AICurlPrivate::ThreadSafeCurlEasyRequest) { }
public:
// Used for storing this object in a standard container (see MultiHandle::add_easy_request).
AICurlEasyRequest(AICurlEasyRequest const& orig) : mCurlEasyRequest(orig.mCurlEasyRequest) { }
// For the rest, only allow read operations.

View File

@@ -34,6 +34,8 @@
#include <sstream>
#include "llatomic.h"
class AIHTTPHeaders;
namespace AICurlPrivate {
namespace curlthread { class MultiHandle; }
@@ -213,13 +215,14 @@ class CurlEasyHandle : public boost::noncopyable, protected AICurlEasyHandleEven
// and the CurlEasyRequest destructed.
class CurlEasyRequest : public CurlEasyHandle {
private:
void setPost_raw(S32 size, char const* data);
void setPost_raw(U32 size, char const* data);
public:
void setPost(S32 size) { setPost_raw(size, NULL); }
void setPost(AIPostFieldPtr const& postdata, S32 size);
void setPost(char const* data, S32 size) { setPost(new AIPostField(data), size); }
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 setoptString(CURLoption option, std::string const& value);
void addHeader(char const* str);
void addHeaders(AIHTTPHeaders const& headers);
private:
// Callback stubs.
@@ -324,11 +327,13 @@ class CurlEasyRequest : public CurlEasyHandle {
// is deleted and the CurlResponderBuffer destructed.
class CurlResponderBuffer : protected AICurlEasyHandleEvents {
public:
void resetState(AICurlEasyRequest_wat& curl_easy_request_w);
void prepRequest(AICurlEasyRequest_wat& buffered_curl_easy_request_w, std::vector<std::string> const& headers, AICurlInterface::ResponderPtr responder, S32 time_out = 0, bool post = false);
typedef AICurlInterface::Responder::buffer_ptr_t buffer_ptr_t;
LLIOPipe::buffer_ptr_t& getInput(void) { return mInput; }
LLIOPipe::buffer_ptr_t& getOutput(void) { return mOutput; }
void resetState(AICurlEasyRequest_wat& curl_easy_request_w);
void prepRequest(AICurlEasyRequest_wat& buffered_curl_easy_request_w, AIHTTPHeaders const& headers, AICurlInterface::ResponderPtr responder, S32 time_out = 0);
buffer_ptr_t& getInput(void) { return mInput; }
buffer_ptr_t& getOutput(void) { return mOutput; }
// Called if libcurl doesn't deliver within mRequestTimeOut seconds.
void timed_out(void);
@@ -346,9 +351,9 @@ class CurlResponderBuffer : protected AICurlEasyHandleEvents {
/*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w);
private:
LLIOPipe::buffer_ptr_t mInput;
buffer_ptr_t mInput;
U8* mLastRead; // Pointer into mInput where we last stopped reading (or NULL to start at the beginning).
LLIOPipe::buffer_ptr_t mOutput;
buffer_ptr_t mOutput;
AICurlInterface::ResponderPtr mResponder;
//U32 mBodyLimit; // From the old LLURLRequestDetail::mBodyLimit, but never used.
U32 mStatus; // HTTP status, decoded from the first header line.

View File

@@ -702,7 +702,11 @@ CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...)
{
LibcwDoutStream << "NULL";
}
LibcwDoutStream << "](" << (is_postfield ? postfieldsize : size) << " bytes))";
LibcwDoutStream << "]";
if (str)
{
LibcwDoutStream << "(" << (is_postfield ? postfieldsize : size) << " bytes))";
}
}
else
{