Skip to content
Snippets Groups Projects
url.c 47.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • Daniel Stenberg's avatar
    Daniel Stenberg committed
    /*****************************************************************************
     *                                  _   _ ____  _     
     *  Project                     ___| | | |  _ \| |    
     *                             / __| | | | |_) | |    
     *                            | (__| |_| |  _ <| |___ 
     *                             \___|\___/|_| \_\_____|
     *
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     * Copyright (C) 2000, Daniel Stenberg, <daniel@haxx.se>, et al.
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     *
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     * In order to be useful for every potential user, curl and libcurl are
     * dual-licensed under the MPL and the MIT/X-derivate licenses.
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     *
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     * 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.
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     *
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     * KIND, either express or implied.
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     *
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     * $Id$
     *****************************************************************************/
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    /* -- WIN32 approved -- */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #include <stdio.h>
    #include <string.h>
    #include <stdarg.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    
    #include <errno.h>
    
    #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
    #include <winsock.h>
    #include <time.h>
    #include <io.h>
    #else
    #ifdef HAVE_SYS_SOCKET_H
    #include <sys/socket.h>
    #endif
    #include <netinet/in.h>
    #include <sys/time.h>
    #include <sys/resource.h>
    #ifdef HAVE_UNISTD_H
    #include <unistd.h>
    #endif
    #include <netdb.h>
    #ifdef HAVE_ARPA_INET_H
    #include <arpa/inet.h>
    #endif
    #ifdef HAVE_NET_IF_H
    #include <net/if.h>
    #endif
    #include <sys/ioctl.h>
    #include <signal.h>
    
    #ifdef HAVE_SYS_PARAM_H
    #include <sys/param.h>
    #endif
    
    #ifdef HAVE_SYS_SELECT_H
    #include <sys/select.h>
    #endif
    
    #ifndef HAVE_SELECT
    #error "We can't compile without select() support!"
    #endif
    #ifndef HAVE_SOCKET
    #error "We can't compile without socket() support!"
    #endif
    
    #endif
    
    #include "urldata.h"
    #include "netrc.h"
    
    #include "formdata.h"
    #include "base64.h"
    #include "ssluse.h"
    #include "hostip.h"
    #include "if2ip.h"
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #include "sendf.h"
    #include "getpass.h"
    #include "progress.h"
    #include "cookie.h"
    
    #include "strequal.h"
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    /* And now for the protocols */
    #include "ftp.h"
    #include "dict.h"
    #include "telnet.h"
    #include "http.h"
    #include "file.h"
    #include "ldap.h"
    
    
    #include <curl/types.h>
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    #define _MPRINTF_REPLACE /* use our functions only */
    #include <curl/mprintf.h>
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #ifdef KRB4
    #include "security.h"
    #endif
    
    /* The last #include file should be: */
    #ifdef MALLOCDEBUG
    #include "memdebug.h"
    #endif
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    /* -- -- */
    
    
    
    CURLcode _urlget(struct UrlData *data);
    
    /* does nothing, returns OK */
    CURLcode curl_init(void)
    
      return CURLE_OK;
    
    /* does nothing */
    
    void static urlfree(struct UrlData *data, bool totally)
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    {
    #ifdef USE_SSLEAY
    
      if (data->ssl.use) {
        if(data->ssl.handle) {
          (void)SSL_shutdown(data->ssl.handle);
          SSL_set_connect_state(data->ssl.handle);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
          SSL_free (data->ssl.handle);
          data->ssl.handle = NULL;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        }
    
        if(data->ssl.ctx) {
          SSL_CTX_free (data->ssl.ctx);
          data->ssl.ctx = NULL;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        }
    
        data->ssl.use = FALSE; /* get back to ordinary socket usage */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      }
    #endif /* USE_SSLEAY */
    
      /* close possibly still open sockets */
      if(-1 != data->secondarysocket) {
        sclose(data->secondarysocket);
        data->secondarysocket = -1;	
      }
      if(-1 != data->firstsocket) {
        sclose(data->firstsocket);
        data->firstsocket=-1;
      }
    
    
      if(data->bits.proxystringalloc) {
    
        data->bits.proxystringalloc=FALSE;;
    
        free(data->proxy);
        data->proxy=NULL;
    
    
        /* Since we allocated the string the previous round, it means that we
           "discovered" the proxy in the environment variables and thus we must
           switch off that knowledge again... */
        data->bits.httpproxy=FALSE;
    
      
      if(data->bits.rangestringalloc) {
        free(data->range);
        data->range=NULL;
    
        data->bits.rangestringalloc=0; /* free now */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
      if(data->ptr_proxyuserpwd) {
        free(data->ptr_proxyuserpwd);
        data->ptr_proxyuserpwd=NULL;
      }
      if(data->ptr_uagent) {
        free(data->ptr_uagent);
        data->ptr_uagent=NULL;
      }
      if(data->ptr_userpwd) {
        free(data->ptr_userpwd);
        data->ptr_userpwd=NULL;
      }
      if(data->ptr_rangeline) {
        free(data->ptr_rangeline);
        data->ptr_rangeline=NULL;
      }
      if(data->ptr_ref) {
        free(data->ptr_ref);
        data->ptr_ref=NULL;
      }
      if(data->ptr_cookie) {
        free(data->ptr_cookie);
        data->ptr_cookie=NULL;
      }
      if(data->ptr_host) {
        free(data->ptr_host);
        data->ptr_host=NULL;
      }
    
      if(totally) {
        /* we let the switch decide whether we're doing a part or total
           cleanup */
    
        /* check for allocated [URL] memory to free: */
        if(data->freethis)
          free(data->freethis);
    
        if(data->headerbuff)
          free(data->headerbuff);
    
    
        if(data->free_referer)
          free(data->referer);
    
    
        if(data->bits.urlstringalloc)
          /* the URL is allocated, free it! */
          free(data->url);
    
    
        Curl_cookie_cleanup(data->cookies);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
        free(data);
    
    
    CURLcode curl_close(CURL *curl)
    {
      struct UrlData *data=(struct UrlData *)curl;
      
      void *protocol = data->proto.generic;
    
    
      /* total session cleanup (frees 'data' as well!)*/
    
      urlfree(data, TRUE);
    
      if(protocol)
        free(protocol);
    
      return CURLE_OK;
    }
    
    int my_getpass(void *clientp, char *prompt, char* buffer, int buflen )
    {
    
      char *retbuf;
      retbuf = getpass_r(prompt, buffer, buflen);
      if(NULL == retbuf)
        return 1;
      else
        return 0; /* success */
    
    CURLcode curl_open(CURL **curl, char *url)
    
    {
      /* We don't yet support specifying the URL at this point */
    
      struct UrlData *data;
    
    
      /* Very simple start-up: alloc the struct, init it with zeroes and return */
    
      data = (struct UrlData *)malloc(sizeof(struct UrlData));
    
        memset(data, 0, sizeof(struct UrlData));
        data->handle = STRUCT_OPEN;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->interf = CURLI_NORMAL; /* normal interface by default */
    
    
        /* We do some initial setup here, all those fields that can't be just 0 */
    
        data-> headerbuff=(char*)malloc(HEADERSIZE);
        if(!data->headerbuff) {
          free(data); /* free the memory again */
          return CURLE_OUT_OF_MEMORY;
        }
    
        data-> headersize=HEADERSIZE;
    
        data->out = stdout; /* default output to stdout */
        data->in  = stdin;  /* default input from stdin */
        data->err  = stderr;  /* default stderr to stderr */
    
        data->firstsocket = -1; /* no file descriptor */
        data->secondarysocket = -1; /* no file descriptor */
    
        /* use fwrite as default function to store output */
        data->fwrite = (size_t (*)(char *, size_t, size_t, FILE *))fwrite;
    
        /* use fread as default function to read input */
        data->fread = (size_t (*)(char *, size_t, size_t, FILE *))fread;
    
    
        /* set the default passwd function */
        data->fpasswd = my_getpass;
    
    
        data->infilesize = -1; /* we don't know any size */
    
        data->current_speed = -1; /* init to negative == impossible */
    
    
        data->httpreq = HTTPREQ_GET; /* Default HTTP request */
    
    
        return CURLE_OK;
    
      }
    
      /* this is a very serious error */
    
      return CURLE_OUT_OF_MEMORY;
    
    CURLcode curl_setopt(CURL *curl, CURLoption option, ...)
    
    {
      struct UrlData *data = curl;
      va_list param;
      char *cookiefile;
    
      va_start(param, option);
    
      switch(option) {
    
      case CURLOPT_VERBOSE:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.verbose = va_arg(param, long)?TRUE:FALSE;
    
        break;
      case CURLOPT_HEADER:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.http_include_header = va_arg(param, long)?TRUE:FALSE;
    
        break;
      case CURLOPT_NOPROGRESS:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.hide_progress = va_arg(param, long)?TRUE:FALSE;
    
        if(data->bits.hide_progress)
          data->progress.flags |= PGRS_HIDE;
        break;
      case CURLOPT_NOBODY:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.no_body = va_arg(param, long)?TRUE:FALSE;
    
        break;
      case CURLOPT_FAILONERROR:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.http_fail_on_error = va_arg(param, long)?TRUE:FALSE;
    
        break;
      case CURLOPT_UPLOAD:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.upload = va_arg(param, long)?TRUE:FALSE;
    
        if(data->bits.upload)
          /* If this is HTTP, PUT is what's needed to "upload" */
          data->httpreq = HTTPREQ_PUT;
    
        break;
      case CURLOPT_POST:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.http_post = va_arg(param, long)?TRUE:FALSE;
    
        if(data->bits.http_post)
          data->httpreq = HTTPREQ_POST;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      case CURLOPT_FILETIME:
        data->bits.get_filetime = va_arg(param, long)?TRUE:FALSE;
        break;
    
      case CURLOPT_FTPLISTONLY:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.ftp_list_only = va_arg(param, long)?TRUE:FALSE;
    
        break;
      case CURLOPT_FTPAPPEND:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.ftp_append = va_arg(param, long)?TRUE:FALSE;
    
        break;
      case CURLOPT_NETRC:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.use_netrc = va_arg(param, long)?TRUE:FALSE;
    
        break;
      case CURLOPT_FOLLOWLOCATION:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.http_follow_location = va_arg(param, long)?TRUE:FALSE;
    
        break;
      case CURLOPT_FTPASCII:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.ftp_ascii = va_arg(param, long)?TRUE:FALSE;
    
        break;
      case CURLOPT_PUT:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.http_put = va_arg(param, long)?TRUE:FALSE;
    
        if(data->bits.http_put)
          data->httpreq = HTTPREQ_PUT;
    
        break;
      case CURLOPT_MUTE:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.mute = va_arg(param, long)?TRUE:FALSE;
    
        break;
      case CURLOPT_TIMECONDITION:
    
        data->timecondition = va_arg(param, long);
        break;
    
      case CURLOPT_TIMEVALUE:
    
        data->timevalue = va_arg(param, long);
        break;
    
      case CURLOPT_SSLVERSION:
    
        data->ssl.version = va_arg(param, long);
    
      case CURLOPT_COOKIEFILE:
    
        cookiefile = (char *)va_arg(param, void *);
        if(cookiefile) {
    
          data->cookies = Curl_cookie_init(cookiefile);
    
      case CURLOPT_WRITEHEADER:
    
        data->writeheader = (FILE *)va_arg(param, FILE *);
        break;
    
      case CURLOPT_COOKIE:
    
        data->cookie = va_arg(param, char *);
        break;
    
      case CURLOPT_ERRORBUFFER:
    
        data->errorbuffer = va_arg(param, char *);
        break;
    
      case CURLOPT_FILE:
    
        data->out = va_arg(param, FILE *);
        break;
    
      case CURLOPT_FTPPORT:
    
        data->ftpport = va_arg(param, char *);
    
        data->bits.ftp_use_port = data->ftpport?1:0;
    
      case CURLOPT_HTTPHEADER:
    
        data->headers = va_arg(param, struct curl_slist *);
    
      case CURLOPT_CUSTOMREQUEST:
    
        data->customrequest = va_arg(param, char *);
    
        if(data->customrequest)
          data->httpreq = HTTPREQ_CUSTOM;
    
      case CURLOPT_HTTPPOST:
    
        data->httppost = va_arg(param, struct HttpPost *);
    
        data->bits.http_formpost = data->httppost?1:0;
    
        if(data->bits.http_formpost)
          data->httpreq = HTTPREQ_POST_FORM;
    
      case CURLOPT_INFILE:
    
        data->in = va_arg(param, FILE *);
        break;
    
      case CURLOPT_INFILESIZE:
    
        data->infilesize = va_arg(param, long);
        break;
    
      case CURLOPT_LOW_SPEED_LIMIT:
    
        data->low_speed_limit=va_arg(param, long);
        break;
    
      case CURLOPT_LOW_SPEED_TIME:
    
        data->low_speed_time=va_arg(param, long);
        break;
    
      case CURLOPT_URL:
    
        data->url = va_arg(param, char *);
        break;
    
      case CURLOPT_PORT:
    
      case CURLOPT_POSTFIELDS:
    
        data->postfields = va_arg(param, char *);
        break;
    
      case CURLOPT_POSTFIELDSIZE:
        data->postfieldsize = va_arg(param, long);
        break;
    
      case CURLOPT_REFERER:
    
        data->referer = va_arg(param, char *);
    
        data->bits.http_set_referer = (data->referer && *data->referer)?1:0;
    
      case CURLOPT_AUTOREFERER:
        data->bits.http_auto_referer = va_arg(param, long)?1:0;
        break;
    
      case CURLOPT_PROXY:
    
        data->proxy = va_arg(param, char *);
    
        data->bits.httpproxy = data->proxy?1:0;
    
      case CURLOPT_HTTPPROXYTUNNEL:
        data->bits.tunnel_thru_httpproxy = va_arg(param, long)?TRUE:FALSE;
        break;
    
      case CURLOPT_PROXYPORT:
        data->proxyport = va_arg(param, long);
    
      case CURLOPT_TIMEOUT:
    
        data->timeout = va_arg(param, long);
        break;
    
      case CURLOPT_MAXREDIRS:
        data->maxredirs = va_arg(param, long);
        break;
    
      case CURLOPT_USERAGENT:
    
        data->useragent = va_arg(param, char *);
        break;
    
      case CURLOPT_USERPWD:
    
        data->userpwd = va_arg(param, char *);
    
        data->bits.user_passwd = data->userpwd?1:0;
    
      case CURLOPT_POSTQUOTE:
    
        data->postquote = va_arg(param, struct curl_slist *);
        break;
    
      case CURLOPT_PROGRESSFUNCTION:
        data->fprogress = va_arg(param, curl_progress_callback);
    
        data->progress.callback = TRUE; /* no longer internal */
    
        break;
      case CURLOPT_PROGRESSDATA:
        data->progress_client = va_arg(param, void *);
        break;
    
      case CURLOPT_PASSWDFUNCTION:
        data->fpasswd = va_arg(param, curl_passwd_callback);
        break;
      case CURLOPT_PASSWDDATA:
        data->passwd_client = va_arg(param, void *);
        break;
    
      case CURLOPT_PROXYUSERPWD:
    
        data->proxyuserpwd = va_arg(param, char *);
    
        data->bits.proxy_user_passwd = data->proxyuserpwd?1:0;
    
      case CURLOPT_RANGE:
    
        data->range = va_arg(param, char *);
    
        data->bits.set_range = data->range?1:0;
    
      case CURLOPT_RESUME_FROM:
    
        data->resume_from = va_arg(param, long);
        break;
    
      case CURLOPT_STDERR:
    
        data->err = va_arg(param, FILE *);
        break;
    
      case CURLOPT_WRITEFUNCTION:
    
        data->fwrite = va_arg(param, curl_write_callback);
    
      case CURLOPT_READFUNCTION:
    
        data->fread = va_arg(param, curl_read_callback);
    
      case CURLOPT_SSLCERT:
    
        data->cert = va_arg(param, char *);
        break;
    
      case CURLOPT_SSLCERTPASSWD:
    
        data->cert_passwd = va_arg(param, char *);
        break;
    
      case CURLOPT_CRLF:
    
        data->crlf = va_arg(param, long);
        break;
    
      case CURLOPT_QUOTE:
    
        data->quote = va_arg(param, struct curl_slist *);
        break;
    
      case CURLOPT_INTERFACE:
        data->device = va_arg(param, char *);
        break;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      case CURLOPT_KRB4LEVEL:
        data->krb4_level = va_arg(param, char *);
        data->bits.krb4=data->krb4_level?TRUE:FALSE;
        break;
    
      case CURLOPT_SSL_VERIFYPEER:
        data->ssl.verifypeer = va_arg(param, long);
        break;
      case CURLOPT_CAINFO:
        data->ssl.CAfile = va_arg(param, char *);
        data->ssl.CApath = NULL; /*This does not work on windows.*/
        break;
    
      default:
        /* unknown tag and its companion, just ignore: */
    
        return CURLE_READ_ERROR; /* correct this */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      }
    
      return CURLE_OK;
    
    #if !defined(WIN32)||defined(__CYGWIN32__)
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #ifndef RETSIGTYPE
    #define RETSIGTYPE void
    #endif
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    RETSIGTYPE alarmfunc(int signal)
    {
      /* this is for "-ansi -Wall -pedantic" to stop complaining!   (rabe) */
      (void)signal;
      return;
    }
    #endif
    
    
    CURLcode curl_disconnect(CURLconnect *c_connect)
    {
      struct connectdata *conn = c_connect;
    
      struct UrlData *data = conn->data;
    
    
    #ifdef ENABLE_IPV6
      if(conn->res) /* host name info */
        freeaddrinfo(conn->res);
    #else
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      if(conn->hostent_buf) /* host name info */
        free(conn->hostent_buf);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
      if(conn->path) /* the URL path part */
        free(conn->path);
    
    
      free(conn); /* free the connection oriented data */
    
    
      /* clean up the sockets and SSL stuff from the previous "round" */
      urlfree(data, FALSE);
    
      return CURLE_OK;
    }
    
    
    static CURLcode _connect(CURL *curl, CURLconnect **in_connect)
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    {
    
      char *tmp;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      char *buf;
    
      CURLcode result;
    
      struct UrlData *data = curl;
      struct connectdata *conn;
    
    #ifdef HAVE_SIGACTION
      struct sigaction sigact;
    #endif
    
      int urllen;
    
    #ifdef ENABLE_IPV6
      struct addrinfo *ai;
    #endif
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /*************************************************************
       * Check input data
       *************************************************************/
    
    
      if(!data || (data->handle != STRUCT_OPEN))
        return CURLE_BAD_FUNCTION_ARGUMENT; /* TBD: make error codes */
    
      if(!data->url)
        return CURLE_URL_MALFORMAT;
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /*************************************************************
       * Allocate and initiate a connection struct
       *************************************************************/
    
      conn = (struct connectdata *)malloc(sizeof(struct connectdata));
      if(!conn) {
        *in_connect = NULL; /* clear the pointer */
        return CURLE_OUT_OF_MEMORY;
      }
      *in_connect = conn;
    
      memset(conn, 0, sizeof(struct connectdata));
      conn->handle = STRUCT_CONNECT;
    
      conn->data = data; /* remember our daddy */
      conn->state = CONN_INIT;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
      conn->upload_bufsize = UPLOAD_BUFSIZE; /* the smallest upload buffer size
                                                we use */
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      buf = data->buffer; /* this is our buffer */
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /*************************************************************
       * Set signal handler
       *************************************************************/
    
    #ifdef HAVE_SIGACTION
      sigaction(SIGALRM, NULL, &sigact);
      sigact.sa_handler = alarmfunc;
    
    #ifdef SA_RESTART
      /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */
    
    #else
      /* no sigaction(), revert to the much lamer signal() */
    #ifdef HAVE_SIGNAL
      signal(SIGALRM, alarmfunc);
    #endif
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #endif
    
    
    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->proto,
                      conn->path)) && strequal(conn->proto, "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]);
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        strcpy(conn->proto, "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->proto, 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->proto, "ftp");
          }
          else if(strnequal(conn->gname, "GOPHER", 6))
            strcpy(conn->proto, "gopher");
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #ifdef USE_SSLEAY
    
          else if(strnequal(conn->gname, "HTTPS", 5))
            strcpy(conn->proto, "https");
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #endif /* USE_SSLEAY */
    
          else if(strnequal(conn->gname, "TELNET", 6))
            strcpy(conn->proto, "telnet");
          else if (strnequal(conn->gname, "DICT", sizeof("DICT")-1))
            strcpy(conn->proto, "DICT");
          else if (strnequal(conn->gname, "LDAP", sizeof("LDAP")-1))
            strcpy(conn->proto, "LDAP");
          else {
            strcpy(conn->proto, "http");
          }
    
          conn->protocol |= PROT_MISSING; /* not given in URL */
        }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /*************************************************************
       * Take care of user and password authentication stuff
       *************************************************************/
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
      if(data->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
       *************************************************************/
    
      if(data->bits.proxy_user_passwd) {
    
        data->proxyuser[0] =0;
        data->proxypasswd[0]=0;
    
        if(*data->proxyuserpwd != ':') {
          /* the name is given, get user+password */
    
          sscanf(data->proxyuserpwd, "%127[^:]:%127[^\n]",
    
                 data->proxyuser, data->proxypasswd);
    
    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;
      data->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.
         */
    
    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(no_proxy, ", "):NULL;
          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(NULL, ", ");
          }
          if(!nope) {
    	/* It was not listed as without proxy */
    
    	char *protop = conn->proto;
    
    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
    
    
    	if(!prox) {
              /* 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 */
    
                proxy=curl_getenv("ALL_PROXY");
    
    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->proto, 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.
       ***********************************************************/
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      if(data->resume_from) {
    
        if(!data->bits.set_range) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          /* if it already was in use, we just skip this */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          snprintf(resumerange, sizeof(resumerange), "%d-", data->resume_from);
    
          data->range=strdup(resumerange); /* tell ourselves to fetch this range */
          data->bits.rangestringalloc = TRUE; /* mark as allocated */
    
          data->bits.set_range = 1; /* switch on range usage */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /*************************************************************
       * Set timeout if that is being used
       *************************************************************/
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      if(data->timeout) {
        /* 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 */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        myalarm(data->timeout); /* this sends a signal when the timeout fires
    			       off, and that will abort system calls */
      }
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /*************************************************************
       * Setup internals depending on protocol
       *************************************************************/
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
      if (strequal(conn->proto, "HTTP")) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        if(!data->port)
          data->port = PORT_HTTP;
        data->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->proto, "HTTPS")) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #ifdef USE_SSLEAY
        if(!data->port)
          data->port = PORT_HTTPS;
        data->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->proto, "GOPHER")) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        if(!data->port)
          data->port = PORT_GOPHER;
        data->remote_port = PORT_GOPHER;
        /* 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
      }
    
      else if(strequal(conn->proto, "FTP")) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        char *type;
        if(!data->port)
          data->port = PORT_FTP;
        data->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 */
    
          conn->curl_do = Curl_http;
          conn->curl_done = Curl_http_done;