Skip to content
Snippets Groups Projects
url.c 139 KiB
Newer Older
  • Learn to ignore specific revisions
  •   case CURLOPT_SSH_AUTH_TYPES:
        data->set.ssh_auth_types = va_arg(param, long);
        break;
    
      case CURLOPT_SSH_PUBLIC_KEYFILE:
        /*
         * Use this file instead of the $HOME/.ssh/id_dsa.pub file
         */
    
        result = setstropt(&data->set.str[STRING_SSH_PUBLIC_KEY],
    
        break;
    
      case CURLOPT_SSH_PRIVATE_KEYFILE:
        /*
         * Use this file instead of the $HOME/.ssh/id_dsa file
         */
    
        result = setstropt(&data->set.str[STRING_SSH_PRIVATE_KEY],
    
      case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5:
        /*
    
         * Option to allow for the MD5 of the host public key to be checked
    
        result = setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5],
    
      case CURLOPT_HTTP_TRANSFER_DECODING:
        /*
         * disable libcurl transfer encoding is used
         */
        data->set.http_te_skip = (bool)(0 == va_arg(param, long));
        break;
    
      case CURLOPT_HTTP_CONTENT_DECODING:
        /*
         * raw data passed to the application when content encoding is used
         */
        data->set.http_ce_skip = (bool)(0 == va_arg(param, long));
        break;
    
    
      case CURLOPT_NEW_FILE_PERMS:
        /*
         * Uses these permissions instead of 0644
         */
        data->set.new_file_perms = va_arg(param, long);
        break;
    
      case CURLOPT_NEW_DIRECTORY_PERMS:
        /*
         * Uses these permissions instead of 0755
         */
        data->set.new_directory_perms = va_arg(param, long);
        break;
    
      case CURLOPT_PROXY_TRANSFER_MODE:
        /*
         * set transfer mode (;type=<a|i>) when doing FTP via an HTTP proxy
         */
        switch (va_arg(param, long)) {
          case 0:
            data->set.proxy_transfer_mode = FALSE;
            break;
          case 1:
            data->set.proxy_transfer_mode = TRUE;
            break;
          default:
            /* reserve other values for future use */
            result = CURLE_FAILED_INIT;
            break;
        }
        break;
    
      default:
        /* unknown tag and its companion, just ignore: */
    
        result = CURLE_FAILED_INIT; /* correct this */
        break;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      }
    
    static void conn_free(struct connectdata *conn)
    {
    
        return;
    
      /* close possibly still open sockets */
      if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
        sclose(conn->sock[SECONDARYSOCKET]);
      if(CURL_SOCKET_BAD != conn->sock[FIRSTSOCKET])
        sclose(conn->sock[FIRSTSOCKET]);
    
      Curl_safefree(conn->user);
      Curl_safefree(conn->passwd);
      Curl_safefree(conn->proxyuser);
      Curl_safefree(conn->proxypasswd);
      Curl_safefree(conn->allocptr.proxyuserpwd);
      Curl_safefree(conn->allocptr.uagent);
      Curl_safefree(conn->allocptr.userpwd);
      Curl_safefree(conn->allocptr.accept_encoding);
      Curl_safefree(conn->allocptr.rangeline);
      Curl_safefree(conn->allocptr.ref);
      Curl_safefree(conn->allocptr.host);
      Curl_safefree(conn->allocptr.cookiehost);
      Curl_safefree(conn->ip_addr_str);
      Curl_safefree(conn->trailer);
      Curl_safefree(conn->host.rawalloc); /* host name buffer */
      Curl_safefree(conn->proxy.rawalloc); /* proxy name buffer */
    
    
      Curl_llist_destroy(conn->send_pipe, NULL);
      Curl_llist_destroy(conn->recv_pipe, NULL);
    
      /* possible left-overs from the async name resolvers */
    #if defined(USE_ARES)
      Curl_safefree(conn->async.hostname);
      Curl_safefree(conn->async.os_specific);
    #elif defined(CURLRES_THREADED)
      Curl_destroy_thread_data(&conn->async);
    #endif
    
    
      Curl_ssl_close(conn, FIRSTSOCKET);
      Curl_ssl_close(conn, SECONDARYSOCKET);
    
      Curl_free_ssl_config(&conn->ssl_config);
    
      free(conn); /* free all the connection oriented data */
    }
    
    
    CURLcode Curl_disconnect(struct connectdata *conn)
    
      struct SessionHandle *data;
    
      if(!conn)
        return CURLE_OK; /* this is closed and fine already */
    
      data = conn->data;
    
      if(!data) {
        DEBUGF(infof(data, "DISCONNECT without easy handle, ignoring\n"));
        return CURLE_OK;
      }
    
    
    #if defined(CURLDEBUG) && defined(AGGRESIVE_TEST)
      /* scan for DNS cache entries still marked as in use */
      Curl_hash_apply(data->hostcache,
                      NULL, Curl_scan_cache_used);
    #endif
    
    
      Curl_expire(data, 0); /* shut off timers */
    
      Curl_hostcache_prune(data); /* kill old DNS cache entries */
    
    
      if((conn->ntlm.state != NTLMSTATE_NONE) ||
    
         (conn->proxyntlm.state != NTLMSTATE_NONE)) {
    
        /* Authentication data is a mix of connection-related and sessionhandle-
           related stuff. NTLM is connection-related so when we close the shop
           we shall forget. */
    
        data->state.authhost.done = FALSE;
    
        data->state.authhost.picked =
    
          data->state.authhost.want;
    
        data->state.authproxy.done = FALSE;
    
        data->state.authproxy.picked =
    
          data->state.authproxy.want;
    
    
        data->state.authproblem = FALSE;
    
        /* This is set if protocol-specific cleanups should be made */
    
      if(-1 != conn->connectindex) {
    
        infof(data, "Closing connection #%ld\n", conn->connectindex);
    
        if(data->state.connc)
          /* only clear the table entry if we still know in which cache we
             used to be in */
          data->state.connc->connects[conn->connectindex] = NULL;
    
    #ifdef USE_LIBIDN
    
        idn_free(conn->host.encalloc); /* encoded host name buffer, must be freed
                                          with idn_free() since this was allocated
                                          by libidn */
    
        idn_free(conn->proxy.encalloc); /* encoded proxy name buffer, must be
                                           freed with idn_free() since this was
                                           allocated by libidn */
    
      /* Indicate to all handles on the pipe that we're dead */
    
        signalPipeClose(conn->send_pipe);
        signalPipeClose(conn->recv_pipe);
      }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    /*
     * This function should return TRUE if the socket is to be assumed to
     * be dead. Most commonly this happens when the server has closed the
     * connection due to inactivity.
     */
    
    static bool SocketIsDead(curl_socket_t sock)
    
    {
      int sval;
      bool ret_val = TRUE;
    
      sval = Curl_socket_ready(sock, CURL_SOCKET_BAD, 0);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        /* timeout */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      return ret_val;
    }
    
    
    static bool IsPipeliningPossible(const struct SessionHandle *handle)
    
      if(handle->multi && Curl_multi_canPipeline(handle->multi) &&
    
          (handle->set.httpreq == HTTPREQ_GET ||
           handle->set.httpreq == HTTPREQ_HEAD) &&
          handle->set.httpversion != CURL_HTTP_VERSION_1_0)
        return TRUE;
    
      return FALSE;
    }
    
    
    static bool IsPipeliningEnabled(const struct SessionHandle *handle)
    
      if(handle->multi && Curl_multi_canPipeline(handle->multi))
    
    CURLcode Curl_addHandleToPipeline(struct SessionHandle *data,
    
    #ifdef CURLDEBUG
      if(!IsPipeliningPossible(data)) {
        /* when not pipelined, there MUST be no handle in the list already */
    
          infof(data, "PIPE when no PIPE supposed!\n");
      }
    #endif
    
      if(!Curl_llist_insert_next(pipeline, pipeline->tail, data))
    
        return CURLE_OUT_OF_MEMORY;
      return CURLE_OK;
    
    int Curl_removeHandleFromPipeline(struct SessionHandle *handle,
    
          Curl_llist_remove(pipeline, curr, NULL);
    
    #if 0 /* this code is saved here as it is useful for debugging purposes */
    
    static void Curl_printPipeline(struct curl_llist *pipeline)
    
        struct SessionHandle *data = (struct SessionHandle *) curr->ptr;
    
        infof(data, "Handle in pipeline: %s\n", data->state.path);
    
        curr = curr->next;
      }
    }
    #endif
    
    bool Curl_isHandleAtHead(struct SessionHandle *handle,
    
      struct curl_llist_element *curr = pipeline->head;
    
    Yang Tse's avatar
    Yang Tse committed
        return (bool)(curr->ptr == handle);
    
    static struct SessionHandle* gethandleathead(struct curl_llist *pipeline)
    
      struct curl_llist_element *curr = pipeline->head;
    
    static void signalPipeClose(struct curl_llist *pipeline)
    
        struct curl_llist_element *next = curr->next;
        struct SessionHandle *data = (struct SessionHandle *) curr->ptr;
    
    
    #ifdef CURLDEBUG /* debug-only code */
        if(data->magic != CURLEASY_MAGIC_NUMBER) {
          /* MAJOR BADNESS */
    
          infof(data, "signalPipeClose() found BAAD easy handle\n");
    
        Curl_multi_handlePipeBreak(data);
    
        Curl_llist_remove(pipeline, curr, NULL);
    
     * Given one filled in connection struct (named needle), this function should
    
     * detect if there already is one that has all the significant details
    
     * exactly the same and thus should be used instead.
    
     *
     * If there is a match, this function returns TRUE - and has marked the
     * connection as 'in-use'. It must later be called with ConnectionDone() to
     * return back to 'idle' (unused) state.
    
    ConnectionExists(struct SessionHandle *data,
    
                     struct connectdata *needle,
                     struct connectdata **usethis)
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    {
    
      struct connectdata *check;
    
      bool canPipeline = IsPipeliningPossible(data);
    
      for(i=0; i< data->state.connc->num; i++) {
    
    Yang Tse's avatar
    Yang Tse committed
        size_t pipeLen = 0;
    
        /*
         * Note that if we use a HTTP proxy, we check connections to that
         * proxy and not to the actual remote server.
         */
    
        check = data->state.connc->connects[i];
    
        if(!check)
          /* NULL pointer means not filled-in entry */
          continue;
    
        pipeLen = check->send_pipe->size + check->recv_pipe->size;
    
    
          check->connectindex = i; /* Set this appropriately since it might have
                                      been set to -1 when the easy was removed
                                      from the multi */
        }
    
    
          /* can only happen within multi handles, and means that another easy
    
        /* ip_addr_str is NULL only if the resolving of the name hasn't completed
           yet and until then we don't re-use this connection */
    
                "Connection #%ld hasn't finished name resolve, can't reuse\n",
    
        if((check->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) || check->bits.close) {
    
          /* Don't pick a connection that hasn't connected yet or that is going to
             get closed. */
          infof(data, "Connection #%ld isn't open enough, can't reuse\n",
                check->connectindex);
    #ifdef CURLDEBUG
    
            infof(data, "BAD! Unconnected #%ld has a non-empty recv pipeline!\n",
                  check->connectindex);
          }
    #endif
          continue;
        }
    
    
          infof(data, "Connection #%ld has its pipeline full, can't reuse\n",
                check->connectindex);
    
          /* Make sure the pipe has only GET requests */
          struct SessionHandle* sh = gethandleathead(check->send_pipe);
          struct SessionHandle* rh = gethandleathead(check->recv_pipe);
    
        if((needle->protocol&PROT_SSL) != (check->protocol&PROT_SSL))
          /* don't do mixed SSL and non-SSL connections */
          continue;
    
    
        if(needle->bits.proxy != check->bits.proxy)
          /* don't do mixed proxy and non-proxy connections */
          continue;
    
        if(!needle->bits.httpproxy || needle->protocol&PROT_SSL ||
           (needle->bits.httpproxy && check->bits.httpproxy &&
            needle->bits.tunnel_proxy && check->bits.tunnel_proxy &&
            strequal(needle->proxy.name, check->proxy.name) &&
            (needle->port == check->port))) {
          /* The requested connection does not use a HTTP proxy or it uses SSL or
             it is a non-SSL protocol tunneled over the same http proxy name and
             port number */
    
    
          if(strequal(needle->protostr, check->protostr) &&
    
             strequal(needle->host.name, check->host.name) &&
    
             (needle->remote_port == check->remote_port) ) {
    
            if(needle->protocol & PROT_SSL) {
              /* This is SSL, verify that we're using the same
                 ssl options as well */
    
              if(!Curl_ssl_config_matches(&needle->ssl_config,
                                          &check->ssl_config)) {
    
                infof(data,
                      "Connection #%ld has different SSL parameters, "
                      "can't reuse\n",
                      check->connectindex );
    
            if((needle->protocol & PROT_FTP) ||
               ((needle->protocol & PROT_HTTP) &&
    
                (data->state.authhost.want==CURLAUTH_NTLM))) {
    
              /* This is FTP or HTTP+NTLM, verify that we're using the same name
                 and password as well */
    
              if(!strequal(needle->user, check->user) ||
                 !strequal(needle->passwd, check->passwd)) {
    
                /* one of them was different */
                continue;
              }
            }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          }
    
        else { /* The requested needle connection is using a proxy,
    
                  is the checked one using the same host, port and type? */
          if(check->bits.proxy &&
             (needle->proxytype == check->proxytype) &&
    
             strequal(needle->proxy.name, check->proxy.name) &&
    
             needle->port == check->port) {
            /* This is the same proxy connection, use it! */
    
            /* The check for a dead socket makes sense only in the
               non-pipelining case */
            bool dead = SocketIsDead(check->sock[FIRSTSOCKET]);
            if(dead) {
    
              infof(data, "Connection #%d seems to be dead!\n", i);
    
    
              Curl_disconnect(check); /* disconnect resources */
              data->state.connc->connects[i]=NULL; /* nothing here */
    
          check->inuse = TRUE; /* mark this as being in use so that no other
                                  handle in a multi stack may nick it */
    
            /* Mark the connection as being in a pipeline */
            check->is_in_pipeline = TRUE;
    
          *usethis = check;
          return TRUE; /* yes, we found one to use! */
    
      return FALSE; /* no matching connecting exists */
    }
    
    
    /*
     * This function frees/closes a connection in the connection cache. This
     * should take the previously set policy into account when deciding which
     * of the connections to kill.
     */
    
    ConnectionKillOne(struct SessionHandle *data)
    
      struct connectdata *conn;
    
      long highscore=-1;
      long connindex=-1;
      long score;
    
      struct timeval now;
    
      now = Curl_tvnow();
    
      for(i=0; data->state.connc && (i< data->state.connc->num); i++) {
        conn = data->state.connc->connects[i];
    
        /* Set higher score for the age passed since the connection was used */
        score = Curl_tvdiff(now, conn->now);
    
    
        if(score > highscore) {
          highscore = score;
          connindex = i;
        }
      }
      if(connindex >= 0) {
    
        /* Set the connection's owner correctly */
        conn = data->state.connc->connects[connindex];
        conn->data = data;
    
    
        /* the winner gets the honour of being disconnected */
    
    
        /* clean the array entry */
    
        data->state.connc->connects[connindex] = NULL;
    
      }
    
      return connindex; /* return the available index or -1 */
    }
    
    
    /* this connection can now be marked 'idle' */
    static void
    ConnectionDone(struct connectdata *conn)
    {
      conn->inuse = FALSE;
    
    /*
     * 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.
     */
    
    ConnectionStore(struct SessionHandle *data,
    
                    struct connectdata *conn)
    {
    
      for(i=0; i< data->state.connc->num; i++) {
        if(!data->state.connc->connects[i])
    
        /* there was no room available, kill one */
        i = ConnectionKillOne(data);
    
          infof(data, "Connection (#%d) was killed to make room (holds %d)\n",
                i, data->state.connc->num);
    
        else
          infof(data, "This connection did not fit in the connection cache\n");
    
      conn->connectindex = i; /* Make the child know where the pointer to this
                                 particular data is stored. But note that this -1
                                 if this is not within the cache and this is
                                 probably not checked for everywhere (yet). */
      conn->inuse = TRUE;
    
        /* Only do this if a true index was returned, if -1 was returned there
    
           is no room in the cache for an unknown reason and we cannot store
    
           this there.
    
           TODO: make sure we really can work with more handles than positions in
           the cache, or possibly we should (allow to automatically) resize the
           connection cache when we add more easy handles to a multi handle!
        */
        data->state.connc->connects[i] = conn; /* fill in this */
        conn->data = data;
    
    static CURLcode ConnectPlease(struct SessionHandle *data,
                                  struct connectdata *conn,
    
      CURLcode result;
    
    Yang Tse's avatar
    Yang Tse committed
    #ifndef CURL_DISABLE_VERBOSE_STRINGS
    
      char *hostname = conn->bits.proxy?conn->proxy.name:conn->host.name;
    
      infof(data, "About to connect() to %s%s port %d (#%d)\n",
    
            hostname, conn->port, conn->connectindex);
    
    Yang Tse's avatar
    Yang Tse committed
    #endif
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
      /*************************************************************
    
       * Connect to server/proxy
    
       *************************************************************/
    
      result= Curl_connecthost(conn,
    
      if(CURLE_OK == result) {
    
        /* All is cool, then we store the current information */
        conn->dns_entry = hostaddr;
        conn->ip_addr = addr;
    
        result = Curl_store_ip_addr(conn);
    
        if(CURLE_OK == result) {
    
          switch(data->set.proxytype) {
          case CURLPROXY_SOCKS5:
    
          case CURLPROXY_SOCKS5_HOSTNAME:
            result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd,
                                 conn->host.name, conn->remote_port,
                                 FIRSTSOCKET, conn);
    
          case CURLPROXY_HTTP:
    
            /* do nothing here. handled later. */
            break;
    
          case CURLPROXY_SOCKS4:
    
            result = Curl_SOCKS4(conn->proxyuser, conn->host.name,
    
                                 conn->remote_port, FIRSTSOCKET, conn, FALSE);
    
            break;
          case CURLPROXY_SOCKS4A:
            result = Curl_SOCKS4(conn->proxyuser, conn->host.name,
    
                                 conn->remote_port, FIRSTSOCKET, conn, TRUE);
    
            failf(data, "unknown proxytype option given");
            result = CURLE_COULDNT_CONNECT;
            break;
    
      if(result)
        *connected = FALSE; /* mark it as not connected */
    
      return result;
    
     * verboseconnect() displays verbose information after a connect
    
    Yang Tse's avatar
    Yang Tse committed
    #ifndef CURL_DISABLE_VERBOSE_STRINGS
    
    static void verboseconnect(struct connectdata *conn)
    
      infof(conn->data, "Connected to %s (%s) port %d (#%d)\n",
    
            conn->bits.proxy ? conn->proxy.dispname : conn->host.dispname,
    
            conn->ip_addr_str, conn->port, conn->connectindex);
    
    Yang Tse's avatar
    Yang Tse committed
    #endif
    
    int Curl_protocol_getsock(struct connectdata *conn,
                              curl_socket_t *socks,
                              int numsocks)
    
      if(conn->handler->proto_getsock)
        return conn->handler->proto_getsock(conn, socks, numsocks);
    
    int Curl_doing_getsock(struct connectdata *conn,
                           curl_socket_t *socks,
                           int numsocks)
    
      if(conn && conn->handler->doing_getsock)
    
        return conn->handler->doing_getsock(conn, socks, numsocks);
    
    }
    
    /*
     * We are doing protocol-specific connecting and this is being called over and
     * over from the multi interface until the connection phase is done on
     * protocol layer.
     */
    
    
    CURLcode Curl_protocol_connecting(struct connectdata *conn,
                                      bool *done)
    
      if(conn && conn->handler->connecting) {
    
        result = conn->handler->connecting(conn, done);
    
      }
      else
        *done = TRUE;
    
      return result;
    }
    
    /*
     * We are DOING this is being called over and over from the multi interface
     * until the DOING phase is done on protocol layer.
     */
    
    CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done)
    {
      CURLcode result=CURLE_OK;
    
    
        result = conn->handler->doing(conn, done);
    
    /*
     * We have discovered that the TCP connection has been successful, we can now
     * proceed with some action.
     *
     */
    
    CURLcode Curl_protocol_connect(struct connectdata *conn,
                                   bool *protocol_done)
    
      struct SessionHandle *data = conn->data;
    
      *protocol_done = FALSE;
    
      if(conn->bits.tcpconnect && conn->bits.protoconnstart) {
    
        /* We already are connected, get back. This may happen when the connect
           worked fine in the first call, like when we connect to a local server
    
           or proxy. Note that we don't know if the protocol is actually done.
    
           Unless this protocol doesn't have any protocol-connect callback, as
           then we know we're done. */
    
        Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
    
          /* 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->handler->connect_it(conn, protocol_done);
    
        }
        else
          *protocol_done = TRUE;
    
        /* it has started, possibly even completed but that knowledge isn't stored
           in this bit! */
    
    /*
     * Helpers for IDNA convertions.
     */
    #ifdef USE_LIBIDN
    
    static bool is_ASCII_name(const char *hostname)
    
    {
      const unsigned char *ch = (const unsigned char*)hostname;
    
    
    Gisle Vanem's avatar
     
    Gisle Vanem committed
    
    /*
     * Check if characters in hostname is allowed in Top Level Domain.
     */
    
    static bool tld_check_name(struct SessionHandle *data,
                               const char *ace_hostname)
    
    Gisle Vanem's avatar
     
    Gisle Vanem committed
    {
      size_t err_pos;
      char *uc_name = NULL;
      int rc;
    
    Yang Tse's avatar
    Yang Tse committed
    #ifndef CURL_DISABLE_VERBOSE_STRINGS
    
      char *tld_errmsg = (char *)"<no msg>";
    
    Yang Tse's avatar
    Yang Tse committed
    #else
      (void)data;
    #endif
    
    Gisle Vanem's avatar
     
    Gisle Vanem committed
    
      /* Convert (and downcase) ACE-name back into locale's character set */
      rc = idna_to_unicode_lzlz(ace_hostname, &uc_name, 0);
    
    Gisle Vanem's avatar
     
    Gisle Vanem committed
        return (FALSE);
    
    Gisle Vanem's avatar
     
    Gisle Vanem committed
    
      rc = tld_check_lz(uc_name, &err_pos, NULL);
    
    Yang Tse's avatar
    Yang Tse committed
    #ifndef CURL_DISABLE_VERBOSE_STRINGS
    
    Yang Tse's avatar
    Yang Tse committed
        tld_errmsg = (char *)tld_strerror((Tld_rc)rc);
    
    Yang Tse's avatar
    Yang Tse committed
        infof(data, "WARNING: %s; pos %u = `%c'/0x%02X\n",
              tld_errmsg, err_pos, uc_name[err_pos],
              uc_name[err_pos] & 255);
    
    Yang Tse's avatar
    Yang Tse committed
        infof(data, "WARNING: TLD check for %s failed; %s\n",
              uc_name, tld_errmsg);
    #endif /* CURL_DISABLE_VERBOSE_STRINGS */
    
    Gisle Vanem's avatar
     
    Gisle Vanem committed
         idn_free(uc_name);
    
    Yang Tse's avatar
    Yang Tse committed
      return (bool)(rc == TLD_SUCCESS);
    
    Gisle Vanem's avatar
     
    Gisle Vanem committed
    }
    
    static void fix_hostname(struct SessionHandle *data,
                             struct connectdata *conn, struct hostname *host)
    
    Yang Tse's avatar
    Yang Tse committed
    #ifndef USE_LIBIDN
      (void)data;
      (void)conn;
    #elif defined(CURL_DISABLE_VERBOSE_STRINGS)
      (void)conn;
    #endif
    
    
      /* set the name we use to display the host name */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      host->dispname = host->name;
    
    
    #ifdef USE_LIBIDN
      /*************************************************************
       * Check name for non-ASCII and convert hostname to ACE form.
       *************************************************************/
    
          stringprep_check_version(LIBIDN_REQUIRED_VERSION)) {
    
        char *ace_hostname = NULL;
        int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0);
        infof (data, "Input domain encoded as `%s'\n",
               stringprep_locale_charset ());
    
          infof(data, "Failed to convert %s to ACE; %s\n",
                host->name, Curl_idn_strerror(conn,rc));
    
          /* tld_check_name() displays a warning if the host name contains
             "illegal" characters for this TLD */
          (void)tld_check_name(data, ace_hostname);
    
    Gisle Vanem's avatar
     
    Gisle Vanem committed
    
    
          host->encalloc = ace_hostname;
          /* change the name pointer to point to the encoded hostname */
          host->name = host->encalloc;
        }
      }
    
    Gisle Vanem's avatar
    Gisle Vanem committed
    #endif
    
    /*
     * Parse URL and fill in the relevant members of the connection struct.
    
    static CURLcode ParseURLAndFillConnection(struct SessionHandle *data,
                                              struct connectdata *conn)
    
    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->change.url, "%15[^:]:%[^\n]",
    
                      path)) && strequal(conn->protostr, "file")) {
        if(path[0] == '/' && path[1] == '/') {
    
          /* Allow omitted hostname (e.g. file:/<path>).  This is not strictly
           * speaking a valid file: URL by RFC 1738, but treating file:/<path> as
           * file://localhost/<path> is similar to how other schemes treat missing
           * hostnames.  See RFC 1808. */
    
          /* This cannot be done with strcpy() in a portable manner, since the
             memory areas overlap! */
    
          memmove(path, path + 2, strlen(path + 2)+1);
    
    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
         */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          /* the URL included a host name, we ignore host names in file:// URLs
             as the standards don't define what to do with them */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          if(ptr) {
            /* there was a slash present
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
               RFC1738 (section 3.1, page 5) says:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
               The rest of the locator consists of data specific to the scheme,
               and is known as the "url-path". It supplies the details of how the
               specified resource can be accessed. Note that the "/" between the
               host (or port) and the url-path is NOT part of the url-path.
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
               As most agents use file://localhost/foo to get '/foo' although the
    
               slash preceding foo is a separator and not a slash for the path,
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
               a URL as file://localhost//foo must be valid as well, to refer to
               the same file with an absolute path.
            */
    
            if(ptr[1] && ('/' == ptr[1]))
              /* if there was two slashes, we skip the first one as that is then
                 used truly as a separator */
    
            /* This cannot be made with strcpy, as the memory chunks overlap! */
    
        strcpy(conn->protostr, "file"); /* store protocol string lowercase */
    
    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->change.url, "%[^\n/]%[^\n]",
    
    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.
           */