Skip to content
url.c 33.8 KiB
Newer Older
Daniel Stenberg's avatar
Daniel Stenberg committed
  }
  /* file:// is handled above */
  /*  else if (strequal(proto, "FILE")) {
    data->conf |= CONF_FILE;

    result = file(data, path, &bytecount);
    if(result)
      return result;

    return URG_OK;
    }*/
  else {
    failf(data, "Unsupported protocol: %s", proto);
    return URG_UNSUPPORTED_PROTOCOL;
  }

  if(data->conf & CONF_NETRC) {
    if(ParseNetrc(data->hostname, data->user, data->passwd)) {
      infof(data, "Couldn't find host %s in the .netrc file, using defaults",
            data->hostname);
    }
    /* weather we failed or not, we don't know which fields that were filled
       in anyway */
    if(!data->user[0])
      strcpy(data->user, CURL_DEFAULT_USER);
    if(!data->passwd[0])
      strcpy(data->passwd, CURL_DEFAULT_PASSWORD);
    if(data->conf & CONF_HTTP) {
      data->conf |= CONF_USERPWD;
    }
  }
  else if(!(data->conf & CONF_USERPWD) &&
	  (data->conf & (CONF_FTP|CONF_HTTP)) ) {
    /* This is a FTP or HTTP URL, and we haven't got the user+password in
       the extra parameter, we will now try to extract the possible
       user+password pair in a string like:
       ftp://user:password@ftp.my.site:8021/README */
    char *ptr=NULL; /* assign to remove possible warnings */
    if(':' == *name) {
      failf(data, "URL malformat: user can't be zero length");
      return URG_URL_MALFORMAT_USER;
    }
    if((1 <= sscanf(name, "%127[^:]:%127[^@]",
		    data->user, data->passwd)) && (ptr=strchr(name, '@'))) {
      name = ++ptr;
      data->conf |= CONF_USERPWD;
    }
    else {
      strcpy(data->user, CURL_DEFAULT_USER);
      strcpy(data->passwd, CURL_DEFAULT_PASSWORD);
    }
  }

  if(!(data->conf & CONF_PROXY)) {
    /* If not connecting via a proxy, extract the port from the URL, if it is
     * there, thus overriding any defaults that might have been set above. */
    tmp = strchr(name, ':');
    if (tmp) {
      *tmp++ = '\0';
      data->port = atoi(tmp);
    }
    
    /* Connect to target host right on */
    if(!(hp = GetHost(data, name))) {
      failf(data, "Couldn't resolv host '%s'", name);
      return URG_COULDNT_RESOLVE_HOST;
    }
  }
  else {
    char *prox_portno;
    char *endofprot;

    /* We need to make a duplicate of the proxy so that we can modify the
       string safely. */
    char *proxydup=strdup(data->proxy);

    /* We use 'proxyptr' to point to the proxy name from now on... */
    char *proxyptr=proxydup;

    if(NULL == proxydup) {
      failf(data, "memory shortage");
      return URG_OUT_OF_MEMORY;
    }

Daniel Stenberg's avatar
Daniel Stenberg committed
    /* we use proxy all right, but we wanna know the remote port for SSL
       reasons */
    tmp = strchr(name, ':');
    if (tmp) {
      *tmp++ = '\0'; /* cut off the name there */
      data->remote_port = atoi(tmp);
    }

    /* Daniel Dec 10, 1998:
       We do the proxy host string parsing here. We want the host name and the
       port name. Accept a protocol:// prefix, even though it should just be
       ignored. */

    /* 1. skip the protocol part if present */
Daniel Stenberg's avatar
Daniel Stenberg committed
    if(endofprot) {
Daniel Stenberg's avatar
Daniel Stenberg committed
    }

    /* allow user to specify proxy.server.com:1080 if desired */
Daniel Stenberg's avatar
Daniel Stenberg committed
    if (prox_portno) {
      *prox_portno = 0x0; /* cut off number from host name */
      prox_portno ++;
      /* now set the local port number */
      data->port = atoi(prox_portno);
    }

    /* connect to proxy */
    if(!(hp = GetHost(data, proxyptr))) {
      failf(data, "Couldn't resolv proxy '%s'", proxyptr);
Daniel Stenberg's avatar
Daniel Stenberg committed
      return URG_COULDNT_RESOLVE_PROXY;
    }

    free(proxydup); /* free the duplicate pointer and not the modified */
Daniel Stenberg's avatar
Daniel Stenberg committed
  }
  pgrsTime(data, TIMER_NAMELOOKUP);
Daniel Stenberg's avatar
Daniel Stenberg committed

  data->firstsocket = socket(AF_INET, SOCK_STREAM, 0);

  memset((char *) &serv_addr, '\0', sizeof(serv_addr));
  memcpy((char *)&(serv_addr.sin_addr), hp->h_addr, hp->h_length);
  serv_addr.sin_family = hp->h_addrtype;

  serv_addr.sin_port = htons(data->port);

  if (connect(data->firstsocket, (struct sockaddr *) &serv_addr,
	      sizeof(serv_addr)) < 0) {
    switch(errno) {
#ifdef ECONNREFUSED
      /* this should be made nicer */
    case ECONNREFUSED:
      failf(data, "Connection refused");
      break;
#endif
#ifdef EINTR
    case EINTR:
      failf(data, "Connection timeouted");
      break;
#endif
    default:
      failf(data, "Can't connect to server: %d", errno);
      break;
    }
    return URG_COULDNT_CONNECT;
  }

  if(data->conf & CONF_PROXYUSERPWD) {
    char authorization[512];
    sprintf(data->buffer, "%s:%s", data->proxyuser, data->proxypasswd);
    base64Encode(data->buffer, authorization);

    data->ptr_proxyuserpwd = maprintf("Proxy-authorization: Basic %s\015\012",
				      authorization);
  }
  if(data->conf & (CONF_HTTPS|CONF_HTTP|CONF_PROXY)) {
Daniel Stenberg's avatar
Daniel Stenberg committed
    if(data->useragent) {
      data->ptr_uagent = maprintf("User-Agent: %s\015\012", data->useragent);
    }
  }


  /* If we are not using a proxy and we want a secure connection,
   * perform SSL initialization & connection now.
   * If using a proxy with https, then we must tell the proxy to CONNECT
   * us to the host we want to talk to.  Only after the connect
   * has occured, can we start talking SSL
   */
   if (data->conf & CONF_HTTPS) {
     if (data->conf & CONF_PROXY) {

        /* OK, now send the connect statment */
        sendf(data->firstsocket, data,
              "CONNECT %s:%d HTTP/1.0\015\012"
              "%s"
	      "%s"
              "\r\n",
              data->hostname, data->remote_port,
              (data->conf&CONF_PROXYUSERPWD)?data->ptr_proxyuserpwd:"",
	      (data->useragent?data->ptr_uagent:"")
              );

        /* wait for the proxy to send us a HTTP/1.0 200 OK header */
	/* Daniel rewrote this part Nov 5 1998 to make it more obvious */
	{
	  int httperror=0;
	  int subversion=0;
	  while(GetLine(data->firstsocket, data->buffer, data)) {
	    if('\r' == data->buffer[0])
	      break; /* end of headers */
	    if(2 == sscanf(data->buffer, "HTTP/1.%d %d",
			   &subversion,
			   &httperror)) {
	      ;
	    }
	  }
	  if(200 != httperror) {
	    if(407 == httperror)
	      /* Added Nov 6 1998 */
	      failf(data, "Proxy requires authorization!");
	    else 
	      failf(data, "Received error code %d from proxy", httperror);
	    return URG_READ_ERROR;
	  }
	}
        infof (data, "Proxy has replied to CONNECT request\n");
     }

      /* now, perform the SSL initialization for this socket */
     if(UrgSSLConnect (data)) {
       return URG_SSL_CONNECT_ERROR;
     }
  }
  pgrsTime(data, TIMER_CONNECT);
Daniel Stenberg's avatar
Daniel Stenberg committed

  now = tvnow(); /* time this *after* the connect is done */
  bytecount = 0;
  
  /* Figure out the ip-number and the first host name it shows: */
  {
    struct in_addr in;
    (void) memcpy(&in.s_addr, *hp->h_addr_list, sizeof (in.s_addr));
    infof(data, "Connected to %s (%s)\n", hp->h_name, inet_ntoa(in));
  }

#if 0 /* Kerberos experiements! Beware! Take cover! */
  kerberos_connect(data, name);
#endif

#ifdef __EMX__
  /* 20000330 mgs
   * the check is quite a hack...
   * we're calling _fsetmode to fix the problem with fwrite converting newline
   * characters (you get mangled text files, and corrupted binary files when
   * you download to stdout and redirect it to a file). */

  if ((data->out)->_handle == NULL) {
    _fsetmode(stdout, "b");
  }
#endif

Daniel Stenberg's avatar
Daniel Stenberg committed
  if((data->conf&(CONF_FTP|CONF_PROXY)) == CONF_FTP) {
    result = ftp(data, &bytecount, data->user, data->passwd, ppath);
    if(result)
      return result;
  }
  else if(data->conf & CONF_TELNET) {
    result=telnet(data);
    if(result)
      return result;
  }
  else if (data->conf & CONF_LDAP) {
    result = ldap(data, path, &bytecount);
    if (result)
      return result;
  }
  else if (data->conf & CONF_DICT) {
    result = dict(data, path, &bytecount);
    if(result)
      return result;
  }
  else {
    result = http(data, ppath, name, &bytecount);
    if(result)
      return result;
  }
  if(bytecount) {
    double ittook = tvdiff (tvnow(), now);
    infof(data, "%i bytes transfered in %.3lf seconds (%.0lf bytes/sec).\n",
          bytecount, ittook, (double)bytecount/(ittook!=0.0?ittook:1));
  }
  return URG_OK;
}