Be more verbose about internal (curl / timeout) errors.

Translates the CURLE_WRITE_ERROR into what it really means: that the low
speed check failed.
This commit is contained in:
Aleric Inglewood
2013-03-09 05:26:52 +01:00
parent df93ebb8f6
commit 96d302aa42
16 changed files with 93 additions and 39 deletions

View File

@@ -873,13 +873,13 @@ void CurlEasyRequest::setSSLCtxCallback(curl_ssl_ctx_callback callback, void* us
static size_t noHeaderCallback(char* ptr, size_t size, size_t nmemb, void* userdata)
{
llmaybewarns << "Calling noHeaderCallback(); curl session aborted." << llendl;
return 0; // Cause a CURL_WRITE_ERROR
return 0; // Cause a CURLE_WRITE_ERROR
}
static size_t noWriteCallback(char* ptr, size_t size, size_t nmemb, void* userdata)
{
llmaybewarns << "Calling noWriteCallback(); curl session aborted." << llendl;
return 0; // Cause a CURL_WRITE_ERROR
return 0; // Cause a CURLE_WRITE_ERROR
}
static size_t noReadCallback(char* ptr, size_t size, size_t nmemb, void* userdata)
@@ -1277,7 +1277,7 @@ static int const HTTP_REDIRECTS_DEFAULT = 10;
LLChannelDescriptors const BufferedCurlEasyRequest::sChannels;
BufferedCurlEasyRequest::BufferedCurlEasyRequest() : mRequestTransferedBytes(0), mResponseTransferedBytes(0), mBufferEventsTarget(NULL), mStatus(HTTP_INTERNAL_ERROR)
BufferedCurlEasyRequest::BufferedCurlEasyRequest() : mRequestTransferedBytes(0), mResponseTransferedBytes(0), mBufferEventsTarget(NULL), mStatus(HTTP_INTERNAL_ERROR_OTHER)
{
AICurlInterface::Stats::BufferedCurlEasyRequest_count++;
}
@@ -1312,7 +1312,7 @@ BufferedCurlEasyRequest::~BufferedCurlEasyRequest()
void BufferedCurlEasyRequest::timed_out(void)
{
mResponder->finished(CURLE_OK, HTTP_INTERNAL_ERROR, "Request timeout, aborted.", sChannels, mOutput);
mResponder->finished(CURLE_OK, HTTP_INTERNAL_ERROR_CURL_LOCKUP, "Request timeout, aborted.", sChannels, mOutput);
if (mResponder->needsHeaders())
{
send_buffer_events_to(NULL); // Revoke buffer events: we send them to the responder.
@@ -1322,7 +1322,7 @@ void BufferedCurlEasyRequest::timed_out(void)
void BufferedCurlEasyRequest::bad_socket(void)
{
mResponder->finished(CURLE_OK, HTTP_INTERNAL_ERROR, "File descriptor went bad! Aborted.", sChannels, mOutput);
mResponder->finished(CURLE_OK, HTTP_INTERNAL_ERROR_CURL_BADSOCKET, "File descriptor went bad! Aborted.", sChannels, mOutput);
if (mResponder->needsHeaders())
{
send_buffer_events_to(NULL); // Revoke buffer events: we send them to the responder.
@@ -1343,7 +1343,7 @@ void BufferedCurlEasyRequest::resetState(void)
mRequestTransferedBytes = 0;
mResponseTransferedBytes = 0;
mBufferEventsTarget = NULL;
mStatus = HTTP_INTERNAL_ERROR;
mStatus = HTTP_INTERNAL_ERROR_OTHER;
}
void BufferedCurlEasyRequest::print_diagnostics(CURLcode code)

View File

@@ -435,7 +435,7 @@ class BufferedCurlEasyRequest : public CurlEasyRequest {
ThreadSafeBufferedCurlEasyRequest const* get_lockobj(void) const;
// Return true when an error code was received that can occur before the upload finished.
// So far the only such error I've seen is HTTP_BAD_REQUEST.
bool upload_error_status(void) const { return mStatus == HTTP_BAD_REQUEST /*&& mStatus != HTTP_INTERNAL_ERROR*/; }
bool upload_error_status(void) const { return mStatus == HTTP_BAD_REQUEST; }
// Return true when prepRequest was already called and the object has not been
// invalidated as a result of calling timed_out().

View File

@@ -1937,7 +1937,7 @@ void BufferedCurlEasyRequest::setStatusAndReason(U32 status, std::string const&
// 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->redirect_status_ok())
{
llerrs << "Received " << status << " (" << reason << ") for responder \"" << mTimeoutPolicy->name() << "\" which has no followRedir()!" << llendl;
llerrs << "Received " << status << " (" << reason << ") for responder \"" << mResponder->getName() << "\" which has no followRedir()!" << llendl;
}
}
@@ -1949,7 +1949,7 @@ void BufferedCurlEasyRequest::processOutput(void)
CURLcode code;
AITransferInfo info;
getResult(&code, &info);
if (code == CURLE_OK && mStatus != HTTP_INTERNAL_ERROR)
if (code == CURLE_OK && !is_internal_http_error(mStatus))
{
getinfo(CURLINFO_RESPONSE_CODE, &responseCode);
// If getResult code is CURLE_OK then we should have decoded the first header line ourselves.
@@ -1961,8 +1961,30 @@ void BufferedCurlEasyRequest::processOutput(void)
}
else
{
responseCode = HTTP_INTERNAL_ERROR;
responseReason = (code == CURLE_OK) ? mReason : std::string(curl_easy_strerror(code));
switch (code)
{
case CURLE_FAILED_INIT:
responseCode = HTTP_INTERNAL_ERROR_OTHER;
break;
case CURLE_OPERATION_TIMEDOUT:
responseCode = HTTP_INTERNAL_ERROR_CURL_TIMEOUT;
break;
case CURLE_WRITE_ERROR:
responseCode = HTTP_INTERNAL_ERROR_LOW_SPEED;
break;
default:
responseCode = HTTP_INTERNAL_ERROR_CURL_OTHER;
break;
}
if (responseCode == HTTP_INTERNAL_ERROR_LOW_SPEED)
{
// Rewrite error to something understandable.
responseReason = llformat("Download stalled: received less than %u bytes in %u seconds (in total received %u bytes, using responder %s). "
"To change these values, tune debug settings CurlTimeoutLowSpeedLimit and CurlTimeoutLowSpeedTime respectively.",
mResponder->getHTTPTimeoutPolicy().getLowSpeedLimit(), mResponder->getHTTPTimeoutPolicy().getLowSpeedTime(),
mResponseTransferedBytes, mResponder->getName());
}
setopt(CURLOPT_FRESH_CONNECT, TRUE);
}
@@ -2099,7 +2121,7 @@ size_t BufferedCurlEasyRequest::curlHeaderCallback(char* data, size_t size, size
}
// Either way, this status value is not understood (or taken into account).
// Set it to internal error so that the rest of code treats it as an error.
status = HTTP_INTERNAL_ERROR;
status = HTTP_INTERNAL_ERROR_OTHER;
}
self_w->received_HTTP_header();
self_w->setStatusAndReason(status, reason);

View File

@@ -294,6 +294,7 @@ bool HTTPTimeout::lowspeed(size_t bytes)
#endif
"aborting slow connection (average transfer rate below " << low_speed_limit <<
" for more than " << low_speed_time << " second" << ((low_speed_time == 1) ? "" : "s") << ")." << llendl;
// This causes curl to exit with CURLE_WRITE_ERROR.
return true;
}
}

View File

@@ -304,7 +304,7 @@ 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)
{
AICurlInterface::Stats::llsd_body_count++;
if (status == HTTP_INTERNAL_ERROR)
if (is_internal_http_error(status))
{
// 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.
@@ -355,7 +355,7 @@ 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)
{
AICurlInterface::Stats::raw_body_count++;
if (status == HTTP_INTERNAL_ERROR)
if (is_internal_http_error(status))
{
// 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.
@@ -612,11 +612,10 @@ static LLSD blocking_request(
responder->wait();
S32 http_status = HTTP_INTERNAL_ERROR;
LLSD response = LLSD::emptyMap();
CURLcode result = responder->result_code();
S32 http_status = responder->http_status();
http_status = responder->http_status();
bool http_success = http_status >= 200 && http_status < 300;
if (result == CURLE_OK && http_success)
{

View File

@@ -380,7 +380,7 @@ public:
}
public:
LegacyPolledResponder(void) : mStatus(HTTP_INTERNAL_ERROR) { }
LegacyPolledResponder(void) : mStatus(HTTP_INTERNAL_ERROR_OTHER) { }
// Accessors.
U32 http_status(void) const { return mStatus; }

View File

@@ -47,7 +47,6 @@
#include "llscopedvolatileaprpool.h"
#include "llfasttimer.h"
#include "message.h"
static const U32 HTTP_STATUS_PIPE_ERROR = 499;
/**
* String constants