Rearranged code and changed Curl_readwrite_init() and Curl_pre_readwrite() into

do_init() and do_complete() which now are called first and last in the DO
function. It simplified the flow in multi.c and the functions got more
sensible names!
This commit is contained in:
Daniel Stenberg 2007-11-15 21:45:45 +00:00
parent ca95f58ac0
commit 50feea3eef
8 changed files with 139 additions and 148 deletions

View File

@ -378,7 +378,6 @@ static CURLcode Curl_file(struct connectdata *conn, bool *done)
*done = TRUE; /* unconditionally */ *done = TRUE; /* unconditionally */
Curl_readwrite_init(conn);
Curl_initinfo(data); Curl_initinfo(data);
Curl_pgrsStartNow(data); Curl_pgrsStartNow(data);

View File

@ -178,7 +178,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
if(*datap == 0x0a) { if(*datap == 0x0a) {
/* we're now expecting data to come, unless size was zero! */ /* we're now expecting data to come, unless size was zero! */
if(0 == ch->datasize) { if(0 == ch->datasize) {
if(conn->bits.trailerHdrPresent!=TRUE) { if(conn->bits.trailerhdrpresent!=TRUE) {
/* No Trailer: header found - revert to original Curl processing */ /* No Trailer: header found - revert to original Curl processing */
ch->state = CHUNK_STOPCR; ch->state = CHUNK_STOPCR;

View File

@ -1121,11 +1121,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
} }
else { else {
/* we're done with the DO, now DO_DONE */ /* we're done with the DO, now DO_DONE */
easy->result = Curl_readwrite_init(easy->easy_conn); multistate(easy, CURLM_STATE_DO_DONE);
if(CURLE_OK == easy->result) { result = CURLM_CALL_MULTI_PERFORM;
multistate(easy, CURLM_STATE_DO_DONE);
result = CURLM_CALL_MULTI_PERFORM;
}
} }
} }
else { else {
@ -1152,11 +1149,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
} }
else { else {
/* we're done with the DO, now DO_DONE */ /* we're done with the DO, now DO_DONE */
easy->result = Curl_readwrite_init(easy->easy_conn); multistate(easy, CURLM_STATE_DO_DONE);
if(CURLE_OK == easy->result) { result = CURLM_CALL_MULTI_PERFORM;
multistate(easy, CURLM_STATE_DO_DONE);
result = CURLM_CALL_MULTI_PERFORM;
}
} }
} /* dophase_done */ } /* dophase_done */
} }
@ -1179,9 +1173,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
*/ */
easy->result = Curl_do_more(easy->easy_conn); easy->result = Curl_do_more(easy->easy_conn);
if(CURLE_OK == easy->result)
easy->result = Curl_readwrite_init(easy->easy_conn);
/* No need to remove ourselves from the send pipeline here since that /* No need to remove ourselves from the send pipeline here since that
is done for us in Curl_done() */ is done for us in Curl_done() */
@ -1207,9 +1198,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
easy->easy_conn->recv_pipe); easy->easy_conn->recv_pipe);
multistate(easy, CURLM_STATE_WAITPERFORM); multistate(easy, CURLM_STATE_WAITPERFORM);
result = CURLM_CALL_MULTI_PERFORM; result = CURLM_CALL_MULTI_PERFORM;
Curl_pre_readwrite(easy->easy_conn);
break; break;
case CURLM_STATE_WAITPERFORM: case CURLM_STATE_WAITPERFORM:

View File

@ -725,10 +725,6 @@ static CURLcode Curl_tftp(struct connectdata *conn, bool *done)
} }
state = (tftp_state_data_t *)data->reqdata.proto.tftp; state = (tftp_state_data_t *)data->reqdata.proto.tftp;
code = Curl_readwrite_init(conn);
if(code)
return code;
/* Run the TFTP State Machine */ /* Run the TFTP State Machine */
for(code=tftp_state_machine(state, TFTP_EVENT_INIT); for(code=tftp_state_machine(state, TFTP_EVENT_INIT);
(state->state != TFTP_STATE_FIN) && (code == CURLE_OK); (state->state != TFTP_STATE_FIN) && (code == CURLE_OK);

View File

@ -992,7 +992,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
* *
* It seems both Trailer: and Trailers: occur in the wild. * It seems both Trailer: and Trailers: occur in the wild.
*/ */
conn->bits.trailerHdrPresent = TRUE; conn->bits.trailerhdrpresent = TRUE;
} }
else if(checkprefix("Content-Encoding:", k->p) && else if(checkprefix("Content-Encoding:", k->p) &&
@ -1640,102 +1640,6 @@ CURLcode Curl_readwrite(struct connectdata *conn,
return CURLE_OK; return CURLE_OK;
} }
/*
* Curl_readwrite_init() inits the readwrite session. This is inited each time
* for a transfer, sometimes multiple times on the same SessionHandle
*/
CURLcode Curl_readwrite_init(struct connectdata *conn)
{
struct SessionHandle *data = conn->data;
struct Curl_transfer_keeper *k = &data->reqdata.keep;
/* NB: the content encoding software depends on this initialization of
Curl_transfer_keeper.*/
memset(k, 0, sizeof(struct Curl_transfer_keeper));
k->start = Curl_tvnow(); /* start time */
k->now = k->start; /* current time is now */
k->header = TRUE; /* assume header */
k->httpversion = -1; /* unknown at this point */
k->size = data->reqdata.size;
k->maxdownload = data->reqdata.maxdownload;
k->bytecountp = data->reqdata.bytecountp;
k->writebytecountp = data->reqdata.writebytecountp;
k->bytecount = 0;
k->buf = data->state.buffer;
k->uploadbuf = data->state.uploadbuffer;
k->maxfd = (conn->sockfd>conn->writesockfd?
conn->sockfd:conn->writesockfd)+1;
k->hbufp = data->state.headerbuff;
k->ignorebody=FALSE;
Curl_pgrsTime(data, TIMER_PRETRANSFER);
Curl_speedinit(data);
Curl_pgrsSetUploadCounter(data, 0);
Curl_pgrsSetDownloadCounter(data, 0);
if(!conn->bits.getheader) {
k->header = FALSE;
if(k->size > 0)
Curl_pgrsSetDownloadSize(data, k->size);
}
/* we want header and/or body, if neither then don't do this! */
if(conn->bits.getheader || !conn->bits.no_body) {
if(conn->sockfd != CURL_SOCKET_BAD) {
k->keepon |= KEEP_READ;
}
if(conn->writesockfd != CURL_SOCKET_BAD) {
/* HTTP 1.1 magic:
Even if we require a 100-return code before uploading data, we might
need to write data before that since the REQUEST may not have been
finished sent off just yet.
Thus, we must check if the request has been sent before we set the
state info where we wait for the 100-return code
*/
if(data->state.expect100header &&
(data->reqdata.proto.http->sending == HTTPSEND_BODY)) {
/* wait with write until we either got 100-continue or a timeout */
k->write_after_100_header = TRUE;
k->start100 = k->start;
}
else {
if(data->state.expect100header)
/* when we've sent off the rest of the headers, we must await a
100-continue */
k->wait100_after_headers = TRUE;
k->keepon |= KEEP_WRITE;
}
}
}
return CURLE_OK;
}
/*
* Curl_readwrite may get called multiple times. This function is called
* immediately before the first Curl_readwrite. Note that this can't be moved
* to Curl_readwrite_init since that function can get called while another
* pipeline request is in the middle of receiving data.
*
* We init chunking and trailer bits to their default values here immediately
* before receiving any header data for the current request in the pipeline.
*/
void Curl_pre_readwrite(struct connectdata *conn)
{
conn->bits.chunk=FALSE;
conn->bits.trailerHdrPresent=FALSE;
}
/* /*
* Curl_single_getsock() gets called by the multi interface code when the app * Curl_single_getsock() gets called by the multi interface code when the app
* has requested to get the sockets for the current connection. This function * has requested to get the sockets for the current connection. This function
@ -1757,6 +1661,9 @@ int Curl_single_getsock(const struct connectdata *conn,
return GETSOCK_BLANK; return GETSOCK_BLANK;
if(data->reqdata.keep.keepon & KEEP_READ) { if(data->reqdata.keep.keepon & KEEP_READ) {
DEBUGASSERT(conn->sockfd != CURL_SOCKET_BAD);
bitmap |= GETSOCK_READSOCK(sockindex); bitmap |= GETSOCK_READSOCK(sockindex);
sock[sockindex] = conn->sockfd; sock[sockindex] = conn->sockfd;
} }
@ -1769,6 +1676,9 @@ int Curl_single_getsock(const struct connectdata *conn,
one, we increase index */ one, we increase index */
if(data->reqdata.keep.keepon & KEEP_READ) if(data->reqdata.keep.keepon & KEEP_READ)
sockindex++; /* increase index if we need two entries */ sockindex++; /* increase index if we need two entries */
DEBUGASSERT(conn->writesockfd != CURL_SOCKET_BAD);
sock[sockindex] = conn->writesockfd; sock[sockindex] = conn->writesockfd;
} }
@ -1810,15 +1720,6 @@ Transfer(struct connectdata *conn)
if(!conn->bits.getheader && conn->bits.no_body) if(!conn->bits.getheader && conn->bits.no_body)
return CURLE_OK; return CURLE_OK;
if(!(conn->protocol & (PROT_FILE|PROT_TFTP))) {
/* Only do this if we are not transferring FILE or TFTP, since those
transfers are treated differently. They do their entire transfers in
the DO function and just returns from this. That is ugly indeed.
*/
Curl_readwrite_init(conn);
Curl_pre_readwrite(conn);
}
while(!done) { while(!done) {
curl_socket_t fd_read; curl_socket_t fd_read;
curl_socket_t fd_write; curl_socket_t fd_write;
@ -2523,25 +2424,23 @@ CURLcode Curl_perform(struct SessionHandle *data)
*/ */
CURLcode CURLcode
Curl_setup_transfer( Curl_setup_transfer(
struct connectdata *c_conn, /* connection data */ struct connectdata *conn, /* connection data */
int sockindex, /* socket index to read from or -1 */ int sockindex, /* socket index to read from or -1 */
curl_off_t size, /* -1 if unknown at this point */ curl_off_t size, /* -1 if unknown at this point */
bool getheader, /* TRUE if header parsing is wanted */ bool getheader, /* TRUE if header parsing is wanted */
curl_off_t *bytecountp, /* return number of bytes read or NULL */ curl_off_t *bytecountp, /* return number of bytes read or NULL */
int writesockindex, /* socket index to write to, it may very int writesockindex, /* socket index to write to, it may very well be
well be the same we read from. -1 the same we read from. -1 disables */
disables */ curl_off_t *writecountp /* return number of bytes written or NULL */
curl_off_t *writecountp /* return number of bytes written or )
NULL */
)
{ {
struct connectdata *conn = (struct connectdata *)c_conn;
struct SessionHandle *data; struct SessionHandle *data;
struct Curl_transfer_keeper *k;
if(!conn) DEBUGASSERT(conn != NULL);
return CURLE_BAD_FUNCTION_ARGUMENT;
data = conn->data; data = conn->data;
k = &data->reqdata.keep;
DEBUGASSERT((sockindex <= 1) && (sockindex >= -1)); DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
@ -2556,5 +2455,47 @@ Curl_setup_transfer(
data->reqdata.bytecountp = bytecountp; data->reqdata.bytecountp = bytecountp;
data->reqdata.writebytecountp = writecountp; data->reqdata.writebytecountp = writecountp;
/* The code sequence below is placed in this function just because all
necessary input is not always known in do_complete() as this function may
be called after that */
if(!conn->bits.getheader) {
k->header = FALSE;
if(k->size > 0)
Curl_pgrsSetDownloadSize(data, k->size);
}
/* we want header and/or body, if neither then don't do this! */
if(conn->bits.getheader || !conn->bits.no_body) {
if(conn->sockfd != CURL_SOCKET_BAD) {
k->keepon |= KEEP_READ;
}
if(conn->writesockfd != CURL_SOCKET_BAD) {
/* HTTP 1.1 magic:
Even if we require a 100-return code before uploading data, we might
need to write data before that since the REQUEST may not have been
finished sent off just yet.
Thus, we must check if the request has been sent before we set the
state info where we wait for the 100-return code
*/
if(data->state.expect100header &&
(data->reqdata.proto.http->sending == HTTPSEND_BODY)) {
/* wait with write until we either got 100-continue or a timeout */
k->write_after_100_header = TRUE;
k->start100 = k->start;
}
else {
if(data->state.expect100header)
/* when we've sent off the rest of the headers, we must await a
100-continue */
k->wait100_after_headers = TRUE;
k->keepon |= KEEP_WRITE;
}
}
}
return CURLE_OK; return CURLE_OK;
} }

View File

@ -31,8 +31,6 @@ CURLcode Curl_readwrite(struct connectdata *conn, bool *done);
int Curl_single_getsock(const struct connectdata *conn, int Curl_single_getsock(const struct connectdata *conn,
curl_socket_t *socks, curl_socket_t *socks,
int numsocks); int numsocks);
CURLcode Curl_readwrite_init(struct connectdata *conn);
void Curl_pre_readwrite(struct connectdata *conn);
CURLcode Curl_readrewind(struct connectdata *conn); CURLcode Curl_readrewind(struct connectdata *conn);
CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp); CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp);
bool Curl_retry_request(struct connectdata *conn, char **url); bool Curl_retry_request(struct connectdata *conn, char **url);

View File

@ -121,6 +121,7 @@ void idn_free (void *ptr); /* prototype from idn-free.h, not provided by
#include "select.h" #include "select.h"
#include "multiif.h" #include "multiif.h"
#include "easyif.h" #include "easyif.h"
#include "speedcheck.h"
/* And now for the protocols */ /* And now for the protocols */
#include "ftp.h" #include "ftp.h"
@ -164,6 +165,8 @@ static void conn_free(struct connectdata *conn);
static void signalPipeClose(struct curl_llist *pipeline); static void signalPipeClose(struct curl_llist *pipeline);
static struct SessionHandle* gethandleathead(struct curl_llist *pipeline); static struct SessionHandle* gethandleathead(struct curl_llist *pipeline);
static CURLcode do_init(struct connectdata *conn);
static void do_complete(struct connectdata *conn);
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
static void flush_cookies(struct SessionHandle *data, int cleanup); static void flush_cookies(struct SessionHandle *data, int cleanup);
@ -4449,21 +4452,83 @@ CURLcode Curl_done(struct connectdata **connp,
return result; return result;
} }
/*
* do_init() inits the readwrite session. This is inited each time (in the DO
* function before the protocol-specific DO functions are invoked) for a
* transfer, sometimes multiple times on the same SessionHandle. Make sure
* nothing in here depends on stuff that are setup dynamicly for the transfer.
*/
static CURLcode do_init(struct connectdata *conn)
{
struct SessionHandle *data = conn->data;
struct Curl_transfer_keeper *k = &data->reqdata.keep;
conn->bits.done = FALSE; /* Curl_done() is not called yet */
conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to use */
/* NB: the content encoding software depends on this initialization of
Curl_transfer_keeper.*/
memset(k, 0, sizeof(struct Curl_transfer_keeper));
k->start = Curl_tvnow(); /* start time */
k->now = k->start; /* current time is now */
k->header = TRUE; /* assume header */
k->httpversion = -1; /* unknown at this point */
k->bytecount = 0;
k->buf = data->state.buffer;
k->uploadbuf = data->state.uploadbuffer;
k->hbufp = data->state.headerbuff;
k->ignorebody=FALSE;
Curl_pgrsTime(data, TIMER_PRETRANSFER);
Curl_speedinit(data);
Curl_pgrsSetUploadCounter(data, 0);
Curl_pgrsSetDownloadCounter(data, 0);
return CURLE_OK;
}
/*
* do_complete is called when the DO actions are complete.
*
* We init chunking and trailer bits to their default values here immediately
* before receiving any header data for the current request in the pipeline.
*/
static void do_complete(struct connectdata *conn)
{
struct SessionHandle *data = conn->data;
struct Curl_transfer_keeper *k = &data->reqdata.keep;
conn->bits.chunk=FALSE;
conn->bits.trailerhdrpresent=FALSE;
k->maxfd = (conn->sockfd>conn->writesockfd?
conn->sockfd:conn->writesockfd)+1;
k->size = data->reqdata.size;
k->maxdownload = data->reqdata.maxdownload;
k->bytecountp = data->reqdata.bytecountp;
k->writebytecountp = data->reqdata.writebytecountp;
}
CURLcode Curl_do(struct connectdata **connp, bool *done) CURLcode Curl_do(struct connectdata **connp, bool *done)
{ {
CURLcode result=CURLE_OK; CURLcode result=CURLE_OK;
struct connectdata *conn = *connp; struct connectdata *conn = *connp;
struct SessionHandle *data = conn->data; struct SessionHandle *data = conn->data;
conn->bits.done = FALSE; /* Curl_done() is not called yet */ /* setup and init stuff before DO starts, in preparing for the transfer */
conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to use */ do_init(conn);
if(conn->handler->do_it) { if(conn->handler->do_it) {
/* generic protocol-specific function pointer set in curl_connect() */ /* generic protocol-specific function pointer set in curl_connect() */
result = conn->handler->do_it(conn, done); result = conn->handler->do_it(conn, done);
/* This was formerly done in transfer.c, but we better do it here */ /* This was formerly done in transfer.c, but we better do it here */
if((CURLE_SEND_ERROR == result) && conn->bits.reuse) { if((CURLE_SEND_ERROR == result) && conn->bits.reuse) {
/* This was a re-use of a connection and we got a write error in the /* This was a re-use of a connection and we got a write error in the
* DO-phase. Then we DISCONNECT this connection and have another attempt * DO-phase. Then we DISCONNECT this connection and have another attempt
@ -4513,6 +4578,10 @@ CURLcode Curl_do(struct connectdata **connp, bool *done)
} }
} }
} }
if(result == CURLE_OK)
/* pre readwrite must be called after the protocol-specific DO function */
do_complete(conn);
} }
return result; return result;
} }

View File

@ -600,7 +600,7 @@ struct ConnectBits {
requests */ requests */
bool netrc; /* name+password provided by netrc */ bool netrc; /* name+password provided by netrc */
bool trailerHdrPresent; /* Set when Trailer: header found in HTTP response. bool trailerhdrpresent; /* Set when Trailer: header found in HTTP response.
Required to determine whether to look for trailers Required to determine whether to look for trailers
in case of Transfer-Encoding: chunking */ in case of Transfer-Encoding: chunking */
bool done; /* set to FALSE when Curl_do() is called and set to TRUE bool done; /* set to FALSE when Curl_do() is called and set to TRUE