HTTP timeout bug fix! Plus work in progress.

Use the better understandable alias CURLOPT_HTTPHEADER in debug output

Bug fix - finally!

This fixes a bug I've been looking for a week.
By accidently calling get_clock_count() for the mTimeoutLowSpeedClock
'event', the time difference 'now' - 'event' becomes negative, which
should be impossible; the result being that timeout_low_speed
stalled for 24 seconds while looping over the full 32 bit. That in
turn made SSL handshakes of libcurl fail, which seemed to be
impossible since the calls to libcurl had not changed!
This commit is contained in:
Aleric Inglewood
2012-10-09 21:01:55 +02:00
parent 02ead94848
commit faee255730
4 changed files with 133 additions and 18 deletions

View File

@@ -697,7 +697,7 @@ bool MergeIterator::next(curl_socket_t& fd_out, int& ev_bitmask_out)
#if defined(CWDEBUG) || defined(DEBUG_CURLIO)
#undef AI_CASE_RETURN
#define AI_CASE_RETURN(x) do { case x: return #x; } while(0)
#define AI_CASE_RETURN(x) case x: return #x;
static char const* action_str(int action)
{
switch(action)
@@ -710,6 +710,32 @@ static char const* action_str(int action)
}
return "<unknown action>";
}
struct DebugFdSet {
int nfds;
fd_set* fdset;
DebugFdSet(int n, fd_set* p) : nfds(n), fdset(p) { }
};
std::ostream& operator<<(std::ostream& os, DebugFdSet const& s)
{
if (!s.fdset)
return os << "NULL";
bool first = true;
os << '{';
for (int fd = 0; fd < s.nfds; ++fd)
{
if (FD_ISSET(fd, s.fdset))
{
if (!first)
os << ", ";
os << fd;
first = false;
}
}
os << '}';
return os;
}
#endif
// A class with info for each socket that is in use by curl.
@@ -763,9 +789,17 @@ void CurlSocketInfo::set_action(int action)
else
{
mMultiHandle.mWritePollSet->remove(mSocketFd);
// If CURL_POLL_OUT is removed, we have nothing more to send apparently.
// The following is a bit of a hack, needed because of the lack of proper timeout callbacks in libcurl.
// The removal of CURL_POLL_OUT could be part of the SSL handshake, therefore check if we're already connected:
AICurlEasyRequest_wat curl_easy_request_w(*mEasyRequest);
curl_easy_request_w->timeout_upload_finished(); // Update timeout administration.
double pretransfer_time;
curl_easy_request_w->getinfo(CURLINFO_PRETRANSFER_TIME, &pretransfer_time);
if (pretransfer_time > 0)
{
// If CURL_POLL_OUT is removed and CURLINFO_PRETRANSFER_TIME is already set, then we have nothing more to send apparently.
curl_easy_request_w->timeout_upload_finished(); // Update timeout administration.
}
}
}
}
@@ -1284,6 +1318,9 @@ void AICurlThread::run(void)
timeout.tv_sec = timeout_ms / 1000;
timeout.tv_usec = (timeout_ms % 1000) * 1000;
#ifdef CWDEBUG
#ifdef DEBUG_CURLIO
Dout(dc::curl|flush_cf|continued_cf, "select(" << nfds << ", " << DebugFdSet(nfds, read_fd_set) << ", " << DebugFdSet(nfds, write_fd_set) << ", NULL, timeout = " << timeout_ms << " ms) = ");
#else
static int last_nfds = -1;
static long last_timeout_ms = -1;
static int same_count = 0;
@@ -1299,10 +1336,14 @@ void AICurlThread::run(void)
{
++same_count;
}
#endif
#endif
ready = select(nfds, read_fd_set, write_fd_set, NULL, &timeout);
mWakeUpMutex.unlock();
#ifdef CWDEBUG
#ifdef DEBUG_CURLIO
Dout(dc::finish|cond_error_cf(ready == -1), ready);
#else
static int last_ready = -2;
static int last_errno = 0;
if (!same)
@@ -1319,6 +1360,7 @@ void AICurlThread::run(void)
last_ready = ready;
if (ready == -1)
last_errno = errno;
#endif
#endif
// Select returns the total number of bits set in each of the fd_set's (upon return),
// or -1 when an error occurred. A value of 0 means that a timeout occurred.
@@ -1329,6 +1371,7 @@ void AICurlThread::run(void)
}
// Clock count used for timeouts.
CurlEasyRequest::sTimeoutClockCount = get_clock_count();
Dout(dc::curl, "CurlEasyRequest::sTimeoutClockCount = " << CurlEasyRequest::sTimeoutClockCount);
if (ready == 0)
{
multi_handle_w->socket_action(CURL_SOCKET_TIMEOUT, 0);
@@ -1607,7 +1650,7 @@ void MultiHandle::finish_easy_request(AICurlEasyRequest const& easy_request, CUR
{
AICurlEasyRequest_wat curl_easy_request_w(*easy_request);
// Store the result in the easy handle.
curl_easy_request_w->store_result(result);
curl_easy_request_w->storeResult(result);
#ifdef CWDEBUG
char* eff_url;
curl_easy_request_w->getinfo(CURLINFO_EFFECTIVE_URL, &eff_url);