cURL / Mailing Lists / curl-library / Single Mail

curl-library

RE: CURL loops infinitely when cable is pulled out.

From: Sonia Subramanian <sonia_subramanian_at_symantec.com>
Date: Mon, 23 Apr 2007 10:58:56 -0700

Hi Daniel,
 
My apologies if that is the way I came accross. I thought I removed the quotes.
 
The company has this policy accross the board and
requesting for an exception is very time consuming and the management has not managed to get that yet.
I had requested permission to submit the WinCE patch like you requested but I think this has been turned down.
What I did was emailed my WinCE patch to whoever requested for it directly about half a dozen times. Though this is not allowed either -it has been overlooked given the circumstances.
 
But anyways putting that aside for a bit I personally would like to share what I found.
 
1. If the cable is pulled put CUrl does return CURL Partial file.
2. The program detects this and exits normally. This information is stored.
3. In the next session a new CURL object is created and it does a bunch of other things (like head requests) before actually requesting for the object.
4. It looks at the file information and and if the info says partial it sets the CURL resume from, from that byte.
5. This worked well in the previous version that I used. (7.15.4).
6. In the new version, in this scenario I got http 416.
I then stepped thru the code and in CreateConnection in url.c I made the following change
the
< indicates what was removed and
> is what was added.
 
After the range is set in the following lines ConnectionExists is called and reuse comes back as false.
In this case all the data in reqdata ( not is set_data) is wiped out. When I stepped in I think it gets wiped out in Curl_Disconnect that is called from ConnectionExists.
 
Whether we have a new object or not, I think we have to be able to set the range parameter correctly and get only the bytes we request for.
 
#ifndef CURL_DISABLE_HTTP

/************************************************************

* RESUME on a HTTP page is a tricky business. First, let's just check that

* 'range' isn't used, then set the range parameter and leave the resume as

* it is to inform about this situation for later use. We will then

* "attempt" to resume, and if we're talking to a HTTP/1.1 (or later)

* server, we will get the document resumed. If we talk to a HTTP/1.0

* server, we just fail since we can't rewind the file writing from within

* this function.

***********************************************************/

if(data->reqdata.resume_from) {

if(!data->reqdata.use_range) {

/* if it already was in use, we just skip this */

data->reqdata.range = aprintf("%" FORMAT_OFF_T "-", data->reqdata.resume_from);

if(!data->reqdata.range)

return CURLE_OUT_OF_MEMORY;

data->reqdata.rangestringalloc = TRUE; /* mark as allocated */

data->reqdata.use_range = 1; /* switch on range usage */

}

}

#endif

/*************************************************************

* Check the current list of connections to see if we can

* re-use an already existing one or if we have to create a

* new one.

*************************************************************/

/* get a cloned copy of the SSL config situation stored in the

connection struct */

if(!Curl_clone_ssl_config(&data->set.ssl, &conn->ssl_config))

return CURLE_OUT_OF_MEMORY;

/* reuse_fresh is TRUE if we are told to use a new connection by force, but

we only acknowledge this option if this is not a re-used connection

already (which happens due to follow-location or during a HTTP

authentication phase). */

if(data->set.reuse_fresh && !data->state.this_is_a_follow)

reuse = FALSE;

else

reuse = ConnectionExists(data, conn, &conn_temp);

if(reuse) {

/*

* We already have a connection for this, we got the former connection

* in the conn_temp variable and thus we need to cleanup the one we

* just allocated before we can move along and use the previously

* existing one.

*/

struct connectdata *old_conn = conn;

if(old_conn->proxy.rawalloc)

free(old_conn->proxy.rawalloc);

/* free the SSL config struct from this connection struct as this was

allocated in vain and is targeted for destruction */

Curl_free_ssl_config(&conn->ssl_config);

conn = conn_temp; /* use this connection from now on */

conn->data = old_conn->data;

/* get the user+password information from the old_conn struct since it may

* be new for this request even when we re-use an existing connection */

conn->bits.user_passwd = old_conn->bits.user_passwd;

if (conn->bits.user_passwd) {

/* use the new user namd and password though */

Curl_safefree(conn->user);

Curl_safefree(conn->passwd);

conn->user = old_conn->user;

conn->passwd = old_conn->passwd;

old_conn->user = NULL;

old_conn->passwd = NULL;

}

conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd;

if (conn->bits.proxy_user_passwd) {

/* use the new proxy user name and proxy password though */

Curl_safefree(conn->proxyuser);

Curl_safefree(conn->proxypasswd);

conn->proxyuser = old_conn->proxyuser;

conn->proxypasswd = old_conn->proxypasswd;

old_conn->proxyuser = NULL;

old_conn->proxypasswd = NULL;

}

/* host can change, when doing keepalive with a proxy ! */

if (conn->bits.proxy) {

free(conn->host.rawalloc);

conn->host=old_conn->host;

}

else

free(old_conn->host.rawalloc); /* free the newly allocated name buffer */

/* get the newly set value, not the old one */

conn->bits.no_body = old_conn->bits.no_body;

/* re-use init */

conn->bits.reuse = TRUE; /* yes, we're re-using here */

Curl_safefree(old_conn->user);

Curl_safefree(old_conn->passwd);

Curl_safefree(old_conn->proxyuser);

Curl_safefree(old_conn->proxypasswd);

Curl_llist_destroy(old_conn->send_pipe, NULL);

Curl_llist_destroy(old_conn->recv_pipe, NULL);

free(old_conn); /* we don't need this anymore */

/*

* If we're doing a resumed transfer, we need to setup our stuff

* properly.

*/

data->reqdata.resume_from = data->set.set_resume_from;

if (data->reqdata.resume_from) {

if (data->reqdata.rangestringalloc == TRUE)

free(data->reqdata.range);

data->reqdata.range = aprintf("%" FORMAT_OFF_T "-",

data->reqdata.resume_from);

if(!data->reqdata.range)

return CURLE_OUT_OF_MEMORY;

/* tell ourselves to fetch this range */

data->reqdata.use_range = TRUE; /* enable range download */

data->reqdata.rangestringalloc = TRUE; /* mark range string allocated */

}

else if (data->set.set_range) {

/* There is a range, but is not a resume, useful for random ftp access */

data->reqdata.range = strdup(data->set.set_range);

if(!data->reqdata.range)

return CURLE_OUT_OF_MEMORY;

data->reqdata.rangestringalloc = TRUE; /* mark range string allocated */

data->reqdata.use_range = TRUE; /* enable range download */

}

else

data->reqdata.use_range = FALSE; /* disable range download */

*in_connect = conn; /* return this instead! */

infof(data, "Re-using existing connection! (#%ld) with host %s\n",

conn->connectindex,

conn->proxy.name?conn->proxy.dispname:conn->host.dispname);

}

else {

/*

* This is a brand new connection, so let's store it in the connection

* cache of ours!

*/

< ConnectionStore(data, conn);

-> //Fix ssubrama - we have probably called Curl Disconnect

-> //Reset the entire resume from structure - to be safe.

-> data->reqdata.resume_from = data->set.set_resume_from;

-> if (data->reqdata.resume_from) {

-> if (data->reqdata.rangestringalloc == TRUE)

-> free(data->reqdata.range);

-> data->reqdata.range = aprintf("%" FORMAT_OFF_T "-",

-> data->reqdata.resume_from);

-> if(!data->reqdata.range)

-> return CURLE_OUT_OF_MEMORY;

->

-> /* tell ourselves to fetch this range */

-> data->reqdata.use_range = TRUE; /* enable range download */

-> data->reqdata.rangestringalloc = TRUE; /* mark range string allocated */

-> }

-> else if (data->set.set_range) {

-> /* There is a range, but is not a resume, useful for random ftp access */

-> data->reqdata.range = strdup(data->set.set_range);

-> if(!data->reqdata.range)

-> return CURLE_OUT_OF_MEMORY;

-> data->reqdata.rangestringalloc = TRUE; /* mark range string allocated */

-> data->reqdata.use_range = TRUE; /* enable range download */

-> }

-> else

-> data->reqdata.use_range = FALSE; /* disable range download */

-> ConnectionStore(data, conn);

}

/* Continue connectdata initialization here. */

/*

*

Thanks,
Sonia.
 
 
Received on 2007-04-23