From 6f8ea87c46b85b405652c59f16d95d0b6434158a Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Tue, 13 Nov 2012 21:46:35 +0100 Subject: [PATCH] Add ResponderHeadersOnly. ResponderHeadersOnly is a base class for responders that use HTTPClient::head or HTTPClient::getHeaderOnly. It already has a needsHeaders() that return true and only allows for completedHeaders to be overridden. I removed the CURLOPT_HEADER option for these cases, because that only causes the headers to be send to the writeCallback as if they are part of the body, in addition to the headerCallback; That gave raise to some confusion for the existing code (ie, unexpected errors when trying to decode the body as LLSD and duplicated 'low speed' information for the Timeout policy code. --- indra/llmessage/llhttpclient.cpp | 4 +-- indra/llmessage/llhttpclient.h | 45 +++++++++++++++++++++++++---- indra/llmessage/llurlrequest.cpp | 1 - indra/newview/llfloaterurlentry.cpp | 26 ++++++++--------- indra/newview/llpanellogin.cpp | 9 ++---- indra/newview/llviewermedia.cpp | 23 +++++++++------ 6 files changed, 71 insertions(+), 37 deletions(-) diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index b2bf549ab..1764a857a 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -231,7 +231,7 @@ void LLHTTPClient::getByteRange(std::string const& url, S32 offset, S32 bytes, R 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); } @@ -241,7 +241,7 @@ void LLHTTPClient::get(std::string const& url, ResponderPtr responder, AIHTTPHea 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); } diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index fa37e8b62..3e491de82 100644 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -183,6 +183,39 @@ public: // 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 * @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) { mCode = code; - // Allow classes derived from ResponderBase to override completedRaw - // (if not they should override completed or be derived from Responder instead). + // Allow classes derived from ResponderWithCompleted to override completedRaw + // (if not they should override completed or be derived from ResponderWithResult instead). completedRaw(http_status, reason, channels, buffer); mFinished = true; } @@ -324,8 +357,8 @@ public: /** @name non-blocking API */ //@{ - static void head(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers); - static void head(std::string const& url, ResponderPtr responder) + 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 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) { 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, ResponderPtr responder) + 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 post(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers); diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index e6b4ee4c3..927b64b7a 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -212,7 +212,6 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w) switch(mAction) { case HTTP_HEAD: - curlEasyRequest_w->setopt(CURLOPT_HEADER, 1); curlEasyRequest_w->setopt(CURLOPT_NOBODY, 1); curlEasyRequest_w->setopt(CURLOPT_FOLLOWLOCATION, 1); rv = true; diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp index d8d4f5e84..60d6ad963 100644 --- a/indra/newview/llfloaterurlentry.cpp +++ b/indra/newview/llfloaterurlentry.cpp @@ -53,7 +53,7 @@ static LLFloaterURLEntry* sInstance = NULL; // Move this to its own file. // 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 -class LLMediaTypeResponder : public LLHTTPClient::ResponderIgnoreBody +class LLMediaTypeResponder : public LLHTTPClient::ResponderHeadersOnly { public: LLMediaTypeResponder( const LLHandle parent ) : @@ -62,20 +62,20 @@ public: LLHandle mParent; - virtual bool needsHeaders(void) const { return true; } - virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) { - std::string media_type; - bool content_type_found = headers.getFirstValue("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); - } - - virtual void error( U32 status, const std::string& reason ) - { + if (200 <= status && status < 300) + { + std::string media_type; + if (headers.getFirstValue("content-type", media_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 << "LLMediaTypeResponder::completedHeaders: OK HTTP status (" << status << ") but no Content-Type! Received headers: " << headers << llendl; + } completeAny(status, "none/none"); } diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index cc20ab576..019ddd668 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -168,7 +168,7 @@ std::string gFullName; // 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 -class LLIamHereLogin : public LLHTTPClient::ResponderWithCompleted +class LLIamHereLogin : public LLHTTPClient::ResponderHeadersOnly { private: LLIamHereLogin( LLPanelLogin* parent ) : @@ -188,10 +188,7 @@ class LLIamHereLogin : public LLHTTPClient::ResponderWithCompleted mParent = parentIn; }; - // We don't actually expect LLSD back, so need to override completedRaw - virtual void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) + /*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) { if (mParent) { @@ -887,7 +884,7 @@ void LLPanelLogin::refreshLoginPage() std::string login_page = gHippoGridManager->getConnectedGrid()->getLoginPage(); if (!login_page.empty()) { - LLHTTPClient::head(login_page, gResponsePtr); + LLHTTPClient::head(login_page, gResponsePtr.get()); } else { sInstance->setSiteIsAlive(false); } diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index bc7c88e2b..94b05c958 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -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 // on the Panel Land Media and to discover the MIME type -class LLMimeDiscoveryResponder : public LLHTTPClient::ResponderIgnoreBody +class LLMimeDiscoveryResponder : public LLHTTPClient::ResponderHeadersOnly { LOG_CLASS(LLMimeDiscoveryResponder); public: @@ -80,16 +80,21 @@ public: mInitialized(false) {} - /*virtual*/ bool needsHeaders(void) const { return true; } - /*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) { - std::string media_type; - bool content_type_found = headers.getFirstValue("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); + if (200 <= status && status < 300) + { + std::string media_type; + if (headers.getFirstValue("content-type", media_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)