Newer
Older
case CURLOPT_CAPATH:
/*
* Set CA path info for SSL connection. Specify directory name of the CA certificates
* which have been prepared using openssl c_rehash utility.
*/
data->set.ssl.CApath = va_arg(param, char *); /*This does not work on windows.*/
Daniel Stenberg
committed
break;
case CURLOPT_TELNETOPTIONS:
/*
* Set a linked list of telnet options
*/
Daniel Stenberg
committed
data->set.telnet_options = va_arg(param, struct curl_slist *);
case CURLOPT_BUFFERSIZE:
/*
* The application kindly asks for a differently sized receive buffer.
* If it seems reasonable, we'll use it.
*/
data->set.buffer_size = va_arg(param, long);
if(data->set.buffer_size> (BUFSIZE -1 ))
data->set.buffer_size = 0; /* huge internal default */
break;
default:
/* unknown tag and its companion, just ignore: */
return CURLE_FAILED_INIT; /* correct this */
CURLcode Curl_disconnect(struct connectdata *conn)
if(!conn)
return CURLE_OK; /* this is closed and fine already */
/*
* The range string is usually freed in curl_done(), but we might
* get here *instead* if we fail prematurely. Thus we need to be able
* to free this resource here as well.
*/
if(conn->bits.rangestringalloc) {
free(conn->range);
conn->bits.rangestringalloc = FALSE;
}
Daniel Stenberg
committed
/* unlink ourselves! */
Daniel Stenberg
committed
infof(conn->data, "Closing connection #%d\n", conn->connectindex);
Daniel Stenberg
committed
conn->data->state.connects[conn->connectindex] = NULL;
Daniel Stenberg
committed
if(conn->curl_disconnect)
/* This is set if protocol-specific cleanups should be made */
conn->curl_disconnect(conn);
if(conn->proto.generic)
free(conn->proto.generic);
Daniel Stenberg
committed
if(conn->newurl)
free(conn->newurl);
if(conn->path) /* the URL path part */
free(conn->path);
Curl_SSL_Close(conn);
#endif /* USE_SSLEAY */
/* close possibly still open sockets */
if(-1 != conn->secondarysocket)
sclose(conn->secondarysocket);
if(-1 != conn->firstsocket)
sclose(conn->firstsocket);
if(conn->allocptr.proxyuserpwd)
free(conn->allocptr.proxyuserpwd);
if(conn->allocptr.uagent)
free(conn->allocptr.uagent);
if(conn->allocptr.userpwd)
free(conn->allocptr.userpwd);
if(conn->allocptr.rangeline)
free(conn->allocptr.rangeline);
if(conn->allocptr.ref)
free(conn->allocptr.ref);
if(conn->allocptr.cookie)
free(conn->allocptr.cookie);
if(conn->allocptr.host)
free(conn->allocptr.host);
if(conn->proxyhost)
free(conn->proxyhost);
free(conn); /* free all the connection oriented data */
/*
* This function should return TRUE if the socket is to be assumed to
* be dead. Most commonly this happens when the server has closed the
* connection due to inactivity.
*/
Daniel Stenberg
committed
static bool SocketIsDead(int sock)
{
int sval;
bool ret_val = TRUE;
fd_set check_set;
struct timeval to;
FD_ZERO(&check_set);
FD_SET(sock,&check_set);
to.tv_sec = 0;
to.tv_usec = 0;
sval = select(sock + 1, &check_set, 0, 0, &to);
Daniel Stenberg
committed
if(sval == 0)
ret_val = FALSE;
* Given one filled in connection struct (named needle), this function should
* detect if there already is one that have all the significant details
* exactly the same and thus should be used instead.
Daniel Stenberg
committed
ConnectionExists(struct SessionHandle *data,
struct connectdata *needle,
struct connectdata **usethis)
struct connectdata *check;
Daniel Stenberg
committed
for(i=0; i< data->state.numconnects; i++) {
bool match = FALSE;
/*
* Note that if we use a HTTP proxy, we check connections to that
* proxy and not to the actual remote server.
*/
Daniel Stenberg
committed
check = data->state.connects[i];
if(!check)
/* NULL pointer means not filled-in entry */
continue;
if(!needle->bits.httpproxy || needle->protocol&PROT_SSL) {
/* The requested connection does not use a HTTP proxy or it
uses SSL. */
if(!(needle->protocol&PROT_SSL) && check->bits.httpproxy)
/* we don't do SSL but the cached connection has a proxy,
then don't match this */
continue;
if(strequal(needle->protostr, check->protostr) &&
strequal(needle->name, check->name) &&
(needle->remote_port == check->remote_port) ) {
if(strequal(needle->protostr, "FTP")) {
/* This is FTP, verify that we're using the same name and
password as well */
Daniel Stenberg
committed
if(!strequal(needle->data->state.user, check->proto.ftp->user) ||
!strequal(needle->data->state.passwd, check->proto.ftp->passwd)) {
/* one of them was different */
continue;
}
}
match = TRUE;
else { /* The requested needle connection is using a proxy,
is the checked one using the same? */
if(check->bits.httpproxy &&
strequal(needle->proxyhost, check->proxyhost) &&
needle->port == check->port) {
/* This is the same proxy connection, use it! */
match = TRUE;
}
}
if(match) {
bool dead = SocketIsDead(check->firstsocket);
if(dead) {
/*
*/
infof(data, "Connection %d seems to be dead!\n", i);
Curl_disconnect(check); /* disconnect resources */
data->state.connects[i]=NULL; /* nothing here */
/* There's no need to continue searching, because we only store
one connection for each unique set of identifiers */
return FALSE;
*usethis = check;
return TRUE; /* yes, we found one to use! */
}
return FALSE; /* no matching connecting exists */
}
/*
* This function frees/closes a connection in the connection cache. This
* should take the previously set policy into account when deciding which
* of the connections to kill.
*/
static int
Daniel Stenberg
committed
ConnectionKillOne(struct SessionHandle *data)
int highscore=-1;
int connindex=-1;
int score;
CURLcode result;
struct timeval now;
now = Curl_tvnow();
Daniel Stenberg
committed
for(i=0; i< data->state.numconnects; i++) {
conn = data->state.connects[i];
if(!conn)
continue;
/*
* By using the set policy, we score each connection.
*/
Daniel Stenberg
committed
switch(data->set.closepolicy) {
case CURLCLOSEPOLICY_LEAST_RECENTLY_USED:
/*
* Set higher score for the age passed since the connection
* was used.
*/
score = Curl_tvdiff(now, conn->now);
break;
case CURLCLOSEPOLICY_OLDEST:
/*
* Set higher score for the age passed since the connection
* was created.
*/
score = Curl_tvdiff(now, conn->created);
break;
}
if(score > highscore) {
highscore = score;
connindex = i;
}
}
if(connindex >= 0) {
/* the winner gets the honour of being disconnected */
Daniel Stenberg
committed
result = Curl_disconnect(data->state.connects[connindex]);
/* clean the array entry */
Daniel Stenberg
committed
data->state.connects[connindex] = NULL;
}
return connindex; /* return the available index or -1 */
}
/*
* The given input connection struct pointer is to be stored. If the "cache"
* is already full, we must clean out the most suitable using the previously
* set policy.
*
* The given connection should be unique. That must've been checked prior to
* this call.
*/
static unsigned int
Daniel Stenberg
committed
ConnectionStore(struct SessionHandle *data,
struct connectdata *conn)
{
Daniel Stenberg
committed
for(i=0; i< data->state.numconnects; i++) {
if(!data->state.connects[i])
Daniel Stenberg
committed
if(i == data->state.numconnects) {
/* there was no room available, kill one */
i = ConnectionKillOne(data);
infof(data, "Connection (#%d) was killed to make room\n", i);
}
if(-1 != i) {
/* only do this if a true index was returned, if -1 was returned there
is no room in the cache for an unknown reason and we cannot store
this there. */
data->state.connects[i] = conn; /* fill in this */
conn->connectindex = i; /* make the child know where the pointer to this
particular data is stored */
}
static CURLcode ConnectPlease(struct connectdata *conn,
Curl_addrinfo *hostaddr)
/*************************************************************
*************************************************************/
hostaddr,
conn->port,
&conn->firstsocket,
&addr);
if(CURLE_OK == result) {
/* All is cool, then we store the current information from the hostaddr
struct to the serv_addr, as it might be needed later. The address
returned from the function above is crucial here. */
#ifdef ENABLE_IPV6
conn->serv_addr = addr;
#else
memset((char *) &conn->serv_addr, '\0', sizeof(conn->serv_addr));
memcpy((char *)&(conn->serv_addr.sin_addr),
(struct in_addr *)addr, sizeof(struct in_addr));
conn->serv_addr.sin_family = hostaddr->h_addrtype;
conn->serv_addr.sin_port = htons(conn->port);
#endif
}
static void verboseconnect(struct connectdata *conn,
Curl_addrinfo *hostaddr)
Daniel Stenberg
committed
{
#ifdef HAVE_INET_NTOA_R
char ntoa_buf[64];
#endif
struct SessionHandle *data = conn->data;
/* Figure out the ip-number and display the first host name it shows: */
#ifdef ENABLE_IPV6
(void)hostaddr; /* not used in the IPv6 enabled version */
Daniel Stenberg
committed
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
{
char hbuf[NI_MAXHOST];
#ifdef NI_WITHSCOPEID
const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
#else
const int niflags = NI_NUMERICHOST;
#endif
struct addrinfo *ai = conn->serv_addr;
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) port %d\n", ai->ai_canonname, hbuf,
conn->port);
} else {
infof(data, "Connected to %s port %d\n", hbuf, conn->port);
}
}
#else
{
struct in_addr in;
(void) memcpy(&in.s_addr, &conn->serv_addr.sin_addr, sizeof (in.s_addr));
infof(data, "Connected to %s (%s) port %d\n",
hostaddr?hostaddr->h_name:"[re-used]",
Daniel Stenberg
committed
#if defined(HAVE_INET_NTOA_R)
inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf)),
#else
inet_ntoa(in),
#endif
conn->port);
}
#endif
}
static CURLcode CreateConnection(struct SessionHandle *data,
struct connectdata **in_connect)
{
char *tmp;
char *buf;
CURLcode result=CURLE_OK;
char resumerange[40]="";
struct connectdata *conn;
struct connectdata *conn_temp;
int urllen;
Curl_addrinfo *hostaddr;
Daniel Stenberg
committed
#ifdef HAVE_ALARM
unsigned int prev_alarm;
#endif
#ifdef HAVE_SIGACTION
struct sigaction keep_sigact; /* store the old struct here */
bool keep_copysig; /* did copy it? */
#else
#ifdef HAVE_SIGNAL
void *keep_sigact; /* store the old handler here */
#endif
Daniel Stenberg
committed
#endif
/*************************************************************
* Check input data
*************************************************************/
Daniel Stenberg
committed
if(!data->change.url)
return CURLE_URL_MALFORMAT;
/* First, split up the current URL in parts so that we can use the
parts for checking against the already present connections. In order
to not have to modify everything at once, we allocate a temporary
connection data struct and fill in for comparison purposes. */
conn = (struct connectdata *)malloc(sizeof(struct connectdata));
if(!conn) {
*in_connect = NULL; /* clear the pointer */
return CURLE_OUT_OF_MEMORY;
}
/* We must set the return variable as soon as possible, so that our
parent can cleanup any possible allocs we may have done before
any failure */
*in_connect = conn;
/* we have to init the struct */
memset(conn, 0, sizeof(struct connectdata));
/* and we setup a few fields in case we end up actually using this struct */
conn->data = data; /* remember our daddy */
conn->firstsocket = -1; /* no file descriptor */
conn->secondarysocket = -1; /* no file descriptor */
conn->connectindex = -1; /* no index */
Daniel Stenberg
committed
conn->bits.httpproxy = data->change.proxy?TRUE:FALSE; /* proxy-or-not */
conn->bits.use_range = data->set.set_range?TRUE:FALSE; /* range status */
conn->range = data->set.set_range; /* clone the range setting */
conn->resume_from = data->set.set_resume_from; /* inherite resume_from */
/* Default protocol-independent behavior doesn't support persistant
connections, so we set this to force-close. Protocols that support
this need to set this to FALSE in their "curl_do" functions. */
conn->bits.close = TRUE;
Daniel Stenberg
committed
/* inherite initial knowledge from the data struct */
Daniel Stenberg
committed
conn->bits.user_passwd = data->set.userpwd?1:0;
conn->bits.proxy_user_passwd = data->set.proxyuserpwd?1:0;
/* maxdownload must be -1 on init, as 0 is a valid value! */
conn->maxdownload = -1; /* might have been used previously! */
/* Store creation time to help future close decision making */
conn->created = Curl_tvnow();
Daniel Stenberg
committed
/***********************************************************
* We need to allocate memory to store the path in. We get the size of the
* full URL to be sure, and we need to make it at least 256 bytes since
* other parts of the code will rely on this fact
***********************************************************/
Daniel Stenberg
committed
urllen=strlen(data->change.url);
if(urllen < LEAST_PATH_ALLOC)
urllen=LEAST_PATH_ALLOC;
conn->path=(char *)malloc(urllen);
if(NULL == conn->path)
return CURLE_OUT_OF_MEMORY; /* really bad error */
/*************************************************************
* Parse the URL.
*
* We need to parse the url even when using the proxy, because we will need
* the hostname and port in case we are trying to SSL connect through the
* proxy -- and we don't know if we will need to use SSL until we parse the
* url ...
************************************************************/
Daniel Stenberg
committed
if((2 == sscanf(data->change.url, "%64[^:]://%[^\n]",
conn->protostr,
conn->path)) && strequal(conn->protostr, "file")) {
/*
* we deal with file://<host>/<path> differently since it supports no
* hostname other than "localhost" and "127.0.0.1", which is unique among
* the URL protocols specified in RFC 1738
*/
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
if(conn->path[0] != '/') {
/* the URL included a host name, we ignore host names in file:// URLs
as the standards don't define what to do with them */
char *ptr=strchr(conn->path, '/');
if(ptr) {
/* there was a slash present
RFC1738 (section 3.1, page 5) says:
The rest of the locator consists of data specific to the scheme,
and is known as the "url-path". It supplies the details of how the
specified resource can be accessed. Note that the "/" between the
host (or port) and the url-path is NOT part of the url-path.
As most agents use file://localhost/foo to get '/foo' although the
slash preceeding foo is a separator and not a slash for the path,
a URL as file://localhost//foo must be valid as well, to refer to
the same file with an absolute path.
*/
if(ptr[1] && ('/' == ptr[1]))
/* if there was two slashes, we skip the first one as that is then
used truly as a separator */
ptr++;
strcpy(conn->path, ptr);
}
}
strcpy(conn->protostr, "file"); /* store protocol string lowercase */
else {
/* Set default host and default path */
Daniel Stenberg
committed
if (2 > sscanf(data->change.url,
Daniel Stenberg
committed
"%64[^\n:]://%512[^\n/]%[^\n]",
conn->protostr, conn->gname, conn->path)) {
/*
* The URL was badly formatted, let's try the browser-style _without_
* protocol specified like 'http://'.
*/
Daniel Stenberg
committed
if((1 > sscanf(data->change.url, "%512[^\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, "FTPS", 4))
strcpy(conn->protostr, "ftps");
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 */
}
Daniel Stenberg
committed
buf = data->state.buffer; /* this is our buffer */
/*
* So if the URL was A://B/C,
* conn->protostr is A
* conn->gname is B
* conn->path is /C
*/
/*************************************************************
* Take care of proxy authentication stuff
*************************************************************/
Daniel Stenberg
committed
if(conn->bits.proxy_user_passwd) {
Daniel Stenberg
committed
data->state.proxyuser[0] =0;
data->state.proxypasswd[0]=0;
Daniel Stenberg
committed
if(*data->set.proxyuserpwd != ':') {
/* the name is given, get user+password */
Daniel Stenberg
committed
sscanf(data->set.proxyuserpwd, "%127[^:]:%127[^\n]",
data->state.proxyuser, data->state.proxypasswd);
else
/* no name given, get the password only */
Daniel Stenberg
committed
sscanf(data->set.proxyuserpwd+1, "%127[^\n]", data->state.proxypasswd);
/* check for password, if no ask for one */
Daniel Stenberg
committed
if( !data->state.proxypasswd[0] ) {
Daniel Stenberg
committed
if(data->set.fpasswd( data->set.passwd_client,
"proxy password:",
data->state.proxypasswd,
sizeof(data->state.proxypasswd))) {
failf(data, "Bad password from password callback");
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
*************************************************************/
Daniel Stenberg
committed
if(!data->change.proxy) {
/* 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_r(no_proxy, ", ", &no_proxy_tok_buf):NULL;
unsigned int namelen;
Daniel Stenberg
committed
char *endptr = strchr(conn->name, ':');
if(endptr)
namelen=endptr-conn->name;
else
namelen=strlen(conn->name);
if(strlen(nope) <= namelen) {
Daniel Stenberg
committed
conn->name + namelen - strlen(nope);
if(strnequal(nope, checkn, strlen(nope))) {
/* no proxy for this host! */
break;
}
}
nope=strtok_r(NULL, ", ", &no_proxy_tok_buf);
}
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);
Daniel Stenberg
committed
/*
* We don't try the uppercase version of HTTP_PROXY because of
* security reasons:
*
* When curl is used in a webserver application
* environment (cgi or php), this environment variable can
* be controlled by the web server user by setting the
* http header 'Proxy:' to some value.
*
* This can cause 'internal' http/ftp requests to be
* arbitrarily redirected by any external attacker.
*/
if(!prox && !strequal("http_proxy", proxy_env)) {
/* 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 */
Daniel Stenberg
committed
data->change.proxy = proxy;
data->change.proxy_alloc=TRUE; /* this needs to be freed later */
conn->bits.httpproxy = TRUE;
} /* if (!nope) - it wasn't specified non-proxy */
if(no_proxy)
free(no_proxy);
/*************************************************************
Daniel Stenberg
committed
* No protocol part in URL was used, add it!
*************************************************************/
Daniel Stenberg
committed
if(conn->protocol&PROT_MISSING) {
/* We're guessing prefixes here and if we're told to use a proxy or if
we're gonna follow a Location: later or... then we need the protocol
part added so that we have a valid URL. */
Daniel Stenberg
committed
reurl = aprintf("%s://%s", conn->protostr, data->change.url);
Daniel Stenberg
committed
data->change.url = reurl;
data->change.url_alloc = TRUE; /* free this later */
conn->protocol &= ~PROT_MISSING; /* switch that one off again */
#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(conn->resume_from) {
if(!conn->bits.use_range) {
snprintf(resumerange, sizeof(resumerange), "%d-", conn->resume_from);
conn->range=strdup(resumerange); /* tell ourselves to fetch this range */
conn->bits.rangestringalloc = TRUE; /* mark as allocated */
conn->bits.use_range = 1; /* switch on range usage */
#endif
/*************************************************************
* Setup internals depending on protocol
*************************************************************/
if (strequal(conn->protostr, "HTTP")) {
#ifndef CURL_DISABLE_HTTP
conn->port = (data->set.use_port && data->state.allow_port)?
data->set.use_port:PORT_HTTP;
conn->remote_port = PORT_HTTP;
conn->curl_do = Curl_http;
conn->curl_done = Curl_http_done;
conn->curl_connect = Curl_http_connect;
#else
failf(data, LIBCURL_NAME
" was built with HTTP disabled, http: not supported!");
return CURLE_UNSUPPORTED_PROTOCOL;
#endif
else if (strequal(conn->protostr, "HTTPS")) {
#if defined(USE_SSLEAY) && !defined(CURL_DISABLE_HTTP)
conn->port = (data->set.use_port && data->state.allow_port)?
data->set.use_port:PORT_HTTPS;
conn->remote_port = PORT_HTTPS;
conn->protocol |= PROT_HTTP|PROT_HTTPS|PROT_SSL;
conn->curl_do = Curl_http;
conn->curl_done = Curl_http_done;
conn->curl_connect = Curl_http_connect;
failf(data, LIBCURL_NAME
" was built with SSL disabled, https: not supported!");
else if (strequal(conn->protostr, "GOPHER")) {
#ifndef CURL_DISABLE_GOPHER
conn->port = (data->set.use_port && data->state.allow_port)?
data->set.use_port:PORT_GOPHER;
conn->remote_port = PORT_GOPHER;
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;
#else
failf(data, LIBCURL_NAME
" was built with GOPHER disabled, gopher: not supported!");
#endif
else if(strequal(conn->protostr, "FTP") ||
strequal(conn->protostr, "FTPS")) {
/* MN 06/07/02 */
#ifndef CURL_DISABLE_FTP
if(strequal(conn->protostr, "FTPS")) {
#ifdef USE_SSLEAY
conn->protocol |= PROT_FTPS|PROT_SSL;
failf(data, LIBCURL_NAME
" was built with SSL disabled, ftps: not supported!");
return CURLE_UNSUPPORTED_PROTOCOL;
#endif /* !USE_SSLEAY */
}
conn->port = (data->set.use_port && data->state.allow_port)?
data->set.use_port:PORT_FTP;
conn->remote_port = PORT_FTP;
Daniel Stenberg
committed
if(data->change.proxy &&
!data->set.tunnel_thru_httpproxy) {
/* Unless we have asked to tunnel ftp operations through the proxy, we
switch and use HTTP operations only */
if(conn->protocol & PROT_FTPS) {
/* FTPS is a hacked protocol and does not work through your
ordinary http proxy! */
failf(data, "ftps does not work through http proxy!");
return CURLE_UNSUPPORTED_PROTOCOL;
}
#ifndef CURL_DISABLE_HTTP
conn->curl_do = Curl_http;
conn->curl_done = Curl_http_done;
#else
failf(data, "FTP over http proxy requires HTTP support built-in!");
return CURLE_UNSUPPORTED_PROTOCOL;
#endif
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=");
*type=0; /* it was in the middle of the hostname */
command = toupper(type[6]);
switch(command) {
case 'A': /* ASCII mode */
Daniel Stenberg
committed
data->set.ftp_ascii = 1;
Daniel Stenberg
committed
data->set.ftp_list_only = 1;
break;
case 'I': /* binary mode */
default:
/* switch off ASCII */
Daniel Stenberg
committed
data->set.ftp_ascii = 0;
/* MN 06/07/02 */
#else /* CURL_DISABLE_FTP */
failf(data, LIBCURL_NAME
" was built with FTP disabled, ftp/ftps: not supported!");
return CURLE_UNSUPPORTED_PROTOCOL;
#endif
else if(strequal(conn->protostr, "TELNET")) {
#ifndef CURL_DISABLE_TELNET
conn->protocol |= PROT_TELNET;
conn->port = (data->set.use_port && data->state.allow_port)?
data->set.use_port: PORT_TELNET;
conn->remote_port = PORT_TELNET;
conn->curl_do = Curl_telnet;
conn->curl_done = Curl_telnet_done;
#else
failf(data, LIBCURL_NAME
" was built with TELNET disabled!");
#endif
else if (strequal(conn->protostr, "DICT")) {
#ifndef CURL_DISABLE_DICT
conn->port = (data->set.use_port && data->state.allow_port)?
data->set.use_port:PORT_DICT;
conn->remote_port = PORT_DICT;
conn->curl_do = Curl_dict;
conn->curl_done = NULL; /* no DICT-specific done */
#else
failf(data, LIBCURL_NAME
" was built with DICT disabled!");
#endif
else if (strequal(conn->protostr, "LDAP")) {
#ifndef CURL_DISABLE_LDAP
conn->port = (data->set.use_port && data->state.allow_port)?
data->set.use_port:PORT_LDAP;
conn->remote_port = PORT_LDAP;
conn->curl_do = Curl_ldap;
conn->curl_done = NULL; /* no LDAP-specific done */
#else
failf(data, LIBCURL_NAME
" was built with LDAP disabled!");
#endif
else if (strequal(conn->protostr, "FILE")) {
#ifndef CURL_DISABLE_FILE
conn->curl_do = Curl_file;
/* anyway, this is supposed to be the connect function so we better
at least check that the file is present here! */
result = Curl_file_connect(conn);
/* Setup a "faked" transfer that'll do nothing */
if(CURLE_OK == result) {
result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */
-1, NULL); /* no upload */
}
return result;
#else
failf(data, LIBCURL_NAME
" was built with FILE disabled!");
#endif
/* We fell through all checks and thus we don't support the specified
protocol */
failf(data, "Unsupported protocol: %s", conn->protostr);
/*************************************************************
* 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. (RFC2732)
*
* The conn->name is currently [user:passwd@]host[:port] where host could
* be a hostname, IPv4 address or IPv6 address.
*************************************************************/
tmp = strrchr(conn->name, ':');
if (tmp) {
char *rest;
unsigned long port;
Daniel Stenberg
committed
port=strtoul(tmp+1, &rest, 10); /* Port number must be decimal */
Daniel Stenberg
committed
if (rest != (tmp+1) && *rest == '\0') {
/* The colon really did have only digits after it,
* so it is either a port number or a mistake */
if (port > 0xffff) { /* Single unix standard says port numbers are
* 16 bits long */
failf(data, "Port number too large: %lu", port);
return CURLE_URL_MALFORMAT;
}