Skip to content
Snippets Groups Projects
url.c 68.6 KiB
Newer Older
  • Learn to ignore specific revisions
  •   struct connectdata *conn;
    
      int highscore=-1;
      int connindex=-1;
      int score;
      CURLcode result;
    
      struct timeval now;
    
      now = Curl_tvnow();
    
    
      for(i=0; i< data->numconnects; i++) {
        conn = data->connects[i];
        
        if(!conn)
          continue;
    
        /*
         * By using the set policy, we score each connection.
         */
        switch(data->closepolicy) {
    
        case CURLCLOSEPOLICY_LEAST_RECENTLY_USED:
    
          /*
           * Set higher score for the age passed since the connection
           * was used.
           */
          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]);
    
    
        /* 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);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #else
      /* IPv6-style */
      struct addrinfo *ai;
    
    
    #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
    
    #ifndef ENABLE_IPV6
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /*************************************************************
    
       * Select device to bind socket to
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
       *************************************************************/
    
      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) {
    
                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;
        }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
        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*/
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /*************************************************************
    
       * Connect to server/proxy
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
       *************************************************************/
    
    #ifdef ENABLE_IPV6
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      conn->firstsocket = -1;
      for (ai = conn->hp; ai; ai = ai->ai_next) {
    
        conn->firstsocket = socket(ai->ai_family,
                                   ai->ai_socktype,
                                   ai->ai_protocol);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        if (conn->firstsocket < 0)
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        if (connect(conn->firstsocket, ai->ai_addr, ai->ai_addrlen) < 0) {
    
          sclose(conn->firstsocket);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          conn->firstsocket = -1;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      conn->ai = ai;
      if (conn->firstsocket < 0) {
    
        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) {
    
        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;
        }
    
        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 */
    
      conn->bits.use_range = data->bits.set_range; /* range status */
      conn->range = data->set_range;               /* clone the range setting */
      conn->resume_from = data->set_resume_from;   /* inherite resume_from */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
      /* 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->userpwd?1:0;
      conn->bits.proxy_user_passwd = data->proxyuserpwd?1:0;
    
      /* maxdownload must be -1 on init, as 0 is a valid value! */
      conn->maxdownload = -1;  /* might have been used previously! */
    
    
      /* Store creation time to help future close decision making */
      conn->created = Curl_tvnow();
    
    Daniel Stenberg's avatar
    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 */
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /*************************************************************
       * 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")) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        /*
         * 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))
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          /* 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 */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      }
    
      else {
        /* Set default host and default path */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        strcpy(conn->gname, "curl.haxx.se");
    
        strcpy(conn->path, "/");
    
        if (2 > sscanf(data->url,
    
                       "%64[^\n:]://%256[^\n/]%[^\n]",
    
                       conn->protostr, conn->gname, conn->path)) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          /*
           * The URL was badly formatted, let's try the browser-style _without_
           * protocol specified like 'http://'.
           */
    
          if((1 > sscanf(data->url, "%256[^\n/]%[^\n]",
    
                         conn->gname, conn->path)) ) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
            /*
             * We couldn't even get this format.
             */
    
            failf(data, "<url> malformed");
            return CURLE_URL_MALFORMAT;
          }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
          /*
           * 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");
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #ifdef USE_SSLEAY
    
          else if(strnequal(conn->gname, "HTTPS", 5))
    
            strcpy(conn->protostr, "https");
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          else if(strnequal(conn->gname, "FTPS", 4))
            strcpy(conn->protostr, "ftps");
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #endif /* USE_SSLEAY */
    
          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 */
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /*************************************************************
       * Take care of user and password authentication stuff
       *************************************************************/
    
    Daniel Stenberg's avatar
    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]",
    
                 data->user, data->passwd);
    
        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;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /*************************************************************
       * Take care of proxy authentication stuff
       *************************************************************/
    
        data->proxyuser[0] =0;
        data->proxypasswd[0]=0;
    
        if(*data->proxyuserpwd != ':') {
          /* the name is given, get user+password */
    
          sscanf(data->proxyuserpwd, "%127[^:]:%127[^\n]",
    
                 data->proxyuser, data->proxypasswd);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          }
    
        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;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /*************************************************************
       * Set a few convenience pointers 
       *************************************************************/
    
      conn->name = conn->gname;
      conn->ppath = conn->path;
    
      conn->hostname = conn->name;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /*************************************************************
       * Detect what (if any) proxy to use
       *************************************************************/
    
      if(!data->bits.httpproxy) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        /* If proxy was not specified, we check for default proxy environment
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
         * 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_tok_buf;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        char *proxy=NULL;
        char proxy_env[128];
    
    
        no_proxy=curl_getenv("no_proxy");
    
          no_proxy=curl_getenv("NO_PROXY");
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        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;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          while(nope) {
    
            if(strlen(nope) <= strlen(conn->name)) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
              char *checkn=
    
                conn->name + strlen(conn->name) - strlen(nope);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
              if(strnequal(nope, checkn, strlen(nope))) {
                /* no proxy for this host! */
                break;
              }
            }
    
    	nope=strtok_r(NULL, ", ", &no_proxy_tok_buf);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          }
          if(!nope) {
    	/* It was not listed as without proxy */
    
    	char *protop = conn->protostr;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    	char *envp = proxy_env;
    	char *prox;
    
    
    	/* Now, build <protocol>_proxy and check for such a one to use */
    	while(*protop)
    	  *envp++ = tolower(*protop++);
    
    	/* append _proxy */
    	strcpy(envp, "_proxy");
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    	/* read the protocol proxy: */
    
    Daniel Stenberg's avatar
    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);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    	if(prox && *prox) { /* don't count "" strings */
    	  proxy = prox; /* use this */
    
    	  proxy = curl_getenv("all_proxy"); /* default proxy to use */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
            if(proxy && *proxy) {
              /* we have a proxy here to set */
              data->proxy = proxy;
    
              data->bits.proxystringalloc=1; /* this needs to be freed later */
    
              data->bits.httpproxy=1;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
            }
    
          } /* if (!nope) - it wasn't specified non-proxy */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        } /* NO_PROXY wasn't specified or '*' */
    
        if(no_proxy)
          free(no_proxy);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      } /* if not using proxy */
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /*************************************************************
       * No protocol but proxy usage needs attention
       *************************************************************/
    
      if((conn->protocol&PROT_MISSING) && data->bits.httpproxy ) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        /* 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);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
        if(!reurl)
    
          return CURLE_OUT_OF_MEMORY;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
        data->url = reurl;
        if(data->freethis)
          free(data->freethis);
        data->freethis = reurl;
    
    
        conn->protocol &= ~PROT_MISSING; /* switch that one off again */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /************************************************************
       * 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's avatar
    Daniel Stenberg committed
          /* if it already was in use, we just skip this */
    
          snprintf(resumerange, sizeof(resumerange), "%d-", conn->resume_from);
          conn->range=strdup(resumerange); /* tell ourselves to fetch this range */
          conn->bits.rangestringalloc = TRUE; /* mark as allocated */
          conn->bits.use_range = 1; /* switch on range usage */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /*************************************************************
       * Set timeout if that is being used
       *************************************************************/
    
      if(data->timeout || data->connecttimeout) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        /* We set the timeout on the connection/resolving phase first, separately
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
         * 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);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /*************************************************************
       * Setup internals depending on protocol
       *************************************************************/
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
      if (strequal(conn->protostr, "HTTP")) {
    
        conn->port = (data->use_port && allow_port)?data->use_port:PORT_HTTP;
        conn->remote_port = PORT_HTTP;
    
        conn->protocol |= PROT_HTTP;
    
        conn->curl_do = Curl_http;
        conn->curl_done = Curl_http_done;
        conn->curl_close = Curl_http_close;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      }
    
      else if (strequal(conn->protostr, "HTTPS")) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #ifdef USE_SSLEAY
    
    
        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;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #else /* USE_SSLEAY */
    
        failf(data, "libcurl was built with SSL disabled, https: not supported!");
    
        return CURLE_UNSUPPORTED_PROTOCOL;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #endif /* !USE_SSLEAY */
      }
    
      else if (strequal(conn->protostr, "GOPHER")) {
    
        conn->port = (data->use_port && allow_port)?data->use_port:PORT_GOPHER;
        conn->remote_port = PORT_GOPHER;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        /* Skip /<item-type>/ in path if present */
    
        if (isdigit((int)conn->path[1])) {
          conn->ppath = strchr(&conn->path[1], '/');
          if (conn->ppath == NULL)
    	conn->ppath = conn->path;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          }
    
        conn->protocol |= PROT_GOPHER;
    
        conn->curl_do = Curl_http;
        conn->curl_done = Curl_http_done;
        conn->curl_close = Curl_http_close;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      else if(strequal(conn->protostr, "FTP") ||
              strequal(conn->protostr, "FTPS")) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        char *type;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
        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;
    
        conn->protocol |= PROT_FTP;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
        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 */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          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;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          conn->curl_disconnect = Curl_ftp_disconnect;
    
        }
    
        conn->ppath++; /* don't include the initial slash */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
        /* FTP URLs support an extension like ";type=<typecode>" that
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
         * we'll try to get now! */
    
        type=strstr(conn->ppath, ";type=");
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        if(!type) {
    
          type=strstr(conn->gname, ";type=");
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        }
        if(type) {
          char command;
          *type=0;
          command = toupper(type[6]);
          switch(command) {
          case 'A': /* ASCII mode */
    
    	data->bits.ftp_ascii = 1;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    	break;
          case 'D': /* directory mode */
    
    	data->bits.ftp_list_only = 1;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    	break;
          case 'I': /* binary mode */
          default:
    	/* switch off ASCII */
    
    	data->bits.ftp_ascii = 0;
    
      else if(strequal(conn->protostr, "TELNET")) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        /* telnet testing factory */
    
        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;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      }
    
      else if (strequal(conn->protostr, "DICT")) {
    
        conn->protocol |= PROT_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;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      }
    
      else if (strequal(conn->protostr, "LDAP")) {
    
        conn->protocol |= PROT_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;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      }
    
      else if (strequal(conn->protostr, "FILE")) {
    
        conn->protocol |= PROT_FILE;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
        /* no done() function */
    
        /* 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;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      else {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        /* We fell through all checks and thus we don't support the specified
           protocol */
    
        failf(data, "Unsupported protocol: %s", conn->protostr);
    
        return CURLE_UNSUPPORTED_PROTOCOL;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /*************************************************************
       * .netrc scanning coming up
       *************************************************************/
    
      if(data->bits.use_netrc) {
    
        if(Curl_parsenetrc(conn->hostname, data->user, data->passwd)) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          infof(data, "Couldn't find host %s in the .netrc file, using defaults",
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        }
    
          conn->bits.user_passwd = 1; /* enable user+password */
    
    Daniel Stenberg's avatar
    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);
      }
    
    	  (conn->protocol & (PROT_FTP|PROT_HTTP)) ) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        /* This is a FTP or HTTP URL, and we haven't got the user+password in
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
         * 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 */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        char *ptr=NULL; /* assign to remove possible warnings */
    
          /* there's a user+password given here, to the left of the @ */
    
          data->user[0] =0;
          data->passwd[0]=0;
    
          if(*conn->name != ':') {
            /* the name is given, get user+password */
    
            sscanf(conn->name, "%127[^:@]:%127[^@]",
    
                   data->user, data->passwd);
          }
          else
            /* no name given, get the password only */
            sscanf(conn->name+1, "%127[^@]", data->passwd);
    
    
          if(data->user[0]) {
            char *newname=curl_unescape(data->user, 0);
            if(strlen(newname) < sizeof(data->user)) {
              strcpy(data->user, newname);
            }
            /* if the new name is longer than accepted, then just use
               the unconverted name, it'll be wrong but what the heck */
            free(newname);
          }
    
    
          /* check for password, if no ask for one */
          if( !data->passwd[0] ) {
    
            if(!data->fpasswd ||
               data->fpasswd(data->passwd_client,
                             "password:",data->passwd,sizeof(data->passwd)))
              return CURLE_BAD_PASSWORD_ENTERED;
    
          else {
            /* we have a password found in the URL, decode it! */
            char *newpasswd=curl_unescape(data->passwd, 0);
            if(strlen(newpasswd) < sizeof(data->passwd)) {
              strcpy(data->passwd, newpasswd);
            }
            free(newpasswd);
          }
    
          conn->name = ++ptr;
    
          conn->bits.user_passwd=TRUE; /* enable user+password */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        }
        else {
          strcpy(data->user, CURL_DEFAULT_USER);
          strcpy(data->passwd, CURL_DEFAULT_PASSWORD);
        }
      }
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /*************************************************************
       * 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.
       *************************************************************/
    
    
      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 */
    
      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 */