Newer
Older
Daniel Stenberg
committed
struct SessionHandle *data = conn->data;
char *hostname = data->change.proxy?conn->proxy.name:conn->host.name;
infof(data, "About to connect() to %s port %d\n",
hostname, conn->port);
/*************************************************************
*************************************************************/
hostaddr,
Daniel Stenberg
committed
&conn->sock[FIRSTSOCKET],
&addr,
connected);
Daniel Stenberg
committed
/* All is cool, then we store the current information */
conn->dns_entry = hostaddr;
conn->ip_addr = addr;
Daniel Stenberg
committed
Curl_store_ip_addr(conn);
Daniel Stenberg
committed
if (conn->data->set.proxytype == CURLPROXY_SOCKS5) {
return handleSock5Proxy(conn->proxyuser,
conn->proxypasswd,
Daniel Stenberg
committed
conn) ?
Daniel Stenberg
committed
CURLE_COULDNT_CONNECT : CURLE_OK;
}
else if (conn->data->set.proxytype == CURLPROXY_HTTP) {
/* do nothing here. handled later. */
}
else {
failf(conn->data, "unknown proxytype option given");
Daniel Stenberg
committed
}
}
* verboseconnect() displays verbose information after a connect
static void verboseconnect(struct connectdata *conn)
Daniel Stenberg
committed
{
infof(conn->data, "Connected to %s (%s) port %d\n",
Daniel Stenberg
committed
conn->bits.httpproxy ? conn->proxy.dispname : conn->host.dispname,
conn->ip_addr_str, conn->port);
Daniel Stenberg
committed
}
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
CURLcode Curl_protocol_fdset(struct connectdata *conn,
fd_set *read_fd_set,
fd_set *write_fd_set,
int *max_fdp)
{
CURLcode res = CURLE_OK;
if(conn->curl_proto_fdset)
res = conn->curl_proto_fdset(conn, read_fd_set, write_fd_set, max_fdp);
return res;
}
CURLcode Curl_doing_fdset(struct connectdata *conn,
fd_set *read_fd_set,
fd_set *write_fd_set,
int *max_fdp)
{
CURLcode res = CURLE_OK;
if(conn && conn->curl_doing_fdset)
res = conn->curl_doing_fdset(conn, read_fd_set, write_fd_set, max_fdp);
return res;
}
/*
* We are doing protocol-specific connecting and this is being called over and
* over from the multi interface until the connection phase is done on
* protocol layer.
*/
CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done)
{
CURLcode result=CURLE_OK;
if(conn && conn->curl_connecting) {
*done = FALSE;
result = conn->curl_connecting(conn, done);
}
else
*done = TRUE;
return result;
}
/*
* We are DOING this is being called over and over from the multi interface
* until the DOING phase is done on protocol layer.
*/
CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done)
{
CURLcode result=CURLE_OK;
if(conn && conn->curl_doing) {
*done = FALSE;
result = conn->curl_doing(conn, done);
}
else
*done = TRUE;
return result;
}
/*
* We have discovered that the TCP connection has been successful, we can now
* proceed with some action.
*
*/
CURLcode Curl_protocol_connect(struct connectdata *conn, bool *protocol_done)
{
struct SessionHandle *data = conn->data;
CURLcode result=CURLE_OK;
*protocol_done = FALSE;
if(conn->bits.tcpconnect && conn->bits.protoconnstart) {
/* We already are connected, get back. This may happen when the connect
worked fine in the first call, like when we connect to a local server
or proxy. Note that we don't know if the protocol is actually done.
Unless this protocol doesn't have any protocol-connect callback, as
then we know we're done. */
if(!conn->curl_connecting)
*protocol_done = TRUE;
return CURLE_OK;
}
if(!conn->bits.tcpconnect) {
Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
if(data->set.verbose)
verboseconnect(conn);
}
if(!conn->bits.protoconnstart) {
if(conn->curl_connect) {
/* is there a protocol-specific 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 */
result = conn->curl_connect(conn, protocol_done);
}
else
*protocol_done = TRUE;
/* it has started, possibly even completed but that knowledge isn't stored
in this bit! */
conn->bits.protoconnstart = TRUE;
}
return result; /* pass back status */
}
/*
* Helpers for IDNA convertions.
*/
#ifdef USE_LIBIDN
static bool is_ASCII_name (const char *hostname)
{
const unsigned char *ch = (const unsigned char*)hostname;
while (*ch) {
if (*ch++ & 0x80)
return FALSE;
}
return TRUE;
}
/*
* Check if characters in hostname is allowed in Top Level Domain.
*/
const char *ace_hostname)
{
size_t err_pos;
char *uc_name = NULL;
int rc;
/* Convert (and downcase) ACE-name back into locale's character set */
rc = idna_to_unicode_lzlz(ace_hostname, &uc_name, 0);
if (rc != IDNA_SUCCESS)
rc = tld_check_lz(uc_name, &err_pos, NULL);
if (rc == TLD_INVALID)
infof(data, "WARNING: %s; pos %u = `%c'/0x%02X\n",
#ifdef HAVE_TLD_STRERROR
tld_strerror(rc),
#else
"<no msg>",
#endif
err_pos, uc_name[err_pos],
uc_name[err_pos] & 255);
else if (rc != TLD_SUCCESS)
infof(data, "WARNING: TLD check for %s failed; %s\n",
uc_name,
#ifdef HAVE_TLD_STRERROR
tld_strerror(rc)
#else
"<no msg>"
#endif
);
if (uc_name)
idn_free(uc_name);
return (rc == TLD_SUCCESS);
}
#endif
static void fix_hostname(struct connectdata *conn, struct hostname *host)
{
/* set the name we use to display the host name */
#ifdef USE_LIBIDN
/*************************************************************
* Check name for non-ASCII and convert hostname to ACE form.
*************************************************************/
Daniel Stenberg
committed
if (!is_ASCII_name(host->name) &&
stringprep_check_version(LIBIDN_REQUIRED_VERSION)) {
char *ace_hostname = NULL;
struct SessionHandle *data = conn->data;
int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0);
infof (data, "Input domain encoded as `%s'\n",
stringprep_locale_charset ());
if (rc != IDNA_SUCCESS)
infof(data, "Failed to convert %s to ACE; %s\n",
host->name, Curl_idn_strerror(conn,rc));
else {
host->encalloc = ace_hostname;
/* change the name pointer to point to the encoded hostname */
host->name = host->encalloc;
}
}
Daniel Stenberg
committed
#else
(void)conn; /* never used */
#endif
}
Daniel Stenberg
committed
/**
Daniel Stenberg
committed
* CreateConnection() sets up a new connectdata struct, or re-uses an already
* existing one, and resolves host name.
*
* if this function returns CURLE_OK and *async is set to TRUE, the resolve
* response will be coming asynchronously. If *async is FALSE, the name is
* already resolved.
Daniel Stenberg
committed
*
* @param data The sessionhandle pointer
* @param in_connect is set to the next connection data pointer
* @param addr is set to the new dns entry for this connection
* @param async is set TRUE/FALSE depending on the nature of this lookup
* @return CURLcode
* @see SetupConnection()
Daniel Stenberg
committed
*/
static CURLcode CreateConnection(struct SessionHandle *data,
Daniel Stenberg
committed
struct connectdata **in_connect,
struct Curl_dns_entry **addr,
bool *async)
Daniel Stenberg
committed
char *at;
CURLcode result=CURLE_OK;
struct connectdata *conn_temp = NULL;
struct Curl_dns_entry *hostaddr;
#if defined(HAVE_ALARM) && !defined(USE_ARES)
Daniel Stenberg
committed
#endif
char endbracket;
char user[MAX_CURL_USER_LENGTH];
char passwd[MAX_CURL_PASSWORD_LENGTH];
Daniel Stenberg
committed
int rc;
Daniel Stenberg
committed
bool reuse;
Daniel Stenberg
committed
#ifdef SIGALRM
Daniel Stenberg
committed
#ifdef HAVE_SIGACTION
struct sigaction keep_sigact; /* store the old struct here */
bool keep_copysig=FALSE; /* did copy it? */
#else
#ifdef HAVE_SIGNAL
void *keep_sigact; /* store the old handler here */
#endif /* HAVE_SIGNAL */
#endif /* HAVE_SIGACTION */
#endif /* SIGALRM */
#endif /* USE_ARES */
Daniel Stenberg
committed
*addr = NULL; /* nothing yet */
*async = FALSE;
/*************************************************************
* 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 *)calloc(sizeof(struct connectdata), 1);
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;
/* and we setup a few fields in case we end up actually using this struct */
conn->data = data; /* remember our daddy */
Daniel Stenberg
committed
conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
conn->connectindex = -1; /* no index */
Daniel Stenberg
committed
conn->bits.httpproxy = (data->change.proxy && *data->change.proxy &&
(data->set.proxytype == CURLPROXY_HTTP))?
TRUE:FALSE; /* http proxy or not */
/* 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;
/* 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();
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 */
conn->bits.user_passwd = data->set.userpwd?1:0;
conn->bits.proxy_user_passwd = data->set.proxyuserpwd?1:0;
Daniel Stenberg
committed
conn->bits.no_body = data->set.opt_no_body;
conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
conn->bits.ftp_use_lprt = data->set.ftp_use_lprt;
Daniel Stenberg
committed
/* This initing continues below, see the comment "Continue connectdata
* initialization here" */
/***********************************************************
* 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;
Daniel Stenberg
committed
conn->pathbuffer=(char *)malloc(urllen);
if(NULL == conn->pathbuffer)
return CURLE_OUT_OF_MEMORY; /* really bad error */
Daniel Stenberg
committed
conn->path = conn->pathbuffer;
conn->host.rawalloc=(char *)malloc(urllen);
if(NULL == conn->host.rawalloc)
Daniel Stenberg
committed
return CURLE_OUT_OF_MEMORY;
conn->host.name = conn->host.rawalloc;
conn->host.name[0] = 0;
/*************************************************************
* 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 ...
************************************************************/
if((2 == sscanf(data->change.url, "%15[^:]:%[^\n]",
conn->protostr,
conn->path)) && strequal(conn->protostr, "file")) {
if(conn->path[0] == '/' && conn->path[1] == '/') {
/* Allow omitted hostname (e.g. file:/<path>). This is not strictly
* speaking a valid file: URL by RFC 1738, but treating file:/<path> as
* file://localhost/<path> is similar to how other schemes treat missing
* hostnames. See RFC 1808. */
/* This cannot be done with strcpy() in a portable manner, since the
memory areas overlap! */
memmove(conn->path, conn->path + 2, strlen(conn->path + 2)+1);
}
/*
* 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
*/
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
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 */
Daniel Stenberg
committed
/* This cannot be made with strcpy, as the memory chunks overlap! */
memmove(conn->path, ptr, strlen(ptr)+1);
strcpy(conn->protostr, "file"); /* store protocol string lowercase */
/* clear path */
conn->path[0]=0;
Daniel Stenberg
committed
if (2 > sscanf(data->change.url,
Daniel Stenberg
committed
"%15[^\n:]://%[^\n/]%[^\n]",
Daniel Stenberg
committed
conn->protostr,
conn->host.name, 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, "%[^\n/]%[^\n]",
conn->host.name, conn->path)) ) {
/*
* 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.
*/
/* Note: if you add a new protocol, please update the list in
* lib/version.c too! */
Daniel Stenberg
committed
if(checkprefix("GOPHER.", conn->host.name))
strcpy(conn->protostr, "gopher");
Daniel Stenberg
committed
#ifdef USE_SSL
else if(checkprefix("FTPS", conn->host.name))
Daniel Stenberg
committed
#endif /* USE_SSL */
Daniel Stenberg
committed
else if(checkprefix("FTP.", conn->host.name))
strcpy(conn->protostr, "ftp");
Daniel Stenberg
committed
else if(checkprefix("TELNET.", conn->host.name))
strcpy(conn->protostr, "telnet");
Daniel Stenberg
committed
else if (checkprefix("DICT.", conn->host.name))
strcpy(conn->protostr, "DICT");
Daniel Stenberg
committed
else if (checkprefix("LDAP.", conn->host.name))
strcpy(conn->protostr, "LDAP");
strcpy(conn->protostr, "http");
}
conn->protocol |= PROT_MISSING; /* not given in URL */
}
Daniel Stenberg
committed
/* We search for '?' in the host name (but only on the right side of a
* @-letter to allow ?-letters in username and password) to handle things
* like http://example.com?param= (notice the missing '/').
*/
at = strchr(conn->host.name, '@');
if(at)
tmp = strchr(at+1, '?');
else
tmp = strchr(conn->host.name, '?');
if(tmp) {
/* We must insert a slash before the '?'-letter in the URL. If the URL had
a slash after the '?', that is where the path currently begins and the
'?string' is still part of the host name.
We must move the trailing part from the host name and put it first in
the path. And have it all prefixed with a slash.
*/
size_t hostlen = strlen(tmp);
size_t pathlen = strlen(conn->path);
/* move the existing path plus the zero byte forward, to make room for
the host-name part */
memmove(conn->path+hostlen+1, conn->path, pathlen+1);
/* now copy the trailing host part in front of the existing path */
memcpy(conn->path+1, tmp, hostlen);
Daniel Stenberg
committed
conn->path[0]='/'; /* prepend the missing slash */
Daniel Stenberg
committed
*tmp=0; /* now cut off the hostname at the ? */
}
else if(!conn->path[0]) {
/* if there's no path set, use a single slash */
strcpy(conn->path, "/");
}
Daniel Stenberg
committed
Daniel Stenberg
committed
/* If the URL is malformatted (missing a '/' after hostname before path) we
* insert a slash here. The only letter except '/' we accept to start a path
* is '?'.
*/
if(conn->path[0] == '?') {
/* We need this function to deal with overlapping memory areas. We know
that the memory area 'path' points to is 'urllen' bytes big and that
is bigger than the path. Use +1 to move the zero byte too. */
memmove(&conn->path[1], conn->path, strlen(conn->path)+1);
Daniel Stenberg
committed
conn->path[0] = '/';
}
/*
* So if the URL was A://B/C,
* conn->protostr is A
* conn->host.name is B
* conn->path is /C
*/
/*************************************************************
* Take care of proxy authentication stuff
*************************************************************/
Daniel Stenberg
committed
if(conn->bits.proxy_user_passwd) {
char proxyuser[MAX_CURL_USER_LENGTH]="";
char proxypasswd[MAX_CURL_PASSWORD_LENGTH]="";
Daniel Stenberg
committed
sscanf(data->set.proxyuserpwd,
"%" MAX_CURL_USER_LENGTH_TXT "[^:]:"
"%" MAX_CURL_PASSWORD_LENGTH_TXT "[^\n]",
proxyuser, proxypasswd);
Daniel Stenberg
committed
conn->proxyuser = curl_unescape(proxyuser,0);
if(!conn->proxyuser)
return CURLE_OUT_OF_MEMORY;
Daniel Stenberg
committed
conn->proxypasswd = curl_unescape(proxypasswd,0);
if(!conn->proxypasswd)
return CURLE_OUT_OF_MEMORY;
Daniel Stenberg
committed
#ifndef CURL_DISABLE_HTTP
/*************************************************************
* 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;
char *endptr = strchr(conn->host.name, ':');
Daniel Stenberg
committed
if(endptr)
namelen=endptr-conn->host.name;
Daniel Stenberg
committed
else
namelen=strlen(conn->host.name);
Daniel Stenberg
committed
if(strlen(nope) <= namelen) {
conn->host.name + namelen - strlen(nope);
if(checkprefix(nope, checkn)) {
/* no proxy for this host! */
break;
}
}
nope=strtok_r(NULL, ", ", &no_proxy_tok_buf);
/* It was not listed as without proxy */
char *protop = conn->protostr;
char *envp = proxy_env;
char *prox;
/* Now, build <protocol>_proxy and check for such a one to use */
while(*protop)
*envp++ = tolower((int)*protop++);
/* append _proxy */
strcpy(envp, "_proxy");
/* read the protocol 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.
Daniel Stenberg
committed
* 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((int)*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 */
if(!proxy)
proxy=curl_getenv("ALL_PROXY");
Daniel Stenberg
committed
long bits = conn->protocol & (PROT_HTTPS|PROT_SSL);
Daniel Stenberg
committed
data->change.proxy = proxy;
data->change.proxy_alloc=TRUE; /* this needs to be freed later */
conn->bits.httpproxy = TRUE;
Daniel Stenberg
committed
/* force this to become HTTP */
conn->protocol = PROT_HTTP | bits;
} /* if (!nope) - it wasn't specified non-proxy */
if(no_proxy)
free(no_proxy);
Daniel Stenberg
committed
#endif /* CURL_DISABLE_HTTP */
/*************************************************************
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) {
Daniel Stenberg
committed
conn->range = aprintf("%" FORMAT_OFF_T "-", conn->resume_from);
if(!conn->range)
return CURLE_OUT_OF_MEMORY;
conn->bits.rangestringalloc = TRUE; /* mark as allocated */
conn->bits.use_range = 1; /* switch on range usage */
#endif
/*************************************************************
* Setup internals depending on protocol
*************************************************************/
Daniel Stenberg
committed
conn->socktype = SOCK_STREAM; /* most of them are TCP streams */
if (strequal(conn->protostr, "HTTP")) {
#ifndef CURL_DISABLE_HTTP
Daniel Stenberg
committed
conn->port = PORT_HTTP;
conn->remote_port = PORT_HTTP;
conn->curl_do = Curl_http;
conn->curl_do_more = NULL;
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")) {
Daniel Stenberg
committed
#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
Daniel Stenberg
committed
conn->port = PORT_HTTPS;
conn->remote_port = PORT_HTTPS;
conn->protocol |= PROT_HTTP|PROT_HTTPS|PROT_SSL;
conn->curl_do = Curl_http;
conn->curl_do_more = NULL;
conn->curl_done = Curl_http_done;
conn->curl_connect = Curl_http_connect;
Daniel Stenberg
committed
#else /* USE_SS */
failf(data, LIBCURL_NAME
" was built with SSL disabled, https: not supported!");
Daniel Stenberg
committed
#endif /* !USE_SSL */
else if (strequal(conn->protostr, "GOPHER")) {
#ifndef CURL_DISABLE_GOPHER
Daniel Stenberg
committed
conn->port = PORT_GOPHER;
conn->remote_port = PORT_GOPHER;
Daniel Stenberg
committed
conn->path = strchr(&conn->path[1], '/');
if (conn->path == NULL)
conn->path = conn->pathbuffer;
Daniel Stenberg
committed
}
conn->curl_do = Curl_http;
conn->curl_do_more = NULL;
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")) {
#ifndef CURL_DISABLE_FTP
int port = PORT_FTP;
Daniel Stenberg
committed
#ifdef USE_SSL
conn->protocol |= PROT_FTPS|PROT_SSL;
Daniel Stenberg
committed
conn->ssl[SECONDARYSOCKET].use = TRUE; /* send data securely */
port = PORT_FTPS;
failf(data, LIBCURL_NAME
" was built with SSL disabled, ftps: not supported!");
Daniel Stenberg
committed
#endif /* !USE_SSL */
Daniel Stenberg
committed
conn->port = port;
conn->remote_port = port;
Daniel Stenberg
committed
if(data->change.proxy &&
*data->change.proxy &&
Daniel Stenberg
committed
!data->set.tunnel_thru_httpproxy) {
/* Unless we have asked to tunnel ftp operations through the proxy, we
switch and use HTTP operations only */
#ifndef CURL_DISABLE_HTTP
conn->curl_do = Curl_http;
conn->curl_done = Curl_http_done;
Daniel Stenberg
committed
conn->protocol = PROT_HTTP; /* switch to HTTP */
#else
failf(data, "FTP over http proxy requires HTTP support built-in!");
return CURLE_UNSUPPORTED_PROTOCOL;
#endif
conn->curl_do = Curl_ftp;
conn->curl_do_more = Curl_ftp_nextconnect;
conn->curl_done = Curl_ftp_done;
conn->curl_connect = Curl_ftp_connect;
conn->curl_connecting = Curl_ftp_multi_statemach;
conn->curl_doing = Curl_ftp_doing;
conn->curl_proto_fdset = Curl_ftp_fdset;
conn->curl_doing_fdset = Curl_ftp_fdset;
Daniel Stenberg
committed
conn->path++; /* don't include the initial slash */
/* FTP URLs support an extension like ";type=<typecode>" that
Daniel Stenberg
committed
type=strstr(conn->path, ";type=");
type=strstr(conn->host.rawalloc, ";type=");
*type=0; /* it was in the middle of the hostname */
Daniel Stenberg
committed
command = toupper((int)type[6]);
data->set.ftp_ascii = 1;
break;
data->set.ftp_list_only = 1;
break;
/* switch off ASCII */
data->set.ftp_ascii = 0;
break;
#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;
Daniel Stenberg
committed
conn->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
Daniel Stenberg
committed
conn->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
Daniel Stenberg
committed
conn->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;
conn->curl_done = Curl_file_done;
/* 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) {
conn->bits.tcpconnect = TRUE; /* we are "connected */
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
}
else if (strequal(conn->protostr, "TFTP")) {
#ifndef CURL_DISABLE_TFTP
char *type;
Daniel Stenberg
committed
conn->socktype = SOCK_DGRAM; /* UDP datagram based */
conn->protocol |= PROT_TFTP;
conn->port = PORT_TFTP;
conn->remote_port = PORT_TFTP;
conn->curl_connect = Curl_tftp_connect;
conn->curl_do = Curl_tftp;
Daniel Stenberg
committed
conn->curl_done = Curl_tftp_done;
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
/* TFTP URLs support an extension like ";mode=<typecode>" that
* we'll try to get now! */
type=strstr(conn->path, ";mode=");
if(!type) {
type=strstr(conn->host.rawalloc, ";mode=");
}
if(type) {
char command;
*type=0; /* it was in the middle of the hostname */
command = toupper((int)type[6]);
switch(command) {
case 'A': /* ASCII mode */
case 'N': /* NETASCII mode */
data->set.ftp_ascii = 1;
break;
case 'O': /* octet mode */
case 'I': /* binary mode */
default:
/* switch off ASCII */
data->set.ftp_ascii = 0;
break;
}
}
#else
failf(data, LIBCURL_NAME
" was built with TFTP disabled!");
#endif
/* We fell through all checks and thus we don't support the specified
protocol */
failf(data, "Unsupported protocol: %s", conn->protostr);
if(data->change.proxy && *data->change.proxy) {
/* If this is supposed to use a proxy, we need to figure out the proxy
host name name, so that we can re-use an existing connection
that may exist registered to the same proxy host. */
char *prox_portno;
char *endofprot;
/* We need to make a duplicate of the proxy so that we can modify the
string safely. */
Daniel Stenberg
committed
char *proxydup=strdup(data->change.proxy);
/* We use 'proxyptr' to point to the proxy name from now on... */
char *proxyptr=proxydup;
char *portptr;
Daniel Stenberg
committed
char *atsign;
if(NULL == proxydup) {
failf(data, "memory shortage");
return CURLE_OUT_OF_MEMORY;
}
/* 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.
*/