Fixed showing TOS floater.

This creates a separate events interface structure
for CurlResponderBuffer (AICurlResponderBufferEvents)
for dealing with received HTTP headers.

The headers are passed to the Responder, but only
if the class derived from Responder implements
completedHeaders (otherwise it makes little sense
to even decode the headers).

Basically this is a reimplementation of the functionality
of the old LLHTTPClientURLAdaptor class.
This commit is contained in:
Aleric Inglewood
2012-09-18 23:59:09 +02:00
parent a032bd28ad
commit 1d5a63c180
13 changed files with 142 additions and 113 deletions

View File

@@ -445,9 +445,10 @@ void Responder::setURL(std::string const& url)
// Called with HTML header.
// virtual
void Responder::completedHeader(U32, std::string const&, LLSD const&)
void Responder::completedHeaders(U32, std::string const&, AIHTTPHeaders const&)
{
// Nothing.
// This should not be called unless a derived class implemented it.
llerrs << "Unexpected call to completedHeaders()." << llendl;
}
// Called with HTML body.
@@ -1242,12 +1243,6 @@ void CurlEasyRequest::added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_req
mEventsTarget->added_to_multi_handle(curl_easy_request_w);
}
void CurlEasyRequest::decoded_header(AICurlEasyRequest_wat& curl_easy_request_w, std::string const& key, std::string const& value)
{
if (mEventsTarget)
mEventsTarget->decoded_header(curl_easy_request_w, key, value);
}
void CurlEasyRequest::finished(AICurlEasyRequest_wat& curl_easy_request_w)
{
if (mEventsTarget)
@@ -1268,7 +1263,7 @@ static S32 const CURL_REQUEST_TIMEOUT = 30; // Seconds per operation.
LLChannelDescriptors const CurlResponderBuffer::sChannels;
CurlResponderBuffer::CurlResponderBuffer() : mRequestTransferedBytes(0), mResponseTransferedBytes(0)
CurlResponderBuffer::CurlResponderBuffer() : mRequestTransferedBytes(0), mResponseTransferedBytes(0), mEventsTarget(NULL)
{
ThreadSafeBufferedCurlEasyRequest* lockobj = get_lockobj();
AICurlEasyRequest_wat curl_easy_request_w(*lockobj);
@@ -1358,6 +1353,11 @@ void CurlResponderBuffer::prepRequest(AICurlEasyRequest_wat& curl_easy_request_w
// Keep responder alive.
mResponder = responder;
// Send header events to responder if needed.
if (mResponder->needsHeaders())
{
send_events_to(mResponder.get());
}
// Add extra headers.
curl_easy_request_w->addHeaders(headers);
@@ -1444,7 +1444,11 @@ size_t CurlResponderBuffer::curlHeaderCallback(char* data, size_t size, size_t n
reason = "Header parse error.";
llwarns << "Received broken header line from server: \"" << header << "\"" << llendl;
}
AICurlResponderBuffer_wat(*lockobj)->setStatusAndReason(status, reason);
{
AICurlResponderBuffer_wat curl_responder_buffer_w(*lockobj);
curl_responder_buffer_w->received_HTTP_header();
curl_responder_buffer_w->setStatusAndReason(status, reason);
}
return header_len;
}
@@ -1458,7 +1462,7 @@ size_t CurlResponderBuffer::curlHeaderCallback(char* data, size_t size, size_t n
key = utf8str_tolower(utf8str_trim(key));
value = utf8str_trim(value);
AICurlResponderBuffer_wat(*lockobj)->decoded_header(buffered_easy_request_w, key, value);
AICurlResponderBuffer_wat(*lockobj)->received_header(key, value);
}
else
{
@@ -1472,19 +1476,20 @@ size_t CurlResponderBuffer::curlHeaderCallback(char* data, size_t size, size_t n
return header_len;
}
void CurlResponderBuffer::added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w)
void CurlResponderBuffer::setStatusAndReason(U32 status, std::string const& reason)
{
Dout(dc::curl, "Calling CurlResponderBuffer::added_to_multi_handle(@" << (void*)&*curl_easy_request_w << ") for this = " << (void*)this);
mStatus = status;
mReason = reason;
}
void CurlResponderBuffer::decoded_header(AICurlEasyRequest_wat& curl_easy_request_w, std::string const& key, std::string const& value)
void CurlResponderBuffer::added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w)
{
Dout(dc::curl, "Calling CurlResponderBuffer::decoded_header(@" << (void*)&*curl_easy_request_w << ", \"" << key << "\", \"" << value << "\") for this = " << (void*)this);
llerrs << "Unexpected call to added_to_multi_handle()." << llendl;
}
void CurlResponderBuffer::finished(AICurlEasyRequest_wat& curl_easy_request_w)
{
Dout(dc::curl, "Calling CurlResponderBuffer::finished(@" << (void*)&*curl_easy_request_w << ") for this = " << (void*)this);
llerrs << "Unexpected call to finished()." << llendl;
}
void CurlResponderBuffer::removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w)
@@ -1534,6 +1539,14 @@ void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request
if (mResponder)
{
if (mEventsTarget)
{
// Only the responder registers for these events.
llassert(mEventsTarget == mResponder.get());
// Allow clients to parse headers before we attempt to parse
// the body and provide completed/result/error calls.
mEventsTarget->completed_headers(responseCode, responseReason);
}
mResponder->completedRaw(responseCode, responseReason, sChannels, mOutput);
mResponder = NULL;
}
@@ -1541,6 +1554,24 @@ void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request
resetState(curl_easy_request_w);
}
void CurlResponderBuffer::received_HTTP_header(void)
{
if (mEventsTarget)
mEventsTarget->received_HTTP_header();
}
void CurlResponderBuffer::received_header(std::string const& key, std::string const& value)
{
if (mEventsTarget)
mEventsTarget->received_header(key, value);
}
void CurlResponderBuffer::completed_headers(U32 status, std::string const& reason)
{
if (mEventsTarget)
mEventsTarget->completed_headers(status, reason);
}
//-----------------------------------------------------------------------------
// CurlMultiHandle

View File

@@ -52,6 +52,7 @@
#include "stdtypes.h" // U32
#include "llatomic.h" // LLAtomicU32
#include "aithreadsafe.h"
#include "aihttpheaders.h"
class LLSD;
class LLBufferArray;
@@ -86,6 +87,13 @@ class AICurlNoBody : public AICurlError {
// End Exceptions.
//-----------------------------------------------------------------------------
// Events generated by AICurlPrivate::CurlResponderBuffer.
struct AICurlResponderBufferEvents {
virtual void received_HTTP_header(void) = 0; // For example "HTTP/1.0 200 OK", the first header of a reply.
virtual void received_header(std::string const& key, std::string const& value) = 0; // Subsequent headers.
virtual void completed_headers(U32 status, std::string const& reason) = 0; // Transaction completed.
};
// Things defined in this namespace are called from elsewhere in the viewer code.
namespace AICurlInterface {
@@ -153,7 +161,7 @@ void setCAPath(std::string const& file);
// destructed. Also, if any of those are destructed then the Responder is automatically
// destructed too.
//
class Responder {
class Responder : public AICurlResponderBufferEvents {
public:
typedef boost::shared_ptr<LLBufferArray> buffer_ptr_t;
@@ -165,17 +173,42 @@ class Responder {
// Associated URL, used for debug output.
std::string mURL;
// Headers received from the server.
AIHTTPHeaders mReceivedHeaders;
public:
// Called to set the URL of the current request for this Responder,
// used only when printing debug output regarding activity of the Responder.
void setURL(std::string const& url);
public:
// Called from LLHTTPClientURLAdaptor::complete():
protected:
// Called when the "HTTP/1.0 <status> <reason>" header is received.
/*virual*/ void received_HTTP_header(void)
{
// 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();
}
// Called for all remaining headers.
/*virtual*/ void received_header(std::string const& key, std::string const& value)
{
mReceivedHeaders.addHeader(key, value);
}
// Called when the whole transaction is completed (also the body was received), but before the body is processed.
/*virtual*/ void completed_headers(U32 status, std::string const& reason)
{
completedHeaders(status, reason, mReceivedHeaders);
}
// Derived classes can override this to get the HTML header that was received, when the message is completed.
// The default does nothing.
virtual void completedHeader(U32 status, std::string const& reason, LLSD const& content);
virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPHeaders const& headers);
public:
// Derived classes that implement completedHeaders() should return true here.
virtual bool needsHeaders(void) const { return false; }
// 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().
@@ -251,7 +284,6 @@ typedef AIAccess<AICurlPrivate::CurlEasyRequest> AICurlEasyRequest_wat;
struct AICurlEasyHandleEvents {
// Events.
virtual void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
virtual void decoded_header(AICurlEasyRequest_wat& curl_easy_request_w, std::string const& key, std::string const& value) = 0;
virtual void finished(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
virtual void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
// Avoid compiler warning.

View File

@@ -77,11 +77,6 @@ void AICurlEasyRequestStateMachine::added_to_multi_handle(AICurlEasyRequest_wat&
set_state(AICurlEasyRequestStateMachine_added);
}
// CURL-THREAD
void AICurlEasyRequestStateMachine::decoded_header(AICurlEasyRequest_wat&, std::string const& key, std::string const& value)
{
}
// CURL-THREAD
void AICurlEasyRequestStateMachine::finished(AICurlEasyRequest_wat&)
{

View File

@@ -81,9 +81,6 @@ class AICurlEasyRequestStateMachine : public AIStateMachine, public AICurlEasyHa
// Called when this curl easy handle was added to a multi handle.
/*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat&);
// Called for each received HTTP header key/value pair.
/*virtual*/ void decoded_header(AICurlEasyRequest_wat&, std::string const& key, std::string const& value);
// Called when this curl easy handle finished processing (right before it is removed from the multi handle).
/*virtual*/ void finished(AICurlEasyRequest_wat&);

View File

@@ -308,7 +308,6 @@ class CurlEasyRequest : public CurlEasyHandle {
protected:
// Pass events to parent.
/*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w);
/*virtual*/ void decoded_header(AICurlEasyRequest_wat& curl_easy_request_w, std::string const& key, std::string const& value);
/*virtual*/ void finished(AICurlEasyRequest_wat& curl_easy_request_w);
/*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w);
};
@@ -328,7 +327,7 @@ class CurlEasyRequest : public CurlEasyHandle {
// is created which only happens by creating a AICurlEasyRequest(true) instance,
// and when the last AICurlEasyRequest is deleted, then the ThreadSafeBufferedCurlEasyRequest
// is deleted and the CurlResponderBuffer destructed.
class CurlResponderBuffer : protected AICurlEasyHandleEvents {
class CurlResponderBuffer : protected AICurlResponderBufferEvents, protected AICurlEasyHandleEvents {
public:
typedef AICurlInterface::Responder::buffer_ptr_t buffer_ptr_t;
@@ -347,9 +346,17 @@ class CurlResponderBuffer : protected AICurlEasyHandleEvents {
// Do not write more than this amount.
//void setBodyLimit(U32 size) { mBodyLimit = size; }
// Post-initialization, set the parent to pass the events to.
void send_events_to(AICurlResponderBufferEvents* target) { mEventsTarget = target; }
protected:
// Events from this class.
/*virtual*/ void received_HTTP_header(void);
/*virtual*/ void received_header(std::string const& key, std::string const& value);
/*virtual*/ void completed_headers(U32 status, std::string const& reason);
// CurlEasyHandle events.
/*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w);
/*virtual*/ void decoded_header(AICurlEasyRequest_wat& curl_easy_request_w, std::string const& key, std::string const& value);
/*virtual*/ void finished(AICurlEasyRequest_wat& curl_easy_request_w);
/*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w);
@@ -363,6 +370,7 @@ class CurlResponderBuffer : protected AICurlEasyHandleEvents {
std::string mReason; // The "reason" from the same header line.
S32 mRequestTransferedBytes;
S32 mResponseTransferedBytes;
AICurlResponderBufferEvents* mEventsTarget;
public:
static LLChannelDescriptors const sChannels; // Channel object for mInput (channel out()) and mOutput (channel in()).
@@ -380,7 +388,7 @@ class CurlResponderBuffer : protected AICurlEasyHandleEvents {
static size_t curlHeaderCallback(char* data, size_t size, size_t nmemb, void* user_data);
// Called from curlHeaderCallback.
void setStatusAndReason(U32 status, std::string const& reason) { mStatus = status; mReason = reason; }
void setStatusAndReason(U32 status, std::string const& reason);
public:
// Return pointer to the ThreadSafe (wrapped) version of this object.

View File

@@ -54,6 +54,9 @@ class AIHTTPHeaders {
// Construct a container with a single header.
AIHTTPHeaders(std::string const& key, std::string const& value);
// Clear all headers.
void clear(void) { if (mContainer) mContainer->mKeyValuePairs.clear(); }
// Add a header. Returns true if the header already existed.
bool addHeader(std::string const& key, std::string const& value, op_type op = new_header);
@@ -63,7 +66,7 @@ class AIHTTPHeaders {
// Return true if the header already exists.
bool hasHeader(std::string const& key) const;
// Return true if key exists and full value_out with the value. Return false otherwise.
// Return true if key exists and fill value_out with the value. Return false otherwise.
bool getValue(std::string const& key, std::string& value_out) const;
// Append the headers to slist.

View File

@@ -129,7 +129,7 @@ namespace LLAvatarNameCache
// Erase expired names from cache
void eraseUnrefreshed();
bool expirationFromCacheControl(LLSD headers, F64 *expires);
bool expirationFromCacheControl(AIHTTPHeaders const& headers, F64* expires);
}
/* Sample response:
@@ -179,16 +179,14 @@ private:
std::vector<LLUUID> mAgentIDs;
// Need the headers to look up Expires: and Retry-After:
LLSD mHeaders;
AIHTTPHeaders mHeaders;
public:
LLAvatarNameResponder(const std::vector<LLUUID>& agent_ids)
: mAgentIDs(agent_ids),
mHeaders()
: mAgentIDs(agent_ids)
{ }
/*virtual*/ void completedHeader(U32 status, const std::string& reason,
const LLSD& headers)
/*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPHeaders const& headers)
{
mHeaders = headers;
}
@@ -788,7 +786,7 @@ void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_na
sCache[agent_id] = av_name;
}
F64 LLAvatarNameCache::nameExpirationFromHeaders(LLSD headers)
F64 LLAvatarNameCache::nameExpirationFromHeaders(AIHTTPHeaders const& headers)
{
F64 expires = 0.0;
if (expirationFromCacheControl(headers, &expires))
@@ -804,16 +802,15 @@ F64 LLAvatarNameCache::nameExpirationFromHeaders(LLSD headers)
}
}
bool LLAvatarNameCache::expirationFromCacheControl(LLSD headers, F64 *expires)
bool LLAvatarNameCache::expirationFromCacheControl(AIHTTPHeaders const& headers, F64* expires)
{
bool fromCacheControl = false;
F64 now = LLFrameTimer::getTotalSeconds();
// Allow the header to override the default
LLSD cache_control_header = headers["cache-control"];
if (cache_control_header.isDefined())
std::string cache_control;
if (headers.getValue("cache-control", cache_control))
{
S32 max_age = 0;
std::string cache_control = cache_control_header.asString();
if (max_age_from_cache_control(cache_control, &max_age))
{
*expires = now + (F64)max_age;

View File

@@ -32,8 +32,8 @@
#include <boost/signals2.hpp>
class LLSD;
class LLUUID;
class AIHTTPHeaders;
namespace LLAvatarNameCache
{
@@ -98,7 +98,7 @@ namespace LLAvatarNameCache
// Compute name expiration time from HTTP Cache-Control header,
// or return default value, in seconds from epoch.
F64 nameExpirationFromHeaders(LLSD headers);
F64 nameExpirationFromHeaders(AIHTTPHeaders const& headers);
void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb);
}

View File

@@ -37,52 +37,6 @@
F32 const HTTP_REQUEST_EXPIRY_SECS = 60.0f;
////////////////////////////////////////////////////////////////////////////
#if 0
class LLHTTPClientURLAdaptor : public LLURLRequestComplete
{
public:
LLHTTPClientURLAdaptor(LLCurl::ResponderPtr responder)
: LLURLRequestComplete(), mResponder(responder), mStatus(499),
mReason("LLURLRequest complete w/no status")
{
}
~LLHTTPClientURLAdaptor()
{
}
virtual void httpStatus(U32 status, const std::string& reason)
{
LLURLRequestComplete::httpStatus(status,reason);
mStatus = status;
mReason = reason;
}
virtual void complete(const LLChannelDescriptors& channels,
const buffer_ptr_t& buffer)
{
if (mResponder.get())
{
// Allow clients to parse headers before we attempt to parse
// the body and provide completed/result/error calls.
mResponder->completedHeader(mStatus, mReason, mHeaderOutput);
mResponder->completedRaw(mStatus, mReason, channels, buffer);
}
}
virtual void header(const std::string& header, const std::string& value)
{
mHeaderOutput[header] = value;
}
private:
LLCurl::ResponderPtr mResponder;
U32 mStatus;
std::string mReason;
LLSD mHeaderOutput;
};
#endif
class LLSDInjector : public Injector
{
public:

View File

@@ -278,7 +278,7 @@ static void request(const std::string &url,
if ((method != LLURLRequest::HTTP_PUT) && (method != LLURLRequest::HTTP_POST)) {
std::string accept = "Accept: ";
accept += handler->getAcceptMimeType();
req->addHeader(accept.c_str());
//AIFIXME req is not defined: req->addHeader(accept.c_str());
}
//AIFIXME: req->setCallback(new HippoRestComplete(handler));
@@ -286,7 +286,7 @@ static void request(const std::string &url,
if ((method == LLURLRequest::HTTP_PUT) || (method == LLURLRequest::HTTP_POST)) {
std::string content = "Content-Type: ";
content += body->contentType();
req->addHeader(content.c_str());
//AIFIXME req is not defined: req->addHeader(content.c_str());
//AIFIXME: chain.push_back(LLIOPipe::ptr_t(body));
}

View File

@@ -59,10 +59,13 @@ public:
LLHandle<LLFloater> mParent;
virtual bool needsHeaders(void) const { return true; }
virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content)
virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPHeaders const& headers)
{
std::string media_type = content["content-type"].asString();
std::string media_type;
bool content_type_found = headers.getValue("content-type", media_type);
llassert_always(content_type_found);
std::string::size_type idx1 = media_type.find_first_of(";");
std::string mime_type = media_type.substr(0, idx1);
completeAny(status, mime_type);

View File

@@ -178,9 +178,8 @@ class LLDisplayNameUpdate : public LLHTTPNode
// default value
// *TODO: get actual headers out of ResponsePtr
//LLSD headers = response->mHeaders;
LLSD headers;
av_name.mExpires =
LLAvatarNameCache::nameExpirationFromHeaders(headers);
LLAvatarNameCache::nameExpirationFromHeaders(AIHTTPHeaders());
LLAvatarNameCache::insert(agent_id, av_name);

View File

@@ -75,11 +75,13 @@ public:
mInitialized(false)
{}
virtual bool needsHeaders(void) const { return true; }
virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content)
virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPHeaders const& headers)
{
std::string media_type = content["content-type"].asString();
std::string media_type;
bool content_type_found = headers.getValue("content-type", media_type);
llassert_always(content_type_found);
std::string::size_type idx1 = media_type.find_first_of(";");
std::string mime_type = media_type.substr(0, idx1);
completeAny(status, mime_type);
@@ -114,13 +116,17 @@ public:
{
}
/* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content)
/* virtual */ bool needsHeaders(void) const { return true; }
/* virtual */ void completedHeaders(U32 status, std::string const& reason, AIHTTPHeaders const& headers)
{
LL_DEBUGS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL;
LL_DEBUGS("MediaAuth") << content << LL_ENDL;
std::string cookie = content["set-cookie"].asString();
LLViewerMedia::openIDCookieResponse(cookie);
LL_DEBUGS("MediaAuth") << headers << LL_ENDL;
std::string cookie;
if (headers.getValue("set-cookie", cookie))
{
LLViewerMedia::openIDCookieResponse(cookie);
}
}
/* virtual */ void completedRaw(
@@ -148,14 +154,18 @@ public:
{
}
/* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content)
/* virtual */ bool needsHeaders(void) const { return true; }
/* virtual */ void completedHeaders(U32 status, std::string const& reason, AIHTTPHeaders const& headers)
{
LL_WARNS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL;
LL_WARNS("MediaAuth") << content << LL_ENDL;
LL_INFOS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL;
LL_INFOS("MediaAuth") << headers << LL_ENDL;
std::string cookie = content["set-cookie"].asString();
LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost);
std::string cookie;
if (headers.getValue("set-cookie", cookie))
{
LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost);
}
}
void completedRaw(