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 11:56:18 -0700

Hi,

Thanks very much.
I will give this feedback to my manager.

Sonia.

-----Original Message-----
From: curl-library-bounces_at_cool.haxx.se
[mailto:curl-library-bounces_at_cool.haxx.se] On Behalf Of Tom Donnelly
Sent: Monday, April 23, 2007 11:16 AM
To: libcurl development
Subject: RE: CURL loops infinitely when cable is pulled out.

Sonia - I realise it's not your fault, but your company is acting like a
parasite if it thinks it can make a living out of charging for software,
yet exploit the goodwill of others for free while giving nothing back.

Tom

-----Original Message-----
From: curl-library-bounces_at_cool.haxx.se
[mailto:curl-library-bounces_at_cool.haxx.se] On Behalf Of Sonia
Subramanian
Sent: 23 April 2007 18:59
To: libcurl development; libcurl development
Cc: Charlotte Chang; Robert Spath; Shalu Jain
Subject: RE: CURL loops infinitely when cable is pulled out.

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