diff --git a/lib/multi.c b/lib/multi.c index 8bb93660d..c471c48d9 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -1810,6 +1810,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, { char *newurl = NULL; bool retry = FALSE; + bool comeback = FALSE; /* check if over send speed */ if((data->set.max_send_speed > 0) && @@ -1844,7 +1845,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } /* read/write data if it is ready to do so */ - result = Curl_readwrite(data->easy_conn, data, &done); + result = Curl_readwrite(data->easy_conn, data, &done, &comeback); k = &data->req; @@ -1950,6 +1951,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, rc = CURLM_CALL_MULTI_PERFORM; } } + else if(comeback) + rc = CURLM_CALL_MULTI_PERFORM; free(newurl); break; diff --git a/lib/transfer.c b/lib/transfer.c index f5987feb2..82a961f0e 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -384,11 +384,15 @@ bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc) * Go ahead and do a read if we have a readable socket or if * the stream was rewound (in which case we have data in a * buffer) + * + * return '*comeback' TRUE if we didn't properly drain the socket so this + * function should get called again without select() or similar in between! */ static CURLcode readwrite_data(struct Curl_easy *data, struct connectdata *conn, struct SingleRequest *k, - int *didwhat, bool *done) + int *didwhat, bool *done, + bool *comeback) { CURLcode result = CURLE_OK; ssize_t nread; /* number of bytes read */ @@ -398,6 +402,7 @@ static CURLcode readwrite_data(struct Curl_easy *data, int maxloops = 100; *done = FALSE; + *comeback = FALSE; /* This is where we loop until we have read everything there is to read or we get a CURLE_AGAIN */ @@ -804,6 +809,12 @@ static CURLcode readwrite_data(struct Curl_easy *data, } while(data_pending(conn) && maxloops--); + if(maxloops <= 0) { + /* we mark it as read-again-please */ + conn->cselect_bits = CURL_CSELECT_IN; + *comeback = TRUE; + } + if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) && conn->bits.close) { /* When we've read the entire thing and the close bit is set, the server @@ -1029,10 +1040,14 @@ static CURLcode readwrite_upload(struct Curl_easy *data, /* * Curl_readwrite() is the low-level function to be called when data is to * be read and written to/from the connection. + * + * return '*comeback' TRUE if we didn't properly drain the socket so this + * function should get called again without select() or similar in between! */ CURLcode Curl_readwrite(struct connectdata *conn, struct Curl_easy *data, - bool *done) + bool *done, + bool *comeback) { struct SingleRequest *k = &data->req; CURLcode result; @@ -1077,7 +1092,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, if((k->keepon & KEEP_RECV) && ((select_res & CURL_CSELECT_IN) || conn->bits.stream_was_rewound)) { - result = readwrite_data(data, conn, k, &didwhat, done); + result = readwrite_data(data, conn, k, &didwhat, done, comeback); if(result || *done) return result; } diff --git a/lib/transfer.h b/lib/transfer.h index 0e253e373..0058f8c86 100644 --- a/lib/transfer.h +++ b/lib/transfer.h @@ -40,10 +40,9 @@ typedef enum { CURLcode Curl_follow(struct Curl_easy *data, char *newurl, followtype type); - - CURLcode Curl_readwrite(struct connectdata *conn, - struct Curl_easy *data, bool *done); + struct Curl_easy *data, bool *done, + bool *comeback); int Curl_single_getsock(const struct connectdata *conn, curl_socket_t *socks, int numsocks);