diff options
Diffstat (limited to 'Source/CTest/Curl/url.c')
-rw-r--r-- | Source/CTest/Curl/url.c | 1092 |
1 files changed, 826 insertions, 266 deletions
diff --git a/Source/CTest/Curl/url.c b/Source/CTest/Curl/url.c index d830fb6..3216fd6 100644 --- a/Source/CTest/Curl/url.c +++ b/Source/CTest/Curl/url.c @@ -1,25 +1,25 @@ -/***************************************************************************** +/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2001, Daniel Stenberg, <daniel@haxx.se>, et al. - * - * In order to be useful for every potential user, curl and libcurl are - * dual-licensed under the MPL and the MIT/X-derivate licenses. + * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al. * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the MPL or the MIT/X-derivate - * licenses. You may pick one of these licenses. + * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * $Id$ - *****************************************************************************/ + ***************************************************************************/ /* -- WIN32 approved -- */ @@ -72,6 +72,10 @@ #include <inet.h> #endif +#ifdef HAVE_SETJMP_H +#include <setjmp.h> +#endif + #ifndef HAVE_SELECT #error "We can't compile without select() support!" #endif @@ -107,6 +111,7 @@ #include "ldap.h" #include "url.h" #include "connect.h" +#include "ca-bundle.h" #include <curl/types.h> @@ -120,6 +125,7 @@ #ifdef KRB4 #include "security.h" #endif + /* The last #include file should be: */ #ifdef MALLOCDEBUG #include "memdebug.h" @@ -138,11 +144,17 @@ static unsigned int ConnectionStore(struct SessionHandle *data, #ifndef RETSIGTYPE #define RETSIGTYPE void #endif +#ifdef HAVE_SIGSETJMP +extern sigjmp_buf curl_jmpenv; +#endif static RETSIGTYPE alarmfunc(int signal) { /* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */ (void)signal; +#ifdef HAVE_SIGSETJMP + siglongjmp(curl_jmpenv, 1); +#endif return; } #endif @@ -167,6 +179,13 @@ CURLcode Curl_close(struct SessionHandle *data) Curl_SSL_Close_All(data); #endif + /* No longer a dirty share, if it exists */ + if (data->share) + data->share->dirty--; + + if(data->change.cookielist) /* clean up list if any */ + curl_slist_free_all(data->change.cookielist); + if(data->state.auth_host) free(data->state.auth_host); @@ -182,11 +201,13 @@ CURLcode Curl_close(struct SessionHandle *data) if(data->state.headerbuff) free(data->state.headerbuff); +#ifndef CURL_DISABLE_HTTP if(data->set.cookiejar) /* we have a "destination" for all the cookies to get dumped to */ Curl_cookie_output(data->cookies, data->set.cookiejar); Curl_cookie_cleanup(data->cookies); +#endif /* free the connection cache */ free(data->state.connects); @@ -262,7 +283,11 @@ CURLcode Curl_open(struct SessionHandle **curl) /* Set the default size of the SSL session ID cache */ data->set.ssl.numsessions = 5; + + data->set.proxyport = 1080; + data->set.proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */ + /* create an array with connection data struct pointers */ data->state.numconnects = 5; /* hard-coded right now */ data->state.connects = (struct connectdata **) @@ -272,12 +297,23 @@ CURLcode Curl_open(struct SessionHandle **curl) free(data); return CURLE_OUT_OF_MEMORY; } - + + /* + * libcurl 7.10 introduces SSL verification *by default*! This needs to be + * switched off unless wanted. + */ + data->set.ssl.verifypeer = TRUE; + data->set.ssl.verifyhost = 2; +#ifdef CURL_CA_BUNDLE + /* This is our prefered CA cert bundle since install time */ + data->set.ssl.CAfile = (char *)CURL_CA_BUNDLE; +#endif + + memset(data->state.connects, 0, sizeof(struct connectdata *)*data->state.numconnects); *curl = data; - return CURLE_OK; } @@ -439,7 +475,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...) /* * Parse the $HOME/.netrc file */ - data->set.use_netrc = va_arg(param, long)?TRUE:FALSE; + data->set.use_netrc = va_arg(param, long); break; case CURLOPT_FOLLOWLOCATION: /* @@ -493,13 +529,36 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...) data->set.ssl.version = va_arg(param, long); break; + case CURLOPT_COOKIESESSION: + /* + * Set this option to TRUE to start a new "cookie session". It will + * prevent the forthcoming read-cookies-from-file actions to accept + * cookies that are marked as being session cookies, as they belong to a + * previous session. + * + * In the original Netscape cookie spec, "session cookies" are cookies + * with no expire date set. RFC2109 describes the same action if no + * 'Max-Age' is set and RFC2965 includes the RFC2109 description and adds + * a 'Discard' action that can enforce the discard even for cookies that + * have a Max-Age. + * + * We run mostly with the original cookie spec, as hardly anyone implements + * anything else. + */ + data->set.cookiesession = (bool)va_arg(param, long); + break; + +#ifndef CURL_DISABLE_HTTP case CURLOPT_COOKIEFILE: /* * Set cookie file to read and parse. Can be used multiple times. */ cookiefile = (char *)va_arg(param, void *); if(cookiefile) - data->cookies = Curl_cookie_init(cookiefile, data->cookies); + /* append the cookie file name to the list of file names, and deal with + them later */ + data->change.cookielist = + curl_slist_append(data->change.cookielist, cookiefile); break; case CURLOPT_COOKIEJAR: @@ -512,8 +571,11 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...) * Activate the cookie parser. This may or may not already * have been made. */ - data->cookies = Curl_cookie_init(NULL, data->cookies); + data->cookies = Curl_cookie_init(NULL, data->cookies, + data->set.cookiesession); break; +#endif + case CURLOPT_WRITEHEADER: /* * Custom pointer to pass the header write callback function @@ -634,8 +696,9 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...) data->set.use_port = va_arg(param, long); break; case CURLOPT_POST: - /* Does this option serve a purpose anymore? */ - + /* Does this option serve a purpose anymore? Yes it does, when + CURLOPT_POSTFIELDS isn't used and the POST data is read off the + callback! */ if(va_arg(param, long)) data->set.httpreq = HTTPREQ_POST; break; @@ -673,7 +736,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...) break; case CURLOPT_PROXY: /* - * Set proxy server:port to use as HTTP proxy + * Set proxy server:port to use as HTTP proxy. + * + * If the proxy is set to "" we explicitly say that we don't want to use a + * proxy (even though there might be environment variables saying so). + * + * Setting it to NULL, means no proxy but allows the environment variables + * to decide for us. */ if(data->change.proxy_alloc) { /* @@ -723,6 +792,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...) */ data->set.useragent = va_arg(param, char *); break; + case CURLOPT_ENCODING: + /* + * String to use at the value of Accept-Encoding header. 08/28/02 jhrg + */ + data->set.encoding = va_arg(param, char *); + break; + case CURLOPT_USERPWD: /* * user:password to use in the operation @@ -752,7 +828,11 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...) * Progress callback function */ data->set.fprogress = va_arg(param, curl_progress_callback); - data->progress.callback = TRUE; /* no longer internal */ + if(data->set.fprogress) + data->progress.callback = TRUE; /* no longer internal */ + else + data->progress.callback = FALSE; /* NULL enforces internal */ + break; case CURLOPT_PROGRESSDATA: /* @@ -765,6 +845,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...) * Password prompt callback */ data->set.fpasswd = va_arg(param, curl_passwd_callback); + /* + * if the callback provided is null, reset the default callback + */ + if(!data->set.fpasswd) + { + data->set.fpasswd = my_getpass; + } break; case CURLOPT_PASSWDDATA: /* @@ -790,12 +877,30 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...) */ data->set.set_resume_from = va_arg(param, long); break; + case CURLOPT_DEBUGFUNCTION: + /* + * stderr write callback. + */ + data->set.fdebug = va_arg(param, curl_debug_callback); + /* + * if the callback provided is NULL, it'll use the default callback + */ + break; + case CURLOPT_DEBUGDATA: + /* + * Set to a void * that should receive all error writes. This + * defaults to CURLOPT_STDERR for normal operations. + */ + data->set.debugdata = va_arg(param, void *); + break; case CURLOPT_STDERR: /* * Set to a FILE * that should receive all error writes. This * defaults to stderr for normal operations. */ data->set.err = va_arg(param, FILE *); + if(!data->set.err) + data->set.err = stderr; break; case CURLOPT_HEADERFUNCTION: /* @@ -928,7 +1033,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...) * Set CA info for SSL connection. Specify file name of the CA certificate */ data->set.ssl.CAfile = va_arg(param, char *); - data->set.ssl.CApath = NULL; /*This does not work on windows.*/ + break; + 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. + */ + /* This does not work on windows. */ + data->set.ssl.CApath = va_arg(param, char *); break; case CURLOPT_TELNETOPTIONS: /* @@ -936,9 +1048,49 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...) */ data->set.telnet_options = va_arg(param, struct curl_slist *); break; + + 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; + + case CURLOPT_NOSIGNAL: + /* + * The application asks not to set any signal() or alarm() handlers, + * even when using a timeout. + */ + data->set.no_signal = va_arg(param, long) ? TRUE : FALSE; + break; + + case CURLOPT_SHARE: + { + curl_share *set; + set = va_arg(param, curl_share *); + if(data->share) + data->share->dirty--; + + data->share = set; + data->share->dirty++; + } + break; + + case CURLOPT_PROXYTYPE: + /* + * Set proxy type. HTTP/SOCKS4/SOCKS5 + */ + data->set.proxytype = va_arg(param, long); + break; + default: /* unknown tag and its companion, just ignore: */ - return CURLE_READ_ERROR; /* correct this */ + return CURLE_FAILED_INIT; /* correct this */ } return CURLE_OK; } @@ -993,6 +1145,8 @@ CURLcode Curl_disconnect(struct connectdata *conn) free(conn->allocptr.uagent); if(conn->allocptr.userpwd) free(conn->allocptr.userpwd); + if(conn->allocptr.accept_encoding) + free(conn->allocptr.accept_encoding); if(conn->allocptr.rangeline) free(conn->allocptr.rangeline); if(conn->allocptr.ref) @@ -1026,7 +1180,7 @@ static bool SocketIsDead(int sock) FD_SET(sock,&check_set); to.tv_sec = 0; - to.tv_usec = 1; + to.tv_usec = 0; sval = select(sock + 1, &check_set, 0, 0, &to); if(sval == 0) @@ -1050,6 +1204,7 @@ ConnectionExists(struct SessionHandle *data, struct connectdata *check; 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. @@ -1070,7 +1225,6 @@ ConnectionExists(struct SessionHandle *data, if(strequal(needle->protostr, check->protostr) && strequal(needle->name, check->name) && (needle->remote_port == check->remote_port) ) { - bool dead; if(strequal(needle->protostr, "FTP")) { /* This is FTP, verify that we're using the same name and password as well */ @@ -1080,27 +1234,7 @@ ConnectionExists(struct SessionHandle *data, continue; } } - dead = SocketIsDead(check->firstsocket); - if(dead) { - /* - * Even though the connection seems to have passed away, we could - * still make an effort to get the name information, as we intend to - * connect to the same host again. - * - * This is now subject to discussion. What do you think? - */ - 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 search, because we only store - one connection for each unique set of identifiers */ - return FALSE; - } - - *usethis = check; - return TRUE; /* yes, we found one to use! */ - + match = TRUE; } } else { /* The requested needle connection is using a proxy, @@ -1109,9 +1243,26 @@ ConnectionExists(struct SessionHandle *data, strequal(needle->proxyhost, check->proxyhost) && needle->port == check->port) { /* This is the same proxy connection, use it! */ - *usethis = check; - return TRUE; + 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 */ @@ -1213,7 +1364,197 @@ ConnectionStore(struct SessionHandle *data, return i; } -static CURLcode ConnectPlease(struct connectdata *conn) +/* + * This function logs in to a SOCKS5 proxy and sends the specifies the final + * desitination server. + */ +static int handleSock5Proxy( + const char *proxy_name, + const char *proxy_password, + struct connectdata *conn, + int sock) +{ + unsigned char socksreq[600]; /* room for large user/pw (255 max each) */ + int actualread; + int written; + CURLcode result; + + Curl_nonblock(sock, FALSE); + + socksreq[0] = 5; /* version */ + socksreq[1] = (char)(proxy_name[0] ? 2 : 1); /* number of methods (below) */ + socksreq[2] = 0; /* no authentication */ + socksreq[3] = 2; /* username/password */ + + result = Curl_write(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]), + &written); + if ((result != CURLE_OK) || (written != (2 + (int)socksreq[1]))) { + failf(conn->data, "Unable to send initial SOCKS5 request."); + return 1; + } + + result=Curl_read(conn, sock, (char *)socksreq, 2, &actualread); + if ((result != CURLE_OK) || (actualread != 2)) { + failf(conn->data, "Unable to receive initial SOCKS5 response."); + return 1; + } + + if (socksreq[0] != 5) { + failf(conn->data, "Received invalid version in initial SOCKS5 response."); + return 1; + } + if (socksreq[1] == 0) { + /* Nothing to do, no authentication needed */ + ; + } + else if (socksreq[1] == 2) { + /* Needs user name and password */ + int userlen, pwlen, len; + + userlen = strlen(proxy_name); + pwlen = strlen(proxy_password); + + /* username/password request looks like + * +----+------+----------+------+----------+ + * |VER | ULEN | UNAME | PLEN | PASSWD | + * +----+------+----------+------+----------+ + * | 1 | 1 | 1 to 255 | 1 | 1 to 255 | + * +----+------+----------+------+----------+ + */ + len = 0; + socksreq[len++] = 1; /* username/pw subnegotiation version */ + socksreq[len++] = (char) userlen; + memcpy(socksreq + len, proxy_name, (int) userlen); + len += userlen; + socksreq[len++] = (char) pwlen; + memcpy(socksreq + len, proxy_password, (int) pwlen); + len += pwlen; + + result = Curl_write(conn, sock, (char *)socksreq, len, &written); + if ((result != CURLE_OK) || (len != written)) { + failf(conn->data, "Failed to send SOCKS5 sub-negotiation request."); + return 1; + } + + result=Curl_read(conn, sock, (char *)socksreq, 2, &actualread); + if ((result != CURLE_OK) || (actualread != 2)) { + failf(conn->data, "Unable to receive SOCKS5 sub-negotiation response."); + return 1; + } + + if ((socksreq[0] != 5) || /* version */ + (socksreq[1] != 0)) { /* status */ + failf(conn->data, "User was rejected by the SOCKS5 server (%d %d).", + socksreq[0], socksreq[1]); + return 1; + } + + /* Everything is good so far, user was authenticated! */ + } + else { + /* error */ + if (socksreq[1] == 1) { + failf(conn->data, + "SOCKS5 GSSAPI per-message authentication is not supported."); + return 1; + } + else if (socksreq[1] == 255) { + if (proxy_name[0] == 0) { + failf(conn->data, + "No authentication method was acceptable. (It is quite likely" + " that the SOCKS5 server wanted a username/password, since none" + " was supplied to the server on this connection.)"); + } + else { + failf(conn->data, "No authentication method was acceptable."); + } + return 1; + } + else { + failf(conn->data, + "Undocumented SOCKS5 mode attempted to be used by server."); + return 1; + } + } + + /* Authentication is complete, now specify destination to the proxy */ + socksreq[0] = 5; /* version (SOCKS5) */ + socksreq[1] = 1; /* connect */ + socksreq[2] = 0; /* must be zero */ + socksreq[3] = 1; /* IPv4 = 1 */ + + { +#ifndef ENABLE_IPV6 + struct Curl_dns_entry *dns; + Curl_addrinfo *hp=NULL; + dns = Curl_resolv(conn->data, conn->hostname, conn->remote_port); + /* + * We cannot use 'hostent' as a struct that Curl_resolv() returns. It + * returns a Curl_addrinfo pointer that may not always look the same. + */ + if(dns) + hp=dns->addr; + if (hp && hp->h_addr_list[0]) { + socksreq[4] = ((char*)hp->h_addr_list[0])[0]; + socksreq[5] = ((char*)hp->h_addr_list[0])[1]; + socksreq[6] = ((char*)hp->h_addr_list[0])[2]; + socksreq[7] = ((char*)hp->h_addr_list[0])[3]; + + Curl_resolv_unlock(dns); /* not used anymore from now on */ + } + else { + failf(conn->data, "Failed to resolve \"%s\" for SOCKS5 connect.", + conn->hostname); + return 1; + } +#else + failf(conn->data, + "%s:%d has an internal error an needs to be fixed to work", + __FILE__, __LINE__); + return 1; +#endif + } + + *((unsigned short*)&socksreq[8]) = htons(conn->remote_port); + + { + const int packetsize = 10; + + result = Curl_write(conn, sock, (char *)socksreq, packetsize, &written); + if ((result != CURLE_OK) || (written != packetsize)) { + failf(conn->data, "Failed to send SOCKS5 connect request."); + return 1; + } + + result = Curl_read(conn, sock, (char *)socksreq, packetsize, &actualread); + if ((result != CURLE_OK) || (actualread != packetsize)) { + failf(conn->data, "Failed to receive SOCKS5 connect request ack."); + return 1; + } + + if (socksreq[0] != 5) { /* version */ + failf(conn->data, + "SOCKS5 reply has wrong version, version should be 5."); + return 1; + } + if (socksreq[1] != 0) { /* Anything besides 0 is an error */ + failf(conn->data, + "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)", + (unsigned char)socksreq[4], (unsigned char)socksreq[5], + (unsigned char)socksreq[6], (unsigned char)socksreq[7], + (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])), + socksreq[1]); + return 1; + } + } + + Curl_nonblock(sock, TRUE); + return 0; /* Proxy was successful! */ +} + +static CURLcode ConnectPlease(struct connectdata *conn, + struct Curl_dns_entry *hostaddr, + bool *connected) { CURLcode result; Curl_ipconnect *addr; @@ -1222,28 +1563,130 @@ static CURLcode ConnectPlease(struct connectdata *conn) * Connect to server/proxy *************************************************************/ result= Curl_connecthost(conn, - conn->hostaddr, + hostaddr, conn->port, &conn->firstsocket, - &addr); + &addr, + connected); 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. */ + conn->connect_addr = hostaddr; + #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 = conn->hostaddr->h_addrtype; - conn->serv_addr.sin_port = htons(conn->port); + conn->serv_addr.sin_family = hostaddr->addr->h_addrtype; + conn->serv_addr.sin_port = htons((unsigned short)conn->port); #endif + + if (conn->data->set.proxytype == CURLPROXY_SOCKS5) { + return handleSock5Proxy(conn->data->state.proxyuser, + conn->data->state.proxypasswd, + conn, + conn->firstsocket) ? + 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"); + return CURLE_COULDNT_CONNECT; + } } return result; } +static void verboseconnect(struct connectdata *conn, + struct Curl_dns_entry *dns) +{ +#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)dns; /* not used in the IPv6 enabled version */ + { + 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 + { + Curl_addrinfo *hostaddr=dns->addr; + 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:"", +#if defined(HAVE_INET_NTOA_R) + inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf)), +#else + inet_ntoa(in), +#endif + conn->port); + } +#endif +} + +/* + * We have discovered that the TCP connection has been successful, we can now + * proceed with some action. + * + * If we're using the multi interface, this host address pointer is most + * likely NULL at this point as we can't keep the resolved info around. This + * may call for some reworking, like a reference counter in the struct or + * something. The hostaddr is not used for very much though, we have the + * 'serv_addr' field in the connectdata struct for most of it. + */ +CURLcode Curl_protocol_connect(struct connectdata *conn, + struct Curl_dns_entry *hostaddr) +{ + struct SessionHandle *data = conn->data; + CURLcode result=CURLE_OK; + + Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */ + + if(data->set.verbose) + verboseconnect(conn, hostaddr); + + 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); + } + + return result; /* pass back status */ +} + static CURLcode CreateConnection(struct SessionHandle *data, struct connectdata **in_connect) { @@ -1253,18 +1696,16 @@ static CURLcode CreateConnection(struct SessionHandle *data, char resumerange[40]=""; struct connectdata *conn; struct connectdata *conn_temp; - char endbracket; int urllen; -#ifdef HAVE_INET_NTOA_R - char ntoa_buf[64]; -#endif + struct Curl_dns_entry *hostaddr; #ifdef HAVE_ALARM - unsigned int prev_alarm; + unsigned int prev_alarm=0; #endif + char endbracket; #ifdef HAVE_SIGACTION struct sigaction keep_sigact; /* store the old struct here */ - bool keep_copysig; /* did copy it? */ + bool keep_copysig=FALSE; /* did copy it? */ #else #ifdef HAVE_SIGNAL void *keep_sigact; /* store the old handler here */ @@ -1301,16 +1742,18 @@ static CURLcode CreateConnection(struct SessionHandle *data, conn->firstsocket = -1; /* no file descriptor */ conn->secondarysocket = -1; /* no file descriptor */ conn->connectindex = -1; /* no index */ - conn->bits.httpproxy = data->change.proxy?TRUE:FALSE; /* proxy-or-not */ + conn->bits.httpproxy = (data->change.proxy && *data->change.proxy && + (data->set.proxytype == CURLPROXY_HTTP))? + TRUE:FALSE; /* http 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->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; - + /* inherite initial knowledge from the data struct */ conn->bits.user_passwd = data->set.userpwd?1:0; conn->bits.proxy_user_passwd = data->set.proxyuserpwd?1:0; @@ -1321,6 +1764,20 @@ static CURLcode CreateConnection(struct SessionHandle *data, /* Store creation time to help future close decision making */ conn->created = Curl_tvnow(); + /* Set the start time temporary to this creation time to allow easier + timeout checks before the transfer has started for real. The start time + is later set "for real" using Curl_pgrsStartNow(). */ + conn->data->progress.start = conn->created; + + conn->bits.upload_chunky = + ((conn->protocol&PROT_HTTP) && + data->set.upload && + (data->set.infilesize == -1) && + (data->set.httpversion != CURL_HTTP_VERSION_1_0))? + /* HTTP, upload, unknown file size and not HTTP 1.0 */ + TRUE: + /* else, no chunky upload */ + FALSE; /*********************************************************** * We need to allocate memory to store the path in. We get the size of the @@ -1410,22 +1867,25 @@ static CURLcode CreateConnection(struct SessionHandle *data, * is based on the first letters of the server name. */ - if(strnequal(conn->gname, "FTP", 3)) { + /* Note: if you add a new protocol, please update the list in + * lib/version.c too! */ + + if(checkprefix("FTP", conn->gname)) { strcpy(conn->protostr, "ftp"); } - else if(strnequal(conn->gname, "GOPHER", 6)) + else if(checkprefix("GOPHER", conn->gname)) strcpy(conn->protostr, "gopher"); #ifdef USE_SSLEAY - else if(strnequal(conn->gname, "HTTPS", 5)) + else if(checkprefix("HTTPS", conn->gname)) strcpy(conn->protostr, "https"); - else if(strnequal(conn->gname, "FTPS", 4)) + else if(checkprefix("FTPS", conn->gname)) strcpy(conn->protostr, "ftps"); #endif /* USE_SSLEAY */ - else if(strnequal(conn->gname, "TELNET", 6)) + else if(checkprefix("TELNET", conn->gname)) strcpy(conn->protostr, "telnet"); - else if (strnequal(conn->gname, "DICT", sizeof("DICT")-1)) + else if (checkprefix("DICT", conn->gname)) strcpy(conn->protostr, "DICT"); - else if (strnequal(conn->gname, "LDAP", sizeof("LDAP")-1)) + else if (checkprefix("LDAP", conn->gname)) strcpy(conn->protostr, "LDAP"); else { strcpy(conn->protostr, "http"); @@ -1437,32 +1897,12 @@ static CURLcode CreateConnection(struct SessionHandle *data, buf = data->state.buffer; /* this is our buffer */ - /************************************************************* - * Take care of user and password authentication stuff - *************************************************************/ - - if(conn->bits.user_passwd && !data->set.use_netrc) { - data->state.user[0] =0; - data->state.passwd[0]=0; - - if(*data->set.userpwd != ':') { - /* the name is given, get user+password */ - sscanf(data->set.userpwd, "%127[^:]:%127[^\n]", - data->state.user, data->state.passwd); - } - else - /* no name given, get the password only */ - sscanf(data->set.userpwd+1, "%127[^\n]", data->state.passwd); - - /* check for password, if no ask for one */ - if( !data->state.passwd[0] ) { - if(!data->set.fpasswd || - data->set.fpasswd(data->set.passwd_client, - "password:", data->state.passwd, - sizeof(data->state.passwd))) - return CURLE_BAD_PASSWORD_ENTERED; - } - } + /* + * 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 @@ -1482,12 +1922,13 @@ static CURLcode CreateConnection(struct SessionHandle *data, /* check for password, if no ask for one */ if( !data->state.proxypasswd[0] ) { - if(!data->set.fpasswd || - data->set.fpasswd( data->set.passwd_client, - "proxy password:", - data->state.proxypasswd, - sizeof(data->state.proxypasswd))) + 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; + } } } @@ -1537,10 +1978,17 @@ static CURLcode CreateConnection(struct SessionHandle *data, nope=no_proxy?strtok_r(no_proxy, ", ", &no_proxy_tok_buf):NULL; while(nope) { - if(strlen(nope) <= strlen(conn->name)) { + unsigned int namelen; + char *endptr = strchr(conn->name, ':'); + if(endptr) + namelen=endptr-conn->name; + else + namelen=strlen(conn->name); + + if(strlen(nope) <= namelen) { char *checkn= - conn->name + strlen(conn->name) - strlen(nope); - if(strnequal(nope, checkn, strlen(nope))) { + conn->name + namelen - strlen(nope); + if(checkprefix(nope, checkn)) { /* no proxy for this host! */ break; } @@ -1622,6 +2070,7 @@ static CURLcode CreateConnection(struct SessionHandle *data, 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 @@ -1640,22 +2089,29 @@ static CURLcode CreateConnection(struct SessionHandle *data, 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->protocol |= PROT_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")) { -#ifdef USE_SSLEAY +#if defined(USE_SSLEAY) && !defined(CURL_DISABLE_HTTP) conn->port = (data->set.use_port && data->state.allow_port)? data->set.use_port:PORT_HTTPS; @@ -1663,6 +2119,7 @@ static CURLcode CreateConnection(struct SessionHandle *data, 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; @@ -1673,6 +2130,7 @@ static CURLcode CreateConnection(struct SessionHandle *data, #endif /* !USE_SSLEAY */ } 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; @@ -1684,10 +2142,18 @@ static CURLcode CreateConnection(struct SessionHandle *data, } conn->protocol |= PROT_GOPHER; 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")) { + +/* MN 06/07/02 */ +#ifndef CURL_DISABLE_FTP char *type; if(strequal(conn->protostr, "FTPS")) { @@ -1706,6 +2172,7 @@ static CURLcode CreateConnection(struct SessionHandle *data, conn->protocol |= PROT_FTP; if(data->change.proxy && + *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 */ @@ -1715,11 +2182,17 @@ static CURLcode CreateConnection(struct SessionHandle *data, 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 } else { 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_disconnect = Curl_ftp_disconnect; @@ -1735,7 +2208,7 @@ static CURLcode CreateConnection(struct SessionHandle *data, } if(type) { char command; - *type=0; + *type=0; /* it was in the middle of the hostname */ command = toupper(type[6]); switch(command) { case 'A': /* ASCII mode */ @@ -1751,8 +2224,16 @@ static CURLcode CreateConnection(struct SessionHandle *data, break; } } + +/* 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 /* telnet testing factory */ conn->protocol |= PROT_TELNET; @@ -1761,24 +2242,39 @@ static CURLcode CreateConnection(struct SessionHandle *data, 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->protocol |= PROT_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->protocol |= PROT_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->protocol |= PROT_FILE; conn->curl_do = Curl_file; @@ -1795,6 +2291,10 @@ static CURLcode CreateConnection(struct SessionHandle *data, } return result; +#else + failf(data, LIBCURL_NAME + " was built with FILE disabled!"); +#endif } else { /* We fell through all checks and thus we don't support the specified @@ -1804,84 +2304,6 @@ static CURLcode CreateConnection(struct SessionHandle *data, } /************************************************************* - * .netrc scanning coming up - *************************************************************/ - if(data->set.use_netrc) { - if(Curl_parsenetrc(conn->hostname, - data->state.user, - data->state.passwd)) { - infof(data, "Couldn't find host %s in the .netrc file, using defaults", - conn->hostname); - } - else - conn->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->state.user[0]) - strcpy(data->state.user, CURL_DEFAULT_USER); - if(!data->state.passwd[0]) - strcpy(data->state.passwd, CURL_DEFAULT_PASSWORD); - } - 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->state.user[0] =0; - data->state.passwd[0]=0; - - if(*conn->name != ':') { - /* the name is given, get user+password */ - sscanf(conn->name, "%127[^:@]:%127[^@]", - data->state.user, data->state.passwd); - } - else - /* no name given, get the password only */ - sscanf(conn->name+1, "%127[^@]", data->state.passwd); - - if(data->state.user[0]) { - char *newname=curl_unescape(data->state.user, 0); - if(strlen(newname) < sizeof(data->state.user)) { - strcpy(data->state.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->state.passwd[0] ) { - if(!data->set.fpasswd || - data->set.fpasswd(data->set.passwd_client, - "password:", data->state.passwd, - sizeof(data->state.passwd))) - return CURLE_BAD_PASSWORD_ENTERED; - } - else { - /* we have a password found in the URL, decode it! */ - char *newpasswd=curl_unescape(data->state.passwd, 0); - if(strlen(newpasswd) < sizeof(data->state.passwd)) { - strcpy(data->state.passwd, newpasswd); - } - free(newpasswd); - } - - conn->name = ++ptr; - conn->bits.user_passwd=TRUE; /* enable user+password */ - } - else { - strcpy(data->state.user, CURL_DEFAULT_USER); - strcpy(data->state.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 @@ -1889,32 +2311,48 @@ static CURLcode CreateConnection(struct SessionHandle *data, * * 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. *************************************************************/ - if((1 == sscanf(conn->name, "[%*39[0-9a-fA-F:.]%c", &endbracket)) && (']' == endbracket)) { - /* This is a (IPv6-style) specified IP-address. We support _any_ - IP within brackets to be really generic. */ - conn->name++; /* pass the starting bracket */ + /* this is a RFC2732-style specified IP-address */ + conn->bits.ipv6_ip = TRUE; + conn->name++; /* pass the starting bracket */ + conn->hostname++; tmp = strchr(conn->name, ']'); *tmp = 0; /* zero terminate */ - tmp++; /* pass the ending bracket */ if(':' != *tmp) tmp = NULL; /* no port number available */ } - else { - /* traditional IPv4-style port-extracting */ - tmp = strchr(conn->name, ':'); - } + else + tmp = strrchr(conn->name, ':'); if (tmp) { - *tmp++ = '\0'; /* cut off the name there */ - conn->remote_port = atoi(tmp); + char *rest; + unsigned long port; + + port=strtoul(tmp+1, &rest, 10); /* Port number must be decimal */ + + 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; + } + + *tmp = '\0'; /* cut off the name there */ + conn->remote_port = (unsigned short)port; + } } - if(data->change.proxy) { + 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. */ @@ -1966,6 +2404,137 @@ static CURLcode CreateConnection(struct SessionHandle *data, } /************************************************************* + * Take care of user and password authentication stuff + *************************************************************/ + + /* + * Inputs: data->set.userpwd (CURLOPT_USERPWD) + * data->set.fpasswd (CURLOPT_PASSWDFUNCTION) + * data->set.use_netrc (CURLOPT_NETRC) + * conn->hostname + * netrc file + * hard-coded defaults + * + * Outputs: (almost :- all currently undefined) + * conn->bits.user_passwd - non-zero if non-default passwords exist + * conn->state.user - non-zero length if defined + * conn->state.passwd - ditto + * conn->hostname - remove user name and password + */ + + /* At this point, we're hoping all the other special cases have + * been taken care of, so conn->hostname is at most + * [user[:password]]@]hostname + * + * We need somewhere to put the embedded details, so do that first. + */ + + data->state.user[0] =0; /* to make everything well-defined */ + data->state.passwd[0]=0; + + if (conn->protocol & (PROT_FTP|PROT_HTTP)) { + /* This is a FTP or HTTP URL, 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=strchr(conn->name, '@'); + char *userpass = conn->name; + if(ptr != NULL) { + /* there's a user+password given here, to the left of the @ */ + + conn->name = conn->hostname = ++ptr; + + /* So the hostname is sane. Only bother interpreting the + * results if we could care. It could still be wasted + * work because it might be overtaken by the programmatically + * set user/passwd, but doing that first adds more cases here :-( + */ + + if (data->set.use_netrc != CURL_NETRC_REQUIRED) { + /* We could use the one in the URL */ + + conn->bits.user_passwd = 1; /* enable user+password */ + + if(*userpass != ':') { + /* the name is given, get user+password */ + sscanf(userpass, "%127[^:@]:%127[^@]", + data->state.user, data->state.passwd); + } + else + /* no name given, get the password only */ + sscanf(userpass, ":%127[^@]", data->state.passwd); + + if(data->state.user[0]) { + char *newname=curl_unescape(data->state.user, 0); + if(strlen(newname) < sizeof(data->state.user)) { + strcpy(data->state.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); + } + if (data->state.passwd[0]) { + /* we have a password found in the URL, decode it! */ + char *newpasswd=curl_unescape(data->state.passwd, 0); + if(strlen(newpasswd) < sizeof(data->state.passwd)) { + strcpy(data->state.passwd, newpasswd); + } + free(newpasswd); + } + } + } + } + + /* Programmatically set password: + * - always applies, if available + * - takes precedence over the values we just set above + * so scribble it over the top. + * User-supplied passwords are assumed not to need unescaping. + * + * user_password is set in "inherite initial knowledge' above, + * so it doesn't have to be set in this block + */ + if (data->set.userpwd != NULL) { + if(*data->set.userpwd != ':') { + /* the name is given, get user+password */ + sscanf(data->set.userpwd, "%127[^:]:%127[^\n]", + data->state.user, data->state.passwd); + } + else + /* no name given, get the password only */ + sscanf(data->set.userpwd+1, "%127[^\n]", data->state.passwd); + } + + if (data->set.use_netrc != CURL_NETRC_IGNORED && + data->state.passwd[0] == '\0' ) { /* need passwd */ + if(Curl_parsenetrc(conn->hostname, + data->state.user, + data->state.passwd)) { + infof(data, "Couldn't find host %s in the .netrc file, using defaults", + conn->hostname); + } else + conn->bits.user_passwd = 1; /* enable user+password */ + } + + /* if we have a user but no password, ask for one */ + if(conn->bits.user_passwd && + !data->state.passwd[0] ) { + if(data->set.fpasswd(data->set.passwd_client, + "password:", data->state.passwd, + sizeof(data->state.passwd))) + return CURLE_BAD_PASSWORD_ENTERED; + } + + /* So we could have a password but no user; that's just too bad. */ + + /* If our protocol needs a password and we have none, use the defaults */ + if ( (conn->protocol & (PROT_FTP|PROT_HTTP)) && + !conn->bits.user_passwd) { + strcpy(data->state.user, CURL_DEFAULT_USER); + strcpy(data->state.passwd, CURL_DEFAULT_PASSWORD); + /* This is the default password, so DON'T set conn->bits.user_passwd */ + } + + /************************************************************* * 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. @@ -1988,6 +2557,10 @@ static CURLcode CreateConnection(struct SessionHandle *data, free(old_conn->proxyhost); conn = conn_temp; /* use this connection from now on */ + /* If we speak over a proxy, we need to copy the host name too, as it + might be another remote host even when re-using a connection */ + strcpy(conn->gname, old_conn->gname); /* safe strcpy() */ + /* we need these pointers if we speak over a proxy */ conn->hostname = conn->gname; conn->name = &conn->gname[old_conn->name - old_conn->gname]; @@ -2044,7 +2617,7 @@ static CURLcode CreateConnection(struct SessionHandle *data, /************************************************************* * Set timeout if that is being used *************************************************************/ - if(data->set.timeout || data->set.connecttimeout) { + if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) { /************************************************************* * Set signal handler to catch SIGALRM * Store the old value to be able to set it back later! @@ -2089,33 +2662,31 @@ static CURLcode CreateConnection(struct SessionHandle *data, /************************************************************* * Resolve the name of the server or proxy *************************************************************/ - if(!data->change.proxy) { + if(conn->bits.reuse) { + /* re-used connection, no resolving is necessary */ + hostaddr = NULL; + } + else if(!data->change.proxy || !*data->change.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. */ conn->port = conn->remote_port; /* it is the same port */ /* Resolve target host right on */ - if(!conn->hostaddr) { - /* it might already be set if reusing a connection */ - conn->hostaddr = Curl_resolv(data, conn->name, conn->port, - &conn->hostent_buf); - } - if(!conn->hostaddr) { + hostaddr = Curl_resolv(data, conn->name, conn->port); + + if(!hostaddr) { failf(data, "Couldn't resolve host '%s'", conn->name); result = CURLE_COULDNT_RESOLVE_HOST; /* don't return yet, we need to clean up the timeout first */ } } - else if(!conn->hostaddr) { - /* This is a proxy that hasn't been resolved yet. It may be resolved - if we're reusing an existing connection. */ + else { + /* This is a proxy that hasn't been resolved yet. */ /* resolve proxy */ - /* it might already be set if reusing a connection */ - conn->hostaddr = Curl_resolv(data, conn->proxyhost, conn->port, - &conn->hostent_buf); + hostaddr = Curl_resolv(data, conn->proxyhost, conn->port); - if(!conn->hostaddr) { + if(!hostaddr) { failf(data, "Couldn't resolve proxy '%s'", conn->proxyhost); result = CURLE_COULDNT_RESOLVE_PROXY; /* don't return yet, we need to clean up the timeout first */ @@ -2123,7 +2694,7 @@ static CURLcode CreateConnection(struct SessionHandle *data, } Curl_pgrsTime(data, TIMER_NAMELOOKUP); #ifdef HAVE_ALARM - if(data->set.timeout || data->set.connecttimeout) { + if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) { #ifdef HAVE_SIGACTION if(keep_copysig) { /* we got a struct as it looked before, now put that one back nice @@ -2185,7 +2756,8 @@ static CURLcode CreateConnection(struct SessionHandle *data, * Send user-agent to HTTP proxies even if the target protocol * isn't HTTP. *************************************************************/ - if((conn->protocol&PROT_HTTP) || data->change.proxy) { + if((conn->protocol&PROT_HTTP) || + (data->change.proxy && *data->change.proxy)) { if(data->set.useragent) { if(conn->allocptr.uagent) free(conn->allocptr.uagent); @@ -2194,68 +2766,36 @@ static CURLcode CreateConnection(struct SessionHandle *data, } } - if(-1 == conn->firstsocket) { - /* Connect only if not already connected! */ - result = ConnectPlease(conn); - if(CURLE_OK != result) - return result; - - if(conn->curl_connect) { - /* 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 */ - result = conn->curl_connect(conn); - if(result != CURLE_OK) - return result; /* pass back errors */ - } + if(data->set.encoding) { + if(conn->allocptr.accept_encoding) + free(conn->allocptr.accept_encoding); + conn->allocptr.accept_encoding = + aprintf("Accept-Encoding: %s\015\012", data->set.encoding); } - Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected */ - - conn->now = Curl_tvnow(); /* time this *after* the connect is done */ conn->bytecount = 0; conn->headerbytecount = 0; - /* 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 - struct addrinfo *ai = conn->serv_addr; + if(-1 == conn->firstsocket) { + bool connected; - 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); - } + /* Connect only if not already connected! */ + result = ConnectPlease(conn, hostaddr, &connected); + + if(connected) + result = Curl_protocol_connect(conn, hostaddr); + + if(CURLE_OK != result) + return result; } -#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)\n", conn->hostaddr->h_name, -#if defined(HAVE_INET_NTOA_R) - inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf)) -#else - inet_ntoa(in) -#endif - ); + else { + Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */ + if(data->set.verbose) + verboseconnect(conn, hostaddr); } -#endif + + conn->now = Curl_tvnow(); /* time this *after* the connect is done, we + set this here perhaps a second time */ #ifdef __EMX__ /* 20000330 mgs @@ -2293,7 +2833,6 @@ CURLcode Curl_connect(struct SessionHandle *data, return code; } - CURLcode Curl_done(struct connectdata *conn) { struct SessionHandle *data=conn->data; @@ -2311,7 +2850,16 @@ CURLcode Curl_done(struct connectdata *conn) free(conn->newurl); conn->newurl = NULL; } - + + if(conn->connect_addr) + Curl_resolv_unlock(conn->connect_addr); /* done with this */ + +#if defined(MALLOCDEBUG) && defined(AGGRESIVE_TEST) + /* scan for DNS cache entries still marked as in use */ + Curl_hash_apply(data->hostcache, + NULL, Curl_scan_cache_used); +#endif + /* this calls the protocol-specific function pointer previously set */ if(conn->curl_done) result = conn->curl_done(conn); @@ -2341,13 +2889,15 @@ CURLcode Curl_do(struct connectdata **connp) struct connectdata *conn = *connp; struct SessionHandle *data=conn->data; + conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to use */ + if(conn->curl_do) { /* generic protocol-specific function pointer set in curl_connect() */ result = conn->curl_do(conn); /* This was formerly done in transfer.c, but we better do it here */ - if((CURLE_WRITE_ERROR == result) && conn->bits.reuse) { + if((CURLE_SEND_ERROR == result) && conn->bits.reuse) { /* This was a re-use of a connection and we got a write error in the * DO-phase. Then we DISCONNECT this connection and have another attempt * to CONNECT and then DO again! The retry cannot possibly find another @@ -2370,6 +2920,16 @@ CURLcode Curl_do(struct connectdata **connp) return result; } +CURLcode Curl_do_more(struct connectdata *conn) +{ + CURLcode result=CURLE_OK; + + if(conn->curl_do_more) + result = conn->curl_do_more(conn); + + return result; +} + /* * local variables: * eval: (load-file "../curl-mode.el") |