Newer
Older
*/
score = Curl_tvlong(now) - Curl_tvlong(conn->now);
break;
case CURLCLOSEPOLICY_OLDEST:
/*
* Set higher score for the age passed since the connection
* was created.
*/
score = Curl_tvlong(now) - Curl_tvlong(conn->created);
break;
}
if(score > highscore) {
highscore = score;
connindex = i;
}
}
if(connindex >= 0) {
/* the winner gets the honour of being disconnected */
result = Curl_disconnect(data->connects[connindex]);
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
/* clean the array entry */
data->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
ConnectionStore(struct UrlData *data,
struct connectdata *conn)
{
size_t i;
for(i=0; i< data->numconnects; i++) {
if(!data->connects[i])
break;
}
if(i == data->numconnects) {
/* there was no room available, kill one */
i = ConnectionKillOne(data);
infof(data, "Connection (#%d) was killed to make room\n", i);
}
data->connects[i] = conn; /* fill in this */
conn->connectindex = i; /* make the child know where the pointer to this
particular data is stored */
return i;
}
static CURLcode ConnectPlease(struct UrlData *data,
struct connectdata *conn)
{
#if defined(WIN32)
unsigned long nonblock = 0;
fd_set connectfd;
struct timeval conntimeout;
#endif
#ifndef ENABLE_IPV6
conn->firstsocket = socket(AF_INET, SOCK_STREAM, 0);
memset((char *) &conn->serv_addr, '\0', sizeof(conn->serv_addr));
memcpy((char *)&(conn->serv_addr.sin_addr),
conn->hp->h_addr, conn->hp->h_length);
conn->serv_addr.sin_family = conn->hp->h_addrtype;
conn->serv_addr.sin_port = htons(conn->port);
#else
/* IPv6-style */
struct addrinfo *ai;
Daniel Stenberg
committed
#endif
#if !defined(WIN32)||defined(__CYGWIN32__)
/* We don't generally like checking for OS-versions, we should make this
HAVE_XXXX based, although at the moment I don't have a decent test for
this! */
#ifdef HAVE_INET_NTOA
#ifndef INADDR_NONE
#define INADDR_NONE (unsigned long) ~0
/*************************************************************
* Select device to bind socket to
*************************************************************/
if (data->device && (strlen(data->device)<255)) {
struct sockaddr_in sa;
struct hostent *h=NULL;
char *hostdataptr=NULL;
size_t size;
char myhost[256] = "";
unsigned long in;
if(Curl_if2ip(data->device, myhost, sizeof(myhost))) {
h = Curl_gethost(data, myhost, &hostdataptr);
}
else {
if(strlen(data->device)>1) {
h = Curl_gethost(data, data->device, &hostdataptr);
}
if(h) {
/* we know data->device is shorter than the myhost array */
strcpy(myhost, data->device);
}
}
if(! *myhost) {
/* need to fix this
h=Curl_gethost(data,
getmyhost(*myhost,sizeof(myhost)),
hostent_buf,
sizeof(hostent_buf));
*/
printf("in here\n");
}
infof(data, "We connect from %s\n", myhost);
if ( (in=inet_addr(myhost)) != INADDR_NONE ) {
if ( h ) {
memset((char *)&sa, 0, sizeof(sa));
memcpy((char *)&sa.sin_addr,
h->h_addr,
h->h_length);
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = in;
sa.sin_port = 0; /* get any port */
if( bind(conn->firstsocket, (struct sockaddr *)&sa, sizeof(sa)) >= 0) {
/* we succeeded to bind */
struct sockaddr_in add;
size = sizeof(add);
if(getsockname(conn->firstsocket, (struct sockaddr *) &add,
(socklen_t *)&size)<0) {
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
failf(data, "getsockname() failed");
return CURLE_HTTP_PORT_FAILED;
}
}
else {
switch(errno) {
case EBADF:
failf(data, "Invalid descriptor: %d", errno);
break;
case EINVAL:
failf(data, "Invalid request: %d", errno);
break;
case EACCES:
failf(data, "Address is protected, user not superuser: %d", errno);
break;
case ENOTSOCK:
failf(data,
"Argument is a descriptor for a file, not a socket: %d",
errno);
break;
case EFAULT:
failf(data, "Inaccessable memory error: %d", errno);
break;
case ENAMETOOLONG:
failf(data, "Address too long: %d", errno);
break;
case ENOMEM:
failf(data, "Insufficient kernel memory was available: %d", errno);
break;
default:
failf(data,"errno %d\n");
} /* end of switch */
return CURLE_HTTP_PORT_FAILED;
} /* end of else */
} /* end of if h */
else {
failf(data,"could't find my own IP address (%s)", myhost);
return CURLE_HTTP_PORT_FAILED;
}
} /* end of inet_addr */
else {
failf(data, "could't find my own IP address (%s)", myhost);
return CURLE_HTTP_PORT_FAILED;
}
if(hostdataptr)
free(hostdataptr); /* allocated by Curl_gethost() */
} /* end of device selection support */
#endif /* end of HAVE_INET_NTOA */
#endif /* end of not WIN32 */
#endif /*ENABLE_IPV6*/
/*************************************************************
*************************************************************/
conn->firstsocket = -1;
for (ai = conn->hp; ai; ai = ai->ai_next) {
conn->firstsocket = socket(ai->ai_family,
ai->ai_socktype,
ai->ai_protocol);
if (connect(conn->firstsocket, ai->ai_addr, ai->ai_addrlen) < 0) {
continue;
}
break;
}
failf(data, strerror(errno));
return CURLE_COULDNT_CONNECT;
}
#else
/* non-zero nonblock value sets socket as nonblocking under Win32 */
#if defined(WIN32)
FD_ZERO (&connectfd);
FD_SET(conn->firstsocket, &connectfd);
if (conn->data->connecttimeout > 0) {
}
ioctlsocket(conn->firstsocket, FIONBIO, &nonblock);
#endif
if (connect(conn->firstsocket,
(struct sockaddr *) &(conn->serv_addr),
sizeof(conn->serv_addr)
) < 0) {
#if defined(WIN32)
conntimeout.tv_sec = conn->data->connecttimeout;
conntimeout.tv_usec = 0;
if(-1 != select (conn->firstsocket + 1, NULL, &connectfd, NULL, &conntimeout)) {
if (FD_ISSET(conn->firstsocket, &connectfd)) {
/* shut off non-blocking again */
nonblock = 0;
ioctlsocket(conn->firstsocket, FIONBIO, &nonblock);
return CURLE_OK;
}
else
errno = EINTR;
}
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
switch(errno) {
#ifdef ECONNREFUSED
/* this should be made nicer */
case ECONNREFUSED:
failf(data, "Connection refused");
break;
case EFAULT:
failf(data, "Invalid socket address: %d",errno);
break;
case EISCONN:
failf(data, "Socket already connected: %d",errno);
break;
case ETIMEDOUT:
failf(data, "Timeout while accepting connection, server busy: %d",errno);
break;
case ENETUNREACH:
failf(data, "Network is unreachable: %d",errno);
break;
case EADDRINUSE:
failf(data, "Local address already in use: %d",errno);
break;
case EINPROGRESS:
failf(data, "Socket is nonblocking and connection can not be completed immediately: %d",errno);
break;
case EALREADY:
failf(data, "Socket is nonblocking and a previous connection attempt not completed: %d",errno);
break;
case EAGAIN:
failf(data, "No more free local ports: %d",errno);
break;
case EACCES:
case EPERM:
failf(data, "Attempt to connect to broadcast address without socket broadcast flag or local firewall rule violated: %d",errno);
break;
#endif
case EINTR:
failf(data, "Connection timed out");
break;
default:
failf(data, "Can't connect to server: %d", errno);
break;
}
return CURLE_COULDNT_CONNECT;
}
#endif
return CURLE_OK;
}
static CURLcode Connect(struct UrlData *data,
struct connectdata **in_connect,
bool allow_port) /* allow data->use_port ? */
{
char *tmp;
char *buf;
CURLcode result;
char resumerange[40]="";
struct connectdata *conn;
struct connectdata *conn_temp;
char endbracket;
int urllen;
/*************************************************************
* Check input data
*************************************************************/
if(!data->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->upload_bufsize = UPLOAD_BUFSIZE; /* default upload buffer size */
conn->firstsocket = -1; /* no file descriptor */
conn->secondarysocket = -1; /* no file descriptor */
conn->connectindex = -1; /* no index */
conn->bits.httpproxy = data->bits.httpproxy; /* proxy-or-not status */
/* 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 */
conn->bits.user_passwd = data->userpwd?1:0;
conn->bits.proxy_user_passwd = data->proxyuserpwd?1:0;
/* 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
***********************************************************/
#define LEAST_PATH_ALLOC 256
urllen=strlen(data->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 ...
************************************************************/
if((2 == sscanf(data->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
*/
if (strnequal(conn->path, "localhost/", 10) ||
strnequal(conn->path, "127.0.0.1/", 10))
/* If there's another host name than the one we support, <host>/ is
* quietly ommitted */
strcpy(conn->path, &conn->path[10]);
strcpy(conn->protostr, "file"); /* store protocol string lowercase */
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, "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 */
}
buf = data->buffer; /* this is our buffer */
/*************************************************************
* Take care of user and password authentication stuff
*************************************************************/
Daniel Stenberg
committed
if(conn->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
*************************************************************/
Daniel Stenberg
committed
if(conn->bits.proxy_user_passwd) {
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);
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 */
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 || data->connecttimeout) {
/* We set the timeout on the connection/resolving phase first, separately
* from the download/upload part to allow a maximum time on everything */
/* myalarm() makes a signal get sent when the timeout fires off, and that
will abort system calls */
if(data->connecttimeout)
myalarm(data->connecttimeout);
else
myalarm(data->timeout);
/*************************************************************
* Setup internals depending on protocol
*************************************************************/
if (strequal(conn->protostr, "HTTP")) {
conn->port = (data->use_port && allow_port)?data->use_port:PORT_HTTP;
conn->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")) {
conn->port = (data->use_port && allow_port)?data->use_port:PORT_HTTPS;
conn->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")) {
conn->port = (data->use_port && allow_port)?data->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;
conn->curl_close = Curl_http_close;
else if(strequal(conn->protostr, "FTP") ||
strequal(conn->protostr, "FTPS")) {
if(strequal(conn->protostr, "FTPS")) {
#ifdef USE_SSLEAY
conn->protocol |= PROT_FTPS;
#else
failf(data, "libcurl was built with SSL disabled, ftps: not supported!");
return CURLE_UNSUPPORTED_PROTOCOL;
#endif /* !USE_SSLEAY */
}
conn->port = (data->use_port && allow_port)?data->use_port:PORT_FTP;
conn->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 */
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;
}
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")) {
conn->protocol |= PROT_TELNET;
conn->port = (data->use_port && allow_port)?data->use_port: PORT_TELNET;
conn->remote_port = PORT_TELNET;
conn->curl_do = Curl_telnet;
conn->curl_done = Curl_telnet_done;
else if (strequal(conn->protostr, "DICT")) {
conn->port = (data->use_port && allow_port)?data->use_port:PORT_DICT;
conn->remote_port = PORT_DICT;
conn->curl_do = Curl_dict;
conn->curl_done = Curl_dict_done;
else if (strequal(conn->protostr, "LDAP")) {
conn->port = (data->use_port && allow_port)?data->use_port:PORT_LDAP;
conn->remote_port = PORT_LDAP;
conn->curl_do = Curl_ldap;
conn->curl_done = Curl_ldap_done;
else if (strequal(conn->protostr, "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;
/* 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
Daniel Stenberg
committed
conn->bits.user_passwd = 1; /* enable user+password */
Daniel Stenberg
committed
/* 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);
}
Daniel Stenberg
committed
else if(!(conn->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);
}
Daniel Stenberg
committed
conn->bits.user_passwd=TRUE; /* 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
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
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 */
conn->remote_port = atoi(tmp);
Daniel Stenberg
committed
}
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
if(data->bits.httpproxy) {
/* 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. */
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");
return CURLE_OUT_OF_MEMORY;
}
/* 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 */
endofprot=strstr(proxyptr, "://");
if(endofprot) {
proxyptr = endofprot+3;
}
/* allow user to specify proxy.server.com:1080 if desired */
prox_portno = strchr (proxyptr, ':');
if (prox_portno) {
*prox_portno = 0x0; /* cut off number from host name */
prox_portno ++;
/* now set the local port number */
conn->port = atoi(prox_portno);
}
else if(data->proxyport) {
/* None given in the proxy string, then get the default one if it is
given */
conn->port = data->proxyport;
}
/* now, clone the cleaned proxy host name */
conn->proxyhost = strdup(proxyptr);
free(proxydup); /* free the duplicate pointer and not the modified */
}
/*************************************************************
* 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.
*************************************************************/