Merge branch 'master' of git://github.com/AlericInglewood/SingularityViewer

This commit is contained in:
Siana Gearz
2012-11-14 19:40:45 +01:00
9 changed files with 209 additions and 59 deletions

View File

@@ -1222,19 +1222,6 @@ void CurlEasyRequest::removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy
mHandleEventsTarget->removed_from_multi_handle(curl_easy_request_w); mHandleEventsTarget->removed_from_multi_handle(curl_easy_request_w);
} }
void CurlEasyRequest::print_diagnostics(CURLcode code)
{
if (code == CURLE_OPERATION_TIMEDOUT)
{
// mTimeout SHOULD always be set, but I see no reason not to test it, as
// this is far from the code that guaranteeds that it is set.
if (mTimeout)
{
mTimeout->print_diagnostics(this);
}
}
}
PerHostRequestQueuePtr CurlEasyRequest::getPerHostPtr(void) PerHostRequestQueuePtr CurlEasyRequest::getPerHostPtr(void)
{ {
if (!mPerHostPtr) if (!mPerHostPtr)
@@ -1314,6 +1301,25 @@ void BufferedCurlEasyRequest::resetState(void)
mInput.reset(); mInput.reset();
} }
void BufferedCurlEasyRequest::print_diagnostics(CURLcode code)
{
char* eff_url;
getinfo(CURLINFO_EFFECTIVE_URL, &eff_url);
if (code == CURLE_OPERATION_TIMEDOUT)
{
// mTimeout SHOULD always be set, but I see no reason not to test it, as
// this is far from the code that guaranteeds that it is set.
if (mTimeout)
{
mTimeout->print_diagnostics(this, eff_url);
}
}
else
{
llwarns << "Curl returned error code " << code << " (" << curl_easy_strerror(code) << ") for HTTP request to \"" << eff_url << "\"." << llendl;
}
}
ThreadSafeBufferedCurlEasyRequest* BufferedCurlEasyRequest::get_lockobj(void) ThreadSafeBufferedCurlEasyRequest* BufferedCurlEasyRequest::get_lockobj(void)
{ {
return static_cast<ThreadSafeBufferedCurlEasyRequest*>(AIThreadSafeSimple<BufferedCurlEasyRequest>::wrapper_cast(this)); return static_cast<ThreadSafeBufferedCurlEasyRequest*>(AIThreadSafeSimple<BufferedCurlEasyRequest>::wrapper_cast(this));

View File

@@ -97,7 +97,7 @@ class HTTPTimeout : public LLRefCount {
bool has_stalled(void) const { return mStalled < sClockCount; } bool has_stalled(void) const { return mStalled < sClockCount; }
// Called from BufferedCurlEasyRequest::processOutput if a timeout occurred. // Called from BufferedCurlEasyRequest::processOutput if a timeout occurred.
void print_diagnostics(CurlEasyRequest const* curl_easy_request); void print_diagnostics(CurlEasyRequest const* curl_easy_request, char const* eff_url);
#if defined(CWDEBUG) || defined(DEBUG_CURLIO) #if defined(CWDEBUG) || defined(DEBUG_CURLIO)
void* get_lockobj(void) const { return mLockObj; } void* get_lockobj(void) const { return mLockObj; }
@@ -344,9 +344,6 @@ class CurlEasyRequest : public CurlEasyHandle {
finished(curl_easy_request_w); finished(curl_easy_request_w);
} }
// Called by in case of an error.
void print_diagnostics(CURLcode code);
// Called by MultiHandle::check_msg_queue() to fill info with the transfer info. // Called by MultiHandle::check_msg_queue() to fill info with the transfer info.
void getTransferInfo(AITransferInfo* info); void getTransferInfo(AITransferInfo* info);
@@ -356,7 +353,7 @@ class CurlEasyRequest : public CurlEasyHandle {
// For debugging purposes. // For debugging purposes.
void print_curl_timings(void) const; void print_curl_timings(void) const;
private: protected:
curl_slist* mHeaders; curl_slist* mHeaders;
AICurlEasyHandleEvents* mHandleEventsTarget; AICurlEasyHandleEvents* mHandleEventsTarget;
CURLcode mResult; //AIFIXME: this does not belong in the request object, but belongs in the response object. CURLcode mResult; //AIFIXME: this does not belong in the request object, but belongs in the response object.
@@ -478,6 +475,9 @@ class BufferedCurlEasyRequest : public CurlEasyRequest {
// Called from curlHeaderCallback. // Called from curlHeaderCallback.
void setStatusAndReason(U32 status, std::string const& reason); void setStatusAndReason(U32 status, std::string const& reason);
// Called from processOutput by in case of an error.
void print_diagnostics(CURLcode code);
public: public:
// Return pointer to the ThreadSafe (wrapped) version of this object. // Return pointer to the ThreadSafe (wrapped) version of this object.
ThreadSafeBufferedCurlEasyRequest* get_lockobj(void); ThreadSafeBufferedCurlEasyRequest* get_lockobj(void);

View File

@@ -1971,9 +1971,102 @@ void HTTPTimeout::done(AICurlEasyRequest_wat const& curlEasyRequest_w, CURLcode
DoutCurl("done: mStalled set to -1"); DoutCurl("done: mStalled set to -1");
} }
void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request) void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, char const* eff_url)
{ {
llwarns << "Request to " << curl_easy_request->getLowercaseHostname() << " timed out for " << curl_easy_request->getTimeoutPolicy()->name() << llendl; llwarns << "Request to \"" << curl_easy_request->getLowercaseHostname() << "\" timed out for " << curl_easy_request->getTimeoutPolicy()->name() << llendl;
llinfos << "Effective URL: \"" << eff_url << "\"." << llendl;
double namelookup_time, connect_time, appconnect_time, pretransfer_time, starttransfer_time;
curl_easy_request->getinfo(CURLINFO_NAMELOOKUP_TIME, &namelookup_time);
curl_easy_request->getinfo(CURLINFO_CONNECT_TIME, &connect_time);
curl_easy_request->getinfo(CURLINFO_APPCONNECT_TIME, &appconnect_time);
curl_easy_request->getinfo(CURLINFO_PRETRANSFER_TIME, &pretransfer_time);
curl_easy_request->getinfo(CURLINFO_STARTTRANSFER_TIME, &starttransfer_time);
if (namelookup_time == 0)
{
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;
llassert(connect_time == 0);
llassert(appconnect_time == 0);
llassert(pretransfer_time == 0);
llassert(starttransfer_time == 0);
// Fatal error for diagnostics.
return;
}
// If namelookup_time is less than 500 microseconds, then it's very likely just a DNS cache lookup.
else if (namelookup_time < 500e-6)
{
llinfos << "Hostname was still in DNS cache." << llendl;
}
else
{
llwarns << "DNS lookup of " << curl_easy_request->getLowercaseHostname() << " took " << namelookup_time << " seconds." << llendl;
}
if (connect_time == 0)
{
llwarns << "Huh? Curl returned CURLE_OPERATION_TIMEDOUT, but connection did not occur according to timings. Expected CURLE_COULDNT_CONNECT!" << 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.
if (connect_time - namelookup_time <= 1e-6)
{
llinfos << "The socket was already connected (to remote or proxy)." << llendl;
if (appconnect_time == 0)
{
llwarns << "The SSL/TLS handshake never occurred according to the timings!" << llendl;
return;
}
// If appconnect_time is almost equal to connect_time, then it was just set because this is a connection re-use.
if (appconnect_time - connect_time <= 1e-6)
{
llinfos << "Connection with HTTP server was already established; this was a re-used connection." << llendl;
}
else
{
llinfos << "SSL/TLS handshake with HTTP server took " << (appconnect_time - connect_time) << " seconds." << llendl;
}
}
else
{
llinfos << "Socket connected to remote host (or proxy) in " << (connect_time - namelookup_time) << " seconds." << llendl;
if (appconnect_time == 0)
{
llwarns << "The SSL/TLS handshake never occurred according to the timings!" << llendl;
return;
}
llinfos << "SSL/TLS handshake with HTTP server took " << (appconnect_time - connect_time) << " seconds." << llendl;
}
if (pretransfer_time == 0)
{
llwarns << "The transfer never happened because there was too much in the pipeline (apparently)." << llendl;
return;
}
else if (pretransfer_time - appconnect_time >= 1e-6)
{
llinfos << "Apparently there was a delay, due to waits in line for the pipeline, of " << (pretransfer_time - appconnect_time) << " seconds before the transfer began." << llendl;
}
if (starttransfer_time == 0)
{
llwarns << "No data was ever received from the server according to the timings." << llendl;
}
else
{
llinfos << "The time it took to send the request to the server plus the time it took before the server started to reply was " << (starttransfer_time - pretransfer_time) << " seconds." << llendl;
}
if (mNothingReceivedYet)
{
llinfos << "No data at all was actually received from the server." << llendl;
}
if (mUploadFinished)
{
llinfos << "The request upload finished successfully." << llendl;
}
if (mLastSecond > 0 && mLowSpeedOn)
{
llinfos << "The " << (mNothingReceivedYet ? "upload" : "download") << " did last " << mLastSecond << " second" << ((mLastSecond == 1) ? "" : "s") << ", before it timed out." << llendl;
}
} }
} // namespace curlthread } // namespace curlthread

View File

@@ -136,7 +136,7 @@ class FileInjector : public Injector
/*virtual*/ U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer) /*virtual*/ U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer)
{ {
llifstream fstream(mFilename, std::iostream::binary | std::iostream::out); llifstream fstream(mFilename, std::ios::binary);
if (!fstream.is_open()) if (!fstream.is_open())
throw AICurlNoBody(llformat("Failed to open \"%s\".", mFilename.c_str())); throw AICurlNoBody(llformat("Failed to open \"%s\".", mFilename.c_str()));
LLBufferStream ostream(channels, buffer.get()); LLBufferStream ostream(channels, buffer.get());
@@ -149,7 +149,8 @@ class FileInjector : public Injector
#endif #endif
while (fstream) while (fstream)
{ {
std::streamsize len = fstream.readsome(tmpbuf, sizeof(tmpbuf)); fstream.read(tmpbuf, sizeof(tmpbuf));
std::streamsize len = fstream.gcount();
if (len > 0) if (len > 0)
{ {
ostream.write(tmpbuf, len); ostream.write(tmpbuf, len);
@@ -158,6 +159,8 @@ class FileInjector : public Injector
#endif #endif
} }
} }
if (fstream.bad())
throw AICurlNoBody(llformat("An error occured while reading \"%s\".", mFilename.c_str()));
fstream.close(); fstream.close();
ostream << std::flush; ostream << std::flush;
llassert(total_len == file_size && total_len == ostream.count_out()); llassert(total_len == file_size && total_len == ostream.count_out());
@@ -231,7 +234,7 @@ void LLHTTPClient::getByteRange(std::string const& url, S32 offset, S32 bytes, R
request(url, LLURLRequest::HTTP_GET, NULL, responder, headers); request(url, LLURLRequest::HTTP_GET, NULL, responder, headers);
} }
void LLHTTPClient::head(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers) void LLHTTPClient::head(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers)
{ {
request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers); request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers);
} }
@@ -241,7 +244,7 @@ void LLHTTPClient::get(std::string const& url, ResponderPtr responder, AIHTTPHea
request(url, LLURLRequest::HTTP_GET, NULL, responder, headers); request(url, LLURLRequest::HTTP_GET, NULL, responder, headers);
} }
void LLHTTPClient::getHeaderOnly(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers) void LLHTTPClient::getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers)
{ {
request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers); request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers);
} }
@@ -290,6 +293,13 @@ AIHTTPTimeoutPolicy const& LLHTTPClient::ResponderBase::getHTTPTimeoutPolicy(voi
void LLHTTPClient::ResponderBase::decode_llsd_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, LLSD& content) void LLHTTPClient::ResponderBase::decode_llsd_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, LLSD& content)
{ {
AICurlInterface::Stats::llsd_body_count++; AICurlInterface::Stats::llsd_body_count++;
if (status == HTTP_INTERNAL_ERROR)
{
// In case of an internal error (ie, a curl error), a description of the (curl) error is the best we can do.
// In any case, the body if anything was received at all, can not be relied upon.
content = reason;
return;
}
// If the status indicates success (and we get here) then we expect the body to be LLSD. // If the status indicates success (and we get here) then we expect the body to be LLSD.
bool const should_be_llsd = (200 <= status && status < 300); bool const should_be_llsd = (200 <= status && status < 300);
if (should_be_llsd) if (should_be_llsd)
@@ -334,6 +344,13 @@ void LLHTTPClient::ResponderBase::decode_llsd_body(U32 status, std::string const
void LLHTTPClient::ResponderBase::decode_raw_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, std::string& content) void LLHTTPClient::ResponderBase::decode_raw_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, std::string& content)
{ {
AICurlInterface::Stats::raw_body_count++; AICurlInterface::Stats::raw_body_count++;
if (status == HTTP_INTERNAL_ERROR)
{
// In case of an internal error (ie, a curl error), a description of the (curl) error is the best we can do.
// In any case, the body if anything was received at all, can not be relied upon.
content = reason;
return;
}
LLMutexLock lock(buffer->getMutex()); LLMutexLock lock(buffer->getMutex());
LLBufferArray::const_segment_iterator_t const end = buffer->endSegment(); LLBufferArray::const_segment_iterator_t const end = buffer->endSegment();
for (LLBufferArray::const_segment_iterator_t iter = buffer->beginSegment(); iter != end; ++iter) for (LLBufferArray::const_segment_iterator_t iter = buffer->beginSegment(); iter != end; ++iter)

View File

@@ -183,6 +183,39 @@ public:
// This function must delete the ResponderBase object when the reference count reaches zero. // This function must delete the ResponderBase object when the reference count reaches zero.
}; };
// Responders derived from this base class should use HTTPClient::head or HTTPClient::getHeaderOnly.
// That will set the curl option CURLOPT_NOBODY so that only headers are received.
class ResponderHeadersOnly : public ResponderBase {
private:
/*virtual*/ bool needsHeaders(void) const { return true; }
protected:
// ResponderBase event
// The responder finished. Do not override this function in derived classes; override completedRaw instead.
/*virtual*/ void finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer)
{
mCode = code;
// Allow classes derived from ResponderHeadersOnly to override completedHeaders.
completedHeaders(http_status, reason, mReceivedHeaders);
mFinished = true;
}
protected:
#ifdef SHOW_ASSERT
// Responders derived from this class must override completedHeaders.
// They may not attempt to override any of the virual functions defined by ResponderBase.
// Define those functions here with different parameters in order to cause a compile
// warning when a class accidently tries to override them.
enum YOU_MAY_ONLY_OVERRIDE_COMPLETED_HEADERS { };
virtual void completedRaw(YOU_MAY_ONLY_OVERRIDE_COMPLETED_HEADERS) { }
virtual void completed(YOU_MAY_ONLY_OVERRIDE_COMPLETED_HEADERS) { }
virtual void result(YOU_MAY_ONLY_OVERRIDE_COMPLETED_HEADERS) { }
virtual void errorWithContent(YOU_MAY_ONLY_OVERRIDE_COMPLETED_HEADERS) { }
virtual void error(YOU_MAY_ONLY_OVERRIDE_COMPLETED_HEADERS) { }
#endif
};
/** /**
* @class ResponderWithCompleted * @class ResponderWithCompleted
* @brief Base class for Responders that implement completed, or completedRaw if the response is not LLSD. * @brief Base class for Responders that implement completed, or completedRaw if the response is not LLSD.
@@ -195,8 +228,8 @@ public:
/*virtual*/ void finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) /*virtual*/ void finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer)
{ {
mCode = code; mCode = code;
// Allow classes derived from ResponderBase to override completedRaw // Allow classes derived from ResponderWithCompleted to override completedRaw
// (if not they should override completed or be derived from Responder instead). // (if not they should override completed or be derived from ResponderWithResult instead).
completedRaw(http_status, reason, channels, buffer); completedRaw(http_status, reason, channels, buffer);
mFinished = true; mFinished = true;
} }
@@ -324,8 +357,8 @@ public:
/** @name non-blocking API */ /** @name non-blocking API */
//@{ //@{
static void head(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers); static void head(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers);
static void head(std::string const& url, ResponderPtr responder) static void head(std::string const& url, ResponderHeadersOnly* responder)
{ AIHTTPHeaders headers; head(url, responder, headers); } { AIHTTPHeaders headers; head(url, responder, headers); }
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);
@@ -344,8 +377,8 @@ public:
static void put(std::string const& url, LLSD const& body, ResponderPtr responder) static void put(std::string const& url, LLSD const& body, ResponderPtr responder)
{ AIHTTPHeaders headers; put(url, body, responder, headers); } { AIHTTPHeaders headers; put(url, body, responder, headers); }
static void getHeaderOnly(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers); static void getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers);
static void getHeaderOnly(std::string const& url, ResponderPtr responder) static void getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder)
{ AIHTTPHeaders headers; getHeaderOnly(url, responder, headers); } { AIHTTPHeaders headers; getHeaderOnly(url, responder, headers); }
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);

View File

@@ -212,7 +212,6 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w)
switch(mAction) switch(mAction)
{ {
case HTTP_HEAD: case HTTP_HEAD:
curlEasyRequest_w->setopt(CURLOPT_HEADER, 1);
curlEasyRequest_w->setopt(CURLOPT_NOBODY, 1); curlEasyRequest_w->setopt(CURLOPT_NOBODY, 1);
curlEasyRequest_w->setopt(CURLOPT_FOLLOWLOCATION, 1); curlEasyRequest_w->setopt(CURLOPT_FOLLOWLOCATION, 1);
rv = true; rv = true;

View File

@@ -53,7 +53,7 @@ static LLFloaterURLEntry* sInstance = NULL;
// Move this to its own file. // Move this to its own file.
// helper class that tries to download a URL from a web site and calls a method // helper class that tries to download a URL from a web site and calls a method
// on the Panel Land Media and to discover the MIME type // on the Panel Land Media and to discover the MIME type
class LLMediaTypeResponder : public LLHTTPClient::ResponderIgnoreBody class LLMediaTypeResponder : public LLHTTPClient::ResponderHeadersOnly
{ {
public: public:
LLMediaTypeResponder( const LLHandle<LLFloater> parent ) : LLMediaTypeResponder( const LLHandle<LLFloater> parent ) :
@@ -62,20 +62,20 @@ public:
LLHandle<LLFloater> mParent; LLHandle<LLFloater> mParent;
virtual bool needsHeaders(void) const { return true; }
virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers)
{ {
std::string media_type; if (200 <= status && status < 300)
bool content_type_found = headers.getFirstValue("content-type", media_type); {
llassert_always(content_type_found); std::string media_type;
std::string::size_type idx1 = media_type.find_first_of(";"); if (headers.getFirstValue("content-type", media_type))
std::string mime_type = media_type.substr(0, idx1); {
completeAny(status, mime_type); std::string::size_type idx1 = media_type.find_first_of(";");
} std::string mime_type = media_type.substr(0, idx1);
completeAny(status, mime_type);
virtual void error( U32 status, const std::string& reason ) return;
{ }
llwarns << "LLMediaTypeResponder::completedHeaders: OK HTTP status (" << status << ") but no Content-Type! Received headers: " << headers << llendl;
}
completeAny(status, "none/none"); completeAny(status, "none/none");
} }

View File

@@ -168,7 +168,7 @@ std::string gFullName;
// helper class that trys to download a URL from a web site and calls a method // helper class that trys to download a URL from a web site and calls a method
// on parent class indicating if the web server is working or not // on parent class indicating if the web server is working or not
class LLIamHereLogin : public LLHTTPClient::ResponderWithCompleted class LLIamHereLogin : public LLHTTPClient::ResponderHeadersOnly
{ {
private: private:
LLIamHereLogin( LLPanelLogin* parent ) : LLIamHereLogin( LLPanelLogin* parent ) :
@@ -188,10 +188,7 @@ class LLIamHereLogin : public LLHTTPClient::ResponderWithCompleted
mParent = parentIn; mParent = parentIn;
}; };
// We don't actually expect LLSD back, so need to override completedRaw /*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers)
virtual void completedRaw(U32 status, const std::string& reason,
const LLChannelDescriptors& channels,
const LLIOPipe::buffer_ptr_t& buffer)
{ {
if (mParent) if (mParent)
{ {
@@ -887,7 +884,7 @@ void LLPanelLogin::refreshLoginPage()
std::string login_page = gHippoGridManager->getConnectedGrid()->getLoginPage(); std::string login_page = gHippoGridManager->getConnectedGrid()->getLoginPage();
if (!login_page.empty()) { if (!login_page.empty()) {
LLHTTPClient::head(login_page, gResponsePtr); LLHTTPClient::head(login_page, gResponsePtr.get());
} else { } else {
sInstance->setSiteIsAlive(false); sInstance->setSiteIsAlive(false);
} }

View File

@@ -71,7 +71,7 @@ const int RIGHT_BUTTON = 1;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Helper class that tries to download a URL from a web site and calls a method // Helper class that tries to download a URL from a web site and calls a method
// on the Panel Land Media and to discover the MIME type // on the Panel Land Media and to discover the MIME type
class LLMimeDiscoveryResponder : public LLHTTPClient::ResponderIgnoreBody class LLMimeDiscoveryResponder : public LLHTTPClient::ResponderHeadersOnly
{ {
LOG_CLASS(LLMimeDiscoveryResponder); LOG_CLASS(LLMimeDiscoveryResponder);
public: public:
@@ -80,16 +80,21 @@ public:
mInitialized(false) mInitialized(false)
{} {}
/*virtual*/ bool needsHeaders(void) const { return true; }
/*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) /*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers)
{ {
std::string media_type; if (200 <= status && status < 300)
bool content_type_found = headers.getFirstValue("content-type", media_type); {
llassert_always(content_type_found); std::string media_type;
std::string::size_type idx1 = media_type.find_first_of(";"); if (headers.getFirstValue("content-type", media_type))
std::string mime_type = media_type.substr(0, idx1); {
completeAny(status, mime_type); std::string::size_type idx1 = media_type.find_first_of(";");
std::string mime_type = media_type.substr(0, idx1);
completeAny(status, mime_type);
return;
}
llwarns << "LLMimeDiscoveryResponder::completedHeaders: OK HTTP status (" << status << ") but no Content-Type! Received headers: " << headers << llendl;
}
completeAny(status, "none/none");
} }
void completeAny(U32 status, const std::string& mime_type) void completeAny(U32 status, const std::string& mime_type)