Newer
Older
*protocol_done = FALSE; /* default to not done */
Daniel Stenberg
committed
/* set proxy_connect_closed to false unconditionally already here since it
is used strictly to provide extra information to a parent function in the
case of proxy CONNECT failures and we must make sure we don't have it
lingering set from a previous invoke */
conn->bits.proxy_connect_closed = FALSE;
Daniel Stenberg
committed
/*
* Set user-agent. Used for HTTP, but since we can attempt to tunnel
* basically anything through a http proxy we can't limit this based on
* protocol.
*/
if(data->set.str[STRING_USERAGENT]) {
Daniel Stenberg
committed
Curl_safefree(conn->allocptr.uagent);
conn->allocptr.uagent =
Daniel Stenberg
committed
aprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]);
Daniel Stenberg
committed
if(!conn->allocptr.uagent)
return CURLE_OUT_OF_MEMORY;
Daniel Stenberg
committed
data->req.headerbytecount = 0;
Daniel Stenberg
committed
#ifdef CURL_DO_LINEEND_CONV
data->state.crlf_conversions = 0; /* reset CRLF conversion counter */
#endif /* CURL_DO_LINEEND_CONV */
/* set start time here for timeout purposes in the connect procedure, it
is later set again for the progress meter purpose */
conn->now = Curl_tvnow();
if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) {
conn->bits.tcpconnect[FIRSTSOCKET] = FALSE;
result = Curl_connecthost(conn, conn->dns_entry);
Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */
conn->bits.tcpconnect[FIRSTSOCKET] = TRUE;
*protocol_done = TRUE;
Curl_updateconninfo(conn, conn->sock[FIRSTSOCKET]);
Curl_verboseconnect(conn);
Daniel Stenberg
committed
conn->now = Curl_tvnow(); /* time this *after* the connect is done, we
set this here perhaps a second time */
/*
* This check is quite a hack. We're calling _fsetmode to fix the problem
* with fwrite converting newline characters (you get mangled text files,
* and corrupted binary files when you download to stdout and redirect it to
* a file).
*/
Daniel Stenberg
committed
if((data->set.out)->_handle == NULL) {
_fsetmode(stdout, "b");
}
#endif
return result;
Daniel Stenberg
committed
CURLcode Curl_connect(struct SessionHandle *data,
Daniel Stenberg
committed
struct connectdata **in_connect,
bool *asyncp,
bool *protocol_done)
Daniel Stenberg
committed
*asyncp = FALSE; /* assume synchronous resolves by default */
/* call the stuff that needs to be called */
result = create_conn(data, in_connect, asyncp);
Daniel Stenberg
committed
Daniel Stenberg
committed
/* no error */
if((*in_connect)->send_pipe->size || (*in_connect)->recv_pipe->size)
Daniel Stenberg
committed
/* pipelining */
*protocol_done = TRUE;
else if(!*asyncp) {
Daniel Stenberg
committed
/* DNS resolution is done: that's either because this is a reused
connection, in which case DNS was unnecessary, or because DNS
really did finish already (synch resolver/fast async resolve) */
result = Curl_setup_conn(*in_connect, protocol_done);
Daniel Stenberg
committed
}
Daniel Stenberg
committed
}
if(result == CURLE_NO_CONNECTION_AVAILABLE) {
*in_connect = NULL;
if(result && *in_connect) {
/* We're not allowed to return failure with memory left allocated
in the connectdata struct, free those here */
Curl_disconnect(*in_connect, FALSE); /* close the connection */
Daniel Stenberg
committed
*in_connect = NULL; /* return a NULL */
Daniel Stenberg
committed
Daniel Stenberg
committed
CURLcode Curl_done(struct connectdata **connp,
Daniel Stenberg
committed
CURLcode status, /* an error if this is called after an
error was detected */
bool premature)
struct connectdata *conn;
struct SessionHandle *data;
DEBUGASSERT(*connp);
conn = *connp;
data = conn->data;
DEBUGF(infof(data, "Curl_done\n"));
if(data->state.done)
Daniel Stenberg
committed
/* Stop if Curl_done() has already been called */
return CURLE_OK;
Curl_getoff_all_pipelines(data, conn);
/* Cleanup possible redirect junk */
Markus Elfring
committed
free(data->req.newurl);
data->req.newurl = NULL;
free(data->req.location);
data->req.location = NULL;
switch(status) {
case CURLE_ABORTED_BY_CALLBACK:
case CURLE_READ_ERROR:
case CURLE_WRITE_ERROR:
/* When we're aborted due to a callback return code it basically have to
be counted as premature as there is trouble ahead if we don't. We have
many callbacks and protocols work differently, we could potentially do
this more fine-grained in the future. */
premature = TRUE;
default:
break;
}
/* this calls the protocol-specific function pointer previously set */
Patrick Monnerat
committed
if(conn->handler->done)
result = conn->handler->done(conn, status, premature);
if(CURLE_ABORTED_BY_CALLBACK != result) {
/* avoid this if we already aborted by callback to avoid this calling
another callback */
CURLcode rc = Curl_pgrsDone(conn);
if(!result && rc)
result = CURLE_ABORTED_BY_CALLBACK;
}
if((!premature &&
conn->send_pipe->size + conn->recv_pipe->size != 0 &&
!data->set.reuse_forbid &&
!conn->bits.close)) {
/* Stop if pipeline is not empty and we do not have to close
connection. */
DEBUGF(infof(data, "Connection still in use, no more Curl_done now!\n"));
return CURLE_OK;
}
data->state.done = TRUE; /* called just now! */
Curl_resolver_cancel(conn);
if(conn->dns_entry) {
Curl_resolv_unlock(data, conn->dns_entry); /* done with this */
conn->dns_entry = NULL;
}
Daniel Stenberg
committed
/* if the transfer was completed in a paused state there can be buffered
data left to write and then kill */
Markus Elfring
committed
free(data->state.tempwrite);
data->state.tempwrite = NULL;
Daniel Stenberg
committed
Daniel Stenberg
committed
/* if data->set.reuse_forbid is TRUE, it means the libcurl client has
forced us to close this connection. This is ignored for requests taking
place in a NTLM authentication handshake
if conn->bits.close is TRUE, it means that the connection should be
closed in spite of all our efforts to be nice, due to protocol
Daniel Stenberg
committed
restrictions in our or the server's end
if premature is TRUE, it means this connection was said to be DONE before
the entire request operation is complete and thus we can't know in what
state it is for re-using, so we're forced to close it. In a perfect world
we can add code that keep track of if we really must close it here or not,
but currently we have no such detail knowledge.
*/
if((data->set.reuse_forbid
#if defined(USE_NTLM)
&& !(conn->ntlm.state == NTLMSTATE_TYPE2 ||
conn->proxyntlm.state == NTLMSTATE_TYPE2)
#endif
) || conn->bits.close || premature) {
CURLcode res2 = Curl_disconnect(conn, premature); /* close connection */
Daniel Stenberg
committed
/* If we had an error already, make sure we return that one. But
if we got a new error, return that. */
if(!result && res2)
result = res2;
}
Daniel Stenberg
committed
else {
/* the connection is no longer in use */
if(ConnectionDone(data, conn)) {
/* remember the most recently used connection */
data->state.lastconnect = conn;
infof(data, "Connection #%ld to host %s left intact\n",
conn->connection_id,
conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
}
else
data->state.lastconnect = NULL;
Daniel Stenberg
committed
}
*connp = NULL; /* to make the caller of this function better detect that
this was either closed or handed over to the connection
cache here, and therefore cannot be used from this point on
*/
Curl_free_request_state(data);
Daniel Stenberg
committed
/*
* Curl_init_do() 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 dynamically for the
* transfer.
*
* Allow this function to get called with 'conn' set to NULL.
Daniel Stenberg
committed
*/
CURLcode Curl_init_do(struct SessionHandle *data, struct connectdata *conn)
Daniel Stenberg
committed
{
Daniel Stenberg
committed
struct SingleRequest *k = &data->req;
Daniel Stenberg
committed
if(conn)
conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to
* use */
data->state.done = FALSE; /* Curl_done() is not called yet */
data->state.expect100header = FALSE;
Daniel Stenberg
committed
Daniel Stenberg
committed
if(data->set.opt_no_body)
/* in HTTP lingo, no body means using the HEAD request... */
data->set.httpreq = HTTPREQ_HEAD;
else if(HTTPREQ_HEAD == data->set.httpreq)
/* ... but if unset there really is no perfect method that is the
"opposite" of HEAD but in reality most people probably think GET
then. The important thing is that we can't let it remain HEAD if the
opt_no_body is set FALSE since then we'll behave wrong when getting
HTTP. */
data->set.httpreq = HTTPREQ_GET;
Daniel Stenberg
committed
k->start = Curl_tvnow(); /* start time */
k->now = k->start; /* current time is now */
k->header = TRUE; /* assume header */
k->bytecount = 0;
k->buf = data->state.buffer;
k->uploadbuf = data->state.uploadbuffer;
k->hbufp = data->state.headerbuff;
k->ignorebody=FALSE;
Curl_speedinit(data);
Curl_pgrsSetUploadCounter(data, 0);
Curl_pgrsSetDownloadCounter(data, 0);
return CURLE_OK;
}
6286
6287
6288
6289
6290
6291
6292
6293
6294
6295
6296
6297
6298
6299
6300
6301
6302
6303
6304
6305
6306
6307
6308
6309
6310
6311
6312
6313
6314
6315
6316
6317
6318
6319
6320
6321
6322
6323
6324
6325
6326
6327
6328
6329
6330
6331
6332
6333
6334
6335
6336
6337
6338
6339
6340
6341
6342
6343
6344
6345
6346
6347
6348
6349
6350
6351
6352
6353
6354
6355
6356
6357
6358
6359
6360
6361
6362
6363
6364
6365
6366
6367
6368
6369
6370
6371
6372
6373
6374
6375
6376
6377
6378
6379
6380
6381
6382
6383
6384
6385
6386
6387
6388
6389
6390
6391
6392
6393
/*
* get_protocol_family()
*
* This is used to return the protocol family for a given protocol.
*
* Parameters:
*
* protocol [in] - A single bit protocol identifier such as HTTP or HTTPS.
*
* Returns the family as a single bit protocol identifier.
*/
unsigned int get_protocol_family(unsigned int protocol)
{
unsigned int family;
switch(protocol) {
case CURLPROTO_HTTP:
case CURLPROTO_HTTPS:
family = CURLPROTO_HTTP;
break;
case CURLPROTO_FTP:
case CURLPROTO_FTPS:
family = CURLPROTO_IMAP;
break;
case CURLPROTO_SCP:
family = CURLPROTO_SCP;
break;
case CURLPROTO_SFTP:
family = CURLPROTO_SFTP;
break;
case CURLPROTO_TELNET:
family = CURLPROTO_TELNET;
break;
case CURLPROTO_LDAP:
case CURLPROTO_LDAPS:
family = CURLPROTO_IMAP;
break;
case CURLPROTO_DICT:
family = CURLPROTO_DICT;
break;
case CURLPROTO_FILE:
family = CURLPROTO_FILE;
break;
case CURLPROTO_TFTP:
family = CURLPROTO_TFTP;
break;
case CURLPROTO_IMAP:
case CURLPROTO_IMAPS:
family = CURLPROTO_IMAP;
break;
case CURLPROTO_POP3:
case CURLPROTO_POP3S:
family = CURLPROTO_POP3;
break;
case CURLPROTO_SMTP:
case CURLPROTO_SMTPS:
family = CURLPROTO_SMTP;
break;
case CURLPROTO_RTSP:
family = CURLPROTO_RTSP;
break;
case CURLPROTO_RTMP:
case CURLPROTO_RTMPS:
family = CURLPROTO_RTMP;
break;
case CURLPROTO_RTMPT:
case CURLPROTO_RTMPTS:
family = CURLPROTO_RTMPT;
break;
case CURLPROTO_RTMPE:
family = CURLPROTO_RTMPE;
break;
case CURLPROTO_RTMPTE:
family = CURLPROTO_RTMPTE;
break;
case CURLPROTO_GOPHER:
family = CURLPROTO_GOPHER;
break;
case CURLPROTO_SMB:
case CURLPROTO_SMBS:
family = CURLPROTO_SMB;
break;
default:
family = 0;
break;
}
return family;