Newer
Older
else {
/* Set default host and default path */
strcpy(conn->path, "/");
if (2 > sscanf(data->url,
conn->protostr, conn->gname, conn->path)) {
/*
* The URL was badly formatted, let's try the browser-style _without_
* protocol specified like 'http://'.
*/
if((1 > sscanf(data->url, "%256[^\n/]%[^\n]",
/*
* We couldn't even get this format.
*/
failf(data, "<url> malformed");
return CURLE_URL_MALFORMAT;
}
/*
* Since there was no protocol part specified, we guess what protocol it
* is based on the first letters of the server name.
*/
if(strnequal(conn->gname, "FTP", 3)) {
strcpy(conn->protostr, "ftp");
}
else if(strnequal(conn->gname, "GOPHER", 6))
strcpy(conn->protostr, "gopher");
else if(strnequal(conn->gname, "HTTPS", 5))
strcpy(conn->protostr, "https");
else if(strnequal(conn->gname, "TELNET", 6))
strcpy(conn->protostr, "telnet");
else if (strnequal(conn->gname, "DICT", sizeof("DICT")-1))
strcpy(conn->protostr, "DICT");
else if (strnequal(conn->gname, "LDAP", sizeof("LDAP")-1))
strcpy(conn->protostr, "LDAP");
strcpy(conn->protostr, "http");
}
conn->protocol |= PROT_MISSING; /* not given in URL */
}
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
buf = data->buffer; /* this is our buffer */
/*************************************************************
* Set signal handler
*************************************************************/
#ifdef HAVE_SIGACTION
sigaction(SIGALRM, NULL, &sigact);
sigact.sa_handler = alarmfunc;
#ifdef SA_RESTART
/* HPUX doesn't have SA_RESTART but defaults to that behaviour! */
sigact.sa_flags &= ~SA_RESTART;
#endif
sigaction(SIGALRM, &sigact, NULL);
#else
/* no sigaction(), revert to the much lamer signal() */
#ifdef HAVE_SIGNAL
signal(SIGALRM, alarmfunc);
#endif
#endif
/*************************************************************
* Take care of user and password authentication stuff
*************************************************************/
if(data->bits.user_passwd && !data->bits.use_netrc) {
data->user[0] =0;
data->passwd[0]=0;
if(*data->userpwd != ':') {
/* the name is given, get user+password */
sscanf(data->userpwd, "%127[^:]:%127[^\n]",
else
/* no name given, get the password only */
sscanf(data->userpwd+1, "%127[^\n]", data->passwd);
/* check for password, if no ask for one */
if( !data->passwd[0] ) {
if(!data->fpasswd ||
data->fpasswd(data->passwd_client,
"password:", data->passwd, sizeof(data->passwd)))
return CURLE_BAD_PASSWORD_ENTERED;
/*************************************************************
* Take care of proxy authentication stuff
*************************************************************/
data->proxyuser[0] =0;
data->proxypasswd[0]=0;
if(*data->proxyuserpwd != ':') {
/* the name is given, get user+password */
sscanf(data->proxyuserpwd, "%127[^:]:%127[^\n]",
data->proxyuser, data->proxypasswd);
else
/* no name given, get the password only */
sscanf(data->proxyuserpwd+1, "%127[^\n]", data->proxypasswd);
/* check for password, if no ask for one */
if( !data->proxypasswd[0] ) {
if(!data->fpasswd ||
data->fpasswd( data->passwd_client,
"proxy password:",
data->proxypasswd,
sizeof(data->proxypasswd)))
return CURLE_BAD_PASSWORD_ENTERED;
/*************************************************************
* Set a few convenience pointers
*************************************************************/
conn->name = conn->gname;
conn->ppath = conn->path;
conn->hostname = conn->name;
/*************************************************************
* Detect what (if any) proxy to use
*************************************************************/
/* If proxy was not specified, we check for default proxy environment
* variables, to enable i.e Lynx compliance:
*
* http_proxy=http://some.server.dom:port/
* https_proxy=http://some.server.dom:port/
* ftp_proxy=http://some.server.dom:port/
* gopher_proxy=http://some.server.dom:port/
* no_proxy=domain1.dom,host.domain2.dom
* (a comma-separated list of hosts which should
* not be proxied, or an asterisk to override
* all proxy variables)
* all_proxy=http://some.server.dom:port/
* (seems to exist for the CERN www lib. Probably
* the first to check for.)
*
* For compatibility, the all-uppercase versions of these variables are
* checked if the lowercase versions don't exist.
*/
char *no_proxy=NULL;
no_proxy=curl_getenv("no_proxy");
if(!no_proxy)
no_proxy=curl_getenv("NO_PROXY");
if(!no_proxy || !strequal("*", no_proxy)) {
/* NO_PROXY wasn't specified or it wasn't just an asterisk */
char *nope;
nope=no_proxy?strtok(no_proxy, ", "):NULL;
while(nope) {
if(strlen(nope) <= strlen(conn->name)) {
conn->name + strlen(conn->name) - strlen(nope);
if(strnequal(nope, checkn, strlen(nope))) {
/* no proxy for this host! */
break;
}
}
nope=strtok(NULL, ", ");
}
if(!nope) {
/* It was not listed as without proxy */
char *protop = conn->protostr;
/* Now, build <protocol>_proxy and check for such a one to use */
while(*protop)
*envp++ = tolower(*protop++);
/* append _proxy */
strcpy(envp, "_proxy");
prox=curl_getenv(proxy_env);
if(!prox) {
/* There was no lowercase variable, try the uppercase version: */
for(envp = proxy_env; *envp; envp++)
*envp = toupper(*envp);
prox=curl_getenv(proxy_env);
if(prox && *prox) { /* don't count "" strings */
proxy = prox; /* use this */
}
else {
proxy = curl_getenv("all_proxy"); /* default proxy to use */
proxy=curl_getenv("ALL_PROXY");
if(proxy && *proxy) {
/* we have a proxy here to set */
data->proxy = proxy;
data->bits.proxystringalloc=1; /* this needs to be freed later */
} /* if (!nope) - it wasn't specified non-proxy */
if(no_proxy)
free(no_proxy);
/*************************************************************
* No protocol but proxy usage needs attention
*************************************************************/
if((conn->protocol&PROT_MISSING) && data->bits.httpproxy ) {
/* We're guessing prefixes here and since we're told to use a proxy, we
need to add the protocol prefix to the URL string before we continue!
*/
char *reurl;
reurl = aprintf("%s://%s", conn->protostr, data->url);
data->url = reurl;
if(data->freethis)
free(data->freethis);
data->freethis = reurl;
conn->protocol &= ~PROT_MISSING; /* switch that one off again */
/************************************************************
* 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.
***********************************************************/
snprintf(resumerange, sizeof(resumerange), "%d-", data->resume_from);
data->range=strdup(resumerange); /* tell ourselves to fetch this range */
data->bits.rangestringalloc = TRUE; /* mark as allocated */
data->bits.set_range = 1; /* switch on range usage */
/*************************************************************
* Set timeout if that is being used
*************************************************************/
if(data->timeout) {
/* We set the timeout on the connection/resolving phase first, separately
* from the download/upload part to allow a maximum time on everything */
myalarm(data->timeout); /* this sends a signal when the timeout fires
off, and that will abort system calls */
}
/*************************************************************
* Setup internals depending on protocol
*************************************************************/
if (strequal(conn->protostr, "HTTP")) {
if(!data->port)
data->port = PORT_HTTP;
data->remote_port = PORT_HTTP;
conn->curl_do = Curl_http;
conn->curl_done = Curl_http_done;
conn->curl_close = Curl_http_close;
else if (strequal(conn->protostr, "HTTPS")) {
#ifdef USE_SSLEAY
if(!data->port)
data->port = PORT_HTTPS;
data->remote_port = PORT_HTTPS;
conn->protocol |= PROT_HTTP;
conn->protocol |= PROT_HTTPS;
conn->curl_do = Curl_http;
conn->curl_done = Curl_http_done;
conn->curl_connect = Curl_http_connect;
conn->curl_close = Curl_http_close;
failf(data, "libcurl was built with SSL disabled, https: not supported!");
else if (strequal(conn->protostr, "GOPHER")) {
if(!data->port)
data->port = PORT_GOPHER;
data->remote_port = PORT_GOPHER;
/* Skip /<item-type>/ in path if present */
if (isdigit((int)conn->path[1])) {
conn->ppath = strchr(&conn->path[1], '/');
if (conn->ppath == NULL)
conn->ppath = conn->path;
conn->curl_do = Curl_http;
conn->curl_done = Curl_http_done;
conn->curl_close = Curl_http_close;
else if(strequal(conn->protostr, "FTP")) {
char *type;
if(!data->port)
data->port = PORT_FTP;
data->remote_port = PORT_FTP;
if(data->bits.httpproxy &&
!data->bits.tunnel_thru_httpproxy) {
/* Unless we have asked to tunnel ftp operations through the proxy, we
switch and use HTTP operations only */
conn->curl_do = Curl_http;
conn->curl_done = Curl_http_done;
conn->curl_close = Curl_http_close;
conn->curl_do = Curl_ftp;
conn->curl_done = Curl_ftp_done;
conn->curl_connect = Curl_ftp_connect;
}
conn->ppath++; /* don't include the initial slash */
/* FTP URLs support an extension like ";type=<typecode>" that
type=strstr(conn->ppath, ";type=");
type=strstr(conn->gname, ";type=");
}
if(type) {
char command;
*type=0;
command = toupper(type[6]);
switch(command) {
case 'A': /* ASCII mode */
break;
case 'I': /* binary mode */
default:
/* switch off ASCII */
else if(strequal(conn->protostr, "TELNET")) {
if(!data->port)
data->port = PORT_TELNET;
data->remote_port = PORT_TELNET;
conn->curl_do = Curl_telnet;
conn->curl_done = Curl_telnet_done;
else if (strequal(conn->protostr, "DICT")) {
if(!data->port)
data->port = PORT_DICT;
data->remote_port = PORT_DICT;
conn->curl_do = Curl_dict;
conn->curl_done = Curl_dict_done;
else if (strequal(conn->protostr, "LDAP")) {
if(!data->port)
data->port = PORT_LDAP;
data->remote_port = PORT_LDAP;
conn->curl_do = Curl_ldap;
conn->curl_done = Curl_ldap_done;
else if (strequal(conn->protostr, "FILE")) {
conn->curl_do = file;
/* no done() function */
Daniel Stenberg
committed
result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */
-1, NULL); /* no upload */
return CURLE_OK;
/* We fell through all checks and thus we don't support the specified
protocol */
failf(data, "Unsupported protocol: %s", conn->protostr);
/*************************************************************
* .netrc scanning coming up
*************************************************************/
if(Curl_parsenetrc(conn->hostname, data->user, data->passwd)) {
infof(data, "Couldn't find host %s in the .netrc file, using defaults",
Daniel Stenberg
committed
else
data->bits.user_passwd = 1; /* enable user+password */
/* weather we failed or not, we don't know which fields that were filled
in anyway */
if(!data->user[0])
strcpy(data->user, CURL_DEFAULT_USER);
if(!data->passwd[0])
strcpy(data->passwd, CURL_DEFAULT_PASSWORD);
}
else if(!(data->bits.user_passwd) &&
(conn->protocol & (PROT_FTP|PROT_HTTP)) ) {
/* This is a FTP or HTTP URL, and we haven't got the user+password in
* the extra parameter, we will now try to extract the possible
* user+password pair in a string like:
* ftp://user:password@ftp.my.site:8021/README */
char *ptr=NULL; /* assign to remove possible warnings */
if((ptr=strchr(conn->name, '@'))) {
/* there's a user+password given here, to the left of the @ */
data->user[0] =0;
data->passwd[0]=0;
if(*conn->name != ':') {
/* the name is given, get user+password */
sscanf(conn->name, "%127[^:@]:%127[^@]",
data->user, data->passwd);
}
else
/* no name given, get the password only */
sscanf(conn->name+1, "%127[^@]", data->passwd);
if(data->user[0]) {
char *newname=curl_unescape(data->user, 0);
if(strlen(newname) < sizeof(data->user)) {
strcpy(data->user, newname);
}
/* if the new name is longer than accepted, then just use
the unconverted name, it'll be wrong but what the heck */
free(newname);
}
/* check for password, if no ask for one */
if( !data->passwd[0] ) {
if(!data->fpasswd ||
data->fpasswd(data->passwd_client,
"password:",data->passwd,sizeof(data->passwd)))
return CURLE_BAD_PASSWORD_ENTERED;
else {
/* we have a password found in the URL, decode it! */
char *newpasswd=curl_unescape(data->passwd, 0);
if(strlen(newpasswd) < sizeof(data->passwd)) {
strcpy(data->passwd, newpasswd);
}
free(newpasswd);
}
conn->name = ++ptr;
data->bits.user_passwd=1; /* enable user+password */
}
else {
strcpy(data->user, CURL_DEFAULT_USER);
strcpy(data->passwd, CURL_DEFAULT_PASSWORD);
}
}
/*************************************************************
* Figure out the remote port number
*
* No matter if we use a proxy or not, we have to figure out the remote
* port number of various reasons.
*
* To be able to detect port number flawlessly, we must not confuse them
* IPv6-specified addresses in the [0::1] style.
*************************************************************/
Daniel Stenberg
committed
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
if((1 == sscanf(conn->name, "[%*39[0-9a-fA-F:]%c", &endbracket)) &&
(']' == endbracket)) {
/* this is a IPv6-style specified IP-address */
#ifndef ENABLE_IPV6
failf(data, "You haven't enabled IPv6 support");
return CURLE_URL_MALFORMAT;
#else
tmp = strchr(conn->name, ']');
tmp++; /* pass the ending bracket */
if(':' != *tmp)
tmp = NULL; /* no port number available */
#endif
}
else {
/* traditional IPv4-style port-extracting */
tmp = strchr(conn->name, ':');
}
if (tmp) {
*tmp++ = '\0'; /* cut off the name there */
data->remote_port = atoi(tmp);
}
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
/* copy the port-specifics to the connection struct */
conn->port = data->port;
conn->remote_port = data->remote_port;
/*************************************************************
* 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.
*************************************************************/
if(ConnectionExists(data, conn, &conn_temp)) {
/*
* 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.
*/
char *path = conn->path; /* setup the current path pointer properly */
free(conn); /* we don't need this new one */
conn = conn_temp; /* use this connection from now on */
free(conn->path); /* free the previous path pointer */
conn->path = path; /* use this one */
conn->ppath = path; /* set this too */
}
else {
/*
* This is a brand new connection, so let's store it in the connection
* cache of ours!
*/
ConnectionStore(data, conn);
}
*in_connect = conn;
/*************************************************************
* Resolve the name of the server or proxy
*************************************************************/
/* If not connecting via a proxy, extract the port from the URL, if it is
* there, thus overriding any defaults that might have been set above. */
Daniel Stenberg
committed
data->port = data->remote_port; /* it is the same port */
/* Resolve target host right on */
if(!conn->res)
/* it might already be set if reusing a connection */
conn->res = Curl_getaddrinfo(data, conn->name, data->port);
if(!conn->res)
#else
if(!conn->hp)
/* it might already be set if reusing a connection */
conn->hp = Curl_gethost(data, conn->name, &conn->hostent_buf);
if(!conn->hp)
#endif
{
failf(data, "Couldn't resolve host '%s'", conn->name);
else if(!conn->hp) {
/* This is a proxy that hasn't been resolved yet. It may be resolved
if we're reusing an existing connection. */
#ifdef ENABLE_IPV6
failf(data, "proxy yet to be supported");
return CURLE_OUT_OF_MEMORY;
#else
Daniel Stenberg
committed
/* We need to make a duplicate of the proxy so that we can modify the
string safely. */
char *proxydup=strdup(data->proxy);
/* We use 'proxyptr' to point to the proxy name from now on... */
char *proxyptr=proxydup;
if(NULL == proxydup) {
failf(data, "memory shortage");
Daniel Stenberg
committed
}
/* Daniel Dec 10, 1998:
We do the proxy host string parsing here. We want the host name and the
port name. Accept a protocol:// prefix, even though it should just be
ignored. */
/* 1. skip the protocol part if present */
Daniel Stenberg
committed
endofprot=strstr(proxyptr, "://");
Daniel Stenberg
committed
proxyptr = endofprot+3;
}
/* allow user to specify proxy.server.com:1080 if desired */
Daniel Stenberg
committed
prox_portno = strchr (proxyptr, ':');
if (prox_portno) {
*prox_portno = 0x0; /* cut off number from host name */
prox_portno ++;
/* now set the local port number */
data->port = atoi(prox_portno);
}
else if(data->proxyport) {
/* None given in the proxy string, then get the default one if it is
given */
data->port = data->proxyport;
}
conn->hp = Curl_gethost(data, proxyptr, &conn->hostent_buf);
failf(data, "Couldn't resolve proxy '%s'", proxyptr);
return CURLE_COULDNT_RESOLVE_PROXY;
Daniel Stenberg
committed
free(proxydup); /* free the duplicate pointer and not the modified */
Curl_pgrsTime(data, TIMER_NAMELOOKUP);
if(-1 == conn->firstsocket) {
/* Connect only if not already connected! */
result = ConnectPlease(data, conn);
if(CURLE_OK != result)
return result;
/*************************************************************
* Proxy authentication
*************************************************************/
snprintf(data->buffer, BUFSIZE, "%s:%s",
data->proxyuser, data->proxypasswd);
if(Curl_base64_encode(data->buffer, strlen(data->buffer),
&authorization) >= 0) {
aprintf("Proxy-authorization: Basic %s\015\012", authorization);
/*************************************************************
* Send user-agent to HTTP proxies even if the target protocol
* isn't HTTP.
*************************************************************/
if((conn->protocol&PROT_HTTP) || data->bits.httpproxy) {
data->ptr_uagent =
aprintf("User-Agent: %s\015\012", data->useragent);
Daniel Stenberg
committed
/* is there a connect() procedure? */
/* 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();
/* Call the protocol-specific connect function */
if(result != CURLE_OK)
return result; /* pass back errors */
Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected */
conn->now = Curl_tvnow(); /* time this *after* the connect is done */
/* Figure out the ip-number and display the first host name it shows: */
#ifdef ENABLE_IPV6
{
char hbuf[NI_MAXHOST];
#ifdef NI_WITHSCOPEID
const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
#else
const int niflags = NI_NUMERICHOST;
#endif
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf), NULL, 0,
niflags)) {
snprintf(hbuf, sizeof(hbuf), "?");
}
if (ai->ai_canonname) {
infof(data, "Connected to %s (%s)\n", ai->ai_canonname, hbuf);
} else {
infof(data, "Connected to %s\n", hbuf);
}
}
#else
(void) memcpy(&in.s_addr, *conn->hp->h_addr_list, sizeof (in.s_addr));
infof(data, "Connected to %s (%s)\n", conn->hp->h_name, inet_ntoa(in));
#ifdef __EMX__
/* 20000330 mgs
* the 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). */
if ((data->out)->_handle == NULL) {
_fsetmode(stdout, "b");
}
#endif
CURLcode curl_connect(CURL *curl, CURLconnect **in_connect)
{
CURLcode code;
struct connectdata *conn;
/* call the stuff that needs to be called */
code = _connect(curl, in_connect);
if(CURLE_OK != code) {
/* We're not allowed to return failure with memory left allocated
in the connectdata struct, free those here */
conn = (struct connectdata *)*in_connect;
if(conn) {
#ifdef ENABLE_IPV6
if(conn->res)
freeaddrinfo(conn->res);
#else
if(conn->hostent_buf)
free(conn->hostent_buf);
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
free(conn);
*in_connect=NULL;
}
}
return code;
}
/*
* NAME curl_connect()
*
* DESCRIPTION
*
* Connects to the peer server and performs the initial setup. This function
* writes a connect handle to its second argument that is a unique handle for
* this connect. This allows multiple connects from the same handle returned
* by curl_open().
*
* EXAMPLE
*
* CURLCode result;
* CURL curl;
* CURLconnect connect;
* result = curl_connect(curl, &connect);
*/
CURLcode curl_done(CURLconnect *c_connect)
{
struct connectdata *conn = c_connect;
struct UrlData *data;
CURLcode result;
if(!conn || (conn->handle!= STRUCT_CONNECT)) {
return CURLE_BAD_FUNCTION_ARGUMENT;
if(conn->state != CONN_DO) {
/* This can only be called after a curl_do() */
return CURLE_BAD_CALLING_ORDER;
data = conn->data;
/* this calls the protocol-specific function pointer previously set */
if(conn->curl_done)
result = conn->curl_done(conn);
else
result = CURLE_OK;
Curl_pgrsDone(data); /* done with the operation */
/* if bits.close is TRUE, it means that the connection should be closed
in spite of all our efforts to be nice */
if((CURLE_OK == result) && conn->bits.close) {
index = conn->connectindex; /* get the index */
result = curl_disconnect(conn); /* close the connection */
data->connects[index]=NULL; /* clear the pointer */
}
return result;
}
CURLcode curl_do(CURLconnect *in_conn)
{
struct connectdata *conn = in_conn;
CURLcode result;
if(!conn || (conn->handle!= STRUCT_CONNECT)) {
return CURLE_BAD_FUNCTION_ARGUMENT;
switch(conn->state) {
case CONN_INIT:
case CONN_DONE:
/* these two states are OK */
break;
default:
/* anything else is bad */
if(conn->curl_do) {
/* generic protocol-specific function pointer set in curl_connect() */
result = conn->curl_do(conn);
if(result) {
conn->state = CONN_ERROR;
conn->state = CONN_DO; /* we have entered this state */
return CURLE_OK;