1
0
mirror of https://github.com/moparisthebest/curl synced 2024-08-13 17:03:50 -04:00

Hoist the loop out of get_request, and make sure that it can be reentered when a request is

half-finished.

Note the the req struct used to be re-initialized AFTER reading pipeline data, so now that we
initialize it from the caller we must be careful not to overwrite the pipeline data.

Also we now need to handle the case where the buffer is already full when get_request is called -
previously this never happened as it was always called with an empty buffer and looped until done.

Now get_request is called in a loop, so the next step is to run the loop on a socket only when poll
signals it is readable.
This commit is contained in:
Joe Mason 2012-08-01 17:09:38 -04:00
parent 81656a8466
commit 19035292d0

View File

@ -110,6 +110,7 @@ struct httprequest {
int callcount; /* times ProcessRequest() gets called */ int callcount; /* times ProcessRequest() gets called */
unsigned short connect_port; /* the port number CONNECT used */ unsigned short connect_port; /* the port number CONNECT used */
bool connmon; /* monitor the state of the connection, log disconnects */ bool connmon; /* monitor the state of the connection, log disconnects */
int done_processing;
}; };
static int ProcessRequest(struct httprequest *req); static int ProcessRequest(struct httprequest *req);
@ -793,27 +794,15 @@ storerequest_cleanup:
dumpfile, error, strerror(error)); dumpfile, error, strerror(error));
} }
/* return 0 on success, non-zero on failure */ static void init_httprequest(struct httprequest *req)
static int get_request(curl_socket_t sock, struct httprequest *req)
{ {
int error; /* Pipelining is already set, so do not initialize it here. Only initialize
int fail = 0; checkindex and offset if pipelining is not set, since in a pipeline they
int done_processing = 0; need to be inherited from the previous request. */
char *reqbuf = req->reqbuf; if(!req->pipelining) {
ssize_t got = 0; req->checkindex = 0;
req->offset = 0;
char *pipereq = NULL;
size_t pipereq_length = 0;
if(req->pipelining) {
pipereq = reqbuf + req->checkindex;
pipereq_length = req->offset - req->checkindex;
} }
/*** Init the httprequest structure properly for the upcoming request ***/
req->checkindex = 0;
req->offset = 0;
req->testno = DOCNUMBER_NOTHING; req->testno = DOCNUMBER_NOTHING;
req->partno = 0; req->partno = 0;
req->open = TRUE; req->open = TRUE;
@ -827,13 +816,39 @@ static int get_request(curl_socket_t sock, struct httprequest *req)
req->writedelay = 0; req->writedelay = 0;
req->rcmd = RCMD_NORMALREQ; req->rcmd = RCMD_NORMALREQ;
req->prot_version = 0; req->prot_version = 0;
req->pipelining = FALSE;
req->callcount = 0; req->callcount = 0;
req->connect_port = 0; req->connect_port = 0;
req->done_processing = 0;
}
/*** end of httprequest init ***/ /* return 0 on success, non-zero on failure */
static int get_request(curl_socket_t sock, struct httprequest *req)
{
int error;
int fail = 0;
char *reqbuf = req->reqbuf;
ssize_t got = 0;
int overflow = 0;
while(!done_processing && (req->offset < REQBUFSIZ-1)) { char *pipereq = NULL;
size_t pipereq_length = 0;
if(req->pipelining) {
pipereq = reqbuf + req->checkindex;
pipereq_length = req->offset - req->checkindex;
/* Now that we've got the pipelining info we can reset the
pipelining-related vars which were skipped in init_httprequest */
req->pipelining = FALSE;
req->checkindex = 0;
req->offset = 0;
}
if(req->offset >= REQBUFSIZ-1) {
/* buffer is already full; do nothing */
overflow = 1;
}
else {
if(pipereq_length && pipereq) { if(pipereq_length && pipereq) {
memmove(reqbuf, pipereq, pipereq_length); memmove(reqbuf, pipereq, pipereq_length);
got = curlx_uztosz(pipereq_length); got = curlx_uztosz(pipereq_length);
@ -871,17 +886,17 @@ static int get_request(curl_socket_t sock, struct httprequest *req)
req->offset += (size_t)got; req->offset += (size_t)got;
reqbuf[req->offset] = '\0'; reqbuf[req->offset] = '\0';
done_processing = ProcessRequest(req); req->done_processing = ProcessRequest(req);
if(got_exit_signal) if(got_exit_signal)
return 1; return 1;
if(done_processing && req->pipe) { if(req->done_processing && req->pipe) {
logmsg("Waiting for another piped request"); logmsg("Waiting for another piped request");
done_processing = 0; req->done_processing = 0;
req->pipe--; req->pipe--;
} }
} }
if((req->offset == REQBUFSIZ-1) && (got > 0)) { if(overflow || (req->offset == REQBUFSIZ-1 && got > 0)) {
logmsg("Request would overflow buffer, closing connection"); logmsg("Request would overflow buffer, closing connection");
/* dump request received so far to external file anyway */ /* dump request received so far to external file anyway */
reqbuf[REQBUFSIZ-1] = '\0'; reqbuf[REQBUFSIZ-1] = '\0';
@ -896,8 +911,9 @@ static int get_request(curl_socket_t sock, struct httprequest *req)
else else
reqbuf[req->offset] = '\0'; reqbuf[req->offset] = '\0';
/* dump the request to an external file */ /* at the end of a request dump it to an external file */
storerequest(reqbuf, req->pipelining ? req->checkindex : req->offset); if (fail || req->done_processing)
storerequest(reqbuf, req->pipelining ? req->checkindex : req->offset);
if(got_exit_signal) if(got_exit_signal)
return 1; return 1;
@ -1443,7 +1459,12 @@ static void http_connect(curl_socket_t *infdp,
logmsg("TCP_NODELAY set for client DATA conection"); logmsg("TCP_NODELAY set for client DATA conection");
#endif #endif
req2.pipelining = FALSE; req2.pipelining = FALSE;
err = get_request(datafd, &req2); init_httprequest(&req2);
while(!req2.done_processing) {
err = get_request(datafd, &req2);
if(err)
break;
}
if(!err) { if(!err) {
err = send_doc(datafd, &req2); err = send_doc(datafd, &req2);
if(!err && (req2.testno == DOCNUMBER_CONNECT)) { if(!err && (req2.testno == DOCNUMBER_CONNECT)) {
@ -1727,9 +1748,13 @@ static int service_connection(int msgsock, struct httprequest *req,
if(got_exit_signal) if(got_exit_signal)
return 1; return 1;
if(get_request(msgsock, req)) init_httprequest(req);
/* non-zero means error, break out of loop */ while(!req->done_processing) {
return 1; if (get_request(msgsock, req)) {
/* non-zero means error, break out of loop */
return 1;
}
}
if(prevbounce) { if(prevbounce) {
/* bounce treatment requested */ /* bounce treatment requested */
@ -1974,9 +1999,9 @@ int main(int argc, char *argv[])
if (CURL_SOCKET_BAD == msgsock) if (CURL_SOCKET_BAD == msgsock)
goto sws_cleanup; goto sws_cleanup;
/* initialization of httprequest struct is done in get_request(), but due /* initialization of httprequest struct is done before get_request(), but
to pipelining treatment the pipelining struct field must be initialized the pipelining struct field must be initialized previously to FALSE
previously to FALSE every time a new connection arrives. */ every time a new connection arrives. */
req.pipelining = FALSE; req.pipelining = FALSE;