Skip to content
Snippets Groups Projects
url.c 42.9 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 "getenv.h"
    #include "base64.h"
    #include "ssluse.h"
    #include "hostip.h"
    #include "if2ip.h"
    #include "download.h"
    #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 */
    
    
        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;
    
        break;
      case CURLOPT_POST:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.http_post = va_arg(param, long)?TRUE:FALSE;
    
    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;
    
        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 *);
        break;
    
      case CURLOPT_HTTPPOST:
    
        data->httppost = va_arg(param, struct HttpPost *);
    
        data->bits.http_formpost = data->httppost?1:0;
    
      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;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    }
    
    #ifndef WIN32
    #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_write(CURLconnect *c_conn, char *buf, size_t amount,
                       size_t *n)
    {
      struct connectdata *conn = (struct connectdata *)c_conn;
      struct UrlData *data;
      size_t bytes_written;
    
      if(!n || !conn || (conn->handle != STRUCT_CONNECT))
        return CURLE_FAILED_INIT;
      data = conn->data;
    
    #ifdef USE_SSLEAY
    
      if (data->ssl.use) {
        bytes_written = SSL_write(data->ssl.handle, buf, amount);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #ifdef KRB4
        if(conn->sec_complete)
    
          bytes_written = sec_write(conn, conn->writesockfd, buf, amount);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        else
    #endif
          bytes_written = swrite(conn->writesockfd, buf, amount);
    
    #ifdef USE_SSLEAY
      }
    #endif /* USE_SSLEAY */
    
      *n = bytes_written;
      return CURLE_OK;
    }
    
    CURLcode curl_read(CURLconnect *c_conn, char *buf, size_t buffersize,
                       size_t *n)
    {
      struct connectdata *conn = (struct connectdata *)c_conn;
      struct UrlData *data;
      size_t nread;
    
      if(!n || !conn || (conn->handle != STRUCT_CONNECT))
        return CURLE_FAILED_INIT;
      data = conn->data;
    
    #ifdef USE_SSLEAY
    
      if (data->ssl.use) {
        nread = SSL_read (data->ssl.handle, buf, buffersize);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #ifdef KRB4
        if(conn->sec_complete)
          nread = sec_read(conn, conn->sockfd, buf, buffersize);
        else
    #endif
          nread = sread (conn->sockfd, buf, buffersize);
    
    #ifdef USE_SSLEAY
      }
    #endif /* USE_SSLEAY */
      *n = nread;
      return CURLE_OK;
    }
    
    CURLcode curl_disconnect(CURLconnect *c_connect)
    {
      struct connectdata *conn = c_connect;
    
      struct UrlData *data = conn->data;
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      if(conn->hostent_buf) /* host name info */
        free(conn->hostent_buf);
    
    
      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;
    
    
      if(!data || (data->handle != STRUCT_OPEN))
        return CURLE_BAD_FUNCTION_ARGUMENT; /* TBD: make error codes */
    
      if(!data->url)
        return CURLE_URL_MALFORMAT;
    
      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 */
    
    
    #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
    
    
      /* 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 <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 protocols specified in RFC 1738 */
        if (strnequal(conn->path, "localhost/", 10) ||
            strnequal(conn->path, "127.0.0.1/", 10))
          /* ... since coincidentally both host strings are of equal length
             otherwise, <host>/ is quietly ommitted */
          strcpy(conn->path, &conn->path[10]);
    
        strcpy(conn->proto, "file");
    
    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
          
    
          /* badly formatted, let's try the browser-style _without_ 'http://' */
    
          if((1 > sscanf(data->url, "%256[^\n/]%[^\n]",
    
                         conn->gname, conn->path)) ) {
            failf(data, "<url> malformed");
            return CURLE_URL_MALFORMAT;
          }
          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 */
        }
    
      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);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          }
    
        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;
    
      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
        }
    
      conn->name = conn->gname;
      conn->ppath = conn->path;
      data->hostname = conn->name;
    
      if(!data->bits.httpproxy) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        /* If proxy was not specified, we check for default proxy environment
           variables, to enable i.e Lynx compliance:
    
    
           http_proxy=http://some.server.dom:port/
           https_proxy=http://some.server.dom:port/
           ftp_proxy=http://some.server.dom:port/
           gopher_proxy=http://some.server.dom:port/
           no_proxy=domain1.dom,host.domain2.dom
                                     (a comma-separated list of hosts which should
                                      not be proxied, or an asterisk to override
                                      all proxy variables)
           all_proxy=http://some.server.dom:port/
                                     (seems to exist for the CERN www lib. Probably
                                      the first to check for.)
    
           For compatibility, the all-uppercase versions of these variables are
           checked if the lowercase versions don't exist.
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
           */
    
    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 */
    
    
      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. */
      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
        }
      }
    
    
      if(data->timeout) {
        /* We set the timeout on the connection/resolving phase first, separately
           from the download/upload part to allow a maximum time on everything */
        myalarm(data->timeout); /* this sends a signal when the timeout fires
    			       off, and that will abort system calls */
      }
    
      /*
       * Hmm, if we are using a proxy, then we can skip the GOPHER and the
       * FTP steps, although we cannot skip the HTTPS step (since the proxy
       * works differently, depending on whether its SSL or not).
       */
    
    
      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;
          conn->curl_close = Curl_http_close;